1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-10 12:52:39 +01:00
openrw/rwengine/include/script/ScriptMachine.hpp

164 lines
3.5 KiB
C++
Raw Normal View History

2014-07-21 01:34:28 +02:00
#pragma once
#ifndef _SCRIPTMACHINE_HPP_
#define _SCRIPTMACHINE_HPP_
#include <script/ScriptTypes.hpp>
#include <sstream>
#include <iomanip>
2014-07-21 01:34:28 +02:00
#include <string>
2014-07-25 04:30:44 +02:00
#include <stack>
2014-07-21 01:34:28 +02:00
2014-07-25 04:30:44 +02:00
#define SCM_NEGATE_CONDITIONAL_MASK 0x8000
#define SCM_CONDITIONAL_MASK_PASSED 0xFF
#define SCM_THREAD_LOCAL_SIZE 256
2014-07-25 04:30:44 +02:00
/* as shipped, SCM variables are 4 bytes wide, this isn't enough for 64-bit
* pointers, so we re-allocate the global and local space taking into account
* the native pointer size */
#define SCM_VARIABLE_SIZE sizeof(void*)
class GameWorld;
class SCMFile;
2014-07-21 01:34:28 +02:00
struct SCMException
{
virtual ~SCMException() { }
virtual std::string what() const = 0;
};
struct IllegalInstruction : SCMException
{
SCMOpcode opcode;
unsigned int offset;
std::string thread;
2014-07-21 01:34:28 +02:00
IllegalInstruction(SCMOpcode opcode, unsigned int offset, const std::string& thread)
: opcode(opcode), offset(offset), thread(thread) { }
2014-07-21 01:34:28 +02:00
std::string what() const {
std::stringstream ss;
ss << "Illegal Instruction " <<
std::setfill('0') << std::setw(4) << std::hex << opcode <<
" encountered at offset " <<
std::setfill('0') << std::setw(4) << std::hex << offset <<
" on thread " << thread;
2014-07-21 01:34:28 +02:00
return ss.str();
}
};
struct UnknownType : SCMException
{
SCMByte type;
unsigned int offset;
std::string thread;
2014-07-21 01:34:28 +02:00
UnknownType(SCMByte type, unsigned int offset, const std::string& thread)
: type(type), offset(offset), thread(thread) {}
2014-07-21 01:34:28 +02:00
std::string what() const {
std::stringstream ss;
ss << "Unkown data type " <<
std::setfill('0') << std::hex << static_cast<unsigned int>(type) <<
" encountered at offset " <<
std::setfill('0') << std::hex << offset <<
" on thread " << thread;
2014-07-21 01:34:28 +02:00
return ss.str();
}
};
2014-07-25 04:30:44 +02:00
struct UnimplementedOpcode : SCMException
{
SCMOpcode opcode;
SCMParams parameters;
UnimplementedOpcode(SCMOpcode opcode, SCMParams parameters)
: opcode(opcode), parameters(parameters) {}
std::string what() const {
std::stringstream ss;
ss << "Unimplemented opcode " <<
std::setfill('0') << std::hex << opcode <<
" called with parameters:\n";
int i = 0;
for(const SCMOpcodeParameter& p : parameters) {
ss << (i++) << " " << p.type << " ";
switch (p.type) {
case TInt8:
case TInt16:
case TInt32:
ss << p.integer;
break;
case TFloat16:
ss << p.real;
break;
case TGlobal:
ss << "Global: " << p.globalPtr;
break;
default:
ss << "Unprintable";
break;
}
ss << "\n";
}
return ss.str();
}
};
static SCMMicrocodeTable knownOps;
struct SCMThread
{
typedef unsigned int pc_t;
2014-07-21 01:34:28 +02:00
std::string name;
pc_t baseAddress;
pc_t programCounter;
2014-07-25 04:30:44 +02:00
unsigned int conditionCount;
bool conditionResult;
std::uint8_t conditionMask;
bool conditionAND;
/** Number of MS until the thread should be waked (-1 = yeilded) */
int wakeCounter;
2014-07-25 04:30:44 +02:00
SCMByte locals[SCM_THREAD_LOCAL_SIZE * (SCM_VARIABLE_SIZE)];
bool isMission;
bool finished;
/// Stores the return-addresses for calls.
std::stack<pc_t> calls;
2014-07-21 01:34:28 +02:00
};
class ScriptMachine
{
SCMFile* _file;
SCMOpcodes* _ops;
2014-07-25 04:30:44 +02:00
GameWorld* _world;
2014-07-21 01:34:28 +02:00
std::vector<SCMThread> _activeThreads;
2014-07-21 01:34:28 +02:00
void executeThread(SCMThread& t, int msPassed);
2014-07-21 01:34:28 +02:00
2014-07-25 04:30:44 +02:00
SCMByte* _globals;
public:
2014-07-25 04:30:44 +02:00
ScriptMachine(GameWorld* world, SCMFile* file, SCMOpcodes* ops);
~ScriptMachine();
2014-07-25 04:30:44 +02:00
SCMFile* getFile() const { return _file; }
void startThread(SCMThread::pc_t start, bool mission = false);
2014-07-21 01:34:28 +02:00
SCMByte* getGlobals();
2014-07-21 01:34:28 +02:00
2014-07-25 04:30:44 +02:00
GameWorld* getWorld() const { return _world; }
/**
* @brief executes threads until they are all in waiting state.
*/
void execute(float dt);
2014-07-21 01:34:28 +02:00
};
#endif