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!");
}
}
}
}