Tilt Five™ Unity API  1.3.0
 
Loading...
Searching...
No Matches
TiltFiveManager2.cs
Go to the documentation of this file.
1/*
2 * Copyright (C) 2020-2022 Tilt Five, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16using System.Collections.Generic;
17using UnityEngine;
18
19#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
20using UnityEngine.InputSystem;
21#endif
22
23using TiltFive;
25
26namespace TiltFive
27{
28
32 [DisallowMultipleComponent]
33#if !UNITY_2019_1_OR_NEWER || !INPUTSYSTEM_AVAILABLE
34 // Workaround to enable inputs to be collected before other scripts execute their Update() functions.
35 // This is unnecessary if we're using the Input System's OnBeforeUpdate() to collect fresh inputs.
36 [DefaultExecutionOrder(-500)]
37#else
38 // If the Input System's OnBeforeUpdate is available, set TiltFiveManager's execution order to be very late.
39 // This is desirable in two similar scenarios:
40 // - Our Update() executes last, providing the freshest pose data possible to any scripts using LateUpdate().
41 // - Our LateUpdate() executes last, providing the freshest pose data possible before we render to the glasses.
42 [DefaultExecutionOrder(500)]
43#endif
44 public class TiltFiveManager2 : TiltFive.SingletonComponent<TiltFiveManager2>, ISceneInfo
45 {
50 {
51 get
52 {
53 if(allPlayerSettings[0] == null)
54 {
55 allPlayerSettings[0] = new PlayerSettings() { PlayerIndex = PlayerIndex.One };
56 }
57 return allPlayerSettings[0];
58 }
59 }
60
65 {
66 get
67 {
68 if (allPlayerSettings[1] == null)
69 {
70 allPlayerSettings[1] = new PlayerSettings() { PlayerIndex = PlayerIndex.Two };
71 }
72 return allPlayerSettings[1];
73 }
74 }
75
80 {
81 get
82 {
83 if (allPlayerSettings[2] == null)
84 {
85 allPlayerSettings[2] = new PlayerSettings() { PlayerIndex = PlayerIndex.Three };
86 }
87 return allPlayerSettings[2];
88 }
89 }
90
95 {
96 get
97 {
98 if (allPlayerSettings[3] == null)
99 {
100 allPlayerSettings[3] = new PlayerSettings() { PlayerIndex = PlayerIndex.Four };
101 }
102 return allPlayerSettings[3];
103 }
104 }
105
107
108 public uint supportedPlayerCount = 3;
109
114
119
120#if UNITY_EDITOR
124 public EditorSettings2 editorSettings = new EditorSettings2();
125 public PlayerIndex selectedPlayer => editorSettings.selectedPlayer;
126
127 private HashSet<GameBoard> renderedGameboards = new HashSet<GameBoard>();
128#endif
129
130 private bool needsDriverUpdateNotifiedOnce = false;
131 private bool needsDriverUpdateErroredOnce = false;
132
133 private static bool upgradeInProgress = false;
134
138 protected override void Awake()
139 {
140 base.Awake();
141
142 // Apply log settings
143 Log.LogLevel = logSettings.level;
144 Log.TAG = logSettings.TAG;
145
147 {
148 Log.Warn("Failed to send application info to the T5 Control Panel.");
149 enabled = false;
150 }
151
152 // Initialize the player settings if necessary
153 for (int i = 0; i < allPlayerSettings.Length; i++)
154 {
155 var currentPlayerSettings = allPlayerSettings[i];
156 if(currentPlayerSettings == null)
157 {
159 }
160 }
161 }
162
163
164#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
168 private void OnBeforeUpdate()
169 {
170#if UNITY_EDITOR
171 if (UnityEditor.EditorApplication.isPaused)
172 {
173 return;
174 }
175#endif
176 if (Player.scanningForPlayers)
177 {
178 return;
179 }
180
182 Player.ScanForNewPlayers(); // Should only be executed once per frame
183 Wand.GetLatestInputs(); // Should only be executed once per frame
184
185 // OnBeforeUpdate can get called multiple times per frame. Unity seems to not properly utilize the camera positions for rendering
186 // if they are updated after Late Update and before render, causing a disparity between render pose and camera position leading to
187 // shaky displays in the headset. To avoid this, we prevent updating the camera positions during the BeforeRender Input State.
188 if (UnityEngine.InputSystem.LowLevel.InputState.currentUpdateType != UnityEngine.InputSystem.LowLevel.InputUpdateType.BeforeRender)
189 {
190 Update();
191 }
192 }
193#endif
194
198 void Update()
199 {
200#if !UNITY_2019_1_OR_NEWER || !INPUTSYSTEM_AVAILABLE
202 Player.ScanForNewPlayers(); // Should only be executed once per frame
203 Wand.GetLatestInputs(); // Should only be executed once per frame
204#endif
206
207 for (int i = 0; i < supportedPlayerCount; i++)
208 {
209 var playerSettings = allPlayerSettings[i];
210 if (playerSettings != null)
211 {
212 Player.Update(playerSettings, spectatorSettings);
213 }
214 }
215
216 var spectatedPlayer = spectatorSettings.spectatedPlayer;
217 if (Glasses.TryGetPreviewPose(spectatedPlayer, out var spectatedPlayerPose))
218 {
219 spectatorSettings.spectatorCamera?.transform.SetPositionAndRotation(
220 spectatedPlayerPose.position,
221 spectatedPlayerPose.rotation);
222 }
223 }
224
225
230 {
231 // Trackables should be updated just before rendering occurs,
232 // after all Update() calls are completed.
233 // This allows any Game Board movements to be finished before we base the
234 // Glasses/Wand poses off of its pose, preventing perceived jittering.
235 for (int i = 0; i < supportedPlayerCount; i++)
236 {
237 var playerSettings = allPlayerSettings[i];
238 if (playerSettings != null)
239 {
240 Player.Update(playerSettings, spectatorSettings);
241 }
242 }
243 }
244
256 public bool NeedsDriverUpdate()
257 {
259 {
260 try
261 {
263 bool needsUpdate = compatibility == ServiceCompatibility.Incompatible;
264
265 if (needsUpdate)
266 {
268 {
269 Log.Warn("Incompatible Tilt Five service. Please update driver package.");
271 }
272 }
273 else
274 {
275 // Not incompatible. Reset the incompatibility warning.
277 }
278 return needsUpdate;
279 }
280 catch (System.DllNotFoundException e)
281 {
282 Log.Info(
283 "Could not connect to Tilt Five plugin for compatibility check: {0}",
284 e.Message);
286 }
287 catch (System.Exception e)
288 {
289 Log.Error(e.Message);
291 }
292 }
293
294 // Failed to communicate with Tilt Five plugin at some point, so don't know whether
295 // an update is needed or not. Just say no.
296 return false;
297 }
298
302 private void OnEnable()
303 {
304 try
305 {
306 // TODO: change this to something in the settings drawer once that exists
307 NativePlugin.SetMaxDesiredGlasses((byte)GlassesSettings.MAX_SUPPORTED_GLASSES_COUNT);
308 }
309 catch (System.DllNotFoundException e)
310 {
311 Log.Info(
312 "Could not connect to Tilt Five plugin for setting max glasses: {0}",
313 e.Message);
314 }
315 catch (System.Exception e)
316 {
317 Log.Error(e.Message);
318 }
319
320 // Initialize the player settings if necessary
321 for (int i = 0; i < allPlayerSettings.Length; i++)
322 {
323 var currentPlayerSettings = allPlayerSettings[i];
324 if (currentPlayerSettings == null)
325 {
327 }
328 }
329
331
332 for (int i = 0; i < supportedPlayerCount; i++)
333 {
334 var playerSettings = allPlayerSettings[i];
335 if (playerSettings != null)
336 {
337 Player.Reset(playerSettings, spectatorSettings);
338 }
339 }
340
341#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
342 InputSystem.onBeforeUpdate += OnBeforeUpdate;
343#endif
344 }
345
346 private void OnDisable()
347 {
348#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
349 InputSystem.onBeforeUpdate -= OnBeforeUpdate;
350 //Input.OnDisable();
351#endif
352 Player.OnDisable();
353 }
354
355 private void OnDestroy()
356 {
357 Player.OnDisable();
358 }
359
360 private void OnApplicationQuit()
361 {
362 OnDisable();
363 }
364
365 // There's a longstanding bug where UnityPluginUnload isn't called.
366 // - https://forum.unity.com/threads/unitypluginunload-never-called.414066/
367 // - https://gamedev.stackexchange.com/questions/200118/unity-native-plugin-unitypluginload-is-called-but-unitypluginunload-is-not
368 // - https://issuetracker.unity3d.com/issues/unitypluginunload-is-never-called-in-a-standalone-build
369 // Work around this by invoking it via Application.quitting.
370 private static void Quit()
371 {
372 try
373 {
375 }
376 catch (System.DllNotFoundException)
377 {
378 // nothing to report on quit if the plugin isn't present
379 }
380 catch (System.Exception e)
381 {
382 Log.Error(e.Message);
383 }
384 }
385
386 [RuntimeInitializeOnLoadMethod]
387 private static void RunOnStart()
388 {
389 Application.quitting += Quit;
390 }
391
393 {
394 // Warn developers if they've left the spectatorCamera field empty
395 // TiltFiveManager2's custom inspector should already warn them in the editor, but this warns them again at runtime.
397 {
398 Log.Warn("No spectator camera detected in TiltFiveManager2's spectator settings. A spectator camera is required.");
399 }
400
401 // Make sure that the spectated player isn't set to a player index higher than what TiltFiveManager2 supports
402 var highestSupportedPlayer = (PlayerIndex)supportedPlayerCount;
403 if (spectatorSettings.spectatedPlayer > highestSupportedPlayer)
404 {
405 Log.Warn($"Invalid spectatorSettings.spectatedPlayer [{spectatorSettings.spectatedPlayer}]. TiltFiveManager2 currently only supports up to Player {highestSupportedPlayer}.");
406 spectatorSettings.spectatedPlayer = highestSupportedPlayer;
407 }
408 }
409
410#if UNITY_EDITOR
411
415 void OnValidate()
416 {
417 // Don't do any validation if we're in the middle of copying settings.
419 {
420 return;
421 }
422
423 Log.LogLevel = logSettings.level;
424 Log.TAG = logSettings.TAG;
425
426 playerOneSettings.PlayerIndex = PlayerIndex.One;
427 playerTwoSettings.PlayerIndex = PlayerIndex.Two;
428 playerThreeSettings.PlayerIndex = PlayerIndex.Three;
429 playerFourSettings.PlayerIndex = PlayerIndex.Four;
430
432 if (Application.isEditor && !Application.isPlaying)
433 {
435 }
436 for (int i = 0; i < allPlayerSettings.Length; i++)
437 {
438 var playerSettings = allPlayerSettings[i];
439 if (playerSettings != null)
440 {
441 Player.Validate(playerSettings);
442 playerSettings.glassesSettings.glassesMirrorMode = spectatorSettings.glassesMirrorMode;
443 }
444 }
446 }
447
451 void OnDrawGizmos()
452 {
453 if (!enabled)
454 {
455 return;
456 }
457
458 renderedGameboards.Clear();
459
460 for (int i = 0; i < supportedPlayerCount; i++)
461 {
462 var playerSettings = allPlayerSettings[i];
463 if (playerSettings != null)
464 {
465 var currentGameboard = playerSettings.gameboardSettings.currentGameBoard;
466 if (!renderedGameboards.Contains(currentGameboard))
467 {
468 renderedGameboards.Add(currentGameboard);
469 Player.DrawGizmos(playerSettings);
470 }
471 }
472 }
473 }
474
475 public static void CreateFromTiltFiveManager(TiltFiveManager tiltFiveManager)
476 {
477 var parentGameObject = tiltFiveManager.gameObject;
478
479 // Ideally, we only want one TiltFiveManager2 in the scene.
480 // If the developer clicks the upgrade button repeatedly, we don't want to keep creating more of them.
481 // In this scenario, ask the developer whether they'd like to overwrite the settings on the existing
482 // TiltFiveManager2 with the TiltFiveManager's settings.
483 var isTiltFiveManager2AlreadyPresent = parentGameObject.TryGetComponent<TiltFiveManager2>(out var existingTiltFiveManager2);
484 var confirmationDialogTitle = "Existing TiltFiveManager2 detected";
485 var confirmationDialogText = $"The GameObject \"{parentGameObject.name}\" already has a TiltFiveManager2 component." +
486 System.Environment.NewLine + System.Environment.NewLine +
487 "Overwrite the existing TiltFiveManager2 component values?" +
488 System.Environment.NewLine + System.Environment.NewLine +
489 "Warning: This cannot be undone via Edit > Undo (Ctrl+Z)";
490 var confirmButtonLabel = "Overwrite";
491 var cancelButtonLabel = "Cancel";
492 var overwriteExistingTiltFiveManager2 = isTiltFiveManager2AlreadyPresent
493 && UnityEditor.EditorUtility.DisplayDialog(confirmationDialogTitle, confirmationDialogText, confirmButtonLabel, cancelButtonLabel);
494
495 if(isTiltFiveManager2AlreadyPresent && !overwriteExistingTiltFiveManager2)
496 {
497 Debug.Log($"Aborted attempt to upgrade TiltFiveManager.");
498 return;
499 }
500
501 upgradeInProgress = true;
502
503 TiltFiveManager2 tiltFiveManager2 = overwriteExistingTiltFiveManager2
504 ? existingTiltFiveManager2
505 : parentGameObject.AddComponent<TiltFiveManager2>();
506
507 // Disable the old TiltFiveManager.
508 tiltFiveManager.enabled = false;
509
510 // Default to supporting a single player, just like TiltFiveManager did.
511 tiltFiveManager2.supportedPlayerCount = 1;
512
513 // Copy the various settings objects from TiltFiveManager to playerOneSettings.
514 tiltFiveManager2.playerOneSettings.glassesSettings = tiltFiveManager.glassesSettings.Copy();
515
516 tiltFiveManager2.playerOneSettings.scaleSettings = tiltFiveManager.scaleSettings.Copy();
517
518 tiltFiveManager2.playerOneSettings.gameboardSettings = tiltFiveManager.gameBoardSettings.Copy();
519
520 tiltFiveManager2.playerOneSettings.leftWandSettings = tiltFiveManager.leftWandSettings.Copy();
521 tiltFiveManager2.playerOneSettings.rightWandSettings = tiltFiveManager.rightWandSettings.Copy();
522
523 // Emulate TiltFiveManager, which used a single camera internally for eye camera cloning and onscreen previews
524 tiltFiveManager2.spectatorSettings.spectatorCamera = tiltFiveManager.glassesSettings.cameraTemplate;
525
526 // Copy TiltFiveManager's GlassesSettings' mirror mode, which has moved to SpectatorSettings for TiltFiveManager2
527 tiltFiveManager2.spectatorSettings.glassesMirrorMode = tiltFiveManager.glassesSettings.glassesMirrorMode;
528
529 // For the sake of thoroughness, let's copy the old log settings, too.
530 tiltFiveManager2.logSettings = tiltFiveManager.logSettings.Copy();
531
532 upgradeInProgress = false;
533
534 var resultText = overwriteExistingTiltFiveManager2
535 ? $"Successfully overwrote component values on the existing TiltFiveManager2 component attached to \"{parentGameObject.name}\" using the old TiltFiveManager component values."
536 : $"Successfully attached a new TiltFiveManager2 component to \"{parentGameObject.name}\" and imported the old TiltFiveManager component values.";
537 Debug.Log($"{resultText}{System.Environment.NewLine}The old TiltFiveManager has been disabled - it can safely be removed.");
538 }
539
540#endif
541
542 #region ISceneInfo Implementation
543
544 public float GetScaleToUWRLD_UGBD()
545 {
547 }
548
549 public Pose GetGameboardPose()
550 {
552 }
553
554 public Camera GetEyeCamera()
555 {
556 return Glasses.GetLeftEye(PlayerIndex.One);
557 }
558
560 {
562 }
563
564 public bool IsActiveAndEnabled()
565 {
566 return isActiveAndEnabled;
567 }
568
569 #endregion ISceneInfo Implementation
570 }
571
572}
static bool SetApplicationInfo()
Definition: Display.cs:144
Vector3 gameBoardRotation
The game board rotation or focal rotational offset.
Vector3 gameBoardCenter
The game board position or focal position offset.
GameBoard currentGameBoard
The game board is the window into the game world, as well as the origin about which the glasses/wand ...
float gameBoardScale
The game board's scale multiplies the perceived size of objects in the scene.
The Glasses API and runtime.
Definition: Glasses.cs:35
static Camera GetLeftEye(PlayerIndex playerIndex)
Definition: Glasses.cs:305
static bool TryGetPreviewPose(PlayerIndex playerIndex, out Pose pose)
Attempts to get the position and orientation of the specified player's glasses, smoothed for on-scree...
Definition: Glasses.cs:285
GlassesSettings encapsulates all configuration data used by the Glasses' tracking runtime to compute ...
Camera cameraTemplate
The camera used as a template for creating the eye cameras at runtime.
GlassesMirrorMode glassesMirrorMode
The Logger.
Definition: Log.cs:42
static void Warn(string m, params object[] list)
WARN logging function call.
Definition: Log.cs:166
static void Info(string m, params object[] list)
INFO logging function call.
Definition: Log.cs:140
static void Error(string m, params object[] list)
ERROR logging function call.
Definition: Log.cs:127
static void UnloadWorkaround()
static ServiceCompatibility GetServiceCompatibility()
static void SetMaxDesiredGlasses(byte maxCount)
Provides access to player settings and functionality.
Definition: Player.cs:16
ScaleSettings scaleSettings
GameBoardSettings gameboardSettings
static uint MAX_SUPPORTED_PLAYERS
float GetScaleToUWRLD_UGBD(float gameboardScale)
PlayerIndex spectatedPlayer
The player that will have their perspective mirrored on screen.
GlassesMirrorMode glassesMirrorMode
The spectator camera will display content on screen depending on the mirroring mode....
Camera spectatorCamera
The camera used for rendering the onscreen preview.
The Tilt Five manager.
LogSettings logSettings
The log settings.
PlayerSettings[] allPlayerSettings
bool NeedsDriverUpdate()
Check if a driver update is needed.
SpectatorSettings spectatorSettings
The spectator camera's runtime configuration data.
void OnEnable()
Called when the GameObject is enabled.
override void Awake()
Awake this instance.
void Update()
Update this instance.
PlayerSettings playerFourSettings
The fourth player's runtime configuration data.
PlayerSettings playerOneSettings
The first player's runtime configuration data.
void LateUpdate()
Update this instance after all components have finished executing their Update() functions.
PlayerSettings playerTwoSettings
The second player's runtime configuration data.
PlayerSettings playerThreeSettings
The third player's runtime configuration data.
The Tilt Five manager.
LogSettings logSettings
The log settings.
GameBoardSettings gameBoardSettings
The game board runtime configuration data.
WandSettings rightWandSettings
The wand runtime configuration data for the right hand wand.
ScaleSettings scaleSettings
The scale conversion runtime configuration data.
GlassesSettings glassesSettings
The glasses runtime configuration data.
WandSettings leftWandSettings
The wand runtime configuration data for the left hand wand.
The Wand API and runtime.
Definition: Wand.cs:56
Definition: Log.cs:21
ServiceCompatibility
Whether the running service is compatible.
PlayerIndex
The Player index (e.g. Player One, Player Two, etc)