lua: added object support reding property and console

Dieser Commit ist enthalten in:
reinder 2020-02-22 18:16:53 +01:00
Ursprung 853ab3f1e0
Commit 9722c03f8d
9 geänderte Dateien mit 345 neuen und 13 gelöschten Zeilen

Datei anzeigen

@ -50,6 +50,8 @@ class IdObject : public Object
Property<std::string> id;
~IdObject() override;
const std::weak_ptr<World>& world() const { return m_world; }
};
#endif

75
server/src/lua/console.cpp Normale Datei
Datei anzeigen

@ -0,0 +1,75 @@
/**
* server/src/lua/console.cpp - Lua console wrapper
*
* This file is part of the traintastic source code.
*
* Copyright (C) 2019-2020 Reinder Feenstra
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "console.hpp"
#include "readonlytable.hpp"
#include "sandbox.hpp"
#include "script.hpp"
#include "../core/traintastic.hpp"
namespace Lua {
void Console::push(lua_State* L)
{
lua_createtable(L, 0, 7);
lua_pushcfunction(L, debug);
lua_setfield(L, -2, "debug");
lua_pushcfunction(L, info);
lua_setfield(L, -2, "info");
lua_pushcfunction(L, notice);
lua_setfield(L, -2, "notice");
lua_pushcfunction(L, warning);
lua_setfield(L, -2, "warning");
lua_pushcfunction(L, error);
lua_setfield(L, -2, "error");
lua_pushcfunction(L, critical);
lua_setfield(L, -2, "critical");
lua_pushcfunction(L, fatal);
lua_setfield(L, -2, "fatal");
ReadOnlyTable::setMetatable(L, -1);
}
void Console::log(lua_State* L, ::Console::Level level, const std::string& message)
{
Traintastic::instance->console->log(level, Sandbox::getStateData(L).script().id, message);
}
int Console::log(lua_State* L, ::Console::Level level)
{
const int top = lua_gettop(L);
std::string message;
for(int i = 1; i <= top; i++)
{
if(i != 1)
message += " ";
message += luaL_checkstring(L, i);
}
log(L, level, message);
return 0;
}
}

60
server/src/lua/console.hpp Normale Datei
Datei anzeigen

@ -0,0 +1,60 @@
/**
* server/src/lua/console.hpp - Lua console wrapper
*
* This file is part of the traintastic source code.
*
* Copyright (C) 2019-2020 Reinder Feenstra
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef SERVER_LUA_CONSOLE_HPP
#define SERVER_LUA_CONSOLE_HPP
#include <lua.hpp>
#include "../core/console.hpp"
namespace Lua {
class Console
{
private:
static int log(lua_State* L, ::Console::Level level);
static int debug(lua_State* L) { return log(L, ::Console::Level::Debug); }
static int info(lua_State* L) { return log(L, ::Console::Level::Info); }
static int notice(lua_State* L) { return log(L, ::Console::Level::Notice); }
static int warning(lua_State* L) { return log(L, ::Console::Level::Warning); }
static int error(lua_State* L) { return log(L, ::Console::Level::Error); }
static int critical(lua_State* L) { return log(L, ::Console::Level::Critical); }
static int fatal(lua_State* L) { return log(L, ::Console::Level::Fatal); }
public:
static void push(lua_State* L);
static void log(lua_State* L, ::Console::Level level, const std::string& message);
inline static void debug(lua_State* L, const std::string& message) { return log(L, ::Console::Level::Debug, message); }
inline static void info(lua_State* L, const std::string& message) { return log(L, ::Console::Level::Info, message); }
inline static void notice(lua_State* L, const std::string& message) { return log(L, ::Console::Level::Info, message); }
inline static void warning(lua_State* L, const std::string& message) { return log(L, ::Console::Level::Warning, message); }
inline static void error(lua_State* L, const std::string& message) { return log(L, ::Console::Level::Error, message); }
inline static void critical(lua_State* L, const std::string& message) { return log(L, ::Console::Level::Critical, message); }
inline static void fatal(lua_State* L, const std::string& message) { return log(L, ::Console::Level::Fatal, message); }
};
}
#endif

134
server/src/lua/object.cpp Normale Datei
Datei anzeigen

@ -0,0 +1,134 @@
/**
* server/src/lua/object.cpp - Lua object wrapper
*
* This file is part of the traintastic source code.
*
* Copyright (C) 2019-2020 Reinder Feenstra
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "object.hpp"
#include "push.hpp"
#include "../core/object.hpp"
#include "../core/abstractproperty.hpp"
namespace Lua {
ObjectPtr Object::check(lua_State* L, int index)
{
ObjectPtrWeak& data = **static_cast<ObjectPtrWeak**>(luaL_checkudata(L, index, metaTableName));
if(ObjectPtr object = data.lock())
return object;
else
{
luaL_error(L, "dead object");
abort(); // never happens, luaL_error doesn't return
}
}
ObjectPtr Object::test(lua_State* L, int index)
{
ObjectPtrWeak* data = *static_cast<ObjectPtrWeak**>(luaL_testudata(L, index, metaTableName));
if(!data)
return ObjectPtr();
else if(ObjectPtr object = data->lock())
return object;
else
{
luaL_error(L, "dead object");
abort(); // never happens, luaL_error doesn't return
}
}
void Object::push(lua_State* L, const ObjectPtr& value)
{
if(value)
{
*static_cast<ObjectPtrWeak**>(lua_newuserdata(L, sizeof(ObjectPtrWeak*))) = new ObjectPtrWeak(value);
luaL_getmetatable(L, metaTableName);
lua_setmetatable(L, -2);
}
else
lua_pushnil(L);
}
void Object::registerType(lua_State* L)
{
luaL_newmetatable(L, metaTableName);
lua_pushcfunction(L, __gc);
lua_setfield(L, -2, "__gc");
lua_pushcfunction(L, __index);
lua_setfield(L, -2, "__index");
lua_pop(L, 1);
}
int Object::__gc(lua_State* L)
{
delete *static_cast<ObjectPtrWeak**>(lua_touserdata(L, 1));
return 0;
}
int Object::__index(lua_State* L)
{
ObjectPtr object{check(L, 1)};
const std::string name{lua_tostring(L, 2)};
if(InterfaceItem* item = object->getItem(name))
{
// TODO: test scriptable
if(AbstractProperty* property = dynamic_cast<AbstractProperty*>(item))
{
switch(property->type())
{
case ValueType::Boolean:
Lua::push(L, property->toBool());
break;
//case ValueType::Enum:
case ValueType::Integer:
Lua::push(L, property->toInt64());
break;
case ValueType::Float:
Lua::push(L, property->toDouble());
break;
case ValueType::String:
Lua::push(L, property->toString());
break;
case ValueType::Object:
push(L, property->toObject());
break;
default:
assert(false);
lua_pushnil(L);
break;
}
}
else
lua_pushnil(L);
}
else
lua_pushnil(L);
return 1;
}
}

Datei anzeigen

@ -1,9 +1,9 @@
/**
* server/src/lua/traintastic.hpp
* server/src/lua/object.hpp - Lua object wrapper
*
* This file is part of the traintastic source code.
*
* Copyright (C) 2019 Reinder Feenstra
* Copyright (C) 2019-2020 Reinder Feenstra
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -20,19 +20,32 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef SERVER_LUA_TRAINTASTIC_HPP
#define SERVER_LUA_TRAINTASTIC_HPP
#ifndef SERVER_LUA_OBJECT_HPP
#define SERVER_LUA_OBJECT_HPP
#include <lua.hpp>
#include <memory>
#include "../core/objectptr.hpp"
namespace Lua {
struct Traintastic
class Object
{
static int get_object(lua_State* L);
private:
static int __gc(lua_State* L);
static int __index(lua_State* L);
public:
static constexpr char const* metaTableName = "object";
static ObjectPtr check(lua_State* L, int index);
static ObjectPtr test(lua_State* L, int index);
static void push(lua_State* L, const ObjectPtr& value);
static void registerType(lua_State* L);
};
}
#endif

Datei anzeigen

@ -26,6 +26,7 @@
#include <type_traits>
#include <string>
#include "enum.hpp"
#include "object.hpp"
namespace Lua {
@ -50,6 +51,8 @@ void push(lua_State* L, const T& value)
lua_pushnumber(L, value);
else if constexpr(std::is_same_v<T, std::string>)
lua_pushlstring(L, value.data(), value.size());
else if constexpr(std::is_same_v<T, ObjectPtr>)
Object::push(L, value);
else
static_assert(sizeof(T) != sizeof(T), "don't know how to push type");
}

Datei anzeigen

@ -21,11 +21,14 @@
*/
#include "sandbox.hpp"
#include "push.hpp"
#include "object.hpp"
#include "console.hpp"
#include <utils/str.hpp>
#include "../core/world.hpp"
#include "../enum/traintasticmode.hpp"
#include "../enum/decoderprotocol.hpp"
#include "../enum/direction.hpp"
// TODO: #include "object.hpp"
#define LUA_SANDBOX "_sandbox"
@ -38,10 +41,11 @@ namespace Lua {
void Sandbox::close(lua_State* L)
{
delete *static_cast<StateData**>(lua_getextraspace(L)); // free state data
lua_close(L);
}
SandboxPtr Sandbox::create()
SandboxPtr Sandbox::create(Script& script)
{
lua_State* L = luaL_newstate();
@ -50,11 +54,14 @@ SandboxPtr Sandbox::create()
lua_pushliteral(L, "");
lua_call(L, 1, 0);
// create state data:
*static_cast<StateData**>(lua_getextraspace(L)) = new StateData(script);
// register types:
Enum<TraintasticMode>::registerType(L);
Enum<DecoderProtocol>::registerType(L);
Enum<Direction>::registerType(L);
// TODO: Object::registerType(L);
Object::registerType(L);
// setup sandbox:
lua_newtable(L);
@ -65,6 +72,18 @@ SandboxPtr Sandbox::create()
ADD_GLOBAL_TO_SANDBOX("pairs")
ADD_GLOBAL_TO_SANDBOX("ipairs")
// set VERSION:
lua_pushliteral(L, STR(VERSION));
lua_setfield(L, -2, "VERSION");
// add world:
push(L, std::static_pointer_cast<::Object>(script.world().lock()));
lua_setfield(L, -2, "world");
// add console:
Console::push(L);
lua_setfield(L, -2, "console");
// add enum values:
lua_newtable(L);
Enum<TraintasticMode>::registerValues(L);
@ -83,6 +102,11 @@ SandboxPtr Sandbox::create()
return SandboxPtr(L, close);
}
Sandbox::StateData& Sandbox::getStateData(lua_State* L)
{
return **static_cast<StateData**>(lua_getextraspace(L));
}
int Sandbox::getGlobal(lua_State* L, const char* name)
{
lua_getglobal(L, LUA_SANDBOX); // get the sandbox

Datei anzeigen

@ -23,11 +23,13 @@
#ifndef SERVER_LUA_SANDBOX_HPP
#define SERVER_LUA_SANDBOX_HPP
#include <lua.hpp>
#include <memory>
#include <lua.hpp>
namespace Lua {
class Script;
using SandboxPtr = std::unique_ptr<lua_State, void(*)(lua_State*)>;
class Sandbox
@ -36,7 +38,25 @@ class Sandbox
static void close(lua_State* L);
public:
static SandboxPtr create();
class StateData
{
private:
Script& m_script;
public:
StateData(Script& script) :
m_script{script}
{
}
inline Script& script() const
{
return m_script;
}
};
static SandboxPtr create(Script& script);
static StateData& getStateData(lua_State* L);
static int getGlobal(lua_State* L, const char* name);
static int pcall(lua_State* L, int nargs = 0, int nresults = 0, int errfunc = 0);
};

Datei anzeigen

@ -82,7 +82,8 @@ void Script::modeChanged(TraintasticMode mode)
void Script::init()
{
assert(!m_sandbox);
if((m_sandbox = Sandbox::create()))
auto world = m_world.lock();
if(world && (m_sandbox = Sandbox::create(*this)))
{
lua_State* L = m_sandbox.get();
const int error = luaL_loadbuffer(L, code.value().c_str(), code.value().size(), "=") || Sandbox::pcall(L, 0, LUA_MULTRET);