Decompiled source of OvertimeClock v1.0.2

OvertimeClock.dll

Decompiled 3 weeks ago
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.Json;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using OvertimeClock.Behaviors;
using OvertimeClock.Settings;
using UnityEngine;
using Utils.Logger;
using Utils.Settings;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("OvertimeClock")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("OvertimeClock is a mod for Deep Rock Galactic: Survivor that enhances extraction time control and offers advanced configuration options for players.")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: AssemblyInformationalVersion("1.0.2+0e48eb5b4c0c71faf05ff83e93301a69dd2244f3")]
[assembly: AssemblyProduct("OvertimeClock")]
[assembly: AssemblyTitle("OvertimeClock")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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 Utils.Settings
{
	public class Config
	{
		public static string PluginGUID;

		public static string PluginFolderPath;

		internal static ConfigFile cfg;

		private static List<Action> configActions = new List<Action>();

		public static ConfigElement<T> Bind<T>(string section, string key, T defaultValue, string description)
		{
			return new ConfigElement<T>(cfg.Bind<T>(section, key, defaultValue, description), section, key, defaultValue, description);
		}

		public static void Save()
		{
			cfg.Save();
		}

		public static void Reload()
		{
			cfg.Reload();
		}

		public static void Setup(string pluginGUID, ConfigFile config, int skipCaller = 4, params Action[] actions)
		{
			PluginGUID = pluginGUID;
			cfg = config;
			PluginFolderPath = Paths.ConfigPath + "\\" + PluginGUID;
			if (!Directory.Exists(PluginFolderPath))
			{
				Directory.CreateDirectory(PluginFolderPath);
			}
			ENV.Debug.Setup(skipCaller);
			AddConfigActions(actions);
		}

		public static void Load()
		{
			if (configActions == null || configActions.Count == 0)
			{
				return;
			}
			foreach (Action configAction in configActions)
			{
				configAction();
			}
		}

		public static void AddConfigActions(params Action[] actions)
		{
			configActions.AddRange(actions);
		}
	}
	public class ConfigElement<T>
	{
		public List<Action<T>> OnValueChanged = new List<Action<T>>();

		private ConfigEntry<T> OriginalConfig;

		public string Section { get; }

		public string Key { get; }

		public string Description { get; }

		public Type ElementType => typeof(T);

		public T Value
		{
			get
			{
				return GetValue();
			}
			set
			{
				SetValue(value);
			}
		}

		public T DefaultValue { get; }

		private T GetValue()
		{
			return OriginalConfig.Value;
		}

		public ConfigElement(ConfigEntry<T> original, string section, string key, T defaultValue, string description)
		{
			OriginalConfig = original;
			Section = section;
			Key = key;
			DefaultValue = defaultValue;
			Description = description;
		}

		private void SetValue(T value)
		{
			if ((Value == null && value == null) || (Value != null && Value.Equals(value)))
			{
				return;
			}
			OriginalConfig.Value = value;
			foreach (Action<T> item in OnValueChanged)
			{
				item?.Invoke(value);
			}
		}
	}
	public static class ENV
	{
		public class Debug
		{
			private static string debugSection = "\ud83e\udeb2Debug";

			private static ConfigElement<bool> DebugLogOnTempFile;

			private static ConfigElement<bool> DebugEnableTraceLogs;

			public static void Setup(int skipCaller)
			{
				Config.AddConfigActions(delegate
				{
					load(skipCaller);
				});
			}

			private static void load(int skipCaller)
			{
				if (enableDebugConfigs(skipCaller))
				{
					DebugLogOnTempFile = Config.Bind(debugSection, "LogOnTempFile", defaultValue: false, "Enabled, will log every plugin log on a temp file");
					DebugEnableTraceLogs = Config.Bind(debugSection, "EnableTraceLogs", defaultValue: false, "Enabled, will print Trace logs (Debug output in BepInEx)");
				}
				validateValues();
			}

			private static void validateValues()
			{
				if (DebugLogOnTempFile != null)
				{
					LogOnTempFile = DebugLogOnTempFile.Value;
				}
				if (DebugEnableTraceLogs != null)
				{
					EnableTraceLogs = DebugEnableTraceLogs.Value;
				}
				Config.cfg.Save();
			}

			private static bool enableDebugConfigs(int skipCaller)
			{
				return new StackTrace().GetFrame(skipCaller).GetMethod().DeclaringType.Assembly.GetCustomAttribute<AssemblyConfigurationAttribute>()?.Configuration != "Release";
			}
		}

		public static bool LogOnTempFile;

		public static bool EnableTraceLogs;
	}
}
namespace Utils.Logger
{
	public class Config
	{
		internal static ManualLogSource logger;

		private static string tempLogFile;

		public static void Setup(ManualLogSource logger, string worldType = "")
		{
			Config.logger = logger;
			string value = "";
			if (worldType != "")
			{
				value = "-" + worldType;
			}
			tempLogFile = $"{Utils.Settings.Config.PluginFolderPath}\\{Utils.Settings.Config.PluginGUID}{value}.txt";
			Log.Start("Using \"" + tempLogFile + "\" to save logs.");
		}

		public static void TestSetup()
		{
		}

		internal static void logFile(object data, string level, string prefix = "")
		{
			if (Utils.Settings.ENV.LogOnTempFile)
			{
				using (StreamWriter streamWriter = File.AppendText(tempLogFile))
				{
					string value = $"{prefix}{DateTime.Now.ToString("hh:mm:ss")} [{level} {Utils.Settings.Config.PluginGUID}]: {data}";
					streamWriter.WriteLine(value);
				}
			}
		}
	}
	public class Log
	{
		private static ConcurrentDictionary<string, long> timedLog = new ConcurrentDictionary<string, long>();

		private static List<string> firstLog = new List<string>();

		public static void Info(object data)
		{
			Config.logger.LogInfo(data);
			Config.logFile(data, "Info:   ");
		}

		public static void Error(object data)
		{
			Config.logger.LogError(data);
			Config.logFile(data, "Error:  ");
		}

		public static void Debug(object data)
		{
			Config.logger.LogDebug(data);
			Config.logFile(data, "Debug:  ");
		}

		public static void Fatal(object data)
		{
			Config.logger.LogFatal(data);
			Config.logFile(data, "Fatal:  ");
		}

		public static void Warning(object data)
		{
			Config.logger.LogWarning(data);
			Config.logFile(data, "Warning:");
		}

		public static void Message(object data)
		{
			Config.logger.LogMessage(data);
			Config.logFile(data, "Message:");
		}

		public static void Start(object data)
		{
			Config.logger.LogMessage(data);
			Config.logFile(data, "Start:  ", "\n");
		}

		public static void Trace(object data)
		{
			if (Utils.Settings.ENV.EnableTraceLogs)
			{
				Config.logger.LogDebug(data);
				Config.logFile(data, "Trace:  ");
			}
		}

		public static void Struct<T>(T data)
		{
			if (Utils.Settings.ENV.EnableTraceLogs)
			{
				string text = structToString(data);
				Config.logger.LogDebug((object)text);
				Config.logFile(text, "Struct: ");
			}
		}

		public static void Timed(Action action, int ms, string id = "")
		{
			if (!blocked(ms, id))
			{
				action();
			}
		}

		public static void First(Action action, string id = "")
		{
			if (first(id))
			{
				action();
			}
		}

		private static string structToString<T>(T data)
		{
			Type type = data.GetType();
			FieldInfo[] fields = type.GetFields();
			PropertyInfo[] properties = type.GetProperties();
			Dictionary<string, object> values = new Dictionary<string, object>();
			Array.ForEach(properties, delegate(PropertyInfo property)
			{
				values.TryAdd(property.Name, property.GetValue(data));
			});
			Array.ForEach(fields, delegate(FieldInfo field)
			{
				values.TryAdd(field.Name, field.GetValue(data));
			});
			List<string> list = new List<string>();
			foreach (KeyValuePair<string, object> item in values)
			{
				list.Add($"\"{item.Key}\":\"{item.Value}\"");
			}
			return "\"" + type.ToString() + "\": {" + string.Join(",", list) + "}";
		}

		private static bool first(string id)
		{
			if (firstLog.Contains(id))
			{
				return false;
			}
			firstLog.Add(id);
			return true;
		}

		private static bool blocked(int ms, string id)
		{
			long num = DateTimeOffset.Now.ToUnixTimeMilliseconds();
			if (!timedLog.TryGetValue(id, out var value))
			{
				long newTimestamp = DateTimeOffset.Now.AddMilliseconds(ms).ToUnixTimeMilliseconds();
				timedLog.AddOrUpdate(id, newTimestamp, (string key, long oldValue) => newTimestamp);
				return true;
			}
			if (num < value)
			{
				return true;
			}
			timedLog.TryRemove(id, out var _);
			return false;
		}
	}
}
namespace Utils.Database
{
	public static class Cache
	{
		public static ConcurrentDictionary<string, long> LastUpdate = new ConcurrentDictionary<string, long>();

		public static ConcurrentDictionary<string, bool> Cached = new ConcurrentDictionary<string, bool>();

		public static bool IsBlocked(string key, long blockedDuration)
		{
			long now = DateTimeOffset.Now.ToUnixTimeMilliseconds();
			if (LastUpdate.TryGetValue(key, out var value) && now - value < blockedDuration)
			{
				return true;
			}
			LastUpdate.AddOrUpdate(key, now, (string _, long _) => now);
			return false;
		}

		public static bool Key(string key, bool cache = true)
		{
			if (!cache)
			{
				return false;
			}
			return Cached.AddOrUpdate(key, addValue: true, (string _, bool _) => true);
		}

		public static bool Exists(string key)
		{
			if (Cached.TryGetValue(key, out var value) && value)
			{
				return true;
			}
			return false;
		}

		public static bool RemoveKey(string key)
		{
			bool value;
			return Cached.TryRemove(key, out value);
		}

		public static void Clear()
		{
			Cached.Clear();
			LastUpdate.Clear();
		}
	}
	public static class DB
	{
		private static JsonSerializerOptions JSONOptions = new JsonSerializerOptions
		{
			WriteIndented = false,
			IncludeFields = false
		};

		private static JsonSerializerOptions Pretty_JSON_options = new JsonSerializerOptions
		{
			WriteIndented = true,
			IncludeFields = true
		};

		private static List<Action> loadActions = new List<Action>();

		private static List<Action> saveActions = new List<Action>();

		private static List<Action> cleanActions = new List<Action>();

		public static void Setup(List<Action> load, List<Action> save, List<Action> clean)
		{
			if (load != null)
			{
				loadActions.AddRange(load);
			}
			if (save != null)
			{
				saveActions.AddRange(save);
			}
			if (clean != null)
			{
				cleanActions.AddRange(clean);
			}
		}

		public static void Load()
		{
			if (loadActions == null)
			{
				return;
			}
			foreach (Action loadAction in loadActions)
			{
				loadAction();
			}
			Log.Info($"All({loadActions.Count}) database actions loaded.");
		}

		public static void Save()
		{
			if (saveActions == null)
			{
				return;
			}
			foreach (Action saveAction in saveActions)
			{
				saveAction();
			}
			Log.Info($"All({saveActions.Count}) database actions saved.");
		}

		public static void Clean()
		{
			if (cleanActions == null)
			{
				return;
			}
			foreach (Action cleanAction in cleanActions)
			{
				cleanAction();
			}
			Log.Info($"All({cleanActions.Count}) database actions cleaned.");
		}

		public static void AddLoadActions(params Action[] actions)
		{
			loadActions.AddRange(actions);
		}

		public static void AddSaveActions(params Action[] actions)
		{
			saveActions.AddRange(actions);
		}

		public static void AddCleanActions(params Action[] actions)
		{
			cleanActions.AddRange(actions);
		}

		public static void saveFile<T>(string fileName, T data, bool pretty = false, string extension = ".json")
		{
			JsonSerializerOptions options = JSONOptions;
			if (pretty)
			{
				options = Pretty_JSON_options;
			}
			File.WriteAllText(Utils.Settings.Config.PluginFolderPath + "\\" + fileName + extension, JsonSerializer.Serialize(data, options));
		}

		public static void loadFile<T>(string fileName, ref T data, string extension = ".json") where T : new()
		{
			string path = Utils.Settings.Config.PluginFolderPath + "\\" + fileName + extension;
			if (!File.Exists(path))
			{
				File.Create(path).Dispose();
			}
			string json = File.ReadAllText(path);
			try
			{
				data = JsonSerializer.Deserialize<T>(json);
				Log.Trace(fileName + " DB Populated");
			}
			catch
			{
				data = new T();
				Log.Trace(fileName + " DB Created");
			}
		}
	}
}
namespace OvertimeClock
{
	[BepInPlugin("OvertimeClock", "OvertimeClock", "1.0.2")]
	public class Plugin : BasePlugin
	{
		public static readonly Harmony Harmony = new Harmony("OvertimeClock");

		private static MonoBehaviour _keybindingBehavior;

		public override void Load()
		{
			OvertimeClock.Settings.Config.Load(((BasePlugin)this).Config, ((BasePlugin)this).Log, "Client");
			_keybindingBehavior = (MonoBehaviour)(object)((BasePlugin)this).AddComponent<Keybinding>();
			Log.Trace("Patching harmony");
			Harmony.PatchAll();
			Log.Info("Plugin OvertimeClock v1.0.2 loaded!");
		}

		public override bool Unload()
		{
			if ((Object)(object)_keybindingBehavior != (Object)null)
			{
				Object.Destroy((Object)(object)_keybindingBehavior);
				_keybindingBehavior = null;
			}
			Log.Trace("Unpatching harmony");
			Harmony.UnpatchSelf();
			Log.Info("Plugin OvertimeClock v1.0.2 unloaded!");
			return true;
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "OvertimeClock";

		public const string PLUGIN_NAME = "OvertimeClock";

		public const string PLUGIN_VERSION = "1.0.2";
	}
}
namespace OvertimeClock.Settings
{
	public class Config
	{
		public static void Load(ConfigFile configFile, ManualLogSource logger, string worldType)
		{
			ENV.Settings.Setup();
			Utils.Settings.Config.Setup("OvertimeClock", configFile, 4);
			Utils.Settings.Config.Load();
			Utils.Logger.Config.Setup(logger, worldType);
		}
	}
	public static class ENV
	{
		public static class Settings
		{
			public static void Setup()
			{
				Utils.Settings.Config.AddConfigActions(load);
			}

			private static void load()
			{
				OverrideDropPodTimeout = Utils.Settings.Config.Bind(settings, "OverrideDropPodTimeout", defaultValue: true, "Override the default drop pod timeout. if disable the timeout will be increased by DropPodTimeoutInSeconds instead override.");
				DropPodTimeoutInSeconds = Utils.Settings.Config.Bind(settings, "DropPodTimeoutInSeconds", 180, "The countdown duration in seconds.");
				ReloadSettingsKey = Utils.Settings.Config.Bind<KeyCode>(settings, "ReloadSettingsKey", (KeyCode)286, "The key to reload the settings.");
				Utils.Settings.Config.Save();
			}
		}

		private static readonly string settings = "0.⚙\ufe0f Settings";

		public static ConfigElement<bool> OverrideDropPodTimeout;

		public static ConfigElement<int> DropPodTimeoutInSeconds;

		public static ConfigElement<KeyCode> ReloadSettingsKey;
	}
}
namespace OvertimeClock.Hooks
{
	[Harmony]
	public class DropPodPatch
	{
		[HarmonyPatch(typeof(DropPod), "Awake")]
		public static class Awake
		{
			private static void Prefix(DropPod __instance)
			{
				try
				{
					if (OvertimeClock.Settings.ENV.OverrideDropPodTimeout.Value)
					{
						__instance.secondsToTimeOut = OvertimeClock.Settings.ENV.DropPodTimeoutInSeconds.Value;
					}
					else
					{
						__instance.secondsToTimeOut += OvertimeClock.Settings.ENV.DropPodTimeoutInSeconds.Value;
					}
				}
				catch (Exception data)
				{
					Log.Fatal(data);
				}
			}
		}
	}
}
namespace OvertimeClock.Behaviors
{
	public class Keybinding : MonoBehaviour
	{
		public void Update()
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			if (Input.GetKeyDown(OvertimeClock.Settings.ENV.ReloadSettingsKey.Value))
			{
				Utils.Settings.Config.Reload();
				Log.Info("Settings reloaded!");
			}
		}
	}
}