Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Earendil Ship v2.4.0
EarendilShip.dll
Decompiled 2 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; using UnityEngine.Networking; using UnityEngine.Profiling; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace EarendilShip; [BepInPlugin("goyboys.earendilship", "Earendil Ship", "2.4.0")] public class EarendilPlugin : BaseUnityPlugin { private class SavedMaterial { public Material mat; public Dictionary<string, Color> colors = new Dictionary<string, Color>(); public Dictionary<string, Color> colorTargets = new Dictionary<string, Color>(); public Dictionary<string, float> floats = new Dictionary<string, float>(); public Dictionary<string, float> floatTargets = new Dictionary<string, float>(); } private class ShipEffects { public List<SavedMaterial> materials = new List<SavedMaterial>(); public GameObject lightObj; public Light light; public GameObject shieldObj; public ZNetView shieldView; public ShieldGenerator shield; public GameObject demisterObj; public ParticleSystemForceField mistField; public AudioSource audio; public bool fading = true; public bool audioFading = true; } private class Chord { public ConfigEntry<KeyboardShortcut> entry; public KeyCode main; public bool[] wanted; public Chord(ConfigEntry<KeyboardShortcut> e) { entry = e; wanted = new bool[ModifierKeys.Length]; Refresh(); } public void Refresh() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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) //IL_0014: 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_004c: 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_0059: Invalid comparison between I4 and Unknown KeyboardShortcut value = entry.Value; main = ((KeyboardShortcut)(ref value)).MainKey; for (int i = 0; i < wanted.Length; i++) { wanted[i] = false; } foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers) { for (int j = 0; j < ModifierKeys.Length; j++) { if ((int)ModifierKeys[j] == (int)modifier) { wanted[j] = true; } } } } } private class PerfCounter { public string name; public long ticks; public long calls; public long worst; public PerfCounter(string n) { name = n; } } public const string GUID = "goyboys.earendilship"; public const string NAME = "Earendil Ship"; public const string VERSION = "2.4.0"; private const string KeyActive = "earendil_active"; private const string KeyStartMs = "earendil_start_ms"; private const string KeyMuted = "earendil_muted"; private const string KeyShield = "earendil_shield"; private const bool ShieldDefault = false; private const bool MistDefault = true; private const string KeyMist = "earendil_mist"; private const string SpecProp = "_SpecColor"; private const float CarrySaneSpeed = 200f; internal static ManualLogSource Log; internal static ConfigEntry<KeyboardShortcut> ToggleKey; internal static ConfigEntry<KeyboardShortcut> MuteKey; internal static ConfigEntry<KeyCode> AscendKey; internal static ConfigEntry<KeyCode> DescendKey; internal static ConfigEntry<KeyboardShortcut> ShieldKey; internal static ConfigEntry<KeyboardShortcut> MistKey; internal static ConfigEntry<float> FlySpeed; internal static ConfigEntry<float> ClimbSpeed; internal static ConfigEntry<float> TurnSpeed; internal static ConfigEntry<float> Acceleration; internal static ConfigEntry<float> GlowIntensity; internal static ConfigEntry<float> LightIntensity; internal static ConfigEntry<float> LightRange; internal static ConfigEntry<float> Shine; internal static ConfigEntry<float> FadeSeconds; internal static ConfigEntry<bool> PlayAudio; internal static ConfigEntry<string> AudioFile; internal static ConfigEntry<float> Volume; internal static ConfigEntry<float> MusicFadeSeconds; internal static ConfigEntry<bool> LoopAudio; internal static ConfigEntry<bool> AudioFromShip; internal static ConfigEntry<bool> AllowPassengerJump; internal static ConfigEntry<bool> EnableShield; internal static ConfigEntry<float> ShieldRadius; internal static ConfigEntry<float> ShieldMargin; internal static ConfigEntry<string> ShieldPrefab; internal static ConfigEntry<float> ShieldHeight; internal static ConfigEntry<bool> EnableMist; internal static ConfigEntry<float> MistRadius; internal static ConfigEntry<bool> LogPerformance; internal static ConfigEntry<float> PerformanceInterval; private static EarendilPlugin instance; private static Action<Ship, float> updateSailSize; private static AudioClip clip; private static bool clipLoading; private static readonly string[] DefaultAudioNames = new string[3] { "earendil.ogg", "earendil.wav", "earendil.mp3" }; private static readonly string[] TintProps = new string[2] { "_Color", "_TintColor" }; private static readonly string[] EmissionProps = new string[2] { "_EmissionColor", "_EmissiveColor" }; private static readonly string[] GlossProps = new string[2] { "_Glossiness", "_GlossMapScale" }; private static Dictionary<Ship, ShipEffects> effects = new Dictionary<Ship, ShipEffects>(); private static HashSet<Ship> gravityOff = new HashSet<Ship>(); private static Ship carryShip; private static Vector3 carryAnchorLocal; private static Vector3 carryAnchorWorld; private static Vector3 carryLastVel; private static readonly string[] ShieldRpcs = new string[4] { "RPC_AddFuel", "RPC_SetFuel", "RPC_Attack", "RPC_HitNow" }; private static GameObject shieldPrefab; private static bool shieldPrefabMissing; private static readonly HashSet<ShieldGenerator> ourShields = new HashSet<ShieldGenerator>(); private static readonly KeyCode[] ModifierKeys = (KeyCode[])(object)new KeyCode[8] { (KeyCode)304, (KeyCode)303, (KeyCode)306, (KeyCode)305, (KeyCode)308, (KeyCode)307, (KeyCode)310, (KeyCode)309 }; private static Chord toggleChord; private static Chord muteChord; private static Chord shieldChord; private static Chord mistChord; private static bool perfEnabled; private static readonly PerfCounter perfShipTick = new PerfCounter("Ship tick postfix"); private static readonly PerfCounter perfSail = new PerfCounter("Sail prefix"); private static readonly PerfCounter perfControls = new PerfCounter("Controls prefix"); private static readonly PerfCounter perfCarry = new PerfCounter("Character tick postfix"); private static readonly PerfCounter perfUpdate = new PerfCounter("Plugin Update"); private static float perfWindowStart; private static long perfHeapStart; private static int perfGen0Start; private void Awake() { //IL_0029: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_0501: Unknown result type (might be due to invalid IL or missing references) //IL_0507: Expected O, but got Unknown //IL_0554: Unknown result type (might be due to invalid IL or missing references) //IL_0561: Expected O, but got Unknown //IL_05ba: Unknown result type (might be due to invalid IL or missing references) //IL_05c8: Expected O, but got Unknown //IL_07c5: Unknown result type (might be due to invalid IL or missing references) //IL_07d3: Expected O, but got Unknown //IL_0622: Unknown result type (might be due to invalid IL or missing references) //IL_062f: Expected O, but got Unknown //IL_068c: Unknown result type (might be due to invalid IL or missing references) //IL_0699: Expected O, but got Unknown //IL_06f5: Unknown result type (might be due to invalid IL or missing references) //IL_0703: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; instance = this; ToggleKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("1. Keys", "Toggle", new KeyboardShortcut((KeyCode)106, (KeyCode[])(object)new KeyCode[0]), "Toggles flight on the ship whose helm you hold."); MuteKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("1. Keys", "Mute music", new KeyboardShortcut((KeyCode)106, (KeyCode[])(object)new KeyCode[1] { (KeyCode)304 }), "Mutes or unmutes the ship's music for everyone, from the helm."); ShieldKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("1. Keys", "Shield", new KeyboardShortcut((KeyCode)106, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Raises or drops the shield dome on the ship whose helm you hold."); MistKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("1. Keys", "Mist clearing", new KeyboardShortcut((KeyCode)106, (KeyCode[])(object)new KeyCode[1] { (KeyCode)306 }), "Turns the ship's mist clearing on or off, from the helm. Note this shares a modifier with the default descend key, so descending while pressing the base key toggles it."); AscendKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("1. Keys", "Ascend", (KeyCode)32, "Hold at the helm to climb. Jump is suppressed at the helm of a flying ship so this does not release it."); DescendKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("1. Keys", "Descend", (KeyCode)306, "Hold at the helm to descend. Crouch is suppressed at the helm of a flying ship."); FlySpeed = ((BaseUnityPlugin)this).Config.Bind<float>("2. Flight", "Flight speed", 25f, "Metres per second at Full sail."); ClimbSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("2. Flight", "Climb speed", 6f, "Metres per second while holding ascend or descend."); TurnSpeed = ((BaseUnityPlugin)this).Config.Bind<float>("2. Flight", "Turn speed", 45f, "Degrees per second at full rudder."); Acceleration = ((BaseUnityPlugin)this).Config.Bind<float>("2. Flight", "Acceleration seconds", 6f, "Seconds to build from standstill to full flight speed, and to slow back down. 0 = instant."); GlowIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("3. Light", "Glow intensity", 0.7f, "Emission strength on the hull and sail."); LightIntensity = ((BaseUnityPlugin)this).Config.Bind<float>("3. Light", "Light intensity", 1.2f, "Brightness of the white point light carried by the ship."); LightRange = ((BaseUnityPlugin)this).Config.Bind<float>("3. Light", "Light range", 40f, "Radius the ship lights up around itself."); Shine = ((BaseUnityPlugin)this).Config.Bind<float>("3. Light", "Shine", 0f, "Surface smoothness while flying, 0 to 1. 0 leaves materials untouched. Higher values look glossier but cause sparkly, spotty highlights on detailed textures."); FadeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("3. Light", "Fade-in seconds", 2.5f, "How long the glow and light take to reach full strength when flight starts. 0 = instant."); PlayAudio = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Audio", "Play audio", true, "Play an audio file while a ship is flying."); AudioFile = ((BaseUnityPlugin)this).Config.Bind<string>("4. Audio", "Audio file", "", "Audio file to play. Absolute path, or a filename next to this plugin. Leave empty to auto-detect earendil.ogg / .wav / .mp3 in BepInEx/EarendilShip, then in the plugin folder. OGG is the most reliable format."); Volume = ((BaseUnityPlugin)this).Config.Bind<float>("4. Audio", "Volume", 0.4f, "Playback volume, 0 to 1."); MusicFadeSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("4. Audio", "Music fade-in seconds", 3f, "How long the music takes to reach full volume when flight starts. 0 = instant."); LoopAudio = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Audio", "Loop", true, "Repeat until flight is switched off."); AudioFromShip = ((BaseUnityPlugin)this).Config.Bind<bool>("4. Audio", "Play from ship", true, "Positional audio emitted by the ship. Disable for flat non-positional playback."); AllowPassengerJump = ((BaseUnityPlugin)this).Config.Bind<bool>("2. Flight", "Passengers may jump", true, "Let everyone aboard a flying ship jump. The ship's velocity is carried under them while they are in the air, so a jump does not leave the deck behind. The captain never jumps: at the helm that key ascends and would drop the rudder."); EnableShield = ((BaseUnityPlugin)this).Config.Bind<bool>("6. Shield", "Shield", true, "Allow a shield generator dome over a flying ship, held at full power without fuel. The dome starts down and is raised from the helm with the shield key."); ShieldRadius = ((BaseUnityPlugin)this).Config.Bind<float>("6. Shield", "Shield radius", 0f, "Dome radius in metres. 0 fits it to the hull: the ship's own half-length plus the margin below, so it covers the deck and no more."); ShieldMargin = ((BaseUnityPlugin)this).Config.Bind<float>("6. Shield", "Shield margin", 4f, "Metres of dome beyond the hull when the radius is fitted automatically."); ShieldPrefab = ((BaseUnityPlugin)this).Config.Bind<string>("6. Shield", "Shield prefab", "", "Name of the prefab to take the dome from. Empty picks one automatically. Every candidate found is listed in the log at startup."); ShieldHeight = ((BaseUnityPlugin)this).Config.Bind<float>("6. Shield", "Shield height", 2f, "Height of the dome's centre above the ship, in metres."); EnableMist = ((BaseUnityPlugin)this).Config.Bind<bool>("7. Mist", "Clear mist", true, "Clear Mistlands mist around a flying ship."); MistRadius = ((BaseUnityPlugin)this).Config.Bind<float>("7. Mist", "Mist clearing radius", 70f, "Radius cleared, in metres. A wisplight clears 20, so this is three and a half of them."); LogPerformance = ((BaseUnityPlugin)this).Config.Bind<bool>("5. Diagnostics", "Log performance", false, "Periodically log the CPU time and memory used by this mod."); PerformanceInterval = ((BaseUnityPlugin)this).Config.Bind<float>("5. Diagnostics", "Performance log interval", 10f, "Seconds between performance log lines."); toggleChord = new Chord(ToggleKey); muteChord = new Chord(MuteKey); shieldChord = new Chord(ShieldKey); mistChord = new Chord(MistKey); ((BaseUnityPlugin)this).Config.SettingChanged += OnSettingChanged; perfEnabled = LogPerformance.Value; ResetPerfWindow(); try { Harmony val = new Harmony("goyboys.earendilship"); MethodInfo methodInfo = AccessTools.Method(typeof(Ship), "CustomFixedUpdate", (Type[])null, (Type[])null); if (methodInfo == null) { Log.LogError((object)"Ship.CustomFixedUpdate not found. The mod is inactive."); return; } val.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(EarendilPlugin), "ShipUpdatePostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"Patched Ship.CustomFixedUpdate for flight and effects."); MethodInfo methodInfo2 = AccessTools.Method(typeof(Player), "SetControls", (Type[])null, (Type[])null); if (methodInfo2 == null) { Log.LogWarning((object)"Player.SetControls not found. Ascend will also release the helm."); } else { val.Patch((MethodBase)methodInfo2, new HarmonyMethod(AccessTools.Method(typeof(EarendilPlugin), "PlayerControlsPrefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"Patched Player.SetControls to free ascend/descend keys."); } MethodInfo methodInfo3 = AccessTools.Method(typeof(Character), "CustomFixedUpdate", (Type[])null, (Type[])null); if (methodInfo3 == null) { Log.LogWarning((object)"Character.CustomFixedUpdate not found. Jumping aboard will throw you off."); } else { val.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(EarendilPlugin), "CharacterTickPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"Patched Character.CustomFixedUpdate to carry jumping passengers."); } MethodInfo methodInfo4 = AccessTools.Method(typeof(Character), "ApplyGroundForce", (Type[])null, (Type[])null); if (methodInfo4 == null) { Log.LogWarning((object)"Character.ApplyGroundForce not found. Steering a jump aboard will drag you off."); } else { val.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, new HarmonyMethod(AccessTools.Method(typeof(EarendilPlugin), "GroundForcePostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"Patched Character.ApplyGroundForce to steer jumps in the ship's frame."); } MethodInfo methodInfo5 = AccessTools.Method(typeof(ShieldGenerator), "Update", (Type[])null, (Type[])null); if (methodInfo5 == null) { Log.LogWarning((object)"ShieldGenerator.Update not found. The dome will not follow the ship."); } else { val.Patch((MethodBase)methodInfo5, new HarmonyMethod(AccessTools.Method(typeof(EarendilPlugin), "ShieldUpdatePrefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"Patched ShieldGenerator.Update to keep the dome with the ship."); } MethodInfo methodInfo6 = AccessTools.Method(typeof(Ship), "UpdateSailSize", (Type[])null, (Type[])null); if (methodInfo6 != null) { try { updateSailSize = (Action<Ship, float>)Delegate.CreateDelegate(typeof(Action<Ship, float>), null, methodInfo6); } catch (Exception ex) { Log.LogWarning((object)("Could not bind Ship.UpdateSailSize: " + ex.Message)); } } MethodInfo methodInfo7 = AccessTools.Method(typeof(Ship), "UpdateSail", (Type[])null, (Type[])null); if (methodInfo7 == null || updateSailSize == null) { Log.LogWarning((object)"Ship sail internals not found. Sails will follow the helm while flying."); return; } val.Patch((MethodBase)methodInfo7, new HarmonyMethod(AccessTools.Method(typeof(EarendilPlugin), "UpdateSailPrefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Log.LogInfo((object)"Patched Ship.UpdateSail for full, straight sails."); } catch (Exception ex2) { Log.LogError((object)("Harmony patch failed: " + ex2)); } } private static void OnSettingChanged(object sender, SettingChangedEventArgs args) { toggleChord.Refresh(); muteChord.Refresh(); shieldChord.Refresh(); mistChord.Refresh(); } private void Update() { perfEnabled = LogPerformance.Value; long start = PerfBegin(); try { PruneUnloadedShips(); if (ChordDown(toggleChord)) { Toggle(); } if (ChordDown(muteChord)) { ToggleMute(); } if (ChordDown(shieldChord)) { ToggleFlag("earendil_shield", fallback: false, "The shield closes over her.", "The shield opens."); } if (ChordDown(mistChord)) { ToggleFlag("earendil_mist", fallback: true, "The mist draws back.", "The mist returns."); } } finally { PerfEnd(perfUpdate, start); } if (perfEnabled && Time.realtimeSinceStartup - perfWindowStart >= PerformanceInterval.Value) { ReportPerformance(); } } private static ZNetView GetNetView(Ship ship) { ZNetView component = ((Component)ship).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return null; } return component; } private static bool IsFlying(Ship ship) { if ((Object)(object)ship == (Object)null) { return false; } ZNetView netView = GetNetView(ship); if ((Object)(object)netView != (Object)null) { return netView.GetZDO().GetBool("earendil_active", false); } return false; } private static ZDO TakeCommand() { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return null; } Ship controlledShip = localPlayer.GetControlledShip(); if ((Object)(object)controlledShip == (Object)null) { return null; } ZNetView netView = GetNetView(controlledShip); if ((Object)(object)netView == (Object)null) { return null; } netView.ClaimOwnership(); return netView.GetZDO(); } private static void ToggleMute() { ZDO val = TakeCommand(); if (val != null) { bool flag = !val.GetBool("earendil_muted", false); val.Set("earendil_muted", flag); Message(flag ? "The music is silenced." : "The music returns."); } } private static void Toggle() { ZDO val = TakeCommand(); if (val != null) { bool flag = !val.GetBool("earendil_active", false); val.Set("earendil_active", flag); if (flag) { val.Set("earendil_start_ms", (long)(ZNet.instance.GetTimeSeconds() * 1000.0)); } Message(flag ? "Earendil rises." : "The light fades."); } } private static bool ChordDown(Chord chord) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (chord == null) { return false; } if ((int)chord.main == 0 || !Input.GetKeyDown(chord.main)) { return false; } for (int i = 0; i < ModifierKeys.Length; i++) { if (chord.wanted[i] != Input.GetKey(ModifierKeys[i])) { return false; } } return true; } private static void ToggleFlag(string key, bool fallback, string onMessage, string offMessage) { ZDO val = TakeCommand(); if (val != null) { bool flag = !val.GetBool(key, fallback); val.Set(key, flag); Message(flag ? onMessage : offMessage); } } public static void CharacterTickPostfix(Character __instance, float dt) { if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } long start = PerfBegin(); try { CarryTick(dt); } finally { PerfEnd(perfCarry, start); } } private static void CarryTick(float dt) { //IL_0042: 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_004c: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: 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_006b: 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_00c9: 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_00df: 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_00e6: 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_00d8: 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_00b2: 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_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013c: 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_0160: 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_0167: 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_0171: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; Ship standingOnShip = ((Character)localPlayer).GetStandingOnShip(); bool flag = (Object)(object)standingOnShip != (Object)null && IsFlying(standingOnShip); if (flag && (Object)(object)carryShip != (Object)(object)standingOnShip) { carryShip = standingOnShip; carryAnchorLocal = ((Component)standingOnShip).transform.InverseTransformPoint(((Component)localPlayer).transform.position); carryAnchorWorld = ((Component)standingOnShip).transform.TransformPoint(carryAnchorLocal); carryLastVel = Vector3.zero; } else { if ((Object)(object)carryShip == (Object)null) { return; } if (!flag && (((Character)localPlayer).IsOnGround() || ((Character)localPlayer).IsAttached() || ((Character)localPlayer).InNumShipVolumes <= 0 || !IsFlying(carryShip))) { carryShip = null; carryLastVel = Vector3.zero; return; } Transform transform = ((Component)carryShip).transform; Vector3 val = transform.TransformPoint(carryAnchorLocal); Vector3 val2 = ((dt > 0f) ? ((val - carryAnchorWorld) / dt) : Vector3.zero); carryAnchorWorld = val; if (((Vector3)(ref val2)).magnitude > 200f) { carryLastVel = Vector3.zero; return; } if (flag) { carryAnchorLocal = transform.InverseTransformPoint(((Component)localPlayer).transform.position); carryAnchorWorld = transform.TransformPoint(carryAnchorLocal); carryLastVel = val2; return; } Rigidbody component = ((Component)localPlayer).GetComponent<Rigidbody>(); if ((Object)(object)component == (Object)null) { carryShip = null; return; } component.linearVelocity += val2 - carryLastVel; carryLastVel = val2; } } public static void GroundForcePostfix(Character __instance, ref Vector3 vel) { //IL_0026: 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_0030: 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) if (!((Object)(object)carryShip == (Object)null) && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !__instance.IsOnGround()) { vel += carryLastVel; } } private static void UpdateSubsystems(Ship ship, ShipEffects fx) { ZNetView netView = GetNetView(ship); ZDO val = (((Object)(object)netView != (Object)null) ? netView.GetZDO() : null); bool flag = EnableShield.Value && (val == null || val.GetBool("earendil_shield", false)); if (flag && (Object)(object)fx.shieldObj == (Object)null) { CreateShield(ship, fx); } else if (!flag && (Object)(object)fx.shieldObj != (Object)null) { DestroyShield(fx); } bool flag2 = EnableMist.Value && (val == null || val.GetBool("earendil_mist", true)); if (flag2 && (Object)(object)fx.demisterObj == (Object)null) { CreateDemister(ship, fx); } else if (!flag2 && (Object)(object)fx.demisterObj != (Object)null) { Object.Destroy((Object)(object)fx.demisterObj); fx.demisterObj = null; fx.mistField = null; } if ((Object)(object)fx.mistField != (Object)null && fx.mistField.endRange != MistRadius.Value) { fx.mistField.endRange = MistRadius.Value; } } private static bool IsUsableShield(ShieldGenerator shield) { if ((Object)(object)shield.m_shieldDome == (Object)null || (Object)(object)shield.m_energyParticlesFlare == (Object)null) { return false; } if (shield.m_energyParticles == null || shield.m_coloredLights == null) { return false; } for (int i = 0; i < shield.m_energyParticles.Length; i++) { if ((Object)(object)shield.m_energyParticles[i] == (Object)null) { return false; } } for (int j = 0; j < shield.m_coloredLights.Length; j++) { if ((Object)(object)shield.m_coloredLights[j] == (Object)null) { return false; } } return true; } private static GameObject FindShieldPrefab() { if ((Object)(object)shieldPrefab != (Object)null || shieldPrefabMissing) { return shieldPrefab; } ZNetScene val = ZNetScene.instance; if ((Object)(object)val == (Object)null || val.m_prefabs == null) { return null; } string value = ShieldPrefab.Value; GameObject val2 = null; List<string> list = new List<string>(); for (int i = 0; i < val.m_prefabs.Count; i++) { GameObject val3 = val.m_prefabs[i]; if ((Object)(object)val3 == (Object)null) { continue; } ShieldGenerator component = val3.GetComponent<ShieldGenerator>(); if ((Object)(object)component == (Object)null) { continue; } bool flag = IsUsableShield(component); list.Add(((Object)val3).name + (flag ? "" : " (incomplete)")); if (!string.IsNullOrEmpty(value)) { if (((Object)val3).name == value) { shieldPrefab = val3; } } else if (flag && (Object)(object)shieldPrefab == (Object)null) { shieldPrefab = val3; } else if ((Object)(object)val2 == (Object)null) { val2 = val3; } } if (list.Count == 0) { shieldPrefabMissing = true; Log.LogWarning((object)"No ShieldGenerator prefab found. The ship carries no shield."); return null; } Log.LogInfo((object)("Shield generator prefabs: " + string.Join(", ", list.ToArray()) + ".")); if ((Object)(object)shieldPrefab == (Object)null) { if (!string.IsNullOrEmpty(value)) { Log.LogWarning((object)("Configured shield prefab '" + value + "' was not found.")); } shieldPrefab = val2; } if ((Object)(object)shieldPrefab == (Object)null) { shieldPrefabMissing = true; Log.LogWarning((object)"No usable ShieldGenerator prefab. The ship carries no shield."); return null; } Log.LogInfo((object)("Shield generator prefab: " + ((Object)shieldPrefab).name + ".")); return shieldPrefab; } private static void CreateShield(Ship ship, ShipEffects fx) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) GameObject val = FindShieldPrefab(); if ((Object)(object)val == (Object)null) { return; } bool activeSelf = val.activeSelf; val.SetActive(false); GameObject val2; try { val2 = Object.Instantiate<GameObject>(val, ((Component)ship).transform, false); } finally { val.SetActive(activeSelf); } ((Object)val2).name = "EarendilShield"; val2.transform.localPosition = new Vector3(0f, ShieldHeight.Value, 0f); val2.transform.localRotation = Quaternion.identity; StripShieldClone(val2); ShieldGenerator component = val2.GetComponent<ShieldGenerator>(); if ((Object)(object)component == (Object)null) { Object.Destroy((Object)(object)val2); return; } component.m_defaultFuel = component.m_maxFuel; component.m_fuelPerDamage = 0f; component.m_offWhenNoFuel = false; float num = ((ShieldRadius.Value > 0f) ? ShieldRadius.Value : FitRadius(ship)); if (num > 0f) { component.m_maxShieldRadius = num; component.m_minShieldRadius = Mathf.Min(component.m_minShieldRadius, num); } HideShieldModel(val2, component); val2.SetActive(true); fx.shieldObj = val2; fx.shieldView = GetNetView(ship); fx.shield = component; ourShields.Add(component); Log.LogInfo((object)("Shield raised on " + ((Object)ship).name + " at radius " + component.m_maxShieldRadius + ".")); } private static float FitRadius(Ship ship) { //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_0055: 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_005e: 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_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) Transform transform = ((Component)ship).transform; float num = 0f; bool flag = false; Collider[] componentsInChildren = ((Component)ship).GetComponentsInChildren<Collider>(true); Vector3 val2 = default(Vector3); foreach (Collider val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !val.isTrigger && val.enabled) { Bounds bounds = val.bounds; Vector3 center = ((Bounds)(ref bounds)).center; Vector3 extents = ((Bounds)(ref bounds)).extents; for (int j = 0; j < 8; j++) { ((Vector3)(ref val2))..ctor(center.x + (((j & 1) == 0) ? (0f - extents.x) : extents.x), center.y + (((j & 2) == 0) ? (0f - extents.y) : extents.y), center.z + (((j & 4) == 0) ? (0f - extents.z) : extents.z)); Vector3 val3 = transform.InverseTransformPoint(val2); num = Mathf.Max(num, Mathf.Abs(val3.x)); num = Mathf.Max(num, Mathf.Abs(val3.z)); flag = true; } } } if (!flag) { return 0f; } return num + ShieldMargin.Value; } private static void HideShieldModel(GameObject clone, ShieldGenerator shield) { Transform val = (((Object)(object)shield.m_shieldDome != (Object)null) ? shield.m_shieldDome.transform : null); if ((Object)(object)val != (Object)null && !val.IsChildOf(clone.transform)) { val = null; } Renderer[] componentsInChildren = clone.GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { if ((Object)(object)val == (Object)null || !((Component)componentsInChildren[i]).transform.IsChildOf(val)) { componentsInChildren[i].enabled = false; } } Light[] componentsInChildren2 = clone.GetComponentsInChildren<Light>(true); for (int j = 0; j < componentsInChildren2.Length; j++) { if ((Object)(object)val == (Object)null || !((Component)componentsInChildren2[j]).transform.IsChildOf(val)) { ((Behaviour)componentsInChildren2[j]).enabled = false; } } AudioSource[] componentsInChildren3 = clone.GetComponentsInChildren<AudioSource>(true); for (int k = 0; k < componentsInChildren3.Length; k++) { if ((Object)(object)val == (Object)null || !((Component)componentsInChildren3[k]).transform.IsChildOf(val)) { ((Behaviour)componentsInChildren3[k]).enabled = false; } } Log.LogInfo((object)("Shield model hidden" + (((Object)(object)val != (Object)null) ? ", dome kept." : "; no dome of its own."))); } public static void ShieldUpdatePrefix(ShieldGenerator __instance, ref float ___m_radiusSent) { if (ourShields.Count > 0 && ourShields.Contains(__instance)) { ___m_radiusSent = float.MinValue; } } private static void DestroyShield(ShipEffects fx) { if ((Object)(object)fx.shieldObj != (Object)null) { Object.Destroy((Object)(object)fx.shieldObj); fx.shieldObj = null; } if ((Object)(object)fx.shield != (Object)null) { ourShields.Remove(fx.shield); fx.shield = null; } if ((Object)(object)fx.shieldView != (Object)null && fx.shieldView.IsValid()) { for (int i = 0; i < ShieldRpcs.Length; i++) { fx.shieldView.Unregister(ShieldRpcs[i]); } } fx.shieldView = null; } private static void StripShieldClone(GameObject clone) { Collider[] componentsInChildren = clone.GetComponentsInChildren<Collider>(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].enabled = false; } StripComponents((Component[])(object)clone.GetComponentsInChildren<ZNetView>(true)); StripComponents((Component[])(object)clone.GetComponentsInChildren<ZSyncTransform>(true)); StripComponents((Component[])(object)clone.GetComponentsInChildren<Piece>(true)); StripComponents((Component[])(object)clone.GetComponentsInChildren<WearNTear>(true)); StripComponents((Component[])(object)clone.GetComponentsInChildren<Destructible>(true)); StripComponents((Component[])(object)clone.GetComponentsInChildren<StaticPhysics>(true)); } private static void StripComponents(Component[] components) { for (int i = 0; i < components.Length; i++) { if ((Object)(object)components[i] != (Object)null) { Object.DestroyImmediate((Object)(object)components[i]); } } } private static void CreateDemister(Ship ship, ShipEffects fx) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("EarendilDemister"); val.transform.SetParent(((Component)ship).transform, false); val.transform.localPosition = new Vector3(0f, 2f, 0f); ParticleSystemForceField val2 = val.AddComponent<ParticleSystemForceField>(); val2.shape = (ParticleSystemForceFieldShape)0; val2.startRange = 0f; val2.endRange = MistRadius.Value; val2.gravity = new MinMaxCurve(-1f); val.AddComponent<Demister>(); fx.demisterObj = val; fx.mistField = val2; Log.LogInfo((object)("Mist clearing on " + ((Object)ship).name + " at " + MistRadius.Value + " metres.")); } public static void ShipUpdatePostfix(Ship __instance) { long start = PerfBegin(); try { FlyTick(__instance); } finally { PerfEnd(perfShipTick, start); } } private static void FlyTick(Ship ship) { //IL_00e5: 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_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Expected I4, but got Unknown //IL_00a5: 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_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_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_016b: 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_01bc: 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_01c5: 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_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) bool flag = IsFlying(ship); SyncEffects(ship, flag); Rigidbody component = ((Component)ship).GetComponent<Rigidbody>(); ZNetView netView = GetNetView(ship); if ((Object)(object)component == (Object)null || (Object)(object)netView == (Object)null) { return; } if (!flag) { if (gravityOff.Remove(ship)) { component.useGravity = true; } return; } Player localPlayer = Player.m_localPlayer; bool flag2 = (Object)(object)localPlayer != (Object)null && (Object)(object)localPlayer.GetControlledShip() == (Object)(object)ship; if (flag2 && !netView.IsOwner()) { netView.ClaimOwnership(); } if (!netView.IsOwner()) { return; } component.useGravity = false; gravityOff.Add(ship); float y = 0f; if (flag2) { if (Input.GetKey(AscendKey.Value)) { y = ClimbSpeed.Value; } else if (Input.GetKey(DescendKey.Value)) { y = 0f - ClimbSpeed.Value; } } float num = 0f; Speed speedSetting = ship.GetSpeedSetting(); switch (speedSetting - 1) { case 3: num = 1f; break; case 2: num = 0.6f; break; case 1: num = 0.3f; break; case 0: num = -0.3f; break; } Vector3 forward = ((Component)ship).transform.forward; forward.y = 0f; if (((Vector3)(ref forward)).sqrMagnitude > 0.0001f) { ((Vector3)(ref forward)).Normalize(); } Vector3 linearVelocity = component.linearVelocity; linearVelocity.y = 0f; float num2 = Vector3.Dot(linearVelocity, forward); float num3 = num * FlySpeed.Value; float value = Acceleration.Value; float num4 = ((value <= 0f) ? num3 : Mathf.MoveTowards(num2, num3, FlySpeed.Value / value * Time.fixedDeltaTime)); Vector3 linearVelocity2 = forward * num4; linearVelocity2.y = y; component.linearVelocity = linearVelocity2; float rudderValue = ship.GetRudderValue(); component.angularVelocity = new Vector3(0f, rudderValue * TurnSpeed.Value * ((float)Math.PI / 180f), 0f); Quaternion val = Quaternion.Euler(0f, ((Component)ship).transform.eulerAngles.y, 0f); component.MoveRotation(Quaternion.Slerp(component.rotation, val, Time.fixedDeltaTime * 4f)); } public static bool UpdateSailPrefix(Ship __instance, float __0, ref Speed ___m_speed) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected I4, but got Unknown //IL_0015: 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_0046: 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_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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_0075: Unknown result type (might be due to invalid IL or missing references) long start = PerfBegin(); try { if (!IsFlying(__instance)) { return true; } Speed val = ___m_speed; ___m_speed = (Speed)4; try { updateSailSize(__instance, __0); } finally { ___m_speed = (Speed)(int)val; } GameObject mastObject = __instance.m_mastObject; if ((Object)(object)mastObject != (Object)null) { Quaternion val2 = Quaternion.LookRotation(-((Component)__instance).transform.forward, ((Component)__instance).transform.up); mastObject.transform.rotation = Quaternion.RotateTowards(mastObject.transform.rotation, val2, 90f * __0); } return false; } finally { PerfEnd(perfSail, start); } } public static void PlayerControlsPrefix(Player __instance, ref bool jump, ref bool crouch) { long start = PerfBegin(); try { if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer)) { if (IsFlying(__instance.GetControlledShip())) { jump = false; crouch = false; } else if (!AllowPassengerJump.Value && IsFlying(((Character)__instance).GetStandingOnShip())) { jump = false; crouch = false; } } } finally { PerfEnd(perfControls, start); } } private static void SyncEffects(Ship ship, bool flying) { bool flag = effects.TryGetValue(ship, out var value); if (flying && !flag) { value = ApplyEffects(ship); effects[ship] = value; flag = true; } else if (!flying && flag) { RemoveEffects(value); effects.Remove(ship); return; } if (!flying) { return; } UpdateSubsystems(ship, value); if (value.fading) { UpdateFade(ship, value); } if ((Object)(object)value.audio != (Object)null) { ZNetView netView = GetNetView(ship); value.audio.mute = (Object)(object)netView != (Object)null && netView.GetZDO().GetBool("earendil_muted", false); if (value.audioFading) { UpdateMusicFade(ship, value); } } } private static void UpdateMusicFade(Ship ship, ShipEffects fx) { float num = FadeProgress(ship, MusicFadeSeconds.Value); fx.audio.volume = Volume.Value * Ease(num); if (num >= 1f) { fx.audioFading = false; } } private static float Ease(float t) { return t * t * (3f - 2f * t); } private static float FadeProgress(Ship ship, float duration) { if (duration <= 0f || (Object)(object)ZNet.instance == (Object)null) { return 1f; } ZNetView netView = GetNetView(ship); if ((Object)(object)netView == (Object)null) { return 1f; } long num = netView.GetZDO().GetLong("earendil_start_ms", 0L); if (num <= 0) { return 1f; } double num2 = ZNet.instance.GetTimeSeconds() - (double)num / 1000.0; return Mathf.Clamp01((float)(num2 / (double)duration)); } private static void UpdateFade(Ship ship, ShipEffects fx) { //IL_0064: 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) float num = FadeProgress(ship, FadeSeconds.Value); float num2 = Ease(num); for (int i = 0; i < fx.materials.Count; i++) { SavedMaterial savedMaterial = fx.materials[i]; if ((Object)(object)savedMaterial.mat == (Object)null) { continue; } foreach (KeyValuePair<string, Color> color in savedMaterial.colors) { savedMaterial.mat.SetColor(color.Key, Color.Lerp(color.Value, savedMaterial.colorTargets[color.Key], num2)); } foreach (KeyValuePair<string, float> @float in savedMaterial.floats) { savedMaterial.mat.SetFloat(@float.Key, Mathf.Lerp(@float.Value, savedMaterial.floatTargets[@float.Key], num2)); } } if ((Object)(object)fx.light != (Object)null) { fx.light.intensity = LightIntensity.Value * num2; } if (num >= 1f) { fx.fading = false; } } private static ShipEffects ApplyEffects(Ship ship) { //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Expected O, but got Unknown //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_021b: 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_008b: 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_00df: 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_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) ShipEffects shipEffects = new ShipEffects(); Dictionary<string, int> dictionary = new Dictionary<string, int>(); Renderer[] componentsInChildren = ((Component)ship).GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Material[] materials = componentsInChildren[i].materials; foreach (Material val in materials) { if ((Object)(object)val == (Object)null) { continue; } SavedMaterial savedMaterial = new SavedMaterial(); savedMaterial.mat = val; for (int k = 0; k < TintProps.Length; k++) { CaptureColor(savedMaterial, TintProps[k], Color.white, dictionary); } for (int l = 0; l < EmissionProps.Length; l++) { CaptureColor(savedMaterial, EmissionProps[l], Color.white * GlowIntensity.Value, dictionary); } if (Shine.Value > 0f) { if (val.HasProperty("_SpecColor")) { Color color = val.GetColor("_SpecColor"); CaptureColor(savedMaterial, "_SpecColor", Color.Lerp(color, Color.white, Shine.Value), dictionary); } for (int m = 0; m < GlossProps.Length; m++) { string text = GlossProps[m]; if (val.HasProperty(text)) { float num = val.GetFloat(text); savedMaterial.floats[text] = num; savedMaterial.floatTargets[text] = Mathf.Max(num, Shine.Value); Count(dictionary, text); } } } val.EnableKeyword("_EMISSION"); shipEffects.materials.Add(savedMaterial); } } shipEffects.lightObj = new GameObject("EarendilLight"); shipEffects.lightObj.transform.SetParent(((Component)ship).transform, false); shipEffects.lightObj.transform.localPosition = new Vector3(0f, 3f, 0f); shipEffects.light = shipEffects.lightObj.AddComponent<Light>(); shipEffects.light.type = (LightType)2; shipEffects.light.color = Color.white; shipEffects.light.intensity = 0f; shipEffects.light.range = LightRange.Value; shipEffects.light.shadows = (LightShadows)0; UpdateFade(ship, shipEffects); StartAudio(ship, shipEffects); List<string> list = new List<string>(); foreach (KeyValuePair<string, int> item in dictionary) { list.Add(item.Key + " x" + item.Value); } Log.LogInfo((object)("Flight started on " + ((Object)ship).name + ": " + shipEffects.materials.Count + " materials (" + ((list.Count > 0) ? string.Join(", ", list.ToArray()) : "no matching properties") + ").")); return shipEffects; } private static void CaptureColor(SavedMaterial entry, string prop, Color target, Dictionary<string, int> matched) { //IL_001d: 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) if (entry.mat.HasProperty(prop)) { entry.colors[prop] = entry.mat.GetColor(prop); entry.colorTargets[prop] = target; Count(matched, prop); } } private static void Count(Dictionary<string, int> counts, string key) { counts.TryGetValue(key, out var value); counts[key] = value + 1; } private static void RemoveEffects(ShipEffects fx) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < fx.materials.Count; i++) { SavedMaterial savedMaterial = fx.materials[i]; if ((Object)(object)savedMaterial.mat == (Object)null) { continue; } foreach (KeyValuePair<string, Color> color in savedMaterial.colors) { savedMaterial.mat.SetColor(color.Key, color.Value); } foreach (KeyValuePair<string, float> @float in savedMaterial.floats) { savedMaterial.mat.SetFloat(@float.Key, @float.Value); } } fx.materials.Clear(); if ((Object)(object)fx.lightObj != (Object)null) { Object.Destroy((Object)(object)fx.lightObj); fx.lightObj = null; fx.light = null; } DestroyShield(fx); if ((Object)(object)fx.demisterObj != (Object)null) { Object.Destroy((Object)(object)fx.demisterObj); fx.demisterObj = null; fx.mistField = null; } StopAudio(fx); } private static void PruneUnloadedShips() { if (effects.Count == 0 && gravityOff.Count == 0) { return; } List<Ship> list = null; foreach (KeyValuePair<Ship, ShipEffects> effect in effects) { if ((Object)(object)effect.Key == (Object)null) { if (list == null) { list = new List<Ship>(); } list.Add(effect.Key); } } if (list != null) { for (int i = 0; i < list.Count; i++) { StopAudio(effects[list[i]]); effects.Remove(list[i]); } } gravityOff.RemoveWhere((Ship s) => (Object)(object)s == (Object)null); ourShields.RemoveWhere((ShieldGenerator s) => (Object)(object)s == (Object)null); } private static string ResolveAudioPath() { string directoryName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); string value = AudioFile.Value; if (!string.IsNullOrEmpty(value)) { string text = (Path.IsPathRooted(value) ? value : Path.Combine(directoryName, value)); if (File.Exists(text)) { return text; } Log.LogWarning((object)("Configured audio file not found: " + text)); return null; } string[] array = new string[2] { Path.Combine(Paths.BepInExRootPath, "EarendilShip"), directoryName }; for (int i = 0; i < array.Length; i++) { for (int j = 0; j < DefaultAudioNames.Length; j++) { string text2 = Path.Combine(array[i], DefaultAudioNames[j]); if (File.Exists(text2)) { return text2; } } } return null; } private static AudioType AudioTypeFor(string path) { string text = Path.GetExtension(path).ToLowerInvariant(); if (!(text == ".wav")) { if (!(text == ".mp3")) { return (AudioType)14; } return (AudioType)13; } return (AudioType)20; } private static void StartAudio(Ship ship, ShipEffects fx) { //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Expected O, but got Unknown if (!PlayAudio.Value || (Object)(object)fx.audio != (Object)null) { return; } if ((Object)(object)clip == (Object)null) { if (!clipLoading && (Object)(object)instance != (Object)null) { string text = ResolveAudioPath(); if (text == null) { Log.LogInfo((object)"No audio file found. Put earendil.ogg in BepInEx/EarendilShip, or set 'Audio file' in the config."); } else { ((MonoBehaviour)instance).StartCoroutine(instance.LoadClip(text)); } } return; } float time = 0f; ZNetView netView = GetNetView(ship); if ((Object)(object)netView != (Object)null && (Object)(object)ZNet.instance != (Object)null) { long num = netView.GetZDO().GetLong("earendil_start_ms", 0L); double num2 = ZNet.instance.GetTimeSeconds() - (double)num / 1000.0; if (num > 0 && num2 > 0.0) { if (LoopAudio.Value) { time = (float)(num2 % (double)clip.length); } else { if (num2 >= (double)clip.length) { return; } time = (float)num2; } } } GameObject val = new GameObject("EarendilAudio"); bool value = AudioFromShip.Value; if (value) { val.transform.SetParent(((Component)ship).transform, false); } fx.audio = val.AddComponent<AudioSource>(); fx.audio.clip = clip; fx.audio.volume = Volume.Value * Ease(FadeProgress(ship, MusicFadeSeconds.Value)); fx.audio.loop = LoopAudio.Value; fx.audio.spatialBlend = (value ? 1f : 0f); fx.audio.rolloffMode = (AudioRolloffMode)1; fx.audio.minDistance = 8f; fx.audio.maxDistance = 160f; fx.audio.time = time; fx.audio.mute = (Object)(object)netView != (Object)null && netView.GetZDO().GetBool("earendil_muted", false); fx.audio.Play(); } private static void StopAudio(ShipEffects fx) { if (!((Object)(object)fx.audio == (Object)null)) { fx.audio.Stop(); Object.Destroy((Object)(object)((Component)fx.audio).gameObject); fx.audio = null; } } private IEnumerator LoadClip(string path) { clipLoading = true; string url = "file:///" + path.Replace("\\", "/"); UnityWebRequest request = UnityWebRequestMultimedia.GetAudioClip(url, AudioTypeFor(path)); yield return request.SendWebRequest(); clipLoading = false; if ((int)request.result != 1) { Log.LogError((object)("Failed to load audio from " + path + ": " + request.error)); yield break; } clip = DownloadHandlerAudioClip.GetContent(request); Log.LogInfo((object)("Loaded audio: " + Path.GetFileName(path))); foreach (KeyValuePair<Ship, ShipEffects> effect in effects) { if ((Object)(object)effect.Key != (Object)null) { StartAudio(effect.Key, effect.Value); } } } private static long PerfBegin() { if (!perfEnabled) { return 0L; } return Stopwatch.GetTimestamp(); } private static void PerfEnd(PerfCounter counter, long start) { if (start != 0) { long num = Stopwatch.GetTimestamp() - start; counter.ticks += num; counter.calls++; if (num > counter.worst) { counter.worst = num; } } } private static void ResetPerfWindow() { perfWindowStart = Time.realtimeSinceStartup; perfHeapStart = GC.GetTotalMemory(forceFullCollection: false); perfGen0Start = GC.CollectionCount(0); PerfCounter[] array = new PerfCounter[5] { perfShipTick, perfSail, perfControls, perfCarry, perfUpdate }; for (int i = 0; i < array.Length; i++) { array[i].ticks = 0L; array[i].calls = 0L; array[i].worst = 0L; } } private static void ReportPerformance() { float num = Time.realtimeSinceStartup - perfWindowStart; if (num <= 0f) { return; } double num2 = 1000.0 / (double)Stopwatch.Frequency; PerfCounter[] array = new PerfCounter[5] { perfShipTick, perfSail, perfControls, perfCarry, perfUpdate }; double num3 = 0.0; List<string> list = new List<string>(); foreach (PerfCounter perfCounter in array) { double num4 = (double)perfCounter.ticks * num2 / (double)num; num3 += num4; double num5 = ((perfCounter.calls > 0) ? ((double)perfCounter.ticks * num2 * 1000.0 / (double)perfCounter.calls) : 0.0); list.Add($"{perfCounter.name}: {(float)perfCounter.calls / num:F0}/s, {num4:F3} ms/s, avg {num5:F1} us, worst {(double)perfCounter.worst * num2:F2} ms"); } int num6 = 0; int num7 = 0; foreach (KeyValuePair<Ship, ShipEffects> effect in effects) { num6 += effect.Value.materials.Count; if ((Object)(object)effect.Value.audio != (Object)null) { num7++; } } long totalMemory = GC.GetTotalMemory(forceFullCollection: false); string text = (((Object)(object)clip == (Object)null) ? "not loaded" : $"{(double)Profiler.GetRuntimeMemorySizeLong((Object)(object)clip) / 1048576.0:F1} MB runtime, {(double)((long)clip.samples * (long)clip.channels * 4) / 1048576.0:F1} MB PCM estimate"); Log.LogInfo((object)string.Format("[perf] window {0:F1}s | mod CPU {1:F3} ms/s ({2:F3}% of one core) | {3}", num, num3, num3 / 10.0, string.Join(" | ", list.ToArray()))); Log.LogInfo((object)$"[perf] flying ships {effects.Count}, owned-flying {gravityOff.Count}, instanced materials {num6}, audio sources {num7} | audio clip {text} | managed heap {(double)totalMemory / 1048576.0:F1} MB (delta {(double)(totalMemory - perfHeapStart) / 1048576.0:+0.0;-0.0} MB), gen0 GCs {GC.CollectionCount(0) - perfGen0Start} | Unity allocated {(double)Profiler.GetTotalAllocatedMemoryLong() / 1048576.0:F1} MB, mono used {(double)Profiler.GetMonoUsedSizeLong() / 1048576.0:F1} MB"); ResetPerfWindow(); } private static void Message(string text) { Log.LogInfo((object)text); if ((Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)2, text, 0, (Sprite)null, false); } } }