From f0e2ee45fae4c3d7060193a28b3fb4479fec7dba Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Wed, 13 May 2020 21:17:08 +0200 Subject: [PATCH 01/45] reuse ImplicitRef and ExplicitRef for enable, disable, getdisabled, startscript; move scriptrunning and stopscript --- apps/openmw/mwscript/interpretercontext.cpp | 70 --------- apps/openmw/mwscript/interpretercontext.hpp | 15 -- apps/openmw/mwscript/miscextensions.cpp | 84 +++++++++++ .../mwscript/transformationextensions.cpp | 45 ++++++ components/CMakeLists.txt | 2 +- components/compiler/exprparser.cpp | 92 +----------- components/compiler/extensions0.cpp | 7 + components/compiler/generator.cpp | 133 ------------------ components/compiler/generator.hpp | 14 -- components/compiler/lineparser.cpp | 54 +------ components/compiler/opcodes.hpp | 12 ++ components/compiler/scanner.cpp | 3 - components/compiler/scanner.hpp | 5 +- components/compiler/stringparser.cpp | 9 +- components/interpreter/context.hpp | 15 -- components/interpreter/installopcodes.cpp | 18 --- components/interpreter/miscopcodes.hpp | 72 ---------- components/interpreter/scriptopcodes.hpp | 63 --------- components/interpreter/spatialopcodes.hpp | 43 ------ 19 files changed, 155 insertions(+), 601 deletions(-) delete mode 100644 components/interpreter/scriptopcodes.hpp delete mode 100644 components/interpreter/spatialopcodes.hpp diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index 58596a2f4..f9d85375b 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -415,58 +415,6 @@ namespace MWScript return MWBase::Environment::get().getWorld()->getCellName(); } - bool InterpreterContext::isScriptRunning (const std::string& name) const - { - return MWBase::Environment::get().getScriptManager()->getGlobalScripts().isRunning (name); - } - - void InterpreterContext::startScript (const std::string& name, const std::string& targetId) - { - MWWorld::Ptr target; - if (targetId.empty()) - target = getReference(false); - else - target = getReferenceImp(targetId); - MWBase::Environment::get().getScriptManager()->getGlobalScripts().addScript (name, target); - } - - void InterpreterContext::stopScript (const std::string& name) - { - MWBase::Environment::get().getScriptManager()->getGlobalScripts().removeScript (name); - } - - float InterpreterContext::getDistance (const std::string& name, const std::string& id) const - { - // NOTE: id may be empty, indicating an implicit reference - - MWWorld::Ptr ref2 = getReferenceImp(id); - - if (ref2.getContainerStore()) // is the object contained? - { - MWWorld::Ptr container = MWBase::Environment::get().getWorld()->findContainer(ref2); - - if (!container.isEmpty()) - ref2 = container; - else - throw std::runtime_error("failed to find container ptr"); - } - - const MWWorld::Ptr ref = MWBase::Environment::get().getWorld()->getPtr(name, false); - - // If the objects are in different worldspaces, return a large value (just like vanilla) - if (!ref.isInCell() || !ref2.isInCell() || ref.getCell()->getCell()->getCellId().mWorldspace != ref2.getCell()->getCell()->getCellId().mWorldspace) - return std::numeric_limits::max(); - - double diff[3]; - - const float* const pos1 = ref.getRefData().getPosition().pos; - const float* const pos2 = ref2.getRefData().getPosition().pos; - for (int i=0; i<3; ++i) - diff[i] = pos1[i] - pos2[i]; - - return static_cast(std::sqrt(diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2])); - } - void InterpreterContext::executeActivation(MWWorld::Ptr ptr, MWWorld::Ptr actor) { std::shared_ptr action = (ptr.getClass().activate(ptr, actor)); @@ -482,24 +430,6 @@ namespace MWScript return MWBase::Environment::get().getFrameDuration(); } - bool InterpreterContext::isDisabled (const std::string& id) const - { - const MWWorld::Ptr ref = getReferenceImp (id, false); - return !ref.getRefData().isEnabled(); - } - - void InterpreterContext::enable (const std::string& id) - { - MWWorld::Ptr ref = getReferenceImp (id, false); - MWBase::Environment::get().getWorld()->enable (ref); - } - - void InterpreterContext::disable (const std::string& id) - { - MWWorld::Ptr ref = getReferenceImp (id, false); - MWBase::Environment::get().getWorld()->disable (ref); - } - int InterpreterContext::getMemberShort (const std::string& id, const std::string& name, bool global) const { diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 1c465ee3e..7e9f09cdb 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -121,26 +121,11 @@ namespace MWScript virtual std::string getCurrentCellName() const; - virtual bool isScriptRunning (const std::string& name) const; - - virtual void startScript (const std::string& name, const std::string& targetId = ""); - - virtual void stopScript (const std::string& name); - - virtual float getDistance (const std::string& name, const std::string& id = "") const; - ///< @note if \a id is empty, assumes an implicit reference - void executeActivation(MWWorld::Ptr ptr, MWWorld::Ptr actor); ///< Execute the activation action for this ptr. If ptr is mActivated, mark activation as handled. virtual float getSecondsPassed() const; - virtual bool isDisabled (const std::string& id = "") const; - - virtual void enable (const std::string& id = ""); - - virtual void disable (const std::string& id = ""); - virtual int getMemberShort (const std::string& id, const std::string& name, bool global) const; virtual int getMemberLong (const std::string& id, const std::string& name, bool global) const; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index b7b91cf5c..915b3221c 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -78,6 +78,80 @@ namespace MWScript { namespace Misc { + template + class OpStartScript : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + std::string name = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + MWWorld::Ptr target = R()(runtime, false); + MWBase::Environment::get().getScriptManager()->getGlobalScripts().addScript (name, target); + } + }; + + class OpScriptRunning : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + std::string name = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + runtime.push(MWBase::Environment::get().getScriptManager()->getGlobalScripts().isRunning (name)); + } + }; + + class OpStopScript : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + std::string name = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + MWBase::Environment::get().getScriptManager()->getGlobalScripts().removeScript (name); + } + }; + + template + class OpEnable : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + MWBase::Environment::get().getWorld()->enable (ptr); + } + }; + + template + class OpDisable : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + MWBase::Environment::get().getWorld()->disable (ptr); + } + }; + + template + class OpGetDisabled : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + MWWorld::Ptr ptr = R()(runtime); + runtime.push (!ptr.getRefData().isEnabled()); + } + }; + class OpPlayBink : public Interpreter::Opcode0 { public: @@ -1456,6 +1530,16 @@ namespace MWScript void installOpcodes (Interpreter::Interpreter& interpreter) { + interpreter.installSegment5 (Compiler::Misc::opcodeScriptRunning, new OpScriptRunning); + interpreter.installSegment5 (Compiler::Misc::opcodeStartScript, new OpStartScript); + interpreter.installSegment5 (Compiler::Misc::opcodeStartScriptExplicit, new OpStartScript); + interpreter.installSegment5 (Compiler::Misc::opcodeStopScript, new OpStopScript); + interpreter.installSegment5 (Compiler::Misc::opcodeEnable, new OpEnable); + interpreter.installSegment5 (Compiler::Misc::opcodeEnableExplicit, new OpEnable); + interpreter.installSegment5 (Compiler::Misc::opcodeDisable, new OpDisable); + interpreter.installSegment5 (Compiler::Misc::opcodeDisableExplicit, new OpDisable); + interpreter.installSegment5 (Compiler::Misc::opcodeGetDisabled, new OpGetDisabled); + interpreter.installSegment5 (Compiler::Misc::opcodeGetDisabledExplicit, new OpGetDisabled); interpreter.installSegment5 (Compiler::Misc::opcodeXBox, new OpXBox); interpreter.installSegment5 (Compiler::Misc::opcodeOnActivate, new OpOnActivate); interpreter.installSegment5 (Compiler::Misc::opcodeOnActivateExplicit, new OpOnActivate); diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index d28d9c373..3af54b394 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -39,6 +39,49 @@ namespace MWScript } } + template + class OpGetDistance : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + std::string name = runtime.getStringLiteral (runtime[0].mInteger); + runtime.pop(); + + MWWorld::Ptr from = R()(runtime); + if (from.getContainerStore()) // is the object contained? + { + MWWorld::Ptr container = MWBase::Environment::get().getWorld()->findContainer(from); + + if (!container.isEmpty()) + from = container; + else + throw std::runtime_error("failed to find container ptr"); + } + + const MWWorld::Ptr to = MWBase::Environment::get().getWorld()->getPtr(name, false); + + float distance; + // If the objects are in different worldspaces, return a large value (just like vanilla) + if (!to.isInCell() || !from.isInCell() || to.getCell()->getCell()->getCellId().mWorldspace != from.getCell()->getCell()->getCellId().mWorldspace) + distance = std::numeric_limits::max(); + else + { + double diff[3]; + + const float* const pos1 = to.getRefData().getPosition().pos; + const float* const pos2 = from.getRefData().getPosition().pos; + for (int i=0; i<3; ++i) + diff[i] = pos1[i] - pos2[i]; + + distance = static_cast(std::sqrt(diff[0] * diff[0] + diff[1] * diff[1] + diff[2] * diff[2])); + } + + runtime.push(distance); + } + }; + template class OpSetScale : public Interpreter::Opcode0 { @@ -730,6 +773,8 @@ namespace MWScript void installOpcodes (Interpreter::Interpreter& interpreter) { + interpreter.installSegment5(Compiler::Transformation::opcodeGetDistance, new OpGetDistance); + interpreter.installSegment5(Compiler::Transformation::opcodeGetDistanceExplicit, new OpGetDistance); interpreter.installSegment5(Compiler::Transformation::opcodeSetScale,new OpSetScale); interpreter.installSegment5(Compiler::Transformation::opcodeSetScaleExplicit,new OpSetScale); interpreter.installSegment5(Compiler::Transformation::opcodeSetAngle,new OpSetAngle); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a7d70b4e0..19fb2de89 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -111,7 +111,7 @@ add_component_dir (compiler add_component_dir (interpreter context controlopcodes genericopcodes installopcodes interpreter localopcodes mathopcodes - miscopcodes opcodes runtime scriptopcodes spatialopcodes types defines + miscopcodes opcodes runtime types defines ) add_component_dir (translation diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 20873385b..8e8f063bb 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -372,9 +372,7 @@ namespace Compiler keyword==Scanner::K_elseif || keyword==Scanner::K_while || keyword==Scanner::K_endwhile || keyword==Scanner::K_return || keyword==Scanner::K_messagebox || keyword==Scanner::K_set || - keyword==Scanner::K_to || keyword==Scanner::K_startscript || - keyword==Scanner::K_stopscript || keyword==Scanner::K_enable || - keyword==Scanner::K_disable) + keyword==Scanner::K_to) { return parseName (loc.mLiteral, loc, scanner); } @@ -385,53 +383,6 @@ namespace Compiler { if (mRefOp && mNextOperand) { - if (keyword==Scanner::K_getdisabled) - { - start(); - - mTokenLoc = loc; - - Generator::getDisabled (mCode, mLiterals, mExplicit); - mOperands.push_back ('l'); - mExplicit.clear(); - mRefOp = false; - - std::vector ignore; - parseArguments ("x", scanner, ignore); - - mNextOperand = false; - return true; - } - else if (keyword==Scanner::K_getdistance) - { - start(); - - mTokenLoc = loc; - parseArguments ("c", scanner); - - Generator::getDistance (mCode, mLiterals, mExplicit); - mOperands.push_back ('f'); - mExplicit.clear(); - mRefOp = false; - - mNextOperand = false; - return true; - } - else if (keyword==Scanner::K_scriptrunning) - { - start(); - - mTokenLoc = loc; - parseArguments ("c", scanner); - - Generator::scriptRunning (mCode); - mOperands.push_back ('l'); - - mExplicit.clear(); - mRefOp = false; - mNextOperand = false; - return true; - } // check for custom extensions if (const Extensions *extensions = getContext().getExtensions()) @@ -508,32 +459,6 @@ namespace Compiler mNextOperand = false; return true; } - else if (keyword==Scanner::K_scriptrunning) - { - start(); - - mTokenLoc = loc; - parseArguments ("c", scanner); - - Generator::scriptRunning (mCode); - mOperands.push_back ('l'); - - mNextOperand = false; - return true; - } - else if (keyword==Scanner::K_getdistance) - { - start(); - - mTokenLoc = loc; - parseArguments ("c", scanner); - - Generator::getDistance (mCode, mLiterals, ""); - mOperands.push_back ('f'); - - mNextOperand = false; - return true; - } else if (keyword==Scanner::K_getsecondspassed) { start(); @@ -546,21 +471,6 @@ namespace Compiler mNextOperand = false; return true; } - else if (keyword==Scanner::K_getdisabled) - { - start(); - - mTokenLoc = loc; - - Generator::getDisabled (mCode, mLiterals, ""); - mOperands.push_back ('l'); - - std::vector ignore; - parseArguments ("x", scanner, ignore); - - mNextOperand = false; - return true; - } else { // check for custom extensions diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index f23d2d86e..02a68d891 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -241,6 +241,12 @@ namespace Compiler { void registerExtensions (Extensions& extensions) { + extensions.registerFunction ("scriptrunning", 'l', "c", opcodeScriptRunning); + extensions.registerInstruction ("startscript", "c", opcodeStartScript, opcodeStartScriptExplicit); + extensions.registerInstruction ("stopscript", "c", opcodeStopScript); + extensions.registerInstruction ("enable", "", opcodeEnable, opcodeEnableExplicit); + extensions.registerInstruction ("disable", "", opcodeDisable, opcodeDisableExplicit); + extensions.registerFunction ("getdisabled", 'l', "x", opcodeGetDisabled, opcodeGetDisabledExplicit); extensions.registerFunction ("xbox", 'l', "", opcodeXBox); extensions.registerFunction ("onactivate", 'l', "", opcodeOnActivate, opcodeOnActivateExplicit); extensions.registerInstruction ("activate", "x", opcodeActivate, opcodeActivateExplicit); @@ -533,6 +539,7 @@ namespace Compiler { void registerExtensions (Extensions& extensions) { + extensions.registerFunction("getdistance",'f',"c",opcodeGetDistance,opcodeGetDistanceExplicit); extensions.registerInstruction("setscale","f",opcodeSetScale,opcodeSetScaleExplicit); extensions.registerFunction("getscale",'f',"",opcodeGetScale,opcodeGetScaleExplicit); extensions.registerInstruction("setangle","cf",opcodeSetAngle,opcodeSetAngleExplicit); diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index 7e6437e20..c16df660c 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -292,65 +292,10 @@ namespace code.push_back (Compiler::Generator::segment5 (45)); } - void opScriptRunning (Compiler::Generator::CodeContainer& code) - { - code.push_back (Compiler::Generator::segment5 (46)); - } - - void opStartScript (Compiler::Generator::CodeContainer& code, bool targeted) - { - code.push_back (Compiler::Generator::segment5 (targeted ? 71 : 47)); - } - - void opStopScript (Compiler::Generator::CodeContainer& code) - { - code.push_back (Compiler::Generator::segment5 (48)); - } - - void opGetDistance (Compiler::Generator::CodeContainer& code) - { - code.push_back (Compiler::Generator::segment5 (49)); - } - void opGetSecondsPassed (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (50)); } - - void opEnable (Compiler::Generator::CodeContainer& code) - { - code.push_back (Compiler::Generator::segment5 (51)); - } - - void opDisable (Compiler::Generator::CodeContainer& code) - { - code.push_back (Compiler::Generator::segment5 (52)); - } - - void opGetDisabled (Compiler::Generator::CodeContainer& code) - { - code.push_back (Compiler::Generator::segment5 (53)); - } - - void opEnableExplicit (Compiler::Generator::CodeContainer& code) - { - code.push_back (Compiler::Generator::segment5 (54)); - } - - void opDisableExplicit (Compiler::Generator::CodeContainer& code) - { - code.push_back (Compiler::Generator::segment5 (55)); - } - - void opGetDisabledExplicit (Compiler::Generator::CodeContainer& code) - { - code.push_back (Compiler::Generator::segment5 (56)); - } - - void opGetDistanceExplicit (Compiler::Generator::CodeContainer& code) - { - code.push_back (Compiler::Generator::segment5 (57)); - } } namespace Compiler @@ -812,87 +757,9 @@ namespace Compiler opRandom (code); } - void scriptRunning (CodeContainer& code) - { - opScriptRunning (code); - } - - void startScript (CodeContainer& code, Literals& literals, const std::string& id) - { - if (id.empty()) - opStartScript (code, false); - else - { - int index = literals.addString (id); - opPushInt (code, index); - opStartScript (code, true); - } - } - - void stopScript (CodeContainer& code) - { - opStopScript (code); - } - - void getDistance (CodeContainer& code, Literals& literals, const std::string& id) - { - if (id.empty()) - { - opGetDistance (code); - } - else - { - int index = literals.addString (id); - opPushInt (code, index); - opGetDistanceExplicit (code); - } - } - void getSecondsPassed (CodeContainer& code) { opGetSecondsPassed (code); } - - void getDisabled (CodeContainer& code, Literals& literals, const std::string& id) - { - if (id.empty()) - { - opGetDisabled (code); - } - else - { - int index = literals.addString (id); - opPushInt (code, index); - opGetDisabledExplicit (code); - } - } - - void enable (CodeContainer& code, Literals& literals, const std::string& id) - { - if (id.empty()) - { - opEnable (code); - } - else - { - int index = literals.addString (id); - opPushInt (code, index); - opEnableExplicit (code); - } - } - - void disable (CodeContainer& code, Literals& literals, const std::string& id) - { - if (id.empty()) - { - opDisable (code); - } - else - { - int index = literals.addString (id); - opPushInt (code, index); - opDisableExplicit (code); - } - } } } diff --git a/components/compiler/generator.hpp b/components/compiler/generator.hpp index a56d7c1f1..f4386f605 100644 --- a/components/compiler/generator.hpp +++ b/components/compiler/generator.hpp @@ -109,21 +109,7 @@ namespace Compiler void random (CodeContainer& code); - void scriptRunning (CodeContainer& code); - - void startScript (CodeContainer& code, Literals& literals, const std::string& id); - - void stopScript (CodeContainer& code); - - void getDistance (CodeContainer& code, Literals& literals, const std::string& id); - void getSecondsPassed (CodeContainer& code); - - void getDisabled (CodeContainer& code, Literals& literals, const std::string& id); - - void enable (CodeContainer& code, Literals& literals, const std::string& id); - - void disable (CodeContainer& code, Literals& literals, const std::string& id); } } diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index 646685b39..eaa833800 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -247,35 +247,6 @@ namespace Compiler if (mState==BeginState || mState==ExplicitState) { - switch (keyword) - { - case Scanner::K_enable: - - Generator::enable (mCode, mLiterals, mExplicit); - mState = PotentialEndState; - return true; - - case Scanner::K_disable: - - Generator::disable (mCode, mLiterals, mExplicit); - mState = PotentialEndState; - return true; - - case Scanner::K_startscript: - - mExprParser.parseArguments ("c", scanner, mCode); - Generator::startScript (mCode, mLiterals, mExplicit); - mState = EndState; - return true; - - case Scanner::K_stopscript: - - mExprParser.parseArguments ("c", scanner, mCode); - Generator::stopScript (mCode); - mState = EndState; - return true; - } - // check for custom extensions if (const Extensions *extensions = getContext().getExtensions()) { @@ -323,21 +294,6 @@ namespace Compiler } } - if (keyword==Scanner::K_getdisabled || keyword==Scanner::K_getdistance) - { - if (mAllowExpression) - { - scanner.putbackKeyword (keyword, loc); - parseExpression (scanner, loc); - } - else - { - getErrorHandler().warning ("Unexpected naked expression", loc); - } - mState = EndState; - return true; - } - if (const Extensions *extensions = getContext().getExtensions()) { char returnType; @@ -416,13 +372,6 @@ namespace Compiler mState = EndState; return true; - case Scanner::K_stopscript: - - mExprParser.parseArguments ("c", scanner, mCode); - Generator::stopScript (mCode); - mState = EndState; - return true; - case Scanner::K_else: getErrorHandler().warning ("Stray else", loc); @@ -487,8 +436,7 @@ namespace Compiler if (mAllowExpression) { if (keyword==Scanner::K_getsquareroot || keyword==Scanner::K_menumode || - keyword==Scanner::K_random || keyword==Scanner::K_scriptrunning || - keyword==Scanner::K_getsecondspassed) + keyword==Scanner::K_random || keyword==Scanner::K_getsecondspassed) { scanner.putbackKeyword (keyword, loc); parseExpression (scanner, loc); diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index d3446e688..72e3cea89 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -201,6 +201,16 @@ namespace Compiler namespace Misc { + const int opcodeScriptRunning = 46; + const int opcodeStartScript = 47; + const int opcodeStopScript = 48; + const int opcodeEnable = 51; + const int opcodeDisable = 52; + const int opcodeGetDisabled = 53; + const int opcodeEnableExplicit = 54; + const int opcodeDisableExplicit = 55; + const int opcodeGetDisabledExplicit = 56; + const int opcodeStartScriptExplicit = 71; const int opcodeXBox = 0x200000c; const int opcodeOnActivate = 0x200000d; const int opcodeOnActivateExplicit = 0x2000306; @@ -473,6 +483,8 @@ namespace Compiler namespace Transformation { + const int opcodeGetDistance = 49; + const int opcodeGetDistanceExplicit = 57; const int opcodeSetScale = 0x2000164; const int opcodeSetScaleExplicit = 0x2000165; const int opcodeSetAngle = 0x2000166; diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 83686e4c1..2be679cd2 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -268,10 +268,7 @@ namespace Compiler "getsquareroot", "menumode", "random", - "startscript", "stopscript", "scriptrunning", - "getdistance", "getsecondspassed", - "enable", "disable", "getdisabled", 0 }; diff --git a/components/compiler/scanner.hpp b/components/compiler/scanner.hpp index b8d057677..973761898 100644 --- a/components/compiler/scanner.hpp +++ b/components/compiler/scanner.hpp @@ -211,10 +211,7 @@ namespace Compiler K_getsquareroot, K_menumode, K_random, - K_startscript, K_stopscript, K_scriptrunning, - K_getdistance, - K_getsecondspassed, - K_enable, K_disable, K_getdisabled + K_getsecondspassed }; enum special diff --git a/components/compiler/stringparser.cpp b/components/compiler/stringparser.cpp index ad88bb857..a9974297d 100644 --- a/components/compiler/stringparser.cpp +++ b/components/compiler/stringparser.cpp @@ -63,12 +63,9 @@ namespace Compiler keyword==Scanner::K_elseif || keyword==Scanner::K_while || keyword==Scanner::K_endwhile || keyword==Scanner::K_return || keyword==Scanner::K_messagebox || keyword==Scanner::K_set || - keyword==Scanner::K_to || keyword==Scanner::K_startscript || - keyword==Scanner::K_stopscript || keyword==Scanner::K_enable || - keyword==Scanner::K_disable || keyword==Scanner::K_getdisabled || - keyword==Scanner::K_getdistance || keyword==Scanner::K_scriptrunning || - keyword==Scanner::K_getsquareroot || keyword==Scanner::K_menumode || - keyword==Scanner::K_random || keyword==Scanner::K_getsecondspassed) + keyword==Scanner::K_to || keyword==Scanner::K_getsquareroot || + keyword==Scanner::K_menumode || keyword==Scanner::K_random || + keyword==Scanner::K_getsecondspassed) { return parseName (loc.mLiteral, loc, scanner); } diff --git a/components/interpreter/context.hpp b/components/interpreter/context.hpp index 88fdae128..30744dcec 100644 --- a/components/interpreter/context.hpp +++ b/components/interpreter/context.hpp @@ -79,23 +79,8 @@ namespace Interpreter virtual std::string getCurrentCellName() const = 0; - virtual bool isScriptRunning (const std::string& name) const = 0; - - virtual void startScript (const std::string& name, const std::string& targetId = "") = 0; - - virtual void stopScript (const std::string& name) = 0; - - virtual float getDistance (const std::string& name, const std::string& id = "") const - = 0; - virtual float getSecondsPassed() const = 0; - virtual bool isDisabled (const std::string& id = "") const = 0; - - virtual void enable (const std::string& id = "") = 0; - - virtual void disable (const std::string& id = "") = 0; - virtual int getMemberShort (const std::string& id, const std::string& name, bool global) const = 0; virtual int getMemberLong (const std::string& id, const std::string& name, bool global) const = 0; diff --git a/components/interpreter/installopcodes.cpp b/components/interpreter/installopcodes.cpp index 31e911f8b..dfaabe325 100644 --- a/components/interpreter/installopcodes.cpp +++ b/components/interpreter/installopcodes.cpp @@ -8,8 +8,6 @@ #include "mathopcodes.hpp" #include "controlopcodes.hpp" #include "miscopcodes.hpp" -#include "scriptopcodes.hpp" -#include "spatialopcodes.hpp" namespace Interpreter { @@ -100,22 +98,6 @@ namespace Interpreter interpreter.installSegment5 (38, new OpMenuMode); interpreter.installSegment5 (45, new OpRandom); interpreter.installSegment5 (50, new OpGetSecondsPassed); - interpreter.installSegment5 (51, new OpEnable); - interpreter.installSegment5 (52, new OpDisable); - interpreter.installSegment5 (53, new OpGetDisabled); - interpreter.installSegment5 (54, new OpEnableExplicit); - interpreter.installSegment5 (55, new OpDisableExplicit); - interpreter.installSegment5 (56, new OpGetDisabledExplicit); interpreter.installSegment5 (58, new OpReport); - - // script control - interpreter.installSegment5 (46, new OpScriptRunning); - interpreter.installSegment5 (47, new OpStartScript); - interpreter.installSegment5 (48, new OpStopScript); - interpreter.installSegment5 (71, new OpStartScriptExplicit); - - // spacial - interpreter.installSegment5 (49, new OpGetDistance); - interpreter.installSegment5 (57, new OpGetDistanceExplicit); } } diff --git a/components/interpreter/miscopcodes.hpp b/components/interpreter/miscopcodes.hpp index a77e0d7d8..e1b1843ef 100644 --- a/components/interpreter/miscopcodes.hpp +++ b/components/interpreter/miscopcodes.hpp @@ -206,78 +206,6 @@ namespace Interpreter } }; - class OpEnable : public Opcode0 - { - public: - - virtual void execute (Runtime& runtime) - { - runtime.getContext().enable(); - } - }; - - class OpDisable : public Opcode0 - { - public: - - virtual void execute (Runtime& runtime) - { - runtime.getContext().disable(); - } - }; - - class OpGetDisabled : public Opcode0 - { - public: - - virtual void execute (Runtime& runtime) - { - runtime.push (runtime.getContext().isDisabled()); - } - }; - - class OpEnableExplicit : public Opcode0 - { - public: - - virtual void execute (Runtime& runtime) - { - int index = runtime[0].mInteger; - runtime.pop(); - std::string id = runtime.getStringLiteral (index); - - runtime.getContext().enable (id); - } - }; - - class OpDisableExplicit : public Opcode0 - { - public: - - virtual void execute (Runtime& runtime) - { - int index = runtime[0].mInteger; - runtime.pop(); - std::string id = runtime.getStringLiteral (index); - - runtime.getContext().disable (id); - } - }; - - class OpGetDisabledExplicit : public Opcode0 - { - public: - - virtual void execute (Runtime& runtime) - { - int index = runtime[0].mInteger; - runtime.pop(); - std::string id = runtime.getStringLiteral (index); - - runtime.push (runtime.getContext().isDisabled (id)); - } - }; - } #endif diff --git a/components/interpreter/scriptopcodes.hpp b/components/interpreter/scriptopcodes.hpp deleted file mode 100644 index c98bcd23e..000000000 --- a/components/interpreter/scriptopcodes.hpp +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef INTERPRETER_SCRIPTOPCODES_H_INCLUDED -#define INTERPRETER_SCRIPTOPCODES_H_INCLUDED - -#include "opcodes.hpp" -#include "runtime.hpp" -#include "context.hpp" - -namespace Interpreter -{ - class OpScriptRunning : public Opcode0 - { - public: - - virtual void execute (Runtime& runtime) - { - std::string name = runtime.getStringLiteral (runtime[0].mInteger); - runtime[0].mInteger = runtime.getContext().isScriptRunning (name); - } - }; - - class OpStartScript : public Opcode0 - { - public: - - virtual void execute (Runtime& runtime) - { - std::string name = runtime.getStringLiteral (runtime[0].mInteger); - runtime.pop(); - runtime.getContext().startScript (name); - } - }; - - class OpStartScriptExplicit : public Opcode0 - { - public: - - virtual void execute (Runtime& runtime) - { - std::string targetId = runtime.getStringLiteral (runtime[0].mInteger); - runtime.pop(); - - std::string name = runtime.getStringLiteral (runtime[0].mInteger); - runtime.pop(); - - runtime.getContext().startScript (name, targetId); - } - }; - - class OpStopScript : public Opcode0 - { - public: - - virtual void execute (Runtime& runtime) - { - std::string name = runtime.getStringLiteral (runtime[0].mInteger); - runtime.pop(); - runtime.getContext().stopScript (name); - } - }; -} - -#endif - diff --git a/components/interpreter/spatialopcodes.hpp b/components/interpreter/spatialopcodes.hpp deleted file mode 100644 index e37df8116..000000000 --- a/components/interpreter/spatialopcodes.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef INTERPRETER_SPATIALOPCODES_H_INCLUDED -#define INTERPRETER_SPATIALOPCODES_H_INCLUDED - -#include "opcodes.hpp" -#include "runtime.hpp" - -namespace Interpreter -{ - class OpGetDistance : public Opcode0 - { - public: - - virtual void execute (Runtime& runtime) - { - std::string name = runtime.getStringLiteral (runtime[0].mInteger); - - Type_Float distance = runtime.getContext().getDistance (name); - - runtime[0].mFloat = distance; - } - }; - - class OpGetDistanceExplicit : public Opcode0 - { - public: - - virtual void execute (Runtime& runtime) - { - int index = runtime[0].mInteger; - runtime.pop(); - std::string id = runtime.getStringLiteral (index); - - std::string name = runtime.getStringLiteral (runtime[0].mInteger); - - Type_Float distance = runtime.getContext().getDistance (name, id); - - runtime[0].mFloat = distance; - } - }; -} - -#endif - From e827d9c04f3646cc4eaf262985a2886b4a98164e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 15 May 2020 12:38:22 +0400 Subject: [PATCH 02/45] Disable physics profiler, if Bullet was compiled without profiling support --- apps/openmw/mwgui/windowmanagerimp.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 21e84613c..1d2dc185b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -15,6 +15,9 @@ #include #include +// For BT_NO_PROFILE +#include + #include #include @@ -2202,7 +2205,9 @@ namespace MWGui void WindowManager::toggleDebugWindow() { +#ifndef BT_NO_PROFILE mDebugWindow->setVisible(!mDebugWindow->isVisible()); +#endif } void WindowManager::cycleSpell(bool next) From add42830d9e482bb22466a284cacf8909f0f7e29 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 15 May 2020 12:39:04 +0400 Subject: [PATCH 03/45] Add a flag to use double-precision functions from Bullet --- CMakeLists.txt | 2 +- apps/openmw/CMakeLists.txt | 4 ++++ components/CMakeLists.txt | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ba73908ac..4cc9ccd55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,7 @@ option(BUILD_NIFTEST "Build nif file tester" ON) option(BUILD_DOCS "Build documentation." OFF ) option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF) +option(BULLET_USE_DOUBLES "Use double precision for Bullet" OFF) if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD) set(USE_QT FALSE) @@ -904,4 +905,3 @@ if (DOXYGEN_FOUND) WORKING_DIRECTORY ${OpenMW_BINARY_DIR} COMMENT "Generating documentation for the github-pages at ${DOXYGEN_PAGES_OUTPUT_DIR}" VERBATIM) endif () - diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 34824ea33..2107b74fe 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -15,6 +15,10 @@ set(GAME_HEADER engine.hpp ) +if (BULLET_USE_DOUBLES) + add_definitions(-DBT_USE_DOUBLE_PRECISION) +endif() + source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a7d70b4e0..859c79920 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -285,3 +285,7 @@ endif() # Make the variable accessible for other subdirectories set(COMPONENT_FILES ${COMPONENT_FILES} PARENT_SCOPE) + +if (BULLET_USE_DOUBLES) + add_definitions(-DBT_USE_DOUBLE_PRECISION) +endif() From 3ebbe14a62474acc421f8081d884318968a95e36 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 18 Sep 2019 10:21:25 +0400 Subject: [PATCH 04/45] Avoid zero division --- apps/openmw/mwmechanics/actors.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 9cfada560..3bbd8cf29 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -774,6 +774,9 @@ namespace MWMechanics if (visitor.mRemainingTime > 0) { double timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor(); + if(timeScale == 0.0) + timeScale = 1; + restoreHours = std::max(0.0, hours - visitor.mRemainingTime * timeScale / 3600.f); } else if (visitor.mRemainingTime == -1) @@ -1935,7 +1938,11 @@ namespace MWMechanics void Actors::rest(double hours, bool sleep) { - float duration = hours * 3600.f / MWBase::Environment::get().getWorld()->getTimeScaleFactor(); + float duration = hours * 3600.f; + float timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor(); + if (timeScale != 0.f) + duration /= timeScale; + const MWWorld::Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); const osg::Vec3f playerPos = player.getRefData().getPosition().asVec3(); From b5833f3c59e3dc19481ff7b2f3d4a7c3ca17fed4 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Wed, 18 Sep 2019 09:43:32 +0400 Subject: [PATCH 05/45] Use real time to update spell effects instead of game timestamps (bug #5165) --- CHANGELOG.md | 3 +- apps/openmw/mwmechanics/activespells.cpp | 51 ++++++------------------ apps/openmw/mwmechanics/activespells.hpp | 5 +-- apps/openmw/mwmechanics/actors.cpp | 2 + apps/openmw/mwmechanics/spellcasting.cpp | 3 ++ components/esm/activespells.cpp | 14 ++++++- components/esm/activespells.hpp | 2 +- components/esm/savedgame.cpp | 2 +- 8 files changed, 36 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 434b45fb3..138ef1707 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Bug #3676: NiParticleColorModifier isn't applied properly Bug #4774: Guards are ignorant of an invisible player that tries to attack them Bug #5108: Savegame bloating due to inefficient fog textures format + Bug #5165: Active spells should use real time intead of timestamps Bug #5358: ForceGreeting always resets the dialogue window completely Bug #5363: Enchantment autocalc not always 0/1 Bug #5364: Script fails/stops if trying to startscript an unknown script @@ -188,8 +189,8 @@ Bug #5158: Objects without a name don't fallback to their ID Bug #5159: NiMaterialColorController can only control the diffuse color Bug #5161: Creature companions can't be activated when they are knocked down - Bug #5164: Faction owned items handling is incorrect Bug #5163: UserData is not copied during node cloning + Bug #5164: Faction owned items handling is incorrect Bug #5166: Scripts still should be executed after player's death Bug #5167: Player can select and cast spells before magic menu is enabled Bug #5168: Force1stPerson and Force3rdPerson commands are not really force view change diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 57b009689..4b4b40607 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -12,14 +12,12 @@ namespace MWMechanics { - void ActiveSpells::update() const + void ActiveSpells::update(float duration) const { bool rebuild = false; - MWWorld::TimeStamp now = MWBase::Environment::get().getWorld()->getTimeStamp(); - // Erase no longer active spells and effects - if (mLastUpdate!=now) + if (duration > 0) { TContainer::iterator iter (mSpells.begin()); while (iter!=mSpells.end()) @@ -34,21 +32,20 @@ namespace MWMechanics std::vector& effects = iter->second.mEffects; for (std::vector::iterator effectIt = effects.begin(); effectIt != effects.end();) { - MWWorld::TimeStamp start = iter->second.mTimeStamp; - MWWorld::TimeStamp end = start + static_cast(effectIt->mDuration)*MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60); - if (end <= now) + if (effectIt->mTimeLeft <= 0) { effectIt = effects.erase(effectIt); rebuild = true; } else + { + effectIt->mTimeLeft -= duration; ++effectIt; + } } ++iter; } } - - mLastUpdate = now; } if (mSpellsChanged) @@ -63,24 +60,15 @@ namespace MWMechanics void ActiveSpells::rebuildEffects() const { - MWWorld::TimeStamp now = MWBase::Environment::get().getWorld()->getTimeStamp(); - mEffects = MagicEffects(); for (TIterator iter (begin()); iter!=end(); ++iter) { - const MWWorld::TimeStamp& start = iter->second.mTimeStamp; - const std::vector& effects = iter->second.mEffects; for (std::vector::const_iterator effectIt = effects.begin(); effectIt != effects.end(); ++effectIt) { - double duration = effectIt->mDuration; - MWWorld::TimeStamp end = start; - end += duration * - MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60); - - if (end>now) + if (effectIt->mTimeLeft > 0) mEffects.add(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), MWMechanics::EffectParam(effectIt->mMagnitude)); } } @@ -88,12 +76,11 @@ namespace MWMechanics ActiveSpells::ActiveSpells() : mSpellsChanged (false) - , mLastUpdate (MWBase::Environment::get().getWorld()->getTimeStamp()) {} const MagicEffects& ActiveSpells::getMagicEffects() const { - update(); + update(0.f); return mEffects; } @@ -116,19 +103,14 @@ namespace MWMechanics for (std::vector::const_iterator iter (effects.begin()); iter!=effects.end(); ++iter) { - if (iter->mDuration > duration) - duration = iter->mDuration; + if (iter->mTimeLeft > duration) + duration = iter->mTimeLeft; } - double scaledDuration = duration * - MWBase::Environment::get().getWorld()->getTimeScaleFactor()/(60*60); - - double usedUp = MWBase::Environment::get().getWorld()->getTimeStamp() - iterator->second.mTimeStamp; - - if (usedUp>=scaledDuration) + if (duration < 0) return 0; - return scaledDuration-usedUp; + return duration; } bool ActiveSpells::isSpellActive(const std::string& id) const @@ -152,7 +134,6 @@ namespace MWMechanics TContainer::iterator it(mSpells.find(id)); ActiveSpellParams params; - params.mTimeStamp = MWBase::Environment::get().getWorld()->getTimeStamp(); params.mEffects = effects; params.mDisplayName = displayName; params.mCasterActorId = casterActorId; @@ -211,19 +192,15 @@ namespace MWMechanics { for (TContainer::const_iterator it = begin(); it != end(); ++it) { - float timeScale = MWBase::Environment::get().getWorld()->getTimeScaleFactor(); - for (std::vector::const_iterator effectIt = it->second.mEffects.begin(); effectIt != it->second.mEffects.end(); ++effectIt) { std::string name = it->second.mDisplayName; - float remainingTime = effectIt->mDuration + - static_cast(it->second.mTimeStamp - MWBase::Environment::get().getWorld()->getTimeStamp())*3600/timeScale; float magnitude = effectIt->mMagnitude; if (magnitude) - visitor.visit(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), name, it->first, it->second.mCasterActorId, magnitude, remainingTime, effectIt->mDuration); + visitor.visit(MWMechanics::EffectKey(effectIt->mEffectId, effectIt->mArg), name, it->first, it->second.mCasterActorId, magnitude, effectIt->mTimeLeft, effectIt->mDuration); } } } @@ -316,7 +293,6 @@ namespace MWMechanics params.mEffects = it->second.mEffects; params.mCasterActorId = it->second.mCasterActorId; params.mDisplayName = it->second.mDisplayName; - params.mTimeStamp = it->second.mTimeStamp.toEsm(); state.mSpells.insert (std::make_pair(it->first, params)); } @@ -331,7 +307,6 @@ namespace MWMechanics params.mEffects = it->second.mEffects; params.mCasterActorId = it->second.mCasterActorId; params.mDisplayName = it->second.mDisplayName; - params.mTimeStamp = MWWorld::TimeStamp(it->second.mTimeStamp); mSpells.insert (std::make_pair(it->first, params)); mSpellsChanged = true; diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index a19c8a51d..ddfa56ecf 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -44,15 +44,14 @@ namespace MWMechanics TIterator end() const; + void update(float duration) const; + private: mutable TContainer mSpells; mutable MagicEffects mEffects; mutable bool mSpellsChanged; - mutable MWWorld::TimeStamp mLastUpdate; - void update() const; - void rebuildEffects() const; /// Add any effects that are in "from" and not in "addTo" to "addTo" diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 3bbd8cf29..223d9fc34 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1622,6 +1622,8 @@ namespace MWMechanics player.getClass().getCreatureStats(player).setHitAttemptActorId(-1); } + iter->first.getClass().getCreatureStats(iter->first).getActiveSpells().update(duration); + // For dead actors we need to remove looping spell particles if (iter->first.getClass().getCreatureStats(iter->first).isDead()) ctrl->updateContinuousVfx(); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 044a4338e..769934986 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -183,6 +183,7 @@ namespace MWMechanics effect.mEffectId = effectIt->mEffectID; effect.mArg = MWMechanics::EffectKey(*effectIt).mArg; effect.mMagnitude = magnitude; + effect.mTimeLeft = 0.f; // Avoid applying absorb effects if the caster is the target // We still need the spell to be added @@ -225,6 +226,8 @@ namespace MWMechanics { effect.mDuration = hasDuration ? static_cast(effectIt->mDuration) : 1.f; + effect.mTimeLeft = effect.mDuration; + targetEffects.add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(effect.mMagnitude)); // add to list of active effects, to apply in next frame diff --git a/components/esm/activespells.cpp b/components/esm/activespells.cpp index 4f51a619e..46558ceb7 100644 --- a/components/esm/activespells.cpp +++ b/components/esm/activespells.cpp @@ -16,7 +16,6 @@ namespace ESM esm.writeHNT ("CAST", params.mCasterActorId); esm.writeHNString ("DISP", params.mDisplayName); - esm.writeHNT ("TIME", params.mTimeStamp); for (std::vector::const_iterator effectIt = params.mEffects.begin(); effectIt != params.mEffects.end(); ++effectIt) { @@ -25,12 +24,15 @@ namespace ESM esm.writeHNT ("ARG_", effectIt->mArg); esm.writeHNT ("MAGN", effectIt->mMagnitude); esm.writeHNT ("DURA", effectIt->mDuration); + esm.writeHNT ("LEFT", effectIt->mTimeLeft); } } } void ActiveSpells::load(ESMReader &esm) { + int format = esm.getFormat(); + while (esm.isNextSub("ID__")) { std::string spellId = esm.getHString(); @@ -38,7 +40,10 @@ namespace ESM ActiveSpellParams params; esm.getHNT (params.mCasterActorId, "CAST"); params.mDisplayName = esm.getHNString ("DISP"); - esm.getHNT (params.mTimeStamp, "TIME"); + + // spell casting timestamp, no longer used + if (esm.isNextSub("TIME")) + esm.skipHSub(); while (esm.isNextSub("MGEF")) { @@ -48,6 +53,11 @@ namespace ESM esm.getHNOT(effect.mArg, "ARG_"); esm.getHNT (effect.mMagnitude, "MAGN"); esm.getHNT (effect.mDuration, "DURA"); + if (format < 9) + effect.mTimeLeft = effect.mDuration; + else + esm.getHNT (effect.mTimeLeft, "LEFT"); + params.mEffects.push_back(effect); } mSpells.insert(std::make_pair(spellId, params)); diff --git a/components/esm/activespells.hpp b/components/esm/activespells.hpp index d9e9a8c63..20b2f652d 100644 --- a/components/esm/activespells.hpp +++ b/components/esm/activespells.hpp @@ -21,6 +21,7 @@ namespace ESM float mMagnitude; int mArg; // skill or attribute float mDuration; + float mTimeLeft; }; // format 0, saved games only @@ -29,7 +30,6 @@ namespace ESM struct ActiveSpellParams { std::vector mEffects; - ESM::TimeStamp mTimeStamp; std::string mDisplayName; int mCasterActorId; }; diff --git a/components/esm/savedgame.cpp b/components/esm/savedgame.cpp index f2ebc7bf0..6696ed478 100644 --- a/components/esm/savedgame.cpp +++ b/components/esm/savedgame.cpp @@ -5,7 +5,7 @@ #include "defs.hpp" unsigned int ESM::SavedGame::sRecordId = ESM::REC_SAVE; -int ESM::SavedGame::sCurrentFormat = 8; +int ESM::SavedGame::sCurrentFormat = 9; void ESM::SavedGame::load (ESMReader &esm) { From b8513e03181c319b05edfe1bf130dc919b137d76 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 16 May 2020 14:53:42 +0200 Subject: [PATCH 06/45] Remove unused arguments --- apps/openmw/mwmechanics/aiwander.cpp | 20 ++++++++++---------- apps/openmw/mwmechanics/aiwander.hpp | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 53e80f54e..8b90eb1d7 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -165,7 +165,7 @@ namespace MWMechanics * actors will enter combat (i.e. no longer wandering) and different pathfinding * will kick in. */ - bool AiWander::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) + bool AiWander::execute (const MWWorld::Ptr& actor, CharacterController& /*characterController*/, AiState& state, float duration) { MWMechanics::CreatureStats& cStats = actor.getClass().getCreatureStats(actor); if (cStats.isDead() || cStats.getHealth().getCurrent() <= 0) @@ -206,7 +206,7 @@ namespace MWMechanics { if (storage.mState == AiWanderStorage::Wander_Walking) { - stopWalking(actor, storage, false); + stopWalking(actor, false); mObstacleCheck.clear(); storage.setState(AiWanderStorage::Wander_IdleNow); } @@ -230,7 +230,7 @@ namespace MWMechanics if (mDistance <= 0) storage.mCanWanderAlongPathGrid = false; - if (isPackageCompleted(actor, storage)) + if (isPackageCompleted(actor)) { // Reset package so it can be used again mRemainingDuration=mDuration; @@ -315,14 +315,14 @@ namespace MWMechanics return actor.getRefData().getPosition().asVec3(); } - bool AiWander::isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage) + bool AiWander::isPackageCompleted(const MWWorld::Ptr& actor) { if (mDuration) { // End package if duration is complete if (mRemainingDuration <= 0) { - stopWalking(actor, storage); + stopWalking(actor); return true; } } @@ -395,7 +395,7 @@ namespace MWMechanics } void AiWander::completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage) { - stopWalking(actor, storage); + stopWalking(actor); mObstacleCheck.clear(); storage.setState(AiWanderStorage::Wander_IdleNow); } @@ -460,7 +460,7 @@ namespace MWMechanics // Is there no destination or are we there yet? if ((!mPathFinder.isPathConstructed()) || pathTo(actor, osg::Vec3f(mPathFinder.getPath().back()), duration, DESTINATION_TOLERANCE)) { - stopWalking(actor, storage); + stopWalking(actor); storage.setState(AiWanderStorage::Wander_ChooseAction); } else @@ -518,7 +518,7 @@ namespace MWMechanics storage.mTrimCurrentNode = true; trimAllowedNodes(storage.mAllowedNodes, mPathFinder); mObstacleCheck.clear(); - stopWalking(actor, storage); + stopWalking(actor); storage.setState(AiWanderStorage::Wander_MoveNow); } @@ -529,7 +529,7 @@ namespace MWMechanics if (storage.mStuckCount >= getCountBeforeReset(actor)) // something has gone wrong, reset { mObstacleCheck.clear(); - stopWalking(actor, storage); + stopWalking(actor); storage.setState(AiWanderStorage::Wander_ChooseAction); storage.mStuckCount = 0; } @@ -609,7 +609,7 @@ namespace MWMechanics return TypeIdWander; } - void AiWander::stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage, bool clearPath) + void AiWander::stopWalking(const MWWorld::Ptr& actor, bool clearPath) { if (clearPath) { diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 376be3a25..405799c1f 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -118,7 +118,7 @@ namespace MWMechanics private: // NOTE: mDistance and mDuration must be set already void init(); - void stopWalking(const MWWorld::Ptr& actor, AiWanderStorage& storage, bool clearPath = true); + void stopWalking(const MWWorld::Ptr& actor, bool clearPath = true); /// Have the given actor play an idle animation /// @return Success or error @@ -133,7 +133,7 @@ namespace MWMechanics void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage); bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos); - bool isPackageCompleted(const MWWorld::Ptr& actor, AiWanderStorage& storage); + bool isPackageCompleted(const MWWorld::Ptr& actor); void wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance); bool destinationIsAtWater(const MWWorld::Ptr &actor, const osg::Vec3f& destination); void completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage); From 131f2557b16da7c6b7bc4dfa0f181004731ce958 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 16 May 2020 14:57:20 +0200 Subject: [PATCH 07/45] Split functions to remove redundant clearPath argument --- apps/openmw/mwmechanics/aiwander.cpp | 18 ++++++++++-------- apps/openmw/mwmechanics/aiwander.hpp | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 8b90eb1d7..e37039403 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -89,6 +89,11 @@ namespace MWMechanics const auto maxHalfExtent = std::max(halfExtents.x(), std::max(halfExtents.y(), halfExtents.z())); return world->isAreaOccupiedByOtherActor(destination, 2 * maxHalfExtent, actor); } + + void stopMovement(const MWWorld::Ptr& actor) + { + actor.getClass().getMovementSettings(actor).mPosition[1] = 0; + } } AiWander::AiWander(int distance, int duration, int timeOfDay, const std::vector& idle, bool repeat): @@ -206,7 +211,7 @@ namespace MWMechanics { if (storage.mState == AiWanderStorage::Wander_Walking) { - stopWalking(actor, false); + stopMovement(actor); mObstacleCheck.clear(); storage.setState(AiWanderStorage::Wander_IdleNow); } @@ -609,14 +614,11 @@ namespace MWMechanics return TypeIdWander; } - void AiWander::stopWalking(const MWWorld::Ptr& actor, bool clearPath) + void AiWander::stopWalking(const MWWorld::Ptr& actor) { - if (clearPath) - { - mPathFinder.clearPath(); - mHasDestination = false; - } - actor.getClass().getMovementSettings(actor).mPosition[1] = 0; + mPathFinder.clearPath(); + mHasDestination = false; + stopMovement(actor); } bool AiWander::playIdle(const MWWorld::Ptr& actor, unsigned short idleSelect) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 405799c1f..716c695ea 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -118,7 +118,7 @@ namespace MWMechanics private: // NOTE: mDistance and mDuration must be set already void init(); - void stopWalking(const MWWorld::Ptr& actor, bool clearPath = true); + void stopWalking(const MWWorld::Ptr& actor); /// Have the given actor play an idle animation /// @return Success or error From 256c9917a415d22d5525beb6ba2f6571a10bf6cd Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 16 May 2020 14:58:50 +0200 Subject: [PATCH 08/45] Make AiWander::isPackageCompleted const --- apps/openmw/mwmechanics/aiwander.cpp | 18 +++++------------- apps/openmw/mwmechanics/aiwander.hpp | 2 +- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index e37039403..f04477243 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -235,8 +235,9 @@ namespace MWMechanics if (mDistance <= 0) storage.mCanWanderAlongPathGrid = false; - if (isPackageCompleted(actor)) + if (isPackageCompleted()) { + stopWalking(actor); // Reset package so it can be used again mRemainingDuration=mDuration; init(); @@ -320,19 +321,10 @@ namespace MWMechanics return actor.getRefData().getPosition().asVec3(); } - bool AiWander::isPackageCompleted(const MWWorld::Ptr& actor) + bool AiWander::isPackageCompleted() const { - if (mDuration) - { - // End package if duration is complete - if (mRemainingDuration <= 0) - { - stopWalking(actor); - return true; - } - } - // if get here, not yet completed - return false; + // End package if duration is complete + return mDuration && mRemainingDuration <= 0; } /* diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 716c695ea..8154ea995 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -133,7 +133,7 @@ namespace MWMechanics void onWalkingStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); void onChooseActionStatePerFrameActions(const MWWorld::Ptr& actor, AiWanderStorage& storage); bool reactionTimeActions(const MWWorld::Ptr& actor, AiWanderStorage& storage, ESM::Position& pos); - bool isPackageCompleted(const MWWorld::Ptr& actor); + inline bool isPackageCompleted() const; void wanderNearStart(const MWWorld::Ptr &actor, AiWanderStorage &storage, int wanderDistance); bool destinationIsAtWater(const MWWorld::Ptr &actor, const osg::Vec3f& destination); void completeManualWalking(const MWWorld::Ptr &actor, AiWanderStorage &storage); From d86669843e15a0b4a72aa7ea0cf25e9ccde507fd Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 16 May 2020 17:07:42 +0200 Subject: [PATCH 09/45] Remove unseud pointTolerance argument --- apps/openmw/mwmechanics/aiwander.cpp | 9 +++------ apps/openmw/mwmechanics/aiwander.hpp | 2 +- apps/openmw/mwmechanics/pathfinding.cpp | 2 +- apps/openmw/mwmechanics/pathfinding.hpp | 2 +- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index f04477243..597453409 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -463,7 +463,7 @@ namespace MWMechanics else { // have not yet reached the destination - evadeObstacles(actor, duration, storage); + evadeObstacles(actor, storage); } } @@ -494,15 +494,12 @@ namespace MWMechanics storage.setState(AiWanderStorage::Wander_IdleNow); } - void AiWander::evadeObstacles(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage) + void AiWander::evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage) { if (mUsePathgrid) { const auto halfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(actor); - const float actorTolerance = 2 * actor.getClass().getSpeed(actor) * duration - + 1.2 * std::max(halfExtents.x(), halfExtents.y()); - const float pointTolerance = std::max(MIN_TOLERANCE, actorTolerance); - mPathFinder.buildPathByNavMeshToNextPoint(actor, halfExtents, getNavigatorFlags(actor), pointTolerance); + mPathFinder.buildPathByNavMeshToNextPoint(actor, halfExtents, getNavigatorFlags(actor)); } if (mObstacleCheck.isEvading()) diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 8154ea995..6e69b6c79 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -126,7 +126,7 @@ namespace MWMechanics bool checkIdle(const MWWorld::Ptr& actor, unsigned short idleSelect); short unsigned getRandomIdle(); void setPathToAnAllowedNode(const MWWorld::Ptr& actor, AiWanderStorage& storage, const ESM::Position& actorPos); - void evadeObstacles(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); + void evadeObstacles(const MWWorld::Ptr& actor, AiWanderStorage& storage); void turnActorToFacePlayer(const osg::Vec3f& actorPosition, const osg::Vec3f& playerPosition, AiWanderStorage& storage); void doPerFrameActionsForState(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); void onIdleStatePerFrameActions(const MWWorld::Ptr& actor, float duration, AiWanderStorage& storage); diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index a7bba5b63..b072f55f8 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -361,7 +361,7 @@ namespace MWMechanics } void PathFinder::buildPathByNavMeshToNextPoint(const MWWorld::ConstPtr& actor, const osg::Vec3f& halfExtents, - const DetourNavigator::Flags flags, const float pointTolerance) + const DetourNavigator::Flags flags) { if (mPath.empty()) return; diff --git a/apps/openmw/mwmechanics/pathfinding.hpp b/apps/openmw/mwmechanics/pathfinding.hpp index 06b4aa10d..cb33471ca 100644 --- a/apps/openmw/mwmechanics/pathfinding.hpp +++ b/apps/openmw/mwmechanics/pathfinding.hpp @@ -97,7 +97,7 @@ namespace MWMechanics const DetourNavigator::Flags flags); void buildPathByNavMeshToNextPoint(const MWWorld::ConstPtr& actor, const osg::Vec3f& halfExtents, - const DetourNavigator::Flags flags, const float pointTolerance); + const DetourNavigator::Flags flags); /// Remove front point if exist and within tolerance void update(const osg::Vec3f& position, const float pointTolerance, const float destinationTolerance); From 38daa83ff6f73defbeeb3c86a4744ca5ba66c796 Mon Sep 17 00:00:00 2001 From: psi29a Date: Sat, 16 May 2020 21:55:14 +0000 Subject: [PATCH 10/45] Merge branch 'ninja' into 'master' Enable Windows Ninja builds See merge request OpenMW/openmw!202 (cherry picked from commit e0b352323226ff11e230f6489e826df332fa681a) c1e673ce Unify path conversion functions fdf0fdbb Fix NMake with MSVC 2019 bdd4a814 Activate MSVC during CMake setup for NMake eae41050 Support sourcing c0d28a0e Warn that MSVC environment will need to be activated bd16ad62 Ninja 7d57e6e2 Support MSVC 2015 3679d329 Check MSVC activated correctly ed4b73b8 Fix post-2015 Visual Studio 4ffa116a Print message when it's necessary instead of when it isn't c6e09461 Add instructions for using VS' non-.sln support d9bb6e63 Activate MSVC later 9ca26358 Create batch script to activate correct MSVC 61df647d Provide scripts to activate selected MSVC in existing shell without kerfuffle --- CI/ActivateMSVC.ps1 | 26 +++++++ CI/activate_msvc.sh | 76 +++++++++++++++++++ CI/before_script.msvc.sh | 153 ++++++++++++++++++++++++++++++++++----- 3 files changed, 236 insertions(+), 19 deletions(-) create mode 100644 CI/ActivateMSVC.ps1 create mode 100644 CI/activate_msvc.sh diff --git a/CI/ActivateMSVC.ps1 b/CI/ActivateMSVC.ps1 new file mode 100644 index 000000000..ca78ef588 --- /dev/null +++ b/CI/ActivateMSVC.ps1 @@ -0,0 +1,26 @@ +& "${env:COMSPEC}" /c ActivateMSVC.bat "&&" set | ForEach-Object { + $name, $value = $_ -split '=', 2 + Set-Content env:\"$name" $value +} + +$MissingTools = $false +$tools = "cl", "link", "rc", "mt", "awooga" +$descriptions = "MSVC Compiler", "MSVC Linker", "MS Windows Resource Compiler", "MS Windows Manifest Tool", "A made up command" +for ($i = 0; $i -lt $tools.Length; $i++) { + $present = $true + try { + Get-Command $tools[$i] *>&1 | Out-Null + $present = $present -and $? + } catch { + $present = $false + } + if (!$present) { + Write-Warning "$($tools[$i]) ($($descriptions[$i])) missing." + $MissingTools = $true + } +} + +if ($MissingTools) { + Write-Error "Some build tools were unavailable after activating MSVC in the shell. It's likely that your Visual Studio $MSVC_DISPLAY_YEAR installation needs repairing." + exit 1 +} \ No newline at end of file diff --git a/CI/activate_msvc.sh b/CI/activate_msvc.sh new file mode 100644 index 000000000..0764cd02f --- /dev/null +++ b/CI/activate_msvc.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +set -euo pipefail + +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + echo "Error: Script not sourced." + echo "You must source this script for it to work, i.e. " + echo "source ./activate_msvc.sh" + echo "or" + echo ". ./activate_msvc.sh" + exit 1 +fi + +command -v unixPathAsWindows >/dev/null 2>&1 || function unixPathAsWindows { + if command -v cygpath >/dev/null 2>&1; then + cygpath -w $1 + else + echo "$1" | sed "s,^/\([^/]\)/,\\1:/," | sed "s,/,\\\\,g" + fi +} + +function windowsSystemPathAsUnix { + if command -v cygpath >/dev/null 2>&1; then + cygpath -u -p $1 + else + IFS=';' read -r -a paths <<< "$1" + declare -a convertedPaths + for entry in paths; do + convertedPaths+=(windowsPathAsUnix $entry) + done + convertedPath=printf ":%s" ${convertedPaths[@]} + echo ${convertedPath:1} + fi +} + +# capture CMD environment so we know what's been changed +declare -A originalCmdEnv +originalIFS="$IFS" +IFS=$'\n\r' +for pair in $(cmd //c "set"); do + IFS='=' read -r -a separatedPair <<< "${pair}" + originalCmdEnv["${separatedPair[0]}"]="${separatedPair[1]}" +done + +# capture CMD environment in a shell with MSVC activated +cmdEnv="$(cmd //c "$(unixPathAsWindows "$(dirname "${BASH_SOURCE[0]}")")\ActivateMSVC.bat" "&&" set)" + +declare -A cmdEnvChanges +for pair in $cmdEnv; do + if [ -n "$pair" ]; then + IFS='=' read -r -a separatedPair <<< "${pair}" + key="${separatedPair[0]}" + value="${separatedPair[1]}" + if ! [ ${originalCmdEnv[$key]+_} ] || [ "${originalCmdEnv[$key]}" != "$value" ]; then + if [ $key != 'PATH' ] && [ $key != 'path' ] && [ $key != 'Path' ]; then + export "$key=$value" + else + export PATH=$(windowsSystemPathAsUnix $value) + fi + fi + fi +done + +MISSINGTOOLS=0 + +command -v cl >/dev/null 2>&1 || { echo "Error: cl (MSVC Compiler) missing."; MISSINGTOOLS=1; } +command -v link >/dev/null 2>&1 || { echo "Error: link (MSVC Linker) missing."; MISSINGTOOLS=1; } +command -v rc >/dev/null 2>&1 || { echo "Error: rc (MS Windows Resource Compiler) missing."; MISSINGTOOLS=1; } +command -v mt >/dev/null 2>&1 || { echo "Error: mt (MS Windows Manifest Tool) missing."; MISSINGTOOLS=1; } + +if [ $MISSINGTOOLS -ne 0 ]; then + echo "Some build tools were unavailable after activating MSVC in the shell. It's likely that your Visual Studio $MSVC_DISPLAY_YEAR installation needs repairing." + return 1 +fi + +IFS="$originalIFS" \ No newline at end of file diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 3a0b062e6..bf115d315 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -1,25 +1,49 @@ #!/bin/bash # set -x # turn-on for debugging +function wrappedExit { + if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + exit $1 + else + return $1 + fi +} + MISSINGTOOLS=0 command -v 7z >/dev/null 2>&1 || { echo "Error: 7z (7zip) is not on the path."; MISSINGTOOLS=1; } command -v cmake >/dev/null 2>&1 || { echo "Error: cmake (CMake) is not on the path."; MISSINGTOOLS=1; } if [ $MISSINGTOOLS -ne 0 ]; then - exit 1 + wrappedExit 1 fi WORKINGDIR="$(pwd)" case "$WORKINGDIR" in *[[:space:]]*) echo "Error: Working directory contains spaces." - exit 1 + wrappedExit 1 ;; esac set -euo pipefail +function windowsPathAsUnix { + if command -v cygpath >/dev/null 2>&1; then + cygpath -u $1 + else + echo "$1" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1," + fi +} + +function unixPathAsWindows { + if command -v cygpath >/dev/null 2>&1; then + cygpath -w $1 + else + echo "$1" | sed "s,^/\([^/]\)/,\\1:/," | sed "s,/,\\\\,g" + fi +} + APPVEYOR=${APPVEYOR:-} CI=${CI:-} STEP=${STEP:-} @@ -32,12 +56,16 @@ KEEP="" UNITY_BUILD="" VS_VERSION="" NMAKE="" +NINJA="" PLATFORM="" CONFIGURATION="" TEST_FRAMEWORK="" GOOGLE_INSTALL_ROOT="" INSTALL_PREFIX="." +ACTIVATE_MSVC="" +SINGLE_CONFIG="" + while [ $# -gt 0 ]; do ARGSTR=$1 shift @@ -45,7 +73,7 @@ while [ $# -gt 0 ]; do if [ ${ARGSTR:0:1} != "-" ]; then echo "Unknown argument $ARGSTR" echo "Try '$0 -h'" - exit 1 + wrappedExit 1 fi for (( i=1; i<${#ARGSTR}; i++ )); do @@ -72,6 +100,9 @@ while [ $# -gt 0 ]; do n ) NMAKE=true ;; + + N ) + NINJA=true ;; p ) PLATFORM=$1 @@ -111,25 +142,31 @@ Options: -v <2013/2015/2017/2019> Choose the Visual Studio version to use. -n - Produce NMake makefiles instead of a Visual Studio solution. + Produce NMake makefiles instead of a Visual Studio solution. Cannout be used with -N. + -N + Produce Ninja (multi-config if CMake is new enough to support it) files instead of a Visual Studio solution. Cannot be used with -n. -V Run verbosely -i CMake install prefix EOF - exit 0 + wrappedExit 0 ;; * ) echo "Unknown argument $ARG." echo "Try '$0 -h'" - exit 1 ;; + wrappedExit 1 ;; esac done done -if [ -n "$NMAKE" ]; then - command -v nmake -? >/dev/null 2>&1 || { echo "Error: nmake (NMake) is not on the path. Make sure you have the necessary environment variables set for command-line C++ development (for example, by starting from a Developer Command Prompt)."; exit 1; } +if [ -n "$NMAKE" ] || [ -n "$NINJA" ]; then + if [ -n "$NMAKE" ] && [ -n "$NINJA" ]; then + echo "Cannout run in NMake and Ninja mode at the same time." + wrappedExit 1 + fi + ACTIVATE_MSVC=true fi if [ -z $VERBOSE ]; then @@ -139,7 +176,7 @@ fi if [ -z $APPVEYOR ]; then echo "Running prebuild outside of Appveyor." - DIR=$(echo "$0" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,") + DIR=$(windowsPathAsUnix "${BASH_SOURCE[0]}") cd $(dirname "$DIR")/.. else echo "Running prebuild in Appveyor." @@ -322,7 +359,7 @@ case $PLATFORM in * ) echo "Unknown platform $PLATFORM." - exit 1 + wrappedExit 1 ;; esac @@ -349,9 +386,18 @@ fi if [ -n "$NMAKE" ]; then GENERATOR="NMake Makefiles" + SINGLE_CONFIG=true fi -if [ $MSVC_REAL_VER -ge 16 ]; then +if [ -n "$NINJA" ]; then + GENERATOR="Ninja Multi-Config" + if ! cmake -E capabilities | grep -F "$GENERATOR" > /dev/null; then + SINGLE_CONFIG=true + GENERATOR="Ninja" + fi +fi + +if [ $MSVC_REAL_VER -ge 16 ] && [ -z "$NMAKE" ] && [ -z "$NINJA" ]; then if [ $BITS -eq 64 ]; then add_cmake_opts "-G\"$GENERATOR\" -A x64" else @@ -361,7 +407,7 @@ else add_cmake_opts "-G\"$GENERATOR\"" fi -if [ -n "$NMAKE" ]; then +if [ -n "$SINGLE_CONFIG" ]; then add_cmake_opts "-DCMAKE_BUILD_TYPE=${BUILD_CONFIG}" fi @@ -456,7 +502,13 @@ cd .. #/.. BUILD_DIR="MSVC${MSVC_DISPLAY_YEAR}_${BITS}" if [ -n "$NMAKE" ]; then - BUILD_DIR="${BUILD_DIR}_NMake_${BUILD_CONFIG}" + BUILD_DIR="${BUILD_DIR}_NMake" +elif [ -n "$NINJA" ]; then + BUILD_DIR="${BUILD_DIR}_Ninja" +fi + +if [ -n "$SINGLE_CONFIG" ]; then + BUILD_DIR="${BUILD_DIR}_${BUILD_CONFIG}" fi if [ -z $KEEP ]; then @@ -494,10 +546,10 @@ fi # We work around this by installing to root of the current working drive and then move it to our deps # get the current working drive's root, we'll install to that temporarily CWD_DRIVE_ROOT="$(powershell -command '(get-location).Drive.Root')Boost_temp" - CWD_DRIVE_ROOT_BASH=$(echo "$CWD_DRIVE_ROOT" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,") + CWD_DRIVE_ROOT_BASH=$(windowsPathAsUnix "$CWD_DRIVE_ROOT") if [ -d CWD_DRIVE_ROOT_BASH ]; then printf "Cannot continue, ${CWD_DRIVE_ROOT_BASH} aka ${CWD_DRIVE_ROOT} already exists. Please remove before re-running. "; - exit 1; + wrappedExit 1; fi if [ -d ${BOOST_SDK} ] && grep "BOOST_VERSION ${BOOST_VER_SDK}" Boost/boost/version.hpp > /dev/null; then @@ -695,7 +747,7 @@ fi else SUFFIX="" fi - DIR=$(echo "${QT_SDK}" | sed "s,\\\\,/,g" | sed "s,\(.\):,/\\1,") + DIR=$(windowsPathAsUnix "${QT_SDK}") add_runtime_dlls "${DIR}/bin/Qt5"{Core,Gui,Network,OpenGL,Widgets}${SUFFIX}.dll add_qt_platform_dlls "${DIR}/plugins/platforms/qwindows${SUFFIX}.dll" echo Done. @@ -806,14 +858,15 @@ fi #if [ -z $CI ]; then echo "- Copying Runtime DLLs..." DLL_PREFIX="" - if [ -z $NMAKE ]; then + if [ -z $SINGLE_CONFIG ]; then mkdir -p $BUILD_CONFIG DLL_PREFIX="$BUILD_CONFIG/" fi for DLL in $RUNTIME_DLLS; do TARGET="$(basename "$DLL")" if [[ "$DLL" == *":"* ]]; then - IFS=':'; SPLIT=( ${DLL} ); unset IFS + originalIFS="$IFS" + IFS=':'; SPLIT=( ${DLL} ); IFS=$originalIFS DLL=${SPLIT[0]} TARGET=${SPLIT[1]} fi @@ -836,6 +889,42 @@ fi done echo #fi + +if ! [ -z $ACTIVATE_MSVC ]; then + echo -n "- Activating MSVC in the current shell... " + command -v vswhere >/dev/null 2>&1 || { echo "Error: vswhere is not on the path."; wrappedExit 1; } + + MSVC_INSTALLATION_PATH=$(vswhere -legacy -version "[$MSVC_VER,$(awk "BEGIN { print $MSVC_REAL_VER + 1; exit }"))" -property installationPath) + if [ $MSVC_REAL_VER -ge 15 ]; then + echo "@\"${MSVC_INSTALLATION_PATH}\Common7\Tools\VsDevCmd.bat\" -no_logo -arch=$([ $BITS -eq 64 ] && echo "amd64" || echo "x86") -host_arch=$([ $(uname -m) == 'x86_64' ] && echo "amd64" || echo "x86")" > ActivateMSVC.bat + else + if [ $(uname -m) == 'x86_64' ]; then + if [ $BITS -eq 64 ]; then + compiler=amd64 + else + compiler=amd64_x86 + fi + else + if [ $BITS -eq 64 ]; then + compiler=x86_amd64 + else + compiler=x86 + fi + fi + echo "@\"${MSVC_INSTALLATION_PATH}\VC\vcvarsall.bat\" $compiler" > ActivateMSVC.bat + fi + + cp "../CI/activate_msvc.sh" . + sed -i "s/\$MSVC_DISPLAY_YEAR/$MSVC_DISPLAY_YEAR/g" activate_msvc.sh + source ./activate_msvc.sh + + cp "../CI/ActivateMSVC.ps1" . + sed -i "s/\$MSVC_DISPLAY_YEAR/$MSVC_DISPLAY_YEAR/g" ActivateMSVC.ps1 + + echo "done." + echo +fi + if [ -z $VERBOSE ]; then printf -- "- Configuring... " else @@ -846,8 +935,34 @@ RET=$? if [ -z $VERBOSE ]; then if [ $RET -eq 0 ]; then echo Done. + if [ -n $ACTIVATE_MSVC ]; then + echo + echo "Note: you must manually activate MSVC for the shell in which you want to do the build." + echo + echo "Some scripts have been created in the build directory to do so in an existing shell." + echo "Bash: source activate_msvc.sh" + echo "CMD: ActivateMSVC.bat" + echo "PowerShell: ActivateMSVC.ps1" + echo + echo "You may find options to launch a Development/Native Tools/Cross Tools shell in your start menu or Visual Studio." + echo + if [ $(uname -m) == 'x86_64' ]; then + if [ $BITS -eq 64 ]; then + inheritEnvironments=msvc_x64_x64 + else + inheritEnvironments=msvc_x64 + fi + else + if [ $BITS -eq 64 ]; then + inheritEnvironments=msvc_x86_x64 + else + inheritEnvironments=msvc_x86 + fi + fi + echo "In Visual Studio 15.3 (2017 Update 3) or later, try setting '\"inheritEnvironments\": [ \"$inheritEnvironments\" ]' in CMakeSettings.json to build in the IDE." + fi else echo Failed. fi fi -exit $RET +wrappedExit $RET From 7b781d88909214120ae2f5655e12d68cbc08ec2c Mon Sep 17 00:00:00 2001 From: "Alexander \"Ananace\" Olofsson" Date: Sun, 17 May 2020 01:12:04 +0200 Subject: [PATCH 11/45] Windows CI dependency upgrade (#2847) * Windows CI: Use OSG 3.4-experimental for 0.46 * Update compiled Windows CI dependencies Only built and pushed so far, still need to try making full OpenMW builds with them as well. * Update missed Bullet version number * MyGUI uses RelWithDebInfo for Release builds now * Update Windows CI dependencies, switch Qt install * Fix aqt retrieval and setup * Make aqt install output slightly nicer * Bump to Qt 5.15 for VS2019 support * Fix FFmpeg and Qt install parts * Fix OSG plugin DLL copying * Add CMake flag for double-precision bullet * Roll back 2019 to Boost 1.71 for CI * Move aqt into unpack step, to allow manual install --- CI/before_script.msvc.sh | 211 ++++++++++++++++++++++++--------------- 1 file changed, 132 insertions(+), 79 deletions(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 3a0b062e6..c1786889a 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -5,6 +5,7 @@ MISSINGTOOLS=0 command -v 7z >/dev/null 2>&1 || { echo "Error: 7z (7zip) is not on the path."; MISSINGTOOLS=1; } command -v cmake >/dev/null 2>&1 || { echo "Error: cmake (CMake) is not on the path."; MISSINGTOOLS=1; } +command -v python >/dev/null 2>&1 || { echo "Warning: Python is not on the path, automatic Qt installation impossible."; } if [ $MISSINGTOOLS -ne 0 ]; then exit 1 @@ -32,11 +33,15 @@ KEEP="" UNITY_BUILD="" VS_VERSION="" NMAKE="" +PDBS="" PLATFORM="" CONFIGURATION="" TEST_FRAMEWORK="" GOOGLE_INSTALL_ROOT="" INSTALL_PREFIX="." +BULLET_DOUBLE="" +BULLET_DBL="" +BULLET_DBL_DISPLAY="Single precision" while [ $# -gt 0 ]; do ARGSTR=$1 @@ -57,6 +62,9 @@ while [ $# -gt 0 ]; do d ) SKIP_DOWNLOAD=true ;; + D ) + BULLET_DOUBLE=true ;; + e ) SKIP_EXTRACT=true ;; @@ -77,6 +85,9 @@ while [ $# -gt 0 ]; do PLATFORM=$1 shift ;; + P ) + PDBS=true ;; + c ) CONFIGURATION=$1 shift ;; @@ -96,6 +107,8 @@ Options: Set the configuration, can also be set with environment variable CONFIGURATION. -d Skip checking the downloads. + -D + Use double-precision Bullet -e Skip extracting dependencies. -h @@ -112,6 +125,8 @@ Options: Choose the Visual Studio version to use. -n Produce NMake makefiles instead of a Visual Studio solution. + -P + Download debug symbols where available -V Run verbosely -i @@ -264,6 +279,7 @@ case $VS_VERSION in MSVC_REAL_VER="16" MSVC_VER="14.2" MSVC_YEAR="2015" + MSVC_REAL_YEAR="2019" MSVC_DISPLAY_YEAR="2019" BOOST_VER="1.71.0" BOOST_VER_URL="1_71_0" @@ -276,6 +292,7 @@ case $VS_VERSION in MSVC_REAL_VER="15" MSVC_VER="14.1" MSVC_YEAR="2015" + MSVC_REAL_YEAR="2017" MSVC_DISPLAY_YEAR="2017" BOOST_VER="1.67.0" BOOST_VER_URL="1_67_0" @@ -288,6 +305,7 @@ case $VS_VERSION in MSVC_REAL_VER="14" MSVC_VER="14.0" MSVC_YEAR="2015" + MSVC_REAL_YEAR="2015" MSVC_DISPLAY_YEAR="2015" BOOST_VER="1.67.0" BOOST_VER_URL="1_67_0" @@ -295,15 +313,8 @@ case $VS_VERSION in ;; 12|12.0|2013 ) - GENERATOR="Visual Studio 12 2013" - TOOLSET="vc120" - MSVC_REAL_VER="12" - MSVC_VER="12.0" - MSVC_YEAR="2013" - MSVC_DISPLAY_YEAR="2013" - BOOST_VER="1.58.0" - BOOST_VER_URL="1_58_0" - BOOST_VER_SDK="105800" + echo "Visual Studio 2013 is no longer supported" + exit 1 ;; esac @@ -369,6 +380,12 @@ if ! [ -z $UNITY_BUILD ]; then add_cmake_opts "-DOPENMW_UNITY_BUILD=True" fi +if [ -n "$BULLET_DOUBLE" ]; then + BULLET_DBL="-double" + BULLET_DBL_DISPLAY="Double precision" + add_cmake_opts "-DBULLET_USE_DOUBLES=True" +fi + echo echo "===================================" echo "Starting prebuild on MSVC${MSVC_DISPLAY_YEAR} WIN${BITS}" @@ -393,45 +410,54 @@ if [ -z $SKIP_DOWNLOAD ]; then fi # Bullet - download "Bullet 2.87" \ - "https://www.lysator.liu.se/~ace/OpenMW/deps/Bullet-2.87-msvc${MSVC_YEAR}-win${BITS}.7z" \ - "Bullet-2.87-msvc${MSVC_YEAR}-win${BITS}.7z" + download "Bullet 2.89 (${BULLET_DBL_DISPLAY})" \ + "https://rgw.ctrl-c.liu.se/openmw/Deps/Bullet-2.89-msvc${MSVC_YEAR}-win${BITS}${BULLET_DBL}.7z" \ + "Bullet-2.89-msvc${MSVC_YEAR}-win${BITS}${BULLET_DBL}.7z" # FFmpeg - download "FFmpeg 3.2.4" \ - "https://ffmpeg.zeranoe.com/builds/win${BITS}/shared/ffmpeg-3.2.4-win${BITS}-shared.zip" \ - "ffmpeg-3.2.4-win${BITS}.zip" \ - "https://ffmpeg.zeranoe.com/builds/win${BITS}/dev/ffmpeg-3.2.4-win${BITS}-dev.zip" \ - "ffmpeg-3.2.4-dev-win${BITS}.zip" + download "FFmpeg 4.2.2" \ + "https://ffmpeg.zeranoe.com/builds/win${BITS}/shared/ffmpeg-4.2.2-win${BITS}-shared.zip" \ + "ffmpeg-4.2.2-win${BITS}.zip" \ + "https://ffmpeg.zeranoe.com/builds/win${BITS}/dev/ffmpeg-4.2.2-win${BITS}-dev.zip" \ + "ffmpeg-4.2.2-dev-win${BITS}.zip" # MyGUI - download "MyGUI 3.2.2" \ - "https://www.lysator.liu.se/~ace/OpenMW/deps/MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" \ - "MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" + download "MyGUI 3.4.0" \ + "https://rgw.ctrl-c.liu.se/openmw/Deps/MyGUI-3.4.0-msvc${MSVC_REAL_YEAR}-win${BITS}.7z" \ + "MyGUI-3.4.0-msvc${MSVC_REAL_YEAR}-win${BITS}.7z" + + if [ -n "$PDBS" ]; then + download "MyGUI symbols" \ + "https://rgw.ctrl-c.liu.se/openmw/Deps/MyGUI-3.4.0-msvc${MSVC_REAL_YEAR}-win${BITS}-sym.7z" \ + "MyGUI-3.4.0-msvc${MSVC_REAL_YEAR}-win${BITS}-sym.7z" + fi # OpenAL - download "OpenAL-Soft 1.19.1" \ - "http://openal-soft.org/openal-binaries/openal-soft-1.19.1-bin.zip" \ - "OpenAL-Soft-1.19.1.zip" + download "OpenAL-Soft 1.20.1" \ + "http://openal-soft.org/openal-binaries/openal-soft-1.20.1-bin.zip" \ + "OpenAL-Soft-1.20.1.zip" # OSG - download "OpenSceneGraph 3.4.1-scrawl" \ - "https://www.lysator.liu.se/~ace/OpenMW/deps/OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" \ - "OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" + download "OpenSceneGraph 3.6.5" \ + "https://rgw.ctrl-c.liu.se/openmw/Deps/OSG-3.6.5-msvc${MSVC_REAL_YEAR}-win${BITS}.7z" \ + "OSG-3.6.5-msvc${MSVC_REAL_YEAR}-win${BITS}.7z" + + if [ -n "$PDBS" ]; then + download "OpenSceneGraph symbols" \ + "https://rgw.ctrl-c.liu.se/openmw/Deps/OSG-3.6.5-msvc${MSVC_REAL_YEAR}-win${BITS}-sym.7z" \ + "OSG-3.6.5-msvc${MSVC_REAL_YEAR}-win${BITS}-sym.7z" + fi # Qt if [ -z $APPVEYOR ]; then - if [ $BITS == "64" ]; then - QT_SUFFIX="_64" - else - QT_SUFFIX="" + if [ "${MSVC_REAL_YEAR}" = "2015" ] && [ "${BITS}" = "32" ]; then + echo "Qt no longer provides MSVC2015 Win32 packages, switch to 64-bit or a newer Visual Studio. Sorry." + exit 1 fi - download "Qt 5.7.0" \ - "https://download.qt.io/new_archive/qt/5.7/5.7.0/qt-opensource-windows-x86-msvc${MSVC_YEAR}${QT_SUFFIX}-5.7.0.exe" \ - "qt-5.7.0-msvc${MSVC_YEAR}-win${BITS}.exe" \ - "https://www.lysator.liu.se/~ace/OpenMW/deps/qt-5-install.qs" \ - "qt-5-install.qs" + download "AQt installer" \ + "https://files.pythonhosted.org/packages/f3/bb/aee972f08deecca31bfc46b5aedfad1ce6c7f3aaf1288d685e4a914b53ac/aqtinstall-0.8-py2.py3-none-any.whl" \ + "aqtinstall-0.8-py2.py3-none-any.whl" fi # SDL2 @@ -533,15 +559,15 @@ fi cd $DEPS echo # Bullet -printf "Bullet 2.87... " +printf "Bullet 2.89 (${BULLET_DBL_DISPLAY})... " { cd $DEPS_INSTALL if [ -d Bullet ]; then printf -- "Exists. (No version checking) " elif [ -z $SKIP_EXTRACT ]; then rm -rf Bullet - eval 7z x -y "${DEPS}/Bullet-2.87-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP - mv "Bullet-2.87-msvc${MSVC_YEAR}-win${BITS}" Bullet + eval 7z x -y "${DEPS}/Bullet-2.89-msvc${MSVC_YEAR}-win${BITS}${BULLET_DBL}.7z" $STRIP + mv "Bullet-2.89-msvc${MSVC_YEAR}-win${BITS}${BULLET_DBL}" Bullet fi export BULLET_ROOT="$(real_pwd)/Bullet" echo Done. @@ -549,21 +575,21 @@ printf "Bullet 2.87... " cd $DEPS echo # FFmpeg -printf "FFmpeg 3.2.4... " +printf "FFmpeg 4.2.2... " { cd $DEPS_INSTALL - if [ -d FFmpeg ] && grep "FFmpeg version: 3.2.4" FFmpeg/README.txt > /dev/null; then + if [ -d FFmpeg ] && grep "4.2.2" FFmpeg/README.txt > /dev/null; then printf "Exists. " elif [ -z $SKIP_EXTRACT ]; then rm -rf FFmpeg - eval 7z x -y "${DEPS}/ffmpeg-3.2.4-win${BITS}.zip" $STRIP - eval 7z x -y "${DEPS}/ffmpeg-3.2.4-dev-win${BITS}.zip" $STRIP - mv "ffmpeg-3.2.4-win${BITS}-shared" FFmpeg - cp -r "ffmpeg-3.2.4-win${BITS}-dev/"* FFmpeg/ - rm -rf "ffmpeg-3.2.4-win${BITS}-dev" + eval 7z x -y "${DEPS}/ffmpeg-4.2.2-win${BITS}.zip" $STRIP + eval 7z x -y "${DEPS}/ffmpeg-4.2.2-dev-win${BITS}.zip" $STRIP + mv "ffmpeg-4.2.2-win${BITS}-shared" FFmpeg + cp -r "ffmpeg-4.2.2-win${BITS}-dev/"* FFmpeg/ + rm -rf "ffmpeg-4.2.2-win${BITS}-dev" fi export FFMPEG_HOME="$(real_pwd)/FFmpeg" - add_runtime_dlls "$(pwd)/FFmpeg/bin/"{avcodec-57,avformat-57,avutil-55,swresample-2,swscale-4}.dll + add_runtime_dlls "$(pwd)/FFmpeg/bin/"{avcodec-58,avformat-58,avutil-56,swresample-3,swscale-5}.dll if [ $BITS -eq 32 ]; then add_cmake_opts "-DCMAKE_EXE_LINKER_FLAGS=\"/machine:X86 /safeseh:no\"" fi @@ -572,62 +598,66 @@ printf "FFmpeg 3.2.4... " cd $DEPS echo # MyGUI -printf "MyGUI 3.2.2... " +printf "MyGUI 3.4.0... " { cd $DEPS_INSTALL if [ -d MyGUI ] && \ grep "MYGUI_VERSION_MAJOR 3" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \ - grep "MYGUI_VERSION_MINOR 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \ - grep "MYGUI_VERSION_PATCH 2" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null + grep "MYGUI_VERSION_MINOR 4" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null && \ + grep "MYGUI_VERSION_PATCH 0" MyGUI/include/MYGUI/MyGUI_Prerequest.h > /dev/null then printf "Exists. " elif [ -z $SKIP_EXTRACT ]; then rm -rf MyGUI - eval 7z x -y "${DEPS}/MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP - mv "MyGUI-3.2.2-msvc${MSVC_YEAR}-win${BITS}" MyGUI + eval 7z x -y "${DEPS}/MyGUI-3.4.0-msvc${MSVC_REAL_YEAR}-win${BITS}.7z" $STRIP + [ -n "$PDBS" ] && eval 7z x -y "${DEPS}/MyGUI-3.4.0-msvc${MSVC_REAL_YEAR}-win${BITS}-sym.7z" $STRIP + mv "MyGUI-3.4.0-msvc${MSVC_REAL_YEAR}-win${BITS}" MyGUI fi export MYGUI_HOME="$(real_pwd)/MyGUI" if [ $CONFIGURATION == "Debug" ]; then SUFFIX="_d" + MYGUI_CONFIGURATION="Debug" else SUFFIX="" + MYGUI_CONFIGURATION="RelWithDebInfo" fi - add_runtime_dlls "$(pwd)/MyGUI/bin/${CONFIGURATION}/MyGUIEngine${SUFFIX}.dll" + add_runtime_dlls "$(pwd)/MyGUI/bin/${MYGUI_CONFIGURATION}/MyGUIEngine${SUFFIX}.dll" echo Done. } cd $DEPS echo # OpenAL -printf "OpenAL-Soft 1.19.1... " +printf "OpenAL-Soft 1.20.1... " { - if [ -d openal-soft-1.19.1-bin ]; then + if [ -d openal-soft-1.20.1-bin ]; then printf "Exists. " elif [ -z $SKIP_EXTRACT ]; then - rm -rf openal-soft-1.19.1-bin - eval 7z x -y OpenAL-Soft-1.19.1.zip $STRIP + rm -rf openal-soft-1.20.1-bin + eval 7z x -y OpenAL-Soft-1.20.1.zip $STRIP fi - OPENAL_SDK="$(real_pwd)/openal-soft-1.19.1-bin" + OPENAL_SDK="$(real_pwd)/openal-soft-1.20.1-bin" add_cmake_opts -DOPENAL_INCLUDE_DIR="${OPENAL_SDK}/include/AL" \ -DOPENAL_LIBRARY="${OPENAL_SDK}/libs/Win${BITS}/OpenAL32.lib" - add_runtime_dlls "$(pwd)/openal-soft-1.19.1-bin/bin/WIN${BITS}/soft_oal.dll:OpenAL32.dll" + add_runtime_dlls "$(pwd)/openal-soft-1.20.1-bin/bin/WIN${BITS}/soft_oal.dll:OpenAL32.dll" echo Done. } cd $DEPS echo # OSG -printf "OSG 3.4.1-scrawl... " +printf "OSG 3.6.5... " { cd $DEPS_INSTALL if [ -d OSG ] && \ grep "OPENSCENEGRAPH_MAJOR_VERSION 3" OSG/include/osg/Version > /dev/null && \ - grep "OPENSCENEGRAPH_MINOR_VERSION 4" OSG/include/osg/Version > /dev/null && \ - grep "OPENSCENEGRAPH_PATCH_VERSION 1" OSG/include/osg/Version > /dev/null + grep "OPENSCENEGRAPH_MINOR_VERSION 6" OSG/include/osg/Version > /dev/null && \ + grep "OPENSCENEGRAPH_PATCH_VERSION 5" OSG/include/osg/Version > /dev/null then printf "Exists. " elif [ -z $SKIP_EXTRACT ]; then rm -rf OSG - eval 7z x -y "${DEPS}/OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}.7z" $STRIP - mv "OSG-3.4.1-scrawl-msvc${MSVC_YEAR}-win${BITS}" OSG + eval 7z x -y "${DEPS}/OSG-3.6.5-msvc${MSVC_REAL_YEAR}-win${BITS}.7z" $STRIP + [ -n "$PDBS" ] && eval 7z x -y "${DEPS}/OSG-3.6.5-msvc${MSVC_REAL_YEAR}-win${BITS}-sym.7z" $STRIP + mv "OSG-3.6.5-msvc${MSVC_REAL_YEAR}-win${BITS}" OSG fi OSG_SDK="$(real_pwd)/OSG" add_cmake_opts -DOSG_DIR="$OSG_SDK" @@ -636,17 +666,17 @@ printf "OSG 3.4.1-scrawl... " else SUFFIX="" fi - add_runtime_dlls "$(pwd)/OSG/bin/"{OpenThreads,zlib,libpng*}${SUFFIX}.dll \ + add_runtime_dlls "$(pwd)/OSG/bin/"{OpenThreads,zlib,libpng}${SUFFIX}.dll \ "$(pwd)/OSG/bin/osg"{,Animation,DB,FX,GA,Particle,Text,Util,Viewer,Shadow}${SUFFIX}.dll - add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_"{bmp,dds,freetype,jpeg,osg,png,tga}${SUFFIX}.dll - add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.4.1/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer,shadow}${SUFFIX}.dll + add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.6.5/osgdb_"{bmp,dds,freetype,jpeg,osg,png,tga}${SUFFIX}.dll + add_osg_dlls "$(pwd)/OSG/bin/osgPlugins-3.6.5/osgdb_serializers_osg"{,animation,fx,ga,particle,text,util,viewer,shadow}${SUFFIX}.dll echo Done. } cd $DEPS echo # Qt if [ -z $APPVEYOR ]; then - printf "Qt 5.7.0... " + printf "Qt 5.15.0... " else printf "Qt 5.13 AppVeyor... " fi @@ -658,21 +688,44 @@ fi fi if [ -z $APPVEYOR ]; then cd $DEPS_INSTALL - QT_SDK="$(real_pwd)/Qt/5.7/msvc${MSVC_YEAR}${SUFFIX}" - if [ -d Qt ] && head -n2 Qt/InstallationLog.txt | grep "5.7.0" > /dev/null; then + QT_SDK="$(real_pwd)/Qt/5.15.0/msvc${MSVC_YEAR}${SUFFIX}" + + if [ -d 'Qt/5.15.0' ]; then printf "Exists. " elif [ -z $SKIP_EXTRACT ]; then + pushd "$DEPS" > /dev/null + if ! [ -d 'aqt-venv' ]; then + echo " Creating Virtualenv for aqt..." + eval python -m venv aqt-venv $STRIP + fi + if [ -d 'aqt-venv/bin' ]; then + VENV_BIN_DIR='bin' + elif [ -d 'aqt-venv/Scripts' ]; then + VENV_BIN_DIR='Scripts' + else + echo "Error: Failed to create virtualenv." + exit 1 + fi + + if ! [ -e "aqt-venv/${VENV_BIN_DIR}/aqt" ]; then + echo " Installing aqt wheel into virtualenv..." + eval "aqt-venv/${VENV_BIN_DIR}/pip" install aqtinstall-0.8-py2.py3-none-any.whl $STRIP + fi + popd > /dev/null + rm -rf Qt - cp "${DEPS}/qt-5-install.qs" qt-install.qs - sed -i "s|INSTALL_DIR|$(real_pwd)/Qt|" qt-install.qs - sed -i "s/qt.VERSION.winBITS_msvcYEAR/qt.57.win${BITS}_msvc${MSVC_YEAR}${SUFFIX}/" qt-install.qs - printf -- "(Installation might take a while) " - "${DEPS}/qt-5.7.0-msvc${MSVC_YEAR}-win${BITS}.exe" --script qt-install.qs --silent - mv qt-install.qs Qt/ - echo Done. + + mkdir Qt + cd Qt + + eval "${DEPS}/aqt-venv/${VENV_BIN_DIR}/aqt" install 5.15.0 windows desktop "win${BITS}_msvc${MSVC_REAL_YEAR}${SUFFIX}" $STRIP + printf " Cleaning up extraneous data... " - rm -r "$(real_pwd)/Qt/"{dist,Docs,Examples,Tools,vcredist,components.xml,MaintenanceTool.dat,MaintenanceTool.exe,MaintenanceTool.ini,network.xml,qt-install.qs} + rm -rf Qt/{aqtinstall.log,Tools} + + echo Done. fi + cd $QT_SDK add_cmake_opts -DDESIRED_QT_VERSION=5 \ -DQT_QMAKE_EXECUTABLE="${QT_SDK}/bin/qmake.exe" \ @@ -822,10 +875,10 @@ fi done echo echo "- OSG Plugin DLLs..." - mkdir -p ${DLL_PREFIX}osgPlugins-3.4.1 + mkdir -p ${DLL_PREFIX}osgPlugins-3.6.5 for DLL in $OSG_PLUGINS; do echo " $(basename $DLL)." - cp "$DLL" ${DLL_PREFIX}osgPlugins-3.4.1 + cp "$DLL" ${DLL_PREFIX}osgPlugins-3.6.5 done echo echo "- Qt Platform DLLs..." From 2e09e96f5df38dd149b69713b94df531226d37b4 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 17 May 2020 15:19:07 +0200 Subject: [PATCH 12/45] Fix msvc dir for Qt Otherwise it fails with: Qt 5.15.0... Exists. CI/before_script.msvc.sh: line 781: cd: MSVC2019_64_Ninja/deps/Qt/5.15.0/msvc2015_64: No such file or directory --- CI/before_script.msvc.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/before_script.msvc.sh b/CI/before_script.msvc.sh index 3da7eb0f9..2f40aef9c 100644 --- a/CI/before_script.msvc.sh +++ b/CI/before_script.msvc.sh @@ -740,7 +740,7 @@ fi fi if [ -z $APPVEYOR ]; then cd $DEPS_INSTALL - QT_SDK="$(real_pwd)/Qt/5.15.0/msvc${MSVC_YEAR}${SUFFIX}" + QT_SDK="$(real_pwd)/Qt/5.15.0/msvc${MSVC_REAL_YEAR}${SUFFIX}" if [ -d 'Qt/5.15.0' ]; then printf "Exists. " From e3cce0949e4fb4e97d423b81b8d7d933cbe8eb93 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 17 May 2020 17:24:47 +0200 Subject: [PATCH 13/45] Replace condition that may lead to UB by assert If mPackages is empty it means package is a pointer to a deleted object at line . We can assume it couldn't happen because execute is always called next for this object at line 289. --- apps/openmw/mwmechanics/aisequence.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 5f3931fcf..201701634 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -265,16 +265,15 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac } } - if (!mPackages.empty()) - { - if (nearestDist < std::numeric_limits::max() && mPackages.begin() != itActualCombat) - { - // move combat package with nearest target to the front - mPackages.splice(mPackages.begin(), mPackages, itActualCombat); - } + assert(!mPackages.empty()); - package = mPackages.front(); + if (nearestDist < std::numeric_limits::max() && mPackages.begin() != itActualCombat) + { + // move combat package with nearest target to the front + mPackages.splice(mPackages.begin(), mPackages, itActualCombat); } + + package = mPackages.front(); } try From ca93f8ee39483cfb3fd4ee3f55527a65373a2b70 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 17 May 2020 17:38:10 +0200 Subject: [PATCH 14/45] Compare initialized iterator Comparsion of untilialized iterator is UB. Initialize with packages end. --- apps/openmw/mwmechanics/aisequence.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 201701634..269468090 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -223,7 +223,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac // if active package is combat one, choose nearest target if (packageTypeId == AiPackage::TypeIdCombat) { - std::list::iterator itActualCombat; + auto itActualCombat = mPackages.end(); float nearestDist = std::numeric_limits::max(); osg::Vec3f vActorPos = actor.getRefData().getPosition().asVec3(); @@ -269,6 +269,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac if (nearestDist < std::numeric_limits::max() && mPackages.begin() != itActualCombat) { + assert(itActualCombat != mPackages.end()); // move combat package with nearest target to the front mPackages.splice(mPackages.begin(), mPackages, itActualCombat); } From 3b5ce71d71fafb3a4a1d49b79ac209fae38bafd8 Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 16 May 2020 19:05:52 +0200 Subject: [PATCH 15/45] Remove redundant explicit dtor definition for AiPackage --- apps/openmw/mwmechanics/aipackage.cpp | 2 -- apps/openmw/mwmechanics/aipackage.hpp | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 114e011ce..dca882a3b 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -24,8 +24,6 @@ #include -MWMechanics::AiPackage::~AiPackage() {} - MWMechanics::AiPackage::AiPackage() : mTimer(AI_REACTION_TIME + 1.0f), // to force initial pathbuild mTargetActorRefId(""), diff --git a/apps/openmw/mwmechanics/aipackage.hpp b/apps/openmw/mwmechanics/aipackage.hpp index ec0715e52..a09362baa 100644 --- a/apps/openmw/mwmechanics/aipackage.hpp +++ b/apps/openmw/mwmechanics/aipackage.hpp @@ -56,8 +56,7 @@ namespace MWMechanics ///Default constructor AiPackage(); - ///Default Deconstructor - virtual ~AiPackage(); + virtual ~AiPackage() = default; ///Clones the package virtual AiPackage *clone() const = 0; From f566ab03ab253f396de906d0bf55f39e038546eb Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 16 May 2020 18:56:02 +0200 Subject: [PATCH 16/45] Mark overriden AiPackage methods as final --- apps/openmw/mwmechanics/aiactivate.hpp | 10 +++++----- apps/openmw/mwmechanics/aiavoiddoor.hpp | 14 +++++++------- apps/openmw/mwmechanics/aibreathe.hpp | 14 +++++++------- apps/openmw/mwmechanics/aicast.hpp | 16 ++++++++-------- apps/openmw/mwmechanics/aicombat.hpp | 18 +++++++++--------- apps/openmw/mwmechanics/aiescort.hpp | 18 +++++++++--------- apps/openmw/mwmechanics/aiface.hpp | 14 +++++++------- apps/openmw/mwmechanics/aifollow.hpp | 22 +++++++++++----------- apps/openmw/mwmechanics/aipursue.hpp | 16 ++++++++-------- apps/openmw/mwmechanics/aitravel.hpp | 18 +++++++++--------- apps/openmw/mwmechanics/aiwander.hpp | 20 ++++++++++---------- 11 files changed, 90 insertions(+), 90 deletions(-) diff --git a/apps/openmw/mwmechanics/aiactivate.hpp b/apps/openmw/mwmechanics/aiactivate.hpp index 8de4be69f..4cc9f3036 100644 --- a/apps/openmw/mwmechanics/aiactivate.hpp +++ b/apps/openmw/mwmechanics/aiactivate.hpp @@ -19,7 +19,7 @@ namespace MWMechanics { /// \brief Causes actor to walk to activatable object and activate it /** Will activate when close to object **/ - class AiActivate : public AiPackage + class AiActivate final : public AiPackage { public: /// Constructor @@ -28,11 +28,11 @@ namespace MWMechanics AiActivate(const ESM::AiSequence::AiActivate* activate); - virtual AiActivate *clone() const; - virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); - virtual int getTypeId() const; + AiActivate *clone() const final; + bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; + int getTypeId() const final; - virtual void writeState(ESM::AiSequence::AiSequence& sequence) const; + void writeState(ESM::AiSequence::AiSequence& sequence) const final; private: std::string mObjectId; diff --git a/apps/openmw/mwmechanics/aiavoiddoor.hpp b/apps/openmw/mwmechanics/aiavoiddoor.hpp index 4c8be29eb..39a78192b 100644 --- a/apps/openmw/mwmechanics/aiavoiddoor.hpp +++ b/apps/openmw/mwmechanics/aiavoiddoor.hpp @@ -16,22 +16,22 @@ namespace MWMechanics /// \brief AiPackage to have an actor avoid an opening door /** The AI will retreat from the door until it has finished opening, walked far away from it, or one second has passed, in an attempt to avoid it **/ - class AiAvoidDoor : public AiPackage + class AiAvoidDoor final : public AiPackage { public: /// Avoid door until the door is fully open AiAvoidDoor(const MWWorld::ConstPtr& doorPtr); - virtual AiAvoidDoor *clone() const; + AiAvoidDoor *clone() const final; - virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); + bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; - virtual int getTypeId() const; + int getTypeId() const final; - virtual unsigned int getPriority() const; + unsigned int getPriority() const final; - virtual bool canCancel() const { return false; } - virtual bool shouldCancelPreviousAi() const { return false; } + bool canCancel() const final { return false; } + bool shouldCancelPreviousAi() const final { return false; } private: float mDuration; diff --git a/apps/openmw/mwmechanics/aibreathe.hpp b/apps/openmw/mwmechanics/aibreathe.hpp index 263ab8c2b..daa2782c2 100644 --- a/apps/openmw/mwmechanics/aibreathe.hpp +++ b/apps/openmw/mwmechanics/aibreathe.hpp @@ -7,21 +7,21 @@ namespace MWMechanics { /// \brief AiPackage to have an actor resurface to breathe // The AI will go up if lesser than half breath left - class AiBreathe : public AiPackage + class AiBreathe final : public AiPackage { public: AiBreathe(); - virtual AiBreathe *clone() const; + AiBreathe *clone() const final; - virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); + bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; - virtual int getTypeId() const; + int getTypeId() const final; - virtual unsigned int getPriority() const; + unsigned int getPriority() const final; - virtual bool canCancel() const { return false; } - virtual bool shouldCancelPreviousAi() const { return false; } + bool canCancel() const final { return false; } + bool shouldCancelPreviousAi() const final { return false; } }; } #endif diff --git a/apps/openmw/mwmechanics/aicast.hpp b/apps/openmw/mwmechanics/aicast.hpp index 7128fe7a2..6b10370c6 100644 --- a/apps/openmw/mwmechanics/aicast.hpp +++ b/apps/openmw/mwmechanics/aicast.hpp @@ -11,22 +11,22 @@ namespace MWWorld namespace MWMechanics { /// AiPackage which makes an actor to cast given spell. - class AiCast : public AiPackage { + class AiCast final : public AiPackage { public: AiCast(const std::string& targetId, const std::string& spellId, bool manualSpell=false); - virtual AiPackage *clone() const; + AiPackage *clone() const final; - virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); + bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; - virtual int getTypeId() const; + int getTypeId() const final; - virtual MWWorld::Ptr getTarget() const; + MWWorld::Ptr getTarget() const final; - virtual unsigned int getPriority() const; + unsigned int getPriority() const final; - virtual bool canCancel() const { return false; } - virtual bool shouldCancelPreviousAi() const { return false; } + bool canCancel() const final { return false; } + bool shouldCancelPreviousAi() const final { return false; } private: std::string mTargetId; diff --git a/apps/openmw/mwmechanics/aicombat.hpp b/apps/openmw/mwmechanics/aicombat.hpp index f89e71678..049857e71 100644 --- a/apps/openmw/mwmechanics/aicombat.hpp +++ b/apps/openmw/mwmechanics/aicombat.hpp @@ -91,7 +91,7 @@ namespace MWMechanics }; /// \brief Causes the actor to fight another actor - class AiCombat : public AiPackage + class AiCombat final : public AiPackage { public: ///Constructor @@ -102,21 +102,21 @@ namespace MWMechanics void init(); - virtual AiCombat *clone() const; + AiCombat *clone() const final; - virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); + bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; - virtual int getTypeId() const; + int getTypeId() const final; - virtual unsigned int getPriority() const; + unsigned int getPriority() const final; ///Returns target ID - MWWorld::Ptr getTarget() const; + MWWorld::Ptr getTarget() const final; - virtual void writeState(ESM::AiSequence::AiSequence &sequence) const; + void writeState(ESM::AiSequence::AiSequence &sequence) const final; - virtual bool canCancel() const { return false; } - virtual bool shouldCancelPreviousAi() const { return false; } + bool canCancel() const final { return false; } + bool shouldCancelPreviousAi() const final { return false; } private: /// Returns true if combat should end diff --git a/apps/openmw/mwmechanics/aiescort.hpp b/apps/openmw/mwmechanics/aiescort.hpp index e4319b425..5b49807a2 100644 --- a/apps/openmw/mwmechanics/aiescort.hpp +++ b/apps/openmw/mwmechanics/aiescort.hpp @@ -16,7 +16,7 @@ namespace AiSequence namespace MWMechanics { /// \brief AI Package to have an NPC lead the player to a specific point - class AiEscort : public AiPackage + class AiEscort final : public AiPackage { public: /// Implementation of AiEscort @@ -30,21 +30,21 @@ namespace MWMechanics AiEscort(const ESM::AiSequence::AiEscort* escort); - virtual AiEscort *clone() const; + AiEscort *clone() const final; - virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); + bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; - virtual int getTypeId() const; + int getTypeId() const final; - virtual bool useVariableSpeed() const { return true;} + bool useVariableSpeed() const final { return true; } - virtual bool sideWithTarget() const { return true; } + bool sideWithTarget() const final { return true; } - void writeState(ESM::AiSequence::AiSequence &sequence) const; + void writeState(ESM::AiSequence::AiSequence &sequence) const final; - void fastForward(const MWWorld::Ptr& actor, AiState& state); + void fastForward(const MWWorld::Ptr& actor, AiState& state) final; - virtual osg::Vec3f getDestination() const { return osg::Vec3f(mX, mY, mZ); } + osg::Vec3f getDestination() const final { return osg::Vec3f(mX, mY, mZ); } private: std::string mCellId; diff --git a/apps/openmw/mwmechanics/aiface.hpp b/apps/openmw/mwmechanics/aiface.hpp index 099e5d237..98d9ea04b 100644 --- a/apps/openmw/mwmechanics/aiface.hpp +++ b/apps/openmw/mwmechanics/aiface.hpp @@ -6,20 +6,20 @@ namespace MWMechanics { /// AiPackage which makes an actor face a certain direction. - class AiFace : public AiPackage { + class AiFace final : public AiPackage { public: AiFace(float targetX, float targetY); - virtual AiPackage *clone() const; + AiPackage *clone() const final; - virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); + bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; - virtual int getTypeId() const; + int getTypeId() const final; - virtual unsigned int getPriority() const; + unsigned int getPriority() const final; - virtual bool canCancel() const { return false; } - virtual bool shouldCancelPreviousAi() const { return false; } + bool canCancel() const final { return false; } + bool shouldCancelPreviousAi() const final { return false; } private: float mTargetX, mTargetY; diff --git a/apps/openmw/mwmechanics/aifollow.hpp b/apps/openmw/mwmechanics/aifollow.hpp index 24263bbc0..fc4b7fc0b 100644 --- a/apps/openmw/mwmechanics/aifollow.hpp +++ b/apps/openmw/mwmechanics/aifollow.hpp @@ -39,7 +39,7 @@ namespace MWMechanics /// \brief AiPackage for an actor to follow another actor/the PC /** The AI will follow the target until a condition (time, or position) are set. Both can be disabled to cause the actor to follow the other indefinitely **/ - class AiFollow : public AiPackage + class AiFollow final : public AiPackage { public: AiFollow(const std::string &actorId, float duration, float x, float y, float z); @@ -53,30 +53,30 @@ namespace MWMechanics AiFollow(const ESM::AiSequence::AiFollow* follow); - virtual bool sideWithTarget() const { return true; } - virtual bool followTargetThroughDoors() const { return true; } - virtual bool shouldCancelPreviousAi() const { return !mCommanded; } + bool sideWithTarget() const final { return true; } + bool followTargetThroughDoors() const final { return true; } + bool shouldCancelPreviousAi() const final { return !mCommanded; } - virtual AiFollow *clone() const; + AiFollow *clone() const final; - virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); + bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; - virtual int getTypeId() const; + int getTypeId() const final; - virtual bool useVariableSpeed() const { return true;} + bool useVariableSpeed() const final { return true; } /// Returns the actor being followed std::string getFollowedActor(); - virtual void writeState (ESM::AiSequence::AiSequence& sequence) const; + void writeState (ESM::AiSequence::AiSequence& sequence) const final; bool isCommanded() const; int getFollowIndex() const; - void fastForward(const MWWorld::Ptr& actor, AiState& state); + void fastForward(const MWWorld::Ptr& actor, AiState& state) final; - virtual osg::Vec3f getDestination() const + osg::Vec3f getDestination() const final { MWWorld::Ptr target = getTarget(); if (target.isEmpty()) diff --git a/apps/openmw/mwmechanics/aipursue.hpp b/apps/openmw/mwmechanics/aipursue.hpp index ea83a10e5..3f2c2923e 100644 --- a/apps/openmw/mwmechanics/aipursue.hpp +++ b/apps/openmw/mwmechanics/aipursue.hpp @@ -17,7 +17,7 @@ namespace MWMechanics /** Used for arresting players. Causes the actor to run to the pursued actor and activate them, to arrest them. Note that while very similar to AiActivate, it will ONLY activate when evry close to target (Not also when the path is completed). **/ - class AiPursue : public AiPackage + class AiPursue final : public AiPackage { public: ///Constructor @@ -26,16 +26,16 @@ namespace MWMechanics AiPursue(const ESM::AiSequence::AiPursue* pursue); - virtual AiPursue *clone() const; - virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); - virtual int getTypeId() const; + AiPursue *clone() const final; + bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; + int getTypeId() const final; - MWWorld::Ptr getTarget() const; + MWWorld::Ptr getTarget() const final; - virtual void writeState (ESM::AiSequence::AiSequence& sequence) const; + void writeState (ESM::AiSequence::AiSequence& sequence) const final; - virtual bool canCancel() const { return false; } - virtual bool shouldCancelPreviousAi() const { return false; } + bool canCancel() const final { return false; } + bool shouldCancelPreviousAi() const final { return false; } }; } #endif diff --git a/apps/openmw/mwmechanics/aitravel.hpp b/apps/openmw/mwmechanics/aitravel.hpp index e7895462f..43b6c9d16 100644 --- a/apps/openmw/mwmechanics/aitravel.hpp +++ b/apps/openmw/mwmechanics/aitravel.hpp @@ -14,7 +14,7 @@ namespace AiSequence namespace MWMechanics { /// \brief Causes the AI to travel to the specified point - class AiTravel : public AiPackage + class AiTravel final : public AiPackage { public: /// Default constructor @@ -22,21 +22,21 @@ namespace MWMechanics AiTravel(const ESM::AiSequence::AiTravel* travel); /// Simulates the passing of time - virtual void fastForward(const MWWorld::Ptr& actor, AiState& state); + void fastForward(const MWWorld::Ptr& actor, AiState& state) final; - void writeState(ESM::AiSequence::AiSequence &sequence) const; + void writeState(ESM::AiSequence::AiSequence &sequence) const final; - virtual AiTravel *clone() const; + AiTravel *clone() const final; - virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); + bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; - virtual int getTypeId() const; + int getTypeId() const final; - virtual bool useVariableSpeed() const { return true;} + bool useVariableSpeed() const final { return true; } - virtual bool alwaysActive() const { return true; } + bool alwaysActive() const final { return true; } - virtual osg::Vec3f getDestination() const { return osg::Vec3f(mX, mY, mZ); } + osg::Vec3f getDestination() const final { return osg::Vec3f(mX, mY, mZ); } private: float mX; diff --git a/apps/openmw/mwmechanics/aiwander.hpp b/apps/openmw/mwmechanics/aiwander.hpp index 6e69b6c79..f6e7f6d0c 100644 --- a/apps/openmw/mwmechanics/aiwander.hpp +++ b/apps/openmw/mwmechanics/aiwander.hpp @@ -78,7 +78,7 @@ namespace MWMechanics }; /// \brief Causes the Actor to wander within a specified range - class AiWander : public AiPackage + class AiWander final : public AiPackage { public: /// Constructor @@ -91,23 +91,23 @@ namespace MWMechanics AiWander (const ESM::AiSequence::AiWander* wander); - virtual AiPackage *clone() const; + AiPackage *clone() const final; - virtual bool execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration); + bool execute(const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) final; - virtual int getTypeId() const; + int getTypeId() const final; - virtual bool useVariableSpeed() const { return true;} + bool useVariableSpeed() const final { return true; } - virtual void writeState(ESM::AiSequence::AiSequence &sequence) const; + void writeState(ESM::AiSequence::AiSequence &sequence) const final; - virtual void fastForward(const MWWorld::Ptr& actor, AiState& state); + void fastForward(const MWWorld::Ptr& actor, AiState& state) final; - bool getRepeat() const; + bool getRepeat() const final; - osg::Vec3f getDestination(const MWWorld::Ptr& actor) const; + osg::Vec3f getDestination(const MWWorld::Ptr& actor) const final; - virtual osg::Vec3f getDestination() const + osg::Vec3f getDestination() const final { if (!mHasDestination) return osg::Vec3f(0, 0, 0); From d48eead0384b64ef878d3629556b662d55093c7a Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 17 May 2020 22:34:11 +0200 Subject: [PATCH 17/45] Check type id of current package If package is changed the following usage of it is not consistent. --- apps/openmw/mwmechanics/aisequence.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index 269468090..d33a0a3f8 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -275,6 +275,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac } package = mPackages.front(); + packageTypeId = package->getTypeId(); } try From 3875b837bcf2ff8a264916f045c1a03655e309a3 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Sun, 17 May 2020 22:34:54 +0200 Subject: [PATCH 18/45] make MenuMode, Random, GetSecondsPassed regular functions --- apps/openmw/mwscript/interpretercontext.cpp | 10 ----- apps/openmw/mwscript/interpretercontext.hpp | 4 -- apps/openmw/mwscript/miscextensions.cpp | 42 +++++++++++++++++++++ components/compiler/exprparser.cpp | 37 ------------------ components/compiler/extensions0.cpp | 3 ++ components/compiler/generator.cpp | 30 --------------- components/compiler/generator.hpp | 6 --- components/compiler/lineparser.cpp | 12 ------ components/compiler/opcodes.hpp | 3 ++ components/compiler/scanner.cpp | 3 -- components/compiler/scanner.hpp | 5 +-- components/compiler/stringparser.cpp | 4 +- components/interpreter/context.hpp | 4 -- components/interpreter/installopcodes.cpp | 3 -- components/interpreter/miscopcodes.hpp | 39 ------------------- 15 files changed, 50 insertions(+), 155 deletions(-) diff --git a/apps/openmw/mwscript/interpretercontext.cpp b/apps/openmw/mwscript/interpretercontext.cpp index f9d85375b..62febb33d 100644 --- a/apps/openmw/mwscript/interpretercontext.cpp +++ b/apps/openmw/mwscript/interpretercontext.cpp @@ -192,11 +192,6 @@ namespace MWScript { } - bool InterpreterContext::menuMode() - { - return MWBase::Environment::get().getWindowManager()->isGuiMode(); - } - int InterpreterContext::getGlobalShort (const std::string& name) const { return MWBase::Environment::get().getWorld()->getGlobalInt (name); @@ -425,11 +420,6 @@ namespace MWScript } } - float InterpreterContext::getSecondsPassed() const - { - return MWBase::Environment::get().getFrameDuration(); - } - int InterpreterContext::getMemberShort (const std::string& id, const std::string& name, bool global) const { diff --git a/apps/openmw/mwscript/interpretercontext.hpp b/apps/openmw/mwscript/interpretercontext.hpp index 7e9f09cdb..e7c2790ce 100644 --- a/apps/openmw/mwscript/interpretercontext.hpp +++ b/apps/openmw/mwscript/interpretercontext.hpp @@ -77,8 +77,6 @@ namespace MWScript virtual void report (const std::string& message); ///< By default, do nothing. - virtual bool menuMode(); - virtual int getGlobalShort (const std::string& name) const; virtual int getGlobalLong (const std::string& name) const; @@ -124,8 +122,6 @@ namespace MWScript void executeActivation(MWWorld::Ptr ptr, MWWorld::Ptr actor); ///< Execute the activation action for this ptr. If ptr is mActivated, mark activation as handled. - virtual float getSecondsPassed() const; - virtual int getMemberShort (const std::string& id, const std::string& name, bool global) const; virtual int getMemberLong (const std::string& id, const std::string& name, bool global) const; diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 915b3221c..89bf44701 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -12,6 +12,8 @@ #include #include +#include + #include #include @@ -78,6 +80,33 @@ namespace MWScript { namespace Misc { + class OpMenuMode : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + runtime.push (MWBase::Environment::get().getWindowManager()->isGuiMode()); + } + }; + + class OpRandom : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + Interpreter::Type_Integer limit = runtime[0].mInteger; + runtime.pop(); + + if (limit<0) + throw std::runtime_error ( + "random: argument out of range (Don't be so negative!)"); + + runtime.push (static_cast(::Misc::Rng::rollDice(limit))); // [o, limit) + } + }; + template class OpStartScript : public Interpreter::Opcode0 { @@ -116,6 +145,16 @@ namespace MWScript } }; + class OpGetSecondsPassed : public Interpreter::Opcode0 + { + public: + + virtual void execute (Interpreter::Runtime& runtime) + { + runtime.push (MWBase::Environment::get().getFrameDuration()); + } + }; + template class OpEnable : public Interpreter::Opcode0 { @@ -1530,10 +1569,13 @@ namespace MWScript void installOpcodes (Interpreter::Interpreter& interpreter) { + interpreter.installSegment5 (Compiler::Misc::opcodeMenuMode, new OpMenuMode); + interpreter.installSegment5 (Compiler::Misc::opcodeRandom, new OpRandom); interpreter.installSegment5 (Compiler::Misc::opcodeScriptRunning, new OpScriptRunning); interpreter.installSegment5 (Compiler::Misc::opcodeStartScript, new OpStartScript); interpreter.installSegment5 (Compiler::Misc::opcodeStartScriptExplicit, new OpStartScript); interpreter.installSegment5 (Compiler::Misc::opcodeStopScript, new OpStopScript); + interpreter.installSegment5 (Compiler::Misc::opcodeGetSecondsPassed, new OpGetSecondsPassed); interpreter.installSegment5 (Compiler::Misc::opcodeEnable, new OpEnable); interpreter.installSegment5 (Compiler::Misc::opcodeEnableExplicit, new OpEnable); interpreter.installSegment5 (Compiler::Misc::opcodeDisable, new OpDisable); diff --git a/components/compiler/exprparser.cpp b/components/compiler/exprparser.cpp index 8e8f063bb..8c8fe640e 100644 --- a/components/compiler/exprparser.cpp +++ b/components/compiler/exprparser.cpp @@ -434,43 +434,6 @@ namespace Compiler mNextOperand = false; return true; } - else if (keyword==Scanner::K_menumode) - { - start(); - - mTokenLoc = loc; - - Generator::menuMode (mCode); - mOperands.push_back ('l'); - - mNextOperand = false; - return true; - } - else if (keyword==Scanner::K_random) - { - start(); - - mTokenLoc = loc; - parseArguments ("l", scanner); - - Generator::random (mCode); - mOperands.push_back ('f'); - - mNextOperand = false; - return true; - } - else if (keyword==Scanner::K_getsecondspassed) - { - start(); - - mTokenLoc = loc; - - Generator::getSecondsPassed (mCode); - mOperands.push_back ('f'); - - mNextOperand = false; - return true; - } else { // check for custom extensions diff --git a/components/compiler/extensions0.cpp b/components/compiler/extensions0.cpp index 02a68d891..c67af29c2 100644 --- a/components/compiler/extensions0.cpp +++ b/components/compiler/extensions0.cpp @@ -241,9 +241,12 @@ namespace Compiler { void registerExtensions (Extensions& extensions) { + extensions.registerFunction ("menumode", 'l', "", opcodeMenuMode); + extensions.registerFunction ("random", 'f', "l", opcodeRandom); extensions.registerFunction ("scriptrunning", 'l', "c", opcodeScriptRunning); extensions.registerInstruction ("startscript", "c", opcodeStartScript, opcodeStartScriptExplicit); extensions.registerInstruction ("stopscript", "c", opcodeStopScript); + extensions.registerFunction ("getsecondspassed", 'f', "", opcodeGetSecondsPassed); extensions.registerInstruction ("enable", "", opcodeEnable, opcodeEnableExplicit); extensions.registerInstruction ("disable", "", opcodeDisable, opcodeDisableExplicit); extensions.registerFunction ("getdisabled", 'l', "x", opcodeGetDisabled, opcodeGetDisabledExplicit); diff --git a/components/compiler/generator.cpp b/components/compiler/generator.cpp index c16df660c..2787488c2 100644 --- a/components/compiler/generator.cpp +++ b/components/compiler/generator.cpp @@ -222,11 +222,6 @@ namespace code.push_back (Compiler::Generator::segment5 (37)); } - void opMenuMode (Compiler::Generator::CodeContainer& code) - { - code.push_back (Compiler::Generator::segment5 (38)); - } - void opStoreGlobalShort (Compiler::Generator::CodeContainer& code) { code.push_back (Compiler::Generator::segment5 (39)); @@ -286,16 +281,6 @@ namespace { code.push_back (Compiler::Generator::segment5 (global ? 70 : 64)); } - - void opRandom (Compiler::Generator::CodeContainer& code) - { - code.push_back (Compiler::Generator::segment5 (45)); - } - - void opGetSecondsPassed (Compiler::Generator::CodeContainer& code) - { - code.push_back (Compiler::Generator::segment5 (50)); - } } namespace Compiler @@ -590,11 +575,6 @@ namespace Compiler } } - void menuMode (CodeContainer& code) - { - opMenuMode (code); - } - void assignToGlobal (CodeContainer& code, Literals& literals, char localType, const std::string& name, const CodeContainer& value, char valueType) { @@ -751,15 +731,5 @@ namespace Compiler assert (0); } } - - void random (CodeContainer& code) - { - opRandom (code); - } - - void getSecondsPassed (CodeContainer& code) - { - opGetSecondsPassed (code); - } } } diff --git a/components/compiler/generator.hpp b/components/compiler/generator.hpp index f4386f605..55bba2a75 100644 --- a/components/compiler/generator.hpp +++ b/components/compiler/generator.hpp @@ -91,8 +91,6 @@ namespace Compiler void compare (CodeContainer& code, char op, char valueType1, char valueType2); - void menuMode (CodeContainer& code); - void assignToGlobal (CodeContainer& code, Literals& literals, char localType, const std::string& name, const CodeContainer& value, char valueType); @@ -106,10 +104,6 @@ namespace Compiler void fetchMember (CodeContainer& code, Literals& literals, char memberType, const std::string& name, const std::string& id, bool global); ///< \param global Member of a global script instead of a script of a reference. - - void random (CodeContainer& code); - - void getSecondsPassed (CodeContainer& code); } } diff --git a/components/compiler/lineparser.cpp b/components/compiler/lineparser.cpp index eaa833800..326b5f9f6 100644 --- a/components/compiler/lineparser.cpp +++ b/components/compiler/lineparser.cpp @@ -433,18 +433,6 @@ namespace Compiler return true; } - if (mAllowExpression) - { - if (keyword==Scanner::K_getsquareroot || keyword==Scanner::K_menumode || - keyword==Scanner::K_random || keyword==Scanner::K_getsecondspassed) - { - scanner.putbackKeyword (keyword, loc); - parseExpression (scanner, loc); - mState = EndState; - return true; - } - } - return Parser::parseKeyword (keyword, loc, scanner); } diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 72e3cea89..363e8bb85 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -201,9 +201,12 @@ namespace Compiler namespace Misc { + const int opcodeMenuMode = 38; + const int opcodeRandom = 45; const int opcodeScriptRunning = 46; const int opcodeStartScript = 47; const int opcodeStopScript = 48; + const int opcodeGetSecondsPassed = 50; const int opcodeEnable = 51; const int opcodeDisable = 52; const int opcodeGetDisabled = 53; diff --git a/components/compiler/scanner.cpp b/components/compiler/scanner.cpp index 2be679cd2..9f2865868 100644 --- a/components/compiler/scanner.cpp +++ b/components/compiler/scanner.cpp @@ -266,9 +266,6 @@ namespace Compiler "messagebox", "set", "to", "getsquareroot", - "menumode", - "random", - "getsecondspassed", 0 }; diff --git a/components/compiler/scanner.hpp b/components/compiler/scanner.hpp index 973761898..b6321a92d 100644 --- a/components/compiler/scanner.hpp +++ b/components/compiler/scanner.hpp @@ -208,10 +208,7 @@ namespace Compiler K_return, K_messagebox, K_set, K_to, - K_getsquareroot, - K_menumode, - K_random, - K_getsecondspassed + K_getsquareroot }; enum special diff --git a/components/compiler/stringparser.cpp b/components/compiler/stringparser.cpp index a9974297d..1bacf7941 100644 --- a/components/compiler/stringparser.cpp +++ b/components/compiler/stringparser.cpp @@ -63,9 +63,7 @@ namespace Compiler keyword==Scanner::K_elseif || keyword==Scanner::K_while || keyword==Scanner::K_endwhile || keyword==Scanner::K_return || keyword==Scanner::K_messagebox || keyword==Scanner::K_set || - keyword==Scanner::K_to || keyword==Scanner::K_getsquareroot || - keyword==Scanner::K_menumode || keyword==Scanner::K_random || - keyword==Scanner::K_getsecondspassed) + keyword==Scanner::K_to || keyword==Scanner::K_getsquareroot) { return parseName (loc.mLiteral, loc, scanner); } diff --git a/components/interpreter/context.hpp b/components/interpreter/context.hpp index 30744dcec..862018bdc 100644 --- a/components/interpreter/context.hpp +++ b/components/interpreter/context.hpp @@ -35,8 +35,6 @@ namespace Interpreter virtual void report (const std::string& message) = 0; - virtual bool menuMode() = 0; - virtual int getGlobalShort (const std::string& name) const = 0; virtual int getGlobalLong (const std::string& name) const = 0; @@ -79,8 +77,6 @@ namespace Interpreter virtual std::string getCurrentCellName() const = 0; - virtual float getSecondsPassed() const = 0; - virtual int getMemberShort (const std::string& id, const std::string& name, bool global) const = 0; virtual int getMemberLong (const std::string& id, const std::string& name, bool global) const = 0; diff --git a/components/interpreter/installopcodes.cpp b/components/interpreter/installopcodes.cpp index dfaabe325..afee36bc2 100644 --- a/components/interpreter/installopcodes.cpp +++ b/components/interpreter/installopcodes.cpp @@ -95,9 +95,6 @@ namespace Interpreter // misc interpreter.installSegment3 (0, new OpMessageBox); - interpreter.installSegment5 (38, new OpMenuMode); - interpreter.installSegment5 (45, new OpRandom); - interpreter.installSegment5 (50, new OpGetSecondsPassed); interpreter.installSegment5 (58, new OpReport); } } diff --git a/components/interpreter/miscopcodes.hpp b/components/interpreter/miscopcodes.hpp index e1b1843ef..07bd84ec9 100644 --- a/components/interpreter/miscopcodes.hpp +++ b/components/interpreter/miscopcodes.hpp @@ -11,7 +11,6 @@ #include "runtime.hpp" #include "defines.hpp" -#include #include namespace Interpreter @@ -168,44 +167,6 @@ namespace Interpreter } }; - class OpMenuMode : public Opcode0 - { - public: - - virtual void execute (Runtime& runtime) - { - runtime.push (runtime.getContext().menuMode()); - } - }; - - class OpRandom : public Opcode0 - { - public: - - virtual void execute (Runtime& runtime) - { - Type_Integer limit = runtime[0].mInteger; - - if (limit<0) - throw std::runtime_error ( - "random: argument out of range (Don't be so negative!)"); - - runtime[0].mFloat = static_cast(Misc::Rng::rollDice(limit)); // [o, limit) - } - }; - - class OpGetSecondsPassed : public Opcode0 - { - public: - - virtual void execute (Runtime& runtime) - { - Type_Float duration = runtime.getContext().getSecondsPassed(); - - runtime.push (duration); - } - }; - } #endif From a4fbcb8a1092eb57664f4576e74f11bb92680ec2 Mon Sep 17 00:00:00 2001 From: elsid Date: Sun, 17 May 2020 22:37:44 +0200 Subject: [PATCH 19/45] Remember package iterator to erase it from list without find call --- apps/openmw/mwmechanics/aisequence.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/aisequence.cpp b/apps/openmw/mwmechanics/aisequence.cpp index d33a0a3f8..00d44202a 100644 --- a/apps/openmw/mwmechanics/aisequence.cpp +++ b/apps/openmw/mwmechanics/aisequence.cpp @@ -212,7 +212,8 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac return; } - MWMechanics::AiPackage* package = mPackages.front(); + auto packageIt = mPackages.begin(); + MWMechanics::AiPackage* package = *packageIt; if (!package->alwaysActive() && outOfRange) return; @@ -274,7 +275,8 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac mPackages.splice(mPackages.begin(), mPackages, itActualCombat); } - package = mPackages.front(); + packageIt = mPackages.begin(); + package = *packageIt; packageTypeId = package->getTypeId(); } @@ -290,9 +292,7 @@ void AiSequence::execute (const MWWorld::Ptr& actor, CharacterController& charac } // To account for the rare case where AiPackage::execute() queued another AI package // (e.g. AiPursue executing a dialogue script that uses startCombat) - std::list::iterator toRemove = - std::find(mPackages.begin(), mPackages.end(), package); - mPackages.erase(toRemove); + mPackages.erase(packageIt); delete package; if (isActualAiPackage(packageTypeId)) mDone = true; From 087d12589af1582d0d3b814c8f11155bf2a92dcd Mon Sep 17 00:00:00 2001 From: AnyOldName3 Date: Mon, 18 May 2020 16:37:18 +0100 Subject: [PATCH 20/45] Ignore VS Code files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 45c87a2c5..1a164592a 100644 --- a/.gitignore +++ b/.gitignore @@ -31,6 +31,7 @@ files/windows/*.aps ## qt-creator CMakeLists.txt.user* .vs +.vscode ## resources data From d7a920a04b1a82fd9d074eb99787164cc959d54c Mon Sep 17 00:00:00 2001 From: elsid Date: Sat, 16 May 2020 13:45:02 +0200 Subject: [PATCH 21/45] Env variable to write OSG stats into file --- apps/openmw/engine.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 0fd6a1cb5..330d0e194 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -1,6 +1,7 @@ #include "engine.hpp" #include +#include #include @@ -738,6 +739,14 @@ void OMW::Engine::go() mEnvironment.getWindowManager()->executeInConsole(mStartupScript); } + std::ofstream stats; + if (const auto path = std::getenv("OPENMW_OSG_STATS_FILE")) + { + stats.open(path, std::ios_base::out); + if (!stats) + Log(Debug::Warning) << "Failed to open file for stats: " << path; + } + // Start the main rendering loop osg::Timer frameTimer; double simulationTime = 0.0; @@ -768,6 +777,12 @@ void OMW::Engine::go() simulationTime += dt; } + if (stats) + { + const auto frameNumber = mViewer->getFrameStamp()->getFrameNumber(); + mViewer->getViewerStats()->report(stats, frameNumber); + } + mEnvironment.limitFrameRate(frameTimer.time_s()); } From a59e25e093544b1d544a0e78c73a35d26f4083b5 Mon Sep 17 00:00:00 2001 From: elsid Date: Thu, 21 May 2020 15:24:06 +0200 Subject: [PATCH 22/45] Optimize MWRender::Animation::hasAnimation Use a set to check for group start existence. Reduce time taken from 2.6% to 0.08% and MWMechanics::MechanicsManager::update from 7% to 5% in relative CPU time usage for a scene with ~100 actors. --- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwmechanics/character.hpp | 3 +- apps/openmw/mwrender/animation.cpp | 50 ++++++--------- apps/openmw/mwrender/animation.hpp | 11 ++-- components/nifosg/nifloader.cpp | 3 +- components/nifosg/nifloader.hpp | 3 +- components/nifosg/textkeymap.hpp | 87 +++++++++++++++++++++++++++ 7 files changed, 117 insertions(+), 42 deletions(-) create mode 100644 components/nifosg/textkeymap.hpp diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 92eec1af6..ac8d417f3 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -942,7 +942,7 @@ void split(const std::string &s, char delim, std::vector &elems) { } } -void CharacterController::handleTextKey(const std::string &groupname, const std::multimap::const_iterator &key, const std::multimap &map) +void CharacterController::handleTextKey(const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key, const NifOsg::TextKeyMap& map) { const std::string &evt = key->second; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 614beca1c..aa3c035ba 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -238,8 +238,7 @@ public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim); virtual ~CharacterController(); - virtual void handleTextKey(const std::string &groupname, const std::multimap::const_iterator &key, - const std::multimap& map); + virtual void handleTextKey(const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key, const NifOsg::TextKeyMap& map); // Be careful when to call this, see comment in Actors void updateContinuousVfx(); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 8f3641795..77157377b 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -151,20 +151,8 @@ namespace } }; - NifOsg::TextKeyMap::const_iterator findGroupStart(const NifOsg::TextKeyMap &keys, const std::string &groupname) - { - NifOsg::TextKeyMap::const_iterator iter(keys.begin()); - for(;iter != keys.end();++iter) - { - if(iter->second.compare(0, groupname.size(), groupname) == 0 && - iter->second.compare(groupname.size(), 2, ": ") == 0) - break; - } - return iter; - } - - float calcAnimVelocity(const std::multimap& keys, - NifOsg::KeyframeController *nonaccumctrl, const osg::Vec3f& accum, const std::string &groupname) + float calcAnimVelocity(const NifOsg::TextKeyMap& keys, NifOsg::KeyframeController *nonaccumctrl, + const osg::Vec3f& accum, const std::string &groupname) { const std::string start = groupname+": start"; const std::string loopstart = groupname+": loop start"; @@ -179,7 +167,7 @@ namespace // but the animation velocity calculation uses the second one. // As result the animation velocity calculation is not correct, and this incorrect velocity must be replicated, // because otherwise the Creature's Speed (dagoth uthol) would not be sufficient to move fast enough. - NifOsg::TextKeyMap::const_reverse_iterator keyiter(keys.rbegin()); + auto keyiter = keys.rbegin(); while(keyiter != keys.rend()) { if(keyiter->second == start || keyiter->second == loopstart) @@ -553,7 +541,7 @@ namespace MWRender ControllerMap mControllerMap[Animation::sNumBlendMasks]; - const std::multimap& getTextKeys() const; + const NifOsg::TextKeyMap& getTextKeys() const; }; void UpdateVfxCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) @@ -702,7 +690,7 @@ namespace MWRender return 0; } - const std::multimap &Animation::AnimSource::getTextKeys() const + const NifOsg::TextKeyMap &Animation::AnimSource::getTextKeys() const { return mKeyframes->mTextKeys; } @@ -825,7 +813,7 @@ namespace MWRender for(;iter != mAnimSources.end();++iter) { const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys(); - if(findGroupStart(keys, anim) != keys.end()) + if (keys.hasGroupStart(anim)) return true; } @@ -838,7 +826,7 @@ namespace MWRender { const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys(); - NifOsg::TextKeyMap::const_iterator found = findGroupStart(keys, groupname); + const auto found = keys.findGroupStart(groupname); if(found != keys.end()) return found->first; } @@ -851,7 +839,7 @@ namespace MWRender { const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys(); - for(NifOsg::TextKeyMap::const_iterator iterKey(keys.begin()); iterKey != keys.end(); ++iterKey) + for(auto iterKey = keys.begin(); iterKey != keys.end(); ++iterKey) { if(iterKey->second.compare(0, textKey.size(), textKey) == 0) return iterKey->first; @@ -861,8 +849,8 @@ namespace MWRender return -1.f; } - void Animation::handleTextKey(AnimState &state, const std::string &groupname, const std::multimap::const_iterator &key, - const std::multimap& map) + void Animation::handleTextKey(AnimState &state, const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key, + const NifOsg::TextKeyMap& map) { const std::string &evt = key->second; @@ -939,7 +927,7 @@ namespace MWRender if (state.mPlaying) { - NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.getTime())); + auto textkey = textkeys.lowerBound(state.getTime()); while(textkey != textkeys.end() && textkey->first <= state.getTime()) { handleTextKey(state, groupname, textkey, textkeys); @@ -955,7 +943,7 @@ namespace MWRender if(state.getTime() >= state.mLoopStopTime) break; - NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.getTime())); + auto textkey = textkeys.lowerBound(state.getTime()); while(textkey != textkeys.end() && textkey->first <= state.getTime()) { handleTextKey(state, groupname, textkey, textkeys); @@ -974,7 +962,7 @@ namespace MWRender { // Look for text keys in reverse. This normally wouldn't matter, but for some reason undeadwolf_2.nif has two // separate walkforward keys, and the last one is supposed to be used. - NifOsg::TextKeyMap::const_reverse_iterator groupend(keys.rbegin()); + auto groupend = keys.rbegin(); for(;groupend != keys.rend();++groupend) { if(groupend->second.compare(0, groupname.size(), groupname) == 0 && @@ -983,7 +971,7 @@ namespace MWRender } std::string starttag = groupname+": "+start; - NifOsg::TextKeyMap::const_reverse_iterator startkey(groupend); + auto startkey = groupend; while(startkey != keys.rend() && startkey->second != starttag) ++startkey; if(startkey == keys.rend() && start == "loop start") @@ -997,7 +985,7 @@ namespace MWRender return false; const std::string stoptag = groupname+": "+stop; - NifOsg::TextKeyMap::const_reverse_iterator stopkey(groupend); + auto stopkey = groupend; while(stopkey != keys.rend() // We have to ignore extra garbage at the end. // The Scrib's idle3 animation has "Idle3: Stop." instead of "Idle3: Stop". @@ -1030,7 +1018,7 @@ namespace MWRender const std::string loopstarttag = groupname+": loop start"; const std::string loopstoptag = groupname+": loop stop"; - NifOsg::TextKeyMap::const_reverse_iterator key(groupend); + auto key = groupend; for (; key != startkey && key != keys.rend(); ++key) { if (key->first > state.getTime()) @@ -1201,7 +1189,7 @@ namespace MWRender for(;animsrc != mAnimSources.rend();++animsrc) { const NifOsg::TextKeyMap &keys = (*animsrc)->getTextKeys(); - if(findGroupStart(keys, groupname) != keys.end()) + if (keys.hasGroupStart(groupname)) break; } if(animsrc == mAnimSources.rend()) @@ -1280,7 +1268,7 @@ namespace MWRender } const NifOsg::TextKeyMap &textkeys = state.mSource->getTextKeys(); - NifOsg::TextKeyMap::const_iterator textkey(textkeys.upper_bound(state.getTime())); + auto textkey = textkeys.upperBound(state.getTime()); float timepassed = duration * state.mSpeedMult; while(state.mPlaying) @@ -1316,7 +1304,7 @@ namespace MWRender state.setTime(state.mLoopStartTime); state.mPlaying = true; - textkey = textkeys.lower_bound(state.getTime()); + textkey = textkeys.lowerBound(state.getTime()); while(textkey != textkeys.end() && textkey->first <= state.getTime()) { handleTextKey(state, stateiter->first, textkey, textkeys); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 7b1e1d3e9..dddde7d9a 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace ESM { @@ -147,8 +148,8 @@ public: class TextKeyListener { public: - virtual void handleTextKey(const std::string &groupname, const std::multimap::const_iterator &key, - const std::multimap& map) = 0; + virtual void handleTextKey(const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key, + const NifOsg::TextKeyMap& map) = 0; virtual ~TextKeyListener() = default; }; @@ -296,12 +297,12 @@ protected: * the marker is not found, or if the markers are the same, it returns * false. */ - bool reset(AnimState &state, const std::multimap &keys, + bool reset(AnimState &state, const NifOsg::TextKeyMap &keys, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, bool loopfallback); - void handleTextKey(AnimState &state, const std::string &groupname, const std::multimap::const_iterator &key, - const std::multimap& map); + void handleTextKey(AnimState &state, const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key, + const NifOsg::TextKeyMap& map); /** Sets the root model of the object. * diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 521764274..e3c6d823f 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -157,7 +157,8 @@ namespace nextpos = std::distance(str.begin(), ++last); } std::string result = str.substr(pos, nextpos-pos); - textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::lowerCase(result))); + Misc::StringUtils::lowerCaseInPlace(result); + textkeys.emplace(tk->list[i].time, std::move(result)); pos = nextpos; } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 4de9027b8..49a78ad5f 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -7,6 +7,7 @@ #include #include "controller.hpp" +#include "textkeymap.hpp" namespace osg { @@ -20,8 +21,6 @@ namespace Resource namespace NifOsg { - typedef std::multimap TextKeyMap; - struct TextKeyMapHolder : public osg::Object { public: diff --git a/components/nifosg/textkeymap.hpp b/components/nifosg/textkeymap.hpp new file mode 100644 index 000000000..49e1e461e --- /dev/null +++ b/components/nifosg/textkeymap.hpp @@ -0,0 +1,87 @@ +#ifndef OPENMW_COMPONENTS_NIFOSG_TEXTKEYMAP +#define OPENMW_COMPONENTS_NIFOSG_TEXTKEYMAP + +#include +#include +#include +#include + +namespace NifOsg +{ + class TextKeyMap + { + public: + using ConstIterator = std::multimap::const_iterator; + + auto begin() const noexcept + { + return mTextKeyByTime.begin(); + } + + auto end() const noexcept + { + return mTextKeyByTime.end(); + } + + auto rbegin() const noexcept + { + return mTextKeyByTime.rbegin(); + } + + auto rend() const noexcept + { + return mTextKeyByTime.rend(); + } + + auto lowerBound(float time) const + { + return mTextKeyByTime.lower_bound(time); + } + + auto upperBound(float time) const + { + return mTextKeyByTime.upper_bound(time); + } + + void emplace(float time, std::string&& textKey) + { + const auto separator = textKey.find(": "); + if (separator != std::string::npos) + mGroups.emplace(textKey.substr(0, separator)); + + mTextKeyByTime.emplace(time, std::move(textKey)); + } + + bool empty() const noexcept + { + return mTextKeyByTime.empty(); + } + + auto findGroupStart(const std::string &groupName) const + { + return std::find_if(mTextKeyByTime.begin(), mTextKeyByTime.end(), IsGroupStart{groupName}); + } + + bool hasGroupStart(const std::string &groupName) const + { + return mGroups.count(groupName) > 0; + } + + private: + struct IsGroupStart + { + const std::string &mGroupName; + + bool operator ()(const std::multimap::value_type& value) const + { + return value.second.compare(0, mGroupName.size(), mGroupName) == 0 && + value.second.compare(mGroupName.size(), 2, ": ") == 0; + } + }; + + std::set mGroups; + std::multimap mTextKeyByTime; + }; +} + +#endif From 9326111f4c10c278888fb402092a7de131f0eefa Mon Sep 17 00:00:00 2001 From: elsid Date: Thu, 21 May 2020 17:23:32 +0200 Subject: [PATCH 23/45] Use vector for Animation::mActiveControllers Container is only used to add elements, iterate over all of them and clear. Multimap adds overhead for all of these operations without any benefits. Reduce Animation::resetActiveGroups CPU time usage by 50%. --- apps/openmw/mwrender/animation.cpp | 8 ++++---- apps/openmw/mwrender/animation.hpp | 5 +++-- apps/openmw/mwrender/npcanimation.cpp | 2 +- apps/openmw/mwrender/weaponanimation.cpp | 4 ++-- apps/openmw/mwrender/weaponanimation.hpp | 2 +- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 8f3641795..aad9458d4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1064,7 +1064,7 @@ namespace MWRender void Animation::resetActiveGroups() { // remove all previous external controllers from the scene graph - for (ControllerMap::iterator it = mActiveControllers.begin(); it != mActiveControllers.end(); ++it) + for (auto it = mActiveControllers.begin(); it != mActiveControllers.end(); ++it) { osg::Node* node = it->first; node->removeUpdateCallback(it->second); @@ -1103,7 +1103,7 @@ namespace MWRender osg::ref_ptr node = getNodeMap().at(it->first); // this should not throw, we already checked for the node existing in addAnimSource node->addUpdateCallback(it->second); - mActiveControllers.insert(std::make_pair(node, it->second)); + mActiveControllers.emplace_back(node, it->second); if (blendMask == 0 && node == mAccumRoot) { @@ -1116,7 +1116,7 @@ namespace MWRender mResetAccumRootCallback->setAccumulate(mAccumulate); } mAccumRoot->addUpdateCallback(mResetAccumRootCallback); - mActiveControllers.insert(std::make_pair(mAccumRoot, mResetAccumRootCallback)); + mActiveControllers.emplace_back(mAccumRoot, mResetAccumRootCallback); } } } @@ -1850,7 +1850,7 @@ namespace MWRender { mHeadController = new RotateController(mObjectRoot.get()); node->addUpdateCallback(mHeadController); - mActiveControllers.insert(std::make_pair(node, mHeadController)); + mActiveControllers.emplace_back(node, mHeadController); } } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 7b1e1d3e9..ad10a5575 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -6,6 +6,8 @@ #include #include +#include + namespace ESM { struct Light; @@ -246,8 +248,7 @@ protected: // Keep track of controllers that we added to our scene graph. // We may need to rebuild these controllers when the active animation groups / sources change. - typedef std::multimap, osg::ref_ptr > ControllerMap; - ControllerMap mActiveControllers; + std::vector, osg::ref_ptr>> mActiveControllers; std::shared_ptr mAnimationTimePtr[sNumBlendMasks]; diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 41fadd98e..ec825ca2f 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -956,7 +956,7 @@ void NpcAnimation::addControllers() osg::MatrixTransform* node = found->second.get(); mFirstPersonNeckController = new NeckController(mObjectRoot.get()); node->addUpdateCallback(mFirstPersonNeckController); - mActiveControllers.emplace(node, mFirstPersonNeckController); + mActiveControllers.emplace_back(node, mFirstPersonNeckController); } } else if (mViewMode == VM_Normal) diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index 24c92bc32..2af5fdb41 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -168,7 +168,7 @@ void WeaponAnimation::releaseArrow(MWWorld::Ptr actor, float attackStrength) } void WeaponAnimation::addControllers(const std::map >& nodes, - std::multimap, osg::ref_ptr > &map, osg::Node* objectRoot) + std::vector, osg::ref_ptr>> &map, osg::Node* objectRoot) { for (int i=0; i<2; ++i) { @@ -180,7 +180,7 @@ void WeaponAnimation::addControllers(const std::mapsecond; mSpineControllers[i] = new RotateController(objectRoot); node->addUpdateCallback(mSpineControllers[i]); - map.insert(std::make_pair(node, mSpineControllers[i])); + map.emplace_back(node, mSpineControllers[i]); } } } diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index ece0beaa6..a1988703c 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -41,7 +41,7 @@ namespace MWRender /// Add WeaponAnimation-related controllers to \a nodes and store the added controllers in \a map. void addControllers(const std::map >& nodes, - std::multimap, osg::ref_ptr >& map, osg::Node* objectRoot); + std::vector, osg::ref_ptr>>& map, osg::Node* objectRoot); void deleteControllers(); From 904b245d30df0a7895af913ac79a656703274f24 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 22 May 2020 14:26:02 +0300 Subject: [PATCH 24/45] Re-enable non-biped creature headtracking (bug #5424) --- CHANGELOG.md | 1 + apps/openmw/mwrender/animation.cpp | 43 ++++++++++++++---------------- 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 138ef1707..3fc9e827c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Bug #5400: Editor: Verifier checks race of non-skin bodyparts Bug #5415: Environment maps in ebony cuirass and HiRez Armors Indoril cuirass don't work Bug #5416: Junk non-node records before the root node are not handled gracefully + Bug #5424: Creatures do not headtrack player Feature #5362: Show the soul gems' trapped soul in count dialog 0.46.0 diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index df2000221..8f8e8c233 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1815,33 +1815,30 @@ namespace MWRender { mHeadController = nullptr; - if (mPtr.getClass().isBipedal(mPtr)) + NodeMap::const_iterator found = getNodeMap().find("bip01 head"); + if (found == getNodeMap().end()) + return; + + osg::MatrixTransform* node = found->second; + + bool foundKeyframeCtrl = false; + osg::Callback* cb = node->getUpdateCallback(); + while (cb) { - NodeMap::const_iterator found = getNodeMap().find("bip01 head"); - if (found != getNodeMap().end()) + if (dynamic_cast(cb)) { - osg::MatrixTransform* node = found->second; - - bool foundKeyframeCtrl = false; - osg::Callback* cb = node->getUpdateCallback(); - while (cb) - { - if (dynamic_cast(cb)) - { - foundKeyframeCtrl = true; - break; - } - cb = cb->getNestedCallback(); - } - - if (foundKeyframeCtrl) - { - mHeadController = new RotateController(mObjectRoot.get()); - node->addUpdateCallback(mHeadController); - mActiveControllers.emplace_back(node, mHeadController); - } + foundKeyframeCtrl = true; + break; } + cb = cb->getNestedCallback(); } + + if (!foundKeyframeCtrl) + return; + + mHeadController = new RotateController(mObjectRoot.get()); + node->addUpdateCallback(mHeadController); + mActiveControllers.emplace_back(node, mHeadController); } void Animation::setHeadPitch(float pitchRadians) From c9c9599ec54c3e06947e859d9e2227fe5009750e Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 22 May 2020 14:04:26 +0300 Subject: [PATCH 25/45] Improve GetDistance and object search warnings (bug #5427) Allow GetDistance to work with a non-existent object argument or with inventory items that belong to a container store that doesn't exist --- CHANGELOG.md | 1 + .../mwscript/transformationextensions.cpp | 20 ++++++++++++++++--- apps/openmw/mwworld/worldimp.cpp | 5 ++++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fc9e827c..285301a1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ Bug #5415: Environment maps in ebony cuirass and HiRez Armors Indoril cuirass don't work Bug #5416: Junk non-node records before the root node are not handled gracefully Bug #5424: Creatures do not headtrack player + Bug #5427: GetDistance unknown ID error is misleading Feature #5362: Show the soul gems' trapped soul in count dialog 0.46.0 diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index 3af54b394..791d054f3 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -46,10 +46,10 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { + MWWorld::Ptr from = R()(runtime); std::string name = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - MWWorld::Ptr from = R()(runtime); if (from.getContainerStore()) // is the object contained? { MWWorld::Ptr container = MWBase::Environment::get().getWorld()->findContainer(from); @@ -57,10 +57,24 @@ namespace MWScript if (!container.isEmpty()) from = container; else - throw std::runtime_error("failed to find container ptr"); + { + std::string error = "Failed to find the container of object '" + from.getCellRef().getRefId() + "'"; + runtime.getContext().report(error); + Log(Debug::Error) << error; + runtime.push(0.f); + return; + } } - const MWWorld::Ptr to = MWBase::Environment::get().getWorld()->getPtr(name, false); + const MWWorld::Ptr to = MWBase::Environment::get().getWorld()->searchPtr(name, false); + if (to.isEmpty()) + { + std::string error = "Failed to find an instance of object '" + name + "'"; + runtime.getContext().report(error); + Log(Debug::Error) << error; + runtime.push(0.f); + return; + } float distance; // If the objects are in different worldspaces, return a large value (just like vanilla) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8caec9876..ba4a6467a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -741,7 +741,10 @@ namespace MWWorld Ptr ret = searchPtr(name, activeOnly); if (!ret.isEmpty()) return ret; - throw std::runtime_error ("unknown ID: " + name); + std::string error = "failed to find an instance of object '" + name + "'"; + if (activeOnly) + error += " in active cells"; + throw std::runtime_error(error); } Ptr World::searchPtrViaActorId (int actorId) From 69df6098e5d118fecc9e7d3a1a800462fd3643d8 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 22 May 2020 00:11:23 +0200 Subject: [PATCH 26/45] Report frame number, number of actors and objects to stats --- apps/openmw/engine.cpp | 4 +++- apps/openmw/mwbase/environment.cpp | 6 ++++++ apps/openmw/mwbase/environment.hpp | 7 +++++++ apps/openmw/mwbase/mechanicsmanager.hpp | 3 +++ apps/openmw/mwbase/world.hpp | 3 +++ apps/openmw/mwmechanics/actors.hpp | 1 + .../mwmechanics/mechanicsmanagerimp.cpp | 7 +++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 2 ++ apps/openmw/mwmechanics/objects.hpp | 5 +++++ apps/openmw/mwphysics/physicssystem.cpp | 8 ++++++++ apps/openmw/mwphysics/physicssystem.hpp | 3 +++ apps/openmw/mwworld/worldimp.cpp | 6 ++++++ apps/openmw/mwworld/worldimp.hpp | 3 +++ components/resource/stats.cpp | 20 ++++++++++++++----- 14 files changed, 72 insertions(+), 6 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 330d0e194..110efedc0 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -203,12 +203,14 @@ bool OMW::Engine::frame(float frametime) if (stats->collectStats("resource")) { + stats->setAttribute(frameNumber, "FrameNumber", frameNumber); + mResourceSystem->reportStats(frameNumber, stats); stats->setAttribute(frameNumber, "WorkQueue", mWorkQueue->getNumItems()); stats->setAttribute(frameNumber, "WorkThread", mWorkQueue->getNumActiveThreads()); - mEnvironment.getWorld()->getNavigator()->reportStats(frameNumber, *stats); + mEnvironment.reportStats(frameNumber, *stats); } } diff --git a/apps/openmw/mwbase/environment.cpp b/apps/openmw/mwbase/environment.cpp index 5d01525b9..c70debda1 100644 --- a/apps/openmw/mwbase/environment.cpp +++ b/apps/openmw/mwbase/environment.cpp @@ -198,3 +198,9 @@ const MWBase::Environment& MWBase::Environment::get() assert (sThis); return *sThis; } + +void MWBase::Environment::reportStats(unsigned int frameNumber, osg::Stats& stats) const +{ + mMechanicsManager->reportStats(frameNumber, stats); + mWorld->reportStats(frameNumber, stats); +} diff --git a/apps/openmw/mwbase/environment.hpp b/apps/openmw/mwbase/environment.hpp index 9163b21f3..80e6a6243 100644 --- a/apps/openmw/mwbase/environment.hpp +++ b/apps/openmw/mwbase/environment.hpp @@ -1,6 +1,11 @@ #ifndef GAME_BASE_ENVIRONMENT_H #define GAME_BASE_ENVIRONMENT_H +namespace osg +{ + class Stats; +} + namespace MWBase { class World; @@ -97,6 +102,8 @@ namespace MWBase static const Environment& get(); ///< Return instance of this class. + + void reportStats(unsigned int frameNumber, osg::Stats& stats) const; }; } diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index 411f5fab1..cca789a40 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -11,6 +11,7 @@ namespace osg { + class Stats; class Vec3f; } @@ -269,6 +270,8 @@ namespace MWBase virtual bool isAttackPreparing(const MWWorld::Ptr& ptr) = 0; virtual bool isRunning(const MWWorld::Ptr& ptr) = 0; virtual bool isSneaking(const MWWorld::Ptr& ptr) = 0; + + virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const = 0; }; } diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 84f9b4984..4bd80132d 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -21,6 +21,7 @@ namespace osg class Matrixf; class Quat; class Image; + class Stats; } namespace Loading @@ -629,6 +630,8 @@ namespace MWBase virtual bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const = 0; virtual bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, const MWWorld::ConstPtr& ignore) const = 0; + + virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const = 0; }; } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index eb705fd68..4e952d1c8 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -70,6 +70,7 @@ namespace MWMechanics PtrActorMap::const_iterator begin() { return mActors.begin(); } PtrActorMap::const_iterator end() { return mActors.end(); } + std::size_t size() const { return mActors.size(); } void notifyDied(const MWWorld::Ptr &actor); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 25b33c486..5ca7b3cdd 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1,5 +1,7 @@ #include "mechanicsmanagerimp.hpp" +#include + #include #include @@ -1944,4 +1946,9 @@ namespace MWMechanics mActors.cleanupSummonedCreature(caster.getClass().getCreatureStats(caster), creatureActorId); } + void MechanicsManager::reportStats(unsigned int frameNumber, osg::Stats& stats) const + { + stats.setAttribute(frameNumber, "Mechanics Actors", mActors.size()); + stats.setAttribute(frameNumber, "Mechanics Objects", mObjects.size()); + } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 640bd3bdd..83d1b236f 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -240,6 +240,8 @@ namespace MWMechanics virtual bool isRunning(const MWWorld::Ptr& ptr) override; virtual bool isSneaking(const MWWorld::Ptr& ptr) override; + virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const override; + private: bool canCommitCrimeAgainst(const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker); bool canReportCrime(const MWWorld::Ptr &actor, const MWWorld::Ptr &victim, std::set &playerFollowers); diff --git a/apps/openmw/mwmechanics/objects.hpp b/apps/openmw/mwmechanics/objects.hpp index 1bcf646a4..5160114a3 100644 --- a/apps/openmw/mwmechanics/objects.hpp +++ b/apps/openmw/mwmechanics/objects.hpp @@ -52,6 +52,11 @@ namespace MWMechanics void persistAnimationStates(); void getObjectsInRange (const osg::Vec3f& position, float radius, std::vector& out); + + std::size_t size() const + { + return mObjects.size(); + } }; } diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index a205abeb4..808b1e75a 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -1,6 +1,7 @@ #include "physicssystem.hpp" #include +#include #include #include @@ -883,4 +884,11 @@ namespace MWPhysics mCollisionWorld->getBroadphase()->aabbTest(aabbMin, aabbMax, callback); return callback.getResult(); } + + void PhysicsSystem::reportStats(unsigned int frameNumber, osg::Stats& stats) const + { + stats.setAttribute(frameNumber, "Physics Actors", mActors.size()); + stats.setAttribute(frameNumber, "Physics Objects", mObjects.size()); + stats.setAttribute(frameNumber, "Physics HeightFields", mHeightFields.size()); + } } diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 0f2ecc092..8b09722af 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -17,6 +17,7 @@ namespace osg { class Group; class Object; + class Stats; } namespace MWRender @@ -186,6 +187,8 @@ namespace MWPhysics bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, const MWWorld::ConstPtr& ignore) const; + void reportStats(unsigned int frameNumber, osg::Stats& stats) const; + private: void updateWater(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 8caec9876..c217df5e7 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3947,4 +3947,10 @@ namespace MWWorld { return mPhysics->isAreaOccupiedByOtherActor(position, radius, ignore); } + + void World::reportStats(unsigned int frameNumber, osg::Stats& stats) const + { + mNavigator->reportStats(frameNumber, stats); + mPhysics->reportStats(frameNumber, stats); + } } diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 7b6d2afdc..942788499 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -20,6 +20,7 @@ namespace osg { class Group; + class Stats; } namespace osgViewer @@ -732,6 +733,8 @@ namespace MWWorld bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const override; bool isAreaOccupiedByOtherActor(const osg::Vec3f& position, const float radius, const MWWorld::ConstPtr& ignore) const override; + + void reportStats(unsigned int frameNumber, osg::Stats& stats) const override; }; } diff --git a/components/resource/stats.cpp b/components/resource/stats.cpp index 59d65e889..0dd52ffb6 100644 --- a/components/resource/stats.cpp +++ b/components/resource/stats.cpp @@ -262,7 +262,6 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer) stateset->setAttribute(new osg::PolygonMode(), osg::StateAttribute::PROTECTED); #endif - osg::Vec3 pos(_statsWidth-420.f, _statsHeight-500.0f,0.0f); osg::Vec4 backgroundColor(0.0, 0.0, 0.0f, 0.3); osg::Vec4 staticTextColor(1.0, 1.0, 0.0f, 1.0); osg::Vec4 dynamicTextColor(1.0, 1.0, 1.0f, 1.0); @@ -277,6 +276,8 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer) _switch->addChild(group, false); static const std::vector statNames({ + "FrameNumber", + "", "Compiling", "WorkQueue", "WorkThread", @@ -302,16 +303,25 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer) "NavMesh CacheSize", "NavMesh UsedTiles", "NavMesh CachedTiles", + "", + "Mechanics Actors", + "Mechanics Objects", + "", + "Physics Actors", + "Physics Objects", + "Physics HeightFields", }); static const auto longest = std::max_element(statNames.begin(), statNames.end(), [] (const std::string& lhs, const std::string& rhs) { return lhs.size() < rhs.size(); }); - const int numLines = statNames.size(); const float statNamesWidth = 13 * _characterSize + 2 * backgroundMargin; + const float statTextWidth = 7 * _characterSize + 2 * backgroundMargin; + const float statHeight = statNames.size() * _characterSize + 2 * backgroundMargin; + osg::Vec3 pos(_statsWidth - statNamesWidth - backgroundSpacing - statTextWidth, statHeight, 0.0f); group->addChild(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, _characterSize + backgroundMargin, 0), statNamesWidth, - numLines * _characterSize + 2 * backgroundMargin, + statHeight, backgroundColor)); osg::ref_ptr staticText = new osgText::Text; @@ -335,8 +345,8 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer) pos.x() += statNamesWidth + backgroundSpacing; group->addChild(createBackgroundRectangle(pos + osg::Vec3(-backgroundMargin, _characterSize + backgroundMargin, 0), - 7 * _characterSize + 2 * backgroundMargin, - numLines * _characterSize + 2 * backgroundMargin, + statTextWidth, + statHeight, backgroundColor)); osg::ref_ptr statsText = new osgText::Text; From e0ecbc08dfdb2bee437eaaf4ded3b9e8d32b9d9b Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Fri, 22 May 2020 18:31:10 +0300 Subject: [PATCH 27/45] Give new opcodes to old functions made custom --- apps/openmw/mwscript/docs/vmformat.txt | 17 +++++++++++++- components/compiler/opcodes.hpp | 30 ++++++++++++------------ components/interpreter/docs/vmformat.txt | 20 +++------------- 3 files changed, 34 insertions(+), 33 deletions(-) diff --git a/apps/openmw/mwscript/docs/vmformat.txt b/apps/openmw/mwscript/docs/vmformat.txt index 5a333a5b7..ccc579b30 100644 --- a/apps/openmw/mwscript/docs/vmformat.txt +++ b/apps/openmw/mwscript/docs/vmformat.txt @@ -464,5 +464,20 @@ op 0x200030d: RepairedOnMe, explicit op 0x200030e: TestCells op 0x200030f: TestInteriorCells op 0x2000310: ToggleRecastMesh +op 0x2000311: MenuMode +op 0x2000312: Random +op 0x2000313: ScriptRunning +op 0x2000314: StartScript +op 0x2000315: StopScript +op 0x2000316: GetSecondsPassed +op 0x2000317: Enable +op 0x2000318: Disable +op 0x2000319: GetDisabled +op 0x200031a: Enable, explicit +op 0x200031b: Disable, explicit +op 0x200031c: GetDisabled, explicit +op 0x200031d: StartScript, explicit +op 0x200031e: GetDistance +op 0x200031f: GetDistance, explicit -opcodes 0x2000311-0x3ffffff unused +opcodes 0x2000320-0x3ffffff unused diff --git a/components/compiler/opcodes.hpp b/components/compiler/opcodes.hpp index 363e8bb85..fdc3e0eab 100644 --- a/components/compiler/opcodes.hpp +++ b/components/compiler/opcodes.hpp @@ -201,19 +201,6 @@ namespace Compiler namespace Misc { - const int opcodeMenuMode = 38; - const int opcodeRandom = 45; - const int opcodeScriptRunning = 46; - const int opcodeStartScript = 47; - const int opcodeStopScript = 48; - const int opcodeGetSecondsPassed = 50; - const int opcodeEnable = 51; - const int opcodeDisable = 52; - const int opcodeGetDisabled = 53; - const int opcodeEnableExplicit = 54; - const int opcodeDisableExplicit = 55; - const int opcodeGetDisabledExplicit = 56; - const int opcodeStartScriptExplicit = 71; const int opcodeXBox = 0x200000c; const int opcodeOnActivate = 0x200000d; const int opcodeOnActivateExplicit = 0x2000306; @@ -318,6 +305,19 @@ namespace Compiler const int opcodeRepairedOnMe = 0x200030c; const int opcodeRepairedOnMeExplicit = 0x200030d; const int opcodeToggleRecastMesh = 0x2000310; + const int opcodeMenuMode = 0x2000311; + const int opcodeRandom = 0x2000312; + const int opcodeScriptRunning = 0x2000313; + const int opcodeStartScript = 0x2000314; + const int opcodeStopScript = 0x2000315; + const int opcodeGetSecondsPassed = 0x2000316; + const int opcodeEnable = 0x2000317; + const int opcodeDisable = 0x2000318; + const int opcodeGetDisabled = 0x2000319; + const int opcodeEnableExplicit = 0x200031a; + const int opcodeDisableExplicit = 0x200031b; + const int opcodeGetDisabledExplicit = 0x200031c; + const int opcodeStartScriptExplicit = 0x200031d; } namespace Sky @@ -486,8 +486,6 @@ namespace Compiler namespace Transformation { - const int opcodeGetDistance = 49; - const int opcodeGetDistanceExplicit = 57; const int opcodeSetScale = 0x2000164; const int opcodeSetScaleExplicit = 0x2000165; const int opcodeSetAngle = 0x2000166; @@ -528,6 +526,8 @@ namespace Compiler const int opcodeMoveWorldExplicit = 0x2000209; const int opcodeResetActors = 0x20002f4; const int opcodeFixme = 0x2000302; + const int opcodeGetDistance = 0x200031e; + const int opcodeGetDistanceExplicit = 0x200031f; } namespace User diff --git a/components/interpreter/docs/vmformat.txt b/components/interpreter/docs/vmformat.txt index 5d1eba088..b5c9cf0ae 100644 --- a/components/interpreter/docs/vmformat.txt +++ b/components/interpreter/docs/vmformat.txt @@ -96,27 +96,14 @@ op 34: compare (float) stack[1] with stack[0]; pop twice; push 1 if lesser than op 35: compare (float) stack[1] with stack[0]; pop twice; push 1 if lesser or equal, 0 else op 36: compare (float) stack[1] with stack[0]; pop twice; push 1 if greater than, 0 else op 37: compare (float) stack[1] with stack[0]; pop twice; push 1 if greater or equal, 0 else -op 38: push 1 if game is in menu mode, 0 else +opcode 38 unused op 39: store stack[0] in global short stack[1] and pop twice op 40: store stack[0] in global long stack[1] and pop twice op 41: store stack[0] in global float stack[1] and pop twice op 42: replace stack[0] with global short stack[0] op 43: replace stack[0] with global long stack[0] op 44: replace stack[0] with global float stack[0] -op 45: replace stack[0] with a random integer value in the range [0, stack[0]-1] -op 46: replace stack[0] with 1, if global script stack[0] is running, 0 else -op 47: start script stack[0] and pop -op 48: stop script stack[0] and pop -op 49: replace stack[0] with distance between implicit reference and a reference of ID stack[0] -op 50: push frame duration (float) -op 51: enable implicit reference -op 52: disable implicit reference -op 53: push 1, if implicit reference is disabled, 0 else -op 54: explicit reference = stack[0]; pop; enable explicit reference -op 55: explicit reference = stack[0]; pop; disable explicit reference -op 56: explicit reference = stack[0]; pop; push 1, if explicit reference is disabled, 0 else -op 57: explicit reference = stack[0]; pop; - replace stack[0] with distance between explicit reference and a reference of ID stack[0] +opcodes 45-57 unused op 58: report string literal index in stack[0]; additional arguments (if any) in stack[n]..stack[1]; n is determined according to the message string @@ -133,6 +120,5 @@ op 67: store stack[0] in member float stack[2] of global script with ID stack[1] op 68: replace stack[0] with member short stack[1] of global script with ID stack[0] op 69: replace stack[0] with member short stack[1] of global script with ID stack[0] op 70: replace stack[0] with member short stack[1] of global script with ID stack[0] -op 71: explicit reference (target) = stack[0]; pop; start script stack[0] and pop -opcodes 72-33554431 unused +opcodes 71-33554431 unused opcodes 33554432-67108863 reserved for extensions From e8ec62b298b1198f9cb14d63e83c8e4cee9d8794 Mon Sep 17 00:00:00 2001 From: Fanael Linithien Date: Sun, 24 May 2020 16:49:20 +0200 Subject: [PATCH 28/45] Use all-lowercase names for windows API headers This allows the code to successfully cross-compile from hosts with case sensitive file names, like linux. --- components/files/windowspath.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/files/windowspath.cpp b/components/files/windowspath.cpp index 7f15a7efe..92d1a9ff0 100644 --- a/components/files/windowspath.cpp +++ b/components/files/windowspath.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include namespace bconv = boost::locale::conv; From 51c0806a31d631a18d59ec3ac65e8a3aff8ddd73 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sat, 23 May 2020 23:12:56 +0300 Subject: [PATCH 29/45] Use AppliedOnce flag in more effect duration calculations (#5425) --- CHANGELOG.md | 1 + apps/openmw/mwgui/widgets.cpp | 3 +++ apps/openmw/mwmechanics/autocalcspell.cpp | 2 ++ apps/openmw/mwmechanics/spellcasting.cpp | 11 +++++++---- apps/openmw/mwmechanics/spellpriority.cpp | 3 ++- apps/openmw/mwmechanics/spellutil.cpp | 3 +++ 6 files changed, 18 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 285301a1d..369fe0470 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ Bug #5415: Environment maps in ebony cuirass and HiRez Armors Indoril cuirass don't work Bug #5416: Junk non-node records before the root node are not handled gracefully Bug #5424: Creatures do not headtrack player + Bug #5425: Poison effect only appears for one frame Bug #5427: GetDistance unknown ID error is misleading Feature #5362: Show the soul gems' trapped soul in count dialog diff --git a/apps/openmw/mwgui/widgets.cpp b/apps/openmw/mwgui/widgets.cpp index 0568efeb4..74076641a 100644 --- a/apps/openmw/mwgui/widgets.cpp +++ b/apps/openmw/mwgui/widgets.cpp @@ -443,6 +443,9 @@ namespace MWGui // constant effects have no duration and no target if (!mEffectParams.mIsConstant) { + if (!(magicEffect->mData.mFlags & ESM::MagicEffect::AppliedOnce)) + mEffectParams.mDuration = std::max(1, mEffectParams.mDuration); + if (mEffectParams.mDuration > 0 && !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) { spellLine += " " + MWBase::Environment::get().getWindowManager()->getGameSettingString("sfor", "") + " " + MyGUI::utility::toString(mEffectParams.mDuration) + ((mEffectParams.mDuration == 1) ? sec : secs); diff --git a/apps/openmw/mwmechanics/autocalcspell.cpp b/apps/openmw/mwmechanics/autocalcspell.cpp index 6d3090918..9cee1aa31 100644 --- a/apps/openmw/mwmechanics/autocalcspell.cpp +++ b/apps/openmw/mwmechanics/autocalcspell.cpp @@ -262,6 +262,8 @@ namespace MWMechanics int duration = 0; if (!(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration)) duration = effect.mDuration; + if (!(magicEffect->mData.mFlags & ESM::MagicEffect::AppliedOnce)) + duration = std::max(1, duration); static const float fEffectCostMult = MWBase::Environment::get().getWorld()->getStore() .get().find("fEffectCostMult")->mValue.getFloat(); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 769934986..7aec5d471 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -208,10 +208,15 @@ namespace MWMechanics } bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration); - if (hasDuration && effectIt->mDuration == 0) + effect.mDuration = hasDuration ? static_cast(effectIt->mDuration) : 1.f; + + bool appliedOnce = magicEffect->mData.mFlags & ESM::MagicEffect::AppliedOnce; + if (!appliedOnce) + effect.mDuration = std::max(1.f, effect.mDuration); + + if (effect.mDuration == 0) { // We still should add effect to list to allow GetSpellEffects to detect this spell - effect.mDuration = 0.f; appliedLastingEffects.push_back(effect); // duration 0 means apply full magnitude instantly @@ -224,8 +229,6 @@ namespace MWMechanics } else { - effect.mDuration = hasDuration ? static_cast(effectIt->mDuration) : 1.f; - effect.mTimeLeft = effect.mDuration; targetEffects.add(MWMechanics::EffectKey(*effectIt), MWMechanics::EffectParam(effect.mMagnitude)); diff --git a/apps/openmw/mwmechanics/spellpriority.cpp b/apps/openmw/mwmechanics/spellpriority.cpp index 9428beafc..81658193d 100644 --- a/apps/openmw/mwmechanics/spellpriority.cpp +++ b/apps/openmw/mwmechanics/spellpriority.cpp @@ -394,8 +394,9 @@ namespace MWMechanics priority = 10; const MWMechanics::CreatureStats& stats = actor.getClass().getCreatureStats(actor); const DynamicStat& current = stats.getDynamic(effect.mEffectID - ESM::MagicEffect::RestoreHealth); + // NB: this currently assumes the hardcoded magic effect flags are used const float magnitude = (effect.mMagnMin + effect.mMagnMax)/2.f; - const float toHeal = magnitude * effect.mDuration; + const float toHeal = magnitude * std::max(1, effect.mDuration); // Effect doesn't heal more than we need, *or* we are below 1/2 health if (current.getModified() - current.getCurrent() > toHeal || current.getCurrent() < current.getModified()*0.5) diff --git a/apps/openmw/mwmechanics/spellutil.cpp b/apps/openmw/mwmechanics/spellutil.cpp index def3bbbc8..bb4953e48 100644 --- a/apps/openmw/mwmechanics/spellutil.cpp +++ b/apps/openmw/mwmechanics/spellutil.cpp @@ -31,9 +31,12 @@ namespace MWMechanics magicEffect = store.get().find(effect.mEffectID); bool hasMagnitude = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoMagnitude); bool hasDuration = !(magicEffect->mData.mFlags & ESM::MagicEffect::NoDuration); + bool appliedOnce = magicEffect->mData.mFlags & ESM::MagicEffect::AppliedOnce; int minMagn = hasMagnitude ? effect.mMagnMin : 1; int maxMagn = hasMagnitude ? effect.mMagnMax : 1; int duration = hasDuration ? effect.mDuration : 1; + if (!appliedOnce) + duration = std::max(1, duration); static const float fEffectCostMult = store.get().find("fEffectCostMult")->mValue.getFloat(); float x = 0.5 * (std::max(1, minMagn) + std::max(1, maxMagn)); From 89a2c69a61c028302c59c86f46c34d93cbcb82bc Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 25 May 2020 23:51:15 +0300 Subject: [PATCH 30/45] Support particle node transformations --- components/nifosg/nifloader.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index e3c6d823f..5b9d0698d 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -496,14 +496,6 @@ namespace NifOsg switch (nifNode->recType) { - case Nif::RC_NiAutoNormalParticles: - case Nif::RC_NiRotatingParticles: - // Leaf nodes in the NIF hierarchy, so won't be able to dynamically attach children. - // No support for keyframe controllers (just crashes in the original engine). - if (nifNode->trafo.isIdentity()) - node = new osg::Group; - dataVariance = osg::Object::STATIC; - break; case Nif::RC_NiBillboardNode: dataVariance = osg::Object::DYNAMIC; break; From e3df170a53def32cefcad3ad527f66d1913d2865 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 26 May 2020 10:58:24 +0400 Subject: [PATCH 31/45] Fix mControlsDisabled flag usage --- apps/openmw/mwbase/inputmanager.hpp | 2 ++ apps/openmw/mwinput/controllermanager.cpp | 10 ++++------ apps/openmw/mwinput/controllermanager.hpp | 3 +-- apps/openmw/mwinput/inputmanagerimp.cpp | 8 +++++--- apps/openmw/mwinput/inputmanagerimp.hpp | 3 +++ apps/openmw/mwinput/keyboardmanager.cpp | 6 +++--- apps/openmw/mwinput/keyboardmanager.hpp | 4 ---- apps/openmw/mwinput/mousemanager.cpp | 12 +++++------- apps/openmw/mwinput/mousemanager.hpp | 3 +-- 9 files changed, 24 insertions(+), 27 deletions(-) diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index 932463e97..951b5053a 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -76,6 +76,8 @@ namespace MWBase virtual void resetIdleTime() = 0; virtual void executeAction(int action) = 0; + + virtual bool controlsDisabled() = 0; }; } diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index a71c5b31a..50a169c5c 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -36,7 +36,6 @@ namespace MWInput , mSneakToggleShortcutTimer(0.f) , mGamepadZoom(0) , mGamepadGuiCursorEnabled(true) - , mControlsDisabled(false) , mJoystickLastUsed(false) , mSneakGamepadShortcut(false) , mGamepadPreviewMode(false) @@ -83,9 +82,8 @@ namespace MWInput } } - bool ControllerManager::update(float dt, bool disableControls) + bool ControllerManager::update(float dt) { - mControlsDisabled = disableControls; mGamepadPreviewMode = mActionManager->getPreviewDelay() == 1.f; if (mGuiCursorEnabled && !(mJoystickLastUsed && !mGamepadGuiCursorEnabled)) @@ -232,7 +230,7 @@ namespace MWInput auto kc = sdlKeyToMyGUI(SDLK_ESCAPE); mBindingsManager->setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyPress(kc, 0)); - if (!mControlsDisabled) + if (!MWBase::Environment::get().getInputManager()->controlsDisabled()) mBindingsManager->controllerButtonPressed(deviceID, arg); } @@ -244,7 +242,7 @@ namespace MWInput return; } - if (!mJoystickEnabled || mControlsDisabled) + if (!mJoystickEnabled || MWBase::Environment::get().getInputManager()->controlsDisabled()) return; mJoystickLastUsed = true; @@ -275,7 +273,7 @@ namespace MWInput void ControllerManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg) { - if (!mJoystickEnabled || mControlsDisabled) + if (!mJoystickEnabled || MWBase::Environment::get().getInputManager()->controlsDisabled()) return; mJoystickLastUsed = true; diff --git a/apps/openmw/mwinput/controllermanager.hpp b/apps/openmw/mwinput/controllermanager.hpp index 6b9546b0c..94faff088 100644 --- a/apps/openmw/mwinput/controllermanager.hpp +++ b/apps/openmw/mwinput/controllermanager.hpp @@ -23,7 +23,7 @@ namespace MWInput virtual ~ControllerManager() = default; - bool update(float dt, bool disableControls); + bool update(float dt); virtual void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg); virtual void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg); @@ -56,7 +56,6 @@ namespace MWInput float mSneakToggleShortcutTimer; float mGamepadZoom; bool mGamepadGuiCursorEnabled; - bool mControlsDisabled; bool mJoystickLastUsed; bool mGuiCursorEnabled; bool mSneakGamepadShortcut; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 48e1581be..044f50668 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -31,6 +31,7 @@ namespace MWInput const std::string& userFile, bool userFileExists, const std::string& userControllerBindingsFile, const std::string& controllerBindingsFile, bool grab) : mGrabCursor(Settings::Manager::getBool("grab cursor", "Input")) + , mControlsDisabled(false) { mInputWrapper = new SDLUtil::InputWrapper(window, viewer, grab); mInputWrapper->setWindowEventCallback(MWBase::Environment::get().getWindowManager()); @@ -105,10 +106,11 @@ namespace MWInput void InputManager::update(float dt, bool disableControls, bool disableEvents) { + mControlsDisabled = disableControls; + mInputWrapper->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible()); mInputWrapper->capture(disableEvents); - mKeyboardManager->setControlsDisabled(disableControls); if (disableControls) { updateCursorMode(); @@ -119,8 +121,8 @@ namespace MWInput updateCursorMode(); - bool controllerMove = mControllerManager->update(dt, disableControls); - mMouseManager->update(dt, disableControls); + bool controllerMove = mControllerManager->update(dt); + mMouseManager->update(dt); mSensorManager->update(dt); mActionManager->update(dt, controllerMove); } diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 4ecb6a82d..de969d040 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -94,6 +94,8 @@ namespace MWInput virtual void executeAction(int action); + virtual bool controlsDisabled() { return mControlsDisabled; } + private: void convertMousePosForMyGUI(int& x, int& y); @@ -110,6 +112,7 @@ namespace MWInput SDLUtil::InputWrapper* mInputWrapper; bool mGrabCursor; + bool mControlsDisabled; ControlSwitch* mControlSwitch; diff --git a/apps/openmw/mwinput/keyboardmanager.cpp b/apps/openmw/mwinput/keyboardmanager.cpp index 20115155e..db047a342 100644 --- a/apps/openmw/mwinput/keyboardmanager.cpp +++ b/apps/openmw/mwinput/keyboardmanager.cpp @@ -18,7 +18,6 @@ namespace MWInput { KeyboardManager::KeyboardManager(BindingsManager* bindingsManager) : mBindingsManager(bindingsManager) - , mControlsDisabled(false) { } @@ -53,10 +52,11 @@ namespace MWInput if (arg.repeat) return; - if (!mControlsDisabled && !consumed) + MWBase::InputManager* input = MWBase::Environment::get().getInputManager(); + if (!input->controlsDisabled() && !consumed) mBindingsManager->keyPressed(arg); - MWBase::Environment::get().getInputManager()->setJoystickLastUsed(false); + input->setJoystickLastUsed(false); } void KeyboardManager::keyReleased(const SDL_KeyboardEvent &arg) diff --git a/apps/openmw/mwinput/keyboardmanager.hpp b/apps/openmw/mwinput/keyboardmanager.hpp index ae473be51..b7027220f 100644 --- a/apps/openmw/mwinput/keyboardmanager.hpp +++ b/apps/openmw/mwinput/keyboardmanager.hpp @@ -19,12 +19,8 @@ namespace MWInput virtual void keyPressed(const SDL_KeyboardEvent &arg); virtual void keyReleased(const SDL_KeyboardEvent &arg); - void setControlsDisabled(bool disabled) { mControlsDisabled = disabled; } - private: BindingsManager* mBindingsManager; - - bool mControlsDisabled; }; } #endif diff --git a/apps/openmw/mwinput/mousemanager.cpp b/apps/openmw/mwinput/mousemanager.cpp index 2cce1cd80..de0ff80e0 100644 --- a/apps/openmw/mwinput/mousemanager.cpp +++ b/apps/openmw/mwinput/mousemanager.cpp @@ -33,7 +33,6 @@ namespace MWInput , mGuiCursorY(0) , mMouseWheel(0) , mMouseLookEnabled(false) - , mControlsDisabled(false) , mGuiCursorEnabled(true) { float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); @@ -88,7 +87,7 @@ namespace MWInput MWBase::Environment::get().getWindowManager()->setCursorActive(true); } - if (mMouseLookEnabled && !mControlsDisabled) + if (mMouseLookEnabled && !input->controlsDisabled()) { float x = arg.xrel * mCameraSensitivity * (mInvertX ? -1 : 1) / 256.f; float y = arg.yrel * mCameraSensitivity * (mInvertY ? -1 : 1) * mCameraYMultiplier / 256.f; @@ -136,10 +135,11 @@ namespace MWInput void MouseManager::mouseWheelMoved(const SDL_MouseWheelEvent &arg) { - if (mBindingsManager->isDetectingBindingState() || !mControlsDisabled) + MWBase::InputManager* input = MWBase::Environment::get().getInputManager(); + if (mBindingsManager->isDetectingBindingState() || !input->controlsDisabled()) mBindingsManager->mouseWheelMoved(arg); - MWBase::Environment::get().getInputManager()->setJoystickLastUsed(false); + input->setJoystickLastUsed(false); } void MouseManager::mousePressed(const SDL_MouseButtonEvent &arg, Uint8 id) @@ -169,10 +169,8 @@ namespace MWInput mBindingsManager->mousePressed(arg, id); } - void MouseManager::update(float dt, bool disableControls) + void MouseManager::update(float dt) { - mControlsDisabled = disableControls; - if (!mMouseLookEnabled) return; diff --git a/apps/openmw/mwinput/mousemanager.hpp b/apps/openmw/mwinput/mousemanager.hpp index 58d97f6e5..aea07c8db 100644 --- a/apps/openmw/mwinput/mousemanager.hpp +++ b/apps/openmw/mwinput/mousemanager.hpp @@ -20,7 +20,7 @@ namespace MWInput virtual ~MouseManager() = default; - void update(float dt, bool disableControls); + void update(float dt); virtual void mouseMoved(const SDLUtil::MouseMotionEvent &arg); virtual void mousePressed(const SDL_MouseButtonEvent &arg, Uint8 id); @@ -51,7 +51,6 @@ namespace MWInput float mGuiCursorY; int mMouseWheel; bool mMouseLookEnabled; - bool mControlsDisabled; bool mGuiCursorEnabled; }; } From fc9a10ba489278facc29dc993f3233f63bae76b8 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 26 May 2020 00:33:19 +0300 Subject: [PATCH 32/45] Streamline node controller handling Reduce code duplication Allow non-animated nodes controlled by NiVisController to be optimized out --- components/nifosg/nifloader.cpp | 136 ++++++++++---------------------- 1 file changed, 42 insertions(+), 94 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 5b9d0698d..c6a79333d 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -512,17 +512,9 @@ namespace NifOsg // This takes advantage of the fact root nodes can't have additional controllers // loaded from an external .kf file (original engine just throws "can't find node" errors if you try). if (!nifNode->parent && nifNode->controller.empty() && nifNode->trafo.isIdentity()) - { node = new osg::Group; - dataVariance = osg::Object::STATIC; - } - else - { - dataVariance = (nifNode->controller.empty() ? osg::Object::STATIC : osg::Object::DYNAMIC); - } - if (nifNode->isBone) - dataVariance = osg::Object::DYNAMIC; + dataVariance = nifNode->isBone ? osg::Object::DYNAMIC : osg::Object::STATIC; break; } @@ -535,7 +527,7 @@ namespace NifOsg } osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::ImageManager* imageManager, - std::vector boundTextures, int animflags, bool skipMeshes, bool hasMarkers, bool isAnimated, TextKeyMap* textKeys, osg::Node* rootNode=nullptr) + std::vector boundTextures, int animflags, bool skipMeshes, bool hasMarkers, bool hasAnimatedParents, TextKeyMap* textKeys, osg::Node* rootNode=nullptr) { if (rootNode != nullptr && Misc::StringUtils::ciEqual(nifNode->name, "Bounding Box")) return nullptr; @@ -547,9 +539,6 @@ namespace NifOsg node->addCullCallback(new BillboardCallback); } - if (!nifNode->controller.empty() && nifNode->controller->recType == Nif::RC_NiKeyframeController) - isAnimated = true; - node->setName(nifNode->name); if (parentNode) @@ -619,16 +608,6 @@ namespace NifOsg node->setNodeMask(Loader::getHiddenNodeMask()); } - if ((skipMeshes || hasMarkers) && isAnimated) // make sure the empty node is not optimized away so the physicssystem can find it. - { - node->setDataVariance(osg::Object::DYNAMIC); - } - - if ((nifNode->recType == Nif::RC_NiTriShape || nifNode->recType == Nif::RC_NiTriStrips) && isAnimated) // Same thing for animated shapes - { - node->setDataVariance(osg::Object::DYNAMIC); - } - osg::ref_ptr composite = new SceneUtil::CompositeStateSetUpdater; applyNodeProperties(nifNode, node, composite, imageManager, boundTextures, animflags); @@ -660,9 +639,12 @@ namespace NifOsg if (composite->getNumControllers() > 0) node->addUpdateCallback(composite); - if (nifNode->recType != Nif::RC_NiTriShape && nifNode->recType != Nif::RC_NiTriStrips - && !nifNode->controller.empty() && node->getDataVariance() == osg::Object::DYNAMIC) - handleNodeControllers(nifNode, static_cast(node.get()), animflags); + bool isAnimated = false; + handleNodeControllers(nifNode, node, animflags, isAnimated); + hasAnimatedParents |= isAnimated; + // Make sure empty nodes are not optimized away so the physics system can find them. + if (isAnimated || (hasAnimatedParents && (skipMeshes || hasMarkers))) + node->setDataVariance(osg::Object::DYNAMIC); // LOD and Switch nodes must be wrapped by a transform (the current node) to support transformations properly // and we need to attach their children to the osg::LOD/osg::Switch nodes @@ -703,7 +685,7 @@ namespace NifOsg for(size_t i = 0;i < children.length();++i) { if(!children[i].empty()) - handleNode(children[i].getPtr(), currentNode, imageManager, boundTextures, animflags, skipMeshes, hasMarkers, isAnimated, textKeys, rootNode); + handleNode(children[i].getPtr(), currentNode, imageManager, boundTextures, animflags, skipMeshes, hasMarkers, hasAnimatedParents, textKeys, rootNode); } } @@ -734,40 +716,10 @@ namespace NifOsg setupController(niuvctrl, uvctrl, animflags); composite->addController(uvctrl); } - else if (ctrl->recType == Nif::RC_NiKeyframeController) - { - const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); - if(!key->data.empty()) - { - osg::ref_ptr callback(new KeyframeController(key->data.getPtr())); - - setupController(key, callback, animflags); - node->addUpdateCallback(callback); - } - } - else if (ctrl->recType == Nif::RC_NiPathController) - { - const Nif::NiPathController *path = static_cast(ctrl.getPtr()); - if (!path->posData.empty() && !path->floatData.empty()) - { - osg::ref_ptr callback(new PathController(path)); - - setupController(path, callback, animflags); - node->addUpdateCallback(callback); - } - } - else if (ctrl->recType == Nif::RC_NiVisController) - { - handleVisController(static_cast(ctrl.getPtr()), node, animflags); - } - else if(ctrl->recType == Nif::RC_NiGeomMorpherController) - {} // handled in handleTriShape - else - Log(Debug::Info) << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename; } } - void handleNodeControllers(const Nif::Node* nifNode, osg::MatrixTransform* transformNode, int animflags) + void handleNodeControllers(const Nif::Node* nifNode, osg::Node* node, int animflags, bool& isAnimated) { for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { @@ -776,56 +728,54 @@ namespace NifOsg if (ctrl->recType == Nif::RC_NiKeyframeController) { const Nif::NiKeyframeController *key = static_cast(ctrl.getPtr()); - if(!key->data.empty()) - { - osg::ref_ptr callback(new KeyframeController(key->data.getPtr())); - - setupController(key, callback, animflags); - transformNode->addUpdateCallback(callback); - } + if (key->data.empty()) + continue; + osg::ref_ptr callback(new KeyframeController(key->data.getPtr())); + setupController(key, callback, animflags); + node->addUpdateCallback(callback); + isAnimated = true; } else if (ctrl->recType == Nif::RC_NiPathController) { const Nif::NiPathController *path = static_cast(ctrl.getPtr()); - if (!path->posData.empty() && !path->floatData.empty()) - { - osg::ref_ptr callback(new PathController(path)); - - setupController(path, callback, animflags); - transformNode->addUpdateCallback(callback); - } + if (path->posData.empty() || path->floatData.empty()) + continue; + osg::ref_ptr callback(new PathController(path)); + setupController(path, callback, animflags); + node->addUpdateCallback(callback); + isAnimated = true; } else if (ctrl->recType == Nif::RC_NiVisController) { - handleVisController(static_cast(ctrl.getPtr()), transformNode, animflags); + const Nif::NiVisController *visctrl = static_cast(ctrl.getPtr()); + if (visctrl->data.empty()) + continue; + osg::ref_ptr callback(new VisController(visctrl->data.getPtr(), Loader::getHiddenNodeMask())); + setupController(visctrl, callback, animflags); + node->addUpdateCallback(callback); } else if (ctrl->recType == Nif::RC_NiRollController) { - handleRollController(static_cast(ctrl.getPtr()), transformNode, animflags); + const Nif::NiRollController *rollctrl = static_cast(ctrl.getPtr()); + if (rollctrl->data.empty()) + continue; + osg::ref_ptr callback(new RollController(rollctrl->data.getPtr())); + setupController(rollctrl, callback, animflags); + node->addUpdateCallback(callback); + isAnimated = true; + } + else if (ctrl->recType == Nif::RC_NiGeomMorpherController + || ctrl->recType == Nif::RC_NiParticleSystemController + || ctrl->recType == Nif::RC_NiBSPArrayController + || ctrl->recType == Nif::RC_NiUVController) + { + // These controllers are handled elsewhere } else Log(Debug::Info) << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename; } } - void handleVisController(const Nif::NiVisController* visctrl, osg::Node* node, int animflags) - { - if (visctrl->data.empty()) - return; - osg::ref_ptr callback(new VisController(visctrl->data.getPtr(), Loader::getHiddenNodeMask())); - setupController(visctrl, callback, animflags); - node->addUpdateCallback(callback); - } - - void handleRollController(const Nif::NiRollController* rollctrl, osg::Node* node, int animflags) - { - if (rollctrl->data.empty()) - return; - osg::ref_ptr callback(new RollController(rollctrl->data.getPtr())); - setupController(rollctrl, callback, animflags); - node->addUpdateCallback(callback); - } - void handleMaterialControllers(const Nif::Property *materialProperty, SceneUtil::CompositeStateSetUpdater* composite, int animflags) { for (Nif::ControllerPtr ctrl = materialProperty->controller; !ctrl.empty(); ctrl = ctrl->next) @@ -1062,8 +1012,6 @@ namespace NifOsg continue; if(ctrl->recType == Nif::RC_NiParticleSystemController || ctrl->recType == Nif::RC_NiBSPArrayController) partctrl = static_cast(ctrl.getPtr()); - else - Log(Debug::Info) << "Unhandled controller " << ctrl->recName << " on node " << nifNode->recIndex << " in " << mFilename; } if (!partctrl) { From 7a9403aeed428ae222c5c09948f44a27f0d0c940 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 26 May 2020 15:01:26 +0300 Subject: [PATCH 33/45] Remove unnecessary casts --- components/nifosg/nifloader.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index c6a79333d..fc5f8e1f8 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -1175,12 +1175,7 @@ namespace NifOsg osg::ref_ptr drawable; osg::ref_ptr geom (new osg::Geometry); triShapeToGeometry(nifNode, geom, parentNode, composite, boundTextures, animflags); - Nif::ControllerPtr ctrl; - if (nifNode->recType == Nif::RC_NiTriShape) - ctrl = static_cast(nifNode)->controller; - else - ctrl = static_cast(nifNode)->controller; - for (; !ctrl.empty(); ctrl = ctrl->next) + for (Nif::ControllerPtr ctrl = nifNode->controller; !ctrl.empty(); ctrl = ctrl->next) { if (!(ctrl->flags & Nif::NiNode::ControllerFlag_Active)) continue; From 74a74209acbf5eab9b7da24cf4be0f3c74b3e03d Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 26 May 2020 15:08:10 +0300 Subject: [PATCH 34/45] Allow junk (data-less) NiParticleColorModifiers --- components/nifosg/nifloader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index fc5f8e1f8..131f0c470 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -870,6 +870,8 @@ namespace NifOsg else if (affectors->recType == Nif::RC_NiParticleColorModifier) { const Nif::NiParticleColorModifier *cl = static_cast(affectors.getPtr()); + if (cl->data.empty()) + continue; const Nif::NiColorData *clrdata = cl->data.getPtr(); program->addOperator(new ParticleColorAffector(clrdata)); } From 95cd47335299c59b2109b65a7ccded07491af0c1 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Tue, 26 May 2020 17:01:45 +0300 Subject: [PATCH 35/45] Reenable weapon animation lower body animation blending in FPV (#5441) Disabling it is a non-vanilla behavior that breaks things that aren't broken in vanilla --- CHANGELOG.md | 1 + apps/openmw/mwmechanics/character.cpp | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 285301a1d..d153e9202 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ Bug #5416: Junk non-node records before the root node are not handled gracefully Bug #5424: Creatures do not headtrack player Bug #5427: GetDistance unknown ID error is misleading + Bug #5441: Enemies can't push a player character when in critical strike stance Feature #5362: Show the soul gems' trapped soul in count dialog 0.46.0 diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index ac8d417f3..0a332a10c 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1260,10 +1260,9 @@ bool CharacterController::updateWeaponState(CharacterState& idle) } } - // Use blending only with 3d-person movement animations for bipedal actors - bool firstPersonPlayer = (mPtr == MWMechanics::getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson()); + // For biped actors, blend weapon animations with lower body animations with higher priority MWRender::Animation::AnimPriority priorityWeapon(Priority_Weapon); - if (!firstPersonPlayer && mPtr.getClass().isBipedal(mPtr)) + if (mPtr.getClass().isBipedal(mPtr)) priorityWeapon[MWRender::Animation::BoneGroup_LowerBody] = Priority_WeaponLowerBody; bool forcestateupdate = false; From b00d72b9e4905672d9327354cc1839f8a555c2ed Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 26 May 2020 11:24:47 +0400 Subject: [PATCH 36/45] Move cursor update to the MouseManager --- apps/openmw/mwinput/inputmanagerimp.cpp | 36 +++---------------------- apps/openmw/mwinput/inputmanagerimp.hpp | 3 --- apps/openmw/mwinput/mousemanager.cpp | 31 +++++++++++++++++++-- apps/openmw/mwinput/mousemanager.hpp | 2 ++ 4 files changed, 34 insertions(+), 38 deletions(-) diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 044f50668..79541fbe4 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -30,8 +30,7 @@ namespace MWInput osgViewer::ScreenCaptureHandler::CaptureOperation *screenCaptureOperation, const std::string& userFile, bool userFileExists, const std::string& userControllerBindingsFile, const std::string& controllerBindingsFile, bool grab) - : mGrabCursor(Settings::Manager::getBool("grab cursor", "Input")) - , mControlsDisabled(false) + : mControlsDisabled(false) { mInputWrapper = new SDLUtil::InputWrapper(window, viewer, grab); mInputWrapper->setWindowEventCallback(MWBase::Environment::get().getWindowManager()); @@ -81,29 +80,6 @@ namespace MWInput mActionManager->setAttemptJump(jumping); } - void InputManager::updateCursorMode() - { - bool grab = !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) - && !MWBase::Environment::get().getWindowManager()->isConsoleMode(); - - bool wasRelative = mInputWrapper->getMouseRelative(); - bool isRelative = !MWBase::Environment::get().getWindowManager()->isGuiMode(); - - // don't keep the pointer away from the window edge in gui mode - // stop using raw mouse motions and switch to system cursor movements - mInputWrapper->setMouseRelative(isRelative); - - //we let the mouse escape in the main menu - mInputWrapper->setGrabPointer(grab && (mGrabCursor || isRelative)); - - //we switched to non-relative mode, move our cursor to where the in-game - //cursor is - if (!isRelative && wasRelative != isRelative) - { - mMouseManager->warpMouse(); - } - } - void InputManager::update(float dt, bool disableControls, bool disableEvents) { mControlsDisabled = disableControls; @@ -113,13 +89,13 @@ namespace MWInput if (disableControls) { - updateCursorMode(); + mMouseManager->updateCursorMode(); return; } mBindingsManager->update(dt); - updateCursorMode(); + mMouseManager->updateCursorMode(); bool controllerMove = mControllerManager->update(dt); mMouseManager->update(dt); @@ -153,12 +129,6 @@ namespace MWInput void InputManager::processChangedSettings(const Settings::CategorySettingVector& changed) { - for (const auto& setting : changed) - { - if (setting.first == "Input" && setting.second == "grab cursor") - mGrabCursor = Settings::Manager::getBool("grab cursor", "Input"); - } - mMouseManager->processChangedSettings(changed); mSensorManager->processChangedSettings(changed); } diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index de969d040..debbf27e0 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -101,8 +101,6 @@ namespace MWInput void handleGuiArrowKey(int action); - void updateCursorMode(); - void quickKey(int index); void showQuickKeysMenu(); @@ -111,7 +109,6 @@ namespace MWInput SDLUtil::InputWrapper* mInputWrapper; - bool mGrabCursor; bool mControlsDisabled; ControlSwitch* mControlSwitch; diff --git a/apps/openmw/mwinput/mousemanager.cpp b/apps/openmw/mwinput/mousemanager.cpp index de0ff80e0..df38868e1 100644 --- a/apps/openmw/mwinput/mousemanager.cpp +++ b/apps/openmw/mwinput/mousemanager.cpp @@ -24,8 +24,9 @@ namespace MWInput MouseManager::MouseManager(BindingsManager* bindingsManager, SDLUtil::InputWrapper* inputWrapper, SDL_Window* window) : mInvertX(Settings::Manager::getBool("invert x axis", "Input")) , mInvertY(Settings::Manager::getBool("invert y axis", "Input")) - , mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input")) - , mCameraYMultiplier (Settings::Manager::getFloat("camera y multiplier", "Input")) + , mGrabCursor(Settings::Manager::getBool("grab cursor", "Input")) + , mCameraSensitivity(Settings::Manager::getFloat("camera sensitivity", "Input")) + , mCameraYMultiplier(Settings::Manager::getFloat("camera y multiplier", "Input")) , mBindingsManager(bindingsManager) , mInputWrapper(inputWrapper) , mInvUiScalingFactor(1.f) @@ -58,6 +59,9 @@ namespace MWInput if (setting.first == "Input" && setting.second == "camera sensitivity") mCameraSensitivity = Settings::Manager::getFloat("camera sensitivity", "Input"); + + if (setting.first == "Input" && setting.second == "grab cursor") + mGrabCursor = Settings::Manager::getBool("grab cursor", "Input"); } } @@ -169,6 +173,29 @@ namespace MWInput mBindingsManager->mousePressed(arg, id); } + void MouseManager::updateCursorMode() + { + bool grab = !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) + && !MWBase::Environment::get().getWindowManager()->isConsoleMode(); + + bool wasRelative = mInputWrapper->getMouseRelative(); + bool isRelative = !MWBase::Environment::get().getWindowManager()->isGuiMode(); + + // don't keep the pointer away from the window edge in gui mode + // stop using raw mouse motions and switch to system cursor movements + mInputWrapper->setMouseRelative(isRelative); + + //we let the mouse escape in the main menu + mInputWrapper->setGrabPointer(grab && (mGrabCursor || isRelative)); + + //we switched to non-relative mode, move our cursor to where the in-game + //cursor is + if (!isRelative && wasRelative != isRelative) + { + warpMouse(); + } + } + void MouseManager::update(float dt) { if (!mMouseLookEnabled) diff --git a/apps/openmw/mwinput/mousemanager.hpp b/apps/openmw/mwinput/mousemanager.hpp index aea07c8db..0f523591a 100644 --- a/apps/openmw/mwinput/mousemanager.hpp +++ b/apps/openmw/mwinput/mousemanager.hpp @@ -20,6 +20,7 @@ namespace MWInput virtual ~MouseManager() = default; + void updateCursorMode(); void update(float dt); virtual void mouseMoved(const SDLUtil::MouseMotionEvent &arg); @@ -40,6 +41,7 @@ namespace MWInput private: bool mInvertX; bool mInvertY; + bool mGrabCursor; float mCameraSensitivity; float mCameraYMultiplier; From 000e44a18ecf190608efab7ba320782c5828da5f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 26 May 2020 16:45:08 +0400 Subject: [PATCH 37/45] Move data from WindowManager to CharacterCreation to simplify API --- apps/openmw/mwbase/windowmanager.hpp | 6 --- apps/openmw/mwgui/charactercreation.cpp | 63 +++++++++++----------- apps/openmw/mwgui/charactercreation.hpp | 5 ++ apps/openmw/mwgui/windowmanagerimp.cpp | 69 ------------------------- apps/openmw/mwgui/windowmanagerimp.hpp | 14 ----- 5 files changed, 38 insertions(+), 119 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 2639fe590..4fa782b8f 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -253,12 +253,6 @@ namespace MWBase virtual void onFrame (float frameDuration) = 0; - /// \todo get rid of this stuff. Move it to the respective UI element classes, if needed. - virtual std::map getPlayerSkillValues() = 0; - virtual std::map getPlayerAttributeValues() = 0; - virtual SkillList getPlayerMinorSkills() = 0; - virtual SkillList getPlayerMajorSkills() = 0; - /** * Fetches a GMST string from the store, if there is no setting with the given * ID or it is not a string the default string is returned. diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 44376b87a..54e1a69a4 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -105,23 +105,32 @@ namespace MWGui mGenerateClassSpecializations[0] = 0; mGenerateClassSpecializations[1] = 0; mGenerateClassSpecializations[2] = 0; + + // Setup player stats + for (int i = 0; i < ESM::Attribute::Length; ++i) + mPlayerAttributes.emplace(ESM::Attribute::sAttributeIds[i], MWMechanics::AttributeValue()); + + for (int i = 0; i < ESM::Skill::Length; ++i) + mPlayerSkillValues.emplace(ESM::Skill::sSkillIds[i], MWMechanics::SkillValue()); } void CharacterCreation::setValue (const std::string& id, const MWMechanics::AttributeValue& value) { - if (mReviewDialog) + static const char *ids[] = { - static const char *ids[] = - { - "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", - "AttribVal6", "AttribVal7", "AttribVal8", - 0 - }; + "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", + "AttribVal5", "AttribVal6", "AttribVal7", "AttribVal8", 0 + }; - for (int i=0; ids[i]; ++i) + for (int i=0; ids[i]; ++i) + { + if (ids[i]==id) { - if (ids[i]==id) - mReviewDialog->setAttribute(ESM::Attribute::AttributeID(i), value); + mPlayerAttributes[static_cast(i)] = value; + if (mReviewDialog) + mReviewDialog->setAttribute(static_cast(i), value); + + break; } } } @@ -147,6 +156,7 @@ namespace MWGui void CharacterCreation::setValue(const ESM::Skill::SkillEnum parSkill, const MWMechanics::SkillValue& value) { + mPlayerSkillValues[parSkill] = value; if (mReviewDialog) mReviewDialog->setSkillValue(parSkill, value); } @@ -155,6 +165,9 @@ namespace MWGui { if (mReviewDialog) mReviewDialog->configureSkills(major, minor); + + mPlayerMajorSkills = major; + mPlayerMinorSkills = minor; } void CharacterCreation::onFrame(float duration) @@ -269,31 +282,21 @@ namespace MWGui mReviewDialog->setClass(*playerClass); mReviewDialog->setBirthSign(player.getBirthSign()); - { - MWWorld::Ptr playerPtr = MWMechanics::getPlayer(); - const MWMechanics::CreatureStats& stats = playerPtr.getClass().getCreatureStats(playerPtr); - - mReviewDialog->setHealth ( stats.getHealth() ); - mReviewDialog->setMagicka( stats.getMagicka() ); - mReviewDialog->setFatigue( stats.getFatigue() ); - } + MWWorld::Ptr playerPtr = MWMechanics::getPlayer(); + const MWMechanics::CreatureStats& stats = playerPtr.getClass().getCreatureStats(playerPtr); + mReviewDialog->setHealth(stats.getHealth()); + mReviewDialog->setMagicka(stats.getMagicka()); + mReviewDialog->setFatigue(stats.getFatigue()); + for (auto& attributePair : mPlayerAttributes) { - std::map attributes = MWBase::Environment::get().getWindowManager()->getPlayerAttributeValues(); - for (auto& attributePair : attributes) - { - mReviewDialog->setAttribute(static_cast (attributePair.first), attributePair.second); - } + mReviewDialog->setAttribute(static_cast (attributePair.first), attributePair.second); } - + for (auto& skillPair : mPlayerSkillValues) { - std::map skills = MWBase::Environment::get().getWindowManager()->getPlayerSkillValues(); - for (auto& skillPair : skills) - { - mReviewDialog->setSkillValue(static_cast (skillPair.first), skillPair.second); - } - mReviewDialog->configureSkills(MWBase::Environment::get().getWindowManager()->getPlayerMajorSkills(), MWBase::Environment::get().getWindowManager()->getPlayerMinorSkills()); + mReviewDialog->setSkillValue(static_cast (skillPair.first), skillPair.second); } + mReviewDialog->configureSkills(mPlayerMajorSkills, mPlayerMinorSkills); mReviewDialog->eventDone += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogDone); mReviewDialog->eventBack += MyGUI::newDelegate(this, &CharacterCreation::onReviewDialogBack); diff --git a/apps/openmw/mwgui/charactercreation.hpp b/apps/openmw/mwgui/charactercreation.hpp index d5739c3d0..4f6296785 100644 --- a/apps/openmw/mwgui/charactercreation.hpp +++ b/apps/openmw/mwgui/charactercreation.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include "../mwmechanics/stat.hpp" @@ -56,6 +57,10 @@ namespace MWGui osg::Group* mParent; Resource::ResourceSystem* mResourceSystem; + SkillList mPlayerMajorSkills, mPlayerMinorSkills; + std::map mPlayerAttributes; + std::map mPlayerSkillValues; + //Dialogs TextInputDialog* mNameDialog; RaceDialog* mRaceDialog; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 1d2dc185b..bcd878d34 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -182,12 +182,6 @@ namespace MWGui , mCursorVisible(true) , mCursorActive(false) , mPlayerBounty(-1) - , mPlayerName() - , mPlayerRaceId() - , mPlayerAttributes() - , mPlayerMajorSkills() - , mPlayerMinorSkills() - , mPlayerSkillValues() , mGui(nullptr) , mGuiModes() , mCursorManager(nullptr) @@ -594,17 +588,6 @@ namespace MWGui mCharGen = new CharacterCreation(mViewer->getSceneData()->asGroup(), mResourceSystem); - // Setup player stats - for (int i = 0; i < ESM::Attribute::Length; ++i) - { - mPlayerAttributes.insert(std::make_pair(ESM::Attribute::sAttributeIds[i], MWMechanics::AttributeValue())); - } - - for (int i = 0; i < ESM::Skill::Length; ++i) - { - mPlayerSkillValues.insert(std::make_pair(ESM::Skill::sSkillIds[i], MWMechanics::SkillValue())); - } - updatePinnedWindows(); // Set up visibility @@ -797,40 +780,14 @@ namespace MWGui { mStatsWindow->setValue (id, value); mCharGen->setValue(id, value); - - static const char *ids[] = - { - "AttribVal1", "AttribVal2", "AttribVal3", "AttribVal4", "AttribVal5", - "AttribVal6", "AttribVal7", "AttribVal8" - }; - static ESM::Attribute::AttributeID attributes[] = - { - ESM::Attribute::Strength, - ESM::Attribute::Intelligence, - ESM::Attribute::Willpower, - ESM::Attribute::Agility, - ESM::Attribute::Speed, - ESM::Attribute::Endurance, - ESM::Attribute::Personality, - ESM::Attribute::Luck - }; - for (size_t i = 0; i < sizeof(ids)/sizeof(ids[0]); ++i) - { - if (id != ids[i]) - continue; - mPlayerAttributes[attributes[i]] = value; - break; - } } - void WindowManager::setValue (int parSkill, const MWMechanics::SkillValue& value) { /// \todo Don't use the skill enum as a parameter type (we will have to drop it anyway, once we /// allow custom skills. mStatsWindow->setValue(static_cast (parSkill), value); mCharGen->setValue(static_cast (parSkill), value); - mPlayerSkillValues[parSkill] = value; } void WindowManager::setValue (const std::string& id, const MWMechanics::DynamicStat& value) @@ -843,10 +800,6 @@ namespace MWGui void WindowManager::setValue (const std::string& id, const std::string& value) { mStatsWindow->setValue (id, value); - if (id=="name") - mPlayerName = value; - else if (id=="race") - mPlayerRaceId = value; } void WindowManager::setValue (const std::string& id, int value) @@ -868,8 +821,6 @@ namespace MWGui { mStatsWindow->configureSkills (major, minor); mCharGen->configureSkills(major, minor); - mPlayerMajorSkills = major; - mPlayerMinorSkills = minor; } void WindowManager::updateSkillArea() @@ -1639,26 +1590,6 @@ namespace MWGui return mGuiModes.back(); } - std::map WindowManager::getPlayerSkillValues() - { - return mPlayerSkillValues; - } - - std::map WindowManager::getPlayerAttributeValues() - { - return mPlayerAttributes; - } - - WindowManager::SkillList WindowManager::getPlayerMinorSkills() - { - return mPlayerMinorSkills; - } - - WindowManager::SkillList WindowManager::getPlayerMajorSkills() - { - return mPlayerMajorSkills; - } - void WindowManager::disallowMouse() { mInputBlocker->setVisible (true); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 8b16cf25f..22f407c2b 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -282,12 +282,6 @@ namespace MWGui virtual void onFrame (float frameDuration); - /// \todo get rid of this stuff. Move it to the respective UI element classes, if needed. - virtual std::map getPlayerSkillValues(); - virtual std::map getPlayerAttributeValues(); - virtual SkillList getPlayerMinorSkills(); - virtual SkillList getPlayerMajorSkills(); - /** * Fetches a GMST string from the store, if there is no setting with the given * ID or it is not a string the default string is returned. @@ -474,14 +468,6 @@ namespace MWGui void setCursorVisible(bool visible); - /// \todo get rid of this stuff. Move it to the respective UI element classes, if needed. - // Various stats about player as needed by window manager - std::string mPlayerName; - std::string mPlayerRaceId; - std::map mPlayerAttributes; - SkillList mPlayerMajorSkills, mPlayerMinorSkills; - std::map mPlayerSkillValues; - MyGUI::Gui *mGui; // Gui struct GuiModeState From dcfc4cc5dd3249af593b49d1c5a1a48cbcc3760f Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 26 May 2020 16:54:04 +0400 Subject: [PATCH 38/45] Rename onFrame() to update() to make WindowManager consistent with other managers --- apps/openmw/engine.cpp | 2 +- apps/openmw/mwbase/windowmanager.hpp | 2 +- apps/openmw/mwgui/windowmanagerimp.cpp | 2 +- apps/openmw/mwgui/windowmanagerimp.hpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 330d0e194..2ed6b424b 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -181,7 +181,7 @@ bool OMW::Engine::frame(float frametime) osg::Timer_t afterWorldTick = osg::Timer::instance()->tick(); // update GUI - mEnvironment.getWindowManager()->onFrame(frametime); + mEnvironment.getWindowManager()->update(frametime); unsigned int frameNumber = mViewer->getFrameStamp()->getFrameNumber(); osg::Stats* stats = mViewer->getViewerStats(); diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 4fa782b8f..d6afe9243 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -251,7 +251,7 @@ namespace MWBase /// returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) virtual int readPressedButton() = 0; - virtual void onFrame (float frameDuration) = 0; + virtual void update (float duration) = 0; /** * Fetches a GMST string from the store, if there is no setting with the given diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index bcd878d34..7bae74dfc 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -956,7 +956,7 @@ namespace MWGui mHud->setPlayerPos(x, y, u, v); } - void WindowManager::onFrame (float frameDuration) + void WindowManager::update (float frameDuration) { bool gameRunning = MWBase::Environment::get().getStateManager()->getState()!= MWBase::StateManager::State_NoGame; diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 22f407c2b..2de0a4ca8 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -280,7 +280,7 @@ namespace MWGui virtual int readPressedButton (); ///< returns the index of the pressed button or -1 if no button was pressed (->MessageBoxmanager->InteractiveMessageBox) - virtual void onFrame (float frameDuration); + virtual void update (float duration); /** * Fetches a GMST string from the store, if there is no setting with the given From 2ff04b4e73d317e63622829e7ff4c9d1699500ef Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Tue, 26 May 2020 17:10:56 +0400 Subject: [PATCH 39/45] Move TextColours initialization to the TextColours itself --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwgui/textcolours.cpp | 36 ++++++++++++++++++++++++++ apps/openmw/mwgui/textcolours.hpp | 5 ++-- apps/openmw/mwgui/windowmanagerimp.cpp | 32 +---------------------- 4 files changed, 41 insertions(+), 34 deletions(-) create mode 100644 apps/openmw/mwgui/textcolours.cpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 2107b74fe..68e3949ba 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -45,7 +45,7 @@ add_openmw_dir (mwgui itemmodel containeritemmodel inventoryitemmodel sortfilteritemmodel itemview tradeitemmodel companionitemmodel pickpocketitemmodel controllers savegamedialog recharge mode videowidget backgroundimage itemwidget screenfader debugwindow spellmodel spellview - draganddrop timeadvancer jailscreen itemchargeview keyboardnavigation + draganddrop timeadvancer jailscreen itemchargeview keyboardnavigation textcolours ) add_openmw_dir (mwdialogue diff --git a/apps/openmw/mwgui/textcolours.cpp b/apps/openmw/mwgui/textcolours.cpp new file mode 100644 index 000000000..77afa5e26 --- /dev/null +++ b/apps/openmw/mwgui/textcolours.cpp @@ -0,0 +1,36 @@ +#include "textcolours.hpp" + +#include + +#include + +namespace MWGui +{ + MyGUI::Colour getTextColour(const std::string& type) + { + return MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=" + type + "}")); + } + + void TextColours::loadColours() + { + header = getTextColour("header"); + normal = getTextColour("normal"); + notify = getTextColour("notify"); + + link = getTextColour("link"); + linkOver = getTextColour("link_over"); + linkPressed = getTextColour("link_pressed"); + + answer = getTextColour("answer"); + answerOver = getTextColour("answer_over"); + answerPressed = getTextColour("answer_pressed"); + + journalLink = getTextColour("journal_link"); + journalLinkOver = getTextColour("journal_link_over"); + journalLinkPressed = getTextColour("journal_link_pressed"); + + journalTopic = getTextColour("journal_topic"); + journalTopicOver = getTextColour("journal_topic_over"); + journalTopicPressed = getTextColour("journal_topic_pressed"); + } +} diff --git a/apps/openmw/mwgui/textcolours.hpp b/apps/openmw/mwgui/textcolours.hpp index 3fa55654b..83bc1d3f5 100644 --- a/apps/openmw/mwgui/textcolours.hpp +++ b/apps/openmw/mwgui/textcolours.hpp @@ -5,14 +5,12 @@ namespace MWGui { - struct TextColours { MyGUI::Colour header; MyGUI::Colour normal; MyGUI::Colour notify; - MyGUI::Colour link; MyGUI::Colour linkOver; MyGUI::Colour linkPressed; @@ -28,6 +26,9 @@ namespace MWGui MyGUI::Colour journalTopic; MyGUI::Colour journalTopicOver; MyGUI::Colour journalTopicPressed; + + public: + void loadColours(); }; } diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 7bae74dfc..98bebe889 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -117,19 +117,8 @@ #include "keyboardnavigation.hpp" #include "resourceskin.hpp" -namespace -{ - - MyGUI::Colour getTextColour(const std::string& type) - { - return MyGUI::Colour::parse(MyGUI::LanguageManager::getInstance().replaceTags("#{fontcolour=" + type + "}")); - } - -} - namespace MWGui { - WindowManager::WindowManager( SDL_Window* window, osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue, const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage, @@ -392,26 +381,7 @@ namespace MWGui int w = MyGUI::RenderManager::getInstance().getViewSize().width; int h = MyGUI::RenderManager::getInstance().getViewSize().height; - mTextColours.header = getTextColour("header"); - mTextColours.normal = getTextColour("normal"); - mTextColours.notify = getTextColour("notify"); - - mTextColours.link = getTextColour("link"); - mTextColours.linkOver = getTextColour("link_over"); - mTextColours.linkPressed = getTextColour("link_pressed"); - - mTextColours.answer = getTextColour("answer"); - mTextColours.answerOver = getTextColour("answer_over"); - mTextColours.answerPressed = getTextColour("answer_pressed"); - - mTextColours.journalLink = getTextColour("journal_link"); - mTextColours.journalLinkOver = getTextColour("journal_link_over"); - mTextColours.journalLinkPressed = getTextColour("journal_link_pressed"); - - mTextColours.journalTopic = getTextColour("journal_topic"); - mTextColours.journalTopicOver = getTextColour("journal_topic_over"); - mTextColours.journalTopicPressed = getTextColour("journal_topic_pressed"); - + mTextColours.loadColours(); mDragAndDrop = new DragAndDrop(); From a8231ae2977f31e79d7266e0cab73e8ecd5dd8b0 Mon Sep 17 00:00:00 2001 From: Evil Eye Date: Tue, 26 May 2020 19:01:33 +0200 Subject: [PATCH 40/45] fix explicit startscript calls --- apps/openmw/mwscript/miscextensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 89bf44701..0dd0287a7 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -114,9 +114,9 @@ namespace MWScript virtual void execute (Interpreter::Runtime& runtime) { + MWWorld::Ptr target = R()(runtime, false); std::string name = runtime.getStringLiteral (runtime[0].mInteger); runtime.pop(); - MWWorld::Ptr target = R()(runtime, false); MWBase::Environment::get().getScriptManager()->getGlobalScripts().addScript (name, target); } }; From 396afe79f128dc8c1ad239eef51b4a019282246e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 28 May 2020 23:09:10 +0400 Subject: [PATCH 41/45] Move font loading to the FontLoader --- apps/openmw/mwgui/windowmanagerimp.cpp | 99 +---------------------- apps/openmw/mwgui/windowmanagerimp.hpp | 4 - components/fontloader/fontloader.cpp | 107 ++++++++++++++++++++++++- components/fontloader/fontloader.hpp | 12 ++- components/widgets/fontwrapper.hpp | 2 +- 5 files changed, 116 insertions(+), 108 deletions(-) diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 98bebe889..ab7c3334c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -181,7 +181,6 @@ namespace MWGui , mRestAllowed(true) , mShowOwned(0) , mEncoding(encoding) - , mFontHeight(16) , mVersionDescription(versionDescription) , mWindowVisible(true) { @@ -219,13 +218,6 @@ namespace MWGui SpellView::registerComponents(); Gui::registerAllWidgets(); - int fontSize = Settings::Manager::getInt("font size", "GUI"); - fontSize = std::min(std::max(12, fontSize), 20); - mFontHeight = fontSize; - - MyGUI::ResourceManager::getInstance().unregisterLoadXmlDelegate("Resource"); - MyGUI::ResourceManager::getInstance().registerLoadXmlDelegate("Resource") = newDelegate(this, &WindowManager::loadFontDelegate); - MyGUI::FactoryManager::getInstance().registerFactory("Controller"); MyGUI::FactoryManager::getInstance().registerFactory("Resource", "ResourceImageSetPointer"); @@ -282,94 +274,6 @@ namespace MWGui Settings::Manager::getFloat("contrast", "Video")); } - void WindowManager::loadFontDelegate(MyGUI::xml::ElementPtr _node, const std::string& _file, MyGUI::Version _version) - { - MyGUI::xml::ElementEnumerator resourceNode = _node->getElementEnumerator(); - bool createCopy = false; - while (resourceNode.next("Resource")) - { - std::string type, name; - resourceNode->findAttribute("type", type); - resourceNode->findAttribute("name", name); - - if (name.empty()) - continue; - - if (Misc::StringUtils::ciEqual(type, "ResourceTrueTypeFont")) - { - createCopy = true; - - // For TrueType fonts we should override Size and Resolution properties - // to allow to configure font size via config file, without need to edit XML files. - // Also we should take UI scaling factor in account. - int resolution = Settings::Manager::getInt("ttf resolution", "GUI"); - resolution = std::min(960, std::max(48, resolution)); - - float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); - resolution *= uiScale; - - MyGUI::xml::ElementPtr resolutionNode = resourceNode->createChild("Property"); - resolutionNode->addAttribute("key", "Resolution"); - resolutionNode->addAttribute("value", std::to_string(resolution)); - - MyGUI::xml::ElementPtr sizeNode = resourceNode->createChild("Property"); - sizeNode->addAttribute("key", "Size"); - sizeNode->addAttribute("value", std::to_string(mFontHeight)); - } - else if (Misc::StringUtils::ciEqual(type, "ResourceSkin") || - Misc::StringUtils::ciEqual(type, "AutoSizedResourceSkin")) - { - // We should adjust line height for MyGUI widgets depending on font size - MyGUI::xml::ElementPtr heightNode = resourceNode->createChild("Property"); - heightNode->addAttribute("key", "HeightLine"); - heightNode->addAttribute("value", std::to_string(mFontHeight+2)); - } - } - - MyGUI::ResourceManager::getInstance().loadFromXmlNode(_node, _file, _version); - - if (createCopy) - { - MyGUI::xml::ElementPtr copy = _node->createCopy(); - - MyGUI::xml::ElementEnumerator copyFont = copy->getElementEnumerator(); - while (copyFont.next("Resource")) - { - std::string type, name; - copyFont->findAttribute("type", type); - copyFont->findAttribute("name", name); - - if (name.empty()) - continue; - - if (Misc::StringUtils::ciEqual(type, "ResourceTrueTypeFont")) - { - // Since the journal and books use the custom scaling factor depending on resolution, - // setup separate fonts with different Resolution to fit these windows. - // These fonts have an internal prefix. - int resolution = Settings::Manager::getInt("ttf resolution", "GUI"); - resolution = std::min(960, std::max(48, resolution)); - - float currentX = Settings::Manager::getInt("resolution x", "Video"); - float currentY = Settings::Manager::getInt("resolution y", "Video"); - // TODO: read size from openmw_layout.xml - float heightScale = (currentY / 520); - float widthScale = (currentX / 600); - float uiScale = std::min(widthScale, heightScale); - resolution *= uiScale; - - MyGUI::xml::ElementPtr resolutionNode = copyFont->createChild("Property"); - resolutionNode->addAttribute("key", "Resolution"); - resolutionNode->addAttribute("value", std::to_string(resolution)); - - copyFont->setAttribute("name", "Journalbook " + name); - } - } - - MyGUI::ResourceManager::getInstance().loadFromXmlNode(copy, _file, _version); - } - } - void WindowManager::loadUserFonts() { mFontLoader->loadTrueTypeFonts(); @@ -566,7 +470,7 @@ namespace MWGui int WindowManager::getFontHeight() const { - return mFontHeight; + return mFontLoader->getFontHeight(); } void WindowManager::setNewGame(bool newgame) @@ -587,7 +491,6 @@ namespace MWGui { mKeyboardNavigation.reset(); - MyGUI::ResourceManager::getInstance().unregisterLoadXmlDelegate("Resource"); MyGUI::LanguageManager::getInstance().eventRequestTag.clear(); MyGUI::PointerManager::getInstance().eventChangeMousePointer.clear(); MyGUI::InputManager::getInstance().eventChangeKeyFocus.clear(); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 2de0a4ca8..42750705d 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -411,8 +411,6 @@ namespace MWGui MWWorld::Ptr mSelectedEnchantItem; MWWorld::Ptr mSelectedWeapon; - void loadFontDelegate(MyGUI::xml::ElementPtr _node, const std::string& _file, MyGUI::Version _version); - std::vector mCurrentModals; // Markers placed manually by the player. Must be shared between both map views (the HUD map and the map window). @@ -517,8 +515,6 @@ namespace MWGui ToUTF8::FromType mEncoding; - int mFontHeight; - std::string mVersionDescription; bool mWindowVisible; diff --git a/components/fontloader/fontloader.cpp b/components/fontloader/fontloader.cpp index dae83a1f9..6dcebe0bd 100644 --- a/components/fontloader/fontloader.cpp +++ b/components/fontloader/fontloader.cpp @@ -21,6 +21,8 @@ #include +#include + namespace { unsigned long utf8ToUnicode(const std::string& utf8) @@ -147,15 +149,24 @@ namespace Gui FontLoader::FontLoader(ToUTF8::FromType encoding, const VFS::Manager* vfs, const std::string& userDataPath) : mVFS(vfs) , mUserDataPath(userDataPath) + , mFontHeight(16) { if (encoding == ToUTF8::WINDOWS_1252) mEncoding = ToUTF8::CP437; else mEncoding = encoding; + + int fontSize = Settings::Manager::getInt("font size", "GUI"); + mFontHeight = std::min(std::max(12, fontSize), 20); + + MyGUI::ResourceManager::getInstance().unregisterLoadXmlDelegate("Resource"); + MyGUI::ResourceManager::getInstance().registerLoadXmlDelegate("Resource") = MyGUI::newDelegate(this, &FontLoader::loadFontFromXml); } FontLoader::~FontLoader() { + MyGUI::ResourceManager::getInstance().unregisterLoadXmlDelegate("Resource"); + for (std::vector::iterator it = mTextures.begin(); it != mTextures.end(); ++it) delete *it; mTextures.clear(); @@ -190,7 +201,7 @@ namespace Gui { size_t pos = name.find_last_of('.'); if (pos != std::string::npos && name.compare(pos, name.size()-pos, ".fnt") == 0) - loadFont(name, exportToFile); + loadBitmapFont(name, exportToFile); } else break; @@ -238,7 +249,7 @@ namespace Gui float ascent; } GlyphInfo; - void FontLoader::loadFont(const std::string &fileName, bool exportToFile) + void FontLoader::loadBitmapFont(const std::string &fileName, bool exportToFile) { Files::IStreamPtr file = mVFS->get(fileName); @@ -527,4 +538,96 @@ namespace Gui MyGUI::ResourceManager::getInstance().addResource(bookFont); } + void FontLoader::loadFontFromXml(MyGUI::xml::ElementPtr _node, const std::string& _file, MyGUI::Version _version) + { + MyGUI::xml::ElementEnumerator resourceNode = _node->getElementEnumerator(); + bool createCopy = false; + while (resourceNode.next("Resource")) + { + std::string type, name; + resourceNode->findAttribute("type", type); + resourceNode->findAttribute("name", name); + + if (name.empty()) + continue; + + if (Misc::StringUtils::ciEqual(type, "ResourceTrueTypeFont")) + { + createCopy = true; + + // For TrueType fonts we should override Size and Resolution properties + // to allow to configure font size via config file, without need to edit XML files. + // Also we should take UI scaling factor in account. + int resolution = Settings::Manager::getInt("ttf resolution", "GUI"); + resolution = std::min(960, std::max(48, resolution)); + + float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); + resolution *= uiScale; + + MyGUI::xml::ElementPtr resolutionNode = resourceNode->createChild("Property"); + resolutionNode->addAttribute("key", "Resolution"); + resolutionNode->addAttribute("value", std::to_string(resolution)); + + MyGUI::xml::ElementPtr sizeNode = resourceNode->createChild("Property"); + sizeNode->addAttribute("key", "Size"); + sizeNode->addAttribute("value", std::to_string(mFontHeight)); + } + else if (Misc::StringUtils::ciEqual(type, "ResourceSkin") || + Misc::StringUtils::ciEqual(type, "AutoSizedResourceSkin")) + { + // We should adjust line height for MyGUI widgets depending on font size + MyGUI::xml::ElementPtr heightNode = resourceNode->createChild("Property"); + heightNode->addAttribute("key", "HeightLine"); + heightNode->addAttribute("value", std::to_string(mFontHeight+2)); + } + } + + MyGUI::ResourceManager::getInstance().loadFromXmlNode(_node, _file, _version); + + if (createCopy) + { + MyGUI::xml::ElementPtr copy = _node->createCopy(); + + MyGUI::xml::ElementEnumerator copyFont = copy->getElementEnumerator(); + while (copyFont.next("Resource")) + { + std::string type, name; + copyFont->findAttribute("type", type); + copyFont->findAttribute("name", name); + + if (name.empty()) + continue; + + if (Misc::StringUtils::ciEqual(type, "ResourceTrueTypeFont")) + { + // Since the journal and books use the custom scaling factor depending on resolution, + // setup separate fonts with different Resolution to fit these windows. + // These fonts have an internal prefix. + int resolution = Settings::Manager::getInt("ttf resolution", "GUI"); + resolution = std::min(960, std::max(48, resolution)); + + float currentX = Settings::Manager::getInt("resolution x", "Video"); + float currentY = Settings::Manager::getInt("resolution y", "Video"); + // TODO: read size from openmw_layout.xml somehow + float heightScale = (currentY / 520); + float widthScale = (currentX / 600); + float uiScale = std::min(widthScale, heightScale); + resolution *= uiScale; + + MyGUI::xml::ElementPtr resolutionNode = copyFont->createChild("Property"); + resolutionNode->addAttribute("key", "Resolution"); + resolutionNode->addAttribute("value", std::to_string(resolution)); + + copyFont->setAttribute("name", "Journalbook " + name); + } + } + + MyGUI::ResourceManager::getInstance().loadFromXmlNode(copy, _file, _version); + } + } + + int FontLoader::getFontHeight() + { + return mFontHeight; + } } diff --git a/components/fontloader/fontloader.hpp b/components/fontloader/fontloader.hpp index 39301f9f5..94b022501 100644 --- a/components/fontloader/fontloader.hpp +++ b/components/fontloader/fontloader.hpp @@ -3,6 +3,9 @@ #include "boost/filesystem/operations.hpp" +#include +#include + #include #include @@ -19,8 +22,6 @@ namespace MyGUI namespace Gui { - - /// @brief loads Morrowind's .fnt/.tex fonts for use with MyGUI and OSG /// @note The FontLoader needs to remain in scope as long as you want to use the loaded fonts. class FontLoader @@ -33,16 +34,21 @@ namespace Gui void loadBitmapFonts (bool exportToFile); void loadTrueTypeFonts (); + void loadFontFromXml(MyGUI::xml::ElementPtr _node, const std::string& _file, MyGUI::Version _version); + + int getFontHeight(); + private: ToUTF8::FromType mEncoding; const VFS::Manager* mVFS; std::string mUserDataPath; + int mFontHeight; std::vector mTextures; std::vector mFonts; /// @param exportToFile export the converted font (Image and XML with glyph metrics) to files? - void loadFont (const std::string& fileName, bool exportToFile); + void loadBitmapFont (const std::string& fileName, bool exportToFile); FontLoader(const FontLoader&); void operator=(const FontLoader&); diff --git a/components/widgets/fontwrapper.hpp b/components/widgets/fontwrapper.hpp index 84406c70c..8b0011dda 100644 --- a/components/widgets/fontwrapper.hpp +++ b/components/widgets/fontwrapper.hpp @@ -38,7 +38,7 @@ namespace Gui std::string getFontSize() { - // Note: we can not use the WindowManager here, so there is a code duplication a bit. + // Note: we can not use the FontLoader here, so there is a code duplication a bit. static const std::string fontSize = std::to_string(clamp(Settings::Manager::getInt("font size", "GUI"), 12, 20)); return fontSize; } From 48b3fe5733e98ccb88025bb2b0976b7b6e35dd13 Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Fri, 29 May 2020 12:26:02 +0400 Subject: [PATCH 42/45] Use C++11-style loops in the StateManager --- apps/openmw/mwstate/statemanagerimp.cpp | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwstate/statemanagerimp.cpp b/apps/openmw/mwstate/statemanagerimp.cpp index 86a26212f..02f4bc7e7 100644 --- a/apps/openmw/mwstate/statemanagerimp.cpp +++ b/apps/openmw/mwstate/statemanagerimp.cpp @@ -240,12 +240,8 @@ void MWState::StateManager::saveGame (const std::string& description, const Slot ESM::ESMWriter writer; - const std::vector& current = - MWBase::Environment::get().getWorld()->getContentFiles(); - - for (std::vector::const_iterator iter (current.begin()); iter!=current.end(); - ++iter) - writer.addMaster (*iter, 0); // not using the size information anyway -> use value of 0 + for (const std::string& contentFile : MWBase::Environment::get().getWorld()->getContentFiles()) + writer.addMaster(contentFile, 0); // not using the size information anyway -> use value of 0 writer.setFormat (ESM::SavedGame::sCurrentFormat); @@ -346,10 +342,10 @@ void MWState::StateManager::quickSave (std::string name) if (currentCharacter) { - for (Character::SlotIterator it = currentCharacter->begin(); it != currentCharacter->end(); ++it) + for (auto& save : *currentCharacter) { //Visiting slots allows the quicksave finder to find the oldest quicksave - saveFinder.visitSave(&*it); + saveFinder.visitSave(&save); } } @@ -360,12 +356,10 @@ void MWState::StateManager::quickSave (std::string name) void MWState::StateManager::loadGame(const std::string& filepath) { - for (CharacterIterator it = mCharacterManager.begin(); it != mCharacterManager.end(); ++it) + for (const auto& character : mCharacterManager) { - const MWState::Character& character = *it; - for (MWState::Character::SlotIterator slotIt = character.begin(); slotIt != character.end(); ++slotIt) + for (const auto& slot : character) { - const MWState::Slot& slot = *slotIt; if (slot.mPath == boost::filesystem::path(filepath)) { loadGame(&character, slot.mPath.string()); @@ -630,13 +624,12 @@ bool MWState::StateManager::verifyProfile(const ESM::SavedGame& profile) const { const std::vector& selectedContentFiles = MWBase::Environment::get().getWorld()->getContentFiles(); bool notFound = false; - for (std::vector::const_iterator it = profile.mContentFiles.begin(); - it != profile.mContentFiles.end(); ++it) + for (const std::string& contentFile : profile.mContentFiles) { - if (std::find(selectedContentFiles.begin(), selectedContentFiles.end(), *it) + if (std::find(selectedContentFiles.begin(), selectedContentFiles.end(), contentFile) == selectedContentFiles.end()) { - Log(Debug::Warning) << "Warning: Saved game dependency " << *it << " is missing."; + Log(Debug::Warning) << "Warning: Saved game dependency " << contentFile << " is missing."; notFound = true; } } From efd5f13b2b076e7ad5739f72489c7b789a496871 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 17 May 2020 04:06:39 +0300 Subject: [PATCH 43/45] Make greeting-related actor data temporary (bug #5397) --- CHANGELOG.md | 1 + apps/openmw/mwbase/mechanicsmanager.hpp | 8 +++ apps/openmw/mwmechanics/actor.cpp | 40 +++++++++++ apps/openmw/mwmechanics/actor.hpp | 18 +++++ apps/openmw/mwmechanics/actors.cpp | 71 ++++++++++++++----- apps/openmw/mwmechanics/actors.hpp | 11 ++- apps/openmw/mwmechanics/actorutil.hpp | 7 ++ apps/openmw/mwmechanics/aitravel.cpp | 6 +- apps/openmw/mwmechanics/aiwander.cpp | 4 +- apps/openmw/mwmechanics/creaturestats.cpp | 43 +---------- apps/openmw/mwmechanics/creaturestats.hpp | 24 ------- .../mwmechanics/mechanicsmanagerimp.cpp | 20 ++++++ .../mwmechanics/mechanicsmanagerimp.hpp | 5 ++ apps/openmw/mwscript/aiextensions.cpp | 10 +-- 14 files changed, 173 insertions(+), 95 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9f293cb2..dea84b56b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ Bug #5367: Selecting a spell on an enchanted item per hotkey always plays the equip sound Bug #5369: Spawnpoint in the Grazelands doesn't produce oversized creatures Bug #5370: Opening an unlocked but trapped door uses the key + Bug #5397: NPC greeting does not reset if you leave + reenter area Bug #5400: Editor: Verifier checks race of non-skin bodyparts Bug #5415: Environment maps in ebony cuirass and HiRez Armors Indoril cuirass don't work Bug #5416: Junk non-node records before the root node are not handled gracefully diff --git a/apps/openmw/mwbase/mechanicsmanager.hpp b/apps/openmw/mwbase/mechanicsmanager.hpp index cca789a40..3bde83e94 100644 --- a/apps/openmw/mwbase/mechanicsmanager.hpp +++ b/apps/openmw/mwbase/mechanicsmanager.hpp @@ -7,6 +7,9 @@ #include #include +#include "../mwmechanics/actorutil.hpp" +// For MWMechanics::GreetingState + #include "../mwworld/ptr.hpp" namespace osg @@ -272,6 +275,11 @@ namespace MWBase virtual bool isSneaking(const MWWorld::Ptr& ptr) = 0; virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const = 0; + + virtual int getGreetingTimer(const MWWorld::Ptr& ptr) const = 0; + virtual float getAngleToPlayer(const MWWorld::Ptr& ptr) const = 0; + virtual MWMechanics::GreetingState getGreetingState(const MWWorld::Ptr& ptr) const = 0; + virtual bool isTurningToPlayer(const MWWorld::Ptr& ptr) const = 0; }; } diff --git a/apps/openmw/mwmechanics/actor.cpp b/apps/openmw/mwmechanics/actor.cpp index f7c6b7f1c..a5c55633a 100644 --- a/apps/openmw/mwmechanics/actor.cpp +++ b/apps/openmw/mwmechanics/actor.cpp @@ -18,4 +18,44 @@ namespace MWMechanics { return mCharacterController.get(); } + + int Actor::getGreetingTimer() const + { + return mGreetingTimer; + } + + void Actor::setGreetingTimer(int timer) + { + mGreetingTimer = timer; + } + + float Actor::getAngleToPlayer() const + { + return mTargetAngleRadians; + } + + void Actor::setAngleToPlayer(float angle) + { + mTargetAngleRadians = angle; + } + + GreetingState Actor::getGreetingState() const + { + return mGreetingState; + } + + void Actor::setGreetingState(GreetingState state) + { + mGreetingState = state; + } + + bool Actor::isTurningToPlayer() const + { + return mIsTurningToPlayer; + } + + void Actor::setTurningToPlayer(bool turning) + { + mIsTurningToPlayer = turning; + } } diff --git a/apps/openmw/mwmechanics/actor.hpp b/apps/openmw/mwmechanics/actor.hpp index 119527b64..287ca420f 100644 --- a/apps/openmw/mwmechanics/actor.hpp +++ b/apps/openmw/mwmechanics/actor.hpp @@ -3,6 +3,8 @@ #include +#include "../mwmechanics/actorutil.hpp" + namespace MWRender { class Animation; @@ -27,8 +29,24 @@ namespace MWMechanics CharacterController* getCharacterController(); + int getGreetingTimer() const; + void setGreetingTimer(int timer); + + float getAngleToPlayer() const; + void setAngleToPlayer(float angle); + + GreetingState getGreetingState() const; + void setGreetingState(GreetingState state); + + bool isTurningToPlayer() const; + void setTurningToPlayer(bool turning); + private: std::unique_ptr mCharacterController; + int mGreetingTimer{0}; + float mTargetAngleRadians{0.f}; + GreetingState mGreetingState{Greet_None}; + bool mIsTurningToPlayer{false}; }; } diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index 223d9fc34..adc13efa7 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -447,7 +447,7 @@ namespace MWMechanics actor.getClass().getMovementSettings(actor).mSpeedFactor = newSpeedFactor; } - void Actors::updateGreetingState(const MWWorld::Ptr& actor, bool turnOnly) + void Actors::updateGreetingState(const MWWorld::Ptr& actor, Actor* actorState, bool turnOnly) { if (!actor.getClass().isActor() || actor == getPlayer()) return; @@ -460,9 +460,9 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->isSwimming(actor) || (packageId != AiPackage::TypeIdWander && packageId != AiPackage::TypeIdTravel && packageId != -1)) { - stats.setTurningToPlayer(false); - stats.setGreetingTimer(0); - stats.setGreetingState(Greet_None); + actorState->setTurningToPlayer(false); + actorState->setGreetingTimer(0); + actorState->setGreetingState(Greet_None); return; } @@ -471,14 +471,14 @@ namespace MWMechanics osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); osg::Vec3f dir = playerPos - actorPos; - if (stats.isTurningToPlayer()) + if (actorState->isTurningToPlayer()) { // Reduce the turning animation glitch by using a *HUGE* value of // epsilon... TODO: a proper fix might be in either the physics or the // animation subsystem - if (zTurn(actor, stats.getAngleToPlayer(), osg::DegreesToRadians(5.f))) + if (zTurn(actor, actorState->getAngleToPlayer(), osg::DegreesToRadians(5.f))) { - stats.setTurningToPlayer(false); + actorState->setTurningToPlayer(false); // An original engine launches an endless idle2 when an actor greets player. playAnimationGroup (actor, "idle2", 0, std::numeric_limits::max(), false); } @@ -493,8 +493,8 @@ namespace MWMechanics float helloDistance = static_cast(stats.getAiSetting(CreatureStats::AI_Hello).getModified() * iGreetDistanceMultiplier); - int greetingTimer = stats.getGreetingTimer(); - GreetingState greetingState = stats.getGreetingState(); + int greetingTimer = actorState->getGreetingTimer(); + GreetingState greetingState = actorState->getGreetingState(); if (greetingState == Greet_None) { if ((playerPos - actorPos).length2() <= helloDistance*helloDistance && @@ -516,7 +516,7 @@ namespace MWMechanics greetingTimer++; if (greetingTimer <= GREETING_SHOULD_END || MWBase::Environment::get().getSoundManager()->sayActive(actor)) - turnActorToFacePlayer(actor, dir); + turnActorToFacePlayer(actor, actorState, dir); if (greetingTimer >= GREETING_COOLDOWN) { @@ -532,20 +532,19 @@ namespace MWMechanics greetingState = Greet_None; } - stats.setGreetingTimer(greetingTimer); - stats.setGreetingState(greetingState); + actorState->setGreetingTimer(greetingTimer); + actorState->setGreetingState(greetingState); } - void Actors::turnActorToFacePlayer(const MWWorld::Ptr& actor, const osg::Vec3f& dir) + void Actors::turnActorToFacePlayer(const MWWorld::Ptr& actor, Actor* actorState, const osg::Vec3f& dir) { actor.getClass().getMovementSettings(actor).mPosition[1] = 0; actor.getClass().getMovementSettings(actor).mPosition[0] = 0; - CreatureStats &stats = actor.getClass().getCreatureStats(actor); - if (!stats.isTurningToPlayer()) + if (!actorState->isTurningToPlayer()) { - stats.setAngleToPlayer(std::atan2(dir.x(), dir.y())); - stats.setTurningToPlayer(true); + actorState->setAngleToPlayer(std::atan2(dir.x(), dir.y())); + actorState->setTurningToPlayer(true); } } @@ -1695,7 +1694,7 @@ namespace MWMechanics if (isConscious(iter->first)) { stats.getAiSequence().execute(iter->first, *ctrl, duration); - updateGreetingState(iter->first, timerUpdateHello > 0); + updateGreetingState(iter->first, iter->second, timerUpdateHello > 0); playIdleDialogue(iter->first); updateMovementSpeed(iter->first); } @@ -2390,6 +2389,42 @@ namespace MWMechanics return ctrl->isAttackingOrSpell(); } + int Actors::getGreetingTimer(const MWWorld::Ptr& ptr) const + { + PtrActorMap::const_iterator it = mActors.find(ptr); + if (it == mActors.end()) + return 0; + + return it->second->getGreetingTimer(); + } + + float Actors::getAngleToPlayer(const MWWorld::Ptr& ptr) const + { + PtrActorMap::const_iterator it = mActors.find(ptr); + if (it == mActors.end()) + return 0.f; + + return it->second->getAngleToPlayer(); + } + + GreetingState Actors::getGreetingState(const MWWorld::Ptr& ptr) const + { + PtrActorMap::const_iterator it = mActors.find(ptr); + if (it == mActors.end()) + return Greet_None; + + return it->second->getGreetingState(); + } + + bool Actors::isTurningToPlayer(const MWWorld::Ptr& ptr) const + { + PtrActorMap::const_iterator it = mActors.find(ptr); + if (it == mActors.end()) + return false; + + return it->second->isTurningToPlayer(); + } + void Actors::fastForwardAi() { if (!MWBase::Environment::get().getMechanicsManager()->isAIActive()) diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 4e952d1c8..25716d392 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -7,6 +7,8 @@ #include #include +#include "../mwmechanics/actorutil.hpp" + namespace ESM { class ESMReader; @@ -123,8 +125,8 @@ namespace MWMechanics void playIdleDialogue(const MWWorld::Ptr& actor); void updateMovementSpeed(const MWWorld::Ptr& actor); - void updateGreetingState(const MWWorld::Ptr& actor, bool turnOnly); - void turnActorToFacePlayer(const MWWorld::Ptr& actor, const osg::Vec3f& dir); + void updateGreetingState(const MWWorld::Ptr& actor, Actor* actorState, bool turnOnly); + void turnActorToFacePlayer(const MWWorld::Ptr& actor, Actor* actorState, const osg::Vec3f& dir); void updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor, MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance); @@ -195,6 +197,11 @@ namespace MWMechanics bool isReadyToBlock(const MWWorld::Ptr& ptr) const; bool isAttackingOrSpell(const MWWorld::Ptr& ptr) const; + int getGreetingTimer(const MWWorld::Ptr& ptr) const; + float getAngleToPlayer(const MWWorld::Ptr& ptr) const; + GreetingState getGreetingState(const MWWorld::Ptr& ptr) const; + bool isTurningToPlayer(const MWWorld::Ptr& ptr) const; + private: void updateVisibility (const MWWorld::Ptr& ptr, CharacterController* ctrl); diff --git a/apps/openmw/mwmechanics/actorutil.hpp b/apps/openmw/mwmechanics/actorutil.hpp index 82a904799..cf3d92558 100644 --- a/apps/openmw/mwmechanics/actorutil.hpp +++ b/apps/openmw/mwmechanics/actorutil.hpp @@ -8,6 +8,13 @@ namespace MWWorld namespace MWMechanics { + enum GreetingState + { + Greet_None, + Greet_InProgress, + Greet_Done + }; + MWWorld::Ptr getPlayer(); bool isPlayerInCombat(); bool canActorMoveByZAxis(const MWWorld::Ptr& actor); diff --git a/apps/openmw/mwmechanics/aitravel.cpp b/apps/openmw/mwmechanics/aitravel.cpp index dba70316b..822523c76 100644 --- a/apps/openmw/mwmechanics/aitravel.cpp +++ b/apps/openmw/mwmechanics/aitravel.cpp @@ -3,6 +3,7 @@ #include #include "../mwbase/environment.hpp" +#include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" @@ -43,14 +44,15 @@ namespace MWMechanics bool AiTravel::execute (const MWWorld::Ptr& actor, CharacterController& characterController, AiState& state, float duration) { - auto& stats = actor.getClass().getCreatureStats(actor); + MWBase::MechanicsManager* mechMgr = MWBase::Environment::get().getMechanicsManager(); - if (stats.isTurningToPlayer() || stats.getGreetingState() == Greet_InProgress) + if (mechMgr->isTurningToPlayer(actor) || mechMgr->getGreetingState(actor) == Greet_InProgress) return false; const osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); const osg::Vec3f targetPos(mX, mY, mZ); + auto& stats = actor.getClass().getCreatureStats(actor); stats.setMovementFlag(CreatureStats::Flag_Run, false); stats.setDrawState(DrawState_Nothing); diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index 597453409..2c40c1ba5 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -206,7 +206,7 @@ namespace MWMechanics storage.setState(AiWanderStorage::Wander_Walking); } - GreetingState greetingState = cStats.getGreetingState(); + GreetingState greetingState = MWBase::Environment::get().getMechanicsManager()->getGreetingState(actor); if (greetingState == Greet_InProgress) { if (storage.mState == AiWanderStorage::Wander_Walking) @@ -442,7 +442,7 @@ namespace MWMechanics } // Check if idle animation finished - GreetingState greetingState = actor.getClass().getCreatureStats(actor).getGreetingState(); + GreetingState greetingState = MWBase::Environment::get().getMechanicsManager()->getGreetingState(actor); if (!checkIdle(actor, storage.mIdleAnimation) && (greetingState == Greet_Done || greetingState == Greet_None)) { if (mPathFinder.isPathConstructed()) diff --git a/apps/openmw/mwmechanics/creaturestats.cpp b/apps/openmw/mwmechanics/creaturestats.cpp index 1c377540a..800b5c22f 100644 --- a/apps/openmw/mwmechanics/creaturestats.cpp +++ b/apps/openmw/mwmechanics/creaturestats.cpp @@ -23,53 +23,12 @@ namespace MWMechanics mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false), mHitRecovery(false), mBlock(false), mMovementFlags(0), mFallHeight(0), mRecalcMagicka(false), mLastRestock(0,0), mGoldPool(0), mActorId(-1), mHitAttemptActorId(-1), - mDeathAnimation(-1), mTimeOfDeath(), mGreetingState(Greet_None), - mGreetingTimer(0), mTargetAngleRadians(0), mIsTurningToPlayer(false), mLevel (0) + mDeathAnimation(-1), mTimeOfDeath(), mLevel (0) { for (int i=0; i<4; ++i) mAiSettings[i] = 0; } - int MWMechanics::CreatureStats::getGreetingTimer() const - { - return mGreetingTimer; - } - - void MWMechanics::CreatureStats::setGreetingTimer(int timer) - { - mGreetingTimer = timer; - } - - float MWMechanics::CreatureStats::getAngleToPlayer() const - { - return mTargetAngleRadians; - } - - void MWMechanics::CreatureStats::setAngleToPlayer(float angle) - { - mTargetAngleRadians = angle; - } - - GreetingState MWMechanics::CreatureStats::getGreetingState() const - { - return mGreetingState; - } - - void MWMechanics::CreatureStats::setGreetingState(GreetingState state) - { - mGreetingState = state; - } - - bool MWMechanics::CreatureStats::isTurningToPlayer() const - { - return mIsTurningToPlayer; - } - - void MWMechanics::CreatureStats::setTurningToPlayer(bool turning) - { - mIsTurningToPlayer = turning; - } - const AiSequence& CreatureStats::getAiSequence() const { return mAiSequence; diff --git a/apps/openmw/mwmechanics/creaturestats.hpp b/apps/openmw/mwmechanics/creaturestats.hpp index 7c4a83db1..a4ecb23b3 100644 --- a/apps/openmw/mwmechanics/creaturestats.hpp +++ b/apps/openmw/mwmechanics/creaturestats.hpp @@ -19,13 +19,6 @@ namespace ESM namespace MWMechanics { - enum GreetingState - { - Greet_None, - Greet_InProgress, - Greet_Done - }; - /// \brief Common creature stats /// /// @@ -77,11 +70,6 @@ namespace MWMechanics MWWorld::TimeStamp mTimeOfDeath; - GreetingState mGreetingState; - int mGreetingTimer; - float mTargetAngleRadians; - bool mIsTurningToPlayer; - public: typedef std::pair SummonKey; // private: @@ -97,18 +85,6 @@ namespace MWMechanics public: CreatureStats(); - int getGreetingTimer() const; - void setGreetingTimer(int timer); - - float getAngleToPlayer() const; - void setAngleToPlayer(float angle); - - GreetingState getGreetingState() const; - void setGreetingState(GreetingState state); - - bool isTurningToPlayer() const; - void setTurningToPlayer(bool turning); - DrawState_ getDrawState() const; void setDrawState(DrawState_ state); diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp index 5ca7b3cdd..88045ec44 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.cpp @@ -1951,4 +1951,24 @@ namespace MWMechanics stats.setAttribute(frameNumber, "Mechanics Actors", mActors.size()); stats.setAttribute(frameNumber, "Mechanics Objects", mObjects.size()); } + + int MechanicsManager::getGreetingTimer(const MWWorld::Ptr &ptr) const + { + return mActors.getGreetingTimer(ptr); + } + + float MechanicsManager::getAngleToPlayer(const MWWorld::Ptr &ptr) const + { + return mActors.getAngleToPlayer(ptr); + } + + GreetingState MechanicsManager::getGreetingState(const MWWorld::Ptr &ptr) const + { + return mActors.getGreetingState(ptr); + } + + bool MechanicsManager::isTurningToPlayer(const MWWorld::Ptr &ptr) const + { + return mActors.isTurningToPlayer(ptr); + } } diff --git a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp index 83d1b236f..6785f979f 100644 --- a/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp +++ b/apps/openmw/mwmechanics/mechanicsmanagerimp.hpp @@ -242,6 +242,11 @@ namespace MWMechanics virtual void reportStats(unsigned int frameNumber, osg::Stats& stats) const override; + virtual int getGreetingTimer(const MWWorld::Ptr& ptr) const override; + virtual float getAngleToPlayer(const MWWorld::Ptr& ptr) const override; + virtual GreetingState getGreetingState(const MWWorld::Ptr& ptr) const override; + virtual bool isTurningToPlayer(const MWWorld::Ptr& ptr) const override; + private: bool canCommitCrimeAgainst(const MWWorld::Ptr& victim, const MWWorld::Ptr& attacker); bool canReportCrime(const MWWorld::Ptr &actor, const MWWorld::Ptr &victim, std::set &playerFollowers); diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 79639197d..603ed8836 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -430,13 +430,13 @@ namespace MWScript if (!targetPtr.isEmpty() && targetPtr.getCellRef().getRefId() == testedTargetId) targetsAreEqual = true; } - else + else if (testedTargetId == "player") // Currently the player ID is hardcoded { - bool turningToPlayer = creatureStats.isTurningToPlayer(); - bool greeting = creatureStats.getGreetingState() == MWMechanics::Greet_InProgress; + MWBase::MechanicsManager* mechMgr = MWBase::Environment::get().getMechanicsManager(); + bool greeting = mechMgr->getGreetingState(actor) == MWMechanics::Greet_InProgress; bool sayActive = MWBase::Environment::get().getSoundManager()->sayActive(actor); - if (turningToPlayer || (greeting && sayActive)) - targetsAreEqual = (testedTargetId == "player"); // Currently the player ID is hardcoded + if ((greeting && sayActive) || mechMgr->isTurningToPlayer(actor)) + targetsAreEqual = true; } runtime.push(int(targetsAreEqual)); } From b0b4550f0593e4ab8b8fa13b687fbbc644e6f0af Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Mon, 18 May 2020 23:04:48 +0300 Subject: [PATCH 44/45] Pass Actor by reference, simplify GetTarget for greetings --- apps/openmw/mwmechanics/actors.cpp | 32 +++++++++++++-------------- apps/openmw/mwmechanics/actors.hpp | 4 ++-- apps/openmw/mwscript/aiextensions.cpp | 3 +-- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index adc13efa7..873d5fa7c 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -447,7 +447,7 @@ namespace MWMechanics actor.getClass().getMovementSettings(actor).mSpeedFactor = newSpeedFactor; } - void Actors::updateGreetingState(const MWWorld::Ptr& actor, Actor* actorState, bool turnOnly) + void Actors::updateGreetingState(const MWWorld::Ptr& actor, Actor& actorState, bool turnOnly) { if (!actor.getClass().isActor() || actor == getPlayer()) return; @@ -460,9 +460,9 @@ namespace MWMechanics MWBase::Environment::get().getWorld()->isSwimming(actor) || (packageId != AiPackage::TypeIdWander && packageId != AiPackage::TypeIdTravel && packageId != -1)) { - actorState->setTurningToPlayer(false); - actorState->setGreetingTimer(0); - actorState->setGreetingState(Greet_None); + actorState.setTurningToPlayer(false); + actorState.setGreetingTimer(0); + actorState.setGreetingState(Greet_None); return; } @@ -471,14 +471,14 @@ namespace MWMechanics osg::Vec3f actorPos(actor.getRefData().getPosition().asVec3()); osg::Vec3f dir = playerPos - actorPos; - if (actorState->isTurningToPlayer()) + if (actorState.isTurningToPlayer()) { // Reduce the turning animation glitch by using a *HUGE* value of // epsilon... TODO: a proper fix might be in either the physics or the // animation subsystem - if (zTurn(actor, actorState->getAngleToPlayer(), osg::DegreesToRadians(5.f))) + if (zTurn(actor, actorState.getAngleToPlayer(), osg::DegreesToRadians(5.f))) { - actorState->setTurningToPlayer(false); + actorState.setTurningToPlayer(false); // An original engine launches an endless idle2 when an actor greets player. playAnimationGroup (actor, "idle2", 0, std::numeric_limits::max(), false); } @@ -493,8 +493,8 @@ namespace MWMechanics float helloDistance = static_cast(stats.getAiSetting(CreatureStats::AI_Hello).getModified() * iGreetDistanceMultiplier); - int greetingTimer = actorState->getGreetingTimer(); - GreetingState greetingState = actorState->getGreetingState(); + int greetingTimer = actorState.getGreetingTimer(); + GreetingState greetingState = actorState.getGreetingState(); if (greetingState == Greet_None) { if ((playerPos - actorPos).length2() <= helloDistance*helloDistance && @@ -532,19 +532,19 @@ namespace MWMechanics greetingState = Greet_None; } - actorState->setGreetingTimer(greetingTimer); - actorState->setGreetingState(greetingState); + actorState.setGreetingTimer(greetingTimer); + actorState.setGreetingState(greetingState); } - void Actors::turnActorToFacePlayer(const MWWorld::Ptr& actor, Actor* actorState, const osg::Vec3f& dir) + void Actors::turnActorToFacePlayer(const MWWorld::Ptr& actor, Actor& actorState, const osg::Vec3f& dir) { actor.getClass().getMovementSettings(actor).mPosition[1] = 0; actor.getClass().getMovementSettings(actor).mPosition[0] = 0; - if (!actorState->isTurningToPlayer()) + if (!actorState.isTurningToPlayer()) { - actorState->setAngleToPlayer(std::atan2(dir.x(), dir.y())); - actorState->setTurningToPlayer(true); + actorState.setAngleToPlayer(std::atan2(dir.x(), dir.y())); + actorState.setTurningToPlayer(true); } } @@ -1694,7 +1694,7 @@ namespace MWMechanics if (isConscious(iter->first)) { stats.getAiSequence().execute(iter->first, *ctrl, duration); - updateGreetingState(iter->first, iter->second, timerUpdateHello > 0); + updateGreetingState(iter->first, *iter->second, timerUpdateHello > 0); playIdleDialogue(iter->first); updateMovementSpeed(iter->first); } diff --git a/apps/openmw/mwmechanics/actors.hpp b/apps/openmw/mwmechanics/actors.hpp index 25716d392..bd5a14c0d 100644 --- a/apps/openmw/mwmechanics/actors.hpp +++ b/apps/openmw/mwmechanics/actors.hpp @@ -125,8 +125,8 @@ namespace MWMechanics void playIdleDialogue(const MWWorld::Ptr& actor); void updateMovementSpeed(const MWWorld::Ptr& actor); - void updateGreetingState(const MWWorld::Ptr& actor, Actor* actorState, bool turnOnly); - void turnActorToFacePlayer(const MWWorld::Ptr& actor, Actor* actorState, const osg::Vec3f& dir); + void updateGreetingState(const MWWorld::Ptr& actor, Actor& actorState, bool turnOnly); + void turnActorToFacePlayer(const MWWorld::Ptr& actor, Actor& actorState, const osg::Vec3f& dir); void updateHeadTracking(const MWWorld::Ptr& actor, const MWWorld::Ptr& targetActor, MWWorld::Ptr& headTrackTarget, float& sqrHeadTrackDistance); diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 603ed8836..05c07a972 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -435,8 +435,7 @@ namespace MWScript MWBase::MechanicsManager* mechMgr = MWBase::Environment::get().getMechanicsManager(); bool greeting = mechMgr->getGreetingState(actor) == MWMechanics::Greet_InProgress; bool sayActive = MWBase::Environment::get().getSoundManager()->sayActive(actor); - if ((greeting && sayActive) || mechMgr->isTurningToPlayer(actor)) - targetsAreEqual = true; + targetsAreEqual = (greeting && sayActive) || mechMgr->isTurningToPlayer(actor); } runtime.push(int(targetsAreEqual)); } From 577786f1109eb40f4a283e64a5d350e6d830c462 Mon Sep 17 00:00:00 2001 From: Capostrophic Date: Sun, 24 May 2020 19:03:54 +0300 Subject: [PATCH 45/45] Don't disable player's collision shape in TCL (#5435) --- CHANGELOG.md | 1 + apps/openmw/mwphysics/physicssystem.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9f293cb2..64b1526d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ Bug #5424: Creatures do not headtrack player Bug #5425: Poison effect only appears for one frame Bug #5427: GetDistance unknown ID error is misleading + Bug #5435: Enemies can't hurt the player when collision is off Bug #5441: Enemies can't push a player character when in critical strike stance Feature #5362: Show the soul gems' trapped soul in count dialog diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 808b1e75a..7cc0f7770 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -648,7 +648,7 @@ namespace MWPhysics bool cmode = found->second->getCollisionMode(); cmode = !cmode; found->second->enableCollisionMode(cmode); - found->second->enableCollisionBody(cmode); + // NB: Collision body isn't disabled for vanilla TCL compatibility return cmode; }