Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/network/src/story_entities/game_world.cc @ 6376

Last change on this file since 6376 was 6376, checked in by patrick, 18 years ago

network: load param is now processed correctly

File size: 17.5 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
12   main-programmer: Patrick Boenzli
13   co-programmer: Christian Meyer
14   co-programmer: Benjamin Grauer
15*/
16
17#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_WORLD
18
19#include "game_world.h"
20
21#include "shell_command.h"
22#include "resource_manager.h"
23#include "state.h"
24
25#include "p_node.h"
26#include "world_entity.h"
27#include "player.h"
28#include "camera.h"
29#include "environment.h"
30#include "terrain.h"
31
32#include "test_entity.h"
33#include "terrain.h"
34#include "light.h"
35#include "load_param.h"
36#include "shell.h"
37
38#include "fast_factory.h"
39#include "animation_player.h"
40#include "particle_engine.h"
41#include "graphics_engine.h"
42#include "physics_engine.h"
43#include "fields.h"
44
45#include "md2Model.h"
46
47#include "glmenu_imagescreen.h"
48#include "game_loader.h"
49
50#include "animation3d.h"
51
52#include "substring.h"
53
54#include "factory.h"
55
56#include "weapons/projectile.h"
57#include "event_handler.h"
58#include "sound_engine.h"
59#include "ogg_player.h"
60
61#include "class_list.h"
62
63#include "cd_engine.h"
64#include "npcs/npc_test1.h"
65#include "shader.h"
66
67#include "playable.h"
68#include "network_manager.h"
69#include "playable.h"
70
71
72SHELL_COMMAND(speed, GameWorld, setSpeed);
73SHELL_COMMAND(togglePNodeVisibility, GameWorld, togglePNodeVisibility);
74SHELL_COMMAND(toggleBVVisibility, GameWorld, toggleBVVisibility);
75
76using namespace std;
77
78//! This creates a Factory to fabricate a GameWorld
79CREATE_FACTORY(GameWorld, CL_GAME_WORLD);
80
81
82
83GameWorld::GameWorld(const TiXmlElement* root)
84  : StoryEntity()
85{
86  this->setClassID(CL_GAME_WORLD, "GameWorld");
87  this->setName("Preloaded World - no name yet");
88
89  this->gameTime = 0.0f;
90  this->setSpeed(1.0f);
91  this->music = NULL;
92  this->shell = NULL;
93  this->localPlayer = NULL;
94  this->localCamera = NULL;
95
96  this->showPNodes = false;
97  this->showBV = false;
98
99  this->path = NULL;
100}
101
102/**
103 *  remove the GameWorld from memory
104 *
105 *  delete everything explicitly, that isn't contained in the parenting tree!
106 *  things contained in the tree are deleted automaticaly
107 */
108GameWorld::~GameWorld ()
109{
110  delete this->shell;
111  PRINTF(3)("GameWorld::~GameWorld() - deleting current world\n");
112
113  delete this->localPlayer;
114
115  // delete all the initialized Engines.
116  FastFactory::flushAll(true);
117  delete LightManager::getInstance();
118  delete ParticleEngine::getInstance();
119  delete AnimationPlayer::getInstance();
120  delete PhysicsEngine::getInstance();
121
122  // external engines initialized by the orxonox-class get deleted
123  SoundEngine::getInstance()->flushAllBuffers();
124  SoundEngine::getInstance()->flushAllSources();
125
126  if (State::getObjectManager() == &this->objectManager)
127    State::setObjectManager(NULL);
128  // erease everything that is left.
129  delete PNode::getNullParent();
130
131  //secondary cleanup of PNodes;
132  const std::list<BaseObject*>* nodeList = ClassList::getList(CL_PARENT_NODE);
133  if (nodeList != NULL)
134    while (!nodeList->empty())
135      delete nodeList->front();
136
137  Shader::suspendShader();
138
139  // unload the resources !!
140  ResourceManager::getInstance()->unloadAllByPriority(RP_LEVEL);
141}
142
143
144
145/**
146 * loads the parameters of a GameWorld from an XML-element
147 * @param root the XML-element to load from
148 */
149void GameWorld::loadParams(const TiXmlElement* root)
150{
151  static_cast<StoryEntity*>(this)->loadParams(root);
152
153  LoadParam(root, "path", this, GameWorld, setPath)
154    .describe("The Filename of this GameWorld (relative from the data-dir)");
155
156  PRINTF(4)("Loaded GameWorld specific stuff\n");
157}
158
159
160/**
161 * this is executed just before load
162 *
163 * since the load function sometimes needs data, that has been initialized
164 * before the load and after the proceeding storyentity has finished
165*/
166ErrorMessage GameWorld::init()
167{
168  State::setObjectManager(&this->objectManager);
169  this->cycle = 0;
170
171  /* init the world interface */
172  this->shell = new Shell();
173
174  LightManager::getInstance();
175  PNode::getNullParent();
176
177  AnimationPlayer::getInstance(); // initializes the animationPlayer
178  ParticleEngine::getInstance();
179  PhysicsEngine::getInstance();
180
181  this->localCamera = new Camera();
182  this->localCamera->setName ("GameWorld-Camera");
183
184  State::setCamera(this->localCamera, this->localCamera->getTarget());
185
186  GraphicsEngine::getInstance()->displayFPS(true);
187}
188
189
190/**
191 *  loads the GameWorld by initializing all resources, and set their default values.
192 */
193ErrorMessage GameWorld::loadData()
194{
195  this->displayLoadScreen();
196
197  PRINTF(3)("> Loading world: '%s'\n", getPath());
198  TiXmlElement* element;
199  GameLoader* loader = GameLoader::getInstance();
200
201  if( getPath() == NULL)
202    {
203      PRINTF(1)("GameWorld has no path specified for loading");
204      return (ErrorMessage){213,"Path not specified","GameWorld::load()"};
205    }
206
207  TiXmlDocument* XMLDoc = new TiXmlDocument( getPath());
208  // load the campaign document
209  if( !XMLDoc->LoadFile())
210  {
211    // report an error
212    PRINTF(1)("loading XML File: %s @ %s:l%d:c%d\n", XMLDoc->ErrorDesc(), this->getPath(), XMLDoc->ErrorRow(), XMLDoc->ErrorCol());
213    delete XMLDoc;
214    return (ErrorMessage){213,"XML File parsing error","GameWorld::load()"};
215  }
216
217  // check basic validity
218  TiXmlElement* root = XMLDoc->RootElement();
219  assert( root != NULL);
220
221  if( root == NULL || root->Value() == NULL || strcmp( root->Value(), "WorldDataFile"))
222    {
223      // report an error
224      PRINTF(1)("Specified XML File is not an orxonox world data file (WorldDataFile element missing)\n");
225      delete XMLDoc;
226      return (ErrorMessage){213,"Path not a WorldDataFile","GameWorld::load()"};
227    }
228
229  // load the parameters
230  // name
231  const char* string = grabParameter( root, "name");
232  if( string == NULL)
233    {
234      PRINTF(2)("GameWorld is missing a proper 'name'\n");
235      this->setName("Unknown");
236    }
237  else
238    {
239      this->setName(string);
240    }
241
242  ////////////////
243  // LOADSCREEN //
244  ////////////////
245  element = root->FirstChildElement("LoadScreen");
246  if (element == NULL)
247    {
248      PRINTF(2)("no LoadScreen specified, loading default\n");
249
250      glmis->setBackgroundImage("pictures/load_screen.jpg");
251      this->glmis->setMaximum(8);
252      this->glmis->draw();
253    }
254  else
255    {
256      this->glmis->loadParams(element);
257      this->glmis->draw();
258    }
259  this->glmis->draw();
260
261  ////////////////////////
262  // find WorldEntities //
263  ////////////////////////
264
265  element = root->FirstChildElement("WorldEntities");
266
267  if( element == NULL)
268    {
269      PRINTF(1)("GameWorld is missing 'WorldEntities'\n");
270    }
271  else
272    {
273      element = element->FirstChildElement();
274      // load Players/Objects/Whatever
275      PRINTF(4)("Loading WorldEntities\n");
276      while( element != NULL)
277        {
278          BaseObject* created = Factory::fabricate(element);
279          if( created != NULL )
280          {
281            if(created->isA(CL_WORLD_ENTITY))
282              this->spawn(dynamic_cast<WorldEntity*>(created));
283            printf("Created a %s: %s\n", created->getClassName(), created->getName());
284          }
285
286          // if we load a 'Player' we use it as localPlayer
287
288
289          //todo do this more elegant
290          if( element->Value() != NULL && !strcmp( element->Value(), "SkyBox"))
291            this->sky = dynamic_cast<WorldEntity*>(created);
292          if( element->Value() != NULL && !strcmp( element->Value(), "Terrain"))
293          {
294            terrain = dynamic_cast<Terrain*>(created);
295            CDEngine::getInstance()->setTerrain(terrain);
296          }
297          element = element->NextSiblingElement();
298          glmis->step(); //! @todo temporary
299        }
300      PRINTF(4)("Done loading WorldEntities\n");
301    }
302
303    //////////////////////////////
304    // LOADING ADDITIONAL STUFF //
305    //////////////////////////////
306
307    LoadParamXML(root, "LightManager", LightManager::getInstance(), LightManager, loadParams);
308
309   LoadParamXML(root, "ParticleEngine", ParticleEngine::getInstance(), ParticleEngine, loadParams);
310//   LoadParamXML(root, "PhysicsEngine", PhysicsEngine::getInstance(), PhysicsEngine, loadParams);
311
312  // free the XML data
313
314  delete XMLDoc;
315  /* GENERIC LOADING PROCESS FINISHED */
316
317
318  // Create a Player
319  this->localPlayer = new Player();
320
321  Playable* playable;
322  const list<BaseObject*>* playableList = ClassList::getList(CL_PLAYABLE);
323  if (playableList != NULL)
324  {
325    playable = dynamic_cast<Playable*>(playableList->front());
326    this->localPlayer->setControllable(playable);
327  }
328
329
330//   //localCamera->setParent(TrackNode::getInstance());
331//  tn->addChild(this->localCamera);
332  localCamera->setClipRegion(1, 10000.0);
333//  localCamera->lookAt(playable);
334//  this->localPlayer->setParentMode(PNODE_ALL);
335  if (this->sky != NULL)
336  {
337    this->localCamera->addChild(sky);
338  }
339  SoundEngine::getInstance()->setListener(this->localCamera);
340
341  /* some static stuff*/
342
343  this->music = NULL;
344  //(OggPlayer*)ResourceManager::getInstance()->load("sound/00-luke_grey_-_hypermode.ogg", OGG, RP_LEVEL);
345  //music->playback();
346
347  this->releaseLoadScreen();
348}
349
350
351/**
352 *  initializes a new GameWorld shortly before start
353 *
354 * this is the function, that will be loaded shortly before the world is
355 * started
356*/
357ErrorMessage GameWorld::preStart()
358{
359  this->bPause = false;
360
361  /* update the object position before game start - so there are no wrong coordinates used in the first processing */
362  PNode::getNullParent()->updateNode (0.001f);
363  PNode::getNullParent()->updateNode (0.001f);
364}
365
366
367/**
368 *  starts the GameWorld
369 */
370ErrorMessage GameWorld::start()
371{
372  this->bQuitWorld = false;
373  this->mainLoop();
374}
375
376/**
377 *  stops the world.
378
379   This happens, when the player decides to end the Level.
380*/
381ErrorMessage GameWorld::stop()
382{
383  PRINTF(3)("GameWorld::stop() - got stop signal\n");
384  this->bQuitWorld= true;
385}
386
387/**
388 *  pauses the Game
389*/
390ErrorMessage GameWorld::pause()
391{
392  this->isPaused = true;
393}
394
395/**
396 *  ends the pause Phase
397*/
398ErrorMessage GameWorld::resume()
399{
400  this->isPaused = false;
401}
402
403
404/**
405 *  shows the loading screen
406*/
407void GameWorld::displayLoadScreen ()
408{
409  PRINTF(3)("GameWorld::displayLoadScreen - start\n");
410
411  //GLMenuImageScreen*
412  this->glmis = new GLMenuImageScreen();
413  this->glmis->setMaximum(8);
414
415  PRINTF(3)("GameWorld::displayLoadScreen - end\n");
416}
417
418/**
419 * @brief removes the loadscreen, and changes over to the game
420 *
421 * @todo take out the delay
422*/
423void GameWorld::releaseLoadScreen ()
424{
425  PRINTF(3)("GameWorld::releaseLoadScreen - start\n");
426  this->glmis->setValue(this->glmis->getMaximum());
427  PRINTF(3)("GameWorld::releaseLoadScreen - end\n");
428  delete this->glmis;
429}
430
431
432/**
433 *  synchronize local data with remote data
434*/
435void GameWorld::synchronize ()
436{
437  // Get remote input
438  // Update synchronizables
439/*  NetworkManager::getInstance()->synchronize();*/
440}
441
442
443/**
444 *  run all input processing
445
446   the command node is the central input event dispatcher. the node uses the even-queue from
447   sdl and has its own event-passing-queue.
448*/
449void GameWorld::handleInput ()
450{
451  EventHandler::getInstance()->process();
452
453  // remoteinput
454}
455
456void GameWorld::tick(std::list<WorldEntity*> entityList, float dt)
457{
458  std::list<WorldEntity*>::iterator entity;
459  for (entity = entityList.begin(); entity != entityList.end(); entity++)
460    (*entity)->tick(dt);
461
462}
463
464/**
465 *  advance the timeline
466
467   this calculates the time used to process one frame (with all input handling, drawing, etc)
468   the time is mesured in ms and passed to all world-entities and other classes that need
469   a heart-beat.
470*/
471void GameWorld::tick ()
472{
473  Uint32 currentFrame = SDL_GetTicks();
474  if(!this->bPause)
475    {
476      this->dt = currentFrame - this->lastFrame;
477
478      if( this->dt > 10)
479        {
480          float fps = 1000/dt;
481
482          // temporary, only for showing how fast the text-engine is
483          char tmpChar[20];
484          sprintf(tmpChar, "fps: %4.0f", fps);
485        }
486      else
487        {
488          /* the frame-rate is limited to 100 frames per second, all other things are for
489             nothing.
490          */
491          PRINTF(3)("fps = 1000 - frame rate is adjusted\n");
492          SDL_Delay(10-dt);
493          this->dt = 10;
494        }
495
496      this->dtS = (float)this->dt / 1000.0 * this->speed;
497      this->gameTime += this->dtS;
498
499      this->tick(this->objectManager.getObjectList(OM_DEAD_TICK), this->dtS);
500      this->tick(this->objectManager.getObjectList(OM_COMMON), this->dtS);
501      this->tick(this->objectManager.getObjectList(OM_GROUP_00), this->dtS);
502      this->tick(this->objectManager.getObjectList(OM_GROUP_01), this->dtS);
503      this->tick(this->objectManager.getObjectList(OM_GROUP_01_PROJ), this->dtS);
504
505      /* update tick the rest */
506      this->localCamera->tick(this->dtS);
507      // tick the engines
508      AnimationPlayer::getInstance()->tick(this->dtS);
509//      if (this->cycle > 5)
510        PhysicsEngine::getInstance()->tick(this->dtS);
511
512      ParticleEngine::getInstance()->tick(this->dtS);
513
514
515      /** actualy the Graphics Engine should tick the world not the other way around...
516         but since we like the things not too complicated we got it this way around
517         until there is need or time to do it the other way around.
518         @todo: GraphicsEngine ticks world: separation of processes and data...
519
520        bensch: in my opinion the GraphicsEngine could draw the world, but not tick it,
521         beceause graphics have nothing(or at least not much) to do with Motion.
522      */
523      GraphicsEngine::getInstance()->tick(this->dtS);
524    }
525  this->lastFrame = currentFrame;
526}
527
528
529/**
530 *  this function gives the world a consistant state
531
532   after ticking (updating the world state) this will give a constistant
533   state to the whole system.
534*/
535void GameWorld::update()
536{
537  GraphicsEngine::getInstance()->update(this->dtS);
538  PNode::getNullParent()->updateNode (this->dtS);
539  SoundEngine::getInstance()->update();
540  //music->update();
541}
542
543
544void GameWorld::collide()
545{
546  CDEngine::getInstance()->checkCollisions(this->objectManager.getObjectList(OM_GROUP_00),
547                                            this->objectManager.getObjectList(OM_GROUP_01_PROJ));
548  CDEngine::getInstance()->checkCollisions(this->objectManager.getObjectList(OM_GROUP_01),
549                                            this->objectManager.getObjectList(OM_COMMON));
550}
551
552/**
553 *  render the current frame
554
555   clear all buffers and draw the world
556*/
557void GameWorld::display ()
558{
559  // clear buffer
560  glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
561  // set camera
562  this->localCamera->apply ();
563  // draw world
564  this->draw();
565  // draw HUD
566  /** @todo draw HUD */
567  // flip buffers
568  GraphicsEngine::swapBuffers();
569  //SDL_Surface* screen = Orxonox::getInstance()->getScreen ();
570  //SDL_Flip (screen);
571}
572
573
574/**
575 *  runs through all entities calling their draw() methods
576 */
577void GameWorld::draw ()
578{
579  GraphicsEngine* engine = GraphicsEngine::getInstance();
580  engine->draw(State::getObjectManager()->getObjectList(OM_ENVIRON_NOTICK));
581  engine->draw(State::getObjectManager()->getObjectList(OM_ENVIRON));
582  engine->draw(State::getObjectManager()->getObjectList(OM_COMMON));
583  engine->draw(State::getObjectManager()->getObjectList(OM_GROUP_00));
584  engine->draw(State::getObjectManager()->getObjectList(OM_GROUP_01));
585  engine->draw(State::getObjectManager()->getObjectList(OM_GROUP_01_PROJ));
586
587   if( unlikely( this->showBV))  // to draw the bounding boxes of the objects at level 2 for debug purp
588   {
589     CDEngine* engine = CDEngine::getInstance();
590     engine->drawBV(State::getObjectManager()->getObjectList(OM_ENVIRON_NOTICK));
591     engine->drawBV(State::getObjectManager()->getObjectList(OM_ENVIRON));
592     engine->drawBV(State::getObjectManager()->getObjectList(OM_COMMON));
593     engine->drawBV(State::getObjectManager()->getObjectList(OM_GROUP_00));
594     engine->drawBV(State::getObjectManager()->getObjectList(OM_GROUP_01));
595     engine->drawBV(State::getObjectManager()->getObjectList(OM_GROUP_01_PROJ));
596   }
597
598//   {
599//     if( entity->isVisible() ) entity->draw();
600  //FIXME
601//     entity = iterator->nextElement();
602//   }
603
604  ParticleEngine::getInstance()->draw();
605
606  if (unlikely(this->showPNodes))
607    PNode::getNullParent()->debugDraw(0);
608
609  engine->draw();
610  //TextEngine::getInstance()->draw();
611}
612
613
614/**
615 * \brief main loop of the world: executing all world relevant function
616 *
617 * in this loop we synchronize (if networked), handle input events, give the heart-beat to
618 * all other member-entities of the world (tick to player, enemies etc.), checking for
619 * collisions drawing everything to the screen.
620 */
621void GameWorld::mainLoop()
622{
623  this->lastFrame = SDL_GetTicks ();
624  PRINTF(3)("GameWorld::mainLoop() - Entering main loop\n");
625
626  while(!this->bQuitWorld) /* @todo implement pause */
627  {
628    ++this->cycle;
629      // Network
630    this->synchronize ();
631      // Process input
632    this->handleInput ();
633    if( this->bQuitWorld)
634      break;
635      // Process time
636    this->tick ();
637      // Process collision
638    this->collide ();
639      // Update the state
640    this->update ();
641      // Draw
642    this->display ();
643  }
644
645  PRINTF(3)("GameWorld::mainLoop() - Exiting the main loop\n");
646}
647
648
649
650/**
651 *  add and spawn a new entity to this world
652 * @param entity to be added
653*/
654void GameWorld::spawn(WorldEntity* entity)
655{
656//   this->entities->add (entity);
657  entity->postSpawn ();
658}
659
660/**
661 *  sets the track path of this world
662 * @param name the name of the path
663 */
664void GameWorld::setPath( const char* name)
665{
666  if (this->path)
667    delete this->path;
668  if (ResourceManager::isFile(name))
669  {
670    this->path = new char[strlen(name)+1];
671    strcpy(this->path, name);
672  }
673  else
674    {
675      this->path = new char[strlen(ResourceManager::getInstance()->getDataDir()) + strlen(name) +1];
676      sprintf(this->path, "%s%s", ResourceManager::getInstance()->getDataDir(), name);
677    }
678}
679
Note: See TracBrowser for help on using the repository browser.