1
0
mirror of https://github.com/rwengine/openrw.git synced 2024-11-22 10:22:52 +01:00

Merge pull request #179 from darkf/exit

Rework how exiting and cleanup is handled.
This commit is contained in:
Daniel Evans 2016-08-01 19:14:50 +01:00 committed by GitHub
commit 4f79258a32
7 changed files with 71 additions and 32 deletions

View File

@ -35,6 +35,7 @@ StdOutReciever logPrinter;
RWGame::RWGame(int argc, char* argv[]) RWGame::RWGame(int argc, char* argv[])
: config("openrw.ini") : config("openrw.ini")
, state(nullptr), world(nullptr), renderer(nullptr), script(nullptr), , state(nullptr), world(nullptr), renderer(nullptr), script(nullptr),
window(nullptr), work(nullptr),
debugScript(false), inFocus(true), debugScript(false), inFocus(true),
showDebugStats(false), showDebugPaths(false), showDebugPhysics(false), showDebugStats(false), showDebugPaths(false), showDebugPhysics(false),
accum(0.f), timescale(1.f) accum(0.f), timescale(1.f)
@ -90,8 +91,11 @@ RWGame::RWGame(int argc, char* argv[])
if (SDL_Init(SDL_INIT_VIDEO) < 0) if (SDL_Init(SDL_INIT_VIDEO) < 0)
throw std::runtime_error("Failed to initialize SDL2!"); throw std::runtime_error("Failed to initialize SDL2!");
window.create(w, h, fullscreen); window = new GameWindow();
window.hideCursor(); window->create(w, h, fullscreen);
window->hideCursor();
work = new WorkContext();
log.addReciever(&logPrinter); log.addReciever(&logPrinter);
log.info("Game", "Game directory: " + config.getGameDataPath()); log.info("Game", "Game directory: " + config.getGameDataPath());
@ -101,7 +105,7 @@ RWGame::RWGame(int argc, char* argv[])
throw std::runtime_error("Invalid game directory path: " + config.getGameDataPath()); throw std::runtime_error("Invalid game directory path: " + config.getGameDataPath());
} }
data = new GameData(&log, &work, config.getGameDataPath()); data = new GameData(&log, work, config.getGameDataPath());
// Initalize all the archives. // Initalize all the archives.
data->loadIMG("/models/gta3"); data->loadIMG("/models/gta3");
@ -168,10 +172,30 @@ RWGame::RWGame(int argc, char* argv[])
RWGame::~RWGame() RWGame::~RWGame()
{ {
log.info("Game", "Beginning cleanup");
log.info("Game", "Stopping work queue");
work->stop();
log.info("Game", "Cleaning up scripts");
delete script; delete script;
log.info("Game", "Cleaning up renderer");
delete renderer; delete renderer;
log.info("Game", "Cleaning up world");
delete world; delete world;
log.info("Game", "Cleaning up state");
delete state; delete state;
log.info("Game", "Cleaning up window");
delete window;
log.info("Game", "Cleaning up work queue");
delete work;
log.info("Game", "Done cleaning up");
} }
void RWGame::newGame() void RWGame::newGame()
@ -183,7 +207,7 @@ void RWGame::newGame()
} }
state = new GameState(); state = new GameState();
world = new GameWorld(&log, &work, data); world = new GameWorld(&log, work, data);
world->dynamicsWorld->setDebugDrawer(debug); world->dynamicsWorld->setDebugDrawer(debug);
// Associate the new world with the new state and vice versa // Associate the new world with the new state and vice versa
@ -294,8 +318,8 @@ int RWGame::run()
{ {
last_clock_time = clock.now(); last_clock_time = clock.now();
// Loop until the window is closed or we run out of state. // Loop until we run out of states.
while (window.isOpen() && StateManager::get().states.size()) { while (StateManager::get().states.size()) {
State* state = StateManager::get().states.back(); State* state = StateManager::get().states.back();
RW_PROFILE_FRAME_BOUNDARY(); RW_PROFILE_FRAME_BOUNDARY();
@ -305,7 +329,7 @@ int RWGame::run()
while (SDL_PollEvent(&event)) { while (SDL_PollEvent(&event)) {
switch (event.type) { switch (event.type) {
case SDL_QUIT: case SDL_QUIT:
window.close(); StateManager::get().clear();
break; break;
case SDL_WINDOWEVENT: case SDL_WINDOWEVENT:
@ -343,14 +367,14 @@ int RWGame::run()
RW_PROFILE_BEGIN("Update"); RW_PROFILE_BEGIN("Update");
if ( accum >= GAME_TIMESTEP ) { if ( accum >= GAME_TIMESTEP ) {
RW_PROFILE_BEGIN("state");
StateManager::get().tick(GAME_TIMESTEP);
RW_PROFILE_END();
if (StateManager::get().states.size() == 0) { if (StateManager::get().states.size() == 0) {
break; break;
} }
RW_PROFILE_BEGIN("state");
StateManager::get().tick(GAME_TIMESTEP);
RW_PROFILE_END();
RW_PROFILE_BEGIN("engine"); RW_PROFILE_BEGIN("engine");
tick(GAME_TIMESTEP); tick(GAME_TIMESTEP);
RW_PROFILE_END(); RW_PROFILE_END();
@ -385,7 +409,7 @@ int RWGame::run()
renderProfile(); renderProfile();
window.swap(); window->swap();
} }
if( httpserver_thread ) if( httpserver_thread )
@ -483,7 +507,7 @@ void RWGame::render(float alpha, float time)
getRenderer()->getRenderer()->swap(); getRenderer()->getRenderer()->swap();
glm::ivec2 windowSize = window.getSize(); glm::ivec2 windowSize = window->getSize();
renderer->setViewport(windowSize.x, windowSize.y); renderer->setViewport(windowSize.x, windowSize.y);
ViewCamera viewCam; ViewCamera viewCam;

View File

@ -28,11 +28,11 @@ class RWGame
GameRenderer* renderer; GameRenderer* renderer;
ScriptMachine* script; ScriptMachine* script;
// Background worker // Background worker
WorkContext work; WorkContext *work;
bool debugScript; bool debugScript;
HttpServer* httpserver = nullptr; HttpServer* httpserver = nullptr;
std::thread* httpserver_thread = nullptr; std::thread* httpserver_thread = nullptr;
GameWindow window; GameWindow *window;
std::chrono::steady_clock clock; std::chrono::steady_clock clock;
std::chrono::steady_clock::time_point last_clock_time; std::chrono::steady_clock::time_point last_clock_time;
@ -79,7 +79,7 @@ public:
GameWindow& getWindow() GameWindow& getWindow()
{ {
return window; return *window;
} }
ScriptMachine* getScript() const ScriptMachine* getScript() const

View File

@ -80,6 +80,11 @@ struct StateManager
} }
std::deque<State*> states; std::deque<State*> states;
void clear()
{
states.clear();
}
void enter(State* state) void enter(State* state)
{ {

View File

@ -20,7 +20,7 @@ void MenuState::enterMainMenu()
m->addEntry(Menu::lambda("Load Game", [=] { enterLoadMenu(); })); m->addEntry(Menu::lambda("Load Game", [=] { enterLoadMenu(); }));
m->addEntry(Menu::lambda("Test", [=] { StateManager::get().enter(new IngameState(game, true, "test")); })); m->addEntry(Menu::lambda("Test", [=] { StateManager::get().enter(new IngameState(game, true, "test")); }));
m->addEntry(Menu::lambda("Options", [] { RW_UNIMPLEMENTED("Options Menu"); })); m->addEntry(Menu::lambda("Options", [] { RW_UNIMPLEMENTED("Options Menu"); }));
m->addEntry(Menu::lambda("Exit", [=] { getWindow().close(); })); m->addEntry(Menu::lambda("Exit", [] { StateManager::get().clear(); }));
this->enterMenu(m); this->enterMenu(m);
} }

View File

@ -10,7 +10,7 @@ PauseState::PauseState(RWGame* game)
m->offset = glm::vec2( 200.f, 200.f ); m->offset = glm::vec2( 200.f, 200.f );
m->addEntry(Menu::lambda("Continue", [] { StateManager::get().exit(); })); m->addEntry(Menu::lambda("Continue", [] { StateManager::get().exit(); }));
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", [] { StateManager::get().clear(); }));
this->enterMenu(m); this->enterMenu(m);
} }

View File

@ -12,20 +12,21 @@ void WorkContext::workNext()
{ {
WorkJob* j = nullptr; WorkJob* j = nullptr;
_inMutex.lock(); {
if( ! _workQueue.empty() ) { std::lock_guard<std::mutex> guard( _inMutex );
j = _workQueue.front();
_workQueue.pop(); if( ! _workQueue.empty() ) {
j = _workQueue.front();
_workQueue.pop();
}
} }
_inMutex.unlock();
if( j == nullptr ) return; if( j == nullptr ) return;
j->work(); j->work();
_outMutex.lock(); std::lock_guard<std::mutex> guard( _outMutex );
_completeQueue.push(j); _completeQueue.push(j);
_outMutex.unlock();
} }
void WorkContext::update() void WorkContext::update()

View File

@ -5,8 +5,11 @@
#include <queue> #include <queue>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
#include <atomic>
#include <memory>
#include <functional> #include <functional>
#include <fstream> #include <fstream>
#include <iostream>
class WorkContext; class WorkContext;
@ -16,7 +19,7 @@ class LoadWorker
public: public:
bool _running; std::atomic<bool> _running;
std::thread _thread; std::thread _thread;
void start(); void start();
@ -66,26 +69,32 @@ class GameWorld;
*/ */
class WorkContext class WorkContext
{ {
std::unique_ptr<LoadWorker> _worker;
std::queue<WorkJob*> _workQueue; std::queue<WorkJob*> _workQueue;
std::queue<WorkJob*> _completeQueue; std::queue<WorkJob*> _completeQueue;
LoadWorker _worker;
std::mutex _inMutex; std::mutex _inMutex;
std::mutex _outMutex; std::mutex _outMutex;
public: public:
WorkContext() WorkContext()
: _worker(this) { } : _worker(new LoadWorker(this)) { }
void queueJob( WorkJob* job ) void queueJob( WorkJob* job )
{ {
std::lock_guard<std::mutex> guard(_inMutex); std::lock_guard<std::mutex> guard( _inMutex );
_workQueue.push( job ); _workQueue.push( job );
} }
// Called by the worker thread - don't touch; void stop()
{
// Stop serving the queue.
_worker.reset(nullptr);
}
// Called by the worker thread - don't touch
void workNext(); void workNext();
const std::queue<WorkJob*> getWorkQueue() const { return _workQueue; } const std::queue<WorkJob*> getWorkQueue() const { return _workQueue; }