Skip to content

Commit 582ff23

Browse files
committed
[UI] Implement the base interface for servers list UI and Scenes API management
1 parent 4c73f4c commit 582ff23

File tree

5 files changed

+254
-11
lines changed

5 files changed

+254
-11
lines changed

COTLMP/Api/Assets.cs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* PROJECT: Cult of the Lamb Multiplayer Mod
3+
* LICENSE: MIT (https://spdx.org/licenses/MIT)
4+
* PURPOSE: Assets management
5+
* COPYRIGHT: Copyright 2025 GeoB99 <geobman1999@gmail.com>
6+
*/
7+
8+
/* IMPORTS ********************************************************************/
9+
10+
using COTLMP;
11+
using COTLMP.Debug;
12+
using HarmonyLib;
13+
using BepInEx;
14+
using MMTools;
15+
using System;
16+
using System.IO;
17+
using System.Reflection;
18+
using UnityEngine;
19+
using UnityEngine.SceneManagement;
20+
using UnityEngine.UI;
21+
22+
/* CLASSES & CODE *************************************************************/
23+
24+
/*
25+
* @brief
26+
* Contains the classes and code for the Unity Assets management.
27+
*
28+
* @class Assets
29+
* The class for Scenes API management.
30+
*/
31+
namespace COTLMP.Api
32+
{
33+
internal static class Assets
34+
{
35+
/*
36+
* @brief
37+
* Opens an assets bundle file and loads it into memory.
38+
*
39+
* @param[in] BundleName
40+
* A string that points to the name of the bundle file to be
41+
* opened.
42+
*
43+
* @returns
44+
* Returns the asset bundle object to the caller. NULL is returned
45+
* if said scene asset couldn't be found within the Assets folder.
46+
*/
47+
public static AssetBundle OpenAssetBundleFile(string BundleName)
48+
{
49+
AssetBundle Bundle;
50+
string AssetsLocation;
51+
string AbsolutePath;
52+
53+
/* Sanity check -- Make sure the Assets folder of the mod exists */
54+
AssetsLocation = Path.Combine(Plugin.CotlmpPathLocation, "Assets");
55+
COTLMP.Debug.Assertions.Assert(Directory.Exists(AssetsLocation), true, "Assets folder missing", "The Assets folder is either missing or corrupt, please re-install COTLMP!");
56+
57+
/* Now build the absolute path to the UI assets bundle */
58+
AbsolutePath = Path.Combine(AssetsLocation, BundleName);
59+
COTLMP.Debug.PrintLogger.Print(DebugLevel.MESSAGE_LEVEL, DebugComponent.ASSETS_MANAGEMENT_COMPONENT, $"Absolute Path -> {AbsolutePath}");
60+
61+
/* And load it from the absolute path */
62+
Bundle = AssetBundle.LoadFromFile(AbsolutePath);
63+
if (Bundle == null)
64+
{
65+
COTLMP.Debug.PrintLogger.Print(DebugLevel.ERROR_LEVEL, DebugComponent.ASSETS_MANAGEMENT_COMPONENT,
66+
$"Failed to load the bundle file -- {BundleName}!");
67+
return null;
68+
}
69+
70+
return Bundle;
71+
}
72+
73+
/*
74+
* @brief
75+
* Loads a scene and shows it to the screen, given its name.
76+
*
77+
* @param[in] SceneName
78+
* A string to the name of the scene of which to be loaded.
79+
*
80+
* @param[in] ActionToTakeCallback
81+
* An action callback provided by the caller. The method executes
82+
* this callback if the scene name is "Main Menu" of which it
83+
* performs a specific action depending on the pointed callback.
84+
* This parameter is optional and ignored for every other scene name.
85+
*
86+
*/
87+
public static void ShowScene(string SceneName, Action ActionToTakeCallback)
88+
{
89+
/*
90+
* The caller asked to load the main menu scene, use MMTools for that
91+
* as the main menu scene is built-in COTL natively.
92+
*/
93+
if (SceneName == "Main Menu")
94+
{
95+
MMTools.MMTransition.Play(MMTransition.TransitionType.LoadAndFadeOut,
96+
MMTransition.Effect.BlackFade,
97+
SceneName,
98+
1,
99+
null,
100+
ActionToTakeCallback);
101+
return;
102+
}
103+
104+
/* Otherwise use the scene manager to load whatever scene */
105+
SceneManager.LoadScene(SceneName, LoadSceneMode.Single);
106+
}
107+
}
108+
}
109+
110+
/* EOF */

COTLMP/Debug/PrintLogger.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ public enum DebugLevel
7474
*
7575
* @field LOCALIZATION_COMPONENT
7676
* Localization API component of the mod.
77+
*
78+
* @field CONFIGURATION_COMPONENT
79+
* Save/Load configuration settings component of the mod.
80+
*
81+
* @field SCENES_MANAGEMENT_COMPONENT
82+
* UI scenes management component of the mod.
83+
*
84+
* @field DEBUG_COMPONENT
85+
* Core debug routines component of the mod.
7786
*/
7887
public enum DebugComponent
7988
{
@@ -82,6 +91,7 @@ public enum DebugComponent
8291
NETWORK_STACK_COMPONENT,
8392
LOCALIZATION_COMPONENT,
8493
CONFIGURATION_COMPONENT,
94+
ASSETS_MANAGEMENT_COMPONENT,
8595
DEBUG_COMPONENT
8696
}
8797

@@ -136,6 +146,12 @@ private static string GetComponentName(DebugComponent Component)
136146
break;
137147
}
138148

149+
case DebugComponent.ASSETS_MANAGEMENT_COMPONENT:
150+
{
151+
Name = "ASSETS_MANAGEMENT_COMPONENT";
152+
break;
153+
}
154+
139155
case DebugComponent.DEBUG_COMPONENT:
140156
{
141157
Name = "DEBUG_COMPONENT";

COTLMP/Plugin.cs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@
1515
using COTLMP.Ui;
1616
using HarmonyLib;
1717
using System;
18+
using System.IO;
1819
using System.Linq;
1920
using System.Reflection;
20-
using UnityEngine.SceneManagement;
21+
using UnityEngine;
2122

2223
/* NAMESPACES *****************************************************************/
2324

@@ -39,10 +40,13 @@ namespace COTLMP;
3940
*/
4041
public class Plugin : BaseUnityPlugin
4142
{
43+
internal static string CotlmpPathLocation;
4244
internal static new ManualLogSource Logger;
4345
internal static new ConfigFile Config;
4446
internal static ModDataGlobals Globals;
4547
internal static InternalData GlobalsInternal;
48+
internal static AssetBundle ModScenesBundle;
49+
internal static MonoBehaviour MonoInstance;
4650
private Harmony HarmonyInstance;
4751

4852
/*
@@ -52,20 +56,28 @@ public class Plugin : BaseUnityPlugin
5256
*/
5357
private void Awake()
5458
{
55-
Object SettingData;
59+
System.Object SettingData;
5660
int MaxPlayers;
5761
string ServerName, PlayerName, GameMode;
5862
bool ToggleMod, VoiceChat;
63+
bool Success;
5964

6065
/*
6166
* Start patching the game assembly with our code
6267
* and cache a harmony instance of this mod.
6368
*/
6469
HarmonyInstance = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly());
6570

66-
/* Cache the plugin class methods so that the COTL MP mod can use them across different modules */
71+
/* Cache the path location of the COTLMP mod */
72+
CotlmpPathLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
73+
74+
/*
75+
* Cache the plugin class methods and the Mono instance so that the
76+
* COTL MP mod can use them across different modules.
77+
*/
6778
Logger = base.Logger;
6879
Config = base.Config;
80+
MonoInstance = this;
6981

7082
/* Fetch the flags and switches of the mod, reserved for internal use */
7183
GlobalsInternal = new InternalData();
@@ -177,9 +189,24 @@ private void Awake()
177189
VoiceChat);
178190

179191
/* Initialize the Settings UI */
180-
COTLMP.Ui.Settings.InitializeUI();
192+
Success = COTLMP.Ui.Settings.InitializeUI();
193+
if (!Success)
194+
{
195+
Logger.LogFatal("Failed to initialize the Settings UI!");
196+
HarmonyInstance.UnpatchSelf();
197+
return;
198+
}
199+
200+
/* Load all the COTLMP scene assets bundle in memory */
201+
ModScenesBundle = COTLMP.Api.Assets.OpenAssetBundleFile("cotlmpscenes");
202+
if (ModScenesBundle == null)
203+
{
204+
Logger.LogFatal("Failed to open the COTLMP scenes bundle file!");
205+
HarmonyInstance.UnpatchSelf();
206+
return;
207+
}
181208

182-
// Initialize the network features
209+
/* Initialize the network features */
183210
COTLMP.Network.Network.Initialize();
184211

185212
/* Log to the debugger that our mod is loaded */

COTLMP/Ui/MainMenu.cs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@
99

1010
using COTLMP;
1111
using COTLMP.Debug;
12-
using BepInEx;
1312
using HarmonyLib;
13+
using BepInEx;
1414
using I2.Loc;
1515
using Lamb.UI;
1616
using Lamb.UI.MainMenu;
1717
using src.UI;
18-
using UnityEngine.UI;
1918

2019
/* CLASSES & CODE *************************************************************/
2120

@@ -52,10 +51,9 @@ internal static class MainMenuPatches
5251
[HarmonyPrefix]
5352
private static bool OnMultiplayerButtonClickedPatch(MainMenu __instance)
5453
{
55-
/* Throw a dialog box warning the user Multiplayer is currently WIP */
56-
COTLMP.Debug.PrintLogger.Print(DebugLevel.MESSAGE_LEVEL, DebugComponent.UI_COMPONENT, "The Multiplayer button has been clicked!");
57-
UIMenuConfirmationWindow ConfirmDialog = __instance.Push<UIMenuConfirmationWindow>(MonoSingleton<UIManager>.Instance.ConfirmationWindowTemplate);
58-
ConfirmDialog.Configure(MultiplayerModLocalization.UI.Multiplayer_Title, MultiplayerModLocalization.UI.Multiplayer_Text, true);
54+
/* Display the servers list UI */
55+
COTLMP.Debug.PrintLogger.PrintVerbose(DebugLevel.MESSAGE_LEVEL, DebugComponent.UI_COMPONENT, "The Multiplayer button has been clicked!");
56+
COTLMP.Ui.ServerList.DisplayUi();
5957
return false;
6058
}
6159

COTLMP/Ui/ServersList.cs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* PROJECT: Cult of the Lamb Multiplayer Mod
3+
* LICENSE: MIT (https://spdx.org/licenses/MIT)
4+
* PURPOSE: Servers List UI management code
5+
* COPYRIGHT: Copyright 2025 GeoB99 <geobman1999@gmail.com>
6+
*/
7+
8+
/* IMPORTS ********************************************************************/
9+
10+
using COTLMP;
11+
using COTLMP.Api;
12+
using COTLMP.Data;
13+
using COTLMP.Debug;
14+
using HarmonyLib;
15+
using BepInEx;
16+
using I2.Loc;
17+
using System.Collections;
18+
using UnityEngine;
19+
using UnityEngine.UI;
20+
21+
/* CLASSES & CODE *************************************************************/
22+
23+
/*
24+
* @brief
25+
* Contains the classes and code for the server list user interface.
26+
*
27+
* @class ServerList
28+
* The main server list UI class of which it contains UI management
29+
* code and related stuff.
30+
*/
31+
namespace COTLMP.Ui
32+
{
33+
public static class ServerList
34+
{
35+
private static Button BackButton;
36+
37+
/*
38+
* @brief
39+
* Main UI element handler for the "Back" button.
40+
* It gets executed whenever the button is clicked.
41+
*/
42+
private static void BackButtonHandler()
43+
{
44+
COTLMP.Debug.PrintLogger.PrintVerbose(DebugLevel.MESSAGE_LEVEL, DebugComponent.UI_COMPONENT, "BackButtonHandler() called");
45+
46+
/* Return to the main menu of the game */
47+
COTLMP.Api.Assets.ShowScene("Main Menu", null);
48+
}
49+
50+
/*
51+
* @brief
52+
* Main UI element handler binding routine which is executed when
53+
* the server list UI is displayed.
54+
*/
55+
private static IEnumerator BindUiElementsToHandlers()
56+
{
57+
/*
58+
* Wait for at least one frame for Unity to initialize all the UI elements
59+
* and then proceed to bind them to respective handlers.
60+
*/
61+
COTLMP.Debug.PrintLogger.PrintVerbose(DebugLevel.MESSAGE_LEVEL, DebugComponent.UI_COMPONENT, "BindUiElements() called");
62+
yield return null;
63+
64+
/* Bind the "Back" button to its handler */
65+
BackButton = GameObject.Find("BackButton").GetComponent<Button>();
66+
COTLMP.Debug.Assertions.Assert(BackButton != null, false, "BackButton gameobject returned NULL!", null);
67+
BackButton.onClick.AddListener(BackButtonHandler);
68+
yield break;
69+
}
70+
71+
/*
72+
* @brief
73+
* Displays the server list UI.
74+
*/
75+
public static void DisplayUi()
76+
{
77+
/* Load the server list UI scene, the asset bundle should be already loaded */
78+
COTLMP.Api.Assets.ShowScene("ServerListUI", null);
79+
80+
/*
81+
* Setup a coroutine to bind each UI element (buttons, list views, etc.) to
82+
* their respective handlers. The reason we use a coroutine here is because
83+
* ShowScene() might not initialize all the UI elements of a scene immediately
84+
* and therefore we could incur in a runtime error if we were to bind the UI
85+
* elements right away.
86+
*/
87+
Plugin.MonoInstance.StartCoroutine(BindUiElementsToHandlers());
88+
}
89+
}
90+
}
91+
92+
/* EOF */

0 commit comments

Comments
 (0)