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 Valerius Prefab Baker v0.9.0
plugins/ValeriusPrefabBaker.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using 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.InteropServices; using System.Runtime.Versioning; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn; using Jotunn.Entities; using Jotunn.Managers; using Unity.Collections; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("ValeriusPrefabBaker")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ValeriusPrefabBaker")] [assembly: AssemblyCopyright("")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("0.1.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.0.0")] namespace ValeriusPrefabBaker; internal static class BlueprintObjExporter { private sealed class CachedSubmesh { public int[] Triangles; public string MaterialKey; public Color Color; public bool HasColor; public string TexturePath; } private sealed class CachedMesh { public string Name; public Vector3[] Vertices; public Vector2[] UVs; public List<CachedSubmesh> Submeshes = new List<CachedSubmesh>(); } private sealed class CachedPrefab { public List<CachedMesh> Meshes = new List<CachedMesh>(); public List<string> Warnings = new List<string>(); } private sealed class ExportMaterial { public Color Color; public bool HasColor; public string TexturePath; } internal sealed class RawMesh { public Vector3[] Vertices; public Vector2[] UVs; public Vector3[] Normals = Array.Empty<Vector3>(); public Vector4[] Tangents = Array.Empty<Vector4>(); public List<int[]> Triangles = new List<int[]>(); } private static readonly CultureInfo Invariant = CultureInfo.InvariantCulture; private const int PiecesPerFrame = 10; public static IEnumerator Export() { if ((Object)(object)Player.m_localPlayer == (Object)null) { Logger.LogWarning((object)"Enter a world before starting the dungeon export."); yield break; } string text = Path.Combine(Paths.ConfigPath, "PlanBuild"); string outputDirectory = Path.Combine(Paths.BepInExRootPath, "ValeriusDungeonExport"); if (!Directory.Exists(text)) { Logger.LogError((object)("Blueprint directory not found: " + text)); yield break; } string[] files = Directory.GetFiles(text, "*.blueprint"); if (files.Length == 0) { Logger.LogWarning((object)("No .blueprint files found in: " + text)); yield break; } Directory.CreateDirectory(outputDirectory); Dictionary<string, CachedPrefab> prefabCache = new Dictionary<string, CachedPrefab>(); string[] array = files; foreach (string input in array) { IEnumerator routine = ExportBlueprint(input, outputDirectory, prefabCache); while (routine.MoveNext()) { yield return routine.Current; } } Logger.LogInfo((object)"All blueprint exports finished."); } private static IEnumerator ExportBlueprint(string input, string outputDirectory, Dictionary<string, CachedPrefab> prefabCache) { string fileName = Path.GetFileNameWithoutExtension(input); string path = Path.Combine(outputDirectory, fileName + ".obj"); string mtlPath = Path.Combine(outputDirectory, fileName + ".mtl"); string manifestPath = Path.Combine(outputDirectory, fileName + "_manifest.txt"); Dictionary<string, string> materialIds = new Dictionary<string, string>(); Dictionary<string, ExportMaterial> materials = new Dictionary<string, ExportMaterial>(); StringBuilder manifest = new StringBuilder(); int vertexOffset = 0; int uvOffset = 0; int pieceCount = 0; int meshCount = 0; int missingCount = 0; int materialNumber = 0; int processedSinceYield = 0; bool readingPieces = false; Logger.LogInfo((object)("Starting export: " + Path.GetFileName(input))); using (StreamWriter obj = new StreamWriter(path, append: false, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false))) { obj.WriteLine("# Exported from Valheim by ValeriusPrefabBaker"); obj.WriteLine("mtllib " + fileName + ".mtl"); foreach (string item in File.ReadLines(input)) { string text = item.Trim(); if (text == "#Pieces") { readingPieces = true; } else { if (!readingPieces || text.Length == 0 || text.StartsWith("#")) { continue; } try { string[] array = text.Split(new char[1] { ';' }); if (array.Length < 10) { continue; } string text2 = array[0].Trim(); if (text2.Length == 0) { continue; } if (!TryParsePiece(array, out var position, out var rotation, out var scale)) { manifest.AppendLine("INVALID TRANSFORM: " + text2); missingCount++; continue; } if (prefabCache.TryGetValue(text2, out var value)) { goto IL_0335; } GameObject prefab = PrefabManager.Instance.GetPrefab(text2); if ((Object)(object)prefab == (Object)null) { manifest.AppendLine("MISSING PREFAB: " + text2); missingCount++; continue; } value = (prefabCache[text2] = CachePrefab(prefab, text2, outputDirectory)); foreach (string warning in value.Warnings) { manifest.AppendLine("MESH WARNING: " + warning); } Logger.LogInfo((object)("Cached prefab: " + text2 + " " + $"({value.Meshes.Count} meshes)")); goto IL_0335; IL_0335: if (value.Meshes.Count == 0) { manifest.AppendLine("ZERO GEOMETRY: " + text2); missingCount++; continue; } pieceCount++; manifest.AppendLine($"PIECE: {text2} | position={position} " + $"rotation={((Quaternion)(ref rotation)).eulerAngles} scale={scale}"); Matrix4x4 val = Matrix4x4.TRS(position, rotation, scale); foreach (CachedMesh mesh in value.Meshes) { int num = vertexOffset; int num2 = uvOffset; obj.WriteLine($"o piece_{pieceCount}_{SafeName(mesh.Name)}"); Vector3[] vertices = mesh.Vertices; foreach (Vector3 val2 in vertices) { Vector3 val3 = ((Matrix4x4)(ref val)).MultiplyPoint3x4(val2); obj.WriteLine("v " + F(val3.x) + " " + F(val3.y) + " " + F(val3.z)); } vertexOffset += mesh.Vertices.Length; Vector2[] uVs = mesh.UVs; foreach (Vector2 val4 in uVs) { obj.WriteLine("vt " + F(val4.x) + " " + F(val4.y)); } uvOffset += mesh.UVs.Length; foreach (CachedSubmesh submesh in mesh.Submeshes) { if (!materialIds.TryGetValue(submesh.MaterialKey, out var value2)) { int i = materialNumber + 1; materialNumber = i; value2 = $"mat_{i:0000}"; materialIds[submesh.MaterialKey] = value2; materials[value2] = new ExportMaterial { Color = submesh.Color, HasColor = submesh.HasColor, TexturePath = submesh.TexturePath }; } obj.WriteLine("usemtl " + value2); int[] triangles = submesh.Triangles; for (int j = 0; j + 2 < triangles.Length; j += 3) { int num3 = triangles[j]; int num4 = triangles[j + 1]; int num5 = triangles[j + 2]; if (num3 >= 0 && num4 >= 0 && num5 >= 0 && num3 < mesh.Vertices.Length && num4 < mesh.Vertices.Length && num5 < mesh.Vertices.Length) { if (mesh.UVs.Length == mesh.Vertices.Length) { obj.WriteLine($"f {num + num3 + 1}/{num2 + num3 + 1} " + $"{num + num4 + 1}/{num2 + num4 + 1} " + $"{num + num5 + 1}/{num2 + num5 + 1}"); } else { obj.WriteLine($"f {num + num3 + 1} " + $"{num + num4 + 1} " + $"{num + num5 + 1}"); } } } } meshCount++; } goto IL_07f5; } catch (Exception ex) { manifest.AppendLine("EXPORT ERROR: " + text + " | " + ex.Message); missingCount++; Logger.LogWarning((object)("Could not export a blueprint piece: " + ex.Message)); goto IL_07f5; } } continue; IL_07f5: processedSinceYield++; if (processedSinceYield >= 10) { processedSinceYield = 0; yield return null; } } } using (StreamWriter streamWriter = new StreamWriter(mtlPath, append: false, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false))) { foreach (KeyValuePair<string, ExportMaterial> item2 in materials) { streamWriter.WriteLine("newmtl " + item2.Key); ExportMaterial value3 = item2.Value; Color color = value3.Color; streamWriter.WriteLine("Kd " + F(color.r) + " " + F(color.g) + " " + F(color.b)); streamWriter.WriteLine("d " + F(color.a)); if (!string.IsNullOrEmpty(value3.TexturePath)) { streamWriter.WriteLine("map_Kd " + value3.TexturePath); } streamWriter.WriteLine(); } } manifest.Insert(0, $"Pieces exported: {pieceCount}\n" + $"Mesh filters exported: {meshCount}\n" + $"Missing/errors: {missingCount}\n\n"); manifest.AppendLine(); manifest.AppendLine("Material mapping (OBJ ID -> source material):"); foreach (KeyValuePair<string, string> item3 in materialIds) { manifest.AppendLine(item3.Value + " -> " + item3.Key); } File.WriteAllText(manifestPath, manifest.ToString(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); Logger.LogInfo((object)($"Finished {fileName}: pieces={pieceCount}, " + $"meshes={meshCount}, errors={missingCount}")); yield return null; } private static CachedPrefab CachePrefab(GameObject source, string prefabName, string outputDirectory) { //IL_000c: 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_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) CachedPrefab cachedPrefab = new CachedPrefab(); Matrix4x4 worldToLocalMatrix = source.transform.worldToLocalMatrix; MeshFilter[] componentsInChildren = source.GetComponentsInChildren<MeshFilter>(true); Dictionary<int, RawMesh> dictionary = new Dictionary<int, RawMesh>(); MeshFilter[] array = componentsInChildren; foreach (MeshFilter val in array) { Mesh sharedMesh = val.sharedMesh; MeshRenderer component = ((Component)val).GetComponent<MeshRenderer>(); if ((Object)(object)sharedMesh == (Object)null || (Object)(object)component == (Object)null) { continue; } if (!((Component)val).gameObject.activeInHierarchy || !((Renderer)component).enabled) { bool flag = true; Transform val2 = ((Component)val).transform; while ((Object)(object)val2 != (Object)null && (Object)(object)val2 != (Object)(object)source.transform) { if (!((Component)val2).gameObject.activeSelf) { flag = false; break; } val2 = val2.parent; } if (!flag || !((Renderer)component).enabled) { continue; } } try { int instanceID = ((Object)sharedMesh).GetInstanceID(); if (!dictionary.TryGetValue(instanceID, out var value)) { value = (dictionary[instanceID] = ReadRawMesh(sharedMesh, prefabName, cachedPrefab.Warnings)); } if (value == null) { continue; } Matrix4x4 val3 = worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix; CachedMesh cachedMesh = new CachedMesh { Name = ((Object)val).name, Vertices = (Vector3[])(object)new Vector3[value.Vertices.Length], UVs = value.UVs }; for (int j = 0; j < value.Vertices.Length; j++) { cachedMesh.Vertices[j] = ((Matrix4x4)(ref val3)).MultiplyPoint3x4(value.Vertices[j]); } Material[] sharedMaterials = ((Renderer)component).sharedMaterials; for (int k = 0; k < value.Triangles.Count; k++) { int[] array2 = value.Triangles[k]; if (array2.Length == 0) { continue; } Material val4 = ((k < sharedMaterials.Length) ? sharedMaterials[k] : null); Texture2D val5 = null; if ((Object)(object)val4 != (Object)null) { if (val4.HasProperty("_MainTex")) { Texture texture = val4.GetTexture("_MainTex"); val5 = (Texture2D)(object)((texture is Texture2D) ? texture : null); } if ((Object)(object)val5 == (Object)null && val4.HasProperty("_BaseMap")) { Texture texture2 = val4.GetTexture("_BaseMap"); val5 = (Texture2D)(object)((texture2 is Texture2D) ? texture2 : null); } } string texturePath = (((Object)(object)val5 != (Object)null) ? ExportTexture(val5, outputDirectory) : null); string materialKey = (((Object)(object)val4 == (Object)null) ? "unknown" : (((Object)val4).name + "|" + (((Object)(object)val4.shader == (Object)null) ? "unknown" : ((Object)val4.shader).name) + "|" + (((Object)(object)val5 == (Object)null) ? "no-texture" : ((Object)val5).name))); cachedMesh.Submeshes.Add(new CachedSubmesh { Triangles = array2, MaterialKey = materialKey, Color = (((Object)(object)val4 != (Object)null && val4.HasProperty("_Color")) ? val4.color : (((Object)(object)val4 != (Object)null && val4.HasProperty("_BaseColor")) ? val4.GetColor("_BaseColor") : Color.white)), HasColor = ((Object)(object)val4 != (Object)null && (val4.HasProperty("_Color") || val4.HasProperty("_BaseColor"))), TexturePath = texturePath }); } if (cachedMesh.Submeshes.Count > 0) { cachedPrefab.Meshes.Add(cachedMesh); } } catch (Exception ex) { cachedPrefab.Warnings.Add(prefabName + "/" + ((Object)val).name + "/" + ((Object)sharedMesh).name + ": " + ex.Message); } } return cachedPrefab; } internal static RawMesh ReadRawMesh(Mesh mesh, string prefabName, List<string> warnings) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) try { if (mesh.isReadable) { RawMesh rawMesh = new RawMesh { Vertices = mesh.vertices, UVs = mesh.uv, Normals = mesh.normals, Tangents = mesh.tangents }; for (int i = 0; i < mesh.subMeshCount; i++) { rawMesh.Triangles.Add(((int)mesh.GetTopology(i) == 0) ? mesh.GetTriangles(i) : Array.Empty<int>()); } return rawMesh; } } catch (Exception ex) { warnings.Add(prefabName + "/" + ((Object)mesh).name + ": CPU read failed: " + ex.Message); } try { RawMesh rawMesh2 = ReadBackMeshFromGPU(mesh); warnings.Add(prefabName + "/" + ((Object)mesh).name + ": GPU readback succeeded (" + rawMesh2.Vertices.Length + " vertices)"); return rawMesh2; } catch (Exception ex2) { warnings.Add(prefabName + "/" + ((Object)mesh).name + ": GPU recovery unavailable: " + ex2.GetType().Name + " - " + ex2.Message); return null; } } private static RawMesh ReadBackMeshFromGPU(Mesh mesh) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: 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_0319: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0331: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Unknown result type (might be due to invalid IL or missing references) //IL_033a: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) if (!SystemInfo.supportsAsyncGPUReadback) { throw new NotSupportedException("Async GPU readback unsupported by this graphics device"); } if (!mesh.HasVertexAttribute((VertexAttribute)0)) { throw new NotSupportedException("Position attribute missing"); } if ((int)mesh.GetVertexAttributeFormat((VertexAttribute)0) != 0 || mesh.GetVertexAttributeDimension((VertexAttribute)0) < 3) { throw new NotSupportedException("GPU vertex position format is not Float32x3"); } int vertexAttributeStream = mesh.GetVertexAttributeStream((VertexAttribute)0); Dictionary<int, byte[]> dictionary = new Dictionary<int, byte[]>(); byte[] bytes = (dictionary[vertexAttributeStream] = ReadVertexStream(mesh, vertexAttributeStream)); int vertexCount = mesh.vertexCount; int vertexBufferStride = mesh.GetVertexBufferStride(vertexAttributeStream); int vertexAttributeOffset = mesh.GetVertexAttributeOffset((VertexAttribute)0); RawMesh rawMesh = new RawMesh { Vertices = (Vector3[])(object)new Vector3[vertexCount] }; for (int i = 0; i < vertexCount; i++) { int num = i * vertexBufferStride + vertexAttributeOffset; rawMesh.Vertices[i] = new Vector3(ReadFloat(bytes, num), ReadFloat(bytes, num + 4), ReadFloat(bytes, num + 8)); } rawMesh.UVs = Array.Empty<Vector2>(); if (mesh.HasVertexAttribute((VertexAttribute)4) && (int)mesh.GetVertexAttributeFormat((VertexAttribute)4) == 0 && mesh.GetVertexAttributeDimension((VertexAttribute)4) >= 2) { int vertexAttributeStream2 = mesh.GetVertexAttributeStream((VertexAttribute)4); if (!dictionary.TryGetValue(vertexAttributeStream2, out var value)) { value = (dictionary[vertexAttributeStream2] = ReadVertexStream(mesh, vertexAttributeStream2)); } int vertexBufferStride2 = mesh.GetVertexBufferStride(vertexAttributeStream2); int vertexAttributeOffset2 = mesh.GetVertexAttributeOffset((VertexAttribute)4); rawMesh.UVs = (Vector2[])(object)new Vector2[vertexCount]; for (int j = 0; j < vertexCount; j++) { int num2 = j * vertexBufferStride2 + vertexAttributeOffset2; rawMesh.UVs[j] = new Vector2(ReadFloat(value, num2), ReadFloat(value, num2 + 4)); } } if (mesh.HasVertexAttribute((VertexAttribute)1) && (int)mesh.GetVertexAttributeFormat((VertexAttribute)1) == 0 && mesh.GetVertexAttributeDimension((VertexAttribute)1) >= 3) { int vertexAttributeStream3 = mesh.GetVertexAttributeStream((VertexAttribute)1); if (!dictionary.TryGetValue(vertexAttributeStream3, out var value2)) { value2 = (dictionary[vertexAttributeStream3] = ReadVertexStream(mesh, vertexAttributeStream3)); } int vertexBufferStride3 = mesh.GetVertexBufferStride(vertexAttributeStream3); int vertexAttributeOffset3 = mesh.GetVertexAttributeOffset((VertexAttribute)1); rawMesh.Normals = (Vector3[])(object)new Vector3[vertexCount]; for (int k = 0; k < vertexCount; k++) { int num3 = k * vertexBufferStride3 + vertexAttributeOffset3; rawMesh.Normals[k] = new Vector3(ReadFloat(value2, num3), ReadFloat(value2, num3 + 4), ReadFloat(value2, num3 + 8)); } } if (mesh.HasVertexAttribute((VertexAttribute)2) && (int)mesh.GetVertexAttributeFormat((VertexAttribute)2) == 0 && mesh.GetVertexAttributeDimension((VertexAttribute)2) >= 4) { int vertexAttributeStream4 = mesh.GetVertexAttributeStream((VertexAttribute)2); if (!dictionary.TryGetValue(vertexAttributeStream4, out var value3)) { value3 = (dictionary[vertexAttributeStream4] = ReadVertexStream(mesh, vertexAttributeStream4)); } int vertexBufferStride4 = mesh.GetVertexBufferStride(vertexAttributeStream4); int vertexAttributeOffset4 = mesh.GetVertexAttributeOffset((VertexAttribute)2); rawMesh.Tangents = (Vector4[])(object)new Vector4[vertexCount]; for (int l = 0; l < vertexCount; l++) { int num4 = l * vertexBufferStride4 + vertexAttributeOffset4; rawMesh.Tangents[l] = new Vector4(ReadFloat(value3, num4), ReadFloat(value3, num4 + 4), ReadFloat(value3, num4 + 8), ReadFloat(value3, num4 + 12)); } } byte[] value4 = ReadIndexBuffer(mesh); int num5 = (((int)mesh.indexFormat == 0) ? 2 : 4); for (int m = 0; m < mesh.subMeshCount; m++) { SubMeshDescriptor subMesh = mesh.GetSubMesh(m); if ((int)((SubMeshDescriptor)(ref subMesh)).topology != 0) { rawMesh.Triangles.Add(Array.Empty<int>()); continue; } int[] array5 = new int[((SubMeshDescriptor)(ref subMesh)).indexCount]; for (int n = 0; n < array5.Length; n++) { int startIndex = (((SubMeshDescriptor)(ref subMesh)).indexStart + n) * num5; array5[n] = (int)((num5 == 2) ? BitConverter.ToUInt16(value4, startIndex) : BitConverter.ToUInt32(value4, startIndex)) + ((SubMeshDescriptor)(ref subMesh)).baseVertex; if (array5[n] < 0 || array5[n] >= vertexCount) { throw new InvalidDataException("Recovered triangle index out of range"); } } rawMesh.Triangles.Add(array5); } return rawMesh; } private static byte[] ReadVertexStream(Mesh mesh, int stream) { GraphicsBuffer val = null; try { val = mesh.GetVertexBuffer(stream); return ReadGpuBuffer(val); } finally { if (val != null) { val.Dispose(); } } } private static byte[] ReadIndexBuffer(Mesh mesh) { GraphicsBuffer val = null; try { val = mesh.GetIndexBuffer(); return ReadGpuBuffer(val); } finally { if (val != null) { val.Dispose(); } } } private static byte[] ReadGpuBuffer(GraphicsBuffer buffer) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) AsyncGPUReadbackRequest val = AsyncGPUReadback.Request(buffer, (Action<AsyncGPUReadbackRequest>)null); ((AsyncGPUReadbackRequest)(ref val)).WaitForCompletion(); if (((AsyncGPUReadbackRequest)(ref val)).hasError) { throw new InvalidOperationException("GPU refused buffer readback (backend/buffer usage limitation)"); } return ((AsyncGPUReadbackRequest)(ref val)).GetData<byte>(0).ToArray(); } private static float ReadFloat(byte[] bytes, int offset) { return BitConverter.ToSingle(bytes, offset); } private static string ExportTexture(Texture2D source, string outputDirectory) { //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) string text = Path.Combine(outputDirectory, "textures"); Directory.CreateDirectory(text); string text2 = SafeName(((Object)source).name); if (string.IsNullOrWhiteSpace(text2)) { text2 = "texture"; } string text3 = $"{text2}_{((Object)source).GetInstanceID()}.png"; string path = Path.Combine(text, text3); if (File.Exists(path)) { return "textures/" + text3; } Texture2D val = null; RenderTexture val2 = null; RenderTexture active = RenderTexture.active; try { val2 = RenderTexture.GetTemporary(((Texture)source).width, ((Texture)source).height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)0); Graphics.Blit((Texture)(object)source, val2); RenderTexture.active = val2; val = new Texture2D(((Texture)source).width, ((Texture)source).height, (TextureFormat)4, false); val.ReadPixels(new Rect(0f, 0f, (float)((Texture)source).width, (float)((Texture)source).height), 0, 0); val.Apply(); File.WriteAllBytes(path, ImageConversion.EncodeToPNG(val)); Logger.LogInfo((object)$"Exported texture: {((Object)source).name} ({((Texture)source).width}x{((Texture)source).height})"); return "textures/" + text3; } catch (Exception ex) { Logger.LogWarning((object)("Could not export texture '" + ((Object)source).name + "': " + ex.Message)); return null; } finally { RenderTexture.active = active; if ((Object)(object)val2 != (Object)null) { RenderTexture.ReleaseTemporary(val2); } if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } } } private static bool TryParsePiece(string[] fields, out Vector3 position, out Quaternion rotation, out Vector3 scale) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: 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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: 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_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) position = Vector3.zero; rotation = Quaternion.identity; scale = Vector3.one; try { position = new Vector3(Parse(fields[3]), Parse(fields[4]), Parse(fields[5])); int num = -1; for (int i = 6; i < fields.Length; i++) { if (fields[i].Length == 0) { num = i; break; } } if (num < 0) { return false; } switch (num - 6) { case 4: rotation = new Quaternion(Parse(fields[6]), Parse(fields[7]), Parse(fields[8]), Parse(fields[9])); break; case 3: rotation = Quaternion.Euler(Parse(fields[6]), Parse(fields[7]), Parse(fields[8])); break; default: return false; } if (num + 3 >= fields.Length) { return false; } scale = new Vector3(Parse(fields[num + 1]), Parse(fields[num + 2]), Parse(fields[num + 3])); return true; } catch { return false; } } private static float ReadFloat(NativeArray<byte> data, int offset) { return BitConverter.ToSingle(new byte[4] { data[offset], data[offset + 1], data[offset + 2], data[offset + 3] }, 0); } private static float Parse(string value) { return float.Parse(value, Invariant); } private static string F(float value) { return value.ToString("R", Invariant); } private static string SafeName(string value) { char[] invalidFileNameChars = Path.GetInvalidFileNameChars(); foreach (char oldChar in invalidFileNameChars) { value = value.Replace(oldChar, '_'); } return value.Replace(' ', '_'); } } internal static class ValeriusBakeRules { internal enum Mode { Static, Interactive, CollisionOnly, VisualSeparate, Skip } private static ConfigFile config; private static ConfigEntry<bool> bakeVegetation; private static ConfigEntry<bool> bakeRocks; private static ConfigEntry<bool> bakeInteractibles; private static ConfigEntry<bool> bakeStructures; private static ConfigEntry<bool> snowCoverage; private static ConfigEntry<bool> disableAllSnow; private static ConfigEntry<string> interactive; private static ConfigEntry<string> boundaries; private static ConfigEntry<string> vegetation; private static ConfigEntry<string> preserved; private static ConfigEntry<string> skipped; private static ConfigEntry<string> aliases; private static ConfigEntry<string> alwaysBake; private static ConfigEntry<string> neverBake; private static ConfigEntry<string> protectedPrefabs; private static ConfigEntry<string> lockedVegetation; private static HashSet<string> interactiveNames; private static HashSet<string> boundaryNames; private static HashSet<string> vegetationNames; private static HashSet<string> preservedNames; private static HashSet<string> skippedNames; private static HashSet<string> alwaysBakeNames; private static HashSet<string> neverBakeNames; private static HashSet<string> protectedNames; private static HashSet<string> lockedNames; private static Dictionary<string, string> aliasMap; internal static bool PreserveVegetationColliders => true; internal static bool LeafShadows => false; internal static bool StaticCollision => true; internal static float SpatialChunkSize => 16f; internal static bool GroupBySharedMaterial => true; internal static bool ProtectDungeonDecorations => true; internal static float SnowCoverageDistance => 200f; internal static bool SnowCoverageEnabled { get { if (snowCoverage.Value) { return !disableAllSnow.Value; } return false; } } internal static bool DisableAllSnow => disableAllSnow.Value; internal static bool IsProtectedDecoration(string name) { if (config == null) { Initialize(); } return protectedNames.Contains(name); } internal static bool ShouldLockVegetation(string name, bool separated) { if (config == null) { Initialize(); } return lockedNames.Contains(name); } internal static void Initialize() { if (config == null) { config = ((BaseUnityPlugin)ValeriusPlugin.Instance).Config; bakeVegetation = config.Bind<bool>("General", "BakeVegetation", false, "Combine vegetation into static geometry instead of preserving original prefabs. Requires rebaking."); bakeRocks = config.Bind<bool>("General", "BakeRocks", true, "Combine rock geometry. Requires rebaking."); bakeInteractibles = config.Bind<bool>("General", "BakeInteractibles", false, "Combine interactive objects, removing their individual interactions. Requires rebaking."); bakeStructures = config.Bind<bool>("General", "BakeStructures", true, "Combine structural geometry. Requires rebaking."); snowCoverage = config.Bind<bool>("General", "EnableOverheadCheck", true, "BETA / EXPERIMENTAL: Attempt to detect overhead shelter and suppress snow on covered baked surfaces. Roof-edge results may be inaccurate. Restart to apply."); disableAllSnow = config.Bind<bool>("General", "DisableAllSnow", false, "BETA / EXPERIMENTAL: Attempt to disable snow on baked materials and separately spawned originals. Some vegetation shaders and snow textures may be unaffected. Does not affect world weather. Restart to apply."); interactive = config.Bind<string>("General", "InteractivePrefabs", "cloth_hanging_door_double,piece_cloth_hanging_door,piece_cloth_hanging_door_blue,dvergrtown_slidingdoor,crypt_skeleton_chest,TreasureChest_ashland_stone,TreasureChest_fCrypt,CastleKit_groundtorch,CastleKit_groundtorch_blue,piece_groundtorch_blue,piece_groundtorch_mist,piece_walltorch,MountainKit_brazier_blue,piece_brazierceiling01,piece_brazierfloor02,piece_dvergr_lantern,piece_dvergr_lantern_pole,piece_hoodedlantern,BogWitch_Fire_Pit,iron_grate,pickable_mushroom_magecap", "Prefab names retained as functional originals when interactive baking is disabled."); boundaries = config.Bind<string>("General", "BoundaryPrefabs", "InvisibleFloor,InvisibleWall,ValeriusInvisibleFloor,ValeriusInvisibleWall,ValeriusInvisibleFloor4x4,ValeriusInvisibleWall4x4", "Collision-only prefabs; never baked as visible geometry."); vegetation = config.Bind<string>("General", "SeparateVegetation", "FirTree,FirTree_small,FirTree_small_dead,Pinetree_01,Pinetree_Snow,SwampTree1,SwampTree1_Stub,SwampTree2_log,VineGreen,vines,VineAshlands,YggaShoot1,YggaShoot2,YggaShoot3,YggaShoot_small1,YggdrasilRoot,AshlandsBush1,AshlandsBush2,FernAshlands,Bush01,Bush01_heath,Bush02_en,shrub_2,shrub_2_heath", "Vegetation prefab names kept as originals when vegetation baking is disabled."); preserved = config.Bind<string>("General", "PreserveOriginalPrefabs", "Morkhalla_Banner2,dvergrprops_banner,dvergrprops_curtain,piece_banner01,piece_banner11,piece_FairylightGarland", "Always keep these decorative prefab hierarchies, animations and effects."); skipped = config.Bind<string>("General", "NeverInclude", "FireFlies,WaterLiquid", "Omit these prefab names completely. Has priority over all other lists."); aliases = config.Bind<string>("General", "Aliases", "InvisibleFloor=ValeriusInvisibleFloor,InvisibleWall=ValeriusInvisibleWall", "Map blueprint names to registered prefabs: old=new."); alwaysBake = config.Bind<string>("General", "AlwaysBake", "", "Always convert these prefab names to static geometry, except collision boundaries or excluded objects."); neverBake = config.Bind<string>("General", "NeverBake", "", "Always spawn these prefab names as complete originals."); protectedPrefabs = config.Bind<string>("General", "ProtectedPrefabs", "VineGreen,vines,VineAshlands,piece_dvergr_lantern,piece_dvergr_lantern_pole,piece_hoodedlantern,cloth_hanging_door_double,piece_cloth_hanging_door,piece_cloth_hanging_door_blue,dvergrprops_curtain,Morkhalla_Banner2,dvergrprops_banner,piece_banner01,piece_banner11,piece_FairylightGarland,piece_walltorch,piece_groundtorch_blue,piece_groundtorch_mist,CastleKit_groundtorch,CastleKit_groundtorch_blue,MountainKit_brazier_blue,piece_brazierceiling01,piece_brazierfloor02,BogWitch_Fire_Pit", "Dungeon-spawned originals protected from WearNTear updates."); lockedVegetation = config.Bind<string>("General", "LockedVegetation", "FirTree,FirTree_small,Pinetree_01,FirTree_small_dead,Pinetree_Snow,Bush01,Bush01_heath,Bush02_en,shrub_2,shrub_02,shrub_2_heath", "Dungeon-spawned originals with gravity/settling physics locked; no effect on world vegetation."); Refresh(); config.SettingChanged += delegate { Refresh(); }; } } private static HashSet<string> Names(string csv) { HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); string[] array = csv.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0) { hashSet.Add(text); } } return hashSet; } private static void Refresh() { interactiveNames = Names(interactive.Value); boundaryNames = Names(boundaries.Value); vegetationNames = Names(vegetation.Value); preservedNames = Names(preserved.Value); skippedNames = Names(skipped.Value); alwaysBakeNames = Names(alwaysBake.Value); neverBakeNames = Names(neverBake.Value); protectedNames = Names(protectedPrefabs.Value); lockedNames = Names(lockedVegetation.Value); aliasMap = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); string[] array = aliases.Value.Split(new char[1] { ',' }); foreach (string text in array) { int num = text.IndexOf('='); if (num > 0 && num != text.Length - 1) { aliasMap[text.Substring(0, num).Trim()] = text.Substring(num + 1).Trim(); } } } internal static string Resolve(string original) { if (config == null) { Initialize(); } if (!aliasMap.TryGetValue(original, out var value)) { return original; } return value; } private static bool Has(HashSet<string> set, string original, string registered) { if (!set.Contains(original)) { return set.Contains(registered); } return true; } internal static string CategoryFor(string original, string registered) { if (config == null) { Initialize(); } if (Has(skippedNames, original, registered)) { return "Skip"; } if (Has(boundaryNames, original, registered)) { return "Boundary"; } if (Has(alwaysBakeNames, original, registered)) { return "ForceBake"; } if (Has(preservedNames, original, registered)) { return "PreservedDecoration"; } if (Has(neverBakeNames, original, registered)) { return "ForceOriginal"; } if (Has(vegetationNames, original, registered)) { return "Vegetation"; } if (Has(interactiveNames, original, registered)) { return "Interactible"; } GameObject prefab = PrefabManager.Instance.GetPrefab(registered); if ((Object)(object)prefab != (Object)null) { if ((Object)(object)prefab.GetComponentInChildren<MineRock5>(true) != (Object)null) { return "Rock"; } if ((Object)(object)prefab.GetComponent<Piece>() != (Object)null) { return "Structure"; } } return "Unclassified"; } internal static Mode ModeFor(string original, string registered) { switch (CategoryFor(original, registered)) { case "Skip": return Mode.Skip; case "Boundary": return Mode.CollisionOnly; case "ForceBake": return Mode.Static; case "PreservedDecoration": return Mode.VisualSeparate; case "ForceOriginal": return Mode.Interactive; case "Vegetation": if (!bakeVegetation.Value) { return Mode.VisualSeparate; } return Mode.Static; case "Rock": if (!bakeRocks.Value) { return Mode.VisualSeparate; } return Mode.Static; case "Interactible": if (!bakeInteractibles.Value) { return Mode.Interactive; } return Mode.Static; case "Structure": if (!bakeStructures.Value) { return Mode.Interactive; } return Mode.Static; default: return Mode.Static; } } } internal sealed class ValeriusDynamicSpawner : MonoBehaviour { private sealed class SpawnConfig { internal string[] Names; internal Matrix4x4[] Matrices; internal bool[] Vegetation; internal float YOffset; } private const string ClothDoorName = "cloth_hanging_door_double"; private const int MaxTransformProbes = 20; private int transformProbes; private string[] names; private Matrix4x4[] matrices; private bool[] vegetation; private float yOffset; private const string KeyPrefix = "prefabbaker_original_"; internal const string OriginalZdoKey = "prefabbaker_dungeon_original"; internal const string SceneryZdoKey = "prefabbaker_scenery_lock"; internal const string DecorationZdoKey = "prefabbaker_protected_decoration"; internal const string VisualSnowZdoKey = "prefabbaker_no_snow"; internal const string VisualClothZdoKey = "prefabbaker_cloth_lod"; private static readonly Dictionary<string, SpawnConfig> Configs = new Dictionary<string, SpawnConfig>(StringComparer.Ordinal); private static bool VerboseDiagnostics => ValeriusPlugin.VerboseDiagnostics; private static string PrefabKey(string objectName) { if (!objectName.EndsWith("(Clone)", StringComparison.Ordinal)) { return objectName; } return objectName.Substring(0, objectName.Length - "(Clone)".Length); } internal void Configure(string[] prefabNames, Matrix4x4[] transforms, bool[] vegetationFlags, float originOffset) { names = prefabNames; matrices = transforms; vegetation = vegetationFlags; yOffset = originOffset; Configs[PrefabKey(((Object)((Component)this).gameObject).name)] = new SpawnConfig { Names = prefabNames, Matrices = transforms, Vegetation = vegetationFlags, YOffset = originOffset }; if (VerboseDiagnostics) { Logger.LogWarning((object)("[PrefabBaker originals] Configured " + PrefabKey(((Object)((Component)this).gameObject).name) + " entries=" + prefabNames.Length)); } } internal static void LockVegetationPhysics(GameObject obj, string prefabName) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) int num = 0; int num2 = 0; Rigidbody[] componentsInChildren = obj.GetComponentsInChildren<Rigidbody>(true); foreach (Rigidbody obj2 in componentsInChildren) { obj2.linearVelocity = Vector3.zero; obj2.angularVelocity = Vector3.zero; obj2.useGravity = false; obj2.isKinematic = true; num++; } MonoBehaviour[] componentsInChildren2 = obj.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val in componentsInChildren2) { if ((Object)(object)val != (Object)null && ((object)val).GetType().Name == "StaticPhysics") { ((Behaviour)val).enabled = false; num2++; } } if (VerboseDiagnostics) { Logger.LogWarning((object)("[PrefabBaker vegetation lock] " + prefabName + " rigidbodies=" + num + " staticPhysics=" + num2)); } } private static void DecodeTransform(Matrix4x4 m, out Vector3 scale, out Quaternion rotation) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: 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_0034: 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_0040: 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) //IL_0093: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //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_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0105: 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_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0130: 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) Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(m.m00, m.m10, m.m20); Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(m.m01, m.m11, m.m21); Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(m.m02, m.m12, m.m22); scale = new Vector3(((Vector3)(ref val)).magnitude, ((Vector3)(ref val2)).magnitude, ((Vector3)(ref val3)).magnitude); if (((Matrix4x4)(ref m)).determinant < 0f) { scale.x = 0f - scale.x; } if (scale.x != 0f) { val /= scale.x; } if (scale.y != 0f) { val2 /= scale.y; } if (scale.z != 0f) { val3 /= scale.z; } if (((Vector3)(ref val3)).sqrMagnitude < 1E-06f || ((Vector3)(ref val2)).sqrMagnitude < 1E-06f) { rotation = Quaternion.identity; return; } ((Vector3)(ref val3)).Normalize(); Vector3 val4 = val2 - Vector3.Dot(val2, val3) * val3; val2 = ((Vector3)(ref val4)).normalized; rotation = ((((Vector3)(ref val2)).sqrMagnitude < 1E-06f) ? Quaternion.identity : Quaternion.LookRotation(val3, val2)); } private static bool IsDungeonCloth(string prefabName) { if (!prefabName.Equals("cloth_hanging_door_double", StringComparison.OrdinalIgnoreCase) && !prefabName.Equals("piece_cloth_hanging_door", StringComparison.OrdinalIgnoreCase) && !prefabName.Equals("piece_cloth_hanging_door_blue", StringComparison.OrdinalIgnoreCase) && !prefabName.Equals("dvergrprops_curtain", StringComparison.OrdinalIgnoreCase) && !prefabName.Equals("Morkhalla_Banner2", StringComparison.OrdinalIgnoreCase) && !prefabName.Equals("dvergrprops_banner", StringComparison.OrdinalIgnoreCase) && !prefabName.Equals("piece_banner01", StringComparison.OrdinalIgnoreCase)) { return prefabName.Equals("piece_banner11", StringComparison.OrdinalIgnoreCase); } return true; } private static string DescribeRenderBounds(GameObject obj) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_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) Renderer[] componentsInChildren = obj.GetComponentsInChildren<Renderer>(true); if (componentsInChildren.Length == 0) { return "none"; } Bounds bounds = componentsInChildren[0].bounds; for (int i = 1; i < componentsInChildren.Length; i++) { ((Bounds)(ref bounds)).Encapsulate(componentsInChildren[i].bounds); } return "center=" + ((object)((Bounds)(ref bounds)).center/*cast due to .constrained prefix*/).ToString() + " size=" + ((object)((Bounds)(ref bounds)).size/*cast due to .constrained prefix*/).ToString(); } private IEnumerator CheckOriginalPlacement(GameObject obj, string prefabName, int index, Vector3 expected, Vector3 intendedScale) { //IL_001c: 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) //IL_0024: 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) if (!((Object)(object)obj == (Object)null)) { Vector3 initial = obj.transform.position; Vector3 initialScale = obj.transform.lossyScale; yield return (object)new WaitForSeconds(2f); if (!((Object)(object)obj == (Object)null)) { Vector3 position = obj.transform.position; string[] obj2 = new string[22] { "[PrefabBaker placement CHECK] ", prefabName, " #", index.ToString(), " expected=", ((Vector3)(ref expected)).ToString("F3"), " spawned=", ((Vector3)(ref initial)).ToString("F3"), " after2s=", ((Vector3)(ref position)).ToString("F3"), " drift=", null, null, null, null, null, null, null, null, null, null, null }; Vector3 val = position - initial; obj2[11] = ((Vector3)(ref val)).ToString("F3"); obj2[12] = " intendedScale="; obj2[13] = ((Vector3)(ref intendedScale)).ToString("F3"); obj2[14] = " instanceScale="; obj2[15] = ((Vector3)(ref initialScale)).ToString("F3"); obj2[16] = " afterScale="; val = obj.transform.lossyScale; obj2[17] = ((Vector3)(ref val)).ToString("F3"); obj2[18] = " hasStaticPhysics="; obj2[19] = ((Object)(object)obj.GetComponentInChildren<StaticPhysics>(true) != (Object)null).ToString(); obj2[20] = " renderBounds="; obj2[21] = DescribeRenderBounds(obj); Logger.LogInfo((object)string.Concat(obj2)); } } } private static bool IsTransformTarget(string prefabName) { if (!prefabName.Equals("SwampTree2_log", StringComparison.OrdinalIgnoreCase) && !prefabName.Equals("piece_dvergr_lantern_pole", StringComparison.OrdinalIgnoreCase) && !prefabName.Equals("dverger_pole_lantern", StringComparison.OrdinalIgnoreCase) && !prefabName.Equals("YggdrasilRoot", StringComparison.OrdinalIgnoreCase)) { return prefabName.StartsWith("YggaShoot", StringComparison.OrdinalIgnoreCase); } return true; } private IEnumerator MonitorCloth(GameObject obj) { bool first = true; bool priorActive = false; bool priorEnabled = false; bool priorVisible = false; int reports = 0; while ((Object)(object)obj != (Object)null && reports < 12) { Renderer[] componentsInChildren = obj.GetComponentsInChildren<Renderer>(true); bool flag = false; bool flag2 = false; Renderer[] array = componentsInChildren; foreach (Renderer val in array) { if (!((Object)(object)val == (Object)null)) { flag |= val.enabled && ((Component)val).gameObject.activeInHierarchy; flag2 |= val.isVisible; } } bool activeInHierarchy = obj.activeInHierarchy; if (first || priorActive != activeInHierarchy || priorEnabled != flag || priorVisible != flag2) { first = false; priorActive = activeInHierarchy; priorEnabled = flag; priorVisible = flag2; float num = (((Object)(object)Player.m_localPlayer == (Object)null) ? (-1f) : Vector3.Distance(((Component)Player.m_localPlayer).transform.position, obj.transform.position)); Logger.LogInfo((object)("[PrefabBaker cloth probe] active=" + activeInHierarchy + " enabled=" + flag + " visible=" + flag2 + " renderers=" + componentsInChildren.Length + " playerDistance=" + num.ToString("F1") + "m")); reports++; } yield return (object)new WaitForSeconds(2f); } } private unsafe IEnumerator Start() { if (!((Object)((Component)this).gameObject).name.EndsWith("(Clone)", StringComparison.Ordinal)) { yield break; } if (!Configs.TryGetValue(PrefabKey(((Object)((Component)this).gameObject).name), out var value)) { Logger.LogWarning((object)("[PrefabBaker originals] No spawn configuration for " + ((Object)((Component)this).gameObject).name)); yield break; } names = value.Names; matrices = value.Matrices; vegetation = value.Vegetation; yOffset = value.YOffset; if (names == null || matrices == null || vegetation == null || names.Length != matrices.Length || names.Length != vegetation.Length) { Logger.LogWarning((object)("[PrefabBaker originals] Invalid spawn configuration for " + ((Object)((Component)this).gameObject).name)); yield break; } if (VerboseDiagnostics) { Logger.LogWarning((object)("[PrefabBaker originals] Starting " + ((Object)((Component)this).gameObject).name + " entries=" + names.Length)); } ZNetView component = ((Component)this).GetComponent<ZNetView>(); for (int frame = 0; frame < 300; frame++) { if (!((Object)(object)component == (Object)null) && component.IsValid() && !((Object)(object)ZNetScene.instance == (Object)null) && !((Object)(object)ZNet.instance == (Object)null)) { break; } yield return null; component = ((Component)this).GetComponent<ZNetView>(); } if ((Object)(object)component == (Object)null || !component.IsValid() || (Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ZNet.instance == (Object)null) { Logger.LogWarning((object)("[PrefabBaker originals] Root not initialized: " + ((Object)this).name)); yield break; } bool server = ZNet.instance.IsServer(); ZDO rootZdo = component.GetZDO(); int networked = 0; int local = 0; int missing = 0; int failed = 0; int marked = 0; int nonNetworkInteractive = 0; for (int frame = 0; frame < names.Length; frame++) { GameObject prefab = ZNetScene.instance.GetPrefab(names[frame]); if ((Object)(object)prefab == (Object)null) { prefab = PrefabManager.Instance.GetPrefab(names[frame]); } if ((Object)(object)prefab == (Object)null) { missing++; if (missing <= 5) { Logger.LogWarning((object)("[PrefabBaker originals] MISSING " + names[frame] + " index=" + frame)); } continue; } bool flag = (Object)(object)prefab.GetComponent<ZNetView>() != (Object)null; if ((frame < 20 || names[frame].IndexOf("grate", StringComparison.OrdinalIgnoreCase) >= 0 || names[frame].IndexOf("door", StringComparison.OrdinalIgnoreCase) >= 0) && VerboseDiagnostics) { Logger.LogWarning((object)("[PrefabBaker originals] SOURCE " + names[frame] + " index=" + frame + " net=" + flag + " door=" + ((Object)(object)prefab.GetComponentInChildren<Door>(true) != (Object)null) + " rootScale=" + ((object)prefab.transform.localScale/*cast due to .constrained prefix*/).ToString() + " vegetation=" + vegetation[frame])); } if (flag && !server) { continue; } if (!flag && !vegetation[frame]) { int num = nonNetworkInteractive + 1; nonNetworkInteractive = num; if (num <= 20 && VerboseDiagnostics) { Logger.LogWarning((object)("[PrefabBaker originals] Local non-networked decoration: " + names[frame] + " index=" + frame)); } } string key = "prefabbaker_original_" + frame; if (flag && rootZdo != null && rootZdo.GetBool(key, false)) { marked++; continue; } GameObject obj = null; try { Matrix4x4 val = matrices[frame]; DecodeTransform(val, out var scale, out var rotation); Vector3 val2 = ((Component)this).transform.TransformPoint(new Vector3(val.m03, val.m13 + yOffset, val.m23)); obj = Object.Instantiate<GameObject>(prefab, val2, ((Component)this).transform.rotation * rotation); obj.transform.localScale = Vector3.Scale(prefab.transform.localScale, Vector3.Scale(((Component)this).transform.lossyScale, scale)); if (!obj.activeSelf) { obj.SetActive(true); } ValeriusDungeonVisualFix.Ensure(obj, ValeriusBakeRules.DisableAllSnow, IsDungeonCloth(names[frame])); if ((names[frame].Equals("SwampTree2_log", StringComparison.OrdinalIgnoreCase) || names[frame].Equals("YggdrasilRoot", StringComparison.OrdinalIgnoreCase) || names[frame].Equals("piece_dvergr_lantern_pole", StringComparison.OrdinalIgnoreCase)) && transformProbes < 9) { transformProbes++; ((MonoBehaviour)this).StartCoroutine(CheckOriginalPlacement(obj, names[frame], frame, val2, scale)); } if (VerboseDiagnostics && transformProbes < 20 && IsTransformTarget(names[frame])) { transformProbes++; string[] obj2 = new string[26] { "[PrefabBaker transform probe] prefab=", names[frame], " index=", frame.ToString(), " storedPos=", ((object)new Vector3(val.m03, val.m13, val.m23)/*cast due to .constrained prefix*/).ToString(), " blueprintScale=", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null }; Vector3 val3 = scale; obj2[7] = ((object)(*(Vector3*)(&val3))/*cast due to .constrained prefix*/).ToString(); obj2[8] = " prefabScale="; obj2[9] = ((object)prefab.transform.localScale/*cast due to .constrained prefix*/).ToString(); obj2[10] = " dungeonScale="; obj2[11] = ((object)((Component)this).transform.lossyScale/*cast due to .constrained prefix*/).ToString(); obj2[12] = " spawnedPos="; obj2[13] = ((object)obj.transform.position/*cast due to .constrained prefix*/).ToString(); obj2[14] = " spawnedScale="; obj2[15] = ((object)obj.transform.localScale/*cast due to .constrained prefix*/).ToString(); obj2[16] = " rotation="; Quaternion rotation2 = obj.transform.rotation; obj2[17] = ((object)((Quaternion)(ref rotation2)).eulerAngles/*cast due to .constrained prefix*/).ToString(); obj2[18] = " networked="; obj2[19] = flag.ToString(); obj2[20] = " prefabRootPos="; obj2[21] = ((object)prefab.transform.position/*cast due to .constrained prefix*/).ToString(); obj2[22] = " sourceBounds="; obj2[23] = DescribeRenderBounds(prefab); obj2[24] = " spawnedBounds="; obj2[25] = DescribeRenderBounds(obj); Logger.LogInfo((object)string.Concat(obj2)); } if (ValeriusBakeRules.IsProtectedDecoration(names[frame])) { obj.AddComponent<ValeriusProtectedDecoration>(); WearNTear[] componentsInChildren = obj.GetComponentsInChildren<WearNTear>(true); foreach (WearNTear obj3 in componentsInChildren) { obj3.m_health = Mathf.Max(obj3.m_health, 1000000f); } } if (vegetation[frame] && ValeriusBakeRules.ShouldLockVegetation(names[frame], vegetation[frame])) { LockVegetationPhysics(obj, names[frame]); } if (!flag) { obj.transform.SetParent(((Component)this).transform, true); local++; } } catch (Exception ex) { failed++; if ((Object)(object)obj != (Object)null) { Object.Destroy((Object)(object)obj); } Logger.LogWarning((object)("[PrefabBaker originals] FAILED " + names[frame] + " index=" + frame + ": " + ex)); continue; } if (flag) { ZNetView child = null; for (int i = 0; i < 30; i++) { try { if ((Object)(object)obj != (Object)null) { child = obj.GetComponent<ZNetView>(); } if ((Object)(object)child != (Object)null && child.IsValid() && child.GetZDO() != null) { break; } } catch (Exception ex2) { Logger.LogWarning((object)("[PrefabBaker originals] ZDO check failed " + names[frame] + " index=" + frame + ": " + ex2.Message)); break; } yield return null; } if ((Object)(object)obj == (Object)null || (Object)(object)child == (Object)null || !child.IsValid() || child.GetZDO() == null) { failed++; if ((Object)(object)obj != (Object)null) { Object.Destroy((Object)(object)obj); } Logger.LogWarning((object)("[PrefabBaker originals] ZDO FAILED " + names[frame] + " index=" + frame)); continue; } child.GetZDO().Set("prefabbaker_dungeon_original", true); if (vegetation[frame] && ValeriusBakeRules.ShouldLockVegetation(names[frame], vegetation[frame])) { child.GetZDO().Set("prefabbaker_scenery_lock", true); if (VerboseDiagnostics) { Logger.LogWarning((object)("[PrefabBaker scenery ZDO] marked " + names[frame] + " index=" + frame)); } } if (ValeriusBakeRules.IsProtectedDecoration(names[frame])) { child.GetZDO().Set("prefabbaker_protected_decoration", true); } if (ValeriusBakeRules.DisableAllSnow) { child.GetZDO().Set("prefabbaker_no_snow", true); } if (IsDungeonCloth(names[frame])) { child.GetZDO().Set("prefabbaker_cloth_lod", true); } if (rootZdo != null) { rootZdo.Set(key, true); } networked++; } if (frame % 25 == 0) { yield return null; } } if (VerboseDiagnostics || missing > 0 || failed > 0 || nonNetworkInteractive > 0) { Logger.LogInfo((object)("[PrefabBaker originals] " + ((Object)this).name + " total=" + names.Length + " networked=" + networked + " localVisual=" + local + " marked=" + marked + " missing=" + missing + " noNetworkInteractive=" + nonNetworkInteractive + " failed=" + failed + " server=" + server)); } } } internal sealed class ValeriusProtectedDecoration : MonoBehaviour { } [HarmonyPatch] internal static class ValeriusDecorationWearPatch { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(WearNTear), "UpdateWear", (Type[])null, (Type[])null); } private static bool Prefix(WearNTear __instance) { if ((Object)(object)__instance == (Object)null || !ValeriusBakeRules.ProtectDungeonDecorations) { return true; } if ((Object)(object)((Component)__instance).GetComponentInParent<ValeriusProtectedDecoration>() != (Object)null) { return false; } ZNetView componentInParent = ((Component)__instance).GetComponentInParent<ZNetView>(); if ((Object)(object)componentInParent == (Object)null || !componentInParent.IsValid()) { return true; } ZDO zDO = componentInParent.GetZDO(); if (zDO != null) { return !zDO.GetBool("prefabbaker_protected_decoration", false); } return true; } } [HarmonyPatch(typeof(StaticPhysics), "SUpdate")] internal static class ValeriusSceneryStaticPhysicsPatch { private static bool Prefix(StaticPhysics __instance) { if ((Object)(object)__instance == (Object)null) { return true; } ZNetView componentInParent = ((Component)__instance).GetComponentInParent<ZNetView>(); if ((Object)(object)componentInParent == (Object)null || !componentInParent.IsValid()) { return true; } ZDO zDO = componentInParent.GetZDO(); if (zDO != null) { return !zDO.GetBool("prefabbaker_scenery_lock", false); } return true; } } internal sealed class ValeriusDungeonVisualFix : MonoBehaviour { private bool noSnow; private bool cloth; private Coroutine retry; internal static void Ensure(GameObject instance, bool removeSnow, bool fixCloth) { if (!((Object)(object)instance == (Object)null) && (removeSnow || fixCloth)) { ValeriusDungeonVisualFix valeriusDungeonVisualFix = instance.GetComponent<ValeriusDungeonVisualFix>(); if ((Object)(object)valeriusDungeonVisualFix == (Object)null) { valeriusDungeonVisualFix = instance.AddComponent<ValeriusDungeonVisualFix>(); } valeriusDungeonVisualFix.noSnow |= removeSnow; valeriusDungeonVisualFix.cloth |= fixCloth; valeriusDungeonVisualFix.Apply(); if (((Behaviour)valeriusDungeonVisualFix).isActiveAndEnabled && valeriusDungeonVisualFix.retry == null) { valeriusDungeonVisualFix.retry = ((MonoBehaviour)valeriusDungeonVisualFix).StartCoroutine(valeriusDungeonVisualFix.ReapplyAfterInitialization()); } } } private void Apply() { //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_006b: Unknown result type (might be due to invalid IL or missing references) if (noSnow && ValeriusBakeRules.DisableAllSnow) { ValeriusPrefabBaker.ApplyNoSnowToInstance(((Component)this).gameObject); } if (cloth) { LODGroup[] componentsInChildren = ((Component)this).GetComponentsInChildren<LODGroup>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].ForceLOD(0); } SkinnedMeshRenderer[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true); foreach (SkinnedMeshRenderer obj in componentsInChildren2) { obj.updateWhenOffscreen = true; Bounds localBounds = ((Renderer)obj).localBounds; ((Bounds)(ref localBounds)).Expand(20f); ((Renderer)obj).localBounds = localBounds; } } } private IEnumerator ReapplyAfterInitialization() { yield return null; Apply(); yield return (object)new WaitForSeconds(1f); Apply(); yield return (object)new WaitForSeconds(3f); Apply(); retry = null; } } [HarmonyPatch] internal static class ValeriusDungeonVisualOnNetworkSpawn { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(ZNetScene), "CreateObject", new Type[1] { typeof(ZDO) }, (Type[])null); } private static void Postfix(ZDO zdo, GameObject __result) { if (zdo == null || (Object)(object)__result == (Object)null) { return; } bool flag = zdo.GetBool("prefabbaker_no_snow", false); bool flag2 = zdo.GetBool("prefabbaker_cloth_lod", false); bool flag3 = zdo.GetBool("prefabbaker_scenery_lock", false); bool flag4 = zdo.GetBool("prefabbaker_protected_decoration", false); if (flag || flag2 || flag3 || flag4) { if (flag || flag2) { ValeriusDungeonVisualFix.Ensure(__result, flag, flag2); } if (flag3) { ValeriusDynamicSpawner.LockVegetationPhysics(__result, ((Object)__result).name); } if (flag4 && (Object)(object)__result.GetComponent<ValeriusProtectedDecoration>() == (Object)null) { __result.AddComponent<ValeriusProtectedDecoration>(); } } } } internal static class ValeriusMeshExtractor { internal sealed class RawMesh { public Vector3[] Vertices; public Vector2[] UVs; public Vector3[] Normals; public Vector4[] Tangents; public List<int[]> Triangles = new List<int[]>(); } internal static RawMesh ReadRawMesh(Mesh mesh, string prefabName, List<string> warnings) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) try { if (mesh.isReadable) { RawMesh rawMesh = new RawMesh { Vertices = mesh.vertices, UVs = mesh.uv, Normals = mesh.normals, Tangents = mesh.tangents }; for (int i = 0; i < mesh.subMeshCount; i++) { rawMesh.Triangles.Add(((int)mesh.GetTopology(i) == 0) ? mesh.GetTriangles(i) : Array.Empty<int>()); } return rawMesh; } } catch (Exception ex) { warnings.Add(prefabName + "/" + ((Object)mesh).name + ": CPU read failed: " + ex.Message); } try { RawMesh rawMesh2 = ReadBackMeshFromGPU(mesh); warnings.Add(prefabName + "/" + ((Object)mesh).name + ": GPU readback succeeded (" + rawMesh2.Vertices.Length + " vertices)"); return rawMesh2; } catch (Exception ex2) { warnings.Add(prefabName + "/" + ((Object)mesh).name + ": GPU recovery unavailable: " + ex2.GetType().Name + " - " + ex2.Message); return null; } } private static RawMesh ReadBackMeshFromGPU(Mesh mesh) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: 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_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) if (!SystemInfo.supportsAsyncGPUReadback) { throw new NotSupportedException("Async GPU readback unsupported by this graphics device"); } if (!mesh.HasVertexAttribute((VertexAttribute)0)) { throw new NotSupportedException("Position attribute missing"); } if ((int)mesh.GetVertexAttributeFormat((VertexAttribute)0) != 0 || mesh.GetVertexAttributeDimension((VertexAttribute)0) < 3) { throw new NotSupportedException("GPU vertex position format is not Float32x3"); } int vertexAttributeStream = mesh.GetVertexAttributeStream((VertexAttribute)0); Dictionary<int, byte[]> dictionary = new Dictionary<int, byte[]>(); byte[] bytes = (dictionary[vertexAttributeStream] = ReadVertexStream(mesh, vertexAttributeStream)); int vertexCount = mesh.vertexCount; int vertexBufferStride = mesh.GetVertexBufferStride(vertexAttributeStream); int vertexAttributeOffset = mesh.GetVertexAttributeOffset((VertexAttribute)0); RawMesh rawMesh = new RawMesh { Vertices = (Vector3[])(object)new Vector3[vertexCount] }; for (int i = 0; i < vertexCount; i++) { int num = i * vertexBufferStride + vertexAttributeOffset; rawMesh.Vertices[i] = new Vector3(ReadFloat(bytes, num), ReadFloat(bytes, num + 4), ReadFloat(bytes, num + 8)); } rawMesh.UVs = Array.Empty<Vector2>(); if (mesh.HasVertexAttribute((VertexAttribute)4) && (int)mesh.GetVertexAttributeFormat((VertexAttribute)4) == 0 && mesh.GetVertexAttributeDimension((VertexAttribute)4) >= 2) { int vertexAttributeStream2 = mesh.GetVertexAttributeStream((VertexAttribute)4); if (!dictionary.TryGetValue(vertexAttributeStream2, out var value)) { value = (dictionary[vertexAttributeStream2] = ReadVertexStream(mesh, vertexAttributeStream2)); } int vertexBufferStride2 = mesh.GetVertexBufferStride(vertexAttributeStream2); int vertexAttributeOffset2 = mesh.GetVertexAttributeOffset((VertexAttribute)4); rawMesh.UVs = (Vector2[])(object)new Vector2[vertexCount]; for (int j = 0; j < vertexCount; j++) { int num2 = j * vertexBufferStride2 + vertexAttributeOffset2; rawMesh.UVs[j] = new Vector2(ReadFloat(value, num2), ReadFloat(value, num2 + 4)); } } byte[] value2 = ReadIndexBuffer(mesh); int num3 = (((int)mesh.indexFormat == 0) ? 2 : 4); for (int k = 0; k < mesh.subMeshCount; k++) { SubMeshDescriptor subMesh = mesh.GetSubMesh(k); if ((int)((SubMeshDescriptor)(ref subMesh)).topology != 0) { rawMesh.Triangles.Add(Array.Empty<int>()); continue; } int[] array3 = new int[((SubMeshDescriptor)(ref subMesh)).indexCount]; for (int l = 0; l < array3.Length; l++) { int startIndex = (((SubMeshDescriptor)(ref subMesh)).indexStart + l) * num3; array3[l] = (int)((num3 == 2) ? BitConverter.ToUInt16(value2, startIndex) : BitConverter.ToUInt32(value2, startIndex)) + ((SubMeshDescriptor)(ref subMesh)).baseVertex; if (array3[l] < 0 || array3[l] >= vertexCount) { throw new InvalidDataException("Recovered triangle index out of range"); } } rawMesh.Triangles.Add(array3); } rawMesh.Normals = Array.Empty<Vector3>(); rawMesh.Tangents = Array.Empty<Vector4>(); return rawMesh; } private static byte[] ReadVertexStream(Mesh mesh, int stream) { GraphicsBuffer val = null; try { val = mesh.GetVertexBuffer(stream); return ReadGpuBuffer(val); } finally { if (val != null) { val.Dispose(); } } } private static byte[] ReadIndexBuffer(Mesh mesh) { GraphicsBuffer val = null; try { val = mesh.GetIndexBuffer(); return ReadGpuBuffer(val); } finally { if (val != null) { val.Dispose(); } } } private static byte[] ReadGpuBuffer(GraphicsBuffer buffer) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) AsyncGPUReadbackRequest val = AsyncGPUReadback.Request(buffer, (Action<AsyncGPUReadbackRequest>)null); ((AsyncGPUReadbackRequest)(ref val)).WaitForCompletion(); if (((AsyncGPUReadbackRequest)(ref val)).hasError) { throw new InvalidOperationException("GPU refused buffer readback (backend/buffer usage limitation)"); } return ((AsyncGPUReadbackRequest)(ref val)).GetData<byte>(0).ToArray(); } private static float ReadFloat(byte[] bytes, int offset) { return BitConverter.ToSingle(bytes, offset); } } [BepInPlugin("PrefabBaker", "Valerius Prefab Baker", "0.9.0")] public sealed class ValeriusPlugin : BaseUnityPlugin { private Harmony harmony; private const float ProgressCooldownSeconds = 5f; private static float lastProgressTime = -1000f; internal static ValeriusPlugin Instance { get; private set; } internal static bool VerboseDiagnostics { get; set; } = false; internal static void ShowBakeProgress(string message) { if (!((Object)(object)Player.m_localPlayer == (Object)null)) { float realtimeSinceStartup = Time.realtimeSinceStartup; if (!(realtimeSinceStartup - lastProgressTime < 5f)) { lastProgressTime = realtimeSinceStartup; ((Character)Player.m_localPlayer).Message((MessageType)1, "[PrefabBaker] " + message, 0, (Sprite)null, false); } } } internal static void ShowBakeCompletion(string message) { if ((Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)1, "[PrefabBaker] " + message, 0, (Sprite)null, false); } lastProgressTime = Time.realtimeSinceStartup; } private void Awake() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown Instance = this; harmony = new Harmony("PrefabBaker.patches"); harmony.PatchAll(typeof(ValeriusPlugin).Assembly); ValeriusPrefabBaker.Register(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"PrefabBaker initialized."); } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } if ((Object)(object)Instance == (Object)(object)this) { Instance = null; } } } internal static class ValeriusPrefabBaker { private sealed class Part { public string Prefab; public int FilterIndex; public int MaterialIndex; public Matrix4x4 Local; public Vector3[] V; public Vector2[] UV; public Vector3[] N; public Vector4[] Tan; public int[] T; } private sealed class Piece { public int PrefabIndex; public Matrix4x4 World; } private sealed class PrefabData { public string Name; public readonly List<int> PartIndexes = new List<int>(); } private sealed class DynamicEntry { public string Name; public Matrix4x4 Transform; public ValeriusBakeRules.Mode Mode; } private sealed class Buffer { public string MaterialRef; public Material Material; public readonly List<Vector3> V = new List<Vector3>(); public readonly List<Vector2> UV = new List<Vector2>(); public readonly List<Vector3> N = new List<Vector3>(); public readonly List<Vector4> Tan = new List<Vector4>(); public bool HasAllTangents = true; public readonly List<int> T = new List<int>(); } private sealed class SnowCoverIndex { private const float Grid = 2.5f; private const int MaxCells = 350000; private const int MaxStampCellsPerTriangle = 256; private readonly Dictionary<long, float> roof = new Dictionary<long, float>(); internal int TriangleCount { get; private set; } internal int OversizedCount { get; private set; } internal bool AtLimit { get; private set; } internal int CellCount => roof.Count; private static long Key(int x, int z) { return ((long)x << 32) ^ (uint)z; } private static float ProjectedHeight(Vector3 a, Vector3 b, Vector3 c, float x, float z) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0067: 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_007c: 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_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) float num = (b.z - c.z) * (a.x - c.x) + (c.x - b.x) * (a.z - c.z); if (Mathf.Abs(num) < 1E-05f) { return float.NaN; } float num2 = ((b.z - c.z) * (x - c.x) + (c.x - b.x) * (z - c.z)) / num; float num3 = ((c.z - a.z) * (x - c.x) + (a.x - c.x) * (z - c.z)) / num; if (num2 < -0.0001f || num3 < -0.0001f || num2 + num3 > 1.0001f) { return float.NaN; } return num2 * a.y + num3 * b.y + (1f - num2 - num3) * c.y; } private void Stamp(int x, int z, float y) { if (float.IsNaN(y)) { return; } long key = Key(x, z); if (roof.TryGetValue(key, out var value)) { if (y > value) { roof[key] = y; } } else if (roof.Count < 350000) { roof.Add(key, y); } else { AtLimit = true; } } private void Add(Vector3 a, Vector3 b, Vector3 c) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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_0045: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_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_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00db: 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_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0230: 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_0236: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0246: 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_025b: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: 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_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) if (Mathf.Abs((b.x - a.x) * (c.z - a.z) - (c.x - a.x) * (b.z - a.z)) < 0.08f) { return; } Vector3 val = Vector3.Cross(b - a, c - a); if (Mathf.Abs(val.y) < ((Vector3)(ref val)).magnitude * 0.7f) { return; } TriangleCount++; int num = Mathf.FloorToInt(Mathf.Min(a.x, Mathf.Min(b.x, c.x)) / 2.5f); int num2 = Mathf.FloorToInt(Mathf.Max(a.x, Mathf.Max(b.x, c.x)) / 2.5f); int num3 = Mathf.FloorToInt(Mathf.Min(a.z, Mathf.Min(b.z, c.z)) / 2.5f); int num4 = Mathf.FloorToInt(Mathf.Max(a.z, Mathf.Max(b.z, c.z)) / 2.5f); long num5 = (long)(num2 - num + 1) * (long)(num4 - num3 + 1); if (num5 > 256) { OversizedCount++; int num6 = Mathf.Max(1, Mathf.CeilToInt(Mathf.Sqrt((float)num5 / 256f))); for (int i = num; i <= num2; i += num6) { for (int j = num3; j <= num4; j += num6) { Stamp(i, j, ProjectedHeight(a, b, c, ((float)i + 0.5f) * 2.5f, ((float)j + 0.5f) * 2.5f)); } } return; } int num7 = 0; for (int k = num; k <= num2; k++) { for (int l = num3; l <= num4; l++) { float num8 = ProjectedHeight(a, b, c, ((float)k + 0.5f) * 2.5f, ((float)l + 0.5f) * 2.5f); if (!float.IsNaN(num8)) { Stamp(k, l, num8); num7++; } } } if (num7 == 0) { Vector3 val2 = (a + b + c) / 3f; Stamp(Mathf.FloorToInt(val2.x / 2.5f), Mathf.FloorToInt(val2.z / 2.5f), val2.y); } } private float CoverFraction(Vector3 pos, float distance) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) float num = pos.x / 2.5f - 0.5f; float num2 = pos.z / 2.5f - 0.5f; int num3 = Mathf.FloorToInt(num); int num4 = Mathf.FloorToInt(num2); float num5 = num - (float)num3; float num6 = num2 - (float)num4; float num7 = 0f; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { if (roof.TryGetValue(Key(num3 + i, num4 + j), out var value) && !(value <= pos.y + 0.35f) && !(value >= pos.y + distance)) { num7 += ((i == 0) ? (1f - num5) : num5) * ((j == 0) ? (1f - num6) : num6); } } } return Mathf.Clamp01(num7); } internal bool HasCover(Vector3 pos, float distance) { //IL_0001: 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_002f: 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_0058: Unknown result type (might be due to invalid IL or missing references) float num = CoverFraction(pos, distance); if (num <= 0.2f) { return false; } if (num >= 0.8f) { return true; } float num2 = Mathf.PerlinNoise(pos.x * 0.17f + 29.31f, pos.z * 0.17f + 81.73f); float num3 = Mathf.PerlinNoise(pos.x * 0.53f + 113.9f, pos.z * 0.53f + 19.1f); float num4 = (num2 - 0.5f) * 0.16f + (num3 - 0.5f) * 0.05f; return num + num4 >= 0.5f; } internal static SnowCoverIndex Build(List<PrefabData> prefabs, List<Part> parts, List<Piece> pieces) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0083: 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_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) SnowCoverIndex snowCoverIndex = new SnowCoverIndex(); foreach (Piece piece in pieces) { if (piece.PrefabIndex < 0 || piece.PrefabIndex >= prefabs.Count) { continue; } foreach (int partIndex in prefabs[piece.PrefabIndex].PartIndexes) { if (partIndex < 0 || partIndex >= parts.Count) { continue; } Part part = parts[partIndex]; Matrix4x4 val = piece.World * part.Local; for (int i = 0; i + 2 < part.T.Length; i += 3) { int num = part.T[i]; int num2 = part.T[i + 1]; int num3 = part.T[i + 2]; if (num >= 0 && num2 >= 0 && num3 >= 0 && num < part.V.Length && num2 < part.V.Length && num3 < part.V.Length) { snowCoverIndex.Add(((Matrix4x4)(ref val)).MultiplyPoint3x4(part.V[num]), ((Matrix4x4)(ref val)).MultiplyPoint3x4(part.V[num2]), ((Matrix4x4)(ref val)).MultiplyPoint3x4(part.V[num3])); } } } } return snowCoverIndex; } } private const int Magic = 827870278; private const int MaxVerts = 45000; private static readonly CultureInfo CI = CultureInfo.InvariantCulture; private static readonly string Root = Path.Combine(Paths.BepInExRootPath, "PrefabBakerBakes"); private static bool running; private static bool lastBakeSucceeded; private static readonly Dictionary<int, Material> noSnowVariants = new Dictionary<int, Material>(); private static readonly int[] snowPropertyIds = new int[5] { Shader.PropertyToID("_AddSnow"), Shader.PropertyToID("_Snow"), Shader.PropertyToID("_SnowAmount"), Shader.PropertyToID("_SnowEnabled"), Shader.PropertyToID("_EnableSnow") }; private static float CellSize => ValeriusBakeRules.SpatialChunkSize; private static bool VerboseDiagnostics => ValeriusPlugin.VerboseDiagnostics; public static void Register() { CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new BakeRuntimeCommand()); ValeriusBakeRules.Initialize(); PrefabManager.OnVanillaPrefabsAvailable += LoadSaved; } public static void Begin(MonoBehaviour runner, string name) { if (running) { Logger.LogWarning((object)"Runtime bake already running"); } else if ((Object)(object)Player.m_localPlayer == (Object)null) { Logger.LogWarning((object)"Enter a world first"); } else if (string.IsNullOrWhiteSpace(name) || Path.GetFileName(name) != name || name.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0) { Logger.LogWarning((object)"Invalid blueprint name"); } else { runner.StartCoroutine(Bake(name)); } } public static void BeginAll(MonoBehaviour runner) { if (running) { Logger.LogWarning((object)"[PrefabBaker] Bake already running"); return; } if ((Object)(object)Player.m_localPlayer == (Object)null) { Logger.LogWarning((object)"[PrefabBaker] Enter a world first"); return; } string text = Path.Combine(Paths.ConfigPath, "PlanBuild"); if (!Directory.Exists(text)) { Logger.LogWarning((object)("[PrefabBaker] Blueprint directory missing: " + text)); return; } string[] array = (from n in Directory.GetFiles(text, "*.blueprint").Select(Path.GetFileNameWithoutExtension) where !n.StartsWith("BakedBluePrint_", StringComparison.OrdinalIgnoreCase) select n).OrderBy<string, string>((string n) => n, StringComparer.OrdinalIgnoreCase).ToArray(); if (array.Length == 0) { Logger.LogWarning((object)("[PrefabBaker] No source blueprints found in " + text)); return; } running = true; runner.StartCoroutine(BakeAll(array)); } private static IEnumerator BakeAll(string[] names) { try { Logger.LogInfo((object)("[PrefabBaker] Batch starting: " + names.Length + " source blueprints")); int succeeded = 0; int failed = 0; for (int i = 0; i < names.Length; i++) { yield return Bake(names[i], partOfBatch: true); if (lastBakeSucceeded) { succeeded++; } else { failed++; } running = true; } Logger.LogInfo((object)("[PrefabBaker] Batch complete: " + succeeded + " succeeded, " + failed + " failed")); ValeriusPlugin.ShowBakeCompletion("Batch complete: " + succeeded + " succeeded, " + failed + " failed. Restart Valheim to load updated prefabs."); } finally { running = false; } } private static void BakeProgress(string message, bool completed = false) { if (completed) { ValeriusPlugin.ShowBakeCompletion(message); } else { ValeriusPlugin.ShowBakeProgress(message); } } private static IEnumerator Bake(string name, bool partOfBatch = false) { lastBakeSucceeded = false; running = true; try { string source = Path.Combine(Paths.ConfigPath, "PlanBuild", name + ".blueprint"); if (!File.Exists(source)) { Logger.LogError((object)("Blueprint not found: " + source)); yield break; } Directory.CreateDirectory(Root); List<PrefabData> prefabs = new List<PrefabData>(); Dictionary<string, int> prefabIds = new Dictionary<string, int>(StringComparer.Ordinal); List<Part> parts = new List<Part>(); List<Piece> pieces = new List<Piece>(); List<DynamicEntry> dynamicEntries = new List<DynamicEntry>(); List<string> warnings = new List<string>(); bool inside = false; int lineNo = 0; int failed = 0; int seen = 0; bool flag = false; int total = 0; int nextProgress = 5; foreach (string item2 in File.ReadLines(source)) { string text = item2.Trim(); if (text == "#Pieces") { flag = true; } else if (flag && text.Length > 0 && !text.StartsWith("#")) { total++; } } BakeProgress(name + ": 0%"); foreach (string item3 in File.ReadLines(source)) { lineNo++; string text2 = item3.Trim(); if (text2 == "#Pieces") { inside = true; } else { if (!inside || text2.Length == 0 || text2.StartsWith("#")) { continue; } seen++; if (total > 0 && nextProgress <= 100 && (long)seen * 100L >= (long)nextProgress * (long)total) { int num = Math.Min(100, (int)((long)seen * 100L / total / 5 * 5)); BakeProgress(name + ": " + num + "%"); nextProgress = num + 5; } string[] array = text2.Split(new char[1] { ';' }); if (array.Length < 10 || !TryTransform(array, out var result)) { failed++; continue; } string original = array[0].Trim(); string text3 = ValeriusBakeRules.Resolve(original); ValeriusBakeRules.Mode mode = ValeriusBakeRules.ModeFor(original, text3); switch (mode) { default: if ((Object)(object)PrefabManager.Instance.GetPrefab(text3) == (Object)null) { warnings.Add("MISSING SPECIAL PREFAB: " + text3); failed++; break; } dynamicEntries.Add(new DynamicEntry { Name = text3, Transform = result, Mode = mode }); if (seen % 20 == 0) { yield return null; } break; case ValeriusBakeRules.Mode.Static: { if (!prefabIds.TryGetValue(text3, out var value)) { GameObject prefab = PrefabManager.Instance.GetPrefab(text3); if ((Object)(object)prefab == (Object)null) { warnings.Add("MISSING PREFAB: " + text3); failed++; break; } value = prefabs.Count; PrefabData prefabData = new PrefabData { Name = text3 }; prefabs.Add(prefabData); prefabIds.Add(text3, value); MeshFilter[] componentsInChildren = prefab.GetComponentsInChildren<MeshFilter>(true); Matrix4x4 worldToLocalMatrix = prefab.transform.worldToLocalMatrix; for (int i = 0; i < componentsInChildren.Length; i++) { MeshFilter val = componentsInChildren[i]; MeshRenderer component = ((Component)val).GetComponent<MeshRenderer>(); if ((Object)(object)val.sharedMesh == (Object)null || (Object)(object)component == (Object)null || !((Renderer)component).enabled || !ActiveBelowRoot(((Component)val).transform, prefab.transform)) { continue; } try { ValeriusMeshExtractor.RawMesh rawMesh = ValeriusMeshExtractor.ReadRawMesh(val.sharedMesh, text3, warnings); if (rawMesh == null) { continue; } Material[] sharedMaterials = ((Renderer)component).sharedMaterials; for (int j = 0; j < rawMesh.Triangles.Count; j++) { if (j < sharedMaterials.Length && !((Object)(object)sharedMaterials[j] == (Object)null) && rawMesh.Triangles[j].Length != 0) { Part item = new Part { Prefab = text3, FilterIndex = i, MaterialIndex = j, Local = worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix, V = rawMesh.Vertices, UV = rawMesh.UVs, N = rawMesh.Normals, Tan = rawMesh.Tangents, T = rawMesh.Triangles[j] }; prefabData.PartIndexes.Add(parts.Count); parts.Add(item); } } } catch (Exception ex) { warnings.Add(text3 + "/" + ((Object)val).name + ": " + ex.Message); } } if (prefabData.PartIndexes.Count == 0) { warnings.Add("ZERO GEOMETRY: " + text3); } } pieces.Add(new Piece { PrefabIndex = value, World = result }); if (seen % 20 == 0) { yield return null; } break; } case ValeriusBakeRules.Mode.Skip: break; } } } string text4 = Path.Combine(Root, "BakedPrefab_" + name + ".flex"); string text5 = text4 + ".tmp"; using (FileStream output = new FileStream(text5, FileMode.Create, FileAccess.Write, FileShare.None)) { using BinaryWriter binaryWriter = new BinaryWriter(output); binaryWriter.Write(827870278); binaryWriter.Write(name); binaryWriter.Write(prefabs.Count); foreach (PrefabData item4 in prefabs) { binaryWriter.Write(item4.Name); binaryWriter.Write(item4.PartIndexes.Count); foreach (int partIndex in item4.PartIndexes) { binaryWriter.Write(partIndex); } } binaryWriter.Write(parts.Count); foreach (Part item5 in parts) { binaryWriter.Write(item5.Prefab); binaryWriter.Write(item5.FilterIndex); binaryWriter.Write(item5.MaterialIndex); WriteMatrix(binaryWriter, item5.Local); binaryWriter.Write(item5.V.Length); Vector3[] v = item5.V; foreach (Vector3 val2 in v) { binaryWriter.Write(val2.x); binaryWriter.Write(val2.y); binaryWriter.Write(val2.z); } binaryWriter.Write((item5.UV != null) ? item5.UV.Length : 0); if (item5.UV != null) { Vector2[] uV = item5.UV; foreach (Vector2 val3 in uV) { binaryWriter.Write(val3.x); binaryWriter.Write(val3.y); } } binaryWriter.Write((item5.N != null) ? item5.N.Length : 0); if (item5.N != null) { v = item5.N; foreach (Vector3 val4 in v) { binaryWriter.Write(val4.x); binaryWriter.Write(val4.y); binaryWriter.Write(val4.z); } } binaryWriter.Write((item5.Tan != null) ? item5.Tan.Length : 0); if (item5.Tan != null) { Vector4[] tan = item5.Tan; foreach (Vector4 val5 in tan) { binaryWriter.Write(val5.x); binaryWriter.Write(val5.y); binaryWriter.Write(val5.z); binaryWriter.Write(val5.w); } } binaryWriter.Write(item5.T.Length); int[] t = item5.T; foreach (int value2 in t) { binaryWriter.Write(value2); } } binaryWriter.Write(pieces.Count); foreach (Piece item6 in pieces) { binaryWriter.Write(item6.PrefabIndex); WriteMatrix(binaryWriter, item6.World); } binaryWriter.Write(dynamicEntries.Count); foreach (DynamicEntry item7 in dynamicEntries) { binaryWriter.Write(item7.Name); binaryWriter.Write((byte)item7.Mode); WriteMatrix(binaryWriter, item7.Transform); } } if (File.Exists(text4)) { File.Delete(text4); } File.Move(text5, text4); string text6 = "BakedPrefab_" + name; string text7 = "BakedBluePrint_" + name; string path = Path.Combine(Paths.ConfigPath, "PlanBuild", text7 + ".blueprint"); string[] contents = new string[10] { "#Name:" + text7, "#Creator:PrefabBaker", "#Description:Single-prefab wrapper generated from " + name, "#Category:Valerius", "#Center:", "#Coordinates:0,0,0", "#Rotation:0,0,0", "#SnapPoints", "#Pieces", text6 + ";;0;0;0;0;0;0;1;;1;1;1;" }; try { if (string.Equals(Path.GetFullPath(source), Path.GetFullPath(path), StringComparison.OrdinalIgnoreCase)) { throw new IOException("Wrapper path would overwrite input blueprint"); } File.WriteAllLines(path, contents); } catch (Exception ex2) { Logger.LogWarning((object)("[PrefabBaker] Flex saved, but wrapper blueprint could not be written: " + ex2.Message)); } File.WriteAllLines(Path.Combine(Root, "BakedPrefab_" + name + "_report.txt"), new string[6] { "Blueprint: " + name, "Instances: " + pieces.Count, "Unique prefabs: " + prefabs.Count, "Submeshes: " + parts.Count, "Skipped lines: " + failed, "Special objects: " + dynamicEntries.Count }.Concat(warnings).ToArray()); lastBakeSucceeded = true; if (!partOfBatch) { BakeProgress(name + ": Complete! Restart Valheim to load the prefab.", completed: true); } Logger.LogInfo((object)("[PrefabBaker] Baked " + name + ": " + pieces.Count + " static, " + dynamicEntries.Count + " originals, " + failed + " skipped")); } finally { running = false; } } private static bool ActiveBelowRoot(Transform current, Transform root) { while ((Object)(object)current != (Object)null && (Object)(object)current != (Object)(object)root) { if (!((Component)current).gameObject.activeSelf) { return false; } current = current.parent; } return true; } private static string Alias(string name) { if (name == "InvisibleFloor") { return "ValeriusInvisibleFloor"; } if (name == "InvisibleWall") { return "ValeriusInvisibleWall"; } return name; } private static bool TryTransform(string[] f, out Matrix4x4 result) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_00af: 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_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing reference