mirror of
https://github.com/rwengine/openrw.git
synced 2024-11-22 10:22:52 +01:00
Add breakpoints to ScriptMachine, remove from GameWorld.
+ Adds breakpoints on program counter values to the ScriptMachine. + Adds breakpoint handler for acting on breakpoints + Remove GameWorld::script and make RWGame responsible for script
This commit is contained in:
parent
a20d170d16
commit
159510cace
@ -23,8 +23,6 @@ class VehicleObject;
|
||||
|
||||
struct WeaponScan;
|
||||
|
||||
class ScriptMachine;
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <btBulletDynamicsCommon.h>
|
||||
@ -70,8 +68,6 @@ public:
|
||||
*/
|
||||
bool defineItems(const std::string& name);
|
||||
|
||||
void runScript(const std::string& name);
|
||||
|
||||
/**
|
||||
* Loads an IPL into the game.
|
||||
* @param name The name of the IPL as it appears in the games' gta.dat
|
||||
@ -241,8 +237,6 @@ public:
|
||||
*/
|
||||
WorkContext* _work;
|
||||
|
||||
ScriptMachine* script;
|
||||
|
||||
/**
|
||||
* @brief Loads and starts the named cutscene.
|
||||
* @param name
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <stack>
|
||||
#include <set>
|
||||
|
||||
#define SCM_NEGATE_CONDITIONAL_MASK 0x8000
|
||||
#define SCM_CONDITIONAL_MASK_PASSED 0xFF
|
||||
@ -130,18 +131,20 @@ struct SCMThread
|
||||
std::stack<pc_t> calls;
|
||||
};
|
||||
|
||||
/**
|
||||
* Breakpoint callback information
|
||||
*/
|
||||
struct SCMBreakpoint
|
||||
{
|
||||
SCMThread::pc_t pc;
|
||||
SCMThread* thread;
|
||||
ScriptMachine* vm;
|
||||
ScriptFunctionMeta* function;
|
||||
ScriptArguments* args;
|
||||
};
|
||||
|
||||
class ScriptMachine
|
||||
{
|
||||
SCMFile* _file;
|
||||
SCMOpcodes* _ops;
|
||||
GameWorld* _world;
|
||||
|
||||
std::vector<SCMThread> _activeThreads;
|
||||
|
||||
void executeThread(SCMThread& t, int msPassed);
|
||||
|
||||
SCMByte* _globals;
|
||||
|
||||
public:
|
||||
ScriptMachine(GameWorld* world, SCMFile* file, SCMOpcodes* ops);
|
||||
~ScriptMachine();
|
||||
@ -153,11 +156,32 @@ public:
|
||||
SCMByte* getGlobals();
|
||||
|
||||
GameWorld* getWorld() const { return _world; }
|
||||
|
||||
typedef std::function<void (const SCMBreakpoint&)> BreakpointHandler;
|
||||
|
||||
void setBreakpointHandler(const BreakpointHandler& handler);
|
||||
|
||||
void addBreakpoint(SCMThread::pc_t pc);
|
||||
void removeBreakpoint(SCMThread::pc_t pc);
|
||||
|
||||
/**
|
||||
* @brief executes threads until they are all in waiting state.
|
||||
*/
|
||||
void execute(float dt);
|
||||
|
||||
private:
|
||||
SCMFile* _file;
|
||||
SCMOpcodes* _ops;
|
||||
GameWorld* _world;
|
||||
|
||||
std::vector<SCMThread> _activeThreads;
|
||||
|
||||
void executeThread(SCMThread& t, int msPassed);
|
||||
|
||||
SCMByte* _globals;
|
||||
|
||||
BreakpointHandler bpHandler;
|
||||
std::set<SCMThread::pc_t> breakpoints;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -11,11 +11,6 @@
|
||||
#include <data/WeaponData.hpp>
|
||||
#include <WorkContext.hpp>
|
||||
|
||||
#include <script/ScriptMachine.hpp>
|
||||
#include <script/modules/VMModule.hpp>
|
||||
#include <script/modules/GameModule.hpp>
|
||||
#include <script/modules/ObjectModule.hpp>
|
||||
|
||||
// 3 isn't enough to cause a factory.
|
||||
#include <objects/CharacterObject.hpp>
|
||||
#include <objects/InstanceObject.hpp>
|
||||
@ -80,7 +75,7 @@ public:
|
||||
|
||||
GameWorld::GameWorld(Logger* log, const std::string& path)
|
||||
: logger(log), gameTime(0.f), gameData(log, path), randomEngine(rand()),
|
||||
_work( new WorkContext( this ) ), script(nullptr), cutsceneAudio(nullptr), missionAudio(nullptr),
|
||||
_work( new WorkContext( this ) ), cutsceneAudio(nullptr), missionAudio(nullptr),
|
||||
paused(false)
|
||||
{
|
||||
gameData.engine = this;
|
||||
@ -144,24 +139,6 @@ bool GameWorld::defineItems(const std::string& name)
|
||||
return false;
|
||||
}
|
||||
|
||||
void GameWorld::runScript(const std::string &name)
|
||||
{
|
||||
SCMFile* f = gameData.loadSCM(name);
|
||||
if( f ) {
|
||||
if( script ) delete script;
|
||||
|
||||
SCMOpcodes* opcodes = new SCMOpcodes;
|
||||
opcodes->modules.push_back(new VMModule);
|
||||
opcodes->modules.push_back(new GameModule);
|
||||
opcodes->modules.push_back(new ObjectModule);
|
||||
|
||||
script = new ScriptMachine(this, f, opcodes);
|
||||
}
|
||||
else {
|
||||
logger->error("World", "Failed to load SCM: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
bool GameWorld::placeItems(const std::string& name)
|
||||
{
|
||||
auto i = gameData.iplLocations.find(name);
|
||||
|
@ -29,26 +29,13 @@ bool SCMOpcodes::findOpcode(ScriptFunctionID id, ScriptFunctionMeta** out)
|
||||
|
||||
void ScriptMachine::executeThread(SCMThread &t, int msPassed)
|
||||
{
|
||||
#if SCM_DEBUG_INSTRUCTIONS
|
||||
std::string threadfilter;
|
||||
if(getenv("SCM_DEBUG_THREAD"))
|
||||
{
|
||||
threadfilter = getenv("SCM_DEBUG_THREAD");
|
||||
}
|
||||
|
||||
bool debug_op = threadfilter.empty() || threadfilter.find(t.name) != std::string::npos || threadfilter.find(std::to_string(t.baseAddress)) != std::string::npos;
|
||||
|
||||
if ( debug_op )
|
||||
{
|
||||
_world->logger.verbose("SCM", "Thread " + t.name + " woke at " + std::to_string(t.wakeCounter) );
|
||||
}
|
||||
#endif
|
||||
|
||||
if( t.wakeCounter > 0 ) {
|
||||
t.wakeCounter = std::max( t.wakeCounter - msPassed, 0 );
|
||||
}
|
||||
if( t.wakeCounter > 0 ) return;
|
||||
|
||||
bool hasDebugging = !! bpHandler;
|
||||
|
||||
while( t.wakeCounter == 0 ) {
|
||||
auto opcode = _file->read<SCMOpcode>(t.programCounter);
|
||||
auto opcorg = opcode;
|
||||
@ -63,6 +50,8 @@ void ScriptMachine::executeThread(SCMThread &t, int msPassed)
|
||||
}
|
||||
ScriptFunctionMeta& code = *foundcode;
|
||||
|
||||
// Keep the pc for the debugger
|
||||
auto pc = t.programCounter;
|
||||
t.programCounter += sizeof(SCMOpcode);
|
||||
|
||||
SCMParams parameters;
|
||||
@ -126,81 +115,25 @@ void ScriptMachine::executeThread(SCMThread &t, int msPassed)
|
||||
};
|
||||
}
|
||||
|
||||
if(! code.function)
|
||||
if(code.function)
|
||||
{
|
||||
#if SCM_DEBUG_INSTRUCTIONS
|
||||
std::cout << std::setw(7) << std::setfill(' ') << t.name <<
|
||||
" " << std::dec << std::setw(8) << std::setfill(' ') << t.programCounter <<
|
||||
" " << std::hex << std::setw(4) << std::setfill('0') << opcorg <<
|
||||
" " << std::dec;
|
||||
for(SCMOpcodeParameter& p : parameters) {
|
||||
std::cout << p.type << ":";
|
||||
switch(p.type) {
|
||||
case TGlobal:
|
||||
case TLocal:
|
||||
std::cout << *p.globalInteger;
|
||||
break;
|
||||
case TInt8:
|
||||
case TInt16:
|
||||
case TInt32:
|
||||
std::cout << p.integer;
|
||||
break;
|
||||
case TFloat16:
|
||||
std::cout << p.real;
|
||||
break;
|
||||
case TString:
|
||||
std::cout << p.string;
|
||||
break;
|
||||
}
|
||||
std::cout << " ";
|
||||
}
|
||||
std::cout << code.signature << " unimplemented"<< std::endl;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#if SCM_DEBUG_INSTRUCTIONS
|
||||
if( debug_op )
|
||||
{
|
||||
std::cout << std::setw(7) << std::setfill(' ') << t.name <<
|
||||
" " << std::dec << std::setw(8) << std::setfill(' ') << t.programCounter <<
|
||||
" " << std::hex << std::setw(4) << std::setfill('0') << opcorg <<
|
||||
" " << std::dec;
|
||||
for(SCMOpcodeParameter& p : parameters) {
|
||||
std::cout << p.type << ":";
|
||||
switch(p.type) {
|
||||
case TGlobal:
|
||||
case TLocal:
|
||||
std::cout << *p.globalInteger << "(" << p.globalInteger << ")";
|
||||
break;
|
||||
case TInt8:
|
||||
case TInt16:
|
||||
case TInt32:
|
||||
std::cout << p.integer;
|
||||
break;
|
||||
case TFloat16:
|
||||
std::cout << p.real;
|
||||
break;
|
||||
case TString:
|
||||
std::cout << p.string;
|
||||
break;
|
||||
}
|
||||
std::cout << " ";
|
||||
}
|
||||
std::cout << code.signature << std::endl;
|
||||
}
|
||||
#endif
|
||||
ScriptArguments sca(¶meters, &t, this);
|
||||
code.function(sca);
|
||||
#if SCM_DEBUG_INSTRUCTIONS
|
||||
if( debug_op )
|
||||
|
||||
if( hasDebugging )
|
||||
{
|
||||
if( code.conditional )
|
||||
if( breakpoints.find(pc) != breakpoints.end() )
|
||||
{
|
||||
std::cout << " => " << t.conditionResult << std::endl;
|
||||
SCMBreakpoint bp;
|
||||
bp.pc = pc;
|
||||
bp.thread = &t;
|
||||
bp.vm = this;
|
||||
bp.function = &code;
|
||||
bp.args = &sca;
|
||||
bpHandler(bp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
code.function(sca);
|
||||
}
|
||||
|
||||
if(isNegatedConditional) {
|
||||
@ -299,3 +232,20 @@ void ScriptMachine::execute(float dt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptMachine::setBreakpointHandler(const ScriptMachine::BreakpointHandler& handler)
|
||||
{
|
||||
bpHandler = handler;
|
||||
}
|
||||
|
||||
void ScriptMachine::addBreakpoint(SCMThread::pc_t pc)
|
||||
{
|
||||
breakpoints.insert(pc);
|
||||
}
|
||||
|
||||
void ScriptMachine::removeBreakpoint(SCMThread::pc_t pc)
|
||||
{
|
||||
breakpoints.erase(pc);
|
||||
}
|
||||
|
||||
|
||||
|
@ -10,7 +10,11 @@
|
||||
#include <engine/GameWorld.hpp>
|
||||
#include <render/GameRenderer.hpp>
|
||||
#include <render/DebugDraw.hpp>
|
||||
|
||||
#include <script/ScriptMachine.hpp>
|
||||
#include <script/modules/VMModule.hpp>
|
||||
#include <script/modules/GameModule.hpp>
|
||||
#include <script/modules/ObjectModule.hpp>
|
||||
|
||||
#include <data/CutsceneData.hpp>
|
||||
#include <ai/PlayerController.hpp>
|
||||
@ -22,12 +26,13 @@ DebugDraw* debug;
|
||||
StdOutReciever logPrinter;
|
||||
|
||||
RWGame::RWGame(const std::string& gamepath, int argc, char* argv[])
|
||||
: engine(nullptr), renderer(nullptr), inFocus(true), showDebugStats(false),
|
||||
: engine(nullptr), renderer(nullptr), script(nullptr), inFocus(true), showDebugStats(false),
|
||||
accum(0.f), timescale(1.f)
|
||||
{
|
||||
size_t w = GAME_WINDOW_WIDTH, h = GAME_WINDOW_HEIGHT;
|
||||
bool fullscreen = false;
|
||||
bool newgame = false;
|
||||
bool debugscript = false;
|
||||
|
||||
for( int i = 1; i < argc; ++i )
|
||||
{
|
||||
@ -47,6 +52,10 @@ RWGame::RWGame(const std::string& gamepath, int argc, char* argv[])
|
||||
{
|
||||
newgame = true;
|
||||
}
|
||||
if( strcmp( "--debug", argv[i] ) == 0 )
|
||||
{
|
||||
debugscript = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -128,10 +137,51 @@ RWGame::RWGame(const std::string& gamepath, int argc, char* argv[])
|
||||
|
||||
RWGame::~RWGame()
|
||||
{
|
||||
delete script;
|
||||
delete renderer;
|
||||
delete engine;
|
||||
}
|
||||
|
||||
void RWGame::startScript(const std::string& name)
|
||||
{
|
||||
SCMFile* f = engine->gameData.loadSCM(name);
|
||||
if( f ) {
|
||||
if( script ) delete script;
|
||||
|
||||
SCMOpcodes* opcodes = new SCMOpcodes;
|
||||
opcodes->modules.push_back(new VMModule);
|
||||
opcodes->modules.push_back(new GameModule);
|
||||
opcodes->modules.push_back(new ObjectModule);
|
||||
|
||||
script = new ScriptMachine(engine, f, opcodes);
|
||||
|
||||
// Set up breakpoint handler
|
||||
script->setBreakpointHandler(
|
||||
[&](const SCMBreakpoint& bp)
|
||||
{
|
||||
log.info("Script", "Breakpoint hit!");
|
||||
std::stringstream ss;
|
||||
ss << " " << bp.function->description << ".";
|
||||
ss << " Args:";
|
||||
for(int a = 0; a < bp.args->getParameters().size(); a++)
|
||||
{
|
||||
auto& arg = bp.args->getParameters()[a];
|
||||
ss << " " << arg.integerValue();
|
||||
if( a != bp.args->getParameters().size()-1 )
|
||||
{
|
||||
ss << ",";
|
||||
}
|
||||
}
|
||||
|
||||
log.info("Script", ss.str());
|
||||
});
|
||||
script->addBreakpoint(0);
|
||||
}
|
||||
else {
|
||||
log.error("Game", "Failed to load SCM: " + name);
|
||||
}
|
||||
}
|
||||
|
||||
int RWGame::run()
|
||||
{
|
||||
clock.restart();
|
||||
@ -250,9 +300,9 @@ void RWGame::tick(float dt)
|
||||
|
||||
engine->dynamicsWorld->stepSimulation(dt, 2, dt);
|
||||
|
||||
if( engine->script ) {
|
||||
if( script ) {
|
||||
try {
|
||||
engine->script->execute(dt);
|
||||
script->execute(dt);
|
||||
}
|
||||
catch( SCMException& ex ) {
|
||||
std::cerr << ex.what() << std::endl;
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <core/Logger.hpp>
|
||||
#include <engine/GameWorld.hpp>
|
||||
#include <render/GameRenderer.hpp>
|
||||
#include <script/ScriptMachine.hpp>
|
||||
#include "game.hpp"
|
||||
|
||||
#include <SFML/Graphics.hpp>
|
||||
@ -14,6 +15,7 @@ class RWGame
|
||||
GameWorld* engine;
|
||||
// must be allocated after Logger setup.
|
||||
GameRenderer* renderer;
|
||||
ScriptMachine* script;
|
||||
sf::RenderWindow window;
|
||||
sf::Clock clock;
|
||||
bool inFocus;
|
||||
@ -45,6 +47,11 @@ public:
|
||||
return window;
|
||||
}
|
||||
|
||||
ScriptMachine* getScript() const
|
||||
{
|
||||
return script;
|
||||
}
|
||||
|
||||
bool hitWorldRay(glm::vec3 &hit, glm::vec3 &normal, GameObject** object = nullptr)
|
||||
{
|
||||
auto vc = nextCam;
|
||||
@ -74,6 +81,8 @@ public:
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void startScript(const std::string& name);
|
||||
|
||||
private:
|
||||
void tick(float dt);
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <render/Model.hpp>
|
||||
#include <items/WeaponItem.hpp>
|
||||
#include <engine/GameWorld.hpp>
|
||||
#include <script/ScriptMachine.hpp>
|
||||
|
||||
#define AUTOLOOK_TIME 2.f
|
||||
|
||||
@ -68,7 +69,7 @@ void IngameState::startTest()
|
||||
|
||||
void IngameState::startGame()
|
||||
{
|
||||
getWorld()->runScript("data/main.scm");
|
||||
game->startScript("data/main.scm");
|
||||
getWorld()->sound.playBackground( getWorld()->gameData.getDataPath() + "/audio/City.wav" );
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user