Decompiled source of ValheimDBDumper v1.0.0

ValheimDBDumper.dll

Decompiled 8 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using UnityEngine;
using ValheimDBDumper.Tools;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace ValheimDBDumper
{
	public class PrefabNode
	{
		public string object_name { get; set; }

		public bool is_active { get; set; }

		public string layer { get; set; }

		public string tag { get; set; }

		public List<ComponentData> components { get; set; } = new List<ComponentData>();


		public List<PrefabNode> children { get; set; } = new List<PrefabNode>();

	}
	public class ComponentData
	{
		public string type { get; set; }

		public Dictionary<string, string> fields { get; set; } = new Dictionary<string, string>();

	}
	public class CreatureDataDump
	{
		public string prefab_name { get; set; }

		public string creature_name { get; set; }

		public string creature_rawName { get; set; }

		public float max_health { get; set; }

		public string faction { get; set; }

		public bool tolerate_water { get; set; }

		public bool tolerate_fire { get; set; }

		public List<CreatureDropData> drops { get; set; } = new List<CreatureDropData>();

	}
	public class CreatureDropData
	{
		public string item_prefab { get; set; }

		public int min_amount { get; set; }

		public int max_amount { get; set; }

		public float chance_percent { get; set; }

		public bool level_multiplier { get; set; }
	}
	public static class CreaturesExporter
	{
		[CompilerGenerated]
		private sealed class <ExportCreaturesCoroutine>d__0 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string baseFolder;

			public ConsoleEventArgs args;

			public bool exportJson;

			public bool exportIcons;

			public bool exportPrefab;

			public bool exportModel3d;

			public Action onFinished;

			private string <creaturesFolder>5__1;

			private string <iconsFolder>5__2;

			private string <prefabsFolder>5__3;

			private string <modelsFolder>5__4;

			private string <texturesFolder>5__5;

			private List<GameObject> <allPrefabs>5__6;

			private List<CreatureDataDump> <exportedCreatures>5__7;

			private int <operationsThisFrame>5__8;

			private int <i>5__9;

			private GameObject <prefab>5__10;

			private Character <character>5__11;

			private string <prefabName>5__12;

			private string <creatureRawName>5__13;

			private CharacterDrop <dropComponent>5__14;

			private List<Drop>.Enumerator <>s__15;

			private Drop <drop>5__16;

			private ItemDrop <trophyItem>5__17;

			private CreatureDataDump <data>5__18;

			private List<Drop>.Enumerator <>s__19;

			private Drop <drop>5__20;

			private string <targetFile>5__21;

			private string <targetObjPath>5__22;

			private string <jsonOutput>5__23;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ExportCreaturesCoroutine>d__0(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<creaturesFolder>5__1 = null;
				<iconsFolder>5__2 = null;
				<prefabsFolder>5__3 = null;
				<modelsFolder>5__4 = null;
				<texturesFolder>5__5 = null;
				<allPrefabs>5__6 = null;
				<exportedCreatures>5__7 = null;
				<prefab>5__10 = null;
				<character>5__11 = null;
				<prefabName>5__12 = null;
				<creatureRawName>5__13 = null;
				<dropComponent>5__14 = null;
				<>s__15 = default(List<Drop>.Enumerator);
				<drop>5__16 = null;
				<trophyItem>5__17 = null;
				<data>5__18 = null;
				<>s__19 = default(List<Drop>.Enumerator);
				<drop>5__20 = null;
				<targetFile>5__21 = null;
				<targetObjPath>5__22 = null;
				<jsonOutput>5__23 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<creaturesFolder>5__1 = Path.Combine(baseFolder, "data", "creatures");
					<iconsFolder>5__2 = Path.Combine(baseFolder, "icons");
					<prefabsFolder>5__3 = Path.Combine(baseFolder, "prefabs", "creatures");
					<modelsFolder>5__4 = Path.Combine(baseFolder, "models", "creatures");
					<texturesFolder>5__5 = Path.Combine(baseFolder, "textures", "creatures");
					if (exportJson)
					{
						Directory.CreateDirectory(<creaturesFolder>5__1);
					}
					if (exportIcons)
					{
						Directory.CreateDirectory(<iconsFolder>5__2);
					}
					if (exportPrefab)
					{
						Directory.CreateDirectory(<prefabsFolder>5__3);
					}
					if (exportModel3d)
					{
						Directory.CreateDirectory(<modelsFolder>5__4);
						Directory.CreateDirectory(<texturesFolder>5__5);
					}
					<allPrefabs>5__6 = ZNetScene.instance.m_prefabs;
					<exportedCreatures>5__7 = new List<CreatureDataDump>();
					args.Context.AddString($"<color=yellow>[Valheim DBDumper] Scanning {<allPrefabs>5__6.Count} game prefabs for creatures...</color>");
					LogSystem.Info($"Scanning {<allPrefabs>5__6.Count} game prefabs for creatures...");
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<operationsThisFrame>5__8 = 0;
					<i>5__9 = 0;
					goto IL_0785;
				case 2:
					{
						<>1__state = -1;
						goto IL_074f;
					}
					IL_0785:
					if (<i>5__9 < <allPrefabs>5__6.Count)
					{
						<prefab>5__10 = <allPrefabs>5__6[<i>5__9];
						if (!((Object)(object)<prefab>5__10 == (Object)null))
						{
							<character>5__11 = <prefab>5__10.GetComponent<Character>();
							if (!((Object)(object)<character>5__11 == (Object)null))
							{
								<prefabName>5__12 = ((Object)<prefab>5__10).name;
								<creatureRawName>5__13 = <character>5__11.m_name;
								if (!<prefabName>5__12.ToLower().Contains("player"))
								{
									<dropComponent>5__14 = <prefab>5__10.GetComponent<CharacterDrop>();
									if (exportIcons && (Object)(object)<dropComponent>5__14 != (Object)null && <dropComponent>5__14.m_drops != null)
									{
										Directory.CreateDirectory(Path.Combine(<iconsFolder>5__2, "Creatures"));
										<>s__15 = <dropComponent>5__14.m_drops.GetEnumerator();
										try
										{
											while (<>s__15.MoveNext())
											{
												<drop>5__16 = <>s__15.Current;
												if ((Object)(object)<drop>5__16.m_prefab != (Object)null && ((Object)<drop>5__16.m_prefab).name.ToLower().Contains("trophy"))
												{
													<trophyItem>5__17 = <drop>5__16.m_prefab.GetComponent<ItemDrop>();
													if ((Object)(object)<trophyItem>5__17 != (Object)null)
													{
														ItemData itemData = <trophyItem>5__17.m_itemData;
														if (itemData != null && itemData.m_shared?.m_icons?.Length > 0)
														{
															SaveCroppedSpriteAsPNG(<trophyItem>5__17.m_itemData.m_shared.m_icons[0], Path.Combine(<iconsFolder>5__2, "Creatures", <prefabName>5__12 + ".png"));
															<operationsThisFrame>5__8++;
															break;
														}
													}
													<trophyItem>5__17 = null;
												}
												<drop>5__16 = null;
											}
										}
										finally
										{
											((IDisposable)<>s__15).Dispose();
										}
										<>s__15 = default(List<Drop>.Enumerator);
									}
									if (exportJson)
									{
										<data>5__18 = new CreatureDataDump
										{
											prefab_name = <prefabName>5__12,
											creature_name = TranslateToken(<creatureRawName>5__13),
											creature_rawName = <creatureRawName>5__13,
											max_health = <character>5__11.m_health,
											faction = ((object)(Faction)(ref <character>5__11.m_faction)).ToString(),
											tolerate_water = <character>5__11.m_tolerateWater,
											tolerate_fire = <character>5__11.m_tolerateFire
										};
										if ((Object)(object)<dropComponent>5__14 != (Object)null && <dropComponent>5__14.m_drops != null)
										{
											<>s__19 = <dropComponent>5__14.m_drops.GetEnumerator();
											try
											{
												while (<>s__19.MoveNext())
												{
													<drop>5__20 = <>s__19.Current;
													if (<drop>5__20 != null && !((Object)(object)<drop>5__20.m_prefab == (Object)null))
													{
														<data>5__18.drops.Add(new CreatureDropData
														{
															item_prefab = ((Object)<drop>5__20.m_prefab).name,
															min_amount = <drop>5__20.m_amountMin,
															max_amount = <drop>5__20.m_amountMax,
															chance_percent = <drop>5__20.m_chance * 100f,
															level_multiplier = <drop>5__20.m_levelMultiplier
														});
														<drop>5__20 = null;
													}
												}
											}
											finally
											{
												((IDisposable)<>s__19).Dispose();
											}
											<>s__19 = default(List<Drop>.Enumerator);
										}
										<exportedCreatures>5__7.Add(<data>5__18);
										<data>5__18 = null;
									}
									if (exportPrefab)
									{
										<targetFile>5__21 = Path.Combine(<prefabsFolder>5__3, <prefabName>5__12 + ".json");
										DumpPrefabHierarchyToJson(<prefab>5__10, <targetFile>5__21);
										<operationsThisFrame>5__8++;
										<targetFile>5__21 = null;
									}
									if (exportModel3d)
									{
										<targetObjPath>5__22 = Path.Combine(<modelsFolder>5__4, <prefabName>5__12 + ".obj");
										ExportPrefabToObj(<prefab>5__10, <targetObjPath>5__22);
										ExportCreatureSkinTexture(<prefab>5__10, <texturesFolder>5__5, <prefabName>5__12);
										<operationsThisFrame>5__8++;
										<targetObjPath>5__22 = null;
									}
									if (<exportedCreatures>5__7.Count % 20 == 0)
									{
										args.Context.AddString($"<color=#00FFD9>[Valheim DBDumper] Processed {<exportedCreatures>5__7.Count} unique creatures...</color>");
									}
									if (<operationsThisFrame>5__8 >= 30)
									{
										<operationsThisFrame>5__8 = 0;
										<>2__current = null;
										<>1__state = 2;
										return true;
									}
									goto IL_074f;
								}
							}
						}
						goto IL_0773;
					}
					if (exportJson && <exportedCreatures>5__7.Count > 0)
					{
						<jsonOutput>5__23 = JsonConvert.SerializeObject((object)<exportedCreatures>5__7, (Formatting)1);
						File.WriteAllText(Path.Combine(<creaturesFolder>5__1, "creatures.json"), <jsonOutput>5__23);
						<jsonOutput>5__23 = null;
					}
					args.Context.AddString("<color=green>[Valheim DBDumper] Creatures module finished! Geometries and skin textures successfully dumped.</color>");
					LogSystem.Success("Creatures module finished! Geometries and skin textures successfully dumped.");
					onFinished?.Invoke();
					return false;
					IL_0773:
					<i>5__9++;
					goto IL_0785;
					IL_074f:
					<prefab>5__10 = null;
					<character>5__11 = null;
					<prefabName>5__12 = null;
					<creatureRawName>5__13 = null;
					<dropComponent>5__14 = null;
					goto IL_0773;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[IteratorStateMachine(typeof(<ExportCreaturesCoroutine>d__0))]
		public static IEnumerator ExportCreaturesCoroutine(string baseFolder, ConsoleEventArgs args, bool exportJson, bool exportIcons, bool exportPrefab, bool exportModel3d, Action onFinished)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ExportCreaturesCoroutine>d__0(0)
			{
				baseFolder = baseFolder,
				args = args,
				exportJson = exportJson,
				exportIcons = exportIcons,
				exportPrefab = exportPrefab,
				exportModel3d = exportModel3d,
				onFinished = onFinished
			};
		}

		private static void ExportCreatureSkinTexture(GameObject prefab, string texturesFolder, string prefabName)
		{
			string text = Path.Combine(texturesFolder, prefabName + ".png");
			if (File.Exists(text))
			{
				return;
			}
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			Renderer[] array = componentsInChildren;
			foreach (Renderer val in array)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.material == (Object)null))
				{
					Texture val2 = val.material.mainTexture;
					if ((Object)(object)val2 == (Object)null && val.material.HasProperty("_MainTex"))
					{
						val2 = val.material.GetTexture("_MainTex");
					}
					if ((Object)(object)val2 != (Object)null && val2.width > 32 && val2.height > 32)
					{
						SaveRuntimeTextureAsPNG(val2, text);
						break;
					}
				}
			}
		}

		private static void SaveRuntimeTextureAsPNG(Texture srcTexture, string outputPath)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				int width = srcTexture.width;
				int height = srcTexture.height;
				RenderTexture temporary = RenderTexture.GetTemporary(width, height, 0, (RenderTextureFormat)7, (RenderTextureReadWrite)1);
				Graphics.Blit(srcTexture, temporary);
				RenderTexture active = RenderTexture.active;
				RenderTexture.active = temporary;
				Texture2D val = new Texture2D(width, height, (TextureFormat)4, false);
				val.ReadPixels(new Rect(0f, 0f, (float)width, (float)height), 0, 0);
				val.Apply();
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
				byte[] bytes = ImageConversion.EncodeToPNG(val);
				File.WriteAllBytes(outputPath, bytes);
				Object.Destroy((Object)(object)val);
			}
			catch (Exception ex)
			{
				LogSystem.Error("Error saving creature skin texture: " + ex.Message + "\n");
			}
		}

		private static void DumpPrefabHierarchyToJson(GameObject prefab, string outputPath)
		{
			try
			{
				PrefabNode prefabNode = BuildPrefabNodeElement(prefab.transform);
				string contents = JsonConvert.SerializeObject((object)prefabNode, (Formatting)1);
				File.WriteAllText(outputPath, contents);
			}
			catch (Exception ex)
			{
				LogSystem.Error("Error dumping prefab hierarchy: " + ex.Message);
			}
		}

		private static PrefabNode BuildPrefabNodeElement(Transform current)
		{
			PrefabNode prefabNode = new PrefabNode
			{
				object_name = ((Object)current).name,
				is_active = ((Component)current).gameObject.activeSelf,
				layer = LayerMask.LayerToName(((Component)current).gameObject.layer),
				tag = ((Component)current).gameObject.tag
			};
			Component[] components = ((Component)current).GetComponents<Component>();
			Component[] array = components;
			foreach (Component val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				ComponentData componentData = new ComponentData
				{
					type = ((object)val).GetType().Name
				};
				if (val is Character || val is Humanoid || val is MonsterAI)
				{
					FieldInfo[] fields = ((object)val).GetType().GetFields(BindingFlags.Instance | BindingFlags.Public);
					FieldInfo[] array2 = fields;
					foreach (FieldInfo fieldInfo in array2)
					{
						try
						{
							object value = fieldInfo.GetValue(val);
							if (value != null && !(value is GameObject) && !(value is Component))
							{
								componentData.fields[fieldInfo.Name] = value.ToString();
							}
						}
						catch (Exception ex)
						{
							LogSystem.Error("Error getting field value: " + ex.Message);
						}
					}
				}
				prefabNode.components.Add(componentData);
			}
			for (int k = 0; k < current.childCount; k++)
			{
				prefabNode.children.Add(BuildPrefabNodeElement(current.GetChild(k)));
			}
			return prefabNode;
		}

		private static void ExportPrefabToObj(GameObject prefab, string outputPath)
		{
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//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_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			if (File.Exists(outputPath))
			{
				return;
			}
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("# Valheim DBDumper - 3D Mesh of " + ((Object)prefab).name);
				int vOffset = 1;
				int nOffset = 1;
				int uvOffset = 1;
				Matrix4x4 worldToLocalMatrix = prefab.transform.worldToLocalMatrix;
				SkinnedMeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren<SkinnedMeshRenderer>(true);
				SkinnedMeshRenderer[] array = componentsInChildren;
				foreach (SkinnedMeshRenderer val in array)
				{
					if ((Object)(object)val == (Object)null || (Object)(object)val.sharedMesh == (Object)null)
					{
						continue;
					}
					Mesh val2 = new Mesh();
					try
					{
						val.BakeMesh(val2);
						Matrix4x4 localToRoot = worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix;
						ProcessMeshAsset(val2, ((Object)val).name, stringBuilder, localToRoot, ref vOffset, ref nOffset, ref uvOffset);
					}
					catch (Exception ex)
					{
						LogSystem.Warn("Error baking mesh: " + ex.Message);
						Matrix4x4 localToRoot2 = worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix;
						ProcessMeshAsset(val.sharedMesh, ((Object)val).name, stringBuilder, localToRoot2, ref vOffset, ref nOffset, ref uvOffset);
					}
					finally
					{
						if ((Object)(object)val2 != (Object)null)
						{
							Object.Destroy((Object)(object)val2);
						}
					}
				}
				MeshFilter[] componentsInChildren2 = prefab.GetComponentsInChildren<MeshFilter>(true);
				MeshFilter[] array2 = componentsInChildren2;
				foreach (MeshFilter val3 in array2)
				{
					if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3.sharedMesh == (Object)null))
					{
						Matrix4x4 localToRoot3 = worldToLocalMatrix * ((Component)val3).transform.localToWorldMatrix;
						ProcessMeshAsset(val3.sharedMesh, ((Object)val3).name, stringBuilder, localToRoot3, ref vOffset, ref nOffset, ref uvOffset);
					}
				}
				if (vOffset > 1)
				{
					File.WriteAllText(outputPath, stringBuilder.ToString());
				}
			}
			catch (Exception ex2)
			{
				LogSystem.Error("Error exporting prefab to OBJ: " + ex2.Message);
			}
		}

		private static void ProcessMeshAsset(Mesh mesh, string name, StringBuilder sb, Matrix4x4 localToRoot, ref int vOffset, ref int nOffset, ref int uvOffset)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_004c: 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_0092: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: 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)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			sb.AppendLine("\ng " + name);
			Vector3[] vertices = mesh.vertices;
			Vector3[] array = vertices;
			foreach (Vector3 val in array)
			{
				Vector3 val2 = ((Matrix4x4)(ref localToRoot)).MultiplyPoint3x4(val);
				sb.AppendLine($"v {val2.x} {val2.y} {val2.z}");
			}
			Vector2[] uv = mesh.uv;
			Vector2[] array2 = uv;
			foreach (Vector2 val3 in array2)
			{
				sb.AppendLine($"vt {val3.x} {val3.y}");
			}
			Vector3[] normals = mesh.normals;
			Vector3[] array3 = normals;
			foreach (Vector3 val4 in array3)
			{
				Vector3 val5 = ((Matrix4x4)(ref localToRoot)).MultiplyVector(val4);
				Vector3 normalized = ((Vector3)(ref val5)).normalized;
				sb.AppendLine($"vn {normalized.x} {normalized.y} {normalized.z}");
			}
			bool flag = uv.Length != 0;
			bool flag2 = normals.Length != 0;
			for (int l = 0; l < mesh.subMeshCount; l++)
			{
				int[] triangles = mesh.GetTriangles(l);
				for (int m = 0; m < triangles.Length; m += 3)
				{
					int num = triangles[m] + vOffset;
					int num2 = triangles[m + 1] + vOffset;
					int num3 = triangles[m + 2] + vOffset;
					int num4 = triangles[m] + uvOffset;
					int num5 = triangles[m + 1] + uvOffset;
					int num6 = triangles[m + 2] + uvOffset;
					int num7 = triangles[m] + nOffset;
					int num8 = triangles[m + 1] + nOffset;
					int num9 = triangles[m + 2] + nOffset;
					if (flag && flag2)
					{
						sb.AppendLine($"f {num3}/{num6}/{num9} {num2}/{num5}/{num8} {num}/{num4}/{num7}");
					}
					else if (flag)
					{
						sb.AppendLine($"f {num3}/{num6} {num2}/{num5} {num}/{num4}");
					}
					else if (flag2)
					{
						sb.AppendLine($"f {num3}//{num9} {num2}//{num8} {num}//{num7}");
					}
					else
					{
						sb.AppendLine($"f {num3} {num2} {num}");
					}
				}
			}
			vOffset += vertices.Length;
			uvOffset += uv.Length;
			nOffset += normals.Length;
		}

		private static string TranslateToken(string token)
		{
			if (string.IsNullOrEmpty(token))
			{
				return "";
			}
			if (!token.StartsWith("$"))
			{
				return token;
			}
			try
			{
				Type type = typeof(Terminal).Assembly.GetType("Localization") ?? Type.GetType("Valheim.Localization, assembly_valheim");
				if (type == null)
				{
					return token;
				}
				object obj = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
				if (obj == null)
				{
					return token;
				}
				return (type.GetMethod("Localize", new Type[1] { typeof(string) })?.Invoke(obj, new object[1] { token }) as string) ?? token;
			}
			catch (Exception ex)
			{
				LogSystem.Error("Error translating token: " + ex.Message);
				return token;
			}
		}

		private static void SaveCroppedSpriteAsPNG(Sprite sprite, string outputPath)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			if (File.Exists(outputPath))
			{
				return;
			}
			try
			{
				Texture2D texture = sprite.texture;
				if (!((Object)(object)texture == (Object)null))
				{
					Rect textureRect = sprite.textureRect;
					int num = (int)((Rect)(ref textureRect)).width;
					int num2 = (int)((Rect)(ref textureRect)).height;
					RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0, (RenderTextureFormat)7, (RenderTextureReadWrite)1);
					Graphics.Blit((Texture)(object)texture, temporary);
					RenderTexture active = RenderTexture.active;
					RenderTexture.active = temporary;
					Texture2D val = new Texture2D(num, num2, (TextureFormat)4, false);
					val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)num, (float)num2), 0, 0);
					val.Apply();
					RenderTexture.active = active;
					RenderTexture.ReleaseTemporary(temporary);
					byte[] bytes = ImageConversion.EncodeToPNG(val);
					File.WriteAllBytes(outputPath, bytes);
					Object.Destroy((Object)(object)val);
				}
			}
			catch (Exception ex)
			{
				LogSystem.Error("Error saving creature skin texture: " + ex.Message);
			}
		}
	}
	public class ItemDataDump
	{
		public string prefab_name { get; set; }

		public string item_name { get; set; }

		public string item_rawName { get; set; }

		public string description { get; set; }

		public string type { get; set; }

		public float weight { get; set; }

		public int max_stack { get; set; }

		public float max_durability { get; set; }

		public float armor { get; set; }

		public float blunt_damage { get; set; }

		public float slash_damage { get; set; }

		public float pierce_damage { get; set; }

		public float chop_damage { get; set; }

		public float pickaxe_damage { get; set; }

		public float fire_damage { get; set; }

		public float frost_damage { get; set; }

		public float lightning_damage { get; set; }

		public float poison_damage { get; set; }

		public float spirit_damage { get; set; }
	}
	public static class ItemsExporter
	{
		[CompilerGenerated]
		private sealed class <ExportItemsCoroutine>d__0 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string baseFolder;

			public ConsoleEventArgs args;

			public bool exportJson;

			public bool exportIcons;

			public bool exportPrefab;

			public bool exportModel3d;

			public Action onFinished;

			private string <itemsFolder>5__1;

			private string <iconsFolder>5__2;

			private string <prefabsFolder>5__3;

			private string <modelsFolder>5__4;

			private string <texturesFolder>5__5;

			private List<GameObject> <itemPrefabs>5__6;

			private List<ItemDataDump> <exportedItems>5__7;

			private int <operationsThisFrame>5__8;

			private int <i>5__9;

			private GameObject <prefab>5__10;

			private ItemDrop <itemDrop>5__11;

			private SharedData <shared>5__12;

			private string <prefabName>5__13;

			private Sprite[] <iconsArray>5__14;

			private ItemDataDump <data>5__15;

			private string <targetFile>5__16;

			private string <targetObjPath>5__17;

			private string <jsonOutput>5__18;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ExportItemsCoroutine>d__0(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<itemsFolder>5__1 = null;
				<iconsFolder>5__2 = null;
				<prefabsFolder>5__3 = null;
				<modelsFolder>5__4 = null;
				<texturesFolder>5__5 = null;
				<itemPrefabs>5__6 = null;
				<exportedItems>5__7 = null;
				<prefab>5__10 = null;
				<itemDrop>5__11 = null;
				<shared>5__12 = null;
				<prefabName>5__13 = null;
				<iconsArray>5__14 = null;
				<data>5__15 = null;
				<targetFile>5__16 = null;
				<targetObjPath>5__17 = null;
				<jsonOutput>5__18 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<itemsFolder>5__1 = Path.Combine(baseFolder, "data", "items");
					<iconsFolder>5__2 = Path.Combine(baseFolder, "icons");
					<prefabsFolder>5__3 = Path.Combine(baseFolder, "prefabs", "items");
					<modelsFolder>5__4 = Path.Combine(baseFolder, "models", "items");
					<texturesFolder>5__5 = Path.Combine(baseFolder, "textures", "items");
					if (exportJson)
					{
						Directory.CreateDirectory(<itemsFolder>5__1);
					}
					if (exportIcons)
					{
						Directory.CreateDirectory(<iconsFolder>5__2);
					}
					if (exportPrefab)
					{
						Directory.CreateDirectory(<prefabsFolder>5__3);
					}
					if (exportModel3d)
					{
						Directory.CreateDirectory(<modelsFolder>5__4);
						Directory.CreateDirectory(<texturesFolder>5__5);
					}
					<itemPrefabs>5__6 = ObjectDB.instance.m_items;
					<exportedItems>5__7 = new List<ItemDataDump>();
					args.Context.AddString($"<color=yellow>[Valheim DBDumper] Processing {<itemPrefabs>5__6.Count} items into unified pipeline...</color>");
					LogSystem.Info($"Processing {<itemPrefabs>5__6.Count} items into unified pipeline...");
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<operationsThisFrame>5__8 = 0;
					<i>5__9 = 0;
					goto IL_0639;
				case 2:
					{
						<>1__state = -1;
						goto IL_060a;
					}
					IL_0639:
					if (<i>5__9 < <itemPrefabs>5__6.Count)
					{
						<prefab>5__10 = <itemPrefabs>5__6[<i>5__9];
						if (!((Object)(object)<prefab>5__10 == (Object)null))
						{
							<itemDrop>5__11 = <prefab>5__10.GetComponent<ItemDrop>();
							if (!((Object)(object)<itemDrop>5__11 == (Object)null) && <itemDrop>5__11.m_itemData != null)
							{
								<shared>5__12 = <itemDrop>5__11.m_itemData.m_shared;
								<prefabName>5__13 = ((Object)<prefab>5__10).name;
								if (exportIcons)
								{
									Directory.CreateDirectory(Path.Combine(<iconsFolder>5__2, "Items"));
									<iconsArray>5__14 = <shared>5__12.m_icons;
									if (<iconsArray>5__14 != null && <iconsArray>5__14.Length != 0 && (Object)(object)<iconsArray>5__14[0] != (Object)null)
									{
										SaveCroppedSpriteAsPNG(<iconsArray>5__14[0], Path.Combine(<iconsFolder>5__2, "Items", <prefabName>5__13 + ".png"));
										<operationsThisFrame>5__8++;
									}
									<iconsArray>5__14 = null;
								}
								if (exportJson)
								{
									<data>5__15 = new ItemDataDump
									{
										prefab_name = <prefabName>5__13,
										item_name = TranslateToken(<shared>5__12.m_name),
										item_rawName = <shared>5__12.m_name,
										description = TranslateToken(<shared>5__12.m_description),
										type = ((object)(ItemType)(ref <shared>5__12.m_itemType)).ToString(),
										weight = <shared>5__12.m_weight,
										max_stack = <shared>5__12.m_maxStackSize,
										max_durability = <shared>5__12.m_maxDurability,
										armor = <shared>5__12.m_armor,
										blunt_damage = <shared>5__12.m_damages.m_blunt,
										slash_damage = <shared>5__12.m_damages.m_slash,
										pierce_damage = <shared>5__12.m_damages.m_pierce,
										chop_damage = <shared>5__12.m_damages.m_chop,
										pickaxe_damage = <shared>5__12.m_damages.m_pickaxe,
										fire_damage = <shared>5__12.m_damages.m_fire,
										frost_damage = <shared>5__12.m_damages.m_frost,
										lightning_damage = <shared>5__12.m_damages.m_lightning,
										poison_damage = <shared>5__12.m_damages.m_poison,
										spirit_damage = <shared>5__12.m_damages.m_spirit
									};
									<exportedItems>5__7.Add(<data>5__15);
									<data>5__15 = null;
								}
								if (exportPrefab)
								{
									<targetFile>5__16 = Path.Combine(<prefabsFolder>5__3, <prefabName>5__13 + ".json");
									DumpPrefabHierarchyToJson(<prefab>5__10, <targetFile>5__16);
									<operationsThisFrame>5__8++;
									<targetFile>5__16 = null;
								}
								if (exportModel3d)
								{
									<targetObjPath>5__17 = Path.Combine(<modelsFolder>5__4, <prefabName>5__13 + ".obj");
									ExportPrefabToObj(<prefab>5__10, <targetObjPath>5__17);
									ExportItemSkinTexture(<prefab>5__10, <texturesFolder>5__5, <prefabName>5__13);
									<operationsThisFrame>5__8++;
									<targetObjPath>5__17 = null;
								}
								if (<i>5__9 > 0 && <i>5__9 % 150 == 0)
								{
									args.Context.AddString($"<color=lightblue>[Valheim DBDumper] Processed {<i>5__9}/{<itemPrefabs>5__6.Count} unique items...</color>");
								}
								if (<operationsThisFrame>5__8 >= 25)
								{
									<operationsThisFrame>5__8 = 0;
									<>2__current = null;
									<>1__state = 2;
									return true;
								}
								goto IL_060a;
							}
						}
						goto IL_0627;
					}
					if (exportJson && <exportedItems>5__7.Count > 0)
					{
						<jsonOutput>5__18 = JsonConvert.SerializeObject((object)<exportedItems>5__7, (Formatting)1);
						File.WriteAllText(Path.Combine(<itemsFolder>5__1, "items.json"), <jsonOutput>5__18);
						<jsonOutput>5__18 = null;
					}
					args.Context.AddString("<color=green>[Valheim DBDumper] Item module finished processing successfully! Models and textures sync'd.</color>");
					LogSystem.Success("Item module finished processing successfully! Models and textures sync'd.");
					onFinished?.Invoke();
					return false;
					IL_060a:
					<prefab>5__10 = null;
					<itemDrop>5__11 = null;
					<shared>5__12 = null;
					<prefabName>5__13 = null;
					goto IL_0627;
					IL_0627:
					<i>5__9++;
					goto IL_0639;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[IteratorStateMachine(typeof(<ExportItemsCoroutine>d__0))]
		public static IEnumerator ExportItemsCoroutine(string baseFolder, ConsoleEventArgs args, bool exportJson, bool exportIcons, bool exportPrefab, bool exportModel3d, Action onFinished)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ExportItemsCoroutine>d__0(0)
			{
				baseFolder = baseFolder,
				args = args,
				exportJson = exportJson,
				exportIcons = exportIcons,
				exportPrefab = exportPrefab,
				exportModel3d = exportModel3d,
				onFinished = onFinished
			};
		}

		private static void DumpPrefabHierarchyToJson(GameObject prefab, string outputPath)
		{
			try
			{
				PrefabNode prefabNode = BuildPrefabNodeElement(prefab.transform);
				string contents = JsonConvert.SerializeObject((object)prefabNode, (Formatting)1);
				File.WriteAllText(outputPath, contents);
			}
			catch (Exception ex)
			{
				LogSystem.Error("Error dumping prefab hierarchy: " + ex.Message);
			}
		}

		private static PrefabNode BuildPrefabNodeElement(Transform current)
		{
			PrefabNode prefabNode = new PrefabNode
			{
				object_name = ((Object)current).name,
				is_active = ((Component)current).gameObject.activeSelf,
				layer = LayerMask.LayerToName(((Component)current).gameObject.layer),
				tag = ((Component)current).gameObject.tag
			};
			Component[] components = ((Component)current).GetComponents<Component>();
			Component[] array = components;
			foreach (Component val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				ComponentData componentData = new ComponentData
				{
					type = ((object)val).GetType().Name
				};
				if (val is ItemDrop)
				{
					FieldInfo[] fields = ((object)val).GetType().GetFields(BindingFlags.Instance | BindingFlags.Public);
					FieldInfo[] array2 = fields;
					foreach (FieldInfo fieldInfo in array2)
					{
						try
						{
							object value = fieldInfo.GetValue(val);
							if (value != null && !(value is GameObject) && !(value is Component))
							{
								componentData.fields[fieldInfo.Name] = value.ToString();
							}
						}
						catch (Exception ex)
						{
							LogSystem.Error("Error dumping prefab hierarchy: " + ex.Message);
						}
					}
				}
				prefabNode.components.Add(componentData);
			}
			for (int k = 0; k < current.childCount; k++)
			{
				prefabNode.children.Add(BuildPrefabNodeElement(current.GetChild(k)));
			}
			return prefabNode;
		}

		private static void ExportPrefabToObj(GameObject prefab, string outputPath)
		{
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: 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_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//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_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: 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_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b1: Unknown result type (might be due to invalid IL or missing references)
			if (File.Exists(outputPath))
			{
				return;
			}
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("# Valheim DBDumper - 3D Mesh of Item: " + ((Object)prefab).name);
				int vOffset = 1;
				int nOffset = 1;
				int uvOffset = 1;
				Matrix4x4 worldToLocalMatrix = prefab.transform.worldToLocalMatrix;
				SkinnedMeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren<SkinnedMeshRenderer>(true);
				SkinnedMeshRenderer[] array = componentsInChildren;
				foreach (SkinnedMeshRenderer val in array)
				{
					if ((Object)(object)val == (Object)null || (Object)(object)val.sharedMesh == (Object)null)
					{
						continue;
					}
					Mesh val2 = new Mesh();
					try
					{
						val.BakeMesh(val2);
						Matrix4x4 localToRoot = worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix;
						ProcessMeshAsset(val2, ((Object)val).name, stringBuilder, localToRoot, ref vOffset, ref nOffset, ref uvOffset);
					}
					catch (Exception ex)
					{
						LogSystem.Warn("Error processing mesh " + ((Object)val).name + ": " + ex.Message);
						Matrix4x4 localToRoot2 = worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix;
						ProcessMeshAsset(val.sharedMesh, ((Object)val).name, stringBuilder, localToRoot2, ref vOffset, ref nOffset, ref uvOffset);
					}
					finally
					{
						if ((Object)(object)val2 != (Object)null)
						{
							Object.Destroy((Object)(object)val2);
						}
					}
				}
				MeshFilter[] componentsInChildren2 = prefab.GetComponentsInChildren<MeshFilter>(true);
				MeshFilter[] array2 = componentsInChildren2;
				foreach (MeshFilter val3 in array2)
				{
					if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3.sharedMesh == (Object)null))
					{
						Matrix4x4 localToRoot3 = worldToLocalMatrix * ((Component)val3).transform.localToWorldMatrix;
						ProcessMeshAsset(val3.sharedMesh, ((Object)val3).name, stringBuilder, localToRoot3, ref vOffset, ref nOffset, ref uvOffset);
					}
				}
				if (vOffset > 1)
				{
					File.WriteAllText(outputPath, stringBuilder.ToString());
				}
			}
			catch (Exception ex2)
			{
				LogSystem.Error("Error exporting prefab to OBJ: " + ex2.Message);
			}
		}

		private static void ProcessMeshAsset(Mesh mesh, string name, StringBuilder sb, Matrix4x4 localToRoot, ref int vOffset, ref int nOffset, ref int uvOffset)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_004c: 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_0092: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: 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)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			sb.AppendLine("\ng " + name);
			Vector3[] vertices = mesh.vertices;
			Vector3[] array = vertices;
			foreach (Vector3 val in array)
			{
				Vector3 val2 = ((Matrix4x4)(ref localToRoot)).MultiplyPoint3x4(val);
				sb.AppendLine($"v {val2.x} {val2.y} {val2.z}");
			}
			Vector2[] uv = mesh.uv;
			Vector2[] array2 = uv;
			foreach (Vector2 val3 in array2)
			{
				sb.AppendLine($"vt {val3.x} {val3.y}");
			}
			Vector3[] normals = mesh.normals;
			Vector3[] array3 = normals;
			foreach (Vector3 val4 in array3)
			{
				Vector3 val5 = ((Matrix4x4)(ref localToRoot)).MultiplyVector(val4);
				Vector3 normalized = ((Vector3)(ref val5)).normalized;
				sb.AppendLine($"vn {normalized.x} {normalized.y} {normalized.z}");
			}
			bool flag = uv.Length != 0;
			bool flag2 = normals.Length != 0;
			for (int l = 0; l < mesh.subMeshCount; l++)
			{
				int[] triangles = mesh.GetTriangles(l);
				for (int m = 0; m < triangles.Length; m += 3)
				{
					int num = triangles[m] + vOffset;
					int num2 = triangles[m + 1] + vOffset;
					int num3 = triangles[m + 2] + vOffset;
					int num4 = triangles[m] + uvOffset;
					int num5 = triangles[m + 1] + uvOffset;
					int num6 = triangles[m + 2] + uvOffset;
					int num7 = triangles[m] + nOffset;
					int num8 = triangles[m + 1] + nOffset;
					int num9 = triangles[m + 2] + nOffset;
					if (flag && flag2)
					{
						sb.AppendLine($"f {num3}/{num6}/{num9} {num2}/{num5}/{num8} {num}/{num4}/{num7}");
					}
					else if (flag)
					{
						sb.AppendLine($"f {num3}/{num6} {num2}/{num5} {num}/{num4}");
					}
					else if (flag2)
					{
						sb.AppendLine($"f {num3}//{num9} {num2}//{num8} {num}//{num7}");
					}
					else
					{
						sb.AppendLine($"f {num3} {num2} {num}");
					}
				}
			}
			vOffset += vertices.Length;
			uvOffset += uv.Length;
			nOffset += normals.Length;
		}

		private static void ExportItemSkinTexture(GameObject prefab, string texturesFolder, string prefabName)
		{
			string text = Path.Combine(texturesFolder, prefabName + ".png");
			if (File.Exists(text))
			{
				return;
			}
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			Renderer[] array = componentsInChildren;
			foreach (Renderer val in array)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.material == (Object)null))
				{
					Texture val2 = val.material.mainTexture;
					if ((Object)(object)val2 == (Object)null && val.material.HasProperty("_MainTex"))
					{
						val2 = val.material.GetTexture("_MainTex");
					}
					if ((Object)(object)val2 != (Object)null && val2.width > 32 && val2.height > 32)
					{
						SaveRuntimeTextureAsPNG(val2, text);
						break;
					}
				}
			}
		}

		private static void SaveRuntimeTextureAsPNG(Texture srcTexture, string outputPath)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				int width = srcTexture.width;
				int height = srcTexture.height;
				RenderTexture temporary = RenderTexture.GetTemporary(width, height, 0, (RenderTextureFormat)7, (RenderTextureReadWrite)1);
				Graphics.Blit(srcTexture, temporary);
				RenderTexture active = RenderTexture.active;
				RenderTexture.active = temporary;
				Texture2D val = new Texture2D(width, height, (TextureFormat)4, false);
				val.ReadPixels(new Rect(0f, 0f, (float)width, (float)height), 0, 0);
				val.Apply();
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
				byte[] bytes = ImageConversion.EncodeToPNG(val);
				File.WriteAllBytes(outputPath, bytes);
				Object.Destroy((Object)(object)val);
			}
			catch (Exception ex)
			{
				LogSystem.Error("Failed to export " + outputPath + ": " + ex.Message);
			}
		}

		private static string TranslateToken(string token)
		{
			if (string.IsNullOrEmpty(token))
			{
				return "";
			}
			if (!token.StartsWith("$"))
			{
				return token;
			}
			try
			{
				Type type = typeof(Terminal).Assembly.GetType("Localization") ?? Type.GetType("Valheim.Localization, assembly_valheim");
				if (type == null)
				{
					return token;
				}
				object obj = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
				if (obj == null)
				{
					return token;
				}
				return (type.GetMethod("Localize", new Type[1] { typeof(string) })?.Invoke(obj, new object[1] { token }) as string) ?? token;
			}
			catch (Exception ex)
			{
				LogSystem.Error("Error translating token: " + ex.Message);
				return token;
			}
		}

		private static void SaveCroppedSpriteAsPNG(Sprite sprite, string outputPath)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			if (File.Exists(outputPath))
			{
				return;
			}
			try
			{
				Texture2D texture = sprite.texture;
				if (!((Object)(object)texture == (Object)null))
				{
					Rect textureRect = sprite.textureRect;
					int num = (int)((Rect)(ref textureRect)).width;
					int num2 = (int)((Rect)(ref textureRect)).height;
					RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0, (RenderTextureFormat)7, (RenderTextureReadWrite)1);
					Graphics.Blit((Texture)(object)texture, temporary);
					RenderTexture active = RenderTexture.active;
					RenderTexture.active = temporary;
					Texture2D val = new Texture2D(num, num2, (TextureFormat)4, false);
					val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)num, (float)num2), 0, 0);
					val.Apply();
					RenderTexture.active = active;
					RenderTexture.ReleaseTemporary(temporary);
					byte[] bytes = ImageConversion.EncodeToPNG(val);
					File.WriteAllBytes(outputPath, bytes);
					Object.Destroy((Object)(object)val);
				}
			}
			catch (Exception ex)
			{
				LogSystem.Error("Failed to export " + outputPath + ": " + ex.Message);
			}
		}
	}
	public class PickableDataDump
	{
		public string prefab_name { get; set; }

		public string pickable_name { get; set; }

		public string pickable_rawName { get; set; }

		public string drop_item_prefab { get; set; }

		public int min_amount { get; set; }

		public int max_amount { get; set; }

		public int respawn_minutes { get; set; }
	}
	public static class PickablesExporter
	{
		[CompilerGenerated]
		private sealed class <ExportPickablesCoroutine>d__0 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string baseFolder;

			public ConsoleEventArgs args;

			public bool exportJson;

			public bool exportIcons;

			public bool exportPrefab;

			public bool exportModel3d;

			public Action onFinished;

			private string <pickablesFolder>5__1;

			private string <iconsFolder>5__2;

			private string <prefabsFolder>5__3;

			private string <modelsFolder>5__4;

			private string <texturesFolder>5__5;

			private List<GameObject> <allPrefabs>5__6;

			private List<PickableDataDump> <exportedPickables>5__7;

			private int <operationsThisFrame>5__8;

			private int <i>5__9;

			private GameObject <prefab>5__10;

			private Pickable <pickable>5__11;

			private string <prefabName>5__12;

			private GameObject <dropItemObj>5__13;

			private string <dropPrefabName>5__14;

			private ItemDrop <itemDrop>5__15;

			private string <rawName>5__16;

			private PickableDataDump <data>5__17;

			private string <targetFile>5__18;

			private string <targetObjPath>5__19;

			private string <jsonOutput>5__20;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ExportPickablesCoroutine>d__0(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<pickablesFolder>5__1 = null;
				<iconsFolder>5__2 = null;
				<prefabsFolder>5__3 = null;
				<modelsFolder>5__4 = null;
				<texturesFolder>5__5 = null;
				<allPrefabs>5__6 = null;
				<exportedPickables>5__7 = null;
				<prefab>5__10 = null;
				<pickable>5__11 = null;
				<prefabName>5__12 = null;
				<dropItemObj>5__13 = null;
				<dropPrefabName>5__14 = null;
				<itemDrop>5__15 = null;
				<rawName>5__16 = null;
				<data>5__17 = null;
				<targetFile>5__18 = null;
				<targetObjPath>5__19 = null;
				<jsonOutput>5__20 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<pickablesFolder>5__1 = Path.Combine(baseFolder, "data", "pickables");
					<iconsFolder>5__2 = Path.Combine(baseFolder, "icons");
					<prefabsFolder>5__3 = Path.Combine(baseFolder, "prefabs", "pickables");
					<modelsFolder>5__4 = Path.Combine(baseFolder, "models", "pickables");
					<texturesFolder>5__5 = Path.Combine(baseFolder, "textures", "pickables");
					if (exportJson)
					{
						Directory.CreateDirectory(<pickablesFolder>5__1);
					}
					if (exportIcons)
					{
						Directory.CreateDirectory(<iconsFolder>5__2);
					}
					if (exportPrefab)
					{
						Directory.CreateDirectory(<prefabsFolder>5__3);
					}
					if (exportModel3d)
					{
						Directory.CreateDirectory(<modelsFolder>5__4);
						Directory.CreateDirectory(<texturesFolder>5__5);
					}
					<allPrefabs>5__6 = ZNetScene.instance.m_prefabs;
					<exportedPickables>5__7 = new List<PickableDataDump>();
					args.Context.AddString($"<color=yellow>[Valheim DBDumper] Scanning {<allPrefabs>5__6.Count} game prefabs for pickables...</color>");
					LogSystem.Info($"Scanning {<allPrefabs>5__6.Count} game prefabs for pickables...");
					<>2__current = null;
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					<operationsThisFrame>5__8 = 0;
					<i>5__9 = 0;
					goto IL_05ad;
				case 2:
					{
						<>1__state = -1;
						goto IL_0577;
					}
					IL_05ad:
					if (<i>5__9 < <allPrefabs>5__6.Count)
					{
						<prefab>5__10 = <allPrefabs>5__6[<i>5__9];
						if (!((Object)(object)<prefab>5__10 == (Object)null))
						{
							<pickable>5__11 = <prefab>5__10.GetComponent<Pickable>();
							if (!((Object)(object)<pickable>5__11 == (Object)null))
							{
								<prefabName>5__12 = ((Object)<prefab>5__10).name;
								<dropItemObj>5__13 = <pickable>5__11.m_itemPrefab;
								<dropPrefabName>5__14 = (((Object)(object)<dropItemObj>5__13 != (Object)null) ? ((Object)<dropItemObj>5__13).name : "None");
								if (exportIcons && (Object)(object)<dropItemObj>5__13 != (Object)null)
								{
									Directory.CreateDirectory(Path.Combine(<iconsFolder>5__2, "Pickables"));
									<itemDrop>5__15 = <dropItemObj>5__13.GetComponent<ItemDrop>();
									if ((Object)(object)<itemDrop>5__15 != (Object)null)
									{
										ItemData itemData = <itemDrop>5__15.m_itemData;
										if (itemData != null && itemData.m_shared?.m_icons?.Length > 0)
										{
											SaveCroppedSpriteAsPNG(<itemDrop>5__15.m_itemData.m_shared.m_icons[0], Path.Combine(<iconsFolder>5__2, "Pickables", <prefabName>5__12 + ".png"));
											<operationsThisFrame>5__8++;
										}
									}
									<itemDrop>5__15 = null;
								}
								if (exportJson)
								{
									<rawName>5__16 = (string.IsNullOrEmpty(((Object)<pickable>5__11).name) ? <prefabName>5__12 : ((Object)<pickable>5__11).name);
									<data>5__17 = new PickableDataDump
									{
										prefab_name = <prefabName>5__12,
										pickable_name = TranslateToken(<rawName>5__16),
										pickable_rawName = <rawName>5__16,
										drop_item_prefab = <dropPrefabName>5__14,
										min_amount = <pickable>5__11.m_amount,
										max_amount = <pickable>5__11.m_amount,
										respawn_minutes = (int)<pickable>5__11.m_respawnTimeMinutes
									};
									<exportedPickables>5__7.Add(<data>5__17);
									<rawName>5__16 = null;
									<data>5__17 = null;
								}
								if (exportPrefab)
								{
									<targetFile>5__18 = Path.Combine(<prefabsFolder>5__3, <prefabName>5__12 + ".json");
									DumpPrefabHierarchyToJson(<prefab>5__10, <targetFile>5__18);
									<operationsThisFrame>5__8++;
									<targetFile>5__18 = null;
								}
								if (exportModel3d)
								{
									<targetObjPath>5__19 = Path.Combine(<modelsFolder>5__4, <prefabName>5__12 + ".obj");
									ExportPrefabToObj(<prefab>5__10, <targetObjPath>5__19);
									ExportPickableSkinTexture(<prefab>5__10, <texturesFolder>5__5, <prefabName>5__12);
									<operationsThisFrame>5__8++;
									<targetObjPath>5__19 = null;
								}
								if (<exportedPickables>5__7.Count % 15 == 0)
								{
									args.Context.AddString($"<color=lightblue>[Valheim DBDumper] Processed {<exportedPickables>5__7.Count} unique pickables...</color>");
								}
								if (<operationsThisFrame>5__8 >= 30)
								{
									<operationsThisFrame>5__8 = 0;
									<>2__current = null;
									<>1__state = 2;
									return true;
								}
								goto IL_0577;
							}
						}
						goto IL_059b;
					}
					if (exportJson && <exportedPickables>5__7.Count > 0)
					{
						<jsonOutput>5__20 = JsonConvert.SerializeObject((object)<exportedPickables>5__7, (Formatting)1);
						File.WriteAllText(Path.Combine(<pickablesFolder>5__1, "pickables.json"), <jsonOutput>5__20);
						<jsonOutput>5__20 = null;
					}
					args.Context.AddString($"<color=green>[Valheim DBDumper] Pickables module finished! Saved {<exportedPickables>5__7.Count} environment assets and geometries.</color>");
					LogSystem.Success($"Pickables module finished! Saved {<exportedPickables>5__7.Count} environment assets and geometries.");
					onFinished?.Invoke();
					return false;
					IL_0577:
					<prefab>5__10 = null;
					<pickable>5__11 = null;
					<prefabName>5__12 = null;
					<dropItemObj>5__13 = null;
					<dropPrefabName>5__14 = null;
					goto IL_059b;
					IL_059b:
					<i>5__9++;
					goto IL_05ad;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[IteratorStateMachine(typeof(<ExportPickablesCoroutine>d__0))]
		public static IEnumerator ExportPickablesCoroutine(string baseFolder, ConsoleEventArgs args, bool exportJson, bool exportIcons, bool exportPrefab, bool exportModel3d, Action onFinished)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ExportPickablesCoroutine>d__0(0)
			{
				baseFolder = baseFolder,
				args = args,
				exportJson = exportJson,
				exportIcons = exportIcons,
				exportPrefab = exportPrefab,
				exportModel3d = exportModel3d,
				onFinished = onFinished
			};
		}

		private static void DumpPrefabHierarchyToJson(GameObject prefab, string outputPath)
		{
			try
			{
				PrefabNode prefabNode = BuildPrefabNodeElement(prefab.transform);
				string contents = JsonConvert.SerializeObject((object)prefabNode, (Formatting)1);
				File.WriteAllText(outputPath, contents);
			}
			catch (Exception ex)
			{
				LogSystem.Error("Error dumping prefab hierarchy: " + ex.Message);
			}
		}

		private static PrefabNode BuildPrefabNodeElement(Transform current)
		{
			PrefabNode prefabNode = new PrefabNode
			{
				object_name = ((Object)current).name,
				is_active = ((Component)current).gameObject.activeSelf,
				layer = LayerMask.LayerToName(((Component)current).gameObject.layer),
				tag = ((Component)current).gameObject.tag
			};
			Component[] components = ((Component)current).GetComponents<Component>();
			Component[] array = components;
			foreach (Component val in array)
			{
				if ((Object)(object)val == (Object)null)
				{
					continue;
				}
				ComponentData componentData = new ComponentData
				{
					type = ((object)val).GetType().Name
				};
				if (val is Pickable)
				{
					FieldInfo[] fields = ((object)val).GetType().GetFields(BindingFlags.Instance | BindingFlags.Public);
					FieldInfo[] array2 = fields;
					foreach (FieldInfo fieldInfo in array2)
					{
						try
						{
							object value = fieldInfo.GetValue(val);
							if (value != null && !(value is GameObject) && !(value is Component))
							{
								componentData.fields[fieldInfo.Name] = value.ToString();
							}
						}
						catch (Exception ex)
						{
							LogSystem.Error("Error getting field value: " + ex.Message);
						}
					}
				}
				prefabNode.components.Add(componentData);
			}
			for (int k = 0; k < current.childCount; k++)
			{
				prefabNode.children.Add(BuildPrefabNodeElement(current.GetChild(k)));
			}
			return prefabNode;
		}

		private static void ExportPrefabToObj(GameObject prefab, string outputPath)
		{
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: 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_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			//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_00a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: 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)
			//IL_018a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			if (File.Exists(outputPath))
			{
				return;
			}
			try
			{
				StringBuilder stringBuilder = new StringBuilder();
				stringBuilder.AppendLine("# Valheim DBDumper - 3D Mesh of Pickable Resource: " + ((Object)prefab).name);
				int vOffset = 1;
				int nOffset = 1;
				int uvOffset = 1;
				Matrix4x4 worldToLocalMatrix = prefab.transform.worldToLocalMatrix;
				SkinnedMeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren<SkinnedMeshRenderer>(true);
				SkinnedMeshRenderer[] array = componentsInChildren;
				foreach (SkinnedMeshRenderer val in array)
				{
					if ((Object)(object)val == (Object)null || (Object)(object)val.sharedMesh == (Object)null)
					{
						continue;
					}
					Mesh val2 = new Mesh();
					try
					{
						val.BakeMesh(val2);
						Matrix4x4 localToRoot = worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix;
						ProcessMeshAsset(val2, ((Object)val).name, stringBuilder, localToRoot, ref vOffset, ref nOffset, ref uvOffset);
					}
					catch (Exception ex)
					{
						LogSystem.Warn("Error baking mesh: " + ex.Message);
						Matrix4x4 localToRoot2 = worldToLocalMatrix * ((Component)val).transform.localToWorldMatrix;
						ProcessMeshAsset(val.sharedMesh, ((Object)val).name, stringBuilder, localToRoot2, ref vOffset, ref nOffset, ref uvOffset);
					}
					finally
					{
						if ((Object)(object)val2 != (Object)null)
						{
							Object.Destroy((Object)(object)val2);
						}
					}
				}
				MeshFilter[] componentsInChildren2 = prefab.GetComponentsInChildren<MeshFilter>(true);
				MeshFilter[] array2 = componentsInChildren2;
				foreach (MeshFilter val3 in array2)
				{
					if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3.sharedMesh == (Object)null))
					{
						Matrix4x4 localToRoot3 = worldToLocalMatrix * ((Component)val3).transform.localToWorldMatrix;
						ProcessMeshAsset(val3.sharedMesh, ((Object)val3).name, stringBuilder, localToRoot3, ref vOffset, ref nOffset, ref uvOffset);
					}
				}
				if (vOffset > 1)
				{
					File.WriteAllText(outputPath, stringBuilder.ToString());
				}
			}
			catch (Exception ex2)
			{
				LogSystem.Error("Error exporting prefab to OBJ: " + ex2.Message);
			}
		}

		private static void ProcessMeshAsset(Mesh mesh, string name, StringBuilder sb, Matrix4x4 localToRoot, ref int vOffset, ref int nOffset, ref int uvOffset)
		{
			//IL_0027: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: 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_004c: 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_0092: 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_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: 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)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_0120: Unknown result type (might be due to invalid IL or missing references)
			sb.AppendLine("\ng " + name);
			Vector3[] vertices = mesh.vertices;
			Vector3[] array = vertices;
			foreach (Vector3 val in array)
			{
				Vector3 val2 = ((Matrix4x4)(ref localToRoot)).MultiplyPoint3x4(val);
				sb.AppendLine($"v {val2.x} {val2.y} {val2.z}");
			}
			Vector2[] uv = mesh.uv;
			Vector2[] array2 = uv;
			foreach (Vector2 val3 in array2)
			{
				sb.AppendLine($"vt {val3.x} {val3.y}");
			}
			Vector3[] normals = mesh.normals;
			Vector3[] array3 = normals;
			foreach (Vector3 val4 in array3)
			{
				Vector3 val5 = ((Matrix4x4)(ref localToRoot)).MultiplyVector(val4);
				Vector3 normalized = ((Vector3)(ref val5)).normalized;
				sb.AppendLine($"vn {normalized.x} {normalized.y} {normalized.z}");
			}
			bool flag = uv.Length != 0;
			bool flag2 = normals.Length != 0;
			for (int l = 0; l < mesh.subMeshCount; l++)
			{
				int[] triangles = mesh.GetTriangles(l);
				for (int m = 0; m < triangles.Length; m += 3)
				{
					int num = triangles[m] + vOffset;
					int num2 = triangles[m + 1] + vOffset;
					int num3 = triangles[m + 2] + vOffset;
					int num4 = triangles[m] + uvOffset;
					int num5 = triangles[m + 1] + uvOffset;
					int num6 = triangles[m + 2] + uvOffset;
					int num7 = triangles[m] + nOffset;
					int num8 = triangles[m + 1] + nOffset;
					int num9 = triangles[m + 2] + nOffset;
					if (flag && flag2)
					{
						sb.AppendLine($"f {num3}/{num6}/{num9} {num2}/{num5}/{num8} {num}/{num4}/{num7}");
					}
					else if (flag)
					{
						sb.AppendLine($"f {num3}/{num6} {num2}/{num5} {num}/{num4}");
					}
					else if (flag2)
					{
						sb.AppendLine($"f {num3}//{num9} {num2}//{num8} {num}//{num7}");
					}
					else
					{
						sb.AppendLine($"f {num3} {num2} {num}");
					}
				}
			}
			vOffset += vertices.Length;
			uvOffset += uv.Length;
			nOffset += normals.Length;
		}

		private static void ExportPickableSkinTexture(GameObject prefab, string texturesFolder, string prefabName)
		{
			string text = Path.Combine(texturesFolder, prefabName + ".png");
			if (File.Exists(text))
			{
				return;
			}
			Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true);
			Renderer[] array = componentsInChildren;
			foreach (Renderer val in array)
			{
				if (!((Object)(object)val == (Object)null) && !((Object)(object)val.material == (Object)null))
				{
					Texture val2 = val.material.mainTexture;
					if ((Object)(object)val2 == (Object)null && val.material.HasProperty("_MainTex"))
					{
						val2 = val.material.GetTexture("_MainTex");
					}
					if ((Object)(object)val2 != (Object)null && val2.width > 32 && val2.height > 32)
					{
						SaveRuntimeTextureAsPNG(val2, text);
						break;
					}
				}
			}
		}

		private static void SaveRuntimeTextureAsPNG(Texture srcTexture, string outputPath)
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003b: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				int width = srcTexture.width;
				int height = srcTexture.height;
				RenderTexture temporary = RenderTexture.GetTemporary(width, height, 0, (RenderTextureFormat)7, (RenderTextureReadWrite)1);
				Graphics.Blit(srcTexture, temporary);
				RenderTexture active = RenderTexture.active;
				RenderTexture.active = temporary;
				Texture2D val = new Texture2D(width, height, (TextureFormat)4, false);
				val.ReadPixels(new Rect(0f, 0f, (float)width, (float)height), 0, 0);
				val.Apply();
				RenderTexture.active = active;
				RenderTexture.ReleaseTemporary(temporary);
				byte[] bytes = ImageConversion.EncodeToPNG(val);
				File.WriteAllBytes(outputPath, bytes);
				Object.Destroy((Object)(object)val);
			}
			catch (Exception ex)
			{
				LogSystem.Error("Error saving runtime texture: " + ex.Message);
			}
		}

		private static string TranslateToken(string token)
		{
			if (string.IsNullOrEmpty(token))
			{
				return "";
			}
			if (!token.StartsWith("$"))
			{
				return token;
			}
			try
			{
				Type type = typeof(Terminal).Assembly.GetType("Localization") ?? Type.GetType("Valheim.Localization, assembly_valheim");
				if (type == null)
				{
					return token;
				}
				object obj = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
				if (obj == null)
				{
					return token;
				}
				return (type.GetMethod("Localize", new Type[1] { typeof(string) })?.Invoke(obj, new object[1] { token }) as string) ?? token;
			}
			catch (Exception ex)
			{
				LogSystem.Error("Error translating token: " + ex.Message);
				return token;
			}
		}

		private static void SaveCroppedSpriteAsPNG(Sprite sprite, string outputPath)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			if (File.Exists(outputPath))
			{
				return;
			}
			try
			{
				Texture2D texture = sprite.texture;
				if (!((Object)(object)texture == (Object)null))
				{
					Rect textureRect = sprite.textureRect;
					int num = (int)((Rect)(ref textureRect)).width;
					int num2 = (int)((Rect)(ref textureRect)).height;
					RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0, (RenderTextureFormat)7, (RenderTextureReadWrite)1);
					Graphics.Blit((Texture)(object)texture, temporary);
					RenderTexture active = RenderTexture.active;
					RenderTexture.active = temporary;
					Texture2D val = new Texture2D(num, num2, (TextureFormat)4, false);
					val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)num, (float)num2), 0, 0);
					val.Apply();
					RenderTexture.active = active;
					RenderTexture.ReleaseTemporary(temporary);
					byte[] bytes = ImageConversion.EncodeToPNG(val);
					File.WriteAllBytes(outputPath, bytes);
					Object.Destroy((Object)(object)val);
				}
			}
			catch (Exception ex)
			{
				LogSystem.Error("Error saving cropped sprite: " + ex.Message);
			}
		}
	}
	public class PieceDataDump
	{
		public string prefab_name { get; set; }

		public string piece_name { get; set; }

		public string piece_rawName { get; set; }

		public string description { get; set; }

		public string category { get; set; }

		public string primary_tool { get; set; }

		public string required_station { get; set; }

		public List<PieceRequirementData> resources { get; set; } = new List<PieceRequirementData>();

	}
	public class PieceRequirementData
	{
		public string item_prefab { get; set; }

		public int amount { get; set; }

		public bool recover { get; set; }
	}
	public static class PiecesExporter
	{
		[CompilerGenerated]
		private sealed class <ExportPiecesCoroutine>d__0 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string baseFolder;

			public ConsoleEventArgs args;

			public bool exportJson;

			public bool exportIcons;

			public Action onFinished;

			private string <piecesFolder>5__1;

			private string <iconsFolder>5__2;

			private List<GameObject> <itemPrefabs>5__3;

			private List<PieceDataDump> <exportedPieces>5__4;

			private HashSet<string> <processedPrefabs>5__5;

			private int <operationsThisFrame>5__6;

			private List<GameObject>.Enumerator <>s__7;

			private GameObject <itemObj>5__8;

			private ItemDrop <itemDrop>5__9;

			private PieceTable <pieceTable>5__10;

			private string <toolName>5__11;

			private List<GameObject>.Enumerator <>s__12;

			private GameObject <pieceObj>5__13;

			private string <prefabName>5__14;

			private Piece <piece>5__15;

			private string <stationName>5__16;

			private PieceDataDump <data>5__17;

			private Requirement[] <>s__18;

			private int <>s__19;

			private Requirement <req>5__20;

			private string <jsonOutput>5__21;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ExportPiecesCoroutine>d__0(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				int num = <>1__state;
				if ((uint)(num - -4) <= 1u || num == 2)
				{
					try
					{
						if (num == -4 || num == 2)
						{
							try
							{
							}
							finally
							{
								<>m__Finally2();
							}
						}
					}
					finally
					{
						<>m__Finally1();
					}
				}
				<piecesFolder>5__1 = null;
				<iconsFolder>5__2 = null;
				<itemPrefabs>5__3 = null;
				<exportedPieces>5__4 = null;
				<processedPrefabs>5__5 = null;
				<>s__7 = default(List<GameObject>.Enumerator);
				<itemObj>5__8 = null;
				<itemDrop>5__9 = null;
				<pieceTable>5__10 = null;
				<toolName>5__11 = null;
				<>s__12 = default(List<GameObject>.Enumerator);
				<pieceObj>5__13 = null;
				<prefabName>5__14 = null;
				<piece>5__15 = null;
				<stationName>5__16 = null;
				<data>5__17 = null;
				<>s__18 = null;
				<req>5__20 = null;
				<jsonOutput>5__21 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<piecesFolder>5__1 = Path.Combine(baseFolder, "data", "pieces");
						<iconsFolder>5__2 = Path.Combine(baseFolder, "icons");
						if (exportJson)
						{
							Directory.CreateDirectory(<piecesFolder>5__1);
						}
						if (exportIcons)
						{
							Directory.CreateDirectory(<iconsFolder>5__2);
						}
						<itemPrefabs>5__3 = ObjectDB.instance.m_items;
						<exportedPieces>5__4 = new List<PieceDataDump>();
						<processedPrefabs>5__5 = new HashSet<string>();
						args.Context.AddString("<color=yellow>[Valheim DBDumper] Scanning tools for building pieces...</color>");
						LogSystem.Info("Scanning tools for building pieces...");
						<>2__current = null;
						<>1__state = 1;
						return true;
					case 1:
						<>1__state = -1;
						<operationsThisFrame>5__6 = 0;
						<>s__7 = <itemPrefabs>5__3.GetEnumerator();
						<>1__state = -3;
						goto IL_05c2;
					case 2:
						{
							<>1__state = -4;
							goto IL_056c;
						}
						IL_05c2:
						while (true)
						{
							if (<>s__7.MoveNext())
							{
								<itemObj>5__8 = <>s__7.Current;
								if ((Object)(object)<itemObj>5__8 == (Object)null)
								{
									continue;
								}
								<itemDrop>5__9 = <itemObj>5__8.GetComponent<ItemDrop>();
								if (!((Object)(object)<itemDrop>5__9 == (Object)null) && <itemDrop>5__9.m_itemData != null)
								{
									<pieceTable>5__10 = <itemDrop>5__9.m_itemData.m_shared.m_buildPieces;
									if (!((Object)(object)<pieceTable>5__10 == (Object)null) && <pieceTable>5__10.m_pieces != null)
									{
										break;
									}
								}
								continue;
							}
							<>m__Finally1();
							<>s__7 = default(List<GameObject>.Enumerator);
							if (exportJson && <exportedPieces>5__4.Count > 0)
							{
								<jsonOutput>5__21 = JsonConvert.SerializeObject((object)<exportedPieces>5__4, (Formatting)1);
								File.WriteAllText(Path.Combine(<piecesFolder>5__1, "pieces.json"), <jsonOutput>5__21);
								<jsonOutput>5__21 = null;
							}
							args.Context.AddString($"<color=green>[Valheim DBDumper] Pieces module finished! Saved {<exportedPieces>5__4.Count} unique structures.</color>");
							LogSystem.Success($"Pieces module finished! Saved {<exportedPieces>5__4.Count} unique structures.");
							onFinished?.Invoke();
							return false;
						}
						Directory.CreateDirectory(Path.Combine(<iconsFolder>5__2, "Pieces"));
						<toolName>5__11 = ((Object)<itemObj>5__8).name;
						<>s__12 = <pieceTable>5__10.m_pieces.GetEnumerator();
						<>1__state = -4;
						goto IL_0582;
						IL_056c:
						<prefabName>5__14 = null;
						<piece>5__15 = null;
						<pieceObj>5__13 = null;
						goto IL_0582;
						IL_0582:
						while (<>s__12.MoveNext())
						{
							<pieceObj>5__13 = <>s__12.Current;
							if ((Object)(object)<pieceObj>5__13 == (Object)null)
							{
								continue;
							}
							<prefabName>5__14 = ((Object)<pieceObj>5__13).name;
							if (<processedPrefabs>5__5.Contains(<prefabName>5__14))
							{
								continue;
							}
							<piece>5__15 = <pieceObj>5__13.GetComponent<Piece>();
							if ((Object)(object)<piece>5__15 == (Object)null)
							{
								continue;
							}
							goto IL_028e;
						}
						<>m__Finally2();
						<>s__12 = default(List<GameObject>.Enumerator);
						<itemDrop>5__9 = null;
						<pieceTable>5__10 = null;
						<toolName>5__11 = null;
						<itemObj>5__8 = null;
						goto IL_05c2;
						IL_028e:
						if (exportIcons && (Object)(object)<piece>5__15.m_icon != (Object)null)
						{
							SaveCroppedSpriteAsPNG(<piece>5__15.m_icon, Path.Combine(<iconsFolder>5__2, "Pieces", <prefabName>5__14 + ".png"));
							<operationsThisFrame>5__6++;
						}
						if (exportJson)
						{
							<stationName>5__16 = (((Object)(object)<piece>5__15.m_craftingStation != (Object)null) ? <piece>5__15.m_craftingStation.m_name : "None");
							<data>5__17 = new PieceDataDump
							{
								prefab_name = <prefabName>5__14,
								piece_name = TranslateToken(<piece>5__15.m_name),
								piece_rawName = <piece>5__15.m_name,
								description = TranslateToken(<piece>5__15.m_description),
								category = ((object)(PieceCategory)(ref <piece>5__15.m_category)).ToString(),
								primary_tool = <toolName>5__11,
								required_station = <stationName>5__16
							};
							if (<piece>5__15.m_resources != null)
							{
								<>s__18 = <piece>5__15.m_resources;
								for (<>s__19 = 0; <>s__19 < <>s__18.Length; <>s__19++)
								{
									<req>5__20 = <>s__18[<>s__19];
									if (<req>5__20 != null && !((Object)(object)<req>5__20.m_resItem == (Object)null))
									{
										<data>5__17.resources.Add(new PieceRequirementData
										{
											item_prefab = ((Object)((Component)<req>5__20.m_resItem).gameObject).name,
											amount = <req>5__20.m_amount,
											recover = <req>5__20.m_recover
										});
										<req>5__20 = null;
									}
								}
								<>s__18 = null;
							}
							<exportedPieces>5__4.Add(<data>5__17);
							<stationName>5__16 = null;
							<data>5__17 = null;
						}
						<processedPrefabs>5__5.Add(<prefabName>5__14);
						if (<processedPrefabs>5__5.Count % 50 == 0)
						{
							args.Context.AddString($"<color=lightblue>[Valheim DBDumper] Processed {<processedPrefabs>5__5.Count} unique building pieces...</color>");
						}
						if (<operationsThisFrame>5__6 >= 25)
						{
							<operationsThisFrame>5__6 = 0;
							<>2__current = null;
							<>1__state = 2;
							return true;
						}
						goto IL_056c;
					}
				}
				catch
				{
					//try-fault
					((IDisposable)this).Dispose();
					throw;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			private void <>m__Finally1()
			{
				<>1__state = -1;
				((IDisposable)<>s__7).Dispose();
			}

			private void <>m__Finally2()
			{
				<>1__state = -3;
				((IDisposable)<>s__12).Dispose();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[IteratorStateMachine(typeof(<ExportPiecesCoroutine>d__0))]
		public static IEnumerator ExportPiecesCoroutine(string baseFolder, ConsoleEventArgs args, bool exportJson, bool exportIcons, Action onFinished)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ExportPiecesCoroutine>d__0(0)
			{
				baseFolder = baseFolder,
				args = args,
				exportJson = exportJson,
				exportIcons = exportIcons,
				onFinished = onFinished
			};
		}

		private static string TranslateToken(string token)
		{
			if (string.IsNullOrEmpty(token))
			{
				return "";
			}
			if (!token.StartsWith("$"))
			{
				return token;
			}
			try
			{
				Type type = typeof(Terminal).Assembly.GetType("Localization") ?? Type.GetType("Valheim.Localization, assembly_valheim");
				if (type == null)
				{
					return token;
				}
				object obj = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
				if (obj == null)
				{
					return token;
				}
				return (type.GetMethod("Localize", new Type[1] { typeof(string) })?.Invoke(obj, new object[1] { token }) as string) ?? token;
			}
			catch (Exception ex)
			{
				LogSystem.Error("Error translating token: " + ex.Message);
				return token;
			}
		}

		private static void SaveCroppedSpriteAsPNG(Sprite sprite, string outputPath)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			if (File.Exists(outputPath))
			{
				return;
			}
			try
			{
				Texture2D texture = sprite.texture;
				if (!((Object)(object)texture == (Object)null))
				{
					Rect textureRect = sprite.textureRect;
					int num = (int)((Rect)(ref textureRect)).width;
					int num2 = (int)((Rect)(ref textureRect)).height;
					RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0, (RenderTextureFormat)7, (RenderTextureReadWrite)1);
					Graphics.Blit((Texture)(object)texture, temporary);
					RenderTexture active = RenderTexture.active;
					RenderTexture.active = temporary;
					Texture2D val = new Texture2D(num, num2, (TextureFormat)4, false);
					val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)num, (float)num2), 0, 0);
					val.Apply();
					RenderTexture.active = active;
					RenderTexture.ReleaseTemporary(temporary);
					byte[] bytes = ImageConversion.EncodeToPNG(val);
					File.WriteAllBytes(outputPath, bytes);
					Object.Destroy((Object)(object)val);
				}
			}
			catch (Exception ex)
			{
				LogSystem.Error("Error saving cropped sprite as PNG: " + ex.Message);
			}
		}
	}
	public class RecipeData
	{
		public string prefab_name { get; set; }

		public string item_name { get; set; }

		public string item_rawName { get; set; }

		public string crafting_station { get; set; }

		public int min_station_level { get; set; }

		public int amount { get; set; }

		public List<RequirementData> requirements { get; set; } = new List<RequirementData>();

	}
	public class RequirementData
	{
		public string item_prefab { get; set; }

		public int amount { get; set; }

		public int amount_per_level { get; set; }
	}
	public static class RecipeExporter
	{
		[CompilerGenerated]
		private sealed class <ExportRecipesCoroutine>d__0 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string baseFolder;

			public ConsoleEventArgs args;

			public bool exportJson;

			public bool exportIcons;

			public Action onFinished;

			private string <recipesFolder>5__1;

			private string <iconsFolder>5__2;

			private List<Recipe> <recipeList>5__3;

			private List<RecipeData> <exportedRecipes>5__4;

			private int <operationsThisFrame>5__5;

			private int <i>5__6;

			private Recipe <recipe>5__7;

			private string <prefabName>5__8;

			private Sprite[] <iconsArray>5__9;

			private string <itemName>5__10;

			private string <stationName>5__11;

			private RecipeData <data>5__12;

			private Requirement[] <>s__13;

			private int <>s__14;

			private Requirement <req>5__15;

			private string <jsonOutput>5__16;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <ExportRecipesCoroutine>d__0(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<recipesFolder>5__1 = null;
				<iconsFolder>5__2 = null;
				<recipeList>5__3 = null;
				<exportedRecipes>5__4 = null;
				<recipe>5__7 = null;
				<prefabName>5__8 = null;
				<iconsArray>5__9 = null;
				<itemName>5__10 = null;
				<stationName>5__11 = null;
				<data>5__12 = null;
				<>s__13 = null;
				<req>5__15 = null;
				<jsonOutput>5__16 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				if (num != 0)
				{
					if (num != 1)
					{
						return false;
					}
					<>1__state = -1;
					goto IL_0480;
				}
				<>1__state = -1;
				<recipesFolder>5__1 = Path.Combine(baseFolder, "data", "recipes");
				<iconsFolder>5__2 = Path.Combine(baseFolder, "icons");
				if (exportJson)
				{
					Directory.CreateDirectory(<recipesFolder>5__1);
				}
				if (exportIcons)
				{
					Directory.CreateDirectory(<iconsFolder>5__2);
				}
				<recipeList>5__3 = ObjectDB.instance.m_recipes;
				<exportedRecipes>5__4 = new List<RecipeData>();
				args.Context.AddString($"<color=yellow>[Valheim DBDumper] Processing {<recipeList>5__3.Count} recipes...</color>");
				LogSystem.Info($"Processing {<recipeList>5__3.Count} recipes...");
				<operationsThisFrame>5__5 = 0;
				Directory.CreateDirectory(Path.Combine(<iconsFolder>5__2, "Recipes"));
				<i>5__6 = 0;
				goto IL_04a1;
				IL_04a1:
				if (<i>5__6 < <recipeList>5__3.Count)
				{
					<recipe>5__7 = <recipeList>5__3[<i>5__6];
					if ((Object)(object)<recipe>5__7 == (Object)null || (Object)(object)<recipe>5__7.m_item == (Object)null)
					{
						goto IL_048f;
					}
					<prefabName>5__8 = ((Object)((Component)<recipe>5__7.m_item).gameObject).name;
					if (exportIcons)
					{
						<iconsArray>5__9 = <recipe>5__7.m_item.m_itemData.m_shared.m_icons;
						if (<iconsArray>5__9 != null && <iconsArray>5__9.Length != 0 && (Object)(object)<iconsArray>5__9[0] != (Object)null)
						{
							SaveCroppedSpriteAsPNG(<iconsArray>5__9[0], Path.Combine(<iconsFolder>5__2, "Recipes", <prefabName>5__8 + ".png"));
							<operationsThisFrame>5__5++;
						}
						<iconsArray>5__9 = null;
					}
					if (exportJson)
					{
						<itemName>5__10 = <recipe>5__7.m_item.m_itemData.m_shared.m_name;
						<stationName>5__11 = (((Object)(object)<recipe>5__7.m_craftingStation != (Object)null) ? <recipe>5__7.m_craftingStation.m_name : "Hand");
						<data>5__12 = new RecipeData
						{
							prefab_name = <prefabName>5__8,
							item_name = TranslateToken(<itemName>5__10),
							item_rawName = <itemName>5__10,
							crafting_station = <stationName>5__11,
							min_station_level = <recipe>5__7.m_minStationLevel,
							amount = <recipe>5__7.m_amount
						};
						if (<recipe>5__7.m_resources != null)
						{
							<>s__13 = <recipe>5__7.m_resources;
							for (<>s__14 = 0; <>s__14 < <>s__13.Length; <>s__14++)
							{
								<req>5__15 = <>s__13[<>s__14];
								if (<req>5__15 != null && !((Object)(object)<req>5__15.m_resItem == (Object)null))
								{
									<data>5__12.requirements.Add(new RequirementData
									{
										item_prefab = ((Object)((Component)<req>5__15.m_resItem).gameObject).name,
										amount = <req>5__15.m_amount,
										amount_per_level = <req>5__15.m_amountPerLevel
									});
									<req>5__15 = null;
								}
							}
							<>s__13 = null;
						}
						<exportedRecipes>5__4.Add(<data>5__12);
						<itemName>5__10 = null;
						<stationName>5__11 = null;
						<data>5__12 = null;
					}
					if (<i>5__6 > 0 && <i>5__6 % 150 == 0)
					{
						args.Context.AddString($"<color=lightblue>[Valheim DBDumper] Processed {<i>5__6}/{<recipeList>5__3.Count} recipes...</color>");
					}
					if (<operationsThisFrame>5__5 >= 25)
					{
						<operationsThisFrame>5__5 = 0;
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					goto IL_0480;
				}
				if (exportJson && <exportedRecipes>5__4.Count > 0)
				{
					<jsonOutput>5__16 = JsonConvert.SerializeObject((object)<exportedRecipes>5__4, (Formatting)1);
					File.WriteAllText(Path.Combine(<recipesFolder>5__1, "recipes.json"), <jsonOutput>5__16);
					<jsonOutput>5__16 = null;
				}
				args.Context.AddString("<color=green>[Valheim DBDumper] Recipe module finished processing successfully!</color>");
				LogSystem.Success("Recipe module finished processing successfully!");
				onFinished?.Invoke();
				return false;
				IL_0480:
				<recipe>5__7 = null;
				<prefabName>5__8 = null;
				goto IL_048f;
				IL_048f:
				<i>5__6++;
				goto IL_04a1;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[IteratorStateMachine(typeof(<ExportRecipesCoroutine>d__0))]
		public static IEnumerator ExportRecipesCoroutine(string baseFolder, ConsoleEventArgs args, bool exportJson, bool exportIcons, Action onFinished)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <ExportRecipesCoroutine>d__0(0)
			{
				baseFolder = baseFolder,
				args = args,
				exportJson = exportJson,
				exportIcons = exportIcons,
				onFinished = onFinished
			};
		}

		private static string TranslateToken(string token)
		{
			if (string.IsNullOrEmpty(token))
			{
				return "";
			}
			if (!token.StartsWith("$"))
			{
				return token;
			}
			try
			{
				Type type = typeof(Terminal).Assembly.GetType("Localization") ?? Type.GetType("Valheim.Localization, assembly_valheim");
				if (type == null)
				{
					return token;
				}
				object obj = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public)?.GetValue(null);
				if (obj == null)
				{
					return token;
				}
				return (type.GetMethod("Localize", new Type[1] { typeof(string) })?.Invoke(obj, new object[1] { token }) as string) ?? token;
			}
			catch (Exception ex)
			{
				LogSystem.Error("Error translating token: " + ex.Message);
				return token;
			}
		}

		private static void SaveCroppedSpriteAsPNG(Sprite sprite, string outputPath)
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Expected O, but got Unknown
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			if (File.Exists(outputPath))
			{
				return;
			}
			try
			{
				Texture2D texture = sprite.texture;
				if (!((Object)(object)texture == (Object)null))
				{
					Rect textureRect = sprite.textureRect;
					int num = (int)((Rect)(ref textureRect)).width;
					int num2 = (int)((Rect)(ref textureRect)).height;
					RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0, (RenderTextureFormat)7, (RenderTextureReadWrite)1);
					Graphics.Blit((Texture)(object)texture, temporary);
					RenderTexture active = RenderTexture.active;
					RenderTexture.active = temporary;
					Texture2D val = new Texture2D(num, num2, (TextureFormat)4, false);
					val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)num, (float)num2), 0, 0);
					val.Apply();
					RenderTexture.active = active;
					RenderTexture.ReleaseTemporary(temporary);
					byte[] bytes = ImageConversion.EncodeToPNG(val);
					File.WriteAllBytes(outputPath, bytes);
					Object.Destroy((Object)(object)val);
				}
			}
			catch (Exception ex)
			{
				LogSystem.Error("Failed to export " + outputPath + ": " + ex.Message);
			}
		}
	}
	public class Color
	{
		public static readonly string RESET = "\u001b[0m";

		public static readonly string BOLD = "\u001b[1m";

		public static readonly string DIM = "\u001b[2m";

		public static readonly string ITALIC = "\u001b[3m";

		public static readonly string UNDERLINE = "\u001b[4m";

		public static readonly string BLINK = "\u001b[5m";

		public static readonly string REVERSE = "\u001b[7m";

		public static readonly string HIDDEN = "\u001b[8m";

		public static readonly string STRIKETHROUGH = "\u001b[9m";

		public static readonly string BLACK = "\u001b[30m";

		public static readonly string RED = "\u001b[31m";

		public static readonly string GREEN = "\u001b[32m";

		public static readonly string YELLOW = "\u001b[33m";

		public static readonly string BLUE = "\u001b[34m";

		public static readonly string MAGENTA = "\u001b[35m";

		public static readonly string CYAN = "\u001b[36m";

		public static readonly string WHITE = "\u001b[37m";

		public static readonly string GRAY = "\u001b[90m";

		public static readonly string ORANGE = TextFromRGB(255, 165, 0);

		public static readonly string PINK = TextFromRGB(255, 192, 203);

		public static readonly string BRIGHT_RED = "\u001b[91m";

		public static readonly string BRIGHT_GREEN = "\u001b[92m";

		public static readonly string BRIGHT_YELLOW = "\u001b[93m";

		public static readonly string BRIGHT_BLUE = "\u001b[94m";

		public static readonly string BRIGHT_MAGENTA = "\u001b[95m";

		public static readonly string BRIGHT_CYAN = "\u001b[96m";

		public static readonly string BRIGHT_WHITE = "\u001b[97m";

		public static readonly string BRIGHT_ORANGE = TextFromRGB(255, 153, 28);

		public static readonly string BRIGHT_PINK = TextFromRGB(244, 160, 250);

		public static readonly string BG_BLACK = "\u001b[40m";

		public static readonly string BG_RED = "\u001b[41m";

		public static readonly string BG_GREEN = "\u001b[42m";

		public static readonly string BG_YELLOW = "\u001b[43m";

		public static readonly string BG_BLUE = "\u001b[44m";

		public static readonly string BG_MAGENTA = "\u001b[45m";

		public static readonly string BG_CYAN = "\u001b[46m";

		public static readonly string BG_WHITE = "\u001b[47m";

		public static readonly string BG_GRAY = "\u001b[100m";

		public static readonly string BG_ORANGE = BGFromRGB(255, 165, 0);

		public static readonly string BG_PINK = BGFromRGB(255, 192, 203);

		public static readonly string BG_BRIGHT_RED = "\u001b[101m";

		public static readonly string BG_BRIGHT_GREEN = BGFromRGB(48, 255, 62);

		public static readonly string BG_BRIGHT_YELLOW = "\u001b[103m";

		public static readonly string BG_BRIGHT_BLUE = "\u001b[104m";

		public static readonly string BG_BRIGHT_MAGENTA = "\u001b[105m";

		public static readonly string BG_BRIGHT_CYAN = BGFromRGB(115, 255, 250);

		public static readonly string BG_BRIGHT_WHITE = "\u001b[107m";

		public static readonly string BG_BRIGHT_ORANGE = BGFromRGB(255, 153, 28);

		public static readonly string BG_BRIGHT_PINK = BGFromRGB(244, 160, 250);

		public static readonly string BLACK_BRIGHT = "\u001b[90m";

		public static readonly string RED_BRIGHT = "\u001b[91m";

		public static readonly string GREEN_BRIGHT = "\u001b[92m";

		public static readonly string YELLOW_BRIGHT = "\u001b[93m";

		public static readonly string BLUE_BRIGHT = "\u001b[94m";

		public static readonly string MAGENTA_BRIGHT = "\u001b[95m";

		public static readonly string CYAN_BRIGHT = "\u001b[96m";

		public static readonly string WHITE_BRIGHT = "\u001b[97m";

		private static bool IsColourSupported(int r, int g, int b)
		{
			if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255)
			{
				throw new ArgumentException("Invalid Colour: Colour code must be set between 0 and 255.");
			}
			return true;
		}

		public static string TextFromRGB(int r, int g, int b)
		{
			if (IsColourSupported(r, g, b))
			{
				return $"\u001b[38;2;{r};{g};{b}m";
			}
			return string.Empty;
		}

		public static string BGFromRGB(int r, int g, int b)
		{
			if (IsColourSupported(r, g, b))
			{
				return $"\u001b[48;2;{r};{g};{b}m";
			}
			return string.Empty;
		}
	}
	[BepInPlugin("n1h1lius.valheimdbdumper", "Valheim-DB-Dumper", "1.0.0")]
	public class ValheimDBDumper : BaseUnityPlugin
	{
		[HarmonyPatch(typeof(Terminal), "Awake")]
		public static class Terminal_Awake_Patch
		{
			[Serializable]
			[CompilerGenerated]
			private sealed class <>c
			{
				public static readonly <>c <>9 = new <>c();

				public static Func<string, bool> <>9__0_1;

				public static Func<string, bool> <>9__0_2;

				public static Func<string, bool> <>9__0_3;

				public static Func<string, bool> <>9__0_4;

				public static ConsoleEvent <>9__0_0;

				internal void <Postfix>b__0_0(ConsoleEventArgs args)
				{
					<>c__DisplayClass0_0 CS$<>8__locals0 = new <>c__DisplayClass0_0
					{
						args = args
					};
					if (CS$<>8__locals0.args.Args == null || CS$<>8__locals0.args.Args.Length < 2)
					{
						PrintHelp(CS$<>8__locals0.args);
						return;
					}
					if ((Object)(object)ObjectDB.instance == (Object)null || ObjectDB.instance.m_items.Count == 0)
					{
						CS$<>8__locals0.args.Context.AddString("<color=red>[Valheim DBDumper] Error: You must be inside a world with your character to dump data.</color>");
						return;
					}
					try
					{
						string value = ConfigExportPath.Value;
						if (!Directory.Exists(value))
						{
							Directory.CreateDirectory(value);
						}
						ExtractEmbeddedTools(value);
						string text = CS$<>8__locals0.args.Args[1].ToLower();
						_activeExports = ((!(text == "all")) ? 1 : 5);
						bool exportIcons = !CS$<>8__locals0.args.Args.Any((string a) => a.Equals("--no-icon", StringComparison.OrdinalIgnoreCase));
						bool exportJson = !CS$<>8__locals0.args.Args.Any((string a) => a.Equals("--no-json", StringComparison.OrdinalIgnoreCase));
						bool exportPrefab = !CS$<>8__locals0.args.Args.Any((string a) => a.Equals("--no-prefab", StringComparison.OrdinalIgnoreCase));
						bool exportModel3d = !CS$<>8__locals0.args.Args.Any((string a) => a.Equals("--no-model3d", StringComparison.OrdinalIgnoreCase));
						if (text == "all")
						{
							LogSystem.Log("Exporting all database structures...");
						}
						if (text == "all" || text == "recipes")
						{
							if (text != "all")
							{
								LogSystem.Log("Exporting manufacturing recipes...");
							}
							((MonoBehaviour)Instance).StartCoroutine(RecipeExporter.ExportRecipesCoroutine(value, CS$<>8__locals0.args, exportJs