Decompiled source of TaleSpire Tilt Five v1.0.0
plugins/TaleSpireTiltFive/TaleSpireTiltFive.dll
Decompiled 2 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using DataModel; using HarmonyLib; using TiltFive; using TiltFive.Logging; using Unity.Mathematics; using UnityEngine; using UnityEngine.Experimental.Rendering; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.Rendering; using UnityEngine.Rendering.PostProcessing; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("TiltFiveEditor")] [assembly: AssemblyVersion("0.0.0.0")] namespace TaleSpireTiltFive { internal class HiddenCreatureFilter : MonoBehaviour { internal Func<int> GmSeat = () => 1; internal const string HideVolumeBufferName = "TsHideVolumeCommands"; private readonly List<Renderer> hiddenRenderers = new List<Renderer>(); private readonly List<Renderer> switchedOff = new List<Renderer>(); private float nextRefresh; private int hiddenCreatureCount; private int volumeHiddenCount; private bool loggedActive; private bool loggedOverride; private int errors; private static readonly int ShowOverrideId = Shader.PropertyToID("G_ShowOverride"); private bool overrideSaved; private float savedOverride; private readonly List<(Camera cam, CameraEvent evt, CommandBuffer cb)> detached = new List<(Camera, CameraEvent, CommandBuffer)>(); private readonly Dictionary<Camera, List<(CameraEvent, CommandBuffer)>> boxBuffers = new Dictionary<Camera, List<(CameraEvent, CommandBuffer)>>(); private static readonly CameraEvent[] AllEvents = (CameraEvent[])Enum.GetValues(typeof(CameraEvent)); internal int OverridesApplied { get; private set; } private void OnEnable() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown Camera.onPreCull = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(PreCull)); Camera.onPostRender = (CameraCallback)Delegate.Combine((Delegate?)(object)Camera.onPostRender, (Delegate?)new CameraCallback(PostRender)); } private void OnDisable() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown Camera.onPreCull = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPreCull, (Delegate?)new CameraCallback(PreCull)); Camera.onPostRender = (CameraCallback)Delegate.Remove((Delegate?)(object)Camera.onPostRender, (Delegate?)new CameraCallback(PostRender)); RestoreAll(); } private void Update() { PlayerVisibility.GmSeat = GmSeat; if (Time.unscaledTime < nextRefresh) { return; } nextRefresh = Time.unscaledTime + 0.5f; try { hiddenRenderers.Clear(); hiddenCreatureCount = 0; volumeHiddenCount = 0; CreatureBoardAsset[] array = Object.FindObjectsOfType<CreatureBoardAsset>(); foreach (CreatureBoardAsset val in array) { bool flag = false; try { flag = val.IsExplicitlyHidden; } catch { } bool flag2 = !flag && PlayerVisibility.IsHiddenByVolume(val); if (flag || flag2) { if (flag) { hiddenCreatureCount++; } else { volumeHiddenCount++; } hiddenRenderers.AddRange(((Component)val).GetComponentsInChildren<Renderer>(false)); } } if (hiddenCreatureCount + volumeHiddenCount > 0 && !loggedActive && SeatCameras.Count > 0) { loggedActive = true; TaleSpireTiltFivePlugin.Log.LogInfo((object)$"Hidden filter active: {hiddenCreatureCount} GM-hidden + {volumeHiddenCount} hide-volume creature(s) ({hiddenRenderers.Count} renderers) kept out of non-GM glasses."); } RefreshBoxBuffers(); } catch (Exception ex) { if (errors++ < 10) { TaleSpireTiltFivePlugin.Log.LogWarning((object)("Hidden filter refresh failed: " + ex.Message)); } } } private void RefreshBoxBuffers() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) boxBuffers.Clear(); foreach (Camera eyeCamera in TileRenderHooks.EyeCameras) { if ((Object)(object)eyeCamera == (Object)null) { continue; } List<(CameraEvent, CommandBuffer)> list = null; CameraEvent[] allEvents = AllEvents; foreach (CameraEvent val in allEvents) { CommandBuffer[] commandBuffers = eyeCamera.GetCommandBuffers(val); foreach (CommandBuffer val2 in commandBuffers) { if (val2 != null && val2.name == "TsHideVolumeCommands") { (list ?? (list = new List<(CameraEvent, CommandBuffer)>())).Add((val, val2)); } } } if (list != null) { boxBuffers[eyeCamera] = list; } } } private void PreCull(Camera cam) { //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)cam == (Object)null) { return; } int num = SeatCameras.SeatOf(cam); if (num == 0 || num == GmSeat()) { return; } RestoreAll(); foreach (Renderer hiddenRenderer in hiddenRenderers) { if ((Object)(object)hiddenRenderer != (Object)null && hiddenRenderer.enabled) { hiddenRenderer.enabled = false; switchedOff.Add(hiddenRenderer); } } try { float globalFloat = Shader.GetGlobalFloat(ShowOverrideId); if (globalFloat != 0f) { savedOverride = globalFloat; overrideSaved = true; Shader.SetGlobalFloat(ShowOverrideId, 0f); OverridesApplied++; if (!loggedOverride) { loggedOverride = true; TaleSpireTiltFivePlugin.Log.LogInfo((object)"GM show-hidden override is on; keeping hide-volume contents out of non-GM glasses."); } } } catch (Exception ex) { if (errors++ < 10) { TaleSpireTiltFivePlugin.Log.LogWarning((object)("Show-override filter failed: " + ex.Message)); } } if (!boxBuffers.TryGetValue(cam, out var value)) { return; } foreach (var (val, val2) in value) { try { cam.RemoveCommandBuffer(val, val2); detached.Add((cam, val, val2)); } catch { } } } private void PostRender(Camera cam) { if (SeatCameras.IsEye(cam)) { RestoreAll(); } } private void LateUpdate() { RestoreAll(); } private void RestoreAll() { //IL_0083: 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_009e: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < switchedOff.Count; i++) { if ((Object)(object)switchedOff[i] != (Object)null) { switchedOff[i].enabled = true; } } switchedOff.Clear(); if (overrideSaved) { overrideSaved = false; try { Shader.SetGlobalFloat(ShowOverrideId, savedOverride); } catch { } } for (int j = 0; j < detached.Count; j++) { var (val, val2, val3) = detached[j]; try { if ((Object)(object)val != (Object)null && val3 != null) { val.AddCommandBuffer(val2, val3); } } catch { } } detached.Clear(); } internal string Describe() { return $"hidden={hiddenCreatureCount} inVolumes={volumeHiddenCount} overrides={OverridesApplied}"; } } internal static class TileRenderHooks { internal static readonly List<Camera> EyeCameras = new List<Camera>(); internal static Camera CullCamera; internal static Camera MainCamera; internal static bool WideCulling = true; internal static bool CullHookOk; internal static bool DrawHookOk; private static Harmony harmony; private static int drawCalls; private static bool reportedDraws; internal static bool Active => EyeCameras.Count > 0; internal static void Install() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Expected O, but got Unknown ManualLogSource log = TaleSpireTiltFivePlugin.Log; harmony = new Harmony("com.faaze.talespire.tiltfive"); Type type = AccessTools.TypeByName("Unity.Rendering.FrustumPlanes"); MethodInfo methodInfo = type?.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault((MethodInfo m) => m.Name == "BuildSoaPlanePackets" && m.GetParameters().Length == 2 && m.GetParameters()[0].ParameterType == typeof(Camera)); if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(TileRenderHooks), "BuildPlanesPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); CullHookOk = true; log.LogInfo((object)("Hooked " + type.FullName + ".BuildSoaPlanePackets(Camera, ...) for wide culling.")); } else { log.LogWarning((object)"FrustumPlanes.BuildSoaPlanePackets(Camera, ...) not found; tiles outside TaleSpire's own view will be culled in the glasses."); } Type type2 = AccessTools.TypeByName("BoardPresentation"); MethodInfo methodInfo2 = ((type2 != null) ? AccessTools.Method(type2, "CullAndRender", (Type[])null, (Type[])null) : null); if (methodInfo2 != null) { harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(TileRenderHooks), "CullAndRenderTranspiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); log.LogInfo((object)"Hooked BoardPresentation.CullAndRender tile draws for the eye cameras."); } else { log.LogWarning((object)"BoardPresentation.CullAndRender not found; tiles won't render in the glasses."); } } private static void BuildPlanesPrefix(ref Camera cam) { if (WideCulling && Active && (Object)(object)CullCamera != (Object)null && (Object)(object)cam != (Object)null && (Object)(object)cam == (Object)(object)MainCamera) { cam = CullCamera; } } private static IEnumerable<CodeInstruction> CullAndRenderTranspiler(IEnumerable<CodeInstruction> instructions) { MethodInfo replacement = AccessTools.Method(typeof(TileRenderHooks), "DrawForAllCameras", (Type[])null, (Type[])null); int replaced = 0; foreach (CodeInstruction instruction in instructions) { if ((instruction.opcode == OpCodes.Call || instruction.opcode == OpCodes.Callvirt) && instruction.operand is MethodInfo methodInfo && methodInfo.DeclaringType == typeof(Graphics) && methodInfo.Name == "DrawMeshInstancedIndirect" && methodInfo.GetParameters().Length == 12) { instruction.opcode = OpCodes.Call; instruction.operand = replacement; replaced++; } yield return instruction; } DrawHookOk = replaced > 0; TaleSpireTiltFivePlugin.Log.LogInfo((object)$"CullAndRender transpiler replaced {replaced} tile draw call(s)."); if (replaced == 0) { TaleSpireTiltFivePlugin.Log.LogWarning((object)"Tile draw hook found no draw calls to patch; TaleSpire may have changed. Tiles will be missing in the glasses."); } } public static void DrawForAllCameras(Mesh mesh, int submeshIndex, Material material, Bounds bounds, ComputeBuffer bufferWithArgs, int argsOffset, MaterialPropertyBlock properties, ShadowCastingMode castShadows, bool receiveShadows, int layer, Camera camera, LightProbeUsage lightProbeUsage) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0056: 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) Graphics.DrawMeshInstancedIndirect(mesh, submeshIndex, material, bounds, bufferWithArgs, argsOffset, properties, castShadows, receiveShadows, layer, camera, lightProbeUsage); if ((Object)(object)camera == (Object)null || !Active) { return; } for (int i = 0; i < EyeCameras.Count; i++) { Camera val = EyeCameras[i]; if (!((Object)(object)val == (Object)null) && ((Behaviour)val).isActiveAndEnabled) { Graphics.DrawMeshInstancedIndirect(mesh, submeshIndex, material, bounds, bufferWithArgs, argsOffset, properties, castShadows, receiveShadows, layer, val, lightProbeUsage); drawCalls++; } } if (!reportedDraws && drawCalls > 0) { reportedDraws = true; TaleSpireTiltFivePlugin.Log.LogInfo((object)$"Tile draws are now being issued for {EyeCameras.Count} eye camera(s)."); } } } internal static class TaleSpireOps { internal static bool CanEdit(out string why) { why = null; try { if (!InBoard()) { why = "not in a board"; return false; } if (!IsGm()) { why = "TaleSpire isn't in GM mode"; return false; } return true; } catch (Exception ex) { why = ex.Message; return false; } } [MethodImpl(MethodImplOptions.NoInlining)] private static bool InBoard() { return BoardSessionManager.InBoard; } [MethodImpl(MethodImplOptions.NoInlining)] private static bool IsGm() { return LocalClient.IsInGmMode; } internal static HashSet<string> CreatureIds() { //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) HashSet<string> hashSet = new HashSet<string>(); CreatureBoardAsset[] array = Object.FindObjectsOfType<CreatureBoardAsset>(); foreach (CreatureBoardAsset val in array) { try { hashSet.Add(((object)val.CreatureId/*cast due to .constrained prefix*/).ToString()); } catch { } } return hashSet; } } internal static class SeatCameras { private static readonly Dictionary<Camera, int> eyeSeat = new Dictionary<Camera, int>(); internal static int Count => eyeSeat.Count; internal static void Refresh(int playerCount) { eyeSeat.Clear(); for (int i = 1; i <= Mathf.Clamp(playerCount, 1, 4); i++) { PlayerIndex playerIndex = (PlayerIndex)i; try { if (Player.IsConnected(playerIndex)) { Camera leftEye = Glasses.GetLeftEye(playerIndex); Camera rightEye = Glasses.GetRightEye(playerIndex); if ((Object)(object)leftEye != (Object)null) { eyeSeat[leftEye] = i; } if ((Object)(object)rightEye != (Object)null) { eyeSeat[rightEye] = i; } } } catch { } } } internal static int SeatOf(Camera cam) { if (!((Object)(object)cam != (Object)null) || !eyeSeat.TryGetValue(cam, out var value)) { return 0; } return value; } internal static bool IsEye(Camera cam) { if ((Object)(object)cam != (Object)null) { return eyeSeat.ContainsKey(cam); } return false; } } internal interface ITable { float SurfaceY { get; } Camera PcCamera { get; } bool FollowCamera { get; set; } string LevelText { get; } float LevelFloorY { get; } Transform BoardFor(int seat); bool IsPersonal(int seat); void SetPersonal(int seat, bool personal); float ZoomFor(int seat); void SetZoomFor(int seat, float zoom); void BoardMovedBy(int seat); float WorldPerCm(int seat); string StepLevel(int direction); string ClearLevel(); void EveryoneToTable(); string SetLevel(int storey); bool IsSeatConnected(int seat); } internal static class CutPlane { internal static bool Broken; internal static bool TryGet(out float height) { height = 0f; if (Broken) { return false; } try { height = GetInner(); return true; } catch (Exception e) { Fail(e); return false; } } internal static bool TrySet(float height) { if (Broken) { return false; } try { SetInner(height); return true; } catch (Exception e) { Fail(e); return false; } } [MethodImpl(MethodImplOptions.NoInlining)] private static float GetInner() { return CameraController.HideHeightPlaneValue; } [MethodImpl(MethodImplOptions.NoInlining)] private static void SetInner(float h) { CameraController.SetHidePlaneHeight(h); } private static void Fail(Exception e) { Broken = true; TaleSpireTiltFivePlugin.Log.LogWarning((object)("TaleSpire cut plane not reachable (" + e.GetType().Name + ": " + e.Message + "); wand level control disabled.")); } } [BepInPlugin("com.faaze.talespire.tiltfive", "TaleSpire Tilt Five", "1.0.0")] public class TaleSpireTiltFivePlugin : BaseUnityPlugin { public const string PluginGuid = "com.faaze.talespire.tiltfive"; public const string PluginName = "TaleSpire Tilt Five"; public const string PluginVersion = "1.0.0"; internal static ManualLogSource Log; internal static TaleSpireTiltFivePlugin Instance; internal ConfigEntry<float> TileSizeCm; internal ConfigEntry<float> TileWorldUnits; internal ConfigEntry<float> BoardZoom; internal ConfigEntry<float> BoardHeight; internal ConfigEntry<bool> FollowCamera; internal ConfigEntry<bool> FollowCameraYaw; internal ConfigEntry<bool> ShowPreview; internal ConfigEntry<bool> ShowOverlay; internal ConfigEntry<string> PerfMode; internal ConfigEntry<float> EyeShadowDistance; internal ConfigEntry<float> EyeLodBias; internal ConfigEntry<bool> EyePostProcessing; internal ConfigEntry<bool> CopyPostProcessing; internal ConfigEntry<bool> MirrorCommandBuffers; internal ConfigEntry<bool> MatchGlassesFramerate; internal ConfigEntry<bool> VerboseDiagnostics; internal ConfigEntry<bool> WideCulling; internal ConfigEntry<float> CullRadius; internal ConfigEntry<int> PlayerCount; internal ConfigEntry<bool> WandControls; internal ConfigEntry<bool> PointerFromEyes; internal ConfigEntry<int> GmSeat; internal ConfigEntry<bool> RestrictToOwnMinis; internal ConfigEntry<bool> HideHiddenFromPlayers; internal ConfigEntry<bool> AllowPersonalView; internal ConfigEntry<float> LevelStep; internal ConfigEntry<float> LevelCutHeight; private TaleSpireRig rig; private void Awake() { //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Expected O, but got Unknown //IL_0435: Unknown result type (might be due to invalid IL or missing references) //IL_0460: Unknown result type (might be due to invalid IL or missing references) //IL_0465: Unknown result type (might be due to invalid IL or missing references) //IL_046d: Unknown result type (might be due to invalid IL or missing references) //IL_0473: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; TileSizeCm = ((BaseUnityPlugin)this).Config.Bind<float>("Scale", "TileSizeCm", 2.54f, "Physical size of one TaleSpire tile on the Tilt Five board, in centimeters. 2.54 = classic 1-inch miniature grid."); TileWorldUnits = ((BaseUnityPlugin)this).Config.Bind<float>("Scale", "TileWorldUnits", 1f, "Size of one TaleSpire tile in Unity world units (TaleSpire tiles are believed to be 1 unit)."); BoardZoom = ((BaseUnityPlugin)this).Config.Bind<float>("Scale", "BoardZoom", 1f, "Extra zoom multiplier. >1 shows more of the map on the board (smaller minis). Adjust live with PageUp/PageDown."); BoardHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Board", "BoardHeight", -0.2f, "World Y height (in tiles) the physical gameboard surface sits at. Lower = scene sits higher above the board. Adjust live with Home/End."); FollowCamera = ((BaseUnityPlugin)this).Config.Bind<bool>("Board", "FollowCamera", true, "Keep the board centered on where the TaleSpire camera is looking. Toggle live with F9."); FollowCameraYaw = ((BaseUnityPlugin)this).Config.Bind<bool>("Board", "FollowCameraYaw", false, "Also rotate the board when the TaleSpire camera rotates. Off = use F10 to align once."); PerfMode = ((BaseUnityPlugin)this).Config.Bind<string>("Performance", "Mode", "Auto", new ConfigDescription("Eye-camera quality. Auto = full quality for 1-2 players, the Fast settings from 3 players up. Quality = always full. Fast = always the Fast settings.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "Auto", "Quality", "Fast" }), Array.Empty<object>())); EyeShadowDistance = ((BaseUnityPlugin)this).Config.Bind<float>("Performance", "EyeShadowDistance", 25f, "Fast mode: shadow distance for the glasses, in tiles (times board zoom)."); EyeLodBias = ((BaseUnityPlugin)this).Config.Bind<float>("Performance", "EyeLodBias", 0.7f, "Fast mode: level-of-detail bias for the glasses (lower = simpler models sooner)."); EyePostProcessing = ((BaseUnityPlugin)this).Config.Bind<bool>("Performance", "EyePostProcessing", false, "Fast mode: keep post-processing (colour grading, bloom) on the glasses."); ShowOverlay = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "ShowOverlay", false, "Frame-time overlay in the corner of the PC screen (fps, per-eye render time, players, health). Toggle live with F3."); ShowPreview = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "ShowPreview", true, "Draw a picture-in-picture mirror of the left eye in the corner of the TaleSpire window. Toggle live with F11."); CopyPostProcessing = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "CopyPostProcessing", true, "Clone TaleSpire's PostProcessLayer onto the eye cameras (color grading, bloom, fog)."); MirrorCommandBuffers = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "MirrorCommandBuffers", true, "Copy TaleSpire's per-camera command buffers (its custom lights, decals, cut caps) onto the eye cameras."); WideCulling = ((BaseUnityPlugin)this).Config.Bind<bool>("Rendering", "WideCulling", true, "While the glasses are active, cull TaleSpire's tiles against a wide area around the board instead of only TaleSpire's own camera view."); CullRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Rendering", "CullRadius", 80f, "Radius (in tiles, multiplied by board zoom) around the board center that stays rendered while the glasses are active."); PlayerCount = ((BaseUnityPlugin)this).Config.Bind<int>("Players", "PlayerCount", 4, "How many Tilt Five glasses (players) to support at once, 1-4. Each extra player adds two eye renders."); WandControls = ((BaseUnityPlugin)this).Config.Bind<bool>("Players", "WandControls", true, "Let each player point with their wand and pick up / move minis (trigger = grab/drop, B = cancel)."); PointerFromEyes = ((BaseUnityPlugin)this).Config.Bind<bool>("Players", "PointerFromEyes", true, "Wand selection ray goes from the player's eyes through the wand tip onto the board. Off = straight out of the wand tip."); GmSeat = ((BaseUnityPlugin)this).Config.Bind<int>("Players", "GmSeat", 1, "Which Tilt Five player (1-4) is the GM. The GM can move any mini, assign owners (A), move the board (hold 2 / hold 1 + stick) and sees GM-hidden creatures."); RestrictToOwnMinis = ((BaseUnityPlugin)this).Config.Bind<bool>("Players", "RestrictToOwnMinis", true, "Players can only pick up minis the GM has assigned to them. Off = anyone can move any visible mini."); HideHiddenFromPlayers = ((BaseUnityPlugin)this).Config.Bind<bool>("Players", "HideHiddenFromPlayers", true, "Keep GM-hidden creatures out of the non-GM players' glasses."); AllowPersonalView = ((BaseUnityPlugin)this).Config.Bind<bool>("Players", "AllowPersonalView", true, "Players can press Y to unlock their own board and move around the scene on their own (Y again = back to the table view)."); LevelStep = ((BaseUnityPlugin)this).Config.Bind<float>("Levels", "LevelStep", 2.5f, "Height of one storey in tiles, for the GM's X / Y level buttons (2.5 = a floor tile plus a standard 2-high wall)."); LevelCutHeight = ((BaseUnityPlugin)this).Config.Bind<float>("Levels", "LevelCutHeight", 2.25f, "How far above the current level's floor TaleSpire's cut plane goes: everything higher (roof, upper storeys) is hidden."); MatchGlassesFramerate = ((BaseUnityPlugin)this).Config.Bind<bool>("Display", "MatchGlassesFramerate", true, "Let the Tilt Five SDK set the frame-rate cap to match the glasses."); VerboseDiagnostics = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "VerboseDiagnostics", true, "Log cameras, command buffers and TaleSpire camera-controller members to help with development."); LogFix.Apply(); Installer.Run(); try { TileRenderHooks.Install(); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Failed to install TaleSpire render hooks: {arg}"); } Log.LogInfo((object)string.Format("{0} {1} loading (Unity {2}, gfx {3}).", "TaleSpire Tilt Five", "1.0.0", Application.unityVersion, SystemInfo.graphicsDeviceType)); Application.quitting += OnQuit; GameObject val = new GameObject("TaleSpireTiltFive Bootstrap") { hideFlags = (HideFlags)61 }; Object.DontDestroyOnLoad((Object)val); val.AddComponent<Bootstrapper>().Plugin = this; } private static void OnQuit() { try { if (!NativePlugin.DetectedMissingDLL) { NativePlugin.UnloadWorkaround(); } } catch (Exception ex) { ManualLogSource log = Log; if (log != null) { log.LogWarning((object)("UnloadWorkaround failed: " + ex.Message)); } } } private void OnDestroy() { ManualLogSource log = Log; if (log != null) { log.LogInfo((object)"Plugin component destroyed (expected in some games; rig keeps running on its own object)."); } } internal void CreateRig(Camera main) { //IL_002a: 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_0050: 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_0085: Expected O, but got Unknown ManualLogSource log = Log; object[] obj = new object[5] { ((Object)main).name, main.depth, main.renderingPath, main.allowHDR, null }; Scene scene = ((Component)main).gameObject.scene; obj[4] = ((Scene)(ref scene)).name; log.LogInfo((object)string.Format("Found TaleSpire camera '{0}' (depth {1}, path {2}, hdr {3}, scene '{4}').", obj)); if (VerboseDiagnostics.Value) { Diagnostics.LogCameras(); Diagnostics.LogCameraControllerMembers(); } GameObject val = new GameObject("TaleSpireTiltFive Rig"); ((Object)val).hideFlags = (HideFlags)61; Object.DontDestroyOnLoad((Object)(object)val); rig = val.AddComponent<TaleSpireRig>(); rig.Initialize(this, main); } } internal class Bootstrapper : MonoBehaviour { internal TaleSpireTiltFivePlugin Plugin; private float nextCheck; private float nextReport; private bool done; private void Update() { //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) if (done || Plugin == null || Time.unscaledTime < nextCheck) { return; } nextCheck = Time.unscaledTime + 1f; Camera val = CameraUtil.FindTaleSpireCamera(); if ((Object)(object)val != (Object)null && CameraUtil.LooksLikeGameplayCamera(val)) { done = true; try { Plugin.CreateRig(val); return; } catch (Exception arg) { TaleSpireTiltFivePlugin.Log.LogError((object)$"CreateRig failed: {arg}"); return; } } if (Time.unscaledTime >= nextReport) { nextReport = Time.unscaledTime + 15f; Camera[] allCameras = Camera.allCameras; ManualLogSource log = TaleSpireTiltFivePlugin.Log; Scene activeScene = SceneManager.GetActiveScene(); log.LogInfo((object)($"Waiting for a board camera... scene '{((Scene)(ref activeScene)).name}', {allCameras.Length} active camera(s): " + string.Join(", ", allCameras.Select((Camera c) => $"'{((Object)c).name}'(tag {((Component)c).tag}, rt {(Object)(object)c.targetTexture != (Object)null})")))); } } } internal static class CameraUtil { internal static readonly string[] OurCameraNames = new string[4] { "Left Eye Camera", "Right Eye Camera", "T5 Spectator", "T5 Eye Template" }; internal static bool IsOurs(Camera c) { if ((Object)(object)c != (Object)null) { return OurCameraNames.Contains(((Object)((Component)c).gameObject).name); } return false; } internal static bool LooksLikeGameplayCamera(Camera c) { if ((Object)(object)c != (Object)null && !IsOurs(c) && !c.orthographic) { return ((Behaviour)c).isActiveAndEnabled; } return false; } internal static Camera FindTaleSpireCamera() { Camera main = Camera.main; if ((Object)(object)main != (Object)null && ((Behaviour)main).isActiveAndEnabled && !IsOurs(main)) { return main; } Camera val = null; Camera[] allCameras = Camera.allCameras; foreach (Camera val2 in allCameras) { if (!IsOurs(val2) && !((Object)(object)val2.targetTexture != (Object)null) && ((Object)(object)val == (Object)null || val2.depth > val.depth)) { val = val2; } } return val; } internal static void ApplyLook(Camera eye, Camera source) { //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_001a: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0075: 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) eye.clearFlags = source.clearFlags; eye.backgroundColor = source.backgroundColor; eye.renderingPath = source.renderingPath; eye.allowHDR = source.allowHDR; eye.allowMSAA = source.allowMSAA; eye.depthTextureMode = source.depthTextureMode; eye.useOcclusionCulling = false; eye.cullingMask = source.cullingMask; eye.layerCullDistances = source.layerCullDistances; eye.layerCullSpherical = source.layerCullSpherical; eye.opaqueSortMode = source.opaqueSortMode; eye.transparencySortMode = source.transparencySortMode; eye.stereoTargetEye = (StereoTargetEyeMask)0; } } [DefaultExecutionOrder(-200)] internal class TaleSpireRig : MonoBehaviour, ITable, IRigControl { private TaleSpireTiltFivePlugin plugin; private Camera taleSpireCamera; private GameObject managerObject; private TiltFiveManager2 manager; private GameBoard gameBoard; private Camera spectatorCamera; private Camera eyeTemplate; private Camera cullCamera; private readonly HashSet<Camera> configuredEyes = new HashSet<Camera>(); private readonly Dictionary<Camera, List<KeyValuePair<CameraEvent, CommandBuffer>>> mirroredBuffers = new Dictionary<Camera, List<KeyValuePair<CameraEvent, CommandBuffer>>>(); private float nextEyeScan; private readonly bool[] wasConnected = new bool[4]; private int mirroredSourceCount = -1; private WandInteraction wands; private HiddenCreatureFilter hiddenFilter; private SessionGuard guard; private PerfTuning perf; private SessionFeatures session; private readonly GameBoard[] personalBoards = new GameBoard[4]; private readonly bool[] personal = new bool[4]; private bool levelOn; private float levelY; private float savedCut; private float frameAccum; private float worstFrame; private int frameCount; private Vector3 lastFocus; private static readonly Rect PreviewRect = new Rect(0.68f, 0.02f, 0.3f, 0.3f); private float nextStatus; private float nextSeatScan; private int errorCount; private float lastCullRadius; private static readonly Vector2[] ViewportSamples = (Vector2[])(object)new Vector2[9] { new Vector2(0f, 0f), new Vector2(1f, 0f), new Vector2(0f, 1f), new Vector2(1f, 1f), new Vector2(0.5f, 0f), new Vector2(0.5f, 1f), new Vector2(0f, 0.5f), new Vector2(1f, 0.5f), new Vector2(0.5f, 0.5f) }; private static readonly string[] SkipBufferPrefixes = new string[6] { "Post-processing", "Opaque Only Post-processing", "Deferred Ambient Occlusion", "Deferred Fog", "Glasses HDR", "PixelPicker" }; private int PlayerCountClamped => Mathf.Clamp(plugin.PlayerCount.Value, 1, 4); private float ContentScaleRatio => Mathf.Max(0.01f, plugin.TileSizeCm.Value / Mathf.Max(0.0001f, plugin.TileWorldUnits.Value)); public Camera PcCamera => taleSpireCamera; public float SurfaceY => plugin.BoardHeight.Value + (levelOn ? levelY : 0f); public bool FollowCamera { get { return plugin.FollowCamera.Value; } set { if (plugin.FollowCamera.Value != value) { plugin.FollowCamera.Value = value; TaleSpireTiltFivePlugin.Log.LogInfo((object)$"Follow camera: {value}"); } } } public string LevelText { get { if (!levelOn) { return "All levels"; } float num = Mathf.Max(0.25f, plugin.LevelStep.Value); int num2 = Mathf.RoundToInt(levelY / num); if (num2 != 0) { if (num2 <= 0) { return $"Level {-num2} down"; } return $"Level {num2} up"; } return "Ground level"; } } public float LevelFloorY { get { if (!levelOn) { return 0f; } return levelY; } } public int EyeCameraCount => TileRenderHooks.EyeCameras.Count((Camera c) => (Object)(object)c != (Object)null); internal void Initialize(TaleSpireTiltFivePlugin owner, Camera mainCamera) { plugin = owner; taleSpireCamera = mainCamera; try { BuildRig(); if (plugin.WandControls.Value) { wands = ((Component)this).gameObject.AddComponent<WandInteraction>(); wands.PlayerCount = PlayerCountClamped; wands.BoardHeight = () => SurfaceY; wands.WorldPerTile = () => plugin.TileWorldUnits.Value; wands.HeadThroughTip = () => plugin.PointerFromEyes.Value; wands.RestrictToOwned = () => plugin.RestrictToOwnMinis.Value; wands.GmSeat = () => Mathf.Clamp(plugin.GmSeat.Value, 1, 4); wands.Table = this; wands.AllowPersonalView = () => plugin.AllowPersonalView.Value; wands.OwnersFile = Path.Combine(Paths.ConfigPath, "com.faaze.talespire.tiltfive.owners.txt"); wands.Init(); } perf = ((Component)this).gameObject.AddComponent<PerfTuning>(); perf.Plugin = plugin; perf.PlayerCount = PlayerCountClamped; session = ((Component)this).gameObject.AddComponent<SessionFeatures>(); session.Wands = wands; session.GmSeat = () => Mathf.Clamp(plugin.GmSeat.Value, 1, 4); session.WorldPerTile = () => plugin.TileWorldUnits.Value; session.StartPointsFile = Path.Combine(Paths.ConfigPath, "com.faaze.talespire.tiltfive.startpoints.txt"); session.Init(); if ((Object)(object)wands != (Object)null) { wands.Session = session; } guard = ((Component)this).gameObject.AddComponent<SessionGuard>(); guard.Plugin = plugin; guard.Rig = this; guard.Wands = wands; guard.PlayerCount = PlayerCountClamped; if (plugin.HideHiddenFromPlayers.Value) { hiddenFilter = ((Component)this).gameObject.AddComponent<HiddenCreatureFilter>(); hiddenFilter.GmSeat = () => Mathf.Clamp(plugin.GmSeat.Value, 1, 4); } TaleSpireTiltFivePlugin.Log.LogInfo((object)$"Tilt Five rig created for up to {PlayerCountClamped} player(s). Hotkeys: F6 everyone back to the table view, F7 cycle preview player, F8 recenter, F9 follow on/off, F10 align yaw, PageUp/PageDown zoom, Home/End board height, F11 preview."); } catch (Exception arg) { TaleSpireTiltFivePlugin.Log.LogError((object)$"Failed to build Tilt Five rig: {arg}"); ((Behaviour)this).enabled = false; } } private void BuildRig() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0043: 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_005d: 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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Expected O, but got Unknown //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Expected O, but got Unknown //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Expected O, but got Unknown //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Expected O, but got Unknown //IL_03ae: Unknown result type (might be due to invalid IL or missing references) //IL_03b3: Unknown result type (might be due to invalid IL or missing references) //IL_03b8: Unknown result type (might be due to invalid IL or missing references) //IL_03bd: Unknown result type (might be due to invalid IL or missing references) //IL_0360: Unknown result type (might be due to invalid IL or missing references) //IL_0365: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("T5 GameBoard"); val.transform.SetParent(((Component)this).transform, false); gameBoard = val.AddComponent<GameBoard>(); lastFocus = (Vector3)(((??)ComputeFocusPoint(taleSpireCamera, out var _)) ?? Vector3.zero); val.transform.position = lastFocus; val.transform.rotation = Quaternion.Euler(0f, ((Component)taleSpireCamera).transform.eulerAngles.y, 0f); gameBoard.localScale = Mathf.Max(0.01f, plugin.BoardZoom.Value); GameObject val2 = new GameObject("T5 Eye Template"); val2.SetActive(false); val2.transform.SetParent(((Component)this).transform, false); eyeTemplate = val2.AddComponent<Camera>(); ((Behaviour)eyeTemplate).enabled = true; CameraUtil.ApplyLook(eyeTemplate, taleSpireCamera); if (plugin.CopyPostProcessing.Value) { PostProcessCloner.TryClone(taleSpireCamera, val2); } GameObject val3 = new GameObject("T5 Cull Camera"); val3.transform.SetParent(((Component)this).transform, false); cullCamera = val3.AddComponent<Camera>(); ((Behaviour)cullCamera).enabled = false; cullCamera.aspect = 1f; TileRenderHooks.CullCamera = cullCamera; TileRenderHooks.MainCamera = taleSpireCamera; UpdateCullCamera(); GameObject val4 = new GameObject("T5 Spectator"); val4.transform.SetParent(((Component)this).transform, false); spectatorCamera = val4.AddComponent<Camera>(); spectatorCamera.clearFlags = (CameraClearFlags)2; spectatorCamera.backgroundColor = Color.black; spectatorCamera.cullingMask = 0; spectatorCamera.allowHDR = false; spectatorCamera.allowMSAA = false; ApplyPreviewMode(); managerObject = new GameObject("T5 Manager"); managerObject.SetActive(false); managerObject.transform.SetParent(((Component)this).transform, false); manager = managerObject.AddComponent<TiltFiveManager2>(); manager.supportedPlayerCount = (uint)PlayerCountClamped; manager.graphicsSettings.matchGlassesFramerate = plugin.MatchGlassesFramerate.Value; for (int i = 0; i < 4; i++) { GameObject val5 = new GameObject($"T5 GameBoard P{i + 1} (personal)"); val5.transform.SetParent(((Component)this).transform, false); personalBoards[i] = val5.AddComponent<GameBoard>(); personalBoards[i].localScale = gameBoard.localScale; if (manager.allPlayerSettings[i] == null) { manager.allPlayerSettings[i] = new PlayerSettings(); } PlayerSettings obj = manager.allPlayerSettings[i]; obj.PlayerIndex = (PlayerIndex)(i + 1); obj.gameboardSettings.currentGameBoard = gameBoard; obj.scaleSettings.contentScaleUnit = LengthUnit.Centimeters; obj.scaleSettings.contentScaleRatio = ContentScaleRatio; obj.glassesSettings.cameraTemplate = eyeTemplate; obj.glassesSettings.cloneCameraTemplateChildren = false; obj.glassesSettings.cullingMask = LayerMask.op_Implicit(taleSpireCamera.cullingMask); obj.glassesSettings.friendlyName = "TaleSpire"; } SpectatorSettings spectatorSettings = manager.spectatorSettings; spectatorSettings.spectatorCamera = spectatorCamera; spectatorSettings.spectatedPlayer = PlayerIndex.One; spectatorSettings.glassesMirrorMode = GlassesMirrorMode.LeftEye; spectatorSettings.cullingMask = LayerMask.op_Implicit(0); spectatorSettings.rect = PreviewRect; managerObject.SetActive(true); } private bool ValidSeat(int seat) { if (seat >= 1) { return seat <= 4; } return false; } public bool IsPersonal(int seat) { if (ValidSeat(seat)) { return personal[seat - 1]; } return false; } public Transform BoardFor(int seat) { if (!IsPersonal(seat)) { return ((Component)gameBoard).transform; } return ((Component)personalBoards[seat - 1]).transform; } public float ZoomFor(int seat) { if (!IsPersonal(seat)) { return plugin.BoardZoom.Value; } return personalBoards[seat - 1].localScale; } public void SetZoomFor(int seat, float zoom) { if (IsPersonal(seat)) { personalBoards[seat - 1].localScale = Mathf.Clamp(zoom, 0.05f, 50f); } else { SetZoom(zoom, quiet: true); } } public float WorldPerCm(int seat) { return ZoomFor(seat) / ContentScaleRatio; } public void SetPersonal(int seat, bool on) { //IL_0036: 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) if (ValidSeat(seat) && personal[seat - 1] != on) { GameBoard gameBoard = personalBoards[seat - 1]; if (on) { ((Component)gameBoard).transform.SetPositionAndRotation(((Component)this.gameBoard).transform.position, ((Component)this.gameBoard).transform.rotation); gameBoard.localScale = this.gameBoard.localScale; } personal[seat - 1] = on; PlayerSettings playerSettings = manager.allPlayerSettings[seat - 1]; if (playerSettings != null) { playerSettings.gameboardSettings.currentGameBoard = (on ? gameBoard : this.gameBoard); } TaleSpireTiltFivePlugin.Log.LogInfo((object)(on ? $"Player {seat} unlocked a personal view." : $"Player {seat} is back on the table view.")); } } public void BoardMovedBy(int seat) { if (!IsPersonal(seat) && plugin.FollowCamera.Value) { plugin.FollowCamera.Value = false; TaleSpireTiltFivePlugin.Log.LogInfo((object)$"Player {seat} moved the table board with the wand; follow-camera turned off (F9 or F8 to bring it back)."); } } public string StepLevel(int direction) { if (!CutPlane.TryGet(out var height)) { return "Levels unavailable"; } float num = Mathf.Max(0.25f, plugin.LevelStep.Value); if (!levelOn) { levelOn = true; savedCut = height; levelY = 0f; } else { levelY += (float)direction * num; levelY = Mathf.Clamp(levelY, -20f * num, 40f * num); } CutPlane.TrySet(levelY + plugin.LevelCutHeight.Value); string levelText = LevelText; TaleSpireTiltFivePlugin.Log.LogInfo((object)$"{levelText}: floor y {levelY:0.##}, cut plane {levelY + plugin.LevelCutHeight.Value:0.##}."); return levelText; } public void EveryoneToTable() { for (int i = 1; i <= 4; i++) { SetPersonal(i, on: false); } TaleSpireTiltFivePlugin.Log.LogInfo((object)"Everyone is back on the table view."); } public string SetLevel(int storey) { if (!CutPlane.TryGet(out var height)) { return "Levels unavailable"; } float num = Mathf.Max(0.25f, plugin.LevelStep.Value); if (!levelOn) { levelOn = true; savedCut = height; } levelY = (float)Mathf.Clamp(storey, -20, 40) * num; CutPlane.TrySet(levelY + plugin.LevelCutHeight.Value); TaleSpireTiltFivePlugin.Log.LogInfo((object)$"{LevelText}: floor y {levelY:0.##}, cut plane {levelY + plugin.LevelCutHeight.Value:0.##}."); return LevelText; } public bool IsSeatConnected(int seat) { try { return ValidSeat(seat) && Player.IsConnected((PlayerIndex)seat); } catch { return false; } } public string ClearLevel() { if (!levelOn) { return "All levels"; } levelOn = false; levelY = 0f; CutPlane.TrySet(savedCut); TaleSpireTiltFivePlugin.Log.LogInfo((object)$"Level mode off: cut plane back to {savedCut:0.##}."); return "All levels"; } private void ApplyPreviewMode() { if (!((Object)(object)spectatorCamera == (Object)null) && !((Object)(object)taleSpireCamera == (Object)null)) { spectatorCamera.depth = (plugin.ShowPreview.Value ? (taleSpireCamera.depth + 50f) : (taleSpireCamera.depth - 50f)); } } private void Update() { try { UpdateInner(); } catch (Exception arg) { if (errorCount++ < 20) { TaleSpireTiltFivePlugin.Log.LogError((object)$"Rig update error: {arg}"); } } } private void UpdateInner() { if ((Object)(object)manager == (Object)null) { return; } if ((Object)(object)taleSpireCamera == (Object)null || !((Behaviour)taleSpireCamera).isActiveAndEnabled) { Camera val = CameraUtil.FindTaleSpireCamera(); if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)taleSpireCamera) { taleSpireCamera = val; TaleSpireTiltFivePlugin.Log.LogInfo((object)("TaleSpire camera changed to '" + ((Object)val).name + "'.")); configuredEyes.Clear(); RetargetToCamera(); ApplyPreviewMode(); } if ((Object)(object)taleSpireCamera == (Object)null) { return; } } bool flag = false; for (int i = 0; i < PlayerCountClamped; i++) { if (flag) { break; } try { flag = Player.IsConnected((PlayerIndex)(i + 1)); } catch { } } if ((Object)(object)spectatorCamera != (Object)null && ((Behaviour)spectatorCamera).enabled != flag) { ((Behaviour)spectatorCamera).enabled = flag; } frameAccum += Time.unscaledDeltaTime; frameCount++; worstFrame = Mathf.Max(worstFrame, Time.unscaledDeltaTime); HandleHotkeys(); UpdateBoard(); TileRenderHooks.MainCamera = taleSpireCamera; TileRenderHooks.WideCulling = plugin.WideCulling.Value; UpdateCullCamera(); if (Time.unscaledTime >= nextSeatScan) { nextSeatScan = Time.unscaledTime + 0.5f; SeatCameras.Refresh(PlayerCountClamped); } if (Time.unscaledTime >= nextEyeScan) { nextEyeScan = Time.unscaledTime + 1f; ScanEyeCameras(); ReportConnection(); LogFix.Apply(); } if (Time.unscaledTime >= nextStatus) { nextStatus = Time.unscaledTime + 10f; Diagnostics.LogT5Status(gameBoard, taleSpireCamera, spectatorCamera); float num = ((frameCount > 0) ? (frameAccum / (float)frameCount) : 0f); TaleSpireTiltFivePlugin.Log.LogInfo((object)($"[perf] avg {num * 1000f:0.0} ms ({((num > 0f) ? (1f / num) : 0f):0} fps), worst {worstFrame * 1000f:0.0} ms, eye cameras {TileRenderHooks.EyeCameras.Count}, " + string.Format("hooks cull={0} draw={1}, cull radius {2:0} u, level {3}, personal [{4}]", TileRenderHooks.CullHookOk, TileRenderHooks.DrawHookOk, lastCullRadius, levelOn ? levelY.ToString("0.##") : "off", string.Join("", personal.Select((bool x) => (!x) ? "-" : "P"))) + (((Object)(object)wands != (Object)null) ? (" | " + wands.Describe()) : "") + (((Object)(object)hiddenFilter != (Object)null) ? (" " + hiddenFilter.Describe()) : ""))); frameAccum = 0f; frameCount = 0; worstFrame = 0f; } } private void UpdateCullCamera() { //IL_0028: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0131: 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_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_030a: Unknown result type (might be due to invalid IL or missing references) //IL_0311: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_031d: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_0329: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0177: 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_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_0182: 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_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: 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_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0243: 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_0254: 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_025d: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Unknown result type (might be due to invalid IL or missing references) //IL_0349: Unknown result type (might be due to invalid IL or missing references) //IL_034d: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_035b: Unknown result type (might be due to invalid IL or missing references) //IL_0360: Unknown result type (might be due to invalid IL or missing references) //IL_0367: Unknown result type (might be due to invalid IL or missing references) //IL_036e: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_03bf: Unknown result type (might be due to invalid IL or missing references) //IL_03c1: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_03d0: Unknown result type (might be due to invalid IL or missing references) //IL_03e5: Unknown result type (might be due to invalid IL or missing references) //IL_03ea: Unknown result type (might be due to invalid IL or missing references) //IL_03ef: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)cullCamera == (Object)null || (Object)(object)gameBoard == (Object)null) { return; } Vector3 position = ((Component)gameBoard).transform.position; float num = Mathf.Max(5f, plugin.CullRadius.Value * plugin.TileWorldUnits.Value * gameBoard.localScale); float num2 = position.x - num; float num3 = position.x + num; float num4 = position.z - num; float num5 = position.z + num; List<Vector3> list = new List<Vector3>(ViewportSamples.Length + 16); for (int i = 0; i < 4; i++) { if (personal[i]) { Vector3 position2 = ((Component)personalBoards[i]).transform.position; float num6 = Mathf.Max(5f, plugin.CullRadius.Value * plugin.TileWorldUnits.Value * personalBoards[i].localScale); Vector3[] array = (Vector3[])(object)new Vector3[4] { new Vector3(num6, 0f, 0f), new Vector3(0f - num6, 0f, 0f), new Vector3(0f, 0f, num6), new Vector3(0f, 0f, 0f - num6) }; foreach (Vector3 val in array) { Vector3 val2 = position2 + val; list.Add(val2); num2 = Mathf.Min(num2, val2.x); num3 = Mathf.Max(num3, val2.x); num4 = Mathf.Min(num4, val2.z); num5 = Mathf.Max(num5, val2.z); } } } if ((Object)(object)taleSpireCamera != (Object)null) { Plane val3 = default(Plane); ((Plane)(ref val3))..ctor(Vector3.up, new Vector3(0f, SurfaceY, 0f)); Vector2[] viewportSamples = ViewportSamples; float num7 = default(float); foreach (Vector2 val4 in viewportSamples) { Ray val5 = taleSpireCamera.ViewportPointToRay(new Vector3(val4.x, val4.y, 0f)); Vector3 val6 = ((((Plane)(ref val3)).Raycast(val5, ref num7) && num7 > 0f && num7 < 300f) ? ((Ray)(ref val5)).GetPoint(num7) : ((Ray)(ref val5)).GetPoint(300f)); list.Add(val6); num2 = Mathf.Min(num2, val6.x); num3 = Mathf.Max(num3, val6.x); num4 = Mathf.Min(num4, val6.z); num5 = Mathf.Max(num5, val6.z); } } Vector3 val7 = default(Vector3); ((Vector3)(ref val7))..ctor((num2 + num3) * 0.5f, position.y, (num4 + num5) * 0.5f); float num8 = Vector2.Distance(new Vector2(val7.x, val7.z), new Vector2(position.x, position.z)) + num; foreach (Vector3 item in list) { num8 = Mathf.Max(num8, Vector2.Distance(new Vector2(val7.x, val7.z), new Vector2(item.x, item.z))); } num8 = (lastCullRadius = Mathf.Min(num8 + 2f, 600f)); ((Component)cullCamera).transform.position = val7 + Vector3.up * 500f; ((Component)cullCamera).transform.rotation = Quaternion.LookRotation(Vector3.down, Vector3.forward); cullCamera.fieldOfView = 2f * Mathf.Atan(num8 / 500f) * 57.29578f; cullCamera.nearClipPlane = 1f; cullCamera.farClipPlane = 1000f; } private void RetargetToCamera() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) CameraUtil.ApplyLook(eyeTemplate, taleSpireCamera); PlayerSettings[] allPlayerSettings = manager.allPlayerSettings; foreach (PlayerSettings playerSettings in allPlayerSettings) { if (playerSettings != null) { playerSettings.glassesSettings.cullingMask = LayerMask.op_Implicit(taleSpireCamera.cullingMask); } } PostProcessCloner.Retarget(((Component)eyeTemplate).gameObject, taleSpireCamera); Camera[] array = Resources.FindObjectsOfTypeAll<Camera>(); foreach (Camera val in array) { if (!((Object)(object)val == (Object)null)) { string name = ((Object)((Component)val).gameObject).name; if (name == "Left Eye Camera" || name == "Right Eye Camera") { PostProcessCloner.Retarget(((Component)val).gameObject, taleSpireCamera); } } } } private void HandleHotkeys() { //IL_0076: 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_0050: 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_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) if (Keys.Pressed((KeyCode)288)) { CycleSpectator(); } if (Keys.Pressed((KeyCode)287)) { EveryoneToTable(); } if (Keys.Pressed((KeyCode)289)) { float distance; Vector3? val = ComputeFocusPoint(taleSpireCamera, out distance); if (val.HasValue) { lastFocus = val.Value; ((Component)gameBoard).transform.position = lastFocus; } TaleSpireTiltFivePlugin.Log.LogInfo((object)$"Board recentered at {lastFocus}."); } if (Keys.Pressed((KeyCode)290)) { plugin.FollowCamera.Value = !plugin.FollowCamera.Value; TaleSpireTiltFivePlugin.Log.LogInfo((object)$"Follow camera: {plugin.FollowCamera.Value}"); } if (Keys.Pressed((KeyCode)291)) { ((Component)gameBoard).transform.rotation = Quaternion.Euler(0f, ((Component)taleSpireCamera).transform.eulerAngles.y, 0f); TaleSpireTiltFivePlugin.Log.LogInfo((object)"Board yaw aligned to camera."); } if (Keys.Pressed((KeyCode)278)) { SetBoardHeight(plugin.BoardHeight.Value + 0.05f); } if (Keys.Pressed((KeyCode)279)) { SetBoardHeight(plugin.BoardHeight.Value - 0.05f); } if (Keys.Pressed((KeyCode)280)) { SetZoom(plugin.BoardZoom.Value * 1.25f); } if (Keys.Pressed((KeyCode)281)) { SetZoom(plugin.BoardZoom.Value / 1.25f); } if (Keys.Pressed((KeyCode)292)) { plugin.ShowPreview.Value = !plugin.ShowPreview.Value; ApplyPreviewMode(); } } private void CycleSpectator() { SpectatorSettings spectatorSettings = manager.spectatorSettings; int spectatedPlayer = (int)spectatorSettings.spectatedPlayer; for (int i = 1; i <= PlayerCountClamped; i++) { int num = (spectatedPlayer - 1 + i) % PlayerCountClamped + 1; if (Player.IsConnected((PlayerIndex)num)) { spectatorSettings.spectatedPlayer = (PlayerIndex)num; TaleSpireTiltFivePlugin.Log.LogInfo((object)$"Preview now shows player {num}."); return; } } TaleSpireTiltFivePlugin.Log.LogInfo((object)"No other connected player to preview."); } private void SetBoardHeight(float h) { plugin.BoardHeight.Value = Mathf.Round(Mathf.Clamp(h, -50f, 50f) * 100f) / 100f; TaleSpireTiltFivePlugin.Log.LogInfo((object)$"Board height {plugin.BoardHeight.Value:0.00}"); } public void ApplyScale() { PlayerSettings[] allPlayerSettings = manager.allPlayerSettings; foreach (PlayerSettings playerSettings in allPlayerSettings) { if (playerSettings != null) { playerSettings.scaleSettings.contentScaleRatio = ContentScaleRatio; } } } public void SetZoomLive(float zoom) { SetZoom(zoom, quiet: true); } public void ApplyPreview() { ApplyPreviewMode(); } public void OnBoardChanged(string why) { //IL_0082: 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_0098: Unknown result type (might be due to invalid IL or missing references) levelOn = false; levelY = 0f; for (int i = 1; i <= 4; i++) { SetPersonal(i, on: false); } wands?.ResetForBoard(); if ((Object)(object)taleSpireCamera == (Object)null || !((Behaviour)taleSpireCamera).isActiveAndEnabled) { taleSpireCamera = CameraUtil.FindTaleSpireCamera() ?? taleSpireCamera; } float distance; Vector3? val = ComputeFocusPoint(taleSpireCamera, out distance); if (val.HasValue) { lastFocus = val.Value; ((Component)gameBoard).transform.position = lastFocus; } mirroredSourceCount = -1; TaleSpireTiltFivePlugin.Log.LogInfo((object)("[session] " + why + ": held minis released, menus closed, levels and personal views reset, table board recentred.")); } private void SetZoom(float zoom, bool quiet = false) { zoom = Mathf.Clamp(zoom, 0.05f, 50f); plugin.BoardZoom.Value = zoom; gameBoard.localScale = zoom; if (!quiet) { TaleSpireTiltFivePlugin.Log.LogInfo((object)$"Board zoom {zoom:0.###}"); } } private void UpdateBoard() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_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_0043: 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_0126: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: 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_00e4: Unknown result type (might be due to invalid IL or missing references) if (plugin.FollowCamera.Value) { float distance; Vector3? val = ComputeFocusPoint(taleSpireCamera, out distance); if (val.HasValue) { lastFocus = val.Value; ((Component)gameBoard).transform.position = lastFocus; } } float surfaceY = SurfaceY; Vector3 position = ((Component)gameBoard).transform.position; if (!Mathf.Approximately(position.y, surfaceY)) { ((Component)gameBoard).transform.position = new Vector3(position.x, surfaceY, position.z); } for (int i = 0; i < 4; i++) { if (personal[i]) { Transform transform = ((Component)personalBoards[i]).transform; if (!Mathf.Approximately(transform.position.y, surfaceY)) { transform.position = new Vector3(transform.position.x, surfaceY, transform.position.z); } } } if (plugin.FollowCameraYaw.Value) { ((Component)gameBoard).transform.rotation = Quaternion.Euler(0f, ((Component)taleSpireCamera).transform.eulerAngles.y, 0f); } } private Vector3? ComputeFocusPoint(Camera cam, out float distance) { //IL_001c: 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_0043: 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_005a: 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) distance = 0f; if ((Object)(object)cam == (Object)null) { return null; } Plane val = default(Plane); ((Plane)(ref val))..ctor(Vector3.up, new Vector3(0f, SurfaceY, 0f)); Ray val2 = default(Ray); ((Ray)(ref val2))..ctor(((Component)cam).transform.position, ((Component)cam).transform.forward); if (((Plane)(ref val)).Raycast(val2, ref distance) && distance > 0f && distance < 5000f) { return ((Ray)(ref val2)).GetPoint(distance); } return null; } private int CountMirrorableBuffers() { //IL_001f: 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_002b: Unknown result type (might be due to invalid IL or missing references) int num = 0; foreach (CameraEvent value in Enum.GetValues(typeof(CameraEvent))) { CommandBuffer[] commandBuffers = taleSpireCamera.GetCommandBuffers(value); foreach (CommandBuffer cb in commandBuffers) { if (!SkipBufferPrefixes.Any((string p) => (cb.name ?? "").StartsWith(p))) { num++; } } } return num; } private void ScanEyeCameras() { //IL_01ae: 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_01c5: Unknown result type (might be due to invalid IL or missing references) TileRenderHooks.EyeCameras.RemoveAll((Camera c) => (Object)(object)c == (Object)null); configuredEyes.RemoveWhere((Camera c) => (Object)(object)c == (Object)null); foreach (Camera item in mirroredBuffers.Keys.Where((Camera c) => (Object)(object)c == (Object)null).ToList()) { mirroredBuffers.Remove(item); } if (plugin.MirrorCommandBuffers.Value && (Object)(object)taleSpireCamera != (Object)null) { int num = CountMirrorableBuffers(); if (mirroredSourceCount >= 0 && num != mirroredSourceCount) { TaleSpireTiltFivePlugin.Log.LogInfo((object)$"TaleSpire camera buffers changed ({mirroredSourceCount} -> {num}); re-mirroring onto {configuredEyes.Count} eye camera(s)."); foreach (Camera configuredEye in configuredEyes) { MirrorBuffers(configuredEye); } } mirroredSourceCount = num; } Camera[] array = Resources.FindObjectsOfTypeAll<Camera>(); foreach (Camera val in array) { if ((Object)(object)val == (Object)null || configuredEyes.Contains(val)) { continue; } Scene scene = ((Component)val).gameObject.scene; if (((Scene)(ref scene)).name == null && (int)((Object)((Component)val).gameObject).hideFlags == 0) { continue; } string name = ((Object)((Component)val).gameObject).name; if (!(name != "Left Eye Camera") || !(name != "Right Eye Camera")) { CameraUtil.ApplyLook(val, taleSpireCamera); if (!TileRenderHooks.EyeCameras.Contains(val)) { TileRenderHooks.EyeCameras.Add(val); } if (plugin.MirrorCommandBuffers.Value) { MirrorBuffers(val); } configuredEyes.Add(val); TaleSpireTiltFivePlugin.Log.LogInfo((object)("Configured eye camera '" + name + "' (target " + (Object.op_Implicit((Object)(object)val.targetTexture) ? (((Texture)val.targetTexture).width + "x" + ((Texture)val.targetTexture).height) : "none") + ").")); if (plugin.VerboseDiagnostics.Value && configuredEyes.Count == 1) { Diagnostics.LogCommandBuffers(taleSpireCamera, "TaleSpire camera"); } } } } private void MirrorBuffers(Camera eye) { //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_0080: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) if (mirroredBuffers.TryGetValue(eye, out var value)) { foreach (KeyValuePair<CameraEvent, CommandBuffer> item in value) { eye.RemoveCommandBuffer(item.Key, item.Value); } } List<KeyValuePair<CameraEvent, CommandBuffer>> list = new List<KeyValuePair<CameraEvent, CommandBuffer>>(); foreach (CameraEvent value2 in Enum.GetValues(typeof(CameraEvent))) { CommandBuffer[] commandBuffers = taleSpireCamera.GetCommandBuffers(value2); foreach (CommandBuffer cb in commandBuffers) { if (!SkipBufferPrefixes.Any((string p) => (cb.name ?? "").StartsWith(p))) { eye.AddCommandBuffer(value2, cb); list.Add(new KeyValuePair<CameraEvent, CommandBuffer>(value2, cb)); } } } mirroredBuffers[eye] = list; TaleSpireTiltFivePlugin.Log.LogInfo((object)$"Mirrored {list.Count} command buffer(s) onto '{((Object)eye).name}'."); } private void ReportConnection() { for (int i = 0; i < PlayerCountClamped; i++) { bool flag = false; try { flag = Player.IsConnected((PlayerIndex)(i + 1)); } catch { } if (flag != wasConnected[i]) { wasConnected[i] = flag; TaleSpireTiltFivePlugin.Log.LogInfo((object)(flag ? $"Tilt Five glasses connected (player {i + 1})." : $"Tilt Five glasses disconnected (player {i + 1}).")); } } } } internal static class Keys { private static bool legacyBroken; private static readonly Dictionary<KeyCode, Key> map = new Dictionary<KeyCode, Key>(); internal static bool Pressed(KeyCode key) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return Query(key, held: false); } internal static bool Held(KeyCode key) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return Query(key, held: true); } private static bool Query(KeyCode key, bool held) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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) try { Keyboard current = Keyboard.current; if (current != null) { Key val = ToInputSystemKey(key); if ((int)val != 0) { return held ? ((ButtonControl)current[val]).isPressed : ((ButtonControl)current[val]).wasPressedThisFrame; } } } catch { } if (legacyBroken) { return false; } try { return held ? Input.GetKey(key) : Input.GetKeyDown(key); } catch (InvalidOperationException) { legacyBroken = true; return false; } } private unsafe static Key ToInputSystemKey(KeyCode key) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_002c: 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_0026: Unknown result type (might be due to invalid IL or missing references) if (!map.TryGetValue(key, out var value)) { if (!Enum.TryParse<Key>(((object)(*(KeyCode*)(&key))/*cast due to .constrained prefix*/).ToString(), out value)) { value = (Key)0; } map[key] = value; } return value; } } internal static class PostProcessCloner { internal static void Retarget(GameObject target, Camera source) { //IL_0030: 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) try { PostProcessLayer component = target.GetComponent<PostProcessLayer>(); if (!((Object)(object)component == (Object)null)) { PostProcessLayer component2 = ((Component)source).GetComponent<PostProcessLayer>(); component.volumeTrigger = ((Component)source).transform; if ((Object)(object)component2 != (Object)null) { component.volumeLayer = component2.volumeLayer; component.fog = component2.fog; } } } catch (Exception ex) { TaleSpireTiltFivePlugin.Log.LogWarning((object)("PostProcessLayer retarget failed: " + ex.Message)); } } internal static void TryClone(Camera source, GameObject target) { //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_0058: Unknown result type (might be due to invalid IL or missing references) try { PostProcessLayer component = ((Component)source).GetComponent<PostProcessLayer>(); if ((Object)(object)component == (Object)null) { TaleSpireTiltFivePlugin.Log.LogInfo((object)"TaleSpire camera has no PostProcessLayer; eye cameras will render without post-processing."); return; } PostProcessLayer val = target.AddComponent<PostProcessLayer>(); val.volumeLayer = component.volumeLayer; val.volumeTrigger = ((Component)source).transform; val.stopNaNPropagation = component.stopNaNPropagation; val.finalBlitToCameraTarget = false; val.antialiasingMode = (Antialiasing)0; val.fog = component.fog; object? obj = typeof(PostProcessLayer).GetField("m_Resources", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(component); PostProcessResources val2 = (PostProcessResources)((obj is PostProcessResources) ? obj : null); if ((Object)(object)val2 != (Object)null) { val.Init(val2); TaleSpireTiltFivePlugin.Log.LogInfo((object)$"Cloned PostProcessLayer (volume layer mask {((LayerMask)(ref val.volumeLayer)).value})."); } else { Object.DestroyImmediate((Object)(object)val); TaleSpireTiltFivePlugin.Log.LogWarning((object)"Could not read PostProcessResources from TaleSpire's camera; skipping post-processing on eye cameras."); } } catch (Exception ex) { TaleSpireTiltFivePlugin.Log.LogWarning((object)("PostProcessLayer clone failed: " + ex.Message)); } } } internal static class LogFix { private static bool announced; internal static void Apply() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Invalid comparison between Unknown and I4 ILogger unityLogger = Debug.unityLogger; if (unityLogger.logEnabled && (int)unityLogger.filterLogType == 3) { return; } unityLogger.logEnabled = true; unityLogger.filterLogType = (LogType)3; if (!announced) { announced = true; ManualLogSource log = TaleSpireTiltFivePlugin.Log; if (log != null) { log.LogInfo((object)"Re-enabled Unity logging (TaleSpire had it off) so SDK messages and exceptions are visible."); } } } } internal static class Diagnostics { internal static void LogT5Status(GameBoard board, Camera tsCam, Camera spectator) { //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) ManualLogSource log = TaleSpireTiltFivePlugin.Log; string text = "?"; try { text = SystemControl.GetServiceCompatibility().ToString(); } catch (Exception ex) { text = "err:" + ex.GetType().Name; } bool flag = false; bool flag2 = false; bool flag3 = false; try { flag = Player.TryGetGlassesHandle(PlayerIndex.One, out var _); } catch { } try { flag2 = Player.IsConnected(PlayerIndex.One); } catch { } try { flag3 = Glasses.IsTracked(); } catch { } List<string> list = new List<string>(); for (int i = 1; i <= 4; i++) { bool flag4 = false; bool flag5 = false; try { flag4 = Player.IsConnected((PlayerIndex)i); flag5 = flag4 && Glasses.IsTracked((PlayerIndex)i); } catch { } if (flag4) { list.Add(string.Format("P{0}{1}", i, flag5 ? "+" : "-")); } } IEnumerable<string> values = from c in Resources.FindObjectsOfTypeAll<Camera>().Where(delegate(Camera c) { //IL_0033: 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) if ((Object)(object)c != (Object)null && (((Object)c).name == "Left Eye Camera" || ((Object)c).name == "Right Eye Camera")) { Scene scene = ((Component)c).gameObject.scene; return ((Scene)(ref scene)).IsValid(); } return false; }) select string.Format("{0}[en={1} rt={2} pos={3:F1} mask=0x{4:X}]", ((Object)c).name, ((Behaviour)c).isActiveAndEnabled, Object.op_Implicit((Object)(object)c.targetTexture) ? (((Texture)c.targetTexture).width + "x" + ((Texture)c.targetTexture).height) : "none", ((Component)c).transform.position, c.cullingMask); int num = (((Object)(object)spectator != (Object)null) ? ((Component)spectator).GetComponents<SplitStereoCamera>().Length : (-1)); string[] obj5 = new string[7] { string.Format("[status] players=[{0}] service={1} handle={2} connected={3} tracked={4} splitStereo={5} ", string.Join(" ", list), text, flag, flag2, flag3, num), "board=", null, null, null, null, null }; object obj6; Vector3 position; if (!Object.op_Implicit((Object)(object)board)) { obj6 = "null"; } else { position = ((Component)board).transform.position; obj6 = ((Vector3)(ref position)).ToString("F1") + " x" + board.localScale.ToString("0.##"); } obj5[2] = (string)obj6; obj5[3] = " tsCam="; object obj7; if (!Object.op_Implicit((Object)(object)tsCam)) { obj7 = "null"; } else { string name = ((Object)tsCam).name; position = ((Component)tsCam).transform.position; obj7 = name + "@" + ((Vector3)(ref position)).ToString("F1"); } obj5[4] = (string)obj7; obj5[5] = " eyes: "; obj5[6] = string.Join(" ", values); log.LogInfo((object)string.Concat(obj5)); } internal static void LogCameras() { //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_00c5: Unknown result type (might be due to invalid IL or missing references) ManualLogSource log = TaleSpireTiltFivePlugin.Log; Camera[] array = Resources.FindObjectsOfTypeAll<Camera>(); foreach (Camera val in array) { Scene scene = ((Component)val).gameObject.scene; if (((Scene)(ref scene)).name != null) { string text = string.Join(", ", from x in ((Component)val).GetComponents<Component>() select (!((Object)(object)x == (Object)null)) ? ((object)x).GetType().Name : "null"); log.LogInfo((object)$"[cam] '{((Object)val).name}' active={((Behaviour)val).isActiveAndEnabled} depth={val.depth} tag={((Component)val).tag} mask=0x{val.cullingMask:X} rt={(Object)(object)val.targetTexture != (Object)null} path={val.renderingPath} comps=[{text}]"); } } } internal static void LogCommandBuffers(Camera cam, string label) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) ManualLogSource log = TaleSpireTiltFivePlugin.Log; int num = 0; foreach (CameraEvent value in Enum.GetValues(typeof(CameraEvent))) { CommandBuffer[] commandBuffers = cam.GetCommandBuffers(value); foreach (CommandBuffer val2 in commandBuffers) { log.LogInfo((object)$"[cmdbuf] {label} {(object)value}: '{val2.name}' ({val2.sizeInBytes} bytes)"); num++; } } log.LogInfo((object)$"[cmdbuf] {label}: {num} buffer(s) total."); } internal static void LogCameraControllerMembers() { ManualLogSource log = TaleSpireTiltFivePlugin.Log; try { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { string name = assembly.GetName().Name; if (!name.StartsWith("Bouncyrock") && name != "Assembly-CSharp") { continue; } Type[] source; try { source = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { source = ex.Types.Where((Type t) => t != null).ToArray(); } foreach (Type item in source.Where((Type t) => t.Name == "CameraController" || t.Name == "ActiveCameraManager")) { log.LogInfo((object)("[ctrl] " + item.FullName + " in " + name)); foreach (FieldInfo item2 in item.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Take(60)) { log.LogInfo((object)("[ctrl] field " + (item2.IsStatic ? "static " : "") + item2.FieldType.Name + " " + item2.Name)); } foreach (PropertyInfo item3 in item.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Take(60)) { log.LogInfo((object)("[ctrl] prop " + item3.PropertyType.Name + " " + item3.Name)); } } } } catch (Exception ex2) { log.LogWarning((object)("Camera controller reflection failed: " + ex2.Message)); } } } internal class SessionFeatures : MonoBehaviour { internal WandInteraction Wands; internal Func<int> GmSeat = () => 1; internal Func<float> WorldPerTile = () => 1f; internal string StartPointsFile; private string currentTurnKey; private float nextTurnPoll; private LineRenderer turnRing; private bool initiativeBroken; private readonly Dictionary<string, Vector3> startPoints = new Dictionary<string, Vector3>(); internal CreatureBoardAsset CurrentTurn { get; private set; } internal bool HasStartPoint { get { string text = SafeBoardKey(); if (text != null) { return startPoints.ContainsKey(text); } return false; } } internal Vector3? StartPoint { get { //IL_0023: Unknown result type (might be due to invalid IL or missing references) string text = SafeBoardKey(); if (text == null || !startPoints.TryGetValue(text, out var value)) { return null; } return value; } } private static string SafeName(CreatureBoardAsset c) { try { return c.Name; } catch { return ((Object)(object)c != (Object)null) ? ((Object)c).name : "?"; } } internal void Init() { //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_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Expected O, but got Unknown Shader val = Shader.Find("Hidden/Internal-Colored"); if ((Object)(object)val != (Object)null) { Material val2 = new Material(val) { hideFlags = (HideFlags)61, renderQueue = 3100 }; val2.SetInt("_SrcBlend", 5); val2.SetInt("_DstBlend", 10); val2.SetInt("_ZWrite", 0); val2.SetInt("_Cull", 0); GameObject val3 = new GameObject("T5 Turn Ring"); val3.transform.SetParent(((Component)this).transform, false); turnRing = val3.AddComponent<LineRenderer>(); ((Renderer)turnRing).sharedMaterial = val2; turnRing.useWorldSpace = true; turnRing.loop = true; turnRing.positionCount = 48; ((Renderer)turnRing).shadowCastingMode = (ShadowCastingMode)0; ((Renderer)turnRing).receiveShadows = false; ((Renderer)turnRing).enabled = false; } LoadStartPoints(); } private void Update() { if (Time.unscaledTime >= nextTurnPoll && !initiativeBroken) { nextTurnPoll = Time.unscaledTime + 0.25f; PollTurn(); } DrawTurnRing(); } private void PollTurn() { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) string text = null; try { text = CurrentTurnCreatureKey(); } catch (Exception ex) { initiativeBroken = true; TaleSpireTiltFivePlugin.Log.LogWarning((object)("Turn indicator off: TaleSpire's initiative tracker isn't readable (" + ex.GetType().Name + ": " + ex.Message + ").")); return; } if (text == currentTurnKey) { return; } currentTurnKey = text; CurrentTurn = null; if (text != null && (Object)(object)Wands != (Object)null) { foreach (CreatureBoardAsset creature in Wands.CreatureList) { try { if ((Object)(object)creature != (Object)null && ((object)creature.CreatureId/*cast due to .constrained prefix*/).ToString() == text) { CurrentTurn = creature; break; } } catch { } } } if (!((Object)(object)CurrentTurn == (Object)null)) { string text2 = SafeName(CurrentTurn); int num = Wands.OwnerOfCreature(CurrentTurn); bool flag = false; flag = PlayerVisibility.IsHiddenFromPlayers(CurrentTurn); TaleSpireTiltFivePlugin.Log.LogInfo((object)("[turn] " + text2 + "'s turn" + ((num > 0) ? $" (player {num})" : "") + (flag ? ", hidden" : "") + ".")); Wands.FlashSeat(GmSeat(), "Turn: " + text2, 3f); if (num > 0 && num != GmSeat()) { Wands.FlashSeat(num, "Your turn: " + text2, 4f); Wands.PulseSeat(num, 0.6f, 0.1f); ((MonoBehaviour)this).StartCoroutine(SecondPulse(num)); } } } private IEnumerator SecondPulse(int seat) { yield return (object)new WaitForSecondsRealtime(0.25f); Wands.PulseSeat(seat, 0.6f, 0.1f); } [MethodImpl(MethodImplOptions.NoInlining)] private unsafe static string CurrentTurnCreatureKey() { //IL_0013: 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_0019: 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) List<QueueElement> turnQueueList = InitiativeManager.TurnQueueList; if (turnQueueList == null || turnQueueList.Count == 0) { return null; } QueueElement currentTurnElement = InitiativeManager.CurrentTurnElement; if ((int)currentTurnElement.Type != 0) { return null; } return ((object)(*(CreatureGuid*)(¤tTurnElement.CreatureGuid))/*cast due to .constrained prefix*/).ToString(); } private void DrawTurnRing() { //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_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0188: 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_01a8: 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_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)turnRing == (Object)null) { return; } CreatureBoardAsset currentTurn = CurrentTurn; bool flag = false; flag = PlayerVisibility.IsHiddenFromPlayers(currentTurn); if ((Object)(object)currentTurn == (Object)null || !((Behaviour)currentTurn).isActiveAndEnabled || flag || ((Object)(object)Wands != (Object)null && Wands.IsHeld(currentTurn))) { ((Renderer)turnRing).enabled = false; return; } float num = Mathf.Max(0.0001f, WorldPerTile()); float num2 = 0.55f * num; try { Bounds creatureBounds = currentTurn.CreatureBounds; if (((Bounds)(ref creatureBounds)).size.y > 0.05f) { num2 = Mathf.Clamp(Mathf.Max(((Bounds)(ref creatureBounds)).extents.x, ((Bounds)(ref creatureBounds)).extents.z), 0.25f, 5f) * 1.35f; } } catch { } float num3 = 0.5f + 0.5f * Mathf.Sin(Time.unscaledTime * 4f); Color val = default(Color); ((Color)(ref val))..ctor(1f, 0.82f, 0.25f, 0.55f + 0.45f * num3); LineRenderer obj2 = turnRing; Color startColor = (turnRing.endColor = val); obj2.startColor = startColor; turnRing.widthMultiplier = (0.05f + 0.03f * num3) * num; Vector3 position = ((Component)currentTurn).transform.position; int positionCount = turnRing.positionCount; for (int i = 0; i < positionCount; i++) { float num4 = (float)i * (float)Math.PI * 2f / (float)positionCount; turnRing.SetPosition(i, position + new Vector3(Mathf.Cos(num4) * num2, 0.03f * num, Mathf.Sin(num4) * num2)); } ((Renderer)turnRing).enabled = true; } [MethodImpl(MethodImplOptions.NoInlining)] private static string BoardKey() { return ((object)Unsafe.As<BoardGuid, BoardGuid>(ref BoardSessionManager.CurrentBoardInfo.Id)/*cast due to .constrained prefix*/).ToString(); } private static string SafeBoardKey() { try { return BoardKey(); } catch { return null; } } internal string SetStartPoint(Vector3 at) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_006f: 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) string text = SafeBoardKey(); if (text == null) { return "! no board loaded"; } startPoints[text] = at; SaveStartPoints(); float num = Mathf.Max(0.0001f, WorldPerTile()); TaleSpireTiltFivePlugin.Log.LogInfo((object)$"[start] party start for board {text.Substring(0, Math.Min(8, text.Length))} set at {at}."); return string.Format(CultureInfo.InvariantCulture, "Party start set at ({0:0.#}, {1:0.#})", at.x / num, at.z / num); } internal IEnumerator GatherParty(Action<string> done) { Vector3? start = StartPoint; if (!start.HasValue) { done("! no party start on this board yet (menu: Set party start here)"); yield break; } if (!TaleSpireOps.CanEdit(out var why)) { done("! can't move minis: " + why); yield break; } float tile = Mathf.Max(0.0001f, WorldPerTile()); List<CreatureBoardAsset> party = (from c in Wands.CreatureList where (Object)(object)c != (Object)null && Wands.OwnerOfCreature(c) >= 1 && Wands.OwnerOfCreature(c) != GmSeat() && !Wands.IsHeld(c) orderby Wands.OwnerOfCreature(c), SafeName(c) select c).ToList(); if (party.Count == 0) { done("! no minis are assigned to players yet"); yield break; } List<Vector2> spots = Spiral(party.Count); int moved = 0; for (int i = 0; i < party.Count; i++) { CreatureBoardAsset val = party[i]; Vector3 val2 = start.Value + new Vector3(spots[i].x * tile, 0f, spots[i].y * tile); val2.y = ((Component)val).transform.position.y; try { val.Pickup(); Vector3 val3 = val.FindLegalDropPos(val2); val.Drop(val3, val3.y); moved++; } catch (Exception ex) { TaleSpireTiltFivePlugin.Log.LogWarning((object)("[start] couldn't move " + SafeName(val) + ": " + ex.Message)); } yield return null; } TaleSpireTiltFivePlugin.Log.LogInfo((object)$"[start] gathered {moved} of {party.Count} party mini(s) at the start."); done((moved > 0) ? $"Party gathered ({moved})" : "! couldn't move the party"); } private static List<Vector2> Spiral(int n) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) List<Vector2> list = new List<Vector2>(); int num = 0; while (list.Count < n && num < 10) { for (int i = -num; i <= num; i++) { for (int j = -num; j <= num; j++) { if (Mathf.Max(Mathf.Abs(i), Mathf.Abs(j)) == num) { list.Add(new Vector2((float)i, (float)j)); } } } num++; } return list; } private void LoadStartPoints() { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) try { if (StartPointsFile == null || !File.Exists(StartPointsFile)) { return; } string[] array = File.ReadAllLines(StartPointsFile); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length == 0 || text.StartsWith("#")) { continue; } string[] array2 = text.Split('='); if (array2.Length == 2) { float[] array3 = (from v in array2[1].Split(',') select float.Parse(v, CultureInfo.InvariantCulture)).ToArray(); if (array3.Length == 3) { startPoints[array2[0].Trim()] = new Vector3(array3[0], array3[1], array3[2]); } } } } catch (Exception ex) { TaleSpireTiltFivePlugin.Log.LogWarning((object)("Could not read start points: " + ex.Message)); } } private void SaveStartPoints() { try { if (StartPointsFile != null) { List<string> list = new List<string> { "# TaleSpire Tilt Five: party start point per board (board id = x,y,z in world units)" }; list.AddRange(startPoints.Select((KeyValuePair<string, Vector3> kv) => string.Format(CultureInfo.InvariantCulture, "{0}={1},{2},{3}", kv.Key, kv.Value.x, kv.Value.y, kv.Value.z))); File.WriteAllLines(StartPointsFile, list); } } catch (Exception ex) { TaleSpireTiltFivePlugin.Log.LogWarning((object)("Could not save start points: " + ex.Message)); } } internal IEnumerator Roll(string roll, string label, bool gmHidden, Action<string> done) { roll = (roll ?? "1d20").Replace(" ", "").ToLowerInvariant(); if (!Regex.IsMatch(roll, "^(\\d*d\\d+|\\d+)([+-](\\d*d\\d+|\\d+))*$")) { done("! '" + roll + "' isn't a dice roll TaleSpire understands"); yield break; } string name = (string.IsNullOrWhiteSpace(label) ? roll : label.Trim()); string url = "talespire://dice/" + Uri.EscapeDataString(name) + ":" + roll; string err = null; try { LoadDice(url); } catch (Exception ex) { err = ex.Message; } if (err != null) { done("! dice failed: " + err); yield break; } yield return null; yield return null; try { Throw(gmHidden); } catch (Exception ex2) { err = ex2.Message; } TaleSpireTiltFivePlugin.Log.LogInfo((object)("[dice] " + name + ": " + roll + (gmHidden ? " (GM hidden)" : "") + ((err != null) ? (" - throw failed: " + err) : "") + ".")); done((err == null) ? ("Rolling " + roll + (gmHidden ? " (hidden)" : "")) : ("Dice loaded in the tray (" + roll + "); throw failed: " + err)); } [MethodImpl(MethodImplOptions.NoInlining)] private static void LoadDice(string url) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) LocalConnectionManager.ProcessTaleSpireUrl(url); } [MethodImpl(MethodImplOptions.NoInlining)] private static void Throw(bool gmHidden) { UIDiceTray diceTray = GUIManager.DiceTray; if ((Object)(object)diceTray == (Object)null) { throw new InvalidOperationException("no dice tray"); } if (gmHidden) { diceTray.SpawnGMDice(); } else { diceTray.SpawnDice(); } } internal string Describe(Func<CreatureBoardAsset, string> idOf) { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(); if ((Object)(object)CurrentTurn != (Object)null) { list.Add("Current turn (TaleSpire initiative): " + (idOf(CurrentTurn) ?? "?") + " \"" + SafeName(CurrentTurn) + "\"."); } Vector3? startPoint = StartPoint; float num = Mathf.Max(0.0001f, WorldPerTile()); if (startPoint.HasValue) { list.Add(string.Format(CultureInfo.InvariantCulture, "Party start point: ({0:0.#}, {1:0.#}).", startPoint.Value.x / num, startPoint.Value.z / num)); } return string.Join(" ", list); } } internal static class PlayerVisibility { internal static Func<int> GmSeat = () => 1; private static bool volumeApiBroken; internal static bool VolumeApiOk => !volumeApiBroken; internal static bool IsPlayerEye(Camera cam) { int num = SeatCameras.SeatOf(cam); if (num != 0) { return num != GmSeat(); } return false; } internal static bool IsHiddenFromPlayers(CreatureBoardAsset c) { if ((Object)(object)c == (Object)null) { return false; } try { if (c.IsExplicitlyHidden) { return true; } } catch { } return IsHiddenByVolume(c); } internal static bool IsHiddenByVolume(CreatureBoardAsset c) { if (volumeApiBroken || (Object)(object)c == (Object)null) { return false; } try { return VolumeInner(c); } catch (Exception ex) { volumeApiBroken = true; TaleSpireTiltFivePlugin.Log.LogWarning((object)("Hide-volume creature check unavailable (" + ex.GetType().Name + ": " + ex.Message + "); only GM-hidden creatures are filtered.")); return false; } } [MethodImpl(MethodImplOptions.NoInlining)] private static bool VolumeInner(CreatureBoardAsset c) { //IL_0001: Unknown result type (might