From aefa0ec1c4767485212757f8eb922d6588a7414a Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 29 Jun 2025 10:45:48 +0200 Subject: [PATCH 1/3] Add multiline (un)indent behaviour to the script editor --- apps/opencs/view/world/scriptedit.cpp | 89 +++++++++++++++++++++------ apps/opencs/view/world/scriptedit.hpp | 1 + 2 files changed, 71 insertions(+), 19 deletions(-) diff --git a/apps/opencs/view/world/scriptedit.cpp b/apps/opencs/view/world/scriptedit.cpp index 2871e0ced1..a846d4b342 100644 --- a/apps/opencs/view/world/scriptedit.cpp +++ b/apps/opencs/view/world/scriptedit.cpp @@ -21,6 +21,24 @@ #include "../../model/world/tablemimedata.hpp" #include "../../model/world/universalid.hpp" +namespace +{ + void prependToEachLine(QTextCursor begin, const QString& text) + { + QTextCursor end = begin; + begin.setPosition(begin.selectionStart()); + begin.movePosition(QTextCursor::StartOfLine); + end.setPosition(end.selectionEnd()); + end.movePosition(QTextCursor::EndOfLine); + begin.beginEditBlock(); + for (; begin < end; begin.movePosition(QTextCursor::EndOfLine), begin.movePosition(QTextCursor::Right)) + { + begin.insertText(text); + } + begin.endEditBlock(); + } +} + CSVWorld::ScriptEdit::ChangeLock::ChangeLock(ScriptEdit& edit) : mEdit(edit) { @@ -46,6 +64,55 @@ bool CSVWorld::ScriptEdit::event(QEvent* event) return QPlainTextEdit::event(event); } +void CSVWorld::ScriptEdit::keyPressEvent(QKeyEvent* event) +{ + if (event->key() == Qt::Key_Backtab) + { + QTextCursor cursor = textCursor(); + QTextCursor end = cursor; + cursor.setPosition(cursor.selectionStart()); + cursor.movePosition(QTextCursor::StartOfLine); + end.setPosition(end.selectionEnd()); + end.movePosition(QTextCursor::EndOfLine); + cursor.beginEditBlock(); + for (; cursor < end; cursor.movePosition(QTextCursor::EndOfLine), cursor.movePosition(QTextCursor::Right)) + { + cursor.select(QTextCursor::LineUnderCursor); + QString line = cursor.selectedText(); + + if (line.isEmpty()) + continue; + qsizetype index = 0; + if (line[0] == '\t') + index = 1; + else + { + // Remove up to a tab worth of spaces instead + while (line[index].isSpace() && index < mTabCharCount && line[index] != '\t') + index++; + } + + if (index != 0) + { + line.remove(0, index); + cursor.insertText(line); + } + } + cursor.endEditBlock(); + return; + } + else if (event->key() == Qt::Key_Tab) + { + QTextCursor cursor = textCursor(); + if (cursor.hasSelection()) + { + prependToEachLine(cursor, "\t"); + return; + } + } + QPlainTextEdit::keyPressEvent(event); +} + CSVWorld::ScriptEdit::ScriptEdit(const CSMDoc::Document& document, ScriptHighlighter::Mode mode, QWidget* parent) : QPlainTextEdit(parent) , mChangeLocked(0) @@ -316,22 +383,7 @@ void CSVWorld::ScriptEdit::markOccurrences() void CSVWorld::ScriptEdit::commentSelection() { - QTextCursor begin = textCursor(); - QTextCursor end = begin; - begin.setPosition(begin.selectionStart()); - begin.movePosition(QTextCursor::StartOfLine); - - end.setPosition(end.selectionEnd()); - end.movePosition(QTextCursor::EndOfLine); - - begin.beginEditBlock(); - - for (; begin < end; begin.movePosition(QTextCursor::EndOfLine), begin.movePosition(QTextCursor::Right)) - { - begin.insertText(";"); - } - - begin.endEditBlock(); + prependToEachLine(textCursor(), ";"); } void CSVWorld::ScriptEdit::uncommentSelection() @@ -345,17 +397,16 @@ void CSVWorld::ScriptEdit::uncommentSelection() end.movePosition(QTextCursor::EndOfLine); begin.beginEditBlock(); - for (; begin < end; begin.movePosition(QTextCursor::EndOfLine), begin.movePosition(QTextCursor::Right)) { begin.select(QTextCursor::LineUnderCursor); QString line = begin.selectedText(); - if (line.size() == 0) + if (line.isEmpty()) continue; // get first nonspace character in line - int index; + qsizetype index; for (index = 0; index != line.size(); ++index) { if (!line[index].isSpace()) diff --git a/apps/opencs/view/world/scriptedit.hpp b/apps/opencs/view/world/scriptedit.hpp index 53fa88ced3..d44c29eaab 100644 --- a/apps/opencs/view/world/scriptedit.hpp +++ b/apps/opencs/view/world/scriptedit.hpp @@ -74,6 +74,7 @@ namespace CSVWorld protected: bool event(QEvent* event) override; + void keyPressEvent(QKeyEvent* e) override; public: ScriptEdit(const CSMDoc::Document& document, ScriptHighlighter::Mode mode, QWidget* parent); From 27ee192354a943c4f3282a4227486a4dc6ce5c8e Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 29 Jun 2025 10:57:23 +0200 Subject: [PATCH 2/3] Set default hotkeys for (un)commenting script lines --- apps/opencs/model/prefs/values.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/prefs/values.hpp b/apps/opencs/model/prefs/values.hpp index 16e5434d6b..7b6d5e9f5f 100644 --- a/apps/opencs/model/prefs/values.hpp +++ b/apps/opencs/model/prefs/values.hpp @@ -507,8 +507,10 @@ namespace CSMPrefs Settings::SettingValue mOrbitRollRight{ mIndex, sName, "orbit-roll-right", "E" }; Settings::SettingValue mOrbitSpeedMode{ mIndex, sName, "orbit-speed-mode", "" }; Settings::SettingValue mOrbitCenterSelection{ mIndex, sName, "orbit-center-selection", "C" }; - Settings::SettingValue mScriptEditorComment{ mIndex, sName, "script-editor-comment", "" }; - Settings::SettingValue mScriptEditorUncomment{ mIndex, sName, "script-editor-uncomment", "" }; + Settings::SettingValue mScriptEditorComment{ mIndex, sName, "script-editor-comment", + "Ctrl+Slash" }; + Settings::SettingValue mScriptEditorUncomment{ mIndex, sName, "script-editor-uncomment", + "Ctrl+Shift+Question" }; }; struct ModelsCategory : Settings::WithIndex From 645eb811331b7d8337afb8dbf4f1b6314b26b6a0 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Sat, 21 Dec 2024 11:01:39 +0400 Subject: [PATCH 3/3] Run onUpdate when the game is paused --- CMakeLists.txt | 2 +- apps/openmw/mwlua/luamanagerimp.cpp | 13 ++++++------- .../reference/lua-scripting/engine_handlers.rst | 2 +- files/data/scripts/omw/camera/camera.lua | 4 ++++ .../scripts/omw/mechanics/animationcontroller.lua | 4 ++++ .../data/scripts/omw/mechanics/playercontroller.lua | 6 +++++- files/data/scripts/omw/music/actor.lua | 6 +++--- files/lua_api/openmw/core.lua | 2 +- files/lua_api/openmw/world.lua | 2 +- 9 files changed, 26 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0d8e3cade9..b4ef872eb6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,7 +82,7 @@ message(STATUS "Configuring OpenMW...") set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MINOR 50) set(OPENMW_VERSION_RELEASE 0) -set(OPENMW_LUA_API_REVISION 85) +set(OPENMW_LUA_API_REVISION 86) set(OPENMW_POSTPROCESSING_API_REVISION 3) set(OPENMW_VERSION_COMMITHASH "") diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp index 9c2778e55d..df9c9cd50f 100644 --- a/apps/openmw/mwlua/luamanagerimp.cpp +++ b/apps/openmw/mwlua/luamanagerimp.cpp @@ -212,13 +212,12 @@ namespace MWLua // Run engine handlers mEngineEvents.callEngineHandlers(); - if (!timeManager.isPaused()) - { - float frameDuration = MWBase::Environment::get().getFrameDuration(); - for (LocalScripts* scripts : mActiveLocalScripts) - scripts->update(frameDuration); - mGlobalScripts.update(frameDuration); - } + bool isPaused = timeManager.isPaused(); + + float frameDuration = MWBase::Environment::get().getFrameDuration(); + for (LocalScripts* scripts : mActiveLocalScripts) + scripts->update(isPaused ? 0 : frameDuration); + mGlobalScripts.update(isPaused ? 0 : frameDuration); mLua.protectedCall([&](LuaUtil::LuaView& lua) { mScriptTracker.unloadInactiveScripts(lua); }); } diff --git a/docs/source/reference/lua-scripting/engine_handlers.rst b/docs/source/reference/lua-scripting/engine_handlers.rst index 29b14aee55..cc1e45403f 100644 --- a/docs/source/reference/lua-scripting/engine_handlers.rst +++ b/docs/source/reference/lua-scripting/engine_handlers.rst @@ -28,7 +28,7 @@ Engine handler is a function defined by a script, that can be called by the engi | `assigned to a script in openmw-cs (not yet implemented).` | ``onInterfaceOverride`` can be called before ``onInit``. * - onUpdate(dt) - - | Called every frame if the game is not paused. `dt` is + - | Called every frame in the Lua thread (even if the game is paused). `dt` is | the simulation time from the last update in seconds. * - onSave() -> savedData - | Called when the game is saving. May be called in inactive state, diff --git a/files/data/scripts/omw/camera/camera.lua b/files/data/scripts/omw/camera/camera.lua index 6730e0c069..52b64906ea 100644 --- a/files/data/scripts/omw/camera/camera.lua +++ b/files/data/scripts/omw/camera/camera.lua @@ -182,6 +182,10 @@ local function updateCrosshair() end local function onUpdate(dt) + if dt <= 0 then + return + end + camera.setExtraPitch(0) camera.setExtraYaw(0) camera.setExtraRoll(0) diff --git a/files/data/scripts/omw/mechanics/animationcontroller.lua b/files/data/scripts/omw/mechanics/animationcontroller.lua index 91cb60d177..9edc7565ca 100644 --- a/files/data/scripts/omw/mechanics/animationcontroller.lua +++ b/files/data/scripts/omw/mechanics/animationcontroller.lua @@ -41,6 +41,10 @@ end local initialized = false local function onUpdate(dt) + if dt <= 0 then + return + end + -- The script is loaded before the actor's CharacterController object is initialized, therefore -- we have to delay this initialization step or the call won't have any effect. if not initialized then diff --git a/files/data/scripts/omw/mechanics/playercontroller.lua b/files/data/scripts/omw/mechanics/playercontroller.lua index 8b4d618917..6de31afdea 100644 --- a/files/data/scripts/omw/mechanics/playercontroller.lua +++ b/files/data/scripts/omw/mechanics/playercontroller.lua @@ -96,7 +96,11 @@ local function skillUsedHandler(skillid, params) end end -local function onUpdate() +local function onUpdate(dt) + if dt <= 0 then + return + end + if self.cell ~= cell then cell = self.cell onCellChange() diff --git a/files/data/scripts/omw/music/actor.lua b/files/data/scripts/omw/music/actor.lua index 8f3ac7915a..02cded7904 100755 --- a/files/data/scripts/omw/music/actor.lua +++ b/files/data/scripts/omw/music/actor.lua @@ -11,7 +11,7 @@ local function emitTargetsChanged() end end -local function onUpdate() +local function onUpdate(dt) if types.Actor.isDeathFinished(self) or not types.Actor.isInActorsProcessingRange(self) then if next(targets) ~= nil then targets = {} @@ -21,10 +21,10 @@ local function onUpdate() return end - -- Early-out for actors without targets and without combat state + -- Early-out for actors without targets and without combat state when the game is not paused -- TODO: use events or engine handlers to detect when targets change local isStanceNothing = types.Actor.getStance(self) == types.Actor.STANCE.Nothing - if isStanceNothing and next(targets) == nil and not AI.isFleeing() then + if isStanceNothing and next(targets) == nil and not AI.isFleeing() and dt > 0 then return end diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index 0567cec859..054e96674b 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -42,7 +42,7 @@ -- @return #number --- --- Whether the world is paused (onUpdate doesn't work when the world is paused). +-- Whether the world is paused. -- @function [parent=#core] isWorldPaused -- @return #boolean diff --git a/files/lua_api/openmw/world.lua b/files/lua_api/openmw/world.lua index ae494f8c99..22126ce8f4 100644 --- a/files/lua_api/openmw/world.lua +++ b/files/lua_api/openmw/world.lua @@ -119,7 +119,7 @@ -- @param #number ratio --- --- Whether the world is paused (onUpdate doesn't work when the world is paused). +-- Whether the world is paused. -- @function [parent=#world] isWorldPaused -- @return #boolean