Implemented frame callbacks.
git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@4035 127b21dd-08f5-0310-b4b7-95ae10353056
This commit is contained in:
parent
53996131e3
commit
56f5e760ce
@ -339,7 +339,8 @@ OOLITE_SCRIPTING_FILES = \
|
||||
OOLegacyScriptWhitelist.m \
|
||||
OOPListScript.m \
|
||||
OOScript.m \
|
||||
OOScriptTimer.m
|
||||
OOScriptTimer.m \
|
||||
OOJSFrameCallbacks.m
|
||||
|
||||
OOLITE_SOUND_FILES = \
|
||||
OOBasicSoundReferencePoint.m \
|
||||
|
@ -60,6 +60,7 @@
|
||||
1A0729DA0EF56D1200B0F925 /* OOConvertSystemDescriptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A0729D80EF56D1200B0F925 /* OOConvertSystemDescriptions.m */; };
|
||||
1A0729FE0EF5796500B0F925 /* OldSchoolPropertyListWriting.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A0729FC0EF5796500B0F925 /* OldSchoolPropertyListWriting.h */; };
|
||||
1A0729FF0EF5796500B0F925 /* OldSchoolPropertyListWriting.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A0729FD0EF5796500B0F925 /* OldSchoolPropertyListWriting.m */; };
|
||||
1A0942CE12D7D5B9003B6273 /* OOJSFrameCallbacks.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A0942C812D7C011003B6273 /* OOJSFrameCallbacks.m */; };
|
||||
1A09EF4412BD0BCA00BF7F48 /* PlayerEntityStickMapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 1A26D09E0BCF9CF70073F257 /* PlayerEntityStickMapper.m */; };
|
||||
1A09EF5812BD0C4100BF7F48 /* Oolite Leopard support.bundle in Copy Plug-ins */ = {isa = PBXBuildFile; fileRef = 1A09EF5412BD0C1900BF7F48 /* Oolite Leopard support.bundle */; };
|
||||
1A0BF3D510DAE2B30099984D /* cobra1_redux1.dat in Copy Models */ = {isa = PBXBuildFile; fileRef = 1A0BF3D310DAE2B30099984D /* cobra1_redux1.dat */; };
|
||||
@ -1262,6 +1263,8 @@
|
||||
1A0729D80EF56D1200B0F925 /* OOConvertSystemDescriptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOConvertSystemDescriptions.m; sourceTree = "<group>"; };
|
||||
1A0729FC0EF5796500B0F925 /* OldSchoolPropertyListWriting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OldSchoolPropertyListWriting.h; sourceTree = "<group>"; };
|
||||
1A0729FD0EF5796500B0F925 /* OldSchoolPropertyListWriting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OldSchoolPropertyListWriting.m; sourceTree = "<group>"; };
|
||||
1A0942C712D7C011003B6273 /* OOJSFrameCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OOJSFrameCallbacks.h; sourceTree = "<group>"; };
|
||||
1A0942C812D7C011003B6273 /* OOJSFrameCallbacks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OOJSFrameCallbacks.m; sourceTree = "<group>"; };
|
||||
1A09EF4F12BD0C1900BF7F48 /* LeopardFeatures.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = LeopardFeatures.xcodeproj; path = "Mac-specific/LeopardFeatures/LeopardFeatures.xcodeproj"; sourceTree = "<group>"; };
|
||||
1A0BF3D310DAE2B30099984D /* cobra1_redux1.dat */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = cobra1_redux1.dat; sourceTree = "<group>"; };
|
||||
1A0BF3D410DAE2B30099984D /* cobra1_redux2.dat */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = cobra1_redux2.dat; sourceTree = "<group>"; };
|
||||
@ -2581,6 +2584,8 @@
|
||||
1AC27A0E0EA7E9940054E5F0 /* OOJSEquipmentInfo.m */,
|
||||
1A11F8490F35F60C001C886C /* OOJSShipGroup.h */,
|
||||
1A11F8480F35F60C001C886C /* OOJSShipGroup.m */,
|
||||
1A0942C712D7C011003B6273 /* OOJSFrameCallbacks.h */,
|
||||
1A0942C812D7C011003B6273 /* OOJSFrameCallbacks.m */,
|
||||
);
|
||||
name = JavaScript;
|
||||
sourceTree = "<group>";
|
||||
@ -3851,6 +3856,7 @@
|
||||
1A7038A212BB9F5A0015CCDC /* dummy.cpp in Sources */,
|
||||
1A09EF4412BD0BCA00BF7F48 /* PlayerEntityStickMapper.m in Sources */,
|
||||
1AB5E1F012BD628500C334DD /* OOJoystickManager.m in Sources */,
|
||||
1A0942CE12D7D5B9003B6273 /* OOJSFrameCallbacks.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -63,11 +63,12 @@ MA 02110-1301, USA.
|
||||
#import "OOShipRegistry.h"
|
||||
#import "OOEquipmentType.h"
|
||||
#import "OOCamera.h"
|
||||
#import "NSFileManagerOOExtensions.h"
|
||||
|
||||
#import "OOScript.h"
|
||||
#import "OOScriptTimer.h"
|
||||
#import "OOJavaScriptEngine.h"
|
||||
#import "NSFileManagerOOExtensions.h"
|
||||
#import "OOJSFrameCallbacks.h"
|
||||
|
||||
#import "OOJoystickManager.h"
|
||||
#import "PlayerEntityStickMapper.h"
|
||||
@ -1269,6 +1270,7 @@ static GLfloat sBaseMass = 0.0;
|
||||
|
||||
[[OOMusicController sharedController] stop];
|
||||
[OOScriptTimer noteGameReset];
|
||||
OOJSFrameCallbacksRemoveAll();
|
||||
}
|
||||
|
||||
|
||||
|
@ -36,6 +36,7 @@ MA 02110-1301, USA.
|
||||
#import "NSFileManagerOOExtensions.h"
|
||||
#import "OOLogOutputHandler.h"
|
||||
#import "OODebugFlags.h"
|
||||
#import "OOJSFrameCallbacks.h"
|
||||
|
||||
#define kOOLogUnconvertedNSLog @"unclassified.GameController"
|
||||
|
||||
@ -336,6 +337,8 @@ static BOOL _switchRez = NO, _switchRezDeferred = NO;
|
||||
[UNIVERSE update:delta_t];
|
||||
[OOSound update];
|
||||
|
||||
OOJSFrameCallbacksInvoke(delta_t);
|
||||
|
||||
#if OOLITE_HAVE_APPKIT
|
||||
if (fullscreen)
|
||||
{
|
||||
|
@ -351,6 +351,15 @@ enum {
|
||||
#endif
|
||||
|
||||
|
||||
#if OOLITE_FAST_ENUMERATION
|
||||
#define foreach(VAR,ARR) for(VAR in ARR)
|
||||
#define foreachkey(VAR,DICT) for(VAR in DICT)
|
||||
#else
|
||||
#define foreach(VAR,OBJ) for (NSEnumerator *ooForEachEnum = [(OBJ) objectEnumerator]; ((VAR) = [ooForEachEnum nextObject]); )
|
||||
#define foreachkey(VAR,DICT) for (NSEnumerator *ooForEachEnum = [(DICT) keyEnumerator]; ((VAR) = [ooForEachEnum nextObject]); )
|
||||
#endif
|
||||
|
||||
|
||||
/* Speech synthesis
|
||||
*/
|
||||
#if OOLITE_MAC_OS_X || defined(HAVE_LIBESPEAK)
|
||||
|
36
src/Core/Scripting/OOJSFrameCallbacks.h
Normal file
36
src/Core/Scripting/OOJSFrameCallbacks.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
|
||||
OOJSFrameCallbacks.h
|
||||
|
||||
Support for JavaScript callbacks to be invoked on every frame.
|
||||
|
||||
|
||||
Copyright (C) 2011 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 "OOJavaScriptEngine.h"
|
||||
|
||||
void InitOOJSFrameCallbacks(JSContext *context, JSObject *global);
|
||||
|
||||
void OOJSFrameCallbacksInvoke(OOTimeDelta delta);
|
||||
|
||||
void OOJSFrameCallbacksRemoveAll(void);
|
417
src/Core/Scripting/OOJSFrameCallbacks.m
Normal file
417
src/Core/Scripting/OOJSFrameCallbacks.m
Normal file
@ -0,0 +1,417 @@
|
||||
/*
|
||||
|
||||
OOJSFrameCallbacks.m
|
||||
|
||||
|
||||
Copyright (C) 2011 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 "OOJSFrameCallbacks.h"
|
||||
#import "OOCollectionExtractors.h"
|
||||
|
||||
|
||||
enum
|
||||
{
|
||||
kMinCount = 16
|
||||
};
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
jsval callback;
|
||||
uint32 trackingID;
|
||||
uint32 _padding;
|
||||
} CallbackEntry;
|
||||
|
||||
|
||||
static CallbackEntry *sCallbacks;
|
||||
static OOUInteger sCount; // Number of slots in use.
|
||||
static OOUInteger sSpace; // Number of slots allocated.
|
||||
static OOUInteger sHighWaterMark; // Number of slots which are GC roots.
|
||||
static NSMutableArray *sDeferredOps; // Deferred adds/removes while running.
|
||||
static uint32 sNextID;
|
||||
static BOOL sRunning;
|
||||
|
||||
|
||||
// Methods
|
||||
static JSBool GlobalAddFrameCallback(OOJS_NATIVE_ARGS);
|
||||
static JSBool GlobalRemoveFrameCallback(OOJS_NATIVE_ARGS);
|
||||
static JSBool GlobalIsValidFrameCallback(OOJS_NATIVE_ARGS);
|
||||
|
||||
|
||||
// Internals
|
||||
static BOOL AddCallback(JSContext *context, jsval callback, uint32 trackingID, NSString **errorString);
|
||||
static BOOL GrowCallbackList(JSContext *context, NSString **errorString);
|
||||
|
||||
static BOOL GetIndexForTrackingID(uint32 trackingID, OOUInteger *outIndex);
|
||||
|
||||
static BOOL RemoveCallbackWithTrackingID(JSContext *context, uint32 trackingID);
|
||||
static void RemoveCallbackAtIndex(JSContext *context, OOUInteger index);
|
||||
|
||||
static void QueueDeferredOperation(NSString *opType, uint32 trackingID, OOJSValue *value);
|
||||
static void RunDeferredOperations(JSContext *context);
|
||||
|
||||
|
||||
// MARK: Public
|
||||
|
||||
void InitOOJSFrameCallbacks(JSContext *context, JSObject *global)
|
||||
{
|
||||
JS_DefineFunction(context, global, "addFrameCallback", GlobalAddFrameCallback, 1, 0);
|
||||
JS_DefineFunction(context, global, "removeFrameCallback", GlobalRemoveFrameCallback, 1, 0);
|
||||
JS_DefineFunction(context, global, "isValidFrameCallback", GlobalIsValidFrameCallback, 1, 0);
|
||||
|
||||
// Set randomish initial ID to catch bad habits.
|
||||
sNextID = [[NSDate date] timeIntervalSinceReferenceDate];
|
||||
}
|
||||
|
||||
|
||||
void OOJSFrameCallbacksInvoke(OOTimeDelta delta)
|
||||
{
|
||||
NSCAssert1(!sRunning, @"%s cannot be called while frame callbacks are running.", __PRETTY_FUNCTION__);
|
||||
|
||||
if (sCount != 0)
|
||||
{
|
||||
OOJavaScriptEngine *jsEng = [OOJavaScriptEngine sharedEngine];
|
||||
JSContext *context = [jsEng acquireContext];
|
||||
jsval deltaVal, result;
|
||||
OOUInteger i;
|
||||
|
||||
JS_BeginRequest(context);
|
||||
|
||||
if (EXPECT_NOT(!JS_NewDoubleValue(context, delta, &deltaVal))) return;
|
||||
|
||||
// Block mutations.
|
||||
sRunning = YES;
|
||||
|
||||
/*
|
||||
The watchdog timer only fires once per second in deployment builds,
|
||||
but in testrelease builds at least we can keep them on a short leash.
|
||||
*/
|
||||
OOJSStartTimeLimiterWithTimeLimit(0.1);
|
||||
|
||||
for (i = 0; i < sCount; i++)
|
||||
{
|
||||
JS_CallFunctionValue(context, NULL, sCallbacks[i].callback, 1, &deltaVal, &result);
|
||||
}
|
||||
|
||||
OOJSStopTimeLimiter();
|
||||
sRunning = NO;
|
||||
|
||||
if (EXPECT_NOT(sDeferredOps != NULL))
|
||||
{
|
||||
RunDeferredOperations(context);
|
||||
DESTROY(sDeferredOps);
|
||||
}
|
||||
|
||||
JS_EndRequest(context);
|
||||
[jsEng releaseContext:context];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OOJSFrameCallbacksRemoveAll(void)
|
||||
{
|
||||
NSCAssert1(!sRunning, @"%s cannot be called while frame callbacks are running.", __PRETTY_FUNCTION__);
|
||||
|
||||
if (sCount != 0)
|
||||
{
|
||||
OOJavaScriptEngine *jsEng = [OOJavaScriptEngine sharedEngine];
|
||||
JSContext *context = [jsEng acquireContext];
|
||||
JS_BeginRequest(context);
|
||||
|
||||
while (sCount != 0) RemoveCallbackAtIndex(context, sCount - 1);
|
||||
|
||||
JS_EndRequest(context);
|
||||
[jsEng releaseContext:context];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Methods
|
||||
|
||||
// addFrameCallback(callback : Function) : Number
|
||||
static JSBool GlobalAddFrameCallback(OOJS_NATIVE_ARGS)
|
||||
{
|
||||
OOJS_NATIVE_ENTER(context)
|
||||
|
||||
// Get callback argument and verify that it's a function.
|
||||
jsval callback = OOJS_ARG(0);
|
||||
if (EXPECT_NOT(!JSVAL_IS_OBJECT(callback) || !JS_ObjectIsFunction(context, JSVAL_TO_OBJECT(callback))))
|
||||
{
|
||||
OOJSReportBadArguments(context, nil, @"addFrameCallback", 1, OOJS_ARGV, nil, @"function");
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Assign a tracking ID.
|
||||
uint32 trackingID = sNextID;
|
||||
|
||||
/* Increment by a large prime number to produce a non-obvious sequence
|
||||
which still uses all 2^32 values.
|
||||
*/
|
||||
sNextID += 992699;
|
||||
|
||||
if (EXPECT(!sRunning))
|
||||
{
|
||||
// Add to list immediately.
|
||||
NSString *errorString = nil;
|
||||
if (EXPECT_NOT(!AddCallback(context, callback, trackingID, &errorString)))
|
||||
{
|
||||
OOJSReportError(context, @"%@", errorString);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Defer mutations during callback invocation.
|
||||
QueueDeferredOperation(@"add", trackingID, [OOJSValue valueWithJSValue:callback inContext:context]);
|
||||
}
|
||||
|
||||
OOJS_RETURN_INT(trackingID);
|
||||
|
||||
OOJS_NATIVE_EXIT
|
||||
}
|
||||
|
||||
|
||||
// removeFrameCallback(trackingID : Number)
|
||||
static JSBool GlobalRemoveFrameCallback(OOJS_NATIVE_ARGS)
|
||||
{
|
||||
OOJS_NATIVE_ENTER(context)
|
||||
|
||||
// Get tracking ID argument.
|
||||
uint32 trackingID;
|
||||
if (EXPECT_NOT(!JS_ValueToECMAUint32(context, OOJS_ARG(0), &trackingID)))
|
||||
{
|
||||
OOJSReportBadArguments(context, nil, @"removeFrameCallback", 1, OOJS_ARGV, nil, @"frame callback tracking ID");
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (EXPECT(!sRunning))
|
||||
{
|
||||
// Remove it.
|
||||
if (EXPECT_NOT(!RemoveCallbackWithTrackingID(context, trackingID)))
|
||||
{
|
||||
OOJSReportWarning(context, @"removeFrameCallback(): invalid tracking ID.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Defer mutations during callback invocation.
|
||||
QueueDeferredOperation(@"remove", trackingID, nil);
|
||||
}
|
||||
|
||||
OOJS_RETURN_VOID;
|
||||
|
||||
OOJS_NATIVE_EXIT
|
||||
}
|
||||
|
||||
|
||||
// isValidFrameCallback(trackingID : Number)
|
||||
static JSBool GlobalIsValidFrameCallback(OOJS_NATIVE_ARGS)
|
||||
{
|
||||
OOJS_NATIVE_ENTER(context)
|
||||
|
||||
// Get tracking ID argument.
|
||||
uint32 trackingID;
|
||||
if (EXPECT_NOT(!JS_ValueToECMAUint32(context, OOJS_ARG(0), &trackingID)))
|
||||
{
|
||||
OOJS_RETURN_BOOL(NO);
|
||||
}
|
||||
|
||||
OOUInteger index;
|
||||
OOJS_RETURN_BOOL(GetIndexForTrackingID(trackingID, &index));
|
||||
|
||||
OOJS_NATIVE_EXIT
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internals
|
||||
|
||||
static BOOL AddCallback(JSContext *context, jsval callback, uint32 trackingID, NSString **errorString)
|
||||
{
|
||||
NSCParameterAssert(context != NULL && JS_IsInRequest(context));
|
||||
NSCParameterAssert(errorString != NULL);
|
||||
NSCAssert1(!sRunning, @"%s cannot be called while frame callbacks are running.", __PRETTY_FUNCTION__);
|
||||
|
||||
if (EXPECT_NOT(sCount == sSpace))
|
||||
{
|
||||
if (!GrowCallbackList(context, errorString)) return NO;
|
||||
}
|
||||
|
||||
sCallbacks[sCount].callback = callback;
|
||||
if (sCount >= sHighWaterMark)
|
||||
{
|
||||
// If we haven't used this slot before, root it.
|
||||
|
||||
if (EXPECT_NOT(!OOJSAddGCValueRoot(context, &sCallbacks[sCount].callback, "frame callback")))
|
||||
{
|
||||
*errorString = @"Failed to add GC root for frame callback.";
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
sCallbacks[sCount].trackingID = trackingID;
|
||||
sCount++;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
static BOOL GrowCallbackList(JSContext *context, NSString **errorString)
|
||||
{
|
||||
NSCParameterAssert(context != NULL && JS_IsInRequest(context));
|
||||
NSCParameterAssert(errorString != NULL);
|
||||
|
||||
OOUInteger newSpace = MAX(sSpace * 2, (OOUInteger)kMinCount);
|
||||
|
||||
CallbackEntry *newCallbacks = calloc(sizeof (CallbackEntry), newSpace);
|
||||
if (newCallbacks == NULL) return NO;
|
||||
|
||||
CallbackEntry *oldCallbacks = sCallbacks;
|
||||
|
||||
// Root and copy occupied slots.
|
||||
OOUInteger newHighWaterMark = sCount;
|
||||
OOUInteger i;
|
||||
for (i = 0; i < newHighWaterMark; i++)
|
||||
{
|
||||
if (EXPECT_NOT(!OOJSAddGCValueRoot(context, &newCallbacks[i].callback, "frame callback")))
|
||||
{
|
||||
// If we can't root them all, we fail; unroot all entries to date, free the buffer and return NO.
|
||||
OOUInteger j;
|
||||
for (j = 0; i < i; j++)
|
||||
{
|
||||
JS_RemoveValueRoot(context, &newCallbacks[j].callback);
|
||||
}
|
||||
free(newCallbacks);
|
||||
|
||||
*errorString = @"Failed to add GC root for frame callback.";
|
||||
return NO;
|
||||
}
|
||||
newCallbacks[i] = oldCallbacks[i];
|
||||
}
|
||||
|
||||
// Unroot old array's slots.
|
||||
for (i = 0; i < sHighWaterMark; i++)
|
||||
{
|
||||
JS_RemoveValueRoot(context, &oldCallbacks[i].callback);
|
||||
}
|
||||
|
||||
// We only rooted the occupied slots, so reset high water mark.
|
||||
sHighWaterMark = newHighWaterMark;
|
||||
|
||||
// Replace array.
|
||||
sCallbacks = newCallbacks;
|
||||
free(oldCallbacks);
|
||||
sSpace = newSpace;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
static BOOL GetIndexForTrackingID(uint32 trackingID, OOUInteger *outIndex)
|
||||
{
|
||||
NSCParameterAssert(outIndex != 0);
|
||||
|
||||
/* It is assumed that few frame callbacks will be active at once, so a
|
||||
linear search is reasonable. If they become unexpectedly popular, we
|
||||
can switch to a sorted list or a separate lookup table without changing
|
||||
the API.
|
||||
*/
|
||||
OOUInteger i;
|
||||
for (i = 0; i < sCount; i++)
|
||||
{
|
||||
if (sCallbacks[i].trackingID == trackingID)
|
||||
{
|
||||
*outIndex = i;
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
static BOOL RemoveCallbackWithTrackingID(JSContext *context, uint32 trackingID)
|
||||
{
|
||||
NSCParameterAssert(context != NULL && JS_IsInRequest(context));
|
||||
NSCAssert1(!sRunning, @"%s cannot be called while frame callbacks are running.", __PRETTY_FUNCTION__);
|
||||
|
||||
OOUInteger index;
|
||||
if (GetIndexForTrackingID(trackingID, &index))
|
||||
{
|
||||
RemoveCallbackAtIndex(context, index);
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
static void RemoveCallbackAtIndex(JSContext *context, OOUInteger index)
|
||||
{
|
||||
NSCParameterAssert(context != NULL && JS_IsInRequest(context));
|
||||
NSCParameterAssert(index < sCount && sCallbacks != NULL);
|
||||
NSCAssert1(!sRunning, @"%s cannot be called while frame callbacks are running.", __PRETTY_FUNCTION__);
|
||||
|
||||
// Overwrite entry to be removed with last entry, and decrement count.
|
||||
sCallbacks[index] = sCallbacks[sCount - 1];
|
||||
sCount--;
|
||||
}
|
||||
|
||||
|
||||
static void QueueDeferredOperation(NSString *opType, uint32 trackingID, OOJSValue *value)
|
||||
{
|
||||
NSCAssert1(sRunning, @"%s can only be called while frame callbacks are running.", __PRETTY_FUNCTION__);
|
||||
|
||||
if (sDeferredOps == nil) sDeferredOps = [[NSMutableArray alloc] init];
|
||||
[sDeferredOps addObject:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
opType, @"operation",
|
||||
[NSNumber numberWithInt:trackingID], @"trackingID",
|
||||
value, @"value",
|
||||
nil]];
|
||||
}
|
||||
|
||||
|
||||
static void RunDeferredOperations(JSContext *context)
|
||||
{
|
||||
NSDictionary *operation = nil;
|
||||
|
||||
foreach(operation, sDeferredOps)
|
||||
{
|
||||
NSString *opType = [operation objectForKey:@"operation"];
|
||||
uint32 trackingID = [operation oo_intForKey:@"trackingID"];
|
||||
|
||||
if ([opType isEqualToString:@"add"])
|
||||
{
|
||||
OOJSValue *callbackObj = [operation objectForKey:@"value"];
|
||||
NSString *errorString = nil;
|
||||
|
||||
if (!AddCallback(context, [callbackObj oo_jsValueInContext:context], trackingID, &errorString))
|
||||
{
|
||||
OOLogWARN(@"script.frameCallback.deferredAdd.failed", @"Deferred frame callback insertion failed: %@", errorString);
|
||||
}
|
||||
}
|
||||
else if ([opType isEqualToString:@"remove"])
|
||||
{
|
||||
RemoveCallbackWithTrackingID(context, trackingID);
|
||||
}
|
||||
}
|
||||
}
|
@ -59,6 +59,7 @@ MA 02110-1301, USA.
|
||||
#import "OOJSSystemInfo.h"
|
||||
#import "OOJSEquipmentInfo.h"
|
||||
#import "OOJSShipGroup.h"
|
||||
#import "OOJSFrameCallbacks.h"
|
||||
|
||||
#import "OOProfilingStopwatch.h"
|
||||
#import "OOLoggingExtended.h"
|
||||
@ -332,6 +333,7 @@ static void ReportJSError(JSContext *context, const char *message, JSErrorReport
|
||||
InitOOJSSystemInfo(mainContext, globalObject);
|
||||
InitOOJSEquipmentInfo(mainContext, globalObject);
|
||||
InitOOJSShipGroup(mainContext, globalObject);
|
||||
InitOOJSFrameCallbacks(mainContext, globalObject);
|
||||
|
||||
JS_EndRequest(mainContext);
|
||||
|
||||
|
@ -4424,6 +4424,8 @@ OOINLINE BOOL EntityInRange(Vector p1, Entity *e2, float range)
|
||||
Vector p1;
|
||||
NSMutableArray *result = nil;
|
||||
|
||||
OOJSPauseTimeLimiter();
|
||||
|
||||
if (predicate == NULL) predicate = YESPredicate;
|
||||
|
||||
result = [NSMutableArray arrayWithCapacity:n_entities];
|
||||
@ -4443,6 +4445,8 @@ OOINLINE BOOL EntityInRange(Vector p1, Entity *e2, float range)
|
||||
}
|
||||
}
|
||||
|
||||
OOJSResumeTimeLimiter();
|
||||
|
||||
return result;
|
||||
|
||||
OOJS_PROFILE_EXIT
|
||||
@ -4455,6 +4459,8 @@ OOINLINE BOOL EntityInRange(Vector p1, Entity *e2, float range)
|
||||
unsigned i;
|
||||
Entity *candidate = nil;
|
||||
|
||||
OOJSPauseTimeLimiter();
|
||||
|
||||
if (predicate == NULL) predicate = YESPredicate;
|
||||
|
||||
for (i = 0; i < n_entities; i++)
|
||||
@ -4463,6 +4469,8 @@ OOINLINE BOOL EntityInRange(Vector p1, Entity *e2, float range)
|
||||
if (predicate(candidate, parameter)) return candidate;
|
||||
}
|
||||
|
||||
OOJSResumeTimeLimiter();
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user