using System;
using System.Collections;
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 System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Steamworks;
using Steamworks.Data;
using UnityEngine;
using UnityEngine.SceneManagement;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("WKDebugAccess")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+892f606ebe41243b9ce1bd5bc88cc2a227080e65")]
[assembly: AssemblyProduct("WKDebugAccess")]
[assembly: AssemblyTitle("WKDebugAccess")]
[assembly: AssemblyVersion("1.0.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 WKDebugAccess
{
[BepInPlugin("boiled.whiteknuckle.debugaccess", "WK Debug Access", "1.0.3")]
public sealed class WKDebugAccessPlugin : BaseUnityPlugin
{
private sealed class WKDebugAccessRunner : MonoBehaviour
{
private void Update()
{
Heartbeat("runner update");
}
}
private struct ScoreSnapshot
{
public int Count;
public float Bonus;
public float Multiplier;
public float Total;
}
private const string PluginGuid = "boiled.whiteknuckle.debugaccess";
private const string Version = "1.0.3";
private const string Prefix = "wkdebug_";
private const string DebugScoreId = "wkdebug-score";
private static ManualLogSource logSource;
private static Harmony harmony;
private static GameObject runnerObject;
private static bool registered;
private static bool hooksPatched;
private static float nextRetryLogTime;
private static float nextStatusWriteTime;
private static DateTime lastCommandWriteTimeUtc;
private static readonly List<string> recentMessages = new List<string>();
private void Awake()
{
logSource = ((BaseUnityPlugin)this).Logger;
((BaseUnityPlugin)this).Logger.LogInfo((object)"WK Debug Access loaded. Waiting for CommandConsole.");
PatchConsoleHooks();
SceneManager.sceneLoaded += OnSceneLoaded;
EnsureRunner();
EnsureCommandFiles();
TryRegister("plugin awake");
}
private void OnDestroy()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
ManualLogSource obj = logSource;
if (obj != null)
{
obj.LogInfo((object)"WK Debug Access plugin host destroyed; persistent runner and Harmony patches remain active.");
}
}
private void Update()
{
Heartbeat("plugin update");
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
TryRegister("scene loaded: " + ((Scene)(ref scene)).name);
}
private static void PatchConsoleHooks()
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Expected O, but got Unknown
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Expected O, but got Unknown
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Expected O, but got Unknown
//IL_0108: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Expected O, but got Unknown
if (hooksPatched)
{
return;
}
try
{
harmony = new Harmony("boiled.whiteknuckle.debugaccess");
MethodInfo methodInfo = AccessTools.Method(typeof(CommandConsole), "Awake", (Type[])null, (Type[])null);
MethodInfo methodInfo2 = AccessTools.Method(typeof(CommandConsole), "ExecuteCommand", new Type[2]
{
typeof(string),
typeof(bool)
}, (Type[])null);
MethodInfo methodInfo3 = AccessTools.Method(typeof(CommandConsole), "ExecuteCommand", new Type[3]
{
typeof(string),
typeof(bool),
typeof(bool)
}, (Type[])null);
harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(WKDebugAccessPlugin), "CommandConsoleAwakePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(WKDebugAccessPlugin), "CommandConsoleExecuteCommandTwoArgsPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(WKDebugAccessPlugin), "CommandConsoleExecuteCommandThreeArgsPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
hooksPatched = true;
ManualLogSource obj = logSource;
if (obj != null)
{
obj.LogInfo((object)("Patched CommandConsole hooks. Awake=" + (methodInfo != null) + ", ExecuteCommand2=" + (methodInfo2 != null) + ", ExecuteCommand3=" + (methodInfo3 != null)));
}
}
catch (Exception ex)
{
ManualLogSource obj2 = logSource;
if (obj2 != null)
{
obj2.LogError((object)("Failed to patch CommandConsole hooks: " + ex));
}
}
}
private static void EnsureRunner()
{
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Expected O, but got Unknown
if (!((Object)(object)runnerObject != (Object)null))
{
runnerObject = new GameObject("WKDebugAccessRunner");
Object.DontDestroyOnLoad((Object)(object)runnerObject);
((Object)runnerObject).hideFlags = (HideFlags)61;
runnerObject.AddComponent<WKDebugAccessRunner>();
ManualLogSource obj = logSource;
if (obj != null)
{
obj.LogInfo((object)"Persistent WKDebugAccessRunner created.");
}
}
}
private static void Heartbeat(string reason)
{
TryRegister(reason);
ProcessCommandFile();
CheckHotkeys();
WriteStatusThrottled();
}
private static void TryRegister(string reason)
{
if (registered)
{
return;
}
CommandConsole val = FindConsole();
if ((Object)(object)val == (Object)null)
{
if (Time.unscaledTime >= nextRetryLogTime)
{
nextRetryLogTime = Time.unscaledTime + 10f;
ManualLogSource obj = logSource;
if (obj != null)
{
obj.LogInfo((object)("CommandConsole not available yet; retrying. Source=" + reason + ", found=" + CountConsoleObjects()));
}
}
return;
}
try
{
if ((Object)(object)CommandConsole.instance == (Object)null)
{
CommandConsole.instance = val;
}
RegisterCommands(val);
registered = true;
ManualLogSource obj2 = logSource;
if (obj2 != null)
{
obj2.LogInfo((object)("WK Debug Access commands registered. Source=" + reason));
}
}
catch (Exception ex)
{
ManualLogSource obj3 = logSource;
if (obj3 != null)
{
obj3.LogError((object)("Failed to register WK Debug Access commands from " + reason + ": " + ex));
}
}
}
private static CommandConsole FindConsole()
{
if ((Object)(object)CommandConsole.instance != (Object)null)
{
return CommandConsole.instance;
}
try
{
CommandConsole[] array = Resources.FindObjectsOfTypeAll<CommandConsole>();
if (array == null || array.Length == 0)
{
return null;
}
CommandConsole val = ((IEnumerable<CommandConsole>)array).FirstOrDefault((Func<CommandConsole, bool>)((CommandConsole c) => (Object)(object)c != (Object)null && (Object)(object)c.inputField != (Object)null));
return (CommandConsole)(((Object)(object)val != (Object)null) ? ((object)val) : ((object)((IEnumerable<CommandConsole>)array).FirstOrDefault((Func<CommandConsole, bool>)((CommandConsole c) => (Object)(object)c != (Object)null))));
}
catch (Exception ex)
{
ManualLogSource obj = logSource;
if (obj != null)
{
obj.LogWarning((object)("FindConsole failed: " + ex.Message));
}
return null;
}
}
private static int CountConsoleObjects()
{
try
{
CommandConsole[] array = Resources.FindObjectsOfTypeAll<CommandConsole>();
return (array != null) ? array.Length : 0;
}
catch
{
return -1;
}
}
private static void RegisterCommands(CommandConsole console)
{
SafeCommandRaw(console, "wkdebug", RootCommand, "[command] WK Debug Access root command. Try: wkdebug help");
SafeCommandRaw(console, "wkhascheated", HasCheated, "Print CommandConsole.hasCheated.");
SafeCommandRaw(console, "wksethascheated", SetHasCheated, "[true|false] Set CommandConsole.hasCheated.");
SafeCommandRaw(console, "wksessioninfo", SessionInfo, "Print current gamemode/session summary.");
SafeCommandRaw(console, "wkliststats", ListStats, "[filter] [limit=80] List StatManager.sessionStats entries.");
SafeCommandRaw(console, "wkgetstat", GetStat, "[id] Print one session stat.");
SafeCommandRaw(console, "wksetstat", SetStat, "[id] [value] [int|float|string optional] Set or create a session stat.");
SafeCommandRaw(console, "wkaddstat", AddStat, "[id] [delta] [int|float optional] Add to a session stat.");
SafeCommandRaw(console, "wkexportstats", ExportStats, "[filter optional] Export session stats to BepInEx/config/WKDebugAccess/session_stats.tsv.");
SafeCommandRaw(console, "wksavesession", SaveSession, "[resetroom=true|false optional] Force SaveSession to campaign-save.session.");
SafeCommandRaw(console, "wkgettime", GetTime, "Print current runtime/session/best time.");
SafeCommandRaw(console, "wksettime", SetTime, "[seconds|mm:ss|hh:mm:ss] Set current run time.");
SafeCommandRaw(console, "wkgetscore", GetScore, "Print runtime score entries and saved score stats.");
SafeCommandRaw(console, "wklistscores", ListScores, "[filter] [limit=80] List CL_ScoreManager session score entries.");
SafeCommandRaw(console, "wksetscore", SetScore, "[value] Set session score stat and wkdebug score entry.");
SafeCommandRaw(console, "wkaddscore", AddScore, "[id] [bonus] [multiplier=0] [count=0] [title optional] Add/update runtime score entry.");
SafeCommandRaw(console, "wkgethighscore", GetHighScore, "Print global and gamemode high score.");
SafeCommandRaw(console, "wksethighscore", SetHighScore, "[value] Set global and gamemode high score.");
SafeCommandRaw(console, "wkresetleaderboard", ResetLeaderboard, "[score=0] [steam leaderboard name optional] Reset local leaderboard/high score and optionally force-update Steam score.");
SafeCommandRaw(console, "wkresetlb", ResetLeaderboard, "[score=0] [steam leaderboard name optional] Alias for wkresetleaderboard.");
SafeCommandRaw(console, "wksetbesttime", SetBestTime, "[seconds|mm:ss|hh:mm:ss] Set global and gamemode best time.");
SafeCommandRaw(console, "wkmarkwin", MarkWin, "[score optional] [time optional] Save win stats without opening end screen.");
SafeCommandRaw(console, "wkcompletegame", CompleteGame, "[score optional] [time optional] Set score/time/win stats and save.");
SafeCommandRaw(console, "wkfinishgame", FinishGame, "[win|lose] Start the game's end sequence.");
SafeCommandRaw(console, "wkgetflag", GetFlag, "[id] Print a session/save flag.");
SafeCommandRaw(console, "wksetflag", SetFlag, "[id] [true|false] [data optional] [save=true] Set a game flag.");
SafeCommandRaw(console, "wklistachievements", ListAchievements, "[filter] [limit=80] List loaded achievements.");
SafeCommandRaw(console, "wksetachievement", SetAchievement, "[id] [true|false] [save=true] Set an achievement through the game API.");
SafeCommandRaw(console, "wksavestats", SaveStatsCommand, "[writeall=true] Save StatManager data.");
SafeCommand(console, "help", Help, "List WK Debug Access commands.");
SafeCommand(console, "hascheated", HasCheated, "Print CommandConsole.hasCheated.");
SafeCommand(console, "sethascheated", SetHasCheated, "[true|false] Set CommandConsole.hasCheated without marking this command as a cheat.");
SafeCommand(console, "sessioninfo", SessionInfo, "Print current gamemode/session summary.");
SafeCommand(console, "liststats", ListStats, "[filter] [limit=80] List StatManager.sessionStats entries.");
SafeCommand(console, "getstat", GetStat, "[id] Print one session stat.");
SafeCommand(console, "setstat", SetStat, "[id] [value] [int|float|string optional] Set or create a session stat.");
SafeCommand(console, "addstat", AddStat, "[id] [delta] [int|float optional] Add to a session stat.");
SafeCommand(console, "exportstats", ExportStats, "[filter optional] Export session stats to BepInEx/config/WKDebugAccess/session_stats.tsv.");
SafeCommand(console, "savesession", SaveSession, "[resetroom=true|false optional] Force SaveSession to campaign-save.session.");
SafeCommand(console, "gettime", GetTime, "Print current runtime/session/best time.");
SafeCommand(console, "settime", SetTime, "[seconds|mm:ss|hh:mm:ss] Set current run time.");
SafeCommand(console, "getscore", GetScore, "Print runtime score entries and saved score stats.");
SafeCommand(console, "listscores", ListScores, "[filter] [limit=80] List CL_ScoreManager session score entries.");
SafeCommand(console, "setscore", SetScore, "[value] Set session score stat and wkdebug score entry.");
SafeCommand(console, "addscore", AddScore, "[id] [bonus] [multiplier=0] [count=0] [title optional] Add/update runtime score entry.");
SafeCommand(console, "gethighscore", GetHighScore, "Print global and gamemode high score.");
SafeCommand(console, "sethighscore", SetHighScore, "[value] Set global and gamemode high score.");
SafeCommand(console, "resetleaderboard", ResetLeaderboard, "[score=0] [steam leaderboard name optional] Reset local leaderboard/high score and optionally force-update Steam score.");
SafeCommand(console, "resetlb", ResetLeaderboard, "[score=0] [steam leaderboard name optional] Alias for resetleaderboard.");
SafeCommand(console, "setbesttime", SetBestTime, "[seconds|mm:ss|hh:mm:ss] Set global and gamemode best time.");
SafeCommand(console, "markwin", MarkWin, "[score optional] [time optional] Save win stats without opening end screen.");
SafeCommand(console, "completegame", CompleteGame, "[score optional] [time optional] Set score/time/win stats and save.");
SafeCommand(console, "finishgame", FinishGame, "[win|lose] Start the game's end sequence.");
SafeCommand(console, "getflag", GetFlag, "[id] Print a session/save flag.");
SafeCommand(console, "setflag", SetFlag, "[id] [true|false] [data optional] [save=true] Set a game flag.");
SafeCommand(console, "listachievements", ListAchievements, "[filter] [limit=80] List loaded achievements.");
SafeCommand(console, "setachievement", SetAchievement, "[id] [true|false] [save=true] Set an achievement through the game API.");
SafeCommand(console, "savestats", SaveStatsCommand, "[writeall=true] Save StatManager data.");
}
private static void SafeCommand(CommandConsole console, string name, Action<string[]> callback, string description)
{
SafeCommandRaw(console, "wkdebug_" + name, callback, description);
}
private static void SafeCommandRaw(CommandConsole console, string name, Action<string[]> callback, string description)
{
object obj = AccessTools.Method(typeof(CommandConsole), "RegisterCommand", new Type[3]
{
typeof(string),
typeof(Action<string[]>),
typeof(bool)
}, (Type[])null).Invoke(console, new object[3] { name, callback, false });
if (obj == null)
{
ManualLogSource obj2 = logSource;
if (obj2 != null)
{
obj2.LogWarning((object)("RegisterCommand returned null for " + name));
}
}
else
{
Type type = obj.GetType();
type.GetField("cheat", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(obj, false);
type.GetField("description", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(obj, description);
}
}
private static void RootCommand(string[] args)
{
if (args.Length == 0)
{
Help(args);
}
else
{
RunSubcommand(args[0], args.Skip(1).ToArray());
}
}
private static void Help(string[] args)
{
Log("Commands:");
Log(" wkdebug help");
Log(" wkdebug hascheated");
Log(" wkdebug sethascheated false");
Log(" wkdebug liststats [filter] [limit]");
Log(" wkdebug getstat bank-roaches");
Log(" wkdebug setstat bank-roaches 999 int");
Log(" wkdebug gettime");
Log(" wkdebug settime 12:34");
Log(" wkdebug getscore");
Log(" wkdebug setscore 50000");
Log(" wkdebug addscore debug-bonus 50000 0 1 Debug Score");
Log(" wkdebug gethighscore");
Log(" wkdebug sethighscore 50000");
Log(" wkdebug resetleaderboard [score=0] [steam leaderboard name optional]");
Log(" wkdebug setbesttime 12:34");
Log(" wkdebug markwin [score] [time]");
Log(" wkdebug completegame [score] [time]");
Log(" wkdebug finishgame win|lose");
Log(" wkdebug getflag flag-id");
Log(" wkdebug setflag flag-id true data true");
Log(" wkdebug listachievements [filter] [limit]");
Log(" wkdebug setachievement ACH_ID true");
Log(" wkdebug savestats [writeall]");
Log(" wkdebug savesession [resetroom]");
Log(" wkdebug_hascheated");
Log(" wkdebug_sethascheated false");
Log(" wkdebug_sessioninfo");
Log(" wkdebug_liststats [filter] [limit]");
Log(" wkdebug_getstat bank-roaches");
Log(" wkdebug_setstat bank-roaches 999 int");
Log(" wkdebug_addstat bank-roaches 10 int");
Log(" wkdebug_exportstats [filter]");
Log(" wkdebug_savesession [resetroom]");
}
private static void CommandConsoleAwakePostfix()
{
TryRegister("CommandConsole.Awake postfix");
}
private static bool CommandConsoleExecuteCommandTwoArgsPrefix(string input)
{
return HandleExecuteCommandPrefix(input, "ExecuteCommand2");
}
private static bool CommandConsoleExecuteCommandThreeArgsPrefix(string input)
{
return HandleExecuteCommandPrefix(input, "ExecuteCommand3");
}
private static bool HandleExecuteCommandPrefix(string input, string source)
{
if (!string.IsNullOrWhiteSpace(input) && input.TrimStart().StartsWith("wk", StringComparison.OrdinalIgnoreCase))
{
ManualLogSource obj = logSource;
if (obj != null)
{
obj.LogInfo((object)("Intercept candidate from " + source + ": " + input));
}
}
return !TryHandleRawCommand(input);
}
private static bool TryHandleRawCommand(string input)
{
if (string.IsNullOrWhiteSpace(input))
{
return false;
}
string text = input.Trim();
string[] array = SplitCommandLine(text);
if (array.Length == 0)
{
return false;
}
string text2 = array[0].ToLowerInvariant();
string text3 = null;
string[] array2 = Array.Empty<string>();
if (text2 == "wkdebug")
{
text3 = ((array.Length > 1) ? array[1] : "help");
array2 = array.Skip(2).ToArray();
}
else if (text2.StartsWith("wkdebug_", StringComparison.Ordinal))
{
text3 = text2.Substring("wkdebug_".Length);
array2 = array.Skip(1).ToArray();
}
else
{
if (!text2.StartsWith("wk", StringComparison.Ordinal))
{
return false;
}
text3 = text2.Substring("wk".Length);
array2 = array.Skip(1).ToArray();
}
ManualLogSource obj = logSource;
if (obj != null)
{
obj.LogInfo((object)("Handling WK Debug Access raw command: " + text));
}
RunSubcommand(text3, array2);
return true;
}
private static void EnsureCommandFiles()
{
try
{
string configDir = GetConfigDir();
Directory.CreateDirectory(configDir);
string path = Path.Combine(configDir, "command.txt");
if (!File.Exists(path))
{
File.WriteAllText(path, "# Write one command, save the file, and the mod will run it.\n# Examples:\n# sethascheated false\n# getscore\n# settime 12:34\n# setscore 50000\n# sethighscore 50000\n# resetleaderboard\n# resetleaderboard 0 \"Steam Leaderboard Name\"\n# markwin 50000 12:34\n# finishgame win\n# exportstats\n", Encoding.UTF8);
}
WriteStatus(force: true);
}
catch (Exception ex)
{
ManualLogSource obj = logSource;
if (obj != null)
{
obj.LogWarning((object)("Could not create command files: " + ex.Message));
}
}
}
private static void ProcessCommandFile()
{
try
{
string path = Path.Combine(GetConfigDir(), "command.txt");
if (!File.Exists(path))
{
EnsureCommandFiles();
return;
}
DateTime lastWriteTimeUtc = File.GetLastWriteTimeUtc(path);
if (!(lastWriteTimeUtc <= lastCommandWriteTimeUtc))
{
lastCommandWriteTimeUtc = lastWriteTimeUtc;
string text = (from l in File.ReadAllLines(path)
select l.Trim()).FirstOrDefault((string l) => l.Length > 0 && !l.StartsWith("#", StringComparison.Ordinal));
if (!string.IsNullOrEmpty(text))
{
Log("Running command file command: " + text);
RunFileCommand(text);
WriteStatus(force: true);
}
}
}
catch (Exception ex)
{
Log("Command file error: " + ex.Message);
}
}
private static void RunFileCommand(string command)
{
if (!TryHandleRawCommand(command))
{
string[] array = SplitCommandLine(command.Trim());
if (array.Length != 0)
{
RunSubcommand(array[0], array.Skip(1).ToArray());
}
}
}
private static void CheckHotkeys()
{
try
{
if (Input.GetKeyDown((KeyCode)287))
{
SetHasCheated(new string[1] { "false" });
WriteStatus(force: true);
}
if (Input.GetKeyDown((KeyCode)288))
{
ExportStats(Array.Empty<string>());
WriteStatus(force: true);
}
if (Input.GetKeyDown((KeyCode)289))
{
SaveSession(Array.Empty<string>());
WriteStatus(force: true);
}
}
catch
{
}
}
private static void WriteStatusThrottled()
{
if (!(Time.unscaledTime < nextStatusWriteTime))
{
nextStatusWriteTime = Time.unscaledTime + 2f;
WriteStatus(force: false);
}
}
private static void WriteStatus(bool force)
{
try
{
string configDir = GetConfigDir();
Directory.CreateDirectory(configDir);
string path = Path.Combine(configDir, "live_status.txt");
GameStats sessionStats = GetSessionStats();
ScoreSnapshot scoreSnapshot = GetScoreSnapshot();
float? currentGameTime = GetCurrentGameTime();
float? statFloat = GetStatFloat(sessionStats, "score");
float? statFloat2 = GetStatFloat(sessionStats, "game-time");
float? statFloat3 = GetStatFloat(GetGlobalStats(), "score");
float? statFloat4 = GetStatFloat(GetGamemodeStats(), "score");
float? statFloat5 = GetStatFloat(GetGlobalStats(), "best-time");
float? statFloat6 = GetStatFloat(GetGamemodeStats(), "best-time");
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("WKDebugAccess 1.0.3");
stringBuilder.AppendLine("updated=" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture));
stringBuilder.AppendLine("commandsRegistered=" + registered);
stringBuilder.AppendLine("commandConsoleObjects=" + CountConsoleObjects());
stringBuilder.AppendLine("hasCheated=" + CommandConsole.hasCheated);
stringBuilder.AppendLine("gamemode=" + SafeGamemodeName());
stringBuilder.AppendLine("runHasEnded=" + CL_GameManager.runHasEnded);
stringBuilder.AppendLine("runtimeGameTime=" + FormatNullableSeconds(currentGameTime));
stringBuilder.AppendLine("sessionGameTime=" + FormatNullableSeconds(statFloat2));
stringBuilder.AppendLine("sessionScoreStat=" + FormatNullableFloat(statFloat));
stringBuilder.AppendLine("sessionScoreEntries=" + scoreSnapshot.Count);
stringBuilder.AppendLine("sessionScoreBonus=" + FormatFloat(scoreSnapshot.Bonus));
stringBuilder.AppendLine("sessionScoreMultiplier=" + FormatFloat(scoreSnapshot.Multiplier));
stringBuilder.AppendLine("sessionScoreTotal=" + FormatFloat(scoreSnapshot.Total));
stringBuilder.AppendLine("globalHighScore=" + FormatNullableFloat(statFloat3));
stringBuilder.AppendLine("gamemodeHighScore=" + FormatNullableFloat(statFloat4));
stringBuilder.AppendLine("globalBestTime=" + FormatNullableSeconds(statFloat5));
stringBuilder.AppendLine("gamemodeBestTime=" + FormatNullableSeconds(statFloat6));
stringBuilder.AppendLine("sessionStatsCount=" + (sessionStats?.statistics?.Count).GetValueOrDefault());
stringBuilder.AppendLine("configDir=" + configDir);
stringBuilder.AppendLine("hotkeys=F6 sethascheated false, F7 exportstats, F8 savesession");
stringBuilder.AppendLine("commandFile=" + Path.Combine(configDir, "command.txt"));
stringBuilder.AppendLine("lastMessages=");
foreach (string item in recentMessages.Take(20))
{
stringBuilder.AppendLine(item);
}
File.WriteAllText(path, stringBuilder.ToString(), Encoding.UTF8);
}
catch (Exception ex)
{
if (force)
{
ManualLogSource obj = logSource;
if (obj != null)
{
obj.LogWarning((object)("Could not write live_status.txt: " + ex.Message));
}
}
}
}
private static void RunSubcommand(string subcommand, string[] args)
{
switch ((subcommand ?? "help").ToLowerInvariant())
{
case "help":
Help(args);
break;
case "hascheated":
HasCheated(args);
break;
case "sethascheated":
SetHasCheated(args);
break;
case "sessioninfo":
SessionInfo(args);
break;
case "liststats":
ListStats(args);
break;
case "getstat":
GetStat(args);
break;
case "setstat":
SetStat(args);
break;
case "addstat":
AddStat(args);
break;
case "exportstats":
ExportStats(args);
break;
case "savesession":
SaveSession(args);
break;
case "time":
case "gettime":
GetTime(args);
break;
case "settime":
SetTime(args);
break;
case "getscore":
case "score":
GetScore(args);
break;
case "listscores":
ListScores(args);
break;
case "setscore":
SetScore(args);
break;
case "addscore":
AddScore(args);
break;
case "highscore":
if (args.Length == 0)
{
GetHighScore(args);
}
else
{
SetHighScore(args);
}
break;
case "gethighscore":
GetHighScore(args);
break;
case "sethighscore":
SetHighScore(args);
break;
case "resetlb":
case "resetleaderboard":
ResetLeaderboard(args);
break;
case "besttime":
if (args.Length == 0)
{
GetTime(args);
}
else
{
SetBestTime(args);
}
break;
case "setbesttime":
SetBestTime(args);
break;
case "markwin":
MarkWin(args);
break;
case "completegame":
CompleteGame(args);
break;
case "finishgame":
case "finish":
FinishGame(args);
break;
case "getflag":
GetFlag(args);
break;
case "setflag":
SetFlag(args);
break;
case "achievements":
case "listachievements":
ListAchievements(args);
break;
case "setachievement":
SetAchievement(args);
break;
case "savestats":
case "saveprogress":
SaveStatsCommand(args);
break;
default:
Log("Unknown WK Debug Access subcommand: " + subcommand);
Help(args);
break;
}
}
private static void HasCheated(string[] args)
{
Log("CommandConsole.hasCheated = " + CommandConsole.hasCheated);
}
private static void SetHasCheated(string[] args)
{
if (args.Length < 1 || !bool.TryParse(args[0], out var result))
{
Log("Usage: wkdebug_sethascheated true|false");
return;
}
CommandConsole.hasCheated = result;
TrySetCheatTracker(result);
Log("CommandConsole.hasCheated = " + CommandConsole.hasCheated);
}
private static void SessionInfo(string[] args)
{
string text = (((Object)(object)CL_GameManager.gamemode != (Object)null) ? CL_GameManager.GetGamemodeName(true, false) : "null");
int valueOrDefault = (GetSessionStats()?.statistics?.Count).GetValueOrDefault();
Log("Gamemode: " + text);
Log("hasCheated: " + CommandConsole.hasCheated);
Log("isSavedRun: " + CL_SaveManager.IsInSavedRun());
Log("sessionStats count: " + valueOrDefault);
Log("roaches: " + CL_GameManager.GetRoaches(false));
Log("game-time: " + FormatNullableSeconds(GetCurrentGameTime()));
Log("score: " + FormatNullableFloat(GetStatFloat(GetSessionStats(), "score")) + ", runtimeTotal=" + FormatFloat(GetScoreSnapshot().Total));
Log("high score: global=" + FormatNullableFloat(GetStatFloat(GetGlobalStats(), "score")) + ", gamemode=" + FormatNullableFloat(GetStatFloat(GetGamemodeStats(), "score")));
}
private static void ListStats(string[] args)
{
GameStats sessionStats = GetSessionStats();
if (sessionStats == null)
{
Log("StatManager.sessionStats is null.");
return;
}
string filter = ((args.Length != 0) ? args[0] : "");
int result = 80;
if (args.Length > 1)
{
int.TryParse(args[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out result);
if (result <= 0)
{
result = 80;
}
}
List<Statistic> list = sessionStats.statistics.Where((Statistic s) => s != null && (string.IsNullOrEmpty(filter) || s.id.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0)).Take(result).ToList();
Log("sessionStats matches: " + list.Count + " / total " + sessionStats.statistics.Count);
foreach (Statistic item in list)
{
Log(FormatStat(item));
}
}
private static void GetStat(string[] args)
{
if (args.Length < 1)
{
Log("Usage: wkdebug_getstat <id>");
return;
}
Statistic val = FindSessionStat(args[0]);
if (val == null)
{
Log("Session stat not found: " + args[0]);
}
else
{
Log(FormatStat(val));
}
}
private unsafe static void SetStat(string[] args)
{
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
if (args.Length < 2)
{
Log("Usage: wkdebug_setstat <id> <value> [int|float|string]");
return;
}
GameStats sessionStats = GetSessionStats();
if (sessionStats == null)
{
Log("StatManager.sessionStats is null.");
return;
}
string text = args[0];
string text2 = args[1];
Statistic val = FindSessionStat(text);
DataType val2 = ((args.Length > 2) ? ParseType(args[2]) : (val?.type ?? InferType(text2)));
if (!TryParseValue(text2, val2, out var parsed))
{
Log("Could not parse '" + text2 + "' as " + ((object)(*(DataType*)(&val2))/*cast due to .constrained prefix*/).ToString() + ".");
}
else
{
sessionStats.SetStatistic(text, parsed, val2);
Log("Set " + FormatStat(FindSessionStat(text)));
}
}
private unsafe static void AddStat(string[] args)
{
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_005a: Invalid comparison between Unknown and I4
//IL_0046: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
if (args.Length < 2)
{
Log("Usage: wkdebug_addstat <id> <delta> [int|float]");
return;
}
GameStats sessionStats = GetSessionStats();
if (sessionStats == null)
{
Log("StatManager.sessionStats is null.");
return;
}
string text = args[0];
string text2 = args[1];
Statistic val = FindSessionStat(text);
DataType val2 = ((args.Length > 2) ? ParseType(args[2]) : (val?.type ?? InferType(text2)));
object parsed;
if ((int)val2 == 1)
{
Log("wkdebug_addstat only supports int/float.");
}
else if (!TryParseValue(text2, val2, out parsed))
{
Log("Could not parse '" + text2 + "' as " + ((object)(*(DataType*)(&val2))/*cast due to .constrained prefix*/).ToString() + ".");
}
else
{
sessionStats.UpdateStatistic(text, parsed, val2, (ModType)1, (DisplayType)0, (ModType)1);
Log("Added. " + FormatStat(FindSessionStat(text)));
}
}
private static void ExportStats(string[] args)
{
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
GameStats sessionStats = GetSessionStats();
if (sessionStats == null)
{
Log("StatManager.sessionStats is null.");
return;
}
string value = ((args.Length != 0) ? args[0] : "");
string text = Path.Combine(Paths.ConfigPath, "WKDebugAccess");
Directory.CreateDirectory(text);
string text2 = Path.Combine(text, "session_stats.tsv");
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("id\tvalue\ttype\tdefaultModType\tdisplayType");
foreach (Statistic statistic in sessionStats.statistics)
{
if (statistic != null && (string.IsNullOrEmpty(value) || statistic.id.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0))
{
stringBuilder.Append(statistic.id).Append('\t').Append(statistic.value)
.Append('\t')
.Append(statistic.type)
.Append('\t')
.Append(statistic.defaultModType)
.Append('\t')
.Append(statistic.displayType)
.AppendLine();
}
}
File.WriteAllText(text2, stringBuilder.ToString(), Encoding.UTF8);
Log("Exported session stats to: " + text2);
}
private static void SaveSession(string[] args)
{
if ((Object)(object)CL_SaveManager.instance == (Object)null)
{
Log("CL_SaveManager.instance is null; cannot save session here.");
return;
}
bool result = false;
if (args.Length != 0)
{
bool.TryParse(args[0], out result);
}
CL_SaveManager.instance.SaveSession(false, true, false, "", result);
Log("SaveSession wrote current run. resetRoom=" + result + ", hasCheated=" + CommandConsole.hasCheated);
}
private static void GetTime(string[] args)
{
float? currentGameTime = GetCurrentGameTime();
float? statFloat = GetStatFloat(GetSessionStats(), "game-time");
float? statFloat2 = GetStatFloat(GetGlobalStats(), "best-time");
float? statFloat3 = GetStatFloat(GetGamemodeStats(), "best-time");
Log("runtime game-time = " + FormatNullableSeconds(currentGameTime));
Log("session stat game-time = " + FormatNullableSeconds(statFloat));
Log("global best-time = " + FormatNullableSeconds(statFloat2));
Log("gamemode best-time = " + FormatNullableSeconds(statFloat3));
}
private static void SetTime(string[] args)
{
if (args.Length < 1 || !TryParseTime(args[0], out var seconds))
{
Log("Usage: wkdebug_settime <seconds|mm:ss|hh:mm:ss>");
}
else if (SetCurrentGameTime(seconds))
{
Log("Current run game-time set to " + FormatSeconds(seconds) + ".");
}
}
private static void GetScore(string[] args)
{
ScoreSnapshot scoreSnapshot = GetScoreSnapshot();
Log("runtime score entries = " + scoreSnapshot.Count);
Log("runtime score bonus = " + FormatFloat(scoreSnapshot.Bonus));
Log("runtime score multiplier = " + FormatFloat(scoreSnapshot.Multiplier));
Log("runtime score total = " + FormatFloat(scoreSnapshot.Total));
Log("session stat score = " + FormatNullableFloat(GetStatFloat(GetSessionStats(), "score")));
GetHighScore(args);
}
private static void ListScores(string[] args)
{
SessionScore sessionScore = CL_ScoreManager.sessionScore;
if (sessionScore == null || sessionScore.scores == null)
{
Log("CL_ScoreManager.sessionScore is null or empty.");
return;
}
string filter = ((args.Length != 0) ? args[0] : "");
int count = ParseOptionalInt(args, 1, 80);
List<Score> list = sessionScore.scores.Where((Score s) => s != null && (string.IsNullOrEmpty(filter) || s.id.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0 || (s.title ?? "").IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0)).Take(count).ToList();
Log("score entries matches: " + list.Count + " / total " + sessionScore.scores.Count);
foreach (Score item in list)
{
Log(FormatScoreEntry(item));
}
}
private static void SetScore(string[] args)
{
if (args.Length < 1 || !TryParseFloat(args[0], out var value))
{
Log("Usage: wkdebug_setscore <value>");
}
else if (SetRuntimeScoreTarget(value))
{
SetSessionScoreStat(value);
ScoreSnapshot scoreSnapshot = GetScoreSnapshot();
Log("Session score set. stat=" + FormatFloat(value) + ", runtimeTotal=" + FormatFloat(scoreSnapshot.Total) + ", entry=wkdebug-score");
}
}
private static void AddScore(string[] args)
{
if (args.Length < 2 || !TryParseFloat(args[1], out var value))
{
Log("Usage: wkdebug_addscore <id> <bonus> [multiplier=0] [count=0] [title optional]");
return;
}
string text = args[0];
float value2 = 0f;
int result = 0;
if (args.Length > 2 && !TryParseFloat(args[2], out value2))
{
Log("Could not parse multiplier: " + args[2]);
return;
}
if (args.Length > 3 && !int.TryParse(args[3], NumberStyles.Integer, CultureInfo.InvariantCulture, out result))
{
Log("Could not parse count: " + args[3]);
return;
}
string text2 = ((args.Length > 4) ? string.Join(" ", args.Skip(4).ToArray()) : text);
SessionScore val = EnsureSessionScore();
val.AddScore(text, text2, value, value2, result);
ScoreSnapshot scoreSnapshot = GetScoreSnapshot();
SetSessionScoreStat(scoreSnapshot.Total);
Log("Added score entry. " + FormatScoreEntry(val.scoreDict[text]));
Log("Runtime score now bonus=" + FormatFloat(scoreSnapshot.Bonus) + ", multiplier=" + FormatFloat(scoreSnapshot.Multiplier) + ", total=" + FormatFloat(scoreSnapshot.Total));
}
private static void GetHighScore(string[] args)
{
Log("global high score = " + FormatNullableFloat(GetStatFloat(GetGlobalStats(), "score")));
Log("gamemode high score = " + FormatNullableFloat(GetStatFloat(GetGamemodeStats(), "score")) + " (" + SafeGamemodeName() + ")");
}
private static void SetHighScore(string[] args)
{
if (args.Length < 1 || !TryParseFloat(args[0], out var value))
{
Log("Usage: wkdebug_sethighscore <value>");
}
else if (SetHighScoreValue(value, persist: true))
{
Log("High score set to " + FormatFloat(value) + " globally and for gamemode " + SafeGamemodeName() + ".");
}
}
private static void ResetLeaderboard(string[] args)
{
float num = 0f;
string text = null;
if (args.Length != 0)
{
if (TryParseFloat(args[0], out var value))
{
num = value;
if (args.Length > 1)
{
text = string.Join(" ", args.Skip(1).ToArray());
}
}
else
{
text = string.Join(" ", args);
}
}
if (ResetLocalLeaderboardScore(num))
{
if (string.IsNullOrWhiteSpace(text))
{
Log("Local leaderboard/high score reset to " + FormatFloat(num) + ". To also force a Steam leaderboard score, use: resetleaderboard " + FormatFloat(num) + " \"Steam Leaderboard Name\"");
}
else
{
ResetSteamLeaderboardScoreAsync(text.Trim(), Mathf.RoundToInt(num));
}
}
}
private static void SetBestTime(string[] args)
{
if (args.Length < 1 || !TryParseTime(args[0], out var seconds))
{
Log("Usage: wkdebug_setbesttime <seconds|mm:ss|hh:mm:ss>");
}
else if (SetBestTimeValue(seconds, persist: true))
{
Log("Best time set to " + FormatSeconds(seconds) + " globally and for gamemode " + SafeGamemodeName() + ".");
}
}
private static void MarkWin(string[] args)
{
float? scoreOverride = null;
float? timeOverride = null;
if (args.Length != 0)
{
if (!TryParseFloat(args[0], out var value))
{
Log("Could not parse score: " + args[0]);
return;
}
scoreOverride = value;
}
if (args.Length > 1)
{
if (!TryParseTime(args[1], out var seconds))
{
Log("Could not parse time: " + args[1]);
return;
}
timeOverride = seconds;
}
if (ApplyFinishStats(win: true, scoreOverride, timeOverride, save: true))
{
Log("Win stats saved without opening the end screen.");
}
}
private static void CompleteGame(string[] args)
{
float? scoreOverride = null;
float? timeOverride = null;
if (args.Length != 0)
{
if (!TryParseFloat(args[0], out var value))
{
Log("Could not parse score: " + args[0]);
return;
}
scoreOverride = value;
}
if (args.Length > 1)
{
if (!TryParseTime(args[1], out var seconds))
{
Log("Could not parse time: " + args[1]);
return;
}
timeOverride = seconds;
}
if (scoreOverride.HasValue)
{
SetRuntimeScoreTarget(scoreOverride.Value);
SetHighScoreValue(scoreOverride.Value, persist: false);
}
if (timeOverride.HasValue)
{
SetCurrentGameTime(timeOverride.Value);
SetBestTimeValue(timeOverride.Value, persist: false);
}
if (ApplyFinishStats(win: true, scoreOverride, timeOverride, save: true))
{
TryUpdateUnlocks();
Log("Complete-game stats saved. Use 'finishgame win' if you also want the in-game end sequence.");
}
}
private static void FinishGame(string[] args)
{
bool flag = true;
if (args.Length != 0)
{
switch (args[0].ToLowerInvariant())
{
case "win":
case "won":
case "true":
case "1":
flag = true;
break;
case "lose":
case "loss":
case "dead":
case "false":
case "0":
flag = false;
break;
default:
Log("Usage: wkdebug_finishgame win|lose");
return;
}
}
if ((Object)(object)CL_GameManager.gMan == (Object)null)
{
Log("CL_GameManager.gMan is null; cannot finish the game from here.");
return;
}
CommandConsole.hasCheated = false;
TrySetCheatTracker(active: false);
try
{
if (flag)
{
CL_GameManager.gMan.Win();
}
else
{
MethodInfo methodInfo = AccessTools.Method(typeof(CL_GameManager), "EndGameSequence", new Type[1] { typeof(bool) }, (Type[])null);
if (methodInfo == null)
{
Log("Could not find CL_GameManager.EndGameSequence(bool).");
return;
}
object obj = methodInfo.Invoke(CL_GameManager.gMan, new object[1] { false });
((MonoBehaviour)CL_GameManager.gMan).StartCoroutine((IEnumerator)obj);
}
Log("Started end-game sequence. win=" + flag + ", hasCheated=" + CommandConsole.hasCheated);
}
catch (Exception ex)
{
Log("finishgame failed: " + ex.Message);
}
}
private static void GetFlag(string[] args)
{
if (args.Length < 1)
{
Log("Usage: wkdebug_getflag <id>");
return;
}
string text = args[0];
bool flag = false;
if ((Object)(object)CL_GameManager.gMan != (Object)null)
{
SessionFlag gameFlag = CL_GameManager.GetGameFlag(text);
if (gameFlag != null)
{
Log("session flag " + text + " = " + gameFlag.state + ", data=" + gameFlag.data);
flag = true;
}
}
SaveFlags val = FindSaveFlag(text);
if (val != null)
{
Log("save flag " + text + " = " + val.value + ", data=" + val.data);
flag = true;
}
if (!flag)
{
Log("Flag not found: " + text);
}
}
private static void SetFlag(string[] args)
{
if (args.Length < 2 || !TryParseBool(args[1], out var value))
{
Log("Usage: wkdebug_setflag <id> <true|false> [data optional] [save=true]");
return;
}
if ((Object)(object)CL_GameManager.gMan == (Object)null)
{
Log("CL_GameManager.gMan is null; cannot set runtime game flag.");
return;
}
string text = args[0];
string text2 = "";
bool value2 = true;
if (args.Length == 3)
{
if (TryParseBool(args[2], out var value3))
{
value2 = value3;
}
else
{
text2 = args[2];
}
}
else if (args.Length > 3)
{
text2 = args[2];
if (!TryParseBool(args[3], out value2))
{
Log("Could not parse save flag: " + args[3]);
return;
}
}
CL_GameManager.SetGameFlag(text, value, text2, value2, false);
if (value2)
{
SaveStatsToDisk(writeAll: false);
}
Log("Set flag " + text + " = " + value + ", data=" + text2 + ", save=" + value2);
}
private static void ListAchievements(string[] args)
{
IEnumerable achievementsEnumerable = GetAchievementsEnumerable();
if (achievementsEnumerable == null)
{
Log("CL_AchievementManager achievements are not available.");
return;
}
string value = ((args.Length != 0) ? args[0] : "");
int num = ParseOptionalInt(args, 1, 80);
int num2 = 0;
int num3 = 0;
foreach (object item in achievementsEnumerable)
{
num2++;
string fieldString = GetFieldString(item, "id");
string fieldString2 = GetFieldString(item, "name");
if ((string.IsNullOrEmpty(value) || fieldString.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0 || fieldString2.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) && num3 < num)
{
num3++;
Log(fieldString + " = " + GetFieldBool(item, "flagged") + " :: " + fieldString2);
}
}
Log("achievement matches shown: " + num3 + " / total " + num2);
}
private static void SetAchievement(string[] args)
{
if (args.Length < 2 || !TryParseBool(args[1], out var value))
{
Log("Usage: wkdebug_setachievement <id> <true|false> [save=true]");
return;
}
bool value2 = true;
if (args.Length > 2 && !TryParseBool(args[2], out value2))
{
Log("Could not parse save flag: " + args[2]);
return;
}
CL_AchievementManager.SetAchievementValue(args[0], value);
if (value2)
{
CL_AchievementManager.SaveAchievements();
SaveStatsToDisk(writeAll: false);
}
Log("Set achievement " + args[0] + " = " + value + ", save=" + value2);
}
private static void SaveStatsCommand(string[] args)
{
bool value = true;
if (args.Length != 0 && !TryParseBool(args[0], out value))
{
Log("Usage: wkdebug_savestats [writeall=true|false]");
}
else
{
SaveStatsToDisk(value);
}
}
private static bool ApplyFinishStats(bool win, float? scoreOverride, float? timeOverride, bool save)
{
GameStats sessionStats = GetSessionStats();
if (sessionStats == null)
{
Log("StatManager.sessionStats is null; cannot write finish stats.");
return false;
}
CommandConsole.hasCheated = false;
TrySetCheatTracker(active: false);
float num = timeOverride ?? GetCurrentGameTime() ?? GetStatFloat(sessionStats, "game-time").GetValueOrDefault();
float num2 = scoreOverride ?? GetGamemodePlayerScore(win) ?? GetScoreSnapshot().Total;
if (timeOverride.HasValue)
{
SetCurrentGameTime(num);
}
if (scoreOverride.HasValue)
{
SetRuntimeScoreTarget(num2);
}
SetSessionScoreStat(num2);
sessionStats.UpdateStatistic("game-time", (object)num, (DataType)2, (ModType)0, (DisplayType)4, (ModType)1);
if (win)
{
sessionStats.UpdateStatistic("wins", (object)1, (DataType)0, (ModType)0, (DisplayType)0, (ModType)1);
sessionStats.UpdateStatistic("best-time", (object)num, (DataType)2, (ModType)3, (DisplayType)4, (ModType)3);
}
if (save)
{
SaveStatsToDisk(writeAll: true);
}
SetPreviousHighScore(Math.Max(GetStatFloat(GetGamemodeStats(), "score") ?? num2, num2));
Log("Finish stats prepared. win=" + win + ", score=" + FormatFloat(num2) + ", game-time=" + FormatSeconds(num) + ", hasCheated=" + CommandConsole.hasCheated);
return true;
}
private static bool ResetLocalLeaderboardScore(float value)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Expected O, but got Unknown
CommandConsole.hasCheated = false;
TrySetCheatTracker(active: false);
try
{
CL_ScoreManager.sessionScore = new SessionScore();
CL_ScoreManager.sessionScore.Initialize();
SetScoreEntry("wkdebug-score", "WK Debug Leaderboard Reset", value, 0f, 0);
SetSessionScoreStat(value);
if (!SetHighScoreValue(value, persist: false))
{
return false;
}
SetPreviousHighScore(value);
SaveStatsToDisk(writeAll: false);
TryUpdateStatUi();
Log("Reset local leaderboard/high score. score=" + FormatFloat(value) + ", gamemode=" + SafeGamemodeName() + ", hasCheated=" + CommandConsole.hasCheated);
return true;
}
catch (Exception ex)
{
Log("Local leaderboard reset failed: " + ex.Message);
return false;
}
}
private static async Task ResetSteamLeaderboardScoreAsync(string leaderboardName, int score)
{
_ = 1;
try
{
if (!SteamClient.IsValid || !SteamClient.IsLoggedOn)
{
Log("Steam client is not connected; local leaderboard reset is done, but Steam leaderboard was not updated.");
return;
}
Log("Finding Steam leaderboard '" + leaderboardName + "'...");
Leaderboard? val = await SteamUserStats.FindLeaderboardAsync(leaderboardName);
if (!val.HasValue)
{
Log("Steam leaderboard not found: " + leaderboardName);
return;
}
Leaderboard value = val.Value;
LeaderboardUpdate? val2 = await ((Leaderboard)(ref value)).ReplaceScore(score, (int[])null);
if (!val2.HasValue)
{
Log("Steam leaderboard ReplaceScore failed for: " + leaderboardName);
return;
}
bool flag = SteamUserStats.StoreStats();
Log("Steam leaderboard score forced. name=" + leaderboardName + ", score=" + val2.Value.Score + ", changed=" + val2.Value.Changed + ", oldRank=" + val2.Value.OldGlobalRank + ", newRank=" + val2.Value.NewGlobalRank + ", StoreStats=" + flag);
}
catch (Exception ex)
{
Log("Steam leaderboard reset failed: " + ex.Message);
}
}
private static bool SetHighScoreValue(float value, bool persist)
{
bool flag = false;
GameStats globalStats = GetGlobalStats();
if (globalStats != null)
{
globalStats.UpdateStatistic("score", (object)value, (DataType)2, (ModType)0, (DisplayType)0, (ModType)2);
flag = true;
}
GameStats gamemodeStats = GetGamemodeStats();
if (gamemodeStats != null)
{
gamemodeStats.UpdateStatistic("score", (object)value, (DataType)2, (ModType)0, (DisplayType)0, (ModType)2);
flag = true;
}
if (!flag)
{
Log("StatManager.saveData is not available; cannot set high score.");
return false;
}
SetPreviousHighScore(value);
if (persist)
{
SaveStatsToDisk(writeAll: false);
}
return true;
}
private static bool SetBestTimeValue(float seconds, bool persist)
{
bool flag = false;
GameStats globalStats = GetGlobalStats();
if (globalStats != null)
{
globalStats.UpdateStatistic("best-time", (object)seconds, (DataType)2, (ModType)0, (DisplayType)4, (ModType)3);
flag = true;
}
GameStats gamemodeStats = GetGamemodeStats();
if (gamemodeStats != null)
{
gamemodeStats.UpdateStatistic("best-time", (object)seconds, (DataType)2, (ModType)0, (DisplayType)4, (ModType)3);
flag = true;
}
if (!flag)
{
Log("StatManager.saveData is not available; cannot set best time.");
return false;
}
if (persist)
{
SaveStatsToDisk(writeAll: false);
}
return true;
}
private static bool SaveStatsToDisk(bool writeAll)
{
if ((Object)(object)StatManager.instance == (Object)null)
{
Log("StatManager.instance is null; cannot save stats to disk yet.");
return false;
}
CommandConsole.hasCheated = false;
TrySetCheatTracker(active: false);
try
{
StatManager.instance.SaveStats(writeAll);
Log("StatManager.SaveStats(" + writeAll + ") complete. hasCheated=" + CommandConsole.hasCheated);
return true;
}
catch (Exception ex)
{
Log("SaveStats failed: " + ex.Message);
return false;
}
}
private static bool SetCurrentGameTime(float seconds)
{
if (seconds < 0f)
{
seconds = 0f;
}
if ((Object)(object)CL_GameManager.gMan == (Object)null)
{
Log("CL_GameManager.gMan is null; cannot set runtime game-time.");
return false;
}
try
{
MethodInfo methodInfo = AccessTools.Method(typeof(CL_GameManager), "SetGameTime", new Type[1] { typeof(float) }, (Type[])null);
if (methodInfo != null)
{
methodInfo.Invoke(CL_GameManager.gMan, new object[1] { seconds });
}
else
{
FieldInfo fieldInfo = AccessTools.Field(typeof(CL_GameManager), "gameTime");
if (fieldInfo == null)
{
Log("Could not find CL_GameManager.SetGameTime or gameTime field.");
return false;
}
fieldInfo.SetValue(CL_GameManager.gMan, seconds);
}
GameStats sessionStats = GetSessionStats();
if (sessionStats != null)
{
sessionStats.UpdateStatistic("game-time", (object)seconds, (DataType)2, (ModType)0, (DisplayType)4, (ModType)1);
}
return true;
}
catch (Exception ex)
{
Log("Set game-time failed: " + ex.Message);
return false;
}
}
private static float? GetCurrentGameTime()
{
try
{
if ((Object)(object)CL_GameManager.gMan != (Object)null)
{
return CL_GameManager.gMan.GetGameTime();
}
}
catch
{
}
return GetStatFloat(GetSessionStats(), "game-time");
}
private static float? GetGamemodePlayerScore(bool win)
{
try
{
object gamemode = CL_GameManager.gamemode;
if (gamemode == null)
{
return null;
}
MethodInfo methodInfo = AccessTools.Method(gamemode.GetType(), "GetPlayerScore", new Type[1] { typeof(bool) }, (Type[])null);
if (methodInfo == null)
{
return null;
}
object obj = methodInfo.Invoke(gamemode, new object[1] { win });
if (obj == null)
{
return null;
}
return Convert.ToSingle(obj, CultureInfo.InvariantCulture);
}
catch
{
return null;
}
}
private static bool SetRuntimeScoreTarget(float target)
{
SessionScore val = EnsureSessionScore();
float num = 0f;
float num2 = 0f;
if (val.scores != null)
{
foreach (Score score in val.scores)
{
if (score != null && !string.Equals(score.id, "wkdebug-score", StringComparison.OrdinalIgnoreCase))
{
num += score.bonus;
num2 += score.multiplier;
}
}
}
SetScoreEntry("wkdebug-score", "WK Debug Score", target - num, 0f - num2, 1);
return true;
}
private static void SetSessionScoreStat(float value)
{
GameStats sessionStats = GetSessionStats();
if (sessionStats != null)
{
sessionStats.UpdateStatistic("score", (object)value, (DataType)2, (ModType)0, (DisplayType)0, (ModType)2);
}
}
private static SessionScore EnsureSessionScore()
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Expected O, but got Unknown
if (CL_ScoreManager.sessionScore == null)
{
CL_ScoreManager.sessionScore = new SessionScore();
}
if (CL_ScoreManager.sessionScore.scores == null || CL_ScoreManager.sessionScore.scoreDict == null)
{
CL_ScoreManager.sessionScore.Initialize();
}
return CL_ScoreManager.sessionScore;
}
private static void SetScoreEntry(string id, string title, float bonus, float multiplier, int count)
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Expected O, but got Unknown
SessionScore val = EnsureSessionScore();
if (val.scoreDict == null)
{
val.Initialize();
}
if (!val.scoreDict.TryGetValue(id, out var value))
{
value = new Score
{
id = id
};
val.scores.Add(value);
val.scoreDict[id] = value;
}
value.title = title;
value.bonus = bonus;
value.multiplier = multiplier;
value.count = count;
}
private static ScoreSnapshot GetScoreSnapshot()
{
ScoreSnapshot result = new ScoreSnapshot
{
Multiplier = 1f
};
SessionScore sessionScore = CL_ScoreManager.sessionScore;
if (sessionScore == null || sessionScore.scores == null)
{
result.Total = 0f;
return result;
}
foreach (Score score in sessionScore.scores)
{
if (score != null)
{
result.Count++;
result.Bonus += score.bonus;
result.Multiplier += score.multiplier;
}
}
result.Multiplier = Mathf.Max(result.Multiplier, 0f);
result.Total = result.Bonus * result.Multiplier;
return result;
}
private static string FormatScoreEntry(Score entry)
{
if (entry == null)
{
return "<null score entry>";
}
return entry.id + " = bonus " + FormatFloat(entry.bonus) + ", multiplier " + FormatFloat(entry.multiplier) + ", count " + entry.count + ", title=" + entry.title;
}
private static void SetPreviousHighScore(float value)
{
try
{
if ((Object)(object)CL_GameManager.gMan != (Object)null)
{
AccessTools.Field(typeof(CL_GameManager), "previousHighScore")?.SetValue(CL_GameManager.gMan, value);
}
}
catch
{
}
}
private static void TryUpdateUnlocks()
{
try
{
Type type = AccessTools.TypeByName("CL_ProgressionManager");
((type != null) ? AccessTools.Method(type, "UpdateUnlocks", new Type[1] { typeof(bool) }, (Type[])null) : null)?.Invoke(null, new object[1] { true });
}
catch
{
}
}
private static void TryUpdateStatUi()
{
try
{
StatManager instance = StatManager.instance;
if (instance != null)
{
instance.UpdateUI();
}
}
catch
{
}
}
private static GameStats GetGlobalStats()
{
try
{
if (StatManager.saveData == null || StatManager.saveData.gameStats == null)
{
return null;
}
EnsureStatsDictionary(StatManager.saveData.gameStats);
return StatManager.saveData.gameStats;
}
catch
{
return null;
}
}
private static GameStats GetGamemodeStats()
{
try
{
if (StatManager.saveData == null)
{
return null;
}
string text = SafeGamemodeName();
if (string.IsNullOrEmpty(text) || text == "null")
{
return null;
}
GameModeData gameMode = StatManager.saveData.GetGameMode(text);
if (gameMode == null || gameMode.stats == null)
{
return null;
}
EnsureStatsDictionary(gameMode.stats);
return gameMode.stats;
}
catch
{
return null;
}
}
private static void EnsureStatsDictionary(GameStats stats)
{
if (stats != null && (stats.statsDictionary == null || stats.statsDictionary.Count == 0))
{
stats.InitializeDictionary();
}
}
private static float? GetStatFloat(GameStats stats, string id)
{
try
{
if (stats == null || string.IsNullOrEmpty(id))
{
return null;
}
EnsureStatsDictionary(stats);
if (!stats.HasStatistic(id))
{
return null;
}
object value = stats.GetStatistic(id).GetValue();
if (value is float value2)
{
return value2;
}
if (value is int num)
{
return num;
}
if (value is string raw && TryParseFloat(raw, out var value3))
{
return value3;
}
}
catch
{
return null;
}
return null;
}
private static SaveFlags FindSaveFlag(string id)
{
if (StatManager.saveData?.flags == null)
{
return null;
}
return ((IEnumerable<SaveFlags>)StatManager.saveData.flags).FirstOrDefault((Func<SaveFlags, bool>)((SaveFlags f) => f != null && string.Equals(f.name, id, StringComparison.OrdinalIgnoreCase)));
}
private static IEnumerable GetAchievementsEnumerable()
{
if ((Object)(object)CL_AchievementManager.instance == (Object)null)
{
return null;
}
return AccessTools.Field(typeof(CL_AchievementManager), "achievements")?.GetValue(CL_AchievementManager.instance) as IEnumerable;
}
private static string GetFieldString(object obj, string fieldName)
{
return (obj?.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj))?.ToString() ?? "";
}
private static bool GetFieldBool(object obj, string fieldName)
{
object obj2 = obj?.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(obj);
bool flag = default(bool);
int num;
if (obj2 is bool)
{
flag = (bool)obj2;
num = 1;
}
else
{
num = 0;
}
return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
}
private static string SafeGamemodeName()
{
try
{
return ((Object)(object)CL_GameManager.gamemode != (Object)null) ? CL_GameManager.GetGamemodeName(true, false) : "null";
}
catch
{
return "unknown";
}
}
private static int ParseOptionalInt(string[] args, int index, int defaultValue)
{
if (args.Length <= index || !int.TryParse(args[index], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) || result <= 0)
{
return defaultValue;
}
return result;
}
private static bool TryParseFloat(string raw, out float value)
{
value = 0f;
if (!string.IsNullOrWhiteSpace(raw))
{
return float.TryParse(raw.Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out value);
}
return false;
}
private static bool TryParseBool(string raw, out bool value)
{
value = false;
if (bool.TryParse(raw, out value))
{
return true;
}
if (string.Equals(raw, "1", StringComparison.OrdinalIgnoreCase) || string.Equals(raw, "yes", StringComparison.OrdinalIgnoreCase) || string.Equals(raw, "on", StringComparison.OrdinalIgnoreCase))
{
value = true;
return true;
}
if (string.Equals(raw, "0", StringComparison.OrdinalIgnoreCase) || string.Equals(raw, "no", StringComparison.OrdinalIgnoreCase) || string.Equals(raw, "off", StringComparison.OrdinalIgnoreCase))
{
value = false;
return true;
}
return false;
}
private static bool TryParseTime(string raw, out float seconds)
{
seconds = 0f;
if (string.IsNullOrWhiteSpace(raw))
{
return false;
}
raw = raw.Trim();
if (!raw.Contains(":"))
{
return TryParseFloat(raw, out seconds);
}
string[] array = raw.Split(':');
float num = 1f;
for (int num2 = array.Length - 1; num2 >= 0; num2--)
{
if (!TryParseFloat(array[num2], out var value))
{
seconds = 0f;
return false;
}
seconds += value * num;
num *= 60f;
}
return true;
}
private static string FormatNullableFloat(float? value)
{
if (!value.HasValue)
{
return "null";
}
return FormatFloat(value.Value);
}
private static string FormatFloat(float value)
{
return value.ToString("0.###", CultureInfo.InvariantCulture);
}
private static string FormatNullableSeconds(float? seconds)
{
if (!seconds.HasValue)
{
return "null";
}
return FormatSeconds(seconds.Value);
}
private static string FormatSeconds(float seconds)
{
if (seconds < 0f)
{
seconds = 0f;
}
TimeSpan timeSpan = TimeSpan.FromSeconds(seconds);
string text = ((timeSpan.TotalHours >= 1.0) ? timeSpan.ToString("hh\\:mm\\:ss\\.ff", CultureInfo.InvariantCulture) : timeSpan.ToString("mm\\:ss\\.ff", CultureInfo.InvariantCulture));
return FormatFloat(seconds) + "s (" + text + ")";
}
private static string[] SplitCommandLine(string command)
{
List<string> list = new List<string>();
StringBuilder stringBuilder = new StringBuilder();
bool flag = false;
foreach (char c in command)
{
if (c == '"')
{
flag = !flag;
}
else if (!flag && char.IsWhiteSpace(c))
{
if (stringBuilder.Length > 0)
{
list.Add(stringBuilder.ToString());
stringBuilder.Length = 0;
}
}
else
{
stringBuilder.Append(c);
}
}
if (stringBuilder.Length > 0)
{
list.Add(stringBuilder.ToString());
}
return list.ToArray();
}
private static GameStats GetSessionStats()
{
if (StatManager.sessionStats == null)
{
return null;
}
if (StatManager.sessionStats.statsDictionary == null || StatManager.sessionStats.statsDictionary.Count == 0)
{
StatManager.sessionStats.InitializeDictionary();
}
return StatManager.sessionStats;
}
private static Statistic FindSessionStat(string id)
{
GameStats sessionStats = GetSessionStats();
if (sessionStats == null || string.IsNullOrEmpty(id))
{
return null;
}
if (sessionStats.statsDictionary != null && sessionStats.statsDictionary.TryGetValue(id, out var value))
{
return value;
}
return ((IEnumerable<Statistic>)sessionStats.statistics).FirstOrDefault((Func<Statistic, bool>)((Statistic s) => s != null && string.Equals(s.id, id, StringComparison.OrdinalIgnoreCase)));
}
private static string FormatStat(Statistic stat)
{
if (stat == null)
{
return "<null>";
}
return stat.id + " = " + stat.value + " (" + ((object)Unsafe.As<DataType, DataType>(ref stat.type)/*cast due to .constrained prefix*/).ToString() + ", defaultMod=" + ((object)Unsafe.As<ModType, ModType>(ref stat.defaultModType)/*cast due to .constrained prefix*/).ToString() + ", display=" + ((object)Unsafe.As<DisplayType, DisplayType>(ref stat.displayType)/*cast due to .constrained prefix*/).ToString() + ")";
}
private static DataType ParseType(string type)
{
if (!string.Equals(type, "int", StringComparison.OrdinalIgnoreCase) && !string.Equals(type, "0", StringComparison.OrdinalIgnoreCase))
{
if (!string.Equals(type, "string", StringComparison.OrdinalIgnoreCase) && !string.Equals(type, "str", StringComparison.OrdinalIgnoreCase) && !string.Equals(type, "1", StringComparison.OrdinalIgnoreCase))
{
if (!string.Equals(type, "float", StringComparison.OrdinalIgnoreCase) && !string.Equals(type, "single", StringComparison.OrdinalIgnoreCase))
{
string.Equals(type, "2", StringComparison.OrdinalIgnoreCase);
}
return (DataType)2;
}
return (DataType)1;
}
return (DataType)0;
}
private static DataType InferType(string value)
{
if (!int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var _))
{
if (!float.TryParse(value.Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out var _))
{
return (DataType)1;
}
return (DataType)2;
}
return (DataType)0;
}
private static bool TryParseValue(string rawValue, DataType type, out object parsed)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Expected I4, but got Unknown
switch ((int)type)
{
case 0:
{
if (int.TryParse(rawValue, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2))
{
parsed = result2;
return true;
}
parsed = null;
return false;
}
case 2:
{
if (float.TryParse(rawValue.Replace(',', '.'), NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
{
parsed = result;
return true;
}
parsed = null;
return false;
}
case 1:
parsed = rawValue;
return true;
default:
parsed = null;
return false;
}
}
private static void TrySetCheatTracker(bool active)
{
try
{
if ((Object)(object)CL_UIManager.instance != (Object)null && (Object)(object)CL_UIManager.instance.cheatTracker != (Object)null)
{
CL_UIManager.instance.cheatTracker.SetActive(active);
}
}
catch
{
}
}
private static void Log(string message)
{
string text = "[WKDebugAccess] " + message;
recentMessages.Insert(0, DateTime.Now.ToString("HH:mm:ss", CultureInfo.InvariantCulture) + " " + message);
while (recentMessages.Count > 40)
{
recentMessages.RemoveAt(recentMessages.Count - 1);
}
try
{
CommandConsole.Log(text);
}
catch
{
}
Debug.Log((object)text);
ManualLogSource obj2 = logSource;
if (obj2 != null)
{
obj2.LogInfo((object)message);
}
try
{
string configDir = GetConfigDir();
Directory.CreateDirectory(configDir);
File.AppendAllText(Path.Combine(configDir, "WKDebugAccess.log"), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture) + " " + message + Environment.NewLine, Encoding.UTF8);
}
catch
{
}
}
private static string GetConfigDir()
{
return Path.Combine(Paths.ConfigPath, "WKDebugAccess");
}
}
}