diff --git a/LevelImposter/Assets/Assets b/LevelImposter/Assets/Assets
index 8e5be716..fcaa5b1c 100644
Binary files a/LevelImposter/Assets/Assets and b/LevelImposter/Assets/Assets differ
diff --git a/LevelImposter/Assets/Assets.manifest b/LevelImposter/Assets/Assets.manifest
index 801ecd57..d1a8d272 100644
--- a/LevelImposter/Assets/Assets.manifest
+++ b/LevelImposter/Assets/Assets.manifest
@@ -1,7 +1,10 @@
ManifestFileVersion: 0
-CRC: 2386985233
+CRC: 2742641410
AssetBundleManifest:
AssetBundleInfos:
Info_0:
Name: shop
Dependencies: {}
+ Info_1:
+ Name: loadingbar
+ Dependencies: {}
diff --git a/LevelImposter/Assets/loadingbar b/LevelImposter/Assets/loadingbar
new file mode 100644
index 00000000..bf421337
Binary files /dev/null and b/LevelImposter/Assets/loadingbar differ
diff --git a/LevelImposter/Assets/loadingbar.manifest b/LevelImposter/Assets/loadingbar.manifest
new file mode 100644
index 00000000..9f2d819e
--- /dev/null
+++ b/LevelImposter/Assets/loadingbar.manifest
@@ -0,0 +1,77 @@
+ManifestFileVersion: 0
+CRC: 3049509670
+Hashes:
+ AssetFileHash:
+ serializedVersion: 2
+ Hash: 2e5e38824854ae56f754be848fb8fa52
+ TypeTreeHash:
+ serializedVersion: 2
+ Hash: 7c653b85788f9e6027325f678c0f4f02
+HashAppended: 0
+ClassTypes:
+- Class: 1
+ Script: {instanceID: 0}
+- Class: 4
+ Script: {instanceID: 0}
+- Class: 21
+ Script: {instanceID: 0}
+- Class: 23
+ Script: {instanceID: 0}
+- Class: 28
+ Script: {instanceID: 0}
+- Class: 48
+ Script: {instanceID: 0}
+- Class: 114
+ Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3}
+- Class: 114
+ Script: {fileID: 11500000, guid: 71c1514a6bd24e1e882cebbe1904ce04, type: 3}
+- Class: 114
+ Script: {fileID: 11500000, guid: e27d931aa83cda344a1633cd123a82c9, type: 3}
+- Class: 115
+ Script: {instanceID: 0}
+- Class: 128
+ Script: {instanceID: 0}
+- Class: 212
+ Script: {instanceID: 0}
+- Class: 213
+ Script: {instanceID: 0}
+- Class: 224
+ Script: {instanceID: 0}
+- Class: 331
+ Script: {instanceID: 0}
+SerializeReferenceClassIdentifiers:
+- AssemblyName: Unity.TextMeshPro
+ ClassName: TMPro.FaceInfo_Legacy
+- AssemblyName: Unity.TextMeshPro
+ ClassName: TMPro.FontAssetCreationSettings
+- AssemblyName: Unity.TextMeshPro
+ ClassName: TMPro.KerningTable
+- AssemblyName: Unity.TextMeshPro
+ ClassName: TMPro.TMP_Character
+- AssemblyName: Unity.TextMeshPro
+ ClassName: TMPro.TMP_FontFeatureTable
+- AssemblyName: Unity.TextMeshPro
+ ClassName: TMPro.TMP_FontWeightPair
+- AssemblyName: Unity.TextMeshPro
+ ClassName: TMPro.TMP_GlyphAdjustmentRecord
+- AssemblyName: Unity.TextMeshPro
+ ClassName: TMPro.TMP_GlyphPairAdjustmentRecord
+- AssemblyName: Unity.TextMeshPro
+ ClassName: TMPro.TMP_GlyphValueRecord
+- AssemblyName: Unity.TextMeshPro
+ ClassName: TMPro.VertexGradient
+- AssemblyName: UnityEngine.CoreModule
+ ClassName: UnityEngine.Events.PersistentCallGroup
+- AssemblyName: UnityEngine.TextCoreModule
+ ClassName: UnityEngine.TextCore.FaceInfo
+- AssemblyName: UnityEngine.TextCoreModule
+ ClassName: UnityEngine.TextCore.Glyph
+- AssemblyName: UnityEngine.TextCoreModule
+ ClassName: UnityEngine.TextCore.GlyphMetrics
+- AssemblyName: UnityEngine.TextCoreModule
+ ClassName: UnityEngine.TextCore.GlyphRect
+- AssemblyName: UnityEngine.UI
+ ClassName: UnityEngine.UI.MaskableGraphic/CullStateChangedEvent
+Assets:
+- Assets/Prefabs/LoadingBar.prefab
+Dependencies: []
diff --git a/LevelImposter/Assets/shop b/LevelImposter/Assets/shop
index 1081ba73..87721262 100644
Binary files a/LevelImposter/Assets/shop and b/LevelImposter/Assets/shop differ
diff --git a/LevelImposter/Assets/shop.manifest b/LevelImposter/Assets/shop.manifest
index 0b107693..9553dfe7 100644
--- a/LevelImposter/Assets/shop.manifest
+++ b/LevelImposter/Assets/shop.manifest
@@ -1,9 +1,9 @@
ManifestFileVersion: 0
-CRC: 3599790525
+CRC: 4005544444
Hashes:
AssetFileHash:
serializedVersion: 2
- Hash: e2dbbc72aa56e5fcbee1c2078a7f2c27
+ Hash: 95736c394c97a65fc511c7395fb99918
TypeTreeHash:
serializedVersion: 2
Hash: afd525e58be886efe4d69cac465cee90
diff --git a/LevelImposter/Builders/BuildRouter.cs b/LevelImposter/Builders/BuildRouter.cs
index 7a9fb83a..0c86611a 100644
--- a/LevelImposter/Builders/BuildRouter.cs
+++ b/LevelImposter/Builders/BuildRouter.cs
@@ -53,11 +53,20 @@ public class BuildRouter
new TriggerAreaBuilder(),
new TriggerConsoleBuilder(),
new TriggerStartBuilder(),
+ new TriggerDeathBuilder(),
+ new TriggerShakeBuilder(),
new TriggerBuilder(),
+ new CustomTextBuilder(),
new ColorBuilder()
};
+ ///
+ /// Patch me to add your own custom builders.
+ /// Builders should implement IElemBuilder.
+ ///
+ public BuildRouter() { }
+
///
/// Passes LIElement data through the build
/// stack to construct a GameObject.
diff --git a/LevelImposter/Builders/Generic/CustomTextBuilder.cs b/LevelImposter/Builders/Generic/CustomTextBuilder.cs
new file mode 100644
index 00000000..c4bb5035
--- /dev/null
+++ b/LevelImposter/Builders/Generic/CustomTextBuilder.cs
@@ -0,0 +1,68 @@
+using LevelImposter.Core;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace LevelImposter.Builders
+{
+ ///
+ /// Replaces String in the Translation Controller with Custom Text
+ ///
+ public class CustomTextBuilder : IElemBuilder
+ {
+ private readonly Dictionary _customTextDB = new Dictionary
+ {
+ { "MedHello", StringNames.MedHello },
+ { "SamplesPress", StringNames.SamplesPress },
+ { "SamplesSelect", StringNames.SamplesSelect },
+ { "MedETA", StringNames.MedETA },
+ { "BadResult", StringNames.BadResult },
+ { "SamplesThanks", StringNames.SamplesThanks },
+ { "SamplesComplete", StringNames.SamplesComplete },
+ { "More", StringNames.More },
+ { "SamplesAdding", StringNames.SamplesAdding },
+ { "TakeBreak", StringNames.TakeBreak },
+ { "GrabCoffee", StringNames.GrabCoffee },
+ { "DontNeedWait", StringNames.DontNeedWait },
+ { "DoSomethingElse", StringNames.DoSomethingElse },
+ { "ReactorNominal", StringNames.ReactorNominal },
+ { "ReactorHoldToStop", StringNames.ReactorHoldToStop },
+ { "ReactorWaiting", StringNames.ReactorWaiting },
+ };
+
+ public void Build(LIElement elem, GameObject obj)
+ {
+ // Get Custom Text
+ var customText = elem.properties.customText;
+ if (customText == null || customText.Count <= 0)
+ return;
+
+ // ShipStatus
+ var shipStatus = LIShipStatus.Instance;
+ if (shipStatus == null)
+ throw new MissingShipException();
+
+ // Replace Custom Text
+ foreach (var (textID, text) in customText)
+ {
+ // Skip Empty Text
+ if (string.IsNullOrEmpty(textID) || string.IsNullOrEmpty(text))
+ continue;
+
+ // Find String Name
+ bool hasTextID = _customTextDB.TryGetValue(textID, out StringNames stringName);
+ if (!hasTextID)
+ {
+ LILogger.Warn($"Unknown custom text '{textID}'");
+ continue;
+ }
+
+ // Replace Text
+ shipStatus.Renames.Add(stringName, text);
+ LILogger.Info($"Custom Text '{stringName}' >>> '{text}'");
+ }
+
+ }
+
+ public void PostBuild() { }
+ }
+}
diff --git a/LevelImposter/Builders/Sab/SabConsoleBuilder.cs b/LevelImposter/Builders/Sab/SabConsoleBuilder.cs
index b467cfc6..4206d519 100644
--- a/LevelImposter/Builders/Sab/SabConsoleBuilder.cs
+++ b/LevelImposter/Builders/Sab/SabConsoleBuilder.cs
@@ -52,7 +52,7 @@ public void Build(LIElement elem, GameObject obj)
Console console = obj.AddComponent();
console.ConsoleId = 0;
console.Image = spriteRenderer;
- console.onlyFromBelow = elem.properties.onlyFromBelow == null ? true : (bool)elem.properties.onlyFromBelow;
+ console.onlyFromBelow = elem.properties.onlyFromBelow ?? true;
console.usableDistance = elem.properties.range ?? 1.0f;
console.Room = systemType;
console.TaskTypes = prefabConsole.TaskTypes;
diff --git a/LevelImposter/Builders/Trigger/TriggerDeathBuilder.cs b/LevelImposter/Builders/Trigger/TriggerDeathBuilder.cs
new file mode 100644
index 00000000..bfe52f3b
--- /dev/null
+++ b/LevelImposter/Builders/Trigger/TriggerDeathBuilder.cs
@@ -0,0 +1,25 @@
+using LevelImposter.Core;
+using UnityEngine;
+
+namespace LevelImposter.Builders
+{
+ public class TriggerDeathBuilder : IElemBuilder
+ {
+ public void Build(LIElement elem, GameObject obj)
+ {
+ if (elem.type != "util-triggerdeath")
+ return;
+
+ // Colliders
+ Collider2D[] colliders = obj.GetComponentsInChildren();
+ foreach (Collider2D collider in colliders)
+ collider.isTrigger = true;
+
+ // Trigger Area
+ LIDeathArea deathArea = obj.AddComponent();
+ deathArea.SetCreateDeadBody(elem.properties.createDeadBody ?? true);
+ }
+
+ public void PostBuild() { }
+ }
+}
diff --git a/LevelImposter/Builders/Trigger/TriggerShakeBuilder.cs b/LevelImposter/Builders/Trigger/TriggerShakeBuilder.cs
new file mode 100644
index 00000000..7478961a
--- /dev/null
+++ b/LevelImposter/Builders/Trigger/TriggerShakeBuilder.cs
@@ -0,0 +1,28 @@
+using LevelImposter.Core;
+using UnityEngine;
+
+namespace LevelImposter.Builders
+{
+ public class TriggerShakeBuilder : IElemBuilder
+ {
+ public void Build(LIElement elem, GameObject obj)
+ {
+ if (elem.type != "util-triggershake")
+ return;
+
+ // Colliders
+ Collider2D[] colliders = obj.GetComponentsInChildren();
+ foreach (Collider2D collider in colliders)
+ collider.isTrigger = true;
+
+ // Trigger Area
+ LIShakeArea shakeArea = obj.AddComponent();
+ shakeArea.SetParameters(
+ elem.properties.shakeAmount ?? 0.03f,
+ elem.properties.shakePeriod ?? 400.0f
+ );
+ }
+
+ public void PostBuild() { }
+ }
+}
diff --git a/LevelImposter/Core/Components/GIFAnimator.cs b/LevelImposter/Core/Components/GIFAnimator.cs
index 2d72910a..46464402 100644
--- a/LevelImposter/Core/Components/GIFAnimator.cs
+++ b/LevelImposter/Core/Components/GIFAnimator.cs
@@ -33,6 +33,7 @@ public GIFAnimator(IntPtr intPtr) : base(intPtr)
private bool _defaultLoopGIF = false;
private bool _isAnimating = false;
+ private int _frame = 0;
private GIFFile? _gifData = null;
private SpriteRenderer? _spriteRenderer;
private Coroutine? _animationCoroutine = null;
@@ -99,7 +100,8 @@ public void Stop(bool reversed = false)
if (_spriteRenderer != null && _gifData != null)
{
- _spriteRenderer.sprite = _gifData.GetFrameSprite(reversed ? _gifData.Frames.Count - 1 : 0);
+ _frame = reversed ? _gifData.Frames.Count - 1 : 0;
+ _spriteRenderer.sprite = _gifData.GetFrameSprite(_frame);
_spriteRenderer.enabled = true;
}
}
@@ -117,7 +119,6 @@ private IEnumerator CoAnimate(bool repeat, bool reverse)
yield break;
_isAnimating = true;
_spriteRenderer.enabled = true;
- int t = 0;
while (_isAnimating)
{
// Wait for main thread
@@ -125,15 +126,20 @@ private IEnumerator CoAnimate(bool repeat, bool reverse)
yield return null;
// Render sprite
- int frame = reverse ? _gifData.Frames.Count - t - 1 : t;
- _spriteRenderer.sprite = _gifData.GetFrameSprite(frame);
+ _spriteRenderer.sprite = _gifData.GetFrameSprite(_frame);
// Wait for next frame
- yield return new WaitForSeconds(_gifData.Frames[frame].Delay);
+ yield return new WaitForSeconds(_gifData.Frames[_frame].Delay);
- // Update time
- t = (t + 1) % _gifData.Frames.Count;
- if (t == 0 && !repeat)
+ // Update frame index
+ _frame = reverse ? _frame - 1 : _frame + 1;
+
+ // Keep frame in bounds
+ bool isOutOfBounds = _frame < 0 || _frame >= _gifData.Frames.Count;
+ _frame = (_frame + _gifData.Frames.Count) % _gifData.Frames.Count;
+
+ // Stop if out of bounds
+ if (isOutOfBounds && !repeat)
Stop(!reverse);
}
}
diff --git a/LevelImposter/Core/Components/LIDeathArea.cs b/LevelImposter/Core/Components/LIDeathArea.cs
new file mode 100644
index 00000000..1e13d7ef
--- /dev/null
+++ b/LevelImposter/Core/Components/LIDeathArea.cs
@@ -0,0 +1,94 @@
+using Reactor.Networking.Attributes;
+using System;
+using System.Linq;
+using UnityEngine;
+
+namespace LevelImposter.Core
+{
+ ///
+ /// Object that kills all players that enter it's range
+ ///
+ public class LIDeathArea : PlayerArea
+ {
+ public LIDeathArea(IntPtr intPtr) : base(intPtr)
+ {
+ }
+
+ private bool _createDeadBody = true;
+
+ public void SetCreateDeadBody(bool value)
+ {
+ _createDeadBody = value;
+ }
+
+ public void KillAllPlayers()
+ {
+ if (CurrentPlayersIDs == null)
+ return;
+
+ // Only the host can handle kill triggers?
+ if (!AmongUsClient.Instance.AmHost)
+ return;
+
+ // Iterate over all players in the area
+ byte[] playerIDs = CurrentPlayersIDs.ToArray(); // <-- Copy to avoid mutation during iteration
+ foreach (byte playerID in playerIDs)
+ {
+ // Get Player by ID
+ PlayerControl? player = GetPlayer(playerID);
+ if (player == null)
+ continue;
+
+ // Fire RPC to kill player
+ RPCTriggerDeath(player, _createDeadBody);
+ }
+ }
+
+ [MethodRpc((uint)LIRpc.KillPlayer)]
+ public static void RPCTriggerDeath(PlayerControl player, bool createDeadBody)
+ {
+ if (player == null || player.Data.IsDead)
+ return;
+ LILogger.Info($"[RPC] Trigger killing {player.name}");
+
+ // Kill Player
+ player.Die(DeathReason.Kill, false);
+
+ // Play Kill Sound (if I'm the Player)
+ if (player.AmOwner)
+ PlayKillSound();
+
+ // Create Dead Body
+ if (createDeadBody)
+ CreateDeadBody(player);
+ }
+
+ private static void CreateDeadBody(PlayerControl player)
+ {
+ // Create/Disable Dead Body
+ DeadBody deadBody = Instantiate(GameManager.Instance.DeadBodyPrefab);
+ deadBody.enabled = false;
+ deadBody.ParentId = player.PlayerId;
+
+ // Set Colors
+ foreach (SpriteRenderer renderer in deadBody.bodyRenderers)
+ player.SetPlayerMaterialColors(renderer);
+ player.SetPlayerMaterialColors(deadBody.bloodSplatter);
+
+ // Set Offset
+ Vector3 bodyOffset = player.KillAnimations.First().BodyOffset;
+ Vector3 bodyPosition = player.transform.position + bodyOffset;
+ bodyPosition.z = bodyPosition.y / 1000f;
+ deadBody.transform.position = bodyPosition;
+
+ // Enable Dead Body
+ deadBody.enabled = true;
+ }
+
+ private static void PlayKillSound()
+ {
+ AudioClip killSFX = PlayerControl.LocalPlayer.KillSfx;
+ SoundManager.Instance.PlaySound(killSFX, false, 0.8f);
+ }
+ }
+}
diff --git a/LevelImposter/Core/Components/LIShakeArea.cs b/LevelImposter/Core/Components/LIShakeArea.cs
new file mode 100644
index 00000000..4817e7f2
--- /dev/null
+++ b/LevelImposter/Core/Components/LIShakeArea.cs
@@ -0,0 +1,53 @@
+using System;
+using UnityEngine;
+
+namespace LevelImposter.Core
+{
+ ///
+ /// Object that shakes the screen when players enter it's range
+ ///
+ public class LIShakeArea : PlayerArea
+ {
+ public LIShakeArea(IntPtr intPtr) : base(intPtr)
+ {
+ }
+
+ private float _shakeAmount = 0.03f;
+ private float _shakePeriod = 400.0f;
+
+ public void SetParameters(float shakeAmount, float shakePeriod)
+ {
+ _shakeAmount = shakeAmount;
+ _shakePeriod = shakePeriod;
+ }
+
+ public void SetEnabled(bool enabled)
+ {
+ this.enabled = enabled;
+ SetShakeEnabled(enabled && IsLocalPlayerInside);
+ }
+
+ private void SetShakeEnabled(bool enabled)
+ {
+ FollowerCamera camera = Camera.main.GetComponent();
+ if (camera != null)
+ {
+ camera.shakeAmount = enabled ? _shakeAmount : 0.0f;
+ camera.shakePeriod = enabled ? _shakePeriod : 0.0f;
+ }
+ }
+
+ protected override void OnPlayerEnter(PlayerControl player)
+ {
+ LILogger.Info("Player Entered");
+ if (player.AmOwner)
+ SetShakeEnabled(true);
+ }
+
+ protected override void OnPlayerExit(PlayerControl player)
+ {
+ if (player.AmOwner)
+ SetShakeEnabled(false);
+ }
+ }
+}
diff --git a/LevelImposter/Core/Components/LIShipStatus.cs b/LevelImposter/Core/Components/LIShipStatus.cs
index 5114962b..29a7e65e 100644
--- a/LevelImposter/Core/Components/LIShipStatus.cs
+++ b/LevelImposter/Core/Components/LIShipStatus.cs
@@ -238,20 +238,46 @@ private IEnumerator CoLoadingScreen()
GameObject loadingBean = DestroyableSingleton.Instance.GameLoadAnimation;
Color sabColor = fullScreen.color;
- // Loading
+ // Create LoadingBar
+ if (LoadingBar.Instance == null)
+ Instantiate(MapUtils.LoadAssetBundle("loadingbar"), DestroyableSingleton.Instance.transform);
+ if (LoadingBar.Instance == null)
+ LILogger.Warn("Missing LoadingBar asset bundle!");
+
+ // Show Loading Screen
LILogger.Info($"Showing loading screen (Freeplay={isFreeplay})");
if (isFreeplay)
{
fullScreen.color = new Color(0, 0, 0, 0.9f);
fullScreen.gameObject.SetActive(true);
}
+ LoadingBar.Instance?.SetMapName(CurrentMap?.name ?? "Loading...");
+ LoadingBar.Instance?.SetVisible(true);
while (!IsReady)
{
loadingBean.SetActive(true);
+
+ // Approximate Progress
+ if (SpriteLoader.Instance?.RenderCount > 0)
+ {
+ double renderTotal = SpriteLoader.Instance?.RenderTotal ?? 1;
+ if (renderTotal == 0)
+ renderTotal = 1;
+ double renderCount = renderTotal - (SpriteLoader.Instance?.RenderCount ?? 0);
+ float progress = (float)(renderCount / renderTotal);
+ LoadingBar.Instance?.SetProgress(progress);
+ LoadingBar.Instance?.SetStatus($"{Math.Round(progress * 100)}% ({renderCount}/{renderTotal})");
+ }
+ else
+ {
+ LoadingBar.Instance?.SetProgress(1);
+ LoadingBar.Instance?.SetStatus("waiting for host");
+ }
+
yield return null;
}
- // Sabotage
+ // Revert Loading Screen
LILogger.Info($"Hiding loading screen (Freeplay={isFreeplay})");
if (isFreeplay)
{
@@ -259,6 +285,7 @@ private IEnumerator CoLoadingScreen()
fullScreen.gameObject.SetActive(false);
}
loadingBean.SetActive(false);
+ LoadingBar.Instance?.SetVisible(false);
}
///
diff --git a/LevelImposter/Core/Components/LITriggerArea.cs b/LevelImposter/Core/Components/LITriggerArea.cs
index cd555a80..10b1d44c 100644
--- a/LevelImposter/Core/Components/LITriggerArea.cs
+++ b/LevelImposter/Core/Components/LITriggerArea.cs
@@ -1,13 +1,11 @@
using System;
-using System.Collections.Generic;
-using UnityEngine;
namespace LevelImposter.Core
{
///
/// Object that fires a trigger when the player enters/exits it's range
///
- public class LITriggerArea : MonoBehaviour
+ public class LITriggerArea : PlayerArea
{
public LITriggerArea(IntPtr intPtr) : base(intPtr)
{
@@ -16,7 +14,6 @@ public LITriggerArea(IntPtr intPtr) : base(intPtr)
private const string ENTER_TRIGGGER_ID = "onEnter";
private const string EXIT_TRIGGER_ID = "onExit";
- private List? _currentPlayersIDs = new();
private bool _isClientSide = false;
///
@@ -28,36 +25,20 @@ public void SetClientSide(bool isClientSide)
_isClientSide = isClientSide;
}
- public void OnTriggerEnter2D(Collider2D collider)
+ protected override void OnPlayerEnter(PlayerControl player)
{
- PlayerControl? player = collider.GetComponent();
- if (player == null)
- return;
-
- bool triggerServerSided = _currentPlayersIDs?.Count <= 0 && !_isClientSide;
- bool triggerClientSided = MapUtils.IsLocalPlayer(collider.gameObject) && _isClientSide;
+ bool triggerServerSided = CurrentPlayersIDs?.Count <= 1 && !_isClientSide;
+ bool triggerClientSided = player.AmOwner && _isClientSide;
if (triggerClientSided || triggerServerSided)
LITriggerable.Trigger(transform.gameObject, ENTER_TRIGGGER_ID, null);
-
- if (_currentPlayersIDs?.Contains(player.PlayerId) ?? false)
- _currentPlayersIDs?.Add(player.PlayerId);
}
- public void OnTriggerExit2D(Collider2D collider)
- {
- PlayerControl? player = collider.GetComponent();
- if (player == null)
- return;
-
- _currentPlayersIDs?.RemoveAll(id => id == player.PlayerId);
- bool triggerServer = _currentPlayersIDs?.Count <= 0 && !_isClientSide;
- bool triggerClient = MapUtils.IsLocalPlayer(collider.gameObject) && _isClientSide;
- if (triggerClient || triggerServer)
- LITriggerable.Trigger(transform.gameObject, EXIT_TRIGGER_ID, null);
- }
- public void OnDestroy()
+ protected override void OnPlayerExit(PlayerControl player)
{
- _currentPlayersIDs = null;
+ bool triggerServerSided = CurrentPlayersIDs?.Count <= 0 && !_isClientSide;
+ bool triggerClientSided = player.AmOwner && _isClientSide;
+ if (triggerClientSided || triggerServerSided)
+ LITriggerable.Trigger(transform.gameObject, EXIT_TRIGGER_ID, null);
}
}
}
diff --git a/LevelImposter/Core/Components/LITriggerable.cs b/LevelImposter/Core/Components/LITriggerable.cs
index fd253fdd..c461445a 100644
--- a/LevelImposter/Core/Components/LITriggerable.cs
+++ b/LevelImposter/Core/Components/LITriggerable.cs
@@ -234,6 +234,11 @@ private void OnTrigger(PlayerControl? orgin, int stackSize = 0)
trigger.StopTimer();
break;
+ // Death
+ case "killArea":
+ SetComponentsEnabled(true);
+ break;
+
// Door
case "open":
SetDoorOpen(true);
@@ -358,6 +363,16 @@ private void SetComponentsEnabled(bool? isEnabled = null, bool? isLooped = null)
LITeleporter? teleporter = GetComponent();
if (teleporter != null)
teleporter.enabled = isEnabled ?? !teleporter.enabled;
+
+ // Kill Area
+ LIDeathArea? deathArea = GetComponent();
+ if (deathArea != null)
+ deathArea.KillAllPlayers();
+
+ // Trigger Shake
+ LIShakeArea? triggerShake = GetComponent();
+ if (triggerShake != null)
+ triggerShake.SetEnabled(isEnabled ?? !triggerShake.enabled);
}
///
diff --git a/LevelImposter/Core/Components/PlayerArea.cs b/LevelImposter/Core/Components/PlayerArea.cs
new file mode 100644
index 00000000..d6230334
--- /dev/null
+++ b/LevelImposter/Core/Components/PlayerArea.cs
@@ -0,0 +1,85 @@
+using Il2CppInterop.Runtime.Attributes;
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace LevelImposter.Core
+{
+ ///
+ /// Object that tracks the players that are inside it's range
+ ///
+ public class PlayerArea : MonoBehaviour
+ {
+ public PlayerArea(IntPtr intPtr) : base(intPtr)
+ {
+ }
+
+ private List? _currentPlayersIDs = new();
+ private bool _isLocalPlayerInside = false;
+
+ [HideFromIl2Cpp]
+ protected List? CurrentPlayersIDs => _currentPlayersIDs;
+ protected bool IsLocalPlayerInside => _isLocalPlayerInside;
+
+ ///
+ /// Gets a player by it's ID
+ ///
+ /// Player ID to search
+ /// The cooresponding PlayerControl or null if it can't be found
+ protected PlayerControl? GetPlayer(byte playerID)
+ {
+ foreach (PlayerControl player in PlayerControl.AllPlayerControls)
+ if (player.PlayerId == playerID)
+ return player;
+ return null;
+ }
+
+ ///
+ /// Called when a player enters the collider
+ ///
+ /// Player that entered the collider
+ virtual protected void OnPlayerEnter(PlayerControl player)
+ {
+ }
+
+ ///
+ /// Called when a player exits the collider
+ ///
+ /// Player that exited the collider
+ virtual protected void OnPlayerExit(PlayerControl player)
+ {
+ }
+
+ public void OnTriggerEnter2D(Collider2D collider)
+ {
+ PlayerControl? player = collider.GetComponent();
+ if (player == null)
+ return;
+
+ _currentPlayersIDs?.Add(player.PlayerId);
+ if (player.AmOwner)
+ _isLocalPlayerInside = true;
+
+ if (enabled)
+ OnPlayerEnter(player);
+ }
+
+ public void OnTriggerExit2D(Collider2D collider)
+ {
+ PlayerControl? player = collider.GetComponent();
+ if (player == null)
+ return;
+
+ _currentPlayersIDs?.RemoveAll(id => id == player.PlayerId);
+ if (player.AmOwner)
+ _isLocalPlayerInside = false;
+
+ if (enabled)
+ OnPlayerExit(player);
+ }
+ public void OnDestroy()
+ {
+ _currentPlayersIDs = null;
+ }
+ }
+}
diff --git a/LevelImposter/Core/Components/SpriteLoader.cs b/LevelImposter/Core/Components/SpriteLoader.cs
index dd2ac287..9843fe82 100644
--- a/LevelImposter/Core/Components/SpriteLoader.cs
+++ b/LevelImposter/Core/Components/SpriteLoader.cs
@@ -28,8 +28,10 @@ public SpriteLoader(IntPtr intPtr) : base(intPtr)
private Stack? _spriteCache = new();
private int _renderCount = 0;
+ private int _renderTotal = 0;
public int RenderCount => _renderCount;
+ public int RenderTotal => _renderTotal;
///
/// Searches for a Sprite in cache by GUID
@@ -59,6 +61,7 @@ public void Clean()
{
OnLoad = null;
_spriteCache?.Clear();
+ _renderTotal = 0;
}
///
@@ -183,9 +186,10 @@ private IEnumerator CoLoadSpriteAsync(Stream? imgStream, Action? on
{
{
_renderCount++;
+ _renderTotal = Math.Max(_renderTotal, _renderCount);
yield return null;
yield return null;
- while (!LagLimiter.ShouldContinue(1))
+ while (!LagLimiter.ShouldContinue(20))
yield return null;
// Search Cache
diff --git a/LevelImposter/Core/Models/LIConstants.cs b/LevelImposter/Core/Models/LIConstants.cs
index 54a43159..10383ae0 100644
--- a/LevelImposter/Core/Models/LIConstants.cs
+++ b/LevelImposter/Core/Models/LIConstants.cs
@@ -8,8 +8,9 @@ public static class LIConstants
public const StringNames MAP_STRING_NAME = (StringNames)392001; // StringName that placeholdes the map names
public const string MAP_NAME = "Random Custom Map"; // Name to populate Constants.MapNames
public const float PLAYER_POS = -5.0f; // Z value of the player
- public const int CONNECTION_TIMEOUT = 20; // Maximum time for host to wait (AmongUsClient.MAX_CLIENT_WAIT_TIME)
- public const int MAX_LOAD_TIME = 12; // Maximum time to build map before aborting
+ public const int MAX_HOST_TIMEOUT = 40; // Maximum time for host to wait (AmongUsClient.MAX_CLIENT_WAIT_TIME)
+ public const int MAX_LOAD_TIME = 35; // Maximum time to build map before aborting
+ public const int MAX_CONNECTION_TIMEOUT = 15; // Maximum time to wait for a client connection
public const int ELEM_WARN_TIME = 200; // Time to warn the user (in ms) when an element is taking too long to load
public const bool FREEPLAY_FLUSH_CACHE = true; // Whether to flush the cache when entering freeplay maps
public const bool OVERRIDE_HORSE_MODE = false; // Whether to override the horse mode setting
diff --git a/LevelImposter/Core/Models/LIProperties.cs b/LevelImposter/Core/Models/LIProperties.cs
index 453744a7..8131bd22 100644
--- a/LevelImposter/Core/Models/LIProperties.cs
+++ b/LevelImposter/Core/Models/LIProperties.cs
@@ -1,5 +1,6 @@
#nullable enable
using System;
+using System.Collections.Generic;
namespace LevelImposter.Core
{
@@ -17,6 +18,7 @@ public class LIProperties
public LIColor? highlightColor { get; set; }
public int? triggerCount { get; set; }
public bool? triggerLoop { get; set; }
+ public bool? createDeadBody { get; set; }
// Sprite
public Guid? spriteID { get; set; }
@@ -25,6 +27,10 @@ public class LIProperties
public LIColor? color { get; set; }
public bool? loopGIF { get; set; }
+ // Shake
+ public float? shakeAmount { get; set; }
+ public float? shakePeriod { get; set; }
+
// Legacy
[Obsolete("Use spriteID instead")]
public string? spriteData { get; set; }
@@ -47,6 +53,9 @@ public class LIProperties
public float? scrollingXSpeed { get; set; }
public float? scrollingYSpeed { get; set; }
+ // Custom Text
+ public Dictionary? customText { get; set; }
+
// Minigame
public LIMinigameSprite[]? minigames { get; set; }
public LIMinigameProps? minigameProps { get; set; }
diff --git a/LevelImposter/Core/Models/LIRpc.cs b/LevelImposter/Core/Models/LIRpc.cs
index 6dde0552..ffd755bb 100644
--- a/LevelImposter/Core/Models/LIRpc.cs
+++ b/LevelImposter/Core/Models/LIRpc.cs
@@ -12,10 +12,11 @@
public enum LIRpc
{
FireTrigger = 94, // Fires a global trigger on an object
- TeleportPlayer, // Uses a util-tele object
+ TeleportPlayer, // Used by util-tele object
SyncMapID, // Syncs the map ID in the lobby
SyncRandomSeed, // Syncs a random seed for util-triggerrand
ResetPlayer, // Resets the player on Ctrl-R E S
- DownloadCheck // Warns the host that the client is still downloading the map
+ DownloadCheck, // Warns the host that the client is still downloading the map
+ KillPlayer, // Used by util-triggerdeath object
}
}
diff --git a/LevelImposter/Core/Patches/Fixes/DeconControlPatch.cs b/LevelImposter/Core/Patches/Fixes/DeconControlPatch.cs
new file mode 100644
index 00000000..fab1334e
--- /dev/null
+++ b/LevelImposter/Core/Patches/Fixes/DeconControlPatch.cs
@@ -0,0 +1,45 @@
+using HarmonyLib;
+using UnityEngine;
+
+namespace LevelImposter.Core
+{
+ ///
+ /// Allows decon controls to bypass physics collisions.
+ ///
+ [HarmonyPatch(typeof(DeconControl), nameof(DeconControl.CanUse))]
+ public class DeconControlPatch
+ {
+ public static void Postfix(
+ DeconControl __instance,
+ [HarmonyArgument(0)] GameData.PlayerInfo playerInfo,
+ [HarmonyArgument(1)] ref bool canUse,
+ [HarmonyArgument(2)] ref bool couldUse,
+ ref float __result)
+ {
+ // Custom Maps Only
+ if (LIShipStatus.Instance == null)
+ return;
+ // Ignore if the system is not idle
+ if (__instance.System.CurState != DeconSystem.States.Idle)
+ return;
+
+ // Check if the player can use the decon
+ couldUse = playerInfo.Object.CanMove && !playerInfo.IsDead;
+ canUse = (couldUse && __instance.cooldown == 0f);
+ __result = float.MaxValue;
+
+ // Check if the player is close enough to use the decon
+ if (canUse)
+ {
+ // Get Adjusted Position
+ Vector2 truePosition = playerInfo.Object.GetTruePosition();
+ Vector3 position = __instance.transform.position;
+ position.y -= 0.1f; // <-- Adjust for player height
+
+ // Compare Distance
+ __result = Vector2.Distance(truePosition, position);
+ canUse &= (__result <= __instance.UsableDistance);
+ }
+ }
+ }
+}
diff --git a/LevelImposter/Core/Patches/Fixes/HorsePatch.cs b/LevelImposter/Core/Patches/Fixes/HorsePatch.cs
index cb92a7c0..11c12550 100644
--- a/LevelImposter/Core/Patches/Fixes/HorsePatch.cs
+++ b/LevelImposter/Core/Patches/Fixes/HorsePatch.cs
@@ -7,6 +7,7 @@ namespace LevelImposter.Core
///
/// Disables the april-fools horse mode due to incompatibility with lots of mods.
///
+ /*
[HarmonyPatch(typeof(Constants), nameof(Constants.ShouldHorseAround))]
public static class HorsePatch
{
@@ -19,6 +20,7 @@ public static bool Prefix(ref bool __result)
return false;
}
}
+ */
#pragma warning restore CS0162
}
\ No newline at end of file
diff --git a/LevelImposter/Core/Patches/Loading/LoadingShipPatch.cs b/LevelImposter/Core/Patches/Loading/LoadingShipPatch.cs
index c562a811..a1790028 100644
--- a/LevelImposter/Core/Patches/Loading/LoadingShipPatch.cs
+++ b/LevelImposter/Core/Patches/Loading/LoadingShipPatch.cs
@@ -32,7 +32,7 @@ public static class LoadingShipTimerPatch
{
public static void Postfix(AmongUsClient __instance)
{
- __instance.MAX_CLIENT_WAIT_TIME = LIConstants.CONNECTION_TIMEOUT;
+ __instance.MAX_CLIENT_WAIT_TIME = LIConstants.MAX_HOST_TIMEOUT;
}
}
}
diff --git a/LevelImposter/Core/Patches/Ship/ShipStatusPatch.cs b/LevelImposter/Core/Patches/Ship/ShipStatusPatch.cs
index cc0568cf..2c4ebe01 100644
--- a/LevelImposter/Core/Patches/Ship/ShipStatusPatch.cs
+++ b/LevelImposter/Core/Patches/Ship/ShipStatusPatch.cs
@@ -11,6 +11,8 @@ public static class ShipStatusPatch
{
public static void Prefix(ShipStatus __instance)
{
+ //UnityToMapGenerator.GenerateMap(__instance);
+
if (MapUtils.GetCurrentMapType() == MapType.LevelImposter)
__instance.gameObject.AddComponent();
else if (!MapLoader.IsFallback)
diff --git a/LevelImposter/Core/Patches/Ship/SporePatch.cs b/LevelImposter/Core/Patches/Ship/SporePatch.cs
index 70d25169..28fd782e 100644
--- a/LevelImposter/Core/Patches/Ship/SporePatch.cs
+++ b/LevelImposter/Core/Patches/Ship/SporePatch.cs
@@ -20,7 +20,7 @@ public static bool Prefix(
{
if (LIShipStatus.Instance == null)
return true;
- if (callId != (byte)RpcCalls.TriggerSpores || callId != (byte)RpcCalls.CheckSpore)
+ if (callId != (byte)RpcCalls.TriggerSpores && callId != (byte)RpcCalls.CheckSpore)
return true;
// Find spores
diff --git a/LevelImposter/Core/Patches/Triggers/ConsolePatch.cs b/LevelImposter/Core/Patches/Triggers/ConsolePatch.cs
index 0a59e643..517f6540 100644
--- a/LevelImposter/Core/Patches/Triggers/ConsolePatch.cs
+++ b/LevelImposter/Core/Patches/Triggers/ConsolePatch.cs
@@ -24,6 +24,16 @@ public static bool Prefix(MonoBehaviour __instance)
if (LIShipStatus.Instance == null)
return true;
+ // Get IUsable
+ var usable = __instance.TryCast();
+ if (usable == null)
+ return true;
+
+ // Check if the player can use the console
+ usable.CanUse(PlayerControl.LocalPlayer.Data, out bool canUse, out _);
+ if (!canUse)
+ return true;
+
// Update Last Console
MinigamePatch.LastConsole = __instance.gameObject;
diff --git a/LevelImposter/Core/Patches/Utils/ConnectionPatch.cs b/LevelImposter/Core/Patches/Utils/ConnectionPatch.cs
new file mode 100644
index 00000000..67f430c6
--- /dev/null
+++ b/LevelImposter/Core/Patches/Utils/ConnectionPatch.cs
@@ -0,0 +1,17 @@
+using HarmonyLib;
+using Hazel.Udp;
+
+namespace LevelImposter.Core
+{
+ ///
+ /// Increases the max timeout for the low level connection to the server.
+ ///
+ [HarmonyPatch(typeof(UnityUdpClientConnection), nameof(UnityUdpClientConnection.ConnectAsync))]
+ public static class TimeoutPatch
+ {
+ public static void Postfix(UnityUdpClientConnection __instance)
+ {
+ __instance.DisconnectTimeoutMs = LIConstants.MAX_CONNECTION_TIMEOUT * 1000;
+ }
+ }
+}
diff --git a/LevelImposter/Core/Utils/GCHandler.cs b/LevelImposter/Core/Utils/GCHandler.cs
index 5b0d7708..18bb3b72 100644
--- a/LevelImposter/Core/Utils/GCHandler.cs
+++ b/LevelImposter/Core/Utils/GCHandler.cs
@@ -55,8 +55,8 @@ public static bool IsLowMemory()
{
Process process = Process.GetCurrentProcess();
bool isLow = process.PrivateMemorySize64 > MAX_MEMORY;
- if (isLow)
- LILogger.Msg("Warning: Low on memory");
+ //if (isLow)
+ // LILogger.Msg("Warning: Low on memory");
return isLow;
}
diff --git a/LevelImposter/LevelImposter.cs b/LevelImposter/LevelImposter.cs
index 584326ca..686321a0 100644
--- a/LevelImposter/LevelImposter.cs
+++ b/LevelImposter/LevelImposter.cs
@@ -21,6 +21,7 @@ public partial class LevelImposter : BasePlugin
public const string ID = "com.DigiWorm.LevelImposter";
public HarmonyLib.Harmony Harmony { get; } = new HarmonyLib.Harmony(ID);
+ public static string DisplayVersion { get; } = Version.Contains('+') ? Version.Substring(0, Version.IndexOf('+')) : Version;
public override void Load()
{
@@ -48,6 +49,8 @@ public override void Load()
ClassInjector.RegisterTypeInIl2Cpp();
ClassInjector.RegisterTypeInIl2Cpp();
ClassInjector.RegisterTypeInIl2Cpp();
+ ClassInjector.RegisterTypeInIl2Cpp();
+ ClassInjector.RegisterTypeInIl2Cpp();
ClassInjector.RegisterTypeInIl2Cpp();
ClassInjector.RegisterTypeInIl2Cpp();
ClassInjector.RegisterTypeInIl2Cpp();
@@ -64,6 +67,7 @@ public override void Load()
ClassInjector.RegisterTypeInIl2Cpp();
ClassInjector.RegisterTypeInIl2Cpp();
ClassInjector.RegisterTypeInIl2Cpp();
+ ClassInjector.RegisterTypeInIl2Cpp();
ClassInjector.RegisterTypeInIl2Cpp(usableInterface);
// Patch Methods
diff --git a/LevelImposter/LevelImposter.csproj b/LevelImposter/LevelImposter.csproj
index 45c7661c..9636905b 100644
--- a/LevelImposter/LevelImposter.csproj
+++ b/LevelImposter/LevelImposter.csproj
@@ -1,7 +1,7 @@
LevelImposter
- 0.18.0
+ 0.19.0
Custom Among Us Mapping Studio
DigiWorm
@@ -13,15 +13,15 @@
C:\Program Files (x86)\Steam\steamapps\common\Among Us
- 2023.11.28
+ 2024.6.4
-
+
-
+
diff --git a/LevelImposter/Shop/Components/LoadingBar.cs b/LevelImposter/Shop/Components/LoadingBar.cs
new file mode 100644
index 00000000..ae103acc
--- /dev/null
+++ b/LevelImposter/Shop/Components/LoadingBar.cs
@@ -0,0 +1,82 @@
+using System;
+using UnityEngine;
+
+namespace LevelImposter.Shop
+{
+ public class LoadingBar : MonoBehaviour
+ {
+ public LoadingBar(IntPtr intPtr) : base(intPtr)
+ {
+ }
+
+ public static LoadingBar? Instance { get; private set; }
+
+ private GameObject? _loadingBar = null;
+ private TMPro.TMP_Text? _mapText = null;
+ private TMPro.TMP_Text? _statusText = null;
+
+ ///
+ /// Sets the name of the map being loaded
+ ///
+ /// Name of the map
+ public void SetMapName(string mapName)
+ {
+ _mapText?.SetText(mapName);
+ }
+
+ ///
+ /// Sets the status text of the loading bar
+ ///
+ /// Text to display
+ public void SetStatus(string status)
+ {
+ _statusText?.SetText(status);
+ }
+
+ ///
+ /// Sets the progress of the loading bar
+ ///
+ /// Percentage of completion, from 0 to 1
+ public void SetProgress(float percent)
+ {
+ if (_loadingBar == null)
+ return;
+
+ _loadingBar.transform.localPosition = new Vector3(percent - 1, 0, 0);
+ }
+
+ ///
+ /// Sets the visibility of the loading bar
+ ///
+ /// True iff the loading bar should be visible
+ public void SetVisible(bool visible)
+ {
+ gameObject.SetActive(visible);
+ }
+
+ public void Awake()
+ {
+ // Singleton
+ if (Instance != null)
+ {
+ Destroy(gameObject);
+ return;
+ }
+ Instance = this;
+
+ _loadingBar = transform.Find("BarMask").Find("Bar").gameObject;
+ _mapText = transform.Find("MapText").GetComponent();
+ _statusText = transform.Find("StatusText").GetComponent();
+
+ //DontDestroyOnLoad(gameObject);
+ }
+ public void OnDestroy()
+ {
+ Instance = null;
+
+ _loadingBar = null;
+ _mapText = null;
+ _statusText = null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/LevelImposter/Shop/Components/ShopManager.cs b/LevelImposter/Shop/Components/ShopManager.cs
index a3beee56..3108604a 100644
--- a/LevelImposter/Shop/Components/ShopManager.cs
+++ b/LevelImposter/Shop/Components/ShopManager.cs
@@ -24,6 +24,7 @@ public ShopManager(IntPtr intPtr) : base(intPtr)
private Tab _currentTab = Tab.None;
private GameObject? _overlay = null;
+ private SpriteRenderer? _overlayBackground = null;
private TMPro.TMP_Text? _overlayText = null;
private Scroller? _scroller = null;
private SpriteRenderer? _title = null;
@@ -93,6 +94,10 @@ public void SetTab(Tab tab)
// Clear the shop
Clear();
+ // Show Loading Spinner
+ SetOverlayText("Retrieving Maps...");
+ SetOverlayEnabled(true, false);
+
// Switch on the tab
Action callback = tab switch
{
@@ -128,6 +133,9 @@ private IEnumerator CoSetDownloadsTab()
AddBanner(metadata);
yield return null;
}
+
+ // Hide Loading Spinner
+ SetOverlayEnabled(false);
}
}
@@ -168,6 +176,9 @@ private void OnAPIRespose(LIMetadata[] maps, Tab tab)
Clear();
foreach (LIMetadata map in maps)
AddBanner(map);
+
+ // Hide Loading Spinner
+ SetOverlayEnabled(false);
}
///
@@ -256,9 +267,12 @@ public static void RegenerateFallbackMap()
/// Toggles the overlay
///
/// true if the overlay should be visible
- public void SetOverlayEnabled(bool isEnabled)
+ /// true if the overlay background should be visible
+ public void SetOverlayEnabled(bool isEnabled, bool isBackgroundEnabled = true)
{
_overlay?.SetActive(isEnabled);
+ if (_overlayBackground != null)
+ _overlayBackground.enabled = isBackgroundEnabled;
}
///
@@ -310,6 +324,7 @@ public void Awake()
Instance = this;
_overlay = transform.Find("Overlay").gameObject;
+ _overlayBackground = _overlay?.GetComponent();
_overlayText = _overlay?.transform.Find("Text").GetComponent();
_scroller = transform.Find("Scroll/Scroller").GetComponent();
_title = _scroller?.transform.Find("Inner/Title").GetComponent();
diff --git a/LevelImposter/Shop/Models/LIUpdate.cs b/LevelImposter/Shop/Models/LIUpdate.cs
index fabcbd90..3c7fbc3e 100644
--- a/LevelImposter/Shop/Models/LIUpdate.cs
+++ b/LevelImposter/Shop/Models/LIUpdate.cs
@@ -13,7 +13,7 @@ public bool isCurrent
{
get
{
- return tag.Equals(LevelImposter.Version);
+ return tag.Equals(LevelImposter.DisplayVersion);
}
}
}
diff --git a/LevelImposter/Shop/Patches/PingPatch.cs b/LevelImposter/Shop/Patches/PingPatch.cs
index 91297c80..1dd7bbe2 100644
--- a/LevelImposter/Shop/Patches/PingPatch.cs
+++ b/LevelImposter/Shop/Patches/PingPatch.cs
@@ -32,28 +32,26 @@ public static void Postfix(PingTracker __instance)
StringBuilder pingBuilder = new();
- // Shrink all to fit
- pingBuilder.Append("");
-
- // LevelImposter "Logo"
- if (isInLobby)
- pingBuilder.Append($"LevelImposter v{LevelImposter.Version}\n");
-
// Existing Ping/Mods
pingBuilder.Append(__instance.text.text);
if (!__instance.text.text.EndsWith("\n"))
pingBuilder.Append("\n");
+ // LevelImposter "Logo"
+ if (isInLobby)
+ pingBuilder.Append($"LevelImposter v{LevelImposter.DisplayVersion}\n");
+
// Map Name
- pingBuilder.Append($"{mapName}\n");
+ pingBuilder.Append($"{mapName}");
// Map Author
if (isFallback && isInLobby)
- pingBuilder.Append($"by ???");
+ pingBuilder.Append("");
else if (isPublished)
- pingBuilder.Append($"by {currentMap.authorName}");
+ pingBuilder.Append($"\nby {currentMap.authorName}");
else
- pingBuilder.Append($"(Freeplay Only)");
+ pingBuilder.Append($"\n(Freeplay Only)");
+
__instance.text.text = pingBuilder.ToString();
}
diff --git a/LevelImposter/Shop/Patches/VersionPatch.cs b/LevelImposter/Shop/Patches/VersionPatch.cs
index be16c490..6b2bbaf8 100644
--- a/LevelImposter/Shop/Patches/VersionPatch.cs
+++ b/LevelImposter/Shop/Patches/VersionPatch.cs
@@ -49,7 +49,7 @@ public static void Postfix()
logoText.fontSize = 1.5f;
logoText.alignment = TextAlignmentOptions.BottomLeft;
logoText.raycastTarget = false;
- logoText.SetText("v" + LevelImposter.Version);
+ logoText.SetText("v" + LevelImposter.DisplayVersion);
}
private static Sprite GetLogoSprite()
diff --git a/LevelImposter/Shop/Util/GitHubAPI.cs b/LevelImposter/Shop/Util/GitHubAPI.cs
index 6668b4ca..83a26123 100644
--- a/LevelImposter/Shop/Util/GitHubAPI.cs
+++ b/LevelImposter/Shop/Util/GitHubAPI.cs
@@ -86,7 +86,7 @@ private static bool IsUpdateForbidden(GHRelease[] releases)
public static bool IsCurrent(GHRelease release)
{
string versionString = release.name.Split(" ")[1];
- return versionString == LevelImposter.Version || LevelImposter.Version.Contains(DEV_VERSION_FLAG);
+ return versionString == LevelImposter.DisplayVersion || LevelImposter.DisplayVersion.Contains(DEV_VERSION_FLAG);
}
///
diff --git a/LevelImposter/Shop/Util/LevelImposterAPI.cs b/LevelImposter/Shop/Util/LevelImposterAPI.cs
index ccd01e8b..d3c50f59 100644
--- a/LevelImposter/Shop/Util/LevelImposterAPI.cs
+++ b/LevelImposter/Shop/Util/LevelImposterAPI.cs
@@ -33,7 +33,7 @@ public static void Request(string url, Action callback, Action onE
if (response == null)
onError("Invalid API Response");
else if (response.v != API_VERSION)
- onError($"You are running on an older version of LevelImposter {LevelImposter.Version}. Update to get access to the API.");
+ onError($"You are running on an older version of LevelImposter {LevelImposter.DisplayVersion}. Update to get access to the API.");
else if (!string.IsNullOrEmpty(response.error))
onError(response.error);
else