Migrate settings to a more manageable structure and implement Service Locator pattern for runtime Addressables retrieval
This commit is contained in:
@@ -15,7 +15,7 @@ MonoBehaviour:
|
|||||||
m_DefaultGroup: 6f3207429a65b3e4b83935ac19791077
|
m_DefaultGroup: 6f3207429a65b3e4b83935ac19791077
|
||||||
m_currentHash:
|
m_currentHash:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
Hash: c0cf00979528ae95d3583c572e4eb343
|
Hash: 00000000000000000000000000000000
|
||||||
m_OptimizeCatalogSize: 0
|
m_OptimizeCatalogSize: 0
|
||||||
m_BuildRemoteCatalog: 0
|
m_BuildRemoteCatalog: 0
|
||||||
m_CatalogRequestsTimeout: 0
|
m_CatalogRequestsTimeout: 0
|
||||||
@@ -61,6 +61,7 @@ MonoBehaviour:
|
|||||||
m_GroupAssets:
|
m_GroupAssets:
|
||||||
- {fileID: 11400000, guid: efe7e1728e73e9546ac5dfee2eff524f, type: 2}
|
- {fileID: 11400000, guid: efe7e1728e73e9546ac5dfee2eff524f, type: 2}
|
||||||
- {fileID: 11400000, guid: 6e4927e7e19eef34b93dc2baa9e9e8e2, type: 2}
|
- {fileID: 11400000, guid: 6e4927e7e19eef34b93dc2baa9e9e8e2, type: 2}
|
||||||
|
- {fileID: 11400000, guid: e25c7672a65b5974bb354fcfb2a8400c, type: 2}
|
||||||
- {fileID: 11400000, guid: 7fcc03e584505ed4381983b6ebb1179d, type: 2}
|
- {fileID: 11400000, guid: 7fcc03e584505ed4381983b6ebb1179d, type: 2}
|
||||||
m_BuildSettings:
|
m_BuildSettings:
|
||||||
m_LogResourceManagerExceptions: 1
|
m_LogResourceManagerExceptions: 1
|
||||||
|
|||||||
36
Assets/AddressableAssetsData/AssetGroups/Settings.asset
Normal file
36
Assets/AddressableAssetsData/AssetGroups/Settings.asset
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: bbb281ee3bf0b054c82ac2347e9e782c, type: 3}
|
||||||
|
m_Name: Settings
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_GroupName: Settings
|
||||||
|
m_GUID: c62e6f02418e19949bca4cccdd5fa02e
|
||||||
|
m_SerializeEntries:
|
||||||
|
- m_GUID: 35bfcff00faa72c4eb272a9e8288f965
|
||||||
|
m_Address: Settings/PlayerFollowerSettings
|
||||||
|
m_ReadOnly: 0
|
||||||
|
m_SerializedLabels: []
|
||||||
|
FlaggedDuringContentUpdateRestriction: 0
|
||||||
|
- m_GUID: 8f5195fb013895049a19488fd4d8f2a1
|
||||||
|
m_Address: Settings/InteractionSettings
|
||||||
|
m_ReadOnly: 0
|
||||||
|
m_SerializedLabels: []
|
||||||
|
FlaggedDuringContentUpdateRestriction: 0
|
||||||
|
- m_GUID: a9569848f604a6540827d4d4bb0a35c2
|
||||||
|
m_Address: Settings/MinigameSettings
|
||||||
|
m_ReadOnly: 0
|
||||||
|
m_SerializedLabels: []
|
||||||
|
FlaggedDuringContentUpdateRestriction: 0
|
||||||
|
m_ReadOnly: 0
|
||||||
|
m_Settings: {fileID: 11400000, guid: 11da9bb90d9dd5848b4f7629415a6937, type: 2}
|
||||||
|
m_SchemaSet:
|
||||||
|
m_Schemas: []
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e25c7672a65b5974bb354fcfb2a8400c
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -18,7 +18,7 @@ namespace Editor
|
|||||||
private enum ItemType { None, Pickup, ItemSlot }
|
private enum ItemType { None, Pickup, ItemSlot }
|
||||||
private ItemType _itemType = ItemType.None;
|
private ItemType _itemType = ItemType.None;
|
||||||
|
|
||||||
[MenuItem("Tools/Item Prefab Editor")]
|
[MenuItem("AppleHills/Item Prefab Editor")]
|
||||||
public static void ShowWindow()
|
public static void ShowWindow()
|
||||||
{
|
{
|
||||||
var window = GetWindow<ItemPrefabEditorWindow>("Item Prefab Editor");
|
var window = GetWindow<ItemPrefabEditorWindow>("Item Prefab Editor");
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ namespace Editor
|
|||||||
|
|
||||||
private bool _createNext = false;
|
private bool _createNext = false;
|
||||||
|
|
||||||
[MenuItem("Tools/Prefab Creator")]
|
[MenuItem("AppleHills/Item Prefab Creator")]
|
||||||
public static void ShowWindow()
|
public static void ShowWindow()
|
||||||
{
|
{
|
||||||
var window = GetWindow<PrefabCreatorWindow>("Prefab Creator");
|
var window = GetWindow<PrefabCreatorWindow>("Prefab Creator");
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ public class PuzzleChainEditorWindow : EditorWindow
|
|||||||
private Vector2 scrollPos;
|
private Vector2 scrollPos;
|
||||||
private const int INDENT_SIZE = 24;
|
private const int INDENT_SIZE = 24;
|
||||||
|
|
||||||
[MenuItem("Tools/Puzzle Chain Editor")]
|
[MenuItem("AppleHills/Puzzle Chain Editor")]
|
||||||
public static void ShowWindow()
|
public static void ShowWindow()
|
||||||
{
|
{
|
||||||
var window = GetWindow<PuzzleChainEditorWindow>("Puzzle Chain Editor");
|
var window = GetWindow<PuzzleChainEditorWindow>("Puzzle Chain Editor");
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class SceneObjectLocatorWindow : EditorWindow
|
|||||||
private List<PickupInfo> pickupInfos = new List<PickupInfo>();
|
private List<PickupInfo> pickupInfos = new List<PickupInfo>();
|
||||||
private Vector2 scrollPos;
|
private Vector2 scrollPos;
|
||||||
|
|
||||||
[MenuItem("Tools/Scene Object Locator")]
|
[MenuItem("AppleHills/Scene Object Locator")]
|
||||||
public static void ShowWindow()
|
public static void ShowWindow()
|
||||||
{
|
{
|
||||||
var window = GetWindow<SceneObjectLocatorWindow>("Scene Object Locator");
|
var window = GetWindow<SceneObjectLocatorWindow>("Scene Object Locator");
|
||||||
|
|||||||
190
Assets/Editor/SettingsEditorWindow.cs
Normal file
190
Assets/Editor/SettingsEditorWindow.cs
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace AppleHills.Core.Settings.Editor
|
||||||
|
{
|
||||||
|
public class SettingsEditorWindow : EditorWindow
|
||||||
|
{
|
||||||
|
private Vector2 scrollPosition;
|
||||||
|
private List<BaseSettings> allSettings = new List<BaseSettings>();
|
||||||
|
private string[] tabNames = new string[] { "Player & Follower", "Interaction & Items", "Minigames" };
|
||||||
|
private int selectedTab = 0;
|
||||||
|
private Dictionary<string, SerializedObject> serializedSettingsObjects = new Dictionary<string, SerializedObject>();
|
||||||
|
private GUIStyle headerStyle;
|
||||||
|
|
||||||
|
[MenuItem("AppleHills/Settings Editor")]
|
||||||
|
public static void ShowWindow()
|
||||||
|
{
|
||||||
|
GetWindow<SettingsEditorWindow>("Game Settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
LoadAllSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadAllSettings()
|
||||||
|
{
|
||||||
|
allSettings.Clear();
|
||||||
|
serializedSettingsObjects.Clear();
|
||||||
|
|
||||||
|
// Find all settings assets
|
||||||
|
string[] guids = AssetDatabase.FindAssets("t:BaseSettings");
|
||||||
|
foreach (string guid in guids)
|
||||||
|
{
|
||||||
|
string path = AssetDatabase.GUIDToAssetPath(guid);
|
||||||
|
BaseSettings settings = AssetDatabase.LoadAssetAtPath<BaseSettings>(path);
|
||||||
|
if (settings != null)
|
||||||
|
{
|
||||||
|
allSettings.Add(settings);
|
||||||
|
serializedSettingsObjects[settings.GetType().Name] = new SerializedObject(settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If any settings are missing, create them
|
||||||
|
CreateSettingsIfMissing<PlayerFollowerSettings>("PlayerFollowerSettings");
|
||||||
|
CreateSettingsIfMissing<InteractionSettings>("InteractionSettings");
|
||||||
|
CreateSettingsIfMissing<MinigameSettings>("MinigameSettings");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateSettingsIfMissing<T>(string fileName) where T : BaseSettings
|
||||||
|
{
|
||||||
|
if (!allSettings.Any(s => s is T))
|
||||||
|
{
|
||||||
|
// Check if the asset already exists
|
||||||
|
string[] guids = AssetDatabase.FindAssets($"t:{typeof(T).Name}");
|
||||||
|
if (guids.Length == 0)
|
||||||
|
{
|
||||||
|
// Create the settings folder if it doesn't exist
|
||||||
|
if (!AssetDatabase.IsValidFolder("Assets/Settings"))
|
||||||
|
{
|
||||||
|
AssetDatabase.CreateFolder("Assets", "Settings");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new settings asset
|
||||||
|
T settings = CreateInstance<T>();
|
||||||
|
string path = $"Assets/Settings/{fileName}.asset";
|
||||||
|
AssetDatabase.CreateAsset(settings, path);
|
||||||
|
AssetDatabase.SaveAssets();
|
||||||
|
|
||||||
|
allSettings.Add(settings);
|
||||||
|
serializedSettingsObjects[typeof(T).Name] = new SerializedObject(settings);
|
||||||
|
Debug.Log($"Created missing settings asset: {path}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Load existing asset
|
||||||
|
string path = AssetDatabase.GUIDToAssetPath(guids[0]);
|
||||||
|
T settings = AssetDatabase.LoadAssetAtPath<T>(path);
|
||||||
|
allSettings.Add(settings);
|
||||||
|
serializedSettingsObjects[typeof(T).Name] = new SerializedObject(settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGUI()
|
||||||
|
{
|
||||||
|
if (headerStyle == null)
|
||||||
|
{
|
||||||
|
headerStyle = new GUIStyle(EditorStyles.boldLabel);
|
||||||
|
headerStyle.fontSize = 14;
|
||||||
|
headerStyle.margin = new RectOffset(0, 0, 10, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.Space(10);
|
||||||
|
EditorGUILayout.LabelField("Apple Hills Game Settings", headerStyle);
|
||||||
|
EditorGUILayout.HelpBox("Use this window to modify game settings. Changes are saved automatically.", MessageType.Info);
|
||||||
|
|
||||||
|
EditorGUILayout.Space(10);
|
||||||
|
selectedTab = GUILayout.Toolbar(selectedTab, tabNames);
|
||||||
|
|
||||||
|
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
|
||||||
|
|
||||||
|
switch (selectedTab)
|
||||||
|
{
|
||||||
|
case 0: // Player & Follower
|
||||||
|
DrawSettingsEditor<PlayerFollowerSettings>();
|
||||||
|
break;
|
||||||
|
case 1: // Interaction & Items
|
||||||
|
DrawSettingsEditor<InteractionSettings>();
|
||||||
|
break;
|
||||||
|
case 2: // Minigames
|
||||||
|
DrawSettingsEditor<MinigameSettings>();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.EndScrollView();
|
||||||
|
|
||||||
|
EditorGUILayout.Space(10);
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
|
||||||
|
if (GUILayout.Button("Refresh", GUILayout.Width(100)))
|
||||||
|
{
|
||||||
|
LoadAllSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUILayout.Button("Save All", GUILayout.Width(100)))
|
||||||
|
{
|
||||||
|
foreach (var serializedObj in serializedSettingsObjects.Values)
|
||||||
|
{
|
||||||
|
serializedObj.ApplyModifiedProperties();
|
||||||
|
EditorUtility.SetDirty(serializedObj.targetObject);
|
||||||
|
}
|
||||||
|
AssetDatabase.SaveAssets();
|
||||||
|
Debug.Log("All settings saved!");
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawSettingsEditor<T>() where T : BaseSettings
|
||||||
|
{
|
||||||
|
BaseSettings settings = allSettings.Find(s => s is T);
|
||||||
|
if (settings == null)
|
||||||
|
{
|
||||||
|
EditorGUILayout.HelpBox($"No {typeof(T).Name} found. Click Refresh to create one.", MessageType.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SerializedObject serializedObj = serializedSettingsObjects[typeof(T).Name];
|
||||||
|
serializedObj.Update();
|
||||||
|
|
||||||
|
EditorGUILayout.Space(10);
|
||||||
|
|
||||||
|
// Draw all properties
|
||||||
|
SerializedProperty property = serializedObj.GetIterator();
|
||||||
|
bool enterChildren = true;
|
||||||
|
while (property.NextVisible(enterChildren))
|
||||||
|
{
|
||||||
|
enterChildren = false;
|
||||||
|
|
||||||
|
// Skip the script field
|
||||||
|
if (property.name == "m_Script") continue;
|
||||||
|
|
||||||
|
EditorGUILayout.PropertyField(property, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply changes
|
||||||
|
if (serializedObj.ApplyModifiedProperties())
|
||||||
|
{
|
||||||
|
EditorUtility.SetDirty(settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method to highlight important fields
|
||||||
|
private void DrawHighlightedProperty(SerializedProperty property, string tooltip = null)
|
||||||
|
{
|
||||||
|
GUI.backgroundColor = new Color(1f, 1f, 0.8f);
|
||||||
|
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
|
||||||
|
GUI.backgroundColor = Color.white;
|
||||||
|
|
||||||
|
EditorGUILayout.PropertyField(property, new GUIContent(property.displayName, tooltip));
|
||||||
|
|
||||||
|
EditorGUILayout.EndVertical();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Assets/Editor/SettingsEditorWindow.cs.meta
Normal file
3
Assets/Editor/SettingsEditorWindow.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bfb9e77c746e41a2903603a39df3d424
|
||||||
|
timeCreated: 1758619952
|
||||||
307
Assets/Editor/SettingsMigrationWindow.cs
Normal file
307
Assets/Editor/SettingsMigrationWindow.cs
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.AddressableAssets;
|
||||||
|
using UnityEditor.AddressableAssets.Settings;
|
||||||
|
using System.IO;
|
||||||
|
using AppleHills.Core.Settings;
|
||||||
|
|
||||||
|
namespace AppleHills.Editor
|
||||||
|
{
|
||||||
|
public class SettingsMigrationWindow : EditorWindow
|
||||||
|
{
|
||||||
|
private GameSettings legacySettings;
|
||||||
|
private bool settingsFolderExists;
|
||||||
|
private bool addressablesInstalled;
|
||||||
|
private AddressableAssetSettings addressableSettings;
|
||||||
|
private AddressableAssetGroup settingsGroup;
|
||||||
|
private GUIStyle headerStyle;
|
||||||
|
private GUIStyle successStyle;
|
||||||
|
private Vector2 scrollPosition;
|
||||||
|
private bool migrationCompleted = false;
|
||||||
|
|
||||||
|
[MenuItem("AppleHills/Migrate Legacy Settings")]
|
||||||
|
public static void ShowWindow()
|
||||||
|
{
|
||||||
|
var window = GetWindow<SettingsMigrationWindow>("Settings Migration");
|
||||||
|
window.minSize = new Vector2(450, 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
// Check if Settings folder exists
|
||||||
|
settingsFolderExists = AssetDatabase.IsValidFolder("Assets/Settings");
|
||||||
|
|
||||||
|
// Check if Addressables package is installed
|
||||||
|
addressablesInstalled = AddressableAssetSettingsDefaultObject.SettingsExists;
|
||||||
|
|
||||||
|
if (addressablesInstalled)
|
||||||
|
{
|
||||||
|
addressableSettings = AddressableAssetSettingsDefaultObject.Settings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGUI()
|
||||||
|
{
|
||||||
|
if (headerStyle == null)
|
||||||
|
{
|
||||||
|
headerStyle = new GUIStyle(EditorStyles.boldLabel);
|
||||||
|
headerStyle.fontSize = 14;
|
||||||
|
headerStyle.margin = new RectOffset(0, 0, 10, 10);
|
||||||
|
|
||||||
|
successStyle = new GUIStyle(EditorStyles.label);
|
||||||
|
successStyle.normal.textColor = Color.green;
|
||||||
|
successStyle.fontSize = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
|
||||||
|
|
||||||
|
EditorGUILayout.LabelField("Migrate Legacy Settings", headerStyle);
|
||||||
|
EditorGUILayout.Space(10);
|
||||||
|
|
||||||
|
EditorGUILayout.HelpBox(
|
||||||
|
"This tool will migrate your legacy GameSettings to the new modular settings system. " +
|
||||||
|
"It will create new settings assets in the Assets/Settings folder, mark them as Addressables, " +
|
||||||
|
"and copy values from your legacy settings.",
|
||||||
|
MessageType.Info);
|
||||||
|
|
||||||
|
EditorGUILayout.Space(10);
|
||||||
|
|
||||||
|
// Prerequisites section
|
||||||
|
EditorGUILayout.LabelField("Prerequisites", EditorStyles.boldLabel);
|
||||||
|
|
||||||
|
// Check Addressables
|
||||||
|
GUI.enabled = false;
|
||||||
|
EditorGUILayout.Toggle("Addressables Package Installed", addressablesInstalled);
|
||||||
|
GUI.enabled = true;
|
||||||
|
|
||||||
|
if (!addressablesInstalled)
|
||||||
|
{
|
||||||
|
EditorGUILayout.HelpBox(
|
||||||
|
"The Addressables package is not installed. Please install it via Window > Package Manager.",
|
||||||
|
MessageType.Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.Space(5);
|
||||||
|
|
||||||
|
// Legacy settings field
|
||||||
|
legacySettings = EditorGUILayout.ObjectField("Legacy GameSettings", legacySettings, typeof(GameSettings), false) as GameSettings;
|
||||||
|
|
||||||
|
if (legacySettings == null)
|
||||||
|
{
|
||||||
|
EditorGUILayout.HelpBox(
|
||||||
|
"Please assign your legacy GameSettings asset to migrate from.",
|
||||||
|
MessageType.Warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.Space(15);
|
||||||
|
|
||||||
|
// Migration button
|
||||||
|
GUI.enabled = legacySettings != null && addressablesInstalled;
|
||||||
|
|
||||||
|
if (GUILayout.Button("Migrate Settings", GUILayout.Height(30)))
|
||||||
|
{
|
||||||
|
MigrateSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
GUI.enabled = true;
|
||||||
|
|
||||||
|
// Success message
|
||||||
|
if (migrationCompleted)
|
||||||
|
{
|
||||||
|
EditorGUILayout.Space(10);
|
||||||
|
EditorGUILayout.LabelField("Migration completed successfully!", successStyle);
|
||||||
|
EditorGUILayout.HelpBox(
|
||||||
|
"The legacy settings have been migrated to the new system. " +
|
||||||
|
"You can now access these settings through the AppleHills > Settings Editor menu.",
|
||||||
|
MessageType.Info);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.EndScrollView();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MigrateSettings()
|
||||||
|
{
|
||||||
|
// Create Settings folder if it doesn't exist
|
||||||
|
if (!settingsFolderExists)
|
||||||
|
{
|
||||||
|
AssetDatabase.CreateFolder("Assets", "Settings");
|
||||||
|
settingsFolderExists = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup Addressables group for settings
|
||||||
|
SetupAddressablesGroup();
|
||||||
|
|
||||||
|
// Create and populate the new settings assets
|
||||||
|
CreatePlayerFollowerSettings();
|
||||||
|
CreateInteractionSettings();
|
||||||
|
CreateMinigameSettings();
|
||||||
|
|
||||||
|
// Save all assets
|
||||||
|
AssetDatabase.SaveAssets();
|
||||||
|
|
||||||
|
migrationCompleted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetupAddressablesGroup()
|
||||||
|
{
|
||||||
|
// Find or create a settings group
|
||||||
|
settingsGroup = addressableSettings.FindGroup("Settings");
|
||||||
|
|
||||||
|
if (settingsGroup == null)
|
||||||
|
{
|
||||||
|
settingsGroup = addressableSettings.CreateGroup("Settings", false, false, true, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddAssetToAddressables(string assetPath, string address)
|
||||||
|
{
|
||||||
|
// Create entry in addressables
|
||||||
|
var guid = AssetDatabase.AssetPathToGUID(assetPath);
|
||||||
|
var entry = addressableSettings.CreateOrMoveEntry(guid, settingsGroup);
|
||||||
|
|
||||||
|
// Set the address
|
||||||
|
entry.address = address;
|
||||||
|
|
||||||
|
Debug.Log($"Added {assetPath} to Addressables with address {address}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreatePlayerFollowerSettings()
|
||||||
|
{
|
||||||
|
// Create the settings asset
|
||||||
|
var settings = ScriptableObject.CreateInstance<PlayerFollowerSettings>();
|
||||||
|
|
||||||
|
// Copy values from legacy settings
|
||||||
|
if (legacySettings != null)
|
||||||
|
{
|
||||||
|
// Player settings
|
||||||
|
var playerSettings = typeof(GameSettings).GetField("moveSpeed");
|
||||||
|
if (playerSettings != null) settings.GetType().GetField("moveSpeed", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.moveSpeed);
|
||||||
|
|
||||||
|
var stopDistanceField = typeof(GameSettings).GetField("stopDistance");
|
||||||
|
if (stopDistanceField != null) settings.GetType().GetField("stopDistance", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.stopDistance);
|
||||||
|
|
||||||
|
var useRigidbodyField = typeof(GameSettings).GetField("useRigidbody");
|
||||||
|
if (useRigidbodyField != null) settings.GetType().GetField("useRigidbody", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.useRigidbody);
|
||||||
|
|
||||||
|
var defaultHoldMovementModeField = typeof(GameSettings).GetField("defaultHoldMovementMode");
|
||||||
|
if (defaultHoldMovementModeField != null) settings.GetType().GetField("defaultHoldMovementMode", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.defaultHoldMovementMode);
|
||||||
|
|
||||||
|
// Follower settings
|
||||||
|
var followDistanceField = typeof(GameSettings).GetField("followDistance");
|
||||||
|
if (followDistanceField != null) settings.GetType().GetField("followDistance", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.followDistance);
|
||||||
|
|
||||||
|
var manualMoveSmoothField = typeof(GameSettings).GetField("manualMoveSmooth");
|
||||||
|
if (manualMoveSmoothField != null) settings.GetType().GetField("manualMoveSmooth", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.manualMoveSmooth);
|
||||||
|
|
||||||
|
var thresholdFarField = typeof(GameSettings).GetField("thresholdFar");
|
||||||
|
if (thresholdFarField != null) settings.GetType().GetField("thresholdFar", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.thresholdFar);
|
||||||
|
|
||||||
|
var thresholdNearField = typeof(GameSettings).GetField("thresholdNear");
|
||||||
|
if (thresholdNearField != null) settings.GetType().GetField("thresholdNear", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.thresholdNear);
|
||||||
|
|
||||||
|
var stopThresholdField = typeof(GameSettings).GetField("stopThreshold");
|
||||||
|
if (stopThresholdField != null) settings.GetType().GetField("stopThreshold", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.stopThreshold);
|
||||||
|
|
||||||
|
// Backend settings
|
||||||
|
var followUpdateIntervalField = typeof(GameSettings).GetField("followUpdateInterval");
|
||||||
|
if (followUpdateIntervalField != null) settings.GetType().GetField("followUpdateInterval", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.followUpdateInterval);
|
||||||
|
|
||||||
|
var followerSpeedMultiplierField = typeof(GameSettings).GetField("followerSpeedMultiplier");
|
||||||
|
if (followerSpeedMultiplierField != null) settings.GetType().GetField("followerSpeedMultiplier", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.followerSpeedMultiplier);
|
||||||
|
|
||||||
|
var heldIconDisplayHeightField = typeof(GameSettings).GetField("heldIconDisplayHeight");
|
||||||
|
if (heldIconDisplayHeightField != null) settings.GetType().GetField("heldIconDisplayHeight", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.heldIconDisplayHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the asset
|
||||||
|
string assetPath = "Assets/Settings/PlayerFollowerSettings.asset";
|
||||||
|
AssetDatabase.CreateAsset(settings, assetPath);
|
||||||
|
|
||||||
|
// Add to addressables
|
||||||
|
AddAssetToAddressables(assetPath, "Settings/PlayerFollowerSettings");
|
||||||
|
|
||||||
|
Debug.Log("Created PlayerFollowerSettings asset");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateInteractionSettings()
|
||||||
|
{
|
||||||
|
// Create the settings asset
|
||||||
|
var settings = ScriptableObject.CreateInstance<InteractionSettings>();
|
||||||
|
|
||||||
|
// Copy values from legacy settings
|
||||||
|
if (legacySettings != null)
|
||||||
|
{
|
||||||
|
// Interaction settings
|
||||||
|
var playerStopDistanceField = typeof(GameSettings).GetField("playerStopDistance");
|
||||||
|
if (playerStopDistanceField != null) settings.GetType().GetField("playerStopDistance", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.playerStopDistance);
|
||||||
|
|
||||||
|
var playerStopDistanceDirectInteractionField = typeof(GameSettings).GetField("playerStopDistanceDirectInteraction");
|
||||||
|
if (playerStopDistanceDirectInteractionField != null) settings.GetType().GetField("playerStopDistanceDirectInteraction", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.playerStopDistanceDirectInteraction);
|
||||||
|
|
||||||
|
var followerPickupDelayField = typeof(GameSettings).GetField("followerPickupDelay");
|
||||||
|
if (followerPickupDelayField != null) settings.GetType().GetField("followerPickupDelay", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.followerPickupDelay);
|
||||||
|
|
||||||
|
var interactableLayerMaskField = typeof(GameSettings).GetField("interactableLayerMask");
|
||||||
|
if (interactableLayerMaskField != null) settings.GetType().GetField("interactableLayerMask", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.interactableLayerMask);
|
||||||
|
|
||||||
|
// Prefabs
|
||||||
|
var basePickupPrefabField = typeof(GameSettings).GetField("basePickupPrefab");
|
||||||
|
if (basePickupPrefabField != null) settings.GetType().GetField("basePickupPrefab", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.basePickupPrefab);
|
||||||
|
|
||||||
|
var levelSwitchMenuPrefabField = typeof(GameSettings).GetField("levelSwitchMenuPrefab");
|
||||||
|
if (levelSwitchMenuPrefabField != null) settings.GetType().GetField("levelSwitchMenuPrefab", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.levelSwitchMenuPrefab);
|
||||||
|
|
||||||
|
// Item configuration
|
||||||
|
var combinationRulesField = typeof(GameSettings).GetField("combinationRules");
|
||||||
|
if (combinationRulesField != null) settings.GetType().GetField("combinationRules", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.combinationRules);
|
||||||
|
|
||||||
|
var slotItemConfigsField = typeof(GameSettings).GetField("slotItemConfigs");
|
||||||
|
if (slotItemConfigsField != null) settings.GetType().GetField("slotItemConfigs", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.slotItemConfigs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the asset
|
||||||
|
string assetPath = "Assets/Settings/InteractionSettings.asset";
|
||||||
|
AssetDatabase.CreateAsset(settings, assetPath);
|
||||||
|
|
||||||
|
// Add to addressables
|
||||||
|
AddAssetToAddressables(assetPath, "Settings/InteractionSettings");
|
||||||
|
|
||||||
|
Debug.Log("Created InteractionSettings asset");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateMinigameSettings()
|
||||||
|
{
|
||||||
|
// Create the settings asset
|
||||||
|
var settings = ScriptableObject.CreateInstance<MinigameSettings>();
|
||||||
|
|
||||||
|
// Copy values from legacy settings
|
||||||
|
if (legacySettings != null)
|
||||||
|
{
|
||||||
|
// Endless descender settings
|
||||||
|
var endlessDescenderLerpSpeedField = typeof(GameSettings).GetField("endlessDescenderLerpSpeed");
|
||||||
|
if (endlessDescenderLerpSpeedField != null) settings.GetType().GetField("endlessDescenderLerpSpeed", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.endlessDescenderLerpSpeed);
|
||||||
|
|
||||||
|
var endlessDescenderMaxOffsetField = typeof(GameSettings).GetField("endlessDescenderMaxOffset");
|
||||||
|
if (endlessDescenderMaxOffsetField != null) settings.GetType().GetField("endlessDescenderMaxOffset", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.endlessDescenderMaxOffset);
|
||||||
|
|
||||||
|
var endlessDescenderClampXMinField = typeof(GameSettings).GetField("endlessDescenderClampXMin");
|
||||||
|
if (endlessDescenderClampXMinField != null) settings.GetType().GetField("endlessDescenderClampXMin", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.endlessDescenderClampXMin);
|
||||||
|
|
||||||
|
var endlessDescenderClampXMaxField = typeof(GameSettings).GetField("endlessDescenderClampXMax");
|
||||||
|
if (endlessDescenderClampXMaxField != null) settings.GetType().GetField("endlessDescenderClampXMax", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.endlessDescenderClampXMax);
|
||||||
|
|
||||||
|
var endlessDescenderSpeedExponentField = typeof(GameSettings).GetField("endlessDescenderSpeedExponent");
|
||||||
|
if (endlessDescenderSpeedExponentField != null) settings.GetType().GetField("endlessDescenderSpeedExponent", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(settings, legacySettings.endlessDescenderSpeedExponent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the asset
|
||||||
|
string assetPath = "Assets/Settings/MinigameSettings.asset";
|
||||||
|
AssetDatabase.CreateAsset(settings, assetPath);
|
||||||
|
|
||||||
|
// Add to addressables
|
||||||
|
AddAssetToAddressables(assetPath, "Settings/MinigameSettings");
|
||||||
|
|
||||||
|
Debug.Log("Created MinigameSettings asset");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Assets/Editor/SettingsMigrationWindow.cs.meta
Normal file
3
Assets/Editor/SettingsMigrationWindow.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b16caebbe9934df3a34f0b75879e65f2
|
||||||
|
timeCreated: 1758630926
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using AppleHills.Core.Settings;
|
||||||
|
using System.Collections;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Singleton manager for global game state and settings. Provides accessors for various gameplay parameters.
|
/// Singleton manager for global game state and settings. Provides accessors for various gameplay parameters.
|
||||||
@@ -29,53 +31,115 @@ public class GameManager : MonoBehaviour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Header("Game Settings")]
|
[Header("Legacy Game Settings (Deprecated)")]
|
||||||
public GameSettings gameSettings;
|
[Tooltip("This is only used for migration to the new settings system")]
|
||||||
|
public GameSettings legacyGameSettings;
|
||||||
|
|
||||||
|
[Header("Settings Status")]
|
||||||
|
[SerializeField] private bool _settingsLoaded = false;
|
||||||
|
|
||||||
void Awake()
|
void Awake()
|
||||||
{
|
{
|
||||||
_instance = this;
|
_instance = this;
|
||||||
if (gameSettings == null)
|
|
||||||
{
|
// Create settings provider if it doesn't exist
|
||||||
gameSettings = Resources.Load<GameSettings>("DefaultSettings");
|
SettingsProvider.Instance.gameObject.name = "Settings Provider";
|
||||||
if (gameSettings == null)
|
|
||||||
{
|
// Load all settings
|
||||||
Debug.LogError("GameSettings asset not found in Resources!");
|
StartCoroutine(InitializeSettings());
|
||||||
}
|
|
||||||
}
|
|
||||||
// DontDestroyOnLoad(gameObject);
|
// DontDestroyOnLoad(gameObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IEnumerator InitializeSettings()
|
||||||
|
{
|
||||||
|
// Initialize the settings provider
|
||||||
|
var initComplete = false;
|
||||||
|
SettingsProvider.Instance.PreloadAllSettings(() => initComplete = true);
|
||||||
|
|
||||||
|
// Wait for settings to be loaded
|
||||||
|
while (!initComplete)
|
||||||
|
{
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register settings with service locator
|
||||||
|
ServiceLocator.Register<IPlayerFollowerSettings>(
|
||||||
|
SettingsProvider.Instance.GetSettings<PlayerFollowerSettings>());
|
||||||
|
|
||||||
|
ServiceLocator.Register<IInteractionSettings>(
|
||||||
|
SettingsProvider.Instance.GetSettings<InteractionSettings>());
|
||||||
|
|
||||||
|
ServiceLocator.Register<IMinigameSettings>(
|
||||||
|
SettingsProvider.Instance.GetSettings<MinigameSettings>());
|
||||||
|
|
||||||
|
// Log success
|
||||||
|
Debug.Log("All settings loaded and registered with ServiceLocator");
|
||||||
|
_settingsLoaded = true;
|
||||||
|
|
||||||
|
// Migrate settings if needed
|
||||||
|
if (legacyGameSettings != null)
|
||||||
|
{
|
||||||
|
MigrateFromLegacySettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MigrateFromLegacySettings()
|
||||||
|
{
|
||||||
|
// This method can be used to copy settings from the old GameSettings to the new system
|
||||||
|
// Implement if needed for your production environment
|
||||||
|
Debug.Log("Legacy settings migration available but not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
void OnApplicationQuit()
|
void OnApplicationQuit()
|
||||||
{
|
{
|
||||||
_isQuitting = true;
|
_isQuitting = true;
|
||||||
|
ServiceLocator.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accessors for game settings
|
// Helper method to get settings
|
||||||
public float PlayerStopDistance => gameSettings != null ? gameSettings.playerStopDistance : 1.0f;
|
private T GetSettings<T>() where T : class
|
||||||
public float FollowerPickupDelay => gameSettings != null ? gameSettings.followerPickupDelay : 0.2f;
|
{
|
||||||
public float FollowDistance => gameSettings != null ? gameSettings.followDistance : 1.5f;
|
return ServiceLocator.Get<T>();
|
||||||
public float ManualMoveSmooth => gameSettings != null ? gameSettings.manualMoveSmooth : 8f;
|
}
|
||||||
public float ThresholdFar => gameSettings != null ? gameSettings.thresholdFar : 2.5f;
|
|
||||||
public float ThresholdNear => gameSettings != null ? gameSettings.thresholdNear : 0.5f;
|
// PLAYER & FOLLOWER SETTINGS
|
||||||
public float StopThreshold => gameSettings != null ? gameSettings.stopThreshold : 0.5f;
|
|
||||||
public float MoveSpeed => gameSettings != null ? gameSettings.moveSpeed : 5f;
|
// Player settings
|
||||||
public float StopDistance => gameSettings != null ? gameSettings.stopDistance : 0.1f;
|
public float MoveSpeed => GetSettings<IPlayerFollowerSettings>()?.MoveSpeed ?? 5f;
|
||||||
public bool UseRigidbody => gameSettings != null ? gameSettings.useRigidbody : true;
|
public float StopDistance => GetSettings<IPlayerFollowerSettings>()?.StopDistance ?? 0.1f;
|
||||||
public float FollowUpdateInterval => gameSettings != null ? gameSettings.followUpdateInterval : 0.1f;
|
public bool UseRigidbody => GetSettings<IPlayerFollowerSettings>()?.UseRigidbody ?? true;
|
||||||
public float FollowerSpeedMultiplier => gameSettings != null ? gameSettings.followerSpeedMultiplier : 1.2f;
|
public GameSettings.HoldMovementMode DefaultHoldMovementMode =>
|
||||||
public float HeldIconDisplayHeight => gameSettings != null ? gameSettings.heldIconDisplayHeight : 2.0f;
|
GetSettings<IPlayerFollowerSettings>()?.DefaultHoldMovementMode ?? GameSettings.HoldMovementMode.Pathfinding;
|
||||||
public GameObject BasePickupPrefab => gameSettings != null ? gameSettings.basePickupPrefab : null;
|
|
||||||
public LayerMask InteractableLayerMask => gameSettings != null ? gameSettings.interactableLayerMask : -1;
|
// Follower settings
|
||||||
public float PlayerStopDistanceDirectInteraction => gameSettings != null ? gameSettings.playerStopDistanceDirectInteraction : 2.0f;
|
public float FollowDistance => GetSettings<IPlayerFollowerSettings>()?.FollowDistance ?? 1.5f;
|
||||||
|
public float ManualMoveSmooth => GetSettings<IPlayerFollowerSettings>()?.ManualMoveSmooth ?? 8f;
|
||||||
|
public float ThresholdFar => GetSettings<IPlayerFollowerSettings>()?.ThresholdFar ?? 2.5f;
|
||||||
|
public float ThresholdNear => GetSettings<IPlayerFollowerSettings>()?.ThresholdNear ?? 0.5f;
|
||||||
|
public float StopThreshold => GetSettings<IPlayerFollowerSettings>()?.StopThreshold ?? 0.1f;
|
||||||
|
public float FollowUpdateInterval => GetSettings<IPlayerFollowerSettings>()?.FollowUpdateInterval ?? 0.1f;
|
||||||
|
public float FollowerSpeedMultiplier => GetSettings<IPlayerFollowerSettings>()?.FollowerSpeedMultiplier ?? 1.2f;
|
||||||
|
public float HeldIconDisplayHeight => GetSettings<IPlayerFollowerSettings>()?.HeldIconDisplayHeight ?? 2.0f;
|
||||||
|
|
||||||
|
// INTERACTION SETTINGS
|
||||||
|
|
||||||
|
public float PlayerStopDistance => GetSettings<IInteractionSettings>()?.PlayerStopDistance ?? 6.0f;
|
||||||
|
public float PlayerStopDistanceDirectInteraction => GetSettings<IInteractionSettings>()?.PlayerStopDistanceDirectInteraction ?? 2.0f;
|
||||||
|
public float FollowerPickupDelay => GetSettings<IInteractionSettings>()?.FollowerPickupDelay ?? 0.2f;
|
||||||
|
public LayerMask InteractableLayerMask => GetSettings<IInteractionSettings>()?.InteractableLayerMask ?? -1;
|
||||||
|
public GameObject BasePickupPrefab => GetSettings<IInteractionSettings>()?.BasePickupPrefab;
|
||||||
|
public GameObject LevelSwitchMenuPrefab => GetSettings<IInteractionSettings>()?.LevelSwitchMenuPrefab;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the combination rule for two items, if any.
|
/// Returns the combination rule for two items, if any.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public GameSettings.CombinationRule GetCombinationRule(PickupItemData item1, PickupItemData item2)
|
public GameSettings.CombinationRule GetCombinationRule(PickupItemData item1, PickupItemData item2)
|
||||||
{
|
{
|
||||||
if (gameSettings == null || gameSettings.combinationRules == null) return null;
|
var settings = GetSettings<IInteractionSettings>();
|
||||||
foreach (var rule in gameSettings.combinationRules)
|
if (settings == null || settings.CombinationRules == null) return null;
|
||||||
|
|
||||||
|
foreach (var rule in settings.CombinationRules)
|
||||||
{
|
{
|
||||||
if ((PickupItemData.AreEquivalent(rule.itemA, item1) && PickupItemData.AreEquivalent(rule.itemB, item2)) ||
|
if ((PickupItemData.AreEquivalent(rule.itemA, item1) && PickupItemData.AreEquivalent(rule.itemB, item2)) ||
|
||||||
(PickupItemData.AreEquivalent(rule.itemA, item2) && PickupItemData.AreEquivalent(rule.itemB, item1)))
|
(PickupItemData.AreEquivalent(rule.itemA, item2) && PickupItemData.AreEquivalent(rule.itemB, item1)))
|
||||||
@@ -91,20 +155,23 @@ public class GameManager : MonoBehaviour
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public GameSettings.SlotItemConfig GetSlotItemConfig(PickupItemData slotItem)
|
public GameSettings.SlotItemConfig GetSlotItemConfig(PickupItemData slotItem)
|
||||||
{
|
{
|
||||||
if (gameSettings == null || gameSettings.slotItemConfigs == null || slotItem == null) return null;
|
var settings = GetSettings<IInteractionSettings>();
|
||||||
foreach (var config in gameSettings.slotItemConfigs)
|
if (settings == null || settings.SlotItemConfigs == null || slotItem == null) return null;
|
||||||
|
|
||||||
|
foreach (var config in settings.SlotItemConfigs)
|
||||||
{
|
{
|
||||||
if (PickupItemData.AreEquivalent(slotItem, config.slotItem))
|
if (PickupItemData.AreEquivalent(slotItem, config.slotItem))
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// Add more accessors as needed
|
|
||||||
public float EndlessDescenderLerpSpeed => gameSettings != null ? gameSettings.endlessDescenderLerpSpeed : 12f;
|
// MINIGAME SETTINGS
|
||||||
public float EndlessDescenderMaxOffset => gameSettings != null ? gameSettings.endlessDescenderMaxOffset : 3f;
|
|
||||||
public float EndlessDescenderClampXMin => gameSettings != null ? gameSettings.endlessDescenderClampXMin : -5f;
|
// Endless Descender settings
|
||||||
public float EndlessDescenderClampXMax => gameSettings != null ? gameSettings.endlessDescenderClampXMax : 5f;
|
public float EndlessDescenderLerpSpeed => GetSettings<IMinigameSettings>()?.EndlessDescenderLerpSpeed ?? 12f;
|
||||||
public float EndlessDescenderSpeedExponent => gameSettings != null ? gameSettings.endlessDescenderSpeedExponent : 2.5f;
|
public float EndlessDescenderMaxOffset => GetSettings<IMinigameSettings>()?.EndlessDescenderMaxOffset ?? 3f;
|
||||||
public GameSettings.HoldMovementMode DefaultHoldMovementMode => gameSettings != null ? gameSettings.defaultHoldMovementMode : GameSettings.HoldMovementMode.Pathfinding;
|
public float EndlessDescenderClampXMin => GetSettings<IMinigameSettings>()?.EndlessDescenderClampXMin ?? -3.5f;
|
||||||
public GameObject LevelSwitchMenuPrefab => gameSettings != null ? gameSettings.levelSwitchMenuPrefab : null;
|
public float EndlessDescenderClampXMax => GetSettings<IMinigameSettings>()?.EndlessDescenderClampXMax ?? 3.5f;
|
||||||
|
public float EndlessDescenderSpeedExponent => GetSettings<IMinigameSettings>()?.EndlessDescenderSpeedExponent ?? 2.5f;
|
||||||
}
|
}
|
||||||
|
|||||||
3
Assets/Scripts/Core/Settings.meta
Normal file
3
Assets/Scripts/Core/Settings.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e380783135324fcd925048783e01d691
|
||||||
|
timeCreated: 1758619858
|
||||||
16
Assets/Scripts/Core/Settings/BaseSettings.cs
Normal file
16
Assets/Scripts/Core/Settings/BaseSettings.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AppleHills.Core.Settings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for all settings ScriptableObjects.
|
||||||
|
/// Provides common functionality for all settings types.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class BaseSettings : ScriptableObject
|
||||||
|
{
|
||||||
|
public virtual void OnValidate()
|
||||||
|
{
|
||||||
|
// Override in derived classes to add validation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Assets/Scripts/Core/Settings/BaseSettings.cs.meta
Normal file
3
Assets/Scripts/Core/Settings/BaseSettings.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: cd33ef6036eb49358acbbd50dfd9bb13
|
||||||
|
timeCreated: 1758619858
|
||||||
48
Assets/Scripts/Core/Settings/InteractionSettings.cs
Normal file
48
Assets/Scripts/Core/Settings/InteractionSettings.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AppleHills.Core.Settings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Settings related to interactions and items
|
||||||
|
/// </summary>
|
||||||
|
[CreateAssetMenu(fileName = "InteractionSettings", menuName = "AppleHills/Settings/Interaction & Items", order = 2)]
|
||||||
|
public class InteractionSettings : BaseSettings, IInteractionSettings
|
||||||
|
{
|
||||||
|
[Header("Interactions")]
|
||||||
|
[SerializeField] private float playerStopDistance = 6.0f;
|
||||||
|
[SerializeField] private float playerStopDistanceDirectInteraction = 2.0f;
|
||||||
|
[SerializeField] private float followerPickupDelay = 0.2f;
|
||||||
|
|
||||||
|
[Header("InputManager Settings")]
|
||||||
|
[Tooltip("Layer(s) to use for interactable objects.")]
|
||||||
|
[SerializeField] private LayerMask interactableLayerMask = -1; // Default to Everything
|
||||||
|
|
||||||
|
[Header("Default Prefabs")]
|
||||||
|
[SerializeField] private GameObject basePickupPrefab;
|
||||||
|
[SerializeField] private GameObject levelSwitchMenuPrefab;
|
||||||
|
|
||||||
|
[Header("Item Configuration")]
|
||||||
|
[SerializeField] private List<GameSettings.CombinationRule> combinationRules = new List<GameSettings.CombinationRule>();
|
||||||
|
[SerializeField] private List<GameSettings.SlotItemConfig> slotItemConfigs = new List<GameSettings.SlotItemConfig>();
|
||||||
|
|
||||||
|
// IInteractionSettings implementation
|
||||||
|
public float PlayerStopDistance => playerStopDistance;
|
||||||
|
public float PlayerStopDistanceDirectInteraction => playerStopDistanceDirectInteraction;
|
||||||
|
public float FollowerPickupDelay => followerPickupDelay;
|
||||||
|
public LayerMask InteractableLayerMask => interactableLayerMask;
|
||||||
|
public GameObject BasePickupPrefab => basePickupPrefab;
|
||||||
|
public GameObject LevelSwitchMenuPrefab => levelSwitchMenuPrefab;
|
||||||
|
public List<GameSettings.CombinationRule> CombinationRules => combinationRules;
|
||||||
|
public List<GameSettings.SlotItemConfig> SlotItemConfigs => slotItemConfigs;
|
||||||
|
|
||||||
|
public override void OnValidate()
|
||||||
|
{
|
||||||
|
base.OnValidate();
|
||||||
|
// Validate values
|
||||||
|
playerStopDistance = Mathf.Max(0.1f, playerStopDistance);
|
||||||
|
playerStopDistanceDirectInteraction = Mathf.Max(0.1f, playerStopDistanceDirectInteraction);
|
||||||
|
followerPickupDelay = Mathf.Max(0f, followerPickupDelay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Assets/Scripts/Core/Settings/InteractionSettings.cs.meta
Normal file
3
Assets/Scripts/Core/Settings/InteractionSettings.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ac22b092dc6f4db5b3dad35172b6e4c4
|
||||||
|
timeCreated: 1758619914
|
||||||
49
Assets/Scripts/Core/Settings/MinigameSettings.cs
Normal file
49
Assets/Scripts/Core/Settings/MinigameSettings.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AppleHills.Core.Settings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Settings related to minigames
|
||||||
|
/// </summary>
|
||||||
|
[CreateAssetMenu(fileName = "MinigameSettings", menuName = "AppleHills/Settings/Minigames", order = 3)]
|
||||||
|
public class MinigameSettings : BaseSettings, IMinigameSettings
|
||||||
|
{
|
||||||
|
[Header("Endless Descender Settings")]
|
||||||
|
[Tooltip("How quickly the character follows the finger horizontally (higher = more responsive)")]
|
||||||
|
[SerializeField] private float endlessDescenderLerpSpeed = 12f;
|
||||||
|
|
||||||
|
[Tooltip("Maximum horizontal offset allowed between character and finger position")]
|
||||||
|
[SerializeField] private float endlessDescenderMaxOffset = 3f;
|
||||||
|
|
||||||
|
[Tooltip("Minimum allowed X position for endless descender movement")]
|
||||||
|
[SerializeField] private float endlessDescenderClampXMin = -3.5f;
|
||||||
|
|
||||||
|
[Tooltip("Maximum allowed X position for endless descender movement")]
|
||||||
|
[SerializeField] private float endlessDescenderClampXMax = 3.5f;
|
||||||
|
|
||||||
|
[Tooltip("Exponent for speed drop-off curve (higher = sharper drop near target)")]
|
||||||
|
[SerializeField] private float endlessDescenderSpeedExponent = 2.5f;
|
||||||
|
|
||||||
|
// IMinigameSettings implementation
|
||||||
|
public float EndlessDescenderLerpSpeed => endlessDescenderLerpSpeed;
|
||||||
|
public float EndlessDescenderMaxOffset => endlessDescenderMaxOffset;
|
||||||
|
public float EndlessDescenderClampXMin => endlessDescenderClampXMin;
|
||||||
|
public float EndlessDescenderClampXMax => endlessDescenderClampXMax;
|
||||||
|
public float EndlessDescenderSpeedExponent => endlessDescenderSpeedExponent;
|
||||||
|
|
||||||
|
public override void OnValidate()
|
||||||
|
{
|
||||||
|
base.OnValidate();
|
||||||
|
// Validate values
|
||||||
|
endlessDescenderLerpSpeed = Mathf.Max(0.1f, endlessDescenderLerpSpeed);
|
||||||
|
endlessDescenderMaxOffset = Mathf.Max(0.1f, endlessDescenderMaxOffset);
|
||||||
|
endlessDescenderSpeedExponent = Mathf.Max(0.1f, endlessDescenderSpeedExponent);
|
||||||
|
|
||||||
|
// Ensure min is less than max
|
||||||
|
if (endlessDescenderClampXMin >= endlessDescenderClampXMax)
|
||||||
|
{
|
||||||
|
endlessDescenderClampXMin = endlessDescenderClampXMax - 0.1f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Assets/Scripts/Core/Settings/MinigameSettings.cs.meta
Normal file
3
Assets/Scripts/Core/Settings/MinigameSettings.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0ce4dba7a1c54e73b1b3d7131a1c0570
|
||||||
|
timeCreated: 1758619927
|
||||||
53
Assets/Scripts/Core/Settings/PlayerFollowerSettings.cs
Normal file
53
Assets/Scripts/Core/Settings/PlayerFollowerSettings.cs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AppleHills.Core.Settings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Settings related to player and follower behavior
|
||||||
|
/// </summary>
|
||||||
|
[CreateAssetMenu(fileName = "PlayerFollowerSettings", menuName = "AppleHills/Settings/Player & Follower", order = 1)]
|
||||||
|
public class PlayerFollowerSettings : BaseSettings, IPlayerFollowerSettings
|
||||||
|
{
|
||||||
|
[Header("Player Settings")]
|
||||||
|
[SerializeField] private float moveSpeed = 5f;
|
||||||
|
[SerializeField] private float stopDistance = 0.1f;
|
||||||
|
[SerializeField] private bool useRigidbody = true;
|
||||||
|
[SerializeField] private GameSettings.HoldMovementMode defaultHoldMovementMode = GameSettings.HoldMovementMode.Pathfinding;
|
||||||
|
|
||||||
|
[Header("Follower Settings")]
|
||||||
|
[SerializeField] private float followDistance = 1.5f;
|
||||||
|
[SerializeField] private float manualMoveSmooth = 8f;
|
||||||
|
[SerializeField] private float thresholdFar = 2.5f;
|
||||||
|
[SerializeField] private float thresholdNear = 0.5f;
|
||||||
|
[SerializeField] private float stopThreshold = 0.1f;
|
||||||
|
|
||||||
|
[Header("Backend Settings")]
|
||||||
|
[Tooltip("Technical parameters, not for design tuning")]
|
||||||
|
[SerializeField] private float followUpdateInterval = 0.1f;
|
||||||
|
[SerializeField] private float followerSpeedMultiplier = 1.2f;
|
||||||
|
[SerializeField] private float heldIconDisplayHeight = 2.0f;
|
||||||
|
|
||||||
|
// IPlayerFollowerSettings implementation
|
||||||
|
public float MoveSpeed => moveSpeed;
|
||||||
|
public float StopDistance => stopDistance;
|
||||||
|
public bool UseRigidbody => useRigidbody;
|
||||||
|
public GameSettings.HoldMovementMode DefaultHoldMovementMode => defaultHoldMovementMode;
|
||||||
|
public float FollowDistance => followDistance;
|
||||||
|
public float ManualMoveSmooth => manualMoveSmooth;
|
||||||
|
public float ThresholdFar => thresholdFar;
|
||||||
|
public float ThresholdNear => thresholdNear;
|
||||||
|
public float StopThreshold => stopThreshold;
|
||||||
|
public float FollowUpdateInterval => followUpdateInterval;
|
||||||
|
public float FollowerSpeedMultiplier => followerSpeedMultiplier;
|
||||||
|
public float HeldIconDisplayHeight => heldIconDisplayHeight;
|
||||||
|
|
||||||
|
public override void OnValidate()
|
||||||
|
{
|
||||||
|
base.OnValidate();
|
||||||
|
// Validate values
|
||||||
|
moveSpeed = Mathf.Max(0.1f, moveSpeed);
|
||||||
|
followDistance = Mathf.Max(0.1f, followDistance);
|
||||||
|
followerSpeedMultiplier = Mathf.Max(0.1f, followerSpeedMultiplier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 32cd6d14d9304d5ba0fd590da1346654
|
||||||
|
timeCreated: 1758619904
|
||||||
51
Assets/Scripts/Core/Settings/ServiceLocator.cs
Normal file
51
Assets/Scripts/Core/Settings/ServiceLocator.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AppleHills.Core.Settings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Service Locator implementation for managing settings services.
|
||||||
|
/// Provides a central registry for all settings services.
|
||||||
|
/// </summary>
|
||||||
|
public static class ServiceLocator
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<Type, object> _services = new Dictionary<Type, object>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register a service with the service locator.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The interface type for the service</typeparam>
|
||||||
|
/// <param name="service">The service implementation</param>
|
||||||
|
public static void Register<T>(T service) where T : class
|
||||||
|
{
|
||||||
|
_services[typeof(T)] = service;
|
||||||
|
Debug.Log($"Service registered: {typeof(T).Name}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a service from the service locator.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The interface type for the service</typeparam>
|
||||||
|
/// <returns>The service implementation, or null if not found</returns>
|
||||||
|
public static T Get<T>() where T : class
|
||||||
|
{
|
||||||
|
if (_services.TryGetValue(typeof(T), out object service))
|
||||||
|
{
|
||||||
|
return service as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.LogWarning($"Service of type {typeof(T).Name} not found!");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clear all registered services.
|
||||||
|
/// </summary>
|
||||||
|
public static void Clear()
|
||||||
|
{
|
||||||
|
_services.Clear();
|
||||||
|
Debug.Log("All services cleared");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Assets/Scripts/Core/Settings/ServiceLocator.cs.meta
Normal file
3
Assets/Scripts/Core/Settings/ServiceLocator.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 16cc39d2f99b4e7fa65c4a8b39f3e87c
|
||||||
|
timeCreated: 1758619866
|
||||||
54
Assets/Scripts/Core/Settings/SettingsInterfaces.cs
Normal file
54
Assets/Scripts/Core/Settings/SettingsInterfaces.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AppleHills.Core.Settings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for player and follower settings
|
||||||
|
/// </summary>
|
||||||
|
public interface IPlayerFollowerSettings
|
||||||
|
{
|
||||||
|
// Player settings
|
||||||
|
float MoveSpeed { get; }
|
||||||
|
float StopDistance { get; }
|
||||||
|
bool UseRigidbody { get; }
|
||||||
|
GameSettings.HoldMovementMode DefaultHoldMovementMode { get; }
|
||||||
|
|
||||||
|
// Follower settings
|
||||||
|
float FollowDistance { get; }
|
||||||
|
float ManualMoveSmooth { get; }
|
||||||
|
float ThresholdFar { get; }
|
||||||
|
float ThresholdNear { get; }
|
||||||
|
float StopThreshold { get; }
|
||||||
|
float FollowUpdateInterval { get; }
|
||||||
|
float FollowerSpeedMultiplier { get; }
|
||||||
|
float HeldIconDisplayHeight { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for interaction and item settings
|
||||||
|
/// </summary>
|
||||||
|
public interface IInteractionSettings
|
||||||
|
{
|
||||||
|
float PlayerStopDistance { get; }
|
||||||
|
float PlayerStopDistanceDirectInteraction { get; }
|
||||||
|
float FollowerPickupDelay { get; }
|
||||||
|
LayerMask InteractableLayerMask { get; }
|
||||||
|
GameObject BasePickupPrefab { get; }
|
||||||
|
GameObject LevelSwitchMenuPrefab { get; }
|
||||||
|
System.Collections.Generic.List<GameSettings.CombinationRule> CombinationRules { get; }
|
||||||
|
System.Collections.Generic.List<GameSettings.SlotItemConfig> SlotItemConfigs { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface for minigame settings
|
||||||
|
/// </summary>
|
||||||
|
public interface IMinigameSettings
|
||||||
|
{
|
||||||
|
// Endless Descender settings
|
||||||
|
float EndlessDescenderLerpSpeed { get; }
|
||||||
|
float EndlessDescenderMaxOffset { get; }
|
||||||
|
float EndlessDescenderClampXMin { get; }
|
||||||
|
float EndlessDescenderClampXMax { get; }
|
||||||
|
float EndlessDescenderSpeedExponent { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Assets/Scripts/Core/Settings/SettingsInterfaces.cs.meta
Normal file
3
Assets/Scripts/Core/Settings/SettingsInterfaces.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 54611ae012ab4455a53bd60961d9e7ea
|
||||||
|
timeCreated: 1758619892
|
||||||
106
Assets/Scripts/Core/Settings/SettingsProvider.cs
Normal file
106
Assets/Scripts/Core/Settings/SettingsProvider.cs
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.AddressableAssets;
|
||||||
|
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||||
|
|
||||||
|
namespace AppleHills.Core.Settings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Responsible for loading and caching settings from Addressables.
|
||||||
|
/// </summary>
|
||||||
|
public class SettingsProvider : MonoBehaviour
|
||||||
|
{
|
||||||
|
private static SettingsProvider _instance;
|
||||||
|
private Dictionary<string, BaseSettings> _settingsCache = new Dictionary<string, BaseSettings>();
|
||||||
|
|
||||||
|
// Singleton instance
|
||||||
|
public static SettingsProvider Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_instance == null)
|
||||||
|
{
|
||||||
|
GameObject go = new GameObject("Settings Provider");
|
||||||
|
_instance = go.AddComponent<SettingsProvider>();
|
||||||
|
DontDestroyOnLoad(go);
|
||||||
|
}
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
if (_instance == null)
|
||||||
|
{
|
||||||
|
_instance = this;
|
||||||
|
DontDestroyOnLoad(gameObject);
|
||||||
|
}
|
||||||
|
else if (_instance != this)
|
||||||
|
{
|
||||||
|
Destroy(gameObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Load settings asynchronously using Addressables
|
||||||
|
/// </summary>
|
||||||
|
public void LoadSettings<T>(Action<T> onLoaded) where T : BaseSettings
|
||||||
|
{
|
||||||
|
string key = typeof(T).Name;
|
||||||
|
|
||||||
|
// Return from cache if already loaded
|
||||||
|
if (_settingsCache.TryGetValue(key, out BaseSettings cachedSettings))
|
||||||
|
{
|
||||||
|
onLoaded?.Invoke(cachedSettings as T);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load using Addressables
|
||||||
|
Addressables.LoadAssetAsync<T>($"Settings/{key}.asset").Completed += handle =>
|
||||||
|
{
|
||||||
|
if (handle.Status == AsyncOperationStatus.Succeeded)
|
||||||
|
{
|
||||||
|
_settingsCache[key] = handle.Result;
|
||||||
|
onLoaded?.Invoke(handle.Result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogError($"Failed to load settings: {key}");
|
||||||
|
onLoaded?.Invoke(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get cached settings
|
||||||
|
/// </summary>
|
||||||
|
public T GetSettings<T>() where T : BaseSettings
|
||||||
|
{
|
||||||
|
string key = typeof(T).Name;
|
||||||
|
if (_settingsCache.TryGetValue(key, out BaseSettings settings))
|
||||||
|
{
|
||||||
|
return settings as T;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preload all settings - call this at game startup
|
||||||
|
/// </summary>
|
||||||
|
public void PreloadAllSettings(Action onComplete)
|
||||||
|
{
|
||||||
|
// Load all necessary settings types
|
||||||
|
int pendingLoads = 3; // Number of settings types
|
||||||
|
Action decrementCounter = () => {
|
||||||
|
pendingLoads--;
|
||||||
|
if (pendingLoads <= 0)
|
||||||
|
onComplete?.Invoke();
|
||||||
|
};
|
||||||
|
|
||||||
|
LoadSettings<PlayerFollowerSettings>(settings => decrementCounter());
|
||||||
|
LoadSettings<InteractionSettings>(settings => decrementCounter());
|
||||||
|
LoadSettings<MinigameSettings>(settings => decrementCounter());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Assets/Scripts/Core/Settings/SettingsProvider.cs.meta
Normal file
3
Assets/Scripts/Core/Settings/SettingsProvider.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4d212b25192045d198f2bf42ef74f278
|
||||||
|
timeCreated: 1758619879
|
||||||
50
Assets/Settings/InteractionSettings.asset
Normal file
50
Assets/Settings/InteractionSettings.asset
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: ac22b092dc6f4db5b3dad35172b6e4c4, type: 3}
|
||||||
|
m_Name: InteractionSettings
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
playerStopDistance: 10
|
||||||
|
playerStopDistanceDirectInteraction: 2
|
||||||
|
followerPickupDelay: 0.2
|
||||||
|
interactableLayerMask:
|
||||||
|
serializedVersion: 2
|
||||||
|
m_Bits: 1024
|
||||||
|
basePickupPrefab: {fileID: 7447346505753002421, guid: bf4b9d7045397f946b2125b1ad4a3fbd, type: 3}
|
||||||
|
levelSwitchMenuPrefab: {fileID: 4062459998181038721, guid: de2ed28e4200a4340a5af4086c98a0dc, type: 3}
|
||||||
|
combinationRules:
|
||||||
|
- itemA: {fileID: 11400000, guid: 33e7ca06b22108d4e802486e08bcdfd1, type: 2}
|
||||||
|
itemB: {fileID: 11400000, guid: 8b2616beb14825a46b9b1ed85ad3cb25, type: 2}
|
||||||
|
resultPrefab: {fileID: 1610562450228973293, guid: 58654125374567147839eb382fcde422, type: 3}
|
||||||
|
- itemA: {fileID: 11400000, guid: 983414276ae3f004c854e9c450f27f88, type: 2}
|
||||||
|
itemB: {fileID: 11400000, guid: 0c6986639ca176a419c92f5a327d95ce, type: 2}
|
||||||
|
resultPrefab: {fileID: 5562196803416682102, guid: bb505cdbd2463b64790deffc6244c55c, type: 3}
|
||||||
|
slotItemConfigs:
|
||||||
|
- slotItem: {fileID: 11400000, guid: e0fad48a84a6b6346ac17c84bc512500, type: 2}
|
||||||
|
allowedItems:
|
||||||
|
- {fileID: 11400000, guid: ecae2d83a5ab2a047a2733ebff607380, type: 2}
|
||||||
|
forbiddenItems: []
|
||||||
|
- slotItem: {fileID: 11400000, guid: f97b9e24d6dceb145b56426c1152ebeb, type: 2}
|
||||||
|
allowedItems:
|
||||||
|
- {fileID: 11400000, guid: ff4bbba87722023468a0f6395d1f96c7, type: 2}
|
||||||
|
forbiddenItems: []
|
||||||
|
- slotItem: {fileID: 11400000, guid: d28f5774afad9d14f823601707150700, type: 2}
|
||||||
|
allowedItems:
|
||||||
|
- {fileID: 11400000, guid: 6934dcb56c610c44da228f7f24ca13c9, type: 2}
|
||||||
|
forbiddenItems: []
|
||||||
|
- slotItem: {fileID: 11400000, guid: aaf36cd26cf74334e9c7db6c1b03b3fb, type: 2}
|
||||||
|
allowedItems:
|
||||||
|
- {fileID: 11400000, guid: c50330645a2b9d549aae3639bdfcea19, type: 2}
|
||||||
|
forbiddenItems: []
|
||||||
|
- slotItem: {fileID: 11400000, guid: c68dea945fecbf44094359769db04f31, type: 2}
|
||||||
|
allowedItems:
|
||||||
|
- {fileID: 11400000, guid: ab57c8237aac144439a18d69f56d36c6, type: 2}
|
||||||
|
forbiddenItems: []
|
||||||
8
Assets/Settings/InteractionSettings.asset.meta
Normal file
8
Assets/Settings/InteractionSettings.asset.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8f5195fb013895049a19488fd4d8f2a1
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
19
Assets/Settings/MinigameSettings.asset
Normal file
19
Assets/Settings/MinigameSettings.asset
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 0ce4dba7a1c54e73b1b3d7131a1c0570, type: 3}
|
||||||
|
m_Name: MinigameSettings
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
endlessDescenderLerpSpeed: 2.03
|
||||||
|
endlessDescenderMaxOffset: 10
|
||||||
|
endlessDescenderClampXMin: -3.5
|
||||||
|
endlessDescenderClampXMax: 3.5
|
||||||
|
endlessDescenderSpeedExponent: 0.97
|
||||||
8
Assets/Settings/MinigameSettings.asset.meta
Normal file
8
Assets/Settings/MinigameSettings.asset.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a9569848f604a6540827d4d4bb0a35c2
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
26
Assets/Settings/PlayerFollowerSettings.asset
Normal file
26
Assets/Settings/PlayerFollowerSettings.asset
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 32cd6d14d9304d5ba0fd590da1346654, type: 3}
|
||||||
|
m_Name: PlayerFollowerSettings
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
moveSpeed: 25
|
||||||
|
stopDistance: 2
|
||||||
|
useRigidbody: 1
|
||||||
|
defaultHoldMovementMode: 1
|
||||||
|
followDistance: 5
|
||||||
|
manualMoveSmooth: 2
|
||||||
|
thresholdFar: 10
|
||||||
|
thresholdNear: 7
|
||||||
|
stopThreshold: 0.5
|
||||||
|
followUpdateInterval: 0.1
|
||||||
|
followerSpeedMultiplier: 1.2
|
||||||
|
heldIconDisplayHeight: 2
|
||||||
8
Assets/Settings/PlayerFollowerSettings.asset.meta
Normal file
8
Assets/Settings/PlayerFollowerSettings.asset.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 35bfcff00faa72c4eb272a9e8288f965
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Reference in New Issue
Block a user