distinguish between local and remote scripting

This commit is contained in:
Emil Axelsson
2016-09-16 14:53:20 +02:00
parent 41fafcb5df
commit 13610b390d
24 changed files with 419 additions and 273 deletions

View File

@@ -67,6 +67,7 @@ public:
void addKeyframe(const network::datamessagestructures::CameraKeyframe &kf);
void clearKeyframes();
void bindKeyLocal(Key key, KeyModifier modifier, std::string lua);
void bindKey(Key key, KeyModifier modifier, std::string lua);
void lockControls();
void unlockControls();
@@ -109,7 +110,7 @@ private:
bool _cameraUpdatedFromScript = false;
std::multimap<KeyWithModifier, std::string > _keyLua;
std::multimap<KeyWithModifier, std::pair<std::string, bool>> _keyLua;
std::unique_ptr<InputState> _inputState;
Camera* _camera;

View File

@@ -26,6 +26,7 @@
#define LUACONSOLE_H
#include <openspace/scripting/scriptengine.h>
#include <openspace/network/parallelconnection.h>
#include <openspace/util/keys.h>
@@ -50,12 +51,16 @@ public:
bool isVisible() const;
void setVisible(bool visible);
void toggleVisibility();
bool isRemoteScripting() const;
void setRemoteScripting(bool remoteScripting);
void toggleMode();
static scripting::LuaLibrary luaLibrary();
private:
void parallelConnectionChanged(const network::Status& status);
void addToCommand(std::string c);
std::string UnicodeToUTF8(unsigned int codepoint);
@@ -73,6 +78,7 @@ private:
} _autoCompleteInfo;
bool _isVisible;
bool _remoteScripting;
};
} // namespace openspace

View File

@@ -33,6 +33,9 @@
//glm includes
#include <glm/gtx/quaternion.hpp>
//ghoul includes
#include <ghoul/designpattern/event.h>
//std includes
#include <string>
#include <vector>
@@ -59,16 +62,24 @@ typedef int _SOCKET;
#include <netdb.h>
#endif
namespace openspace{
namespace openspace {
namespace network{
namespace network {
enum class Status : uint32_t {
Disconnected = 0,
ClientWithoutHost,
ClientWithHost,
Host
};
enum class MessageType : uint32_t {
Authentication = 0,
Data,
HostInformation,
ConnectionStatus,
HostshipRequest,
HostshipResignation
HostshipResignation,
NConnections
};
struct Message {
@@ -106,9 +117,13 @@ namespace openspace{
void setAddress(const std::string &address);
void setName(const std::string& name);
bool isAuthenticated();
bool isHost();
const std::string& hostName();
void requestHostship(const std::string &password);
void resignHostship();
@@ -133,7 +148,15 @@ namespace openspace{
* interaction
*/
static scripting::LuaLibrary luaLibrary();
Status status();
size_t nConnections();
std::shared_ptr<ghoul::Event<>> connectionEvent();
protected:
private:
@@ -162,7 +185,10 @@ namespace openspace{
void dataMessageReceived(const std::vector<char>& messageContent);
void hostInfoMessageReceived(const std::vector<char>& messageContent);
void connectionStatusMessageReceived(const std::vector<char>& messageContent);
void nConnectionsMessageReceived(const std::vector<char>& messageContent);
void broadcast();
@@ -171,26 +197,37 @@ namespace openspace{
void sendFunc();
void threadManagement();
void setStatus(Status status);
void setHostName(const std::string& hostName);
void setNConnections(size_t nConnections);
std::string scriptFromPropertyAndValue(const std::string property, const std::string value);
//std::string scriptFromPropertyAndValue(const std::string property, const std::string value);
uint32_t _passCode;
std::string _port;
std::string _address;
std::string _name;
_SOCKET _clientSocket;
std::unique_ptr<std::thread> _connectionThread;
std::unique_ptr<std::thread> _broadcastThread;
std::unique_ptr<std::thread> _sendThread;
std::unique_ptr<std::thread> _listenThread;
std::unique_ptr<std::thread> _handlerThread;
std::atomic<bool> _isHost;
std::atomic<bool> _isConnected;
std::atomic<bool> _isRunning;
std::atomic<bool> _tryConnect;
std::atomic<bool> _disconnect;
std::atomic<bool> _initializationTimejumpRequired;
std::atomic<size_t> _nConnections;
std::atomic<Status> _status;
std::string _hostName;
std::condition_variable _disconnectCondition;
std::mutex _disconnectMutex;
@@ -206,6 +243,8 @@ namespace openspace{
std::atomic<bool> _latestTimeKeyframeValid;
std::map<std::string, std::string> _currentState;
std::mutex _currentStateMutex;
std::shared_ptr<ghoul::Event<>> _connectionEvent;
};
} // namespace network

View File

@@ -37,9 +37,8 @@ namespace scripting {
struct LuaLibrary {
/**
* This structure represents a Lua function with its #name, #function pointer
* #argumentText describing the arguments this function takes, the #helpText
* describing the function, and whether it should be shared in a parallel
* connection (#parallelShared)
* #argumentText describing the arguments this function takes, and the the #helpText
* describing the function.
*/
struct Function {
/// The name of the function
@@ -50,9 +49,6 @@ struct LuaLibrary {
std::string argumentText;
/// A help text describing what the function does/
std::string helpText;
/// If <code>true</code>, this function will be shared with other parallel
/// connections
bool parallelShared;
};
/// The name of the library
std::string name;

View File

@@ -49,6 +49,7 @@ namespace scripting {
*/
class ScriptEngine {
public:
using RemoteScripting = ghoul::Boolean;
/**
* Initializes the internal Lua state and registers a common set of library functions
* \throw LuaRuntimeException If the creation of the new Lua state fails
@@ -81,7 +82,7 @@ public:
void preSynchronization();
void queueScript(const std::string &script);
void queueScript(const std::string &script, RemoteScripting remoteScripting);
void setLogFile(const std::string& filename, const std::string& type);
@@ -90,9 +91,9 @@ public:
std::vector<std::string> allLuaFunctions() const;
//parallel functions
bool parseLibraryAndFunctionNames(std::string &library, std::string &function, const std::string &script);
bool shouldScriptBeSent(const std::string &library, const std::string &function);
void cacheScript(const std::string &library, const std::string &function, const std::string &script);
//bool parseLibraryAndFunctionNames(std::string &library, std::string &function, const std::string &script);
//bool shouldScriptBeSent(const std::string &library, const std::string &function);
//void cacheScript(const std::string &library, const std::string &function, const std::string &script);
private:
@@ -109,13 +110,13 @@ private:
//sync variables
std::mutex _mutex;
std::vector<std::string> _queuedScripts;
std::vector<std::pair<std::string, bool>> _queuedScripts;
std::vector<std::string> _receivedScripts;
std::string _currentSyncedScript;
//parallel variables
std::map<std::string, std::map<std::string, std::string>> _cachedScripts;
std::mutex _cachedScriptsMutex;
//std::map<std::string, std::map<std::string, std::string>> _cachedScripts;
//std::mutex _cachedScriptsMutex;
//logging variables
bool _logFileExists = false;

View File

@@ -155,7 +155,7 @@ void addScreenSpaceRenderable(std::string texturePath) {
std::string luaTable =
"{Type = 'ScreenSpaceImage', TexturePath = '" + absPath(texturePath) + "' }";
std::string script = "openspace.registerScreenSpaceRenderable(" + luaTable + ");";
OsEng.scriptEngine().queueScript(script);
OsEng.scriptEngine().queueScript(script, openspace::scripting::ScriptEngine::RemoteScripting::Yes);
}
} // namespace
@@ -453,22 +453,26 @@ void GUI::render() {
if (toSun) {
OsEng.scriptEngine().queueScript(
"openspace.setPropertyValue('Interaction.coordinateSystem', 'Sun');"
"openspace.setPropertyValue('Interaction.coordinateSystem', 'Sun');",
scripting::ScriptEngine::RemoteScripting::Yes
);
}
if (toPluto) {
OsEng.scriptEngine().queueScript(
"openspace.setPropertyValue('Interaction.coordinateSystem', 'Pluto');"
"openspace.setPropertyValue('Interaction.coordinateSystem', 'Pluto');",
scripting::ScriptEngine::RemoteScripting::Yes
);
}
if (toJupiter) {
OsEng.scriptEngine().queueScript(
"openspace.setPropertyValue('Interaction.coordinateSystem', 'Jupiter');"
"openspace.setPropertyValue('Interaction.coordinateSystem', 'Jupiter');",
scripting::ScriptEngine::RemoteScripting::Yes
);
}
if (to67P) {
OsEng.scriptEngine().queueScript(
"openspace.setPropertyValue('Interaction.coordinateSystem', '67P');"
"openspace.setPropertyValue('Interaction.coordinateSystem', '67P');",
scripting::ScriptEngine::RemoteScripting::Yes
);
}

View File

@@ -65,7 +65,8 @@ void GuiOriginComponent::render() {
if (hasChanged) {
OsEng.scriptEngine().queueScript(
"openspace.setPropertyValue('Interaction.origin', '" +
nodes[currentPosition]->name() + "');"
nodes[currentPosition]->name() + "');",
scripting::ScriptEngine::RemoteScripting::Yes
);
}
}

View File

@@ -38,7 +38,8 @@ void GuiTimeComponent::render() {
bool changed = ImGui::SliderFloat("Delta Time", &deltaTime, -5000.f, 5000.f);
if (changed) {
OsEng.scriptEngine().queueScript(
"openspace.time.setDeltaTime(" + std::to_string(deltaTime) + ")"
"openspace.time.setDeltaTime(" + std::to_string(deltaTime) + ")",
scripting::ScriptEngine::RemoteScripting::Yes
);
}
}

View File

@@ -47,7 +47,7 @@ void renderTooltip(Property* prop) {
void executeScript(const std::string& id, const std::string& value) {
std::string script =
"openspace.setPropertyValueSingle('" + id + "', " + value + ");";
OsEng.scriptEngine().queueScript(script);
OsEng.scriptEngine().queueScript(script, scripting::ScriptEngine::RemoteScripting::Yes);
}
void renderBoolProperty(Property* prop, const std::string& ownerName) {

View File

@@ -15,10 +15,14 @@ openspace.bindKey("q", helper.renderable.toggle('SunMarker'))
openspace.bindKey("e", helper.renderable.toggle('EarthMarker'))
openspace.bindKey("x", helper.renderable.toggle('Constellation Bounds'))
openspace.bindKey("c", "openspace.parallel.setAddress('130.236.142.51');openspace.parallel.setPassword('newhorizons-20150714');openspace.parallel.connect();")
--openspace.bindKey("c", "openspace.parallel.setAddress('130.236.142.51');openspace.parallel.setPassword('newhorizons-20150714');openspace.parallel.connect();")
openspace.bindKey("h", "openspace.iswa.setBaseUrl('https://iswa-demo-server.herokuapp.com/')");
--openspace.bindKey("h", "openspace.iswa.setBaseUrl('https://iswa-demo-server.herokuapp.com/')");
openspace.bindKey("g", "openspace.iswa.setBaseUrl('http://128.183.168.116:3000/')");
openspace.bindKey("l", "openspace.iswa.setBaseUrl('http://localhost:3000/')");
openspace.bindKey("v", "openspace.time.setTime('2015-03-15T02:00:00.00')");
openspace.bindKey("v", "openspace.time.setTime('2015-03-15T02:00:00.00')");
openspace.bindKeyLocal("h", "openspace.parallel.setAddress('127.0.0.2');openspace.parallel.setPort('25001');openspace.parallel.setPassword('test');openspace.parallel.connect();openspace.parallel.requestHostship('test');")
openspace.bindKeyLocal("c", "openspace.parallel.setAddress('127.0.0.3');openspace.parallel.setPort('25001');openspace.parallel.setPassword('test');openspace.parallel.connect();")
openspace.bindKeyLocal("d", "openspace.parallel.setAddress('127.0.0.4');openspace.parallel.setPort('25001');openspace.parallel.setPassword('test');openspace.parallel.connect();")

View File

@@ -17,10 +17,12 @@ openspace.bindKey("s", "openspace.setPropertyValue('Interaction.origin', 'Rosett
-- openspace.bindKey("F5", "openspace.setPropertyValue('Interaction.coordinateSystem', 'Sun'); openspace.printInfo('Changing Viewpoint to Sun');");
openspace.bindKey("F6", "openspace.setPropertyValue('Interaction.coordinateSystem', '67P'); openspace.printInfo('Changing Viewpoint to 67P');");
openspace.bindKey("F7", "openspace.time.setTime('2014-08-15T03:05:18.101')");
openspace.bindKey("F8", "openspace.setPropertyValue('67P.renderable.ProjectionComponent.clearAllProjections', true);");
openspace.bindKey("i", helper.renderable.toggle('ImagePlaneRosetta'))
openspace.bindKey("q", helper.renderable.toggle('SunMarker'))
openspace.bindKey("e", helper.renderable.toggle('EarthMarker'))
openspace.bindKey("c", "openspace.parallel.setAddress('130.236.142.51');openspace.parallel.setPassword('newhorizons-20150714');openspace.parallel.connect();")
openspace.bindKeyLocal("h", "openspace.parallel.setAddress('127.0.0.1');openspace.parallel.setPort('25001');openspace.parallel.setPassword('test');openspace.parallel.connect();openspace.parallel.requestHostship('test');")
openspace.bindKeyLocal("c", "openspace.parallel.setAddress('127.0.0.1');openspace.parallel.setPort('25001');openspace.parallel.setPassword('test');openspace.parallel.connect();")

View File

@@ -7,24 +7,24 @@ helper.property = {}
-- Function that sets the most common key bindings that are common to most (all?)
-- scenes
helper.setCommonKeys = function()
openspace.bindKey("F1", "openspace.gui.toggle()")
openspace.bindKey("F2", "openspace.setPerformanceMeasurement(true)")
openspace.bindKey("F3", "openspace.setPerformanceMeasurement(false)")
openspace.bindKeyLocal("F1", "openspace.gui.toggle()")
openspace.bindKeyLocal("F2", "openspace.setPerformanceMeasurement(true)")
openspace.bindKeyLocal("F3", "openspace.setPerformanceMeasurement(false)")
openspace.bindKey("t", "openspace.toggleFrametimeType(1)")
openspace.bindKey("Shift+t", "openspace.toggleFrametimeType(0)")
openspace.bindKeyLocal("t", "openspace.toggleFrametimeType(1)")
openspace.bindKeyLocal("Shift+t", "openspace.toggleFrametimeType(0)")
openspace.bindKey("ESC", "openspace.toggleShutdown()")
openspace.bindKeyLocal("ESC", "openspace.toggleShutdown()")
openspace.bindKey("PRINT_SCREEN", "openspace.takeScreenshot()")
openspace.bindKeyLocal("PRINT_SCREEN", "openspace.takeScreenshot()")
openspace.bindKey("SPACE", "openspace.time.togglePause()")
openspace.bindKey("COMMA", "openspace.setRenderer('Framebuffer');")
openspace.bindKey("PERIOD", "openspace.setRenderer('ABuffer');")
openspace.bindKey("f", helper.property.invert('Interaction.rotationalFriction'))
openspace.bindKey("Shift+f", helper.property.invert('Interaction.zoomFriction'))
openspace.bindKeyLocal("f", helper.property.invert('Interaction.rotationalFriction'))
openspace.bindKeyLocal("Shift+f", helper.property.invert('Interaction.zoomFriction'))
openspace.bindKey("w", "openspace.toggleFade(3)")
end

View File

@@ -556,6 +556,7 @@ void OpenSpaceEngine::runScripts(const ghoul::Dictionary& scripts) {
//@JK
//temporary solution to ensure that startup scripts may be syncrhonized over parallel connection
/*
std::ifstream scriptFile;
scriptFile.open(absoluteScriptPath.c_str());
std::string line;
@@ -569,7 +570,7 @@ void OpenSpaceEngine::runScripts(const ghoul::Dictionary& scripts) {
_engine->scriptEngine().cacheScript(lib, func, line);
}
}
}
}*/
}
}
@@ -858,14 +859,13 @@ void OpenSpaceEngine::keyboardCallback(Key key, KeyModifier mod, KeyAction actio
return;
}
#endif
if (key == _console->commandInputButton() && (action == KeyAction::Press || action == KeyAction::Repeat))
_console->toggleVisibility();
if (!_console->isVisible()) {
if (key == _console->commandInputButton()) {
if (action == KeyAction::Press) {
_console->toggleMode();
}
} else if (!_console->isVisible()) {
_interactionHandler->keyboardCallback(key, mod, action);
}
else {
} else {
_console->keyboardCallback(key, mod, action);
}
}

View File

@@ -269,8 +269,10 @@ void InteractionHandler::keyboardCallback(Key key, KeyModifier modifier, KeyActi
// iterate over key bindings
auto ret = _keyLua.equal_range({ key, modifier });
for (auto it = ret.first; it != ret.second; ++it) {
//OsEng.scriptEngine()->runScript(it->second);
OsEng.scriptEngine().queueScript(it->second);
OsEng.scriptEngine().queueScript(it->second.first,
it->second.second ?
scripting::ScriptEngine::RemoteScripting::Yes :
scripting::ScriptEngine::RemoteScripting::No);
}
}
}
@@ -378,12 +380,20 @@ void InteractionHandler::resetKeyBindings() {
_keyLua.clear();
}
void InteractionHandler::bindKeyLocal(Key key, KeyModifier modifier, std::string lua) {
_keyLua.insert({
{ key, modifier },
std::make_pair(lua, false)
});
}
void InteractionHandler::bindKey(Key key, KeyModifier modifier, std::string lua) {
_keyLua.insert({
{ key, modifier },
lua
std::make_pair(lua, true)
});
}
void InteractionHandler::writeKeyboardDocumentation(const std::string& type, const std::string& file)
{
@@ -391,8 +401,14 @@ void InteractionHandler::writeKeyboardDocumentation(const std::string& type, con
std::ofstream f(absPath(file));
for (const auto& p : _keyLua) {
std::string remoteScriptingInfo;
bool remoteScripting = p.second.second;
if (!remoteScripting) {
remoteScriptingInfo = " (LOCAL)";
}
f << std::to_string(p.first) << ": " <<
p.second << std::endl;
p.second.first << remoteScriptingInfo << std::endl;
}
}
else {
@@ -417,7 +433,14 @@ scripting::LuaLibrary InteractionHandler::luaLibrary() {
"bindKey",
&luascriptfunctions::bindKey,
"string, string",
"Binds a key by name to a lua string command"
"Binds a key by name to a lua string command to execute both locally "
"and to broadcast to clients if this is the host of a parallel session"
},
{
"bindKeyLocal",
&luascriptfunctions::bindKeyLocal,
"string, string",
"Binds a key by name to a lua string command to execute only locally"
},
{
"setInteractionMode",

View File

@@ -60,7 +60,9 @@ int setOrigin(lua_State* L) {
/**
* \ingroup LuaScripts
* bindKey():
* Binds a key to Lua command
* Binds a key to Lua command to both execute locally
* and broadcast to all clients if this node is hosting
* a parallel connection.
*/
int bindKey(lua_State* L) {
using ghoul::lua::luaTypeToString;
@@ -93,6 +95,42 @@ int bindKey(lua_State* L) {
return 0;
}
/**
* \ingroup LuaScripts
* bindKey():
* Binds a key to Lua command to execute only locally
*/
int bindKeyLocal(lua_State* L) {
using ghoul::lua::luaTypeToString;
int nArguments = lua_gettop(L);
if (nArguments != 2)
return luaL_error(L, "Expected %i arguments, got %i", 2, nArguments);
std::string key = luaL_checkstring(L, -2);
std::string command = luaL_checkstring(L, -1);
if (command.empty())
return luaL_error(L, "Command string is empty");
openspace::KeyWithModifier iKey = openspace::stringToKey(key);
if (iKey.key == openspace::Key::Unknown) {
LERRORC("lua.bindKey", "Could not find key '" << key << "'");
return 0;
}
OsEng.interactionHandler().bindKeyLocal(
iKey.key,
iKey.modifier,
command
);
return 0;
}
/**
* \ingroup LuaScripts
* clearKeys():
@@ -176,120 +214,7 @@ int resetCameraDirection(lua_State* L) {
OsEng.interactionHandler().resetCameraDirection();
}
#ifdef USE_OLD_INTERACTIONHANDLER
/**
* \ingroup LuaScripts
* dt(bool):
* Get current frame time
*/
int dt(lua_State* L) {
/*
int nArguments = lua_gettop(L);
if (nArguments != 0)
return luaL_error(L, "Expected %i arguments, got %i", 0, nArguments);
lua_pushnumber(L,OsEng.interactionHandler().deltaTime());
*/return 1;
}
/**
* \ingroup LuaScripts
* distance(double, double):
* Change distance to origin
*/
int distance(lua_State* L) {
/*
int nArguments = lua_gettop(L);
if (nArguments != 2)
return luaL_error(L, "Expected %i arguments, got %i", 2, nArguments);
double d1 = luaL_checknumber(L, -2);
double d2 = luaL_checknumber(L, -1);
PowerScaledScalar dist(static_cast<float>(d1), static_cast<float>(d2));
OsEng.interactionHandler().distanceDelta(dist);
*/
return 0;
}
/**
* \ingroup LuaScripts
* setInteractionSensitivity(double):
* Changes the global interaction sensitivity to the passed value
*/
int setInteractionSensitivity(lua_State* L) {
int nArguments = lua_gettop(L);
if (nArguments != 1)
return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments);
float sensitivity = static_cast<float>(luaL_checknumber(L, -1));
//OsEng.interactionHandler().setInteractionSensitivity(sensitivity);
return 0;
}
/**
* \ingroup LuaScripts
* interactionSensitivity():
* Returns the current, global interaction sensitivity
*/
int interactionSensitivity(lua_State* L) {
//float sensitivity = OsEng.interactionHandler().interactionSensitivity();
//lua_pushnumber(L, sensitivity);
return 1;
}
/**
* \ingroup LuaScripts
* setInvertRoll(bool):
* Determines if the roll movement is inverted
*/
int setInvertRoll(lua_State* L) {
int nArguments = lua_gettop(L);
if (nArguments != 1)
return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments);
bool invert = lua_toboolean(L, -1) == 1;
//OsEng.interactionHandler().setInvertRoll(invert);
return 0;
}
/**
* \ingroup LuaScripts
* invertRoll():
* Returns the current setting for inversion of roll movement
*/
int invertRoll(lua_State* L) {
//bool invert = OsEng.interactionHandler().invertRoll();
//lua_pushboolean(L, invert);
return 1;
}
/**
* \ingroup LuaScripts
* setInvertRotation(bool):
* Determines if the rotation movement is inverted
*/
int setInvertRotation(lua_State* L) {
int nArguments = lua_gettop(L);
if (nArguments != 1)
return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments);
bool invert = lua_toboolean(L, -1) == 1;
//OsEng.interactionHandler().setInvertRotation(invert);
return 0;
}
/**
* \ingroup LuaScripts
* invertRotation():
* Returns the current setting for inversion of rotation movement
*/
int invertRotation(lua_State* L) {
//bool invert = OsEng.interactionHandler().invertRotation();
//lua_pushboolean(L, invert);
return 1;
}
#endif USE_OLD_INTERACTIONHANDLER
} // namespace luascriptfunctions
} // namespace openspace

View File

@@ -58,6 +58,7 @@ LuaConsole::LuaConsole()
, _filename("")
, _autoCompleteInfo({NoAutoComplete, false, ""})
, _isVisible(false)
, _remoteScripting(true)
{
// _commands.push_back("");
// _activeCommand = _commands.size() - 1;
@@ -89,6 +90,13 @@ void LuaConsole::initialize() {
}
_commands.push_back("");
_activeCommand = _commands.size() - 1;
OsEng.parallelConnection().connectionEvent()->subscribe("luaConsole",
"statusChanged", [this]() {
network::Status status = OsEng.parallelConnection().status();
parallelConnectionChanged(status);
});
}
void LuaConsole::deinitialize() {
@@ -102,6 +110,8 @@ void LuaConsole::deinitialize() {
file.write(s.c_str(), length);
}
}
OsEng.parallelConnection().connectionEvent()->unsubscribe("luaConsole");
}
void LuaConsole::keyboardCallback(Key key, KeyModifier modifier, KeyAction action) {
@@ -169,7 +179,8 @@ void LuaConsole::keyboardCallback(Key key, KeyModifier modifier, KeyAction actio
else {
std::string cmd = _commands.at(_activeCommand);
if (cmd != "") {
OsEng.scriptEngine().queueScript(cmd);
OsEng.scriptEngine().queueScript(cmd,
_remoteScripting ? scripting::ScriptEngine::RemoteScripting::Yes : scripting::ScriptEngine::RemoteScripting::No);
// Only add the current command to the history if it hasn't been
// executed before. We don't want two of the same commands in a row
@@ -309,13 +320,28 @@ void LuaConsole::render() {
startY = startY - font_size * 15.0f * 2.0f;
const glm::vec4 red(1, 0, 0, 1);
const glm::vec4 lightBlue(0.4, 0.4, 1, 1);
const glm::vec4 green(0, 1, 0, 1);
const glm::vec4 white(1, 1, 1, 1);
std::shared_ptr<ghoul::fontrendering::Font> font = OsEng.fontManager().font("Mono", font_size);
using ghoul::fontrendering::RenderFont;
RenderFont(*font, glm::vec2(15.f, startY), red, "$");
if (_remoteScripting) {
int nClients = OsEng.parallelConnection().nConnections() - 1;
if (nClients == 1) {
RenderFont(*font, glm::vec2(15.f, startY + 20.0f), red, "Broadcasting script to 1 client");
} else {
RenderFont(*font, glm::vec2(15.f, startY + 20.0f), red, ("Broadcasting script to " + std::to_string(nClients) + " clients").c_str());
}
RenderFont(*font, glm::vec2(15.f, startY), red, "$");
}
else {
if (OsEng.parallelConnection().isHost()) {
RenderFont(*font, glm::vec2(15.f, startY + 20.0f), lightBlue, "Local script execution");
}
RenderFont(*font, glm::vec2(15.f, startY), lightBlue, "$");
}
RenderFont(*font, glm::vec2(15.f + font_size, startY), white, "%s", _commands.at(_activeCommand).c_str());
size_t n = std::count(_commands.at(_activeCommand).begin(), _commands.at(_activeCommand).begin() + _inputPosition, '\n');
@@ -390,10 +416,24 @@ void LuaConsole::setVisible(bool visible) {
_isVisible = visible;
}
void LuaConsole::toggleVisibility() {
_isVisible = !_isVisible;
void LuaConsole::toggleMode() {
if (_isVisible) {
if (_remoteScripting) {
_remoteScripting = false;
} else {
_isVisible = false;
}
} else {
_remoteScripting = OsEng.parallelConnection().isHost();
_isVisible = true;
}
}
void LuaConsole::parallelConnectionChanged(const network::Status& status) {
_remoteScripting = status == network::Status::Host;
}
scripting::LuaLibrary LuaConsole::luaLibrary() {
return {
"console",

View File

@@ -64,7 +64,7 @@ int toggle(lua_State* L) {
if (nArguments != 0)
return luaL_error(L, "Expected %i arguments, got %i", 0, nArguments);
OsEng.console().toggleVisibility();
OsEng.console().toggleMode();
return 0;
}

View File

@@ -67,7 +67,7 @@ bool NetworkEngine::handleMessage(const std::string& message) {
{
std::string script = message.substr(1);
//LINFO("Received Lua Script: '" << script << "'");
OsEng.scriptEngine().queueScript(script);
OsEng.scriptEngine().queueScript(script, scripting::ScriptEngine::RemoteScripting::No);
return true;
}
case MessageTypeExternalControlConnected:

View File

@@ -84,14 +84,16 @@ ParallelConnection::ParallelConnection()
, _listenThread(nullptr)
, _handlerThread(nullptr)
, _isRunning(true)
, _isHost(false)
, _nConnections(0)
, _status(Status::Disconnected)
, _hostName("")
, _isConnected(false)
, _tryConnect(false)
, _disconnect(false)
, _latestTimeKeyframeValid(false)
, _initializationTimejumpRequired(false)
{
//create handler thread
_connectionEvent = std::make_shared<ghoul::Event<>>();
_handlerThread = std::make_unique<std::thread>(&ParallelConnection::threadManagement, this);
}
@@ -174,7 +176,7 @@ void ParallelConnection::disconnect(){
_isConnected.store(false);
//tell broadcast thread to stop broadcasting (we're no longer host)
_isHost.store(false);
setStatus(Status::Disconnected);
//join connection thread and delete it
if(_connectionThread != nullptr){
@@ -320,8 +322,14 @@ void ParallelConnection::establishConnection(addrinfo *info){
//we no longer need to try to establish connection
_tryConnect.store(false);
_sendBufferMutex.lock();
_sendBuffer.clear();
_sendBufferMutex.unlock();
//send authentication
sendAuthentication();
} else {
LINFO("Connection attempt failed.");
}
#ifdef WIN32
@@ -380,8 +388,11 @@ void ParallelConnection::handleMessage(const Message& message) {
case MessageType::Data:
dataMessageReceived(message.content);
break;
case MessageType::HostInformation:
hostInfoMessageReceived(message.content);
case MessageType::ConnectionStatus:
connectionStatusMessageReceived(message.content);
break;
case MessageType::NConnections:
nConnectionsMessageReceived(message.content);
break;
default:
//unknown message type
@@ -475,7 +486,7 @@ void ParallelConnection::dataMessageReceived(const std::vector<char>& messageCon
uint32_t type = *(reinterpret_cast<const uint32_t*>(messageContent.data()));
std::vector<char> buffer(messageContent.begin() + sizeof(uint32_t), messageContent.end());
switch(type){
switch(static_cast<network::datamessagestructures::Type>(type)) {
case network::datamessagestructures::Type::CameraData: {
network::datamessagestructures::CameraKeyframe kf(buffer);
OsEng.interactionHandler().addKeyframe(kf);
@@ -522,7 +533,7 @@ void ParallelConnection::dataMessageReceived(const std::vector<char>& messageCon
case network::datamessagestructures::Type::ScriptData: {
network::datamessagestructures::ScriptMessage sm;
sm.deserialize(buffer);
OsEng.scriptEngine().queueScript(sm._script);
OsEng.scriptEngine().queueScript(sm._script, scripting::ScriptEngine::RemoteScripting::No);
break;
}
@@ -562,8 +573,13 @@ void ParallelConnection::sendFunc(){
std::unique_lock<std::mutex> unqlock(_sendBufferMutex);
_sendCondition.wait(unqlock);
if (_disconnect) {
break;
}
while (!_sendBuffer.empty()) {
const Message& message = _sendBuffer.front();
Message message = _sendBuffer.front();
unqlock.unlock();
std::vector<char> header;
//insert header into buffer
@@ -594,65 +610,79 @@ void ParallelConnection::sendFunc(){
signalDisconnect();
}
unqlock.lock();
_sendBuffer.erase(_sendBuffer.begin());
}
}
}
std::lock_guard<std::mutex> sendLock(_sendBufferMutex);
_sendBuffer.clear();
}
void ParallelConnection::hostInfoMessageReceived(const std::vector<char>& message){
if (message.size() < 1) {
LERROR("Malformed host info message.");
void ParallelConnection::connectionStatusMessageReceived(const std::vector<char>& message) {
if (message.size() < 2 * sizeof(uint32_t)) {
LERROR("Malformed connection status message.");
return;
}
char hostInfo = message[0];
size_t pointer = 0;
uint32_t statusIn = *(reinterpret_cast<const uint32_t*>(&message[pointer]));
network::Status status = static_cast<network::Status>(statusIn);
pointer += sizeof(uint32_t);
size_t hostNameSize = *(reinterpret_cast<const uint32_t*>(&message[pointer]));
pointer += sizeof(uint32_t);
if (hostNameSize > message.size() - pointer) {
LERROR("Malformed connection status message.");
return;
}
std::string hostName = "";
if (hostNameSize > 0) {
hostName = std::string(&message[pointer], hostNameSize);
}
pointer += hostNameSize;
if (hostInfo == 1) { // assigned as host
if (_isHost.load()) {
//we're already host, do nothing (dummy check)
return;
}
_isHost.store(true);
if (status > Status::Host) {
LERROR("Invalid status.");
return;
}
//start broadcasting
if (status == _status) {
//status remains unchanged.
return;
}
setStatus(status);
setHostName(hostName);
if (status == Status::Host) { // assigned as host
_broadcastThread = std::make_unique<std::thread>(&ParallelConnection::broadcast, this);
} else { // assigned as client
if (!_isHost.load()) {
//we're already a client, do nothing (dummy check)
return;
}
//stop broadcast loop
_isHost.store(false);
// delete broadcasting thread
// (the thread is allowed to terminate once the status is set to non-host.)
if (_broadcastThread != nullptr) {
_broadcastThread->join();
_broadcastThread = nullptr;
}
OsEng.interactionHandler().clearKeyframes();
//clear buffered any keyframes
//request init package from the host
//int size = headerSize();
//std::vector<char> buffer;
//buffer.reserve(size);
//write header
//writeHeader(buffer, MessageTypes::InitializationRequest);
//send message
//std::cout << "host info queue" << std::endl;
//queueMessage(MessageTypes::InitializationRequest, buffer);
}
}
void ParallelConnection::nConnectionsMessageReceived(const std::vector<char>& message) {
if (message.size() < sizeof(uint32_t)) {
LERROR("Malformed host info message.");
return;
}
uint32_t nConnections = *(reinterpret_cast<const uint32_t*>(&message[0]));
setNConnections(nConnections);
}
//void ParallelConnection::initializationRequestMessageReceived(const std::vector<char>& message){
/*
//get current state as scripts
@@ -742,8 +772,10 @@ void ParallelConnection::listenCommunication() {
//if enough data was received
if (nBytesRead <= 0) {
LERROR("Error " << _ERRNO << " detected in connection when reading header, disconnecting!");
signalDisconnect();
if (!_disconnect) {
LERROR("Error " << _ERRNO << " detected in connection when reading header, disconnecting!");
signalDisconnect();
}
break;
}
@@ -773,8 +805,10 @@ void ParallelConnection::listenCommunication() {
nBytesRead = receiveData(_clientSocket, messageBuffer, messageSize, 0);
if (nBytesRead <= 0) {
LERROR("Error " << _ERRNO << " detected in connection when reading message, disconnecting!");
signalDisconnect();
if (!_disconnect) {
LERROR("Error " << _ERRNO << " detected in connection when reading message, disconnecting!");
signalDisconnect();
}
break;
}
@@ -816,10 +850,7 @@ void ParallelConnection::setName(const std::string& name){
_name = name;
}
bool ParallelConnection::isHost(){
return _isHost.load();
}
void ParallelConnection::requestHostship(const std::string &password){
std::vector<char> buffer;
uint32_t passcode = hash(password);
@@ -863,7 +894,7 @@ bool ParallelConnection::initNetworkAPI(){
}
void ParallelConnection::sendScript(const std::string& script) {
if (!_isHost) return;
if (!isHost()) return;
network::datamessagestructures::ScriptMessage sm;
sm._script = script;
@@ -886,7 +917,7 @@ void ParallelConnection::preSynchronization(){
//std::cout << "start." << std::endl;
//if we're the host
if(_isHost){
//if(_isHost){
/*
//get current time parameters and create a keyframe
network::datamessagestructures::TimeKeyframe tf;
@@ -925,8 +956,8 @@ void ParallelConnection::preSynchronization(){
std::cout << "host 7." << std::endl;
*/
}
else{
//}
//else{
/*
//if we're not the host and we have a valid keyframe (one that hasnt been used before)
if(_latestTimeKeyframeValid.load()){
@@ -951,7 +982,7 @@ void ParallelConnection::preSynchronization(){
}
*/
}
//}
//std::cout << "stop." << std::endl;
}
@@ -1012,10 +1043,47 @@ void ParallelConnection::preSynchronization(){
//}
void ParallelConnection::setStatus(Status status) {
if (_status != status) {
_status = status;
_connectionEvent->publish("statusChanged");
}
}
Status ParallelConnection::status() {
return _status;
}
void ParallelConnection::setNConnections(size_t nConnections) {
if (_nConnections != nConnections) {
_nConnections = nConnections;
_connectionEvent->publish("nConnectionsChanged");
}
}
size_t ParallelConnection::nConnections() {
return _nConnections;
}
bool ParallelConnection::isHost() {
return _status == Status::Host;
}
void ParallelConnection::setHostName(const std::string& hostName) {
if (_hostName != hostName) {
_hostName = hostName;
_connectionEvent->publish("hostNameChanged");
}
}
const std::string& ParallelConnection::hostName() {
return _hostName;
}
void ParallelConnection::broadcast(){
//while we're still connected and we're the host
while (_isConnected && _isHost) {
while (_isConnected && isHost()) {
//create a keyframe with current position and orientation of camera
network::datamessagestructures::CameraKeyframe kf;
kf._position = OsEng.interactionHandler().camera()->positionVec3();
@@ -1054,6 +1122,11 @@ uint32_t ParallelConnection::hash(const std::string &val) {
return hashVal;
};
std::shared_ptr<ghoul::Event<>> ParallelConnection::connectionEvent() {
return _connectionEvent;
}
scripting::LuaLibrary ParallelConnection::luaLibrary() {
return {

View File

@@ -763,23 +763,20 @@ scripting::LuaLibrary RenderEngine::luaLibrary() {
"toggleFade",
&luascriptfunctions::toggleFade,
"number",
"Toggles fading in or out",
true
"Toggles fading in or out"
},
{
"fadeIn",
&luascriptfunctions::fadeIn,
"number",
"",
true
""
},
//also temporary @JK
{
"fadeOut",
&luascriptfunctions::fadeOut,
"number",
"",
true
""
},
{
"registerScreenSpaceRenderable",
@@ -1334,6 +1331,45 @@ void RenderEngine::renderInformation() {
break;
}
network::Status status = OsEng.parallelConnection().status();
size_t nConnections = OsEng.parallelConnection().nConnections();
const std::string& hostName = OsEng.parallelConnection().hostName();
std::string connectionInfo = "";
int nClients = nConnections;
if (status == network::Status::Host) {
nClients--;
if (nClients == 1) {
connectionInfo = "Hosting session with 1 client";
} else {
connectionInfo = "Hosting session with " + std::to_string(nClients) + " clients";
}
} else if (status == network::Status::ClientWithHost) {
nClients--;
connectionInfo = "Session hosted by '" + hostName + "'";
} else if (status == network::Status::ClientWithoutHost) {
connectionInfo = "Host is disconnected";
}
if (status == network::Status::ClientWithHost || status == network::Status::ClientWithoutHost) {
connectionInfo += "\n";
if (nClients > 2) {
connectionInfo += "You and " + std::to_string(nClients - 1) + " more clients are tuned in";
} else if (nClients == 2) {
connectionInfo += "You and " + std::to_string(nClients - 1) + " more client are tuned in";
} else if (nClients == 1) {
connectionInfo += "You are the only client";
}
}
if (connectionInfo != "") {
RenderFontCr(*_fontInfo,
penPosition,
connectionInfo.c_str()
);
}
#ifdef OPENSPACE_MODULE_NEWHORIZONS_ENABLED
bool hasNewHorizons = scene()->sceneGraphNode("NewHorizons");
double currentTime = Time::ref().currentTime();

View File

@@ -137,7 +137,7 @@ ScreenSpaceRenderable::ScreenSpaceRenderable(const ghoul::Dictionary& dictionary
_delete.onChange([this](){
std::string script =
"openspace.unregisterScreenSpaceRenderable('" + name() + "');";
OsEng.scriptEngine().queueScript(script);
OsEng.scriptEngine().queueScript(script, scripting::ScriptEngine::RemoteScripting::Yes);
});
}

View File

@@ -467,7 +467,6 @@ scripting::LuaLibrary Scene::luaLibrary() {
"Sets a property identified by the URI in "
"the first argument. The second argument can be any type, but it has to "
"match the type that the property expects.",
true
},
{
"getPropertyValue",

View File

@@ -156,16 +156,7 @@ bool ScriptEngine::runScript(const std::string& script) {
LERRORC(e.component, e.message);
return false;
}
// if we're currently hosting the parallel session, find out if script should be synchronized.
if (OsEng.parallelConnection().isHost()) {
std::string lib, func;
if (parseLibraryAndFunctionNames(lib, func, script) && shouldScriptBeSent(lib, func)){
OsEng.parallelConnection().sendScript(script);
// cacheScript(lib, func, script);
}
}
return true;
}
@@ -194,7 +185,7 @@ bool ScriptEngine::runScriptFile(const std::string& filename) {
return true;
}
bool ScriptEngine::shouldScriptBeSent(const std::string& library, const std::string& function) {
/*bool ScriptEngine::shouldScriptBeSent(const std::string& library, const std::string& function) {
std::set<LuaLibrary>::const_iterator libit;
for (libit = _registeredLibraries.cbegin();
libit != _registeredLibraries.cend();
@@ -219,9 +210,9 @@ bool ScriptEngine::shouldScriptBeSent(const std::string& library, const std::str
}
return false;
}
}*/
void ScriptEngine::cacheScript(const std::string &library, const std::string &function, const std::string &script){
/*void ScriptEngine::cacheScript(const std::string &library, const std::string &function, const std::string &script){
_cachedScriptsMutex.lock();
_cachedScripts[library][function] = script;
_cachedScriptsMutex.unlock();
@@ -246,8 +237,9 @@ std::vector<std::string> ScriptEngine::cachedScripts(){
_cachedScriptsMutex.unlock();
return retVal;
}
}*/
/*
bool ScriptEngine::parseLibraryAndFunctionNames(std::string &library, std::string &function, const std::string &script){
//"deconstruct the script to find library and function name
@@ -289,7 +281,7 @@ bool ScriptEngine::parseLibraryAndFunctionNames(std::string &library, std::strin
//if we found a function all is good
return !function.empty();
}
*/
bool ScriptEngine::isLibraryNameAllowed(lua_State* state, const std::string& name) {
bool result = false;
lua_getglobal(state, _openspaceLibraryName.c_str());
@@ -665,23 +657,30 @@ void ScriptEngine::preSynchronization() {
_mutex.lock();
if (!_queuedScripts.empty()){
_currentSyncedScript = _queuedScripts.back();
_queuedScripts.pop_back();
_currentSyncedScript = _queuedScripts.back().first;
bool remoteScripting = _queuedScripts.back().second;
//Not really a received script but the master also needs to run the script...
_receivedScripts.push_back(_currentSyncedScript);
_queuedScripts.pop_back();
if (OsEng.parallelConnection().isHost() && remoteScripting) {
OsEng.parallelConnection().sendScript(_currentSyncedScript);
}
}
_mutex.unlock();
}
void ScriptEngine::queueScript(const std::string &script){
void ScriptEngine::queueScript(const std::string &script, ScriptEngine::RemoteScripting remoteScripting){
if (script.empty())
return;
_mutex.lock();
_queuedScripts.insert(_queuedScripts.begin(), script);
_queuedScripts.insert(_queuedScripts.begin(), std::make_pair(script, remoteScripting));
_mutex.unlock();
}

View File

@@ -249,8 +249,7 @@ scripting::LuaLibrary Time::luaLibrary() {
&luascriptfunctions::time_setDeltaTime,
"number",
"Sets the amount of simulation time that happens "
"in one second of real time",
true
"in one second of real time"
},
{
"deltaTime",
@@ -263,16 +262,14 @@ scripting::LuaLibrary Time::luaLibrary() {
"setPause",
&luascriptfunctions::time_setPause,
"bool",
"Pauses the simulation time or restores the delta time",
true
"Pauses the simulation time or restores the delta time"
},
{
"togglePause",
&luascriptfunctions::time_togglePause,
"",
"Toggles the pause function, i.e. temporarily setting the delta time to 0"
" and restoring it afterwards",
true
" and restoring it afterwards"
},
{
"setTime",
@@ -281,8 +278,7 @@ scripting::LuaLibrary Time::luaLibrary() {
"Sets the current simulation time to the "
"specified value. If the parameter is a number, the value is the number "
"of seconds past the J2000 epoch. If it is a string, it has to be a "
"valid ISO 8601 date string (YYYY-MM-DDTHH:MN:SS)",
true
"valid ISO 8601 date string (YYYY-MM-DDTHH:MN:SS)"
},
{
"currentTime",