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 OrbLights v1.0.0
BepInEx/plugins/OrbLights/OrbLights.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("OrbLights")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("OrbLights")] [assembly: AssemblyTitle("OrbLights")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 OrbLights { public sealed class OrbInstance : MonoBehaviour { internal Light Point; internal bool Lit = true; internal float Distance2; private Fireplace fire; private ZNetView view; private Transform orb; private int revision = -1; private bool registered; private bool requiredFuel; private static readonly MethodInfo UpdateFuel = AccessTools.Method(typeof(Fireplace), "UpdateFireplace", (Type[])null, (Type[])null); private void Start() { fire = ((Component)this).GetComponent<Fireplace>(); view = ((Component)this).GetComponent<ZNetView>(); orb = ((Component)this).transform.Find("OrbLights_Orb"); Point = (Object.op_Implicit((Object)(object)orb) ? ((Component)orb).GetComponent<Light>() : null); if (Object.op_Implicit((Object)(object)view) && view.IsValid()) { if (Object.op_Implicit((Object)(object)fire)) { ((MonoBehaviour)fire).CancelInvoke(); } if (Object.op_Implicit((Object)(object)Plugin.Instance)) { Plugin.Instance.Orbs.Add(this); registered = true; Refresh(fuelTick: true); } } } internal void Refresh(bool fuelTick) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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_0231: 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) Plugin instance = Plugin.Instance; if (!Object.op_Implicit((Object)(object)instance) || !Object.op_Implicit((Object)(object)view) || !view.IsValid()) { if (Object.op_Implicit((Object)(object)Point)) { ((Behaviour)Point).enabled = false; } Lit = false; return; } Settings options = instance.Options; if (revision != instance.Revision) { revision = instance.Revision; instance.ApplyRecipe(((Component)this).GetComponent<Piece>()); if (Object.op_Implicit((Object)(object)orb)) { orb.localScale = Vector3.one * options.F(options.Size, 0.05f, 0.6f); } if (Object.op_Implicit((Object)(object)Point)) { Point.color = options.LightColor; Point.range = options.EffectiveRadius; Point.intensity = options.F(options.Intensity, 0f, 4f); Point.shadows = (LightShadows)((options.Preset.Value == PerformancePreset.Custom && options.Shadows.Value) ? 2 : 0); } if (Object.op_Implicit((Object)(object)fire)) { if (options.Fuel.Value != requiredFuel && view.IsOwner()) { view.GetZDO().Set(ZDOVars.s_lastTime, ZNet.instance.GetTime().Ticks); } requiredFuel = options.Fuel.Value; fire.m_infiniteFuel = !options.Fuel.Value; fire.m_canRefill = options.Fuel.Value; fire.m_secPerFuel = 3600f / options.F(options.BurnRate, 0.05f, 10f); } } if (fuelTick) { bool flag = false; if (options.Rain.Value && Object.op_Implicit((Object)(object)EnvMan.instance) && EnvMan.IsWet()) { float num = default(float); bool flag2 = default(bool); Cover.GetCoverForPoint(Object.op_Implicit((Object)(object)orb) ? orb.position : ((Component)this).transform.position, ref num, ref flag2, 0.5f); flag = !flag2; } Lit = !flag && (!options.Fuel.Value || view.GetZDO().GetFloat(ZDOVars.s_fuel, 1f) > 0f); if (options.Fuel.Value && Object.op_Implicit((Object)(object)fire) && view.IsOwner()) { UpdateFuel.Invoke(fire, null); } if (Object.op_Implicit((Object)(object)orb) && ((Component)orb).gameObject.activeSelf != Lit) { ((Component)orb).gameObject.SetActive(Lit); } } } private void OnDestroy() { if (registered && Object.op_Implicit((Object)(object)Plugin.Instance)) { Plugin.Instance.Orbs.Remove(this); } } } [HarmonyPatch(typeof(Fireplace), "Awake")] internal static class FireplaceAwakePatch { private static void Postfix(Fireplace __instance) { if (Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<OrbInstance>())) { ((MonoBehaviour)__instance).CancelInvoke(); } } } [HarmonyPatch(typeof(Fireplace), "IsBurning")] internal static class FireplaceBurnPatch { private static bool Prefix(Fireplace __instance, ref bool __result) { OrbInstance component = ((Component)__instance).GetComponent<OrbInstance>(); if (!Object.op_Implicit((Object)(object)component)) { return true; } __result = component.Lit; return false; } } [HarmonyPatch(typeof(Fireplace), "Interact")] internal static class FireplaceInteractPatch { private static bool Prefix(Fireplace __instance, ref bool __result) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<OrbInstance>())) { return true; } __result = false; if (Object.op_Implicit((Object)(object)Plugin.Instance) && Plugin.Instance.Options.Fuel.Value) { return PrivateArea.CheckAccess(((Component)__instance).transform.position, 0f, true, false); } return false; } } [HarmonyPatch(typeof(Fireplace), "UseItem")] internal static class FireplaceUseItemPatch { private static bool Prefix(Fireplace __instance, ref bool __result) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)((Component)__instance).GetComponent<OrbInstance>())) { return true; } __result = false; if (Object.op_Implicit((Object)(object)Plugin.Instance) && Plugin.Instance.Options.Fuel.Value) { return PrivateArea.CheckAccess(((Component)__instance).transform.position, 0f, true, false); } return false; } } [BepInPlugin("org.orblights.valheim", "OrbLights", "1.0.0")] [BepInDependency("com.jotunn.jotunn", "2.30.2")] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "org.orblights.valheim"; public const string PrefabName = "OrbLights_OrbTorch"; internal static Plugin Instance; internal Settings Options; internal Material OrbMaterial; internal int Revision; internal readonly HashSet<OrbInstance> Orbs = new HashSet<OrbInstance>(); private readonly List<OrbInstance> candidates = new List<OrbInstance>(); private readonly List<OrbInstance> active = new List<OrbInstance>(); private Harmony harmony; private Texture2D iconTexture; private Sprite icon; private DateTime configWrite; private bool dirty = true; private float nextFuel; private float nextLog; private float nextConfig; private CustomPiece custom; private void Awake() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown Instance = this; Options = new Settings(((BaseUnityPlugin)this).Config); ((BaseUnityPlugin)this).Config.SettingChanged += Changed; harmony = new Harmony("org.orblights.valheim"); harmony.PatchAll(typeof(Plugin).Assembly); PrefabManager.OnVanillaPrefabsAvailable += Register; PieceManager.OnPiecesRegistered += PiecesReady; SynchronizationManager.OnConfigurationSynchronized += Synchronized; ((MonoBehaviour)this).StartCoroutine(Schedule()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"OrbLights 1.0.0 initialized; global color controls, centralized light budget, Jotunn required on all peers."); } private void Changed(object sender, SettingChangedEventArgs e) { dirty = true; } private void Synchronized(object sender, ConfigurationSynchronizationEventArgs e) { Options.ApplyLock(); dirty = true; } private void PiecesReady() { dirty = true; ApplyRecipe(); } internal void ApplyRecipe(Piece piece = null) { //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_00cd: 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_00eb: Expected O, but got Unknown //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)ObjectDB.instance) || custom == null) { return; } if (!Object.op_Implicit((Object)(object)piece)) { piece = custom.PiecePrefab.GetComponent<Piece>(); } List<Requirement> list = new List<Requirement>(); string[] array = new string[3] { "Wood", "Resin", "SurtlingCore" }; int[] array2 = new int[3] { Options.Wood.Value, Options.Resin.Value, Options.Core.Value }; for (int i = 0; i < 3; i++) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(array[i]); if (!Object.op_Implicit((Object)(object)itemPrefab)) { return; } if (array2[i] > 0) { list.Add(new Requirement { m_resItem = itemPrefab.GetComponent<ItemDrop>(), m_amount = Mathf.Clamp(array2[i], 0, 100), m_recover = true }); } } piece.m_resources = list.ToArray(); GameObject val = ((Options.Station.Value == "None") ? null : PrefabManager.Instance.GetPrefab(Options.Station.Value)); piece.m_craftingStation = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<CraftingStation>() : null); PieceCategory? pieceCategory = PieceManager.Instance.GetPieceCategory(Options.Category.Value); if (pieceCategory.HasValue) { piece.m_category = pieceCategory.Value; } } private void Register() { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Invalid comparison between Unknown and I4 //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_014c: Expected O, but got Unknown //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Invalid comparison between Unknown and I4 //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Expected O, but got Unknown //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_02fa: Expected O, but got Unknown //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Expected O, but got Unknown if (custom != null) { return; } try { GameObject prefab = PrefabManager.Instance.GetPrefab("piece_groundtorch_wood"); if (!Object.op_Implicit((Object)(object)prefab)) { throw new InvalidOperationException("Vanilla piece_groundtorch_wood is unavailable."); } Shader val = Shader.Find("Standard") ?? Shader.Find("Custom/Standard") ?? Shader.Find("Custom/StaticRock") ?? Shader.Find("Unlit/Color"); if (!Object.op_Implicit((Object)(object)val)) { Material val2 = ((IEnumerable<Material>)Resources.FindObjectsOfTypeAll<Material>()).FirstOrDefault((Func<Material, bool>)((Material m) => Object.op_Implicit((Object)(object)m) && Object.op_Implicit((Object)(object)m.shader) && m.HasProperty("_EmissionColor") && m.HasProperty("_Color"))); if (Object.op_Implicit((Object)(object)val2)) { val = val2.shader; } } if (!Object.op_Implicit((Object)(object)val) && (int)SystemInfo.graphicsDeviceType == 4) { Material? obj = (from r in prefab.GetComponentsInChildren<Renderer>(true) select r.sharedMaterial).FirstOrDefault((Func<Material, bool>)((Material m) => Object.op_Implicit((Object)(object)m) && Object.op_Implicit((Object)(object)m.shader))); val = ((obj != null) ? obj.shader : null); } if (!Object.op_Implicit((Object)(object)val) || (!val.isSupported && (int)SystemInfo.graphicsDeviceType != 4)) { throw new InvalidOperationException("No supported orb shader found; refusing to register a broken piece."); } OrbMaterial = new Material(val) { name = "OrbLights_SharedOrb" }; if (OrbMaterial.HasProperty("_MainTex")) { OrbMaterial.SetTexture("_MainTex", (Texture)(object)Texture2D.whiteTexture); } if (OrbMaterial.HasProperty("_Glossiness")) { OrbMaterial.SetFloat("_Glossiness", 0.35f); } if (OrbMaterial.HasProperty("_Metallic")) { OrbMaterial.SetFloat("_Metallic", 0f); } using (Stream stream = typeof(Plugin).Assembly.GetManifestResourceStream("OrbLights.icon.png")) { using MemoryStream memoryStream = new MemoryStream(); if (stream == null) { throw new InvalidOperationException("Embedded Orb Torch icon missing."); } stream.CopyTo(memoryStream); iconTexture = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(iconTexture, memoryStream.ToArray())) { throw new InvalidOperationException("Could not decode icon."); } icon = Sprite.Create(iconTexture, new Rect(0f, 0f, (float)((Texture)iconTexture).width, (float)((Texture)iconTexture).height), new Vector2(0.5f, 0.5f), 100f); } List<RequirementConfig> list = new List<RequirementConfig>(); AddCost(list, "Wood", Options.Wood.Value); AddCost(list, "Resin", Options.Resin.Value); AddCost(list, "SurtlingCore", Options.Core.Value); PieceConfig val3 = new PieceConfig(); val3.Name = "Orb Torch"; val3.Description = "A quiet glowing orb on a wooden stand."; val3.PieceTable = "Hammer"; val3.Category = Options.Category.Value; val3.Usage = new string[2] { "Furniture", "Lighting" }; val3.CraftingStation = ((Options.Station.Value == "None") ? "" : Options.Station.Value); val3.Icon = icon; val3.Requirements = list.ToArray(); custom = new CustomPiece("OrbLights_OrbTorch", "piece_groundtorch_wood", val3); GameObject piecePrefab = custom.PiecePrefab; if (list.Count == 0) { piecePrefab.GetComponent<Piece>().m_resources = Array.Empty<Requirement>(); } if (Options.Station.Value == "None") { piecePrefab.GetComponent<Piece>().m_craftingStation = null; } Sanitize(piecePrefab); if (!PieceManager.Instance.AddPiece(custom)) { throw new InvalidOperationException("Jotunn rejected piece registration."); } dirty = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("Registered OrbLights_OrbTorch with shader " + ((Object)val).name + "; vanilla torch unchanged.")); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("OrbLights registration failed: " + ex)); } } private static void AddCost(List<RequirementConfig> costs, string item, int amount) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Expected O, but got Unknown if (amount > 0) { costs.Add(new RequirementConfig(item, Mathf.Clamp(amount, 0, 100), 0, true)); } } private unsafe void Sanitize(GameObject root) { //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_0077: 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_0081: 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) //IL_01f9: Expected O, but got Unknown //IL_0259: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Expected O, but got Unknown //IL_0264: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Expected O, but got Unknown //IL_02ee: 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_031f: Unknown result type (might be due to invalid IL or missing references) //IL_037e: Unknown result type (might be due to invalid IL or missing references) //IL_037f: Unknown result type (might be due to invalid IL or missing references) Fireplace component = root.GetComponent<Fireplace>(); if (!Object.op_Implicit((Object)(object)component)) { throw new InvalidOperationException("Standing torch has no Fireplace; prefab layout changed."); } Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(0f, 1.35f, 0f); Light componentInChildren = root.GetComponentInChildren<Light>(true); if (Object.op_Implicit((Object)(object)componentInChildren)) { val = root.transform.InverseTransformPoint(((Component)componentInChildren).transform.position); } else if (Object.op_Implicit((Object)(object)component.m_enabledObject)) { val = root.transform.InverseTransformPoint(component.m_enabledObject.transform.position); } GameObject[] array = (GameObject[])(object)new GameObject[8] { component.m_enabledObject, component.m_enabledObjectLow, component.m_enabledObjectHigh, component.m_fullObject, component.m_halfObject, component.m_emptyObject, component.m_playerBaseObject, component.m_snowMelter }; foreach (GameObject val2 in array) { if (Object.op_Implicit((Object)(object)val2) && (Object)(object)val2 != (Object)(object)root) { val2.SetActive(false); } } ParticleSystem[] componentsInChildren = root.GetComponentsInChildren<ParticleSystem>(true); foreach (ParticleSystem obj in componentsInChildren) { obj.Stop(true, (ParticleSystemStopBehavior)0); ((Component)obj).gameObject.SetActive(false); } Component[] componentsInChildren2 = root.GetComponentsInChildren<Component>(true); foreach (Component val3 in componentsInChildren2) { if (val3 is Light || val3 is AudioSource || val3 is ParticleSystem || val3 is ParticleSystemRenderer || val3 is Animator || val3 is Animation || val3 is EffectArea || val3 is SmokeSpawner || val3 is LightLod || ((object)val3).GetType().Name == "LightFlicker" || ((object)val3).GetType().Name == "ZSFX") { Object.DestroyImmediate((Object)(object)val3); } } component.m_enabledObject = new GameObject("OrbLights_FuelState"); component.m_enabledObject.transform.SetParent(root.transform, false); component.m_enabledObjectLow = (component.m_enabledObjectHigh = null); component.m_fullObject = (component.m_halfObject = (component.m_emptyObject = null)); component.m_playerBaseObject = (component.m_snowMelter = null); component.m_smokeSpawner = null; component.m_fuelAddedEffects = new EffectList(); component.m_toggleOnEffects = new EffectList(); component.m_fireworkItemList = Array.Empty<FireworkItem>(); component.m_igniteInterval = 0f; component.m_igniteChance = 0f; component.m_firePrefab = null; component.m_disableCoverCheck = true; component.m_canTurnOff = false; component.m_startFuel = 1f; component.m_maxFuel = 10f; component.m_name = "Orb Torch"; GameObject obj2 = GameObject.CreatePrimitive((PrimitiveType)0); ((Object)obj2).name = "OrbLights_Orb"; obj2.transform.SetParent(root.transform, false); obj2.transform.localPosition = val; obj2.transform.localScale = Vector3.one * Options.F(Options.Size, 0.05f, 0.6f); Object.DestroyImmediate((Object)(object)obj2.GetComponent<Collider>()); MeshRenderer component2 = obj2.GetComponent<MeshRenderer>(); ((Renderer)component2).sharedMaterial = OrbMaterial; ((Renderer)component2).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)component2).receiveShadows = false; Light obj3 = obj2.AddComponent<Light>(); obj3.type = (LightType)2; obj3.shadows = (LightShadows)0; ((Behaviour)obj3).enabled = false; root.AddComponent<OrbInstance>(); ManualLogSource logger = ((BaseUnityPlugin)this).Logger; Vector3 val4 = val; logger.LogInfo((object)("Orb offset from cloned torch light: " + ((object)(*(Vector3*)(&val4))/*cast due to .constrained prefix*/).ToString())); } private void ApplyMaterial() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_0073: 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_00c7: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)OrbMaterial)) { Color val = (Options.Matches.Value ? Options.LightColor : Color.white); if (OrbMaterial.HasProperty("_Color")) { OrbMaterial.SetColor("_Color", val); } if (OrbMaterial.HasProperty("_BaseColor")) { OrbMaterial.SetColor("_BaseColor", val); } if (OrbMaterial.HasProperty("_EmissionColor")) { OrbMaterial.EnableKeyword("_EMISSION"); OrbMaterial.SetColor("_EmissionColor", val * Options.F(Options.Emission, 0f, 5f)); } } } private IEnumerator Schedule() { WaitForSecondsRealtime wait = new WaitForSecondsRealtime(0.1f); int tick = 0; while (true) { int num = tick + 1; tick = num; if (num % 5 == 0) { Refresh(); } if (Options.EffectiveFlicker) { foreach (OrbInstance item in active) { if (Object.op_Implicit((Object)(object)item) && Object.op_Implicit((Object)(object)item.Point)) { item.Point.intensity = Options.F(Options.Intensity, 0f, 4f) * (1f + Mathf.Sin(Time.unscaledTime * Options.F(Options.FlickerSpeed, 0.1f, 5f) * 2f * MathF.PI + (float)((Object)item).GetInstanceID()) * Options.F(Options.FlickerAmount, 0f, 0.5f)); } } } yield return wait; } } private void Refresh() { //IL_0160: 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_0175: Unknown result type (might be due to invalid IL or missing references) if (Time.unscaledTime >= nextConfig) { nextConfig = Time.unscaledTime + 2f; try { DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(((BaseUnityPlugin)this).Config.ConfigFilePath); if (configWrite != default(DateTime) && lastWriteTimeUtc != configWrite) { ((BaseUnityPlugin)this).Config.Reload(); } configWrite = lastWriteTimeUtc; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Config reload failed: " + ex.Message)); } } if (dirty) { dirty = false; Revision++; ApplyMaterial(); ApplyRecipe(); } bool flag = Time.unscaledTime >= nextFuel; if (flag) { nextFuel = Time.unscaledTime + 2f; } candidates.Clear(); Player localPlayer = Player.m_localPlayer; float num = Options.EffectiveDistance * Options.EffectiveDistance; foreach (OrbInstance orb in Orbs) { if (!Object.op_Implicit((Object)(object)orb)) { continue; } orb.Refresh(flag); if (Object.op_Implicit((Object)(object)localPlayer) && ((Behaviour)orb).isActiveAndEnabled && orb.Lit && Object.op_Implicit((Object)(object)orb.Point)) { Vector3 val = ((Component)orb).transform.position - ((Component)localPlayer).transform.position; orb.Distance2 = ((Vector3)(ref val)).sqrMagnitude; if (orb.Distance2 <= num) { candidates.Add(orb); } } } candidates.Sort(delegate(OrbInstance a, OrbInstance b) { int num4 = a.Distance2.CompareTo(b.Distance2); return (num4 == 0) ? ((Object)a).GetInstanceID().CompareTo(((Object)b).GetInstanceID()) : num4; }); foreach (OrbInstance item in active) { if (Object.op_Implicit((Object)(object)item) && Object.op_Implicit((Object)(object)item.Point)) { ((Behaviour)item.Point).enabled = false; } } active.Clear(); int num2 = Math.Min(Options.EffectiveMaximum, candidates.Count); for (int num3 = 0; num3 < num2; num3++) { OrbInstance orbInstance = candidates[num3]; ((Behaviour)orbInstance.Point).enabled = true; active.Add(orbInstance); } if (Options.Debug.Value && Time.unscaledTime >= nextLog) { nextLog = Time.unscaledTime + 30f; ((BaseUnityPlugin)this).Logger.LogInfo((object)$"OrbLights registered={Orbs.Count}, nearby={candidates.Count}, active={active.Count}, budget={Options.EffectiveMaximum}"); } } private void OnDestroy() { ((MonoBehaviour)this).StopAllCoroutines(); PrefabManager.OnVanillaPrefabsAvailable -= Register; PieceManager.OnPiecesRegistered -= PiecesReady; SynchronizationManager.OnConfigurationSynchronized -= Synchronized; ((BaseUnityPlugin)this).Config.SettingChanged -= Changed; Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } foreach (OrbInstance orb in Orbs) { if (Object.op_Implicit((Object)(object)orb) && Object.op_Implicit((Object)(object)orb.Point)) { ((Behaviour)orb.Point).enabled = false; } } Orbs.Clear(); active.Clear(); candidates.Clear(); if (Object.op_Implicit((Object)(object)OrbMaterial)) { Object.Destroy((Object)(object)OrbMaterial); } if (Object.op_Implicit((Object)(object)icon)) { Object.Destroy((Object)(object)icon); } if (Object.op_Implicit((Object)(object)iconTexture)) { Object.Destroy((Object)(object)iconTexture); } Instance = null; } } public enum PerformancePreset { Potato, Performance, Balanced, Quality, Custom } public enum ColorPreset { Custom, WarmWhite, NeutralWhite, CoolWhite, Red, Orange, Yellow, Green, Cyan, Blue, Purple, Pink } public sealed class Settings { public readonly ConfigEntry<bool> EnableLight; public readonly ConfigEntry<bool> Matches; public readonly ConfigEntry<bool> Flicker; public readonly ConfigEntry<bool> Shadows; public readonly ConfigEntry<bool> EmissionOnly; public readonly ConfigEntry<bool> Fuel; public readonly ConfigEntry<bool> Rain; public readonly ConfigEntry<bool> Debug; public readonly ConfigEntry<int> Red; public readonly ConfigEntry<int> Green; public readonly ConfigEntry<int> Blue; public readonly ConfigEntry<int> Maximum; public readonly ConfigEntry<int> Wood; public readonly ConfigEntry<int> Resin; public readonly ConfigEntry<int> Core; public readonly ConfigEntry<float> Intensity; public readonly ConfigEntry<float> Radius; public readonly ConfigEntry<float> Size; public readonly ConfigEntry<float> Emission; public readonly ConfigEntry<float> FlickerAmount; public readonly ConfigEntry<float> FlickerSpeed; public readonly ConfigEntry<float> Distance; public readonly ConfigEntry<float> BurnRate; public readonly ConfigEntry<string> Category; public readonly ConfigEntry<string> Station; public readonly ConfigEntry<PerformancePreset> Preset; public readonly ConfigEntry<ColorPreset> ColorChoice; public readonly ConfigEntry<bool> Lock; private readonly ConfigFile file; public Color LightColor => (Color)(ColorChoice.Value switch { ColorPreset.WarmWhite => RGB(255, 225, 185), ColorPreset.NeutralWhite => Color.white, ColorPreset.CoolWhite => RGB(195, 220, 255), ColorPreset.Red => RGB(255, 50, 40), ColorPreset.Orange => RGB(255, 135, 40), ColorPreset.Yellow => RGB(255, 235, 65), ColorPreset.Green => RGB(75, 255, 90), ColorPreset.Cyan => RGB(65, 245, 255), ColorPreset.Blue => RGB(75, 115, 255), ColorPreset.Purple => RGB(165, 80, 255), ColorPreset.Pink => RGB(255, 110, 195), _ => RGB(Red.Value, Green.Value, Blue.Value), }); public float EffectiveRadius { get { if (Preset.Value != PerformancePreset.Custom) { return (Preset.Value == PerformancePreset.Performance) ? 8 : ((Preset.Value == PerformancePreset.Quality) ? 16 : 12); } return F(Radius, 1f, 25f); } } public float EffectiveDistance { get { if (Preset.Value != PerformancePreset.Custom) { return (Preset.Value == PerformancePreset.Performance) ? 25 : ((Preset.Value == PerformancePreset.Quality) ? 60 : 40); } return F(Distance, 5f, 100f); } } public int EffectiveMaximum { get { if (!EmissionOnly.Value && EnableLight.Value && Preset.Value != PerformancePreset.Potato) { if (Preset.Value != PerformancePreset.Custom) { if (Preset.Value != PerformancePreset.Performance) { if (Preset.Value != PerformancePreset.Quality) { return 32; } return 64; } return 16; } return Mathf.Clamp(Maximum.Value, 0, 128); } return 0; } } public bool EffectiveFlicker { get { if (Preset.Value == PerformancePreset.Custom) { return Flicker.Value; } return false; } } public Settings(ConfigFile config) { file = config; Lock = Bind("7. Multiplayer", "LockConfiguration", value: true, "Lock visual and performance settings to the server. When false these settings are client-local. Recipe and fuel settings always remain server-authoritative. Restart all peers after changing.", null, true); EnableLight = Bind("1. General", "EnableLight", value: true, "Enable real-time point lights; the orb remains visible when disabled."); Category = Bind("1. General", "PieceCategory", "Furniture", "Hammer category. Restart required.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[4] { "Furniture", "Misc", "Building", "Crafting" })); Wood = Number("2. Recipe", "Wood", 2, 0, 100, "Wood cost; zero removes this ingredient. Restart required."); Resin = Number("2. Recipe", "Resin", 1, 0, 100, "Resin cost; zero removes this ingredient. Restart required."); Core = Number("2. Recipe", "SurtlingCore", 1, 0, 100, "Surtling Core cost; zero removes this ingredient. Restart required."); Station = Bind("2. Recipe", "CraftingStationRequirement", "None", "Required station. Restart required.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[6] { "None", "piece_workbench", "forge", "piece_stonecutter", "piece_artisanstation", "piece_magetable" })); ColorChoice = Bind("3. Light Color", "ColorPreset", ColorPreset.Custom, "Global light color preset. Custom uses the RGB values below."); Red = Number("3. Light Color", "Red", 255, 0, 255, "Custom red channel."); Green = Number("3. Light Color", "Green", 225, 0, 255, "Custom green channel."); Blue = Number("3. Light Color", "Blue", 185, 0, 255, "Custom blue channel."); Intensity = Number("4. Light Appearance", "Intensity", 1.2f, 0f, 4f, "Point-light intensity."); Radius = Number("4. Light Appearance", "LightRadius", 12f, 1f, 25f, "Point-light radius in metres. Presets override this unless Custom."); Size = Number("4. Light Appearance", "OrbSize", 0.22f, 0.05f, 0.6f, "Orb diameter in metres."); Emission = Number("4. Light Appearance", "OrbEmissionStrength", 2f, 0f, 5f, "Material emission strength; bloom depends on game settings."); Matches = Bind("4. Light Appearance", "OrbMatchesLightColor", value: false, "Tint the visible orb to the selected light color; otherwise white."); Flicker = Bind("4. Light Appearance", "EnableFlicker", value: false, "Enable centrally sampled flicker on active lights only (10 Hz)."); FlickerAmount = Number("4. Light Appearance", "FlickerAmount", 0.1f, 0f, 0.5f, "Maximum fractional intensity variation."); FlickerSpeed = Number("4. Light Appearance", "FlickerSpeed", 1f, 0.1f, 5f, "Flicker frequency in Hz."); Preset = Bind("5. Performance", "PerformancePreset", PerformancePreset.Balanced, "Potato: emission only. Performance: 8m/25m/16 lights. Balanced: 12m/40m/32. Quality: 16m/60m/64. Custom uses configured radius/distance/count/shadows/flicker."); EmissionOnly = Bind("5. Performance", "EmissionOnlyMode", value: false, "Always disables point lights, including with a preset selected."); Shadows = Bind("5. Performance", "EnableShadows", value: false, "Expensive point-light shadows. Only honored in Custom."); Distance = Number("5. Performance", "MaximumRenderDistance", 40f, 5f, 100f, "Maximum point-light distance from local player in metres. Custom only; emissive geometry is unaffected."); Maximum = Number("5. Performance", "MaximumActiveLights", 32, 0, 128, "Maximum nearby point lights, nearest first. Custom only; zero disables all."); Fuel = Bind("6. Fuel", "RequireFuel", value: false, "Use vanilla Resin refueling and persistent fuel storage. Starts with one Resin unit. When false, no fuel is burned."); BurnRate = Number("6. Fuel", "FuelBurnRate", 1f, 0.05f, 10f, "Resin units per real hour while loaded and lit. Fuel amount persists; consumption resumes on load without charging for offline time."); Rain = Bind("6. Fuel", "ExtinguishInRain", value: false, "Rain extinguishes uncovered orbs. Roofed orbs stay lit."); Debug = Bind("8. Debugging", "EnableDebugLogging", value: false, "Log active and registered light counts every 30 seconds.", null, false); } private ConfigEntry<T> Bind<T>(string section, string key, T value, string description, AcceptableValueBase range = null, bool? sync = null) { //IL_0015: 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_0029: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown return file.Bind<T>(section, key, value, new ConfigDescription(description, range, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = (sync ?? true) } })); } public void ApplyLock() { foreach (KeyValuePair<ConfigDefinition, ConfigEntryBase> item in file) { switch (item.Key.Section) { default: if (!(item.Key.Key == "EnableLight")) { continue; } break; case "3. Light Color": case "4. Light Appearance": case "5. Performance": break; } object[] tags = item.Value.Description.Tags; foreach (object obj in tags) { ConfigurationManagerAttributes val = (ConfigurationManagerAttributes)((obj is ConfigurationManagerAttributes) ? obj : null); if (val != null) { val.IsAdminOnly = Lock.Value; } } } } private ConfigEntry<int> Number(string s, string k, int v, int min, int max, string d) { return Bind(s, k, v, d, (AcceptableValueBase)(object)new AcceptableValueRange<int>(min, max)); } private ConfigEntry<float> Number(string s, string k, float v, float min, float max, string d) { return Bind(s, k, v, d, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max)); } public static float Safe(float value, float fallback, float min, float max) { if (!float.IsNaN(value) && !float.IsInfinity(value)) { return Mathf.Clamp(value, min, max); } return fallback; } public float F(ConfigEntry<float> c, float min, float max) { return Safe(c.Value, (float)((ConfigEntryBase)c).DefaultValue, min, max); } private static Color RGB(int r, int g, int b) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) return new Color((float)Mathf.Clamp(r, 0, 255) / 255f, (float)Mathf.Clamp(g, 0, 255) / 255f, (float)Mathf.Clamp(b, 0, 255) / 255f); } } }