diff --git a/Assets/Prefabs/GameManager.prefab b/Assets/Prefabs/GameManager.prefab index e169bc67..4b030c89 100644 --- a/Assets/Prefabs/GameManager.prefab +++ b/Assets/Prefabs/GameManager.prefab @@ -27,6 +27,8 @@ GameObject: - component: {fileID: 5853763562556677784} - component: {fileID: 7588617501852694525} - component: {fileID: 6547606932669875539} + - component: {fileID: 8970227709208402880} + - component: {fileID: 3898620812402470502} m_Layer: 0 m_Name: GameManager m_TagString: Untagged @@ -352,3 +354,27 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 28b5c4d8f70199a438f3c28f59d87264, type: 3} m_Name: m_EditorClassIdentifier: +--- !u!114 &8970227709208402880 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1297494511425690} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 37e62fd808355224f8f300f0f87734d9, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &3898620812402470502 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1297494511425690} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: aabf0ed3019cb714e9079ac483b9a670, type: 3} + m_Name: + m_EditorClassIdentifier: diff --git a/Assets/Scripts/Behaviours/GameModeManager.cs b/Assets/Scripts/Behaviours/GameModeManager.cs new file mode 100644 index 00000000..68e125a4 --- /dev/null +++ b/Assets/Scripts/Behaviours/GameModeManager.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace SanAndreasUnity.Behaviours +{ + public class GameModeManager : MonoBehaviour + { + public static GameModeManager Instance { get; private set; } + + public class GameModeInfo + { + public string Name { get; } + public string Description { get; } + public System.Action ActivationCallback { get; } + + public GameModeInfo(string name, string description, Action activationCallback) + { + Name = name; + Description = description; + ActivationCallback = activationCallback; + } + } + + List m_gameModes = new List(); + public IReadOnlyList GameModes => m_gameModes; + + private GameModeInfo m_activeGameMode; + + + void Awake() + { + Instance = this; + } + + public void RegisterGameMode(GameModeInfo gameModeInfo) + { + m_gameModes.Add(gameModeInfo); + } + + public void ActivateGameMode(GameModeInfo gameModeInfo) + { + if (m_activeGameMode != null) + { + if (m_activeGameMode == gameModeInfo) + throw new Exception($"Can not activate game mode '{gameModeInfo.Name}' because it is already activated"); + throw new Exception($"Can not activate game mode '{gameModeInfo.Name}' because another one ('{m_activeGameMode.Name}') is already activated"); + } + + m_activeGameMode = gameModeInfo; + gameModeInfo.ActivationCallback(); + } + } +} diff --git a/Assets/Scripts/Behaviours/GameModeManager.cs.meta b/Assets/Scripts/Behaviours/GameModeManager.cs.meta new file mode 100644 index 00000000..d0416593 --- /dev/null +++ b/Assets/Scripts/Behaviours/GameModeManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: aabf0ed3019cb714e9079ac483b9a670 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Behaviours/PluginManager.cs b/Assets/Scripts/Behaviours/PluginManager.cs new file mode 100644 index 00000000..46c9750f --- /dev/null +++ b/Assets/Scripts/Behaviours/PluginManager.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using SanAndreasUnity.Utilities; +using UnityEngine; + +namespace SanAndreasUnity.Behaviours +{ + public class PluginManager : MonoBehaviour + { + + public static string[] PluginDirectories => new [] + { + #if UNITY_EDITOR + Path.Combine(Application.dataPath, "../SAU_Plugins"), + #else + Path.Combine(Application.dataPath, "Plugins"), + #endif + }; + + void Awake() + { + F.RunExceptionSafe(LoadPlugins, $"Error while loading plugins: "); + } + + void LoadPlugins() + { + // find all plugins + + var allFiles = new List(); + foreach (string pluginsDirectory in PluginDirectories) + { + if (!Directory.Exists(pluginsDirectory)) + continue; + + var filePaths = Directory.GetFiles(pluginsDirectory, "*.dll", SearchOption.TopDirectoryOnly); + + // sort files manually to prevent undefined behavior + Array.Sort(filePaths); + + allFiles.AddRange(filePaths); + } + + //allFiles.RemoveAll(path => !path.EndsWith(".json", StringComparison.InvariantCultureIgnoreCase) || !path.EndsWith(".dll", StringComparison.InvariantCultureIgnoreCase)); + + + int numLoaded = 0; + foreach (string pluginFilePath in allFiles) + { + if (LoadPlugin(pluginFilePath)) + numLoaded++; + } + + if (allFiles.Count > 0) + Debug.Log($"Loaded {numLoaded}/{allFiles.Count} plugins"); + } + + bool LoadPlugin(string pluginFilePath) + { + return F.RunExceptionSafe( + () => Assembly.LoadFrom(pluginFilePath), + $"error loading plugin from '{pluginFilePath}': "); + } + } +} diff --git a/Assets/Scripts/Behaviours/PluginManager.cs.meta b/Assets/Scripts/Behaviours/PluginManager.cs.meta new file mode 100644 index 00000000..d8123da5 --- /dev/null +++ b/Assets/Scripts/Behaviours/PluginManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37e62fd808355224f8f300f0f87734d9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/UI/StartGameWindow.cs b/Assets/Scripts/UI/StartGameWindow.cs index 3c97aa28..afeadb3b 100644 --- a/Assets/Scripts/UI/StartGameWindow.cs +++ b/Assets/Scripts/UI/StartGameWindow.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.Linq; +using SanAndreasUnity.Behaviours; using UnityEngine; using SanAndreasUnity.Utilities; using SanAndreasUnity.Net; @@ -13,7 +15,7 @@ namespace SanAndreasUnity.UI bool m_dedicatedServer = false; string m_maxNumPlayersStr = "40"; [SerializeField] string[] m_availableScenes = new string[0]; - int m_selectedSceneIndex = 0; + int m_selectedModeIndex = 0; bool m_registerAtMasterServer = false; public int width = 550; @@ -60,8 +62,12 @@ namespace SanAndreasUnity.UI GUILayout.Label("Max num players:"); m_maxNumPlayersStr = GUILayout.TextField(m_maxNumPlayersStr, GUILayout.Width(100)); - GUILayout.Label("Map:"); - m_selectedSceneIndex = GUILayout.SelectionGrid(m_selectedSceneIndex, m_availableScenes, this.mapSelectionGridXCount, GUILayout.MinHeight(this.minMapButtonHeight)); + GUILayout.Label("Game mode:"); + m_selectedModeIndex = GUILayout.SelectionGrid( + m_selectedModeIndex, + m_availableScenes.Concat(GameModeManager.Instance.GameModes.Select(gm => gm.Name)).ToArray(), + this.mapSelectionGridXCount, + GUILayout.MinHeight(this.minMapButtonHeight)); GUILayout.Space(5); m_registerAtMasterServer = GUILayout.Toggle(m_registerAtMasterServer, "Register at master server"); @@ -86,13 +92,24 @@ namespace SanAndreasUnity.UI try { ushort port = ushort.Parse(m_portStr); - string scene = m_availableScenes[m_selectedSceneIndex]; + string scene = m_selectedModeIndex < m_availableScenes.Length + ? m_availableScenes[m_selectedModeIndex] + : m_availableScenes[0]; ushort maxNumPlayers = ushort.Parse(m_maxNumPlayersStr); MasterServerClient.Instance.IsServerRegistrationEnabled = m_registerAtMasterServer; NetManager.StartServer(port, scene, maxNumPlayers, m_dedicatedServer, m_dontListen); + // activate game mode if it is selected + if (m_selectedModeIndex >= m_availableScenes.Length) + { + var gm = GameModeManager.Instance.GameModes[m_availableScenes.Length - m_selectedModeIndex]; + F.RunExceptionSafe( + () => GameModeManager.Instance.ActivateGameMode(gm), + $"Error while activating game mode '{gm.Name}': "); + } + } catch (System.Exception ex) { diff --git a/Assets/Scripts/Utilities/F.cs b/Assets/Scripts/Utilities/F.cs index a240b030..1f8fe94c 100644 --- a/Assets/Scripts/Utilities/F.cs +++ b/Assets/Scripts/Utilities/F.cs @@ -396,6 +396,20 @@ namespace SanAndreasUnity.Utilities } + public static bool RunExceptionSafe (System.Action function, string errorMessagePrefix) + { + try { + function(); + return true; + } catch(System.Exception ex) { + try { + Debug.LogError (errorMessagePrefix + ex); + } catch {} + } + + return false; + } + public static void RunExceptionSafe (System.Action function) { try {