diff --git a/source/core/StarLua.cpp b/source/core/StarLua.cpp index eb8541c..93ed516 100644 --- a/source/core/StarLua.cpp +++ b/source/core/StarLua.cpp @@ -125,7 +125,7 @@ LuaValue LuaConverter::from(LuaEngine& engine, Json const& v) { } else if (v.isType(Json::Type::Int)) { return LuaInt(v.toInt()); } else if (v.isType(Json::Type::String)) { - return engine.createString(v.stringPtr()->utf8Ptr()); + return engine.createString(*v.stringPtr()); } else { return LuaDetail::jsonContainerToTable(engine, v); } @@ -451,7 +451,10 @@ ByteArray LuaEngine::compile(ByteArray const& contents, String const& name) { } LuaString LuaEngine::createString(String const& str) { - return createString(str.utf8Ptr()); + lua_checkstack(m_state, 1); + + lua_pushlstring(m_state, str.utf8Ptr(), str.utf8Size()); + return LuaString(LuaDetail::LuaHandle(RefPtr(this), popHandle(m_state))); } LuaString LuaEngine::createString(char const* str) { diff --git a/source/game/StarInput.cpp b/source/game/StarInput.cpp index 59b9593..a8ac76f 100644 --- a/source/game/StarInput.cpp +++ b/source/game/StarInput.cpp @@ -1,9 +1,22 @@ #include "StarInput.hpp" #include "StarAssets.hpp" #include "StarRoot.hpp" +#include "StarJsonExtra.hpp" namespace Star { +const KeyMod KeyModOptional = KeyMod::Num | KeyMod::Caps | KeyMod::Scroll; + +inline bool compareKeyModLenient(KeyMod input, KeyMod test) { + input |= KeyModOptional; + test |= KeyModOptional; + return (test & input) == test; +} + +inline bool compareKeyMod(KeyMod input, KeyMod test) { + return (input | (KeyModOptional & ~test)) == (test | KeyModOptional); +} + Json keyModsToJson(KeyMod mod) { JsonArray array; @@ -49,11 +62,62 @@ size_t hash::operator()(InputVariant const& v) const { return indexHash; } +Json Input::inputEventToJson(InputEvent const& input) { + String type; + Json data; + + if (auto keyDown = input.ptr()) { + type = "KeyDown"; + data = JsonObject{ + {"key", KeyNames.getRight(keyDown->key)}, + {"mods", keyModsToJson(keyDown->mods)} + }; + } else if (auto keyUp = input.ptr()) { + type = "KeyUp"; + data = JsonObject{ + {"key", KeyNames.getRight(keyUp->key)} + }; + } else if (auto mouseDown = input.ptr()) { + type = "MouseButtonDown"; + data = JsonObject{ + {"mouseButton", MouseButtonNames.getRight(mouseDown->mouseButton)}, + {"mousePosition", jsonFromVec2I(mouseDown->mousePosition)} + }; + } else if (auto mouseUp = input.ptr()) { + type = "MouseButtonUp"; + data = JsonObject{ + {"mouseButton", MouseButtonNames.getRight(mouseUp->mouseButton)}, + {"mousePosition", jsonFromVec2I(mouseUp->mousePosition)} + }; + } else if (auto mouseWheel = input.ptr()) { + type = "MouseWheel"; + data = JsonObject{ + {"mouseWheel", MouseWheelNames.getRight(mouseWheel->mouseWheel)}, + {"mousePosition", jsonFromVec2I(mouseWheel->mousePosition)} + }; + } else if (auto mouseMove = input.ptr()) { + type = "MouseMove"; + data = JsonObject{ + {"mouseMove", jsonFromVec2I(mouseMove->mouseMove)}, + {"mousePosition", jsonFromVec2I(mouseMove->mousePosition)} + }; + } + + if (data) { + return JsonObject{ + {"type", type}, + {"data", data} + }; + } + + return data; +} + Input::Bind Input::bindFromJson(Json const& json) { Bind bind; String type = json.getString("type"); - Json value = json.get("value"); + Json value = json.get("value", {}); if (type == "key") { KeyBind keyBind; @@ -117,8 +181,8 @@ Input::BindEntry::BindEntry(String entryId, Json const& config, BindCategory con Input::BindCategory::BindCategory(String categoryId, Json const& categoryConfig) { id = move(categoryId); - name = config.getString("name", id); config = categoryConfig; + name = config.getString("name", id); ConfigurationPtr userConfig = Root::singletonPtr()->configuration(); auto userBindings = userConfig->get("modBindings"); @@ -142,6 +206,20 @@ Input::BindCategory::BindCategory(String categoryId, Json const& categoryConfig) } } +List Input::filterBindEntries(List const& binds, KeyMod mods) const { + uint8_t maxPriority = 0; + List result{}; + for (const BindRef& bind : binds) { + if (bind.priority < maxPriority) + break; + else if (compareKeyModLenient(mods, bind.mods)) { + maxPriority = bind.priority; + result.emplace_back(bind.entry); + } + } + return result; +} + Input* Input::s_singleton; Input* Input::singletonPtr() { @@ -174,15 +252,34 @@ Input::~Input() { s_singleton = nullptr; } +List> const& Input::inputEventsThisFrame() const { + return m_inputEvents; +} + void Input::reset() { + m_inputEvents.resize(0); // keeps reserved memory m_inputStates.clear(); m_bindStates.clear(); } +void Input::update() { + reset(); +} + +bool Input::handleInput(InputEvent const& input, bool gameProcessed) { + m_inputEvents.emplace_back(input, gameProcessed); + + + return false; +} + +void Input::rebuildMappings() { + m_bindMappings.clear(); +} + void Input::reload() { reset(); m_bindCategories.clear(); - m_inputsToBinds.clear(); auto assets = Root::singleton().assets(); @@ -202,6 +299,8 @@ void Input::reload() { count += pair.second.entries.size(); Logger::info("Binds: Loaded {} bind{}", count, count == 1 ? "" : "s"); + + rebuildMappings(); } } \ No newline at end of file diff --git a/source/game/StarInput.hpp b/source/game/StarInput.hpp index efe68fb..6dab146 100644 --- a/source/game/StarInput.hpp +++ b/source/game/StarInput.hpp @@ -20,6 +20,9 @@ namespace Star { class Input { public: + + static Json inputEventToJson(InputEvent const& event); + struct KeyBind { Key key = Key::Zero; KeyMod mods = KeyMod::NoMod; @@ -124,29 +127,39 @@ namespace Star { Input(Input const&) = delete; Input& operator=(Input const&) = delete; - // Clears input state. Should be done at the end of the client loop. + List> const& inputEventsThisFrame() const; + + // Clears input state. Should be done at the very start or end of the client loop. void reset(); + void update(); + // Handles an input event. - bool handleInput(InputEvent const& event); + bool handleInput(InputEvent const& input, bool gameProcessed); + + void rebuildMappings(); // Loads input categories and their binds from Assets. void reload(); private: + List filterBindEntries(List const& binds, KeyMod mods) const; + static Input* s_singleton; // Regenerated on reload. StringMap m_bindCategories; // Contains raw pointers to bind entries in categories, so also regenerated on reload. - HashMap> m_inputsToBinds; + HashMap> m_bindMappings; ListenerPtr m_rootReloadListener; - // Per-frame input state maps. + // Per-frame input event storage for Lua. + List> m_inputEvents; - //Raw input state + // Per-frame input state maps. + //Input states HashMap m_inputStates; - //Bind input state + //Bind states HashMap m_bindStates; }; } diff --git a/source/game/scripting/StarPlayerLuaBindings.cpp b/source/game/scripting/StarPlayerLuaBindings.cpp index 41198da..fe1c06d 100644 --- a/source/game/scripting/StarPlayerLuaBindings.cpp +++ b/source/game/scripting/StarPlayerLuaBindings.cpp @@ -85,6 +85,9 @@ LuaCallbacks LuaBindings::makePlayerCallbacks(Player* player) { } }); + callbacks.registerCallback("name", [player]() { return player->name(); }); + callbacks.registerCallback("setName", [player](String const& name) { player->setName(name); }); + callbacks.registerCallback("species", [player]() { return player->species(); }); callbacks.registerCallback("setSpecies", [player](String const& species) { player->setSpecies(species); }); @@ -101,8 +104,6 @@ LuaCallbacks LuaBindings::makePlayerCallbacks(Player* player) { player->setPersonality(parsePersonality(newPersonality, personalityConfig)); }); - void setPersonality(Personality const& personality); - callbacks.registerCallback("id", [player]() { return player->entityId(); }); callbacks.registerCallback("uniqueId", [player]() { return player->uniqueId(); }); callbacks.registerCallback("isAdmin", [player]() { return player->isAdmin(); }); diff --git a/source/game/scripting/StarRootLuaBindings.cpp b/source/game/scripting/StarRootLuaBindings.cpp index d80d21d..de70950 100644 --- a/source/game/scripting/StarRootLuaBindings.cpp +++ b/source/game/scripting/StarRootLuaBindings.cpp @@ -30,6 +30,8 @@ LuaCallbacks LuaBindings::makeRootCallbacks() { auto root = Root::singletonPtr(); + callbacks.registerCallbackWithSignature("assetsByExtension", bind(RootCallbacks::assetsByExtension, root, _1)); + callbacks.registerCallbackWithSignature("assetData", bind(RootCallbacks::assetData, root, _1)); callbacks.registerCallbackWithSignature("assetJson", bind(RootCallbacks::assetJson, root, _1)); callbacks.registerCallbackWithSignature("makeCurrentVersionedJson", bind(RootCallbacks::makeCurrentVersionedJson, root, _1, _2)); callbacks.registerCallbackWithSignature("loadVersionedJson", bind(RootCallbacks::loadVersionedJson, root, _1, _2)); @@ -170,6 +172,15 @@ LuaCallbacks LuaBindings::makeRootCallbacks() { return callbacks; } +StringList LuaBindings::RootCallbacks::assetsByExtension(Root* root, String const& extension) { + return root->assets()->scanExtension(extension); +} + +String LuaBindings::RootCallbacks::assetData(Root* root, String const& path) { + auto bytes = root->assets()->bytes(path); + return String(bytes->ptr(), bytes->size()); +} + Json LuaBindings::RootCallbacks::assetJson(Root* root, String const& path) { return root->assets()->json(path); } diff --git a/source/game/scripting/StarRootLuaBindings.hpp b/source/game/scripting/StarRootLuaBindings.hpp index 8d1bda4..570d2d7 100644 --- a/source/game/scripting/StarRootLuaBindings.hpp +++ b/source/game/scripting/StarRootLuaBindings.hpp @@ -13,6 +13,8 @@ namespace LuaBindings { LuaCallbacks makeRootCallbacks(); namespace RootCallbacks { + StringList assetsByExtension(Root* root, String const& extension); + String assetData(Root* root, String const& path); Json assetJson(Root* root, String const& path); Json makeCurrentVersionedJson(Root* root, String const& identifier, Json const& content); Json loadVersionedJson(Root* root, Json const& versionedJson, String const& expectedIdentifier);