mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
Remove ScriptingHost initialisation code (share with ScriptInterface instead).
Fix GUI scripts to avoid strict warnings. Rejig GUI/SpiderMonkey interface to use less custom code, and to work with JSOPTION_VAROBJFIX. Add event name to GUI event handler function names (visible in the profiler). This was SVN commit r7769.
This commit is contained in:
parent
ac9412458a
commit
9674c3c0fe
15 changed files with 81 additions and 231 deletions
|
|
@ -13,12 +13,12 @@ function startMainMenu()
|
|||
guiUnHide ("pg");
|
||||
|
||||
// Play main 0 A.D. theme when the main menu starts.
|
||||
curr_music = newRandomSound("music", "menu");
|
||||
if (curr_music)
|
||||
curr_music.loop();
|
||||
global.curr_music = newRandomSound("music", "menu");
|
||||
if (global.curr_music)
|
||||
global.curr_music.loop();
|
||||
|
||||
// Set starting volume (I'm using a value of zero here for no sound; feel free to comment out these two lines to use defaults).
|
||||
// curr_music.setGain (0.0);
|
||||
// global.curr_music.setGain (0.0);
|
||||
// g_ConfigDB.system["sound.mastergain"] = 0.0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ function setCurrItemValue (objectName, string)
|
|||
return -1; // Return -1 if nothing selected.
|
||||
var list = getGUIObjectByName(objectName).list;
|
||||
// Seek through list.
|
||||
for (ctr = 0; ctr < list.length; ctr++)
|
||||
for (var ctr = 0; ctr < list.length; ctr++)
|
||||
{
|
||||
// If we have found the string in the list,
|
||||
if (list[ctr] == string)
|
||||
|
|
@ -161,4 +161,4 @@ function setCurrItemValue (objectName, string)
|
|||
return -2;
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// ====================================================================
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ function newRandomSound(soundType, soundSubType, soundPrePath)
|
|||
if (soundArray.length == 0)
|
||||
{
|
||||
console.write ("Failed to find sounds matching '*"+soundSubType+"*'");
|
||||
return;
|
||||
return undefined;
|
||||
}
|
||||
// Get a random number within the sound's range.
|
||||
var randomSound = getRandom (0, soundArray.length-1);
|
||||
|
|
@ -103,4 +103,4 @@ function crossFade (outHandle, inHandle, fadeDuration)
|
|||
return true;
|
||||
}
|
||||
|
||||
// ====================================================================
|
||||
// ====================================================================
|
||||
|
|
|
|||
|
|
@ -38,8 +38,8 @@ function init(data)
|
|||
function reallyStartGame()
|
||||
{
|
||||
// Stop the music
|
||||
if (typeof curr_music != "undefined" && curr_music)
|
||||
curr_music.fade(-1, 0.0, 5.0); // fade to 0 over 5 seconds
|
||||
if (global.curr_music)
|
||||
global.curr_music.fade(-1, 0.0, 5.0); // fade to 0 over 5 seconds
|
||||
|
||||
// This is a reserved function name that is executed by the engine when it is ready
|
||||
// to start the game (i.e. loading progress has reached 100%).
|
||||
|
|
@ -50,4 +50,3 @@ function reallyStartGame()
|
|||
// Restore default cursor.
|
||||
setCursor ("arrow-default");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<objects>
|
||||
|
||||
<script>
|
||||
function init () { }
|
||||
function init() { }
|
||||
</script>
|
||||
|
||||
<!--
|
||||
|
|
@ -328,8 +328,8 @@ Watch for updates or get involved in the development: http://wildfiregames.com/0
|
|||
tooltip="Tired of 0 A.D. ? Click here to leave and reenter the real world."
|
||||
>
|
||||
<action on="Press"><![CDATA[
|
||||
btCaptions = ["Yes, let me out!", "Nooooo!"];
|
||||
btCode = [exit, null];
|
||||
var btCaptions = ["Yes, let me out!", "Nooooo!"];
|
||||
var btCode = [exit, null];
|
||||
messageBox (400, 200, "Do you really want to quit [icon=iconProduct] A.D.? This will cause a sudden return to reality.", "Confirmation", 0, btCaptions, btCode);
|
||||
]]></action>
|
||||
</object>
|
||||
|
|
@ -434,12 +434,12 @@ Watch for updates or get involved in the development: http://wildfiregames.com/0
|
|||
// either. Maybe this control isn't finished yet?)
|
||||
if(this.checked)
|
||||
{
|
||||
curr_music.setGain (0.0);
|
||||
global.curr_music.setGain (0.0);
|
||||
g_ConfigDB.system["sound.mastergain"] = 0.0;
|
||||
}
|
||||
if(!this.checked)
|
||||
{
|
||||
curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
|
||||
global.curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
|
||||
g_ConfigDB.system["sound.mastergain"] = getGUIObjectByName ("pgOptionsAudioMusicGain").caption;
|
||||
}
|
||||
]]></action>
|
||||
|
|
@ -485,7 +485,7 @@ Watch for updates or get involved in the development: http://wildfiregames.com/0
|
|||
if (getGUIObjectByName ("pgOptionsAudioMusicGain").caption > 0.0)
|
||||
guiModifyCaption ("pgOptionsAudioMusicGain", -.1, 1);
|
||||
|
||||
curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
|
||||
global.curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
|
||||
g_ConfigDB.system["sound.mastergain"] = getGUIObjectByName ("pgOptionsAudioMusicGain").caption;
|
||||
]]></action>
|
||||
</object>
|
||||
|
|
@ -499,7 +499,7 @@ Watch for updates or get involved in the development: http://wildfiregames.com/0
|
|||
if (getGUIObjectByName ("pgOptionsAudioMusicGain").caption < 1.0)
|
||||
guiModifyCaption ("pgOptionsAudioMusicGain", .1, 1);
|
||||
|
||||
curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
|
||||
global.curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
|
||||
g_ConfigDB.system["sound.mastergain"] = getGUIObjectByName ("pgOptionsAudioMusicGain").caption;
|
||||
]]></action>
|
||||
</object>
|
||||
|
|
@ -514,12 +514,12 @@ Watch for updates or get involved in the development: http://wildfiregames.com/0
|
|||
|
||||
if(this.checked)
|
||||
{
|
||||
curr_music.setGain (0.0);
|
||||
global.curr_music.setGain (0.0);
|
||||
g_ConfigDB.system["sound.mastergain"] = 0.0;
|
||||
}
|
||||
if(!this.checked)
|
||||
{
|
||||
curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
|
||||
global.curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
|
||||
g_ConfigDB.system["sound.mastergain"] = getGUIObjectByName ("pgOptionsAudioMusicGain").caption;
|
||||
}
|
||||
]]></action>
|
||||
|
|
@ -590,12 +590,12 @@ Watch for updates or get involved in the development: http://wildfiregames.com/0
|
|||
|
||||
if(this.checked)
|
||||
{
|
||||
// curr_music.setGain (0.0);
|
||||
// global.curr_music.setGain (0.0);
|
||||
// g_ConfigDB.system["sound.mastergain"] = 0.0;
|
||||
}
|
||||
if(!this.checked)
|
||||
{
|
||||
// curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
|
||||
// global.curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
|
||||
// g_ConfigDB.system["sound.mastergain"] = getGUIObjectByName ("pgOptionsAudioMusicGain").caption;
|
||||
}
|
||||
]]></action>
|
||||
|
|
@ -666,12 +666,12 @@ Watch for updates or get involved in the development: http://wildfiregames.com/0
|
|||
|
||||
if(this.checked)
|
||||
{
|
||||
// curr_music.setGain (0.0);
|
||||
// global.curr_music.setGain (0.0);
|
||||
// g_ConfigDB.system["sound.mastergain"] = 0.0;
|
||||
}
|
||||
if(!this.checked)
|
||||
{
|
||||
// curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
|
||||
// global.curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
|
||||
// g_ConfigDB.system["sound.mastergain"] = getGUIObjectByName ("pgOptionsAudioMusicGain").caption;
|
||||
}
|
||||
]]></action>
|
||||
|
|
@ -741,12 +741,12 @@ Watch for updates or get involved in the development: http://wildfiregames.com/0
|
|||
|
||||
if(this.checked)
|
||||
{
|
||||
// curr_music.setGain (0.0);
|
||||
// global.curr_music.setGain (0.0);
|
||||
// g_ConfigDB.system["sound.mastergain"] = 0.0;
|
||||
}
|
||||
if(!this.checked)
|
||||
{
|
||||
// curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
|
||||
// global.curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
|
||||
// g_ConfigDB.system["sound.mastergain"] = getGUIObjectByName ("pgOptionsAudioMusicGain").caption;
|
||||
}
|
||||
]]></action>
|
||||
|
|
|
|||
|
|
@ -53,11 +53,12 @@ function updateCursor()
|
|||
function findGatherType(gatherer, supply)
|
||||
{
|
||||
if (!gatherer || !supply)
|
||||
return;
|
||||
return undefined;
|
||||
if (gatherer[supply.type.generic+"."+supply.type.specific])
|
||||
return supply.type.specific;
|
||||
if (gatherer[supply.type.generic])
|
||||
return supply.type.generic;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -69,17 +70,17 @@ function determineAction(x, y)
|
|||
|
||||
// No action if there's no selection
|
||||
if (!selection.length)
|
||||
return;
|
||||
return undefined;
|
||||
|
||||
// If the selection doesn't exist, no action
|
||||
var entState = Engine.GuiInterfaceCall("GetEntityState", selection[0]);
|
||||
if (!entState)
|
||||
return;
|
||||
return undefined;
|
||||
|
||||
// If the selection isn't friendly units, no action
|
||||
var player = Engine.GetPlayerID();
|
||||
if (entState.player != player && !g_DevSettings.controlAll)
|
||||
return;
|
||||
return undefined;
|
||||
|
||||
var targets = Engine.PickEntitiesAtPoint(x, y);
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ function layoutButtonRow(rowNumber, guiName, buttonSideLength, buttonSpacer, sta
|
|||
{
|
||||
var colNumber = 0;
|
||||
|
||||
for (i = startIndex; i < endIndex; i++)
|
||||
for (var i = startIndex; i < endIndex; i++)
|
||||
{
|
||||
var button = getGUIObjectByName("unit"+guiName+"Button["+i+"]");
|
||||
var size = button.size;
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@ CGUI
|
|||
#include "ps/Profile.h"
|
||||
|
||||
#include "scripting/ScriptingHost.h"
|
||||
#include "scripting/JSConversions.h"
|
||||
#include "ps/Hotkey.h"
|
||||
#include "ps/Globals.h"
|
||||
#include "ps/Filesystem.h"
|
||||
|
|
@ -66,45 +65,10 @@ const double SELECT_DBLCLICK_RATE = 0.5;
|
|||
#include "ps/CLogger.h"
|
||||
#define LOG_CATEGORY L"gui"
|
||||
|
||||
|
||||
// Class for global JavaScript object
|
||||
JSClass GUIClass = {
|
||||
"GUIClass", JSCLASS_HAS_PRIVATE,
|
||||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
|
||||
};
|
||||
|
||||
static JSBool GetGUIObjectByName(JSContext* cx, JSObject* obj, uintN UNUSED(argc), jsval* argv, jsval* rval)
|
||||
{
|
||||
CGUI* gui = (CGUI*)JS_GetInstancePrivate(cx, obj, &GUIClass, argv);
|
||||
if (! gui)
|
||||
return JS_FALSE;
|
||||
try
|
||||
{
|
||||
CStr name = ToPrimitive<CStr>(cx, argv[0]);
|
||||
IGUIObject* guiObj = gui->FindObjectByName(name);
|
||||
if (guiObj)
|
||||
*rval = OBJECT_TO_JSVAL(guiObj->GetJSObject());
|
||||
else
|
||||
*rval = JSVAL_NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
catch (PSERROR_Scripting&)
|
||||
{
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
JSFunctionSpec GUIClassFunctions[] = {
|
||||
{ "getGUIObjectByName", GetGUIObjectByName, 1, 0, 0 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
void CGUI::ScriptingInit()
|
||||
{
|
||||
JSI_IGUIObject::init();
|
||||
JSI_GUITypes::init();
|
||||
g_ScriptingHost.DefineCustomObjectType(&GUIClass, NULL, 0, NULL, GUIClassFunctions, NULL, NULL);
|
||||
}
|
||||
|
||||
InReaction CGUI::HandleEvent(const SDL_Event_* ev)
|
||||
|
|
@ -383,10 +347,9 @@ CGUI::CGUI() : m_MouseButtons(0), m_FocusedObject(NULL), m_InternalNameNumber(0)
|
|||
m_BaseObject->SetGUI(this);
|
||||
|
||||
// Construct the parent object for all GUI JavaScript things
|
||||
m_ScriptObject = JS_NewObject(g_ScriptingHost.getContext(), &GUIClass, NULL, NULL);
|
||||
m_ScriptObject = JS_NewObject(g_ScriptingHost.getContext(), NULL, g_ScriptingHost.GetGlobalObject(), NULL);
|
||||
debug_assert(m_ScriptObject != NULL); // How should it handle errors?
|
||||
JS_AddRoot(g_ScriptingHost.getContext(), &m_ScriptObject);
|
||||
JS_SetPrivate(g_ScriptingHost.getContext(), m_ScriptObject, this);
|
||||
}
|
||||
|
||||
CGUI::~CGUI()
|
||||
|
|
@ -398,8 +361,6 @@ CGUI::~CGUI()
|
|||
|
||||
if (m_ScriptObject)
|
||||
{
|
||||
// Make sure it doesn't have dangling references to this CGUI
|
||||
JS_SetPrivate(g_ScriptingHost.getContext(), m_ScriptObject, NULL);
|
||||
// Let it be garbage-collected
|
||||
JS_RemoveRoot(g_ScriptingHost.getContext(), &m_ScriptObject);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,6 +166,10 @@ void CGUIManager::LoadPage(SGUIPage& page)
|
|||
page.gui->LoadXmlFile(path, page.inputs);
|
||||
}
|
||||
|
||||
// Remember this GUI page, in case the scripts call FindObjectByName
|
||||
shared_ptr<CGUI> oldGUI = m_CurrentGUI;
|
||||
m_CurrentGUI = page.gui;
|
||||
|
||||
page.gui->SendEventToAll("load");
|
||||
|
||||
// Call the init() function
|
||||
|
|
@ -173,6 +177,8 @@ void CGUIManager::LoadPage(SGUIPage& page)
|
|||
{
|
||||
LOGERROR(L"GUI page '%ls': Failed to call init() function", page.name.c_str());
|
||||
}
|
||||
|
||||
m_CurrentGUI = oldGUI;
|
||||
}
|
||||
|
||||
LibError CGUIManager::ReloadChangedFiles(const VfsPath& path)
|
||||
|
|
@ -243,7 +249,12 @@ SGUIIcon CGUIManager::GetIcon(const CStr& str) const
|
|||
|
||||
IGUIObject* CGUIManager::FindObjectByName(const CStr& name) const
|
||||
{
|
||||
return top()->FindObjectByName(name);
|
||||
// This can be called from scripts run by TickObjects,
|
||||
// and we want to return it the same GUI page as is being ticked
|
||||
if (m_CurrentGUI)
|
||||
return m_CurrentGUI->FindObjectByName(name);
|
||||
else
|
||||
return top()->FindObjectByName(name);
|
||||
}
|
||||
|
||||
void CGUIManager::SendEventToAll(const CStr& eventName)
|
||||
|
|
@ -257,7 +268,11 @@ void CGUIManager::TickObjects()
|
|||
PageStackType pageStack = m_PageStack;
|
||||
|
||||
for (PageStackType::iterator it = pageStack.begin(); it != pageStack.end(); ++it)
|
||||
{
|
||||
m_CurrentGUI = it->gui;
|
||||
it->gui->TickObjects();
|
||||
}
|
||||
m_CurrentGUI.reset();
|
||||
}
|
||||
|
||||
void CGUIManager::Draw()
|
||||
|
|
|
|||
|
|
@ -122,6 +122,8 @@ private:
|
|||
typedef std::vector<SGUIPage> PageStackType;
|
||||
PageStackType m_PageStack;
|
||||
|
||||
shared_ptr<CGUI> m_CurrentGUI; // used to latch state during TickObjects/LoadPage (this is kind of ugly)
|
||||
|
||||
ScriptInterface& m_ScriptInterface;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -445,7 +445,7 @@ void IGUIObject::RegisterScriptHandler(const CStr& Action, const CStr& Code, CGU
|
|||
// Generate a unique name
|
||||
static int x=0;
|
||||
char buf[64];
|
||||
sprintf_s(buf, ARRAY_SIZE(buf), "__eventhandler%d", x++);
|
||||
sprintf_s(buf, ARRAY_SIZE(buf), "__eventhandler%d (%s)", x++, Action.c_str());
|
||||
|
||||
JSFunction* func = JS_CompileFunction(g_ScriptingHost.getContext(), pGUI->m_ScriptObject,
|
||||
buf, paramCount, paramNames, Code.c_str(), Code.length(), CodeName, 0);
|
||||
|
|
@ -484,7 +484,7 @@ void IGUIObject::ScriptEvent(const CStr& Action)
|
|||
jsval guiObject = PRIVATE_TO_JSVAL(this);
|
||||
|
||||
// Make a 'this', allowing access to the IGUIObject
|
||||
JSObject* jsGuiObject = JS_ConstructObjectWithArguments(g_ScriptingHost.getContext(), &JSI_IGUIObject::JSI_class, NULL, m_pGUI->m_ScriptObject, 1, &guiObject);
|
||||
JSObject* jsGuiObject = JS_ConstructObjectWithArguments(g_ScriptingHost.getContext(), &JSI_IGUIObject::JSI_class, m_pGUI->m_ScriptObject, NULL, 1, &guiObject);
|
||||
debug_assert(jsGuiObject); // TODO: Handle errors
|
||||
|
||||
// Prevent it from being garbage-collected before it's passed into the function
|
||||
|
|
@ -495,7 +495,7 @@ void IGUIObject::ScriptEvent(const CStr& Action)
|
|||
mouseParams[0] = INT_TO_JSVAL(m_pGUI->m_MousePos.x);
|
||||
mouseParams[1] = INT_TO_JSVAL(m_pGUI->m_MousePos.y);
|
||||
mouseParams[2] = INT_TO_JSVAL(m_pGUI->m_MouseButtons);
|
||||
JSObject* mouseObj = JS_ConstructObjectWithArguments(g_ScriptingHost.getContext(), &JSI_GUIMouse::JSI_class, NULL, m_pGUI->m_ScriptObject, 3, mouseParams);
|
||||
JSObject* mouseObj = JS_ConstructObjectWithArguments(g_ScriptingHost.getContext(), &JSI_GUIMouse::JSI_class, m_pGUI->m_ScriptObject, NULL, 3, mouseParams);
|
||||
debug_assert(mouseObj); // TODO: Handle errors
|
||||
|
||||
// Don't garbage collect the mouse
|
||||
|
|
|
|||
|
|
@ -336,14 +336,6 @@ static void InitScripting()
|
|||
new ScriptingHost;
|
||||
|
||||
RegisterJavascriptInterfaces();
|
||||
|
||||
#define REG_JS_CONSTANT(_name) g_ScriptingHost.DefineConstant(#_name, _name)
|
||||
REG_JS_CONSTANT(SDL_BUTTON_LEFT);
|
||||
REG_JS_CONSTANT(SDL_BUTTON_MIDDLE);
|
||||
REG_JS_CONSTANT(SDL_BUTTON_RIGHT);
|
||||
REG_JS_CONSTANT(SDL_BUTTON_WHEELUP);
|
||||
REG_JS_CONSTANT(SDL_BUTTON_WHEELDOWN);
|
||||
#undef REG_JS_CONSTANT
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@
|
|||
#include "graphics/UnitManager.h"
|
||||
#include "graphics/scripting/JSInterface_Camera.h"
|
||||
#include "graphics/scripting/JSInterface_LightEnv.h"
|
||||
#include "gui/GUIManager.h"
|
||||
#include "gui/IGUIObject.h"
|
||||
#include "lib/timer.h"
|
||||
#include "lib/svn_revision.h"
|
||||
#include "lib/frequency_filter.h"
|
||||
|
|
@ -61,7 +63,6 @@
|
|||
#define LOG_CATEGORY L"script"
|
||||
extern bool g_TerrainModified;
|
||||
|
||||
|
||||
// rationale: the function table is now at the end of the source file to
|
||||
// avoid the need for forward declarations for every function.
|
||||
|
||||
|
|
@ -404,6 +405,23 @@ JSBool SetCameraTarget( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval*
|
|||
return( JS_TRUE );
|
||||
}
|
||||
|
||||
JSBool GetGUIObjectByName(JSContext* cx, JSObject* UNUSED(obj), uintN UNUSED(argc), jsval* argv, jsval* rval)
|
||||
{
|
||||
try
|
||||
{
|
||||
CStr name = ToPrimitive<CStr>(cx, argv[0]);
|
||||
IGUIObject* guiObj = g_GUI->FindObjectByName(name);
|
||||
if (guiObj)
|
||||
*rval = OBJECT_TO_JSVAL(guiObj->GetJSObject());
|
||||
else
|
||||
*rval = JSVAL_NULL;
|
||||
return JS_TRUE;
|
||||
}
|
||||
catch (PSERROR_Scripting&)
|
||||
{
|
||||
return JS_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Miscellany
|
||||
|
|
@ -645,6 +663,7 @@ JSFunctionSpec ScriptFunctionTable[] =
|
|||
JS_FUNC("getCursorName", GetCursorName, 0)
|
||||
JS_FUNC("getFPS", GetFps, 0)
|
||||
JS_FUNC("isGameRunning", isGameRunning, 0)
|
||||
JS_FUNC("getGUIObjectByName", GetGUIObjectByName, 1)
|
||||
|
||||
// Miscellany
|
||||
JS_FUNC("v3dist", ComputeDistanceBetweenTwoPoints, 2)
|
||||
|
|
|
|||
|
|
@ -29,79 +29,24 @@
|
|||
|
||||
#define LOG_CATEGORY L"scriptinghost"
|
||||
|
||||
namespace
|
||||
{
|
||||
const int RUNTIME_MEMORY_ALLOWANCE = 16 * 1024 * 1024;
|
||||
const int STACK_CHUNK_SIZE = 16 * 1024;
|
||||
|
||||
JSClass GlobalClass =
|
||||
{
|
||||
"global", JSCLASS_GLOBAL_FLAGS,
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub,
|
||||
JS_ConvertStub, JS_FinalizeStub
|
||||
};
|
||||
}
|
||||
|
||||
ScriptingHost::ScriptingHost()
|
||||
: m_RunTime(NULL), m_Context(NULL), m_GlobalObject(NULL)
|
||||
{
|
||||
m_RunTime = JS_NewRuntime(RUNTIME_MEMORY_ALLOWANCE);
|
||||
if(!m_RunTime)
|
||||
m_ScriptInterface = new ScriptInterface("Engine");
|
||||
|
||||
m_Context = m_ScriptInterface->GetContext();
|
||||
|
||||
m_GlobalObject = JS_GetGlobalObject(m_Context);
|
||||
|
||||
if (!JS_DefineFunctions(m_Context, m_GlobalObject, ScriptFunctionTable))
|
||||
throw PSERROR_Scripting_SetupFailed();
|
||||
|
||||
m_Context = JS_NewContext(m_RunTime, STACK_CHUNK_SIZE);
|
||||
if(!m_Context)
|
||||
if (!JS_DefineProperties(m_Context, m_GlobalObject, ScriptGlobalTable))
|
||||
throw PSERROR_Scripting_SetupFailed();
|
||||
|
||||
// JS_SetGCZeal(m_Context, 2);
|
||||
|
||||
JS_SetErrorReporter(m_Context, ScriptingHost::ErrorReporter);
|
||||
|
||||
JS_SetVersion(m_Context, JSVERSION_LATEST);
|
||||
|
||||
JS_BeginRequest(m_Context);
|
||||
|
||||
m_GlobalObject = JS_NewObject(m_Context, &GlobalClass, NULL, NULL);
|
||||
if(!m_GlobalObject)
|
||||
throw PSERROR_Scripting_SetupFailed();
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Register our script and function handlers - note: docs say they don't like
|
||||
// nulls passed as closures, nor should they return nulls.
|
||||
JS_SetExecuteHook( m_RunTime, jshook_script, this );
|
||||
JS_SetCallHook( m_RunTime, jshook_function, this );
|
||||
#endif
|
||||
|
||||
if (JS_InitStandardClasses(m_Context, m_GlobalObject) == JSVAL_FALSE)
|
||||
throw PSERROR_Scripting_SetupFailed();
|
||||
|
||||
if (JS_DefineFunctions(m_Context, m_GlobalObject, ScriptFunctionTable) == JS_FALSE)
|
||||
throw PSERROR_Scripting_SetupFailed();
|
||||
|
||||
if( JS_DefineProperties( m_Context, m_GlobalObject, ScriptGlobalTable ) == JS_FALSE )
|
||||
throw PSERROR_Scripting_SetupFailed();
|
||||
|
||||
m_ScriptInterface = new ScriptInterface("Engine", m_Context);
|
||||
}
|
||||
|
||||
ScriptingHost::~ScriptingHost()
|
||||
{
|
||||
delete m_ScriptInterface;
|
||||
|
||||
if (m_Context != NULL)
|
||||
{
|
||||
JS_EndRequest(m_Context);
|
||||
JS_DestroyContext(m_Context);
|
||||
m_Context = NULL;
|
||||
}
|
||||
|
||||
if (m_RunTime != NULL)
|
||||
{
|
||||
JS_DestroyRuntime(m_RunTime);
|
||||
m_RunTime = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ScriptInterface& ScriptingHost::GetScriptInterface()
|
||||
|
|
@ -306,77 +251,3 @@ jsval ScriptingHost::UCStringToValue( const CStrW& str )
|
|||
{
|
||||
return STRING_TO_JSVAL(JS_NewUCStringCopyZ(m_Context, str.utf16().c_str()));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// called by SpiderMonkey whenever someone does JS_ReportError.
|
||||
// prints that message as well as locus to log, debug output and console.
|
||||
void ScriptingHost::ErrorReporter(JSContext* UNUSED(cx), const char* pmessage, JSErrorReport* report)
|
||||
{
|
||||
const char* file = report->filename? report->filename : "(current document)";
|
||||
int line = report->lineno;
|
||||
const char* message = pmessage? pmessage : "No error message available";
|
||||
// apparently there is no further information in this struct we can use
|
||||
// because linebuf/tokenptr require a buffer to have been allocated.
|
||||
// that doesn't look possible since we are a callback and there is
|
||||
// no mention in the docs about where this would happen (typical).
|
||||
|
||||
// for developer convenience: write to output window so they can
|
||||
// double-click on that line and be taken to the error locus.
|
||||
debug_printf(L"%hs(%d): %hs\n", file, line, message);
|
||||
|
||||
// note: CLogger's LOG already takes care of writing to the console,
|
||||
// so don't do that here.
|
||||
|
||||
LOG(CLogger::Error, LOG_CATEGORY, L"JavaScript Error (%hs, line %d): %hs", file, line, message);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
void* ScriptingHost::jshook_script( JSContext* UNUSED(cx), JSStackFrame* UNUSED(fp),
|
||||
JSBool before, JSBool* UNUSED(ok), void* closure )
|
||||
{
|
||||
if (!CProfileManager::IsInitialised())
|
||||
return closure;
|
||||
|
||||
if( before )
|
||||
{
|
||||
g_Profiler.StartScript( "script invocation" );
|
||||
}
|
||||
else
|
||||
g_Profiler.Stop();
|
||||
|
||||
return( closure );
|
||||
}
|
||||
|
||||
void* ScriptingHost::jshook_function( JSContext* cx, JSStackFrame* fp, JSBool before, JSBool* UNUSED(ok), void* closure )
|
||||
{
|
||||
if (!CProfileManager::IsInitialised())
|
||||
return closure;
|
||||
|
||||
JSFunction* fn = JS_GetFrameFunction( cx, fp );
|
||||
if( before )
|
||||
{
|
||||
if( fn )
|
||||
{
|
||||
g_Profiler.StartScript( JS_GetFunctionName( fn ) );
|
||||
}
|
||||
else
|
||||
g_Profiler.StartScript( "function invocation" );
|
||||
}
|
||||
else
|
||||
g_Profiler.Stop();
|
||||
|
||||
return( closure );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ private:
|
|||
JSClass * m_Class;
|
||||
};
|
||||
|
||||
JSRuntime * m_RunTime;
|
||||
JSContext * m_Context;
|
||||
JSObject * m_GlobalObject;
|
||||
|
||||
|
|
@ -73,13 +72,6 @@ private:
|
|||
|
||||
std::map < std::string, CustomType > m_CustomObjectTypes;
|
||||
|
||||
#ifndef NDEBUG
|
||||
// A hook to capture script calls
|
||||
static void* jshook_script( JSContext* cx, JSStackFrame* fp, JSBool before, JSBool* ok, void* closure );
|
||||
// A hook to capture function calls
|
||||
static void* jshook_function( JSContext* cx, JSStackFrame* fp, JSBool before, JSBool* ok, void* closure );
|
||||
#endif
|
||||
|
||||
// The long-term plan is to migrate from ScriptingHost to the newer shinier ScriptInterface.
|
||||
// For now, just have a ScriptInterface that hooks onto the ScriptingHost's context so they
|
||||
// can both be used.
|
||||
|
|
@ -126,8 +118,6 @@ public:
|
|||
std::string ValueToString(const jsval value);
|
||||
CStrW ValueToUCString(const jsval value);
|
||||
jsval UCStringToValue(const CStrW& str);
|
||||
|
||||
static void ErrorReporter(JSContext * context, const char * message, JSErrorReport * report);
|
||||
};
|
||||
|
||||
#define g_ScriptingHost ScriptingHost::GetSingleton()
|
||||
|
|
|
|||
Loading…
Reference in a new issue