using System;
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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Pigeon.Math;
using TMPro;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Sparroh")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("WeeklyTimerFix")]
[assembly: AssemblyTitle("WeeklyTimerFix")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[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;
}
}
}
internal static class ConfigManager
{
private static ConfigFile config;
private static ManualLogSource log;
private static FileSystemWatcher watcher;
private static bool reloadPending;
private static float reloadReadyTime;
private const float ReloadDebounceSeconds = 0.25f;
public static ConfigEntry<bool> UseUnifiedOvertimeSeed { get; private set; }
public static bool UnifiedOvertimeSeedEnabled
{
get
{
if (UseUnifiedOvertimeSeed != null)
{
return UseUnifiedOvertimeSeed.Value;
}
return false;
}
}
public static void Initialize(ConfigFile configFile, ManualLogSource logSource)
{
config = configFile;
log = logSource;
UseUnifiedOvertimeSeed = config.Bind<bool>("General", "Use Unified Overtime Seed", false, "When enabled, Weekly Overtime mission seed (and legacy weekData content) use the same Mycopunk week boundary as Incursion/Cranius/ResetWeekly (Thu 17:00 UTC). When disabled (default), overtime keeps the vanilla seed/roll so it matches unmodded clients. The weekly reset TIMER is always synced either way.");
StartWatcher();
}
public static void Tick()
{
if (!reloadPending || config == null || Time.unscaledTime < reloadReadyTime)
{
return;
}
reloadPending = false;
try
{
config.Reload();
ManualLogSource obj = log;
if (obj != null)
{
obj.LogInfo((object)"Config reloaded.");
}
WeeklyTimerPatches.OnConfigChanged();
}
catch (Exception ex)
{
ManualLogSource obj2 = log;
if (obj2 != null)
{
obj2.LogError((object)("Config reload failed: " + ex.Message));
}
}
}
public static void Dispose()
{
if (watcher != null)
{
watcher.EnableRaisingEvents = false;
watcher.Changed -= OnWatcherEvent;
watcher.Created -= OnWatcherEvent;
watcher.Renamed -= OnWatcherEvent;
watcher.Dispose();
watcher = null;
}
}
private static void StartWatcher()
{
try
{
string configPath = Paths.ConfigPath;
string fileName = Path.GetFileName(config.ConfigFilePath);
if (!string.IsNullOrEmpty(configPath) && !string.IsNullOrEmpty(fileName))
{
watcher = new FileSystemWatcher(configPath, fileName)
{
NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite)
};
watcher.Changed += OnWatcherEvent;
watcher.Created += OnWatcherEvent;
watcher.Renamed += OnWatcherEvent;
watcher.EnableRaisingEvents = true;
}
}
catch (Exception ex)
{
ManualLogSource obj = log;
if (obj != null)
{
obj.LogWarning((object)("Config file watcher not started: " + ex.Message));
}
}
}
private static void OnWatcherEvent(object sender, FileSystemEventArgs e)
{
reloadPending = true;
reloadReadyTime = Time.unscaledTime + 0.25f;
}
}
[BepInPlugin("sparroh.weeklytimerfix", "WeeklyTimerFix", "1.0.0")]
[MycoMod(/*Could not decode attribute arguments.*/)]
public class SparrohPlugin : BaseUnityPlugin
{
public const string PluginGUID = "sparroh.weeklytimerfix";
public const string PluginName = "WeeklyTimerFix";
public const string PluginVersion = "1.0.0";
internal static ManualLogSource Log;
private Harmony _harmony;
private void Awake()
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
ConfigManager.Initialize(((BaseUnityPlugin)this).Config, ((BaseUnityPlugin)this).Logger);
_harmony = new Harmony("sparroh.weeklytimerfix");
try
{
_harmony.PatchAll(typeof(WeeklyTimerPatches));
WeeklyTimerPatches.OnConfigChanged();
Log.LogInfo((object)("WeeklyTimerFix v1.0.0 loaded — overtime timer synced to Global.CurrentWeek; unified overtime seed=" + (ConfigManager.UnifiedOvertimeSeedEnabled ? "ON" : "OFF (vanilla)") + "; granular weekly countdowns enabled."));
}
catch (Exception arg)
{
Log.LogError((object)$"Error applying patches: {arg}");
}
}
private void Update()
{
ConfigManager.Tick();
}
private void OnDestroy()
{
ConfigManager.Dispose();
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
}
internal static class WeeklyTimerPatches
{
private static readonly FieldInfo WeekDataField = AccessTools.Field(typeof(WeeklyOvertimeAssignment), "weekData");
private static readonly Type WeekDataType = AccessTools.Inner(typeof(WeeklyOvertimeAssignment), "WeekData");
private static bool weekDataCleared;
private static bool warnedWeekDataNeedsRestart;
private static readonly FieldInfo MissionSelectTimerField = AccessTools.Field(typeof(MissionSelectButton), "timer");
private static readonly FieldInfo MissionSelectLastTimerField = AccessTools.Field(typeof(MissionSelectButton), "lastTimerUpdateTime");
private static readonly FieldInfo MissionSelectMissionField = AccessTools.Field(typeof(MissionSelectButton), "mission");
internal static long GetNextWeeklyResetUnix()
{
return 1752166800 + (long)(Global.CurrentWeek + 1) * 604800L;
}
internal static int GetSyncedOvertimeSeed()
{
return MathUtil.Squirrel3Hash((int)GetNextWeeklyResetUnix(), 47832154);
}
internal static void OnConfigChanged()
{
if (ConfigManager.UnifiedOvertimeSeedEnabled)
{
ClearLegacyWeekData();
}
else if (weekDataCleared && !warnedWeekDataNeedsRestart)
{
warnedWeekDataNeedsRestart = true;
ManualLogSource log = SparrohPlugin.Log;
if (log != null)
{
log.LogWarning((object)"Use Unified Overtime Seed was turned off after legacy weekData was cleared this session. Restart the game to fully restore vanilla overtime weekData content.");
}
}
}
internal static void ClearLegacyWeekData()
{
if (!ConfigManager.UnifiedOvertimeSeedEnabled || weekDataCleared || WeekDataField == null || WeekDataType == null)
{
return;
}
WeeklyOvertimeAssignment val = null;
try
{
if (Global.Instance != null)
{
val = Global.Instance.OvertimeAssignment;
}
}
catch (Exception)
{
return;
}
if (val != null)
{
Array value = Array.CreateInstance(WeekDataType, 0);
WeekDataField.SetValue(val, value);
weekDataCleared = true;
ManualLogSource log = SparrohPlugin.Log;
if (log != null)
{
log.LogInfo((object)"Cleared legacy WeeklyOvertimeAssignment.weekData; unified overtime seed uses Global.CurrentWeek.");
}
}
}
[HarmonyPatch(typeof(Global), "LoadInstance")]
[HarmonyPostfix]
private static void GlobalLoadInstancePostfix()
{
ClearLegacyWeekData();
}
[HarmonyPatch(typeof(WeeklyOvertimeAssignment), "GetResetDateTime")]
[HarmonyPrefix]
private static bool GetResetDateTimePrefix(out long unixTime, ref bool __result)
{
unixTime = GetNextWeeklyResetUnix();
__result = true;
return false;
}
[HarmonyPatch(typeof(WeeklyOvertimeAssignment), "GetMissionSeed")]
[HarmonyPrefix]
private static bool GetMissionSeedPrefix(out int seed, ref bool __result)
{
if (!ConfigManager.UnifiedOvertimeSeedEnabled)
{
seed = 0;
return true;
}
ClearLegacyWeekData();
seed = GetSyncedOvertimeSeed();
__result = true;
return false;
}
[HarmonyPatch(typeof(MissionSelectButton), "Update")]
[HarmonyPrefix]
private static bool MissionSelectButtonUpdatePrefix(MissionSelectButton __instance)
{
//IL_005a: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
if (MissionSelectTimerField == null || MissionSelectLastTimerField == null || MissionSelectMissionField == null)
{
return true;
}
object? value = MissionSelectTimerField.GetValue(__instance);
TextMeshProUGUI val = (TextMeshProUGUI)((value is TextMeshProUGUI) ? value : null);
if ((Object)(object)val == (Object)null)
{
return false;
}
long num = default(long);
if (!(MissionSelectMissionField.GetValue(__instance) is MissionData val2) || ((MissionData)(ref val2)).Container == null || !((MissionData)(ref val2)).Container.GetResetDateTime(((MissionData)(ref val2)).Mission, ref num))
{
return false;
}
float unscaledTime = Time.unscaledTime;
float num2 = (float)MissionSelectLastTimerField.GetValue(__instance);
if (unscaledTime - num2 <= 1f)
{
return false;
}
MissionSelectLastTimerField.SetValue(__instance, unscaledTime);
int num3 = FillGranularWeeklyDuration(num - Global.GlobalSeconds, Global.charBuffer);
((TMP_Text)val).SetCharArray(Global.charBuffer, 0, num3);
return false;
}
internal static int FillGranularWeeklyDuration(long totalSeconds, char[] buffer)
{
if (totalSeconds < 0)
{
totalSeconds = 0L;
}
int num = (int)(totalSeconds / 86400);
int num2 = (int)(totalSeconds % 86400 / 3600);
int value = (int)(totalSeconds % 3600 / 60);
int value2 = (int)(totalSeconds % 60);
int index = 0;
if (num > 0)
{
index = WriteInt(num, buffer, index);
buffer[index++] = 'd';
buffer[index++] = ' ';
index = WriteTwoDigits(num2, buffer, index);
buffer[index++] = ':';
index = WriteTwoDigits(value, buffer, index);
buffer[index++] = ':';
return WriteTwoDigits(value2, buffer, index);
}
if (num2 > 0)
{
index = WriteInt(num2, buffer, index);
buffer[index++] = ':';
index = WriteTwoDigits(value, buffer, index);
buffer[index++] = ':';
return WriteTwoDigits(value2, buffer, index);
}
index = WriteInt(value, buffer, index);
buffer[index++] = ':';
return WriteTwoDigits(value2, buffer, index);
}
private static int WriteInt(int value, char[] buffer, int index)
{
if (value == 0)
{
buffer[index++] = '0';
return index;
}
int num = index;
for (int num2 = value; num2 > 0; num2 /= 10)
{
buffer[index++] = (char)(48 + num2 % 10);
}
int num3 = index - 1;
while (num < num3)
{
char c = buffer[num];
buffer[num] = buffer[num3];
buffer[num3] = c;
num++;
num3--;
}
return index;
}
private static int WriteTwoDigits(int value, char[] buffer, int index)
{
if (value < 0)
{
value = 0;
}
if (value > 99)
{
value %= 100;
}
buffer[index++] = (char)(48 + value / 10);
buffer[index++] = (char)(48 + value % 10);
return index;
}
}
namespace WeeklyTimerFix
{
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "WeeklyTimerFix";
public const string PLUGIN_NAME = "WeeklyTimerFix";
public const string PLUGIN_VERSION = "1.0.0";
}
}
namespace System.Runtime.CompilerServices
{
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
internal sealed class IgnoresAccessChecksToAttribute : Attribute
{
public IgnoresAccessChecksToAttribute(string assemblyName)
{
}
}
}