mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-07 03:12:36 +01:00
Initial Script Machine implementation + some ops
This commit is contained in:
parent
e0a0c4882f
commit
c3e2172f3b
@ -18,6 +18,7 @@ struct DynamicObjectData;
|
|||||||
struct WeaponData;
|
struct WeaponData;
|
||||||
class GameWorld;
|
class GameWorld;
|
||||||
class TextureAtlas;
|
class TextureAtlas;
|
||||||
|
class SCMFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Stores simple data about Textures such as transparency flags.
|
* @brief Stores simple data about Textures such as transparency flags.
|
||||||
@ -103,6 +104,8 @@ public:
|
|||||||
void loadWeather(const std::string& path);
|
void loadWeather(const std::string& path);
|
||||||
|
|
||||||
void loadHandling(const std::string& path);
|
void loadHandling(const std::string& path);
|
||||||
|
|
||||||
|
SCMFile* loadSCM(const std::string& path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads water level data
|
* Loads water level data
|
||||||
|
@ -17,6 +17,8 @@ class VehicleObject;
|
|||||||
|
|
||||||
class WeaponScan;
|
class WeaponScan;
|
||||||
|
|
||||||
|
class ScriptMachine;
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
#include <btBulletDynamicsCommon.h>
|
#include <btBulletDynamicsCommon.h>
|
||||||
@ -77,6 +79,8 @@ public:
|
|||||||
* Loads an IDE into the game
|
* Loads an IDE into the game
|
||||||
*/
|
*/
|
||||||
bool defineItems(const std::string& name);
|
bool defineItems(const std::string& name);
|
||||||
|
|
||||||
|
void runScript(const std::string& name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads an IPL into the game.
|
* Loads an IPL into the game.
|
||||||
@ -214,6 +218,8 @@ public:
|
|||||||
* Work related
|
* Work related
|
||||||
*/
|
*/
|
||||||
WorkContext* _work;
|
WorkContext* _work;
|
||||||
|
|
||||||
|
ScriptMachine* script;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
12
rwengine/include/script/Opcodes3.hpp
Normal file
12
rwengine/include/script/Opcodes3.hpp
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef _OPCODES_3_HPP_
|
||||||
|
#define _OPCODES_3_HPP_
|
||||||
|
#include <script/ScriptTypes.hpp>
|
||||||
|
|
||||||
|
struct Opcodes3 : SCMOpcodes
|
||||||
|
{
|
||||||
|
Opcodes3();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -1,12 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#ifndef _SCMFILE_HPP_
|
#ifndef _SCMFILE_HPP_
|
||||||
#define _SCMFILE_HPP_
|
#define _SCMFILE_HPP_
|
||||||
#include <cstdint>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <script/ScriptTypes.hpp>
|
||||||
typedef uint16_t SCMOpcode;
|
|
||||||
typedef char SCMByte;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Handles in-memory SCM file data including section offsets.
|
* @brief Handles in-memory SCM file data including section offsets.
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#ifndef _SCRIPTMACHINE_HPP_
|
#ifndef _SCRIPTMACHINE_HPP_
|
||||||
#define _SCRIPTMACHINE_HPP_
|
#define _SCRIPTMACHINE_HPP_
|
||||||
|
#include <script/ScriptTypes.hpp>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <vector>
|
||||||
|
|
||||||
#define SCM_CONDITIONAL_MASK 0xF000
|
#define SCM_CONDITIONAL_MASK 0xF000
|
||||||
|
#define SCM_THREAD_LOCAL_SIZE 256
|
||||||
|
|
||||||
|
class SCMFile;
|
||||||
|
|
||||||
struct SCMException
|
struct SCMException
|
||||||
{
|
{
|
||||||
@ -16,16 +22,18 @@ struct IllegalInstruction : SCMException
|
|||||||
{
|
{
|
||||||
SCMOpcode opcode;
|
SCMOpcode opcode;
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
|
std::string thread;
|
||||||
|
|
||||||
IllegalInstruction(SCMOpcode opcode, unsigned int offset)
|
IllegalInstruction(SCMOpcode opcode, unsigned int offset, const std::string& thread)
|
||||||
: opcode(opcode), offset(offset) { }
|
: opcode(opcode), offset(offset), thread(thread) { }
|
||||||
|
|
||||||
std::string what() const {
|
std::string what() const {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Illegal Instruction " <<
|
ss << "Illegal Instruction " <<
|
||||||
std::setfill('0') << std::setw(4) << std::hex << opcode <<
|
std::setfill('0') << std::setw(4) << std::hex << opcode <<
|
||||||
" encountered at offset " <<
|
" encountered at offset " <<
|
||||||
std::setfill('0') << std::setw(4) << std::hex << offset;
|
std::setfill('0') << std::setw(4) << std::hex << offset <<
|
||||||
|
" on thread " << thread;
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -34,54 +42,56 @@ struct UnknownType : SCMException
|
|||||||
{
|
{
|
||||||
SCMByte type;
|
SCMByte type;
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
|
std::string thread;
|
||||||
|
|
||||||
UnknownType(SCMByte type, unsigned int offset)
|
UnknownType(SCMByte type, unsigned int offset, const std::string& thread)
|
||||||
: type(type), offset(offset) {}
|
: type(type), offset(offset), thread(thread) {}
|
||||||
|
|
||||||
std::string what() const {
|
std::string what() const {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Unkown data type " <<
|
ss << "Unkown data type " <<
|
||||||
std::setfill('0') << std::hex << static_cast<unsigned int>(type) <<
|
std::setfill('0') << std::hex << static_cast<unsigned int>(type) <<
|
||||||
" encountered at offset " <<
|
" encountered at offset " <<
|
||||||
std::setfill('0') << std::hex << offset;
|
std::setfill('0') << std::hex << offset <<
|
||||||
|
" on thread " << thread;
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SCMMicrocode {
|
static SCMMicrocodeTable knownOps;
|
||||||
|
|
||||||
|
struct SCMThread
|
||||||
|
{
|
||||||
|
typedef unsigned int pc_t;
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
int parameters;
|
pc_t programCounter;
|
||||||
|
/** Number of MS until the thread should be waked (-1 = yeilded) */
|
||||||
|
int wakeCounter;
|
||||||
|
SCMByte locals[SCM_THREAD_LOCAL_SIZE];
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<SCMOpcode, SCMMicrocode> SCMMicrocodeTable;
|
class ScriptMachine
|
||||||
|
{
|
||||||
|
SCMFile* _file;
|
||||||
|
SCMOpcodes* _ops;
|
||||||
|
|
||||||
SCMMicrocodeTable knownOps;
|
std::vector<SCMThread> _activeThreads;
|
||||||
|
|
||||||
enum SCMType {
|
void executeThread(SCMThread& t, int msPassed);
|
||||||
EndOfArgList = 0x00,
|
|
||||||
TInt32 = 0x01,
|
|
||||||
TGlobal = 0x02,
|
|
||||||
TLocal = 0x03,
|
|
||||||
TInt8 = 0x04,
|
|
||||||
TInt16 = 0x05,
|
|
||||||
TFloat16 = 0x06,
|
|
||||||
TString = 0x09,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SCMTypeInfo {
|
public:
|
||||||
uint8_t size;
|
ScriptMachine(SCMFile* file, SCMOpcodes* ops);
|
||||||
};
|
~ScriptMachine();
|
||||||
|
|
||||||
typedef std::map<SCMType, SCMTypeInfo> SCMTypeInfoTable;
|
void startThread(SCMThread::pc_t start);
|
||||||
|
|
||||||
SCMTypeInfoTable typeData = {
|
SCMByte* getGlobals();
|
||||||
{TInt8, {1}},
|
|
||||||
{TInt16, {2}},
|
/**
|
||||||
{TInt32, {4}},
|
* @brief executes threads until they are all in waiting state.
|
||||||
{TGlobal, {2}},
|
*/
|
||||||
{TLocal, {2}},
|
void execute(float dt);
|
||||||
{TFloat16,{2}},
|
|
||||||
{EndOfArgList, {0}},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
70
rwengine/include/script/ScriptTypes.hpp
Normal file
70
rwengine/include/script/ScriptTypes.hpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef _SCRIPTTYPES_HPP_
|
||||||
|
#define _SCRIPTTYPES_HPP_
|
||||||
|
#include <cstdint>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
class ScriptMachine;
|
||||||
|
class SCMThread;
|
||||||
|
|
||||||
|
typedef uint16_t SCMOpcode;
|
||||||
|
typedef char SCMByte;
|
||||||
|
|
||||||
|
enum SCMType {
|
||||||
|
EndOfArgList = 0x00,
|
||||||
|
TInt32 = 0x01,
|
||||||
|
TGlobal = 0x02,
|
||||||
|
TLocal = 0x03,
|
||||||
|
TInt8 = 0x04,
|
||||||
|
TInt16 = 0x05,
|
||||||
|
TFloat16 = 0x06,
|
||||||
|
TString = 0x09,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SCMTypeInfo {
|
||||||
|
uint8_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::map<SCMType, SCMTypeInfo> SCMTypeInfoTable;
|
||||||
|
|
||||||
|
static SCMTypeInfoTable typeData = {
|
||||||
|
{TInt8, {1}},
|
||||||
|
{TInt16, {2}},
|
||||||
|
{TInt32, {4}},
|
||||||
|
{TGlobal, {2}},
|
||||||
|
{TLocal, {2}},
|
||||||
|
{TFloat16,{2}},
|
||||||
|
{EndOfArgList, {0}},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct SCMOpcodeParameter {
|
||||||
|
SCMType type;
|
||||||
|
union {
|
||||||
|
int integer;
|
||||||
|
float real;
|
||||||
|
char string[8];
|
||||||
|
void* globalPtr;
|
||||||
|
int* globalInteger;
|
||||||
|
float* globalReal;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<SCMOpcodeParameter> SCMParams;
|
||||||
|
|
||||||
|
struct SCMMicrocode {
|
||||||
|
std::string name;
|
||||||
|
int parameters;
|
||||||
|
std::function<void (ScriptMachine*, SCMThread*, std::vector<SCMOpcodeParameter>*)> func;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::map<SCMOpcode, SCMMicrocode> SCMMicrocodeTable;
|
||||||
|
|
||||||
|
struct SCMOpcodes
|
||||||
|
{
|
||||||
|
std::map<SCMOpcode, SCMMicrocode> codes;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -7,6 +7,7 @@
|
|||||||
#include <loaders/LoaderCOL.hpp>
|
#include <loaders/LoaderCOL.hpp>
|
||||||
#include <data/ObjectData.hpp>
|
#include <data/ObjectData.hpp>
|
||||||
#include <data/WeaponData.hpp>
|
#include <data/WeaponData.hpp>
|
||||||
|
#include <script/SCMFile.hpp>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@ -347,6 +348,25 @@ void GameData::loadHandling(const std::string& path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SCMFile *GameData::loadSCM(const std::string &path)
|
||||||
|
{
|
||||||
|
std::ifstream f(datpath + "/" + path);
|
||||||
|
|
||||||
|
if(! f.is_open() ) return nullptr;
|
||||||
|
|
||||||
|
f.seekg(0, std::ios_base::end);
|
||||||
|
unsigned int size = f.tellg();
|
||||||
|
f.seekg(0);
|
||||||
|
|
||||||
|
char* buff = new char[size];
|
||||||
|
f.read(buff, size);
|
||||||
|
SCMFile* scm = new SCMFile;
|
||||||
|
scm->loadFile(buff, size);
|
||||||
|
delete buff;
|
||||||
|
|
||||||
|
return scm;
|
||||||
|
}
|
||||||
|
|
||||||
void GameData::loadWaterpro(const std::string& path)
|
void GameData::loadWaterpro(const std::string& path)
|
||||||
{
|
{
|
||||||
std::ifstream ifstr(path.c_str());
|
std::ifstream ifstr(path.c_str());
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
#include <data/WeaponData.hpp>
|
#include <data/WeaponData.hpp>
|
||||||
#include <WorkContext.hpp>
|
#include <WorkContext.hpp>
|
||||||
|
|
||||||
|
#include <script/Opcodes3.hpp>
|
||||||
|
#include <script/ScriptMachine.hpp>
|
||||||
|
|
||||||
// 3 isn't enough to cause a factory.
|
// 3 isn't enough to cause a factory.
|
||||||
#include <objects/CharacterObject.hpp>
|
#include <objects/CharacterObject.hpp>
|
||||||
#include <objects/InstanceObject.hpp>
|
#include <objects/InstanceObject.hpp>
|
||||||
@ -67,7 +70,7 @@ public:
|
|||||||
|
|
||||||
GameWorld::GameWorld(const std::string& path)
|
GameWorld::GameWorld(const std::string& path)
|
||||||
: gameTime(0.f), gameData(path), renderer(this), randomEngine(rand()),
|
: gameTime(0.f), gameData(path), renderer(this), randomEngine(rand()),
|
||||||
_work( new WorkContext( this ) )
|
_work( new WorkContext( this ) ), script(nullptr)
|
||||||
{
|
{
|
||||||
gameData.engine = this;
|
gameData.engine = this;
|
||||||
}
|
}
|
||||||
@ -167,6 +170,19 @@ bool GameWorld::defineItems(const std::string& name)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameWorld::runScript(const std::string &name)
|
||||||
|
{
|
||||||
|
SCMFile* f = gameData.loadSCM(name);
|
||||||
|
if( f ) {
|
||||||
|
if( script ) delete script;
|
||||||
|
|
||||||
|
script = new ScriptMachine(f, new Opcodes3);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logError("Failed to load SCM: " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool GameWorld::placeItems(const std::string& name)
|
bool GameWorld::placeItems(const std::string& name)
|
||||||
{
|
{
|
||||||
auto i = gameData.iplLocations.find(name);
|
auto i = gameData.iplLocations.find(name);
|
||||||
|
94
rwengine/src/script/Opcodes3.cpp
Normal file
94
rwengine/src/script/Opcodes3.cpp
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
#include <script/Opcodes3.hpp>
|
||||||
|
#include <script/ScriptMachine.hpp>
|
||||||
|
|
||||||
|
SCMMicrocodeTable ops_global = {
|
||||||
|
{ 0x0002,
|
||||||
|
{
|
||||||
|
"Jump",
|
||||||
|
1,
|
||||||
|
[](ScriptMachine*, SCMThread* t, SCMParams* p)
|
||||||
|
{
|
||||||
|
t->programCounter = p->at(0).integer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{ 0x0004,
|
||||||
|
{
|
||||||
|
"Set Global Integer",
|
||||||
|
2,
|
||||||
|
[](ScriptMachine*, SCMThread*, SCMParams* p)
|
||||||
|
{
|
||||||
|
*p->at(0).globalInteger = p->at(1).integer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{ 0x0005,
|
||||||
|
{
|
||||||
|
"Set Global Float",
|
||||||
|
2,
|
||||||
|
[](ScriptMachine*, SCMThread*, SCMParams* p)
|
||||||
|
{
|
||||||
|
*p->at(0).globalReal = p->at(1).real;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{ 0x0015,
|
||||||
|
{
|
||||||
|
"Divide Global by Float",
|
||||||
|
2,
|
||||||
|
[](ScriptMachine*, SCMThread*, SCMParams* p)
|
||||||
|
{
|
||||||
|
*p->at(0).globalReal /= p->at(1).real;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{ 0x0086,
|
||||||
|
{
|
||||||
|
"Set Global Float To Global",
|
||||||
|
2,
|
||||||
|
[](ScriptMachine*, SCMThread*, SCMParams* p)
|
||||||
|
{
|
||||||
|
*p->at(0).globalReal = *p->at(1).globalReal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{ 0x03A4,
|
||||||
|
{
|
||||||
|
"Name Thread",
|
||||||
|
1,
|
||||||
|
[](ScriptMachine*, SCMThread* t, SCMParams* p)
|
||||||
|
{
|
||||||
|
t->name = p->at(0).string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SCM_FUNC(c) [](ScriptMachine* m, SCMThread* t, SCMParams* p) c
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
SCMMicrocodeTable ops_game = {
|
||||||
|
|
||||||
|
{ 0x042C,
|
||||||
|
{ "Set Total Missions", 1,
|
||||||
|
SCM_FUNC({
|
||||||
|
std::cout << "Total Missions: " << p->at(0).integer << std::endl;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Opcodes3::Opcodes3()
|
||||||
|
{
|
||||||
|
codes.insert(ops_global.begin(), ops_global.end());
|
||||||
|
codes.insert(ops_game.begin(), ops_game.end());
|
||||||
|
}
|
@ -0,0 +1,111 @@
|
|||||||
|
#include <script/ScriptMachine.hpp>
|
||||||
|
#include <script/SCMFile.hpp>
|
||||||
|
|
||||||
|
void ScriptMachine::executeThread(SCMThread &t, int msPassed)
|
||||||
|
{
|
||||||
|
if( t.wakeCounter > 0 ) {
|
||||||
|
t.wakeCounter = std::max( t.wakeCounter - msPassed, 0 );
|
||||||
|
}
|
||||||
|
if( t.wakeCounter > 0 ) return;
|
||||||
|
|
||||||
|
while( t.wakeCounter == 0 ) {
|
||||||
|
auto opcode = _file->read<SCMOpcode>(t.programCounter);
|
||||||
|
auto it = _ops->codes.find(opcode);
|
||||||
|
if( it == _ops->codes.end() ) throw IllegalInstruction(opcode, t.programCounter, t.name);
|
||||||
|
t.programCounter += sizeof(SCMOpcode);
|
||||||
|
|
||||||
|
SCMMicrocode& code = it->second;
|
||||||
|
|
||||||
|
SCMParams parameters;
|
||||||
|
|
||||||
|
for( int p = 0; p < code.parameters; ++p ) {
|
||||||
|
auto type_r = _file->read<SCMByte>(t.programCounter);
|
||||||
|
auto type = static_cast<SCMType>(type_r);
|
||||||
|
|
||||||
|
if( type_r > 42 ) {
|
||||||
|
// for implicit strings, we need the byte we just read.
|
||||||
|
type = TString;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
t.programCounter += sizeof(SCMByte);
|
||||||
|
}
|
||||||
|
|
||||||
|
parameters.push_back(SCMOpcodeParameter { type, 0 });
|
||||||
|
switch(type) {
|
||||||
|
case TInt8:
|
||||||
|
parameters.back().integer = _file->read<std::uint8_t>(t.programCounter);
|
||||||
|
t.programCounter += sizeof(SCMByte);
|
||||||
|
break;
|
||||||
|
case TInt16:
|
||||||
|
parameters.back().integer = _file->read<std::uint16_t>(t.programCounter);
|
||||||
|
t.programCounter += sizeof(SCMByte) * 2;
|
||||||
|
break;
|
||||||
|
case TGlobal: {
|
||||||
|
auto v = _file->read<std::uint16_t>(t.programCounter);
|
||||||
|
parameters.back().globalPtr = getGlobals() + v;
|
||||||
|
t.programCounter += sizeof(SCMByte) * 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TInt32:
|
||||||
|
parameters.back().integer = _file->read<std::uint32_t>(t.programCounter);
|
||||||
|
t.programCounter += sizeof(SCMByte) * 4;
|
||||||
|
break;
|
||||||
|
case TString:
|
||||||
|
std::copy(_file->data()+t.programCounter, _file->data()+t.programCounter+8,
|
||||||
|
parameters.back().string);
|
||||||
|
t.programCounter += sizeof(SCMByte) * 8;
|
||||||
|
break;
|
||||||
|
case TFloat16:
|
||||||
|
parameters.back().real = (float)(_file->read<std::uint16_t>(t.programCounter)) / 16.f;
|
||||||
|
t.programCounter += sizeof(SCMByte) * 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw UnknownType(type, t.programCounter, t.name);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
code.func(this, &t, ¶meters);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( t.wakeCounter == -1 ) {
|
||||||
|
t.wakeCounter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptMachine::ScriptMachine(SCMFile *file, SCMOpcodes *ops)
|
||||||
|
: _file(file), _ops(ops)
|
||||||
|
{
|
||||||
|
startThread(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptMachine::~ScriptMachine()
|
||||||
|
{
|
||||||
|
delete _file;
|
||||||
|
delete _ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptMachine::startThread(SCMThread::pc_t start)
|
||||||
|
{
|
||||||
|
SCMThread t;
|
||||||
|
for(int i = 0; i < SCM_THREAD_LOCAL_SIZE; ++i) {
|
||||||
|
t.locals[i] = 0;
|
||||||
|
}
|
||||||
|
t.name = "THREAD";
|
||||||
|
t.programCounter = start;
|
||||||
|
t.wakeCounter = 0;
|
||||||
|
_activeThreads.push_back(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
SCMByte *ScriptMachine::getGlobals()
|
||||||
|
{
|
||||||
|
return _file->data() + _file->getGlobalSection();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptMachine::execute(float dt)
|
||||||
|
{
|
||||||
|
int ms = dt * 1000.f;
|
||||||
|
for(auto& thread : _activeThreads) {
|
||||||
|
executeThread( thread, ms );
|
||||||
|
}
|
||||||
|
}
|
@ -7,9 +7,20 @@
|
|||||||
#include <objects/ItemPickup.hpp>
|
#include <objects/ItemPickup.hpp>
|
||||||
#include <render/Model.hpp>
|
#include <render/Model.hpp>
|
||||||
#include <items/WeaponItem.hpp>
|
#include <items/WeaponItem.hpp>
|
||||||
|
#include <script/ScriptMachine.hpp>
|
||||||
|
|
||||||
IngameState::IngameState()
|
IngameState::IngameState(bool test)
|
||||||
: _player(nullptr), _playerCharacter(nullptr)
|
: _player(nullptr), _playerCharacter(nullptr)
|
||||||
|
{
|
||||||
|
if( test ) {
|
||||||
|
startTest();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
getWorld()->runScript("data/main.scm");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IngameState::startTest()
|
||||||
{
|
{
|
||||||
_playerCharacter = getWorld()->createPedestrian(1, {-1000.f, -990.f, 13.f});
|
_playerCharacter = getWorld()->createPedestrian(1, {-1000.f, -990.f, 13.f});
|
||||||
_player = new PlayerController(_playerCharacter);
|
_player = new PlayerController(_playerCharacter);
|
||||||
@ -72,17 +83,7 @@ void IngameState::spawnPlayerVehicle()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IngameState::enter()
|
void IngameState::updateView()
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void IngameState::exit()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void IngameState::tick(float dt)
|
|
||||||
{
|
{
|
||||||
float qpi = glm::half_pi<float>();
|
float qpi = glm::half_pi<float>();
|
||||||
|
|
||||||
@ -153,6 +154,34 @@ void IngameState::tick(float dt)
|
|||||||
setViewParameters( viewPos + localview * viewFraction, {localX, _lookAngles.y} );
|
setViewParameters( viewPos + localview * viewFraction, {localX, _lookAngles.y} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IngameState::enter()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void IngameState::exit()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void IngameState::tick(float dt)
|
||||||
|
{
|
||||||
|
if( _player ) {
|
||||||
|
updateView();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( getWorld()->script ) {
|
||||||
|
try {
|
||||||
|
getWorld()->script->execute(dt);
|
||||||
|
}
|
||||||
|
catch( SCMException& ex ) {
|
||||||
|
std::cerr << ex.what() << std::endl;
|
||||||
|
getWorld()->logError( ex.what() );
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void IngameState::handleEvent(const sf::Event &event)
|
void IngameState::handleEvent(const sf::Event &event)
|
||||||
{
|
{
|
||||||
switch(event.type) {
|
switch(event.type) {
|
||||||
|
@ -13,10 +13,13 @@ class IngameState : public State
|
|||||||
glm::vec2 _lookAngles;
|
glm::vec2 _lookAngles;
|
||||||
glm::vec3 _movement;
|
glm::vec3 _movement;
|
||||||
public:
|
public:
|
||||||
IngameState();
|
IngameState(bool test = false);
|
||||||
|
|
||||||
|
void startTest();
|
||||||
void spawnPlayerVehicle();
|
void spawnPlayerVehicle();
|
||||||
|
|
||||||
|
void updateView();
|
||||||
|
|
||||||
virtual void enter();
|
virtual void enter();
|
||||||
virtual void exit();
|
virtual void exit();
|
||||||
|
|
||||||
|
@ -6,7 +6,8 @@ MenuState::MenuState()
|
|||||||
{
|
{
|
||||||
Menu *m = new Menu(getFont());
|
Menu *m = new Menu(getFont());
|
||||||
m->offset = glm::vec2(50.f, 100.f);
|
m->offset = glm::vec2(50.f, 100.f);
|
||||||
m->addEntry(Menu::lambda("Test", [] { StateManager::get().enter(new IngameState); }));
|
m->addEntry(Menu::lambda("Start", [] { StateManager::get().enter(new IngameState); }));
|
||||||
|
m->addEntry(Menu::lambda("Test", [] { StateManager::get().enter(new IngameState(true)); }));
|
||||||
m->addEntry(Menu::lambda("Options", [] { std::cout << "Options" << std::endl; }));
|
m->addEntry(Menu::lambda("Options", [] { std::cout << "Options" << std::endl; }));
|
||||||
m->addEntry(Menu::lambda("Exit", [] { getWindow().close(); }));
|
m->addEntry(Menu::lambda("Exit", [] { getWindow().close(); }));
|
||||||
this->enterMenu(m);
|
this->enterMenu(m);
|
||||||
|
@ -49,7 +49,7 @@ void dumpOpcodes(SCMFile* scm, unsigned int offset, unsigned int size)
|
|||||||
|
|
||||||
// If we don't know the size of the operator's parameters we can't jump over it.
|
// If we don't know the size of the operator's parameters we can't jump over it.
|
||||||
if( opit == knownOps.end() ) {
|
if( opit == knownOps.end() ) {
|
||||||
throw IllegalInstruction(op, i);
|
throw IllegalInstruction(op, i, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << std::hex << std::setfill('0') << std::right <<
|
std::cout << std::hex << std::setfill('0') << std::right <<
|
||||||
@ -67,7 +67,7 @@ void dumpOpcodes(SCMFile* scm, unsigned int offset, unsigned int size)
|
|||||||
auto typeit = typeData.find(static_cast<SCMType>(datatype));
|
auto typeit = typeData.find(static_cast<SCMType>(datatype));
|
||||||
if( typeit == typeData.end()) {
|
if( typeit == typeData.end()) {
|
||||||
if( datatype < 0x06 ) {
|
if( datatype < 0x06 ) {
|
||||||
throw UnknownType(datatype, i);
|
throw UnknownType(datatype, i, "");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
datatype = TString;
|
datatype = TString;
|
||||||
|
29
tests/test_scriptmachine.cpp
Normal file
29
tests/test_scriptmachine.cpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
#include "test_globals.hpp"
|
||||||
|
#include <script/ScriptMachine.hpp>
|
||||||
|
#include <script/SCMFile.hpp>
|
||||||
|
|
||||||
|
SCMByte data[] = {
|
||||||
|
0x02,0x00,0x01,0x08,0x00,0x00,0x00,0x00,
|
||||||
|
0x02,0x00,0x01,0x18,0x00,0x00,0x00,0x00,
|
||||||
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x02,0x00,0x01,0x28,0x00,0x00,0x00,0x00,
|
||||||
|
0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||||
|
0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE(ScriptMachineTests)
|
||||||
|
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(scmfile_test)
|
||||||
|
{
|
||||||
|
SCMFile f;
|
||||||
|
f.loadFile(data, sizeof(data));
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL( f.getModelSection(), 0x10 );
|
||||||
|
BOOST_CHECK_EQUAL( f.getMissionSection(), 0x20 );
|
||||||
|
BOOST_CHECK_EQUAL( f.getCodeSection(), 0x28 );
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
Loading…
Reference in New Issue
Block a user