From 076b01559fabc3d04c22c186132d52d5fc373efc Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Fri, 2 Jul 2010 17:21:27 +0200 Subject: [PATCH] added local script compiling --- CMakeLists.txt | 4 +- apps/openmw/engine.cpp | 14 ++- apps/openmw/engine.hpp | 6 ++ apps/openmw/mwscript/compilercontext.hpp | 15 ++++ .../openmw/mwscript/compilercontextscript.hpp | 22 +++++ apps/openmw/mwscript/scriptmanager.cpp | 89 +++++++++++++++++-- apps/openmw/mwscript/scriptmanager.hpp | 16 +++- apps/openmw/refdata.hpp | 9 +- apps/openmw/world.cpp | 51 ++++++----- 9 files changed, 187 insertions(+), 39 deletions(-) create mode 100644 apps/openmw/mwscript/compilercontext.hpp create mode 100644 apps/openmw/mwscript/compilercontextscript.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 136858132..f3aa546ac 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,7 +41,9 @@ set(GAMESCRIPT apps/openmw/mwscript/scriptmanager.cpp) set(GAMESCRIPT_HEADER apps/openmw/mwscript/locals.hpp - apps/openmw/mwscript/scriptmanager.hpp) + apps/openmw/mwscript/scriptmanager.hpp + apps/openmw/mwscript/compilercontext.hpp + apps/openmw/mwscript/compilercontextscript.hpp) source_group(apps\\openmw\\mwscript FILES ${GAMESCRIPT} ${GAMESCRIPT_HEADER}) set(APPS ${GAME} ${GAMEREND} ${GAMEINPUT} ${GAMESCRIPT}) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index e308c9a38..3baccdc6e 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -9,6 +9,7 @@ #include "mwinput/inputmanager.hpp" #include "mwscript/scriptmanager.hpp" +#include "mwscript/compilercontextscript.hpp" #include "world.hpp" @@ -30,12 +31,13 @@ void OMW::Engine::executeLocalScripts() for (World::ScriptList::const_iterator iter (mWorld->getLocalScripts().begin()); iter!=mWorld->getLocalScripts().end(); ++iter) { - mScriptManager->run (iter->first); + mScriptManager->run (iter->first, *iter->second); } } -OMW::Engine::Engine() : mWorld(NULL), mDebug (false), mScriptManager (0) +OMW::Engine::Engine() +: mWorld(NULL), mDebug (false), mScriptManager (0), mScriptContext (0) { mspCommandServer.reset( new OMW::CommandServer::Server(&mCommandQueue, kCommandServerPort)); @@ -46,6 +48,7 @@ OMW::Engine::~Engine() // mspCommandServer->stop(); delete mWorld; delete mScriptManager; + delete mScriptContext; } // Load all BSA files in data directory. @@ -158,8 +161,11 @@ void OMW::Engine::go() // Create the world mWorld = new World (mOgre, mDataDir, mMaster, mCellName); - - mScriptManager = new MWScript::ScriptManager (mWorld->getStore(), mVerboseScripts); + + mScriptContext = new MWScript::CompilerContextScript; + + mScriptManager = new MWScript::ScriptManager (mWorld->getStore(), mVerboseScripts, + *mScriptContext); executeLocalScripts(); // TODO move into a framelistener diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 47f4e88c8..84b675af9 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -12,6 +12,11 @@ #include "mwrender/mwscene.hpp" +namespace Compiler +{ + class Context; +} + namespace MWScript { class ScriptManager; @@ -39,6 +44,7 @@ namespace OMW std::auto_ptr mspCommandServer; MWScript::ScriptManager *mScriptManager; + Compiler::Context *mScriptContext; // not implemented Engine (const Engine&); diff --git a/apps/openmw/mwscript/compilercontext.hpp b/apps/openmw/mwscript/compilercontext.hpp new file mode 100644 index 000000000..ef6900ea1 --- /dev/null +++ b/apps/openmw/mwscript/compilercontext.hpp @@ -0,0 +1,15 @@ +#ifndef GAME_SCRIPT_COMPILERCONTEXT_H +#define GAME_SCRIPT_COMPILERCONTEXT_H + +#include + +namespace MWScript +{ + class CompilerContext : public Compiler::Context + { + }; +} + +#endif + + diff --git a/apps/openmw/mwscript/compilercontextscript.hpp b/apps/openmw/mwscript/compilercontextscript.hpp new file mode 100644 index 000000000..28e5bff68 --- /dev/null +++ b/apps/openmw/mwscript/compilercontextscript.hpp @@ -0,0 +1,22 @@ +#ifndef GAME_SCRIPT_COMPILERCONTEXTSCRIPT_H +#define GAME_SCRIPT_COMPILERCONTEXTSCRIPT_H + +#include "compilercontext.hpp" + +namespace MWScript +{ + /// Context for local scripts, global scripts and targetted scripts + + class CompilerContextScript : public CompilerContext + { + public: + + // Is the compiler allowed to declare local variables? + virtual bool canDeclareLocals() const + { + return true; + } + }; +} + +#endif diff --git a/apps/openmw/mwscript/scriptmanager.cpp b/apps/openmw/mwscript/scriptmanager.cpp index 1c9f61abd..06d6616c7 100644 --- a/apps/openmw/mwscript/scriptmanager.cpp +++ b/apps/openmw/mwscript/scriptmanager.cpp @@ -1,19 +1,98 @@ #include "scriptmanager.hpp" +#include + +#include #include +#include +#include + +#include +#include namespace MWScript { - ScriptManager::ScriptManager (const ESMS::ESMStore& store, bool verbose) - : mStore (store), mVerbose (verbose) + ScriptManager::ScriptManager (const ESMS::ESMStore& store, bool verbose, + Compiler::Context& compilerContext) + : mErrorHandler (std::cerr), mStore (store), mVerbose (verbose), + mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext) {} - void ScriptManager::run (const std::string& name/*, Compiler::Context& compilerContext, - Interpreter::Context& interpreterContext, Locals& locals*/) + bool ScriptManager::compile (const std::string& name) { - std::cout << "script request: " << name << std::endl; + mParser.reset(); + mErrorHandler.reset(); + + bool Success = true; + + if (const ESM::Script *script = mStore.scripts.find (name)) + { + if (mVerbose) + std::cout << "compiling script: " << name << std::endl; + + try + { + std::istringstream input (script->scriptText); + + Compiler::Scanner scanner (mErrorHandler, input); + + scanner.scan (mParser); + + if (!mErrorHandler.isGood()) + Success = false; + } + catch (const std::exception& error) + { + Success = false; + } + + if (!Success && mVerbose) + { + std::cerr + << "compiling failed: " << name << std::endl + << script->scriptText + << std::endl << std::endl; + } + + if (Success) + { + std::vector code; + mParser.getCode (code); + mScripts.insert (std::make_pair (name, code)); + + // TODO sanity check on generated locals + + return true; + } + } + + return false; + } + + void ScriptManager::run (const std::string& name/*, + Interpreter::Context& interpreterContext*/, Locals& locals) + { + // compile script + std::map >::iterator iter = + mScripts.find (name); + + if (iter==mScripts.end()) + { + if (!compile (name)) + { + // failed -> ignore script from now on. + std::vector empty; + mScripts.insert (std::make_pair (name, empty)); + return; + } + + iter = mScripts.find (name); + assert (iter!=mScripts.end()); + } + // execute script + } } diff --git a/apps/openmw/mwscript/scriptmanager.hpp b/apps/openmw/mwscript/scriptmanager.hpp index a399bb8da..1b5176609 100644 --- a/apps/openmw/mwscript/scriptmanager.hpp +++ b/apps/openmw/mwscript/scriptmanager.hpp @@ -5,6 +5,9 @@ #include #include +#include +#include + #include namespace ESMS @@ -28,20 +31,25 @@ namespace MWScript class ScriptManager { + Compiler::StreamErrorHandler mErrorHandler; const ESMS::ESMStore& mStore; bool mVerbose; + Compiler::Context& mCompilerContext; + Compiler::FileParser mParser; std::map > mScripts; + bool compile (const std::string& name); + public: - ScriptManager (const ESMS::ESMStore& store, bool verbose); + ScriptManager (const ESMS::ESMStore& store, bool verbose, + Compiler::Context& compilerContext); - void run (const std::string& name/*, Compiler::Context& compilerContext, - Interpreter::Context& interpreterContext, Locals& locals*/); + void run (const std::string& name/*, + Interpreter::Context& interpreterContext*/, Locals& locals); }; }; #endif - diff --git a/apps/openmw/refdata.hpp b/apps/openmw/refdata.hpp index 8ffe757b7..f10c27298 100644 --- a/apps/openmw/refdata.hpp +++ b/apps/openmw/refdata.hpp @@ -19,8 +19,11 @@ namespace OMW MWScript::Locals mLocals; // if we find the overhead of heaving a locals // object in the refdata of refs without a script, // we can make this a pointer later. + bool mHasLocals; public: + + RefData() : mHasLocals (false) {} std::string getHandle() { @@ -29,7 +32,11 @@ namespace OMW void setLocals (const ESM::Script& script) { - mLocals.configure (script); + if (!mHasLocals) + { + mLocals.configure (script); + mHasLocals = true; + } } void setHandle (const std::string& handle) diff --git a/apps/openmw/world.cpp b/apps/openmw/world.cpp index a4460a512..df6e0f183 100644 --- a/apps/openmw/world.cpp +++ b/apps/openmw/world.cpp @@ -10,20 +10,23 @@ namespace { template - void listCellScripts (ESMS::CellRefList& cellRefList, - OMW::World::ScriptList& scriptList) + void listCellScripts (const ESMS::ESMStore& store, + ESMS::CellRefList& cellRefList, OMW::World::ScriptList& scriptList) { for (typename ESMS::CellRefList::List::iterator iter ( cellRefList.list.begin()); iter!=cellRefList.list.end(); ++iter) { if (!iter->base->script.empty()) - scriptList.push_back ( - std::make_pair (iter->base->script, static_cast (0))); + { + if (const ESM::Script *script = store.scripts.find (iter->base->script)) + { + iter->mData.setLocals (*script); - // TODO local variables - - + scriptList.push_back ( + std::make_pair (iter->base->script, &iter->mData.getLocals())); + } + } } } } @@ -32,23 +35,23 @@ namespace OMW { void World::insertInteriorScripts (ESMS::CellStore& cell) { - listCellScripts (cell.activators, mLocalScripts); - listCellScripts (cell.potions, mLocalScripts); - listCellScripts (cell.appas, mLocalScripts); - listCellScripts (cell.armors, mLocalScripts); - listCellScripts (cell.books, mLocalScripts); - listCellScripts (cell.clothes, mLocalScripts); - listCellScripts (cell.containers, mLocalScripts); - listCellScripts (cell.creatures, mLocalScripts); - listCellScripts (cell.doors, mLocalScripts); - listCellScripts (cell.ingreds, mLocalScripts); - listCellScripts (cell.lights, mLocalScripts); - listCellScripts (cell.lockpicks, mLocalScripts); - listCellScripts (cell.miscItems, mLocalScripts); - listCellScripts (cell.npcs, mLocalScripts); - listCellScripts (cell.probes, mLocalScripts); - listCellScripts (cell.repairs, mLocalScripts); - listCellScripts (cell.weapons, mLocalScripts); + listCellScripts (mStore, cell.activators, mLocalScripts); + listCellScripts (mStore, cell.potions, mLocalScripts); + listCellScripts (mStore, cell.appas, mLocalScripts); + listCellScripts (mStore, cell.armors, mLocalScripts); + listCellScripts (mStore, cell.books, mLocalScripts); + listCellScripts (mStore, cell.clothes, mLocalScripts); + listCellScripts (mStore, cell.containers, mLocalScripts); + listCellScripts (mStore, cell.creatures, mLocalScripts); + listCellScripts (mStore, cell.doors, mLocalScripts); + listCellScripts (mStore, cell.ingreds, mLocalScripts); + listCellScripts (mStore, cell.lights, mLocalScripts); + listCellScripts (mStore, cell.lockpicks, mLocalScripts); + listCellScripts (mStore, cell.miscItems, mLocalScripts); + listCellScripts (mStore, cell.npcs, mLocalScripts); + listCellScripts (mStore, cell.probes, mLocalScripts); + listCellScripts (mStore, cell.repairs, mLocalScripts); + listCellScripts (mStore, cell.weapons, mLocalScripts); } World::World (Render::OgreRenderer& renderer, const boost::filesystem::path& dataDir,