# include "scene.hpp"
# include <limits>
# include <iostream>
/*
Start of tes3mp addition
Include additional headers for multiplayer purposes
*/
# include "../mwmp/Main.hpp"
# include "../mwmp/LocalPlayer.hpp"
/*
End of tes3mp addition
*/
# include <components/loadinglistener/loadinglistener.hpp>
# include <components/misc/resourcehelpers.hpp>
# include <components/settings/settings.hpp>
# include <components/resource/resourcesystem.hpp>
# include <components/resource/scenemanager.hpp>
# include "../mwbase/environment.hpp"
# include "../mwbase/world.hpp"
# include "../mwbase/soundmanager.hpp"
# include "../mwbase/mechanicsmanager.hpp"
# include "../mwbase/windowmanager.hpp"
# include "../mwrender/renderingmanager.hpp"
# include "../mwrender/landmanager.hpp"
# include "../mwphysics/physicssystem.hpp"
# include "player.hpp"
# include "localscripts.hpp"
# include "esmstore.hpp"
# include "class.hpp"
# include "cellvisitors.hpp"
# include "cellstore.hpp"
# include "cellpreloader.hpp"
namespace
{
void setNodeRotation ( const MWWorld : : Ptr & ptr , MWRender : : RenderingManager & rendering , bool inverseRotationOrder )
{
if ( ! ptr . getRefData ( ) . getBaseNode ( ) )
return ;
osg : : Quat worldRotQuat ( ptr . getRefData ( ) . getPosition ( ) . rot [ 2 ] , osg : : Vec3 ( 0 , 0 , - 1 ) ) ;
if ( ! ptr . getClass ( ) . isActor ( ) )
{
float xr = ptr . getRefData ( ) . getPosition ( ) . rot [ 0 ] ;
float yr = ptr . getRefData ( ) . getPosition ( ) . rot [ 1 ] ;
if ( ! inverseRotationOrder )
worldRotQuat = worldRotQuat * osg : : Quat ( yr , osg : : Vec3 ( 0 , - 1 , 0 ) ) *
osg : : Quat ( xr , osg : : Vec3 ( - 1 , 0 , 0 ) ) ;
else
worldRotQuat = osg : : Quat ( xr , osg : : Vec3 ( - 1 , 0 , 0 ) ) * osg : : Quat ( yr , osg : : Vec3 ( 0 , - 1 , 0 ) ) * worldRotQuat ;
}
rendering . rotateObject ( ptr , worldRotQuat ) ;
}
void addObject ( const MWWorld : : Ptr & ptr , MWPhysics : : PhysicsSystem & physics ,
MWRender : : RenderingManager & rendering )
{
if ( ptr . getRefData ( ) . getBaseNode ( ) | | physics . getActor ( ptr ) )
{
std : : cerr < < " Warning: Tried to add " < < ptr . getCellRef ( ) . getRefId ( ) < < " to the scene twice " < < std : : endl ;
return ;
}
bool useAnim = ptr . getClass ( ) . useAnim ( ) ;
std : : string model = ptr . getClass ( ) . getModel ( ptr ) ;
if ( useAnim )
model = Misc : : ResourceHelpers : : correctActorModelPath ( model , rendering . getResourceSystem ( ) - > getVFS ( ) ) ;
std : : string id = ptr . getCellRef ( ) . getRefId ( ) ;
if ( id = = " prisonmarker " | | id = = " divinemarker " | | id = = " templemarker " | | id = = " northmarker " )
model = " " ; // marker objects that have a hardcoded function in the game logic, should be hidden from the player
ptr . getClass ( ) . insertObjectRendering ( ptr , model , rendering ) ;
setNodeRotation ( ptr , rendering , false ) ;
ptr . getClass ( ) . insertObject ( ptr , model , physics ) ;
if ( useAnim )
MWBase : : Environment : : get ( ) . getMechanicsManager ( ) - > add ( ptr ) ;
if ( ptr . getClass ( ) . isActor ( ) )
rendering . addWaterRippleEmitter ( ptr ) ;
// Restore effect particles
MWBase : : Environment : : get ( ) . getWorld ( ) - > applyLoopingParticles ( ptr ) ;
}
void updateObjectRotation ( const MWWorld : : Ptr & ptr , MWPhysics : : PhysicsSystem & physics ,
MWRender : : RenderingManager & rendering , bool inverseRotationOrder )
{
setNodeRotation ( ptr , rendering , inverseRotationOrder ) ;
physics . updateRotation ( ptr ) ;
}
void updateObjectScale ( const MWWorld : : Ptr & ptr , MWPhysics : : PhysicsSystem & physics ,
MWRender : : RenderingManager & rendering )
{
if ( ptr . getRefData ( ) . getBaseNode ( ) ! = NULL )
{
float scale = ptr . getCellRef ( ) . getScale ( ) ;
osg : : Vec3f scaleVec ( scale , scale , scale ) ;
ptr . getClass ( ) . adjustScale ( ptr , scaleVec , true ) ;
rendering . scaleObject ( ptr , scaleVec ) ;
physics . updateScale ( ptr ) ;
}
}
struct InsertVisitor
{
MWWorld : : CellStore & mCell ;
bool mRescale ;
Loading : : Listener & mLoadingListener ;
MWPhysics : : PhysicsSystem & mPhysics ;
MWRender : : RenderingManager & mRendering ;
std : : vector < MWWorld : : Ptr > mToInsert ;
InsertVisitor ( MWWorld : : CellStore & cell , bool rescale , Loading : : Listener & loadingListener ,
MWPhysics : : PhysicsSystem & physics , MWRender : : RenderingManager & rendering ) ;
bool operator ( ) ( const MWWorld : : Ptr & ptr ) ;
void insert ( ) ;
} ;
InsertVisitor : : InsertVisitor ( MWWorld : : CellStore & cell , bool rescale ,
Loading : : Listener & loadingListener , MWPhysics : : PhysicsSystem & physics ,
MWRender : : RenderingManager & rendering )
: mCell ( cell ) , mRescale ( rescale ) , mLoadingListener ( loadingListener ) ,
mPhysics ( physics ) ,
mRendering ( rendering )
{ }
bool InsertVisitor : : operator ( ) ( const MWWorld : : Ptr & ptr )
{
// do not insert directly as we can't modify the cell from within the visitation
// CreatureLevList::insertObjectRendering may spawn a new creature
mToInsert . push_back ( ptr ) ;
return true ;
}
void InsertVisitor : : insert ( )
{
for ( std : : vector < MWWorld : : Ptr > : : iterator it = mToInsert . begin ( ) ; it ! = mToInsert . end ( ) ; + + it )
{
MWWorld : : Ptr ptr = * it ;
if ( mRescale )
{
if ( ptr . getCellRef ( ) . getScale ( ) < 0.5 )
ptr . getCellRef ( ) . setScale ( 0.5 ) ;
else if ( ptr . getCellRef ( ) . getScale ( ) > 2 )
ptr . getCellRef ( ) . setScale ( 2 ) ;
}
if ( ! ptr . getRefData ( ) . isDeleted ( ) & & ptr . getRefData ( ) . isEnabled ( ) )
{
try
{
addObject ( ptr , mPhysics , mRendering ) ;
}
catch ( const std : : exception & e )
{
std : : string error ( " failed to render ' " + ptr . getCellRef ( ) . getRefId ( ) + " ': " ) ;
std : : cerr < < error + e . what ( ) < < std : : endl ;
}
}
mLoadingListener . increaseProgress ( 1 ) ;
}
}
struct AdjustPositionVisitor
{
bool operator ( ) ( const MWWorld : : Ptr & ptr )
{
if ( ! ptr . getRefData ( ) . isDeleted ( ) & & ptr . getRefData ( ) . isEnabled ( ) )
ptr . getClass ( ) . adjustPosition ( ptr , false ) ;
return true ;
}
} ;
}
namespace MWWorld
{
void Scene : : updateObjectRotation ( const Ptr & ptr , bool inverseRotationOrder )
{
: : updateObjectRotation ( ptr , * mPhysics , mRendering , inverseRotationOrder ) ;
}
void Scene : : updateObjectScale ( const Ptr & ptr )
{
: : updateObjectScale ( ptr , * mPhysics , mRendering ) ;
}
void Scene : : getGridCenter ( int & cellX , int & cellY )
{
int maxX = std : : numeric_limits < int > : : min ( ) ;
int maxY = std : : numeric_limits < int > : : min ( ) ;
int minX = std : : numeric_limits < int > : : max ( ) ;
int minY = std : : numeric_limits < int > : : max ( ) ;
CellStoreCollection : : iterator iter = mActiveCells . begin ( ) ;
while ( iter ! = mActiveCells . end ( ) )
{
assert ( ( * iter ) - > getCell ( ) - > isExterior ( ) ) ;
int x = ( * iter ) - > getCell ( ) - > getGridX ( ) ;
int y = ( * iter ) - > getCell ( ) - > getGridY ( ) ;
maxX = std : : max ( x , maxX ) ;
maxY = std : : max ( y , maxY ) ;
minX = std : : min ( x , minX ) ;
minY = std : : min ( y , minY ) ;
+ + iter ;
}
cellX = ( minX + maxX ) / 2 ;
cellY = ( minY + maxY ) / 2 ;
}
void Scene : : update ( float duration , bool paused )
{
mPreloadTimer + = duration ;
if ( mPreloadTimer > 0.1f )
{
preloadCells ( 0.1f ) ;
mPreloadTimer = 0.f ;
}
mRendering . update ( duration , paused ) ;
mPreloader - > updateCache ( mRendering . getReferenceTime ( ) ) ;
}
void Scene : : unloadCell ( CellStoreCollection : : iterator iter )
{
std : : cout < < " Unloading cell \n " ;
ListAndResetObjectsVisitor visitor ;
/*
Start of tes3mp addition
Set a const pointer to the iterator ' s ESM : : Cell here , because
( * iter ) - > getCell ( ) can become invalid later down
*/
const ESM : : Cell * cell = ( * iter ) - > getCell ( ) ;
/*
End of tes3mp addition
*/
( * iter ) - > forEach < ListAndResetObjectsVisitor > ( visitor ) ;
for ( std : : vector < MWWorld : : Ptr > : : const_iterator iter2 ( visitor . mObjects . begin ( ) ) ;
iter2 ! = visitor . mObjects . end ( ) ; + + iter2 )
{
mPhysics - > remove ( * iter2 ) ;
}
if ( ( * iter ) - > getCell ( ) - > isExterior ( ) )
{
const ESM : : Land * land =
MWBase : : Environment : : get ( ) . getWorld ( ) - > getStore ( ) . get < ESM : : Land > ( ) . search (
( * iter ) - > getCell ( ) - > getGridX ( ) ,
( * iter ) - > getCell ( ) - > getGridY ( )
) ;
if ( land & & land - > mDataTypes & ESM : : Land : : DATA_VHGT )
mPhysics - > removeHeightField ( ( * iter ) - > getCell ( ) - > getGridX ( ) , ( * iter ) - > getCell ( ) - > getGridY ( ) ) ;
}
MWBase : : Environment : : get ( ) . getMechanicsManager ( ) - > drop ( * iter ) ;
mRendering . removeCell ( * iter ) ;
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > removeCell ( * iter ) ;
MWBase : : Environment : : get ( ) . getWorld ( ) - > getLocalScripts ( ) . clearCell ( * iter ) ;
MWBase : : Environment : : get ( ) . getSoundManager ( ) - > stopSound ( * iter ) ;
mActiveCells . erase ( * iter ) ;
/*
Start of tes3mp addition
Store a cell unload for the LocalPlayer
*/
mwmp : : Main : : get ( ) . getLocalPlayer ( ) - > storeCellState ( * cell , mwmp : : CellState : : Type : : Unload ) ;
/*
End of tes3mp addition
*/
}
void Scene : : loadCell ( CellStore * cell , Loading : : Listener * loadingListener , bool respawn )
{
std : : pair < CellStoreCollection : : iterator , bool > result = mActiveCells . insert ( cell ) ;
if ( result . second )
{
std : : cout < < " Loading cell " < < cell - > getCell ( ) - > getDescription ( ) < < std : : endl ;
float verts = ESM : : Land : : LAND_SIZE ;
float worldsize = ESM : : Land : : REAL_SIZE ;
// Load terrain physics first...
if ( cell - > getCell ( ) - > isExterior ( ) )
{
int cellX = cell - > getCell ( ) - > getGridX ( ) ;
int cellY = cell - > getCell ( ) - > getGridY ( ) ;
osg : : ref_ptr < const ESMTerrain : : LandObject > land = mRendering . getLandManager ( ) - > getLand ( cellX , cellY ) ;
const ESM : : Land : : LandData * data = land ? land - > getData ( ESM : : Land : : DATA_VHGT ) : 0 ;
if ( data )
{
mPhysics - > addHeightField ( data - > mHeights , cellX , cell - > getCell ( ) - > getGridY ( ) , worldsize / ( verts - 1 ) , verts , data - > mMinHeight , data - > mMaxHeight , land . get ( ) ) ;
}
else
{
static std : : vector < float > defaultHeight ;
defaultHeight . resize ( verts * verts , ESM : : Land : : DEFAULT_HEIGHT ) ;
mPhysics - > addHeightField ( & defaultHeight [ 0 ] , cell - > getCell ( ) - > getGridX ( ) , cell - > getCell ( ) - > getGridY ( ) , worldsize / ( verts - 1 ) , verts , ESM : : Land : : DEFAULT_HEIGHT , ESM : : Land : : DEFAULT_HEIGHT , land . get ( ) ) ;
}
}
// register local scripts
// do this before insertCell, to make sure we don't add scripts from levelled creature spawning twice
MWBase : : Environment : : get ( ) . getWorld ( ) - > getLocalScripts ( ) . addCell ( cell ) ;
if ( respawn )
cell - > respawn ( ) ;
// ... then references. This is important for adjustPosition to work correctly.
/// \todo rescale depending on the state of a new GMST
/*
Start of tes3mp change ( major )
Instead of always rescaling objects as in the original code , never rescale them ,
so they can maintain their server - set scales when their cells are reloaded
*/
insertCell ( * cell , false , loadingListener ) ;
/*
End of tes3mp change ( major )
*/
mRendering . addCell ( cell ) ;
bool waterEnabled = cell - > getCell ( ) - > hasWater ( ) | | cell - > isExterior ( ) ;
float waterLevel = cell - > getWaterLevel ( ) ;
mRendering . setWaterEnabled ( waterEnabled ) ;
if ( waterEnabled )
{
mPhysics - > enableWater ( waterLevel ) ;
mRendering . setWaterHeight ( waterLevel ) ;
}
else
mPhysics - > disableWater ( ) ;
if ( ! cell - > isExterior ( ) & & ! ( cell - > getCell ( ) - > mData . mFlags & ESM : : Cell : : QuasiEx ) )
mRendering . configureAmbient ( cell - > getCell ( ) ) ;
/*
Start of tes3mp addition
Store a cell load for the LocalPlayer
*/
mwmp : : Main : : get ( ) . getLocalPlayer ( ) - > storeCellState ( * cell - > getCell ( ) , mwmp : : CellState : : Type : : Load ) ;
/*
End of tes3mp addition
*/
}
mPreloader - > notifyLoaded ( cell ) ;
}
void Scene : : clear ( )
{
CellStoreCollection : : iterator active = mActiveCells . begin ( ) ;
while ( active ! = mActiveCells . end ( ) )
unloadCell ( active + + ) ;
assert ( mActiveCells . empty ( ) ) ;
mCurrentCell = NULL ;
mPreloader - > clear ( ) ;
}
void Scene : : playerMoved ( const osg : : Vec3f & pos )
{
if ( ! mCurrentCell | | ! mCurrentCell - > isExterior ( ) )
return ;
// figure out the center of the current cell grid (*not* necessarily mCurrentCell, which is the cell the player is in)
int cellX , cellY ;
getGridCenter ( cellX , cellY ) ;
float centerX , centerY ;
MWBase : : Environment : : get ( ) . getWorld ( ) - > indexToPosition ( cellX , cellY , centerX , centerY , true ) ;
const float maxDistance = 8192 / 2 + mCellLoadingThreshold ; // 1/2 cell size + threshold
float distance = std : : max ( std : : abs ( centerX - pos . x ( ) ) , std : : abs ( centerY - pos . y ( ) ) ) ;
if ( distance > maxDistance )
{
int newX , newY ;
MWBase : : Environment : : get ( ) . getWorld ( ) - > positionToIndex ( pos . x ( ) , pos . y ( ) , newX , newY ) ;
changeCellGrid ( newX , newY ) ;
}
}
void Scene : : changeCellGrid ( int X , int Y , bool changeEvent )
{
Loading : : Listener * loadingListener = MWBase : : Environment : : get ( ) . getWindowManager ( ) - > getLoadingScreen ( ) ;
Loading : : ScopedLoad load ( loadingListener ) ;
std : : string loadingExteriorText = " #{sLoadingMessage3} " ;
loadingListener - > setLabel ( loadingExteriorText ) ;
CellStoreCollection : : iterator active = mActiveCells . begin ( ) ;
while ( active ! = mActiveCells . end ( ) )
{
if ( ( * active ) - > getCell ( ) - > isExterior ( ) )
{
if ( std : : abs ( X - ( * active ) - > getCell ( ) - > getGridX ( ) ) < = mHalfGridSize & &
std : : abs ( Y - ( * active ) - > getCell ( ) - > getGridY ( ) ) < = mHalfGridSize )
{
// keep cells within the new grid
+ + active ;
continue ;
}
}
unloadCell ( active + + ) ;
}
int refsToLoad = 0 ;
// get the number of refs to load
for ( int x = X - mHalfGridSize ; x < = X + mHalfGridSize ; + + x )
{
for ( int y = Y - mHalfGridSize ; y < = Y + mHalfGridSize ; + + y )
{
CellStoreCollection : : iterator iter = mActiveCells . begin ( ) ;
while ( iter ! = mActiveCells . end ( ) )
{
assert ( ( * iter ) - > getCell ( ) - > isExterior ( ) ) ;
if ( x = = ( * iter ) - > getCell ( ) - > getGridX ( ) & &
y = = ( * iter ) - > getCell ( ) - > getGridY ( ) )
break ;
+ + iter ;
}
if ( iter = = mActiveCells . end ( ) )
refsToLoad + = MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( x , y ) - > count ( ) ;
}
}
loadingListener - > setProgressRange ( refsToLoad ) ;
// Load cells
for ( int x = X - mHalfGridSize ; x < = X + mHalfGridSize ; + + x )
{
for ( int y = Y - mHalfGridSize ; y < = Y + mHalfGridSize ; + + y )
{
CellStoreCollection : : iterator iter = mActiveCells . begin ( ) ;
while ( iter ! = mActiveCells . end ( ) )
{
assert ( ( * iter ) - > getCell ( ) - > isExterior ( ) ) ;
if ( x = = ( * iter ) - > getCell ( ) - > getGridX ( ) & &
y = = ( * iter ) - > getCell ( ) - > getGridY ( ) )
break ;
+ + iter ;
}
if ( iter = = mActiveCells . end ( ) )
{
CellStore * cell = MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( x , y ) ;
loadCell ( cell , loadingListener , changeEvent ) ;
}
}
}
/*
Start of tes3mp addition
Send an ID_PLAYER_CELL_STATE packet with all cell states stored in LocalPlayer
and then clear them , but only if the player has finished character generation
*/
if ( mwmp : : Main : : get ( ) . getLocalPlayer ( ) - > hasFinishedCharGen ( ) )
{
mwmp : : Main : : get ( ) . getLocalPlayer ( ) - > sendCellStates ( ) ;
mwmp : : Main : : get ( ) . getLocalPlayer ( ) - > clearCellStates ( ) ;
}
/*
End of tes3mp addition
*/
CellStore * current = MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( X , Y ) ;
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > changeCell ( current ) ;
if ( changeEvent )
mCellChanged = true ;
}
void Scene : : changePlayerCell ( CellStore * cell , const ESM : : Position & pos , bool adjustPlayerPos )
{
mCurrentCell = cell ;
mRendering . enableTerrain ( cell - > isExterior ( ) ) ;
MWBase : : World * world = MWBase : : Environment : : get ( ) . getWorld ( ) ;
MWWorld : : Ptr old = world - > getPlayerPtr ( ) ;
world - > getPlayer ( ) . setCell ( cell ) ;
MWWorld : : Ptr player = world - > getPlayerPtr ( ) ;
mRendering . updatePlayerPtr ( player ) ;
if ( adjustPlayerPos ) {
world - > moveObject ( player , pos . pos [ 0 ] , pos . pos [ 1 ] , pos . pos [ 2 ] ) ;
float x = pos . rot [ 0 ] ;
float y = pos . rot [ 1 ] ;
float z = pos . rot [ 2 ] ;
world - > rotateObject ( player , x , y , z ) ;
Some PVS-Studio and cppcheck fixes
cppcheck:
[apps/esmtool/record.cpp:697]: (performance) Prefer prefix ++/-- operators for non-primitive types.
[apps/esmtool/record.cpp:1126]: (performance) Prefer prefix ++/-- operators for non-primitive types.
[apps/esmtool/record.cpp:1138]: (performance) Prefer prefix ++/-- operators for non-primitive types.
[apps/niftest/niftest.cpp:36]: (performance) Function parameter 'filename' should be passed by reference.
[apps/niftest/niftest.cpp:41]: (performance) Function parameter 'filename' should be passed by reference.
[apps/opencs/model/prefs/boolsetting.cpp:25]: (warning) Possible leak in public function. The pointer 'mWidget' is not deallocated before it is allocated.
[apps/opencs/model/prefs/shortcuteventhandler.cpp:52]: (warning) Return value of std::remove() ignored. Elements remain in container.
[apps/openmw/mwstate/quicksavemanager.cpp:5]: (performance) Variable 'mSaveName' is assigned in constructor body. Consider performing initialization in initialization list.
PVS-Studio:
apps/opencs/model/filter/parser.cpp 582 warn V560 A part of conditional expression is always true: allowPredefined.
apps/opencs/view/world/referencecreator.cpp 67 warn V547 Expression '!errors.empty()' is always false.
apps/opencs/view/world/referencecreator.cpp 74 warn V547 Expression '!errors.empty()' is always false.
apps/opencs/view/doc/loader.cpp 170 warn V560 A part of conditional expression is always true: !completed.
apps/opencs/view/doc/loader.cpp 170 warn V560 A part of conditional expression is always true: !error.empty().
apps/opencs/model/tools/pathgridcheck.cpp 32 err V517 The use of 'if (A) {...} else if (A) {...}' pattern was detected. There is a probability of logical error presence. Check lines: 32, 34.
apps/opencs/model/world/refidadapterimp.cpp 1376 err V547 Expression 'subColIndex < 3' is always true.
apps/openmw/mwgui/widgets.hpp 318 warn V703 It is odd that the 'mEnableRepeat' field in derived class 'MWScrollBar' overwrites field in base class 'ScrollBar'. Check lines: widgets.hpp:318, MyGUI_ScrollBar.h:179.
apps/openmw/mwgui/widgets.hpp 319 warn V703 It is odd that the 'mRepeatTriggerTime' field in derived class 'MWScrollBar' overwrites field in base class 'ScrollBar'. Check lines: widgets.hpp:319, MyGUI_ScrollBar.h:180.
apps/openmw/mwgui/widgets.hpp 320 warn V703 It is odd that the 'mRepeatStepTime' field in derived class 'MWScrollBar' overwrites field in base class 'ScrollBar'. Check lines: widgets.hpp:320, MyGUI_ScrollBar.h:181
apps/openmw/mwmechanics/actors.cpp 1425 warn V547 Expression '!detected' is always true.
apps/openmw/mwmechanics/character.cpp 2155 err V547 Expression 'mode == 0' is always true.
apps/openmw/mwmechanics/character.cpp 1192 warn V592 The expression was enclosed by parentheses twice: ((expression)). One pair of parentheses is unnecessary or misprint is present.
apps/openmw/mwmechanics/character.cpp 521 warn V560 A part of conditional expression is always true: (idle == mIdleState).
apps/openmw/mwmechanics/pathfinding.cpp 317 err V547 Expression 'mPath.size() >= 2' is always true.
apps/openmw/mwscript/interpretercontext.cpp 409 warn V560 A part of conditional expression is always false: rank > 9.
apps/openmw/mwgui/windowbase.cpp 28 warn V560 A part of conditional expression is always true: !visible.
apps/openmw/mwgui/journalwindow.cpp 561 warn V547 Expression '!mAllQuests' is always false.
apps/openmw/mwgui/referenceinterface.cpp 18 warn V571 Recurring check. The '!mPtr.isEmpty()' condition was already verified in line 16.
apps/openmw/mwworld/scene.cpp 463 warn V547 Expression 'adjustPlayerPos' is always true.
apps/openmw/mwworld/worldimp.cpp 409 err V766 An item with the same key '"sCompanionShare"' has already been added.
apps/openmw/mwworld/cellstore.cpp 691 warn V519 The 'state.mWaterLevel' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 689, 691.
apps/openmw/mwworld/weather.cpp 1125 warn V519 The 'mResult.mParticleEffect' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 1123, 1125.
apps/openmw/mwworld/weather.cpp 1137 warn V519 The 'mResult.mParticleEffect' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 1135, 1137.
apps/wizard/unshield/unshieldworker.cpp 475 warn V728 An excessive check can be simplified. The '(A && B) || (!A && !B)' expression is equivalent to the 'bool(A) == bool(B)' expression.
apps/wizard/installationpage.cpp 163 warn V735 Possibly an incorrect HTML. The "</p" closing tag was encountered, while the "</span" tag was expected.
components/fontloader/fontloader.cpp 427 err V547 Expression 'i == 1' is always true.
components/nifosg/nifloader.cpp 282 warn V519 The 'created' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 278, 282.
components/esm/loadregn.cpp 119 err V586 The 'clear' function is called twice for deallocation of the same resource. Check lines: 112, 119.
components/esm/cellref.cpp 178 warn V581 The conditional expressions of the 'if' statements situated alongside each other are identical. Check lines: 175, 178.
components/esmterrain/storage.cpp 235 warn V560 A part of conditional expression is always true: colStart == 0.
components/esmterrain/storage.cpp 237 warn V560 A part of conditional expression is always true: rowStart == 0.
7 years ago
player . getClass ( ) . adjustPosition ( player , true ) ;
}
MWBase : : MechanicsManager * mechMgr =
MWBase : : Environment : : get ( ) . getMechanicsManager ( ) ;
mechMgr - > updateCell ( old , player ) ;
mechMgr - > watchActor ( player ) ;
mPhysics - > updatePtr ( old , player ) ;
MWBase : : Environment : : get ( ) . getWorld ( ) - > adjustSky ( ) ;
mLastPlayerPos = pos . asVec3 ( ) ;
}
Scene : : Scene ( MWRender : : RenderingManager & rendering , MWPhysics : : PhysicsSystem * physics )
: mCurrentCell ( 0 ) , mCellChanged ( false ) , mPhysics ( physics ) , mRendering ( rendering )
, mPreloadTimer ( 0.f )
, mHalfGridSize ( Settings : : Manager : : getInt ( " exterior cell load distance " , " Cells " ) )
, mCellLoadingThreshold ( 1024.f )
, mPreloadDistance ( Settings : : Manager : : getInt ( " preload distance " , " Cells " ) )
, mPreloadEnabled ( Settings : : Manager : : getBool ( " preload enabled " , " Cells " ) )
, mPreloadExteriorGrid ( Settings : : Manager : : getBool ( " preload exterior grid " , " Cells " ) )
, mPreloadDoors ( Settings : : Manager : : getBool ( " preload doors " , " Cells " ) )
, mPreloadFastTravel ( Settings : : Manager : : getBool ( " preload fast travel " , " Cells " ) )
, mPredictionTime ( Settings : : Manager : : getFloat ( " prediction time " , " Cells " ) )
{
mPreloader . reset ( new CellPreloader ( rendering . getResourceSystem ( ) , physics - > getShapeManager ( ) , rendering . getTerrain ( ) , rendering . getLandManager ( ) ) ) ;
mPreloader - > setWorkQueue ( mRendering . getWorkQueue ( ) ) ;
mPreloader - > setUnrefQueue ( rendering . getUnrefQueue ( ) ) ;
mPhysics - > setUnrefQueue ( rendering . getUnrefQueue ( ) ) ;
rendering . getResourceSystem ( ) - > setExpiryDelay ( Settings : : Manager : : getFloat ( " cache expiry delay " , " Cells " ) ) ;
mPreloader - > setExpiryDelay ( Settings : : Manager : : getFloat ( " preload cell expiry delay " , " Cells " ) ) ;
mPreloader - > setMinCacheSize ( Settings : : Manager : : getInt ( " preload cell cache min " , " Cells " ) ) ;
mPreloader - > setMaxCacheSize ( Settings : : Manager : : getInt ( " preload cell cache max " , " Cells " ) ) ;
mPreloader - > setPreloadInstances ( Settings : : Manager : : getBool ( " preload instances " , " Cells " ) ) ;
}
Scene : : ~ Scene ( )
{
}
bool Scene : : hasCellChanged ( ) const
{
return mCellChanged ;
}
const Scene : : CellStoreCollection & Scene : : getActiveCells ( ) const
{
return mActiveCells ;
}
void Scene : : changeToInteriorCell ( const std : : string & cellName , const ESM : : Position & position , bool adjustPlayerPos , bool changeEvent )
{
CellStore * cell = MWBase : : Environment : : get ( ) . getWorld ( ) - > getInterior ( cellName ) ;
bool loadcell = ( mCurrentCell = = NULL ) ;
if ( ! loadcell )
loadcell = * mCurrentCell ! = * cell ;
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > fadeScreenOut ( 0.5 ) ;
Loading : : Listener * loadingListener = MWBase : : Environment : : get ( ) . getWindowManager ( ) - > getLoadingScreen ( ) ;
std : : string loadingInteriorText = " #{sLoadingMessage2} " ;
loadingListener - > setLabel ( loadingInteriorText ) ;
Loading : : ScopedLoad load ( loadingListener ) ;
if ( ! loadcell )
{
MWBase : : World * world = MWBase : : Environment : : get ( ) . getWorld ( ) ;
world - > moveObject ( world - > getPlayerPtr ( ) , position . pos [ 0 ] , position . pos [ 1 ] , position . pos [ 2 ] ) ;
float x = position . rot [ 0 ] ;
float y = position . rot [ 1 ] ;
float z = position . rot [ 2 ] ;
world - > rotateObject ( world - > getPlayerPtr ( ) , x , y , z ) ;
if ( adjustPlayerPos )
world - > getPlayerPtr ( ) . getClass ( ) . adjustPosition ( world - > getPlayerPtr ( ) , true ) ;
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > fadeScreenIn ( 0.5 ) ;
return ;
}
std : : cout < < " Changing to interior \n " ;
// unload
CellStoreCollection : : iterator active = mActiveCells . begin ( ) ;
while ( active ! = mActiveCells . end ( ) )
unloadCell ( active + + ) ;
int refsToLoad = cell - > count ( ) ;
loadingListener - > setProgressRange ( refsToLoad ) ;
// Load cell.
loadCell ( cell , loadingListener , changeEvent ) ;
/*
Start of tes3mp addition
Send an ID_PLAYER_CELL_STATE packet with all cell states stored in LocalPlayer
and then clear them , but only if the player has finished character generation
*/
if ( mwmp : : Main : : get ( ) . getLocalPlayer ( ) - > hasFinishedCharGen ( ) )
{
mwmp : : Main : : get ( ) . getLocalPlayer ( ) - > sendCellStates ( ) ;
mwmp : : Main : : get ( ) . getLocalPlayer ( ) - > clearCellStates ( ) ;
}
/*
End of tes3mp addition
*/
changePlayerCell ( cell , position , adjustPlayerPos ) ;
// adjust fog
mRendering . configureFog ( mCurrentCell - > getCell ( ) ) ;
// Sky system
MWBase : : Environment : : get ( ) . getWorld ( ) - > adjustSky ( ) ;
if ( changeEvent )
mCellChanged = true ;
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > fadeScreenIn ( 0.5 ) ;
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > changeCell ( mCurrentCell ) ;
}
void Scene : : changeToExteriorCell ( const ESM : : Position & position , bool adjustPlayerPos , bool changeEvent )
{
int x = 0 ;
int y = 0 ;
MWBase : : Environment : : get ( ) . getWorld ( ) - > positionToIndex ( position . pos [ 0 ] , position . pos [ 1 ] , x , y ) ;
if ( changeEvent )
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > fadeScreenOut ( 0.5 ) ;
changeCellGrid ( x , y , changeEvent ) ;
CellStore * current = MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( x , y ) ;
changePlayerCell ( current , position , adjustPlayerPos ) ;
if ( changeEvent )
MWBase : : Environment : : get ( ) . getWindowManager ( ) - > fadeScreenIn ( 0.5 ) ;
}
CellStore * Scene : : getCurrentCell ( )
{
return mCurrentCell ;
}
void Scene : : markCellAsUnchanged ( )
{
mCellChanged = false ;
}
void Scene : : insertCell ( CellStore & cell , bool rescale , Loading : : Listener * loadingListener )
{
InsertVisitor insertVisitor ( cell , rescale , * loadingListener , * mPhysics , mRendering ) ;
cell . forEach ( insertVisitor ) ;
insertVisitor . insert ( ) ;
// do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order
AdjustPositionVisitor adjustPosVisitor ;
cell . forEach ( adjustPosVisitor ) ;
}
void Scene : : addObjectToScene ( const Ptr & ptr )
{
try
{
addObject ( ptr , * mPhysics , mRendering ) ;
MWBase : : Environment : : get ( ) . getWorld ( ) - > scaleObject ( ptr , ptr . getCellRef ( ) . getScale ( ) ) ;
}
catch ( std : : exception & e )
{
std : : cerr < < " failed to render ' " < < ptr . getCellRef ( ) . getRefId ( ) < < " ': " < < e . what ( ) < < std : : endl ;
}
}
void Scene : : removeObjectFromScene ( const Ptr & ptr )
{
MWBase : : Environment : : get ( ) . getMechanicsManager ( ) - > remove ( ptr ) ;
MWBase : : Environment : : get ( ) . getSoundManager ( ) - > stopSound3D ( ptr ) ;
mPhysics - > remove ( ptr ) ;
mRendering . removeObject ( ptr ) ;
if ( ptr . getClass ( ) . isActor ( ) )
mRendering . removeWaterRippleEmitter ( ptr ) ;
}
bool Scene : : isCellActive ( const CellStore & cell )
{
CellStoreCollection : : iterator active = mActiveCells . begin ( ) ;
while ( active ! = mActiveCells . end ( ) ) {
if ( * * active = = cell ) {
return true ;
}
+ + active ;
}
return false ;
}
Ptr Scene : : searchPtrViaActorId ( int actorId )
{
for ( CellStoreCollection : : const_iterator iter ( mActiveCells . begin ( ) ) ;
iter ! = mActiveCells . end ( ) ; + + iter )
if ( Ptr ptr = ( * iter ) - > searchViaActorId ( actorId ) )
return ptr ;
return Ptr ( ) ;
}
class PreloadMeshItem : public SceneUtil : : WorkItem
{
public :
PreloadMeshItem ( const std : : string & mesh , Resource : : SceneManager * sceneManager )
: mMesh ( mesh ) , mSceneManager ( sceneManager )
{
}
virtual void doWork ( )
{
try
{
mSceneManager - > getTemplate ( mMesh ) ;
}
catch ( std : : exception & e )
{
}
}
private :
std : : string mMesh ;
Resource : : SceneManager * mSceneManager ;
} ;
void Scene : : preload ( const std : : string & mesh , bool useAnim )
{
std : : string mesh_ = mesh ;
if ( useAnim )
mesh_ = Misc : : ResourceHelpers : : correctActorModelPath ( mesh_ , mRendering . getResourceSystem ( ) - > getVFS ( ) ) ;
if ( ! mRendering . getResourceSystem ( ) - > getSceneManager ( ) - > checkLoaded ( mesh_ , mRendering . getReferenceTime ( ) ) )
mRendering . getWorkQueue ( ) - > addWorkItem ( new PreloadMeshItem ( mesh_ , mRendering . getResourceSystem ( ) - > getSceneManager ( ) ) ) ;
}
void Scene : : preloadCells ( float dt )
{
std : : vector < osg : : Vec3f > exteriorPositions ;
const MWWorld : : ConstPtr player = MWBase : : Environment : : get ( ) . getWorld ( ) - > getPlayerPtr ( ) ;
osg : : Vec3f playerPos = player . getRefData ( ) . getPosition ( ) . asVec3 ( ) ;
osg : : Vec3f moved = playerPos - mLastPlayerPos ;
osg : : Vec3f predictedPos = playerPos + moved / dt * mPredictionTime ;
if ( mCurrentCell - > isExterior ( ) )
exteriorPositions . push_back ( predictedPos ) ;
mLastPlayerPos = playerPos ;
if ( mPreloadEnabled )
{
if ( mPreloadDoors )
preloadTeleportDoorDestinations ( playerPos , predictedPos , exteriorPositions ) ;
if ( mPreloadExteriorGrid )
preloadExteriorGrid ( playerPos , predictedPos ) ;
if ( mPreloadFastTravel )
preloadFastTravelDestinations ( playerPos , predictedPos , exteriorPositions ) ;
}
mPreloader - > setTerrainPreloadPositions ( exteriorPositions ) ;
}
void Scene : : preloadTeleportDoorDestinations ( const osg : : Vec3f & playerPos , const osg : : Vec3f & predictedPos , std : : vector < osg : : Vec3f > & exteriorPositions )
{
std : : vector < MWWorld : : ConstPtr > teleportDoors ;
for ( CellStoreCollection : : const_iterator iter ( mActiveCells . begin ( ) ) ;
iter ! = mActiveCells . end ( ) ; + + iter )
{
const MWWorld : : CellStore * cellStore = * iter ;
typedef MWWorld : : CellRefList < ESM : : Door > : : List DoorList ;
const DoorList & doors = cellStore - > getReadOnlyDoors ( ) . mList ;
for ( DoorList : : const_iterator doorIt = doors . begin ( ) ; doorIt ! = doors . end ( ) ; + + doorIt )
{
if ( ! doorIt - > mRef . getTeleport ( ) ) {
continue ;
}
teleportDoors . push_back ( MWWorld : : ConstPtr ( & * doorIt , cellStore ) ) ;
}
}
for ( std : : vector < MWWorld : : ConstPtr > : : iterator it = teleportDoors . begin ( ) ; it ! = teleportDoors . end ( ) ; + + it )
{
const MWWorld : : ConstPtr & door = * it ;
float sqrDistToPlayer = ( playerPos - door . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) . length2 ( ) ;
sqrDistToPlayer = std : : min ( sqrDistToPlayer , ( predictedPos - door . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) . length2 ( ) ) ;
if ( sqrDistToPlayer < mPreloadDistance * mPreloadDistance )
{
try
{
if ( ! door . getCellRef ( ) . getDestCell ( ) . empty ( ) )
preloadCell ( MWBase : : Environment : : get ( ) . getWorld ( ) - > getInterior ( door . getCellRef ( ) . getDestCell ( ) ) ) ;
else
{
osg : : Vec3f pos = door . getCellRef ( ) . getDoorDest ( ) . asVec3 ( ) ;
int x , y ;
MWBase : : Environment : : get ( ) . getWorld ( ) - > positionToIndex ( pos . x ( ) , pos . y ( ) , x , y ) ;
preloadCell ( MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( x , y ) , true ) ;
exteriorPositions . push_back ( pos ) ;
}
}
catch ( std : : exception & e )
{
// ignore error for now, would spam the log too much
}
}
}
}
void Scene : : preloadExteriorGrid ( const osg : : Vec3f & playerPos , const osg : : Vec3f & predictedPos )
{
if ( ! MWBase : : Environment : : get ( ) . getWorld ( ) - > isCellExterior ( ) )
return ;
int halfGridSizePlusOne = mHalfGridSize + 1 ;
int cellX , cellY ;
getGridCenter ( cellX , cellY ) ;
float centerX , centerY ;
MWBase : : Environment : : get ( ) . getWorld ( ) - > indexToPosition ( cellX , cellY , centerX , centerY , true ) ;
for ( int dx = - halfGridSizePlusOne ; dx < = halfGridSizePlusOne ; + + dx )
{
for ( int dy = - halfGridSizePlusOne ; dy < = halfGridSizePlusOne ; + + dy )
{
if ( dy ! = halfGridSizePlusOne & & dy ! = - halfGridSizePlusOne & & dx ! = halfGridSizePlusOne & & dx ! = - halfGridSizePlusOne )
continue ; // only care about the outer (not yet loaded) part of the grid
float thisCellCenterX , thisCellCenterY ;
MWBase : : Environment : : get ( ) . getWorld ( ) - > indexToPosition ( cellX + dx , cellY + dy , thisCellCenterX , thisCellCenterY , true ) ;
float dist = std : : max ( std : : abs ( thisCellCenterX - playerPos . x ( ) ) , std : : abs ( thisCellCenterY - playerPos . y ( ) ) ) ;
dist = std : : min ( dist , std : : max ( std : : abs ( thisCellCenterX - predictedPos . x ( ) ) , std : : abs ( thisCellCenterY - predictedPos . y ( ) ) ) ) ;
float loadDist = 8192 / 2 + 8192 - mCellLoadingThreshold + mPreloadDistance ;
if ( dist < loadDist )
preloadCell ( MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( cellX + dx , cellY + dy ) ) ;
}
}
}
void Scene : : preloadCell ( CellStore * cell , bool preloadSurrounding )
{
if ( preloadSurrounding & & cell - > isExterior ( ) )
{
int x = cell - > getCell ( ) - > getGridX ( ) ;
int y = cell - > getCell ( ) - > getGridY ( ) ;
unsigned int numpreloaded = 0 ;
for ( int dx = - mHalfGridSize ; dx < = mHalfGridSize ; + + dx )
{
for ( int dy = - mHalfGridSize ; dy < = mHalfGridSize ; + + dy )
{
mPreloader - > preload ( MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( x + dx , y + dy ) , mRendering . getReferenceTime ( ) ) ;
if ( + + numpreloaded > = mPreloader - > getMaxCacheSize ( ) )
break ;
}
}
}
else
mPreloader - > preload ( cell , mRendering . getReferenceTime ( ) ) ;
}
void Scene : : preloadTerrain ( const osg : : Vec3f & pos )
{
std : : vector < osg : : Vec3f > vec ;
vec . push_back ( pos ) ;
mPreloader - > setTerrainPreloadPositions ( vec ) ;
}
struct ListFastTravelDestinationsVisitor
{
ListFastTravelDestinationsVisitor ( float preloadDist , const osg : : Vec3f & playerPos )
: mPreloadDist ( preloadDist )
, mPlayerPos ( playerPos )
{
}
bool operator ( ) ( const MWWorld : : Ptr & ptr )
{
if ( ( ptr . getRefData ( ) . getPosition ( ) . asVec3 ( ) - mPlayerPos ) . length2 ( ) > mPreloadDist * mPreloadDist )
return true ;
if ( ptr . getClass ( ) . isNpc ( ) )
{
const std : : vector < ESM : : Transport : : Dest > & transport = ptr . get < ESM : : NPC > ( ) - > mBase - > mTransport . mList ;
mList . insert ( mList . begin ( ) , transport . begin ( ) , transport . end ( ) ) ;
}
else
{
const std : : vector < ESM : : Transport : : Dest > & transport = ptr . get < ESM : : Creature > ( ) - > mBase - > mTransport . mList ;
mList . insert ( mList . begin ( ) , transport . begin ( ) , transport . end ( ) ) ;
}
return true ;
}
float mPreloadDist ;
osg : : Vec3f mPlayerPos ;
std : : vector < ESM : : Transport : : Dest > mList ;
} ;
void Scene : : preloadFastTravelDestinations ( const osg : : Vec3f & playerPos , const osg : : Vec3f & /*predictedPos*/ , std : : vector < osg : : Vec3f > & exteriorPositions ) // ignore predictedPos here since opening dialogue with travel service takes extra time
{
const MWWorld : : ConstPtr player = MWBase : : Environment : : get ( ) . getWorld ( ) - > getPlayerPtr ( ) ;
ListFastTravelDestinationsVisitor listVisitor ( mPreloadDistance , player . getRefData ( ) . getPosition ( ) . asVec3 ( ) ) ;
for ( CellStoreCollection : : const_iterator iter ( mActiveCells . begin ( ) ) ; iter ! = mActiveCells . end ( ) ; + + iter )
{
MWWorld : : CellStore * cellStore = * iter ;
cellStore - > forEachType < ESM : : NPC > ( listVisitor ) ;
cellStore - > forEachType < ESM : : Creature > ( listVisitor ) ;
}
for ( std : : vector < ESM : : Transport : : Dest > : : const_iterator it = listVisitor . mList . begin ( ) ; it ! = listVisitor . mList . end ( ) ; + + it )
{
if ( ! it - > mCellName . empty ( ) )
preloadCell ( MWBase : : Environment : : get ( ) . getWorld ( ) - > getInterior ( it - > mCellName ) ) ;
else
{
osg : : Vec3f pos = it - > mPos . asVec3 ( ) ;
int x , y ;
MWBase : : Environment : : get ( ) . getWorld ( ) - > positionToIndex ( pos . x ( ) , pos . y ( ) , x , y ) ;
preloadCell ( MWBase : : Environment : : get ( ) . getWorld ( ) - > getExterior ( x , y ) , true ) ;
exteriorPositions . push_back ( pos ) ;
}
}
}
}