using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using Mirror;
using Shipmate.Porting;
using SmolMods.Core;
using Steamworks;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("smolMods.ColorSelf")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+e90a00273091d71235f09886429f05ccd89d5c5b")]
[assembly: AssemblyProduct("smolMods.ColorSelf")]
[assembly: AssemblyTitle("smolMods.ColorSelf")]
[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;
}
}
}
namespace SmolMods.ColorSelf
{
[HarmonyPatch]
internal static class PlayerColorFeature
{
private const int NoOverride = -1;
private static ModRowDef _headRow;
private static ModRowDef _torsoRow;
private static ModRowDef _legsRow;
private static ModRowDef _rememberRow;
private static string[] _colorNames;
private static int _framesUntilAutoApply = -1;
private const int SliderMaxIndex = 23;
private const float SendInterval = 0.35f;
private static readonly int[] PendingSend = new int[3] { -2147483648, -2147483648, -2147483648 };
private static float _nextNetSend;
private static bool ShinyAllowed => ShinyOwnership.Owned;
internal static int TorsoRowValue
{
get
{
ModRowDef torsoRow = _torsoRow;
if (torsoRow == null)
{
return -1;
}
return torsoRow.Value;
}
}
internal static void Register()
{
_headRow = AddColorRow("Head color", "settings_mod_headColor", (LookPart)0);
_torsoRow = AddColorRow("Torso color", "settings_mod_torsoColor", (LookPart)1);
_legsRow = AddColorRow("Legs color", "settings_mod_legsColor", (LookPart)2);
ModSettingsApi.AddSliderRow(300, "_Speechlessness", "settings_mod_speechlessness", 0, 0, 100, (Action<int>)delegate(int v)
{
SpeechlessDrive.SetLocalLevel((float)v / 100f);
}, (Func<int, string>)((int v) => v.ToString()), false, 5, false, (Func<int, Color?>)null, true).VisibleWhen = () => SpeechlessUnlock.Owned;
_rememberRow = ModSettingsApi.AddArrayRow(300, "Remember colors", "settings_mod_rememberColors", 1, new int[2] { 0, 1 }, (Func<int, string>)((int v) => (v != 1) ? "Off" : "On"), (Action<int>)delegate
{
}, (Func<int, Color?>)null, false, false);
ModSettingsApi.AddTicker((Action)TickSend);
ModSettingsApi.AddMenuOpenedHandler((Action)OnMenuOpened);
ModSettingsApi.PlayerLookChanged += delegate
{
SyncRowsFromCharacter();
ModSettingsApi.RefreshRows();
};
ShinyOwnership.Changed += ModSettingsApi.RefreshRows;
SpeechlessUnlock.Changed += ModSettingsApi.RefreshRows;
ModSettingsApi.RequestCharacterPreview();
ModSettingsApi.SetPreviewLookProvider((Func<PreviewLook>)delegate
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
PreviewLook result = default(PreviewLook);
ModRowDef headRow = _headRow;
result.Head = ((headRow != null) ? headRow.Value : (-1));
ModRowDef torsoRow = _torsoRow;
result.Torso = ((torsoRow != null) ? torsoRow.Value : (-1));
ModRowDef legsRow = _legsRow;
result.Legs = ((legsRow != null) ? legsRow.Value : (-1));
return result;
});
ModSettingsApi.AddNoteLine(300, (Func<string>)NoteLine);
}
private static string NoteLine()
{
if (ShinyOwnership.Owned)
{
return null;
}
if (!ShinyOwnership.Resolved)
{
return "Shiny colours appear once Steam confirms the achievement.";
}
return null;
}
private static ModRowDef AddColorRow(string title, string saveKey, LookPart part)
{
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
return ModSettingsApi.AddSliderRow(300, title, saveKey, -1, -1, 23, (Action<int>)delegate(int v)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
ApplyPart(part, v);
}, (Func<int, string>)((int v) => LabelFor(v)), false, 1, false, (Func<int, Color?>)((int v) => TintFor(v)), true);
}
private static void EnsureColorNames()
{
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
if (_colorNames != null)
{
return;
}
PlayerLookSet lookSet = PlayerPalette.LookSet;
if ((Object)(object)lookSet == (Object)null)
{
return;
}
int length = ((Il2CppArrayBase<LookColor>)(object)lookSet.colors).Length;
_colorNames = new string[length];
Dictionary<string, int> dictionary = new Dictionary<string, int>();
for (int i = 0; i < length; i++)
{
string text = NameColor(lookSet.GetColor(i));
if (dictionary.TryGetValue(text, out var value))
{
dictionary[text] = value + 1;
_colorNames[i] = $"{text} {value + 1}";
}
else
{
dictionary[text] = 1;
_colorNames[i] = text;
}
}
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogInfo((object)("Palette names: " + string.Join(", ", _colorNames)));
}
}
private static string NameColor(Color c)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: 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)
float num = c.r;
float num2 = c.g;
float num3 = c.b;
if (float.IsNaN(num) || float.IsNaN(num2) || float.IsNaN(num3))
{
return "Mystery";
}
float num4 = Mathf.Max(num, Mathf.Max(num2, num3));
if (num4 > 1f)
{
num /= num4;
num2 /= num4;
num3 /= num4;
}
float num5 = default(float);
float num6 = default(float);
float num7 = default(float);
Color.RGBToHSV(new Color(num, num2, num3), ref num5, ref num6, ref num7);
if (num6 < 0.13f || num7 < 0.09f)
{
if (num7 < 0.09f)
{
return "Black";
}
if (num7 < 0.3f)
{
return "Dark Grey";
}
if (num7 < 0.6f)
{
return "Grey";
}
if (num7 < 0.85f)
{
return "Light Grey";
}
return "White";
}
float num8 = num5 * 360f;
string text = ((num8 < 12f) ? "Red" : ((num8 < 38f) ? ((num7 < 0.55f && num6 > 0.4f) ? "Brown" : "Orange") : ((num8 < 65f) ? "Yellow" : ((num8 < 95f) ? "Lime" : ((num8 < 150f) ? "Green" : ((num8 < 185f) ? "Teal" : ((num8 < 200f) ? "Cyan" : ((num8 < 250f) ? "Blue" : ((num8 < 290f) ? "Purple" : ((!(num8 < 330f)) ? "Red" : "Magenta"))))))))));
if ((text == "Red" || text == "Magenta") && num7 > 0.75f && num6 < 0.55f)
{
return "Pink";
}
if (text == "Brown")
{
return "Brown";
}
if (num7 < 0.35f)
{
return "Dark " + text;
}
if (num7 > 0.85f && num6 < 0.35f)
{
return "Pale " + text;
}
return text;
}
private static string LabelFor(int v)
{
if (v < 0)
{
return "Default";
}
EnsureColorNames();
if (_colorNames != null && v < _colorNames.Length)
{
if (!ShinyPalette.IsShiny(v))
{
return _colorNames[v];
}
return _colorNames[v] + " (shiny)";
}
return (v + 1).ToString();
}
internal static void SyncRowsFromCharacter()
{
OnMenuOpened();
}
private static Color? TintFor(int v)
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
//IL_00a7: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
PlayerLookSet lookSet = PlayerPalette.LookSet;
if (v < 0 || (Object)(object)lookSet == (Object)null)
{
return null;
}
Color color = lookSet.GetColor(v);
if (float.IsNaN(color.r) || float.IsNaN(color.g) || float.IsNaN(color.b))
{
return null;
}
float num = Mathf.Max(color.r, Mathf.Max(color.g, color.b));
if (num > 1f)
{
color.r /= num;
color.g /= num;
color.b /= num;
}
float num2 = default(float);
float num3 = default(float);
float num4 = default(float);
Color.RGBToHSV(new Color(color.r, color.g, color.b), ref num2, ref num3, ref num4);
num4 = Mathf.Min(num4, 0.8f);
Color value = Color.HSVToRGB(num2, num3, num4);
value.a = 1f;
return value;
}
private static void ApplyPart(LookPart part, int value)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
if (value == -2)
{
ModRowDef obj = RowFor(part);
if (obj != null)
{
obj.SetValue(-1, true);
}
}
else
{
if (value < 0)
{
return;
}
if (ShinyPalette.IsShiny(value) && !ShinyAllowed)
{
int num = NearestAllowed(value);
if (num != value)
{
ModRowDef obj2 = RowFor(part);
if (obj2 != null)
{
obj2.SetValue(num, true);
}
}
}
else
{
PendingSend[part] = value;
}
}
}
private static ModRowDef RowFor(LookPart part)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0003: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Invalid comparison between Unknown and I4
if ((int)part != 0)
{
if ((int)part == 1)
{
return _torsoRow;
}
return _legsRow;
}
return _headRow;
}
private static int NearestAllowed(int value)
{
for (int i = 1; i <= 24; i++)
{
int num = value - i;
int num2 = value + i;
if (num >= 0 && !ShinyPalette.IsShiny(num))
{
return num;
}
if (num2 <= 23 && !ShinyPalette.IsShiny(num2))
{
return num2;
}
}
return -1;
}
private static void TickSend()
{
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Expected O, but got Unknown
if ((PendingSend[0] == int.MinValue && PendingSend[1] == int.MinValue && PendingSend[2] == int.MinValue) || Time.unscaledTime < _nextNetSend)
{
return;
}
PlayerCharacter val = PlayerPalette.FindLocalPlayer();
if ((Object)(object)val == (Object)null || (Object)(object)val.playerNetworking == (Object)null)
{
return;
}
_nextNetSend = Time.unscaledTime + 0.35f;
bool flag = default(bool);
for (int i = 0; i < 3; i++)
{
int num = PendingSend[i];
if (num == int.MinValue)
{
continue;
}
PendingSend[i] = int.MinValue;
try
{
val.playerNetworking.CmdChangeLook(num, (LookPart)i);
}
catch (Exception ex)
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(22, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("CmdChangeLook failed: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<Exception>(ex);
}
logger.LogError(val2);
}
}
}
}
private static void ApplyAll()
{
ApplyPart((LookPart)0, _headRow.Value);
ApplyPart((LookPart)1, _torsoRow.Value);
ApplyPart((LookPart)2, _legsRow.Value);
}
private static void OnMenuOpened()
{
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Expected O, but got Unknown
PlayerCharacter val = PlayerPalette.FindLocalPlayer();
if ((Object)(object)val != (Object)null && val.looks != null)
{
try
{
int lookId = val.looks.GetLookId((LookPart)0);
int lookId2 = val.looks.GetLookId((LookPart)1);
int lookId3 = val.looks.GetLookId((LookPart)2);
if (ShinyAllowed || !ShinyPalette.IsShiny(lookId))
{
_headRow.SetValue(lookId, true);
}
if (ShinyAllowed || !ShinyPalette.IsShiny(lookId2))
{
_torsoRow.SetValue(lookId2, true);
}
if (ShinyAllowed || !ShinyPalette.IsShiny(lookId3))
{
_legsRow.SetValue(lookId3, true);
}
}
catch (Exception ex)
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
bool flag = default(bool);
BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(29, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Reading current look failed: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
}
logger.LogWarning(val2);
}
}
}
EnsureColorNames();
}
[HarmonyPostfix]
[HarmonyPatch(typeof(PlayerCharacter), "Start")]
private static void PlayerStart_Postfix(PlayerCharacter __instance)
{
try
{
if (((NetworkBehaviour)__instance).isLocalPlayer && _rememberRow != null && _rememberRow.Value == 1 && (_headRow.Value >= 0 || _torsoRow.Value >= 0 || _legsRow.Value >= 0))
{
_framesUntilAutoApply = 180;
}
}
catch
{
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(PlayerCharacter), "Update")]
private static void PlayerUpdate_Postfix(PlayerCharacter __instance)
{
if (_framesUntilAutoApply >= 0 && ((NetworkBehaviour)__instance).isLocalPlayer && --_framesUntilAutoApply == 0)
{
_framesUntilAutoApply = -1;
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
logger.LogInfo((object)"Auto-applying saved colors after spawn");
}
ApplyAll();
}
}
}
[BepInPlugin("com.smolmods.colorself", "smolMods.ColorSelf", "1.0.11")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BasePlugin
{
public const string PluginGuid = "com.smolmods.colorself";
public const string PluginName = "smolMods.ColorSelf";
public const string PluginVersion = "1.0.11";
internal static ManualLogSource Logger;
public override void Load()
{
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Expected O, but got Unknown
Logger = ((BasePlugin)this).Log;
try
{
PlayerPrefs.DeleteKey("settings_mod_shinyColors");
}
catch
{
}
SpeechlessUnlock.Register();
SpeechlessDrive.Register();
PlayerColorFeature.Register();
TorsoHudRow.Register();
ShinyOwnership.Register();
Harmony val = new Harmony("com.smolmods.colorself");
val.PatchAll(typeof(Plugin).Assembly);
int num = 0;
foreach (MethodBase patchedMethod in val.GetPatchedMethods())
{
_ = patchedMethod;
num++;
}
ManualLogSource log = ((BasePlugin)this).Log;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(27, 3, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("smolMods.ColorSelf");
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("1.0.11");
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" loaded, ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" methods patched.");
}
log.LogInfo(val2);
}
}
internal static class ShinyOwnership
{
private const string LatchKey = "smolmods_shinyOwnedConfirmed";
private static bool _resolved;
private static bool _confirmed;
private static float _nextProbeAt = 5f;
private static string _apiName;
private static bool _loggedGameProbeFailure;
private static bool _loggedCandidates;
internal static bool Owned
{
get
{
if (!_confirmed)
{
if (!_resolved)
{
return PlayerPrefs.GetInt("smolmods_shinyOwnedConfirmed", 0) == 1;
}
return false;
}
return true;
}
}
internal static bool Resolved => _resolved;
internal static event Action Changed;
internal static void Register()
{
ModSettingsApi.AddTicker((Action)Tick);
}
private static void Tick()
{
if (!_resolved && !(Time.unscaledTime < _nextProbeAt))
{
_nextProbeAt = Time.unscaledTime + 30f;
Probe();
}
}
private static string ApiName()
{
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Expected O, but got Unknown
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_006b: Expected O, but got Unknown
if (!string.IsNullOrEmpty(_apiName))
{
return _apiName;
}
bool flag = default(bool);
try
{
EPlatformAchievement shiny = BWAchievements.Shiny;
if (shiny == null)
{
return null;
}
string text = shiny.SteamStatAPIName;
if (string.IsNullOrEmpty(text))
{
text = shiny.StorageName;
}
if (string.IsNullOrEmpty(text))
{
text = shiny.Name;
}
if (!string.IsNullOrEmpty(text))
{
_apiName = text;
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(39, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Shiny achievement API name resolved: '");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'");
}
logger.LogInfo(val);
}
}
return _apiName;
}
catch (Exception ex)
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(38, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Shiny achievement handle unavailable: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
}
logger.LogWarning(val2);
}
return null;
}
}
private static bool? GameSaysUnlocked()
{
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_007e: Expected O, but got Unknown
try
{
AbstractPlatformAchievements achievements = AbstractPlatformManager<PlatformManager>.Achievements;
if (achievements == null)
{
return null;
}
EPlatformAchievement shiny = BWAchievements.Shiny;
if (shiny == null)
{
return null;
}
if (achievements.IsAchievementUnlocked(shiny))
{
return true;
}
try
{
achievements.AsyncFetchAchievements();
}
catch
{
}
return false;
}
catch (Exception ex)
{
if (!_loggedGameProbeFailure)
{
_loggedGameProbeFailure = true;
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
bool flag = default(bool);
BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(36, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Game achievement cache unavailable: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
}
logger.LogWarning(val);
}
}
return null;
}
}
private static string[] Candidates(string raw)
{
List<string> list = new List<string>();
if (!string.IsNullOrEmpty(raw))
{
list.Add(raw);
}
try
{
string text = Encoding.UTF8.GetString(Convert.FromBase64String(raw));
if (!string.IsNullOrEmpty(text) && text != raw)
{
list.Add(text);
}
}
catch
{
}
return list.ToArray();
}
private static void Probe()
{
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Expected O, but got Unknown
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Expected O, but got Unknown
bool flag = default(bool);
try
{
if (GameSaysUnlocked() == true)
{
Settle(achieved: true, "game achievement cache");
return;
}
string text = ApiName();
if (string.IsNullOrEmpty(text))
{
return;
}
try
{
SteamUserStats.RequestCurrentStats();
}
catch
{
}
string[] array = Candidates(text);
bool achieved = default(bool);
uint num = default(uint);
foreach (string text2 in array)
{
if (!SteamUserStats.GetAchievementAndUnlockTime(text2, ref achieved, ref num))
{
if (_loggedCandidates)
{
continue;
}
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(35, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Shiny probe: Steam does not know '");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text2);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'");
}
logger.LogInfo(val);
}
continue;
}
Settle(achieved, "Steam name '" + text2 + "'");
return;
}
_loggedCandidates = true;
}
catch (Exception ex)
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(30, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Shiny ownership probe failed: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
}
logger.LogWarning(val2);
}
}
}
private static void Settle(bool achieved, string via)
{
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00c2: Expected O, but got Unknown
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Expected O, but got Unknown
bool owned = Owned;
_resolved = true;
_confirmed = achieved;
try
{
if (achieved)
{
PlayerPrefs.SetInt("smolmods_shinyOwnedConfirmed", 1);
}
else
{
PlayerPrefs.DeleteKey("smolmods_shinyOwnedConfirmed");
}
PlayerPrefs.Save();
}
catch
{
}
ManualLogSource logger = Plugin.Logger;
bool flag = default(bool);
if (logger != null)
{
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(36, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Shiny achievement ownership: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(achieved ? "CONFIRMED" : "not owned");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" (via ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(via);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(")");
}
logger.LogInfo(val);
}
if (Owned == owned)
{
return;
}
try
{
ShinyOwnership.Changed?.Invoke();
}
catch (Exception ex)
{
logger = Plugin.Logger;
if (logger != null)
{
BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(32, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Shiny ownership handler failed: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message);
}
logger.LogWarning(val2);
}
}
}
}
internal static class ShinyPalette
{
private static bool[] _flags;
private static bool _attempted;
internal static bool FlagsKnown
{
get
{
EnsureRead();
return _flags != null;
}
}
internal static bool IsShiny(int index)
{
EnsureRead();
if (_flags != null && index >= 0 && index < _flags.Length)
{
return _flags[index];
}
return false;
}
private static void EnsureRead()
{
if (!_attempted)
{
PlayerLookSet lookSet = PlayerPalette.LookSet;
if (!((Object)(object)lookSet == (Object)null))
{
_attempted = true;
ReadShinyFlags(lookSet);
}
}
}
private unsafe static void ReadShinyFlags(PlayerLookSet set)
{
//IL_0257: Unknown result type (might be due to invalid IL or missing references)
//IL_025e: Expected O, but got Unknown
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: Unknown result type (might be due to invalid IL or missing references)
//IL_003f: 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_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Expected O, but got Unknown
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0133: Unknown result type (might be due to invalid IL or missing references)
//IL_0152: Unknown result type (might be due to invalid IL or missing references)
//IL_0171: Unknown result type (might be due to invalid IL or missing references)
//IL_01fb: Unknown result type (might be due to invalid IL or missing references)
//IL_0202: Expected O, but got Unknown
_flags = null;
bool flag = default(bool);
try
{
Il2CppStructArray<LookColor> colors = set.colors;
int length = ((Il2CppArrayBase<LookColor>)(object)colors).Length;
byte* ptr = (byte*)(void*)((Il2CppObjectBase)colors).Pointer + 32;
ManualLogSource logger;
for (int i = 0; i < Math.Min(4, length); i++)
{
float* ptr2 = (float*)(ptr + i * 24);
Color color = set.GetColor(i);
if (!(Math.Abs(*ptr2 - color.r) > 0.005f) && !(Math.Abs(ptr2[1] - color.g) > 0.005f) && !(Math.Abs(ptr2[2] - color.b) > 0.005f))
{
continue;
}
logger = Plugin.Logger;
if (logger != null)
{
BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(85, 7, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("LookColor raw layout mismatch at #");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(i);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": raw=(");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(*ptr2, "F2");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(",");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(ptr2[1], "F2");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(",");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(ptr2[2], "F2");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(") ");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("GetColor=(");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(color.r, "F2");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(",");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(color.g, "F2");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(",");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(color.b, "F2");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(") — shiny detection disabled");
}
logger.LogWarning(val);
}
return;
}
bool[] array = new bool[length];
int num = 0;
for (int j = 0; j < length; j++)
{
array[j] = (ptr + j * 24)[20] != 0;
if (array[j])
{
num++;
}
}
_flags = array;
logger = Plugin.Logger;
if (logger != null)
{
BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(34, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Shiny flags: ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(num);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" of ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<int>(length);
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" colors are shiny");
}
logger.LogInfo(val2);
}
}
catch (Exception ex)
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(24, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Shiny flag read failed: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
}
logger.LogWarning(val);
}
}
}
}
[HarmonyPatch]
internal static class SpeechlessDrive
{
private sealed class RemoteState
{
internal float Target;
internal float Level;
}
private const byte Subtype = 3;
private const float RemoteRate = 0.5f;
private static float _local;
private static readonly Dictionary<ulong, RemoteState> Remotes = new Dictionary<ulong, RemoteState>();
private static readonly Dictionary<int, (ulong netId, byte level)> HostStates = new Dictionary<int, (ulong, byte)>();
private static bool _dirty;
private static float _nextSend;
internal static float LocalLevel => _local;
internal static void Register()
{
ModChannel.Register((byte)3, (Action<int, byte[]>)OnServerFrame, (Action<byte[]>)OnClientFrame);
ModChannel.PeerHello += OnPeerHello;
ModChannel.PeerLeft += OnPeerLeft;
ModChannel.SessionReset += OnSessionReset;
ModSettingsApi.AddTicker((Action)Tick);
}
internal static void SetLocalLevel(float level)
{
level = Mathf.Clamp01(level);
if (!Mathf.Approximately(_local, level))
{
_local = level;
_dirty = true;
}
}
private static void Tick()
{
if (Remotes.Count > 0)
{
float num = Time.unscaledDeltaTime * 0.5f;
List<ulong> list = null;
foreach (KeyValuePair<ulong, RemoteState> remote in Remotes)
{
remote.Value.Level = Mathf.MoveTowards(remote.Value.Level, remote.Value.Target, num);
if (remote.Value.Target <= 0f && remote.Value.Level <= 0f)
{
(list ?? (list = new List<ulong>())).Add(remote.Key);
}
}
if (list != null)
{
foreach (ulong item in list)
{
Remotes.Remove(item);
}
}
}
ModChannel.Tick();
PushState();
Apply();
}
private static void PushState()
{
if (!_dirty || Time.unscaledTime < _nextSend)
{
return;
}
ulong num = NetIds.LocalNetId();
if (num != 0L)
{
_dirty = false;
_nextSend = Time.unscaledTime + 0.25f;
byte level = (byte)Mathf.RoundToInt(_local * 100f);
if (ModChannel.IsServer)
{
ModChannel.Broadcast((byte)3, Body(level, num), -1);
}
else
{
ModChannel.SendToHost((byte)3, Body(level, num));
}
}
}
private static void Apply()
{
if (_local <= 0f && Remotes.Count == 0)
{
return;
}
List<PlayerCharacter> allPlayerCharacters = PlayerCharacter.allPlayerCharacters;
if (allPlayerCharacters == null)
{
return;
}
for (int i = 0; i < allPlayerCharacters.Count; i++)
{
PlayerCharacter val = allPlayerCharacters[i];
if ((Object)(object)val == (Object)null)
{
continue;
}
float num = LevelFor(val);
if (num <= 0f)
{
continue;
}
try
{
PlayerLooks looks = val.looks;
if (looks != null)
{
looks.SetSpeechlessness(Mathf.Max(num, GameLevel(val)));
}
}
catch
{
}
}
}
private static float GameLevel(PlayerCharacter pc)
{
try
{
PlayerSpeechless speechless = pc.speechless;
return (speechless != null) ? speechless.speechlessness : 0f;
}
catch
{
return 0f;
}
}
private static float LevelFor(PlayerCharacter pc)
{
try
{
if (((NetworkBehaviour)pc).isLocalPlayer)
{
return _local;
}
if (Remotes.Count == 0)
{
return 0f;
}
ulong num = 0uL;
try
{
num = ((NetworkBehaviour)pc).netId;
}
catch
{
}
if (num != 0L && Remotes.TryGetValue(num, out var value))
{
return value.Level;
}
}
catch
{
}
return 0f;
}
[HarmonyPatch(typeof(PlayerLooks), "SetSpeechlessness")]
[HarmonyPrefix]
private static void SetSpeechlessness_Prefix(PlayerLooks __instance, ref float speechlessness)
{
try
{
if (_local <= 0f && Remotes.Count == 0)
{
return;
}
PlayerCharacter playerCharacter = __instance.playerCharacter;
if (!((Object)(object)playerCharacter == (Object)null))
{
float num = LevelFor(playerCharacter);
if (num > speechlessness)
{
speechlessness = num;
}
}
}
catch
{
}
}
private static byte[] Body(byte level, ulong netId)
{
byte[] array = new byte[9] { level, 0, 0, 0, 0, 0, 0, 0, 0 };
for (int i = 0; i < 8; i++)
{
array[1 + i] = (byte)(netId >> 8 * i);
}
return array;
}
private static void OnServerFrame(int connId, byte[] body)
{
if (body.Length >= 1)
{
byte b = body[0];
ulong num = ModChannel.NetIdOf(connId);
SetRemote(num, b);
if (connId > 0)
{
HostStates[connId] = (num, b);
}
ModChannel.Broadcast((byte)3, Body(b, num), connId);
}
}
private static void OnClientFrame(byte[] body)
{
if (body.Length >= 9)
{
ulong num = 0uL;
for (int i = 0; i < 8; i++)
{
num |= (ulong)body[1 + i] << 8 * i;
}
SetRemote(num, body[0]);
}
}
private static void SetRemote(ulong netId, byte level)
{
if (netId != 0L)
{
float num = Mathf.Clamp01((float)(int)level / 100f);
if (Remotes.TryGetValue(netId, out var value))
{
value.Target = num;
}
else if (num > 0f)
{
Remotes[netId] = new RemoteState
{
Target = num,
Level = 0f
};
}
}
}
private static void OnPeerHello(int connId)
{
if (connId < 0)
{
_dirty = true;
return;
}
ulong num = NetIds.LocalNetId();
if (num != 0L)
{
ModChannel.SendToConnection(connId, (byte)3, Body((byte)Mathf.RoundToInt(_local * 100f), num));
}
foreach (KeyValuePair<int, (ulong, byte)> hostState in HostStates)
{
if (hostState.Key != connId && hostState.Value.Item1 != 0L)
{
ModChannel.SendToConnection(connId, (byte)3, Body(hostState.Value.Item2, hostState.Value.Item1));
}
}
}
private static void OnPeerLeft(int connId)
{
if (HostStates.TryGetValue(connId, out (ulong, byte) value))
{
HostStates.Remove(connId);
if (value.Item1 != 0L)
{
SetRemote(value.Item1, 0);
ModChannel.Broadcast((byte)3, Body(0, value.Item1), -1);
}
}
}
private static void OnSessionReset()
{
HostStates.Clear();
Remotes.Clear();
_dirty = true;
}
}
internal static class SpeechlessUnlock
{
private const string LatchKey = "smolmods_endingOwnedConfirmed";
private static bool _resolved;
private static bool _confirmed;
private static float _nextProbeAt = 5f;
private static bool _fetchAsked;
internal static bool Owned
{
get
{
if (!_confirmed)
{
if (!_resolved)
{
return PlayerPrefs.GetInt("smolmods_endingOwnedConfirmed", 0) == 1;
}
return false;
}
return true;
}
}
internal static bool Resolved => _resolved;
internal static event Action Changed;
internal static void Register()
{
ModSettingsApi.AddTicker((Action)Tick);
}
private static void Tick()
{
if (!_resolved && !(Time.unscaledTime < _nextProbeAt))
{
_nextProbeAt = Time.unscaledTime + 30f;
Probe();
}
}
private static EPlatformAchievement[] Handles()
{
try
{
return (EPlatformAchievement[])(object)new EPlatformAchievement[2]
{
BWAchievements.Ending1,
BWAchievements.Ending2
};
}
catch
{
return null;
}
}
private static bool GameSaysUnlocked()
{
try
{
AbstractPlatformAchievements achievements = AbstractPlatformManager<PlatformManager>.Achievements;
EPlatformAchievement[] array = Handles();
if (achievements == null || array == null)
{
return false;
}
EPlatformAchievement[] array2 = array;
foreach (EPlatformAchievement val in array2)
{
if (val != null && achievements.IsAchievementUnlocked(val))
{
return true;
}
}
if (!_fetchAsked)
{
_fetchAsked = true;
try
{
achievements.AsyncFetchAchievements();
}
catch
{
}
}
}
catch
{
}
return false;
}
private static List<string> SteamNames()
{
List<string> list = new List<string>();
EPlatformAchievement[] array = Handles();
if (array == null)
{
return list;
}
EPlatformAchievement[] array2 = array;
foreach (EPlatformAchievement val in array2)
{
if (val == null)
{
continue;
}
string text = null;
try
{
text = val.SteamStatAPIName;
if (string.IsNullOrEmpty(text))
{
text = val.StorageName;
}
if (string.IsNullOrEmpty(text))
{
text = val.Name;
}
}
catch
{
}
if (string.IsNullOrEmpty(text))
{
continue;
}
list.Add(text);
try
{
string text2 = Encoding.UTF8.GetString(Convert.FromBase64String(text));
if (!string.IsNullOrEmpty(text2) && text2 != text)
{
list.Add(text2);
}
}
catch
{
}
}
return list;
}
private static void Probe()
{
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
//IL_00b5: Expected O, but got Unknown
try
{
if (GameSaysUnlocked())
{
Settle(achieved: true, "game achievement cache");
return;
}
List<string> list = SteamNames();
if (list.Count == 0)
{
return;
}
try
{
SteamUserStats.RequestCurrentStats();
}
catch
{
}
bool flag = false;
bool flag2 = default(bool);
uint num = default(uint);
foreach (string item in list)
{
if (SteamUserStats.GetAchievementAndUnlockTime(item, ref flag2, ref num))
{
flag = true;
if (flag2)
{
Settle(achieved: true, "Steam name '" + item + "'");
return;
}
}
}
if (flag)
{
Settle(achieved: false, "Steam (no ending achieved)");
}
}
catch (Exception ex)
{
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
bool flag3 = default(bool);
BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(31, 1, ref flag3);
if (flag3)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Ending ownership probe failed: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
}
logger.LogWarning(val);
}
}
}
private static void Settle(bool achieved, string via)
{
//IL_0044: Unknown result type (might be due to invalid IL or missing references)
//IL_004a: Expected O, but got Unknown
bool owned = Owned;
_resolved = true;
_confirmed = achieved;
try
{
if (achieved)
{
PlayerPrefs.SetInt("smolmods_endingOwnedConfirmed", 1);
}
else
{
PlayerPrefs.DeleteKey("smolmods_endingOwnedConfirmed");
}
PlayerPrefs.Save();
}
catch
{
}
ManualLogSource logger = Plugin.Logger;
if (logger != null)
{
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(50, 3, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Ending achievement ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(achieved ? "confirmed" : "not owned");
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" via ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(via);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" — _Speechlessness colour ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(achieved ? "unlocked" : "hidden");
}
logger.LogInfo(val);
}
if (Owned != owned)
{
try
{
SpeechlessUnlock.Changed?.Invoke();
}
catch
{
}
}
}
}
internal static class TorsoHudRow
{
private const string ClaimId = "colorself.torsohud";
private static ModRowDef _row;
private static bool _flipping;
internal static void Register()
{
_row = ModSettingsApi.AddArrayRow(305, "Torso HUD color", "settings_mod_torsoHud", 1, new int[2] { 0, 1 }, (Func<int, string>)((int v) => (v != 1) ? "Off" : "On"), (Action<int>)delegate(int v)
{
if (!_flipping)
{
if (v == 1)
{
HudTintApi.Claim("colorself.torsohud", (Func<Color?>)TorsoTint, (Action)OnPreempted);
}
else
{
HudTintApi.Release("colorself.torsohud");
}
}
}, (Func<int, Color?>)null, false, false);
}
private static void OnPreempted()
{
_flipping = true;
try
{
_row.SetValue(0, true);
ModSettingsApi.RefreshRows();
}
finally
{
_flipping = false;
}
}
private static Color? TorsoTint()
{
try
{
int num = default(int);
int num2 = default(int);
int num3 = default(int);
if (PlayerPalette.TryGetActualLook(ref num, ref num2, ref num3) && num2 >= 0)
{
return PlayerPalette.PaletteDisplayColor(num2);
}
return PlayerPalette.PaletteDisplayColor(PlayerColorFeature.TorsoRowValue);
}
catch
{
return null;
}
}
}
}