- Fix for maintaining foldout state in ServiceKitWindow
- Fix for services registered in addressable scenes being listed under DoNotDestroy in the ServiceKit Window
- Added an early return to ServiceKitBehaviour.IsServiceLocatorMissing when the application is quitting
- Deleted a test with an invalid meta file
-
TOCTOU Race Condition in Optional Dependencies: Fixed critical race condition in optional dependency resolution
- Previously used separate IsServiceReady() and GetService() calls which weren't atomic
- Service could be unregistered between the check and get operations (e.g., during scene unload)
- This caused InitializeService to be called with null optional dependencies despite services being ready
- Fixed by using atomic TryGetService() operation that checks and gets under a single lock
- Eliminates race condition where ServiceB's InitializeService could be called with null ServiceA
-
Services Not Injected on Ignored Cancellation: Fixed critical bug where resolved services were not injected when cancellation was ignored
- When application quits or ShouldIgnoreCancellation returns true, ExecuteAsync would return early without injecting already-resolved services
- This caused InitializeService to be called with null dependencies even though services were successfully resolved
- Fixed by ensuring resolved services are always injected before returning, even when cancellation is ignored
-
Awake Order Race Condition for Optional Dependencies: Fixed race condition where optional dependencies were incorrectly treated as absent
- When ServiceA with optional dependency on ServiceB had its Awake() called before ServiceB's Awake(), ServiceB would be null
- This occurred because Unity's Awake order is non-deterministic within a scene
- ServiceA would check for ServiceB before ServiceB had a chance to register itself
- Fixed by adding a one-frame delay when optional dependencies are not registered, allowing all services in the scene to complete their Awake phase
- Now correctly distinguishes between "not registered yet" and "truly absent" optional dependencies
- Code Quality: Enhanced code standards and self-documentation
- Renamed methods for clarity (e.g., WaitForAwakePhaseCompletion)
- Removed redundant comments and debug logging
- Extracted complex logic into well-named helper methods
- Improved overall code maintainability and readability
- Optional Dependency Race Condition: Fixed critical bug in optional dependency resolution
- Optional dependencies marked with
Required = falsethat were registered but not ready now correctly wait for the service - Previously, multiple waiters for the same service could interfere with each other's cancellation tokens
- Fixed by implementing per-caller TaskCompletionSource to isolate cancellation behavior
- This ensures the documented 3-state intelligent resolution works correctly:
- Service ready → inject immediately
- Service registered but not ready → wait for it (treat as temporarily required)
- Service not registered → skip injection (field remains null)
- Optional dependencies marked with
- Code Quality: Enhanced ServiceInjectionBuilder for better maintainability
- Extracted timeout exception building into well-named helper methods
- Improved self-documentation with clear method names
- Added explicit comments explaining optional dependency behavior
- Removed debug logging and simplified async service resolution
- Removed performance tests as they had corrupted meta files
-
Memory Performance Optimizations: Comprehensive memory allocation improvements
- Added
ServiceKitObjectPoolfor object pooling of Lists and StringBuilders - Eliminated LINQ allocations in hot paths (GetAllServices, GetServicesWithTag, etc.)
- Replaced string concatenation with pooled StringBuilder usage
- Added pre-allocated lists for batch operations in TimeoutManager
- Zero-allocation service resolution for cached services
- Added
-
Memory Performance Tests: New comprehensive test suite for memory profiling
MemoryAllocationTrackerutility for precise allocation measurementServiceKitMemoryPerformanceTestsfor core operation allocation testingLinqVsOptimizedComparisonTestscomparing LINQ vs optimized implementationsServiceKitMemoryBenchmarkRunnerfor automated benchmark execution with CSV export
- Runtime Exit Errors: Fixed ServiceKitTimeoutManager cleanup issues
- Resolved "objects were not cleaned up" warning when exiting Play Mode
- Fixed timeout exceptions being thrown during application quit
- Added proper cleanup in OnDestroy, OnApplicationQuit, and editor mode transitions
- Enhanced ServiceKitPlayModeHandler to properly clean up on exit
-
Code Standards: Enhanced self-documenting code throughout
- Refactored ServiceKitTimeoutManager with descriptive method names
- Improved ServiceKitBehaviour with better encapsulation
- Enhanced ServiceKitObjectPool with generic helper methods
- Consistent preprocessor directive formatting (no indentation)
- Better separation of concerns with extracted helper methods
-
Performance: Significant reduction in runtime allocations
- GetService: Now allocation-free for cached services
- IsServiceReady: Zero allocations
- GetAllServices: Reduced allocations by ~70% through pooling
- String operations: 90% reduction through StringBuilder pooling
- ServiceKitBehaviour API Changes: Renamed methods and fields for improved self-documenting code
- Protected Fields:
Registered→IsServiceRegisteredReady→IsServiceReady
- Protected Methods:
RegisterService()→RegisterServiceWithLocator()UnregisterService()→UnregisterServiceFromLocator()InjectServicesAsync()→InjectDependenciesAsync()MarkServiceReady()→MarkServiceAsReady()OnServiceInjectionFailed()→HandleDependencyInjectionFailure()
- Protected Fields:
- Code Quality: Major refactoring for self-documenting code
- All method names now clearly express their intent
- Improved variable naming throughout the codebase
- Extracted helper methods for better separation of concerns
- Enhanced readability following Microsoft C# coding guidelines
- Simplified cancellation token handling using Unity's built-in
destroyCancellationToken
See the README.md for detailed migration instructions from v1.x to v2.0
- Edit Mode Test Compatibility: Fixed DontDestroyOnLoad error in ServiceKitTimeoutManager during Edit Mode tests
- Added conditional compilation to only call DontDestroyOnLoad in Play Mode
- Ensures ServiceKitTimeoutManager works correctly in Edit Mode tests, Play Mode, and built applications
- Test Coverage: Added comprehensive test for InitializeService timing with optional dependencies
- Verifies that InitializeService waits for all registered dependencies (even optional ones) to become ready
- Confirms 3-state dependency resolution behavior is working as designed
- Compilation Error: Fixed CS0246 error in ServiceKitThreading.cs when SERVICEKIT_UNITASK is not defined
- Added conditional using statements to properly import System.Threading.Tasks namespace
- Ensures Task type is available in both UniTask and standard .NET Task scenarios
- Code Quality: Comprehensive coding standards review and refactoring
- Applied "never nesting" principle - eliminated all nested if statements with early returns and guard clauses
- Enhanced self-documenting code with clear, action-oriented method names
- Applied SOLID principles with improved Single Responsibility adherence
- Better separation of concerns in ServiceInjectionBuilder, ServiceKitLocator, and ServiceKitBehaviour
- Improved method names and variable naming for better code readability
- No functional changes - purely internal code quality improvements
- Intelligent 3-State Dependency Resolution: Enhanced
InjectServiceattribute with smart behavior whenRequired = false- Service is ready → Inject immediately
- Service is registered but not ready → Wait for it (treat as required temporarily)
- Service is not registered → Skip injection (field remains null)
- Comprehensive test coverage for all three dependency resolution states
- Mixed scenario testing for complex dependency graphs
- BREAKING CHANGE: Enhanced
Required = falsebehavior - now uses intelligent resolution instead of simple ready-check - Updated
InjectServiceAttributedocumentation to reflect new 3-state behavior - Updated README.md with detailed explanation of intelligent dependency resolution
- Eliminates guesswork in optional dependency management
- More predictable behavior for developers
- Better handling of services that are "coming soon" vs "never coming"
- Maintains backward compatibility for
Required = true(default behavior unchanged)
- Improved error handling for service registration failures
- Enhanced null service detection to identify missing interface implementations
- Added detailed error messages showing which interfaces a ServiceKitBehaviour failed to implement
- ServiceKitBehaviour now provides proactive error checking before attempting registration
- Hotfix added the ExecuteWithCancellationAsync method to the IServiceInjectionBuilder
- hotfix to remove the hidden tools directory. The content has been moved to it's own repo for ServiceKit Roslyn Analyzers
- updated the path to retrieve the Roslyn Analyzers dll to always pull the latest.
- Abstracted some functionality out of the ServiceInjectionBuilder as it was bloated
- Added a convieniance method to execute and cancel a services injection request.
- Updated package path in README
- Hotfix for race condition in ServiceKitTimeoutManager
- Added tests for race condition
- Added performance tests
- Added documentation on performance
- Changed the define for Unitask inclusion from INCLUDE_UNITASK to SERVICEKIT_UNITASK
- Added UniTask support for performance gains out of the box
- Added support for service tags
- Updated the ServiceKitServicesTab to use the same logic as ServiceKitLocatorDrawer to select the ServiceKitLocator.
- Enhanced the ServiceKitLocatorDrawer to assign the ServiceKitLocator without having to look at the component in the inspector.
- Also improved how the instance of ServiceKitLocator is selected. By default it will now select the instance in the package unless ServiceKitSettings provide an alternative.
- Enhanced circular dependency detection to detect circular dependencies created later in the registration process.
- Services that encounter circular dependencies will be highlighted red in the ServiceKit Window with a warning icon and tooltip explaining the issue.
- Added an infinite icon to the ServiceItems displayed in the ServiceKit Window. The icon is coloured when circular dependency detection is enabled for the service and greyed out when detection is disabled.
- Added tooltip to the infinite icon to explain the meaning.
- As the ServiceKitLocator is a ScriptableObject it is capable of persisting state in Editor. I've added the ServiceKitPlayModeHandler to cleanup the state of the ServiceKitLocator when exiting play mode in editor.
- ServiceKit Windowe now shows the registration status of each service
- Fix for icon pathing issues when package loaded via package manager
- Added circular dependency detection
- Simplified the use of ServiceKitBehaviour
- Switched to a 2 phase injection process
- Updated the ServiceInjectionBuilders GetFieldsToInject method which only looks at the specific type passed to it but will now walk up the inheritance hierarchy and inject parents
- Added additional tests for this scenario
- Updated the ServiceInjectionBuilder to introduce the ServiceKitTimeoutManager which provides a revised timeout system that respects timescale and provides more insightful error messages.
- ServiceKitBehaviour now calls OnRegister in OnDestroy
- Made the OnServicesInjected method abstract
- Moved the ServiceKitProjectSettings into the Editor folder to prevent it being included in builds
- Removed use of ScriptableSingleton in Settings because it's an Editor only class