1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-09-03 17:19:46 +02: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:
Daniel Evans 2015-04-04 03:12:28 +01:00
parent a20d170d16
commit 159510cace
7 changed files with 133 additions and 128 deletions

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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(&parameters, &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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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" );
}