Oolite 1.91.0.7604-240417-a536cbe
Loading...
Searching...
No Matches
OOScriptTimer.m
Go to the documentation of this file.
1/*
2
3OOScriptTimer.m
4
5
6Oolite
7Copyright (C) 2004-2013 Giles C Williams and contributors
8
9This program is free software; you can redistribute it and/or
10modify it under the terms of the GNU General Public License
11as published by the Free Software Foundation; either version 2
12of the License, or (at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22MA 02110-1301, USA.
23
24*/
25
26#import "OOScriptTimer.h"
27#import "Universe.h"
28#import "OOLogging.h"
29#import "OOPriorityQueue.h"
30
31
33
34// During an update, new timers must be deferred to avoid an infinite loop.
35static BOOL sUpdating;
36static NSMutableArray *sDeferredTimers;
37
38
39@implementation OOScriptTimer
40
41- (id) initWithNextTime:(OOTimeAbsolute)nextTime
42 interval:(OOTimeDelta)interval
43{
45
46 if ((self = [super init]))
47 {
48 if (interval <= 0.0) interval = -1.0;
49
50 now = [UNIVERSE getTime];
51 if (nextTime < 0.0) nextTime = now + interval;
52 if (nextTime < now && interval < 0)
53 {
54 // Negative or old nextTime and negative interval = meaningless.
55 [self release];
56 self = nil;
57 }
58 else
59 {
62 _hasBeenRun = NO;
63 }
64 }
65
66 return self;
67}
68
69 // Sets nextTime to current time + delay.
70- (id) initOneShotTimerWithDelay:(OOTimeDelta)delay
71{
72 return [self initWithNextTime:[UNIVERSE getTime] + delay interval:-1.0];
73}
74
75
76- (void) dealloc
77{
78 if (_isScheduled) [self unscheduleTimer];
79
80 [super dealloc];
81}
82
83
84- (NSString *) descriptionComponents
85{
86 NSString *intervalDesc = nil;
87
88 if (_interval <= 0.0) intervalDesc = @"one-shot";
89 else intervalDesc = [NSString stringWithFormat:@"interval: %g", _interval];
90
91 return [NSString stringWithFormat:@"nextTime: %g, %@, %srunning", _nextTime, intervalDesc, _isScheduled ? "" : "not "];
92}
93
94
96{
97 return _nextTime;
98}
99
100
101- (BOOL)setNextTime:(OOTimeAbsolute)nextTime
102{
103 if (_isScheduled) return NO;
104
106 return YES;
107}
108
109
111{
112 return _interval;
113}
114
115
116- (void)setInterval:(OOTimeDelta)interval
117{
118 if (interval <= 0.0) interval = -1.0;
120}
121
122
123- (void) timerFired
124{
126}
127
128
129- (BOOL) scheduleTimer
130{
131 if (_isScheduled) return YES;
132 if (![self isValidForScheduling]) return NO;
133
134 if (EXPECT(!sUpdating))
135 {
136 if (EXPECT_NOT(sTimers == nil)) sTimers = [[OOPriorityQueue alloc] initWithComparator:@selector(compareByNextFireTime:)];
137 [sTimers addObject:self];
138 }
139 else
140 {
141 if (sDeferredTimers == nil) sDeferredTimers = [[NSMutableArray alloc] init];
142 [sDeferredTimers addObject:self];
143 }
144
145 _isScheduled = YES;
146 return YES;
147}
148
149
150- (void) unscheduleTimer
151{
152 [sTimers removeExactObject:self];
153 _isScheduled = NO;
154 _hasBeenRun = NO;
155}
156
157
158- (BOOL) isScheduled
159{
160 return _isScheduled;
161}
162
163
164+ (void) updateTimers
165{
166 OOScriptTimer *timer = nil;
167 OOTimeAbsolute now;
168
169 sUpdating = YES;
170
171 now = [UNIVERSE getTime];
172 for (;;)
173 {
174 timer = [sTimers peekAtNextObject];
175 if (timer == nil || now < [timer nextTime]) break;
176
177 [sTimers removeNextObject];
178
179 // Must fire before rescheduling so that the timer callback can stop itself. -- Ahruman 2011-01-01
180 [timer timerFired];
181
182 timer->_hasBeenRun = YES;
183
184 if (timer->_isScheduled)
185 {
186 timer->_isScheduled = NO;
187 [timer scheduleTimer];
188 }
189 }
190
191 if (sDeferredTimers != nil)
192 {
193 [sTimers addObjects:sDeferredTimers];
195 }
196
197 sUpdating = NO;
198}
199
200
201+ (void) noteGameReset
202{
203 NSArray *timers = nil;
204 NSEnumerator *timerEnum = nil;
205 OOScriptTimer *timer = nil;
206
207 // Intermediate array is required so we don't get stuck in an endless loop over reinserted timers. Note that -sortedObjects also clears the queue!
208 timers = [sTimers sortedObjects];
209 for (timerEnum = [timers objectEnumerator]; (timer = [timerEnum nextObject]); )
210 {
211 timer->_isScheduled = NO;
212 }
213}
214
215
217{
218 OOTimeAbsolute now;
219 double scaled;
220
221 now = [UNIVERSE getTime];
222 if (_nextTime <= now)
223 {
224 if (_interval <= 0.0 && _hasBeenRun) return NO; // One-shot timer which has expired
225
226 // Move _nextTime to the closest future time that's a multiple of _interval
227 scaled = (now - _nextTime) / _interval;
228 scaled = ceil(scaled);
229 _nextTime += scaled * _interval;
230 if (_nextTime <= now && _hasBeenRun)
231 {
232 // Should only happen if _nextTime is exactly equal to now after previous stuff
234 }
235 }
236
237 return YES;
238}
239
240- (NSComparisonResult) compareByNextFireTime:(OOScriptTimer *)other
241{
242 OOTimeAbsolute otherTime = -INFINITY;
243
244 @try
245 {
246 if (other != nil) otherTime = [other nextTime];
247 }
248 @catch (NSException *exception)
249 {
250 OOLog(kOOLogException, @"\n\n***** Ignoring Timer Exception: %@ : %@ *****\n\n",[exception name], [exception reason]);
251 }
252
253 if (_nextTime < otherTime) return NSOrderedAscending;
254 else if (_nextTime > otherTime) return NSOrderedDescending;
255 else return NSOrderedSame;
256}
257
258@end
#define DESTROY(x)
Definition OOCocoa.h:77
#define EXPECT_NOT(x)
#define EXPECT(x)
NSString *const kOOLogException
Definition OOLogging.m:651
#define OOLogGenericSubclassResponsibility()
Definition OOLogging.h:129
#define OOLog(class, format,...)
Definition OOLogging.h:88
return nil
static NSMutableArray * sDeferredTimers
static BOOL sUpdating
static OOPriorityQueue * sTimers
double OOTimeDelta
Definition OOTypes.h:224
double OOTimeAbsolute
Definition OOTypes.h:223
void removeExactObject:(id object)
void addObject:(id object)
void addObjects:(id collection)
NSArray * sortedObjects()
OOTimeAbsolute _nextTime
BOOL isValidForScheduling()
OOTimeDelta interval()
OOTimeDelta _interval
NSString * descriptionComponents()
OOTimeAbsolute nextTime()