Skip to content

Commit 2e94f0f

Browse files
committed
Added Downloading Animation/Overlay
1 parent ae7317a commit 2e94f0f

8 files changed

Lines changed: 191 additions & 61 deletions

File tree

1.96 KB
Binary file not shown.

LevelImposter/LevelImposter.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,9 @@ public override void Load()
7878

7979
ClassInjector.RegisterTypeInIl2Cpp<Shop.ProgressBar>();
8080
ClassInjector.RegisterTypeInIl2Cpp<ConnectionAnimation>();
81+
ClassInjector.RegisterTypeInIl2Cpp<FloatingAnimation>();
8182
ClassInjector.RegisterTypeInIl2Cpp<PulseAnimation>();
83+
ClassInjector.RegisterTypeInIl2Cpp<LoadingOverlay>();
8284
ClassInjector.RegisterTypeInIl2Cpp<RandomOverlay>();
8385
ClassInjector.RegisterTypeInIl2Cpp<MapBanner>();
8486
ClassInjector.RegisterTypeInIl2Cpp<GameObjectGrid>();

LevelImposter/Shop/Components/ConnectionAnimation.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class ConnectionAnimation(IntPtr intPtr) : MonoBehaviour(intPtr)
1717
public Il2CppValueField<float> fadePercentage;
1818
public Il2CppValueField<float> animationDuration;
1919

20+
private bool _isReverse = false;
2021
private readonly List<SpriteRenderer> _dots = [];
2122

2223
public void Start()
@@ -44,6 +45,8 @@ private IEnumerator CoAnimateDots()
4445
// Calculate progress with offset
4546
var dotTimeOffset = t + (i * durationPerDot);
4647
var progress = (dotTimeOffset % animationDuration) / animationDuration;
48+
if (_isReverse)
49+
progress = 1.0f - progress;
4750

4851
// Position
4952
_dots[i].transform.localPosition = Vector3.Lerp(startPosition, endPosition, progress);
@@ -69,4 +72,13 @@ private IEnumerator CoAnimateDots()
6972
yield return null;
7073
}
7174
}
75+
76+
/// <summary>
77+
/// Sets whether the animation is in reverse.
78+
/// </summary>
79+
/// <param name="isReverse">True to reverse the animation, false for normal direction.</param>
80+
public void SetReverse(bool isReverse)
81+
{
82+
_isReverse = isReverse;
83+
}
7284
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using BepInEx.Unity.IL2CPP.Utils.Collections;
5+
using Il2CppInterop.Runtime.Attributes;
6+
using Il2CppInterop.Runtime.InteropTypes.Fields;
7+
using UnityEngine;
8+
9+
namespace LevelImposter.Shop;
10+
11+
public class FloatingAnimation(IntPtr intPtr) : MonoBehaviour(intPtr)
12+
{
13+
public Il2CppValueField<float> floatSpeed;
14+
public Il2CppValueField<float> floatAmplitude;
15+
16+
private Vector3 _initialPosition;
17+
18+
public void Start()
19+
{
20+
_initialPosition = transform.localPosition;
21+
}
22+
23+
public void Update()
24+
{
25+
var t = (Mathf.Sin(Time.time * floatSpeed) + 1f) / 2f; // Normalized to [0, 1]
26+
27+
transform.localPosition = _initialPosition + new Vector3(0, Mathf.Lerp(-floatAmplitude, floatAmplitude, t), 0);
28+
}
29+
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using BepInEx.Unity.IL2CPP.Utils.Collections;
5+
using Il2CppInterop.Runtime.Attributes;
6+
using Il2CppInterop.Runtime.InteropTypes.Fields;
7+
using TMPro;
8+
using UnityEngine;
9+
10+
namespace LevelImposter.Shop;
11+
12+
public class LoadingOverlay(IntPtr intPtr) : MonoBehaviour(intPtr)
13+
{
14+
// Serialized fields
15+
public Il2CppReferenceField<ConnectionAnimation> connectionAnimation;
16+
public Il2CppReferenceField<GameObject> errorAnimation;
17+
public Il2CppReferenceField<TextMeshPro> titleText;
18+
public Il2CppReferenceField<TextMeshPro> descriptionText;
19+
public Il2CppReferenceField<ProgressBar> progressBar;
20+
public Il2CppReferenceField<GameObject> fullBackground;
21+
public Il2CppReferenceField<PassiveButton> closeButton;
22+
23+
public bool PreventClose => fullBackground.Value.active && gameObject.activeSelf;
24+
25+
// Among Us themed loading texts
26+
private readonly string[] _funLoadingTexts =
27+
[
28+
"Searching for habitable planets...",
29+
"Scanning for planetary systems...",
30+
"Searching dropship...",
31+
"Calibrating engines...",
32+
"Stabilizing reactor...",
33+
"Aligning telescope...",
34+
"Navigating asteroids...",
35+
"Diverting power...",
36+
"Doing card swipe...",
37+
"Fueling engines...",
38+
"Charting course...",
39+
];
40+
41+
public void Awake()
42+
{
43+
closeButton.Value.OnClick.AddListener((Action)Hide);
44+
}
45+
46+
public void Show(
47+
bool reverseAnimation = false,
48+
bool preventClose = false)
49+
{
50+
// Show Overlay
51+
gameObject.SetActive(true);
52+
fullBackground.Value.SetActive(preventClose);
53+
54+
// Set Text
55+
RandomizeText();
56+
57+
// Connection Animation
58+
connectionAnimation.Value.gameObject.SetActive(true);
59+
connectionAnimation.Value.SetReverse(reverseAnimation);
60+
errorAnimation.Value.SetActive(false);
61+
62+
// Hide Close Button
63+
closeButton.Value.gameObject.SetActive(false);
64+
65+
// Progress Bar
66+
SetProgress(null);
67+
}
68+
69+
public void Hide()
70+
{
71+
gameObject.SetActive(false);
72+
}
73+
74+
public void ShowError(string title, string description)
75+
{
76+
// Show Overlay
77+
gameObject.SetActive(true);
78+
79+
// Set Text
80+
titleText.Value.text = title;
81+
descriptionText.Value.text = description;
82+
83+
// Show Error Animation
84+
connectionAnimation.Value.gameObject.SetActive(false);
85+
errorAnimation.Value.SetActive(true);
86+
87+
// Show Close Button if needed
88+
closeButton.Value.gameObject.SetActive(PreventClose);
89+
}
90+
91+
public void RandomizeText(string subtitle = "(Fetching maps)")
92+
{
93+
var randomIndex = UnityEngine.Random.Range(0, _funLoadingTexts.Length);
94+
SetText(_funLoadingTexts[randomIndex], subtitle);
95+
}
96+
97+
public void SetProgress(float? progress)
98+
{
99+
if (progress == null)
100+
{
101+
progressBar.Value.gameObject.SetActive(false);
102+
return;
103+
}
104+
105+
progressBar.Value.gameObject.SetActive(true);
106+
progressBar.Value.SetProgress(progress.Value);
107+
}
108+
109+
public void SetText(string title, string description)
110+
{
111+
titleText.Value.text = title;
112+
descriptionText.Value.text = description;
113+
}
114+
}

LevelImposter/Shop/Components/MapBanner.cs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,23 +98,35 @@ public void OnDownloadClick()
9898
throw new InvalidOperationException("Current map is null");
9999

100100
// Update UI Overlay
101-
// ShopManager.Instance?.SetOverlayEnabled(true);
102-
// OnDownloadProgress(0);
101+
ShopManager.Instance?.LoadingOverlay.Show(true, true);
102+
ShopManager.Instance?.LoadingOverlay.SetText($"Downloading {_currentMap.name}...", "(Looking for download URL)");
103103

104104
// Start Download
105105
MapFileAPI.DownloadMap(
106106
new Guid(_currentMap.id),
107-
null,
107+
OnMapDownloadProgress,
108108
OnMapDownloaded,
109-
LILogger.Error);
109+
OnMapDownloadError);
110110
}
111111
[HideFromIl2Cpp]
112112
private void OnMapDownloaded(FileStore _)
113113
{
114-
// ShopManager.Instance?.SetOverlayEnabled(false);
114+
ShopManager.Instance?.LoadingOverlay.Hide();
115115
ShopManager.Instance?.RandomizeMapOnClose();
116116
UpdateButtonState();
117117
}
118+
private void OnMapDownloadProgress(float percent)
119+
{
120+
ShopManager.Instance?.LoadingOverlay.SetText(
121+
$"Downloading {_currentMap?.name ?? "map"}...",
122+
$"{Mathf.RoundToInt(percent * 100)}%");
123+
124+
ShopManager.Instance?.LoadingOverlay.SetProgress(percent);
125+
}
126+
private void OnMapDownloadError(string error)
127+
{
128+
ShopManager.Instance?.LoadingOverlay.ShowError("The impostor sabotaged the download!", error);
129+
}
118130

119131
/// <summary>
120132
/// Launches the specified map in freeplay mode

LevelImposter/Shop/Components/ProgressBar.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ public class ProgressBar(IntPtr intPtr) : MonoBehaviour(intPtr)
2424
public void Update()
2525
{
2626
// Update fill size
27-
var currentFillSize = progressBarFill.Value.size.x;
28-
var targetFillSize = _progress * progressBarBackground.Value.size.x;
29-
if (Mathf.Approximately(currentFillSize, targetFillSize))
27+
var currentProgress = progressBarFill.Value.size.x / progressBarBackground.Value.size.x;
28+
if (Mathf.Approximately(_progress, currentProgress))
3029
return;
3130

3231
// Animate the fill towards the target
33-
var deltaFillSize = (currentFillSize - targetFillSize) * ANIMATION_SPEED * Time.deltaTime;
34-
var newFillSize = currentFillSize - deltaFillSize;
35-
progressBarFill.Value.size = new Vector2(newFillSize, progressBarFill.Value.size.y);
32+
var deltaProgress = (currentProgress - _progress) * ANIMATION_SPEED * Time.deltaTime;
33+
var newProgress = currentProgress - deltaProgress;
34+
var fillSize = newProgress * progressBarBackground.Value.size.x;
35+
progressBarFill.Value.size = new Vector2(fillSize, progressBarFill.Value.size.y);
3636

3737
// Update color if set
3838
var currentColor = progressBarFill.Value.color;

LevelImposter/Shop/Components/ShopManager.cs

Lines changed: 11 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -38,31 +38,18 @@ public class ShopManager(IntPtr intPtr) : MonoBehaviour(intPtr)
3838
public Il2CppReferenceField<GameObjectGrid> mapBannerGrid;
3939
public Il2CppReferenceField<PassiveButton> exitButton;
4040
public Il2CppReferenceField<PassiveButton> openMapsFolderButton;
41-
public Il2CppReferenceField<GameObject> loadingOverlay;
42-
public Il2CppReferenceField<TextMeshPro> loadingText;
43-
public Il2CppReferenceField<GameObject> errorOverlay;
44-
public Il2CppReferenceField<TextMeshPro> errorText;
41+
public Il2CppReferenceField<LoadingOverlay> loadingOverlay;
4542

4643
public static ShopManager? Instance { get; private set; }
4744

4845
private const string CONTROLLER_OVERLAY_ID = "LIShop";
4946

47+
public LoadingOverlay LoadingOverlay => loadingOverlay.Value;
48+
5049
/// If true, re-runs the map randomization when the shop is closed
5150
private bool _randomizeMapsOnClose;
5251
private ShopTab _currentTab = ShopTab.None;
5352
private ShopTabButton[]? _shopTabButtons;
54-
private readonly string[] _funLoadingTexts =
55-
[
56-
"Searching dropship...",
57-
"Calibrating engines...",
58-
"Searching for habitable planets...",
59-
"Stabilizing reactor...",
60-
"Scanning for planetary systems...",
61-
"Aligning telescope...",
62-
"Navigating asteroids...",
63-
"Diverting power...",
64-
"Doing card swipe..."
65-
];
6653

6754
public void Awake()
6855
{
@@ -104,6 +91,9 @@ private static void OpenMapsFolder()
10491
/// </summary>
10592
public void CloseShop()
10693
{
94+
if (LoadingOverlay.PreventClose)
95+
return;
96+
10797
if (_randomizeMapsOnClose)
10898
MapRandomizer.RandomizeMap(false);
10999

@@ -147,19 +137,19 @@ public void SetTab(ShopTab tab, Sprite? titleSprite = null)
147137
SetMaps(lobbyMaps);
148138
break;
149139
case ShopTab.FeaturedWorkshopMaps:
150-
SetLoadingVisible(true);
140+
LoadingOverlay.Show();
151141
LevelImposterAPI.GetFeatured(
152142
m => OnWorkshopLoaded(m, tab),
153143
error => OnError(tab, error));
154144
break;
155145
case ShopTab.TopWorkshopMaps:
156-
SetLoadingVisible(true);
146+
LoadingOverlay.Show();
157147
LevelImposterAPI.GetTop(
158148
m => OnWorkshopLoaded(m, tab),
159149
error => OnError(tab, error));
160150
break;
161151
case ShopTab.RecentWorkshopMaps:
162-
SetLoadingVisible(true);
152+
LoadingOverlay.Show();
163153
LevelImposterAPI.GetRecent(
164154
m => OnWorkshopLoaded(m, tab),
165155
error => OnError(tab, error));
@@ -185,17 +175,7 @@ private void OnError(ShopTab tab, string message)
185175
if (_currentTab != tab)
186176
return;
187177

188-
SetErrorVisible(true, message);
189-
}
190-
private void SetErrorVisible(bool isVisible, string message = "")
191-
{
192-
errorOverlay.Value.SetActive(isVisible);
193-
errorText.Value.text = message;
194-
if (!isVisible)
195-
return;
196-
197-
// Disable loading overlay
198-
SetLoadingVisible(false);
178+
LoadingOverlay.ShowError("The impostor sabotaged comms!", message);
199179
}
200180

201181
/// <summary>
@@ -219,8 +199,7 @@ private void UpdateTabButtonState()
219199
private void SetMaps(LIMetadata[] maps)
220200
{
221201
// Hide Overlays
222-
SetLoadingVisible(false);
223-
SetErrorVisible(false);
202+
LoadingOverlay.Hide();
224203

225204
// Clear Existing Banners
226205
mapBannerGrid.Value.DestroyAll();
@@ -246,24 +225,6 @@ public void RandomizeMapOnClose()
246225
{
247226
_randomizeMapsOnClose = true;
248227
}
249-
250-
/// <summary>
251-
/// Shows or hides the loading overlay
252-
/// </summary>
253-
/// <param name="isVisible">Whether the loading overlay should be visible</param>
254-
public void SetLoadingVisible(bool isVisible)
255-
{
256-
loadingOverlay.Value.SetActive(isVisible);
257-
if (!isVisible)
258-
return;
259-
260-
// Disable error overlay
261-
SetErrorVisible(false);
262-
263-
// Randomize loading text
264-
var randomIndex = UnityEngine.Random.Range(0, _funLoadingTexts.Length);
265-
loadingText.Value.text = _funLoadingTexts[randomIndex];
266-
}
267228

268229
private void AddStarField()
269230
{

0 commit comments

Comments
 (0)