# Apple Hills Settings System Centralized, designer-friendly configuration using `ScriptableObject` assets, with runtime access via `SettingsProvider` (Addressables-backed) and editor/live-preview access via `SettingsAccess`. This page follows the style of other updated docs (TOC, inline code, code-first usage, case studies). ## Table of Contents - [What This Solves](#what-this-solves) - [Architecture at a Glance](#architecture-at-a-glance) - [Quick Start (Code-First)](#quick-start-code-first) - [Get Settings at Runtime](#get-settings-at-runtime) - [Use Editor-Time Values via `SettingsAccess`](#use-editor-time-values-via-settingsaccess) - [Access Example Fields](#access-example-fields) - [Authoring in the Editor](#authoring-in-the-editor) - [Creating/Editing Settings Assets](#creatingediting-settings-assets) - [Addressables Keys & Loading](#addressables-keys--loading) - [Available Settings Types](#available-settings-types) - [Case Studies](#case-studies) - [Tune Interaction Distances](#tune-interaction-distances) - [Follower Handling & Movement](#follower-handling--movement) - [Diving Minigame Tuning](#diving-minigame-tuning) - [Troubleshooting / FAQ](#troubleshooting--faq) - [Paths & Namespaces](#paths--namespaces) - [Change Log](#change-log) ## What This Solves - Consistent, centralized configuration across gameplay systems. - Safe, designer-editable `ScriptableObject` assets with validation (`OnValidate`). - Simple, Addressables-based runtime loading and caching via `SettingsProvider`. - Editor-time overrides and scene gizmo feedback via `SettingsAccess` helpers. ## Architecture at a Glance - Base: `BaseSettings` (`ScriptableObject`) — common parent for all settings. Implements optional `OnValidate()`. - Access (runtime): `SettingsProvider` (singleton `MonoBehaviour`) — loads assets synchronously via Addressables at keys `Settings/` and caches them. - Access (editor/dev): `SettingsAccess` (static) — editor-friendly shim for reading selected values even when not in Play Mode, falling back to `GameManager` at runtime. - Contracts: `SettingsInterfaces` (`IPlayerFollowerSettings`, `IInteractionSettings`, `IDivingMinigameSettings`) used by systems to remain decoupled from concrete assets. - Editor tooling: `AppleHills/Settings Editor` — finds/creates assets under `Assets/Settings` and provides a tabbed UI. ## Quick Start (Code-First) ### Get Settings at Runtime ```csharp using AppleHills.Core.Settings; var playerFollower = SettingsProvider.Instance.GetSettings(); float speed = playerFollower.MoveSpeed; ``` Or fetch interaction settings once and reuse: ```csharp using AppleHills.Core.Settings; private IInteractionSettings _interaction; void Awake() { _interaction = SettingsProvider.Instance.GetSettings(); } void UseIt() { float stopDist = _interaction.PlayerStopDistance; } ``` ### Use Editor-Time Values via `SettingsAccess` For scene tools, gizmos, or editors that should reflect current settings outside Play Mode: ```csharp // Returns editor-sourced values in Edit Mode; GameManager-backed in Play Mode float stopDist = AppleHills.SettingsAccess.GetPlayerStopDistance(); float directStop = AppleHills.SettingsAccess.GetPlayerStopDistanceDirectInteraction(); float puzzleRange = AppleHills.SettingsAccess.GetPuzzlePromptRange(); ``` ### Access Example Fields ```csharp using AppleHills.Core.Settings; var pf = SettingsProvider.Instance.GetSettings(); // Player float moveSpeed = pf.MoveSpeed; float accel = pf.MaxAcceleration; bool useRb = pf.UseRigidbody; // Follower float followDist = pf.FollowDistance; float near = pf.ThresholdNear; var inter = SettingsProvider.Instance.GetSettings(); LayerMask interactMask = inter.InteractableLayerMask; GameObject pickupPrefab = inter.BasePickupPrefab; float promptRange = inter.DefaultPuzzlePromptRange; ``` ## Authoring in the Editor ### Creating/Editing Settings Assets - Open via menu: `AppleHills/Settings Editor`. - The window discovers all assets of type `BaseSettings` and provides tabbed editing for: - `PlayerFollowerSettings` - `InteractionSettings` - `DivingMinigameSettings` - If an asset is missing, the tool auto-creates it under `Assets/Settings/`: - `Assets/Settings/PlayerFollowerSettings.asset` - `Assets/Settings/InteractionSettings.asset` - `Assets/Settings/DivingMinigameSettings.asset` - Click “Save All” to persist and refresh editor providers/gizmos. ### Addressables Keys & Loading At runtime, `SettingsProvider` synchronously loads settings via Addressables with keys: - `Settings/PlayerFollowerSettings` - `Settings/InteractionSettings` - `Settings/DivingMinigameSettings` Ensure these assets are marked as Addressables with the exact keys above. The provider caches objects, so subsequent `GetSettings()` calls are fast. ## Available Settings Types - `PlayerFollowerSettings` (`IPlayerFollowerSettings`) - Player: `MoveSpeed`, `MaxAcceleration`, `StopDistance`, `UseRigidbody`, `DefaultHoldMovementMode`. - Follower: `FollowDistance`, `ManualMoveSmooth`, `ThresholdFar`, `ThresholdNear`, `StopThreshold`. - Backend: `FollowUpdateInterval`, `FollowerSpeedMultiplier`, `HeldIconDisplayHeight`. - `InteractionSettings` (`IInteractionSettings`) - Interactions: `PlayerStopDistance`, `PlayerStopDistanceDirectInteraction`, `FollowerPickupDelay`. - Input/Layering: `InteractableLayerMask`. - Prefabs: `BasePickupPrefab`, `LevelSwitchMenuPrefab`, `DefaultPuzzleIndicatorPrefab`. - Puzzle/UI: `DefaultPuzzlePromptRange`. - Items: `CombinationRules`, `SlotItemConfigs` plus helpers `GetCombinationRule(...)`, `GetSlotItemConfig(...)`. - `DivingMinigameSettings` (`IDivingMinigameSettings`) - Movement, spawning, scoring, surfacing, normalized movement, tile generation, obstacles, camera viewfinder settings, photo input mode (`PhotoInputModes`). ## Case Studies ### Tune Interaction Distances ```csharp using AppleHills.Core.Settings; public class InteractDistanceExample { private readonly IInteractionSettings _s = SettingsProvider.Instance.GetSettings(); public bool IsInRange(float dist) => dist <= _s.PlayerStopDistance; } ``` ### Follower Handling & Movement ```csharp using AppleHills.Core.Settings; public class FollowerMover { private readonly IPlayerFollowerSettings _pf = SettingsProvider.Instance.GetSettings(); public float TargetSpeed(float error) => Mathf.Clamp(error * _pf.FollowerSpeedMultiplier, 0f, _pf.MoveSpeed); } ``` ### Diving Minigame Tuning ```csharp using AppleHills.Core.Settings; public class SpawnController { private readonly IDivingMinigameSettings _m = SettingsProvider.Instance.GetSettings(); public float NextCooldown(float baseCooldown) => Mathf.Clamp(baseCooldown + Random.Range(-_m.ObstacleSpawnIntervalVariation, _m.ObstacleSpawnIntervalVariation), 0.1f, 99); } ``` ## Troubleshooting / FAQ - Settings return null at runtime: - Ensure assets are Addressable with keys `Settings/` and Addressables are initialized before first access. - Editor changes don’t reflect in scene gizmos: - Click “Save All” in `AppleHills/Settings Editor`; the editor provider refresh call updates views. - Which API to use: `SettingsProvider` vs `SettingsAccess`? - Use `SettingsProvider` in runtime code. Use `SettingsAccess` in editor tools/gizmos or shared code that runs both in Edit and Play Modes. ## Paths & Namespaces - Scripts: `Assets/Scripts/Core/Settings/` - `BaseSettings.cs` - `SettingsInterfaces.cs` - `SettingsProvider.cs` - `PlayerFollowerSettings.cs` - `InteractionSettings.cs` - `DivingMinigameSettings.cs` - Editor tooling: `Assets/Editor/SettingsEditorWindow.cs` - Editor-time facade: `Assets/Scripts/Core/SettingsAccess.cs` - Namespaces: - Runtime: `AppleHills.Core.Settings` - Editor window: `AppleHills.Core.Settings.Editor` - Facade: `AppleHills` ## Change Log - v1.1: New page with TOC, code-first usage, authoring workflow, Addressables keys, case studies, troubleshooting, and paths.