mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-03 22:39:41 +00:00
Merge branch 'lua_console' into 'master'
Lua console See merge request OpenMW/openmw!1780
This commit is contained in:
commit
1206d30add
18 changed files with 522 additions and 28 deletions
|
@ -92,6 +92,8 @@ namespace MWBase
|
||||||
|
|
||||||
// Drops script cache and reloads all scripts. Calls `onSave` and `onLoad` for every script.
|
// Drops script cache and reloads all scripts. Calls `onSave` and `onLoad` for every script.
|
||||||
virtual void reloadAllScripts() = 0;
|
virtual void reloadAllScripts() = 0;
|
||||||
|
|
||||||
|
virtual void handleConsoleCommand(const std::string& consoleMode, const std::string& command, const MWWorld::Ptr& selectedPtr) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,6 +154,13 @@ namespace MWBase
|
||||||
virtual void updateSpellWindow() = 0;
|
virtual void updateSpellWindow() = 0;
|
||||||
|
|
||||||
virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0;
|
virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0;
|
||||||
|
virtual void setConsoleMode(const std::string& mode) = 0;
|
||||||
|
|
||||||
|
static constexpr std::string_view sConsoleColor_Default = "#FFFFFF";
|
||||||
|
static constexpr std::string_view sConsoleColor_Error = "#FF2222";
|
||||||
|
static constexpr std::string_view sConsoleColor_Success = "#FF00FF";
|
||||||
|
static constexpr std::string_view sConsoleColor_Info = "#AAAAAA";
|
||||||
|
virtual void printToConsole(const std::string& msg, std::string_view color) = 0;
|
||||||
|
|
||||||
/// Set time left for the player to start drowning (update the drowning bar)
|
/// Set time left for the player to start drowning (update the drowning bar)
|
||||||
/// @param time time left to start drowning
|
/// @param time time left to start drowning
|
||||||
|
|
|
@ -162,25 +162,34 @@ namespace MWGui
|
||||||
MyGUI::LayerManager::getInstance().upLayerItem(mMainWidget);
|
MyGUI::LayerManager::getInstance().upLayerItem(mMainWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::print(const std::string &msg, const std::string& color)
|
void Console::print(const std::string &msg, std::string_view color)
|
||||||
{
|
{
|
||||||
mHistory->addText(color + MyGUI::TextIterator::toTagsString(msg));
|
mHistory->addText(std::string(color) + MyGUI::TextIterator::toTagsString(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::printOK(const std::string &msg)
|
void Console::printOK(const std::string &msg)
|
||||||
{
|
{
|
||||||
print(msg + "\n", "#FF00FF");
|
print(msg + "\n", MWBase::WindowManager::sConsoleColor_Success);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::printError(const std::string &msg)
|
void Console::printError(const std::string &msg)
|
||||||
{
|
{
|
||||||
print(msg + "\n", "#FF2222");
|
print(msg + "\n", MWBase::WindowManager::sConsoleColor_Error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::execute (const std::string& command)
|
void Console::execute (const std::string& command)
|
||||||
{
|
{
|
||||||
// Log the command
|
// Log the command
|
||||||
|
if (mConsoleMode.empty())
|
||||||
print("> " + command + "\n");
|
print("> " + command + "\n");
|
||||||
|
else
|
||||||
|
print(mConsoleMode + " " + command + "\n");
|
||||||
|
|
||||||
|
if (!mConsoleMode.empty() || (command.size() >= 3 && std::string_view(command).substr(0, 3) == "lua"))
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getLuaManager()->handleConsoleCommand(mConsoleMode, command, mPtr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Compiler::Locals locals;
|
Compiler::Locals locals;
|
||||||
if (!mPtr.isEmpty())
|
if (!mPtr.isEmpty())
|
||||||
|
@ -271,7 +280,7 @@ namespace MWGui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(key == MyGUI::KeyCode::Tab)
|
else if(key == MyGUI::KeyCode::Tab && mConsoleMode.empty())
|
||||||
{
|
{
|
||||||
std::vector<std::string> matches;
|
std::vector<std::string> matches;
|
||||||
listNames();
|
listNames();
|
||||||
|
@ -489,23 +498,31 @@ namespace MWGui
|
||||||
if (!object.isEmpty())
|
if (!object.isEmpty())
|
||||||
{
|
{
|
||||||
if (object == mPtr)
|
if (object == mPtr)
|
||||||
{
|
|
||||||
setTitle("#{sConsoleTitle}");
|
|
||||||
mPtr = MWWorld::Ptr();
|
mPtr = MWWorld::Ptr();
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
setTitle("#{sConsoleTitle} (" + object.getCellRef().getRefId() + ")");
|
|
||||||
mPtr = object;
|
mPtr = object;
|
||||||
}
|
|
||||||
// User clicked on an object. Restore focus to the console command line.
|
// User clicked on an object. Restore focus to the console command line.
|
||||||
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine);
|
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mCommandLine);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
setTitle("#{sConsoleTitle}");
|
|
||||||
mPtr = MWWorld::Ptr();
|
mPtr = MWWorld::Ptr();
|
||||||
|
updateConsoleTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Console::updateConsoleTitle()
|
||||||
|
{
|
||||||
|
std::string title = "#{sConsoleTitle}";
|
||||||
|
if (!mConsoleMode.empty())
|
||||||
|
title = mConsoleMode + " " + title;
|
||||||
|
if (!mPtr.isEmpty())
|
||||||
|
title.append(" (" + mPtr.getCellRef().getRefId() + ")");
|
||||||
|
setTitle(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Console::setConsoleMode(std::string_view mode)
|
||||||
|
{
|
||||||
|
mConsoleMode = std::string(mode);
|
||||||
|
updateConsoleTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Console::onReferenceUnavailable()
|
void Console::onReferenceUnavailable()
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include <components/compiler/output.hpp>
|
#include <components/compiler/output.hpp>
|
||||||
#include <components/compiler/extensions.hpp>
|
#include <components/compiler/extensions.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
#include "../mwscript/compilercontext.hpp"
|
#include "../mwscript/compilercontext.hpp"
|
||||||
#include "../mwscript/interpretercontext.hpp"
|
#include "../mwscript/interpretercontext.hpp"
|
||||||
|
|
||||||
|
@ -40,7 +42,7 @@ namespace MWGui
|
||||||
void onResChange(int width, int height) override;
|
void onResChange(int width, int height) override;
|
||||||
|
|
||||||
// Print a message to the console, in specified color.
|
// Print a message to the console, in specified color.
|
||||||
void print(const std::string &msg, const std::string& color = "#FFFFFF");
|
void print(const std::string &msg, std::string_view color = MWBase::WindowManager::sConsoleColor_Default);
|
||||||
|
|
||||||
// These are pre-colored versions that you should use.
|
// These are pre-colored versions that you should use.
|
||||||
|
|
||||||
|
@ -60,12 +62,19 @@ namespace MWGui
|
||||||
|
|
||||||
void resetReference () override;
|
void resetReference () override;
|
||||||
|
|
||||||
|
const std::string& getConsoleMode() const { return mConsoleMode; }
|
||||||
|
void setConsoleMode(std::string_view mode);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void onReferenceUnavailable() override;
|
void onReferenceUnavailable() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
std::string mConsoleMode;
|
||||||
|
|
||||||
|
void updateConsoleTitle();
|
||||||
|
|
||||||
void keyPress(MyGUI::Widget* _sender,
|
void keyPress(MyGUI::Widget* _sender,
|
||||||
MyGUI::KeyCode key,
|
MyGUI::KeyCode key,
|
||||||
MyGUI::Char _char);
|
MyGUI::Char _char);
|
||||||
|
|
|
@ -2069,6 +2069,16 @@ namespace MWGui
|
||||||
mConsole->setSelectedObject(object);
|
mConsole->setSelectedObject(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowManager::printToConsole(const std::string& msg, std::string_view color)
|
||||||
|
{
|
||||||
|
mConsole->print(msg, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowManager::setConsoleMode(const std::string& mode)
|
||||||
|
{
|
||||||
|
mConsole->setConsoleMode(mode);
|
||||||
|
}
|
||||||
|
|
||||||
std::string WindowManager::correctIconPath(const std::string& path)
|
std::string WindowManager::correctIconPath(const std::string& path)
|
||||||
{
|
{
|
||||||
return Misc::ResourceHelpers::correctIconPath(path, mResourceSystem->getVFS());
|
return Misc::ResourceHelpers::correctIconPath(path, mResourceSystem->getVFS());
|
||||||
|
|
|
@ -195,6 +195,8 @@ namespace MWGui
|
||||||
void updateSpellWindow() override;
|
void updateSpellWindow() override;
|
||||||
|
|
||||||
void setConsoleSelectedObject(const MWWorld::Ptr& object) override;
|
void setConsoleSelectedObject(const MWWorld::Ptr& object) override;
|
||||||
|
void printToConsole(const std::string& msg, std::string_view color) override;
|
||||||
|
void setConsoleMode(const std::string& mode) override;
|
||||||
|
|
||||||
/// Set time left for the player to start drowning (update the drowning bar)
|
/// Set time left for the player to start drowning (update the drowning bar)
|
||||||
/// @param time time left to start drowning
|
/// @param time time left to start drowning
|
||||||
|
|
|
@ -242,6 +242,9 @@ namespace MWLua
|
||||||
for (const std::string& message : mUIMessages)
|
for (const std::string& message : mUIMessages)
|
||||||
windowManager->messageBox(message);
|
windowManager->messageBox(message);
|
||||||
mUIMessages.clear();
|
mUIMessages.clear();
|
||||||
|
for (auto& [msg, color] : mInGameConsoleMessages)
|
||||||
|
windowManager->printToConsole(msg, "#" + color.toHex());
|
||||||
|
mInGameConsoleMessages.clear();
|
||||||
|
|
||||||
for (std::unique_ptr<Action>& action : mActionQueue)
|
for (std::unique_ptr<Action>& action : mActionQueue)
|
||||||
action->safeApply(mWorldView);
|
action->safeApply(mWorldView);
|
||||||
|
@ -256,6 +259,7 @@ namespace MWLua
|
||||||
{
|
{
|
||||||
LuaUi::clearUserInterface();
|
LuaUi::clearUserInterface();
|
||||||
mUiResourceManager.clear();
|
mUiResourceManager.clear();
|
||||||
|
MWBase::Environment::get().getWindowManager()->setConsoleMode("");
|
||||||
mActiveLocalScripts.clear();
|
mActiveLocalScripts.clear();
|
||||||
mLocalEvents.clear();
|
mLocalEvents.clear();
|
||||||
mGlobalEvents.clear();
|
mGlobalEvents.clear();
|
||||||
|
@ -480,6 +484,7 @@ namespace MWLua
|
||||||
Log(Debug::Info) << "Reload Lua";
|
Log(Debug::Info) << "Reload Lua";
|
||||||
|
|
||||||
LuaUi::clearUserInterface();
|
LuaUi::clearUserInterface();
|
||||||
|
MWBase::Environment::get().getWindowManager()->setConsoleMode("");
|
||||||
mUiResourceManager.clear();
|
mUiResourceManager.clear();
|
||||||
mLua.dropScriptCache();
|
mLua.dropScriptCache();
|
||||||
initConfiguration();
|
initConfiguration();
|
||||||
|
@ -503,6 +508,25 @@ namespace MWLua
|
||||||
scripts->receiveEngineEvent(LocalScripts::OnActive());
|
scripts->receiveEngineEvent(LocalScripts::OnActive());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LuaManager::handleConsoleCommand(const std::string& consoleMode, const std::string& command, const MWWorld::Ptr& selectedPtr)
|
||||||
|
{
|
||||||
|
PlayerScripts* playerScripts = nullptr;
|
||||||
|
if (!mPlayer.isEmpty())
|
||||||
|
playerScripts = dynamic_cast<PlayerScripts*>(mPlayer.getRefData().getLuaScripts());
|
||||||
|
if (!playerScripts)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->printToConsole("You must enter a game session to run Lua commands\n",
|
||||||
|
MWBase::WindowManager::sConsoleColor_Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sol::object selected = sol::nil;
|
||||||
|
if (!selectedPtr.isEmpty())
|
||||||
|
selected = sol::make_object(mLua.sol(), LObject(getId(selectedPtr), mWorldView.getObjectRegistry()));
|
||||||
|
if (!playerScripts->consoleCommand(consoleMode, command, selected))
|
||||||
|
MWBase::Environment::get().getWindowManager()->printToConsole("No Lua handlers for console\n",
|
||||||
|
MWBase::WindowManager::sConsoleColor_Error);
|
||||||
|
}
|
||||||
|
|
||||||
LuaManager::Action::Action(LuaUtil::LuaState* state)
|
LuaManager::Action::Action(LuaUtil::LuaState* state)
|
||||||
{
|
{
|
||||||
static const bool luaDebug = Settings::Manager::getBool("lua debug", "Lua");
|
static const bool luaDebug = Settings::Manager::getBool("lua debug", "Lua");
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
#include <components/lua_ui/resources.hpp>
|
#include <components/lua_ui/resources.hpp>
|
||||||
|
|
||||||
|
#include <components/misc/color.hpp>
|
||||||
|
|
||||||
#include "../mwbase/luamanager.hpp"
|
#include "../mwbase/luamanager.hpp"
|
||||||
|
|
||||||
#include "object.hpp"
|
#include "object.hpp"
|
||||||
|
@ -60,6 +62,10 @@ namespace MWLua
|
||||||
// Used only in Lua bindings
|
// Used only in Lua bindings
|
||||||
void addCustomLocalScript(const MWWorld::Ptr&, int scriptId);
|
void addCustomLocalScript(const MWWorld::Ptr&, int scriptId);
|
||||||
void addUIMessage(std::string_view message) { mUIMessages.emplace_back(message); }
|
void addUIMessage(std::string_view message) { mUIMessages.emplace_back(message); }
|
||||||
|
void addInGameConsoleMessage(const std::string& msg, const Misc::Color& color)
|
||||||
|
{
|
||||||
|
mInGameConsoleMessages.push_back({msg, color});
|
||||||
|
}
|
||||||
|
|
||||||
// Some changes to the game world can not be done from the scripting thread (because it runs in parallel with OSG Cull),
|
// Some changes to the game world can not be done from the scripting thread (because it runs in parallel with OSG Cull),
|
||||||
// so we need to queue it and apply from the main thread. All such changes should be implemented as classes inherited
|
// so we need to queue it and apply from the main thread. All such changes should be implemented as classes inherited
|
||||||
|
@ -94,6 +100,8 @@ namespace MWLua
|
||||||
// Drops script cache and reloads all scripts. Calls `onSave` and `onLoad` for every script.
|
// Drops script cache and reloads all scripts. Calls `onSave` and `onLoad` for every script.
|
||||||
void reloadAllScripts() override;
|
void reloadAllScripts() override;
|
||||||
|
|
||||||
|
void handleConsoleCommand(const std::string& consoleMode, const std::string& command, const MWWorld::Ptr& selectedPtr) override;
|
||||||
|
|
||||||
// Used to call Lua callbacks from C++
|
// Used to call Lua callbacks from C++
|
||||||
void queueCallback(LuaUtil::Callback callback, sol::object arg)
|
void queueCallback(LuaUtil::Callback callback, sol::object arg)
|
||||||
{
|
{
|
||||||
|
@ -172,6 +180,7 @@ namespace MWLua
|
||||||
std::vector<std::unique_ptr<Action>> mActionQueue;
|
std::vector<std::unique_ptr<Action>> mActionQueue;
|
||||||
std::unique_ptr<Action> mTeleportPlayerAction;
|
std::unique_ptr<Action> mTeleportPlayerAction;
|
||||||
std::vector<std::string> mUIMessages;
|
std::vector<std::string> mUIMessages;
|
||||||
|
std::vector<std::pair<std::string, Misc::Color>> mInGameConsoleMessages;
|
||||||
|
|
||||||
LuaUtil::LuaStorage mGlobalStorage{mLua.sol()};
|
LuaUtil::LuaStorage mGlobalStorage{mLua.sol()};
|
||||||
LuaUtil::LuaStorage mPlayerStorage{mLua.sol()};
|
LuaUtil::LuaStorage mPlayerStorage{mLua.sol()};
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace MWLua
|
||||||
PlayerScripts(LuaUtil::LuaState* lua, const LObject& obj) : LocalScripts(lua, obj, ESM::LuaScriptCfg::sPlayer)
|
PlayerScripts(LuaUtil::LuaState* lua, const LObject& obj) : LocalScripts(lua, obj, ESM::LuaScriptCfg::sPlayer)
|
||||||
{
|
{
|
||||||
registerEngineHandlers({
|
registerEngineHandlers({
|
||||||
&mKeyPressHandlers, &mKeyReleaseHandlers,
|
&mConsoleCommandHandlers, &mKeyPressHandlers, &mKeyReleaseHandlers,
|
||||||
&mControllerButtonPressHandlers, &mControllerButtonReleaseHandlers,
|
&mControllerButtonPressHandlers, &mControllerButtonReleaseHandlers,
|
||||||
&mActionHandlers, &mInputUpdateHandlers,
|
&mActionHandlers, &mInputUpdateHandlers,
|
||||||
&mTouchpadPressed, &mTouchpadReleased, &mTouchpadMoved
|
&mTouchpadPressed, &mTouchpadReleased, &mTouchpadMoved
|
||||||
|
@ -59,7 +59,14 @@ namespace MWLua
|
||||||
|
|
||||||
void inputUpdate(float dt) { callEngineHandlers(mInputUpdateHandlers, dt); }
|
void inputUpdate(float dt) { callEngineHandlers(mInputUpdateHandlers, dt); }
|
||||||
|
|
||||||
|
bool consoleCommand(const std::string& consoleMode, const std::string& command, const sol::object& selectedObject)
|
||||||
|
{
|
||||||
|
callEngineHandlers(mConsoleCommandHandlers, consoleMode, command, selectedObject);
|
||||||
|
return !mConsoleCommandHandlers.mList.empty();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
EngineHandlerList mConsoleCommandHandlers{"onConsoleCommand"};
|
||||||
EngineHandlerList mKeyPressHandlers{"onKeyPress"};
|
EngineHandlerList mKeyPressHandlers{"onKeyPress"};
|
||||||
EngineHandlerList mKeyReleaseHandlers{"onKeyRelease"};
|
EngineHandlerList mKeyReleaseHandlers{"onKeyRelease"};
|
||||||
EngineHandlerList mControllerButtonPressHandlers{"onControllerButtonPress"};
|
EngineHandlerList mControllerButtonPressHandlers{"onControllerButtonPress"};
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#include "context.hpp"
|
#include "context.hpp"
|
||||||
#include "luamanagerimp.hpp"
|
#include "luamanagerimp.hpp"
|
||||||
|
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
namespace MWLua
|
namespace MWLua
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
|
@ -213,6 +215,33 @@ namespace MWLua
|
||||||
{
|
{
|
||||||
luaManager->addUIMessage(message);
|
luaManager->addUIMessage(message);
|
||||||
};
|
};
|
||||||
|
api["CONSOLE_COLOR"] = LuaUtil::makeReadOnly(context.mLua->tableFromPairs<std::string, Misc::Color>({
|
||||||
|
{"Default", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Default.substr(1))},
|
||||||
|
{"Error", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Error.substr(1))},
|
||||||
|
{"Success", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Success.substr(1))},
|
||||||
|
{"Info", Misc::Color::fromHex(MWBase::WindowManager::sConsoleColor_Info.substr(1))},
|
||||||
|
}));
|
||||||
|
api["printToConsole"] = [luaManager=context.mLuaManager](const std::string& message, const Misc::Color& color)
|
||||||
|
{
|
||||||
|
luaManager->addInGameConsoleMessage(message + "\n", color);
|
||||||
|
};
|
||||||
|
api["setConsoleMode"] = [luaManager=context.mLuaManager](std::string_view mode)
|
||||||
|
{
|
||||||
|
luaManager->addAction(
|
||||||
|
[mode = std::string(mode)]{ MWBase::Environment::get().getWindowManager()->setConsoleMode(mode); });
|
||||||
|
};
|
||||||
|
api["setConsoleSelectedObject"] = [luaManager=context.mLuaManager](const sol::object& obj)
|
||||||
|
{
|
||||||
|
auto* wm = MWBase::Environment::get().getWindowManager();
|
||||||
|
if (obj == sol::nil)
|
||||||
|
luaManager->addAction([wm]{ wm->setConsoleSelectedObject(MWWorld::Ptr()); });
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!obj.is<LObject>())
|
||||||
|
throw std::runtime_error("Game object expected");
|
||||||
|
luaManager->addAction([wm, obj=obj.as<LObject>()]{ wm->setConsoleSelectedObject(obj.ptr()); });
|
||||||
|
}
|
||||||
|
};
|
||||||
api["content"] = [](const sol::table& table)
|
api["content"] = [](const sol::table& table)
|
||||||
{
|
{
|
||||||
return LuaUi::Content(table);
|
return LuaUi::Content(table);
|
||||||
|
|
|
@ -70,23 +70,28 @@ Engine handler is a function defined by a script, that can be called by the engi
|
||||||
:widths: 20 80
|
:widths: 20 80
|
||||||
|
|
||||||
* - onInputUpdate(dt)
|
* - onInputUpdate(dt)
|
||||||
- | Called every frame (if the game is not paused) right after processing
|
- | Called every frame (if the game is not paused) right after
|
||||||
| user input. Use it only for latency-critical stuff.
|
| processing user input. Use it only for latency-critical stuff.
|
||||||
* - onKeyPress(key)
|
* - onKeyPress(key)
|
||||||
- | `Key <openmw_input.html##(KeyboardEvent)>`_ is pressed.
|
- | `Key <openmw_input.html##(KeyboardEvent)>`_ is pressed.
|
||||||
| Usage example: ``if key.symbol == 'z' and key.withShift then ...``
|
| Usage example:
|
||||||
|
| ``if key.symbol == 'z' and key.withShift then ...``
|
||||||
* - onKeyRelease(key)
|
* - onKeyRelease(key)
|
||||||
- | `Key <openmw_input.html##(KeyboardEvent)>`_ is released.
|
- | `Key <openmw_input.html##(KeyboardEvent)>`_ is released.
|
||||||
| Usage example: ``if key.symbol == 'z' and key.withShift then ...``
|
| Usage example:
|
||||||
|
| ``if key.symbol == 'z' and key.withShift then ...``
|
||||||
* - onControllerButtonPress(id)
|
* - onControllerButtonPress(id)
|
||||||
- | A `button <openmw_input.html##(CONTROLLER_BUTTON)>`_ on a game controller is pressed.
|
- | A `button <openmw_input.html##(CONTROLLER_BUTTON)>`_ on a game controller is pressed.
|
||||||
| Usage example: ``if id == input.CONTROLLER_BUTTON.LeftStick then ...``
|
| Usage example:
|
||||||
|
| ``if id == input.CONTROLLER_BUTTON.LeftStick then ...``
|
||||||
* - onControllerButtonRelease(id)
|
* - onControllerButtonRelease(id)
|
||||||
- | A `button <openmw_input.html##(CONTROLLER_BUTTON)>`_ on a game controller is released.
|
- | A `button <openmw_input.html##(CONTROLLER_BUTTON)>`_ on a game controller is released.
|
||||||
| Usage example: ``if id == input.CONTROLLER_BUTTON.LeftStick then ...``
|
| Usage example:
|
||||||
|
| ``if id == input.CONTROLLER_BUTTON.LeftStick then ...``
|
||||||
* - onInputAction(id)
|
* - onInputAction(id)
|
||||||
- | `Game control <openmw_input.html##(ACTION)>`_ is pressed.
|
- | `Game control <openmw_input.html##(ACTION)>`_ is pressed.
|
||||||
| Usage example: ``if id == input.ACTION.ToggleWeapon then ...``
|
| Usage example:
|
||||||
|
| ``if id == input.ACTION.ToggleWeapon then ...``
|
||||||
* - onTouchPress(touchEvent)
|
* - onTouchPress(touchEvent)
|
||||||
- | A finger pressed on a touch device.
|
- | A finger pressed on a touch device.
|
||||||
| `Touch event <openmw_input.html##(TouchEvent)>`_.
|
| `Touch event <openmw_input.html##(TouchEvent)>`_.
|
||||||
|
@ -96,3 +101,8 @@ Engine handler is a function defined by a script, that can be called by the engi
|
||||||
* - onTouchMove(touchEvent)
|
* - onTouchMove(touchEvent)
|
||||||
- | A finger moved on a touch device.
|
- | A finger moved on a touch device.
|
||||||
| `Touch event <openmw_input.html##(TouchEvent)>`_.
|
| `Touch event <openmw_input.html##(TouchEvent)>`_.
|
||||||
|
* - | onConsoleCommand(
|
||||||
|
| mode, command, selectedObject)
|
||||||
|
- | User entered `command` in in-game console. Called if either
|
||||||
|
| `mode` is not default or `command` starts with prefix `lua`.
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,9 @@ set(LUA_BUILTIN_FILES
|
||||||
scripts/omw/camera.lua
|
scripts/omw/camera.lua
|
||||||
scripts/omw/head_bobbing.lua
|
scripts/omw/head_bobbing.lua
|
||||||
scripts/omw/third_person.lua
|
scripts/omw/third_person.lua
|
||||||
|
scripts/omw/console/player.lua
|
||||||
|
scripts/omw/console/global.lua
|
||||||
|
scripts/omw/console/local.lua
|
||||||
|
|
||||||
l10n/Calendar/en.yaml
|
l10n/Calendar/en.yaml
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,2 +1,5 @@
|
||||||
PLAYER: scripts/omw/camera.lua
|
PLAYER: scripts/omw/camera.lua
|
||||||
NPC,CREATURE: scripts/omw/ai.lua
|
NPC,CREATURE: scripts/omw/ai.lua
|
||||||
|
PLAYER: scripts/omw/console/player.lua
|
||||||
|
GLOBAL: scripts/omw/console/global.lua
|
||||||
|
CUSTOM: scripts/omw/console/local.lua
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
-------------------------------------------------------------------------------
|
---
|
||||||
-- `openmw_aux.util` defines utility functions that are implemented in Lua rather than in C++.
|
-- `openmw_aux.util` defines utility functions that are implemented in Lua rather than in C++.
|
||||||
-- Implementation can be found in `resources/vfs/openmw_aux/util.lua`.
|
-- Implementation can be found in `resources/vfs/openmw_aux/util.lua`.
|
||||||
-- @module util
|
-- @module util
|
||||||
|
@ -6,6 +6,27 @@
|
||||||
|
|
||||||
local aux_util = {}
|
local aux_util = {}
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Works like `tostring` but shows also content of tables.
|
||||||
|
-- @function [parent=#util] deepToString
|
||||||
|
-- @param #any value The value to conver to string
|
||||||
|
-- @param #number maxDepth Max depth of tables unpacking (optional, 2 by default)
|
||||||
|
function aux_util.deepToString(val, level, prefix)
|
||||||
|
level = (level or 1) - 1
|
||||||
|
local ok, iter, t = pcall(function() return pairs(val) end)
|
||||||
|
if level < 0 or not ok then
|
||||||
|
return tostring(val)
|
||||||
|
end
|
||||||
|
local prefix = prefix or ''
|
||||||
|
local newPrefix = prefix .. ' '
|
||||||
|
local strs = {tostring(val) .. ' {\n'}
|
||||||
|
for k, v in iter, t do
|
||||||
|
strs[#strs + 1] = newPrefix .. tostring(k) .. ' = ' .. aux_util.deepToString(v, level, newPrefix) .. ',\n'
|
||||||
|
end
|
||||||
|
strs[#strs + 1] = prefix .. '}'
|
||||||
|
return table.concat(strs)
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Finds the nearest object to the given point in the given list.
|
-- Finds the nearest object to the given point in the given list.
|
||||||
-- Ignores cells, uses only coordinates. Returns the nearest object,
|
-- Ignores cells, uses only coordinates. Returns the nearest object,
|
||||||
|
|
81
files/builtin_scripts/scripts/omw/console/global.lua
Normal file
81
files/builtin_scripts/scripts/omw/console/global.lua
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
local util = require('openmw.util')
|
||||||
|
|
||||||
|
local player = nil
|
||||||
|
|
||||||
|
local function printToConsole(...)
|
||||||
|
local strs = {}
|
||||||
|
for i = 1, select('#', ...) do
|
||||||
|
strs[i] = tostring(select(i, ...))
|
||||||
|
end
|
||||||
|
player:sendEvent('OMWConsolePrint', table.concat(strs, '\t'))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function printRes(...)
|
||||||
|
if select('#', ...) >= 0 then
|
||||||
|
printToConsole(...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local env = {
|
||||||
|
I = require('openmw.interfaces'),
|
||||||
|
util = require('openmw.util'),
|
||||||
|
storage = require('openmw.storage'),
|
||||||
|
core = require('openmw.core'),
|
||||||
|
types = require('openmw.types'),
|
||||||
|
async = require('openmw.async'),
|
||||||
|
world = require('openmw.world'),
|
||||||
|
aux_util = require('openmw_aux.util'),
|
||||||
|
view = require('openmw_aux.util').deepToString,
|
||||||
|
print = printToConsole,
|
||||||
|
exit = function() player:sendEvent('OMWConsoleExit') end,
|
||||||
|
help = function() player:sendEvent('OMWConsoleHelp') end,
|
||||||
|
}
|
||||||
|
env._G = env
|
||||||
|
setmetatable(env, {__index = _G, __metatable = false})
|
||||||
|
_G = nil
|
||||||
|
|
||||||
|
local function executeLuaCode(code)
|
||||||
|
local fn
|
||||||
|
local ok, err = pcall(function() fn = util.loadCode('return ' .. code, env) end)
|
||||||
|
if ok then
|
||||||
|
ok, err = pcall(function() printRes(fn()) end)
|
||||||
|
else
|
||||||
|
ok, err = pcall(function() util.loadCode(code, env)() end)
|
||||||
|
end
|
||||||
|
if not ok then
|
||||||
|
player:sendEvent('OMWConsoleError', err)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
eventHandlers = {
|
||||||
|
OMWConsoleEval = function(data)
|
||||||
|
player = data.player
|
||||||
|
env.selected = data.selected
|
||||||
|
executeLuaCode(data.code)
|
||||||
|
if env.selected ~= data.selected then
|
||||||
|
local ok, err = pcall(function() player:sendEvent('OMWConsoleSetSelected', env.selected) end)
|
||||||
|
if not ok then player:sendEvent('OMWConsoleError', err) end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
OMWConsoleStartLocal = function(data)
|
||||||
|
player = data.player
|
||||||
|
ok, err = pcall(function()
|
||||||
|
if not data.selected:hasScript('scripts/omw/console/local.lua') then
|
||||||
|
data.selected:addScript('scripts/omw/console/local.lua')
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
if ok then
|
||||||
|
player:sendEvent('OMWConsoleSetContext', data.selected)
|
||||||
|
else
|
||||||
|
player:sendEvent('OMWConsoleError', err)
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
OMWConsoleStopLocal = function(obj)
|
||||||
|
if obj:hasScript('scripts/omw/console/local.lua') then
|
||||||
|
obj:removeScript('scripts/omw/console/local.lua')
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
71
files/builtin_scripts/scripts/omw/console/local.lua
Normal file
71
files/builtin_scripts/scripts/omw/console/local.lua
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
local util = require('openmw.util')
|
||||||
|
local core = require('openmw.core')
|
||||||
|
local self = require('openmw.self')
|
||||||
|
|
||||||
|
local player = nil
|
||||||
|
|
||||||
|
local function printToConsole(...)
|
||||||
|
local strs = {}
|
||||||
|
for i = 1, select('#', ...) do
|
||||||
|
strs[i] = tostring(select(i, ...))
|
||||||
|
end
|
||||||
|
player:sendEvent('OMWConsolePrint', table.concat(strs, '\t'))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function printRes(...)
|
||||||
|
if select('#', ...) >= 0 then
|
||||||
|
printToConsole(...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local env = {
|
||||||
|
I = require('openmw.interfaces'),
|
||||||
|
util = require('openmw.util'),
|
||||||
|
storage = require('openmw.storage'),
|
||||||
|
core = require('openmw.core'),
|
||||||
|
types = require('openmw.types'),
|
||||||
|
async = require('openmw.async'),
|
||||||
|
nearby = require('openmw.nearby'),
|
||||||
|
self = require('openmw.self'),
|
||||||
|
aux_util = require('openmw_aux.util'),
|
||||||
|
view = require('openmw_aux.util').deepToString,
|
||||||
|
print = printToConsole,
|
||||||
|
exit = function() player:sendEvent('OMWConsoleExit') end,
|
||||||
|
help = function() player:sendEvent('OMWConsoleHelp') end,
|
||||||
|
}
|
||||||
|
env._G = env
|
||||||
|
setmetatable(env, {__index = _G, __metatable = false})
|
||||||
|
_G = nil
|
||||||
|
|
||||||
|
local function executeLuaCode(code)
|
||||||
|
local fn
|
||||||
|
local ok, err = pcall(function() fn = util.loadCode('return ' .. code, env) end)
|
||||||
|
if ok then
|
||||||
|
ok, err = pcall(function() printRes(fn()) end)
|
||||||
|
else
|
||||||
|
ok, err = pcall(function() util.loadCode(code, env)() end)
|
||||||
|
end
|
||||||
|
if not ok then
|
||||||
|
player:sendEvent('OMWConsoleError', err)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
eventHandlers = {
|
||||||
|
OMWConsoleEval = function(data)
|
||||||
|
player = data.player
|
||||||
|
env.selected = data.selected
|
||||||
|
executeLuaCode(data.code)
|
||||||
|
if env.selected ~= data.selected then
|
||||||
|
local ok, err = pcall(function() player:sendEvent('OMWConsoleSetSelected', env.selected) end)
|
||||||
|
if not ok then player:sendEvent('OMWConsoleError', err) end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
},
|
||||||
|
engineHandlers = {
|
||||||
|
onLoad = function()
|
||||||
|
core.sendGlobalEvent('OMWConsoleStopLocal', self.object)
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
158
files/builtin_scripts/scripts/omw/console/player.lua
Normal file
158
files/builtin_scripts/scripts/omw/console/player.lua
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
local ui = require('openmw.ui')
|
||||||
|
local util = require('openmw.util')
|
||||||
|
local self = require('openmw.self')
|
||||||
|
local core = require('openmw.core')
|
||||||
|
|
||||||
|
local function printHelp()
|
||||||
|
local msg = [[
|
||||||
|
This is the built-in Lua interpreter.
|
||||||
|
help() - print this message
|
||||||
|
exit() - exit Lua mode
|
||||||
|
selected - currently selected object (click on any object to change)
|
||||||
|
view(_G) - print content of the table `_G` (current environment)
|
||||||
|
standard libraries (math, string, etc.) are loaded by default but not visible in `_G`
|
||||||
|
view(types, 2) - print table `types` (i.e. `openmw.types`) and its subtables (2 - traversal depth)]]
|
||||||
|
ui.printToConsole(msg, ui.CONSOLE_COLOR.Info)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function printToConsole(...)
|
||||||
|
local strs = {}
|
||||||
|
for i = 1, select('#', ...) do
|
||||||
|
strs[i] = tostring(select(i, ...))
|
||||||
|
end
|
||||||
|
return ui.printToConsole(table.concat(strs, '\t'), ui.CONSOLE_COLOR.Info)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function printRes(...)
|
||||||
|
if select('#', ...) >= 0 then
|
||||||
|
printToConsole(...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local currentSelf = nil
|
||||||
|
local currentMode = ''
|
||||||
|
|
||||||
|
local function exitLuaMode()
|
||||||
|
currentSelf = nil
|
||||||
|
currentMode = ''
|
||||||
|
ui.setConsoleMode('')
|
||||||
|
ui.printToConsole('Lua mode OFF', ui.CONSOLE_COLOR.Success)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function setContext(obj)
|
||||||
|
ui.printToConsole('Lua mode ON, use exit() to return, help() for more info', ui.CONSOLE_COLOR.Success)
|
||||||
|
if obj == self then
|
||||||
|
currentMode = 'Lua[Player]'
|
||||||
|
ui.printToConsole('Context: Player', ui.CONSOLE_COLOR.Success)
|
||||||
|
elseif obj then
|
||||||
|
if not obj:isValid() then error('Object not available') end
|
||||||
|
currentMode = 'Lua['..obj.recordId..']'
|
||||||
|
ui.printToConsole('Context: Local['..tostring(obj)..']', ui.CONSOLE_COLOR.Success)
|
||||||
|
else
|
||||||
|
currentMode = 'Lua[Global]'
|
||||||
|
ui.printToConsole('Context: Global', ui.CONSOLE_COLOR.Success)
|
||||||
|
end
|
||||||
|
currentSelf = obj
|
||||||
|
ui.setConsoleMode(currentMode)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function setSelected(obj)
|
||||||
|
local ok, err = pcall(function() ui.setConsoleSelectedObject(obj) end)
|
||||||
|
if ok then
|
||||||
|
ui.printToConsole('Selected object changed', ui.CONSOLE_COLOR.Success)
|
||||||
|
else
|
||||||
|
ui.printToConsole(err, ui.CONSOLE_COLOR.Error)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local env = {
|
||||||
|
I = require('openmw.interfaces'),
|
||||||
|
util = require('openmw.util'),
|
||||||
|
storage = require('openmw.storage'),
|
||||||
|
core = require('openmw.core'),
|
||||||
|
types = require('openmw.types'),
|
||||||
|
async = require('openmw.async'),
|
||||||
|
nearby = require('openmw.nearby'),
|
||||||
|
self = require('openmw.self'),
|
||||||
|
input = require('openmw.input'),
|
||||||
|
ui = require('openmw.ui'),
|
||||||
|
camera = require('openmw.camera'),
|
||||||
|
aux_util = require('openmw_aux.util'),
|
||||||
|
view = require('openmw_aux.util').deepToString,
|
||||||
|
print = printToConsole,
|
||||||
|
exit = exitLuaMode,
|
||||||
|
help = printHelp,
|
||||||
|
}
|
||||||
|
env._G = env
|
||||||
|
setmetatable(env, {__index = _G, __metatable = false})
|
||||||
|
_G = nil
|
||||||
|
|
||||||
|
local function executeLuaCode(code)
|
||||||
|
local fn
|
||||||
|
local ok, err = pcall(function() fn = util.loadCode('return ' .. code, env) end)
|
||||||
|
if ok then
|
||||||
|
ok, err = pcall(function() printRes(fn()) end)
|
||||||
|
else
|
||||||
|
ok, err = pcall(function() util.loadCode(code, env)() end)
|
||||||
|
end
|
||||||
|
if not ok then
|
||||||
|
ui.printToConsole(err, ui.CONSOLE_COLOR.Error)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function onConsoleCommand(mode, cmd, selectedObject)
|
||||||
|
env.selected = selectedObject
|
||||||
|
if mode == '' then
|
||||||
|
cmd, arg = cmd:lower():match('(%w+) *(%w*)')
|
||||||
|
if cmd == 'lua' then
|
||||||
|
if arg == 'player' then
|
||||||
|
cmd = 'luap'
|
||||||
|
elseif arg == 'global' then
|
||||||
|
cmd = 'luag'
|
||||||
|
elseif arg == 'selected' then
|
||||||
|
cmd = 'luas'
|
||||||
|
else
|
||||||
|
local msg = [[
|
||||||
|
Usage: 'lua player' or 'luap' - enter player context
|
||||||
|
'lua global' or 'luag' - enter global context
|
||||||
|
'lua selected' or 'luas' - enter local context on the selected object]]
|
||||||
|
ui.printToConsole(msg, ui.CONSOLE_COLOR.Info)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if cmd == 'luap' or (cmd == 'luas' and selectedObject == self.object) then
|
||||||
|
setContext(self)
|
||||||
|
elseif cmd == 'luag' then
|
||||||
|
setContext()
|
||||||
|
elseif cmd == 'luas' then
|
||||||
|
if selectedObject then
|
||||||
|
core.sendGlobalEvent('OMWConsoleStartLocal', {player=self.object, selected=selectedObject})
|
||||||
|
else
|
||||||
|
ui.printToConsole('No selected object', ui.CONSOLE_COLOR.Error)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif mode == currentMode then
|
||||||
|
if cmd == 'exit()' then
|
||||||
|
exitLuaMode()
|
||||||
|
elseif currentSelf == self then
|
||||||
|
executeLuaCode(cmd)
|
||||||
|
if env.selected ~= selectedObject then setSelected(env.selected) end
|
||||||
|
elseif currentSelf then
|
||||||
|
currentSelf:sendEvent('OMWConsoleEval', {player=self.object, code=cmd, selected=selectedObject})
|
||||||
|
else
|
||||||
|
core.sendGlobalEvent('OMWConsoleEval', {player=self.object, code=cmd, selected=selectedObject})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
engineHandlers = {onConsoleCommand = onConsoleCommand},
|
||||||
|
eventHandlers = {
|
||||||
|
OMWConsolePrint = function(msg) ui.printToConsole(tostring(msg), ui.CONSOLE_COLOR.Info) end,
|
||||||
|
OMWConsoleError = function(msg) ui.printToConsole(tostring(msg), ui.CONSOLE_COLOR.Error) end,
|
||||||
|
OMWConsoleSetContext = setContext,
|
||||||
|
OMWConsoleSetSelected = setSelected,
|
||||||
|
OMWConsoleExit = exitLuaMode,
|
||||||
|
OMWConsoleHelp = printHelp,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -38,6 +38,37 @@
|
||||||
-- @function [parent=#ui] showMessage
|
-- @function [parent=#ui] showMessage
|
||||||
-- @param #string msg
|
-- @param #string msg
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Predefined colors for console output
|
||||||
|
-- @field [parent=#ui] #CONSOLE_COLOR CONSOLE_COLOR
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Predefined colors for console output
|
||||||
|
-- @type CONSOLE_COLOR
|
||||||
|
-- @field openmw.util#Color Default
|
||||||
|
-- @field openmw.util#Color Error
|
||||||
|
-- @field openmw.util#Color Success
|
||||||
|
-- @field openmw.util#Color Info
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Print to the in-game console.
|
||||||
|
-- @function [parent=#ui] printToConsole
|
||||||
|
-- @param #string msg
|
||||||
|
-- @param openmw.util#Color color
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Set mode of the in-game console.
|
||||||
|
-- The mode can be any string, by default is empty.
|
||||||
|
-- If not empty, then the console doesn't handle mwscript commands and
|
||||||
|
-- instead passes user input to Lua scripts via `onConsoleCommand` engine handler.
|
||||||
|
-- @function [parent=#ui] setConsoleMode
|
||||||
|
-- @param #string mode
|
||||||
|
|
||||||
|
---
|
||||||
|
-- Set selected object for console.
|
||||||
|
-- @function [parent=#ui] setConsoleSelectedObject
|
||||||
|
-- @param openmw.core#GameObject obj
|
||||||
|
|
||||||
---
|
---
|
||||||
-- Returns the size of the OpenMW window in pixels as a 2D vector.
|
-- Returns the size of the OpenMW window in pixels as a 2D vector.
|
||||||
-- @function [parent=#ui] screenSize
|
-- @function [parent=#ui] screenSize
|
||||||
|
|
Loading…
Reference in a new issue