using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.Json;
using BoneLib;
using BoneLib.BoneMenu;
using BoneLib.Notifications;
using FavoritesMod;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSLZ.Marrow;
using Il2CppSLZ.Marrow.Utilities;
using LabFusion.Data;
using LabFusion.Network;
using LabFusion.Player;
using LabFusion.SDK.Metadata;
using MelonLoader;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Main), "Fusion Favorites", "0.4.0", "YourName", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("FusionFavorites")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("FusionFavorites")]
[assembly: AssemblyTitle("FusionFavorites")]
[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 FavoritesMod
{
public class FavoritePlayer
{
public string Name { get; set; } = "";
public string PlayerId { get; set; } = "";
public string NetworkLayer { get; set; } = "";
public string Note { get; set; } = "";
public DateTime DateAdded { get; set; } = DateTime.UtcNow;
public DateTime? LastSeen { get; set; }
public string LastLevel { get; set; } = "";
public string LastLobby { get; set; } = "";
}
public class LobbyPlayer
{
public string Name = "";
public string PlayerId = "";
public string NetworkLayer = "";
}
public class LobbyStatus
{
public string LobbyName = "";
public string HostName = "";
public string Level = "";
public string Gamemode = "";
public string Privacy = "";
public string Version = "";
public string LobbyKey = "";
public bool Full;
public int Players;
public int MaxPlayers;
public bool Voice;
public bool Mortality;
public bool FriendlyFire;
public bool NameTags;
public List<string> PlayerNames = new List<string>();
public DateTime ScannedAt = DateTime.UtcNow;
}
public class WaitEntry
{
public FavoritePlayer Fav;
public string LobbyKey = "";
public string LobbyName = "";
public float StartedAt;
public int Misses;
}
public enum WaitState
{
Waiting,
JoinNow,
LobbyGone,
FriendLeft
}
public static class FavoritesStore
{
private static readonly string FilePath = Path.Combine(MelonEnvironment.UserDataDirectory, "FusionFavorites.json");
public static List<FavoritePlayer> Favorites { get; private set; } = new List<FavoritePlayer>();
public static void Load()
{
try
{
if (File.Exists(FilePath))
{
Favorites = JsonSerializer.Deserialize<List<FavoritePlayer>>(File.ReadAllText(FilePath)) ?? new List<FavoritePlayer>();
}
}
catch (Exception ex)
{
MelonLogger.Error("Failed to load favorites: " + ex.Message);
Favorites = new List<FavoritePlayer>();
}
}
public static void Save()
{
try
{
string contents = JsonSerializer.Serialize(Favorites, new JsonSerializerOptions
{
WriteIndented = true
});
File.WriteAllText(FilePath, contents);
}
catch (Exception ex)
{
MelonLogger.Error("Failed to save favorites: " + ex.Message);
}
}
public static bool Add(LobbyPlayer p)
{
FavoritePlayer favoritePlayer = Favorites.FirstOrDefault((FavoritePlayer f) => f.PlayerId == p.PlayerId && f.NetworkLayer == p.NetworkLayer);
if (favoritePlayer != null)
{
favoritePlayer.Name = p.Name;
Save();
return false;
}
Favorites.Add(new FavoritePlayer
{
Name = p.Name,
PlayerId = p.PlayerId,
NetworkLayer = p.NetworkLayer
});
Save();
return true;
}
public static void Remove(FavoritePlayer f)
{
Favorites.Remove(f);
Save();
}
}
public static class FusionBridge
{
private static NetworkLayer CurrentLayer => NetworkLayerManager.Layer;
public static string CurrentLayerName
{
get
{
NetworkLayer currentLayer = CurrentLayer;
return ((currentLayer != null) ? currentLayer.Title : null) ?? "";
}
}
public static List<LobbyPlayer> GetPlayersInCurrentLobby()
{
List<LobbyPlayer> list = new List<LobbyPlayer>();
NetworkLayer currentLayer = CurrentLayer;
if (currentLayer == null)
{
return list;
}
foreach (PlayerID item in PlayerIDManager.PlayerIDs.ToList())
{
if (item == null || item.IsMe || string.IsNullOrEmpty(item.PlatformID))
{
continue;
}
string text = null;
try
{
PlayerMetadata metadata = item.Metadata;
object obj;
if (metadata == null)
{
obj = null;
}
else
{
MetadataVariable username = metadata.Username;
obj = ((username != null) ? username.GetValue() : null);
}
text = (string)obj;
}
catch
{
}
if (string.IsNullOrWhiteSpace(text))
{
try
{
text = currentLayer.GetUsername(item.PlatformID);
}
catch
{
}
}
if (string.IsNullOrWhiteSpace(text))
{
text = $"Player {item.SmallID}";
}
list.Add(new LobbyPlayer
{
Name = text,
PlayerId = item.PlatformID,
NetworkLayer = currentLayer.Title
});
}
return list;
}
public static void ScanFavorites(IEnumerable<FavoritePlayer> favs, Action<Dictionary<string, LobbyStatus>> done)
{
Dictionary<string, LobbyStatus> found = new Dictionary<string, LobbyStatus>();
NetworkLayer layer = CurrentLayer;
NetworkLayer obj = layer;
IMatchmaker val = ((obj != null) ? obj.Matchmaker : null);
if (val == null)
{
done(found);
return;
}
HashSet<string> wanted = new HashSet<string>(from f in favs
where string.Equals(f.NetworkLayer, layer.Title, StringComparison.OrdinalIgnoreCase)
select f.PlayerId);
val.RequestLobbies((Action<MatchmakerCallbackInfo>)delegate(MatchmakerCallbackInfo info)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
try
{
LobbyInfo[] lobbies = info.Lobbies;
if (lobbies != null)
{
LobbyInfo[] array = lobbies;
for (int i = 0; i < array.Length; i++)
{
LobbyMetadataInfo metadata = array[i].Metadata;
LobbyInfo lobbyInfo = ((LobbyMetadataInfo)(ref metadata)).LobbyInfo;
if (lobbyInfo != null && !IsOffLimits(metadata))
{
LobbyStatus lobbyStatus = null;
foreach (string item in PlatformIdsIn(lobbyInfo))
{
if (wanted.Contains(item) && !found.ContainsKey(item))
{
if (lobbyStatus == null)
{
lobbyStatus = BuildStatus(lobbyInfo, metadata);
}
found[item] = lobbyStatus;
}
}
}
}
}
}
catch (Exception value)
{
MelonLogger.Error($"Scan failed: {value}");
}
done(found);
});
}
public static void TryJoin(FavoritePlayer fav, Action<string> report)
{
NetworkLayer currentLayer = CurrentLayer;
if (currentLayer == null)
{
report("Fusion isn't logged in to a network layer yet.");
return;
}
if (!string.Equals(currentLayer.Title, fav.NetworkLayer, StringComparison.OrdinalIgnoreCase))
{
report($"{fav.Name} was saved on the {fav.NetworkLayer} layer, but you're on {currentLayer.Title}. " + "Change Target Layer in Fusion's Network Layer Manager and restart.");
return;
}
IMatchmaker matchmaker = currentLayer.Matchmaker;
if (matchmaker == null)
{
report("This network layer has no lobby search.");
return;
}
report("Searching for " + fav.Name + "...");
matchmaker.RequestLobbies((Action<MatchmakerCallbackInfo>)delegate(MatchmakerCallbackInfo info)
{
//IL_0000: 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_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: 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_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0100: Unknown result type (might be due to invalid IL or missing references)
try
{
LobbyInfo[] lobbies = info.Lobbies;
if (lobbies == null)
{
report(fav.Name + " isn't in a lobby you can join right now.");
}
else
{
LobbyInfo[] array = lobbies;
foreach (LobbyInfo val in array)
{
LobbyMetadataInfo metadata = val.Metadata;
LobbyInfo lobbyInfo = ((LobbyMetadataInfo)(ref metadata)).LobbyInfo;
if (lobbyInfo != null && !IsOffLimits(metadata) && PlatformIdsIn(lobbyInfo).Contains(fav.PlayerId))
{
if (IsFull(metadata, lobbyInfo))
{
report($"{fav.Name}'s lobby is full ({lobbyInfo.PlayerCount}/{lobbyInfo.MaxPlayers}). Use Wait for a spot.");
}
else
{
Action action = ((LobbyMetadataInfo)(ref metadata)).CreateJoinDelegate(val.Lobby);
report("Joining " + fav.Name + "'s lobby...");
action?.Invoke();
}
return;
}
}
report(fav.Name + " isn't in a lobby you can join right now.");
}
}
catch (Exception value)
{
MelonLogger.Error($"Join search failed: {value}");
report("Something went wrong searching lobbies (see the MelonLoader log).");
}
});
}
private static bool IsFull(LobbyMetadataInfo meta, LobbyInfo data)
{
if (!((LobbyMetadataInfo)(ref meta)).Full)
{
if (data.MaxPlayers > 0)
{
return data.PlayerCount >= data.MaxPlayers;
}
return false;
}
return true;
}
private static string KeyOf(LobbyInfo data)
{
if (!string.IsNullOrEmpty(data.LobbyID))
{
return data.LobbyID;
}
return data.LobbyCode + "|" + data.LobbyHostID;
}
public static bool IsHostingServer()
{
try
{
return NetworkInfo.HasServer && NetworkInfo.IsHost;
}
catch
{
return false;
}
}
public static void PollWaitlist(List<WaitEntry> entries, Action<List<(WaitEntry Entry, WaitState State, Action Join)>> done)
{
List<(WaitEntry, WaitState, Action)> results = new List<(WaitEntry, WaitState, Action)>();
NetworkLayer currentLayer = CurrentLayer;
IMatchmaker val = ((currentLayer != null) ? currentLayer.Matchmaker : null);
if (val == null || entries.Count == 0)
{
done(results);
return;
}
val.RequestLobbies((Action<MatchmakerCallbackInfo>)delegate(MatchmakerCallbackInfo info)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: 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_0035: 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_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
try
{
Dictionary<string, (LobbyMetadataInfo, LobbyInfo, INetworkLobby)> dictionary = new Dictionary<string, (LobbyMetadataInfo, LobbyInfo, INetworkLobby)>();
LobbyInfo[] lobbies = info.Lobbies;
if (lobbies != null)
{
LobbyInfo[] array = lobbies;
foreach (LobbyInfo val2 in array)
{
LobbyMetadataInfo metadata = val2.Metadata;
LobbyInfo lobbyInfo = ((LobbyMetadataInfo)(ref metadata)).LobbyInfo;
if (lobbyInfo != null && !IsOffLimits(metadata))
{
dictionary[KeyOf(lobbyInfo)] = (metadata, lobbyInfo, val2.Lobby);
}
}
}
foreach (WaitEntry entry in entries)
{
if (!dictionary.TryGetValue(entry.LobbyKey, out var value))
{
results.Add((entry, WaitState.LobbyGone, null));
}
else if (!PlatformIdsIn(value.Item2).Contains(entry.Fav.PlayerId))
{
results.Add((entry, WaitState.FriendLeft, null));
}
else if (IsFull(value.Item1, value.Item2))
{
results.Add((entry, WaitState.Waiting, null));
}
else
{
results.Add((entry, WaitState.JoinNow, ((LobbyMetadataInfo)(ref value.Item1)).CreateJoinDelegate(value.Item3)));
}
}
}
catch (Exception value2)
{
MelonLogger.Error($"Waitlist check failed: {value2}");
results.Clear();
}
done(results);
});
}
private static bool IsOffLimits(LobbyMetadataInfo meta)
{
//IL_0002: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Invalid comparison between Unknown and I4
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0012: Invalid comparison between Unknown and I4
if ((int)((LobbyMetadataInfo)(ref meta)).Privacy != 1)
{
return (int)((LobbyMetadataInfo)(ref meta)).Privacy == 3;
}
return true;
}
private static List<string> PlatformIdsIn(LobbyInfo data)
{
List<string> list = new List<string>();
if (!string.IsNullOrEmpty(data.LobbyHostID))
{
list.Add(data.LobbyHostID);
}
PlayerList playerList = data.PlayerList;
PlayerInfo[] array = ((playerList != null) ? playerList.Players : null);
if (array != null)
{
PlayerInfo[] array2 = array;
foreach (PlayerInfo val in array2)
{
if (val != null && !string.IsNullOrEmpty(val.PlatformID))
{
list.Add(val.PlatformID);
}
}
}
return list;
}
private static LobbyStatus BuildStatus(LobbyInfo data, LobbyMetadataInfo meta)
{
//IL_005c: 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_00b5: Unknown result type (might be due to invalid IL or missing references)
LobbyStatus lobbyStatus = new LobbyStatus
{
LobbyName = (data.LobbyName ?? ""),
HostName = (data.LobbyHostName ?? ""),
Level = (data.LevelTitle ?? ""),
Gamemode = (data.GamemodeTitle ?? ""),
Privacy = ((object)((LobbyMetadataInfo)(ref meta)).Privacy/*cast due to .constrained prefix*/).ToString().ToLowerInvariant().Replace('_', ' '),
Version = ((data.LobbyVersion != null) ? data.LobbyVersion.ToString() : ""),
LobbyKey = KeyOf(data),
Full = IsFull(meta, data),
Players = data.PlayerCount,
MaxPlayers = data.MaxPlayers,
Voice = data.VoiceChat,
Mortality = data.Mortality,
FriendlyFire = data.FriendlyFire,
NameTags = data.NameTags
};
PlayerList playerList = data.PlayerList;
PlayerInfo[] array = ((playerList != null) ? playerList.Players : null);
if (array != null)
{
PlayerInfo[] array2 = array;
foreach (PlayerInfo val in array2)
{
if (val != null)
{
string text = ((!string.IsNullOrWhiteSpace(val.Username)) ? val.Username : val.Nickname);
if (!string.IsNullOrWhiteSpace(text))
{
lobbyStatus.PlayerNames.Add(text);
}
}
}
}
return lobbyStatus;
}
}
public class Main : MelonMod
{
private Page _root;
private Page _addPage;
private Page _favoritesPage;
private readonly Dictionary<string, LobbyStatus> _status = new Dictionary<string, LobbyStatus>();
private bool _scanning;
private float _lastScanTime = -999f;
private PanelSettings _panelSettings;
private WristPanel _panel;
private bool _panelErrorLogged;
private readonly List<WaitEntry> _waitlist = new List<WaitEntry>();
private const float WaitPollSeconds = 6f;
private const float WaitMaxSeconds = 1200f;
private const int WaitMissesBeforeCancel = 2;
private bool _waitPolling;
private float _waitPollStartedAt;
private float _nextWaitPoll;
private bool _waitErrorLogged;
private const float MinScanAge = 60f;
public static Main Instance { get; private set; }
internal Dictionary<string, LobbyStatus> Status => _status;
internal bool IsScanning => _scanning;
internal bool ScanIsStale => Time.unscaledTime - _lastScanTime > 60f;
internal IReadOnlyList<WaitEntry> WaitEntries => _waitlist;
public override void OnInitializeMelon()
{
Instance = this;
FavoritesStore.Load();
_panelSettings = PanelSettingsStore.Load();
_panel = new WristPanel(_panelSettings);
BuildMenu();
((MelonBase)this).LoggerInstance.Msg($"Loaded {FavoritesStore.Favorites.Count} favorite(s).");
}
public override void OnLateUpdate()
{
try
{
_panel?.Update();
}
catch (Exception value)
{
if (!_panelErrorLogged)
{
_panelErrorLogged = true;
((MelonBase)this).LoggerInstance.Error($"Wrist panel error (logged once): {value}");
}
}
try
{
TickWaitlist();
}
catch (Exception value2)
{
if (!_waitErrorLogged)
{
_waitErrorLogged = true;
((MelonBase)this).LoggerInstance.Error($"Waitlist error (logged once): {value2}");
}
}
}
internal bool IsWaiting(FavoritePlayer fav)
{
return _waitlist.Any((WaitEntry w) => w.Fav.PlayerId == fav.PlayerId);
}
internal void StartWait(FavoritePlayer fav)
{
if (IsWaiting(fav))
{
Notify("Already waiting for " + fav.Name + ".");
return;
}
if (!_status.TryGetValue(fav.PlayerId, out var value) || string.IsNullOrEmpty(value.LobbyKey))
{
Notify("Scan first, so I know which lobby they're in.");
return;
}
if (!value.Full)
{
FusionBridge.TryJoin(fav, Notify);
return;
}
_waitlist.Add(new WaitEntry
{
Fav = fav,
LobbyKey = value.LobbyKey,
LobbyName = value.LobbyName,
StartedAt = Time.unscaledTime
});
_nextWaitPoll = 0f;
Notify("Waiting for a spot in " + fav.Name + "'s lobby. I'll join when there's room, if they're still in it.");
RefreshPages();
}
internal void CancelWait(FavoritePlayer fav)
{
if (_waitlist.RemoveAll((WaitEntry w) => w.Fav.PlayerId == fav.PlayerId) > 0)
{
Notify("Stopped waiting for " + fav.Name + ".");
}
RefreshPages();
}
private void TickWaitlist()
{
if (_waitlist.Count == 0)
{
_waitPolling = false;
return;
}
float unscaledTime = Time.unscaledTime;
if (_waitPolling && unscaledTime - _waitPollStartedAt > 30f)
{
_waitPolling = false;
}
if (_waitPolling || unscaledTime < _nextWaitPoll)
{
return;
}
bool flag = false;
for (int num = _waitlist.Count - 1; num >= 0; num--)
{
if (!(unscaledTime - _waitlist[num].StartedAt <= 1200f))
{
Notify("Stopped waiting for " + _waitlist[num].Fav.Name + " (20 minutes passed).");
_waitlist.RemoveAt(num);
flag = true;
}
}
if (flag)
{
RefreshPages();
}
if (_waitlist.Count != 0)
{
_waitPolling = true;
_waitPollStartedAt = unscaledTime;
_nextWaitPoll = unscaledTime + 6f;
FusionBridge.PollWaitlist(_waitlist.ToList(), delegate(List<(WaitEntry Entry, WaitState State, Action Join)> results)
{
_waitPolling = false;
HandleWaitResults(results);
});
}
}
private void HandleWaitResults(List<(WaitEntry Entry, WaitState State, Action Join)> results)
{
bool flag = false;
foreach (var result in results)
{
if (!_waitlist.Contains(result.Entry))
{
continue;
}
switch (result.State)
{
case WaitState.Waiting:
result.Entry.Misses = 0;
break;
case WaitState.LobbyGone:
case WaitState.FriendLeft:
result.Entry.Misses++;
if (result.Entry.Misses >= 2)
{
Notify((result.State == WaitState.FriendLeft) ? (result.Entry.Fav.Name + " left that lobby, so I stopped waiting.") : (result.Entry.Fav.Name + "'s lobby closed, so I stopped waiting."));
_waitlist.Remove(result.Entry);
flag = true;
}
break;
case WaitState.JoinNow:
if (FusionBridge.IsHostingServer())
{
Notify("A spot opened in " + result.Entry.Fav.Name + "'s lobby, but you're hosting, so I didn't move you. Join them yourself if you want.");
_waitlist.Remove(result.Entry);
flag = true;
break;
}
Notify("A spot opened! Joining " + result.Entry.Fav.Name + "'s lobby...");
_waitlist.Clear();
try
{
result.Join?.Invoke();
}
catch (Exception ex)
{
((MelonBase)this).LoggerInstance.Error("Waitlist join failed: " + ex.Message);
}
RefreshPages();
return;
}
}
if (flag)
{
RefreshPages();
}
}
private void BuildMenu()
{
//IL_000b: 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_004a: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
_root = Page.Root.CreatePage("Fusion Favorites", Color.cyan, 0, true);
_root.CreateFunction("Scan for friends", Color.green, (Action)Scan);
_addPage = _root.CreatePage("Add from this lobby", Color.white, 0, true);
_favoritesPage = _root.CreatePage("My favorites", Color.yellow, 0, true);
_root.CreateFunction("Refresh lists", Color.gray, (Action)RefreshPages);
BuildPanelSettingsMenu();
RefreshPages();
}
private void TogglePanel()
{
_panel.Toggle();
}
private void Tweak(string what, Action<PanelSettings> change)
{
change(_panelSettings);
PanelSettingsStore.Save(_panelSettings);
Notify($"{what} (size {_panelSettings.Scale:0.0}x)");
}
private void BuildPanelSettingsMenu()
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: 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_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: Unknown result type (might be due to invalid IL or missing references)
//IL_00ae: 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_00e8: Unknown result type (might be due to invalid IL or missing references)
//IL_0105: Unknown result type (might be due to invalid IL or missing references)
//IL_0122: Unknown result type (might be due to invalid IL or missing references)
//IL_013f: Unknown result type (might be due to invalid IL or missing references)
//IL_015c: Unknown result type (might be due to invalid IL or missing references)
//IL_0179: Unknown result type (might be due to invalid IL or missing references)
//IL_0196: Unknown result type (might be due to invalid IL or missing references)
//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
//IL_01cf: Unknown result type (might be due to invalid IL or missing references)
Page obj = _root.CreatePage("Wrist panel", Color.white, 0, true);
obj.CreateFunction("Open or close panel", Color.green, (Action)TogglePanel);
obj.CreateFunction("Wrist tap area bigger", Color.white, (Action)delegate
{
Tweak("Tap area bigger", delegate(PanelSettings p)
{
p.TapRadius = Mathf.Clamp(p.TapRadius + 0.01f, 0.04f, 0.2f);
});
});
obj.CreateFunction("Wrist tap area smaller", Color.white, (Action)delegate
{
Tweak("Tap area smaller", delegate(PanelSettings p)
{
p.TapRadius = Mathf.Clamp(p.TapRadius - 0.01f, 0.04f, 0.2f);
});
});
obj.CreateFunction("Bigger", Color.white, (Action)delegate
{
Tweak("Bigger", delegate(PanelSettings p)
{
p.Scale = Mathf.Clamp(p.Scale + 0.1f, 0.4f, 2.5f);
});
});
obj.CreateFunction("Smaller", Color.white, (Action)delegate
{
Tweak("Smaller", delegate(PanelSettings p)
{
p.Scale = Mathf.Clamp(p.Scale - 0.1f, 0.4f, 2.5f);
});
});
obj.CreateFunction("Move away from arm", Color.white, (Action)delegate
{
Tweak("Moved out", delegate(PanelSettings p)
{
p.Up = Mathf.Clamp(p.Up + 0.01f, -0.1f, 0.3f);
});
});
obj.CreateFunction("Move closer to arm", Color.white, (Action)delegate
{
Tweak("Moved in", delegate(PanelSettings p)
{
p.Up = Mathf.Clamp(p.Up - 0.01f, -0.1f, 0.3f);
});
});
obj.CreateFunction("Move toward elbow", Color.white, (Action)delegate
{
Tweak("Toward elbow", delegate(PanelSettings p)
{
p.Along = Mathf.Clamp(p.Along + 0.01f, -0.2f, 0.3f);
});
});
obj.CreateFunction("Move toward hand", Color.white, (Action)delegate
{
Tweak("Toward hand", delegate(PanelSettings p)
{
p.Along = Mathf.Clamp(p.Along - 0.01f, -0.2f, 0.3f);
});
});
obj.CreateFunction("Nudge left", Color.white, (Action)delegate
{
Tweak("Nudged left", delegate(PanelSettings p)
{
p.Side = Mathf.Clamp(p.Side + 0.01f, -0.2f, 0.2f);
});
});
obj.CreateFunction("Nudge right", Color.white, (Action)delegate
{
Tweak("Nudged right", delegate(PanelSettings p)
{
p.Side = Mathf.Clamp(p.Side - 0.01f, -0.2f, 0.2f);
});
});
obj.CreateFunction("Pointer higher", Color.cyan, (Action)delegate
{
Tweak("Pointer higher", delegate(PanelSettings p)
{
p.PointerNudgeUp = Mathf.Clamp(p.PointerNudgeUp + 0.01f, -0.1f, 0.15f);
});
});
obj.CreateFunction("Pointer lower", Color.cyan, (Action)delegate
{
Tweak("Pointer lower", delegate(PanelSettings p)
{
p.PointerNudgeUp = Mathf.Clamp(p.PointerNudgeUp - 0.01f, -0.1f, 0.15f);
});
});
obj.CreateFunction("Pointer farther ahead", Color.cyan, (Action)delegate
{
Tweak("Pointer ahead", delegate(PanelSettings p)
{
p.PointerNudgeAhead = Mathf.Clamp(p.PointerNudgeAhead + 0.01f, -0.15f, 0.3f);
});
});
obj.CreateFunction("Pointer closer to hand", Color.cyan, (Action)delegate
{
Tweak("Pointer back", delegate(PanelSettings p)
{
p.PointerNudgeAhead = Mathf.Clamp(p.PointerNudgeAhead - 0.01f, -0.15f, 0.3f);
});
});
obj.CreateFunction("Reset position and size", Color.red, (Action)delegate
{
Tweak("Reset", delegate(PanelSettings p)
{
p.Scale = 1f;
p.Up = 0f;
p.Along = 0f;
p.Side = 0f;
p.PointerNudgeUp = 0.02f;
p.PointerNudgeAhead = 0f;
p.TapRadius = 0.08f;
});
});
}
internal void Scan()
{
if (_scanning)
{
Notify("Already scanning...");
return;
}
_scanning = true;
_lastScanTime = Time.unscaledTime;
Notify("Scanning public lobbies...");
FusionBridge.ScanFavorites(FavoritesStore.Favorites, delegate(Dictionary<string, LobbyStatus> found)
{
_scanning = false;
_status.Clear();
bool flag = false;
foreach (FavoritePlayer favorite in FavoritesStore.Favorites)
{
if (found.TryGetValue(favorite.PlayerId, out var value))
{
_status[favorite.PlayerId] = value;
favorite.LastSeen = DateTime.UtcNow;
favorite.LastLevel = value.Level;
favorite.LastLobby = value.LobbyName;
flag = true;
}
}
if (flag)
{
FavoritesStore.Save();
}
Notify($"{_status.Count} of {FavoritesStore.Favorites.Count} favorites online");
RefreshPages();
});
}
internal void RefreshPages()
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: 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_0100: Unknown result type (might be due to invalid IL or missing references)
//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
//IL_01dc: Unknown result type (might be due to invalid IL or missing references)
_addPage.RemoveAll();
_favoritesPage.RemoveAll();
List<LobbyPlayer> playersInCurrentLobby = FusionBridge.GetPlayersInCurrentLobby();
if (playersInCurrentLobby.Count == 0)
{
_addPage.CreateFunction("(nobody else here)", Color.gray, (Action)delegate
{
});
}
foreach (LobbyPlayer item in playersInCurrentLobby)
{
LobbyPlayer player = item;
_addPage.CreateFunction("Add " + player.Name, Color.white, (Action)delegate
{
Notify(FavoritesStore.Add(player) ? ("Added " + player.Name) : (player.Name + " was already saved (name refreshed)"));
RefreshPages();
});
}
_favoritesPage.CreateFunction("Scan now", Color.green, (Action)Scan);
if (FavoritesStore.Favorites.Count == 0)
{
_favoritesPage.CreateFunction("(no favorites yet)", Color.gray, (Action)delegate
{
});
return;
}
foreach (FavoritePlayer item2 in (from f in FavoritesStore.Favorites
orderby _status.ContainsKey(f.PlayerId) descending, f.Name
select f).ToList())
{
LobbyStatus value;
bool flag = _status.TryGetValue(item2.PlayerId, out value);
string text = (flag ? (item2.Name + " - " + (string.IsNullOrEmpty(value.Level) ? "online" : value.Level)) : item2.Name);
Page page = _favoritesPage.CreatePage(text, flag ? Color.green : Color.gray, 0, true);
BuildProfile(page, item2, flag ? value : null);
}
}
private void BuildProfile(Page page, FavoritePlayer fav, LobbyStatus st)
{
//IL_0514: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Unknown result type (might be due to invalid IL or missing references)
//IL_05d8: Unknown result type (might be due to invalid IL or missing references)
//IL_05f5: 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_00d2: 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_0664: Unknown result type (might be due to invalid IL or missing references)
//IL_0634: Unknown result type (might be due to invalid IL or missing references)
//IL_05a8: Unknown result type (might be due to invalid IL or missing references)
//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
//IL_016b: Unknown result type (might be due to invalid IL or missing references)
//IL_01f5: Unknown result type (might be due to invalid IL or missing references)
//IL_0263: Unknown result type (might be due to invalid IL or missing references)
//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
//IL_02e8: Unknown result type (might be due to invalid IL or missing references)
//IL_0328: Unknown result type (might be due to invalid IL or missing references)
//IL_0368: Unknown result type (might be due to invalid IL or missing references)
//IL_03a8: Unknown result type (might be due to invalid IL or missing references)
//IL_03f0: Unknown result type (might be due to invalid IL or missing references)
//IL_04df: Unknown result type (might be due to invalid IL or missing references)
//IL_049f: Unknown result type (might be due to invalid IL or missing references)
if (st != null)
{
if (st.Full)
{
page.CreateFunction($"Lobby full ({st.Players}/{st.MaxPlayers})", Color.red, (Action)delegate
{
});
if (IsWaiting(fav))
{
page.CreateFunction("Waiting for a spot... (cancel)", Color.yellow, (Action)delegate
{
CancelWait(fav);
});
}
else
{
page.CreateFunction("Wait for a spot", Color.yellow, (Action)delegate
{
StartWait(fav);
});
}
}
else
{
page.CreateFunction("Join lobby", Color.green, (Action)delegate
{
FusionBridge.TryJoin(fav, Notify);
});
}
page.CreateFunction("Map: " + Or(st.Level, "unknown"), Color.cyan, (Action)delegate
{
});
if (!string.IsNullOrEmpty(st.Gamemode))
{
page.CreateFunction("Gamemode: " + st.Gamemode, Color.white, (Action)delegate
{
});
}
page.CreateFunction("Lobby: " + Or(st.LobbyName, "unnamed"), Color.white, (Action)delegate
{
});
page.CreateFunction("Host: " + Or(st.HostName, "unknown"), Color.white, (Action)delegate
{
});
page.CreateFunction($"Players: {st.Players}/{st.MaxPlayers}", Color.white, (Action)delegate
{
});
page.CreateFunction("Privacy: " + Or(st.Privacy, "unknown"), Color.white, (Action)delegate
{
});
page.CreateFunction("Voice chat: " + OnOff(st.Voice), Color.white, (Action)delegate
{
});
page.CreateFunction("Mortality: " + OnOff(st.Mortality), Color.white, (Action)delegate
{
});
page.CreateFunction("Friendly fire: " + OnOff(st.FriendlyFire), Color.white, (Action)delegate
{
});
page.CreateFunction("Nametags: " + OnOff(st.NameTags), Color.white, (Action)delegate
{
});
if (!string.IsNullOrEmpty(st.Version))
{
page.CreateFunction("Fusion version: " + st.Version, Color.gray, (Action)delegate
{
});
}
if (st.PlayerNames.Count > 0)
{
string text = string.Join(", ", st.PlayerNames.Take(6));
if (st.PlayerNames.Count > 6)
{
text += $" +{st.PlayerNames.Count - 6} more";
}
page.CreateFunction("In lobby: " + text, Color.gray, (Action)delegate
{
});
}
page.CreateFunction("Scanned " + Ago(st.ScannedAt), Color.gray, (Action)delegate
{
});
}
else
{
page.CreateFunction("Not in a public lobby right now", Color.gray, (Action)delegate
{
});
if (fav.LastSeen.HasValue)
{
string text2 = (string.IsNullOrEmpty(fav.LastLevel) ? "" : (" on " + fav.LastLevel));
page.CreateFunction("Last seen " + Ago(fav.LastSeen.Value) + text2, Color.gray, (Action)delegate
{
});
}
page.CreateFunction("Try to join anyway", Color.white, (Action)delegate
{
FusionBridge.TryJoin(fav, Notify);
});
page.CreateFunction("Scan again", Color.green, (Action)Scan);
}
if (!string.IsNullOrEmpty(fav.Note))
{
page.CreateFunction("Note: " + fav.Note, Color.yellow, (Action)delegate
{
});
}
page.CreateFunction("Remove", Color.red, (Action)delegate
{
FavoritesStore.Remove(fav);
_status.Remove(fav.PlayerId);
Notify("Removed " + fav.Name);
RefreshPages();
});
}
private static string Or(string value, string fallback)
{
if (!string.IsNullOrWhiteSpace(value))
{
return value;
}
return fallback;
}
private static string OnOff(bool v)
{
if (!v)
{
return "off";
}
return "on";
}
internal static string Ago(DateTime utc)
{
TimeSpan timeSpan = DateTime.UtcNow - utc;
if (timeSpan.TotalSeconds < 60.0)
{
return "just now";
}
if (!(timeSpan.TotalMinutes < 60.0))
{
if (!(timeSpan.TotalHours < 24.0))
{
return $"{(int)timeSpan.TotalDays} d ago";
}
return $"{(int)timeSpan.TotalHours} h ago";
}
return $"{(int)timeSpan.TotalMinutes} min ago";
}
internal static void Notify(string message)
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//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_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Expected O, but got Unknown
MelonLogger.Msg(message);
try
{
Notifier.Send(new Notification
{
Title = NotificationText.op_Implicit("Fusion Favorites"),
Message = NotificationText.op_Implicit(message),
PopupLength = 3f,
ShowTitleOnPopup = true
});
}
catch
{
}
}
}
public class PanelSettings
{
public float TapRadius { get; set; } = 0.08f;
public float Scale { get; set; } = 1f;
public float Up { get; set; }
public float Along { get; set; }
public float Side { get; set; }
public float PointerNudgeUp { get; set; } = 0.02f;
public float PointerNudgeAhead { get; set; }
}
public static class PanelSettingsStore
{
private static readonly string FilePath = Path.Combine(MelonEnvironment.UserDataDirectory, "FusionFavorites.panel.json");
public static PanelSettings Load()
{
try
{
if (File.Exists(FilePath))
{
return JsonSerializer.Deserialize<PanelSettings>(File.ReadAllText(FilePath)) ?? new PanelSettings();
}
}
catch (Exception ex)
{
MelonLogger.Error("Couldn't load panel settings: " + ex.Message);
}
return new PanelSettings();
}
public static void Save(PanelSettings s)
{
try
{
File.WriteAllText(FilePath, JsonSerializer.Serialize(s, new JsonSerializerOptions
{
WriteIndented = true
}));
}
catch (Exception ex)
{
MelonLogger.Error("Couldn't save panel settings: " + ex.Message);
}
}
}
internal sealed class WristPanel
{
private sealed class Row
{
public string Text;
public Color Color;
public Action OnSelect;
public Row(string text, Color color, Action onSelect = null)
{
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
Text = text;
Color = color;
OnSelect = onSelect;
}
}
private sealed class PageData
{
public string Title;
public List<Row> Rows;
}
private sealed class RowView
{
public GameObject Go;
public Image Bg;
public Image Outline;
public Text Label;
public string LastText;
}
private const float Width = 340f;
private const float RowWidth = 324f;
private const float RowHeight = 40f;
private const float HeaderHeight = 46f;
private const float CloseWidth = 52f;
private const float RowsTopPad = 6f;
private const int MaxRows = 8;
private const float Height = 380f;
private const float BaseScale = 0.0005f;
private const float DoubleTapWindow = 0.8f;
private const float TapCooldown = 1.5f;
private const float MaxPointerDistance = 2.5f;
private const int HoverNone = -2;
private const int HoverBack = -1;
private const int HoverClose = -3;
private static readonly Color Online = new Color(0.37f, 0.85f, 0.54f);
private static readonly Color Accent = new Color(0.37f, 0.82f, 0.91f);
private static readonly Color Yellow = new Color(0.95f, 0.78f, 0.36f);
private static readonly Color Gray = new Color(0.54f, 0.56f, 0.61f);
private static readonly Color Danger = new Color(0.94f, 0.42f, 0.42f);
private static readonly Color Plain = new Color(0.9f, 0.91f, 0.93f);
private static readonly Color PanelBg = new Color(0.06f, 0.07f, 0.09f, 0.94f);
private static readonly Color RowBg = new Color(0.115f, 0.125f, 0.153f, 0.95f);
private static readonly Color RowBgInfo = new Color(0.09f, 0.1f, 0.12f, 0.7f);
private static readonly Color RowBgHover = new Color(0.2f, 0.25f, 0.31f, 1f);
private static readonly Color CloseBg = new Color(0.25f, 0.1f, 0.1f, 0.95f);
private static readonly Color CloseBgHover = new Color(0.5f, 0.16f, 0.16f, 1f);
private static readonly Color OutlineRed = new Color(0.9f, 0.16f, 0.2f, 1f);
private static readonly Color OutlineHot = new Color(1f, 0.38f, 0.38f, 1f);
private static Sprite _sprPanel;
private static Sprite _sprPanelRing;
private static Sprite _sprRow;
private static Sprite _sprRowRing;
private static Sprite _sprDot;
private GameObject _root;
private RowView _header;
private RowView _close;
private Image _cursor;
private RectTransform _cursorRt;
private readonly List<RowView> _views = new List<RowView>();
private Font _font;
private GameObject _laserGo;
private LineRenderer _line;
private bool _pointerSourceLogged;
private bool _tapNear;
private float _lastTap = -10f;
private float _tapCooldownUntil;
private int _latchTarget = -2;
private float _latchSince;
private float _latchSeen;
private Func<PageData> _page;
private readonly Stack<Func<PageData>> _history = new Stack<Func<PageData>>();
private readonly List<Row> _shown = new List<Row>();
private string _title = "";
private int _scroll;
private bool _dirty = true;
private float _nextRefresh;
private bool _visible;
private bool _hasPose;
private Vector3 _pos;
public PanelSettings Settings { get; }
public bool IsOpen { get; private set; }
public WristPanel(PanelSettings settings)
{
Settings = settings;
_page = HomePage;
}
public void Update()
{
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: 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_007f: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: 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_008c: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Unknown result type (might be due to invalid IL or missing references)
//IL_0092: Unknown result type (might be due to invalid IL or missing references)
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
//IL_00b2: 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)
//IL_00b9: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: 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_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
//IL_010b: Unknown result type (might be due to invalid IL or missing references)
//IL_0110: Unknown result type (might be due to invalid IL or missing references)
//IL_0115: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_0132: Unknown result type (might be due to invalid IL or missing references)
//IL_0137: Unknown result type (might be due to invalid IL or missing references)
//IL_014f: Unknown result type (might be due to invalid IL or missing references)
//IL_0154: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: Unknown result type (might be due to invalid IL or missing references)
//IL_0122: Unknown result type (might be due to invalid IL or missing references)
//IL_0169: Unknown result type (might be due to invalid IL or missing references)
//IL_0176: Unknown result type (might be due to invalid IL or missing references)
//IL_017c: Unknown result type (might be due to invalid IL or missing references)
//IL_0181: 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)
//IL_018c: Unknown result type (might be due to invalid IL or missing references)
//IL_0198: Unknown result type (might be due to invalid IL or missing references)
//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
//IL_0203: Unknown result type (might be due to invalid IL or missing references)
//IL_020b: Unknown result type (might be due to invalid IL or missing references)
//IL_0213: Unknown result type (might be due to invalid IL or missing references)
//IL_021b: Unknown result type (might be due to invalid IL or missing references)
//IL_024d: Unknown result type (might be due to invalid IL or missing references)
//IL_024f: Unknown result type (might be due to invalid IL or missing references)
//IL_0251: Unknown result type (might be due to invalid IL or missing references)
//IL_0253: Unknown result type (might be due to invalid IL or missing references)
//IL_0235: Unknown result type (might be due to invalid IL or missing references)
//IL_0237: Unknown result type (might be due to invalid IL or missing references)
try
{
CheckOpenGesture();
}
catch
{
}
if (IsOpen && !Player.HandsExist)
{
IsOpen = false;
}
if (!IsOpen)
{
SetVisible(show: false);
return;
}
Hand rightHand = Player.RightHand;
Transform head = Player.Head;
if ((Object)(object)rightHand == (Object)null || (Object)(object)head == (Object)null)
{
SetVisible(show: false);
return;
}
EnsureBuilt();
if ((Object)(object)_root == (Object)null)
{
return;
}
Vector3 position = ((Component)rightHand).transform.position;
Vector3 val = ForearmDirection(rightHand, head);
Vector3 val2 = Vector3.ProjectOnPlane(head.position - position, val);
if (((Vector3)(ref val2)).sqrMagnitude < 1E-06f)
{
val2 = head.up;
}
((Vector3)(ref val2)).Normalize();
Vector3 val3 = Vector3.Cross(val, val2);
Vector3 normalized = ((Vector3)(ref val3)).normalized;
Vector3 val4 = position - val * (0.1f + Settings.Along) + val2 * (0.08f + Settings.Up) + normalized * Settings.Side;
if (!_hasPose)
{
_pos = val4;
_hasPose = true;
}
else
{
_pos = Vector3.Lerp(_pos, val4, 1f - Mathf.Exp(-18f * Time.unscaledDeltaTime));
}
Transform transform = _root.transform;
transform.position = _pos;
transform.rotation = Quaternion.LookRotation(_pos - head.position, head.up);
transform.localScale = Vector3.one * (0.0005f * Settings.Scale);
SetVisible(show: true);
if (_dirty || Time.unscaledTime >= _nextRefresh)
{
Render();
_dirty = false;
_nextRefresh = Time.unscaledTime + 0.5f;
}
int num = -2;
bool num2 = LeftHandEmpty();
bool havePointer = false;
bool onPanel = false;
Vector3 origin = default(Vector3);
Vector3 dir = default(Vector3);
Vector3 hitWorld = default(Vector3);
Vector2 localPos = default(Vector2);
if (num2 && GetPointerRay(head, out origin, out dir))
{
havePointer = true;
num = FindPointerTarget(origin, dir, transform, out localPos, out onPanel, out hitWorld);
}
UpdatePointerVisuals(havePointer, onPanel, origin, dir, hitWorld, localPos);
ApplyHover(num);
float unscaledTime = Time.unscaledTime;
if (num != -2)
{
if (num != _latchTarget)
{
_latchTarget = num;
_latchSince = unscaledTime;
}
_latchSeen = unscaledTime;
}
if (num2 && ClickPressed())
{
int num3 = num;
if (num3 == -2 && _latchTarget != -2 && unscaledTime - _latchSeen < 0.25f && _latchSeen - _latchSince > 0.08f)
{
num3 = _latchTarget;
}
if (num3 != -2)
{
_latchTarget = -2;
BuzzLeft();
Activate(num3);
}
}
}
private static Vector3 ForearmDirection(Hand hand, Transform head)
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: 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_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: 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_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: 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_0096: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
Transform val = null;
try
{
Rigidbody val2 = (((Object)(object)hand.physHand != (Object)null) ? hand.physHand.rbLower : null);
if ((Object)(object)val2 != (Object)null)
{
val = ((Component)val2).transform;
}
}
catch
{
}
Vector3 val3 = (((Object)(object)val != (Object)null) ? (((Component)hand).transform.position - val.position) : ((!((Object)(object)Player.Chest != (Object)null)) ? head.forward : (((Component)hand).transform.position - Player.Chest.position)));
if (((Vector3)(ref val3)).sqrMagnitude < 1E-06f)
{
val3 = head.forward;
}
return ((Vector3)(ref val3)).normalized;
}
private void SetVisible(bool show)
{
if ((Object)(object)_root == (Object)null)
{
_visible = false;
_hasPose = false;
}
else if (show != _visible)
{
_visible = show;
_root.SetActive(show);
if (show)
{
OnShown();
return;
}
_hasPose = false;
_latchTarget = -2;
HidePointerVisuals();
}
}
private void OnShown()
{
_dirty = true;
Main instance = Main.Instance;
if (instance != null && instance.ScanIsStale && !instance.IsScanning)
{
instance.Scan();
}
}
private bool GetPointerRay(Transform head, out Vector3 origin, out Vector3 dir)
{
//IL_0001: 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)
//IL_0021: 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_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: 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_003b: 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_0045: 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_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
//IL_0141: Unknown result type (might be due to invalid IL or missing references)
//IL_0146: Unknown result type (might be due to invalid IL or missing references)
//IL_014b: Unknown result type (might be due to invalid IL or missing references)
//IL_016c: 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_017e: Unknown result type (might be due to invalid IL or missing references)
//IL_0184: Unknown result type (might be due to invalid IL or missing references)
//IL_0194: Unknown result type (might be due to invalid IL or missing references)
//IL_0199: Unknown result type (might be due to invalid IL or missing references)
//IL_019e: Unknown result type (might be due to invalid IL or missing references)
//IL_01a3: Unknown result type (might be due to invalid IL or missing references)
//IL_015c: 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_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: 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_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_009a: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: 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)
//IL_00a8: 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_00af: 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)
//IL_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_00be: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_00da: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: 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)
//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: 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_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_010a: 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)
origin = default(Vector3);
dir = default(Vector3);
Hand leftHand = Player.LeftHand;
if ((Object)(object)leftHand == (Object)null)
{
return false;
}
Vector3 val = ForearmDirection(leftHand, head);
Vector3 position = ((Component)leftHand).transform.position;
origin = position + val * 0.08f;
dir = val;
bool flag = false;
try
{
OpenControllerRig controllerRig = Player.ControllerRig;
Transform palmPositionTransform = leftHand.palmPositionTransform;
if ((Object)(object)controllerRig != (Object)null && (Object)(object)palmPositionTransform != (Object)null)
{
SimpleTransform lPointerInPalmOffset = controllerRig.lPointerInPalmOffset;
Vector3 val2 = palmPositionTransform.position + palmPositionTransform.rotation * lPointerInPalmOffset.position;
Vector3 val3 = palmPositionTransform.rotation * lPointerInPalmOffset.rotation * Vector3.forward;
if (((Vector3)(ref val3)).sqrMagnitude > 1E-06f)
{
((Vector3)(ref val3)).Normalize();
if (Vector3.Dot(val3, val) > 0.3f)
{
Vector3 val4 = val2 - position;
if (((Vector3)(ref val4)).sqrMagnitude < 0.16f)
{
origin = val2;
dir = val3;
flag = true;
}
}
}
}
}
catch
{
}
if (!_pointerSourceLogged)
{
_pointerSourceLogged = true;
MelonLogger.Msg(flag ? "Wrist panel pointer: using the game's palm pointer." : "Wrist panel pointer: game pointer unavailable, using the hand fallback.");
}
Vector3 val5 = Vector3.ProjectOnPlane(Vector3.up, dir);
if (((Vector3)(ref val5)).sqrMagnitude < 0.0001f)
{
val5 = head.up;
}
((Vector3)(ref val5)).Normalize();
origin += val5 * Settings.PointerNudgeUp + dir * Settings.PointerNudgeAhead;
return true;
}
private int FindPointerTarget(Vector3 origin, Vector3 dir, Transform panel, out Vector2 localPos, out bool onPanel, out Vector3 hitWorld)
{
//IL_0002: 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_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: 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_0058: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_005b: Unknown result type (might be due to invalid IL or missing references)
//IL_0060: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_007d: Unknown result type (might be due to invalid IL or missing references)
//IL_0086: 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_00b9: Unknown result type (might be due to invalid IL or missing references)
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: 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)
localPos = default(Vector2);
onPanel = false;
hitWorld = default(Vector3);
Vector3 forward = panel.forward;
float num = Vector3.Dot(dir, forward);
if (num < 0.05f)
{
return -2;
}
float num2 = Vector3.Dot(panel.position - origin, forward) / num;
if (num2 <= 0f || num2 > 2.5f)
{
return -2;
}
hitWorld = origin + dir * num2;
Vector3 val = panel.InverseTransformPoint(hitWorld);
float num3 = 190f - val.y;
if (Mathf.Abs(val.x) > 170f || num3 < 0f || num3 > 380f)
{
return -2;
}
onPanel = true;
localPos = new Vector2(val.x, val.y);
if (num3 < 46f)
{
if (!(val.x > 110f))
{
return -1;
}
return -3;
}
int num4 = (int)((num3 - 46f - 6f) / 40f);
if (num4 < 0 || num4 >= _shown.Count)
{
return -2;
}
return num4;
}
private void UpdatePointerVisuals(bool havePointer, bool onPanel, Vector3 origin, Vector3 dir, Vector3 hit, Vector2 cursorLocal)
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: 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_003c: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_009c: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_line != (Object)null)
{
if (havePointer)
{
((Renderer)_line).enabled = true;
_line.SetPosition(0, origin);
_line.SetPosition(1, onPanel ? hit : (origin + dir * 0.5f));
}
else
{
((Renderer)_line).enabled = false;
}
}
if ((Object)(object)_cursor != (Object)null)
{
bool flag = havePointer && onPanel;
if (((Component)_cursor).gameObject.activeSelf != flag)
{
((Component)_cursor).gameObject.SetActive(flag);
}
if (flag)
{
_cursorRt.anchoredPosition = cursorLocal;
}
}
}
private void HidePointerVisuals()
{
if ((Object)(object)_line != (Object)null)
{
((Renderer)_line).enabled = false;
}
if ((Object)(object)_cursor != (Object)null && ((Component)_cursor).gameObject.activeSelf)
{
((Component)_cursor).gameObject.SetActive(false);
}
}
private static bool LeftHandEmpty()
{
try
{
Hand leftHand = Player.LeftHand;
return (Object)(object)leftHand != (Object)null && (Object)(object)Player.GetObjectInHand(leftHand) == (Object)null;
}
catch
{
return false;
}
}
private static bool ClickPressed()
{
try
{
BaseController leftController = Player.LeftController;
if ((Object)(object)leftController == (Object)null)
{
return false;
}
return leftController.GetPrimaryInteractionButtonDown() || leftController.GetAButtonDown();
}
catch
{
return false;
}
}
private static void BuzzLeft()
{
try
{
BaseController leftController = Player.LeftController;
if ((Object)(object)leftController != (Object)null)
{
leftController.Haptic(0.3f);
}
}
catch
{
}
}
private void Activate(int hover)
{
try
{
switch (hover)
{
case -3:
Close();
break;
case -1:
Pop();
break;
default:
_shown[hover].OnSelect?.Invoke();
_dirty = true;
break;
}
}
catch (Exception value)
{
MelonLogger.Error($"Wrist panel action failed: {value}");
}
}
public void Toggle()
{
if (IsOpen)
{
Close();
}
else
{
Open();
}
}
private void Open()
{
IsOpen = true;
_dirty = true;
Main.Notify("Wrist panel open. Point at the red X to close it.");
}
private void Close()
{
IsOpen = false;
SetVisible(show: false);
Main.Notify("Wrist panel closed. Tap your right wrist twice with your left hand to open it.");
}
private void CheckOpenGesture()
{
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_0063: 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_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
if (IsOpen || !Player.HandsExist)
{
_tapNear = false;
return;
}
Hand leftHand = Player.LeftHand;
Hand rightHand = Player.RightHand;
Transform head = Player.Head;
if ((Object)(object)leftHand == (Object)null || (Object)(object)rightHand == (Object)null || (Object)(object)head == (Object)null)
{
_tapNear = false;
return;
}
Vector3 val = ((Component)rightHand).transform.position - ForearmDirection(rightHand, head) * 0.1f;
bool flag = Vector3.Distance(((Component)leftHand).transform.position, val) < Settings.TapRadius;
bool num = flag && !_tapNear;
_tapNear = flag;
if (!num)
{
return;
}
float unscaledTime = Time.unscaledTime;
if (!(unscaledTime < _tapCooldownUntil))
{
if ((Object)(object)Player.GetObjectInHand(leftHand) != (Object)null || (Object)(object)Player.GetObjectInHand(rightHand) != (Object)null)
{
_lastTap = -10f;
}
else if (unscaledTime - _lastTap <= 0.8f)
{
_lastTap = -10f;
_tapCooldownUntil = unscaledTime + 1.5f;
Open();
}
else
{
_lastTap = unscaledTime;
}
}
}
private void Push(Func<PageData> next)
{
_history.Push(_page);
_page = next;
_scroll = 0;
_dirty = true;
}
private void Pop()
{
if (_history.Count != 0)
{
_page = _history.Pop();
_scroll = 0;
_dirty = true;
}
}
private PageData HomePage()
{
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_0101: 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_019e: Unknown result type (might be due to invalid IL or missing references)
Main main = Main.Instance;
int count = FavoritesStore.Favorites.Count;
int count2 = main.Status.Count;
List<Row> list = new List<Row>
{
new Row(main.IsScanning ? "Scanning..." : $"Scan for friends ({count2}/{count} online)", Online, delegate
{
main.Scan();
}),
new Row($"My favorites ({count})", Yellow, delegate
{
Push(FavoritesPage);
}),
new Row("Add from this lobby", Plain, delegate
{
Push(AddPage);
}),
new Row("Layer: " + Or(FusionBridge.CurrentLayerName, "not connected"), Gray)
};
foreach (WaitEntry waitEntry in main.WaitEntries)
{
FavoritePlayer fav = waitEntry.Fav;
list.Insert(1, new Row("Waiting: " + fav.Name + " (tap to cancel)", Yellow, delegate
{
main.CancelWait(fav);
}));
}
return new PageData
{
Title = "Fusion Favorites",
Rows = list
};
}
private PageData FavoritesPage()
{
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0114: Unknown result type (might be due to invalid IL or missing references)
//IL_010d: Unknown result type (might be due to invalid IL or missing references)
Main main = Main.Instance;
List<Row> list = new List<Row>();
List<FavoritePlayer> list2 = (from f in FavoritesStore.Favorites
orderby main.Status.ContainsKey(f.PlayerId) descending, f.Name
select f).ToList();
if (list2.Count == 0)
{
list.Add(new Row("No favorites yet", Gray));
}
foreach (FavoritePlayer item in list2)
{
FavoritePlayer fav = item;
LobbyStatus value;
bool flag = main.Status.TryGetValue(fav.PlayerId, out value);
string text = (flag ? (fav.Name + " - " + Or(value.Level, "online")) : fav.Name);
list.Add(new Row(text, flag ? Online : Gray, delegate
{
Push(() => ProfilePage(fav));
}));
}
return new PageData
{
Title = "My favorites",
Rows = list
};
}
private PageData AddPage()
{
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
List<Row> list = new List<Row>();
List<LobbyPlayer> list2;
try
{
list2 = FusionBridge.GetPlayersInCurrentLobby();
}
catch
{
list2 = new List<LobbyPlayer>();
}
if (list2.Count == 0)
{
list.Add(new Row("Nobody else here", Gray));
}
foreach (LobbyPlayer item in list2)
{
LobbyPlayer player = item;
bool flag = FavoritesStore.Favorites.Any((FavoritePlayer f) => f.PlayerId == player.PlayerId && f.NetworkLayer == player.NetworkLayer);
list.Add(new Row(flag ? (player.Name + " (saved)") : ("Add " + player.Name), flag ? Gray : Online, delegate
{
Main.Notify(FavoritesStore.Add(player) ? ("Added " + player.Name) : (player.Name + " was already saved"));
Main.Instance.RefreshPages();
}));
}
return new PageData
{
Title = "Add from lobby",
Rows = list
};
}
private PageData ProfilePage(FavoritePlayer fav)
{
//IL_035a: Unknown result type (might be due to invalid IL or missing references)
//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
//IL_040d: Unknown result type (might be due to invalid IL or missing references)
//IL_0111: Unknown result type (might be due to invalid IL or missing references)
//IL_00a2: Unknown result type (might be due to invalid IL or missing references)
//IL_0147: 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_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_0466: Unknown result type (might be due to invalid IL or missing references)
//IL_0450: Unknown result type (might be due to invalid IL or missing references)
//IL_03d6: Unknown result type (might be due to invalid IL or missing references)
//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
//IL_0223: Unknown result type (might be due to invalid IL or missing references)
//IL_0259: Unknown result type (might be due to invalid IL or missing references)
//IL_028f: 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_033f: Unknown result type (might be due to invalid IL or missing references)
//IL_0319: Unknown result type (might be due to invalid IL or missing references)
Main main = Main.Instance;
LobbyStatus value;
bool num = main.Status.TryGetValue(fav.PlayerId, out value);
List<Row> list = new List<Row>();
if (num)
{
if (value.Full)
{
list.Add(new Row($"Lobby full ({value.Players}/{value.MaxPlayers})", Danger));
if (main.IsWaiting(fav))
{
list.Add(new Row("Waiting for a spot... tap to cancel", Yellow, delegate
{
main.CancelWait(fav);
}));
}
else
{
list.Add(new Row("Wait for a spot", Yellow, delegate
{
main.StartWait(fav);
}));
}
}
else
{
list.Add(new Row("Join lobby", Online, delegate
{
FusionBridge.TryJoin(fav, Main.Notify);
}));
}
list.Add(new Row("Map: " + Or(value.Level, "unknown"), Accent));
if (!string.IsNullOrEmpty(value.Gamemode))
{
list.Add(new Row("Mode: " + value.Gamemode, Plain));
}
list.Add(new Row("Lobby: " + Or(value.LobbyName, "unnamed"), Plain));
list.Add(new Row($"Host: {Or(value.HostName, "?")} ({value.Players}/{value.MaxPlayers})", Plain));
list.Add(new Row(Or(value.Privacy, "?") + " | voice " + OnOff(value.Voice), Plain));
list.Add(new Row("mortality " + OnOff(value.Mortality) + " | fire " + OnOff(value.FriendlyFire), Plain));
if (value.PlayerNames.Count > 0)
{
string text = string.Join(", ", value.PlayerNames.Take(4));
if (value.PlayerNames.Count > 4)
{
text += $" +{value.PlayerNames.Count - 4}";
}
list.Add(new Row("In lobby: " + text, Gray));
}
list.Add(new Row("Scanned " + Main.Ago(value.ScannedAt), Gray));
}
else
{
list.Add(new Row("Not in a public lobby", Gray));
if (fav.LastSeen.HasValue)
{
string text2 = (string.IsNullOrEmpty(fav.LastLevel) ? "" : (" on " + fav.LastLevel));
list.Add(new Row("Last seen " + Main.Ago(fav.LastSeen.Value) + text2, Gray));
}
list.Add(new Row("Try to join anyway", Plain, delegate
{
FusionBridge.TryJoin(fav, Main.Notify);
}));
list.Add(new Row("Scan again", Online, delegate
{
main.Scan();
}));
}
if (!string.IsNullOrEmpty(fav.Note))
{
list.Add(new Row("Note: " + fav.Note, Yellow));
}
list.Add(new Row("Remove", Danger, delegate
{
FavoritesStore.Remove(fav);
main.Status.Remove(fav.PlayerId);
main.RefreshPages();
Main.Notify("Removed " + fav.Name);
Pop();
}));
return new PageData
{
Title = fav.Name,
Rows = list
};
}
private static string Or(string v, string fallback)
{
if (!string.IsNullOrWhiteSpace(v))
{
return v;
}
return fallback;
}
private static string OnOff(bool v)
{
if (!v)
{
return "off";
}
return "on";
}
private void Render()
{
//IL_012e: Unknown result type (might be due to invalid IL or missing references)
//IL_0127: Unknown result type (might be due to invalid IL or missing references)
//IL_0194: Unknown result type (might be due to invalid IL or missing references)
//IL_01a9: Unknown result type (might be due to invalid IL or missing references)
//IL_0204: Unknown result type (might be due to invalid IL or missing references)
//IL_0166: Unknown result type (might be due to invalid IL or missing references)
//IL_015f: Unknown result type (might be due to invalid IL or missing references)
PageData pageData;
try
{
pageData = _page();
}
catch (Exception ex)
{
MelonLogger.Error("Wrist panel page failed: " + ex.Message);
_page = HomePage;
_history.Clear();
pageData = HomePage();
}
_title = ((_history.Count > 0) ? "< " : "") + pageData.Title;
_shown.Clear();
List<Row> rows = pageData.Rows;
if (rows.Count <= 8)
{
_shown.AddRange(rows);
}
else
{
int window = 6;
_scroll = Mathf.Clamp(_scroll, 0, rows.Count - window);
_shown.AddRange(rows.Skip(_scroll).Take(window));
bool flag = _scroll > 0;
bool flag2 = _scroll + window < rows.Count;
_shown.Add(new Row("^ more", flag ? Accent : Gray, flag ? ((Action)delegate
{
_scroll = Math.Max(0, _scroll - window);
}) : null));
_shown.Add(new Row("v more", flag2 ? Accent : Gray, flag2 ? ((Action)delegate
{
_scroll += window;
}) : null));
}
SetLabel(_header, _title, Accent);
SetLabel(_close, "X", Danger);
for (int num = 0; num < _views.Count; num++)
{
RowView rowView = _views[num];
if (num < _shown.Count)
{
rowView.Go.SetActive(true);
SetLabel(rowView, _shown[num].Text, _shown[num].Color);
}
else
{
rowView.Go.SetActive(false);
}
}
}
private static void SetLabel(RowView v, string text, Color color)
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
if (v.LastText != text)
{
v.Label.text = text;
v.LastText = text;
}
((Graphic)v.Label).color = color;
}
private void ApplyHover(int hover)
{
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_005d: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_00bb: 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)
bool flag = _history.Count > 0;
bool flag2 = hover == -1 && flag;
((Graphic)_header.Bg).color = (flag2 ? RowBgHover : RowBg);
SetOutline(_header, flag, flag2);
bool flag3 = hover == -3;
((Graphic)_close.Bg).color = (flag3 ? CloseBgHover : CloseBg);
SetOutline(_close, visible: true, flag3);
for (int i = 0; i < _views.Count && i < _shown.Count; i++)
{
bool flag4 = _shown[i].OnSelect != null;
bool flag5 = flag4 && i == hover;
((Graphic)_views[i].Bg).color = ((!flag4) ? RowBgInfo : (flag5 ? RowBgHover : RowBg));
SetOutline(_views[i], flag4, flag5);
}
}
private static void SetOutline(RowView v, bool visible, bool hot)
{
//IL_003c: 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)
if (!((Object)(object)v.Outline == (Object)null))
{
if (((Behaviour)v.Outline).enabled != visible)
{
((Behaviour)v.Outline).enabled = visible;
}
if (visible)
{
((Graphic)v.Outline).color = (hot ? OutlineHot : OutlineRed);
}
}
}
private void EnsureBuilt()
{
//IL_0065: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Expected O, but got Unknown
//IL_008f: 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_00bc: Invalid comparison between Unknown and I4
//IL_00da: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_010a: Unknown result type (might be due to invalid IL or missing references)
//IL_010f: Unknown result type (might be due to invalid IL or missing references)
//IL_011e: Unknown result type (might be due to invalid IL or missing references)
//IL_013f: Unknown result type (might be due to invalid IL or missing references)
//IL_0144: Unknown result type (might be due to invalid IL or missing references)
//IL_0153: Unknown result type (might be due to invalid IL or missing references)
//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
//IL_026f: Unknown result type (might be due to invalid IL or missing references)
//IL_0274: Unknown result type (might be due to invalid IL or missing references)
//IL_0283: Unknown result type (might be due to invalid IL or missing references)
if (!((Object)(object)_root != (Object)null))
{
_views.Clear();
_visible = false;
_hasPose = false;
_dirty = true;
if ((Object)(object)_laserGo != (Object)null)
{
Object.Destroy((Object)(object)_laserGo);
}
_line = null;
_font = FindFont();
EnsureSprites();
_root = new GameObject("FusionFavoritesWristPanel");
Object.DontDestroyOnLoad((Object)(object)_root);
_root.AddComponent<RectTransform>().sizeDelta = new Vector2(340f, 380f);
_root.AddComponent<Canvas>().renderMode = (RenderMode)2;
_root.AddComponent<CanvasScaler>().dynamicPixelsPerUnit = (((int)Application.platform == 11) ? 2f : 4f);
_root.transform.localScale = Vector3.one * (0.0005f * Settings.Scale);
MakeImage("Backdrop", _root.transform, PanelBg, Vector2.zero, new Vector2(340f, 380f), _sprPanel, sliced: true);
MakeImage("PanelOutline", _root.transform, OutlineRed, Vector2.zero, new Vector2(340f, 380f), _sprPanelRing, sliced: true);
float num = 190f;
float y = num - 23f - 2f;
float width = 266f;
_header = MakeRow("Header", -29f, y, width, 42f, 26f, (TextAnchor)3, 12f, 8f);
_close = MakeRow("Close", 136f, y, 52f, 42f, 26f, (TextAnchor)4, 0f, 0f);
((Graphic)_close.Bg).color = CloseBg;
for (int i = 0; i < 8; i++)
{
float y2 = num - 46f - 6f - ((float)i + 0.5f) * 40f;
_views.Add(MakeRow("Row" + i, 0f, y2, 324f, 36f, 22f, (TextAnchor)3, 12f, 12f));
}
_cursor = MakeImage("Cursor", _root.transform, Accent, Vector2.zero, new Vector2(14f, 14f), _sprDot);
_cursorRt = ((Component)_cursor).GetComponent<RectTransform>();
((Component)_cursor).gameObject.SetActive(false);
BuildLaser();
_root.SetActive(false);
}
}
private void BuildLaser()
{
//IL_001f: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Expected O, but got Unknown
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0056: Expected O, but got Unknown
//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
try
{
Shader val = Shader.Find("Sprites/Default");
if (!((Object)(object)val == (Object)null))
{
_laserGo = new GameObject("FusionFavoritesLaser");
Object.DontDestroyOnLoad((Object)(object)_laserGo);
_line = _laserGo.AddComponent<LineRenderer>();
((Renderer)_line).material = new Material(val);
_line.positionCount = 2;
_line.useWorldSpace = true;
_line.startWidth = 0.004f;
_line.endWidth = 0.0015f;
_line.startColor = new Color(0.37f, 0.82f, 0.91f, 0.9f);
_line.endColor = new Color(0.37f, 0.82f, 0.91f, 0.15f);
((Renderer)_line).enabled = false;
}
}
catch (Exception ex)
{
MelonLogger.Warning("Laser line unavailable (the cursor dot still works): " + ex.Message);
_line = null;
}
}
private RowView MakeRow(string name, float x, float y, float width, float height, float fontSize, TextAnchor align, float leftInset, float rightInset)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//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_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_005c: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_0071: 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_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_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_00d4: 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)
//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
//IL_012c: 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)
Image val = MakeImage(name, _root.transform, RowBg, new Vector2(x, y), new Vector2(width, height), _sprRow, sliced: true);
GameObject val2 = new GameObject(name + "Outline");
RectTransform obj = val2.AddComponent<RectTransform>();
((Transform)obj).SetParent(((Component)val).transform, false);
obj.anchorMin = Vector2.zero;
obj.anchorMax = Vector2.one;
obj.offsetMin = Vector2.zero;
obj.offsetMax = Vector2.zero;
Image val3 = val2.AddComponent<Image>();
val3.sprite = _sprRowRing;
val3.type = (Type)1;
((Graphic)val3).color = OutlineRed;
((Graphic)val3).raycastTarget = false;
GameObject val4 = new GameObject(name + "Text");
RectTransform obj2 = val4.AddComponent<RectTransform>();
((Transform)obj2).SetParent(((Component)val).transform, false);
obj2.anchorMin = Vector2.zero;
obj2.anchorMax = Vector2.one;
obj2.offsetMin = new Vector2(leftInset, 0f);
obj2.offsetMax = new Vector2(0f - rightInset, 0f);
Text val5 = val4.AddComponent<Text>();
if ((Object)(object)_font != (Object)null)
{
val5.font = _font;
}
val5.fontSize = (int)fontSize;
val5.alignment = align;
val5.horizontalOverflow = (HorizontalWrapMode)0;
val5.verticalOverflow = (VerticalWrapMode)0;
val5.resizeTextForBestFit = true;
val5.resizeTextMinSize = 10;
val5.resizeTextMaxSize = (int)fontSize;
((Graphic)val5).raycastTarget = false;
((Graphic)val5).color = Plain;
return new RowView
{
Go = ((Component)val).gameObject,
Bg = val,
Outline = val3,
Label = val5,
LastText = null
};
}
private static Image MakeImage(string name, Transform parent, Color color, Vector2 pos, Vector2 size, Sprite sprite = null, bool sliced = false)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
GameObject val = new GameObject(name);
RectTransform obj = val.AddComponent<RectTransform>();
((Transform)obj).SetParent(parent, false);
obj.sizeDelta = size;
obj.anchoredPosition = pos;
Image val2 = val.AddComponent<Image>();
if ((Object)(object)sprite != (Object)null)
{
val2.sprite = sprite;
val2.type = (Type)(sliced ? 1 : 0);
}
((Graphic)val2).color = color;
((Graphic)val2).raycastTarget = false;
return val2;
}
private static void EnsureSprites()
{
if (!((Object)(object)_sprPanel != (Object)null) || !((Object)(object)_sprPanelRing != (Object)null) || !((Object)(object)_sprRow != (Object)null) || !((Object)(object)_sprRowRing != (Object)null) || !((Object)(object)_sprDot != (Object)null))
{
_sprPanel = MakeSprite(56, 24f, 0f, 26);
_sprPanelRing = MakeSprite(56, 24f, 3f, 26);
_sprRow = MakeSprite(28, 11f, 0f, 13);
_sprRowRing = MakeSprite(28, 11f, 2.2f, 13);
_sprDot = MakeSprite(20, 10f, 0f, 0);
}
}
private static Sprite MakeSprite(int size, float radius, float thickness, int border)
{
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
//IL_000a: Expected O, but got Unknown
//IL_011f: Unknown result type (might be due to invalid IL or missing references)
//IL_012e: Unknown result type (might be due to invalid IL or missing references)
//IL_0142: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
Texture2D val = new Texture2D(size, size, (TextureFormat)4, false);
((Texture)val).filterMode = (FilterMode)1;
((Texture)val).wrapMode = (TextureWrapMode)1;
((Object)val).hideFlags = (HideFlags)61;
float num = (float)size * 0.5f;
float num2 = num - radius;
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
float num3 = Mathf.Abs((float)j + 0.5f - num) - num2;
float num4 = Mathf.Abs((float)i + 0.5f - num) - num2;
float num5 = Mathf.Max(num3, 0f);
float num6 = Mathf.Max(num4, 0f);
float num7 = Mathf.Sqrt(num5 * num5 + num6 * num6) + Mathf.Min(Mathf.Max(num3, num4), 0f) - radius;
float num8 = Mathf.Clamp01(0.5f - num7);
if (thickness > 0f)
{
num8 = Mathf.Clamp01(num8 - Mathf.Clamp01(0.5f - (num7 + thickness)));
}
val.SetPixel(j, i, new Color(1f, 1f, 1f, num8));
}
}
val.Apply();
Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)size, (float)size), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, new Vector4((float)border, (float)border, (float)border, (float)border));
((Object)obj).hideFlags = (HideFlags)61;
return obj;
}
private static Font FindFont()
{
try
{
HashSet<string> hashSet = new HashSet<string>();
Il2CppStringArray oSInstalledFontNames = Font.GetOSInstalledFontNames();
if (oSInstalledFontNames != null)
{
foreach (string item in (Il2CppArrayBase<string>)(object)oSInstalledFontNames)
{
hashSet.Add(item);
}
}
string[] array = new string[6] { "Arial", "Roboto", "Noto Sans", "Droid Sans", "Segoe UI", "Helvetica" };
foreach (string text in array)
{
if (hashSet.Contains(text))
{
Font val = Font.CreateDynamicFontFromOSFont(text, 32);
if ((Object)(object)val != (Object)null)
{
return val;
}
}
}
foreach (string item2 in hashSet)
{
Font val2 = Font.CreateDynamicFontFromOSFont(item2, 32);
if ((Object)(object)val2 != (Object)null)
{
return val2;
}
}
}
catch
{
}
try
{
Font builtinResource = Resources.GetBuiltinResource<Font>("Arial.ttf");
if ((Object)(object)builtinResource != (Object)null)
{
return builtinResource;
}
}
catch
{
}
return null;
}
}
}