From 0b3e29dea9863c4b5ca0c77958bbcb32a05867ca Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sat, 14 Feb 2015 23:12:07 +0100 Subject: Some work towards scriptable events --- resources/script/interact.lua | 3 ++ resources/script/test.lua | 20 ++++++---- src/CMakeLists.txt | 1 + src/control/MapContext.cpp | 14 +++++-- src/control/MapContext.hpp | 4 +- src/control/RPGEdit.cpp | 3 +- src/control/RPGEdit.hpp | 2 + src/control/ScriptContext.cpp | 90 +++++++++++++++++++++++++++++++++++++++++++ src/control/ScriptContext.hpp | 63 ++++++++++-------------------- src/model/Entity.hpp | 15 ++++++-- src/model/ScriptValue.hpp | 6 +-- 11 files changed, 160 insertions(+), 61 deletions(-) create mode 100644 resources/script/interact.lua create mode 100644 src/control/ScriptContext.cpp diff --git a/resources/script/interact.lua b/resources/script/interact.lua new file mode 100644 index 0000000..98bb34f --- /dev/null +++ b/resources/script/interact.lua @@ -0,0 +1,3 @@ +function interact(entity, time) + print('Interact! ' .. time) +end diff --git a/resources/script/test.lua b/resources/script/test.lua index f78cf13..1dc1fc4 100644 --- a/resources/script/test.lua +++ b/resources/script/test.lua @@ -1,14 +1,20 @@ -function print_table(foo, bar) +local function print_table(foo, bar) for k, v in pairs(foo) do print(bar .. k, v) - if type(v) == 'table' and bar .. k ~= '_G' then - print_table(v, bar .. k .. '.') - end + --if type(v) == 'table' and bar .. k ~= '_G' then + -- print_table(v, bar .. k .. '.') + --end end end -print_table(_G, '') +--print(getmetatable(_G)) +--setmetatable(_G, {}) +--print_table(_G, '') -print(getmetatable('').__index) -print(string) +print(bar) +print(getmetatable(bar)) + +--print(getmetatable('').bar) +--getmetatable('').bar = 'bar' +--print(getmetatable('').bar) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3e7dd61..46eb1a2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(rpgedit rpgedit.cpp control/MapContext.cpp control/RPGEdit.cpp + control/ScriptContext.cpp model/Map.cpp model/Scriptable.cpp view/MapView.cpp diff --git a/src/control/MapContext.cpp b/src/control/MapContext.cpp index 6ba3b6b..f7ad2fe 100644 --- a/src/control/MapContext.cpp +++ b/src/control/MapContext.cpp @@ -31,10 +31,13 @@ namespace RPGEdit { namespace Control { -MapContext::MapContext(EventBus *eventBus0, InputHandler *inputHandler0, const std::shared_ptr &window, const Model::Map &map0) - : eventBus(eventBus0), inputHandler(inputHandler0), map(map0) { +MapContext::MapContext(EventBus *eventBus0, InputHandler *inputHandler0, ScriptContext *scriptContext0, const std::shared_ptr &window, const Model::Map &map0) + : eventBus(eventBus0), inputHandler(inputHandler0), scriptContext(scriptContext0), map(map0) { view = std::unique_ptr(new View::MapView(window, map.getTileset())); + Model::Entity *square = map.addEntity("square", Model::Position{10, 10}); + square->setScriptInteract("interact", "interact"); + playerEntity = map.addEntity("square", Model::Position{8, 8}); view->updateEntities(map.getEntities()); @@ -80,7 +83,12 @@ void MapContext::interact(uint64_t time) { if (!target) return; - target->interact(time); + const std::pair &interactScript = target->getScriptInteract(); + if (interactScript.first.empty()) + return; + + Model::ScriptNumber scriptTime(time); + scriptContext->run(interactScript.first, interactScript.second, nullptr, &scriptTime); } void MapContext::keyPressed(uint16_t key, uint64_t time) { diff --git a/src/control/MapContext.hpp b/src/control/MapContext.hpp index 18d4cfe..5e17a42 100644 --- a/src/control/MapContext.hpp +++ b/src/control/MapContext.hpp @@ -28,6 +28,7 @@ #include "EventBus.hpp" #include "InputHandler.hpp" +#include "ScriptContext.hpp" #include "../model/Map.hpp" #include "../view/MapView.hpp" @@ -43,6 +44,7 @@ class MapContext { private: EventBus *const eventBus; InputHandler *const inputHandler; + ScriptContext *const scriptContext; std::unique_ptr view; @@ -59,7 +61,7 @@ private: } public: - MapContext(EventBus *eventBus0, InputHandler *inputHandler0, const std::shared_ptr &window, const Model::Map &map0); + MapContext(EventBus *eventBus0, InputHandler *inputHandler0, ScriptContext *scriptContext0, const std::shared_ptr &window, const Model::Map &map0); void render(uint64_t time) { view->render(&map, getViewPosition(time), time); diff --git a/src/control/RPGEdit.cpp b/src/control/RPGEdit.cpp index a1a699f..6068236 100644 --- a/src/control/RPGEdit.cpp +++ b/src/control/RPGEdit.cpp @@ -26,7 +26,6 @@ #include "RPGEdit.hpp" #include "MapContext.hpp" -#include "ScriptContext.hpp" #include "../view/MapView.hpp" @@ -106,7 +105,7 @@ void RPGEdit::run() { window = std::make_shared(); - ctx = std::make_shared(&eventBus, &inputHandler, window, *map); + ctx = std::make_shared(&eventBus, &inputHandler, &scriptContext, window, *map); eventThread = std::thread([this] { eventLoop(); }); diff --git a/src/control/RPGEdit.hpp b/src/control/RPGEdit.hpp index 6011ecd..6c6c743 100644 --- a/src/control/RPGEdit.hpp +++ b/src/control/RPGEdit.hpp @@ -46,6 +46,8 @@ private: EventBus eventBus; InputHandler inputHandler; + ScriptContext scriptContext; + std::shared_ptr window; std::shared_ptr ctx; diff --git a/src/control/ScriptContext.cpp b/src/control/ScriptContext.cpp new file mode 100644 index 0000000..cc10f74 --- /dev/null +++ b/src/control/ScriptContext.cpp @@ -0,0 +1,90 @@ +/* + Copyright (c) 2014, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include "ScriptContext.hpp" + + +namespace RPGEdit { + +namespace Control { + +void ScriptContext::setupEnv() { + const std::pair libs[] = { + {"_G", luaopen_base}, + {"bit32", luaopen_bit32}, + {"math", luaopen_math}, + {"string", luaopen_string}, + {"table", luaopen_table}, + }; + + for (auto &lib : libs) { + luaL_requiref(L, lib.first, lib.second, 1); + lua_pop(L, 1); + } + + for (const char *f : {"dofile", "loadfile", "require"}) { + lua_pushnil(L); + lua_setglobal(L, f); + } +} + +void ScriptContext::cleanupEnv() { + lua_pushglobaltable(L); + + lua_pushnil(L); + lua_setmetatable(L, -2); + + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + lua_pop(L, 1); + + lua_pushvalue(L, -1); + lua_pushnil(L); + + lua_rawset(L, -4); + } + + lua_pop(L, 1); +} + +void ScriptContext::load(const std::string &script) { + if (loadedScripts.count(script)) + return; + + std::string filename = "../resources/script/" + script + ".lua"; + + lua_rawgetp(L, LUA_REGISTRYINDEX, this); + lua_pushstring(L, script.c_str()); + luaL_loadfile(L, filename.c_str()); + lua_rawset(L, -3); + lua_pop(L, 1); + + loadedScripts.insert(script); +} + +} + +} diff --git a/src/control/ScriptContext.hpp b/src/control/ScriptContext.hpp index 86c8c0f..f9f8445 100644 --- a/src/control/ScriptContext.hpp +++ b/src/control/ScriptContext.hpp @@ -36,6 +36,7 @@ extern "C" { #include #include +#include namespace RPGEdit { @@ -46,43 +47,25 @@ class ScriptContext { private: lua_State *L; - void setupEnv() { - const std::pair libs[] = { - {"_G", luaopen_base}, - {"bit32", luaopen_bit32}, - {"math", luaopen_math}, - {"string", luaopen_string}, - {"table", luaopen_table}, - }; - - for (auto &lib : libs) { - luaL_requiref(L, lib.first, lib.second, 1); - lua_pop(L, 1); - } - - for (const char *f : {"dofile", "loadfile", "require"}) { - lua_pushnil(L); - lua_setglobal(L, f); - } - } + std::unordered_set loadedScripts; - void cleanupEnv() { - lua_pushglobaltable(L); + void setupEnv(); + void cleanupEnv(); - lua_pushnil(L); - lua_setmetatable(L, -2); + void load(const std::string &script); - lua_pushnil(L); - while (lua_next(L, -2) != 0) { - lua_pop(L, 1); + size_t pushArgs() { + return 0; + } - lua_pushvalue(L, -1); + template + size_t pushArgs(Model::ScriptValue *v, Args ...args) { + if (v) + v->push(L); + else lua_pushnil(L); - lua_rawset(L, -4); - } - - lua_pop(L, 1); + return pushArgs(args...) + 1; } public: @@ -107,25 +90,21 @@ public: lua_setglobal(L, key.c_str()); } - void load(const std::string &name) { - std::string filename = "../resources/script/" + name + ".lua"; + template + void run(const std::string &script, const std::string &name, Args ...args) { + load(script); - lua_rawgetp(L, LUA_REGISTRYINDEX, this); - lua_pushstring(L, name.c_str()); - luaL_loadfile(L, filename.c_str()); - lua_rawset(L, -3); - lua_pop(L, 1); - } - - void run(const std::string &name) { setupEnv(); lua_rawgetp(L, LUA_REGISTRYINDEX, this); - lua_getfield(L, -1, name.c_str()); + lua_getfield(L, -1, script.c_str()); lua_remove(L, -2); lua_call(L, 0, 0); + lua_getglobal(L, name.c_str()); + lua_call(L, pushArgs(args...), 0); + cleanupEnv(); } }; diff --git a/src/model/Entity.hpp b/src/model/Entity.hpp index fc1debb..b14e122 100644 --- a/src/model/Entity.hpp +++ b/src/model/Entity.hpp @@ -28,19 +28,23 @@ #include "Direction.hpp" +#include "Scriptable.hpp" #include +#include namespace RPGEdit { namespace Model { -class Entity { +class Entity : public Scriptable { private: std::string name; + std::pair scriptInteract; + Direction direction; public: @@ -60,8 +64,13 @@ public: direction = dir; } - void interact(uint64_t time) { - std::fprintf(stderr, "Tried to interact with `%s' entity at %llu\n", name.c_str(), (unsigned long long)time); + const std::pair & getScriptInteract() const { + return scriptInteract; + } + + void setScriptInteract(const std::string &script, const std::string &name) { + scriptInteract.first = script; + scriptInteract.second = name; } }; diff --git a/src/model/ScriptValue.hpp b/src/model/ScriptValue.hpp index a82ba8e..04c4e55 100644 --- a/src/model/ScriptValue.hpp +++ b/src/model/ScriptValue.hpp @@ -116,13 +116,13 @@ public: class ScriptTable : public ScriptValue { public: - typedef std::unordered_map> MapType; + typedef std::unordered_map, std::shared_ptr> MapType; private: MapType value; public: - std::shared_ptr & operator[](const std::string &key) { + std::shared_ptr & operator[](const std::shared_ptr &key) { return value[key]; } @@ -130,7 +130,7 @@ public: lua_createtable(L, 0, value.size()); for (const auto &entry : value) { - lua_pushstring(L, entry.first.c_str()); + entry.first->push(L); entry.second->push(L); lua_settable(L, -3); -- cgit v1.2.3