From 36840f3ad463ccd1b70fc08361c5a4096586d525 Mon Sep 17 00:00:00 2001 From: ThomasCharester Date: Sun, 20 Sep 2026 15:26:03 +0300 Subject: [PATCH] Second commit --- Assets/AddressableAssetsData.meta | 8 + .../AddressableAssetSettings.asset | 124 + .../AddressableAssetSettings.asset.meta | 8 + .../AssetGroupTemplates.meta | 8 + .../AssetGroupTemplates/Packed Assets.asset | 79 + .../Packed Assets.asset.meta | 8 + Assets/AddressableAssetsData/AssetGroups.meta | 8 + .../AssetGroups/Default Local Group.asset | 65 + .../Default Local Group.asset.meta | 8 + .../AssetGroups/Schemas.meta | 8 + ... Local Group_BundledAssetGroupSchema.asset | 48 + ...l Group_BundledAssetGroupSchema.asset.meta | 8 + ...Local Group_ContentUpdateGroupSchema.asset | 16 + ... Group_ContentUpdateGroupSchema.asset.meta | 8 + .../AddressableAssetsData/DataBuilders.meta | 8 + .../DataBuilders/BuildScriptFastMode.asset | 20 + .../BuildScriptFastMode.asset.meta | 8 + .../DataBuilders/BuildScriptPackedMode.asset | 20 + .../BuildScriptPackedMode.asset.meta | 8 + .../BuildScriptPackedPlayMode.asset | 20 + .../BuildScriptPackedPlayMode.asset.meta | 8 + .../AddressableAssetsData/DefaultObject.asset | 15 + .../DefaultObject.asset.meta | 8 + Assets/Code.meta | 8 + Assets/Code/D.meta | 3 + Assets/Code/D/CleanTools.meta | 3 + Assets/Code/D/CleanTools/CleanTool.cs | 31 + Assets/Code/D/CleanTools/CleanTool.cs.meta | 3 + Assets/Code/D/CleanTools/CleanToolConfig.cs | 15 + .../Code/D/CleanTools/CleanToolConfig.cs.meta | 3 + .../D/CleanTools/CleanToolInteractable.cs | 9 + .../CleanTools/CleanToolInteractable.cs.meta | 3 + Assets/Code/D/CleanTools/CleanToolType.cs | 7 + .../Code/D/CleanTools/CleanToolType.cs.meta | 3 + Assets/Code/D/CleanTools/DirtyToolCleaner.cs | 14 + .../D/CleanTools/DirtyToolCleaner.cs.meta | 3 + Assets/Code/D/CleanTools/ToolUsageInfo.cs | 11 + .../Code/D/CleanTools/ToolUsageInfo.cs.meta | 3 + Assets/Code/D/CleanTools/Tryapka.cs | 44 + Assets/Code/D/CleanTools/Tryapka.cs.meta | 3 + Assets/Code/D/Cleaning.meta | 3 + Assets/Code/D/Cleaning/Cleanable.cs | 11 + Assets/Code/D/Cleaning/Cleanable.cs.meta | 3 + Assets/Code/D/Cleaning/CleanableAsset.cs | 35 + Assets/Code/D/Cleaning/CleanableAsset.cs.meta | 3 + Assets/Code/D/Cleaning/CleanableSurface.cs | 490 +++ .../Code/D/Cleaning/CleanableSurface.cs.meta | 3 + Assets/Code/D/Cleaning/CleaningService.cs | 58 + .../Code/D/Cleaning/CleaningService.cs.meta | 3 + Assets/Code/D/Cleaning/Shaders.meta | 3 + .../D/Cleaning/Shaders/BrushPainter.shader | 85 + .../Cleaning/Shaders/BrushPainter.shader.meta | 3 + Assets/Code/D/Cleaning/UI.meta | 3 + Assets/Code/D/Cleaning/UI/CleanToolWidget.cs | 9 + .../D/Cleaning/UI/CleanToolWidget.cs.meta | 3 + Assets/Code/D/Cleaning/UI/CleaningPanel.cs | 31 + .../Code/D/Cleaning/UI/CleaningPanel.cs.meta | 3 + Assets/Code/D/Cleaning/UI/TryapkaWidget.cs | 43 + .../Code/D/Cleaning/UI/TryapkaWidget.cs.meta | 3 + Assets/Code/D/Player.meta | 3 + Assets/Code/D/Player/CleanerCameraState.cs | 93 + .../Code/D/Player/CleanerCameraState.cs.meta | 3 + Assets/Code/D/Player/Factory.meta | 3 + Assets/Code/D/Player/Factory/PlayerFactory.cs | 45 + .../D/Player/Factory/PlayerFactory.cs.meta | 3 + .../D/Player/Factory/PlayerFactorySettings.cs | 13 + .../Factory/PlayerFactorySettings.cs.meta | 3 + Assets/Code/D/Player/PlayerCameraTarget.cs | 13 + .../Code/D/Player/PlayerCameraTarget.cs.meta | 3 + .../Code/D/Player/PlayerControlsProvider.cs | 96 + .../D/Player/PlayerControlsProvider.cs.meta | 3 + .../Code/D/Player/PlayerDetailMaskDrawer.cs | 114 + .../D/Player/PlayerDetailMaskDrawer.cs.meta | 3 + Assets/Code/D/Player/PlayerEquipment.cs | 105 + Assets/Code/D/Player/PlayerEquipment.cs.meta | 3 + Assets/Code/D/Player/PlayerInteractor.cs | 64 + Assets/Code/D/Player/PlayerInteractor.cs.meta | 3 + .../Code/D/Player/PlayerMovementController.cs | 644 ++++ .../D/Player/PlayerMovementController.cs.meta | 3 + Assets/Code/Debug.meta | 3 + Assets/Code/Debug/StartFromBootstrap.cs | 20 + Assets/Code/Debug/StartFromBootstrap.cs.meta | 3 + Assets/Code/Debug/TestingLevel.meta | 3 + .../TestingLevelSceneInstaller.cs | 51 + .../TestingLevelSceneInstaller.cs.meta | 3 + .../Code/Debug/TestingLevel/TestingState.cs | 122 + .../Debug/TestingLevel/TestingState.cs.meta | 3 + Assets/Code/Debug/UVVisualizer.shader | 74 + Assets/Code/Debug/UVVisualizer.shader.meta | 3 + Assets/Code/Infrastructure.meta | 3 + Assets/Code/Infrastructure/App.meta | 8 + .../Infrastructure/App/AppStateMachine.cs | 33 + .../App/AppStateMachine.cs.meta | 3 + Assets/Code/Infrastructure/Audio.meta | 8 + .../Code/Infrastructure/Audio/AudioFactory.cs | 83 + .../Infrastructure/Audio/AudioFactory.cs.meta | 3 + Assets/Code/Infrastructure/Audio/AudioInfo.cs | 131 + .../Infrastructure/Audio/AudioInfo.cs.meta | 2 + .../Infrastructure/Audio/AudioInfoConfig.cs | 14 + .../Audio/AudioInfoConfig.cs.meta | 3 + .../Audio/AudioInfoLODedConfig.cs | 11 + .../Audio/AudioInfoLODedConfig.cs.meta | 2 + .../Audio/AudioInfoRandomConfig.cs | 11 + .../Audio/AudioInfoRandomConfig.cs.meta | 2 + .../Audio/AudioInfoSingleConfig.cs | 11 + .../Audio/AudioInfoSingleConfig.cs.meta | 2 + .../Audio/AudioMixerSettings.cs | 13 + .../Audio/AudioMixerSettings.cs.meta | 3 + .../Code/Infrastructure/Audio/AudioService.cs | 366 +++ .../Infrastructure/Audio/AudioService.cs.meta | 3 + .../Audio/AudioSourceFollower.cs | 15 + .../Audio/AudioSourceFollower.cs.meta | 3 + .../Infrastructure/Audio/AudioSourcePool.cs | 121 + .../Audio/AudioSourcePool.cs.meta | 3 + .../Infrastructure/Audio/AudioSourcePrefab.cs | 13 + .../Audio/AudioSourcePrefab.cs.meta | 3 + .../Audio/AudioSourceSettings.cs | 15 + .../Audio/AudioSourceSettings.cs.meta | 2 + Assets/Code/Infrastructure/Camera.meta | 8 + .../Infrastructure/Camera/CameraFactory.cs | 68 + .../Camera/CameraFactory.cs.meta | 3 + .../Camera/CameraStateMachine.cs | 36 + .../Camera/CameraStateMachine.cs.meta | 3 + .../Camera/CameraStateMachineRunner.cs | 15 + .../Camera/CameraStateMachineRunner.cs.meta | 3 + .../Infrastructure/Camera/CameraStates.meta | 3 + .../Camera/CameraStates/BaseCameraState.cs | 14 + .../CameraStates/BaseCameraState.cs.meta | 3 + .../Camera/CameraStates/NoneCameraState.cs | 22 + .../CameraStates/NoneCameraState.cs.meta | 3 + .../Code/Infrastructure/Camera/GameCamera.cs | 19 + .../Infrastructure/Camera/GameCamera.cs.meta | 3 + Assets/Code/Infrastructure/Configs.meta | 8 + .../Infrastructure/Configs/ConfigLocator.cs | 37 + .../Configs/ConfigLocator.cs.meta | 2 + .../Configs/ConfigReferences.cs | 9 + .../Configs/ConfigReferences.cs.meta | 2 + Assets/Code/Infrastructure/Generators.meta | 3 + .../Infrastructure/Generators/Attributes.cs | 48 + .../Generators/Attributes.cs.meta | 3 + .../Generators/AudioMixerGenerator.cs | 53 + .../Generators/AudioMixerGenerator.cs.meta | 3 + .../Generators/ConfigGenerator.cs | 79 + .../Generators/ConfigGenerator.cs.meta | 3 + .../Generators/StateMachineGenerator.cs | 105 + .../Generators/StateMachineGenerator.cs.meta | 3 + .../Generators/TypeExtensions.cs | 28 + .../Generators/TypeExtensions.cs.meta | 3 + Assets/Code/Infrastructure/Input.meta | 8 + .../Code/Infrastructure/Input/InputService.cs | 63 + .../Infrastructure/Input/InputService.cs.meta | 3 + .../Input/InputServiceConfig.cs | 13 + .../Input/InputServiceConfig.cs.meta | 3 + Assets/Code/Infrastructure/Loadings.meta | 8 + .../Code/Infrastructure/Loadings/Loading.cs | 104 + .../Infrastructure/Loadings/Loading.cs.meta | 3 + Assets/Code/Infrastructure/Particles.meta | 8 + .../Infrastructure/Particles/ParticleInfo.cs | 46 + .../Particles/ParticleInfo.cs.meta | 2 + .../Particles/ParticleLoader.cs | 110 + .../Particles/ParticleLoader.cs.meta | 2 + .../Particles/ParticlePoolManager.cs | 117 + .../Particles/ParticlePoolManager.cs.meta | 2 + .../Particles/ParticleService.cs | 56 + .../Particles/ParticleService.cs.meta | 2 + Assets/Code/Infrastructure/SceneLoader.meta | 8 + .../SceneLoader/CustomSceneManager.cs | 109 + .../SceneLoader/CustomSceneManager.cs.meta | 3 + .../Infrastructure/SceneLoader/SceneInfo.cs | 14 + .../SceneLoader/SceneInfo.cs.meta | 3 + .../SceneLoader/ScenesAssetReferences.cs | 9 + .../SceneLoader/ScenesAssetReferences.cs.meta | 3 + Assets/Code/Infrastructure/StateMachine.meta | 3 + .../StateMachine/AbstractStateMachine.cs | 52 + .../StateMachine/AbstractStateMachine.cs.meta | 3 + .../Infrastructure/StateMachine/BaseState.cs | 19 + .../StateMachine/BaseState.cs.meta | 3 + Assets/Code/Infrastructure/UI.meta | 8 + .../Code/Infrastructure/UI/CanvasSettings.cs | 18 + .../Infrastructure/UI/CanvasSettings.cs.meta | 3 + Assets/Code/Infrastructure/UI/UIFactory.cs | 118 + .../Code/Infrastructure/UI/UIFactory.cs.meta | 2 + Assets/Code/Infrastructure/UI/UIPanel.cs | 22 + Assets/Code/Infrastructure/UI/UIPanel.cs.meta | 2 + .../Code/Infrastructure/UI/UIPanelSettings.cs | 14 + .../Infrastructure/UI/UIPanelSettings.cs.meta | 2 + Assets/Code/Infrastructure/Utils.meta | 8 + .../Utils/AddressablesUtilities.cs | 30 + .../Utils/AddressablesUtilities.cs.meta | 3 + .../Infrastructure/Utils/ConfigUtility.cs | 61 + .../Utils/ConfigUtility.cs.meta | 3 + Assets/Code/Infrastructure/Utils/EnumUtil.cs | 17 + .../Infrastructure/Utils/EnumUtil.cs.meta | 3 + Assets/Code/Infrastructure/Volume.meta | 3 + .../Infrastructure/Volume/VolumeFactory.cs | 76 + .../Volume/VolumeFactory.cs.meta | 3 + .../Infrastructure/Volume/VolumeService.cs | 32 + .../Volume/VolumeService.cs.meta | 3 + .../Infrastructure/Volume/VolumeSettings.cs | 15 + .../Volume/VolumeSettings.cs.meta | 2 + Assets/Code/Musician.meta | 3 + Assets/Code/PapaInstaller.cs | 165 + Assets/Code/PapaInstaller.cs.meta | 3 + Assets/Code/Tests.meta | 3 + Assets/Code/Tests/Editor.meta | 3 + .../Code/Tests/Editor/CleaningToolsTests.cs | 23 + .../Tests/Editor/CleaningToolsTests.cs.meta | 3 + Assets/Code/UserDefinedEnums.meta | 3 + .../Code/UserDefinedEnums/ActionMappings.cs | 21 + .../UserDefinedEnums/ActionMappings.cs.meta | 3 + Assets/Code/UserDefinedEnums/AppStates.cs | 7 + .../Code/UserDefinedEnums/AppStates.cs.meta | 3 + .../Code/UserDefinedEnums/AudioGroupType.cs | 13 + .../UserDefinedEnums/AudioGroupType.cs.meta | 2 + Assets/Code/UserDefinedEnums/AudioLODLevel.cs | 10 + .../UserDefinedEnums/AudioLODLevel.cs.meta | 2 + .../Code/UserDefinedEnums/AudioPartition.cs | 9 + .../UserDefinedEnums/AudioPartition.cs.meta | 2 + .../Code/UserDefinedEnums/AudioSourceType.cs | 8 + .../UserDefinedEnums/AudioSourceType.cs.meta | 2 + .../UserDefinedEnums/ParticlePartition.cs | 8 + .../ParticlePartition.cs.meta | 2 + Assets/Code/UserDefinedEnums/SceneId.cs | 10 + Assets/Code/UserDefinedEnums/SceneId.cs.meta | 3 + Assets/Code/UserDefinedEnums/UIPanelType.cs | 8 + .../Code/UserDefinedEnums/UIPanelType.cs.meta | 2 + Assets/Code/UserDefinedEnums/VolumeId.cs | 7 + Assets/Code/UserDefinedEnums/VolumeId.cs.meta | 3 + Assets/Infrastructure.meta | 8 + Assets/Infrastructure/Audio.meta | 8 + .../Infrastructure/Audio/Audio Source.prefab | 131 + .../Audio/Audio Source.prefab.meta | 7 + .../Audio/AudioMixerSettings.asset | 15 + .../Audio/AudioMixerSettings.asset.meta | 8 + .../Audio/AudioSourcePrefab.asset | 20 + .../Audio/AudioSourcePrefab.asset.meta | 8 + .../Infrastructure/Audio/Full3DSource.asset | 16 + .../Audio/Full3DSource.asset.meta | 8 + Assets/Infrastructure/Audio/MainMixer.mixer | 181 ++ .../Infrastructure/Audio/MainMixer.mixer.meta | 8 + .../Infrastructure/Audio/NoBlendSource.asset | 16 + .../Audio/NoBlendSource.asset.meta | 8 + Assets/Infrastructure/Bootstrap.unity | 353 +++ Assets/Infrastructure/Bootstrap.unity.meta | 7 + Assets/Infrastructure/Camera.meta | 8 + Assets/Infrastructure/Camera/GameCamera.asset | 20 + .../Camera/GameCamera.asset.meta | 8 + Assets/Infrastructure/Input.meta | 8 + .../Input/ActionMap.inputactions | 776 +++++ .../Input/ActionMap.inputactions.meta | 14 + .../Infrastructure/Input/InputService.asset | 15 + .../Input/InputService.asset.meta | 8 + Assets/Infrastructure/UI.meta | 8 + Assets/Infrastructure/UI/BlankPanel.prefab | 37 + .../Infrastructure/UI/BlankPanel.prefab.meta | 7 + Assets/Infrastructure/UI/CanvasSettings.asset | 20 + .../UI/CanvasSettings.asset.meta | 8 + Assets/KinematicCharacterController.meta | 8 + .../APIReference.zip | Bin 0 -> 276699 bytes .../APIReference.zip.meta | 14 + Assets/KinematicCharacterController/Core.meta | 9 + .../Core/Editor.meta | 10 + .../Editor/KinematicCharacterMotorEditor.cs | 28 + .../KinematicCharacterMotorEditor.cs.meta | 20 + .../Core/Editor/ReadOnlyPropertyDrawer.cs | 21 + .../Editor/ReadOnlyPropertyDrawer.cs.meta | 20 + .../Core/ICharacterController.cs | 50 + .../Core/ICharacterController.cs.meta | 18 + .../Core/IMoverController.cs | 14 + .../Core/IMoverController.cs.meta | 18 + .../Core/KCCSettings.cs | 33 + .../Core/KCCSettings.cs.meta | 18 + .../Core/KinematicCharacterMotor.cs | 2691 +++++++++++++++++ .../Core/KinematicCharacterMotor.cs.meta | 18 + .../Core/KinematicCharacterSystem.cs | 294 ++ .../Core/KinematicCharacterSystem.cs.meta | 19 + .../Core/PhysicsMover.cs | 261 ++ .../Core/PhysicsMover.cs.meta | 19 + .../Core/ReadOnlyAttribute.cs | 8 + .../Core/ReadOnlyAttribute.cs.meta | 20 + Assets/NuGet.config | 18 + Assets/NuGet.config.meta | 28 + Assets/Packages.meta | 8 + .../Microsoft.Bcl.TimeProvider.8.0.0.meta | 8 + .../.signature.p7s | Bin 0 -> 24214 bytes .../Microsoft.Bcl.TimeProvider.8.0.0/Icon.png | 3 + .../Icon.png.meta | 117 + .../LICENSE.TXT | 23 + .../LICENSE.TXT.meta | 7 + .../Microsoft.Bcl.TimeProvider.nuspec | 32 + .../Microsoft.Bcl.TimeProvider.nuspec.meta | 7 + .../PACKAGE.md | 57 + .../PACKAGE.md.meta | 7 + .../THIRD-PARTY-NOTICES.TXT | 1272 ++++++++ .../THIRD-PARTY-NOTICES.TXT.meta | 7 + .../buildTransitive.meta | 8 + .../buildTransitive/net461.meta | 8 + .../net461/Microsoft.Bcl.TimeProvider.targets | 6 + .../Microsoft.Bcl.TimeProvider.targets.meta | 7 + .../buildTransitive/net462.meta | 8 + .../buildTransitive/net462/_._ | 0 .../buildTransitive/net462/_._.meta | 7 + .../buildTransitive/net6.0.meta | 8 + .../buildTransitive/net6.0/_._ | 0 .../buildTransitive/net6.0/_._.meta | 7 + .../buildTransitive/netcoreapp2.0.meta | 8 + .../Microsoft.Bcl.TimeProvider.targets | 6 + .../Microsoft.Bcl.TimeProvider.targets.meta | 7 + .../Microsoft.Bcl.TimeProvider.8.0.0/lib.meta | 8 + .../lib/netstandard2.0.meta | 8 + .../Microsoft.Bcl.TimeProvider.dll | Bin 0 -> 32416 bytes .../Microsoft.Bcl.TimeProvider.dll.meta | 29 + .../Microsoft.Bcl.TimeProvider.xml | 415 +++ .../Microsoft.Bcl.TimeProvider.xml.meta | 7 + .../useSharedDesignerContext.txt | 0 .../useSharedDesignerContext.txt.meta | 7 + .../Packages/ObservableCollections.3.3.4.meta | 8 + .../.signature.p7s | Bin 0 -> 12921 bytes .../ObservableCollections.3.3.4/Icon.png | 3 + .../ObservableCollections.3.3.4/Icon.png.meta | 117 + .../ObservableCollections.nuspec | 27 + .../ObservableCollections.nuspec.meta | 7 + .../ObservableCollections.3.3.4/lib.meta | 8 + .../lib/netstandard2.1.meta | 8 + .../netstandard2.1/ObservableCollections.dll | Bin 0 -> 155136 bytes .../ObservableCollections.dll.meta | 29 + .../netstandard2.1/ObservableCollections.xml | 391 +++ .../ObservableCollections.xml.meta | 7 + .../ObservableCollections.R3.3.3.4.meta | 8 + .../.signature.p7s | Bin 0 -> 12920 bytes .../ObservableCollections.R3.3.3.4/Icon.png | 3 + .../Icon.png.meta | 117 + .../ObservableCollections.R3.nuspec | 34 + .../ObservableCollections.R3.nuspec.meta | 7 + .../ObservableCollections.R3.3.3.4/lib.meta | 8 + .../lib/netstandard2.1.meta | 8 + .../ObservableCollections.R3.dll | Bin 0 -> 48640 bytes .../ObservableCollections.R3.dll.meta | 29 + .../ObservableCollections.R3.xml | 352 +++ .../ObservableCollections.R3.xml.meta | 7 + Assets/Packages/R3.1.3.1.meta | 8 + Assets/Packages/R3.1.3.1/.signature.p7s | Bin 0 -> 12982 bytes Assets/Packages/R3.1.3.1/Icon.png | 3 + Assets/Packages/R3.1.3.1/Icon.png.meta | 117 + Assets/Packages/R3.1.3.1/R3.nuspec | 37 + Assets/Packages/R3.1.3.1/R3.nuspec.meta | 7 + Assets/Packages/R3.1.3.1/README.md | 2328 ++++++++++++++ Assets/Packages/R3.1.3.1/README.md.meta | 7 + Assets/Packages/R3.1.3.1/lib.meta | 8 + .../Packages/R3.1.3.1/lib/netstandard2.1.meta | 8 + .../R3.1.3.1/lib/netstandard2.1/R3.dll | Bin 0 -> 601600 bytes .../R3.1.3.1/lib/netstandard2.1/R3.dll.meta | 29 + .../R3.1.3.1/lib/netstandard2.1/R3.xml | 446 +++ .../R3.1.3.1/lib/netstandard2.1/R3.xml.meta | 7 + ...stem.ComponentModel.Annotations.5.0.0.meta | 8 + .../.signature.p7s | Bin 0 -> 18711 bytes .../Icon.png | 3 + .../Icon.png.meta | 117 + .../LICENSE.TXT | 23 + .../LICENSE.TXT.meta | 7 + .../System.ComponentModel.Annotations.nuspec | 70 + ...tem.ComponentModel.Annotations.nuspec.meta | 7 + .../THIRD-PARTY-NOTICES.TXT | 884 ++++++ .../THIRD-PARTY-NOTICES.TXT.meta | 7 + .../lib.meta | 8 + .../lib/netstandard2.1.meta | 8 + .../System.ComponentModel.Annotations.dll | Bin 0 -> 89992 bytes ...System.ComponentModel.Annotations.dll.meta | 29 + .../System.ComponentModel.Annotations.xml | 1210 ++++++++ ...System.ComponentModel.Annotations.xml.meta | 7 + .../useSharedDesignerContext.txt | 0 .../useSharedDesignerContext.txt.meta | 7 + .../version.txt | 1 + .../version.txt.meta | 7 + .../System.Threading.Channels.8.0.0.meta | 8 + .../.signature.p7s | Bin 0 -> 24215 bytes .../System.Threading.Channels.8.0.0/Icon.png | 3 + .../Icon.png.meta | 117 + .../LICENSE.TXT | 23 + .../LICENSE.TXT.meta | 7 + .../PACKAGE.md | 73 + .../PACKAGE.md.meta | 7 + .../System.Threading.Channels.nuspec | 34 + .../System.Threading.Channels.nuspec.meta | 7 + .../THIRD-PARTY-NOTICES.TXT | 1272 ++++++++ .../THIRD-PARTY-NOTICES.TXT.meta | 7 + .../buildTransitive.meta | 8 + .../buildTransitive/net461.meta | 8 + .../net461/System.Threading.Channels.targets | 6 + .../System.Threading.Channels.targets.meta | 7 + .../buildTransitive/net462.meta | 8 + .../buildTransitive/net462/_._ | 0 .../buildTransitive/net462/_._.meta | 7 + .../buildTransitive/net6.0.meta | 8 + .../buildTransitive/net6.0/_._ | 0 .../buildTransitive/net6.0/_._.meta | 7 + .../buildTransitive/netcoreapp2.0.meta | 8 + .../System.Threading.Channels.targets | 6 + .../System.Threading.Channels.targets.meta | 7 + .../System.Threading.Channels.8.0.0/lib.meta | 8 + .../lib/netstandard2.1.meta | 8 + .../System.Threading.Channels.dll | Bin 0 -> 75952 bytes .../System.Threading.Channels.dll.meta | 29 + .../System.Threading.Channels.xml | 243 ++ .../System.Threading.Channels.xml.meta | 7 + .../useSharedDesignerContext.txt | 0 .../useSharedDesignerContext.txt.meta | 7 + Assets/Resources.meta | 8 + Assets/Resources/ConfigReferences.asset | 57 + Assets/Resources/ConfigReferences.asset.meta | 8 + Assets/Resources/ReflexSettings.asset | 17 + Assets/Resources/ReflexSettings.asset.meta | 8 + Assets/Resources/RootScope.prefab | 59 + Assets/Resources/RootScope.prefab.meta | 7 + Assets/Settings.meta | 8 + Assets/Settings/DefaultVolumeProfile.asset | 986 ++++++ .../Settings/DefaultVolumeProfile.asset.meta | 8 + Assets/Settings/Mobile_RPAsset.asset | 143 + Assets/Settings/Mobile_RPAsset.asset.meta | 8 + Assets/Settings/Mobile_Renderer.asset | 52 + Assets/Settings/Mobile_Renderer.asset.meta | 8 + Assets/Settings/PC_RPAsset.asset | 143 + Assets/Settings/PC_RPAsset.asset.meta | 8 + Assets/Settings/PC_Renderer.asset | 95 + Assets/Settings/PC_Renderer.asset.meta | 8 + Assets/Settings/SampleSceneProfile.asset | 159 + Assets/Settings/SampleSceneProfile.asset.meta | 8 + ...niversalRenderPipelineGlobalSettings.asset | 484 +++ ...salRenderPipelineGlobalSettings.asset.meta | 8 + Assets/Tremble Sync Settings.asset | 76 + Assets/Tremble Sync Settings.asset.meta | 8 + Assets/Tremble.meta | 8 + Assets/Tremble/AssetLoading.meta | 3 + Assets/Tremble/AssetLoading/Adaptors.meta | 3 + .../Adaptors/AddressablesLoaderAdaptor.cs | 159 + .../AddressablesLoaderAdaptor.cs.meta | 10 + .../Adaptors/EditorLoaderAdaptor.cs | 105 + .../Adaptors/EditorLoaderAdaptor.cs.meta | 10 + .../Adaptors/IAssetLoaderAdaptor.cs | 36 + .../Adaptors/IAssetLoaderAdaptor.cs.meta | 10 + .../Adaptors/NullLoaderAdaptor.cs | 61 + .../Adaptors/NullLoaderAdaptor.cs.meta | 10 + .../AssetLoading/TrembleAssetLoader.cs | 170 ++ .../AssetLoading/TrembleAssetLoader.cs.meta | 10 + Assets/Tremble/Attributes.meta | 3 + Assets/Tremble/Attributes/Classes.meta | 3 + .../Classes/BrushEntityAttribute.cs | 73 + .../Classes/BrushEntityAttribute.cs.meta | 10 + .../Attributes/Classes/EntityAttributeBase.cs | 26 + .../Classes/EntityAttributeBase.cs.meta | 10 + .../Classes/PointEntityAttribute.cs | 41 + .../Classes/PointEntityAttribute.cs.meta | 10 + .../Classes/PrefabEntityAttribute.cs | 71 + .../Classes/PrefabEntityAttribute.cs.meta | 10 + .../Attributes/Classes/SimpleRegexUtil.cs | 19 + .../Classes/SimpleRegexUtil.cs.meta | 10 + Assets/Tremble/Attributes/Fields.meta | 3 + .../Attributes/Fields/SpawnFlagsAttribute.cs | 36 + .../Fields/SpawnFlagsAttribute.cs.meta | 10 + .../Attributes/Fields/TrembleAttribute.cs | 39 + .../Fields/TrembleAttribute.cs.meta | 10 + Assets/Tremble/Editor.meta | 9 + Assets/Tremble/Editor/AssetImporters.meta | 3 + .../AssetImporters/FgdFileAssetImporter.cs | 31 + .../FgdFileAssetImporter.cs.meta | 10 + .../AssetImporters/TrembleMapAssetImporter.cs | 231 ++ .../TrembleMapAssetImporter.cs.meta | 10 + .../AssetImporters/WadFileAssetImporter.cs | 42 + .../WadFileAssetImporter.cs.meta | 10 + Assets/Tremble/Editor/AssetProcessors.meta | 3 + .../FgdFileAssetPostprocessor.cs | 39 + .../FgdFileAssetPostprocessor.cs.meta | 10 + .../MapFileAssetPostprocessor.cs | 146 + .../MapFileAssetPostprocessor.cs.meta | 10 + .../MapLiveUpdatePostprocessor.cs | 202 ++ .../MapLiveUpdatePostprocessor.cs.meta | 10 + .../TrembleCacheDropperPostprocessor.cs | 22 + .../TrembleCacheDropperPostprocessor.cs.meta | 10 + .../WadFileAssetPostprocessor.cs | 38 + .../WadFileAssetPostprocessor.cs.meta | 10 + Assets/Tremble/Editor/EditorUI.meta | 3 + .../Editor/EditorUI/DiagnosticsWindow.cs | 146 + .../Editor/EditorUI/DiagnosticsWindow.cs.meta | 10 + Assets/Tremble/Editor/EditorUI/Drawers.meta | 3 + .../EditorUI/Drawers/BaseClassPickerDrawer.cs | 125 + .../Drawers/BaseClassPickerDrawer.cs.meta | 10 + .../Drawers/MapProcessorClassDrawer.cs | 15 + .../Drawers/MapProcessorClassDrawer.cs.meta | 10 + .../Drawers/WorldspawnScriptDrawer.cs | 15 + .../Drawers/WorldspawnScriptDrawer.cs.meta | 10 + Assets/Tremble/Editor/EditorUI/Editors.meta | 3 + .../Editors/WadAssetImporterEditor.cs | 139 + .../Editors/WadAssetImporterEditor.cs.meta | 10 + .../Editor/EditorUI/MapHierarchyIcons.cs | 141 + .../Editor/EditorUI/MapHierarchyIcons.cs.meta | 10 + .../Editor/EditorUI/MapRepairWindow.cs | 642 ++++ .../Editor/EditorUI/MapRepairWindow.cs.meta | 10 + Assets/Tremble/Editor/EditorUI/Materials.meta | 3 + .../Materials/MaterialInspectorGUI.cs | 198 ++ .../Materials/MaterialInspectorGUI.cs.meta | 10 + .../Materials/NewMaterialGroupWindow.cs | 90 + .../Materials/NewMaterialGroupWindow.cs.meta | 10 + .../Editor/EditorUI/Q3Map2OutputWindow.cs | 142 + .../EditorUI/Q3Map2OutputWindow.cs.meta | 18 + Assets/Tremble/Editor/EditorUI/Settings.meta | 3 + .../TrembleProjectSettingsProvider.cs | 126 + .../TrembleProjectSettingsProvider.cs.meta | 10 + .../Settings/TrembleSyncSettingsEditor.cs | 1031 +++++++ .../TrembleSyncSettingsEditor.cs.meta | 10 + .../Tremble/Editor/EditorUI/TrembleIcons.cs | 226 ++ .../Editor/EditorUI/TrembleIcons.cs.meta | 10 + .../Editor/EditorUI/TrembleSyncOverlay.cs | 79 + .../EditorUI/TrembleSyncOverlay.cs.meta | 10 + Assets/Tremble/Editor/EditorUI/Utils.meta | 3 + .../EditorUI/Utils/EditorGUILayoutUtil.cs | 117 + .../Utils/EditorGUILayoutUtil.cs.meta | 10 + .../Utils/EditorGameObjectIconUtil.cs | 81 + .../Utils/EditorGameObjectIconUtil.cs.meta | 10 + .../EditorUI/Utils/MaterialGroupUtil.cs | 154 + .../EditorUI/Utils/MaterialGroupUtil.cs.meta | 10 + .../EditorUI/Utils/MaterialRenderDataUtil.cs | 31 + .../Utils/MaterialRenderDataUtil.cs.meta | 18 + .../EditorUI/Utils/TrembleSettingsGUI.cs | 391 +++ .../EditorUI/Utils/TrembleSettingsGUI.cs.meta | 10 + Assets/Tremble/Editor/Icons.meta | 8 + Assets/Tremble/Editor/Icons/T_TB_Config.png | 3 + .../Tremble/Editor/Icons/T_TB_Config.png.meta | 176 ++ Assets/Tremble/Editor/Icons/T_TB_Import.png | 3 + .../Tremble/Editor/Icons/T_TB_Import.png.meta | 160 + Assets/Tremble/Editor/Icons/T_TB_Manual.png | 3 + .../Tremble/Editor/Icons/T_TB_Manual.png.meta | 176 ++ Assets/Tremble/Editor/Icons/T_TB_Sync.png | 3 + .../Tremble/Editor/Icons/T_TB_Sync.png.meta | 160 + Assets/Tremble/Editor/Icons/T_TrembleLogo.png | 3 + .../Editor/Icons/T_TrembleLogo.png.meta | 164 + Assets/Tremble/Editor/Manual.meta | 3 + .../Tremble/Editor/Manual/FNT_UbuntuMono.ttf | Bin 0 -> 205748 bytes .../Editor/Manual/FNT_UbuntuMono.ttf.meta | 28 + Assets/Tremble/Editor/Manual/ManualEntry.cs | 34 + .../Tremble/Editor/Manual/ManualEntry.cs.meta | 10 + .../Tremble/Editor/Manual/ManualImages.meta | 8 + .../ManualImages/T_Manual_BrushEntity.png | 3 + .../T_Manual_BrushEntity.png.meta | 176 ++ .../ManualImages/T_Manual_CreateMap.png | 3 + .../ManualImages/T_Manual_CreateMap.png.meta | 176 ++ .../ManualImages/T_Manual_LiveUpdate1.png | 3 + .../T_Manual_LiveUpdate1.png.meta | 176 ++ .../ManualImages/T_Manual_LiveUpdate2.png | 3 + .../T_Manual_LiveUpdate2.png.meta | 176 ++ .../ManualImages/T_Manual_MapProcessor.png | 3 + .../T_Manual_MapProcessor.png.meta | 176 ++ .../ManualImages/T_Manual_MapRepair.png | 3 + .../ManualImages/T_Manual_MapRepair.png.meta | 176 ++ .../T_Manual_MapRepair_Entities.png | 3 + .../T_Manual_MapRepair_Entities.png.meta | 176 ++ .../ManualImages/T_Manual_MapRepair_NoFGD.png | 3 + .../T_Manual_MapRepair_NoFGD.png.meta | 176 ++ .../T_Manual_MapRepair_Required.png | 3 + .../T_Manual_MapRepair_Required.png.meta | 176 ++ .../T_Manual_MapRepair_Textures.png | 3 + .../T_Manual_MapRepair_Textures.png.meta | 176 ++ .../T_Manual_MapRepair_WithFGD.png | 3 + .../T_Manual_MapRepair_WithFGD.png.meta | 176 ++ .../ManualImages/T_Manual_MaterialGroups.png | 3 + .../T_Manual_MaterialGroups.png.meta | 176 ++ .../ManualImages/T_Manual_MissingGeo_TB1.png | 3 + .../T_Manual_MissingGeo_TB1.png.meta | 121 + .../ManualImages/T_Manual_MissingGeo_TB2.png | 3 + .../T_Manual_MissingGeo_TB2.png.meta | 121 + .../T_Manual_MissingGeo_Unity1.png | 3 + .../T_Manual_MissingGeo_Unity1.png.meta | 121 + .../T_Manual_MissingGeo_Unity2.png | 3 + .../T_Manual_MissingGeo_Unity2.png.meta | 121 + .../Manual/ManualImages/T_Manual_Pipeline.png | 3 + .../ManualImages/T_Manual_Pipeline.png.meta | 163 + .../ManualImages/T_Manual_PointEntity.png | 3 + .../T_Manual_PointEntity.png.meta | 176 ++ .../ManualImages/T_Manual_PrefabEntity.png | 3 + .../T_Manual_PrefabEntity.png.meta | 176 ++ .../ManualImages/T_Manual_RenderSettings.png | 3 + .../T_Manual_RenderSettings.png.meta | 137 + .../ManualImages/T_Manual_SpawnablePrefab.png | 3 + .../T_Manual_SpawnablePrefab.png.meta | 176 ++ .../ManualImages/T_Manual_Trouble_DLL1.png | 3 + .../T_Manual_Trouble_DLL1.png.meta | 176 ++ .../ManualImages/T_Manual_Trouble_DLL2.png | 3 + .../T_Manual_Trouble_DLL2.png.meta | 176 ++ ...T_Manual_Trouble_FixPinkMaterialsVideo.png | 3 + ...ual_Trouble_FixPinkMaterialsVideo.png.meta | 176 ++ .../T_Manual_Trouble_MaterialBrightness.png | 3 + ...Manual_Trouble_MaterialBrightness.png.meta | 176 ++ ...ual_Trouble_MaterialBrightnessSettings.png | 3 + ...rouble_MaterialBrightnessSettings.png.meta | 176 ++ .../T_Manual_Trouble_PinkMaterials.png | 3 + .../T_Manual_Trouble_PinkMaterials.png.meta | 176 ++ .../ManualImages/T_Manual_WadImport2.png | 3 + .../ManualImages/T_Manual_WadImport2.png.meta | 176 ++ .../Editor/Manual/ManualPageAttribute.cs | 32 + .../Editor/Manual/ManualPageAttribute.cs.meta | 10 + .../Tremble/Editor/Manual/ManualPageBase.cs | 389 +++ .../Editor/Manual/ManualPageBase.cs.meta | 10 + Assets/Tremble/Editor/Manual/ManualStyles.cs | 112 + .../Editor/Manual/ManualStyles.cs.meta | 10 + Assets/Tremble/Editor/Manual/ManualWindow.cs | 558 ++++ .../Editor/Manual/ManualWindow.cs.meta | 10 + Assets/Tremble/Editor/Manual/Pages.meta | 3 + .../Tremble/Editor/Manual/Pages/Advanced.meta | 3 + .../Manual/Pages/Advanced/BaseClassesPage.cs | 90 + .../Pages/Advanced/BaseClassesPage.cs.meta | 10 + .../Manual/Pages/Advanced/CustomTypesPage.cs | 120 + .../Pages/Advanced/CustomTypesPage.cs.meta | 10 + .../Manual/Pages/Advanced/MapProcessorPage.cs | 97 + .../Pages/Advanced/MapProcessorPage.cs.meta | 10 + .../Advanced/OnImportFromMapEntityPage.cs | 58 + .../OnImportFromMapEntityPage.cs.meta | 10 + .../Manual/Pages/Advanced/PipelinePage.cs | 40 + .../Pages/Advanced/PipelinePage.cs.meta | 10 + .../Pages/Advanced/RuntimeQueryingPage.cs | 73 + .../Advanced/RuntimeQueryingPage.cs.meta | 10 + .../Tremble/Editor/Manual/Pages/Basics.meta | 3 + .../Manual/Pages/Basics/CreateMapPage.cs | 49 + .../Manual/Pages/Basics/CreateMapPage.cs.meta | 10 + .../Manual/Pages/Basics/LiveUpdatePage.cs | 105 + .../Pages/Basics/LiveUpdatePage.cs.meta | 10 + .../Manual/Pages/Basics/SettingsPage.cs | 27 + .../Manual/Pages/Basics/SettingsPage.cs.meta | 10 + .../Manual/Pages/Basics/SyncOverlayPage.cs | 71 + .../Pages/Basics/SyncOverlayPage.cs.meta | 10 + Assets/Tremble/Editor/Manual/Pages/Debug.meta | 3 + .../Pages/Debug/DebugSanityCheckPage.cs | 181 ++ .../Pages/Debug/DebugSanityCheckPage.cs.meta | 10 + .../Pages/Debug/DebugShowEntitiesPage.cs | 68 + .../Pages/Debug/DebugShowEntitiesPage.cs.meta | 10 + .../Pages/Debug/DebugShowMaterialsPage.cs | 112 + .../Debug/DebugShowMaterialsPage.cs.meta | 10 + .../Tremble/Editor/Manual/Pages/Entities.meta | 3 + .../Pages/Entities/BrushEntitiesPage.cs | 62 + .../Pages/Entities/BrushEntitiesPage.cs.meta | 10 + .../Manual/Pages/Entities/BuilderPageBase.cs | 94 + .../Pages/Entities/BuilderPageBase.cs.meta | 10 + .../Manual/Pages/Entities/Builders.meta | 3 + .../Entities/Builders/BrushBuilderPage.cs | 158 + .../Builders/BrushBuilderPage.cs.meta | 10 + .../Entities/Builders/PointBuilderPage.cs | 163 + .../Builders/PointBuilderPage.cs.meta | 10 + .../Entities/Builders/PrefabBuilderPage.cs | 592 ++++ .../Builders/PrefabBuilderPage.cs.meta | 10 + .../Pages/Entities/EntitiesOverviewPage.cs | 49 + .../Entities/EntitiesOverviewPage.cs.meta | 10 + .../Pages/Entities/PointEntitiesPage.cs | 51 + .../Pages/Entities/PointEntitiesPage.cs.meta | 10 + .../Editor/Manual/Pages/Entities/Prefabs.meta | 3 + .../Entities/Prefabs/PrefabEntitiesPage.cs | 54 + .../Prefabs/PrefabEntitiesPage.cs.meta | 10 + .../Entities/Prefabs/SpawnablePrefabsPage.cs | 40 + .../Prefabs/SpawnablePrefabsPage.cs.meta | 10 + .../Editor/Manual/Pages/MapRepairPage.cs | 37 + .../Editor/Manual/Pages/MapRepairPage.cs.meta | 10 + .../Editor/Manual/Pages/Materials.meta | 3 + .../Pages/Materials/MaterialGroupsPage.cs | 138 + .../Materials/MaterialGroupsPage.cs.meta | 10 + .../Pages/Materials/MaterialRenderDataPage.cs | 71 + .../Materials/MaterialRenderDataPage.cs.meta | 10 + .../Pages/Materials/MaterialsAboutPage.cs | 57 + .../Materials/MaterialsAboutPage.cs.meta | 10 + .../Editor/Manual/Pages/OtherGames.meta | 3 + .../Manual/Pages/OtherGames/ImportFgdPage.cs | 43 + .../Pages/OtherGames/ImportFgdPage.cs.meta | 10 + .../Manual/Pages/OtherGames/ImportWadPage.cs | 28 + .../Pages/OtherGames/ImportWadPage.cs.meta | 10 + .../OtherGames/MapRepairFgdComparisonPage.cs | 30 + .../MapRepairFgdComparisonPage.cs.meta | 10 + .../Pages/OtherGames/MapRepairForeignPage.cs | 82 + .../OtherGames/MapRepairForeignPage.cs.meta | 10 + .../Editor/Manual/Pages/OverviewPage.cs | 125 + .../Editor/Manual/Pages/OverviewPage.cs.meta | 10 + .../Editor/Manual/Pages/Troubleshooting.meta | 3 + .../Troubleshooting/TroubleshootingDLLPage.cs | 50 + .../TroubleshootingDLLPage.cs.meta | 10 + .../TroubleshootingGetHelpPage.cs | 32 + .../TroubleshootingGetHelpPage.cs.meta | 10 + .../TroubleshootingMaterialBrightnessPage.cs | 56 + ...ubleshootingMaterialBrightnessPage.cs.meta | 10 + .../TroubleshootingMissingGeoPage.cs | 57 + .../TroubleshootingMissingGeoPage.cs.meta | 10 + .../TroubleshootingPinkMaterialsPage.cs | 34 + .../TroubleshootingPinkMaterialsPage.cs.meta | 10 + .../Manual/Pages/UserGeneratedContent.meta | 3 + .../UgcPlayerHintsPage.cs | 61 + .../UgcPlayerHintsPage.cs.meta | 10 + .../UserGeneratedContent/UgcSetupPage.cs | 100 + .../UserGeneratedContent/UgcSetupPage.cs.meta | 10 + .../Tremble/Editor/Manual/T_Bookmark_Off.png | 3 + .../Editor/Manual/T_Bookmark_Off.png.meta | 176 ++ .../Tremble/Editor/Manual/T_Bookmark_On.png | 3 + .../Editor/Manual/T_Bookmark_On.png.meta | 176 ++ Assets/Tremble/Editor/Templates.meta | 8 + .../Tremble/Editor/Templates/gameconfig-4.cfg | 45 + .../Editor/Templates/gameconfig-4.cfg.meta | 14 + .../Tremble/Editor/Templates/gameconfig-8.cfg | 45 + .../Editor/Templates/gameconfig-8.cfg.meta | 14 + .../Tremble/Editor/Templates/gameconfig-9.cfg | 42 + .../Editor/Templates/gameconfig-9.cfg.meta | 14 + .../Editor/TinyGoose.Tremble.Editor.asmdef | 25 + .../TinyGoose.Tremble.Editor.asmdef.meta | 14 + Assets/Tremble/Editor/TrembleEditorAPI.cs | 96 + .../Tremble/Editor/TrembleEditorAPI.cs.meta | 10 + Assets/Tremble/Editor/TrembleEditorUtility.cs | 38 + .../Editor/TrembleEditorUtility.cs.meta | 10 + Assets/Tremble/Editor/TrembleMenu.cs | 181 ++ Assets/Tremble/Editor/TrembleMenu.cs.meta | 10 + Assets/Tremble/Editor/TrembleSync.cs | 1031 +++++++ Assets/Tremble/Editor/TrembleSync.cs.meta | 10 + .../Tremble/Editor/TrembleSyncAddressables.cs | 160 + .../Editor/TrembleSyncAddressables.cs.meta | 10 + Assets/Tremble/Editor/Utils.meta | 3 + .../Tremble/Editor/Utils/AssetDatabaseUtil.cs | 37 + .../Editor/Utils/AssetDatabaseUtil.cs.meta | 10 + .../Tremble/Editor/Utils/EditorCompileUtil.cs | 113 + .../Editor/Utils/EditorCompileUtil.cs.meta | 10 + .../Editor/Utils/EditorPrefsBackedString.cs | 81 + .../Utils/EditorPrefsBackedString.cs.meta | 10 + Assets/Tremble/Editor/Utils/ModTimeDB.cs | 158 + Assets/Tremble/Editor/Utils/ModTimeDB.cs.meta | 10 + .../Editor/Utils/SerializedObjectUtil.cs | 169 ++ .../Editor/Utils/SerializedObjectUtil.cs.meta | 10 + Assets/Tremble/Editor/Utils/VersionCheck.cs | 152 + .../Tremble/Editor/Utils/VersionCheck.cs.meta | 10 + Assets/Tremble/FieldConverters.meta | 8 + .../Tremble/FieldConverters/BaseClasses.meta | 3 + .../BaseClasses/UnityAssetFieldConverter.cs | 120 + .../UnityAssetFieldConverter.cs.meta | 10 + .../FieldConverters/BoolFieldConverter.cs | 99 + .../BoolFieldConverter.cs.meta | 18 + .../FieldConverters/ColourFieldConverter.cs | 48 + .../ColourFieldConverter.cs.meta | 18 + .../ComponentReferenceFieldConverter.cs | 74 + .../ComponentReferenceFieldConverter.cs.meta | 18 + .../FieldConverters/EnumFieldConverter.cs | 98 + .../EnumFieldConverter.cs.meta | 10 + .../FieldConverters/FloatFieldConverter.cs | 58 + .../FloatFieldConverter.cs.meta | 18 + .../FieldConverters/IntFieldConverter.cs | 57 + .../FieldConverters/IntFieldConverter.cs.meta | 18 + .../FieldConverters/MaterialFieldConverter.cs | 14 + .../MaterialFieldConverter.cs.meta | 10 + .../FieldConverters/PrefabFieldConverter.cs | 14 + .../PrefabFieldConverter.cs.meta | 10 + .../ScriptableObjectFieldConverter.cs | 14 + .../ScriptableObjectFieldConverter.cs.meta | 10 + .../FieldConverters/StringFieldConverter.cs | 47 + .../StringFieldConverter.cs.meta | 18 + .../FieldConverters/TrembleFieldConverter.cs | 114 + .../TrembleFieldConverter.cs.meta | 18 + .../TrembleFieldConverterCollection.cs | 81 + .../TrembleFieldConverterCollection.cs.meta | 10 + .../FieldConverters/Vector3Converter.cs | 82 + .../FieldConverters/Vector3Converter.cs.meta | 18 + .../FieldConverters/Vector3IntConverter.cs | 71 + .../Vector3IntConverter.cs.meta | 18 + Assets/Tremble/IO.meta | 3 + Assets/Tremble/IO/BSP.meta | 3 + Assets/Tremble/IO/BSP/BspParser.cs | 461 +++ Assets/Tremble/IO/BSP/BspParser.cs.meta | 18 + Assets/Tremble/IO/FGD.meta | 3 + Assets/Tremble/IO/FGD/FgdClass.cs | 166 + Assets/Tremble/IO/FGD/FgdClass.cs.meta | 10 + Assets/Tremble/IO/FGD/FgdFieldBase.cs | 89 + Assets/Tremble/IO/FGD/FgdFieldBase.cs.meta | 10 + Assets/Tremble/IO/FGD/FgdFieldFactory.cs | 86 + Assets/Tremble/IO/FGD/FgdFieldFactory.cs.meta | 18 + .../IO/FGD/FgdInferredFieldExtensions.cs | 130 + .../IO/FGD/FgdInferredFieldExtensions.cs.meta | 10 + Assets/Tremble/IO/FGD/FgdParser.cs | 283 ++ Assets/Tremble/IO/FGD/FgdParser.cs.meta | 18 + Assets/Tremble/IO/FGD/FgdWriter.cs | 239 ++ Assets/Tremble/IO/FGD/FgdWriter.cs.meta | 10 + Assets/Tremble/IO/FGD/FieldTypes.meta | 3 + .../IO/FGD/FieldTypes/FgdAnglesField.cs | 44 + .../IO/FGD/FieldTypes/FgdAnglesField.cs.meta | 10 + .../IO/FGD/FieldTypes/FgdBooleanField.cs | 39 + .../IO/FGD/FieldTypes/FgdBooleanField.cs.meta | 10 + .../IO/FGD/FieldTypes/FgdChoicesIntField.cs | 48 + .../FGD/FieldTypes/FgdChoicesIntField.cs.meta | 10 + .../FGD/FieldTypes/FgdChoicesStringField.cs | 48 + .../FieldTypes/FgdChoicesStringField.cs.meta | 10 + .../IO/FGD/FieldTypes/FgdColourField.cs | 39 + .../IO/FGD/FieldTypes/FgdColourField.cs.meta | 10 + .../Tremble/IO/FGD/FieldTypes/FgdComment.cs | 33 + .../IO/FGD/FieldTypes/FgdComment.cs.meta | 10 + .../Tremble/IO/FGD/FieldTypes/FgdEnumField.cs | 124 + .../IO/FGD/FieldTypes/FgdEnumField.cs.meta | 10 + .../IO/FGD/FieldTypes/FgdFlagsField.cs | 97 + .../IO/FGD/FieldTypes/FgdFlagsField.cs.meta | 10 + .../IO/FGD/FieldTypes/FgdFloatField.cs | 38 + .../IO/FGD/FieldTypes/FgdFloatField.cs.meta | 10 + .../IO/FGD/FieldTypes/FgdIntegerField.cs | 38 + .../IO/FGD/FieldTypes/FgdIntegerField.cs.meta | 10 + .../IO/FGD/FieldTypes/FgdSpawnFlagField.cs | 33 + .../FGD/FieldTypes/FgdSpawnFlagField.cs.meta | 10 + .../IO/FGD/FieldTypes/FgdStringField.cs | 38 + .../IO/FGD/FieldTypes/FgdStringField.cs.meta | 10 + .../FieldTypes/FgdTargetDestinationField.cs | 40 + .../FgdTargetDestinationField.cs.meta | 10 + .../IO/FGD/FieldTypes/FgdTargetSourceField.cs | 38 + .../FieldTypes/FgdTargetSourceField.cs.meta | 10 + .../IO/FGD/FieldTypes/FgdVectorField.cs | 53 + .../IO/FGD/FieldTypes/FgdVectorField.cs.meta | 10 + Assets/Tremble/IO/FGD/Writers.meta | 3 + .../IO/FGD/Writers/EntityClassWriter.cs | 330 ++ .../IO/FGD/Writers/EntityClassWriter.cs.meta | 10 + .../IO/FGD/Writers/EntityEnumWriter.cs | 69 + .../IO/FGD/Writers/EntityEnumWriter.cs.meta | 18 + Assets/Tremble/IO/MAP.meta | 3 + Assets/Tremble/IO/MAP/MapParser.cs | 294 ++ Assets/Tremble/IO/MAP/MapParser.cs.meta | 10 + Assets/Tremble/IO/StreamIO.cs | 246 ++ Assets/Tremble/IO/StreamIO.cs.meta | 10 + Assets/Tremble/IO/TokenParser.cs | 251 ++ Assets/Tremble/IO/TokenParser.cs.meta | 10 + Assets/Tremble/IO/WAD.meta | 3 + Assets/Tremble/IO/WAD/WadFile.cs | 304 ++ Assets/Tremble/IO/WAD/WadFile.cs.meta | 10 + Assets/Tremble/IO/WAD/WadParser.cs | 102 + Assets/Tremble/IO/WAD/WadParser.cs.meta | 10 + Assets/Tremble/Import.meta | 3 + Assets/Tremble/Import/MapCompiler.cs | 232 ++ Assets/Tremble/Import/MapCompiler.cs.meta | 10 + .../Import/MapCompilerOutputHandler.cs | 59 + .../Import/MapCompilerOutputHandler.cs.meta | 10 + Assets/Tremble/Import/MapProcessorBase.cs | 38 + .../Tremble/Import/MapProcessorBase.cs.meta | 10 + Assets/Tremble/Import/Q3Map2Dll.cs | 196 ++ Assets/Tremble/Import/Q3Map2Dll.cs.meta | 18 + Assets/Tremble/Import/Q3Map2VersionInfo.cs | 45 + .../Tremble/Import/Q3Map2VersionInfo.cs.meta | 10 + Assets/Tremble/Interfaces.meta | 3 + .../Interfaces/IOnImportFromMapEntity.cs | 21 + .../Interfaces/IOnImportFromMapEntity.cs.meta | 10 + Assets/Tremble/Interfaces/IOnLiveUpdate.cs | 18 + .../Tremble/Interfaces/IOnLiveUpdate.cs.meta | 10 + .../Tremble/Interfaces/ITrembleBaseClass.cs | 41 + .../Interfaces/ITrembleBaseClass.cs.meta | 10 + Assets/Tremble/LICENSE | 327 ++ Assets/Tremble/LICENSE.meta | 10 + Assets/Tremble/Materials.meta | 8 + Assets/Tremble/Materials/Clip.shader | 38 + Assets/Tremble/Materials/Clip.shader.meta | 16 + Assets/Tremble/Materials/M_NullRender.mat | 154 + .../Tremble/Materials/M_NullRender.mat.meta | 15 + Assets/Tremble/MonoBehaviours.meta | 3 + Assets/Tremble/MonoBehaviours/MapDocument.cs | 288 ++ .../MonoBehaviours/MapDocument.cs.meta | 10 + Assets/Tremble/MonoBehaviours/SeparateMesh.cs | 18 + .../MonoBehaviours/SeparateMesh.cs.meta | 10 + .../MonoBehaviours/TrembleSpawnablePrefab.cs | 25 + .../TrembleSpawnablePrefab.cs.meta | 18 + Assets/Tremble/MonoBehaviours/Worldspawn.cs | 15 + .../Tremble/MonoBehaviours/Worldspawn.cs.meta | 10 + Assets/Tremble/Plugins.meta | 8 + Assets/Tremble/Plugins/ARM64.meta | 8 + Assets/Tremble/Plugins/ARM64/q3map2.dylib | Bin 0 -> 1257456 bytes .../Tremble/Plugins/ARM64/q3map2.dylib.meta | 70 + Assets/Tremble/Plugins/x86_64.meta | 8 + Assets/Tremble/Plugins/x86_64/q3map2.dll | Bin 0 -> 799744 bytes Assets/Tremble/Plugins/x86_64/q3map2.dll.meta | 70 + Assets/Tremble/Plugins/x86_64/q3map2.dylib | Bin 0 -> 967256 bytes .../Tremble/Plugins/x86_64/q3map2.dylib.meta | 70 + Assets/Tremble/Plugins/x86_64/q3map2.so | Bin 0 -> 1144112 bytes Assets/Tremble/Plugins/x86_64/q3map2.so.meta | 70 + Assets/Tremble/ScriptableObjects.meta | 3 + .../Tremble/ScriptableObjects/FgdFileAsset.cs | 13 + .../ScriptableObjects/FgdFileAsset.cs.meta | 10 + .../Tremble/ScriptableObjects/MapFileAsset.cs | 22 + .../ScriptableObjects/MapFileAsset.cs.meta | 18 + .../Tremble/ScriptableObjects/WadFileAsset.cs | 15 + .../ScriptableObjects/WadFileAsset.cs.meta | 10 + Assets/Tremble/TinyGoose.Tremble.asmdef | 33 + Assets/Tremble/TinyGoose.Tremble.asmdef.meta | 14 + Assets/Tremble/Tremble User Guide.pdf | Bin 0 -> 1535816 bytes Assets/Tremble/Tremble User Guide.pdf.meta | 14 + Assets/Tremble/TrembleConsts.cs | 88 + Assets/Tremble/TrembleConsts.cs.meta | 10 + Assets/Tremble/TrembleMapImport.cs | 1086 +++++++ Assets/Tremble/TrembleMapImport.cs.meta | 10 + Assets/Tremble/TrembleRuntimeAPI.cs | 130 + Assets/Tremble/TrembleRuntimeAPI.cs.meta | 10 + Assets/Tremble/TrembleSyncSettings.cs | 400 +++ Assets/Tremble/TrembleSyncSettings.cs.meta | 10 + Assets/Tremble/TypeLookups.meta | 8 + Assets/Tremble/TypeLookups/MapTypeLookup.cs | 94 + .../Tremble/TypeLookups/MapTypeLookup.cs.meta | 18 + .../Tremble/TypeLookups/MaterialNameLookup.cs | 107 + .../TypeLookups/MaterialNameLookup.cs.meta | 18 + .../Tremble/TypeLookups/PrefabNameLookup.cs | 177 ++ .../TypeLookups/PrefabNameLookup.cs.meta | 18 + Assets/Tremble/Types.meta | 3 + Assets/Tremble/Types/BspTypes.cs | 306 ++ Assets/Tremble/Types/BspTypes.cs.meta | 10 + Assets/Tremble/Types/MapBspGetters.cs | 290 ++ Assets/Tremble/Types/MapBspGetters.cs.meta | 10 + Assets/Tremble/Types/MapProcessorClass.cs | 125 + .../Tremble/Types/MapProcessorClass.cs.meta | 10 + Assets/Tremble/Types/MaterialExportSize.cs | 41 + .../Tremble/Types/MaterialExportSize.cs.meta | 10 + Assets/Tremble/Types/MaterialRenderData.cs | 81 + .../Tremble/Types/MaterialRenderData.cs.meta | 10 + Assets/Tremble/Types/TpakArchive.cs | 136 + Assets/Tremble/Types/TpakArchive.cs.meta | 10 + Assets/Tremble/Types/TrembleTimer.cs | 149 + Assets/Tremble/Types/TrembleTimer.cs.meta | 10 + Assets/Tremble/Types/TwoWayDictionary.cs | 77 + Assets/Tremble/Types/TwoWayDictionary.cs.meta | 10 + Assets/Tremble/Types/WorldspawnScript.cs | 36 + Assets/Tremble/Types/WorldspawnScript.cs.meta | 10 + Assets/Tremble/Utils.meta | 3 + Assets/Tremble/Utils/DirectoryUtil.cs | 85 + Assets/Tremble/Utils/DirectoryUtil.cs.meta | 10 + Assets/Tremble/Utils/FieldUtil.cs | 327 ++ Assets/Tremble/Utils/FieldUtil.cs.meta | 10 + Assets/Tremble/Utils/FloatFormatUtil.cs | 39 + Assets/Tremble/Utils/FloatFormatUtil.cs.meta | 10 + Assets/Tremble/Utils/GameObjectUtil.cs | 28 + Assets/Tremble/Utils/GameObjectUtil.cs.meta | 10 + Assets/Tremble/Utils/InitHack.cs | 11 + Assets/Tremble/Utils/InitHack.cs.meta | 10 + Assets/Tremble/Utils/MD3Util.cs | 361 +++ Assets/Tremble/Utils/MD3Util.cs.meta | 19 + Assets/Tremble/Utils/MapTextureSnapshotter.cs | 468 +++ .../Utils/MapTextureSnapshotter.cs.meta | 10 + Assets/Tremble/Utils/MeshBuilder.cs | 451 +++ Assets/Tremble/Utils/MeshBuilder.cs.meta | 10 + Assets/Tremble/Utils/NamingConventionUtil.cs | 157 + .../Utils/NamingConventionUtil.cs.meta | 18 + Assets/Tremble/Utils/PackedResourceUtil.cs | 49 + .../Tremble/Utils/PackedResourceUtil.cs.meta | 10 + Assets/Tremble/Utils/PrefabUtil.cs | 27 + Assets/Tremble/Utils/PrefabUtil.cs.meta | 10 + Assets/Tremble/Utils/ProgressUtil.cs | 71 + Assets/Tremble/Utils/ProgressUtil.cs.meta | 10 + Assets/Tremble/Utils/StreamWriterUtil.cs | 20 + Assets/Tremble/Utils/StreamWriterUtil.cs.meta | 18 + Assets/Tremble/Utils/StringUtil.cs | 131 + Assets/Tremble/Utils/StringUtil.cs.meta | 10 + Assets/Tremble/Utils/TextureUtil.cs | 201 ++ Assets/Tremble/Utils/TextureUtil.cs.meta | 10 + Assets/Tremble/Utils/TrenchBroomUtil.cs | 237 ++ Assets/Tremble/Utils/TrenchBroomUtil.cs.meta | 18 + Assets/Tremble/Utils/TypeDatabase.cs | 365 +++ Assets/Tremble/Utils/TypeDatabase.cs.meta | 10 + Assets/UnityCodeGen.Generated.meta | 8 + .../AudioMixer.Generated.cs | 26 + .../AudioMixer.Generated.cs.meta | 2 + ...lay.Player.CleanerCameraState.Generated.cs | 12 + ...layer.CleanerCameraState.Generated.cs.meta | 2 + ...ame.TestingLevel.TestingState.Generated.cs | 12 + ...estingLevel.TestingState.Generated.cs.meta | 2 + ...structure.App.AppStateMachine.Generated.cs | 24 + ...ture.App.AppStateMachine.Generated.cs.meta | 2 + ...ure.Camera.CameraStateMachine.Generated.cs | 29 + ...amera.CameraStateMachine.Generated.cs.meta | 2 + ....CameraStates.NoneCameraState.Generated.cs | 12 + ...raStates.NoneCameraState.Generated.cs.meta | 2 + .../ConfigLocator.Generated.cs | 56 + .../ConfigLocator.Generated.cs.meta | 2 + .../ConfigReferences.Generated.cs | 38 + .../ConfigReferences.Generated.cs.meta | 2 + Assets/packages.config | 9 + Assets/packages.config.meta | 28 + Packages/manifest.json | 53 + Packages/packages-lock.json | 521 ++++ ProjectSettings/AlchemySettings.json | 32 + ProjectSettings/AudioManager.asset | 19 + ProjectSettings/ClusterInputManager.asset | 6 + ProjectSettings/DynamicsManager.asset | 46 + ProjectSettings/EditorBuildSettings.asset | 13 + ProjectSettings/EditorSettings.asset | 53 + ProjectSettings/GraphicsSettings.asset | 67 + ProjectSettings/InputManager.asset | 487 +++ ProjectSettings/MemorySettings.asset | 35 + ProjectSettings/MultiplayerManager.asset | 7 + ProjectSettings/NavMeshAreas.asset | 91 + ProjectSettings/PackageManagerSettings.asset | 44 + ProjectSettings/Physics2DSettings.asset | 56 + .../PhysicsCoreProjectSettings2D.asset | 6 + ProjectSettings/PresetManager.asset | 7 + ProjectSettings/ProjectAuditorSettings.asset | 36 + ProjectSettings/ProjectSettings.asset | 951 ++++++ ProjectSettings/ProjectVersion.txt | 2 + ProjectSettings/QualitySettings.asset | 137 + ProjectSettings/SceneTemplateSettings.json | 121 + ProjectSettings/ShaderGraphSettings.asset | 19 + ProjectSettings/TagManager.asset | 54 + ProjectSettings/TimeManager.asset | 9 + ProjectSettings/URPProjectSettings.asset | 16 + ProjectSettings/UnityConnectSettings.asset | 42 + ProjectSettings/VFXManager.asset | 12 + ProjectSettings/VersionControlSettings.asset | 8 + ProjectSettings/XRSettings.asset | 10 + 999 files changed, 61364 insertions(+) create mode 100644 Assets/AddressableAssetsData.meta create mode 100644 Assets/AddressableAssetsData/AddressableAssetSettings.asset create mode 100644 Assets/AddressableAssetsData/AddressableAssetSettings.asset.meta create mode 100644 Assets/AddressableAssetsData/AssetGroupTemplates.meta create mode 100644 Assets/AddressableAssetsData/AssetGroupTemplates/Packed Assets.asset create mode 100644 Assets/AddressableAssetsData/AssetGroupTemplates/Packed Assets.asset.meta create mode 100644 Assets/AddressableAssetsData/AssetGroups.meta create mode 100644 Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset create mode 100644 Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset.meta create mode 100644 Assets/AddressableAssetsData/AssetGroups/Schemas.meta create mode 100644 Assets/AddressableAssetsData/AssetGroups/Schemas/Default Local Group_BundledAssetGroupSchema.asset create mode 100644 Assets/AddressableAssetsData/AssetGroups/Schemas/Default Local Group_BundledAssetGroupSchema.asset.meta create mode 100644 Assets/AddressableAssetsData/AssetGroups/Schemas/Default Local Group_ContentUpdateGroupSchema.asset create mode 100644 Assets/AddressableAssetsData/AssetGroups/Schemas/Default Local Group_ContentUpdateGroupSchema.asset.meta create mode 100644 Assets/AddressableAssetsData/DataBuilders.meta create mode 100644 Assets/AddressableAssetsData/DataBuilders/BuildScriptFastMode.asset create mode 100644 Assets/AddressableAssetsData/DataBuilders/BuildScriptFastMode.asset.meta create mode 100644 Assets/AddressableAssetsData/DataBuilders/BuildScriptPackedMode.asset create mode 100644 Assets/AddressableAssetsData/DataBuilders/BuildScriptPackedMode.asset.meta create mode 100644 Assets/AddressableAssetsData/DataBuilders/BuildScriptPackedPlayMode.asset create mode 100644 Assets/AddressableAssetsData/DataBuilders/BuildScriptPackedPlayMode.asset.meta create mode 100644 Assets/AddressableAssetsData/DefaultObject.asset create mode 100644 Assets/AddressableAssetsData/DefaultObject.asset.meta create mode 100644 Assets/Code.meta create mode 100644 Assets/Code/D.meta create mode 100644 Assets/Code/D/CleanTools.meta create mode 100644 Assets/Code/D/CleanTools/CleanTool.cs create mode 100644 Assets/Code/D/CleanTools/CleanTool.cs.meta create mode 100644 Assets/Code/D/CleanTools/CleanToolConfig.cs create mode 100644 Assets/Code/D/CleanTools/CleanToolConfig.cs.meta create mode 100644 Assets/Code/D/CleanTools/CleanToolInteractable.cs create mode 100644 Assets/Code/D/CleanTools/CleanToolInteractable.cs.meta create mode 100644 Assets/Code/D/CleanTools/CleanToolType.cs create mode 100644 Assets/Code/D/CleanTools/CleanToolType.cs.meta create mode 100644 Assets/Code/D/CleanTools/DirtyToolCleaner.cs create mode 100644 Assets/Code/D/CleanTools/DirtyToolCleaner.cs.meta create mode 100644 Assets/Code/D/CleanTools/ToolUsageInfo.cs create mode 100644 Assets/Code/D/CleanTools/ToolUsageInfo.cs.meta create mode 100644 Assets/Code/D/CleanTools/Tryapka.cs create mode 100644 Assets/Code/D/CleanTools/Tryapka.cs.meta create mode 100644 Assets/Code/D/Cleaning.meta create mode 100644 Assets/Code/D/Cleaning/Cleanable.cs create mode 100644 Assets/Code/D/Cleaning/Cleanable.cs.meta create mode 100644 Assets/Code/D/Cleaning/CleanableAsset.cs create mode 100644 Assets/Code/D/Cleaning/CleanableAsset.cs.meta create mode 100644 Assets/Code/D/Cleaning/CleanableSurface.cs create mode 100644 Assets/Code/D/Cleaning/CleanableSurface.cs.meta create mode 100644 Assets/Code/D/Cleaning/CleaningService.cs create mode 100644 Assets/Code/D/Cleaning/CleaningService.cs.meta create mode 100644 Assets/Code/D/Cleaning/Shaders.meta create mode 100644 Assets/Code/D/Cleaning/Shaders/BrushPainter.shader create mode 100644 Assets/Code/D/Cleaning/Shaders/BrushPainter.shader.meta create mode 100644 Assets/Code/D/Cleaning/UI.meta create mode 100644 Assets/Code/D/Cleaning/UI/CleanToolWidget.cs create mode 100644 Assets/Code/D/Cleaning/UI/CleanToolWidget.cs.meta create mode 100644 Assets/Code/D/Cleaning/UI/CleaningPanel.cs create mode 100644 Assets/Code/D/Cleaning/UI/CleaningPanel.cs.meta create mode 100644 Assets/Code/D/Cleaning/UI/TryapkaWidget.cs create mode 100644 Assets/Code/D/Cleaning/UI/TryapkaWidget.cs.meta create mode 100644 Assets/Code/D/Player.meta create mode 100644 Assets/Code/D/Player/CleanerCameraState.cs create mode 100644 Assets/Code/D/Player/CleanerCameraState.cs.meta create mode 100644 Assets/Code/D/Player/Factory.meta create mode 100644 Assets/Code/D/Player/Factory/PlayerFactory.cs create mode 100644 Assets/Code/D/Player/Factory/PlayerFactory.cs.meta create mode 100644 Assets/Code/D/Player/Factory/PlayerFactorySettings.cs create mode 100644 Assets/Code/D/Player/Factory/PlayerFactorySettings.cs.meta create mode 100644 Assets/Code/D/Player/PlayerCameraTarget.cs create mode 100644 Assets/Code/D/Player/PlayerCameraTarget.cs.meta create mode 100644 Assets/Code/D/Player/PlayerControlsProvider.cs create mode 100644 Assets/Code/D/Player/PlayerControlsProvider.cs.meta create mode 100644 Assets/Code/D/Player/PlayerDetailMaskDrawer.cs create mode 100644 Assets/Code/D/Player/PlayerDetailMaskDrawer.cs.meta create mode 100644 Assets/Code/D/Player/PlayerEquipment.cs create mode 100644 Assets/Code/D/Player/PlayerEquipment.cs.meta create mode 100644 Assets/Code/D/Player/PlayerInteractor.cs create mode 100644 Assets/Code/D/Player/PlayerInteractor.cs.meta create mode 100644 Assets/Code/D/Player/PlayerMovementController.cs create mode 100644 Assets/Code/D/Player/PlayerMovementController.cs.meta create mode 100644 Assets/Code/Debug.meta create mode 100644 Assets/Code/Debug/StartFromBootstrap.cs create mode 100644 Assets/Code/Debug/StartFromBootstrap.cs.meta create mode 100644 Assets/Code/Debug/TestingLevel.meta create mode 100644 Assets/Code/Debug/TestingLevel/TestingLevelSceneInstaller.cs create mode 100644 Assets/Code/Debug/TestingLevel/TestingLevelSceneInstaller.cs.meta create mode 100644 Assets/Code/Debug/TestingLevel/TestingState.cs create mode 100644 Assets/Code/Debug/TestingLevel/TestingState.cs.meta create mode 100644 Assets/Code/Debug/UVVisualizer.shader create mode 100644 Assets/Code/Debug/UVVisualizer.shader.meta create mode 100644 Assets/Code/Infrastructure.meta create mode 100644 Assets/Code/Infrastructure/App.meta create mode 100644 Assets/Code/Infrastructure/App/AppStateMachine.cs create mode 100644 Assets/Code/Infrastructure/App/AppStateMachine.cs.meta create mode 100644 Assets/Code/Infrastructure/Audio.meta create mode 100644 Assets/Code/Infrastructure/Audio/AudioFactory.cs create mode 100644 Assets/Code/Infrastructure/Audio/AudioFactory.cs.meta create mode 100644 Assets/Code/Infrastructure/Audio/AudioInfo.cs create mode 100644 Assets/Code/Infrastructure/Audio/AudioInfo.cs.meta create mode 100644 Assets/Code/Infrastructure/Audio/AudioInfoConfig.cs create mode 100644 Assets/Code/Infrastructure/Audio/AudioInfoConfig.cs.meta create mode 100644 Assets/Code/Infrastructure/Audio/AudioInfoLODedConfig.cs create mode 100644 Assets/Code/Infrastructure/Audio/AudioInfoLODedConfig.cs.meta create mode 100644 Assets/Code/Infrastructure/Audio/AudioInfoRandomConfig.cs create mode 100644 Assets/Code/Infrastructure/Audio/AudioInfoRandomConfig.cs.meta create mode 100644 Assets/Code/Infrastructure/Audio/AudioInfoSingleConfig.cs create mode 100644 Assets/Code/Infrastructure/Audio/AudioInfoSingleConfig.cs.meta create mode 100644 Assets/Code/Infrastructure/Audio/AudioMixerSettings.cs create mode 100644 Assets/Code/Infrastructure/Audio/AudioMixerSettings.cs.meta create mode 100644 Assets/Code/Infrastructure/Audio/AudioService.cs create mode 100644 Assets/Code/Infrastructure/Audio/AudioService.cs.meta create mode 100644 Assets/Code/Infrastructure/Audio/AudioSourceFollower.cs create mode 100644 Assets/Code/Infrastructure/Audio/AudioSourceFollower.cs.meta create mode 100644 Assets/Code/Infrastructure/Audio/AudioSourcePool.cs create mode 100644 Assets/Code/Infrastructure/Audio/AudioSourcePool.cs.meta create mode 100644 Assets/Code/Infrastructure/Audio/AudioSourcePrefab.cs create mode 100644 Assets/Code/Infrastructure/Audio/AudioSourcePrefab.cs.meta create mode 100644 Assets/Code/Infrastructure/Audio/AudioSourceSettings.cs create mode 100644 Assets/Code/Infrastructure/Audio/AudioSourceSettings.cs.meta create mode 100644 Assets/Code/Infrastructure/Camera.meta create mode 100644 Assets/Code/Infrastructure/Camera/CameraFactory.cs create mode 100644 Assets/Code/Infrastructure/Camera/CameraFactory.cs.meta create mode 100644 Assets/Code/Infrastructure/Camera/CameraStateMachine.cs create mode 100644 Assets/Code/Infrastructure/Camera/CameraStateMachine.cs.meta create mode 100644 Assets/Code/Infrastructure/Camera/CameraStateMachineRunner.cs create mode 100644 Assets/Code/Infrastructure/Camera/CameraStateMachineRunner.cs.meta create mode 100644 Assets/Code/Infrastructure/Camera/CameraStates.meta create mode 100644 Assets/Code/Infrastructure/Camera/CameraStates/BaseCameraState.cs create mode 100644 Assets/Code/Infrastructure/Camera/CameraStates/BaseCameraState.cs.meta create mode 100644 Assets/Code/Infrastructure/Camera/CameraStates/NoneCameraState.cs create mode 100644 Assets/Code/Infrastructure/Camera/CameraStates/NoneCameraState.cs.meta create mode 100644 Assets/Code/Infrastructure/Camera/GameCamera.cs create mode 100644 Assets/Code/Infrastructure/Camera/GameCamera.cs.meta create mode 100644 Assets/Code/Infrastructure/Configs.meta create mode 100644 Assets/Code/Infrastructure/Configs/ConfigLocator.cs create mode 100644 Assets/Code/Infrastructure/Configs/ConfigLocator.cs.meta create mode 100644 Assets/Code/Infrastructure/Configs/ConfigReferences.cs create mode 100644 Assets/Code/Infrastructure/Configs/ConfigReferences.cs.meta create mode 100644 Assets/Code/Infrastructure/Generators.meta create mode 100644 Assets/Code/Infrastructure/Generators/Attributes.cs create mode 100644 Assets/Code/Infrastructure/Generators/Attributes.cs.meta create mode 100644 Assets/Code/Infrastructure/Generators/AudioMixerGenerator.cs create mode 100644 Assets/Code/Infrastructure/Generators/AudioMixerGenerator.cs.meta create mode 100644 Assets/Code/Infrastructure/Generators/ConfigGenerator.cs create mode 100644 Assets/Code/Infrastructure/Generators/ConfigGenerator.cs.meta create mode 100644 Assets/Code/Infrastructure/Generators/StateMachineGenerator.cs create mode 100644 Assets/Code/Infrastructure/Generators/StateMachineGenerator.cs.meta create mode 100644 Assets/Code/Infrastructure/Generators/TypeExtensions.cs create mode 100644 Assets/Code/Infrastructure/Generators/TypeExtensions.cs.meta create mode 100644 Assets/Code/Infrastructure/Input.meta create mode 100644 Assets/Code/Infrastructure/Input/InputService.cs create mode 100644 Assets/Code/Infrastructure/Input/InputService.cs.meta create mode 100644 Assets/Code/Infrastructure/Input/InputServiceConfig.cs create mode 100644 Assets/Code/Infrastructure/Input/InputServiceConfig.cs.meta create mode 100644 Assets/Code/Infrastructure/Loadings.meta create mode 100644 Assets/Code/Infrastructure/Loadings/Loading.cs create mode 100644 Assets/Code/Infrastructure/Loadings/Loading.cs.meta create mode 100644 Assets/Code/Infrastructure/Particles.meta create mode 100644 Assets/Code/Infrastructure/Particles/ParticleInfo.cs create mode 100644 Assets/Code/Infrastructure/Particles/ParticleInfo.cs.meta create mode 100644 Assets/Code/Infrastructure/Particles/ParticleLoader.cs create mode 100644 Assets/Code/Infrastructure/Particles/ParticleLoader.cs.meta create mode 100644 Assets/Code/Infrastructure/Particles/ParticlePoolManager.cs create mode 100644 Assets/Code/Infrastructure/Particles/ParticlePoolManager.cs.meta create mode 100644 Assets/Code/Infrastructure/Particles/ParticleService.cs create mode 100644 Assets/Code/Infrastructure/Particles/ParticleService.cs.meta create mode 100644 Assets/Code/Infrastructure/SceneLoader.meta create mode 100644 Assets/Code/Infrastructure/SceneLoader/CustomSceneManager.cs create mode 100644 Assets/Code/Infrastructure/SceneLoader/CustomSceneManager.cs.meta create mode 100644 Assets/Code/Infrastructure/SceneLoader/SceneInfo.cs create mode 100644 Assets/Code/Infrastructure/SceneLoader/SceneInfo.cs.meta create mode 100644 Assets/Code/Infrastructure/SceneLoader/ScenesAssetReferences.cs create mode 100644 Assets/Code/Infrastructure/SceneLoader/ScenesAssetReferences.cs.meta create mode 100644 Assets/Code/Infrastructure/StateMachine.meta create mode 100644 Assets/Code/Infrastructure/StateMachine/AbstractStateMachine.cs create mode 100644 Assets/Code/Infrastructure/StateMachine/AbstractStateMachine.cs.meta create mode 100644 Assets/Code/Infrastructure/StateMachine/BaseState.cs create mode 100644 Assets/Code/Infrastructure/StateMachine/BaseState.cs.meta create mode 100644 Assets/Code/Infrastructure/UI.meta create mode 100644 Assets/Code/Infrastructure/UI/CanvasSettings.cs create mode 100644 Assets/Code/Infrastructure/UI/CanvasSettings.cs.meta create mode 100644 Assets/Code/Infrastructure/UI/UIFactory.cs create mode 100644 Assets/Code/Infrastructure/UI/UIFactory.cs.meta create mode 100644 Assets/Code/Infrastructure/UI/UIPanel.cs create mode 100644 Assets/Code/Infrastructure/UI/UIPanel.cs.meta create mode 100644 Assets/Code/Infrastructure/UI/UIPanelSettings.cs create mode 100644 Assets/Code/Infrastructure/UI/UIPanelSettings.cs.meta create mode 100644 Assets/Code/Infrastructure/Utils.meta create mode 100644 Assets/Code/Infrastructure/Utils/AddressablesUtilities.cs create mode 100644 Assets/Code/Infrastructure/Utils/AddressablesUtilities.cs.meta create mode 100644 Assets/Code/Infrastructure/Utils/ConfigUtility.cs create mode 100644 Assets/Code/Infrastructure/Utils/ConfigUtility.cs.meta create mode 100644 Assets/Code/Infrastructure/Utils/EnumUtil.cs create mode 100644 Assets/Code/Infrastructure/Utils/EnumUtil.cs.meta create mode 100644 Assets/Code/Infrastructure/Volume.meta create mode 100644 Assets/Code/Infrastructure/Volume/VolumeFactory.cs create mode 100644 Assets/Code/Infrastructure/Volume/VolumeFactory.cs.meta create mode 100644 Assets/Code/Infrastructure/Volume/VolumeService.cs create mode 100644 Assets/Code/Infrastructure/Volume/VolumeService.cs.meta create mode 100644 Assets/Code/Infrastructure/Volume/VolumeSettings.cs create mode 100644 Assets/Code/Infrastructure/Volume/VolumeSettings.cs.meta create mode 100644 Assets/Code/Musician.meta create mode 100644 Assets/Code/PapaInstaller.cs create mode 100644 Assets/Code/PapaInstaller.cs.meta create mode 100644 Assets/Code/Tests.meta create mode 100644 Assets/Code/Tests/Editor.meta create mode 100644 Assets/Code/Tests/Editor/CleaningToolsTests.cs create mode 100644 Assets/Code/Tests/Editor/CleaningToolsTests.cs.meta create mode 100644 Assets/Code/UserDefinedEnums.meta create mode 100644 Assets/Code/UserDefinedEnums/ActionMappings.cs create mode 100644 Assets/Code/UserDefinedEnums/ActionMappings.cs.meta create mode 100644 Assets/Code/UserDefinedEnums/AppStates.cs create mode 100644 Assets/Code/UserDefinedEnums/AppStates.cs.meta create mode 100644 Assets/Code/UserDefinedEnums/AudioGroupType.cs create mode 100644 Assets/Code/UserDefinedEnums/AudioGroupType.cs.meta create mode 100644 Assets/Code/UserDefinedEnums/AudioLODLevel.cs create mode 100644 Assets/Code/UserDefinedEnums/AudioLODLevel.cs.meta create mode 100644 Assets/Code/UserDefinedEnums/AudioPartition.cs create mode 100644 Assets/Code/UserDefinedEnums/AudioPartition.cs.meta create mode 100644 Assets/Code/UserDefinedEnums/AudioSourceType.cs create mode 100644 Assets/Code/UserDefinedEnums/AudioSourceType.cs.meta create mode 100644 Assets/Code/UserDefinedEnums/ParticlePartition.cs create mode 100644 Assets/Code/UserDefinedEnums/ParticlePartition.cs.meta create mode 100644 Assets/Code/UserDefinedEnums/SceneId.cs create mode 100644 Assets/Code/UserDefinedEnums/SceneId.cs.meta create mode 100644 Assets/Code/UserDefinedEnums/UIPanelType.cs create mode 100644 Assets/Code/UserDefinedEnums/UIPanelType.cs.meta create mode 100644 Assets/Code/UserDefinedEnums/VolumeId.cs create mode 100644 Assets/Code/UserDefinedEnums/VolumeId.cs.meta create mode 100644 Assets/Infrastructure.meta create mode 100644 Assets/Infrastructure/Audio.meta create mode 100644 Assets/Infrastructure/Audio/Audio Source.prefab create mode 100644 Assets/Infrastructure/Audio/Audio Source.prefab.meta create mode 100644 Assets/Infrastructure/Audio/AudioMixerSettings.asset create mode 100644 Assets/Infrastructure/Audio/AudioMixerSettings.asset.meta create mode 100644 Assets/Infrastructure/Audio/AudioSourcePrefab.asset create mode 100644 Assets/Infrastructure/Audio/AudioSourcePrefab.asset.meta create mode 100644 Assets/Infrastructure/Audio/Full3DSource.asset create mode 100644 Assets/Infrastructure/Audio/Full3DSource.asset.meta create mode 100644 Assets/Infrastructure/Audio/MainMixer.mixer create mode 100644 Assets/Infrastructure/Audio/MainMixer.mixer.meta create mode 100644 Assets/Infrastructure/Audio/NoBlendSource.asset create mode 100644 Assets/Infrastructure/Audio/NoBlendSource.asset.meta create mode 100644 Assets/Infrastructure/Bootstrap.unity create mode 100644 Assets/Infrastructure/Bootstrap.unity.meta create mode 100644 Assets/Infrastructure/Camera.meta create mode 100644 Assets/Infrastructure/Camera/GameCamera.asset create mode 100644 Assets/Infrastructure/Camera/GameCamera.asset.meta create mode 100644 Assets/Infrastructure/Input.meta create mode 100644 Assets/Infrastructure/Input/ActionMap.inputactions create mode 100644 Assets/Infrastructure/Input/ActionMap.inputactions.meta create mode 100644 Assets/Infrastructure/Input/InputService.asset create mode 100644 Assets/Infrastructure/Input/InputService.asset.meta create mode 100644 Assets/Infrastructure/UI.meta create mode 100644 Assets/Infrastructure/UI/BlankPanel.prefab create mode 100644 Assets/Infrastructure/UI/BlankPanel.prefab.meta create mode 100644 Assets/Infrastructure/UI/CanvasSettings.asset create mode 100644 Assets/Infrastructure/UI/CanvasSettings.asset.meta create mode 100644 Assets/KinematicCharacterController.meta create mode 100644 Assets/KinematicCharacterController/APIReference.zip create mode 100644 Assets/KinematicCharacterController/APIReference.zip.meta create mode 100644 Assets/KinematicCharacterController/Core.meta create mode 100644 Assets/KinematicCharacterController/Core/Editor.meta create mode 100644 Assets/KinematicCharacterController/Core/Editor/KinematicCharacterMotorEditor.cs create mode 100644 Assets/KinematicCharacterController/Core/Editor/KinematicCharacterMotorEditor.cs.meta create mode 100644 Assets/KinematicCharacterController/Core/Editor/ReadOnlyPropertyDrawer.cs create mode 100644 Assets/KinematicCharacterController/Core/Editor/ReadOnlyPropertyDrawer.cs.meta create mode 100644 Assets/KinematicCharacterController/Core/ICharacterController.cs create mode 100644 Assets/KinematicCharacterController/Core/ICharacterController.cs.meta create mode 100644 Assets/KinematicCharacterController/Core/IMoverController.cs create mode 100644 Assets/KinematicCharacterController/Core/IMoverController.cs.meta create mode 100644 Assets/KinematicCharacterController/Core/KCCSettings.cs create mode 100644 Assets/KinematicCharacterController/Core/KCCSettings.cs.meta create mode 100644 Assets/KinematicCharacterController/Core/KinematicCharacterMotor.cs create mode 100644 Assets/KinematicCharacterController/Core/KinematicCharacterMotor.cs.meta create mode 100644 Assets/KinematicCharacterController/Core/KinematicCharacterSystem.cs create mode 100644 Assets/KinematicCharacterController/Core/KinematicCharacterSystem.cs.meta create mode 100644 Assets/KinematicCharacterController/Core/PhysicsMover.cs create mode 100644 Assets/KinematicCharacterController/Core/PhysicsMover.cs.meta create mode 100644 Assets/KinematicCharacterController/Core/ReadOnlyAttribute.cs create mode 100644 Assets/KinematicCharacterController/Core/ReadOnlyAttribute.cs.meta create mode 100644 Assets/NuGet.config create mode 100644 Assets/NuGet.config.meta create mode 100644 Assets/Packages.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/.signature.p7s create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/Icon.png create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/Icon.png.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/LICENSE.TXT create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/LICENSE.TXT.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/Microsoft.Bcl.TimeProvider.nuspec create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/Microsoft.Bcl.TimeProvider.nuspec.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/PACKAGE.md create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/PACKAGE.md.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/THIRD-PARTY-NOTICES.TXT create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/THIRD-PARTY-NOTICES.TXT.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net461.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net461/Microsoft.Bcl.TimeProvider.targets create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net461/Microsoft.Bcl.TimeProvider.targets.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net462.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net462/_._ create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net462/_._.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net6.0.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net6.0/_._ create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net6.0/_._.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/netcoreapp2.0.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/netcoreapp2.0/Microsoft.Bcl.TimeProvider.targets create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/netcoreapp2.0/Microsoft.Bcl.TimeProvider.targets.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib/netstandard2.0.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib/netstandard2.0/Microsoft.Bcl.TimeProvider.dll create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib/netstandard2.0/Microsoft.Bcl.TimeProvider.dll.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib/netstandard2.0/Microsoft.Bcl.TimeProvider.xml create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib/netstandard2.0/Microsoft.Bcl.TimeProvider.xml.meta create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/useSharedDesignerContext.txt create mode 100644 Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/useSharedDesignerContext.txt.meta create mode 100644 Assets/Packages/ObservableCollections.3.3.4.meta create mode 100644 Assets/Packages/ObservableCollections.3.3.4/.signature.p7s create mode 100644 Assets/Packages/ObservableCollections.3.3.4/Icon.png create mode 100644 Assets/Packages/ObservableCollections.3.3.4/Icon.png.meta create mode 100644 Assets/Packages/ObservableCollections.3.3.4/ObservableCollections.nuspec create mode 100644 Assets/Packages/ObservableCollections.3.3.4/ObservableCollections.nuspec.meta create mode 100644 Assets/Packages/ObservableCollections.3.3.4/lib.meta create mode 100644 Assets/Packages/ObservableCollections.3.3.4/lib/netstandard2.1.meta create mode 100644 Assets/Packages/ObservableCollections.3.3.4/lib/netstandard2.1/ObservableCollections.dll create mode 100644 Assets/Packages/ObservableCollections.3.3.4/lib/netstandard2.1/ObservableCollections.dll.meta create mode 100644 Assets/Packages/ObservableCollections.3.3.4/lib/netstandard2.1/ObservableCollections.xml create mode 100644 Assets/Packages/ObservableCollections.3.3.4/lib/netstandard2.1/ObservableCollections.xml.meta create mode 100644 Assets/Packages/ObservableCollections.R3.3.3.4.meta create mode 100644 Assets/Packages/ObservableCollections.R3.3.3.4/.signature.p7s create mode 100644 Assets/Packages/ObservableCollections.R3.3.3.4/Icon.png create mode 100644 Assets/Packages/ObservableCollections.R3.3.3.4/Icon.png.meta create mode 100644 Assets/Packages/ObservableCollections.R3.3.3.4/ObservableCollections.R3.nuspec create mode 100644 Assets/Packages/ObservableCollections.R3.3.3.4/ObservableCollections.R3.nuspec.meta create mode 100644 Assets/Packages/ObservableCollections.R3.3.3.4/lib.meta create mode 100644 Assets/Packages/ObservableCollections.R3.3.3.4/lib/netstandard2.1.meta create mode 100644 Assets/Packages/ObservableCollections.R3.3.3.4/lib/netstandard2.1/ObservableCollections.R3.dll create mode 100644 Assets/Packages/ObservableCollections.R3.3.3.4/lib/netstandard2.1/ObservableCollections.R3.dll.meta create mode 100644 Assets/Packages/ObservableCollections.R3.3.3.4/lib/netstandard2.1/ObservableCollections.R3.xml create mode 100644 Assets/Packages/ObservableCollections.R3.3.3.4/lib/netstandard2.1/ObservableCollections.R3.xml.meta create mode 100644 Assets/Packages/R3.1.3.1.meta create mode 100644 Assets/Packages/R3.1.3.1/.signature.p7s create mode 100644 Assets/Packages/R3.1.3.1/Icon.png create mode 100644 Assets/Packages/R3.1.3.1/Icon.png.meta create mode 100644 Assets/Packages/R3.1.3.1/R3.nuspec create mode 100644 Assets/Packages/R3.1.3.1/R3.nuspec.meta create mode 100644 Assets/Packages/R3.1.3.1/README.md create mode 100644 Assets/Packages/R3.1.3.1/README.md.meta create mode 100644 Assets/Packages/R3.1.3.1/lib.meta create mode 100644 Assets/Packages/R3.1.3.1/lib/netstandard2.1.meta create mode 100644 Assets/Packages/R3.1.3.1/lib/netstandard2.1/R3.dll create mode 100644 Assets/Packages/R3.1.3.1/lib/netstandard2.1/R3.dll.meta create mode 100644 Assets/Packages/R3.1.3.1/lib/netstandard2.1/R3.xml create mode 100644 Assets/Packages/R3.1.3.1/lib/netstandard2.1/R3.xml.meta create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0.meta create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0/.signature.p7s create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0/Icon.png create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0/Icon.png.meta create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0/LICENSE.TXT create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0/LICENSE.TXT.meta create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0/System.ComponentModel.Annotations.nuspec create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0/System.ComponentModel.Annotations.nuspec.meta create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0/THIRD-PARTY-NOTICES.TXT create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0/THIRD-PARTY-NOTICES.TXT.meta create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0/lib.meta create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0/lib/netstandard2.1.meta create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0/lib/netstandard2.1/System.ComponentModel.Annotations.dll create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0/lib/netstandard2.1/System.ComponentModel.Annotations.dll.meta create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0/lib/netstandard2.1/System.ComponentModel.Annotations.xml create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0/lib/netstandard2.1/System.ComponentModel.Annotations.xml.meta create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0/useSharedDesignerContext.txt create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0/useSharedDesignerContext.txt.meta create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0/version.txt create mode 100644 Assets/Packages/System.ComponentModel.Annotations.5.0.0/version.txt.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/.signature.p7s create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/Icon.png create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/Icon.png.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/LICENSE.TXT create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/LICENSE.TXT.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/PACKAGE.md create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/PACKAGE.md.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/System.Threading.Channels.nuspec create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/System.Threading.Channels.nuspec.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/THIRD-PARTY-NOTICES.TXT create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/THIRD-PARTY-NOTICES.TXT.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/buildTransitive.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/buildTransitive/net461.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/buildTransitive/net461/System.Threading.Channels.targets create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/buildTransitive/net461/System.Threading.Channels.targets.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/buildTransitive/net462.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/buildTransitive/net462/_._ create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/buildTransitive/net462/_._.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/buildTransitive/net6.0.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/buildTransitive/net6.0/_._ create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/buildTransitive/net6.0/_._.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/buildTransitive/netcoreapp2.0.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/buildTransitive/netcoreapp2.0/System.Threading.Channels.targets create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/buildTransitive/netcoreapp2.0/System.Threading.Channels.targets.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/lib.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/lib/netstandard2.1.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/lib/netstandard2.1/System.Threading.Channels.dll create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/lib/netstandard2.1/System.Threading.Channels.dll.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/lib/netstandard2.1/System.Threading.Channels.xml create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/lib/netstandard2.1/System.Threading.Channels.xml.meta create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/useSharedDesignerContext.txt create mode 100644 Assets/Packages/System.Threading.Channels.8.0.0/useSharedDesignerContext.txt.meta create mode 100644 Assets/Resources.meta create mode 100644 Assets/Resources/ConfigReferences.asset create mode 100644 Assets/Resources/ConfigReferences.asset.meta create mode 100644 Assets/Resources/ReflexSettings.asset create mode 100644 Assets/Resources/ReflexSettings.asset.meta create mode 100644 Assets/Resources/RootScope.prefab create mode 100644 Assets/Resources/RootScope.prefab.meta create mode 100644 Assets/Settings.meta create mode 100644 Assets/Settings/DefaultVolumeProfile.asset create mode 100644 Assets/Settings/DefaultVolumeProfile.asset.meta create mode 100644 Assets/Settings/Mobile_RPAsset.asset create mode 100644 Assets/Settings/Mobile_RPAsset.asset.meta create mode 100644 Assets/Settings/Mobile_Renderer.asset create mode 100644 Assets/Settings/Mobile_Renderer.asset.meta create mode 100644 Assets/Settings/PC_RPAsset.asset create mode 100644 Assets/Settings/PC_RPAsset.asset.meta create mode 100644 Assets/Settings/PC_Renderer.asset create mode 100644 Assets/Settings/PC_Renderer.asset.meta create mode 100644 Assets/Settings/SampleSceneProfile.asset create mode 100644 Assets/Settings/SampleSceneProfile.asset.meta create mode 100644 Assets/Settings/UniversalRenderPipelineGlobalSettings.asset create mode 100644 Assets/Settings/UniversalRenderPipelineGlobalSettings.asset.meta create mode 100644 Assets/Tremble Sync Settings.asset create mode 100644 Assets/Tremble Sync Settings.asset.meta create mode 100644 Assets/Tremble.meta create mode 100644 Assets/Tremble/AssetLoading.meta create mode 100644 Assets/Tremble/AssetLoading/Adaptors.meta create mode 100644 Assets/Tremble/AssetLoading/Adaptors/AddressablesLoaderAdaptor.cs create mode 100644 Assets/Tremble/AssetLoading/Adaptors/AddressablesLoaderAdaptor.cs.meta create mode 100644 Assets/Tremble/AssetLoading/Adaptors/EditorLoaderAdaptor.cs create mode 100644 Assets/Tremble/AssetLoading/Adaptors/EditorLoaderAdaptor.cs.meta create mode 100644 Assets/Tremble/AssetLoading/Adaptors/IAssetLoaderAdaptor.cs create mode 100644 Assets/Tremble/AssetLoading/Adaptors/IAssetLoaderAdaptor.cs.meta create mode 100644 Assets/Tremble/AssetLoading/Adaptors/NullLoaderAdaptor.cs create mode 100644 Assets/Tremble/AssetLoading/Adaptors/NullLoaderAdaptor.cs.meta create mode 100644 Assets/Tremble/AssetLoading/TrembleAssetLoader.cs create mode 100644 Assets/Tremble/AssetLoading/TrembleAssetLoader.cs.meta create mode 100644 Assets/Tremble/Attributes.meta create mode 100644 Assets/Tremble/Attributes/Classes.meta create mode 100644 Assets/Tremble/Attributes/Classes/BrushEntityAttribute.cs create mode 100644 Assets/Tremble/Attributes/Classes/BrushEntityAttribute.cs.meta create mode 100644 Assets/Tremble/Attributes/Classes/EntityAttributeBase.cs create mode 100644 Assets/Tremble/Attributes/Classes/EntityAttributeBase.cs.meta create mode 100644 Assets/Tremble/Attributes/Classes/PointEntityAttribute.cs create mode 100644 Assets/Tremble/Attributes/Classes/PointEntityAttribute.cs.meta create mode 100644 Assets/Tremble/Attributes/Classes/PrefabEntityAttribute.cs create mode 100644 Assets/Tremble/Attributes/Classes/PrefabEntityAttribute.cs.meta create mode 100644 Assets/Tremble/Attributes/Classes/SimpleRegexUtil.cs create mode 100644 Assets/Tremble/Attributes/Classes/SimpleRegexUtil.cs.meta create mode 100644 Assets/Tremble/Attributes/Fields.meta create mode 100644 Assets/Tremble/Attributes/Fields/SpawnFlagsAttribute.cs create mode 100644 Assets/Tremble/Attributes/Fields/SpawnFlagsAttribute.cs.meta create mode 100644 Assets/Tremble/Attributes/Fields/TrembleAttribute.cs create mode 100644 Assets/Tremble/Attributes/Fields/TrembleAttribute.cs.meta create mode 100644 Assets/Tremble/Editor.meta create mode 100644 Assets/Tremble/Editor/AssetImporters.meta create mode 100644 Assets/Tremble/Editor/AssetImporters/FgdFileAssetImporter.cs create mode 100644 Assets/Tremble/Editor/AssetImporters/FgdFileAssetImporter.cs.meta create mode 100644 Assets/Tremble/Editor/AssetImporters/TrembleMapAssetImporter.cs create mode 100644 Assets/Tremble/Editor/AssetImporters/TrembleMapAssetImporter.cs.meta create mode 100644 Assets/Tremble/Editor/AssetImporters/WadFileAssetImporter.cs create mode 100644 Assets/Tremble/Editor/AssetImporters/WadFileAssetImporter.cs.meta create mode 100644 Assets/Tremble/Editor/AssetProcessors.meta create mode 100644 Assets/Tremble/Editor/AssetProcessors/FgdFileAssetPostprocessor.cs create mode 100644 Assets/Tremble/Editor/AssetProcessors/FgdFileAssetPostprocessor.cs.meta create mode 100644 Assets/Tremble/Editor/AssetProcessors/MapFileAssetPostprocessor.cs create mode 100644 Assets/Tremble/Editor/AssetProcessors/MapFileAssetPostprocessor.cs.meta create mode 100644 Assets/Tremble/Editor/AssetProcessors/MapLiveUpdatePostprocessor.cs create mode 100644 Assets/Tremble/Editor/AssetProcessors/MapLiveUpdatePostprocessor.cs.meta create mode 100644 Assets/Tremble/Editor/AssetProcessors/TrembleCacheDropperPostprocessor.cs create mode 100644 Assets/Tremble/Editor/AssetProcessors/TrembleCacheDropperPostprocessor.cs.meta create mode 100644 Assets/Tremble/Editor/AssetProcessors/WadFileAssetPostprocessor.cs create mode 100644 Assets/Tremble/Editor/AssetProcessors/WadFileAssetPostprocessor.cs.meta create mode 100644 Assets/Tremble/Editor/EditorUI.meta create mode 100644 Assets/Tremble/Editor/EditorUI/DiagnosticsWindow.cs create mode 100644 Assets/Tremble/Editor/EditorUI/DiagnosticsWindow.cs.meta create mode 100644 Assets/Tremble/Editor/EditorUI/Drawers.meta create mode 100644 Assets/Tremble/Editor/EditorUI/Drawers/BaseClassPickerDrawer.cs create mode 100644 Assets/Tremble/Editor/EditorUI/Drawers/BaseClassPickerDrawer.cs.meta create mode 100644 Assets/Tremble/Editor/EditorUI/Drawers/MapProcessorClassDrawer.cs create mode 100644 Assets/Tremble/Editor/EditorUI/Drawers/MapProcessorClassDrawer.cs.meta create mode 100644 Assets/Tremble/Editor/EditorUI/Drawers/WorldspawnScriptDrawer.cs create mode 100644 Assets/Tremble/Editor/EditorUI/Drawers/WorldspawnScriptDrawer.cs.meta create mode 100644 Assets/Tremble/Editor/EditorUI/Editors.meta create mode 100644 Assets/Tremble/Editor/EditorUI/Editors/WadAssetImporterEditor.cs create mode 100644 Assets/Tremble/Editor/EditorUI/Editors/WadAssetImporterEditor.cs.meta create mode 100644 Assets/Tremble/Editor/EditorUI/MapHierarchyIcons.cs create mode 100644 Assets/Tremble/Editor/EditorUI/MapHierarchyIcons.cs.meta create mode 100644 Assets/Tremble/Editor/EditorUI/MapRepairWindow.cs create mode 100644 Assets/Tremble/Editor/EditorUI/MapRepairWindow.cs.meta create mode 100644 Assets/Tremble/Editor/EditorUI/Materials.meta create mode 100644 Assets/Tremble/Editor/EditorUI/Materials/MaterialInspectorGUI.cs create mode 100644 Assets/Tremble/Editor/EditorUI/Materials/MaterialInspectorGUI.cs.meta create mode 100644 Assets/Tremble/Editor/EditorUI/Materials/NewMaterialGroupWindow.cs create mode 100644 Assets/Tremble/Editor/EditorUI/Materials/NewMaterialGroupWindow.cs.meta create mode 100644 Assets/Tremble/Editor/EditorUI/Q3Map2OutputWindow.cs create mode 100644 Assets/Tremble/Editor/EditorUI/Q3Map2OutputWindow.cs.meta create mode 100644 Assets/Tremble/Editor/EditorUI/Settings.meta create mode 100644 Assets/Tremble/Editor/EditorUI/Settings/TrembleProjectSettingsProvider.cs create mode 100644 Assets/Tremble/Editor/EditorUI/Settings/TrembleProjectSettingsProvider.cs.meta create mode 100644 Assets/Tremble/Editor/EditorUI/Settings/TrembleSyncSettingsEditor.cs create mode 100644 Assets/Tremble/Editor/EditorUI/Settings/TrembleSyncSettingsEditor.cs.meta create mode 100644 Assets/Tremble/Editor/EditorUI/TrembleIcons.cs create mode 100644 Assets/Tremble/Editor/EditorUI/TrembleIcons.cs.meta create mode 100644 Assets/Tremble/Editor/EditorUI/TrembleSyncOverlay.cs create mode 100644 Assets/Tremble/Editor/EditorUI/TrembleSyncOverlay.cs.meta create mode 100644 Assets/Tremble/Editor/EditorUI/Utils.meta create mode 100644 Assets/Tremble/Editor/EditorUI/Utils/EditorGUILayoutUtil.cs create mode 100644 Assets/Tremble/Editor/EditorUI/Utils/EditorGUILayoutUtil.cs.meta create mode 100644 Assets/Tremble/Editor/EditorUI/Utils/EditorGameObjectIconUtil.cs create mode 100644 Assets/Tremble/Editor/EditorUI/Utils/EditorGameObjectIconUtil.cs.meta create mode 100644 Assets/Tremble/Editor/EditorUI/Utils/MaterialGroupUtil.cs create mode 100644 Assets/Tremble/Editor/EditorUI/Utils/MaterialGroupUtil.cs.meta create mode 100644 Assets/Tremble/Editor/EditorUI/Utils/MaterialRenderDataUtil.cs create mode 100644 Assets/Tremble/Editor/EditorUI/Utils/MaterialRenderDataUtil.cs.meta create mode 100644 Assets/Tremble/Editor/EditorUI/Utils/TrembleSettingsGUI.cs create mode 100644 Assets/Tremble/Editor/EditorUI/Utils/TrembleSettingsGUI.cs.meta create mode 100644 Assets/Tremble/Editor/Icons.meta create mode 100644 Assets/Tremble/Editor/Icons/T_TB_Config.png create mode 100644 Assets/Tremble/Editor/Icons/T_TB_Config.png.meta create mode 100644 Assets/Tremble/Editor/Icons/T_TB_Import.png create mode 100644 Assets/Tremble/Editor/Icons/T_TB_Import.png.meta create mode 100644 Assets/Tremble/Editor/Icons/T_TB_Manual.png create mode 100644 Assets/Tremble/Editor/Icons/T_TB_Manual.png.meta create mode 100644 Assets/Tremble/Editor/Icons/T_TB_Sync.png create mode 100644 Assets/Tremble/Editor/Icons/T_TB_Sync.png.meta create mode 100644 Assets/Tremble/Editor/Icons/T_TrembleLogo.png create mode 100644 Assets/Tremble/Editor/Icons/T_TrembleLogo.png.meta create mode 100644 Assets/Tremble/Editor/Manual.meta create mode 100644 Assets/Tremble/Editor/Manual/FNT_UbuntuMono.ttf create mode 100644 Assets/Tremble/Editor/Manual/FNT_UbuntuMono.ttf.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualEntry.cs create mode 100644 Assets/Tremble/Editor/Manual/ManualEntry.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_BrushEntity.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_BrushEntity.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_CreateMap.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_CreateMap.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_LiveUpdate1.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_LiveUpdate1.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_LiveUpdate2.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_LiveUpdate2.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MapProcessor.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MapProcessor.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MapRepair.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MapRepair.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MapRepair_Entities.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MapRepair_Entities.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MapRepair_NoFGD.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MapRepair_NoFGD.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MapRepair_Required.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MapRepair_Required.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MapRepair_Textures.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MapRepair_Textures.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MapRepair_WithFGD.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MapRepair_WithFGD.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MaterialGroups.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MaterialGroups.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MissingGeo_TB1.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MissingGeo_TB1.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MissingGeo_TB2.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MissingGeo_TB2.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MissingGeo_Unity1.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MissingGeo_Unity1.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MissingGeo_Unity2.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_MissingGeo_Unity2.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_Pipeline.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_Pipeline.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_PointEntity.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_PointEntity.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_PrefabEntity.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_PrefabEntity.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_RenderSettings.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_RenderSettings.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_SpawnablePrefab.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_SpawnablePrefab.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_Trouble_DLL1.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_Trouble_DLL1.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_Trouble_DLL2.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_Trouble_DLL2.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_Trouble_FixPinkMaterialsVideo.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_Trouble_FixPinkMaterialsVideo.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_Trouble_MaterialBrightness.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_Trouble_MaterialBrightness.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_Trouble_MaterialBrightnessSettings.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_Trouble_MaterialBrightnessSettings.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_Trouble_PinkMaterials.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_Trouble_PinkMaterials.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_WadImport2.png create mode 100644 Assets/Tremble/Editor/Manual/ManualImages/T_Manual_WadImport2.png.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualPageAttribute.cs create mode 100644 Assets/Tremble/Editor/Manual/ManualPageAttribute.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualPageBase.cs create mode 100644 Assets/Tremble/Editor/Manual/ManualPageBase.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualStyles.cs create mode 100644 Assets/Tremble/Editor/Manual/ManualStyles.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/ManualWindow.cs create mode 100644 Assets/Tremble/Editor/Manual/ManualWindow.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Advanced.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Advanced/BaseClassesPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Advanced/BaseClassesPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Advanced/CustomTypesPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Advanced/CustomTypesPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Advanced/MapProcessorPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Advanced/MapProcessorPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Advanced/OnImportFromMapEntityPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Advanced/OnImportFromMapEntityPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Advanced/PipelinePage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Advanced/PipelinePage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Advanced/RuntimeQueryingPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Advanced/RuntimeQueryingPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Basics.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Basics/CreateMapPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Basics/CreateMapPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Basics/LiveUpdatePage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Basics/LiveUpdatePage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Basics/SettingsPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Basics/SettingsPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Basics/SyncOverlayPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Basics/SyncOverlayPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Debug.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Debug/DebugSanityCheckPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Debug/DebugSanityCheckPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Debug/DebugShowEntitiesPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Debug/DebugShowEntitiesPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Debug/DebugShowMaterialsPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Debug/DebugShowMaterialsPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/BrushEntitiesPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/BrushEntitiesPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/BuilderPageBase.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/BuilderPageBase.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/Builders.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/Builders/BrushBuilderPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/Builders/BrushBuilderPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/Builders/PointBuilderPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/Builders/PointBuilderPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/Builders/PrefabBuilderPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/Builders/PrefabBuilderPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/EntitiesOverviewPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/EntitiesOverviewPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/PointEntitiesPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/PointEntitiesPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/Prefabs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/Prefabs/PrefabEntitiesPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/Prefabs/PrefabEntitiesPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/Prefabs/SpawnablePrefabsPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Entities/Prefabs/SpawnablePrefabsPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/MapRepairPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/MapRepairPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Materials.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Materials/MaterialGroupsPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Materials/MaterialGroupsPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Materials/MaterialRenderDataPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Materials/MaterialRenderDataPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Materials/MaterialsAboutPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Materials/MaterialsAboutPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/OtherGames.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/OtherGames/ImportFgdPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/OtherGames/ImportFgdPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/OtherGames/ImportWadPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/OtherGames/ImportWadPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/OtherGames/MapRepairFgdComparisonPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/OtherGames/MapRepairFgdComparisonPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/OtherGames/MapRepairForeignPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/OtherGames/MapRepairForeignPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/OverviewPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/OverviewPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Troubleshooting.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Troubleshooting/TroubleshootingDLLPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Troubleshooting/TroubleshootingDLLPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Troubleshooting/TroubleshootingGetHelpPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Troubleshooting/TroubleshootingGetHelpPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Troubleshooting/TroubleshootingMaterialBrightnessPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Troubleshooting/TroubleshootingMaterialBrightnessPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Troubleshooting/TroubleshootingMissingGeoPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Troubleshooting/TroubleshootingMissingGeoPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/Troubleshooting/TroubleshootingPinkMaterialsPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/Troubleshooting/TroubleshootingPinkMaterialsPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/UserGeneratedContent.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/UserGeneratedContent/UgcPlayerHintsPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/UserGeneratedContent/UgcPlayerHintsPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/Pages/UserGeneratedContent/UgcSetupPage.cs create mode 100644 Assets/Tremble/Editor/Manual/Pages/UserGeneratedContent/UgcSetupPage.cs.meta create mode 100644 Assets/Tremble/Editor/Manual/T_Bookmark_Off.png create mode 100644 Assets/Tremble/Editor/Manual/T_Bookmark_Off.png.meta create mode 100644 Assets/Tremble/Editor/Manual/T_Bookmark_On.png create mode 100644 Assets/Tremble/Editor/Manual/T_Bookmark_On.png.meta create mode 100644 Assets/Tremble/Editor/Templates.meta create mode 100644 Assets/Tremble/Editor/Templates/gameconfig-4.cfg create mode 100644 Assets/Tremble/Editor/Templates/gameconfig-4.cfg.meta create mode 100644 Assets/Tremble/Editor/Templates/gameconfig-8.cfg create mode 100644 Assets/Tremble/Editor/Templates/gameconfig-8.cfg.meta create mode 100644 Assets/Tremble/Editor/Templates/gameconfig-9.cfg create mode 100644 Assets/Tremble/Editor/Templates/gameconfig-9.cfg.meta create mode 100644 Assets/Tremble/Editor/TinyGoose.Tremble.Editor.asmdef create mode 100644 Assets/Tremble/Editor/TinyGoose.Tremble.Editor.asmdef.meta create mode 100644 Assets/Tremble/Editor/TrembleEditorAPI.cs create mode 100644 Assets/Tremble/Editor/TrembleEditorAPI.cs.meta create mode 100644 Assets/Tremble/Editor/TrembleEditorUtility.cs create mode 100644 Assets/Tremble/Editor/TrembleEditorUtility.cs.meta create mode 100644 Assets/Tremble/Editor/TrembleMenu.cs create mode 100644 Assets/Tremble/Editor/TrembleMenu.cs.meta create mode 100644 Assets/Tremble/Editor/TrembleSync.cs create mode 100644 Assets/Tremble/Editor/TrembleSync.cs.meta create mode 100644 Assets/Tremble/Editor/TrembleSyncAddressables.cs create mode 100644 Assets/Tremble/Editor/TrembleSyncAddressables.cs.meta create mode 100644 Assets/Tremble/Editor/Utils.meta create mode 100644 Assets/Tremble/Editor/Utils/AssetDatabaseUtil.cs create mode 100644 Assets/Tremble/Editor/Utils/AssetDatabaseUtil.cs.meta create mode 100644 Assets/Tremble/Editor/Utils/EditorCompileUtil.cs create mode 100644 Assets/Tremble/Editor/Utils/EditorCompileUtil.cs.meta create mode 100644 Assets/Tremble/Editor/Utils/EditorPrefsBackedString.cs create mode 100644 Assets/Tremble/Editor/Utils/EditorPrefsBackedString.cs.meta create mode 100644 Assets/Tremble/Editor/Utils/ModTimeDB.cs create mode 100644 Assets/Tremble/Editor/Utils/ModTimeDB.cs.meta create mode 100644 Assets/Tremble/Editor/Utils/SerializedObjectUtil.cs create mode 100644 Assets/Tremble/Editor/Utils/SerializedObjectUtil.cs.meta create mode 100644 Assets/Tremble/Editor/Utils/VersionCheck.cs create mode 100644 Assets/Tremble/Editor/Utils/VersionCheck.cs.meta create mode 100644 Assets/Tremble/FieldConverters.meta create mode 100644 Assets/Tremble/FieldConverters/BaseClasses.meta create mode 100644 Assets/Tremble/FieldConverters/BaseClasses/UnityAssetFieldConverter.cs create mode 100644 Assets/Tremble/FieldConverters/BaseClasses/UnityAssetFieldConverter.cs.meta create mode 100644 Assets/Tremble/FieldConverters/BoolFieldConverter.cs create mode 100644 Assets/Tremble/FieldConverters/BoolFieldConverter.cs.meta create mode 100644 Assets/Tremble/FieldConverters/ColourFieldConverter.cs create mode 100644 Assets/Tremble/FieldConverters/ColourFieldConverter.cs.meta create mode 100644 Assets/Tremble/FieldConverters/ComponentReferenceFieldConverter.cs create mode 100644 Assets/Tremble/FieldConverters/ComponentReferenceFieldConverter.cs.meta create mode 100644 Assets/Tremble/FieldConverters/EnumFieldConverter.cs create mode 100644 Assets/Tremble/FieldConverters/EnumFieldConverter.cs.meta create mode 100644 Assets/Tremble/FieldConverters/FloatFieldConverter.cs create mode 100644 Assets/Tremble/FieldConverters/FloatFieldConverter.cs.meta create mode 100644 Assets/Tremble/FieldConverters/IntFieldConverter.cs create mode 100644 Assets/Tremble/FieldConverters/IntFieldConverter.cs.meta create mode 100644 Assets/Tremble/FieldConverters/MaterialFieldConverter.cs create mode 100644 Assets/Tremble/FieldConverters/MaterialFieldConverter.cs.meta create mode 100644 Assets/Tremble/FieldConverters/PrefabFieldConverter.cs create mode 100644 Assets/Tremble/FieldConverters/PrefabFieldConverter.cs.meta create mode 100644 Assets/Tremble/FieldConverters/ScriptableObjectFieldConverter.cs create mode 100644 Assets/Tremble/FieldConverters/ScriptableObjectFieldConverter.cs.meta create mode 100644 Assets/Tremble/FieldConverters/StringFieldConverter.cs create mode 100644 Assets/Tremble/FieldConverters/StringFieldConverter.cs.meta create mode 100644 Assets/Tremble/FieldConverters/TrembleFieldConverter.cs create mode 100644 Assets/Tremble/FieldConverters/TrembleFieldConverter.cs.meta create mode 100644 Assets/Tremble/FieldConverters/TrembleFieldConverterCollection.cs create mode 100644 Assets/Tremble/FieldConverters/TrembleFieldConverterCollection.cs.meta create mode 100644 Assets/Tremble/FieldConverters/Vector3Converter.cs create mode 100644 Assets/Tremble/FieldConverters/Vector3Converter.cs.meta create mode 100644 Assets/Tremble/FieldConverters/Vector3IntConverter.cs create mode 100644 Assets/Tremble/FieldConverters/Vector3IntConverter.cs.meta create mode 100644 Assets/Tremble/IO.meta create mode 100644 Assets/Tremble/IO/BSP.meta create mode 100644 Assets/Tremble/IO/BSP/BspParser.cs create mode 100644 Assets/Tremble/IO/BSP/BspParser.cs.meta create mode 100644 Assets/Tremble/IO/FGD.meta create mode 100644 Assets/Tremble/IO/FGD/FgdClass.cs create mode 100644 Assets/Tremble/IO/FGD/FgdClass.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FgdFieldBase.cs create mode 100644 Assets/Tremble/IO/FGD/FgdFieldBase.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FgdFieldFactory.cs create mode 100644 Assets/Tremble/IO/FGD/FgdFieldFactory.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FgdInferredFieldExtensions.cs create mode 100644 Assets/Tremble/IO/FGD/FgdInferredFieldExtensions.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FgdParser.cs create mode 100644 Assets/Tremble/IO/FGD/FgdParser.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FgdWriter.cs create mode 100644 Assets/Tremble/IO/FGD/FgdWriter.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FieldTypes.meta create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdAnglesField.cs create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdAnglesField.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdBooleanField.cs create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdBooleanField.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdChoicesIntField.cs create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdChoicesIntField.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdChoicesStringField.cs create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdChoicesStringField.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdColourField.cs create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdColourField.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdComment.cs create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdComment.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdEnumField.cs create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdEnumField.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdFlagsField.cs create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdFlagsField.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdFloatField.cs create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdFloatField.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdIntegerField.cs create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdIntegerField.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdSpawnFlagField.cs create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdSpawnFlagField.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdStringField.cs create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdStringField.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdTargetDestinationField.cs create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdTargetDestinationField.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdTargetSourceField.cs create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdTargetSourceField.cs.meta create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdVectorField.cs create mode 100644 Assets/Tremble/IO/FGD/FieldTypes/FgdVectorField.cs.meta create mode 100644 Assets/Tremble/IO/FGD/Writers.meta create mode 100644 Assets/Tremble/IO/FGD/Writers/EntityClassWriter.cs create mode 100644 Assets/Tremble/IO/FGD/Writers/EntityClassWriter.cs.meta create mode 100644 Assets/Tremble/IO/FGD/Writers/EntityEnumWriter.cs create mode 100644 Assets/Tremble/IO/FGD/Writers/EntityEnumWriter.cs.meta create mode 100644 Assets/Tremble/IO/MAP.meta create mode 100644 Assets/Tremble/IO/MAP/MapParser.cs create mode 100644 Assets/Tremble/IO/MAP/MapParser.cs.meta create mode 100644 Assets/Tremble/IO/StreamIO.cs create mode 100644 Assets/Tremble/IO/StreamIO.cs.meta create mode 100644 Assets/Tremble/IO/TokenParser.cs create mode 100644 Assets/Tremble/IO/TokenParser.cs.meta create mode 100644 Assets/Tremble/IO/WAD.meta create mode 100644 Assets/Tremble/IO/WAD/WadFile.cs create mode 100644 Assets/Tremble/IO/WAD/WadFile.cs.meta create mode 100644 Assets/Tremble/IO/WAD/WadParser.cs create mode 100644 Assets/Tremble/IO/WAD/WadParser.cs.meta create mode 100644 Assets/Tremble/Import.meta create mode 100644 Assets/Tremble/Import/MapCompiler.cs create mode 100644 Assets/Tremble/Import/MapCompiler.cs.meta create mode 100644 Assets/Tremble/Import/MapCompilerOutputHandler.cs create mode 100644 Assets/Tremble/Import/MapCompilerOutputHandler.cs.meta create mode 100644 Assets/Tremble/Import/MapProcessorBase.cs create mode 100644 Assets/Tremble/Import/MapProcessorBase.cs.meta create mode 100644 Assets/Tremble/Import/Q3Map2Dll.cs create mode 100644 Assets/Tremble/Import/Q3Map2Dll.cs.meta create mode 100644 Assets/Tremble/Import/Q3Map2VersionInfo.cs create mode 100644 Assets/Tremble/Import/Q3Map2VersionInfo.cs.meta create mode 100644 Assets/Tremble/Interfaces.meta create mode 100644 Assets/Tremble/Interfaces/IOnImportFromMapEntity.cs create mode 100644 Assets/Tremble/Interfaces/IOnImportFromMapEntity.cs.meta create mode 100644 Assets/Tremble/Interfaces/IOnLiveUpdate.cs create mode 100644 Assets/Tremble/Interfaces/IOnLiveUpdate.cs.meta create mode 100644 Assets/Tremble/Interfaces/ITrembleBaseClass.cs create mode 100644 Assets/Tremble/Interfaces/ITrembleBaseClass.cs.meta create mode 100644 Assets/Tremble/LICENSE create mode 100644 Assets/Tremble/LICENSE.meta create mode 100644 Assets/Tremble/Materials.meta create mode 100644 Assets/Tremble/Materials/Clip.shader create mode 100644 Assets/Tremble/Materials/Clip.shader.meta create mode 100644 Assets/Tremble/Materials/M_NullRender.mat create mode 100644 Assets/Tremble/Materials/M_NullRender.mat.meta create mode 100644 Assets/Tremble/MonoBehaviours.meta create mode 100644 Assets/Tremble/MonoBehaviours/MapDocument.cs create mode 100644 Assets/Tremble/MonoBehaviours/MapDocument.cs.meta create mode 100644 Assets/Tremble/MonoBehaviours/SeparateMesh.cs create mode 100644 Assets/Tremble/MonoBehaviours/SeparateMesh.cs.meta create mode 100644 Assets/Tremble/MonoBehaviours/TrembleSpawnablePrefab.cs create mode 100644 Assets/Tremble/MonoBehaviours/TrembleSpawnablePrefab.cs.meta create mode 100644 Assets/Tremble/MonoBehaviours/Worldspawn.cs create mode 100644 Assets/Tremble/MonoBehaviours/Worldspawn.cs.meta create mode 100644 Assets/Tremble/Plugins.meta create mode 100644 Assets/Tremble/Plugins/ARM64.meta create mode 100644 Assets/Tremble/Plugins/ARM64/q3map2.dylib create mode 100644 Assets/Tremble/Plugins/ARM64/q3map2.dylib.meta create mode 100644 Assets/Tremble/Plugins/x86_64.meta create mode 100644 Assets/Tremble/Plugins/x86_64/q3map2.dll create mode 100644 Assets/Tremble/Plugins/x86_64/q3map2.dll.meta create mode 100644 Assets/Tremble/Plugins/x86_64/q3map2.dylib create mode 100644 Assets/Tremble/Plugins/x86_64/q3map2.dylib.meta create mode 100644 Assets/Tremble/Plugins/x86_64/q3map2.so create mode 100644 Assets/Tremble/Plugins/x86_64/q3map2.so.meta create mode 100644 Assets/Tremble/ScriptableObjects.meta create mode 100644 Assets/Tremble/ScriptableObjects/FgdFileAsset.cs create mode 100644 Assets/Tremble/ScriptableObjects/FgdFileAsset.cs.meta create mode 100644 Assets/Tremble/ScriptableObjects/MapFileAsset.cs create mode 100644 Assets/Tremble/ScriptableObjects/MapFileAsset.cs.meta create mode 100644 Assets/Tremble/ScriptableObjects/WadFileAsset.cs create mode 100644 Assets/Tremble/ScriptableObjects/WadFileAsset.cs.meta create mode 100644 Assets/Tremble/TinyGoose.Tremble.asmdef create mode 100644 Assets/Tremble/TinyGoose.Tremble.asmdef.meta create mode 100644 Assets/Tremble/Tremble User Guide.pdf create mode 100644 Assets/Tremble/Tremble User Guide.pdf.meta create mode 100644 Assets/Tremble/TrembleConsts.cs create mode 100644 Assets/Tremble/TrembleConsts.cs.meta create mode 100644 Assets/Tremble/TrembleMapImport.cs create mode 100644 Assets/Tremble/TrembleMapImport.cs.meta create mode 100644 Assets/Tremble/TrembleRuntimeAPI.cs create mode 100644 Assets/Tremble/TrembleRuntimeAPI.cs.meta create mode 100644 Assets/Tremble/TrembleSyncSettings.cs create mode 100644 Assets/Tremble/TrembleSyncSettings.cs.meta create mode 100644 Assets/Tremble/TypeLookups.meta create mode 100644 Assets/Tremble/TypeLookups/MapTypeLookup.cs create mode 100644 Assets/Tremble/TypeLookups/MapTypeLookup.cs.meta create mode 100644 Assets/Tremble/TypeLookups/MaterialNameLookup.cs create mode 100644 Assets/Tremble/TypeLookups/MaterialNameLookup.cs.meta create mode 100644 Assets/Tremble/TypeLookups/PrefabNameLookup.cs create mode 100644 Assets/Tremble/TypeLookups/PrefabNameLookup.cs.meta create mode 100644 Assets/Tremble/Types.meta create mode 100644 Assets/Tremble/Types/BspTypes.cs create mode 100644 Assets/Tremble/Types/BspTypes.cs.meta create mode 100644 Assets/Tremble/Types/MapBspGetters.cs create mode 100644 Assets/Tremble/Types/MapBspGetters.cs.meta create mode 100644 Assets/Tremble/Types/MapProcessorClass.cs create mode 100644 Assets/Tremble/Types/MapProcessorClass.cs.meta create mode 100644 Assets/Tremble/Types/MaterialExportSize.cs create mode 100644 Assets/Tremble/Types/MaterialExportSize.cs.meta create mode 100644 Assets/Tremble/Types/MaterialRenderData.cs create mode 100644 Assets/Tremble/Types/MaterialRenderData.cs.meta create mode 100644 Assets/Tremble/Types/TpakArchive.cs create mode 100644 Assets/Tremble/Types/TpakArchive.cs.meta create mode 100644 Assets/Tremble/Types/TrembleTimer.cs create mode 100644 Assets/Tremble/Types/TrembleTimer.cs.meta create mode 100644 Assets/Tremble/Types/TwoWayDictionary.cs create mode 100644 Assets/Tremble/Types/TwoWayDictionary.cs.meta create mode 100644 Assets/Tremble/Types/WorldspawnScript.cs create mode 100644 Assets/Tremble/Types/WorldspawnScript.cs.meta create mode 100644 Assets/Tremble/Utils.meta create mode 100644 Assets/Tremble/Utils/DirectoryUtil.cs create mode 100644 Assets/Tremble/Utils/DirectoryUtil.cs.meta create mode 100644 Assets/Tremble/Utils/FieldUtil.cs create mode 100644 Assets/Tremble/Utils/FieldUtil.cs.meta create mode 100644 Assets/Tremble/Utils/FloatFormatUtil.cs create mode 100644 Assets/Tremble/Utils/FloatFormatUtil.cs.meta create mode 100644 Assets/Tremble/Utils/GameObjectUtil.cs create mode 100644 Assets/Tremble/Utils/GameObjectUtil.cs.meta create mode 100644 Assets/Tremble/Utils/InitHack.cs create mode 100644 Assets/Tremble/Utils/InitHack.cs.meta create mode 100644 Assets/Tremble/Utils/MD3Util.cs create mode 100644 Assets/Tremble/Utils/MD3Util.cs.meta create mode 100644 Assets/Tremble/Utils/MapTextureSnapshotter.cs create mode 100644 Assets/Tremble/Utils/MapTextureSnapshotter.cs.meta create mode 100644 Assets/Tremble/Utils/MeshBuilder.cs create mode 100644 Assets/Tremble/Utils/MeshBuilder.cs.meta create mode 100644 Assets/Tremble/Utils/NamingConventionUtil.cs create mode 100644 Assets/Tremble/Utils/NamingConventionUtil.cs.meta create mode 100644 Assets/Tremble/Utils/PackedResourceUtil.cs create mode 100644 Assets/Tremble/Utils/PackedResourceUtil.cs.meta create mode 100644 Assets/Tremble/Utils/PrefabUtil.cs create mode 100644 Assets/Tremble/Utils/PrefabUtil.cs.meta create mode 100644 Assets/Tremble/Utils/ProgressUtil.cs create mode 100644 Assets/Tremble/Utils/ProgressUtil.cs.meta create mode 100644 Assets/Tremble/Utils/StreamWriterUtil.cs create mode 100644 Assets/Tremble/Utils/StreamWriterUtil.cs.meta create mode 100644 Assets/Tremble/Utils/StringUtil.cs create mode 100644 Assets/Tremble/Utils/StringUtil.cs.meta create mode 100644 Assets/Tremble/Utils/TextureUtil.cs create mode 100644 Assets/Tremble/Utils/TextureUtil.cs.meta create mode 100644 Assets/Tremble/Utils/TrenchBroomUtil.cs create mode 100644 Assets/Tremble/Utils/TrenchBroomUtil.cs.meta create mode 100644 Assets/Tremble/Utils/TypeDatabase.cs create mode 100644 Assets/Tremble/Utils/TypeDatabase.cs.meta create mode 100644 Assets/UnityCodeGen.Generated.meta create mode 100644 Assets/UnityCodeGen.Generated/AudioMixer.Generated.cs create mode 100644 Assets/UnityCodeGen.Generated/AudioMixer.Generated.cs.meta create mode 100644 Assets/UnityCodeGen.Generated/Code.Game.Gameplay.Player.CleanerCameraState.Generated.cs create mode 100644 Assets/UnityCodeGen.Generated/Code.Game.Gameplay.Player.CleanerCameraState.Generated.cs.meta create mode 100644 Assets/UnityCodeGen.Generated/Code.Game.TestingLevel.TestingState.Generated.cs create mode 100644 Assets/UnityCodeGen.Generated/Code.Game.TestingLevel.TestingState.Generated.cs.meta create mode 100644 Assets/UnityCodeGen.Generated/Code.Infrastructure.App.AppStateMachine.Generated.cs create mode 100644 Assets/UnityCodeGen.Generated/Code.Infrastructure.App.AppStateMachine.Generated.cs.meta create mode 100644 Assets/UnityCodeGen.Generated/Code.Infrastructure.Camera.CameraStateMachine.Generated.cs create mode 100644 Assets/UnityCodeGen.Generated/Code.Infrastructure.Camera.CameraStateMachine.Generated.cs.meta create mode 100644 Assets/UnityCodeGen.Generated/Code.Infrastructure.Camera.CameraStates.NoneCameraState.Generated.cs create mode 100644 Assets/UnityCodeGen.Generated/Code.Infrastructure.Camera.CameraStates.NoneCameraState.Generated.cs.meta create mode 100644 Assets/UnityCodeGen.Generated/ConfigLocator.Generated.cs create mode 100644 Assets/UnityCodeGen.Generated/ConfigLocator.Generated.cs.meta create mode 100644 Assets/UnityCodeGen.Generated/ConfigReferences.Generated.cs create mode 100644 Assets/UnityCodeGen.Generated/ConfigReferences.Generated.cs.meta create mode 100644 Assets/packages.config create mode 100644 Assets/packages.config.meta create mode 100644 Packages/manifest.json create mode 100644 Packages/packages-lock.json create mode 100644 ProjectSettings/AlchemySettings.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/PackageManagerSettings.asset create mode 100644 ProjectSettings/Physics2DSettings.asset create mode 100644 ProjectSettings/PhysicsCoreProjectSettings2D.asset create mode 100644 ProjectSettings/PresetManager.asset create mode 100644 ProjectSettings/ProjectAuditorSettings.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/Assets/AddressableAssetsData.meta b/Assets/AddressableAssetsData.meta new file mode 100644 index 00000000..8ae34a0a --- /dev/null +++ b/Assets/AddressableAssetsData.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f0070d9ab552be2bb8aa0b8fa9f5b035 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AddressableAssetsData/AddressableAssetSettings.asset b/Assets/AddressableAssetsData/AddressableAssetSettings.asset new file mode 100644 index 00000000..98d8ca42 --- /dev/null +++ b/Assets/AddressableAssetsData/AddressableAssetSettings.asset @@ -0,0 +1,124 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 468a46d0ae32c3544b7d98094e6448a9, type: 3} + m_Name: AddressableAssetSettings + m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.AddressableAssetSettings + m_DefaultGroup: c6b29e598b23fb86ab8489c479625427 + m_currentHash: + serializedVersion: 2 + Hash: 6035695aa4e96d0309c1b9843c316678 + m_ExtractTypeTreeData: 0 + m_OptimizeCatalogSize: 0 + m_BuildRemoteCatalog: 0 + m_CatalogRequestsTimeout: 0 + m_DisableCatalogUpdateOnStart: 0 + m_InternalIdNamingMode: 0 + m_InternalBundleIdMode: 1 + m_AssetLoadMode: 0 + m_BundledAssetProviderType: + m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.BundledAssetProvider + m_AssetBundleProviderType: + m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.AssetBundleProvider + m_IgnoreUnsupportedFilesInBuild: 0 + m_UniqueBundleIds: 0 + m_EnableJsonCatalog: 0 + m_NonRecursiveBuilding: 1 + m_AllowNestedBundleFolders: 0 + m_CCDEnabled: 0 + m_maxConcurrentWebRequests: 3 + m_UseUWRForLocalBundles: 0 + m_BundleTimeout: 0 + m_BundleRetryCount: 0 + m_BundleRedirectLimit: -1 + m_SharedBundleSettings: 0 + m_SharedBundleSettingsCustomGroupIndex: 0 + m_simulatedLoadDelay: 0.1 + m_ContiguousBundles: 1 + m_StripUnityVersionFromBundleBuild: 0 + m_DisableVisibleSubAssetRepresentations: 0 + m_BuiltInBundleNaming: 0 + mBuiltInBundleCustomNaming: + m_MonoScriptBundleNaming: 0 + m_CheckForContentUpdateRestrictionsOption: 0 + m_MonoScriptBundleCustomNaming: + m_RemoteCatalogBuildPath: + m_Id: + m_RemoteCatalogLoadPath: + m_Id: + m_ContentStateBuildPathProfileVariableName: + m_CustomContentStateBuildPath: + m_ContentStateBuildPath: + m_BuildAddressablesWithPlayerBuild: 0 + m_overridePlayerVersion: '[UnityEditor.PlayerSettings.bundleVersion]' + m_GroupAssets: + - {fileID: 11400000, guid: 26d0fba16e9d375ab8f8eee15dc5c99a, type: 2} + m_BuildSettings: + m_LogResourceManagerExceptions: 1 + m_BundleBuildPath: Temp/com.unity.addressables/AssetBundles + m_ProfileSettings: + m_Profiles: + - m_InheritedParent: + m_Id: 7936c68390da9b21c9d4f479d7f7a261 + m_ProfileName: Default + m_Values: + - m_Id: 29df4a9753b8b149d85f010cf7480237 + m_Value: '[UnityEngine.AddressableAssets.Addressables.BuildPath]/[BuildTarget]' + - m_Id: 2fad9c55a0f95113b8afde036bf8d205 + m_Value: + - m_Id: 4efa63d245bcc3563a4e5c228ff91b55 + m_Value: '{UnityEngine.AddressableAssets.Addressables.RuntimePath}/[BuildTarget]' + - m_Id: 4f6d10d48bbef02988375cf7a5a315a3 + m_Value: '[UnityEditor.EditorUserBuildSettings.activeBuildTarget]' + - m_Id: 523506dc6b7458e49b2586343fb4ffa9 + m_Value: 'ServerData/[BuildTarget]' + m_ProfileEntryNames: + - m_Id: 29df4a9753b8b149d85f010cf7480237 + m_Name: Local.BuildPath + m_InlineUsage: 0 + - m_Id: 2fad9c55a0f95113b8afde036bf8d205 + m_Name: Remote.LoadPath + m_InlineUsage: 0 + - m_Id: 4efa63d245bcc3563a4e5c228ff91b55 + m_Name: Local.LoadPath + m_InlineUsage: 0 + - m_Id: 4f6d10d48bbef02988375cf7a5a315a3 + m_Name: BuildTarget + m_InlineUsage: 0 + - m_Id: 523506dc6b7458e49b2586343fb4ffa9 + m_Name: Remote.BuildPath + m_InlineUsage: 0 + m_ProfileVersion: 1 + m_LabelTable: + m_LabelNames: + - default + - AudioSourceSettings + - AudioInfo + - Particles + - UIPanel + - Volume + - SceneInfo + - CleanTool + m_SchemaTemplates: [] + m_GroupTemplateObjects: + - {fileID: 11400000, guid: 8c4ebef95ae1ef057bea1e3916daec48, type: 2} + m_InitializationObjects: [] + m_CertificateHandlerType: + m_AssemblyName: + m_ClassName: + m_ActivePlayerDataBuilderIndex: 2 + m_DataBuilders: + - {fileID: 11400000, guid: 954ad4ecd0dc213b192cfe18e6022fcf, type: 2} + - {fileID: 11400000, guid: e30c90a90283fe46d88ee48888ca5acf, type: 2} + - {fileID: 11400000, guid: 36ff3fee814db2e40b7585fa27714179, type: 2} + m_ActiveProfileId: 7936c68390da9b21c9d4f479d7f7a261 diff --git a/Assets/AddressableAssetsData/AddressableAssetSettings.asset.meta b/Assets/AddressableAssetsData/AddressableAssetSettings.asset.meta new file mode 100644 index 00000000..a721f2f9 --- /dev/null +++ b/Assets/AddressableAssetsData/AddressableAssetSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fca3ff8b9d20369af80cdf3da2a95a6f +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AddressableAssetsData/AssetGroupTemplates.meta b/Assets/AddressableAssetsData/AssetGroupTemplates.meta new file mode 100644 index 00000000..2eaaa305 --- /dev/null +++ b/Assets/AddressableAssetsData/AssetGroupTemplates.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e2e850970db2d8c579a490fc8dafcc5e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AddressableAssetsData/AssetGroupTemplates/Packed Assets.asset b/Assets/AddressableAssetsData/AssetGroupTemplates/Packed Assets.asset new file mode 100644 index 00000000..912bb131 --- /dev/null +++ b/Assets/AddressableAssetsData/AssetGroupTemplates/Packed Assets.asset @@ -0,0 +1,79 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1a3c5d64ac83548c09dd1678b9f6f1cd, type: 3} + m_Name: Packed Assets + m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.AddressableAssetGroupTemplate + m_SchemaObjects: + - {fileID: 8078399966258360141} + - {fileID: 1844683351890208849} + m_Description: Pack assets into asset bundles. + m_Settings: {fileID: 11400000, guid: fca3ff8b9d20369af80cdf3da2a95a6f, type: 2} +--- !u!114 &1844683351890208849 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5834b5087d578d24c926ce20cd31e6d6, type: 3} + m_Name: ContentUpdateGroupSchema + m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.GroupSchemas.ContentUpdateGroupSchema + m_Group: {fileID: 0} + m_StaticContent: 0 +--- !u!114 &8078399966258360141 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e5d17a21594effb4e9591490b009e7aa, type: 3} + m_Name: BundledAssetGroupSchema + m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.GroupSchemas.BundledAssetGroupSchema + m_Group: {fileID: 0} + m_InternalBundleIdMode: 1 + m_Compression: 1 + m_IncludeAddressInCatalog: 1 + m_IncludeGUIDInCatalog: 1 + m_IncludeLabelsInCatalog: 1 + m_InternalIdNamingMode: 0 + m_CacheClearBehavior: 0 + m_IncludeInBuild: 1 + m_BundledAssetProviderType: + m_AssemblyName: + m_ClassName: + m_StripDownloadOptions: 0 + m_ForceUniqueProvider: 0 + m_UseAssetBundleCache: 1 + m_UseAssetBundleCrc: 1 + m_UseAssetBundleCrcForCachedBundles: 1 + m_UseUWRForLocalBundles: 0 + m_Timeout: 0 + m_ChunkedTransfer: 0 + m_RedirectLimit: -1 + m_RetryCount: 0 + m_BuildPath: + m_Id: + m_LoadPath: + m_Id: + m_BundleMode: 0 + m_AssetBundleProviderType: + m_AssemblyName: + m_ClassName: + m_UseDefaultSchemaSettings: 0 + m_SelectedPathPairIndex: 0 + m_BundleNaming: 0 + m_AssetLoadMode: 0 diff --git a/Assets/AddressableAssetsData/AssetGroupTemplates/Packed Assets.asset.meta b/Assets/AddressableAssetsData/AssetGroupTemplates/Packed Assets.asset.meta new file mode 100644 index 00000000..1881776d --- /dev/null +++ b/Assets/AddressableAssetsData/AssetGroupTemplates/Packed Assets.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8c4ebef95ae1ef057bea1e3916daec48 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AddressableAssetsData/AssetGroups.meta b/Assets/AddressableAssetsData/AssetGroups.meta new file mode 100644 index 00000000..6450178c --- /dev/null +++ b/Assets/AddressableAssetsData/AssetGroups.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3dc806bebae8fc990aed755daf9f2e11 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset b/Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset new file mode 100644 index 00000000..d6da9c97 --- /dev/null +++ b/Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset @@ -0,0 +1,65 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bbb281ee3bf0b054c82ac2347e9e782c, type: 3} + m_Name: Default Local Group + m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.AddressableAssetGroup + m_GroupName: Default Local Group + m_GUID: c6b29e598b23fb86ab8489c479625427 + m_SerializeEntries: + - m_GUID: 0ad4fd11028eb24559196762a241834a + m_Address: Assets/Infrastructure/Audio/NoBlendSource.asset + m_ReadOnly: 0 + m_SerializedLabels: + - AudioSourceSettings + FlaggedDuringContentUpdateRestriction: 0 + - m_GUID: 0e4f435f78018b832b63442391e12c8b + m_Address: Assets/DCleaner/Camera/GameCamera.asset + m_ReadOnly: 0 + m_SerializedLabels: [] + FlaggedDuringContentUpdateRestriction: 0 + - m_GUID: 1d088f052c2092d1f9cb64b3a16f5779 + m_Address: Assets/Infrastructure/UI/CanvasSettings.asset + m_ReadOnly: 0 + m_SerializedLabels: [] + FlaggedDuringContentUpdateRestriction: 0 + - m_GUID: 23d63858ba5674a208b4577b77319113 + m_Address: Assets/DCleaner/Audio/Audio Source.prefab + m_ReadOnly: 0 + m_SerializedLabels: [] + FlaggedDuringContentUpdateRestriction: 0 + - m_GUID: 2e21bba962bb10f53a41bb8aee11cbb2 + m_Address: Assets/Infrastructure/Audio/AudioSourcePrefab.asset + m_ReadOnly: 0 + m_SerializedLabels: [] + FlaggedDuringContentUpdateRestriction: 0 + - m_GUID: 4063962b1b4e97ccd90729bd538a1fb4 + m_Address: Assets/Infrastructure/Audio/Full3DSource.asset + m_ReadOnly: 0 + m_SerializedLabels: + - AudioSourceSettings + FlaggedDuringContentUpdateRestriction: 0 + - m_GUID: 7e53d1050bed148929357759009cc715 + m_Address: Assets/Infrastructure/Audio/AudioMixerSettings.asset + m_ReadOnly: 0 + m_SerializedLabels: [] + FlaggedDuringContentUpdateRestriction: 0 + - m_GUID: e92086276d9b32213abd64903ad4b730 + m_Address: Assets/Infrastructure/Input/InputService.asset + m_ReadOnly: 0 + m_SerializedLabels: [] + FlaggedDuringContentUpdateRestriction: 0 + m_ReadOnly: 0 + m_Settings: {fileID: 11400000, guid: fca3ff8b9d20369af80cdf3da2a95a6f, type: 2} + m_SchemaSet: + m_Schemas: + - {fileID: 11400000, guid: 4c0a03f9a585ef062b42f9bf0e69ab08, type: 2} + - {fileID: 11400000, guid: a4b2eb4eda3160b34a3cfbea0f1a3049, type: 2} diff --git a/Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset.meta b/Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset.meta new file mode 100644 index 00000000..834a4ac6 --- /dev/null +++ b/Assets/AddressableAssetsData/AssetGroups/Default Local Group.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 26d0fba16e9d375ab8f8eee15dc5c99a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AddressableAssetsData/AssetGroups/Schemas.meta b/Assets/AddressableAssetsData/AssetGroups/Schemas.meta new file mode 100644 index 00000000..462a6d04 --- /dev/null +++ b/Assets/AddressableAssetsData/AssetGroups/Schemas.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0d19f468b4db9986098a38c3b4cfd69e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AddressableAssetsData/AssetGroups/Schemas/Default Local Group_BundledAssetGroupSchema.asset b/Assets/AddressableAssetsData/AssetGroups/Schemas/Default Local Group_BundledAssetGroupSchema.asset new file mode 100644 index 00000000..6c0f94c1 --- /dev/null +++ b/Assets/AddressableAssetsData/AssetGroups/Schemas/Default Local Group_BundledAssetGroupSchema.asset @@ -0,0 +1,48 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e5d17a21594effb4e9591490b009e7aa, type: 3} + m_Name: Default Local Group_BundledAssetGroupSchema + m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.GroupSchemas.BundledAssetGroupSchema + m_Group: {fileID: 11400000, guid: 26d0fba16e9d375ab8f8eee15dc5c99a, type: 2} + m_InternalBundleIdMode: 1 + m_Compression: 1 + m_IncludeAddressInCatalog: 1 + m_IncludeGUIDInCatalog: 1 + m_IncludeLabelsInCatalog: 1 + m_InternalIdNamingMode: 0 + m_CacheClearBehavior: 0 + m_IncludeInBuild: 1 + m_BundledAssetProviderType: + m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.BundledAssetProvider + m_StripDownloadOptions: 0 + m_ForceUniqueProvider: 0 + m_UseAssetBundleCache: 1 + m_UseAssetBundleCrc: 1 + m_UseAssetBundleCrcForCachedBundles: 1 + m_UseUWRForLocalBundles: 0 + m_Timeout: 0 + m_ChunkedTransfer: 0 + m_RedirectLimit: -1 + m_RetryCount: 0 + m_BuildPath: + m_Id: 29df4a9753b8b149d85f010cf7480237 + m_LoadPath: + m_Id: 4efa63d245bcc3563a4e5c228ff91b55 + m_BundleMode: 0 + m_AssetBundleProviderType: + m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.AssetBundleProvider + m_UseDefaultSchemaSettings: 0 + m_SelectedPathPairIndex: 0 + m_BundleNaming: 0 + m_AssetLoadMode: 0 diff --git a/Assets/AddressableAssetsData/AssetGroups/Schemas/Default Local Group_BundledAssetGroupSchema.asset.meta b/Assets/AddressableAssetsData/AssetGroups/Schemas/Default Local Group_BundledAssetGroupSchema.asset.meta new file mode 100644 index 00000000..d027433e --- /dev/null +++ b/Assets/AddressableAssetsData/AssetGroups/Schemas/Default Local Group_BundledAssetGroupSchema.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4c0a03f9a585ef062b42f9bf0e69ab08 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AddressableAssetsData/AssetGroups/Schemas/Default Local Group_ContentUpdateGroupSchema.asset b/Assets/AddressableAssetsData/AssetGroups/Schemas/Default Local Group_ContentUpdateGroupSchema.asset new file mode 100644 index 00000000..47e17e4e --- /dev/null +++ b/Assets/AddressableAssetsData/AssetGroups/Schemas/Default Local Group_ContentUpdateGroupSchema.asset @@ -0,0 +1,16 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5834b5087d578d24c926ce20cd31e6d6, type: 3} + m_Name: Default Local Group_ContentUpdateGroupSchema + m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.GroupSchemas.ContentUpdateGroupSchema + m_Group: {fileID: 11400000, guid: 26d0fba16e9d375ab8f8eee15dc5c99a, type: 2} + m_StaticContent: 0 diff --git a/Assets/AddressableAssetsData/AssetGroups/Schemas/Default Local Group_ContentUpdateGroupSchema.asset.meta b/Assets/AddressableAssetsData/AssetGroups/Schemas/Default Local Group_ContentUpdateGroupSchema.asset.meta new file mode 100644 index 00000000..c07d20f8 --- /dev/null +++ b/Assets/AddressableAssetsData/AssetGroups/Schemas/Default Local Group_ContentUpdateGroupSchema.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a4b2eb4eda3160b34a3cfbea0f1a3049 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AddressableAssetsData/DataBuilders.meta b/Assets/AddressableAssetsData/DataBuilders.meta new file mode 100644 index 00000000..be94f942 --- /dev/null +++ b/Assets/AddressableAssetsData/DataBuilders.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 91b16a7e9299972d698d5de40363afd1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AddressableAssetsData/DataBuilders/BuildScriptFastMode.asset b/Assets/AddressableAssetsData/DataBuilders/BuildScriptFastMode.asset new file mode 100644 index 00000000..12ab1d22 --- /dev/null +++ b/Assets/AddressableAssetsData/DataBuilders/BuildScriptFastMode.asset @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 88d21199f5d473f4db36845f2318f180, type: 3} + m_Name: BuildScriptFastMode + m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Build.DataBuilders.BuildScriptFastMode + instanceProviderType: + m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.InstanceProvider + sceneProviderType: + m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.SceneProvider diff --git a/Assets/AddressableAssetsData/DataBuilders/BuildScriptFastMode.asset.meta b/Assets/AddressableAssetsData/DataBuilders/BuildScriptFastMode.asset.meta new file mode 100644 index 00000000..0655ebd0 --- /dev/null +++ b/Assets/AddressableAssetsData/DataBuilders/BuildScriptFastMode.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 954ad4ecd0dc213b192cfe18e6022fcf +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AddressableAssetsData/DataBuilders/BuildScriptPackedMode.asset b/Assets/AddressableAssetsData/DataBuilders/BuildScriptPackedMode.asset new file mode 100644 index 00000000..d8c59fdd --- /dev/null +++ b/Assets/AddressableAssetsData/DataBuilders/BuildScriptPackedMode.asset @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3e2e0ffa088c91d41a086d0b8cb16bdc, type: 3} + m_Name: BuildScriptPackedMode + m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Build.DataBuilders.BuildScriptPackedMode + instanceProviderType: + m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.InstanceProvider + sceneProviderType: + m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.SceneProvider diff --git a/Assets/AddressableAssetsData/DataBuilders/BuildScriptPackedMode.asset.meta b/Assets/AddressableAssetsData/DataBuilders/BuildScriptPackedMode.asset.meta new file mode 100644 index 00000000..60c587c3 --- /dev/null +++ b/Assets/AddressableAssetsData/DataBuilders/BuildScriptPackedMode.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 36ff3fee814db2e40b7585fa27714179 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AddressableAssetsData/DataBuilders/BuildScriptPackedPlayMode.asset b/Assets/AddressableAssetsData/DataBuilders/BuildScriptPackedPlayMode.asset new file mode 100644 index 00000000..d566c2c9 --- /dev/null +++ b/Assets/AddressableAssetsData/DataBuilders/BuildScriptPackedPlayMode.asset @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ad8c280d42ee0ed41a27db23b43dd2bf, type: 3} + m_Name: BuildScriptPackedPlayMode + m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Build.DataBuilders.BuildScriptPackedPlayMode + instanceProviderType: + m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.InstanceProvider + sceneProviderType: + m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null + m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.SceneProvider diff --git a/Assets/AddressableAssetsData/DataBuilders/BuildScriptPackedPlayMode.asset.meta b/Assets/AddressableAssetsData/DataBuilders/BuildScriptPackedPlayMode.asset.meta new file mode 100644 index 00000000..ef5d372e --- /dev/null +++ b/Assets/AddressableAssetsData/DataBuilders/BuildScriptPackedPlayMode.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e30c90a90283fe46d88ee48888ca5acf +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/AddressableAssetsData/DefaultObject.asset b/Assets/AddressableAssetsData/DefaultObject.asset new file mode 100644 index 00000000..f023f3e2 --- /dev/null +++ b/Assets/AddressableAssetsData/DefaultObject.asset @@ -0,0 +1,15 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3a189bb168d8d90478a09ea08c2f3d72, type: 3} + m_Name: DefaultObject + m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.AddressableAssetSettingsDefaultObject + m_AddressableAssetSettingsGuid: fca3ff8b9d20369af80cdf3da2a95a6f diff --git a/Assets/AddressableAssetsData/DefaultObject.asset.meta b/Assets/AddressableAssetsData/DefaultObject.asset.meta new file mode 100644 index 00000000..901ff258 --- /dev/null +++ b/Assets/AddressableAssetsData/DefaultObject.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 56f261798a15fdfc4a61112565af447b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Code.meta b/Assets/Code.meta new file mode 100644 index 00000000..da192b0a --- /dev/null +++ b/Assets/Code.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cccfb83c072506af5ace8e119f44435b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Code/D.meta b/Assets/Code/D.meta new file mode 100644 index 00000000..a39afcbb --- /dev/null +++ b/Assets/Code/D.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f948a9778c6c4fd78629a4618a7e5302 +timeCreated: 1785829267 \ No newline at end of file diff --git a/Assets/Code/D/CleanTools.meta b/Assets/Code/D/CleanTools.meta new file mode 100644 index 00000000..42d2b254 --- /dev/null +++ b/Assets/Code/D/CleanTools.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 601de2d2ea58417f8b5a46faf0b11196 +timeCreated: 1785923690 \ No newline at end of file diff --git a/Assets/Code/D/CleanTools/CleanTool.cs b/Assets/Code/D/CleanTools/CleanTool.cs new file mode 100644 index 00000000..2e1b4efb --- /dev/null +++ b/Assets/Code/D/CleanTools/CleanTool.cs @@ -0,0 +1,31 @@ +using R3; +using UnityEngine; + +namespace Code.D.Cleaning.CleanTools +{ + public abstract class CleanTool + { + protected float DurabilityUsageStep; + protected Texture2D BrushTexture; + protected float CleanRadius; + + public abstract CleanToolType ToolType { get; } + + protected CleanTool(float durabilityUsageStep, float cleanRadius, Texture2D brushTexture) + { + IsDirty.Value = false; + + DurabilityUsageStep = durabilityUsageStep; + CleanRadius = cleanRadius; + BrushTexture = brushTexture; + } + + public ReactiveProperty IsDirty { get; } = new(); + public ReactiveProperty CurrentDirtiness { get; } + = new(0f); + + public abstract TryapkaUsageInfo Use(); + + public abstract void Clean(); + } +} \ No newline at end of file diff --git a/Assets/Code/D/CleanTools/CleanTool.cs.meta b/Assets/Code/D/CleanTools/CleanTool.cs.meta new file mode 100644 index 00000000..8d70df68 --- /dev/null +++ b/Assets/Code/D/CleanTools/CleanTool.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cc959003316e4db99a7f190b1b431298 +timeCreated: 1785939044 \ No newline at end of file diff --git a/Assets/Code/D/CleanTools/CleanToolConfig.cs b/Assets/Code/D/CleanTools/CleanToolConfig.cs new file mode 100644 index 00000000..32bc4d15 --- /dev/null +++ b/Assets/Code/D/CleanTools/CleanToolConfig.cs @@ -0,0 +1,15 @@ +using Code.Infrastructure.Generators; +using UnityEngine; + +namespace Code.D.Cleaning.CleanTools +{ + [Config("Cleaning/CleanToolConfig", multiple: true)] + [CreateAssetMenu(fileName = "CleanToolConfig", menuName = "Config/CleanToolConfig")] + public class CleanToolConfig : ScriptableObject + { + public float DurabilityUsageStep; + public Texture2D BrushTexture; + public float CleanRadius; + public CleanToolType ToolType; + } +} \ No newline at end of file diff --git a/Assets/Code/D/CleanTools/CleanToolConfig.cs.meta b/Assets/Code/D/CleanTools/CleanToolConfig.cs.meta new file mode 100644 index 00000000..0599fea7 --- /dev/null +++ b/Assets/Code/D/CleanTools/CleanToolConfig.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 98cb6ddb562747d8b4549287a391a98e +timeCreated: 1786032650 \ No newline at end of file diff --git a/Assets/Code/D/CleanTools/CleanToolInteractable.cs b/Assets/Code/D/CleanTools/CleanToolInteractable.cs new file mode 100644 index 00000000..1f85560b --- /dev/null +++ b/Assets/Code/D/CleanTools/CleanToolInteractable.cs @@ -0,0 +1,9 @@ +using UnityEngine; + +namespace Code.D.Cleaning.CleanTools +{ + public abstract class CleanToolInteractable : MonoBehaviour + { + public abstract void Use(CleanTool tool); + } +} \ No newline at end of file diff --git a/Assets/Code/D/CleanTools/CleanToolInteractable.cs.meta b/Assets/Code/D/CleanTools/CleanToolInteractable.cs.meta new file mode 100644 index 00000000..94caf360 --- /dev/null +++ b/Assets/Code/D/CleanTools/CleanToolInteractable.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1d17365593864a6e9c5cab8971c33c75 +timeCreated: 1785938942 \ No newline at end of file diff --git a/Assets/Code/D/CleanTools/CleanToolType.cs b/Assets/Code/D/CleanTools/CleanToolType.cs new file mode 100644 index 00000000..f42b66db --- /dev/null +++ b/Assets/Code/D/CleanTools/CleanToolType.cs @@ -0,0 +1,7 @@ +namespace Code.D.Cleaning.CleanTools +{ + public enum CleanToolType + { + Tryapka + } +} \ No newline at end of file diff --git a/Assets/Code/D/CleanTools/CleanToolType.cs.meta b/Assets/Code/D/CleanTools/CleanToolType.cs.meta new file mode 100644 index 00000000..996425f3 --- /dev/null +++ b/Assets/Code/D/CleanTools/CleanToolType.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 56a8b3bb2a354e59a3a9a3d6e83c8fe0 +timeCreated: 1786028280 \ No newline at end of file diff --git a/Assets/Code/D/CleanTools/DirtyToolCleaner.cs b/Assets/Code/D/CleanTools/DirtyToolCleaner.cs new file mode 100644 index 00000000..a644e656 --- /dev/null +++ b/Assets/Code/D/CleanTools/DirtyToolCleaner.cs @@ -0,0 +1,14 @@ +using System; +using UnityEngine; + +namespace Code.D.Cleaning.CleanTools +{ + public class DirtyToolCleaner : CleanToolInteractable + { + public override void Use(CleanTool tool) + { + tool.Clean(); + Debug.Log("Tool cleaned"); + } + } +} \ No newline at end of file diff --git a/Assets/Code/D/CleanTools/DirtyToolCleaner.cs.meta b/Assets/Code/D/CleanTools/DirtyToolCleaner.cs.meta new file mode 100644 index 00000000..4b3a2678 --- /dev/null +++ b/Assets/Code/D/CleanTools/DirtyToolCleaner.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 90e6386fcc8249afad82234df1fcf3d4 +timeCreated: 1785923693 \ No newline at end of file diff --git a/Assets/Code/D/CleanTools/ToolUsageInfo.cs b/Assets/Code/D/CleanTools/ToolUsageInfo.cs new file mode 100644 index 00000000..aee32cfb --- /dev/null +++ b/Assets/Code/D/CleanTools/ToolUsageInfo.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +namespace Code.D.Cleaning.CleanTools +{ + public record ToolUsageInfo + { + public float Dirtiness; + public bool IsDirty; + public Texture BrushTexture; + } +} \ No newline at end of file diff --git a/Assets/Code/D/CleanTools/ToolUsageInfo.cs.meta b/Assets/Code/D/CleanTools/ToolUsageInfo.cs.meta new file mode 100644 index 00000000..643233ab --- /dev/null +++ b/Assets/Code/D/CleanTools/ToolUsageInfo.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0723fb7c41244d8c8b9272d09977dc8f +timeCreated: 1785939283 \ No newline at end of file diff --git a/Assets/Code/D/CleanTools/Tryapka.cs b/Assets/Code/D/CleanTools/Tryapka.cs new file mode 100644 index 00000000..0a4295e5 --- /dev/null +++ b/Assets/Code/D/CleanTools/Tryapka.cs @@ -0,0 +1,44 @@ +using UnityEngine; + +namespace Code.D.Cleaning.CleanTools +{ + public class Tryapka : CleanTool + { + public Tryapka(float durabilityUsageStep, float cleanRadius, Texture2D brushTexture) : base(durabilityUsageStep, cleanRadius, brushTexture) + { + } + + public override CleanToolType ToolType => CleanToolType.Tryapka; + + public override TryapkaUsageInfo Use() + { + if (!IsDirty.CurrentValue) + { + CurrentDirtiness.Value += DurabilityUsageStep; + + if (CurrentDirtiness.Value >= 1) IsDirty.Value = true; + } + + return new(CleanRadius, CurrentDirtiness.Value, IsDirty.CurrentValue, BrushTexture); + } + + public override void Clean() + { + CurrentDirtiness.Value = 0; + IsDirty.Value = false; + } + } + + public record TryapkaUsageInfo : ToolUsageInfo + { + public float Radius; + + public TryapkaUsageInfo(float radius, float dirtiness, bool isDirty, Texture brush) + { + Radius = radius; + Dirtiness = dirtiness; + IsDirty = isDirty; + BrushTexture = brush; + } + } +} \ No newline at end of file diff --git a/Assets/Code/D/CleanTools/Tryapka.cs.meta b/Assets/Code/D/CleanTools/Tryapka.cs.meta new file mode 100644 index 00000000..262dc1bd --- /dev/null +++ b/Assets/Code/D/CleanTools/Tryapka.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5da5c20e36c0403691a65f6e0317c129 +timeCreated: 1785923693 \ No newline at end of file diff --git a/Assets/Code/D/Cleaning.meta b/Assets/Code/D/Cleaning.meta new file mode 100644 index 00000000..998c736d --- /dev/null +++ b/Assets/Code/D/Cleaning.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6b6718c9ff8a4963941f9f966f49f795 +timeCreated: 1785923035 \ No newline at end of file diff --git a/Assets/Code/D/Cleaning/Cleanable.cs b/Assets/Code/D/Cleaning/Cleanable.cs new file mode 100644 index 00000000..bdfddc61 --- /dev/null +++ b/Assets/Code/D/Cleaning/Cleanable.cs @@ -0,0 +1,11 @@ +using R3; +using UnityEngine; + +namespace Code.D.Cleaning +{ + public class Cleanable : MonoBehaviour + { + public ReactiveProperty Cleaned { get; } = new(); + public ReactiveProperty CleanProgress { get; } = new(); + } +} \ No newline at end of file diff --git a/Assets/Code/D/Cleaning/Cleanable.cs.meta b/Assets/Code/D/Cleaning/Cleanable.cs.meta new file mode 100644 index 00000000..aaa04c3d --- /dev/null +++ b/Assets/Code/D/Cleaning/Cleanable.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 219620ccf64f42d7a64d27a3a152f961 +timeCreated: 1785923122 \ No newline at end of file diff --git a/Assets/Code/D/Cleaning/CleanableAsset.cs b/Assets/Code/D/Cleaning/CleanableAsset.cs new file mode 100644 index 00000000..21dd1b2d --- /dev/null +++ b/Assets/Code/D/Cleaning/CleanableAsset.cs @@ -0,0 +1,35 @@ +using UnityEngine; + +namespace Code.D.Cleaning +{ + public class CleanableAsset : Cleanable + { + private Collider _dirtyCollider; + private static readonly int MaskMap = Shader.PropertyToID("_Mask"); + [SerializeField] private float cleanCountPerFrame; + private Material _renderMaterial; + + private void Awake() + { + _dirtyCollider = GetComponent(); + + _renderMaterial = GetComponent().material; + } + private void AssumedAsCleaned() + { + Cleaned.Value = true; + _dirtyCollider.enabled = false; + _renderMaterial.SetTexture(MaskMap, Texture2D.blackTexture); + } + + public void Clean() + { + CleanProgress.Value += cleanCountPerFrame; + + if(CleanProgress.CurrentValue >= 100) + AssumedAsCleaned(); + + Debug.Log($"{name} прогресс очистки: {CleanProgress.CurrentValue}"); + } + } +} \ No newline at end of file diff --git a/Assets/Code/D/Cleaning/CleanableAsset.cs.meta b/Assets/Code/D/Cleaning/CleanableAsset.cs.meta new file mode 100644 index 00000000..41b53e91 --- /dev/null +++ b/Assets/Code/D/Cleaning/CleanableAsset.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b184056d80d64c5d9f9cdb03cb00efc7 +timeCreated: 1785923122 \ No newline at end of file diff --git a/Assets/Code/D/Cleaning/CleanableSurface.cs b/Assets/Code/D/Cleaning/CleanableSurface.cs new file mode 100644 index 00000000..0fb4a035 --- /dev/null +++ b/Assets/Code/D/Cleaning/CleanableSurface.cs @@ -0,0 +1,490 @@ +using System.Collections.Generic; +using Code.D.Cleaning.CleanTools; +using Cysharp.Threading.Tasks; +using TinyGoose.Tremble; +using Unity.Collections; +using UnityEngine; +using UnityEngine.Rendering; +#if UNITY_EDITOR +using UnityEditor; +#endif + +namespace Code.D.Cleaning +{ + [BrushEntity("CleanableSurface", layer: "Cleanable")] + public class CleanableSurface : Cleanable, IOnImportFromMapEntity + { + private static readonly int MaskMap = Shader.PropertyToID("_Mask"); + private static readonly int DrawPosition = Shader.PropertyToID("_DrawPosition"); + private static readonly int DrawRadius = Shader.PropertyToID("_DrawRadius"); + private static readonly int ToolDirtiness = Shader.PropertyToID("_ToolDirtiness"); + private static readonly int BrushTex = Shader.PropertyToID("_BrushTex"); + private static readonly int DrawAngleX = Shader.PropertyToID("_DrawAngleX"); + private static readonly int DrawAngleY = Shader.PropertyToID("_DrawAngleY"); + + private const int CalcResolution = 64; + + [SerializeField] private float cleanedThreshold = 0.7f; + + private RenderTexture _maskRT; + private RenderTexture _calcRT; + private Material _brushMaterial; + private Material _renderMaterial; + + private bool _onProcess; + private UniTask _calculationOperation; + + private void Awake() + { + gameObject.tag = "CleanableSurface"; + + _maskRT = new RenderTexture(1024, 1024, 0, RenderTextureFormat.ARGB32); + _maskRT.Create(); + Graphics.Blit(Texture2D.whiteTexture, _maskRT); + + _calcRT = new RenderTexture(CalcResolution, CalcResolution, 0, RenderTextureFormat.ARGB32); + _calcRT.Create(); + + _brushMaterial = new Material(Shader.Find("Unlit/BrushPainter")); + + if (!TryGetComponent(out var renderer)) return; + _renderMaterial = renderer.material; + _renderMaterial.SetTexture(MaskMap, _maskRT); + } + + /// + /// Нейросеть написала и этот метод, слишком много математики мне он не нравится. Он заставляет игру лагать. Нужно сделать проще. + /// Хотябы комментарии оставлены человеком. + /// Я профнепригоден. + /// + /// + /// + /// + public void Clean(RaycastHit hit, TryapkaUsageInfo tryapkaUsageInfo, Transform playerCamera) + { + if (Cleaned.CurrentValue) return; + + Vector2 uv = hit.textureCoord; + + // Логика вычисления направления кисти + Vector3 dirToCamera = playerCamera.position - hit.point; + Vector3 projDir = Vector3.ProjectOnPlane(dirToCamera, hit.normal); + + if (projDir.sqrMagnitude < 0.0001f) + { + projDir = Vector3.ProjectOnPlane(playerCamera.up, hit.normal); + } + + projDir.Normalize(); + + // Логика определения U V или W + Vector3 localDir = hit.transform.InverseTransformDirection(projDir); + Vector3 localNormal = hit.transform.InverseTransformDirection(hit.normal).normalized; + + ComputeTangentBasis(localNormal, out var axisU, out var axisV); + + // Определяем синус и косинус поворота + float u = Vector3.Dot(localDir, axisU); + float v = Vector3.Dot(localDir, axisV); + + _brushMaterial.SetVector(DrawPosition, uv); + _brushMaterial.SetFloat(DrawRadius, tryapkaUsageInfo.Radius); + _brushMaterial.SetFloat(DrawAngleX, v); + _brushMaterial.SetFloat(DrawAngleY, u); + _brushMaterial.SetFloat(ToolDirtiness, tryapkaUsageInfo.Dirtiness); + _brushMaterial.SetTexture(BrushTex, tryapkaUsageInfo.BrushTexture); + + Graphics.Blit(Texture2D.blackTexture, _maskRT, _brushMaterial, 0); + + if (_calculationOperation.Status != UniTaskStatus.Pending) + { + _calculationOperation = CalculateCleanPercentage(); + } + } + + private static void ComputeTangentBasis(Vector3 normal, out Vector3 axisU, out Vector3 axisV) + { + if (Mathf.Abs(normal.y) > FlatNormalThreshold) + { + axisU = Vector3.right; + axisV = Vector3.forward; + } + else + { + axisU = Vector3.Cross(Vector3.up, normal).normalized; + axisV = Vector3.up; + } + } + + private async UniTask CalculateCleanPercentage() + { + if (!_maskRT || _onProcess) return; + + _onProcess = true; + + Graphics.Blit(_maskRT, _calcRT); + + var destroyToken = this.GetCancellationTokenOnDestroy(); + var request = AsyncGPUReadback.Request(_calcRT, 0, TextureFormat.RGBA32); + await request.ToUniTask(cancellationToken: destroyToken); + + if (request.hasError) + { + _onProcess = false; + return; + } + + NativeArray data = request.GetData(); + int totalBytes = data.Length; + long totalBrightness = 0; + + for (var i = 0; i < totalBytes; i += 4) + { + totalBrightness += data[i]; + } + + int pixelCount = totalBytes / 4; + float maxPossibleBrightness = pixelCount * 255f; + + float progress = 1.0f - (totalBrightness / maxPossibleBrightness); + + if (Mathf.Abs(progress - CleanProgress.CurrentValue) > 0.01f) + { + CleanProgress.Value = progress; + } + + if (CleanProgress.CurrentValue >= cleanedThreshold && !Cleaned.CurrentValue) + { + AssumedAsCleaned(); + } + + _onProcess = false; + } + + private void AssumedAsCleaned() + { + Cleaned.Value = true; + FinishClean(); + } + + private void FinishClean() + { + Graphics.Blit(Texture2D.blackTexture, _maskRT); + } + + private void OnDestroy() + { + if (_maskRT) _maskRT.Release(); + if (_calcRT) _calcRT.Release(); + if (_brushMaterial) Destroy(_brushMaterial); + if (_renderMaterial) Destroy(_renderMaterial); + } + + public void OnImportFromMapEntity(MapBsp mapBsp, BspEntity entity) + { + Debug.Log("Found a brush!"); + + var meshFilter = gameObject.GetComponent(); + if (meshFilter == null) + { + Debug.LogError($"[CleanableSurface] MeshFilter отсутствует на {gameObject.name}"); + return; + } + + var sourceMesh = meshFilter.sharedMesh; + if (sourceMesh == null) + { + Debug.LogError($"[CleanableSurface] sharedMesh == null на {gameObject.name}"); + return; + } + + if (!sourceMesh.isReadable) + { + Debug.LogError($"[CleanableSurface] Меш '{sourceMesh.name}' не readable, не могу построить UV"); + return; + } + + if (sourceMesh.vertexCount == 0 || sourceMesh.triangles.Length == 0) + { + Debug.LogError($"[CleanableSurface] Меш '{sourceMesh.name}' пустой"); + return; + } + + try + { + BuildLayeredUVInPlace(sourceMesh); + } + catch (System.Exception ex) + { + Debug.LogError($"[CleanableSurface] Исключение при построении UV для {gameObject.name}: {ex}"); + return; + } + + var meshCollider = gameObject.GetComponent(); + if (meshCollider != null) + meshCollider.sharedMesh = sourceMesh; + +#if UNITY_EDITOR + var existingFlags = GameObjectUtility.GetStaticEditorFlags(gameObject); + GameObjectUtility.SetStaticEditorFlags(gameObject, existingFlags | StaticEditorFlags.ContributeGI); +#endif + + Debug.Log( + $"[CleanableSurface] UV построен для {gameObject.name}: verts={sourceMesh.vertexCount}, tris={sourceMesh.triangles.Length / 3}"); + } + + private const float MaskUvPadding = 0.08f; + + private const float WeldEpsilon = 0.0005f; + + private const float CoplanarDotThreshold = 0.999f; + + private const float FlatNormalThreshold = 0.999f; + + /// + /// Этот большой и сложный метод написан нейросетью Claude Sonnet 5 Medium. Я профнепригоден + /// + /// + private static void BuildLayeredUVInPlace(Mesh mesh) + { + var srcVerts = mesh.vertices; + var srcNormals = mesh.normals; + var srcUvTile = mesh.uv; + bool hasNormals = srcNormals.Length == srcVerts.Length; + bool hasUvTile = srcUvTile.Length == srcVerts.Length; + + int subMeshCount = mesh.subMeshCount; + + var posToId = new Dictionary(); + + int CanonicalId(Vector3 p) + { + var key = new Vector3Int( + Mathf.RoundToInt(p.x / WeldEpsilon), + Mathf.RoundToInt(p.y / WeldEpsilon), + Mathf.RoundToInt(p.z / WeldEpsilon)); + if (posToId.TryGetValue(key, out var id)) return id; + id = posToId.Count; + posToId[key] = id; + return id; + } + + var triSubMesh = new List(); + var triI0 = new List(); + var triI1 = new List(); + var triI2 = new List(); + var triCanonA = new List(); + var triCanonB = new List(); + var triCanonC = new List(); + var triNormal = new List(); + + for (int s = 0; s < subMeshCount; s++) + { + var tris = mesh.GetTriangles(s); + for (int t = 0; t < tris.Length; t += 3) + { + int i0 = tris[t], i1 = tris[t + 1], i2 = tris[t + 2]; + Vector3 p0 = srcVerts[i0], p1 = srcVerts[i1], p2 = srcVerts[i2]; + Vector3 n = Vector3.Cross(p1 - p0, p2 - p0); + n = n.sqrMagnitude > 1e-10f ? n.normalized : Vector3.up; + + triSubMesh.Add(s); + triI0.Add(i0); + triI1.Add(i1); + triI2.Add(i2); + triCanonA.Add(CanonicalId(p0)); + triCanonB.Add(CanonicalId(p1)); + triCanonC.Add(CanonicalId(p2)); + triNormal.Add(n); + } + } + + int triCount = triSubMesh.Count; + + var parent = new int[triCount]; + for (int i = 0; i < triCount; i++) parent[i] = i; + + int Find(int x) + { + while (parent[x] != x) + { + parent[x] = parent[parent[x]]; + x = parent[x]; + } + + return x; + } + + void Union(int a, int b) + { + a = Find(a); + b = Find(b); + if (a != b) parent[a] = b; + } + + var edgeMap = new Dictionary(); + + long PackEdge(int a, int b) + { + if (a > b) (a, b) = (b, a); + return ((long)a << 32) | (uint)b; + } + + void ProcessEdge(long e, int t) + { + if (edgeMap.TryGetValue(e, out var other)) + { + if (Vector3.Dot(triNormal[t], triNormal[other]) > CoplanarDotThreshold) + Union(t, other); + } + else + { + edgeMap[e] = t; + } + } + + for (int t = 0; t < triCount; t++) + { + int a = triCanonA[t], b = triCanonB[t], c = triCanonC[t]; + ProcessEdge(PackEdge(a, b), t); + ProcessEdge(PackEdge(b, c), t); + ProcessEdge(PackEdge(c, a), t); + } + + var islandOf = new int[triCount]; + var islandRootToIndex = new Dictionary(); + for (int t = 0; t < triCount; t++) + { + int root = Find(t); + if (!islandRootToIndex.TryGetValue(root, out var idx)) + { + idx = islandRootToIndex.Count; + islandRootToIndex[root] = idx; + } + + islandOf[t] = idx; + } + + int islandCount = islandRootToIndex.Count; + + var accumNormal = new Vector3[islandCount]; + for (int t = 0; t < triCount; t++) + accumNormal[islandOf[t]] += triNormal[t]; + + var islandAxisU = new Vector3[islandCount]; + var islandAxisV = new Vector3[islandCount]; + for (int i = 0; i < islandCount; i++) + { + var n = accumNormal[i].normalized; + ComputeTangentBasis(n, out islandAxisU[i], out islandAxisV[i]); + } + + var islandMinU = new float[islandCount]; + var islandMinV = new float[islandCount]; + var islandMaxU = new float[islandCount]; + var islandMaxV = new float[islandCount]; + for (int i = 0; i < islandCount; i++) + { + islandMinU[i] = islandMinV[i] = float.PositiveInfinity; + islandMaxU[i] = islandMaxV[i] = float.NegativeInfinity; + } + + Vector2 ProjectUV(Vector3 local, Vector3 axisU, Vector3 axisV) => + new Vector2(Vector3.Dot(local, axisU), Vector3.Dot(local, axisV)); + + for (int t = 0; t < triCount; t++) + { + int island = islandOf[t]; + Vector2 a = ProjectUV(srcVerts[triI0[t]], islandAxisU[island], islandAxisV[island]); + Vector2 b = ProjectUV(srcVerts[triI1[t]], islandAxisU[island], islandAxisV[island]); + Vector2 c = ProjectUV(srcVerts[triI2[t]], islandAxisU[island], islandAxisV[island]); + + islandMinU[island] = Mathf.Min(islandMinU[island], a.x, b.x, c.x); + islandMinV[island] = Mathf.Min(islandMinV[island], a.y, b.y, c.y); + islandMaxU[island] = Mathf.Max(islandMaxU[island], a.x, b.x, c.x); + islandMaxV[island] = Mathf.Max(islandMaxV[island], a.y, b.y, c.y); + } + + int gridSize = Mathf.Max(1, Mathf.CeilToInt(Mathf.Sqrt(islandCount))); + float cellSize = 1f / gridSize; + float cellPad = cellSize * MaskUvPadding * 0.5f; + + var islandCellOrigin = new Vector2[islandCount]; + var islandScale = new float[islandCount]; + for (int i = 0; i < islandCount; i++) + { + int col = i % gridSize; + int row = i / gridSize; + islandCellOrigin[i] = new Vector2(col * cellSize, row * cellSize); + + float span = Mathf.Max(Mathf.Max(islandMaxU[i] - islandMinU[i], islandMaxV[i] - islandMinV[i]), 1e-5f); + float usableCell = cellSize - cellPad * 2f; + islandScale[i] = usableCell / span; + } + + var newVerts = new List(); + var newNormals = new List(); + var newUvMask = new List(); + var newUvTile = new List(); + var subTriangleLists = new List[subMeshCount]; + for (int s = 0; s < subMeshCount; s++) subTriangleLists[s] = new List(); + + for (int t = 0; t < triCount; t++) + { + int island = islandOf[t]; + + Vector2 MapAtlas(Vector3 local) + { + Vector2 uv = ProjectUV(local, islandAxisU[island], islandAxisV[island]); + Vector2 norm = new Vector2(uv.x - islandMinU[island], uv.y - islandMinV[island]) * + islandScale[island]; + return islandCellOrigin[island] + new Vector2(cellPad, cellPad) + norm; + } + + int i0 = triI0[t], i1 = triI1[t], i2 = triI2[t]; + Vector3 p0 = srcVerts[i0], p1 = srcVerts[i1], p2 = srcVerts[i2]; + + int baseIndex = newVerts.Count; + newVerts.Add(p0); + newVerts.Add(p1); + newVerts.Add(p2); + newNormals.Add(hasNormals ? srcNormals[i0] : triNormal[t]); + newNormals.Add(hasNormals ? srcNormals[i1] : triNormal[t]); + newNormals.Add(hasNormals ? srcNormals[i2] : triNormal[t]); + + newUvMask.Add(MapAtlas(p0)); + newUvMask.Add(MapAtlas(p1)); + newUvMask.Add(MapAtlas(p2)); + + newUvTile.Add(hasUvTile ? srcUvTile[i0] : Vector2.zero); + newUvTile.Add(hasUvTile ? srcUvTile[i1] : Vector2.zero); + newUvTile.Add(hasUvTile ? srcUvTile[i2] : Vector2.zero); + + int subMesh = triSubMesh[t]; + subTriangleLists[subMesh].Add(baseIndex); + subTriangleLists[subMesh].Add(baseIndex + 1); + subTriangleLists[subMesh].Add(baseIndex + 2); + } + + mesh.Clear(); + mesh.indexFormat = newVerts.Count > 65000 + ? UnityEngine.Rendering.IndexFormat.UInt32 + : UnityEngine.Rendering.IndexFormat.UInt16; + mesh.SetVertices(newVerts); + mesh.SetNormals(newNormals); + mesh.SetUVs(0, newUvMask); + mesh.SetUVs(2, newUvTile); + mesh.subMeshCount = subMeshCount; + for (int s = 0; s < subMeshCount; s++) + mesh.SetTriangles(subTriangleLists[s], s); + + mesh.RecalculateBounds(); + if (!hasNormals) mesh.RecalculateNormals(); + mesh.RecalculateTangents(); + +#if UNITY_EDITOR + Unwrapping.GenerateSecondaryUVSet(mesh); +#endif + } + } +} \ No newline at end of file diff --git a/Assets/Code/D/Cleaning/CleanableSurface.cs.meta b/Assets/Code/D/Cleaning/CleanableSurface.cs.meta new file mode 100644 index 00000000..bcf20754 --- /dev/null +++ b/Assets/Code/D/Cleaning/CleanableSurface.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a09905e536314ef1bd4c016d3b5cfb76 +timeCreated: 1785923052 \ No newline at end of file diff --git a/Assets/Code/D/Cleaning/CleaningService.cs b/Assets/Code/D/Cleaning/CleaningService.cs new file mode 100644 index 00000000..886df566 --- /dev/null +++ b/Assets/Code/D/Cleaning/CleaningService.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using R3; +using UnityEngine; + +namespace Code.D.Cleaning +{ + public interface ICleaningService + { + } + + public class CleaningService : IDisposable, ICleaningService + { + private List _cleanableSurfaces = new(); + + private IDisposable _surfaces; + + public ReactiveProperty LevelCleaned { get; } = new(); + + public CleaningService(Cleanable[] cleanableSurfaces) + { + DisposableBuilder builder = new DisposableBuilder(); + + foreach (var cleanable in cleanableSurfaces) + { + _cleanableSurfaces.Add(cleanable); + builder.Add(cleanable.Cleaned + .Subscribe(x => CheckProgress(cleanable))); + } + + _surfaces = builder.Build(); + } + + private void CheckProgress(Cleanable cleanable) + { + if(cleanable.Cleaned.CurrentValue) Debug.Log($"{cleanable.name} cleaned"); + + CheckOverallProgress(); + } + + private void CheckOverallProgress() + { + if (LevelCleaned.CurrentValue) + return; + + foreach (var t in _cleanableSurfaces) + if (!t.Cleaned.CurrentValue) return; + + Debug.Log($"VICTORY!!!"); + LevelCleaned.Value = true; + } + + public void Dispose() + { + _surfaces?.Dispose(); + } + } +} \ No newline at end of file diff --git a/Assets/Code/D/Cleaning/CleaningService.cs.meta b/Assets/Code/D/Cleaning/CleaningService.cs.meta new file mode 100644 index 00000000..5681aa77 --- /dev/null +++ b/Assets/Code/D/Cleaning/CleaningService.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b5ce468dffcf438d98691a527f9c51ba +timeCreated: 1785923122 \ No newline at end of file diff --git a/Assets/Code/D/Cleaning/Shaders.meta b/Assets/Code/D/Cleaning/Shaders.meta new file mode 100644 index 00000000..df640d22 --- /dev/null +++ b/Assets/Code/D/Cleaning/Shaders.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9a45200a1a0d48beaea636b4b794ed95 +timeCreated: 1785925560 \ No newline at end of file diff --git a/Assets/Code/D/Cleaning/Shaders/BrushPainter.shader b/Assets/Code/D/Cleaning/Shaders/BrushPainter.shader new file mode 100644 index 00000000..13262e39 --- /dev/null +++ b/Assets/Code/D/Cleaning/Shaders/BrushPainter.shader @@ -0,0 +1,85 @@ +Shader "Unlit/BrushPainter" +{ + Properties + { + _DrawPosition("Draw Position", Vector) = (0.5, 0.5, 0, 0) + _DrawRadius("Draw Radius", Float) = 0.05 + _DrawAngleX("Draw Angle (Rad) X", Float) = 0.0 + _DrawAngleY("Draw Angle (Rad) Y", Float) = 0.0 + _ToolDirtiness("Tool Dirtiness", Range(0, 1)) = 0 + [MainTexture] _BrushTex("Brush Texture", 2D) = "white" {} + } + + SubShader + { + Tags + { + "RenderType" = "Transparent" + "Queue" = "Transparent" + } + + Pass + { + Blend SrcAlpha OneMinusSrcAlpha + ZWrite Off + ZTest Always + + HLSLPROGRAM + #pragma vertex vert + #pragma fragment frag + + #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" + + struct Attributes + { + float4 positionOS : POSITION; + float2 uv : TEXCOORD0; + }; + + struct Varyings + { + float4 positionHCS : SV_POSITION; + float2 uv : TEXCOORD0; + }; + + float4 _DrawPosition; + float _DrawRadius; + float _DrawAngleX; + float _DrawAngleY; + float _ToolDirtiness; + + TEXTURE2D(_BrushTex); + SAMPLER(sampler_BrushTex); + + Varyings vert(Attributes IN) + { + Varyings OUT; + OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz); + OUT.uv = IN.uv; + return OUT; + } + + half4 frag(Varyings IN) : SV_Target + { + float2 centeredUV = (IN.uv - _DrawPosition.xy) / (_DrawRadius * 2.0); + + float2 rotatedUV; + rotatedUV.x = centeredUV.x * _DrawAngleX - centeredUV.y * _DrawAngleY; + rotatedUV.y = centeredUV.x * _DrawAngleY + centeredUV.y * _DrawAngleX; + + float2 brushUV = rotatedUV + 0.5; + + float inBounds = step(0.0, brushUV.x) * step(brushUV.x, 1.0) * + step(0.0, brushUV.y) * step(brushUV.y, 1.0); + + half4 brushColor = SAMPLE_TEXTURE2D(_BrushTex, sampler_BrushTex, brushUV); + + float brushMask = brushColor.a * inBounds; + float fillValue = _ToolDirtiness * brushMask; + + return half4(fillValue, fillValue, fillValue, brushMask); + } + ENDHLSL + } + } +} \ No newline at end of file diff --git a/Assets/Code/D/Cleaning/Shaders/BrushPainter.shader.meta b/Assets/Code/D/Cleaning/Shaders/BrushPainter.shader.meta new file mode 100644 index 00000000..2e4204fe --- /dev/null +++ b/Assets/Code/D/Cleaning/Shaders/BrushPainter.shader.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 31f42842d3a8460ea125575cb5a72a5a +timeCreated: 1785925570 \ No newline at end of file diff --git a/Assets/Code/D/Cleaning/UI.meta b/Assets/Code/D/Cleaning/UI.meta new file mode 100644 index 00000000..8e9b891f --- /dev/null +++ b/Assets/Code/D/Cleaning/UI.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b5e608514d754bcfb44c3df7c722601d +timeCreated: 1786025274 \ No newline at end of file diff --git a/Assets/Code/D/Cleaning/UI/CleanToolWidget.cs b/Assets/Code/D/Cleaning/UI/CleanToolWidget.cs new file mode 100644 index 00000000..34ebe936 --- /dev/null +++ b/Assets/Code/D/Cleaning/UI/CleanToolWidget.cs @@ -0,0 +1,9 @@ +using UnityEngine; + +namespace Code.D.Cleaning.UI +{ + public abstract class CleanToolWidget : MonoBehaviour + { + public abstract void SetToolDirtiness(float dirtiness); + } +} \ No newline at end of file diff --git a/Assets/Code/D/Cleaning/UI/CleanToolWidget.cs.meta b/Assets/Code/D/Cleaning/UI/CleanToolWidget.cs.meta new file mode 100644 index 00000000..6a811550 --- /dev/null +++ b/Assets/Code/D/Cleaning/UI/CleanToolWidget.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 95907fda6bb942a1865c6f1d9a6c1f91 +timeCreated: 1786025360 \ No newline at end of file diff --git a/Assets/Code/D/Cleaning/UI/CleaningPanel.cs b/Assets/Code/D/Cleaning/UI/CleaningPanel.cs new file mode 100644 index 00000000..2e4d1574 --- /dev/null +++ b/Assets/Code/D/Cleaning/UI/CleaningPanel.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using System.Threading; +using Code.D.Cleaning.CleanTools; +using Code.Infrastructure.UI; +using Cysharp.Threading.Tasks; +using Reflex.Attributes; +using UnityEngine; + +namespace Code.D.Cleaning.UI +{ + public class CleaningPanel : UIPanel + { + [Inject] + private void Construct(List cleanTools) + { + Debug.Log("InjectingPanel"); + + foreach (var cleanTool in cleanTools) Debug.Log(cleanTool); + } + + public override UniTask Open(CancellationToken cts = default) + { + return UniTask.CompletedTask; + } + + public override UniTask Close(CancellationToken cts = default) + { + return UniTask.CompletedTask; + } + } +} \ No newline at end of file diff --git a/Assets/Code/D/Cleaning/UI/CleaningPanel.cs.meta b/Assets/Code/D/Cleaning/UI/CleaningPanel.cs.meta new file mode 100644 index 00000000..b5b93c79 --- /dev/null +++ b/Assets/Code/D/Cleaning/UI/CleaningPanel.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4f7be6d67e6944899ab2c3ae0255b58e +timeCreated: 1786025297 \ No newline at end of file diff --git a/Assets/Code/D/Cleaning/UI/TryapkaWidget.cs b/Assets/Code/D/Cleaning/UI/TryapkaWidget.cs new file mode 100644 index 00000000..0d925014 --- /dev/null +++ b/Assets/Code/D/Cleaning/UI/TryapkaWidget.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Code.D.Cleaning.CleanTools; +using R3; +using Reflex.Attributes; +using UnityEngine; +using UnityEngine.UI; + +namespace Code.D.Cleaning.UI +{ + public class TryapkaWidget : CleanToolWidget + { + [SerializeField] private Image toolImage; + [SerializeField] private Color cleanToolColor; + [SerializeField] private Color dirtyToolColor; + + private IDisposable _disposable; + + [Inject] + private void Construct(List cleanTools) + { + Debug.Log("InjectingWidget"); + + var tool = cleanTools.SingleOrDefault(x => x.ToolType == CleanToolType.Tryapka); + + if (tool == null) return; + + _disposable = tool.CurrentDirtiness + .Subscribe(SetToolDirtiness); + } + + private void OnDestroy() + { + _disposable?.Dispose(); + } + + public override void SetToolDirtiness(float dirtiness) + { + toolImage.color = Color.Lerp(cleanToolColor, dirtyToolColor, dirtiness); + } + } +} \ No newline at end of file diff --git a/Assets/Code/D/Cleaning/UI/TryapkaWidget.cs.meta b/Assets/Code/D/Cleaning/UI/TryapkaWidget.cs.meta new file mode 100644 index 00000000..49936282 --- /dev/null +++ b/Assets/Code/D/Cleaning/UI/TryapkaWidget.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6cbf9cd4573e4544a67318da5d5fa072 +timeCreated: 1786025415 \ No newline at end of file diff --git a/Assets/Code/D/Player.meta b/Assets/Code/D/Player.meta new file mode 100644 index 00000000..1490a0a4 --- /dev/null +++ b/Assets/Code/D/Player.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9891a4d4490a4d35ab073ab28b4d0c25 +timeCreated: 1785846398 \ No newline at end of file diff --git a/Assets/Code/D/Player/CleanerCameraState.cs b/Assets/Code/D/Player/CleanerCameraState.cs new file mode 100644 index 00000000..4e69827e --- /dev/null +++ b/Assets/Code/D/Player/CleanerCameraState.cs @@ -0,0 +1,93 @@ +using System; +using Code.Infrastructure.Camera; +using Code.Infrastructure.Camera.CameraStates; +using Code.Infrastructure.Generators; +using Code.Infrastructure.Input; +using Cysharp.Threading.Tasks; +using R3; +using UnityEngine; +using UnityEngine.InputSystem; + +namespace Code.Game.Gameplay.Player +{ + [State(typeof(CameraMode),typeof(CameraStateMachineContext), ManualInherit = true)] + public partial class CleanerCameraState : BaseCameraState + { + public void SetTarget(Transform target) + { + _target = target; + Context.cameraLoadedData.Camera.transform.position = _target.position; + Context.cameraLoadedData.Camera.transform.rotation = _target.rotation; + } + + private IDisposable _disposable; + public void SetPlayer(PlayerMovementController playerMovementController) + { + _disposable = playerMovementController.IsSliding.Subscribe(SlideToggle); + } + + private void SlideToggle(bool isSliding) => _isSliding = isSliding; + + private Transform _target; + private Vector2 _mouseDelta; + private Vector2 _rotation = Vector2.zero; + + private float _sensitivityX = 0.1f; + private float _sensitivityY = 0.1f; + private float _slideStupidity = 1f; + private bool _isSliding; + + public CleanerCameraState(CameraStateMachineContext context) : base(context) + { + } + + private void LookCancelled(InputAction.CallbackContext obj) => _mouseDelta = Vector2.zero; + private void LookPerformed(InputAction.CallbackContext obj) => _mouseDelta = obj.ReadValue(); + + public override CameraMode MyState => CameraMode.Cleaner; + + public override UniTask EnterState() + { + Context.InputService.BindActionPerformed((int)ActionMappings.Cleaning, (int)CleaningActions.Watchment, LookPerformed); + Context.InputService.BindActionCancelled((int)ActionMappings.Cleaning, (int)CleaningActions.Watchment, LookCancelled); + return UniTask.CompletedTask; + } + + public override UniTask ExitState() + { + Context.InputService.UnbindActionPerformed((int)ActionMappings.Cleaning, (int)CleaningActions.Watchment, LookPerformed); + Context.InputService.UnbindActionCancelled((int)ActionMappings.Cleaning, (int)CleaningActions.Watchment, LookCancelled); + _disposable.Dispose(); + return UniTask.CompletedTask; + } + + public override void Update() + { + } + + public override void LateUpdate() + { + if (_target is null) return; + + var camTransform = Context.cameraLoadedData.Camera.transform; + + camTransform.position = _target.position; + + var mouseDeltaX = _mouseDelta.x * _sensitivityX; + var mouseDeltaY = _mouseDelta.y * _sensitivityY; + + if (_isSliding) + { + mouseDeltaX = Mathf.Clamp(mouseDeltaX, -_slideStupidity, _slideStupidity); + mouseDeltaY = Mathf.Clamp(mouseDeltaY, -_slideStupidity, _slideStupidity); + } + + _rotation.x += mouseDeltaX; + _rotation.y -= mouseDeltaY; + + _rotation.y = Mathf.Clamp(_rotation.y, -90f, 90f); + + camTransform.localRotation = Quaternion.Euler(_rotation.y, _rotation.x, 0f); + } + } +} \ No newline at end of file diff --git a/Assets/Code/D/Player/CleanerCameraState.cs.meta b/Assets/Code/D/Player/CleanerCameraState.cs.meta new file mode 100644 index 00000000..f81aba3e --- /dev/null +++ b/Assets/Code/D/Player/CleanerCameraState.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9e592628c3fe45bf9659d1050680c296 +timeCreated: 1785846388 \ No newline at end of file diff --git a/Assets/Code/D/Player/Factory.meta b/Assets/Code/D/Player/Factory.meta new file mode 100644 index 00000000..7755a5ad --- /dev/null +++ b/Assets/Code/D/Player/Factory.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c9b8ea0290514b809c83dd30d68391ca +timeCreated: 1785846388 \ No newline at end of file diff --git a/Assets/Code/D/Player/Factory/PlayerFactory.cs b/Assets/Code/D/Player/Factory/PlayerFactory.cs new file mode 100644 index 00000000..5118ee1b --- /dev/null +++ b/Assets/Code/D/Player/Factory/PlayerFactory.cs @@ -0,0 +1,45 @@ +using System; +using Code.Infrastructure.Utils; +using Cysharp.Threading.Tasks; +using Reflex.Attributes; +using Reflex.Core; +using Reflex.Injectors; +using UnityEngine; +using UnityEngine.AddressableAssets; + +namespace Code.Game.Gameplay.Player.Factory +{ + public interface IPlayerFactory + { + UniTask CreatePlayer(); + void InjectPlayer(Container container); + } + + public class PlayerFactory : IDisposable, IPlayerFactory + { + private readonly SingleConfig _config; + + private GameObject _playerInstance; + + public PlayerFactory(SingleConfig config) + { + _config = config; + } + public async UniTask CreatePlayer() + { + _playerInstance ??= await Addressables.InstantiateAsync(_config.Config.Player).ToUniTask(); + + return _playerInstance; + } + + public void InjectPlayer(Container container) + { + GameObjectInjector.InjectRecursive(_playerInstance, container); + } + + public void Dispose() + { + Addressables.ReleaseInstance(_playerInstance); + } + } +} \ No newline at end of file diff --git a/Assets/Code/D/Player/Factory/PlayerFactory.cs.meta b/Assets/Code/D/Player/Factory/PlayerFactory.cs.meta new file mode 100644 index 00000000..4beb3dc2 --- /dev/null +++ b/Assets/Code/D/Player/Factory/PlayerFactory.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fdc8848de9734ba3bb1c3e3ec81145e6 +timeCreated: 1778956904 \ No newline at end of file diff --git a/Assets/Code/D/Player/Factory/PlayerFactorySettings.cs b/Assets/Code/D/Player/Factory/PlayerFactorySettings.cs new file mode 100644 index 00000000..8fce9eb0 --- /dev/null +++ b/Assets/Code/D/Player/Factory/PlayerFactorySettings.cs @@ -0,0 +1,13 @@ +using Code.Infrastructure.Generators; +using UnityEngine; +using UnityEngine.AddressableAssets; + +namespace Code.Game.Gameplay.Player.Factory +{ + [Config("Configs/Gameplay/PlayerFactory")] + [CreateAssetMenu(fileName = "PlayerFactorySettings", menuName = "Configs/Gameplay/PlayerFactory")] + public class PlayerFactorySettings : ScriptableObject + { + public AssetReference Player; + } +} \ No newline at end of file diff --git a/Assets/Code/D/Player/Factory/PlayerFactorySettings.cs.meta b/Assets/Code/D/Player/Factory/PlayerFactorySettings.cs.meta new file mode 100644 index 00000000..5d2a395d --- /dev/null +++ b/Assets/Code/D/Player/Factory/PlayerFactorySettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c312323c8dc049b2b7e7330f54b09aad +timeCreated: 1785871572 \ No newline at end of file diff --git a/Assets/Code/D/Player/PlayerCameraTarget.cs b/Assets/Code/D/Player/PlayerCameraTarget.cs new file mode 100644 index 00000000..66834fbf --- /dev/null +++ b/Assets/Code/D/Player/PlayerCameraTarget.cs @@ -0,0 +1,13 @@ +using Code.Infrastructure.Camera; +using Reflex.Attributes; +using UnityEngine; + +namespace Code.Game.Gameplay.Player +{ + public class PlayerCameraTarget : MonoBehaviour + { + [Inject] + private void Construct(CameraStateMachine cameraStateMachine) => + ((CleanerCameraState)cameraStateMachine.CurrentBaseState).SetTarget(transform); + } +} \ No newline at end of file diff --git a/Assets/Code/D/Player/PlayerCameraTarget.cs.meta b/Assets/Code/D/Player/PlayerCameraTarget.cs.meta new file mode 100644 index 00000000..143457b2 --- /dev/null +++ b/Assets/Code/D/Player/PlayerCameraTarget.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c579fd0c46544b26b3dd27ecdf36fc37 +timeCreated: 1785846388 \ No newline at end of file diff --git a/Assets/Code/D/Player/PlayerControlsProvider.cs b/Assets/Code/D/Player/PlayerControlsProvider.cs new file mode 100644 index 00000000..2e6e1b6f --- /dev/null +++ b/Assets/Code/D/Player/PlayerControlsProvider.cs @@ -0,0 +1,96 @@ +using Code.Game.Gameplay.Player; +using Code.Infrastructure.Camera; +using Code.Infrastructure.Input; +using Reflex.Attributes; +using UnityEngine; +using UnityEngine.InputSystem; + +namespace Code.Game.Cleaning.Player +{ + public class PlayerControlsProvider : MonoBehaviour + { + [SerializeField] private PlayerMovementController playerMovementController; + + private IInputService _inputService; + + private Vector2 _movementInput; + private bool _jumpDown; + private bool _crouchDown; + private bool _walkOn; + private Transform _cameraTransform; + + [Inject] + private void Construct(IInputService inputService, CameraStateMachine cameraStateMachine) + { + _cameraTransform = cameraStateMachine.Camera.transform; + _inputService = inputService; + + _inputService.BindActionPerformed((int)ActionMappings.Cleaning, (int)CleaningActions.Movement, + MovementPerformed); + _inputService.BindActionCancelled((int)ActionMappings.Cleaning, (int)CleaningActions.Movement, + MovementCancelled); + + _inputService.BindActionPerformed((int)ActionMappings.Cleaning, + (int)CleaningActions.Jump, JumpPerformed); + _inputService.BindActionCancelled((int)ActionMappings.Cleaning, + (int)CleaningActions.Jump, JumpCancelled); + + _inputService.BindActionPerformed((int)ActionMappings.Cleaning, + (int)CleaningActions.Walk, WalkPerformed); + + _inputService.BindActionPerformed((int)ActionMappings.Cleaning, + (int)CleaningActions.Crouch, CrouchPerformed); + _inputService.BindActionCancelled((int)ActionMappings.Cleaning, + (int)CleaningActions.Crouch, CrouchCancelled); + } + + private void CrouchPerformed(InputAction.CallbackContext obj) => _crouchDown = true; + private void CrouchCancelled(InputAction.CallbackContext obj) => _crouchDown = false; + + private void WalkPerformed(InputAction.CallbackContext obj) => _walkOn = !_walkOn; + private void JumpCancelled(InputAction.CallbackContext obj) => _jumpDown = false; + private void JumpPerformed(InputAction.CallbackContext obj) => _jumpDown = true; + + private void MovementCancelled(InputAction.CallbackContext obj) => _movementInput = Vector2.zero; + private void MovementPerformed(InputAction.CallbackContext obj) => _movementInput = obj.ReadValue(); + + private void Update() + { + if (!_cameraTransform) return; + + var inputs = new PlayerCharacterInputs() + { + MoveAxisForward = _movementInput.y, + MoveAxisRight = _movementInput.x, + CameraRotation = _cameraTransform.rotation, + JumpDown = _jumpDown, + CrouchDown = _crouchDown, + CrouchUp = !_crouchDown, + WalkOn = _walkOn + }; + + playerMovementController.SetInputs(ref inputs); + } + + private void OnDestroy() + { + _inputService.UnbindActionPerformed((int)ActionMappings.Cleaning, (int)CleaningActions.Movement, + MovementPerformed); + _inputService.UnbindActionCancelled((int)ActionMappings.Cleaning, (int)CleaningActions.Movement, + MovementCancelled); + + _inputService.UnbindActionPerformed((int)ActionMappings.Cleaning, + (int)CleaningActions.Jump, JumpPerformed); + _inputService.UnbindActionCancelled((int)ActionMappings.Cleaning, + (int)CleaningActions.Jump, JumpCancelled); + + _inputService.UnbindActionPerformed((int)ActionMappings.Cleaning, + (int)CleaningActions.Walk, WalkPerformed); + + _inputService.UnbindActionPerformed((int)ActionMappings.Cleaning, + (int)CleaningActions.Crouch, CrouchPerformed); + _inputService.UnbindActionCancelled((int)ActionMappings.Cleaning, + (int)CleaningActions.Crouch, CrouchCancelled); + } + } +} \ No newline at end of file diff --git a/Assets/Code/D/Player/PlayerControlsProvider.cs.meta b/Assets/Code/D/Player/PlayerControlsProvider.cs.meta new file mode 100644 index 00000000..a95a143c --- /dev/null +++ b/Assets/Code/D/Player/PlayerControlsProvider.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 75c0d109df244d6ebf8c0eb976553c6a +timeCreated: 1785846388 \ No newline at end of file diff --git a/Assets/Code/D/Player/PlayerDetailMaskDrawer.cs b/Assets/Code/D/Player/PlayerDetailMaskDrawer.cs new file mode 100644 index 00000000..d48a2477 --- /dev/null +++ b/Assets/Code/D/Player/PlayerDetailMaskDrawer.cs @@ -0,0 +1,114 @@ +using Code.D.Cleaning; +using Code.D.Player; +using Code.Infrastructure.Camera; +using Code.Infrastructure.Input; +using Cysharp.Threading.Tasks; +using R3; +using Reflex.Attributes; +using UnityEngine; +using UnityEngine.InputSystem; + +namespace Code.Game.Gameplay.Player +{ + public class PlayerDetailMaskDrawer : MonoBehaviour + { + private IInputService _inputService; + private Transform _cameraTransform; + + private bool _cleaning, _cleaningUnder; + + private LayerMask _layerMask; + private TagHandle _surfaceTag; + + private CleanableSurface _lastCleaned; + [SerializeField] private float cleaningDistance = 5f; + [SerializeField] private PlayerEquipment playerEquipment; + + private void Awake() + { + _surfaceTag = TagHandle.GetExistingTag("CleanableSurface"); + _layerMask = LayerMask.GetMask("Cleanable"); + + GetComponent().IsSliding.Subscribe(SlideToggle).AddTo(destroyCancellationToken); + } + + [Inject] + private void Construct(IInputService inputService, CameraStateMachine cameraStateMachine) + { + _cameraTransform = cameraStateMachine.Camera.transform; + _inputService = inputService; + + _inputService.BindActionPerformed((int)ActionMappings.Cleaning, (int)CleaningActions.Clean, DrawPerformed); + _inputService.BindActionCancelled((int)ActionMappings.Cleaning, (int)CleaningActions.Clean, DrawCancelled); + } + + private void SlideToggle(bool isSliding) => _cleaningUnder = isSliding; + + private void DrawPerformed(InputAction.CallbackContext obj) => _cleaning = true; + + private void DrawCancelled(InputAction.CallbackContext obj) => _cleaning = false; + + private void FixedUpdate() + { + if (_cleaning) CleanInFront(); + if (_cleaningUnder) CleanUnder(); + } + + private void CleanUnder() + { + if (!Physics.Raycast( + _cameraTransform.position, + -transform.up, + out var info, + 5f, + layerMask: _layerMask)) return; + + if (info.collider.CompareTag(_surfaceTag)) + CleanSurface(info); + } + + private void CleanInFront() + { + if (!Physics.Raycast( + _cameraTransform.position, + _cameraTransform.forward, + out var info, + cleaningDistance, + layerMask: _layerMask)) return; + + if (info.collider.CompareTag(_surfaceTag)) + CleanSurface(info); + else + CleanAsset(info); + } + + private void CleanAsset(RaycastHit info) + { + var cleanable = info.collider.GetComponent(); + + cleanable.Clean(); + } + + private void CleanSurface(RaycastHit info) + { + CleanableSurface cleanable; + if (_lastCleaned is not null && info.collider.GetEntityId() == _lastCleaned.GetEntityId()) + cleanable = _lastCleaned; + else + { + cleanable = info.collider.GetComponent(); + _lastCleaned = cleanable; + } + + cleanable.Clean(info, playerEquipment.CurrentTool.Use(), _cameraTransform); + } + + private void OnDestroy() + { + _inputService.UnbindActionPerformed((int)ActionMappings.Cleaning, (int)CleaningActions.Clean, + DrawPerformed); + _inputService.UnbindActionCancelled((int)ActionMappings.Cleaning, (int)CleaningActions.Clean, + DrawCancelled); + } + } +} \ No newline at end of file diff --git a/Assets/Code/D/Player/PlayerDetailMaskDrawer.cs.meta b/Assets/Code/D/Player/PlayerDetailMaskDrawer.cs.meta new file mode 100644 index 00000000..74ebf985 --- /dev/null +++ b/Assets/Code/D/Player/PlayerDetailMaskDrawer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f1606bdb9e6840f5960df117e5298061 +timeCreated: 1785923251 \ No newline at end of file diff --git a/Assets/Code/D/Player/PlayerEquipment.cs b/Assets/Code/D/Player/PlayerEquipment.cs new file mode 100644 index 00000000..613c4745 --- /dev/null +++ b/Assets/Code/D/Player/PlayerEquipment.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Code.D.Cleaning.CleanTools; +using R3; +using Reflex.Attributes; +using Unity.Burst; +using UnityEngine; + +namespace Code.D.Player +{ + public class PlayerEquipment : MonoBehaviour + { + [SerializeField] private Texture2D tryapkaBrushTexture; + public CleanTool CurrentTool { get; private set; } + private Dictionary _cleanTools = new(); + public ReactiveProperty CurrentToolType { get; } = new(); + + private IDisposable _dirtinessDisposable; + + [Inject] + private void Construct(List cleanTools) + { + foreach (var cleanTool in cleanTools) _cleanTools.Add(cleanTool.ToolType, cleanTool); + + var firstTool = _cleanTools.First(); + CurrentToolType.Value = firstTool.Key; + CurrentTool = firstTool.Value; + } + + private void Awake() + { + //CurrentTool = new Tryapka(0.0001f, 0.005f, tryapkaBrushTexture); + // + // DisposableBuilder builder = new DisposableBuilder(); + // // Я безумец, здесь подписаться на все сразу + // builder.Add(CurrentTool.CurrentDirtiness.Subscribe(x => CurrentToolDirtiness.Value = + // new ToolDirtinessData + // { + // Dirtiness = x, + // ToolType = CleanToolType.Tryapka + // } + // )); + // + // _dirtinessDisposable = builder.Build(); + + } + + private void OnDestroy() + { + _dirtinessDisposable?.Dispose(); + } + } + + public struct ToolDirtinessData : IEquatable + { + public float Dirtiness; + public CleanToolType ToolType; + + public bool Equals(ToolDirtinessData other) + { + return Mathf.Approximately(Dirtiness, other.Dirtiness) && ToolType == other.ToolType; + } + + [BurstDiscard] + public override bool Equals(object obj) + { + return obj is ToolDirtinessData other && Equals(other); + } + + [BurstDiscard] + public override int GetHashCode() + { + return HashCode.Combine(Dirtiness, ToolType); + } + + public static bool operator ==(ToolDirtinessData left, ToolDirtinessData right) => left.Equals(right); + public static bool operator !=(ToolDirtinessData left, ToolDirtinessData right) => !left.Equals(right); + } + + public struct ToolDirtyData : IEquatable + { + public CleanToolType ToolType; + + public bool Equals(ToolDirtyData other) + { + return ToolType == other.ToolType; + } + + [BurstDiscard] + public override bool Equals(object obj) + { + return obj is ToolDirtyData other && Equals(other); + } + + [BurstDiscard] + public override int GetHashCode() + { + return ToolType.GetHashCode(); + } + + public static bool operator ==(ToolDirtyData left, ToolDirtyData right) => left.Equals(right); + public static bool operator !=(ToolDirtyData left, ToolDirtyData right) => !left.Equals(right); + } +} \ No newline at end of file diff --git a/Assets/Code/D/Player/PlayerEquipment.cs.meta b/Assets/Code/D/Player/PlayerEquipment.cs.meta new file mode 100644 index 00000000..e8016bf7 --- /dev/null +++ b/Assets/Code/D/Player/PlayerEquipment.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ba4e659f17b147db992374aab735ed4c +timeCreated: 1785940207 \ No newline at end of file diff --git a/Assets/Code/D/Player/PlayerInteractor.cs b/Assets/Code/D/Player/PlayerInteractor.cs new file mode 100644 index 00000000..ee802e30 --- /dev/null +++ b/Assets/Code/D/Player/PlayerInteractor.cs @@ -0,0 +1,64 @@ +using Code.D.Cleaning.CleanTools; +using Code.Infrastructure.Camera; +using Code.Infrastructure.Input; +using Reflex.Attributes; +using UnityEngine; +using UnityEngine.InputSystem; + +namespace Code.D.Player +{ + public class PlayerInteractor : MonoBehaviour + { + private IInputService _inputService; + private LayerMask _cleanToolInteractableMask; + private Transform _cameraTransform; + private CleanToolInteractable _lastCleanToolInteractable; + + [SerializeField] private float interactionDistance = 5f; + [SerializeField] private PlayerEquipment playerEquipment; + + private void Awake() + { + _cleanToolInteractableMask = LayerMask.GetMask("CleanToolInteractable"); + } + + [Inject] + private void Construct(IInputService inputService, CameraStateMachine cameraStateMachine) + { + _cameraTransform = cameraStateMachine.Camera.transform; + + _inputService = inputService; + inputService.BindActionPerformed((int)ActionMappings.Cleaning, (int)CleaningActions.Interact, TryInteract); + } + + private void OnDestroy() + { + _inputService.UnbindActionPerformed((int)ActionMappings.Cleaning, (int)CleaningActions.Interact, + TryInteract); + } + + private void TryInteract(InputAction.CallbackContext obj) + { + if (!Physics.Raycast( + _cameraTransform.position, + _cameraTransform.forward, + out var info, + interactionDistance, + layerMask: _cleanToolInteractableMask)) return; + + CleanToolInteractable interactable; + if (_lastCleanToolInteractable is not null && + info.collider.GetEntityId() == _lastCleanToolInteractable.GetEntityId()) + { + interactable = _lastCleanToolInteractable; + } + else + { + interactable = info.collider.gameObject.GetComponent(); + _lastCleanToolInteractable = interactable; + } + + interactable.Use(playerEquipment.CurrentTool); + } + } +} \ No newline at end of file diff --git a/Assets/Code/D/Player/PlayerInteractor.cs.meta b/Assets/Code/D/Player/PlayerInteractor.cs.meta new file mode 100644 index 00000000..74d1546e --- /dev/null +++ b/Assets/Code/D/Player/PlayerInteractor.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 997fa523ddda4b1ea3f4b0b1e1e7864a +timeCreated: 1785939712 \ No newline at end of file diff --git a/Assets/Code/D/Player/PlayerMovementController.cs b/Assets/Code/D/Player/PlayerMovementController.cs new file mode 100644 index 00000000..0bee1205 --- /dev/null +++ b/Assets/Code/D/Player/PlayerMovementController.cs @@ -0,0 +1,644 @@ +using System.Collections.Generic; +using Alchemy.Inspector; +using KinematicCharacterController; +using LitMotion; +using LitMotion.Extensions; +using R3; +using UnityEngine; + +namespace Code.Game.Gameplay.Player +{ + public enum CharacterState + { + Default, + Sliding + } + + public enum OrientationMethod + { + TowardsCamera, + TowardsMovement, + } + + public struct PlayerCharacterInputs + { + public float MoveAxisForward; + public float MoveAxisRight; + public Quaternion CameraRotation; + public bool JumpDown; + public bool CrouchDown; + public bool CrouchUp; + public bool WalkOn; + } + + public struct AICharacterInputs + { + public Vector3 MoveVector; + public Quaternion Look; + } + + public enum BonusOrientationMethod + { + None, + TowardsGravity, + TowardsGroundSlopeAndGravity, + } + + public class PlayerMovementController : MonoBehaviour, ICharacterController + { + public KinematicCharacterMotor Motor; + + [TabGroup("Stable Movement")] public float MaxStableMoveSpeed = 10f; + [TabGroup("Stable Movement")] public float SprintingModifier = 2f; + [TabGroup("Stable Movement")] public float StableMovementSharpness = 15f; + [TabGroup("Stable Movement")] public float OrientationSharpness = 10f; + [TabGroup("Stable Movement")] public OrientationMethod OrientationMethod = OrientationMethod.TowardsCamera; + + [TabGroup("Sliding")] public AnimationCurve SlideSpeedMultiplierCurve; + [TabGroup("Sliding")] public float SlideSpeedCurveStep = 0.1f; + [TabGroup("Sliding")] public float MaxCrouchMoveSpeed = 5f; + [TabGroup("Sliding")] public float InCrouchTime = 1f; + [TabGroup("Sliding")] public float OutCrouchTime = 1f; + [TabGroup("Sliding")] public float SlideStupidity = 0.1f; + + [TabGroup("Air Movement")] public float MaxAirMoveSpeed = 15f; + [TabGroup("Air Movement")] public float AirAccelerationSpeed = 15f; + [TabGroup("Air Movement")] public float Drag = 0.1f; + + [TabGroup("Jumping")] public bool AllowJumpingWhenSliding = false; + [TabGroup("Jumping")] public float JumpUpSpeed = 10f; + [TabGroup("Jumping")] public float JumpScalableForwardSpeed = 10f; + [TabGroup("Jumping")] public float JumpPreGroundingGraceTime = 0f; + [TabGroup("Jumping")] public float JumpPostGroundingGraceTime = 0f; + [TabGroup("Jumping")] public BonusOrientationMethod BonusOrientationMethod = BonusOrientationMethod.None; + [TabGroup("Jumping")] public float BonusOrientationSharpness = 10f; + [TabGroup("Jumping")] public float BonusOrientationGravitySharpness; + [TabGroup("Jumping")] public Vector3 Gravity = new Vector3(0, -30f, 0); + + [TabGroup("Misc")] public List IgnoredColliders = new List(); + [TabGroup("Misc")] public Transform cameraTransform; + [TabGroup("Misc")] public float CrouchedCapsuleHeight = 1f; + public CharacterState CurrentCharacterState { get; private set; } + public Vector3 CurrentVelocity => Motor.Velocity; + public Quaternion CurrentRotation => Motor.TransientRotation; + + private Collider[] _probedColliders = new Collider[8]; + private RaycastHit[] _probedHits = new RaycastHit[8]; + private Vector3 _moveInputVector; + private Vector3 _lookInputVector; + private bool _jumpRequested = false; + private bool _jumpConsumed = false; + private bool _jumpedThisFrame = false; + private float _timeSinceJumpRequested = Mathf.Infinity; + private float _timeSinceLastAbleToJump = 0f; + private Vector3 _internalVelocityAdd = Vector3.zero; + private bool _shouldBeCrouching = false; + private bool _isCrouching = false; + public ReactiveProperty IsSliding { get; } = new(); + private bool _isSliding = false; + private float _slideCurveProgress; + private bool _isSlideEnded = false; + private bool _isSprinting = false; + + private Vector3 lastInnerNormal = Vector3.zero; + private Vector3 lastOuterNormal = Vector3.zero; + + private void Awake() + { + // Handle initial state + TransitionToState(CharacterState.Default); + + // Assign the characterController to the motor + Motor.CharacterController = this; + } + + /// + /// Handles movement state transitions and enter/exit callbacks + /// + public void TransitionToState(CharacterState newState) + { + CharacterState tmpInitialState = CurrentCharacterState; + OnStateExit(tmpInitialState, newState); + CurrentCharacterState = newState; + OnStateEnter(newState, tmpInitialState); + } + + /// + /// Event when entering a state + /// + public void OnStateEnter(CharacterState state, CharacterState fromState) + { + switch (state) + { + case CharacterState.Default: + { + break; + } + } + } + + /// + /// Event when exiting a state + /// + public void OnStateExit(CharacterState state, CharacterState toState) + { + switch (state) + { + case CharacterState.Default: + { + break; + } + } + } + + /// + /// This is called every frame by ExamplePlayer in order to tell the character what its inputs are + /// + public void SetInputs(ref PlayerCharacterInputs inputs) + { + // Clamp input + Vector3 moveInputVector = + Vector3.ClampMagnitude(new Vector3(inputs.MoveAxisRight, 0f, inputs.MoveAxisForward), 1f); + + // Calculate camera direction and rotation on the character plane + Vector3 cameraPlanarDirection = + Vector3.ProjectOnPlane(inputs.CameraRotation * Vector3.forward, Motor.CharacterUp).normalized; + if (cameraPlanarDirection.sqrMagnitude == 0f) + { + cameraPlanarDirection = Vector3.ProjectOnPlane(inputs.CameraRotation * Vector3.up, Motor.CharacterUp) + .normalized; + } + + Quaternion cameraPlanarRotation = Quaternion.LookRotation(cameraPlanarDirection, Motor.CharacterUp); + + switch (CurrentCharacterState) + { + case CharacterState.Default: + { + if (_isSliding) + { + moveInputVector.x *= SlideStupidity; + } + // Move and look inputs + _moveInputVector = cameraPlanarRotation * moveInputVector; + + switch (OrientationMethod) + { + case OrientationMethod.TowardsCamera: + _lookInputVector = cameraPlanarDirection; + break; + case OrientationMethod.TowardsMovement: + _lookInputVector = _moveInputVector.normalized; + break; + } + + // Jumping input + if (inputs.JumpDown) + { + _timeSinceJumpRequested = 0f; + _jumpRequested = true; + } + + _isSprinting = !inputs.WalkOn; + + // Crouching input + if (inputs.CrouchDown) + { + _shouldBeCrouching = true; + + if (!_isCrouching) + { + if(_isSprinting && !_isSlideEnded) + { + _isSliding = true; + IsSliding.Value = true; + } + else _isSlideEnded = true; + + _isCrouching = true; + Motor.SetCapsuleDimensions(0.5f, CrouchedCapsuleHeight, CrouchedCapsuleHeight * 0.5f); + + if(_crouchTransition.IsPlaying()) _crouchTransition.Cancel(); + + _crouchTransition = LMotion.Create(cameraTransform.localPosition.y, 0.85f, InCrouchTime) + .WithEase(Ease.InOutQuad) + .BindToLocalPositionY(cameraTransform); + } + + } + else if (inputs.CrouchUp) + { + _shouldBeCrouching = false; + } + + break; + } + } + } + + /// + /// This is called every frame by the AI script in order to tell the character what its inputs are + /// + public void SetInputs(ref AICharacterInputs inputs) + { + // _moveInputVector = inputs.MoveVector; + // _lookInputVector = inputs.Look; + var cameraPlanarDirection = + Vector3.ProjectOnPlane(inputs.Look * Vector3.forward, Motor.CharacterUp).normalized; + + if (cameraPlanarDirection.sqrMagnitude == 0f) + { + cameraPlanarDirection = Vector3.ProjectOnPlane(inputs.Look * Vector3.up, Motor.CharacterUp) + .normalized; + } + + //var cameraPlanarRotation = Quaternion.LookRotation(cameraPlanarDirection, Motor.CharacterUp); + + _moveInputVector = inputs.MoveVector; // cameraPlanarRotation * + _lookInputVector = cameraPlanarDirection; + } + + private Quaternion _tmpTransientRot; + private MotionHandle _crouchTransition; + + /// + /// (Called by KinematicCharacterMotor during its update cycle) + /// This is called before the character begins its movement update + /// + public void BeforeCharacterUpdate(float deltaTime) + { + } + + /// + /// (Called by KinematicCharacterMotor during its update cycle) + /// This is where you tell your character what its rotation should be right now. + /// This is the ONLY place where you should set the character's rotation + /// + public void UpdateRotation(ref Quaternion currentRotation, float deltaTime) + { + switch (CurrentCharacterState) + { + case CharacterState.Default: + { + if (_lookInputVector.sqrMagnitude > 0f && OrientationSharpness > 0f) + { + // Smoothly interpolate from current to target look direction + + Vector3 smoothedLookInputDirection = Vector3.Slerp(Motor.CharacterForward, _lookInputVector, + 1 - Mathf.Exp(-OrientationSharpness * deltaTime)).normalized; + + // Set the current rotation (which will be used by the KinematicCharacterMotor) + currentRotation = Quaternion.LookRotation(smoothedLookInputDirection, Motor.CharacterUp); + } + + Vector3 currentUp = (currentRotation * Vector3.up); + if (BonusOrientationMethod == BonusOrientationMethod.TowardsGravity) + { + // Rotate from current up to invert gravity + Vector3 smoothedGravityDir = Vector3.Slerp(currentUp, -Gravity.normalized, + 1 - Mathf.Exp(-BonusOrientationSharpness * deltaTime)); + currentRotation = Quaternion.FromToRotation(currentUp, smoothedGravityDir) * currentRotation; + } + else if (BonusOrientationMethod == BonusOrientationMethod.TowardsGroundSlopeAndGravity) + { + if (Motor.GroundingStatus.IsStableOnGround) + { + Vector3 initialCharacterBottomHemiCenter = + Motor.TransientPosition + (currentUp * Motor.Capsule.radius); + + Vector3 smoothedGroundNormal = Vector3.Slerp(Motor.CharacterUp, + Motor.GroundingStatus.GroundNormal, + 1 - Mathf.Exp(-BonusOrientationSharpness * deltaTime)); + currentRotation = Quaternion.FromToRotation(currentUp, smoothedGroundNormal) * + currentRotation; + + // Move the position to create a rotation around the bottom hemi center instead of around the pivot + Motor.SetTransientPosition(initialCharacterBottomHemiCenter + + (currentRotation * Vector3.down * Motor.Capsule.radius)); + } + else + { + BonusOrientationGravitySharpness = 0.01f; + Vector3 smoothedGravityDir = Vector3.Slerp(currentUp, Motor.Velocity.normalized, + 1 - Mathf.Exp(-BonusOrientationSharpness * deltaTime * + BonusOrientationGravitySharpness)); + // Vector3 smoothedGravityDir = Vector3.Slerp(currentUp, -Gravity.normalized, + // 1 - Mathf.Exp(-BonusOrientationSharpness * deltaTime * BonusOrientationGravitySharpness)); + currentRotation = Quaternion.FromToRotation(currentUp, smoothedGravityDir) * + currentRotation; + } + } + else + { + Vector3 smoothedGravityDir = Vector3.Slerp(currentUp, Vector3.up, + 1 - Mathf.Exp(-BonusOrientationSharpness * deltaTime)); + currentRotation = Quaternion.FromToRotation(currentUp, smoothedGravityDir) * currentRotation; + } + + break; + } + } + } + + /// + /// (Called by KinematicCharacterMotor during its update cycle) + /// This is where you tell your character what its velocity should be right now. + /// This is the ONLY place where you can set the character's velocity + /// + public void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime) + { + switch (CurrentCharacterState) + { + case CharacterState.Default: + { + // Ground movement + if (Motor.GroundingStatus.IsStableOnGround) + { + float currentVelocityMagnitude = currentVelocity.magnitude; + + Vector3 effectiveGroundNormal = Motor.GroundingStatus.GroundNormal; + + // Reorient velocity on slope + currentVelocity = Motor.GetDirectionTangentToSurface(currentVelocity, effectiveGroundNormal) * + currentVelocityMagnitude; + + // Calculate target velocity + Vector3 inputRight = Vector3.Cross(_moveInputVector, Motor.CharacterUp); + + Vector3 reorientedInput = Vector3.Cross(effectiveGroundNormal, inputRight).normalized * + _moveInputVector.magnitude; + + Vector3 targetMovementVelocity; + + switch (_isCrouching) + { + case true when _isSliding && !_isSlideEnded: + { + _slideCurveProgress += deltaTime; + + var slideMultiplier = SlideSpeedMultiplierCurve + .Evaluate(_slideCurveProgress * SlideSpeedCurveStep); + targetMovementVelocity = reorientedInput * (MaxStableMoveSpeed * slideMultiplier); + + if (_slideCurveProgress >= 1f) _isSlideEnded = true; + break; + } + case true: + targetMovementVelocity = reorientedInput * MaxCrouchMoveSpeed; + break; + default: + targetMovementVelocity = reorientedInput * MaxStableMoveSpeed; + break; + } + + if (_isSprinting) targetMovementVelocity *= SprintingModifier; + + // Smooth movement Velocity + currentVelocity = Vector3.Lerp(currentVelocity, targetMovementVelocity, + 1f - Mathf.Exp(-StableMovementSharpness * deltaTime)); + } + // Air movement + else + { + // Add move input + if (_moveInputVector.sqrMagnitude > 0f) + { + Vector3 addedVelocity = _moveInputVector * (AirAccelerationSpeed * deltaTime); + + Vector3 currentVelocityOnInputsPlane = + Vector3.ProjectOnPlane(currentVelocity, Motor.CharacterUp); + + // Limit air velocity from inputs + if (currentVelocityOnInputsPlane.magnitude < MaxAirMoveSpeed) + { + // clamp addedVel to make total vel not exceed max vel on inputs plane + Vector3 newTotal = Vector3.ClampMagnitude(currentVelocityOnInputsPlane + addedVelocity, + MaxAirMoveSpeed); + addedVelocity = newTotal - currentVelocityOnInputsPlane; + } + else + { + // Make sure added vel doesn't go in the direction of the already-exceeding velocity + if (Vector3.Dot(currentVelocityOnInputsPlane, addedVelocity) > 0f) + { + addedVelocity = Vector3.ProjectOnPlane(addedVelocity, + currentVelocityOnInputsPlane.normalized); + } + } + + // Prevent air-climbing sloped walls + if (Motor.GroundingStatus.FoundAnyGround) + { + if (Vector3.Dot(currentVelocity + addedVelocity, addedVelocity) > 0f) + { + Vector3 perpenticularObstructionNormal = Vector3 + .Cross(Vector3.Cross(Motor.CharacterUp, Motor.GroundingStatus.GroundNormal), + Motor.CharacterUp).normalized; + addedVelocity = + Vector3.ProjectOnPlane(addedVelocity, perpenticularObstructionNormal); + } + } + + // Apply added velocity + currentVelocity += addedVelocity; + } + + // Gravity + currentVelocity += Gravity * deltaTime; + + // Drag + currentVelocity *= (1f / (1f + (Drag * deltaTime))); + } + + // Handle jumping + _jumpedThisFrame = false; + _timeSinceJumpRequested += deltaTime; + if (_jumpRequested) + { + // See if we actually are allowed to jump + if (!_jumpConsumed && + ((AllowJumpingWhenSliding + ? Motor.GroundingStatus.FoundAnyGround + : Motor.GroundingStatus.IsStableOnGround) || + _timeSinceLastAbleToJump <= JumpPostGroundingGraceTime)) + { + // Calculate jump direction before ungrounding + Vector3 jumpDirection = Motor.CharacterUp; + if (Motor.GroundingStatus.FoundAnyGround && !Motor.GroundingStatus.IsStableOnGround) + { + jumpDirection = Motor.GroundingStatus.GroundNormal; + } + + // Makes the character skip ground probing/snapping on its next update. + // If this line weren't here, the character would remain snapped to the ground when trying to jump. Try commenting this line out and see. + Motor.ForceUnground(); + + // Add to the return velocity and reset jump state + currentVelocity += (jumpDirection * JumpUpSpeed) - + Vector3.Project(currentVelocity, Motor.CharacterUp); + currentVelocity += (_moveInputVector * JumpScalableForwardSpeed); + _jumpRequested = false; + _jumpConsumed = true; + _jumpedThisFrame = true; + } + } + + // Take into account additive velocity + if (_internalVelocityAdd.sqrMagnitude > 0f) + { + currentVelocity += _internalVelocityAdd; + _internalVelocityAdd = Vector3.zero; + } + + break; + } + } + } + + /// + /// (Called by KinematicCharacterMotor during its update cycle) + /// This is called after the character has finished its movement update + /// + public void AfterCharacterUpdate(float deltaTime) + { + switch (CurrentCharacterState) + { + case CharacterState.Default: + { + // Handle jump-related values + { + // Handle jumping pre-ground grace period + if (_jumpRequested && _timeSinceJumpRequested > JumpPreGroundingGraceTime) + { + _jumpRequested = false; + } + + if (AllowJumpingWhenSliding + ? Motor.GroundingStatus.FoundAnyGround + : Motor.GroundingStatus.IsStableOnGround) + { + // If we're on a ground surface, reset jumping values + if (!_jumpedThisFrame) + { + _jumpConsumed = false; + } + + _timeSinceLastAbleToJump = 0f; + } + else + { + // Keep track of time since we were last able to jump (for grace period) + _timeSinceLastAbleToJump += deltaTime; + } + } + + if (_isSliding && _isSlideEnded) + { + _isSliding = false; + IsSliding.Value = false; + } + // Handle uncrouching + if (_isCrouching && !_shouldBeCrouching) + { + // Do an overlap test with the character's standing height to see if there are any obstructions + Motor.SetCapsuleDimensions(0.5f, 2f, 1f); + if (Motor.CharacterOverlap( + Motor.TransientPosition, + Motor.TransientRotation, + _probedColliders, + Motor.CollidableLayers, + QueryTriggerInteraction.Ignore) > 0) + { + // If obstructions, just stick to crouching dimensions + Motor.SetCapsuleDimensions(0.5f, CrouchedCapsuleHeight, CrouchedCapsuleHeight * 0.5f); + } + else + { + // If no obstructions, uncrouch + if(_crouchTransition.IsPlaying()) _crouchTransition.Cancel(); + + _crouchTransition = LMotion.Create(cameraTransform.localPosition.y, 1.71f, OutCrouchTime) + .WithEase(Ease.InOutQuad) + .BindToLocalPositionY(cameraTransform); + + _isCrouching = false; + _isSliding = false; + IsSliding.Value = false; + _isSlideEnded = false; + _slideCurveProgress = 0f; + } + } + + break; + } + } + } + + public void PostGroundingUpdate(float deltaTime) + { + // Handle landing and leaving ground + if (Motor.GroundingStatus.IsStableOnGround && !Motor.LastGroundingStatus.IsStableOnGround) + { + OnLanded(); + } + else if (!Motor.GroundingStatus.IsStableOnGround && Motor.LastGroundingStatus.IsStableOnGround) + { + OnLeaveStableGround(); + } + } + + public bool IsColliderValidForCollisions(Collider coll) + { + if (IgnoredColliders.Count == 0) + { + return true; + } + + if (IgnoredColliders.Contains(coll)) + { + return false; + } + + return true; + } + + public void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, + ref HitStabilityReport hitStabilityReport) + { + } + + public void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, + ref HitStabilityReport hitStabilityReport) + { + } + + public void AddVelocity(Vector3 velocity) + { + switch (CurrentCharacterState) + { + case CharacterState.Default: + { + _internalVelocityAdd += velocity; + break; + } + } + } + + public void ProcessHitStabilityReport(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, + Vector3 atCharacterPosition, Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport) + { + } + + protected void OnLanded() + { + } + + protected void OnLeaveStableGround() + { + } + + public void OnDiscreteCollisionDetected(Collider hitCollider) + { + } + } +} \ No newline at end of file diff --git a/Assets/Code/D/Player/PlayerMovementController.cs.meta b/Assets/Code/D/Player/PlayerMovementController.cs.meta new file mode 100644 index 00000000..396306be --- /dev/null +++ b/Assets/Code/D/Player/PlayerMovementController.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 45d9830d22b54832ade96a92f599643a +timeCreated: 1785846388 \ No newline at end of file diff --git a/Assets/Code/Debug.meta b/Assets/Code/Debug.meta new file mode 100644 index 00000000..d314591e --- /dev/null +++ b/Assets/Code/Debug.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e882a0f0fb5d41f5a1d3b2c41d1f4097 +timeCreated: 1785874067 \ No newline at end of file diff --git a/Assets/Code/Debug/StartFromBootstrap.cs b/Assets/Code/Debug/StartFromBootstrap.cs new file mode 100644 index 00000000..5b65d27e --- /dev/null +++ b/Assets/Code/Debug/StartFromBootstrap.cs @@ -0,0 +1,20 @@ +#if UNITY_EDITOR +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; + +[InitializeOnLoad] +public class StartFromBootstrap +{ + static StartFromBootstrap() + { + var scenePath = "Assets/Infrastructure/Bootstrap.unity"; + var sceneAsset = AssetDatabase.LoadAssetAtPath(scenePath); + + if (sceneAsset != null) + EditorSceneManager.playModeStartScene = sceneAsset; + else + Debug.LogError("Could not find scene at " + scenePath); + } +} +#endif \ No newline at end of file diff --git a/Assets/Code/Debug/StartFromBootstrap.cs.meta b/Assets/Code/Debug/StartFromBootstrap.cs.meta new file mode 100644 index 00000000..de9965e2 --- /dev/null +++ b/Assets/Code/Debug/StartFromBootstrap.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5c1b8ca63d9a4ba19fb70cb4ec7b7609 +timeCreated: 1785874078 \ No newline at end of file diff --git a/Assets/Code/Debug/TestingLevel.meta b/Assets/Code/Debug/TestingLevel.meta new file mode 100644 index 00000000..9ee0a36f --- /dev/null +++ b/Assets/Code/Debug/TestingLevel.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c030bebb626a43c7acf7f3a48acc09eb +timeCreated: 1785847329 \ No newline at end of file diff --git a/Assets/Code/Debug/TestingLevel/TestingLevelSceneInstaller.cs b/Assets/Code/Debug/TestingLevel/TestingLevelSceneInstaller.cs new file mode 100644 index 00000000..21e1e131 --- /dev/null +++ b/Assets/Code/Debug/TestingLevel/TestingLevelSceneInstaller.cs @@ -0,0 +1,51 @@ +using System; +using Code.Game.Gameplay.Player.Factory; +using Code.Infrastructure.SceneLoader; +using Cysharp.Threading.Tasks; +using R3; +using Reflex.Core; +using UnityEngine; + +namespace Code.Game.TestingLevel +{ + + [Serializable] + public struct TestingLevelData + { + public Transform playerSpawnPoint; + } + public class TestingLevelSceneInstaller: MonoBehaviour, IInstaller, IDisposable + { + private IDisposable _onContainerBuildDisposable; + [SerializeField] private TestingLevelData testingLevelData; + + public void InstallBindings(ContainerBuilder containerBuilder) + { + containerBuilder.RegisterValue(testingLevelData); + + _onContainerBuildDisposable = Observable + .FromEvent( + h => containerBuilder.OnContainerBuilt += h, + h => containerBuilder.OnContainerBuilt -= h) + .Subscribe(x => OnContainerBuilt(x).Forget()); + } + + private ISceneContainerManager _sceneContainerManager; + private async UniTaskVoid OnContainerBuilt(Container container) + { + await UniTask.Yield(); + + container.Resolve().InjectPlayer(container); + + _onContainerBuildDisposable.Dispose(); + + _sceneContainerManager = container.Resolve(); + _sceneContainerManager.ScenesContainers.Add(SceneId.Testing, container); + } + + public void Dispose() + { + _sceneContainerManager.ScenesContainers.Remove(SceneId.Testing); + } + } +} \ No newline at end of file diff --git a/Assets/Code/Debug/TestingLevel/TestingLevelSceneInstaller.cs.meta b/Assets/Code/Debug/TestingLevel/TestingLevelSceneInstaller.cs.meta new file mode 100644 index 00000000..8a959c18 --- /dev/null +++ b/Assets/Code/Debug/TestingLevel/TestingLevelSceneInstaller.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: db514476e4864e78b2ab1734a44b450c +timeCreated: 1785847631 \ No newline at end of file diff --git a/Assets/Code/Debug/TestingLevel/TestingState.cs b/Assets/Code/Debug/TestingLevel/TestingState.cs new file mode 100644 index 00000000..0ea9e764 --- /dev/null +++ b/Assets/Code/Debug/TestingLevel/TestingState.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Code.D.Cleaning.CleanTools; +using Code.D.Cleaning.UI; +using Code.D.Player; +using Code.Game.Gameplay.Player; +using Code.Game.Gameplay.Player.Factory; +using Code.Infrastructure.App; +using Code.Infrastructure.Camera; +using Code.Infrastructure.Generators; +using Code.Infrastructure.Input; +using Code.Infrastructure.SceneLoader; +using Code.Infrastructure.UI; +using Code.Infrastructure.Utils; +using Cysharp.Threading.Tasks; +using KinematicCharacterController; +using ObservableCollections; +using R3; +using Reflex.Core; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace Code.Game.TestingLevel +{ + [State(typeof(AppStates), typeof(AppStateMachineContext))] + public partial class TestingState + { + public TestingState(AppStateMachineContext context) : base(context) + { + } + + public override AppStates MyState => AppStates.Testing; + + public override async UniTask EnterState() + { + Cursor.lockState = CursorLockMode.Locked; + + Context.InputService.EnableMap(ActionMappings.Cleaning); + + Context.AudioService.SetAudioListener(Context.Camera.Camera.GetComponent()); + + await Context.Camera.SwitchState(CameraMode.Cleaner); + + var waitForContainer = + Context.SceneContainerManager.ScenesContainers + .ObserveDictionaryAdd() + .Where(x => x.Key == SceneId.Testing) + .Take(1) + .WaitAsync() + .AsUniTask(); + + var cleaningPanel = (CleaningPanel) await Context.UIFactory.LoadPanel(UIPanelType.Cleaning,true); + + var factoryConfig = new SingleConfig(); + var cleanToolsConfigs = new MultipleConfig(); + + await UniTask.WhenAll( + factoryConfig.LoadConfig(), + cleanToolsConfigs.LoadConfigs() + ); + + var factory = new PlayerFactory(factoryConfig); + var player = await factory.CreatePlayer(); + var playerKinematicCharacterMotor = player.GetComponent(); + var playerMovementController = player.GetComponent(); + var playerEquipment = player.GetComponent(); + + CleanToolConfig[] toolsConfigs = cleanToolsConfigs.Configs.ToArray(); + List cleanTools = new(); + + // TODO Сделать сервис снабжения игрока + foreach (var toolConfig in toolsConfigs) + { + switch (toolConfig.ToolType) + { + case CleanToolType.Tryapka: + cleanTools.Add(new Tryapka(toolConfig.DurabilityUsageStep, toolConfig.CleanRadius, toolConfig.BrushTexture)); + break; + } + } + + void InstallExtra(Scene scene, ContainerBuilder builder) + { + builder.RegisterValue(factoryConfig); + builder.RegisterValue(factory, new []{typeof(IPlayerFactory)}); + builder.RegisterValue(playerKinematicCharacterMotor); + builder.RegisterValue(playerMovementController); + builder.RegisterValue(playerEquipment); + builder.RegisterValue(cleanTools); + builder.RegisterValue(cleaningPanel); + } + + await UniTask.WhenAll( + Context.SceneLoader + .LoadSceneAsync( + SceneId.Testing, + LoadSceneMode.Single, + true, + InstallExtra), + waitForContainer + ); + + var container = Context.SceneContainerManager.ScenesContainers[SceneId.Testing]; + + container.Resolve() + .SetPositionAndRotation( + container.Resolve().playerSpawnPoint.position, + container.Resolve().playerSpawnPoint.rotation); + + ((CleanerCameraState)Context.Camera.CurrentBaseState) + .SetPlayer(container.Resolve()); + } + + public override async UniTask ExitState() + { + Context.InputService.DisableMap(ActionMappings.Cleaning); + + await Context.SceneLoader.UnloadSceneAsync(SceneId.Testing); + } + } +} \ No newline at end of file diff --git a/Assets/Code/Debug/TestingLevel/TestingState.cs.meta b/Assets/Code/Debug/TestingLevel/TestingState.cs.meta new file mode 100644 index 00000000..e1cd0bb8 --- /dev/null +++ b/Assets/Code/Debug/TestingLevel/TestingState.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7c6095424c534587b8b6ed7c758375e5 +timeCreated: 1785847339 \ No newline at end of file diff --git a/Assets/Code/Debug/UVVisualizer.shader b/Assets/Code/Debug/UVVisualizer.shader new file mode 100644 index 00000000..c5e3ca3b --- /dev/null +++ b/Assets/Code/Debug/UVVisualizer.shader @@ -0,0 +1,74 @@ +Shader "Custom/UVRegionHighlighter" +{ + Properties + { + _HighlightMin ("Highlight Min (U, V)", Vector) = (0.2, 0.2, 0, 0) + _HighlightMax ("Highlight Max (U, V)", Vector) = (0.5, 0.5, 0, 0) + _GridCount ("Grid Count", Float) = 10.0 + _HighlightColor ("Highlight Color", Color) = (1, 0, 0, 1) + } + SubShader + { + Tags { "RenderType"="Opaque" } + LOD 100 + + Pass + { + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #include "UnityCG.cginc" + + struct appdata + { + float4 vertex : POSITION; + float2 uv : TEXCOORD1; + }; + + struct v2f + { + float2 uv : TEXCOORD1; + float4 vertex : SV_POSITION; + }; + + float4 _HighlightMin; + float4 _HighlightMax; + float _GridCount; + fixed4 _HighlightColor; + + v2f vert (appdata v) + { + v2f o; + o.vertex = UnityObjectToClipPos(v.vertex); + o.uv = v.uv; + return o; + } + + fixed4 frag (v2f i) : SV_Target + { + float2 uv = i.uv; + + // Сетка (линии разметки) + float2 grid = frac(uv * _GridCount); + float lineMask = step(0.92, grid.x) + step(0.92, grid.y); + lineMask = saturate(lineMask); + + // Проверка: находится ли пиксель в выбранных UV-координатах + bool inRegion = (uv.x >= _HighlightMin.x && uv.x <= _HighlightMax.x && + uv.y >= _HighlightMin.y && uv.y <= _HighlightMax.y); + + // Базовый цвет UV + черная сетка + fixed4 baseColor = lerp(fixed4(uv.x, uv.y, 0.0, 1.0), fixed4(0, 0, 0, 1), lineMask); + + // Если пиксель внутри выделенного участка UV — подсвечиваем его + if (inRegion) + { + return lerp(_HighlightColor, fixed4(1, 1, 1, 1), lineMask * 0.5); + } + + return baseColor; + } + ENDCG + } + } +} \ No newline at end of file diff --git a/Assets/Code/Debug/UVVisualizer.shader.meta b/Assets/Code/Debug/UVVisualizer.shader.meta new file mode 100644 index 00000000..a933648a --- /dev/null +++ b/Assets/Code/Debug/UVVisualizer.shader.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fa803291ec594773ad1056019437aa30 +timeCreated: 1786007069 \ No newline at end of file diff --git a/Assets/Code/Infrastructure.meta b/Assets/Code/Infrastructure.meta new file mode 100644 index 00000000..f229f2dc --- /dev/null +++ b/Assets/Code/Infrastructure.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 67a3491d6e6742faa2f703b763446706 +timeCreated: 1785766160 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/App.meta b/Assets/Code/Infrastructure/App.meta new file mode 100644 index 00000000..7176aa08 --- /dev/null +++ b/Assets/Code/Infrastructure/App.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 03ec58f5292de68cb94cf053c242d44a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Code/Infrastructure/App/AppStateMachine.cs b/Assets/Code/Infrastructure/App/AppStateMachine.cs new file mode 100644 index 00000000..c4714f55 --- /dev/null +++ b/Assets/Code/Infrastructure/App/AppStateMachine.cs @@ -0,0 +1,33 @@ +using Code.Infrastructure.Audio; +using Code.Infrastructure.Camera; +using Code.Infrastructure.Input; +using Code.Infrastructure.Particles; +using Code.Infrastructure.SceneLoader; +using Code.Infrastructure.UI; +using Code.Infrastructure.Volume; +using Reflex.Attributes; + +namespace Code.Infrastructure.App +{ + public class AppStateMachineContext + { + [Inject] public ISceneContainerManager SceneContainerManager { get; set; } + [Inject] public ISceneLoader SceneLoader { get; set; } + [Inject] public IUIFactory UIFactory { get; set; } + [Inject] public CameraStateMachine Camera { get; set; } + [Inject] public ICameraFactory CameraFactory { get; set; } + [Inject] public IAudioService AudioService { get; set; } + [Inject] public IAudioFactory AudioFactory { get; set; } + [Inject] public IInputService InputService { get; set; } + [Inject] public IVolumeService VolumeService { get; set; } + [Inject] public IParticleLoader ParticleLoader { get; set; } + public AppStateMachine StateMachine { get; set; } + } + + [Generators.StateMachine(typeof(AppStateMachineContext),typeof(AppStates))] + public partial class AppStateMachine + { + + } + +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/App/AppStateMachine.cs.meta b/Assets/Code/Infrastructure/App/AppStateMachine.cs.meta new file mode 100644 index 00000000..605294e7 --- /dev/null +++ b/Assets/Code/Infrastructure/App/AppStateMachine.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5627248405434f028be921cb7916f823 +timeCreated: 1765572329 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio.meta b/Assets/Code/Infrastructure/Audio.meta new file mode 100644 index 00000000..2f4268c8 --- /dev/null +++ b/Assets/Code/Infrastructure/Audio.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cc39950ba97e90dc09676d793e810207 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Code/Infrastructure/Audio/AudioFactory.cs b/Assets/Code/Infrastructure/Audio/AudioFactory.cs new file mode 100644 index 00000000..25a67e3f --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioFactory.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using Code.Infrastructure.Configs; +using Code.Infrastructure.Utils; +using Cysharp.Threading.Tasks; +using UnityEngine.AddressableAssets; +using UnityEngine.ResourceManagement.AsyncOperations; + +namespace Code.Infrastructure.Audio +{ + public interface IAudioFactory + { + void UnloadAudioClips(AudioPartition groupPartition); + UniTask LoadAudioClips(AudioPartition groupPartition); + public Dictionary> ReferenceDictionary { get; } + } + + public interface IAudioFactoryInitializer + { + UniTask LoadConfigs(); + } + + public class AudioFactory : IAudioFactory, IDisposable, IAudioFactoryInitializer + { + private string _label; + private AsyncOperationHandle> _configsHandle; + + public Dictionary> ReferenceDictionary { get; } = new(); + + public AudioFactory(IConfigLocator configLocator) + { + _label = configLocator.TryGetManyConfigAssetReferences(); + + } + + public async UniTask LoadConfigs() + { + if(!await AddressablesUtilities.CheckLabelExists(_label)) return; + + _configsHandle = Addressables.LoadAssetsAsync(_label); + + await _configsHandle.ToUniTask(); + + foreach (AudioInfoConfig config in _configsHandle.Result) + { + if(!ReferenceDictionary.ContainsKey(config.GroupPartition)) + ReferenceDictionary.Add(config.GroupPartition, new()); + ReferenceDictionary[config.GroupPartition].Add(config.id, config.Reference); + } + } + + public async UniTask LoadAudioClips(AudioPartition groupPartition) + { + foreach (var reference in ReferenceDictionary[groupPartition]) + { + var load = reference.Value.Load(); + if (load.Status == UniTaskStatus.Pending) + await load; + } + } + + public void UnloadAudioClips(AudioPartition groupPartition) + { + foreach (var reference in ReferenceDictionary[groupPartition]) + { + reference.Value.Unload(); + } + } + public void Dispose() + { + foreach (var partition in ReferenceDictionary) + { + foreach (var reference in partition.Value) + { + reference.Value.Unload(); + } + } + + if(_configsHandle.IsValid()) _configsHandle.Release(); + } + } + +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioFactory.cs.meta b/Assets/Code/Infrastructure/Audio/AudioFactory.cs.meta new file mode 100644 index 00000000..81da7af9 --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioFactory.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cc45c23918ed446681564b467668304b +timeCreated: 1769344269 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioInfo.cs b/Assets/Code/Infrastructure/Audio/AudioInfo.cs new file mode 100644 index 00000000..50557eff --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioInfo.cs @@ -0,0 +1,131 @@ +using System; +using Cysharp.Threading.Tasks; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.ResourceManagement.AsyncOperations; +using Random = UnityEngine.Random; + +namespace Code.Infrastructure.Audio +{ + [Serializable] + public abstract class AudioReference + { + public abstract UniTask Load(); + public abstract void Unload(); + } + + [Serializable] + public class AudioReferenceLODed : AudioReference + { + private AsyncOperationHandle _interiorClipHandle; + private AsyncOperationHandle _closeClipHandle; + private AsyncOperationHandle _distantClipHandle; + private AsyncOperationHandle _farClipHandle; + + public override async UniTask Load() + { + if (_interiorClipHandle.IsValid()) return; + + _interiorClipHandle = Addressables.LoadAssetAsync(interior); + _closeClipHandle = Addressables.LoadAssetAsync(close); + _distantClipHandle = Addressables.LoadAssetAsync(distant); + _farClipHandle = Addressables.LoadAssetAsync(far); + + await UniTask.WhenAll( + _interiorClipHandle.ToUniTask(), + _closeClipHandle.ToUniTask(), + _distantClipHandle.ToUniTask(), + _farClipHandle.ToUniTask() + ); + + Interior = _interiorClipHandle.Result; + Close = _closeClipHandle.Result; + Distant = _distantClipHandle.Result; + Far = _farClipHandle.Result; + } + + public override void Unload() + { + if (!_interiorClipHandle.IsValid()) return; + + _interiorClipHandle.Release(); + _closeClipHandle.Release(); + _distantClipHandle.Release(); + _farClipHandle.Release(); + + Interior = null; + Close = null; + Distant = null; + Far = null; + } + + [SerializeField] private AssetReference interior; + [SerializeField] private AssetReference close; + [SerializeField] private AssetReference distant; + [SerializeField] private AssetReference far; + + public AudioClip Interior { get; private set; } + public AudioClip Close { get; private set; } + public AudioClip Distant { get; private set; } + public AudioClip Far { get; private set; } + } + + [Serializable] + public class AudioReferenceSingle : AudioReference + { + private AsyncOperationHandle _clipHandle; + + public override async UniTask Load() + { + if (_clipHandle.IsValid()) return; + + _clipHandle = Addressables.LoadAssetAsync(clip); + + await _clipHandle.ToUniTask(); + + Clip = _clipHandle.Result; + } + + public override void Unload() + { + if (!_clipHandle.IsValid()) return; + + _clipHandle.Release(); + + Clip = null; + } + + [SerializeField] private AssetReference clip; + + public AudioClip Clip { get; private set; } + } + [Serializable] + public class AudioReferenceRandom : AudioReference + { + private AsyncOperationHandle[] _clipHandles; + + public override async UniTask Load() + { + if (_clipHandles != null) return; + + _clipHandles = new AsyncOperationHandle[clips.Length]; + + for (var i = 0; i < clips.Length; i++) + { + _clipHandles[i] = Addressables.LoadAssetAsync(clips[i]); + await _clipHandles[i].ToUniTask(); + } + } + + public override void Unload() + { + if (_clipHandles == null) return; + + for (var i = 0; i < clips.Length; i++) Addressables.Release(_clipHandles[i]); + } + + [SerializeField] private AssetReference[] clips; + + public AudioClip Clip => _clipHandles[Random.Range(0, _clipHandles.Length)].Result; + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioInfo.cs.meta b/Assets/Code/Infrastructure/Audio/AudioInfo.cs.meta new file mode 100644 index 00000000..8f18ead7 --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioInfo.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e4423af0d471f60ef89f8df279e82af2 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioInfoConfig.cs b/Assets/Code/Infrastructure/Audio/AudioInfoConfig.cs new file mode 100644 index 00000000..94ef1060 --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioInfoConfig.cs @@ -0,0 +1,14 @@ +using Code.Infrastructure.Generators; +using UnityEngine; + +namespace Code.Infrastructure.Audio +{ + [Config("Configs/Audio/AudioInfo", true, true)] + public abstract class AudioInfoConfig : ScriptableObject + { + public AudioPartition GroupPartition; + public int id; + + public abstract AudioReference Reference { get; } + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioInfoConfig.cs.meta b/Assets/Code/Infrastructure/Audio/AudioInfoConfig.cs.meta new file mode 100644 index 00000000..f61f9702 --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioInfoConfig.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 24ed33a7f788429eb32b93b79fcb84bd +timeCreated: 1785871082 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioInfoLODedConfig.cs b/Assets/Code/Infrastructure/Audio/AudioInfoLODedConfig.cs new file mode 100644 index 00000000..57ac00a6 --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioInfoLODedConfig.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +namespace Code.Infrastructure.Audio +{ + [CreateAssetMenu(fileName = "AudioInfoLODed", menuName = "Configs/Audio/AudioInfoLODed")] + public class AudioInfoLODedConfig : AudioInfoConfig + { + public AudioReferenceLODed reference; + public override AudioReference Reference => reference; + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioInfoLODedConfig.cs.meta b/Assets/Code/Infrastructure/Audio/AudioInfoLODedConfig.cs.meta new file mode 100644 index 00000000..d7a7d4a5 --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioInfoLODedConfig.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 97e55393d63f871ac8472894d1d9f627 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioInfoRandomConfig.cs b/Assets/Code/Infrastructure/Audio/AudioInfoRandomConfig.cs new file mode 100644 index 00000000..3cd718b4 --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioInfoRandomConfig.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +namespace Code.Infrastructure.Audio +{ + [CreateAssetMenu(fileName = "AudioInfoRandom", menuName = "Configs/Audio/AudioInfoRandom")] + public class AudioInfoRandomConfig : AudioInfoConfig + { + public AudioReferenceRandom reference; + public override AudioReference Reference => reference; + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioInfoRandomConfig.cs.meta b/Assets/Code/Infrastructure/Audio/AudioInfoRandomConfig.cs.meta new file mode 100644 index 00000000..6d053a81 --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioInfoRandomConfig.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: fb3ca31ee67afb7818583cdd1dc6a43d \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioInfoSingleConfig.cs b/Assets/Code/Infrastructure/Audio/AudioInfoSingleConfig.cs new file mode 100644 index 00000000..107da1e9 --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioInfoSingleConfig.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +namespace Code.Infrastructure.Audio +{ + [CreateAssetMenu(fileName = "AudioInfoSingle", menuName = "Configs/Audio/AudioInfoSingle")] + public class AudioInfoSingleConfig : AudioInfoConfig + { + public AudioReferenceSingle reference; + public override AudioReference Reference => reference; + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioInfoSingleConfig.cs.meta b/Assets/Code/Infrastructure/Audio/AudioInfoSingleConfig.cs.meta new file mode 100644 index 00000000..445e26c5 --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioInfoSingleConfig.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c3a6a54ee0524ae96905e8f5293922fd \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioMixerSettings.cs b/Assets/Code/Infrastructure/Audio/AudioMixerSettings.cs new file mode 100644 index 00000000..a1fca7f0 --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioMixerSettings.cs @@ -0,0 +1,13 @@ +using Code.Infrastructure.Generators; +using UnityEngine; +using UnityEngine.Audio; + +namespace Code.Infrastructure.Audio +{ + [Config("Configs/Audio/AudioMixer")] + [CreateAssetMenu(fileName = "AudioMixerSettings", menuName = "Configs/Audio/AudioMixer")] + public class AudioMixerSettings : ScriptableObject + { + public AudioMixer mixerAsset; + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioMixerSettings.cs.meta b/Assets/Code/Infrastructure/Audio/AudioMixerSettings.cs.meta new file mode 100644 index 00000000..0573a689 --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioMixerSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 89e2ff4d31a24b78b40d9c4e20e1f1bc +timeCreated: 1785871073 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioService.cs b/Assets/Code/Infrastructure/Audio/AudioService.cs new file mode 100644 index 00000000..1d9ad4f9 --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioService.cs @@ -0,0 +1,366 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using Code.Infrastructure.Configs; +using Cysharp.Threading.Tasks; +using LitMotion; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.Audio; + +namespace Code.Infrastructure.Audio +{ + public interface IAudioService + { + UniTaskVoid PlayOneShot(AudioPartition groupPartition, int id, AudioGroupType audioGroupType, + Vector3 position = new Vector3(), + AudioSourceType sourceType = AudioSourceType.NoBlend, + AudioSource audioSource = null, bool isLOD = false); + + UniTaskVoid PlayRepeatedly(AudioPartition groupPartition, int id, AudioGroupType audioGroupType, + Vector3 position = new Vector3(), + AudioSourceType sourceType = AudioSourceType.NoBlend, AudioSource audioSource = null, + CancellationTokenSource cancellationTokenSource = null); + + void CancelMusic(AudioPartition groupPartition, int id); + void ReleaseCancellationSource(AudioPartition groupPartition, int id); + + UniTask ApplyParameter(string effectName, float value, float time, Action callback = null, + CancellationTokenSource cts = null); + + UniTask ChangeGroupVolume(AudioGroupType groupType, float value, float time, Action callback = null, + CancellationTokenSource cts = null); + + void SetAudioListener(AudioListener listener); + + UniTaskVoid PlayRepeatedly(AudioPartition groupPartition, int id, AudioGroupType audioGroupType, + Transform parent, + AudioSourceType sourceType = AudioSourceType.NoBlend, AudioSource audioSource = null, + CancellationTokenSource cancellationTokenSource = null); + + UniTaskVoid PlayOneShot(AudioPartition groupPartition, int id, AudioGroupType audioGroupType, + Transform parent, + AudioSourceType sourceType = AudioSourceType.NoBlend, + AudioSource audioSource = null); + } + + public interface IAudioServiceInitializer + { + UniTask LoadMixerAsset(); + } + + public partial class AudioService : IAudioService, IAudioServiceInitializer + { + private IAudioFactory _audioFactory; + private IAudioSourcePool _pool; + private AudioMixer _mixer; + private AudioListener _listener; + private Dictionary _audioMixerGroups = new(); + + public AudioService(IAudioFactory audioFactory, IAudioSourcePool pool, + IConfigLocator configLocator) + { + _audioFactory = audioFactory; + _pool = pool; + + _mixerConfig = configLocator.TryGetConfigAssetReference(); + } + + public void SetAudioListener(AudioListener listener) + { + if(_listener) + _listener.enabled = false; + + _listener = listener; + _listener.enabled = true; + } + private partial void InitializeMixer(); + + public async UniTask LoadMixerAsset() + { + var audioMixer = await Addressables.LoadAssetAsync(_mixerConfig); + + _mixer = audioMixer.mixerAsset; + + InitializeMixer(); + } + + public async UniTaskVoid PlayOneShot(AudioPartition groupPartition, int id, AudioGroupType audioGroupType, + Vector3 position = new Vector3(), + AudioSourceType sourceType = AudioSourceType.NoBlend, + AudioSource audioSource = null, bool isLOD = false) + { + if (!CheckClip(groupPartition, id)) return; + + if (!audioSource) audioSource = _pool.GetSource(sourceType); + + audioSource.transform.position = position; + audioSource.outputAudioMixerGroup = _audioMixerGroups[audioGroupType]; + + if (sourceType == AudioSourceType.NoBlend) + audioSource.PlayOneShot(GetSingleClip(groupPartition, id)); + if (sourceType == AudioSourceType.Full3D) + { + audioSource.PlayOneShot(isLOD + ? GetLODClip(groupPartition, id, GetLODLevelOnPosition(position)) + : GetSingleClip(groupPartition, id)); + } + + await UniTask.NextFrame(); + await UniTask.WaitUntilValueChanged(audioSource, _ => !audioSource.isPlaying); + + _pool.ReleaseSource(audioSource); + } + + public async UniTaskVoid PlayOneShot(AudioPartition groupPartition, int id, AudioGroupType audioGroupType, + Transform parent, + AudioSourceType sourceType = AudioSourceType.NoBlend, + AudioSource audioSource = null) + { + if (!CheckClip(groupPartition, id)) return; + + if (!audioSource) audioSource = _pool.GetSource(sourceType); + + audioSource.GetComponent().FollowTarget = parent; + + audioSource.outputAudioMixerGroup = _audioMixerGroups[audioGroupType]; + + if (sourceType == AudioSourceType.NoBlend) + audioSource.PlayOneShot(GetSingleClip(groupPartition, id)); + if (sourceType == AudioSourceType.Full3D) + audioSource.PlayOneShot(GetLODClip(groupPartition, id, GetLODLevelOnPosition(parent.position))); + + await UniTask.NextFrame(); + await UniTask.WaitUntilValueChanged(audioSource, _ => !audioSource.isPlaying); + + _pool.ReleaseSource(audioSource); + } + private Dictionary _cancellationTokenSources = new(); + private AssetReference _mixerConfig; + + public void CancelMusic(AudioPartition groupPartition, int id) + { + var key = new AudioPartitionIdPair(groupPartition, id); + + if (!_cancellationTokenSources.ContainsKey(key)) return; + + _cancellationTokenSources[key].Cancel(); + _cancellationTokenSources[key].Dispose(); + _cancellationTokenSources.Remove(key); + } + + public void ReleaseCancellationSource(AudioPartition groupPartition, int id) + { + _cancellationTokenSources.Remove(new AudioPartitionIdPair(groupPartition, id)); + } + + public async UniTaskVoid PlayRepeatedly(AudioPartition groupPartition, int id, AudioGroupType audioGroupType, + Vector3 position = new(), + AudioSourceType sourceType = AudioSourceType.NoBlend, AudioSource audioSource = null, + CancellationTokenSource cancellationTokenSource = null) + { + if (!CheckClip(groupPartition, id)) return; + + if (cancellationTokenSource == null) + { + cancellationTokenSource = new CancellationTokenSource(); + _cancellationTokenSources[new AudioPartitionIdPair(groupPartition, id)] = cancellationTokenSource; + } + + if (!audioSource) audioSource = _pool.GetSource(sourceType); + + if (!audioSource.resource) + { + if (sourceType == AudioSourceType.NoBlend) + audioSource.resource = GetSingleClip(groupPartition, id); + if (sourceType == AudioSourceType.Full3D) + audioSource.resource = GetLODClip(groupPartition, id, GetLODLevelOnPosition(position)); + } + + audioSource.outputAudioMixerGroup = _audioMixerGroups[audioGroupType]; + audioSource.Play(); + + var (isCanceled, _) = await UniTask.WaitUntilValueChanged(audioSource, + _ => !audioSource.isPlaying, + cancellationToken: cancellationTokenSource.Token).SuppressCancellationThrow(); + + if (isCanceled) + { + cancellationTokenSource.Dispose(); + + _pool.ReleaseSource(audioSource); + + ReleaseCancellationSource(groupPartition, id); + + return; + } + + PlayRepeatedly(groupPartition, id, AudioGroupType.Music, position, sourceType, audioSource, + cancellationTokenSource) + .Forget(); + } + + public async UniTaskVoid PlayRepeatedly(AudioPartition groupPartition, int id, AudioGroupType audioGroupType, + Transform parent, + AudioSourceType sourceType = AudioSourceType.NoBlend, AudioSource audioSource = null, + CancellationTokenSource cancellationTokenSource = null) + { + if (!CheckClip(groupPartition, id)) return; + + if (cancellationTokenSource == null) + { + cancellationTokenSource = new CancellationTokenSource(); + _cancellationTokenSources[new AudioPartitionIdPair(groupPartition, id)] = cancellationTokenSource; + } + + if (!audioSource) + { + audioSource = _pool.GetSource(sourceType); + audioSource.GetComponent().FollowTarget = parent; + } + + if (!audioSource.resource) + { + if (sourceType == AudioSourceType.NoBlend) + audioSource.resource = GetSingleClip(groupPartition, id); + if (sourceType == AudioSourceType.Full3D) + audioSource.resource = GetLODClip(groupPartition, id, GetLODLevelOnPosition(parent.position)); + } + + audioSource.outputAudioMixerGroup = _audioMixerGroups[audioGroupType]; + audioSource.Play(); + + var (isCanceled, _) = await UniTask.WaitUntilValueChanged(audioSource, + _ => !audioSource.isPlaying, + cancellationToken: cancellationTokenSource.Token).SuppressCancellationThrow(); + + if (isCanceled) + { + cancellationTokenSource.Dispose(); + + _pool.ReleaseSource(audioSource); + + ReleaseCancellationSource(groupPartition, id); + + return; + } + + PlayRepeatedly(groupPartition, id, AudioGroupType.Music, parent, sourceType, audioSource, + cancellationTokenSource) + .Forget(); + } + private AudioLODLevel GetLODLevelOnPosition(Vector3 position) + { + var distance = Vector3.Distance(position, _listener.transform.position); + AudioLODLevel lodLevel; + if (distance < 5f) lodLevel = AudioLODLevel.Interior; + else if (distance < 20f) lodLevel = AudioLODLevel.Close; + else if (distance < 50f) lodLevel = AudioLODLevel.Distant; + else lodLevel = AudioLODLevel.Far; + return lodLevel; + } + public AudioClip GetSingleClip(AudioPartition groupPartition, int id) + { + var reference = _audioFactory.ReferenceDictionary[groupPartition][id]; + var asSingle = reference as AudioReferenceSingle; + + if(asSingle != null) return asSingle.Clip; + return ((AudioReferenceRandom)reference).Clip; + } + + public AudioClip GetLODClip(AudioPartition groupPartition, int id, AudioLODLevel lodLevel) + { + switch (lodLevel) + { + case AudioLODLevel.Interior: + return ((AudioReferenceLODed)_audioFactory.ReferenceDictionary[groupPartition][id]).Interior; + case AudioLODLevel.Close: + return ((AudioReferenceLODed)_audioFactory.ReferenceDictionary[groupPartition][id]).Close; + case AudioLODLevel.Distant: + return ((AudioReferenceLODed)_audioFactory.ReferenceDictionary[groupPartition][id]).Distant; + case AudioLODLevel.Far: + return ((AudioReferenceLODed)_audioFactory.ReferenceDictionary[groupPartition][id]).Far; + } + + return null; + } + + public bool CheckClip(AudioPartition groupPartition, int id) + { + return _audioFactory.ReferenceDictionary.ContainsKey(groupPartition) + && _audioFactory.ReferenceDictionary[groupPartition].ContainsKey(id); + } + + public async UniTask ApplyParameter(string effectName, + float value, + float time, + Action callback = null, + CancellationTokenSource cts = null) + { + _mixer.GetFloat(effectName, out float startValue); + if (time == 0f) _mixer.SetFloat(effectName, value); + else + { + // TODO Проверить отмену + if (cts != null) + await LMotion.Create(startValue, value, time) + .WithOnComplete(callback) + .WithOnCancel(() => _mixer.SetFloat(effectName, value)) + .Bind(x => _mixer.SetFloat(effectName, x)) + .ToUniTask(cts.Token); + else + await LMotion.Create(startValue, value, time) + .WithOnComplete(callback) + .WithOnCancel(() => _mixer.SetFloat(effectName, value)) + .Bind(x => _mixer.SetFloat(effectName, x)) + .ToUniTask(); + } + } + + private Dictionary _volumeCancellationSources = new(); + + // TODO Очередь принятия параметров + public async UniTask ChangeGroupVolume( + AudioGroupType groupType, + float value, + float time, + Action callback = null, + CancellationTokenSource cts = null) + { + if (_volumeCancellationSources.ContainsKey(groupType)) _volumeCancellationSources[groupType].Cancel(); + + _volumeCancellationSources[groupType] = cts ?? new CancellationTokenSource(); + + await ApplyParameter(_audioMixerGroups[groupType].name, Mathf.Log10(value == 0f ? 0.001f : value) * 20, + time, + callback, cts); + } + } + + public struct AudioPartitionIdPair : IEquatable + { + public AudioPartition AudioPartition; + public int ID; + + public AudioPartitionIdPair(AudioPartition audioPartition, int id) + { + AudioPartition = audioPartition; + ID = id; + } + + public bool Equals(AudioPartitionIdPair other) + { + return AudioPartition == other.AudioPartition && ID == other.ID; + } + + public override bool Equals(object obj) + { + return obj is AudioPartitionIdPair other && Equals(other); + } + + public override int GetHashCode() + { + return HashCode.Combine((int)AudioPartition, ID); + } + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioService.cs.meta b/Assets/Code/Infrastructure/Audio/AudioService.cs.meta new file mode 100644 index 00000000..19a52604 --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioService.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e8426c9e925a431aa73069c49d6a71c0 +timeCreated: 1769446252 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioSourceFollower.cs b/Assets/Code/Infrastructure/Audio/AudioSourceFollower.cs new file mode 100644 index 00000000..a2f54e9c --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioSourceFollower.cs @@ -0,0 +1,15 @@ +using System; +using UnityEngine; + +namespace Code.Infrastructure.Audio +{ + public class AudioSourceFollower : MonoBehaviour + { + [NonSerialized] + public Transform FollowTarget; + private void Update() + { + if(FollowTarget) transform.SetPositionAndRotation(FollowTarget.position, FollowTarget.rotation); + } + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioSourceFollower.cs.meta b/Assets/Code/Infrastructure/Audio/AudioSourceFollower.cs.meta new file mode 100644 index 00000000..dd5c7054 --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioSourceFollower.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7f6debe328864a5a88509519354fcfc7 +timeCreated: 1776704631 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioSourcePool.cs b/Assets/Code/Infrastructure/Audio/AudioSourcePool.cs new file mode 100644 index 00000000..a4ebdb6c --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioSourcePool.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Code.Infrastructure.Configs; +using Cysharp.Threading.Tasks; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.Pool; +using UnityEngine.ResourceManagement.AsyncOperations; +using Object = UnityEngine.Object; + +namespace Code.Infrastructure.Audio +{ + public interface IAudioSourcePoolInitializer + { + UniTask LoadConfigs(); + } + + public interface IAudioSourcePool + { + AudioSource GetSource(AudioSourceType sourceType); + void ReleaseSource(AudioSource source); + } + + public class AudioSourcePool : IAudioSourcePool, IAudioSourcePoolInitializer, IDisposable + { + // The pool holds plain GameObjects (you can swap this for any component type). + private IObjectPool _pool; + private GameObject _sourcePrefab; + + private Dictionary _settings; + + private string _configsLabel; + private AsyncOperationHandle> _handles; + private AssetReference _sourcePrefabConfigReference; + private AsyncOperationHandle _prefabConfigHandle; + private AsyncOperationHandle _prefabHandle; + + public AudioSourcePool(IConfigLocator configLocator) + { + _configsLabel = configLocator.TryGetManyConfigAssetReferences(); + _sourcePrefabConfigReference = configLocator.TryGetConfigAssetReference(); + } + + public async UniTask LoadConfigs() + { + _prefabConfigHandle = Addressables.LoadAssetAsync(_sourcePrefabConfigReference); + _handles = Addressables.LoadAssetsAsync(_configsLabel); + + await UniTask.WhenAll( + _prefabConfigHandle.ToUniTask(), + _handles.ToUniTask()); + + _prefabHandle = Addressables.LoadAssetAsync(_prefabConfigHandle.Result.sourcePrefab); + + _settings = _handles.Result.ToDictionary(x => x.sourceType); + + await _prefabHandle.ToUniTask(); + + _pool = new ObjectPool( + createFunc: CreateItem, + // actionOnGet: OnGet, + actionOnRelease: OnRelease, + actionOnDestroy: OnDestroyItem, + collectionCheck: true, // helps catch double-release mistakes + defaultCapacity: 10, + maxSize: 20 + ); + } + + // Creates a new pooled GameObject the first time (and whenever the pool needs more). + private AudioSource CreateItem() + { + var audioSource = Object.Instantiate(_prefabHandle.Result).GetComponent(); + audioSource.name = "PooledAudioSource"; + Object.DontDestroyOnLoad(audioSource); + return audioSource; + } + + // Called when an item is taken from the pool. + private void OnGet(AudioSource source) + { + //source.gameObject.SetActive(true); + } + + // Called when an item is returned to the pool. + private void OnRelease(AudioSource source) + { + if (!source) return; + + source.Stop(); + source.resource = null; + source.GetComponent().FollowTarget = null; + //source.gameObject.SetActive(false); + } + + // Called when the pool decides to destroy an item (e.g., above max size). + private void OnDestroyItem(AudioSource source) + { + Object.Destroy(source.gameObject); + } + + public AudioSource GetSource(AudioSourceType sourceType) + { + var source = _pool.Get(); + + source.spatialBlend = _settings[sourceType].spatialBlend; + + return source; + } + + public void ReleaseSource(AudioSource source) => _pool.Release(source); + + public void Dispose() + { + Addressables.Release(_handles); + Addressables.Release(_prefabConfigHandle); + if (_sourcePrefab) Addressables.Release(_sourcePrefab); + } + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioSourcePool.cs.meta b/Assets/Code/Infrastructure/Audio/AudioSourcePool.cs.meta new file mode 100644 index 00000000..3cfdb3ea --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioSourcePool.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 246ae406fabc4ca791673d3f38cfe1c5 +timeCreated: 1769448041 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioSourcePrefab.cs b/Assets/Code/Infrastructure/Audio/AudioSourcePrefab.cs new file mode 100644 index 00000000..220e319d --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioSourcePrefab.cs @@ -0,0 +1,13 @@ +using Code.Infrastructure.Generators; +using UnityEngine; +using UnityEngine.AddressableAssets; + +namespace Code.Infrastructure.Audio +{ + [Config("Configs/Audio/AudioSourcePrefab")] + [CreateAssetMenu(fileName = "AudioSourcePrefab", menuName = "Configs/Audio/AudioSourcePrefab")] + public partial class AudioSourcePrefab : ScriptableObject + { + public AssetReference sourcePrefab; + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioSourcePrefab.cs.meta b/Assets/Code/Infrastructure/Audio/AudioSourcePrefab.cs.meta new file mode 100644 index 00000000..5757f02e --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioSourcePrefab.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9e812cfdf0544504b47cfe48b621ac4e +timeCreated: 1785852790 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioSourceSettings.cs b/Assets/Code/Infrastructure/Audio/AudioSourceSettings.cs new file mode 100644 index 00000000..f1c84437 --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioSourceSettings.cs @@ -0,0 +1,15 @@ +using Code.Infrastructure.Generators; +using UnityEngine; + +namespace Code.Infrastructure.Audio +{ + [CreateAssetMenu(fileName = "AudioSourceSettings", menuName = "Configs/Audio/AudioSourceSettings")] + [Config("Configs/Audio/AudioSourceSettings", true)] + public class AudioSourceSettings : ScriptableObject + { + // Дополнять по мере необходимости + public float spatialBlend; + + public AudioSourceType sourceType; + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Audio/AudioSourceSettings.cs.meta b/Assets/Code/Infrastructure/Audio/AudioSourceSettings.cs.meta new file mode 100644 index 00000000..8430f34b --- /dev/null +++ b/Assets/Code/Infrastructure/Audio/AudioSourceSettings.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: fdbfd61d34d228d088f8be38588cd571 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Camera.meta b/Assets/Code/Infrastructure/Camera.meta new file mode 100644 index 00000000..b1217f29 --- /dev/null +++ b/Assets/Code/Infrastructure/Camera.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5f30c588256ece023ad9a01d0f51d747 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Code/Infrastructure/Camera/CameraFactory.cs b/Assets/Code/Infrastructure/Camera/CameraFactory.cs new file mode 100644 index 00000000..3d588839 --- /dev/null +++ b/Assets/Code/Infrastructure/Camera/CameraFactory.cs @@ -0,0 +1,68 @@ +using System; +using Code.Infrastructure.Configs; +using Cysharp.Threading.Tasks; +using Unity.VisualScripting; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.Rendering.Universal; +using UnityEngine.ResourceManagement.AsyncOperations; +using Object = UnityEngine.Object; + +namespace Code.Infrastructure.Camera +{ + public interface ICameraFactory + { + UniTask CreateCameraStateMachine(); + void CreateCameraStateMachineRunner(CameraStateMachine cameraStateMachine); + } + + public class CameraFactory : IDisposable, ICameraFactory + { + private AsyncOperationHandle _configHandle; + private GameCamera _config; + private AssetReference _gameCameraConfigReference; + + private UnityEngine.Camera _camera; + + public CameraFactory(IConfigLocator configLocator) + { + _gameCameraConfigReference = configLocator.TryGetConfigAssetReference(); + } + + public async UniTask CreateCameraStateMachine() + { + _configHandle = Addressables.LoadAssetAsync(_gameCameraConfigReference); + await _configHandle.ToUniTask(); + _config = _configHandle.Result; + + var cameraObject = new GameObject { name = "Camera" }; + + cameraObject.AddComponent(); + _camera = cameraObject.AddComponent(); + + var universalCameraData = _camera.GetUniversalAdditionalCameraData(); + universalCameraData.renderPostProcessing = _config.PostProcessing; + + _camera.fieldOfView = _config.FieldOfView; + _camera.nearClipPlane = _config.NearClip; + _camera.farClipPlane = _config.FarClip; + _camera.clearFlags = _config.ClearFlags; + + Object.DontDestroyOnLoad(cameraObject); + + return new CameraStateMachineContext.CameraLoadedData(_camera); + } + + public void CreateCameraStateMachineRunner(CameraStateMachine cameraStateMachine) + { + var runner = _camera.AddComponent(); + runner.SetStateMachine(cameraStateMachine); + } + + public void Dispose() + { + Addressables.Release(_configHandle); + Addressables.ReleaseInstance(_camera.gameObject); + } + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Camera/CameraFactory.cs.meta b/Assets/Code/Infrastructure/Camera/CameraFactory.cs.meta new file mode 100644 index 00000000..d2ac93f9 --- /dev/null +++ b/Assets/Code/Infrastructure/Camera/CameraFactory.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4c05e01628b742be94dfd0bbbdfb87fa +timeCreated: 1767302222 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Camera/CameraStateMachine.cs b/Assets/Code/Infrastructure/Camera/CameraStateMachine.cs new file mode 100644 index 00000000..299b144a --- /dev/null +++ b/Assets/Code/Infrastructure/Camera/CameraStateMachine.cs @@ -0,0 +1,36 @@ +using Code.Infrastructure.Camera.CameraStates; +using Code.Infrastructure.Input; +using Reflex.Attributes; + +namespace Code.Infrastructure.Camera +{ + public enum CameraMode + { + None, + Cleaner + } + + public class CameraStateMachineContext + { + public class CameraLoadedData + { + public UnityEngine.Camera Camera; + + public CameraLoadedData(UnityEngine.Camera camera) + { + Camera = camera; + } + } + public CameraLoadedData cameraLoadedData; + [Inject] public IInputService InputService; + } + + [Generators.StateMachine(typeof(CameraStateMachineContext), typeof(CameraMode))] + public partial class CameraStateMachine + { + public UnityEngine.Camera Camera => StateMachineContext.cameraLoadedData.Camera; + + public void Update() => ((BaseCameraState)CurrentBaseState).Update(); + public void LateUpdate() => ((BaseCameraState)CurrentBaseState).LateUpdate(); + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Camera/CameraStateMachine.cs.meta b/Assets/Code/Infrastructure/Camera/CameraStateMachine.cs.meta new file mode 100644 index 00000000..d8c09054 --- /dev/null +++ b/Assets/Code/Infrastructure/Camera/CameraStateMachine.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b220b02510c34ea08257cc951d949fd7 +timeCreated: 1761671720 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Camera/CameraStateMachineRunner.cs b/Assets/Code/Infrastructure/Camera/CameraStateMachineRunner.cs new file mode 100644 index 00000000..80bf14c5 --- /dev/null +++ b/Assets/Code/Infrastructure/Camera/CameraStateMachineRunner.cs @@ -0,0 +1,15 @@ +using UnityEngine; + +namespace Code.Infrastructure.Camera +{ + public class CameraStateMachineRunner : MonoBehaviour + { + private CameraStateMachine _cameraStateMachine; + + public void SetStateMachine(CameraStateMachine cameraStateMachine) => _cameraStateMachine = cameraStateMachine; + + private void Update() => _cameraStateMachine.Update(); + + private void LateUpdate() => _cameraStateMachine.LateUpdate(); + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Camera/CameraStateMachineRunner.cs.meta b/Assets/Code/Infrastructure/Camera/CameraStateMachineRunner.cs.meta new file mode 100644 index 00000000..ab570f55 --- /dev/null +++ b/Assets/Code/Infrastructure/Camera/CameraStateMachineRunner.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fc7c5cfabb3c4d60bb283444a1c9a53b +timeCreated: 1775490818 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Camera/CameraStates.meta b/Assets/Code/Infrastructure/Camera/CameraStates.meta new file mode 100644 index 00000000..b72130ea --- /dev/null +++ b/Assets/Code/Infrastructure/Camera/CameraStates.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d7399e433dff42a185f62d79b546b059 +timeCreated: 1761671908 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Camera/CameraStates/BaseCameraState.cs b/Assets/Code/Infrastructure/Camera/CameraStates/BaseCameraState.cs new file mode 100644 index 00000000..8c204f18 --- /dev/null +++ b/Assets/Code/Infrastructure/Camera/CameraStates/BaseCameraState.cs @@ -0,0 +1,14 @@ +using Code.Infrastructure.StateMachine; + +namespace Code.Infrastructure.Camera.CameraStates +{ + public abstract class BaseCameraState : BaseState + { + protected BaseCameraState(CameraStateMachineContext context) : base(context) + { + } + + public abstract void Update(); + public abstract void LateUpdate(); + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Camera/CameraStates/BaseCameraState.cs.meta b/Assets/Code/Infrastructure/Camera/CameraStates/BaseCameraState.cs.meta new file mode 100644 index 00000000..7a89b52c --- /dev/null +++ b/Assets/Code/Infrastructure/Camera/CameraStates/BaseCameraState.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7901175f2c0646fda8741c4c269ce54b +timeCreated: 1767127681 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Camera/CameraStates/NoneCameraState.cs b/Assets/Code/Infrastructure/Camera/CameraStates/NoneCameraState.cs new file mode 100644 index 00000000..96121a3a --- /dev/null +++ b/Assets/Code/Infrastructure/Camera/CameraStates/NoneCameraState.cs @@ -0,0 +1,22 @@ +using Code.Infrastructure.Generators; + +namespace Code.Infrastructure.Camera.CameraStates +{ + [State(typeof(CameraMode),typeof(CameraStateMachineContext), ManualInherit = true)] + public partial class NoneCameraState : BaseCameraState + { + public NoneCameraState(CameraStateMachineContext context) : base(context) + { + } + + public override CameraMode MyState => CameraMode.None; + + public override void Update() + { + } + + public override void LateUpdate() + { + } + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Camera/CameraStates/NoneCameraState.cs.meta b/Assets/Code/Infrastructure/Camera/CameraStates/NoneCameraState.cs.meta new file mode 100644 index 00000000..1ccd8f48 --- /dev/null +++ b/Assets/Code/Infrastructure/Camera/CameraStates/NoneCameraState.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cb14de48ff13488c8edb4431ac34e5be +timeCreated: 1767301090 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Camera/GameCamera.cs b/Assets/Code/Infrastructure/Camera/GameCamera.cs new file mode 100644 index 00000000..15beece8 --- /dev/null +++ b/Assets/Code/Infrastructure/Camera/GameCamera.cs @@ -0,0 +1,19 @@ +using Code.Infrastructure.Generators; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.Rendering.Universal; + +namespace Code.Infrastructure.Camera +{ + [CreateAssetMenu(fileName = "GameCamera", menuName = "Configs/Camera/CameraConfig")] + [Config("Configs/Camera/CameraConfig")] + public class GameCamera : ScriptableObject + { + public float FieldOfView; + public float NearClip; + public float FarClip; + public bool PostProcessing; + public bool RenderShadows; + public CameraClearFlags ClearFlags; + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Camera/GameCamera.cs.meta b/Assets/Code/Infrastructure/Camera/GameCamera.cs.meta new file mode 100644 index 00000000..4073f36a --- /dev/null +++ b/Assets/Code/Infrastructure/Camera/GameCamera.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8bbd78d2335f4e55945f1e56ff536200 +timeCreated: 1785830560 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Configs.meta b/Assets/Code/Infrastructure/Configs.meta new file mode 100644 index 00000000..39276bad --- /dev/null +++ b/Assets/Code/Infrastructure/Configs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 89adaad2de8d3daf1858a612b6dbedea +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Code/Infrastructure/Configs/ConfigLocator.cs b/Assets/Code/Infrastructure/Configs/ConfigLocator.cs new file mode 100644 index 00000000..e8a96274 --- /dev/null +++ b/Assets/Code/Infrastructure/Configs/ConfigLocator.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.AddressableAssets; + +namespace Code.Infrastructure.Configs +{ + public interface IConfigLocator + { + AssetReference TryGetConfigAssetReference(); + string TryGetManyConfigAssetReferences(); + } + public partial class ConfigLocator : IConfigLocator + { + private readonly Dictionary _singleConfigReferences = new(); + private readonly Dictionary _multipleConfigReferences = new(); + + private ConfigReferences _configReferences; + + public AssetReference TryGetConfigAssetReference() => _singleConfigReferences.GetValueOrDefault(typeof(T), null); + public string TryGetManyConfigAssetReferences() => _multipleConfigReferences.GetValueOrDefault(typeof(T), null); + + partial void LoadConfigs(); + + public ConfigLocator() + { + LoadConfigReferences(); + + LoadConfigs(); + } + + private void LoadConfigReferences() + { + _configReferences = Resources.Load("ConfigReferences"); + } + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Configs/ConfigLocator.cs.meta b/Assets/Code/Infrastructure/Configs/ConfigLocator.cs.meta new file mode 100644 index 00000000..4d168790 --- /dev/null +++ b/Assets/Code/Infrastructure/Configs/ConfigLocator.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 23ccbd5d4d27ba1bdadaa94c0b564ff9 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Configs/ConfigReferences.cs b/Assets/Code/Infrastructure/Configs/ConfigReferences.cs new file mode 100644 index 00000000..7fa9c298 --- /dev/null +++ b/Assets/Code/Infrastructure/Configs/ConfigReferences.cs @@ -0,0 +1,9 @@ +using UnityEngine; + +namespace Code.Infrastructure.Configs +{ + [CreateAssetMenu(fileName = "ConfigReferences", menuName = "Configs/ConfigReferences")] + public partial class ConfigReferences : ScriptableObject + { + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Configs/ConfigReferences.cs.meta b/Assets/Code/Infrastructure/Configs/ConfigReferences.cs.meta new file mode 100644 index 00000000..ed8e015e --- /dev/null +++ b/Assets/Code/Infrastructure/Configs/ConfigReferences.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 02095449ead629e7490547f6fa161935 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Generators.meta b/Assets/Code/Infrastructure/Generators.meta new file mode 100644 index 00000000..a2e57ff5 --- /dev/null +++ b/Assets/Code/Infrastructure/Generators.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: daf23f61a4d244d5aec0ffcc9b9c8ac4 +timeCreated: 1785767213 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Generators/Attributes.cs b/Assets/Code/Infrastructure/Generators/Attributes.cs new file mode 100644 index 00000000..104b1833 --- /dev/null +++ b/Assets/Code/Infrastructure/Generators/Attributes.cs @@ -0,0 +1,48 @@ +using System; + +namespace Code.Infrastructure.Generators +{ + public class StateMachine : Attribute + { + public Type StateMachineContextType; + public Type StateMachineEnumType; + + public StateMachine(Type stateMachineContextType, Type stateMachineEnumType) + { + StateMachineContextType = stateMachineContextType; + StateMachineEnumType = stateMachineEnumType; + } + } + + public class State : Attribute + { + public Type StateEnum; + public Type StateMachineContext; + public bool ManualInherit; + + public State(Type stateEnum,Type stateMachineContext, bool manualInherit = false) + { + StateEnum = stateEnum; + StateMachineContext = stateMachineContext; + ManualInherit = manualInherit; + } + } + public class Config : Attribute + { + public bool Multiple; + public bool OnlyLocator; + public string MenuName; + public Config(string menuName, bool multiple = false, bool onlyLocator = false) + { + Multiple = multiple; + MenuName = menuName; + OnlyLocator = onlyLocator; + } + } + public class SceneIdEnum : Attribute + { + } + public class AudioMixerEnum : Attribute + { + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Generators/Attributes.cs.meta b/Assets/Code/Infrastructure/Generators/Attributes.cs.meta new file mode 100644 index 00000000..2559cc8f --- /dev/null +++ b/Assets/Code/Infrastructure/Generators/Attributes.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1f1a9e94d27945afad92fd36ee148c7d +timeCreated: 1785767311 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Generators/AudioMixerGenerator.cs b/Assets/Code/Infrastructure/Generators/AudioMixerGenerator.cs new file mode 100644 index 00000000..8a4d8d8b --- /dev/null +++ b/Assets/Code/Infrastructure/Generators/AudioMixerGenerator.cs @@ -0,0 +1,53 @@ +#if UNITY_EDITOR +using UnityCodeGen; +using UnityEditor; + +namespace Code.Infrastructure.Generators +{ + [Generator] + public class AudioMixerGenerator : ICodeGenerator + { + public void Execute(GeneratorContext context) + { + var Enum = TypeCache.GetTypesWithAttribute(); + + var initializedCode = ""; + var serviceCode = ""; + var interfacesUsingsCode = $@" +// using Code.Infrastructure.Audio; +"; + + foreach (var en in Enum) + { + if (!en.IsEnum) return; + + var members = en.GetFields(); + + foreach (var member in members) + { + if (member.FieldType.FullName != en.FullName) continue; + initializedCode += $@" + _audioMixerGroups.Add({en.FullName}.{member.Name}, _mixer.FindMatchingGroups(""{member.Name}"")[0]); + +"; + } + + serviceCode += $@" +#pragma warning disable CS0105 +{interfacesUsingsCode} +#pragma warning restore CS0105 +namespace Code.Infrastructure.Audio{{ +public partial class AudioService + {{ +private partial void InitializeMixer(){{ + {initializedCode} +}} + }} +}}"; + } + + context.AddCode($"AudioMixer.Generated.cs", serviceCode); + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Generators/AudioMixerGenerator.cs.meta b/Assets/Code/Infrastructure/Generators/AudioMixerGenerator.cs.meta new file mode 100644 index 00000000..74bffcea --- /dev/null +++ b/Assets/Code/Infrastructure/Generators/AudioMixerGenerator.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d4380f9fef404347be28b7e95548c008 +timeCreated: 1785767222 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Generators/ConfigGenerator.cs b/Assets/Code/Infrastructure/Generators/ConfigGenerator.cs new file mode 100644 index 00000000..6fe77ab7 --- /dev/null +++ b/Assets/Code/Infrastructure/Generators/ConfigGenerator.cs @@ -0,0 +1,79 @@ +#if UNITY_EDITOR +using System.Linq; +using Unity.VisualScripting; +using UnityCodeGen; +using UnityEditor; + +namespace Code.Infrastructure.Generators +{ + [Generator] + public class ConfigGenerator : ICodeGenerator + { + public void Execute(GeneratorContext context) + { + var configs = TypeCache.GetTypesWithAttribute(); + + var configsCode = ""; + var configAddCode = ""; + var configReferencesCode = ""; + var configReferencesUsingsCode = ""; + var configOfConfigsCode = ""; + + foreach (var cfg in configs.OrderByDescending(o => o.Name)) + { + var attribute = cfg.GetAttribute(); + + configReferencesUsingsCode += $"using {cfg.Namespace};\n"; + + if (attribute.Multiple) + { + configReferencesCode += $"public string {cfg.Name};\n"; + configAddCode += $@" + _multipleConfigReferences.Add(typeof({cfg.FullName}), _configReferences.{cfg.Name}); +"; + } + else + { + configReferencesCode += $"public AssetReference {cfg.Name};\n"; + configAddCode += $@" + _singleConfigReferences.Add(typeof({cfg.FullName}), _configReferences.{cfg.Name}); +"; + } + } + configsCode += $@" +#pragma warning disable CS0105 + {configReferencesUsingsCode} +#pragma warning restore CS0105 + + namespace Code.Infrastructure.Configs + {{ + + public partial class ConfigLocator + {{ + partial void LoadConfigs() + {{ + {configAddCode} + }} + }} + }} + "; + context.AddCode($"ConfigLocator.Generated.cs", configsCode); + + configOfConfigsCode += $@" +#pragma warning disable CS0105 + {configReferencesUsingsCode} + using UnityEngine.AddressableAssets; +#pragma warning restore CS0105 + + namespace Code.Infrastructure.Configs{{ + public partial class ConfigReferences + {{ + {configReferencesCode} + }} +}} +"; + context.AddCode($"ConfigReferences.Generated.cs", configOfConfigsCode); + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Generators/ConfigGenerator.cs.meta b/Assets/Code/Infrastructure/Generators/ConfigGenerator.cs.meta new file mode 100644 index 00000000..96cdc423 --- /dev/null +++ b/Assets/Code/Infrastructure/Generators/ConfigGenerator.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4dd23f7e41734b9d86b74032d5f7f71d +timeCreated: 1785767609 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Generators/StateMachineGenerator.cs b/Assets/Code/Infrastructure/Generators/StateMachineGenerator.cs new file mode 100644 index 00000000..9bc781d9 --- /dev/null +++ b/Assets/Code/Infrastructure/Generators/StateMachineGenerator.cs @@ -0,0 +1,105 @@ +#if UNITY_EDITOR +using System.Linq; +using Unity.VisualScripting; +using UnityCodeGen; +using UnityEditor; + +namespace Code.Infrastructure.Generators +{ + [Generator] + public class StateMachineGenerator : ICodeGenerator + { + public void Execute(GeneratorContext context) + { + GenerateStates(context); + GenerateStateMachine(context); + } + + private void GenerateStateMachine(GeneratorContext context) + { + var stateMachines = TypeCache.GetTypesWithAttribute(); + + foreach (var sm in stateMachines) + { + var attribute = sm.GetAttribute(); + + var states = TypeCache.GetTypesWithAttribute() + .Where(st => + st.GetAttribute().StateMachineContext.FullName == + attribute.StateMachineContextType.FullName); + + var statesCode = ""; + var statesNamespacesCode = ""; + + foreach (var st in states) + { + statesNamespacesCode += $@" +using {st.Namespace}; +"; + statesCode += $@" +var state{st.Name} = new {st.Name}(StateMachineContext); +States.Add(state{st.Name}.MyState, state{st.Name}); +"; + + } + + var stateMachineCode = + $@" +// +#pragma warning disable CS0105 +using Code.Infrastructure.StateMachine; +{statesNamespacesCode} +#pragma warning restore CS0105 +namespace {sm.Namespace} +{{ + +public partial class {sm.Name} : AbstractStateMachine<{attribute.StateMachineEnumType.FullName},{attribute.StateMachineContextType.FullName}> +{{ + + public {sm.Name}({attribute.StateMachineContextType.FullName} context) : base(context) + {{ + {statesCode} + }} +}} +}} + +"; + + context.AddCode($"{sm.FullName}.Generated.cs", stateMachineCode); + } + } + + private void GenerateStates(GeneratorContext context) + { + var states = TypeCache.GetTypesWithAttribute(); + + foreach (var st in states) + { + var attribute = st.GetAttribute(); + + var genetics = ""; + if (!attribute.ManualInherit) + genetics = + $@" : BaseState<{attribute.StateEnum.FullName}, {attribute.StateMachineContext.FullName}>"; + + var statesCode = $@" + +// retard-generated + +using Code.Infrastructure.StateMachine; + +namespace {st.Namespace} +{{ + public partial class {st.Name} {genetics} + {{ + }} +}} +"; + + + context.AddCode($"{st.FullName}.Generated.cs", statesCode); + } + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Generators/StateMachineGenerator.cs.meta b/Assets/Code/Infrastructure/Generators/StateMachineGenerator.cs.meta new file mode 100644 index 00000000..814ce258 --- /dev/null +++ b/Assets/Code/Infrastructure/Generators/StateMachineGenerator.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 20bfbd0b7c5840c8a5f351cff2be58e0 +timeCreated: 1785767485 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Generators/TypeExtensions.cs b/Assets/Code/Infrastructure/Generators/TypeExtensions.cs new file mode 100644 index 00000000..b90612d6 --- /dev/null +++ b/Assets/Code/Infrastructure/Generators/TypeExtensions.cs @@ -0,0 +1,28 @@ +#if UNITY_EDITOR +using System; +using System.Linq; + +namespace Code.Infrastructure.Generators +{ + public static class TypeExtensions + { + public static string GetFriendlyName(this Type type) + { + if (type.IsGenericType) + { + if (type.FullName != null) + { + string name = type.FullName.Split('`')[0]; + + var genericArgs = type.GetGenericArguments() + .Select(t => t.GetFriendlyName()); + + return $"{name}<{string.Join(", ", genericArgs)}>"; + } + } + + return type.FullName ?? type.Name; + } + } +} +#endif \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Generators/TypeExtensions.cs.meta b/Assets/Code/Infrastructure/Generators/TypeExtensions.cs.meta new file mode 100644 index 00000000..4e2169ee --- /dev/null +++ b/Assets/Code/Infrastructure/Generators/TypeExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b9ad74e45abc4260bee92ebe33d28602 +timeCreated: 1785767387 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Input.meta b/Assets/Code/Infrastructure/Input.meta new file mode 100644 index 00000000..7a062ffa --- /dev/null +++ b/Assets/Code/Infrastructure/Input.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bcb18c4105d206e10b66ddcac7f7eee7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Code/Infrastructure/Input/InputService.cs b/Assets/Code/Infrastructure/Input/InputService.cs new file mode 100644 index 00000000..6f95a3d1 --- /dev/null +++ b/Assets/Code/Infrastructure/Input/InputService.cs @@ -0,0 +1,63 @@ +using System; +using Code.Infrastructure.Configs; +using Cysharp.Threading.Tasks; +using UnityEngine.AddressableAssets; +using UnityEngine.InputSystem; +using UnityEngine.ResourceManagement.AsyncOperations; + +namespace Code.Infrastructure.Input +{ + public interface IInputService + { + void EnableMap(ActionMappings actionMap); + void DisableMap(ActionMappings actionMap); + void BindActionPerformed(int mapId, int actionId, Action action); + void BindActionCancelled(int mapId, int actionId, Action action); + void UnbindActionPerformed(int mapId, int actionId, Action action); + void UnbindActionCancelled(int mapId, int actionId, Action action); + } + + public interface IInputServiceInitializer + { + UniTask LoadConfigs(); + } + + public class InputService : IInputService, IInputServiceInitializer + { + private InputActionAsset _inputActionAsset; + + private AsyncOperationHandle _configHandle; + private readonly AssetReference _configReference; + + public InputService(IConfigLocator configLocator) + { + _configReference = configLocator.TryGetConfigAssetReference(); + } + + public async UniTask LoadConfigs() + { + _configHandle = Addressables.LoadAssetAsync(_configReference); + + await _configHandle.ToUniTask(); + + _inputActionAsset = _configHandle.Result.inputActionAsset; + } + + public void EnableMap(ActionMappings actionMap) => _inputActionAsset.actionMaps[(int)actionMap].Enable(); + public void DisableMap(ActionMappings actionMap) => _inputActionAsset.actionMaps[(int)actionMap].Disable(); + + public void BindActionPerformed(int mapId, int actionId, Action action) => _inputActionAsset + .actionMaps[mapId].actions[actionId].performed += action; + + public void BindActionCancelled(int mapId, int actionId, Action action) => _inputActionAsset + .actionMaps[mapId].actions[actionId].canceled += action; + + public void UnbindActionPerformed(int mapId, int actionId, Action action) => + _inputActionAsset + .actionMaps[mapId].actions[actionId].performed -= action; + + public void UnbindActionCancelled(int mapId, int actionId, Action action) => + _inputActionAsset + .actionMaps[mapId].actions[actionId].canceled -= action; + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Input/InputService.cs.meta b/Assets/Code/Infrastructure/Input/InputService.cs.meta new file mode 100644 index 00000000..8bff0dfd --- /dev/null +++ b/Assets/Code/Infrastructure/Input/InputService.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2755e684d68a4f79994f0f92e8327a73 +timeCreated: 1766612399 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Input/InputServiceConfig.cs b/Assets/Code/Infrastructure/Input/InputServiceConfig.cs new file mode 100644 index 00000000..5251e4b8 --- /dev/null +++ b/Assets/Code/Infrastructure/Input/InputServiceConfig.cs @@ -0,0 +1,13 @@ +using Code.Infrastructure.Generators; +using UnityEngine; +using UnityEngine.InputSystem; + +namespace Code.Infrastructure.Input +{ + [Config("Configs/InputService")] + [CreateAssetMenu(fileName = "InputService", menuName = "Configs/InputService")] + public class InputServiceConfig : ScriptableObject + { + public InputActionAsset inputActionAsset; + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Input/InputServiceConfig.cs.meta b/Assets/Code/Infrastructure/Input/InputServiceConfig.cs.meta new file mode 100644 index 00000000..b3d4238c --- /dev/null +++ b/Assets/Code/Infrastructure/Input/InputServiceConfig.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a3fe014c5e7645708654c530a664a11d +timeCreated: 1785871062 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Loadings.meta b/Assets/Code/Infrastructure/Loadings.meta new file mode 100644 index 00000000..73ec5ee9 --- /dev/null +++ b/Assets/Code/Infrastructure/Loadings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3135ae3e535d681ecb827013e589ed05 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Code/Infrastructure/Loadings/Loading.cs b/Assets/Code/Infrastructure/Loadings/Loading.cs new file mode 100644 index 00000000..f7e89f50 --- /dev/null +++ b/Assets/Code/Infrastructure/Loadings/Loading.cs @@ -0,0 +1,104 @@ +using System; +using System.Threading; +using Cysharp.Threading.Tasks; +using UnityEngine; + +namespace Code.Infrastructure.Loadings +{ + public class Loading + { + private int _progress; + public bool Completed { get; private set; } + private Action _completed; + private Action _loadProgress; + + public Loading(int externalMaxProgress, Action completed, Action loadProgress = null) + { + _progress = externalMaxProgress; + MaxProgress = externalMaxProgress; + + _completed = completed; + _loadProgress = loadProgress; + } + /// + /// Получаем текущее значение прогресса + /// + public int CurrentProgress => _progress; + public int MaxProgress { get; private set; } + /// + /// Сдвигаем прогресс загрузки на 1 + /// + public void DoProgress() + { + _progress--; + _loadProgress?.Invoke(this); + + if(_progress == 0) // Зачем инвертировать, если так читается лучше, райдер соси + { + Completed = true; + _completed?.Invoke(); + + _cts?.Dispose(); + } + } + /// + /// Ждём заполнения шкалы прогресса + /// + public async UniTask FreezeTillDone() + { + _cts ??= new CancellationTokenSource(); + try + { + await UniTask.WaitUntil(this, _ => Completed) + .AttachExternalCancellation(_cts.Token) + .SuppressCancellationThrow(); + } + catch (OperationCanceledException) + { + throw; + } + catch (Exception e) + { + Debug.LogException(e); + throw; + } + } + /// + /// Привязать асинхронный процесс к выполнению загрузки. Сдвигает MaxProgress на 1 + /// + public Loading AttachProcess(Func process) + { + AddLoadProcess(process).Forget(); + return this; + } + private CancellationTokenSource _cts; + /// + /// Привязать асинхронный процесс к выполнению загрузки. Сдвигает MaxProgress на 1 + /// + // Originally written by MrTorex https://github.com/MrTorex + public async UniTaskVoid AddLoadProcess(Func loader) + { + _cts ??= new CancellationTokenSource(); + + MaxProgress++; + _progress++; + try + { + await loader().AttachExternalCancellation(_cts.Token); + } + catch (OperationCanceledException) + { + throw; + } + catch (Exception e) + { + Debug.LogException(e); + throw; + } + finally + { + DoProgress(); + } + } + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Loadings/Loading.cs.meta b/Assets/Code/Infrastructure/Loadings/Loading.cs.meta new file mode 100644 index 00000000..65a594bb --- /dev/null +++ b/Assets/Code/Infrastructure/Loadings/Loading.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a1707a55b78d4218b1557d42adb7d961 +timeCreated: 1766483205 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Particles.meta b/Assets/Code/Infrastructure/Particles.meta new file mode 100644 index 00000000..5681ae6a --- /dev/null +++ b/Assets/Code/Infrastructure/Particles.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5403b8aeab91da411a1a1d04dc34d392 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Code/Infrastructure/Particles/ParticleInfo.cs b/Assets/Code/Infrastructure/Particles/ParticleInfo.cs new file mode 100644 index 00000000..c0f66cd0 --- /dev/null +++ b/Assets/Code/Infrastructure/Particles/ParticleInfo.cs @@ -0,0 +1,46 @@ +using System; +using Code.Infrastructure.Generators; +using UnityEngine; +using UnityEngine.AddressableAssets; + +namespace Code.Infrastructure.Particles +{ + [CreateAssetMenu(fileName = "ParticleInfo", menuName = "Configs/Particles/ParticleInfo")] + [Config("Configs/Particles/ParticleInfo", true)] + public class ParticleInfo : ScriptableObject + { + public AssetReference particleSystem; + public int particleId; + public ParticlePartition particlePartition; + public int CountInPool; + public ParticlePartitionIDPair PartitionIDPair; + } + + [Serializable] + public struct ParticlePartitionIDPair : IEquatable + { + public ParticlePartition ParticlePartition; + public int ID; + + public ParticlePartitionIDPair(ParticlePartition particlePartition, int id) + { + ParticlePartition = particlePartition; + ID = id; + } + + public bool Equals(ParticlePartitionIDPair other) + { + return ParticlePartition == other.ParticlePartition && ID == other.ID; + } + + public override bool Equals(object obj) + { + return obj is ParticlePartitionIDPair other && Equals(other); + } + + public override int GetHashCode() + { + return HashCode.Combine((int)ParticlePartition, ID); + } + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Particles/ParticleInfo.cs.meta b/Assets/Code/Infrastructure/Particles/ParticleInfo.cs.meta new file mode 100644 index 00000000..27f16a00 --- /dev/null +++ b/Assets/Code/Infrastructure/Particles/ParticleInfo.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7b7578a949deb96ef808e8b285d8e68e \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Particles/ParticleLoader.cs b/Assets/Code/Infrastructure/Particles/ParticleLoader.cs new file mode 100644 index 00000000..cb653972 --- /dev/null +++ b/Assets/Code/Infrastructure/Particles/ParticleLoader.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; +using Code.Infrastructure.Configs; +using Code.Infrastructure.Utils; +using Cysharp.Threading.Tasks; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.ResourceManagement.AsyncOperations; + +namespace Code.Infrastructure.Particles +{ + public interface IParticleLoader + { + UniTask LoadParticleSystems(ParticlePartition partition); + void ReleaseParticles(ParticlePartition partition); + void Dispose(); + } + + public interface IParticleLoaderInitializer + { + UniTask LoadConfigs(); + } + + public class ParticleLoader : IParticleLoader, IParticleLoaderInitializer, IDisposable + { + private readonly string _label; + private Dictionary> ParticleInfos { get; } = new(); + + private readonly Dictionary>> + _particleSystemHandles = new(); + + private AsyncOperationHandle> _configsHandle; + + private readonly IParticlePoolManagerForFabric _poolManagerForFabric; + + public ParticleLoader(IConfigLocator configLocator, IParticlePoolManagerForFabric poolManagerForFabric) + { + _poolManagerForFabric = poolManagerForFabric; + _label = configLocator.TryGetManyConfigAssetReferences(); + + for (var i = 0; i < typeof(ParticlePartition).GetEnumValues().Length; i++) + { + ParticleInfos.Add((ParticlePartition)i, new Dictionary()); + _particleSystemHandles.Add((ParticlePartition)i, + new Dictionary>()); + } + } + + public async UniTask LoadConfigs() + { + if (!await AddressablesUtilities.CheckLabelExists(_label)) return; + + _configsHandle = Addressables.LoadAssetsAsync(_label); + + await _configsHandle.ToUniTask(); + + foreach (var config in _configsHandle.Result) + ParticleInfos[config.particlePartition].Add(config.particleId, config); + } + + public async UniTask LoadParticleSystems(ParticlePartition partition) + { + foreach (var particleInfo in ParticleInfos[partition]) + if (!_particleSystemHandles[partition].ContainsKey(particleInfo.Key)) + _particleSystemHandles[partition].Add(particleInfo.Key, + Addressables.LoadAssetAsync(particleInfo.Value.particleSystem)); + else + _particleSystemHandles[partition][particleInfo.Key] = + Addressables.LoadAssetAsync(particleInfo.Value.particleSystem); + + foreach (var handle in _particleSystemHandles[partition]) + await handle.Value.ToUniTask(); + + foreach (var particleInfo in ParticleInfos[partition]) + _poolManagerForFabric.CreatePoolOfParticles( + particleInfo.Value, + _particleSystemHandles[partition][particleInfo.Key].Result.GetComponent() + ); + } + + public void ReleaseParticles(ParticlePartition partition) + { + if (_particleSystemHandles[partition].Count == 0) return; + + foreach (var handle in _particleSystemHandles[partition]) + { + _poolManagerForFabric.DeletePoolOfParticles(partition, handle.Key); + Addressables.Release(handle.Value); + } + + _particleSystemHandles[partition].Clear(); + } + + public void Dispose() + { + foreach (var handles in _particleSystemHandles) + { + foreach (var handle in handles.Value) + { + _poolManagerForFabric.DeletePoolOfParticles(handles.Key, handle.Key); + handle.Value.Release(); + } + } + + _particleSystemHandles.Clear(); + + if (_configsHandle.IsValid()) _configsHandle.Release(); + } + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Particles/ParticleLoader.cs.meta b/Assets/Code/Infrastructure/Particles/ParticleLoader.cs.meta new file mode 100644 index 00000000..c7924fe6 --- /dev/null +++ b/Assets/Code/Infrastructure/Particles/ParticleLoader.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4e0558ddc52d6d69e825887b8be94f10 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Particles/ParticlePoolManager.cs b/Assets/Code/Infrastructure/Particles/ParticlePoolManager.cs new file mode 100644 index 00000000..72cb8530 --- /dev/null +++ b/Assets/Code/Infrastructure/Particles/ParticlePoolManager.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using Reflex.Attributes; +using Unity.VisualScripting; +using UnityEngine; +using UnityEngine.Pool; +using Object = UnityEngine.Object; + +namespace Code.Infrastructure.Particles +{ + public class ParticlePool + { + public IObjectPool Pool; + + private ParticleInfo _particleInfoConfig; + private ParticleSystem _particleSystemPrefab; + + public ParticlePool(ParticleInfo particleInfoConfig, ParticleSystem particleSystemPrefab) + { + _particleSystemPrefab = particleSystemPrefab; + _particleInfoConfig = particleInfoConfig; + + Pool = new ObjectPool( + createFunc: CreateItem, + // actionOnGet: OnGet, + actionOnRelease: OnRelease, + actionOnDestroy: OnDestroyItem, + collectionCheck: true, // helps catch double-release mistakes + defaultCapacity: particleInfoConfig.CountInPool, + maxSize: 20 + ); + } + + public ParticleSystem Get() => Pool.Get(); + public void Release(ParticleSystem particleSystem) => Pool.Release(particleSystem); + + // Creates a new pooled GameObject the first time (and whenever the pool needs more). + private ParticleSystem CreateItem() + { + var particleSystem = Object + .Instantiate(_particleSystemPrefab) // Он уже загружен + .GetComponent(); + particleSystem.name = "PooledParticleSystem"; + Object.DontDestroyOnLoad(particleSystem); + return particleSystem; + } + + // Called when an item is taken from the pool. + private void OnGet(ParticleSystem source) + { + // Настроить если надо + } + + // Called when an item is returned to the pool. + private void OnRelease(ParticleSystem particleSystem) + { + if (!particleSystem) return; + + particleSystem.Stop(); + + // Настроить если надо + + } + + // Called when the pool decides to destroy an item (e.g., above max size). + private void OnDestroyItem(ParticleSystem source) + { + Object.Destroy(source.gameObject); + } + } + + public interface IParticlePoolManagerForService + { + ParticleSystem GetParticleSystem(ParticlePartition partition, int id); + void ReleaseParticleSystem(ParticlePartition partition, int id, ParticleSystem particleSystem); + } + + public interface IParticlePoolManagerForFabric + { + void CreatePoolOfParticles(ParticleInfo particleInfoConfig, ParticleSystem particleSystemPrefab); + void DeletePoolOfParticles(ParticlePartition partition, int id); + } + + public class ParticlePoolManager : IParticlePoolManagerForService, IParticlePoolManagerForFabric + { + // The pool holds plain GameObjects (you can swap this for any component type). + private Dictionary> _poolDictionary = new(); + + public void CreatePoolOfParticles(ParticleInfo particleInfoConfig, ParticleSystem particleSystemPrefab) + { + if(!_poolDictionary.ContainsKey(particleInfoConfig.particlePartition)) + _poolDictionary[particleInfoConfig.particlePartition] = new(); + + _poolDictionary[particleInfoConfig.particlePartition] + .Add(particleInfoConfig.particleId, new ParticlePool(particleInfoConfig, particleSystemPrefab)); + } + public void DeletePoolOfParticles(ParticlePartition partition, int id) + { + _poolDictionary[partition][id].Pool.Clear(); + _poolDictionary[partition].Remove(id); + } + + public ParticleSystem GetParticleSystem(ParticlePartition partition, int id) + { + var source = _poolDictionary[partition][id].Get(); + + // Настроить если надо + + return source; + } + + public void ReleaseParticleSystem(ParticlePartition partition, int id, ParticleSystem particleSystem) + { + if(_poolDictionary[partition].ContainsKey(id)) _poolDictionary[partition][id].Release(particleSystem); + } + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Particles/ParticlePoolManager.cs.meta b/Assets/Code/Infrastructure/Particles/ParticlePoolManager.cs.meta new file mode 100644 index 00000000..5ef9c99b --- /dev/null +++ b/Assets/Code/Infrastructure/Particles/ParticlePoolManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 21ce106fcb48566dc92ae832b09fa268 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Particles/ParticleService.cs b/Assets/Code/Infrastructure/Particles/ParticleService.cs new file mode 100644 index 00000000..f22b818e --- /dev/null +++ b/Assets/Code/Infrastructure/Particles/ParticleService.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using Cysharp.Threading.Tasks; +using Reflex.Attributes; +using UnityEngine; + +namespace Code.Infrastructure.Particles +{ + public interface IParticleService + { + UniTaskVoid EmitOneShot(ParticlePartitionIDPair pair, int particleCount, Vector3 position, Quaternion rotation); + UniTaskVoid EmitTillCancelled(ParticlePartitionIDPair pair, CancellationToken token, Vector3 position, Quaternion rotation); + } + + public class ParticleService : IParticleService + { + [Inject] private IParticlePoolManagerForService _poolManagerForService; + [Inject] private IParticleLoader _particleLoader; + + public async UniTaskVoid EmitOneShot(ParticlePartitionIDPair pair, int particleCount, Vector3 position, Quaternion rotation) + { + var particleSystem = _poolManagerForService.GetParticleSystem(pair.ParticlePartition, pair.ID); + + particleSystem.transform.position = position; + particleSystem.transform.rotation = rotation; + + particleSystem.Emit(particleCount); + + await UniTask.WaitWhile(() => particleSystem.particleCount > 0); + + _poolManagerForService.ReleaseParticleSystem(pair.ParticlePartition, pair.ID, particleSystem); + } + public async UniTaskVoid EmitTillCancelled(ParticlePartitionIDPair pair, CancellationToken token, Vector3 position, Quaternion rotation) + { + var particleSystem = _poolManagerForService.GetParticleSystem(pair.ParticlePartition, pair.ID); + + particleSystem.transform.position = position; + particleSystem.transform.rotation = rotation; + + particleSystem.Play(); + try + { + await UniTask.WaitUntilCanceled(cancellationToken: token); + } + catch + { + // + } + + particleSystem.Stop(); + + _poolManagerForService.ReleaseParticleSystem(pair.ParticlePartition, pair.ID, particleSystem); + } + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Particles/ParticleService.cs.meta b/Assets/Code/Infrastructure/Particles/ParticleService.cs.meta new file mode 100644 index 00000000..1e7e6e62 --- /dev/null +++ b/Assets/Code/Infrastructure/Particles/ParticleService.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0a4f2bf7e8fd80581b714c3d32e47f20 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/SceneLoader.meta b/Assets/Code/Infrastructure/SceneLoader.meta new file mode 100644 index 00000000..1e528d41 --- /dev/null +++ b/Assets/Code/Infrastructure/SceneLoader.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e1152e782dc9c46c5bc317f1ba499fd6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Code/Infrastructure/SceneLoader/CustomSceneManager.cs b/Assets/Code/Infrastructure/SceneLoader/CustomSceneManager.cs new file mode 100644 index 00000000..19974a9e --- /dev/null +++ b/Assets/Code/Infrastructure/SceneLoader/CustomSceneManager.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Code.Infrastructure.Configs; +using Code.Infrastructure.Utils; +using Cysharp.Threading.Tasks; +using ObservableCollections; +using Reflex.Core; +using UnityEngine; +using UnityEngine.ResourceManagement.AsyncOperations; +using UnityEngine.ResourceManagement.ResourceProviders; +using UnityEngine.SceneManagement; + +namespace Code.Infrastructure.SceneLoader +{ + using UnityEngine.AddressableAssets; + + public interface ISceneLoader + { + UniTask LoadSceneAsync(SceneId id, LoadSceneMode loadMode, bool setActive, Action extraInstall = null); + Scene GetScene(SceneId id); + UniTask UnloadSceneAsync(SceneId id); + } + + public interface ISceneContainerManager + { + ObservableDictionary ScenesContainers { get; } + } + + public interface ICustomSceneManagerInitializer + { + UniTask LoadConfigs(); + } + + public class CustomCustomSceneManager : IDisposable, ISceneLoader, ISceneContainerManager, + ICustomSceneManagerInitializer + { + private AsyncOperationHandle> _loadHandle; + private AsyncOperationHandle> _configHandle; + private readonly string _configsLabel; + + public ObservableDictionary ScenesContainers { get; } = new(); + + private Dictionary _sceneInfos = new(); + private Dictionary> _loadedScenes = new(); + + public CustomCustomSceneManager(IConfigLocator configLocator) + { + _configsLabel = configLocator.TryGetManyConfigAssetReferences(); + } + + // Киська + // TODO При загрузке нескольких сцен сразу может быть неприятность + public async UniTask LoadSceneAsync( + SceneId id, + LoadSceneMode loadMode, + bool setActive, + Action extraInstall = null) + { + if (loadMode == LoadSceneMode.Single) + for (var i = 0; i < _loadedScenes.Count; i++) + UnloadSceneAsync(_loadedScenes.Keys.ToList()[i]).Forget(); + + if (extraInstall != null) ContainerScope.OnSceneContainerBuilding += extraInstall; + + _loadedScenes.Add(id, Addressables.LoadSceneAsync(_sceneInfos[id].SceneAsset, LoadSceneMode.Additive)); + + await _loadedScenes[id]; + + if (extraInstall != null) ContainerScope.OnSceneContainerBuilding -= extraInstall; + + if (setActive) SceneManager.SetActiveScene(_loadedScenes[id].Result.Scene); + } + + public Scene GetScene(SceneId id) => _loadedScenes[id].Result.Scene; + + public async UniTask UnloadSceneAsync(SceneId id) + { + await Addressables.UnloadSceneAsync(_loadedScenes[id]); + _loadedScenes.Remove(id); + } + + + public async UniTask LoadConfigs() + { + if (!await AddressablesUtilities.CheckLabelExists(_configsLabel)) return; + + _configHandle = + Addressables.LoadAssetsAsync(_configsLabel, OnSceneConfigLoaded, + Addressables.MergeMode.Union); + + await _configHandle.ToUniTask(); + } + + private void OnSceneConfigLoaded(SceneInfo sceneInfoConfig) + { + SceneInfo sceneInfo = ScriptableObject.CreateInstance(); + sceneInfo.SceneId = sceneInfoConfig.SceneId; + sceneInfo.SceneAsset = sceneInfoConfig.SceneAsset; + + _sceneInfos.Add(sceneInfoConfig.SceneId, sceneInfo); + } + + public void Dispose() + { + if(_configHandle.IsValid()) Addressables.Release(_configHandle); + } + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/SceneLoader/CustomSceneManager.cs.meta b/Assets/Code/Infrastructure/SceneLoader/CustomSceneManager.cs.meta new file mode 100644 index 00000000..82e3e281 --- /dev/null +++ b/Assets/Code/Infrastructure/SceneLoader/CustomSceneManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 760817ac86164799ac58327509052257 +timeCreated: 1766325358 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/SceneLoader/SceneInfo.cs b/Assets/Code/Infrastructure/SceneLoader/SceneInfo.cs new file mode 100644 index 00000000..49096c42 --- /dev/null +++ b/Assets/Code/Infrastructure/SceneLoader/SceneInfo.cs @@ -0,0 +1,14 @@ +using Code.Infrastructure.Generators; +using UnityEngine; +using UnityEngine.AddressableAssets; + +namespace Code.Infrastructure.SceneLoader +{ + [Config("Configs/SceneConfig", true)] + [CreateAssetMenu(fileName = "SceneInfo", menuName = "Configs/SceneConfig")] + public class SceneInfo : ScriptableObject + { + public AssetReference SceneAsset; + public SceneId SceneId; + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/SceneLoader/SceneInfo.cs.meta b/Assets/Code/Infrastructure/SceneLoader/SceneInfo.cs.meta new file mode 100644 index 00000000..dd33897f --- /dev/null +++ b/Assets/Code/Infrastructure/SceneLoader/SceneInfo.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f8b44b2bf5414b47a94fc1633e021e94 +timeCreated: 1785871561 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/SceneLoader/ScenesAssetReferences.cs b/Assets/Code/Infrastructure/SceneLoader/ScenesAssetReferences.cs new file mode 100644 index 00000000..cf22d8ce --- /dev/null +++ b/Assets/Code/Infrastructure/SceneLoader/ScenesAssetReferences.cs @@ -0,0 +1,9 @@ +using UnityEngine; + +namespace Code.Infrastructure.SceneLoader +{ + [CreateAssetMenu(fileName = "ScenesAssetReferences", menuName = "Configs/ScenesAssetReferences")] + public class ScenesAssetReferences : ScriptableObject + { + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/SceneLoader/ScenesAssetReferences.cs.meta b/Assets/Code/Infrastructure/SceneLoader/ScenesAssetReferences.cs.meta new file mode 100644 index 00000000..3900da41 --- /dev/null +++ b/Assets/Code/Infrastructure/SceneLoader/ScenesAssetReferences.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9759979f397044a5bcb03ded0d1c9561 +timeCreated: 1766325404 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/StateMachine.meta b/Assets/Code/Infrastructure/StateMachine.meta new file mode 100644 index 00000000..3b6a4d6f --- /dev/null +++ b/Assets/Code/Infrastructure/StateMachine.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7364161b6b6945d3866be9f0445777a5 +timeCreated: 1785766193 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/StateMachine/AbstractStateMachine.cs b/Assets/Code/Infrastructure/StateMachine/AbstractStateMachine.cs new file mode 100644 index 00000000..46dd4b2c --- /dev/null +++ b/Assets/Code/Infrastructure/StateMachine/AbstractStateMachine.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using Cysharp.Threading.Tasks; + +namespace Code.Infrastructure.StateMachine +{ + public class AbstractStateMachine + where TStateMachineContext : new() + { + protected AbstractStateMachine(TStateMachineContext stateMachineContext) + { + StateMachineContext = stateMachineContext; + } + + public TStateEnum CurrentState { get; protected set; } + public TStateEnum NextState { get; protected set; } + public BaseState CurrentBaseState { get; private set; } + private BaseState _previousBaseState; + + protected Dictionary> States = new(); + protected Dictionary StatesTypes = new(); + protected TStateMachineContext StateMachineContext { get; } + + private readonly SemaphoreSlim _stateLock = new (1, 1); + + public virtual async UniTask SwitchState(TStateEnum nextState) + { + await _stateLock.WaitAsync(); + + try + { + NextState = nextState; + + if (CurrentBaseState != null) await CurrentBaseState.ExitState(); + + var newState = States[nextState]; + await newState.EnterState(); + + CurrentBaseState = newState; + CurrentState = nextState; + NextState = default; + + // Logger + } + finally + { + _stateLock.Release(); + } + } + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/StateMachine/AbstractStateMachine.cs.meta b/Assets/Code/Infrastructure/StateMachine/AbstractStateMachine.cs.meta new file mode 100644 index 00000000..580635e3 --- /dev/null +++ b/Assets/Code/Infrastructure/StateMachine/AbstractStateMachine.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b58aba24383545149cd08a2a0511bf67 +timeCreated: 1785766207 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/StateMachine/BaseState.cs b/Assets/Code/Infrastructure/StateMachine/BaseState.cs new file mode 100644 index 00000000..f100048a --- /dev/null +++ b/Assets/Code/Infrastructure/StateMachine/BaseState.cs @@ -0,0 +1,19 @@ +using Cysharp.Threading.Tasks; + +namespace Code.Infrastructure.StateMachine +{ + public abstract class BaseState + { + public abstract TEnum MyState { get; } + + protected BaseState(TStateMachineContext context) + { + Context = context; + } + + protected TStateMachineContext Context { get; } + + public virtual UniTask EnterState() => UniTask.CompletedTask; + public virtual UniTask ExitState() => UniTask.CompletedTask; + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/StateMachine/BaseState.cs.meta b/Assets/Code/Infrastructure/StateMachine/BaseState.cs.meta new file mode 100644 index 00000000..8168eb0e --- /dev/null +++ b/Assets/Code/Infrastructure/StateMachine/BaseState.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: dbb4ded54baa4a58b4f7b77f84fd57ed +timeCreated: 1785766328 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/UI.meta b/Assets/Code/Infrastructure/UI.meta new file mode 100644 index 00000000..07cdc94d --- /dev/null +++ b/Assets/Code/Infrastructure/UI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0d4a5df853da427b2870df717e157028 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Code/Infrastructure/UI/CanvasSettings.cs b/Assets/Code/Infrastructure/UI/CanvasSettings.cs new file mode 100644 index 00000000..ec432f9d --- /dev/null +++ b/Assets/Code/Infrastructure/UI/CanvasSettings.cs @@ -0,0 +1,18 @@ +using Code.Infrastructure.Generators; +using UnityEngine; +using UnityEngine.UI; + +namespace Code.Infrastructure.UI +{ + [CreateAssetMenu(fileName = "CanvasSettings", menuName = "Configs/UI/CanvasSettings")] + [Config("Configs/UI/CanvasSettings")] + public class CanvasSettings : ScriptableObject + { + public RenderMode RenderMode; + public int OrderInLayer; + public CanvasScaler.ScaleMode ScaleMode; + public int ReferenceResolutionX; + public int ReferenceResolutionY; + public float PlaneDistance; + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/UI/CanvasSettings.cs.meta b/Assets/Code/Infrastructure/UI/CanvasSettings.cs.meta new file mode 100644 index 00000000..eb20cf80 --- /dev/null +++ b/Assets/Code/Infrastructure/UI/CanvasSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d23873b1c0034bf89886915f997b2f9a +timeCreated: 1785859025 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/UI/UIFactory.cs b/Assets/Code/Infrastructure/UI/UIFactory.cs new file mode 100644 index 00000000..ab9459de --- /dev/null +++ b/Assets/Code/Infrastructure/UI/UIFactory.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Code.Infrastructure.Configs; +using Code.Infrastructure.Utils; +using Cysharp.Threading.Tasks; +using Unity.VisualScripting; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.ResourceManagement.AsyncOperations; +using UnityEngine.UI; + +namespace Code.Infrastructure.UI +{ + public interface IUIFactory + { + Canvas GameplayCanvas { get; } + Canvas Canvas { get; } + UniTask LoadPanel(UIPanelType panelType, bool gameplayCanvas, Transform parent = null); + } + + public interface IUIFactoryInitializer + { + UniTask LoadConfigs(); + void SetCanvas(Canvas canvas); + void SetCanvasCamera(UnityEngine.Camera camera); + } + + public class UIFactory : IDisposable, IUIFactory, IUIFactoryInitializer + { + private Dictionary _configs; + private readonly AssetReference _canvasConfigReference; + private readonly string _configsLabel; + + private AsyncOperationHandle> _configsHandle; + private AsyncOperationHandle _canvasSettingsHandle; + private CanvasSettings _canvasConfig; + + private GameObject _gameplayCanvas; + + public Canvas GameplayCanvas { get; private set; } + public Canvas Canvas { get; private set; } + + public UIFactory(IConfigLocator configLocator) + { + _configsLabel = configLocator.TryGetManyConfigAssetReferences(); + _canvasConfigReference = configLocator.TryGetConfigAssetReference(); + } + + public void SetCanvas(Canvas canvas) + { + Canvas = canvas; + UnityEngine.Object.DontDestroyOnLoad(canvas.gameObject); + } + + public void SetCanvasCamera(UnityEngine.Camera camera) + { + Canvas.worldCamera = camera; + Canvas.planeDistance = 0.1f; + + GameplayCanvas.worldCamera = camera; + } + + public async UniTask LoadPanel(UIPanelType panelType, bool gameplayCanvas, Transform parent = null) + { + var panel = (await Addressables.InstantiateAsync(_configs[panelType].Prefab, + parent ?? gameplayCanvas ? _gameplayCanvas.transform : Canvas.transform).ToUniTask()) + .GetComponent(); + + panel.PanelType = panelType; + + return panel; + } + + public async UniTask LoadConfigs() + { + if (await AddressablesUtilities.CheckLabelExists(_configsLabel)) await LoadPanelConfigs(); + + _canvasSettingsHandle = Addressables.LoadAssetAsync(_canvasConfigReference); + + await _canvasSettingsHandle.ToUniTask(); + + _canvasConfig = _canvasSettingsHandle.Result; + + _gameplayCanvas = new GameObject { name = "GameplayCanvas" }; + UnityEngine.Object.DontDestroyOnLoad(_gameplayCanvas); + + GameplayCanvas = _gameplayCanvas.AddComponent(); + GameplayCanvas.renderMode = _canvasConfig.RenderMode; + GameplayCanvas.sortingOrder = _canvasConfig.OrderInLayer; + GameplayCanvas.planeDistance = _canvasConfig.PlaneDistance; + var scaler = GameplayCanvas.AddComponent(); + + scaler.uiScaleMode = _canvasConfig.ScaleMode; + scaler.referenceResolution = + new Vector2(_canvasConfig.ReferenceResolutionX, _canvasConfig.ReferenceResolutionY); + + GameplayCanvas.AddComponent(); + } + + private async UniTask LoadPanelConfigs() + { + _configsHandle = Addressables.LoadAssetsAsync(_configsLabel); + await _configsHandle.ToUniTask(); + _configs = _configsHandle.Result.ToDictionary(c => c.UIPanelType); + } + + public void Dispose() + { + if (_configsHandle.IsValid()) + Addressables.Release(_configsHandle); + if (_canvasSettingsHandle.IsValid()) + Addressables.Release(_canvasSettingsHandle); + if (_gameplayCanvas) + Addressables.ReleaseInstance(_gameplayCanvas); + } + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/UI/UIFactory.cs.meta b/Assets/Code/Infrastructure/UI/UIFactory.cs.meta new file mode 100644 index 00000000..22e7bced --- /dev/null +++ b/Assets/Code/Infrastructure/UI/UIFactory.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 35696d0a97ac9023daa173dc582e7057 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/UI/UIPanel.cs b/Assets/Code/Infrastructure/UI/UIPanel.cs new file mode 100644 index 00000000..2499578d --- /dev/null +++ b/Assets/Code/Infrastructure/UI/UIPanel.cs @@ -0,0 +1,22 @@ +using System; +using System.Threading; +using Cysharp.Threading.Tasks; +using UnityEngine; +using UnityEngine.AddressableAssets; + +namespace Code.Infrastructure.UI +{ + public abstract class UIPanel : MonoBehaviour, IDisposable + { + public UIPanelType PanelType { get; set; } + + public abstract UniTask Open(CancellationToken cts = default); + public abstract UniTask Close(CancellationToken cts = default); + + public void Dispose() + { + Addressables.ReleaseInstance(gameObject); + } + } + +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/UI/UIPanel.cs.meta b/Assets/Code/Infrastructure/UI/UIPanel.cs.meta new file mode 100644 index 00000000..166e5108 --- /dev/null +++ b/Assets/Code/Infrastructure/UI/UIPanel.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 87687716d22d15d189146c86f059f922 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/UI/UIPanelSettings.cs b/Assets/Code/Infrastructure/UI/UIPanelSettings.cs new file mode 100644 index 00000000..a8d2c5a6 --- /dev/null +++ b/Assets/Code/Infrastructure/UI/UIPanelSettings.cs @@ -0,0 +1,14 @@ +using Code.Infrastructure.Generators; +using UnityEngine; +using UnityEngine.AddressableAssets; + +namespace Code.Infrastructure.UI +{ + [Config("Configs/UI/UIPanelSettings", true)] + [CreateAssetMenu(fileName = "UIPanelSettings", menuName = "Configs/UI/UIPanelSettings")] + public class UIPanelSettings : ScriptableObject + { + public AssetReference Prefab; + public UIPanelType UIPanelType; + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/UI/UIPanelSettings.cs.meta b/Assets/Code/Infrastructure/UI/UIPanelSettings.cs.meta new file mode 100644 index 00000000..991d952c --- /dev/null +++ b/Assets/Code/Infrastructure/UI/UIPanelSettings.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 263960ff516f55c6686b3c63c7a6a28e \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Utils.meta b/Assets/Code/Infrastructure/Utils.meta new file mode 100644 index 00000000..4792ace7 --- /dev/null +++ b/Assets/Code/Infrastructure/Utils.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9252caa218789b530ad841271890c0f7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Code/Infrastructure/Utils/AddressablesUtilities.cs b/Assets/Code/Infrastructure/Utils/AddressablesUtilities.cs new file mode 100644 index 00000000..0f9ce70c --- /dev/null +++ b/Assets/Code/Infrastructure/Utils/AddressablesUtilities.cs @@ -0,0 +1,30 @@ +using Cysharp.Threading.Tasks; +using UnityEngine.AddressableAssets; +using UnityEngine.ResourceManagement.AsyncOperations; + +namespace Code.Infrastructure.Utils +{ + public static class AddressablesUtilities + { + public static async UniTask CheckLabelExists(string labelName) + { + if (labelName is null) return false; + + var handle = Addressables.LoadResourceLocationsAsync(labelName); + + await handle.ToUniTask(); + + if (handle.Status == AsyncOperationStatus.Succeeded) + { + if (handle.Result.Count > 0) + { + Addressables.Release(handle); + return true; + } + } + + Addressables.Release(handle); + return false; + } + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Utils/AddressablesUtilities.cs.meta b/Assets/Code/Infrastructure/Utils/AddressablesUtilities.cs.meta new file mode 100644 index 00000000..626a42cd --- /dev/null +++ b/Assets/Code/Infrastructure/Utils/AddressablesUtilities.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 607f50d5faeb41f585a2b4079902fbc6 +timeCreated: 1774778444 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Utils/ConfigUtility.cs b/Assets/Code/Infrastructure/Utils/ConfigUtility.cs new file mode 100644 index 00000000..cde3d9a2 --- /dev/null +++ b/Assets/Code/Infrastructure/Utils/ConfigUtility.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using Code.Infrastructure.Configs; +using Cysharp.Threading.Tasks; +using Reflex.Core; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.ResourceManagement.AsyncOperations; + +namespace Code.Infrastructure.Utils +{ + public class MultipleConfig : IDisposable where TConfig : ScriptableObject + { + private AsyncOperationHandle> _configsHandle; + + public IList Configs => _configsHandle.Result; + + public async UniTask> LoadConfigs() + { + if (_configsHandle.IsValid()) return _configsHandle.Result; + var configLocator = Container.RootContainer.Resolve(); + + var label = configLocator.TryGetManyConfigAssetReferences(); + + _configsHandle = Addressables.LoadAssetsAsync(label); + + await _configsHandle; + + return _configsHandle.Result; + } + + public void Dispose() + { + if(_configsHandle.IsValid()) _configsHandle.Release(); + } + } + public class SingleConfig : IDisposable where TConfig : ScriptableObject + { + private AsyncOperationHandle _configHandle; + public TConfig Config => _configHandle.IsDone ? _configHandle.Result : null; + + public async UniTask LoadConfig() + { + if (_configHandle.IsValid()) return _configHandle.Result; + var configLocator = Container.RootContainer.Resolve(); + + var label = configLocator.TryGetConfigAssetReference(); + + _configHandle = Addressables.LoadAssetAsync(label); + + await _configHandle; + + return _configHandle.Result; + } + + public void Dispose() + { + if(_configHandle.IsValid()) _configHandle.Release(); + } + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Utils/ConfigUtility.cs.meta b/Assets/Code/Infrastructure/Utils/ConfigUtility.cs.meta new file mode 100644 index 00000000..3f7b7e86 --- /dev/null +++ b/Assets/Code/Infrastructure/Utils/ConfigUtility.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d66e152012484170908388987ee81821 +timeCreated: 1783878002 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Utils/EnumUtil.cs b/Assets/Code/Infrastructure/Utils/EnumUtil.cs new file mode 100644 index 00000000..26087308 --- /dev/null +++ b/Assets/Code/Infrastructure/Utils/EnumUtil.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Code.Infrastructure.Utils +{ +// Source - https://stackoverflow.com/a/972323 +// Posted by JaredPar, modified by community. See post 'Timeline' for change history +// Retrieved 2026-07-22, License - CC BY-SA 4.0 +// Thanks to him :) + public static class EnumUtil { + public static IEnumerable GetValues() { + return Enum.GetValues(typeof(T)).Cast(); + } + } + +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Utils/EnumUtil.cs.meta b/Assets/Code/Infrastructure/Utils/EnumUtil.cs.meta new file mode 100644 index 00000000..349a9cdb --- /dev/null +++ b/Assets/Code/Infrastructure/Utils/EnumUtil.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d87b3cb42445428888da6391d1e23d87 +timeCreated: 1784729151 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Volume.meta b/Assets/Code/Infrastructure/Volume.meta new file mode 100644 index 00000000..4a81b6cd --- /dev/null +++ b/Assets/Code/Infrastructure/Volume.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 36efee4891434aaebe4c6fb8fa5de4a1 +timeCreated: 1785788377 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Volume/VolumeFactory.cs b/Assets/Code/Infrastructure/Volume/VolumeFactory.cs new file mode 100644 index 00000000..3667e753 --- /dev/null +++ b/Assets/Code/Infrastructure/Volume/VolumeFactory.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Code.Infrastructure.Configs; +using Code.Infrastructure.Utils; +using Cysharp.Threading.Tasks; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.ResourceManagement.AsyncOperations; +using Object = UnityEngine.Object; + +namespace Code.Infrastructure.Volume +{ + public interface IVolumeFactory + { + UniTask LoadVolume(VolumeId volumeId, Transform transform = null); + void ReleaseVolume(UnityEngine.Rendering.Volume volume); + } + + public interface IVolumeFactoryInitializer + { + UniTask LoadConfigs(); + } + + public class VolumeFactory : IDisposable, IVolumeFactory, IVolumeFactoryInitializer + { + private Dictionary _configs; + + private AsyncOperationHandle> _configsHandle; + private string _configsLabel; + + public VolumeFactory(IConfigLocator configLocator) + { + _configsLabel = configLocator.TryGetManyConfigAssetReferences(); + } + + public async UniTask LoadConfigs() + { + if(!await AddressablesUtilities.CheckLabelExists(_configsLabel)) + { + _configs = new(); + return; + } + + _configsHandle = Addressables.LoadAssetsAsync(_configsLabel); + + await _configsHandle.ToUniTask(); + + _configs = _configsHandle.Result.ToDictionary(c => c.id); + } + + public async UniTask LoadVolume(VolumeId volumeId, Transform transform = null) + { + UnityEngine.Rendering.Volume volume = !transform + ? (await Addressables.InstantiateAsync(_configs[volumeId].prefab, transform).ToUniTask()) + .GetComponent() + : (await Addressables.InstantiateAsync(_configs[volumeId].prefab).ToUniTask()) + .GetComponent(); + + if(_configs[volumeId].doNotDestroyOnLoad) + Object.DontDestroyOnLoad(volume.gameObject); + + return volume; + } + + public void ReleaseVolume(UnityEngine.Rendering.Volume volume) + { + Addressables.ReleaseInstance(volume.gameObject); + } + + public void Dispose() + { + if(_configsHandle.IsValid()) Addressables.Release(_configsHandle); + } + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Volume/VolumeFactory.cs.meta b/Assets/Code/Infrastructure/Volume/VolumeFactory.cs.meta new file mode 100644 index 00000000..543dfed1 --- /dev/null +++ b/Assets/Code/Infrastructure/Volume/VolumeFactory.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c607472c188d483a8bb65a5b4a775e44 +timeCreated: 1769169793 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Volume/VolumeService.cs b/Assets/Code/Infrastructure/Volume/VolumeService.cs new file mode 100644 index 00000000..39db6bcb --- /dev/null +++ b/Assets/Code/Infrastructure/Volume/VolumeService.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using Cysharp.Threading.Tasks; + +namespace Code.Infrastructure.Volume +{ + public interface IVolumeService + { + UniTask LoadVolume(VolumeId volumeId); + void RemoveVolume(VolumeId volumeId); + } + + public class VolumeService : IVolumeService + { + private readonly Dictionary _loadedVolumes = new(); + private readonly IVolumeFactory _factory; + + public VolumeService(IVolumeFactory factory) + { + _factory = factory; + } + public async UniTask LoadVolume(VolumeId volumeId) + { + var volume = await _factory.LoadVolume(volumeId); + _loadedVolumes.Add(volumeId, volume); + } + public void RemoveVolume(VolumeId volumeId) + { + _factory.ReleaseVolume(_loadedVolumes[volumeId]); + _loadedVolumes.Remove(volumeId); + } + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Volume/VolumeService.cs.meta b/Assets/Code/Infrastructure/Volume/VolumeService.cs.meta new file mode 100644 index 00000000..5c41793a --- /dev/null +++ b/Assets/Code/Infrastructure/Volume/VolumeService.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c301e693e9ef44d9b5395e9d9627f87b +timeCreated: 1769171742 \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Volume/VolumeSettings.cs b/Assets/Code/Infrastructure/Volume/VolumeSettings.cs new file mode 100644 index 00000000..180a259b --- /dev/null +++ b/Assets/Code/Infrastructure/Volume/VolumeSettings.cs @@ -0,0 +1,15 @@ +using Code.Infrastructure.Generators; +using UnityEngine; +using UnityEngine.AddressableAssets; + +namespace Code.Infrastructure.Volume +{ + [Config("Configs/PostProcessing/VolumeSetting", true)] + [CreateAssetMenu(fileName = "VolumeSettings", menuName = "Configs/PostProcessing/VolumeSetting")] + public class VolumeSettings : ScriptableObject + { + public AssetReference prefab; + public VolumeId id; + public bool doNotDestroyOnLoad; + } +} \ No newline at end of file diff --git a/Assets/Code/Infrastructure/Volume/VolumeSettings.cs.meta b/Assets/Code/Infrastructure/Volume/VolumeSettings.cs.meta new file mode 100644 index 00000000..c1075470 --- /dev/null +++ b/Assets/Code/Infrastructure/Volume/VolumeSettings.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 765e27414fb74f3b9bd11835ae098f92 \ No newline at end of file diff --git a/Assets/Code/Musician.meta b/Assets/Code/Musician.meta new file mode 100644 index 00000000..a074f277 --- /dev/null +++ b/Assets/Code/Musician.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 473029a1888e4666b8cc34fb41d73591 +timeCreated: 1789657647 \ No newline at end of file diff --git a/Assets/Code/PapaInstaller.cs b/Assets/Code/PapaInstaller.cs new file mode 100644 index 00000000..c355922f --- /dev/null +++ b/Assets/Code/PapaInstaller.cs @@ -0,0 +1,165 @@ +using Code.Infrastructure.App; +using Code.Infrastructure.Audio; +using Code.Infrastructure.Camera; +using Code.Infrastructure.Configs; +using Code.Infrastructure.Input; +using Code.Infrastructure.Loadings; +using Code.Infrastructure.Particles; +using Code.Infrastructure.SceneLoader; +using Code.Infrastructure.UI; +using Code.Infrastructure.Volume; +using Cysharp.Threading.Tasks; +using Reflex.Core; +using Reflex.Enums; +using UnityEngine; +using UnityEngine.Rendering.Universal; +using Resolution = Reflex.Enums.Resolution; + +namespace Code.Game +{ + public class PapaInstaller : MonoBehaviour, IInstaller + { + private Loading _ui2CamLoading; + private Container _thatRightContainer; + private Canvas _canvas; + + public void InstallBindings(ContainerBuilder containerBuilder) + { + Debug.Log("Bindings installation"); + + Cursor.lockState = CursorLockMode.Locked; + + _canvas = FindAnyObjectByType(); + + InitLoadings(); + + containerBuilder.OnContainerBuilt += Bootstrap; + + containerBuilder.RegisterType(typeof(ConfigLocator), new[] { typeof(IConfigLocator) }, Lifetime.Singleton, + Resolution.Eager); + containerBuilder.RegisterType(typeof(CustomCustomSceneManager), + new[] { typeof(ISceneLoader), typeof(ICustomSceneManagerInitializer), typeof(ISceneContainerManager) }, + Lifetime.Singleton, Resolution.Eager); + containerBuilder.RegisterType(typeof(InputService), + new[] { typeof(IInputService), typeof(IInputServiceInitializer) }, Lifetime.Singleton, + Resolution.Eager); + + containerBuilder.RegisterType(typeof(AppStateMachine), Lifetime.Singleton, Resolution.Lazy); + containerBuilder.RegisterType(typeof(AppStateMachineContext), Lifetime.Singleton, Resolution.Lazy); + + containerBuilder.RegisterType(typeof(CameraFactory), new[] { typeof(ICameraFactory) }, Lifetime.Singleton, + Resolution.Lazy); + containerBuilder.RegisterType(typeof(CameraStateMachine), Lifetime.Singleton, Resolution.Lazy); + containerBuilder.RegisterType(typeof(CameraStateMachineContext), Lifetime.Singleton, Resolution.Lazy); + + containerBuilder.RegisterType(typeof(UIFactory), + new[] { typeof(IUIFactory), typeof(IUIFactoryInitializer) }, Lifetime.Singleton, + Resolution.Eager); + + containerBuilder.RegisterType(typeof(VolumeService), new[] { typeof(IVolumeService) }, Lifetime.Singleton, + Resolution.Lazy); + containerBuilder.RegisterType(typeof(VolumeFactory), + new[] { typeof(IVolumeFactory), typeof(IVolumeFactoryInitializer) }, Lifetime.Singleton, + Resolution.Eager); + + containerBuilder.RegisterType(typeof(AudioFactory), + new[] { typeof(IAudioFactory), typeof(IAudioFactoryInitializer) }, Lifetime.Singleton, + Resolution.Eager); + containerBuilder.RegisterType(typeof(AudioSourcePool), + new[] { typeof(IAudioSourcePool), typeof(IAudioSourcePoolInitializer) }, + Lifetime.Singleton, + Resolution.Eager); + containerBuilder.RegisterType(typeof(AudioService), + new[] { typeof(IAudioService), typeof(IAudioServiceInitializer) }, Lifetime.Singleton, + Resolution.Eager); + + containerBuilder.RegisterType(typeof(ParticlePoolManager), + new[] { typeof(IParticlePoolManagerForFabric), typeof(IParticlePoolManagerForService) }, + Lifetime.Singleton, + Resolution.Eager); + containerBuilder.RegisterType(typeof(ParticleLoader), + new[] { typeof(IParticleLoader), typeof(IParticleLoaderInitializer) }, + Lifetime.Singleton, + Resolution.Eager); + containerBuilder.RegisterType(typeof(ParticleService), new[] { typeof(IParticleService) }, + Lifetime.Singleton, + Resolution.Eager); + } + + + private void InitLoadings() + { + _ui2CamLoading = new Loading(2, + () => + { + var camera = _thatRightContainer + .Resolve().cameraLoadedData.Camera; + + var uiFactory = _thatRightContainer.Resolve(); + uiFactory.SetCanvasCamera(camera); + }); + } + + private void Bootstrap(Container container) + { + _thatRightContainer = container; + + // UIFactory + + // Scene configs + + // Input service + + // Camera + + // Volume Factory + + // Particle Loader + + // Audio Factory + + // Audio Pool + + // Audio Service + + new Loading(0, () => EssentialLoadEnded(_thatRightContainer)) + .AttachProcess(container.Resolve().LoadConfigs) + .AttachProcess(container.Resolve().LoadConfigs) + .AttachProcess(InitializeCamera) + .AttachProcess(InitializeUIFactory) + .AttachProcess(container.Resolve().LoadConfigs) + .AttachProcess(container.Resolve().LoadConfigs) + .AttachProcess(container.Resolve().LoadConfigs) + .AttachProcess(container.Resolve().LoadConfigs) + .AttachProcess(container.Resolve().LoadMixerAsset); + } + + private void EssentialLoadEnded(Container container) + { + var appStateMachine = container.Resolve(); + + container.Resolve().StateMachine = appStateMachine; + + appStateMachine.SwitchState(AppStates.Testing).Forget(); + } + + private async UniTask InitializeCamera() + { + var cameraFactory = _thatRightContainer.Resolve(); + + var cameraLoadedData = await cameraFactory.CreateCameraStateMachine(); + + _thatRightContainer.Resolve().cameraLoadedData = cameraLoadedData; + var cameraStateMachine = _thatRightContainer.Resolve(); + await cameraStateMachine.SwitchState(CameraMode.None); + + cameraFactory.CreateCameraStateMachineRunner(cameraStateMachine); + + cameraLoadedData.Camera.GetUniversalAdditionalCameraData().renderPostProcessing = true; + + _ui2CamLoading.DoProgress(); + } + + private async UniTask InitializeUIFactory() + { + var uiFactoryInitializer = _thatRightContainer.Resolve(); + + await uiFactoryInitializer.LoadConfigs(); + + uiFactoryInitializer.SetCanvas(_canvas); + + _ui2CamLoading.DoProgress(); + } + } +} \ No newline at end of file diff --git a/Assets/Code/PapaInstaller.cs.meta b/Assets/Code/PapaInstaller.cs.meta new file mode 100644 index 00000000..86a84820 --- /dev/null +++ b/Assets/Code/PapaInstaller.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4fa6382447eb48b4ae3dd0831ec60c80 +timeCreated: 1785829279 \ No newline at end of file diff --git a/Assets/Code/Tests.meta b/Assets/Code/Tests.meta new file mode 100644 index 00000000..6179edde --- /dev/null +++ b/Assets/Code/Tests.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 90e5a9b0bdd844f19a9a7826bf773ed6 +timeCreated: 1785934671 \ No newline at end of file diff --git a/Assets/Code/Tests/Editor.meta b/Assets/Code/Tests/Editor.meta new file mode 100644 index 00000000..ae14c973 --- /dev/null +++ b/Assets/Code/Tests/Editor.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4767eecc89374b629a8ef5e48b5b1090 +timeCreated: 1785937258 \ No newline at end of file diff --git a/Assets/Code/Tests/Editor/CleaningToolsTests.cs b/Assets/Code/Tests/Editor/CleaningToolsTests.cs new file mode 100644 index 00000000..df11f523 --- /dev/null +++ b/Assets/Code/Tests/Editor/CleaningToolsTests.cs @@ -0,0 +1,23 @@ +using Code.D.Cleaning.CleanTools; +using NUnit.Framework; +using UnityEngine; + +namespace Code.Tests.Editor +{ + [TestFixture] + public class CleaningToolsTests + { + [Test] + public void TestTryapkaTool() + { + var tryapka = new Tryapka(0.1f, 0.03f, new Texture2D(100,100)); + + for (int i = 0; i < 10; i++) + { + tryapka.Use(); + } + + Assert.AreEqual(tryapka.IsDirty.CurrentValue, true); + } + } +} \ No newline at end of file diff --git a/Assets/Code/Tests/Editor/CleaningToolsTests.cs.meta b/Assets/Code/Tests/Editor/CleaningToolsTests.cs.meta new file mode 100644 index 00000000..a54497df --- /dev/null +++ b/Assets/Code/Tests/Editor/CleaningToolsTests.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 602a706c78c642dd8e6e8f91e5a0c141 +timeCreated: 1785937303 \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums.meta b/Assets/Code/UserDefinedEnums.meta new file mode 100644 index 00000000..e2d2dba4 --- /dev/null +++ b/Assets/Code/UserDefinedEnums.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: eead7acec5e04960a4d2d8cb4e2637f3 +timeCreated: 1785771040 \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/ActionMappings.cs b/Assets/Code/UserDefinedEnums/ActionMappings.cs new file mode 100644 index 00000000..0bdd512d --- /dev/null +++ b/Assets/Code/UserDefinedEnums/ActionMappings.cs @@ -0,0 +1,21 @@ +namespace Code.Infrastructure.Input +{ + public enum ActionMappings + { + UI, + Cleaning, + } + + public enum CleaningActions + { + Movement, + Watchment, + Crouch, + Walk, + Interact, + Take, + Drop, + Jump, + Clean + } +} \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/ActionMappings.cs.meta b/Assets/Code/UserDefinedEnums/ActionMappings.cs.meta new file mode 100644 index 00000000..7ee92eb4 --- /dev/null +++ b/Assets/Code/UserDefinedEnums/ActionMappings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: dc62fec94fde411ab1420155a5087d64 +timeCreated: 1766613550 \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/AppStates.cs b/Assets/Code/UserDefinedEnums/AppStates.cs new file mode 100644 index 00000000..232eb786 --- /dev/null +++ b/Assets/Code/UserDefinedEnums/AppStates.cs @@ -0,0 +1,7 @@ +namespace Code.Infrastructure.App +{ + public enum AppStates + { + Testing + } +} \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/AppStates.cs.meta b/Assets/Code/UserDefinedEnums/AppStates.cs.meta new file mode 100644 index 00000000..a13b439d --- /dev/null +++ b/Assets/Code/UserDefinedEnums/AppStates.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3248f5dd026e49c6a681c9c043da641c +timeCreated: 1785788293 \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/AudioGroupType.cs b/Assets/Code/UserDefinedEnums/AudioGroupType.cs new file mode 100644 index 00000000..8e8fc282 --- /dev/null +++ b/Assets/Code/UserDefinedEnums/AudioGroupType.cs @@ -0,0 +1,13 @@ +using Code.Infrastructure.Generators; + +namespace Code.Infrastructure.Audio +{ + [AudioMixerEnum] + public enum AudioGroupType + { + Master, + SFX, + Music, + UIFX + } +} \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/AudioGroupType.cs.meta b/Assets/Code/UserDefinedEnums/AudioGroupType.cs.meta new file mode 100644 index 00000000..83116d95 --- /dev/null +++ b/Assets/Code/UserDefinedEnums/AudioGroupType.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8d22b9c06e12c2e8582ac6aab205bfad \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/AudioLODLevel.cs b/Assets/Code/UserDefinedEnums/AudioLODLevel.cs new file mode 100644 index 00000000..0b7310c7 --- /dev/null +++ b/Assets/Code/UserDefinedEnums/AudioLODLevel.cs @@ -0,0 +1,10 @@ +namespace Code.Infrastructure.Audio +{ + public enum AudioLODLevel + { + Interior, + Close, + Distant, + Far + } +} \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/AudioLODLevel.cs.meta b/Assets/Code/UserDefinedEnums/AudioLODLevel.cs.meta new file mode 100644 index 00000000..35cd1f6c --- /dev/null +++ b/Assets/Code/UserDefinedEnums/AudioLODLevel.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 0c90e18e89dcd275b8b2c0a7b199971b \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/AudioPartition.cs b/Assets/Code/UserDefinedEnums/AudioPartition.cs new file mode 100644 index 00000000..6fe9d8bc --- /dev/null +++ b/Assets/Code/UserDefinedEnums/AudioPartition.cs @@ -0,0 +1,9 @@ +namespace Code.Infrastructure.Audio +{ + public enum AudioPartition + { + Music, + UI, + SFX + } +} \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/AudioPartition.cs.meta b/Assets/Code/UserDefinedEnums/AudioPartition.cs.meta new file mode 100644 index 00000000..bfd99e3f --- /dev/null +++ b/Assets/Code/UserDefinedEnums/AudioPartition.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: df6d139ae4f89409fbcb00b85cd5cc6f \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/AudioSourceType.cs b/Assets/Code/UserDefinedEnums/AudioSourceType.cs new file mode 100644 index 00000000..bc0794d6 --- /dev/null +++ b/Assets/Code/UserDefinedEnums/AudioSourceType.cs @@ -0,0 +1,8 @@ +namespace Code.Infrastructure.Audio +{ + public enum AudioSourceType + { + Full3D, + NoBlend + } +} \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/AudioSourceType.cs.meta b/Assets/Code/UserDefinedEnums/AudioSourceType.cs.meta new file mode 100644 index 00000000..4c1544f3 --- /dev/null +++ b/Assets/Code/UserDefinedEnums/AudioSourceType.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2ba7059aee2b4a5bd9afaea65ee0a039 \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/ParticlePartition.cs b/Assets/Code/UserDefinedEnums/ParticlePartition.cs new file mode 100644 index 00000000..98d2d385 --- /dev/null +++ b/Assets/Code/UserDefinedEnums/ParticlePartition.cs @@ -0,0 +1,8 @@ +namespace Code.Infrastructure.Particles +{ + public enum ParticlePartition + { + ProjectileExplosions, + DestroyExplosions, + } +} \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/ParticlePartition.cs.meta b/Assets/Code/UserDefinedEnums/ParticlePartition.cs.meta new file mode 100644 index 00000000..458a2d4e --- /dev/null +++ b/Assets/Code/UserDefinedEnums/ParticlePartition.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d0544f84ac6fa317a988dee2214c572b \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/SceneId.cs b/Assets/Code/UserDefinedEnums/SceneId.cs new file mode 100644 index 00000000..9fc0e214 --- /dev/null +++ b/Assets/Code/UserDefinedEnums/SceneId.cs @@ -0,0 +1,10 @@ +using Code.Infrastructure.Generators; + +namespace Code.Infrastructure.SceneLoader +{ + [SceneIdEnum] + public enum SceneId + { + Testing + } +} \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/SceneId.cs.meta b/Assets/Code/UserDefinedEnums/SceneId.cs.meta new file mode 100644 index 00000000..31b12b49 --- /dev/null +++ b/Assets/Code/UserDefinedEnums/SceneId.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: af1da0e870d542f2a864d7ddbbe9fb4c +timeCreated: 1766396924 \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/UIPanelType.cs b/Assets/Code/UserDefinedEnums/UIPanelType.cs new file mode 100644 index 00000000..cd8e36e7 --- /dev/null +++ b/Assets/Code/UserDefinedEnums/UIPanelType.cs @@ -0,0 +1,8 @@ +namespace Code.Infrastructure.UI +{ + public enum UIPanelType + { + // Cleaning + Cleaning + } +} \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/UIPanelType.cs.meta b/Assets/Code/UserDefinedEnums/UIPanelType.cs.meta new file mode 100644 index 00000000..56ef5d05 --- /dev/null +++ b/Assets/Code/UserDefinedEnums/UIPanelType.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8996c732cb6da50e7bd300bc1e7d2c07 \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/VolumeId.cs b/Assets/Code/UserDefinedEnums/VolumeId.cs new file mode 100644 index 00000000..8c6b6f8a --- /dev/null +++ b/Assets/Code/UserDefinedEnums/VolumeId.cs @@ -0,0 +1,7 @@ +namespace Code.Infrastructure.Volume +{ + public enum VolumeId + { + MenuRetro + } +} \ No newline at end of file diff --git a/Assets/Code/UserDefinedEnums/VolumeId.cs.meta b/Assets/Code/UserDefinedEnums/VolumeId.cs.meta new file mode 100644 index 00000000..8b0f17bf --- /dev/null +++ b/Assets/Code/UserDefinedEnums/VolumeId.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: fc1ca5d8022249c58205c664b7ff628d +timeCreated: 1769169852 \ No newline at end of file diff --git a/Assets/Infrastructure.meta b/Assets/Infrastructure.meta new file mode 100644 index 00000000..9530d497 --- /dev/null +++ b/Assets/Infrastructure.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 93cb0779db5745df2b63ceb1577ede66 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Infrastructure/Audio.meta b/Assets/Infrastructure/Audio.meta new file mode 100644 index 00000000..3e187844 --- /dev/null +++ b/Assets/Infrastructure/Audio.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cf249fc4cac7b9458960ac967b9ce1cd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Infrastructure/Audio/Audio Source.prefab b/Assets/Infrastructure/Audio/Audio Source.prefab new file mode 100644 index 00000000..1948a8e5 --- /dev/null +++ b/Assets/Infrastructure/Audio/Audio Source.prefab @@ -0,0 +1,131 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &4141704314933224767 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3587551500770720074} + - component: {fileID: 8906943801904817571} + m_Layer: 0 + m_Name: Audio Source + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3587551500770720074 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4141704314933224767} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: -0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!82 &8906943801904817571 +AudioSource: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4141704314933224767} + m_Enabled: 1 + serializedVersion: 4 + OutputAudioMixerGroup: {fileID: 0} + m_audioClip: {fileID: 0} + m_Resource: {fileID: 0} + m_PlayOnAwake: 1 + m_Volume: 1 + m_Pitch: 1 + Loop: 0 + Mute: 0 + Spatialize: 0 + SpatializePostEffects: 0 + Priority: 128 + DopplerLevel: 1 + MinDistance: 1 + MaxDistance: 500 + Pan2D: 0 + rolloffMode: 0 + BypassEffects: 0 + BypassListenerEffects: 0 + BypassReverbZones: 0 + rolloffCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + panLevelCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + spreadCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + reverbZoneMixCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 diff --git a/Assets/Infrastructure/Audio/Audio Source.prefab.meta b/Assets/Infrastructure/Audio/Audio Source.prefab.meta new file mode 100644 index 00000000..c8fe22a2 --- /dev/null +++ b/Assets/Infrastructure/Audio/Audio Source.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 23d63858ba5674a208b4577b77319113 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Infrastructure/Audio/AudioMixerSettings.asset b/Assets/Infrastructure/Audio/AudioMixerSettings.asset new file mode 100644 index 00000000..21ee8fd6 --- /dev/null +++ b/Assets/Infrastructure/Audio/AudioMixerSettings.asset @@ -0,0 +1,15 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 89e2ff4d31a24b78b40d9c4e20e1f1bc, type: 3} + m_Name: AudioMixerSettings + m_EditorClassIdentifier: Assembly-CSharp::Code.Infrastructure.Audio.AudioMixerSettings + mixerAsset: {fileID: 24100000, guid: bf2d5153339e5afafb0bdabc1b147628, type: 2} diff --git a/Assets/Infrastructure/Audio/AudioMixerSettings.asset.meta b/Assets/Infrastructure/Audio/AudioMixerSettings.asset.meta new file mode 100644 index 00000000..78ed6afd --- /dev/null +++ b/Assets/Infrastructure/Audio/AudioMixerSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7e53d1050bed148929357759009cc715 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Infrastructure/Audio/AudioSourcePrefab.asset b/Assets/Infrastructure/Audio/AudioSourcePrefab.asset new file mode 100644 index 00000000..d304164b --- /dev/null +++ b/Assets/Infrastructure/Audio/AudioSourcePrefab.asset @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9e812cfdf0544504b47cfe48b621ac4e, type: 3} + m_Name: AudioSourcePrefab + m_EditorClassIdentifier: Assembly-CSharp::Code.Infrastructure.Audio.AudioSourcePrefab + sourcePrefab: + m_AssetGUID: 23d63858ba5674a208b4577b77319113 + m_SubObjectName: + m_SubObjectType: + m_SubObjectGUID: + m_EditorAssetChanged: 0 diff --git a/Assets/Infrastructure/Audio/AudioSourcePrefab.asset.meta b/Assets/Infrastructure/Audio/AudioSourcePrefab.asset.meta new file mode 100644 index 00000000..5a52ff46 --- /dev/null +++ b/Assets/Infrastructure/Audio/AudioSourcePrefab.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2e21bba962bb10f53a41bb8aee11cbb2 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Infrastructure/Audio/Full3DSource.asset b/Assets/Infrastructure/Audio/Full3DSource.asset new file mode 100644 index 00000000..25bb0c45 --- /dev/null +++ b/Assets/Infrastructure/Audio/Full3DSource.asset @@ -0,0 +1,16 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fdbfd61d34d228d088f8be38588cd571, type: 3} + m_Name: Full3DSource + m_EditorClassIdentifier: Assembly-CSharp::Code.Infrastructure.Audio.AudioSourceSettings + spatialBlend: 1 + sourceType: 0 diff --git a/Assets/Infrastructure/Audio/Full3DSource.asset.meta b/Assets/Infrastructure/Audio/Full3DSource.asset.meta new file mode 100644 index 00000000..62b1297a --- /dev/null +++ b/Assets/Infrastructure/Audio/Full3DSource.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4063962b1b4e97ccd90729bd538a1fb4 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Infrastructure/Audio/MainMixer.mixer b/Assets/Infrastructure/Audio/MainMixer.mixer new file mode 100644 index 00000000..b6d5d3ab --- /dev/null +++ b/Assets/Infrastructure/Audio/MainMixer.mixer @@ -0,0 +1,181 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!243 &-7429802166376080216 +AudioMixerGroupController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: UIFX + m_AudioMixer: {fileID: 24100000} + m_GroupID: fdc517d5761b8db9b9fa95354e430a44 + m_Children: [] + m_Volume: b0f00e39997cdedc88e8453521796161 + m_Pitch: c8a5d1589b49f6622be78b1d01dc4b37 + m_Send: 00000000000000000000000000000000 + m_Effects: + - {fileID: -1056152004455092785} + m_UserColorIndex: 0 + m_Mute: 0 + m_Solo: 0 + m_BypassEffects: 0 +--- !u!244 &-1056152004455092785 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: 0d0321c17b5a2864bba09d45d7190d18 + m_EffectName: Attenuation + m_MixLevel: 725a9cc0416153f5b934523cbf97b76c + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!244 &-31783261406540268 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: d2561644492c8a08d96be1a2ab290180 + m_EffectName: Attenuation + m_MixLevel: 896d7174c800d6182a2ee1e599e2712d + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!241 &24100000 +AudioMixerController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: MainMixer + m_OutputGroup: {fileID: 0} + m_MasterGroup: {fileID: 24300002} + m_Snapshots: + - {fileID: 24500006} + m_StartSnapshot: {fileID: 24500006} + m_SuspendThreshold: -80 + m_EnableSuspend: 1 + m_UpdateMode: 0 + m_ExposedParameters: + - guid: aeacc4002c794a1e0a95e702de10fec9 + name: Master + - guid: fd2d9ab03cdaad7d48ebb41ef4e105cf + name: Music + - guid: eef8de3af1d1a5ab78710dce7993c59a + name: SFX + - guid: b0f00e39997cdedc88e8453521796161 + name: UIFX + m_AudioMixerGroupViews: + - guids: + - 663aabe557cfae6bf9135986379e66b8 + - 875e9ea74a80be142915454f07a7a169 + - fdc517d5761b8db9b9fa95354e430a44 + - a77b168a8b1122cc29e355f981a76dea + name: View + m_CurrentViewIndex: 0 + m_TargetSnapshot: {fileID: 24500006} +--- !u!243 &24300002 +AudioMixerGroupController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Master + m_AudioMixer: {fileID: 24100000} + m_GroupID: 663aabe557cfae6bf9135986379e66b8 + m_Children: + - {fileID: 6004818246001997804} + - {fileID: -7429802166376080216} + - {fileID: 3275661087747709516} + m_Volume: aeacc4002c794a1e0a95e702de10fec9 + m_Pitch: 003929af7111d4f378efe2de66a6a290 + m_Send: 00000000000000000000000000000000 + m_Effects: + - {fileID: 24400004} + m_UserColorIndex: 0 + m_Mute: 0 + m_Solo: 0 + m_BypassEffects: 0 +--- !u!244 &24400004 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: 0d2fe4767829cd03d9e8a9aa278b9b0f + m_EffectName: Attenuation + m_MixLevel: 7cc0170e4e2fde43288797a47132e377 + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!245 &24500006 +AudioMixerSnapshotController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Snapshot + m_AudioMixer: {fileID: 24100000} + m_SnapshotID: 30e014f1dd5a0644bbc7855cc19d8f34 + m_FloatValues: {} + m_TransitionOverrides: {} +--- !u!244 &3189508261589768436 +AudioMixerEffectController: + m_ObjectHideFlags: 3 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: + m_EffectID: c52e122916565f9c3b53437277497834 + m_EffectName: Attenuation + m_MixLevel: 95da92ed095059cbc902c8a36df27d54 + m_Parameters: [] + m_SendTarget: {fileID: 0} + m_EnableWetMix: 0 + m_Bypass: 0 +--- !u!243 &3275661087747709516 +AudioMixerGroupController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Music + m_AudioMixer: {fileID: 24100000} + m_GroupID: a77b168a8b1122cc29e355f981a76dea + m_Children: [] + m_Volume: fd2d9ab03cdaad7d48ebb41ef4e105cf + m_Pitch: 0341a29b3620c9bba863d970092f34b7 + m_Send: 00000000000000000000000000000000 + m_Effects: + - {fileID: 3189508261589768436} + m_UserColorIndex: 0 + m_Mute: 0 + m_Solo: 0 + m_BypassEffects: 0 +--- !u!243 &6004818246001997804 +AudioMixerGroupController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: SFX + m_AudioMixer: {fileID: 24100000} + m_GroupID: 875e9ea74a80be142915454f07a7a169 + m_Children: [] + m_Volume: eef8de3af1d1a5ab78710dce7993c59a + m_Pitch: da14106679a19dc04a859d069a541082 + m_Send: 00000000000000000000000000000000 + m_Effects: + - {fileID: -31783261406540268} + m_UserColorIndex: 0 + m_Mute: 0 + m_Solo: 0 + m_BypassEffects: 0 diff --git a/Assets/Infrastructure/Audio/MainMixer.mixer.meta b/Assets/Infrastructure/Audio/MainMixer.mixer.meta new file mode 100644 index 00000000..ce06327d --- /dev/null +++ b/Assets/Infrastructure/Audio/MainMixer.mixer.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bf2d5153339e5afafb0bdabc1b147628 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 24100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Infrastructure/Audio/NoBlendSource.asset b/Assets/Infrastructure/Audio/NoBlendSource.asset new file mode 100644 index 00000000..0728c28c --- /dev/null +++ b/Assets/Infrastructure/Audio/NoBlendSource.asset @@ -0,0 +1,16 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fdbfd61d34d228d088f8be38588cd571, type: 3} + m_Name: NoBlendSource + m_EditorClassIdentifier: Assembly-CSharp::Code.Infrastructure.Audio.AudioSourceSettings + spatialBlend: 0 + sourceType: 1 diff --git a/Assets/Infrastructure/Audio/NoBlendSource.asset.meta b/Assets/Infrastructure/Audio/NoBlendSource.asset.meta new file mode 100644 index 00000000..3b6c6ea5 --- /dev/null +++ b/Assets/Infrastructure/Audio/NoBlendSource.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0ad4fd11028eb24559196762a241834a +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Infrastructure/Bootstrap.unity b/Assets/Infrastructure/Bootstrap.unity new file mode 100644 index 00000000..5bf42ec4 --- /dev/null +++ b/Assets/Infrastructure/Bootstrap.unity @@ -0,0 +1,353 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 10 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0, g: 0, b: 0, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0, g: 0, b: 0, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 1 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 2 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 1 + m_PVRFilteringGaussRadiusAO: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &572614179 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 572614180} + - component: {fileID: 572614182} + - component: {fileID: 572614181} + m_Layer: 5 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &572614180 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 572614179} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1882035660} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &572614181 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 572614179} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 01614664b831546d2ae94a42149d80ac, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.InputSystem::UnityEngine.InputSystem.UI.InputSystemUIInputModule + m_SendPointerHoverToParent: 1 + m_MoveRepeatDelay: 0.5 + m_MoveRepeatRate: 0.1 + m_XRTrackingOrigin: {fileID: 0} + m_ActionsAsset: {fileID: -944628639613478452, guid: 052faaac586de48259a63d0c4782560b, type: 3} + m_PointAction: {fileID: -4941704798450900507, guid: 052faaac586de48259a63d0c4782560b, type: 3} + m_MoveAction: {fileID: 8517769201737652018, guid: 052faaac586de48259a63d0c4782560b, type: 3} + m_SubmitAction: {fileID: -6797543698261162040, guid: 052faaac586de48259a63d0c4782560b, type: 3} + m_CancelAction: {fileID: 8589568661092742892, guid: 052faaac586de48259a63d0c4782560b, type: 3} + m_LeftClickAction: {fileID: -3524507381045633928, guid: 052faaac586de48259a63d0c4782560b, type: 3} + m_MiddleClickAction: {fileID: 4067208702748641927, guid: 052faaac586de48259a63d0c4782560b, type: 3} + m_RightClickAction: {fileID: 3365605549075805472, guid: 052faaac586de48259a63d0c4782560b, type: 3} + m_ScrollWheelAction: {fileID: -1441784132718050532, guid: 052faaac586de48259a63d0c4782560b, type: 3} + m_TrackedDevicePositionAction: {fileID: -2696365092829278462, guid: 052faaac586de48259a63d0c4782560b, type: 3} + m_TrackedDeviceOrientationAction: {fileID: 7755751760002662814, guid: 052faaac586de48259a63d0c4782560b, type: 3} + m_DeselectOnBackgroundClick: 1 + m_PointerBehavior: 0 + m_CursorLockBehavior: 0 + m_ScrollDeltaPerTick: 6 +--- !u!114 &572614182 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 572614179} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.EventSystems.EventSystem + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!1 &1143616099 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1143616101} + - component: {fileID: 1143616100} + m_Layer: 0 + m_Name: SceneScope + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1143616100 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1143616099} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5312032623c34414a54ea00e35a7eb8e, type: 3} + m_Name: + m_EditorClassIdentifier: Reflex::Reflex.Core.ContainerScope +--- !u!4 &1143616101 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1143616099} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1882035656 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1882035660} + - component: {fileID: 1882035659} + - component: {fileID: 1882035658} + - component: {fileID: 1882035657} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1882035657 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1882035656} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.GraphicRaycaster + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &1882035658 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1882035656} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: UnityEngine.UI::UnityEngine.UI.CanvasScaler + m_UiScaleMode: 1 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 1280, y: 720} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &1882035659 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1882035656} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_VertexColorAlwaysGammaSpace: 0 + m_UseReflectionProbes: 0 + m_AdditionalShaderChannelsFlag: 0 + m_UpdateRectTransformForStandalone: 0 + m_SortingLayerID: 0 + m_SortingOrder: 1 + m_TargetDisplay: 0 +--- !u!224 &1882035660 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1882035656} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 572614180} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 1143616101} + - {fileID: 1882035660} diff --git a/Assets/Infrastructure/Bootstrap.unity.meta b/Assets/Infrastructure/Bootstrap.unity.meta new file mode 100644 index 00000000..89f2cba6 --- /dev/null +++ b/Assets/Infrastructure/Bootstrap.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 39c007cb2d91bab9092a107e9575b736 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Infrastructure/Camera.meta b/Assets/Infrastructure/Camera.meta new file mode 100644 index 00000000..3485287a --- /dev/null +++ b/Assets/Infrastructure/Camera.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 150daa8d23d65703488f4a076e35ca94 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Infrastructure/Camera/GameCamera.asset b/Assets/Infrastructure/Camera/GameCamera.asset new file mode 100644 index 00000000..eed95afd --- /dev/null +++ b/Assets/Infrastructure/Camera/GameCamera.asset @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8bbd78d2335f4e55945f1e56ff536200, type: 3} + m_Name: GameCamera + m_EditorClassIdentifier: Assembly-CSharp::Code.Infrastructure.Camera.GameCamera + FieldOfView: 60 + NearClip: 0.01 + FarClip: 1000 + PostProcessing: 1 + RenderShadows: 1 + ClearFlags: 4 diff --git a/Assets/Infrastructure/Camera/GameCamera.asset.meta b/Assets/Infrastructure/Camera/GameCamera.asset.meta new file mode 100644 index 00000000..98edf05e --- /dev/null +++ b/Assets/Infrastructure/Camera/GameCamera.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0e4f435f78018b832b63442391e12c8b +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Infrastructure/Input.meta b/Assets/Infrastructure/Input.meta new file mode 100644 index 00000000..e5364cfe --- /dev/null +++ b/Assets/Infrastructure/Input.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d97da6f397c32b365b42b4733314d925 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Infrastructure/Input/ActionMap.inputactions b/Assets/Infrastructure/Input/ActionMap.inputactions new file mode 100644 index 00000000..47e65721 --- /dev/null +++ b/Assets/Infrastructure/Input/ActionMap.inputactions @@ -0,0 +1,776 @@ +{ + "version": 1, + "name": "ActionMap", + "maps": [ + { + "name": "UI", + "id": "45521ad3-b2df-4f35-9f02-85d906f367df", + "actions": [ + { + "name": "Navigate", + "type": "PassThrough", + "id": "f9f76167-f90a-4a37-a570-83f3d09feb30", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Submit", + "type": "Button", + "id": "a5a3f311-6226-41d1-b2ac-97c613b82f30", + "expectedControlType": "", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Cancel", + "type": "Button", + "id": "dd2afbe2-187f-44a9-81af-8f6534ec4853", + "expectedControlType": "", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Point", + "type": "PassThrough", + "id": "0ed7b2a9-2386-49fd-bcd1-5fda018b9b82", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "Click", + "type": "PassThrough", + "id": "2360c89d-c05a-45ad-996d-e20e1ad5290b", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "ScrollWheel", + "type": "PassThrough", + "id": "81566102-3fca-462f-b172-b4b872c02ea3", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "MiddleClick", + "type": "PassThrough", + "id": "c120dd12-11a7-4cc5-bd60-535e153c66e0", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "RightClick", + "type": "PassThrough", + "id": "c1c6923a-69f9-4204-ad3f-4d4621cd1c9f", + "expectedControlType": "Button", + "processors": "", + "interactions": "", + "initialStateCheck": false + } + ], + "bindings": [ + { + "name": "Gamepad", + "id": "ec8020b3-b137-48a4-bce1-7021c702e8b9", + "path": "2DVector", + "interactions": "", + "processors": "", + "groups": "", + "action": "Navigate", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "a7594b37-8ab6-4cce-8ca5-9d0f84888414", + "path": "/leftStick/up", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "up", + "id": "edb36a40-12bf-4689-bb7d-6b66bc78f940", + "path": "/rightStick/up", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "87b7d5a6-5a53-43bb-85ed-2d5722894343", + "path": "/leftStick/down", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "c48efd73-537b-4bdd-a6c8-53c703e7f9b6", + "path": "/rightStick/down", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "9b2d498e-538a-4676-b182-632a1d7ba0d1", + "path": "/leftStick/left", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "445df771-6d46-4caa-89f1-9af31ee1a479", + "path": "/rightStick/left", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "97f45796-bba3-472f-a4de-b92505f2cf61", + "path": "/leftStick/right", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "df7bc431-a7d4-4295-836f-54953badcf9d", + "path": "/rightStick/right", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "", + "id": "f7eda4d4-6064-410a-8d36-42a074fb0b0c", + "path": "/dpad", + "interactions": "", + "processors": "", + "groups": ";Gamepad", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "Joystick", + "id": "fe6f6f10-708f-416f-8b9a-58e0430c8d58", + "path": "2DVector", + "interactions": "", + "processors": "", + "groups": "", + "action": "Navigate", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "d799451c-ce46-4e51-98f4-85a2bf4eeb79", + "path": "/stick/up", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "25fc3b55-f07d-4c46-9e43-030364507d75", + "path": "/stick/down", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "12e89f13-b8ea-446c-a4bc-de36e6e5ec3f", + "path": "/stick/left", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "75037a3e-5bea-47f5-8d7c-1cd3aa7788a1", + "path": "/stick/right", + "interactions": "", + "processors": "", + "groups": "Joystick", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "Keyboard", + "id": "70610bdd-eea4-474d-83cd-3d50127d0c02", + "path": "2DVector", + "interactions": "", + "processors": "", + "groups": "", + "action": "Navigate", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "7553342b-c040-48d9-b4bd-d76b31db6a3c", + "path": "/w", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "up", + "id": "d661f361-72dd-460c-83ec-ea84f19b62a5", + "path": "/upArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "555b4879-43df-48f6-8cae-7241512c25f8", + "path": "/s", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "72c4b9b1-d3e6-4588-b309-0b56001aaf40", + "path": "/downArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "032e1379-53e0-4c9f-8e51-140974bb254e", + "path": "/a", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "7af4e4cf-b01c-46ac-bd40-5aa71f02269b", + "path": "/leftArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "db0ccb18-0194-4947-ac21-edf0afb3509d", + "path": "/d", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "05939f2d-a613-482d-909b-7e82e4520755", + "path": "/rightArrow", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Navigate", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "", + "id": "e520fd11-3b37-4168-adda-ce9b8a02790c", + "path": "*/{Submit}", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse;Gamepad;Touch;Joystick;XR", + "action": "Submit", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "1be1bc37-81e7-4730-ac7c-591a489bf3c6", + "path": "*/{Cancel}", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse;Gamepad;Touch;Joystick;XR", + "action": "Cancel", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "07ef5aa8-d381-40b4-ba0e-0e87fed53a4e", + "path": "/position", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Point", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "dc969216-88ba-4fbf-95f2-372d98c6c327", + "path": "/position", + "interactions": "", + "processors": "", + "groups": "Keyboard&Mouse", + "action": "Point", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "ed530faa-b2ff-4d42-811c-78179e436a3c", + "path": "/touch*/position", + "interactions": "", + "processors": "", + "groups": "Touch", + "action": "Point", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "5a7e8cce-fef9-4f73-9679-7b04aa3f8566", + "path": "/leftButton", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "0750cb4b-8403-4ce2-8edd-9b1a86c8a338", + "path": "/tip", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "66c7e5aa-b2d3-4989-8edb-3e8ea48352b7", + "path": "/touch*/press", + "interactions": "", + "processors": "", + "groups": "Touch", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "6ff9501c-0e7e-423e-9067-ff4b39742a11", + "path": "/trigger", + "interactions": "", + "processors": "", + "groups": "XR", + "action": "Click", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "78bf1d29-d2c4-475a-a313-7f6e96873d2c", + "path": "/scroll", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "ScrollWheel", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "ba4b77f7-a1cf-40c5-a4f6-49b99ffc86cf", + "path": "/middleButton", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "MiddleClick", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "cb5fcee5-a389-4271-8a77-b4b3ef8c60b8", + "path": "/rightButton", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "RightClick", + "isComposite": false, + "isPartOfComposite": false + } + ] + }, + { + "name": "Cleaning", + "id": "9b5783a8-3bd0-4660-a836-089d0ab5acbd", + "actions": [ + { + "name": "Movement", + "type": "Value", + "id": "68bcfd88-01df-4b47-8b32-8f60c8e09d43", + "expectedControlType": "Vector2", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "Watchment", + "type": "Value", + "id": "4b3366aa-cec1-455e-bd9a-6cb067d80a8c", + "expectedControlType": "Delta", + "processors": "", + "interactions": "", + "initialStateCheck": true + }, + { + "name": "Crouch", + "type": "Button", + "id": "e3f8e65f-a85e-4a90-ade1-b09c2c52810f", + "expectedControlType": "", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Walk", + "type": "Button", + "id": "62929910-41d3-4a33-9722-d819ef81a706", + "expectedControlType": "", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Interact", + "type": "Button", + "id": "286bd00a-264b-44da-bf61-9d99b1daa6a5", + "expectedControlType": "", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Take", + "type": "Button", + "id": "712d9e66-4567-47a1-a4aa-4dbb3106b668", + "expectedControlType": "", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Drop", + "type": "Button", + "id": "9f1618a8-e036-4125-b169-704225a8e09a", + "expectedControlType": "", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Jump", + "type": "Button", + "id": "898d85b4-4556-425b-a4ae-8a39c5954807", + "expectedControlType": "", + "processors": "", + "interactions": "", + "initialStateCheck": false + }, + { + "name": "Clean", + "type": "Button", + "id": "db64e1b2-b344-43db-bf34-6925d6607170", + "expectedControlType": "", + "processors": "", + "interactions": "", + "initialStateCheck": false + } + ], + "bindings": [ + { + "name": "2D Vector", + "id": "c7b0f48a-f6fa-4848-aca6-e4cdface5703", + "path": "2DVector", + "interactions": "", + "processors": "", + "groups": "", + "action": "Movement", + "isComposite": true, + "isPartOfComposite": false + }, + { + "name": "up", + "id": "27adc1b7-54b2-4892-8399-624105edbf97", + "path": "/w", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Movement", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "down", + "id": "df8c8996-7f01-43e6-90c3-b9d3f1d26d16", + "path": "/s", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Movement", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "left", + "id": "42b18e8f-a2e7-431a-a44d-b609fb09f77d", + "path": "/a", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Movement", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "right", + "id": "22a18c7f-fa96-4567-badf-a137b12e4cac", + "path": "/d", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Movement", + "isComposite": false, + "isPartOfComposite": true + }, + { + "name": "", + "id": "7bdc0903-6f32-4c0a-9671-d70fc5ab621e", + "path": "/leftButton", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Clean", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "297ef31b-bce3-44eb-b57d-89fa5aee2932", + "path": "/delta", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Watchment", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "d04f1334-e9fd-4483-ac64-4108c6a27403", + "path": "/leftCtrl", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Crouch", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "cb70698d-88a3-4e41-a1c5-3a7d1d4037c6", + "path": "/alt", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Walk", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "9c5576e6-9215-4af4-8a2f-b5898b44535d", + "path": "/e", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Interact", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "4ebb4981-6ca4-4ca6-97bc-cf355df6eb5e", + "path": "/f", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Take", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "77114e38-bdc7-4354-b195-439bc22a3398", + "path": "/q", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Drop", + "isComposite": false, + "isPartOfComposite": false + }, + { + "name": "", + "id": "c5d8ba95-fc42-417b-b5fa-1745ca703f69", + "path": "/space", + "interactions": "", + "processors": "", + "groups": ";Keyboard&Mouse", + "action": "Jump", + "isComposite": false, + "isPartOfComposite": false + } + ] + } + ], + "controlSchemes": [ + { + "name": "Keyboard&Mouse", + "bindingGroup": "Keyboard&Mouse", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + }, + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "Gamepad", + "bindingGroup": "Gamepad", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "Touch", + "bindingGroup": "Touch", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "Joystick", + "bindingGroup": "Joystick", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + }, + { + "name": "XR", + "bindingGroup": "XR", + "devices": [ + { + "devicePath": "", + "isOptional": false, + "isOR": false + } + ] + } + ] +} \ No newline at end of file diff --git a/Assets/Infrastructure/Input/ActionMap.inputactions.meta b/Assets/Infrastructure/Input/ActionMap.inputactions.meta new file mode 100644 index 00000000..6b38b043 --- /dev/null +++ b/Assets/Infrastructure/Input/ActionMap.inputactions.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: 052faaac586de48259a63d0c4782560b +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 8404be70184654265930450def6a9037, type: 3} + generateWrapperCode: 0 + wrapperCodePath: + wrapperClassName: + wrapperCodeNamespace: diff --git a/Assets/Infrastructure/Input/InputService.asset b/Assets/Infrastructure/Input/InputService.asset new file mode 100644 index 00000000..e5000e0d --- /dev/null +++ b/Assets/Infrastructure/Input/InputService.asset @@ -0,0 +1,15 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a3fe014c5e7645708654c530a664a11d, type: 3} + m_Name: InputService + m_EditorClassIdentifier: Assembly-CSharp::Code.Infrastructure.Input.InputServiceConfig + inputActionAsset: {fileID: -944628639613478452, guid: 052faaac586de48259a63d0c4782560b, type: 3} diff --git a/Assets/Infrastructure/Input/InputService.asset.meta b/Assets/Infrastructure/Input/InputService.asset.meta new file mode 100644 index 00000000..3fb05c01 --- /dev/null +++ b/Assets/Infrastructure/Input/InputService.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e92086276d9b32213abd64903ad4b730 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Infrastructure/UI.meta b/Assets/Infrastructure/UI.meta new file mode 100644 index 00000000..908ca3b3 --- /dev/null +++ b/Assets/Infrastructure/UI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0b243d29a97df79429ee745d340a478a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Infrastructure/UI/BlankPanel.prefab b/Assets/Infrastructure/UI/BlankPanel.prefab new file mode 100644 index 00000000..9bf1bae7 --- /dev/null +++ b/Assets/Infrastructure/UI/BlankPanel.prefab @@ -0,0 +1,37 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &6954848672672011412 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2206152566286397088} + m_Layer: 5 + m_Name: BlankPanel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2206152566286397088 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6954848672672011412} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} diff --git a/Assets/Infrastructure/UI/BlankPanel.prefab.meta b/Assets/Infrastructure/UI/BlankPanel.prefab.meta new file mode 100644 index 00000000..1585825c --- /dev/null +++ b/Assets/Infrastructure/UI/BlankPanel.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 81ffb445dd84fb086a5447a4841d4486 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Infrastructure/UI/CanvasSettings.asset b/Assets/Infrastructure/UI/CanvasSettings.asset new file mode 100644 index 00000000..4f17985c --- /dev/null +++ b/Assets/Infrastructure/UI/CanvasSettings.asset @@ -0,0 +1,20 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d23873b1c0034bf89886915f997b2f9a, type: 3} + m_Name: CanvasSettings + m_EditorClassIdentifier: Assembly-CSharp::Code.Infrastructure.UI.CanvasSettings + RenderMode: 1 + OrderInLayer: 0 + ScaleMode: 1 + ReferenceResolutionX: 1280 + ReferenceResolutionY: 720 + PlaneDistance: 0.011 diff --git a/Assets/Infrastructure/UI/CanvasSettings.asset.meta b/Assets/Infrastructure/UI/CanvasSettings.asset.meta new file mode 100644 index 00000000..efeadef6 --- /dev/null +++ b/Assets/Infrastructure/UI/CanvasSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1d088f052c2092d1f9cb64b3a16f5779 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/KinematicCharacterController.meta b/Assets/KinematicCharacterController.meta new file mode 100644 index 00000000..95ea513d --- /dev/null +++ b/Assets/KinematicCharacterController.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 66078219645bc69d39585d82783435b1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/KinematicCharacterController/APIReference.zip b/Assets/KinematicCharacterController/APIReference.zip new file mode 100644 index 0000000000000000000000000000000000000000..793e271e37772f466adf166bfd530b314f81abc5 GIT binary patch literal 276699 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

%4 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 z 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�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 HGYS6>16K!T literal 0 HcmV?d00001 diff --git a/Assets/KinematicCharacterController/APIReference.zip.meta b/Assets/KinematicCharacterController/APIReference.zip.meta new file mode 100644 index 00000000..2ada889b --- /dev/null +++ b/Assets/KinematicCharacterController/APIReference.zip.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: aadf824e76564404c8d43d99803c60a1 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 99131 + packageName: Kinematic Character Controller + packageVersion: 3.4.4 + assetPath: Assets/KinematicCharacterController/APIReference.zip + uploadId: 505601 diff --git a/Assets/KinematicCharacterController/Core.meta b/Assets/KinematicCharacterController/Core.meta new file mode 100644 index 00000000..fe4fdf56 --- /dev/null +++ b/Assets/KinematicCharacterController/Core.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: c8854cb84deea8146b0cc7833ff338fd +folderAsset: yes +timeCreated: 1499134826 +licenseType: Store +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/KinematicCharacterController/Core/Editor.meta b/Assets/KinematicCharacterController/Core/Editor.meta new file mode 100644 index 00000000..965efb3a --- /dev/null +++ b/Assets/KinematicCharacterController/Core/Editor.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 220667f043f505a4eb52d0208e14818e +folderAsset: yes +timeCreated: 1504492780 +licenseType: Store +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/KinematicCharacterController/Core/Editor/KinematicCharacterMotorEditor.cs b/Assets/KinematicCharacterController/Core/Editor/KinematicCharacterMotorEditor.cs new file mode 100644 index 00000000..12eb811a --- /dev/null +++ b/Assets/KinematicCharacterController/Core/Editor/KinematicCharacterMotorEditor.cs @@ -0,0 +1,28 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEditor; + +namespace KinematicCharacterController +{ + [CustomEditor(typeof(KinematicCharacterMotor))] + public class KinematicCharacterMotorEditor : Editor + { + protected virtual void OnSceneGUI() + { + KinematicCharacterMotor motor = (target as KinematicCharacterMotor); + if (motor) + { + Vector3 characterBottom = motor.transform.position + (motor.Capsule.center + (-Vector3.up * (motor.Capsule.height * 0.5f))); + + Handles.color = Color.yellow; + Handles.CircleHandleCap( + 0, + characterBottom + (motor.transform.up * motor.MaxStepHeight), + Quaternion.LookRotation(motor.transform.up, motor.transform.forward), + motor.Capsule.radius + 0.1f, + EventType.Repaint); + } + } + } +} \ No newline at end of file diff --git a/Assets/KinematicCharacterController/Core/Editor/KinematicCharacterMotorEditor.cs.meta b/Assets/KinematicCharacterController/Core/Editor/KinematicCharacterMotorEditor.cs.meta new file mode 100644 index 00000000..b7ca7619 --- /dev/null +++ b/Assets/KinematicCharacterController/Core/Editor/KinematicCharacterMotorEditor.cs.meta @@ -0,0 +1,20 @@ +fileFormatVersion: 2 +guid: 7db3ed6d74cbf2b489cab5e1586bed7a +timeCreated: 1518400757 +licenseType: Store +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 99131 + packageName: Kinematic Character Controller + packageVersion: 3.4.4 + assetPath: Assets/KinematicCharacterController/Core/Editor/KinematicCharacterMotorEditor.cs + uploadId: 505601 diff --git a/Assets/KinematicCharacterController/Core/Editor/ReadOnlyPropertyDrawer.cs b/Assets/KinematicCharacterController/Core/Editor/ReadOnlyPropertyDrawer.cs new file mode 100644 index 00000000..5a1aa7cd --- /dev/null +++ b/Assets/KinematicCharacterController/Core/Editor/ReadOnlyPropertyDrawer.cs @@ -0,0 +1,21 @@ +using UnityEngine; +using UnityEditor; + +namespace KinematicCharacterController +{ + [CustomPropertyDrawer(typeof(ReadOnlyAttribute))] + public class ReadOnlyPropertyDrawer : PropertyDrawer + { + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return EditorGUI.GetPropertyHeight(property, label, true); + } + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + GUI.enabled = false; + EditorGUI.PropertyField(position, property, label, true); + GUI.enabled = true; + } + } +} \ No newline at end of file diff --git a/Assets/KinematicCharacterController/Core/Editor/ReadOnlyPropertyDrawer.cs.meta b/Assets/KinematicCharacterController/Core/Editor/ReadOnlyPropertyDrawer.cs.meta new file mode 100644 index 00000000..07739469 --- /dev/null +++ b/Assets/KinematicCharacterController/Core/Editor/ReadOnlyPropertyDrawer.cs.meta @@ -0,0 +1,20 @@ +fileFormatVersion: 2 +guid: 0d4351ab88853824b85a8f458928d825 +timeCreated: 1504492796 +licenseType: Store +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 99131 + packageName: Kinematic Character Controller + packageVersion: 3.4.4 + assetPath: Assets/KinematicCharacterController/Core/Editor/ReadOnlyPropertyDrawer.cs + uploadId: 505601 diff --git a/Assets/KinematicCharacterController/Core/ICharacterController.cs b/Assets/KinematicCharacterController/Core/ICharacterController.cs new file mode 100644 index 00000000..4ae54acf --- /dev/null +++ b/Assets/KinematicCharacterController/Core/ICharacterController.cs @@ -0,0 +1,50 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace KinematicCharacterController +{ + public interface ICharacterController + { + ///

+ /// This is called when the motor wants to know what its rotation should be right now + /// + void UpdateRotation(ref Quaternion currentRotation, float deltaTime); + /// + /// This is called when the motor wants to know what its velocity should be right now + /// + void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime); + /// + /// This is called before the motor does anything + /// + void BeforeCharacterUpdate(float deltaTime); + /// + /// This is called after the motor has finished its ground probing, but before PhysicsMover/Velocity/etc.... handling + /// + void PostGroundingUpdate(float deltaTime); + /// + /// This is called after the motor has finished everything in its update + /// + void AfterCharacterUpdate(float deltaTime); + /// + /// This is called after when the motor wants to know if the collider can be collided with (or if we just go through it) + /// + bool IsColliderValidForCollisions(Collider coll); + /// + /// This is called when the motor's ground probing detects a ground hit + /// + void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport); + /// + /// This is called when the motor's movement logic detects a hit + /// + void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport); + /// + /// This is called after every move hit, to give you an opportunity to modify the HitStabilityReport to your liking + /// + void ProcessHitStabilityReport(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, Vector3 atCharacterPosition, Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport); + /// + /// This is called when the character detects discrete collisions (collisions that don't result from the motor's capsuleCasts when moving) + /// + void OnDiscreteCollisionDetected(Collider hitCollider); + } +} \ No newline at end of file diff --git a/Assets/KinematicCharacterController/Core/ICharacterController.cs.meta b/Assets/KinematicCharacterController/Core/ICharacterController.cs.meta new file mode 100644 index 00000000..4a36db8d --- /dev/null +++ b/Assets/KinematicCharacterController/Core/ICharacterController.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: f13aa252bd3bf9943b1d65e68d93dcfb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 99131 + packageName: Kinematic Character Controller + packageVersion: 3.4.4 + assetPath: Assets/KinematicCharacterController/Core/ICharacterController.cs + uploadId: 505601 diff --git a/Assets/KinematicCharacterController/Core/IMoverController.cs b/Assets/KinematicCharacterController/Core/IMoverController.cs new file mode 100644 index 00000000..f582ec1e --- /dev/null +++ b/Assets/KinematicCharacterController/Core/IMoverController.cs @@ -0,0 +1,14 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace KinematicCharacterController +{ + public interface IMoverController + { + /// + /// This is called to let you tell the PhysicsMover where it should be right now + /// + void UpdateMovement(out Vector3 goalPosition, out Quaternion goalRotation, float deltaTime); + } +} \ No newline at end of file diff --git a/Assets/KinematicCharacterController/Core/IMoverController.cs.meta b/Assets/KinematicCharacterController/Core/IMoverController.cs.meta new file mode 100644 index 00000000..4281edf8 --- /dev/null +++ b/Assets/KinematicCharacterController/Core/IMoverController.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 8ae7eceec45f1be4c8450edc46c0ad36 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 99131 + packageName: Kinematic Character Controller + packageVersion: 3.4.4 + assetPath: Assets/KinematicCharacterController/Core/IMoverController.cs + uploadId: 505601 diff --git a/Assets/KinematicCharacterController/Core/KCCSettings.cs b/Assets/KinematicCharacterController/Core/KCCSettings.cs new file mode 100644 index 00000000..23e68481 --- /dev/null +++ b/Assets/KinematicCharacterController/Core/KCCSettings.cs @@ -0,0 +1,33 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace KinematicCharacterController +{ + [CreateAssetMenu] + public class KCCSettings : ScriptableObject + { + /// + /// Determines if the system simulates automatically. + /// If true, the simulation is done on FixedUpdate + /// + [Tooltip("Determines if the system simulates automatically. If true, the simulation is done on FixedUpdate")] + public bool AutoSimulation = true; + /// + /// Should interpolation of characters and PhysicsMovers be handled + /// + [Tooltip("Should interpolation of characters and PhysicsMovers be handled")] + public bool Interpolate = true; + /// + + /// Initial capacity of the system's list of Motors (will resize automatically if needed, but setting a high initial capacity can help preventing GC allocs) + /// + [Tooltip("Initial capacity of the system's list of Motors (will resize automatically if needed, but setting a high initial capacity can help preventing GC allocs)")] + public int MotorsListInitialCapacity = 100; + /// + /// Initial capacity of the system's list of Movers (will resize automatically if needed, but setting a high initial capacity can help preventing GC allocs) + /// + [Tooltip("Initial capacity of the system's list of Movers (will resize automatically if needed, but setting a high initial capacity can help preventing GC allocs)")] + public int MoversListInitialCapacity = 100; + } +} \ No newline at end of file diff --git a/Assets/KinematicCharacterController/Core/KCCSettings.cs.meta b/Assets/KinematicCharacterController/Core/KCCSettings.cs.meta new file mode 100644 index 00000000..e7ea95fc --- /dev/null +++ b/Assets/KinematicCharacterController/Core/KCCSettings.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 2b43d8459fe4812488b2c47ac60e41c3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 99131 + packageName: Kinematic Character Controller + packageVersion: 3.4.4 + assetPath: Assets/KinematicCharacterController/Core/KCCSettings.cs + uploadId: 505601 diff --git a/Assets/KinematicCharacterController/Core/KinematicCharacterMotor.cs b/Assets/KinematicCharacterController/Core/KinematicCharacterMotor.cs new file mode 100644 index 00000000..ff09738a --- /dev/null +++ b/Assets/KinematicCharacterController/Core/KinematicCharacterMotor.cs @@ -0,0 +1,2691 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace KinematicCharacterController +{ + public enum RigidbodyInteractionType + { + None, + Kinematic, + SimulatedDynamic + } + + public enum StepHandlingMethod + { + None, + Standard, + Extra + } + + public enum MovementSweepState + { + Initial, + AfterFirstHit, + FoundBlockingCrease, + FoundBlockingCorner, + } + + /// + /// Represents the entire state of a character motor that is pertinent for simulation. + /// Use this to save state or revert to past state + /// + [System.Serializable] + public struct KinematicCharacterMotorState + { + public Vector3 Position; + public Quaternion Rotation; + public Vector3 BaseVelocity; + + public bool MustUnground; + public float MustUngroundTime; + public bool LastMovementIterationFoundAnyGround; +#pragma warning disable UAC1001 + public CharacterTransientGroundingReport GroundingStatus; +#pragma warning restore UAC1001 + + public Rigidbody AttachedRigidbody; + public Vector3 AttachedRigidbodyVelocity; + } + + /// + /// Describes an overlap between the character capsule and another collider + /// + public struct OverlapResult + { + public Vector3 Normal; + public Collider Collider; + + public OverlapResult(Vector3 normal, Collider collider) + { + Normal = normal; + Collider = collider; + } + } + + /// + /// Contains all the information for the motor's grounding status + /// + public struct CharacterGroundingReport + { + public bool FoundAnyGround; + public bool IsStableOnGround; + public bool SnappingPrevented; + public Vector3 GroundNormal; + public Vector3 InnerGroundNormal; + public Vector3 OuterGroundNormal; + + public Collider GroundCollider; + public Vector3 GroundPoint; + + public void CopyFrom(CharacterTransientGroundingReport transientGroundingReport) + { + FoundAnyGround = transientGroundingReport.FoundAnyGround; + IsStableOnGround = transientGroundingReport.IsStableOnGround; + SnappingPrevented = transientGroundingReport.SnappingPrevented; + GroundNormal = transientGroundingReport.GroundNormal; + InnerGroundNormal = transientGroundingReport.InnerGroundNormal; + OuterGroundNormal = transientGroundingReport.OuterGroundNormal; + + GroundCollider = null; + GroundPoint = Vector3.zero; + } + } + + /// + /// Contains the simulation-relevant information for the motor's grounding status + /// + public struct CharacterTransientGroundingReport + { + public bool FoundAnyGround; + public bool IsStableOnGround; + public bool SnappingPrevented; + public Vector3 GroundNormal; + public Vector3 InnerGroundNormal; + public Vector3 OuterGroundNormal; + + public void CopyFrom(CharacterGroundingReport groundingReport) + { + FoundAnyGround = groundingReport.FoundAnyGround; + IsStableOnGround = groundingReport.IsStableOnGround; + SnappingPrevented = groundingReport.SnappingPrevented; + GroundNormal = groundingReport.GroundNormal; + InnerGroundNormal = groundingReport.InnerGroundNormal; + OuterGroundNormal = groundingReport.OuterGroundNormal; + } + } + + /// + /// Contains all the information from a hit stability evaluation + /// + public struct HitStabilityReport + { + public bool IsStable; + + public bool FoundInnerNormal; + public Vector3 InnerNormal; + public bool FoundOuterNormal; + public Vector3 OuterNormal; + + public bool ValidStepDetected; + public Collider SteppedCollider; + + public bool LedgeDetected; + public bool IsOnEmptySideOfLedge; + public float DistanceFromLedge; + public bool IsMovingTowardsEmptySideOfLedge; + public Vector3 LedgeGroundNormal; + public Vector3 LedgeRightDirection; + public Vector3 LedgeFacingDirection; + } + + /// + /// Contains the information of hit rigidbodies during the movement phase, so they can be processed afterwards + /// + public struct RigidbodyProjectionHit + { + public Rigidbody Rigidbody; + public Vector3 HitPoint; + public Vector3 EffectiveHitNormal; + public Vector3 HitVelocity; + public bool StableOnHit; + } + + /// + /// Component that manages character collisions and movement solving + /// + [RequireComponent(typeof(CapsuleCollider))] + public class KinematicCharacterMotor : MonoBehaviour + { +#pragma warning disable 0414 + [Header("Components")] + /// + /// The capsule collider of this motor + /// + [ReadOnly] + public CapsuleCollider Capsule; + + [Header("Capsule Settings")] + /// + /// Radius of the character's capsule + /// + [SerializeField] + [Tooltip("Radius of the Character Capsule")] + private float CapsuleRadius = 0.5f; + /// + /// Height of the character's capsule + /// + [SerializeField] + [Tooltip("Height of the Character Capsule")] + private float CapsuleHeight = 2f; + /// + /// Local y position of the character's capsule center + /// + [SerializeField] + [Tooltip("Height of the Character Capsule")] + private float CapsuleYOffset = 1f; + /// + /// Physics material of the character's capsule + /// + [SerializeField] + [Tooltip("Physics material of the Character Capsule (Does not affect character movement. Only affects things colliding with it)")] +#pragma warning disable 0649 + private PhysicsMaterial CapsulePhysicsMaterial; +#pragma warning restore 0649 + + + [Header("Grounding settings")] + /// + /// Increases the range of ground detection, to allow snapping to ground at very high speeds + /// + [Tooltip("Increases the range of ground detection, to allow snapping to ground at very high speeds")] + public float GroundDetectionExtraDistance = 0f; + /// + /// Maximum slope angle on which the character can be stable + /// + [Range(0f, 89f)] + [Tooltip("Maximum slope angle on which the character can be stable")] + public float MaxStableSlopeAngle = 60f; + /// + /// Which layers can the character be considered stable on + /// + [Tooltip("Which layers can the character be considered stable on")] + public LayerMask StableGroundLayers = -1; + /// + /// Notifies the Character Controller when discrete collisions are detected + /// + [Tooltip("Notifies the Character Controller when discrete collisions are detected")] + public bool DiscreteCollisionEvents = false; + + + [Header("Step settings")] + /// + /// Handles properly detecting grounding status on steps, but has a performance cost. + /// + [Tooltip("Handles properly detecting grounding status on steps, but has a performance cost.")] + public StepHandlingMethod StepHandling = StepHandlingMethod.Standard; + /// + /// Maximum height of a step which the character can climb + /// + [Tooltip("Maximum height of a step which the character can climb")] + public float MaxStepHeight = 0.5f; + /// + /// Can the character step up obstacles even if it is not currently stable? + /// + [Tooltip("Can the character step up obstacles even if it is not currently stable?")] + public bool AllowSteppingWithoutStableGrounding = false; + /// + /// Minimum length of a step that the character can step on (used in Extra stepping method. Use this to let the character step on steps that are smaller that its radius + /// + [Tooltip("Minimum length of a step that the character can step on (used in Extra stepping method). Use this to let the character step on steps that are smaller that its radius")] + public float MinRequiredStepDepth = 0.1f; + + + [Header("Ledge settings")] + /// + /// Handles properly detecting ledge information and grounding status, but has a performance cost. + /// + [Tooltip("Handles properly detecting ledge information and grounding status, but has a performance cost.")] + public bool LedgeAndDenivelationHandling = true; + /// + /// The distance from the capsule central axis at which the character can stand on a ledge and still be stable + /// + [Tooltip("The distance from the capsule central axis at which the character can stand on a ledge and still be stable")] + public float MaxStableDistanceFromLedge = 0.5f; + /// + /// Prevents snapping to ground on ledges beyond a certain velocity + /// + [Tooltip("Prevents snapping to ground on ledges beyond a certain velocity")] + public float MaxVelocityForLedgeSnap = 0f; + /// + /// The maximun downward slope angle change that the character can be subjected to and still be snapping to the ground + /// + [Tooltip("The maximun downward slope angle change that the character can be subjected to and still be snapping to the ground")] + [Range(1f, 180f)] + public float MaxStableDenivelationAngle = 180f; + + + [Header("Rigidbody interaction settings")] + /// + /// Handles properly being pushed by and standing on PhysicsMovers or dynamic rigidbodies. Also handles pushing dynamic rigidbodies + /// + [Tooltip("Handles properly being pushed by and standing on PhysicsMovers or dynamic rigidbodies. Also handles pushing dynamic rigidbodies")] + public bool InteractiveRigidbodyHandling = true; + /// + /// How the character interacts with non-kinematic rigidbodies. \"Kinematic\" mode means the character pushes the rigidbodies with infinite force (as a kinematic body would). \"SimulatedDynamic\" pushes the rigidbodies with a simulated mass value. + /// + [Tooltip("How the character interacts with non-kinematic rigidbodies. \"Kinematic\" mode means the character pushes the rigidbodies with infinite force (as a kinematic body would). \"SimulatedDynamic\" pushes the rigidbodies with a simulated mass value.")] + public RigidbodyInteractionType RigidbodyInteractionType; + [Tooltip("Mass used for pushing bodies")] + public float SimulatedCharacterMass = 1f; + /// + /// Determines if the character preserves moving platform velocities when de-grounding from them + /// + [Tooltip("Determines if the character preserves moving platform velocities when de-grounding from them")] + public bool PreserveAttachedRigidbodyMomentum = true; + + + [Header("Constraints settings")] + /// + /// Determines if the character's movement uses the planar constraint + /// + [Tooltip("Determines if the character's movement uses the planar constraint")] + public bool HasPlanarConstraint = false; + /// + /// Defines the plane that the character's movement is constrained on, if HasMovementConstraintPlane is active + /// + [Tooltip("Defines the plane that the character's movement is constrained on, if HasMovementConstraintPlane is active")] + public Vector3 PlanarConstraintAxis = Vector3.forward; + + [Header("Other settings")] + /// + /// How many times can we sweep for movement per update + /// + [Tooltip("How many times can we sweep for movement per update")] + public int MaxMovementIterations = 5; + /// + /// How many times can we check for decollision per update + /// + [Tooltip("How many times can we check for decollision per update")] + public int MaxDecollisionIterations = 1; + /// + /// Checks for overlaps before casting movement, making sure all collisions are detected even when already intersecting geometry (has a performance cost, but provides safety against tunneling through colliders) + /// + [Tooltip("Checks for overlaps before casting movement, making sure all collisions are detected even when already intersecting geometry (has a performance cost, but provides safety against tunneling through colliders)")] + public bool CheckMovementInitialOverlaps = true; + /// + /// Sets the velocity to zero if exceed max movement iterations + /// + [Tooltip("Sets the velocity to zero if exceed max movement iterations")] + public bool KillVelocityWhenExceedMaxMovementIterations = true; + /// + /// Sets the remaining movement to zero if exceed max movement iterations + /// + [Tooltip("Sets the remaining movement to zero if exceed max movement iterations")] + public bool KillRemainingMovementWhenExceedMaxMovementIterations = true; + + /// + /// Contains the current grounding information + /// + [System.NonSerialized] + public CharacterGroundingReport GroundingStatus = new CharacterGroundingReport(); + /// + /// Contains the previous grounding information + /// + [System.NonSerialized] + public CharacterTransientGroundingReport LastGroundingStatus = new CharacterTransientGroundingReport(); + /// + /// Specifies the LayerMask that the character's movement algorithm can detect collisions with. By default, this uses the rigidbody's layer's collision matrix + /// + [System.NonSerialized] + public LayerMask CollidableLayers = -1; + + /// + /// The Transform of the character motor + /// + public Transform Transform { get { return _transform; } } + private Transform _transform; + /// + /// The character's goal position in its movement calculations (always up-to-date during the character update phase) + /// + public Vector3 TransientPosition { get { return _transientPosition; } } + private Vector3 _transientPosition; + /// + /// The character's up direction (always up-to-date during the character update phase) + /// + public Vector3 CharacterUp { get { return _characterUp; } } + private Vector3 _characterUp; + /// + /// The character's forward direction (always up-to-date during the character update phase) + /// + public Vector3 CharacterForward { get { return _characterForward; } } + private Vector3 _characterForward; + /// + /// The character's right direction (always up-to-date during the character update phase) + /// + public Vector3 CharacterRight { get { return _characterRight; } } + private Vector3 _characterRight; + /// + /// The character's position before the movement calculations began + /// + public Vector3 InitialSimulationPosition { get { return _initialSimulationPosition; } } + private Vector3 _initialSimulationPosition; + /// + /// The character's rotation before the movement calculations began + /// + public Quaternion InitialSimulationRotation { get { return _initialSimulationRotation; } } + private Quaternion _initialSimulationRotation; + /// + /// Represents the Rigidbody to stay attached to + /// + public Rigidbody AttachedRigidbody { get { return _attachedRigidbody; } } + private Rigidbody _attachedRigidbody; + /// + /// Vector3 from the character transform position to the capsule center + /// + public Vector3 CharacterTransformToCapsuleCenter { get { return _characterTransformToCapsuleCenter; } } + private Vector3 _characterTransformToCapsuleCenter; + /// + /// Vector3 from the character transform position to the capsule bottom + /// + public Vector3 CharacterTransformToCapsuleBottom { get { return _characterTransformToCapsuleBottom; } } + private Vector3 _characterTransformToCapsuleBottom; + /// + /// Vector3 from the character transform position to the capsule top + /// + public Vector3 CharacterTransformToCapsuleTop { get { return _characterTransformToCapsuleTop; } } + private Vector3 _characterTransformToCapsuleTop; + /// + /// Vector3 from the character transform position to the capsule bottom hemi center + /// + public Vector3 CharacterTransformToCapsuleBottomHemi { get { return _characterTransformToCapsuleBottomHemi; } } + private Vector3 _characterTransformToCapsuleBottomHemi; + /// + /// Vector3 from the character transform position to the capsule top hemi center + /// + public Vector3 CharacterTransformToCapsuleTopHemi { get { return _characterTransformToCapsuleTopHemi; } } + private Vector3 _characterTransformToCapsuleTopHemi; + /// + /// The character's velocity resulting from standing on rigidbodies or PhysicsMover + /// + public Vector3 AttachedRigidbodyVelocity { get { return _attachedRigidbodyVelocity; } } + private Vector3 _attachedRigidbodyVelocity; + /// + /// The number of overlaps detected so far during character update (is reset at the beginning of the update) + /// + public int OverlapsCount { get { return _overlapsCount; } } + private int _overlapsCount; + /// + /// The overlaps detected so far during character update + /// + public OverlapResult[] Overlaps { get { return _overlaps; } } + private OverlapResult[] _overlaps = new OverlapResult[MaxRigidbodyOverlapsCount]; + + /// + /// The motor's assigned controller + /// + [NonSerialized] + public ICharacterController CharacterController; + /// + /// Did the motor's last swept collision detection find a ground? + /// + [NonSerialized] + public bool LastMovementIterationFoundAnyGround; + /// + /// Index of this motor in KinematicCharacterSystem arrays + /// + [NonSerialized] + public int IndexInCharacterSystem; + /// + /// Remembers initial position before all simulation are done + /// + [NonSerialized] + public Vector3 InitialTickPosition; + /// + /// Remembers initial rotation before all simulation are done + /// + [NonSerialized] + public Quaternion InitialTickRotation; + /// + /// Specifies a Rigidbody to stay attached to + /// + [NonSerialized] + public Rigidbody AttachedRigidbodyOverride; + /// + /// The character's velocity resulting from direct movement + /// + [NonSerialized] + public Vector3 BaseVelocity; + + // Private + private RaycastHit[] _internalCharacterHits = new RaycastHit[MaxHitsBudget]; + private Collider[] _internalProbedColliders = new Collider[MaxCollisionBudget]; + private List _rigidbodiesPushedThisMove = new List(16); + private RigidbodyProjectionHit[] _internalRigidbodyProjectionHits = new RigidbodyProjectionHit[MaxRigidbodyOverlapsCount]; + private Rigidbody _lastAttachedRigidbody; + private bool _solveMovementCollisions = true; + private bool _solveGrounding = true; + private bool _movePositionDirty = false; + private Vector3 _movePositionTarget = Vector3.zero; + private bool _moveRotationDirty = false; + private Quaternion _moveRotationTarget = Quaternion.identity; + private bool _lastSolvedOverlapNormalDirty = false; + private Vector3 _lastSolvedOverlapNormal = Vector3.forward; + private int _rigidbodyProjectionHitCount = 0; + private bool _isMovingFromAttachedRigidbody = false; + private bool _mustUnground = false; + private float _mustUngroundTimeCounter = 0f; + private Vector3 _cachedWorldUp = Vector3.up; + private Vector3 _cachedWorldForward = Vector3.forward; + private Vector3 _cachedWorldRight = Vector3.right; + private Vector3 _cachedZeroVector = Vector3.zero; + + private Quaternion _transientRotation; + /// + /// The character's goal rotation in its movement calculations (always up-to-date during the character update phase) + /// + public Quaternion TransientRotation + { + get + { + return _transientRotation; + } + private set + { + _transientRotation = value; + _characterUp = _transientRotation * _cachedWorldUp; + _characterForward = _transientRotation * _cachedWorldForward; + _characterRight = _transientRotation * _cachedWorldRight; + } + } + + /// + /// The character's total velocity, including velocity from standing on rigidbodies or PhysicsMover + /// + public Vector3 Velocity + { + get + { + return BaseVelocity + _attachedRigidbodyVelocity; + } + } + + // Warning: Don't touch these constants unless you know exactly what you're doing! + public const int MaxHitsBudget = 16; + public const int MaxCollisionBudget = 16; + public const int MaxGroundingSweepIterations = 2; + public const int MaxSteppingSweepIterations = 3; + public const int MaxRigidbodyOverlapsCount = 16; + public const float CollisionOffset = 0.01f; + public const float GroundProbeReboundDistance = 0.02f; + public const float MinimumGroundProbingDistance = 0.005f; + public const float GroundProbingBackstepDistance = 0.1f; + public const float SweepProbingBackstepDistance = 0.002f; + public const float SecondaryProbesVertical = 0.02f; + public const float SecondaryProbesHorizontal = 0.001f; + public const float MinVelocityMagnitude = 0.01f; + public const float SteppingForwardDistance = 0.03f; + public const float MinDistanceForLedge = 0.05f; + public const float CorrelationForVerticalObstruction = 0.01f; + public const float ExtraSteppingForwardDistance = 0.01f; + public const float ExtraStepHeightPadding = 0.01f; +#pragma warning restore 0414 + + private void OnEnable() + { + KinematicCharacterSystem.EnsureCreation(); + KinematicCharacterSystem.RegisterCharacterMotor(this); + } + + private void OnDisable() + { + KinematicCharacterSystem.UnregisterCharacterMotor(this); + } + + private void Reset() + { + ValidateData(); + } + + private void OnValidate() + { + ValidateData(); + } + + [ContextMenu("Remove Component")] + private void HandleRemoveComponent() + { + CapsuleCollider tmpCapsule = gameObject.GetComponent(); + DestroyImmediate(this); + DestroyImmediate(tmpCapsule); + } + + /// + /// Handle validating all required values + /// + public void ValidateData() + { + Capsule = GetComponent(); + CapsuleRadius = Mathf.Clamp(CapsuleRadius, 0f, CapsuleHeight * 0.5f); + Capsule.direction = 1; + Capsule.sharedMaterial = CapsulePhysicsMaterial; + SetCapsuleDimensions(CapsuleRadius, CapsuleHeight, CapsuleYOffset); + + MaxStepHeight = Mathf.Clamp(MaxStepHeight, 0f, Mathf.Infinity); + MinRequiredStepDepth = Mathf.Clamp(MinRequiredStepDepth, 0f, CapsuleRadius); + MaxStableDistanceFromLedge = Mathf.Clamp(MaxStableDistanceFromLedge, 0f, CapsuleRadius); + + transform.localScale = Vector3.one; + +#if UNITY_EDITOR + Capsule.hideFlags = HideFlags.NotEditable; + if (!Mathf.Approximately(transform.lossyScale.x, 1f) || !Mathf.Approximately(transform.lossyScale.y, 1f) || !Mathf.Approximately(transform.lossyScale.z, 1f)) + { + Debug.LogError("Character's lossy scale is not (1,1,1). This is not allowed. Make sure the character's transform and all of its parents have a (1,1,1) scale.", this.gameObject); + } +#endif + } + + /// + /// Sets whether or not the capsule collider will detect collisions + /// + public void SetCapsuleCollisionsActivation(bool collisionsActive) + { + Capsule.isTrigger = !collisionsActive; + } + + /// + /// Sets whether or not the motor will solve collisions when moving (or moved onto) + /// + public void SetMovementCollisionsSolvingActivation(bool movementCollisionsSolvingActive) + { + _solveMovementCollisions = movementCollisionsSolvingActive; + } + + /// + /// Sets whether or not grounding will be evaluated for all hits + /// + public void SetGroundSolvingActivation(bool stabilitySolvingActive) + { + _solveGrounding = stabilitySolvingActive; + } + + /// + /// Sets the character's position directly + /// + public void SetPosition(Vector3 position, bool bypassInterpolation = true) + { + _transform.position = position; + _initialSimulationPosition = position; + _transientPosition = position; + + if (bypassInterpolation) + { + InitialTickPosition = position; + } + } + + /// + /// Sets the character's rotation directly + /// + public void SetRotation(Quaternion rotation, bool bypassInterpolation = true) + { + _transform.rotation = rotation; + _initialSimulationRotation = rotation; + TransientRotation = rotation; + + if (bypassInterpolation) + { + InitialTickRotation = rotation; + } + } + + /// + /// Sets the character's position and rotation directly + /// + public void SetPositionAndRotation(Vector3 position, Quaternion rotation, bool bypassInterpolation = true) + { + _transform.SetPositionAndRotation(position, rotation); + _initialSimulationPosition = position; + _initialSimulationRotation = rotation; + _transientPosition = position; + TransientRotation = rotation; + + if (bypassInterpolation) + { + InitialTickPosition = position; + InitialTickRotation = rotation; + } + } + + /// + /// Moves the character position, taking all movement collision solving int account. The actual move is done the next time the motor updates are called + /// + public void MoveCharacter(Vector3 toPosition) + { + _movePositionDirty = true; + _movePositionTarget = toPosition; + } + + /// + /// Moves the character rotation. The actual move is done the next time the motor updates are called + /// + public void RotateCharacter(Quaternion toRotation) + { + _moveRotationDirty = true; + _moveRotationTarget = toRotation; + } + + /// + /// Returns all the state information of the motor that is pertinent for simulation + /// + public KinematicCharacterMotorState GetState() + { + KinematicCharacterMotorState state = new KinematicCharacterMotorState(); + + state.Position = _transientPosition; + state.Rotation = _transientRotation; + + state.BaseVelocity = BaseVelocity; + state.AttachedRigidbodyVelocity = _attachedRigidbodyVelocity; + + state.MustUnground = _mustUnground; + state.MustUngroundTime = _mustUngroundTimeCounter; + state.LastMovementIterationFoundAnyGround = LastMovementIterationFoundAnyGround; + state.GroundingStatus.CopyFrom(GroundingStatus); + state.AttachedRigidbody = _attachedRigidbody; + + return state; + } + + /// + /// Applies a motor state instantly + /// + public void ApplyState(KinematicCharacterMotorState state, bool bypassInterpolation = true) + { + SetPositionAndRotation(state.Position, state.Rotation, bypassInterpolation); + + BaseVelocity = state.BaseVelocity; + _attachedRigidbodyVelocity = state.AttachedRigidbodyVelocity; + + _mustUnground = state.MustUnground; + _mustUngroundTimeCounter = state.MustUngroundTime; + LastMovementIterationFoundAnyGround = state.LastMovementIterationFoundAnyGround; + GroundingStatus.CopyFrom(state.GroundingStatus); + _attachedRigidbody = state.AttachedRigidbody; + } + + /// + /// Resizes capsule. ALso caches importand capsule size data + /// + public void SetCapsuleDimensions(float radius, float height, float yOffset) + { + height = Mathf.Max(height, (radius * 2f) + 0.01f); // Safety to prevent invalid capsule geometries + + CapsuleRadius = radius; + CapsuleHeight = height; + CapsuleYOffset = yOffset; + + Capsule.radius = CapsuleRadius; + Capsule.height = Mathf.Clamp(CapsuleHeight, CapsuleRadius * 2f, CapsuleHeight); + Capsule.center = new Vector3(0f, CapsuleYOffset, 0f); + + _characterTransformToCapsuleCenter = Capsule.center; + _characterTransformToCapsuleBottom = Capsule.center + (-_cachedWorldUp * (Capsule.height * 0.5f)); + _characterTransformToCapsuleTop = Capsule.center + (_cachedWorldUp * (Capsule.height * 0.5f)); + _characterTransformToCapsuleBottomHemi = Capsule.center + (-_cachedWorldUp * (Capsule.height * 0.5f)) + (_cachedWorldUp * Capsule.radius); + _characterTransformToCapsuleTopHemi = Capsule.center + (_cachedWorldUp * (Capsule.height * 0.5f)) + (-_cachedWorldUp * Capsule.radius); + } + + private void Awake() + { + _transform = this.transform; + ValidateData(); + + _transientPosition = _transform.position; + TransientRotation = _transform.rotation; + + // Build CollidableLayers mask + CollidableLayers = 0; + for (int i = 0; i < 32; i++) + { + if (!Physics.GetIgnoreLayerCollision(this.gameObject.layer, i)) + { + CollidableLayers |= (1 << i); + } + } + + SetCapsuleDimensions(CapsuleRadius, CapsuleHeight, CapsuleYOffset); + } + + /// + /// Update phase 1 is meant to be called after physics movers have calculated their velocities, but + /// before they have simulated their goal positions/rotations. It is responsible for: + /// - Initializing all values for update + /// - Handling MovePosition calls + /// - Solving initial collision overlaps + /// - Ground probing + /// - Handle detecting potential interactable rigidbodies + /// + public void UpdatePhase1(float deltaTime) + { + // NaN propagation safety stop + if (float.IsNaN(BaseVelocity.x) || float.IsNaN(BaseVelocity.y) || float.IsNaN(BaseVelocity.z)) + { + BaseVelocity = Vector3.zero; + } + if (float.IsNaN(_attachedRigidbodyVelocity.x) || float.IsNaN(_attachedRigidbodyVelocity.y) || float.IsNaN(_attachedRigidbodyVelocity.z)) + { + _attachedRigidbodyVelocity = Vector3.zero; + } + +#if UNITY_EDITOR + if (!Mathf.Approximately(_transform.lossyScale.x, 1f) || !Mathf.Approximately(_transform.lossyScale.y, 1f) || !Mathf.Approximately(_transform.lossyScale.z, 1f)) + { + Debug.LogError("Character's lossy scale is not (1,1,1). This is not allowed. Make sure the character's transform and all of its parents have a (1,1,1) scale.", this.gameObject); + } +#endif + + _rigidbodiesPushedThisMove.Clear(); + + // Before update + CharacterController.BeforeCharacterUpdate(deltaTime); + + _transientPosition = _transform.position; + TransientRotation = _transform.rotation; + _initialSimulationPosition = _transientPosition; + _initialSimulationRotation = _transientRotation; + _rigidbodyProjectionHitCount = 0; + _overlapsCount = 0; + _lastSolvedOverlapNormalDirty = false; + + #region Handle Move Position + if (_movePositionDirty) + { + if (_solveMovementCollisions) + { + Vector3 tmpVelocity = GetVelocityFromMovement(_movePositionTarget - _transientPosition, deltaTime); + if (InternalCharacterMove(ref tmpVelocity, deltaTime)) + { + if (InteractiveRigidbodyHandling) + { + ProcessVelocityForRigidbodyHits(ref tmpVelocity, deltaTime); + } + } + } + else + { + _transientPosition = _movePositionTarget; + } + + _movePositionDirty = false; + } + #endregion + + LastGroundingStatus.CopyFrom(GroundingStatus); + GroundingStatus = new CharacterGroundingReport(); + GroundingStatus.GroundNormal = _characterUp; + + if (_solveMovementCollisions) + { + #region Resolve initial overlaps + Vector3 resolutionDirection = _cachedWorldUp; + float resolutionDistance = 0f; + int iterationsMade = 0; + bool overlapSolved = false; + while (iterationsMade < MaxDecollisionIterations && !overlapSolved) + { + int nbOverlaps = CharacterCollisionsOverlap(_transientPosition, _transientRotation, _internalProbedColliders); + + if (nbOverlaps > 0) + { + // Solve overlaps that aren't against dynamic rigidbodies or physics movers + for (int i = 0; i < nbOverlaps; i++) + { + if (GetInteractiveRigidbody(_internalProbedColliders[i]) == null) + { + // Process overlap + Transform overlappedTransform = _internalProbedColliders[i].GetComponent(); + if (Physics.ComputePenetration( + Capsule, + _transientPosition, + _transientRotation, + _internalProbedColliders[i], + overlappedTransform.position, + overlappedTransform.rotation, + out resolutionDirection, + out resolutionDistance)) + { + // Resolve along obstruction direction + HitStabilityReport mockReport = new HitStabilityReport(); + mockReport.IsStable = IsStableOnNormal(resolutionDirection); + resolutionDirection = GetObstructionNormal(resolutionDirection, mockReport.IsStable); + + // Solve overlap + Vector3 resolutionMovement = resolutionDirection * (resolutionDistance + CollisionOffset); + _transientPosition += resolutionMovement; + + // Remember overlaps + if (_overlapsCount < _overlaps.Length) + { + _overlaps[_overlapsCount] = new OverlapResult(resolutionDirection, _internalProbedColliders[i]); + _overlapsCount++; + } + + break; + } + } + } + } + else + { + overlapSolved = true; + } + + iterationsMade++; + } + #endregion + } + + #region Ground Probing and Snapping + // Handle ungrounding + if (_solveGrounding) + { + if (MustUnground()) + { + _transientPosition += _characterUp * (MinimumGroundProbingDistance * 1.5f); + } + else + { + // Choose the appropriate ground probing distance + float selectedGroundProbingDistance = MinimumGroundProbingDistance; + if (!LastGroundingStatus.SnappingPrevented && (LastGroundingStatus.IsStableOnGround || LastMovementIterationFoundAnyGround)) + { + if (StepHandling != StepHandlingMethod.None) + { + selectedGroundProbingDistance = Mathf.Max(CapsuleRadius, MaxStepHeight); + } + else + { + selectedGroundProbingDistance = CapsuleRadius; + } + + selectedGroundProbingDistance += GroundDetectionExtraDistance; + } + + ProbeGround(ref _transientPosition, _transientRotation, selectedGroundProbingDistance, ref GroundingStatus); + + if (!LastGroundingStatus.IsStableOnGround && GroundingStatus.IsStableOnGround) + { + // Handle stable landing + BaseVelocity = Vector3.ProjectOnPlane(BaseVelocity, CharacterUp); + BaseVelocity = GetDirectionTangentToSurface(BaseVelocity, GroundingStatus.GroundNormal) * BaseVelocity.magnitude; + } + } + } + + LastMovementIterationFoundAnyGround = false; + + if (_mustUngroundTimeCounter > 0f) + { + _mustUngroundTimeCounter -= deltaTime; + } + _mustUnground = false; + #endregion + + if (_solveGrounding) + { + CharacterController.PostGroundingUpdate(deltaTime); + } + + if (InteractiveRigidbodyHandling) + { + #region Interactive Rigidbody Handling + _lastAttachedRigidbody = _attachedRigidbody; + if (AttachedRigidbodyOverride) + { + _attachedRigidbody = AttachedRigidbodyOverride; + } + else + { + // Detect interactive rigidbodies from grounding + if (GroundingStatus.IsStableOnGround && GroundingStatus.GroundCollider.attachedRigidbody) + { + Rigidbody interactiveRigidbody = GetInteractiveRigidbody(GroundingStatus.GroundCollider); + if (interactiveRigidbody) + { + _attachedRigidbody = interactiveRigidbody; + } + } + else + { + _attachedRigidbody = null; + } + } + + Vector3 tmpVelocityFromCurrentAttachedRigidbody = Vector3.zero; + Vector3 tmpAngularVelocityFromCurrentAttachedRigidbody = Vector3.zero; + if (_attachedRigidbody) + { + GetVelocityFromRigidbodyMovement(_attachedRigidbody, _transientPosition, deltaTime, out tmpVelocityFromCurrentAttachedRigidbody, out tmpAngularVelocityFromCurrentAttachedRigidbody); + } + + // Conserve momentum when de-stabilized from an attached rigidbody + if (PreserveAttachedRigidbodyMomentum && _lastAttachedRigidbody != null && _attachedRigidbody != _lastAttachedRigidbody) + { + BaseVelocity += _attachedRigidbodyVelocity; + BaseVelocity -= tmpVelocityFromCurrentAttachedRigidbody; + } + + // Process additionnal Velocity from attached rigidbody + _attachedRigidbodyVelocity = _cachedZeroVector; + if (_attachedRigidbody) + { + _attachedRigidbodyVelocity = tmpVelocityFromCurrentAttachedRigidbody; + + // Rotation from attached rigidbody + Vector3 newForward = Vector3.ProjectOnPlane(Quaternion.Euler(Mathf.Rad2Deg * tmpAngularVelocityFromCurrentAttachedRigidbody * deltaTime) * _characterForward, _characterUp).normalized; + TransientRotation = Quaternion.LookRotation(newForward, _characterUp); + } + + // Cancel out horizontal velocity upon landing on an attached rigidbody + if (GroundingStatus.GroundCollider && + GroundingStatus.GroundCollider.attachedRigidbody && + GroundingStatus.GroundCollider.attachedRigidbody == _attachedRigidbody && + _attachedRigidbody != null && + _lastAttachedRigidbody == null) + { + BaseVelocity -= Vector3.ProjectOnPlane(_attachedRigidbodyVelocity, _characterUp); + } + + // Movement from Attached Rigidbody + if (_attachedRigidbodyVelocity.sqrMagnitude > 0f) + { + _isMovingFromAttachedRigidbody = true; + + if (_solveMovementCollisions) + { + // Perform the move from rgdbdy velocity + InternalCharacterMove(ref _attachedRigidbodyVelocity, deltaTime); + } + else + { + _transientPosition += _attachedRigidbodyVelocity * deltaTime; + } + + _isMovingFromAttachedRigidbody = false; + } + #endregion + } + } + + /// + /// Update phase 2 is meant to be called after physics movers have simulated their goal positions/rotations. + /// At the end of this, the TransientPosition/Rotation values will be up-to-date with where the motor should be at the end of its move. + /// It is responsible for: + /// - Solving Rotation + /// - Handle MoveRotation calls + /// - Solving potential attached rigidbody overlaps + /// - Solving Velocity + /// - Applying planar constraint + /// + public void UpdatePhase2(float deltaTime) + { + // Handle rotation + CharacterController.UpdateRotation(ref _transientRotation, deltaTime); + TransientRotation = _transientRotation; + + // Handle move rotation + if (_moveRotationDirty) + { + TransientRotation = _moveRotationTarget; + _moveRotationDirty = false; + } + + if (_solveMovementCollisions && InteractiveRigidbodyHandling) + { + if (InteractiveRigidbodyHandling) + { + #region Solve potential attached rigidbody overlap + if (_attachedRigidbody) + { + float upwardsOffset = Capsule.radius; + + RaycastHit closestHit; + if (CharacterGroundSweep( + _transientPosition + (_characterUp * upwardsOffset), + _transientRotation, + -_characterUp, + upwardsOffset, + out closestHit)) + { + if (closestHit.collider.attachedRigidbody == _attachedRigidbody && IsStableOnNormal(closestHit.normal)) + { + float distanceMovedUp = (upwardsOffset - closestHit.distance); + _transientPosition = _transientPosition + (_characterUp * distanceMovedUp) + (_characterUp * CollisionOffset); + } + } + } + #endregion + } + + if (InteractiveRigidbodyHandling) + { + #region Resolve overlaps that could've been caused by rotation or physics movers simulation pushing the character + Vector3 resolutionDirection = _cachedWorldUp; + float resolutionDistance = 0f; + int iterationsMade = 0; + bool overlapSolved = false; + while (iterationsMade < MaxDecollisionIterations && !overlapSolved) + { + int nbOverlaps = CharacterCollisionsOverlap(_transientPosition, _transientRotation, _internalProbedColliders); + if (nbOverlaps > 0) + { + for (int i = 0; i < nbOverlaps; i++) + { + // Process overlap + Transform overlappedTransform = _internalProbedColliders[i].GetComponent(); + if (Physics.ComputePenetration( + Capsule, + _transientPosition, + _transientRotation, + _internalProbedColliders[i], + overlappedTransform.position, + overlappedTransform.rotation, + out resolutionDirection, + out resolutionDistance)) + { + // Resolve along obstruction direction + HitStabilityReport mockReport = new HitStabilityReport(); + mockReport.IsStable = IsStableOnNormal(resolutionDirection); + resolutionDirection = GetObstructionNormal(resolutionDirection, mockReport.IsStable); + + // Solve overlap + Vector3 resolutionMovement = resolutionDirection * (resolutionDistance + CollisionOffset); + _transientPosition += resolutionMovement; + + // If interactiveRigidbody, register as rigidbody hit for velocity + if (InteractiveRigidbodyHandling) + { + Rigidbody probedRigidbody = GetInteractiveRigidbody(_internalProbedColliders[i]); + if (probedRigidbody != null) + { + HitStabilityReport tmpReport = new HitStabilityReport(); + tmpReport.IsStable = IsStableOnNormal(resolutionDirection); + if (tmpReport.IsStable) + { + LastMovementIterationFoundAnyGround = tmpReport.IsStable; + } + if (probedRigidbody != _attachedRigidbody) + { + Vector3 characterCenter = _transientPosition + (_transientRotation * _characterTransformToCapsuleCenter); + Vector3 estimatedCollisionPoint = _transientPosition; + + + StoreRigidbodyHit( + probedRigidbody, + Velocity, + estimatedCollisionPoint, + resolutionDirection, + tmpReport); + } + } + } + + // Remember overlaps + if (_overlapsCount < _overlaps.Length) + { + _overlaps[_overlapsCount] = new OverlapResult(resolutionDirection, _internalProbedColliders[i]); + _overlapsCount++; + } + + break; + } + } + } + else + { + overlapSolved = true; + } + + iterationsMade++; + } + #endregion + } + } + + // Handle velocity + CharacterController.UpdateVelocity(ref BaseVelocity, deltaTime); + + //this.CharacterController.UpdateVelocity(ref BaseVelocity, deltaTime); + if (BaseVelocity.magnitude < MinVelocityMagnitude) + { + BaseVelocity = Vector3.zero; + } + + #region Calculate Character movement from base velocity + // Perform the move from base velocity + if (BaseVelocity.sqrMagnitude > 0f) + { + if (_solveMovementCollisions) + { + InternalCharacterMove(ref BaseVelocity, deltaTime); + } + else + { + _transientPosition += BaseVelocity * deltaTime; + } + } + + // Process rigidbody hits/overlaps to affect velocity + if (InteractiveRigidbodyHandling) + { + ProcessVelocityForRigidbodyHits(ref BaseVelocity, deltaTime); + } + #endregion + + // Handle planar constraint + if (HasPlanarConstraint) + { + _transientPosition = _initialSimulationPosition + Vector3.ProjectOnPlane(_transientPosition - _initialSimulationPosition, PlanarConstraintAxis.normalized); + } + + // Discrete collision detection + if (DiscreteCollisionEvents) + { + int nbOverlaps = CharacterCollisionsOverlap(_transientPosition, _transientRotation, _internalProbedColliders, CollisionOffset * 2f); + for (int i = 0; i < nbOverlaps; i++) + { + CharacterController.OnDiscreteCollisionDetected(_internalProbedColliders[i]); + } + } + + CharacterController.AfterCharacterUpdate(deltaTime); + } + + /// + /// Determines if motor can be considered stable on given slope normal + /// + private bool IsStableOnNormal(Vector3 normal) + { + return Vector3.Angle(_characterUp, normal) <= MaxStableSlopeAngle; + } + + /// + /// Determines if motor can be considered stable on given slope normal + /// + private bool IsStableWithSpecialCases(ref HitStabilityReport stabilityReport, Vector3 velocity) + { + if (LedgeAndDenivelationHandling) + { + if (stabilityReport.LedgeDetected) + { + if (stabilityReport.IsMovingTowardsEmptySideOfLedge) + { + // Max snap vel + Vector3 velocityOnLedgeNormal = Vector3.Project(velocity, stabilityReport.LedgeFacingDirection); + if (velocityOnLedgeNormal.magnitude >= MaxVelocityForLedgeSnap) + { + return false; + } + } + + // Distance from ledge + if (stabilityReport.IsOnEmptySideOfLedge && stabilityReport.DistanceFromLedge > MaxStableDistanceFromLedge) + { + return false; + } + } + + // "Launching" off of slopes of a certain denivelation angle + if (LastGroundingStatus.FoundAnyGround && stabilityReport.InnerNormal.sqrMagnitude != 0f && stabilityReport.OuterNormal.sqrMagnitude != 0f) + { + float denivelationAngle = Vector3.Angle(stabilityReport.InnerNormal, stabilityReport.OuterNormal); + if (denivelationAngle > MaxStableDenivelationAngle) + { + return false; + } + else + { + denivelationAngle = Vector3.Angle(LastGroundingStatus.InnerGroundNormal, stabilityReport.OuterNormal); + if (denivelationAngle > MaxStableDenivelationAngle) + { + return false; + } + } + } + } + + return true; + } + + /// + /// Probes for valid ground and midifies the input transientPosition if ground snapping occurs + /// + public void ProbeGround(ref Vector3 probingPosition, Quaternion atRotation, float probingDistance, ref CharacterGroundingReport groundingReport) + { + if (probingDistance < MinimumGroundProbingDistance) + { + probingDistance = MinimumGroundProbingDistance; + } + + int groundSweepsMade = 0; + RaycastHit groundSweepHit = new RaycastHit(); + bool groundSweepingIsOver = false; + Vector3 groundSweepPosition = probingPosition; + Vector3 groundSweepDirection = (atRotation * -_cachedWorldUp); + float groundProbeDistanceRemaining = probingDistance; + while (groundProbeDistanceRemaining > 0 && (groundSweepsMade <= MaxGroundingSweepIterations) && !groundSweepingIsOver) + { + // Sweep for ground detection + if (CharacterGroundSweep( + groundSweepPosition, // position + atRotation, // rotation + groundSweepDirection, // direction + groundProbeDistanceRemaining, // distance + out groundSweepHit)) // hit + { + Vector3 targetPosition = groundSweepPosition + (groundSweepDirection * groundSweepHit.distance); + HitStabilityReport groundHitStabilityReport = new HitStabilityReport(); + EvaluateHitStability(groundSweepHit.collider, groundSweepHit.normal, groundSweepHit.point, targetPosition, _transientRotation, BaseVelocity, ref groundHitStabilityReport); + + groundingReport.FoundAnyGround = true; + groundingReport.GroundNormal = groundSweepHit.normal; + groundingReport.InnerGroundNormal = groundHitStabilityReport.InnerNormal; + groundingReport.OuterGroundNormal = groundHitStabilityReport.OuterNormal; + groundingReport.GroundCollider = groundSweepHit.collider; + groundingReport.GroundPoint = groundSweepHit.point; + groundingReport.SnappingPrevented = false; + + // Found stable ground + if (groundHitStabilityReport.IsStable) + { + // Find all scenarios where ground snapping should be canceled + groundingReport.SnappingPrevented = !IsStableWithSpecialCases(ref groundHitStabilityReport, BaseVelocity); + + groundingReport.IsStableOnGround = true; + + // Ground snapping + if (!groundingReport.SnappingPrevented) + { + probingPosition = groundSweepPosition + (groundSweepDirection * (groundSweepHit.distance - CollisionOffset)); + } + + CharacterController.OnGroundHit(groundSweepHit.collider, groundSweepHit.normal, groundSweepHit.point, ref groundHitStabilityReport); + groundSweepingIsOver = true; + } + else + { + // Calculate movement from this iteration and advance position + Vector3 sweepMovement = (groundSweepDirection * groundSweepHit.distance) + ((atRotation * _cachedWorldUp) * Mathf.Max(CollisionOffset, groundSweepHit.distance)); + groundSweepPosition = groundSweepPosition + sweepMovement; + + // Set remaining distance + groundProbeDistanceRemaining = Mathf.Min(GroundProbeReboundDistance, Mathf.Max(groundProbeDistanceRemaining - sweepMovement.magnitude, 0f)); + + // Reorient direction + groundSweepDirection = Vector3.ProjectOnPlane(groundSweepDirection, groundSweepHit.normal).normalized; + } + } + else + { + groundSweepingIsOver = true; + } + + groundSweepsMade++; + } + } + + /// + /// Forces the character to unground itself on its next grounding update + /// + public void ForceUnground(float time = 0.1f) + { + _mustUnground = true; + _mustUngroundTimeCounter = time; + } + + public bool MustUnground() + { + return _mustUnground || _mustUngroundTimeCounter > 0f; + } + + /// + /// Returns the direction adjusted to be tangent to a specified surface normal relatively to the character's up direction. + /// Useful for reorienting a direction on a slope without any lateral deviation in trajectory + /// + public Vector3 GetDirectionTangentToSurface(Vector3 direction, Vector3 surfaceNormal) + { + Vector3 directionRight = Vector3.Cross(direction, _characterUp); + return Vector3.Cross(surfaceNormal, directionRight).normalized; + } + + /// + /// Moves the character's position by given movement while taking into account all physics simulation, step-handling and + /// velocity projection rules that affect the character motor + /// + /// Returns false if movement could not be solved until the end + private bool InternalCharacterMove(ref Vector3 transientVelocity, float deltaTime) + { + if (deltaTime <= 0f) + return false; + + // Planar constraint + if (HasPlanarConstraint) + { + transientVelocity = Vector3.ProjectOnPlane(transientVelocity, PlanarConstraintAxis.normalized); + } + + bool wasCompleted = true; + Vector3 remainingMovementDirection = transientVelocity.normalized; + float remainingMovementMagnitude = transientVelocity.magnitude * deltaTime; + Vector3 originalVelocityDirection = remainingMovementDirection; + int sweepsMade = 0; + bool hitSomethingThisSweepIteration = true; + Vector3 tmpMovedPosition = _transientPosition; + bool previousHitIsStable = false; + Vector3 previousVelocity = _cachedZeroVector; + Vector3 previousObstructionNormal = _cachedZeroVector; + MovementSweepState sweepState = MovementSweepState.Initial; + + // Project movement against current overlaps before doing the sweeps + for (int i = 0; i < _overlapsCount; i++) + { + Vector3 overlapNormal = _overlaps[i].Normal; + if (Vector3.Dot(remainingMovementDirection, overlapNormal) < 0f) + { + bool stableOnHit = IsStableOnNormal(overlapNormal) && !MustUnground(); + Vector3 velocityBeforeProjection = transientVelocity; + Vector3 obstructionNormal = GetObstructionNormal(overlapNormal, stableOnHit); + + InternalHandleVelocityProjection( + stableOnHit, + overlapNormal, + obstructionNormal, + originalVelocityDirection, + ref sweepState, + previousHitIsStable, + previousVelocity, + previousObstructionNormal, + ref transientVelocity, + ref remainingMovementMagnitude, + ref remainingMovementDirection); + + previousHitIsStable = stableOnHit; + previousVelocity = velocityBeforeProjection; + previousObstructionNormal = obstructionNormal; + } + } + + // Sweep the desired movement to detect collisions + while (remainingMovementMagnitude > 0f && + (sweepsMade <= MaxMovementIterations) && + hitSomethingThisSweepIteration) + { + bool foundClosestHit = false; + Vector3 closestSweepHitPoint = default; + Vector3 closestSweepHitNormal = default; + float closestSweepHitDistance = 0f; + Collider closestSweepHitCollider = null; + + if (CheckMovementInitialOverlaps) + { + int numOverlaps = CharacterCollisionsOverlap( + tmpMovedPosition, + _transientRotation, + _internalProbedColliders, + 0f, + false); + if (numOverlaps > 0) + { + closestSweepHitDistance = 0f; + + float mostObstructingOverlapNormalDotProduct = 2f; + + for (int i = 0; i < numOverlaps; i++) + { + Collider tmpCollider = _internalProbedColliders[i]; + + if (Physics.ComputePenetration( + Capsule, + tmpMovedPosition, + _transientRotation, + tmpCollider, + tmpCollider.transform.position, + tmpCollider.transform.rotation, + out Vector3 resolutionDirection, + out float resolutionDistance)) + { + float dotProduct = Vector3.Dot(remainingMovementDirection, resolutionDirection); + if (dotProduct < 0f && dotProduct < mostObstructingOverlapNormalDotProduct) + { + mostObstructingOverlapNormalDotProduct = dotProduct; + + closestSweepHitNormal = resolutionDirection; + closestSweepHitCollider = tmpCollider; + closestSweepHitPoint = tmpMovedPosition + (_transientRotation * CharacterTransformToCapsuleCenter) + (resolutionDirection * resolutionDistance); + + foundClosestHit = true; + } + } + } + } + } + + if (!foundClosestHit && CharacterCollisionsSweep( + tmpMovedPosition, // position + _transientRotation, // rotation + remainingMovementDirection, // direction + remainingMovementMagnitude + CollisionOffset, // distance + out RaycastHit closestSweepHit, // closest hit + _internalCharacterHits) // all hits + > 0) + { + closestSweepHitNormal = closestSweepHit.normal; + closestSweepHitDistance = closestSweepHit.distance; + closestSweepHitCollider = closestSweepHit.collider; + closestSweepHitPoint = closestSweepHit.point; + + foundClosestHit = true; + } + + if (foundClosestHit) + { + // Calculate movement from this iteration + Vector3 sweepMovement = (remainingMovementDirection * (Mathf.Max(0f, closestSweepHitDistance - CollisionOffset))); + tmpMovedPosition += sweepMovement; + remainingMovementMagnitude -= sweepMovement.magnitude; + + // Evaluate if hit is stable + HitStabilityReport moveHitStabilityReport = new HitStabilityReport(); + EvaluateHitStability(closestSweepHitCollider, closestSweepHitNormal, closestSweepHitPoint, tmpMovedPosition, _transientRotation, transientVelocity, ref moveHitStabilityReport); + + // Handle stepping up steps points higher than bottom capsule radius + bool foundValidStepHit = false; + if (_solveGrounding && StepHandling != StepHandlingMethod.None && moveHitStabilityReport.ValidStepDetected) + { + float obstructionCorrelation = Mathf.Abs(Vector3.Dot(closestSweepHitNormal, _characterUp)); + if (obstructionCorrelation <= CorrelationForVerticalObstruction) + { + Vector3 stepForwardDirection = Vector3.ProjectOnPlane(-closestSweepHitNormal, _characterUp).normalized; + Vector3 stepCastStartPoint = (tmpMovedPosition + (stepForwardDirection * SteppingForwardDistance)) + + (_characterUp * MaxStepHeight); + + // Cast downward from the top of the stepping height + int nbStepHits = CharacterCollisionsSweep( + stepCastStartPoint, // position + _transientRotation, // rotation + -_characterUp, // direction + MaxStepHeight, // distance + out RaycastHit closestStepHit, // closest hit + _internalCharacterHits, + 0f, + true); // all hits + + // Check for hit corresponding to stepped collider + for (int i = 0; i < nbStepHits; i++) + { + if (_internalCharacterHits[i].collider == moveHitStabilityReport.SteppedCollider) + { + Vector3 endStepPosition = stepCastStartPoint + (-_characterUp * (_internalCharacterHits[i].distance - CollisionOffset)); + tmpMovedPosition = endStepPosition; + foundValidStepHit = true; + + // Project velocity on ground normal at step + transientVelocity = Vector3.ProjectOnPlane(transientVelocity, CharacterUp); + remainingMovementDirection = transientVelocity.normalized; + + break; + } + } + } + } + + // Handle movement solving + if (!foundValidStepHit) + { + Vector3 obstructionNormal = GetObstructionNormal(closestSweepHitNormal, moveHitStabilityReport.IsStable); + + // Movement hit callback + CharacterController.OnMovementHit(closestSweepHitCollider, closestSweepHitNormal, closestSweepHitPoint, ref moveHitStabilityReport); + + // Handle remembering rigidbody hits + if (InteractiveRigidbodyHandling && closestSweepHitCollider.attachedRigidbody) + { + StoreRigidbodyHit( + closestSweepHitCollider.attachedRigidbody, + transientVelocity, + closestSweepHitPoint, + obstructionNormal, + moveHitStabilityReport); + } + + bool stableOnHit = moveHitStabilityReport.IsStable && !MustUnground(); + Vector3 velocityBeforeProj = transientVelocity; + + // Project velocity for next iteration + InternalHandleVelocityProjection( + stableOnHit, + closestSweepHitNormal, + obstructionNormal, + originalVelocityDirection, + ref sweepState, + previousHitIsStable, + previousVelocity, + previousObstructionNormal, + ref transientVelocity, + ref remainingMovementMagnitude, + ref remainingMovementDirection); + + previousHitIsStable = stableOnHit; + previousVelocity = velocityBeforeProj; + previousObstructionNormal = obstructionNormal; + } + } + // If we hit nothing... + else + { + hitSomethingThisSweepIteration = false; + } + + // Safety for exceeding max sweeps allowed + sweepsMade++; + if (sweepsMade > MaxMovementIterations) + { + if (KillRemainingMovementWhenExceedMaxMovementIterations) + { + remainingMovementMagnitude = 0f; + } + + if (KillVelocityWhenExceedMaxMovementIterations) + { + transientVelocity = Vector3.zero; + } + wasCompleted = false; + } + } + + // Move position for the remainder of the movement + tmpMovedPosition += (remainingMovementDirection * remainingMovementMagnitude); + _transientPosition = tmpMovedPosition; + + return wasCompleted; + } + + /// + /// Gets the effective normal for movement obstruction depending on current grounding status + /// + private Vector3 GetObstructionNormal(Vector3 hitNormal, bool stableOnHit) + { + // Find hit/obstruction/offset normal + Vector3 obstructionNormal = hitNormal; + if (GroundingStatus.IsStableOnGround && !MustUnground() && !stableOnHit) + { + Vector3 obstructionLeftAlongGround = Vector3.Cross(GroundingStatus.GroundNormal, obstructionNormal).normalized; + obstructionNormal = Vector3.Cross(obstructionLeftAlongGround, _characterUp).normalized; + } + + // Catch cases where cross product between parallel normals returned 0 + if (obstructionNormal.sqrMagnitude == 0f) + { + obstructionNormal = hitNormal; + } + + return obstructionNormal; + } + + /// + /// Remembers a rigidbody hit for processing later + /// + private void StoreRigidbodyHit(Rigidbody hitRigidbody, Vector3 hitVelocity, Vector3 hitPoint, Vector3 obstructionNormal, HitStabilityReport hitStabilityReport) + { + if (_rigidbodyProjectionHitCount < _internalRigidbodyProjectionHits.Length) + { + if (!hitRigidbody.GetComponent()) + { + RigidbodyProjectionHit rph = new RigidbodyProjectionHit(); + rph.Rigidbody = hitRigidbody; + rph.HitPoint = hitPoint; + rph.EffectiveHitNormal = obstructionNormal; + rph.HitVelocity = hitVelocity; + rph.StableOnHit = hitStabilityReport.IsStable; + + _internalRigidbodyProjectionHits[_rigidbodyProjectionHitCount] = rph; + _rigidbodyProjectionHitCount++; + } + } + } + + public void SetTransientPosition(Vector3 newPos) + { + _transientPosition = newPos; + } + + /// + /// Processes movement projection upon detecting a hit + /// + private void InternalHandleVelocityProjection(bool stableOnHit, Vector3 hitNormal, Vector3 obstructionNormal, Vector3 originalDirection, + ref MovementSweepState sweepState, bool previousHitIsStable, Vector3 previousVelocity, Vector3 previousObstructionNormal, + ref Vector3 transientVelocity, ref float remainingMovementMagnitude, ref Vector3 remainingMovementDirection) + { + if (transientVelocity.sqrMagnitude <= 0f) + { + return; + } + + Vector3 velocityBeforeProjection = transientVelocity; + + if (stableOnHit) + { + LastMovementIterationFoundAnyGround = true; + HandleVelocityProjection(ref transientVelocity, obstructionNormal, stableOnHit); + } + else + { + // Handle projection + if (sweepState == MovementSweepState.Initial) + { + HandleVelocityProjection(ref transientVelocity, obstructionNormal, stableOnHit); + sweepState = MovementSweepState.AfterFirstHit; + } + // Blocking crease handling + else if (sweepState == MovementSweepState.AfterFirstHit) + { + EvaluateCrease( + transientVelocity, + previousVelocity, + obstructionNormal, + previousObstructionNormal, + stableOnHit, + previousHitIsStable, + GroundingStatus.IsStableOnGround && !MustUnground(), + out bool foundCrease, + out Vector3 creaseDirection); + + if (foundCrease) + { + if (GroundingStatus.IsStableOnGround && !MustUnground()) + { + transientVelocity = Vector3.zero; + sweepState = MovementSweepState.FoundBlockingCorner; + } + else + { + transientVelocity = Vector3.Project(transientVelocity, creaseDirection); + sweepState = MovementSweepState.FoundBlockingCrease; + } + } + else + { + HandleVelocityProjection(ref transientVelocity, obstructionNormal, stableOnHit); + } + } + // Blocking corner handling + else if (sweepState == MovementSweepState.FoundBlockingCrease) + { + transientVelocity = Vector3.zero; + sweepState = MovementSweepState.FoundBlockingCorner; + } + } + + if (HasPlanarConstraint) + { + transientVelocity = Vector3.ProjectOnPlane(transientVelocity, PlanarConstraintAxis.normalized); + } + + float newVelocityFactor = transientVelocity.magnitude / velocityBeforeProjection.magnitude; + remainingMovementMagnitude *= newVelocityFactor; + remainingMovementDirection = transientVelocity.normalized; + } + + private void EvaluateCrease( + Vector3 currentCharacterVelocity, + Vector3 previousCharacterVelocity, + Vector3 currentHitNormal, + Vector3 previousHitNormal, + bool currentHitIsStable, + bool previousHitIsStable, + bool characterIsStable, + out bool isValidCrease, + out Vector3 creaseDirection) + { + isValidCrease = false; + creaseDirection = default; + + if (!characterIsStable || !currentHitIsStable || !previousHitIsStable) + { + Vector3 tmpBlockingCreaseDirection = Vector3.Cross(currentHitNormal, previousHitNormal).normalized; + float dotPlanes = Vector3.Dot(currentHitNormal, previousHitNormal); + bool isVelocityConstrainedByCrease = false; + + // Avoid calculations if the two planes are the same + if (dotPlanes < 0.999f) + { + // TODO: can this whole part be made simpler? (with 2d projections, etc) + Vector3 normalAOnCreasePlane = Vector3.ProjectOnPlane(currentHitNormal, tmpBlockingCreaseDirection).normalized; + Vector3 normalBOnCreasePlane = Vector3.ProjectOnPlane(previousHitNormal, tmpBlockingCreaseDirection).normalized; + float dotPlanesOnCreasePlane = Vector3.Dot(normalAOnCreasePlane, normalBOnCreasePlane); + + Vector3 enteringVelocityDirectionOnCreasePlane = Vector3.ProjectOnPlane(previousCharacterVelocity, tmpBlockingCreaseDirection).normalized; + + if (dotPlanesOnCreasePlane <= (Vector3.Dot(-enteringVelocityDirectionOnCreasePlane, normalAOnCreasePlane) + 0.001f) && + dotPlanesOnCreasePlane <= (Vector3.Dot(-enteringVelocityDirectionOnCreasePlane, normalBOnCreasePlane) + 0.001f)) + { + isVelocityConstrainedByCrease = true; + } + } + + if (isVelocityConstrainedByCrease) + { + // Flip crease direction to make it representative of the real direction our velocity would be projected to + if (Vector3.Dot(tmpBlockingCreaseDirection, currentCharacterVelocity) < 0f) + { + tmpBlockingCreaseDirection = -tmpBlockingCreaseDirection; + } + + isValidCrease = true; + creaseDirection = tmpBlockingCreaseDirection; + } + } + } + + /// + /// Allows you to override the way velocity is projected on an obstruction + /// + public virtual void HandleVelocityProjection(ref Vector3 velocity, Vector3 obstructionNormal, bool stableOnHit) + { + if (GroundingStatus.IsStableOnGround && !MustUnground()) + { + // On stable slopes, simply reorient the movement without any loss + if (stableOnHit) + { + velocity = GetDirectionTangentToSurface(velocity, obstructionNormal) * velocity.magnitude; + } + // On blocking hits, project the movement on the obstruction while following the grounding plane + else + { + Vector3 obstructionRightAlongGround = Vector3.Cross(obstructionNormal, GroundingStatus.GroundNormal).normalized; + Vector3 obstructionUpAlongGround = Vector3.Cross(obstructionRightAlongGround, obstructionNormal).normalized; + velocity = GetDirectionTangentToSurface(velocity, obstructionUpAlongGround) * velocity.magnitude; + velocity = Vector3.ProjectOnPlane(velocity, obstructionNormal); + } + } + else + { + if (stableOnHit) + { + // Handle stable landing + velocity = Vector3.ProjectOnPlane(velocity, CharacterUp); + velocity = GetDirectionTangentToSurface(velocity, obstructionNormal) * velocity.magnitude; + } + // Handle generic obstruction + else + { + velocity = Vector3.ProjectOnPlane(velocity, obstructionNormal); + } + } + } + + /// + /// Allows you to override the way hit rigidbodies are pushed / interacted with. + /// ProcessedVelocity is what must be modified if this interaction affects the character's velocity. + /// + public virtual void HandleSimulatedRigidbodyInteraction(ref Vector3 processedVelocity, RigidbodyProjectionHit hit, float deltaTime) + { + } + + /// + /// Takes into account rigidbody hits for adding to the velocity + /// + private void ProcessVelocityForRigidbodyHits(ref Vector3 processedVelocity, float deltaTime) + { + for (int i = 0; i < _rigidbodyProjectionHitCount; i++) + { + RigidbodyProjectionHit bodyHit = _internalRigidbodyProjectionHits[i]; + + if (bodyHit.Rigidbody && !_rigidbodiesPushedThisMove.Contains(bodyHit.Rigidbody)) + { + if (_internalRigidbodyProjectionHits[i].Rigidbody != _attachedRigidbody) + { + // Remember we hit this rigidbody + _rigidbodiesPushedThisMove.Add(bodyHit.Rigidbody); + + float characterMass = SimulatedCharacterMass; + Vector3 characterVelocity = bodyHit.HitVelocity; + + KinematicCharacterMotor hitCharacterMotor = bodyHit.Rigidbody.GetComponent(); + bool hitBodyIsCharacter = hitCharacterMotor != null; + bool hitBodyIsDynamic = !bodyHit.Rigidbody.isKinematic; + float hitBodyMass = bodyHit.Rigidbody.mass; + float hitBodyMassAtPoint = bodyHit.Rigidbody.mass; // todo + Vector3 hitBodyVelocity = bodyHit.Rigidbody.linearVelocity; + if (hitBodyIsCharacter) + { + hitBodyMass = hitCharacterMotor.SimulatedCharacterMass; + hitBodyMassAtPoint = hitCharacterMotor.SimulatedCharacterMass; // todo + hitBodyVelocity = hitCharacterMotor.BaseVelocity; + } + else if (!hitBodyIsDynamic) + { + PhysicsMover physicsMover = bodyHit.Rigidbody.GetComponent(); + if(physicsMover) + { + hitBodyVelocity = physicsMover.Velocity; + } + } + + // Calculate the ratio of the total mass that the character mass represents + float characterToBodyMassRatio = 1f; + { + if (characterMass + hitBodyMassAtPoint > 0f) + { + characterToBodyMassRatio = characterMass / (characterMass + hitBodyMassAtPoint); + } + else + { + characterToBodyMassRatio = 0.5f; + } + + // Hitting a non-dynamic body + if (!hitBodyIsDynamic) + { + characterToBodyMassRatio = 0f; + } + // Emulate kinematic body interaction + else if (RigidbodyInteractionType == RigidbodyInteractionType.Kinematic && !hitBodyIsCharacter) + { + characterToBodyMassRatio = 1f; + } + } + + ComputeCollisionResolutionForHitBody( + bodyHit.EffectiveHitNormal, + characterVelocity, + hitBodyVelocity, + characterToBodyMassRatio, + out Vector3 velocityChangeOnCharacter, + out Vector3 velocityChangeOnBody); + + processedVelocity += velocityChangeOnCharacter; + + if (hitBodyIsCharacter) + { + hitCharacterMotor.BaseVelocity += velocityChangeOnCharacter; + } + else if (hitBodyIsDynamic) + { + bodyHit.Rigidbody.AddForceAtPosition(velocityChangeOnBody, bodyHit.HitPoint, ForceMode.VelocityChange); + } + + if (RigidbodyInteractionType == RigidbodyInteractionType.SimulatedDynamic) + { + HandleSimulatedRigidbodyInteraction(ref processedVelocity, bodyHit, deltaTime); + } + } + } + } + + } + + public void ComputeCollisionResolutionForHitBody( + Vector3 hitNormal, + Vector3 characterVelocity, + Vector3 bodyVelocity, + float characterToBodyMassRatio, + out Vector3 velocityChangeOnCharacter, + out Vector3 velocityChangeOnBody) + { + velocityChangeOnCharacter = default; + velocityChangeOnBody = default; + + float bodyToCharacterMassRatio = 1f - characterToBodyMassRatio; + float characterVelocityMagnitudeOnHitNormal = Vector3.Dot(characterVelocity, hitNormal); + float bodyVelocityMagnitudeOnHitNormal = Vector3.Dot(bodyVelocity, hitNormal); + + // if character velocity was going against the obstruction, restore the portion of the velocity that got projected during the movement phase + if (characterVelocityMagnitudeOnHitNormal < 0f) + { + Vector3 restoredCharacterVelocity = hitNormal * characterVelocityMagnitudeOnHitNormal; + velocityChangeOnCharacter += restoredCharacterVelocity; + } + + // solve impulse velocities on both bodies, but only if the body velocity would be giving resistance to the character in any way + if (bodyVelocityMagnitudeOnHitNormal > characterVelocityMagnitudeOnHitNormal) + { + Vector3 relativeImpactVelocity = hitNormal * (bodyVelocityMagnitudeOnHitNormal - characterVelocityMagnitudeOnHitNormal); + velocityChangeOnCharacter += relativeImpactVelocity * bodyToCharacterMassRatio; + velocityChangeOnBody += -relativeImpactVelocity * characterToBodyMassRatio; + } + } + + /// + /// Determines if the input collider is valid for collision processing + /// + /// Returns true if the collider is valid + private bool CheckIfColliderValidForCollisions(Collider coll) + { + // Ignore self + if (coll == Capsule) + { + return false; + } + + if (!InternalIsColliderValidForCollisions(coll)) + { + return false; + } + + return true; + } + + /// + /// Determines if the input collider is valid for collision processing + /// + private bool InternalIsColliderValidForCollisions(Collider coll) + { + Rigidbody colliderAttachedRigidbody = coll.attachedRigidbody; + if (colliderAttachedRigidbody) + { + bool isRigidbodyKinematic = colliderAttachedRigidbody.isKinematic; + + // If movement is made from AttachedRigidbody, ignore the AttachedRigidbody + if (_isMovingFromAttachedRigidbody && (!isRigidbodyKinematic || colliderAttachedRigidbody == _attachedRigidbody)) + { + return false; + } + + // don't collide with dynamic rigidbodies if our RigidbodyInteractionType is kinematic + if (RigidbodyInteractionType == RigidbodyInteractionType.Kinematic && !isRigidbodyKinematic) + { + // wake up rigidbody + if (coll.attachedRigidbody) + { + coll.attachedRigidbody.WakeUp(); + } + + return false; + } + } + + // Custom checks + bool colliderValid = CharacterController.IsColliderValidForCollisions(coll); + if (!colliderValid) + { + return false; + } + + return true; + } + + /// + /// Determines if the motor is considered stable on a given hit + /// + public void EvaluateHitStability(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, Vector3 atCharacterPosition, Quaternion atCharacterRotation, Vector3 withCharacterVelocity, ref HitStabilityReport stabilityReport) + { + if (!_solveGrounding) + { + stabilityReport.IsStable = false; + return; + } + + Vector3 atCharacterUp = atCharacterRotation * _cachedWorldUp; + Vector3 innerHitDirection = Vector3.ProjectOnPlane(hitNormal, atCharacterUp).normalized; + + stabilityReport.IsStable = this.IsStableOnNormal(hitNormal); + + stabilityReport.FoundInnerNormal = false; + stabilityReport.FoundOuterNormal = false; + stabilityReport.InnerNormal = hitNormal; + stabilityReport.OuterNormal = hitNormal; + + // Ledge handling + if (LedgeAndDenivelationHandling) + { + float ledgeCheckHeight = MinDistanceForLedge; + if (StepHandling != StepHandlingMethod.None) + { + ledgeCheckHeight = MaxStepHeight; + } + + bool isStableLedgeInner = false; + bool isStableLedgeOuter = false; + + if (CharacterCollisionsRaycast( + hitPoint + (atCharacterUp * SecondaryProbesVertical) + (innerHitDirection * SecondaryProbesHorizontal), + -atCharacterUp, + ledgeCheckHeight + SecondaryProbesVertical, + out RaycastHit innerLedgeHit, + _internalCharacterHits) > 0) + { + Vector3 innerLedgeNormal = innerLedgeHit.normal; + stabilityReport.InnerNormal = innerLedgeNormal; + stabilityReport.FoundInnerNormal = true; + isStableLedgeInner = IsStableOnNormal(innerLedgeNormal); + } + + if (CharacterCollisionsRaycast( + hitPoint + (atCharacterUp * SecondaryProbesVertical) + (-innerHitDirection * SecondaryProbesHorizontal), + -atCharacterUp, + ledgeCheckHeight + SecondaryProbesVertical, + out RaycastHit outerLedgeHit, + _internalCharacterHits) > 0) + { + Vector3 outerLedgeNormal = outerLedgeHit.normal; + stabilityReport.OuterNormal = outerLedgeNormal; + stabilityReport.FoundOuterNormal = true; + isStableLedgeOuter = IsStableOnNormal(outerLedgeNormal); + } + + stabilityReport.LedgeDetected = (isStableLedgeInner != isStableLedgeOuter); + if (stabilityReport.LedgeDetected) + { + stabilityReport.IsOnEmptySideOfLedge = isStableLedgeOuter && !isStableLedgeInner; + stabilityReport.LedgeGroundNormal = isStableLedgeOuter ? stabilityReport.OuterNormal : stabilityReport.InnerNormal; + stabilityReport.LedgeRightDirection = Vector3.Cross(hitNormal, stabilityReport.LedgeGroundNormal).normalized; + stabilityReport.LedgeFacingDirection = Vector3.ProjectOnPlane(Vector3.Cross(stabilityReport.LedgeGroundNormal, stabilityReport.LedgeRightDirection), CharacterUp).normalized; + stabilityReport.DistanceFromLedge = Vector3.ProjectOnPlane((hitPoint - (atCharacterPosition + (atCharacterRotation * _characterTransformToCapsuleBottom))), atCharacterUp).magnitude; + stabilityReport.IsMovingTowardsEmptySideOfLedge = Vector3.Dot(withCharacterVelocity.normalized, stabilityReport.LedgeFacingDirection) > 0f; + } + + if (stabilityReport.IsStable) + { + stabilityReport.IsStable = IsStableWithSpecialCases(ref stabilityReport, withCharacterVelocity); + } + } + + // Step handling + if (StepHandling != StepHandlingMethod.None && !stabilityReport.IsStable) + { + // Stepping not supported on dynamic rigidbodies + Rigidbody hitRigidbody = hitCollider.attachedRigidbody; + if (!(hitRigidbody && !hitRigidbody.isKinematic)) + { + DetectSteps(atCharacterPosition, atCharacterRotation, hitPoint, innerHitDirection, ref stabilityReport); + + if (stabilityReport.ValidStepDetected) + { + stabilityReport.IsStable = true; + } + } + } + + CharacterController.ProcessHitStabilityReport(hitCollider, hitNormal, hitPoint, atCharacterPosition, atCharacterRotation, ref stabilityReport); + } + + private void DetectSteps(Vector3 characterPosition, Quaternion characterRotation, Vector3 hitPoint, Vector3 innerHitDirection, ref HitStabilityReport stabilityReport) + { + int nbStepHits = 0; + Collider tmpCollider; + RaycastHit outerStepHit; + Vector3 characterUp = characterRotation * _cachedWorldUp; + Vector3 verticalCharToHit = Vector3.Project((hitPoint - characterPosition), characterUp); + Vector3 horizontalCharToHitDirection = Vector3.ProjectOnPlane((hitPoint - characterPosition), characterUp).normalized; + Vector3 stepCheckStartPos = (hitPoint - verticalCharToHit) + (characterUp * MaxStepHeight) + (horizontalCharToHitDirection * CollisionOffset * 3f); + + // Do outer step check with capsule cast on hit point + nbStepHits = CharacterCollisionsSweep( + stepCheckStartPos, + characterRotation, + -characterUp, + MaxStepHeight + CollisionOffset, + out outerStepHit, + _internalCharacterHits, + 0f, + true); + + // Check for overlaps and obstructions at the hit position + if (CheckStepValidity(nbStepHits, characterPosition, characterRotation, innerHitDirection, stepCheckStartPos, out tmpCollider)) + { + stabilityReport.ValidStepDetected = true; + stabilityReport.SteppedCollider = tmpCollider; + } + + if (StepHandling == StepHandlingMethod.Extra && !stabilityReport.ValidStepDetected) + { + // Do min reach step check with capsule cast on hit point + stepCheckStartPos = characterPosition + (characterUp * MaxStepHeight) + (-innerHitDirection * MinRequiredStepDepth); + nbStepHits = CharacterCollisionsSweep( + stepCheckStartPos, + characterRotation, + -characterUp, + MaxStepHeight - CollisionOffset, + out outerStepHit, + _internalCharacterHits, + 0f, + true); + + // Check for overlaps and obstructions at the hit position + if (CheckStepValidity(nbStepHits, characterPosition, characterRotation, innerHitDirection, stepCheckStartPos, out tmpCollider)) + { + stabilityReport.ValidStepDetected = true; + stabilityReport.SteppedCollider = tmpCollider; + } + } + } + + private bool CheckStepValidity(int nbStepHits, Vector3 characterPosition, Quaternion characterRotation, Vector3 innerHitDirection, Vector3 stepCheckStartPos, out Collider hitCollider) + { + hitCollider = null; + Vector3 characterUp = characterRotation * Vector3.up; + + // Find the farthest valid hit for stepping + bool foundValidStepPosition = false; + + while (nbStepHits > 0 && !foundValidStepPosition) + { + // Get farthest hit among the remaining hits + RaycastHit farthestHit = new RaycastHit(); + float farthestDistance = 0f; + int farthestIndex = 0; + for (int i = 0; i < nbStepHits; i++) + { + float hitDistance = _internalCharacterHits[i].distance; + if (hitDistance > farthestDistance) + { + farthestDistance = hitDistance; + farthestHit = _internalCharacterHits[i]; + farthestIndex = i; + } + } + + Vector3 characterPositionAtHit = stepCheckStartPos + (-characterUp * (farthestHit.distance - CollisionOffset)); + + int atStepOverlaps = CharacterCollisionsOverlap(characterPositionAtHit, characterRotation, _internalProbedColliders); + if (atStepOverlaps <= 0) + { + // Check for outer hit slope normal stability at the step position + if (CharacterCollisionsRaycast( + farthestHit.point + (characterUp * SecondaryProbesVertical) + (-innerHitDirection * SecondaryProbesHorizontal), + -characterUp, + MaxStepHeight + SecondaryProbesVertical, + out RaycastHit outerSlopeHit, + _internalCharacterHits, + true) > 0) + { + if (IsStableOnNormal(outerSlopeHit.normal)) + { + // Cast upward to detect any obstructions to moving there + if (CharacterCollisionsSweep( + characterPosition, // position + characterRotation, // rotation + characterUp, // direction + MaxStepHeight - farthestHit.distance, // distance + out RaycastHit tmpUpObstructionHit, // closest hit + _internalCharacterHits) // all hits + <= 0) + { + // Do inner step check... + bool innerStepValid = false; + RaycastHit innerStepHit; + + if (AllowSteppingWithoutStableGrounding) + { + innerStepValid = true; + } + else + { + // At the capsule center at the step height + if (CharacterCollisionsRaycast( + characterPosition + Vector3.Project((characterPositionAtHit - characterPosition), characterUp), + -characterUp, + MaxStepHeight, + out innerStepHit, + _internalCharacterHits, + true) > 0) + { + if (IsStableOnNormal(innerStepHit.normal)) + { + innerStepValid = true; + } + } + } + + if (!innerStepValid) + { + // At inner step of the step point + if (CharacterCollisionsRaycast( + farthestHit.point + (innerHitDirection * SecondaryProbesHorizontal), + -characterUp, + MaxStepHeight, + out innerStepHit, + _internalCharacterHits, + true) > 0) + { + if (IsStableOnNormal(innerStepHit.normal)) + { + innerStepValid = true; + } + } + } + + // Final validation of step + if (innerStepValid) + { + hitCollider = farthestHit.collider; + foundValidStepPosition = true; + return true; + } + } + } + } + } + + // Discard hit if not valid step + if (!foundValidStepPosition) + { + nbStepHits--; + if (farthestIndex < nbStepHits) + { + _internalCharacterHits[farthestIndex] = _internalCharacterHits[nbStepHits]; + } + } + } + + return false; + } + + /// + /// Get true linear velocity (taking into account rotational velocity) on a given point of a rigidbody + /// + public void GetVelocityFromRigidbodyMovement(Rigidbody interactiveRigidbody, Vector3 atPoint, float deltaTime, out Vector3 linearVelocity, out Vector3 angularVelocity) + { + if (deltaTime > 0f) + { + linearVelocity = interactiveRigidbody.linearVelocity; + angularVelocity = interactiveRigidbody.angularVelocity; + if(interactiveRigidbody.isKinematic) + { + PhysicsMover physicsMover = interactiveRigidbody.GetComponent(); + if (physicsMover) + { + linearVelocity = physicsMover.Velocity; + angularVelocity = physicsMover.AngularVelocity; + } + } + + if (angularVelocity != Vector3.zero) + { + Vector3 centerOfRotation = interactiveRigidbody.transform.TransformPoint(interactiveRigidbody.centerOfMass); + + Vector3 centerOfRotationToPoint = atPoint - centerOfRotation; + Quaternion rotationFromInteractiveRigidbody = Quaternion.Euler(Mathf.Rad2Deg * angularVelocity * deltaTime); + Vector3 finalPointPosition = centerOfRotation + (rotationFromInteractiveRigidbody * centerOfRotationToPoint); + linearVelocity += (finalPointPosition - atPoint) / deltaTime; + } + } + else + { + linearVelocity = default; + angularVelocity = default; + return; + } + } + + /// + /// Determines if a collider has an attached interactive rigidbody + /// + private Rigidbody GetInteractiveRigidbody(Collider onCollider) + { + Rigidbody colliderAttachedRigidbody = onCollider.attachedRigidbody; + if (colliderAttachedRigidbody) + { + if (colliderAttachedRigidbody.gameObject.GetComponent()) + { + return colliderAttachedRigidbody; + } + + if (!colliderAttachedRigidbody.isKinematic) + { + return colliderAttachedRigidbody; + } + } + return null; + } + + /// + /// Calculates the velocity required to move the character to the target position over a specific deltaTime. + /// Useful for when you wish to work with positions rather than velocities in the UpdateVelocity callback + /// + public Vector3 GetVelocityForMovePosition(Vector3 fromPosition, Vector3 toPosition, float deltaTime) + { + return GetVelocityFromMovement(toPosition - fromPosition, deltaTime); + } + + public Vector3 GetVelocityFromMovement(Vector3 movement, float deltaTime) + { + if (deltaTime <= 0f) + return Vector3.zero; + + return movement / deltaTime; + } + + /// + /// Trims a vector to make it restricted against a plane + /// + private void RestrictVectorToPlane(ref Vector3 vector, Vector3 toPlane) + { + if (vector.x > 0 != toPlane.x > 0) + { + vector.x = 0; + } + if (vector.y > 0 != toPlane.y > 0) + { + vector.y = 0; + } + if (vector.z > 0 != toPlane.z > 0) + { + vector.z = 0; + } + } + + /// + /// Detect if the character capsule is overlapping with anything collidable + /// + /// Returns number of overlaps + public int CharacterCollisionsOverlap(Vector3 position, Quaternion rotation, Collider[] overlappedColliders, float inflate = 0f, bool acceptOnlyStableGroundLayer = false) + { + int queryLayers = CollidableLayers; + if (acceptOnlyStableGroundLayer) + { + queryLayers = CollidableLayers & StableGroundLayers; + } + + Vector3 bottom = position + (rotation * _characterTransformToCapsuleBottomHemi); + Vector3 top = position + (rotation * _characterTransformToCapsuleTopHemi); + if (inflate != 0f) + { + bottom += (rotation * Vector3.down * inflate); + top += (rotation * Vector3.up * inflate); + } + + int nbHits = 0; + int nbUnfilteredHits = Physics.OverlapCapsuleNonAlloc( + bottom, + top, + Capsule.radius + inflate, + overlappedColliders, + queryLayers, + QueryTriggerInteraction.Ignore); + + // Filter out invalid colliders + nbHits = nbUnfilteredHits; + for (int i = nbUnfilteredHits - 1; i >= 0; i--) + { + if (!CheckIfColliderValidForCollisions(overlappedColliders[i])) + { + nbHits--; + if (i < nbHits) + { + overlappedColliders[i] = overlappedColliders[nbHits]; + } + } + } + + return nbHits; + } + + /// + /// Detect if the character capsule is overlapping with anything + /// + /// Returns number of overlaps + public int CharacterOverlap(Vector3 position, Quaternion rotation, Collider[] overlappedColliders, LayerMask layers, QueryTriggerInteraction triggerInteraction, float inflate = 0f) + { + Vector3 bottom = position + (rotation * _characterTransformToCapsuleBottomHemi); + Vector3 top = position + (rotation * _characterTransformToCapsuleTopHemi); + if (inflate != 0f) + { + bottom += (rotation * Vector3.down * inflate); + top += (rotation * Vector3.up * inflate); + } + + int nbHits = 0; + int nbUnfilteredHits = Physics.OverlapCapsuleNonAlloc( + bottom, + top, + Capsule.radius + inflate, + overlappedColliders, + layers, + triggerInteraction); + + // Filter out the character capsule itself + nbHits = nbUnfilteredHits; + for (int i = nbUnfilteredHits - 1; i >= 0; i--) + { + if (overlappedColliders[i] == Capsule) + { + nbHits--; + if (i < nbHits) + { + overlappedColliders[i] = overlappedColliders[nbHits]; + } + } + } + + return nbHits; + } + + /// + /// Sweeps the capsule's volume to detect collision hits + /// + /// Returns the number of hits + public int CharacterCollisionsSweep(Vector3 position, Quaternion rotation, Vector3 direction, float distance, out RaycastHit closestHit, RaycastHit[] hits, float inflate = 0f, bool acceptOnlyStableGroundLayer = false) + { + int queryLayers = CollidableLayers; + if (acceptOnlyStableGroundLayer) + { + queryLayers = CollidableLayers & StableGroundLayers; + } + + Vector3 bottom = position + (rotation * _characterTransformToCapsuleBottomHemi) - (direction * SweepProbingBackstepDistance); + Vector3 top = position + (rotation * _characterTransformToCapsuleTopHemi) - (direction * SweepProbingBackstepDistance); + if (inflate != 0f) + { + bottom += (rotation * Vector3.down * inflate); + top += (rotation * Vector3.up * inflate); + } + + // Capsule cast + int nbHits = 0; + int nbUnfilteredHits = Physics.CapsuleCastNonAlloc( + bottom, + top, + Capsule.radius + inflate, + direction, + hits, + distance + SweepProbingBackstepDistance, + queryLayers, + QueryTriggerInteraction.Ignore); + + // Hits filter + closestHit = new RaycastHit(); + float closestDistance = Mathf.Infinity; + nbHits = nbUnfilteredHits; + for (int i = nbUnfilteredHits - 1; i >= 0; i--) + { + hits[i].distance -= SweepProbingBackstepDistance; + + RaycastHit hit = hits[i]; + float hitDistance = hit.distance; + + // Filter out the invalid hits + if (hitDistance <= 0f || !CheckIfColliderValidForCollisions(hit.collider)) + { + nbHits--; + if (i < nbHits) + { + hits[i] = hits[nbHits]; + } + } + else + { + // Remember closest valid hit + if (hitDistance < closestDistance) + { + closestHit = hit; + closestDistance = hitDistance; + } + } + } + + return nbHits; + } + + /// + /// Sweeps the capsule's volume to detect hits + /// + /// Returns the number of hits + public int CharacterSweep(Vector3 position, Quaternion rotation, Vector3 direction, float distance, out RaycastHit closestHit, RaycastHit[] hits, LayerMask layers, QueryTriggerInteraction triggerInteraction, float inflate = 0f) + { + closestHit = new RaycastHit(); + + Vector3 bottom = position + (rotation * _characterTransformToCapsuleBottomHemi); + Vector3 top = position + (rotation * _characterTransformToCapsuleTopHemi); + if (inflate != 0f) + { + bottom += (rotation * Vector3.down * inflate); + top += (rotation * Vector3.up * inflate); + } + + // Capsule cast + int nbHits = 0; + int nbUnfilteredHits = Physics.CapsuleCastNonAlloc( + bottom, + top, + Capsule.radius + inflate, + direction, + hits, + distance, + layers, + triggerInteraction); + + // Hits filter + float closestDistance = Mathf.Infinity; + nbHits = nbUnfilteredHits; + for (int i = nbUnfilteredHits - 1; i >= 0; i--) + { + RaycastHit hit = hits[i]; + + // Filter out the character capsule + if (hit.distance <= 0f || hit.collider == Capsule) + { + nbHits--; + if (i < nbHits) + { + hits[i] = hits[nbHits]; + } + } + else + { + // Remember closest valid hit + float hitDistance = hit.distance; + if (hitDistance < closestDistance) + { + closestHit = hit; + closestDistance = hitDistance; + } + } + } + + return nbHits; + } + + /// + /// Casts the character volume in the character's downward direction to detect ground + /// + /// Returns the number of hits + private bool CharacterGroundSweep(Vector3 position, Quaternion rotation, Vector3 direction, float distance, out RaycastHit closestHit) + { + closestHit = new RaycastHit(); + + // Capsule cast + int nbUnfilteredHits = Physics.CapsuleCastNonAlloc( + position + (rotation * _characterTransformToCapsuleBottomHemi) - (direction * GroundProbingBackstepDistance), + position + (rotation * _characterTransformToCapsuleTopHemi) - (direction * GroundProbingBackstepDistance), + Capsule.radius, + direction, + _internalCharacterHits, + distance + GroundProbingBackstepDistance, + CollidableLayers & StableGroundLayers, + QueryTriggerInteraction.Ignore); + + // Hits filter + bool foundValidHit = false; + float closestDistance = Mathf.Infinity; + for (int i = 0; i < nbUnfilteredHits; i++) + { + RaycastHit hit = _internalCharacterHits[i]; + float hitDistance = hit.distance; + + // Find the closest valid hit + if (hitDistance > 0f && CheckIfColliderValidForCollisions(hit.collider)) + { + if (hitDistance < closestDistance) + { + closestHit = hit; + closestHit.distance -= GroundProbingBackstepDistance; + closestDistance = hitDistance; + + foundValidHit = true; + } + } + } + + return foundValidHit; + } + + /// + /// Raycasts to detect collision hits + /// + /// Returns the number of hits + public int CharacterCollisionsRaycast(Vector3 position, Vector3 direction, float distance, out RaycastHit closestHit, RaycastHit[] hits, bool acceptOnlyStableGroundLayer = false) + { + int queryLayers = CollidableLayers; + if (acceptOnlyStableGroundLayer) + { + queryLayers = CollidableLayers & StableGroundLayers; + } + + // Raycast + int nbHits = 0; + int nbUnfilteredHits = Physics.RaycastNonAlloc( + position, + direction, + hits, + distance, + queryLayers, + QueryTriggerInteraction.Ignore); + + // Hits filter + closestHit = new RaycastHit(); + float closestDistance = Mathf.Infinity; + nbHits = nbUnfilteredHits; + for (int i = nbUnfilteredHits - 1; i >= 0; i--) + { + RaycastHit hit = hits[i]; + float hitDistance = hit.distance; + + // Filter out the invalid hits + if (hitDistance <= 0f || + !CheckIfColliderValidForCollisions(hit.collider)) + { + nbHits--; + if (i < nbHits) + { + hits[i] = hits[nbHits]; + } + } + else + { + // Remember closest valid hit + if (hitDistance < closestDistance) + { + closestHit = hit; + closestDistance = hitDistance; + } + } + } + + return nbHits; + } + } +} \ No newline at end of file diff --git a/Assets/KinematicCharacterController/Core/KinematicCharacterMotor.cs.meta b/Assets/KinematicCharacterController/Core/KinematicCharacterMotor.cs.meta new file mode 100644 index 00000000..89a567c5 --- /dev/null +++ b/Assets/KinematicCharacterController/Core/KinematicCharacterMotor.cs.meta @@ -0,0 +1,18 @@ +fileFormatVersion: 2 +guid: 4d1bc5515e3ab954e80599c538834774 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 99131 + packageName: Kinematic Character Controller + packageVersion: 3.4.4 + assetPath: Assets/KinematicCharacterController/Core/KinematicCharacterMotor.cs + uploadId: 505601 diff --git a/Assets/KinematicCharacterController/Core/KinematicCharacterSystem.cs b/Assets/KinematicCharacterController/Core/KinematicCharacterSystem.cs new file mode 100644 index 00000000..b838d14d --- /dev/null +++ b/Assets/KinematicCharacterController/Core/KinematicCharacterSystem.cs @@ -0,0 +1,294 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace KinematicCharacterController +{ + /// + /// The system that manages the simulation of KinematicCharacterMotor and PhysicsMover + /// + [DefaultExecutionOrder(-100)] + public class KinematicCharacterSystem : MonoBehaviour + { + private static KinematicCharacterSystem _instance; + + public static List CharacterMotors = new List(); + public static List PhysicsMovers = new List(); + + private static float _lastCustomInterpolationStartTime = -1f; + private static float _lastCustomInterpolationDeltaTime = -1f; + + public static KCCSettings Settings; + + /// + /// Creates a KinematicCharacterSystem instance if there isn't already one + /// + public static void EnsureCreation() + { + if (_instance == null) + { + GameObject systemGameObject = new GameObject("KinematicCharacterSystem"); + _instance = systemGameObject.AddComponent(); + + systemGameObject.hideFlags = HideFlags.NotEditable; + _instance.hideFlags = HideFlags.NotEditable; + + Settings = ScriptableObject.CreateInstance(); + + GameObject.DontDestroyOnLoad(systemGameObject); + } + } + + /// + /// Gets the KinematicCharacterSystem instance if any + /// + /// + public static KinematicCharacterSystem GetInstance() + { + return _instance; + } + + /// + /// Sets the maximum capacity of the character motors list, to prevent allocations when adding characters + /// + /// + public static void SetCharacterMotorsCapacity(int capacity) + { + if (capacity < CharacterMotors.Count) + { + capacity = CharacterMotors.Count; + } + CharacterMotors.Capacity = capacity; + } + + /// + /// Registers a KinematicCharacterMotor into the system + /// + public static void RegisterCharacterMotor(KinematicCharacterMotor motor) + { + CharacterMotors.Add(motor); + } + + /// + /// Unregisters a KinematicCharacterMotor from the system + /// + public static void UnregisterCharacterMotor(KinematicCharacterMotor motor) + { + CharacterMotors.Remove(motor); + } + + /// + /// Sets the maximum capacity of the physics movers list, to prevent allocations when adding movers + /// + /// + public static void SetPhysicsMoversCapacity(int capacity) + { + if (capacity < PhysicsMovers.Count) + { + capacity = PhysicsMovers.Count; + } + PhysicsMovers.Capacity = capacity; + } + + /// + /// Registers a PhysicsMover into the system + /// + public static void RegisterPhysicsMover(PhysicsMover mover) + { + PhysicsMovers.Add(mover); + + mover.Rigidbody.interpolation = RigidbodyInterpolation.None; + } + + /// + /// Unregisters a PhysicsMover from the system + /// + public static void UnregisterPhysicsMover(PhysicsMover mover) + { + PhysicsMovers.Remove(mover); + } + + // This is to prevent duplicating the singleton gameobject on script recompiles + private void OnDisable() + { + Destroy(this.gameObject); + } + + private void Awake() + { + _instance = this; + } + + private void FixedUpdate() + { + if (Settings.AutoSimulation) + { + float deltaTime = Time.deltaTime; + + if (Settings.Interpolate) + { + PreSimulationInterpolationUpdate(deltaTime); + } + + Simulate(deltaTime, CharacterMotors, PhysicsMovers); + + if (Settings.Interpolate) + { + PostSimulationInterpolationUpdate(deltaTime); + } + } + } + + private void LateUpdate() + { + if (Settings.Interpolate) + { + CustomInterpolationUpdate(); + } + } + + /// + /// Remembers the point to interpolate from for KinematicCharacterMotors and PhysicsMovers + /// + public static void PreSimulationInterpolationUpdate(float deltaTime) + { + // Save pre-simulation poses and place transform at transient pose + for (int i = 0; i < CharacterMotors.Count; i++) + { + KinematicCharacterMotor motor = CharacterMotors[i]; + + motor.InitialTickPosition = motor.TransientPosition; + motor.InitialTickRotation = motor.TransientRotation; + + motor.Transform.SetPositionAndRotation(motor.TransientPosition, motor.TransientRotation); + } + + for (int i = 0; i < PhysicsMovers.Count; i++) + { + PhysicsMover mover = PhysicsMovers[i]; + + mover.InitialTickPosition = mover.TransientPosition; + mover.InitialTickRotation = mover.TransientRotation; + + mover.Transform.SetPositionAndRotation(mover.TransientPosition, mover.TransientRotation); + mover.Rigidbody.position = mover.TransientPosition; + mover.Rigidbody.rotation = mover.TransientRotation; + } + } + + /// + /// Ticks characters and/or movers + /// + public static void Simulate(float deltaTime, List motors, List movers) + { + int characterMotorsCount = motors.Count; + int physicsMoversCount = movers.Count; + +#pragma warning disable 0162 + // Update PhysicsMover velocities + for (int i = 0; i < physicsMoversCount; i++) + { + movers[i].VelocityUpdate(deltaTime); + } + + // Character controller update phase 1 + for (int i = 0; i < characterMotorsCount; i++) + { + motors[i].UpdatePhase1(deltaTime); + } + + // Simulate PhysicsMover displacement + for (int i = 0; i < physicsMoversCount; i++) + { + PhysicsMover mover = movers[i]; + + mover.Transform.SetPositionAndRotation(mover.TransientPosition, mover.TransientRotation); + mover.Rigidbody.position = mover.TransientPosition; + mover.Rigidbody.rotation = mover.TransientRotation; + } + + // Character controller update phase 2 and move + for (int i = 0; i < characterMotorsCount; i++) + { + KinematicCharacterMotor motor = motors[i]; + + motor.UpdatePhase2(deltaTime); + + motor.Transform.SetPositionAndRotation(motor.TransientPosition, motor.TransientRotation); + } +#pragma warning restore 0162 + } + + /// + /// Initiates the interpolation for KinematicCharacterMotors and PhysicsMovers + /// + public static void PostSimulationInterpolationUpdate(float deltaTime) + { + _lastCustomInterpolationStartTime = Time.time; + _lastCustomInterpolationDeltaTime = deltaTime; + + // Return interpolated roots to their initial poses + for (int i = 0; i < CharacterMotors.Count; i++) + { + KinematicCharacterMotor motor = CharacterMotors[i]; + + motor.Transform.SetPositionAndRotation(motor.InitialTickPosition, motor.InitialTickRotation); + } + + for (int i = 0; i < PhysicsMovers.Count; i++) + { + PhysicsMover mover = PhysicsMovers[i]; + + if (mover.MoveWithPhysics) + { + mover.Rigidbody.position = mover.InitialTickPosition; + mover.Rigidbody.rotation = mover.InitialTickRotation; + + mover.Rigidbody.MovePosition(mover.TransientPosition); + mover.Rigidbody.MoveRotation(mover.TransientRotation); + } + else + { + mover.Rigidbody.position = (mover.TransientPosition); + mover.Rigidbody.rotation = (mover.TransientRotation); + } + } + } + + /// + /// Handles per-frame interpolation + /// + private static void CustomInterpolationUpdate() + { + float interpolationFactor = Mathf.Clamp01((Time.time - _lastCustomInterpolationStartTime) / _lastCustomInterpolationDeltaTime); + + // Handle characters interpolation + for (int i = 0; i < CharacterMotors.Count; i++) + { + KinematicCharacterMotor motor = CharacterMotors[i]; + + motor.Transform.SetPositionAndRotation( + Vector3.Lerp(motor.InitialTickPosition, motor.TransientPosition, interpolationFactor), + Quaternion.Slerp(motor.InitialTickRotation, motor.TransientRotation, interpolationFactor)); + } + + // Handle PhysicsMovers interpolation + for (int i = 0; i < PhysicsMovers.Count; i++) + { + PhysicsMover mover = PhysicsMovers[i]; + + mover.Transform.SetPositionAndRotation( + Vector3.Lerp(mover.InitialTickPosition, mover.TransientPosition, interpolationFactor), + Quaternion.Slerp(mover.InitialTickRotation, mover.TransientRotation, interpolationFactor)); + + Vector3 newPos = mover.Transform.position; + Quaternion newRot = mover.Transform.rotation; + mover.PositionDeltaFromInterpolation = newPos - mover.LatestInterpolationPosition; + mover.RotationDeltaFromInterpolation = Quaternion.Inverse(mover.LatestInterpolationRotation) * newRot; + mover.LatestInterpolationPosition = newPos; + mover.LatestInterpolationRotation = newRot; + } + } + } +} \ No newline at end of file diff --git a/Assets/KinematicCharacterController/Core/KinematicCharacterSystem.cs.meta b/Assets/KinematicCharacterController/Core/KinematicCharacterSystem.cs.meta new file mode 100644 index 00000000..2f4c3405 --- /dev/null +++ b/Assets/KinematicCharacterController/Core/KinematicCharacterSystem.cs.meta @@ -0,0 +1,19 @@ +fileFormatVersion: 2 +guid: dbd80c9a62d41084aad50ae44255beb9 +timeCreated: 1500241576 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 99131 + packageName: Kinematic Character Controller + packageVersion: 3.4.4 + assetPath: Assets/KinematicCharacterController/Core/KinematicCharacterSystem.cs + uploadId: 505601 diff --git a/Assets/KinematicCharacterController/Core/PhysicsMover.cs b/Assets/KinematicCharacterController/Core/PhysicsMover.cs new file mode 100644 index 00000000..2af310ca --- /dev/null +++ b/Assets/KinematicCharacterController/Core/PhysicsMover.cs @@ -0,0 +1,261 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace KinematicCharacterController +{ + /// + /// Represents the entire state of a PhysicsMover that is pertinent for simulation. + /// Use this to save state or revert to past state + /// + [System.Serializable] + public struct PhysicsMoverState + { + public Vector3 Position; + public Quaternion Rotation; + public Vector3 Velocity; + public Vector3 AngularVelocity; + } + + /// + /// Component that manages the movement of moving kinematic rigidbodies for + /// proper interaction with characters + /// + [RequireComponent(typeof(Rigidbody))] + public class PhysicsMover : MonoBehaviour + { + /// + /// The mover's Rigidbody + /// + [ReadOnly] + public Rigidbody Rigidbody; + + /// + /// Determines if the platform moves with rigidbody.MovePosition (when true), or with rigidbody.position (when false) + /// + public bool MoveWithPhysics = true; + + /// + /// Index of this motor in KinematicCharacterSystem arrays + /// + [NonSerialized] + public IMoverController MoverController; + /// + /// Remembers latest position in interpolation + /// + [NonSerialized] + public Vector3 LatestInterpolationPosition; + /// + /// Remembers latest rotation in interpolation + /// + [NonSerialized] + public Quaternion LatestInterpolationRotation; + /// + /// The latest movement made by interpolation + /// + [NonSerialized] + public Vector3 PositionDeltaFromInterpolation; + /// + /// The latest rotation made by interpolation + /// + [NonSerialized] + public Quaternion RotationDeltaFromInterpolation; + + /// + /// Index of this motor in KinematicCharacterSystem arrays + /// + public int IndexInCharacterSystem { get; set; } + /// + /// Remembers initial position before all simulation are done + /// + public Vector3 Velocity { get; protected set; } + /// + /// Remembers initial position before all simulation are done + /// + public Vector3 AngularVelocity { get; protected set; } + /// + /// Remembers initial position before all simulation are done + /// + public Vector3 InitialTickPosition { get; set; } + /// + /// Remembers initial rotation before all simulation are done + /// + public Quaternion InitialTickRotation { get; set; } + + /// + /// The mover's Transform + /// + public Transform Transform { get; private set; } + /// + /// The character's position before the movement calculations began + /// + public Vector3 InitialSimulationPosition { get; private set; } + /// + /// The character's rotation before the movement calculations began + /// + public Quaternion InitialSimulationRotation { get; private set; } + + private Vector3 _internalTransientPosition; + + /// + /// The mover's rotation (always up-to-date during the character update phase) + /// + public Vector3 TransientPosition + { + get + { + return _internalTransientPosition; + } + private set + { + _internalTransientPosition = value; + } + } + + private Quaternion _internalTransientRotation; + /// + /// The mover's rotation (always up-to-date during the character update phase) + /// + public Quaternion TransientRotation + { + get + { + return _internalTransientRotation; + } + private set + { + _internalTransientRotation = value; + } + } + + + private void Reset() + { + ValidateData(); + } + + private void OnValidate() + { + ValidateData(); + } + + /// + /// Handle validating all required values + /// + public void ValidateData() + { + Rigidbody = gameObject.GetComponent(); + + Rigidbody.centerOfMass = Vector3.zero; + Rigidbody.maxAngularVelocity = Mathf.Infinity; + Rigidbody.maxDepenetrationVelocity = Mathf.Infinity; + Rigidbody.isKinematic = true; + Rigidbody.interpolation = RigidbodyInterpolation.None; + } + + private void OnEnable() + { + KinematicCharacterSystem.EnsureCreation(); + KinematicCharacterSystem.RegisterPhysicsMover(this); + } + + private void OnDisable() + { + KinematicCharacterSystem.UnregisterPhysicsMover(this); + } + + private void Awake() + { + Transform = this.transform; + ValidateData(); + + TransientPosition = Rigidbody.position; + TransientRotation = Rigidbody.rotation; + InitialSimulationPosition = Rigidbody.position; + InitialSimulationRotation = Rigidbody.rotation; + LatestInterpolationPosition = Transform.position; + LatestInterpolationRotation = Transform.rotation; + } + + /// + /// Sets the mover's position directly + /// + public void SetPosition(Vector3 position) + { + Transform.position = position; + Rigidbody.position = position; + InitialSimulationPosition = position; + TransientPosition = position; + } + + /// + /// Sets the mover's rotation directly + /// + public void SetRotation(Quaternion rotation) + { + Transform.rotation = rotation; + Rigidbody.rotation = rotation; + InitialSimulationRotation = rotation; + TransientRotation = rotation; + } + + /// + /// Sets the mover's position and rotation directly + /// + public void SetPositionAndRotation(Vector3 position, Quaternion rotation) + { + Transform.SetPositionAndRotation(position, rotation); + Rigidbody.position = position; + Rigidbody.rotation = rotation; + InitialSimulationPosition = position; + InitialSimulationRotation = rotation; + TransientPosition = position; + TransientRotation = rotation; + } + + /// + /// Returns all the state information of the mover that is pertinent for simulation + /// + public PhysicsMoverState GetState() + { + PhysicsMoverState state = new PhysicsMoverState(); + + state.Position = TransientPosition; + state.Rotation = TransientRotation; + state.Velocity = Velocity; + state.AngularVelocity = AngularVelocity; + + return state; + } + + /// + /// Applies a mover state instantly + /// + public void ApplyState(PhysicsMoverState state) + { + SetPositionAndRotation(state.Position, state.Rotation); + Velocity = state.Velocity; + AngularVelocity = state.AngularVelocity; + } + + /// + /// Caches velocity values based on deltatime and target position/rotations + /// + public void VelocityUpdate(float deltaTime) + { + InitialSimulationPosition = TransientPosition; + InitialSimulationRotation = TransientRotation; + + MoverController.UpdateMovement(out _internalTransientPosition, out _internalTransientRotation, deltaTime); + + if (deltaTime > 0f) + { + Velocity = (TransientPosition - InitialSimulationPosition) / deltaTime; + + Quaternion rotationFromCurrentToGoal = TransientRotation * (Quaternion.Inverse(InitialSimulationRotation)); + AngularVelocity = (Mathf.Deg2Rad * rotationFromCurrentToGoal.eulerAngles) / deltaTime; + } + } + } +} \ No newline at end of file diff --git a/Assets/KinematicCharacterController/Core/PhysicsMover.cs.meta b/Assets/KinematicCharacterController/Core/PhysicsMover.cs.meta new file mode 100644 index 00000000..5b821d80 --- /dev/null +++ b/Assets/KinematicCharacterController/Core/PhysicsMover.cs.meta @@ -0,0 +1,19 @@ +fileFormatVersion: 2 +guid: 075ccbe9837b0744985e09ba3f015b9b +timeCreated: 1488089271 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 99131 + packageName: Kinematic Character Controller + packageVersion: 3.4.4 + assetPath: Assets/KinematicCharacterController/Core/PhysicsMover.cs + uploadId: 505601 diff --git a/Assets/KinematicCharacterController/Core/ReadOnlyAttribute.cs b/Assets/KinematicCharacterController/Core/ReadOnlyAttribute.cs new file mode 100644 index 00000000..918d460c --- /dev/null +++ b/Assets/KinematicCharacterController/Core/ReadOnlyAttribute.cs @@ -0,0 +1,8 @@ +using UnityEngine; + +namespace KinematicCharacterController +{ + public class ReadOnlyAttribute : PropertyAttribute + { + } +} \ No newline at end of file diff --git a/Assets/KinematicCharacterController/Core/ReadOnlyAttribute.cs.meta b/Assets/KinematicCharacterController/Core/ReadOnlyAttribute.cs.meta new file mode 100644 index 00000000..a6c96612 --- /dev/null +++ b/Assets/KinematicCharacterController/Core/ReadOnlyAttribute.cs.meta @@ -0,0 +1,20 @@ +fileFormatVersion: 2 +guid: 63e8828991cf67f42bfeb498686aad0b +timeCreated: 1504493014 +licenseType: Store +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: +AssetOrigin: + serializedVersion: 1 + productId: 99131 + packageName: Kinematic Character Controller + packageVersion: 3.4.4 + assetPath: Assets/KinematicCharacterController/Core/ReadOnlyAttribute.cs + uploadId: 505601 diff --git a/Assets/NuGet.config b/Assets/NuGet.config new file mode 100644 index 00000000..d267a780 --- /dev/null +++ b/Assets/NuGet.config @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Assets/NuGet.config.meta b/Assets/NuGet.config.meta new file mode 100644 index 00000000..15dad7b2 --- /dev/null +++ b/Assets/NuGet.config.meta @@ -0,0 +1,28 @@ +fileFormatVersion: 2 +guid: e5b92c5315e5dcca2a23f12e2d67643b +labels: +- NuGetForUnity +PluginImporter: + externalObjects: {} + serializedVersion: 3 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + Any: + enabled: 0 + settings: {} + Editor: + enabled: 0 + settings: + DefaultValueInitialized: true + WindowsStoreApps: + enabled: 0 + settings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages.meta b/Assets/Packages.meta new file mode 100644 index 00000000..badd119e --- /dev/null +++ b/Assets/Packages.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f831f729748e684579e431f4101536fc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0.meta new file mode 100644 index 00000000..c742490b --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 34b8958f6df85e8e1aa95185872496c2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/.signature.p7s b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/.signature.p7s new file mode 100644 index 0000000000000000000000000000000000000000..0b4d4a376f9dd2cdd6deb34eceebce6ee8bfe66d GIT binary patch literal 24214 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 literal 0 HcmV?d00001 diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/Icon.png b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/Icon.png new file mode 100644 index 00000000..b152ee09 --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/Icon.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3356b59b6d9c24db3a22398c0fb3430724052fe75ae5e8430ee8ede2fb713356 +size 7006 diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/Icon.png.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/Icon.png.meta new file mode 100644 index 00000000..c1aad1bc --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/Icon.png.meta @@ -0,0 +1,117 @@ +fileFormatVersion: 2 +guid: 412f003584fce34ad809414b872920ba +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/LICENSE.TXT b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/LICENSE.TXT new file mode 100644 index 00000000..984713a4 --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/LICENSE.TXT @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/LICENSE.TXT.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/LICENSE.TXT.meta new file mode 100644 index 00000000..25da620f --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/LICENSE.TXT.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 99e28d2ad8ac470d885a4c486df60957 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/Microsoft.Bcl.TimeProvider.nuspec b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/Microsoft.Bcl.TimeProvider.nuspec new file mode 100644 index 00000000..d350224f --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/Microsoft.Bcl.TimeProvider.nuspec @@ -0,0 +1,32 @@ + + + + Microsoft.Bcl.TimeProvider + 8.0.0 + Microsoft + MIT + https://licenses.nuget.org/MIT + Icon.png + PACKAGE.md + https://dot.net/ + Provides support for system time abstraction primitives for .NET Framework and .NET Standard. + +Commonly Used Types: +System.TimeProvider +System.ITimer + https://go.microsoft.com/fwlink/?LinkID=799421 + © Microsoft Corporation. All rights reserved. + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/Microsoft.Bcl.TimeProvider.nuspec.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/Microsoft.Bcl.TimeProvider.nuspec.meta new file mode 100644 index 00000000..7eac66f7 --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/Microsoft.Bcl.TimeProvider.nuspec.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b1b2f561ffba900639ea441c2378c573 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/PACKAGE.md b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/PACKAGE.md new file mode 100644 index 00000000..f3c9c372 --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/PACKAGE.md @@ -0,0 +1,57 @@ +## About + +Microsoft.Bcl.TimeProvider provides time abstraction support for apps targeting .NET 7 and earlier, as well as those intended for the .NET Framework. For apps targeting .NET 8 and newer versions, referencing this package is unnecessary, as the types it contains are already included in the .NET 8 and higher platform versions. + +## Key Features + +* Provides a common abstraction for time-related operations. + +## How to Use + +```csharp +using System; + +// A class that uses TimeProvider to get the current time in Utc coordinates +public class UtcClock +{ + private readonly TimeProvider _timeProvider; + + // Constructor that takes a TimeProvider as a dependency + public Clock(TimeProvider timeProvider) + { + _timeProvider = timeProvider; + } + + // A method that returns the current time as a string + public string GetTime() + { + return _timeProvider.GetLocalNow().ToString("HH:mm:ss"); + } +} + +// A class that inherits from TimeProvider and overrides the GetLocalNow method +public class UtcTimeProvider : TimeProvider +{ + // Override the GetLocalNow method to always return UTC time + public override DateTimeOffset GetLocalNow() + { + return TimeProvider.System.GetUtcNow(); + } +} + +``` + +## Main Types + +The main types provided by this library are: + +* `TimeProvider` +* `TimeProviderTaskExtensions` + +## Additional Documentation + +* [API documentation](https://learn.microsoft.com/dotnet/api/system.timeprovider) + +## Feedback & Contributing + +Microsoft.Bcl.TimeProvider is released as open source under the [MIT license](https://licenses.nuget.org/MIT). Bug reports and contributions are welcome at [the GitHub repository](https://github.com/dotnet/runtime). \ No newline at end of file diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/PACKAGE.md.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/PACKAGE.md.meta new file mode 100644 index 00000000..43b00f39 --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/PACKAGE.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 13574b8db8b6fc5f7977f11111709a2c +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/THIRD-PARTY-NOTICES.TXT b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/THIRD-PARTY-NOTICES.TXT new file mode 100644 index 00000000..4b40333f --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/THIRD-PARTY-NOTICES.TXT @@ -0,0 +1,1272 @@ +.NET Runtime uses third-party libraries or other resources that may be +distributed under licenses different than the .NET Runtime software. + +In the event that we accidentally failed to list a required notice, please +bring it to our attention. Post an issue or email us: + + dotnet@microsoft.com + +The attached notices are provided for information only. + +License notice for ASP.NET +------------------------------- + +Copyright (c) .NET Foundation. All rights reserved. +Licensed under the Apache License, Version 2.0. + +Available at +https://github.com/dotnet/aspnetcore/blob/main/LICENSE.txt + +License notice for Slicing-by-8 +------------------------------- + +http://sourceforge.net/projects/slicing-by-8/ + +Copyright (c) 2004-2006 Intel Corporation - All Rights Reserved + + +This software program is licensed subject to the BSD License, available at +http://www.opensource.org/licenses/bsd-license.html. + + +License notice for Unicode data +------------------------------- + +https://www.unicode.org/license.html + +Copyright © 1991-2022 Unicode, Inc. All rights reserved. +Distributed under the Terms of Use in https://www.unicode.org/copyright.html. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Unicode data files and any associated documentation +(the "Data Files") or Unicode software and any associated documentation +(the "Software") to deal in the Data Files or Software +without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, and/or sell copies of +the Data Files or Software, and to permit persons to whom the Data Files +or Software are furnished to do so, provided that either +(a) this copyright and permission notice appear with all copies +of the Data Files or Software, or +(b) this copyright and permission notice appear in associated +Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT OF THIRD PARTY RIGHTS. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THE DATA FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in these Data Files or Software without prior +written authorization of the copyright holder. + +License notice for Zlib +----------------------- + +https://github.com/madler/zlib +https://zlib.net/zlib_license.html + +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.13, October 13th, 2022 + + Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +*/ + +License notice for Mono +------------------------------- + +http://www.mono-project.com/docs/about-mono/ + +Copyright (c) .NET Foundation Contributors + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the Software), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +License notice for International Organization for Standardization +----------------------------------------------------------------- + +Portions (C) International Organization for Standardization 1986: + Permission to copy in any form is granted for use with + conforming SGML systems and applications as defined in + ISO 8879, provided this notice is included in all copies. + +License notice for Intel +------------------------ + +"Copyright (c) 2004-2006 Intel Corporation - All Rights Reserved + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License notice for Xamarin and Novell +------------------------------------- + +Copyright (c) 2015 Xamarin, Inc (http://www.xamarin.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Copyright (c) 2011 Novell, Inc (http://www.novell.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Third party notice for W3C +-------------------------- + +"W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE +Status: This license takes effect 13 May, 2015. +This work is being provided by the copyright holders under the following license. +License +By obtaining and/or copying this work, you (the licensee) agree that you have read, understood, and will comply with the following terms and conditions. +Permission to copy, modify, and distribute this work, with or without modification, for any purpose and without fee or royalty is hereby granted, provided that you include the following on ALL copies of the work or portions thereof, including modifications: +The full text of this NOTICE in a location viewable to users of the redistributed or derivative work. +Any pre-existing intellectual property disclaimers, notices, or terms and conditions. If none exist, the W3C Software and Document Short Notice should be included. +Notice of any changes or modifications, through a copyright statement on the new code or document such as "This software or document includes material copied from or derived from [title and URI of the W3C document]. Copyright © [YEAR] W3C® (MIT, ERCIM, Keio, Beihang)." +Disclaimers +THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. +COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT. +The name and trademarks of copyright holders may NOT be used in advertising or publicity pertaining to the work without specific, written prior permission. Title to copyright in this work will at all times remain with copyright holders." + +License notice for Bit Twiddling Hacks +-------------------------------------- + +Bit Twiddling Hacks + +By Sean Eron Anderson +seander@cs.stanford.edu + +Individually, the code snippets here are in the public domain (unless otherwise +noted) — feel free to use them however you please. The aggregate collection and +descriptions are © 1997-2005 Sean Eron Anderson. The code and descriptions are +distributed in the hope that they will be useful, but WITHOUT ANY WARRANTY and +without even the implied warranty of merchantability or fitness for a particular +purpose. + +License notice for Brotli +-------------------------------------- + +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +compress_fragment.c: +Copyright (c) 2011, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +""AS IS"" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +decode_fuzzer.c: +Copyright (c) 2015 The Chromium Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +""AS IS"" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." + +License notice for Json.NET +------------------------------- + +https://github.com/JamesNK/Newtonsoft.Json/blob/master/LICENSE.md + +The MIT License (MIT) + +Copyright (c) 2007 James Newton-King + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +License notice for vectorized base64 encoding / decoding +-------------------------------------------------------- + +Copyright (c) 2005-2007, Nick Galbreath +Copyright (c) 2013-2017, Alfred Klomp +Copyright (c) 2015-2017, Wojciech Mula +Copyright (c) 2016-2017, Matthieu Darbois +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License notice for vectorized hex parsing +-------------------------------------------------------- + +Copyright (c) 2022, Geoff Langdale +Copyright (c) 2022, Wojciech Mula +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License notice for RFC 3492 +--------------------------- + +The punycode implementation is based on the sample code in RFC 3492 + +Copyright (C) The Internet Society (2003). All Rights Reserved. + +This document and translations of it may be copied and furnished to +others, and derivative works that comment on or otherwise explain it +or assist in its implementation may be prepared, copied, published +and distributed, in whole or in part, without restriction of any +kind, provided that the above copyright notice and this paragraph are +included on all such copies and derivative works. However, this +document itself may not be modified in any way, such as by removing +the copyright notice or references to the Internet Society or other +Internet organizations, except as needed for the purpose of +developing Internet standards in which case the procedures for +copyrights defined in the Internet Standards process must be +followed, or as required to translate it into languages other than +English. + +The limited permissions granted above are perpetual and will not be +revoked by the Internet Society or its successors or assigns. + +This document and the information contained herein is provided on an +"AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING +TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION +HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF +MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Copyright(C) The Internet Society 1997. All Rights Reserved. + +This document and translations of it may be copied and furnished to others, +and derivative works that comment on or otherwise explain it or assist in +its implementation may be prepared, copied, published and distributed, in +whole or in part, without restriction of any kind, provided that the above +copyright notice and this paragraph are included on all such copies and +derivative works.However, this document itself may not be modified in any +way, such as by removing the copyright notice or references to the Internet +Society or other Internet organizations, except as needed for the purpose of +developing Internet standards in which case the procedures for copyrights +defined in the Internet Standards process must be followed, or as required +to translate it into languages other than English. + +The limited permissions granted above are perpetual and will not be revoked +by the Internet Society or its successors or assigns. + +This document and the information contained herein is provided on an "AS IS" +basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE +DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY +RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A +PARTICULAR PURPOSE. + +License notice for Algorithm from RFC 4122 - +A Universally Unique IDentifier (UUID) URN Namespace +---------------------------------------------------- + +Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc. +Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. & +Digital Equipment Corporation, Maynard, Mass. +Copyright (c) 1998 Microsoft. +To anyone who acknowledges that this file is provided "AS IS" +without any express or implied warranty: permission to use, copy, +modify, and distribute this file for any purpose is hereby +granted without fee, provided that the above copyright notices and +this notice appears in all source code copies, and that none of +the names of Open Software Foundation, Inc., Hewlett-Packard +Company, Microsoft, or Digital Equipment Corporation be used in +advertising or publicity pertaining to distribution of the software +without specific, written prior permission. Neither Open Software +Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital +Equipment Corporation makes any representations about the +suitability of this software for any purpose." + +License notice for The LLVM Compiler Infrastructure (Legacy License) +-------------------------------------------------------------------- + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +License notice for Bob Jenkins +------------------------------ + +By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this +code any way you wish, private, educational, or commercial. It's free. + +License notice for Greg Parker +------------------------------ + +Greg Parker gparker@cs.stanford.edu December 2000 +This code is in the public domain and may be copied or modified without +permission. + +License notice for libunwind based code +---------------------------------------- + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +License notice for Printing Floating-Point Numbers (Dragon4) +------------------------------------------------------------ + +/****************************************************************************** + Copyright (c) 2014 Ryan Juckett + http://www.ryanjuckett.com/ + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +******************************************************************************/ + +License notice for Printing Floating-point Numbers (Grisu3) +----------------------------------------------------------- + +Copyright 2012 the V8 project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License notice for xxHash +------------------------- + +xxHash - Extremely Fast Hash algorithm +Header File +Copyright (C) 2012-2021 Yann Collet + +BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php) + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +You can contact the author at: + - xxHash homepage: https://www.xxhash.com + - xxHash source repository: https://github.com/Cyan4973/xxHash + +License notice for Berkeley SoftFloat Release 3e +------------------------------------------------ + +https://github.com/ucb-bar/berkeley-softfloat-3 +https://github.com/ucb-bar/berkeley-softfloat-3/blob/master/COPYING.txt + +License for Berkeley SoftFloat Release 3e + +John R. Hauser +2018 January 20 + +The following applies to the whole of SoftFloat Release 3e as well as to +each source file individually. + +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 The Regents of the +University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions, and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License notice for xoshiro RNGs +-------------------------------- + +Written in 2018 by David Blackman and Sebastiano Vigna (vigna@acm.org) + +To the extent possible under law, the author has dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. + +See . + +License for fastmod (https://github.com/lemire/fastmod), ibm-fpgen (https://github.com/nigeltao/parse-number-fxx-test-data) and fastrange (https://github.com/lemire/fastrange) +-------------------------------------- + + Copyright 2018 Daniel Lemire + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +License for sse4-strstr (https://github.com/WojciechMula/sse4-strstr) +-------------------------------------- + + Copyright (c) 2008-2016, Wojciech Mula + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License notice for The C++ REST SDK +----------------------------------- + +C++ REST SDK + +The MIT License (MIT) + +Copyright (c) Microsoft Corporation + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +License notice for MessagePack-CSharp +------------------------------------- + +MessagePack for C# + +MIT License + +Copyright (c) 2017 Yoshifumi Kawai + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +License notice for lz4net +------------------------------------- + +lz4net + +Copyright (c) 2013-2017, Milosz Krajewski + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License notice for Nerdbank.Streams +----------------------------------- + +The MIT License (MIT) + +Copyright (c) Andrew Arnott + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +License notice for RapidJSON +---------------------------- + +Tencent is pleased to support the open source community by making RapidJSON available. + +Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. + +Licensed under the MIT License (the "License"); you may not use this file except +in compliance with the License. You may obtain a copy of the License at + +http://opensource.org/licenses/MIT + +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. + +License notice for DirectX Math Library +--------------------------------------- + +https://github.com/microsoft/DirectXMath/blob/master/LICENSE + + The MIT License (MIT) + +Copyright (c) 2011-2020 Microsoft Corp + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be included in all copies +or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +License notice for ldap4net +--------------------------- + +The MIT License (MIT) + +Copyright (c) 2018 Alexander Chermyanin + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +License notice for vectorized sorting code +------------------------------------------ + +MIT License + +Copyright (c) 2020 Dan Shechter + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +License notice for musl +----------------------- + +musl as a whole is licensed under the following standard MIT license: + +Copyright © 2005-2020 Rich Felker, et al. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +License notice for "Faster Unsigned Division by Constants" +------------------------------ + +Reference implementations of computing and using the "magic number" approach to dividing +by constants, including codegen instructions. The unsigned division incorporates the +"round down" optimization per ridiculous_fish. + +This is free and unencumbered software. Any copyright is dedicated to the Public Domain. + + +License notice for mimalloc +----------------------------------- + +MIT License + +Copyright (c) 2019 Microsoft Corporation, Daan Leijen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +License notice for The LLVM Project +----------------------------------- + +Copyright 2019 LLVM Project + +Licensed under the Apache License, Version 2.0 (the "License") with LLVM Exceptions; +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://llvm.org/LICENSE.txt + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +License notice for Apple header files +------------------------------------- + +Copyright (c) 1980, 1986, 1993 + The Regents of the University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by the University of + California, Berkeley and its contributors. +4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +License notice for JavaScript queues +------------------------------------- + +CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER. + +Statement of Purpose +The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). +Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. +For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: +the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; +moral rights retained by the original author(s) and/or performer(s); +publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; +rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; +rights protecting the extraction, dissemination, use and reuse of data in a Work; +database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and +other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. +2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. +3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. +4. Limitations and Disclaimers. +a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. +b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. +c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. +d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. + + +License notice for FastFloat algorithm +------------------------------------- +MIT License +Copyright (c) 2021 csFastFloat authors +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +License notice for MsQuic +-------------------------------------- + +Copyright (c) Microsoft Corporation. +Licensed under the MIT License. + +Available at +https://github.com/microsoft/msquic/blob/main/LICENSE + +License notice for m-ou-se/floatconv +------------------------------- + +Copyright (c) 2020 Mara Bos +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License notice for code from The Practice of Programming +------------------------------- + +Copyright (C) 1999 Lucent Technologies + +Excerpted from 'The Practice of Programming +by Brian W. Kernighan and Rob Pike + +You may use this code for any purpose, as long as you leave the copyright notice and book citation attached. + +Notice for Euclidean Affine Functions and Applications to Calendar +Algorithms +------------------------------- + +Aspects of Date/Time processing based on algorithm described in "Euclidean Affine Functions and Applications to Calendar +Algorithms", Cassio Neri and Lorenz Schneider. https://arxiv.org/pdf/2102.06959.pdf + +License notice for amd/aocl-libm-ose +------------------------------- + +Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +License notice for fmtlib/fmt +------------------------------- + +Formatting library for C++ + +Copyright (c) 2012 - present, Victor Zverovich + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +License for Jb Evain +--------------------- + +Copyright (c) 2006 Jb Evain (jbevain@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +--- Optional exception to the license --- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into a machine-executable object form of such +source code, you may redistribute such embedded portions in such object form +without including the above copyright and permission notices. + + +License for MurmurHash3 +-------------------------------------- + +https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp + +MurmurHash3 was written by Austin Appleby, and is placed in the public +domain. The author hereby disclaims copyright to this source + +License for Fast CRC Computation +-------------------------------------- + +https://github.com/intel/isa-l/blob/33a2d9484595c2d6516c920ce39a694c144ddf69/crc/crc32_ieee_by4.asm +https://github.com/intel/isa-l/blob/33a2d9484595c2d6516c920ce39a694c144ddf69/crc/crc64_ecma_norm_by8.asm + +Copyright(c) 2011-2015 Intel Corporation All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +License for C# Implementation of Fast CRC Computation +----------------------------------------------------- + +https://github.com/SixLabors/ImageSharp/blob/f4f689ce67ecbcc35cebddba5aacb603e6d1068a/src/ImageSharp/Formats/Png/Zlib/Crc32.cs + +Copyright (c) Six Labors. +Licensed under the Apache License, Version 2.0. + +Available at +https://github.com/SixLabors/ImageSharp/blob/f4f689ce67ecbcc35cebddba5aacb603e6d1068a/LICENSE diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/THIRD-PARTY-NOTICES.TXT.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/THIRD-PARTY-NOTICES.TXT.meta new file mode 100644 index 00000000..1544e40e --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/THIRD-PARTY-NOTICES.TXT.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 88fffc9b90842d73ba62f9dd60324875 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive.meta new file mode 100644 index 00000000..dba25f98 --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 527de5817c0710cd4bf33382842cf2e4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net461.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net461.meta new file mode 100644 index 00000000..f80e199c --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net461.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 753d620acd8067779975906c210f406f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net461/Microsoft.Bcl.TimeProvider.targets b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net461/Microsoft.Bcl.TimeProvider.targets new file mode 100644 index 00000000..ddbc6be0 --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net461/Microsoft.Bcl.TimeProvider.targets @@ -0,0 +1,6 @@ + + + + + diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net461/Microsoft.Bcl.TimeProvider.targets.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net461/Microsoft.Bcl.TimeProvider.targets.meta new file mode 100644 index 00000000..8529f5cd --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net461/Microsoft.Bcl.TimeProvider.targets.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ee93e206fdde9d7a2a7d4eb2ca631baf +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net462.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net462.meta new file mode 100644 index 00000000..3057d739 --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net462.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d51814beffe3e9389a0bace8ac3fdbdf +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net462/_._ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net462/_._ new file mode 100644 index 00000000..e69de29b diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net462/_._.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net462/_._.meta new file mode 100644 index 00000000..cdf2add6 --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net462/_._.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 94ec11a12326a0862aadc93b83c4da1a +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net6.0.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net6.0.meta new file mode 100644 index 00000000..545f8e58 --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net6.0.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2cdba5539a25a7e0e84d26b565f95609 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net6.0/_._ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net6.0/_._ new file mode 100644 index 00000000..e69de29b diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net6.0/_._.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net6.0/_._.meta new file mode 100644 index 00000000..b1e94f1f --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/net6.0/_._.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 5349130708f620caaa81981e264baad5 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/netcoreapp2.0.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/netcoreapp2.0.meta new file mode 100644 index 00000000..4aba388d --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/netcoreapp2.0.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ed316c1a906170e1ba516e7b19ea7efb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/netcoreapp2.0/Microsoft.Bcl.TimeProvider.targets b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/netcoreapp2.0/Microsoft.Bcl.TimeProvider.targets new file mode 100644 index 00000000..4cbeffbc --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/netcoreapp2.0/Microsoft.Bcl.TimeProvider.targets @@ -0,0 +1,6 @@ + + + + + diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/netcoreapp2.0/Microsoft.Bcl.TimeProvider.targets.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/netcoreapp2.0/Microsoft.Bcl.TimeProvider.targets.meta new file mode 100644 index 00000000..a71b45ce --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/buildTransitive/netcoreapp2.0/Microsoft.Bcl.TimeProvider.targets.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0520e2e22ceefb803b9e37f8a6d426d0 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib.meta new file mode 100644 index 00000000..7e8bb9f1 --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e5546cff16190ddaeace05dbe283e720 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib/netstandard2.0.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib/netstandard2.0.meta new file mode 100644 index 00000000..1fe30ad6 --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib/netstandard2.0.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a816f5fc99abd26eeaf022cdc83ee6f2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib/netstandard2.0/Microsoft.Bcl.TimeProvider.dll b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib/netstandard2.0/Microsoft.Bcl.TimeProvider.dll new file mode 100644 index 0000000000000000000000000000000000000000..d5b34447b77bf759217e227eb4a17edf8ed3e4f2 GIT binary patch literal 32416 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 A@c;k- literal 0 HcmV?d00001 diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib/netstandard2.0/Microsoft.Bcl.TimeProvider.dll.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib/netstandard2.0/Microsoft.Bcl.TimeProvider.dll.meta new file mode 100644 index 00000000..1cd4c70b --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib/netstandard2.0/Microsoft.Bcl.TimeProvider.dll.meta @@ -0,0 +1,29 @@ +fileFormatVersion: 2 +guid: ad4890b105c0b709e883eec5cd2c4c40 +labels: +- NuGetForUnity +PluginImporter: + externalObjects: {} + serializedVersion: 3 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + Any: + enabled: 1 + settings: {} + Editor: + enabled: 0 + settings: + DefaultValueInitialized: true + WindowsStoreApps: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib/netstandard2.0/Microsoft.Bcl.TimeProvider.xml b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib/netstandard2.0/Microsoft.Bcl.TimeProvider.xml new file mode 100644 index 00000000..acba473a --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib/netstandard2.0/Microsoft.Bcl.TimeProvider.xml @@ -0,0 +1,415 @@ + + + + Microsoft.Bcl.TimeProvider + + + + Provides an abstraction for time. + + + + Gets a that provides a clock based on , + a time zone based on , a high-performance time stamp based on , + and a timer based on . + + + If the changes after the object is returned, the change will be reflected in any subsequent operations that retrieve . + + + + + Initializes the . + + + + + Gets a value whose date and time are set to the current + Coordinated Universal Time (UTC) date and time and whose offset is Zero, + all according to this 's notion of time. + + + The default implementation returns . + + + + + Gets a value that is set to the current date and time according to this 's + notion of time based on , with the offset set to the 's offset from Coordinated Universal Time (UTC). + + + + + Gets a object that represents the local time zone according to this 's notion of time. + + + The default implementation returns . + + + + + Gets the frequency of of high-frequency value per second. + + + The default implementation returns . For a given TimeProvider instance, the value must be idempotent and remain unchanged. + + + + + Gets the current high-frequency value designed to measure small time intervals with high accuracy in the timer mechanism. + + A long integer representing the high-frequency counter value of the underlying timer mechanism. + + The default implementation returns . + + + + + Gets the elapsed time between two timestamps retrieved using . + + The timestamp marking the beginning of the time period. + The timestamp marking the end of the time period. + A for the elapsed time between the starting and ending timestamps. + + + + Gets the elapsed time since the value retrieved using . + + The timestamp marking the beginning of the time period. + A for the elapsed time between the starting timestamp and the time of this call./> + + + Creates a new instance, using values to measure time intervals. + + A delegate representing a method to be executed when the timer fires. The method specified for callback should be reentrant, + as it may be invoked simultaneously on two threads if the timer fires again before or while a previous callback is still being handled. + + An object to be passed to the . This may be null. + The amount of time to delay before is invoked. Specify to prevent the timer from starting. Specify to start the timer immediately. + The time interval between invocations of . Specify to disable periodic signaling. + + The newly created instance. + + is null. + The number of milliseconds in the value of or is negative and not equal to , or is greater than . + + + The delegate specified by the callback parameter is invoked once after elapses, and thereafter each time the time interval elapses. + + + If is zero, the callback is invoked immediately. If is -1 milliseconds, is not invoked; the timer is disabled, + but can be re-enabled by calling the method. + + + If is 0 or -1 milliseconds and is positive, is invoked once; the periodic behavior of the timer is disabled, + but can be re-enabled using the method. + + + The return instance will be implicitly rooted while the timer is still scheduled. + + + captures the and stores that with the for use in invoking + each time it's called. That capture can be suppressed with . + + + + + Thin wrapper for a . + + We don't return a TimerQueueTimer directly as it implements IThreadPoolWorkItem and we don't + want it exposed in a way that user code could directly queue the timer to the thread pool. + We also use this instead of Timer because CreateTimer needs to return a timer that's implicitly + rooted while scheduled. + + + + + Used to create a instance returned from and uses the default implementation + provided by which uses , , , and . + + + + Initializes the instance. + + + Represents a timer that can have its due time and period changed. + + Implementations of , , and + must all be thread-safe such that the timer instance may be accessed concurrently from multiple threads. + + + + Changes the start time and the interval between method invocations for a timer, using values to measure time intervals. + + A representing the amount of time to delay before invoking the callback method specified when the was constructed. + Specify to prevent the timer from restarting. Specify to restart the timer immediately. + + + The time interval between invocations of the callback method specified when the Timer was constructed. + Specify to disable periodic signaling. + + if the timer was successfully updated; otherwise, . + The or parameter, in milliseconds, is less than -1 or greater than 4294967294. + + It is the responsibility of the implementer of the ITimer interface to ensure thread safety. + + + + + Provide extensions methods for operations with . + + + The Microsoft.Bcl.TimeProvider library interfaces are intended solely for use in building against pre-.NET 8 surface area. + If your code is being built against .NET 8 or higher, then this library should not be utilized. + + + + Creates a task that completes after a specified time interval. + The with which to interpret . + The to wait before completing the returned task, or to wait indefinitely. + A cancellation token to observe while waiting for the task to complete. + A task that represents the time delay. + The argument is null. + represents a negative time interval other than . + + + + Gets a that will complete when this completes, when the specified timeout expires, or when the specified has cancellation requested. + + The task for which to wait on until completion. + The timeout after which the should be faulted with a if it hasn't otherwise completed. + The with which to interpret . + The to monitor for a cancellation request. + The representing the asynchronous wait. It may or may not be the same instance as the current instance. + The argument is null. + The argument is null. + represents a negative time interval other than . + + + + Gets a that will complete when this completes, when the specified timeout expires, or when the specified has cancellation requested. + + The task for which to wait on until completion. + The timeout after which the should be faulted with a if it hasn't otherwise completed. + The with which to interpret . + The to monitor for a cancellation request. + The representing the asynchronous wait. It may or may not be the same instance as the current instance. + The argument is null. + The argument is null. + represents a negative time interval other than . + + + Initializes a new instance of the class that will be canceled after the specified . + The with which to interpret the . + The time interval to wait before canceling this . + The is negative and not equal to or greater than maximum allowed timer duration. + that will be canceled after the specified . + + + The countdown for the delay starts during the call to the constructor. When the delay expires, + the constructed is canceled if it has + not been canceled already. + + + If running on .NET versions earlier than .NET 8.0, there is a constraint when invoking on the resultant object. + This action will not terminate the initial timer indicated by . However, this restriction does not apply on .NET 8.0 and later versions. + + + + + '{0}' must be a non-negative and non-zero value. + + + '{0}' must be greater than or equal to '{1}'. + + + '{0}' must be less than or equal to '{1}'. + + + The operation cannot be performed when TimeProvider.LocalTimeZone is null. + + + The operation cannot be performed when TimeProvider.TimestampFrequency is zero or negative. + + + + Attribute used to indicate a source generator should create a function for marshalling + arguments instead of relying on the runtime to generate an equivalent marshalling function at run-time. + + + This attribute is meaningless if the source generator associated with it is not enabled. + The current built-in source generator only supports C# and only supplies an implementation when + applied to static, partial, non-generic methods. + + + + + Initializes a new instance of the . + + Name of the library containing the import. + + + + Gets the name of the library containing the import. + + + + + Gets or sets the name of the entry point to be called. + + + + + Gets or sets how to marshal string arguments to the method. + + + If this field is set to a value other than , + must not be specified. + + + + + Gets or sets the used to control how string arguments to the method are marshalled. + + + If this field is specified, must not be specified + or must be set to . + + + + + Gets or sets whether the callee sets an error (SetLastError on Windows or errno + on other platforms) before returning from the attributed method. + + + + + Specifies how strings should be marshalled for generated p/invokes + + + + + Indicates the user is suppling a specific marshaller in . + + + + + Use the platform-provided UTF-8 marshaller. + + + + + Use the platform-provided UTF-16 marshaller. + + + + Specifies that null is allowed as an input even if the corresponding type disallows it. + + + Specifies that null is disallowed as an input even if the corresponding type allows it. + + + Specifies that an output may be null even if the corresponding type disallows it. + + + Specifies that an output will not be null even if the corresponding type allows it. Specifies that an input argument was not null when the call returns. + + + Specifies that when a method returns , the parameter may be null even if the corresponding type disallows it. + + + Initializes the attribute with the specified return value condition. + + The return value condition. If the method returns this value, the associated parameter may be null. + + + + Gets the return value condition. + + + Specifies that when a method returns , the parameter will not be null even if the corresponding type allows it. + + + Initializes the attribute with the specified return value condition. + + The return value condition. If the method returns this value, the associated parameter will not be null. + + + + Gets the return value condition. + + + Specifies that the output will be non-null if the named parameter is non-null. + + + Initializes the attribute with the associated parameter name. + + The associated parameter name. The output will be non-null if the argument to the parameter specified is non-null. + + + + Gets the associated parameter name. + + + Applied to a method that will never return under any circumstance. + + + Specifies that the method will not return if the associated Boolean parameter is passed the specified value. + + + Initializes the attribute with the specified parameter value. + + The condition parameter value. Code after the method will be considered unreachable by diagnostics if the argument to + the associated parameter matches this value. + + + + Gets the condition parameter value. + + + Specifies that the method or property will ensure that the listed field and property members have not-null values. + + + Initializes the attribute with a field or property member. + + The field or property member that is promised to be not-null. + + + + Initializes the attribute with the list of field and property members. + + The list of field and property members that are promised to be not-null. + + + + Gets field or property member names. + + + Specifies that the method or property will ensure that the listed field and property members have not-null values when returning with the specified return value condition. + + + Initializes the attribute with the specified return value condition and a field or property member. + + The return value condition. If the method returns this value, the associated parameter will not be null. + + + The field or property member that is promised to be not-null. + + + + Initializes the attribute with the specified return value condition and list of field and property members. + + The return value condition. If the method returns this value, the associated parameter will not be null. + + + The list of field and property members that are promised to be not-null. + + + + Gets the return value condition. + + + Gets field or property member names. + + + diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib/netstandard2.0/Microsoft.Bcl.TimeProvider.xml.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib/netstandard2.0/Microsoft.Bcl.TimeProvider.xml.meta new file mode 100644 index 00000000..250fd54d --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/lib/netstandard2.0/Microsoft.Bcl.TimeProvider.xml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ac9bcb351662deb1a914ce63937bc141 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/useSharedDesignerContext.txt b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/useSharedDesignerContext.txt new file mode 100644 index 00000000..e69de29b diff --git a/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/useSharedDesignerContext.txt.meta b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/useSharedDesignerContext.txt.meta new file mode 100644 index 00000000..490a37e1 --- /dev/null +++ b/Assets/Packages/Microsoft.Bcl.TimeProvider.8.0.0/useSharedDesignerContext.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1c5a17196e526443bb3fcc0173e76266 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/ObservableCollections.3.3.4.meta b/Assets/Packages/ObservableCollections.3.3.4.meta new file mode 100644 index 00000000..5dbcebff --- /dev/null +++ b/Assets/Packages/ObservableCollections.3.3.4.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7a1966d7b19efe595a19e975a4feacf0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/ObservableCollections.3.3.4/.signature.p7s b/Assets/Packages/ObservableCollections.3.3.4/.signature.p7s new file mode 100644 index 0000000000000000000000000000000000000000..600f42f4302c9258a3dfaae01c7caeb51431cf3f GIT binary patch literal 12921 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 + + + ObservableCollections + 3.3.4 + Cysharp + MIT + https://licenses.nuget.org/MIT + Icon.png + https://github.com/Cysharp/ObservableCollections + High performance observable collections and synchronized views, for WPF, Blazor, Unity. + © Cysharp, Inc. + collection + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Assets/Packages/ObservableCollections.3.3.4/ObservableCollections.nuspec.meta b/Assets/Packages/ObservableCollections.3.3.4/ObservableCollections.nuspec.meta new file mode 100644 index 00000000..b1c041a4 --- /dev/null +++ b/Assets/Packages/ObservableCollections.3.3.4/ObservableCollections.nuspec.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1fcfb76e5910303be843bf604bb4d98a +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/ObservableCollections.3.3.4/lib.meta b/Assets/Packages/ObservableCollections.3.3.4/lib.meta new file mode 100644 index 00000000..db18cf14 --- /dev/null +++ b/Assets/Packages/ObservableCollections.3.3.4/lib.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 316c57455299741d493df124f7527c9c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/ObservableCollections.3.3.4/lib/netstandard2.1.meta b/Assets/Packages/ObservableCollections.3.3.4/lib/netstandard2.1.meta new file mode 100644 index 00000000..d143df62 --- /dev/null +++ b/Assets/Packages/ObservableCollections.3.3.4/lib/netstandard2.1.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a07287331fe1b1ed595f4226338c8329 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/ObservableCollections.3.3.4/lib/netstandard2.1/ObservableCollections.dll b/Assets/Packages/ObservableCollections.3.3.4/lib/netstandard2.1/ObservableCollections.dll new file mode 100644 index 0000000000000000000000000000000000000000..5ff97bce2dfb438cc2b619a1ba03ec66bd01edc4 GIT binary patch literal 155136 zcmd3P2Y@6+)qhR*Y){xYGdnYTdvUoy-=^d42z%soAV-jJz%3y02!}w!EqS(&BT76; z5(Nc85e#Gr22=zU6%|EA?m$f7XZXwsmjCbfs^iS;>>l#}zVBeWs$NyS_v*b@Rj;aR zs`ozRYGo>=lK6Z3ZKWPV$bUP^v+-jsvfE}p(WV~Ge7ond#9rU-S$@K*ky)p%c8*_t z)XB4sIqH;CoYQ9=eeA5&XPh!?)hV-feeVIYPIguvJJ{Nqo#Ub2cd1f)B~10<=d*YD z)LvDa%xX?-rqpsnskDZkJA(Ku#MdHJszc(4l5hU=L-iDZ_^&%+ozzfNW@$1ZrTm7T7?g&{l1AyO5?FAvaYT}p)KDN`l8B^~kH`;0 z36;HKe%Qq{8!eG;8v^Z%2y}{9T*9ys-2fX&cdD1mBxy@Jq&3Y0`{8t^NlPMi1U!oc z!upZ~S})W_;5TW!5QbFP%v8My(UzPskj*E?irXkPHPzd$Y?wq}*4nqSI}ECX5H^~% zVHkbArYKIQXb2rpZI1nKeFF{;_o0L_l+v9VyD#})yUquH*Dt?&w%!}fsy zw;O)GUCX#vqb}oH8-{74SM}NG9er$vsh|taDLK>7G}o;f+}LJ8R8)_U*UN+foNv z%UocXS&KXwY5;Z7vYc_oF66=L&zhFA0(6#_dyO-81*|y*Sjxe0MVMJyUg}+D*cckJ z#>k;~x`*M>yTJpQYu<bScrr=7tQY>DR_FO~qb?9OpzlvQ}w9V%Fk7&am-AzHDddxsq=Ny$AISr+tYIil!Ndv4gYXpfAOs`qz3_O}s#lcRU zmvYWzxl~a|rL?^+1+MYhzo_IP)fFvWv9G)u1JNnI$COKBbU^cbXoAkL0EaQA;lx1w&3b<$=O}bD-Da)Idl@=JK zUY(&WF|V4IMNFrx`wis`q1V@I97A(HVR;B>Xd1UuK~!)h)iU6M(dR}+0i(`bgdTHH z+8U%nrGdrb;PeQCKwrgRDX``9P__3@9z`Z})LgR`@kl2Mn#>hGXh?-oH zdhZNV;~E@6x3ku6s`Dx~L(bU}!DKw&2S@|}Sf?%_5divpfJC-5Y>af4;e3!(fXTj^ zk$IR=?Q4SAwT$%w)?{B7Mz0T}9}1&4FuI6k+miN;(Zo&B#LdyfElg~Qx%*Z`uB16b z>}K+A#+(l`6O7-cL+5seFff2V!stPUsSAD-DZ{w~&+>5Z;ie6#XZu_I+>fzrsTO`0 z;YDC`?q-aAnIn(*)tEcT!a&&=$mf;rftK*sIhFu2GU0rj)%>t~je~}a}V>w z=13BPc0TFBHS;cXp244=5;f+HK6a-B|Mg3v)hu5RozKAv`?<%rWhDmO~pl?T#p} zQqsePM!658q{q^hMujQUc?3_k*nKq2+}fxx1$lgqxq~B*Az1r3N&#)>NuNe2)eox$^^2+T>XUwX9Qr|ZtA2fqD_nl(y3qb) zwna4Z2I8b=;BnY3xCp$Sa_3kJpS(3Z~h1`Z~?32fwf#NF>Q_uSfCbL4wL_L@4` z$&v2|`7$KDKt%OR{vaqx9~d){Dnc$s<%fW0t>%FcbsbBBM6V#iEvAZAjOQdK2g!D?yRz6|Bgs4$r<4xzMcxsQ+vR_6V9;fyW&?hb&hLRJ%1>`#+hKn-)iByMs{tP9VzoBF`1z)cISOq_LtG7^ERHAgK;rC@Z1J$URjpj9r10yPc2!gb%Ajd zvp&gdzSzI9HpTphE!Oz_N7Sa10Jus4zWl@f)T9mso_Q1E(fndiG=NpBM<&1N$+T(O zCV=c!NrX}JjP|9Smg#n&5fn7`mh_yU=a;%|5V=(~A?TaF4Nb*9*Cpe(L6jQN!l0*x zCQ2u4NM9+f`6>_FR-`pvyPXtZVd)K1&61st6su~qFXz=2zfUIB6_e+2Q;$blN|eX; zbg3?LG@=M|n?}tJ?HQj@pU<<_`h1$QmxFzW@$AZ(h^cg)0oA9o`F0^4j^lO%I_xv$ zVZYN*U9Djo`#Lgd5rvG7G`mdAzzF<4-RL;Z*HiFSYulHHKc5jbSJ_P7u(N;{n(|F{ zGa@UtyAHTL9g)pQw5F`Ks$si@7_59MXW6ZYmI~>yI>#+zEb z>Xt`jW3F4ZVml5Q5m+S3?3mV)kV(?hngy+4V^c%h=^WW1cnUvRY#qu$IYX z@@c^s(^yZ&?n1S+)>^<`#2e!Hz0>AePlq8+J$(#+)%sWh+3#GX59$s+|0MJQr$=|I z%Yizgh)C2g^1r4Rs)S6&R1yMoH;Sty>_p?Lga~3PnTBCa`cQps_`1OMgy`bFI=a{j za^Eqg3+=-Ma3DS!b=V6LHjdbBN z*Kr*DvAh17rmnwWI@2d^2geH7rP6DW`goGg3?Pb6>OMcA@1*?~_}b&PcV;a+!JHKO zFO$&EtXf31{Fw4Cw2_{ZPERc&$il}J@%uMHLHPZ%5zz0S!;tR!Tn(tqW9V-`G2w4N zZHl;SGuPjKisYIj^BZUP2HF0eQ?zz+q%X*?i@iU{u3vp1$Pf0O^txdX8MW&TLL09) z!g|s5M!kA*e|G`tMfa>IF=sP8Ch~Xneu}9uJ##MZX2L0H#g(W+OzS>=&wV)m?6K)1JGW!OMZfwJ*Ws)>y5mZR__2iPW z3@Tv4Wb<-Onx{#XJlz%bP|PJsWGIF-{xdKAlp}eM(GY8)vGO z7l!S+^qNp#6WYdNG^55gECBx(Z9{l^XSN|;@&7m5*!peXB*XRd}p?y_Z{^d zU3c7Ywm@qm#<`Jmw4Q@z)ayTb5Wp6~mbA0zu*0Ju!MNkkK^!l+$I%Fv181iil|Oz( z=jjRY482Qu;0V7f{A~R$;o0V0!n5tWglD^n@nFw!dz6Cju>%779`I(pJumugde5=G z?e0{IKCmm_-=Y(PwF)s;c46o{F--VQ%&v&LOPTAt8IfFbWVeRdb`jHxt_^;DJJx%3 zyQ5}o-X{^$c@LgdU82^GqkDCY@E8?AnsoL6R->{E&v&?27x!7}(scH$WxYn`^jZ9O zecIn5Q?>pUp^g2muwK;Ps#lM5`F@c9LK%x1@a~Dr*$c!Y(wYi)CJoR;``X z^)x6-*35we5Zl4<`8xhopRec~Sl=%81?~uijhq9c^HyE_rn4UiOxWL}>(u&qlFt4> z6rD=__XgoRZj7e~P*jGC!~Zg#9>`F}rTw8FZ0}$VQ5U~+5K6Z6wZq9j7_n9}GP*Eh%p-&yrMRLtk%qfS@TmW1}W{qCU-I4A41YF*llG0(Y!eArnZgBW^xz&y#ofFWO zE$ZnbZzLmQ23K7&XjD;M05}H?O*ZJK<8Q-i9ZgYNzBkm-^7l=WpZ7_VWvcm~;^#=n zXUlr>@yBqnnRIDUzXqh8!()2E5?H@B@MSa3D_~zY%MJ)-!M>v3lhwB~J%{^@#OZFB zn#Ngru;SAl$L7NRVamQZ&MS@AH|-Lf44}i|k|Th)C7(>|m25;UN$1E|^Rb#vdIln^ z3B1toXO-l*8}-^oHdhOe4Q=Ga5nnDzMV)M{Txc}Obals^mPXG!YCI|VI@#;MkoJ2) zyFtHnj*d5f9*%sIwD>HY_A!Vy?wi}}8q(UgF)hzZ`ZaoHeI1%Hy*- z`!r_bER^~=@ANgIC@Y^uezSl8?WA14Et>0!r9t$7$oJK z?xr|??w*UZX^dGFgd?MPI4&L{k0#ZHmwa0X@)*b%6>>C?=rt=}#U^0ZTG|Bd;6;Y| zApYQfs@w249e*hCG)nM14Jnk&3f>*+^W|hMj>-QUw z5gEhqQl4jg32nT759`U8(x6^^@8L$$i@q;mlboCIs9GY_>^;Qy0UF>jD#U3zH{)qk z$fztY-^o6}?XcTzX}5L*dj39ux6&^pakdX{^OJaEkOy&n{=(8+; z<=Y+#5-WE~(qFk})~#BE7drvFJ<%-%9E|ba>%^Asfi91Jf5=m~r_eyQ?768Ep_9Q0bke^Cj(|xIAyxU|V1#m~DYm80 zlKBoWUIrHNgA;0S{C9!}9`5TQsm=!<+t=g6z7;f0=fiAosTBw7FtrD~+(iO7lhT?o z7yT;aX~U9q$+TgO`gNRl&MDaSnkqQc_H-0*;09!0j=b;#AKH$mtM?qspO$DlKKV?a zS5t9at@i<|bW>{S!iq7}x!?kpD z(BkM8Y286mRKdrsUN*L%$M@qYyPCmt&eIsd2MxzxwQF}J_y+ZVCwAEvg1_ESwJ z=*L@Z@9QLbcA`F=k4}=``DnL3%TXWC9l%qy+z$9D&d~f|kL*qq!yehk5b&MDT@3lE z;BH2I|6R|09|x#*?jyAE+!xl1&V4oY{8{`HKkp3O+0VkQeS1#IyM~4|^eNqd22bfyR?-OXlR@&glkJ-}yP+(1#kIF3z0jcPSJ3P~;6h6je~ihw{0V(CmxO3z2z?q7op%HJ`=(!lqUKodiCP#;zvm@ zx-MpmoX_D=?S%Py2=y7A7wh6NoyUO4sE`eBEv$d`GSNI0&WonH2D;us=BX+g{_ick zmsaDw1!jY=mLwcahAHZZv%~eTdr8>;jzyUr>+x=K zWz(I`=oK&SY7s7z!lkTk(pc`k8j+kgRD0Y7FJ9uy-Js9ycSy(s*LypS%fqa^k%?>< z)ZqkjX@=|;y%^zU8h*Z10FXavX>|7bpd&&)LVu%5kGk>B~FBWdVO1; z4sBc3w_@p}>aA}B%J262wu+B>>)U{rs`ahU)Bo7|wu;yI`ZnOQ?)o<1^*>$TR`KB3 z#}m+0XdW9sr-tj>`uLxu{Y4#hoGPpx^P=n9`gp{?xV{x>5$k`tzO7H^^ONK^T;JBm z^9A6EHXANZ(C*0k_KPTndGbpLI8Q#skn`l18F|K=6lYw;?HTtgfEgwCt2%g^fl(oF z-Kz4i`!z&*U-D|0_A^LMx*B-n?={yUgb#+b3*N+JOtKcsW_CzeUV#!b7ML>-$Q^FjtMcv%qa02Aq>O?) z0)2pzv}ER>uIN9Y5sk{~hH;ypeE0G+ovycgP){1<>1eTK*k4CMqaqrVO4Z~|krmX+ zinyy#5DPDR0Vn_IEMM;dPK~rY>@`Oli4fK~brJJj&T`<~g*q3K15Nffs#y$>#$@El zE4Usd#`v&iocOs;9T$JC=*L4#kwG3JIZrws5#T4Ca}n+;?a)1<>kzU2K-xkIKbvH3 z%Er!AAG{^Y{w9+4bAxxsvT&=OOZ| z+us6yzg{WOX;M87p0Nkw%YLdoi#x4&rSiaA#H7xbKHfUkAN>%;4#AsD)(0vEkFn~QzCV6?=cXj%E zOyd$NdkP}Ou>>!V5E)O?bsf9nVj`Ob~ zi~r0I_npD_#64cC@w)X?eG}p#c+*c2;ub9m54UKoM}YU4r(KHCePja@;D`6C9gUFx zP~#OAH7X3;R~b*bKV#73zQzD|aQ$4uCifQ-TJA3;Ou4_3FzxOa3uL$ajAg&NCW_!U_A+C}C5`=}#-Z?&_LMDN=3g7nc zlt1|OAu3qF$Zvt)`5hT$>i0ovp0VZ+NT3t!W0;lyM%1kQk-2}uqxVGIMTGnM1df0i zZB2F$`YiiQi`<#Jj5g~0nOVuUCaKqdq-icIuUMY!UzseG2_E?i^DViw>RM=B?mfed zj{D2-66tzGGQ2x04#7=mxasRd$izKne+2?re*6uQ-lqO+Q>o1=I)7(Mc)_BD@Bedc zP5sNwB?>9CRB8fK&21^U@{4rwbD^=KL@c@Fj0Eu`D_k5#9&%0TV&3vdTAC!^iwa5n z0)Obk&_}zKOWXed+1>lk%4gb5r2dK2Y0%Zw_9RmOVhStRsWuyJ_8)GR%DGI83EUY- z%D90_6UGg%)sXQy>1$2)XOpG2lx}?+u88eO`4<7STlT*}b%%rAe*5il)VGPKPh@r> z+JpJKMt>`*zhUU_gk(9?9~3CJwo!g*xi^lD$WTclJ^WZrw;}?VLo23zmEh zjY3E8i5Ajr>6Uy(4_fP8U4cV zWDj)`^_B>|x8n5R?D2dgp`h2`d}LTp=ryRvGf3>$GfB@L17>(cZ!<``ICSG*Zi?=f zbQ4U&9WoG_j)`Y|&zPfh%PKj-^LXI0Nn9U;2ygVUI}us`N8r?@HKOV& zIBCQmlE*83UMf+j{d?stQ(Qf}h-4H~-m*&oIb}QwDPT!eVL206Fp`vRgH7u#1dU0q zTp79t4UeMBWmd=~EI87dJ?$f`!WI?adQn<9&PlHmm$c*&$kCg4>5(ZYoy!(l@~vY< zxFl0^t@$>62WhS?-#%8nov`+Luv|+q-{IYo+98fBZtTf7i~Mro)i2#3u){J;K{7~^K@_>6FG3$4^+Ku8Idp48KM{5VbJF zs#H=m@IvP< z0`96^2mxR}!kZ&`W}b79oSElH6FD=F8D0&;u<({sZHm8Mud~0$sBnTQMeOHFj#ygR z@q_boQLw?mc@GcQ()K(Q^-vrgJ>lIDMVuuJlfk&-vBbW+(JTRv3=o@&42Cv>(kP&?3_(@}fHE<6K>uK)8#?RB= z4E0CO)6>tYf1aMU=AEbCl%{b3(!IeMGyEQ{)?e^O2?t;NseU=*znk&TJCMIqz#q=| zW9={>75bZ3pU+*VUc}EeD)g7mz|Ac9&WxU?oIYe=A>s5RtPJ4MVx^MKAR=Cgq_Y5t zGJFntQ%P)2IM|iKtdr@_SiEiq9g2HLv3Kg#Lx;vC&dWsamsV>+{h00oZac?J?n##U zA&NyH2R~~usj|HnqP+)2+j~!QR4D^q>dNR%bK`iLSVlupmdrXVWgIDTLtvNlo9ggjI!lP?+Mv`SR-IDL)+_`a zU`=os+K7$S@%oLk4T`qloPo0)=DJq7QaEGk%Y>Ww)74pN{jzJrhR$@qmDZkWcr?1y zi|dU2v(fXs-{bL&|E_!MIfXo6f>JB$@j#>Dd@WqG_RY!&7lov-k;CUu{sgA_o6@*= za}Li+XEZNA-q0Docnf(c_U3R`@ifliGgZHLM*w;8f6w_v-DhI!nQcKn0Edg3?I^+M z&tf3QozLL09u!+Ozm zWxaaTAEuP}x^gEFz`Am02Ku8JvaZ~PX{;-EMOeG8H0`-qSi4J^2^H*yFkDi`{4;<3 zXa~O&Z&rCYR>SpdsAj!53SVRqT(Nuc_Z$2TJqtI^a|Dj|Jx*M;Pez>G@xa(EOoeW% z^B#a>tHnJ4Sbq%=d1dt+8L6=h1%}=y1t^yOp?p(pWhfM+7H&3`mEoR5*@qf%*J@XR zR;iF0x)*}i9OqKFv{lo_=8=WfWU!cUNIF<}$T|@BS7RpA>%dr9y$(zlviW9j+0mSD z@z#N|HWaV2wH_>&EpmBy1c&xEy$;M6`HW4;(nkMfphIOLV>+cn>c zJ7xnB6*@fp9hw|QL+T@!^T|b)iqanc653Y1RD59l4WMLHM6*3nKB7y-eaO-w!V=xX zLcUZe3}Ja+%XpwIStb@D+REn&A=`SH*sNO!ofSQu6?2o;S`k~$Ra)yb@|{|11!%31 zE9CQ9YX?$mIPB<|TygO}UQ0tqQ;V;ZD-{R(JsC#*eCNGddngbt%tU_&0j)2$>h&Be z4Q&#k+q9nR3BP!tZXZxxU%K9F>?)&tgC!sO>0ho(JNuHO3I{A_KR$NAj8Z7~P0f{^ z?HTRT<#JtmH-a4>S=f@x4!penDj?03acf}N+o90}zQ9=tI|h2xAWivBkR~r53v%`c zp1%Di$pcopVvbYl@PKOzBMe|QOL4|VOPt+X32A}VNAWiue=p##4S)Pc_-+_vc(&;@ zge?T(AK~9b+D7=NDmd4_V}PYF=4KJ+zxdjaGZWW_oG~_XZOBO?YBS@m4G%!U25UnP zPs6ogLloiKkffDSvs>zvimnBZhJ9l_SZ^&THn#$X($Y5-CxM0$ ztFsuKi!3-em>TuHTz8}I)?E=|Z&B7^)0Mq6Jog^G>*z%A^1gb!a7`F+)7saAb4%o= z?xJu$7lkMwJiQ2>aAR*ho@8a{^E6Wp?j7>9|Dk${!$CJ$)kGI2dTl7a1KtV7*Ml5_ zupT@VfnE=C0OS_~@!j++F0#QVI=w?{JfkLG;RQs)M-FG%TMRkoU6!9QyR3%qGP0V7 zLmzX*5)!x? zCOMVCk+0TVlN@mbR2-e3Ro#u8(%e|WO|Q_I*&&1qT$TiAH}TQx70D6c9bYKmp)xE6 z(lHW0tRj)KG>u$J6Y=b2b2a;5|4!vA)Pg5;oaekYNBc28=Y$*YmSkZGAHMRAKJvJo z;otDMF76XFX4fGa1-=_?$_JzcjE_gdi_*UWH>~}7Z_oFm0wJ#6zZsqGrFcaP_K!x+z+A&V z24T`!iKpZMDGQX6Hr_DwxgS8h7jJqcJW=QM=cJNX&^Z=WX_&_$gkc_!Ap9A8?{P7< zSq7&&Sq6s3y|JAkH@JcrGnhAkbH69BjHK4B(&%_{cU1rdhpeB)5k)~{1%^yLVBbO= z8Q{x`7;x~^(*(8?kqA{`g|abHE;*n!7zWy4B2ubTml|AsMk_|c6Onl?&Z5KXkfUkt z`vEZYHlG^pS8Myk~oaX04fT4JNJf;;h<`GVF5zdf6B~7r|KZK2$Jfj=8$F_U&@Y zDDV^38W)a^D9nGbW0t|;>5D+TCDor!l?V4IWjCB<6s5M2mhXT&6_j#`+?e^6Wc2lE zV)iJ2twu)L=(;RXmICGMhDCm1ujm@&4t!nn8f6vq(1P=j`!YZJO@5Q$@3PA@zsLE! z=+>3kI&E|?OH%Yt(!wB_)ZaNqPo|7vGHU@d?DO$-FJS4oESXy+%L@U5EH6S3%97>$ z-?v0%X{wI~vSb;^5~B}g*$i18T*|J$0QqQwun`p}@l!&~=-X1$3&cs&)It^0bT4M% zvXu2DD+q;4TO|7h!zSlZ#~obtv3W?dB1;K&DA;whG3-)T}`MBAaB+{o3)$XZGF8iawhUCV@3AM1%cbr~9(<2o0 zz*a52>Uu(N67`N3dLNI|gEPtY5ej;cQZ2pedP1*3J&rfb@xwTCh<5&>VT`1Y(*OQ>hK$h zL>3|wncaf$#JakT3?H@KJZQy{`hW~uAqQl11P5f;200)jO^^dJRUmypMq1FMTfhV6 zH7)SZ$7IwcAJjJ4Ym_@XM;=B~aT#YR5;Z+2-oHOWF&plqEQBHZa}0U@@i7g5+)qED z(@!!z72gfN4L0=tdh#$UpGTRWqaOdcCf$Iq0)33UW<7^jZ^D43 z87SI=;GhqO52eRFU0utDquGbcH~^O(f(te&bLVS##EcrP-AVQ}^ck_sAoy$XCq|9D z(2IQrHG9Q}-4pO6^;#hee%G7BcxaMU(Hsz_XY91h*v_{AaLJc3^Gzw)H&63ve;Yu!#_o5RS(ZHbZaetp zyi(62ci`K)y|D&L)3E|3UG2zy7cp^>10VURr*u0{@f%PffBk4AYsplPAF=pN(Bdmm ze1QW^<|2+BlUHI!or<6M`405=SOg% z-jtHiU4<;l@1Ci<9}`Vk@}Rq|sXHO2OL2Wm-Lb8HP+Jz zU(^|^Xq~O5&O$=W6t=oS5Cdt2Y(=!jq+a$w9=^YEij1ExAuHx@{1kxdDZa+v@Xv8L zBKwz#!)i|9H9xM-I!}>Tq&zB>#u@4y5i~4|# z>S9S<94ef!)u z5QEdi!1)ax?tc+b5iZ88-y)&!k^UWG6RaP6yMv9w&#kdLBA(Fhh@%g38V5(fW;LQ} zAC-QniMi-B@M7AF&{F!LzXuEOL#tUcwRB5f+l9y<$Zg+t@F4#iG5&5c4^PnkBNEus zm9vknl^nB@CN5%i{)DKwpKK=FPX?&`X9NRJX!jHIP~d*D?*#5A9LNtN4<}i|7=9eJ zlCVr3^WE)?W%+}tY8ae199_Xq@YGzhK84bfZ*l$t?D3h}_dl0i6#Ad9{=;8ew5VGk z^8@PYEnL zu%&|4cNo5-Y=y^Z3Mu>y24BD?y+qjL12#tk`pz*cUk|w6xr%E~7U%%Yf~|jQJygvaRW)x9 z(a)70od6@TiuM*DZB#g1`+hDwqlx`o{03j)H}`e?TmvMk{anHt`bj1Vz)wm_(CIcI zG)65v$BNIRJJDIvcqj6e=;w~mE-Ne#k70+nujKi;%!IGR`9l*cxhaC+a7b1~b3mBy zD{*FV(g3*Ri#`xb($8hu&fq~`Da*{V_?h2;ZKv1J?hq`ZhBtTf?1+fWFNvhV*TE zG<*|3JzJ;eFb&_P#)vOLKk$8?jm)yiPtho>}=z2Xcnq^KEU$O zw_%s8^=)WL`m-+?XD;HHmvs-L(2WX5pp4Gf4$jjc;5jz@{VHxMp-XPzx5)EQ6#HMB zBETt&rdexY;0ro)O@-!M^Q&X+@QQ6_W&6@}r0;?G>OzG9 zQ?Ts5~q;0ZEAVstO{w`3;0+<2S#@? zEi^5oT&hB5?afFNw=3|?Thd;Llqb`zQE&aJP+mT54?q$xV`YQi2xMQziS@+{Jw5K> zQ~oCXB6fTp9oNbe(B=Tu(Os@Xe|$!qyCKZfIEzgGPAe{#&*R6)TcBz#rxjPo<$T5E z8Y(WQ71voV6g7ohZbhL~DqxF}{1m!|E`}~Oi@7e%@sxai^eB3~W%=kpZi+14dt@*o24_o= zos5uLdAWRre9DDfxk5yR#aw4pg+yd;LlyFLI!>=^6&5@d=IyP3`Q?1Kzr3i|1@rj* zDIN5fHmP7)(|RkAu$Sh#ogra2(oOMuV<6$8qiAmnZiZ%pn;LwDX)%x(jAuctnwvIW z|Iba+$URHijugHC<(i|EN=!a1}4&b{0{$LgSIKYOf9tkj$j2YO+q-IR({mzT{9lB5r9PgJPeb*B&zbex%emEbK2U=uSTFeRQ29Hu zz6tOool9#F)yggU?c4h8a`0lN+RLnmXTo+}Uc*kEb{T4Z<90b$)S?OS`1hys-J+>? zaqh&s#WmYWx4|a?w?|~m+5yjz9SK{@99@tvA;UW6nw^->&j{)|JBM|c6Vyq1bp}Uv z0eJ1n;EwLpAu#e@oGvLfmG?IzFGF@kq3Sh0VGY;#OHlx8{M{tzbazK+jJ^lYu_Aho ztnoG8$*l3urtMW&9?M^J)ad(=`yhL~3SuVK_+0a7VkLJEg0RMytcvD%a8 z1WZ;V^2hOTUTIN(fh^C3EWK%f6uYa8R2`5@4eys0MYjx)xwCFRIO12t@yvX7jP8CY`8}w;N*1-L+%Bv z)bL~d^l>_UJkv+lG4>OfA^ke7UV#r-5kIF&RyBJ8FQEocfAH@l{0+g8Qr;SJpKvdL zUAJ~GfM%C*R^f@2r0#hPV*h<}QJ?+8ow4qQr{7FqrkvZX?EAMRfve8 zcv>QOa?My@VtXT(UGx;+ZU~0=gOgZ&@9hSM^oiCR)AYK6{{3?hF@87_`1j!JgisxAI=jil&x1sS)#_t&wzlY`F5_}8;d*mF5=l3uZ zeh=pXO|0aeMiBfS$*O1$2=o0O&JfOO09^7#zlSC1_b_db;K6qrr!%uGdA{Ex73q(kWIR45C(qFc}!Rp!rZlt>q&}Q z^ZXv-GM)4BjQKrqc`g7f;__UGqPQy0dw94?>zDUZ$C%&H@ei<*8BR1`Zm>#j+jlY z_5;rUmwg+oC6cmtaGv-a)otJbW1i}$wuW#$(K+3hMMFH^>5z%>;P}WD)T-fLiGXg^ zRSfA?t<&%i`su56`WmL;R@HQ@ zdP{Wc@59<7id^y)r2Q@X(B0yQQR{BeYBSDtc*0%K{ht>4!`Ij1$^W&a%hFv;d70HK9|z?tG@_&$Iz${d>RD%56-9ko$K*i059%( za$Vbm9PR}QdM3W|xtJTr)2rHZWL0}`$|{HZJET3Cn)YPJr3JB7)2eRUhlV~XZtFME zwt-PkO9NiL51|dXKekRQnoIiS$uX$R`&|d4HCpS{Xw^0R7f2CbbJ16arU?%s-|b>N z7uvk!4P>Rg9^&>~o95+5Ftbvjqi_2-25d%&5ClWM9tOVe*&KSvb-;7&z}unlZP22J zhR`2;Yre5sr{cx-9i=JgR{=6o7Yg~#iLFF;mt3cFQ#IaPXRZ)^d0|vIQ#W>$cZ&GQ zA4O;UB>uACo&Q2V`DWnJe)4XBC)w94gf;Y&Z$Sb0$+t?->3$d?oW|Q2z(v+5z2Ah- zRK_^x+@W1{en1cI<7eVN^2d>ny+LAwk9;3}WFb^?Zx=#u>8y$XM+x(N$gf{kV!+KHQwx%9reHU3*8EjS2(jGX#8=fQrx>v+hSiJIN0q7ITs{|KpwgsgVKEPC^FJeZd+W0h85;d|6iS z3tk9WhWmmKf(7`<)o4vuBv|rVE<_$8x3Vt?7p9@3%yz+1W`KRcM-ce?g1__Etk@T1 z=lGxWmu2kUT1~t!SS^f*N!1!f(2D>4i+IA7(S4t4HYyxneFu4#Ae_)aCWW|zOzd!w$3Z{7gB;&{lrH%tpu#PfwM^o~ z4~~Rjr!%r?7~g!vv8OCIA45EJLaQ5_Yu0$0BY1M?+XZ|(A(zpckAmSTa1yKUZ9Z~_ zn7mK*7-afo{MGtYUk0A)y+^_t`cz**0r*s3m7vpo8lf@zH9W_Pf5bpU$4cX!%-$o8 z6~T{Vd3YCJiu+aG-Xk;NS8=Y<#7gcn1Yz${vMQPb!hFB#LHbqC0^pJ_?me<3_a2$H zzm5m@9>2lNvgG-DkAhK``X+L@_sI6f8YoSNb49w^xq1$<@%J7zm*kHw6l+EH9z%j- zC5kWDdn9ua?}|z7U4<_3w^(Ez1uilAT!%u>mxxRWLg#v(Q?#`d{<55L!EgT5Q~2vZ zxl%8@Ru)U?4_O+e-jsZ3Go?T9*<$#~r-5XJ2X()V8b*cB^uhy-wEG>zu-%jLKAp*= zd=k`so(0Q7q3n|~D$IxQF_ST-(;D5PCx`H!N==BeYceP`JNS0>ba}qXIn<1~Ggut|teA;JTya>xsoeJq4Qi z8mb-PeqS=binuP~>#7B7cIGWS(7^W*-4_szXo^X#sUIK)O_7FZiV>s2d}>Np)M<@x z!IMLGil!z++BF%Zr3FuU<|Cg5ZOrDB$zb%^6m79}5p6LUS*PebS3V$phV9mOu25&; zohu>_xpRfz>daz?hU#+pkULj?ND2=c?FsoJr~M+5?vL;wgkP4_kRKCLc7MXcUoIDnRV@Ab;(yz)Oqwp_g2>lFZyl;oP3Eb9B^F}A-(G-b*2*UV(yE9I}5 z*;c=C(qbe?QV;7tM-0O{eSVIg(cc$qT;z*mI;%w1%poCW3S0h~nQTRDkx99kmKUTQ zf+-r;D*Xa5Z{+wTON;)71N|{u^tUtxSPSKdzf$CnX~O$D)do0qze0tVhf< z4@Lm>N>kGE1qtUjsG}+4_n@R)Asg}&(j}LpCd}Y%bd~V>WRJhM1WVtZ__Z0z%WcZo zrmGNzehEDCTSVR8;Q@VJ8EB)TqXp!NW9YgDoV=+y z!3U!QPI$2dn}GxKLlAgBPmPm8u1Q?G2y0y)Yxf&X}4fksXqX@0`1m|vqjOlp*1#59?_^3NDOaBq93yES@+CGIBmY43;n?)wO!CevQ|^Yo0=RJ-;f@fZ3~SkTBTS$bERJu0 zybKG8Ao-&p;rO;E+OEep!Wxcme?kF_Z-17c)BOuVWAv|hjur3r{8x=v_lNQK1#w_P zT`4kQc`$jf^ar`0EOP$^GyO46h?U&G5d`y;tcvDr=`bwP)rR#C#K!kuHJ9X%_QYBd|1~5Sxf7K> z5}Avb6O($R`-~px%z*-aTLXQ&|3nt%y??O+#y?3WbrN_447ViyIcG0*kWpdrl8Mg> zv!Hz-_a^az>EB3Tk^ClcdS$Uzev8S$kud~oZ-RKZe&(p#y9sO$uR24(aR9u*@mMY# zGo3G@v|I)gvA(y74K@(BKSCSYAMBL&myn>-H4qx3CZ1!(M?Cw}m>b)lDfdBLCHBYi zP|c%Y5_2rRySvRp;0xpMe<8q#zX;vFtA~o^~#1_3l%5DOJbmc?9l}p+?ahRNivABXCIAz@wk(ULxZ^FWn2t;2p zb(LXLWHA|u^kBl|Tbpniv8u7r#JI@6=-8;6%ZAdHSv_LQA?3)OR6;NQLuB&G zzj0^`XYCAN-mINv=^DFWfrfU`i~_KW7704tR)ofA8=j$E5C`r`ls&ic#wAmw&}MBH zERSYB4$*sd@fmFwztVOgOnY`A^h$0!$-*uqtD>18tky2b8tsB5@g_-F{SWP8D(u4T zAl|Z|^-V&U(F7hqTL!K*Y)UI89uXW&f-Gy3$RWm2&G+BN#vo8nm;j5XqO z6)7KKRiwFTye9mAw4cCo-?i zAch)SBebEd%|rp%+AIk=-5!L-=q7lM72zq#zM#h3c>FRHC#|bR1}qQJ@|F?L)~?mI z_Duxn#mvXN#(QTpy^=edAlRB@RWuWX`L-5ZLgSJ(+8RstE!C{br8KSS%1?n2bJ!eK z6vuw9;U&edcjvNhS*rTxB?P6t`f?h$Ih06D1R@-m7unM0H4m}q81>p~p?&Elka^k{ z>qP7;BsW%~c!PaIvKFx~CaYJNn*!#ID>h5l=$Zu@>Uus3K-awzbh`Mw6dKx(XQ*r9 zm}p!v(fakFo;CYqoO))Z zh@L}wReC0G5j`_`<%eT)(KXVCh(M1c)O9$H2x1vW{t1zDE~4mNK4cuhp|R*(v=B+p zW)?B0#%5Tcq0KBt0ocsu5_Gy-AT&m|#51%R;+WWGo(FAhGb|60@pd8D4DW?L2L|(i zHW=a9GZ-OOas09GzWy$8VvcO!LVdszvfdLOkf;CEK-&dzHta%X_GdNXAPUJ zjx|#R0OKHaZ5&Gwi;e-$JQLc6=9E0rHdrTO8zH$W+aPNZ+hDTFHZYFDPay(r8`NoN z8-iGDo@2$odvlUTJkgwlMUBGV z5M;*kP{mAe>Wx#EAP;8uMQwJ>$DGuPd`++9?o1HOPO>VR3Br7{>q1#)7XVzcMzdqd zz9pJfdsiedC$*teM$bkwaW6c7|KKiV`LY!EZBU3v8|~eYJMe^IQwp(Wi$Gw5WJTNH z?ubQg@WmHH8`Nx*VcH<;L~Jl5H&&uZgL#OoMQo7C>UrorfO%ue9xM$3#`Vhr4fVSW z1)$$OCFpebLTHTcjc2G|;+S|$c`48@%cGf_g!(;S>lcnbeGXyT)34Agx%-eT^eb5v z%>-e!`Xy`BFH81qu34?4-)?N~yq87GQqotg;FsoU)qcsaDS%juMHWykxzMWJ7qQsf z^S$qdy45U`S?ZRRBDxLfRq2+zMRdz#)%bF~^c5n|;|uj0jxT~(#+M$5nR5@t?eZbx z%YMWku7mbR(zBBTm{VgXEYQ$SmZJdd4cgvRKR zc#ah@1IQXiBc9BBaf7s#bU2 zXtv2PZHILtwiA*YD^aAud_mSCw!>uge6bQRZyY$5rEA6k7HFv7<4^$lJzj!N_XLE- z=qfxz{SwE-;{fLitzVW$GmnMrJpIP!3t`&Ruh1*GCz34mD_IrI1Yx!MC2Q0#OLD$o zx{iK1U%a11%Tm%;t>D*nM75YND1catMHWykxzMUT39)hK3(Yc_rEXa%qT7&Om2Syf zM7K;OSWxFCpSTv!P)bH1RsT|Q)7IGOmv`Qj8LJv(ujQ)4GA(9lj! zMFH5!X%ck0s}UNbBY1{(LL3v@3FixKCoB(<9k1=AYQ7MTJtGlfCHHjFgpo*AMRPz{ zt&xx~8VO5szF=A#3C!XQW|k$-Hw(e2ONm)vzF>P}4V0$CEJ#Fj+lQoDY~c0$jk-vaSgA%It=Ey$}VU*NY_RbT3ATc3r{%dS!Lk%0znoVW3x5 zKr22N>eZVg9!3$YDTG~5uR^Qjen4owrL!sm93`w)ubQhjr6lHv3e$D;$~odvA}vcv zU!_7?*AbOsj$q^c)`|#_AOl*ZmmwA(2fp>Ka6O^Xkx{CRwIVtVX)#my^mR(kB06Q# z8wtYiV%;Krgh=#QK+T3@fgqQ$U>(HFIfCML`H->Ta#9HAh%1ovEaXb&KoMMfhBm?i z4Q=Eq6o8Galc3Z6AVLW0Y6h?oR-c58JRR5wD?lpOXdCh8hmUIm5pF#L5ke*R8X@$S z5JFp-8YQgOKr~BlN=eKQ6{fv&G#U3=RxC@NZxTXGm-5d^v8{gNq{T>(q&A7`5Q9nh z??|HOq%ce8`G6pARF(5yiKk=-!iN zn+(%LSSR9FgyhCb6lt)QAZropVX}ILxD7C`|KHBiUjGmE%K{Dc`w18tX98djrwItt|geR zqhHPwcd=+$O8Tl5{JM^)7V`uJ5Nol>0;(k!TD5m0HtzhdSthg8Eh|NI8`7)NEqROR zmdPrg@iyrzM4-n7>Ngx01hI?@k3-CyCn#>04;dFePW<6K@d+e7JGqBBHFm-R4ejKU zC;&UTSAtIWK7_{Tr|=Bzgg7R)6RsunIKc7{+2^&L_;ba5$cHl_9D7D0#7gd`NfSmQ zSryFzVYNm=zGx&Y$+ZO2+DKp)pJ8TM@_e%pjJlMV1=bR5Z>)jRbeIL{YP0w(VsRhh zsmR`w=92u;E?6sK7a_qayC8EByI``)F7V?5jG;uJ?SlFY?LrWXUGRrfvRM5zrtA-Z)R6HCz4s_|_u%u?68c>GmK3IfpMt-6~A# zbNCN2zwEM@oWqy$lHY;@{41oQA?cJHcU$zN9B^l~NYk1054i7qz%qQd4F`hok7t6< z+`UbuviCVsz5jlQ7N>@`Zgj<919;s>0*dete%kFdl)niA?4t$-bPfO@%* zkZ%Id-u=Kmc17NAk+ye4-p(gEN3$^g;p}nZ;F*s$XWEhYS7I>_CX@Q9_~ZHD$C20y zi>sS)Xm}pt;8kr3_-Y)|g6!~xF{S3>Z+HChR@$j3^H+p;wIFzSwwd^L#@}oB+X;X8 zD&iEvaA&qE7Tg|7y@*%rmikwb&keafdkX3cJ!|&^tFxf{MsD1C#%x!l-NmgNd2YuKTfmM;nMcqMKXs@6Fvp9RN`-o9NucC ztaj{a>#C?X;T2cZZ}GI$6~g&Rf`6Uy0$P2YK>jGYC<=zzBDVp=X`^?@Rl(9H;qdI7 z``qlMuxQvXQh!3*nPM;MP?tmYOA$vGLFxkNeyK9iXPLSd+FyzsSO!w}ND3N~)W0N^ zQs}nG`&%bV;#NpWeXOWcc}cC5l4a?n9qN(JnO#d&8UL+Cy^|NXJ;Q2>!eK+C-j9B@ z6shTwnlHR`^R`~(Ef=n*sZAtxgm67e&6CuwQnCm4&k*NtHYLs;-t>#q@m`)z{YxnH z@b+HhUFD_vCAGWY>`?=P<%O=p1%(o3DDNa1G&DfHt@5KMJ~I#cIJ>N}R7Nb8Hy~B~W0W;8FCAF=j&QYyK z8YTZ}B&R%}E>N>2^_wJ97pY!JOFQ7*-#{$VCc^Bz3nsN_cr`2J=3lR>o4t3C<-`blwS) z+Cx(JsP{|BpG%8AiC>VA&%=f52h~NA8j;jv>PkuJl3!HUODZFI&#HSxE;{eq>cI%t zFRC9($qmw?pQxWi=)HnILwYj=%j@dz5iGw~Z$~KnT@_8rT2pvSO*g}OR${TFHWdmj ziESkHyrgo8oy;sKaOQYGl@ohN-X21)JF%Cf?vj$T63ZpEP9(T#;&4f6&g{gILj6Y= z^@r79;si6)?PiJ9Qt}DW?V`jPl7cc(a&h7;Ni7!&OA_ZvYOzq?F>zT0%kGKmB#*!5 z8CH8FZjjWaQgT`1CS4DM|FGIO@li?rS#TblxL21Ht`AQ<9Km@+;!(-dIFC*|p-T$R zV-la2)MCN8D)F?WG|p2K--*;aEAitcJGp6zRJBgPTGJdG!?j_G_y9l{-3aR`+DBjx2_&j+oZT&CAe+PJv$^ep3 z=YfZV*1kE1wVuSYM~#8E{nn0lorxbUJT|y+xEqi+yMK#kclS-!JhgfE z)FzaX=ig`l5%6Ei^D~>V{H5~zZ1+D?J?gB5zex9}1KP;j@3OmRder&Tmo@jO4Zu&x z0>qiyqh8wdm6ot1;g1bo-x`H1RJ+gqWcxz(aQjt|z+v{Uk=r_hZU0?%8K2EZ0p45s z4xTf7QBw!niT zS_!pyAzOEawCL*YQkRAtw03QoZM?d>V?H5ed9oxWV5!WU)A0NV%2?{-=sO9u9=4QF zcg+|AhW!V2!gKRB=I#lNTk89zsZCp|+tMc|OX?_fFrFnmvC;wDQY-OHsOdRk*n5DG zt7iWSknX0lfX9d5gZRGCLNu2+r_Sf|Nvj0U?tY8$-c(7Qjd%(6e>dWM_Nbq=J(}%N zTlM?{c;1*XcS?`CWz(NyJ@`@4o!0nS%?EcUl+%1Go?P?Ws4ePrj%Z5E2-y2O0OsW+E(3)U)RvOd=_c#h~7b3bI_Z< zKWj3ysxj|~D<$GGys3wne}bo$&k582*z-;>J2jZKWPy$;r9XOX~2%{T4Yn7JbC$M7L$tjA~BK1$DnnDIaq3pOw^- zBtPfPVy}6mv!v!H9_g&l)fMQ2aru0I9IpPelJ%+YguWA}K5JfmnfzxZ>r>xtlWOXF zM{Faik^ih@ed-sXSH|1EZk)EiTP3~O3T-?X{d(V7aOTw|UA@pjLahi=cVqrMHAvly z)OkUQdFz5y6YAX-q&krLluo6~nOm9+^{|(kyD3wj_fm^D?ZE!e*CO>ywLVB~hy9=5 zdL=(Q=l=Ok>MudwBS;mn;?Z0`IX|W5>s0zfrE{aZa7 zmHAn<+N-x_!7WWK>Rd0?HTN6yThs+X$prSEE{~yJAODn zum0wxrlVwDjRhq;R9>}W+X_-jZ-u;qDtf73b^Sl`-Ud9X>e?UPA7>^XBqTrxUjZj% z0t^`fAyE(~Fp)u&2C60sYShF`6fr81SfK_@%ml3lzlat!*iaI`8d@#XYQ<}460Rs( zHCU}pYf=)_mU^|=Rx7pdTED$B3GMa%@AE!=-{*Os7oW3Szu#JGf2_UFK4&s>_Sr;# zi=JxHpC>LQG{Yd&o+1`UQN9>2R$9-AnNRyt#RXBDq&uQZPeK(Zp=(bvl zM~M5x6>~$gXNYqx>dXnvo+X~J=odNX&z>y?fF2Y-oKrg6FQ#U4oH+xs#k?qbCnZ~~ zHAuWNcd=`(Xfr6bXVQ3Aj(Et$se4hA|wN=hJs86M@15krlnf=uG zQ$@(48ZD z_$4B3mWg|2?)=m<#afFFq<%0yB>uyq3+Y<4T)Y}Z@1!gju|AGFD*x_zOq?wy0QJk? zdKM5m1!#+Sclx(xpUrOc?||#Y>@Bm;5p#`==1b%36=Jb1g>ByuVW9iyZ}3~=3PqJc z6X&I;k69^p1Jz-*St))pB5tL4afIh8aS&)r?5ruP=y6Lmm z`TW>3{o^??(|x}1Mp3rANMuLRLiYt?VH5@3tHshNTIs%6tcs#F?n}i*QB>wG72zma z=PnmjQMA#0mAEB}BJOL%T~Tzm`+9B`{iU2+w!^{KScDG9?xeTlZnU-o@`AYvL1?}UP2EKA=ln%k+F|N(d%?SN8eoI-vQU|Y){rO8jPQP63QEaemUd9)E&{d z-Wlbo{2d|xJK(x$N|oGc0HLxeo7Ju;+Df+8C^~D(M)_D2{l^p+{dLs*JK%bPzF>SJ ziXP4mW(}iGYT1)fTW5UHNhmMtsS&m-v-sP0{&ygeSH9f_5aN}OcU|Cr#`d%U*7l6p zj=9?(_p?cba*ue-qTWg8N&a~t|2vS#Yvi-yC$JreyD(=Hy{+;^prdj3OkmV)(Kizq zy=)QBkY`OHRLbAtZq6D;$?-R5{WNN;A9Y*Sb5ZnNLeCE&*NbtR)z8EmD6?N~k6SHY zh}u?WSIK=*v}wXd`5#gA+6vfdJ3Su_~`Y}R2BLtlgOHGDAs<*c{G z+$ieJdPkfdMSsou6}!>D1FqE*H_BcEfcB65jaUIsUfr%6`@Xmc=%`#hasSvpaaGjz z$k^YBZ;h}W5e-21;p#Lf?lYdTA0}@SgQCTvbEh);fko@G8Fd&$^}Q1_DEbT%P*@n4FxY>sMK!V(JQ07&1ZgFxI)Nl4G*QW$+4J3&s5qAy}6$}^)V-%sB%M3F0QimU`W8uz!j z)X7t2t3}E2sgtM4UWmCtr+vEN;4tMA0h0S2kP3=WV7u zVUf>!u|HFW@=V-WIUD5+*=W)GX;=DZ%EK1%THup~ry9>q6E618mY-YnOlq6XlA+U# z?eCub@pEJmkU5L9WeL!h*qf*QCO%uXTF-*H)&6Yxv_X`?nxuL1LyP#jnIoqz;4*ns zTw=ZqMbR2pu6zUNDAvzYWsgNXwx`Noi+J@uReEXH2b1|Kd79h~v?cbooP&CyY_T@Z z^+Nffv5B8&Z&nLsJI##Wcq<60z-1%}Xr{xf9F z;vwWs49M6Zqoa~nzI=HuP``X{PL*6NS6lRl)QvJIFSF=ET5Sqsg+=RV^*&Rs2RbTw zG?&UZEaFvoshn6K=-*NKKCOcxSqij8WaT`NaF%?+q7_v8S@M%8dL&`F44i4=c!fSk zegnvi-#N0#+W3y;99d!z&Z8AF3}nuu74o(y`Z#ul+!;kK@eSD#MPI}g%DyP-ajla7 zh@uY@z9~IR(H6{!^W++fcut%z@3n|WtVq5Kv?Z3$jw0D>5Un;FWsy8P#HCQ*X;g}( zXW0;X(0_r#|gf5rcEqakqsqC}p*M!RCtQ98iF>g`g z6>_~ruV)k`mdodW%x9Uf{7)b=Vqy7)@x&PymJ`3hr5u$!eqotz5XP@U`hd*%RmkO0 z?LV{2OGm_2hH2S`Jvm_e3|!v(GbaxiRSp|4s7gC|cv%B!lM< z*`D^_EZ+b+DtRt#mW4&8cD{SMMeYNl`I5BQb*l^)o4BK?i(PfH&!Y9&Qq;@B3yf`j zc4TzDd@hRKiHXRx3ytk#y0f}n-VsHMUAN0)7M(l!1^;*CpQGsY(ch6@0hw8Fr;J%` zO39wv?Y~PVThtl3{)q4@#~Ye%Z`iL^FDF$oM)3Bk`pd5aXjlD zmYEjutb0V}S;T9>4q0H3;E~=TS6RgOpF8AL7V$jWA#b#Z$M#Vfv4}^kMc!`_kJwJx zViC`?@5|j5@jUy!e8D1~FT3PHAaiHcD*pgv?loHFaUgS!waPIi+#^OV(JJRfQID%l zo(shH6E#VX$vZ6KbLDZ_VG;NC2^o7SN)fYCH>)S)MvDq)&3aM>FEh3RI&+?qhoi`w z_ybvaxv_cZ^K833Y|+%z&;9MPq}15*l3Zf9j4c~Nzt%sLjTUhxek6}sbZ}w=p}Z@M z=Yffz`+p>xE#hm=({jL~PwDTkPfLF}dzv-tX?X^aIUAprORbGpsi$S3LCC~2GGY;D z;>YrNAd}BM@|`H^aqW?Rv7Ws4?3G_w#PolopUO&$_)g$C*=rHs2|O=DR~k>g6L?i5Bslzkate^i;M+38+Bk!6OFxjw z*)Qc~QREW8l-r}I$Mud3ZQwHR6FYOhOnz6^03F3l{*`>fBA&_b$+s-x4EDAarPtGMXDXh+zDK$1}x$`fz>Ll zjy(^=@}0mMRcsO830$Naf%puFi@8|Mx{W>S#KKt}DVM2*7EK@ZNy_Ew*cM}3J8IPU zQuW5|20a-6NlLj&zLSx;X9%mcKnLi1i|4Z|)YBIIc~W`mmCAn?dmf18vtzBQwusM; zwdy{DXr!yBtyL`+y%_gW_F6Ts5pndLMtSPhs>`BH6S}jnQAJygjqe#M)h3I04Y^je zSmg6|XJ4zlcN)YBI6J<9c}56Ij>T(6va;E6k{>s7!a&gXhnZ4u|QO0`?W z`Mg050GWJlP;2kyQtAX}@FsQa0fRVa8(YT-ldX>zt% z)mp?kqq`}Ckh9II-6GD}W)*lCamd*%>J5uHXSM3`M~sbgR;L;);+);4+AZRo-KG{c z8&A$zy*gwO=PaT=0Wvv@sIfcPb4%>z$p=S8RF*;F-K2xEK`l0j=GkV|pw>oFk86us z`zYeb=1sg^Jppu|xF_cy6YfwS03DTF-<>M)dqbWsLb(PBw%w)9kJ{eMzDwOZ!nRfY zz#z12tLln+y2Rb8kCEI$pISGod(^xZA!6-Hd#}2Y5U+z=!@cSepgM8YTt<%rnQOPJzu#&xfH#h}=4(Ja4Ty=CHJ@0jBf_p4t69gQoPvtr^lbp)tCZaUo|ZBw5Z8|vGp z#7;r~j>@C-H^6PG*rIo5Nj+aqeewQVKaBWgv|<`T`S1gKxWM7iFfp0J4fzC*3q#WmE4Oc&d3 z0P2tXvA==Pw+)g%puFr*b=JoD+@bCU;+DC@qv{Fk$u)dWeP$8Y@ICc(>u?R(7t=d~w!-e^4+iZ1sqwQ+=JtBQ>9Y*mfcvyMDl)jdGwuhMPm{t=#!tA|I} z9#=a?*q&5v*0wYGi!o2C_7S!psJ%d@M?X*uBAx}^YSNEQDg5d4fbs%y|28EaP-2g<@tk;Bg)HJZ@v>?( zh-N`#?91x8z3`Mg3l6IFKQV~Ec|E9ZwurxZJ*c)sQ68cDEaJPFS5ym-nFX(?Cyb3| z!SxefQO{Y#-z>kXUbb<3%{in7fOt-I$;ry(Jxfq&$tFNMsKJ} zi+GIQRIL{A7`>%>E#fiiQ7JE&I3AKu!BjNVqoK-|Bdjec9D>@%J`M(?OK7V#Lp zqgo8Y7`>yKUW6yc=v`I#9|rLly{lGR#AEcXx+0452wiItkI}DG4Uie5U#W<(VT^vI znk?cmdQY|5I3A;4s}3MDM!!~{b(z}v8~0un=r)MIasRDqwurxR?^6R7@i*?jQ~m?S zlfQ94qN*+8Z`=pfK8yGp_oK@BPvgnoxPPDuE#hz7KTxYJ;&0qPRJBo5MCh(4%FFsl z?Tw-zb=V?a zCyuLxSGb0waXbe4r)?b1$gk8PATuMsQitE*+Rdu*4>bT}#z^Qj zZ?esdkUS;T5tBN(hifpa zhSFzS#3QD4twlUyj(*M}9x<2x#3CLsx6V9lO5qWU(er?~f1L?2`k1xxsu8E>y=^>s zjN~dBlLzvJVvAR`#@%lM(GcX4P!J) z|J5QMqXZrEuBm~?C{cTW%oru=6TfDg8KcoUp_h>vqavbH(JDF zl%yX3GGmmacNl~*O46;?#$%ME_X3&oC|Mt~h|i-jnjZ0_f95R_#OG0}J{O4l_d#;1PVO_FJVq0Bu|+&a6Lqse7^8{$xqf(J zj3(*zzcYx(Xp*k6h{tG>?uw#3LJ3EVCy&u&Jq5^&(PW)rY#5`-I@cl|qbYi+jpH#& z(AKL`xXkIg#M&P7JSH;q_blSS?0NO$KwO_3 zo2d^QB)End+W7<5uqC!&P6MI229c+WP!Pyuccy;YB95D>?>)wGCc86ryG5Mcnff45 zf82-uCOuQXX%JdHQ@?9%-0GQn5XfX=mKJ~HGEIFx9kGb(^J)Ko4cF(>XIsSe`E(el zKkoLdin%^rX%On0tv6U3*Ed_&THB4M?C@skPK!88e*G#Cw@?Oi}-Iyr|J}o_^->S>M0iSUzbnQITrCZ zg$s4iBL4nwp&rqTf`a6*S7+31~<;l*S8yl4Cd>*t&KC7 zuO9(2BeqySXFd5GTcZ7c9cv{w|}8TB^T{+Fara zognC*)UMa%y4E5dhjLvb*=G7)uD4sn<4~^m0GV+w*Dn}^zL)EtTO0SiT>k>d zMV#xk`maEyEm!LlXSna{^c@y)Th{6I^cT{hwye{Q7I9nF>BoUgTh{3x8HBc6qo1`l zZp$^g%i6dtl{$u=y5wAQTdvhfK-?B7uG15M>IIL{bvi3*bBXmjVB1&MN(~McmFReFVsiQI-CKL1<@{{*$$FJFE0RfJ|O)&}p&5dD)=vwTSE6pznwq zu5W{GwTSE6pkD$qdD)=<(;(DWtzWk`uCH46S{vu(MturB>pYZ~Z|RvprY$$=khO8& zH|pms;TCI{gGa3o}$-o$j)T>#NiKKqfDB z`Xhr--);I6YvcNEqm4~WCO9wkdZ|S`cO&{6K&CAXdabo_Tej$TE#kIp(a((;Zp#*Z z*dlJr7X2xZY0DP$TRC>$^wyTEz9;qYu+l)I(!*kN(6WuJ0Z_D%JFzuW|S2aR#Bjd-Y^%kQt*U zon;W(@_?RiZQPazbkN$kEf4B?i?}V{)pr4zwrtlATN}6KA>C>bx8)%{ZIbCbe*$|* z&oBt}J*4MY8`sCX_0e8`aV+0WWmz_r<*QznZNwTwGr5HSnc-MPI}&gSMo-S+ zC$&a0za?hKYDzYqhVQ3WS}XCNbJ%B02FnlTahWB^2A4*ASdmn=Rff43KBlzykqr}T z7`D>=oppQoXYSJ(-Xxz2INv8FVR zb;P4+|38;`GCy3hV{2^0eE1Qq)KWY}XBu1cKkErpk7)PsZ~Rx!=6f*+DDGUb(Eix|Ax+#kv{*be>9C-a-8O&`Df6%Ub& z6E8;Rk|clb*GqJU4wcMj-^mQ0n~GwGefS(dnK9+Cr$%YcN&coxj{5JcyoQ(>^@ymU z_6+CYUm24biTu#72{GcFtCPpbFvFujPbp(oupAowk^0EFWIRXCCBqmWzOtAShH}II zr_U0Uhm+4xbEPmXG&5>=jt#Y8WWDjYhK`iRYO*oX)08uk8QI!lUfC>}wwauaY}NlJ zZ>F@7tup%8@wd=5NQv)Y^)o(GF*^UVG%Yl3`?_3>9L=w*-S8u`!DkBn4G5z%GLuF( zefc_lIBIB3GuLIl5-D*4*Eo|yQ^N3>d$PY-F-#wg9A=bVU70ufzpf!C&#Mx;PAS?Y zjIUh0r-Qko{dcSJaQnZ0Ej2zPGyi|ev!WW!)yib!j_hH^^loGcUpJbjUL(J5c8wgb z;l2!wreQ{o^>CRd&-{OH??#sPINeKpeddSTGqjHVPi;2+8fy91^}P@Gu20attG4%_ zUw18tp{oGx&z8y8g5%TqT5vk)akwtT(?VOgHP&lgWHfk~od;N%+2z{|((^(|5dd zi=r?_nri%au3#fuGEyIE70;YRY7e){wCCSf`%o{<*=;^W8fjK1Gbhbjv4QTQ74BPx zqV{0Mnppnar0ge3?!}PL(5FAnrTLs_uBVd``>%59nBmxAeTW-zVW zJk(P&?ktD0YV_fp4BaREGc)v=>+3#wnNj=aPnZ8+%+>!}Z5}y`hV`MD#s8tdp2Cb|Af0o!*dBkWtx#4SN|5FS9 zpDWqi_m1rQzs|;gX8xb(cwD;%=^I_f8HSdE#4ie4CEb=-5if zEp*JMV-X#T={*LQ(QySGZaTKoF`JHfIl&8E9u=9E6HaijrdC9 zXzw_29_8VDI*P;%^j3u%=p7bY=(v-PyXn|U$8H+c$LM%~j@@E4mA9Jo)ugW>W(~Dq z4UP92@?AsRMP$E->=%)KG1)IB`^99xnCusW`?)9~pAzyZA$%$MTuMHdlFy~&b189` zk^M5VUq<@nWWSv3my`W+vR_VIDcMWOUP^iy*~`dYM)oqYml1ab*{>k`6{MGwUQT*B z>0!!Un0&&-g^3Fjccu6-9S_j4TU;fM(y^6}-_h{^9lOO^@q2oc$B*fFfR5cXd#<3v zO~+Pot$3J@2k6*M8T>vSTj_X|jtA)2Ev_f-dg87p?t0>`C+-F+>ju(qAbo@Q868{c zc$SU_=-4f)iK`~Anz(A>s)@T%yh1x!|Co*k=-5r~{rDLjTj_X~jtA)2O|$rCbZn*L zSvnq|W4EZGm>SY+NZ(BM&1Bz9_RYj?ChivEZXxa#;%*`C7UF6trk373LVASs2C_Ghy@Biv#5EANg}5!mZ6R(8aa)MHoyOpH z(r+g{PVo2aV@SH_oiVJ_F74^@bdK`Qou@+G`z(&Fu80v@6Z*^s{MC-vas;>moca&{276xeQ;Yiq%L2u%Eh8zRx5;B- z<&2+@e2sQ<3X^`2sJwGdi}(VCx&;Q_oL)u#m@=)6+hiw zOeIuFzv5BIQ@kf>2{CKPdSlWW()sDeFxn7Syia{t@iTvwsMoI^pL-8^@)$|Y&lkR_ zj?Q@06{mT;{EGKr@hjeKr3NL`DBk0~M)8w@WToE_1{CjrA5i>^pQ36M zc9K5R%`zKuA!HD8CFB~&GRSq18zCc*ce|TuR*!e>6a3tNv*foyG)sOew^{Q0A)4{K z$Y#l-)+~7ky=I#88_AP*ENRAEB7f@XB+3cx>PYjP%i(#_j2Ygpc)$L38q*g@^7DUt z(W8BecQ5E7Juc>u;(h!Nk`N_Y-ir+}lOMP4&GeG*rE3bB%Xg=o})jRwuL--Z?_!%#mudw^I7KCyuVu> zmGD?xK=bZ(4)!YbV^=o6UOD3v@_cQ2Y`kCdxcD{i))pWciqF%0&gN-8XZ;#8Q1h;K zp9vndV}kc*`wXj-pIXwU10+N7A^p|Nhe^Jf(HdXKEvH`$@>>x6G`{<(7T$BMnE2!I zC7R#ZQKC5mC7R#i5r%(>=67s_(Vnp8{T{-acRDH2+|w}ial9)`{i>2_=usi<8T)oz zSo1y+X=p=O^FAqQ=tU)!+2g9z{0z2N^V)Kret7a*qpDF?HTi5-)v$7GANjmB`cslU zlfE3qCG?Hr6>N4w4PtA^x|DQYH)`~6XRb^LYo5I&Xki#xN<)^ynzIzvyn2T<@5&L@ zyoRuRBq4&@Bb1q^6G}ABTw*#CN-!UqNSC5S@>@(;|2USVi+kyT*YxH4~Kcl^;I^$m--K+T>7`>X`htaF~8L$De?r?fFzZIib|B3!6c?=Buk56jE zK4+g1L#q?b`4ved>FqMjbavAdjhf#*b4c?$S`KO6ajKB6WjmZk$-B`U()@lJFXm4U zty(*Y;rG^@PWlh2WIh)f=`Ny5Hey|El)P(ABUai*te=foKWRiL4~|M!X;M&TinBE%nB0nyO(Ui#x!ueYw1HOxnh(;f z23&i)nOBlm120POQVG{n6wi&li1HIJN$0onuCL0&|K z9DZ+5$l+aIN*td5VTV`Ru)`~DiNj|>B{3h484&!WddT5xRtc3U$5uQ1o}p@ouU6F# zU#+U0JbJ@WwZrcjs&@E2L)8wyXQz@F8GRY$XQ6cvmB=K z-yt7<@6jQL_ZMlxdDJfWIlDs+@6yt28GgF1m;7C#m$L02zYq5(hcPP#(Eh^??-gI| z@IE?+9NwSg82Nh>k2$<*9d>x{_|MSh0pcHv`wT5V?C>t~haKKMzS`kkcMdzecl=?8 zcY?2Wc;}tN4(}LG{M2`-&3q4e*x_B{4>^3Me}=ht$l-JRFqKbtQ@DfTJECN9*x}vn zBa)w_9YD4tlAohJ?C=WUxVn?7QzMd}rA=^g?-E?xyXS>YZccq(e2~*hR(`fNBKeux zh~#H!Ba)w?jYxiW_At#ZT4M!2_0}%<`L;t2uM8A}KB&ixd}+MT(2ZBE`jH zk>VUYXNeyfUY`c&$!z@rsn@!kX;D)!c>kU+{Bh zX)a!SQ(T;r6c=YB&BfX9qF-L>*W={F*8;zb&jr7W=YNWeTU)95%`}ztTg7kbJn}D- zm74cX3AmUKxcHq_As5fILKm-Bg)UyN3SGQjRU@_yq`%4-G>)Xl)5ghcYHC`{#e{Ig75YNxZ5nIK232IyZ9W5 zD1PfqMDZRT5yfw=@>A?ri6!V!MDcsAO3<%};$K)c!he%KHLi7HqvE&tG$OVUv5n;a z1o76BcHan7?X>>5_-?rpdL`+zW9qQ3I*^qPuN4WyHP9n2KD%pN z{06KV7vHTly7)~$jZ|6@Nq*j_iDGv+)h>R%s2TdFYF*9~x9Rpa7!Xw|s*y!O+zjIF%SKr4;)byM0YGj~nd>*D*; zy)M2l-G_YcLq5A`XX^c9+mW$j)CS*JFWu{=kNb@DxR?_pUE&1IoYJ%!D(%`d$IXo6 zW+nl80`vgx>I1l+PjU07hJ6(KSX?X3XTCS)JN#A`-|@E6yk(x}Z7Z#5n^mFaF)h^m z``<#%BU`BX?J|X$-}_al`5j<>x`(-LN}8MdQm9wX`7kZb&9k>q^VmgDLIfp5P(lPH zM5u&?6C)@gj622%#ZGZW5ao4q#=LHRH<;JW?*{X_IiFrP=hN%Prwr<&6n;0}#pUL= zi+Q2vx%q8Ld2W7lQl6WiH}bpr$)W)H?{K_se)m|&&1baN%_Hb_^WF<3xIgi_d2~W< z?olCnRP6rV%nPRV(r#h<#}=YrO_Z7RaffJ~jEgBjo=YgtS5Na&RQ0qlm@t@1=#|h* za3@oZ{D<6}`H-7)9&&TGn~|kvWT_chYDSitDNBc^H6u$+l%?a-YN%BWClvuE4X;&FfVcmF9Nsg?>)RQ66t~rxme%l=I3?yLN>X1r43;IH@SJe4Y=6a5Os$)OVHF4xU(vFdg6^GUr}H}+yI_F^pdVl4JzEcVh^ z-09hivDl0J??vVZknI6vdjQ!UK(+@kA_EwaW7HDbX#v?Dpv(u82cREA=078Ak88lq z@00rs`5!?32ax|(%*+9d!e^B8Y3V002Tox0ofw?;Fj^I~|;=oh2c zVd`U9MkPj}68W!2AFHX4k&I$wpax70mbegs|x~`kROT=AplN z=x-kN_q~if^w&?LUzX8`dh^itM%12%3>2b-LWke{SLpDY|4649QVhP>;VXNw!|(hn zhPBvQ`Dt=5t!eZ=3y0qVSmN+o081Qx3t$t%X9H(sCMMPo$`Ow zn@87Z`g_J^hj1rwg36zpc>?7-ZjN=_ zoK?roIdR;a6UWUtaok*jJ1|{jMy+@!-x$d zHcU~eW5YIzpV+BHY$akV5nGAaO2k$owi2b0%4|jnO|*W}Ut=)Oo6-J#n1{_MvlS(@q9v^;rxoS2qMTNg(~5Fh(UMjh#Vu(^ zY&&Ax5!;T~cEq+LwjHtUh;2t~J9^>7V8mlE)-f3C7>sqyLouEiP7KC6hO_O&@K`6n zKOu%^NCKh~5S4(a1VkkuDuJR>$0pb)Zf6Q&QxKbi*c8O3AT|ZDDTqx$YzksiVmLN{ z*Z`sehzcMoKv65b0Yv4|8uge6ptS+Sh7c7(jUmK_5F0{l2(cl=hEQY3MsbaWh%H2H zAz}*=TZq^~#17gcYP7Q&Q8nf*p;$ulTzV_?X!@Re6UjBAmgGip zJINZ+JS&#IzkGq@UeQ7FInhmWpLm7jMD>eVW5x5jgXD{l`ysnY#)^abFv-_Qjumej zYYcmKLmq^D4f0LMw@Jo|U&V0LZ%B?6{a_}=F_TYntf-3P5^f|plfLIq3(lr*OEUx6 zVidJ1o8B$>>bz|F^~Pb68R9s}Ec%^!w#XHs9RB6Nc_f#L%Se7hRFf(M}j_7v`()j%b9e0Rcg8{|$axvpJ^+J!QAQB-1n8(Fh_Pr+voc((e_V z+)h|K$ulp%Q`|)*bc1;Xo;{F#@b8B_f~X_#IYLn@@{b_uBWl&?!0$=U3miw3kkhHZ zLUOAlq$bA6)sowzCC6&XH9C^}<&xa5c#@fcapY4q--8l7h)svgps1?+3`AwZe>VJc z;a@=d=s*EHm!htvsB0-jZO>ndsAXVQAgTyad;6Die-^2en{DtD&YK5#SWL4FRjKx}UR$Xec$nnJ!Up0RmWClDl;F&?5NAok_ znMt1czS;1}g#k=6ss(22xk&nms6nyqTc9PFe7k8q@PIz{~ryKGW`1GT+Bjowo z;v?`GAZun|kgQq0-;n>P#!P*A-6l&~%wHqZLg#Rm$N8o=1o`bOd9{h1g;oy9Pq(3WB%f~s$2AE7@ zJiggr3P_(6SOL8h)^dmYRRN!Mh}{5dEvyaT?*!8VW*7Na&2Iz$6!<-m-6XSo{Un{- zBPeqaKEj2zL24J*<#Ms-IFeQK)4^xDxP=AKm%?W${cY{Y;$`5A;8_N11(hbWsV9FX=& zh+Mpc82Me29JK*a_3*5RXT6(qvJLz$@Vmh80^f!k-5b!biuT*D>5*9m93GppT2;zGuLiL3)-i6EYY4Qt(T`EJf5Z=tZ!W!&(le0&)ZR zI+R=wYd!dS#5RE62A`eKcg1jicExahcExah+Q9FDPbZZ?ql^+d;n@jKV#u>IhBMg} z^8(GfZbbDU>IkBaAnHgAkN6<;jB>n<_NVU%Qq0q^M8P>k1rX7kB(#BiQ6MqkYwH!$9+tX!wiSaBtFNN zOMKP*U|grTX?_7QnSlaWmqIRsPZ4~|!Bh~F@7n;TmZJ8}uLEBX*#PS{Sa+hdo#1yt zwh`m;?SZuuOgESwFh{@)f)VjN`Z}Il>x$==$Hn7pC7s5ItTb1__#kt^7g&igg3mHo zOG$Tf%U~@-nHAtSfN6mK9nziLZD3m9vlDU`Fx}Ed>M(HrA+9#;0vHH zMbt9rMc~Vzm&3mT`UdcI(CfiBK;H&_7nn9Md%$#p=_WnP*8`>>)+68tp?`#SendL; z3qE=@#&I;aHf}WcE{=5S#b}(5ux7#<9L+gj3T7FYBKVYpsUSVew*gE&mHpo5j?|{#KV)6r>(7WK-1)pxj_Q12>N^bKJcz%R7e?*?!12T!*ER)!( zA>)$Jqa^eQ)(r68ByNe9c#kg^{8I4ckQ>0%L*E8{7xY#{wNg}$uLDdcWEc1@@ZIE3 z`A1YAto_922aZ4=g!Ln|>LcQ56yPb6d3K3pZn;cGFQ98k7csO>CZjLO9OZ$(2iA1> zr$f(x^d_TsQdmpDltWgagbI|f0VULt z?(x;b+JLB?C}$U#HZXhO*$JkbtaN@sAB6r9`tlL!lmU3kG2Cm1B;9R}!E79Z{*t~u zkWMl);Dt34)?D~6BfZ*J1icK_3RpLQX@I^BdMm7LB(r>b!0aEx+3p6@1E!y(lRHRJ z`M%>|9NN+$GvFG_QR7I`c|De+yx=pz=Yn4by$E_4NhdcvmfIgD&+UN4Ogepw3FTLfzi0oGbrYhkSe-vGG{)}7GXAoqajfd76l-KeDpd_PH=C&YMs$HB<)n78AZ8Am$h znPiqP7kUBl*9Ah*mw_*WUIxAb%my&EacE2E7gX9_ahWWA>6~j;{wy zKk0V{`oRy9PHh7(Qn^f-%B_;A9OX(yJHez|$$Td1)MhY2L@fhT1g4Cla(oqFHh`&v z-T=7`%ueWSkbA&%BdP~_KlDM=ejJRLz-@C)Kzk-2ZzQvPLGT68mq8Z6S_ZuWas!wK z=-Z(0L^*9>_JHY_z@HSl!SsOX12YKbI2bXJedI*WxoaZVK8_^KK=7Gha=`?_ECW*n zrW8yW#pVafCUOodVBG*~ot4ZtfZqnDWg=fmcS7HZs5V&lfY}eG8%z(FLFleY+_rSc z%t^eS7eHSISplYwq{r6)rVVlr$*TF?;CrC=lfFGL2&-!{mzfD!FqwN%FqvDsjC7B$ zjQFbgWne16YyeYdCHjTfZD4l7vklCC$S&~R(EF)`w!k2CIfZrC6ka!6q(A7(oWd>1 zB}pq1_+{XWz?8unhF$@^b_&;C2fYEZ4N+}~+5^x1q|?d+YY&(~_zc3wm4zhzpdh|k>#>rPl(VQoWf z8)El^?}q;%q&S7oapx4YG?j-DO_**DQFw4nb3pa3!pE9|1$W8;Zp&=4tfLh zHpmV{b%E~&(@*;LzyO#*FfI>j_i*iAl9X)^*IvL(pumIChtD$jl#!L@KlloG)`6)5 z(*R~C^fpAbA*u@{cf&dWeGt|`SYgmn;BXFAHC&ShpoE}PD=%ZShSg<-7#UkBL$YXht;(>uj^xozOPh{+6e zL+?k_0GL5AB7-v~Gf-Cs*X1QWGmr^AMEdr?vJBKqI@JrN0@gan2>cu1(*U2H;9E(b z7ifdt1-%=3A8PC;#^W1A)F7gSms{fUavRdUY|Zp?y_uxv`<8((gRFq8BRI#r|cp*uM^PKQYe)`k_l7^B!NP7|c!gaW6t7>8}UicS5#;=_mP2z?qGf&qm3l z=lHx}LXc&%Q48dLVx9?fk@Wav7W>OA_Akg{pAhMEHGv+JGZ2QXo5P+vA^YJuK+@w& z&qg1!*}p6s{etYs=9cUyKHt|5Yj7^wHkW-$p_f6A%*E)CB+t2AT0iO3uX*fQ09iMW zt^4P(bwBAjKAFSTbVx5r>U&P7n2}eO!=7~{X_kU-$>DlCAiLNa=tq>C&m}nXnemcN zCCo<)neo-l=ep`h&++YtXFucsJe^$roap2t10?Axlgs{Pr04i{=5opVA!Qz0(@Ey| z>hhT13E4$VW}qL|0qEk?PO&yG{ZuX|{Z#fZJ(b&2b}C1OiShXAphr&SnXsRjd|wy% zK6nm*7pHNQJdMkdr*S!6lJqys)3}@v^fKr>NzeDm1t@<3m*2ObQ~W3|d^-C_Ae}|b zdlzwy!9|_o)4WoW*{6oVN5FTSp;h;+fiu{%CBS!REdjnW?10_@y$@34Gw*>6=CfxI zdMRW$pG&BP9)aEhpB6A3kbRJ1F~^Fa~w=CxDwSwsY(*dRrdLMMLggwO)_H>pYKO}Q}!6lud;?ywoR>;y|r+DSm zNRU6{v_f_T*>eE8w}A2=2p8-TzgZF{J;&ElfHo9x$sN!;p!Y%VgFb*LaVFYuCfaZ& z&)x`0s^v^BbAY7B=PYIES=uQkofcZkqZ}dW;dEa#}ua`p@_ z=UO_z^g%jjb7{e|;d3^8&PGm1r?x?lKyM+REMEttIEQubIqV;VUV6@Ps<9Tb4^pgP z##zDTd!Pp)Ln}C{6nYre2$)uq9$yFeK1lHmF2MsCgp7QH+u!;PE}@I$<4XpPvVE@Zxz7$>&_Qmo{$D~0S^$ypMsSb89XtJoTZUJAVwdM)%?=q=D& zptr8#_H?b{_6)2-OGwZ0Ip4$@^-b3MzS$|RIn8r!r+EIfAW8Rv+H<*Ik#o7fEzk#` zd(LA%2w4hQ3)uqMdLCxf`S5`(g$$q1-?X-z&%Nk?>^q-((Fa`=VXhXj)hXh?(s;ml zz<9v~!34pSLbew1d>bI^3X)u}Q_PIFm>F*|e~t@*sV(jl7cA%?*|MOI*FW?rI zLUvui_Z5B62S~p&ATDI9b0O;<=%p8O+iD?OF67p>KyM|V>jE8MI>2;+=>yXTX5d23 zzgUevu0|hMV?|oc-xqkmc)@tVgjVyoghO{X|*VJ*p9 z7PgS=Ug*7u>k3`O<%cffyQVPoF!abpTylhTkFSe7DSM>TnSL?LzKeNgI+t(>o=Z3b z-b=U~?fHN}<<6uZ7+M zy#;y)^bY8KklstVRbj{oNjh6E>lC9;_g==m2wleQFC}L6>0#)#q<`=9zRS3FaXHKI z!|N2=vx6uDz9Xy5^R3ijPhoAb%R2E4W_I6`f+i zA}{nH>5)Y(S8yLYAid>Wa1wHA5=)(BaveJx;GVeNq41#1^#`@jsq zDz4^QyjSlL$-!Fak*m4J7U*5X-{$MOn$Mj9@Xk7BoOLwTKF>PDu4Dfo^is$$e8S{I z*A6fd__RQ8g|!tWbb)uSVNcIBC=GfLdMRWrWD8{9H5lbeWTuka?13JxM4O?v5>J1Z zuEhBcrVG|S=mW40kTu`uT+30RYuP_^E&GSTM8HId$@jH_=^`dM*mrHG_~9Ae>o_WW z9Y=+)Lm#i>)hPnL6?`l4`MwVDUEuq!<2H-y(emq&!|OTLdp+6!CPWNFP-W$-)8@S9Mm=LTH@Dbwa z9`XjxWGnbC@Llll13v&>Y~YeTklqbkehc&t$UaC>4IjuB$PUOpNO2>qkU_{&$UaE% zEm$Fgkflc6#BHm+iLEV=o{g*rAxj}^AzL6ln_z`3g{*~af$V_ngDm|vd)7j>Kz2a( zL3(cHdV@E!Pbp*{q^M!W0~v%Yh3tbAn_-0vLY6|-LbgD9ZegDwWGQ4VWD8{9EnKg- z73Dy-Kz2a(L5f;fAzL6jAp0Oi9juT+$Wq8YNO2pikU_{&$d=o<-VW$}hOcMOTF4g2 z4#+;p(g>`OEs!0MeUPF7wLrE&c0l$)iY>501|dr!TOd0i`ydzSpXxv9cxSZp2j>)5 z$Q5=y?t0d>%dKMbV=s)oCU$e|cVmAL`(o_WxLf1yj~j?P5tkA_Ietd`{P;`a%i^z$ zzd8QR_@q%qqb?tH<*4dWkx>tfawU``)Fo_9_*+6uVs>J4;**I76F*6uI677y4X zU66Ep(sz^IN%|})Ciy$bZOK1P7GtK2$sDtMOx>7A#vB~;r!fb|&L4NvxF^SbI&MnJ zxhWe{7L1QgU6>k5{Z49o>IKw5Ib@1#PW&vPyF%3-ib3Oe|z%Y z$pe!=pRCgENqZ~pPibQ6#HlN%zCHE+X@k>ZPPy=ur%t)bv(57Z&+j~?=})HbPnXl@ zO|O{#%jq9a&&=4B@rR5rGTh#L@1@@Ryg&86?vnkojq5?2MEd^JXlc zQ8eT78Q+?5+l)tN{A9-d8L!RApuHt$3VN>z?bMq`d;gwFyY8Mwdt>qLaSQ2}-=~X2 zv50ngJ3}P#@7qOz7)!gerO@x#Cy0y1WZF4xD(#Nup&igNXuHEd#?K&m)2J0BuOGFF zRJ!N*Pm`}SI<`Hu$Jv(q3$pw_xg(9Ei z63T7?Wp^1pL$I7Oyn@h5aV9-8u#9%eTQ1J0X9zAJW;Mx+uq)ka%JmviPUvbHfonvG zsG?EWK>OBhqLH|n_NS{Ok9u*1_zrp9g}vu0#67gv+`Y87-2D{QMEl4+Nc+car~Tp{ zrv2fX#SOGq+y>D?`@Vgjo=s?_k{%P^7XMd!UjiRjapc|a%}6trWSy2zNq)Y-#zsD5 zEE_8ZS(5Dm9Y&Jzfo(C;JV}E`Gh$|BTgHIo*ai~FLI?>-APWgefDj;ALLeb5gpiPM zgb*M=fDmxF!m_y!7V!74>VC(JMz&!6<=bDrHB5DPb#--hb$4}jzo&jT;x80##+_}q z;EuLiaW~uT;QURo4}Yt$pYK__3wNr02Y0F6gC3YR?i;wVx%zm556u1+;Aba($Byq? zNcgfj_X3s_Q2gpC1UD8Eyrl2}z!@B0$?)%!schLC;&aN>hXC(C@iD-|)1Cm_n?t#e z*KBTNV?aD<=_b%OfcHyj4i? z_Hu&JN(X<+R2}!DZkaO<@W~k^fGK?Dlmk;R^LW5dRxAdT{3TCW`%{alEwYrvyE({G zZhCjFTN@+Gjx6P-ahH`+oicT0n*1X%mrtz)jf9u7CL2yX4VddsAf2x`q1}#m&E0Ir zWxX#~gn*Iq%U+nAw-cB-48Jw^GMnDbNA{pwa;vP2}8nSKC^eI`3LL?#8=E$c__kv}yY1eLZ8`UH0vHbc??1O?Ui%8jYhFKklZ)P3^cx zmA>a8ZSn=M%7x-WKpl1&H{)Rq%R+1jmbwsjD;xMc(E4G&aIZYpWTc1{8&q)i6K1k}Y0@bim3+Eif91Jtpe zOataJtqhn?0P0vz%E5mQpkLgkRRDiGppM&brvvk6%>d>vfI8Ne8KA5I^ozf0GlBmb zppKhnX8|)_pAAetppF%04k*tA^os)hIN%Ebb*w$d1HTE-FZ%Vlz@H1KV+EQA{1!mJ zi0dZ+p8(XwS@_E^{M9v}UnKPfzz+cGVwX4(n5*0H~F9YUIKpksTH89`CO@4*qEXzX8;7OKcn9Yv?6iypBG>_bt!^I&O+R z3-Gt_0d(d# zss4H3Cj#PYWcsy$ll6ZEoTXn6SgC&raGCyP&{PAW75Y~JSLinZw&-62JVXCF;F93vieIZNT07-GIaTcLDe5-vhiv|98NT>-Pg*p+5k4rT!q`r}Q5I zeqR4E;I;b0fM3ub1^kNsQ^2q4KLfl?|2g0{^rry7ss94-Zv9!n@9Mtc0j2t^OZ?f7JgI@K5^h0pHdC2>8DKXTZby zUjef{e+Tq?{tIxN=RLq8&tbq~kEX#Qc|3q+o-Dvw9v|Rr&p5#2Jh_0!d&UDU^b`Ot z@)Q9s_mlvh>?s9Y<(UL{s%Hvdy=NNW8c#Xk>7MC;XLx1+ws~d&ZuZOpJj-)Dpy`J1AfA@0`PLrO2BJ99|8PV&nbXk_S6D? z)l&y}o2LQr8=kd*_j>|>4|q-o{IRDA@L^92;Lkm006yhu1N@a|1K_Vc8v$SQYzBP8 za~9z5J=*~P=;;7_&l3bZ?CAo`@|u7?Zx3LBHw;+h-2phw+Xq)Qy9@9n?;v2c_dIPH?9Y67{!6t6z-8K6z(y?qxJf%5@NBIKuu~(NZmk8dS33jn z9IXv7qHO?-Y8wIjwatKW?JU5gwheHn)&aO%3t~s{23_@>20M=JHb9 zk2@bWa-zNwaI$_D;8Z;bSf&pG;?7s>Le2rK#z>wI8#&Q4AN!CR&qlyip0fZ?^#lP| zdjPBp?;v-rh1J*K)P@B*4#ks{y~@ zT>*HVcO~E#LDM9@g4`x?BXXO>E#6ZAZ$)mCxSeyq>7`xJ9pJM8pOBf4H7O_SB*45Z zd>>mBXYB%q#2sMOfHSjJ0M174MsXZ+H;L200edIVY!;h9vsr8h z&1P{nXf}&Z&}_kd=rxEC~A#eJaJCJupSyZ9Ywwu?W2X1n+s zXts-YK(ifpOH|QLID0;JU<=s`EWskTSxjo_*TQEt9(0I<+EAN$b>pp1!$pp1z!P{u?BC}Y9^WlYQj zWehjp%*U>E2`J;ZKc*V+WZ!v!HK2@(RiI3W)yPeVdgLa=X}=9o8@_g|_0>!o(7)_#B-p$Ks*o13&hKyyg(cR5YSpxiGiLAhTn0_A?O41aI8Un~dZesMA=4~SLBJs?g+?g6m|d=7|p z$UPuVxVwJWu2wXbO}Xus9|tay$ii7y)E90z3+I(XRXhQ zW$nXlaSvy`nDus+H#;wTdiIUk4`)B0eK>oj?_^)IZ@Vw)yV!TF?^fTPzI%O#e5L+h z`fnZg?Qx&Xxh3bdoa1v>=iZuKbQa8 z{M>@21>Y<9VZo%r<%NO5p2FRQj}*R8xT)yeqQRoOi|#LasVJ{FRJ^D7isGA!zg_%( zaaPIrl1U}!mRvXC@d-0auPeQ`^oi1EOV62j;lzh0_D;HX(*2X3os>VhV)E?C(a8rU zKQj5r$!|>_H>GsSvMGI2u9)(tDSM`UdfHc}-9GKUX^&5PVcMZ-f0$NZ)?T)&?4xC0 zFMFsgzx=H7{_-o!A1q&5(NNJ*aY4n!6+fwXq2j%Y(&_7_4^RK}^y{XdV5~6K87;;( zW5BrHxZ8NZm^-6-M&pb#XIwwy+cSPTTr|6V@s zb;c2fO5Kc2!WuCdtKT%-{V@%`{WP5AO%tc%*N9&ee$CjewO|jl9=|hi64;8pP8-e! z+wt3gRr^f*XvN-y)p;|1Td+Q#h2K{Ewqcdtj$a4X19Q9sv$q5L=pg245Hm1{xfP_@#7bH!-iAg5S|P&~ zDm+z%s}YjkRtp2CFao!x$aK9*uTgaCRCtD z!X6d&D*9eUA6EEtRJcQh5f%2SFsj0s3j0+US7B0xJ5{(_g?m)E7a{3&uabL6rH52{ zpGxmj>HVtQK^1;Xg_o-E6Dqu1g`ZU6r&Rc96<)2v&#CYWD!fjGUqnc9eNokWgG%3^ z(qB<@H>&VvrN5h@KON<6R&=*0{4Gkaw<`ME6~EgR-8U8f4u!u%;qO%VyHxlcmH!=; ze~-f7tMKBm+2ag}~TrJqpg zCy_>R@w969(@GyttNdpa{uzaTM&X}R_~#Vni=GO24VnZ>jWKD*d)fzpc{0Q|aHS^zT*p2ZjHG zO8-fv|D@7?QR%;^^xstaZz}zcO24Dh@2d2>D*e7nzpv6lll>?(Y2S2})>Yc8(q5I$ zR_Sb&_N%mCrE^p|N2T*rI!~qZk*0n>UxgQ{{0mk7u)=>-g$Gpr0hND|N?)YXzgOWx zUCJL*;oU0yt_ts0;R7n1;*swQrC+Pf9M3$&-QJG6JQ z_i0N!2N6H0RrzkyV&iVpmgmmXtMj6wI`2XJ;1lG%hV*Ot5`5zZe6*H=+qCY2D}i5* z-@kaO^S+GmHvFFSRQaC6?W;rF0;YT}h*{^XTek50Kw>z#U=_Er3zo%)z3IPFRN zp2P1Dey`$pn^s%CGV6x&$2=!iJb~Xc_`QnX17iC02gQlgA4j|!;nN78$M0qQUc~Qp z{GP+_GI8(h$H9ljrl?tKCL5vyeP%qEjKx=lIy$NriJDa_Iy#mt>Oib6Vg}=@I;|vS zFupx@X4u@-7)~T9lToX>Iy&mZiT+4%ur3lzBo;3r2F!{gm0eT;ak9`=6lsq&$CBah z!Ma!^Vs<6Nv1nayFxq2=h?FUa!$~O|IF(+VM1pqdGRb#iJe&-6M$9Adm!y?lmT1*1 zT6#N{GnP1WtUWds&UT^2D^g^a$#mf*wmm-BYC?Zq=IX&SgOLG~bt`IG&A!-9D`D#q z${W#nix+1=E&-C1h}I%DHu0I%u8J5yD~rxnkt#&i3`DyS1nOda{lPdXno?>k$<+F| z847m=la$lanK0u!iR_F4b08JdmJD|708MQ?9voaBi$xG`4M%%c4|I2%@wWb8ln`bx z)Dn#hs$^R%o^0u-VT&O{WqIr%0)ecNL@B4<6ntGI7By2a0jq)(tW(?(2y7knn(%Hj z)E3@jrsR(@<{EaI(d4>dG!!x8QdH8Nj5nM+5R8PAm)8}CV^2)r(s=xsBTRK3+=m89A1MmvqPa?<6o@S_MY8o4!pM#)dDcNC&p z(nJ(vD-aEtyDdSi7O6A^q&KvR`-uk_60K$;yobi3g=h@!83aBU?}1v9W*?37>W+?G z@nAni`#L(-grmVoWDuzyGl>*c4j@7&uWAR$({OsYD_fj3;HB zC(jbWle~SPA9DvUmMeQj0xKJsGG3ObejYtPkgh8=UY3aT46c}FlTC5DDNWA$U^ot8 z(hIl+;vq%SL@hO>Q?vS)K<5#*z@uc35Eu0ZEG?v$p}hJqPx4@VkR*fwFheOQdq6uQ zD06-)7X6Jbv-*39Fn3bY>2st;7}_OOjO4+Gxk<)4L4$$tBL)a?JRm5f(Mn^WN*d5A z_ZXtZB}hf};b2cR zmPm%X0wED{Cn&dWAWnL33PywQRoZ*wSe-yuvntZj5srqF;b6o@_9E{HwN<)SteW;! zm9?Ra)B&1QoEeDjjO{R6qC^-Bg*u!TU?EMKYO0Djdkv%IrWPEvjFlmWnTwf~(H0ws zcez$l3r|W4B&4X0fL3neh`BA%ktG77tTE!K{tPHaD@#gnnNv$;Zj@@c8%3pB&2!+b z%2nBFlu~%6EX5^L7I9l2kHM9}+Am#SOOAB3Tc_!HZjGkrDcy}gM`2hZv929vh(~-| zFKmg7TDFGqj1%PzmMw zH|*|WJ0KdOA<0s#HhaQR6^{qQ3CqZ{gQ)PXy_cv>I2$qYn-cx81o^u{X@G{R+=qy@ zW|C5C;;}x3sZFp;sq1HHw=eoM;>9?}y9BYEyMv-Rf#!rEIGy>aZdwP2~@96*S7&I}%L;5iILad%YPk zdq5@{LSdXvtd7Tav6^@t#bUm=qXXjz`L&4z=1^p?$xH@A!DO&DnT&@!2dE^bRw!hK z9E>%%l#s0$E@9Z!kp%2*fV(RTT^|_;ac9)ULReNIFie?K){bo;6KAJHAh8-}2i=X~ z9WG?O**VbD!}}at-sXWwBo&j^c890c==N|DJ0+WgbVp-xR#H>2s~5fLn3x;K!#COnvs1uisHRJ2T z=nfaYDLB|^Qn8J_DQLEdieqY4!|tRRO~5KU%q>-5T{O>xDb1J}h<3BZWP3h>st(&n zGj3U2G&2qZlfp-hltg0;XC^5*R`syF-Qk`AdFU}xx_UFw6%X@*;$+sx%mkV#mmvpj z4NIw62VZY?2QfX;(ayS~W~x&Hn_n~DAB)gPZo{;Q_DDMtcSxiYACP`AJOx)4MnxM; zZ*s5|Zhpck!X~I8V$w*URo9he=?TY6JLyma6CEqJi$Kmm)?up|3GU{YD<9__umy5j zsfo%_upNyKIvHvqV0<#%8K$ErCwKKAOdF0P)mn#@h?hCh z&VCG=QyH^1qqMIQv54FW!++&dOi7Z!336AjjK`ojI!KWzbb%Gcrp=Di>f-X6z|Hoc zNG2>;7Go6|ac(O2dG^xX1T$)_70y6TRI2S>`UXrMw~o00Z4Fjcj$TM^+*E$5iy&Y_ zyLP}Z#JcDRQ7u#Uk)r6pF%{NqI<10FlaQWo+W?MIlP%pqxT01btf!M}Co=4HrC8j5 z;I$?a?6F!bH?Ek+7Q%9ylue_Y_Lv-(0#0HB)&Q{@-5MWkUsj7aQ;INp;;z=b4x*$M54HXN(9#MfghZlf^MWFA&$P@wXTB!>t^vN9KFwQY%zK+%^o_!9G!yO zPZZM43^8>}M248doW|fnKSxYX!25C%&E_sfMpYPgDjR*P4Y#~cB;&zog4RgblYu_& z7COyGe{+C|&0&IYP2s3e<4tssuCXBUnV)^=58vMP2w=2BaQR#S{WW60u5#pYk)WmKVB3Dw*ZStVgPeTO!drXzIGZGBxWCpC<7hvFxEWnT9MzE3f)+R?} zIL^OIN;aCVG){b7sV;lkV62j^lp`I2OKP%9K^hM9;jEgLWHS}7oO3r8mJX)^A-lUA zKBpznmD0dl{(XDQ>HtTiQS7rcx3manF625*!#|%YmPW?I(XKc)O|Tu0TgLRH7R+- z*Rq%*fTPy9$%ky}@t5ebBCsz~3VA3c;H6-}QHel;?59d#p~Rko54PE?5aJ zRlzz6i$XDL&y39<8V7txO&vmHFu=CQ;LNZZMaI*My;ci@nOwDGLHnvza5P*G*^d=p zo(RX9w=-^>>F0hlRMU>s0_g^>LP);PF_WSFzsC?~=SNkv)!{e`Nh9tK#}n>eQq~xw zBuImSpM?X`s{$A*v`8S*glDr9)+Vf8b&fl2l;u9LOA+h04xOwLRyIur_n{QLD6B?! z%7}BUmN?DpU^wca@ESdD?_pWUB}u^hA%kJpnyDvUPta02vXTeyk&9YKbk4K056oh; zqGSq=fdno#7zgg1NkYKAQ8ieb6#UVFxl7^T%Ba{*ev-%5gHB1vEe7EcOdUN8#VUq_ z#Z1OdY`(Aoq&DnuAW}B)YNfTCAlKJ~b>O+qjL>EXTZM2Rc_Inq;N&40 z#}+?9ONuugnb|rvBS)avZY{$O;qvgO-r9{RpMpqy7kFw$c1xgN)|HhvWKz`es$- zhp*^pgY8&y{y>eg2i!4{z!`KOf*l6lhbbio-%(1s2cVm@X4R68jxPCPkZ292J*8!9 z%Z{RoxgMhPqJmY*d92Pf&WjhaoIL!-dw155R?pzEp@sj+Maci6hwn!;lGYk5w>V=U zm1-HC+&W99=i06{h>q>Bb)h%)SU8+1QdB+jh66^A$?5U8!2SgVNiG~As=#^^kSbRw zI~pNMIua&kYiQ>t1`=3~D56f|IL@0o?9z6c&E{@WishZU&q@TXeDXEh6tuY$&pS{# zKi8m8K2vtfrBF;oGI2zCf?_9?S&L`N0w?N#YNMxI(T3ethvC5vi9msRaDvDFcukP~ zb&lZWQ-yLKb)>!kD>n3pupp-)aXcQ!`E*YjT8^XIXDVA&{WsN{$t1^-b3{sKMbSff|!WmM@Di|%JG}2@Yg=Hj2 zubs!+q z#Bs@^F4!N0j|L*_k6;Airj5ZPkFEiFv}$A2+l6)-U1rD8RnU>0?6Ua65#)^_*Fj?u zK59c>KWZfV1=o<{^!Ffv0RAR5guh+gEe!nSX%K&nY5)_%U!)rNYt|V4DwXmpk*dXC zu_i$o2PVidr|ii>H~e1pk@%liDP3F|arjp$WkZ2oXcfEnWi5`|)24%t_ofexUBVQT*=$JWqakDaQ>V*MlR z)iGJsj%CCDQLEaqY504`uE+ne>(u|a=DUsQ|9$IlOqxHe9lPFlH~$~AmK+lm4E@)! zQ^7xSbvP!CFQ-mR!2RE2ZyRc{w#AVe6r!mOFp5n_FEF$Pl62OFh_(w+n0VT;k)f}{ zwuH)>jJ5VyQDA8+MgQJBWA2m-_uSfa?f$9Jb58BrC_IMHyoRRvvjB=pDVm>U=vqD? z5CMikUup5suvQ`{yaZvEA&Q5tqP+5aDxy=gcpI3NVks;|q|wMz<7J!o7k%<`DdJ%HQwGCq9o`@=^ck6M&&! zMrS!}2&sC|L0X+GJBJ2MiO4Q3?nOXqct(X_s^vROsaq+j*in+GFQ>*Lyv`Qpd0;>Y zrLiy;;q8j;Ar-!^!nah2eAbm}gWnlMJp8CK>IcnRs0rPhL)Sa|^gGo_O=>!$-y*~up^c+f&IYm+$f3I-jGVu!gdbSW zE;1}876px#5%e_f%O+1P)JdvgtpcBsr+{q1-K>TpC^@x?!a_7!>78lE629Wz`;g-8Ju$)#z|;+EiE zO~^ky*UF|y4yM1V3?_2;e2Xve#Oi#IphNSsgr1+DkG_ZO7$LSG6PV)yP`Qv)HKD*m zDvIaS@FJjms;`J-DbiU2=KIHNl7=2712lYzR@{$p=s|>%0Z?*MKBX1!g@V`yqE#@3 z#X~PpS;Wfn43EM9nPVsXei<#ZBW2?auS4n2wNri!RL%jd6)W@W*}9%x=EbekWnP~Y zWVi-hpCbnrX13tbRD(PSM`=MZXxOE)k7FzbdXy_rZ;i_SPs71q#DqN2+A7ki553NzWPK<-nsfH4ry2VCg zSPwmd3~x4i3_}6-f_X~j#Xc`avP6QA>Qf|!F^+nSq_Xq5D25`_P4;CeW)1;oOz>r) zhBRamDnd!(pvq6Ngi&0$1T!dM2C39VKBzCHJTQurm60pRAh6D;`GZoo(7lYQk-Y*U zs0lhu@ktoW=&51MLb)(OpM;+W{_d4>^h7=l0cS~t7{$X^$p7^AZZpc*K^6W*c=Z6k@qG?(72LWpe5$=-r=>**bmbjY5Tl zeJYc7otjMx(zUD?7haS2>lvR#^kmhz6uA_xxCW&I@2(zSWw5LFj}z3pG~Aet?)B+q zI>y6@Ht7?6*@R4MD!CoQUj~*KaZI4~JO*j9Zej^}jz}M*K)HsNW|XMhf9wfy4C~f# zJI}rfF-`WiERNowWk+hYM4zO39OH?)$qvXgK8YmFM8?yyB4d>GJ1dJKxx9$pgcxQL zDT|g7>QhTG1*{D#g@v6IA;&)HtwhZC<&lbq{lwN9@jUZ@oFI{`Vick^i|L>To?BQm z;7$;lDDgE6)g5Y%!7FfLG)PdzY+o(}prwTCOQ}L(vCh-V3KDiMU_9AOPzmP9Me}KW zl=GX?7TZjcD;cbzB}a^pv<3GFy9>ZPgOwsp8;y#sBp!7D^#l!uz0hfeD3SenDUiq` z^ULnxaIGTeNRcF>!Hj}5x$~$`ly2ar`&a|qba1%|1a^N(M~Yf8jmVT{?G`8=mXjve zcCseYUWX8})a2Zf)MvY;CZsJj+SW& zeiUEx}&qmD&W6D+F!{fUsNoDZ%%w%?t;p!P%?N~1{j;-;VJTe zZ#KfL9C+1J7+qdGO#c(QoYCc;?Bae%2+v)rL$;gE37m4QwCqU0-5UDYIQX5i^+h;^Y?go=nTbr!5Ql!l1caN6TK~c;@1!KmsIc$;$qeLTyUk4v)geeA( zhVn@QglwgEs~U%BUqv00baxCPA)hlJ$(-^yd>s+0V1q(%#F|=ic&7?nL}M*Q-U)K_ zrIHcPi>*rDLWE?Z4ZUq62x-fN)z*(4PZlvIP0Bex4tprAkoHem@VViJ<38y;pNEL# zIOj=6=8aH-cTvQKeH%hcDwWZ)@__+Yuj_59qB^a7Oq4P?uXq*ykIirK~1RqYm}0OL^2-=MA%4eKjy zt0<~mH0@*~mz_a7!xf>1aUvabsXj?U!eH(agh=oQDS@`p2Ae${b-*I`&e-2e8mRyx zA}RJWc_E}wzLeC>DqoJ9{n#pXsMurH7yGDADXf#{=9@0|S|2v7POHXN$W5hco9FX! z#~fWzOMN*yTnTrr=|b6Uup`IQmS7CMAn8=cWRykr7ENJcjY(^J#_pfook{nPJa<%z zgBuuo7=4X;4P9vCtsSsNgNp30>`OKB5=^`EL;<$&hu(8HR5NMS{@My}A0VZq+esDj#szz`gBX@OG8 zC_n-P2fnmX!u(`q3gxlinryH z1A>}hsPUg(z;3ghhN@^UPpTsClnfVnQ`*pe-_*3eQeE|dd&=rtTNj9^MzR=oa%4ma zQ^>m&H7rR~sYfX`77<&ItO9D$4csCc@v3oB3+%0t7RZi#4-use3(p5pH$undzHxr6 zRA5Z!#m+iMs~0U`wAdk}Q$boxiiYz*Mn<33GR$Rsa*68xx~6+_G~Mr`b(jhO$txxz z@~EE|E;AtzNX~DzTL{Soujz4S!#7IfwG*H;-40Nqo2_!F&Mh704Avrje2RQj!YyE}ZTTH8ZYD=>B4ol!;FPA>afg~6 z^mIU-yp-sC9z#}xr{Z0Tgvjqv@p2Ldy+>MB!`Br}n?E|asoaC)5L&TPX+P8>DoZM| zA5yp20rNTSlbD#aAC{+Fw)4r`^AfFG4S2HAJk(Pn?0`tGAy*A-$_F#FpUQU}Hi6KruXF4| zUwNutBv)t$OSUZsr%JS<;X=$Htli`?!b`C8B{{W;7J82Nhc0Ew>3rI5E~&?zt|ayFAhAh~q!H^$0M6KG z_U;po5~MtY^jb>T=jRxnET$?!4PDpNvMbMobH=AD=0xqXcEnQF>$bA?vmiXp_vLY% zhmeZX5ZaKcBX`;wLYp0u4>*K2b4L^nyEu@d3Rx1K_)cX z)k`CYLQ5%cu~KljOq+q7pH*C1ytLxd_{rkZ{8{AEHl&g(Gr{D_P;hOoIbs!;lOwIT zoF}rloGCC)G~B48{r*SJD>?k=i7%Ytzx|Ys3yYr0IeF+he5GA@hlKbPUWCim0g!HO zt6eO-IOL`O>ff6C`#1jcyh+bJvUc^BJ*6kVnRDLFn|*a({Mn7M(^nPVc>VFkKYVrV zr+2*f@uy#3&i~l{;acW}DjCXQtzmzxWGXGy+*mdpd z>))=R_xb4Wp<;sG2&DJ=)*z0Hr0_OiQk2zmVB({NQM}GKm^rf@CHvA!PG~@h0ifON zCaeW2jKBVIBmJkLYI><~YBLw0KZ^?E{X;iR4!yESe~q+Tlv%Z96v@hLLzCz)nA}XV zH!$byO^_-gCJ@VR(S}yWQ7`?;S3*<}@>~{@UTF;BqmA^3C7pn{g-3XQbolUv=sEPM zMu0lhJ4E0x{&}*?v-E8IpN|;*%JBGQ8?TD=jtd^A4E>nEql}_=Tw-wmW zYsodmbE`s~9!1Ev%EBDV+BBkBPeMJE`Z;-UX= zz0^=V^!qY;sGEZNkBM$FX@ZE59ucP;;)7R#kp;*bE}dwwX`vHI;M7wJ`PL_!@*Bw8 z;TZWn_EScTqhf5`iicovD7cu-r$iBx*D1T)TeIfWJ{xg+fyAM+R&K49{u$Q$SQbV-W_6OJ6C5(y{SPMu9OxVq z&z02?JG&~ZROncJHHc;&f6B+@1L7e!|0Ou(Y{ecwp!)lIul3yj@&M;)GBV7e=^&p z3@Rv3$#B{%pVh%+;0XyCjuH(Jejp%uk{BRz=Znz;1H~uEe6$9gW1mB|k!CGP2jNzZ0PiB5H<`jLD< zs64e&kaBj)Uc)n2+dP<=8!JmCyFPIvKHx?7WmtEZ@A6;JH!oKO4dymMB$DPT=;EWW_lfQy|5!JLGts;sJ9TDeGwDor4Y z#Qa4omUdT%x|gl!UfQ{&d-MW|}|ie<=Lw!FG?ad5E^Q#DcAVhiKC z0!D~BO^nBuKqZC@%#)Qn1ZC}ztta*319S(_Q@`C?BHar(L`-#ZVuMD#o_EF8HB8eTRZW{SjDeesnu`yh=roR3rnzhW|yG&FbtrA=uV%;euzXH1iiW%iBAY-CHv(uvj@al}TBr4!Q`WoqA8Ix!QUkxlE+#Foqh-TGoh z<%n+^&sVk`tBf-u7l=-D~dMNjDN&N6X0Nd4`H;$jb?On2S?d+l@H7Di?A7SBY`a6lgaZ@x?@Z z!7wL>?zQ6&VHtC~<{3*CEm@qp&CSVKZ^rw={FO7(GNz*0IcW6YD=?Um*uch3Y0_7QZ_zg6UG+-snduxH$RaB$#MPU0+w@u(H9Hh%NPhvZdU(5XC$2HU0{T;la<$u zFThv;lJ&TN+OZIOd3;nLl7p6pAvd?xk&bCdKhO>8S1L*nW>;^lk43Rt5>DiFtS+bI>|`wF-wU^kHO!zT-&sr8lz@^{;C%+FI7MZ>()? zz&te8x3-)asBfq@X4bYLJ#&GvG0?uQWkb6Giq_iZ_RU7i8l$#(vvGQ$xqgAsuxWj3 zLtC5C(wY-!THhFG04~s6*SMiR(7e`IjdIN`7{UPzWH4=SF{nbtD$sy(YmBCb*1C1z zT)R5Z7--+TAZJaWy_tBfX=ycTjrFyy?SZ-tjkT@D`VFn?TiO~>eLdJV2b$NkqLzlH zhUWH4)C!!@a3&H)+q&AuMye{Ob_1kuCHaiHmi3!k18di{8|zvc>l=Vv-2lmIS2s4u zs?eyq#@ayB0;9gRsdg<%*J`wYOKT31N$HG@>lz3}_0{74y7oXzGc}{GrMbNoN!YBG z)^@w-#z0%c0;9Gy&_)Vb)7sLsAcxe665tLdDA(K|xsa+^L3WRTgcP;`jkaVl>Kkes z!3*8f%uTe2D|4jXNL>5!=5J(w+jGgA#h8Lw)x6S7Iu7fYW{h%+Fz`A_Uz5Wo0lvadNc6o z@tylVdK^jd-lzKS5L(lEGHhSQZ);o^TiYom|G^gGz*30g@zWA;KsGpeL{Uh<^{=(9 zzU{ne8|FRw;J*bft-3n!s>A|4Ad8_k9BfhfKszK}j_nfVNC6l@~iHA)WdhF_?T z6c@U_ev6aG%mpg@L!APnZplf@gpzaIBT7!_V(HNNxqsO?=i@C;yl}}M*Q34GzjG*V zSgF)-tBXzue7h%JABi-+cX4M1Z$u5uicC7FD@c&6CHpJq7|_K9>_N%9ROT|IQ{#c_dnk!PsGD( zwbu?$;aoh@Md)Z=BI^-o;7WJft-(`wx`>o6^yM<$N9xdlct~tQS@{kEy+J@X3nhSG2Tnb>fym%% zQ{ya;d?$f!CNhDKWw=6>u1Xzwg)3dzYF&n!$Z)q2J?1xXbELfJHNjV}Qv2z~*o|U6 z^s)f4)!gqO97 zda4H%zM;bUqnl|R{bsr-mb8_AO)cq6%3$$46Flja1&3D^Zfm07Qv68w?P4lqpx$?!b@zZzgnPChZKshz{h36)H$i);`XGIh99@tMwvy#) zQDtaE5htr%l#*KgF!D9B-q(Y73^L2NKAaZgC_Tfd8cpB(#6q++l~=mf9i7jI&R0P9 z-J%*bcZ+36btBy=mLOb?+>?;A9RGET#Z0#XbX7>NU|K4<45@0ASPUIt>x_TPdEC{a upXuU7dQpX5(lIcjQ+wZ$L-suv{$FrxHPEl)+9M(M;&k_a|NZ}`f&T-@`t)M} literal 0 HcmV?d00001 diff --git a/Assets/Packages/ObservableCollections.3.3.4/lib/netstandard2.1/ObservableCollections.dll.meta b/Assets/Packages/ObservableCollections.3.3.4/lib/netstandard2.1/ObservableCollections.dll.meta new file mode 100644 index 00000000..d01371d2 --- /dev/null +++ b/Assets/Packages/ObservableCollections.3.3.4/lib/netstandard2.1/ObservableCollections.dll.meta @@ -0,0 +1,29 @@ +fileFormatVersion: 2 +guid: 90dea806f7b90666bb04fa32d2d62877 +labels: +- NuGetForUnity +PluginImporter: + externalObjects: {} + serializedVersion: 3 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + Any: + enabled: 1 + settings: {} + Editor: + enabled: 0 + settings: + DefaultValueInitialized: true + WindowsStoreApps: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/ObservableCollections.3.3.4/lib/netstandard2.1/ObservableCollections.xml b/Assets/Packages/ObservableCollections.3.3.4/lib/netstandard2.1/ObservableCollections.xml new file mode 100644 index 00000000..1a95725f --- /dev/null +++ b/Assets/Packages/ObservableCollections.3.3.4/lib/netstandard2.1/ObservableCollections.xml @@ -0,0 +1,391 @@ + + + + ObservableCollections + + + + NOTE: when replace successfully, list has been sorted. + + + + ReadOnly cloned collection. + + + + + Contract: + IsSingleItem ? (NewItem, OldItem) : (NewItems, OldItems) + Action.Add + NewItem, NewItems, NewStartingIndex + Action.Remove + OldItem, OldItems, OldStartingIndex + Action.Replace + NewItem, NewItems, OldItem, OldItems, (NewStartingIndex, OldStartingIndex = samevalue) + Action.Move + NewStartingIndex, OldStartingIndex + Action.Reset + SortOperation(IsClear, IsReverse, Comparer) + + + + + Create faster, compact INotifyCollectionChanged view, however it does not support ***Range. + + + + + Create faster, compact INotifyCollectionChanged view, however it does not support ***Range. + + + + + similar as AsSpan but modify size to create fixed-size span. + + + + + An attribute that allows parameters to receive the expression of other parameters. + + + + + Initializes a new instance of the class. + + The condition parameter value. + + + + Gets the parameter name the expression is retrieved from. + + + + + Initialize the attribute to refer to the method on the type. + + The type of the builder to use to construct the collection. + The name of the method on the builder to use to construct the collection. + + must refer to a static method that accepts a single parameter of + type and returns an instance of the collection being built containing + a copy of the data from that span. In future releases of .NET, additional patterns may be supported. + + + + + Gets the type of the builder to use to construct the collection. + + + + + Gets the name of the method on the builder to use to construct the collection. + + + This should match the metadata name of the target method. + For example, this might be ".ctor" if targeting the type's constructor. + + + + + Indicates that compiler support for a particular feature is required for the location where this attribute is applied. + + + + + Creates a new instance of the type. + + The name of the feature to indicate. + + + + The name of the compiler feature. + + + + + If true, the compiler can choose to allow access to the location where this attribute is applied if it does not understand . + + + + + The used for the ref structs C# feature. + + + + + The used for the required members C# feature. + + + + + Indicates which arguments to a method involving an interpolated string handler should be passed to that handler. + + + + + Initializes a new instance of the class. + + The name of the argument that should be passed to the handler. + may be used as the name of the receiver in an instance method. + + + + Initializes a new instance of the class. + + The names of the arguments that should be passed to the handler. + may be used as the name of the receiver in an instance method. + + + + Gets the names of the arguments that should be passed to the handler. + + may be used as the name of the receiver in an instance method. + + + + Indicates the attributed type is to be used as an interpolated string handler. + + + + + Reserved to be used by the compiler for tracking metadata. + This class should not be used by developers in source code. + + + + + Used to indicate to the compiler that a method should be called + in its containing module's initializer. + + + When one or more valid methods + with this attribute are found in a compilation, the compiler will + emit a module initializer which calls each of the attributed methods. + + Certain requirements are imposed on any method targeted with this attribute: + - The method must be `static`. + - The method must be an ordinary member method, as opposed to a property accessor, constructor, local function, etc. + - The method must be parameterless. + - The method must return `void`. + - The method must not be generic or be contained in a generic type. + - The method's effective accessibility must be `internal` or `public`. + + The specification for module initializers in the .NET runtime can be found here: + https://github.com/dotnet/runtime/blob/main/docs/design/specs/Ecma-335-Augments.md#module-initializer + + + + + Specifies that a type has required members or that a member is required. + + + + + Reserved for use by a compiler for tracking metadata. + This attribute should not be used by developers in source code. + + + + + Used to indicate to the compiler that the .locals init flag should not be set in method headers. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class with the specified message. + + An optional message associated with this attribute instance. + + + + Returns the optional message associated with this attribute instance. + + + + + Returns the optional URL associated with this attribute instance. + + + + + Indicates that an API is experimental and it may change in the future. + + + This attribute allows call sites to be flagged with a diagnostic that indicates that an experimental + feature is used. Authors can use this attribute to ship preview features in their assemblies. + + + + + Initializes a new instance of the class, + specifying the ID that the compiler will use when reporting a use of the API the attribute applies to. + + The ID that the compiler will use when reporting a use of the API the attribute applies to. + + + + Gets the ID that the compiler will use when reporting a use of the API the attribute applies to. + + The unique diagnostic ID. + + The diagnostic ID is shown in build output for warnings and errors. + This property represents the unique ID that can be used to suppress the warnings or errors, if needed. + + + + + Gets or sets the URL for corresponding documentation. + The API accepts a format string instead of an actual URL, creating a generic URL that includes the diagnostic ID. + + The format string that represents a URL to corresponding documentation. + An example format string is https://contoso.com/obsoletion-warnings/{0}. + + + + Specifies that the method or property will ensure that the listed field and property members have not-null values. + + + + + Initializes the attribute with a field or property member. + + The field or property member that is promised to be not-null. + + + + Initializes the attribute with the list of field and property members. + + The list of field and property members that are promised to be not-null. + + + + Gets field or property member names. + + + + + Specifies that the method or property will ensure that the listed field and property + members have not-null values when returning with the specified return value condition. + + + + + Initializes the attribute with the specified return value condition and a field or property member. + + The return value condition. If the method returns this value, the associated parameter will not be null. + The field or property member that is promised to be not-null. + + + + Initializes the attribute with the specified return value condition and list of field and property members. + + The return value condition. If the method returns this value, the associated parameter will not be null. + The list of field and property members that are promised to be not-null. + + + + Gets the return value condition. + + + + + Gets field or property member names. + + + + + Specifies that this constructor sets all required members for the current type, + and callers do not need to set any required members themselves. + + + + + Specifies the syntax used in a string. + + + + + Initializes the with the identifier of the syntax used. + + The syntax identifier. + + + Initializes the with the identifier of the syntax used. + The syntax identifier. + Optional arguments associated with the specific syntax employed. + + + Gets the identifier of the syntax used. + + + Optional arguments associated with the specific syntax employed. + + + The syntax identifier for strings containing composite formats for string formatting. + + + The syntax identifier for strings containing date format specifiers. + + + The syntax identifier for strings containing date and time format specifiers. + + + The syntax identifier for strings containing format specifiers. + + + The syntax identifier for strings containing format specifiers. + + + The syntax identifier for strings containing JavaScript Object Notation (JSON). + + + The syntax identifier for strings containing numeric format specifiers. + + + The syntax identifier for strings containing regular expressions. + + + The syntax identifier for strings containing time format specifiers. + + + The syntax identifier for strings containing format specifiers. + + + The syntax identifier for strings containing URIs. + + + The syntax identifier for strings containing XML. + + + + Used to indicate a byref escapes and is not scoped. + + + + There are several cases where the C# compiler treats a as implicitly + - where the compiler does not allow the to escape the method. + + + For example: + + for instance methods. + parameters that refer to types. + parameters. + + + + This attribute is used in those instances where the should be allowed to escape. + + + Applying this attribute, in any form, has impact on consumers of the applicable API. It is necessary for + API authors to understand the lifetime implications of applying this attribute and how it may impact their users. + + + + + diff --git a/Assets/Packages/ObservableCollections.3.3.4/lib/netstandard2.1/ObservableCollections.xml.meta b/Assets/Packages/ObservableCollections.3.3.4/lib/netstandard2.1/ObservableCollections.xml.meta new file mode 100644 index 00000000..62b3d3f3 --- /dev/null +++ b/Assets/Packages/ObservableCollections.3.3.4/lib/netstandard2.1/ObservableCollections.xml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 17427504764fe822596c97b72d726ff1 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/ObservableCollections.R3.3.3.4.meta b/Assets/Packages/ObservableCollections.R3.3.3.4.meta new file mode 100644 index 00000000..d448d23d --- /dev/null +++ b/Assets/Packages/ObservableCollections.R3.3.3.4.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 226b83199320c9a30aa1815ecdd2a97a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/ObservableCollections.R3.3.3.4/.signature.p7s b/Assets/Packages/ObservableCollections.R3.3.3.4/.signature.p7s new file mode 100644 index 0000000000000000000000000000000000000000..41fbc4e380876859194123642b002cce054d2548 GIT binary patch literal 12920 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 G5Bwk7L+R)M literal 0 HcmV?d00001 diff --git a/Assets/Packages/ObservableCollections.R3.3.3.4/Icon.png b/Assets/Packages/ObservableCollections.R3.3.3.4/Icon.png new file mode 100644 index 00000000..f24b53ea --- /dev/null +++ b/Assets/Packages/ObservableCollections.R3.3.3.4/Icon.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c1cc0d07828b8dba364f5e29b2f3d1ac6aa0c0ded4d1a97e028981609355b2c8 +size 3185 diff --git a/Assets/Packages/ObservableCollections.R3.3.3.4/Icon.png.meta b/Assets/Packages/ObservableCollections.R3.3.3.4/Icon.png.meta new file mode 100644 index 00000000..8f7b7252 --- /dev/null +++ b/Assets/Packages/ObservableCollections.R3.3.3.4/Icon.png.meta @@ -0,0 +1,117 @@ +fileFormatVersion: 2 +guid: ba61743f03f401928a99cfc06a1ae7a7 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/ObservableCollections.R3.3.3.4/ObservableCollections.R3.nuspec b/Assets/Packages/ObservableCollections.R3.3.3.4/ObservableCollections.R3.nuspec new file mode 100644 index 00000000..cf1cc03a --- /dev/null +++ b/Assets/Packages/ObservableCollections.R3.3.3.4/ObservableCollections.R3.nuspec @@ -0,0 +1,34 @@ + + + + ObservableCollections.R3 + 3.3.4 + Cysharp + MIT + https://licenses.nuget.org/MIT + Icon.png + https://github.com/Cysharp/ObservableCollections + R3 Extensions of ObservableCollections. + © Cysharp, Inc. + collection + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Assets/Packages/ObservableCollections.R3.3.3.4/ObservableCollections.R3.nuspec.meta b/Assets/Packages/ObservableCollections.R3.3.3.4/ObservableCollections.R3.nuspec.meta new file mode 100644 index 00000000..f4038e8d --- /dev/null +++ b/Assets/Packages/ObservableCollections.R3.3.3.4/ObservableCollections.R3.nuspec.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 504671a66d59e61658af89a0ce25a7ca +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/ObservableCollections.R3.3.3.4/lib.meta b/Assets/Packages/ObservableCollections.R3.3.3.4/lib.meta new file mode 100644 index 00000000..12af1670 --- /dev/null +++ b/Assets/Packages/ObservableCollections.R3.3.3.4/lib.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c021741bbd2a58a1abd4852f601b4ad7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/ObservableCollections.R3.3.3.4/lib/netstandard2.1.meta b/Assets/Packages/ObservableCollections.R3.3.3.4/lib/netstandard2.1.meta new file mode 100644 index 00000000..2779104e --- /dev/null +++ b/Assets/Packages/ObservableCollections.R3.3.3.4/lib/netstandard2.1.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ccb1af4f2fcee53ceba5d53f299e92ba +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/ObservableCollections.R3.3.3.4/lib/netstandard2.1/ObservableCollections.R3.dll b/Assets/Packages/ObservableCollections.R3.3.3.4/lib/netstandard2.1/ObservableCollections.R3.dll new file mode 100644 index 0000000000000000000000000000000000000000..93949b00ef2156903ecb09a175aced285f2e7879 GIT binary patch literal 48640 zcmeIb3w)H-wKl%rd1of~`xOE@;i3UTxC9X_YC;kq%B@L2R4RmIfM}AznSfx328mWJ zwJH`b#TEpuT5YvrYg=uhpw(87MQqg`+Q!1E+H!i6UQX-f|Ey>4_nmi=P}}c2{eI{F z{k|w`ul208_g;JL>+JW50n_en3*nWujbMMg&I7*q7(I;G}Y zwtBSdlD|5&^{Y{#G;6X_`+y{Cbm|eLA^hvdKc%wC`?TKzi2wWvSxN!_^al#=mUJ3E!{OI=2v`WMZjwq)#1Is>us~6d!V3r)4tad7eBKUEz&gkY_vr z0v+25zr8;prB+r%W6>6X^sOIE5dXf0f1aNzbXP?*+#Z3U_^OnSfqI&PORAKb?Fxp; zmAK+ZeDkS*ssgjWPpK55ATPm3#AOEB-|Jw1Cq2zqR;X0!_{((aEBf@=aA$0xy|V{S z`NyAQaC@LAed*C+O!~(=g~c<$6M?&(G$8UQpWQ3cx@GtEWQajLKSdO4QXLSdEvHK3*)vV`PMYOZPiBbfF}%Ii zQ$+PluXfv>11ofgcG`bmPp;&OhlXmuMv+-W2@S0rpD%X{%ag(iKRpZ)=*dqkh$_EE zQGke25UreoDzcRAFDxsPk#ZgaTMP#Mg5pxeRzwDz3;-&m2gu}2_Ngk2K@6yz*l^gU z2BYBDMM}V*5saSc^1fi%2w>$Y!P7&Lk<^~vW0=TkkjG0|b5RzCUydD}Xcvrw|P`uG`@pw;$;Ko~;G&tVUu6Vr9apEmZ8MDXZEd|&NQDVHM2%C}e##fy$N-?F^aGip`eEy-`e7Q%`iOoA4?XVB zLe8Q4;c>Szj4X^zZ$H@4m%LgGHLq6B3amZxUc#(O9shwD)DnTgy(D4Ky_7InBpC6| z`d1~gluBONTw zX9ov-WzyJqXJZgaXTu%o>{&>pvjt_}k^vxk0%QQtQaYOq{2r>m-*JOHVBVdJ;y$9k zJ5i=y=W;A(wM2`~L(ZZ5dz{zo{8O4GEQeJv8#Fy(5%2if5ZsQJXm~qbFOm`xqRSFG zUIG*Ecu0Dc6sC-&7Ggag)bCP-&G+9znvC(XMd(Wgbgg+bZWA z8$Gc9>bz#+v}a=4(G^~;v?W2i$*YwX4&7V#d(9*OLz^A;nn`@pbA2BaV&y6E9IW&v z@d;?%zPk(p=X4+1E=)9u1X$01X;i`@qhV=80;~s)IL(2> z6Izusa)c?PmwN5F4L-_`$4{F*6lq2QF+qfR~TGewY%vs@wsO25?}3Z zddx%LB!i2yb~jx%hrzhFb~k4=GxV|O;Ovn&-V!#E)uOGD(NPM{oT=AE)3f-`4mP8q z4YF=ck1nU^5=h5g=ZK&9FqSkO~XOuQtAO>Bn{;o^BCO8Q^xQ z*x%D3wuq;Q3@{l0R7ily47I*baDy};zSz9~nfOLvo-m&i;=4|?1LJ!oKsUZo2yT4E z{lW2-HpJtL4NtG7!jv(4JibzZ&2S{fSBkJ16>ogScPGB$sgAFlqhpW|-!4f4J?oK3 zm<45+$p8>N0Wtt+DRCz=RNOB*RopkAtiLm^r7SGn{24IBuR_j*E_mEMyI~M*6m7f< z1{|L^C2IA`cr`$`gSsK$6s5AQIQ=F}8B4|S8FSxrj*3@e zGuXNlCza_*BGuT8IXe;OXN^leHbd`p?hdqDqT+O}#DJZP^OUq$cQpDbwi%N2V64Ys zu5p-a9j4b|wm8gn4ztx^ux+G{Kf`DHW7j*-4G!~3hq=*VZgQBL9p+OGv&~^X?J&1E z%x8pQ9k)6Vb^-1F?GCeDn57tjcYwhV{;VWrI|NlP3@xqz`d1ry7=z`*iuNy_dK z6qW+QQoz{f1QW}hU|@N#BxRo$6qW+QQoz_31QW|$U|_jhlCt{*g{6S76fm|&FtOYV z2A20rQuctLuoMuM0>-{5m{>jt29^&=QueT*uoMuM0>-{1m{>jn29}RXQubv*VJRRi z1&n<~FtL0L3@kBYVEI)+VJRRi1&lo*m{{%u1Is5RDf^nBuoMuM0>-{BSQM5|fq~^W zBnk9cm@ozeOr>U?+A(t1car4vHgOHd=?BWpOd8QdxFAJKv)VGdtR`-$$o{Y#2;VT3xJUI`;z#3ejtf& z><39Nf{DEZ((`X1$S+CcWsoep?1xCo%YA`s4ucsxvFMCzUIFt#@Caz^Rl#~i<13qp zi{+jlfgQiW*Uc()IX@QdW>J*ACR#ZJzb=@+=M6~$JwK5Ihv0u_8t6I7G}!Y~q~nJ^ z17Cltwf1Mo^AT(92}C0>_zWyQ{R3xU@tFryEF#{M=YYeov}tIwgj2CJndjJ<0}tK_ zr(%i7&}IpzVhLDAu6>GA@z0@k*ZzJ8jIFJ(!12eNHzf{{l^|xte-o^)TbdpD1&H%; zTEo)J1b7UsrCA9FU=2$%65vK!i`(&Y@ioqFB1~C7bT~7~UUHju(>WK5pLRFBZ3c^T zaokf|`+H3A6$Teq?QS|u+&LGEuXZ;*E)#p_TrAGo-E^6Fk@-+3-rC*tc?noJC&!A* zELDyViRXuSEw-);uEhIF>ap2G=N=|rkOW1%#!5vG+k} z`GJ`Ddp?xJ-9H6{rGPO!6490x7+CrwaraLFVJTqD24R_gG4b~VBysmo0bwa%EC|B= zGf7PF@Jy0GPl_b&{z+Z8sE|!mu~ZONkS2!yo^(mdG6Y2+1car4u}r~+-0QNSLDp;0mr0^uWdqBCmh=K}#Qqi(B zT}e)WwWJg+%Sg%fm7R%vQ@?2HEUH{?cbA#k<|ft_%ti6>=Hvu**@LPywImI$Zanf0gxX^QJhQDsZqnF^RWEtN>eCV@mIOJ*Ig z)WWn0<8oC}+>3NycRW{eJcIN^Qm)c&yky*%A|-uQ$G5n06dv^ea9Xd&4P#I#)lL&* z9m=yj`G!fp>CC4`fgWkhcedo45zjYM*z0tC!z&B%_<{LkJjOl-5}73ix{h;&{k&s4 z(%#HbTZ{FiJlofO9<^AH?S)gj9pxSsr zb;5qlDQL7Qs7?xk({tQ{%H~SOd18H!&kkhz%j&`V?8pU3dM*U~o*G z0BNe*=c&P>=|#cemE(NflE>G*0F-4^pt^;L5X#8+9J0OTlJuhG}f^g=)^9& z`{PK<&-8USAhkC)f|fPK*(G3OOF<$Rfnb0wLm~rgvJ9|`Azb+-%zq3p$&WcKd66XM zbH>>vP)>c$xOFK6p0}<^@TsWM0DSs`Wo9j7G!0H@r1Lprrm z3jB@TEzv2ioZ{WkYCkAWwT0nZuZUbj`Uru@jX*+2LX(wn|1jN_94m23K5)|=} zToZe6i-lCyq?TOU-W-MCS()t3F#=tnSJuG2vi0C{v3yJJl-$4v1=j-22_#|d!oojf zjX8c+$>mJfpx2Vm7$=Gp>)=4w+!7GG)P%@AZd~h?;;|V>w73~;0po;84@d^< zI>3>wVyp*spRgt$H-qb$PY)v9nap>Ce5GzI2H)5fZR=bU6N}edmHG?H8@;4a{Sbl71~z)`l6s6d)epJ91oG_m z$SN_$58SjaI{m(slq?8;wJKF10I=uc-^KVRYtbwKU&Oym@bFTVAG?r*GE-=Aw$Pi>{rP!nX})Mrrg!B8)rVQ< zDfzMQwYC{<-!4Fy4UxAnI`P`#OZ zJSkIsUY!?6RpWqXs@Dq71O60ScZDsvssjsiQ`Jd-LqV!a4oKcZsS9&6)l-&Oo|93O zpQ;YBOpEoNrY`32|U zYEP-FNja*lY~@RTJiiY8gWiC2FCr$AjDu|TAX;1p-cM;4+E9nyM0V(oWOn7$K@+6( zb@X8!c%0Lqn@h_i84-~3S!RliJxDz)Gee1S zP^*;%T@j^n)kR$&`f-z*sy0)4meMqJ6QxHeO;W355esP9p_2+}30 zPQ5_sOR!vpcRFz{gfF+C4VU9hu$L$;hAyfuR4-F{7P_m|LWL`ESpJ9IP;i}Etd3Ax z0O@Acpnjx!F)lVj3gi9n*BF<(+1h35CzSqDC~>(={et;EK$-WbX7wvdUx9R=YEdUB zy@*mCR$+yEC)8I7>8omu!UYqgCn0?kxBa+jg4B*08q^gES4xn4kS8H?LuC7$LO@i*{s4uEw3fD%EiedRQU7Z-7)lX&Izz@F}W@QZAP08z2p%v=Fu50;$BZOS9FVF}1^xMpCymNns_s zR)r{CiBcYbG>TFMO8GLRF_f-ADPMzh2BlZfhHpbEqx1mU@LfpbDcy=TJO`9no4#_`9{C!YM9SqzNwA7aa_k#YP;SUG0lARjg3e5NjevF!*cSmrH`c2+3^vl8A z`6;F9nY5IYcpNSPUz#g)U>wBeMU0c_jL*x6kEQkoUP*Ck|3AZf+Z(TOjJh}Vl@w{$ zpVQ*)DoMB0jqr22+7OtYQiy$e61)|pl=h{tZ_kR`-<&0u_37GD_%CN^elfN~tOLb= z&Xb*gnJc}9xw6icjzYTDl|*-oD+Q46URRP*?suhZNc*&u{8(xaUdnsgNXfY(9WqjO zE>>Ulk|&?7jv8HNT955l$6ehoa{TJAMmHnv9h}X4r3ybcB)^Utf+|%@Xi+xKA;XOB z56~s4QX@T))8tQ58QZ`DtOH0Xx!5%wJ?J`nPp-2xJX>4IO&Q*_l@};X6TUVX2f%Ks(eUOu_3P$Oet;=rm=cPZ2>Vy1sA zUY9BTi*`38i`Qi;&*;SKajL{f;`KN+hLZMryjn*|dp%wqq$FPV+Y{8wM(Tt#QN3aE ziPw{qZ>-e*oD#1mso|8w>)+Xv)qG0Y>nUoLmf&?(My1-MrDXAXy4qqS@p`(t*+@&_ z_1WrnBelTmv(@K}v<gpzL2O!XH^x9TJ_FQ$Xk){@(mOEG7Xe8;QdFoapNgvHqJ1OZF)vLED=@!+iRq`>HEgI#& zKy@0avv`z$zS>Ahw`iey%1F|ph3bctq(xKxi`3Y0PK)N|E><;KO76>R@;9o*MrtY& z=@UlUktWjRMw0$(R96`(hf<%BUddYx%iFYsD9y-dQadT>7A;Y4Q_?M3qFx#Av}m1w zsrs3bI*Zr&m#McY=@wn0{%Ry?(IqN(g5;AH_4+SW<0;8ba!2}dwVaZ!ZS-x@V-qFCxtzDCWbB=sHeuT}3*lKR3KZR)?Yl-yW+ zlYND*`d}_(tdWRFH(}R`;Na; zJz=CyNbA%yCZEj4sQRUmBrZ|)0VVPCeSb_%p2XTQb}z~8QWt26UT;vBXo+5LRI7|6 zUT;)a7)iX|q+&)AuQ#d9l(g4ZtLG_cudh}~lchfKdU&84_p(~*goN`vB^}*s)f^*< z*Vn4cD2dkMrwiA zpH#<;v<?yYJ&r5);X!7FpOtDQ!g7Q88Uhq~WLZ)fk$y<2_R zNTX7}k-JlU-AIpQAI|-P+Ha(53g5}SPrYEI<#|@#{puAXU7l8$_eJ&ZMye>9l=rYY zZlpJYi}D^-zcJF6lUni~Q-3zn=Ym(~eO0MSX~PaREqG_%lPbkXZ)ZQ1_ms*t(x}uo z^1h`?jPywMU-Q1L#u(|E!jk+0YNC;r=be>*NKH4=siJ62{tIfJk=_X2 zl>ee?FwzadFXX?hE;Z7eoNwj7qFRmAm-<@%k5mUGnT?Ua>uM{dL#iq5Wd2XoogUr4 zt4Cd3px~$KfJgT;^_r_IEa+Fi_UPVJ)-;KPlzC>sF;zfG*LPe^aCI{ZeyPs)=-yIG zTwQ&^JF3m2`<1%Z)m>6>LT&fx{!=~V>ed$gRz2g<{Z1WmbypYsLA~Yb4h7y-{<9oE zw-@|LokmIgYzzKbO>=c$DEKcm&!hXRy3EymwctG!_2}MLH@doK3qDjkUER`jW#vql z`hIDxO0#gwAUvWJ_k&$Nj-^_A@g{^`HEu{rvmP^2 zXYmaw8P?O3^c>5w=FbpIy(VW_t(0Vr?M%tGEZ#;-eH*fJtYS*KzI>~dlCCe`dW(|G z={E`rtapvn38~0>-{h0Eb(nRoTp^qKhFQxfNqxr(hFgzPlKPGYO00vFWQ6>xV5Ie$ zM|Ya_pRVqMf{Ov=>xO06PFlCQ9Ev^Bw_8)H?wx{AUxtR)`ZnbsAqZcgDi>spU) zy!BaES6@(WJ>=0%w7%o&E-9E~9r5TUTkp8KwFOhH_dU8wD{q!~Eq-2IaF%r@C27N= z;B>3j)om}BX(jt0)Lx?J65g|n<1UER5v=UVSm(xa!!GkR2dl~r=C6QzfO)m9m$ zLrO+gt+ntxM|U__XDz3sb@QyBxVrxe)?06Tbn~s|^PPO9NeirYN;=uy(9pY(BS zuSeHp9d>nBCM~g!dUVUI_g&rHNf%qmRZ@d4bGbE{l0@m-NuRJj=FzRRHo3aDlA5hP zkFM4Fs;e8G9JY>nbZyquYK0#ub3yXuRuv_wuf4FtdcoCQm)vQ+>d{?kT{hdv_x0qc z)kaC@TW{S@>9*qc^R6r0U_I_yT55y!4N6<_DX}_bgLT-|y_Is6b(E5nqSCLnrqwz% z6sLAuRg|>u8taIwTabFK)$h?=XLZ&&`L0XdYHgyV^W9)Q;Of4f`bq0?kM3scXRhu< z>Zh!CJi1$~)HzO>!_z)v6;RS;-fo@i>gv+ATk|}+9o7x5t}E?M>o$+>9_u@~@AW9pu_E>LG(y@NPde_ZosRyjTQPQz~z{;B^ zWopYWTBlQzez)-4>r6`8Ql5fY>giOW4`d4sr3sw}>QiqK_Yu+Bw+lskut4aUL7^J| zVxI7~5${DgKBW=OYkUuGM=d4P#}dRtK_a<=Je(uX*?z&gW)};xi~i{HHGP`3JOdwm z>bvyB%Rhh;EOjW)2Rggh=a%rVC~XaVv(>$WJp5ntb4|9-E$wB-XF4Ka4-tWXw)~fi zBo5ON4PBZO^E(l9^!q;)PqD0orBBU4E?eO(H#{}Vhlc_62Y4G)|7>Y1{`RKWvu*n3ApcrF2S?zat=F-Sdp@|# ze+02`7cb*n+H2t^TIl~wqy+QM=_BoD3+I&A^M3@Uy%k1c4iURhbGYk|nK6X7@5 zFYu|#K1=SI_gQjBF8FQW4o_`-_EytPbxFyd6j$3l`f1Gt4N3Kz@m;3hS|lL)5+Ic(?q z#am7C`=%sYm8$1ra>^OiGjIrEk?Z#napBk%A) zIV>vz(`Y%(CvN~u^T`_k(`Y}9_S1ZFyF1M%_qfxLs}}Zh$2!X=w|}*y^GTaXmy@=V zwv%>|ZYJ#mJrvjmdNgnc=}ywUq>qs9BYm3m5b2AguaX`GT@*YH+7>)PdXn@#pS-E? zo=@IdXyW+y+keh`D41>wo^A`?N<1I<;ou13BZzkq9|Qcqg5|`^iT4qo2D~(B7V%lc z?;u_aygq3@@%hB}5^n;2Wzuru%ZcwJ-U|Hgq;}%%#19eg0{-o!&BQkof0cM2@VAn- z5#MIZ8w1;@Jx=W%&<;=DY0KLZJBgnpz8Cm{RE3q!aNL%= ziWA0C-o`j;?}z1KCAX9(ZJ7%v?ep+9#z|Y=$vA1tTsUdVTsUdVTsUdVTsUdV4dh8% zZWsN2nG1fu%mu$+=0ZA=bRy|Q^8NDWM802ob{g9sop zAa!YX5V?cMP9R-rdx`AzOV92l{s{1g)AkYHrxDisH1Jo`4*BKnkVAfXJLHgG?toqd zZUcEHtt9<{6*sB0eNaTjrdXGM~R=bewcc7#w_9|h}Q;Wg}=j= zcWdSwTxP@x+P_Derhvq)DIhU?k9bo+Vz@jYEA#SzUYVuFR+i8dkchPhBx3CWiC8-P zUz(n7NmQEx68UnhVBw4|+K-@i1hvzE=VfjtejM}5Qtw!=CzWTuXv@r+1BZO8#@&HkR2Jh`_hLz>f>QpLqv8d=IsRGx`Ey z;x7T8&syd)*G@$8So&V(T~2&C@kfa7Bi>HDo%qwhvoa15-%NZn@fU%Q$#_-!K)jFm zHuBrZ-$DKk@;k}zB)^yZQTEg$e(9;bmduO2)IQBQ@-*g1d)CvKBO9`gqb@t;Y0QzE zvtIQtPTG-mA|P|*L_pq)I)QhrtD)6%WG%EO>D5upEZmFvCC(>M0zQ3_&%~R-Te358 z=Gy_8U1|;JM%4$pS?vbxRS)7F zoF%@mfHsqMkZvNqp7b`-yGidSeH_%MzTw-4T+a}Bmh>>`Pf6b){UfPmOZge31*D~< z6G46IEL+N%Nu-YS4XBJa{tS>m}xYFlD&TjHl}ZB>w?l zrOgrA^i%sL`8UZQgXPg-$5`Vr+P`BBSLYYMOB>54(X)M9)gOl0K8aPHk5M9CN;=vn zQ5_BZaL#C0{t>)bj`2y9#sQyMT*+McWj7%B#WK(u=BiX3`c~ zw$QSLmMyew12VHXM*A&3@p%jFx58%9@U67zqYr)5Zl~oQmbQnb?SbXe;d^Mgmo`t( zW`{^TdCbn?JnZGN%v5@huSBo-B0`g=|O4_QhS8jH;Er3 zevJ6L#4WsKgK-;RdjsN0UVtqnKAQMwAcu1*iB}P?29Gw9uL*ofJvO|CmNm3&q~%I# zn^EQk#VxRTc6bYIT7VoI9;3}xB3qejJCR*LDvNgoB&xfC%q-qRn?1<&yWvmJW%klG{E_Osq&#E%hwm$(YDr9rkdC@snZ#X3eLL~UtMyd52s9^4=~imDLi_&k?bPlfzMFIpwR@<2g4+GW50DaZzR5wNHb{* z@fh)5B3nqe65mdI7m?khdw^e1`~>m+L=KQ1OqQq~gtoZk2(|sm(o_A^zDarvHqQ<} z2AeS@@6yIf;TTSlGV@Z{79ypjqk&H?sU%)Sq?)vbcq8$ZM4Cxkh{uTc64^q!m2^At zUF3I@?t%U6k|&7oCvt%FAn=cu93kGHG74jd zNJ$^)1;yKGvx_#nXtM`4&ko-M?dFmvsNGNeAdt4=BSiXPk24kc!#VE~QEBWQ(!4ab zhkzVp!NVgN&l`g*RBC?zG3E~IH zA0huH`FF`%8T2GWJSin#NxqtVBl%|XG4fl;ZzsQt{BF`Gi0mhSfb9%jUm!1(v_sU zNOxz+XxUHxK-O@zzPO+KyTB`pRW{?3O+T|`ri6%8k*^}ZlKe{Yz2tkzZ$YlZIlIX3 z&X$s&U^)9~v!D0@+8iO?PrRS_o3vLsQhOEYO444^U8MVS#Gn1-`^oo{SNN?1%;;RU zntX_S73oSME6KO!4p%!$dWrNB*+qJYct3fS$8t!=llGIULOJ26LY6>2M81lA75Uo2;p&?uD~YTm(po5I zpw6{pi5#MRKW+Mns3O)|B=!1>#NJ;d_8}r;ilqE1@+(PO zY12xZULt+8IYj&r@#93s6iW72a33zAvM;XAvNv=|LpL+;2$jsohf;HN&RI~m%mJEsRi9p z(nq8Z`~}5_i1^3RW}G0kps*p*N8}I@|9IMrrwu4#-S9(1j+2h5pnZklwV<#k z-AjBgasMR2YbS|iE%>(LKG5%#93pavh<~ymwUcQB9yUY{5jjM}KZQ0^XagQLpgT$q z5jjMpb}F?~shuiq?*o5d$syv0i2Ez0?fy!R?Mm8%Z!11d{y6zn_7=O@zsDa=c`D`d z^dF`FDgDbC`!X6c|2;E^C$&j<=OP);#8dEG7T=?QC#)&BjY-4JRJtm_Gg@p4c;1?e zC$#yvrz*npT6tC*GS6zq;DwfbsW;#)xcpq9xoJXYrQHmAl=z=WpUe3SkZ%-h2OS<1 zn{kCgZz9r_En3a*EE4=11$TkYF1{CZSN859`8CAvC4IR_ET? zt&EmG&U*mJief2wSN3B=@@t6S3+h8$Y`p)Gf_Kg2cNPQS(-Aoz;*$cJg?RZ8xeU-; zNEV`(1-=lN4^OxAKu<$7EkvyV{3yiHr^X_#K0NI%0UZx3AMXB62c3i`+ZOIaOTkaU zt)Qi*g8I}fQYeoPVh?bp8)mYx8TnLU8BwhU5h8`KK!2l$3QPfoj%+%o)6li zs$qW(s1LtWUIV@t)TeI7_ZnEZ(UWhv*oJR4u+*nPedrb%%AY^(E`O)(@?>tUp|5-w+Ar8|*nhQ4{ImS?{WtsX^#8#Bs{fb%lt514oWPpE=0IOyTi}ks&cNQl zBY}N^rvtA9ejWH@;KM*lFfTYVcxG@)@MFQc;ELeJ;B~=m!QH_F!54z>1b-jQNg9?k zGpRbMIjJq_rli}FzMS;6q}P&uo|KfFn_Q7xliZoSF?mn&qseb1|1CK;Wo*ivl*K8V zQyxnBPRjEsKTYwcW~RE*m1&o!?MT~|wm@rjI%j8A2JA>)e~FK7HLu`*W8#yGD*U)SPW zZt5^n=U~Lo#VDPJ+y8ou&6O~cx&qru^kbUT);ejC`4q zS0bPIyHfog>y=WgjJ!(Sj+m-frS}hmr3v@(v^KF!EiZ_;Zhu?=gPwH1bX(f8NNSH}Wnc z?=tdzM!wI;dyTx;$PXC#0V6+XPZ@|TVLn2{fYEOC9zwBxG= z|EjUO(9&^UVA4e<{kTaRO}fOS7n$^8lU{1lPndKCQiH{S>4*Ya*7&CQ?s_Yb4~b^+Q|COuD@^65MI~b+!99d^>tUSZ|;(c6Y5G3;x09W zH-w|HMANu-L1e?JR1M({t!xN4w=U{z-_*FSxf7K%MxtGd)`g?Z(qPEdY&n?vq1r9D zQ$W00phFqgw1=Cc&@GH~wXNP1H#d=~+Ys*Tn%CUf+8!3G`kF|`y5=Z(2}yff7xK7} zu7KLVS6+2=P3#ozG=yW}F6iQppnvH^0_gQFL1DUVa1M$3U{nWuC>(A$@K9ls9zn(R zon4hvRpX}4mbKAHXWP}`)}?LXt7J${^+db2js4Xe-J~@G?Q6V4ad2_YARVk}2w#p# zfFVAVN{`*4{cuM1RJF9ZeSNrT{W^?nuW3B~PM^+h#)uxO9zE6vYdFpa!)Aa(qsp`V;CbnpCb6a!>Z@rl~3WxGfM&MKxcgh`sh}M9L6YLVk zp0@z+C>vZMhtgD4Kd{Lt+nvVoAsBZH`Zyf#uUG|sFWS?qm4k+7LXTEDi%F#{x@y*f zNbCCc@Oh^!x?+BPP2IxAIyEa6Ss!f)pSM`e!r%CA3AeX%b!v)S5$+`DuFxXkZ-C44 zvOXHcdcyH8XsbIhAT_~(7C0O03U^d^+cP)Z8IHEKs5RlP6}4^6YdRybuC|u?R@Lei zOsmjYYQ<1-p&}l=cm-4p48DM-#CRSLXa!=8d=RL%1C^m$jTSTVb~)YB}!_lTq>xL+p(`~RXi`rXHp=k)ikn7lyAo zg{D5XXq_AZn%f6gwj??PxFFoI3P+K_)>!=3cVH?Gp+Z4(BGHcKuEDu5Cc2t84#w*{ zTf;-ZX#XiRXyPd}SilFBU%hT!xU*GthPz^2IEpk!J!6i$+|YB#tj7wAhO__1r>d(Q zIL;l#pxN&z^tz|!hH);6t*wc)hB+t9h*TYVWUBhww%EEzOwNp|I>sH=*f|3frY>aPMcw!kkeu<)`m6BU13$%+J+}cdF2BWb{Ky)N%bu5Mf+P-N) zxU0Dp=j-Y&d?)a#^^ytWwzW0f8b@U1XhXRsN)6#F*SAH7GT?TB(mi?WHny~{Zw=3h zMmnUwYH${eV)cj@?s7|HRdFR%8(y`3%^K;$IJR&-wz>plKnvrhPWzhLy1XSU>5R2R z)`eRe!mH!9P0djZf;rN$S4E;%#1(ZLaq@4I$=ci=NA=9cDO=o$!}XnUKEdRowPBB{ zZev%tGbW#&+=x5A&OwluV$B#*S>L&uO9R)SK~^=*_)r#gmKOLO#au`z$Mjlkex!w` zg~8R=L^@Zuty!->>I_!bhGh_Q5sWLHv7j3q$K$izOp3S)2lsGvT?A*AaI5|zYIBB+ zo9L5JeP>&j-jkwn6*{i5d3CsJQv=RQu{h3IUe_L$&XR4!qjFllI2zu7L!=qS9s@nT z8I^``d-Fze9(^NLzr==mluqX@j^g;%(iQi}QPf1%ZHl(7S?f_XUeUHr`k_50ZH#9* zb!g0<5jSs;X6#ZE@j>VnEC(BNcaRWZGVUPOJ*AnY$GOS@ zOo%JYjCzB_|6>BPOknHNw;OFhMz7h_ch9 z`Xhy!9f{yWWT(>SR?nvuG-AN#7iC(Xc=4iQ-fNh_VjCL(;2V4_ZfP~X%%A~GiC!vn1(xe zx>R~}m?hRZbErty+Hh2vRh2!*X^Xofh5Zk!rw$0j2ygYk@U9P3uKb*q#6Jea9LO1> zT&N=J8gV7q))F41)(dJl>gx4oj&UNRFD7G%>q1O9Ga8)P+hvNxR9G&*#+2ag8 zp|*yraT4DYYm2D`Z7tDAEV8;Q5#|*cYmx!UiZr9AX5z?isC0K_WN~jg;}bu@V9+QY zlsOz71SM7&W3T8i_vQIHg=epa@SpbaM6W1dw)#fG^0OY zFwWTVbeJ^*4L;E8PZ?_N`nFcX)?zzu!UAtZE*G)3E=QIj>3%wK76oHl*SWsKuu_6t zoO(pLOEsd@;Sm?Dk}EVE^jadFn7nA3GedY4IrI!Ms)4gY!|mbKU5b0Hs*gz*L@`Qa zi^aGHkw(;pS2wS3?{b5rnt0bZ)Wp{c$;1!+YVbvh*uP8zG%5NI^O1 zQq_zS)&n=_grQ1pfF2tfOZAjJ@l>|!P-Zi{!e^zpCnZwfB4}C%*Gk<&*k3hRcji#F zEEw!fkuG~sJ3VC&(v2IcY-uePSVYg`eL+328b-TWMV)9BNt;B|2!Eo;VWK$F!KEze z3;CM|Zj2fELB0?bf7Y|-OiA=!&<_0Go76028QqZaufZD}%_w0FEE7gTUbSbOm=cDG zpE~aK@Lqb^t8pTlpqUWQ(}+CclZ-y8aZsCRt4sMv+p$uv6URkpt+ce6Wy{DmevPd~ zUGecQwQm|c>N74x?oCdf2}9*M)tEk&?T}--bSb=%QG3d$Pmy{q$3O8|dgLQ>c;?BV zc;fNn+8vMl@PRisFS_S~?|!)cd&%>Z9a5Gb-^`dC0Ldv3HZu_NS(%^!>PbJ5T9Dgg z738e6@|0m)f>AHlCzC8Sm3?po&kfAlby_BTBk(p@)xxKfcLdgkz z?|$gCf|xJD#LBc8=IA~_myG_DcJ(TLx1jYy70ni1ECluX}pdhbRg=onZui2nBO z_9Z80x(-v!b9DFH$&&Xblu-~j@t{Fk(nuPdEcHqhbkGW!ry!^ISq9319U~pgK}H%D zm!u>UOGrbbpf1mz)w3XGPSdNj9BXm*(`vJJN$v z6pECo?+@nmemWz`22C~^U4SUHi7r57nOpCmFT_;O7=#~d8wRQm-we%wYTVJMF{m0d z@w1RwPZ^y-^A4snXebk*rKz*+ZO~Q*P#`$>|`WBW3JJi0q&a(tF^G z;*Es%NemR}b0>%#|6A0McCt5UyF0+4k}dur?POADySt2C@{o2iH?-YOW0yXpolFsJ zx69aN4{0ZZU)$|9cKJy22ecOpls0xMAe8d=zKzjOML(hVy?H_}k zFX)p1g}~;8{O+h?#8IpaoPF%UROut#nE8WZm^G)ZHO*GHqaC*|p!+fx;(|f;>4ey@OvFUvQX#mq?L@}*Ilu;;y zFBR5c1rlc`v#cPRjWu3cZxA^!jR+9MaBY)SL2r|=areR`Kb9p|be1x))tjYRL3Bp9 z1hax@R5oEQk2*&%$(Pgn689fj^Inpkd66!%XY>RVzo!u#q2r}tn9BSye(F&DkYQ>8P8j_LP}C`@GK7?`E1uZrBh( z(34N1cigp}Pp)u~HK(AMzU`VWCO3SLDSK8XqL`m>&6~)X!J80U@A*RK`kk9=8My*I zA9XGt`_Pns(zRSpZYa;6&*_j8tvFpVF!j~PN6NjB*dfy<&fuvb!g{~N5Qf7sQ zQR0@BJPGFc(q&3GLY@wYOd~p)XXSL1CSly`eLAQ205mwXXuwJ3{2&uEFBFt*Tuw0< z;QBxy&O3{~d_>?bq05nMQXWnMGP|M4Nb*ZQQ%Ml>8+AD)$aavPWXJW6Le~FeI1bym zwJi2Y0(wf2g`KNIqH8jgs3}7tGP^Y&&b@?qO35QlTQg!_(pcEm>r0lIm*p? z1faR%Ef!42BYnPHyiy-^YtZ~kQgSs^$ZV%8& zPCX7w^&s$?m|V_~aJ|zDBo=UXxn;(Kg_CD8K0atu5W3_Qz` zW8i^c;8}Vc0}o_6(Mr+1h))YL%(#5ZM~NTdc#D-hO|*v3(6h`)n0;GX-6?5UXOKNF zJ>d(aqP*vmU+m8N@TG}A{dn@v=Z{UxfBlRzdw1dYD3rffsXOrDKj;I2+|XD(MSgd~ zlK*N?l>Ppl-*y-MIdKZ!1ujB{BqZxshiVZES&P4))iH;v88`atKO4d^y%b3|MaSRXYc+^zT9xE zR&u`+#od+MbHvnX0$vHR4WL|mECB7mFD~e-u+y9ytq5$}cr!AGH)tKa@flIe1P?HA z@zairoFSD>$k~Acy~_ML1edVn;4*mCE}bUbW(P+Gd_nx5X$NzcKteilge*QU@lARqr;-4# zQUbF4y<<>?-UyG(mpk(X`RY@JL`$%6H;FdH8a zrNx+`NFU;7ot%yl4vabu5%VZRaiv+S4PUeDaUp#UeMC?l9`8GN+dej8aquV@C=M8S}KqbyRxxJ6W zJLf==0Lb|u0g!V+0w8CC1V9c134k00u!cLe$iXo#nK6a0A#?OV+@Q$3auvzBao*Xx z6Ck}~=XtHnCm{TKDLx@QkN@S)2}z=n-ZP8589kd~0`A!h6L8NKn1FkBzJwS&FMj~Y z{rrVC>ywF%1r2}5G1Fg$1qzH0%t(<&j)0U521mOx=l)1U3*W4%RI-I%u9ctDWE*Sp z6-b;yYN2QsJg>@+a*hu033*&1k;{tq~aF)KryBdQ9C zjPJx~Y=izE@KhQ!ATt{O8~*8=fko~|MN*`vqJf=ap&vrV>?69X7Z=nYek!+ckLO5N~QHx6cIdzD&rw;JmoKmovK*E~ZnZ=o6$Y4Cwez=0C7GxC( z!v}weh(8r*`hxnV(0sf{)ENt>rn;|7hRRyTg{DrPIwf(vN=;oHj&`*1?bc9REQA>t zUbQK-CfbY_AzRBstE1ttEMP5I|JH=dLtT*&UStg6MP9su6^g9tYHsVqyAPq}5MBh{ zlnTqPwJ1j3AiAnK8isLes5usk;MXBgUZ^$F!k20IYFTJC-q4MO%J6(;MoZ;P!h54FmRZ+vsRJQNd_>uc+3L!+u2 zA&)8#T~yyRZ_$#b5G)$17dBlSS~MqAz3}4Dh4l+-%R_a`7B|#2Hii~8q}DH3JiopU zSpCA9`Acf+7tRgMM!toMFof$dkWpyUqL5T*imIu5M_muURs`x*@c9NyFkrjdiHL7R4^CUpS`$wbU)BTi8^AT7iY? zmO=haer+AV*>&)&diMM}T@@NtGrzii zL3yaQdO`JE@vb4X2&FWnikbEDhm=_myG7S`!fB-9L$+aoZMfGt6z9bZDVb=C7x7P@C4 zo9Gx<@LL;{DtdUr?z;N#zW=L(AD`Cx$4Ogy4~*^Ef7zLH@6P({xmVn~`NqoT?|f<0 zhP3SdEAQO?m5%%iGA@06!I_^a`f=}1zWto9645KE199#Y%^>p~AOADD`#dzV6Wh!uQW4{xme! zHg3NydUwf_BNsfq%Nol zBJm`1Je=hDB_Et3PnoA;UF#}^u{ZUs>B@NfsN=0fWW|z8^UHtTnKbIG*$)Jd#9J5= zJ`|U|T&~9szh{r%lc{ZQUx1Zbb>R0ku%h$5WS!%~u_$F==)8sf|Cq=59Nyy(IrSzs zf*UQq2V^iVcJuIWSwGGm`WPV)_-UX^ac{K(v<}}h(unt$7U6BE6-XE23TF}Rp7Hgq)OrI+KVTlM;VwAzCO^-cFi>TP1l%Pu}HOjSDCF8G~{ZeyLR6Z|cM~ zl)Nn`?@-Bgl>T|l--YTdbE~G`t{Pm@V%khbyY+w5aKVNc;0>@c0>*$h zs7eftI$USTyGT;At}_NS0`KJgyj4KuE^GsQT1C&LoPqBd#_+8z^1Um`ZawmLS|_gR z79y28<);R6jPIjGaWSUw{X@fG@3f;9Rx#YT$-UdUg!cb4UPzndNBiQGy_9Wm+9&!- zcr5>>;h)6l5`6EH#a@wEMB%%<2^shPpY@>vmz)wM`KiSymG5Gb%R?zuBDfB*ke04N zJi1`>5TczJpK>5FN?I7(RrGI>$s;2`N^;sKl8*BKj-L(ekHx4X0`K+RZ9D?%pBfEL zKU|0J^0DykJ>D`0_C~xfCZI27qEA-in|@kBr$br|d6k-qbOy9%K{EsYtyWWLHxqW1 zkZ00Xa!!YIHgZfsOz`;`KQlNkt1-G{EX%dCTq4WcuKN1fnQ3u9^q64g|4063Mc{`x VGr*&1dYb>w^6me5^DmFU{|8#YvA+NS literal 0 HcmV?d00001 diff --git a/Assets/Packages/ObservableCollections.R3.3.3.4/lib/netstandard2.1/ObservableCollections.R3.dll.meta b/Assets/Packages/ObservableCollections.R3.3.3.4/lib/netstandard2.1/ObservableCollections.R3.dll.meta new file mode 100644 index 00000000..b1f50ae4 --- /dev/null +++ b/Assets/Packages/ObservableCollections.R3.3.3.4/lib/netstandard2.1/ObservableCollections.R3.dll.meta @@ -0,0 +1,29 @@ +fileFormatVersion: 2 +guid: 043a92f8b27f42bbb94c3b2a62cc2364 +labels: +- NuGetForUnity +PluginImporter: + externalObjects: {} + serializedVersion: 3 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + Any: + enabled: 1 + settings: {} + Editor: + enabled: 0 + settings: + DefaultValueInitialized: true + WindowsStoreApps: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/ObservableCollections.R3.3.3.4/lib/netstandard2.1/ObservableCollections.R3.xml b/Assets/Packages/ObservableCollections.R3.3.3.4/lib/netstandard2.1/ObservableCollections.R3.xml new file mode 100644 index 00000000..6b72ecac --- /dev/null +++ b/Assets/Packages/ObservableCollections.R3.3.3.4/lib/netstandard2.1/ObservableCollections.R3.xml @@ -0,0 +1,352 @@ + + + + ObservableCollections.R3 + + + + + Indicates that an API is experimental and it may change in the future. + + + This attribute allows call sites to be flagged with a diagnostic that indicates that an experimental + feature is used. Authors can use this attribute to ship preview features in their assemblies. + + + + + Initializes a new instance of the class, + specifying the ID that the compiler will use when reporting a use of the API the attribute applies to. + + The ID that the compiler will use when reporting a use of the API the attribute applies to. + + + + Gets the ID that the compiler will use when reporting a use of the API the attribute applies to. + + The unique diagnostic ID. + + The diagnostic ID is shown in build output for warnings and errors. + This property represents the unique ID that can be used to suppress the warnings or errors, if needed. + + + + + Gets or sets the URL for corresponding documentation. + The API accepts a format string instead of an actual URL, creating a generic URL that includes the diagnostic ID. + + The format string that represents a URL to corresponding documentation. + An example format string is https://contoso.com/obsoletion-warnings/{0}. + + + + Specifies that the method or property will ensure that the listed field and property members have not-null values. + + + + + Initializes the attribute with a field or property member. + + The field or property member that is promised to be not-null. + + + + Initializes the attribute with the list of field and property members. + + The list of field and property members that are promised to be not-null. + + + + Gets field or property member names. + + + + + Specifies that the method or property will ensure that the listed field and property + members have not-null values when returning with the specified return value condition. + + + + + Initializes the attribute with the specified return value condition and a field or property member. + + The return value condition. If the method returns this value, the associated parameter will not be null. + The field or property member that is promised to be not-null. + + + + Initializes the attribute with the specified return value condition and list of field and property members. + + The return value condition. If the method returns this value, the associated parameter will not be null. + The list of field and property members that are promised to be not-null. + + + + Gets the return value condition. + + + + + Gets field or property member names. + + + + + Specifies that this constructor sets all required members for the current type, + and callers do not need to set any required members themselves. + + + + + Specifies the syntax used in a string. + + + + + Initializes the with the identifier of the syntax used. + + The syntax identifier. + + + Initializes the with the identifier of the syntax used. + The syntax identifier. + Optional arguments associated with the specific syntax employed. + + + Gets the identifier of the syntax used. + + + Optional arguments associated with the specific syntax employed. + + + The syntax identifier for strings containing composite formats for string formatting. + + + The syntax identifier for strings containing date format specifiers. + + + The syntax identifier for strings containing date and time format specifiers. + + + The syntax identifier for strings containing format specifiers. + + + The syntax identifier for strings containing format specifiers. + + + The syntax identifier for strings containing JavaScript Object Notation (JSON). + + + The syntax identifier for strings containing numeric format specifiers. + + + The syntax identifier for strings containing regular expressions. + + + The syntax identifier for strings containing time format specifiers. + + + The syntax identifier for strings containing format specifiers. + + + The syntax identifier for strings containing URIs. + + + The syntax identifier for strings containing XML. + + + + Used to indicate a byref escapes and is not scoped. + + + + There are several cases where the C# compiler treats a as implicitly + - where the compiler does not allow the to escape the method. + + + For example: + + for instance methods. + parameters that refer to types. + parameters. + + + + This attribute is used in those instances where the should be allowed to escape. + + + Applying this attribute, in any form, has impact on consumers of the applicable API. It is necessary for + API authors to understand the lifetime implications of applying this attribute and how it may impact their users. + + + + + + An attribute that allows parameters to receive the expression of other parameters. + + + + + Initializes a new instance of the class. + + The condition parameter value. + + + + Gets the parameter name the expression is retrieved from. + + + + + Initialize the attribute to refer to the method on the type. + + The type of the builder to use to construct the collection. + The name of the method on the builder to use to construct the collection. + + must refer to a static method that accepts a single parameter of + type and returns an instance of the collection being built containing + a copy of the data from that span. In future releases of .NET, additional patterns may be supported. + + + + + Gets the type of the builder to use to construct the collection. + + + + + Gets the name of the method on the builder to use to construct the collection. + + + This should match the metadata name of the target method. + For example, this might be ".ctor" if targeting the type's constructor. + + + + + Indicates that compiler support for a particular feature is required for the location where this attribute is applied. + + + + + Creates a new instance of the type. + + The name of the feature to indicate. + + + + The name of the compiler feature. + + + + + If true, the compiler can choose to allow access to the location where this attribute is applied if it does not understand . + + + + + The used for the ref structs C# feature. + + + + + The used for the required members C# feature. + + + + + Indicates which arguments to a method involving an interpolated string handler should be passed to that handler. + + + + + Initializes a new instance of the class. + + The name of the argument that should be passed to the handler. + may be used as the name of the receiver in an instance method. + + + + Initializes a new instance of the class. + + The names of the arguments that should be passed to the handler. + may be used as the name of the receiver in an instance method. + + + + Gets the names of the arguments that should be passed to the handler. + + may be used as the name of the receiver in an instance method. + + + + Indicates the attributed type is to be used as an interpolated string handler. + + + + + Reserved to be used by the compiler for tracking metadata. + This class should not be used by developers in source code. + + + + + Used to indicate to the compiler that a method should be called + in its containing module's initializer. + + + When one or more valid methods + with this attribute are found in a compilation, the compiler will + emit a module initializer which calls each of the attributed methods. + + Certain requirements are imposed on any method targeted with this attribute: + - The method must be `static`. + - The method must be an ordinary member method, as opposed to a property accessor, constructor, local function, etc. + - The method must be parameterless. + - The method must return `void`. + - The method must not be generic or be contained in a generic type. + - The method's effective accessibility must be `internal` or `public`. + + The specification for module initializers in the .NET runtime can be found here: + https://github.com/dotnet/runtime/blob/main/docs/design/specs/Ecma-335-Augments.md#module-initializer + + + + + Specifies that a type has required members or that a member is required. + + + + + Reserved for use by a compiler for tracking metadata. + This attribute should not be used by developers in source code. + + + + + Used to indicate to the compiler that the .locals init flag should not be set in method headers. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class with the specified message. + + An optional message associated with this attribute instance. + + + + Returns the optional message associated with this attribute instance. + + + + + Returns the optional URL associated with this attribute instance. + + + + diff --git a/Assets/Packages/ObservableCollections.R3.3.3.4/lib/netstandard2.1/ObservableCollections.R3.xml.meta b/Assets/Packages/ObservableCollections.R3.3.3.4/lib/netstandard2.1/ObservableCollections.R3.xml.meta new file mode 100644 index 00000000..6d14cc47 --- /dev/null +++ b/Assets/Packages/ObservableCollections.R3.3.3.4/lib/netstandard2.1/ObservableCollections.R3.xml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 30453c48f1672c8108ef96427d55ae4f +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/R3.1.3.1.meta b/Assets/Packages/R3.1.3.1.meta new file mode 100644 index 00000000..a81554c1 --- /dev/null +++ b/Assets/Packages/R3.1.3.1.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f90856a7023f90f71928b28052299ad5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/R3.1.3.1/.signature.p7s b/Assets/Packages/R3.1.3.1/.signature.p7s new file mode 100644 index 0000000000000000000000000000000000000000..54fb3706800e41f4a8393fbff0daac5fcf021605 GIT binary patch literal 12982 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 LJ1$sMFZ{m%^uy&O literal 0 HcmV?d00001 diff --git a/Assets/Packages/R3.1.3.1/Icon.png b/Assets/Packages/R3.1.3.1/Icon.png new file mode 100644 index 00000000..f24b53ea --- /dev/null +++ b/Assets/Packages/R3.1.3.1/Icon.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c1cc0d07828b8dba364f5e29b2f3d1ac6aa0c0ded4d1a97e028981609355b2c8 +size 3185 diff --git a/Assets/Packages/R3.1.3.1/Icon.png.meta b/Assets/Packages/R3.1.3.1/Icon.png.meta new file mode 100644 index 00000000..98ba1305 --- /dev/null +++ b/Assets/Packages/R3.1.3.1/Icon.png.meta @@ -0,0 +1,117 @@ +fileFormatVersion: 2 +guid: 7708e9b07d2ee3b3ba2d75f6e1d5e7e7 +TextureImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 13 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + sRGBTexture: 1 + linearTexture: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapsPreserveCoverage: 0 + alphaTestReferenceValue: 0.5 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: 0.25 + normalMapFilter: 0 + flipGreenChannel: 0 + isReadable: 0 + streamingMipmaps: 0 + streamingMipmapsPriority: 0 + vTOnly: 0 + ignoreMipmapLimit: 0 + grayScaleToAlpha: 0 + generateCubemap: 6 + cubemapConvolution: 0 + seamlessCubemap: 0 + textureFormat: 1 + maxTextureSize: 2048 + textureSettings: + serializedVersion: 2 + filterMode: 1 + aniso: 1 + mipBias: 0 + wrapU: 0 + wrapV: 0 + wrapW: 0 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + spriteMode: 0 + spriteExtrude: 1 + spriteMeshType: 1 + alignment: 0 + spritePivot: {x: 0.5, y: 0.5} + spritePixelsToUnits: 100 + spriteBorder: {x: 0, y: 0, z: 0, w: 0} + spriteGenerateFallbackPhysicsShape: 1 + alphaUsage: 1 + alphaIsTransparency: 0 + spriteTessellationDetail: -1 + textureType: 0 + textureShape: 1 + singleChannelComponent: 0 + flipbookRows: 1 + flipbookColumns: 1 + maxTextureSizeSet: 0 + compressionQualitySet: 0 + textureFormatSet: 0 + ignorePngGamma: 0 + applyGammaDecoding: 0 + swizzle: 50462976 + cookieLightType: 0 + platformSettings: + - serializedVersion: 4 + buildTarget: DefaultTexturePlatform + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + - serializedVersion: 4 + buildTarget: Standalone + maxTextureSize: 2048 + resizeAlgorithm: 0 + textureFormat: -1 + textureCompression: 1 + compressionQuality: 50 + crunchedCompression: 0 + allowsAlphaSplitting: 0 + overridden: 0 + ignorePlatformSupport: 0 + androidETC2FallbackOverride: 0 + forceMaximumCompressionQuality_BC6H_BC7: 0 + spriteSheet: + serializedVersion: 2 + sprites: [] + outline: [] + customData: + physicsShape: [] + bones: [] + spriteID: + internalID: 0 + vertices: [] + indices: + edges: [] + weights: [] + secondaryTextures: [] + spriteCustomMetadata: + entries: [] + nameFileIdTable: {} + mipmapLimitGroupName: + pSDRemoveMatte: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/R3.1.3.1/R3.nuspec b/Assets/Packages/R3.1.3.1/R3.nuspec new file mode 100644 index 00000000..3b6a4850 --- /dev/null +++ b/Assets/Packages/R3.1.3.1/R3.nuspec @@ -0,0 +1,37 @@ + + + + R3 + 1.3.1 + Cysharp + MIT + https://licenses.nuget.org/MIT + Icon.png + README.md + https://github.com/Cysharp/R3 + The evolution of dotnet/reactive and UniRx. + © Cysharp, Inc. + rx + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Assets/Packages/R3.1.3.1/R3.nuspec.meta b/Assets/Packages/R3.1.3.1/R3.nuspec.meta new file mode 100644 index 00000000..5039eaa9 --- /dev/null +++ b/Assets/Packages/R3.1.3.1/R3.nuspec.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3c11d278a132ea4b0b3056a504bf80b9 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Packages/R3.1.3.1/README.md b/Assets/Packages/R3.1.3.1/README.md new file mode 100644 index 00000000..42eb3fc9 --- /dev/null +++ b/Assets/Packages/R3.1.3.1/README.md @@ -0,0 +1,2328 @@ +# R3 + +The new future of [dotnet/reactive](https://github.com/dotnet/reactive/) and [UniRx](https://github.com/neuecc/UniRx), which support many platforms including [Unity](#unity), [Godot](#godot), [Avalonia](#avalonia), [WPF](#wpf), [WinForms](#winforms), [WinUI3](#winui3), [Stride](#stride), [LogicLooper](#logiclooper), [MAUI](#maui), [MonoGame](#monogame), [Blazor](#blazor), [Uno](#uno). + +I have over 10 years of experience with Rx, experience in implementing a custom Rx runtime ([UniRx](https://github.com/neuecc/UniRx)) for game engine, and experience in implementing an asynchronous runtime ([UniTask](https://github.com/Cysharp/UniTask/)) for game engine. Based on those experiences, I came to believe that there is a need to implement a new Reactive Extensions for .NET, one that reflects modern C# and returns to the core values of Rx. + +* Stopping the pipeline at OnError is a mistake. +* IScheduler is the root of poor performance. +* Frame-based operations, a missing feature in Rx, are especially important in game engines. +* Single asynchronous operations should be entirely left to async/await. +* Synchronous APIs should not be implemented. +* Query syntax is a bad notation except for SQL. +* The Necessity of a subscription list to prevent subscription leaks (similar to a Parallel Debugger) +* Backpressure should be left to [IAsyncEnumerable](https://learn.microsoft.com/en-us/dotnet/csharp/asynchronous-programming/generate-consume-asynchronous-stream) and [Channels](https://devblogs.microsoft.com/dotnet/an-introduction-to-system-threading-channels/). +* For distributed processing and queries, there are [GraphQL](https://graphql.org/), [Kubernetes](https://kubernetes.io/), [Orleans](https://learn.microsoft.com/en-us/dotnet/orleans/), [Akka.NET](https://getakka.net/), [gRPC](https://grpc.io/), [MagicOnion](https://github.com/Cysharp/MagicOnion). + +In other words, LINQ is not for EveryThing, and we believe that the essence of Rx lies in the processing of in-memory messaging (LINQ to Events), which will be our focus. We are not concerned with communication processes like [Reactive Streams](https://www.reactive-streams.org/). + +To address the shortcomings of dotnet/reactive, we have made changes to the core interfaces. In recent years, Rx-like frameworks optimized for language features, such as [Kotlin Flow](https://kotlinlang.org/docs/flow.html) and [Swift Combine](https://developer.apple.com/documentation/combine), have been standardized. C# has also evolved significantly, now at C# 12, and we believe there is a need for an Rx that aligns with the latest C#. + +Improving performance was also a theme in the reimplementation. For example, this is the result of the terrible performance of IScheduler and the performance difference caused by its removal. + +![image](https://github.com/Cysharp/ZLogger/assets/46207/68a12664-a840-4725-a87c-8fdbb03b4a02) +`Observable.Range(1, 10000).Subscribe()` + +You can also see interesting results in allocations with the addition and deletion to Subject. + +![image](https://github.com/Cysharp/ZLogger/assets/46207/2194c086-37a3-44d6-8642-5fd0fa91b168) +`x10000 subject.Subscribe() -> x10000 subscription.Dispose()` + +This is because dotnet/reactive has adopted ImmutableArray (or its equivalent) for Subject, which results in the allocation of a new array every time one is added or removed. Depending on the design of the application, a large number of subscriptions can occur (we have seen this especially in the complexity of games), which can be a critical issue. In R3, we have devised a way to achieve high performance while avoiding ImmutableArray. + +For those interested in learning more about the implementation philosophy and comparisons, please refer to my blog article [R3 — A New Modern Reimplementation of Reactive Extensions for C#](https://neuecc.medium.com/r3-a-new-modern-reimplementation-of-reactive-extensions-for-c-cf29abcc5826). + +Core Interface +--- +This library is distributed via [NuGet packages/R3](https://www.nuget.org/packages/R3), supporting .NET Standard 2.0, .NET Standard 2.1, .NET 6(.NET 7) and .NET 8 or above. + +```bash +dotnet add package R3 +``` + +Some platforms(WPF, Avalonia, Unity, Godot, etc...) requires additional step to install. Please see [Platform Supports](#platform-supports) section in below. + +R3 code is mostly the same as standard Rx. Make the Observable via factory methods(Timer, Interval, FromEvent, Subject, etc...) and chain operator via LINQ methods. Therefore, your knowledge about Rx and documentation on Rx can be almost directly applied. If you are new to Rx, the [ReactiveX](https://reactivex.io/intro.html) website and [Introduction to Rx.NET](https://introtorx.com/) would be useful resources for reference. + +```csharp +using R3; + +var subscription = Observable.Interval(TimeSpan.FromSeconds(1)) + .Select((_, i) => i) + .Where(x => x % 2 == 0) + .Subscribe(x => Console.WriteLine($"Interval:{x}")); + +var cts = new CancellationTokenSource(); +_ = Task.Run(() => { Console.ReadLine(); cts.Cancel(); }); + +await Observable.Timer(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(3)) + .TakeUntil(cts.Token) + .ForEachAsync(x => Console.WriteLine($"Timer")); + +subscription.Dispose(); +``` + +The surface API remains the same as normal Rx, but the interfaces used internally are different and are not `IObservable/IObserver`. + +`IObservable` being the dual of `IEnumerable` is a beautiful definition, but it was not very practical in use. + +```csharp +public abstract class Observable +{ + public IDisposable Subscribe(Observer observer); +} + +public abstract class Observer : IDisposable +{ + public void OnNext(T value); + public void OnErrorResume(Exception error); + public void OnCompleted(Result result); // Result is (Success | Failure) +} +``` + +The biggest difference is that in normal Rx, when an exception occurs in the pipeline, it flows to `OnError` and the subscription is unsubscribed, but in R3, it flows to `OnErrorResume` and the subscription is not unsubscribed. + +I consider the automatic unsubscription by OnError to be a bad design for event handling. It's very difficult and risky to resolve it within an operator like Retry, and it also led to poor performance (there are many questions and complex answers about stopping and resubscribing all over the world). Also, converting OnErrorResume to OnError(OnCompleted(Result.Failure)) is easy and does not degrade performance, but the reverse is impossible. Therefore, the design was changed to not stop by default and give users the choice to stop. + +Since the original Rx contract was `OnError | OnCompleted`, it was changed to `OnCompleted(Result result)` to consolidate into one method. Result is a readonly struct with two states: `Success() | Failure(Exception)`. + +The reason for changing to an abstract class instead of an interface is that Rx has implicit complex contracts that interfaces do not guarantee. By making it an abstract class, we fully controlled the behavior of Subscribe, OnNext, and Dispose. This made it possible to manage the list of all subscriptions and prevent subscription leaks. + +![image](https://github.com/Cysharp/ZLogger/assets/46207/149abca5-6d84-44ea-8373-b0e8cd2dc46a) + +Subscription leaks are a common problem in applications with long lifecycles, such as GUIs or games. Tracking all subscriptions makes it easy to prevent leaks. + +Internally, when subscribing, an Observer is always linked to the target Observable and doubles as a Subscription. This ensures that Observers are reliably connected from top to bottom, making tracking certain and clear that they are released on OnCompleted/Dispose. In terms of performance, because the Observer itself always becomes a Subscription, there is no need for unnecessary IDisposable allocations. + +TimeProvider instead of IScheduler +--- +In traditional Rx, `IScheduler` was used as an abstraction for time-based processing, but in R3, we have discontinued its use and instead opted for the [TimeProvider](https://learn.microsoft.com/en-us/dotnet/api/system.timeprovider?view=net-8.0) introduced in .NET 8. For example, the operators are defined as follows: + +```csharp +public static Observable Interval(TimeSpan period, TimeProvider timeProvider); +public static Observable Delay(this Observable source, TimeSpan dueTime, TimeProvider timeProvider) +public static Observable Debounce(this Observable source, TimeSpan timeSpan, TimeProvider timeProvider) // same as Throttle in dotnet/reactive +``` + +Originally, `IScheduler` had performance issues, and the internal implementation of dotnet/reactive was peppered with code that circumvented these issues using `PeriodicTimer` and `IStopwatch`, leading to unnecessary complexity. These can be better expressed with TimeProvider (`TimeProvider.CreateTimer()`, `TimeProvider.GetTimestamp()`). + +While TimeProvider is an abstraction for asynchronous operations, excluding the Fake for testing purposes, `IScheduler` included synchronous schedulers like `ImmediateScheduler` and `CurrentThreadScheduler`. However, these were also meaningless as applying them to time-based operators would cause blocking, and `CurrentThreadScheduler` had poor performance. + +![image](https://github.com/Cysharp/ZLogger/assets/46207/68a12664-a840-4725-a87c-8fdbb03b4a02) +`Observable.Range(1, 10000).Subscribe()` + +In R3, anything that requires synchronous execution (like Range) is treated as Immediate, and everything else is considered asynchronous and handled through TimeProvider. + +As for the implementation of TimeProvider, the standard TimeProvider.System using the ThreadPool is the default. For unit testing, FakeTimeProvider (Microsoft.Extensions.TimeProvider.Testing) is available. Additionally, many TimeProvider implementations are provided for different platforms, such as DispatcherTimeProvider for WPF and UpdateTimeProvider for Unity, enhancing ease of use tailored to each platform. + +Frame based operations +--- +In GUI applications, there's the message loop, and in game engines, there's the game loop. Platforms that operate based on loops are not uncommon. The idea of executing something after a few seconds or frames fits very well with Rx. Just as time has been abstracted through TimeProvider, we introduced a layer of abstraction for frames called FrameProvider, and added frame-based operators corresponding to all methods that accept TimeProvider. + +```csharp +public static Observable IntervalFrame(int periodFrame, FrameProvider frameProvider); +public static Observable DelayFrame(this Observable source, int frameCount, FrameProvider frameProvider) +public static Observable DebounceFrame(this Observable source, int frameCount, FrameProvider frameProvider) +``` + +The effectiveness of frame-based processing has been proven in Unity's Rx implementation, [neuecc/UniRx](https://github.com/neuecc/UniRx), which is one of the reasons why UniRx has gained strong support. + +There are also several operators unique to frame-based processing. + +```csharp +// push OnNext every frame. +Observable.EveryUpdate().Subscribe(x => Console.WriteLine(x)); + +// take value until next frame +eventSoure.TakeUntil(Observable.NextFrame()).Subscribe(); + +// polling value changed +Observable.EveryValueChanged(this, x => x.Width).Subscribe(x => WidthText.Text = x.ToString()); +Observable.EveryValueChanged(this, x => x.Height).Subscribe(x => HeightText.Text = x.ToString()); +``` + +`EveryValueChanged` could be interesting, as it converts properties without Push-based notifications like `INotifyPropertyChanged`. + +![](https://cloud.githubusercontent.com/assets/46207/15827886/1573ff16-2c48-11e6-9876-4e4455d7eced.gif)` + +Subjects(ReactiveProperty) +--- +In R3, there are five types of Subjects: `Subject`, `BehaviorSubject`, `ReactiveProperty`, `ReplaySubject`, and `ReplayFrameSubject`. + +`Subject` is an event in Rx. Just as an event can register multiple Actions and distribute values using Invoke, a `Subject` can register multiple `Observer`s and distribute values using OnNext, OnErrorResume, and OnCompleted. There are variations of Subject, such as `BehaviorSubject` and `ReactiveProperty`, which holds a single value internally, `ReplaySubject`, which holds multiple values based on count or time, and `ReplayFrameSubject`, which holds multiple values based on frame time. The internally recorded values are distributed when Subscribe is called. + + `ReactiveProperty` corresponds to what would be a `BehaviorSubject`, but with the added functionality of eliminating duplicate values. In addition, since the value can be set with `.Value`, it can be utilized for binding on XAML platforms, etc. + +Here's an example of creating an observable model using `ReactiveProperty`: + +```csharp +// Reactive Notification Model +public class Enemy +{ + public ReactiveProperty CurrentHp { get; private set; } + + public ReactiveProperty IsDead { get; private set; } + + public Enemy(int initialHp) + { + // Declarative Property + CurrentHp = new ReactiveProperty(initialHp); + IsDead = CurrentHp.Select(x => x <= 0).ToReactiveProperty(); + } +} + +// --- + +// Click button, HP decrement +MyButton.OnClickAsObservable().Subscribe(_ => enemy.CurrentHp.Value -= 99); + +// subscribe from notification model. +enemy.CurrentHp.Subscribe(x => Console.WriteLine("HP:" + x)); +enemy.IsDead.Where(isDead => isDead == true) + .Subscribe(_ => + { + // when dead, disable button + MyButton.SetDisable(); + }); +``` + +In `ReactiveProperty`, the value is updated by `.Value` and if it is identical to the current value, no notification is issued. If you want to force notification of a value even if it is the same, call `.OnNext(value)`. + +`ReactiveProperty` has equivalents in other frameworks as well, such as [Android LiveData](https://developer.android.com/topic/libraries/architecture/livedata) and [Kotlin StateFlow](https://developer.android.com/kotlin/flow/stateflow-and-sharedflow), particularly effective for data binding in UI contexts. In .NET, there is a library called [runceel/ReactiveProperty](https://github.com/runceel/ReactiveProperty), which I originally created. + +Unlike dotnet/reactive's Subject, all Subjects in R3 (Subject, BehaviorSubject, ReactiveProperty, ReplaySubject, ReplayFrameSubject) are designed to call OnCompleted upon disposal. This is because R3 is designed with a focus on subscription management and unsubscription. By calling OnCompleted, it ensures that all subscriptions are unsubscribed from the Subject, the upstream source of events, by default. If you wish to avoid calling OnCompleted, you can do so by calling `Dispose(false)`. + +`ReactiveProperty` is mutable, but it can be converted to a read-only `ReadOnlyReactiveProperty`. Following the [guidance for the Android UI Layer](https://developer.android.com/topic/architecture/ui-layer), the Kotlin code below is + +```kotlin +class NewsViewModel(...) : ViewModel() { + + private val _uiState = MutableStateFlow(NewsUiState()) + val uiState: StateFlow = _uiState.asStateFlow() + ... +} +``` + +can be adapted to the following R3 code. + +```csharp +class NewsViewModel +{ + ReactiveProperty _uiState = new(new NewsUiState()); + public ReadOnlyReactiveProperty UiState => _uiState; +} +``` + +In R3, we use a combination of a mutable private field and a readonly public property. + +By inheriting `ReactiveProperty` and overriding `OnValueChanging` and `OnValueChanged`, you can customize behavior, such as adding validation. + +```csharp +// Since the primary constructor sets values to fields before calling base, it is safe to call OnValueChanging in the base constructor. +public sealed class ClampedReactiveProperty(T initialValue, T min, T max) + : ReactiveProperty(initialValue) where T : IComparable +{ + private static IComparer Comparer { get; } = Comparer.Default; + + protected override void OnValueChanging(ref T value) + { + if (Comparer.Compare(value, min) < 0) + { + value = min; + } + else if (Comparer.Compare(value, max) > 0) + { + value = max; + } + } +} + +// For regular constructors, please set `callOnValueChangeInBaseConstructor` to false and manually call it once to correct the value. +public sealed class ClampedReactiveProperty2 + : ReactiveProperty where T : IComparable +{ + private static IComparer Comparer { get; } = Comparer.Default; + + readonly T min, max; + + // callOnValueChangeInBaseConstructor to avoid OnValueChanging call before min, max set. + public ClampedReactiveProperty2(T initialValue, T min, T max) + : base(initialValue, EqualityComparer.Default, callOnValueChangeInBaseConstructor: false) + { + this.min = min; + this.max = max; + + // modify currentValue manually + OnValueChanging(ref GetValueRef()); + } + + protected override void OnValueChanging(ref T value) + { + if (Comparer.Compare(value, min) < 0) + { + value = min; + } + else if (Comparer.Compare(value, max) > 0) + { + value = max; + } + } +} +``` + +Additionally, `ReactiveProperty` supports serialization with `System.Text.JsonSerializer` in .NET 6 and above. For earlier versions, you need to implement `ReactivePropertyJsonConverterFactory` under the existing implementation and add it to the Converter. + +As an internal implementation, `Subject` and `ReactiveProperty` has a lightweight implementation that consumes less memory. However, in exchange, its behavior differs slightly, especially in multi-threaded environments. For precautions related to multi-threading, please refer to the [Concurrency Policy](#concurrency-policy) section. + +Disposable +--- +To bundle multiple IDisposables (Subscriptions), it's good to use Disposable's methods. In R3, depending on the performance, + +```csharp +Disposable.Combine(IDisposable d1, ..., IDisposable d8); +Disposable.Combine(params IDisposable[]); +Disposable.CreateBuilder(); +CompositeDisposable +DisposableBag +``` + +five types are available for use. In terms of performance advantages, the order is `Combine(d1,...,d8) (>= CreateBuilder) > Combine(IDisposable[]) >= CreateBuilder > DisposableBag > CompositeDisposable`. + +When the number of subscriptions is statically determined, Combine offers the best performance. Internally, for less than 8 arguments, it uses fields, and for 9 or more arguments, it uses an array, making Combine especially efficient for 8 arguments or less. + +```csharp +public partial class MainWindow : Window +{ + IDisposable disposable; + + public MainWindow() + { + var d1 = Observable.IntervalFrame(1).Subscribe(); + var d2 = Observable.IntervalFrame(1).Subscribe(); + var d3 = Observable.IntervalFrame(1).Subscribe(); + + disposable = Disposable.Combine(d1, d2, d3); + } + + protected override void OnClosed(EventArgs e) + { + disposable.Dispose(); + } +} +``` + +If there are many subscriptions and it's cumbersome to hold each one in a variable, `CreateBuilder` can be used instead. At build time, it combines according to the number of items added to it. Since the Builder itself is a struct, there are no allocations. + +```csharp +public partial class MainWindow : Window +{ + IDisposable disposable; + + public MainWindow() + { + var d = Disposable.CreateBuilder(); + Observable.IntervalFrame(1).Subscribe().AddTo(ref d); + Observable.IntervalFrame(1).Subscribe().AddTo(ref d); + Observable.IntervalFrame(1).Subscribe().AddTo(ref d); + + disposable = d.Build(); + } + + protected override void OnClosed(EventArgs e) + { + disposable.Dispose(); + } +} +``` + +For dynamically added items, using `DisposableBag` is advisable. This is an add-only struct with only `Add/Clear/Dispose` methods. It can be used relatively quickly and with low allocation by holding it in a class field and passing it around by reference. However, it is not thread-safe. + +```csharp +public partial class MainWindow : Window +{ + DisposableBag disposable; // DisposableBag is struct, no need new and don't copy + + public MainWindow() + { + Observable.IntervalFrame(1).Subscribe().AddTo(ref disposable); + Observable.IntervalFrame(1).Subscribe().AddTo(ref disposable); + Observable.IntervalFrame(1).Subscribe().AddTo(ref disposable); + } + + void OnClick() + { + Observable.IntervalFrame(1).Subscribe().AddTo(ref disposable); + } + + protected override void OnClosed(EventArgs e) + { + disposable.Dispose(); + } +} +``` + +`CompositeDisposable` is a class that also supports `Remove` and is thread-safe. It is the most feature-rich, but comparatively, it has the lowest performance. + +```csharp +public partial class MainWindow : Window +{ + CompositeDisposable disposable = new CompositeDisposable(); + + public MainWindow() + { + Observable.IntervalFrame(1).Subscribe().AddTo(disposable); + Observable.IntervalFrame(1).Subscribe().AddTo(disposable); + Observable.IntervalFrame(1).Subscribe().AddTo(disposable); + } + + void OnClick() + { + Observable.IntervalFrame(1).Subscribe().AddTo(disposable); + } + + protected override void OnClosed(EventArgs e) + { + disposable.Dispose(); + } +} +``` + +Additionally, there are other utilities for Disposables as follows. + +```csharp +Disposable.Create(Action); +Disposable.Dispose(...); +SingleAssignmentDisposable +SingleAssignmentDisposableCore // struct +SerialDisposable +SerialDisposableCore // struct +``` + +Subscription Management +--- +Managing subscriptions is one of the most crucial aspects of Rx, and inadequate management can lead to memory leaks. There are two patterns for unsubscribing in Rx. One is by disposing of the IDisposable (Subscription) returned by Subscribe. The other is by receiving OnCompleted. + +In R3, to enhance subscription cancellation on both fronts, it's now possible to bundle subscriptions using a variety of Disposable classes for Subscriptions, and for OnCompleted, the upstream side of events (such as Subject or Factory) has been made capable of emitting OnCompleted. Especially, Factories that receive a TimeProvider or FrameProvider can now take a CancellationToken. + +```csharp +public static Observable Interval(TimeSpan period, TimeProvider timeProvider, CancellationToken cancellationToken) +public static Observable EveryUpdate(FrameProvider frameProvider, CancellationToken cancellationToken) +``` + +When cancelled, OnCompleted is sent, and all subscriptions are unsubscribed. + +### ObservableTracker + +R3 incorporates a system called ObservableTracker. When activated, it allows you to view all subscription statuses. + +```csharp +ObservableTracker.EnableTracking = true; // default is false +ObservableTracker.EnableStackTrace = true; + +using var d = Observable.Interval(TimeSpan.FromSeconds(1)) + .Where(x => true) + .Take(10000) + .Subscribe(); + +// check subscription +ObservableTracker.ForEachActiveTask(x => +{ + Console.WriteLine(x); +}); +``` + +```csharp +TrackingState { TrackingId = 1, FormattedType = Timer._Timer, AddTime = 2024/01/09 4:11:39, StackTrace =... } +TrackingState { TrackingId = 2, FormattedType = Where`1._Where, AddTime = 2024/01/09 4:11:39, StackTrace =... } +TrackingState { TrackingId = 3, FormattedType = Take`1._Take, AddTime = 2024/01/09 4:11:39, StackTrace =... } +``` + +Besides directly calling `ForEachActiveTask`, making it more accessible through a GUI can make it easier to check for subscription leaks. Currently, there is an integrated GUI for Unity, and there are plans to provide a screen using Blazor for other platforms. + +ObservableSystem, UnhandledExceptionHandler +--- +For time-based operators that do not specify a TimeProvider or FrameProvider, the default Provider of ObservableSystem is used. This is settable, so if there is a platform-specific Provider (for example, DispatcherTimeProvider in WPF), you can swap it out to create a more user-friendly environment. + +```csharp +public static class ObservableSystem +{ + public static TimeProvider DefaultTimeProvider { get; set; } = TimeProvider.System; + public static FrameProvider DefaultFrameProvider { get; set; } = new NotSupportedFrameProvider(); + + static Action unhandledException = DefaultUnhandledExceptionHandler; + + // Prevent +=, use Set and Get method. + public static void RegisterUnhandledExceptionHandler(Action unhandledExceptionHandler) + { + unhandledException = unhandledExceptionHandler; + } + + public static Action GetUnhandledExceptionHandler() + { + return unhandledException; + } + + static void DefaultUnhandledExceptionHandler(Exception exception) + { + Console.WriteLine("R3 UnhandledException: " + exception.ToString()); + } +} +``` + +In CUI environments, by default, the FrameProvider will throw an exception. If you want to use FrameProvider in a CUI environment, you can set either `NewThreadSleepFrameProvider`, which sleeps in a new thread for a specified number of seconds, or `TimerFrameProvider`, which executes every specified number of seconds. + +### UnhandledExceptionHandler + +When an exception passes through OnErrorResume and is not ultimately handled by Subscribe, the UnhandledExceptionHandler of ObservableSystem is called. This can be set with `RegisterUnhandledExceptionHandler`. By default, it writes to `Console.WriteLine`, but it may need to be changed to use `ILogger` or something else as required. + +Result Handling +--- +The `Result` received by OnCompleted has a field `Exception?`, where it's null in case of success and contains the Exception in case of failure. + +```csharp +// Typical processing code example +void OnCompleted(Result result) +{ + if (result.IsFailure) + { + // do failure + _ = result.Exception; + } + else // result.IsSuccess + { + // do success + } +} +``` + +To generate a `Result`, in addition to using `Result.Success` and `Result.Failure(exception)`, Observer has OnCompleted() and OnCompleted(exception) as shortcuts for Success and Failure, respectively. + +```csharp +observer.OnCompleted(Result.Success); +observer.OnCompleted(Result.Failure(exception)); + +observer.OnCompleted(); // same as Result.Success +observer.OnCompleted(exception); // same as Result.Failure(exception) +``` + +Unit Testing +--- +For unit testing, you can use [FakeTimeProvider](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.time.testing.faketimeprovider) of Microsoft.Extensions.TimeProvider.Testing. + +Additionally, in R3, there is a collection called LiveList, which allows you to obtain subscription statuses as a list. Combining these two features can be very useful for unit testing. + +```csharp +var fakeTime = new FakeTimeProvider(); + +var list = Observable.Timer(TimeSpan.FromSeconds(5), fakeTime).ToLiveList(); + +fakeTime.Advance(TimeSpan.FromSeconds(4)); +list.AssertIsNotCompleted(); + +fakeTime.Advance(TimeSpan.FromSeconds(1)); +list.AssertIsCompleted(); +list.AssertEqual([Unit.Default]); +``` + +For FrameProvider, a `FakeFrameProvider` is provided as standard, and it can be used in the same way as `FakeTimeProvider`. + +```csharp +var cts = new CancellationTokenSource(); +var frameProvider = new FakeFrameProvider(); + +var list = Observable.EveryUpdate(frameProvider, cts.Token) + .Select(_ => frameProvider.GetFrameCount()) + .ToLiveList(); + +list.AssertEqual([]); // list.ShouldBe(expected); + +frameProvider.Advance(); +list.AssertEqual([0]); + +frameProvider.Advance(3); +list.AssertEqual([0, 1, 2, 3]); + +cts.Cancel(); +list.AssertIsCompleted(); // list.IsCompleted.ShouldBeTrue(); + +frameProvider.Advance(); +list.AssertEqual([0, 1, 2, 3]); +list.AssertIsCompleted(); +``` + +`AssertEqual` is a test helper. You can create your own helper to use with the test library. + +```csharp +public static class LiveListExtensions +{ + // Shouldbe() is xUnit + Shouldly + public static void AssertEqual(this LiveList list, params T[] expected) + { + list.ShouldBe(expected); + } + + public static void AssertEqual(this LiveList list, params T[][] expected) + { + list.Count.ShouldBe(expected.Length); + + for (int i = 0; i < expected.Length; i++) + { + list[i].ShouldBe(expected[i]); + } + } + + public static void AssertEmpty(this LiveList list) + { + list.Count.ShouldBe(0); + } + + public static void AssertIsCompleted(this LiveList list) + { + list.IsCompleted.ShouldBeTrue(); + } + + public static void AssertIsNotCompleted(this LiveList list) + { + list.IsCompleted.ShouldBeFalse(); + } + + public static void Advance(this FakeTimeProvider timeProvider, int seconds) + { + timeProvider.Advance(TimeSpan.FromSeconds(seconds)); + } +} +``` + +Interoperability with `IObservable` +--- +`Observable` is not `IObservable`. You can convert both by these methods. + +* `public static Observable ToObservable(this IObservable source)` +* `public static IObservable AsSystemObservable(this Observable source)` + +Interoperability with `async/await` +--- +R3 has special integration with `async/await`. First, all methods that return a single asynchronous operation have now become ***Async methods, returning `Task`. + +Methods that convert to such `Task` (for example `FirstAsync`, `LastAsync`) transform OnErrorResume's Exception into a Faulted Task, similar to OnCompleted(Exception). Note that since the Catch operator does not capture OnErrorResume, if you want integrated error handling, please use `OnErrorResumeAsFailure()` to convert `OnErrorResume(Exception)` to `OnCompleted(Exception)`. + +Furthermore, you can specify special behaviors when asynchronous methods are provided to Where/Select/Subscribe. + +| Name | ReturnType | +| --- | --- | +| **SelectAwait**(this `Observable` source, `Func>` selector, `AwaitOperation` awaitOperation = AwaitOperation.Sequential, `bool` configureAwait = true, `bool` cancelOnCompleted = true, `int` maxConcurrent = -1) | `Observable` | +| **WhereAwait**(this `Observable` source, `Func>` predicate, `AwaitOperation` awaitOperation = AwaitOperation.Sequential, `bool` configureAwait = true, `bool` cancelOnCompleted = true, `int` maxConcurrent = -1) | `Observable` | +| **SubscribeAwait**(this `Observable` source, `Func` onNextAsync, `AwaitOperation` awaitOperation = AwaitOperation.Sequential, `bool` configureAwait = true, `bool` cancelOnCompleted = true, `int` maxConcurrent = -1) | `IDisposable` | +| **SubscribeAwait**(this `Observable` source, `Func` onNextAsync, `Action` onCompleted, `AwaitOperation` awaitOperation = AwaitOperation.Sequential, `bool` configureAwait = true, `bool` cancelOnCompleted = true, `int` maxConcurrent = -1) | `IDisposable` | +| **SubscribeAwait**(this `Observable` source, `Func` onNextAsync, `Action` onErrorResume, `Action` onCompleted, `AwaitOperation` awaitOperation = AwaitOperation.Sequential, `bool` configureAwait = true, `bool` cancelOnCompleted = true, `int` maxConcurrent = -1) | `IDisposable` | + +```csharp +public enum AwaitOperation +{ + /// All values are queued, and the next value waits for the completion of the asynchronous method. + Sequential, + /// Drop new value when async operation is running. + Drop, + /// If the previous asynchronous method is running, it is cancelled and the next asynchronous method is executed. + Switch, + /// All values are sent immediately to the asynchronous method. + Parallel, + /// All values are sent immediately to the asynchronous method, but the results are queued and passed to the next operator in order. + SequentialParallel, + /// Send the first value and the last value while the asynchronous method is running. + ThrottleFirstLast +} +``` + +```csharp +// for example... +// Drop enables prevention of execution by multiple clicks +button.OnClickAsObservable() + .SelectAwait(async (_, ct) => + { + var req = await UnityWebRequest.Get("https://google.com/").SendWebRequest().WithCancellation(ct); + return req.downloadHandler.text; + }, AwaitOperation.Drop) + .SubscribeToText(text); +``` + +`maxConcurrent` is only effective for `Parallel` and `SequentialParallel`, allowing control over the number of parallel operations. By default, it allows unlimited parallelization. + +`cancelOnCompleted` lets you choose whether to cancel the ongoing asynchronous method (by setting CancellationToken to Cancel) when the `OnCompleted` event is received. The default is true, meaning it will be cancelled. If set to false, it waits for the completion of the asynchronous method before calling the subsequent `OnCompleted` (potentially after issuing OnNext, depending on the case). + +Additionally, the following time-related filtering/aggregating methods can also accept asynchronous methods. + +| Name | ReturnType | +| --- | --- | +| **Debounce**(this `Observable` source, `Func` throttleDurationSelector, `Boolean` configureAwait = true) | `Observable` | +| **ThrottleFirst**(this `Observable` source, `Func` sampler, `Boolean` configureAwait = true) | `Observable` | +| **ThrottleLast**(this `Observable` source, `Func` sampler, `Boolean` configureAwait = true) | `Observable` | +| **ThrottleFirstLast**(this `Observable` source, `Func` sampler, `Boolean` configureAwait = true) | `Observable` | +| **SkipUntil**(this `Observable` source, `CancellationToken` cancellationToken) | `Observable` | +| **SkipUntil**(this `Observable` source, `Task` task) | `Observable` | +| **SkipUntil**(this `Observable` source, `Func` asyncFunc, `Boolean` configureAwait = true) | `Observable` | +| **TakeUntil**(this `Observable` source, `CancellationToken` cancellationToken) | `Observable` | +| **TakeUntil**(this `Observable` source, `Task` task) | `Observable` | +| **TakeUntil**(this `Observable` source, `Func` asyncFunc, `Boolean` configureAwait = true) | `Observable` | +| **Chunk**(this `Observable` source, `Func` asyncWindow, `Boolean` configureAwait = true) | `Observable` | + +For example, by using the asynchronous function version of Chunk, you can naturally and easily write complex processes such as generating chunks at random times instead of fixed times. + +```csharp +Observable.Interval(TimeSpan.FromSeconds(1)) + .Index() + .Chunk(async (_, ct) => + { + await Task.Delay(TimeSpan.FromSeconds(Random.Shared.Next(0, 5)), ct); + }) + .Subscribe(xs => + { + Console.WriteLine(string.Join(", ", xs)); + }); +``` +These asynchronous methods are immediately canceled when `OnCompleted` is issued, and the subsequent `OnCompleted` is executed. + +By utilizing async/await for Retry-related operations, you can achieve better handling. For instance, whereas the previous version of Rx could only retry the entire pipeline, with R3, which accepts async/await, it is possible to retry on a per asynchronous method execution basis. + +```csharp +button.OnClickAsObservable() + .SelectAwait(async (_, ct) => + { + var retry = 0; + AGAIN: + try + { + var req = await UnityWebRequest.Get("https://google.com/").SendWebRequest().WithCancellation(ct); + return req.downloadHandler.text; + } + catch + { + if (retry++ < 3) goto AGAIN; + throw; + } + }, AwaitOperation.Drop) +``` + +Repeat can also be implemented in combination with async/await. In this case, handling complex conditions for Repeat might be easier than completing it with Rx alone. + +```csharp +while (!ct.IsCancellationRequested) +{ + await button.OnClickAsObservable() + .Take(1) + .ForEachAsync(_ => + { + // do something + }); +} +``` + +Concurrency Policy +--- +The composition of operators is thread-safe, and it is expected that the values flowing through OnNext are on a single thread. In other words, if OnNext is issued on multiple threads, the operators may behave unexpectedly. This is the same as with dotnet/reactive. + +For example, while Subject itself is thread-safe, the operators are not thread-safe. + +```csharp +// dotnet/reactive +var subject = new System.Reactive.Subjects.Subject(); + +// single execution shows 100 but actually 9* multiple times(broken) +subject.Take(100).Count().Subscribe(x => Console.WriteLine(x)); + +Parallel.For(0, 1000, new ParallelOptions { MaxDegreeOfParallelism = 10 }, x => subject.OnNext(x)); +``` + +This means that the issuance of OnNext must always be done on a single thread. For converting external inputs into Observables, such as with `FromEvent`, and when the source of input issues in a multi-threaded manner, it is necessary to synchronize using `Synchronize` to construct the correct operator chain. + +```csharp +subject.Synchronize(gate).Take(100).Count().Subscribe(); +``` + +Unlike dotnet/reactive, R3.Subject.OnNext is not ThreadSafe. If you are calling OnNext from multiple threads, please use a lock. + +In R3, ReplaySubject and BehaviorSubject do not require Synchronize and are thread-safe, including OnNext. + +ReactiveProperty is not thread-safe and OnNext, set Value and Subscribe cannot be called simultaneously. If you need to use it in such a situation, use `SynchronizedReactiveProperty` instead. + +```csharp +class MyClass +{ + public SynchronizedReactiveProperty Prop { get; } = new(); +} +``` + +Sampling Timing +--- +The `Sample(TimeSpan)` in dotnet/reactive starts a timer in the background when subscribed to, and uses that interval for filtering. Additionally, the timer continues to run in the background indefinitely. + +`ThrottleFirst/Last/FirstLast(TimeSpan)` in R3 behaves differently; the timer is stopped upon subscription and only starts when a value arrives. If the timer is stopped at that time, it starts, and then stops the timer after the specified duration. + +Also, overloads that accept an asynchronous function `Func`, such as `ThrottleFirst/Last/FirstLast`, `Chunk`, `SkipUntil`, `TakeUntil`), behave in such a way that if the asynchronous function is not running when a value arrives, the execution of the asynchronous function begins. + +This change is expected to result in consistent behavior across all operators. + +ObservableCollections +--- +As a special collection for monitoring changes in collections and handling them in R3, the [ObservableCollections](https://github.com/Cysharp/ObservableCollections)'s `ObservableCollections.R3` package is available. + +It has `ObservableList`, `ObservableDictionary`, `ObservableHashSet`, `ObservableQueue`, `ObservableStack`, `ObservableRingBuffer`, `ObservableFixedSizeRingBuffer` and these observe methods. + +```csharp +Observable> IObservableCollection.ObserveAdd() +Observable> IObservableCollection.ObserveRemove() +Observable> IObservableCollection.ObserveReplace() +Observable> IObservableCollection.ObserveMove() +Observable> IObservableCollection.ObserveReset() +``` + +XAML Platforms(`BindableReactiveProperty`) +--- +For XAML based application platforms, R3 provides `BindableReactiveProperty` that can bind observable property to view like [Android LiveData](https://developer.android.com/topic/libraries/architecture/livedata) and [Kotlin StateFlow](https://developer.android.com/kotlin/flow/.stateflow-and-sharedflow). It implements [INotifyPropertyChanged](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.inotifypropertychanged) and [INotifyDataErrorInfo](https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.inotifydataerrorinfo). + +Simple usage, expose `BindableReactiveProperty` via `new` or `ToBindableReactiveProperty`. + +Here is the simple In and Out BindableReactiveProperty ViewModel, Xaml and code-behind. In xaml, `.Value` to bind property. + +```csharp +public class BasicUsagesViewModel : IDisposable +{ + public BindableReactiveProperty Input { get; } + public BindableReactiveProperty Output { get; } + + public BasicUsagesViewModel() + { + Input = new BindableReactiveProperty(""); + Output = Input.Select(x => x.ToUpper()).ToBindableReactiveProperty(""); + } + + public void Dispose() + { + Disposable.Dispose(Input, Output); + } +} +``` + +```xml + + + + + + + + + +``` + +```csharp +namespace WpfApp1; + +public partial class MainWindow : Window +{ + public MainWindow() + { + InitializeComponent(); + } + + protected override void OnClosed(EventArgs e) + { + (this.DataContext as IDisposable)?.Dispose(); + } +} +``` + +![image](https://github.com/Cysharp/R3/assets/46207/01c3738f-e941-412e-b517-8e7867d6f709) + +BindableReactiveProperty also supports validation via DataAnnotation or custom logic. If you want to use DataAnnotation attribute, require to call `EnableValidation()` in field initializer or `EnableValidation(Expression selfSelector)` in constructor. + +```csharp +public class ValidationViewModel : IDisposable +{ + // Pattern 1. use EnableValidation to enable DataAnnotation validation in field initializer + [Range(0.0, 300.0)] + public BindableReactiveProperty Height { get; } = new BindableReactiveProperty().EnableValidation(); + + [Range(0.0, 300.0)] + public BindableReactiveProperty Weight { get; } + + IDisposable customValidation1Subscription; + public BindableReactiveProperty CustomValidation1 { get; set; } + + public BindableReactiveProperty CustomValidation2 { get; set; } + + public ValidationViewModel() + { + // Pattern 2. use EnableValidation(Expression) to enable DataAnnotation validation + Weight = new BindableReactiveProperty().EnableValidation(() => Weight); + + // Pattern 3. EnableValidation() and call OnErrorResume to set custom error message + CustomValidation1 = new BindableReactiveProperty().EnableValidation(); + customValidation1Subscription = CustomValidation1.Subscribe(x => + { + if (0.0 <= x && x <= 300.0) return; + + CustomValidation1.OnErrorResume(new Exception("value is not in range.")); + }); + + // Pattern 4. simplified version of Pattern3, EnableValidation(Func) + CustomValidation2 = new BindableReactiveProperty().EnableValidation(x => + { + if (0.0 <= x && x <= 300.0) return null; // null is no validate result + return new Exception("value is not in range."); + }); + } + + public void Dispose() + { + Disposable.Dispose(Height, Weight, CustomValidation1, customValidation1Subscription, CustomValidation2); + } +} +``` + +```xml + + + + + + + + +``` + +![image](https://github.com/Cysharp/R3/assets/46207/f80149e6-1573-46b5-9a77-b78776dd3527) + +Validation using `EnableValidation` does not trigger for initial values by default. This means that even if you don't allow empty strings, the validation error won't appear for an initially empty value. If you want to perform validation on initial values, you can call `ForceValidate()` after `EnableValidation`. + +```csharp +Weight = new BindableReactiveProperty() + .EnableValidation(() => Weight) + .ForceValidate(); +``` + +There is also `IReadOnlyBindableReactiveProperty`, which is preferable when ReadOnly is required in binding, can create from `IObservable.ToReadOnlyBindableReactiveProperty`. + +### ReactiveCommand + +`ReactiveCommand` and `ReactiveCommand` are observable [ICommand](https://learn.microsoft.com/en-us/dotnet/api/system.windows.input.icommand) implementation. It can create from `Observable canExecuteSource`. + +```csharp +public class CommandViewModel : IDisposable +{ + public BindableReactiveProperty OnCheck { get; } // bind to CheckBox + public ReactiveCommand ShowMessageBox { get; } // bind to Button, non generics ReactiveCommand is ReactiveCommand + + public CommandViewModel() + { + OnCheck = new BindableReactiveProperty(); + ShowMessageBox = OnCheck.ToReactiveCommand(_ => + { + MessageBox.Show("clicked"); + }); + } + + public void Dispose() + { + Disposable.Dispose(OnCheck, ShowMessageBox); + } +} +``` + +```xml + + + + + +