Migrate settings to a more manageable structure and implement Service Locator pattern for runtime Addressables retrieval

This commit is contained in:
Michal Pikulski
2025-09-23 14:43:02 +02:00
parent 4b206b9b2e
commit 197aedddb0
33 changed files with 1179 additions and 44 deletions

View File

@@ -15,7 +15,7 @@ MonoBehaviour:
m_DefaultGroup: 6f3207429a65b3e4b83935ac19791077
m_currentHash:
serializedVersion: 2
Hash: c0cf00979528ae95d3583c572e4eb343
Hash: 00000000000000000000000000000000
m_OptimizeCatalogSize: 0
m_BuildRemoteCatalog: 0
m_CatalogRequestsTimeout: 0
@@ -61,6 +61,7 @@ MonoBehaviour:
m_GroupAssets:
- {fileID: 11400000, guid: efe7e1728e73e9546ac5dfee2eff524f, type: 2}
- {fileID: 11400000, guid: 6e4927e7e19eef34b93dc2baa9e9e8e2, type: 2}
- {fileID: 11400000, guid: e25c7672a65b5974bb354fcfb2a8400c, type: 2}
- {fileID: 11400000, guid: 7fcc03e584505ed4381983b6ebb1179d, type: 2}
m_BuildSettings:
m_LogResourceManagerExceptions: 1

View 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: []

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e25c7672a65b5974bb354fcfb2a8400c
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -18,7 +18,7 @@ namespace Editor
private enum ItemType { None, Pickup, ItemSlot }
private ItemType _itemType = ItemType.None;
[MenuItem("Tools/Item Prefab Editor")]
[MenuItem("AppleHills/Item Prefab Editor")]
public static void ShowWindow()
{
var window = GetWindow<ItemPrefabEditorWindow>("Item Prefab Editor");

View File

@@ -23,7 +23,7 @@ namespace Editor
private bool _createNext = false;
[MenuItem("Tools/Prefab Creator")]
[MenuItem("AppleHills/Item Prefab Creator")]
public static void ShowWindow()
{
var window = GetWindow<PrefabCreatorWindow>("Prefab Creator");

View File

@@ -9,7 +9,7 @@ public class PuzzleChainEditorWindow : EditorWindow
private Vector2 scrollPos;
private const int INDENT_SIZE = 24;
[MenuItem("Tools/Puzzle Chain Editor")]
[MenuItem("AppleHills/Puzzle Chain Editor")]
public static void ShowWindow()
{
var window = GetWindow<PuzzleChainEditorWindow>("Puzzle Chain Editor");

View File

@@ -15,7 +15,7 @@ public class SceneObjectLocatorWindow : EditorWindow
private List<PickupInfo> pickupInfos = new List<PickupInfo>();
private Vector2 scrollPos;
[MenuItem("Tools/Scene Object Locator")]
[MenuItem("AppleHills/Scene Object Locator")]
public static void ShowWindow()
{
var window = GetWindow<SceneObjectLocatorWindow>("Scene Object Locator");

View 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();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bfb9e77c746e41a2903603a39df3d424
timeCreated: 1758619952

View 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");
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b16caebbe9934df3a34f0b75879e65f2
timeCreated: 1758630926

View File

@@ -1,4 +1,6 @@
using UnityEngine;
using AppleHills.Core.Settings;
using System.Collections;
/// <summary>
/// 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")]
public GameSettings gameSettings;
[Header("Legacy Game Settings (Deprecated)")]
[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()
{
_instance = this;
if (gameSettings == null)
{
gameSettings = Resources.Load<GameSettings>("DefaultSettings");
if (gameSettings == null)
{
Debug.LogError("GameSettings asset not found in Resources!");
}
}
// Create settings provider if it doesn't exist
SettingsProvider.Instance.gameObject.name = "Settings Provider";
// Load all settings
StartCoroutine(InitializeSettings());
// 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()
{
_isQuitting = true;
ServiceLocator.Clear();
}
// Accessors for game settings
public float PlayerStopDistance => gameSettings != null ? gameSettings.playerStopDistance : 1.0f;
public float FollowerPickupDelay => gameSettings != null ? gameSettings.followerPickupDelay : 0.2f;
public float FollowDistance => gameSettings != null ? gameSettings.followDistance : 1.5f;
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;
public float StopThreshold => gameSettings != null ? gameSettings.stopThreshold : 0.5f;
public float MoveSpeed => gameSettings != null ? gameSettings.moveSpeed : 5f;
public float StopDistance => gameSettings != null ? gameSettings.stopDistance : 0.1f;
public bool UseRigidbody => gameSettings != null ? gameSettings.useRigidbody : true;
public float FollowUpdateInterval => gameSettings != null ? gameSettings.followUpdateInterval : 0.1f;
public float FollowerSpeedMultiplier => gameSettings != null ? gameSettings.followerSpeedMultiplier : 1.2f;
public float HeldIconDisplayHeight => gameSettings != null ? gameSettings.heldIconDisplayHeight : 2.0f;
public GameObject BasePickupPrefab => gameSettings != null ? gameSettings.basePickupPrefab : null;
public LayerMask InteractableLayerMask => gameSettings != null ? gameSettings.interactableLayerMask : -1;
public float PlayerStopDistanceDirectInteraction => gameSettings != null ? gameSettings.playerStopDistanceDirectInteraction : 2.0f;
// Helper method to get settings
private T GetSettings<T>() where T : class
{
return ServiceLocator.Get<T>();
}
// PLAYER & FOLLOWER SETTINGS
// Player settings
public float MoveSpeed => GetSettings<IPlayerFollowerSettings>()?.MoveSpeed ?? 5f;
public float StopDistance => GetSettings<IPlayerFollowerSettings>()?.StopDistance ?? 0.1f;
public bool UseRigidbody => GetSettings<IPlayerFollowerSettings>()?.UseRigidbody ?? true;
public GameSettings.HoldMovementMode DefaultHoldMovementMode =>
GetSettings<IPlayerFollowerSettings>()?.DefaultHoldMovementMode ?? GameSettings.HoldMovementMode.Pathfinding;
// Follower settings
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>
/// Returns the combination rule for two items, if any.
/// </summary>
public GameSettings.CombinationRule GetCombinationRule(PickupItemData item1, PickupItemData item2)
{
if (gameSettings == null || gameSettings.combinationRules == null) return null;
foreach (var rule in gameSettings.combinationRules)
var settings = GetSettings<IInteractionSettings>();
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)) ||
(PickupItemData.AreEquivalent(rule.itemA, item2) && PickupItemData.AreEquivalent(rule.itemB, item1)))
@@ -91,20 +155,23 @@ public class GameManager : MonoBehaviour
/// </summary>
public GameSettings.SlotItemConfig GetSlotItemConfig(PickupItemData slotItem)
{
if (gameSettings == null || gameSettings.slotItemConfigs == null || slotItem == null) return null;
foreach (var config in gameSettings.slotItemConfigs)
var settings = GetSettings<IInteractionSettings>();
if (settings == null || settings.SlotItemConfigs == null || slotItem == null) return null;
foreach (var config in settings.SlotItemConfigs)
{
if (PickupItemData.AreEquivalent(slotItem, config.slotItem))
return config;
}
return null;
}
// Add more accessors as needed
public float EndlessDescenderLerpSpeed => gameSettings != null ? gameSettings.endlessDescenderLerpSpeed : 12f;
public float EndlessDescenderMaxOffset => gameSettings != null ? gameSettings.endlessDescenderMaxOffset : 3f;
public float EndlessDescenderClampXMin => gameSettings != null ? gameSettings.endlessDescenderClampXMin : -5f;
public float EndlessDescenderClampXMax => gameSettings != null ? gameSettings.endlessDescenderClampXMax : 5f;
public float EndlessDescenderSpeedExponent => gameSettings != null ? gameSettings.endlessDescenderSpeedExponent : 2.5f;
public GameSettings.HoldMovementMode DefaultHoldMovementMode => gameSettings != null ? gameSettings.defaultHoldMovementMode : GameSettings.HoldMovementMode.Pathfinding;
public GameObject LevelSwitchMenuPrefab => gameSettings != null ? gameSettings.levelSwitchMenuPrefab : null;
// MINIGAME SETTINGS
// Endless Descender settings
public float EndlessDescenderLerpSpeed => GetSettings<IMinigameSettings>()?.EndlessDescenderLerpSpeed ?? 12f;
public float EndlessDescenderMaxOffset => GetSettings<IMinigameSettings>()?.EndlessDescenderMaxOffset ?? 3f;
public float EndlessDescenderClampXMin => GetSettings<IMinigameSettings>()?.EndlessDescenderClampXMin ?? -3.5f;
public float EndlessDescenderClampXMax => GetSettings<IMinigameSettings>()?.EndlessDescenderClampXMax ?? 3.5f;
public float EndlessDescenderSpeedExponent => GetSettings<IMinigameSettings>()?.EndlessDescenderSpeedExponent ?? 2.5f;
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e380783135324fcd925048783e01d691
timeCreated: 1758619858

View 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
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cd33ef6036eb49358acbbd50dfd9bb13
timeCreated: 1758619858

View 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);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ac22b092dc6f4db5b3dad35172b6e4c4
timeCreated: 1758619914

View 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;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0ce4dba7a1c54e73b1b3d7131a1c0570
timeCreated: 1758619927

View 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);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 32cd6d14d9304d5ba0fd590da1346654
timeCreated: 1758619904

View 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");
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 16cc39d2f99b4e7fa65c4a8b39f3e87c
timeCreated: 1758619866

View 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; }
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 54611ae012ab4455a53bd60961d9e7ea
timeCreated: 1758619892

View 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());
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4d212b25192045d198f2bf42ef74f278
timeCreated: 1758619879

View 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: []

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8f5195fb013895049a19488fd4d8f2a1
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View 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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a9569848f604a6540827d4d4bb0a35c2
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View 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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 35bfcff00faa72c4eb272a9e8288f965
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant: