@ -2,6 +2,8 @@
# include <iomanip>
# include <fstream>
# include <chrono>
# include <thread>
# include <boost/filesystem/fstream.hpp>
@ -79,6 +81,140 @@ namespace
if ( ret ! = 0 )
Log ( Debug : : Error ) < < " SDL error: " < < SDL_GetError ( ) ;
}
struct UserStats
{
const std : : string mLabel ;
const std : : string mBegin ;
const std : : string mEnd ;
const std : : string mTaken ;
UserStats ( const std : : string & label , const std : : string & prefix )
: mLabel ( label ) ,
mBegin ( prefix + " _time_begin " ) ,
mEnd ( prefix + " _time_end " ) ,
mTaken ( prefix + " _time_taken " )
{ }
} ;
enum class UserStatsType : std : : size_t
{
Input ,
Sound ,
State ,
Script ,
Mechanics ,
Physics ,
World ,
Gui ,
Number ,
} ;
template < UserStatsType type >
struct UserStatsValue
{
static const UserStats sValue ;
} ;
template < >
const UserStats UserStatsValue < UserStatsType : : Input > : : sValue { " Input " , " input " } ;
template < >
const UserStats UserStatsValue < UserStatsType : : Sound > : : sValue { " Sound " , " sound " } ;
template < >
const UserStats UserStatsValue < UserStatsType : : State > : : sValue { " State " , " state " } ;
template < >
const UserStats UserStatsValue < UserStatsType : : Script > : : sValue { " Script " , " script " } ;
template < >
const UserStats UserStatsValue < UserStatsType : : Mechanics > : : sValue { " Mech " , " mechanics " } ;
template < >
const UserStats UserStatsValue < UserStatsType : : Physics > : : sValue { " Phys " , " physics " } ;
template < >
const UserStats UserStatsValue < UserStatsType : : World > : : sValue { " World " , " world " } ;
template < >
const UserStats UserStatsValue < UserStatsType : : Gui > : : sValue { " Gui " , " gui " } ;
template < UserStatsType type >
struct ForEachUserStatsValue
{
template < class F >
static void apply ( F & & f )
{
f ( UserStatsValue < type > : : sValue ) ;
using Next = ForEachUserStatsValue < static_cast < UserStatsType > ( static_cast < std : : size_t > ( type ) + 1 ) > ;
Next : : apply ( std : : forward < F > ( f ) ) ;
}
} ;
template < >
struct ForEachUserStatsValue < UserStatsType : : Number >
{
template < class F >
static void apply ( F & & ) { }
} ;
template < class F >
void forEachUserStatsValue ( F & & f )
{
ForEachUserStatsValue < static_cast < UserStatsType > ( 0 ) > : : apply ( std : : forward < F > ( f ) ) ;
}
template < UserStatsType sType >
class ScopedProfile
{
public :
ScopedProfile ( osg : : Timer_t frameStart , unsigned int frameNumber , const osg : : Timer & timer , osg : : Stats & stats )
: mScopeStart ( timer . tick ( ) ) ,
mFrameStart ( frameStart ) ,
mFrameNumber ( frameNumber ) ,
mTimer ( timer ) ,
mStats ( stats )
{
}
ScopedProfile ( const ScopedProfile & ) = delete ;
ScopedProfile & operator = ( const ScopedProfile & ) = delete ;
~ ScopedProfile ( )
{
const osg : : Timer_t end = mTimer . tick ( ) ;
const UserStats & stats = UserStatsValue < sType > : : sValue ;
mStats . setAttribute ( mFrameNumber , stats . mBegin , mTimer . delta_s ( mFrameStart , mScopeStart ) ) ;
mStats . setAttribute ( mFrameNumber , stats . mTaken , mTimer . delta_s ( mScopeStart , end ) ) ;
mStats . setAttribute ( mFrameNumber , stats . mEnd , mTimer . delta_s ( mFrameStart , end ) ) ;
}
private :
const osg : : Timer_t mScopeStart ;
const osg : : Timer_t mFrameStart ;
const unsigned int mFrameNumber ;
const osg : : Timer & mTimer ;
osg : : Stats & mStats ;
} ;
void initStatsHandler ( Resource : : Profiler & profiler )
{
const osg : : Vec4f textColor ( 1.f , 1.f , 1.f , 1.f ) ;
const osg : : Vec4f barColor ( 1.f , 1.f , 1.f , 1.f ) ;
const float multiplier = 1000 ;
const bool average = true ;
const bool averageInInverseSpace = false ;
const float maxValue = 10000 ;
forEachUserStatsValue ( [ & ] ( const UserStats & v )
{
profiler . addUserStatsLine ( v . mLabel , textColor , barColor , v . mTaken , multiplier ,
average , averageInInverseSpace , v . mBegin , v . mEnd , maxValue ) ;
} ) ;
}
}
void OMW : : Engine : : executeLocalScripts ( )
@ -128,35 +264,45 @@ bool OMW::Engine::frame(float frametime)
{
try
{
mStartTick = mViewer - > getStartTick ( ) ;
const osg : : Timer_t frameStart = mViewer - > getStartTick ( ) ;
const unsigned int frameNumber = mViewer - > getFrameStamp ( ) - > getFrameNumber ( ) ;
const osg : : Timer * const timer = osg : : Timer : : instance ( ) ;
osg : : Stats * const stats = mViewer - > getViewerStats ( ) ;
mEnvironment . setFrameDuration ( frametime ) ;
// update input
mEnvironment . getInputManager ( ) - > update ( frametime , false ) ;
{
ScopedProfile < UserStatsType : : Input > profile ( frameStart , frameNumber , * timer , * stats ) ;
mEnvironment . getInputManager ( ) - > update ( frametime , false ) ;
}
// When the window is minimized, pause the game. Currently this *has* to be here to work around a MyGUI bug.
// If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures (fixed in MyGUI 3.3.2),
// and destroyed widgets will not be deleted (not fixed yet, https://github.com/MyGUI/mygui/issues/21)
if ( ! mEnvironment . getWindowManager ( ) - > isWindowVisible ( ) )
{
mEnvironment . getSoundManager ( ) - > pausePlayback ( ) ;
/*
Start of tes3mp change ( major )
ScopedProfile < UserStatsType : : Sound > profile ( frameStart , frameNumber , * timer , * stats ) ;
The game cannot be paused in multiplayer , so prevent that from happening even here
*/
//return false;
/*
End of tes3mp change ( major )
*/
}
else
mEnvironment . getSoundManager ( ) - > resumePlayback ( ) ;
if ( ! mEnvironment . getWindowManager ( ) - > isWindowVisible ( ) )
{
mEnvironment . getSoundManager ( ) - > pausePlayback ( ) ;
/*
Start of tes3mp change ( major )
The game cannot be paused in multiplayer , so prevent that from happening even here
*/
//return false;
/*
End of tes3mp change ( major )
*/
}
else
mEnvironment . getSoundManager ( ) - > resumePlayback ( ) ;
// sound
if ( mUseSound )
mEnvironment . getSoundManager ( ) - > update ( frametime ) ;
// sound
if ( mUseSound )
mEnvironment . getSoundManager ( ) - > update ( frametime ) ;
}
/*
Start of tes3mp addition
@ -183,9 +329,10 @@ bool OMW::Engine::frame(float frametime)
*/
// update game state
mEnvironment . getStateManager ( ) - > update ( frametime ) ;
bool guiActive = mEnvironment . getWindowManager ( ) - > isGuiMode ( ) ;
{
ScopedProfile < UserStatsType : : State > profile ( frameStart , frameNumber , * timer , * stats ) ;
mEnvironment . getStateManager ( ) - > update ( frametime ) ;
}
/*
Start of tes3mp change ( major )
@ -193,103 +340,91 @@ bool OMW::Engine::frame(float frametime)
Whether the GUI is active should have no relevance in multiplayer , so the guiActive
boolean is always set to false instead
*/
guiActive = false ;
//bool guiActive = mEnvironment.getWindowManager()->isGuiMode();
bool guiActive = false ;
/*
End of tes3mp change ( major )
*/
osg : : Timer_t beforeScriptTick = osg : : Timer : : instance ( ) - > tick ( ) ;
if ( mEnvironment . getStateManager ( ) - > getState ( ) ! =
MWBase : : StateManager : : State_NoGame )
{
if ( ! paused )
ScopedProfile < UserStatsType : : Script > profile ( frameStart , frameNumber , * timer , * stats ) ;
if ( mEnvironment . getStateManager ( ) - > getState ( ) ! = MWBase : : StateManager : : State_NoGame )
{
if ( mEnvironment . getWorld ( ) - > getScriptsEnabled ( ) )
if ( ! paused )
{
// local scripts
executeLocalScripts ( ) ;
if ( mEnvironment . getWorld ( ) - > getScriptsEnabled ( ) )
{
// local scripts
executeLocalScripts ( ) ;
// global scripts
mEnvironment . getScriptManager ( ) - > getGlobalScripts ( ) . run ( ) ;
}
// global scripts
mEnvironment . getScriptManager ( ) - > getGlobalScripts ( ) . run ( ) ;
}
mEnvironment . getWorld ( ) - > markCellAsUnchanged ( ) ;
}
mEnvironment . getWorld ( ) - > markCellAsUnchanged ( ) ;
}
if ( ! guiActive )
{
double hours = ( frametime * mEnvironment . getWorld ( ) - > getTimeScaleFactor ( ) ) / 3600.0 ;
mEnvironment . getWorld ( ) - > advanceTime ( hours , true ) ;
mEnvironment . getWorld ( ) - > rechargeItems ( frametime , true ) ;
if ( ! guiActive )
{
double hours = ( frametime * mEnvironment . getWorld ( ) - > getTimeScaleFactor ( ) ) / 3600.0 ;
mEnvironment . getWorld ( ) - > advanceTime ( hours , true ) ;
mEnvironment . getWorld ( ) - > rechargeItems ( frametime , true ) ;
}
}
}
osg : : Timer_t afterScriptTick = osg : : Timer : : instance ( ) - > tick ( ) ;
// update actors
osg : : Timer_t beforeMechanicsTick = osg : : Timer : : instance ( ) - > tick ( ) ;
if ( mEnvironment . getStateManager ( ) - > getState ( ) ! =
MWBase : : StateManager : : State_NoGame )
// update mechanics
{
mEnvironment . getMechanicsManager ( ) - > update ( frametime ,
guiActive ) ;
}
osg : : Timer_t afterMechanicsTick = osg : : Timer : : instance ( ) - > tick ( ) ;
ScopedProfile < UserStatsType : : Mechanics > profile ( frameStart , frameNumber , * timer , * stats ) ;
if ( mEnvironment . getStateManager ( ) - > getState ( ) = =
MWBase : : StateManager : : State_Running )
{
/*
Start of tes3mp change ( major )
if ( mEnvironment . getStateManager ( ) - > getState ( ) ! = MWBase : : StateManager : : State_NoGame )
{
mEnvironment . getMechanicsManager ( ) - > update ( frametime , guiActive ) ;
}
In multiplayer , the game should not end when the player dies ,
so the code here has been commented out
*/
//MWWorld::Ptr player = mEnvironment.getWorld()->getPlayerPtr();
//if(!guiActive && player.getClass().getCreatureStats(player).isDead())
// mEnvironment.getStateManager()->endGame();
/*
End of tes3mp change ( major )
*/
if ( mEnvironment . getStateManager ( ) - > getState ( ) = = MWBase : : StateManager : : State_Running )
{
MWWorld : : Ptr player = mEnvironment . getWorld ( ) - > getPlayerPtr ( ) ;
/*
Start of tes3mp change ( major )
In multiplayer , the game should not end when the player dies ,
so the code here has been commented out
*/
//if(!guiActive && player.getClass().getCreatureStats(player).isDead())
// mEnvironment.getStateManager()->endGame();
/*
End of tes3mp change ( major )
*/
}
}
// update physics
osg : : Timer_t beforePhysicsTick = osg : : Timer : : instance ( ) - > tick ( ) ;
if ( mEnvironment . getStateManager ( ) - > getState ( ) ! =
MWBase : : StateManager : : State_NoGame )
{
mEnvironment . getWorld ( ) - > updatePhysics ( frametime , guiActive ) ;
ScopedProfile < UserStatsType : : Physics > profile ( frameStart , frameNumber , * timer , * stats ) ;
if ( mEnvironment . getStateManager ( ) - > getState ( ) ! = MWBase : : StateManager : : State_NoGame )
{
mEnvironment . getWorld ( ) - > updatePhysics ( frametime , guiActive ) ;
}
}
osg : : Timer_t afterPhysicsTick = osg : : Timer : : instance ( ) - > tick ( ) ;
// update world
osg : : Timer_t beforeWorldTick = osg : : Timer : : instance ( ) - > tick ( ) ;
if ( mEnvironment . getStateManager ( ) - > getState ( ) ! =
MWBase : : StateManager : : State_NoGame )
{
mEnvironment . getWorld ( ) - > update ( frametime , guiActive ) ;
ScopedProfile < UserStatsType : : World > profile ( frameStart , frameNumber , * timer , * stats ) ;
if ( mEnvironment . getStateManager ( ) - > getState ( ) ! = MWBase : : StateManager : : State_NoGame )
{
mEnvironment . getWorld ( ) - > update ( frametime , guiActive ) ;
}
}
osg : : Timer_t afterWorldTick = osg : : Timer : : instance ( ) - > tick ( ) ;
// update GUI
mEnvironment . getWindowManager ( ) - > update ( frametime ) ;
unsigned int frameNumber = mViewer - > getFrameStamp ( ) - > getFrameNumber ( ) ;
osg : : Stats * stats = mViewer - > getViewerStats ( ) ;
stats - > setAttribute ( frameNumber , " script_time_begin " , osg : : Timer : : instance ( ) - > delta_s ( mStartTick , beforeScriptTick ) ) ;
stats - > setAttribute ( frameNumber , " script_time_taken " , osg : : Timer : : instance ( ) - > delta_s ( beforeScriptTick , afterScriptTick ) ) ;
stats - > setAttribute ( frameNumber , " script_time_end " , osg : : Timer : : instance ( ) - > delta_s ( mStartTick , afterScriptTick ) ) ;
stats - > setAttribute ( frameNumber , " mechanics_time_begin " , osg : : Timer : : instance ( ) - > delta_s ( mStartTick , beforeMechanicsTick ) ) ;
stats - > setAttribute ( frameNumber , " mechanics_time_taken " , osg : : Timer : : instance ( ) - > delta_s ( beforeMechanicsTick , afterMechanicsTick ) ) ;
stats - > setAttribute ( frameNumber , " mechanics_time_end " , osg : : Timer : : instance ( ) - > delta_s ( mStartTick , afterMechanicsTick ) ) ;
stats - > setAttribute ( frameNumber , " physics_time_begin " , osg : : Timer : : instance ( ) - > delta_s ( mStartTick , beforePhysicsTick ) ) ;
stats - > setAttribute ( frameNumber , " physics_time_taken " , osg : : Timer : : instance ( ) - > delta_s ( beforePhysicsTick , afterPhysicsTick ) ) ;
stats - > setAttribute ( frameNumber , " physics_time_end " , osg : : Timer : : instance ( ) - > delta_s ( mStartTick , afterPhysicsTick ) ) ;
stats - > setAttribute ( frameNumber , " world_time_begin " , osg : : Timer : : instance ( ) - > delta_s ( mStartTick , beforeWorldTick ) ) ;
stats - > setAttribute ( frameNumber , " world_time_taken " , osg : : Timer : : instance ( ) - > delta_s ( beforeWorldTick , afterWorldTick ) ) ;
stats - > setAttribute ( frameNumber , " world_time_end " , osg : : Timer : : instance ( ) - > delta_s ( mStartTick , afterWorldTick ) ) ;
{
ScopedProfile < UserStatsType : : Gui > profile ( frameStart , frameNumber , * timer , * stats ) ;
mEnvironment . getWindowManager ( ) - > update ( frametime ) ;
}
if ( stats - > collectStats ( " resource " ) )
{
@ -302,7 +437,6 @@ bool OMW::Engine::frame(float frametime)
mEnvironment . reportStats ( frameNumber , * stats ) ;
}
}
catch ( const std : : exception & e )
{
@ -345,8 +479,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
throw std : : runtime_error ( " Could not initialize SDL! " + std : : string ( SDL_GetError ( ) ) ) ;
}
}
mStartTick = osg : : Timer : : instance ( ) - > tick ( ) ;
}
OMW : : Engine : : ~ Engine ( )
@ -856,14 +988,7 @@ void OMW::Engine::go()
// Setup profiler
osg : : ref_ptr < Resource : : Profiler > statshandler = new Resource : : Profiler ;
statshandler - > addUserStatsLine ( " Script " , osg : : Vec4f ( 1.f , 1.f , 1.f , 1.f ) , osg : : Vec4f ( 1.f , 1.f , 1.f , 1.f ) ,
" script_time_taken " , 1000.0 , true , false , " script_time_begin " , " script_time_end " , 10000 ) ;
statshandler - > addUserStatsLine ( " Mech " , osg : : Vec4f ( 1.f , 1.f , 1.f , 1.f ) , osg : : Vec4f ( 1.f , 1.f , 1.f , 1.f ) ,
" mechanics_time_taken " , 1000.0 , true , false , " mechanics_time_begin " , " mechanics_time_end " , 10000 ) ;
statshandler - > addUserStatsLine ( " Phys " , osg : : Vec4f ( 1.f , 1.f , 1.f , 1.f ) , osg : : Vec4f ( 1.f , 1.f , 1.f , 1.f ) ,
" physics_time_taken " , 1000.0 , true , false , " physics_time_begin " , " physics_time_end " , 10000 ) ;
statshandler - > addUserStatsLine ( " World " , osg : : Vec4f ( 1.f , 1.f , 1.f , 1.f ) , osg : : Vec4f ( 1.f , 1.f , 1.f , 1.f ) ,
" world_time_taken " , 1000.0 , true , false , " world_time_begin " , " world_time_end " , 10000 ) ;
initStatsHandler ( * statshandler ) ;
mViewer - > addEventHandler ( statshandler ) ;
@ -915,7 +1040,7 @@ void OMW::Engine::go()
if ( ! frame ( dt ) )
{
OpenThreads: : Thread : : microSleep ( 5000 ) ;
std: : this_thread : : sleep_for ( std : : chrono : : milliseconds ( 5 ) ) ;
continue ;
}
else