Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of balrond bundling machine v1.1.2
plugins/BalrondPackager.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using HarmonyLib; using LitJson2; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("BalrondPackager")] [assembly: AssemblyDescription("Balrond Packager for Valheim")] [assembly: AssemblyCompany("Balrond")] [assembly: AssemblyProduct("BalrondPackager")] [assembly: ComVisible(false)] [assembly: Guid("cde312a0-cf19-4264-8616-e1c74774beed")] [assembly: AssemblyFileVersion("1.1.2.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.2.0")] [module: UnverifiableCode] namespace BalrondPackager { public static class BalrondTranslator { public static readonly Dictionary<string, Dictionary<string, string>> translations = new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); public static Dictionary<string, string> getLanguage(string language) { if (string.IsNullOrEmpty(language)) { return null; } Dictionary<string, string> value; return translations.TryGetValue(language, out value) ? value : null; } } public sealed class BuildPieceBuilder { private static readonly string[] PieceNames = new string[2] { "packager_bal", "unpackager_bal" }; private Dictionary<string, GameObject> m_prefabByName; public void SetupBuildPieces(List<GameObject> prefabs) { if (prefabs == null) { Debug.LogWarning((object)(Launch.projectName + ": SetupBuildPieces received null prefab list.")); return; } TableMapper.setupTables(prefabs); m_prefabByName = BuildPrefabLookup(prefabs); for (int i = 0; i < PieceNames.Length; i++) { if (!m_prefabByName.TryGetValue(PieceNames[i], out var value) || (Object)(object)value == (Object)null) { Debug.LogWarning((object)(Launch.projectName + ": build piece not found: " + PieceNames[i])); } else { ConfigureBuildPiece(value); } } } private static Dictionary<string, GameObject> BuildPrefabLookup(List<GameObject> prefabs) { Dictionary<string, GameObject> dictionary = new Dictionary<string, GameObject>(StringComparer.Ordinal); for (int i = 0; i < prefabs.Count; i++) { GameObject val = prefabs[i]; if ((Object)(object)val != (Object)null && !string.IsNullOrEmpty(((Object)val).name) && !dictionary.ContainsKey(((Object)val).name)) { dictionary.Add(((Object)val).name, val); } } return dictionary; } private void ConfigureBuildPiece(GameObject gameObject) { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) Piece val = (((Object)(object)gameObject != (Object)null) ? gameObject.GetComponent<Piece>() : null); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)(Launch.projectName + ": Piece component missing on " + (((Object)(object)gameObject != (Object)null) ? ((Object)gameObject).name : "null"))); return; } val.m_category = (PieceCategory)1; val.m_usage = (UsageTagFlags)2; val.m_enabled = false; List<Requirement> list = new List<Requirement>(); bool flag = true; string name = ((Object)gameObject).name; string text = name; CraftingStation val2; if (!(text == "packager_bal")) { if (!(text == "unpackager_bal")) { return; } val2 = TableMapper.workbench; flag &= AddResource(list, "Stone", 10); flag &= AddResource(list, "Wood", 10); } else { val2 = TableMapper.forge; flag &= AddResource(list, "ElderBark", 20); flag &= AddResource(list, "SurtlingCore", 5); flag &= AddResource(list, "Stone", 10); flag &= AddResource(list, "Iron", 10); flag &= AddResource(list, "RoundLog", 10); } if ((Object)(object)val2 == (Object)null) { Debug.LogWarning((object)(Launch.projectName + ": required crafting station missing for " + ((Object)gameObject).name + ". Piece disabled.")); flag = false; } if (!flag) { val.m_resources = list.ToArray(); return; } val.m_craftingStation = val2; val.m_resources = list.ToArray(); val.m_enabled = true; } private bool AddResource(List<Requirement> requirements, string itemName, int amount, int amountPerLevel = 0, bool recover = true) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown if (m_prefabByName == null || !m_prefabByName.TryGetValue(itemName, out var value) || (Object)(object)value == (Object)null) { Debug.LogWarning((object)(Launch.projectName + ": required resource prefab not found: " + itemName)); return false; } ItemDrop component = value.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { Debug.LogWarning((object)(Launch.projectName + ": resource prefab has no ItemDrop: " + itemName)); return false; } requirements.Add(new Requirement { m_resItem = component, m_amount = amount, m_amountPerLevel = amountPerLevel, m_recover = recover }); return true; } } internal class BuildPieceList { public static string[] buildPieces = new string[2] { "packager_bal", "unpackager_bal" }; } public class BalrondPackager : MonoBehaviour { private struct PackedEntry { internal readonly string PrefabName; internal readonly int Stack; internal readonly string SerializedData; internal PackedEntry(string prefabName, int stack, string serializedData) { PrefabName = prefabName; Stack = stack; SerializedData = serializedData; } } public enum Response { Fail, Success, Conversion, Empty } public Switch m_incinerateSwitch; public Container m_container; public Animator m_leverAnim; public EffectList m_leverEffects = new EffectList(); public float m_effectDelayMin = 10f; public float m_effectDelayMax = 15f; [Header("Conversion")] public ItemDrop m_defaultResult; public int m_defaultCost = 1; public Transform output; public GameObject m_enabled; public EffectList m_produceEffects = new EffectList(); private ZNetView m_nview; private bool m_isInUse; private void Awake() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected O, but got Unknown if ((Object)(object)m_incinerateSwitch != (Object)null) { Switch incinerateSwitch = m_incinerateSwitch; incinerateSwitch.m_onUse = (Callback)Delegate.Combine((Delegate?)(object)incinerateSwitch.m_onUse, (Delegate?)new Callback(OnIncinerate)); Switch incinerateSwitch2 = m_incinerateSwitch; incinerateSwitch2.m_onHover = (TooltipCallback)Delegate.Combine((Delegate?)(object)incinerateSwitch2.m_onHover, (Delegate?)new TooltipCallback(GetLeverHoverText)); } else { Debug.LogWarning((object)(Launch.projectName + ": Missing Switch on packager: " + ((Object)((Component)this).gameObject).name)); } m_nview = ((Component)this).GetComponent<ZNetView>(); if (!((Object)(object)m_nview == (Object)null) && m_nview.GetZDO() != null) { m_nview.Register<long>("RPC_RequestPackage", (Action<long, long>)RPC_RequestPackage); m_nview.Register<int>("RPC_PackageRespons", (Action<long, int>)RPC_PackageRespons); m_nview.Register("RPC_AnimateLever", (Action<long>)RPC_AnimateLever); m_nview.Register("RPC_AnimateLeverReturn", (Action<long>)RPC_AnimateLeverReturn); if ((Object)(object)m_enabled != (Object)null) { m_enabled.SetActive(false); } } } private void OnDestroy() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected O, but got Unknown if ((Object)(object)m_incinerateSwitch != (Object)null) { Switch incinerateSwitch = m_incinerateSwitch; incinerateSwitch.m_onUse = (Callback)Delegate.Remove((Delegate?)(object)incinerateSwitch.m_onUse, (Delegate?)new Callback(OnIncinerate)); Switch incinerateSwitch2 = m_incinerateSwitch; incinerateSwitch2.m_onHover = (TooltipCallback)Delegate.Remove((Delegate?)(object)incinerateSwitch2.m_onHover, (Delegate?)new TooltipCallback(GetLeverHoverText)); } } private void ReleaseUseLock() { m_isInUse = false; } public string GetLeverHoverText() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return (Localization.instance != null) ? Localization.instance.Localize("$piece_packager\n$piece_noaccess") : "$piece_packager\n$piece_noaccess"; } return (Localization.instance != null) ? Localization.instance.Localize("[<color=yellow><b>$KEY_Use</b></color>] $piece_pulllever") : "[Use] $piece_pulllever"; } private bool OnIncinerate(Switch sw, Humanoid user, ItemData item) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid() || !m_nview.HasOwner()) { return false; } if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return false; } if ((Object)(object)Game.instance == (Object)null || Game.instance.GetPlayerProfile() == null) { return false; } m_nview.InvokeRPC("RPC_RequestPackage", new object[1] { Game.instance.GetPlayerProfile().GetPlayerID() }); return true; } private void RPC_RequestPackage(long uid, long playerID) { if (!((Object)(object)m_nview == (Object)null) && m_nview.IsOwner()) { if ((Object)(object)m_container == (Object)null || m_container.GetInventory() == null) { m_nview.InvokeRPC(uid, "RPC_PackageRespons", new object[1] { 0 }); } else if (m_container.IsInUse() || m_isInUse) { m_nview.InvokeRPC(uid, "RPC_PackageRespons", new object[1] { 0 }); } else if (m_container.GetInventory().NrOfItems() == 0) { m_nview.InvokeRPC(uid, "RPC_PackageRespons", new object[1] { 3 }); } else { ((MonoBehaviour)this).StartCoroutine(Package(uid)); } } } private IEnumerator Package(long uid) { m_isInUse = true; m_nview.InvokeRPC(ZNetView.Everybody, "RPC_AnimateLever", Array.Empty<object>()); if (m_leverEffects != null) { m_leverEffects.Create(((Component)this).transform.position, ((Component)this).transform.rotation, (Transform)null, 1f, -1, default(ZDOID)); } if ((Object)(object)m_enabled != (Object)null) { m_enabled.SetActive(true); } float delayMin = Mathf.Max(0f, m_effectDelayMin); float delayMax = Mathf.Max(delayMin, m_effectDelayMax); yield return (object)new WaitForSeconds(Random.Range(delayMin, delayMax)); if ((Object)(object)m_nview == (Object)null || !m_nview.IsValid()) { m_isInUse = false; yield break; } m_nview.InvokeRPC(ZNetView.Everybody, "RPC_AnimateLeverReturn", Array.Empty<object>()); if ((Object)(object)m_enabled != (Object)null) { m_enabled.SetActive(false); } if (!m_nview.IsOwner() || (Object)(object)m_container == (Object)null || m_container.GetInventory() == null || m_container.IsInUse()) { m_isInUse = false; yield break; } ((MonoBehaviour)this).Invoke("ReleaseUseLock", 4f); int response = TryCreatePackage(); m_nview.InvokeRPC(uid, "RPC_PackageRespons", new object[1] { response }); } private int TryCreatePackage() { //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02c6: Unknown result type (might be due to invalid IL or missing references) //IL_04b8: Unknown result type (might be due to invalid IL or missing references) //IL_04c3: Unknown result type (might be due to invalid IL or missing references) //IL_04d1: Unknown result type (might be due to invalid IL or missing references) //IL_04d7: Unknown result type (might be due to invalid IL or missing references) Inventory val = (((Object)(object)m_container != (Object)null) ? m_container.GetInventory() : null); if (val == null) { return 0; } List<ItemData> allItems = val.GetAllItems(); if (allItems == null || allItems.Count == 0) { return 3; } if (allItems.Count > 256) { Debug.LogWarning((object)(Launch.projectName + ": Refusing to create package with " + allItems.Count + " entries.")); return 0; } if ((Object)(object)m_defaultResult == (Object)null || (Object)(object)output == (Object)null) { Debug.LogWarning((object)(Launch.projectName + ": Packager missing result item or output transform.")); return 0; } List<PackedEntry> list = new List<PackedEntry>(allItems.Count); StringBuilder stringBuilder = new StringBuilder("Contains:\n", 64 + allItems.Count * 24); bool flag = true; bool flag2 = false; float num = 0f; int num2 = 0; for (int i = 0; i < allItems.Count; i++) { ItemData val2 = allItems[i]; if (!IsValidPackageItem(val2)) { string text = ((val2 != null && (Object)(object)val2.m_dropPrefab != (Object)null) ? ((Object)val2.m_dropPrefab).name : "null"); Debug.LogWarning((object)(Launch.projectName + ": Can't create package; unsupported item: " + text)); return 0; } if (!PackageItemSerializer.TrySerialize(val2, out var encoded)) { Debug.LogWarning((object)(Launch.projectName + ": Failed to serialize " + ((Object)val2.m_dropPrefab).name + ".")); return 0; } num2 += encoded.Length; if (num2 > 1048576) { Debug.LogWarning((object)(Launch.projectName + ": Package payload exceeds the safety limit of " + 1048576 + " encoded characters.")); return 0; } list.Add(new PackedEntry(((Object)val2.m_dropPrefab).name, val2.m_stack, encoded)); stringBuilder.Append(val2.m_shared.m_name).Append(" x").Append(val2.m_stack) .Append('\n'); num += val2.GetWeight(-1); if (!PackageMetadata.IsItemTeleportable(val2)) { flag = false; } if (val2.m_shared.m_toolTier >= 1000) { flag2 = true; } } ItemDrop val3 = Object.Instantiate<ItemDrop>(m_defaultResult, output.position, output.rotation); if ((Object)(object)val3 == (Object)null || val3.m_itemData == null) { return 0; } try { val3.m_itemData.m_stack = 1; PackageMetadata.Set(val3.m_itemData, "BalrondPackageFormatVersion", 3.ToString(CultureInfo.InvariantCulture)); PackageMetadata.Set(val3.m_itemData, "BalrondPackageAmount", list.Count.ToString(CultureInfo.InvariantCulture)); for (int j = 0; j < list.Count; j++) { PackedEntry packedEntry = list[j]; PackageMetadata.Set(val3.m_itemData, "BalrondPackagePrefab-" + j, packedEntry.PrefabName); PackageMetadata.Set(val3.m_itemData, "BalrondPackageData-" + j, packedEntry.SerializedData); ItemData itemData = val3.m_itemData; string key = "BalrondPackageIndex-" + j; string prefabName = packedEntry.PrefabName; int stack = packedEntry.Stack; PackageMetadata.Set(itemData, key, prefabName + "." + stack.ToString(CultureInfo.InvariantCulture)); } string value = stringBuilder.ToString(); float num3 = num * 0.5f; PackageMetadata.Set(val3.m_itemData, "BalrondPackageDescription", value); PackageMetadata.Set(val3.m_itemData, "BalrondPackageWeight", num3.ToString("R", CultureInfo.InvariantCulture)); PackageMetadata.Set(val3.m_itemData, "BalrondPackageTeleportable", flag ? "1" : "0"); PackageMetadata.Set(val3.m_itemData, "BalrondPackageHardNoTeleport", flag2 ? "1" : "0"); val3.Save(); if (m_produceEffects != null) { m_produceEffects.Create(output.position, output.rotation, (Transform)null, 1f, -1, default(ZDOID)); } val.RemoveAll(); return 1; } catch (Exception ex) { if ((Object)(object)val3 != (Object)null && (Object)(object)((Component)val3).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)val3).gameObject); } Debug.LogWarning((object)(Launch.projectName + ": Package creation failed: " + ex)); return 0; } } private static bool IsValidPackageItem(ItemData item) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) if (item == null || item.m_shared == null || (Object)(object)item.m_dropPrefab == (Object)null) { return false; } if (string.Equals(((Object)item.m_dropPrefab).name, "CustomPackageItem_bal", StringComparison.Ordinal)) { return false; } return ValidateItemType(item.m_shared.m_itemType); } private static bool ValidateItemType(ItemType itemType) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Invalid comparison between Unknown and I4 //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Invalid comparison between Unknown and I4 //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 return (int)itemType == 1 || (int)itemType == 2 || (int)itemType == 9 || (int)itemType == 23 || (int)itemType == 16 || (int)itemType == 13 || (int)itemType == 21 || (int)itemType == 24; } private void RPC_PackageRespons(long uid, int response) { if (!((Object)(object)Player.m_localPlayer == (Object)null)) { ((Character)Player.m_localPlayer).Message((MessageType)2, (Response)response switch { Response.Success => "$piece_packager_success", Response.Conversion => "$piece_packager_conversion", Response.Empty => "$piece_packager_empty", _ => "$piece_packager_fail", }, 0, (Sprite)null, false); } } private void RPC_AnimateLever(long uid) { if ((Object)(object)m_leverAnim != (Object)null) { m_leverAnim.SetBool("Pulled", true); } } private void RPC_AnimateLeverReturn(long uid) { if ((Object)(object)m_leverAnim != (Object)null) { m_leverAnim.SetBool("Pulled", false); } } } public class BalrondUnpackager : MonoBehaviour, Hoverable, Interactable { public string m_name = "$tag_unpackager_bal"; public string m_useItemText = "$tag_use_me"; public ItemDrop m_requiredItem; public Transform m_itemSpawnPoint; public float m_SpawnDelay = 2f; [Header("Effects")] public EffectList m_spawnStartEffects = new EffectList(); public EffectList m_spawnFinishEffects = new EffectList(); public Transform m_roofCheckPoint; public bool m_requiresRoof; private ZNetView m_nview; private void Awake() { m_nview = ((Component)this).GetComponent<ZNetView>(); if ((Object)(object)m_nview == (Object)null || m_nview.GetZDO() == null) { ZLog.Log((object)(Launch.projectName + ": Missing ZNetView on unpackager " + ((Object)((Component)this).gameObject).name)); } else if ((Object)(object)m_requiredItem == (Object)null) { m_requiredItem = FindRequiredItem(); } } private static ItemDrop FindRequiredItem() { GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab("CustomPackageItem_bal") : null); if ((Object)(object)val == (Object)null && (Object)(object)ZNetScene.instance != (Object)null && ZNetScene.instance.m_prefabs != null) { val = ZNetScene.instance.m_prefabs.Find((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == "CustomPackageItem_bal"); } return ((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null; } public string GetHoverText() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) string text; if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { text = m_name + "\n$piece_noaccess"; } else { string text2 = string.Empty; if ((Object)(object)m_requiredItem != (Object)null && m_requiredItem.m_itemData != null && m_requiredItem.m_itemData.m_shared != null) { text2 = m_requiredItem.m_itemData.m_shared.m_name; } text = m_name + "\n[<color=yellow><b>1-8</b></color>] \n" + m_useItemText + " " + text2; } return (Localization.instance != null) ? Localization.instance.Localize(text) : text; } public string GetHoverName() { return m_name; } public float GetHoverOffset() { return 0f; } public bool Interact(Humanoid user, bool hold, bool alt) { return !hold; } public bool UseItem(Humanoid user, ItemData item) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)user == (Object)null || (Object)(object)user != (Object)(object)Player.m_localPlayer || item == null || (Object)(object)item.m_dropPrefab == (Object)null) { return false; } if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return true; } if (!CheckUsable((Player)(object)((user is Player) ? user : null), showMessage: true)) { return true; } if (!string.Equals(((Object)item.m_dropPrefab).name, "CustomPackageItem_bal", StringComparison.Ordinal)) { ((Character)user).Message((MessageType)2, "$tag_cant_unpack", 0, (Sprite)null, false); return true; } if (!TryDeserializePackage(item, out var unpackedItems)) { ((Character)user).Message((MessageType)2, "$piece_packager_fail", 0, (Sprite)null, false); return true; } Vector3 spawnPosition = GetSpawnPosition(); if (m_spawnStartEffects != null) { m_spawnStartEffects.Create(spawnPosition, ((Component)this).transform.rotation, (Transform)null, 1f, -1, default(ZDOID)); } if (!SpawnItems(unpackedItems, spawnPosition)) { ((Character)user).Message((MessageType)2, "$piece_packager_fail", 0, (Sprite)null, false); return true; } if (m_spawnFinishEffects != null) { m_spawnFinishEffects.Create(spawnPosition, ((Component)this).transform.rotation, (Transform)null, 1f, -1, default(ZDOID)); } ((Character)user).ShowRemovedMessage(item, 1); user.GetInventory().RemoveItem(item, 1); ((Character)user).Message((MessageType)2, "$tag_unpacked_it", 0, (Sprite)null, false); return true; } public bool CheckUsable(Player player, bool showMessage) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)player == (Object)null) { return false; } if (m_requiresRoof && !player.NoCostCheat()) { if ((Object)(object)m_roofCheckPoint == (Object)null) { return false; } float num = default(float); bool flag = default(bool); Cover.GetCoverForPoint(m_roofCheckPoint.position, ref num, ref flag, 0.5f); if (!flag) { if (showMessage) { ((Character)player).Message((MessageType)2, "$msg_stationneedroof", 0, (Sprite)null, false); } return false; } if (num < 0.7f) { if (showMessage) { ((Character)player).Message((MessageType)2, "$msg_stationtooexposed", 0, (Sprite)null, false); } return false; } } return true; } private Vector3 GetSpawnPosition() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) return ((Object)(object)m_itemSpawnPoint != (Object)null) ? m_itemSpawnPoint.position : ((Component)this).transform.position; } private static bool TryDeserializePackage(ItemData packageItem, out List<ItemData> unpackedItems) { unpackedItems = null; if (packageItem == null || packageItem.m_customData == null || (Object)(object)ObjectDB.instance == (Object)null) { return false; } if (!PackageMetadata.TryGetInt(packageItem, "BalrondPackageAmount", out var value) || value <= 0 || value > 256) { return false; } int formatVersion = PackageMetadata.GetFormatVersion(packageItem); if (formatVersion > 3) { Debug.LogWarning((object)(Launch.projectName + ": Unsupported package format version " + formatVersion + ".")); return false; } List<ItemData> list = new List<ItemData>(value); for (int i = 0; i < value; i++) { if (!TryDeserializeEntry(packageItem, i, formatVersion, out var restored)) { return false; } list.Add(restored); } unpackedItems = list; return true; } private static bool TryDeserializeEntry(ItemData packageItem, int index, int formatVersion, out ItemData restored) { restored = null; if (formatVersion >= 3) { if (!packageItem.m_customData.TryGetValue("BalrondPackagePrefab-" + index, out var value) || !packageItem.m_customData.TryGetValue("BalrondPackageData-" + index, out var value2) || string.IsNullOrEmpty(value) || string.IsNullOrEmpty(value2)) { return false; } return PackageItemSerializer.TryDeserialize(value, value2, out restored); } if (!packageItem.m_customData.TryGetValue("BalrondPackageIndex-" + index, out var value3) || string.IsNullOrEmpty(value3)) { return false; } int num = value3.LastIndexOf('.'); if (num <= 0 || num >= value3.Length - 1) { return false; } string text = value3.Substring(0, num); if (!int.TryParse(value3.Substring(num + 1), NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || result <= 0) { return false; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(text); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val == (Object)null || val.m_itemData == null || val.m_itemData.m_shared == null) { return false; } restored = val.m_itemData.Clone(); restored.m_shared = val.m_itemData.m_shared; restored.m_dropPrefab = itemPrefab; restored.m_stack = result; restored.m_equipped = false; return true; } private static bool SpawnItems(List<ItemData> items, Vector3 spawnPosition) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) if (items == null || items.Count == 0) { return false; } for (int i = 0; i < items.Count; i++) { ItemData val = items[i]; if (val == null || (Object)(object)val.m_dropPrefab == (Object)null || val.m_stack <= 0) { return false; } ItemDrop val2 = ItemDrop.DropItem(val, val.m_stack, spawnPosition, Quaternion.identity); if ((Object)(object)val2 == (Object)null) { return false; } } return true; } } public sealed class DatabaseAddMethods { public bool AddItems(ObjectDB db, List<GameObject> items) { if ((Object)(object)db == (Object)null || db.m_items == null || items == null || items.Count == 0) { return false; } HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); for (int i = 0; i < db.m_items.Count; i++) { GameObject val = db.m_items[i]; if ((Object)(object)val != (Object)null && !string.IsNullOrEmpty(((Object)val).name)) { hashSet.Add(((Object)val).name); } } bool result = false; for (int j = 0; j < items.Count; j++) { GameObject val2 = items[j]; if (!((Object)(object)val2 == (Object)null) && !string.IsNullOrEmpty(((Object)val2).name) && !hashSet.Contains(((Object)val2).name)) { ItemDrop component = val2.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null) { Debug.LogWarning((object)(Launch.projectName + ": Invalid item prefab skipped from ObjectDB: " + ((Object)val2).name)); continue; } db.m_items.Add(val2); hashSet.Add(((Object)val2).name); result = true; } } return result; } public bool AddRecipes(ObjectDB db, List<Recipe> recipes) { if ((Object)(object)db == (Object)null || db.m_recipes == null || recipes == null || recipes.Count == 0) { return false; } HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); for (int i = 0; i < db.m_recipes.Count; i++) { Recipe val = db.m_recipes[i]; if ((Object)(object)val != (Object)null && !string.IsNullOrEmpty(((Object)val).name)) { hashSet.Add(((Object)val).name); } } bool result = false; for (int j = 0; j < recipes.Count; j++) { Recipe val2 = recipes[j]; if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.m_item == (Object)null) && !string.IsNullOrEmpty(((Object)val2).name) && !hashSet.Contains(((Object)val2).name)) { db.m_recipes.Add(val2); hashSet.Add(((Object)val2).name); result = true; } } return result; } public bool AddStatusEffects(ObjectDB db, List<StatusEffect> statusEffects) { if ((Object)(object)db == (Object)null || db.m_StatusEffects == null || statusEffects == null || statusEffects.Count == 0) { return false; } HashSet<int> hashSet = new HashSet<int>(); for (int i = 0; i < db.m_StatusEffects.Count; i++) { StatusEffect val = db.m_StatusEffects[i]; if ((Object)(object)val != (Object)null) { hashSet.Add(val.NameHash()); } } bool result = false; for (int j = 0; j < statusEffects.Count; j++) { StatusEffect val2 = statusEffects[j]; if (!((Object)(object)val2 == (Object)null) && !hashSet.Contains(val2.NameHash())) { db.m_StatusEffects.Add(val2); hashSet.Add(val2.NameHash()); result = true; } } return result; } } public sealed class ModResourceLoader { public AssetBundle assetBundle; public readonly List<GameObject> buildPrefabs = new List<GameObject>(); public readonly List<GameObject> plantPrefabs = new List<GameObject>(); public readonly List<GameObject> itemPrefabs = new List<GameObject>(); public readonly List<GameObject> monsterPrefabs = new List<GameObject>(); public readonly List<GameObject> vegetationPrefabs = new List<GameObject>(); public readonly List<GameObject> clutterPrefabs = new List<GameObject>(); public readonly List<GameObject> locationPrefabs = new List<GameObject>(); public readonly List<GameObject> roomPrefabs = new List<GameObject>(); public readonly List<GameObject> vfxPrefabs = new List<GameObject>(); public readonly List<Sprite> backgrounds = new List<Sprite>(); public readonly List<Recipe> recipes = new List<Recipe>(); public readonly List<StatusEffect> statusEffects = new List<StatusEffect>(); public void LoadAssets() { ClearLoadedCollections(); assetBundle = GetAssetBundleFromResources("balrondpackager"); if ((Object)(object)assetBundle == (Object)null) { Debug.LogError((object)(Launch.projectName + ": embedded AssetBundle 'balrondpackager' was not found or could not be loaded.")); return; } LoadPieces("Assets/Custom/Comission/BalrondPackager/"); LoadItems("Assets/Custom/Comission/BalrondPackager/"); LoadOther("Assets/Custom/Comission/BalrondPackager/"); } private void ClearLoadedCollections() { buildPrefabs.Clear(); plantPrefabs.Clear(); itemPrefabs.Clear(); monsterPrefabs.Clear(); vegetationPrefabs.Clear(); clutterPrefabs.Clear(); locationPrefabs.Clear(); roomPrefabs.Clear(); vfxPrefabs.Clear(); backgrounds.Clear(); recipes.Clear(); statusEffects.Clear(); } public void AddPrefabsToZnetScene(ZNetScene zNetScene) { if ((Object)(object)zNetScene == (Object)null || zNetScene.m_prefabs == null) { return; } HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); HashSet<int> hashSet2 = new HashSet<int>(); for (int i = 0; i < zNetScene.m_prefabs.Count; i++) { GameObject val = zNetScene.m_prefabs[i]; if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(((Object)val).name)) { hashSet.Add(((Object)val).name); hashSet2.Add(StringExtensionMethods.GetStableHashCode(((Object)val).name)); } } AddUniquePrefabs(itemPrefabs, zNetScene, hashSet, hashSet2, requireZNetView: true); AddUniquePrefabs(plantPrefabs, zNetScene, hashSet, hashSet2, requireZNetView: true); AddUniquePrefabs(vfxPrefabs, zNetScene, hashSet, hashSet2, requireZNetView: false); AddUniquePrefabs(buildPrefabs, zNetScene, hashSet, hashSet2, requireZNetView: true); Launch.buildPieceBuilder.SetupBuildPieces(zNetScene.m_prefabs); SetupBuildPiecesList(zNetScene); SetupPackager(zNetScene); SetupUnpackager(zNetScene); } private static void AddUniquePrefabs(List<GameObject> prefabs, ZNetScene zNetScene, HashSet<string> names, HashSet<int> hashes, bool requireZNetView) { if (prefabs == null) { return; } for (int i = 0; i < prefabs.Count; i++) { GameObject val = prefabs[i]; if ((Object)(object)val == (Object)null || string.IsNullOrEmpty(((Object)val).name)) { continue; } if (requireZNetView && (Object)(object)val.GetComponent<ZNetView>() == (Object)null) { Debug.LogWarning((object)(Launch.projectName + ": network prefab skipped because it has no ZNetView: " + ((Object)val).name)); continue; } int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)val).name); if (names.Contains(((Object)val).name)) { Debug.LogWarning((object)(Launch.projectName + ": duplicate ZNetScene prefab name skipped: " + ((Object)val).name)); } else if (hashes.Contains(stableHashCode)) { Debug.LogWarning((object)(Launch.projectName + ": ZNetScene stable-hash collision skipped: " + ((Object)val).name + " (" + stableHashCode + ")")); } else { zNetScene.m_prefabs.Add(val); names.Add(((Object)val).name); hashes.Add(stableHashCode); } } } private void SetupBuildPiecesList(ZNetScene zNetScene) { GameObject val = FindPrefab(zNetScene.m_prefabs, "Hammer"); ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null); PieceTable val3 = (((Object)(object)val2 != (Object)null && val2.m_itemData != null && val2.m_itemData.m_shared != null) ? val2.m_itemData.m_shared.m_buildPieces : null); if ((Object)(object)val3 == (Object)null || val3.m_pieces == null) { Debug.LogWarning((object)(Launch.projectName + ": Hammer PieceTable not available during ZNetScene setup.")); return; } string[] array = new string[4] { "Hammer", "HammerIron_bal", "HammerDverger_bal", "HammerBlackmetal_bal" }; for (int i = 0; i < array.Length; i++) { AddTableToTool(array[i], val3, zNetScene.m_prefabs); } for (int j = 0; j < buildPrefabs.Count; j++) { GameObject val4 = buildPrefabs[j]; if (!((Object)(object)val4 == (Object)null) && !string.IsNullOrEmpty(((Object)val4).name)) { GameObject val5 = FindPrefab(zNetScene.m_prefabs, ((Object)val4).name); if ((Object)(object)val5 == (Object)null) { Debug.LogWarning((object)(Launch.projectName + ": build prefab is not registered in ZNetScene and will not be added to Hammer: " + ((Object)val4).name)); continue; } SetupRavenGuide(val5, zNetScene.m_prefabs); AddToBuildList(val5, val3.m_pieces); } } } private static void AddTableToTool(string name, PieceTable pieceTable, List<GameObject> prefabs) { GameObject val = FindPrefab(prefabs, name); ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null); if (!((Object)(object)val2 == (Object)null) && val2.m_itemData != null && val2.m_itemData.m_shared != null) { val2.m_itemData.m_shared.m_buildPieces = pieceTable; } } public static void SetupRavenGuide(GameObject gameObject, List<GameObject> prefabs) { if ((Object)(object)gameObject == (Object)null || prefabs == null) { return; } Transform val = gameObject.transform.Find("GuidePoint"); GuidePoint val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<GuidePoint>() : null); if (!((Object)(object)val2 == (Object)null)) { GameObject val3 = FindPrefab(prefabs, "piece_workbench"); Transform val4 = (((Object)(object)val3 != (Object)null) ? val3.transform.Find("GuidePoint") : null); GuidePoint val5 = (((Object)(object)val4 != (Object)null) ? ((Component)val4).GetComponent<GuidePoint>() : null); if ((Object)(object)val5 != (Object)null) { val2.m_ravenPrefab = val5.m_ravenPrefab; } } } private static bool AddToBuildList(GameObject prefab, List<GameObject> buildPieces) { if ((Object)(object)prefab == (Object)null || buildPieces == null) { return false; } for (int i = 0; i < buildPieces.Count; i++) { GameObject val = buildPieces[i]; if ((Object)(object)val != (Object)null && string.Equals(((Object)val).name, ((Object)prefab).name, StringComparison.Ordinal)) { return false; } } buildPieces.Add(prefab); return true; } private static GameObject FindPrefab(List<GameObject> prefabs, string name) { if (prefabs == null || string.IsNullOrEmpty(name)) { return null; } for (int i = 0; i < prefabs.Count; i++) { GameObject val = prefabs[i]; if ((Object)(object)val != (Object)null && string.Equals(((Object)val).name, name, StringComparison.Ordinal)) { return val; } } return null; } private static AssetBundle GetAssetBundleFromResources(string filenameSuffix) { Assembly executingAssembly = Assembly.GetExecutingAssembly(); string[] manifestResourceNames = executingAssembly.GetManifestResourceNames(); string text = null; for (int i = 0; i < manifestResourceNames.Length; i++) { if (manifestResourceNames[i].EndsWith(filenameSuffix, StringComparison.OrdinalIgnoreCase)) { text = manifestResourceNames[i]; break; } } if (text == null) { return null; } using Stream stream = executingAssembly.GetManifestResourceStream(text); return (stream != null) ? AssetBundle.LoadFromStream(stream) : null; } private void LoadPieces(string basePath) { string mainPath = basePath + "Pieces/"; for (int i = 0; i < BuildPieceList.buildPieces.Length; i++) { LoadPrefab(mainPath, BuildPieceList.buildPieces[i], buildPrefabs, "piece"); } } private void LoadItems(string basePath) { string mainPath = basePath + "Items/"; for (int i = 0; i < ItemList.items.Length; i++) { LoadPrefab(mainPath, ItemList.items[i], itemPrefabs, "item"); } } private void LoadOther(string basePath) { } private void LoadPrefab(string mainPath, string name, List<GameObject> target, string kind) { if (!((Object)(object)assetBundle == (Object)null) && !string.IsNullOrEmpty(name)) { GameObject val = assetBundle.LoadAsset<GameObject>(mainPath + name + ".prefab"); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)(Launch.projectName + ": could not find " + kind + " prefab: " + name + " at " + mainPath)); } else { ShaderReplacment.Replace(val); target.Add(val); } } } private void SetupPackager(ZNetScene zNetScene) { GameObject val = FindPrefab(zNetScene.m_prefabs, "packager_bal"); if (!((Object)(object)val == (Object)null)) { BalrondPackager balrondPackager = val.GetComponent<BalrondPackager>(); if ((Object)(object)balrondPackager == (Object)null) { balrondPackager = val.AddComponent<BalrondPackager>(); } Incinerator component = val.GetComponent<Incinerator>(); if ((Object)(object)component != (Object)null) { balrondPackager.m_container = component.m_container; balrondPackager.m_leverAnim = component.m_leverAnim; balrondPackager.m_leverEffects = component.m_leverEffects; balrondPackager.m_incinerateSwitch = component.m_incinerateSwitch; Transform val2 = val.transform.Find("_enabled"); balrondPackager.m_enabled = (((Object)(object)val2 != (Object)null) ? ((Component)val2).gameObject : null); balrondPackager.output = val.transform.Find("output"); Object.Destroy((Object)(object)component); } GameObject val3 = FindPrefab(zNetScene.m_prefabs, "CustomPackageItem_bal"); balrondPackager.m_defaultResult = (((Object)(object)val3 != (Object)null) ? val3.GetComponent<ItemDrop>() : null); balrondPackager.m_defaultCost = 1; if ((Object)(object)balrondPackager.m_defaultResult != (Object)null && balrondPackager.m_defaultResult.m_itemData != null && balrondPackager.m_defaultResult.m_itemData.m_shared != null) { balrondPackager.m_defaultResult.m_itemData.m_shared.m_maxStackSize = 1; balrondPackager.m_defaultResult.m_itemData.m_shared.m_autoStack = false; balrondPackager.m_defaultResult.m_itemData.m_shared.m_description = "$tag_packagebundle_description"; } if ((Object)(object)balrondPackager.m_container == (Object)null || (Object)(object)balrondPackager.m_incinerateSwitch == (Object)null || (Object)(object)balrondPackager.output == (Object)null || (Object)(object)balrondPackager.m_defaultResult == (Object)null) { Debug.LogWarning((object)(Launch.projectName + ": packager prefab is missing one or more required references.")); } } } private void SetupUnpackager(ZNetScene zNetScene) { GameObject val = FindPrefab(zNetScene.m_prefabs, "unpackager_bal"); if (!((Object)(object)val == (Object)null)) { BalrondUnpackager balrondUnpackager = val.GetComponent<BalrondUnpackager>(); if ((Object)(object)balrondUnpackager == (Object)null) { balrondUnpackager = val.AddComponent<BalrondUnpackager>(); } balrondUnpackager.m_requiresRoof = false; GameObject val2 = FindPrefab(zNetScene.m_prefabs, "CustomPackageItem_bal"); balrondUnpackager.m_requiredItem = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<ItemDrop>() : null); balrondUnpackager.m_itemSpawnPoint = val.transform.Find("spawnpoint"); balrondUnpackager.m_roofCheckPoint = val.transform.Find("roof_check_pint"); if ((Object)(object)balrondUnpackager.m_itemSpawnPoint == (Object)null) { Debug.LogWarning((object)(Launch.projectName + ": unpackager spawnpoint not found; transform position will be used.")); } } } } public class ShaderReplacment { public static readonly List<GameObject> prefabsToReplaceShader = new List<GameObject>(); public static readonly List<Material> materialsInPrefabs = new List<Material>(); public static readonly List<Shader> shaders = new List<Shader>(); public static bool debug = true; private static readonly HashSet<GameObject> PrefabSet = new HashSet<GameObject>(); private static readonly HashSet<Material> MaterialSet = new HashSet<Material>(); private static readonly Dictionary<string, Shader> ShaderByName = new Dictionary<string, Shader>(StringComparer.Ordinal); private static bool shadersIndexed; private static bool materialFixApplied; public string[] shaderlist = new string[49] { "Custom/AlphaParticle", "Custom/Blob", "Custom/Bonemass", "Custom/Clouds", "Custom/Creature", "Custom/Decal", "Custom/Distortion", "Custom/Flow", "Custom/FlowOpaque", "Custom/Grass", "Custom/GuiScroll", "Custom/Heightmap", "Custom/icon", "Custom/InteriorSide", "Custom/LitGui", "Custom/LitParticles", "Custom/mapshader", "Custom/ParticleDecal", "Custom/Piece", "Custom/Player", "Custom/Rug", "Custom/ShadowBlob", "Custom/SkyboxProcedural", "Custom/SkyObject", "Custom/StaticRock", "Custom/Tar", "Custom/Trilinearmap", "Custom/UI/BGBlur", "Custom/Vegetation", "Custom/Water", "Custom/WaterBottom", "Custom/WaterMask", "Custom/Yggdrasil", "Custom/Yggdrasil/root", "Hidden/BlitCopyHDRTonemap", "Hidden/Dof/DepthOfFieldHdr", "Hidden/Dof/DX11Dof", "Hidden/Internal-Loading", "Hidden/Internal-UIRDefaultWorld", "Hidden/SimpleClear", "Hidden/SunShaftsComposite", "Lux Lit Particles/ Bumped", "Lux Lit Particles/ Tess Bumped", "Particles/Standard Surface2", "Particles/Standard Unlit2", "Standard TwoSided", "ToonDeferredShading2017", "Unlit/DepthWrite", "Unlit/Lighting" }; public static void Replace(GameObject gameObject) { if (!((Object)(object)gameObject == (Object)null)) { if (PrefabSet.Add(gameObject)) { prefabsToReplaceShader.Add(gameObject); } GetMaterialsInPrefab(gameObject); } } public static void GetMaterialsInPrefab(GameObject gameObject) { if ((Object)(object)gameObject == (Object)null) { return; } Renderer[] componentsInChildren = gameObject.GetComponentsInChildren<Renderer>(true); Renderer[] array = componentsInChildren; foreach (Renderer val in array) { if ((Object)(object)val == (Object)null) { continue; } Material[] sharedMaterials = val.sharedMaterials; if (sharedMaterials == null) { continue; } Material[] array2 = sharedMaterials; foreach (Material val2 in array2) { if ((Object)(object)val2 != (Object)null && MaterialSet.Add(val2)) { materialsInPrefabs.Add(val2); } } } } private static void IndexLoadedShaders() { if (shadersIndexed) { return; } shadersIndexed = true; ShaderByName.Clear(); shaders.Clear(); Shader[] array = Resources.FindObjectsOfTypeAll<Shader>(); Shader[] array2 = array; foreach (Shader val in array2) { if (!((Object)(object)val == (Object)null) && !string.IsNullOrEmpty(((Object)val).name) && !ShaderByName.ContainsKey(((Object)val).name)) { ShaderByName.Add(((Object)val).name, val); shaders.Add(val); } } } public static Shader findShader(string name) { return GetShaderByName(name); } public static Shader GetShaderByName(string name) { if (string.IsNullOrWhiteSpace(name)) { return null; } IndexLoadedShaders(); name = name.Trim(); if (ShaderByName.TryGetValue(name, out var value)) { return value; } value = Shader.Find(name); if ((Object)(object)value != (Object)null) { ShaderByName[name] = value; if (!shaders.Contains(value)) { shaders.Add(value); } } return value; } public static void getMeShaders() { IndexLoadedShaders(); } public static void debugShaderList(List<Shader> shaderList) { if (shaderList == null) { return; } foreach (Shader shader in shaderList) { if ((Object)(object)shader != (Object)null) { Debug.LogWarning((object)("SHADER NAME IS: " + ((Object)shader).name)); } } debug = false; } public static void runMaterialFix() { if (materialFixApplied) { return; } materialFixApplied = true; IndexLoadedShaders(); int num = 0; int num2 = 0; foreach (Material materialsInPrefab in materialsInPrefabs) { if ((Object)(object)materialsInPrefab == (Object)null || (Object)(object)materialsInPrefab.shader == (Object)null) { continue; } string name = ((Object)materialsInPrefab.shader).name; if (!string.IsNullOrEmpty(name) && !(name == "Standard") && name.IndexOf("ScrollingTex", StringComparison.Ordinal) < 0 && name.IndexOf("Balrond", StringComparison.Ordinal) >= 0) { string text = checkNaming(name.Replace("Balrond", "Custom")); Shader shaderByName = GetShaderByName(text); if ((Object)(object)shaderByName == (Object)null) { num2++; Debug.LogWarning((object)(Launch.projectName + ": shader replacement not found: " + name + " -> " + text)); } else { materialsInPrefab.shader = shaderByName; num++; } } } Debug.Log((object)$"{Launch.projectName}: shader material pass complete: replaced={num}, unresolved={num2}, uniqueMaterials={materialsInPrefabs.Count}."); } private static string checkNaming(string name) { if (name.IndexOf("Tess Bumped", StringComparison.Ordinal) >= 0 || name.IndexOf("Bumped", StringComparison.Ordinal) >= 0) { return name.Replace("Custom", "Lux Lit Particles"); } if (name.IndexOf("Standard Surface", StringComparison.Ordinal) >= 0) { return name.Replace("Custom", "Particles").Replace("Standard Surface2", "Standard Surface"); } if (name.IndexOf("Standard Unlit", StringComparison.Ordinal) >= 0) { return name.Replace("Custom", "Particles").Replace("Standard Unlit", "Standard Unlit2").Replace("Standard Unlit22", "Standard Unlit2"); } return name; } } public static class TableMapper { public static CraftingStation cauldron; public static CraftingStation workbench; public static CraftingStation heavyWorkbench; public static CraftingStation forge; public static CraftingStation ironworks; public static CraftingStation blackforge; public static CraftingStation stoneCutter; public static CraftingStation artisian; public static CraftingStation magetable; public static CraftingStation runeforge; public static CraftingStation tannery; public static CraftingStation fletcher; public static CraftingStation grill; public static CraftingStation alchemylab; public static void setupTables(List<GameObject> prefabs) { if (prefabs == null) { return; } Dictionary<string, GameObject> dictionary = new Dictionary<string, GameObject>(StringComparer.Ordinal); for (int i = 0; i < prefabs.Count; i++) { GameObject val = prefabs[i]; if ((Object)(object)val != (Object)null && !string.IsNullOrEmpty(((Object)val).name) && !dictionary.ContainsKey(((Object)val).name)) { dictionary.Add(((Object)val).name, val); } } cauldron = FindStation(dictionary, "piece_cauldron"); workbench = FindStation(dictionary, "piece_workbench"); heavyWorkbench = FindStation(dictionary, "piece_heavy_workbench_bal", warn: false); forge = FindStation(dictionary, "forge"); ironworks = FindStation(dictionary, "piece_metalworks_bal", warn: false); blackforge = FindStation(dictionary, "blackforge", warn: false); stoneCutter = FindStation(dictionary, "piece_stonecutter", warn: false); artisian = FindStation(dictionary, "piece_artisanstation", warn: false); runeforge = FindStation(dictionary, "piece_runeforge_bal", warn: false); magetable = FindStation(dictionary, "piece_magetable", warn: false); fletcher = FindStation(dictionary, "piece_fletcher_bal", warn: false); } private static CraftingStation FindStation(Dictionary<string, GameObject> byName, string name, bool warn = true) { if (byName.TryGetValue(name, out var value) && (Object)(object)value != (Object)null) { return value.GetComponent<CraftingStation>(); } if (warn) { Debug.LogWarning((object)(Launch.projectName + ": crafting station not found: " + name)); } return null; } } internal class ItemList { public static string[] items = new string[1] { "CustomPackageItem_bal" }; } public sealed class JsonLoader { public string defaultPath = string.Empty; public void loadJson() { defaultPath = GetTranslationPath(); LoadTranslations(defaultPath); } public void justDefaultPath() { defaultPath = GetTranslationPath(); } public void createDefaultPath() { defaultPath = GetTranslationPath(); EnsureDirectory(defaultPath); } private static string GetTranslationPath() { return Path.Combine(Paths.ConfigPath, "BalrondPackager-translation"); } private static void EnsureDirectory(string path) { try { Directory.CreateDirectory(path); } catch (Exception ex) { Debug.LogWarning((object)("BalrondPackager: failed to create translation directory: " + ex.Message)); } } private static void LoadTranslations(string path) { EnsureDirectory(path); BalrondTranslator.translations.Clear(); string[] files; try { files = Directory.GetFiles(path, "*.json"); } catch (Exception ex) { Debug.LogWarning((object)("BalrondPackager: failed to enumerate translation files: " + ex.Message)); return; } int num = 0; foreach (string text in files) { try { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text); JsonData jsonData = JsonMapper.ToObject(File.ReadAllText(text)); Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.Ordinal); foreach (string key in jsonData.Keys) { dictionary[key] = ((jsonData[key] != null) ? jsonData[key].ToString() : string.Empty); } BalrondTranslator.translations[fileNameWithoutExtension] = dictionary; num++; } catch (Exception ex2) { Debug.LogWarning((object)("BalrondPackager: failed to load translation '" + text + "': " + ex2.Message)); } } Debug.Log((object)("BalrondPackager: translation files loaded: " + num)); } } [BepInPlugin("balrond.astafaraios.BalrondPackager", "BalrondPackager", "1.1.2")] public sealed class Launch : BaseUnityPlugin { [HarmonyPatch(typeof(FejdStartup), "SetupGui")] private static class FejdStartup_SetupGUI { private static void Postfix() { if (Localization.instance != null) { AddTranslations(Localization.instance, Localization.instance.GetSelectedLanguage()); } } } [HarmonyPatch(typeof(AudioMan), "Awake")] private static class AudioMan_Awake_Patch { private static void Postfix(AudioMan __instance) { if (!((Object)(object)__instance == (Object)null) && !((Object)(object)__instance.m_masterMixer == (Object)null)) { ApplyMixer(modResourceLoader.itemPrefabs, __instance); ApplyMixer(modResourceLoader.buildPrefabs, __instance); ApplyMixer(modResourceLoader.monsterPrefabs, __instance); ApplyMixer(modResourceLoader.vfxPrefabs, __instance); ApplyMixer(modResourceLoader.vegetationPrefabs, __instance); } } private static void ApplyMixer(List<GameObject> prefabs, AudioMan audioMan) { if (prefabs == null) { return; } for (int i = 0; i < prefabs.Count; i++) { GameObject val = prefabs[i]; if ((Object)(object)val == (Object)null) { continue; } AudioSource[] componentsInChildren = val.GetComponentsInChildren<AudioSource>(true); for (int j = 0; j < componentsInChildren.Length; j++) { if ((Object)(object)componentsInChildren[j] != (Object)null) { componentsInChildren[j].outputAudioMixerGroup = audioMan.m_masterMixer.outputAudioMixerGroup; } } } } } [HarmonyPriority(800)] [HarmonyPatch(typeof(ObjectDB), "Awake")] private static class ObjectDB_Awake_Patch { private static void Prefix(ObjectDB __instance) { PrepareObjectDB(__instance); } } [HarmonyPriority(800)] [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB", new Type[] { typeof(ObjectDB) })] private static class ObjectDB_CopyOtherDB_Patch { private static void Prefix(ObjectDB __0) { PrepareObjectDB(__0); } } [HarmonyPriority(800)] [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class ZNetScene_Awake_Patch { private static void Prefix(ZNetScene __instance) { if (!((Object)(object)__instance == (Object)null)) { modResourceLoader.AddPrefabsToZnetScene(__instance); if ((Object)(object)ObjectDB.instance != (Object)null) { ObjectDB.instance.m_buildPieces = null; } } } private static void Postfix() { if (!s_materialFixApplied && ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsDedicated())) { ShaderReplacment.runMaterialFix(); s_materialFixApplied = true; } } } [HarmonyPriority(800)] [HarmonyPatch(typeof(Localization), "SetupLanguage")] private static class Translation_SetupLanguage { private static void Postfix(Localization __instance, string __0) { AddTranslations(__instance, __0); } } public const string PluginGUID = "balrond.astafaraios.BalrondPackager"; public const string PluginName = "BalrondPackager"; public const string PluginVersion = "1.1.2"; public static readonly ModResourceLoader modResourceLoader = new ModResourceLoader(); public static readonly DatabaseAddMethods databaseAddMethods = new DatabaseAddMethods(); public static readonly BuildPieceBuilder buildPieceBuilder = new BuildPieceBuilder(); public static readonly JsonLoader jsonLoader = new JsonLoader(); public static GameObject RootObject; public static GameObject PrefabContainer; public static string projectName = "BalrondPackager"; private readonly Harmony m_harmony = new Harmony("balrond.astafaraios.BalrondPackager"); private static bool s_materialFixApplied; private void Awake() { jsonLoader.loadJson(); CreatePrefabContainer(); modResourceLoader.LoadAssets(); RegisterCompatibilityPatches(); } private void RegisterCompatibilityPatches() { int num = 0; num += PatchClass(typeof(FejdStartup_SetupGUI)); num += PatchClass(typeof(AudioMan_Awake_Patch)); num += PatchClass(typeof(ObjectDB_Awake_Patch)); num += PatchClass(typeof(ObjectDB_CopyOtherDB_Patch)); num += PatchClass(typeof(ZNetScene_Awake_Patch)); num += PatchClass(typeof(Translation_SetupLanguage)); num += PatchClass(typeof(PackageItemWeightPatch)); num += PatchClass(typeof(PackageItemTooltipPatch)); num += PatchClass(typeof(PackageInventoryTeleportPatch)); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Valheim Deep North publicized compatibility patches registered: " + num + ".")); } private int PatchClass(Type patchType) { try { m_harmony.CreateClassProcessor(patchType).Patch(); return 1; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("Failed to patch " + patchType.FullName + ": " + ex)); return 0; } } private static void CreatePrefabContainer() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown if (!((Object)(object)RootObject != (Object)null)) { RootObject = new GameObject("_BalrondPackagerRoot"); Object.DontDestroyOnLoad((Object)(object)RootObject); PrefabContainer = new GameObject("Prefabs"); PrefabContainer.transform.SetParent(RootObject.transform, false); PrefabContainer.SetActive(false); } } public static GameObject CloneMe(GameObject source, string name) { if ((Object)(object)source == (Object)null) { Debug.LogWarning((object)("BalrondPackager: CloneMe source is null for " + name)); return null; } if ((Object)(object)PrefabContainer == (Object)null) { CreatePrefabContainer(); } GameObject val = Object.Instantiate<GameObject>(source, PrefabContainer.transform); ((Object)val).name = name; FixMaterials(val, source); val.SetActive(true); return val; } public static GameObject FixMaterials(GameObject clone, GameObject source) { if ((Object)(object)clone == (Object)null || (Object)(object)source == (Object)null) { return clone; } MeshRenderer[] componentsInChildren = source.GetComponentsInChildren<MeshRenderer>(true); MeshRenderer[] componentsInChildren2 = clone.GetComponentsInChildren<MeshRenderer>(true); int num = Mathf.Min(componentsInChildren.Length, componentsInChildren2.Length); for (int i = 0; i < num; i++) { if ((Object)(object)componentsInChildren[i] != (Object)null && (Object)(object)componentsInChildren2[i] != (Object)null) { ((Renderer)componentsInChildren2[i]).sharedMaterials = ((Renderer)componentsInChildren[i]).sharedMaterials; } } return clone; } private void OnDestroy() { m_harmony.UnpatchSelf(); } private static void AddTranslations(Localization localization, string language) { if (localization == null) { return; } string text = (string.IsNullOrEmpty(language) ? "English" : language); Dictionary<string, string> language2 = BalrondTranslator.getLanguage(text); if (language2 == null) { language2 = BalrondTranslator.getLanguage("English"); if (language2 == null) { Debug.LogWarning((object)("BalrondPackager: No translation data found for '" + text + "' or English.")); return; } } foreach (KeyValuePair<string, string> item in language2) { if (!string.IsNullOrEmpty(item.Key)) { localization.AddWord(item.Key, item.Value ?? string.Empty); } } } private static void PrepareObjectDB(ObjectDB db) { if (!((Object)(object)db == (Object)null)) { databaseAddMethods.AddItems(db, modResourceLoader.itemPrefabs); databaseAddMethods.AddStatusEffects(db, modResourceLoader.statusEffects); databaseAddMethods.AddRecipes(db, modResourceLoader.recipes); } } } [HarmonyPatch(typeof(ItemData), "GetWeight", new Type[] { typeof(int) })] internal static class PackageItemWeightPatch { private static void Postfix(ItemData __instance, int __0, ref float __result) { if (PackageMetadata.TryGetWeight(__instance, out var weight)) { int num = ((__0 < 0) ? __instance.m_stack : __0); if (num < 0) { num = 0; } __result = weight * (float)num; } } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(int) })] internal static class PackageItemTooltipPatch { private static void Postfix(ItemData __instance, ref string __result) { if (PackageMetadata.TryGetDescription(__instance, out var description)) { if (Localization.instance != null) { description = Localization.instance.Localize(description); } if (string.IsNullOrEmpty(__result)) { __result = description; } else { __result = __result + "\n" + description; } } } } [HarmonyPatch(typeof(Inventory), "IsTeleportable", new Type[] { typeof(bool) })] internal static class PackageInventoryTeleportPatch { private static bool Prefix(Inventory __instance, bool __0, ref bool __result) { if (__instance == null) { return true; } List<ItemData> allItems = __instance.GetAllItems(); if (allItems == null || allItems.Count == 0) { return true; } bool flag = false; for (int i = 0; i < allItems.Count; i++) { if (PackageMetadata.HasPackagePayload(allItems[i])) { flag = true; break; } } if (!flag) { return true; } for (int j = 0; j < allItems.Count; j++) { ItemData val = allItems[j]; if (val != null && ((val.m_shared != null && val.m_shared.m_toolTier >= 1000) || PackageMetadata.IsHardNoTeleport(val))) { __result = false; return false; } } if (__0 || ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)35))) { __result = true; return false; } for (int k = 0; k < allItems.Count; k++) { if (!PackageMetadata.IsItemTeleportable(allItems[k])) { __result = false; return false; } } __result = true; return false; } } internal static class PackageItemSerializer { private const int SerializerVersion = 1; internal static bool TrySerialize(ItemData item, out string encoded) { encoded = null; if (item == null || item.m_shared == null || (Object)(object)item.m_dropPrefab == (Object)null || item.m_stack <= 0) { return false; } try { using (MemoryStream memoryStream = new MemoryStream(256)) { using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); binaryWriter.Write(1); binaryWriter.Write(item.m_stack); binaryWriter.Write(item.m_durability); binaryWriter.Write(item.m_quality); binaryWriter.Write(item.m_variant); binaryWriter.Write(item.m_crafterID); binaryWriter.Write(item.m_crafterName ?? string.Empty); binaryWriter.Write(item.m_worldLevel); Dictionary<string, string> customData = item.m_customData; int num = customData?.Count ?? 0; if (num < 0 || num > 1024) { return false; } binaryWriter.Write(num); if (customData != null) { foreach (KeyValuePair<string, string> item2 in customData) { string text = item2.Key ?? string.Empty; string text2 = item2.Value ?? string.Empty; if (text.Length > 131072 || text2.Length > 131072) { return false; } binaryWriter.Write(text); binaryWriter.Write(text2); } } binaryWriter.Flush(); encoded = Convert.ToBase64String(memoryStream.ToArray()); } return !string.IsNullOrEmpty(encoded) && encoded.Length <= 262144; } catch (Exception ex) { Debug.LogWarning((object)(Launch.projectName + ": Failed to serialize packed item: " + ex.Message)); encoded = null; return false; } } internal static bool TryDeserialize(string prefabName, string encoded, out ItemData restored) { restored = null; if (string.IsNullOrEmpty(prefabName) || string.IsNullOrEmpty(encoded) || encoded.Length > 262144 || (Object)(object)ObjectDB.instance == (Object)null) { return false; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefabName); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val == (Object)null || val.m_itemData == null || val.m_itemData.m_shared == null) { return false; } try { byte[] buffer = Convert.FromBase64String(encoded); using MemoryStream memoryStream = new MemoryStream(buffer, writable: false); using BinaryReader binaryReader = new BinaryReader(memoryStream); int num = binaryReader.ReadInt32(); if (num != 1) { return false; } int num2 = binaryReader.ReadInt32(); float num3 = binaryReader.ReadSingle(); int num4 = binaryReader.ReadInt32(); int num5 = binaryReader.ReadInt32(); long crafterID = binaryReader.ReadInt64(); string text = binaryReader.ReadString(); int num6 = binaryReader.ReadInt32(); int num7 = binaryReader.ReadInt32(); if (num2 <= 0 || num4 <= 0 || num5 < 0 || num6 < 0 || float.IsNaN(num3) || float.IsInfinity(num3) || num3 < 0f || num7 < 0 || num7 > 1024 || text.Length > 131072) { return false; } Dictionary<string, string> dictionary = new Dictionary<string, string>(num7, StringComparer.Ordinal); for (int i = 0; i < num7; i++) { string text2 = binaryReader.ReadString(); string text3 = binaryReader.ReadString(); if (text2.Length > 131072 || text3.Length > 131072) { return false; } dictionary[text2] = text3; } if (memoryStream.Position != memoryStream.Length) { return false; } ItemData val2 = val.m_itemData.Clone(); val2.m_shared = val.m_itemData.m_shared; val2.m_dropPrefab = itemPrefab; val2.m_stack = num2; val2.m_durability = num3; val2.m_quality = num4; val2.m_variant = num5; val2.m_crafterID = crafterID; val2.m_crafterName = text; val2.m_worldLevel = num6; val2.m_customData = dictionary; val2.m_equipped = false; restored = val2; return true; } catch (Exception ex) { Debug.LogWarning((object)(Launch.projectName + ": Failed to deserialize packed item '" + prefabName + "': " + ex.Message)); restored = null; return false; } } } internal static class PackageMetadata { internal const string PackageAmountKey = "BalrondPackageAmount"; internal const string PackageDescriptionKey = "BalrondPackageDescription"; internal const string PackageWeightKey = "BalrondPackageWeight"; internal const string PackageTeleportableKey = "BalrondPackageTeleportable"; internal const string PackageHardNoTeleportKey = "BalrondPackageHardNoTeleport"; internal const string PackageFormatVersionKey = "BalrondPackageFormatVersion"; internal const string PackageItemDataVersionKey = "BalrondPackageItemDataVersion"; internal const string PackageIndexPrefix = "BalrondPackageIndex-"; internal const string PackagePrefabPrefix = "BalrondPackagePrefab-"; internal const string PackageDataPrefix = "BalrondPackageData-"; internal const string PackagePrefabName = "CustomPackageItem_bal"; internal const int CurrentFormatVersion = 3; internal const int MaxPackedEntries = 256; internal const int MaxSerializedEntryLength = 262144; internal const int MaxSerializedPackageLength = 1048576; internal const int MaxCustomDataEntries = 1024; internal const int MaxCustomDataStringLength = 131072; internal static bool IsPackage(ItemData item) { return item != null && (Object)(object)item.m_dropPrefab != (Object)null && string.Equals(((Object)item.m_dropPrefab).name, "CustomPackageItem_bal", StringComparison.Ordinal); } internal static bool HasPackagePayload(ItemData item) { if (!IsPackage(item) || item.m_customData == null) { return false; } string value; return item.m_customData.TryGetValue("BalrondPackageAmount", out value) && !string.IsNullOrEmpty(value); } internal static void Set(ItemData item, string key, string value) { if (item != null && !string.IsNullOrEmpty(key)) { if (item.m_customData == null) { item.m_customData = new Dictionary<string, string>(); } item.m_customData[key] = value ?? string.Empty; } } internal static bool TryGetInt(ItemData item, string key, out int value) { value = 0; if (item == null || item.m_customData == null || string.IsNullOrEmpty(key)) { return false; } string value2; return item.m_customData.TryGetValue(key, out value2) && int.TryParse(value2, NumberStyles.Integer, CultureInfo.InvariantCulture, out value); } internal static int GetFormatVersion(ItemData item) { int value; return (!TryGetInt(item, "BalrondPackageFormatVersion", out value) || value <= 0) ? 1 : value; } internal static bool TryGetWeight(ItemData item, out float weight) { weight = 0f; if (!HasPackagePayload(item)) { return false; } if (!item.m_customData.TryGetValue("BalrondPackageWeight", out var value)) { return false; } if (!float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out weight) && !float.TryParse(value, NumberStyles.Float, CultureInfo.CurrentCulture, out weight)) { return false; } return !float.IsNaN(weight) && !float.IsInfinity(weight) && weight >= 0f; } internal static bool TryGetTeleportable(ItemData item, out bool teleportable) { teleportable = true; if (!HasPackagePayload(item)) { return false; } if (!item.m_customData.TryGetValue("BalrondPackageTeleportable", out var value)) { return false; } teleportable = value == "1" || string.Equals(value, "true", StringComparison.OrdinalIgnoreCase); return true; } internal static bool IsHardNoTeleport(ItemData item) { if (!HasPackagePayload(item)) { return false; } if (item.m_customData.TryGetValue("BalrondPackageHardNoTeleport", out var value)) { return value == "1" || string.Equals(value, "true", StringComparison.OrdinalIgnoreCase); } if (GetFormatVersion(item) >= 3 || (Object)(object)ObjectDB.instance == (Object)null) { return false; } if (!TryGetInt(item, "BalrondPackageAmount", out var value2) || value2 <= 0 || value2 > 256) { return false; } for (int i = 0; i < value2; i++) { if (!item.m_customData.TryGetValue("BalrondPackageIndex-" + i, out var value3) || string.IsNullOrEmpty(value3)) { continue; } int num = value3.LastIndexOf('.'); if (num > 0) { string text = value3.Substring(0, num); GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(text); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent<ItemDrop>() : null); if ((Object)(object)val != (Object)null && val.m_itemData != null && val.m_itemData.m_shared != null && val.m_itemData.m_shared.m_toolTier >= 1000) { return true; } } } return false; } internal static bool TryGetDescription(ItemData item, out string description) { description = null; if (!HasPackagePayload(item)) { return false; } return item.m_customData.TryGetValue("BalrondPackageDescription", out description) && !string.IsNullOrEmpty(description); } internal static bool IsItemTeleportable(ItemData item) { if (item == null || item.m_shared == null) { return true; } if (TryGetTeleportable(item, out var teleportable)) { return teleportable; } return item.m_shared.m_teleportable; } } } namespace LitJson2 { internal enum JsonType { None, Object, Array, String, Int, Long, Double, Boolean } internal interface IJsonWrapper : IList, IOrderedDictionary, IDictionary, ICollection, IEnumerable { bool IsArray { get; } bool IsBoolean { get; } bool IsDouble { get; } bool IsInt { get; } bool IsLong { get; } bool IsObject { get; } bool IsString { get; } bool GetBoolean(); double GetDouble(); int GetInt(); JsonType GetJsonType(); long GetLong(); string GetString(); void SetBoolean(bool val); void SetDouble(double val); void SetInt(int val); void SetJsonType(JsonType type); void SetLong(long val); void SetString(string val); string ToJson(); void ToJson(JsonWriter writer); } internal class JsonData : IJsonWrapper, IList, IOrderedDictionary, IDictionary, ICollection, IEnumerable, IEquatable<JsonData> { private IList<JsonData> inst_array; private bool inst_boolean; private double inst_double; private int inst_int; private long inst_long; private IDictionary<string, JsonData> inst_object; private string inst_string; private string json; private JsonType type; private IList<KeyValuePair<string, JsonData>> object_list; public int Count => EnsureCollection().Count; public bool IsArray => type == JsonType.Array; public bool IsBoolean => type == JsonType.Boolean; public bool IsDouble => type == JsonType.Double; public bool IsInt => type == JsonType.Int; public bool IsLong => type == JsonType.Long; public bool IsObject => type == JsonType.Object; public bool IsString => type == JsonType.String; public ICollection<string> Keys { get { EnsureDictionary(); return inst_object.Keys; } } int ICollection.Count => Count; bool ICollection.IsSynchronized => EnsureCollection().IsSynchronized; object ICollection.SyncRoot => EnsureCollection().SyncRoot; bool IDictionary.IsFixedSize => EnsureDictionary().IsFixedSize; bool IDictionary.IsReadOnly => EnsureDictionary().IsReadOnly; ICollection IDictionary.Keys { get { EnsureDictionary(); IList<string> list = new List<string>(); foreach (KeyValuePair<string, JsonData> item in object_list) { list.Add(item.Key); } return (ICollection)list; } } ICollection IDictionary.Values { get { EnsureDictionary(); IList<JsonData> list = new List<JsonData>(); foreach (KeyValuePair<string, JsonData> item in object_list) { list.Add(item.Value); } return (ICollection)list; } } bool IJsonWrapper.IsArray => IsArray; bool IJsonWrapper.IsBoolean => IsBoolean; bool IJsonWrapper.IsDouble => IsDouble; bool IJsonWrapper.IsInt => IsInt; bool IJsonWrapper.IsLong => IsLong; bool IJsonWrapper.IsObject => IsObject; bool IJsonWrapper.IsString => IsString; bool IList.IsFixedSize => EnsureList().IsFixedSize; bool IList.IsReadOnly => EnsureList().IsReadOnly; object IDictionary.this[object key] { get { return EnsureDictionary()[key]; } set { if (!(key is string)) { throw new ArgumentException("The key has to be a string"); } JsonData value2 = ToJsonData(value); this[(string)key] = value2; } } object IOrderedDictionary.this[int idx] { get { EnsureDictionary(); return object_list[idx].Value; } set { EnsureDictionary(); JsonData value2 = ToJsonData(value); KeyValuePair<string, JsonData> keyValuePair = object_list[idx]; inst_object[keyValuePair.Key] = value2; KeyValuePair<string, JsonData> value3 = new KeyValuePair<string, JsonData>(keyValuePair.Key, value2); object_list[idx] = value3; } } object IList.this[int index] { get { return EnsureList()[index]; } set { EnsureList(); JsonData value2 = ToJsonData(value); this[index] = value2; } } public JsonData this[string prop_name] { get { EnsureDictionary(); return inst_object[prop_name]; } set { EnsureDictionary(); KeyValuePair<string, JsonData> keyValuePair = new KeyValuePair<string, JsonData>(prop_name, value); if (inst_object.ContainsKey(prop_name)) { for (int i = 0; i < object_list.Count; i++) { if (object_list[i].Key == prop_name) { object_list[i] = keyValuePair; break; } } } else { object_list.Add(keyValuePair); } inst_object[prop_name] = value; json = null; } } public JsonData this[int index] { get { EnsureCollection(); if (type == JsonType.Array) { return inst_array[index]; } return object_list[index].Value; } set { EnsureCollection(); if (type == JsonType.Array) { inst_array[index] = value; } else { KeyValuePair<string, JsonData> keyValuePair = object_list[index]; KeyValuePair<string, JsonData> value2 = new KeyValuePair<string, JsonData>(keyValuePair.Key, value); object_list[index] = value2; inst_object[keyValuePair.Key] = value; } json = null; } } public JsonData() { } public JsonData(bool boolean) { type = JsonType.Boolean; inst_boolean = boolean; } public JsonData(double number) { type = JsonType.Double; inst_double = number; } public JsonData(int number) { type = JsonType.Int; inst_int = number; } public JsonData(long number) { type = JsonType.Long; inst_long = number; } public JsonData(object obj) { if (obj is bool) { type = JsonType.Boolean; inst_boolean = (bool)obj; return; } if (obj is double) { type = JsonType.Double; inst_double = (double)obj; return; } if (obj is int) { type = JsonType.Int; inst_int = (int)obj; return; } if (obj is long) { type = JsonType.Long; inst_long = (long)obj; return; } if (obj is string) { type = JsonType.String; inst_string = (string)obj; return; } throw new ArgumentException("Unable to wrap the given object with JsonData"); } public JsonData(string str) { type = JsonType.String; inst_string = str; } public static implicit operator JsonData(bool data) { return new JsonData(data); } public static implicit operator JsonData(double data) { return new JsonData(data); } public static implicit operator JsonData(int data) { return new JsonData(data); } public static implicit operator JsonData(long data) { return new JsonData(data); } public static implicit operator JsonData(string data) { return new JsonData(data); } public static explicit operator bool(JsonData data) { if (data.type != JsonType.Boolean) { throw new InvalidCastException("Instance of JsonData doesn't hold a double"); } return data.inst_boolean; } public static explicit operator double(JsonData data) { if (data.type != JsonType.Double) { throw new InvalidCastException("Instance of JsonData doesn't hold a double"); } return data.inst_double; } public static explicit operator int(JsonData data) { if (data.type != JsonType.Int) { throw new InvalidCastException("Instance of JsonData doesn't hold an int"); } return data.inst_int; } public static explicit operator long(JsonData data) { if (data.type != JsonType.Long) { throw new InvalidCastException("Instance of JsonData doesn't hold an int"); } return data.inst_long; } public static explicit operator string(JsonData data) { if (data.type != JsonType.String) { throw new InvalidCastException("Instance of JsonData doesn't hold a string"); } return data.inst_string; } void ICollection.CopyTo(Array array, int index) { EnsureCollection().CopyTo(array, index); } void IDictionary.Add(object key, object value) { JsonData value2 = ToJsonData(value); EnsureDictionary().Add(key, value2); KeyValuePair<string, JsonData> item = new KeyValuePair<string, JsonData>((string)key, value2); object_list.Add(item); json = null; } void IDictionary.Clear() { EnsureDictionary().Clear(); object_list.Clear(); json = null; } bool IDictionary.Contains(object key) { return EnsureDictionary().Contains(key); } IDictionaryEnumerator IDictionary.GetEnumerator() { return ((IOrderedDictionary)this).GetEnumerator(); } void IDictionary.Remove(object key) { EnsureDictionary().Remove(key); for (int i = 0; i < object_list.Count; i++) { if (object_list[i].Key == (string)key) { object_list.RemoveAt(i); break; } } json = null; } IEnumerator IEnumerable.GetEnumerator() { return EnsureCollection().GetEnumerator(); } bool IJsonWrapper.GetBoolean() { if (type != JsonType.Boolean) { throw new InvalidOperationException("JsonData instance doesn't hold a boolean"); } return inst_boolean; } double IJsonWrapper.GetDouble() { if (type != JsonType.Double) { throw new InvalidOperationException("JsonData instance doesn't hold a double"); } return inst_double; } int IJsonWrapper.GetInt() { if (type != JsonType.Int) { throw new InvalidOperationException("JsonData instance doesn't hold an int"); } return inst_int; } long IJsonWrapper.GetLong() { if (type != JsonType.Long) { throw new InvalidOperationException("JsonData instance doesn't hold a long"); } return inst_long; } string IJsonWrapper.GetString() { if (type != JsonType.String) { throw new InvalidOperationException("JsonData instance doesn't hold a string"); } return inst_string; } void IJsonWrapper.SetBoolean(bool val) { type = JsonType.Boolean; inst_boolean = val; json = null; } void IJsonWrapper.SetDouble(double val) { type = JsonType.Double; inst_double = val; json = null; } void IJsonWrapper.SetInt(int val) { type = JsonType.Int; inst_int = val; json = null; } void IJsonWrapper.SetLong(long val) { type = JsonType.Long; inst_long = val; json = null; } void IJsonWrapper.SetString(string val) { type = JsonType.String; inst_string = val; json = null; } string IJsonWrapper.ToJson() { return ToJson(); } void IJsonWrapper.ToJson(JsonWriter writer) { ToJson(writer); } int IList.Add(object value) { return Add(value); } void IList.Clear() { EnsureList().Clear(); json = null; } bool IList.Contains(object value) { return EnsureList().Contains(value); } int IList.IndexOf(object value) { return EnsureList().IndexOf(value); } void IList.Insert(int index, object value) { EnsureList().Insert(index, value); json = null; } void IList.Remove(object value) { EnsureList().Remove(value); json = null; } void IList.RemoveAt(int index) { EnsureList().RemoveAt(index); json = null; } IDictionaryEnumerator IOrderedDictionary.GetEnumerator() { EnsureDictionary(); return new OrderedDictionaryEnumerator(object_list.GetEnumerator()); } void IOrderedDictionary.Insert(int idx, object key, object value) { string text = (string)key; JsonData value2 = (this[text] = ToJsonData(value)); KeyValuePair<string, JsonData> item = new KeyValuePair<string, JsonData>(text, value2); object_list.Insert(idx, item); } void IOrderedDictionary.RemoveAt(int idx) { EnsureDictionary(); inst_object.Remove(object_list[idx].Key); object_list.RemoveAt(idx); } private ICollection EnsureCollection() { if (type == JsonType.Array) { return (ICollection)inst_array; } if (type == JsonType.Object) { return (ICollection)inst_object; } throw new InvalidOperationException("The JsonData instance has to be initialized first"); } private IDictionary EnsureDictionary() { if (type == JsonType.Object) { return (IDictionary)inst_object; } if (type != JsonType.None) { throw new InvalidOperationException("Instance of JsonData is not a dictionary"); } type = JsonType.Object; inst_object = new Dictionary<string, JsonData>(); object_list = new List<KeyValuePair<string, JsonData>>(); return (IDictionary)inst_object; } private IList EnsureList() { if (type == JsonType.Array) { return (IList)inst_array; } if (type != JsonType.None) { throw new InvalidOperationException("Instance of JsonData is not a list"); } type = JsonType.Array; inst_array = new List<JsonData>(); return (IList)inst_array; } private JsonData ToJsonData(object obj) { if (obj == null) { return null; } if (obj is JsonData) { return (JsonData)obj; } return new JsonData(obj); } private static void WriteJson(IJsonWrapper obj, JsonWriter writer) { if (obj == null) { writer.Write(null); } else if (obj.IsString) { writer.Write(obj.GetString()); } else if (obj.IsBoolean) { writer.Write(obj.GetBoolean()); } else if (obj.IsDouble) { writer.Write(obj.GetDouble()); } else if (obj.IsInt) { writer.Write(obj.GetInt()); } else if (obj.IsLong) { writer.Write(obj.GetLong()); } else if (obj.IsArray) { writer.WriteArrayStart(); foreach (object item in (IEnumerable)obj) { WriteJson((JsonData)item, writer); } writer.WriteArrayEnd(); } else { if (!obj.IsObject) { return; } writer.WriteObjectStart(); foreach (DictionaryEntry item2 in (IDictionary)obj) { writer.WritePropertyName((string)item2.Key); WriteJson((JsonData)item2.Value, writer); } writer.WriteObjectEnd(); } } public int Add(object value) { JsonData value2 = ToJsonData(value); json = null; return EnsureList().Add(value2); } public void Clear() { if (IsObject) { ((IDictionary)this).Clear(); } else if (IsArray) { ((IList)this).Clear(); } } public bool Equals(JsonData x) { if (x == null) { return false; } if (x.type != type) { return false; } return type switch { JsonType.None => true, JsonType.Object => inst_object.Equals(x.inst_object), JsonType.Array => inst_array.Equals(x.inst_array), JsonType.String => inst_string.Equals(x.inst_string), JsonType.Int => inst_int.Equals(x.inst_int), JsonType.Long => inst_long.Equals(x.inst_long), JsonType.Double => inst_double.Equals(x.inst_double), JsonType.Boolean => inst_boolean.Equals(x.inst_boolean), _ => false, }; } public JsonType GetJsonType() { return type; } public void SetJsonType(JsonType type) { if (this.type != type) { switch (type) { case JsonType.Object: inst_object = new Dictionary<string, JsonData>(); object_list = new List<KeyValuePair<string, JsonData>>(); break; case JsonType.Array: inst_array = new List<JsonData>(); break; case JsonType.String: inst_string = null; break; case JsonType.Int: inst_int = 0; break; case JsonType.Long: inst_long = 0L; break; case JsonType.Double: inst_double = 0.0; break; case JsonType.Boolean: inst_boolean = false; break; } this.type = type; } } public string ToJson() { if (json != null) { return json; } StringWriter stringWriter = new StringWriter(); JsonWriter jsonWriter = new JsonWriter(stringWriter); jsonWriter.Validate = false; WriteJson(this, jsonWriter); json = stringWriter.ToString(); return json; } public void ToJson(JsonWriter writer) { bool validate = writer.Validate; writer.Validate = false; WriteJson(this, writer); writer.Validate = validate; } public override string ToString() { return type switch { JsonType.Array => "JsonData array", JsonType.Boolean => inst_boolean.ToString(), JsonType.Double => inst_double.ToString(), JsonType.Int => inst_int.ToString(), JsonType.Long => inst_long.ToString(), JsonType.Object => "JsonData object", JsonType.String => inst_string, _ => "Uninitialized JsonData", }; } } internal class OrderedDictionaryEnumerator : IDictionaryEnumerator, IEnumerator { private IEnumerator<KeyValuePair<string, JsonData>> list_enumerator; public object Current => Entry; public DictionaryEntry Entry { get { KeyValuePair<string, JsonData> current = list_enumerator.Current; return new DictionaryEntry(current.Key, current.Value); } } public object Key => list_enumerator.Current.Key; public object Value => list_enumerator.Current.Value; public OrderedDictionaryEnumerator(IEnumerator<KeyValuePair<string, JsonData>> enumerator) { list_enumerator = enumerator; } public bool MoveNext() { return list_enumerator.MoveNext(); } public void Reset() { list_enumerator.Reset(); } } internal class JsonException : ApplicationException { public JsonException() { } internal JsonException(ParserToken token) : base($"Invalid token '{token}' in input string") { } internal JsonException(ParserToken token, Exception inner_exception) : base($"Invalid token '{token}' in input string", inner_exception) { } internal JsonException(int c) : base($"Invalid character '{(char)c}' in input string") { } internal JsonException(int c, Exception inner_exception) : base($"Invalid character '{(char)c}' in input string", inner_exception) { } public JsonException(string message) : base(message) { } public JsonException(string message, Exception inner_exception) : base(message, inner_exception) { } } internal struct PropertyMetadata { public MemberInfo Info; public bool IsField; public Type Type; } internal struct ArrayMetadata { private Type element_type; private bool is_array; private bool is_list; public Type ElementType { get { if (element_type == null) { return typeof(JsonData); } return element_type; } set { element_type = value; } } public bool IsArray { get { return is_array; } set { is_array = value; } } public bool IsList { get { return is_list; } set { is_list = value; } } } internal struct ObjectMetadata { private Type element_type; private bool is_dictionary; private IDictionary<string, PropertyMetadata> properties; public Type ElementType { get { if (element_type == null) { return typeof(JsonData); } return element_type; } set { element_type = value; } } public bool IsDictionary { get { return is_dictionary; } set { is_dictionary = value; } } public IDictionary<string, PropertyMetadata> Properties { get { return properties; } set { properties = value; } } } internal delegate void ExporterFunc(object obj, JsonWriter writer); internal delegate void ExporterFunc<T>(T obj, JsonWriter writer); internal delegate object ImporterFunc(object input); internal delegate TValue ImporterFunc<TJson, TValue>(TJson input); internal delegate IJsonWrapper WrapperFactory(); internal class JsonMapper { private static int max_nesting_depth; private static IFormatProvider datetime_format; private static IDictionary<Type, ExporterFunc> base_exporters_table; private static IDictionary<Type, ExporterFunc> custom_exporters_table; private static IDictionary<Type, IDictionary<Type, ImporterFunc>> base_importers_table; private static IDictionary<Type, IDictionary<Type, ImporterFunc>> custom_importers_table; private static IDictionary<Type, ArrayMetadata> array_metadata; private static readonly object array_metadata_lock; private static IDictionary<Type, IDictionary<Type, MethodInfo>> conv_ops; private static readonly object conv_ops_lock; private static IDictionary<Type, ObjectMetadata> object_metadata; private static readonly object object_metadata_lock; private static IDictionary<Type, IList<PropertyMetadata>> type_properties; private static readonly object type_properties_lock; private static JsonWriter static_writer; private static readonly object static_writer_lock; static JsonMapper() { array_metadata_lock = new object(); conv_ops_lock = new object(); object_metadata_lock = new object(); type_properties_lock = new object(); static_writer_lock = new object(); max_nesting_depth = 100; array_metadata = new Dictionary<Type, ArrayMetadata>(); conv_ops = new Dictionary<Type, IDictionary<Type, MethodInfo>>(); object_metadata = new Dictionary<Type, ObjectMetadata>(); type_properties = new Dictionary<Type, IList<PropertyMetadata>>(); static_writer = new JsonWriter(); datetime_format = DateTimeFormatInfo.InvariantInfo; base_exporters_table = new Dictionary<Type, ExporterFunc>(); custom_exporters_table = new Dictionary<Type, ExporterFunc>(); base_importers_table = new Dictionary<Type, IDictionary<Type, ImporterFunc>>(); custom_importers_table = new Dictionary<Type, IDictionary<Type, ImporterFunc>>(); RegisterBaseExporters(); RegisterBaseImporters(); } private static void AddArrayMetadata(Type type) { if (array_metadata.ContainsKey(type)) { return; } ArrayMetadata value = new ArrayMetadata { IsArray = type.IsArray }; if (type.GetInterface("System.Collections.IList") != null) { value.IsList = true; } PropertyInfo[] properties = type.GetProperties(); foreach (PropertyInfo propertyInfo in properties) { if (!(propertyInfo.Name != "Item")) { ParameterInfo[] indexParameters = propertyInfo.GetIndexParameters(); if (indexParameters.Length == 1 && indexParameters[0].ParameterType == typeof(int)) { value.ElementType = propertyInfo.PropertyType; } } } lock (array_metadata_lock) { try { array_metadata.Add(type, value); } catch (ArgumentException) { } } } private static void AddObjectMetadata(Type type) { if (object_metadata.ContainsKey(type)) { return; } ObjectMetadata value = default(ObjectMetadata); if (type.GetInterface("System.Collections.IDictionary") != null) { value.IsDictionary = true; } value.Properties = new Dictionary<string, PropertyMetadata>(); PropertyInfo[] properties = type.GetProperties(); foreach (PropertyInfo propertyInfo in properties) { if (propertyInfo.Name == "Item") { ParameterInfo[] indexParameters = propertyInfo.GetIndexParameters(); if (indexParameters.Length == 1 && indexParameters[0].ParameterType == typeof(string)) { value.ElementType = propertyInfo.PropertyType; } } else { PropertyMetadata value2 = new PropertyMetadata { Info = propertyInfo, Type = propertyInfo.PropertyType }; value.Properties.Add(propertyInfo.Name, value2); } } FieldInfo[] fields = type.GetFields(); foreach (FieldInfo fieldInfo in fields) { PropertyMetadata value3 = new PropertyMetadata { Info = fieldInfo, IsField = true, Type = fieldInfo.FieldType }; value.Properties.Add(fieldInfo.Name, value3); } lock (object_metadata_lock) { try { object_metadata.Add(type, value); } catch (ArgumentException) { } } } private static void AddTypeProperties(Type type) { if (type_properties.ContainsKey(type)) { return; } IList<PropertyMetadata> list = new List<PropertyMetadata>(); PropertyInfo[] properties = type.GetProperties(); foreach (PropertyInfo propertyInfo in properties) { if (!(propertyInfo.Name == "Item")) { list.Add(new PropertyMetadata { Info = propertyInfo, IsField = false }); } } FieldInfo[] fields = type.GetFields(); foreach (FieldInfo info in fields) { list.Add(new PropertyMetadata { Info = info, IsField = true }); } lock (type_properties_lock) { try { type_properties.Add(type, list); } catch (ArgumentException) { } } } private static MethodInfo GetConvOp(Type t1, Type t2) { lock (conv_ops_lock) { if (!conv_ops.ContainsKey(t1)) { conv_ops.Add(t1, new Dictionary<Type, MethodInfo>()); } } if (conv_ops[t1].ContainsKey(t2)) { return conv_ops[t1][t2]; } MethodInfo method = t1.GetMethod("op_Implicit", new Type[1] { t2 }); lock (conv_ops_lock) { try { conv_ops[t1].Add(t2, method); return method; } catch (ArgumentException) { return conv_ops[t1][t2]; } } } private static object ReadValue(Type inst_type, JsonReader reader) { reader.Read(); if (reader.Token == JsonToken.ArrayEnd) { return null; } Type underlyingType = Nullable.GetUnderlyingType(inst_type); Type type = underlyingType ?? inst_type; if (reader.Token == JsonToken.Null) { if (inst_type.IsClass || underlyingType != null) { return null; } throw new JsonException($"Can't assign null to an instance of type {inst_type}"); } if (reader.Token == JsonToken.Double || reader.Token == JsonToken.Int || reader.Token == JsonToken.Long || reader.Token == JsonToken.String || reader.Token == JsonToken.Boolean) { Type type2 = reader.Value.GetType(); if (type.IsAssignableFrom(type2)) { return reader.Value; } if (custom_importers_table.Contain