- Package failed to compile in projects without ServiceKit installed (using directive outside the define guard)
- Recurring milestones now re-trigger when the timer is restarted with
StartTimer()alone, not just afterResetTimer() - Milestones sharing a numeric trigger value across different TimeTypes no longer fire together
- Progress-based range milestones no longer skip intervals on timers shorter than 1 second
TimerRangeMilestonenow throwsArgumentOutOfRangeExceptionfor zero or negative intervals (previously an infinite loop)
- ServiceKit version constraint: Lowered the
TIMERKIT_SERVICEKIT_SUPPORTversion define floor from2.4.0to2.0.0. ServiceKit has only released up to 2.0.2, so the previous constraint meant the ServiceKit extension (BaseTimerService,ITimerService, etc. underNonatomic.TimerKit.Extensions.ServiceKit) never compiled in consumer projects. Projects on ServiceKit 2.0.x can now derive fromBaseTimerServiceas documented.
- ServiceKit V2 Compatibility: Migrated to ServiceKit 2.0 attribute-based registration
BaseTimerServiceis now non-generic (wasBaseTimerService<T>)- Concrete timer services use
[Service(typeof(ITimerService))]attribute - Updated lifecycle methods to match ServiceKit 2.0 conventions
- ServiceKit version constraint bumped to 2.4.0+
- Zero-Allocation Milestone Processing: Complete rewrite of milestone system for allocation-free per-frame updates
- Replaced all
foreachloops with index-based iteration to avoid enumerator allocations - Pooled all temporary collections at class level (HashSet, List) to eliminate per-frame allocations
- Converted tuple-returning methods to use
outparameters to avoid boxing - Removed LINQ dependency (
System.Linq) from MilestoneTimer
MilestoneTimer.Update()now allocates 0 bytes per frame (previously ~160-200 bytes)ProcessAllTriggeredMilestones()allocates 0 bytes (previously ~104 bytes)CheckAndTriggerMilestones()allocates 0 bytes with early exit when no milestones exist- Milestone triggering allocates 0 bytes per trigger
- Range milestone processing allocates 0 bytes
- Early exit optimization in
CheckAndTriggerMilestones()when no milestones are registered - Comprehensive allocation test suite (EditMode and PlayMode) to prevent performance regressions
- Convenience API for AddMilestone: New overload accepting milestone components directly
AddMilestone(TimeType type, float triggerValue, Action callback, bool isRecurring = false)method- Consistent API pattern - both TimerMilestone and TimerRangeMilestone now support component-based creation
- 9 comprehensive tests for convenience API covering all TimeTypes, recurring behavior, and equivalence with manual creation
- ITimer interface extended with new AddMilestone overload
- Null reference errors when timer methods or properties accessed before Unity lifecycle initialization
- Added lazy initialization to all Timer and BaseTimerService methods and properties
- OnDisable now safely handles cases where timer is not yet initialized
- TimerLifecycleTests with 24 tests verifying safe access at any Unity lifecycle point
- Tests cover ResetTimer, StartTimer, properties, milestones, and all timer operations before/after Awake/OnEnable
- OnDurationChanged Event: New event triggered when timer Duration property is modified, providing the new duration value
- Event implemented across all timer classes (BasicTimer, Timer, MilestoneTimer, StandardTimer) and service wrappers
- Comprehensive test coverage for OnDurationChanged event behavior including multiple subscribers and edge cases
- Recurring milestones triggering multiple times per round due to premature re-addition to trigger lookup
- Indentation issue in MilestoneTimer.cs where nested if statements were not properly aligned
- Recurring regular milestones now trigger exactly once per timer round instead of multiple times
- Fixed issue where recurring milestones would trigger multiple times during a single Update() call
- Added
ResetRecurringRegularMilestones()to properly re-add recurring milestones only when timer resets
- Milestones now only trigger when timer is actively running (IsRunning = true)
- Recurring regular milestones are removed from trigger lookup after triggering and re-added on timer reset
- Added 7 tests verifying milestones don't trigger when timer is not running or stopped
- Added tests for FastForward/Rewind behavior when timer is not running
- Added test verifying milestones trigger correctly after ResumeTimer()
- Added de-duplication logic in milestone processing to prevent duplicate triggers
- Recurring Milestones: New
IsRecurringflag for milestones that persist across timer resets - Recurring milestones automatically reset and re-trigger in each timer round
- Added
isRecurringparameter toAddRangeMilestone()method with default valuefalse - Comprehensive tests for recurring milestone behavior across multiple timer rounds
- BREAKING: Updated
AddRangeMilestone()signature to include optionalisRecurringparameter - BREAKING: Updated
ITimerinterface to includeisRecurringparameter - Range milestones with
IsRecurring=trueare automatically reset when timer resets - Non-recurring milestones (default) are removed after triggering as before
- Added tests verifying callback time override works through base class and interface references
- Added tests for all overridden time properties (TimeRemaining, TimeElapsed, ProgressElapsed, ProgressRemaining)
- Added test verifying callback override is properly restored after callback execution
- BREAKING: Made TimeRemaining, TimeElapsed, ProgressElapsed, and ProgressRemaining properties virtual in BasicTimer
- Changed MilestoneTimer property hiding (
new) to proper polymorphic override (override) - This fixes an issue where callback time overrides weren't working through service wrapper chains
- Range milestone callbacks now correctly report interval values when accessed through ITimer interface or service wrappers
- VoiceOverCountdownService and similar implementations now receive correct TimeRemaining values in callbacks
- Range milestones now trigger at correct interval values when crossing multiple intervals in a single Update
- Range milestones no longer trigger outside their defined range boundaries
- Added callback time override mechanism so callbacks see the interval value that triggered them
- Added iteration limit safeguard to prevent infinite loops in milestone processing
- TimeSourceProvider now works with any component implementiAdd tests
- ng
ITimerinterface, not just the concreteTimerMonoBehaviour - Removed
RequireComponent(typeof(Timer))attribute from TimeSourceProvider for greater flexibility - TimeSourceProvider now gracefully handles ITimer implementations that don't support SetTimeSource
- TimeSourceExamples.cs removed from package as it was project-specific
- ITimeSource Interface: New interface for external time synchronization, allowing timers to use custom time sources
- TimeSourceProvider Component: Abstract MonoBehaviour that automatically connects to Timer components as their time source
- preserveTimeSourceValue Parameter: New optional parameter in timer constructors to preserve existing time source values when connecting
- Comprehensive tests for ITimeSource functionality and TimeSourceProvider integration
- All timer constructors now accept optional ITimeSource parameter for external time synchronization
- Timer.SetTimeSource() method now preserves time source values by default when connecting providers
- Improved code organization with extracted helper methods for better readability and maintainability
- Enhanced variable naming throughout codebase for better self-documentation:
processedMilestones→alreadyTriggeredMilestonesnextTriggerValue→lowestUnprocessedTriggerValueidsToRemove→exhaustedMilestoneIdsrangeMilestonesToReAdd→recurringMilestones
- Code now better adheres to SOLID principles with smaller, focused methods
- Removed unnecessary explanatory comments in favor of self-documenting code
- Fixed typos and improved documentation clarity
- Extracted complex logic into well-named helper methods in MilestoneTimer
- Hotfix for ServiceKit update
- The Timers package has been renamed to TimerKit
- Added ServiceKit support
- No longer in beta
- Range Milestones: New
TimerRangeMilestoneclass for triggering events at regular intervals within a time range - New Timer Architecture: Introduced
BasicTimer,MilestoneTimer, andStandardTimerfor better separation of concerns - Interface Segregation: Added
IBasicTimerinterface for basic timer operations - AddRangeMilestone() method to all timer interfaces and implementations
- Comprehensive milestone edge case handling (self-removal, dynamic addition, multiple milestones with same trigger value)
- Enhanced test coverage for complex milestone scenarios
- BREAKING:
SimpleTimeris now deprecated in favor ofStandardTimer(backward compatible with obsolete warning) - Refactored timer inheritance hierarchy:
BasicTimer→MilestoneTimer→StandardTimer ITimerinterface now inherits fromIBasicTimerfor better interface segregation- Updated all internal references to use
StandardTimerinstead ofSimpleTimer - Improved milestone processing to handle complex interaction scenarios
- Enhanced self-documenting code patterns throughout codebase
- Multiple milestones with the same trigger value now all execute correctly
- Milestone self-removal during callback execution no longer causes issues
- Dynamic milestone addition during milestone execution now works properly
- Range milestone reset functionality now works correctly after timer reset
SimpleTimerclass is deprecated; useStandardTimerinstead (maintains full backward compatibility)
No breaking changes - existing code continues to work unchanged.
For new projects, prefer:
BasicTimerfor simple timing needsMilestoneTimerwhen you need milestone supportStandardTimerfor full functionality (recommended)- Replace
new SimpleTimer()withnew StandardTimer()when convenient
- Removed empty assembly
- Fix for Milestones triggering milestone removal during iteration
- Added support for multiple Milestones with the same time rather than overwriting the previous one
- Added call to ResetTimer in the constructor so the TimeRemaining is set to the duration of the timer
- Fix for missing pre processor flag in the TimerService class
- Removed Obsolete Milestone methods
- Added a new interface for the BaseTimerService this allows derived timers to limit the exposed elements of the timer
- Made a BaseTimerService that is easier to inherit from
- Fix: Forgot to add Rewind and FastForward to the ITimer interface and the TimerService
- Exposed SimpleTimer functionality for Rewind and FastForward in the Timer class
- Reduced the ServiceLocator version support to 0.5.0
- Added extension support for ServiceLocator
- Optimized Milstones
- Added additional test for Milestone removal
- Adjust namespace to be more consistent with other Nonatomic packages
- First commit