public override GameReturn RunFrame(idUserCommand[] userCommands) { GameReturn gameReturn = new GameReturn(); idPlayer player = this.LocalPlayer; // set the user commands for this frame _userCommands = (idUserCommand[]) userCommands.Clone(); if((this.IsMultiplayer == false) && (idR.CvarSystem.GetBool("g_stopTime") == true)) { // clear any debug lines from a previous frame _currentRenderWorld.DebugClearLines(_time + 1); if(player != null) { player.Think(); } } else { do { // update the game time _frameCount++; _previousTime = _time; _time += _msec; _realClientTime = _time; // TODO // allow changing SIMD usage on the fly /*if ( com_forceGenericSIMD.IsModified() ) { idSIMD::InitProcessor( "game", com_forceGenericSIMD.GetBool() ); }*/ // make sure the random number counter is used each frame so random events // are influenced by the player's actions _random.Next(); if(player != null) { // update the renderview so that any gui videos play from the right frame idRenderView view = player.RenderView; if(view != null) { _currentRenderWorld.RenderView = view; } } // clear any debug lines from a previous frame _currentRenderWorld.DebugClearLines(_time); // clear any debug polygons from a previous frame _currentRenderWorld.DebugClearPolygons(_time); // free old smoke particles // TODO: smokeParticles->FreeSmokes(); // TODO // process events on the server /*ServerProcessEntityNetworkEventQueue();*/ // update our gravity vector if needed. /* TODO: UpdateGravity(); // create a merged pvs for all players TODO: SetupPlayerPVS(); // sort the active entity list TODO: SortActiveEntityList();*/ /*timer_think.Clear(); TODO: timer_think.Start();*/ // let entities think int count = 0; if(idR.CvarSystem.GetFloat("g_timeentities") > 0) { foreach(idEntity entity in _activeEntities) { // TODO: cinematic /*if ( g_cinematic.GetBool() && inCinematic && !ent->cinematic ) { ent->GetPhysics()->UpdateTime( time ); continue; }*/ // TODO: timer /*timer_singlethink.Clear(); timer_singlethink.Start();*/ entity.Think(); /*timer_singlethink.Stop(); ms = timer_singlethink.Milliseconds(); if ( ms >= g_timeentities.GetFloat() ) { Printf( "%d: entity '%s': %.1f ms\n", time, ent->name.c_str(), ms ); }*/ count++; } } else { /*if ( inCinematic ) { num = 0; for( ent = activeEntities.Next(); ent != NULL; ent = ent->activeNode.Next() ) { if ( g_cinematic.GetBool() && !ent->cinematic ) { ent->GetPhysics()->UpdateTime( time ); continue; } ent->Think(); num++; } } else {*/ count = 0; foreach(idEntity ent in _activeEntities) { ent.Think(); _clientCount++; } /*}*/ } // remove any entities that have stopped thinking if(_entitiesToDeactivate > 0) { idConsole.Warning("TODO: deactivate entities"); /*if ( numEntitiesToDeactivate ) { idEntity *next_ent; int c = 0; for( ent = activeEntities.Next(); ent != NULL; ent = next_ent ) { next_ent = ent->activeNode.Next(); if ( !ent->thinkFlags ) { ent->activeNode.Remove(); c++; } } //assert( numEntitiesToDeactivate == c ); numEntitiesToDeactivate = 0;*/ } // TODO: timer /*timer_think.Stop(); timer_events.Clear(); timer_events.Start();*/ // service any pending events /*idEvent::ServiceEvents(); timer_events.Stop(); // free the player pvs FreePlayerPVS();*/ _gameRules.Run(); // display how long it took to calculate the current game frame /*if ( g_frametime.GetBool() ) { Printf( "game %d: all:%.1f th:%.1f ev:%.1f %d ents \n", time, timer_think.Milliseconds() + timer_events.Milliseconds(), timer_think.Milliseconds(), timer_events.Milliseconds(), num ); }*/ // build the return value gameReturn.ConsistencyHash = 0; gameReturn.SessionCommand = string.Empty; /*if ( !isMultiplayer && player ) { ret.health = player->health; ret.heartRate = player->heartRate; ret.stamina = idMath::FtoiFast( player->stamina ); // combat is a 0-100 value based on lastHitTime and lastDmgTime // each make up 50% of the time spread over 10 seconds ret.combat = 0; if ( player->lastDmgTime > 0 && time < player->lastDmgTime + 10000 ) { ret.combat += 50.0f * (float) ( time - player->lastDmgTime ) / 10000; } if ( player->lastHitTime > 0 && time < player->lastHitTime + 10000 ) { ret.combat += 50.0f * (float) ( time - player->lastHitTime ) / 10000; } }*/ // see if a target_sessionCommand has forced a changelevel if(_sessionCommand != string.Empty) { gameReturn.SessionCommand = _sessionCommand; break; } // make sure we don't loop forever when skipping a cinematic /*if ( skipCinematic && ( time > cinematicMaxSkipTime ) ) { Warning( "Exceeded maximum cinematic skip length. Cinematic may be looping infinitely." ); skipCinematic = false; break; }*/ } while(1 == 0/* TODO: ( inCinematic || ( time < cinematicStopTime ) ) && skipCinematic */); } /*ret.syncNextGameFrame = skipCinematic; if ( skipCinematic ) { soundSystem->SetMute( false ); skipCinematic = false; }*/ // show any debug info for this frame /*RunDebugInfo(); D_DrawDebugLines();*/ return gameReturn; }