diff --git a/binaries/data/mods/public/gui/session_new/selection.js b/binaries/data/mods/public/gui/session_new/selection.js index 0d7affe00e..5997cba66c 100644 --- a/binaries/data/mods/public/gui/session_new/selection.js +++ b/binaries/data/mods/public/gui/session_new/selection.js @@ -3,16 +3,21 @@ var g_Selection = {}; // { id: 1, id: 1, ... } for each selected entity ID 'id' var g_ActiveSelectionColour = { r:1, g:1, b:1, a:1 }; var g_InactiveSelectionColour = { r:0, g:0, b:0, a:0 }; +function setHighlight(ent, colour) +{ + Engine.GuiInterfaceCall("SetSelectionHighlight", { "entity":ent, "colour":colour }); +} + function toggleEntitySelection(ent) { if (g_Selection[ent]) { - Engine.SetEntitySelectionHighlight(ent, g_InactiveSelectionColour); + setHighlight(ent, g_InactiveSelectionColour); delete g_Selection[ent]; } else { - Engine.SetEntitySelectionHighlight(ent, g_ActiveSelectionColour); + setHighlight(ent, g_ActiveSelectionColour); g_Selection[ent] = 1; } } @@ -23,7 +28,7 @@ function addEntitySelection(ents) { if (!g_Selection[ent]) { - Engine.SetEntitySelectionHighlight(ent, g_ActiveSelectionColour); + setHighlight(ent, g_ActiveSelectionColour); g_Selection[ent] = 1; } } @@ -32,7 +37,7 @@ function addEntitySelection(ents) function resetEntitySelection() { for (var ent in g_Selection) - Engine.SetEntitySelectionHighlight(ent, g_InactiveSelectionColour); + setHighlight(ent, g_InactiveSelectionColour); g_Selection = {}; } diff --git a/binaries/data/mods/public/gui/session_new/session.js b/binaries/data/mods/public/gui/session_new/session.js index 251a6deff3..ebf293d302 100644 --- a/binaries/data/mods/public/gui/session_new/session.js +++ b/binaries/data/mods/public/gui/session_new/session.js @@ -13,12 +13,12 @@ function onSimulationUpdate() function updateDebug() { var debug = getGUIObjectByName("debug"); - var simState = Engine.GetSimulationState(); + var simState = Engine.GuiInterfaceCall("GetSimulationState"); var text = "Simulation:\n" + uneval(simState); text += "\n\n"; for (var ent in g_Selection) { - text += "Entity "+ent+":\n" + uneval(Engine.GetEntityState(ent)) + "\n"; + text += "Entity "+ent+":\n" + uneval(Engine.GuiInterfaceCall("GetEntityState", ent)) + "\n"; } debug.caption = text; } @@ -28,7 +28,7 @@ function updateBuildButton() var selection = getEntitySelection(); if (selection.length) { - var entity = Engine.GetEntityState(selection[0]); + var entity = Engine.GuiInterfaceCall("GetEntityState", selection[0]); if (entity.buildEntities && entity.buildEntities.length) { var ent = entity.buildEntities[0]; diff --git a/binaries/data/mods/public/simulation/components/GuiInterface.js b/binaries/data/mods/public/simulation/components/GuiInterface.js index e9bfc5dd37..48e0940444 100644 --- a/binaries/data/mods/public/simulation/components/GuiInterface.js +++ b/binaries/data/mods/public/simulation/components/GuiInterface.js @@ -45,13 +45,13 @@ GuiInterface.prototype.GetEntityState = function(player, ent) return ret; }; -GuiInterface.prototype.SetSelectionHighlight = function(ent, colour) +GuiInterface.prototype.SetSelectionHighlight = function(player, cmd) { - var cmpSelectable = Engine.QueryInterface(ent, IID_Selectable); - cmpSelectable.SetSelectionHighlight(colour); + var cmpSelectable = Engine.QueryInterface(cmd.entity, IID_Selectable); + cmpSelectable.SetSelectionHighlight(cmd.colour); }; -GuiInterface.prototype.SetBuildingPlacementPreview = function(cmd) +GuiInterface.prototype.SetBuildingPlacementPreview = function(player, cmd) { if (!this.placementEntity || this.placementEntity[0] != cmd.template) { @@ -78,10 +78,22 @@ GuiInterface.prototype.SetBuildingPlacementPreview = function(cmd) } }; -GuiInterface.prototype.ScriptCall = function(name, args) +// List the GuiInterface functions that can be safely called by GUI scripts. +// (GUI scripts are non-deterministic and untrusted, so these functions must be +// appropriately careful. They are called with a first argument "player", which is +// trusted and indicates the player associated with the current client; no data should +// be returned unless this player is meant to be able to see it.) +var exposedFunctions = { + "GetSimulationState": 1, + "GetEntityState": 1, + "SetSelectionHighlight": 1, + "SetBuildingPlacementPreview": 1 +}; + +GuiInterface.prototype.ScriptCall = function(player, name, args) { - if (name == "SetBuildingPlacementPreview") - this.SetBuildingPlacementPreview(args); + if (exposedFunctions[name]) + return this[name](player, args); else throw new Error("Invalid GuiInterface Call name \""+name+"\""); }; diff --git a/source/gui/scripting/ScriptFunctions.cpp b/source/gui/scripting/ScriptFunctions.cpp index 3c3b16631a..efda193176 100644 --- a/source/gui/scripting/ScriptFunctions.cpp +++ b/source/gui/scripting/ScriptFunctions.cpp @@ -108,44 +108,6 @@ static jsval CloneValueBetweenContexts(JSContext* cxFrom, JSContext* cxTo, jsval return JSVAL_VOID; } -CScriptVal GetSimulationState(void* cbdata) -{ - CGUIManager* guiManager = static_cast (cbdata); - - if (!g_UseSimulation2 || !g_Game) - return JSVAL_VOID; - CSimulation2* sim = g_Game->GetSimulation2(); - debug_assert(sim); - CmpPtr gui(*sim, SYSTEM_ENTITY); - if (gui.null()) - return JSVAL_VOID; - - int player = -1; - if (g_Game && g_Game->GetLocalPlayer()) - player = g_Game->GetLocalPlayer()->GetPlayerID(); - - return CloneValueBetweenContexts(sim->GetScriptInterface().GetContext(), guiManager->GetScriptInterface().GetContext(), gui->GetSimulationState(player).get()); -} - -CScriptVal GetEntityState(void* cbdata, entity_id_t ent) -{ - CGUIManager* guiManager = static_cast (cbdata); - - if (!g_UseSimulation2 || !g_Game) - return JSVAL_VOID; - CSimulation2* sim = g_Game->GetSimulation2(); - debug_assert(sim); - CmpPtr gui(*sim, SYSTEM_ENTITY); - if (gui.null()) - return JSVAL_VOID; - - int player = -1; - if (g_Game && g_Game->GetLocalPlayer()) - player = g_Game->GetLocalPlayer()->GetPlayerID(); - - return CloneValueBetweenContexts(sim->GetScriptInterface().GetContext(), guiManager->GetScriptInterface().GetContext(), gui->GetEntityState(player, ent).get()); -} - CScriptVal GuiInterfaceCall(void* cbdata, std::string name, CScriptVal data) { CGUIManager* guiManager = static_cast (cbdata); @@ -158,27 +120,16 @@ CScriptVal GuiInterfaceCall(void* cbdata, std::string name, CScriptVal data) if (gui.null()) return JSVAL_VOID; + int player = -1; + if (g_Game && g_Game->GetLocalPlayer()) + player = g_Game->GetLocalPlayer()->GetPlayerID(); + JSContext* cxGui = guiManager->GetScriptInterface().GetContext(); JSContext* cxSim = sim->GetScriptInterface().GetContext(); - CScriptVal ret = gui->ScriptCall(name, CloneValueBetweenContexts(cxGui, cxSim, data.get())); + CScriptVal ret = gui->ScriptCall(player, name, CloneValueBetweenContexts(cxGui, cxSim, data.get())); return CloneValueBetweenContexts(cxSim, cxGui, ret.get()); } -void SetEntitySelectionHighlight(void* UNUSED(cbdata), entity_id_t ent, CColor color) -{ - if (!g_UseSimulation2 || !g_Game) - return; - CSimulation2* sim = g_Game->GetSimulation2(); - debug_assert(sim); - CmpPtr gui(*sim, SYSTEM_ENTITY); - if (gui.null()) - return; - - // TODO: stop duplicating all this prolog code - - gui->SetSelectionHighlight(ent, color); -} - void PostNetworkCommand(void* cbdata, CScriptVal cmd) { CGUIManager* guiManager = static_cast (cbdata); @@ -226,9 +177,6 @@ void GuiScriptingInit(ScriptInterface& scriptInterface) // Simulation<->GUI interface functions: scriptInterface.RegisterFunction("IsNewSimulation"); - scriptInterface.RegisterFunction("GetSimulationState"); - scriptInterface.RegisterFunction("GetEntityState"); - scriptInterface.RegisterFunction("SetEntitySelectionHighlight"); scriptInterface.RegisterFunction("GuiInterfaceCall"); scriptInterface.RegisterFunction("PostNetworkCommand"); diff --git a/source/scriptinterface/ScriptInterface.h b/source/scriptinterface/ScriptInterface.h index 3f3917d778..18e78251c6 100644 --- a/source/scriptinterface/ScriptInterface.h +++ b/source/scriptinterface/ScriptInterface.h @@ -104,6 +104,12 @@ public: template bool CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, R& ret); + /** + * Call the named property on the given object, with return type R and 3 arguments + */ + template + bool CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2, R& ret); + jsval GetGlobalObject(); /** @@ -273,6 +279,21 @@ bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, co return FromJSVal(GetContext(), jsRet, ret); } +template +bool ScriptInterface::CallFunction(jsval val, const char* name, const T0& a0, const T1& a1, const T2& a2, R& ret) +{ + LOCAL_ROOT_SCOPE; + jsval jsRet; + std::vector argv; + argv.push_back(ToJSVal(GetContext(), a0)); + argv.push_back(ToJSVal(GetContext(), a1)); + argv.push_back(ToJSVal(GetContext(), a2)); + bool ok = CallFunction_(val, name, argv, jsRet); + if (!ok) + return false; + return FromJSVal(GetContext(), jsRet, ret); +} + template bool ScriptInterface::SetGlobal(const char* name, const T& value, bool replace) { diff --git a/source/simulation2/components/ICmpGuiInterface.cpp b/source/simulation2/components/ICmpGuiInterface.cpp index de993d9497..d963fa3e13 100644 --- a/source/simulation2/components/ICmpGuiInterface.cpp +++ b/source/simulation2/components/ICmpGuiInterface.cpp @@ -30,25 +30,9 @@ class CCmpGuiInterfaceScripted : public ICmpGuiInterface public: DEFAULT_SCRIPT_WRAPPER(GuiInterfaceScripted) - virtual CScriptVal GetSimulationState(int player) + virtual CScriptVal ScriptCall(int player, std::string cmd, CScriptVal data) { - return m_Script.Call ("GetSimulationState", player); - } - - virtual CScriptVal GetEntityState(int player, entity_id_t ent) - { - return m_Script.Call ("GetEntityState", player, ent); - } - - virtual void SetSelectionHighlight(entity_id_t ent, const CColor& color) - { - m_Script.Call ("SetSelectionHighlight", ent, color); - // ignore return value - } - - virtual CScriptVal ScriptCall(std::string name, CScriptVal data) - { - return m_Script.Call ("ScriptCall", name, data); + return m_Script.Call ("ScriptCall", player, cmd, data); } }; diff --git a/source/simulation2/components/ICmpGuiInterface.h b/source/simulation2/components/ICmpGuiInterface.h index ad9e23ee22..0025dfe8b4 100644 --- a/source/simulation2/components/ICmpGuiInterface.h +++ b/source/simulation2/components/ICmpGuiInterface.h @@ -25,14 +25,10 @@ struct CColor; class ICmpGuiInterface : public IComponent { public: - virtual CScriptVal GetSimulationState(int player) = 0; - virtual CScriptVal GetEntityState(int player, entity_id_t ent) = 0; - virtual void SetSelectionHighlight(entity_id_t ent, const CColor& color) = 0; - /** * Generic call function, for use by GUI scripts to talk to the GuiInterface script. */ - virtual CScriptVal ScriptCall(std::string name, CScriptVal data) = 0; + virtual CScriptVal ScriptCall(int player, std::string cmd, CScriptVal data) = 0; // TODO: some of the earlier functions should just use ScriptCall. DECLARE_INTERFACE_TYPE(GuiInterface)