/* $Id: server.cpp,v 1.36 2005/10/25 12:13:26 uwe Exp $ */ #include "server.hpp" #include #include #include "wopsettings.hpp" #include "world.hpp" #include "servercommunicator.hpp" #include "signalhandler.hpp" #include "spritesequence.cpp" #include "spriteset.cpp" #include "wopsprites.cpp" /**********************************************************/ // So far this function does not do anything sensible any more. // It was introduced to allow the correct increment of all frame // counters on the server, too. But the increment of the frame indices // has now moved into the world, more precisely into the update routine // of the objects. Nevertheless we do not delete this function, because // we may need it once again. void Server::updateGraphics() { // draw the collidable objects on NULL screen for( unsigned int i = 0; i < m_world->getCollidables()->size(); i++ ) { m_sprites.draw( *(*m_world->getCollidables())[i], (*m_world->getCollidables())[i]->getIntPosX(), (*m_world->getCollidables())[i]->getIntPosY(), NULL ); } // draw the noncollidable objects on NULL screen for( unsigned int i = 0; i < m_world->getNoncollidables()->size(); i++ ) { m_sprites.draw( *(*m_world->getNoncollidables())[i], (*m_world->getNoncollidables())[i]->getIntPosX(), (*m_world->getNoncollidables())[i]->getIntPosY(), NULL ); } } /**********************************************************/ Server::Server() : m_world(0x0), m_communicator(0x0), m_syncMutex(0x0), m_syncCond(0x0), m_replay(0x0), m_thread(0x0) { // get WoP configuration WopSettings* settings = WopSettings::getInstance(); // get map dimensions Uint32 sizeX = static_cast( settings->getWidth() ); Uint32 sizeY = static_cast( settings->getHeight() ); // create the world m_world = NEW World( sizeX, sizeY ); ASSERT( m_world, "Server::Server: Could not create the world\n" ); // connect the sprite class with the world using // the inteface base class of WopSprites m_world->setSpriteInterface( &m_sprites ); // create the dummy sprite graphics // This must be done ASSERT( m_sprites.load(), "Server::Server: could not create " "graphic structure\n" ); // create the world from the theme in settings ASSERT( m_world->createFromTheme(), "Server::Server: could not create world from theme\n" ); // setup game mode m_world->setupGameMode(); // activate replay String replayFileName; if( WopSettings::getInstance()->getReplayFileName(replayFileName) ) { m_replay = new GameReplay( replayFileName.getString(), m_world, &m_world->getRandom() ); ASSERT( m_replay, "Server::Server: Could not open replay " " file \"%s\"\n", replayFileName.getString() ); LOG(1) INFO( "Server::Server: writing replay to \"%s\"\n", replayFileName.getString() ); } else { LOG(1) INFO( "Server::Server: no replay file specified\n" ); } // create the mutex for client synchronisation m_syncMutex = SDL_CreateMutex(); ASSERT( m_syncMutex, "Server::Server: Could not create mutex (%s)\n", SDL_GetError() ); // create the condition variable for client synchronisation m_syncCond = SDL_CreateCond(); ASSERT( m_syncCond, "Server::Server: Could not create condition variable (%s)\n", SDL_GetError() ); m_communicator = NEW ServerCommunicator( m_world, m_replay ); ASSERT( m_communicator, "Server::Server: Could not create server communicator (%s)\n", SDL_GetError() ); // enforce all server settings to be present as objects CHECK( settings->enforcePresenceOfServerSettings(), "Server::Server: could not enforce the presence of at least " "one server setting. Expect either inconsistencies or even " "crash\n" ); m_thread = 0; } /**********************************************************/ Server::~Server() { LOG( 1 ) INFO( "Server::~Server: deleting server object\n" ); delete m_replay; delete m_communicator; SDL_DestroyCond( m_syncCond ); SDL_DestroyMutex( m_syncMutex ); delete m_world; } /**********************************************************/ void Server::run() { SignalHandler* signalHandler = SignalHandler::getInstance(); m_status = DEFAULT; while( !signalHandler->hasQuit() && m_status != SHUTDOWN ) { makePace(); processEvents(); if( signalHandler->hasSignal() ) { INFO( "Server::run: Signal received\n" ); signalHandler->setSignal( false ); if( signalHandler->hasPause() ) { INFO( "Server::run: Pausing. Press CTRL-Z to continue\n" ); while( signalHandler->hasPause() ) { SDL_Delay( 1000 ); LOG( 2 ) INFO( "Server::run: Pausing. Press CTRL-Z to continue\n" ); } } } } } void Server::runThreaded() { m_thread = SDL_CreateThread( serverRunWrapper, this ); } int Server::exit() { INFO( "Server::exit: exiting...\n" ); if ( m_thread ) { int status; m_status = SHUTDOWN; INFO( "Server::exit: Waiting for thread to finish\n" ); SDL_WaitThread( m_thread, &status ); INFO( "Server::exit: Thread finished\n" ); return status; } return 0; } /**********************************************************/ void Server::processEvents() { m_communicator->collectEvents(); // DBG( 2 ) INFO( "Server::processEvents: after collectEvents counter = %d\n", m_world->getRandom().getCounter() ); m_communicator->broadcastEcho(); // DBG( 2 ) INFO( "Server::processEvents: after broadcastEcho counter = %d\n", m_world->getRandom().getCounter() ); EchoMessage echoMessage = m_communicator->getEchoMessage(); if( m_replay ) m_replay->addEcho( echoMessage ); if ( !( m_world->getFrame() % 25 ) ) { DBG( 4 ) INFO( "Server::processEvents: starting frame %d\n", m_world->getFrame() ); } // Apply all events to the world m_world->applyEvents( &echoMessage ); // make time step in world m_world->doTimestep(); // apply dummy drawing to update objects updateGraphics(); // Check for TCP messages m_communicator->handleMessages(); // Advance to next frame m_world->incrementFrame(); // Check for new connections m_communicator->listenForClients(); } int serverRunWrapper( void* data ) { Server* server = static_cast( data ); server->run(); return 0; } /**********************************************************/