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 BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using ExitGames.Client.Photon;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using Photon.Realtime;
using QuickWardrobe.Game;
using QuickWardrobe.Net;
using QuickWardrobe.Profiles;
using QuickWardrobe.UI;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.UI;
using Zorro.Core;
[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("QuickWardrobe")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("QuickWardrobe")]
[assembly: AssemblyTitle("QuickWardrobe")]
[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 QuickWardrobe
{
public enum TransitionMode
{
Smoke,
Instant
}
[BepInPlugin("QuickWardrobe", "QuickWardrobe", "1.0.0")]
public class Plugin : BaseUnityPlugin
{
public const string PluginGuid = "QuickWardrobe";
public const string PluginName = "QuickWardrobe";
public const string PluginVersion = "1.0.0";
internal static ManualLogSource Log;
internal static ConfigEntry<int> SlotCount;
internal static ConfigEntry<bool> ConfirmOverwrite;
internal static ConfigEntry<TransitionMode> Transition;
internal static ConfigEntry<float> SmokeLeadIn;
internal static ConfigEntry<float> SmokeMinDuration;
internal static ConfigEntry<int> FramesBetweenChanges;
internal static ConfigEntry<bool> SyncSmokeToOthers;
internal static ConfigEntry<bool> ShowSmokeFromOthers;
internal static ConfigEntry<float> TabOffsetX;
internal static ConfigEntry<float> TabOffsetY;
internal static ConfigEntry<float> TabScale;
internal static ConfigEntry<float> TabSpacing;
internal static ConfigEntry<bool> VerboseLogging;
internal static ProfileStore Store;
private void Awake()
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Expected O, but got Unknown
//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
//IL_00b5: Expected O, but got Unknown
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
//IL_00f2: Expected O, but got Unknown
//IL_011a: Unknown result type (might be due to invalid IL or missing references)
//IL_0124: Expected O, but got Unknown
//IL_01df: Unknown result type (might be due to invalid IL or missing references)
//IL_01e9: Expected O, but got Unknown
//IL_021c: Unknown result type (might be due to invalid IL or missing references)
//IL_0226: Expected O, but got Unknown
//IL_0278: Unknown result type (might be due to invalid IL or missing references)
//IL_027d: Unknown result type (might be due to invalid IL or missing references)
//IL_0285: Unknown result type (might be due to invalid IL or missing references)
//IL_028b: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
SlotCount = ((BaseUnityPlugin)this).Config.Bind<int>("General", "SlotCount", 5, new ConfigDescription("Number of profile slots shown next to the passport.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 9), Array.Empty<object>()));
ConfirmOverwrite = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ConfirmOverwrite", true, "Ask for confirmation before overwriting or clearing a slot that already holds a profile.");
Transition = ((BaseUnityPlugin)this).Config.Bind<TransitionMode>("Transition", "Mode", TransitionMode.Smoke, "Smoke: play the game's own spawn 'poof' around your character while the outfit changes. Instant: no effect.\nBoth modes change cosmetics one slot at a time through the game's own passport logic.");
SmokeLeadIn = ((BaseUnityPlugin)this).Config.Bind<float>("Transition", "SmokeLeadInSeconds", 0.12f, new ConfigDescription("Delay between the poof starting and the first cosmetic change, so the change happens inside the smoke.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>()));
SmokeMinDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Transition", "SmokeMinDurationSeconds", 0.6f, new ConfigDescription("Minimum length of the whole Smoke transition. Profile buttons ignore clicks until it finishes.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>()));
FramesBetweenChanges = ((BaseUnityPlugin)this).Config.Bind<int>("Transition", "FramesBetweenChanges", 1, new ConfigDescription("Frames to wait between two cosmetic changes (both modes).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 10), Array.Empty<object>()));
SyncSmokeToOthers = ((BaseUnityPlugin)this).Config.Bind<bool>("Multiplayer", "SyncSmokeToOthers", true, "Tell other players (who also have QuickWardrobe) to show the poof on your character. Players without the mod simply ignore it.");
ShowSmokeFromOthers = ((BaseUnityPlugin)this).Config.Bind<bool>("Multiplayer", "ShowSmokeFromOthers", true, "Show the poof when another QuickWardrobe user applies a profile.");
TabOffsetX = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "TabOffsetX", 30f, "Gap between the passport page's left edge and the profile tabs (passport UI units).");
TabOffsetY = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "TabOffsetY", 0f, "Vertical offset of the profile tabs relative to the passport page's centre.");
TabScale = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "TabScale", 0.8f, new ConfigDescription("Scale of each profile tab (1 = same size as a cosmetic button).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.4f, 1.5f), Array.Empty<object>()));
TabSpacing = ((BaseUnityPlugin)this).Config.Bind<float>("UI", "TabSpacing", 54f, new ConfigDescription("Vertical distance between tabs (passport UI units).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 120f), Array.Empty<object>()));
VerboseLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseLogging", false, "Log which game method was used for every slot change.");
Store = new ProfileStore(Path.Combine(Paths.ConfigPath, "QuickWardrobe", "profiles.json"));
Store.Load();
GameObject val = new GameObject("QuickWardrobe")
{
hideFlags = (HideFlags)61
};
Object.DontDestroyOnLoad((Object)val);
val.AddComponent<WardrobeRunner>();
Log.LogInfo((object)("Loaded. Profiles file: " + Store.FilePath));
}
}
internal sealed class WardrobeRunner : MonoBehaviour
{
private PassportProfileTabs tabs;
private int uiErrorCount;
internal static WardrobeRunner Instance { get; private set; }
internal ProfileApplier Applier { get; private set; }
private void Awake()
{
Instance = this;
Applier = new ProfileApplier((MonoBehaviour)(object)this);
tabs = new PassportProfileTabs(Applier, Plugin.Store);
SmokeSync.Register();
}
private void OnDestroy()
{
SmokeSync.Unregister();
if ((Object)(object)Instance == (Object)(object)this)
{
Instance = null;
}
}
private void Update()
{
if (uiErrorCount >= 5)
{
return;
}
try
{
tabs.Tick();
}
catch (Exception ex)
{
uiErrorCount++;
Plugin.Log.LogError((object)("Passport profile tabs error: " + ex));
if (uiErrorCount >= 5)
{
Plugin.Log.LogError((object)"Too many UI errors; profile tabs disabled for this session.");
}
}
}
}
}
namespace QuickWardrobe.UI
{
internal sealed class PassportProfileTabs
{
private sealed class SlotView
{
internal int Slot;
internal RectTransform Rect;
internal Image Border;
internal TextMeshProUGUI Label;
}
private const float CosmeticButtonSize = 60f;
private readonly ProfileApplier applier;
private readonly ProfileStore store;
private PassportManager boundManager;
private bool buildFailed;
private RectTransform root;
private readonly List<SlotView> views = new List<SlotView>();
private TextMeshProUGUI status;
private RectTransform confirmPanel;
private TextMeshProUGUI confirmText;
private Action confirmAction;
private float statusUntil;
private float nextRefresh;
private int builtSlotCount;
private TMP_FontAsset font;
private Color textColor = new Color(0.2f, 0.16f, 0.12f);
private Color activeBorder = new Color(0.9f, 0.45f, 0.1f);
private Color inactiveBorder = new Color(0.35f, 0.3f, 0.25f);
private Color paper = new Color(0.96f, 0.93f, 0.85f);
internal PassportProfileTabs(ProfileApplier applier, ProfileStore store)
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//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_004f: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
this.applier = applier;
this.store = store;
}
internal void Tick()
{
PassportManager instance = PassportManager.instance;
if ((Object)(object)instance == (Object)null)
{
Unbind();
return;
}
if ((Object)(object)instance != (Object)(object)boundManager || builtSlotCount != Plugin.SlotCount.Value)
{
Unbind();
boundManager = instance;
}
if ((Object)(object)root == (Object)null)
{
if (buildFailed)
{
return;
}
Build(instance);
if ((Object)(object)root == (Object)null)
{
return;
}
}
bool isOpen = ((MenuWindow)instance).isOpen;
if (((Component)root).gameObject.activeSelf != isOpen)
{
((Component)root).gameObject.SetActive(isOpen);
HideConfirm();
if (isOpen)
{
nextRefresh = 0f;
}
}
if (isOpen)
{
float unscaledTime = Time.unscaledTime;
if (unscaledTime >= nextRefresh)
{
nextRefresh = unscaledTime + 0.25f;
Refresh();
}
if ((Object)(object)status != (Object)null && ((TMP_Text)status).text.Length > 0 && unscaledTime >= statusUntil)
{
((TMP_Text)status).text = "";
}
}
}
private void Unbind()
{
if ((Object)(object)root != (Object)null)
{
Object.Destroy((Object)(object)((Component)root).gameObject);
}
root = null;
views.Clear();
status = null;
confirmPanel = null;
confirmText = null;
confirmAction = null;
boundManager = null;
buildFailed = false;
}
private static RectTransform FindPassportPage(PassportManager pm)
{
PassportButton[] buttons = pm.buttons;
object obj;
if (buttons == null)
{
obj = null;
}
else
{
PassportButton? obj2 = ((IEnumerable<PassportButton>)buttons).FirstOrDefault((Func<PassportButton, bool>)((PassportButton b) => (Object)(object)b != (Object)null));
obj = ((obj2 != null) ? ((Component)obj2).transform : null);
}
Transform val = (Transform)obj;
if ((Object)(object)val == (Object)null || (Object)(object)pm.uiObject == (Object)null)
{
return null;
}
Transform val2 = pm.uiObject.transform.Find("Canvas/Panel/Panel");
if ((Object)(object)val2 != (Object)null && val.IsChildOf(val2))
{
return (RectTransform)(object)((val2 is RectTransform) ? val2 : null);
}
Transform val3 = null;
Transform parent = val.parent;
while ((Object)(object)parent != (Object)null && (Object)(object)((Component)parent).GetComponent<Canvas>() == (Object)null)
{
if ((Object)(object)((Component)parent).GetComponent<Mask>() != (Object)null)
{
val3 = parent;
}
parent = parent.parent;
}
if ((Object)(object)val3 != (Object)null)
{
Transform parent2 = val3.parent;
RectTransform val4 = (RectTransform)(object)((parent2 is RectTransform) ? parent2 : null);
if (val4 != null)
{
Plugin.Log.LogWarning((object)("Passport page not at the expected path; attaching tabs to '" + ((Object)val4).name + "' instead."));
return val4;
}
}
return null;
}
private void Build(PassportManager pm)
{
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_0098: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_012b: Unknown result type (might be due to invalid IL or missing references)
//IL_0132: Expected O, but got Unknown
//IL_013a: Unknown result type (might be due to invalid IL or missing references)
//IL_0144: Expected O, but got Unknown
//IL_016e: Unknown result type (might be due to invalid IL or missing references)
//IL_0175: Unknown result type (might be due to invalid IL or missing references)
//IL_018c: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Unknown result type (might be due to invalid IL or missing references)
//IL_0107: 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: Unknown result type (might be due to invalid IL or missing references)
//IL_0214: Unknown result type (might be due to invalid IL or missing references)
//IL_0229: Unknown result type (might be due to invalid IL or missing references)
//IL_023d: Unknown result type (might be due to invalid IL or missing references)
builtSlotCount = Plugin.SlotCount.Value;
RectTransform val = FindPassportPage(pm);
PassportButton val2 = pm.buttons?.FirstOrDefault((Func<PassportButton, bool>)((PassportButton b) => (Object)(object)b != (Object)null));
if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
{
buildFailed = true;
Plugin.Log.LogWarning((object)"Could not locate the passport page; profile tabs are unavailable in this scene.");
return;
}
if ((Object)(object)pm.nameText != (Object)null)
{
font = ((TMP_Text)pm.nameText).font;
textColor = ((Graphic)pm.nameText).color;
}
activeBorder = pm.activeBorderColor;
inactiveBorder = pm.inactiveBorderColor;
Transform obj = ((Transform)val).Find("BG");
Graphic val3 = ((obj != null) ? ((Component)obj).GetComponent<Graphic>() : null);
if ((Object)(object)val3 != (Object)null)
{
paper = new Color(val3.color.r, val3.color.g, val3.color.b, 1f);
}
int num = builtSlotCount;
GameObject val4 = new GameObject("QuickWardrobe_ProfileTabs", new Type[1] { typeof(RectTransform) });
root = (RectTransform)val4.transform;
((Transform)root).SetParent((Transform)(object)val, false);
RectTransform obj2 = root;
RectTransform obj3 = root;
Vector2 val5 = default(Vector2);
((Vector2)(ref val5))..ctor(0f, 0.5f);
obj3.anchorMax = val5;
obj2.anchorMin = val5;
root.pivot = new Vector2(1f, 0.5f);
for (int num2 = 0; num2 < num; num2++)
{
views.Add(CreateSlot(val2, num2 + 1));
}
status = NewText((Transform)(object)root, "Status", 20f, (TextAlignmentOptions)260);
RectTransform rectTransform = ((TMP_Text)status).rectTransform;
((Vector2)(ref val5))..ctor(1f, 0f);
rectTransform.anchorMax = val5;
rectTransform.anchorMin = val5;
rectTransform.pivot = new Vector2(1f, 1f);
rectTransform.anchoredPosition = new Vector2(0f, -6f);
rectTransform.sizeDelta = new Vector2(300f, 80f);
((TMP_Text)status).text = "";
CreateConfirmPanel();
ApplyLayout();
val4.SetActive(false);
Plugin.Log.LogInfo((object)("Profile tabs attached to passport page '" + GetPath((Transform)(object)val) + "'."));
}
private SlotView CreateSlot(PassportButton template, int slot)
{
//IL_0112: Unknown result type (might be due to invalid IL or missing references)
//IL_0119: Expected O, but got Unknown
//IL_012e: Unknown result type (might be due to invalid IL or missing references)
//IL_0135: Unknown result type (might be due to invalid IL or missing references)
//IL_0148: Unknown result type (might be due to invalid IL or missing references)
//IL_015e: Unknown result type (might be due to invalid IL or missing references)
//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
//IL_00cf: Expected O, but got Unknown
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Expected O, but got Unknown
//IL_01a4: Unknown result type (might be due to invalid IL or missing references)
//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
GameObject val = Object.Instantiate<GameObject>(((Component)template).gameObject, (Transform)(object)root, false);
((Object)val).name = "ProfileButton" + slot;
val.SetActive(true);
PassportButton component = val.GetComponent<PassportButton>();
Image border = (((Object)(object)component != (Object)null) ? component.border : null);
if ((Object)(object)component != (Object)null)
{
if ((Object)(object)component.icon != (Object)null)
{
((Component)component.icon).gameObject.SetActive(false);
}
if ((Object)(object)component.lockedIcon != (Object)null)
{
((Component)component.lockedIcon).gameObject.SetActive(false);
}
((Behaviour)component).enabled = false;
}
Button component2 = val.GetComponent<Button>();
if ((Object)(object)component2 != (Object)null)
{
component2.onClick = new ButtonClickedEvent();
((UnityEvent)component2.onClick).AddListener((UnityAction)delegate
{
OnLeftClick(slot);
});
((Selectable)component2).interactable = true;
}
val.AddComponent<SlotClickRelay>().Init(slot, OnRightClick);
RectTransform val2 = (RectTransform)val.transform;
Vector2 val3 = default(Vector2);
((Vector2)(ref val3))..ctor(0.5f, 1f);
val2.anchorMax = val3;
val2.anchorMin = val3;
val2.pivot = new Vector2(0.5f, 0.5f);
val2.sizeDelta = new Vector2(60f, 60f);
Transform parent = val.transform.Find("Box") ?? val.transform;
TextMeshProUGUI val4 = NewText(parent, "Number", 34f, (TextAlignmentOptions)514);
((TMP_Text)val4).rectTransform.anchorMin = Vector2.zero;
((TMP_Text)val4).rectTransform.anchorMax = Vector2.one;
((TMP_Text)val4).rectTransform.sizeDelta = Vector2.zero;
((TMP_Text)val4).text = slot.ToString();
return new SlotView
{
Slot = slot,
Rect = val2,
Border = border,
Label = val4
};
}
private void CreateConfirmPanel()
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: Expected O, but got Unknown
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Expected O, but got Unknown
//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_007a: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_010c: Unknown result type (might be due to invalid IL or missing references)
//IL_0121: Unknown result type (might be due to invalid IL or missing references)
//IL_0136: Unknown result type (might be due to invalid IL or missing references)
//IL_014a: Unknown result type (might be due to invalid IL or missing references)
//IL_0161: Unknown result type (might be due to invalid IL or missing references)
//IL_0170: Unknown result type (might be due to invalid IL or missing references)
//IL_0193: Unknown result type (might be due to invalid IL or missing references)
//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject("Confirm", new Type[1] { typeof(RectTransform) });
confirmPanel = (RectTransform)val.transform;
((Transform)confirmPanel).SetParent((Transform)(object)root, false);
RectTransform obj = confirmPanel;
RectTransform obj2 = confirmPanel;
Vector2 val2 = default(Vector2);
((Vector2)(ref val2))..ctor(0f, 1f);
obj2.anchorMax = val2;
obj.anchorMin = val2;
confirmPanel.pivot = new Vector2(1f, 0.5f);
confirmPanel.sizeDelta = new Vector2(250f, 96f);
((Graphic)val.AddComponent<Image>()).color = paper;
Outline obj3 = val.AddComponent<Outline>();
((Shadow)obj3).effectColor = inactiveBorder;
((Shadow)obj3).effectDistance = new Vector2(2f, -2f);
confirmText = NewText((Transform)(object)confirmPanel, "Question", 22f, (TextAlignmentOptions)514);
RectTransform rectTransform = ((TMP_Text)confirmText).rectTransform;
rectTransform.anchorMin = new Vector2(0f, 0.5f);
rectTransform.anchorMax = new Vector2(1f, 1f);
rectTransform.offsetMin = new Vector2(8f, 0f);
rectTransform.offsetMax = new Vector2(-8f, -4f);
NewTextButton((Transform)(object)confirmPanel, "Confirm", activeBorder, new Vector2(0.27f, 0.27f), delegate
{
Action action = confirmAction;
HideConfirm();
action?.Invoke();
});
NewTextButton((Transform)(object)confirmPanel, "Cancel", inactiveBorder, new Vector2(0.73f, 0.27f), HideConfirm);
val.SetActive(false);
}
private void ApplyLayout()
{
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Unknown result type (might be due to invalid IL or missing references)
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
float value = Plugin.TabSpacing.Value;
float value2 = Plugin.TabScale.Value;
root.anchoredPosition = new Vector2(0f - Plugin.TabOffsetX.Value, Plugin.TabOffsetY.Value);
root.sizeDelta = new Vector2(60f * value2, value * (float)views.Count);
for (int i = 0; i < views.Count; i++)
{
views[i].Rect.anchoredPosition = new Vector2(0f, (0f - value) * ((float)i + 0.5f));
}
}
private void Refresh()
{
//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
//IL_0103: Unknown result type (might be due to invalid IL or missing references)
//IL_0123: Unknown result type (might be due to invalid IL or missing references)
//IL_0172: Unknown result type (might be due to invalid IL or missing references)
//IL_0161: Unknown result type (might be due to invalid IL or missing references)
//IL_0159: Unknown result type (might be due to invalid IL or missing references)
//IL_0187: Unknown result type (might be due to invalid IL or missing references)
ApplyLayout();
CharacterCustomizationData localData = CosmeticSlots.GetLocalData();
Customization customization = CosmeticSlots.GetCustomization();
int num = 0;
int lastAppliedSlot = store.LastAppliedSlot;
if (lastAppliedSlot > 0 && lastAppliedSlot <= views.Count && CosmeticSlots.IsWorn(store.Get(lastAppliedSlot), localData, customization))
{
num = lastAppliedSlot;
}
int num2 = 1;
while (num == 0 && num2 <= views.Count)
{
if (CosmeticSlots.IsWorn(store.Get(num2), localData, customization))
{
num = num2;
}
num2++;
}
float value = Plugin.TabScale.Value;
foreach (SlotView view in views)
{
bool flag = store.Get(view.Slot) == null;
bool flag2 = view.Slot == num;
((TMP_Text)view.Label).text = (flag ? $"{view.Slot}<size=55%> -</size>" : view.Slot.ToString());
Color color = textColor;
color.a = (flag ? 0.35f : 1f);
((Graphic)view.Label).color = color;
((TMP_Text)view.Label).fontStyle = (FontStyles)(flag2 ? 1 : 0);
if ((Object)(object)view.Border != (Object)null)
{
((Graphic)view.Border).color = (flag2 ? activeBorder : inactiveBorder);
}
((Transform)view.Rect).localScale = Vector3.one * (flag2 ? (value * 1.1f) : value);
}
}
private void ShowStatus(string text, float seconds = 3.5f)
{
if (!((Object)(object)status == (Object)null))
{
((TMP_Text)status).text = text;
statusUntil = Time.unscaledTime + seconds;
}
}
private void Ask(int slot, string question, Action onConfirm)
{
//IL_0039: 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)
if (!Plugin.ConfirmOverwrite.Value)
{
onConfirm();
return;
}
confirmAction = onConfirm;
((TMP_Text)confirmText).text = question;
float y = views[slot - 1].Rect.anchoredPosition.y;
confirmPanel.anchoredPosition = new Vector2(-12f, y);
((Component)confirmPanel).gameObject.SetActive(true);
}
private void HideConfirm()
{
confirmAction = null;
if ((Object)(object)confirmPanel != (Object)null)
{
((Component)confirmPanel).gameObject.SetActive(false);
}
}
private void OnLeftClick(int slot)
{
HideConfirm();
if (applier.IsBusy)
{
return;
}
CosmeticProfile cosmeticProfile = store.Get(slot);
if (cosmeticProfile == null)
{
ShowStatus($"Profile {slot} is empty.\nRight-click to save your current outfit.");
return;
}
ShowStatus($"Applying Profile {slot}...");
applier.Apply(cosmeticProfile, delegate(List<SlotResult> results)
{
store.MarkApplied(slot);
ShowStatus(Summarize(slot, results), 5f);
nextRefresh = 0f;
});
}
private void OnRightClick(int slot)
{
if (applier.IsBusy || slot < 1 || slot > views.Count)
{
return;
}
HideConfirm();
bool num = Keyboard.current != null && Keyboard.current.shiftKey.isPressed;
CosmeticProfile cosmeticProfile = store.Get(slot);
if (num)
{
if (cosmeticProfile == null)
{
ShowStatus($"Profile {slot} is already empty.");
return;
}
Ask(slot, $"Clear Profile {slot}?", delegate
{
ClearSlot(slot);
});
}
else if (cosmeticProfile != null)
{
Ask(slot, $"Overwrite Profile {slot}?", delegate
{
SaveSlot(slot);
});
}
else
{
SaveSlot(slot);
}
}
private void SaveSlot(int slot)
{
CosmeticProfile cosmeticProfile = store.SaveCurrent(slot);
ShowStatus((cosmeticProfile != null) ? $"Saved current outfit to Profile {slot}." : "Could not read your current cosmetics.");
if (cosmeticProfile != null)
{
Plugin.Log.LogInfo((object)$"Saved current cosmetics to slot {slot}.");
}
nextRefresh = 0f;
}
private void ClearSlot(int slot)
{
if (store.Clear(slot))
{
ShowStatus($"Profile {slot} cleared.");
}
nextRefresh = 0f;
}
private static string Summarize(int slot, List<SlotResult> results)
{
List<string> list = (from r in results
where r.Status == SlotStatus.Missing || r.Status == SlotStatus.Locked || r.Status == SlotStatus.Error
select string.Format("{0} {1}", r.Kind, (r.Status == SlotStatus.Missing) ? "missing" : ((r.Status == SlotStatus.Locked) ? "locked" : "failed"))).ToList();
if (list.Count == 0)
{
return $"Profile {slot} applied.";
}
return string.Format("Profile {0} applied.\nSkipped: {1}", slot, string.Join(", ", list));
}
private TextMeshProUGUI NewText(Transform parent, string name, float size, TextAlignmentOptions alignment)
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: 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)
GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
val.transform.SetParent(parent, false);
TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>();
if ((Object)(object)font != (Object)null)
{
((TMP_Text)val2).font = font;
}
((TMP_Text)val2).fontSize = size;
((TMP_Text)val2).alignment = alignment;
((Graphic)val2).color = textColor;
((Graphic)val2).raycastTarget = false;
((TMP_Text)val2).richText = true;
return val2;
}
private void NewTextButton(Transform parent, string caption, Color color, Vector2 anchor, Action onClick)
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Expected O, but got Unknown
//IL_003d: 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_0040: 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_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Expected O, but got Unknown
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject(caption, new Type[1] { typeof(RectTransform) });
RectTransform val2 = (RectTransform)val.transform;
((Transform)val2).SetParent(parent, false);
Vector2 anchorMin = (val2.anchorMax = anchor);
val2.anchorMin = anchorMin;
val2.sizeDelta = new Vector2(108f, 34f);
Image val4 = val.AddComponent<Image>();
((Graphic)val4).color = color;
Button obj = val.AddComponent<Button>();
((Selectable)obj).targetGraphic = (Graphic)(object)val4;
((UnityEvent)obj.onClick).AddListener((UnityAction)delegate
{
onClick();
});
TextMeshProUGUI obj2 = NewText((Transform)(object)val2, "Text", 20f, (TextAlignmentOptions)514);
((TMP_Text)obj2).rectTransform.anchorMin = Vector2.zero;
((TMP_Text)obj2).rectTransform.anchorMax = Vector2.one;
((TMP_Text)obj2).rectTransform.sizeDelta = Vector2.zero;
((Graphic)obj2).color = ((((Color)(ref color)).grayscale > 0.6f) ? textColor : Color.white);
((TMP_Text)obj2).text = caption;
}
private static string GetPath(Transform t)
{
string text = ((Object)t).name;
Transform parent = t.parent;
while ((Object)(object)parent != (Object)null)
{
text = ((Object)parent).name + "/" + text;
parent = parent.parent;
}
return text;
}
}
internal sealed class SlotClickRelay : MonoBehaviour, IPointerClickHandler, IEventSystemHandler
{
private int slot;
private Action<int> onRightClick;
internal void Init(int slotNumber, Action<int> rightClick)
{
slot = slotNumber;
onRightClick = rightClick;
}
public void OnPointerClick(PointerEventData eventData)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0007: Invalid comparison between Unknown and I4
if ((int)eventData.button == 1)
{
onRightClick?.Invoke(slot);
}
}
}
}
namespace QuickWardrobe.Profiles
{
[Serializable]
public class SavedCosmetic
{
public int index = -1;
public string name = "";
public bool IsSet => index >= 0;
}
[Serializable]
public class CosmeticSet
{
public SavedCosmetic skin = new SavedCosmetic();
public SavedCosmetic eyes = new SavedCosmetic();
public SavedCosmetic mouth = new SavedCosmetic();
public SavedCosmetic accessory = new SavedCosmetic();
public SavedCosmetic outfit = new SavedCosmetic();
public SavedCosmetic hat = new SavedCosmetic();
public SavedCosmetic sash = new SavedCosmetic();
public SavedCosmetic medal = new SavedCosmetic();
public SavedCosmetic Get(SlotKind kind)
{
return kind switch
{
SlotKind.Skin => skin,
SlotKind.Eyes => eyes,
SlotKind.Mouth => mouth,
SlotKind.Accessory => accessory,
SlotKind.Outfit => outfit,
SlotKind.Hat => hat,
SlotKind.Sash => sash,
SlotKind.Medal => medal,
_ => null,
};
}
public void Set(SlotKind kind, SavedCosmetic value)
{
switch (kind)
{
case SlotKind.Skin:
skin = value;
break;
case SlotKind.Eyes:
eyes = value;
break;
case SlotKind.Mouth:
mouth = value;
break;
case SlotKind.Accessory:
accessory = value;
break;
case SlotKind.Outfit:
outfit = value;
break;
case SlotKind.Hat:
hat = value;
break;
case SlotKind.Sash:
sash = value;
break;
case SlotKind.Medal:
medal = value;
break;
}
}
}
[Serializable]
public class CosmeticProfile
{
public int slot;
public string id = "";
public string name = "";
public string createdUtc = "";
public string modifiedUtc = "";
public CosmeticSet cosmetics = new CosmeticSet();
}
[Serializable]
public class ProfileFile
{
public int version = 1;
public int lastAppliedSlot;
public List<CosmeticProfile> profiles = new List<CosmeticProfile>();
}
internal sealed class ProfileStore
{
private ProfileFile data = new ProfileFile();
internal string FilePath { get; }
internal int LastAppliedSlot => data.lastAppliedSlot;
internal ProfileStore(string filePath)
{
FilePath = filePath;
}
internal void Load()
{
if (!File.Exists(FilePath))
{
data = new ProfileFile();
return;
}
try
{
data = JsonUtility.FromJson<ProfileFile>(File.ReadAllText(FilePath)) ?? new ProfileFile();
if (data.profiles == null)
{
data.profiles = new List<CosmeticProfile>();
}
data.profiles.RemoveAll((CosmeticProfile p) => p == null || p.slot <= 0);
foreach (CosmeticProfile profile in data.profiles)
{
if (profile.cosmetics == null)
{
profile.cosmetics = new CosmeticSet();
}
SlotKind[] applyOrder = CosmeticSlots.ApplyOrder;
foreach (SlotKind kind in applyOrder)
{
if (profile.cosmetics.Get(kind) == null)
{
profile.cosmetics.Set(kind, new SavedCosmetic());
}
}
}
}
catch (Exception ex)
{
string text = FilePath + ".broken-" + DateTime.Now.ToString("yyyyMMdd-HHmmss", CultureInfo.InvariantCulture);
Plugin.Log.LogError((object)("Could not read " + FilePath + " (" + ex.Message + "). Moving it to " + text + " and starting with empty profiles."));
try
{
File.Move(FilePath, text);
}
catch
{
}
data = new ProfileFile();
}
}
internal void Save()
{
try
{
Directory.CreateDirectory(Path.GetDirectoryName(FilePath));
string text = FilePath + ".tmp";
File.WriteAllText(text, JsonUtility.ToJson((object)data, true));
if (File.Exists(FilePath))
{
File.Delete(FilePath);
}
File.Move(text, FilePath);
}
catch (Exception arg)
{
Plugin.Log.LogError((object)$"Could not write {FilePath}: {arg}");
}
}
internal CosmeticProfile Get(int slot)
{
return data.profiles.Find((CosmeticProfile p) => p.slot == slot);
}
internal CosmeticProfile SaveCurrent(int slot)
{
CosmeticSet cosmeticSet = CosmeticSlots.CaptureCurrent();
if (cosmeticSet == null)
{
return null;
}
string text = DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture);
CosmeticProfile cosmeticProfile = Get(slot);
if (cosmeticProfile == null)
{
cosmeticProfile = new CosmeticProfile
{
slot = slot,
id = Guid.NewGuid().ToString("N"),
name = "Profile " + slot,
createdUtc = text
};
data.profiles.Add(cosmeticProfile);
data.profiles.Sort((CosmeticProfile a, CosmeticProfile b) => a.slot.CompareTo(b.slot));
}
cosmeticProfile.cosmetics = cosmeticSet;
cosmeticProfile.modifiedUtc = text;
Save();
return cosmeticProfile;
}
internal bool Clear(int slot)
{
if (data.profiles.RemoveAll((CosmeticProfile p) => p.slot == slot) == 0)
{
return false;
}
if (data.lastAppliedSlot == slot)
{
data.lastAppliedSlot = 0;
}
Save();
return true;
}
internal void MarkApplied(int slot)
{
if (data.lastAppliedSlot != slot)
{
data.lastAppliedSlot = slot;
Save();
}
}
}
}
namespace QuickWardrobe.Net
{
internal static class SmokeSync
{
internal const byte EventCode = 187;
private const string Magic = "QuickWardrobe.Smoke";
private const int ProtocolVersion = 1;
private const float MinInterval = 0.3f;
private static readonly Dictionary<int, float> lastReceived = new Dictionary<int, float>();
private static bool registered;
internal static void Register()
{
if (!registered && PhotonNetwork.NetworkingClient != null)
{
PhotonNetwork.NetworkingClient.EventReceived += OnEvent;
registered = true;
}
}
internal static void Unregister()
{
if (registered)
{
if (PhotonNetwork.NetworkingClient != null)
{
PhotonNetwork.NetworkingClient.EventReceived -= OnEvent;
}
registered = false;
}
}
internal static void Send()
{
//IL_003f: Unknown result type (might be due to invalid IL or missing references)
//IL_0044: 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_004b: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: Expected O, but got Unknown
if (PhotonNetwork.InRoom && !PhotonNetwork.OfflineMode && PhotonNetwork.CurrentRoom != null && PhotonNetwork.CurrentRoom.PlayerCount >= 2)
{
PhotonNetwork.RaiseEvent((byte)187, (object)new object[2] { "QuickWardrobe.Smoke", 1 }, new RaiseEventOptions
{
Receivers = (ReceiverGroup)0
}, SendOptions.SendReliable);
}
}
private static void OnEvent(EventData e)
{
if (e.Code != 187 || !(e.CustomData is object[] array) || array.Length < 1 || !(array[0] is string text) || text != "QuickWardrobe.Smoke" || !Plugin.ShowSmokeFromOthers.Value || PhotonNetwork.LocalPlayer == null || e.Sender == PhotonNetwork.LocalPlayer.ActorNumber)
{
return;
}
float unscaledTime = Time.unscaledTime;
if (!lastReceived.TryGetValue(e.Sender, out var value) || !(unscaledTime - value < 0.3f))
{
lastReceived[e.Sender] = unscaledTime;
Character character = default(Character);
if (PlayerHandler.TryGetCharacter(e.Sender, ref character))
{
Smoke.PlayOn(character);
}
}
}
}
}
namespace QuickWardrobe.Game
{
public enum SlotKind
{
Skin,
Eyes,
Mouth,
Accessory,
Outfit,
Hat,
Sash,
Medal
}
internal enum SlotStatus
{
Ok,
Unchanged,
NotSaved,
Missing,
Locked,
Error
}
internal struct SlotResult
{
internal SlotKind Kind;
internal SlotStatus Status;
internal string Detail;
internal bool Changed => Status == SlotStatus.Ok;
internal static SlotResult Of(SlotKind kind, SlotStatus status, string detail = null)
{
return new SlotResult
{
Kind = kind,
Status = status,
Detail = detail
};
}
public override string ToString()
{
string arg = Status switch
{
SlotStatus.Ok => "OK",
SlotStatus.Unchanged => "OK (already worn)",
SlotStatus.NotSaved => "not in profile - skipped",
SlotStatus.Missing => "MISSING - skipped",
SlotStatus.Locked => "LOCKED - skipped",
_ => "ERROR - skipped",
};
if (!string.IsNullOrEmpty(Detail))
{
return $"{Kind,-10}{arg} ({Detail})";
}
return $"{Kind,-10}{arg}";
}
}
internal static class CosmeticSlots
{
internal static readonly SlotKind[] ApplyOrder = new SlotKind[8]
{
SlotKind.Skin,
SlotKind.Eyes,
SlotKind.Mouth,
SlotKind.Accessory,
SlotKind.Outfit,
SlotKind.Hat,
SlotKind.Sash,
SlotKind.Medal
};
internal static Type ToGameType(SlotKind kind)
{
return (Type)(kind switch
{
SlotKind.Skin => 0,
SlotKind.Eyes => 20,
SlotKind.Mouth => 30,
SlotKind.Accessory => 10,
SlotKind.Outfit => 40,
SlotKind.Hat => 50,
SlotKind.Sash => 60,
_ => 70,
});
}
internal static Customization GetCustomization()
{
Customization instance = Singleton<Customization>.Instance;
if (!((Object)(object)instance != (Object)null))
{
return null;
}
return instance;
}
internal static CharacterCustomizationData GetLocalData()
{
try
{
if (PhotonNetwork.LocalPlayer == null)
{
return null;
}
PersistentPlayerDataService service = GameHandler.GetService<PersistentPlayerDataService>();
return (service == null) ? null : service.GetPlayerData(PhotonNetwork.LocalPlayer)?.customizationData;
}
catch (Exception)
{
return null;
}
}
internal static int GetIndex(CharacterCustomizationData d, SlotKind kind)
{
return kind switch
{
SlotKind.Skin => d.currentSkin,
SlotKind.Eyes => d.currentEyes,
SlotKind.Mouth => d.currentMouth,
SlotKind.Accessory => d.currentAccessory,
SlotKind.Outfit => d.currentOutfit,
SlotKind.Hat => d.currentHat,
SlotKind.Sash => d.currentSash,
_ => d.currentMedal,
};
}
internal static CosmeticSet CaptureCurrent()
{
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
CharacterCustomizationData localData = GetLocalData();
Customization customization = GetCustomization();
if (localData == null || (Object)(object)customization == (Object)null)
{
return null;
}
CosmeticSet cosmeticSet = new CosmeticSet();
SlotKind[] applyOrder = ApplyOrder;
foreach (SlotKind kind in applyOrder)
{
int index = GetIndex(localData, kind);
CustomizationOption[] list = customization.GetList(ToGameType(kind));
string name = ((list != null && index >= 0 && index < list.Length && (Object)(object)list[index] != (Object)null) ? ((Object)list[index]).name : "");
cosmeticSet.Set(kind, new SavedCosmetic
{
index = index,
name = name
});
}
return cosmeticSet;
}
internal static int Resolve(CustomizationOption[] list, SavedCosmetic saved)
{
if (list == null || saved == null || !saved.IsSet)
{
return -1;
}
bool flag = saved.index < list.Length && (Object)(object)list[saved.index] != (Object)null;
if (string.IsNullOrEmpty(saved.name))
{
if (!flag)
{
return -1;
}
return saved.index;
}
if (flag && ((Object)list[saved.index]).name == saved.name)
{
return saved.index;
}
for (int i = 0; i < list.Length; i++)
{
if ((Object)(object)list[i] != (Object)null && ((Object)list[i]).name == saved.name)
{
return i;
}
}
return -1;
}
internal static bool IsSelectable(SlotKind kind, CustomizationOption[] list, int index)
{
if (kind == SlotKind.Medal)
{
AchievementManager instance = Singleton<AchievementManager>.Instance;
if ((Object)(object)instance == (Object)null || !instance.AllSixtyFourAchievementsUnlocked())
{
return false;
}
PassportManager instance2 = PassportManager.instance;
CustomizationOption val = (((Object)(object)instance2 != (Object)null && (Object)(object)instance2.medalOption != (Object)null) ? instance2.medalOption : list[index]);
if (!((Object)(object)val == (Object)null))
{
return !val.IsLocked;
}
return true;
}
return !list[index].IsLocked;
}
internal static SlotResult ApplyOne(SlotKind kind, SavedCosmetic saved)
{
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
try
{
if (saved == null || !saved.IsSet)
{
return SlotResult.Of(kind, SlotStatus.NotSaved);
}
Customization customization = GetCustomization();
CharacterCustomizationData localData = GetLocalData();
if ((Object)(object)customization == (Object)null || localData == null)
{
return SlotResult.Of(kind, SlotStatus.Error, "customization system not loaded");
}
CustomizationOption[] list = customization.GetList(ToGameType(kind));
int num = Resolve(list, saved);
if (num < 0)
{
return SlotResult.Of(kind, SlotStatus.Missing, $"saved #{saved.index} '{saved.name}'");
}
string detail = ((num != saved.index) ? $"found '{saved.name}' at #{num}" : null);
if (GetIndex(localData, kind) == num)
{
return SlotResult.Of(kind, SlotStatus.Unchanged, detail);
}
if (!IsSelectable(kind, list, num))
{
return SlotResult.Of(kind, SlotStatus.Locked, ((Object)(object)list[num] != (Object)null) ? ((Object)list[num]).name : null);
}
string text = InvokeGame(kind, list[num], num);
CharacterCustomizationData localData2 = GetLocalData();
if (localData2 == null || GetIndex(localData2, kind) != num)
{
return SlotResult.Of(kind, SlotStatus.Error, "game did not accept the change");
}
if (Plugin.VerboseLogging.Value)
{
Plugin.Log.LogInfo((object)$"{kind} -> #{num} '{((Object)list[num]).name}' via {text}");
}
return SlotResult.Of(kind, SlotStatus.Ok, detail);
}
catch (Exception ex)
{
Plugin.Log.LogError((object)$"Applying {kind} failed: {ex}");
return SlotResult.Of(kind, SlotStatus.Error, ex.GetType().Name);
}
}
private static string InvokeGame(SlotKind kind, CustomizationOption option, int index)
{
PassportManager instance = PassportManager.instance;
if ((Object)(object)instance != (Object)null && (Object)(object)Character.localCharacter != (Object)null && (Object)(object)option != (Object)null)
{
if (kind == SlotKind.Medal)
{
instance.SetOption(((Object)(object)instance.medalOption != (Object)null) ? instance.medalOption : option, 0);
}
else
{
instance.SetOption(option, index);
}
return "PassportManager.SetOption";
}
switch (kind)
{
case SlotKind.Skin:
CharacterCustomization.SetCharacterSkinColor(index);
break;
case SlotKind.Eyes:
CharacterCustomization.SetCharacterEyes(index);
break;
case SlotKind.Mouth:
CharacterCustomization.SetCharacterMouth(index);
break;
case SlotKind.Accessory:
CharacterCustomization.SetCharacterAccessory(index);
break;
case SlotKind.Outfit:
CharacterCustomization.SetCharacterOutfit(index);
break;
case SlotKind.Hat:
CharacterCustomization.SetCharacterHat(index);
break;
case SlotKind.Sash:
CharacterCustomization.SetCharacterSash(index);
break;
case SlotKind.Medal:
CharacterCustomization.SetCharacterMedal(index);
break;
}
return "CharacterCustomization.SetCharacter" + kind;
}
internal static bool IsWorn(CosmeticProfile profile, CharacterCustomizationData data, Customization cust)
{
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
if (profile?.cosmetics == null || data == null || (Object)(object)cust == (Object)null)
{
return false;
}
bool result = false;
SlotKind[] applyOrder = ApplyOrder;
foreach (SlotKind kind in applyOrder)
{
SavedCosmetic savedCosmetic = profile.cosmetics.Get(kind);
if (savedCosmetic == null || !savedCosmetic.IsSet)
{
continue;
}
CustomizationOption[] list = cust.GetList(ToGameType(kind));
int num = Resolve(list, savedCosmetic);
if (num >= 0)
{
if (GetIndex(data, kind) == num)
{
result = true;
}
else if (IsSelectable(kind, list, num))
{
return false;
}
}
}
return result;
}
}
internal sealed class ProfileApplier
{
private readonly MonoBehaviour host;
internal bool IsBusy { get; private set; }
internal ProfileApplier(MonoBehaviour host)
{
this.host = host;
}
internal bool Apply(CosmeticProfile profile, Action<List<SlotResult>> onDone)
{
if (IsBusy || profile == null)
{
return false;
}
host.StartCoroutine(ApplyRoutine(profile, onDone));
return true;
}
private IEnumerator ApplyRoutine(CosmeticProfile profile, Action<List<SlotResult>> onDone)
{
IsBusy = true;
List<SlotResult> results = new List<SlotResult>();
try
{
float start = Time.unscaledTime;
bool smoke = Plugin.Transition.Value == TransitionMode.Smoke;
if (smoke)
{
Smoke.PlayOn(Character.localCharacter);
if (Plugin.SyncSmokeToOthers.Value)
{
SmokeSync.Send();
}
if (Plugin.SmokeLeadIn.Value > 0f)
{
yield return (object)new WaitForSecondsRealtime(Plugin.SmokeLeadIn.Value);
}
}
SlotKind[] applyOrder = CosmeticSlots.ApplyOrder;
foreach (SlotKind kind in applyOrder)
{
SlotResult item = CosmeticSlots.ApplyOne(kind, profile.cosmetics.Get(kind));
results.Add(item);
if (item.Changed)
{
for (int j = 0; j < Plugin.FramesBetweenChanges.Value; j++)
{
yield return null;
}
}
}
if (smoke)
{
float num = Plugin.SmokeMinDuration.Value - (Time.unscaledTime - start);
if (num > 0f)
{
yield return (object)new WaitForSecondsRealtime(num);
}
}
LogReport(profile, results);
}
finally
{
IsBusy = false;
}
try
{
onDone?.Invoke(results);
}
catch (Exception ex)
{
Plugin.Log.LogError((object)("Profile apply callback failed: " + ex));
}
}
private static void LogReport(CosmeticProfile profile, List<SlotResult> results)
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("Applying \"").Append(profile.name).Append("\" (slot ")
.Append(profile.slot)
.AppendLine(")...");
foreach (SlotResult result in results)
{
stringBuilder.Append(" ").AppendLine(result.ToString());
}
Plugin.Log.LogInfo((object)stringBuilder.ToString().TrimEnd());
}
}
internal static class Smoke
{
internal static void PlayOn(Character character)
{
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)character == (Object)null || character.refs == null || (Object)(object)character.refs.poof == (Object)null)
{
return;
}
try
{
character.PlayPoofVFX(character.Center);
}
catch (Exception ex)
{
Plugin.Log.LogWarning((object)("Could not play poof VFX: " + ex.Message));
}
}
}
}