using System;
using System.Collections;
using System.Collections.Concurrent;
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.Security;
using System.Security.Permissions;
using BaboonAPI.Hooks.Initializer;
using BaboonAPI.Hooks.Tracks;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Microsoft.FSharp.Core;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using TMPro;
using TootTallyAccounts;
using TootTallyCore;
using TootTallyCore.APIServices;
using TootTallyCore.Graphics;
using TootTallyCore.Graphics.Animations;
using TootTallyCore.Utils.Assets;
using TootTallyCore.Utils.Helpers;
using TootTallyCore.Utils.TootTallyGlobals;
using TootTallyCore.Utils.TootTallyModules;
using TootTallyCore.Utils.TootTallyNotifs;
using TootTallyGameModifiers;
using TootTallySettings;
using TootTallyTrombuddies;
using TootTallyWebsocketLibs;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using WebSocketSharp;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("TootTallySpectator")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Share your gameplay and watch your trombuddies play")]
[assembly: AssemblyFileVersion("1.0.7.0")]
[assembly: AssemblyInformationalVersion("1.0.7")]
[assembly: AssemblyProduct("TootTallySpectator")]
[assembly: AssemblyTitle("TootTallySpectator")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.7.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.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 TootTallySpectator
{
public static class CompatibilityPatches
{
[HarmonyPatch(typeof(TrombuddiesGameObjectFactory), "CreateUserCard")]
[HarmonyPostfix]
public static void InitOverlay(User user, ref GameObject __result)
{
//IL_0052: 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_00c2: Unknown result type (might be due to invalid IL or missing references)
//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
GameObject gameObject = ((Component)__result.transform.Find("LatencyFG/RightContent")).gameObject;
if (!SpectatingManager.IsHosting && user.id == TootTallyUser.userInfo.id)
{
GameObjectFactory.CreateCustomButton(gameObject.transform, Vector2.zero, Vector2.one * 45f, AssetManager.GetSprite("SpectatorIcon.png"), "SpectateUserButton", (Action)delegate
{
SpectatingManager.OnSpectateButtonPress(user.id, user.username);
});
}
if (user.id != TootTallyUser.userInfo.id && SpectatingManager.currentSpectatorIDList.Contains(user.id))
{
GameObjectFactory.CreateCustomButton(gameObject.transform, Vector2.zero, Vector2.one * 45f, AssetManager.GetSprite("SpectatorIcon.png"), "SpectateUserButton", (Action)delegate
{
SpectatingManager.OnSpectateButtonPress(user.id, user.username);
});
}
}
[HarmonyPatch(typeof(UserStatusUpdater), "SetPlayingUserStatus")]
[HarmonyPrefix]
public static bool OverwritePlayingUserStatus()
{
if (!SpectatingManager.IsSpectating)
{
return true;
}
UserStatusManager.SetUserStatus((UserStatus)6);
return false;
}
[HarmonyPatch(typeof(GameController), "pauseQuitLevel")]
[HarmonyPostfix]
public static void OnQuitLoadBackedupModifiers()
{
if (SpectatingManager.IsSpectating)
{
GameModifierManager.LoadBackedupModifiers();
}
}
[HarmonyPatch(typeof(PointSceneController), "updateSave")]
[HarmonyPrefix]
public static bool AvoidSaveChange()
{
return !SpectatingManager.IsSpectating;
}
[HarmonyPatch(typeof(PointSceneController), "checkScoreCheevos")]
[HarmonyPrefix]
public static bool AvoidAchievementCheck()
{
return !SpectatingManager.IsSpectating;
}
[HarmonyPatch(typeof(UserStatusManager), "OnHeartBeatRequestResponse")]
[HarmonyPostfix]
public static void UpdateSpecList()
{
SpectatingManager.UpdateSpectatorIDList();
}
}
[BepInPlugin("TootTallySpectator", "TootTallySpectator", "1.0.7")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin, ITootTallyModule
{
public static Plugin Instance;
private const string CONFIG_NAME = "TootTally.cfg";
private Harmony _harmony;
public static TootTallySettingPage settingPage;
public ConfigEntry<bool> ModuleConfigEnabled { get; set; }
public bool IsConfigInitialized { get; set; }
public string Name
{
get
{
return "TootTallySpectator";
}
set
{
Name = value;
}
}
public ConfigEntry<bool> AllowSpectate { get; private set; }
public ConfigEntry<bool> ShowSpectatorCount { get; private set; }
public static void LogInfo(string msg)
{
((BaseUnityPlugin)Instance).Logger.LogInfo((object)msg);
}
public static void LogError(string msg)
{
((BaseUnityPlugin)Instance).Logger.LogError((object)msg);
}
private void Awake()
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Expected O, but got Unknown
if (!((Object)(object)Instance != (Object)null))
{
Instance = this;
_harmony = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
GameInitializationEvent.Register(((BaseUnityPlugin)this).Info, (Action)TryInitialize);
}
}
private void TryInitialize()
{
ModuleConfigEnabled = ((BaseUnityPlugin)Plugin.Instance).Config.Bind<bool>("Modules", "Spectator", true, "Share your gameplay and watch other plays.");
TootTallyModuleManager.AddModule((ITootTallyModule)(object)this);
Plugin.Instance.AddModuleToSettingPage((ITootTallyModule)(object)this);
}
public void LoadModule()
{
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Expected O, but got Unknown
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Unknown result type (might be due to invalid IL or missing references)
AssetManager.LoadAssets(Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)Instance).Info.Location), "Assets"));
string text = Path.Combine(Paths.BepInExRootPath, "config/");
ConfigFile val = new ConfigFile(text + "TootTally.cfg", true);
AllowSpectate = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Allow Spectate", true, "Allow other players to spectate you while playing.");
ShowSpectatorCount = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Show Spectator Count", true, "Show the number of spectator while playing.");
settingPage = TootTallySettingsManager.AddNewPage("Spectator", "Spectator", 40f, new Color(0f, 0f, 0f, 0f));
settingPage.AddToggle("AllowSpectate", new Vector2(400f, 50f), "Allow Spectate", AllowSpectate, (UnityAction<bool>)SpectatingManager.OnAllowHostConfigChange);
settingPage.AddToggle("ShowSpectatorCount", new Vector2(400f, 50f), "Show Spectator Count", ShowSpectatorCount, (UnityAction<bool>)null);
Plugin.TryAddThunderstoreIconToPageButton(((BaseUnityPlugin)Instance).Info.Location, Name, settingPage);
((Component)this).gameObject.AddComponent<SpectatingManager>();
_harmony.PatchAll(typeof(SpectatingManager.SpectatingManagerPatches));
_harmony.PatchAll(typeof(CompatibilityPatches));
LogInfo("Module loaded!");
}
public void UnloadModule()
{
Object.DestroyImmediate((Object)(object)((Component)this).gameObject.GetComponent<SpectatingManager>());
_harmony.UnpatchSelf();
settingPage.Remove();
LogInfo("Module unloaded!");
}
}
public class SpectatingManager : MonoBehaviour
{
public enum DataType
{
UserState,
SongInfo,
FrameData,
TootData,
NoteData,
SpectatorInfo
}
public enum UserState
{
None,
SelectingSong,
Paused,
Playing,
Restarting,
Quitting,
PointScene,
GettingReady
}
public enum SceneType
{
None,
LevelSelect,
GameController,
HomeController
}
public interface ISocketMessage
{
string dataType { get; }
}
public struct SocketUserState : ISocketMessage
{
public int userState { get; set; }
public string dataType => DataType.UserState.ToString();
}
public struct SocketFrameData : ISocketMessage
{
public float time { get; set; }
public float noteHolder { get; set; }
public float pointerPosition { get; set; }
public string dataType => DataType.FrameData.ToString();
}
public struct SocketTootData : ISocketMessage
{
public float time { get; set; }
public float noteHolder { get; set; }
public bool isTooting { get; set; }
public string dataType => DataType.TootData.ToString();
}
public struct SocketSongInfo : ISocketMessage
{
public string trackRef { get; set; }
public int songID { get; set; }
public float gameSpeed { get; set; }
public float scrollSpeed { get; set; }
public string gamemodifiers { get; set; }
public string dataType => DataType.SongInfo.ToString();
}
public struct SocketNoteData : ISocketMessage
{
public int noteID { get; set; }
public double noteScoreAverage { get; set; }
public bool champMode { get; set; }
public int multiplier { get; set; }
public int totalScore { get; set; }
public bool releasedButtonBetweenNotes { get; set; }
public float health { get; set; }
public int highestCombo { get; set; }
public string dataType => DataType.NoteData.ToString();
}
public struct SocketSpectatorInfo : ISocketMessage
{
public string hostName { get; set; }
public int count { get; set; }
public List<string> spectators { get; set; }
public string dataType => DataType.SpectatorInfo.ToString();
}
public class SocketDataConverter : JsonConverter
{
public override bool CanWrite => false;
public override bool CanConvert(Type objectType)
{
return objectType == typeof(ISocketMessage);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject val = JObject.Load(reader);
object obj = Enum.Parse(typeof(DataType), Extensions.Value<string>((IEnumerable<JToken>)val["dataType"]));
if (1 == 0)
{
}
if (!(obj is DataType))
{
goto IL_00be;
}
switch ((DataType)obj)
{
case DataType.UserState:
break;
case DataType.FrameData:
goto IL_006e;
case DataType.TootData:
goto IL_007e;
case DataType.SongInfo:
goto IL_008e;
case DataType.NoteData:
goto IL_009e;
case DataType.SpectatorInfo:
goto IL_00ae;
default:
goto IL_00be;
}
object result = ((JToken)val).ToObject<SocketUserState>(serializer);
goto IL_00c2;
IL_00c2:
if (1 == 0)
{
}
return result;
IL_00be:
result = null;
goto IL_00c2;
IL_00ae:
result = ((JToken)val).ToObject<SocketSpectatorInfo>(serializer);
goto IL_00c2;
IL_009e:
result = ((JToken)val).ToObject<SocketNoteData>(serializer);
goto IL_00c2;
IL_007e:
result = ((JToken)val).ToObject<SocketTootData>(serializer);
goto IL_00c2;
IL_006e:
result = ((JToken)val).ToObject<SocketFrameData>(serializer);
goto IL_00c2;
IL_008e:
result = ((JToken)val).ToObject<SocketSongInfo>(serializer);
goto IL_00c2;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
public static class SpectatingManagerPatches
{
private static LevelSelectController _levelSelectControllerInstance;
private static GameController _gameControllerInstance;
private static PointSceneController _pointSceneControllerInstance;
private static UserState _lastSpecState = UserState.None;
private static UserState _currentSpecState = UserState.None;
private static List<SocketFrameData> _frameData = new List<SocketFrameData>();
private static List<SocketTootData> _tootData = new List<SocketTootData>();
private static List<SocketNoteData> _noteData = new List<SocketNoteData>();
private static SocketFrameData _lastFrame;
private static SocketFrameData _currentFrame;
private static SocketTootData _currentTootData;
private static SocketNoteData _currentNoteData;
private static SocketSongInfo _lastSongInfo;
private static SocketSongInfo _currentSongInfo;
private static TromboneTrack _lastTrackData;
private static bool _isTooting;
private static int _frameIndex;
private static int _tootIndex;
private static bool _waitingToSync;
private static bool _spectatingStarting;
private static bool _wasSpectating;
private const float SYNC_BUFFER = 1f;
private static bool _lastIsTooting;
private static float _specTracktime;
private static float _elapsedTime;
private static bool _isQuickRestarting;
private static readonly float _targetFramerate = ((Application.targetFrameRate > 60 || Application.targetFrameRate < 1) ? 60 : Application.targetFrameRate);
private static SocketSongInfo _lastHostSongInfo;
private static UserState _currentHostState;
private static UserState _lastHostState;
[HarmonyPatch(typeof(HomeController), "Start")]
[HarmonyPostfix]
public static void InitOverlay()
{
SpectatingOverlay.Initialize();
}
[HarmonyPatch(typeof(LevelSelectController), "Start")]
[HarmonyPostfix]
public static void SetLevelSelectUserStatusOnAdvanceSongs(LevelSelectController __instance)
{
_gameControllerInstance = null;
_pointSceneControllerInstance = null;
_levelSelectControllerInstance = __instance;
_spectatingStarting = false;
_lastSongInfo.trackRef = "";
_wasSpectating = false;
if (IsHosting)
{
SetCurrentUserState(UserState.SelectingSong);
}
else if (IsSpectating)
{
SpectatingOverlay.SetCurrentUserState(UserState.SelectingSong);
}
else if (Plugin.Instance.AllowSpectate.Value && TootTallyUser.userInfo.id != 0)
{
CreateUniqueSpectatingConnection(TootTallyUser.userInfo.id, TootTallyUser.userInfo.username);
SpectatingOverlay.HideViewerIcon();
}
SpectatingOverlay.HidePauseText();
SpectatingOverlay.HideMarquee();
}
[HarmonyPatch(typeof(GameController), "Start")]
[HarmonyPostfix]
public static void OnGameControllerStart(GameController __instance)
{
if (IsHosting && _currentHostState != UserState.GettingReady)
{
if (_lastHostSongInfo.trackRef != "")
{
hostedSpectatingSystem.SendSongInfoToSocket(_lastHostSongInfo);
}
SetCurrentUserState(UserState.GettingReady);
}
_isQuickRestarting = false;
_pointSceneControllerInstance = null;
_levelSelectControllerInstance = null;
_gameControllerInstance = __instance;
_waitingToSync = (_wasSpectating = IsSpectating);
if (IsSpectating)
{
_frameIndex = 0;
_tootIndex = 0;
_lastFrame.time = 0f;
float num2 = (_currentFrame.pointerPosition = 0f);
float time = (_currentFrame.noteHolder = num2);
_currentFrame.time = time;
time = (_currentFrame.noteHolder = 0f);
_currentTootData.time = time;
_currentTootData.isTooting = false;
_isTooting = false;
_elapsedTime = 0f;
if (_lastTrackData != null)
{
SpectatingOverlay.ShowMarquee(_spectatingSystemList.Last().spectatorName, _lastTrackData.trackname_short, _lastSongInfo.gameSpeed, _lastSongInfo.gamemodifiers);
}
}
}
[HarmonyPatch(typeof(GameController), "playsong")]
[HarmonyPrefix]
public static bool OverwriteStartSongIfSyncRequired(GameController __instance)
{
if (!IsSpectating || IsHosting)
{
return true;
}
if (ShouldWaitForSync(out _waitingToSync))
{
TootTallyNotifManager.DisplayNotif("Waiting to sync with host...", 6f);
}
return !_waitingToSync;
}
private static bool ShouldWaitForSync(out bool waitForSync)
{
waitForSync = true;
if (_frameData != null && _frameData.Count > 0 && _frameData.Last().time >= 1f && _currentSpecState != UserState.GettingReady && _currentSpecState != UserState.Restarting)
{
SpectatingOverlay.SetCurrentUserState(UserState.Playing);
waitForSync = false;
}
return waitForSync;
}
[HarmonyPatch(typeof(GameController), "playsong")]
[HarmonyPostfix]
public static void SetPlayingUserStatus(GameController __instance)
{
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
if (IsHosting)
{
SetCurrentUserState(UserState.Playing);
}
if (IsSpectating && _frameData != null && _frameData.Count > 0 && _frameData[_frameIndex].time - __instance.musictrack.time >= 1f)
{
Plugin.LogInfo("Syncing track with replay data...");
float specTracktime = (__instance.musictrack.time = _frameData[_frameIndex].time);
_specTracktime = specTracktime;
__instance.noteholderr.anchoredPosition = new Vector2(_frameData[_frameIndex].noteHolder, __instance.noteholderr.anchoredPosition.y);
}
}
[HarmonyPatch(typeof(GameController), "isNoteButtonPressed")]
[HarmonyPostfix]
public static void GameControllerIsNoteButtonPressedPostfixPatch(GameController __instance, ref bool __result)
{
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
if (IsSpectating)
{
__result = _isTooting;
}
else if (IsHosting && _lastIsTooting != __result && !__instance.paused && !__instance.retrying && !__instance.quitting)
{
hostedSpectatingSystem.SendTootData(__instance.musictrack.time - (float)GlobalVariables.localsettings.latencyadjust / 1000f, __instance.noteholderr.anchoredPosition.x, __result);
}
_lastIsTooting = __result;
}
[HarmonyPatch(typeof(PointSceneController), "Start")]
[HarmonyPostfix]
public static void OnPointSceneControllerStartSetInstance(PointSceneController __instance)
{
_levelSelectControllerInstance = null;
_gameControllerInstance = null;
_pointSceneControllerInstance = __instance;
if (IsHosting)
{
SetCurrentUserState(UserState.PointScene);
}
SpectatingOverlay.HideViewerIcon();
SpectatingOverlay.HideStopSpectatingButton();
SpectatingOverlay.HideMarquee();
}
[HarmonyPatch(typeof(PointSceneController), "Update")]
[HarmonyPostfix]
public static void GetOutOfPointSceneIfHostLeft(PointSceneController __instance)
{
if (IsSpectating && _lastSpecState == UserState.PointScene && !__instance.clickedleave)
{
if (_currentSpecState == UserState.SelectingSong)
{
BackToLevelSelect();
}
else if (_currentSpecState == UserState.Playing)
{
RetryFromPointScene();
}
}
}
public static void PlaybackSpectatingData(GameController __instance, float time)
{
Cursor.visible = true;
if (_frameData != null && _tootData != null)
{
if (!__instance.controllermode)
{
__instance.controllermode = true;
}
if (_frameData.Count > 0)
{
PlaybackFrameData(time, __instance);
}
if (_tootData.Count > 0)
{
PlaybackTootData(time);
}
if (_frameData.Count > _frameIndex)
{
InterpolateCursorPosition(time, __instance);
}
}
}
private static void InterpolateCursorPosition(float trackTime, GameController __instance)
{
if (_currentFrame.time - _lastFrame.time > 0f)
{
float num = (trackTime - _lastFrame.time) / (_currentFrame.time - _lastFrame.time);
float num2 = Mathf.Clamp(EasingHelper.Lerp(_lastFrame.pointerPosition, _currentFrame.pointerPosition, num), -300f, 300f);
SetCursorPosition(__instance, num2);
__instance.puppet_humanc.doPuppetControl((0f - num2) / 225f);
}
else
{
SetCursorPosition(__instance, _currentFrame.pointerPosition);
}
}
private static void PlaybackFrameData(float trackTime, GameController __instance)
{
if (_lastFrame.time != _currentFrame.time && trackTime >= _currentFrame.time)
{
_lastFrame = _currentFrame;
}
if (_frameData.Count > _frameIndex && (_currentFrame.time == -1f || trackTime >= _currentFrame.time))
{
_frameIndex = _frameData.FindIndex((_frameIndex > 1) ? (_frameIndex - 1) : 0, (SocketFrameData x) => trackTime < x.time);
if (_frameData.Count > _frameIndex && _frameIndex != -1)
{
_currentFrame = _frameData[_frameIndex];
}
}
}
private static void SetCursorPosition(GameController __instance, float newPosition)
{
//IL_000c: 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_0025: Unknown result type (might be due to invalid IL or missing references)
Vector3 localPosition = __instance.pointer.transform.localPosition;
localPosition.y = newPosition;
__instance.pointer.transform.localPosition = localPosition;
}
public static void OnFrameDataReceived(SocketFrameData frameData)
{
_frameData?.Add(frameData);
}
public static void OnTootDataReceived(SocketTootData tootData)
{
_tootData?.Add(tootData);
}
public static void OnNoteDataReceived(SocketNoteData noteData)
{
_noteData?.Add(noteData);
}
public static void OnSpectatorDataReceived(SocketSpectatorInfo specData)
{
SpectatingOverlay.UpdateViewerList(specData);
}
public static void PlaybackTootData(float trackTime)
{
if (trackTime >= _currentTootData.time && _isTooting != _currentTootData.isTooting)
{
_isTooting = _currentTootData.isTooting;
}
if (_tootData.Count > _tootIndex && trackTime >= _currentTootData.time)
{
_currentTootData = _tootData[_tootIndex++];
}
}
public static void OnSongInfoReceived(SocketSongInfo info)
{
if (info.trackRef == "" || info.gameSpeed <= 0f)
{
Plugin.LogInfo("SongInfo went wrong.");
}
else
{
_lastSongInfo = info;
}
}
public static void OnUserStateReceived(SocketUserState userState)
{
if (IsSpectating)
{
UserStateHandler((UserState)userState.userState);
}
}
private static void UserStateHandler(UserState state)
{
_lastSpecState = _currentSpecState;
_currentSpecState = state;
switch (state)
{
case UserState.SelectingSong:
if ((Object)(object)_pointSceneControllerInstance != (Object)null)
{
BackToLevelSelect();
}
break;
case UserState.Playing:
if ((Object)(object)_levelSelectControllerInstance != (Object)null)
{
TryStartSong();
}
else if ((Object)(object)_gameControllerInstance != (Object)null && _lastSpecState == UserState.Paused)
{
ResumeSong();
}
else if ((Object)(object)_pointSceneControllerInstance != (Object)null)
{
RetryFromPointScene();
}
break;
case UserState.Paused:
if ((Object)(object)_gameControllerInstance != (Object)null)
{
PauseSong();
}
break;
case UserState.Quitting:
if ((Object)(object)_gameControllerInstance != (Object)null && _waitingToSync)
{
ClearSpectatingData();
}
if ((Object)(object)_gameControllerInstance != (Object)null)
{
QuitSong();
}
break;
case UserState.Restarting:
if ((Object)(object)_gameControllerInstance != (Object)null && _waitingToSync)
{
ClearSpectatingData();
}
if ((Object)(object)_gameControllerInstance != (Object)null)
{
RestartSong();
}
break;
case UserState.GettingReady:
if ((Object)(object)_levelSelectControllerInstance != (Object)null)
{
TryStartSong();
}
else if ((Object)(object)_gameControllerInstance != (Object)null)
{
_waitingToSync = true;
}
break;
case UserState.PointScene:
break;
}
}
private static void BackToLevelSelect()
{
_lastSongInfo.trackRef = "";
_pointSceneControllerInstance.clickCont();
}
private static void RetryFromPointScene()
{
ClearSpectatingData();
TootTallyGlobalVariables.gameSpeedMultiplier = _lastSongInfo.gameSpeed;
GlobalVariables.gamescrollspeed = _lastSongInfo.scrollSpeed;
Plugin.LogInfo("ScrollSpeed Set: " + _lastSongInfo.scrollSpeed);
_pointSceneControllerInstance.clickRetry();
}
private static void ClearSpectatingData()
{
_frameData.Clear();
_tootData.Clear();
_noteData.Clear();
_frameIndex = 0;
_tootIndex = 0;
_isTooting = false;
}
private static void TryStartSong()
{
if (_currentSpecState != UserState.SelectingSong)
{
if (_lastSongInfo.trackRef != null)
{
if (!FSharpOption<TromboneTrack>[TrackLookup.tryLookup(_lastSongInfo.trackRef)])
{
_lastTrackData = TrackLookup.lookup(_lastSongInfo.trackRef);
_currentSongInfo = _lastSongInfo;
_spectatingStarting = true;
ClearSpectatingData();
TootTallyGlobalVariables.gameSpeedMultiplier = _lastSongInfo.gameSpeed;
GlobalVariables.gamescrollspeed = _lastSongInfo.scrollSpeed;
Plugin.LogInfo("ScrollSpeed Set: " + _lastSongInfo.scrollSpeed);
GameModifierManager.LoadModifiersFromString(_lastSongInfo.gamemodifiers);
ClickPlay(_lastTrackData);
}
else
{
Plugin.LogInfo("Do not own the song " + _lastSongInfo.trackRef);
TootTallyNotifManager.DisplayNotif("Do not own the song #" + _lastSongInfo.trackRef, 6f);
}
}
else
{
TootTallyNotifManager.DisplayNotif("No SongInfo from host.", 6f);
}
}
else
{
TootTallyNotifManager.DisplayNotif("Waiting for host to start a song.", 6f);
}
}
private static void ClickPlay(TromboneTrack track)
{
_levelSelectControllerInstance.back_clicked = true;
_levelSelectControllerInstance.bgmus.Stop();
_levelSelectControllerInstance.clipPlayer.cancelCrossfades();
_levelSelectControllerInstance.doSfx(_levelSelectControllerInstance.sfx_musend);
LeanTween.moveX(_levelSelectControllerInstance.playbtnobj, 640f, 0.6f).setEaseInQuart();
GlobalVariables.chosen_track = track.trackref;
GlobalVariables.chosen_track_data = TrackLookup.toTrackData(track);
_levelSelectControllerInstance.fadeOut("loader", 0.65f);
}
private static void ResumeSong()
{
_gameControllerInstance.pausecontroller.clickResume();
SpectatingOverlay.HidePauseText();
}
private static void PauseSong()
{
if (!_gameControllerInstance.quitting && !_gameControllerInstance.level_finished && _gameControllerInstance.pausecontroller.done_animating && !_gameControllerInstance.freeplay)
{
_isTooting = false;
_gameControllerInstance.notebuttonpressed = false;
_gameControllerInstance.musictrack.Pause();
_gameControllerInstance.sfxrefs.backfromfreeplay.Play();
_gameControllerInstance.puppet_humanc.shaking = false;
_gameControllerInstance.puppet_humanc.stopParticleEffects();
_gameControllerInstance.puppet_humanc.playCameraRotationTween(false);
_gameControllerInstance.paused = true;
_gameControllerInstance.quitting = true;
_gameControllerInstance.pausecanvas.SetActive(true);
_gameControllerInstance.pausecontroller.showPausePanel();
Cursor.visible = true;
if (!_gameControllerInstance.track_is_pausable)
{
_gameControllerInstance.curtainc.closeCurtain(false);
}
}
}
public static void QuitSong()
{
_gameControllerInstance.quitting = true;
ClearSpectatingData();
_gameControllerInstance.pauseQuitLevel();
SpectatingOverlay.HidePauseText();
SpectatingOverlay.HideMarquee();
SpectatingOverlay.HideStopSpectatingButton();
SpectatingOverlay.HideViewerIcon();
}
private static void RestartSong()
{
ClearSpectatingData();
_waitingToSync = IsSpectating;
_gameControllerInstance.quitting = true;
_gameControllerInstance.pauseRetryLevel();
SpectatingOverlay.HidePauseText();
SpectatingOverlay.HideMarquee();
SpectatingOverlay.HideStopSpectatingButton();
SpectatingOverlay.HideViewerIcon();
}
[HarmonyPatch(typeof(PauseCanvasController), "showPausePanel")]
[HarmonyPrefix]
public static void OnResumeSetUserStatus(PauseCanvasController __instance)
{
if (IsHosting)
{
SetCurrentUserState(UserState.Paused);
}
if (Input.GetKeyDown((KeyCode)27) && IsSpectating)
{
__instance.gc.quitting = true;
__instance.gc.pauseQuitLevel();
StopAllSpectator();
TootTallyNotifManager.DisplayNotif("Stopped spectating.", 6f);
}
else if (IsSpectating)
{
__instance.panelobj.SetActive(false);
SpectatingOverlay.ShowPauseText();
}
}
[HarmonyPatch(typeof(PauseCanvasController), "clickResume")]
[HarmonyPostfix]
public static void OnPauseSetUserStatus()
{
if (IsHosting)
{
SetCurrentUserState(UserState.Playing);
}
}
[HarmonyPatch(typeof(GameController), "pauseQuitLevel")]
[HarmonyPostfix]
public static void OnGameControllerUpdate()
{
if (IsHosting)
{
SetCurrentUserState(UserState.Quitting);
}
else
{
SpectatingOverlay.SetCurrentUserState(UserState.Quitting);
}
}
[HarmonyPatch(typeof(GameController), "getScoreAverage")]
[HarmonyPrefix]
public static void OnGetScoreAveragePrefixSetCurrentNote(GameController __instance)
{
if (IsHosting)
{
hostedSpectatingSystem.SendNoteData(__instance.rainbowcontroller.champmode, __instance.multiplier, __instance.currentnoteindex, __instance.notescoreaverage, __instance.released_button_between_notes, __instance.totalscore, __instance.currenthealth, __instance.highestcombo_level);
}
else
{
if (!IsSpectating)
{
return;
}
if (_noteData.Count > 0 && _noteData.Last().noteID > __instance.currentnoteindex)
{
_currentNoteData = _noteData.Find((SocketNoteData x) => x.noteID == __instance.currentnoteindex);
}
if (_currentNoteData.noteID != -1)
{
__instance.rainbowcontroller.champmode = _currentNoteData.champMode;
__instance.multiplier = _currentNoteData.multiplier;
__instance.notescoreaverage = (float)_currentNoteData.noteScoreAverage;
__instance.released_button_between_notes = _currentNoteData.releasedButtonBetweenNotes;
if (__instance.currentscore < 0)
{
__instance.currentscore = _currentNoteData.totalScore;
}
__instance.totalscore = _currentNoteData.totalScore;
__instance.currenthealth = _currentNoteData.health;
__instance.highestcombo_level = _currentNoteData.highestCombo;
_currentNoteData.noteID = -1;
}
}
}
[HarmonyPatch(typeof(GameController), "Update")]
[HarmonyPostfix]
public static void OnUpdatePlaybackSpectatingData(GameController __instance)
{
//IL_01db: Unknown result type (might be due to invalid IL or missing references)
//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
if (IsSpectating)
{
if (!__instance.quitting && !__instance.retrying && (_currentSpecState == UserState.SelectingSong || _lastSongInfo.trackRef == "" || _currentSongInfo.trackRef == "" || _lastSongInfo.trackRef != _currentSongInfo.trackRef))
{
QuitSong();
}
if (!_waitingToSync && !__instance.paused && !__instance.quitting && !__instance.retrying)
{
_specTracktime += Time.deltaTime * TootTallyGlobalVariables.gameSpeedMultiplier;
if (Math.Abs(__instance.musictrack.time - _specTracktime) > 0.08f)
{
Plugin.LogInfo("Resynced track time...");
_specTracktime = __instance.musictrack.time;
}
PlaybackSpectatingData(__instance, _specTracktime);
}
else if (_waitingToSync && __instance.curtainc.doneanimating && !ShouldWaitForSync(out _waitingToSync))
{
TootTallyNotifManager.DisplayNotif("Finished syncing with host.", 6f);
__instance.startSong(false);
}
}
else if (IsHosting && !__instance.paused && !__instance.quitting && !__instance.retrying)
{
_elapsedTime += Time.deltaTime;
if (_elapsedTime >= 1f / _targetFramerate)
{
_elapsedTime = 0f;
hostedSpectatingSystem.SendFrameData(__instance.musictrack.time - (float)GlobalVariables.localsettings.latencyadjust / 1000f, __instance.noteholderr.anchoredPosition.x, __instance.pointer.transform.localPosition.y);
}
}
else if (IsHosting && __instance.restarttimer > 0.4f && !_isQuickRestarting)
{
_isQuickRestarting = true;
SetCurrentUserState(UserState.Restarting);
}
}
[HarmonyPatch(typeof(GameController), "pauseRetryLevel")]
[HarmonyPostfix]
public static void OnRetryingSetUserStatus()
{
if (IsHosting)
{
SetCurrentUserState(UserState.Restarting);
}
}
[HarmonyPatch(typeof(LevelSelectController), "clickPlay")]
[HarmonyPostfix]
public static void OnLevelSelectControllerClickPlaySendToSocket(LevelSelectController __instance)
{
SocketSongInfo lastHostSongInfo = default(SocketSongInfo);
lastHostSongInfo.trackRef = __instance.alltrackslist[__instance.songindex].trackref;
lastHostSongInfo.songID = 0;
lastHostSongInfo.gameSpeed = TootTallyGlobalVariables.gameSpeedMultiplier;
lastHostSongInfo.scrollSpeed = GlobalVariables.gamescrollspeed;
lastHostSongInfo.gamemodifiers = GameModifierManager.GetModifiersString();
_lastHostSongInfo = lastHostSongInfo;
if (!IsHosting && !IsSpectating && Plugin.Instance.AllowSpectate.Value && TootTallyUser.userInfo.id != 0)
{
CreateUniqueSpectatingConnection(TootTallyUser.userInfo.id, TootTallyUser.userInfo.username);
}
if (IsHosting)
{
hostedSpectatingSystem.SendSongInfoToSocket(_lastHostSongInfo);
hostedSpectatingSystem.SendUserStateToSocket(UserState.GettingReady);
}
SpectatingOverlay.HideViewerIcon();
}
[HarmonyPatch(typeof(LevelSelectController), "clickPlay")]
[HarmonyPrefix]
public static bool OnLevelSelectControllerClickPlayOverwriteIfSpectating()
{
if (IsSpectating)
{
if (_spectatingStarting)
{
return true;
}
TryStartSong();
return false;
}
return true;
}
[HarmonyPatch(typeof(LevelSelectController), "clickBack")]
[HarmonyPostfix]
public static void OnBackButtonClick()
{
SpectatingOverlay.HideStopSpectatingButton();
SpectatingOverlay.HideViewerIcon();
_levelSelectControllerInstance = null;
if (IsHosting)
{
SetCurrentUserState(UserState.None);
}
}
private static void SetCurrentUserState(UserState userState)
{
_lastHostState = _currentHostState;
_currentHostState = userState;
hostedSpectatingSystem.SendUserStateToSocket(userState);
Plugin.LogInfo($"Current state changed from {_lastHostState} to {_currentHostState}");
SpectatingOverlay.SetCurrentUserState(userState);
}
[HarmonyPatch(typeof(PointSceneController), "doCoins")]
[HarmonyPostfix]
public static void ReplayIndicator(PointSceneController __instance)
{
if (IsSpectating)
{
__instance.tootstext.text = "Spectating Done";
}
}
public static void SendCurrentUserState()
{
hostedSpectatingSystem?.SendUserStateToSocket(_currentHostState);
}
}
public static JsonConverter[] _dataConverter = (JsonConverter[])(object)new JsonConverter[1]
{
new SocketDataConverter()
};
private static List<SpectatingSystem> _spectatingSystemList;
public static SpectatingSystem hostedSpectatingSystem;
public static int[] currentSpectatorIDList;
public static SocketSpectatorInfo nullSpecInfo = new SocketSpectatorInfo
{
count = 0
};
public static bool IsHosting => hostedSpectatingSystem != null && ((WebsocketManager)hostedSpectatingSystem).IsConnected && ((WebsocketManager)hostedSpectatingSystem).IsHost;
public static bool IsSpectating => _spectatingSystemList != null && !IsHosting && _spectatingSystemList.Any((SpectatingSystem x) => ((WebsocketManager)x).IsConnected);
public void Awake()
{
if (_spectatingSystemList == null)
{
_spectatingSystemList = new List<SpectatingSystem>();
}
if (Plugin.Instance.AllowSpectate.Value && TootTallyUser.userInfo != null && TootTallyUser.userInfo.id != 0)
{
CreateUniqueSpectatingConnection(TootTallyUser.userInfo.id, TootTallyUser.userInfo.username);
}
((MonoBehaviour)Plugin.Instance).StartCoroutine((IEnumerator)TootTallyAPIService.GetSpectatorIDList((Action<int[]>)delegate(int[] idList)
{
currentSpectatorIDList = idList;
}));
}
public void Update()
{
_spectatingSystemList?.ForEach(delegate(SpectatingSystem s)
{
s.UpdateStacks();
});
if (Input.GetKey((KeyCode)304) && Input.GetKeyDown((KeyCode)27) && _spectatingSystemList.Count > 0 && !IsHosting)
{
SpectatingOverlay.UpdateViewerList(nullSpecInfo);
SpectatingOverlay.HideStopSpectatingButton();
SpectatingOverlay.HideViewerIcon();
_spectatingSystemList.Last().RemoveFromManager();
}
}
public static void StopAllSpectator()
{
if (_spectatingSystemList != null && _spectatingSystemList.Count > 0)
{
SpectatingOverlay.UpdateViewerList(nullSpecInfo);
SpectatingOverlay.SetCurrentUserState(UserState.None);
int num = 0;
while (num < _spectatingSystemList.Count)
{
RemoveSpectator(_spectatingSystemList[num]);
}
if (hostedSpectatingSystem != null && ((WebsocketManager)hostedSpectatingSystem).IsConnected)
{
hostedSpectatingSystem = null;
}
}
TootTallyGlobalVariables.isSpectating = IsSpectating;
}
public static void CancelPendingConnections()
{
IEnumerable<SpectatingSystem> source = _spectatingSystemList?.Where((SpectatingSystem x) => ((WebsocketManager)x).ConnectionPending);
if (source.Count() > 0)
{
List<SpectatingSystem> canceledSpec = new List<SpectatingSystem>();
source.ToList().ForEach(delegate(SpectatingSystem spec)
{
spec.CancelConnection();
canceledSpec.Add(spec);
});
canceledSpec.ForEach(RemoveSpectator);
}
}
public static SpectatingSystem CreateNewSpectatingConnection(int id, string name)
{
SpectatingSystem spectatingSystem = new SpectatingSystem(id, name);
spectatingSystem.OnWebSocketOpenCallback = OnSpectatingConnect;
_spectatingSystemList.Add(spectatingSystem);
if (id == TootTallyUser.userInfo.id)
{
hostedSpectatingSystem = spectatingSystem;
}
return spectatingSystem;
}
public static void OnSpectatingConnect(SpectatingSystem sender)
{
if (!((WebsocketManager)sender).IsHost)
{
sender.OnSocketSongInfoReceived = SpectatingManagerPatches.OnSongInfoReceived;
sender.OnSocketUserStateReceived = SpectatingManagerPatches.OnUserStateReceived;
sender.OnSocketFrameDataReceived = SpectatingManagerPatches.OnFrameDataReceived;
sender.OnSocketTootDataReceived = SpectatingManagerPatches.OnTootDataReceived;
sender.OnSocketNoteDataReceived = SpectatingManagerPatches.OnNoteDataReceived;
TootTallyNotifManager.DisplayNotif("Waiting for host to pick a song...", 6f);
TootTallyGlobalVariables.isSpectating = true;
}
else
{
OnHostConnection();
SpectatingManagerPatches.SendCurrentUserState();
}
sender.OnSocketSpecInfoReceived = SpectatingManagerPatches.OnSpectatorDataReceived;
}
public static void RemoveSpectator(SpectatingSystem spectator)
{
if (spectator != null)
{
if (((WebsocketManager)spectator).IsConnected)
{
spectator.Disconnect();
}
if (_spectatingSystemList.Contains(spectator))
{
_spectatingSystemList.Remove(spectator);
}
else
{
Plugin.LogInfo("Couldnt find websocket in list.");
}
}
}
public static SpectatingSystem CreateUniqueSpectatingConnection(int id, string name)
{
StopAllSpectator();
return CreateNewSpectatingConnection(id, name);
}
public static void OnAllowHostConfigChange(bool value)
{
if (value && hostedSpectatingSystem == null && TootTallyUser.userInfo.id != 0)
{
CreateUniqueSpectatingConnection(TootTallyUser.userInfo.id, TootTallyUser.userInfo.username);
}
else if (!value && hostedSpectatingSystem != null)
{
RemoveSpectator(hostedSpectatingSystem);
hostedSpectatingSystem = null;
}
}
public static void UpdateSpectatorIDList()
{
((MonoBehaviour)Plugin.Instance).StartCoroutine((IEnumerator)TootTallyAPIService.GetSpectatorIDList((Action<int[]>)delegate(int[] idList)
{
currentSpectatorIDList = idList;
}));
}
public static void OnHostConnection()
{
}
public static bool IsAnyConnectionPending()
{
return _spectatingSystemList.Any((SpectatingSystem x) => ((WebsocketManager)x).ConnectionPending);
}
public static void OnSpectateButtonPress(int id, string name)
{
if (!IsAnyConnectionPending() && (TootTallyUser.userInfo.id != id || !IsHosting))
{
CreateUniqueSpectatingConnection(id, name);
TrombuddiesManager.UpdateUsers();
}
}
}
public static class SpectatingOverlay
{
private static GameObject _overlayCanvas;
private static GameObject _pauseTextHolder;
private static TootTallyAnimation _pauseTextHolderAnimation;
private static TootTallyAnimation _marqueeAnimation;
private static SpectatingViewerIcon _viewerIcon;
private static bool _isInitialized;
private static SpectatingManager.SocketSpectatorInfo _spectatorInfo;
private static SpectatingManager.UserState _currentUserState;
private static CustomButton _stopSpectatingButton;
private static Vector2 _marqueeStartPosition;
private static TMP_Text _marqueeText;
private static bool IsInGameController => _currentUserState == SpectatingManager.UserState.Playing || _currentUserState == SpectatingManager.UserState.Paused;
private static bool IsInLevelSelect => _currentUserState == SpectatingManager.UserState.SelectingSong;
public static void Initialize()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Expected O, but got Unknown
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0088: 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_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_0138: Unknown result type (might be due to invalid IL or missing references)
//IL_013d: Unknown result type (might be due to invalid IL or missing references)
//IL_013e: Unknown result type (might be due to invalid IL or missing references)
//IL_016e: 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_0192: Unknown result type (might be due to invalid IL or missing references)
//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
//IL_01bd: Unknown result type (might be due to invalid IL or missing references)
//IL_01c7: Unknown result type (might be due to invalid IL or missing references)
//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
//IL_01f4: Unknown result type (might be due to invalid IL or missing references)
//IL_0247: 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_0256: Unknown result type (might be due to invalid IL or missing references)
//IL_0257: Unknown result type (might be due to invalid IL or missing references)
//IL_025f: Unknown result type (might be due to invalid IL or missing references)
//IL_0261: Unknown result type (might be due to invalid IL or missing references)
//IL_0262: Unknown result type (might be due to invalid IL or missing references)
//IL_026a: Unknown result type (might be due to invalid IL or missing references)
//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
_overlayCanvas = new GameObject("TootTallySpectatorOverlayCanvas");
_overlayCanvas.SetActive(true);
Object.DontDestroyOnLoad((Object)(object)_overlayCanvas);
Canvas val = _overlayCanvas.AddComponent<Canvas>();
val.renderMode = (RenderMode)0;
val.overrideSorting = true;
val.sortingOrder = 0;
GraphicRaycaster val2 = _overlayCanvas.AddComponent<GraphicRaycaster>();
CanvasScaler val3 = _overlayCanvas.AddComponent<CanvasScaler>();
val3.referenceResolution = new Vector2(1920f, 1080f);
val3.uiScaleMode = (ScaleMode)1;
_stopSpectatingButton = GameObjectFactory.CreateCustomButton(_overlayCanvas.transform, Vector2.zero, new Vector2(200f, 60f), "Stop\nSpectating", "StopSpectatingButton", (Action)OnStopSpectatingButtonClick);
((Component)_stopSpectatingButton).gameObject.SetActive(false);
_marqueeText = GameObjectFactory.CreateSingleText(_overlayCanvas.transform, "SpectatorMarqueeText", "PlaceHolder", new Color(1f, 1f, 1f, 0.75f), (TextFont)0);
_marqueeText.fontSize = 36f;
_marqueeText.rectTransform.anchoredPosition = (_marqueeStartPosition = new Vector2(1300f, 0f));
RectTransform rectTransform = _marqueeText.rectTransform;
RectTransform rectTransform2 = _marqueeText.rectTransform;
Vector2 val4 = default(Vector2);
((Vector2)(ref val4))..ctor(0f, 0.2f);
rectTransform2.anchorMax = val4;
rectTransform.anchorMin = val4;
_marqueeText.rectTransform.pivot = new Vector2(0f, 0.5f);
((Component)_marqueeText).gameObject.SetActive(false);
_viewerIcon = new SpectatingViewerIcon(_overlayCanvas.transform, Vector2.zero, Vector2.one * 80f, "ViewerIcon");
_pauseTextHolder = GameObjectFactory.CreateOverlayPanel(_overlayCanvas.transform, Vector2.zero, new Vector2(1000f, 350f), 8f, "PauseTextOverlay");
_pauseTextHolder.SetActive(false);
((Behaviour)((Component)_pauseTextHolder.transform.Find("FSLatencyPanel")).GetComponent<Image>()).enabled = false;
RectTransform component = _pauseTextHolder.GetComponent<RectTransform>();
Vector2 val6 = (component.pivot = Vector2.one / 2f);
val4 = (component.anchorMax = (component.anchorMin = val6));
GameObject gameObject = ((Component)_pauseTextHolder.transform.Find("FSLatencyPanel/LatencyFG")).gameObject;
GameObjectFactory.DestroyFromParent(gameObject, "title");
GameObjectFactory.DestroyFromParent(gameObject, "subtitle");
GameObjectFactory.DestroyFromParent(gameObject, "MainPage");
TMP_Text val9 = GameObjectFactory.CreateSingleText(gameObject.transform, "PauseText", "Host paused the song.\n Waiting for an action.", Color.white, (TextFont)0);
val9.fontSize = 72f;
val9.alignment = (TextAlignmentOptions)514;
val9.rectTransform.pivot = new Vector2(0f, 0.5f);
_isInitialized = true;
}
public static void UpdateViewerList(SpectatingManager.SocketSpectatorInfo spectatorInfo)
{
if (_isInitialized)
{
_spectatorInfo = spectatorInfo;
_viewerIcon?.UpdateViewerList(spectatorInfo);
UpdateViewIcon();
}
}
public static void SetCurrentUserState(SpectatingManager.UserState newUserState)
{
if (_isInitialized)
{
_currentUserState = newUserState;
UpdateViewIcon();
UpdateStopSpectatingButton();
}
}
public static void OnStopSpectatingButtonClick()
{
if (_isInitialized)
{
if (IsInGameController)
{
SpectatingManager.SpectatingManagerPatches.QuitSong();
}
SpectatingManager.StopAllSpectator();
}
}
public static void UpdateViewIcon()
{
//IL_0077: 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_00b9: 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)
if (_viewerIcon != null && _isInitialized)
{
if (_spectatorInfo.count == 0 || _spectatorInfo.count < 1 || !Plugin.Instance.ShowSpectatorCount.Value)
{
_viewerIcon.Hide();
}
else if (IsInLevelSelect)
{
_viewerIcon.SetAnchorMinMax(new Vector2(0.92f, 0.97f));
_viewerIcon.SetBubblePivot(Vector2.one);
_viewerIcon.Show();
}
else if (IsInGameController)
{
_viewerIcon.SetAnchorMinMax(new Vector2(0.03f, 0.07f));
_viewerIcon.SetBubblePivot(Vector2.zero);
_viewerIcon.Show();
}
else
{
_viewerIcon.Hide();
}
}
}
public static void UpdateStopSpectatingButton()
{
//IL_005c: 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_00b7: 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)
if (_isInitialized)
{
Vector2 val = default(Vector2);
if (IsInLevelSelect && SpectatingManager.IsSpectating)
{
((Component)_stopSpectatingButton).gameObject.SetActive(true);
RectTransform component = ((Component)_stopSpectatingButton).GetComponent<RectTransform>();
RectTransform component2 = ((Component)_stopSpectatingButton).GetComponent<RectTransform>();
((Vector2)(ref val))..ctor(0.14f, 0.88f);
component2.anchorMax = val;
component.anchorMin = val;
}
else if (IsInGameController && SpectatingManager.IsSpectating)
{
((Component)_stopSpectatingButton).gameObject.SetActive(true);
RectTransform component3 = ((Component)_stopSpectatingButton).GetComponent<RectTransform>();
RectTransform component4 = ((Component)_stopSpectatingButton).GetComponent<RectTransform>();
((Vector2)(ref val))..ctor(0.2f, 0.09f);
component4.anchorMax = val;
component3.anchorMin = val;
}
else
{
((Component)_stopSpectatingButton).gameObject.SetActive(false);
}
}
}
public static void ShowViewerIcon()
{
_viewerIcon?.Show();
}
public static void HideViewerIcon()
{
_viewerIcon?.Hide();
}
public static void ShowPauseText()
{
//IL_0026: 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_0058: 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_007c: Expected O, but got Unknown
if (!((Object)(object)_pauseTextHolder == (Object)null))
{
_pauseTextHolder.GetComponent<RectTransform>().anchoredPosition = new Vector2(0f, -1500f);
_pauseTextHolder.SetActive(true);
TootTallyAnimation pauseTextHolderAnimation = _pauseTextHolderAnimation;
if (pauseTextHolderAnimation != null)
{
pauseTextHolderAnimation.Dispose();
}
_pauseTextHolderAnimation = TootTallyAnimationManager.AddNewPositionAnimation(_pauseTextHolder, Vector2.op_Implicit(Vector2.zero), 0.8f, new SecondDegreeDynamicsAnimation(2.25f, 0.94f, 1.15f), (Action<GameObject>)null);
}
}
public static void HidePauseText()
{
if (!((Object)(object)_pauseTextHolder == (Object)null))
{
TootTallyAnimation pauseTextHolderAnimation = _pauseTextHolderAnimation;
if (pauseTextHolderAnimation != null)
{
pauseTextHolderAnimation.Dispose();
}
_pauseTextHolder.SetActive(false);
}
}
public static void ShowStopSpectatingButton()
{
CustomButton stopSpectatingButton = _stopSpectatingButton;
if (stopSpectatingButton != null)
{
((Component)stopSpectatingButton).gameObject.SetActive(true);
}
}
public static void HideStopSpectatingButton()
{
CustomButton stopSpectatingButton = _stopSpectatingButton;
if (stopSpectatingButton != null)
{
((Component)stopSpectatingButton).gameObject.SetActive(false);
}
}
public static void ShowMarquee(string playerName, string songName, float songSpeed, string modifiers)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
_marqueeText.rectTransform.anchoredPosition = _marqueeStartPosition;
_marqueeText.text = "Currently Spectating " + playerName + "\nPlaying " + songName;
if (songSpeed != 1f)
{
TMP_Text marqueeText = _marqueeText;
marqueeText.text += $" [{songSpeed:0.00}x]";
}
if (modifiers != null && modifiers != "None")
{
TMP_Text marqueeText2 = _marqueeText;
marqueeText2.text = marqueeText2.text + " [" + modifiers + "]";
}
AnimateMarquee();
((Component)_marqueeText).gameObject.SetActive(true);
}
public static void AnimateMarquee()
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: 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_001f: 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_0061: Expected O, but got Unknown
_marqueeAnimation = TootTallyAnimationManager.AddNewPositionAnimation(((Component)_marqueeText).gameObject, Vector2.op_Implicit(-_marqueeStartPosition * 1.2f), 30f, new SecondDegreeDynamicsAnimation(0.009f, 0f, 1f), (Action<GameObject>)delegate
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
_marqueeText.rectTransform.anchoredPosition = _marqueeStartPosition;
AnimateMarquee();
});
}
public static void HideMarquee()
{
if (!((Object)(object)_marqueeText == (Object)null))
{
TootTallyAnimation marqueeAnimation = _marqueeAnimation;
if (marqueeAnimation != null)
{
marqueeAnimation.Dispose();
}
((Component)_marqueeText).gameObject.SetActive(false);
}
}
}
public class SpectatingSystem : WebsocketManager
{
private ConcurrentQueue<SpectatingManager.SocketFrameData> _receivedFrameDataQueue;
private ConcurrentQueue<SpectatingManager.SocketTootData> _receivedTootDataQueue;
private ConcurrentQueue<SpectatingManager.SocketNoteData> _receivedNoteDataQueue;
private ConcurrentQueue<SpectatingManager.SocketSongInfo> _receivedSongInfoQueue;
private ConcurrentQueue<SpectatingManager.SocketUserState> _receivedUserStateQueue;
private ConcurrentQueue<SpectatingManager.SocketSpectatorInfo> _receivedSpecInfoQueue;
public Action<SpectatingManager.SocketFrameData> OnSocketFrameDataReceived;
public Action<SpectatingManager.SocketTootData> OnSocketTootDataReceived;
public Action<SpectatingManager.SocketNoteData> OnSocketNoteDataReceived;
public Action<SpectatingManager.SocketUserState> OnSocketUserStateReceived;
public Action<SpectatingManager.SocketSongInfo> OnSocketSongInfoReceived;
public Action<SpectatingManager.SocketSpectatorInfo> OnSocketSpecInfoReceived;
public Action<SpectatingSystem> OnWebSocketOpenCallback;
public string spectatorName;
public string GetSpectatorUserId => ((WebsocketManager)this)._id;
public SpectatingSystem(int id, string name)
: base(id.ToString(), "wss://spec.toottally.com:443/spec/", "1.3.0")
{
spectatorName = name;
_receivedFrameDataQueue = new ConcurrentQueue<SpectatingManager.SocketFrameData>();
_receivedTootDataQueue = new ConcurrentQueue<SpectatingManager.SocketTootData>();
_receivedNoteDataQueue = new ConcurrentQueue<SpectatingManager.SocketNoteData>();
_receivedSongInfoQueue = new ConcurrentQueue<SpectatingManager.SocketSongInfo>();
_receivedUserStateQueue = new ConcurrentQueue<SpectatingManager.SocketUserState>();
_receivedSpecInfoQueue = new ConcurrentQueue<SpectatingManager.SocketSpectatorInfo>();
((WebsocketManager)this).ConnectionPending = true;
((WebsocketManager)this).ConnectToWebSocketServer(((WebsocketManager)this)._url + id, Plugin.GetAPIKey, id == TootTallyUser.userInfo.id);
}
public void SendSongInfoToSocket(string trackRef, int id, float gameSpeed, float scrollSpeed, string gamemodifiers)
{
SpectatingManager.SocketSongInfo socketSongInfo = default(SpectatingManager.SocketSongInfo);
socketSongInfo.trackRef = trackRef;
socketSongInfo.songID = id;
socketSongInfo.gameSpeed = gameSpeed;
socketSongInfo.scrollSpeed = scrollSpeed;
socketSongInfo.gamemodifiers = gamemodifiers;
string text = JsonConvert.SerializeObject((object)socketSongInfo);
((WebsocketManager)this).SendToSocket(text);
}
public void SendSongInfoToSocket(SpectatingManager.SocketSongInfo songInfo)
{
((WebsocketManager)this).SendToSocket(JsonConvert.SerializeObject((object)songInfo));
}
public void SendUserStateToSocket(SpectatingManager.UserState userState)
{
SpectatingManager.SocketUserState socketUserState = default(SpectatingManager.SocketUserState);
socketUserState.userState = (int)userState;
string text = JsonConvert.SerializeObject((object)socketUserState);
((WebsocketManager)this).SendToSocket(text);
}
public void SendNoteData(bool champMode, int multiplier, int noteID, double noteScoreAverage, bool releasedButtonBetweenNotes, int totalScore, float health, int highestCombo)
{
SpectatingManager.SocketNoteData socketNoteData = default(SpectatingManager.SocketNoteData);
socketNoteData.champMode = champMode;
socketNoteData.multiplier = multiplier;
socketNoteData.noteID = noteID;
socketNoteData.noteScoreAverage = noteScoreAverage;
socketNoteData.releasedButtonBetweenNotes = releasedButtonBetweenNotes;
socketNoteData.totalScore = totalScore;
socketNoteData.health = health;
socketNoteData.highestCombo = highestCombo;
SpectatingManager.SocketNoteData socketNoteData2 = socketNoteData;
string text = JsonConvert.SerializeObject((object)socketNoteData2);
((WebsocketManager)this).SendToSocket(text);
}
public void SendFrameData(float time, float noteHolder, float pointerPosition)
{
SpectatingManager.SocketFrameData socketFrameData = default(SpectatingManager.SocketFrameData);
socketFrameData.time = time;
socketFrameData.noteHolder = noteHolder;
socketFrameData.pointerPosition = pointerPosition;
SpectatingManager.SocketFrameData socketFrameData2 = socketFrameData;
string text = JsonConvert.SerializeObject((object)socketFrameData2);
((WebsocketManager)this).SendToSocket(text);
}
public void SendTootData(float time, float noteHolder, bool isTooting)
{
SpectatingManager.SocketTootData socketTootData = default(SpectatingManager.SocketTootData);
socketTootData.time = time;
socketTootData.noteHolder = noteHolder;
socketTootData.isTooting = isTooting;
SpectatingManager.SocketTootData socketTootData2 = socketTootData;
string text = JsonConvert.SerializeObject((object)socketTootData2);
((WebsocketManager)this).SendToSocket(text);
}
protected override void OnDataReceived(object sender, MessageEventArgs e)
{
if (!e.IsText)
{
return;
}
SpectatingManager.ISocketMessage socketMessage;
try
{
socketMessage = JsonConvert.DeserializeObject<SpectatingManager.ISocketMessage>(e.Data, SpectatingManager._dataConverter);
}
catch (Exception)
{
Plugin.LogInfo("Couldn't parse to data: " + e.Data);
return;
}
if (!((WebsocketManager)this).IsHost)
{
if (socketMessage is SpectatingManager.SocketSongInfo item)
{
_receivedSongInfoQueue.Enqueue(item);
}
else if (socketMessage is SpectatingManager.SocketFrameData item2)
{
_receivedFrameDataQueue.Enqueue(item2);
}
else if (socketMessage is SpectatingManager.SocketTootData item3)
{
_receivedTootDataQueue.Enqueue(item3);
}
else if (socketMessage is SpectatingManager.SocketUserState item4)
{
_receivedUserStateQueue.Enqueue(item4);
}
else if (socketMessage is SpectatingManager.SocketNoteData item5)
{
_receivedNoteDataQueue.Enqueue(item5);
}
}
if (socketMessage is SpectatingManager.SocketSpectatorInfo)
{
SpectatingManager.SocketSpectatorInfo item6 = (SpectatingManager.SocketSpectatorInfo)(object)socketMessage;
if (true)
{
Plugin.LogInfo(e.Data);
_receivedSpecInfoQueue.Enqueue(item6);
}
}
}
public void UpdateStacks()
{
if (!((WebsocketManager)this).ConnectionPending)
{
if (OnSocketFrameDataReceived != null && _receivedFrameDataQueue.TryDequeue(out var result))
{
OnSocketFrameDataReceived(result);
}
if (OnSocketTootDataReceived != null && _receivedTootDataQueue.TryDequeue(out var result2))
{
OnSocketTootDataReceived(result2);
}
if (OnSocketSongInfoReceived != null && _receivedSongInfoQueue.TryDequeue(out var result3))
{
OnSocketSongInfoReceived(result3);
}
if (OnSocketUserStateReceived != null && _receivedUserStateQueue.TryDequeue(out var result4))
{
OnSocketUserStateReceived(result4);
}
if (OnSocketNoteDataReceived != null && _receivedNoteDataQueue.TryDequeue(out var result5))
{
OnSocketNoteDataReceived(result5);
}
if (OnSocketSpecInfoReceived != null && _receivedSpecInfoQueue.TryDequeue(out var result6))
{
OnSocketSpecInfoReceived(result6);
}
}
}
protected override void OnWebSocketOpen(object sender, EventArgs e)
{
TootTallyNotifManager.DisplayNotif("Connected to spectating server.", 6f);
OnWebSocketOpenCallback?.Invoke(this);
((WebsocketManager)this).OnWebSocketOpen(sender, e);
}
protected override void OnWebSocketClose(object sender, EventArgs e)
{
if (!((WebsocketManager)this).IsHost)
{
TootTallyGlobalVariables.isSpectating = false;
}
((WebsocketManager)this).OnWebSocketClose(sender, e);
}
public void Disconnect()
{
if (!((WebsocketManager)this).IsHost)
{
TootTallyGlobalVariables.isSpectating = false;
TootTallyNotifManager.DisplayNotif("Disconnected from Spectating server.", 6f);
}
if (((WebsocketManager)this).IsConnected)
{
((WebsocketManager)this).CloseWebsocket();
}
}
public void CancelConnection()
{
((WebsocketManager)this).CloseWebsocket();
}
public void RemoveFromManager()
{
SpectatingManager.RemoveSpectator(this);
}
}
public class SpectatingViewerIcon
{
private GameObject _imageHolder;
private RectTransform _imageRect;
private TMP_Text _text;
private TootTallyAnimation _currentRotAnimation;
private TootTallyAnimation _currentScaleAnimation;
private GameObject _bubble;
private TMP_Text _bubbleText;
private bool _isActive;
private int _lastCount;
public bool isInitialized;
public SpectatingViewerIcon(Transform canvasTransform, Vector2 position, Vector2 size, string name)
{
//IL_000a: 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_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_007c: 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_0103: 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_013c: Unknown result type (might be due to invalid IL or missing references)
_imageHolder = GameObjectFactory.CreateImageHolder(canvasTransform, position, size, AssetManager.GetSprite("SpectatorIcon.png"), name);
((Graphic)_imageHolder.GetComponent<Image>()).color = new Color(1f, 1f, 1f, 0.8f);
_imageHolder.AddComponent<Outline>();
_imageHolder.SetActive(false);
BubblePopupHandler val = _imageHolder.AddComponent<BubblePopupHandler>();
_bubble = GameObjectFactory.CreateBubble(new Vector2(300f, 300f), "ViewerListBubble", "PlaceHolder", new Vector2(0f, 0f), 6, true, 18);
val.Initialize(_bubble, false);
_bubbleText = ((Component)_bubble.transform.Find("Window Body/BubbleText")).GetComponent<TMP_Text>();
_bubbleText.lineSpacing = 40f;
_imageRect = _imageHolder.GetComponent<RectTransform>();
SetAnchorMinMax(new Vector2(0.03f, 0.07f));
_imageRect.anchoredPosition = new Vector2(7f, 0f);
_text = GameObjectFactory.CreateSingleText(_imageHolder.transform, name, "0", Color.white, (TextFont)0);
_text.fontSize = 24f;
_isActive = false;
_lastCount = 0;
}
public void UpdateViewerList(SpectatingManager.SocketSpectatorInfo specInfo)
{
if (specInfo.count == 0)
{
_lastCount = 0;
return;
}
if (_lastCount != specInfo.count)
{
_lastCount = specInfo.count;
_text.text = specInfo.count.ToString();
OnViewerCountChange();
}
_bubbleText.text = GetBubbleStringFromSpecInfo(specInfo);
}
public void OnViewerCountChange()
{
}
private string GetBubbleStringFromSpecInfo(SpectatingManager.SocketSpectatorInfo specInfo)
{
return string.Concat(specInfo.spectators.Select((string name) => name + "\n"));
}
public void SetAnchorMinMax(Vector2 anchor)
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_000d: 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)
RectTransform imageRect = _imageRect;
Vector2 anchorMax = (_imageRect.anchorMin = anchor);
imageRect.anchorMax = anchorMax;
}
public void SetBubblePivot(Vector2 pivot)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
_bubble.GetComponent<RectTransform>().pivot = pivot;
}
private void SetRectToDefault()
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
_imageHolder.transform.eulerAngles = new Vector3(0f, 0f, 260f);
_imageHolder.transform.localScale = Vector2.op_Implicit(Vector2.zero);
}
private void SetRectToFinal()
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
_imageHolder.transform.eulerAngles = new Vector3(0f, 0f, 0f);
_imageHolder.transform.localScale = Vector3.one;
}
public void Show()
{
//IL_0065: 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)
if (!_isActive)
{
_imageHolder.SetActive(true);
TootTallyAnimation currentRotAnimation = _currentRotAnimation;
if (currentRotAnimation != null)
{
currentRotAnimation.Dispose();
}
TootTallyAnimation currentScaleAnimation = _currentScaleAnimation;
if (currentScaleAnimation != null)
{
currentScaleAnimation.Dispose();
}
SetRectToDefault();
_isActive = true;
_currentRotAnimation = TootTallyAnimationManager.AddNewEulerAngleAnimation(_imageHolder, new Vector3(0f, 0f, 0f), 1.5f, GetSecondDegreeAnimation(), (Action<GameObject>)null);
_currentScaleAnimation = TootTallyAnimationManager.AddNewScaleAnimation(_imageHolder, Vector3.one, 1.5f, GetSecondDegreeAnimation(), (Action<GameObject>)delegate
{
OnFinishAnimating();
});
}
}
public void Hide()
{
//IL_005b: 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)
if (_isActive)
{
TootTallyAnimation currentRotAnimation = _currentRotAnimation;
if (currentRotAnimation != null)
{
currentRotAnimation.Dispose();
}
TootTallyAnimation currentScaleAnimation = _currentScaleAnimation;
if (currentScaleAnimation != null)
{
currentScaleAnimation.Dispose();
}
SetRectToFinal();
_isActive = false;
_currentRotAnimation = TootTallyAnimationManager.AddNewEulerAngleAnimation(_imageHolder, new Vector3(0f, 0f, -260f), 1.5f, GetSecondDegreeAnimation(), (Action<GameObject>)null);
_currentScaleAnimation = TootTallyAnimationManager.AddNewScaleAnimation(_imageHolder, Vector2.zero, 1.5f, GetSecondDegreeAnimation(), (Action<GameObject>)delegate
{
OnFinishAnimating();
_imageHolder.SetActive(false);
});
}
}
public void OnFinishAnimating()
{
_currentRotAnimation = null;
_currentScaleAnimation = null;
}
public void ToggleShow()
{
_isActive = !_isActive;
_imageHolder.SetActive(_isActive);
}
public SecondDegreeDynamicsAnimation GetSecondDegreeAnimation()
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
//IL_0015: Expected O, but got Unknown
return new SecondDegreeDynamicsAnimation(2.2f, 0.65f, 1f);
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "TootTallySpectator";
public const string PLUGIN_NAME = "TootTallySpectator";
public const string PLUGIN_VERSION = "1.0.7";
}
}