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 paintingframe v1.0.0
plugins/BalrondPaintingFrame.dll
Decompiled 2 months 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.Linq; 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("BalrondPaintingFrame")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("BalrondPaintingFrame")] [assembly: AssemblyCopyright("Copyright © 2022")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("cde312a0-cf19-4264-8616-e1c74774beed")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace BalrondPaintingFrame { [BepInPlugin("balrond.astafaraios.paintingframe", "BalrondPaintingFrame", "1.0.0")] public class Launch : BaseUnityPlugin { public const string PluginGUID = "balrond.astafaraios.paintingframe"; public const string PluginName = "BalrondPaintingFrame"; public const string PluginVersion = "1.0.0"; private const string BundleResourceName = "paitingframe"; private const string AssetBasePath = "Assets/Custom/BalrondPaintingFrame/"; private const string PiecesPath = "Assets/Custom/BalrondPaintingFrame/Pieces/"; private const string BackgroundsPath = "Assets/Custom/BalrondPaintingFrame/Backgrounds/"; public static JsonLoader jsonLoader = new JsonLoader(); public static Launch Instance; private readonly Harmony harmony = new Harmony("balrond.astafaraios.paintingframe"); private AssetBundle assetBundle; public static readonly List<GameObject> PaintingPiecePrefabs = new List<GameObject>(); public static readonly List<Texture2D> AllPaintingTextures = new List<Texture2D>(); private void Awake() { Instance = this; jsonLoader.loadJson(); LoadAssetBundle(); LoadPaintingTextures(); LoadPaintingPrefabs(); harmony.PatchAll(); Debug.Log((object)string.Format("[{0}] Awake finished. Prefabs={1}, Textures={2}", "BalrondPaintingFrame", PaintingPiecePrefabs.Count, AllPaintingTextures.Count)); } private void OnDestroy() { harmony.UnpatchSelf(); } private void LoadAssetBundle() { assetBundle = GetAssetBundleFromResources("paitingframe"); if ((Object)(object)assetBundle == (Object)null) { Debug.LogError((object)"[BalrondPaintingFrame] Failed to load asset bundle from embedded resources: paitingframe"); } else { Debug.Log((object)"[BalrondPaintingFrame] Asset bundle loaded: paitingframe"); } } private void LoadPaintingTextures() { AllPaintingTextures.Clear(); if ((Object)(object)assetBundle == (Object)null) { Debug.LogError((object)"[BalrondPaintingFrame] Cannot load textures because asset bundle is null."); return; } string[] array = new string[24] { "blank-canvas.png", "mats-minnhagen-apple-release.jpg", "mats-minnhagen-ashlands-encounter.jpg", "mats-minnhagen-ashlands-fortress.jpg", "mats-minnhagen-ashlands-ruins.jpg", "mats-minnhagen-ashlands-ship.jpg", "mats-minnhagen-bog-witch.jpg", "mats-minnhagen-mistletoe.jpg", "mats-minnhagen-the-battle.jpg", "mats-minnhagen-valheim-base.jpg", "mats-minnhagen-valheim-dragons.jpg", "mats-minnhagen-valheim-gjall.jpg", "mats-minnhagen-valheim-halloween.jpg", "mats-minnhagen-valheim-halloween2.jpg", "mats-minnhagen-valheim-hildir.jpg", "mats-minnhagen-valheim-midsummer.jpg", "mats-minnhagen-valheim-mistlands.jpg", "mats-minnhagen-valheim-misunderstanding.jpg", "mats-minnhagen-valheim-seeker.jpg", "mats-minnhagen-valheim-serpent.jpg", "mats-minnhagen-valheim-valborg.jpg", "mats-minnhagen-valheim-valentine.jpg", "mats-minnhagen-valheim-xbox.jpg", "mats-minnhagen-valheim-yule.jpg" }; string[] array2 = array; foreach (string text in array2) { string text2 = "Assets/Custom/BalrondPaintingFrame/Backgrounds/" + text; Texture2D val = assetBundle.LoadAsset<Texture2D>(text2); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("[BalrondPaintingFrame] Missing texture: " + text2)); } else { AllPaintingTextures.Add(val); } } Debug.Log((object)string.Format("[{0}] Loaded painting textures: {1}", "BalrondPaintingFrame", AllPaintingTextures.Count)); } private void LoadPaintingPrefabs() { PaintingPiecePrefabs.Clear(); if ((Object)(object)assetBundle == (Object)null) { Debug.LogError((object)"[BalrondPaintingFrame] Cannot load painting prefabs because asset bundle is null."); return; } GameObject[] array = assetBundle.LoadAllAssets<GameObject>(); GameObject[] array2 = array; foreach (GameObject val in array2) { if (!((Object)(object)val == (Object)null) && ((Object)val).name.StartsWith("piece_", StringComparison.OrdinalIgnoreCase)) { PaintingPiecePrefabs.Add(val); } } Debug.Log((object)string.Format("[{0}] Loaded painting prefabs: {1}", "BalrondPaintingFrame", PaintingPiecePrefabs.Count)); } private static AssetBundle GetAssetBundleFromResources(string filename) { Assembly executingAssembly = Assembly.GetExecutingAssembly(); string text = executingAssembly.GetManifestResourceNames().SingleOrDefault((string str) => str.EndsWith(filename)); if (string.IsNullOrEmpty(text)) { Debug.LogError((object)("[BalrondPaintingFrame] Embedded resource not found: " + filename)); return null; } using Stream stream = executingAssembly.GetManifestResourceStream(text); if (stream == null) { Debug.LogError((object)("[BalrondPaintingFrame] Embedded resource stream is null: " + text)); return null; } return AssetBundle.LoadFromStream(stream); } } public class BalrondTranslator { public static Dictionary<string, Dictionary<string, string>> translations = new Dictionary<string, Dictionary<string, string>>(); public static Dictionary<string, string> getLanguage(string language) { if (string.IsNullOrEmpty(language)) { return null; } if (translations.TryGetValue(language, out var value)) { return value; } return null; } } public class JsonLoader { public string defaultPath = string.Empty; public void loadJson() { LoadTranslations(); justDefaultPath(); } public void justDefaultPath() { string configPath = Paths.ConfigPath; string text = Path.Combine(configPath, "BalrondPaintingFrame-translation/"); defaultPath = text; } public void createDefaultPath() { string configPath = Paths.ConfigPath; string text = Path.Combine(configPath, "BalrondPaintingFrame-translation/"); if (!Directory.Exists(text)) { CreateFolder(text); } else { Debug.Log((object)("BalrondPaintingFrame: Folder already exists: " + text)); } defaultPath = text; } private string[] jsonFilePath(string folderName, string extension) { string configPath = Paths.ConfigPath; string text = Path.Combine(configPath, "BalrondPaintingFrame-translation/"); if (!Directory.Exists(text)) { CreateFolder(text); } else { Debug.Log((object)("BalrondPaintingFrame: Folder already exists: " + text)); } string[] files = Directory.GetFiles(text, extension); Debug.Log((object)("BalrondPaintingFrame:" + folderName + " Json Files Found: " + files.Length)); return files; } private static void CreateFolder(string path) { try { Directory.CreateDirectory(path); Debug.Log((object)"BalrondPaintingFrame: Folder created successfully."); } catch (Exception ex) { Debug.Log((object)("BalrondPaintingFrame: Error creating folder: " + ex.Message)); } } private void LoadTranslations() { int num = 0; string[] array = jsonFilePath("Translation", "*.json"); foreach (string text in array) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text); string json = File.ReadAllText(text); JsonData jsonData = JsonMapper.ToObject(json); Dictionary<string, string> dictionary = new Dictionary<string, string>(); foreach (string key in jsonData.Keys) { dictionary[key] = jsonData[key].ToString(); } if (dictionary != null) { BalrondTranslator.translations.Add(fileNameWithoutExtension, dictionary); Debug.Log((object)("BalrondPaintingFrame: Json Files Language: " + fileNameWithoutExtension)); num++; } else { Debug.LogError((object)("BalrondPaintingFrame: Loading FAILED file: " + text)); } } Debug.Log((object)("BalrondPaintingFrame: Translation JsonFiles Loaded: " + num)); } } public class PaintingFrame : MonoBehaviour, Hoverable, Interactable { private const string ZdoKeyImageIndex = "BalrondPaintingFrame.painting_image_index"; private const string ZdoKeyZoom = "BalrondPaintingFrame.painting_zoom"; private const string ZdoKeyOffsetX = "BalrondPaintingFrame.painting_offset_x"; private const string ZdoKeyOffsetY = "BalrondPaintingFrame.painting_offset_y"; private const string ZdoKeyInUse = "BalrondPaintingFrame.in_use"; private const string ZdoKeyEditorPlayerId = "BalrondPaintingFrame.editor_player_id"; private const string ZdoKeyEditorTimeout = "BalrondPaintingFrame.editor_timeout"; private const string ZdoKeyBaseUvInitialized = "BalrondPaintingFrame.base_uv_initialized"; private const string ZdoKeyBaseScaleX = "BalrondPaintingFrame.base_scale_x"; private const string ZdoKeyBaseScaleY = "BalrondPaintingFrame.base_scale_y"; private const string ZdoKeyBaseOffsetX = "BalrondPaintingFrame.base_offset_x"; private const string ZdoKeyBaseOffsetY = "BalrondPaintingFrame.base_offset_y"; private const string RpcRequestStartEdit = "RPC_RequestStartEdit"; private const string RpcStartEditResponse = "RPC_StartEditResponse"; private const string RpcRequestCommitEdit = "RPC_RequestCommitEdit"; private const string RpcCommitEditResponse = "RPC_CommitEditResponse"; private const string RpcRequestCancelEdit = "RPC_RequestCancelEdit"; private const string RpcCancelEditResponse = "RPC_CancelEditResponse"; private const string RpcRefreshEditLock = "RPC_RefreshEditLock"; private static PaintingFrame ActiveEditor; public Renderer targetRenderer; public List<Texture2D> textures = new List<Texture2D>(); public int materialIndex = 0; public string textureProperty = "_MainTex"; public string hoverName = "$piece_paintingframe"; public string interactText = "$paintingframe_use_change"; public bool requireWardAccess = true; [Header("Default image")] public int defaultImageIndex = 0; [Header("Timing")] public float syncInterval = 2f; public float editInputInterval = 0.05f; public float lockRefreshInterval = 1f; public float lockTimeoutSeconds = 10f; [Header("Frame editing")] public float zoomStep = 0.1f; public float minZoom = 1f; public float maxZoom = 4f; public float moveStep = 0.025f; private ZNetView nview; private Material runtimeMaterial; private bool materialDefaultsCached; private Vector2 baseTextureScale = Vector2.one; private Vector2 baseTextureOffset = Vector2.zero; private bool startedSync; private bool isEditMode; private bool awaitingStartEditResponse; private bool awaitingCommitResponse; private bool awaitingCancelResponse; private int previewImageIndex; private float previewZoom = 1f; private float previewOffsetX = 0f; private float previewOffsetY = 0f; private int lastAppliedIndex = -1; private float lastAppliedZoom = float.MinValue; private float lastAppliedOffsetX = float.MinValue; private float lastAppliedOffsetY = float.MinValue; private uint lastRevision = uint.MaxValue; private void Awake() { nview = ((Component)this).GetComponent<ZNetView>(); EnsureTexturesAssigned(); TrySetupMaterial(); if ((Object)(object)nview != (Object)null) { nview.Register<long>("RPC_RequestStartEdit", (Action<long, long>)RPC_RequestStartEdit); nview.Register<bool>("RPC_StartEditResponse", (Action<long, bool>)RPC_StartEditResponse); nview.Register<ZPackage>("RPC_RequestCommitEdit", (Action<long, ZPackage>)RPC_RequestCommitEdit); nview.Register<bool>("RPC_CommitEditResponse", (Action<long, bool>)RPC_CommitEditResponse); nview.Register<long>("RPC_RequestCancelEdit", (Action<long, long>)RPC_RequestCancelEdit); nview.Register<bool>("RPC_CancelEditResponse", (Action<long, bool>)RPC_CancelEditResponse); nview.Register<long>("RPC_RefreshEditLock", (Action<long, long>)RPC_RefreshEditLock); } } private void OnEnable() { EnsureTexturesAssigned(); StartSync(); ApplyCommittedStateFromZDO(force: true); } private void OnDisable() { ((MonoBehaviour)this).CancelInvoke("SyncFromZDO"); ((MonoBehaviour)this).CancelInvoke("RefreshLocalEditLock"); startedSync = false; awaitingStartEditResponse = false; awaitingCommitResponse = false; awaitingCancelResponse = false; if ((Object)(object)ActiveEditor == (Object)(object)this) { ActiveEditor = null; } isEditMode = false; } private void Update() { if (isEditMode && !((Object)(object)ActiveEditor != (Object)(object)this) && !((Object)(object)Player.m_localPlayer == (Object)null) && textures != null && textures.Count != 0 && !((Object)(object)targetRenderer == (Object)null) && IsLocalPlayerAimingAtPainting()) { HandleEditInput(); } } public string GetHoverName() { string text = (string.IsNullOrWhiteSpace(hoverName) ? "$piece_paintingframe" : hoverName); return (Localization.instance != null) ? Localization.instance.Localize(text) : text; } public string GetHoverText() { EnsureTexturesAssigned(); string text = (string.IsNullOrWhiteSpace(hoverName) ? "$piece_paintingframe" : hoverName); if (textures == null || textures.Count == 0) { string text2 = text + "\n<color=orange>$paintingframe_hover_noimages</color>"; return (Localization.instance != null) ? Localization.instance.Localize(text2) : text2; } if (IsEditLockedByOtherPlayer()) { string text3 = text + "\n<color=orange>$paintingframe_edit_inuse</color>"; return (Localization.instance != null) ? Localization.instance.Localize(text3) : text3; } int num = (isEditMode ? previewImageIndex : GetImageIndex()); if (isEditMode && (Object)(object)ActiveEditor == (Object)(object)this) { string text4 = $"{text} ({num + 1}/{textures.Count})\n" + "$paintingframe_edit_controls"; return (Localization.instance != null) ? Localization.instance.Localize(text4) : text4; } string text5 = $"{text} ({num + 1}/{textures.Count})\n" + "[<color=yellow><b>$KEY_Use</b></color>] " + interactText + "\n[<color=yellow><b>Shift+$KEY_Use</b></color>] $paintingframe_use_previous\n[<color=yellow><b>Alt+$KEY_Use</b></color>] $paintingframe_use_reset\n[<color=yellow><b>Ctrl+$KEY_Use</b></color>] $paintingframe_use_edit"; return (Localization.instance != null) ? Localization.instance.Localize(text5) : text5; } public bool Interact(Humanoid user, bool hold, bool alt) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) EnsureTexturesAssigned(); if (hold) { return false; } if (textures == null || textures.Count == 0) { return false; } if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return false; } if ((Object)(object)targetRenderer == (Object)null) { return false; } if (requireWardAccess && !PrivateArea.CheckAccess(((Component)this).transform.position, 0f, false, true)) { return true; } if (IsCtrlHeld()) { if (isEditMode && (Object)(object)ActiveEditor == (Object)(object)this) { RequestCommitEdit(); return true; } RequestStartEdit(); return true; } if (isEditMode && (Object)(object)ActiveEditor == (Object)(object)this) { return true; } if (IsEditLockedByOtherPlayer()) { MessageLocal("$paintingframe_edit_inuse"); return true; } if (IsAltHeld()) { SetImageIndexImmediate(defaultImageIndex); return true; } if (IsShiftHeld()) { SetImageIndexImmediate(GetPreviousIndex(GetImageIndex())); return true; } SetImageIndexImmediate(GetNextIndex(GetImageIndex())); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } public void RefreshNow() { EnsureTexturesAssigned(); if (isEditMode && (Object)(object)ActiveEditor == (Object)(object)this) { ApplyPreviewState(force: true); } else { ApplyCommittedStateFromZDO(force: true); } } public int GetImageIndex() { EnsureTexturesAssigned(); if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return ClampIndex(defaultImageIndex); } ZDO zDO = nview.GetZDO(); if (zDO == null) { return ClampIndex(defaultImageIndex); } return ClampIndex(zDO.GetInt("BalrondPaintingFrame.painting_image_index", defaultImageIndex)); } private void StartSync() { if (!startedSync) { if (syncInterval <= 0f) { syncInterval = 2f; } if (editInputInterval <= 0f) { editInputInterval = 0.05f; } if (lockRefreshInterval <= 0f) { lockRefreshInterval = 1f; } if (lockTimeoutSeconds <= 0f) { lockTimeoutSeconds = 10f; } ((MonoBehaviour)this).CancelInvoke("SyncFromZDO"); ((MonoBehaviour)this).InvokeRepeating("SyncFromZDO", syncInterval, syncInterval); startedSync = true; } } private void SyncFromZDO() { if (!isEditMode || !((Object)(object)ActiveEditor == (Object)(object)this)) { ApplyCommittedStateFromZDO(force: false); } } private void ApplyCommittedStateFromZDO(bool force) { EnsureTexturesAssigned(); if (textures == null || textures.Count == 0 || (Object)(object)targetRenderer == (Object)null || (Object)(object)nview == (Object)null || !nview.IsValid()) { return; } ZDO zDO = nview.GetZDO(); if (zDO != null) { uint dataRevision = zDO.DataRevision; if (force || dataRevision != lastRevision) { lastRevision = dataRevision; int imageIndex = ClampIndex(zDO.GetInt("BalrondPaintingFrame.painting_image_index", defaultImageIndex)); float zoom = ClampZoom(zDO.GetFloat("BalrondPaintingFrame.painting_zoom", 1f)); float offsetX = zDO.GetFloat("BalrondPaintingFrame.painting_offset_x", 0f); float offsetY = zDO.GetFloat("BalrondPaintingFrame.painting_offset_y", 0f); ClampOffsets(zoom, ref offsetX, ref offsetY); ApplyMaterialState(imageIndex, zoom, offsetX, offsetY, force); } } } private void ApplyPreviewState(bool force) { EnsureTexturesAssigned(); ApplyMaterialState(previewImageIndex, previewZoom, previewOffsetX, previewOffsetY, force); } private void ApplyMaterialState(int imageIndex, float zoom, float offsetX, float offsetY, bool force) { //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) EnsureTexturesAssigned(); if (textures == null || textures.Count == 0 || (Object)(object)targetRenderer == (Object)null) { return; } imageIndex = ClampIndex(imageIndex); zoom = ClampZoom(zoom); if (!TrySetupMaterial()) { return; } ClampOffsets(zoom, ref offsetX, ref offsetY); if (!force && imageIndex == lastAppliedIndex && Mathf.Abs(zoom - lastAppliedZoom) < 0.0001f && Mathf.Abs(offsetX - lastAppliedOffsetX) < 0.0001f && Mathf.Abs(offsetY - lastAppliedOffsetY) < 0.0001f) { return; } Texture2D val = textures[imageIndex]; if (!((Object)(object)val == (Object)null)) { if (runtimeMaterial.HasProperty(textureProperty)) { runtimeMaterial.SetTexture(textureProperty, (Texture)(object)val); } else { runtimeMaterial.mainTexture = (Texture)(object)val; } Vector2 appliedTextureScale = GetAppliedTextureScale(zoom); Vector2 appliedTextureOffset = GetAppliedTextureOffset(offsetX, offsetY); runtimeMaterial.SetTextureScale(textureProperty, appliedTextureScale); runtimeMaterial.SetTextureOffset(textureProperty, appliedTextureOffset); lastAppliedIndex = imageIndex; lastAppliedZoom = zoom; lastAppliedOffsetX = offsetX; lastAppliedOffsetY = offsetY; } } private bool TrySetupMaterial() { if ((Object)(object)runtimeMaterial == (Object)null) { if ((Object)(object)targetRenderer == (Object)null) { return false; } Material[] materials = targetRenderer.materials; if (materials == null || materials.Length == 0) { return false; } if (materialIndex < 0 || materialIndex >= materials.Length) { materialIndex = 0; } runtimeMaterial = materials[materialIndex]; if ((Object)(object)runtimeMaterial == (Object)null) { return false; } } EnsureBaseTextureTransform(); return true; } private Vector2 GetAppliedTextureScale(float zoom) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) zoom = ClampZoom(zoom); return new Vector2(baseTextureScale.x / zoom, baseTextureScale.y / zoom); } private Vector2 GetAppliedTextureOffset(float relativeOffsetX, float relativeOffsetY) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) return new Vector2(baseTextureOffset.x + relativeOffsetX, baseTextureOffset.y + relativeOffsetY); } private void EnsureTexturesAssigned() { if ((textures != null && textures.Count > 0) || Launch.AllPaintingTextures == null || Launch.AllPaintingTextures.Count == 0) { return; } if (textures == null) { textures = new List<Texture2D>(); } else { textures.Clear(); } for (int i = 0; i < Launch.AllPaintingTextures.Count; i++) { Texture2D val = Launch.AllPaintingTextures[i]; if ((Object)(object)val != (Object)null) { textures.Add(val); } } } private void SetImageIndexImmediate(int index) { EnsureTexturesAssigned(); if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return; } ZDO zDO = nview.GetZDO(); if (zDO == null) { return; } if (IsEditLockedByOtherPlayer()) { MessageLocal("$paintingframe_edit_inuse"); return; } index = ClampIndex(index); float num = ClampZoom(zDO.GetFloat("BalrondPaintingFrame.painting_zoom", 1f)); float offsetX = zDO.GetFloat("BalrondPaintingFrame.painting_offset_x", 0f); float offsetY = zDO.GetFloat("BalrondPaintingFrame.painting_offset_y", 0f); ClampOffsets(num, ref offsetX, ref offsetY); if (!nview.IsOwner()) { nview.ClaimOwnership(); } zDO.Set("BalrondPaintingFrame.painting_image_index", index); zDO.Set("BalrondPaintingFrame.painting_zoom", num); zDO.Set("BalrondPaintingFrame.painting_offset_x", offsetX); zDO.Set("BalrondPaintingFrame.painting_offset_y", offsetY); ApplyMaterialState(index, num, offsetX, offsetY, force: true); lastRevision = zDO.DataRevision; } private void RequestStartEdit() { if (awaitingStartEditResponse || awaitingCommitResponse || awaitingCancelResponse) { return; } if ((Object)(object)ActiveEditor != (Object)null && (Object)(object)ActiveEditor != (Object)(object)this) { MessageLocal("$paintingframe_edit_inuse"); return; } if (IsEditLockedByOtherPlayer()) { MessageLocal("$paintingframe_edit_inuse"); return; } long localPlayerId = GetLocalPlayerId(); if (localPlayerId != 0) { awaitingStartEditResponse = true; nview.InvokeRPC("RPC_RequestStartEdit", new object[1] { localPlayerId }); } } private void RequestCommitEdit() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown if (isEditMode && !((Object)(object)ActiveEditor != (Object)(object)this) && !awaitingCommitResponse && !awaitingCancelResponse) { long localPlayerId = GetLocalPlayerId(); if (localPlayerId != 0) { ZPackage val = new ZPackage(); val.Write(localPlayerId); val.Write(previewImageIndex); val.Write(previewZoom); val.Write(previewOffsetX); val.Write(previewOffsetY); awaitingCommitResponse = true; nview.InvokeRPC("RPC_RequestCommitEdit", new object[1] { val }); } } } private void RequestCancelEdit() { if (isEditMode && !((Object)(object)ActiveEditor != (Object)(object)this) && !awaitingCommitResponse && !awaitingCancelResponse) { long localPlayerId = GetLocalPlayerId(); if (localPlayerId != 0) { awaitingCancelResponse = true; nview.InvokeRPC("RPC_RequestCancelEdit", new object[1] { localPlayerId }); } } } private void EnterLocalEditModeFromCommitted() { EnsureTexturesAssigned(); if ((Object)(object)ActiveEditor != (Object)null && (Object)(object)ActiveEditor != (Object)(object)this) { ActiveEditor.ExitLocalEditMode(restoreCommitted: true); } ZDO zDO = nview.GetZDO(); if (zDO != null) { previewImageIndex = ClampIndex(zDO.GetInt("BalrondPaintingFrame.painting_image_index", defaultImageIndex)); previewZoom = ClampZoom(zDO.GetFloat("BalrondPaintingFrame.painting_zoom", 1f)); previewOffsetX = zDO.GetFloat("BalrondPaintingFrame.painting_offset_x", 0f); previewOffsetY = zDO.GetFloat("BalrondPaintingFrame.painting_offset_y", 0f); ClampOffsets(previewZoom, ref previewOffsetX, ref previewOffsetY); isEditMode = true; ActiveEditor = this; ((MonoBehaviour)this).CancelInvoke("RefreshLocalEditLock"); ((MonoBehaviour)this).InvokeRepeating("RefreshLocalEditLock", Mathf.Max(0.25f, lockRefreshInterval * 0.5f), Mathf.Max(0.5f, lockRefreshInterval)); ApplyPreviewState(force: true); } } private void ExitLocalEditMode(bool restoreCommitted) { ((MonoBehaviour)this).CancelInvoke("RefreshLocalEditLock"); isEditMode = false; awaitingStartEditResponse = false; awaitingCommitResponse = false; awaitingCancelResponse = false; if ((Object)(object)ActiveEditor == (Object)(object)this) { ActiveEditor = null; } if (restoreCommitted) { ApplyCommittedStateFromZDO(force: true); } } private void HandleEditInput() { bool flag = false; if (Input.GetKeyDown((KeyCode)27)) { RequestCancelEdit(); return; } if (IsIncreaseScaleHeld()) { previewZoom = ClampZoom(previewZoom + zoomStep * Time.deltaTime * 8f); flag = true; } else if (IsDecreaseScaleHeld()) { previewZoom = ClampZoom(previewZoom - zoomStep * Time.deltaTime * 8f); flag = true; } if (Input.GetKey((KeyCode)275)) { previewOffsetX -= moveStep * Time.deltaTime * 8f; flag = true; } else if (Input.GetKey((KeyCode)276)) { previewOffsetX += moveStep * Time.deltaTime * 8f; flag = true; } if (Input.GetKey((KeyCode)274)) { previewOffsetY += moveStep * Time.deltaTime * 8f; flag = true; } else if (Input.GetKey((KeyCode)273)) { previewOffsetY -= moveStep * Time.deltaTime * 8f; flag = true; } if (Input.GetKeyDown((KeyCode)114)) { previewZoom = 1f; previewOffsetX = 0f; previewOffsetY = 0f; flag = true; } if (flag) { ClampOffsets(previewZoom, ref previewOffsetX, ref previewOffsetY); ApplyPreviewState(force: false); } } private void RefreshLocalEditLock() { if (isEditMode && !((Object)(object)ActiveEditor != (Object)(object)this)) { long localPlayerId = GetLocalPlayerId(); if (localPlayerId != 0) { nview.InvokeRPC("RPC_RefreshEditLock", new object[1] { localPlayerId }); } } } private void RPC_RequestStartEdit(long senderUid, long playerId) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) if (!nview.IsOwner()) { return; } ZDO zDO = nview.GetZDO(); if (zDO != null) { bool flag = CanPlayerEdit(zDO, playerId); if (flag) { SetEditLock(zDO, playerId); ZDOMan.instance.ForceSendZDO(senderUid, zDO.m_uid); } nview.InvokeRPC(senderUid, "RPC_StartEditResponse", new object[1] { flag }); } } private void RPC_StartEditResponse(long senderUid, bool granted) { awaitingStartEditResponse = false; if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { if (granted) { EnterLocalEditModeFromCommitted(); } else { MessageLocal("$paintingframe_edit_inuse"); } } } private void RPC_RequestCommitEdit(long senderUid, ZPackage pkg) { //IL_00e4: Unknown result type (might be due to invalid IL or missing references) if (!nview.IsOwner() || pkg == null) { return; } long playerId = pkg.ReadLong(); int index = pkg.ReadInt(); float zoom = pkg.ReadSingle(); float offsetX = pkg.ReadSingle(); float offsetY = pkg.ReadSingle(); ZDO zDO = nview.GetZDO(); if (zDO != null) { bool flag = HasValidLock(zDO, playerId); if (flag) { index = ClampIndex(index); zoom = ClampZoom(zoom); ClampOffsets(zoom, ref offsetX, ref offsetY); zDO.Set("BalrondPaintingFrame.painting_image_index", index); zDO.Set("BalrondPaintingFrame.painting_zoom", zoom); zDO.Set("BalrondPaintingFrame.painting_offset_x", offsetX); zDO.Set("BalrondPaintingFrame.painting_offset_y", offsetY); ClearEditLock(zDO); ZDOMan.instance.ForceSendZDO(senderUid, zDO.m_uid); } nview.InvokeRPC(senderUid, "RPC_CommitEditResponse", new object[1] { flag }); } } private void RPC_CommitEditResponse(long senderUid, bool granted) { awaitingCommitResponse = false; if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { if (granted) { MessageLocal("$paintingframe_edit_saved"); ExitLocalEditMode(restoreCommitted: false); ApplyCommittedStateFromZDO(force: true); } else { MessageLocal("$paintingframe_edit_inuse"); ExitLocalEditMode(restoreCommitted: true); } } } private void RPC_RequestCancelEdit(long senderUid, long playerId) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) if (!nview.IsOwner()) { return; } ZDO zDO = nview.GetZDO(); if (zDO != null) { bool flag = HasValidLock(zDO, playerId); if (flag) { ClearEditLock(zDO); ZDOMan.instance.ForceSendZDO(senderUid, zDO.m_uid); } nview.InvokeRPC(senderUid, "RPC_CancelEditResponse", new object[1] { flag }); } } private void RPC_CancelEditResponse(long senderUid, bool granted) { awaitingCancelResponse = false; if (granted) { MessageLocal("$paintingframe_edit_canceled"); } ExitLocalEditMode(restoreCommitted: true); } private void RPC_RefreshEditLock(long senderUid, long playerId) { if (nview.IsOwner()) { ZDO zDO = nview.GetZDO(); if (zDO != null && HasValidLock(zDO, playerId)) { SetEditLock(zDO, playerId); } } } private bool CanPlayerEdit(ZDO zdo, long playerId) { if (zdo == null) { return false; } if (!IsLockActive(zdo)) { return true; } long @long = zdo.GetLong("BalrondPaintingFrame.editor_player_id", 0L); return @long == playerId; } private bool HasValidLock(ZDO zdo, long playerId) { if (zdo == null) { return false; } if (!IsLockActive(zdo)) { return false; } long @long = zdo.GetLong("BalrondPaintingFrame.editor_player_id", 0L); return @long == playerId; } private bool IsLockActive(ZDO zdo) { if (zdo == null) { return false; } if (!zdo.GetBool("BalrondPaintingFrame.in_use", false)) { return false; } long @long = zdo.GetLong("BalrondPaintingFrame.editor_player_id", 0L); if (@long == 0) { return false; } long long2 = zdo.GetLong("BalrondPaintingFrame.editor_timeout", 0L); long ticks = DateTime.UtcNow.Ticks; if (long2 <= ticks) { ClearEditLock(zdo); return false; } return true; } private void SetEditLock(ZDO zdo, long playerId) { if (zdo != null) { long ticks = DateTime.UtcNow.AddSeconds(lockTimeoutSeconds).Ticks; zdo.Set("BalrondPaintingFrame.in_use", true); zdo.Set("BalrondPaintingFrame.editor_player_id", playerId); zdo.Set("BalrondPaintingFrame.editor_timeout", ticks); } } private void ClearEditLock(ZDO zdo) { if (zdo != null) { zdo.Set("BalrondPaintingFrame.in_use", false); zdo.Set("BalrondPaintingFrame.editor_player_id", 0L); zdo.Set("BalrondPaintingFrame.editor_timeout", 0L); } } private bool IsEditLockedByOtherPlayer() { if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return false; } ZDO zDO = nview.GetZDO(); if (zDO == null) { return false; } if (!IsLockActive(zDO)) { return false; } long @long = zDO.GetLong("BalrondPaintingFrame.editor_player_id", 0L); long localPlayerId = GetLocalPlayerId(); return @long != 0L && @long != localPlayerId; } private bool IsLocalPlayerAimingAtPainting() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } Camera main = Camera.main; if ((Object)(object)main == (Object)null) { return false; } Ray val = default(Ray); ((Ray)(ref val))..ctor(((Component)main).transform.position, ((Component)main).transform.forward); RaycastHit val2 = default(RaycastHit); if (!Physics.Raycast(val, ref val2, 10f, -5, (QueryTriggerInteraction)1)) { return false; } Transform transform = ((RaycastHit)(ref val2)).transform; if ((Object)(object)transform == (Object)null) { return false; } return (Object)(object)transform == (Object)(object)((Component)this).transform || transform.IsChildOf(((Component)this).transform); } private void ClampOffsets(float zoom, ref float offsetX, ref float offsetY) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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) Vector2 appliedTextureScale = GetAppliedTextureScale(zoom); float num = 0f; float num2 = 1f - appliedTextureScale.x; float num3 = 0f; float num4 = 1f - appliedTextureScale.y; float num5 = num - baseTextureOffset.x; float num6 = num2 - baseTextureOffset.x; float num7 = num3 - baseTextureOffset.y; float num8 = num4 - baseTextureOffset.y; if (num5 > num6) { float num9 = num5; num5 = num6; num6 = num9; } if (num7 > num8) { float num10 = num7; num7 = num8; num8 = num10; } offsetX = Mathf.Clamp(offsetX, num5, num6); offsetY = Mathf.Clamp(offsetY, num7, num8); } private float ClampZoom(float zoom) { if (zoom < minZoom) { zoom = minZoom; } if (zoom > maxZoom) { zoom = maxZoom; } return zoom; } private int ClampIndex(int index) { if (textures == null || textures.Count == 0) { return 0; } if (index < 0) { return 0; } if (index >= textures.Count) { return textures.Count - 1; } return index; } private int GetNextIndex(int current) { if (textures == null || textures.Count == 0) { return 0; } return (current + 1) % textures.Count; } private int GetPreviousIndex(int current) { if (textures == null || textures.Count == 0) { return 0; } current--; if (current < 0) { current = textures.Count - 1; } return current; } private static bool IsShiftHeld() { return Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303); } private static bool IsAltHeld() { return Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307); } private static bool IsCtrlHeld() { return Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305); } private static bool IsDecreaseScalePressed() { return Input.GetKeyDown((KeyCode)45) || Input.GetKeyDown((KeyCode)269); } private static bool IsIncreaseScalePressed() { return Input.GetKeyDown((KeyCode)61) || Input.GetKeyDown((KeyCode)270); } private static bool IsDecreaseScaleHeld() { return Input.GetKey((KeyCode)45) || Input.GetKey((KeyCode)269); } private static bool IsIncreaseScaleHeld() { return Input.GetKey((KeyCode)61) || Input.GetKey((KeyCode)270); } private static long GetLocalPlayerId() { if ((Object)(object)Game.instance == (Object)null) { return 0L; } return Game.instance.GetPlayerProfile().GetPlayerID(); } private static void MessageLocal(string text) { if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { ((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null); } } private void EnsureBaseTextureTransform() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_008e: 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_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) if (!materialDefaultsCached) { Vector2 val = Vector2.one; Vector2 val2 = Vector2.zero; if ((Object)(object)runtimeMaterial != (Object)null && runtimeMaterial.HasProperty(textureProperty)) { val = runtimeMaterial.GetTextureScale(textureProperty); val2 = runtimeMaterial.GetTextureOffset(textureProperty); } if (Mathf.Approximately(val.x, 0f)) { val.x = 1f; } if (Mathf.Approximately(val.y, 0f)) { val.y = 1f; } if (TryLoadBaseTextureTransformFromZDO(out var scale, out var offset)) { baseTextureScale = scale; baseTextureOffset = offset; materialDefaultsCached = true; } else { baseTextureScale = val; baseTextureOffset = val2; materialDefaultsCached = true; TrySaveBaseTextureTransformToZDO(baseTextureScale, baseTextureOffset); } } } private bool TryLoadBaseTextureTransformFromZDO(out Vector2 scale, out Vector2 offset) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) scale = Vector2.one; offset = Vector2.zero; if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return false; } ZDO zDO = nview.GetZDO(); if (zDO == null) { return false; } if (!zDO.GetBool("BalrondPaintingFrame.base_uv_initialized", false)) { return false; } float num = zDO.GetFloat("BalrondPaintingFrame.base_scale_x", 1f); float num2 = zDO.GetFloat("BalrondPaintingFrame.base_scale_y", 1f); float @float = zDO.GetFloat("BalrondPaintingFrame.base_offset_x", 0f); float float2 = zDO.GetFloat("BalrondPaintingFrame.base_offset_y", 0f); if (Mathf.Approximately(num, 0f)) { num = 1f; } if (Mathf.Approximately(num2, 0f)) { num2 = 1f; } scale = new Vector2(num, num2); offset = new Vector2(@float, float2); return true; } private void TrySaveBaseTextureTransformToZDO(Vector2 scale, Vector2 offset) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return; } ZDO zDO = nview.GetZDO(); if (zDO != null && !zDO.GetBool("BalrondPaintingFrame.base_uv_initialized", false)) { if (!nview.IsOwner()) { nview.ClaimOwnership(); } zDO.Set("BalrondPaintingFrame.base_scale_x", scale.x); zDO.Set("BalrondPaintingFrame.base_scale_y", scale.y); zDO.Set("BalrondPaintingFrame.base_offset_x", offset.x); zDO.Set("BalrondPaintingFrame.base_offset_y", offset.y); zDO.Set("BalrondPaintingFrame.base_uv_initialized", true); } } } [HarmonyPatch] public static class Patches { [HarmonyPatch(typeof(ZNetScene), "Awake")] private static class ZNetScene_Awake_Patch { private static void Postfix(ZNetScene __instance) { try { if ((Object)(object)__instance == (Object)null) { return; } if (Launch.PaintingPiecePrefabs == null || Launch.PaintingPiecePrefabs.Count == 0) { Debug.LogWarning((object)"[BalrondPaintingFrame] No painting prefabs loaded"); return; } foreach (GameObject paintingPiecePrefab in Launch.PaintingPiecePrefabs) { if (!((Object)(object)paintingPiecePrefab == (Object)null)) { PrefabSetup.SetupAndRegisterPaintingPrefab(__instance, paintingPiecePrefab); PrefabSetup.TryRegisterPieceToHammer(__instance, paintingPiecePrefab); } } Debug.Log((object)string.Format("[{0}] ZNetScene patch completed. Registered pieces: {1}", "BalrondPaintingFrame", Launch.PaintingPiecePrefabs.Count)); } catch (Exception arg) { Debug.LogError((object)string.Format("[{0}] ZNetScene patch failed\n{1}", "BalrondPaintingFrame", arg)); } } } } public static class PrefabSetup { private static ZNetScene m_znetScene; public static void SetupAndRegisterPaintingPrefab(ZNetScene zNetScene, GameObject prefab) { if ((Object)(object)zNetScene == (Object)null || (Object)(object)prefab == (Object)null) { Debug.LogWarning((object)"[BalrondPaintingFrame] SetupAndRegisterPaintingPrefab failed: null argument"); return; } m_znetScene = zNetScene; ConfigurePaintingPrefab(zNetScene, prefab); if (!zNetScene.m_prefabs.Contains(prefab)) { zNetScene.m_prefabs.Add(prefab); Debug.Log((object)("[BalrondPaintingFrame] Added '" + ((Object)prefab).name + "' to ZNetScene.m_prefabs")); } int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name); if (!zNetScene.m_namedPrefabs.ContainsKey(stableHashCode)) { zNetScene.m_namedPrefabs.Add(stableHashCode, prefab); Debug.Log((object)("[BalrondPaintingFrame] Added '" + ((Object)prefab).name + "' to ZNetScene.m_namedPrefabs")); } } public static void TryRegisterPieceToHammer(ZNetScene zNetScene, GameObject piecePrefab) { if ((Object)(object)zNetScene == (Object)null || (Object)(object)piecePrefab == (Object)null) { Debug.LogWarning((object)"[BalrondPaintingFrame] TryRegisterPieceToHammer failed: null argument"); return; } GameObject val = FindPrefabInZNet("Hammer", zNetScene); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)"[BalrondPaintingFrame] Hammer prefab not found in ZNetScene"); return; } ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null) { Debug.LogWarning((object)"[BalrondPaintingFrame] Hammer ItemDrop data missing"); return; } PieceTable buildPieces = component.m_itemData.m_shared.m_buildPieces; if ((Object)(object)buildPieces == (Object)null) { Debug.LogWarning((object)"[BalrondPaintingFrame] Hammer PieceTable missing"); } else if (!buildPieces.m_pieces.Contains(piecePrefab)) { buildPieces.m_pieces.Add(piecePrefab); Debug.Log((object)("[BalrondPaintingFrame] Registered '" + ((Object)piecePrefab).name + "' to Hammer PieceTable")); } } public static void ConfigurePaintingPrefab(ZNetScene zNetScene, GameObject prefab) { if (!((Object)(object)prefab == (Object)null)) { EnsureZNetView(prefab); ConfigurePiece(zNetScene, prefab); ConfigurePaintingComponent(prefab); ValidatePiece(prefab); } } private static void EnsureZNetView(GameObject prefab) { ZNetView component = prefab.GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null) { prefab.AddComponent<ZNetView>(); Debug.Log((object)("[BalrondPaintingFrame] Added ZNetView to '" + ((Object)prefab).name + "'")); } } private static void ConfigurePaintingComponent(GameObject prefab) { PaintingFrame paintingFrame = prefab.GetComponent<PaintingFrame>(); if ((Object)(object)paintingFrame == (Object)null) { paintingFrame = prefab.AddComponent<PaintingFrame>(); Debug.Log((object)("[BalrondPaintingFrame] Added PaintingFrame to '" + ((Object)prefab).name + "'")); } Renderer val = FindPaintingRenderer(prefab); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("[BalrondPaintingFrame] No painting renderer found on '" + ((Object)prefab).name + "'")); return; } List<Texture2D> textures = BuildTextureListForPrefab(((Object)prefab).name); paintingFrame.targetRenderer = val; paintingFrame.textures = textures; paintingFrame.materialIndex = 0; paintingFrame.textureProperty = "_MainTex"; paintingFrame.hoverName = GetHoverNameForPrefab(prefab); paintingFrame.interactText = "$paintingframe_use_change"; paintingFrame.requireWardAccess = true; paintingFrame.defaultImageIndex = 0; paintingFrame.syncInterval = 2f; paintingFrame.editInputInterval = 0.05f; paintingFrame.lockRefreshInterval = 1f; paintingFrame.lockTimeoutSeconds = 10f; paintingFrame.zoomStep = 0.1f; paintingFrame.minZoom = 1f; paintingFrame.maxZoom = 4f; paintingFrame.moveStep = 0.025f; Debug.Log((object)string.Format("[{0}] ConfigurePaintingComponent '{1}' textures={2}", "BalrondPaintingFrame", ((Object)prefab).name, paintingFrame.textures?.Count ?? 0)); paintingFrame.RefreshNow(); } private static Renderer FindPaintingRenderer(GameObject prefab) { Transform val = prefab.transform.Find("PicturePlane"); if ((Object)(object)val != (Object)null) { Renderer component = ((Component)val).GetComponent<Renderer>(); if ((Object)(object)component != (Object)null) { return component; } } val = prefab.transform.Find("Canvas"); if ((Object)(object)val != (Object)null) { Renderer component2 = ((Component)val).GetComponent<Renderer>(); if ((Object)(object)component2 != (Object)null) { return component2; } } val = prefab.transform.Find("Image"); if ((Object)(object)val != (Object)null) { Renderer component3 = ((Component)val).GetComponent<Renderer>(); if ((Object)(object)component3 != (Object)null) { return component3; } } val = prefab.transform.Find("Plane"); if ((Object)(object)val != (Object)null) { Renderer component4 = ((Component)val).GetComponent<Renderer>(); if ((Object)(object)component4 != (Object)null) { return component4; } } Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true); if (componentsInChildren != null) { foreach (Renderer val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)((Component)val2).transform == (Object)(object)prefab.transform)) { return val2; } } } return null; } private static List<Texture2D> BuildTextureListForPrefab(string prefabName) { List<Texture2D> allPaintingTextures = Launch.AllPaintingTextures; List<Texture2D> list = new List<Texture2D>(); if (allPaintingTextures == null || allPaintingTextures.Count == 0) { Debug.LogWarning((object)("[BalrondPaintingFrame] BuildTextureListForPrefab '" + prefabName + "' - Launch.AllPaintingTextures is empty")); return list; } for (int i = 0; i < allPaintingTextures.Count; i++) { Texture2D val = allPaintingTextures[i]; if ((Object)(object)val != (Object)null) { list.Add(val); } } Debug.Log((object)string.Format("[{0}] BuildTextureListForPrefab '{1}' -> {2} textures", "BalrondPaintingFrame", prefabName, list.Count)); return list; } private static string GetHoverNameForPrefab(GameObject prefabName) { return prefabName.GetComponent<Piece>().m_name; } private static void ConfigurePiece(ZNetScene zNetScene, GameObject prefab) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) Piece component = prefab.GetComponent<Piece>(); if ((Object)(object)component == (Object)null) { Debug.LogWarning((object)("[BalrondPaintingFrame] Prefab '" + ((Object)prefab).name + "' has no Piece")); return; } component.m_category = (PieceCategory)4; component.m_craftingStation = FindCraftingStation("piece_workbench", zNetScene); switch (((Object)prefab).name) { case "piece_painting_smallV_bal": component.m_name = "$piece_painting_small_v"; component.m_description = "$piece_painting_small_desc"; component.m_resources = (Requirement[])(object)new Requirement[0]; AddResource(component, "FineWood", 3); AddResource(component, "Resin", 2); AddResource(component, "Dandelion", 2); AddResource(component, "Bloodbag", 1); break; case "piece_painting_small_bal": component.m_name = "$piece_painting_small"; component.m_description = "$piece_painting_small_desc"; component.m_resources = (Requirement[])(object)new Requirement[0]; AddResource(component, "FineWood", 3); AddResource(component, "Resin", 2); AddResource(component, "Dandelion", 2); AddResource(component, "Bloodbag", 1); break; case "piece_painting_mediumV_bal": component.m_name = "$piece_painting_medium_v"; component.m_description = "$piece_painting_medium_desc"; component.m_resources = (Requirement[])(object)new Requirement[0]; AddResource(component, "FineWood", 6); AddResource(component, "Resin", 4); AddResource(component, "Dandelion", 4); AddResource(component, "Bloodbag", 2); break; case "piece_painting_medium_bal": component.m_name = "$piece_painting_medium"; component.m_description = "$piece_painting_medium_desc"; component.m_resources = (Requirement[])(object)new Requirement[0]; AddResource(component, "FineWood", 6); AddResource(component, "Resin", 4); AddResource(component, "Dandelion", 4); AddResource(component, "Bloodbag", 2); break; case "piece_painting_largeV_bal": component.m_name = "$piece_painting_large_v"; component.m_description = "$piece_painting_large_desc"; component.m_resources = (Requirement[])(object)new Requirement[0]; AddResource(component, "FineWood", 12); AddResource(component, "Resin", 8); AddResource(component, "Dandelion", 6); AddResource(component, "Bloodbag", 3); break; case "piece_painting_large_bal": component.m_name = "$piece_painting_large"; component.m_description = "$piece_painting_large_desc"; component.m_resources = (Requirement[])(object)new Requirement[0]; AddResource(component, "FineWood", 12); AddResource(component, "Resin", 8); AddResource(component, "Dandelion", 6); AddResource(component, "Bloodbag", 3); break; default: component.m_name = "$piece_paintingframe"; component.m_description = "$piece_paintingframe_desc"; component.m_resources = (Requirement[])(object)new Requirement[0]; AddResource(component, "Wood", 6); AddResource(component, "Resin", 2); break; } Debug.Log((object)string.Format("[{0}] Piece '{1}' configured with {2} resources", "BalrondPaintingFrame", ((Object)prefab).name, component.m_resources.Length)); } private static CraftingStation FindCraftingStation(string prefabName, ZNetScene zNetScene) { if ((Object)(object)zNetScene == (Object)null) { return null; } GameObject val = FindPrefabInZNet(prefabName, zNetScene); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("[BalrondPaintingFrame] Could not find station prefab '" + prefabName + "'")); return null; } CraftingStation component = val.GetComponent<CraftingStation>(); if ((Object)(object)component == (Object)null) { Debug.LogWarning((object)("[BalrondPaintingFrame] Prefab '" + prefabName + "' has no CraftingStation")); return null; } return component; } private static void AddResource(Piece piece, string itemName, int amount, int amountPerLevel = 0, bool recover = true) { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Expected O, but got Unknown if ((Object)(object)piece == (Object)null || (Object)(object)m_znetScene == (Object)null) { Debug.LogWarning((object)("[BalrondPaintingFrame] AddResource failed for '" + itemName + "'")); return; } List<Requirement> list = new List<Requirement>(); if (piece.m_resources != null) { list.AddRange(piece.m_resources); } GameObject val = FindPrefabInZNet(itemName, m_znetScene); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("[BalrondPaintingFrame] AddResource: could not find item '" + itemName + "' in ZNetScene")); return; } ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { Debug.LogWarning((object)("[BalrondPaintingFrame] AddResource: item '" + itemName + "' has no ItemDrop")); return; } list.Add(new Requirement { m_resItem = component, m_amount = amount, m_amountPerLevel = amountPerLevel, m_recover = recover }); piece.m_resources = list.ToArray(); } private static GameObject FindPrefabInZNet(string name, ZNetScene zNetScene) { if ((Object)(object)zNetScene == (Object)null || string.IsNullOrWhiteSpace(name)) { return null; } if (!zNetScene.m_namedPrefabs.TryGetValue(StringExtensionMethods.GetStableHashCode(name), out var value)) { value = zNetScene.m_prefabs.Find((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == name); } return value; } private static void ValidatePiece(GameObject prefab) { if ((Object)(object)prefab == (Object)null) { return; } Piece component = prefab.GetComponent<Piece>(); if ((Object)(object)component == (Object)null) { return; } Debug.Log((object)("[BalrondPaintingFrame] ValidatePiece '" + ((Object)prefab).name + "' station=" + (((Object)(object)component.m_craftingStation != (Object)null) ? ((Object)component.m_craftingStation).name : "NULL"))); if (component.m_resources == null) { Debug.LogWarning((object)("[BalrondPaintingFrame] Piece '" + ((Object)prefab).name + "' has NULL resources")); return; } for (int i = 0; i < component.m_resources.Length; i++) { Requirement val = component.m_resources[i]; if (val == null || (Object)(object)val.m_resItem == (Object)null) { Debug.LogWarning((object)string.Format("[{0}] Piece '{1}' resource[{2}] invalid", "BalrondPaintingFrame", ((Object)prefab).name, i)); continue; } Debug.Log((object)string.Format("[{0}] Resource[{1}] {2} x{3} recover={4}", "BalrondPaintingFrame", i, ((Object)val.m_resItem).name, val.m_amount, val.m_recover)); } } } [HarmonyPatch] internal static class TranslationPatches { [HarmonyPatch(typeof(FejdStartup), "SetupGui")] private class FejdStartup_SetupGUI { private static void Postfix() { string selectedLanguage = Localization.instance.GetSelectedLanguage(); Dictionary<string, string> translations = GetTranslations(selectedLanguage); AddTranslations(translations); } } [HarmonyPriority(800)] [HarmonyPatch(typeof(Localization), "SetupLanguage")] private class Translation_SetupLanguage { private static void Prefix(Localization __instance, string language) { Dictionary<string, string> translations = GetTranslations(language); AddTranslations(translations, __instance); } } [HarmonyPriority(800)] [HarmonyPatch(typeof(Localization), "LoadCSV")] private class Translation_LoadCSV { private static void Prefix(Localization __instance, string language) { Dictionary<string, string> translations = GetTranslations(language); AddTranslations(translations, __instance); } } private static Dictionary<string, string> GetTranslations(string language) { Dictionary<string, string> result = BalrondTranslator.getLanguage("English"); if (!string.Equals(language, "English", StringComparison.OrdinalIgnoreCase)) { Dictionary<string, string> language2 = BalrondTranslator.getLanguage(language); if (language2 != null) { result = language2; } else { Debug.Log((object)("BalrondPaintingFrame: Did not find translation file for '" + language + "', loading English")); } } return result; } private static void AddTranslations(Dictionary<string, string> translations, Localization localizationInstance = null) { if (translations == null) { Debug.LogWarning((object)"BalrondPaintingFrame: No translation file found!"); return; } if (localizationInstance != null) { foreach (KeyValuePair<string, string> translation in translations) { localizationInstance.AddWord(translation.Key, translation.Value); } return; } foreach (KeyValuePair<string, string> translation2 in translations) { Localization.instance.AddWord(translation2.Key, translation2.Value); } } } } 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 != 0) { 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 != 0) { 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 = default(ArrayMetadata); value.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 = default(PropertyMetadata); value2.Info = propertyInfo; value2.Type = propertyInfo.PropertyType; value.Properties.Add(propertyInfo.Name, value2); } } FieldInfo[] fields = type.GetFields(); foreach (FieldInfo fieldInfo in fields) { PropertyMetadata value3 = default(PropertyMetadata); value3.Info = fieldInfo; value3.IsField = true; value3.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")) { PropertyMetadata item = default(PropertyMetadata); item.Info = propertyInfo; item.IsField = false; list.Add(item); } } FieldInfo[] fields = type.GetFields(); foreach (FieldInfo info in fields) { PropertyMetadata item2 = default(PropertyMetadata); item2.Info = info; item2.IsField = true; list.Add(item2); } 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.ContainsKey(type2) && custom_importers_table[type2].ContainsKey(type)) { ImporterFunc importerFunc = custom_importers_table[type2][type]; return importerFunc(reader.Value); } if (base_importers_table.ContainsKey(type2) && base_importers_table[type2].ContainsKey(type)) { ImporterFunc importerFunc2 = base_importers_table[type2][type]; return importerFunc2(reader.Value); } if (type.IsEnum) { return Enum.ToObject(type, reader.Value); } MethodInfo convOp = GetConvOp(type, type2); if (convOp != null) { return convOp.Invoke(null, new object[1] { reader.Value }); } throw new JsonException($"Can't assign value '{reader.Value}' (type {type2}) to type {inst_type}"); } object obj = null; if (reader.Token == JsonToken.ArrayStart) { AddArrayMetadata(inst_type); ArrayMetadata arrayMetadata = array_metadata[inst_type]; if (!arrayMetadata.IsArray && !arrayMetadata.IsList) { throw new JsonException($"Type {inst_type} can't act as an array"); } IList list; Type elementType; if (!arrayMetadata.IsArray) { list = (IList)Activator.CreateInstance(inst_type); elementType = arrayMetadata.ElementType; } else { list = new ArrayList(); elementType = inst_type.GetElementType(); } while (true) { object obj2 = ReadValue(elementType, reader); if (obj2 == null && reader.Token == JsonToken.ArrayEnd) { break; } list.Add(obj2); } if (arrayMetadata.IsArray) { int count = list.Count; obj = Array.CreateInstance(elementType, count); for (int i = 0; i < count; i++) { ((Array)obj).SetValue(list[i], i); } } else { obj = list; } } else if (reader.Token == JsonToken.ObjectStart) { AddObjectMetadata(type); ObjectMetadata objectMetadata = object_metadata[type]; obj = Activator.CreateInstance(type); while (true) { reader.Read(); if (reader.Token == JsonToken.ObjectEnd) { break; } string text = (string)reader.Value; if (objectMetadata.Properties.ContainsKey(text)) { PropertyMetadata propertyMetadata = objectMetadata.Properties[text]; if (propertyMetadata.IsField) { ((FieldInfo)propertyMetadata.Info).SetValue(obj, ReadValue(propertyMetadata.Type, reader)); continue; } PropertyInfo propertyInfo = (PropertyInfo)propertyMetadata.Info; if (propertyInfo.CanWrite) { propertyInfo.SetValue(obj, ReadValue(propertyMetadata.Type, reader), null); } else { ReadValue(propertyMetadata.Type, reader); } } else if (!objectMetadata.IsDictionary) { if (!reader.SkipNonMembers) { throw new JsonException($"The type {inst_type} doesn't have the property '{text}'"); } ReadSkip(reader); } else { ((IDictionary)obj).Add(text, ReadValue(objectMetadata.ElementType, reader)); } } } return obj; } private static IJsonWrapper ReadValue(WrapperFactory factory, JsonReader reader) { reader.Read(); if (reader.Token == JsonToken.ArrayEnd || reader.Token == JsonToken.Null) { return null; } IJsonWrapper jsonWrapper = factory(); if (reader.Token == JsonToken.String) { jsonWrapper.SetString((string)reader.Value); return jsonWrapper; } if (reader.Token == JsonToken.Double) { jsonWrapper.SetDouble((double)reader.Value); return jsonWrapper; } if (reader.Token == JsonToken.Int) { jsonWrapper.SetInt((int)reader.Value); return jsonWrapper; } if (reader.Token == JsonToken.Long) { jsonWrapper.SetLong((long)reader.Value); return jsonWrapper; } if (reader.Token == JsonToken.Boolean) { jsonWrapper.SetBoolean((bool)reader.Value); return jsonWrapper; } if (reader.Token == JsonToken.ArrayStart) { jsonWrapper.SetJsonType(JsonType.Array); while (true) { IJsonWrapper jsonWrapper2 = ReadValue(factory, reader); if (jsonWrapper2 == null && reader.Token == JsonToken.ArrayEnd) { break; } jsonWrapper.Add(jsonWrapper2); } } else if (reader.Token == JsonToken.ObjectStart) { jsonWrapper.SetJsonType(JsonType.Object); while (true) { reader.Read(); if (reader.Token == JsonToken.ObjectEnd) { break; } string key = (string)reader.Value; jsonWrapper[key] = ReadValue(factory, reader); } } return jsonWrapper; } private static void ReadSkip(JsonReader reader) { ToWrapper(() => new JsonMockWrapper(), reader); } private static void RegisterBaseExporters() { base_exporters_table[typeof(byte)] = delegate(object obj, JsonWriter writer) { writer.Write(Convert.ToInt32((byte)obj)); }; base_exporters_table[typeof(char)] = delegate(object obj, JsonWriter writer) { writer.Write(Convert.ToString((char)obj)); }; base_exporters_table[typeof(DateTime)] = delegate(object obj, JsonWriter writer) { writer.Write(Convert.ToString((DateTime)obj, datetime_format)); }; base_exporters_table[typeof(decimal)] = delegate(object obj, JsonWriter writer) { writer.Write((decimal)obj); }; base_exporters_table[typeof(sbyte)] = delegate(object obj, JsonWriter writer) { writer.Write(Convert.ToInt32((sbyte)obj)); }; base_exporters_table[typeof(short)] = delegate(object obj, JsonWriter writer) { writer.Write(Convert.ToInt32((short)obj)); }; base_exporters_table[typeof(ushort)] = delegate(object obj, JsonWriter writer) { writer.Write(Convert.ToInt32((ushort)obj)); }; base_exporters_table[typeof(uint)] = delegate(object obj, JsonWriter writer) { writer.Write(Convert.ToUInt64((uint)obj)); }; base_exporters_table[typeof(ulong)] = delegate(object obj, JsonWriter writer) { writer.Write((ulong)obj); }; } private static void RegisterBaseImporters() { ImporterFunc importer = (object input) => Convert.ToByte((int)input); RegisterImporter(base_importers_table, typeof(int), typeof(byte), importer); importer = (object input) => Convert.ToUInt64((int)input); RegisterImporter(base_importers_table, typeof(int), typeof(ulong), importer); importer = (object input) => Convert.ToSByte((int)input); RegisterImporter(base_importers_table, typeof(int), typeof(sbyte), importer); importer = (object input) => Convert.ToInt16((int)input); RegisterImporter(base_importers_table, typeof(int), typeof(short), importer); importer = (object input) => Convert.ToUInt16((int)input); RegisterImporter(base_importers_table, typeof(int), typeof(ushort), importer); importer = (object input) => Convert.ToUInt32((int)input); RegisterImporter(base_importers_table, typeof(int), typeof(uint), importer); importer = (object input) => Convert.ToSingle((int)input); RegisterImporter(base_importers_table, typeof(int), typeof(float), importer); importer = (object input) => Convert.ToDouble((int)input); RegisterImporter(base_importers_table, typeof(int), typeof(double), importer); importer = (object input) => Convert.ToDecimal((double)input); RegisterImporter(base_importers_table, typeof(double), typeof(decimal), importer); importer = (object input) => Convert.ToUInt32((long)input); RegisterImporter(base_importers_table, typeof(long), typeof(uint), importer); importer = (object input) => Convert.ToChar((string)input); RegisterImporter(base_importers_table, typeof(string), typeof(char), importer); importer = (object input) => Convert.ToDateTime((string)input, datetime_format); RegisterImporter(base_importers_table, typeof(string), typeof(DateTime), importer); } private static void RegisterImporter(IDictionary<Type, IDictionary<Type, ImporterFunc>> table, Type json_type, Type value_type, ImporterFunc importer) { if (!table.ContainsKey(json_type)) { table.Add(json_type, new Dictionary<Type, ImporterFunc>()); } table[json_type][value_type] = importer; } private static void WriteValue(object obj, JsonWriter writer, bool writer_is_private, int depth) { if (depth > max_nesting_depth) { throw new JsonException($"Max allowed object depth reached while trying to export from type {obj.GetType()}"); } if (obj == null) { writer.Write(null); return; } if (obj is IJsonWrapper) { if (writer_is_private) { writer.TextWriter.Write(((IJsonWrapper)obj).ToJson()); } else { ((IJsonWrapper)obj).ToJson(writer); } return; } if (obj is string) { writer.Write((string)obj); return; } if (obj is double) { writer.Write((double)obj); return; } if (obj is int) { writer.Write((int)obj); return; } if (obj is bool) { writer.Write((bool)obj); return; } if (obj is long) { writer.Write((long)obj); return; } if (obj is Array) { writer.WriteArrayStart(); foreach (object item in (Array)obj) { WriteValue(item, writer, writer_is_private, depth + 1); } writer.WriteArrayEnd(); return; } if (obj is IList) { writer.WriteArrayStart(); foreach (object item2 in (IList)obj) { WriteValue(item2, writer, writer_is_private, depth + 1); } writer.WriteArrayEnd(); return; } if (obj is IDictionary) { writer.WriteObjectStart(); foreach (DictionaryEntry item3 in (IDictionary)obj) { writer.WritePropertyName((string)item3.Key); WriteValue(item3.Value, writer, writer_is_private, depth + 1); } writer.WriteObjectEnd(); return; } Type type = obj.GetType(); if (custom_exporters_table.ContainsKey(type)) { ExporterFunc exporterFunc = custom_exporters_table[type]; exporterFunc(obj, writer); return; } if (base_exporters_table.ContainsKey(type)) { ExporterFunc exporterFunc2 = base_exporters_table[type]; exporterFunc2(obj, writer); return; } if (obj is Enum) { Type underlyingType = Enum.GetUnderlyingType(type); if (underlyingType == typeof(long) || underlyingType == typeof(uint) || underlyingType == typeof(ulong)) { writer.Write((ulong)obj); } else { writer.Write((int)obj); } return; } AddTypeProperties(type); IList<PropertyMetadata> list = type_properties[type]; writer.WriteObjectStart(); foreach (PropertyMetadata item4 in list) { if (item4.IsField) { writer.WritePropertyName(item4.Info.Name); WriteValue(((FieldInfo)item4.Info).GetValue(obj), writer, writer_is_private, depth + 1); continue; } PropertyInfo propertyInfo = (PropertyInfo)item4.Info; if (propertyInfo.CanRead) { writer.WritePropertyName(item4.Info.Name); WriteValue(propertyInfo.GetValue(obj, null), writer, writer_is_private, depth + 1); } } writer.WriteObjectEnd(); } public static string ToJson(object obj) { lock (static_writer_lock) { static_writer.Reset(); WriteValue(obj, static_writer, writer_is_private: true, 0); return static_writer.ToString(); } } public static void ToJson(object obj, JsonWriter writer) { WriteValue(obj, writer, writer_is_private: false, 0); } public static JsonData ToObject(JsonReader reader) { return (JsonData)ToWrapper(() => new JsonData(), reader); } public static JsonData ToObject(TextReader reader) { JsonReader reader2 = new JsonReader(reader); return (JsonData)ToWrapper(() => new JsonData(), reader2); } public static JsonData ToObject(string json) { return (JsonData)ToWrapper(() => new JsonData(), json); } public static T ToObject<T>(JsonReader reader) { return (T)ReadValue(typeof(T), reader); } public static T ToObject<T>(TextReader reader) { JsonReader reader2 = new JsonReader(reader); return (T)ReadValue(typeof(T), reader2); } public static T ToObject<T>(string json) { JsonReader reader = new JsonReader(json); return (T)ReadValue(typeof(T), reader); } public static IJsonWrapper ToWrapper(WrapperFactory factory, JsonReader reader) { return ReadValue(factory, reader); } public static IJsonWrapper ToWrapper(WrapperFactory factory, string json) { JsonReader reader = new JsonReader(json); return ReadValue(factory, reader); } public static void RegisterExporter<T>(ExporterFunc<T> exporter) { ExporterFunc value = delegate(object obj, JsonWriter writer) { exporter((T)obj, writer); }; custom_exporters_table[typeof(T)] = value; } public static void RegisterImporter<TJson, TValue>(ImporterFunc<TJson, TValue> importer) { ImporterFunc importer2 = (object input) => importer((TJson)input); RegisterImporter(custom_importers_table, typeof(TJson), typeof(TValue), importer2); } public static void UnregisterExporters() { custom_exporters_table.Clear(); } public static void UnregisterImporters() { custom_importers_table.Clear(); } } internal class JsonMockWrapper : IJsonWrapper, IList, IOrderedDictionary, IDictionary, ICollection, IEnumerable { public bool IsArray => false; public bool IsBoolean => false; public bool IsDouble => false; public bool IsInt => false; public bool IsLong => false; public bool IsObject => false; public bool IsString => false; bool IList.IsFixedSize => true; bool IList.IsReadOnly => true; object IList.this[int index] { get { return null; } set { } } int ICollection.Count => 0; bool ICollection.IsSynchronized => false; object ICollection.SyncRoot => null; bool IDictionary.IsFixedSize => true; bool IDictionary.IsReadOnly => true; ICollection IDictionary.Keys => null; ICollection IDictionary.Values => null; object IDictionary.this[object key] { get { return null; } set { } } object IOrderedDictionary.this[int idx] { get { return null; } set { } } public bool GetBoolean() { return false; } public double GetDouble() { return 0.0; } public int GetInt() { return 0; } public JsonType GetJsonType() { return JsonType.None; } public long GetLong() { return 0L; } public string GetString() { return ""; } public void SetBoolean(bool val) { } public void SetDouble(double val) { } public void SetInt(int val) { } public void SetJsonType(JsonType type) { } public void SetLong(long val) { } pub