using System; using System.Collections; using System.Collections.Generic; 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.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using Njord.Core; using Njord.HUD; using Njord.Patches; using ServerSync; using TMPro; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ServerSync { [PublicAPI] public abstract class OwnConfigEntryBase { public object? LocalBaseValue; public bool SynchronizedConfig = true; public abstract ConfigEntryBase BaseConfig { get; } } [PublicAPI] public class SyncedConfigEntry(ConfigEntry sourceConfig) : OwnConfigEntryBase() { public readonly ConfigEntry SourceConfig = sourceConfig; public override ConfigEntryBase BaseConfig => (ConfigEntryBase)(object)SourceConfig; public T Value { get { return SourceConfig.Value; } set { SourceConfig.Value = value; } } public void AssignLocalValue(T value) { if (LocalBaseValue == null) { Value = value; } else { LocalBaseValue = value; } } } public abstract class CustomSyncedValueBase { public object? LocalBaseValue; public readonly string Identifier; public readonly Type Type; private object? boxedValue; protected bool localIsOwner; public readonly int Priority; public object? BoxedValue { get { return boxedValue; } set { boxedValue = value; this.ValueChanged?.Invoke(); } } public event Action? ValueChanged; protected CustomSyncedValueBase(ConfigSync configSync, string identifier, Type type, int priority) { Priority = priority; Identifier = identifier; Type = type; configSync.AddCustomValue(this); localIsOwner = configSync.IsSourceOfTruth; configSync.SourceOfTruthChanged += delegate(bool truth) { localIsOwner = truth; }; } } [PublicAPI] public sealed class CustomSyncedValue : CustomSyncedValueBase { public T Value { get { return (T)base.BoxedValue; } set { base.BoxedValue = value; } } public CustomSyncedValue(ConfigSync configSync, string identifier, T value = default(T), int priority = 0) : base(configSync, identifier, typeof(T), priority) { Value = value; } public void AssignLocalValue(T value) { if (localIsOwner) { Value = value; } else { LocalBaseValue = value; } } } internal class ConfigurationManagerAttributes { [UsedImplicitly] public bool? ReadOnly = false; } [PublicAPI] public class ConfigSync { [HarmonyPatch(typeof(ZRpc), "HandlePackage")] private static class SnatchCurrentlyHandlingRPC { public static ZRpc? currentRpc; [HarmonyPrefix] private static void Prefix(ZRpc __instance) { currentRpc = __instance; } } [HarmonyPatch(typeof(ZNet), "Awake")] internal static class RegisterRPCPatch { [HarmonyPostfix] private static void Postfix(ZNet __instance) { isServer = __instance.IsServer(); foreach (ConfigSync configSync2 in configSyncs) { ZRoutedRpc.instance.Register(configSync2.Name + " ConfigSync", (Action)configSync2.RPC_FromOtherClientConfigSync); if (isServer) { configSync2.InitialSyncDone = true; Debug.Log((object)("Registered '" + configSync2.Name + " ConfigSync' RPC - waiting for incoming connections")); } } if (isServer) { ((MonoBehaviour)__instance).StartCoroutine(WatchAdminListChanges()); } static void SendAdmin(List peers, bool isAdmin) { ZPackage package = ConfigsToPackage(null, null, new PackageEntry[1] { new PackageEntry { section = "Internal", key = "lockexempt", type = typeof(bool), value = isAdmin } }); ConfigSync configSync = configSyncs.First(); if (configSync != null) { ((MonoBehaviour)ZNet.instance).StartCoroutine(configSync.sendZPackage(peers, package)); } } static IEnumerator WatchAdminListChanges() { MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); List CurrentList = new List(adminList.GetList()); while (true) { yield return (object)new WaitForSeconds(30f); if (!adminList.GetList().SequenceEqual(CurrentList)) { CurrentList = new List(adminList.GetList()); List list = ZNet.instance.GetPeers().Where(delegate(ZNetPeer p) { string hostName = p.m_rpc.GetSocket().GetHostName(); return ((object)listContainsId != null) ? ((bool)listContainsId.Invoke(ZNet.instance, new object[2] { adminList, hostName })) : adminList.Contains(hostName); }).ToList(); SendAdmin(ZNet.instance.GetPeers().Except(list).ToList(), isAdmin: false); SendAdmin(list, isAdmin: true); } } } } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] private static class RegisterClientRPCPatch { [HarmonyPostfix] private static void Postfix(ZNet __instance, ZNetPeer peer) { if (__instance.IsServer()) { return; } foreach (ConfigSync configSync in configSyncs) { peer.m_rpc.Register(configSync.Name + " ConfigSync", (Action)configSync.RPC_FromServerConfigSync); } } } private class ParsedConfigs { public readonly Dictionary configValues = new Dictionary(); public readonly Dictionary customValues = new Dictionary(); } [HarmonyPatch(typeof(ZNet), "Shutdown")] private class ResetConfigsOnShutdown { [HarmonyPostfix] private static void Postfix() { ProcessingServerUpdate = true; foreach (ConfigSync configSync in configSyncs) { configSync.resetConfigsFromServer(); configSync.IsSourceOfTruth = true; configSync.InitialSyncDone = false; } ProcessingServerUpdate = false; } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] private class SendConfigsAfterLogin { private class BufferingSocket : ZPlayFabSocket, ISocket { public volatile bool finished; public volatile int versionMatchQueued = -1; public readonly List Package = new List(); public readonly ISocket Original; public BufferingSocket(ISocket original) { Original = original; ((ZPlayFabSocket)this)..ctor(); } public bool IsConnected() { return Original.IsConnected(); } public ZPackage Recv() { return Original.Recv(); } public int GetSendQueueSize() { return Original.GetSendQueueSize(); } public int GetCurrentSendRate() { return Original.GetCurrentSendRate(); } public bool IsHost() { return Original.IsHost(); } public void Dispose() { Original.Dispose(); } public bool GotNewData() { return Original.GotNewData(); } public void Close() { Original.Close(); } public string GetEndPointString() { return Original.GetEndPointString(); } public void GetAndResetStats(out int totalSent, out int totalRecv) { Original.GetAndResetStats(ref totalSent, ref totalRecv); } public void GetConnectionQuality(out float localQuality, out float remoteQuality, out int ping, out float outByteSec, out float inByteSec) { Original.GetConnectionQuality(ref localQuality, ref remoteQuality, ref ping, ref outByteSec, ref inByteSec); } public ISocket Accept() { return Original.Accept(); } public int GetHostPort() { return Original.GetHostPort(); } public bool Flush() { return Original.Flush(); } public string GetHostName() { return Original.GetHostName(); } public void VersionMatch() { if (finished) { Original.VersionMatch(); } else { versionMatchQueued = Package.Count; } } public void Send(ZPackage pkg) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown int pos = pkg.GetPos(); pkg.SetPos(0); int num = pkg.ReadInt(); if ((num == StringExtensionMethods.GetStableHashCode("PeerInfo") || num == StringExtensionMethods.GetStableHashCode("RoutedRPC") || num == StringExtensionMethods.GetStableHashCode("ZDOData")) && !finished) { ZPackage val = new ZPackage(pkg.GetArray()); val.SetPos(pos); Package.Add(val); } else { pkg.SetPos(pos); Original.Send(pkg); } } } [HarmonyPriority(800)] [HarmonyPrefix] private static void Prefix(ref Dictionary? __state, ZNet __instance, ZRpc rpc) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) if (!__instance.IsServer()) { return; } BufferingSocket bufferingSocket = new BufferingSocket(rpc.GetSocket()); AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, bufferingSocket); object? obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc }); ZNetPeer val = (ZNetPeer)((obj is ZNetPeer) ? obj : null); if (val != null && (int)ZNet.m_onlineBackend != 0) { FieldInfo fieldInfo = AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket"); object? value = fieldInfo.GetValue(val); ZPlayFabSocket val2 = (ZPlayFabSocket)((value is ZPlayFabSocket) ? value : null); if (val2 != null) { typeof(ZPlayFabSocket).GetField("m_remotePlayerId").SetValue(bufferingSocket, val2.m_remotePlayerId); } fieldInfo.SetValue(val, bufferingSocket); } if (__state == null) { __state = new Dictionary(); } __state[Assembly.GetExecutingAssembly()] = bufferingSocket; } [HarmonyPostfix] private static void Postfix(Dictionary __state, ZNet __instance, ZRpc rpc) { ZNetPeer peer; if (__instance.IsServer()) { object obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc }); peer = (ZNetPeer)((obj is ZNetPeer) ? obj : null); if (peer == null) { SendBufferedData(); } else { ((MonoBehaviour)__instance).StartCoroutine(sendAsync()); } } void SendBufferedData() { if (rpc.GetSocket() is BufferingSocket bufferingSocket) { AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, bufferingSocket.Original); object? obj2 = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc }); ZNetPeer val = (ZNetPeer)((obj2 is ZNetPeer) ? obj2 : null); if (val != null) { AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, bufferingSocket.Original); } } BufferingSocket bufferingSocket2 = __state[Assembly.GetExecutingAssembly()]; bufferingSocket2.finished = true; for (int i = 0; i < bufferingSocket2.Package.Count; i++) { if (i == bufferingSocket2.versionMatchQueued) { bufferingSocket2.Original.VersionMatch(); } bufferingSocket2.Original.Send(bufferingSocket2.Package[i]); } if (bufferingSocket2.Package.Count == bufferingSocket2.versionMatchQueued) { bufferingSocket2.Original.VersionMatch(); } } IEnumerator sendAsync() { foreach (ConfigSync configSync in configSyncs) { List list = new List(); if (configSync.CurrentVersion != null) { list.Add(new PackageEntry { section = "Internal", key = "serverversion", type = typeof(string), value = configSync.CurrentVersion }); } MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList val = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); list.Add(new PackageEntry { section = "Internal", key = "lockexempt", type = typeof(bool), value = (((object)methodInfo == null) ? ((object)val.Contains(rpc.GetSocket().GetHostName())) : methodInfo.Invoke(ZNet.instance, new object[2] { val, rpc.GetSocket().GetHostName() })) }); ZPackage package = ConfigsToPackage(configSync.allConfigs.Select((OwnConfigEntryBase c) => c.BaseConfig), configSync.allCustomValues, list, partial: false); yield return ((MonoBehaviour)__instance).StartCoroutine(configSync.sendZPackage(new List { peer }, package)); } SendBufferedData(); } } } private class PackageEntry { public string section; public string key; public Type type; public object? value; } [HarmonyPatch(typeof(ConfigEntryBase), "GetSerializedValue")] private static class PreventSavingServerInfo { [HarmonyPrefix] private static bool Prefix(ConfigEntryBase __instance, ref string __result) { OwnConfigEntryBase ownConfigEntryBase = configData(__instance); if (ownConfigEntryBase == null || isWritableConfig(ownConfigEntryBase)) { return true; } __result = TomlTypeConverter.ConvertToString(ownConfigEntryBase.LocalBaseValue, __instance.SettingType); return false; } } [HarmonyPatch(typeof(ConfigEntryBase), "SetSerializedValue")] private static class PreventConfigRereadChangingValues { [HarmonyPrefix] private static bool Prefix(ConfigEntryBase __instance, string value) { OwnConfigEntryBase ownConfigEntryBase = configData(__instance); if (ownConfigEntryBase == null || ownConfigEntryBase.LocalBaseValue == null) { return true; } try { ownConfigEntryBase.LocalBaseValue = TomlTypeConverter.ConvertToValue(value, __instance.SettingType); } catch (Exception ex) { Debug.LogWarning((object)$"Config value of setting \"{__instance.Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}; Value: {value}"); } return false; } } private class InvalidDeserializationTypeException : Exception { public string expected; public string received; public string field = ""; } public static bool ProcessingServerUpdate; public readonly string Name; public string? DisplayName; public string? CurrentVersion; public string? MinimumRequiredVersion; public bool ModRequired; private bool? forceConfigLocking; private bool isSourceOfTruth = true; private static readonly HashSet configSyncs; private readonly HashSet allConfigs = new HashSet(); private HashSet allCustomValues = new HashSet(); private static bool isServer; private static bool lockExempt; private OwnConfigEntryBase? lockedConfig; private const byte PARTIAL_CONFIGS = 1; private const byte FRAGMENTED_CONFIG = 2; private const byte COMPRESSED_CONFIG = 4; private readonly Dictionary> configValueCache = new Dictionary>(); private readonly List> cacheExpirations = new List>(); private static long packageCounter; public bool IsLocked { get { bool? flag = forceConfigLocking; bool num; if (!flag.HasValue) { if (lockedConfig == null) { goto IL_0051; } num = ((IConvertible)lockedConfig.BaseConfig.BoxedValue).ToInt32(CultureInfo.InvariantCulture) != 0; } else { num = flag == true; } if (num) { return !lockExempt; } goto IL_0051; IL_0051: return false; } set { forceConfigLocking = value; } } public bool IsAdmin { get { if (!lockExempt) { return isSourceOfTruth; } return true; } } public bool IsSourceOfTruth { get { return isSourceOfTruth; } private set { if (value != isSourceOfTruth) { isSourceOfTruth = value; this.SourceOfTruthChanged?.Invoke(value); } } } public bool InitialSyncDone { get; private set; } public event Action? SourceOfTruthChanged; private event Action? lockedConfigChanged; static ConfigSync() { ProcessingServerUpdate = false; configSyncs = new HashSet(); lockExempt = false; packageCounter = 0L; RuntimeHelpers.RunClassConstructor(typeof(VersionCheck).TypeHandle); } public ConfigSync(string name) { Name = name; configSyncs.Add(this); new VersionCheck(this); } public SyncedConfigEntry AddConfigEntry(ConfigEntry configEntry) { OwnConfigEntryBase ownConfigEntryBase = configData((ConfigEntryBase)(object)configEntry); SyncedConfigEntry syncedEntry = ownConfigEntryBase as SyncedConfigEntry; if (syncedEntry == null) { syncedEntry = new SyncedConfigEntry(configEntry); AccessTools.DeclaredField(typeof(ConfigDescription), "k__BackingField").SetValue(((ConfigEntryBase)configEntry).Description, new object[1] { new ConfigurationManagerAttributes() }.Concat(((ConfigEntryBase)configEntry).Description.Tags ?? Array.Empty()).Concat(new SyncedConfigEntry[1] { syncedEntry }).ToArray()); configEntry.SettingChanged += delegate { if (!ProcessingServerUpdate && syncedEntry.SynchronizedConfig) { Broadcast(ZRoutedRpc.Everybody, (ConfigEntryBase)configEntry); } }; allConfigs.Add(syncedEntry); } return syncedEntry; } public SyncedConfigEntry AddLockingConfigEntry(ConfigEntry lockingConfig) where T : IConvertible { if (lockedConfig != null) { throw new Exception("Cannot initialize locking ConfigEntry twice"); } lockedConfig = AddConfigEntry(lockingConfig); lockingConfig.SettingChanged += delegate { this.lockedConfigChanged?.Invoke(); }; return (SyncedConfigEntry)lockedConfig; } internal void AddCustomValue(CustomSyncedValueBase customValue) { if (allCustomValues.Select((CustomSyncedValueBase v) => v.Identifier).Concat(new string[1] { "serverversion" }).Contains(customValue.Identifier)) { throw new Exception("Cannot have multiple settings with the same name or with a reserved name (serverversion)"); } allCustomValues.Add(customValue); allCustomValues = new HashSet(allCustomValues.OrderByDescending((CustomSyncedValueBase v) => v.Priority)); customValue.ValueChanged += delegate { if (!ProcessingServerUpdate) { Broadcast(ZRoutedRpc.Everybody, customValue); } }; } private void RPC_FromServerConfigSync(ZRpc rpc, ZPackage package) { lockedConfigChanged += serverLockedSettingChanged; IsSourceOfTruth = false; if (HandleConfigSyncRPC(0L, package, clientUpdate: false)) { InitialSyncDone = true; } } private void RPC_FromOtherClientConfigSync(long sender, ZPackage package) { HandleConfigSyncRPC(sender, package, clientUpdate: true); } private bool HandleConfigSyncRPC(long sender, ZPackage package, bool clientUpdate) { //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Expected O, but got Unknown //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown try { if (isServer && IsLocked) { ZRpc? currentRpc = SnatchCurrentlyHandlingRPC.currentRpc; object obj; if (currentRpc == null) { obj = null; } else { ISocket socket = currentRpc.GetSocket(); obj = ((socket != null) ? socket.GetHostName() : null); } string text = (string)obj; if (text != null) { MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList val = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); if (!(((object)methodInfo == null) ? val.Contains(text) : ((bool)methodInfo.Invoke(ZNet.instance, new object[2] { val, text })))) { return false; } } } cacheExpirations.RemoveAll(delegate(KeyValuePair kv) { if (kv.Key < DateTimeOffset.Now.Ticks) { configValueCache.Remove(kv.Value); return true; } return false; }); byte b = package.ReadByte(); if ((b & 2) != 0) { long num = package.ReadLong(); string text2 = sender.ToString() + num; if (!configValueCache.TryGetValue(text2, out var value)) { value = new SortedDictionary(); configValueCache[text2] = value; cacheExpirations.Add(new KeyValuePair(DateTimeOffset.Now.AddSeconds(60.0).Ticks, text2)); } int key = package.ReadInt(); int num2 = package.ReadInt(); value.Add(key, package.ReadByteArray()); if (value.Count < num2) { return false; } configValueCache.Remove(text2); package = new ZPackage(value.Values.SelectMany((byte[] a) => a).ToArray()); b = package.ReadByte(); } ProcessingServerUpdate = true; if ((b & 4) != 0) { MemoryStream stream = new MemoryStream(package.ReadByteArray()); MemoryStream memoryStream = new MemoryStream(); using (DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress)) { deflateStream.CopyTo(memoryStream); } package = new ZPackage(memoryStream.ToArray()); b = package.ReadByte(); } if ((b & 1) == 0) { resetConfigsFromServer(); } ParsedConfigs parsedConfigs = ReadConfigsFromPackage(package); ConfigFile val2 = null; bool saveOnConfigSet = false; foreach (KeyValuePair configValue in parsedConfigs.configValues) { if (!isServer && configValue.Key.LocalBaseValue == null) { configValue.Key.LocalBaseValue = configValue.Key.BaseConfig.BoxedValue; } if (val2 == null) { val2 = configValue.Key.BaseConfig.ConfigFile; saveOnConfigSet = val2.SaveOnConfigSet; val2.SaveOnConfigSet = false; } configValue.Key.BaseConfig.BoxedValue = configValue.Value; } if (val2 != null) { val2.SaveOnConfigSet = saveOnConfigSet; val2.Save(); } foreach (KeyValuePair customValue in parsedConfigs.customValues) { if (!isServer) { CustomSyncedValueBase key2 = customValue.Key; if (key2.LocalBaseValue == null) { key2.LocalBaseValue = customValue.Key.BoxedValue; } } customValue.Key.BoxedValue = customValue.Value; } Debug.Log((object)string.Format("Received {0} configs and {1} custom values from {2} for mod {3}", parsedConfigs.configValues.Count, parsedConfigs.customValues.Count, (isServer || clientUpdate) ? $"client {sender}" : "the server", DisplayName ?? Name)); if (!isServer) { serverLockedSettingChanged(); } return true; } finally { ProcessingServerUpdate = false; } } private ParsedConfigs ReadConfigsFromPackage(ZPackage package) { ParsedConfigs parsedConfigs = new ParsedConfigs(); Dictionary dictionary = allConfigs.Where((OwnConfigEntryBase c) => c.SynchronizedConfig).ToDictionary((OwnConfigEntryBase c) => c.BaseConfig.Definition.Section + "_" + c.BaseConfig.Definition.Key, (OwnConfigEntryBase c) => c); Dictionary dictionary2 = allCustomValues.ToDictionary((CustomSyncedValueBase c) => c.Identifier, (CustomSyncedValueBase c) => c); int num = package.ReadInt(); for (int num2 = 0; num2 < num; num2++) { string text = package.ReadString(); string text2 = package.ReadString(); string text3 = package.ReadString(); Type type = Type.GetType(text3); if (text3 == "" || type != null) { object obj; try { obj = ((text3 == "") ? null : ReadValueWithTypeFromZPackage(package, type)); } catch (InvalidDeserializationTypeException ex) { Debug.LogWarning((object)("Got unexpected struct internal type " + ex.received + " for field " + ex.field + " struct " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + ex.expected)); continue; } OwnConfigEntryBase value2; if (text == "Internal") { CustomSyncedValueBase value; if (text2 == "serverversion") { if (obj?.ToString() != CurrentVersion) { Debug.LogWarning((object)("Received server version is not equal: server version = " + (obj?.ToString() ?? "null") + "; local version = " + (CurrentVersion ?? "unknown"))); } } else if (text2 == "lockexempt") { if (obj is bool flag) { lockExempt = flag; } } else if (dictionary2.TryGetValue(text2, out value)) { if ((text3 == "" && (!value.Type.IsValueType || Nullable.GetUnderlyingType(value.Type) != null)) || GetZPackageTypeString(value.Type) == text3) { parsedConfigs.customValues[value] = obj; continue; } Debug.LogWarning((object)("Got unexpected type " + text3 + " for internal value " + text2 + " for mod " + (DisplayName ?? Name) + ", expecting " + value.Type.AssemblyQualifiedName)); } } else if (dictionary.TryGetValue(text + "_" + text2, out value2)) { Type type2 = configType(value2.BaseConfig); if ((text3 == "" && (!type2.IsValueType || Nullable.GetUnderlyingType(type2) != null)) || GetZPackageTypeString(type2) == text3) { parsedConfigs.configValues[value2] = obj; continue; } Debug.LogWarning((object)("Got unexpected type " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + type2.AssemblyQualifiedName)); } else { Debug.LogWarning((object)("Received unknown config entry " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ". This may happen if client and server versions of the mod do not match.")); } continue; } Debug.LogWarning((object)("Got invalid type " + text3 + ", abort reading of received configs")); return new ParsedConfigs(); } return parsedConfigs; } private static bool isWritableConfig(OwnConfigEntryBase config) { ConfigSync configSync = configSyncs.FirstOrDefault((ConfigSync cs) => cs.allConfigs.Contains(config)); if (configSync == null) { return true; } if (!configSync.IsSourceOfTruth && config.SynchronizedConfig && config.LocalBaseValue != null) { if (!configSync.IsLocked) { if (config == configSync.lockedConfig) { return lockExempt; } return true; } return false; } return true; } private void serverLockedSettingChanged() { foreach (OwnConfigEntryBase allConfig in allConfigs) { configAttribute(allConfig.BaseConfig).ReadOnly = !isWritableConfig(allConfig); } } private void resetConfigsFromServer() { ConfigFile val = null; bool saveOnConfigSet = false; foreach (OwnConfigEntryBase item in allConfigs.Where((OwnConfigEntryBase config) => config.LocalBaseValue != null)) { if (val == null) { val = item.BaseConfig.ConfigFile; saveOnConfigSet = val.SaveOnConfigSet; val.SaveOnConfigSet = false; } item.BaseConfig.BoxedValue = item.LocalBaseValue; item.LocalBaseValue = null; } if (val != null) { val.SaveOnConfigSet = saveOnConfigSet; } foreach (CustomSyncedValueBase item2 in allCustomValues.Where((CustomSyncedValueBase config) => config.LocalBaseValue != null)) { item2.BoxedValue = item2.LocalBaseValue; item2.LocalBaseValue = null; } lockedConfigChanged -= serverLockedSettingChanged; serverLockedSettingChanged(); } private IEnumerator distributeConfigToPeers(ZNetPeer peer, ZPackage package) { ZRoutedRpc rpc = ZRoutedRpc.instance; if (rpc == null) { yield break; } byte[] data = package.GetArray(); if (data != null && data.LongLength > 250000) { int fragments = (int)(1 + (data.LongLength - 1) / 250000); long packageIdentifier = ++packageCounter; int fragment = 0; while (fragment < fragments) { foreach (bool item in waitForQueue()) { yield return item; } if (peer.m_socket.IsConnected()) { ZPackage val = new ZPackage(); val.Write((byte)2); val.Write(packageIdentifier); val.Write(fragment); val.Write(fragments); val.Write(data.Skip(250000 * fragment).Take(250000).ToArray()); SendPackage(val); if (fragment != fragments - 1) { yield return true; } int num = fragment + 1; fragment = num; continue; } break; } yield break; } foreach (bool item2 in waitForQueue()) { yield return item2; } SendPackage(package); void SendPackage(ZPackage pkg) { string text = Name + " ConfigSync"; if (isServer) { peer.m_rpc.Invoke(text, new object[1] { pkg }); } else { rpc.InvokeRoutedRPC(peer.m_server ? 0 : peer.m_uid, text, new object[1] { pkg }); } } IEnumerable waitForQueue() { float timeout = Time.time + 30f; while (peer.m_socket.GetSendQueueSize() > 20000) { if (Time.time > timeout) { Debug.Log((object)$"Disconnecting {peer.m_uid} after 30 seconds config sending timeout"); peer.m_rpc.Invoke("Error", new object[1] { (object)(ConnectionStatus)5 }); ZNet.instance.Disconnect(peer); break; } yield return false; } } } private IEnumerator sendZPackage(long target, ZPackage package) { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return Enumerable.Empty().GetEnumerator(); } List list = (List)AccessTools.DeclaredField(typeof(ZRoutedRpc), "m_peers").GetValue(ZRoutedRpc.instance); if (target != ZRoutedRpc.Everybody) { list = list.Where((ZNetPeer p) => p.m_uid == target).ToList(); } return sendZPackage(list, package); } private IEnumerator sendZPackage(List peers, ZPackage package) { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { yield break; } byte[] array = package.GetArray(); if (array != null && array.LongLength > 10000) { ZPackage val = new ZPackage(); val.Write((byte)4); MemoryStream memoryStream = new MemoryStream(); using (DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionLevel.Optimal)) { deflateStream.Write(array, 0, array.Length); } val.Write(memoryStream.ToArray()); package = val; } List> writers = (from p in peers where p.IsReady() select distributeConfigToPeers(p, package)).ToList(); writers.RemoveAll((IEnumerator writer) => !writer.MoveNext()); while (writers.Count > 0) { yield return null; writers.RemoveAll((IEnumerator writer) => !writer.MoveNext()); } } private void Broadcast(long target, params ConfigEntryBase[] configs) { if (!IsLocked || isServer) { ZPackage package = ConfigsToPackage(configs); ZNet instance = ZNet.instance; if (instance != null) { ((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package)); } } } private void Broadcast(long target, params CustomSyncedValueBase[] customValues) { if (!IsLocked || isServer) { ZPackage package = ConfigsToPackage(null, customValues); ZNet instance = ZNet.instance; if (instance != null) { ((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package)); } } } private static OwnConfigEntryBase? configData(ConfigEntryBase config) { return config.Description.Tags?.OfType().SingleOrDefault(); } public static SyncedConfigEntry? ConfigData(ConfigEntry config) { return ((ConfigEntryBase)config).Description.Tags?.OfType>().SingleOrDefault(); } private static T configAttribute(ConfigEntryBase config) { return config.Description.Tags.OfType().First(); } private static Type configType(ConfigEntryBase config) { return configType(config.SettingType); } private static Type configType(Type type) { if (!type.IsEnum) { return type; } return Enum.GetUnderlyingType(type); } private static ZPackage ConfigsToPackage(IEnumerable? configs = null, IEnumerable? customValues = null, IEnumerable? packageEntries = null, bool partial = true) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown List list = configs?.Where((ConfigEntryBase config) => configData(config).SynchronizedConfig).ToList() ?? new List(); List list2 = customValues?.ToList() ?? new List(); ZPackage val = new ZPackage(); val.Write(partial ? ((byte)1) : ((byte)0)); val.Write(list.Count + list2.Count + (packageEntries?.Count() ?? 0)); foreach (PackageEntry item in packageEntries ?? Array.Empty()) { AddEntryToPackage(val, item); } foreach (CustomSyncedValueBase item2 in list2) { AddEntryToPackage(val, new PackageEntry { section = "Internal", key = item2.Identifier, type = item2.Type, value = item2.BoxedValue }); } foreach (ConfigEntryBase item3 in list) { AddEntryToPackage(val, new PackageEntry { section = item3.Definition.Section, key = item3.Definition.Key, type = configType(item3), value = item3.BoxedValue }); } return val; } private static void AddEntryToPackage(ZPackage package, PackageEntry entry) { package.Write(entry.section); package.Write(entry.key); package.Write((entry.value == null) ? "" : GetZPackageTypeString(entry.type)); AddValueToZPackage(package, entry.value); } private static string GetZPackageTypeString(Type type) { return type.AssemblyQualifiedName; } private static void AddValueToZPackage(ZPackage package, object? value) { Type type = value?.GetType(); if (value is Enum) { value = ((IConvertible)value).ToType(Enum.GetUnderlyingType(value.GetType()), CultureInfo.InvariantCulture); } else { if (value is ICollection collection) { package.Write(collection.Count); { foreach (object item in collection) { AddValueToZPackage(package, item); } return; } } if ((object)type != null && type.IsValueType && !type.IsPrimitive) { FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); package.Write(fields.Length); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { package.Write(GetZPackageTypeString(fieldInfo.FieldType)); AddValueToZPackage(package, fieldInfo.GetValue(value)); } return; } } ZRpc.Serialize(new object[1] { value }, ref package); } private static object ReadValueWithTypeFromZPackage(ZPackage package, Type type) { if ((object)type != null && type.IsValueType && !type.IsPrimitive && !type.IsEnum) { FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); int num = package.ReadInt(); if (num != fields.Length) { throw new InvalidDeserializationTypeException { received = $"(field count: {num})", expected = $"(field count: {fields.Length})" }; } object uninitializedObject = FormatterServices.GetUninitializedObject(type); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { string text = package.ReadString(); if (text != GetZPackageTypeString(fieldInfo.FieldType)) { throw new InvalidDeserializationTypeException { received = text, expected = GetZPackageTypeString(fieldInfo.FieldType), field = fieldInfo.Name }; } fieldInfo.SetValue(uninitializedObject, ReadValueWithTypeFromZPackage(package, fieldInfo.FieldType)); } return uninitializedObject; } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<, >)) { int num2 = package.ReadInt(); IDictionary dictionary = (IDictionary)Activator.CreateInstance(type); Type type2 = typeof(KeyValuePair<, >).MakeGenericType(type.GenericTypeArguments); FieldInfo field = type2.GetField("key", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo field2 = type2.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic); for (int j = 0; j < num2; j++) { object obj = ReadValueWithTypeFromZPackage(package, type2); dictionary.Add(field.GetValue(obj), field2.GetValue(obj)); } return dictionary; } if (type != typeof(List) && type.IsGenericType) { Type type3 = typeof(ICollection<>).MakeGenericType(type.GenericTypeArguments[0]); if ((object)type3 != null && type3.IsAssignableFrom(type)) { int num3 = package.ReadInt(); object obj2 = Activator.CreateInstance(type); MethodInfo method = type3.GetMethod("Add"); for (int k = 0; k < num3; k++) { method.Invoke(obj2, new object[1] { ReadValueWithTypeFromZPackage(package, type.GenericTypeArguments[0]) }); } return obj2; } } ParameterInfo parameterInfo = (ParameterInfo)FormatterServices.GetUninitializedObject(typeof(ParameterInfo)); AccessTools.DeclaredField(typeof(ParameterInfo), "ClassImpl").SetValue(parameterInfo, type); List source = new List(); ZRpc.Deserialize(new ParameterInfo[2] { null, parameterInfo }, package, ref source); return source.First(); } } [PublicAPI] [HarmonyPatch] public class VersionCheck { private static readonly HashSet versionChecks; private static readonly Dictionary notProcessedNames; public string Name; private string? displayName; private string? currentVersion; private string? minimumRequiredVersion; public bool ModRequired = true; private string? ReceivedCurrentVersion; private string? ReceivedMinimumRequiredVersion; private readonly List ValidatedClients = new List(); private ConfigSync? ConfigSync; public string DisplayName { get { return displayName ?? Name; } set { displayName = value; } } public string CurrentVersion { get { return currentVersion ?? "0.0.0"; } set { currentVersion = value; } } public string MinimumRequiredVersion { get { string text = minimumRequiredVersion; if (text == null) { if (!ModRequired) { return "0.0.0"; } text = CurrentVersion; } return text; } set { minimumRequiredVersion = value; } } private static void PatchServerSync() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown Patches patchInfo = PatchProcessor.GetPatchInfo((MethodBase)AccessTools.DeclaredMethod(typeof(ZNet), "Awake", (Type[])null, (Type[])null)); if (patchInfo != null && patchInfo.Postfixes.Count((Patch p) => p.PatchMethod.DeclaringType == typeof(ConfigSync.RegisterRPCPatch)) > 0) { return; } Harmony val = new Harmony("org.bepinex.helpers.ServerSync"); foreach (Type item in from t in typeof(ConfigSync).GetNestedTypes(BindingFlags.NonPublic).Concat(new Type[1] { typeof(VersionCheck) }) where t.IsClass select t) { val.PatchAll(item); } } static VersionCheck() { versionChecks = new HashSet(); notProcessedNames = new Dictionary(); typeof(ThreadingHelper).GetMethod("StartSyncInvoke").Invoke(ThreadingHelper.Instance, new object[1] { new Action(PatchServerSync) }); } public VersionCheck(string name) { Name = name; ModRequired = true; versionChecks.Add(this); } public VersionCheck(ConfigSync configSync) { ConfigSync = configSync; Name = ConfigSync.Name; versionChecks.Add(this); } public void Initialize() { ReceivedCurrentVersion = null; ReceivedMinimumRequiredVersion = null; if (ConfigSync != null) { Name = ConfigSync.Name; DisplayName = ConfigSync.DisplayName; CurrentVersion = ConfigSync.CurrentVersion; MinimumRequiredVersion = ConfigSync.MinimumRequiredVersion; ModRequired = ConfigSync.ModRequired; } } private bool IsVersionOk() { if (ReceivedMinimumRequiredVersion == null || ReceivedCurrentVersion == null) { return !ModRequired; } bool num = new Version(CurrentVersion) >= new Version(ReceivedMinimumRequiredVersion); bool flag = new Version(ReceivedCurrentVersion) >= new Version(MinimumRequiredVersion); return num && flag; } private string ErrorClient() { if (ReceivedMinimumRequiredVersion == null) { return DisplayName + " is not installed on the server."; } if (!(new Version(CurrentVersion) >= new Version(ReceivedMinimumRequiredVersion))) { return DisplayName + " needs to be at least version " + ReceivedMinimumRequiredVersion + ". You have version " + CurrentVersion + "."; } return DisplayName + " may not be higher than version " + ReceivedCurrentVersion + ". You have version " + CurrentVersion + "."; } private string ErrorServer(ZRpc rpc) { return "Disconnect: The client (" + rpc.GetSocket().GetHostName() + ") doesn't have the correct " + DisplayName + " version " + MinimumRequiredVersion; } private string Error(ZRpc? rpc = null) { if (rpc != null) { return ErrorServer(rpc); } return ErrorClient(); } private static VersionCheck[] GetFailedClient() { return versionChecks.Where((VersionCheck check) => !check.IsVersionOk()).ToArray(); } private static VersionCheck[] GetFailedServer(ZRpc rpc) { return versionChecks.Where((VersionCheck check) => check.ModRequired && !check.ValidatedClients.Contains(rpc)).ToArray(); } private static void Logout() { Game.instance.Logout(true, true); AccessTools.DeclaredField(typeof(ZNet), "m_connectionStatus").SetValue(null, (object)(ConnectionStatus)3); } private static void DisconnectClient(ZRpc rpc) { rpc.Invoke("Error", new object[1] { 3 }); } private static void CheckVersion(ZRpc rpc, ZPackage pkg) { CheckVersion(rpc, pkg, null); } private static void CheckVersion(ZRpc rpc, ZPackage pkg, Action? original) { string text = pkg.ReadString(); string text2 = pkg.ReadString(); string text3 = pkg.ReadString(); bool flag = false; foreach (VersionCheck versionCheck in versionChecks) { if (!(text != versionCheck.Name)) { Debug.Log((object)("Received " + versionCheck.DisplayName + " version " + text3 + " and minimum version " + text2 + " from the " + (ZNet.instance.IsServer() ? "client" : "server") + ".")); versionCheck.ReceivedMinimumRequiredVersion = text2; versionCheck.ReceivedCurrentVersion = text3; if (ZNet.instance.IsServer() && versionCheck.IsVersionOk()) { versionCheck.ValidatedClients.Add(rpc); } flag = true; } } if (flag) { return; } pkg.SetPos(0); if (original != null) { original(rpc, pkg); if (pkg.GetPos() == 0) { notProcessedNames.Add(text, text3); } } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] [HarmonyPrefix] private static bool RPC_PeerInfo(ZRpc rpc, ZNet __instance) { VersionCheck[] array = (__instance.IsServer() ? GetFailedServer(rpc) : GetFailedClient()); if (array.Length == 0) { return true; } VersionCheck[] array2 = array; for (int i = 0; i < array2.Length; i++) { Debug.LogWarning((object)array2[i].Error(rpc)); } if (__instance.IsServer()) { DisconnectClient(rpc); } else { Logout(); } return false; } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] [HarmonyPrefix] private static void RegisterAndCheckVersion(ZNetPeer peer, ZNet __instance) { //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Expected O, but got Unknown notProcessedNames.Clear(); IDictionary dictionary = (IDictionary)typeof(ZRpc).GetField("m_functions", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(peer.m_rpc); if (dictionary.Contains(StringExtensionMethods.GetStableHashCode("ServerSync VersionCheck"))) { object obj = dictionary[StringExtensionMethods.GetStableHashCode("ServerSync VersionCheck")]; Action action = (Action)obj.GetType().GetField("m_action", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(obj); peer.m_rpc.Register("ServerSync VersionCheck", (Action)delegate(ZRpc rpc, ZPackage pkg) { CheckVersion(rpc, pkg, action); }); } else { peer.m_rpc.Register("ServerSync VersionCheck", (Action)CheckVersion); } foreach (VersionCheck versionCheck in versionChecks) { versionCheck.Initialize(); if (versionCheck.ModRequired || __instance.IsServer()) { Debug.Log((object)("Sending " + versionCheck.DisplayName + " version " + versionCheck.CurrentVersion + " and minimum version " + versionCheck.MinimumRequiredVersion + " to the " + (__instance.IsServer() ? "client" : "server") + ".")); ZPackage val = new ZPackage(); val.Write(versionCheck.Name); val.Write(versionCheck.MinimumRequiredVersion); val.Write(versionCheck.CurrentVersion); peer.m_rpc.Invoke("ServerSync VersionCheck", new object[1] { val }); } } } [HarmonyPatch(typeof(ZNet), "Disconnect")] [HarmonyPrefix] private static void RemoveDisconnected(ZNetPeer peer, ZNet __instance) { if (!__instance.IsServer()) { return; } foreach (VersionCheck versionCheck in versionChecks) { versionCheck.ValidatedClients.Remove(peer.m_rpc); } } [HarmonyPatch(typeof(FejdStartup), "ShowConnectError")] [HarmonyPostfix] private static void ShowConnectionError(FejdStartup __instance) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) if (!__instance.m_connectionFailedPanel.activeSelf || (int)ZNet.GetConnectionStatus() != 3) { return; } bool flag = false; VersionCheck[] failedClient = GetFailedClient(); if (failedClient.Length != 0) { string text = string.Join("\n", failedClient.Select((VersionCheck check) => check.Error())); TMP_Text connectionFailedError = __instance.m_connectionFailedError; connectionFailedError.text = connectionFailedError.text + "\n" + text; flag = true; } foreach (KeyValuePair item in notProcessedNames.OrderBy((KeyValuePair kv) => kv.Key)) { if (!__instance.m_connectionFailedError.text.Contains(item.Key)) { TMP_Text connectionFailedError2 = __instance.m_connectionFailedError; connectionFailedError2.text = connectionFailedError2.text + "\nServer expects you to have " + item.Key + " (Version: " + item.Value + ") installed."; flag = true; } } if (flag) { RectTransform component = ((Component)__instance.m_connectionFailedPanel.transform.Find("Image")).GetComponent(); Vector2 sizeDelta = component.sizeDelta; sizeDelta.x = 675f; component.sizeDelta = sizeDelta; __instance.m_connectionFailedError.ForceMeshUpdate(false, false); float num = __instance.m_connectionFailedError.renderedHeight + 105f; RectTransform component2 = ((Component)((Component)component).transform.Find("ButtonOk")).GetComponent(); component2.anchoredPosition = new Vector2(component2.anchoredPosition.x, component2.anchoredPosition.y - (num - component.sizeDelta.y) / 2f); sizeDelta = component.sizeDelta; sizeDelta.y = num; component.sizeDelta = sizeDelta; } } } } namespace Njord { public static class NjordBoatController { public static string GetShipPrefabName(object ship) { Component val = (Component)((ship is Component) ? ship : null); if (val == null) { return "Unknown"; } return ((Object)val.gameObject).name.Replace("(Clone)", "").Trim(); } public static float GetBaseline(NjordSailState state, string shipName) { NjordRuntimeConfig instance = NjordRuntimeConfig.Instance; if (instance == null) { return 0f; } return state switch { NjordSailState.Forward => instance.BaseForwardForce, NjordSailState.Half => instance.BaseForwardForce, NjordSailState.Full => instance.BaseForwardForce, _ => 0f, }; } public static float ApplyAcceleration(float baseline, float dt) { NjordRuntimeConfig instance = NjordRuntimeConfig.Instance; if (instance == null) { return 0f; } float num = baseline * instance.AccelerationMultiplier; if (float.IsNaN(num) || float.IsInfinity(num)) { return 0f; } return num; } public static float GetSailMult(NjordSailState state) { NjordRuntimeConfig instance = NjordRuntimeConfig.Instance; if (instance == null) { return 1f; } return state switch { NjordSailState.Forward => instance.SailForwardForce, NjordSailState.Half => instance.HalfSailForce, NjordSailState.Full => instance.FullSailForce, _ => 1f, }; } public static float GetReverseForce(float dt) { NjordRuntimeConfig instance = NjordRuntimeConfig.Instance; if (instance == null) { return 0f; } float num = instance.BaseReverseForce * instance.ReverseKick; if (float.IsNaN(num) || float.IsInfinity(num)) { return 0f; } return num; } } public static class Njord_ShipControlTracker { public const float READY_DELAY = 0.35f; private static Dictionary _controlMap; private static Dictionary _windAngleMap; private static Dictionary _windGraceTimerMap; private static Dictionary _wasInDeadZoneMap; private static float _lastLookupLogTime = -10f; private const float LOOKUP_LOG_INTERVAL = 2f; public static long CurrentController { get; private set; } = 0L; public static bool ShouldShowHud { get; private set; } = false; public static float ReadyTimer { get; private set; } = 0f; public static bool SteeringGateReady { get; private set; } = false; private static Dictionary ControlMap { get { if (_controlMap == null) { _controlMap = new Dictionary(); } return _controlMap; } } private static Dictionary WindAngleMap { get { if (_windAngleMap == null) { _windAngleMap = new Dictionary(); } return _windAngleMap; } } private static Dictionary WindGraceTimerMap { get { if (_windGraceTimerMap == null) { _windGraceTimerMap = new Dictionary(); } return _windGraceTimerMap; } } private static Dictionary WasInDeadZoneMap { get { if (_wasInDeadZoneMap == null) { _wasInDeadZoneMap = new Dictionary(); } return _wasInDeadZoneMap; } } public static bool GetShipWasInDeadZone(Ship ship, bool defaultValue) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ship == (Object)null) { return defaultValue; } ZNetView component = ((Component)ship).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return defaultValue; } ZDOID uid = component.GetZDO().m_uid; if (WasInDeadZoneMap.TryGetValue(uid, out var value)) { return value; } return defaultValue; } public static void SetShipWasInDeadZone(Ship ship, bool val) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)ship == (Object)null)) { ZNetView component = ((Component)ship).GetComponent(); if (!((Object)(object)component == (Object)null) && component.IsValid()) { ZDOID uid = component.GetZDO().m_uid; WasInDeadZoneMap[uid] = val; } } } public static float GetShipGraceTimer(Ship ship) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ship == (Object)null) { return 0f; } ZNetView component = ((Component)ship).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return 0f; } ZDOID uid = component.GetZDO().m_uid; if (WindGraceTimerMap.TryGetValue(uid, out var value)) { return value; } return 0f; } public static void SetShipGraceTimer(Ship ship, float timer) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)ship == (Object)null)) { ZNetView component = ((Component)ship).GetComponent(); if (!((Object)(object)component == (Object)null) && component.IsValid()) { ZDOID uid = component.GetZDO().m_uid; WindGraceTimerMap[uid] = timer; } } } public static float GetShipWindAngle(Ship ship) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ship == (Object)null) { return 0f; } ZNetView component = ((Component)ship).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return 0f; } ZDOID uid = component.GetZDO().m_uid; if (WindAngleMap.TryGetValue(uid, out var value)) { return value; } float num = Mathf.DeltaAngle(0f, ship.GetWindAngle()); WindAngleMap[uid] = num; return num; } public static void SetShipWindAngle(Ship ship, float angle) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)ship == (Object)null)) { ZNetView component = ((Component)ship).GetComponent(); if (!((Object)(object)component == (Object)null) && component.IsValid()) { ZDOID uid = component.GetZDO().m_uid; WindAngleMap[uid] = angle; } } } public static long GetControllerForShip(object shipObj) { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) if (shipObj == null) { return 0L; } Ship val = (Ship)((shipObj is Ship) ? shipObj : null); if (val == null) { return 0L; } ZNetView component = ((Component)val).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return 0L; } ZDO zDO = component.GetZDO(); if (zDO == null) { return 0L; } ZDOID uid = zDO.m_uid; if (ControlMap.TryGetValue(uid, out var value)) { if (NjordConfig.Debug_Enable.Value && NjordConfig.Debug_AuthControl.Value && Time.time - _lastLookupLogTime >= 2f) { NjordDebug.Debug($"[Tracker] Lookup: {((Object)val).name} ({uid}) → controller={value}"); _lastLookupLogTime = Time.time; } return value; } if (NjordConfig.Debug_Enable.Value && NjordConfig.Debug_AuthControl.Value && Time.time - _lastLookupLogTime >= 2f) { NjordDebug.Debug($"[Tracker] Lookup: {((Object)val).name} ({uid}) → no entry"); _lastLookupLogTime = Time.time; } return 0L; } private static bool LocalPlayerHasControl() { //IL_005d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer == (Object)null) { return false; } long playerID = Player.m_localPlayer.GetPlayerID(); if (playerID == 0L) { return false; } foreach (KeyValuePair item in ControlMap) { if (item.Value == playerID) { if (NjordConfig.Debug_Enable.Value && NjordConfig.Debug_AuthControl.Value) { NjordDebug.Debug($"[Tracker] LocalPlayerHasControl → TRUE (ship {item.Key})"); } return true; } } if (NjordConfig.Debug_Enable.Value && NjordConfig.Debug_AuthControl.Value) { NjordDebug.Debug("[Tracker] LocalPlayerHasControl → FALSE"); } return false; } private static void RecalculateHudState() { bool flag = (Object)(object)Player.m_localPlayer != (Object)null; bool flag2 = LocalPlayerHasControl(); bool value = Plugin.HudEnabledByUser.Value; bool flag3 = flag && flag2 && value; if (ShouldShowHud != flag3 && NjordConfig.Debug_Enable.Value && NjordConfig.Debug_AuthControl.Value) { NjordDebug.Debug($"[Tracker] HUD state changed → {flag3} (hasPlayer={flag}, hasControl={flag2}, hudEnabled={value})"); } ShouldShowHud = flag3; } public static void SetControl(Ship ship, long playerID) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ship == (Object)null) { return; } ZNetView component = ((Component)ship).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } ZDO zDO = component.GetZDO(); if (zDO != null) { ZDOID uid = zDO.m_uid; ControlMap[uid] = playerID; CurrentController = playerID; Njord_Telemetry.ClearErrors(); if (NjordConfig.Debug_Enable.Value && NjordConfig.Debug_AuthControl.Value) { NjordDebug.Debug($"[Tracker] SetControl: ship={((Object)ship).name} ({uid}) → player={playerID}"); } RecalculateHudState(); } } public static void ClearControl(Ship ship) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ship == (Object)null) { return; } ZNetView component = ((Component)ship).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } ZDO zDO = component.GetZDO(); if (zDO == null) { return; } ZDOID uid = zDO.m_uid; ControlMap.Remove(uid); WindAngleMap.Remove(uid); Player localPlayer = Player.m_localPlayer; if (((localPlayer != null) ? localPlayer.GetPlayerID() : 0) == CurrentController) { if (NjordConfig.Debug_Enable.Value && NjordConfig.Debug_AuthControl.Value) { NjordDebug.Debug($"[Tracker] ClearControl: local player lost control of {((Object)ship).name} ({uid})"); } CurrentController = 0L; } else if (NjordConfig.Debug_Enable.Value && NjordConfig.Debug_AuthControl.Value) { NjordDebug.Debug($"[Tracker] ClearControl: removed entry for {((Object)ship).name} ({uid}), local player unaffected"); } RecalculateHudState(); } public static void UpdateController(long controller, float dt) { if (NjordConfig.Debug_Enable.Value && NjordConfig.Debug_AuthControl.Value && Time.time - _lastLookupLogTime >= 2f) { NjordDebug.Debug($"[AuthoritySync] UpdateController: controller={controller}, dt={dt:F4}"); } long num = (((Object)(object)Player.m_localPlayer != (Object)null) ? Player.m_localPlayer.GetPlayerID() : 0); if (controller == 0L || (num != 0L && controller == num)) { CurrentController = controller; } if (controller != 0L) { ReadyTimer += dt; if (ReadyTimer >= 0.35f) { SteeringGateReady = true; } } else { ReadyTimer = 0f; SteeringGateReady = false; } RecalculateHudState(); } } public static class NjordDebug { private static bool _startupPrinted; private static bool IsEnabled() { try { return NjordConfig.Debug_Enable != null && NjordConfig.Debug_Enable.Value; } catch { return false; } } public static void Startup() { if (!_startupPrinted) { _startupPrinted = true; if (Plugin.Log != null) { Plugin.Log.LogInfo((object)"⚓ [Njord] The longship wakes. The sea remembers your hand."); } } } public static void Info(string msg) { if (IsEnabled()) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Njord] " + msg)); } } } public static void Debug(string msg) { if (IsEnabled()) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogDebug((object)("[Njord] " + msg)); } } } public static void Warn(string msg) { if (IsEnabled()) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)("[Njord] " + msg)); } } } public static void Log(string msg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogInfo((object)("[Njord] " + msg)); } } public static void Error(string msg) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogError((object)("[Njord] " + msg)); } } } [BepInPlugin("wubarrk.njord", "Njord", "1.3.2")] public class Plugin : BaseUnityPlugin { public const string ModVersion = "1.3.2"; internal static Plugin Instance; internal static Harmony Harmony; internal static ManualLogSource Log; public static ConfigEntry HudPositionX; public static ConfigEntry HudPositionY; public static ConfigEntry HudEnabledByUser; private bool _hudCreated; public static bool OdinShipDetected { get; private set; } public static bool OdinShipPlusDetected { get; private set; } private void Awake() { //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; NjordDebug.Startup(); Log.LogInfo((object)"The sea stirs. The runes awaken."); OdinShipDetected = Chainloader.PluginInfos.ContainsKey("marlthon.OdinShip"); OdinShipPlusDetected = Chainloader.PluginInfos.ContainsKey("marlthon.OdinShipPlus"); if (OdinShipDetected || OdinShipPlusDetected) { Log.LogInfo((object)("Njord smiles upon the shipwrights: OdinShip" + (OdinShipPlusDetected ? "Plus" : "") + " detected! Taking the helm.")); } else { Log.LogInfo((object)"Njord watches the waves: OdinShip not detected. We sail on."); } NjordConfig.Bind(); HudPositionX = ((BaseUnityPlugin)this).Config.Bind("HUD", "HudPositionX", 40f, "Njord HUD X position."); HudPositionY = ((BaseUnityPlugin)this).Config.Bind("HUD", "HudPositionY", 200f, "Njord HUD Y position."); HudEnabledByUser = ((BaseUnityPlugin)this).Config.Bind("HUD", "HudEnabled", true, "If false, Njord HUD is hidden (F7 toggles)."); Harmony = new Harmony("wubarrk.njord"); NjordPatchCaller.ApplyPatches(); NjordHudManager.Initialize(); RegisterConsoleCommands(); if (NjordConfig.Debug_Enable.Value) { Log.LogInfo((object)"Njord console commands registered (including njord.dumpvfx)."); try { Version version = Assembly.GetExecutingAssembly().GetName().Version; Log.LogInfo((object)$"Njord DLL version: {version}"); } catch { } } Log.LogInfo((object)"Njord, god of the sea, obeys your command."); } private void Update() { if (!_hudCreated && (Object)(object)ZNet.instance != (Object)null) { _hudCreated = true; NjordHudManager.CreateHud(); } if (Input.GetKeyDown((KeyCode)288)) { HudEnabledByUser.Value = !HudEnabledByUser.Value; } } private void OnGUI() { NjordHudManager.OnGUI(); } private void RegisterConsoleCommands() { ConsoleCommand("njord.dumpvfx", delegate { try { NjordRuneSpriteTrail.DumpEmitters(); try { NjordRunePiggyback.DumpEmitters(); } catch { } Log.LogInfo((object)"Njord: dumped VFX emitter state to Njord debug log."); try { MessageHud instance = MessageHud.instance; if (instance != null) { instance.ShowMessage((MessageType)1, "Njord: VFX dump written to log.", 0, (Sprite)null, false); } } catch { } } catch (Exception ex) { Log.LogWarning((object)("njord.dumpvfx failed: " + ex.Message)); } }); ConsoleCommand("njord.vfx.orientation", delegate(string[] args) { try { if (args.Length < 1) { Log.LogInfo((object)"Usage: njord.vfx.orientation "); } else { string text = args[0].ToLowerInvariant(); switch (text) { case "flat": NjordRunePiggyback_SetOrientation("Flat"); break; case "flatinv": NjordRunePiggyback_SetOrientation("FlatInverted"); break; case "upright": NjordRunePiggyback_SetOrientation("Upright"); break; case "camera": NjordRunePiggyback_SetOrientation("CameraFacing"); break; default: Log.LogInfo((object)"Unknown orientation. Valid: flat, flatinv, upright, camera"); return; } Log.LogInfo((object)("Njord: set VFX spawn orientation -> " + text)); } } catch (Exception ex) { Log.LogWarning((object)("njord.vfx.orientation failed: " + ex.Message)); } }); ConsoleCommand("njord.testtrail", delegate { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) try { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { Log.LogWarning((object)"njord.testtrail: no local player"); } else { Transform transform = ((Component)localPlayer).transform; Color vFX_Color = NjordRuntimeConfig.Instance.VFX_Color; float num = 0.6f; Vector3 val = transform.position - transform.forward * 1f + Vector3.up * 0.5f; for (int i = 0; i < 8; i++) { NjordRunePiggyback.SpawnAtWorldPosition(val - transform.forward * ((float)i * num), vFX_Color); } Log.LogInfo((object)"njord.testtrail: spawned test trail behind player"); } } catch (Exception ex) { Log.LogWarning((object)("njord.testtrail failed: " + ex.Message)); } }); if (NjordConfig.Debug_Enable.Value) { Log.LogInfo((object)"Registered console command 'njord.dumpvfx'."); } } public static void NjordRunePiggyback_SetOrientation(string name) { try { Type typeFromHandle = typeof(NjordRunePiggyback); Type nestedType = typeFromHandle.GetNestedType("OrientationMode", BindingFlags.Public | BindingFlags.NonPublic); if (!(nestedType == null)) { object value = Enum.Parse(nestedType, name); FieldInfo field = typeFromHandle.GetField("_spawnOrientation", BindingFlags.Static | BindingFlags.NonPublic); if (field != null) { field.SetValue(null, value); } } } catch { } } private void ConsoleCommand(string name, Action action) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Expected O, but got Unknown //IL_00f8: Unknown result type (might be due to invalid IL or missing references) try { new ConsoleCommand(name, "", (ConsoleEvent)delegate(ConsoleEventArgs args) { action(args.Args); }, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); if (NjordConfig.Debug_Enable.Value) { Log.LogInfo((object)("Registered console command '" + name + "' (immediate).")); } return; } catch (Exception ex) { if (NjordConfig.Debug_Enable.Value) { Log.LogInfo((object)("Immediate registration of console command '" + name + "' failed, will wait for Terminal: " + ex.Message)); } } Type typeFromHandle = typeof(Terminal); object obj = null; FieldInfo field = typeFromHandle.GetField("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { obj = field.GetValue(null); } else { PropertyInfo property = typeFromHandle.GetProperty("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { obj = property.GetValue(null); } } if (obj != null) { try { new ConsoleCommand(name, "", (ConsoleEvent)delegate(ConsoleEventArgs args) { action(args.Args); }, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); if (NjordConfig.Debug_Enable.Value) { Log.LogInfo((object)("Registered console command '" + name + "' after Terminal detected via reflection.")); } return; } catch (Exception ex2) { Log.LogWarning((object)("Failed to register console command '" + name + "' after reflection detect: " + ex2.Message)); return; } } ((MonoBehaviour)this).StartCoroutine(WaitAndRegister(name, action)); } private IEnumerator WaitAndRegister(string name, Action action) { float timeout = 10f; float start = Time.time; ConsoleEvent val = default(ConsoleEvent); while (Time.time - start < timeout) { Type typeFromHandle = typeof(Terminal); FieldInfo field = typeFromHandle.GetField("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); object obj = null; if (field != null) { obj = field.GetValue(null); } else { PropertyInfo property = typeFromHandle.GetProperty("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (property != null) { obj = property.GetValue(null); } } if (obj != null) { try { ConsoleEvent obj2 = val; if (obj2 == null) { ConsoleEvent val2 = delegate(ConsoleEventArgs args) { action(args.Args); }; ConsoleEvent val3 = val2; val = val2; obj2 = val3; } new ConsoleCommand(name, "", obj2, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); if (NjordConfig.Debug_Enable.Value) { Log.LogInfo((object)("Registered console command '" + name + "' after Terminal became available.")); } yield break; } catch (Exception ex) { Log.LogWarning((object)("Failed to register console command '" + name + "' after wait: " + ex.Message)); yield break; } } yield return null; } Log.LogWarning((object)("Timed out waiting for Terminal to register console command '" + name + "'.")); } } public static class NjordRunePiggyback { public enum OrientationMode { Flat, FlatInverted, Upright, CameraFacing } private class Emitter : MonoBehaviour { private Transform _stern; private Color _color = Color.white; private float _spacing = 0.6f; private Vector3 _lastSpawnPos = Vector3.zero; private Action _returnToPool; private Sprite _sprite; private Texture2D _tex; private bool _active = true; private ParticleSystem _wakePS; private Particle[] _buffer = (Particle[])(object)new Particle[512]; private float _wakeInterval = 0.1f; private float _lastWake; private float _lastSternTime; private Vector3 _lastSternPos = Vector3.zero; private float _minSpeed = 0.5f; private float _lastLogTime = -10f; public void Initialize(Transform stern, Color color, float rateMultiplier, Action returnToPool, Sprite sprite, Texture2D tex) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) _stern = stern; _color = color; _returnToPool = returnToPool; _sprite = sprite; _tex = tex; _spacing = 0.6f; _wakeInterval = 0.1f; _minSpeed = 0.5f; try { if (NjordConfig.Debug_Enable != null && NjordConfig.Debug_Enable.Value) { _minSpeed = Mathf.Min(_minSpeed, 0.1f); } } catch { } _lastSpawnPos = (((Object)(object)_stern != (Object)null) ? (_stern.TransformPoint(new Vector3(0f, -0.25f, -1f)) - Vector3.one * 1000f) : Vector3.zero); _lastSternPos = (((Object)(object)_stern != (Object)null) ? _stern.position : Vector3.zero); _lastSternTime = Time.time; _active = true; try { ParticleSystem[] componentsInChildren = ((Component)_stern).GetComponentsInChildren(true); ParticleSystem val = null; ParticleSystem[] array = componentsInChildren; foreach (ParticleSystem val2 in array) { if (!((Object)(object)val2 == (Object)null)) { string text = ((Object)((Component)val2).gameObject).name.ToLowerInvariant(); if (text.Contains("wake") || text.Contains("trail") || text.Contains("speed") || text.Contains("mask")) { val = val2; break; } } } if ((Object)(object)val == (Object)null && componentsInChildren.Length != 0) { val = componentsInChildren[0]; } _wakePS = val; if (IsDebugEnabled()) { try { Plugin.Log.LogInfo((object)("[VFX-Piggyback] Emitter init: wakePS=" + (((Object)(object)_wakePS != (Object)null) ? ((Object)((Component)_wakePS).gameObject).name : "(none)"))); } catch { } } if (!((Object)(object)_wakePS == (Object)null)) { return; } _active = false; if (IsDebugEnabled()) { try { Plugin.Log.LogInfo((object)"[VFX-Piggyback] No wake PS found; emitter disabled (sprite trail used instead)"); return; } catch { return; } } } catch { } } public void UpdateParams(Transform stern, Color color, float rateMultiplier) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) _stern = stern ?? _stern; _color = color; _spacing = 0.6f; } public void SetActive(bool v) { _active = v; } private void Update() { //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0292: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) if (!_active || (Object)(object)_stern == (Object)null) { return; } _ = NjordRuntimeConfig.Instance; float time = Time.time; float num = Mathf.Max(1E-06f, time - _lastSternTime); float num2 = Vector3.Distance(_stern.position, _lastSternPos) / num; _lastSternPos = _stern.position; _lastSternTime = time; if ((Object)(object)_wakePS != (Object)null) { if (Time.time - _lastWake < _wakeInterval) { return; } _lastWake = Time.time; int particles = _wakePS.GetParticles(_buffer); if (IsDebugEnabled()) { try { Plugin.Log.LogDebug((object)$"[VFX-Piggyback] Wake sample: count={particles} speed={num2} minSpeed={_minSpeed}"); } catch { } } if (particles <= 0) { return; } int num3 = Mathf.Min(4, particles); int num4 = Mathf.Max(1, particles / num3); for (int i = 0; i < particles; i += num4) { Vector3 worldPos = ((Component)_wakePS).transform.TransformPoint(((Particle)(ref _buffer[i])).position); if (num2 < _minSpeed) { if (!(Time.time - _lastLogTime > 1f)) { continue; } if (IsDebugEnabled()) { try { Plugin.Log.LogInfo((object)$"[VFX-Piggyback] Skipping wake spawn: speed {num2} < min {_minSpeed}"); } catch { } } _lastLogTime = Time.time; } else { TrySpawnAt(worldPos); } } return; } Vector3 val = _stern.TransformPoint(new Vector3(0f, -0.25f, -1f)); Vector3 val2 = val; int num5 = 0; try { num5 = ((LayerMask.NameToLayer("Water") >= 0) ? (1 << LayerMask.NameToLayer("Water")) : 0); } catch { num5 = 0; } if (num5 == 0) { num5 = -1; } RaycastHit val3 = default(RaycastHit); if (num5 != 0 && Physics.Raycast(val + Vector3.up * 2f, Vector3.down, ref val3, 10f, num5)) { val2.y = ((RaycastHit)(ref val3)).point.y + 0.02f; } for (float num6 = Vector3.Dot(val2 - _lastSpawnPos, _stern.forward); num6 >= _spacing; num6 = Vector3.Dot(val2 - _lastSpawnPos, _stern.forward)) { _lastSpawnPos += _stern.forward * _spacing; Vector3 lastSpawnPos = _lastSpawnPos; lastSpawnPos.y = val2.y; if (num2 >= _minSpeed) { TrySpawnAt(lastSpawnPos); } else if (Time.time - _lastLogTime > 1f) { if (IsDebugEnabled()) { try { Plugin.Log.LogInfo((object)$"[VFX-Piggyback] Skipping trail spawn: speed {num2} < min {_minSpeed}"); } catch { } } _lastLogTime = Time.time; } } } public bool TrySpawnAt(Vector3 worldPos) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) if (!_active || (Object)(object)_stern == (Object)null) { return false; } float num = Vector3.Distance(worldPos, _lastSpawnPos); if (num < _spacing) { if (Time.time - _lastLogTime > 1f) { if (IsDebugEnabled()) { try { Plugin.Log.LogInfo((object)$"[VFX-Piggyback] TrySpawnAt rejected: dist {num} < spacing {_spacing}"); } catch { } } _lastLogTime = Time.time; } return false; } _lastSpawnPos = worldPos; SpawnVisual(worldPos, _color, _sprite, _tex, null, _stern); return true; } private void DoSpawn(Vector3 pos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) SpawnVisual(pos, _color, _sprite, _tex, null, _stern); } } private class RuneFader : MonoBehaviour { private SpriteRenderer _sr; private Vector3 _vel; private float _life; private float _age; private float _startScale; private Color _startColor; private Action _onFinish; public void Init(Action onFinish) { _sr = ((Component)this).GetComponent(); _onFinish = onFinish; } public void Play(Vector3 velocity, float life, float startScale, Color color) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) _vel = velocity; _life = Mathf.Max(0.01f, life); _age = 0f; _startScale = Mathf.Max(0.01f, startScale); _startColor = color; if ((Object)(object)_sr != (Object)null) { _sr.color = color; ((Component)_sr).transform.localScale = Vector3.one * _startScale; } } private void Update() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) float deltaTime = Time.deltaTime; _age += deltaTime; Transform transform = ((Component)this).transform; transform.position += _vel * deltaTime; float num = Mathf.Clamp01(_age / _life); if ((Object)(object)_sr != (Object)null) { Color startColor = _startColor; startColor.a = Mathf.Lerp(_startColor.a, 0f, num); _sr.color = startColor; float num2 = Mathf.Lerp(_startScale, _startScale * 0.4f, num); ((Component)_sr).transform.localScale = Vector3.one * num2; } if (_age >= _life) { _onFinish?.Invoke(((Component)this).gameObject); } } } private const int POOL_INITIAL = 64; private const int POOL_MAX = 1024; private static Queue _pool = new Queue(); private static GameObject _poolRoot; private static Texture2D _runeTex; private static Sprite _runeSprite; private static Mesh _debugQuadMesh; private static bool _inited = false; private static OrientationMode _spawnOrientation = OrientationMode.Flat; private static readonly Dictionary _emitters = new Dictionary(); private static bool IsDebugEnabled() { try { NjordRuntimeConfig instance = NjordRuntimeConfig.Instance; if (instance != null && instance.Debug_Enable) { return true; } } catch { } try { if (NjordConfig.Debug_Enable != null && NjordConfig.Debug_Enable.Value) { return true; } } catch { } return false; } private static void EnsureInit() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Expected O, but got Unknown //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: 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) //IL_010c: Unknown result type (might be due to invalid IL or missing references) if (_inited) { return; } _inited = true; _runeTex = NjordRuneTextureGenerator.GenerateRune((Color)(((??)NjordConfig.VFX_Color?.Value) ?? new Color(0.3f, 0.6f, 1f, 1f))); if ((Object)(object)_runeTex != (Object)null) { _runeSprite = Sprite.Create(_runeTex, new Rect(0f, 0f, (float)((Texture)_runeTex).width, (float)((Texture)_runeTex).height), new Vector2(0.5f, 0.5f), 100f); } else { Texture2D val = new Texture2D(16, 16, (TextureFormat)4, false); Color[] array = (Color[])(object)new Color[256]; for (int i = 0; i < array.Length; i++) { array[i] = Color.white; } val.SetPixels(array); val.Apply(false); _runeTex = val; _runeSprite = Sprite.Create(_runeTex, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); } _poolRoot = new GameObject("NjordRunePiggybackPool"); Object.DontDestroyOnLoad((Object)(object)_poolRoot); for (int j = 0; j < 64; j++) { _pool.Enqueue(CreatePooledGO()); } } private static Mesh GetOrCreateDebugQuadMesh() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: 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) //IL_0102: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_debugQuadMesh != (Object)null) { return _debugQuadMesh; } Mesh val = new Mesh(); ((Object)val).name = "Njord_DebugQuadMesh"; Vector3[] vertices = (Vector3[])(object)new Vector3[4] { new Vector3(-0.5f, 0f, -0.5f), new Vector3(0.5f, 0f, -0.5f), new Vector3(0.5f, 0f, 0.5f), new Vector3(-0.5f, 0f, 0.5f) }; int[] triangles = new int[6] { 0, 1, 2, 0, 2, 3 }; Vector2[] uv = (Vector2[])(object)new Vector2[4] { new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(0f, 1f) }; val.vertices = vertices; val.triangles = triangles; val.uv = uv; val.RecalculateNormals(); val.RecalculateBounds(); _debugQuadMesh = val; return _debugQuadMesh; } private static GameObject CreatePooledGO() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("NjordRune"); val.transform.SetParent(_poolRoot.transform, false); SpriteRenderer val2 = val.AddComponent(); val2.sprite = _runeSprite; ((Renderer)val2).sortingLayerName = "Default"; ((Renderer)val2).sortingOrder = 5000; ((Renderer)val2).shadowCastingMode = (ShadowCastingMode)0; try { Shader val3 = Shader.Find("Sprites/Default"); if ((Object)(object)val3 != (Object)null) { Material val4 = new Material(val3); if (val4.HasProperty("_MainTex") && (Object)(object)_runeTex != (Object)null) { val4.SetTexture("_MainTex", (Texture)(object)_runeTex); } ((Renderer)val2).material = val4; } } catch { } val.AddComponent().Init(ReturnToPool); try { GameObject val5 = new GameObject("Njord_DebugQuad"); val5.transform.SetParent(val.transform, false); val5.transform.localPosition = Vector3.zero; val5.transform.localRotation = Quaternion.identity; val5.AddComponent().mesh = GetOrCreateDebugQuadMesh(); MeshRenderer obj2 = val5.AddComponent(); ((Renderer)obj2).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)obj2).receiveShadows = false; ((Renderer)obj2).enabled = false; } catch { } val.SetActive(false); return val; } private static GameObject GetFromPool() { if (!_inited) { EnsureInit(); } if (_pool.Count > 0) { return _pool.Dequeue(); } if (_pool.Count + 1 <= 1024) { return CreatePooledGO(); } return null; } private static void ReturnToPool(GameObject go) { if (!((Object)(object)go == (Object)null)) { go.SetActive(false); go.transform.SetParent(_poolRoot.transform, false); if (_pool.Count < 1024) { _pool.Enqueue(go); } else { Object.Destroy((Object)(object)go); } } } public static void SpawnBurst(Vector3 pos, Color color, int count) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) if (!NjordConfig.VFX_Enable.Value) { return; } EnsureInit(); float life = 2.5f; float startScale = 1.125f; for (int i = 0; i < Mathf.Max(1, count); i++) { GameObject fromPool = GetFromPool(); if (!((Object)(object)fromPool == (Object)null)) { SpriteRenderer component = fromPool.GetComponent(); if ((Object)(object)component != (Object)null) { component.sprite = _runeSprite; component.color = color; } fromPool.transform.position = pos + Random.insideUnitSphere * 0.35f; fromPool.transform.rotation = Quaternion.Euler(90f, Random.Range(0f, 360f), 0f); fromPool.SetActive(true); RuneFader component2 = fromPool.GetComponent(); if ((Object)(object)component2 != (Object)null) { Vector3 velocity = (Random.onUnitSphere + Vector3.back * 1.5f) * 0.4f; component2.Play(velocity, life, startScale, color); } } } } public static void StartTrailForShip(object ship, Transform stern, Color color, float rateMultiplier = 1f) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) if (ship == null || (Object)(object)stern == (Object)null || !NjordConfig.VFX_Enable.Value) { return; } EnsureInit(); if (_emitters.TryGetValue(ship, out var value) && (Object)(object)value != (Object)null) { value.SetActive(v: true); value.UpdateParams(stern, color, rateMultiplier); return; } GameObject val = new GameObject($"NjordRuneEmitter_{ship.GetHashCode()}"); val.transform.SetParent(stern, true); val.transform.position = stern.TransformPoint(new Vector3(0f, -0.25f, -1f)); Emitter emitter = val.AddComponent(); try { emitter.Initialize(stern, color, rateMultiplier, ReturnToPool, _runeSprite, _runeTex); _emitters[ship] = emitter; if (IsDebugEnabled()) { try { NjordDebug.Info($"[VFX-Piggyback] Created emitter for ship {ship} (stern={((stern != null) ? ((Object)stern).name : null)})"); } catch { } } if (IsDebugEnabled()) { try { Plugin.Log.LogInfo((object)$"[VFX-Piggyback] Created emitter for ship {ship} (stern={((stern != null) ? ((Object)stern).name : null)})"); return; } catch { return; } } } catch (Exception ex) { if (IsDebugEnabled()) { try { Plugin.Log.LogWarning((object)$"[VFX-Piggyback] Failed to initialize emitter for ship {ship}: {ex.Message}"); } catch { } } if (IsDebugEnabled()) { try { NjordDebug.Warn($"[VFX-Piggyback] Failed to initialize emitter for ship {ship}: {ex.Message}"); } catch { } } try { if ((Object)(object)emitter != (Object)null && (Object)(object)((Component)emitter).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)emitter).gameObject); } } catch { } } } public static void StopTrailForShip(object ship) { if (ship != null && _emitters.TryGetValue(ship, out var value) && (Object)(object)value != (Object)null) { value.SetActive(v: false); } } public static void RemoveEmitterForShip(object ship) { if (ship == null) { return; } if (_emitters.TryGetValue(ship, out var value) && (Object)(object)value != (Object)null) { try { if ((Object)(object)((Component)value).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)value).gameObject); } } catch { } } _emitters.Remove(ship); } public static void DumpEmitters() { try { if (IsDebugEnabled()) { try { Plugin.Log.LogInfo((object)$"[VFX-Piggyback] Emitters: count={_emitters.Count} pool={_pool.Count}"); } catch { } } foreach (KeyValuePair emitter in _emitters) { object key = emitter.Key; Emitter value = emitter.Value; if ((Object)(object)value == (Object)null) { if (IsDebugEnabled()) { try { Plugin.Log.LogInfo((object)$"[VFX-Piggyback] Emitter for {key}: null"); } catch { } } } else if (IsDebugEnabled()) { try { ManualLogSource log = Plugin.Log; object arg = ((Behaviour)value).isActiveAndEnabled; GameObject gameObject = ((Component)value).gameObject; log.LogInfo((object)$"[VFX-Piggyback] Emitter for {key}: active={arg} go={((gameObject != null) ? ((Object)gameObject).name : null)}"); } catch { } } } } catch { } } public static void SpawnAtWorldPosition(Vector3 pos, Color color) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) SpawnVisual(pos, color, _runeSprite, _runeTex, null, null); } private static void SpawnVisual(Vector3 pos, Color color, Sprite sprite, Texture2D tex, Vector3? velocityOverride, Transform stern) { //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Unknown result type (might be due to invalid IL or missing references) //IL_03c0: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_0403: Unknown result type (might be due to invalid IL or missing references) //IL_042e: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Unknown result type (might be due to invalid IL or missing references) //IL_025c: 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_0299: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_036a: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Expected O, but got Unknown //IL_03aa: Unknown result type (might be due to invalid IL or missing references) if (!NjordConfig.VFX_Enable.Value) { return; } EnsureInit(); GameObject fromPool = GetFromPool(); if ((Object)(object)fromPool == (Object)null) { return; } SpriteRenderer component = fromPool.GetComponent(); if ((Object)(object)component != (Object)null) { component.sprite = sprite ?? _runeSprite; component.color = color; ((Renderer)component).sortingLayerName = "Default"; ((Renderer)component).sortingOrder = 32767; } fromPool.transform.position = pos; try { switch (_spawnOrientation) { case OrientationMode.Flat: fromPool.transform.rotation = Quaternion.Euler(90f, Random.Range(0f, 360f), 0f); break; case OrientationMode.FlatInverted: fromPool.transform.rotation = Quaternion.Euler(-90f, Random.Range(0f, 360f), 0f); break; case OrientationMode.Upright: fromPool.transform.rotation = Quaternion.Euler(0f, Random.Range(0f, 360f), 0f); break; case OrientationMode.CameraFacing: if ((Object)(object)Camera.main != (Object)null) { fromPool.transform.rotation = Quaternion.LookRotation(((Component)Camera.main).transform.forward); } else { fromPool.transform.rotation = Quaternion.Euler(90f, Random.Range(0f, 360f), 0f); } break; default: fromPool.transform.rotation = Quaternion.Euler(90f, Random.Range(0f, 360f), 0f); break; } } catch { fromPool.transform.rotation = Quaternion.Euler(90f, Random.Range(0f, 360f), 0f); } fromPool.SetActive(true); float life = 2.5f; float startScale = 0.75f; Vector3 velocity = (velocityOverride.HasValue ? velocityOverride.Value : ((!((Object)(object)stern != (Object)null)) ? (Vector3.back * 0.6f + Random.insideUnitSphere * 0.2f) : (-stern.forward * Random.Range(0.6f, 1.2f) + stern.right * Random.Range(-0.25f, 0.25f) + stern.up * Random.Range(-0.05f, 0.05f)))); RuneFader component2 = fromPool.GetComponent(); if ((Object)(object)component2 != (Object)null) { try { component2.Play(velocity, life, startScale, color); } catch { try { component2.Play(velocity, life, startScale, color); } catch { } } } try { fromPool.layer = 0; SpriteRenderer component3 = fromPool.GetComponent(); if ((Object)(object)component3 != (Object)null) { ((Renderer)component3).sortingOrder = 32767; } } catch { } try { if (IsDebugEnabled()) { Transform val = fromPool.transform.Find("Njord_DebugQuad"); if ((Object)(object)val != (Object)null) { MeshRenderer component4 = ((Component)val).GetComponent(); if ((Object)(object)component4 != (Object)null) { if ((Object)(object)((Renderer)component4).sharedMaterial == (Object)null) { Shader val2 = Shader.Find("Unlit/Texture") ?? Shader.Find("Unlit/Color") ?? Shader.Find("Sprites/Default"); if ((Object)(object)val2 != (Object)null) { try { Material val3 = new Material(val2); if (val3.HasProperty("_MainTex") && (Object)(object)tex != (Object)null) { val3.SetTexture("_MainTex", (Texture)(object)tex); } if (val3.HasProperty("_Color")) { val3.SetColor("_Color", color); } ((Renderer)component4).material = val3; } catch { } } } val.localScale = Vector3.one * 0.3f; ((Renderer)component4).enabled = true; try { ((Renderer)component4).material.renderQueue = 5000; } catch { } if (IsDebugEnabled()) { try { Plugin.Log.LogInfo((object)$"[VFX-Piggyback] Spawned debug quad at {pos}"); } catch { } } } } } } catch { } if (!IsDebugEnabled()) { return; } try { Plugin.Log.LogInfo((object)$"[VFX-Piggyback] DoSpawn at {pos}"); } catch { } } } public static class NjordRuneSpriteTrail { private class Emitter : MonoBehaviour { private Transform _stern; private Color _color = Color.white; private float _life = 1.2f; private float _scale = 0.7f; private float _spacing = 0.6f; private Vector3 _lastSpawnPos; private Action _returnToPool; private Sprite _sprite; private bool _active = true; private bool _useTelemetry; private float _cachedWaterY = float.MinValue; private float _lastWaterSampleTime = -10f; private const float WATER_SAMPLE_INTERVAL = 0.1f; private const float WATER_SURFACE_OFFSET = 0.02f; private int _waterMask; private bool _usedAllLayersFallback; private bool _loggedLayerResolution; private float _lastSpawnDebugLog = -10f; private const float SPAWN_DEBUG_LOG_INTERVAL = 1f; private bool _debugNotified; public void Initialize(Transform stern, Color color, float rateMultiplier, Action returnToPool, Sprite sprite, bool useTelemetry) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) //IL_0258: Unknown result type (might be due to invalid IL or missing references) _stern = stern; _useTelemetry = useTelemetry; _color = color; _sprite = sprite; _returnToPool = returnToPool; _active = true; _ = NjordRuntimeConfig.Instance; _life = 2.5f; _scale = 0.41343752f; _spacing = 0.49980003f; _lastSpawnPos = (((Object)(object)_stern != (Object)null) ? _stern.position : Vector3.zero); if (_useTelemetry && (Object)(object)_stern != (Object)null) { try { NjordDebug.Debug($"[VFX-Sprite] Telemetry emitter seeded cachedY={_cachedWaterY = GetRealisticTelemetryWaterY():F2}"); } catch { } } string text = null; string text2 = null; List list = new List(); if (!string.IsNullOrEmpty(text)) { list.Add(text); } list.AddRange(new string[7] { "Water", "water", "WaterSurface", "Ocean", "Sea", "SeaWater", "WaterPlane" }); foreach (string item in list) { if (!string.IsNullOrEmpty(item)) { int num = LayerMask.NameToLayer(item); if (num >= 0) { _waterMask = 1 << num; text2 = item; _usedAllLayersFallback = false; break; } } } if (text2 == null) { SyncedConfigEntry debug_Enable = NjordConfig.Debug_Enable; if (debug_Enable != null && debug_Enable.Value) { _waterMask = -1; _usedAllLayersFallback = true; } else { _waterMask = 0; _usedAllLayersFallback = false; } } if (!_loggedLayerResolution) { string arg = text2 ?? (_usedAllLayersFallback ? "(AllLayers)" : "(none)"); NjordDebug.Debug($"[VFX-Sprite] Resolved water layer -> '{arg}' mask={_waterMask}"); _loggedLayerResolution = true; } if (_useTelemetry || !((Object)(object)_stern != (Object)null)) { return; } try { int num2 = _waterMask; if (num2 == 0) { SyncedConfigEntry debug_Enable2 = NjordConfig.Debug_Enable; if (debug_Enable2 != null && debug_Enable2.Value) { num2 = -1; } } RaycastHit val = default(RaycastHit); if (num2 != 0 && (Physics.Raycast(_stern.position, Vector3.down, ref val, 10f, num2) || Physics.Raycast(_stern.position, Vector3.up, ref val, 10f, num2))) { _cachedWaterY = ((RaycastHit)(ref val)).point.y; NjordDebug.Debug($"[VFX-Sprite] Immediate water sample cachedY={_cachedWaterY:F2}"); } } catch { } } public void UpdateParams(Transform stern, Color color, float rateMultiplier) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) _stern = stern ?? _stern; _color = color; _spacing = 0.6f; } public void SetActive(bool v) { _active = v; } private float GetRealisticTelemetryWaterY() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) float num = (((Object)(object)_stern != (Object)null) ? _stern.position.y : 0f); float waterLevel = Njord_Telemetry.WaterLevel; float boatY = Njord_Telemetry.BoatY; if (float.IsNaN(waterLevel) || float.IsInfinity(waterLevel)) { return num; } float num2 = waterLevel; if ((Object)(object)_stern != (Object)null && !float.IsNaN(boatY) && !float.IsInfinity(boatY) && Mathf.Abs(boatY) > 0.0001f) { num2 = waterLevel + (num - boatY); } return Mathf.Clamp(num2, num - 3f, num + 3f); } private void Update() { //IL_018d: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_0270: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_0306: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Unknown result type (might be due to invalid IL or missing references) //IL_0342: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) if (!_active) { return; } if ((Object)(object)_stern == (Object)null) { _active = false; NjordDebug.Warn("[VFX-Sprite] Emitter stern destroyed; deactivating."); return; } if (_useTelemetry) { try { float waterLevel = Njord_Telemetry.WaterLevel; float boatY = Njord_Telemetry.BoatY; if (!float.IsNaN(waterLevel) && !float.IsInfinity(waterLevel)) { float num = waterLevel; if (!float.IsNaN(boatY) && Mathf.Abs(boatY) > 0.0001f) { num = waterLevel + (_stern.position.y - boatY); } _cachedWaterY = Mathf.Clamp(num, _stern.position.y - 3f, _stern.position.y + 3f); } } catch { } } else if (Time.time - _lastWaterSampleTime > 0.1f) { _lastWaterSampleTime = Time.time; int num2 = _waterMask; if (num2 == 0) { SyncedConfigEntry debug_Enable = NjordConfig.Debug_Enable; if (debug_Enable != null && debug_Enable.Value) { num2 = -1; } } if (num2 != 0) { try { RaycastHit val = default(RaycastHit); if (Physics.Raycast(_stern.position, Vector3.down, ref val, 10f, num2) || Physics.Raycast(_stern.position, Vector3.up, ref val, 10f, num2)) { _cachedWaterY = ((RaycastHit)(ref val)).point.y; } } catch { } } } if (_cachedWaterY == float.MinValue) { _cachedWaterY = _stern.position.y; } float num3 = _stern.position.x - _lastSpawnPos.x; float num4 = _stern.position.z - _lastSpawnPos.z; if (!(num3 * num3 + num4 * num4 < _spacing * _spacing)) { Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(_stern.position.x, _cachedWaterY + 0.02f, _stern.position.z); Vector3 val3 = new Vector3(_stern.right.x, 0f, _stern.right.z); Vector3 normalized = ((Vector3)(ref val3)).normalized; SpawnOneAt(val2 + normalized * Random.Range(-0.15f, 0.15f), 1.1475f); SpawnOneAt(val2 - normalized * 0.9f + normalized * Random.Range(-0.15f, 0.15f), 0.837f); SpawnOneAt(val2 + normalized * 0.9f + normalized * Random.Range(-0.15f, 0.15f), 0.837f); SpawnOneAt(val2 - normalized * 1.8f + normalized * Random.Range(-0.15f, 0.15f), 1.1475f); SpawnOneAt(val2 + normalized * 1.8f + normalized * Random.Range(-0.15f, 0.15f), 1.1475f); _lastSpawnPos = _stern.position; } } public bool TrySpawnAt(Vector3 worldPos) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (!_active || (Object)(object)_stern == (Object)null) { return false; } float num = worldPos.x - _lastSpawnPos.x; float num2 = worldPos.z - _lastSpawnPos.z; if (num * num + num2 * num2 < _spacing * _spacing) { return false; } if (_useTelemetry) { try { worldPos.y = GetRealisticTelemetryWaterY() + 0.02f; } catch { } } _lastSpawnPos = worldPos; SpawnOneAt(worldPos); return true; } private void SpawnOneAt(Vector3 spawnPos, float scaleMultiplier = 1f) { //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0431: Unknown result type (might be due to invalid IL or missing references) //IL_0438: Unknown result type (might be due to invalid IL or missing references) //IL_0443: Unknown result type (might be due to invalid IL or missing references) //IL_0448: Unknown result type (might be due to invalid IL or missing references) //IL_044f: Unknown result type (might be due to invalid IL or missing references) //IL_0454: Unknown result type (might be due to invalid IL or missing references) //IL_045f: Unknown result type (might be due to invalid IL or missing references) //IL_0466: Unknown result type (might be due to invalid IL or missing references) //IL_046b: Unknown result type (might be due to invalid IL or missing references) //IL_0470: Unknown result type (might be due to invalid IL or missing references) //IL_0473: Unknown result type (might be due to invalid IL or missing references) //IL_0484: Unknown result type (might be due to invalid IL or missing references) //IL_0392: Unknown result type (might be due to invalid IL or missing references) //IL_0399: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Expected O, but got Unknown //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Expected O, but got Unknown //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Expected O, but got Unknown //IL_0343: Unknown result type (might be due to invalid IL or missing references) if (_useTelemetry) { try { spawnPos.y = GetRealisticTelemetryWaterY() + 0.02f; } catch { } } GameObject fromPool = GetFromPool(); if ((Object)(object)fromPool == (Object)null) { return; } SpriteRenderer component = fromPool.GetComponent(); if ((Object)(object)component != (Object)null) { component.sprite = ((_runeSprites != null && _runeSprites.Length != 0) ? _runeSprites[Random.Range(0, _runeSprites.Length)] : _sprite); component.color = _color; if ((Object)(object)component.sprite == (Object)null) { NjordDebug.Warn($"[VFX-Sprite] SpawnOneAt: sprite is null for spawned GO at {spawnPos}"); } try { NjordRuntimeConfig instance = NjordRuntimeConfig.Instance; if (instance != null && instance.Debug_Enable) { Shader val = Shader.Find("Sprites/Default"); if ((Object)(object)val != (Object)null) { try { ((Renderer)component).material = new Material(val); } catch { } } } } catch { } } fromPool.transform.position = spawnPos; fromPool.transform.rotation = Quaternion.Euler(Random.Range(0f, 360f), Random.Range(0f, 360f), Random.Range(0f, 360f)); fromPool.SetActive(true); try { NjordRuntimeConfig instance2 = NjordRuntimeConfig.Instance; if (instance2 != null && instance2.Debug_Enable) { if (Time.time - _lastSpawnDebugLog > 1f) { string text = (((Object)(object)component == (Object)null || (Object)(object)component.sprite == (Object)null) ? "(sprite-null)" : "(sprite-ok)"); NjordDebug.Info($"[VFX-Sprite] SpawnOneAt: pos={spawnPos} cachedY={_cachedWaterY} {text} goLayer={fromPool.layer} sortingOrder={(((Object)(object)component != (Object)null) ? ((Renderer)component).sortingOrder : (-1))} active={fromPool.activeSelf}"); _lastSpawnDebugLog = Time.time; } if (!_debugNotified) { try { MessageHud instance3 = MessageHud.instance; if (instance3 != null) { instance3.ShowMessage((MessageType)1, "Njord VFX debug spawns active", 0, (Sprite)null, false); } } catch { } _debugNotified = true; } try { if ((Object)(object)component != (Object)null) { Shader val2 = Shader.Find("Sprites/Default"); if ((Object)(object)val2 != (Object)null) { try { ((Renderer)component).material = new Material(val2); } catch { } } ((Renderer)component).sortingOrder = 32767; } fromPool.layer = 0; try { Transform val3 = fromPool.transform.Find("Njord_DebugQuad"); if ((Object)(object)val3 != (Object)null) { MeshRenderer component2 = ((Component)val3).GetComponent(); MeshFilter component3 = ((Component)val3).GetComponent(); if ((Object)(object)component2 != (Object)null && (Object)(object)component3 != (Object)null) { if ((Object)(object)((Renderer)component2).sharedMaterial == (Object)null) { Shader val4 = Shader.Find("Unlit/Texture") ?? Shader.Find("Unlit/Color") ?? Shader.Find("Sprites/Default"); if ((Object)(object)val4 != (Object)null) { try { Material val5 = new Material(val4); if (val5.HasProperty("_MainTex") && (Object)(object)_runeTex != (Object)null) { val5.SetTexture("_MainTex", (Texture)(object)_runeTex); } if (val5.HasProperty("_Color")) { val5.SetColor("_Color", _color); } val5.renderQueue = 5000; ((Renderer)component2).material = val5; } catch { } } } try { NjordRuntimeConfig instance4 = NjordRuntimeConfig.Instance; float num = Mathf.Max(0.25f, instance4.Debug_Enable ? 1.5f : 0.6f); val3.localScale = Vector3.one * num; } catch { val3.localScale = Vector3.one * 0.6f; } ((Renderer)component2).enabled = true; try { ((Renderer)component2).material.renderQueue = 5000; } catch { } } } } catch { } } catch { } } } catch { } RuneSprite_Fader component4 = fromPool.GetComponent(); if ((Object)(object)component4 != (Object)null) { float num2 = Random.Range(1.5f, 3.5f); float num3 = Random.Range(0.2f, 0.7f); float num4 = Random.Range(-0.4f, 0.4f); Vector3 velocity = Vector3.up * num2 + -_stern.forward * num3 + _stern.right * num4; component4.Play(velocity, _life, _scale * scaleMultiplier, _color); } } } private class RuneSprite_Fader : MonoBehaviour { private SpriteRenderer _sr; private Vector3 _vel; private Vector3 _angularVelocity; private float _life; private float _age; private float _startScale; private Color _startColor; private Action _onFinish; private const float GRAVITY = -0.35f; private const float DRAG = 2.8f; public void Init(Action onFinish) { _sr = ((Component)this).GetComponent(); _onFinish = onFinish; } public void Play(Vector3 velocity, float life, float startScale, Color color) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) _vel = velocity; _life = Mathf.Max(0.01f, life); _age = 0f; _startScale = Mathf.Max(0.01f, startScale); _startColor = color; _angularVelocity = new Vector3(Random.Range(-240f, 240f), Random.Range(-240f, 240f), Random.Range(-240f, 240f)); if ((Object)(object)_sr != (Object)null) { _sr.color = color; ((Component)_sr).transform.localScale = Vector3.one * _startScale; } } private void Update() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) float deltaTime = Time.deltaTime; _age += deltaTime; _vel *= Mathf.Exp(-2.8f * deltaTime); _vel.y += -0.35f * deltaTime; Transform transform = ((Component)this).transform; transform.position += _vel * deltaTime; ((Component)this).transform.Rotate(_angularVelocity * deltaTime, (Space)0); float num = Mathf.Clamp01(_age / _life); if ((Object)(object)_sr != (Object)null) { float num2; if (num < 0.3f) { num2 = 1f; } else { float num3 = (num - 0.3f) / 0.7f; num3 *= num3; num2 = 1f - num3; num2 *= 1f + 0.28f * Mathf.Sin(_age * 18f); num2 = Mathf.Clamp01(num2); } Color startColor = _startColor; startColor.a = _startColor.a * num2; _sr.color = startColor; float num4 = ((num < 0.3f) ? _startScale : Mathf.Lerp(_startScale, 0f, (num - 0.3f) / 0.7f)); ((Component)_sr).transform.localScale = Vector3.one * Mathf.Max(0f, num4); ((Component)_sr).transform.localScale = Vector3.one * num4; } if (_age >= _life) { _onFinish?.Invoke(((Component)this).gameObject); } } } private class WakeSampler : MonoBehaviour { private ParticleSystem _ps; private Particle[] _buffer = (Particle[])(object)new Particle[512]; private float _interval = 0.1f; private float _last; private Color _color = Color.white; private Emitter _emitterRef; public void Init(ParticleSystem ps, Color color, float rate, Emitter emitterRef) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) _ps = ps; _color = color; _interval = Mathf.Max(0.05f, 1f / Mathf.Max(1f, rate)); _last = Time.time - _interval; _emitterRef = emitterRef; } private void Update() { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) try { if (!NjordRuntimeConfig.Instance.VFX_Enable || (Object)(object)_ps == (Object)null || (Object)(object)_emitterRef == (Object)null || Time.time - _last < _interval) { return; } _last = Time.time; int particles = _ps.GetParticles(_buffer); if (particles <= 0) { return; } int num = Mathf.Min(4, particles); int num2 = Mathf.Max(1, particles / num); for (int i = 0; i < particles; i += num2) { Vector3 worldPos = ((Component)_ps).transform.TransformPoint(((Particle)(ref _buffer[i])).position); try { _emitterRef.TrySpawnAt(worldPos); } catch { } } } catch { } } } private const int POOL_INITIAL = 64; private const int POOL_MAX = 1024; private const float VISIBILITY_MULT = 5f; private static Queue _pool = new Queue(); private static GameObject _poolRoot; private static Sprite[] _runeSprites; private static Sprite _runeSprite; private static Texture2D _runeTex; private static Mesh _debugQuadMesh; private static readonly Dictionary _emitters = new Dictionary(); private static readonly Dictionary _wakeSamplers = new Dictionary(); private static bool _inited = false; private static void EnsureInit(Color color) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) if (_inited) { return; } _inited = true; _runeSprites = (Sprite[])(object)new Sprite[16]; for (int i = 0; i < 16; i++) { Texture2D val = NjordRuneTextureGenerator.GenerateRune(Color.white, i); if ((Object)(object)val == (Object)null) { val = new Texture2D(16, 16, (TextureFormat)4, false); Color[] array = (Color[])(object)new Color[256]; for (int j = 0; j < array.Length; j++) { array[j] = Color.white; } val.SetPixels(array); val.Apply(false); } _runeSprites[i] = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); } _runeTex = NjordRuneTextureGenerator.GenerateRune(Color.white, 0); _runeSprite = _runeSprites[0]; NjordDebug.Debug($"[VFX-Sprite] Generated {16} rune sprites."); _poolRoot = new GameObject("NjordRuneSpritePool"); Object.DontDestroyOnLoad((Object)(object)_poolRoot); for (int k = 0; k < 64; k++) { _pool.Enqueue(CreatePooledGO()); } NjordDebug.Log("[VFX-Sprite] Initialized rune sprite trail pool."); } private static GameObject CreatePooledGO() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("NjordRuneSprite"); val.transform.SetParent(_poolRoot.transform, false); SpriteRenderer obj = val.AddComponent(); obj.sprite = _runeSprite; ((Renderer)obj).sortingLayerName = "Default"; ((Renderer)obj).sortingOrder = 5000; ((Renderer)obj).shadowCastingMode = (ShadowCastingMode)0; val.AddComponent().Init(ReturnToPool); try { GameObject val2 = new GameObject("Njord_DebugQuad"); val2.transform.SetParent(val.transform, false); val2.transform.localPosition = Vector3.zero; val2.transform.localRotation = Quaternion.identity; val2.AddComponent().mesh = GetOrCreateDebugQuadMesh(); MeshRenderer obj2 = val2.AddComponent(); ((Renderer)obj2).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)obj2).receiveShadows = false; ((Renderer)obj2).enabled = false; val2.SetActive(true); } catch { } val.SetActive(false); return val; } private static GameObject GetFromPool() { if (_pool.Count > 0) { return _pool.Dequeue(); } if (_pool.Count + 1 <= 1024) { return CreatePooledGO(); } return null; } private static void ReturnToPool(GameObject go) { if (!((Object)(object)go == (Object)null)) { go.SetActive(false); go.transform.SetParent(_poolRoot.transform, false); if (_pool.Count < 1024) { _pool.Enqueue(go); } else { Object.Destroy((Object)(object)go); } } } private static Mesh GetOrCreateDebugQuadMesh() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: 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) //IL_0102: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_debugQuadMesh != (Object)null) { return _debugQuadMesh; } Mesh val = new Mesh(); ((Object)val).name = "Njord_DebugQuadMesh"; Vector3[] vertices = (Vector3[])(object)new Vector3[4] { new Vector3(-0.5f, 0f, -0.5f), new Vector3(0.5f, 0f, -0.5f), new Vector3(0.5f, 0f, 0.5f), new Vector3(-0.5f, 0f, 0.5f) }; int[] triangles = new int[6] { 0, 1, 2, 0, 2, 3 }; Vector2[] uv = (Vector2[])(object)new Vector2[4] { new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(1f, 1f), new Vector2(0f, 1f) }; val.vertices = vertices; val.triangles = triangles; val.uv = uv; val.RecalculateNormals(); val.RecalculateBounds(); _debugQuadMesh = val; return _debugQuadMesh; } public static void SpawnBurst(Vector3 pos, Color color, int count) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: 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) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (!NjordRuntimeConfig.Instance.VFX_Enable) { return; } EnsureInit(color); float life = 12.5f; float startScale = 1.125f; for (int i = 0; i < Mathf.Max(1, count); i++) { GameObject fromPool = GetFromPool(); if (!((Object)(object)fromPool == (Object)null)) { SpriteRenderer component = fromPool.GetComponent(); if ((Object)(object)component != (Object)null) { component.sprite = ((_runeSprites != null) ? _runeSprites[Random.Range(0, _runeSprites.Length)] : _runeSprite); component.color = color; } fromPool.transform.position = pos + Random.insideUnitSphere * 0.35f; fromPool.transform.rotation = Quaternion.Euler(90f, Random.Range(0f, 360f), 0f); fromPool.SetActive(true); RuneSprite_Fader component2 = fromPool.GetComponent(); if ((Object)(object)component2 != (Object)null) { Vector3 velocity = (Random.onUnitSphere + Vector3.back * 1.5f) * 0.4f; component2.Play(velocity, life, startScale, color); } } } } public static void SpawnAtWorldPosition(Vector3 pos, Color color) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) if (!NjordRuntimeConfig.Instance.VFX_Enable) { return; } EnsureInit(color); GameObject fromPool = GetFromPool(); if (!((Object)(object)fromPool == (Object)null)) { SpriteRenderer component = fromPool.GetComponent(); if ((Object)(object)component != (Object)null) { component.sprite = ((_runeSprites != null) ? _runeSprites[Random.Range(0, _runeSprites.Length)] : _runeSprite); component.color = color; } fromPool.transform.position = pos; fromPool.transform.rotation = Quaternion.Euler(90f, Random.Range(0f, 360f), 0f); fromPool.SetActive(true); RuneSprite_Fader component2 = fromPool.GetComponent(); if ((Object)(object)component2 != (Object)null) { Vector3 velocity = Vector3.back * 0.6f + Random.insideUnitSphere * 0.2f; float life = 2.5f; float startScale = 0.3f; component2.Play(velocity, life, startScale, color); } } } public static void StartTrailForShip(object ship, Transform stern, Color color, float rateMultiplier = 1f) { //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) if (ship == null || (Object)(object)stern == (Object)null || !NjordRuntimeConfig.Instance.VFX_Enable) { return; } EnsureInit(color); if (_emitters.TryGetValue(ship, out var value) && (Object)(object)value != (Object)null) { value.SetActive(v: true); value.UpdateParams(stern, color, rateMultiplier); return; } Transform val = stern; try { Component val2 = (Component)((ship is Component) ? ship : null); if (val2 != null && (Object)(object)val2.transform != (Object)null) { val = val2.transform; } } catch { } GameObject val3 = new GameObject($"NjordRuneSpriteEmitter_{ship.GetHashCode()}"); val3.transform.SetParent(val, true); long controllerForShip = Njord_ShipControlTracker.GetControllerForShip(ship); Player localPlayer = Player.m_localPlayer; long num = ((localPlayer != null) ? localPlayer.GetPlayerID() : 0); bool flag = controllerForShip != 0L && num != 0L && controllerForShip == num; Emitter emitter = val3.AddComponent(); emitter.Initialize(stern, color, rateMultiplier, ReturnToPool, _runeSprite, flag); try { if (flag) { val3.transform.position = stern.position - stern.forward * 1f + stern.up * 0.5f; } else { float num2 = 0.25f; float num3 = 1f; float num4 = 0f; Component val4 = (Component)((ship is Component) ? ship : null); if (val4 != null) { string text = ((Object)val4.gameObject).name.Replace("(Clone)", ""); if (text.Contains("VikingShip_Ashlands")) { num4 = 0.55f; num3 = 2.2f; } else if (text.Contains("VikingShip")) { num3 = 2.2f; } } val3.transform.position = stern.TransformPoint(new Vector3(num4, 0f - num2, 0f - num3)); } } catch { } _emitters[ship] = emitter; NjordDebug.Log("[VFX-Sprite] Created sprite emitter for ship."); } public static void StopTrailForShip(object ship) { if (ship != null && _emitters.TryGetValue(ship, out var value) && (Object)(object)value != (Object)null) { value.SetActive(v: false); } } public static void RemoveEmitterForShip(object ship) { if (ship == null) { return; } if (_emitters.TryGetValue(ship, out var value) && (Object)(object)value != (Object)null) { try { if ((Object)(object)((Component)value).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)value).gameObject); } } catch { } } _emitters.Remove(ship); if (!_wakeSamplers.TryGetValue(ship, out var value2) || !((Object)(object)value2 != (Object)null)) { return; } try { if ((Object)(object)((Component)value2).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)value2).gameObject); } } catch { } _wakeSamplers.Remove(ship); } public static void DumpEmitters() { NjordDebug.Info($"[VFX-Sprite] Emitters: count={_emitters.Count} pool={_pool.Count}"); foreach (KeyValuePair emitter in _emitters) { object key = emitter.Key; Emitter value = emitter.Value; if ((Object)(object)value == (Object)null) { NjordDebug.Info($"[VFX-Sprite] Emitter for {key}: null"); continue; } Type type = ((object)value).GetType(); object obj = type.GetField("_active", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(value); object obj2 = type.GetField("_cachedWaterY", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(value); object obj3 = type.GetField("_lastWaterSampleTime", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(value); object obj4 = type.GetField("_waterMask", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(value); object obj5 = type.GetField("_useTelemetry", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(value); object obj6 = type.GetField("_lastSpawnPos", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(value); object obj7 = type.GetField("_stern", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(value); Object val = (Object)((obj7 is Object) ? obj7 : null); bool flag = ((val != null) ? (val != (Object)null) : (obj7 != null)); NjordDebug.Info($"[VFX-Sprite] Emitter for {key}: active={obj} enabled={((Behaviour)value).isActiveAndEnabled} tele={obj5} cachedY={obj2} lastSpawnPos={obj6} lastSample={obj3} mask={obj4} sternAlive={flag}"); } } } public static class NjordRuneVFX { private static bool _initialized; private static GameObject _prefab; private static Material _material; private static Texture2D _runeTex; internal static ParticleSystem _burstSystem; internal static readonly Dictionary _emitters = new Dictionary(); private const float DefaultTrailRate = 30f; private const int DefaultMaxParticles = 400; internal static readonly Dictionary _lastActive = new Dictionary(); public static void DiscoverShaderIfNeeded() { //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Expected O, but got Unknown //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) if (_initialized) { return; } _initialized = true; if (NjordConfig.Debug_Enable.Value) { NjordDebug.Debug("[VFX] Initializing NjordRuneVFX…"); } NjordRuntimeConfig instance = NjordRuntimeConfig.Instance; Texture2D val = (Texture2D)("blend".ToLowerInvariant() switch { "soft" => NjordRuneTextureGenerator.GenerateSoftTrail(instance.VFX_Color), "rune" => NjordRuneTextureGenerator.GenerateRune(instance.VFX_Color), "streak" => NjordRuneTextureGenerator.GenerateStreak(instance.VFX_Color), _ => NjordRuneTextureGenerator.GenerateBlend(instance.VFX_Color), }); if ((Object)(object)val == (Object)null) { NjordDebug.Error("[VFX] Rune texture generation failed."); return; } _runeTex = val; _material = NjordRuneVFX_Helper.GetOrCreateRuneMaterial(val, instance.VFX_Color); if ((Object)(object)_material == (Object)null) { NjordDebug.Error("[VFX] Failed to create rune material (no suitable shader)."); return; } if (_material.HasProperty("_EmissionColor")) { Color vFX_Color = instance.VFX_Color; _material.SetColor("_EmissionColor", vFX_Color * 3f); } _material.SetInt("_SrcBlend", 1); _material.SetInt("_DstBlend", 1); _material.SetInt("_ZWrite", 0); _material.DisableKeyword("_ALPHATEST_ON"); _material.EnableKeyword("_ALPHABLEND_ON"); _material.EnableKeyword("_ALPHAPREMULTIPLY_ON"); _material.renderQueue = 3000; _prefab = BuildPrefab(_material); if ((Object)(object)_prefab == (Object)null) { NjordDebug.Error("[VFX] Failed to build rune prefab."); return; } GameObject obj = Object.Instantiate(_prefab); ((Object)obj).name = "NjordRuneVFX_BurstSystem"; obj.SetActive(true); _burstSystem = obj.GetComponent(); if ((Object)(object)_burstSystem != (Object)null) { EmissionModule emission = _burstSystem.emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(0f); _burstSystem.Stop(); } GameObject val2 = new GameObject("NjordRuneVFX_Manager"); val2.AddComponent(); Object.DontDestroyOnLoad((Object)val2); if (NjordConfig.Debug_Enable.Value) { NjordDebug.Debug("[VFX] NjordRuneVFX initialized successfully."); } } public static void Spawn(Vector3 pos, Color color) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) SpawnBurst(pos, color, 6); } public static void Spawn(Vector3 pos) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) NjordRuntimeConfig instance = NjordRuntimeConfig.Instance; Spawn(pos, instance.VFX_Color); } private static GameObject BuildPrefab(Material mat) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Expected O, but got Unknown //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: Unknown result type (might be due to invalid IL or missing references) //IL_0207: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("NjordRuneVFX_Particle"); ParticleSystem val2 = val.AddComponent(); MainModule main = val2.main; ((MainModule)(ref main)).playOnAwake = false; ((MainModule)(ref main)).loop = true; ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)1; ((MainModule)(ref main)).startLifetime = new MinMaxCurve(0.8f, 1.4f); ((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(0.6f); ((MainModule)(ref main)).startSize = new MinMaxCurve(0.18f, 0.42f); ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(Color.white); ((MainModule)(ref main)).maxParticles = 400; EmissionModule emission = val2.emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(0f); ShapeModule shape = val2.shape; ((ShapeModule)(ref shape)).enabled = true; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)4; ((ShapeModule)(ref shape)).angle = 10f; ((ShapeModule)(ref shape)).radius = 0.15f; ((ShapeModule)(ref shape)).position = Vector3.zero; ((ShapeModule)(ref shape)).rotation = Vector3.zero; VelocityOverLifetimeModule velocityOverLifetime = val2.velocityOverLifetime; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).enabled = true; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).space = (ParticleSystemSimulationSpace)0; ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).x = new MinMaxCurve(0f); ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).y = new MinMaxCurve(-0.05f, 0.05f); ((VelocityOverLifetimeModule)(ref velocityOverLifetime)).z = new MinMaxCurve(-1.6f, -0.6f); ColorOverLifetimeModule colorOverLifetime = val2.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true; Gradient val3 = new Gradient(); val3.SetKeys((GradientColorKey[])(object)new GradientColorKey[2] { new GradientColorKey(Color.white, 0f), new GradientColorKey(Color.white, 1f) }, (GradientAlphaKey[])(object)new GradientAlphaKey[2] { new GradientAlphaKey(1f, 0f), new GradientAlphaKey(0f, 1f) }); ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = new MinMaxGradient(val3); SizeOverLifetimeModule sizeOverLifetime = val2.sizeOverLifetime; ((SizeOverLifetimeModule)(ref sizeOverLifetime)).enabled = true; MinMaxCurve size = default(MinMaxCurve); ((MinMaxCurve)(ref size))..ctor(1f, AnimationCurve.EaseInOut(0f, 1f, 1f, 0.2f)); ((SizeOverLifetimeModule)(ref sizeOverLifetime)).size = size; ParticleSystemRenderer component = val.GetComponent(); component.renderMode = (ParticleSystemRenderMode)0; ((Renderer)component).material = mat; ((Renderer)component).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)component).receiveShadows = false; val.SetActive(false); if (NjordConfig.Debug_Enable.Value) { NjordDebug.Debug("[VFX] Rune particle prefab constructed."); } return val; } private static ParticleSystem GetOrCreateEmitterForShip(object ship, Transform stern, Color color) { //IL_0312: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_0348: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Expected O, but got Unknown //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Expected O, but got Unknown if (ship == null || (Object)(object)stern == (Object)null) { return null; } if (!_initialized) { DiscoverShaderIfNeeded(); } if ((Object)(object)_prefab == (Object)null) { return null; } if (_emitters.TryGetValue(ship, out var value) && (Object)(object)value != (Object)null) { return value; } GameObject val = Object.Instantiate(_prefab, stern.position, stern.rotation); ((Object)val).name = $"NjordRuneVFX_Emitter_{ship.GetHashCode()}"; Vector3 position = stern.TransformPoint(new Vector3(0f, -0.6f, -0.6f)); val.transform.position = position; val.transform.rotation = stern.rotation; val.transform.SetParent(stern, true); val.SetActive(true); value = val.GetComponent(); if ((Object)(object)value == (Object)null) { return null; } ParticleSystemRenderer component = val.GetComponent(); if ((Object)(object)component != (Object)null && (Object)(object)_material != (Object)null) { ((Renderer)component).material = new Material(_material); Material material = ((Renderer)component).material; if (material.HasProperty("_Color")) { material.SetColor("_Color", color); } if (material.HasProperty("_TintColor")) { material.SetColor("_TintColor", color * 2f); } if (material.HasProperty("_EmissionColor")) { material.SetColor("_EmissionColor", color * 3f); } try { Shader val2 = Shader.Find("Particles/Standard Unlit") ?? Shader.Find("Legacy Shaders/Particles/Alpha Blended") ?? Shader.Find("Particles/Alpha Blended"); if ((Object)(object)val2 != (Object)null) { Material val3 = new Material(val2); Texture2D val4 = _runeTex; if ((Object)(object)val4 == (Object)null) { try { Material material2 = _material; Texture obj = ((material2 != null) ? material2.GetTexture("_MainTex") : null); val4 = (Texture2D)(object)((obj is Texture2D) ? obj : null); } catch { } try { if ((Object)(object)val4 == (Object)null) { Material material3 = _material; Texture obj3 = ((material3 != null) ? material3.mainTexture : null); val4 = (Texture2D)(object)((obj3 is Texture2D) ? obj3 : null); } } catch { } } if ((Object)(object)val4 != (Object)null) { if (val3.HasProperty("_MainTex")) { val3.SetTexture("_MainTex", (Texture)(object)val4); } if (val3.HasProperty("_BaseMap")) { val3.SetTexture("_BaseMap", (Texture)(object)val4); } try { val3.mainTexture = (Texture)(object)val4; } catch { } } if (val3.HasProperty("_Color")) { val3.SetColor("_Color", color); } if (val3.HasProperty("_EmissionColor")) { val3.SetColor("_EmissionColor", color * 3f); } try { val3.SetInt("_SrcBlend", 5); val3.SetInt("_DstBlend", 10); val3.SetInt("_ZWrite", 0); val3.DisableKeyword("_ALPHATEST_ON"); val3.EnableKeyword("_ALPHABLEND_ON"); val3.DisableKeyword("_ALPHAPREMULTIPLY_ON"); val3.renderQueue = 3000; } catch { } ((Renderer)component).material = val3; material = ((Renderer)component).material; } } catch { } } MainModule main = value.main; ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(color); ((MainModule)(ref main)).startLifetime = new MinMaxCurve(0.5f, 1.6f); ((MainModule)(ref main)).startSize = new MinMaxCurve(0.12f, 1f); ((MainModule)(ref main)).maxParticles = 400; value.Stop(true, (ParticleSystemStopBehavior)1); _emitters[ship] = value; _lastActive[ship] = Time.time; if (NjordConfig.Debug_Enable.Value) { NjordDebug.Debug($"[VFX] Created emitter for ship {ship}."); } return value; } public static void StartTrailForShip(object ship, Transform stern, Color color, float rateMultiplier = 1f) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) try { NjordRuneSpriteTrail.StartTrailForShip(ship, stern, color, rateMultiplier); } catch { } } public static void StopTrailForShip(object ship) { try { NjordRuneSpriteTrail.StopTrailForShip(ship); } catch { } } public static void SpawnBurst(Vector3 pos, Color color, int count) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (!NjordRuntimeConfig.Instance.VFX_Enable) { return; } try { NjordRuneSpriteTrail.SpawnBurst(pos, color, count); } catch { } } public static void RemoveEmitterForShip(object ship) { if (ship == null) { return; } try { NjordRuneSpriteTrail.RemoveEmitterForShip(ship); } catch { } if (_emitters.TryGetValue(ship, out var value) && (Object)(object)value != (Object)null) { try { if ((Object)(object)((Component)value).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)value).gameObject); } } catch { } } _emitters.Remove(ship); _lastActive.Remove(ship); if (NjordConfig.Debug_Enable.Value) { NjordDebug.Debug($"[VFX] Removed emitter for ship {ship} (destroy hook)."); } } } public class NjordRuneVFX_Manager : MonoBehaviour { private float _timer; private const float CHECK_INTERVAL = 5f; private void Update() { _timer += Time.deltaTime; if (_timer < 5f) { return; } _timer = 0f; _ = NjordRuntimeConfig.Instance; float num = 15f; foreach (object item in new List(NjordRuneVFX._emitters.Keys)) { if (!NjordRuneVFX._emitters.TryGetValue(item, out var value) || (Object)(object)value == (Object)null) { NjordRuneVFX._emitters.Remove(item); NjordRuneVFX._lastActive.Remove(item); continue; } if (!NjordRuneVFX._lastActive.TryGetValue(item, out var value2)) { value2 = Time.time; } if (!(Time.time - value2 > num)) { continue; } try { if ((Object)(object)((Component)value).gameObject != (Object)null) { Object.Destroy((Object)(object)((Component)value).gameObject); } } catch { } NjordRuneVFX._emitters.Remove(item); NjordRuneVFX._lastActive.Remove(item); if (NjordConfig.Debug_Enable.Value) { NjordDebug.Debug($"[VFX] Cleaned up emitter for ship {item} after timeout."); } } } } public static class NjordRuneVFX_Helper { private static readonly Dictionary _materialCache = new Dictionary(); private static bool _initialized = false; private static void Init() { if (!_initialized) { _initialized = true; NjordDebug.Log("\ud83d\udf01 VFX‑Forge: Seeking glowing, additive, unlit shaders worthy of Njord."); } } private unsafe static long MakeCacheKey(Shader shader, Texture2D tex, Color color) { int num = (((Object)(object)shader != (Object)null) ? ((Object)shader).GetInstanceID() : 0); int num2 = (((Object)(object)tex != (Object)null) ? ((Object)tex).GetInstanceID() : 0); int hashCode = ((object)(*(Color*)(&color))/*cast due to .constrained prefix*/).GetHashCode(); return (long)((ulong)((long)num << 32) ^ ((ulong)(uint)num2 << 16) ^ (uint)hashCode); } public static Material GetOrCreateRuneMaterial(Texture2D runeTex, Color color) { //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Expected O, but got Unknown //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Unknown result type (might be due to invalid IL or missing references) Init(); Shader val = Shader.Find("Particles/Standard Unlit") ?? Shader.Find("Legacy Shaders/Particles/Alpha Blended") ?? Shader.Find("Particles/Alpha Blended") ?? Shader.Find("Particles/Additive"); if ((Object)(object)val == (Object)null) { float num = float.MinValue; Material[] array = Resources.FindObjectsOfTypeAll(); foreach (Material val2 in array) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.shader == (Object)null)) { Shader shader = val2.shader; string text = ((Object)shader).name.ToLower(); float num2 = 0f; if (text.Contains("particle")) { num2 += 3f; } if (text.Contains("add")) { num2 += 3f; } if (text.Contains("unlit")) { num2 += 2f; } if (text.Contains("transparent")) { num2 += 1.5f; } if (val2.HasProperty("_Color") && val2.HasProperty("_EmissionColor") && num2 > num) { num = num2; val = shader; } } } } if ((Object)(object)val == (Object)null) { NjordDebug.Error("\ud83d\udf01 VFX‑Forge: No glowing shader found. The runes refuse to shine."); return null; } long key = MakeCacheKey(val, runeTex, color); if (_materialCache.TryGetValue(key, out var value) && (Object)(object)value != (Object)null) { return value; } Material val3 = new Material(val); if ((Object)(object)runeTex != (Object)null) { if (val3.HasProperty("_MainTex")) { val3.SetTexture("_MainTex", (Texture)(object)runeTex); } if (val3.HasProperty("_BaseMap")) { val3.SetTexture("_BaseMap", (Texture)(object)runeTex); } try { val3.mainTexture = (Texture)(object)runeTex; } catch { } } if (val3.HasProperty("_Color")) { val3.SetColor("_Color", color); } if (val3.HasProperty("_TintColor")) { val3.SetColor("_TintColor", color); } if (val3.HasProperty("_EmissionColor")) { val3.SetColor("_EmissionColor", color * 3f); } val3.SetInt("_SrcBlend", 1); val3.SetInt("_DstBlend", 1); val3.SetInt("_ZWrite", 0); val3.DisableKeyword("_ALPHATEST_ON"); val3.EnableKeyword("_ALPHABLEND_ON"); val3.DisableKeyword("_ALPHAPREMULTIPLY_ON"); val3.renderQueue = 3000; _materialCache[key] = val3; NjordDebug.Log("\ud83d\udf01 VFX‑Forge: Forged glowing additive rune material from '" + ((Object)val).name + "'."); return val3; } public static void ClearCache() { _materialCache.Clear(); _initialized = false; } } public static class NjordSeaDogEngineVFXTriggers { public static readonly Dictionary LastController = new Dictionary(); public static readonly Dictionary LastSpeed = new Dictionary(); public static readonly Dictionary LastVfxTime = new Dictionary(); public static readonly Dictionary LastTrailLog = new Dictionary(); private static readonly Dictionary _rudderCache = new Dictionary(); public static Transform GetStern(Ship ship) { if ((Object)(object)ship == (Object)null) { return null; } if (_rudderCache.TryGetValue(ship, out var value) && (Object)(object)value != (Object)null) { return value; } try { ShipControlls componentInChildren = ((Component)ship).GetComponentInChildren(true); if ((Object)(object)componentInChildren != (Object)null) { _rudderCache[ship] = ((Component)componentInChildren).transform; return ((Component)componentInChildren).transform; } } catch { } _rudderCache[ship] = ((Component)ship).transform; return ((Component)ship).transform; } public static void Process(Ship ship, NjordSailState state, string speedStr, long controller, float now, Transform tf, bool debug, NjordRuntimeConfig cfg) { //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0138: 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) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) if (!cfg.VFX_Enable) { return; } if (!LastVfxTime.TryGetValue(ship, out var value)) { value = 0f; } if (!LastController.TryGetValue(ship, out var value2)) { value2 = 0L; } if (!LastSpeed.TryGetValue(ship, out var value3)) { value3 = "Stop"; } if (controller != value2) { LastController[ship] = controller; if (controller != 0L) { if (debug) { NjordDebug.Debug("[SeaDog][VFX] Control change: spawning control burst"); } LastVfxTime[ship] = now; NjordRuneVFX.SpawnBurst(GetStern(ship).position + Vector3.up * 1.2f, cfg.VFX_Color, 8); } else { try { NjordRuneVFX.StopTrailForShip(ship); } catch { } } } if (speedStr != value3) { LastSpeed[ship] = speedStr; if (speedStr == "Half" || speedStr == "Full") { if (debug) { NjordDebug.Debug("[SeaDog][VFX] Sail state change to " + speedStr + ": spawning burst"); } LastVfxTime[ship] = now; Vector3 val = GetStern(ship).position + Vector3.up * 1.5f; for (int i = 0; i < 4; i++) { Vector3 insideUnitSphere = Random.insideUnitSphere; insideUnitSphere.y = Mathf.Abs(insideUnitSphere.y) + 0.3f; NjordRuneVFX.SpawnBurst(val + insideUnitSphere * 0.2f, cfg.VFX_Color, 1); } } } float num = 0f; try { num = ship.GetSpeed(); } catch { num = 0f; } Transform stern = GetStern(ship); if (speedStr != "Stop" && speedStr != "Back" && num > 0.5f) { float maxSpeedForShip = NjordShipSpeed.GetMaxSpeedForShip(ship); float num2 = ((maxSpeedForShip > 0f) ? (num / maxSpeedForShip) : Mathf.Clamp01(num / 10f)); float num3 = Mathf.Clamp(0.5f + num2 * 2f, 0.2f, 4f); if (debug) { LastTrailLog.TryGetValue(ship, out var value4); if (now - value4 >= 2f) { NjordDebug.Debug($"[SeaDog][VFX] Starting trail for ship {ship} at stern {((stern != null) ? ((Object)stern).name : null)} rateMul={num3:F2}"); LastTrailLog[ship] = now; } } NjordRuneVFX.StartTrailForShip(ship, stern, cfg.VFX_Color, num3); LastVfxTime[ship] = now; return; } if (debug) { LastTrailLog.TryGetValue(ship, out var value5); if (now - value5 >= 2f) { NjordDebug.Debug($"[SeaDog][VFX] Stopping trail for ship {ship}"); LastTrailLog[ship] = now; } } NjordRuneVFX.StopTrailForShip(ship); } } } namespace Njord.Patches { [HarmonyPatch(typeof(Player), "StartDoodadControl")] public static class NjordDoodadControlRune { private static void Postfix(Player __instance, IDoodadController shipControl) { if ((Object)(object)__instance == (Object)null || shipControl == null) { return; } ShipControlls val = (ShipControlls)(object)((shipControl is ShipControlls) ? shipControl : null); if (val == null) { return; } Ship ship = val.m_ship; if ((Object)(object)ship == (Object)null) { return; } long playerID = __instance.GetPlayerID(); if (!NjordAuthorityEngine.UseLegacyFallback && (Object)(object)ZNet.instance != (Object)null) { if (ZNet.instance.IsServer()) { NjordAuthorityEngine.Server_OnHelmClaim(ship, playerID); } else { NjordAuthorityEngine.Client_RequestControl(ship); } } Njord_ShipControlTracker.SetControl(ship, playerID); ZNetView component = ((Component)ship).GetComponent(); if ((Object)(object)component != (Object)null && component.IsValid()) { component.ClaimOwnership(); if (NjordConfig.Debug_Enable.Value) { NjordDebug.Debug("[Helm‑Bind] Claimed ZDO ownership for " + ((Object)ship).name + "."); } } if (NjordConfig.Debug_Enable.Value) { NjordDebug.Debug($"[Helm‑Bind] Player {playerID} takes helm of {((Object)ship).name}."); } } } [HarmonyPatch(typeof(ShipControlls), "OnUseStop")] public static class NjordDoodadReleaseRune { private static void Postfix(ShipControlls __instance, Player player) { if ((Object)(object)__instance == (Object)null || (Object)(object)player == (Object)null) { return; } Ship ship = __instance.m_ship; if ((Object)(object)ship == (Object)null) { return; } long playerID = player.GetPlayerID(); if (Njord_ShipControlTracker.GetControllerForShip(ship) != playerID) { return; } if (!NjordAuthorityEngine.UseLegacyFallback && (Object)(object)ZNet.instance != (Object)null) { if (ZNet.instance.IsServer()) { NjordAuthorityEngine.Server_OnHelmRelease(ship); } else { NjordAuthorityEngine.Client_ReleaseControl(ship); } } Njord_ShipControlTracker.ClearControl(ship); if (NjordConfig.Debug_Enable.Value) { NjordDebug.Debug($"[Helm‑Release] Player {playerID} released helm of {((Object)ship).name}."); } } } [HarmonyPatch] public static class NjordSeaDogEngine { private static float _telemetryTimer = 0f; private const float TELEMETRY_INTERVAL = 0.2f; private static float _prevNjordSpeed = 0f; private static float _prevVanillaSpeed = 0f; private static float _lastTickLog = -10f; private const float TICK_LOG_INTERVAL = 2f; private static readonly Dictionary _lastDebugLog = new Dictionary(); private static MethodBase TargetMethod() { Type type = AccessTools.TypeByName("Ship"); if (type == null) { NjordDebug.Error("NjordSeaDogEngine: Ship type not found."); return null; } MethodInfo methodInfo = AccessTools.Method(type, "CustomFixedUpdate", (Type[])null, (Type[])null); if (methodInfo == null) { NjordDebug.Error("NjordSeaDogEngine: CustomFixedUpdate not found on Ship."); } return methodInfo; } public static float Safe(float v) { if (!float.IsNaN(v) && !float.IsInfinity(v)) { return v; } return 0f; } private static void Prefix(object __instance, float fixedDeltaTime) { //IL_0854: Unknown result type (might be due to invalid IL or missing references) //IL_085c: Unknown result type (might be due to invalid IL or missing references) //IL_040c: Unknown result type (might be due to invalid IL or missing references) //IL_06f2: Unknown result type (might be due to invalid IL or missing references) //IL_06f9: Unknown result type (might be due to invalid IL or missing references) //IL_06fe: Unknown result type (might be due to invalid IL or missing references) //IL_0757: Unknown result type (might be due to invalid IL or missing references) //IL_075c: Unknown result type (might be due to invalid IL or missing references) //IL_0709: Unknown result type (might be due to invalid IL or missing references) //IL_070b: Unknown result type (might be due to invalid IL or missing references) //IL_0702: Unknown result type (might be due to invalid IL or missing references) //IL_0707: Unknown result type (might be due to invalid IL or missing references) //IL_06db: Unknown result type (might be due to invalid IL or missing references) //IL_06e0: Unknown result type (might be due to invalid IL or missing references) //IL_06e7: Unknown result type (might be due to invalid IL or missing references) //IL_06ec: Unknown result type (might be due to invalid IL or missing references) //IL_071d: Unknown result type (might be due to invalid IL or missing references) //IL_0726: Unknown result type (might be due to invalid IL or missing references) //IL_072c: Unknown result type (might be due to invalid IL or missing references) //IL_0778: Unknown result type (might be due to invalid IL or missing references) //IL_077f: Unknown result type (might be due to invalid IL or missing references) //IL_0784: Unknown result type (might be due to invalid IL or missing references) //IL_0788: Unknown result type (might be due to invalid IL or missing references) if (__instance == null || fixedDeltaTime <= 0f) { return; } bool value = NjordConfig.Debug_Enable.Value; bool flag = value && Time.fixedTime - _lastTickLog >= 2f; if (flag) { NjordDebug.Debug($"[SeaDog] Tick dt={fixedDeltaTime:0.000}"); _lastTickLog = Time.fixedTime; } Type type = __instance.GetType(); object obj = AccessTools.Field(type, "m_nview")?.GetValue(__instance); if (obj == null) { return; } MethodInfo methodInfo = AccessTools.Method(obj.GetType(), "IsValid", (Type[])null, (Type[])null); if (methodInfo != null && !(bool)methodInfo.Invoke(obj, null)) { return; } object? obj2 = AccessTools.Field(type, "m_body")?.GetValue(__instance); Rigidbody val = (Rigidbody)((obj2 is Rigidbody) ? obj2 : null); if (val == null || (Object)(object)val == (Object)null || float.IsNaN(val.mass) || val.mass <= 0f) { return; } FieldInfo fieldInfo = AccessTools.Field(type, "m_lastDepth"); if (fieldInfo != null && (float)fieldInfo.GetValue(__instance) <= -9000f) { return; } long controllerForShip = Njord_ShipControlTracker.GetControllerForShip(__instance); long num = (((Object)(object)Player.m_localPlayer != (Object)null) ? Player.m_localPlayer.GetPlayerID() : 0); bool flag2 = controllerForShip != 0L && num != 0L && controllerForShip == num; Njord_ShipControlTracker.UpdateController(controllerForShip, fixedDeltaTime); if (flag2) { ZNetView val2 = (ZNetView)((obj is ZNetView) ? obj : null); if (val2 != null && val2.IsValid() && !val2.IsOwner()) { val2.ClaimOwnership(); if (flag) { NjordDebug.Debug("[SeaDog] ZDO ownership reclaimed for locally controlled ship."); } } } float num2 = 0f; float num3 = 0f; float num4 = 1f; float num5 = 0f; float num6 = 1f; Ship val3 = (Ship)((__instance is Ship) ? __instance : null); if (val3 != null) { NjordRuntimeConfig instance = NjordRuntimeConfig.Instance; float shipWindAngle = Njord_ShipControlTracker.GetShipWindAngle(val3); if (instance.Wind_SystemEnable) { num2 = Mathf.DeltaAngle(0f, val3.GetWindAngle()); num3 = num2; if (instance.Wind_AlwaysFull) { num3 = 0f; } else { bool flag3 = Mathf.Abs(num2) > 130f; bool shipWasInDeadZone = Njord_ShipControlTracker.GetShipWasInDeadZone(val3, flag3); float shipGraceTimer = Njord_ShipControlTracker.GetShipGraceTimer(val3); if (flag3 != shipWasInDeadZone) { shipGraceTimer = 0f; Njord_ShipControlTracker.SetShipWasInDeadZone(val3, flag3); } else { shipGraceTimer += fixedDeltaTime; } Njord_ShipControlTracker.SetShipGraceTimer(val3, shipGraceTimer); float num7 = num2; if (flag3 && instance.Wind_NoDeadZone) { FieldInfo fieldInfo2 = AccessTools.Field(type, "m_rudder") ?? AccessTools.Field(type, "m_rudderValue"); float num8 = ((fieldInfo2 != null) ? ((float)fieldInfo2.GetValue(__instance)) : 0f); float num9 = 115f; num7 = ((num8 > 0.05f) ? (0f - num9) : ((!(num8 < -0.05f)) ? ((num2 > 0f) ? num9 : (0f - num9)) : num9)); } else if (!flag3 && instance.Wind_BlendToFull) { num7 = 0f; } num3 = ((!(shipGraceTimer < instance.Wind_GracePeriodDelay)) ? num7 : num2); } num5 = Mathf.MoveTowardsAngle(shipWindAngle, num3, instance.Wind_BlendRate * fixedDeltaTime); Njord_ShipControlTracker.SetShipWindAngle(val3, num5); Njord_Telemetry.WindUIBlend = num5; float num10 = Mathf.Abs(num5); num4 = ((num10 > 130f) ? 0f : ((!(num10 > 90f)) ? Mathf.Lerp(1f, 0.75f, num10 / 90f) : Mathf.Lerp(0.75f, 0f, (num10 - 90f) / 40f))); } else { num6 = val3.GetWindAngleFactor(); } } AccessTools.Field(type, "m_sailForceFactor")?.SetValue(__instance, 0f); AccessTools.Field(type, "m_sailForceOffset")?.SetValue(__instance, 0f); AccessTools.Field(type, "m_backwardForce")?.SetValue(__instance, 0f); AccessTools.Field(type, "m_sailForce")?.SetValue(__instance, Vector3.zero); string text = AccessTools.Method(type, "GetSpeedSetting", (Type[])null, (Type[])null)?.Invoke(__instance, null)?.ToString() ?? "Stop"; NjordSailState njordSailState = text switch { "Back" => NjordSailState.Backward, "Half" => NjordSailState.Half, "Full" => NjordSailState.Full, "Slow" => NjordSailState.Forward, "Stop" => NjordSailState.Forward, _ => NjordSailState.Forward, }; string shipPrefabName = NjordBoatController.GetShipPrefabName(__instance); float v = NjordBoatController.GetBaseline(njordSailState, shipPrefabName); if (text == "Stop") { v = 0f; } v = Safe(v); float v2 = NjordBoatController.ApplyAcceleration(v, fixedDeltaTime); v2 = Safe(v2); float sailMult = NjordBoatController.GetSailMult(njordSailState); sailMult = Safe(sailMult); if (text == "Half" || text == "Full") { sailMult = ((!NjordRuntimeConfig.Instance.Wind_SystemEnable) ? (sailMult * num6) : (sailMult * num4)); } float num11 = Safe(v2 * sailMult * 0.85f); float num12 = Safe(NjordBoatController.GetReverseForce(fixedDeltaTime)); num11 = Mathf.Clamp(num11, 0f, 2000f); num12 = Mathf.Clamp(num12, 0f, 2000f); Ship val4 = (Ship)((__instance is Ship) ? __instance : null); if (val4 != null) { NjordRuntimeConfig instance2 = NjordRuntimeConfig.Instance; if (instance2.Debug_Enable && instance2.Debug_PhysicsWind && (!_lastDebugLog.TryGetValue(val4, out var value2) || Time.time - value2 > 1f)) { _lastDebugLog[val4] = Time.time; string text2 = (instance2.Wind_SystemEnable ? "ON " : "OFF"); NjordDebug.Info($"[Physics] {shipPrefabName} | mode={text} | baseline={v:F1} | accel={v2:F1} | mult={sailMult:F2} | fwForce={num11:F1}"); if (instance2.Wind_SystemEnable) { NjordDebug.Info($"[Wind] Sys:{text2} | AlwaysFull:{instance2.Wind_AlwaysFull} | NatAngle:{num2:F1}° | TgtAngle:{num3:F1}° | CurAngle:{num5:F1}° | Throttle:{num4:F2}"); } } } object? obj3 = AccessTools.Property(type, "transform")?.GetValue(__instance); Transform val5 = (Transform)((obj3 is Transform) ? obj3 : null); if ((Object)(object)val5 == (Object)null) { return; } if (flag2) { Vector3 val6; switch (njordSailState) { case NjordSailState.Backward: val6 = -val5.forward * num12; break; case NjordSailState.Forward: case NjordSailState.Half: case NjordSailState.Full: val6 = val5.forward * num11; break; default: val6 = Vector3.zero; break; } Vector3 val7 = val6; if (((Vector3)(ref val7)).sqrMagnitude > 0.0001f) { val.AddForce(val7 * val.mass * fixedDeltaTime, (ForceMode)1); } } Ship val8 = (Ship)((__instance is Ship) ? __instance : null); if (val8 != null) { float maxSpeedForShip = NjordShipSpeed.GetMaxSpeedForShip(val8); if (maxSpeedForShip > 0f) { Vector3 linearVelocity = val.linearVelocity; float magnitude = ((Vector3)(ref linearVelocity)).magnitude; if (magnitude > maxSpeedForShip && magnitude > 0.0001f) { Vector3 linearVelocity2 = ((Vector3)(ref linearVelocity)).normalized * maxSpeedForShip; val.linearVelocity = linearVelocity2; if (value && flag) { NjordDebug.Debug($"[SeaDog][Limiter] {((Object)val8).name} {magnitude:0.00} → {maxSpeedForShip:0.00}"); } } } } Ship val9 = (Ship)((__instance is Ship) ? __instance : null); if (val9 != null) { try { NjordSeaDogEngineVFXTriggers.Process(val9, njordSailState, text, controllerForShip, Time.time, val5, value, NjordRuntimeConfig.Instance); } catch (Exception arg) { NjordDebug.Error($"[VFX] Exception in NjordSeaDogEngineVFXTriggers.Process: {arg}"); } } if (!flag2) { return; } Ship val10 = (Ship)((__instance is Ship) ? __instance : null); if (val10 == null) { return; } if (value && flag) { NjordDebug.Debug($"[SeaDog] Controlled ship tick: speedState={text}, vel={val10.GetSpeed():0.0}"); } _telemetryTimer += fixedDeltaTime; if (!(_telemetryTimer >= 0.2f)) { return; } _telemetryTimer = 0f; Vector3 position = ((Component)val10).transform.position; WaterVolume val11 = null; float waterLevel = Floating.GetWaterLevel(position, ref val11); float num13 = position.y - waterLevel - val10.m_waterLevelOffset; bool floating = num13 <= val10.m_disableLevel; WearNTear component = ((Component)val10).GetComponent(); if ((Object)(object)component != (Object)null) { object? obj4 = AccessTools.Field(typeof(WearNTear), "m_nview")?.GetValue(component); ZNetView val12 = (ZNetView)((obj4 is ZNetView) ? obj4 : null); if ((Object)(object)val12 != (Object)null && val12.IsValid()) { float num14 = Mathf.Max(1f, Safe(component.m_health)); float v3 = val12.GetZDO().GetFloat(ZDOVars.s_health, num14); v3 = Mathf.Max(0f, Safe(v3)); Njord_Telemetry.SetHP(v3, num14); } else { Njord_Telemetry.SetHP(0f, 1f); } } else { Njord_Telemetry.SetHP(0f, 1f); } float num15 = Safe(val10.GetSpeed()); float num16 = Safe(v); Njord_Telemetry.UpdateBasic(val10, waterLevel, num13, floating, Njord_ShipControlTracker.ReadyTimer, Njord_ShipControlTracker.SteeringGateReady); Njord_Telemetry.UpdateSpeed(_prevNjordSpeed, num15, _prevVanillaSpeed, num16); _prevNjordSpeed = num15; _prevVanillaSpeed = num16; } } [HarmonyPatch(typeof(Hud), "UpdateShipHud")] public static class NjordTheWindsCall { [HarmonyPostfix] public static void Postfix(Hud __instance, Player player, float dt) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0279: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0219: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_033c: Unknown result type (might be due to invalid IL or missing references) //IL_0341: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_02fd: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || (Object)(object)player == (Object)null) { return; } Ship controlledShip = player.GetControlledShip(); if ((Object)(object)controlledShip == (Object)null) { return; } NjordRuntimeConfig instance = NjordRuntimeConfig.Instance; if (instance == null || !instance.Wind_SystemEnable) { return; } float shipWindAngle = Njord_ShipControlTracker.GetShipWindAngle(controlledShip); FieldInfo fieldInfo = AccessTools.Field(typeof(Hud), "m_shipWindIconRoot"); if (fieldInfo != null) { object? value = fieldInfo.GetValue(__instance); RectTransform val = (RectTransform)((value is RectTransform) ? value : null); if ((Object)(object)val != (Object)null) { ((Transform)val).localRotation = Quaternion.Euler(0f, 0f, shipWindAngle); } } Image shipWindIcon = __instance.m_shipWindIcon; if ((Object)(object)shipWindIcon == (Object)null) { return; } float num = Mathf.DeltaAngle(0f, controlledShip.GetWindAngle()); float num2 = num; bool flag = Mathf.Abs(num) > 130f; if (instance.Wind_AlwaysFull) { num2 = 0f; } else { float num3 = num; if (flag && instance.Wind_NoDeadZone) { FieldInfo fieldInfo2 = AccessTools.Field(typeof(Ship), "m_rudder") ?? AccessTools.Field(typeof(Ship), "m_rudderValue"); float num4 = ((fieldInfo2 != null) ? ((float)fieldInfo2.GetValue(controlledShip)) : 0f); float num5 = 115f; num3 = ((num4 > 0.05f) ? (0f - num5) : ((!(num4 < -0.05f)) ? ((num > 0f) ? num5 : (0f - num5)) : num5)); } else if (!flag && instance.Wind_BlendToFull) { num3 = 0f; } num2 = ((!(Njord_ShipControlTracker.GetShipGraceTimer(controlledShip) < instance.Wind_GracePeriodDelay)) ? num3 : num); } float num6 = Mathf.Abs(shipWindAngle); Color color = Color.white; if (Mathf.Abs(Mathf.DeltaAngle(shipWindAngle, num2)) > 2f && (instance.Wind_AlwaysFull || instance.Wind_NoDeadZone || instance.Wind_BlendToFull)) { float num7 = (Mathf.Sin(Time.time * 6f) + 1f) / 2f; color = ((!flag) ? Color.Lerp(new Color(0.4f, 0.7f, 1f, 1f), new Color(0.1f, 0.3f, 1f, 1f), num7) : Color.Lerp(new Color(1f, 0.4f, 0.4f, 1f), new Color(1f, 0.1f, 0.1f, 1f), num7)); } else if (flag) { ((Color)(ref color))..ctor(1f, 0.2f, 0.2f, 1f); } else if (num6 <= 45f) { color = Color.green; } else if (num6 <= 90f) { float num8 = (num6 - 45f) / 45f; color = Color.Lerp(new Color(0.3f, 0.6f, 1f, 1f), Color.green, 1f - num8); } else { float num9 = (num6 - 90f) / 40f; color = Color.Lerp(Color.white, new Color(0.3f, 0.6f, 1f, 1f), 1f - num9); } ((Graphic)shipWindIcon).color = color; } } [HarmonyPatch(typeof(Ship), "OnDestroy")] public static class Njord_Ship_Destroy_Patch { [HarmonyPostfix] public static void Postfix(Ship __instance) { try { if ((Object)(object)__instance != (Object)null) { NjordRuneVFX.RemoveEmitterForShip(__instance); } } catch { } } } [HarmonyPatch(typeof(Player), "OnSpawned")] public static class Njord_PlayerSpawned_Init { [HarmonyPostfix] public static void Postfix(Player __instance) { ((MonoBehaviour)__instance).StartCoroutine(DelayedNjordInit()); } private static IEnumerator DelayedNjordInit() { yield return null; yield return null; yield return null; yield return null; NjordDebug.Info("\ud83c\udf0a Njord Authority initializing AFTER player spawn…"); NjordAuthorityEngine.Initialize(); NjordDebug.Info("\ud83c\udf0a Njord Authority fully initialized."); } } [HarmonyPatch(typeof(Ship), "ApplyControlls")] public static class Patch_Ship_ApplyControlls { [HarmonyPostfix] public static void Postfix(Ship __instance) { if (!((Object)(object)__instance == (Object)null)) { _ = Time.fixedDeltaTime; Type type = ((object)__instance).GetType(); FieldInfo fieldInfo = AccessTools.Field(type, "m_rudder") ?? AccessTools.Field(type, "m_rudderValue"); float num = 0f; if (fieldInfo != null) { num = (float)fieldInfo.GetValue(__instance); } float steeringMultiplier = NjordRuntimeConfig.Instance.SteeringMultiplier; float njord = num * steeringMultiplier; Njord_Telemetry.ReportRudder(num, njord, steeringMultiplier); } } } } namespace Njord.HUD { public static class NjordHudManager { private static bool _initialized = false; private static bool _hudCreated = false; private static bool _stylesCreated = false; private static Rect _hudRect; private static bool _dragging = false; private static Vector2 _dragStartMouse; private static Vector2 _dragStartHud; private static GUIStyle _headerStyle; private static GUIStyle _sectionStyle; private static GUIStyle _labelStyle; private static GUIStyle _smallLabelStyle; private static GUIStyle _hpBgStyle; private static GUIStyle _hpFillStyle; private static readonly Color _bgColor = new Color(0f, 0f, 0f, 0.7f); private const float WIDTH = 360f; private const float HEIGHT = 570f; public static void Initialize() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (!_initialized) { _initialized = true; _hudRect = new Rect(Plugin.HudPositionX.Value, Plugin.HudPositionY.Value, 360f, 570f); } } public static void CreateHud() { if (!_hudCreated) { _hudCreated = true; NjordDebug.Info("[HUD] Njord HUD initialized."); } } public static void OnGUI() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_02a5: Unknown result type (might be due to invalid IL or missing references) if (_initialized && _hudCreated && Njord_ShipControlTracker.ShouldShowHud) { CreateStylesIfNeeded(); GUI.color = _bgColor; GUI.Box(_hudRect, GUIContent.none); GUI.color = Color.white; GUILayout.BeginArea(_hudRect); GUILayout.BeginVertical(Array.Empty()); GUILayout.Label("⚓ NJORD READOUT ⚓", _headerStyle, Array.Empty()); GUILayout.Space(4f); GUILayout.Label("Vessel: " + Njord_Telemetry.VesselName, _labelStyle, Array.Empty()); GUILayout.Label("Status: " + (Njord_Telemetry.IsFloating ? "Floating ✓" : "Not Floating ✗") + " Steering Gate: " + (Njord_Telemetry.GateReady ? "Open ✓" : "Closed ✗"), _smallLabelStyle, Array.Empty()); GUILayout.Space(4f); GUILayout.Label("── Waterline ─────────────────────────────", _sectionStyle, Array.Empty()); string text = (Njord_Telemetry.WaterError ? "—" : Njord_Telemetry.WaterLevel.ToString("F2")); string text2 = (Njord_Telemetry.WaterError ? "—" : Njord_Telemetry.BoatY.ToString("F2")); string arg = (Njord_Telemetry.DepthError ? "—" : Njord_Telemetry.Depth.ToString("F3")); GUILayout.Label("Water Level: " + text, _labelStyle, Array.Empty()); GUILayout.Label("Boat Y: " + text2, _labelStyle, Array.Empty()); GUILayout.Label($"Depth: {arg} (Disable: {Njord_Telemetry.DisableLevel:F3})", _labelStyle, Array.Empty()); GUILayout.Label($"Readiness: {Njord_Telemetry.ReadinessTimer:F2} / {Njord_Telemetry.ReadinessMax:F2}", _labelStyle, Array.Empty()); GUILayout.Space(4f); GUILayout.Label("── Hull Integrity ───────────────────────", _sectionStyle, Array.Empty()); float hPCurrent = Njord_Telemetry.HPCurrent; float num = Mathf.Max(Njord_Telemetry.HPMax, 1f); float num2 = Mathf.Clamp01(hPCurrent / num); GUILayout.Label($"HP: {hPCurrent:F0} / {num:F0} ({num2 * 100f:F1}%)", _labelStyle, Array.Empty()); Rect lastRect = GUILayoutUtility.GetLastRect(); float num3 = 340f; float num4 = 10f; Rect val = default(Rect); ((Rect)(ref val))..ctor(10f, ((Rect)(ref lastRect)).yMax + 2f, num3, num4); GUI.Box(val, GUIContent.none, _hpBgStyle); GUI.Box(new Rect(((Rect)(ref val)).x, ((Rect)(ref val)).y, ((Rect)(ref val)).width * num2, ((Rect)(ref val)).height), GUIContent.none, _hpFillStyle); GUILayout.Space(22f); GUILayout.Label("── Steering ─────────────────────────────", _sectionStyle, Array.Empty()); string text3 = (Njord_Telemetry.RudderError ? "—" : Njord_Telemetry.RudderVanilla.ToString("F2")); string text4 = (Njord_Telemetry.RudderError ? "—" : Njord_Telemetry.RudderNjord.ToString("F2")); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("Vanilla: " + text3, _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) }); GUILayout.Label("Njord: " + text4, _labelStyle, Array.Empty()); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label($"Mult: {Njord_Telemetry.SteeringMultiplier:F2}x", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) }); GUILayout.Label($"Gain: {Njord_Telemetry.SteeringGainPerSecond:+0.00;-0.00;0.00}", _labelStyle, Array.Empty()); GUILayout.EndHorizontal(); GUILayout.Space(4f); GUILayout.Label("── Speed ────────────────────────────────", _sectionStyle, Array.Empty()); string text5 = (Njord_Telemetry.SpeedError ? "—" : Njord_Telemetry.NjordSpeedCurr.ToString("F1")); string text6 = (Njord_Telemetry.SpeedError ? "—" : Njord_Telemetry.MortalSpeedCurr.ToString("F1")); string text7 = (Njord_Telemetry.SpeedError ? "—" : (Njord_Telemetry.NjordSpeedCurr - Njord_Telemetry.MortalSpeedCurr).ToString("0.0")); GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label("Njord: " + text5 + " m/s", _labelStyle, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Width(150f) }); GUILayout.Label("Mortal: " + text6 + " m/s", _labelStyle, Array.Empty()); GUILayout.EndHorizontal(); GUILayout.Label("Gift of the Deep: " + text7 + " m/s", _labelStyle, Array.Empty()); GUILayout.Space(4f); GUILayout.Label("── Wind ─────────────────────────────────", _sectionStyle, Array.Empty()); GUILayout.Label($"UI Blend: {Njord_Telemetry.WindUIBlend:F2}", _labelStyle, Array.Empty()); GUILayout.Label($"UI Color: ({Njord_Telemetry.WindUIColor.r:F2}, {Njord_Telemetry.WindUIColor.g:F2}, {Njord_Telemetry.WindUIColor.b:F2})", _labelStyle, Array.Empty()); GUILayout.Space(6f); GUILayout.Label("Press F7 to toggle HUD (drag anywhere to move)", _smallLabelStyle, Array.Empty()); GUILayout.EndVertical(); GUILayout.EndArea(); HandleDragging(); } } private static void HandleDragging() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Invalid comparison between Unknown and I4 //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Invalid comparison between Unknown and I4 //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Invalid comparison between Unknown and I4 //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) Event current = Event.current; if (current != null) { if ((int)current.type == 0 && current.button == 0 && ((Rect)(ref _hudRect)).Contains(current.mousePosition)) { _dragging = true; _dragStartMouse = current.mousePosition; _dragStartHud = new Vector2(((Rect)(ref _hudRect)).x, ((Rect)(ref _hudRect)).y); current.Use(); } if (_dragging && (int)current.type == 3 && current.button == 0) { Vector2 val = current.mousePosition - _dragStartMouse; ((Rect)(ref _hudRect)).x = _dragStartHud.x + val.x; ((Rect)(ref _hudRect)).y = _dragStartHud.y + val.y; current.Use(); } if (_dragging && ((int)current.type == 1 || (int)current.rawType == 1)) { _dragging = false; Plugin.HudPositionX.Value = ((Rect)(ref _hudRect)).x; Plugin.HudPositionY.Value = ((Rect)(ref _hudRect)).y; current.Use(); } } } private static void CreateStylesIfNeeded() { //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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Expected O, but got Unknown //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected O, but got Unknown //IL_00d7: 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) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Expected O, but got Unknown //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Expected O, but got Unknown //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Expected O, but got Unknown //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Expected O, but got Unknown //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Expected O, but got Unknown if (!_stylesCreated) { _stylesCreated = true; GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = 16, fontStyle = (FontStyle)1 }; val.normal.textColor = new Color(0.9f, 0.8f, 0.5f); _headerStyle = val; GUIStyle val2 = new GUIStyle(GUI.skin.label) { fontSize = 13, fontStyle = (FontStyle)1 }; val2.normal.textColor = new Color(0.85f, 0.75f, 0.55f); _sectionStyle = val2; GUIStyle val3 = new GUIStyle(GUI.skin.label) { fontSize = 12 }; val3.normal.textColor = new Color(0.95f, 0.9f, 0.8f); _labelStyle = val3; GUIStyle val4 = new GUIStyle(GUI.skin.label) { fontSize = 11 }; val4.normal.textColor = new Color(0.95f, 0.9f, 0.8f); _smallLabelStyle = val4; Texture2D val5 = new Texture2D(1, 1); val5.SetPixel(0, 0, new Color(0.2f, 0.05f, 0.05f, 0.8f)); val5.Apply(); _hpBgStyle = new GUIStyle(GUI.skin.box); _hpBgStyle.normal.background = val5; Texture2D val6 = new Texture2D(1, 1); val6.SetPixel(0, 0, new Color(0.1f, 0.7f, 0.1f, 0.9f)); val6.Apply(); _hpFillStyle = new GUIStyle(GUI.skin.box); _hpFillStyle.normal.background = val6; } } } public static class NjordReleaseIndicator { private static GUIStyle labelStyle; private static void EnsureStyle() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Expected O, but got Unknown if (labelStyle == null) { GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = 14, fontStyle = (FontStyle)1 }; val.normal.textColor = Color.white; labelStyle = val; } } public static void Draw() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)Player.m_localPlayer == (Object)null) && Njord_ShipControlTracker.CurrentController != 0L && Plugin.HudEnabledByUser.Value) { EnsureStyle(); float num = (float)Screen.height - 220f; GUI.Label(new Rect(40f, num, 400f, 40f), "Release [E] to leave helm", labelStyle); } } } } namespace Njord.Core { public static class NjordAuthorityEngine { private static readonly Dictionary ServerAuthorityMap = new Dictionary(); private static bool _initialized = false; public static bool UseLegacyFallback { get; private set; } = false; public static void Initialize() { if (_initialized) { return; } try { if (ZRoutedRpc.instance == null) { NjordDebug.Error("[Authority] ZRoutedRpc not ready; enabling legacy fallback."); UseLegacyFallback = true; return; } ZRoutedRpc.instance.Register("Njord_RequestControl", (Action)RPC_RequestControl); ZRoutedRpc.instance.Register("Njord_ReleaseControl", (Action)RPC_ReleaseControl); ZRoutedRpc.instance.Register("Njord_RequestAuthorityState", (Action)RPC_RequestAuthorityState); ZRoutedRpc.instance.Register("Njord_AuthorityUpdate", (Action)RPC_AuthorityUpdate); ZRoutedRpc.instance.Register("Njord_AuthoritySyncAll", (Action)RPC_AuthoritySyncAll); _initialized = true; NjordDebug.Info("[Authority] NjordAuthorityEngine initialized (RPC-only, server-authoritative)."); } catch (Exception arg) { NjordDebug.Error($"[Authority] Initialization failed; enabling legacy fallback. Exception: {arg}"); UseLegacyFallback = true; } } public static void Server_OnHelmClaim(Ship ship, long playerID) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (!UseLegacyFallback && !((Object)(object)ship == (Object)null) && IsServer() && TryGetShipZdoID(ship, out var id)) { ServerAuthorityMap[id] = playerID; BroadcastAuthorityUpdate(id, playerID); ZNetView component = ((Component)ship).GetComponent(); if ((Object)(object)component != (Object)null && component.IsValid()) { component.ClaimOwnership(); } } } public static void Server_OnHelmRelease(Ship ship) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (!UseLegacyFallback && !((Object)(object)ship == (Object)null) && IsServer() && TryGetShipZdoID(ship, out var id)) { ServerAuthorityMap[id] = 0L; BroadcastAuthorityUpdate(id, 0L); ZNetView component = ((Component)ship).GetComponent(); if ((Object)(object)component != (Object)null && component.IsValid() && !component.IsOwner()) { component.ClaimOwnership(); } } } public static void Client_RequestControl(Ship ship) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) if (!UseLegacyFallback && !((Object)(object)ship == (Object)null) && !IsServer() && TryGetShipZdoID(ship, out var id)) { long num = (((Object)(object)Player.m_localPlayer != (Object)null) ? Player.m_localPlayer.GetPlayerID() : 0); if (num != 0L && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC("Njord_RequestControl", new object[2] { id, num }); } } } public static void Client_ReleaseControl(Ship ship) { //IL_005d: Unknown result type (might be due to invalid IL or missing references) if (!UseLegacyFallback && !((Object)(object)ship == (Object)null) && !IsServer() && TryGetShipZdoID(ship, out var id)) { long num = (((Object)(object)Player.m_localPlayer != (Object)null) ? Player.m_localPlayer.GetPlayerID() : 0); if (num != 0L && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC("Njord_ReleaseControl", new object[2] { id, num }); } } } private static void RPC_RequestControl(long sender, ZDOID shipID, long playerID) { //IL_0018: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) if (UseLegacyFallback || !IsServer() || playerID == 0L) { return; } ServerAuthorityMap[shipID] = playerID; BroadcastAuthorityUpdate(shipID, playerID); ZDOMan instance = ZDOMan.instance; ZDO val = ((instance != null) ? instance.GetZDO(shipID) : null); if (val != null) { val.SetOwner(sender); if (NjordConfig.Debug_Enable.Value) { NjordDebug.Debug($"[Authority] ZDO ownership → peer {sender} for ship {shipID}"); } } } private static void RPC_ReleaseControl(long sender, ZDOID shipID, long playerID) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) if (UseLegacyFallback || !IsServer() || (ServerAuthorityMap.TryGetValue(shipID, out var value) && value != playerID)) { return; } ServerAuthorityMap[shipID] = 0L; BroadcastAuthorityUpdate(shipID, 0L); ZDOMan instance = ZDOMan.instance; ZDO val = ((instance != null) ? instance.GetZDO(shipID) : null); if (val == null) { return; } ZNetScene instance2 = ZNetScene.instance; ZNetView val2 = ((instance2 != null) ? instance2.FindInstance(val) : null); if (!((Object)(object)val2 != (Object)null)) { return; } ZNetView component = ((Component)val2).GetComponent(); if ((Object)(object)component != (Object)null && component.IsValid()) { component.ClaimOwnership(); if (NjordConfig.Debug_Enable.Value) { NjordDebug.Debug($"[Authority] ZDO ownership reclaimed by server for ship {shipID}"); } } } private static void RPC_RequestAuthorityState(long sender, ZDOID shipID) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (!UseLegacyFallback && IsServer()) { long value = 0L; ServerAuthorityMap.TryGetValue(shipID, out value); if (ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "Njord_AuthorityUpdate", new object[2] { shipID, value }); } } } private static void RPC_AuthorityUpdate(long sender, ZDOID shipID, long controllerID) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (UseLegacyFallback) { return; } ZDO zDO = ZDOMan.instance.GetZDO(shipID); if (zDO == null) { return; } ZNetView val = ZNetScene.instance.FindInstance(zDO); if ((Object)(object)val == (Object)null) { return; } Ship component = ((Component)val).GetComponent(); if (!((Object)(object)component == (Object)null)) { if (controllerID != 0L) { Njord_ShipControlTracker.SetControl(component, controllerID); } else { Njord_ShipControlTracker.ClearControl(component); } } } private static void RPC_AuthoritySyncAll(long sender, ZPackage pkg) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) if (UseLegacyFallback) { return; } int num = pkg.ReadInt(); long num2 = (((Object)(object)Player.m_localPlayer != (Object)null) ? Player.m_localPlayer.GetPlayerID() : 0); long controller = 0L; for (int i = 0; i < num; i++) { pkg.ReadZDOID(); long num3 = pkg.ReadLong(); if (num2 != 0L && num3 == num2) { controller = num3; } } Njord_ShipControlTracker.UpdateController(controller, 0f); } private static bool IsServer() { if ((Object)(object)ZNet.instance != (Object)null) { return ZNet.instance.IsServer(); } return false; } private static bool TryGetShipZdoID(Ship ship, out ZDOID id) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //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) id = ZDOID.None; if ((Object)(object)ship == (Object)null) { return false; } ZNetView component = ((Component)ship).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return false; } ZDO zDO = component.GetZDO(); if (zDO == null) { return false; } id = zDO.m_uid; return true; } private static void BroadcastAuthorityUpdate(ZDOID shipID, long controllerID) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) if (ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "Njord_AuthorityUpdate", new object[2] { shipID, controllerID }); } } } public static class NjordConfig { private static ConfigSync configSync = new ConfigSync("wubarrk.njord") { DisplayName = "Njord", CurrentVersion = "1.3.2", MinimumRequiredVersion = "1.3.2" }; public static SyncedConfigEntry ServerConfigLocked = null; public static SyncedConfigEntry Wind_SystemEnable = null; public static SyncedConfigEntry Wind_AlwaysFull = null; public static SyncedConfigEntry Wind_NoDeadZone = null; public static SyncedConfigEntry Wind_BlendToFull = null; public static SyncedConfigEntry Wind_BlendRate = null; public static SyncedConfigEntry Wind_GracePeriodDelay = null; public static SyncedConfigEntry SteeringMultiplier = null; public static SyncedConfigEntry AccelerationMultiplier = null; public static SyncedConfigEntry BaseForwardForce = null; public static SyncedConfigEntry BaseReverseForce = null; public static SyncedConfigEntry SailForwardForce = null; public static SyncedConfigEntry HalfSailForce = null; public static SyncedConfigEntry FullSailForce = null; public static SyncedConfigEntry ReverseKick = null; public static SyncedConfigEntry MaxSpeed_Raft = null; public static SyncedConfigEntry MaxSpeed_Karve = null; public static SyncedConfigEntry MaxSpeed_Longship = null; public static SyncedConfigEntry MaxSpeed_Drakkar = null; public static SyncedConfigEntry MaxSpeed_MercantShip = null; public static SyncedConfigEntry MaxSpeed_CargoShip = null; public static SyncedConfigEntry MaxSpeed_BigCargoShip = null; public static SyncedConfigEntry MaxSpeed_RowingCanoe = null; public static SyncedConfigEntry MaxSpeed_DoubleRowingCanoe = null; public static SyncedConfigEntry MaxSpeed_LittleBoat = null; public static SyncedConfigEntry MaxSpeed_WarShip = null; public static SyncedConfigEntry MaxSpeed_CargoCaravel = null; public static SyncedConfigEntry MaxSpeed_HugeCargoShip = null; public static SyncedConfigEntry MaxSpeed_CargoAnimalShip = null; public static SyncedConfigEntry MaxSpeed_HerculeShip = null; public static SyncedConfigEntry MaxSpeed_Skuldelev = null; public static SyncedConfigEntry MaxSpeed_TaurusWarShip = null; public static SyncedConfigEntry MaxSpeed_FastShipSkuldelev = null; public static SyncedConfigEntry MaxSpeed_GoblinShip = null; public static SyncedConfigEntry VFX_Enable = null; public static SyncedConfigEntry VFX_Color = null; public static SyncedConfigEntry Debug_Enable = null; public static SyncedConfigEntry Debug_PhysicsWind = null; public static SyncedConfigEntry Debug_AuthControl = null; private static SyncedConfigEntry config(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true) { ConfigEntry configEntry = ((BaseUnityPlugin)Plugin.Instance).Config.Bind(group, name, value, description); SyncedConfigEntry syncedConfigEntry = configSync.AddConfigEntry(configEntry); syncedConfigEntry.SynchronizedConfig = synchronizedSetting; return syncedConfigEntry; } private static SyncedConfigEntry config(string group, string name, T value, string description, bool synchronizedSetting = true) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty()), synchronizedSetting); } public static void Bind() { //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected O, but got Unknown //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Expected O, but got Unknown //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Expected O, but got Unknown //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Expected O, but got Unknown //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Expected O, but got Unknown //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Expected O, but got Unknown //IL_0282: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Expected O, but got Unknown //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02cb: Expected O, but got Unknown //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_0309: Expected O, but got Unknown //IL_033c: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Expected O, but got Unknown //IL_037a: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Expected O, but got Unknown //IL_03b8: Unknown result type (might be due to invalid IL or missing references) //IL_03c3: Expected O, but got Unknown //IL_03f6: Unknown result type (might be due to invalid IL or missing references) //IL_0401: Expected O, but got Unknown //IL_0445: Unknown result type (might be due to invalid IL or missing references) //IL_0450: Expected O, but got Unknown //IL_0483: Unknown result type (might be due to invalid IL or missing references) //IL_048e: Expected O, but got Unknown //IL_04c1: Unknown result type (might be due to invalid IL or missing references) //IL_04cc: Expected O, but got Unknown //IL_04ff: Unknown result type (might be due to invalid IL or missing references) //IL_050a: Expected O, but got Unknown //IL_053d: Unknown result type (might be due to invalid IL or missing references) //IL_0548: Expected O, but got Unknown //IL_057b: Unknown result type (might be due to invalid IL or missing references) //IL_0586: Expected O, but got Unknown //IL_05b9: Unknown result type (might be due to invalid IL or missing references) //IL_05c4: Expected O, but got Unknown //IL_07fc: Unknown result type (might be due to invalid IL or missing references) //IL_0601: Unknown result type (might be due to invalid IL or missing references) //IL_060c: Expected O, but got Unknown //IL_063f: Unknown result type (might be due to invalid IL or missing references) //IL_064a: Expected O, but got Unknown //IL_067d: Unknown result type (might be due to invalid IL or missing references) //IL_0688: Expected O, but got Unknown //IL_06bb: Unknown result type (might be due to invalid IL or missing references) //IL_06c6: Expected O, but got Unknown //IL_06f9: Unknown result type (might be due to invalid IL or missing references) //IL_0704: Expected O, but got Unknown //IL_0737: Unknown result type (might be due to invalid IL or missing references) //IL_0742: Expected O, but got Unknown //IL_0775: Unknown result type (might be due to invalid IL or missing references) //IL_0780: Expected O, but got Unknown //IL_07b3: Unknown result type (might be due to invalid IL or missing references) //IL_07be: Expected O, but got Unknown ServerConfigLocked = config("1 - General", "Lock Configuration", value: true, "If on, the configuration is locked and can be changed by server admins only."); configSync.AddLockingConfigEntry(ServerConfigLocked.SourceConfig); string text = "\nNote: This value is safely clamped at runtime to protect against NaN, Infinity, and out-of-bounds inputs breaking physics."; Wind_SystemEnable = config("2 - Wind System", "Wind_SystemEnable", value: true, "Master switch for Njord wind physics and UI."); Wind_AlwaysFull = config("2 - Wind System", "Wind_AlwaysFull", value: true, "Always gives perfect tailwind, ignoring all other rules."); Wind_NoDeadZone = config("2 - Wind System", "Wind_NoDeadZone", value: false, "[EXPERIMENTAL] Enables nudging the wind just out of the dead zone (to the 130° edge)."); Wind_BlendToFull = config("2 - Wind System", "Wind_BlendToFull", value: false, "[EXPERIMENTAL] Enables nudging the wind from the crosswind line to the perfect tailwind line."); Wind_BlendRate = config("2 - Wind System", "Wind_BlendRate", 30f, new ConfigDescription("How fast the wind adjusts (degrees per second). [Range: 0f - 180f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(0f, 180f), Array.Empty())); Wind_GracePeriodDelay = config("2 - Wind System", "Wind_GracePeriodDelay", 2.5f, new ConfigDescription("Delay in seconds before the wind system starts assisting. [Range: 0f - 60f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(0f, 60f), Array.Empty())); SteeringMultiplier = config("3 - Steering", "SteeringMultiplier", 1.85f, new ConfigDescription("Multiplier applied to rudder steering. [Range: 0.1f - 10f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 10f), Array.Empty())); AccelerationMultiplier = config("4 - Acceleration", "AccelerationMultiplier", 2.2f, new ConfigDescription("Acceleration multiplier. [Range: 0.1f - 10f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(0.1f, 10f), Array.Empty())); BaseForwardForce = config("4 - Acceleration", "BaseForwardForce", 0.85f, new ConfigDescription("Base forward force. [Range: 0f - 10f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(0f, 10f), Array.Empty())); BaseReverseForce = config("4 - Acceleration", "BaseReverseForce", 0.2f, new ConfigDescription("Base reverse force. [Range: 0f - 10f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(0f, 10f), Array.Empty())); SailForwardForce = config("5 - Sails", "SailForwardForce", 0.3f, new ConfigDescription("Forward force when sails are down. [Range: 0f - 10f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(0f, 10f), Array.Empty())); HalfSailForce = config("5 - Sails", "HalfSailForce", 1.2f, new ConfigDescription("Forward force at half sail. [Range: 0f - 10f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(0f, 10f), Array.Empty())); FullSailForce = config("5 - Sails", "FullSailForce", 4.2f, new ConfigDescription("Forward force at full sail. [Range: 0f - 20f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(0f, 20f), Array.Empty())); ReverseKick = config("5 - Sails", "ReverseKick", 1.8f, new ConfigDescription("Reverse kick multiplier. [Range: 0f - 10f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(0f, 10f), Array.Empty())); MaxSpeed_Raft = config("6 - Speed Limits", "MaxSpeed_Raft", 7f, new ConfigDescription("Absolute max speed for the Raft (m/s). [Range: 1f - 100f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); MaxSpeed_Karve = config("6 - Speed Limits", "MaxSpeed_Karve", 16.8f, new ConfigDescription("Absolute max speed for the Karve (m/s). [Range: 1f - 100f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); MaxSpeed_Longship = config("6 - Speed Limits", "MaxSpeed_Longship", 26f, new ConfigDescription("Absolute max speed for the Longship (m/s). [Range: 1f - 100f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); MaxSpeed_Drakkar = config("6 - Speed Limits", "MaxSpeed_Drakkar", 30f, new ConfigDescription("Absolute max speed for the Drakkar (m/s). [Range: 1f - 100f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); if (Plugin.OdinShipDetected || Plugin.OdinShipPlusDetected) { MaxSpeed_MercantShip = config("7 - OdinShip Speed Limits", "MaxSpeed_MercantShip", 22f, new ConfigDescription("Max speed for MercantShip (m/s). [Range: 1f - 100f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); MaxSpeed_CargoShip = config("7 - OdinShip Speed Limits", "MaxSpeed_CargoShip", 20f, new ConfigDescription("Max speed for CargoShip (m/s). [Range: 1f - 100f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); MaxSpeed_BigCargoShip = config("7 - OdinShip Speed Limits", "MaxSpeed_BigCargoShip", 23.5f, new ConfigDescription("Max speed for BigCargoShip (m/s). [Range: 1f - 100f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); MaxSpeed_RowingCanoe = config("7 - OdinShip Speed Limits", "MaxSpeed_RowingCanoe", 10f, new ConfigDescription("Max speed for RowingCanoe (m/s). [Range: 1f - 100f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); MaxSpeed_DoubleRowingCanoe = config("7 - OdinShip Speed Limits", "MaxSpeed_DoubleRowingCanoe", 12f, new ConfigDescription("Max speed for DoubleRowingCanoe (m/s). [Range: 1f - 100f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); MaxSpeed_LittleBoat = config("7 - OdinShip Speed Limits", "MaxSpeed_LittleBoat", 17f, new ConfigDescription("Max speed for LittleBoat (m/s). [Range: 1f - 100f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); MaxSpeed_WarShip = config("7 - OdinShip Speed Limits", "MaxSpeed_WarShip", 32f, new ConfigDescription("Max speed for WarShip (m/s). [Range: 1f - 100f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); } if (Plugin.OdinShipPlusDetected) { MaxSpeed_CargoCaravel = config("8 - OdinShipPlus Speed Limits", "MaxSpeed_CargoCaravel", 22f, new ConfigDescription("Max speed for CargoCaravel (m/s). [Range: 1f - 100f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); MaxSpeed_HugeCargoShip = config("8 - OdinShipPlus Speed Limits", "MaxSpeed_HugeCargoShip", 18f, new ConfigDescription("Max speed for HugeCargoShip (m/s). [Range: 1f - 100f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); MaxSpeed_CargoAnimalShip = config("8 - OdinShipPlus Speed Limits", "MaxSpeed_CargoAnimalShip", 19f, new ConfigDescription("Max speed for CargoAnimalShip (m/s). [Range: 1f - 100f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); MaxSpeed_HerculeShip = config("8 - OdinShipPlus Speed Limits", "MaxSpeed_HerculeShip", 24f, new ConfigDescription("Max speed for HerculeShip (m/s). [Range: 1f - 100f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); MaxSpeed_Skuldelev = config("8 - OdinShipPlus Speed Limits", "MaxSpeed_Skuldelev", 28f, new ConfigDescription("Max speed for Skuldelev (m/s). [Range: 1f - 100f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); MaxSpeed_TaurusWarShip = config("8 - OdinShipPlus Speed Limits", "MaxSpeed_TaurusWarShip", 25f, new ConfigDescription("Max speed for TaurusWarShip (m/s). [Range: 1f - 100f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); MaxSpeed_FastShipSkuldelev = config("8 - OdinShipPlus Speed Limits", "MaxSpeed_FastShipSkuldelev", 35f, new ConfigDescription("Max speed for FastShipSkuldelev (m/s). [Range: 1f - 100f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); MaxSpeed_GoblinShip = config("8 - OdinShipPlus Speed Limits", "MaxSpeed_GoblinShip", 18f, new ConfigDescription("Max speed for GoblinShip (m/s). [Range: 1f - 100f]." + text, (AcceptableValueBase)(object)new AcceptableValueRange(1f, 100f), Array.Empty())); } VFX_Enable = config("9 - VFX", "VFX_Enable", value: true, "Enable rune VFX."); VFX_Color = config("9 - VFX", "VFX_Color", new Color(0.3f, 0.6f, 1f, 1f), "Rune VFX color."); Debug_Enable = config("10 - Debug", "Debug_Enable", value: false, "Master switch to enable Njord debug logs.", synchronizedSetting: false); Debug_PhysicsWind = config("10 - Debug", "Debug_PhysicsWind", value: false, "Enable logging for Wind calculations and Physics.", synchronizedSetting: false); Debug_AuthControl = config("10 - Debug", "Debug_AuthControl", value: false, "Enable logging for ship ownership and control.", synchronizedSetting: false); } } public class NjordRuntimeConfig { public static NjordRuntimeConfig Instance { get; } = new NjordRuntimeConfig(); public float SteeringMultiplier => NjordConfig.SteeringMultiplier.Value; public float AccelerationMultiplier => NjordConfig.AccelerationMultiplier.Value; public float BaseForwardForce => NjordConfig.BaseForwardForce.Value; public float BaseReverseForce => NjordConfig.BaseReverseForce.Value; public float SailForwardForce => NjordConfig.SailForwardForce.Value; public float HalfSailForce => NjordConfig.HalfSailForce.Value; public float FullSailForce => NjordConfig.FullSailForce.Value; public float ReverseKick => NjordConfig.ReverseKick.Value; public bool Wind_SystemEnable => NjordConfig.Wind_SystemEnable.Value; public bool Wind_AlwaysFull => NjordConfig.Wind_AlwaysFull.Value; public bool Wind_NoDeadZone => NjordConfig.Wind_NoDeadZone.Value; public bool Wind_BlendToFull => NjordConfig.Wind_BlendToFull.Value; public float Wind_BlendRate => NjordConfig.Wind_BlendRate.Value; public float Wind_GracePeriodDelay => NjordConfig.Wind_GracePeriodDelay.Value; public bool VFX_Enable => NjordConfig.VFX_Enable.Value; public Color VFX_Color => NjordConfig.VFX_Color.Value; public bool Debug_Enable => NjordConfig.Debug_Enable.Value; public bool Debug_PhysicsWind => NjordConfig.Debug_PhysicsWind.Value; public bool Debug_AuthControl => NjordConfig.Debug_AuthControl.Value; public float MaxSpeed_Raft => NjordConfig.MaxSpeed_Raft.Value; public float MaxSpeed_Karve => NjordConfig.MaxSpeed_Karve.Value; public float MaxSpeed_Longship => NjordConfig.MaxSpeed_Longship.Value; public float MaxSpeed_Drakkar => NjordConfig.MaxSpeed_Drakkar.Value; } public enum NjordSailState { Forward, Half, Full, Backward } public static class NjordShipSpeed { private static string CleanName(Ship ship) { if ((Object)(object)ship == (Object)null) { return "unknown"; } string name = ((Object)ship).name; if (string.IsNullOrEmpty(name)) { name = ((Object)((Component)ship).gameObject).name; } return name.Replace("(Clone)", "").Trim().ToLowerInvariant(); } public static float GetMaxSpeedForShip(Ship ship) { if ((Object)(object)ship == (Object)null) { return 0f; } string text = CleanName(ship); float num = 0f; if (text.Contains("raft")) { num = NjordConfig.MaxSpeed_Raft.Value; } else if (text.Contains("karve")) { num = NjordConfig.MaxSpeed_Karve.Value; } else if (text.Contains("longship")) { num = NjordConfig.MaxSpeed_Longship.Value; } else if (text.Contains("drakkar")) { num = NjordConfig.MaxSpeed_Drakkar.Value; } if (Plugin.OdinShipDetected || Plugin.OdinShipPlusDetected) { if (text.Contains("mercantship")) { num = NjordConfig.MaxSpeed_MercantShip.Value; } else if (text.Contains("bigcargoship")) { num = NjordConfig.MaxSpeed_BigCargoShip.Value; } else if (text.Contains("cargoship")) { num = NjordConfig.MaxSpeed_CargoShip.Value; } else if (text.Contains("doublerowingcanoe")) { num = NjordConfig.MaxSpeed_DoubleRowingCanoe.Value; } else if (text.Contains("rowingcanoe")) { num = NjordConfig.MaxSpeed_RowingCanoe.Value; } else if (text.Contains("littleboat")) { num = NjordConfig.MaxSpeed_LittleBoat.Value; } else if (text.Contains("warship")) { num = NjordConfig.MaxSpeed_WarShip.Value; } } if (Plugin.OdinShipPlusDetected) { if (text.Contains("cargocaravel")) { num = NjordConfig.MaxSpeed_CargoCaravel.Value; } else if (text.Contains("hugecargoship")) { num = NjordConfig.MaxSpeed_HugeCargoShip.Value; } else if (text.Contains("cargoanimalship")) { num = NjordConfig.MaxSpeed_CargoAnimalShip.Value; } else if (text.Contains("herculeship")) { num = NjordConfig.MaxSpeed_HerculeShip.Value; } else if (text.Contains("fastshipskuldelev")) { num = NjordConfig.MaxSpeed_FastShipSkuldelev.Value; } else if (text.Contains("skuldelev")) { num = NjordConfig.MaxSpeed_Skuldelev.Value; } else if (text.Contains("tauruswarship")) { num = NjordConfig.MaxSpeed_TaurusWarShip.Value; } else if (text.Contains("goblinship")) { num = NjordConfig.MaxSpeed_GoblinShip.Value; } } if (num <= 0f || float.IsNaN(num) || float.IsInfinity(num)) { return 0f; } return num; } } public static class Njord_Telemetry { public static string VesselName = "Unknown"; public static bool GateReady = false; public static bool IsFloating = false; public static float WaterLevel = 0f; public static float BoatY = 0f; public static float Depth = 0f; public static float DisableLevel = 0f; public static float ReadinessTimer = 0f; public static float ReadinessMax = 0f; public static float HPCurrent = 0f; public static float HPMax = 1f; public static float RudderVanilla = 0f; public static float RudderNjord = 0f; public static float SteeringMultiplier = 1f; public static float SteeringGainPerSecond = 0f; private static float _lastRudder = 0f; private static float _lastRudderTime = 0f; public static float SpeedCurrent = 0f; public static float SpeedVanillaBaseline = 0f; public static float SpeedGainPerSecond = 0f; private static float _lastSpeed = 0f; private static float _lastSpeedTime = 0f; public static float NjordSpeedPrev = 0f; public static float NjordSpeedCurr = 0f; public static float MortalSpeedPrev = 0f; public static float MortalSpeedCurr = 0f; public static float WindUIBlend = 0f; public static Color WindUIColor = Color.white; public static bool HasError = false; public static bool DepthError = false; public static bool WaterError = false; public static bool SpeedError = false; public static bool RudderError = false; public static void ClearErrors() { HasError = (DepthError = (WaterError = (SpeedError = (RudderError = false)))); } public static void UpdateBasic(Ship ship, float waterLevel, float depth, bool floating, float readinessTimer, bool gateReady) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)ship)) { return; } VesselName = ((Object)ship).name.Replace("(Clone)", "").Trim(); GateReady = gateReady; IsFloating = floating; ClearErrors(); if (float.IsNaN(waterLevel) || float.IsInfinity(waterLevel)) { WaterError = true; HasError = true; waterLevel = ((Component)ship).transform.position.y; } WaterLevel = waterLevel; BoatY = ((Component)ship).transform.position.y; if (float.IsNaN(depth) || float.IsInfinity(depth)) { DepthError = true; HasError = true; depth = 0f; } Depth = depth; DisableLevel = ship.m_disableLevel; ReadinessTimer = readinessTimer; ReadinessMax = 0.35f; float time = Time.time; if (_lastSpeedTime > 0f) { float num = time - _lastSpeedTime; if (num > 0f) { SpeedGainPerSecond = (SpeedCurrent - _lastSpeed) / num; } } _lastSpeed = SpeedCurrent; _lastSpeedTime = time; } public static void SetHP(float hp, float maxHp) { HPCurrent = Mathf.Max(0f, hp); HPMax = Mathf.Max(1f, maxHp); } public static void ReportRudder(float vanilla, float njord, float mult) { if (float.IsNaN(njord)) { RudderError = true; HasError = true; njord = 0f; } RudderVanilla = vanilla; RudderNjord = njord; SteeringMultiplier = mult; float time = Time.time; if (_lastRudderTime > 0f) { float num = time - _lastRudderTime; if (num > 0f) { SteeringGainPerSecond = (njord - _lastRudder) / num; } } _lastRudder = njord; _lastRudderTime = time; } public static void SetWindUI(float blend, Color color) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) WindUIBlend = Mathf.Clamp01(blend); WindUIColor = color; } public static void SetVanillaSpeedBaseline(float baseline) { SpeedVanillaBaseline = baseline; } public static void UpdateSpeed(float prevNjord, float currNjord, float prevMortal, float currMortal) { if (float.IsNaN(currNjord)) { SpeedError = true; HasError = true; currNjord = 0f; } NjordSpeedPrev = prevNjord; NjordSpeedCurr = currNjord; MortalSpeedPrev = prevMortal; MortalSpeedCurr = currMortal; SpeedCurrent = currNjord; SpeedVanillaBaseline = currMortal; float time = Time.time; if (_lastSpeedTime > 0f) { float num = time - _lastSpeedTime; if (num > 0f) { SpeedGainPerSecond = (currNjord - _lastSpeed) / num; } } _lastSpeed = currNjord; _lastSpeedTime = time; } } public static class NjordPatchCaller { private static Harmony harmony; public static void ApplyPatches() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown if (harmony == null) { harmony = new Harmony("wubarrk.njord"); } NjordDebug.Log("When Njord stirs, the runes awaken…"); BindRune("Þráð‑Njörðr Rune", typeof(Njord_PlayerSpawned_Init), "Njord tugs the world‑threads taut; the longship joins the weave.", "The Thread‑Rune slips from Njord’s grasp, but the sea waits for no one."); BindRune("Njord’s Fang‑Rune", typeof(NjordSeaDogEngine), "The deep bares its fangs and drives the longship onward.", "The Fang‑Rune cracks, but the sea remembers its path."); BindRune("Hrafn‑Skygg Rune", typeof(NjordTheWindsCall), "The ravens whisper the winds’ hidden counsel.", "The Raven‑Sight Rune dims, yet the sky still watches."); BindRune("Stýri‑Hjarta Rune", typeof(Patch_Ship_ApplyControlls), "The helm‑heart beats in rhythm with mortal will.", "The Helm‑Heart falters, but the rudder keeps its vigil."); BindRune("Band‑Njörðr Rune", typeof(NjordDoodadControlRune), "Njord knots the helmsman’s spirit to the vessel’s wyrd.", "The Binding Rune slips, yet the helm awaits another hand."); BindRune("Leys‑Njörðr Rune", typeof(NjordDoodadReleaseRune), "Njord loosens the knot; the helm drifts free into quiet waters.", "The Loosening Rune fades, but the sea releases its hold."); NjordDebug.Log("The longship answers the call of the deep."); } private static void BindRune(string runeName, Type patchType, string successSaga, string failureSaga) { NjordDebug.Log("Invoking " + runeName + "…"); try { harmony.PatchAll(patchType); NjordDebug.Log(successSaga); } catch (Exception ex) { NjordDebug.Warn(failureSaga ?? ""); NjordDebug.Warn("Rune‑scribe’s note: " + ex.Message); } } } public static class NjordRuneTextureGenerator { private const int Size = 128; public unsafe static Texture2D GenerateRune(Color color) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) int runeIndex = Mathf.Abs(((object)(*(Color*)(&color))/*cast due to .constrained prefix*/).GetHashCode()) % 16; return GenerateRune(color, runeIndex); } public static Texture2D GenerateSoftTrail(Color color) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(128, 128, (TextureFormat)4, false); ((Texture)val).filterMode = (FilterMode)1; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(64f, 64f); float num = 64f; Color val3 = default(Color); for (int i = 0; i < 128; i++) { for (int j = 0; j < 128; j++) { float num2 = Vector2.Distance(new Vector2((float)j + 0.5f, (float)i + 0.5f), val2) / num; float num3 = Mathf.Clamp01(1f - num2); num3 = Mathf.SmoothStep(0f, 1f, num3); num3 = Mathf.Pow(num3, 1.6f); ((Color)(ref val3))..ctor(color.r, color.g, color.b, color.a * num3); val.SetPixel(j, i, val3); } } val.Apply(true); return val; } public static Texture2D GenerateStreak(Color color) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(128, 128, (TextureFormat)4, false); ((Texture)val).filterMode = (FilterMode)1; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(64f, 64f); float num = 64f; Color val3 = default(Color); for (int i = 0; i < 128; i++) { for (int j = 0; j < 128; j++) { float num2 = Mathf.Abs((float)i + 0.5f - val2.y) / num; float num3 = Mathf.Abs((float)j + 0.5f - val2.x) / (num * 0.6f); float num4 = Mathf.Clamp01(1f - num3); float num5 = Mathf.SmoothStep(1f, 0f, num2); num4 *= Mathf.Pow(num5, 0.9f); ((Color)(ref val3))..ctor(color.r, color.g, color.b, color.a * num4); val.SetPixel(j, i, val3); } } val.Apply(true); return val; } public static Texture2D GenerateBlend(Color color) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) Texture2D val = GenerateSoftTrail(color); Texture2D val2 = GenerateRune(color); Texture2D val3 = new Texture2D(128, 128, (TextureFormat)4, false); ((Texture)val3).filterMode = (FilterMode)1; Color val4 = default(Color); for (int i = 0; i < 128; i++) { for (int j = 0; j < 128; j++) { Color pixel = val.GetPixel(j, i); Color pixel2 = val2.GetPixel(j, i); float num = Mathf.Clamp01(pixel.a + pixel2.a * 0.65f); ((Color)(ref val4))..ctor(color.r, color.g, color.b, color.a * num); val3.SetPixel(j, i, val4); } } val3.Apply(true); return val3; } public static Texture2D GenerateRune(Color color, int runeIndex) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_025d: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_02a2: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Unknown result type (might be due to invalid IL or missing references) //IL_02f7: Unknown result type (might be due to invalid IL or missing references) //IL_0307: Unknown result type (might be due to invalid IL or missing references) //IL_0317: Unknown result type (might be due to invalid IL or missing references) //IL_032c: Unknown result type (might be due to invalid IL or missing references) //IL_033c: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Unknown result type (might be due to invalid IL or missing references) //IL_037c: Unknown result type (might be due to invalid IL or missing references) //IL_0391: Unknown result type (might be due to invalid IL or missing references) //IL_03a1: Unknown result type (might be due to invalid IL or missing references) //IL_03b1: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: Unknown result type (might be due to invalid IL or missing references) //IL_03d1: Unknown result type (might be due to invalid IL or missing references) //IL_03e1: Unknown result type (might be due to invalid IL or missing references) //IL_03f1: Unknown result type (might be due to invalid IL or missing references) //IL_0401: Unknown result type (might be due to invalid IL or missing references) //IL_0416: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_0436: Unknown result type (might be due to invalid IL or missing references) //IL_0446: Unknown result type (might be due to invalid IL or missing references) //IL_045b: Unknown result type (might be due to invalid IL or missing references) //IL_046b: Unknown result type (might be due to invalid IL or missing references) //IL_047b: Unknown result type (might be due to invalid IL or missing references) //IL_048b: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Unknown result type (might be due to invalid IL or missing references) //IL_04ab: Unknown result type (might be due to invalid IL or missing references) //IL_04bb: Unknown result type (might be due to invalid IL or missing references) //IL_04cb: Unknown result type (might be due to invalid IL or missing references) //IL_04e0: Unknown result type (might be due to invalid IL or missing references) //IL_04f0: Unknown result type (might be due to invalid IL or missing references) //IL_0500: Unknown result type (might be due to invalid IL or missing references) //IL_0510: Unknown result type (might be due to invalid IL or missing references) //IL_0525: Unknown result type (might be due to invalid IL or missing references) //IL_0535: Unknown result type (might be due to invalid IL or missing references) //IL_0545: Unknown result type (might be due to invalid IL or missing references) //IL_0555: Unknown result type (might be due to invalid IL or missing references) //IL_0565: Unknown result type (might be due to invalid IL or missing references) //IL_0575: Unknown result type (might be due to invalid IL or missing references) //IL_0585: Unknown result type (might be due to invalid IL or missing references) //IL_0595: Unknown result type (might be due to invalid IL or missing references) //IL_05a5: Unknown result type (might be due to invalid IL or missing references) //IL_05b5: Unknown result type (might be due to invalid IL or missing references) //IL_05c5: Unknown result type (might be due to invalid IL or missing references) //IL_05d5: Unknown result type (might be due to invalid IL or missing references) //IL_05ea: Unknown result type (might be due to invalid IL or missing references) //IL_05fa: Unknown result type (might be due to invalid IL or missing references) //IL_060a: Unknown result type (might be due to invalid IL or missing references) //IL_061a: Unknown result type (might be due to invalid IL or missing references) //IL_062a: Unknown result type (might be due to invalid IL or missing references) //IL_063a: Unknown result type (might be due to invalid IL or missing references) //IL_064a: Unknown result type (might be due to invalid IL or missing references) //IL_065a: Unknown result type (might be due to invalid IL or missing references) //IL_066f: Unknown result type (might be due to invalid IL or missing references) //IL_067f: Unknown result type (might be due to invalid IL or missing references) //IL_068f: Unknown result type (might be due to invalid IL or missing references) //IL_069f: Unknown result type (might be due to invalid IL or missing references) //IL_06af: Unknown result type (might be due to invalid IL or missing references) //IL_06bf: Unknown result type (might be due to invalid IL or missing references) //IL_06cf: Unknown result type (might be due to invalid IL or missing references) //IL_06df: Unknown result type (might be due to invalid IL or missing references) //IL_06ef: Unknown result type (might be due to invalid IL or missing references) //IL_06ff: Unknown result type (might be due to invalid IL or missing references) //IL_0714: Unknown result type (might be due to invalid IL or missing references) //IL_0724: Unknown result type (might be due to invalid IL or missing references) //IL_0734: Unknown result type (might be due to invalid IL or missing references) //IL_0744: Unknown result type (might be due to invalid IL or missing references) //IL_0754: Unknown result type (might be due to invalid IL or missing references) //IL_0764: Unknown result type (might be due to invalid IL or missing references) //IL_0774: Unknown result type (might be due to invalid IL or missing references) //IL_0784: Unknown result type (might be due to invalid IL or missing references) //IL_0799: Unknown result type (might be due to invalid IL or missing references) //IL_07a9: Unknown result type (might be due to invalid IL or missing references) //IL_07b9: Unknown result type (might be due to invalid IL or missing references) //IL_07c9: Unknown result type (might be due to invalid IL or missing references) //IL_07d9: Unknown result type (might be due to invalid IL or missing references) //IL_07e9: Unknown result type (might be due to invalid IL or missing references) //IL_07f9: Unknown result type (might be due to invalid IL or missing references) //IL_0809: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(128, 128, (TextureFormat)4, true); ((Texture)val).filterMode = (FilterMode)1; ((Texture)val).wrapMode = (TextureWrapMode)1; Color val2 = default(Color); ((Color)(ref val2))..ctor(0f, 0f, 0f, 0f); Color c = default(Color); ((Color)(ref c))..ctor(color.r * 0.6f, color.g * 0.6f, color.b * 0.6f, 0.6f); Color c2 = default(Color); ((Color)(ref c2))..ctor(color.r, color.g, color.b, 1f); Color[] array = (Color[])(object)new Color[16384]; for (int i = 0; i < array.Length; i++) { array[i] = val2; } val.SetPixels(array); switch (runeIndex) { case 0: DrawLine(val, 20, 20, 108, 108, c, 6); DrawLine(val, 108, 20, 20, 108, c, 6); DrawLine(val, 20, 20, 108, 108, c2, 3); DrawLine(val, 108, 20, 20, 108, c2, 3); break; case 1: DrawLine(val, 64, 16, 64, 112, c, 6); DrawLine(val, 64, 64, 32, 96, c, 5); DrawLine(val, 64, 64, 96, 96, c, 5); DrawLine(val, 64, 16, 64, 112, c2, 3); DrawLine(val, 64, 64, 32, 96, c2, 2); DrawLine(val, 64, 64, 96, 96, c2, 2); break; case 2: DrawLine(val, 40, 20, 40, 108, c, 6); DrawLine(val, 40, 96, 96, 112, c, 5); DrawLine(val, 40, 72, 96, 88, c, 5); DrawLine(val, 40, 20, 40, 108, c2, 3); DrawLine(val, 40, 96, 96, 112, c2, 2); DrawLine(val, 40, 72, 96, 88, c2, 2); break; case 3: DrawLine(val, 40, 20, 40, 112, c, 6); DrawLine(val, 40, 96, 88, 112, c, 5); DrawLine(val, 88, 112, 88, 80, c, 5); DrawLine(val, 88, 80, 40, 96, c, 5); DrawLine(val, 40, 20, 40, 112, c2, 3); DrawLine(val, 40, 96, 88, 112, c2, 2); DrawLine(val, 88, 112, 88, 80, c2, 2); DrawLine(val, 88, 80, 40, 96, c2, 2); break; case 4: DrawLine(val, 64, 16, 64, 112, c, 8); DrawLine(val, 64, 16, 64, 112, c2, 4); break; case 5: DrawLine(val, 64, 16, 64, 112, c, 6); DrawLine(val, 64, 40, 32, 72, c, 5); DrawLine(val, 64, 40, 96, 72, c, 5); DrawLine(val, 64, 16, 64, 112, c2, 3); DrawLine(val, 64, 40, 32, 72, c2, 2); DrawLine(val, 64, 40, 96, 72, c2, 2); break; case 6: DrawLine(val, 36, 16, 36, 112, c, 6); DrawLine(val, 92, 16, 92, 112, c, 6); DrawLine(val, 36, 36, 92, 92, c, 5); DrawLine(val, 36, 16, 36, 112, c2, 3); DrawLine(val, 92, 16, 92, 112, c2, 3); DrawLine(val, 36, 36, 92, 92, c2, 2); break; default: DrawLine(val, 80, 20, 40, 20, c, 5); DrawLine(val, 80, 20, 40, 64, c, 5); DrawLine(val, 40, 64, 80, 108, c, 5); DrawLine(val, 80, 108, 40, 108, c, 5); DrawLine(val, 80, 20, 40, 20, c2, 2); DrawLine(val, 80, 20, 40, 64, c2, 2); DrawLine(val, 40, 64, 80, 108, c2, 2); DrawLine(val, 80, 108, 40, 108, c2, 2); break; case 8: DrawLine(val, 64, 16, 64, 112, c, 6); DrawLine(val, 96, 96, 32, 32, c, 5); DrawLine(val, 64, 16, 64, 112, c2, 3); DrawLine(val, 96, 96, 32, 32, c2, 2); break; case 9: DrawLine(val, 32, 48, 32, 112, c, 6); DrawLine(val, 96, 48, 96, 112, c, 6); DrawLine(val, 32, 48, 64, 16, c, 5); DrawLine(val, 64, 16, 96, 48, c, 5); DrawLine(val, 32, 48, 32, 112, c2, 3); DrawLine(val, 96, 48, 96, 112, c2, 3); DrawLine(val, 32, 48, 64, 16, c2, 2); DrawLine(val, 64, 16, 96, 48, c2, 2); break; case 10: DrawLine(val, 48, 16, 48, 112, c, 6); DrawLine(val, 48, 80, 96, 48, c, 5); DrawLine(val, 48, 16, 48, 112, c2, 3); DrawLine(val, 48, 80, 96, 48, c2, 2); break; case 11: DrawLine(val, 64, 112, 96, 72, c, 5); DrawLine(val, 96, 72, 64, 32, c, 5); DrawLine(val, 64, 32, 32, 72, c, 5); DrawLine(val, 32, 72, 64, 112, c, 5); DrawLine(val, 32, 72, 16, 16, c, 5); DrawLine(val, 96, 72, 112, 16, c, 5); DrawLine(val, 64, 112, 96, 72, c2, 2); DrawLine(val, 96, 72, 64, 32, c2, 2); DrawLine(val, 64, 32, 32, 72, c2, 2); DrawLine(val, 32, 72, 64, 112, c2, 2); DrawLine(val, 32, 72, 16, 16, c2, 2); DrawLine(val, 96, 72, 112, 16, c2, 2); break; case 12: DrawLine(val, 20, 20, 64, 64, c, 5); DrawLine(val, 20, 108, 64, 64, c, 5); DrawLine(val, 108, 20, 64, 64, c, 5); DrawLine(val, 108, 108, 64, 64, c, 5); DrawLine(val, 20, 20, 64, 64, c2, 2); DrawLine(val, 20, 108, 64, 64, c2, 2); DrawLine(val, 108, 20, 64, 64, c2, 2); DrawLine(val, 108, 108, 64, 64, c2, 2); break; case 13: DrawLine(val, 36, 16, 36, 112, c, 6); DrawLine(val, 36, 96, 80, 80, c, 5); DrawLine(val, 80, 80, 36, 64, c, 5); DrawLine(val, 36, 64, 80, 48, c, 5); DrawLine(val, 80, 48, 36, 32, c, 5); DrawLine(val, 36, 16, 36, 112, c2, 3); DrawLine(val, 36, 96, 80, 80, c2, 2); DrawLine(val, 80, 80, 36, 64, c2, 2); DrawLine(val, 36, 64, 80, 48, c2, 2); DrawLine(val, 80, 48, 36, 32, c2, 2); break; case 14: DrawLine(val, 32, 16, 32, 112, c, 6); DrawLine(val, 96, 16, 96, 112, c, 6); DrawLine(val, 32, 112, 96, 64, c, 5); DrawLine(val, 96, 112, 32, 64, c, 5); DrawLine(val, 32, 16, 32, 112, c2, 3); DrawLine(val, 96, 16, 96, 112, c2, 3); DrawLine(val, 32, 112, 96, 64, c2, 2); DrawLine(val, 96, 112, 32, 64, c2, 2); break; case 15: DrawLine(val, 64, 16, 108, 64, c, 6); DrawLine(val, 108, 64, 64, 112, c, 6); DrawLine(val, 64, 112, 20, 64, c, 6); DrawLine(val, 20, 64, 64, 16, c, 6); DrawLine(val, 64, 16, 108, 64, c2, 3); DrawLine(val, 108, 64, 64, 112, c2, 3); DrawLine(val, 64, 112, 20, 64, c2, 3); DrawLine(val, 20, 64, 64, 16, c2, 3); break; } val.Apply(true); return val; } private static void DrawLine(Texture2D tex, int x0, int y0, int x1, int y1, Color c, int thickness) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.Abs(x1 - x0); int num2 = Mathf.Abs(y1 - y0); int num3 = ((x0 < x1) ? 1 : (-1)); int num4 = ((y0 < y1) ? 1 : (-1)); int num5 = num - num2; while (true) { DrawCircle(tex, x0, y0, thickness, c); if (x0 != x1 || y0 != y1) { int num6 = 2 * num5; if (num6 > -num2) { num5 -= num2; x0 += num3; } if (num6 < num) { num5 += num; y0 += num4; } continue; } break; } } private static void DrawCircle(Texture2D tex, int cx, int cy, int r, Color c) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) for (int i = -r; i <= r; i++) { for (int j = -r; j <= r; j++) { if (j * j + i * i <= r * r) { int num = cx + j; int num2 = cy + i; if (num >= 0 && num < 128 && num2 >= 0 && num2 < 128) { tex.SetPixel(num, num2, c); } } } } } } }