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:
parent
e9dbb8d38e
commit
7b061ad0f7
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
71
src/Core/OOPriorityQueue.h
Normal file
71
src/Core/OOPriorityQueue.h
Normal 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
596
src/Core/OOPriorityQueue.m
Normal 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
|
69
src/Core/Scripting/OOScriptTimer.h
Normal file
69
src/Core/Scripting/OOScriptTimer.h
Normal 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
|
163
src/Core/Scripting/OOScriptTimer.m
Normal file
163
src/Core/Scripting/OOScriptTimer.m
Normal 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
|
Loading…
x
Reference in New Issue
Block a user