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.2
plugins/BalrondPaintingFrame.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.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using Balrond.Shared; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using JetBrains.Annotations; using LitJson2; using Microsoft.CodeAnalysis; using ServerSync; using TMPro; using UnityEngine; using UnityEngine.Audio; [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("5fbc8420-049b-4da7-b0a5-3bcf377c24c1")] [assembly: AssemblyFileVersion("1.0.3.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.3.0")] [module: UnverifiableCode] namespace Balrond.Shared { public static class AudioRoutingService { public enum AudioRoute { SFX, Ambient, Music, Master } private enum TargetKind { Route, NamedRuntimeGroup } private sealed class AudioTarget { public TargetKind Kind; public AudioRoute Route; public string RuntimeGroupName; public string Reason; } private sealed class AudioBinding { public AudioSource Source; public AudioTarget Target; } private sealed class ProcessedNode { public GameObject Root; public readonly List<AudioBinding> AudioBindings = new List<AudioBinding>(); public readonly List<GameObject> ReferencedRoots = new List<GameObject>(); public readonly HashSet<GameObject> ReferencedRootSet = new HashSet<GameObject>(ReferenceComparer<GameObject>.Instance); } private sealed class ExplicitOverride { public bool UsesNamedGroup; public AudioRoute Route; public string RuntimeGroupName; } private sealed class RuntimeMixerCatalog { private readonly Dictionary<string, AudioMixerGroup> _groupsByName = new Dictionary<string, AudioMixerGroup>(StringComparer.OrdinalIgnoreCase); private AudioMixer _mixer; private AudioMixerGroup _master; private AudioMixerGroup _ambient; private AudioMixerGroup _music; private AudioMixerGroup _sfx; public bool IsReady => (Object)(object)_mixer != (Object)null || (Object)(object)_master != (Object)null || (Object)(object)_ambient != (Object)null || (Object)(object)_music != (Object)null; public void Rebuild(AudioMan audioMan) { _groupsByName.Clear(); _mixer = null; _master = null; _ambient = null; _music = null; _sfx = null; if ((Object)(object)audioMan == (Object)null) { return; } _master = ReadAudioManGroup(audioMan, "m_masterMixer"); _ambient = ReadAudioManGroup(audioMan, "m_ambientMixer"); _music = ReadAudioManGroup(audioMan, "m_musicMixer"); _mixer = GetMixer(_master) ?? GetMixer(_ambient) ?? GetMixer(_music); AddGroup(_master); AddGroup(_ambient); AddGroup(_music); if ((Object)(object)_mixer != (Object)null) { try { AudioMixerGroup[] array = _mixer.FindMatchingGroups(string.Empty); if (array != null) { for (int i = 0; i < array.Length; i++) { AddGroup(array[i]); } } } catch (Exception ex) { Warn("Could not enumerate runtime AudioMixer groups: " + ex.Message); } } _sfx = FindNamedGroup("SFX"); if ((Object)(object)_sfx == (Object)null) { _sfx = QueryExactGroup("SFX"); } if ((Object)(object)_sfx == (Object)null) { AudioMixerGroup val = FindNamedGroup("Effects"); if ((Object)(object)val == (Object)null) { val = QueryExactGroup("Effects"); } _sfx = val; } if ((Object)(object)_sfx == (Object)null) { _sfx = _master; WarnOnce("sfx-group-fallback", "Runtime SFX mixer group was not found. Falling back to the AudioMan master output group."); } } public AudioMixerGroup Resolve(AudioTarget target) { if (target == null) { return ResolveRoute(AudioRoute.SFX); } if (target.Kind == TargetKind.NamedRuntimeGroup) { AudioMixerGroup val = FindNamedGroup(target.RuntimeGroupName); if ((Object)(object)val == (Object)null) { val = QueryExactGroup(target.RuntimeGroupName); } if ((Object)(object)val != (Object)null) { return val; } return ResolveRoute(AudioRoute.SFX); } return ResolveRoute(target.Route); } public bool HasNamedGroup(string groupName) { if (string.IsNullOrEmpty(groupName)) { return false; } return (Object)(object)FindNamedGroup(groupName) != (Object)null || (Object)(object)QueryExactGroup(groupName) != (Object)null; } private AudioMixerGroup ResolveRoute(AudioRoute route) { return (AudioMixerGroup)(route switch { AudioRoute.Ambient => _ambient ?? _sfx ?? _master, AudioRoute.Music => _music ?? _sfx ?? _master, AudioRoute.Master => _master ?? _sfx ?? _ambient ?? _music, _ => _sfx ?? _master ?? _ambient ?? _music, }); } private AudioMixerGroup FindNamedGroup(string groupName) { if (!string.IsNullOrEmpty(groupName) && _groupsByName.TryGetValue(groupName, out var value)) { return value; } return null; } private AudioMixerGroup QueryExactGroup(string groupName) { if ((Object)(object)_mixer == (Object)null || string.IsNullOrEmpty(groupName)) { return null; } try { AudioMixerGroup[] array = _mixer.FindMatchingGroups(groupName); if (array == null) { return null; } foreach (AudioMixerGroup val in array) { AddGroup(val); if ((Object)(object)val != (Object)null && string.Equals(((Object)val).name, groupName, StringComparison.OrdinalIgnoreCase)) { return val; } } } catch (Exception ex) { WarnOnce("query-group-" + groupName, "Could not query runtime AudioMixer group '" + groupName + "': " + ex.Message); } return null; } private void AddGroup(AudioMixerGroup group) { if (!((Object)(object)group == (Object)null) && !string.IsNullOrEmpty(((Object)group).name) && !_groupsByName.ContainsKey(((Object)group).name)) { _groupsByName.Add(((Object)group).name, group); } } private static AudioMixer GetMixer(AudioMixerGroup group) { try { return ((Object)(object)group != (Object)null) ? group.audioMixer : null; } catch { return null; } } private static AudioMixerGroup ReadAudioManGroup(AudioMan audioMan, string fieldName) { try { FieldInfo field = typeof(AudioMan).GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field == null) { return null; } object value = field.GetValue(audioMan); AudioMixerGroup val = (AudioMixerGroup)((value is AudioMixerGroup) ? value : null); if ((Object)(object)val != (Object)null) { return val; } AudioSource val2 = (AudioSource)((value is AudioSource) ? value : null); if ((Object)(object)val2 != (Object)null) { return val2.outputAudioMixerGroup; } } catch (Exception ex) { WarnOnce("audioman-field-" + fieldName, "Could not read AudioMan." + fieldName + ": " + ex.Message); } return null; } } private sealed class ReferenceComparer<T> : IEqualityComparer<T> where T : class { public static readonly ReferenceComparer<T> Instance = new ReferenceComparer<T>(); public bool Equals(T x, T y) { return x == y; } public int GetHashCode(T obj) { return RuntimeHelpers.GetHashCode(obj); } } private const int MaxManagedDepth = 24; private const int MaxCollectionEntries = 4096; private static readonly RuntimeMixerCatalog MixerCatalog = new RuntimeMixerCatalog(); private static readonly Dictionary<string, ExplicitOverride> Overrides = new Dictionary<string, ExplicitOverride>(StringComparer.Ordinal); private static readonly Dictionary<GameObject, ProcessedNode> ProcessedNodes = new Dictionary<GameObject, ProcessedNode>(ReferenceComparer<GameObject>.Instance); private static readonly Dictionary<AudioSource, AudioBinding> SourceBindings = new Dictionary<AudioSource, AudioBinding>(ReferenceComparer<AudioSource>.Instance); private static readonly Dictionary<Type, FieldInfo[]> TraversalFields = new Dictionary<Type, FieldInfo[]>(); private static readonly HashSet<GameObject> RegisteredRootSet = new HashSet<GameObject>(ReferenceComparer<GameObject>.Instance); private static readonly List<GameObject> RegisteredRoots = new List<GameObject>(); private static readonly HashSet<GameObject> ActiveProcessing = new HashSet<GameObject>(ReferenceComparer<GameObject>.Instance); private static readonly HashSet<string> WarnedKeys = new HashSet<string>(StringComparer.Ordinal); private static Action<string> _infoLogger; private static Action<string> _warningLogger; private static Action<string> _errorLogger; public static bool DebugLogging { get; set; } public static void ConfigureLogging(Action<string> infoLogger, Action<string> warningLogger, Action<string> errorLogger) { _infoLogger = infoLogger; _warningLogger = warningLogger; _errorLogger = errorLogger; } public static void SetOverride(string gameObjectName, AudioRoute route) { if (!string.IsNullOrWhiteSpace(gameObjectName)) { Overrides[gameObjectName] = new ExplicitOverride { UsesNamedGroup = false, Route = route, RuntimeGroupName = null }; InvalidateClassificationCaches(); } } public static void SetOverrides(AudioRoute route, params string[] gameObjectNames) { if (gameObjectNames == null) { return; } bool flag = false; foreach (string text in gameObjectNames) { if (!string.IsNullOrWhiteSpace(text)) { Overrides[text] = new ExplicitOverride { UsesNamedGroup = false, Route = route, RuntimeGroupName = null }; flag = true; } } if (flag) { InvalidateClassificationCaches(); } } public static void SetMixerGroupOverride(string gameObjectName, string runtimeMixerGroupName) { if (!string.IsNullOrWhiteSpace(gameObjectName) && !string.IsNullOrWhiteSpace(runtimeMixerGroupName)) { Overrides[gameObjectName] = new ExplicitOverride { UsesNamedGroup = true, Route = AudioRoute.SFX, RuntimeGroupName = runtimeMixerGroupName }; InvalidateClassificationCaches(); } } public static void RemoveOverride(string gameObjectName) { if (!string.IsNullOrWhiteSpace(gameObjectName) && Overrides.Remove(gameObjectName)) { InvalidateClassificationCaches(); } } public static void Process(GameObject root) { if (IsUsable((Object)(object)root)) { RegisterRoot(root); if (MixerCatalog.IsReady) { ProcessRoot(root); } } } public static void Process(IEnumerable<GameObject> roots) { if (roots == null) { return; } foreach (GameObject root in roots) { if (IsUsable((Object)(object)root)) { RegisterRoot(root); } } if (!MixerCatalog.IsReady) { return; } for (int i = 0; i < RegisteredRoots.Count; i++) { GameObject val = RegisteredRoots[i]; if (IsUsable((Object)(object)val)) { ProcessRoot(val); } } } public static void OnAudioManAwake(AudioMan audioMan) { if ((Object)(object)audioMan == (Object)null) { return; } MixerCatalog.Rebuild(audioMan); if (!MixerCatalog.IsReady) { Error("AudioMan was available, but no usable runtime mixer group could be resolved."); return; } HashSet<GameObject> visited = new HashSet<GameObject>(ReferenceComparer<GameObject>.Instance); for (int i = 0; i < RegisteredRoots.Count; i++) { GameObject val = RegisteredRoots[i]; if (IsUsable((Object)(object)val)) { if (ProcessedNodes.TryGetValue(val, out var value)) { ValidateNodeGraph(value, visited); } else { ProcessRoot(val); } } } } private static void RegisterRoot(GameObject root) { if (RegisteredRootSet.Add(root)) { RegisteredRoots.Add(root); } } private static void ProcessRoot(GameObject root) { if (!MixerCatalog.IsReady || !IsUsable((Object)(object)root)) { return; } if (ProcessedNodes.TryGetValue(root, out var value)) { ValidateNodeGraph(value, new HashSet<GameObject>(ReferenceComparer<GameObject>.Instance)); } else { if (!ActiveProcessing.Add(root)) { return; } ProcessedNode processedNode = new ProcessedNode { Root = root }; ProcessedNodes[root] = processedNode; try { ScanAudioSources(root, processedNode); ScanBehaviourReferences(root, processedNode); } catch (Exception ex) { Error("Failed to process audio graph for '" + SafeName((Object)(object)root) + "': " + ex); } finally { ActiveProcessing.Remove(root); } } } private static void ScanAudioSources(GameObject root, ProcessedNode node) { AudioSource[] componentsInChildren; try { componentsInChildren = root.GetComponentsInChildren<AudioSource>(true); } catch (Exception ex) { Warn("Could not enumerate AudioSources under '" + SafeName((Object)(object)root) + "': " + ex.Message); return; } if (componentsInChildren == null) { return; } foreach (AudioSource val in componentsInChildren) { if (IsUsable((Object)(object)val)) { if (!SourceBindings.TryGetValue(val, out var value)) { value = new AudioBinding { Source = val, Target = ClassifySource(root, val) }; SourceBindings[val] = value; } if (!node.AudioBindings.Contains(value)) { node.AudioBindings.Add(value); } ApplyBinding(value, root); } } } private static void ScanBehaviourReferences(GameObject root, ProcessedNode node) { MonoBehaviour[] componentsInChildren; try { componentsInChildren = root.GetComponentsInChildren<MonoBehaviour>(true); } catch (Exception ex) { Warn("Could not enumerate MonoBehaviours under '" + SafeName((Object)(object)root) + "': " + ex.Message); return; } if (componentsInChildren == null) { return; } HashSet<object> managedVisited = new HashSet<object>(ReferenceComparer<object>.Instance); foreach (MonoBehaviour val in componentsInChildren) { if (IsUsable((Object)(object)val) && !(val is ZSFX)) { TraverseManagedObject(val, root, node, managedVisited, 0, isComponentRoot: true); } } } private static void TraverseManagedObject(object value, GameObject ownerRoot, ProcessedNode node, HashSet<object> managedVisited, int depth, bool isComponentRoot) { if (value == null || depth > 24) { return; } Type type = value.GetType(); if (!type.IsValueType && !managedVisited.Add(value)) { return; } FieldInfo[] traversalFields = GetTraversalFields(type, isComponentRoot); foreach (FieldInfo fieldInfo in traversalFields) { object value2; try { value2 = fieldInfo.GetValue(value); } catch { continue; } TraverseValue(value2, ownerRoot, node, managedVisited, depth + 1); } } private static void TraverseValue(object value, GameObject ownerRoot, ProcessedNode node, HashSet<object> managedVisited, int depth) { if (value == null || depth > 24) { return; } EffectList val = (EffectList)((value is EffectList) ? value : null); if (val != null) { TraverseEffectList(val, ownerRoot, node); return; } GameObject val2 = (GameObject)((value is GameObject) ? value : null); if ((Object)(object)val2 != (Object)null) { HandleReferencedGameObject(val2, ownerRoot, node); return; } Component val3 = (Component)((value is Component) ? value : null); if ((Object)(object)val3 != (Object)null) { if (IsUsable((Object)(object)val3)) { HandleReferencedGameObject(val3.gameObject, ownerRoot, node); } return; } AudioClip val4 = (AudioClip)((value is AudioClip) ? value : null); if ((Object)(object)val4 != (Object)null) { return; } Object val5 = (Object)((value is Object) ? value : null); if (val5 != (Object)null) { ScriptableObject val6 = (ScriptableObject)((value is ScriptableObject) ? value : null); if ((Object)(object)val6 != (Object)null) { TraverseManagedObject(val6, ownerRoot, node, managedVisited, depth, isComponentRoot: false); } return; } if (value is IDictionary dictionary) { int num = 0; { foreach (DictionaryEntry item in dictionary) { TraverseValue(item.Value, ownerRoot, node, managedVisited, depth + 1); num++; if (num >= 4096) { break; } } return; } } if (value is IEnumerable enumerable && !(value is string)) { int num2 = 0; { foreach (object item2 in enumerable) { TraverseValue(item2, ownerRoot, node, managedVisited, depth + 1); num2++; if (num2 >= 4096) { break; } } return; } } Type type = value.GetType(); if (ShouldTraverseManagedType(type)) { TraverseManagedObject(value, ownerRoot, node, managedVisited, depth, isComponentRoot: false); } } private static void TraverseEffectList(EffectList effectList, GameObject ownerRoot, ProcessedNode node) { EffectData[] effectPrefabs = effectList.m_effectPrefabs; if (effectPrefabs == null) { return; } for (int i = 0; i < effectPrefabs.Length; i++) { GameObject prefab = effectPrefabs[i].m_prefab; if (IsUsable((Object)(object)prefab)) { HandleReferencedGameObject(prefab, ownerRoot, node); } } } private static void HandleReferencedGameObject(GameObject referenced, GameObject ownerRoot, ProcessedNode ownerNode) { if (IsUsable((Object)(object)referenced) && IsUsable((Object)(object)ownerRoot) && !IsInsideHierarchy(referenced, ownerRoot)) { if (ownerNode.ReferencedRootSet.Add(referenced)) { ownerNode.ReferencedRoots.Add(referenced); } ProcessRoot(referenced); } } private static bool IsInsideHierarchy(GameObject candidate, GameObject root) { if (candidate == root) { return true; } try { Transform transform = candidate.transform; Transform transform2 = root.transform; return (Object)(object)transform != (Object)null && (Object)(object)transform2 != (Object)null && transform.IsChildOf(transform2); } catch { return false; } } private static AudioTarget ClassifySource(GameObject root, AudioSource source) { AudioTarget audioTarget = FindExplicitOverride(((Component)source).gameObject, root); if (audioTarget != null) { return audioTarget; } if (HierarchyHasSfxPrefix(((Component)source).gameObject, root)) { return RouteTarget(AudioRoute.SFX, "sfx_/vfx_/fx_ GameObject name"); } if (HierarchyHasZSFX(((Component)source).gameObject, root)) { return RouteTarget(AudioRoute.SFX, "ZSFX context"); } AudioMixerGroup val = null; try { val = source.outputAudioMixerGroup; } catch { val = null; } AudioTarget audioTarget2 = ClassifyOldMixerGroup(val); if (audioTarget2 != null) { return audioTarget2; } return RouteTarget(AudioRoute.SFX, "default SFX fallback"); } private static AudioTarget FindExplicitOverride(GameObject sourceObject, GameObject root) { Transform val = null; Transform val2 = null; try { val = (((Object)(object)sourceObject != (Object)null) ? sourceObject.transform : null); val2 = (((Object)(object)root != (Object)null) ? root.transform : null); } catch { return null; } while ((Object)(object)val != (Object)null) { string text = (((Object)(object)((Component)val).gameObject != (Object)null) ? ((Object)((Component)val).gameObject).name : null); if (!string.IsNullOrEmpty(text) && Overrides.TryGetValue(text, out var value)) { if (value.UsesNamedGroup) { return NamedTarget(value.RuntimeGroupName, "explicit mixer-group override on '" + text + "'"); } return RouteTarget(value.Route, "explicit route override on '" + text + "'"); } if (val == val2) { break; } val = val.parent; } return null; } private static bool HierarchyHasSfxPrefix(GameObject sourceObject, GameObject root) { Transform val = null; Transform val2 = null; try { val = (((Object)(object)sourceObject != (Object)null) ? sourceObject.transform : null); val2 = (((Object)(object)root != (Object)null) ? root.transform : null); } catch { return false; } while ((Object)(object)val != (Object)null) { string name = (((Object)(object)((Component)val).gameObject != (Object)null) ? ((Object)((Component)val).gameObject).name : null); if (HasSfxPrefix(name)) { return true; } if (val == val2) { break; } val = val.parent; } return false; } private static bool HierarchyHasZSFX(GameObject sourceObject, GameObject root) { Transform val = null; Transform val2 = null; try { val = (((Object)(object)sourceObject != (Object)null) ? sourceObject.transform : null); val2 = (((Object)(object)root != (Object)null) ? root.transform : null); } catch { return false; } while ((Object)(object)val != (Object)null) { try { if ((Object)(object)((Component)val).GetComponent<ZSFX>() != (Object)null) { return true; } } catch { } if (val == val2) { break; } val = val.parent; } return false; } private static AudioTarget ClassifyOldMixerGroup(AudioMixerGroup oldGroup) { if ((Object)(object)oldGroup == (Object)null || string.IsNullOrEmpty(((Object)oldGroup).name)) { return null; } string name = ((Object)oldGroup).name; if (IsGenericMasterName(name)) { return null; } if (ContainsInvariant(name, "ambient")) { return RouteTarget(AudioRoute.Ambient, "old mixer-group name: " + name); } if (ContainsInvariant(name, "music")) { return RouteTarget(AudioRoute.Music, "old mixer-group name: " + name); } if (ContainsInvariant(name, "sfx") || ContainsInvariant(name, "vfx") || ContainsInvariant(name, "effect")) { return RouteTarget(AudioRoute.SFX, "old mixer-group name: " + name); } if (MixerCatalog.HasNamedGroup(name)) { return NamedTarget(name, "matching runtime mixer-group name"); } return null; } private static bool HasSfxPrefix(string name) { if (string.IsNullOrEmpty(name)) { return false; } return name.StartsWith("sfx_", StringComparison.OrdinalIgnoreCase) || name.StartsWith("vfx_", StringComparison.OrdinalIgnoreCase) || name.StartsWith("fx_", StringComparison.OrdinalIgnoreCase); } private static bool IsGenericMasterName(string name) { return string.Equals(name, "Master", StringComparison.OrdinalIgnoreCase) || string.Equals(name, "MasterAudio", StringComparison.OrdinalIgnoreCase) || string.Equals(name, "Master Mixer", StringComparison.OrdinalIgnoreCase); } private static bool ContainsInvariant(string text, string fragment) { return text != null && fragment != null && text.IndexOf(fragment, StringComparison.OrdinalIgnoreCase) >= 0; } private static AudioTarget RouteTarget(AudioRoute route, string reason) { return new AudioTarget { Kind = TargetKind.Route, Route = route, RuntimeGroupName = null, Reason = reason }; } private static AudioTarget NamedTarget(string groupName, string reason) { return new AudioTarget { Kind = TargetKind.NamedRuntimeGroup, Route = AudioRoute.SFX, RuntimeGroupName = groupName, Reason = reason }; } private static void ApplyBinding(AudioBinding binding, GameObject semanticRoot) { if (binding == null || !IsUsable((Object)(object)binding.Source)) { return; } AudioMixerGroup val = MixerCatalog.Resolve(binding.Target); if ((Object)(object)val == (Object)null) { return; } AudioMixerGroup val2 = null; try { val2 = binding.Source.outputAudioMixerGroup; } catch { val2 = null; } if (val2 != val) { try { binding.Source.outputAudioMixerGroup = val; } catch (Exception ex) { Warn("Could not route AudioSource '" + SafeName((Object)(object)((Component)binding.Source).gameObject) + "' under '" + SafeName((Object)(object)semanticRoot) + "': " + ex.Message); return; } } if (DebugLogging) { Info("AudioSource '" + SafeName((Object)(object)((Component)binding.Source).gameObject) + "' under '" + SafeName((Object)(object)semanticRoot) + "' -> '" + ((Object)val).name + "' (" + ((binding.Target != null) ? binding.Target.Reason : "unknown") + ")."); } } private static void ValidateNodeGraph(ProcessedNode node, HashSet<GameObject> visited) { if (node == null || !IsUsable((Object)(object)node.Root) || !visited.Add(node.Root)) { return; } for (int i = 0; i < node.AudioBindings.Count; i++) { ApplyBinding(node.AudioBindings[i], node.Root); } for (int j = 0; j < node.ReferencedRoots.Count; j++) { GameObject val = node.ReferencedRoots[j]; if (IsUsable((Object)(object)val)) { if (ProcessedNodes.TryGetValue(val, out var value)) { ValidateNodeGraph(value, visited); } else { ProcessRoot(val); } } } } private static FieldInfo[] GetTraversalFields(Type type, bool isComponentRoot) { if (TraversalFields.TryGetValue(type, out var value)) { return value; } List<FieldInfo> list = new List<FieldInfo>(); Type type2 = type; while (type2 != null && type2 != typeof(object) && !(type2 == typeof(MonoBehaviour)) && !(type2 == typeof(Behaviour)) && !(type2 == typeof(Component)) && !(type2 == typeof(ScriptableObject)) && !(type2 == typeof(Object))) { FieldInfo[] array; try { array = type2.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } catch { array = null; } if (array != null) { foreach (FieldInfo fieldInfo in array) { if (ShouldInspectField(fieldInfo)) { list.Add(fieldInfo); } } } type2 = type2.BaseType; } value = list.ToArray(); TraversalFields[type] = value; return value; } private static bool ShouldInspectField(FieldInfo field) { if (field == null || field.IsStatic || field.IsLiteral || field.IsNotSerialized) { return false; } Type fieldType = field.FieldType; if (fieldType == null) { return false; } if (typeof(EffectList).IsAssignableFrom(fieldType) || typeof(GameObject).IsAssignableFrom(fieldType) || typeof(Component).IsAssignableFrom(fieldType) || typeof(ScriptableObject).IsAssignableFrom(fieldType)) { return true; } if (fieldType.IsArray || typeof(IEnumerable).IsAssignableFrom(fieldType)) { return true; } if (fieldType == typeof(object) || fieldType.IsInterface || fieldType.IsAbstract) { return HasSerializeReferenceAttribute(field); } return ShouldTraverseManagedType(fieldType); } private static bool HasSerializeReferenceAttribute(FieldInfo field) { try { object[] customAttributes = field.GetCustomAttributes(inherit: false); if (customAttributes == null) { return false; } foreach (object obj in customAttributes) { if (obj != null) { string fullName = obj.GetType().FullName; if (string.Equals(fullName, "UnityEngine.SerializeReference", StringComparison.Ordinal)) { return true; } } } } catch { } return false; } private static bool ShouldTraverseManagedType(Type type) { if (type == null || type.IsPrimitive || type.IsEnum || type.IsPointer) { return false; } if (type == typeof(string) || type == typeof(decimal) || type == typeof(DateTime) || type == typeof(TimeSpan) || type == typeof(Guid) || type == typeof(IntPtr) || type == typeof(UIntPtr) || type == typeof(Type)) { return false; } if (typeof(Delegate).IsAssignableFrom(type)) { return false; } if (typeof(Object).IsAssignableFrom(type)) { return typeof(ScriptableObject).IsAssignableFrom(type); } string text = type.Namespace ?? string.Empty; if (text.StartsWith("System", StringComparison.Ordinal) || text.StartsWith("UnityEngine", StringComparison.Ordinal)) { return false; } return type.IsClass || type.IsValueType; } private static void InvalidateClassificationCaches() { ProcessedNodes.Clear(); SourceBindings.Clear(); ActiveProcessing.Clear(); if (!MixerCatalog.IsReady) { return; } for (int i = 0; i < RegisteredRoots.Count; i++) { GameObject val = RegisteredRoots[i]; if (IsUsable((Object)(object)val)) { ProcessRoot(val); } } } private static bool IsUsable(Object obj) { if (obj == null) { return false; } try { return obj != (Object)null; } catch { return false; } } private static string SafeName(Object obj) { if (!IsUsable(obj)) { return "<null>"; } try { return obj.name ?? "<unnamed>"; } catch { return "<unavailable>"; } } private static void Info(string message) { if (_infoLogger != null) { _infoLogger("[AudioRoutingService] " + message); } } private static void Warn(string message) { if (_warningLogger != null) { _warningLogger("[AudioRoutingService] " + message); } } private static void Error(string message) { if (_errorLogger != null) { _errorLogger("[AudioRoutingService] " + message); } } private static void WarnOnce(string key, string message) { if (WarnedKeys.Add(key)) { Warn(message); } } } } namespace BalrondPaintingFrame { internal static class PaintingFrameConfig { internal static ConfigEntry<bool> LockConfiguration; internal static ConfigEntry<bool> RequireWardAccess; internal static ConfigEntry<float> LockTimeoutSeconds; internal static ConfigEntry<float> ZoomStep; internal static ConfigEntry<float> MaxZoom; internal static ConfigEntry<float> MoveStep; internal static ConfigEntry<bool> AudioDebugLogging; internal static void Bind(ConfigFile config) { LockConfiguration = config.Bind<bool>("Server", "LockConfiguration", true, "Lock synchronized BalrondPaintingFrame settings to the server/host values."); ServerSyncBridge.AddLockingConfigEntry(LockConfiguration); RequireWardAccess = BindSynced(config, "Interaction", "RequireWardAccess", value: true, "Require PrivateArea/ward access before a player may edit a painting."); LockTimeoutSeconds = BindSynced(config, "Interaction", "EditLockTimeoutSeconds", 10f, "How long an abandoned painting edit lock remains valid before another player may take it over."); ZoomStep = BindSynced(config, "Editor", "ZoomStep", 0.1f, "Base zoom speed used by the painting editor."); MaxZoom = BindSynced(config, "Editor", "MaxZoom", 4f, "Maximum painting image zoom. Values below 1 are clamped by the component."); MoveStep = BindSynced(config, "Editor", "MoveStep", 0.025f, "Base image pan speed used by the painting editor."); AudioDebugLogging = config.Bind<bool>("Diagnostics", "AudioDebugLogging", false, "Enable detailed AudioRoutingService logging. Local client setting; not synchronized."); RequireWardAccess.SettingChanged += OnGameplaySettingChanged; LockTimeoutSeconds.SettingChanged += OnGameplaySettingChanged; ZoomStep.SettingChanged += OnGameplaySettingChanged; MaxZoom.SettingChanged += OnGameplaySettingChanged; MoveStep.SettingChanged += OnGameplaySettingChanged; } private static ConfigEntry<T> BindSynced<T>(ConfigFile config, string section, string key, T value, string description) { ConfigEntry<T> val = config.Bind<T>(section, key, value, description); ServerSyncBridge.AddConfigEntry<T>(val); return val; } private static void OnGameplaySettingChanged(object sender, EventArgs e) { PrefabSetup.ApplyRuntimeSettingsToLoadedPrefabs(); } } internal static class ServerSyncBridge { private static ConfigSync sync; internal static void Initialize(string pluginGuid, string displayName, string version) { sync = new ConfigSync(pluginGuid) { DisplayName = displayName, CurrentVersion = version, MinimumRequiredVersion = version, ModRequired = true }; } internal static void AddLockingConfigEntry(ConfigEntry<bool> entry) { sync.AddLockingConfigEntry<bool>(entry); } internal static void AddConfigEntry<T>(ConfigEntry<T> entry) { SyncedConfigEntry<T> syncedConfigEntry = sync.AddConfigEntry<T>(entry); syncedConfigEntry.SynchronizedConfig = true; } internal static void Reset() { sync = null; } } [BepInPlugin("balrond.astafaraios.paintingframe", "BalrondPaintingFrame", "1.0.2")] public class Launch : BaseUnityPlugin { [HarmonyPatch] private static class AudioMan_Initialize_Patch { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(AudioMan), "Awake", (Type[])null, (Type[])null) ?? AccessTools.Method(typeof(AudioMan), "Start", (Type[])null, (Type[])null) ?? AccessTools.Method(typeof(AudioMan), "OnEnable", (Type[])null, (Type[])null) ?? throw new MissingMethodException(typeof(AudioMan).FullName, "Awake/Start/OnEnable"); } private static void Postfix(AudioMan __instance) { AudioRoutingService.OnAudioManAwake(__instance); } } public const string PluginGUID = "balrond.astafaraios.paintingframe"; public const string PluginName = "BalrondPaintingFrame"; public const string PluginVersion = "1.0.2"; 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; ServerSyncBridge.Initialize("balrond.astafaraios.paintingframe", "BalrondPaintingFrame", "1.0.2"); PaintingFrameConfig.Bind(((BaseUnityPlugin)this).Config); AudioRoutingService.ConfigureLogging(delegate(string message) { ((BaseUnityPlugin)this).Logger.LogInfo((object)message); }, delegate(string message) { ((BaseUnityPlugin)this).Logger.LogWarning((object)message); }, delegate(string message) { ((BaseUnityPlugin)this).Logger.LogError((object)message); }); AudioRoutingService.DebugLogging = PaintingFrameConfig.AudioDebugLogging.Value; PaintingFrameConfig.AudioDebugLogging.SettingChanged += delegate { AudioRoutingService.DebugLogging = PaintingFrameConfig.AudioDebugLogging.Value; }; jsonLoader.loadJson(); LoadAssetBundle(); LoadPaintingTextures(); LoadPaintingPrefabs(); AudioRoutingService.Process((IEnumerable<GameObject>)PaintingPiecePrefabs); harmony.PatchAll(); Debug.Log((object)string.Format("[{0}] Awake finished. Prefabs={1}, Textures={2}", "BalrondPaintingFrame", PaintingPiecePrefabs.Count, AllPaintingTextures.Count)); } private void OnDestroy() { harmony.UnpatchSelf(); ServerSyncBridge.Reset(); } 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 float GetHoverOffset() { return 0f; } 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 num = zdo.GetLong("BalrondPaintingFrame.editor_player_id", 0L); return num == playerId; } private bool HasValidLock(ZDO zdo, long playerId) { if (zdo == null) { return false; } if (!IsLockActive(zdo)) { return false; } long num = zdo.GetLong("BalrondPaintingFrame.editor_player_id", 0L); return num == playerId; } private bool IsLockActive(ZDO zdo) { if (zdo == null) { return false; } if (!zdo.GetBool("BalrondPaintingFrame.in_use", false)) { return false; } long num = zdo.GetLong("BalrondPaintingFrame.editor_player_id", 0L); if (num == 0) { return false; } long num2 = zdo.GetLong("BalrondPaintingFrame.editor_timeout", 0L); long ticks = DateTime.UtcNow.Ticks; if (num2 <= 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 num = zDO.GetLong("BalrondPaintingFrame.editor_player_id", 0L); long localPlayerId = GetLocalPlayerId(); return num != 0L && num != 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, false); } } 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 num3 = zDO.GetFloat("BalrondPaintingFrame.base_offset_x", 0f); float num4 = 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(num3, num4); 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); } } PrefabSetup.AuditBuildPieceMetadata(); 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; private static Sprite s_fallbackPieceIcon; 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 + "'")); } } internal static void ApplyRuntimeSettingsToLoadedPrefabs() { for (int i = 0; i < Launch.PaintingPiecePrefabs.Count; i++) { GameObject val = Launch.PaintingPiecePrefabs[i]; if (!((Object)(object)val == (Object)null)) { PaintingFrame component = val.GetComponent<PaintingFrame>(); if (!((Object)(object)component == (Object)null)) { component.requireWardAccess = PaintingFrameConfig.RequireWardAccess == null || PaintingFrameConfig.RequireWardAccess.Value; component.lockTimeoutSeconds = ((PaintingFrameConfig.LockTimeoutSeconds != null) ? Mathf.Max(1f, PaintingFrameConfig.LockTimeoutSeconds.Value) : 10f); component.zoomStep = ((PaintingFrameConfig.ZoomStep != null) ? Mathf.Max(0.01f, PaintingFrameConfig.ZoomStep.Value) : 0.1f); component.maxZoom = ((PaintingFrameConfig.MaxZoom != null) ? Mathf.Max(1f, PaintingFrameConfig.MaxZoom.Value) : 4f); component.moveStep = ((PaintingFrameConfig.MoveStep != null) ? Mathf.Max(0.001f, PaintingFrameConfig.MoveStep.Value) : 0.025f); } } } } 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 = PaintingFrameConfig.RequireWardAccess == null || PaintingFrameConfig.RequireWardAccess.Value; paintingFrame.defaultImageIndex = 0; paintingFrame.syncInterval = 2f; paintingFrame.editInputInterval = 0.05f; paintingFrame.lockRefreshInterval = 1f; paintingFrame.lockTimeoutSeconds = ((PaintingFrameConfig.LockTimeoutSeconds != null) ? Mathf.Max(1f, PaintingFrameConfig.LockTimeoutSeconds.Value) : 10f); paintingFrame.zoomStep = ((PaintingFrameConfig.ZoomStep != null) ? Mathf.Max(0.01f, PaintingFrameConfig.ZoomStep.Value) : 0.1f); paintingFrame.minZoom = 1f; paintingFrame.maxZoom = ((PaintingFrameConfig.MaxZoom != null) ? Mathf.Max(1f, PaintingFrameConfig.MaxZoom.Value) : 4f); paintingFrame.moveStep = ((PaintingFrameConfig.MoveStep != null) ? Mathf.Max(0.001f, PaintingFrameConfig.MoveStep.Value) : 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_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_039a: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: 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_enabled = true; component.m_category = (PieceCategory)4; component.m_usage = (UsageTagFlags)(component.m_usage | 0x280); 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; } EnsurePieceIcon(component, prefab); Debug.Log((object)string.Format("[{0}] Piece '{1}' configured with {2} resources, category={3}, usage={4}, icon={5}", "BalrondPaintingFrame", ((Object)prefab).name, component.m_resources.Length, component.m_category, component.m_usage, ((Object)(object)component.m_icon != (Object)null) ? ((Object)component.m_icon).name : "NULL")); } private static void EnsurePieceIcon(Piece piece, GameObject prefab) { //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)piece == (Object)null || (Object)(object)piece.m_icon != (Object)null) { return; } Texture2D val = null; Renderer val2 = (((Object)(object)prefab != (Object)null) ? FindPaintingRenderer(prefab) : null); if ((Object)(object)val2 != (Object)null && (Object)(object)val2.sharedMaterial != (Object)null) { Texture mainTexture = val2.sharedMaterial.mainTexture; val = (Texture2D)(object)((mainTexture is Texture2D) ? mainTexture : null); } if ((Object)(object)val == (Object)null && Launch.AllPaintingTextures != null && Launch.AllPaintingTextures.Count > 0) { val = Launch.AllPaintingTextures[0]; } if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("[BalrondPaintingFrame] Piece '" + (((Object)(object)prefab != (Object)null) ? ((Object)prefab).name : "NULL") + "' has no icon and no texture was available for a runtime fallback icon")); return; } if ((Object)(object)s_fallbackPieceIcon == (Object)null || (Object)(object)s_fallbackPieceIcon.texture != (Object)(object)val) { s_fallbackPieceIcon = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); ((Object)s_fallbackPieceIcon).name = "BalrondPaintingFrame_RuntimeIcon"; } piece.m_icon = s_fallbackPieceIcon; Debug.Log((object)("[BalrondPaintingFrame] Assigned runtime fallback icon to '" + ((Object)prefab).name + "'")); } public static void AuditBuildPieceMetadata() { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Invalid comparison between Unknown and I4 //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Invalid comparison between Unknown and I4 //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Invalid comparison between Unknown and I4 int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = 0; for (int i = 0; i < Launch.PaintingPiecePrefabs.Count; i++) { GameObject val = Launch.PaintingPiecePrefabs[i]; if ((Object)(object)val == (Object)null) { continue; } num++; Piece component = val.GetComponent<Piece>(); if ((Object)(object)component == (Object)null) { num2++; continue; } if (!component.m_enabled) { num3++; } if ((int)component.m_usage == 0) { num4++; } if ((int)component.m_category < 0 || (int)component.m_category >= 9) { num5++; } if ((Object)(object)component.m_icon == (Object)null) { num6++; } } Debug.Log((object)string.Format("[{0}] Build-piece metadata audit: total={1}, noPiece={2}, disabled={3}, zeroUsage={4}, invalidCategory={5}, missingIcon={6}", "BalrondPaintingFrame", num, num2, num3, num4, num5, num6)); } 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 Jso