From f901f70c1011aa979021e26c151620c6531ba5b0 Mon Sep 17 00:00:00 2001 From: Savya Bikram Shah Date: Tue, 26 May 2026 16:47:16 +0545 Subject: [PATCH] Initial Push --- .DS_Store | Bin 0 -> 8196 bytes .gitignore | 107 ++ .idea/.idea.Colorbook/.idea/.gitignore | 15 + .idea/.idea.Colorbook/.idea/encodings.xml | 7 + .idea/.idea.Colorbook/.idea/indexLayout.xml | 8 + Assets/.DS_Store | Bin 0 -> 6148 bytes Assets/Darkmatter.meta | 8 + Assets/Darkmatter/.DS_Store | Bin 0 -> 6148 bytes Assets/Darkmatter/Code.meta | 8 + Assets/Darkmatter/Code/.DS_Store | Bin 0 -> 6148 bytes Assets/Darkmatter/Code/Core.meta | 8 + .../Darkmatter/Code/Core/Compatibility.meta | 8 + .../Code/Core/Compatibility/IsExternalInit.cs | 9 + .../Core/Compatibility/IsExternalInit.cs.meta | 2 + Assets/Darkmatter/Code/Core/Contracts.meta | 8 + .../Code/Core/Contracts/Services.meta | 8 + .../Code/Core/Contracts/Services/Assets.meta | 8 + .../Services/Assets/IAssetProviderService.cs | 46 + .../Assets/IAssetProviderService.cs.meta | 2 + .../Code/Core/Contracts/Services/Audio.meta | 8 + .../Contracts/Services/Audio/IAudioService.cs | 23 + .../Services/Audio/IAudioService.cs.meta | 3 + .../Contracts/Services/Audio/ISfxPlayer.cs | 14 + .../Services/Audio/ISfxPlayer.cs.meta | 2 + .../Code/Core/Contracts/Services/Scenes.meta | 3 + .../Services/Scenes/ISceneService.cs | 27 + .../Services/Scenes/ISceneService.cs.meta | 3 + Assets/Darkmatter/Code/Core/Core.asmdef | 16 + Assets/Darkmatter/Code/Core/Core.asmdef.meta | 7 + Assets/Darkmatter/Code/Core/Data.meta | 8 + Assets/Darkmatter/Code/Core/Data/Dynamic.meta | 8 + .../Code/Core/Data/Dynamic/Services.meta | 8 + .../Core/Data/Dynamic/Services/Audio.meta | 8 + .../Dynamic/Services/Audio/AudioHandle.cs | 17 + .../Services/Audio/AudioHandle.cs.meta | 3 + .../Dynamic/Services/Audio/AudioRequest.cs | 36 + .../Services/Audio/AudioRequest.cs.meta | 3 + Assets/Darkmatter/Code/Core/Data/Static.meta | 8 + .../Code/Core/Data/Static/Services.meta | 8 + .../Code/Core/Data/Static/Services/Audio.meta | 8 + .../Static/Services/Audio/SfxCatalogSO.cs | 44 + .../Services/Audio/SfxCatalogSO.cs.meta | 2 + Assets/Darkmatter/Code/Core/Enums.meta | 8 + .../Darkmatter/Code/Core/Enums/Services.meta | 8 + .../Code/Core/Enums/Services/Audio.meta | 8 + .../Core/Enums/Services/Audio/AudioChannel.cs | 18 + .../Enums/Services/Audio/AudioChannel.cs.meta | 3 + .../Enums/Services/Audio/AudioPlayMode.cs | 8 + .../Services/Audio/AudioPlayMode.cs.meta | 3 + .../Code/Core/Enums/Services/Audio/SfxId.cs | 16 + .../Core/Enums/Services/Audio/SfxId.cs.meta | 2 + .../Code/Core/Enums/Services/Scenes.meta | 8 + .../Core/Enums/Services/Scenes/GameScene.cs | 11 + .../Enums/Services/Scenes/GameScene.cs.meta | 3 + Assets/Darkmatter/Code/Libs.meta | 8 + Assets/Darkmatter/Code/Libs/FSM.meta | 8 + Assets/Darkmatter/Code/Libs/FSM/Docs.meta | 8 + .../Darkmatter/Code/Libs/FSM/Docs/FSMLib.md | 19 + .../Code/Libs/FSM/Docs/FSMLib.md.meta | 7 + Assets/Darkmatter/Code/Libs/FSM/IState.cs | 9 + .../Darkmatter/Code/Libs/FSM/IState.cs.meta | 2 + .../Darkmatter/Code/Libs/FSM/Libs.FSM.asmdef | 14 + .../Code/Libs/FSM/Libs.FSM.asmdef.meta | 7 + Assets/Darkmatter/Code/Libs/FSM/State.cs | 15 + Assets/Darkmatter/Code/Libs/FSM/State.cs.meta | 2 + .../Darkmatter/Code/Libs/FSM/StateMachine.cs | 26 + .../Code/Libs/FSM/StateMachine.cs.meta | 2 + Assets/Darkmatter/Code/Libs/Installers.meta | 8 + .../Darkmatter/Code/Libs/Installers/Docs.meta | 8 + .../Libs/Installers/Docs/InstallersLib.md | 19 + .../Installers/Docs/InstallersLib.md.meta | 7 + .../Code/Libs/Installers/IServiceModule.cs | 9 + .../Libs/Installers/IServiceModule.cs.meta | 2 + .../Libs/Installers/Libs.Installers.asmdef | 16 + .../Installers/Libs.Installers.asmdef.meta | 7 + Assets/Darkmatter/Code/Libs/Observer.meta | 8 + .../Darkmatter/Code/Libs/Observer/Docs.meta | 8 + .../Code/Libs/Observer/Docs/ObserverLib.md | 20 + .../Libs/Observer/Docs/ObserverLib.md.meta | 7 + .../Darkmatter/Code/Libs/Observer/EventBus.cs | 75 ++ .../Code/Libs/Observer/EventBus.cs.meta | 2 + .../Code/Libs/Observer/IEventBus.cs | 18 + .../Code/Libs/Observer/IEventBus.cs.meta | 2 + .../Code/Libs/Observer/Libs.Observer.asmdef | 16 + .../Libs/Observer/Libs.Observer.asmdef.meta | 7 + Assets/Darkmatter/Code/Libs/PlayerPrefs.meta | 8 + .../Code/Libs/PlayerPrefs/Docs.meta | 8 + ...otectedPlayerPrefsToolkit_Documentation.md | 175 +++ ...edPlayerPrefsToolkit_Documentation.md.meta | 7 + ...tectedPlayerPrefsToolkit_Documentation.pdf | 156 +++ ...dPlayerPrefsToolkit_Documentation.pdf.meta | 7 + .../Code/Libs/PlayerPrefs/Editor.meta | 8 + .../Editor/Libs.PlayerPrefs.Editor.asmdef | 18 + .../Libs.PlayerPrefs.Editor.asmdef.meta | 7 + .../Editor/PlayerPrefsEditorWindow.cs | 559 +++++++++ .../Editor/PlayerPrefsEditorWindow.cs.meta | 2 + ...rotectedPlayerPrefsGettingStartedWindow.cs | 160 +++ ...tedPlayerPrefsGettingStartedWindow.cs.meta | 2 + .../ProtectedPlayerPrefsSettingsUtility.cs | 89 ++ ...rotectedPlayerPrefsSettingsUtility.cs.meta | 2 + .../ProtectedPlayerPrefsSetupBootstrap.cs | 39 + ...ProtectedPlayerPrefsSetupBootstrap.cs.meta | 2 + .../Code/Libs/PlayerPrefs/Runtime.meta | 8 + .../Runtime/Libs.PlayerPrefs.asmdef | 16 + .../Runtime/Libs.PlayerPrefs.asmdef.meta | 7 + .../PlayerPrefs/Runtime/LocalWriteTracker.cs | 46 + .../Runtime/LocalWriteTracker.cs.meta | 2 + .../PlayerPrefs/Runtime/PendingWriteResync.cs | 56 + .../Runtime/PendingWriteResync.cs.meta | 2 + .../Runtime/PlayerPrefsKeyRegistry.cs | 48 + .../Runtime/PlayerPrefsKeyRegistry.cs.meta | 2 + .../PlayerPrefs/Runtime/PlayerPrefsKeys.cs | 51 + .../Runtime/PlayerPrefsKeys.cs.meta | 2 + .../Runtime/ProtectedPlayerPrefs.cs | 354 ++++++ .../Runtime/ProtectedPlayerPrefs.cs.meta | 2 + .../Runtime/ProtectedPlayerPrefsSettings.cs | 21 + .../ProtectedPlayerPrefsSettings.cs.meta | 2 + Assets/Darkmatter/Code/Libs/UI.meta | 8 + Assets/Darkmatter/Code/Libs/UI/Docs.meta | 8 + Assets/Darkmatter/Code/Libs/UI/Docs/UILib.md | 27 + .../Code/Libs/UI/Docs/UILib.md.meta | 7 + Assets/Darkmatter/Code/Libs/UI/Libs.UI.asmdef | 14 + .../Code/Libs/UI/Libs.UI.asmdef.meta | 7 + .../Darkmatter/Code/Libs/UI/ToggleButton.cs | 69 ++ .../Code/Libs/UI/ToggleButton.cs.meta | 2 + .../Code/Libs/UI/ToggleButtonGroup.cs | 110 ++ .../Code/Libs/UI/ToggleButtonGroup.cs.meta | 3 + Assets/Darkmatter/Code/Services.meta | 8 + .../Darkmatter/Code/Services/Analytics.meta | 8 + .../Code/Services/Analytics/Installers.meta | 8 + .../Installers/AnalyticsServiceModule.cs | 17 + .../Installers/AnalyticsServiceModule.cs.meta | 2 + .../Analytics/Services.Analytics.asmdef | 21 + .../Analytics/Services.Analytics.asmdef.meta | 7 + .../Code/Services/Analytics/Systems.meta | 8 + .../Systems/FirebaseAnalyticsSystem.cs | 46 + .../Systems/FirebaseAnalyticsSystem.cs.meta | 2 + Assets/Darkmatter/Code/Services/Assets.meta | 8 + .../Assets/AddressableAssetProviderService.cs | 524 ++++++++ .../AddressableAssetProviderService.cs.meta | 2 + .../Assets/AddressableLoadHandleTracker.cs | 118 ++ .../AddressableLoadHandleTracker.cs.meta | 2 + .../Darkmatter/Code/Services/Assets/Docs.meta | 8 + .../Services/Assets/Docs/AssetsService.md | 17 + .../Assets/Docs/AssetsService.md.meta | 7 + .../Services/Assets/Services.Assets.asmdef | 20 + .../Assets/Services.Assets.asmdef.meta | 7 + Assets/Darkmatter/Code/Services/Audio.meta | 8 + .../Code/Services/Audio/AudioService.cs | 768 ++++++++++++ .../Code/Services/Audio/AudioService.cs.meta | 2 + .../Darkmatter/Code/Services/Audio/Docs.meta | 8 + .../Code/Services/Audio/Docs/AudioService.md | 32 + .../Services/Audio/Docs/AudioService.md.meta | 7 + .../Code/Services/Audio/Services.Audio.asmdef | 19 + .../Services/Audio/Services.Audio.asmdef.meta | 7 + .../Code/Services/Audio/SfxPlayer.cs | 50 + .../Code/Services/Audio/SfxPlayer.cs.meta | 2 + Assets/Darkmatter/Code/Services/Scenes.meta | 3 + .../Darkmatter/Code/Services/Scenes/Docs.meta | 8 + .../Services/Scenes/Docs/ScenesService.md | 16 + .../Scenes/Docs/ScenesService.md.meta | 7 + .../Code/Services/Scenes/SceneService.cs | 163 +++ .../Code/Services/Scenes/SceneService.cs.meta | 3 + .../Services/Scenes/Services.Scenes.asmdef | 20 + .../Scenes/Services.Scenes.asmdef.meta | 7 + Assets/Darkmatter/Data.meta | 8 + Assets/Darkmatter/Data/Inputs.meta | 8 + .../Inputs/InputSystem_Actions.inputactions | 1057 +++++++++++++++++ .../InputSystem_Actions.inputactions.meta | 14 + Assets/Darkmatter/Data/Settings.meta | 8 + .../Darkmatter/Data/Settings/Persistance.meta | 8 + .../Data/Settings/Persistance/Resources.meta | 8 + .../ProtectedPlayerPrefsSettings.asset | 15 + .../ProtectedPlayerPrefsSettings.asset.meta | 8 + .../Darkmatter/Data/Settings/Rendering.meta | 8 + .../Rendering/DefaultVolumeProfile.asset | 798 +++++++++++++ .../Rendering/DefaultVolumeProfile.asset.meta | 8 + .../Lit2DSceneTemplate.scenetemplate | 71 ++ .../Lit2DSceneTemplate.scenetemplate.meta | 8 + .../Data/Settings/Rendering/Renderer2D.asset | 69 ++ .../Settings/Rendering/Renderer2D.asset.meta | 8 + .../Data/Settings/Rendering/UniversalRP.asset | 143 +++ .../Settings/Rendering/UniversalRP.asset.meta | 8 + ...niversalRenderPipelineGlobalSettings.asset | 436 +++++++ ...salRenderPipelineGlobalSettings.asset.meta | 8 + Assets/Darkmatter/Data/Settings/Scenes.meta | 8 + .../Settings/Scenes/URP2DSceneTemplate.unity | 350 ++++++ .../Scenes/URP2DSceneTemplate.unity.meta | 7 + Assets/Darkmatter/Scenes.meta | 8 + Assets/Darkmatter/Scenes/SampleScene.unity | 352 ++++++ .../Darkmatter/Scenes/SampleScene.unity.meta | 7 + Packages/manifest.json | 71 ++ Packages/packages-lock.json | 624 ++++++++++ ProjectSettings/AudioManager.asset | 19 + ProjectSettings/ClusterInputManager.asset | 6 + ProjectSettings/DynamicsManager.asset | 36 + ProjectSettings/EditorBuildSettings.asset | 12 + ProjectSettings/EditorSettings.asset | 52 + ProjectSettings/GraphicsSettings.asset | 69 ++ ProjectSettings/InputManager.asset | 487 ++++++++ ProjectSettings/MemorySettings.asset | 35 + ProjectSettings/MultiplayerManager.asset | 7 + ProjectSettings/NavMeshAreas.asset | 91 ++ ProjectSettings/NetworkManager.asset | 8 + ProjectSettings/PackageManagerSettings.asset | 54 + ProjectSettings/Physics2DSettings.asset | 56 + ProjectSettings/PresetManager.asset | 7 + ProjectSettings/ProjectSettings.asset | 888 ++++++++++++++ ProjectSettings/ProjectVersion.txt | 2 + ProjectSettings/QualitySettings.asset | 336 ++++++ ProjectSettings/SceneTemplateSettings.json | 121 ++ ProjectSettings/ShaderGraphSettings.asset | 19 + ProjectSettings/TagManager.asset | 43 + ProjectSettings/TimeManager.asset | 9 + ProjectSettings/URPProjectSettings.asset | 16 + ProjectSettings/UnityConnectSettings.asset | 40 + ProjectSettings/VFXManager.asset | 12 + ProjectSettings/VersionControlSettings.asset | 7 + ProjectSettings/XRSettings.asset | 10 + 219 files changed, 11642 insertions(+) create mode 100644 .DS_Store create mode 100644 .gitignore create mode 100644 .idea/.idea.Colorbook/.idea/.gitignore create mode 100644 .idea/.idea.Colorbook/.idea/encodings.xml create mode 100644 .idea/.idea.Colorbook/.idea/indexLayout.xml create mode 100644 Assets/.DS_Store create mode 100644 Assets/Darkmatter.meta create mode 100644 Assets/Darkmatter/.DS_Store create mode 100644 Assets/Darkmatter/Code.meta create mode 100644 Assets/Darkmatter/Code/.DS_Store create mode 100644 Assets/Darkmatter/Code/Core.meta create mode 100644 Assets/Darkmatter/Code/Core/Compatibility.meta create mode 100644 Assets/Darkmatter/Code/Core/Compatibility/IsExternalInit.cs create mode 100644 Assets/Darkmatter/Code/Core/Compatibility/IsExternalInit.cs.meta create mode 100644 Assets/Darkmatter/Code/Core/Contracts.meta create mode 100644 Assets/Darkmatter/Code/Core/Contracts/Services.meta create mode 100644 Assets/Darkmatter/Code/Core/Contracts/Services/Assets.meta create mode 100644 Assets/Darkmatter/Code/Core/Contracts/Services/Assets/IAssetProviderService.cs create mode 100644 Assets/Darkmatter/Code/Core/Contracts/Services/Assets/IAssetProviderService.cs.meta create mode 100644 Assets/Darkmatter/Code/Core/Contracts/Services/Audio.meta create mode 100644 Assets/Darkmatter/Code/Core/Contracts/Services/Audio/IAudioService.cs create mode 100644 Assets/Darkmatter/Code/Core/Contracts/Services/Audio/IAudioService.cs.meta create mode 100644 Assets/Darkmatter/Code/Core/Contracts/Services/Audio/ISfxPlayer.cs create mode 100644 Assets/Darkmatter/Code/Core/Contracts/Services/Audio/ISfxPlayer.cs.meta create mode 100644 Assets/Darkmatter/Code/Core/Contracts/Services/Scenes.meta create mode 100644 Assets/Darkmatter/Code/Core/Contracts/Services/Scenes/ISceneService.cs create mode 100644 Assets/Darkmatter/Code/Core/Contracts/Services/Scenes/ISceneService.cs.meta create mode 100644 Assets/Darkmatter/Code/Core/Core.asmdef create mode 100644 Assets/Darkmatter/Code/Core/Core.asmdef.meta create mode 100644 Assets/Darkmatter/Code/Core/Data.meta create mode 100644 Assets/Darkmatter/Code/Core/Data/Dynamic.meta create mode 100644 Assets/Darkmatter/Code/Core/Data/Dynamic/Services.meta create mode 100644 Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio.meta create mode 100644 Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio/AudioHandle.cs create mode 100644 Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio/AudioHandle.cs.meta create mode 100644 Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio/AudioRequest.cs create mode 100644 Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio/AudioRequest.cs.meta create mode 100644 Assets/Darkmatter/Code/Core/Data/Static.meta create mode 100644 Assets/Darkmatter/Code/Core/Data/Static/Services.meta create mode 100644 Assets/Darkmatter/Code/Core/Data/Static/Services/Audio.meta create mode 100644 Assets/Darkmatter/Code/Core/Data/Static/Services/Audio/SfxCatalogSO.cs create mode 100644 Assets/Darkmatter/Code/Core/Data/Static/Services/Audio/SfxCatalogSO.cs.meta create mode 100644 Assets/Darkmatter/Code/Core/Enums.meta create mode 100644 Assets/Darkmatter/Code/Core/Enums/Services.meta create mode 100644 Assets/Darkmatter/Code/Core/Enums/Services/Audio.meta create mode 100644 Assets/Darkmatter/Code/Core/Enums/Services/Audio/AudioChannel.cs create mode 100644 Assets/Darkmatter/Code/Core/Enums/Services/Audio/AudioChannel.cs.meta create mode 100644 Assets/Darkmatter/Code/Core/Enums/Services/Audio/AudioPlayMode.cs create mode 100644 Assets/Darkmatter/Code/Core/Enums/Services/Audio/AudioPlayMode.cs.meta create mode 100644 Assets/Darkmatter/Code/Core/Enums/Services/Audio/SfxId.cs create mode 100644 Assets/Darkmatter/Code/Core/Enums/Services/Audio/SfxId.cs.meta create mode 100644 Assets/Darkmatter/Code/Core/Enums/Services/Scenes.meta create mode 100644 Assets/Darkmatter/Code/Core/Enums/Services/Scenes/GameScene.cs create mode 100644 Assets/Darkmatter/Code/Core/Enums/Services/Scenes/GameScene.cs.meta create mode 100644 Assets/Darkmatter/Code/Libs.meta create mode 100644 Assets/Darkmatter/Code/Libs/FSM.meta create mode 100644 Assets/Darkmatter/Code/Libs/FSM/Docs.meta create mode 100644 Assets/Darkmatter/Code/Libs/FSM/Docs/FSMLib.md create mode 100644 Assets/Darkmatter/Code/Libs/FSM/Docs/FSMLib.md.meta create mode 100644 Assets/Darkmatter/Code/Libs/FSM/IState.cs create mode 100644 Assets/Darkmatter/Code/Libs/FSM/IState.cs.meta create mode 100644 Assets/Darkmatter/Code/Libs/FSM/Libs.FSM.asmdef create mode 100644 Assets/Darkmatter/Code/Libs/FSM/Libs.FSM.asmdef.meta create mode 100644 Assets/Darkmatter/Code/Libs/FSM/State.cs create mode 100644 Assets/Darkmatter/Code/Libs/FSM/State.cs.meta create mode 100644 Assets/Darkmatter/Code/Libs/FSM/StateMachine.cs create mode 100644 Assets/Darkmatter/Code/Libs/FSM/StateMachine.cs.meta create mode 100644 Assets/Darkmatter/Code/Libs/Installers.meta create mode 100644 Assets/Darkmatter/Code/Libs/Installers/Docs.meta create mode 100644 Assets/Darkmatter/Code/Libs/Installers/Docs/InstallersLib.md create mode 100644 Assets/Darkmatter/Code/Libs/Installers/Docs/InstallersLib.md.meta create mode 100644 Assets/Darkmatter/Code/Libs/Installers/IServiceModule.cs create mode 100644 Assets/Darkmatter/Code/Libs/Installers/IServiceModule.cs.meta create mode 100644 Assets/Darkmatter/Code/Libs/Installers/Libs.Installers.asmdef create mode 100644 Assets/Darkmatter/Code/Libs/Installers/Libs.Installers.asmdef.meta create mode 100644 Assets/Darkmatter/Code/Libs/Observer.meta create mode 100644 Assets/Darkmatter/Code/Libs/Observer/Docs.meta create mode 100644 Assets/Darkmatter/Code/Libs/Observer/Docs/ObserverLib.md create mode 100644 Assets/Darkmatter/Code/Libs/Observer/Docs/ObserverLib.md.meta create mode 100644 Assets/Darkmatter/Code/Libs/Observer/EventBus.cs create mode 100644 Assets/Darkmatter/Code/Libs/Observer/EventBus.cs.meta create mode 100644 Assets/Darkmatter/Code/Libs/Observer/IEventBus.cs create mode 100644 Assets/Darkmatter/Code/Libs/Observer/IEventBus.cs.meta create mode 100644 Assets/Darkmatter/Code/Libs/Observer/Libs.Observer.asmdef create mode 100644 Assets/Darkmatter/Code/Libs/Observer/Libs.Observer.asmdef.meta create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs.meta create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs.meta create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs/ProtectedPlayerPrefsToolkit_Documentation.md create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs/ProtectedPlayerPrefsToolkit_Documentation.md.meta create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs/ProtectedPlayerPrefsToolkit_Documentation.pdf create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs/ProtectedPlayerPrefsToolkit_Documentation.pdf.meta create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor.meta create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/Libs.PlayerPrefs.Editor.asmdef create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/Libs.PlayerPrefs.Editor.asmdef.meta create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/PlayerPrefsEditorWindow.cs create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/PlayerPrefsEditorWindow.cs.meta create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsGettingStartedWindow.cs create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsGettingStartedWindow.cs.meta create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsSettingsUtility.cs create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsSettingsUtility.cs.meta create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsSetupBootstrap.cs create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsSetupBootstrap.cs.meta create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime.meta create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/Libs.PlayerPrefs.asmdef create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/Libs.PlayerPrefs.asmdef.meta create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/LocalWriteTracker.cs create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/LocalWriteTracker.cs.meta create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PendingWriteResync.cs create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PendingWriteResync.cs.meta create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PlayerPrefsKeyRegistry.cs create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PlayerPrefsKeyRegistry.cs.meta create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PlayerPrefsKeys.cs create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PlayerPrefsKeys.cs.meta create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/ProtectedPlayerPrefs.cs create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/ProtectedPlayerPrefs.cs.meta create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/ProtectedPlayerPrefsSettings.cs create mode 100644 Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/ProtectedPlayerPrefsSettings.cs.meta create mode 100644 Assets/Darkmatter/Code/Libs/UI.meta create mode 100644 Assets/Darkmatter/Code/Libs/UI/Docs.meta create mode 100644 Assets/Darkmatter/Code/Libs/UI/Docs/UILib.md create mode 100644 Assets/Darkmatter/Code/Libs/UI/Docs/UILib.md.meta create mode 100644 Assets/Darkmatter/Code/Libs/UI/Libs.UI.asmdef create mode 100644 Assets/Darkmatter/Code/Libs/UI/Libs.UI.asmdef.meta create mode 100644 Assets/Darkmatter/Code/Libs/UI/ToggleButton.cs create mode 100644 Assets/Darkmatter/Code/Libs/UI/ToggleButton.cs.meta create mode 100644 Assets/Darkmatter/Code/Libs/UI/ToggleButtonGroup.cs create mode 100644 Assets/Darkmatter/Code/Libs/UI/ToggleButtonGroup.cs.meta create mode 100644 Assets/Darkmatter/Code/Services.meta create mode 100644 Assets/Darkmatter/Code/Services/Analytics.meta create mode 100644 Assets/Darkmatter/Code/Services/Analytics/Installers.meta create mode 100644 Assets/Darkmatter/Code/Services/Analytics/Installers/AnalyticsServiceModule.cs create mode 100644 Assets/Darkmatter/Code/Services/Analytics/Installers/AnalyticsServiceModule.cs.meta create mode 100644 Assets/Darkmatter/Code/Services/Analytics/Services.Analytics.asmdef create mode 100644 Assets/Darkmatter/Code/Services/Analytics/Services.Analytics.asmdef.meta create mode 100644 Assets/Darkmatter/Code/Services/Analytics/Systems.meta create mode 100644 Assets/Darkmatter/Code/Services/Analytics/Systems/FirebaseAnalyticsSystem.cs create mode 100644 Assets/Darkmatter/Code/Services/Analytics/Systems/FirebaseAnalyticsSystem.cs.meta create mode 100644 Assets/Darkmatter/Code/Services/Assets.meta create mode 100644 Assets/Darkmatter/Code/Services/Assets/AddressableAssetProviderService.cs create mode 100644 Assets/Darkmatter/Code/Services/Assets/AddressableAssetProviderService.cs.meta create mode 100644 Assets/Darkmatter/Code/Services/Assets/AddressableLoadHandleTracker.cs create mode 100644 Assets/Darkmatter/Code/Services/Assets/AddressableLoadHandleTracker.cs.meta create mode 100644 Assets/Darkmatter/Code/Services/Assets/Docs.meta create mode 100644 Assets/Darkmatter/Code/Services/Assets/Docs/AssetsService.md create mode 100644 Assets/Darkmatter/Code/Services/Assets/Docs/AssetsService.md.meta create mode 100644 Assets/Darkmatter/Code/Services/Assets/Services.Assets.asmdef create mode 100644 Assets/Darkmatter/Code/Services/Assets/Services.Assets.asmdef.meta create mode 100644 Assets/Darkmatter/Code/Services/Audio.meta create mode 100644 Assets/Darkmatter/Code/Services/Audio/AudioService.cs create mode 100644 Assets/Darkmatter/Code/Services/Audio/AudioService.cs.meta create mode 100644 Assets/Darkmatter/Code/Services/Audio/Docs.meta create mode 100644 Assets/Darkmatter/Code/Services/Audio/Docs/AudioService.md create mode 100644 Assets/Darkmatter/Code/Services/Audio/Docs/AudioService.md.meta create mode 100644 Assets/Darkmatter/Code/Services/Audio/Services.Audio.asmdef create mode 100644 Assets/Darkmatter/Code/Services/Audio/Services.Audio.asmdef.meta create mode 100644 Assets/Darkmatter/Code/Services/Audio/SfxPlayer.cs create mode 100644 Assets/Darkmatter/Code/Services/Audio/SfxPlayer.cs.meta create mode 100644 Assets/Darkmatter/Code/Services/Scenes.meta create mode 100644 Assets/Darkmatter/Code/Services/Scenes/Docs.meta create mode 100644 Assets/Darkmatter/Code/Services/Scenes/Docs/ScenesService.md create mode 100644 Assets/Darkmatter/Code/Services/Scenes/Docs/ScenesService.md.meta create mode 100644 Assets/Darkmatter/Code/Services/Scenes/SceneService.cs create mode 100644 Assets/Darkmatter/Code/Services/Scenes/SceneService.cs.meta create mode 100644 Assets/Darkmatter/Code/Services/Scenes/Services.Scenes.asmdef create mode 100644 Assets/Darkmatter/Code/Services/Scenes/Services.Scenes.asmdef.meta create mode 100644 Assets/Darkmatter/Data.meta create mode 100644 Assets/Darkmatter/Data/Inputs.meta create mode 100644 Assets/Darkmatter/Data/Inputs/InputSystem_Actions.inputactions create mode 100644 Assets/Darkmatter/Data/Inputs/InputSystem_Actions.inputactions.meta create mode 100644 Assets/Darkmatter/Data/Settings.meta create mode 100644 Assets/Darkmatter/Data/Settings/Persistance.meta create mode 100644 Assets/Darkmatter/Data/Settings/Persistance/Resources.meta create mode 100644 Assets/Darkmatter/Data/Settings/Persistance/Resources/ProtectedPlayerPrefsSettings.asset create mode 100644 Assets/Darkmatter/Data/Settings/Persistance/Resources/ProtectedPlayerPrefsSettings.asset.meta create mode 100644 Assets/Darkmatter/Data/Settings/Rendering.meta create mode 100644 Assets/Darkmatter/Data/Settings/Rendering/DefaultVolumeProfile.asset create mode 100644 Assets/Darkmatter/Data/Settings/Rendering/DefaultVolumeProfile.asset.meta create mode 100644 Assets/Darkmatter/Data/Settings/Rendering/Lit2DSceneTemplate.scenetemplate create mode 100644 Assets/Darkmatter/Data/Settings/Rendering/Lit2DSceneTemplate.scenetemplate.meta create mode 100644 Assets/Darkmatter/Data/Settings/Rendering/Renderer2D.asset create mode 100644 Assets/Darkmatter/Data/Settings/Rendering/Renderer2D.asset.meta create mode 100644 Assets/Darkmatter/Data/Settings/Rendering/UniversalRP.asset create mode 100644 Assets/Darkmatter/Data/Settings/Rendering/UniversalRP.asset.meta create mode 100644 Assets/Darkmatter/Data/Settings/Rendering/UniversalRenderPipelineGlobalSettings.asset create mode 100644 Assets/Darkmatter/Data/Settings/Rendering/UniversalRenderPipelineGlobalSettings.asset.meta create mode 100644 Assets/Darkmatter/Data/Settings/Scenes.meta create mode 100644 Assets/Darkmatter/Data/Settings/Scenes/URP2DSceneTemplate.unity create mode 100644 Assets/Darkmatter/Data/Settings/Scenes/URP2DSceneTemplate.unity.meta create mode 100644 Assets/Darkmatter/Scenes.meta create mode 100644 Assets/Darkmatter/Scenes/SampleScene.unity create mode 100644 Assets/Darkmatter/Scenes/SampleScene.unity.meta create mode 100644 Packages/manifest.json create mode 100644 Packages/packages-lock.json create mode 100644 ProjectSettings/AudioManager.asset create mode 100644 ProjectSettings/ClusterInputManager.asset create mode 100644 ProjectSettings/DynamicsManager.asset create mode 100644 ProjectSettings/EditorBuildSettings.asset create mode 100644 ProjectSettings/EditorSettings.asset create mode 100644 ProjectSettings/GraphicsSettings.asset create mode 100644 ProjectSettings/InputManager.asset create mode 100644 ProjectSettings/MemorySettings.asset create mode 100644 ProjectSettings/MultiplayerManager.asset create mode 100644 ProjectSettings/NavMeshAreas.asset create mode 100644 ProjectSettings/NetworkManager.asset create mode 100644 ProjectSettings/PackageManagerSettings.asset create mode 100644 ProjectSettings/Physics2DSettings.asset create mode 100644 ProjectSettings/PresetManager.asset create mode 100644 ProjectSettings/ProjectSettings.asset create mode 100644 ProjectSettings/ProjectVersion.txt create mode 100644 ProjectSettings/QualitySettings.asset create mode 100644 ProjectSettings/SceneTemplateSettings.json create mode 100644 ProjectSettings/ShaderGraphSettings.asset create mode 100644 ProjectSettings/TagManager.asset create mode 100644 ProjectSettings/TimeManager.asset create mode 100644 ProjectSettings/URPProjectSettings.asset create mode 100644 ProjectSettings/UnityConnectSettings.asset create mode 100644 ProjectSettings/VFXManager.asset create mode 100644 ProjectSettings/VersionControlSettings.asset create mode 100644 ProjectSettings/XRSettings.asset diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..06179f8cec29604e75fb7fb05abaa48939fc5242 GIT binary patch literal 8196 zcmeHML2nyH6n^8Hc1@bZNo^+)6j}8JscA_YMWyPYj?;oHK(VrEn<#0WU3=qhv)(bg z>jXE71F6VrpfkG886Phg@E=6Dx)^Zet6?78tgG z$lWi~GWmF{zWiOMr(}>vEoAfesZKTp#PRz&)xg_AkJGcV!)vC)O`wQ_S32-w7`=&8IYi#dY0vG zH9Wh%y1VOJ!A7LNDORg_+;J-0w*#BIo7-~rz-pG=U5*vS4pv)Y%718iKIo9l#-`zU zhTE`8oyU%0TF$Cl;z7Wh8#c5MJC{r9Eu&_;jl$i3LQ|#+#Sga0f%m##xSCVOQBaTVl6Z zku9?|w#9as!JdWkiJqe`D?CM*k4~SX_jS*8xZA+EkQv99HI8p=;v|}AIql&@`WSHs z&cwIij-JH}^f}J32|019JN?`Vah*oFCl$93^iQDY7o*O7!W)pzMWoB*Vt)Zvb?{hN zTVS3ULlS=tU}Yj$tJuGYQy%Thb_9-$Mc+qa(M$xVf}I%nPAQNos21&x-W7>x6h-^s z70_NWYRc#p#h!>@KcMm`Ycb*FsB99loEn1>Qu;T_r$KK6Uf4t1fc^s!ReChaKPl~m zh!5Txys3i*cx-rgcs1d}sPvrV7hba=jn$yjG9<-2(UBui zec}z^6P<&XP-aE`fB)?7|B@+gVhh9;crz`)lK1p`CFs`sqhwIc1P1b`JE)=vzHUgR t2pYj6#$`GVdi)PV^z&-2sAxB&m_hm9KLm)oA-@0P`~M_MeJk(({{V0K*LVN` literal 0 HcmV?d00001 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7b84b9c --- /dev/null +++ b/.gitignore @@ -0,0 +1,107 @@ +# This .gitignore file should be placed at the root of your Unity project directory +# +# Get latest from https://github.com/github/gitignore/blob/main/Unity.gitignore +# +# Recommended: add any editor/OS/tool-specific ignore rules from the Global/ templates as needed. +# See: https://github.com/github/gitignore/tree/main/Global +# +.utmp/ +/[Ll]ibrary/ +/[Tt]emp/ +/[Oo]bj/ +/[Bb]uild/ +/[Bb]uilds/ +/[Ll]ogs/ +/[Uu]ser[Ss]ettings/ +*.log + +# By default unity supports Blender asset imports, *.blend1 blender files do not need to be commited to version control. +*.blend1 +*.blend1.meta + +# MemoryCaptures can get excessive in size. +# They also could contain extremely sensitive data +/[Mm]emoryCaptures/ + +# Recordings can get excessive in size +/[Rr]ecordings/ + +# Uncomment this line if you wish to ignore the asset store tools plugin +# /[Aa]ssets/AssetStoreTools* + +# Autogenerated Jetbrains Rider plugin +/[Aa]ssets/Plugins/Editor/JetBrains* +# Jetbrains Rider personal-layer settings +*.DotSettings.user + +# Visual Studio cache directory +.vs/ + +# Gradle cache directory +.gradle/ + +# Autogenerated VS/MD/Consulo solution and project files +ExportedObj/ +.consulo/ +*.csproj +*.unityproj +*.sln +*.slnx +*.suo +*.tmp +*.user +*.userprefs +*.pidb +*.booproj +*.svd +*.pdb +*.mdb +*.opendb +*.VC.db + +# Unity3D generated meta files +*.pidb.meta +*.pdb.meta +*.mdb.meta + +# Unity3D generated file on crash reports +sysinfo.txt + +# Mono auto generated files +mono_crash.* + +# Builds +*.apk +*.aab +*.unitypackage +*.unitypackage.meta +*.app + +# Crashlytics generated file +crashlytics-build.properties + +# TestRunner generated files +InitTestScene*.unity* + +# Addressables default ignores, before user customizations +/ServerData +/[Aa]ssets/StreamingAssets/aa* +/[Aa]ssets/AddressableAssetsData/link.xml* +/[Aa]ssets/Addressables_Temp* +# By default, Addressables content builds will generate addressables_content_state.bin +# files in platform-specific subfolders, for example: +# /Assets/AddressableAssetsData/OSX/addressables_content_state.bin +/[Aa]ssets/AddressableAssetsData/*/*.bin* + +# Visual Scripting auto-generated files +/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Flow/UnitOptions.db +/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Flow/UnitOptions.db.meta +/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Core/Property Providers +/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Core/Property Providers.meta + +# Auto-generated scenes by play mode tests +/[Aa]ssets/[Ii]nit[Tt]est[Ss]cene*.unity* + +# Auto-generated cache in Assets folder +/[Aa]ssets/[Ss]ceneDependencyCache* + diff --git a/.idea/.idea.Colorbook/.idea/.gitignore b/.idea/.idea.Colorbook/.idea/.gitignore new file mode 100644 index 0000000..59175fa --- /dev/null +++ b/.idea/.idea.Colorbook/.idea/.gitignore @@ -0,0 +1,15 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/contentModel.xml +/projectSettingsUpdater.xml +/modules.xml +/.idea.Colorbook.iml +# Editor-based HTTP Client requests +/httpRequests/ +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.idea.Colorbook/.idea/encodings.xml b/.idea/.idea.Colorbook/.idea/encodings.xml new file mode 100644 index 0000000..935f877 --- /dev/null +++ b/.idea/.idea.Colorbook/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/.idea.Colorbook/.idea/indexLayout.xml b/.idea/.idea.Colorbook/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/.idea/.idea.Colorbook/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/Assets/.DS_Store b/Assets/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..333835de503f0ce920d5f466150427551525cdcb GIT binary patch literal 6148 zcmeHKO-~a+7=8zeZb4*$79nb~u@@5>?Gj(^N0wL*L z@BRRPfQdJ6`UCXn)q{V)i)Vc2qXB8TDlz*uGtWEo&NCm+W@b77KyrKK2>=rS3`_zO z-I%p85f`b&I&@7JB9VPm!G#Ea6oQu4aYd{^tiWYcK@lnL0jB8tKfv2P=hLzsmS)Iej2_U`gxM*n~Iev=ziF?d!#nFU`e$ zH_hhqlHEPmdaw7H{R4yjss402J#=GuWZ>qlf;m`pOS_doOnaXDJjnTbv|#pyxcJ2q zXUhTI$3^EO`YLj~Lkta^BdpN!v(u{8gBrF;omR+B9|x4OjY{B^mv(kS8s*RU>teK0 zzLc|tMe%%cMmsM!)V9R%l)L&vb9!0#G z_iz@DAR?XZQ*~;1`^bUNS`PkWrE)(`1I&WR9$m4YEyK@IDMU>+?8O9vJVKCoa9J>hc!013A%M&5ZnKUI-RsN%0wLME zp1k-2`~fE3yy*|nqgN090WY4h`msEA*z4j4?H%qpmV+WouCgzfjZN!ji}K z@=n*Z;F0Tb7N`KP#K>jsvByhdFDrI5a(+)N0!+5m5+N?+uHGYXp5mUQNkaj{?krXUAv@Eoe} z2HwIu_yk|zJN$%WY{eez#{nF~ah$*mPT>Ns;s(0-Ovfi`5BZiE&j5y`oIK>+T)=(7 z%hV_R?b=%pL$D1DB5>>8|M%o|{{5c;x6u##>-=mmeix05uj?W%Q|?7t1E&(6UqwQm zvS(M(a@O~v84^KV6g3;fux7P1SmKVDftZ2+odNlMNKuiPF<8~8J{?rakCU_~B}yS( z{rVH8Ogm$+s*x-ts6z>LD4HtLPY zjv0sISBRQy*oz4pT#`J$m)v3wZI2)jzwyB3EO~RMP!bcU5&yeKXxX4FH(iDUAYH0ANrN zm~5r$4$Nqf_V&t;^#Pv&jFUNQMQYd5d%3zqLS+E8U568wvrZTC!Q%9N9;pq7I zL?$&cIev6x8olW|_ZAD=Ud89H6z@nIlazLib$CrmBO$lAs}sU6^@P4#Ry`%Nwe4#A zwGOMZtGlzOv$wam?|T10*NvM6tJ|@Q+vPw!>J0aIkn?s}!RiPp;khFB7Xr3RiLONK zWt4Xh$kf#ou*gbJPr8=&tK`#j(jf@glzqJ*zXyuf?DrPGN-18QA=teI0 zSJ&n25v$DkTbyPTPcUBp~0l~p?kY`@HM`x~C^FmK+^@hIYz6_>IQPcEm- zSM8$fm(%xuDi+Oj_O{Y2NY{xqdg_`+On*Aql=_m-eMUhG%974L(k=!J!8GJy9bP~U z-oiV051-*H{D5C@jP2NmgE)j4oWM!U;xsPe8g8PE&sBV){*rI$@ibsaO5-K(<^$j3 zewq4&zghq4VHhgFAOgGT`~N^*XTSf);DQ6;Sw9?X@-spET{JSjX^Jo?cSb94m&PxW z)-*#xoV2H(q`leyqL~swQzSJTqFFQA8a=TRGY~TnGoTm{`$LL~z^ulaLb-KNB{n8u zPYM)5y8QJgOzC!3V@)AhNKl0ms!-Hd4AeIVRN-XLYX6!-6%Ht8rg8MlsBb8!FCLhZ z?toc^aUC-dGjNuH7S*)G`Tu~{@CEn(vq5nyW*}zZzhVHBv-#N^rKHc+bIFObHbrHV siV)#fQz%2I(#Nq>#8KQ&MGDzcLLtm*tSO`(lK4kJ(hyfM1Amo)-(hqVoB#j- literal 0 HcmV?d00001 diff --git a/Assets/Darkmatter/Code/Core.meta b/Assets/Darkmatter/Code/Core.meta new file mode 100644 index 0000000..da26edf --- /dev/null +++ b/Assets/Darkmatter/Code/Core.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 04fd8e2c965eb4fb49f4deca22ee7c1d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Compatibility.meta b/Assets/Darkmatter/Code/Core/Compatibility.meta new file mode 100644 index 0000000..d890153 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Compatibility.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1275b0c93b187472ab525938a5f6308a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Compatibility/IsExternalInit.cs b/Assets/Darkmatter/Code/Core/Compatibility/IsExternalInit.cs new file mode 100644 index 0000000..09502f1 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Compatibility/IsExternalInit.cs @@ -0,0 +1,9 @@ +#if !NET5_0_OR_GREATER +namespace System.Runtime.CompilerServices +{ + // Enables C# 9 records/init-only members on older Unity/.NET profiles. + internal static class IsExternalInit + { + } +} +#endif diff --git a/Assets/Darkmatter/Code/Core/Compatibility/IsExternalInit.cs.meta b/Assets/Darkmatter/Code/Core/Compatibility/IsExternalInit.cs.meta new file mode 100644 index 0000000..0f27b86 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Compatibility/IsExternalInit.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 30b275c4b60da48f7a836b26c9576f6c \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Contracts.meta b/Assets/Darkmatter/Code/Core/Contracts.meta new file mode 100644 index 0000000..9a53ee6 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Contracts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bca93034b2c4d4539936e716adb298a9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Contracts/Services.meta b/Assets/Darkmatter/Code/Core/Contracts/Services.meta new file mode 100644 index 0000000..a3e3571 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Contracts/Services.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 100aa93d3292d46cda004ce163762e13 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Contracts/Services/Assets.meta b/Assets/Darkmatter/Code/Core/Contracts/Services/Assets.meta new file mode 100644 index 0000000..2c187d3 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Contracts/Services/Assets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7d0243ec32cd1418f96bd1a3930eadc3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Contracts/Services/Assets/IAssetProviderService.cs b/Assets/Darkmatter/Code/Core/Contracts/Services/Assets/IAssetProviderService.cs new file mode 100644 index 0000000..880ce99 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Contracts/Services/Assets/IAssetProviderService.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using Cysharp.Threading.Tasks; +using UnityEngine; + +namespace Darkmatter.Core.Contracts.Services.Assets +{ + public interface IAssetProviderService + { + UniTask InstantiateAsync( + string assetId, + Vector3 position, + Quaternion rotation, + IProgress progress, + CancellationToken cancellationToken); + + UniTask InstantiateAsync( + string assetId, + IProgress progress, + CancellationToken cancellationToken); + + UniTask LoadAssetAsync( + string assetId, + IProgress progress, + CancellationToken cancellationToken); + + UniTask> LoadAssetsAsync( + IProgress progress, + CancellationToken cancellationToken); + + UniTask> LoadAssetsAsync( + object key, + IProgress progress, + CancellationToken cancellationToken); + + void UnloadAsset(string assetId); + + UniTask LoadExternalCatalogAsync( + string catalogUrl, + IProgress progress, + CancellationToken cancellationToken); + + void ReleaseInstance(GameObject instance); + } +} diff --git a/Assets/Darkmatter/Code/Core/Contracts/Services/Assets/IAssetProviderService.cs.meta b/Assets/Darkmatter/Code/Core/Contracts/Services/Assets/IAssetProviderService.cs.meta new file mode 100644 index 0000000..851970e --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Contracts/Services/Assets/IAssetProviderService.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d3f25dd3dcb494f9dabbf23a0114b562 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Contracts/Services/Audio.meta b/Assets/Darkmatter/Code/Core/Contracts/Services/Audio.meta new file mode 100644 index 0000000..188a5da --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Contracts/Services/Audio.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9ecc165686aa0429daf34d55396c1bfa +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Contracts/Services/Audio/IAudioService.cs b/Assets/Darkmatter/Code/Core/Contracts/Services/Audio/IAudioService.cs new file mode 100644 index 0000000..c6f81a9 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Contracts/Services/Audio/IAudioService.cs @@ -0,0 +1,23 @@ +using System.Threading; +using Cysharp.Threading.Tasks; +using Darkmatter.Core.Data.Dynamic.Services.Audio; +using Darkmatter.Core.Enums.Services.Audio; +using UnityEngine; + +namespace Darkmatter.Core.Contracts.Services.Audio +{ + public interface IAudioService + { + AudioHandle Play(in AudioRequest request); + UniTask InitializeAsync(CancellationToken cancellationToken); + UniTask LoadClipFromPath(string path, CancellationToken cancellationToken); + void Stop(AudioHandle handle, float fadeOutSeconds = 0f); + void SetPitch(AudioHandle handle, float pitch); + void SetVolume(AudioHandle handle, float volume01); + bool IsPlaying(AudioHandle handle); + void SetChannelPaused(AudioChannel channel, bool paused); + void SetChannelVolume(AudioChannel channel, float volume01); + void SetSnapshotWeights(params float[] weights); + void TransitionSnapshotWeights(float duration, params float[] weights); + } +} diff --git a/Assets/Darkmatter/Code/Core/Contracts/Services/Audio/IAudioService.cs.meta b/Assets/Darkmatter/Code/Core/Contracts/Services/Audio/IAudioService.cs.meta new file mode 100644 index 0000000..eadc78c --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Contracts/Services/Audio/IAudioService.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4a49dff8ccb645b9b282b303b718fb5c +timeCreated: 1770634613 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Contracts/Services/Audio/ISfxPlayer.cs b/Assets/Darkmatter/Code/Core/Contracts/Services/Audio/ISfxPlayer.cs new file mode 100644 index 0000000..ee7c077 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Contracts/Services/Audio/ISfxPlayer.cs @@ -0,0 +1,14 @@ +using Darkmatter.Core.Data.Dynamic.Services.Audio; +using Darkmatter.Core.Enums.Services.Audio; +using UnityEngine; + +namespace Darkmatter.Core.Contracts.Services.Audio +{ + public interface ISfxPlayer + { + AudioHandle Play(SfxId id, Transform follow = null); + AudioHandle PlayLoop(SfxId id, Transform follow = null); + void Stop(AudioHandle handle, float fadeOutSeconds = 0f); + bool IsPlaying(AudioHandle handle); + } +} diff --git a/Assets/Darkmatter/Code/Core/Contracts/Services/Audio/ISfxPlayer.cs.meta b/Assets/Darkmatter/Code/Core/Contracts/Services/Audio/ISfxPlayer.cs.meta new file mode 100644 index 0000000..0c04c00 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Contracts/Services/Audio/ISfxPlayer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8b2cab46f32d7466b9decc9c7ff94eb2 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Contracts/Services/Scenes.meta b/Assets/Darkmatter/Code/Core/Contracts/Services/Scenes.meta new file mode 100644 index 0000000..fe3d994 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Contracts/Services/Scenes.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1903ca430080472fbe36c5c1577bc502 +timeCreated: 1770642710 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Contracts/Services/Scenes/ISceneService.cs b/Assets/Darkmatter/Code/Core/Contracts/Services/Scenes/ISceneService.cs new file mode 100644 index 0000000..f0d52b7 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Contracts/Services/Scenes/ISceneService.cs @@ -0,0 +1,27 @@ +using System; +using System.Threading; +using Cysharp.Threading.Tasks; +using Darkmatter.Core.Enums.Services.Scenes; +using UnityEngine.SceneManagement; + +namespace Darkmatter.Core.Contracts.Services.Scenes +{ + public interface ISceneService + { + UniTask LoadSceneAsync(GameScene scene, IProgress progress, CancellationToken cancellationToken); + UniTask UnloadSceneAsync(GameScene scene, IProgress progress, CancellationToken cancellationToken); + + UniTask LoadSceneAsync( + string sceneKey, + IProgress progress, + CancellationToken cancellationToken, + bool setActiveScene = true); + + UniTask UnloadSceneAsync( + string sceneKey, + IProgress progress, + CancellationToken cancellationToken); + + bool TryGetLoadedScene(string sceneKey, out Scene scene); + } +} diff --git a/Assets/Darkmatter/Code/Core/Contracts/Services/Scenes/ISceneService.cs.meta b/Assets/Darkmatter/Code/Core/Contracts/Services/Scenes/ISceneService.cs.meta new file mode 100644 index 0000000..4a40b8b --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Contracts/Services/Scenes/ISceneService.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c3ea399e8d284f538e256460c1def877 +timeCreated: 1770642720 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Core.asmdef b/Assets/Darkmatter/Code/Core/Core.asmdef new file mode 100644 index 0000000..528670a --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Core.asmdef @@ -0,0 +1,16 @@ +{ + "name": "Core", + "rootNamespace": "Darkmatter.Core", + "references": [ + "GUID:f51ebe6a0ceec4240a699833d6309b23" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Core.asmdef.meta b/Assets/Darkmatter/Code/Core/Core.asmdef.meta new file mode 100644 index 0000000..15d7844 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Core.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6a0a834eb41764f12ba55c3fb04a40cb +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Data.meta b/Assets/Darkmatter/Code/Core/Data.meta new file mode 100644 index 0000000..ffc0595 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5b2cc64aeeed544509ce5b2191154d78 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Data/Dynamic.meta b/Assets/Darkmatter/Code/Core/Data/Dynamic.meta new file mode 100644 index 0000000..db7546f --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Dynamic.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e087f5b8739414488be6e94f4cf8f3ce +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Data/Dynamic/Services.meta b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services.meta new file mode 100644 index 0000000..9231c11 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 56cb41057044542528a751d0be05d961 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio.meta b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio.meta new file mode 100644 index 0000000..5be0e3c --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e5b0eb514db9e488ea6cf383b759a2e4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio/AudioHandle.cs b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio/AudioHandle.cs new file mode 100644 index 0000000..d5c8543 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio/AudioHandle.cs @@ -0,0 +1,17 @@ +namespace Darkmatter.Core.Data.Dynamic.Services.Audio +{ + public readonly struct AudioHandle + { + public static readonly AudioHandle Invalid = new(0, 0); + + public readonly int Id; + public readonly ushort Generation; + public bool IsValid => Id > 0; + + public AudioHandle(int id, ushort generation) + { + Id = id; + Generation = generation; + } + } +} \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio/AudioHandle.cs.meta b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio/AudioHandle.cs.meta new file mode 100644 index 0000000..fab0e8f --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio/AudioHandle.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a062321bebaa428d84c9e6ce14edc4d9 +timeCreated: 1770636619 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio/AudioRequest.cs b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio/AudioRequest.cs new file mode 100644 index 0000000..1f4cdca --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio/AudioRequest.cs @@ -0,0 +1,36 @@ +using Darkmatter.Core.Enums.Services.Audio; +using UnityEngine; + +namespace Darkmatter.Core.Data.Dynamic.Services.Audio +{ + public readonly struct AudioRequest + { + public readonly AudioClip Clip; + public readonly AudioChannel Channel; + public readonly AudioPlayMode PlayMode; + public readonly bool StopChannelBeforePlay; + public readonly float Volume01; + public readonly float Pitch; + public readonly bool Spatial3D; + public readonly Transform FollowTarget; + public readonly float MinDistance; + public readonly float MaxDistance; + + public AudioRequest(AudioClip clip, AudioChannel channel, AudioPlayMode mode, + bool stopChannelBeforePlay = false, + float volume01 = 1f, float pitch = 1f, bool spatial3D = false, Transform followTarget = null, + float minDistance = 1f, float maxDistance = 500f) + { + Clip = clip; + Channel = channel; + PlayMode = mode; + StopChannelBeforePlay = stopChannelBeforePlay; + Volume01 = volume01; + Pitch = pitch; + Spatial3D = spatial3D; + FollowTarget = followTarget; + MinDistance = minDistance; + MaxDistance = maxDistance; + } + } +} \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio/AudioRequest.cs.meta b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio/AudioRequest.cs.meta new file mode 100644 index 0000000..9d63958 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Dynamic/Services/Audio/AudioRequest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0d94a32bb4b841a88971f46d7fc3984b +timeCreated: 1770636723 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Data/Static.meta b/Assets/Darkmatter/Code/Core/Data/Static.meta new file mode 100644 index 0000000..4561334 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Static.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7e90b7ea022ae4de5962d79e5c36846d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Data/Static/Services.meta b/Assets/Darkmatter/Code/Core/Data/Static/Services.meta new file mode 100644 index 0000000..7b8f29c --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Static/Services.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4e05cfff249d84f78a2dc81dc36772c2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Data/Static/Services/Audio.meta b/Assets/Darkmatter/Code/Core/Data/Static/Services/Audio.meta new file mode 100644 index 0000000..35d0210 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Static/Services/Audio.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3346e766e438c4a46a5f2c70019c93da +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Data/Static/Services/Audio/SfxCatalogSO.cs b/Assets/Darkmatter/Code/Core/Data/Static/Services/Audio/SfxCatalogSO.cs new file mode 100644 index 0000000..5a4f6ce --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Static/Services/Audio/SfxCatalogSO.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using Darkmatter.Core.Enums.Services.Audio; +using UnityEngine; + +namespace Darkmatter.Core.Data.Static.Services.Audio +{ + [CreateAssetMenu(fileName = "SfxCatalog", menuName = "Darkmatter/Audio/Sfx Catalog")] + public class SfxCatalogSO : ScriptableObject + { + [Serializable] + public class Entry + { + public SfxId Id; + public AudioClip Clip; + public AudioChannel Channel = AudioChannel.Sfx; + [Range(0f, 1f)] public float Volume = 1f; + [Range(0.1f, 3f)] public float Pitch = 1f; + public bool Loop; + } + + [SerializeField] private List entries = new(); + + private Dictionary _index; + + public bool TryGet(SfxId id, out Entry entry) + { + if (_index == null) BuildIndex(); + return _index.TryGetValue(id, out entry); + } + + private void BuildIndex() + { + _index = new Dictionary(entries.Count); + foreach (var e in entries) + { + if (e != null && e.Id != SfxId.None && e.Clip != null) + _index[e.Id] = e; + } + } + + private void OnValidate() => _index = null; + } +} diff --git a/Assets/Darkmatter/Code/Core/Data/Static/Services/Audio/SfxCatalogSO.cs.meta b/Assets/Darkmatter/Code/Core/Data/Static/Services/Audio/SfxCatalogSO.cs.meta new file mode 100644 index 0000000..66c49e6 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Data/Static/Services/Audio/SfxCatalogSO.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8dc05770caf7f49e9a59dab81283a278 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Enums.meta b/Assets/Darkmatter/Code/Core/Enums.meta new file mode 100644 index 0000000..1909942 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 393a0b77d95da48f3ba6251f868bcf96 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Enums/Services.meta b/Assets/Darkmatter/Code/Core/Enums/Services.meta new file mode 100644 index 0000000..ba241d7 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e97b83c35ee0e4b0d91e6ab4a333abe5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Audio.meta b/Assets/Darkmatter/Code/Core/Enums/Services/Audio.meta new file mode 100644 index 0000000..283db88 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Audio.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2a7ce1f001dba4bc680c52517e4b5c68 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Audio/AudioChannel.cs b/Assets/Darkmatter/Code/Core/Enums/Services/Audio/AudioChannel.cs new file mode 100644 index 0000000..6cba102 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Audio/AudioChannel.cs @@ -0,0 +1,18 @@ +namespace Darkmatter.Core.Enums.Services.Audio +{ + public enum AudioChannel + { + Sfx, + VehicleSfx, + AISfx, + Engine, + VehicleBrake, + PassengerChatter, + Music, + Ambience, + Weather, + BGM, + UI, + Radio + } +} diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Audio/AudioChannel.cs.meta b/Assets/Darkmatter/Code/Core/Enums/Services/Audio/AudioChannel.cs.meta new file mode 100644 index 0000000..64d1098 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Audio/AudioChannel.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d2031508f5c44c969e2a03200a867b36 +timeCreated: 1770636948 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Audio/AudioPlayMode.cs b/Assets/Darkmatter/Code/Core/Enums/Services/Audio/AudioPlayMode.cs new file mode 100644 index 0000000..6a0b049 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Audio/AudioPlayMode.cs @@ -0,0 +1,8 @@ +namespace Darkmatter.Core.Enums.Services.Audio +{ + public enum AudioPlayMode + { + OneShot, + Loop + } +} \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Audio/AudioPlayMode.cs.meta b/Assets/Darkmatter/Code/Core/Enums/Services/Audio/AudioPlayMode.cs.meta new file mode 100644 index 0000000..b929a33 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Audio/AudioPlayMode.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 63f44faaf2da4474ba7c3850f21dd02f +timeCreated: 1770636914 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Audio/SfxId.cs b/Assets/Darkmatter/Code/Core/Enums/Services/Audio/SfxId.cs new file mode 100644 index 0000000..b2a6e9e --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Audio/SfxId.cs @@ -0,0 +1,16 @@ +namespace Darkmatter.Core.Enums.Services.Audio +{ + public enum SfxId + { + None = 0, + + WiperUp = 100, + WiperDown = 101, + + BlinkerTick = 200, + + GearShift = 300, + + ReverseBeep = 400, + } +} diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Audio/SfxId.cs.meta b/Assets/Darkmatter/Code/Core/Enums/Services/Audio/SfxId.cs.meta new file mode 100644 index 0000000..55bb7e9 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Audio/SfxId.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9a490eff4a4c14cbc9ee02b9fcd543b8 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Scenes.meta b/Assets/Darkmatter/Code/Core/Enums/Services/Scenes.meta new file mode 100644 index 0000000..8888270 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 92344a3224a2f4e88ad7438669c9dfb9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Scenes/GameScene.cs b/Assets/Darkmatter/Code/Core/Enums/Services/Scenes/GameScene.cs new file mode 100644 index 0000000..dc87dd2 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Scenes/GameScene.cs @@ -0,0 +1,11 @@ +namespace Darkmatter.Core.Enums.Services.Scenes +{ + public enum GameScene + { + Boot, + MainMenu, + Gameplay, + TestTraffic, + VehicleTest, + } +} \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Core/Enums/Services/Scenes/GameScene.cs.meta b/Assets/Darkmatter/Code/Core/Enums/Services/Scenes/GameScene.cs.meta new file mode 100644 index 0000000..b9062a6 --- /dev/null +++ b/Assets/Darkmatter/Code/Core/Enums/Services/Scenes/GameScene.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2ae040ecfda14b5e9f4082294637b020 +timeCreated: 1770642840 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs.meta b/Assets/Darkmatter/Code/Libs.meta new file mode 100644 index 0000000..456bfbb --- /dev/null +++ b/Assets/Darkmatter/Code/Libs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ea36b1548e1bb42feafed8de99668386 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/FSM.meta b/Assets/Darkmatter/Code/Libs/FSM.meta new file mode 100644 index 0000000..959c796 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/FSM.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a60fee6d8a3034037ac8cc01c45baf11 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/FSM/Docs.meta b/Assets/Darkmatter/Code/Libs/FSM/Docs.meta new file mode 100644 index 0000000..ce4fdb1 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/FSM/Docs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 395d10529759141ddabeab8039459e38 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/FSM/Docs/FSMLib.md b/Assets/Darkmatter/Code/Libs/FSM/Docs/FSMLib.md new file mode 100644 index 0000000..ac4054b --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/FSM/Docs/FSMLib.md @@ -0,0 +1,19 @@ +# FSM Lib + +## Purpose + +`Darkmatter.Libs.FSM` holds reusable finite-state-machine primitives intended for feature-local orchestration without creating cross-feature dependencies. + +## Public Entry Points + +- FSM runtime types under `Assets/Darkmatter/Code/Libs/FSM` + +## Dependencies + +- Intended to remain generic and feature-agnostic +- May be referenced by any feature that needs local state transitions + +## Extension Notes + +- Keep the API deterministic and side-effect free. +- Domain-specific states, transitions, or scene references belong in the consuming feature or service slice. diff --git a/Assets/Darkmatter/Code/Libs/FSM/Docs/FSMLib.md.meta b/Assets/Darkmatter/Code/Libs/FSM/Docs/FSMLib.md.meta new file mode 100644 index 0000000..228b668 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/FSM/Docs/FSMLib.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fa62a43934add4beb92f51d9effd9d84 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/FSM/IState.cs b/Assets/Darkmatter/Code/Libs/FSM/IState.cs new file mode 100644 index 0000000..183e8ca --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/FSM/IState.cs @@ -0,0 +1,9 @@ +namespace Darkmatter.Libs.FSM +{ + public interface IState + { + void Enter(); + void Tick(); + void Exit(); + } +} \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/FSM/IState.cs.meta b/Assets/Darkmatter/Code/Libs/FSM/IState.cs.meta new file mode 100644 index 0000000..21673d8 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/FSM/IState.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2f814fe27db8b43349a93943bf71fcd5 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/FSM/Libs.FSM.asmdef b/Assets/Darkmatter/Code/Libs/FSM/Libs.FSM.asmdef new file mode 100644 index 0000000..8aad641 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/FSM/Libs.FSM.asmdef @@ -0,0 +1,14 @@ +{ + "name": "Libs.FSM", + "rootNamespace": "Darkmatter.Libs.FSM", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/FSM/Libs.FSM.asmdef.meta b/Assets/Darkmatter/Code/Libs/FSM/Libs.FSM.asmdef.meta new file mode 100644 index 0000000..5b32b28 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/FSM/Libs.FSM.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c176ee863a5e74e88a6517f9f102cf92 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/FSM/State.cs b/Assets/Darkmatter/Code/Libs/FSM/State.cs new file mode 100644 index 0000000..dc05509 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/FSM/State.cs @@ -0,0 +1,15 @@ +namespace Darkmatter.Libs.FSM +{ + public abstract class State : IState + { + protected readonly T runner; + protected State(T runner) + { + this.runner = runner; + } + + public virtual void Enter() { } + public virtual void Tick() { } + public virtual void Exit() { } + } +} diff --git a/Assets/Darkmatter/Code/Libs/FSM/State.cs.meta b/Assets/Darkmatter/Code/Libs/FSM/State.cs.meta new file mode 100644 index 0000000..01a9748 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/FSM/State.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e5d044f466d7a46379be2ebb74292a74 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/FSM/StateMachine.cs b/Assets/Darkmatter/Code/Libs/FSM/StateMachine.cs new file mode 100644 index 0000000..50ddd50 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/FSM/StateMachine.cs @@ -0,0 +1,26 @@ +namespace Darkmatter.Libs.FSM +{ + public abstract class StateMachine + { + public IState CurrentState { get; private set; } + public IState PreviousState { get; private set; } + + public void ChangeState(IState newState) + { + if (newState == null) return; + if (CurrentState == newState) return; + + CurrentState?.Exit(); + + PreviousState = CurrentState; + CurrentState = newState; + + CurrentState.Enter(); + } + + public virtual void Tick() + { + CurrentState?.Tick(); + } + } +} \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/FSM/StateMachine.cs.meta b/Assets/Darkmatter/Code/Libs/FSM/StateMachine.cs.meta new file mode 100644 index 0000000..aaf178c --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/FSM/StateMachine.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c9c75568b26bd4667ad07404934fc0c9 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/Installers.meta b/Assets/Darkmatter/Code/Libs/Installers.meta new file mode 100644 index 0000000..b7961bf --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/Installers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d669ee184e2754ff6af32edd4c87fdbc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/Installers/Docs.meta b/Assets/Darkmatter/Code/Libs/Installers/Docs.meta new file mode 100644 index 0000000..d014b79 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/Installers/Docs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6e5889f574d4c4d1ca18fb324f33938d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/Installers/Docs/InstallersLib.md b/Assets/Darkmatter/Code/Libs/Installers/Docs/InstallersLib.md new file mode 100644 index 0000000..21aed6e --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/Installers/Docs/InstallersLib.md @@ -0,0 +1,19 @@ +# Installers Lib + +## Purpose + +`Darkmatter.Libs.Installers` provides the shared installer contract used by App and scene scopes to register feature/service modules through explicit DI composition. + +## Public Entry Points + +- `IServiceModule` + +## Dependencies + +- Depends only on `VContainer` so modules can register against `IContainerBuilder`. +- Is consumed by App scopes (`RootLifetimeScope`, `GameplayLifetimeScope`, `MainMenuLifetimeScope`) and scene/entity scopes that register `MonoBehaviour` modules through explicit inspector wiring. + +## Extension Notes + +- Keep this lib minimal and contract-only. It should stay reusable by both feature and service slices without pulling in higher-layer code. +- New reusable installer helpers belong here only if they remain generic and do not encode game-specific behavior. diff --git a/Assets/Darkmatter/Code/Libs/Installers/Docs/InstallersLib.md.meta b/Assets/Darkmatter/Code/Libs/Installers/Docs/InstallersLib.md.meta new file mode 100644 index 0000000..ac9e104 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/Installers/Docs/InstallersLib.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6c035b34d3ec341d58cdb799f2326799 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/Installers/IServiceModule.cs b/Assets/Darkmatter/Code/Libs/Installers/IServiceModule.cs new file mode 100644 index 0000000..f466adc --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/Installers/IServiceModule.cs @@ -0,0 +1,9 @@ +using VContainer; + +namespace Darkmatter.Libs.Installers +{ + public interface IServiceModule + { + void Register(IContainerBuilder builder); + } +} diff --git a/Assets/Darkmatter/Code/Libs/Installers/IServiceModule.cs.meta b/Assets/Darkmatter/Code/Libs/Installers/IServiceModule.cs.meta new file mode 100644 index 0000000..5e4c3b3 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/Installers/IServiceModule.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a4fccd9c5f4934143929c601592e9616 diff --git a/Assets/Darkmatter/Code/Libs/Installers/Libs.Installers.asmdef b/Assets/Darkmatter/Code/Libs/Installers/Libs.Installers.asmdef new file mode 100644 index 0000000..150365c --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/Installers/Libs.Installers.asmdef @@ -0,0 +1,16 @@ +{ + "name": "Libs.Installers", + "rootNamespace": "Darkmatter.Libs.Installers", + "references": [ + "GUID:b0214a6008ed146ff8f122a6a9c2f6cc" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} diff --git a/Assets/Darkmatter/Code/Libs/Installers/Libs.Installers.asmdef.meta b/Assets/Darkmatter/Code/Libs/Installers/Libs.Installers.asmdef.meta new file mode 100644 index 0000000..b7b0a88 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/Installers/Libs.Installers.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c1c03c0e5b2f4412b9f2be1c20d6a9b1 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/Observer.meta b/Assets/Darkmatter/Code/Libs/Observer.meta new file mode 100644 index 0000000..33b48da --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/Observer.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e8fea732420104e728b3290bc8e9bfc1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/Observer/Docs.meta b/Assets/Darkmatter/Code/Libs/Observer/Docs.meta new file mode 100644 index 0000000..2d2d346 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/Observer/Docs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 62a255738299947f5aa75ed233adb93a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/Observer/Docs/ObserverLib.md b/Assets/Darkmatter/Code/Libs/Observer/Docs/ObserverLib.md new file mode 100644 index 0000000..2e36375 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/Observer/Docs/ObserverLib.md @@ -0,0 +1,20 @@ +# Observer Lib + +## Purpose + +`Darkmatter.Libs.Observer` provides the shared event-bus/observer primitives used for fire-and-forget notifications across slices. + +## Public Entry Points + +- `IEventBus` +- `EventBus` + +## Dependencies + +- Used broadly by App, Features, and Services for cross-slice notifications +- Should remain infrastructure-only; business rules stay in the caller/subscriber + +## Extension Notes + +- Use this lib for notifications, not request/response flows. +- Preserve disposable subscription semantics so lifetime scopes can cleanly unsubscribe on teardown. diff --git a/Assets/Darkmatter/Code/Libs/Observer/Docs/ObserverLib.md.meta b/Assets/Darkmatter/Code/Libs/Observer/Docs/ObserverLib.md.meta new file mode 100644 index 0000000..6e76253 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/Observer/Docs/ObserverLib.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: aeb1895d9f8424537b1a062bba8f6f14 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/Observer/EventBus.cs b/Assets/Darkmatter/Code/Libs/Observer/EventBus.cs new file mode 100644 index 0000000..015ff2b --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/Observer/EventBus.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using VContainer; + +namespace Darkmatter.Libs.Observer +{ + public class EventBus : IEventBus + { + [Inject] + public EventBus() { } + + private readonly Dictionary _map = new(); + public void Publish(T evt) where T : struct + { + if (_map.TryGetValue(typeof(T), out var handlerObj)) + { + var action = (Action)handlerObj; + action?.Invoke(evt); + } + } + + public IDisposable Subscribe(Action handler) where T : struct + { + var t = typeof(T); + + if (_map.TryGetValue(t, out var existingHandlers)) + { + var action = (Action)existingHandlers; + _map[t] = action + handler; + } + else + { + _map[t] = handler; + } + + return new Unsub(this, handler); + } + + internal void Unsubscribe(Action handler) where T : struct + { + var t = typeof(T); + if (_map.TryGetValue(t, out var existingHandlers)) + { + var action = (Action)existingHandlers; + action -= handler; + + if (action == null) + _map.Remove(t); + else + _map[t] = action; + } + } + + private sealed class Unsub : IDisposable where T : struct + { + private readonly EventBus _bus; + private Action _handler; + + public Unsub(EventBus bus, Action handler) + { + _bus = bus; + _handler = handler; + } + + public void Dispose() + { + if (_handler != null) + { + _bus.Unsubscribe(_handler); + _handler = null; + } + } + } + } +} \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/Observer/EventBus.cs.meta b/Assets/Darkmatter/Code/Libs/Observer/EventBus.cs.meta new file mode 100644 index 0000000..b5de6f5 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/Observer/EventBus.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3360f02303be544ecbe8c21dc0c4e33e \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/Observer/IEventBus.cs b/Assets/Darkmatter/Code/Libs/Observer/IEventBus.cs new file mode 100644 index 0000000..3a8df16 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/Observer/IEventBus.cs @@ -0,0 +1,18 @@ +using System; + +namespace Darkmatter.Libs.Observer +{ + public interface IEventBus + { + /// + /// Publish an event of type T to all subscribers. + /// + void Publish(T evt) where T : struct; + + /// + /// Subscribe to an event of type T. + /// Returns IDisposable – calling Dispose() unsubscribes. + /// + IDisposable Subscribe(Action handler) where T : struct; + } +} \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/Observer/IEventBus.cs.meta b/Assets/Darkmatter/Code/Libs/Observer/IEventBus.cs.meta new file mode 100644 index 0000000..720f28d --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/Observer/IEventBus.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 22922a82d6e00458f8e34b78a9599a66 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/Observer/Libs.Observer.asmdef b/Assets/Darkmatter/Code/Libs/Observer/Libs.Observer.asmdef new file mode 100644 index 0000000..4ced2ff --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/Observer/Libs.Observer.asmdef @@ -0,0 +1,16 @@ +{ + "name": "Libs.Observer", + "rootNamespace": "Darkmatter.Libs.Observer", + "references": [ + "VContainer" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/Observer/Libs.Observer.asmdef.meta b/Assets/Darkmatter/Code/Libs/Observer/Libs.Observer.asmdef.meta new file mode 100644 index 0000000..f3a3116 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/Observer/Libs.Observer.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b4c9f7fbf1e144933a1797dc208ece5f +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs.meta b/Assets/Darkmatter/Code/Libs/PlayerPrefs.meta new file mode 100644 index 0000000..28b36e4 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f4c1e3acaf8f7448a847fd93afeb9123 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs.meta b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs.meta new file mode 100644 index 0000000..ce0df21 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 85a19104921a942afae4ed40c49ef826 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs/ProtectedPlayerPrefsToolkit_Documentation.md b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs/ProtectedPlayerPrefsToolkit_Documentation.md new file mode 100644 index 0000000..02e8269 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs/ProtectedPlayerPrefsToolkit_Documentation.md @@ -0,0 +1,175 @@ +# Protected PlayerPrefs Toolkit + +Protected PlayerPrefs Toolkit is a lightweight Unity package for project-local data protection, key management, and editor-side inspection of stored values. It wraps Unity `PlayerPrefs`, hashes keys, encrypts values, and adds a guided setup flow so the package can be configured before it ships. + +[[SCREENSHOT: Package Overview - Add a screenshot of the package files and folders inside the Unity Project window.]] + +## What Is Included + +- `ProtectedPlayerPrefs`: runtime API for string, int, float, and bool values. +- `ProtectedPlayerPrefsSettings`: project settings asset that stores the SHA-256 hash derived from your password. +- Getting Started window: first-run setup that appears automatically when the hash password has not been configured. +- `PlayerPrefsKeyRegistry`: registry asset for known keys and descriptions. +- `PlayerPrefs Editor`: editor window for registered keys, raw lookup, delete actions, and key-code generation. +- `PlayerPrefsKeys`: generated constants class that removes string literals from gameplay and service code. + +## Quick Start + +- Import the package into your project. +- If no hash password is configured, Unity creates the settings asset and opens `Tools/Darkmatter/Protected PlayerPrefs/Getting Started`. +- Enter a strong password and save it. The package stores only the SHA-256 hash, not the raw password. +- Keep the original password in a secure team password manager. +- Use `ProtectedPlayerPrefs` from runtime code and `Tools/Darkmatter/PlayerPrefs Editor` from the editor. + +[[SCREENSHOT: Getting Started Window - Add a screenshot of the first-run setup window with the password fields and action buttons.]] + +## Settings Asset and Hash Password + +The package creates or reuses this asset path by default: + +```text +Assets/Darkmatter/Data/Settings/Persistance/Resources/ProtectedPlayerPrefsSettings.asset +``` + +Important behavior: + +- The runtime loads the settings asset through `Resources`, so the configured hash is available in builds. +- If no configured hash exists, the runtime falls back to the built-in default passphrase for backward compatibility. +- Changing the password later changes the derived encryption key and IV. Existing protected values will no longer decrypt. +- The package stores only the SHA-256 hash of the password. The original password cannot be recovered from the asset. + +[[SCREENSHOT: Settings Asset Inspector - Add a screenshot of the generated ProtectedPlayerPrefsSettings asset in the Inspector.]] + +## Runtime API + +Use `ProtectedPlayerPrefs` exactly like a narrow, protected subset of Unity `PlayerPrefs`. + +```csharp +using Darkmatter.Libs.PlayerPrefs; + +ProtectedPlayerPrefs.SetString(PlayerPrefsKeys.Accounts.SavedAuthRequest, json); +ProtectedPlayerPrefs.SetInt("Profile.Level", 12); +ProtectedPlayerPrefs.SetFloat("Audio.MasterVolume", 0.8f); +ProtectedPlayerPrefs.SetBool("Onboarding.Completed", true); +ProtectedPlayerPrefs.Save(); +``` + +Reading values: + +```csharp +var savedAuth = ProtectedPlayerPrefs.GetString(PlayerPrefsKeys.Accounts.SavedAuthRequest, string.Empty); +var level = ProtectedPlayerPrefs.GetInt("Profile.Level", 1); +var volume = ProtectedPlayerPrefs.GetFloat("Audio.MasterVolume", 1f); +var onboardingDone = ProtectedPlayerPrefs.GetBool("Onboarding.Completed", false); +``` + +Available API surface: + +- `Init(string passphrase)`: optional manual initialization from a raw password. +- `InitWithHash(string hashedPassphrase)`: optional manual initialization from a SHA-256 hash. +- `ComputePassphraseHash(string passphrase)`: helper used by the setup flow. +- `SetString`, `GetString` +- `SetInt`, `GetInt` +- `SetFloat`, `GetFloat` +- `SetBool`, `GetBool` +- `HasKey`, `DeleteKey`, `DeleteAll`, `Save` + +## Key Registry and Code Generation + +Use `PlayerPrefsKeyRegistry` to maintain a curated list of known keys, types, and descriptions. The editor window can generate a strongly named `PlayerPrefsKeys` class from the registry. + +Benefits: + +- Central place to document keys. +- Safer refactoring than raw string literals. +- Cleaner service and feature code. +- Easier QA and debugging in the editor window. + +Example generated structure: + +```csharp +public static class PlayerPrefsKeys +{ + public static class Accounts + { + public const string SavedAuthRequest = "Accounts.SavedAuthRequest"; + } + + public static class SaveGame + { + public const string Session = "SaveGame.Session"; + public const string Vehicle = "SaveGame.Vehicle"; + } +} +``` + +## PlayerPrefs Editor + +Open the tool from: + +```text +Tools/Darkmatter/PlayerPrefs Editor +``` + +The editor window includes three areas: + +- Registered Keys: edit keys defined in the registry and save protected values. +- Raw Lookup: inspect or delete unprotected third-party or legacy keys by name. +- Settings: manage registry generation output and open the Protected PlayerPrefs setup flow. + +[[SCREENSHOT: Registered Keys Tab - Add a screenshot of the Registered Keys tab with a few example entries.]] + +[[SCREENSHOT: Raw Lookup Tab - Add a screenshot of the Raw Lookup tab showing a direct key lookup.]] + +## Integration Notes + +- Treat this package as protection against casual local tampering, not as a replacement for a trusted backend. +- Use generated keys for feature and service code whenever the key is known ahead of time. +- Save immediately after write operations that must survive app termination. +- For sensitive gameplay state, pair local protection with server validation when the product design requires trust. + +## Recommended Workflow for Shipping + +- Configure the hash password on first import. +- Register the keys that belong to your project. +- Generate `PlayerPrefsKeys.cs`. +- Replace raw string literals with generated constants. +- Run a smoke test with a fresh install and with existing saved data. +- Capture the screenshots marked in this documentation before publishing the package. + +## Troubleshooting + +Problem: protected values return defaults after you change the password. + +- Cause: the encryption key changed because the stored hash changed. +- Fix: restore the original password or clear and rebuild the protected local cache. + +Problem: the setup window keeps appearing. + +- Cause: the settings asset exists, but its hash password is still blank. +- Fix: open the Getting Started window and save a password. + +Problem: a key is visible in PlayerPrefs but not in the Registered Keys tab. + +- Cause: the value exists, but the key is not in `PlayerPrefsKeyRegistry`. +- Fix: add the key to the registry or inspect it from Raw Lookup. + +## Package Files + +Core files: + +- `Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/ProtectedPlayerPrefs.cs` +- `Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/ProtectedPlayerPrefsSettings.cs` +- `Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PlayerPrefsKeyRegistry.cs` +- `Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PlayerPrefsKeys.cs` +- `Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/PlayerPrefsEditorWindow.cs` +- `Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsGettingStartedWindow.cs` +- `Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsSetupBootstrap.cs` + +## Final Checklist Before Asset Store Submission + +- Verify the configured hash password is set. +- Remove project-specific sample keys that should not ship. +- Replace every screenshot placeholder in this PDF. +- Confirm the generated documentation opens correctly on a clean machine. +- Test the package in a fresh Unity project before export. diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs/ProtectedPlayerPrefsToolkit_Documentation.md.meta b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs/ProtectedPlayerPrefsToolkit_Documentation.md.meta new file mode 100644 index 0000000..942bda8 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs/ProtectedPlayerPrefsToolkit_Documentation.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3c99b2d93e5a945328d6fc323c99142d +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs/ProtectedPlayerPrefsToolkit_Documentation.pdf b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs/ProtectedPlayerPrefsToolkit_Documentation.pdf new file mode 100644 index 0000000..8d79cdc --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs/ProtectedPlayerPrefsToolkit_Documentation.pdf @@ -0,0 +1,156 @@ +%PDF-1.4 +%“Œ‹ž ReportLab Generated PDF document (opensource) +1 0 obj +<< +/F1 2 0 R /F2 3 0 R /F3 4 0 R +>> +endobj +2 0 obj +<< +/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font +>> +endobj +3 0 obj +<< +/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font +>> +endobj +4 0 obj +<< +/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font +>> +endobj +5 0 obj +<< +/Contents 13 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 12 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +6 0 obj +<< +/Contents 14 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 12 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +7 0 obj +<< +/Contents 15 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 12 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +8 0 obj +<< +/Contents 16 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 12 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +9 0 obj +<< +/Contents 17 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 12 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +10 0 obj +<< +/PageMode /UseNone /Pages 12 0 R /Type /Catalog +>> +endobj +11 0 obj +<< +/Author (Codex) /CreationDate (D:20260412135420+05'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260412135420+05'00') /Producer (ReportLab PDF Library - \(opensource\)) + /Subject (\(unspecified\)) /Title (Protected PlayerPrefs Toolkit Documentation) /Trapped /False +>> +endobj +12 0 obj +<< +/Count 5 /Kids [ 5 0 R 6 0 R 7 0 R 8 0 R 9 0 R ] /Type /Pages +>> +endobj +13 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1830 +>> +stream +Gau`T9lo&I&A@sBlr!.@1r4+mQ;0X/8S@>,b4Leh!0`M_L]eOpZDrE3"\;7i/DKeb;qj*o9`iu'[r:.V9Ye\e@Xf.&^i+;(r'5c80OFg:]EmYL_#*rHNsdV!ZRgpJbOUIN$p=-D-Lg-W"c&IiILmh,Ufm&H4NX:J3/Y?kFro1Qj":d^0?IZfEgH,8RAHM4)t\1npObu!..n78b7!WI!4d7#pTiXIHqaB]%M%TW(Pa`bdD4gH$I&q&9";%gNlc(Y((01jeE]a,!qYk7s4&+M7;1&g(aHC)kMX>!"0sj[+>]nBgP;)i3;(@T=^%okP/04WC`:;NeWo'Q3G3Pt735XT+Gd]J@4(pR\=5H>5%?qQTr(2U@H*D#a#of44c(65VqlZ4^^P&%!uk*l+f$hanbp*?$/=hG-L9`,2hPLWoAocoN=KCPo/-r8Zc$n4ZICfcH[^QRWJRu,-A_j&%3p;@F/TdLW2o#PDjgD-?[8Jld.Z^-#RRUIhsl5"/IGZK8MrAdbaFj8.BM3?Lk!iLNk7u6Va,M6XK8dj1KB\K.^%KC%u:B;I#]i8d<`]p#?MhPP.%ALD\'MY&GG'W*7+L`6faF[XJf;WAc,BR]dJaTEn>'V>Njk9ASK"eDU>!g'[rNe(:DeH&tiF<7]&lT&#i!&\l:"Q,>1&iT:$gX39>VhU#M`O11G8u?S`CmJlVf2-[[3d)&M1on!rl#%eAbRc+Nbfe236$:pW6K0X.>;jb6&+#&pW5V0+A,"f%5/GK"ORLADr@2a[A"SB'O:1&hB:4WQ1/*k=nd*;#tB;d+WScPmt\jIKD8C?d^D^RHq?#]O=aDqF3Tp_YSGGJNF5G$9Sj!6V4B@AU2fO4tCRS)%l4$@nBC*T"8+[Q".AAP'Yb:'A.h.Y3o^kD*ahSFBS\-:Ld42>M.!cI+VmH:LkTnA>U2`Vhij&NlPqU6p5@.,JOqneX6m3-B'1tQg"_U]mPb_0NI09C8`[1MXu4%0]rVAW2loCWb6Y*p*"A:'%`)/%B(#"IMjjQS2QlrlP"cH+BHlIl>lLgom(9f^M'7?(".1dSE:gnDT.]aH337%`&Q$7dZAA*02MKj'o?WF1`%P\^cJ=o.ch'#a%f7[;;hW`XIS35W#kCtTo6:Ti+8l5uQ2s/W"3;VrF!EV'ghotdf3NldB4[V>+T0bGONWiSi6.m5HsDUTE^@!4R%.HW5Kh1C*8rW].kLoKZ-S/)&:.ul]H59;`qC(;i&HT6O*OYcJXE@4&%l;U,KX`:R%+],:Q2\>E$;8nIrcTSbmh=e5[&ePZoPe`r`^Sei"NcC*Q,;]dj>#oZ%rA1)0'NZ3nnUr1JQ)6oD#8>('!&SA"02UguPT,D8rBg\Tg9C+EeO9`IAVRQsK~>endstream +endobj +14 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1690 +>> +stream +Gb"/&>Ar7S'RnB33%-Jr*>1ik?/(Qi&(Y/qicYjW*b^tIfuTmT;K;[(G=]i]in0*C'^Np^+?%0UF8VTiU-F$p4T5=Ree1h1^ba,J_7.OL9$0I2+sHW7j^?SohpS46i;'C?iD;<"tf^!+Ck5\M,a?4:Rlik4n,F&%$,D4SVc[#J_a:_o6CLbOhm$q+$&N28(DKR!maY;#t/.O$#SoJ"8r/OgV>aEg*5dhG\q)SLQ43K+S;GKdAjLK+MbL_:^OKU;lKR`%<.FMXIKIJ4]T*@QUJ9Zp;J`959QUZ^S0n'bY6UNtqI/MOTiBapE!htO4e=q.DL`5)-TW;=;?Ko!WQAM-XANAkPc[amk$eu!%0c,G?`rPe&;1FYK(b"bhHd@Z`eI8Sh;jRAG2+9f;:,T6_p#MEuP_b6*tMXGi_=GB!.VW6O0gL0@bBi%2/RGf'[_A'.1rc5M)kNA!Onrkq)H,8dor,RI[6.iaDPAM(5/XX?o)DT3+4=>U88brZEZjY#mP0%"-aY4nD1IC]Bi5AoJIr8"V.5Ja[+RV,-]<3d07B8rE_b6't7.;l@0TjgX9eS23U,1r2OjSi)3'Bc'S_oe$J-hSJ_iP4)Ij7L^0>&2mM\(`D.-mkDT>l8a)P"WW>#SBbg/#,qeF[*=lpf`kiSkET2AJi^\@;Y.nr"]Nn3JFY?sHJ=JHh$kE#rW*!X[:'~>endstream +endobj +15 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1760 +>> +stream +Gau`UD/\/e&H;*)EaQ(n%\;d#q%!cFfkNI7IF@A0lELN!+K8^%mF>1;IG_k[c?'!#E7$V$Xj([Fc"?]O!K[R9:_/h!OLS$de])/8utXY'jA*h#k_H[nj(G(V3NrlV3)N".O4I?QDEDeDC'qagKH\RH&qITb`f+LS9LelGVgpL9\W;&!S1WcKrP$Mc6e(*_A.OI'1m`F>guf?[c>r@1f>YnHVX\p(-f*hMB<7haddCX*9XA.cuk<^14t=-MXtTT4mad0A@XGl+RlMGq`p?=r8?Q\fTj,jYuNJIC^J`43t_;j?>)D$0*0B\33lq8;c;&VWRCh`I&93C\j^m>25-CiV\gr#E\>5'3e\q:kR&td7A5P8lBIUU&rT[67Hn/A22l:fj+ro30'M\?7uJr(h]`jO&T"8.QN(%]KVgYQmOjmE0mBLljb52_JFj]5j;rIQHnP0;SGCBLFpdnQl8OIoU?'+<,kpKe=hW/Y2.\dn-\!.':j=a!*n9-nr.MNr)lg&j.NNY!F8+N#X6I6TLG#N08+>F$c2TMZZ#@Qoj:R-RBf,K&j4TAGMAS9])sm=9m(4?XGhSNe,&;K,<>m$uTU_.YMJ&.>WK,p5P:l[jY2"9cBo&@gYDJcL0:<[OcmI4Eu1mi]q<&m^'QN,4SrCK`%;\Ql6ABq=[M:'-7iB&dZ\GIntQGnhW,.%?NA5k;[A%Z_pahRL1^n8YjDQh-)(@H'UClPZ&l##js0@eu,SF!q/4*e(Uo@ruf60!oc9.Y2ba#K4EB%TVC[SfZhXC]O<$"(V5M58dd:d*RrbjaAYFLmM:k4I1g26W&ob1u4mMN6.e:4-<(:#9XOh92+Y9.J^mjdf>dhNnN1c9+endstream +endobj +16 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1656 +>> +stream +Gb"/'9on$e&A@P9R,bVG'N#sC+@=:umdGXoM#c9@j(H(*nn6:!e2(s=@I?eLAjhOZThZ65+c=[ZDa#&HJm;b^th"Aq4k<70g[1nFrY4:RL:l1'om%Doqi3"N9c!]E]WE(5/%k'%]jgi"qVnmR`lb_C@[2Dh$0Bq-B-Ra0f+AOU#r8ae1D(](f\.mj]@Wi`Wmd,G]jIWQ)-&i^:3@fh_US:]8XJ/qoOb+3>7p9*R(blW(3/MFP[/a-89FL>d5[o,(.GGE\cScnPI;j7J8?tR:YYWU-qaCQH#*u@"Z+n]1A@9N;Sc]$]Q$&XBl]J>hYSg#_FnE\B[4Y!%8@8A\g^%2WGUN]=I]Cn,(`jA8N.8?Y;KGDuom4im0,B`gfjkB-n74$Ntf[Emf%5%>(n6,s%mJD@>U1Z_A3Z2+f_HPWoc"j>)j632U=rOI9ZkeYJSmnKVgNJm-;j(la"5j=rl]@Y:n4S5Ji1es=YlpP^A15nrE8Yqus-/4;)nPi?1ko/NC<0^d$9#\]Mmclh\8`G,?gQds8G$dk?$Z4=$(CfFCA4dLt=E#/:CG\a)Dl_*%<@@A*7a(0iC4VMWc?#C%an8s=gNb`d?IQB+.`nnl$[dBoVmiE0-^rY(N("nC@ap(Vb8n8\De=ElV"^(>u"CRPk>pUART2l?GG]A1K9KiWVK^MJ?S3_Z`JZ.#W%c7c2#agG%aQc9In)_f'pS^NU]#0g;G>\)Y?4XGM-HO`$@e%p#@ILiG>LrN=l$58G"Zr`fAD#]1*Qib@njPiB(ns*D6NOk2D-ME3a&(%R(,3h,+1'/\s*KN2;;3ZQBf6GXhgkT$Hie'Y."Dh@FS5ldq*o?~>endstream +endobj +17 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1554 +>> +stream +Gb!$H9ip@5'ScA[MRuQ/>0$28*-MK4ZR?2"dWX*!@On]1[cNW^+THnn'ZW0A0EsX2i>h?LmC^$VrK+0K^r9Yis!@ob`<+%8!lT`1$:s(XYdfE`MmKU":)q9Y(P!/p"%$I9beH^Po?V%qKZ%jn5Or1pLCT_A;^`as!lk[16TNqF+8)O,'SgSQH*eSIO#h/'kY>E2*ukms'/p!'5-qTf?tq(R3cQrI*%$Y.Nt[sO:?[IH7ffA(.5X[S9Aq4q>:+86>:EY[O`.c/"VtHQnZ2I.-U9s6D%'5qS:VEC)3@mf5]!69[biS?iPZm8A8/?CCBdiaW=)aAWjsN>Eh0\Q3,h\C"tt'b`(ZU1^ph5,)h4PK>#Qeq;Zk>hnJ(q8h"<-[d^n8[d(goh1!+Kr7AGPNoeL/0'12;2IA$MN[WeAbiQoGUmm;_]*aZOUNT'$f_TchjP>JhMLT:$u*R/As5VcWg&lQ04FflJ+Q"CZ;U4sqg,pLbTK8M.$04aA?R'bUC\oI&bLiNdk-XI(=DfK7UmfMLJ-)#J1Iq1<[_+>=2^#hgN?.)o]F)*T_'=k5==M]`/)]U:X=^mu-O!lS*%V8UNqtiMf7Ifm[FYl=?BZ;.>0l3rYQ@b3GbtFM7@=f_cjGZ^(AVuO$CS%H95\e1i(C@g@:SbrXYCZ[.>32VXTD4`4U_^nj1Dt!q=PUL3t@kj.o?!a;:1UdX.(@H"Hi6e`N55fS#/b$_:"'lG(A:Wa7*J9?93'r>JTV/t;A:g_pM__&VQTdbnUHWbmU5q(rJl!>EKg.WR0CK>m\O'C=%;nrL[GH]08SJ'X++gK+(kIKj!uT<"k?^u`g7l\j(lA.j%`X7kB3bL_8^>=d^eTfIJi-E"*#O6rh(<$qh)ai5E"$.Zg>/h2X6"A*=CUA6Hji_\Ud*6fj`egaSbi.UcOsB-.OXZrTFB?U8&t0P]CT=\jO)lJ*l[/+"9E6I`:T.*j&o==Zo]fRa!eZ^"\EU2W8SJkdi.7paGugTQk8+h?tKKbA3n"Xa9O/VXCKH/h_7#g2YC(WP`;eP"gro(G=@_m"?niCqn3eD7qL1;MSn;0?lTrb4GQ^9h4fM]>/o`jK#E=4t!(0nTEZZ9c\?<9_[0uHeo'2G_<8gZU3I#j/+IHgV93^K!0EN%;QaMK:LR[$QEF)$n^^K7Xp3ssG/8dqU;gX6_54lS#dTLm/H5)5LN3WZ-l0MW"QFRs@bY0l>8_FcR70RoEoDtiK#b?Z-#&!`6)M@BkR9*Uo7")?2C`;~>endstream +endobj +xref +0 18 +0000000000 65535 f +0000000061 00000 n +0000000112 00000 n +0000000219 00000 n +0000000331 00000 n +0000000436 00000 n +0000000641 00000 n +0000000846 00000 n +0000001051 00000 n +0000001256 00000 n +0000001461 00000 n +0000001531 00000 n +0000001834 00000 n +0000001918 00000 n +0000003840 00000 n +0000005622 00000 n +0000007474 00000 n +0000009222 00000 n +trailer +<< +/ID +[] +% ReportLab generated PDF document -- digest (opensource) + +/Info 11 0 R +/Root 10 0 R +/Size 18 +>> +startxref +10868 +%%EOF diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs/ProtectedPlayerPrefsToolkit_Documentation.pdf.meta b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs/ProtectedPlayerPrefsToolkit_Documentation.pdf.meta new file mode 100644 index 0000000..fe436b7 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs/ProtectedPlayerPrefsToolkit_Documentation.pdf.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fad8e38235e6e45a3b3d7fecc3323ea7 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor.meta b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor.meta new file mode 100644 index 0000000..1d93f68 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: af3bb097acf624c119d24f77a7c70eb3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/Libs.PlayerPrefs.Editor.asmdef b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/Libs.PlayerPrefs.Editor.asmdef new file mode 100644 index 0000000..656b1ff --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/Libs.PlayerPrefs.Editor.asmdef @@ -0,0 +1,18 @@ +{ + "name": "Libs.PlayerPrefs.Editor", + "rootNamespace": "Darkmatter.Libs.PlayerPrefs.Editor", + "references": [ + "Libs.PlayerPrefs" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/Libs.PlayerPrefs.Editor.asmdef.meta b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/Libs.PlayerPrefs.Editor.asmdef.meta new file mode 100644 index 0000000..83ca69a --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/Libs.PlayerPrefs.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3f4f71cd22f5047c78946bd1928ea7b1 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/PlayerPrefsEditorWindow.cs b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/PlayerPrefsEditorWindow.cs new file mode 100644 index 0000000..dbdc6a6 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/PlayerPrefsEditorWindow.cs @@ -0,0 +1,559 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; +using UnityEditor; +using UnityEngine; + +namespace Darkmatter.Libs.PlayerPrefs.Editor +{ + public class PlayerPrefsEditorWindow : EditorWindow + { + private PlayerPrefsKeyRegistry _registry; + private Vector2 _scrollPos; + private Dictionary _editValues = new(); + private Dictionary _dirty = new(); + + // Add-key fields + private string _newKey = ""; + private PlayerPrefType _newType = PlayerPrefType.String; + private string _newDescription = ""; + + private enum Tab { Registered, Raw, Settings } + private Tab _currentTab = Tab.Registered; + + [MenuItem("Tools/Darkmatter/PlayerPrefs Editor")] + public static void Open() + { + var window = GetWindow("PlayerPrefs Editor"); + window.minSize = new Vector2(450, 300); + } + + private void OnEnable() + { + FindRegistry(); + } + + private void FindRegistry() + { + var guids = AssetDatabase.FindAssets("t:PlayerPrefsKeyRegistry"); + if (guids.Length > 0) + { + var path = AssetDatabase.GUIDToAssetPath(guids[0]); + _registry = AssetDatabase.LoadAssetAtPath(path); + } + } + + private void OnGUI() + { + DrawToolbar(); + + switch (_currentTab) + { + case Tab.Registered: + DrawRegisteredKeys(); + break; + case Tab.Raw: + DrawRawSection(); + break; + case Tab.Settings: + DrawSettings(); + break; + } + } + + // ── Toolbar ───────────────────────────────────────────── + + private void DrawToolbar() + { + EditorGUILayout.BeginHorizontal(EditorStyles.toolbar); + + if (GUILayout.Toggle(_currentTab == Tab.Registered, "Registered Keys", EditorStyles.toolbarButton)) + _currentTab = Tab.Registered; + if (GUILayout.Toggle(_currentTab == Tab.Raw, "Raw Lookup", EditorStyles.toolbarButton)) + _currentTab = Tab.Raw; + if (GUILayout.Toggle(_currentTab == Tab.Settings, "Settings", EditorStyles.toolbarButton)) + _currentTab = Tab.Settings; + + GUILayout.FlexibleSpace(); + + GUI.backgroundColor = new Color(1f, 0.4f, 0.4f); + if (GUILayout.Button("Delete All PlayerPrefs", EditorStyles.toolbarButton)) + { + if (EditorUtility.DisplayDialog( + "Delete All PlayerPrefs", + "This will permanently delete ALL PlayerPrefs (both regular and protected). Are you sure?", + "Delete All", "Cancel")) + { + UnityEngine.PlayerPrefs.DeleteAll(); + UnityEngine.PlayerPrefs.Save(); + _editValues.Clear(); + _dirty.Clear(); + } + } + GUI.backgroundColor = Color.white; + + EditorGUILayout.EndHorizontal(); + } + + // ── Registered Keys Tab ───────────────────────────────── + + private void DrawRegisteredKeys() + { + // Registry selector + EditorGUILayout.BeginHorizontal(); + _registry = (PlayerPrefsKeyRegistry)EditorGUILayout.ObjectField( + "Key Registry", _registry, typeof(PlayerPrefsKeyRegistry), false); + if (_registry == null && GUILayout.Button("Create", GUILayout.Width(60))) + { + CreateRegistry(); + } + EditorGUILayout.EndHorizontal(); + + if (_registry == null) + { + EditorGUILayout.HelpBox( + "Assign or create a PlayerPrefsKeyRegistry asset to manage keys.", + MessageType.Info); + return; + } + + EditorGUILayout.Space(4); + + // Add new key + DrawAddKeySection(); + + EditorGUILayout.Space(4); + + // Key list + _scrollPos = EditorGUILayout.BeginScrollView(_scrollPos); + + for (int i = _registry.Entries.Count - 1; i >= 0; i--) + { + var entry = _registry.Entries[i]; + DrawKeyEntry(entry, i); + } + + EditorGUILayout.EndScrollView(); + } + + private void DrawAddKeySection() + { + EditorGUILayout.LabelField("Register New Key", EditorStyles.boldLabel); + + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + + _newKey = EditorGUILayout.TextField("Key", _newKey); + _newType = (PlayerPrefType)EditorGUILayout.EnumPopup("Type", _newType); + _newDescription = EditorGUILayout.TextField("Description", _newDescription); + + EditorGUI.BeginDisabledGroup(string.IsNullOrWhiteSpace(_newKey)); + if (GUILayout.Button("Register Key")) + { + Undo.RecordObject(_registry, "Register PlayerPref Key"); + _registry.AddKey(_newKey, _newType, _newDescription); + EditorUtility.SetDirty(_registry); + _newKey = ""; + _newDescription = ""; + GenerateKeysClass(_generatedOutputPath); + } + EditorGUI.EndDisabledGroup(); + + EditorGUILayout.EndVertical(); + } + + private void DrawKeyEntry(PlayerPrefKeyEntry entry, int index) + { + EditorGUILayout.BeginVertical(EditorStyles.helpBox); + + // Header row + EditorGUILayout.BeginHorizontal(); + EditorGUILayout.LabelField(entry.Key, EditorStyles.boldLabel); + GUILayout.Label($"[{entry.Type}]", GUILayout.Width(50)); + + bool hasProtected = ProtectedPlayerPrefs.HasKey(entry.Key); + bool hasRaw = UnityEngine.PlayerPrefs.HasKey(entry.Key); + string source = hasProtected ? "Protected" : hasRaw ? "Raw" : "Not Set"; + GUILayout.Label(source, EditorStyles.miniLabel, GUILayout.Width(70)); + EditorGUILayout.EndHorizontal(); + + if (!string.IsNullOrEmpty(entry.Description)) + { + EditorGUILayout.LabelField(entry.Description, EditorStyles.miniLabel); + } + + // Value display/edit + string currentValue = GetCurrentValue(entry); + string editKey = $"{entry.Key}_{index}"; + + if (!_editValues.ContainsKey(editKey)) + _editValues[editKey] = currentValue; + + EditorGUILayout.BeginHorizontal(); + + string newVal = entry.Type switch + { + PlayerPrefType.Bool => EditorGUILayout.Toggle("Value", + _editValues[editKey] == "1" || _editValues[editKey].Equals("true", StringComparison.OrdinalIgnoreCase)) + ? "1" : "0", + _ => EditorGUILayout.TextField("Value", _editValues[editKey]) + }; + + if (newVal != _editValues[editKey]) + { + _editValues[editKey] = newVal; + _dirty[editKey] = true; + } + + EditorGUILayout.EndHorizontal(); + + // Action buttons + EditorGUILayout.BeginHorizontal(); + + EditorGUI.BeginDisabledGroup(!_dirty.ContainsKey(editKey) || !_dirty[editKey]); + if (GUILayout.Button("Save", GUILayout.Width(50))) + { + SaveValue(entry, _editValues[editKey]); + _dirty[editKey] = false; + GenerateKeysClass(_generatedOutputPath); + } + EditorGUI.EndDisabledGroup(); + + if (GUILayout.Button("Refresh", GUILayout.Width(60))) + { + _editValues[editKey] = GetCurrentValue(entry); + _dirty[editKey] = false; + } + + GUI.backgroundColor = new Color(1f, 0.6f, 0.4f); + if (GUILayout.Button("Delete Value", GUILayout.Width(80))) + { + ProtectedPlayerPrefs.DeleteKey(entry.Key); + UnityEngine.PlayerPrefs.DeleteKey(entry.Key); + UnityEngine.PlayerPrefs.Save(); + _editValues[editKey] = ""; + _dirty[editKey] = false; + } + + if (GUILayout.Button("Unregister", GUILayout.Width(80))) + { + Undo.RecordObject(_registry, "Unregister PlayerPref Key"); + _registry.RemoveKey(entry.Key); + EditorUtility.SetDirty(_registry); + _editValues.Remove(editKey); + _dirty.Remove(editKey); + GenerateKeysClass(_generatedOutputPath); + } + GUI.backgroundColor = Color.white; + + EditorGUILayout.EndHorizontal(); + EditorGUILayout.EndVertical(); + } + + private string GetCurrentValue(PlayerPrefKeyEntry entry) + { + // Try protected first, then raw + if (ProtectedPlayerPrefs.HasKey(entry.Key)) + { + return entry.Type switch + { + PlayerPrefType.String => ProtectedPlayerPrefs.GetString(entry.Key), + PlayerPrefType.Int => ProtectedPlayerPrefs.GetInt(entry.Key).ToString(), + PlayerPrefType.Float => ProtectedPlayerPrefs.GetFloat(entry.Key).ToString(), + PlayerPrefType.Bool => ProtectedPlayerPrefs.GetBool(entry.Key) ? "1" : "0", + _ => "" + }; + } + + if (UnityEngine.PlayerPrefs.HasKey(entry.Key)) + { + return entry.Type switch + { + PlayerPrefType.String => UnityEngine.PlayerPrefs.GetString(entry.Key), + PlayerPrefType.Int => UnityEngine.PlayerPrefs.GetInt(entry.Key).ToString(), + PlayerPrefType.Float => UnityEngine.PlayerPrefs.GetFloat(entry.Key).ToString(), + PlayerPrefType.Bool => UnityEngine.PlayerPrefs.GetInt(entry.Key) == 1 ? "1" : "0", + _ => "" + }; + } + + return ""; + } + + private void SaveValue(PlayerPrefKeyEntry entry, string value) + { + switch (entry.Type) + { + case PlayerPrefType.String: + ProtectedPlayerPrefs.SetString(entry.Key, value); + break; + case PlayerPrefType.Int: + if (int.TryParse(value, out var intVal)) + ProtectedPlayerPrefs.SetInt(entry.Key, intVal); + break; + case PlayerPrefType.Float: + if (float.TryParse(value, out var floatVal)) + ProtectedPlayerPrefs.SetFloat(entry.Key, floatVal); + break; + case PlayerPrefType.Bool: + ProtectedPlayerPrefs.SetBool(entry.Key, value == "1"); + break; + } + ProtectedPlayerPrefs.Save(); + } + + // ── Raw Lookup Tab ────────────────────────────────────── + + private string _rawKey = ""; + private string _rawValue = ""; + private string _rawType = "String"; + + private void DrawRawSection() + { + EditorGUILayout.LabelField("Raw PlayerPrefs Lookup", EditorStyles.boldLabel); + EditorGUILayout.HelpBox( + "Look up any PlayerPrefs key directly (unprotected). Useful for debugging third-party or legacy keys.", + MessageType.Info); + + _rawKey = EditorGUILayout.TextField("Key", _rawKey); + _rawType = EditorGUILayout.TextField("Type (String/Int/Float)", _rawType); + + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("Get")) + { + _rawValue = _rawType.ToLower() switch + { + "int" => UnityEngine.PlayerPrefs.GetInt(_rawKey).ToString(), + "float" => UnityEngine.PlayerPrefs.GetFloat(_rawKey).ToString(), + _ => UnityEngine.PlayerPrefs.GetString(_rawKey) + }; + } + + if (GUILayout.Button("Has Key?")) + { + _rawValue = UnityEngine.PlayerPrefs.HasKey(_rawKey) + ? "Key EXISTS" + : "Key NOT found"; + } + + if (GUILayout.Button("Delete")) + { + UnityEngine.PlayerPrefs.DeleteKey(_rawKey); + UnityEngine.PlayerPrefs.Save(); + _rawValue = "(deleted)"; + } + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.Space(4); + EditorGUILayout.LabelField("Result:", EditorStyles.boldLabel); + EditorGUILayout.SelectableLabel(_rawValue, EditorStyles.textArea, GUILayout.MinHeight(40)); + } + + // ── Settings Tab ──────────────────────────────────────── + + private string _generatedOutputPath = "Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PlayerPrefsKeys.cs"; + + private void DrawSettings() + { + EditorGUILayout.LabelField("Settings", EditorStyles.boldLabel); + + EditorGUILayout.Space(8); + + EditorGUILayout.LabelField("Registry Asset", EditorStyles.boldLabel); + _registry = (PlayerPrefsKeyRegistry)EditorGUILayout.ObjectField( + "Active Registry", _registry, typeof(PlayerPrefsKeyRegistry), false); + + EditorGUILayout.Space(8); + DrawProtectionSettings(); + + EditorGUILayout.Space(8); + EditorGUILayout.LabelField("Code Generation", EditorStyles.boldLabel); + EditorGUILayout.HelpBox( + "Generates a static PlayerPrefsKeys class so you can use PlayerPrefsKeys.Career.Level instead of string literals.", + MessageType.Info); + _generatedOutputPath = EditorGUILayout.TextField("Output Path", _generatedOutputPath); + + EditorGUI.BeginDisabledGroup(_registry == null || _registry.Entries.Count == 0); + if (GUILayout.Button("Generate PlayerPrefsKeys.cs")) + { + GenerateKeysClass(_generatedOutputPath); + } + EditorGUI.EndDisabledGroup(); + + EditorGUILayout.Space(8); + EditorGUILayout.LabelField("Danger Zone", EditorStyles.boldLabel); + + GUI.backgroundColor = new Color(1f, 0.3f, 0.3f); + if (GUILayout.Button("Delete ALL PlayerPrefs")) + { + if (EditorUtility.DisplayDialog( + "Delete All PlayerPrefs", + "This will permanently delete ALL PlayerPrefs. This cannot be undone.", + "Delete All", "Cancel")) + { + UnityEngine.PlayerPrefs.DeleteAll(); + UnityEngine.PlayerPrefs.Save(); + _editValues.Clear(); + _dirty.Clear(); + Debug.Log("[PlayerPrefs Editor] All PlayerPrefs deleted."); + } + } + GUI.backgroundColor = Color.white; + } + + private void DrawProtectionSettings() + { + EditorGUILayout.LabelField("Protection Setup", EditorStyles.boldLabel); + + var settingsAsset = global::Darkmatter.Libs.PlayerPrefs.Editor.ProtectedPlayerPrefsSettingsUtility.FindSettingsAsset(); + using (new EditorGUI.DisabledScope(true)) + { + EditorGUILayout.ObjectField( + "Settings Asset", + settingsAsset, + typeof(ProtectedPlayerPrefsSettings), + false); + } + + var status = settingsAsset != null && settingsAsset.HasConfiguredHash + ? "Configured" + : "Missing"; + EditorGUILayout.LabelField("Hash Password", status); + EditorGUILayout.LabelField("Runtime Source", ProtectedPlayerPrefs.InitializationSource); + + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("Open Getting Started")) + { + global::Darkmatter.Libs.PlayerPrefs.Editor.ProtectedPlayerPrefsGettingStartedWindow.OpenWindow(); + } + + EditorGUI.BeginDisabledGroup(settingsAsset == null); + if (GUILayout.Button("Ping Asset")) + { + EditorGUIUtility.PingObject(settingsAsset); + } + EditorGUI.EndDisabledGroup(); + + if (GUILayout.Button("Open Docs")) + { + global::Darkmatter.Libs.PlayerPrefs.Editor.ProtectedPlayerPrefsSettingsUtility.OpenDocumentationPdf(); + } + EditorGUILayout.EndHorizontal(); + } + + // ── Code Generation ───────────────────────────────────── + + private void GenerateKeysClass(string outputPath) + { + // Keys with a dot → nested class: "career.level" → PlayerPrefsKeys.Career.Level + // Keys without a dot → flat const on PlayerPrefsKeys directly: "volume" → PlayerPrefsKeys.Volume + var groups = new SortedDictionary>(); + var flat = new SortedDictionary(); + + foreach (var entry in _registry.Entries) + { + var dotIndex = entry.Key.IndexOf('.'); + if (dotIndex > 0) + { + var group = ToClassName(entry.Key.Substring(0, dotIndex)); + var member = ToConstName(entry.Key.Substring(dotIndex + 1)); + if (!groups.ContainsKey(group)) + groups[group] = new SortedDictionary(); + groups[group][member] = entry; + } + else + { + flat[ToConstName(entry.Key)] = entry; + } + } + + var sb = new StringBuilder(); + sb.AppendLine("// "); + sb.AppendLine("// Generated by PlayerPrefs Editor — do not edit by hand."); + sb.AppendLine("// Re-generate via Tools > Darkmatter > PlayerPrefs Editor > Settings."); + sb.AppendLine("// "); + sb.AppendLine(); + sb.AppendLine("namespace Darkmatter.Libs.PlayerPrefs"); + sb.AppendLine("{"); + sb.AppendLine(" public static class PlayerPrefsKeys"); + sb.AppendLine(" {"); + + foreach (var (constName, entry) in flat) + { + if (!string.IsNullOrEmpty(entry.Description)) + sb.AppendLine($" /// {entry.Description} ({entry.Type})"); + sb.AppendLine($" public const string {constName} = \"{entry.Key}\";"); + } + + if (flat.Count > 0 && groups.Count > 0) + sb.AppendLine(); + + foreach (var (groupName, members) in groups) + { + sb.AppendLine($" public static class {groupName}"); + sb.AppendLine(" {"); + foreach (var (constName, entry) in members) + { + if (!string.IsNullOrEmpty(entry.Description)) + sb.AppendLine($" /// {entry.Description} ({entry.Type})"); + sb.AppendLine($" public const string {constName} = \"{entry.Key}\";"); + } + sb.AppendLine(" }"); + sb.AppendLine(); + } + + sb.AppendLine(" }"); + sb.AppendLine("}"); + + var fullPath = Path.Combine( + Path.GetDirectoryName(Application.dataPath), + outputPath.TrimStart('/')); + + Directory.CreateDirectory(Path.GetDirectoryName(fullPath)); + File.WriteAllText(fullPath, sb.ToString(), Encoding.UTF8); + AssetDatabase.Refresh(); + + Debug.Log($"[PlayerPrefs Editor] Generated {outputPath}"); + } + + private static string ToClassName(string segment) + { + var clean = Regex.Replace(segment, @"[^a-zA-Z0-9_]", "_"); + return char.ToUpper(clean[0]) + clean.Substring(1); + } + + private static string ToConstName(string segment) + { + // "some.nested.key" → "SomeNestedKey" + var parts = segment.Split('.'); + var sb = new StringBuilder(); + foreach (var part in parts) + { + var clean = Regex.Replace(part, @"[^a-zA-Z0-9_]", "_"); + if (clean.Length == 0) continue; + sb.Append(char.ToUpper(clean[0])); + sb.Append(clean.Substring(1)); + } + return sb.ToString(); + } + + // ── Helpers ───────────────────────────────────────────── + + private void CreateRegistry() + { + var path = EditorUtility.SaveFilePanelInProject( + "Create PlayerPrefs Key Registry", + "PlayerPrefsKeyRegistry", + "asset", + "Choose where to save the registry asset."); + + if (string.IsNullOrEmpty(path)) return; + + var asset = CreateInstance(); + AssetDatabase.CreateAsset(asset, path); + AssetDatabase.SaveAssets(); + _registry = asset; + } + } +} diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/PlayerPrefsEditorWindow.cs.meta b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/PlayerPrefsEditorWindow.cs.meta new file mode 100644 index 0000000..8612942 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/PlayerPrefsEditorWindow.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b322d8950c37b4852a2ce171c9b96e5b \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsGettingStartedWindow.cs b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsGettingStartedWindow.cs new file mode 100644 index 0000000..b68f05d --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsGettingStartedWindow.cs @@ -0,0 +1,160 @@ +using UnityEditor; +using UnityEngine; + +namespace Darkmatter.Libs.PlayerPrefs.Editor +{ + public class ProtectedPlayerPrefsGettingStartedWindow : EditorWindow + { + private string _passphrase = string.Empty; + private string _confirmPassphrase = string.Empty; + private Vector2 _scrollPosition; + + [MenuItem("Tools/Darkmatter/Protected PlayerPrefs/Getting Started")] + public static void OpenWindow() + { + var window = GetWindow( + true, + "Protected PlayerPrefs Setup", + true); + window.minSize = new Vector2(520f, 520f); + } + + private void OnGUI() + { + _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition); + + EditorGUILayout.LabelField("Protected PlayerPrefs Setup", EditorStyles.boldLabel); + EditorGUILayout.Space(4); + EditorGUILayout.HelpBox( + "Set a project-specific hash password before shipping the package. The raw password is not stored - only its SHA-256 hash is saved in the settings asset.", + MessageType.Info); + + DrawChecklist(); + DrawSettingsSummary(); + DrawPassphraseForm(); + DrawActions(); + + EditorGUILayout.EndScrollView(); + } + + private static void DrawChecklist() + { + EditorGUILayout.LabelField("Before You Save", EditorStyles.boldLabel); + EditorGUILayout.LabelField("1. Use a unique project-specific password."); + EditorGUILayout.LabelField("2. Store it in your team password manager."); + EditorGUILayout.LabelField("3. Changing it later will make existing protected values unreadable."); + EditorGUILayout.Space(8); + } + + private static void DrawSettingsSummary() + { + EditorGUILayout.LabelField("Settings Asset", EditorStyles.boldLabel); + + var settingsAsset = ProtectedPlayerPrefsSettingsUtility.GetOrCreateSettingsAsset(); + using (new EditorGUI.DisabledScope(true)) + { + EditorGUILayout.ObjectField( + "Asset", + settingsAsset, + typeof(ProtectedPlayerPrefsSettings), + false); + EditorGUILayout.TextField("Path", ProtectedPlayerPrefsSettingsUtility.GetSettingsPath()); + } + + var status = settingsAsset.HasConfiguredHash + ? "Configured" + : "Hash password missing"; + EditorGUILayout.LabelField("Status", status); + EditorGUILayout.Space(8); + } + + private void DrawPassphraseForm() + { + EditorGUILayout.LabelField("Hash Password", EditorStyles.boldLabel); + _passphrase = EditorGUILayout.PasswordField("Password", _passphrase); + _confirmPassphrase = EditorGUILayout.PasswordField("Confirm", _confirmPassphrase); + + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("Generate Strong Password")) + { + _passphrase = ProtectedPlayerPrefsSettingsUtility.GenerateRandomPassphrase(); + _confirmPassphrase = _passphrase; + GUI.FocusControl(null); + } + + if (GUILayout.Button("Clear")) + { + _passphrase = string.Empty; + _confirmPassphrase = string.Empty; + GUI.FocusControl(null); + } + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.Space(8); + } + + private void DrawActions() + { + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("Save Hash Password", GUILayout.Height(32f))) + { + SaveHashPassword(); + } + + if (GUILayout.Button("Open PlayerPrefs Editor", GUILayout.Height(32f))) + { + PlayerPrefsEditorWindow.Open(); + } + EditorGUILayout.EndHorizontal(); + + EditorGUILayout.BeginHorizontal(); + if (GUILayout.Button("Ping Settings Asset")) + { + var settingsAsset = ProtectedPlayerPrefsSettingsUtility.GetOrCreateSettingsAsset(); + EditorGUIUtility.PingObject(settingsAsset); + } + + EditorGUI.BeginDisabledGroup(!ProtectedPlayerPrefsSettingsUtility.HasDocumentationPdf()); + if (GUILayout.Button("Open Package Docs")) + { + ProtectedPlayerPrefsSettingsUtility.OpenDocumentationPdf(); + } + EditorGUI.EndDisabledGroup(); + EditorGUILayout.EndHorizontal(); + } + + private void SaveHashPassword() + { + if (string.IsNullOrWhiteSpace(_passphrase)) + { + EditorUtility.DisplayDialog( + "Hash Password Required", + "Enter a password before saving the Protected PlayerPrefs settings.", + "OK"); + return; + } + + if (_passphrase.Length < 12) + { + EditorUtility.DisplayDialog( + "Password Too Short", + "Use at least 12 characters so the generated hash is project-specific and hard to guess.", + "OK"); + return; + } + + if (_passphrase != _confirmPassphrase) + { + EditorUtility.DisplayDialog( + "Passwords Do Not Match", + "The confirmation value does not match the password.", + "OK"); + return; + } + + ProtectedPlayerPrefsSettingsUtility.SavePassphrase(_passphrase); + ShowNotification(new GUIContent("Protected PlayerPrefs hash saved.")); + Close(); + } + } +} diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsGettingStartedWindow.cs.meta b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsGettingStartedWindow.cs.meta new file mode 100644 index 0000000..bd89938 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsGettingStartedWindow.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: b13eca0e3647841f58589a5146434751 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsSettingsUtility.cs b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsSettingsUtility.cs new file mode 100644 index 0000000..35cd050 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsSettingsUtility.cs @@ -0,0 +1,89 @@ +using System.IO; +using UnityEditor; +using UnityEngine; + +namespace Darkmatter.Libs.PlayerPrefs.Editor +{ + internal static class ProtectedPlayerPrefsSettingsUtility + { + internal const string DefaultSettingsDirectory = "Assets/Darkmatter/Data/Settings/Persistance/Resources"; + internal const string DefaultSettingsPath = DefaultSettingsDirectory + "/ProtectedPlayerPrefsSettings.asset"; + internal const string DocumentationPdfPath = + "Assets/Darkmatter/Code/Libs/PlayerPrefs/Docs/ProtectedPlayerPrefsToolkit_Documentation.pdf"; + + internal static ProtectedPlayerPrefsSettings FindSettingsAsset() + { + var guids = AssetDatabase.FindAssets("t:ProtectedPlayerPrefsSettings"); + if (guids.Length == 0) + { + return null; + } + + var path = AssetDatabase.GUIDToAssetPath(guids[0]); + return AssetDatabase.LoadAssetAtPath(path); + } + + internal static ProtectedPlayerPrefsSettings GetOrCreateSettingsAsset() + { + var existing = FindSettingsAsset(); + if (existing != null) + { + return existing; + } + + Directory.CreateDirectory(DefaultSettingsDirectory); + + var asset = ScriptableObject.CreateInstance(); + AssetDatabase.CreateAsset(asset, DefaultSettingsPath); + AssetDatabase.SaveAssets(); + return asset; + } + + internal static bool NeedsSetup() + { + var settings = GetOrCreateSettingsAsset(); + return !settings.HasConfiguredHash; + } + + internal static void SavePassphrase(string passphrase) + { + var settings = GetOrCreateSettingsAsset(); + var hashedPassphrase = ProtectedPlayerPrefs.ComputePassphraseHash(passphrase); + settings.SetHashedPassphrase(hashedPassphrase); + EditorUtility.SetDirty(settings); + AssetDatabase.SaveAssets(); + ProtectedPlayerPrefs.InitWithHash(hashedPassphrase); + } + + internal static string GetSettingsPath() + { + var settings = FindSettingsAsset(); + return settings == null ? DefaultSettingsPath : AssetDatabase.GetAssetPath(settings); + } + + internal static bool HasDocumentationPdf() + { + return File.Exists(Path.GetFullPath(DocumentationPdfPath)); + } + + internal static void OpenDocumentationPdf() + { + var absolutePath = Path.GetFullPath(DocumentationPdfPath); + if (!File.Exists(absolutePath)) + { + EditorUtility.DisplayDialog( + "Documentation Missing", + "The package PDF has not been generated yet.", + "OK"); + return; + } + + EditorUtility.OpenWithDefaultApp(absolutePath); + } + + internal static string GenerateRandomPassphrase() + { + return $"{System.Guid.NewGuid():N}{System.Guid.NewGuid():N}"; + } + } +} diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsSettingsUtility.cs.meta b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsSettingsUtility.cs.meta new file mode 100644 index 0000000..ed8bbbb --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsSettingsUtility.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e0a53d97fb18e40cf9c86a04e8ba50a8 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsSetupBootstrap.cs b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsSetupBootstrap.cs new file mode 100644 index 0000000..55cbe57 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsSetupBootstrap.cs @@ -0,0 +1,39 @@ +using UnityEditor; +using UnityEngine; + +namespace Darkmatter.Libs.PlayerPrefs.Editor +{ + [InitializeOnLoad] + internal static class ProtectedPlayerPrefsSetupBootstrap + { + private const string WindowShownSessionKey = + "Darkmatter.Libs.PlayerPrefs.Editor.ProtectedPlayerPrefsSetupBootstrap.WindowShown"; + + static ProtectedPlayerPrefsSetupBootstrap() + { + EditorApplication.delayCall += TryOpenSetupWindow; + } + + private static void TryOpenSetupWindow() + { + if (Application.isBatchMode || EditorApplication.isPlayingOrWillChangePlaymode) + { + return; + } + + if (SessionState.GetBool(WindowShownSessionKey, false)) + { + return; + } + + SessionState.SetBool(WindowShownSessionKey, true); + + if (!ProtectedPlayerPrefsSettingsUtility.NeedsSetup()) + { + return; + } + + ProtectedPlayerPrefsGettingStartedWindow.OpenWindow(); + } + } +} diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsSetupBootstrap.cs.meta b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsSetupBootstrap.cs.meta new file mode 100644 index 0000000..93e94f3 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Editor/ProtectedPlayerPrefsSetupBootstrap.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 696659b857f154ebca037ce7da9608eb \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime.meta b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime.meta new file mode 100644 index 0000000..1fd2823 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8f0ff6fb20d0d4f969c15e636a161c53 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/Libs.PlayerPrefs.asmdef b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/Libs.PlayerPrefs.asmdef new file mode 100644 index 0000000..b0e90b9 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/Libs.PlayerPrefs.asmdef @@ -0,0 +1,16 @@ +{ + "name": "Libs.PlayerPrefs", + "rootNamespace": "Darkmatter.Libs.PlayerPrefs", + "references": [ + "GUID:f51ebe6a0ceec4240a699833d6309b23" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/Libs.PlayerPrefs.asmdef.meta b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/Libs.PlayerPrefs.asmdef.meta new file mode 100644 index 0000000..63367cb --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/Libs.PlayerPrefs.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 564d11c0820a9455c8821cd85e9d0fd1 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/LocalWriteTracker.cs b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/LocalWriteTracker.cs new file mode 100644 index 0000000..0dc5fa5 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/LocalWriteTracker.cs @@ -0,0 +1,46 @@ +namespace Darkmatter.Libs.PlayerPrefs +{ + /// + /// Tracks whether a local PlayerPrefs value has unsynced writes or clears. + /// Prevents stale backend data from overwriting local state when the player + /// was offline during a write or clear operation. + /// + /// Usage: + /// - Before any local write: MarkPendingWrite(key) + /// - Before any local clear: MarkPendingClear(key) + /// - After a confirmed backend success: MarkSynced(key) + /// - On load: check GetState(key) before deciding whether remote wins + /// + public static class LocalWriteTracker + { + public enum WriteState + { + Synced = 0, + PendingWrite = 1, + PendingClear = 2 + } + + private static string StateKey(string dataKey) => $"{dataKey}.__wstate"; + + public static WriteState GetState(string key) + => (WriteState)ProtectedPlayerPrefs.GetInt(StateKey(key), (int)WriteState.Synced); + + public static void MarkPendingWrite(string key) + { + ProtectedPlayerPrefs.SetInt(StateKey(key), (int)WriteState.PendingWrite); + ProtectedPlayerPrefs.Save(); + } + + public static void MarkPendingClear(string key) + { + ProtectedPlayerPrefs.SetInt(StateKey(key), (int)WriteState.PendingClear); + ProtectedPlayerPrefs.Save(); + } + + public static void MarkSynced(string key) + { + ProtectedPlayerPrefs.SetInt(StateKey(key), (int)WriteState.Synced); + ProtectedPlayerPrefs.Save(); + } + } +} diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/LocalWriteTracker.cs.meta b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/LocalWriteTracker.cs.meta new file mode 100644 index 0000000..e770b97 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/LocalWriteTracker.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3f5a82e78f4c64d7094368a8ff06bdb6 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PendingWriteResync.cs b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PendingWriteResync.cs new file mode 100644 index 0000000..8d402b2 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PendingWriteResync.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using Cysharp.Threading.Tasks; +using UnityEngine; + +namespace Darkmatter.Libs.PlayerPrefs +{ + /// + /// Fire-and-forget retry for keys stuck in . + /// Single-flight per key. Uses so a caller-scoped + /// cancellation (e.g. load completing) won't abort an in-flight POST. + /// On success, marks the key synced. Exceptions are swallowed and logged. + /// + public static class PendingWriteResync + { + private static readonly HashSet InFlight = new(); + + [UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.SubsystemRegistration)] + static void ResetDomain() { lock (InFlight) InFlight.Clear(); } + + /// + /// Schedules a resync POST for if one isn't already running. + /// + /// Tracker key to mark synced on success. + /// POST closure; returns true on success. + public static void Schedule(string key, Func> post) + { + if (string.IsNullOrEmpty(key) || post == null) return; + + lock (InFlight) + { + if (!InFlight.Add(key)) return; + } + + RunAsync(key, post).Forget(); + } + + private static async UniTaskVoid RunAsync(string key, Func> post) + { + try + { + var ok = await post(CancellationToken.None); + if (ok) LocalWriteTracker.MarkSynced(key); + } + catch (Exception e) + { + Debug.LogWarning($"[PendingWriteResync] '{key}' failed: {e.Message}"); + } + finally + { + lock (InFlight) InFlight.Remove(key); + } + } + } +} diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PendingWriteResync.cs.meta b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PendingWriteResync.cs.meta new file mode 100644 index 0000000..c99e2e0 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PendingWriteResync.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: acc95e217aee14a7da0cfbdbf1358277 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PlayerPrefsKeyRegistry.cs b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PlayerPrefsKeyRegistry.cs new file mode 100644 index 0000000..5eb70e4 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PlayerPrefsKeyRegistry.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Darkmatter.Libs.PlayerPrefs +{ + public enum PlayerPrefType + { + String, + Int, + Float, + Bool + } + + [Serializable] + public class PlayerPrefKeyEntry + { + public string Key; + public PlayerPrefType Type; + public string Description; + } + + [CreateAssetMenu( + fileName = "PlayerPrefsKeyRegistry", + menuName = "Darkmatter/Libs/PlayerPrefs Key Registry")] + public class PlayerPrefsKeyRegistry : ScriptableObject + { + [SerializeField] private List _entries = new(); + + public IReadOnlyList Entries => _entries; + + public void AddKey(string key, PlayerPrefType type, string description = "") + { + if (_entries.Exists(e => e.Key == key)) return; + _entries.Add(new PlayerPrefKeyEntry + { + Key = key, + Type = type, + Description = description + }); + } + + public void RemoveKey(string key) + { + _entries.RemoveAll(e => e.Key == key); + } + } +} diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PlayerPrefsKeyRegistry.cs.meta b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PlayerPrefsKeyRegistry.cs.meta new file mode 100644 index 0000000..91c6d97 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PlayerPrefsKeyRegistry.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f8ac5d9908c8049e1a3c8b8ac108b5f5 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PlayerPrefsKeys.cs b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PlayerPrefsKeys.cs new file mode 100644 index 0000000..5dd25b7 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PlayerPrefsKeys.cs @@ -0,0 +1,51 @@ +// +// Generated by PlayerPrefs Editor — do not edit by hand. +// Re-generate via Tools > Darkmatter > PlayerPrefs Editor > Settings. +// + +namespace Darkmatter.Libs.PlayerPrefs +{ + public static class PlayerPrefsKeys + { + /// Saves the achievements which the user has unlocked (String) + public const string Achievements = "Achievements"; + public const string LocalLedger = "LocalLedger"; + + public static class Accounts + { + public const string SavedAuthRequest = "Accounts.SavedAuthRequest"; + } + + public static class Economy + { + /// Saves user's hard Currency (Int) + public const string Gold = "Economy.Gold"; + /// Saves User's soft currency (Int) + public const string Rupees = "Economy.Rupees"; + } + + public static class Garage + { + /// Json of ids of the user owned buses (String) + public const string OwnedBusIds = "Garage.OwnedBusIds"; + /// Id of the Bus that the user has selected (String) + public const string SelectedBusId = "Garage.SelectedBusId"; + } + + public static class Progression + { + /// Saves the user's Level (Int) + public const string Level = "Progression.Level"; + /// Saves Xp of the user (Int) + public const string Xp = "Progression.Xp"; + } + + public static class SaveGame + { + /// Saves the users session 's json (String) + public const string Session = "SaveGame.Session"; + public const string Vehicle = "SaveGame.Vehicle"; + } + + } +} diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PlayerPrefsKeys.cs.meta b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PlayerPrefsKeys.cs.meta new file mode 100644 index 0000000..66f1458 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/PlayerPrefsKeys.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2b42d435175264ee197e9f3d62858500 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/ProtectedPlayerPrefs.cs b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/ProtectedPlayerPrefs.cs new file mode 100644 index 0000000..4cb2944 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/ProtectedPlayerPrefs.cs @@ -0,0 +1,354 @@ +using System; +using System.Security.Cryptography; +using System.Text; +using UnityEngine; + +namespace Darkmatter.Libs.PlayerPrefs +{ + /// + /// Wrapper around Unity's PlayerPrefs that obscures keys and encrypts values + /// to discourage casual tampering via plist/registry editors. + /// + public static class ProtectedPlayerPrefs + { + private static byte[] s_key; + private static byte[] s_iv; + private static bool s_initialized; + private static bool s_missingSettingsWarningLogged; + + private const string DefaultPassphrase = "DM_BusGame_2026"; + private const string SettingsResourcePath = "ProtectedPlayerPrefsSettings"; + + public static bool IsUsingConfiguredHash { get; private set; } + public static string InitializationSource { get; private set; } = "Uninitialized"; + + /// + /// Initialize with a custom passphrase. Call once at startup. + /// If never called, the configured settings asset is used when present. + /// + public static void Init(string passphrase) + { + if (string.IsNullOrWhiteSpace(passphrase)) + { + throw new ArgumentException("Passphrase cannot be null or whitespace.", nameof(passphrase)); + } + + ApplyHash(HashPassphraseToBytes(passphrase), "ManualPassphrase", false); + } + + /// + /// Initialize from a precomputed SHA-256 hash generated by . + /// + public static void InitWithHash(string hashedPassphrase) + { + if (!TryParseHash(hashedPassphrase, out var hashBytes)) + { + throw new ArgumentException( + "Hashed passphrase must be a 64-character hexadecimal SHA-256 value.", + nameof(hashedPassphrase)); + } + + ApplyHash(hashBytes, "ManualHash", true); + } + + /// + /// Converts a user-facing passphrase into the SHA-256 hash stored in the settings asset. + /// + public static string ComputePassphraseHash(string passphrase) + { + if (string.IsNullOrWhiteSpace(passphrase)) + { + return string.Empty; + } + + return BytesToHex(HashPassphraseToBytes(passphrase)); + } + + private static void EnsureInitialized() + { + if (s_initialized) + { + return; + } + + if (TryInitializeFromSettings()) + { + return; + } + + ApplyHash(HashPassphraseToBytes(DefaultPassphrase), "DefaultFallback", false); + LogMissingSettingsWarning(); + } + + // ── String ────────────────────────────────────────────── + + public static void SetString(string key, string value) + { + EnsureInitialized(); + var encKey = HashKey(key); + var encVal = Encrypt(value ?? string.Empty); + UnityEngine.PlayerPrefs.SetString(encKey, encVal); + } + + public static string GetString(string key, string defaultValue = "") + { + EnsureInitialized(); + var encKey = HashKey(key); + if (!UnityEngine.PlayerPrefs.HasKey(encKey)) return defaultValue; + try + { + return Decrypt(UnityEngine.PlayerPrefs.GetString(encKey)); + } + catch + { + return defaultValue; + } + } + + // ── Int ───────────────────────────────────────────────── + + public static void SetInt(string key, int value) + { + SetString(key, value.ToString()); + } + + public static int GetInt(string key, int defaultValue = 0) + { + EnsureInitialized(); + var encKey = HashKey(key); + if (!UnityEngine.PlayerPrefs.HasKey(encKey)) return defaultValue; + try + { + var decrypted = Decrypt(UnityEngine.PlayerPrefs.GetString(encKey)); + return int.TryParse(decrypted, out var result) ? result : defaultValue; + } + catch + { + return defaultValue; + } + } + + // ── Float ─────────────────────────────────────────────── + + public static void SetFloat(string key, float value) + { + SetString(key, value.ToString("R")); + } + + public static float GetFloat(string key, float defaultValue = 0f) + { + EnsureInitialized(); + var encKey = HashKey(key); + if (!UnityEngine.PlayerPrefs.HasKey(encKey)) return defaultValue; + try + { + var decrypted = Decrypt(UnityEngine.PlayerPrefs.GetString(encKey)); + return float.TryParse(decrypted, out var result) ? result : defaultValue; + } + catch + { + return defaultValue; + } + } + + // ── Bool (convenience) ────────────────────────────────── + + public static void SetBool(string key, bool value) + { + SetInt(key, value ? 1 : 0); + } + + public static bool GetBool(string key, bool defaultValue = false) + { + EnsureInitialized(); + var encKey = HashKey(key); + if (!UnityEngine.PlayerPrefs.HasKey(encKey)) return defaultValue; + return GetInt(key, defaultValue ? 1 : 0) == 1; + } + + // ── Long (convenience) ────────────────────────────────── + public static void SetLong(string key, long value) + { + SetString(key, value.ToString()); + } + + public static long GetLong(string key, long defaultValue = 0L) + { + EnsureInitialized(); + var encKey = HashKey(key); + if (!UnityEngine.PlayerPrefs.HasKey(encKey)) return defaultValue; + try + { + var decrypted = Decrypt(UnityEngine.PlayerPrefs.GetString(encKey)); + return long.TryParse(decrypted, out var result) ? result : defaultValue; + } + catch + { + return defaultValue; + } + } + + // ── Queries ───────────────────────────────────────────── + + public static bool HasKey(string key) + { + EnsureInitialized(); + return UnityEngine.PlayerPrefs.HasKey(HashKey(key)); + } + + public static void DeleteKey(string key) + { + EnsureInitialized(); + UnityEngine.PlayerPrefs.DeleteKey(HashKey(key)); + } + + public static void DeleteAll() + { + UnityEngine.PlayerPrefs.DeleteAll(); + } + + public static void Save() + { + UnityEngine.PlayerPrefs.Save(); + } + + // ── Internal crypto ───────────────────────────────────── + + internal static string HashKey(string key) + { + EnsureInitialized(); + using var hmac = new HMACSHA256(s_key); + var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(key)); + return "pp_" + BitConverter.ToString(hash).Replace("-", "").Substring(0, 32).ToLowerInvariant(); + } + + private static bool TryInitializeFromSettings() + { + var settings = Resources.Load(SettingsResourcePath); + if (settings == null || !settings.HasConfiguredHash) + { + return false; + } + + if (!TryParseHash(settings.HashedPassphrase, out var hashBytes)) + { + Debug.LogWarning( + "[ProtectedPlayerPrefs] Settings asset contains an invalid hash. Falling back to the default passphrase."); + return false; + } + + ApplyHash(hashBytes, "SettingsAsset", true); + return true; + } + + private static void ApplyHash(byte[] hashBytes, string source, bool usingConfiguredHash) + { + s_key = new byte[16]; + s_iv = new byte[16]; + Array.Copy(hashBytes, 0, s_key, 0, 16); + Array.Copy(hashBytes, 16, s_iv, 0, 16); + s_initialized = true; + IsUsingConfiguredHash = usingConfiguredHash; + InitializationSource = source; + } + + private static byte[] HashPassphraseToBytes(string passphrase) + { + using var sha = SHA256.Create(); + return sha.ComputeHash(Encoding.UTF8.GetBytes(passphrase)); + } + + private static bool TryParseHash(string hashedPassphrase, out byte[] hashBytes) + { + hashBytes = null; + if (string.IsNullOrWhiteSpace(hashedPassphrase)) + { + return false; + } + + var normalized = hashedPassphrase.Trim(); + if (normalized.Length != 64) + { + return false; + } + + try + { + hashBytes = new byte[32]; + for (int index = 0; index < hashBytes.Length; index++) + { + var hexIndex = index * 2; + hashBytes[index] = Convert.ToByte(normalized.Substring(hexIndex, 2), 16); + } + + return hashBytes.Length == 32; + } + catch (Exception) + { + return false; + } + } + + private static string BytesToHex(byte[] bytes) + { + var builder = new StringBuilder(bytes.Length * 2); + foreach (var value in bytes) + { + builder.Append(value.ToString("x2")); + } + + return builder.ToString(); + } + + private static void LogMissingSettingsWarning() + { + if (s_missingSettingsWarningLogged) + { + return; + } + + s_missingSettingsWarningLogged = true; + Debug.LogWarning( + "[ProtectedPlayerPrefs] No configured hash password was found. Using the default fallback passphrase. Open Tools/Darkmatter/Protected PlayerPrefs/Getting Started to configure a project-specific hash."); + } + + [UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.SubsystemRegistration)] + static void ResetDomain() + { + s_key = null; + s_iv = null; + s_initialized = false; + s_missingSettingsWarningLogged = false; + IsUsingConfiguredHash = false; + InitializationSource = "Uninitialized"; + } + + private static string Encrypt(string plainText) + { + using var aes = Aes.Create(); + aes.Key = s_key; + aes.IV = s_iv; + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; + + using var encryptor = aes.CreateEncryptor(); + var plainBytes = Encoding.UTF8.GetBytes(plainText); + var cipherBytes = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length); + return Convert.ToBase64String(cipherBytes); + } + + internal static string Decrypt(string cipherText) + { + using var aes = Aes.Create(); + aes.Key = s_key; + aes.IV = s_iv; + aes.Mode = CipherMode.CBC; + aes.Padding = PaddingMode.PKCS7; + + using var decryptor = aes.CreateDecryptor(); + var cipherBytes = Convert.FromBase64String(cipherText); + var plainBytes = decryptor.TransformFinalBlock(cipherBytes, 0, cipherBytes.Length); + return Encoding.UTF8.GetString(plainBytes); + } + } +} \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/ProtectedPlayerPrefs.cs.meta b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/ProtectedPlayerPrefs.cs.meta new file mode 100644 index 0000000..f057dc7 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/ProtectedPlayerPrefs.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 57fbfc2c31a3b4977bd45a9211d73b38 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/ProtectedPlayerPrefsSettings.cs b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/ProtectedPlayerPrefsSettings.cs new file mode 100644 index 0000000..cdc590b --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/ProtectedPlayerPrefsSettings.cs @@ -0,0 +1,21 @@ +using UnityEngine; + +namespace Darkmatter.Libs.PlayerPrefs +{ + [CreateAssetMenu( + fileName = "ProtectedPlayerPrefsSettings", + menuName = "Darkmatter/Libs/Protected PlayerPrefs Settings")] + public class ProtectedPlayerPrefsSettings : ScriptableObject + { + [SerializeField] private string _hashedPassphrase; + + public string HashedPassphrase => _hashedPassphrase; + + public bool HasConfiguredHash => !string.IsNullOrWhiteSpace(_hashedPassphrase); + + public void SetHashedPassphrase(string hashedPassphrase) + { + _hashedPassphrase = (hashedPassphrase ?? string.Empty).Trim(); + } + } +} diff --git a/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/ProtectedPlayerPrefsSettings.cs.meta b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/ProtectedPlayerPrefsSettings.cs.meta new file mode 100644 index 0000000..856095f --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/PlayerPrefs/Runtime/ProtectedPlayerPrefsSettings.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: cfd2947542f794556827881bef2c9b73 \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/UI.meta b/Assets/Darkmatter/Code/Libs/UI.meta new file mode 100644 index 0000000..502ba89 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/UI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b610d653a5c38498394ce5b72e3a7e34 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/UI/Docs.meta b/Assets/Darkmatter/Code/Libs/UI/Docs.meta new file mode 100644 index 0000000..c407332 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/UI/Docs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ee2cb8a3aba984b298648c1bb1a5d8bc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/UI/Docs/UILib.md b/Assets/Darkmatter/Code/Libs/UI/Docs/UILib.md new file mode 100644 index 0000000..16485fa --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/UI/Docs/UILib.md @@ -0,0 +1,27 @@ +# UI Library + +Reusable UI components. + +## Components + +### ToggleButton + +A single-script toggle button with distinct "On" and "Off" visual states. + +#### Properties +- **onObject**: GameObject active when state is ON. +- **offObject**: GameObject active when state is OFF. +- **button**: The Unity UI Button component for interaction. +- **isOn**: Current state (can be set from Inspector). + +#### Events +- **OnValueChanged**: Action fired when the state changes. + +#### Usage Example + +```csharp +// Inside a parent presenter +view.MyToggle.OnValueChanged += (isOn) => { + Debug.Log($"Toggle is {isOn}"); +}; +``` diff --git a/Assets/Darkmatter/Code/Libs/UI/Docs/UILib.md.meta b/Assets/Darkmatter/Code/Libs/UI/Docs/UILib.md.meta new file mode 100644 index 0000000..f358009 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/UI/Docs/UILib.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c3c2446a0cfe04975b2dc693815bd03f +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/UI/Libs.UI.asmdef b/Assets/Darkmatter/Code/Libs/UI/Libs.UI.asmdef new file mode 100644 index 0000000..e0de398 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/UI/Libs.UI.asmdef @@ -0,0 +1,14 @@ +{ + "name": "Libs.UI", + "rootNamespace": "Darkmatter.Libs.UI", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Assets/Darkmatter/Code/Libs/UI/Libs.UI.asmdef.meta b/Assets/Darkmatter/Code/Libs/UI/Libs.UI.asmdef.meta new file mode 100644 index 0000000..90cc926 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/UI/Libs.UI.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3fef6c79ec73f4278abba9f13e29556e +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Darkmatter/Code/Libs/UI/ToggleButton.cs b/Assets/Darkmatter/Code/Libs/UI/ToggleButton.cs new file mode 100644 index 0000000..d141c05 --- /dev/null +++ b/Assets/Darkmatter/Code/Libs/UI/ToggleButton.cs @@ -0,0 +1,69 @@ +using System; +using UnityEngine; +using UnityEngine.UI; + +namespace Darkmatter.Libs.UI +{ + /// + /// A single reusable toggle button component. + /// Handles its own state and visual updates while exposing an event for Presenters. + /// + [RequireComponent(typeof(Button))] + public class ToggleButton : MonoBehaviour + { + [Header("States")] [SerializeField] private GameObject onObject; + [SerializeField] private GameObject offObject; + + private Button _button; + + [Header("Initial State")] [SerializeField] + private bool isOn; + + public event Action OnValueChanged; + + public bool IsOn + { + get => isOn; + set + { + if (isOn == value) return; + isOn = value; + UpdateVisuals(); + OnValueChanged?.Invoke(isOn); + } + } + + private void Awake() + { + _button = GetComponent