Skip to content

Commit

Permalink
Release v1.4.7
Browse files Browse the repository at this point in the history
  • Loading branch information
IAmBatby committed Feb 3, 2025
1 parent 0d1b614 commit a5524b5
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 47 deletions.
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,36 @@
**Changelog**
--

**<details><summary>Version 1.4.7</summary>**

**<details><summary>Fixes</summary>**

* Tweaked NetworkBundleManager code to improve realibility of the hot-reloading system and prevent unintentional soft-locks related to pulling the lever

</details>

</details>

**<details><summary>Version 1.4.6</summary>**

**<details><summary>Features</summary>**

* Added ExtendedLevel.IsRouteRemoved to indicate if Level has been disabled in the config

</details>

**<details><summary>Fixes</summary>**

* Fixed issue with AssetBundle hotloading when routing from a moon to a moon contained in the same AssetBundle
* Added additional safetey check when performing Audio related Asset restoration
* Changed ExtendedItem terminal registration to ensure accurate item Ids
* Fixed an issue with Locked ExtendedLevel's by setting it's accossiated TerminalNode.acceptEverything to false


</details>

</details>

**<details><summary>Version 1.4.5</summary>**

**<details><summary>Fixes</summary>**
Expand Down
42 changes: 25 additions & 17 deletions LethalLevelLoader/AssetBundles/AssetBundleInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.IO;
using System.Text;
using UnityEngine;
using UnityEngine.ProBuilder.MeshOperations;
using Debug = UnityEngine.Debug;

namespace LethalLevelLoader.AssetBundles
Expand Down Expand Up @@ -105,7 +106,12 @@ public void Initialize()

public bool TryLoadBundle()
{
if (IsAssetBundleLoaded == false && activeLoadRequest == null)
if (IsAssetBundleLoaded == true)
{
OnBundleLoaded.Invoke(this); //Feels a little strange but if something requests a bundle to be loaded and expects this event to fire in response we wanna fire it in the event it's already loaded. (might change later)
return (true);
}
else if (IsAssetBundleLoaded == false && activeLoadRequest == null)
{
coroutineHandler.StartCoroutine(LoadBundleRequest());
return (true);
Expand All @@ -120,7 +126,12 @@ public bool TryLoadBundle()
public bool TryUnloadBundle()
{
if (IsHotReloadable == false) return (false);
if (IsAssetBundleLoaded && activeUnloadRequest == null)
else if (IsAssetBundleLoaded == false)
{
OnBundeUnloaded.Invoke(this); //Feels a little strange but if something requests a bundle to be unloaded and expects this event to fire in response we wanna fire it in the event it's already unloaded. (might change later)
return (true);
}
else if (activeUnloadRequest == null)
{
coroutineHandler.StartCoroutine(UnloadBundleRequest());
return (true);
Expand All @@ -138,28 +149,25 @@ private IEnumerator LoadBundleRequest()
string combinedPath = Path.Combine(Application.streamingAssetsPath, AssetBundleFilePath);
activeLoadRequest = AssetBundle.LoadFromFileAsync(combinedPath);
yield return activeLoadRequest;
if (activeLoadRequest.isDone)
if (assetBundle != null || (activeLoadRequest.isDone && activeLoadRequest.assetBundle != null))
{
if (activeLoadRequest.assetBundle == null)
DebugHelper.LogError("AssetBundleInfo: " + AssetBundleFileName + " failed to load.", DebugType.User);
else
{
assetBundle = activeLoadRequest.assetBundle;
if (hasInitialized == false)
Initialize();
activeLoadRequest = null;
bundleLoadStopwatch.Stop();
LastTimeLoaded = Time.time;
DebugHelper.Log(AssetBundleFileName + " Loaded (" + LastLoadTime + ")!", DebugType.User);
OnBundleLoaded.Invoke(this);
}
assetBundle = activeLoadRequest.assetBundle;
if (hasInitialized == false)
Initialize();
activeLoadRequest = null;
bundleLoadStopwatch.Stop();
LastTimeLoaded = Time.time;
DebugHelper.Log(AssetBundleFileName + " Loaded (" + LastLoadTime + ")!", DebugType.User);
OnBundleLoaded.Invoke(this);
}
else
DebugHelper.LogError("AssetBundleInfo: " + AssetBundleFileName + " failed to load.", DebugType.User);
}

private IEnumerator UnloadBundleRequest()
{
bundleUnloadStopwatch = Stopwatch.StartNew();
yield return new WaitForSeconds(0.01f); //Might remove later but stopped unity freeze when you tried to load and unload a bundle on the same frame
yield return new WaitForSeconds(0.01f); //Might remove later but stopped unity freeze when you tried to load and unload a bundle on the same frame (Confirmed Unity bug on our version)
activeUnloadRequest = assetBundle.UnloadAsync(true);
yield return activeUnloadRequest;
if (activeUnloadRequest.isDone)
Expand Down
7 changes: 7 additions & 0 deletions LethalLevelLoader/General/Patches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ internal static void StartOfRoundAwake_Prefix(StartOfRound __instance)
Plugin.CompleteSetup();
StartOfRound.SetPlanetsWeather();
}
Plugin.LobbyInitialized();

}

Expand Down Expand Up @@ -664,6 +665,12 @@ internal static void StartOfRoundOnClientDisconnect_Postfix()
NetworkBundleManager.Instance.OnClientsChangedRefresh();
}

[HarmonyPatch(typeof(NetworkConnectionManager), nameof(NetworkConnectionManager.OnClientDisconnectFromServer)), HarmonyPostfix, HarmonyPriority(priority)]
internal static void NetworkConnectionManagerOnClientDisconnectFromServer_Postfix()
{
NetworkBundleManager.Instance.OnClientsChangedRefresh();
}

[HarmonyPatch(typeof(StartMatchLever), nameof(StartMatchLever.Start)), HarmonyPostfix, HarmonyPriority(priority)]
internal static void StartMatchLeverStart_Postfix(StartMatchLever __instance)
{
Expand Down
46 changes: 20 additions & 26 deletions LethalLevelLoader/Patches/NetworkBundleManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,25 +48,26 @@ public override void OnNetworkSpawn()
DebugHelper.Log("NetworkBundleManger Has Spawned!", DebugType.IAmBatby);
Instance = this;

if (IsServer)
ResetPlayerLoadStatusListServerRpc();

if (Plugin.IsSetupComplete == true)
{
GenerateSceneDict();
GenerateAssetBundleGroupDict();
Refresh();
}
if (Plugin.IsLobbyInitialized == true)
Initialize();
else
{
Plugin.onSetupComplete += GenerateSceneDict;
Plugin.onSetupComplete += GenerateAssetBundleGroupDict;
Plugin.onSetupComplete += Refresh;
Plugin.onLobbyInitialized -= Initialize;
Plugin.onLobbyInitialized += Initialize;
}
AssetBundles.AssetBundleLoader.OnBundleLoaded.AddListener(Instance.RefreshLoadStatus);
AssetBundles.AssetBundleLoader.OnBundleUnloaded.AddListener(Instance.RefreshLoadStatus);
}

//This should run anytime the client joins a lobby
private void Initialize()
{
DebugHelper.Log("NetworkBundleManager Initializing.", DebugType.User);
GenerateSceneDict();
GenerateAssetBundleGroupDict();
Refresh();
}

//Called on Plugin.onSetupComplete
//Called by StartOfRound.ChangeLevel.Postfix
internal void Refresh()
Expand Down Expand Up @@ -96,25 +97,17 @@ internal void Refresh()
internal void OnClientsChangedRefresh()
{
if (!IsServer) return;
ResetPlayerLoadStatusListServerRpc();
RequestLoadStatusRefreshServerRpc();
}

[ServerRpc(RequireOwnership = false)]
internal void RequestLoadStatusRefreshServerRpc()
{
DebugHelper.Log("Refeshing Loaded Bundles Status!", DebugType.User);
ResetPlayerLoadStatusListServerRpc();
RequestLoadStatusRefreshClientRpc();
}


[ServerRpc]
internal void ResetPlayerLoadStatusListServerRpc()
{
DebugHelper.Log("Reseting PlayerLoadStatus List!", DebugType.User);
playersLoadStatus.Clear();
foreach (ulong clientId in NetworkManager.ConnectedClientsIds)
playersLoadStatus.Add(false);
RequestLoadStatusRefreshClientRpc();
}

[ClientRpc]
Expand All @@ -131,18 +124,19 @@ private void RefreshLoadStatus()
bool loadedStatus = true;
foreach (AssetBundleGroup routeGroup in GetRouteGroups(LevelManager.CurrentExtendedLevel))
if (routeGroup.LoadedStatus != AssetBundleGroupLoadedStatus.Loaded)
{
loadedStatus = false;
if (routeGroup.LoadingStatus != AssetBundleGroupLoadingStatus.Loading)
routeGroup.TryLoadGroup();
}
DebugHelper.Log("Sending LoadedStatus: " + loadedStatus + " To Server!", DebugType.User);
SetLoadedStatusServerRpc(NetworkManager.LocalClientId, loadedStatus);
}

[ServerRpc(RequireOwnership = false)]
private void SetLoadedStatusServerRpc(ulong clientID, bool status)
{
List<ulong> connectedClientIds = new List<ulong>();
foreach (ulong clientId in NetworkManager.ConnectedClientsIds)
connectedClientIds.Add(clientId);
int index = connectedClientIds.IndexOf(clientID);
int index = NetworkManager.ConnectedClientsIds.ToList().IndexOf(clientID);
if (playersLoadStatus.Count <= index)
{
DebugHelper.LogError("Tried To Set LoadedStatus When List Is Invalid (ClientID: " + clientID + ", Index: " + index + "), Resetting.", DebugType.User);
Expand Down
13 changes: 11 additions & 2 deletions LethalLevelLoader/Plugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class Plugin : BaseUnityPlugin
{
public const string ModGUID = "imabatby.lethallevelloader";
public const string ModName = "LethalLevelLoader";
public const string ModVersion = "1.4.6";
public const string ModVersion = "1.4.7";

internal static Plugin Instance;

Expand All @@ -27,8 +27,10 @@ public class Plugin : BaseUnityPlugin
internal static BepInEx.Logging.ManualLogSource logger;

public static event Action onBeforeSetup;
public static event Action onSetupComplete;
public static event Action onSetupComplete; //Happens on the first lobby in a session
public static event Action onLobbyInitialized; //Happens per lobby in a session
public static bool IsSetupComplete { get; private set; } = false;
public static bool IsLobbyInitialized { get; internal set; } = false;

internal static GameObject networkManagerPrefab;

Expand Down Expand Up @@ -85,6 +87,7 @@ private void Awake()

internal static void OnBeforeSetupInvoke()
{
IsLobbyInitialized = false;
onBeforeSetup?.Invoke();
}

Expand All @@ -95,6 +98,12 @@ internal static void CompleteSetup()
onSetupComplete?.Invoke();
}

internal static void LobbyInitialized()
{
IsLobbyInitialized = true;
onLobbyInitialized?.Invoke();
}

private void NetcodePatch()
{
try
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
**Description**
--

### **1.3.0 for Lethal Company v55 Has Released!**
### **1.4.7 for Lethal Company v69 Has Released!**

**LethalLevelLoader** is a custom API to support the manual and dynamic integration of custom levels and dungeons in Lethal Company.
Mod Developers can provide LethalLevelLoader with their custom content via code or via automatic AssetBundle detection, and from there LethalLevelLoader will seamlessly load the content into the game.
Expand Down Expand Up @@ -58,7 +58,7 @@ You should be now set up, and ready compile your fork of LethalLevelLoader on yo
--

* **Evaisa** *(This Mod is directly based from LethalLib's codebase and could have been made without it's pre-existing foundations.)*
* **SkullCrusher** *(This Mod is directly based from SkullCrusher's LethalLib' Fork and could have been made without it's pre-existing foundations.)*
* **SkullCrusher** *(This Mod is directly based from SkullCrusher's LethalLib' Fork and could not have been made without it's pre-existing foundations.)*
* **HolographicWings** *(This Mod was inspired by LethalExpansion and could not have been made without HolographicWing's support and research.)*
* **KayNetsua** *(This Mod was internally tested using KayNetsua's "E Gypt" Custom Level and KayNetsua assisted in testing LethalLevelLoader's usage)*
* **Badhamknibb** *(This Mod was internally tested using Badhamknibb's "SCP Foundation" Custom Dungeon and Badhamknibb's assisted in testing LethalLevelLoader's usage)*
Expand Down

0 comments on commit a5524b5

Please sign in to comment.