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 LumenControl v0.5.0
LumenControl.dll
Decompiled 8 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JG224.LumenControl.Core; using JG224.LumenControl.Networking; using JG224.ModCore.API; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("LumenControl")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.5.0.0")] [assembly: AssemblyInformationalVersion("0.5.0")] [assembly: AssemblyProduct("LumenControl")] [assembly: AssemblyTitle("LumenControl")] [assembly: AssemblyVersion("0.5.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 JG224.LumenControl { internal sealed class LumenControlConfig { private readonly ConfigFile _file; private readonly List<Tuple<ConfigEntryBase, ConfigScope>> _entries = new List<Tuple<ConfigEntryBase, ConfigScope>>(); private readonly HashSet<string> _reportedInvalidTimes = new HashSet<string>(StringComparer.Ordinal); private byte[] _cachedPolicy; internal ConfigEntry<bool> Enabled { get; } internal ConfigEntry<string> LightsOnTime { get; } internal ConfigEntry<string> LightsOffTime { get; } internal ConfigEntry<bool> DebugLogging { get; } internal ConfigEntry<bool> RespectManualOff { get; } internal ConfigEntry<string> IncludedPrefabs { get; } internal ConfigEntry<string> ExcludedPrefabs { get; } internal ConfigEntry<string> ExcludedLightIds { get; } private LumenControlConfig(ConfigFile file) { _file = file; Enabled = Add<bool>(file.Bind<bool>("Lumen", "Enabled", true, "Master switch for scheduled fuel-free decorative lights."), (ConfigScope)2); LightsOnTime = Add<string>(file.Bind<string>("Lumen", "LightsOnTime", "17:30", "Start of the free lights-on window in HH:mm 24-hour time."), (ConfigScope)2); LightsOffTime = Add<string>(file.Bind<string>("Lumen", "LightsOffTime", "09:00", "End of the free lights-on window in HH:mm 24-hour time."), (ConfigScope)2); RespectManualOff = Add<bool>(file.Bind<bool>("Lumen", "RespectManualOff", false, "Keep manually extinguished lights off during the free-fuel window."), (ConfigScope)2); IncludedPrefabs = Add<string>(file.Bind<string>("Lumen", "IncludedPrefabs", "", "Additional exact Fireplace prefab names, comma separated (maximum 2048 characters)."), (ConfigScope)2); ExcludedPrefabs = Add<string>(file.Bind<string>("Lumen", "ExcludedPrefabs", "", "Exact prefab names excluded from scheduling, comma separated (maximum 2048 characters)."), (ConfigScope)2); ExcludedLightIds = Add<string>(file.Bind<string>("Lumen", "ExcludedLightIds", "", "Individual placed-light ZDO IDs to exclude, comma separated. Aim at a light and use lumen_lightid to identify it. Maximum 2048 characters."), (ConfigScope)2); DebugLogging = Add<bool>(file.Bind<bool>("Diagnostics", "DebugLogging", false, "Enable verbose LumenControl diagnostics."), (ConfigScope)5); } internal byte[] PolicyBytes() { return _cachedPolicy ?? (_cachedPolicy = CreatePolicy().Serialize()); } internal static LumenControlConfig Load(BaseUnityPlugin plugin, string configDirectory, ManualLogSource log) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown if (!Directory.Exists(configDirectory)) { Directory.CreateDirectory(configDirectory); } string text = LegacyLumenConfigRules.FindImportSource(Directory.GetFiles(configDirectory, "*.cfg", SearchOption.TopDirectoryOnly)); LumenControlConfig lumenControlConfig = new LumenControlConfig(PluginConfigFiles.Attach(plugin, new ConfigFile(Path.Combine(configDirectory, "jg224.LumenControl.cfg"), true, plugin.Info.Metadata))); if (text != null) { lumenControlConfig.ImportLegacy(text, log); } return lumenControlConfig; } internal LumenPolicy CreatePolicy() { return new LumenPolicy { Enabled = Enabled.Value, LightsOnMinutes = ParseTimeOrDefault(LightsOnTime, 1050), LightsOffMinutes = ParseTimeOrDefault(LightsOffTime, 540), RespectManualOff = RespectManualOff.Value, IncludedPrefabs = IncludedPrefabs.Value, ExcludedPrefabs = ExcludedPrefabs.Value, ExcludedLightIds = ExcludedLightIds.Value }; } internal IEnumerable<IDisposable> RegisterMetadata(ICoreServices services, ModuleId owner) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) foreach (Tuple<ConfigEntryBase, ConfigScope> pair in _entries) { yield return services.Configuration.Register(new ConfigSettingDescriptor(owner, pair.Item1.Definition.Section, pair.Item1.Definition.Key, pair.Item2, (Func<string>)(() => Convert.ToString(pair.Item1.BoxedValue, CultureInfo.InvariantCulture)), 1)); } } private ushort ParseTimeOrDefault(ConfigEntry<string> entry, int fallback) { if (ClockRules.TryParseTime(entry.Value, out var minutes)) { return minutes; } string item = ((object)((ConfigEntryBase)entry).Definition)?.ToString() + "=" + entry.Value; if (_reportedInvalidTimes.Add(item)) { ManualLogSource log = Plugin.Log; if (log != null) { log.LogWarning((object)(((object)((ConfigEntryBase)entry).Definition)?.ToString() + " must use HH:mm; using " + ClockRules.FormatTime(fallback) + ".")); } } return (ushort)fallback; } private void ImportLegacy(string path, ManualLogSource log) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown try { ConfigFile val = new ConfigFile(path, false); Enabled.Value = val.Bind<bool>("Lumen", "Enabled", Enabled.Value, (ConfigDescription)null).Value; LightsOnTime.Value = val.Bind<string>("Lumen", "LightsOnTime", LightsOnTime.Value, (ConfigDescription)null).Value; LightsOffTime.Value = val.Bind<string>("Lumen", "LightsOffTime", LightsOffTime.Value, (ConfigDescription)null).Value; _file.Save(); if (log != null) { log.LogInfo((object)("Imported Lumen settings from " + Path.GetFileName(path) + ".")); } } catch (Exception ex) { if (log != null) { log.LogWarning((object)("Could not import GeneralTweaks Lumen settings; using defaults. " + ex.Message)); } } } private ConfigEntry<T> Add<T>(ConfigEntry<T> entry, ConfigScope scope) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) _entries.Add(Tuple.Create<ConfigEntryBase, ConfigScope>((ConfigEntryBase)(object)entry, scope)); entry.SettingChanged += delegate { _cachedPolicy = null; _reportedInvalidTimes.Clear(); }; return entry; } } [BepInPlugin("jg224.LumenControl", "LumenControl", "0.5.0")] [BepInDependency("com.jg224.modcore", "0.5.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "jg224.LumenControl"; public const string PluginName = "LumenControl"; public const string PluginVersion = "0.5.0"; public const string ModCoreGuid = "com.jg224.modcore"; public const string GeneralTweaksGuid = "JG224.GeneralTweaks"; public const int ProtocolVersion = 2; public static readonly ModuleId ModuleId = new ModuleId("lumencontrol"); private readonly List<IDisposable> _registrations = new List<IDisposable>(); private Harmony _harmony; private PolicyNetwork _network; private bool _active; private bool _shutDown; internal static ManualLogSource Log { get; private set; } internal static LumenControlConfig Settings { get; private set; } internal static LumenPolicy Policy { get; private set; } = new LumenPolicy(); internal static ICoreServices Core { get; private set; } internal static bool HasPolicy { get; private set; } private void Awake() { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_0172: 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) Log = ((BaseUnityPlugin)this).Logger; Settings = LumenControlConfig.Load((BaseUnityPlugin)(object)this, Paths.ConfigPath, ((BaseUnityPlugin)this).Logger); try { if (!ModCoreApi.IsAvailable) { throw new InvalidOperationException("ModCore did not initialize before LumenControl."); } Core = ModCoreApi.Services; RegisterWithCore(); if (TryGetLegacyOwner(out var version)) { string text = "GeneralTweaks " + version?.ToString() + " still contains Lumen; LumenControl is paused to prevent duplicate lighting hooks."; Core.Modules.SetState(ModuleId, (ModuleRuntimeState)3, text); ((BaseUnityPlugin)this).Logger.LogWarning((object)(text + " Update GeneralTweaks to 3.0.0 or newer.")); return; } _network = new PolicyNetwork(Core, Settings); _harmony = new Harmony("jg224.LumenControl"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); _active = true; Core.Modules.SetState(ModuleId, (ModuleRuntimeState)2, "Server-owned decorative-light schedule ready."); Game.isModded = true; ((BaseUnityPlugin)this).Logger.LogInfo((object)("LumenControl 0.5.0 loaded; policy schema " + 2 + ", protocol " + 2 + ".")); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogError((object)("LumenControl failed to initialize safely: " + ex)); if (Core != null) { Core.Modules.SetState(ModuleId, (ModuleRuntimeState)5, ex.Message); } Shutdown(); throw; } } private void Update() { if (_active) { _network?.Tick(Time.unscaledTimeAsDouble); HasPolicy = _network?.HasPolicy ?? false; } } private void OnDestroy() { Shutdown(); } internal static void ApplyPolicy(LumenPolicy policy, string source) { if (policy != null && !Policy.Equals(policy)) { Policy = policy; Debug("Applied " + source + " policy."); } } private unsafe void RegisterWithCore() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown //IL_00b5: 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) //IL_0129: 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_0175: Expected O, but got Unknown //IL_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Expected O, but got Unknown //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) SemanticVersion val = default(SemanticVersion); if (!SemanticVersion.TryParse("0.5.0", ref val)) { throw new InvalidOperationException("LumenControl has invalid release version metadata."); } _registrations.Add(Core.Modules.Register(new ModuleDescriptor(ModuleId, "jg224.LumenControl", "LumenControl", val, 2, (ModuleSide)3, (ModuleRequirement)4, 0uL, 1, 1))); _registrations.Add(Core.Commands.Register(new CommandDescriptor(ModuleId, "lumen_lightid", "Aim at a placed light to read its ID for the server's ExcludedLightIds setting.", false, (TimeSpan?)null, Array.Empty<string>()), (Func<CommandContext, CommandResult>)delegate { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) GameObject val2 = (Object.op_Implicit((Object)(object)Player.m_localPlayer) ? ((Humanoid)Player.m_localPlayer).GetHoverObject() : null); ZNetView val3 = (Object.op_Implicit((Object)(object)val2) ? val2.GetComponentInParent<ZNetView>() : null); if (!Object.op_Implicit((Object)(object)(Object.op_Implicit((Object)(object)val3) ? ((Component)val3).GetComponent<Fireplace>() : null)) || !val3.IsValid()) { return CommandResult.Failure("Aim at a placed light first."); } ZDOID uid = val3.GetZDO().m_uid; return CommandResult.Success("Light ID: " + ((object)(*(ZDOID*)(&uid))/*cast due to .constrained prefix*/).ToString() + "; prefab: " + ((Object)((Component)val3).gameObject).name); })); foreach (IDisposable item in Settings.RegisterMetadata(Core, ModuleId)) { _registrations.Add(item); } _registrations.Add(Core.Namespaces.Register(ModuleId, (NamespaceKind)5, "jg224.lumencontrol.net.", 1, Array.Empty<string>())); _registrations.Add(Core.Namespaces.Register(ModuleId, (NamespaceKind)9, "jg224.lumencontrol.", 1, Array.Empty<string>())); _registrations.Add(Core.Compatibility.Register(new CompatibilityRule("jg224.LumenControl", "TastyChickenLegs.NoSmokeStayLit", (CompatibilityRuleKind)2, (CompatibilitySeverity)2, "Both mods schedule decorative lights; remove one implementation.", "lumen"))); _registrations.Add(Core.Compatibility.Register(new CompatibilityRule("jg224.LumenControl", "jg224.lumencore", (CompatibilityRuleKind)2, (CompatibilitySeverity)2, "LumenCore overlaps LumenControl scheduled decorative lights.", "lumen"))); _registrations.Add(Core.Lifecycle.Subscribe(ModuleId, (LifecycleEventKind)9, (Action<LifecycleEvent>)delegate { ResetRuntime(); }, 0)); _registrations.Add(Core.Lifecycle.Subscribe(ModuleId, (LifecycleEventKind)3, (Action<LifecycleEvent>)delegate { ResetRuntime(); }, 0)); } private static bool TryGetLegacyOwner(out Version version) { version = null; if (!Chainloader.PluginInfos.TryGetValue("JG224.GeneralTweaks", out var value)) { return false; } version = value.Metadata.Version; if (version != null) { return version.CompareTo(new Version(3, 0, 0)) < 0; } return false; } private void ResetRuntime() { HasPolicy = false; } private void Shutdown() { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) if (_shutDown) { return; } _shutDown = true; _active = false; HasPolicy = false; Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } _harmony = null; _network?.Dispose(); _network = null; for (int num = _registrations.Count - 1; num >= 0; num--) { try { _registrations[num].Dispose(); } catch (Exception ex) { ManualLogSource logger = ((BaseUnityPlugin)this).Logger; if (logger != null) { logger.LogWarning((object)("Registration cleanup failed: " + ex.Message)); } } } _registrations.Clear(); if (Core != null) { Core.Metrics.RemoveOwner(ModuleId); } Core = null; Settings = null; Log = null; } internal static void Debug(string message) { LumenControlConfig settings = Settings; if (settings != null && settings.DebugLogging.Value) { ManualLogSource log = Log; if (log != null) { log.LogDebug((object)message); } } } } } namespace JG224.LumenControl.Patches { internal static class LumenRuntime { internal static bool IsEligible(Fireplace fireplace) { if (!Object.op_Implicit((Object)(object)fireplace) || !Plugin.HasPolicy) { return false; } Piece componentInParent = ((Component)fireplace).GetComponentInParent<Piece>(); ZNetView component = ((Component)fireplace).GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)componentInParent) && componentInParent.IsPlacedByPlayer() && Object.op_Implicit((Object)(object)component) && component.IsValid()) { return Plugin.Policy.Includes(((Object)((Component)componentInParent).gameObject).name, ((object)Unsafe.As<ZDOID, ZDOID>(ref component.GetZDO().m_uid)/*cast due to .constrained prefix*/).ToString()); } return false; } internal static bool IsFreeWindow() { if (Plugin.HasPolicy) { LumenPolicy policy = Plugin.Policy; if (policy != null && policy.Enabled && Object.op_Implicit((Object)(object)EnvMan.instance)) { return LumenSchedule.IsFreeWindow(ClockRules.DayMinutes(EnvMan.instance.GetDayFraction()), Plugin.Policy.LightsOnMinutes, Plugin.Policy.LightsOffMinutes); } } return false; } internal static bool IsUnderWater(Fireplace fireplace, bool checkWater, ref WaterVolume previousWater) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) if (!checkWater) { return false; } return Floating.IsUnderWater(Object.op_Implicit((Object)(object)fireplace.m_enabledObject) ? fireplace.m_enabledObject.transform.position : ((Component)fireplace).transform.position, ref previousWater); } internal static void EnsureOn(Fireplace fireplace) { if (Plugin.Policy.RespectManualOff) { return; } ZNetView component = ((Component)fireplace).GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)component) && component.IsValid() && component.IsOwner()) { ZDO zDO = component.GetZDO(); if (zDO != null && zDO.GetInt(ZDOVars.s_state, 1) != 1) { zDO.Set(ZDOVars.s_state, 1, false); } } } } [HarmonyPatch(typeof(Fireplace), "UpdateFireplace")] internal static class LumenUpdatePatch { internal sealed class State : InfiniteFuelState { internal State(bool original) : base(original) { } } [HarmonyPrefix] private static void Prefix(Fireplace __instance, bool ___m_blocked, bool ___m_wet, bool ___m_checkWaterLevel, ref WaterVolume ___m_previousWaterVolume, out State __state) { __state = new State(__instance.m_infiniteFuel); if (!(!LumenRuntime.IsEligible(__instance) || !LumenRuntime.IsFreeWindow() || ___m_blocked || ___m_wet) && !LumenRuntime.IsUnderWater(__instance, ___m_checkWaterLevel, ref ___m_previousWaterVolume)) { LumenRuntime.EnsureOn(__instance); __instance.m_infiniteFuel = true; __state.MarkApplied(); } } [HarmonyPostfix] private static void Postfix(Fireplace __instance, State __state) { Restore(__instance, __state); } [HarmonyFinalizer] private static Exception Finalizer(Exception __exception, Fireplace __instance, State __state) { Restore(__instance, __state); return __exception; } private static void Restore(Fireplace fireplace, State state) { if (Object.op_Implicit((Object)(object)fireplace) && state != null && state.TryRestore(fireplace.m_infiniteFuel, out var restored)) { fireplace.m_infiniteFuel = restored; } } } [HarmonyPatch(typeof(Fireplace), "IsBurning")] internal static class LumenBurningPatch { [HarmonyPostfix] private static void Postfix(Fireplace __instance, ref bool __result, bool ___m_blocked, bool ___m_wet, bool ___m_checkWaterLevel, ref WaterVolume ___m_previousWaterVolume) { if (!(__result || !LumenRuntime.IsEligible(__instance) || !LumenRuntime.IsFreeWindow() || ___m_blocked || ___m_wet) && !LumenRuntime.IsUnderWater(__instance, ___m_checkWaterLevel, ref ___m_previousWaterVolume)) { ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if (Object.op_Implicit((Object)(object)component) && component.IsValid() && component.GetZDO().GetInt(ZDOVars.s_state, 1) == 1) { __result = true; } } } } [HarmonyPatch(typeof(Fireplace), "Interact")] internal static class LumenManualTogglePatch { [HarmonyPrefix] [HarmonyPriority(0)] private static bool Prefix(Fireplace __instance, Humanoid user, bool hold, bool alt, ref bool __result, bool __runOriginal) { if (!__runOriginal || !Object.op_Implicit((Object)(object)__instance) || hold || alt || !__instance.m_canTurnOff || !LumenRuntime.IsEligible(__instance) || !LumenRuntime.IsFreeWindow()) { return true; } if (!Plugin.Policy.RespectManualOff) { LumenRuntime.EnsureOn(__instance); __result = true; return false; } ZNetView component = ((Component)__instance).GetComponent<ZNetView>(); if (!Object.op_Implicit((Object)(object)user) || (Object)(object)user != (Object)(object)Player.m_localPlayer || !Object.op_Implicit((Object)(object)component) || !component.IsValid() || !ManualToggleRules.ShouldToggleWithoutFuel(Plugin.Policy.RespectManualOff, eligible: true, freeWindow: true, __instance.m_canTurnOff, hold, alt, component.GetZDO().GetFloat(ZDOVars.s_fuel, 0f))) { return true; } if (!component.HasOwner()) { component.ClaimOwnership(); } component.InvokeRPC("RPC_ToggleOn", Array.Empty<object>()); __result = true; return false; } } } namespace JG224.LumenControl.Networking { internal sealed class LumenPolicy : IEquatable<LumenPolicy> { internal const int SchemaVersion = 2; internal const int MaximumBytes = 25000; internal bool Enabled = true; internal ushort LightsOnMinutes = 1050; internal ushort LightsOffMinutes = 540; internal bool RespectManualOff; internal string IncludedPrefabs = string.Empty; internal string ExcludedPrefabs = string.Empty; internal string ExcludedLightIds = string.Empty; private HashSet<string> _included; private HashSet<string> _excluded; private HashSet<string> _lights; internal bool Includes(string prefab, string lightId) { if (_included == null) { _included = Entries(IncludedPrefabs); _excluded = Entries(ExcludedPrefabs); _lights = Entries(ExcludedLightIds); } string text = prefab.Replace("(Clone)", string.Empty).Trim(); if (!_excluded.Contains(text) && !_lights.Contains(lightId)) { if (!PrefabRules.IsDecorativeLight(text)) { return _included.Contains(text); } return true; } return false; } private static HashSet<string> Entries(string text) { return new HashSet<string>(Array.ConvertAll(text.Split(new char[1] { ',' }), (string value) => value.Trim()), StringComparer.OrdinalIgnoreCase); } internal byte[] Serialize() { using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); binaryWriter.Write((byte)2); binaryWriter.Write(Enabled); binaryWriter.Write(LightsOnMinutes); binaryWriter.Write(LightsOffMinutes); binaryWriter.Write(RespectManualOff); binaryWriter.Write(IncludedPrefabs); binaryWriter.Write(ExcludedPrefabs); binaryWriter.Write(ExcludedLightIds); binaryWriter.Flush(); return memoryStream.ToArray(); } internal static bool TryDeserialize(byte[] bytes, out LumenPolicy policy, out string error) { policy = null; error = string.Empty; if (bytes == null || bytes.Length == 0 || bytes.Length > 25000) { error = "Policy payload size is invalid."; return false; } try { using MemoryStream memoryStream = new MemoryStream(bytes, writable: false); using BinaryReader binaryReader = new BinaryReader(memoryStream); int num = binaryReader.ReadByte(); if (num != 2) { error = "Unsupported LumenControl policy schema " + num + "."; return false; } LumenPolicy lumenPolicy = new LumenPolicy { Enabled = binaryReader.ReadBoolean(), LightsOnMinutes = binaryReader.ReadUInt16(), LightsOffMinutes = binaryReader.ReadUInt16() }; lumenPolicy.RespectManualOff = binaryReader.ReadBoolean(); lumenPolicy.IncludedPrefabs = binaryReader.ReadString(); lumenPolicy.ExcludedPrefabs = binaryReader.ReadString(); lumenPolicy.ExcludedLightIds = binaryReader.ReadString(); if (lumenPolicy.IncludedPrefabs.Length > 2048 || lumenPolicy.ExcludedPrefabs.Length > 2048 || lumenPolicy.ExcludedLightIds.Length > 2048) { error = "Light selection lists are limited to 2048 characters each."; return false; } if (memoryStream.Position != memoryStream.Length) { error = "Policy payload contains trailing data."; return false; } if (lumenPolicy.LightsOnMinutes >= 1440 || lumenPolicy.LightsOffMinutes >= 1440) { error = "Lumen schedule must use valid 24-hour times."; return false; } policy = lumenPolicy; return true; } catch (Exception ex) { error = "Malformed LumenControl policy: " + ex.Message; return false; } } public bool Equals(LumenPolicy other) { if (other != null && Enabled == other.Enabled && LightsOnMinutes == other.LightsOnMinutes && LightsOffMinutes == other.LightsOffMinutes && RespectManualOff == other.RespectManualOff && IncludedPrefabs == other.IncludedPrefabs && ExcludedPrefabs == other.ExcludedPrefabs) { return ExcludedLightIds == other.ExcludedLightIds; } return false; } public override bool Equals(object obj) { return Equals(obj as LumenPolicy); } public override int GetHashCode() { return ((((Enabled ? 1 : 0) * 397) ^ LightsOnMinutes) * 397) ^ LightsOffMinutes; } } internal sealed class PolicyNetwork : IDisposable { private readonly AuthoritativePolicyChannel _channel; internal bool HasPolicy => _channel.HasPolicy; internal PolicyNetwork(ICoreServices core, LumenControlConfig config) { //IL_0008: 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_0089: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown _channel = new AuthoritativePolicyChannel(core, new PolicyDescriptor(Plugin.ModuleId, 2, 25000, (Func<byte[], string>)((byte[] bytes) => (!LumenPolicy.TryDeserialize(bytes, out var policy, out var _)) ? error : string.Empty)), 2, (ushort)1, (ushort)2, (Func<byte[]>)config.PolicyBytes, (Action<byte[]>)delegate(byte[] bytes) { LumenPolicy.TryDeserialize(bytes, out policy, out error); Plugin.ApplyPolicy(policy, "server"); }, (Action<string>)delegate(string error) { Plugin.Log.LogWarning((object)error); }); } internal void Tick(double now) { _channel.Tick(now, Object.op_Implicit((Object)(object)ZNet.instance), Object.op_Implicit((Object)(object)ZNet.instance) && ZNet.instance.IsServer()); } internal void ResetConnection() { _channel.Reset(); } public void Dispose() { _channel.Dispose(); } } } namespace JG224.LumenControl.Core { internal static class ClockRules { internal static int DayMinutes(float dayFraction) { return (int)Math.Floor((dayFraction - (float)Math.Floor(dayFraction)) * 1440f) % 1440; } internal static string FormatTime(int minutes) { minutes = (minutes % 1440 + 1440) % 1440; return (minutes / 60).ToString("00", CultureInfo.InvariantCulture) + ":" + (minutes % 60).ToString("00", CultureInfo.InvariantCulture); } internal static bool TryParseTime(string value, out ushort minutes) { minutes = 0; if (string.IsNullOrWhiteSpace(value)) { return false; } string[] array = value.Trim().Split(new char[1] { ':' }); if (array.Length != 2 || !int.TryParse(array[0], NumberStyles.None, CultureInfo.InvariantCulture, out var result) || !int.TryParse(array[1], NumberStyles.None, CultureInfo.InvariantCulture, out var result2) || result < 0 || result > 23 || result2 < 0 || result2 > 59) { return false; } minutes = (ushort)(result * 60 + result2); return true; } } internal static class LumenSchedule { internal static bool IsFreeWindow(int currentMinutes, int onMinutes, int offMinutes) { currentMinutes = (currentMinutes % 1440 + 1440) % 1440; if (onMinutes == offMinutes) { return true; } if (onMinutes < offMinutes) { if (currentMinutes >= onMinutes) { return currentMinutes < offMinutes; } return false; } if (currentMinutes < onMinutes) { return currentMinutes < offMinutes; } return true; } } internal static class ManualToggleRules { internal static bool ShouldToggleWithoutFuel(bool respectManualOff, bool eligible, bool freeWindow, bool canTurnOff, bool hold, bool alt, float fuel) { if (respectManualOff && eligible && freeWindow && canTurnOff && !hold && !alt) { return fuel == 0f; } return false; } } internal class InfiniteFuelState { private readonly bool _original; private bool _changed; private bool _restored; internal InfiniteFuelState(bool original) { _original = original; } internal void MarkApplied() { _changed = !_original; } internal bool TryRestore(bool current, out bool restored) { restored = current; if (_restored || !_changed) { return false; } _restored = true; if (!current) { return false; } restored = _original; return true; } } internal static class PrefabRules { internal static bool IsDecorativeLight(string prefabName) { string text = Clean(prefabName).Replace("_", string.Empty).ToLowerInvariant(); if (text.StartsWith("piece", StringComparison.Ordinal)) { if (!text.Contains("groundtorch") && !text.Contains("walltorch") && !text.Contains("brazier")) { return text.Contains("jackoturnip"); } return true; } return false; } private static string Clean(string value) { if (string.IsNullOrEmpty(value)) { return string.Empty; } int num = value.IndexOf("(Clone)", StringComparison.OrdinalIgnoreCase); return ((num >= 0) ? value.Substring(0, num) : value).Trim(); } } internal static class LegacyLumenConfigRules { internal const string CurrentFileName = "jg224.LumenControl.cfg"; internal const string GeneralTweaksFileName = "jg224.GeneralTweaks.cfg"; internal const string LegacyGeneralTweaksFileName = "JG224.GeneralTweaks.cfg"; internal static string FindImportSource(IEnumerable<string> candidatePaths) { string[] paths = ((candidatePaths == null) ? Array.Empty<string>() : candidatePaths.ToArray()); if (FindExact(paths, "jg224.LumenControl.cfg") != null) { return null; } return FindExact(paths, "jg224.GeneralTweaks.cfg") ?? FindExact(paths, "JG224.GeneralTweaks.cfg"); } private static string FindExact(IEnumerable<string> paths, string fileName) { return paths.FirstOrDefault((string path) => string.Equals(Path.GetFileName(path), fileName, StringComparison.Ordinal)); } } }