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 twinstones v1.0.2
plugins/BalrondTwinStones.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; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("BalrondTwinStones")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("BalrondTwinStones")] [assembly: AssemblyCopyright("Copyright © 2022")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("1b2e1e3f-41b3-4b20-a571-677867607a30")] [assembly: AssemblyFileVersion("1.0.6.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.6.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 BalrondTwinStones { public class BalrondPortalPairPiece : MonoBehaviour, Hoverable, Interactable, TextReceiver { private const string ZdoKeyPortalId = "bpp_portal_id"; private const string ZdoKeyLinkedPortalId = "bpp_linked_portal_id"; private const string ZdoKeyPortalName = "bpp_portal_name"; private const string ZdoKeyPendingPlayerId = "bpp_pending_player_id"; private static readonly Dictionary<string, BalrondPortalPairPiece> PortalRegistry = new Dictionary<string, BalrondPortalPairPiece>(); private static readonly Dictionary<long, float> LastTeleportTime = new Dictionary<long, float>(); private ZNetView _nview; private Piece _piece; private GameObject _connectionEffect; private bool _lastLinkedState; private bool _lastPendingState; private string _cachedPortalId = string.Empty; private string _cachedLinkedPortalId = string.Empty; [Header("Link")] public float m_maxLinkDistance = 100f; [Header("Teleport")] public Transform m_exitPoint; public Vector3 m_exitOffset = new Vector3(0f, 0.5f, 1.5f); public float m_teleportCooldown = 1.5f; [Header("Teleport Cost")] public ItemDrop m_fuel = null; public int m_fuelConsume = 0; public bool m_shouldConsumeItem = false; [Header("Visuals")] public GameObject m_visualConnected; public GameObject m_visualUnconnected; public GameObject m_visualPending; [Header("Connection Effect")] public GameObject m_connectionPrefab; public Vector3 m_connectionOffset = Vector3.zero; public float m_connectionEffectTimeout = 0.35f; [Header("Naming")] public int m_nameCharacterLimit = 32; private void Awake() { _nview = ((Component)this).GetComponent<ZNetView>(); _piece = ((Component)this).GetComponent<Piece>(); if ((Object)(object)_nview == (Object)null || _nview.GetZDO() == null) { ((Behaviour)this).enabled = false; return; } EnsurePortalId(); _cachedPortalId = ReadPortalIdFromZDO(); _cachedLinkedPortalId = ReadLinkedPortalIdFromZDO(); RegisterSelf(); UpdateVisualStateImmediate(); } private void OnDestroy() { StopConnectionEffect(); string cachedPortalId = _cachedPortalId; string cachedLinkedPortalId = _cachedLinkedPortalId; ClearPendingState(); if (!string.IsNullOrEmpty(cachedPortalId)) { PortalRegistry.Remove(cachedPortalId); PortalPendingLinkManager.ClearByPortalId(cachedPortalId); } if (!string.IsNullOrEmpty(cachedPortalId) && !string.IsNullOrEmpty(cachedLinkedPortalId)) { BalrondPortalPairPiece balrondPortalPairPiece = FindPortalById(cachedLinkedPortalId); if (IsPortalUsable(balrondPortalPairPiece) && balrondPortalPairPiece.GetLinkedPortalId() == cachedPortalId) { balrondPortalPairPiece.ClaimOwnershipIfNeeded(); balrondPortalPairPiece.SetLinkedPortalId(string.Empty); balrondPortalPairPiece.UpdateCachedLinkedPortalId(); balrondPortalPairPiece.UpdateVisualStateImmediate(); balrondPortalPairPiece.StopConnectionEffect(); } } } private void Update() { UpdateCachedLinkedPortalId(); UpdateVisualState(); } public static void ClearPendingForPlayer(Player player, bool showMessage) { if ((Object)(object)player == (Object)null) { return; } long playerID = player.GetPlayerID(); if (PortalPendingLinkManager.TryGet(playerID, out var portalId)) { ClearPendingStateByPortalId(portalId); } if (PortalPendingLinkManager.Has(playerID)) { PortalPendingLinkManager.Clear(playerID); if (showMessage) { ((Character)player).Message((MessageType)2, "$tag_pending_connection", 0, (Sprite)null, false); } } } public string GetHoverName() { string text = GetText(); if (!string.IsNullOrEmpty(text)) { return text; } return ((Object)(object)_piece != (Object)null) ? Localization.instance.Localize(_piece.m_name) : "Portal"; } public float GetHoverOffset() { return 0f; } public string GetHoverText() { //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) string text = GetHoverName(); if ((Object)(object)m_fuel != (Object)null) { text = text + " Cost: " + GetFuelCostText(); } if (!HasLinkedPortal()) { text += "\n[$tag_unlinked_portal]"; text += "\n[<color=green><b>Shift+$KEY_Use</b></color>] $tag_link_portal"; text += "\n[<color=red><b>Ctrl+$KEY_Use</b></color>] $tag_cancel_portal"; text += "\n[<color=yellow><b>Alt+$KEY_Use</b></color>] $tag_rename_portal"; return Localization.instance.Localize(text); } BalrondPortalPairPiece balrondPortalPairPiece = FindPortalById(GetLinkedPortalId()); if (!IsPortalUsable(balrondPortalPairPiece)) { text += "\n[$tag_missingtarget_portal]"; text += "\n[<color=yellow><b>Shift+$KEY_Use</b></color>] $tag_relink_portal"; text += "\n[<color=red><b>Ctrl+$KEY_Use</b></color>] $tag_disconnect_portal"; text += "\n[<color=yellow><b>Alt+$KEY_Use</b></color>] $tag_rename_portal"; return Localization.instance.Localize(text); } PokeConnectionEffect(); balrondPortalPairPiece.PokeConnectionEffect(); int num = Mathf.RoundToInt(Vector3.Distance(((Component)this).transform.position, ((Component)balrondPortalPairPiece).transform.position)); float maxLinkDistance = Launch.GetMaxLinkDistance(m_maxLinkDistance); text = text + "\n[<color=green><b>$KEY_Use</b></color>] $tag_target_portal: " + balrondPortalPairPiece.GetHoverName() + "\n$tag_distance_portal: " + num + "/" + maxLinkDistance + "m"; text += "\n[<color=yellow><b>Shift+$KEY_Use</b></color>] $tag_relink_portal"; text += "\n[<color=red><b>Ctrl+$KEY_Use</b></color>] $tag_disconnect_portal"; text += "\n[<color=blue><b>Alt+$KEY_Use</b></color>] $tag_rename_portal"; return Localization.instance.Localize(text); } public bool Interact(Humanoid user, bool hold, bool alt) { if (hold) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)val == (Object)null) { return false; } if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || _nview.GetZDO() == null) { return false; } ValidatePendingLink(val.GetPlayerID(), val); if (IsPendingForOtherPlayer(val.GetPlayerID())) { ((Character)val).Message((MessageType)2, "$tag_pending_connection", 0, (Sprite)null, false); return true; } if (IsAltHeld()) { TextInput.instance.RequestText((TextReceiver)(object)this, "Portal name", m_nameCharacterLimit); return true; } if (IsCtrlHeld()) { HandleCtrl(val); return true; } if (IsShiftHeld()) { HandleShift(val); return true; } HandleTeleport(val); return true; } public bool UseItem(Humanoid user, ItemData item) { return false; } public string GetText() { if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || _nview.GetZDO() == null) { return string.Empty; } return _nview.GetZDO().GetString("bpp_portal_name", string.Empty); } public void SetText(string text) { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && _nview.GetZDO() != null) { ClaimOwnershipIfNeeded(); _nview.GetZDO().Set("bpp_portal_name", text ?? string.Empty); } } private void HandleShift(Player player) { //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_nview == (Object)null || !_nview.IsValid() || _nview.GetZDO() == null) { return; } long playerID = player.GetPlayerID(); string portalId = GetPortalId(); if (string.IsNullOrEmpty(portalId)) { return; } if (!PortalPendingLinkManager.TryGet(playerID, out var portalId2)) { if (IsPendingForOtherPlayer(playerID)) { ((Character)player).Message((MessageType)2, "$tag_pending_connection", 0, (Sprite)null, false); return; } PortalPendingLinkManager.Set(playerID, portalId); SetPendingPlayerId(playerID); ((Character)player).Message((MessageType)2, "$tag_link_started", 0, (Sprite)null, false); return; } if (portalId2 == portalId) { ClearPendingState(); PortalPendingLinkManager.Clear(playerID); ((Character)player).Message((MessageType)2, "$tag_link_canceled", 0, (Sprite)null, false); return; } if (IsPendingForOtherPlayer(playerID)) { ((Character)player).Message((MessageType)2, "$tag_pending_connection", 0, (Sprite)null, false); return; } BalrondPortalPairPiece balrondPortalPairPiece = FindPortalById(portalId2); if (!IsPortalUsable(balrondPortalPairPiece)) { PortalPendingLinkManager.Clear(playerID); ClearPendingStateByPortalId(portalId2); ((Character)player).Message((MessageType)2, "$tag_pending_cleared", 0, (Sprite)null, false); return; } float num = Vector3.Distance(((Component)balrondPortalPairPiece).transform.position, ((Component)this).transform.position); float maxLinkDistance = Launch.GetMaxLinkDistance(m_maxLinkDistance); if (num > maxLinkDistance) { ((Character)player).Message((MessageType)2, "$tag_tofar", 0, (Sprite)null, false); return; } LinkPortals(balrondPortalPairPiece, this); balrondPortalPairPiece.ClearPendingState(); PortalPendingLinkManager.Clear(playerID); ((Character)player).Message((MessageType)2, "$tag_linked", 0, (Sprite)null, false); } private void HandleCtrl(Player player) { long playerID = player.GetPlayerID(); if (PortalPendingLinkManager.TryGet(playerID, out var portalId)) { ClearPendingStateByPortalId(portalId); PortalPendingLinkManager.Clear(playerID); ((Character)player).Message((MessageType)2, "$tag_canceled", 0, (Sprite)null, false); } else if (HasLinkedPortal()) { UnlinkPortal(this); ((Character)player).Message((MessageType)2, "$tag_disconnected", 0, (Sprite)null, false); } } private void HandleTeleport(Player player) { //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) if (!HasLinkedPortal()) { ((Character)player).Message((MessageType)2, "$tag_not_linked", 0, (Sprite)null, false); return; } long playerID = player.GetPlayerID(); if (LastTeleportTime.TryGetValue(playerID, out var value) && Time.time - value < m_teleportCooldown) { return; } if (!CanPayTeleportCost(player)) { ((Character)player).Message((MessageType)2, GetMissingCostText(), 0, (Sprite)null, false); return; } BalrondPortalPairPiece balrondPortalPairPiece = FindPortalById(GetLinkedPortalId()); if (!IsPortalUsable(balrondPortalPairPiece)) { UnlinkPortal(this); ((Character)player).Message((MessageType)2, "$tag_linkedportal_missing", 0, (Sprite)null, false); return; } ConsumeTeleportCost(player); balrondPortalPairPiece.GetExitPosition(out var pos, out var rot); LastTeleportTime[playerID] = Time.time; ((Character)player).TeleportTo(pos, rot, false); } private bool CanPayTeleportCost(Player player) { if ((Object)(object)player == (Object)null) { return false; } if ((Object)(object)m_fuel == (Object)null || m_fuelConsume <= 0) { return true; } Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory == null) { return false; } return inventory.CountItems(m_fuel.m_itemData.m_shared.m_name, -1, true) >= m_fuelConsume; } private void ConsumeTeleportCost(Player player) { if (m_shouldConsumeItem && !((Object)(object)player == (Object)null) && !((Object)(object)m_fuel == (Object)null) && m_fuelConsume > 0) { Inventory inventory = ((Humanoid)player).GetInventory(); if (inventory != null) { inventory.RemoveItem(m_fuel.m_itemData.m_shared.m_name, m_fuelConsume, -1, true); } } } private string GetFuelCostText() { if ((Object)(object)m_fuel == (Object)null || m_fuelConsume <= 0) { return ""; } string text = ((Localization.instance != null) ? Localization.instance.Localize(m_fuel.m_itemData.m_shared.m_name) : m_fuel.m_itemData.m_shared.m_name); if (m_shouldConsumeItem) { return text + " x" + m_fuelConsume; } if (m_fuelConsume <= 1) { return text + "$tag_required"; } return text + " x" + m_fuelConsume + "$tag_required"; } private string GetMissingCostText() { if ((Object)(object)m_fuel == (Object)null || m_fuelConsume <= 0) { return string.Empty; } string text = ((Localization.instance != null) ? Localization.instance.Localize(m_fuel.m_itemData.m_shared.m_name) : m_fuel.m_itemData.m_shared.m_name); if (m_shouldConsumeItem) { return "Need " + text + " x" + m_fuelConsume; } if (m_fuelConsume <= 1) { return "Need " + text + " in inventory"; } return "Need " + text + " x" + m_fuelConsume + " in inventory"; } private void GetExitPosition(out Vector3 pos, out Quaternion rot) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_exitPoint != (Object)null) { pos = m_exitPoint.position; rot = m_exitPoint.rotation; } else { pos = ((Component)this).transform.TransformPoint(m_exitOffset); rot = ((Component)this).transform.rotation; } } private void EnsurePortalId() { if (!((Object)(object)_nview == (Object)null) && _nview.GetZDO() != null) { ClaimOwnershipIfNeeded(); if (string.IsNullOrEmpty(ReadPortalIdFromZDO())) { _nview.GetZDO().Set("bpp_portal_id", Guid.NewGuid().ToString("N")); } } } private void RegisterSelf() { string portalId = GetPortalId(); if (!string.IsNullOrEmpty(portalId)) { PortalRegistry[portalId] = this; } } private void ClaimOwnershipIfNeeded() { if (!((Object)(object)_nview == (Object)null) && _nview.IsValid() && !_nview.IsOwner()) { _nview.ClaimOwnership(); } } public string GetPortalId() { string text = ReadPortalIdFromZDO(); if (!string.IsNullOrEmpty(text)) { _cachedPortalId = text; } return _cachedPortalId; } public string GetLinkedPortalId() { string text = ReadLinkedPortalIdFromZDO(); _cachedLinkedPortalId = text ?? string.Empty; return _cachedLinkedPortalId; } private void SetLinkedPortalId(string id) { if (!((Object)(object)_nview == (Object)null) && _nview.GetZDO() != null) { _nview.GetZDO().Set("bpp_linked_portal_id", id ?? string.Empty); _cachedLinkedPortalId = id ?? string.Empty; } } private long GetPendingPlayerId() { if ((Object)(object)_nview == (Object)null || _nview.GetZDO() == null) { return 0L; } return _nview.GetZDO().GetLong("bpp_pending_player_id", 0L); } private void SetPendingPlayerId(long playerId) { if (!((Object)(object)_nview == (Object)null) && _nview.GetZDO() != null) { ClaimOwnershipIfNeeded(); _nview.GetZDO().Set("bpp_pending_player_id", playerId); UpdateVisualStateImmediate(); } } private void ClearPendingState() { SetPendingPlayerId(0L); } private static void ClearPendingStateByPortalId(string portalId) { BalrondPortalPairPiece balrondPortalPairPiece = FindPortalById(portalId); if (IsPortalUsable(balrondPortalPairPiece)) { balrondPortalPairPiece.ClearPendingState(); } } private bool IsPending() { return GetPendingPlayerId() != 0; } private bool IsPendingForOtherPlayer(long playerId) { long pendingPlayerId = GetPendingPlayerId(); return pendingPlayerId != 0L && pendingPlayerId != playerId; } public bool HasLinkedPortal() { return !string.IsNullOrEmpty(GetLinkedPortalId()); } private void UpdateVisualState() { bool flag = HasLinkedPortal(); bool flag2 = IsPending(); if (flag != _lastLinkedState || flag2 != _lastPendingState) { UpdateVisualStateImmediate(); } } private void UpdateVisualStateImmediate() { bool flag = HasLinkedPortal(); bool flag2 = IsPending(); _lastLinkedState = flag; _lastPendingState = flag2; if ((Object)(object)m_visualPending != (Object)null) { m_visualPending.SetActive(flag2); } if ((Object)(object)m_visualConnected != (Object)null) { m_visualConnected.SetActive(flag && !flag2); } if ((Object)(object)m_visualUnconnected != (Object)null) { m_visualUnconnected.SetActive(!flag && !flag2); } } public static void LinkPortals(BalrondPortalPairPiece a, BalrondPortalPairPiece b) { if (IsPortalUsable(a) && IsPortalUsable(b)) { a.ClaimOwnershipIfNeeded(); b.ClaimOwnershipIfNeeded(); string portalId = a.GetPortalId(); string portalId2 = b.GetPortalId(); if (!string.IsNullOrEmpty(portalId) && !string.IsNullOrEmpty(portalId2)) { a.ClearPendingState(); b.ClearPendingState(); a.SetLinkedPortalId(portalId2); b.SetLinkedPortalId(portalId); a.UpdateVisualStateImmediate(); b.UpdateVisualStateImmediate(); } } } public static void UnlinkPortal(BalrondPortalPairPiece p) { if (IsPortalUsable(p)) { BalrondPortalPairPiece balrondPortalPairPiece = FindPortalById(p.GetLinkedPortalId()); p.ClaimOwnershipIfNeeded(); p.SetLinkedPortalId(string.Empty); p.UpdateVisualStateImmediate(); p.StopConnectionEffect(); if (IsPortalUsable(balrondPortalPairPiece)) { balrondPortalPairPiece.ClaimOwnershipIfNeeded(); balrondPortalPairPiece.SetLinkedPortalId(string.Empty); balrondPortalPairPiece.UpdateVisualStateImmediate(); balrondPortalPairPiece.StopConnectionEffect(); } } } public static BalrondPortalPairPiece FindPortalById(string id) { if (string.IsNullOrEmpty(id)) { return null; } PortalRegistry.TryGetValue(id, out var value); return value; } private static bool IsPortalUsable(BalrondPortalPairPiece p) { return (Object)(object)p != (Object)null && (Object)(object)p._nview != (Object)null && p._nview.IsValid() && p._nview.GetZDO() != null; } private void PokeConnectionEffect() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) if (HasLinkedPortal()) { BalrondPortalPairPiece balrondPortalPairPiece = FindPortalById(GetLinkedPortalId()); if (IsPortalUsable(balrondPortalPairPiece)) { StartConnectionEffect(balrondPortalPairPiece.GetConnectionPoint()); } } } private void StartConnectionEffect(Vector3 target) { //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_001e: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)m_connectionPrefab == (Object)null) { return; } Vector3 connectionPoint = GetConnectionPoint(); Vector3 val = target - connectionPoint; if (!(((Vector3)(ref val)).sqrMagnitude <= 0.0001f)) { if ((Object)(object)_connectionEffect == (Object)null) { _connectionEffect = Object.Instantiate<GameObject>(m_connectionPrefab); } _connectionEffect.transform.position = connectionPoint; _connectionEffect.transform.rotation = Quaternion.LookRotation(((Vector3)(ref val)).normalized); _connectionEffect.transform.localScale = new Vector3(1f, 1f, ((Vector3)(ref val)).magnitude); ((MonoBehaviour)this).CancelInvoke("StopConnectionEffect"); ((MonoBehaviour)this).Invoke("StopConnectionEffect", m_connectionEffectTimeout); } } private void StopConnectionEffect() { if ((Object)(object)_connectionEffect != (Object)null) { Object.Destroy((Object)(object)_connectionEffect); _connectionEffect = null; } } private Vector3 GetConnectionPoint() { //IL_0008: 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_0015: Unknown result type (might be due to invalid IL or missing references) return ((Component)this).transform.TransformPoint(m_connectionOffset); } private string ReadPortalIdFromZDO() { if ((Object)(object)_nview == (Object)null || _nview.GetZDO() == null) { return _cachedPortalId; } return _nview.GetZDO().GetString("bpp_portal_id", string.Empty); } private string ReadLinkedPortalIdFromZDO() { if ((Object)(object)_nview == (Object)null || _nview.GetZDO() == null) { return _cachedLinkedPortalId; } return _nview.GetZDO().GetString("bpp_linked_portal_id", string.Empty); } private void UpdateCachedLinkedPortalId() { _cachedLinkedPortalId = ReadLinkedPortalIdFromZDO(); } private static bool IsShiftHeld() { return Input.GetKey((KeyCode)304) || Input.GetKey((KeyCode)303); } private static bool IsCtrlHeld() { return Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305); } private static bool IsAltHeld() { return Input.GetKey((KeyCode)308) || Input.GetKey((KeyCode)307); } public static void ValidatePendingLink(long id, Player player) { if (!PortalPendingLinkManager.TryGet(id, out var portalId)) { return; } BalrondPortalPairPiece p = FindPortalById(portalId); if (!IsPortalUsable(p)) { PortalPendingLinkManager.Clear(id); ClearPendingStateByPortalId(portalId); if ((Object)(object)player != (Object)null) { ((Character)player).Message((MessageType)2, "$tag_pending_connection", 0, (Sprite)null, false); } } } } 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; } } internal class BuildPieceList { public static string[] buildPieces = new string[1] { "piece_obeliskPortal_bal" }; } internal static class EmbeddedDependencyResolver { internal static Assembly LoadServerSync(Assembly owner) { return LoadEmbeddedAssembly(owner, "ServerSync", "BalrondTwinStones.ServerSync.dll", "ServerSync.dll", required: true); } internal static Assembly LoadLitJson(Assembly owner) { return LoadEmbeddedAssembly(owner, "LitJson2", "BalrondTwinStones.LitJson2.dll", null, required: true); } private static Assembly LoadEmbeddedAssembly(Assembly owner, string dependencyName, string resourceName, string looseFileName, bool required) { if (owner == null) { throw new ArgumentNullException("owner"); } Assembly assembly = FindLoaded(dependencyName); if (assembly != null) { return assembly; } using (Stream stream = owner.GetManifestResourceStream(resourceName)) { if (stream != null && stream.Length > 0 && stream.Length <= int.MaxValue) { byte[] array = new byte[(int)stream.Length]; int i; int num; for (i = 0; i < array.Length; i += num) { num = stream.Read(array, i, array.Length - i); if (num <= 0) { break; } } if (i == array.Length) { return Assembly.Load(array); } } } if (!string.IsNullOrEmpty(looseFileName) && !string.IsNullOrEmpty(owner.Location)) { string directoryName = Path.GetDirectoryName(owner.Location); if (!string.IsNullOrEmpty(directoryName)) { string text = Path.Combine(directoryName, looseFileName); if (File.Exists(text)) { return Assembly.LoadFrom(text); } } } if (required) { throw new FileNotFoundException("BalrondTwinStones could not load embedded dependency " + dependencyName + "."); } return null; } private static Assembly FindLoaded(string dependencyName) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { AssemblyName name = assemblies[i].GetName(); if (string.Equals(name.Name, dependencyName, StringComparison.OrdinalIgnoreCase)) { return assemblies[i]; } } return null; } } internal static class ServerSyncBridge { private static object sync; private static Type syncType; internal static void Initialize(Assembly serverSyncAssembly, string pluginGuid, string displayName, string version) { if (serverSyncAssembly == null) { throw new ArgumentNullException("serverSyncAssembly"); } syncType = serverSyncAssembly.GetType("ServerSync.ConfigSync", throwOnError: true); sync = Activator.CreateInstance(syncType, pluginGuid); if (sync == null) { throw new InvalidOperationException("ServerSync.ConfigSync could not be created."); } SetMember("DisplayName", displayName); SetMember("CurrentVersion", version); SetMember("MinimumRequiredVersion", version); SetMember("ModRequired", true); } internal static void AddLockingConfigEntry(ConfigEntry<bool> entry) { if (entry == null) { throw new ArgumentNullException("entry"); } InvokeEntryMethod("AddLockingConfigEntry", entry, typeof(bool)); } internal static void AddConfigEntry<T>(ConfigEntry<T> entry) { if (entry == null) { throw new ArgumentNullException("entry"); } object obj = InvokeEntryMethod("AddConfigEntry", entry, typeof(T)); if (obj == null) { throw new InvalidOperationException("ServerSync.AddConfigEntry returned null."); } Type type = obj.GetType(); PropertyInfo property = type.GetProperty("SynchronizedConfig", BindingFlags.Instance | BindingFlags.Public); if (property != null && property.CanWrite) { property.SetValue(obj, true, null); return; } FieldInfo field = type.GetField("SynchronizedConfig", BindingFlags.Instance | BindingFlags.Public); if (field != null) { field.SetValue(obj, true); return; } throw new MissingMemberException(type.FullName, "SynchronizedConfig"); } internal static void Reset() { sync = null; syncType = null; } private static object InvokeEntryMethod(string name, object entry, Type valueType) { object obj = sync; Type type = syncType; if (obj == null || type == null) { throw new InvalidOperationException("ServerSyncBridge was used before initialization."); } MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public); foreach (MethodInfo methodInfo in methods) { if (!string.Equals(methodInfo.Name, name, StringComparison.Ordinal) || methodInfo.GetParameters().Length != 1) { continue; } MethodInfo methodInfo2 = methodInfo; if (methodInfo.IsGenericMethodDefinition) { Type[] genericArguments = methodInfo.GetGenericArguments(); if (genericArguments.Length != 1) { continue; } methodInfo2 = methodInfo.MakeGenericMethod(valueType); } ParameterInfo[] parameters = methodInfo2.GetParameters(); if (!parameters[0].ParameterType.IsInstanceOfType(entry)) { continue; } return methodInfo2.Invoke(obj, new object[1] { entry }); } throw new MissingMethodException(type.FullName, name); } private static void SetMember(string name, object value) { PropertyInfo property = syncType.GetProperty(name, BindingFlags.Instance | BindingFlags.Public); if (property != null && property.CanWrite) { property.SetValue(sync, value, null); return; } FieldInfo field = syncType.GetField(name, BindingFlags.Instance | BindingFlags.Public); if (field != null) { field.SetValue(sync, value); return; } throw new MissingMemberException(syncType.FullName, name); } } public class DatabaseAddMethods { public void AddItems(List<GameObject> items) { foreach (GameObject item in items) { AddItem(item); } } public void AddRecipes(List<Recipe> recipes) { foreach (Recipe recipe in recipes) { AddRecipe(recipe); } } public void AddStatuseffects(List<StatusEffect> statusEffects) { foreach (StatusEffect statusEffect in statusEffects) { AddStatus(statusEffect); } } private bool IsObjectDBValid() { return (Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.m_items.Count != 0 && ObjectDB.instance.m_recipes.Count != 0 && (Object)(object)ObjectDB.instance.GetItemPrefab("Amber") != (Object)null; } private void AddStatus(StatusEffect status) { if (!IsObjectDBValid()) { return; } if ((Object)(object)status != (Object)null) { if ((Object)(object)ObjectDB.instance.GetStatusEffect(status.m_nameHash) == (Object)null) { ObjectDB.instance.m_StatusEffects.Add(status); } else { Debug.Log((object)(Launch.projectName + ": " + ((Object)status).name + " - Status already in the game")); } } else { Debug.LogError((object)(Launch.projectName + ": " + ((Object)status).name + " - Status not found")); } } private void AddRecipe(Recipe recipe) { if (!IsObjectDBValid()) { return; } if ((Object)(object)recipe != (Object)null) { if ((Object)(object)ObjectDB.instance.m_recipes.Find((Recipe x) => ((Object)x).name == ((Object)recipe).name) == (Object)null) { if ((Object)(object)recipe.m_item != (Object)null) { ObjectDB.instance.m_recipes.Add(recipe); } } else { Debug.Log((object)(Launch.projectName + ": " + ((Object)recipe).name + " - Recipe with this name already in the Game")); } } else { Debug.LogError((object)(Launch.projectName + ": " + ((Object)recipe).name + " - Recipe not found")); } } private void AddItem(GameObject newPrefab) { if (!IsObjectDBValid()) { return; } ItemDrop component = newPrefab.GetComponent<ItemDrop>(); if ((Object)(object)component != (Object)null) { if ((Object)(object)ObjectDB.instance.GetItemPrefab(((Object)newPrefab).name) == (Object)null) { ObjectDB.instance.m_items.Add(newPrefab); Dictionary<int, GameObject> dictionary = (Dictionary<int, GameObject>)typeof(ObjectDB).GetField("m_itemByHash", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(ObjectDB.instance); dictionary[((Object)newPrefab).name.GetHashCode()] = newPrefab; } else { Debug.LogWarning((object)(Launch.projectName + ": " + ((Object)newPrefab).name + " - ItemDrop already exist")); } } else { Debug.LogError((object)(Launch.projectName + ": " + ((Object)newPrefab).name + " - ItemDrop not found on prefab")); } } } public class ModResourceLoader { public AssetBundle assetBundle; public List<GameObject> buildPrefabs = new List<GameObject>(); public List<GameObject> plantPrefabs = new List<GameObject>(); public List<GameObject> itemPrefabs = new List<GameObject>(); public List<GameObject> monsterPrefabs = new List<GameObject>(); public List<GameObject> vegetationPrefabs = new List<GameObject>(); public List<GameObject> clutterPrefabs = new List<GameObject>(); public List<GameObject> locationPrefabs = new List<GameObject>(); public List<GameObject> roomPrefabs = new List<GameObject>(); public List<GameObject> vfxPrefabs = new List<GameObject>(); public List<Texture2D> texturePrefabs = new List<Texture2D>(); public List<Recipe> recipes = new List<Recipe>(); public List<StatusEffect> statusEffects = new List<StatusEffect>(); public StatusEffect newBarleyStatus = null; public ShaderReplacment shaderReplacment = new ShaderReplacment(); public Sprite newLogo = null; public void loadAssets() { assetBundle = GetAssetBundleFromResources("balrondtwinstones"); string basePath = "Assets/Custom/BalrondTwinStones/"; loadPieces(basePath); loadItems(basePath); loadOther(basePath); } public void AddPrefabsToZnetScene(ZNetScene zNetScene) { zNetScene.m_prefabs.AddRange(vegetationPrefabs); foreach (GameObject gm in itemPrefabs) { GameObject val = zNetScene.m_prefabs.Find((GameObject x) => ((Object)x).name == ((Object)gm).name); if ((Object)(object)val == (Object)null) { zNetScene.m_prefabs.Add(gm); } else { Debug.LogWarning((object)("Object exists: " + ((Object)gm).name)); } } foreach (GameObject gm2 in buildPrefabs) { GameObject val2 = zNetScene.m_prefabs.Find((GameObject x) => ((Object)x).name == ((Object)gm2).name); if ((Object)(object)val2 == (Object)null) { zNetScene.m_prefabs.Add(gm2); } else { Debug.LogWarning((object)("Object exists: " + ((Object)gm2).name)); } } foreach (GameObject gm3 in vfxPrefabs) { GameObject val3 = zNetScene.m_prefabs.Find((GameObject x) => ((Object)x).name == ((Object)gm3).name); if ((Object)(object)val3 == (Object)null) { zNetScene.m_prefabs.Add(gm3); } else { Debug.LogWarning((object)("Object exists: " + ((Object)gm3).name)); } } zNetScene.m_prefabs.RemoveAll((GameObject x) => (Object)(object)x == (Object)null); setupNewPortal(zNetScene); addPlantstoCultivator(zNetScene); setupBuildPiecesList(zNetScene); } private void setupNewPortal(ZNetScene zNetScene) { //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) GameObject val = buildPrefabs.Find((GameObject x) => ((Object)x).name == "piece_obeliskPortal_bal"); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)"[Portal] prefab piece_obeliskPortal_bal not found"); return; } Smelter component = val.GetComponent<Smelter>(); if ((Object)(object)component == (Object)null) { Debug.LogError((object)"[Portal] Smelter missing on piece_obeliskPortal_bal"); return; } StationExtension component2 = val.GetComponent<StationExtension>(); if ((Object)(object)component2 == (Object)null) { Debug.LogError((object)"[Portal] StationExtension missing on piece_obeliskPortal_bal"); return; } BalrondPortalPairPiece balrondPortalPairPiece = val.GetComponent<BalrondPortalPairPiece>(); if ((Object)(object)balrondPortalPairPiece == (Object)null) { balrondPortalPairPiece = val.AddComponent<BalrondPortalPairPiece>(); } if ((Object)(object)balrondPortalPairPiece == (Object)null) { Debug.LogError((object)"[Portal] Failed to instantiate BalrondPortalPairPiece on piece_obeliskPortal_bal"); return; } balrondPortalPairPiece.m_exitPoint = component.m_outputPoint; balrondPortalPairPiece.m_visualConnected = component.m_enabledObject; balrondPortalPairPiece.m_visualUnconnected = component.m_disabledObject; balrondPortalPairPiece.m_visualPending = component.m_haveFuelObject; balrondPortalPairPiece.m_fuel = null; balrondPortalPairPiece.m_fuelConsume = 0; balrondPortalPairPiece.m_shouldConsumeItem = true; balrondPortalPairPiece.m_maxLinkDistance = Launch.GetMaxLinkDistance(50f); balrondPortalPairPiece.m_connectionPrefab = component2.m_connectionPrefab; balrondPortalPairPiece.m_connectionOffset = new Vector3(0f, 1f, 0f); Object.DestroyImmediate((Object)(object)component); Object.DestroyImmediate((Object)(object)component2); } private void setupBuildPiecesList(ZNetScene zNetScene) { string[] array = new string[4] { "Hammer", "HammerIron", "HammerDverger", "HammerBlackmetal" }; GameObject val = zNetScene.m_prefabs.Find((GameObject x) => ((Object)x).name == "Hammer"); PieceTable buildPieces = val.GetComponent<ItemDrop>().m_itemData.m_shared.m_buildPieces; string[] array2 = array; foreach (string name in array2) { addBuildpiecesToOtherHammer(name, buildPieces, zNetScene); } List<GameObject> pieces = buildPieces.m_pieces; foreach (GameObject buildPrefab in buildPrefabs) { setupRavenGuide(buildPrefab, zNetScene.m_prefabs); AddToBuildList(buildPrefab, pieces); } } private void addBuildpiecesToOtherHammer(string name, PieceTable pieceTable, ZNetScene zNetScene) { GameObject val = zNetScene.m_prefabs.Find((GameObject x) => ((Object)x).name == name); if (!((Object)(object)val == (Object)null)) { val.GetComponent<ItemDrop>().m_itemData.m_shared.m_buildPieces = pieceTable; } } public void setupRavenGuide(GameObject gameObject, List<GameObject> gameObjects) { GameObject val = null; Transform val2 = gameObject.transform.Find("GuidePoint"); if ((Object)(object)val2 == (Object)null) { return; } GameObject val3 = gameObjects.Find((GameObject x) => ((Object)x).name == "piece_workbench"); if ((Object)(object)val3 != (Object)null) { GameObject gameObject2 = ((Component)val3.transform.Find("GuidePoint")).gameObject; if ((Object)(object)gameObject2 != (Object)null) { GuidePoint component = gameObject2.GetComponent<GuidePoint>(); if ((Object)(object)component != (Object)null) { val = component.m_ravenPrefab; } } } if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)"Ravens not found"); } else { ((Component)val2).GetComponent<GuidePoint>().m_ravenPrefab = val; } } public void setupBuildPiecesListDB() { GameObject val = ObjectDB.instance.m_items.Find((GameObject x) => ((Object)x).name == "Hammer"); List<GameObject> pieces = val.GetComponent<ItemDrop>().m_itemData.m_shared.m_buildPieces.m_pieces; foreach (GameObject buildPrefab in buildPrefabs) { AddToBuildList(buildPrefab, pieces); } } private void AddToBuildList(GameObject prefab, List<GameObject> buildPieces) { if ((Object)(object)buildPieces.Find((GameObject x) => ((Object)x).name == ((Object)prefab).name) == (Object)null) { buildPieces.Add(prefab); } } private void addPlantstoCultivator(ZNetScene zNetScene) { GameObject val = zNetScene.m_prefabs.Find((GameObject x) => ((Object)x).name == "Cultivator"); PieceTable buildPieces = val.GetComponent<ItemDrop>().m_itemData.m_shared.m_buildPieces; List<GameObject> pieces = buildPieces.m_pieces; foreach (GameObject plantPrefab in plantPrefabs) { pieces.Add(plantPrefab); } } private void loadItems(string basePath) { string mainPath = basePath + "Items/"; string[] nameList = new string[0]; addNewPrefabToCollection(nameList, mainPath, itemPrefabs, "item"); } private void addNewPrefabToCollection(string[] nameList, string mainPath, List<GameObject> prefabList, string typeName) { foreach (string text in nameList) { GameObject val = assetBundle.LoadAsset<GameObject>(mainPath + text + ".prefab"); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("Could not find " + typeName + " with name: " + text)); } else if (Object.op_Implicit((Object)(object)val.GetComponent<ZNetView>()) || typeName == "clutter") { ShaderReplacment.Replace(val); prefabList.Add(val); } else { Debug.LogWarning((object)("Prefab with name has no ZNetView could not been removed: " + text)); } } } private AssetBundle GetAssetBundleFromResources(string filename) { Assembly executingAssembly = Assembly.GetExecutingAssembly(); string name = executingAssembly.GetManifestResourceNames().Single((string str) => str.EndsWith(filename)); using Stream stream = executingAssembly.GetManifestResourceStream(name); return AssetBundle.LoadFromStream(stream); } private void loadPlants(string basePath) { string text = basePath + "Plants/"; string[] array = new string[0]; string[] array2 = array; foreach (string text2 in array2) { GameObject val = assetBundle.LoadAsset<GameObject>(text + text2 + ".prefab"); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("Could not find plant with name: " + text2)); continue; } ShaderReplacment.Replace(val); plantPrefabs.Add(val); } } private void loadPieces(string basePath) { string text = basePath + "Pieces/"; string[] buildPieces = BuildPieceList.buildPieces; string[] array = buildPieces; foreach (string text2 in array) { GameObject val = assetBundle.LoadAsset<GameObject>(text + text2 + ".prefab"); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("Could not find piece with name: " + text2)); continue; } ShaderReplacment.Replace(val); buildPrefabs.Add(val); } } private void loadVegetation(string basePath) { string text = basePath + "Vegetation/"; string[] array = new string[0]; string[] array2 = array; foreach (string text2 in array2) { GameObject val = assetBundle.LoadAsset<GameObject>(text + text2 + ".prefab"); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("Could not find vegegation with name: " + text2)); continue; } ShaderReplacment.Replace(val); vegetationPrefabs.Add(val); } } private void loadOther(string basePath) { string text = basePath + "Other/"; string[] array = new string[0]; string[] array2 = array; foreach (string text2 in array2) { GameObject val = assetBundle.LoadAsset<GameObject>(text + text2 + ".prefab"); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("Could not find object with name: " + text2)); continue; } ShaderReplacment.Replace(val); vfxPrefabs.Add(val); } } private void prepareOtherEffects(string mainPath) { string[] array = new string[0]; string[] array2 = array; foreach (string text in array2) { StatusEffect val = (StatusEffect)(object)assetBundle.LoadAsset<SE_Stats>(mainPath + "Status/" + text + ".asset"); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("Status not found: " + text)); } else { statusEffects.Add(val); } } } } public class ShaderReplacment { public static List<GameObject> prefabsToReplaceShader = new List<GameObject>(); public static List<Material> materialsInPrefabs = new List<Material>(); public string[] shaderlist = new string[49] { "Custom/AlphaParticle", "Custom/Blob", "Custom/Bonemass", "Custom/Clouds", "Custom/Creature", "Custom/Decal", "Custom/Distortion", "Custom/Flow", "Custom/FlowOpaque", "Custom/Grass", "Custom/GuiScroll", "Custom/Heightmap", "Custom/icon", "Custom/InteriorSide", "Custom/LitGui", "Custom/LitParticles", "Custom/mapshader", "Custom/ParticleDecal", "Custom/Piece", "Custom/Player", "Custom/Rug", "Custom/ShadowBlob", "Custom/SkyboxProcedural", "Custom/SkyObject", "Custom/StaticRock", "Custom/Tar", "Custom/Trilinearmap", "Custom/UI/BGBlur", "Custom/Vegetation", "Custom/Water", "Custom/WaterBottom", "Custom/WaterMask", "Custom/Yggdrasil", "Custom/Yggdrasil/root", "Hidden/BlitCopyHDRTonemap", "Hidden/Dof/DepthOfFieldHdr", "Hidden/Dof/DX11Dof", "Hidden/Internal-Loading", "Hidden/Internal-UIRDefaultWorld", "Hidden/SimpleClear", "Hidden/SunShaftsComposite", "Lux Lit Particles/ Bumped", "Lux Lit Particles/ Tess Bumped", "Particles/Standard Surface2", "Particles/Standard Unlit2", "Standard TwoSided", "ToonDeferredShading2017", "Unlit/DepthWrite", "Unlit/Lighting" }; public static List<Shader> shaders = new List<Shader>(); private static readonly HashSet<Shader> CachedShaders = new HashSet<Shader>(); public static bool debug = true; public static Shader findShader(string name) { Shader[] array = Resources.FindObjectsOfTypeAll<Shader>(); if (array.Length == 0) { Debug.LogWarning((object)"SHADER LIST IS EMPTY!"); return null; } if (debug) { } return shaders.Find((Shader x) => ((Object)x).name == name); } public static Shader GetShaderByName(string name) { return shaders.Find((Shader x) => ((Object)x).name == name.Trim()); } public static void debugShaderList(List<Shader> shadersRes) { foreach (Shader shadersRe in shadersRes) { Debug.LogWarning((object)("SHADER NAME IS: " + ((Object)shadersRe).name)); } debug = false; } public static void Replace(GameObject gameObject) { prefabsToReplaceShader.Add(gameObject); GetMaterialsInPrefab(gameObject); } public static void GetMaterialsInPrefab(GameObject gameObject) { Renderer[] componentsInChildren = gameObject.GetComponentsInChildren<Renderer>(true); Renderer[] array = componentsInChildren; foreach (Renderer val in array) { Material[] sharedMaterials = val.sharedMaterials; if (sharedMaterials == null || sharedMaterials.Length == 0) { continue; } Material[] array2 = sharedMaterials; foreach (Material val2 in array2) { if ((Object)(object)val2 != (Object)null) { materialsInPrefabs.Add(val2); } } } } public static void getMeShaders() { AssetBundle[] array = Resources.FindObjectsOfTypeAll<AssetBundle>(); AssetBundle[] array2 = array; foreach (AssetBundle val in array2) { IEnumerable<Shader> enumerable3; try { IEnumerable<Shader> enumerable2; if (!val.isStreamedSceneAssetBundle || !Object.op_Implicit((Object)(object)val)) { IEnumerable<Shader> enumerable = val.LoadAllAssets<Shader>(); enumerable2 = enumerable; } else { enumerable2 = from shader in ((IEnumerable<string>)val.GetAllAssetNames()).Select((Func<string, Shader>)val.LoadAsset<Shader>) where (Object)(object)shader != (Object)null select shader; } enumerable3 = enumerable2; } catch (Exception) { continue; } if (enumerable3 == null) { continue; } foreach (Shader item in enumerable3) { CachedShaders.Add(item); } } } public static void runMaterialFix() { getMeShaders(); shaders.AddRange(CachedShaders); foreach (Material materialsInPrefab in materialsInPrefabs) { Shader shader = materialsInPrefab.shader; if (!((Object)(object)shader == (Object)null)) { string name = ((Object)shader).name; if (!(name == "Standard") && name.Contains("Balrond")) { setProperValue(materialsInPrefab, name); } } } } private static void setProperValue(Material material, string shaderName) { string name = shaderName.Replace("Balrond", "Custom"); name = checkNaming(name); Shader shaderByName = GetShaderByName(name); if ((Object)(object)shaderByName == (Object)null) { Debug.LogWarning((object)("Shader not found " + name)); } else { material.shader = shaderByName; } } private static string checkNaming(string name) { string result = name; if (name.Contains("Bumped")) { result = name.Replace("Custom", "Lux Lit Particles"); } if (name.Contains("Tess Bumped")) { result = name.Replace("Custom", "Lux Lit Particles"); } if (name.Contains("Standard Surface")) { result = name.Replace("Custom", "Particles"); result = result.Replace("Standard Surface2", "Standard Surface"); } if (name.Contains("Standard Unlit")) { result = name.Replace("Custom", "Particles"); result = result.Replace("Standard Unlit", "Standard Unlit2"); result = result.Replace("Standard Unlit22", "Standard Unlit2"); } return result; } } 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, "BalrondTwinStones-translation/"); defaultPath = text; } public void createDefaultPath() { string configPath = Paths.ConfigPath; string text = Path.Combine(configPath, "BalrondTwinStones-translation/"); if (!Directory.Exists(text)) { CreateFolder(text); } else { Debug.Log((object)("BalrondTwinStones: Folder already exists: " + text)); } defaultPath = text; } private string[] jsonFilePath(string folderName, string extension) { string configPath = Paths.ConfigPath; string text = Path.Combine(configPath, "BalrondTwinStones-translation/"); if (!Directory.Exists(text)) { CreateFolder(text); } else { Debug.Log((object)("BalrondTwinStones: Folder already exists: " + text)); } string[] files = Directory.GetFiles(text, extension); Debug.Log((object)("BalrondTwinStones:" + folderName + " Json Files Found: " + files.Length)); return files; } private static void CreateFolder(string path) { try { Directory.CreateDirectory(path); Debug.Log((object)"BalrondTwinStones: Folder created successfully."); } catch (Exception ex) { Debug.Log((object)("BalrondTwinStones: 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)("BalrondTwinStones: Json Files Language: " + fileNameWithoutExtension)); num++; } else { Debug.LogError((object)("BalrondTwinStones: Loading FAILED file: " + text)); } } Debug.Log((object)("BalrondTwinStones: Translation JsonFiles Loaded: " + num)); } } [BepInPlugin("balrond.astafaraios.BalrondTwinStones", "BalrondTwinStones", "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); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] public static class Object_CopyOtherDB_Path { public static void Postfix() { if (IsObjectDBValid()) { modResourceLoader.setupBuildPiecesListDB(); modResourceLoader.recipes = recipeFactory.createRecipes(ObjectDB.instance.m_items, modResourceLoader.itemPrefabs); databaseAddMethods.AddItems(modResourceLoader.itemPrefabs); databaseAddMethods.AddStatuseffects(modResourceLoader.statusEffects); databaseAddMethods.AddRecipes(modResourceLoader.recipes); } } } [HarmonyPatch(typeof(ObjectDB), "Awake")] public static class ObjectDB_Awake_Path { public static void Postfix() { if (IsObjectDBValid()) { modResourceLoader.setupBuildPiecesListDB(); modResourceLoader.recipes = recipeFactory.createRecipes(ObjectDB.instance.m_items, modResourceLoader.itemPrefabs); databaseAddMethods.AddItems(modResourceLoader.itemPrefabs); databaseAddMethods.AddStatuseffects(modResourceLoader.statusEffects); databaseAddMethods.AddRecipes(modResourceLoader.recipes); ObjectDB.instance.m_recipes.Sort(SortByScore); } } private static int SortByScore(Recipe p1, Recipe p2) { if ((Object)(object)p1.m_item == (Object)null) { return 0; } if ((Object)(object)p2.m_item == (Object)null) { return 1; } return ((Object)p1.m_item).name.CompareTo(((Object)p2.m_item).name); } } [HarmonyPatch(typeof(ZNetScene), "Awake")] public static class ZNetScene_Awake_Path { public static void Prefix(ZNetScene __instance) { if ((Object)(object)__instance == (Object)null) { Debug.LogWarning((object)(projectName + ": No ZnetScene found")); return; } modResourceLoader.AddPrefabsToZnetScene(__instance); if (!hasSpawned) { buildPieceBuilder.SetupBuildPieces(__instance.m_prefabs); hasSpawned = true; if (!((Object)(object)ZNet.instance != (Object)null) || !ZNet.instance.IsDedicated()) { ShaderReplacment.runMaterialFix(); } } } } [HarmonyPatch] public static class PortalPatches { [HarmonyPatch(typeof(Player), "OnDeath")] [HarmonyPrefix] private static void Player_OnDeath_Prefix(Player __instance) { if (!((Object)(object)__instance == (Object)null)) { BalrondPortalPairPiece.ClearPendingForPlayer(__instance, showMessage: true); } } [HarmonyPatch(typeof(Player), "OnDestroy")] [HarmonyPrefix] private static void Player_OnDestroy_Prefix(Player __instance) { if (!((Object)(object)__instance == (Object)null)) { BalrondPortalPairPiece.ClearPendingForPlayer(__instance, showMessage: false); } } } [HarmonyPatch(typeof(SEMan), "RemoveStatusEffect", new Type[] { typeof(int), typeof(bool) })] public static class SEMan_RemoveStatusEffect_PowerJumpToSlowFall { private static readonly int PowerJumpHash = StringExtensionMethods.GetStableHashCode("SE_PowerJump_bal"); private static readonly int SlowFallHash = StringExtensionMethods.GetStableHashCode("SE_PowerJumpSlowFall_bal"); private static void Prefix(SEMan __instance, int nameHash, bool quiet) { try { if (nameHash == PowerJumpHash) { Character character = __instance.m_character; if (!((Object)(object)character == (Object)null) && character.IsPlayer() && character.IsOwner() && !character.IsDead()) { __instance.AddStatusEffect(SlowFallHash, true, 0, 0f, (short)(-1)); } } } catch (Exception ex) { Debug.LogError((object)("[BalrondTwinStones] Failed PowerJump -> SlowFall handoff: " + ex)); } } } private readonly Harmony harmony = new Harmony("balrond.astafaraios.BalrondTwinStones"); public const string PluginGUID = "balrond.astafaraios.BalrondTwinStones"; public const string PluginName = "BalrondTwinStones"; public const string PluginVersion = "1.0.2"; public const string DefaultPortalBuildRecipe = "Stone:10,Thunderstone:2,GreydwarfEye:4,Iron:2"; public static ModResourceLoader modResourceLoader = new ModResourceLoader(); public static DatabaseAddMethods databaseAddMethods = new DatabaseAddMethods(); public static BuildPieceBuilder buildPieceBuilder = new BuildPieceBuilder(); public static string projectName = "BalrondTwinStones"; public static GameObject RootObject; public static GameObject PrefabContainer; public static bool hasSpawned = false; public static JsonLoader jsonLoader = new JsonLoader(); public static RecipeFactory recipeFactory = new RecipeFactory(); public static ConfigEntry<bool> LockConfiguration; public static ConfigEntry<float> MaxLinkDistance; public static ConfigEntry<string> PortalBuildRecipe; public static ConfigEntry<bool> AudioDebugLogging; public static Vector2 sizeDelta; public static bool addedWidth = false; private void Awake() { ServerSyncBridge.Initialize(typeof(ConfigSync).Assembly, "balrond.astafaraios.BalrondTwinStones", "BalrondTwinStones", "1.0.2"); BindConfiguration(); 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 = AudioDebugLogging.Value; AudioDebugLogging.SettingChanged += delegate { AudioRoutingService.DebugLogging = AudioDebugLogging.Value; }; jsonLoader.loadJson(); createPrefabContainer(); modResourceLoader.loadAssets(); RegisterLoadedAudio(); harmony.PatchAll(); } private void BindConfiguration() { LockConfiguration = ((BaseUnityPlugin)this).Config.Bind<bool>("Server", "LockConfiguration", true, "Lock synchronized BalrondTwinStones settings to the server/host values."); ServerSyncBridge.AddLockingConfigEntry(LockConfiguration); MaxLinkDistance = BindSyncedConfig("Portal", "MaxLinkDistance", 50f, "Maximum distance in meters between two Twin Stones when linking them."); PortalBuildRecipe = BindSyncedConfig("Portal", "BuildRecipe", "Stone:10,Thunderstone:2,GreydwarfEye:4,Iron:2", "Build cost for piece_obeliskPortal_bal. Format: PrefabName:Amount,PrefabName:Amount."); PortalBuildRecipe.SettingChanged += delegate { buildPieceBuilder.ApplyPortalRecipeIfReady(); }; AudioDebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "AudioDebugLogging", false, "Enable detailed AudioRoutingService logging. Local client setting; not synchronized."); } private ConfigEntry<T> BindSyncedConfig<T>(string group, string name, T value, string description) { ConfigEntry<T> val = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, description); ServerSyncBridge.AddConfigEntry<T>(val); return val; } public static float GetMaxLinkDistance(float fallback) { return (MaxLinkDistance != null) ? MaxLinkDistance.Value : fallback; } public static string GetPortalBuildRecipe() { return (PortalBuildRecipe != null) ? PortalBuildRecipe.Value : "Stone:10,Thunderstone:2,GreydwarfEye:4,Iron:2"; } private static void RegisterLoadedAudio() { AudioRoutingService.Process((IEnumerable<GameObject>)modResourceLoader.itemPrefabs); AudioRoutingService.Process((IEnumerable<GameObject>)modResourceLoader.buildPrefabs); AudioRoutingService.Process((IEnumerable<GameObject>)modResourceLoader.monsterPrefabs); AudioRoutingService.Process((IEnumerable<GameObject>)modResourceLoader.vfxPrefabs); AudioRoutingService.Process((IEnumerable<GameObject>)modResourceLoader.vegetationPrefabs); AudioRoutingService.Process((IEnumerable<GameObject>)modResourceLoader.plantPrefabs); AudioRoutingService.Process((IEnumerable<GameObject>)modResourceLoader.clutterPrefabs); AudioRoutingService.Process((IEnumerable<GameObject>)modResourceLoader.locationPrefabs); AudioRoutingService.Process((IEnumerable<GameObject>)modResourceLoader.roomPrefabs); } public void createPrefabContainer() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Expected O, but got Unknown //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown RootObject = new GameObject("_ValheimReforgedRoot"); Object.DontDestroyOnLoad((Object)(object)RootObject); PrefabContainer = new GameObject("Prefabs"); PrefabContainer.transform.parent = RootObject.transform; PrefabContainer.SetActive(false); } public static GameObject cloneMe(GameObject source, string name) { GameObject val = Object.Instantiate<GameObject>(source, PrefabContainer.transform); ((Object)val).name = name; fixMaterials(val, source); val.SetActive(true); return val; } public static GameObject fixMaterials(GameObject clone, GameObject source) { MeshRenderer[] componentsInChildren = source.GetComponentsInChildren<MeshRenderer>(); foreach (MeshRenderer val in componentsInChildren) { MeshRenderer[] componentsInChildren2 = clone.GetComponentsInChildren<MeshRenderer>(); foreach (MeshRenderer val2 in componentsInChildren2) { if (((Object)val).name == ((Object)val2).name) { ((Renderer)val2).materials = ((Renderer)val).sharedMaterials; ((Renderer)val2).sharedMaterials = ((Renderer)val).sharedMaterials; break; } } } return clone; } private void OnDestroy() { harmony.UnpatchSelf(); ServerSyncBridge.Reset(); } private static bool IsObjectDBValid() { return (Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.m_items.Count != 0 && ObjectDB.instance.m_recipes.Count != 0 && (Object)(object)ObjectDB.instance.GetItemPrefab("Amber") != (Object)null; } } public static class PortalPendingLinkManager { private static readonly Dictionary<long, string> PendingLinks = new Dictionary<long, string>(); public static bool TryGet(long playerId, out string portalId) { return PendingLinks.TryGetValue(playerId, out portalId); } public static void Set(long playerId, string portalId) { if (string.IsNullOrEmpty(portalId)) { PendingLinks.Remove(playerId); } else { PendingLinks[playerId] = portalId; } } public static bool Has(long playerId) { return PendingLinks.ContainsKey(playerId); } public static void Clear(long playerId) { PendingLinks.Remove(playerId); } public static void ClearByPortalId(string portalId) { if (string.IsNullOrEmpty(portalId)) { return; } List<long> list = new List<long>(); foreach (KeyValuePair<long, string> pendingLink in PendingLinks) { if (pendingLink.Value == portalId) { list.Add(pendingLink.Key); } } for (int i = 0; i < list.Count; i++) { PendingLinks.Remove(list[i]); } } public static void ClearAll() { PendingLinks.Clear(); } } public class BuildPieceBuilder { private List<GameObject> list; private string[] piecesNames = BuildPieceList.buildPieces; private CraftingStation workbench; private CraftingStation tannery; private CraftingStation runeForge; private CraftingStation alchemyLab; private CraftingStation grill; private CraftingStation fletcher; private CraftingStation blackforge; private CraftingStation forge; private CraftingStation cauldron; private CraftingStation stonecutter; public void SetupBuildPieces(List<GameObject> list) { setupTables(list); this.list = list; string[] array = piecesNames; foreach (string name in array) { GameObject val = list.Find((GameObject x) => ((Object)x).name == name); if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)("Cant find buildpiece with name: " + name)); } else { EditBuildPiece(val); } } } private void EditBuildPiece(GameObject gameObject) { //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) Piece component = gameObject.gameObject.GetComponent<Piece>(); component.m_resources = (Requirement[])(object)new Requirement[0]; SetStation(component, workbench); switch (((Object)gameObject).name) { case "railtrackSwitchRight_bal": case "railtrackSwitchLeft_bal": case "railtrack4m_bal": SetStation(component, forge); component.m_resources = (Requirement[])(object)new Requirement[0]; AddResources(component, "IronNails", 8); AddResources(component, "Wood", 8); AddResources(component, "GreydwarfEye", 2); component.m_category = (PieceCategory)0; break; case "railtrackRamp_bal": case "railtrackRamp45_bal": case "railtrack_bal": SetStation(component, forge); component.m_resources = (Requirement[])(object)new Requirement[0]; AddResources(component, "IronNails", 4); AddResources(component, "Wood", 4); AddResources(component, "GreydwarfEye", 2); component.m_category = (PieceCategory)0; break; case "RailPowerWagon_bal": SetStation(component, forge); component.m_resources = (Requirement[])(object)new Requirement[0]; AddResources(component, "CartBundleItemPower_bal", 1); component.m_category = (PieceCategory)0; break; case "RailCargoWagon_bal": SetStation(component, forge); component.m_resources = (Requirement[])(object)new Requirement[0]; AddResources(component, "CartBundleItemCargo_bal", 1); component.m_category = (PieceCategory)0; break; case "piece_obeliskPortal_bal": SetStation(component, stonecutter); ApplyPortalRecipe(component); component.m_category = (PieceCategory)0; break; } } public void ApplyPortalRecipeIfReady() { if (list == null) { return; } GameObject val = list.Find((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == "piece_obeliskPortal_bal"); if (!((Object)(object)val == (Object)null)) { Piece component = val.GetComponent<Piece>(); if ((Object)(object)component == (Object)null) { Debug.LogWarning((object)(Launch.projectName + ": Piece component missing on piece_obeliskPortal_bal")); } else { ApplyPortalRecipe(component); } } } private void ApplyPortalRecipe(Piece piece) { string portalBuildRecipe = Launch.GetPortalBuildRecipe(); if (!TryParsePortalRecipe(portalBuildRecipe, out var requirements)) { Debug.LogWarning((object)(Launch.projectName + ": Invalid Portal.BuildRecipe config. Using default recipe: Stone:10,Thunderstone:2,GreydwarfEye:4,Iron:2")); if (!TryParsePortalRecipe("Stone:10,Thunderstone:2,GreydwarfEye:4,Iron:2", out requirements)) { Debug.LogError((object)(Launch.projectName + ": Default portal recipe could not be resolved. Existing recipe was left unchanged.")); return; } } piece.m_resources = requirements; } private bool TryParsePortalRecipe(string recipe, out Requirement[] requirements) { //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01da: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Expected O, but got Unknown requirements = null; if (string.IsNullOrWhiteSpace(recipe) || this.list == null) { return false; } string[] array = recipe.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0) { return false; } List<Requirement> list = new List<Requirement>(); HashSet<string> hashSet = new HashSet<string>(StringComparer.Ordinal); string[] array2 = array; foreach (string text in array2) { string text2 = text.Trim(); int num = text2.LastIndexOf(':'); if (num <= 0 || num >= text2.Length - 1) { return false; } string itemName = text2.Substring(0, num).Trim(); string s = text2.Substring(num + 1).Trim(); if (itemName.Length == 0 || !int.TryParse(s, out var result) || result <= 0 || !hashSet.Add(itemName)) { return false; } GameObject val = this.list.Find((GameObject x) => (Object)(object)x != (Object)null && ((Object)x).name == itemName); if ((Object)(object)val == (Object)null && (Object)(object)ObjectDB.instance != (Object)null) { val = ObjectDB.instance.GetItemPrefab(itemName); } if ((Object)(object)val == (Object)null) { Debug.LogWarning((object)(Launch.projectName + ": Portal recipe item not found: " + itemName)); return false; } ItemDrop component = val.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null) { Debug.LogWarning((object)(Launch.projectName + ": Portal recipe prefab has no ItemDrop: " + itemName)); return false; } list.Add(new Requirement { m_resItem = component, m_amount = result, m_amountPerLevel = 0, m_recover = true }); } requirements = list.ToArray(); return requirements.Length != 0; } private void setFireplaceFuelItem(Piece piece, string name, int startFuel = -1, int maxFuel = -1, float secPerFuel = -1f) { Fireplace component = ((Component)piece).GetComponent<Fireplace>(); component.m_fuelItem = FindItem(list, name).GetComponent<ItemDrop>(); component.m_startFuel = ((startFuel != -1) ? ((float)startFuel) : component.m_startFuel); component.m_maxFuel = ((maxFuel != -1) ? ((float)maxFuel) : component.m_maxFuel); component.m_secPerFuel = ((secPerFuel != -1f) ? secPerFuel : component.m_secPerFuel); } private void SetStation(Piece piece, CraftingStation station) { piece.m_craftingStation = station; } private void EditResource(Piece piece, string itemName, int amount, bool remove = false) { if (remove) { List<Requirement> list = new List<Requirement>(); Requirement[] resources = piece.m_resources; foreach (Requirement val in resources) { if (((Object)((Component)val.m_resItem).gameObject).name != itemName) { list.Add(val); } } piece