From 10778d8c3e78169594c0b3474c63d708628d6570 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Thu, 6 Oct 2011 12:29:59 +0200 Subject: [PATCH] Issue #19: factored out local script handling into a separate class This also fixes a bug related to self-destructing references (introduced during the cell handling improvements) --- apps/openmw/CMakeLists.txt | 2 + apps/openmw/engine.cpp | 27 +++++----- apps/openmw/engine.hpp | 2 - apps/openmw/mwworld/localscripts.cpp | 80 ++++++++++++++++++++++++++++ apps/openmw/mwworld/localscripts.hpp | 47 ++++++++++++++++ apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/world.cpp | 29 ++-------- apps/openmw/mwworld/world.hpp | 10 ++-- 8 files changed, 151 insertions(+), 48 deletions(-) create mode 100644 apps/openmw/mwworld/localscripts.cpp create mode 100644 apps/openmw/mwworld/localscripts.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 21f3e18a2..54abb948a 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -149,6 +149,7 @@ set(GAMEWORLD mwworld/containerutil.cpp mwworld/player.cpp mwworld/cells.cpp + mwworld/localscripts.cpp ) set(GAMEWORLD_HEADER mwworld/refdata.hpp @@ -170,6 +171,7 @@ set(GAMEWORLD_HEADER mwworld/player.hpp mwworld/cellfunctors.hpp mwworld/cells.hpp + mwworld/localscripts.hpp ) source_group(apps\\openmw\\mwworld FILES ${GAMEWORLD} ${GAMEWORLD_HEADER}) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index e9ceea2f3..7e69e40f9 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -54,22 +54,23 @@ void OMW::Engine::executeLocalScripts() { - for (MWWorld::World::ScriptList::const_iterator iter ( - mEnvironment.mWorld->getLocalScripts().begin()); - iter!=mEnvironment.mWorld->getLocalScripts().end(); ++iter) + MWWorld::LocalScripts& localScripts = mEnvironment.mWorld->getLocalScripts(); + + localScripts.startIteration(); + + while (!localScripts.isFinished()) { - if (mIgnoreLocalPtr.isEmpty() || mIgnoreLocalPtr!=iter->second) - { - MWScript::InterpreterContext interpreterContext (mEnvironment, - &iter->second.getRefData().getLocals(), MWWorld::Ptr (iter->second)); - mScriptManager->run (iter->first, interpreterContext); + std::pair script = localScripts.getNext(); - if (mEnvironment.mWorld->hasCellChanged()) - break; - } + MWScript::InterpreterContext interpreterContext (mEnvironment, + &script.second.getRefData().getLocals(), script.second); + mScriptManager->run (script.first, interpreterContext); + + if (mEnvironment.mWorld->hasCellChanged()) + break; } - mIgnoreLocalPtr = MWWorld::Ptr(); + mEnvironment.mWorld->getLocalScripts().setIgnore (MWWorld::Ptr()); } @@ -488,7 +489,7 @@ void OMW::Engine::activate() if (!script.empty()) { - mIgnoreLocalPtr = ptr; + mEnvironment.mWorld->getLocalScripts().setIgnore (ptr); mScriptManager->run (script, interpreterContext); } diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 3df0d0b3a..96b7cf52e 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -81,8 +81,6 @@ namespace OMW int focusFrameCounter; static const int focusUpdateFrame = 10; - MWWorld::Ptr mIgnoreLocalPtr; - Files::Collections mFileCollections; bool mFSStrict; diff --git a/apps/openmw/mwworld/localscripts.cpp b/apps/openmw/mwworld/localscripts.cpp new file mode 100644 index 000000000..3fa110338 --- /dev/null +++ b/apps/openmw/mwworld/localscripts.cpp @@ -0,0 +1,80 @@ + +#include "localscripts.hpp" + +void MWWorld::LocalScripts::setIgnore (const Ptr& ptr) +{ + mIgnore = ptr; +} + +void MWWorld::LocalScripts::startIteration() +{ + mIter = mScripts.begin(); +} + +bool MWWorld::LocalScripts::isFinished() const +{ + if (mIter==mScripts.end()) + return true; + + if (!mIgnore.isEmpty() && mIter->second==mIgnore) + { + std::list >::iterator iter = mIter; + return ++iter==mScripts.end(); + } + + return false; +} + +std::pair MWWorld::LocalScripts::getNext() +{ + assert (!isFinished()); + + std::list >::iterator iter = mIter++; + + if (mIgnore.isEmpty() || iter->second!=mIgnore) + return *iter; + + return getNext(); +} + +void MWWorld::LocalScripts::add (const std::string& scriptName, const Ptr& ptr) +{ + mScripts.push_back (std::make_pair (scriptName, ptr)); +} + +void MWWorld::LocalScripts::clear() +{ + mScripts.clear(); +} + +void MWWorld::LocalScripts::clearCell (Ptr::CellStore *cell) +{ + std::list >::iterator iter = mScripts.begin(); + + while (iter!=mScripts.end()) + { + if (iter->second.getCell()==cell) + { + if (iter==mIter) + ++mIter; + + mScripts.erase (iter++); + } + else + ++iter; + } +} + +void MWWorld::LocalScripts::remove (const Ptr& ptr) +{ + for (std::list >::iterator iter = mScripts.begin(); + iter!=mScripts.end(); ++iter) + if (iter->second==ptr) + { + if (iter==mIter) + ++mIter; + + mScripts.erase (iter); + break; + } +} diff --git a/apps/openmw/mwworld/localscripts.hpp b/apps/openmw/mwworld/localscripts.hpp new file mode 100644 index 000000000..bc5a7c1f6 --- /dev/null +++ b/apps/openmw/mwworld/localscripts.hpp @@ -0,0 +1,47 @@ +#ifndef GAME_MWWORLD_LOCALSCRIPTS_H +#define GAME_MWWORLD_LOCALSCRIPTS_H + +#include +#include + +#include "ptr.hpp" + +namespace MWWorld +{ + /// \brief List of active local scripts + class LocalScripts + { + std::list > mScripts; + std::list >::iterator mIter; + MWWorld::Ptr mIgnore; + + public: + + void setIgnore (const Ptr& ptr); + ///< Mark a single reference for ignoring during iteration over local scripts (will revoke + /// previous ignores). + + void startIteration(); + ///< Set the iterator to the begin of the script list. + + bool isFinished() const; + ///< Is iteration finished? + + std::pair getNext(); + ///< Get next local script (must not be called if isFinished()) + + void add (const std::string& scriptName, const Ptr& ptr); + ///< Add script to collection of active local scripts. + + void clear(); + ///< Clear active local scripts collection. + + void clearCell (Ptr::CellStore *cell); + ///< Remove all scripts belonging to \a cell. + + void remove (const Ptr& ptr); + ///< Remove script for given reference (ignored if reference does not have a scirpt listed). + }; +} + +#endif diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 11bdad35f..9cc432ee6 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -57,7 +57,7 @@ namespace MWWorld mPhysics->removeObject (*iter); } - mWorld->removeScripts (iter->first); + mWorld->getLocalScripts().clearCell (iter->first); mEnvironment.mMechanicsManager->dropActors (iter->first); mEnvironment.mSoundManager->stopSound (iter->first); diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index f2e846ef4..62f477bfb 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -27,7 +27,7 @@ namespace { template void listCellScripts (const ESMS::ESMStore& store, - ESMS::CellRefList& cellRefList, MWWorld::World::ScriptList& scriptList, + ESMS::CellRefList& cellRefList, MWWorld::LocalScripts& localScripts, MWWorld::Ptr::CellStore *cell) { for (typename ESMS::CellRefList::List::iterator iter ( @@ -40,8 +40,7 @@ namespace { iter->mData.setLocals (*script); - scriptList.push_back ( - std::make_pair (iter->base->script, MWWorld::Ptr (&*iter, cell))); + localScripts.add (iter->base->script, MWWorld::Ptr (&*iter, cell)); } } } @@ -185,20 +184,6 @@ namespace MWWorld throw std::runtime_error ("month out of range"); } - void World::removeScripts (Ptr::CellStore *cell) - { - ScriptList::iterator iter = mLocalScripts.begin(); - - while (iter!=mLocalScripts.end()) - { - if (iter->second.getCell()==cell) - mLocalScripts.erase (iter++); - else - ++iter; - } - } - - void World::adjustSky() { if (mSky) @@ -306,7 +291,7 @@ namespace MWWorld return mEsm; } - const World::ScriptList& World::getLocalScripts() const + LocalScripts& World::getLocalScripts() { return mLocalScripts; } @@ -575,13 +560,7 @@ namespace MWWorld mPhysics->removeObject (ptr.getRefData().getHandle()); - for (ScriptList::iterator iter = mLocalScripts.begin(); iter!=mLocalScripts.end(); - ++iter) - if (ptr==iter->second) - { - mLocalScripts.erase (iter); - break; - } + mLocalScripts.remove (ptr); } render->deleteObject (ptr.getRefData().getHandle()); diff --git a/apps/openmw/mwworld/world.hpp b/apps/openmw/mwworld/world.hpp index 89c6057fa..ea9f5a56f 100644 --- a/apps/openmw/mwworld/world.hpp +++ b/apps/openmw/mwworld/world.hpp @@ -17,6 +17,7 @@ #include "scene.hpp" #include "physicssystem.hpp" #include "cells.hpp" +#include "localscripts.hpp" #include @@ -55,9 +56,7 @@ namespace MWWorld class World { - public: - typedef std::list > ScriptList; enum RenderMode { @@ -71,7 +70,7 @@ namespace MWWorld MWWorld::Player *mPlayer; ESM::ESMReader mEsm; ESMS::ESMStore mStore; - ScriptList mLocalScripts; + LocalScripts mLocalScripts; MWWorld::Globals *mGlobalVariables; MWWorld::PhysicsSystem *mPhysics; bool mSky; @@ -108,8 +107,6 @@ namespace MWWorld Ptr::CellStore *getInterior (const std::string& name); - void removeScripts (Ptr::CellStore *cell); - void insertInteriorScripts (ESMS::CellStore& cell); void adjustSky(); @@ -120,8 +117,7 @@ namespace MWWorld ESM::ESMReader& getEsmReader(); - const ScriptList& getLocalScripts() const; - ///< Names and local variable state of all local scripts in active cells. + LocalScripts& getLocalScripts(); bool hasCellChanged() const; ///< Has the player moved to a different cell, since the last frame?