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

View File

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

View File

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

View File

@ -20,7 +20,7 @@ void MenuState::enterMainMenu()
m->addEntry(Menu::lambda("Load Game", [=] { enterLoadMenu(); }));
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("Exit", [=] { getWindow().close(); }));
m->addEntry(Menu::lambda("Exit", [] { StateManager::get().clear(); }));
this->enterMenu(m);
}

View File

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

View File

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

View File

@ -5,8 +5,11 @@
#include <queue>
#include <thread>
#include <mutex>
#include <atomic>
#include <memory>
#include <functional>
#include <fstream>
#include <iostream>
class WorkContext;
@ -16,7 +19,7 @@ class LoadWorker
public:
bool _running;
std::atomic<bool> _running;
std::thread _thread;
void start();
@ -66,26 +69,32 @@ class GameWorld;
*/
class WorkContext
{
std::unique_ptr<LoadWorker> _worker;
std::queue<WorkJob*> _workQueue;
std::queue<WorkJob*> _completeQueue;
LoadWorker _worker;
std::mutex _inMutex;
std::mutex _outMutex;
public:
WorkContext()
: _worker(this) { }
: _worker(new LoadWorker(this)) { }
void queueJob( WorkJob* job )
{
std::lock_guard<std::mutex> guard(_inMutex);
std::lock_guard<std::mutex> guard( _inMutex );
_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();
const std::queue<WorkJob*> getWorkQueue() const { return _workQueue; }