Work on script timers.

git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@1172 127b21dd-08f5-0310-b4b7-95ae10353056
This commit is contained in:
Jens Ayton 2007-09-14 15:21:06 +00:00
parent e9dbb8d38e
commit 7b061ad0f7
6 changed files with 916 additions and 1 deletions

View File

@ -26,7 +26,7 @@ endif
OBJC_PROGRAM_NAME = oolite
oolite_C_FILES = legacy_random.c strlcpy.c
oolite_OBJC_FILES = Comparison.m AI.m DustEntity.m Entity.m GameController.m GuiDisplayGen.m HeadUpDisplay.m main.m MyOpenGLView.m OpenGLSprite.m ParticleEntity.m PlanetEntity.m PlayerEntityLegacyScriptEngine.m PlayerEntityContracts.m PlayerEntityControls.m PlayerEntityLoadSave.m PlayerEntitySound.m PlayerEntity.m ResourceManager.m RingEntity.m ShipEntityAI.m ShipEntity.m SkyEntity.m StationEntity.m Universe.m OOSound.m SDLMusic.m NSFileManagerOOExtensions.m JoystickHandler.m PlayerEntityStickMapper.m OOBasicSoundReferencePoint.m OOBasicSoundSource.m OOCharacter.m OOTrumble.m WormholeEntity.m NSScannerOOExtensions.m OOXMLExtensions.m NSMutableDictionaryOOExtensions.m Geometry.m Octree.m CollisionRegion.m OOColor.m OOLogging.m OOCacheManager.m OOCache.m OOStringParsing.m OOCollectionExtractors.m OOVector.m OOMatrix.m OOQuaternion.m OOVoxel.m OOTriangle.m OOPListParsing.m OOFastArithmetic.m OOTextureScaling.m OOConstToString.m OOScript.m OOJSScript.m OOJavaScriptEngine.m OOPListScript.m NSStringOOExtensions.m PlayerEntityScriptMethods.m OOWeakReference.m OOJSEntity.m EntityOOJavaScriptExtensions.m OOJSQuaternion.m OOMaterial.m OOShaderMaterial.m OOShaderProgram.m OOShaderUniform.m OOTexture.m OOTextureLoader.m OOPNGTextureLoader.m OOOpenGLExtensionManager.m OOBasicMaterial.m OOSingleTextureMaterial.m OOCPUInfo.m OOSelfDrawingEntity.m OOEntityWithDrawable.m OODrawable.m OOJSVector.m OOMesh.m OOOpenGL.m OOGraphicsResetManager.m OOProbabilisticTextureManager.m OODebugGLDrawing.m OOShaderUniformMethodType.m OOAsyncQueue.m TextureStore.m OOOXPVerifier.m OOOXPVerifierStage.m OOFileScannerVerifierStage.m OOCheckRequiresPListVerifierStage.m OOCheckDemoShipsPListVerifierStage.m OOCheckEquipmentPListVerifierStage.m OOTextureVerifierStage.m OOModelVerifierStage.m OOCheckShipDataPListVerifierStage.m OOPListSchemaVerifier.m OOJSShip.m OOJSPlayer.m OOJSCall.m OOJSStation.m OOJSSystem.m OOLegacyEventHandlerScript.m OOJSOolite.m OORoleSet.m OOJSGlobal.m OOJSMissionVariables.m OOJSMission.m
oolite_OBJC_FILES = Comparison.m AI.m DustEntity.m Entity.m GameController.m GuiDisplayGen.m HeadUpDisplay.m main.m MyOpenGLView.m OpenGLSprite.m ParticleEntity.m PlanetEntity.m PlayerEntityLegacyScriptEngine.m PlayerEntityContracts.m PlayerEntityControls.m PlayerEntityLoadSave.m PlayerEntitySound.m PlayerEntity.m ResourceManager.m RingEntity.m ShipEntityAI.m ShipEntity.m SkyEntity.m StationEntity.m Universe.m OOSound.m SDLMusic.m NSFileManagerOOExtensions.m JoystickHandler.m PlayerEntityStickMapper.m OOBasicSoundReferencePoint.m OOBasicSoundSource.m OOCharacter.m OOTrumble.m WormholeEntity.m NSScannerOOExtensions.m OOXMLExtensions.m NSMutableDictionaryOOExtensions.m Geometry.m Octree.m CollisionRegion.m OOColor.m OOLogging.m OOCacheManager.m OOCache.m OOStringParsing.m OOCollectionExtractors.m OOVector.m OOMatrix.m OOQuaternion.m OOVoxel.m OOTriangle.m OOPListParsing.m OOFastArithmetic.m OOTextureScaling.m OOConstToString.m OOScript.m OOJSScript.m OOJavaScriptEngine.m OOPListScript.m NSStringOOExtensions.m PlayerEntityScriptMethods.m OOWeakReference.m OOJSEntity.m EntityOOJavaScriptExtensions.m OOJSQuaternion.m OOMaterial.m OOShaderMaterial.m OOShaderProgram.m OOShaderUniform.m OOTexture.m OOTextureLoader.m OOPNGTextureLoader.m OOOpenGLExtensionManager.m OOBasicMaterial.m OOSingleTextureMaterial.m OOCPUInfo.m OOSelfDrawingEntity.m OOEntityWithDrawable.m OODrawable.m OOJSVector.m OOMesh.m OOOpenGL.m OOGraphicsResetManager.m OOProbabilisticTextureManager.m OODebugGLDrawing.m OOShaderUniformMethodType.m OOAsyncQueue.m TextureStore.m OOOXPVerifier.m OOOXPVerifierStage.m OOFileScannerVerifierStage.m OOCheckRequiresPListVerifierStage.m OOCheckDemoShipsPListVerifierStage.m OOCheckEquipmentPListVerifierStage.m OOTextureVerifierStage.m OOModelVerifierStage.m OOCheckShipDataPListVerifierStage.m OOPListSchemaVerifier.m OOJSShip.m OOJSPlayer.m OOJSCall.m OOJSStation.m OOJSSystem.m OOLegacyEventHandlerScript.m OOJSOolite.m OORoleSet.m OOJSGlobal.m OOJSMissionVariables.m OOJSMission.m OOPriorityQueue OOScriptTimer
include $(GNUSTEP_MAKEFILES)/objc.make
include GNUmakefile.postamble

View File

@ -360,6 +360,10 @@
1A5E462F0C32DACE008104B4 /* OOShaderUniformMethodType.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A5E462D0C32DACE008104B4 /* OOShaderUniformMethodType.m */; };
1A5E46300C32DACE008104B4 /* OOShaderUniformMethodType.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A5E462E0C32DACE008104B4 /* OOShaderUniformMethodType.h */; };
1A67050F0C4904ED002551AA /* oolite-cloaking-device.js in Copy Scripts */ = {isa = PBXBuildFile; fileRef = 1A67050E0C4904ED002551AA /* oolite-cloaking-device.js */; };
1A6B1EF00C9AA5C6000717CF /* OOScriptTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A6B1EEE0C9AA5C6000717CF /* OOScriptTimer.h */; };
1A6B1EF10C9AA5C6000717CF /* OOScriptTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B1EEF0C9AA5C6000717CF /* OOScriptTimer.m */; };
1A6B1F360C9AAA60000717CF /* OOPriorityQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A6B1F340C9AAA60000717CF /* OOPriorityQueue.m */; };
1A6B1F370C9AAA60000717CF /* OOPriorityQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A6B1F350C9AAA60000717CF /* OOPriorityQueue.h */; };
1A6B50430C8B42AC0035DFCC /* libOgg.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 25F3E8E9099502BB002F25FD /* libOgg.a */; };
1A6DD1230C57B5BC00A892F4 /* OOPListSchemaVerifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A6DD1210C57B5BC00A892F4 /* OOPListSchemaVerifier.h */; };
1A6DD1240C57B5BC00A892F4 /* OOPListSchemaVerifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A6DD1220C57B5BC00A892F4 /* OOPListSchemaVerifier.m */; };
@ -1263,6 +1267,10 @@
1A5E462D0C32DACE008104B4 /* OOShaderUniformMethodType.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOShaderUniformMethodType.m; sourceTree = "<group>"; };
1A5E462E0C32DACE008104B4 /* OOShaderUniformMethodType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOShaderUniformMethodType.h; sourceTree = "<group>"; };
1A67050E0C4904ED002551AA /* oolite-cloaking-device.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "oolite-cloaking-device.js"; sourceTree = "<group>"; };
1A6B1EEE0C9AA5C6000717CF /* OOScriptTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOScriptTimer.h; sourceTree = "<group>"; };
1A6B1EEF0C9AA5C6000717CF /* OOScriptTimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOScriptTimer.m; sourceTree = "<group>"; };
1A6B1F340C9AAA60000717CF /* OOPriorityQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOPriorityQueue.m; sourceTree = "<group>"; };
1A6B1F350C9AAA60000717CF /* OOPriorityQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOPriorityQueue.h; sourceTree = "<group>"; };
1A6B50370C8B42480035DFCC /* libjs.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = libjs.xcodeproj; path = xcode/libjs.xcodeproj; sourceTree = "<group>"; };
1A6DD1210C57B5BC00A892F4 /* OOPListSchemaVerifier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOPListSchemaVerifier.h; sourceTree = "<group>"; };
1A6DD1220C57B5BC00A892F4 /* OOPListSchemaVerifier.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOPListSchemaVerifier.m; sourceTree = "<group>"; };
@ -1915,6 +1923,8 @@
1A5DBA9F0BC000DC00D57389 /* OOPListScript.m */,
1A73795B0C65CF090097AC37 /* OOLegacyEventHandlerScript.h */,
1A73795C0C65CF090097AC37 /* OOLegacyEventHandlerScript.m */,
1A6B1EEE0C9AA5C6000717CF /* OOScriptTimer.h */,
1A6B1EEF0C9AA5C6000717CF /* OOScriptTimer.m */,
1A5DBAB50BC000E700D57389 /* JavaScript */,
);
path = Scripting;
@ -2122,6 +2132,8 @@
1A2A17D50BD1587D00152975 /* OOCPUInfo.m */,
1A7D83380C40147700E4A5F5 /* OOAsyncQueue.h */,
1A7D83390C40147700E4A5F5 /* OOAsyncQueue.m */,
1A6B1F340C9AAA60000717CF /* OOPriorityQueue.m */,
1A6B1F350C9AAA60000717CF /* OOPriorityQueue.h */,
);
name = Utilities;
sourceTree = "<group>";
@ -2542,6 +2554,8 @@
1ACEA6BF0C91DA3E00C7CE97 /* OOJSGlobal.h in Headers */,
1ACEA7280C91DF2800C7CE97 /* OOJSMissionVariables.h in Headers */,
1ACEA7AA0C91E32800C7CE97 /* OOJSMission.h in Headers */,
1A6B1EF00C9AA5C6000717CF /* OOScriptTimer.h in Headers */,
1A6B1F370C9AAA60000717CF /* OOPriorityQueue.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -2877,6 +2891,8 @@
1ACEA6C00C91DA3E00C7CE97 /* OOJSGlobal.m in Sources */,
1ACEA7290C91DF2800C7CE97 /* OOJSMissionVariables.m in Sources */,
1ACEA7AB0C91E32800C7CE97 /* OOJSMission.m in Sources */,
1A6B1EF10C9AA5C6000717CF /* OOScriptTimer.m in Sources */,
1A6B1F360C9AAA60000717CF /* OOPriorityQueue.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -0,0 +1,71 @@
/*
OOPriorityQueue.h
A prority queue is a collection into which objects may be inserted in any
order, but (primarily) extracted in sorted order. The order is defined by the
comparison selector specified at creation time, which is assumed to have the
same signature as a compare method used for array sorting:
- (NSComparisonResult)compare:(id)other
and must define a partial order on the objects in the priority queue. The
behaviour when provided with an inconsistent comparison method is undefined.
The implementation is the standard one, a binary heap. It is described in
detail in most algorithm textbooks.
This collection is *not* thread-safe.
Copyright (C) 2007 Jens Ayton
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.
*/
#import <Foundation/Foundation.h>
@interface OOPriorityQueue: NSObject <NSCopying>
{
SEL _comparator;
id *_buffer;
unsigned _count,
_capacity;
}
// Note: -init is equivalent to -initWithComparator:@selector(compare:)
+ (id) queueWithComparator:(SEL)comparator;
- (id) initWithComparator:(SEL)comparator;
- (void) addObject:(id)object; // May throw NSInvalidArgumentException or NSMallocException.
- (void) removeObject:(id)object; // Uses comparator (looking for NSOrderedEqual) to find object. Note: relatively expensive.
- (void) removeExactObject:(id)object; // Uses pointer comparison to find object. Note: still relatively expensive.
- (unsigned) count;
- (id) nextObject;
- (id) peekAtNextObject; // Returns next object without removing it.
- (void) removeNextObject;
- (void) addObjects:(id)collection; // collection must respond to -nextObject, or implement -objectEnumerator to return something that implements -nextObject -- such as an NSEnumerator.
- (NSArray *) sortedObjects; // Returns the objects in -nextObject order and empties the heap. To get the objects without emptying the heap, copy the priority queue first.
- (NSEnumerator *) objectEnumerator; // Enumerator which pulls objects off the heap until it's empty. Note however that the queue itself behaves like an enumerator, as -nextObject has similar semantics (except that the enumerator's -nextObject can never start returning objects after it returns nil).
@end

596
src/Core/OOPriorityQueue.m Normal file
View File

@ -0,0 +1,596 @@
/*
OOPriorityQueue.m
Copyright (C) 2007 Jens Ayton
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.
*/
#import "OOPriorityQueue.h"
#import "OOFunctionAttributes.h"
/* Capacity grows by 50% each time. kMinCapacity must be at least 2 or Bad
Things will happen. Some examples of growth patterns based on kMinCapacity:
2: 2 3 4 6 9 13 19 28 42 63 94 141 211 316 474 711 1066...
4: 4 6 9 13 19 28 42 63 94 141 211 316 474 711 1066 1599...
8: 8 12 18 27 40 60 90 135 202 303 454 681 1021 1531 2296...
16: 16 24 36 54 81 121 181 271 406 609 913 1369 2053 3079...
32: 32 48 72 108 162 243 364 546 819 1228 1842 2763 4144...
Special cases: when an OOPriorityQueue is copied, the copy's capacity is
set to the same as its count, which may be less than kMinCapacity. However,
when it is grown, it will be set to at least kMinCapacity (except in the
case of a reallocation failure, in which case an attempt will be made to
grow capacity by one element).
*/
enum
{
kMinCapacity = 16
};
/* Functions to navigate the binary heap.
Using one-based indices, the following hold:
* The left child of a node, L(n), is 2n.
* The right child of a node, R(n), is 2n + 1.
* The parent of a node, P(n), is n/2 for n > 1.
Using zero-based indices, we must convert to and from one-based indices to
perform these calculations, giving:
* Lz(n) = L(n+1)-1 = (2(n+1))-1 = 2n+1
* Rz(n) = R(n+1)-1 = (2(n+1)+1)-1 = 2n+2
* Pz(n) = P(n+1)-1 = ((n+1)/2)-1
*/
OOINLINE unsigned PQLeftChild(unsigned n) INLINE_CONST_FUNC;
OOINLINE unsigned PQRightChild(unsigned n) INLINE_CONST_FUNC;
OOINLINE unsigned PQParent(unsigned n) INLINE_CONST_FUNC;
OOINLINE unsigned PQLeftChild(unsigned n)
{
return (n << 1) + 1;
}
OOINLINE unsigned PQRightChild(unsigned n)
{
return (n << 1) + 2;
}
OOINLINE unsigned PQParent(unsigned n)
{
return ((n + 1) >> 1) - 1;
}
typedef NSComparisonResult (*CompareIMP)(id self, SEL _cmd, id other);
OOINLINE NSComparisonResult PQCompare(id a, id b, SEL comparator)
{
CompareIMP compare = NULL;
NSComparisonResult result;
compare = (CompareIMP)[a methodForSelector:comparator];
result = compare(a, comparator, b);
return result;
}
// Private priority queue methods.
@interface OOPriorityQueue (Private)
- (void) makeObjectsPerformSelector:(SEL)selector;
- (void) bubbleUpFrom:(unsigned)i;
- (void) bubbleDownFrom:(unsigned)i;
- (void) growBuffer;
- (void) shrinkBuffer;
- (void)removeObjectAtIndex:(unsigned)i;
#ifdef OO_DEBUG
- (void) appendDebugDataToString:(NSMutableString *)string index:(unsigned)i depth:(unsigned)depth;
#endif
@end
// NSEnumerator subclass to pull objects from queue.
@interface OOPriorityQueueEnumerator: NSEnumerator
{
OOPriorityQueue *_queue;
}
- (id) initWithPriorityQueue:(OOPriorityQueue *)queue;
@end
@implementation OOPriorityQueue
+ (id) queueWithComparator:(SEL)comparator
{
return [[[self alloc] initWithComparator:comparator] autorelease];
}
- (id) initWithComparator:(SEL)comparator
{
if (comparator == NULL)
{
[self release];
return nil;
}
self = [super init];
if (self != nil)
{
_comparator = comparator;
}
return self;
}
- (id) init
{
return [self initWithComparator:@selector(compare:)];
}
- (void) dealloc
{
[self makeObjectsPerformSelector:@selector(release)];
free(_buffer);
[super dealloc];
}
- (NSString *) description
{
return [NSString stringWithFormat:@"<%@ %p>{count=%u, capacity=%u}", [self class], self, _count, _capacity];
}
#ifdef OO_DEBUG
- (NSString *) debugDescription
{
NSMutableString *result = nil;
result = [NSMutableString string];
[result appendFormat:@"<%@ %p> (count=%u, capacity=%u, comparator=%@)", [self class], self, _count, _capacity, NSStringFromSelector(_comparator)];
if (_count != 0)
{
[result appendString:@"\n{\n"];
[self appendDebugDataToString:result index:0 depth:0];
[result appendString:@"}"];
}
else
{
[result appendString:@" {}"];
}
return result;
}
#endif
- (BOOL) isEqual:(id)object
{
unsigned i;
OOPriorityQueue *selfCopy = nil, *otherCopy = nil;
BOOL identical = YES;
if (object == self) return YES;
if (![object isKindOfClass:[self class]]) return NO;
if (_count != [object count]) return NO;
if (_count == 0) return YES;
selfCopy = [self copy];
otherCopy = [object copy];
i = _count;
while (i--)
{
if (![[selfCopy nextObject] isEqual:[otherCopy nextObject]])
{
identical = NO;
break;
}
}
[selfCopy release];
[otherCopy release];
return identical;
}
- (unsigned) hash
{
return _count;
}
- (id) copyWithZone:(NSZone *)zone
{
OOPriorityQueue *copy = nil;
copy = [[self class] allocWithZone:zone];
if (copy != nil)
{
copy->_comparator = _comparator;
copy->_count = _count;
copy->_capacity = _count;
copy->_buffer = malloc(_count * sizeof(id));
if (copy->_buffer != NULL)
{
memcpy(copy->_buffer, _buffer, _count * sizeof(id));
[copy makeObjectsPerformSelector:@selector(retain)];
}
else if (_count != 0)
{
[copy release];
copy = nil;
}
}
return copy;
}
- (void) addObject:(id)object
{
unsigned i;
// Validate object
if (object == nil)
{
[NSException raise:NSInvalidArgumentException
format:@"Attempt to insert nil into OOPriorityQueue."];
}
if (![object respondsToSelector:_comparator])
{
[NSException raise:NSInvalidArgumentException
format:@"Attempt to insert object (%@) which does not support comparator %@ into OOPriorityQueue.",
object, NSStringFromSelector(_comparator)];
}
// Ensure there is sufficent space.
if (_count == _capacity) [self growBuffer];
// insert object at end of buffer.
i = _count++;
_buffer[i] = object;
[self bubbleUpFrom:i];
[object retain];
}
- (void) removeObject:(id)object
{
unsigned i;
/* Perform linear search for object (using comparator). A depth-first
search could skip leaves of lower priority, but I don't expect this to
be called very often.
*/
if (object == nil) return;
for (i = 0; i < _count; ++i)
{
if (PQCompare(object, _buffer[i], _comparator) == 0)
{
[self removeObjectAtIndex:i];
}
}
}
- (void) removeExactObject:(id)object
{
unsigned i;
if (object == nil) return;
for (i = 0; i < _count; ++i)
{
if (object == _buffer[i])
{
[self removeObjectAtIndex:i];
}
}
}
- (unsigned) count
{
return _count;
}
- (id) nextObject
{
id result = [self peekAtNextObject];
[self removeNextObject];
return result;
}
- (id) peekAtNextObject
{
if (_count == 0) return nil;
return [[_buffer[0] retain] autorelease];
}
- (void) removeNextObject
{
[self removeObjectAtIndex:0];
}
- (void) addObjects:(id)collection
{
id value = nil;
if ([collection respondsToSelector:@selector(objectEnumerator)]) collection = [collection objectEnumerator];
if (![collection respondsToSelector:@selector(nextObject)]) return;
while ((value = [collection nextObject])) [self addObject:value];
}
- (NSArray *) sortedObjects
{
return [[self objectEnumerator] allObjects];
}
- (NSEnumerator *) objectEnumerator
{
return [[[OOPriorityQueueEnumerator alloc] initWithPriorityQueue:self] autorelease];
}
@end
@implementation OOPriorityQueue (Private)
- (void) makeObjectsPerformSelector:(SEL)selector
{
unsigned i;
if (selector == NULL) return;
for (i = 0; i != _count; ++i)
{
[_buffer[i] performSelector:selector];
}
}
- (void) bubbleUpFrom:(unsigned)i
{
unsigned pi;
id obj = nil, par = nil;
while (0 < i)
{
pi = PQParent(i);
obj = _buffer[i];
par = _buffer[pi];
if (PQCompare(obj, par, _comparator) < 0)
{
_buffer[i] = par;
_buffer[pi] = obj;
i = pi;
}
else break;
}
}
- (void) bubbleDownFrom:(unsigned)i
{
unsigned end = _count - 1;
unsigned li, ri, next;
id obj = nil;
obj = _buffer[i];
while (PQLeftChild(i) <= end)
{
li = PQLeftChild(i);
ri = PQRightChild(i);
// If left child has lower priority than right child, or there is only one child...
if (li == end || PQCompare(_buffer[li], _buffer[ri], _comparator) < 0)
{
next = li;
}
else
{
next = ri;
}
if (PQCompare(_buffer[next], obj, _comparator) < 0)
{
// Exchange parent with lowest-priority child
_buffer[i] = _buffer[next];
_buffer[next] = obj;
i = next;
}
else break;
}
}
- (void) growBuffer
{
id *newBuffer = NULL;
unsigned newCapacity;
newCapacity = _capacity * 3 / 2;
if (newCapacity < kMinCapacity) newCapacity = kMinCapacity;
// Note: realloc(NULL, size) with non-zero size is equivalent to malloc(size), so this is OK starting from a NULL buffer.
newBuffer = realloc(_buffer, newCapacity * sizeof(id));
if (newBuffer == NULL)
{
// Attempt to grow by just one waffer-thin slot.
newCapacity = _capacity + 1;
newBuffer = realloc(_buffer, newCapacity * sizeof(id));
if (newBuffer == nil)
{
// Failed to grow.
[NSException raise:NSMallocException
format:@"Could not expand capacity of OOPriorityQueue."];
}
}
_buffer = newBuffer;
_capacity = newCapacity;
assert(_count < _capacity);
}
- (void)shrinkBuffer
{
unsigned amountToRemove;
id *newBuffer = NULL;
unsigned newCapacity;
if (kMinCapacity < _capacity)
{
// Remove two thirds of free space, if at least three slots are free.
amountToRemove = _capacity - _count * 2 / 3;
if (2 < amountToRemove)
{
newCapacity = _capacity = amountToRemove;
newBuffer = realloc(_buffer, newCapacity * sizeof(id));
if (newBuffer != NULL)
{
_buffer = newBuffer;
_capacity = newCapacity;
}
}
}
}
- (void)removeObjectAtIndex:(unsigned)i
{
id object = nil;
if (_count <= i) return;
object = _buffer[i];
if (i < --_count)
{
// Overwrite object with last object in array
_buffer[i] = _buffer[_count];
// Push previously-last object down until tree is partially ordered.
[self bubbleDownFrom:i];
}
else
{
// Special case: removing last (or only) object. No bubbling needed.
}
[object release];
if (_count * 2 <= _capacity) [self shrinkBuffer];
}
#ifdef OO_DEBUG
- (void) appendDebugDataToString:(NSMutableString *)string index:(unsigned)i depth:(unsigned)depth
{
unsigned spaces;
if (_count <= i) return;
spaces = 2 + depth;
while (spaces--) [string appendString:@" "];
[string appendString:[_buffer[i] description]];
[string appendString:@"\n"];
[self appendDebugDataToString:string index:PQLeftChild(i) depth:depth + 1];
[self appendDebugDataToString:string index:PQRightChild(i) depth:depth + 1];
}
#endif
@end
@implementation OOPriorityQueueEnumerator
- (id) initWithPriorityQueue:(OOPriorityQueue *)queue
{
if (queue == nil)
{
[self release];
return nil;
}
self = [super init];
if (self != nil)
{
_queue = [queue retain];
}
return self;
}
- (void) dealloc
{
[_queue release];
[super dealloc];
}
- (id) nextObject
{
id value = [_queue nextObject];
if (value == nil)
{
// Maintain enumerator semantics by ensuring we don't start returning new values after returning nil.
[_queue release];
_queue = nil;
}
return value;
}
@end

View File

@ -0,0 +1,69 @@
/*
OOScriptTimer.h
Abstract base class for script timers. An OOScriptTimer does nothing when it
fires; subclasses should override the -timerFired method.
Timers are immutable. They are retained by the timer subsystem while scheduled.
A timer with a negative interval will only fire once. A negative nexttime when
inited will cause the timer to fire after the specified interval. A persistent
timer will remain if the player dies and respawns; non-persistent timers will
be removed.
Oolite
Copyright (C) 2004-2007 Giles C Williams and contributors
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
*/
#import "OOCocoa.h"
#import "OOTypes.h"
@interface OOScriptTimer: NSObject
{
OOTimeAbsolute _nextTime;
OOTimeDelta _interval;
}
- (id) initWithNextTime:(OOTimeAbsolute)nextTime
interval:(OOTimeDelta)interval;
// Sets nextTime to current time + delay.
- (id) initOneShotTimerWithDelay:(OOTimeDelta)delay;
- (OOTimeAbsolute)nextTime;
// Subclass responsibility:
- (void) timerFired;
- (BOOL) isPersistent; // Default: NO.
- (BOOL) scheduleTimer;
- (void) unscheduleTimer;
+ (void) updateTimers;
+ (void) noteGameReset;
- (BOOL) isValidForScheduling;
- (NSComparisonResult) compareByNextFireTime:(OOScriptTimer *)other;
@end

View File

@ -0,0 +1,163 @@
/*
OOScriptTimer.m
Oolite
Copyright (C) 2004-2007 Giles C Williams and contributors
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
*/
#import "OOScriptTimer.h"
#import "Universe.h"
#import "OOLogging.h"
#import "OOPriorityQueue.h"
static OOPriorityQueue *sTimers = nil;
@implementation OOScriptTimer
- (id) initWithNextTime:(OOTimeAbsolute)nextTime
interval:(OOTimeDelta)interval
{
OOTimeAbsolute now;
self = [super init];
if (self != nil)
{
now = [UNIVERSE getTime];
if (nextTime < 0.0) nextTime = now + interval;
if (nextTime < now)
{
// Negative or old nextTime and negative interval = meaningless.
[self release];
self = nil;
}
}
return self;
}
// Sets nextTime to current time + delay.
- (id) initOneShotTimerWithDelay:(OOTimeDelta)delay
{
return [self initWithNextTime:[UNIVERSE getTime] + delay interval:-1.0];
}
- (OOTimeAbsolute)nextTime
{
return _nextTime;
}
- (void) timerFired
{
OOLogGenericSubclassResponsibility();
}
- (BOOL) isPersistent
{
return NO;
}
- (BOOL) scheduleTimer
{
if (![self isValidForScheduling]) return NO;
if (sTimers == nil) sTimers = [[OOPriorityQueue alloc] initWithComparator:@selector(compareByNextFireTime:)];
[sTimers addObject:self];
return YES;
}
- (void) unscheduleTimer
{
[sTimers removeExactObject:self];
}
+ (void) updateTimers
{
OOScriptTimer *timer = nil;
OOTimeAbsolute now;
now = [UNIVERSE getTime];
for (;;)
{
timer = [sTimers peekAtNextObject];
if (now < [timer nextTime]) break;
[sTimers removeNextObject];
[timer timerFired];
[timer scheduleTimer];
}
}
+ (void) noteGameReset
{
NSArray *timers = nil;
NSEnumerator *timerEnum = nil;
OOScriptTimer *timer = nil;
// Intermediate array is required so we don't get stuck in an endless loop over reinserted timers
timers = [sTimers sortedObjects];
for (timerEnum = [timers objectEnumerator]; (timer = [timerEnum nextObject]); )
{
if ([timer isPersistent]) [timer scheduleTimer];
}
}
- (BOOL) isValidForScheduling
{
OOTimeAbsolute now;
double scaled;
now = [UNIVERSE getTime];
if (_nextTime < now)
{
if (_interval <= 0.0) return NO; // One-shot timer which has expired
// Move _nextTime to the closest future time that's a multiple of _interval
scaled = (now - _nextTime) / _interval;
scaled = ceil(scaled);
_nextTime += scaled * _interval;
}
return YES;
}
- (NSComparisonResult) compareByNextFireTime:(OOScriptTimer *)other
{
OOTimeAbsolute otherTime;
if (other != nil) otherTime = [other nextTime];
else otherTime = -INFINITY;
if (_nextTime < otherTime) return NSOrderedAscending;
else if (_nextTime < otherTime) return NSOrderedDescending;
else return NSOrderedSame;
}
@end