app.hypergames.hypersdk 1.10.0 → 1.11.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/Editor/Scripts/Setup/HyperSDKInstaller.cs +42 -0
  3. package/Editor/Scripts/Tools/HyperGameModeMenu.cs +27 -7
  4. package/Runtime/Internal/AssemblyInfo.cs +1 -0
  5. package/Runtime/Internal/Bootstrap/HyperLoader.cs +186 -8
  6. package/Runtime/Internal/Core/HyperRuntime.cs +82 -0
  7. package/Runtime/Internal/Core/HyperRuntimeHost.cs +6 -0
  8. package/Runtime/Internal/Data/URLData.cs +18 -1
  9. package/Runtime/Internal/Managers/BackendManager.cs +281 -24
  10. package/Runtime/Internal/Managers/DataManager.cs +207 -21
  11. package/Runtime/Internal/Managers/GameManager.cs +365 -17
  12. package/Runtime/Internal/Managers/ReplayManager.cs +117 -0
  13. package/Runtime/Internal/Managers/ReplayManager.cs.meta +11 -0
  14. package/Runtime/Internal/Managers/TimeManager.cs +54 -12
  15. package/Runtime/Internal/Replay/ReplayActivityRecorder.cs +182 -0
  16. package/Runtime/Internal/Replay/ReplayActivityRecorder.cs.meta +2 -0
  17. package/Runtime/Internal/Replay/ReplaySessionState.cs +181 -0
  18. package/Runtime/Internal/Replay/ReplaySessionState.cs.meta +2 -0
  19. package/Runtime/Internal/Replay.meta +8 -0
  20. package/Runtime/Internal/ScriptableObjects/HyperSDKSettings.cs +5 -0
  21. package/Runtime/Internal/UI/Animation/LoadingTextAnimation.cs +15 -1
  22. package/Runtime/Internal/UI/Components/ControlBar.cs +25 -2
  23. package/Runtime/Internal/UI/Components/PauseButton.cs +4 -1
  24. package/Runtime/Internal/UI/Components/ReplayController.cs +527 -0
  25. package/Runtime/Internal/UI/Components/ReplayController.cs.meta +2 -0
  26. package/Runtime/Internal/UI/Components/ReplayMarkerPulse.cs +89 -0
  27. package/Runtime/Internal/UI/Components/ReplayMarkerPulse.cs.meta +2 -0
  28. package/Runtime/Internal/UI/Components/ReplayPresentationCanvas.cs +183 -0
  29. package/Runtime/Internal/UI/Components/ReplayPresentationCanvas.cs.meta +2 -0
  30. package/Runtime/Internal/UI/Modals/LoadingFailedModal.cs +12 -0
  31. package/Runtime/Internal/UI/Modals/ReplayOverModal.cs +61 -0
  32. package/Runtime/Internal/UI/Modals/ReplayOverModal.cs.meta +2 -0
  33. package/Runtime/Internal/UI/Modals/StartingInstructionModal.cs +38 -29
  34. package/Runtime/Public/AssemblyInfo.cs +3 -0
  35. package/Runtime/Public/AssemblyInfo.cs.meta +2 -0
  36. package/Runtime/Public/Core/HyperSDK.cs +305 -109
  37. package/Runtime/Public/Hyper.asmdef +2 -1
  38. package/Runtime/Public/Replay/ReplayPlaybackEngine.cs +555 -0
  39. package/Runtime/Public/Replay/ReplayPlaybackEngine.cs.meta +2 -0
  40. package/Runtime/Public/Replay.meta +8 -0
  41. package/Runtime/Resources/Fonts/Nunito/Nunito-Light SDF.asset +528 -521
  42. package/Runtime/Resources/Materials/HyperReplayScanlines.preset +340 -0
  43. package/Runtime/Resources/Materials/HyperReplayScanlines.preset.meta +8 -0
  44. package/Runtime/Resources/Materials/ReplayScanlineOverlay.mat +55 -0
  45. package/Runtime/Resources/Materials/ReplayScanlineOverlay.mat.meta +8 -0
  46. package/Runtime/Resources/Shaders/ReplayScanlineOverlay.shader +150 -0
  47. package/Runtime/Resources/Shaders/ReplayScanlineOverlay.shader.meta +10 -0
  48. package/Runtime/Resources/Sprites/Replays/Fallback avatar.png +0 -0
  49. package/Runtime/Resources/Sprites/Replays/Fallback avatar.png.meta +156 -0
  50. package/Runtime/Resources/Sprites/Replays/Recording.png +0 -0
  51. package/Runtime/Resources/Sprites/Replays/Recording.png.meta +156 -0
  52. package/Runtime/Resources/Sprites/Replays/Replay frame.png +0 -0
  53. package/Runtime/Resources/Sprites/Replays/Replay frame.png.meta +156 -0
  54. package/Runtime/Resources/Sprites/Replays/Replay modal icon.png +0 -0
  55. package/Runtime/Resources/Sprites/Replays/Replay modal icon.png.meta +156 -0
  56. package/Runtime/Resources/Sprites/Replays.meta +8 -0
  57. package/Runtime/Resources/UIPrefabs/ControlBar.prefab +169 -2
  58. package/Runtime/Resources/UIPrefabs/GamePausedModal_Battle.prefab +1 -1
  59. package/Runtime/Resources/UIPrefabs/ReplayController.prefab +1269 -0
  60. package/Runtime/Resources/UIPrefabs/ReplayController.prefab.meta +7 -0
  61. package/Runtime/Resources/UIPrefabs/ReplayInputBlocker.prefab +90 -0
  62. package/Runtime/Resources/UIPrefabs/ReplayInputBlocker.prefab.meta +7 -0
  63. package/Runtime/Resources/UIPrefabs/ReplayOverModal.prefab +958 -0
  64. package/Runtime/Resources/UIPrefabs/ReplayOverModal.prefab.meta +7 -0
  65. package/Runtime/Resources/UIPrefabs/ReplaySeekOverlay.prefab +189 -0
  66. package/Runtime/Resources/UIPrefabs/ReplaySeekOverlay.prefab.meta +7 -0
  67. package/Runtime/Resources/UIPrefabs/SnackBar.prefab +2 -2
  68. package/Runtime/Shared/AssemblyInfo.cs +5 -0
  69. package/Runtime/Shared/AssemblyInfo.cs.meta +11 -0
  70. package/Runtime/Shared/DTOs/Enums.cs +8 -3
  71. package/Runtime/Shared/DTOs/Score/ScoreSnapshot.cs +13 -1
  72. package/Runtime/Shared/Replay/IReplayPlaybackEngine.cs +37 -0
  73. package/Runtime/Shared/Replay/IReplayPlaybackEngine.cs.meta +11 -0
  74. package/Runtime/Shared/Replay.meta +8 -0
  75. package/Samples~/LaneRunner/LaneRunnerSample.unity +1603 -0
  76. package/Samples~/LaneRunner/LaneRunnerSample.unity.meta +7 -0
  77. package/Samples~/LaneRunner/Materials/DoubleScore.mat +86 -0
  78. package/Samples~/LaneRunner/Materials/DoubleScore.mat.meta +8 -0
  79. package/Samples~/LaneRunner/Materials/Ground.mat +84 -0
  80. package/Samples~/LaneRunner/Materials/Ground.mat.meta +8 -0
  81. package/Samples~/LaneRunner/Materials/Lane.mat +84 -0
  82. package/Samples~/LaneRunner/Materials/Lane.mat.meta +8 -0
  83. package/Samples~/LaneRunner/Materials/LaneMarker.mat +84 -0
  84. package/Samples~/LaneRunner/Materials/LaneMarker.mat.meta +8 -0
  85. package/Samples~/LaneRunner/Materials/Obstacle.mat +84 -0
  86. package/Samples~/LaneRunner/Materials/Obstacle.mat.meta +8 -0
  87. package/Samples~/LaneRunner/Materials/Player.mat +84 -0
  88. package/Samples~/LaneRunner/Materials/Player.mat.meta +8 -0
  89. package/Samples~/LaneRunner/Materials.meta +8 -0
  90. package/Samples~/LaneRunner/Prefabs/DoubleScorePickup.prefab +152 -0
  91. package/Samples~/LaneRunner/Prefabs/DoubleScorePickup.prefab.meta +7 -0
  92. package/Samples~/LaneRunner/Prefabs/Obstacle.prefab +152 -0
  93. package/Samples~/LaneRunner/Prefabs/Obstacle.prefab.meta +7 -0
  94. package/Samples~/LaneRunner/Prefabs.meta +8 -0
  95. package/Samples~/LaneRunner/README.md +35 -0
  96. package/Samples~/LaneRunner/README.md.meta +7 -0
  97. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerCommand.cs +9 -0
  98. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerCommand.cs.meta +2 -0
  99. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerGame.cs +93 -0
  100. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerGame.cs.meta +2 -0
  101. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerPlayer.cs +155 -0
  102. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerPlayer.cs.meta +2 -0
  103. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerSpawner.cs +110 -0
  104. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerSpawner.cs.meta +2 -0
  105. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerTrackItem.cs +41 -0
  106. package/Samples~/LaneRunner/Scripts/Gameplay/LaneRunnerTrackItem.cs.meta +2 -0
  107. package/Samples~/LaneRunner/Scripts/Gameplay.meta +8 -0
  108. package/Samples~/LaneRunner/Scripts/Hyper/LaneRunnerReplayAdapter.cs +62 -0
  109. package/Samples~/LaneRunner/Scripts/Hyper/LaneRunnerReplayAdapter.cs.meta +2 -0
  110. package/Samples~/LaneRunner/Scripts/Hyper/LaneRunnerTournamentAdapter.cs +64 -0
  111. package/Samples~/LaneRunner/Scripts/Hyper/LaneRunnerTournamentAdapter.cs.meta +2 -0
  112. package/Samples~/LaneRunner/Scripts/Hyper.meta +8 -0
  113. package/Samples~/LaneRunner/Scripts.meta +8 -0
  114. package/Tests.meta +8 -0
  115. package/package.json +8 -1
@@ -0,0 +1,89 @@
1
+ using System.Collections;
2
+ using UnityEngine;
3
+ using UnityEngine.UI;
4
+
5
+ namespace Hyper.Internal
6
+ {
7
+ [RequireComponent(typeof(Graphic))]
8
+ internal sealed class ReplayMarkerPulse : MonoBehaviour
9
+ {
10
+ [SerializeField, Range(0f, 1f)] private float minimumAlpha = 0.3f;
11
+ [SerializeField] private float fadeDuration = 0.8f;
12
+
13
+ private Graphic _graphic;
14
+ private Coroutine _pulseCoroutine;
15
+
16
+ private void Awake()
17
+ {
18
+ _graphic = GetComponent<Graphic>();
19
+ }
20
+
21
+ private void OnEnable()
22
+ {
23
+ HyperRuntime.EventManager.OnGameStart += StartPulsing;
24
+ HyperRuntime.EventManager.OnGameEnded += StopPulsing;
25
+ SetAlpha(minimumAlpha);
26
+
27
+ if (HyperRuntime.GameManager != null && HyperRuntime.GameManager.HasGameStarted)
28
+ {
29
+ StartPulsing();
30
+ }
31
+ }
32
+
33
+ private void OnDisable()
34
+ {
35
+ if (HyperRuntime.EventManager != null)
36
+ {
37
+ HyperRuntime.EventManager.OnGameStart -= StartPulsing;
38
+ HyperRuntime.EventManager.OnGameEnded -= StopPulsing;
39
+ }
40
+ StopPulsing();
41
+ }
42
+
43
+ private void StartPulsing()
44
+ {
45
+ if (_pulseCoroutine != null) StopCoroutine(_pulseCoroutine);
46
+ _pulseCoroutine = StartCoroutine(Pulse());
47
+ }
48
+
49
+ private void StopPulsing()
50
+ {
51
+ if (_pulseCoroutine != null)
52
+ {
53
+ StopCoroutine(_pulseCoroutine);
54
+ _pulseCoroutine = null;
55
+ }
56
+ SetAlpha(1f);
57
+ }
58
+
59
+ private IEnumerator Pulse()
60
+ {
61
+ float duration = Mathf.Max(0.05f, fadeDuration);
62
+ while (true)
63
+ {
64
+ yield return Fade(minimumAlpha, 1f, duration);
65
+ yield return Fade(1f, minimumAlpha, duration);
66
+ }
67
+ }
68
+
69
+ private IEnumerator Fade(float from, float to, float duration)
70
+ {
71
+ float elapsed = 0f;
72
+ while (elapsed < duration)
73
+ {
74
+ elapsed += Time.unscaledDeltaTime;
75
+ SetAlpha(Mathf.Lerp(from, to, elapsed / duration));
76
+ yield return null;
77
+ }
78
+ SetAlpha(to);
79
+ }
80
+
81
+ private void SetAlpha(float alpha)
82
+ {
83
+ if (_graphic == null) return;
84
+ Color color = _graphic.color;
85
+ color.a = alpha;
86
+ _graphic.color = color;
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,2 @@
1
+ fileFormatVersion: 2
2
+ guid: 361528b20842ffc4ead65b0e23d7cc78
@@ -0,0 +1,183 @@
1
+ using Hyper.Shared;
2
+ using UnityEngine;
3
+ using UnityEngine.UI;
4
+
5
+ namespace Hyper.Internal
6
+ {
7
+ /// <summary>
8
+ /// Owns replay-only UI independently from the session-scoped HyperCanvas.
9
+ /// The root survives only while a seek restart is in progress.
10
+ /// </summary>
11
+ internal sealed class ReplayPresentationCanvas : MonoBehaviour
12
+ {
13
+ private const int NormalSortingOrder = 9999;
14
+ private const int SeekingSortingOrder = 10001;
15
+
16
+ private static ReplayPresentationCanvas instance;
17
+
18
+ internal GameObject InputBlocker { get; private set; }
19
+ internal GameObject ControllerObject { get; private set; }
20
+ internal ReplayController Controller { get; private set; }
21
+
22
+ internal static ReplayPresentationCanvas GetOrCreate(bool isPortrait)
23
+ {
24
+ if (instance == null)
25
+ {
26
+ instance = FindFirstObjectByType<ReplayPresentationCanvas>();
27
+ }
28
+
29
+ if (instance == null)
30
+ {
31
+ var root = new GameObject(
32
+ "ReplayPresentationCanvas",
33
+ typeof(RectTransform),
34
+ typeof(Canvas),
35
+ typeof(CanvasScaler),
36
+ typeof(GraphicRaycaster));
37
+ instance = root.AddComponent<ReplayPresentationCanvas>();
38
+ DontDestroyOnLoad(root);
39
+ instance.Build(isPortrait);
40
+ }
41
+ else
42
+ {
43
+ instance.ConfigureCanvas(isPortrait);
44
+ instance.EnsurePresentationObjects();
45
+ }
46
+
47
+ instance.gameObject.SetActive(true);
48
+ instance.ControllerObject?.transform.SetAsLastSibling();
49
+ return instance;
50
+ }
51
+
52
+ internal static bool IsPresentationRoot(GameObject root)
53
+ {
54
+ return instance != null && root == instance.gameObject;
55
+ }
56
+
57
+ internal static void SetSeekingLayer(bool isSeeking)
58
+ {
59
+ if (instance == null) return;
60
+ Canvas canvas = instance.GetComponent<Canvas>();
61
+ if (canvas != null) canvas.sortingOrder = isSeeking ? SeekingSortingOrder : NormalSortingOrder;
62
+ }
63
+
64
+ internal static void DestroyCurrent()
65
+ {
66
+ if (instance == null) return;
67
+ Destroy(instance.gameObject);
68
+ instance = null;
69
+ }
70
+
71
+ private void Awake()
72
+ {
73
+ if (instance != null && instance != this)
74
+ {
75
+ Destroy(gameObject);
76
+ return;
77
+ }
78
+
79
+ instance = this;
80
+ }
81
+
82
+ private void OnDestroy()
83
+ {
84
+ if (instance == this) instance = null;
85
+ }
86
+
87
+ private void Build(bool isPortrait)
88
+ {
89
+ ConfigureCanvas(isPortrait);
90
+
91
+ var safeArea = new GameObject("SafeArea", typeof(RectTransform));
92
+ RectTransform safeAreaRect = safeArea.GetComponent<RectTransform>();
93
+ safeAreaRect.SetParent(transform, false);
94
+ StretchToParent(safeAreaRect);
95
+ if (isPortrait) safeArea.AddComponent<SafeArea>();
96
+
97
+ CreateInputBlocker(safeAreaRect);
98
+ CreateController(safeAreaRect);
99
+ }
100
+
101
+ private void ConfigureCanvas(bool isPortrait)
102
+ {
103
+ Canvas canvas = GetComponent<Canvas>();
104
+ canvas.renderMode = RenderMode.ScreenSpaceOverlay;
105
+ canvas.overrideSorting = true;
106
+ canvas.sortingOrder = ReplaySessionState.IsSeeking
107
+ ? SeekingSortingOrder
108
+ : NormalSortingOrder;
109
+
110
+ CanvasScaler scaler = GetComponent<CanvasScaler>();
111
+ scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
112
+ scaler.referenceResolution = new Vector2(1080f, 2160f);
113
+ scaler.matchWidthOrHeight = isPortrait ? 1f : 0.593f;
114
+ }
115
+
116
+ private void EnsurePresentationObjects()
117
+ {
118
+ Transform safeArea = transform.Find("SafeArea");
119
+ if (safeArea == null)
120
+ {
121
+ Build(Screen.height > Screen.width);
122
+ return;
123
+ }
124
+
125
+ if (InputBlocker == null)
126
+ {
127
+ Transform blocker = safeArea.Find("ReplayInputBlocker");
128
+ InputBlocker = blocker != null ? blocker.gameObject : null;
129
+ if (InputBlocker == null) CreateInputBlocker((RectTransform)safeArea);
130
+ }
131
+
132
+ if (ControllerObject == null)
133
+ {
134
+ Transform controller = safeArea.Find("ReplayController");
135
+ ControllerObject = controller != null ? controller.gameObject : null;
136
+ Controller = ControllerObject != null ? ControllerObject.GetComponent<ReplayController>() : null;
137
+ if (ControllerObject == null) CreateController((RectTransform)safeArea);
138
+ }
139
+ }
140
+
141
+ private void CreateInputBlocker(RectTransform parent)
142
+ {
143
+ GameObject prefab = Resources.Load<GameObject>("UIPrefabs/ReplayInputBlocker");
144
+ InputBlocker = prefab != null
145
+ ? Instantiate(prefab, parent, false)
146
+ : new GameObject("ReplayInputBlocker", typeof(RectTransform), typeof(CanvasRenderer), typeof(Image));
147
+
148
+ RectTransform rect = InputBlocker.GetComponent<RectTransform>();
149
+ if (rect.parent == null) rect.SetParent(parent, false);
150
+ StretchToParent(rect);
151
+
152
+ Image image = InputBlocker.GetComponent<Image>();
153
+ if (image != null)
154
+ {
155
+ image.raycastTarget = true;
156
+ if (prefab == null) image.color = Color.clear;
157
+ }
158
+ }
159
+
160
+ private void CreateController(RectTransform parent)
161
+ {
162
+ GameObject prefab = Resources.Load<GameObject>("UIPrefabs/ReplayController");
163
+ if (prefab == null)
164
+ {
165
+ Debug.LogWarning("[ReplayPresentationCanvas] ReplayController prefab not found.");
166
+ return;
167
+ }
168
+
169
+ ControllerObject = Instantiate(prefab, parent, false);
170
+ ControllerObject.transform.SetAsLastSibling();
171
+ Controller = ControllerObject.GetComponent<ReplayController>();
172
+ if (Controller == null) Controller = ControllerObject.AddComponent<ReplayController>();
173
+ }
174
+
175
+ private static void StretchToParent(RectTransform rect)
176
+ {
177
+ rect.anchorMin = Vector2.zero;
178
+ rect.anchorMax = Vector2.one;
179
+ rect.offsetMin = Vector2.zero;
180
+ rect.offsetMax = Vector2.zero;
181
+ }
182
+ }
183
+ }
@@ -0,0 +1,2 @@
1
+ fileFormatVersion: 2
2
+ guid: 01a4ad28a491451587a73a62982beef7
@@ -90,6 +90,12 @@ namespace Hyper.Internal
90
90
  retryTimerText.text = $"00:0{5 - HyperRuntime.BackendManager.CurrentRetryCount}";
91
91
  }
92
92
 
93
+ internal void ShowRetryCountdown(int secondsRemaining)
94
+ {
95
+ DisableAllCTAButtons();
96
+ retryTimerText.text = $"00:{Mathf.Max(0, secondsRemaining):00}";
97
+ }
98
+
93
99
  private void EnableRetryLaterButton()
94
100
  {
95
101
  ctaButtonsHolder.interactable = true;
@@ -115,6 +121,12 @@ namespace Hyper.Internal
115
121
 
116
122
  public void Retry() // On Retry Button Clicked
117
123
  {
124
+ if (_gameManager.IsReplayMode)
125
+ {
126
+ _gameManager.RetryReplayLoading();
127
+ return;
128
+ }
129
+
118
130
  StartReconnectionCoroutine();
119
131
  }
120
132
 
@@ -0,0 +1,61 @@
1
+ using Hyper.Shared;
2
+ using UnityEngine;
3
+ using UnityEngine.UI;
4
+
5
+ namespace Hyper.Internal
6
+ {
7
+ internal sealed class ReplayOverModal : MonoBehaviour
8
+ {
9
+ [SerializeField] private Button watchAgainButton;
10
+ [SerializeField] private Button exitButton;
11
+ private bool _handled;
12
+
13
+ private void Awake()
14
+ {
15
+ Button[] buttons = GetComponentsInChildren<Button>(true);
16
+ for (int i = 0; i < buttons.Length; i++)
17
+ {
18
+ if (buttons[i].name == "Watch Again") watchAgainButton = buttons[i];
19
+ else if (buttons[i].name == "Exit") exitButton = buttons[i];
20
+ }
21
+
22
+ if (watchAgainButton != null) watchAgainButton.onClick.AddListener(WatchAgain);
23
+ if (exitButton != null) exitButton.onClick.AddListener(Exit);
24
+ }
25
+
26
+ private void OnEnable()
27
+ {
28
+ _handled = false;
29
+ if (watchAgainButton != null) watchAgainButton.interactable = true;
30
+ if (exitButton != null) exitButton.interactable = true;
31
+ }
32
+
33
+ private void OnDestroy()
34
+ {
35
+ if (watchAgainButton != null) watchAgainButton.onClick.RemoveListener(WatchAgain);
36
+ if (exitButton != null) exitButton.onClick.RemoveListener(Exit);
37
+ }
38
+
39
+ private void WatchAgain()
40
+ {
41
+ if (_handled) return;
42
+ _handled = true;
43
+ DisableButtons();
44
+ HyperRuntime.RestartReplaySession();
45
+ }
46
+
47
+ private void Exit()
48
+ {
49
+ if (_handled) return;
50
+ _handled = true;
51
+ DisableButtons();
52
+ HyperRuntime.GameManager?.ExitCompletedReplay();
53
+ }
54
+
55
+ private void DisableButtons()
56
+ {
57
+ if (watchAgainButton != null) watchAgainButton.interactable = false;
58
+ if (exitButton != null) exitButton.interactable = false;
59
+ }
60
+ }
61
+ }
@@ -0,0 +1,2 @@
1
+ fileFormatVersion: 2
2
+ guid: 8841f748a9924814cbb010c54be7916e
@@ -1,10 +1,8 @@
1
1
  using System.Collections;
2
- using System.Runtime.InteropServices;
3
2
  using Hyper.Internal.Managers;
4
3
  using Hyper.Shared;
5
4
  using TMPro;
6
5
  using UnityEngine;
7
- using UnityEngine.SceneManagement;
8
6
  using UnityEngine.UI;
9
7
 
10
8
  namespace Hyper.Internal
@@ -12,38 +10,61 @@ namespace Hyper.Internal
12
10
  internal class StartingInstructionModal : MonoBehaviour
13
11
  {
14
12
 
15
- #if UNITY_WEBGL
16
- [DllImport("__Internal")]
17
- private static extern void MarkGameStartedOnHTML();
18
- #endif
19
13
  [SerializeField] private TextMeshProUGUI startCtaLabel;
20
14
  [SerializeField] private BlinkingText blinkingText;
21
15
  [SerializeField] private RectTransform swipeGif;
22
16
  [SerializeField] private RectTransform handSpriteInGif;
23
- private EventManager _eventManager;
24
- private DataManager _dataManager;
17
+ [SerializeField] private float replayAutoStartDelay = 1f;
25
18
  private GameManager _gameManager;
26
- private BackendManager _backendManager;
27
19
  private StartCTA _currentCTA;
28
20
  private SwipeDirection _swipeDirection;
29
21
 
30
22
  private bool _canAcceptInput = false;
31
23
  private Vector2 _swipeStartPosition;
32
24
  private bool _isTrackingSwipe;
25
+ private bool _hasStarted;
26
+ private Coroutine _replayAutoStartCoroutine;
33
27
  private const float SWIPE_THRESHOLD = 50f;
34
28
 
35
29
  void Awake()
36
30
  {
37
- _dataManager = HyperRuntime.DataManager;
38
- _eventManager = HyperRuntime.EventManager;
39
31
  _gameManager = HyperRuntime.GameManager;
40
- _backendManager = HyperRuntime.BackendManager;
41
32
  }
42
33
 
43
34
  void OnEnable()
44
35
  {
45
36
  _canAcceptInput = false;
46
- StartCoroutine(EnableInputAfterDelay());
37
+ _hasStarted = false;
38
+
39
+ if (HyperRuntime.GameManager != null && HyperRuntime.GameManager.IsReplayMode)
40
+ {
41
+ _replayAutoStartCoroutine = StartCoroutine(AutoStartReplay());
42
+ }
43
+ else
44
+ {
45
+ StartCoroutine(EnableInputAfterDelay());
46
+ }
47
+ }
48
+
49
+ private void OnDisable()
50
+ {
51
+ if (_replayAutoStartCoroutine != null)
52
+ {
53
+ StopCoroutine(_replayAutoStartCoroutine);
54
+ _replayAutoStartCoroutine = null;
55
+ }
56
+ }
57
+
58
+ private IEnumerator AutoStartReplay()
59
+ {
60
+ float elapsed = 0f;
61
+ float delay = Mathf.Max(0f, replayAutoStartDelay);
62
+ while (elapsed < delay)
63
+ {
64
+ if (Application.isFocused) elapsed += Time.unscaledDeltaTime;
65
+ yield return null;
66
+ }
67
+ StartGame();
47
68
  }
48
69
 
49
70
  private IEnumerator EnableInputAfterDelay()
@@ -59,6 +80,7 @@ namespace Hyper.Internal
59
80
 
60
81
  void Update()
61
82
  {
83
+ if (HyperRuntime.GameManager != null && HyperRuntime.GameManager.IsReplayMode) return;
62
84
  if (!gameObject.activeSelf || !_canAcceptInput) return;
63
85
 
64
86
  if (_currentCTA == StartCTA.TapToPlay)
@@ -279,23 +301,10 @@ namespace Hyper.Internal
279
301
  /// </summary>
280
302
  private void StartGame()
281
303
  {
282
- _gameManager.HideStartGameDeadlineSnackBar();
283
- _dataManager.UpdateScore(0);
284
- HyperRuntime.Timer.StartActiveGameTimer();
304
+ if (_hasStarted) return;
305
+ _hasStarted = true;
285
306
 
286
- _dataManager.StartCapturingScores(); // Start capture/sender immediately so offline starts still buffer score samples.
287
- _backendManager.StartSendingScores(); // Sender loop already pauses actual submissions while disconnected or token-gated.
288
-
289
- // startGame handshake can only be emitted when socket is connected.
290
- if (_backendManager.isSocketConnected)
291
- {
292
- _backendManager.SendGameStarted();
293
- }
294
-
295
- #if UNITY_WEBGL && !UNITY_EDITOR
296
- MarkGameStartedOnHTML();
297
- #endif
298
- _eventManager.InvokeGameStartEvent();
307
+ _gameManager.StartGameplay();
299
308
  gameObject.SetActive(false);
300
309
  }
301
310
 
@@ -0,0 +1,3 @@
1
+ using System.Runtime.CompilerServices;
2
+
3
+ [assembly: InternalsVisibleTo("Hyper.Tests.EditMode")]
@@ -0,0 +1,2 @@
1
+ fileFormatVersion: 2
2
+ guid: 2fefc67a1c18b054a84657d9260361b9