mirror of
				https://github.com/TES3MP/openmw-tes3mp.git
				synced 2025-11-04 02:56:45 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			240 lines
		
	
	
	
		
			7.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			240 lines
		
	
	
	
		
			7.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "locals.hpp"
 | 
						|
 | 
						|
#include <components/esm/loadscpt.hpp>
 | 
						|
#include <components/esm/variant.hpp>
 | 
						|
#include <components/esm/locals.hpp>
 | 
						|
 | 
						|
#include <components/compiler/locals.hpp>
 | 
						|
#include <components/compiler/exception.hpp>
 | 
						|
 | 
						|
#include "../mwbase/environment.hpp"
 | 
						|
#include "../mwbase/scriptmanager.hpp"
 | 
						|
#include "../mwbase/world.hpp"
 | 
						|
 | 
						|
#include "../mwworld/esmstore.hpp"
 | 
						|
 | 
						|
#include <iostream>
 | 
						|
 | 
						|
namespace MWScript
 | 
						|
{
 | 
						|
    void Locals::ensure (const std::string& scriptName)
 | 
						|
    {
 | 
						|
        if (!mInitialised)
 | 
						|
        {
 | 
						|
            const ESM::Script *script = MWBase::Environment::get().getWorld()->getStore().
 | 
						|
                get<ESM::Script>().find (scriptName);
 | 
						|
 | 
						|
            configure (*script);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    Locals::Locals() : mInitialised (false) {}
 | 
						|
 | 
						|
    bool Locals::configure (const ESM::Script& script)
 | 
						|
    {
 | 
						|
        if (mInitialised)
 | 
						|
            return false;
 | 
						|
 | 
						|
        const Compiler::Locals& locals =
 | 
						|
            MWBase::Environment::get().getScriptManager()->getLocals (script.mId);
 | 
						|
 | 
						|
        mShorts.clear();
 | 
						|
        mShorts.resize (locals.get ('s').size(), 0);
 | 
						|
        mLongs.clear();
 | 
						|
        mLongs.resize (locals.get ('l').size(), 0);
 | 
						|
        mFloats.clear();
 | 
						|
        mFloats.resize (locals.get ('f').size(), 0);
 | 
						|
 | 
						|
        mInitialised = true;
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    bool Locals::isEmpty() const
 | 
						|
    {
 | 
						|
        return (mShorts.empty() && mLongs.empty() && mFloats.empty());
 | 
						|
    }
 | 
						|
 | 
						|
    bool Locals::hasVar(const std::string &script, const std::string &var)
 | 
						|
    {
 | 
						|
        try
 | 
						|
        {
 | 
						|
            ensure (script);
 | 
						|
 | 
						|
            const Compiler::Locals& locals =
 | 
						|
                MWBase::Environment::get().getScriptManager()->getLocals(script);
 | 
						|
            int index = locals.getIndex(var);
 | 
						|
            return (index != -1);
 | 
						|
        }
 | 
						|
        catch (const Compiler::SourceException&)
 | 
						|
        {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    int Locals::getIntVar(const std::string &script, const std::string &var)
 | 
						|
    {
 | 
						|
        ensure (script);
 | 
						|
 | 
						|
        const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script);
 | 
						|
        int index = locals.getIndex(var);
 | 
						|
        char type = locals.getType(var);
 | 
						|
        if(index != -1)
 | 
						|
        {
 | 
						|
            switch(type)
 | 
						|
            {
 | 
						|
                case 's':
 | 
						|
                    return mShorts.at (index);
 | 
						|
 | 
						|
                case 'l':
 | 
						|
                    return mLongs.at (index);
 | 
						|
 | 
						|
                case 'f':
 | 
						|
                    return static_cast<int>(mFloats.at(index));
 | 
						|
                default:
 | 
						|
                    return 0;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    bool Locals::setVarByInt(const std::string& script, const std::string& var, int val)
 | 
						|
    {
 | 
						|
        ensure (script);
 | 
						|
 | 
						|
        const Compiler::Locals& locals = MWBase::Environment::get().getScriptManager()->getLocals(script);
 | 
						|
        int index = locals.getIndex(var);
 | 
						|
        char type = locals.getType(var);
 | 
						|
        if(index != -1)
 | 
						|
        {
 | 
						|
            switch(type)
 | 
						|
            {
 | 
						|
                case 's':
 | 
						|
                    mShorts.at (index) = val; break;
 | 
						|
 | 
						|
                case 'l':
 | 
						|
                    mLongs.at (index) = val; break;
 | 
						|
 | 
						|
                case 'f':
 | 
						|
                    mFloats.at(index) = static_cast<float>(val); break;
 | 
						|
            }
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    bool Locals::write (ESM::Locals& locals, const std::string& script) const
 | 
						|
    {
 | 
						|
        if (!mInitialised)
 | 
						|
            return false;
 | 
						|
 | 
						|
        try
 | 
						|
        {
 | 
						|
            const Compiler::Locals& declarations =
 | 
						|
                MWBase::Environment::get().getScriptManager()->getLocals(script);
 | 
						|
 | 
						|
            for (int i=0; i<3; ++i)
 | 
						|
            {
 | 
						|
                char type = 0;
 | 
						|
 | 
						|
                switch (i)
 | 
						|
                {
 | 
						|
                    case 0: type = 's'; break;
 | 
						|
                    case 1: type = 'l'; break;
 | 
						|
                    case 2: type = 'f'; break;
 | 
						|
                }
 | 
						|
 | 
						|
                const std::vector<std::string>& names = declarations.get (type);
 | 
						|
 | 
						|
                for (int i2=0; i2<static_cast<int> (names.size()); ++i2)
 | 
						|
                {
 | 
						|
                    ESM::Variant value;
 | 
						|
 | 
						|
                    switch (i)
 | 
						|
                    {
 | 
						|
                        case 0: value.setType (ESM::VT_Int); value.setInteger (mShorts.at (i2)); break;
 | 
						|
                        case 1: value.setType (ESM::VT_Int); value.setInteger (mLongs.at (i2)); break;
 | 
						|
                        case 2: value.setType (ESM::VT_Float); value.setFloat (mFloats.at (i2)); break;
 | 
						|
                    }
 | 
						|
 | 
						|
                    locals.mVariables.push_back (std::make_pair (names[i2], value));
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        catch (const Compiler::SourceException&)
 | 
						|
        {
 | 
						|
        }
 | 
						|
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    void Locals::read (const ESM::Locals& locals, const std::string& script)
 | 
						|
    {
 | 
						|
        ensure (script);
 | 
						|
 | 
						|
        try
 | 
						|
        {
 | 
						|
            const Compiler::Locals& declarations =
 | 
						|
                MWBase::Environment::get().getScriptManager()->getLocals(script);
 | 
						|
 | 
						|
            int index = 0, numshorts = 0, numlongs = 0;
 | 
						|
            for (unsigned int v=0; v<locals.mVariables.size();++v)
 | 
						|
            {
 | 
						|
                ESM::VarType type = locals.mVariables[v].second.getType();
 | 
						|
                if (type == ESM::VT_Short)
 | 
						|
                    ++numshorts;
 | 
						|
                else if (type == ESM::VT_Int)
 | 
						|
                    ++numlongs;
 | 
						|
            }
 | 
						|
 | 
						|
            for (std::vector<std::pair<std::string, ESM::Variant> >::const_iterator iter
 | 
						|
                = locals.mVariables.begin(); iter!=locals.mVariables.end(); ++iter,++index)
 | 
						|
            {
 | 
						|
                if (iter->first.empty())
 | 
						|
                {
 | 
						|
                    // no variable names available (this will happen for legacy, i.e. ESS-imported savegames only)
 | 
						|
                    try
 | 
						|
                    {
 | 
						|
                        if (index >= numshorts+numlongs)
 | 
						|
                            mFloats.at(index - (numshorts+numlongs)) = iter->second.getFloat();
 | 
						|
                        else if (index >= numshorts)
 | 
						|
                            mLongs.at(index - numshorts) = iter->second.getInteger();
 | 
						|
                        else
 | 
						|
                            mShorts.at(index) = iter->second.getInteger();
 | 
						|
                    }
 | 
						|
                    catch (std::exception& e)
 | 
						|
                    {
 | 
						|
                        std::cerr << "Failed to read local variable state for script '"
 | 
						|
                                  << script << "' (legacy format): " << e.what()
 | 
						|
                                  << "\nNum shorts: " << numshorts << " / " << mShorts.size()
 | 
						|
                                  << " Num longs: " << numlongs << " / " << mLongs.size() << std::endl;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    char type =  declarations.getType (iter->first);
 | 
						|
                    char index = declarations.getIndex (iter->first);
 | 
						|
 | 
						|
                    try
 | 
						|
                    {
 | 
						|
                        switch (type)
 | 
						|
                        {
 | 
						|
                            case 's': mShorts.at (index) = iter->second.getInteger(); break;
 | 
						|
                            case 'l': mLongs.at (index) = iter->second.getInteger(); break;
 | 
						|
                            case 'f': mFloats.at (index) = iter->second.getFloat(); break;
 | 
						|
 | 
						|
                            // silently ignore locals that don't exist anymore
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    catch (...)
 | 
						|
                    {
 | 
						|
                        // ignore type changes
 | 
						|
                        /// \todo write to log
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        catch (const Compiler::SourceException&)
 | 
						|
        {
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |