using 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> _entries = new List>(); private readonly HashSet _reportedInvalidTimes = new HashSet(StringComparer.Ordinal); private byte[] _cachedPolicy; internal ConfigEntry Enabled { get; } internal ConfigEntry LightsOnTime { get; } internal ConfigEntry LightsOffTime { get; } internal ConfigEntry DebugLogging { get; } internal ConfigEntry RespectManualOff { get; } internal ConfigEntry IncludedPrefabs { get; } internal ConfigEntry ExcludedPrefabs { get; } internal ConfigEntry ExcludedLightIds { get; } private LumenControlConfig(ConfigFile file) { _file = file; Enabled = Add(file.Bind("Lumen", "Enabled", true, "Master switch for scheduled fuel-free decorative lights."), (ConfigScope)2); LightsOnTime = Add(file.Bind("Lumen", "LightsOnTime", "17:30", "Start of the free lights-on window in HH:mm 24-hour time."), (ConfigScope)2); LightsOffTime = Add(file.Bind("Lumen", "LightsOffTime", "09:00", "End of the free lights-on window in HH:mm 24-hour time."), (ConfigScope)2); RespectManualOff = Add(file.Bind("Lumen", "RespectManualOff", false, "Keep manually extinguished lights off during the free-fuel window."), (ConfigScope)2); IncludedPrefabs = Add(file.Bind("Lumen", "IncludedPrefabs", "", "Additional exact Fireplace prefab names, comma separated (maximum 2048 characters)."), (ConfigScope)2); ExcludedPrefabs = Add(file.Bind("Lumen", "ExcludedPrefabs", "", "Exact prefab names excluded from scheduling, comma separated (maximum 2048 characters)."), (ConfigScope)2); ExcludedLightIds = Add(file.Bind("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(file.Bind("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 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 pair in _entries) { yield return services.Configuration.Register(new ConfigSettingDescriptor(owner, pair.Item1.Definition.Section, pair.Item1.Definition.Key, pair.Item2, (Func)(() => Convert.ToString(pair.Item1.BoxedValue, CultureInfo.InvariantCulture)), 1)); } } private ushort ParseTimeOrDefault(ConfigEntry 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("Lumen", "Enabled", Enabled.Value, (ConfigDescription)null).Value; LightsOnTime.Value = val.Bind("Lumen", "LightsOnTime", LightsOnTime.Value, (ConfigDescription)null).Value; LightsOffTime.Value = val.Bind("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 Add(ConfigEntry entry, ConfigScope scope) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) _entries.Add(Tuple.Create((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 _registrations = new List(); 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()), (Func)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() : null); if (!Object.op_Implicit((Object)(object)(Object.op_Implicit((Object)(object)val3) ? ((Component)val3).GetComponent() : 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())); _registrations.Add(Core.Namespaces.Register(ModuleId, (NamespaceKind)9, "jg224.lumencontrol.", 1, Array.Empty())); _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)delegate { ResetRuntime(); }, 0)); _registrations.Add(Core.Lifecycle.Subscribe(ModuleId, (LifecycleEventKind)3, (Action)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(); ZNetView component = ((Component)fireplace).GetComponent(); 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(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(); 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(); 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(); 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()); __result = true; return false; } } } namespace JG224.LumenControl.Networking { internal sealed class LumenPolicy : IEquatable { 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 _included; private HashSet _excluded; private HashSet _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 Entries(string text) { return new HashSet(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[] bytes) => (!LumenPolicy.TryDeserialize(bytes, out var policy, out var _)) ? error : string.Empty)), 2, (ushort)1, (ushort)2, (Func)config.PolicyBytes, (Action)delegate(byte[] bytes) { LumenPolicy.TryDeserialize(bytes, out policy, out error); Plugin.ApplyPolicy(policy, "server"); }, (Action)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 candidatePaths) { string[] paths = ((candidatePaths == null) ? Array.Empty() : 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 paths, string fileName) { return paths.FirstOrDefault((string path) => string.Equals(Path.GetFileName(path), fileName, StringComparison.Ordinal)); } } }