DragonNest/Common/EtWorldBase/EtWorldSector.cpp

1166 lines
33 KiB
C++
Raw Normal View History

2024-12-19 09:48:26 +08:00
#include "StdAfx.h"
#include "EtWorld.h"
#include "EtWorldSector.h"
#include "EtWorldGrid.h"
#include "EtWorldProp.h"
#include "EtWorldEventArea.h"
#include "EtWorldEventControl.h"
#include "EtWorldSound.h"
#include "EtWorldSoundEnvi.h"
#include "EtTrigger.h"
#include "EtWorldWater.h"
#include "EtWorldDecal.h"
#include "navigationmesh.h"
#if !defined( USE_BOOST_MEMPOOL )
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)
#endif
#endif // #if !defined( USE_BOOST_MEMPOOL )
float CEtOctreeNode<CEtWorldProp *>::s_fMinRadius = 1000.f;
float CEtQuadtreeNode<CEtWorldDecal *>::s_fMinRadius = 1000.f;
float CEtQuadtreeNode<CEtWorldEventArea *>::s_fMinRadius = 1000.f;
CEtWorldSector::CEtWorldSector()
{
m_pParentGrid = NULL;
m_pHeight = NULL;
m_nHeightSize = 0;
m_Index = SectorIndex( -1, -1 );
m_Offset = EtVector3( 0.f, 0.f, 0.f );
m_fTileSize = 200.f;
m_fHeightMultiply = 1.f;
m_nBlockCount = 0;
m_pPropOctree = NULL;
m_pDecalQuadtree = NULL;
m_pEventAreaQuadtree = NULL;
m_pSoundInfo = NULL;
m_bLoaded = false;
m_pAttribute = NULL;
m_nAttributeBlockSize = 50;
m_pTrigger = NULL;
m_pWater = NULL;
m_pNaviMesh = NULL;
m_nPropCreateUniqueCount = 0;
m_nEventAreaCreateUniqueCount = 0;
m_nTileWidthCount = m_nTileHeightCount = 0;
m_bLoadFailed = false;
m_fCenterHeight = 0.f;
m_fRadius = 0.f;
m_pCollisionHeight = NULL;
m_nAttributeSize = 0;
}
CEtWorldSector::~CEtWorldSector()
{
Free();
}
void CEtWorldSector::Free()
{
SAFE_DELETEA( m_pCollisionHeight );
SAFE_DELETEA( m_pHeight );
SAFE_DELETE( m_pPropOctree );
SAFE_DELETE( m_pDecalQuadtree );
SAFE_DELETE( m_pEventAreaQuadtree );
SAFE_DELETE_PVEC( m_pVecPropList );
SAFE_DELETE_PVEC( m_pVecAreaControl );
SAFE_DELETE_PVEC( m_pVecDecalList );
SAFE_DELETE( m_pSoundInfo );
SAFE_DELETEA( m_pAttribute );
SAFE_DELETE( m_pTrigger );
SAFE_DELETE( m_pWater );
SAFE_DELETE(m_pNaviMesh);
m_pParentGrid = NULL;
m_pHeight = NULL;
m_Index = SectorIndex( -1, -1 );
m_Offset = EtVector3( 0.f, 0.f, 0.f );
m_fTileSize = 200.f;
m_fHeightMultiply = 1.f;
m_nBlockCount = 0;
m_bLoaded = false;
m_nAttributeBlockSize = 50;
m_nTileWidthCount = m_nTileHeightCount = 0;
m_fCenterHeight = 0.f;
m_fRadius = 0.f;
}
bool CEtWorldSector::Initialize( CEtWorldGrid *pParentGrid, SectorIndex Index )
{
_ASSERT( pParentGrid != NULL );
m_pParentGrid = pParentGrid;
m_Index = Index;
m_Offset.x = -( ( m_pParentGrid->GetGridX() / 2.f ) * (float)m_pParentGrid->GetGridWidth() * 100.f ) + (float)( m_Index.nX * m_pParentGrid->GetGridWidth() * 100.f );
m_Offset.x += ( m_pParentGrid->GetGridWidth() * 100.f ) / 2.f;
m_Offset.y = 0.f;
m_Offset.z = -( ( m_pParentGrid->GetGridY() / 2.f ) * (float)m_pParentGrid->GetGridHeight() * 100.f ) + (float)( m_Index.nY * m_pParentGrid->GetGridHeight() * 100.f );
m_Offset.z += ( m_pParentGrid->GetGridHeight() * 100.f ) / 2.f;
float fSize = max( m_pParentGrid->GetGridWidth() * 100.f, m_pParentGrid->GetGridHeight() * 100.f );
char szPath[_MAX_PATH] = { 0, };
sprintf_s( szPath, "%s\\Grid\\%s\\%d_%d", m_pParentGrid->GetWorld()->GetWorldFolder(), m_pParentGrid->GetName(), m_Index.nX, m_Index.nY );
if( !LoadSectorSize( szPath ) ) {
m_fCenterHeight = 0.f;
m_fRadius = max( fSize, GetHeightMultiply() * 65535.f );
}
m_pDecalQuadtree = new CEtQuadtree<CEtWorldDecal *>;
m_pDecalQuadtree->Initialize( EtVector2( m_Offset.x, m_Offset.z ), fSize );
m_pPropOctree = new CEtOctree<CEtWorldProp *>( false );
m_pPropOctree->Initialize( EtVector3( m_Offset.x, m_fCenterHeight, m_Offset.z ), m_fRadius );
m_pEventAreaQuadtree = new CEtQuadtree<CEtWorldEventArea *>;
m_pEventAreaQuadtree->Initialize( EtVector2( m_Offset.x, m_Offset.z ), fSize );
CalcTileCount();
return true;
}
bool CEtWorldSector::Load( int nBlockIndex, bool bThreadLoad, int nLoadSectorEnum )
{
// <20>ϴ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>б<EFBFBD><D0B1><EFBFBD> <20><><EFBFBD><EFBFBD>.
// <20><><EFBFBD>߿<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E9B6A7> <20><><EFBFBD><EFBFBD><EFBFBD>͸<EFBFBD> <20>о<20>ٷ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>°<EFBFBD> <20>ƴ϶<C6B4>
// <20>о<EFBFBD><D0BE><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>͸<EFBFBD> Ŭ<><C5AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ִ<EFBFBD> <20><><EFBFBD>¿<EFBFBD><C2BF><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>߰<EFBFBD><DFB0>߰<EFBFBD>
// <20><><EFBFBD>ְ<EFBFBD> <20>ٲ<EFBFBD><D9B2><EFBFBD><EFBFBD>Ѵ<EFBFBD>.
char szPath[_MAX_PATH] = { 0, };
bool bResult = false;
sprintf_s( szPath, "%s\\Grid\\%s\\%d_%d", m_pParentGrid->GetWorld()->GetWorldFolder(), m_pParentGrid->GetName(), m_Index.nX, m_Index.nY );
m_szSectorPath = szPath;
if( nLoadSectorEnum & LSE_Terrain ) bResult = LoadTerrain( szPath, nBlockIndex, bThreadLoad );
else bResult = true;
if( !CEtWorld::s_bIgnoreInvalidFile && bResult == false ) {
Free();
return false;
}
ThreadDelay();
if( nLoadSectorEnum & LSE_Prop ) bResult = LoadProp( szPath, nBlockIndex, bThreadLoad );
else bResult = true;
if( !CEtWorld::s_bIgnoreInvalidFile && bResult == false ) {
Free();
return false;
}
ThreadDelay();
if( nLoadSectorEnum & LSE_Control ) bResult = LoadControlArea( szPath );
else bResult = true;
if( !CEtWorld::s_bIgnoreInvalidFile && bResult == false ) {
Free();
return false;
}
ThreadDelay();
if( nLoadSectorEnum & LSE_Sound ) bResult = LoadSound( szPath );
else bResult = true;
if( !CEtWorld::s_bIgnoreInvalidFile && bResult == false ) {
Free();
return false;
}
ThreadDelay();
if( nLoadSectorEnum & LSE_Attribute ) bResult = LoadAttribute( szPath );
else bResult = true;
if( !CEtWorld::s_bIgnoreInvalidFile && bResult == false ) {
Free();
return false;
}
ThreadDelay();
if( nLoadSectorEnum & LSE_Navigation ) bResult = LoadNavigationMesh( szPath );
else bResult = true;
if( !CEtWorld::s_bIgnoreInvalidFile && bResult == false ) {
Free();
return false;
}
ThreadDelay();
if( nLoadSectorEnum & LSE_Trigger ) bResult = LoadTrigger( szPath );
else bResult = true;
if( !CEtWorld::s_bIgnoreInvalidFile && bResult == false ) {
Free();
return false;
}
ThreadDelay();
if( nLoadSectorEnum & LSE_Water ) bResult = LoadWater( szPath );
else bResult = true;
if( !CEtWorld::s_bIgnoreInvalidFile && bResult == false ) {
Free();
return false;
}
ThreadDelay();
if( nLoadSectorEnum & LSE_Decal ) bResult = LoadDecal( szPath );
else bResult = true;
if( !CEtWorld::s_bIgnoreInvalidFile && bResult == false ) {
Free();
return false;
}
ThreadDelay();
if( !( nLoadSectorEnum & LSE_GenCollisionHeight ) )
SAFE_DELETEA( m_pCollisionHeight );
m_bLoaded = true;
return true;
}
bool CEtWorldSector::LoadTerrain( const char *szSectorPath, int nBlockIndex, bool bThreadLoad )
{
char szTemp[_MAX_PATH] = { 0, };
int nSize;
DWORD *pAlpha = NULL;
std::vector<int> nVecBlockTypeList;
std::vector< std::vector<std::string> > szVecLayerTexture;
std::vector< std::vector<float> > fVecLayerTextureDistance;
std::vector< std::vector<float> > fVecLayerTextureRotation;
char *pGrass = NULL;
float fGrassWidth[4] = { 100.f, }, fGrassHeightMin[4] = { 100.f, }, fGrassHeightMax[4] = { 100.f, };
float fGrassShakeMin = 8.f, fGrassShakeMax = 15.f;
std::string szGrassTexture;
CResMngStream Stream;
// Load Height Table
sprintf_s( szTemp, "%s\\Height.ini", szSectorPath );
Stream.Open( szTemp );
if( !Stream.IsValid() ) return false;
Stream.Read( &m_fHeightMultiply, sizeof(float) );
Stream.Read( &nSize, sizeof(int) );
m_pHeight = new short[nSize];
m_nHeightSize = nSize;
Stream.Read( m_pHeight, nSize * sizeof(short) );
if( !Stream.IsEnd() && long(Stream.Size() - Stream.Tell()) >= long(nSize * sizeof(short)) ) {
m_pCollisionHeight = new short[nSize];
Stream.Read( m_pCollisionHeight, nSize * sizeof(short) );
}
Stream.Close();
// Load Alpha Table
sprintf_s( szTemp, "%s\\AlphaTable.ini", szSectorPath );
Stream.Open( szTemp );
if( Stream.IsValid() ) {
Stream.Read( &nSize, sizeof(int) );
pAlpha = new DWORD[nSize];
Stream.Read( pAlpha, nSize * sizeof(DWORD) );
Stream.Close();
}
// Load Grass Table
sprintf_s( szTemp, "%s\\GrassTable.ini", szSectorPath );
Stream.Open( szTemp );
if( Stream.IsValid() ) {
Stream.Read( fGrassWidth, sizeof(fGrassWidth) );
Stream.Read( fGrassHeightMin, sizeof(fGrassHeightMin) );
Stream.Read( fGrassHeightMax, sizeof(fGrassHeightMax) );
Stream.Read( &fGrassShakeMin, sizeof(float) );
Stream.Read( &fGrassShakeMax, sizeof(float) );
ReadStdString( szGrassTexture, &Stream );
Stream.Read( &nSize, sizeof(int) );
pGrass = new char[nSize];
Stream.Read( pGrass, nSize * sizeof(char) );
Stream.Close();
}
// Load Texture Table
sprintf_s( szTemp, "%s\\TexTable.ini", szSectorPath );
Stream.Open( szTemp );
if( Stream.IsValid() ) {
Stream.Read( &m_nBlockCount, sizeof(int) );
// Read Block Type
int nType;
for( int i=0; i<m_nBlockCount; i++ ) {
Stream.Read( &nType, sizeof(int) );
nVecBlockTypeList.push_back( nType );
}
// Read Block Texture
std::string szTexture;
std::vector<std::string> szVecList;
for( int i=0; i<m_nBlockCount; i++ ) {
szVecList.clear();
Stream.Read( &nSize, sizeof(int) );
for( int j=0; j<nSize; j++ ) {
ReadStdString( szTexture, &Stream );
szVecList.push_back( szTexture );
}
szVecLayerTexture.push_back( szVecList );
}
SAFE_DELETE_VEC( szVecList );
// Read Block Texture Distance
float fDistance;
std::vector<float> fVecList;
for( int i=0; i<m_nBlockCount; i++ ) {
fVecList.clear();
Stream.Read( &nSize, sizeof(int) );
for( int j=0; j<nSize; j++ ) {
Stream.Read( &fDistance, sizeof(int) );
fVecList.push_back( fDistance );
}
fVecLayerTextureDistance.push_back( fVecList );
}
// Read Block Texture Rotation - <20><><EFBFBD><EFBFBD> ȣȯ<C8A3><C8AF> <20><><EFBFBD>ؼ<EFBFBD> <20><><EFBFBD><EFBFBD>ó<EFBFBD><C3B3><EFBFBD><EFBFBD> <20>߰<EFBFBD><DFB0>Ѵ<EFBFBD>.(<28><> <20><><EFBFBD>̶<EFBFBD><CCB6><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ϴ<EFBFBD>.)
bool bReadRotation = false;
int nValue = 0;
int nRead = Stream.Read( &nSize, sizeof(int) );
if( nRead != 0 )
{
bReadRotation = true;
nValue = sizeof(int);
Stream.Seek( -nValue, SEEK_CUR );
}
float fRotation;
std::vector<float> fVecList2;
for( int i=0; i<m_nBlockCount; i++ ) {
fVecList2.clear();
if( bReadRotation ) Stream.Read( &nSize, sizeof(int) );
else nSize = 4;
for( int j=0; j<nSize; j++ ) {
if( bReadRotation ) Stream.Read( &fRotation, sizeof(int) );
else fRotation = 0.0f;
fVecList2.push_back( fRotation );
}
fVecLayerTextureRotation.push_back( fVecList2 );
}
Stream.Close();
SAFE_DELETE_VEC( fVecList );
}
InitializeTerrain( pAlpha, nVecBlockTypeList, szVecLayerTexture, fVecLayerTextureDistance, fVecLayerTextureRotation, (char*)szGrassTexture.c_str(), pGrass, fGrassWidth, fGrassHeightMin, fGrassHeightMax, fGrassShakeMin, fGrassShakeMax );
// Clear Used Vector
SAFE_DELETEA( pGrass );
SAFE_DELETEA( pAlpha );
SAFE_DELETE_VEC( nVecBlockTypeList );
for( DWORD i=0; i<szVecLayerTexture.size(); i++ ) {
SAFE_DELETE_VEC( szVecLayerTexture[i] );
}
SAFE_DELETE_VEC( szVecLayerTexture );
for( DWORD i=0; i<fVecLayerTextureDistance.size(); i++ ) {
SAFE_DELETE_VEC( fVecLayerTextureDistance[i] );
}
SAFE_DELETE_VEC( fVecLayerTextureDistance );
for( DWORD i=0; i<fVecLayerTextureRotation.size(); i++ ) {
SAFE_DELETE_VEC( fVecLayerTextureRotation[i] );
}
SAFE_DELETE_VEC( fVecLayerTextureRotation );
return true;
}
void CEtWorldSector::LoadIgnorePropFolder( const char *szSectorPath )
{
m_vecIgnorePropFolder.clear();
char szTemp[_MAX_PATH] = { 0, };
sprintf_s( szTemp, "%s\\IgnorePropFolderInfo.ini", szSectorPath );
CResMngStream Stream( szTemp );
if( !Stream.IsValid() ) return;
int nCount;
std::string szStr;
Stream.Read( &nCount, sizeof(int) );
for( int i=0; i<nCount; i++ ) {
ReadStdString( szStr, &Stream );
m_vecIgnorePropFolder.push_back( szStr );
}
}
bool CEtWorldSector::CheckIgnoreProp( const char *szPropName )
{
if( m_vecIgnorePropFolder.empty() ) return false;
// AddResourcePathȣ<68><C8A3><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><>-<2D><><EFBFBD><EFBFBD> <20><><EFBFBD>ҽ<EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD>ϰ<EFBFBD> <20>Ǿ<EFBFBD><C7BE>ֽ<EFBFBD><D6BD>ϴ<EFBFBD>.
std::string szFullName = CEtResourceMng::GetInstance().GetFullNameInCacheList( szPropName ).c_str();
if( szFullName.empty() ) return false;
std::vector<std::string> vecToken;
TokenizeA( szFullName, vecToken, "\\" );
if( vecToken.size() > 1 ) {
std::string szFolderName = vecToken[vecToken.size()-2];
for( int i = 0; i < (int)m_vecIgnorePropFolder.size(); ++i ) {
if( szFolderName == m_vecIgnorePropFolder[i] )
return true;
}
}
return false;
}
bool CEtWorldSector::LoadProp( const char *szSectorPath, int nBlockIndex, bool bThreadLoad )
{
char szTemp[_MAX_PATH] = { 0, };
sprintf_s( szTemp, "%s\\PropInfo.ini", szSectorPath );
CResMngStream Stream( szTemp );
if( !Stream.IsValid() ) return false;
LoadIgnorePropFolder( szSectorPath );
int nSize;
Stream.Read( &m_nPropCreateUniqueCount, sizeof(int) );
Stream.Read( &nSize, sizeof(int) );
int nStructSize;
CEtWorldProp::PropStruct Struct;
CEtWorldProp *pProp;
for( int i=0; i<nSize; i++ ) {
// <20>տ<EFBFBD> PropSize <20><> Class
Stream.Read( &nStructSize, sizeof(int) );
Stream.Read( &Struct, sizeof(CEtWorldProp::PropStruct) );
if( CheckIgnoreProp( Struct.szPropName ) ) {
int nCustomSize = nStructSize - sizeof(CEtWorldProp::PropStruct);
Stream.Seek( nCustomSize, SEEK_CUR );
continue;
}
int nPropClassID = GetPropClassID( Struct.szPropName );
pProp = AllocProp( nPropClassID );
if( pProp == NULL ) {
int nCustomSize = nStructSize - sizeof(CEtWorldProp::PropStruct);
Stream.Seek( nCustomSize, SEEK_CUR );
OutputDebug( "Warning : <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ֽ<EFBFBD><D6BD>ϴ<EFBFBD>. [ %s ] / Prop Alloc <20><><EFBFBD><EFBFBD>\n", Struct.szPropName );
continue;
}
else pProp->SetClassID( nPropClassID );
pProp->LoadCustomInfo( &Stream );
if( pProp->Initialize( this, Struct.szPropName, Struct.vPosition, Struct.vRotation, Struct.vScale ) == false ) {
SAFE_DELETE( pProp );
continue;
}
pProp->SetCreateUniqueID( Struct.nUniqueID );
pProp->EnableCastShadow( Struct.bCastShadow );
pProp->EnableReceiveShadow( Struct.bReceiveShadow );
pProp->EnableIgnoreBuildColMesh( Struct.bIgnoreBuildColMesh );
pProp->SetNavType( Struct.nNavType );
InsertProp( pProp );
ThreadDelay();
}
return true;
}
void CEtWorldSector::SetTileSize( float fValue )
{
m_fTileSize = fValue;
CalcTileCount();
}
void CEtWorldSector::CalcTileCount()
{
m_nTileWidthCount = 1 + ( m_pParentGrid->GetGridWidth() * 100 ) / (int)m_fTileSize;
m_nTileHeightCount = 1 + ( m_pParentGrid->GetGridHeight() * 100 ) / (int)m_fTileSize;
}
float CEtWorldSector::GetHeightToWorld( float fX, float fZ, EtVector3 *pNormal )
{
fX -= ( m_Offset.x - ( m_pParentGrid->GetGridWidth() * 100.f / 2.f ) );
fZ -= ( m_Offset.z - ( m_pParentGrid->GetGridHeight() * 100.f / 2.f ) );
return GetHeight( fX, fZ, pNormal );
}
float CEtWorldSector::GetHeightFromArray( float fX, float fZ, EtVector3 *pNormal, int nTileScale, short *pHeight )
{
if( pHeight == NULL ) {
if( pNormal ) *pNormal = EtVector3( 0.f, 0.f, 0.f );
return 0.f;
}
if( fX < 0.f ) fX = 0.f;
else if( fX >= m_pParentGrid->GetGridWidth() * 100.f ) fX = ( m_pParentGrid->GetGridWidth() * 100.f ) - 0.1f;
if( fZ < 0.f ) fZ = 0.f;
else if( fZ >= m_pParentGrid->GetGridHeight() * 100.f ) fZ = ( m_pParentGrid->GetGridHeight() * 100.f ) - 0.1f;
int nBlockX = (int)( fX / (m_fTileSize*nTileScale) );
int nBlockZ = (int)( fZ / (m_fTileSize*nTileScale) );
float fCenterX = fX / (m_fTileSize*nTileScale) - nBlockX;
float fCenterZ = fZ / (m_fTileSize*nTileScale) - nBlockZ;
nBlockX *= nTileScale;
nBlockZ *= nTileScale;
DWORD dwSectorWidth = GetTileWidthCount();
int nTemp = ( nBlockZ * dwSectorWidth ) + nBlockX;
// Height <20><><EFBFBD><EFBFBD>ó<EFBFBD><C3B3>.
if( nTemp < 0 || nTemp >= m_nHeightSize || nTemp + nTileScale >= m_nHeightSize )
{
if( pNormal ) *pNormal = EtVector3( 0.f, 0.f, 0.f );
return 0.f;
}
float fEdgeHeight[4];
fEdgeHeight[0] = pHeight[nTemp];
fEdgeHeight[1] = pHeight[nTemp + nTileScale];
nTemp = ( ( nBlockZ + nTileScale ) * dwSectorWidth ) + nBlockX;
// Height <20><><EFBFBD><EFBFBD>ó<EFBFBD><C3B3>.
if( nTemp < 0 || nTemp >= m_nHeightSize || nTemp + nTileScale >= m_nHeightSize )
{
if( pNormal ) *pNormal = EtVector3( 0.f, 0.f, 0.f );
return 0.f;
}
fEdgeHeight[2] = pHeight[nTemp];
fEdgeHeight[3] = pHeight[nTemp + nTileScale];
float fResultHeight;
if( fCenterX > fCenterZ )
{
float fTemp = fEdgeHeight[0] * ( 1.f - fCenterX );
float fCalcHeight1 = fTemp + fEdgeHeight[3] * fCenterX;
float fCalcHeight2 = fTemp + fEdgeHeight[1] * fCenterX;
fTemp = fCenterZ / fCenterX;
fResultHeight = fCalcHeight1 * fTemp + fCalcHeight2 * ( 1 - fTemp );
}
else if( fCenterX < fCenterZ )
{
float fTemp = fEdgeHeight[0] * ( 1 - fCenterZ );
float fCalcHeight1 = fTemp + fEdgeHeight[2] * fCenterZ;
float fCalcHeight2 = fTemp + fEdgeHeight[3] * fCenterZ;
fTemp = fCenterX / fCenterZ;
fResultHeight = fCalcHeight1 * ( 1 - fTemp ) + fCalcHeight2 * fTemp;
}
else
{
fResultHeight = fEdgeHeight[0] * ( 1 - fCenterZ ) + fEdgeHeight[3] * fCenterZ;
}
if( pNormal ) *pNormal = GetHeightNormal( nBlockX, nBlockZ );
return fResultHeight * m_fHeightMultiply;
}
float CEtWorldSector::GetHeight( float fX, float fZ, EtVector3 *pNormal, int nTileScale )
{
return GetHeightFromArray( fX, fZ, pNormal, nTileScale, m_pHeight );
}
float CEtWorldSector::GetCollisionHeight( float fX, float fZ, EtVector3 *pNormal, int nTileScale )
{
return GetHeightFromArray( fX, fZ, pNormal, nTileScale, m_pCollisionHeight );
}
bool CEtWorldSector::GetWaterHeight( float fX, float fZ, float *pfResult )
{
if( !m_pWater ) return false;
return m_pWater->GetHeight( fX, fZ, pfResult );
}
EtVector3 CEtWorldSector::GetHeightNormal( int nBlockX, int nBlockZ )
{
int nHeightIndex;
float fDX, fDZ;
D3DXVECTOR3 Return;
DWORD dwTileWidth = GetTileWidthCount();
DWORD dwTileHeight = GetTileHeightCount();
nHeightIndex = dwTileWidth * nBlockZ + nBlockX;
if( nBlockX == 0 )
fDX = ( m_pHeight[nHeightIndex] - m_pHeight[nHeightIndex+1] ) / m_fTileSize;
else if( nBlockX == dwTileWidth - 1 )
fDX = ( m_pHeight[nHeightIndex-1] - m_pHeight[nHeightIndex] ) / m_fTileSize;
else fDX = ( m_pHeight[nHeightIndex-1] - m_pHeight[nHeightIndex+1] ) / ( m_fTileSize * 2 );
if( nBlockZ == 0 )
fDZ = ( m_pHeight[nHeightIndex] - m_pHeight[nHeightIndex+dwTileWidth] ) / m_fTileSize;
else if( nBlockZ == dwTileHeight - 1 )
fDZ = ( m_pHeight[nHeightIndex-dwTileWidth-2] - m_pHeight[nHeightIndex] ) / m_fTileSize;
else
fDZ = ( m_pHeight[nHeightIndex-dwTileWidth-2] - m_pHeight[nHeightIndex+dwTileWidth] ) / ( m_fTileSize * 2 );
Return.x = fDX;
Return.y = 1.0f;
Return.z = fDZ;
EtVec3Normalize( &Return, &Return );
return Return;
}
char CEtWorldSector::GetAttribute( float fX, float fZ )
{
if( m_pAttribute == NULL ) return 0;
int nBlockX, nBlockZ;
if( fX < 0.f ) fX = 0.f;
else if( fX >= m_pParentGrid->GetGridWidth() * 100.f ) fX = ( m_pParentGrid->GetGridWidth() * 100.f ) - 0.1f;
if( fZ < 0.f ) fZ = 0.f;
else if( fZ >= m_pParentGrid->GetGridHeight() * 100.f ) fZ = ( m_pParentGrid->GetGridHeight() * 100.f ) - 0.1f;
nBlockX = (int)( fX / (float)m_nAttributeBlockSize );
nBlockZ = (int)( fZ / (float)m_nAttributeBlockSize );
int nWidthCount = (int)( GetTileWidthCount() * GetTileSize() ) / m_nAttributeBlockSize;
// Session <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> ó<><C3B3>
int nIndex = nBlockZ * nWidthCount + nBlockX;
if( nIndex >= m_nAttributeSize || nIndex < 0 )
return 0;
return m_pAttribute[ nIndex ];
}
bool CEtWorldSector::Pick( EtVector3 &vOrig, EtVector3 &vDir, EtVector3 &vPickPos )
{
if( !m_Handle ) return false;
return m_Handle->Pick( vOrig, vDir, vPickPos );
}
bool CEtWorldSector::PickWater( EtVector3 &vOrig, EtVector3 &vDir, EtVector3 &vPickPos )
{
/*
if( !m_Handle ) return false;
return m_Handle->Pick( vOrig, vDir, vPickPos );
*/
if( !m_pWater ) return false;
return m_pWater->Pick( vOrig, vDir, vPickPos );
}
CEtWorldProp *CEtWorldSector::AddProp( const char *szPropName, EtVector3 &vPos, EtVector3 &vRotate, EtVector3 &vScale, void *pCustomParam )
{
int nClassID = GetPropClassID( szPropName );
CEtWorldProp *pProp = AllocProp( nClassID );
if( pProp == NULL ) return NULL;
EtVector3 vOffset = *GetOffset();
vOffset.x -= ( GetTileWidthCount() * GetTileSize() ) / 2.f;
vOffset.z -= ( GetTileHeightCount() * GetTileSize() ) / 2.f;
vOffset.y = 0.f;
pProp->SetCustomParam( pCustomParam );
if( pProp->Initialize( this, szPropName, (EtVector3)( vPos - vOffset ), vRotate, vScale ) == false ) {
SAFE_DELETE( pProp );
return NULL;
}
pProp->SetClassID( nClassID );
pProp->SetCreateUniqueID( AddPropCreateUniqueCount() );
InsertProp( pProp );
return pProp;
}
void CEtWorldSector::InsertProp( CEtWorldProp *pProp )
{
SSphere Sphere;
m_pVecPropList.push_back( pProp );
pProp->GetBoundingSphere( Sphere );
pProp->SetCurOctreeNode( m_pPropOctree->Insert( pProp, Sphere ) );
}
bool CEtWorldSector::DeleteProp( CEtWorldProp *pProp )
{
if( !m_pPropOctree->Remove( pProp, pProp->GetCurOctreeNode() ) ) {
m_pPropOctree->Remove( pProp, NULL );
}
pProp->SetCurOctreeNode( NULL );
std::vector<CEtWorldProp *>::iterator it = std::find( m_pVecPropList.begin(), m_pVecPropList.end(), pProp );
if( it == m_pVecPropList.end() )
return false;
m_pVecPropList.erase( it );
return true;
}
DWORD CEtWorldSector::GetPropCount()
{
return (DWORD)m_pVecPropList.size();
}
CEtWorldProp *CEtWorldSector::GetPropFromIndex( DWORD dwIndex )
{
if( dwIndex >= (DWORD)m_pVecPropList.size() ) return NULL;
return m_pVecPropList[dwIndex];
}
CEtWorldProp *CEtWorldSector::AllocProp( int nClass )
{
return new CEtWorldProp;
}
/*
void CEtWorldSector::InsertControl( const char *szControlName )
{
if( GetControlFromName( szControlName ) ) return;
CEtWorldEventControl *pControl = AllocControl();
pControl->SetName( szControlName );
m_pVecAreaControl.push_back( pControl );
}
*/
void CEtWorldSector::InsertControl( CEtWorldEventControl *pControl )
{
if( GetControlFromUniqueID( pControl->GetUniqueID() ) ) return;
m_pVecAreaControl.push_back( pControl );
}
void CEtWorldSector::RemoveControl( int nUniqueID )
{
for( DWORD i=0; i<m_pVecAreaControl.size(); i++ ) {
if( m_pVecAreaControl[i]->GetUniqueID() == nUniqueID ) {
SAFE_DELETE( m_pVecAreaControl[i] );
m_pVecAreaControl.erase( m_pVecAreaControl.begin() + i );
break;
}
}
}
DWORD CEtWorldSector::GetControlCount()
{
return (DWORD)m_pVecAreaControl.size();
}
CEtWorldEventControl *CEtWorldSector::GetControlFromUniqueID( int nUniqueID )
{
for( DWORD i=0; i<m_pVecAreaControl.size(); i++ ) {
if( m_pVecAreaControl[i]->GetUniqueID() == nUniqueID ) return m_pVecAreaControl[i];
}
return NULL;
}
CEtWorldEventControl *CEtWorldSector::GetControlFromIndex( DWORD dwIndex )
{
if( dwIndex >= m_pVecAreaControl.size() ) return NULL;
return m_pVecAreaControl[dwIndex];
}
/*
CEtWorldEventControl *CEtWorldSector::GetControlFromName( const char *szControlName )
{
for( DWORD i=0; i<m_pVecAreaControl.size(); i++ ) {
if( strcmp( szControlName, m_pVecAreaControl[i]->GetName() ) == NULL ) return m_pVecAreaControl[i];
}
return NULL;
}
*/
CEtWorldEventControl *CEtWorldSector::AllocControl()
{
return new CEtWorldEventControl( this );
}
bool CEtWorldSector::LoadControlArea( const char *szSectorPath )
{
EtVector3 vOffset = m_Offset;
vOffset.x -= ( GetTileWidthCount() * GetTileSize() ) / 2.f;
vOffset.z -= ( GetTileHeightCount() * GetTileSize() ) / 2.f;
char szFullName[_MAX_PATH];
int nCount;
sprintf_s( szFullName, "%s\\EventAreaInfo.ini", szSectorPath );
CResMngStream Stream( szFullName );
if( !Stream.IsValid() ) return true;
Stream.Seek( sizeof(int), SEEK_CUR );
Stream.Read( &nCount, sizeof(int) );
for( int i=0; i<nCount; i++ ) {
CEtWorldEventControl *pControl = AllocControl();
if( pControl->Load( &Stream ) == false ) {
SAFE_DELETE( pControl );
continue;
}
InsertControl( pControl );
// <20><><EFBFBD><EFBFBD> <20>ɼ°<C9BC><C2B0><EFBFBD><EFBFBD><EFBFBD> <20>̵<EFBFBD><CCB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ش<EFBFBD>.
CEtWorldEventArea *pArea;
for( DWORD j=0; j<pControl->GetAreaCount(); j++ ) {
pArea = pControl->GetAreaFromIndex(j);
*pArea->GetMax() += vOffset;
*pArea->GetMin() += vOffset;
pArea->CalcOBB();
SCircle Circle;
pArea->GetBoundingCircle( Circle );
pArea->SetCurQuadtreeNode( m_pEventAreaQuadtree->Insert( pArea, Circle ) );
}
ThreadDelay();
}
return true;
}
CEtWorldSound *CEtWorldSector::AllocSound()
{
return new CEtWorldSound( this );
}
bool CEtWorldSector::LoadSound( const char *szSectorPath )
{
char szFullName[_MAX_PATH];
sprintf_s( szFullName, "%s\\SoundInfo.ini", szSectorPath );
m_pSoundInfo = AllocSound();
if( m_pSoundInfo ) {
if( m_pSoundInfo->Load( szFullName ) == false ) {
SAFE_DELETE( m_pSoundInfo );
return false;
}
// m_pSoundInfo->Play();
}
return true;
}
bool CEtWorldSector::LoadAttribute( const char *szSectorPath )
{
char szFullName[_MAX_PATH];
sprintf_s( szFullName, "%s\\HeightAttribute.ini", szSectorPath );
CResMngStream Stream( szFullName );
if( !Stream.IsValid() ) {
int nWidthCount = (int)( GetTileWidthCount() * GetTileSize() ) / m_nAttributeBlockSize;
int nHeightCount = (int)( GetTileWidthCount() * GetTileSize() ) / m_nAttributeBlockSize;
int nSize = nWidthCount * nHeightCount;
m_pAttribute = new char[nSize];
m_nAttributeSize = nSize;
memset( m_pAttribute, 0, nSize );
}
else {
int nSize;
Stream.Read( &m_nAttributeBlockSize, sizeof(int) );
Stream.Read( &nSize, sizeof(int) );
m_pAttribute = new char[nSize];
m_nAttributeSize = nSize;
Stream.Read( m_pAttribute, nSize );
}
return true;
}
bool CEtWorldSector::LoadNavigationMesh( const char *szSectorPath )
{
char szFullName[_MAX_PATH] = {0,};
sprintf_s( szFullName, "%s\\Navigation.ini", szSectorPath );
CResMngStream Stream( szFullName );
if( Stream.IsValid() )
{
m_pNaviMesh = new NavigationMesh();
bool bResult = m_pNaviMesh->LoadFromStream(&Stream);
return bResult;
}
return true;
}
CEtTrigger *CEtWorldSector::AllocTrigger()
{
return new CEtTrigger( this );
}
bool CEtWorldSector::LoadTrigger( const char *szSectorPath )
{
char szFullName[_MAX_PATH];
m_pTrigger = AllocTrigger();
sprintf_s( szFullName, "%s\\TriggerDefine.ini", szSectorPath );
m_pTrigger->LoadDefine( szFullName );
sprintf_s( szFullName, "%s\\Trigger.ini", szSectorPath );
if( m_pTrigger->Load( szFullName ) == false ) {
SAFE_DELETE( m_pTrigger );
return false;
}
return true;
}
CEtWorldWater *CEtWorldSector::AllocWater()
{
return new CEtWorldWater( this );
}
bool CEtWorldSector::LoadWater( const char *szSectorPath )
{
char szFullName[_MAX_PATH];
sprintf_s( szFullName, "%s\\Water.ini", szSectorPath );
m_pWater = AllocWater();
m_pWater->Initialize();
if( m_pWater->Load( szFullName ) == false ) {
SAFE_DELETE( m_pWater );
return false;
}
return true;
}
bool CEtWorldSector::LoadSectorSize( const char *szSectorPath )
{
char szFullName[_MAX_PATH];
sprintf_s( szFullName, "%s\\SectorSize.ini", szSectorPath );
CResMngStream Stream( szFullName );
if( !Stream.IsValid() ) return false;
Stream.Read( &m_fCenterHeight, sizeof(float) );
Stream.Read( &m_fRadius, sizeof(float) );
return true;
}
void CEtWorldSector::ScanProp( EtVector3 &vPos, float fRadius, DNVector(CEtWorldProp*) *pVecResult )
{
if( !m_pPropOctree ) return;
/*
EtVector3 vOffset = m_Offset;
vOffset.x -= ( GetTileWidthCount() * GetTileSize() ) / 2.f;
vOffset.z -= ( GetTileHeightCount() * GetTileSize() ) / 2.f;
*/
SSphere Sphere;
Sphere.Center = vPos;
Sphere.fRadius = fRadius;
m_pPropOctree->Pick( Sphere, *pVecResult );
}
void CEtWorldSector::ScanDecal( EtVector2 &vPos, float fRadius, std::vector<CEtWorldDecal *> *pVecResult )
{
if( !m_pDecalQuadtree ) return;
SCircle Circle;
Circle.Center = vPos;
Circle.fRadius = fRadius;
m_pDecalQuadtree->Pick( Circle, *pVecResult );
}
void CEtWorldSector::ScanEventArea( EtVector2 &vPos, float fRadius, std::vector<CEtWorldEventArea *> *pVecResult )
{
if( !m_pEventAreaQuadtree ) return;
SCircle Circle;
Circle.Center = vPos;
Circle.fRadius = fRadius;
m_pEventAreaQuadtree->Pick( Circle, *pVecResult );
}
void CEtWorldSector::ScanEventArea( SAABox &Box, std::vector<CEtWorldEventArea *> *pVecResult )
{
if( !m_pEventAreaQuadtree ) return;
CEtWorldEventArea *pArea;
EtMatrix matIdentity;
SOBB BoxOBB;
EtMatrixIdentity( &matIdentity );
BoxOBB.Init( Box, matIdentity );
SCircle Circle;
Circle.Center = EtVector2( BoxOBB.Center.x, BoxOBB.Center.z );
Circle.fRadius = max( BoxOBB.Center[0], max( BoxOBB.Center[1], BoxOBB.Center[2] ) );
m_pEventAreaQuadtree->Pick( Circle, *pVecResult );
for( DWORD i=0; i<pVecResult->size(); i++ ) {
pArea = (*pVecResult)[i];
/*
if( !( ( pArea->GetMin()->x >= vMin.x || pArea->GetMax()->x >= vMin.x ) &&
( pArea->GetMin()->x <= vMax.x || pArea->GetMax()->x <= vMax.x ) &&
( pArea->GetMin()->y >= vMin.y || pArea->GetMax()->y >= vMin.y ) &&
( pArea->GetMin()->y <= vMax.y || pArea->GetMax()->y <= vMax.y ) ) ) {
pVecResult->erase( pVecResult->begin() + i );
i--;
}
*/
if( !TestOBBToOBB( BoxOBB, *pArea->GetOBB() ) ) {
pVecResult->erase( pVecResult->begin() + i );
i--;
}
}
}
void CEtWorldSector::ScanEventArea( SOBB &Box, std::vector<CEtWorldEventArea *> *pVecResult )
{
if( !m_pEventAreaQuadtree ) return;
SCircle Circle;
Circle.Center = EtVector2( Box.Center.x, Box.Center.z );
Circle.fRadius = max( Box.Extent[0], max( Box.Extent[1], Box.Extent[2] ) );
m_pEventAreaQuadtree->Pick( Circle, *pVecResult );
CEtWorldEventArea *pArea;
for( DWORD i=0; i<pVecResult->size(); i++ ) {
pArea = (*pVecResult)[i];
if( !TestOBBToOBB( Box, *pArea->GetOBB() ) ) {
pVecResult->erase( pVecResult->begin() + i );
i--;
}
}
}
int CEtWorldSector::AddPropCreateUniqueCount()
{
m_nPropCreateUniqueCount++;
return m_nPropCreateUniqueCount;
}
CEtWorldProp *CEtWorldSector::GetPropFromCreateUniqueID( DWORD dwUniqueID )
{
for( DWORD i=0; i<m_pVecPropList.size(); i++ ) {
if( m_pVecPropList[i]->GetCreateUniqueID() == dwUniqueID ) return m_pVecPropList[i];
}
return NULL;
}
int CEtWorldSector::AddEventAreaCreateUniqueCount()
{
m_nEventAreaCreateUniqueCount++;
return m_nEventAreaCreateUniqueCount;
}
CEtWorldEventArea *CEtWorldSector::GetEventAreaFromCreateUniqueID( int nValue )
{
for( DWORD i=0; i<m_pVecAreaControl.size(); i++ ) {
CEtWorldEventControl *pControl = m_pVecAreaControl[i];
CEtWorldEventArea *pArea = pControl->GetAreaFromCreateUniqueID( nValue );
if( pArea ) return pArea;
}
return NULL;
}
CEtWorldDecal *CEtWorldSector::AllocDecal()
{
return new CEtWorldDecal( this );
}
bool CEtWorldSector::LoadDecal( const char *szSectorPath )
{
char szFullName[_MAX_PATH];
sprintf_s( szFullName, "%s\\DecalInfo.ini", szSectorPath );
CResMngStream Stream( szFullName );
if( !Stream.IsValid() ) return true;
int nCount;
Stream.Read( &nCount, sizeof(int) );
CEtWorldDecal::DecalStruct Struct;
for( int i=0; i<nCount; i++ ) {
Stream.Read( &Struct, sizeof(CEtWorldDecal::DecalStruct) );
CEtWorldDecal *pDecal = AllocDecal();
if( pDecal == NULL ) continue;
if( pDecal->Initialize( Struct.vPos, Struct.fRadius, Struct.fRotate, Struct.vColor, Struct.fAlpha, Struct.szTextureName ) == false ) {
SAFE_DELETE( pDecal );
}
InsertDecal( pDecal );
}
return true;
}
void CEtWorldSector::InsertDecal( CEtWorldDecal *pDecal )
{
std::vector<CEtWorldDecal *>::iterator it = std::find( m_pVecDecalList.begin(), m_pVecDecalList.end(), pDecal );
if( it != m_pVecDecalList.end() ) return;
m_pVecDecalList.push_back( pDecal );
SCircle Circle;
pDecal->GetBoundingCircle( Circle );
pDecal->SetCurQuadtreeNode( m_pDecalQuadtree->Insert( pDecal, Circle ) );
}
void CEtWorldSector::DeleteDecal( CEtWorldDecal *pDecal )
{
std::vector<CEtWorldDecal *>::iterator it = std::find( m_pVecDecalList.begin(), m_pVecDecalList.end(), pDecal );
if( it == m_pVecDecalList.end() ) return;
if( !m_pDecalQuadtree->Remove( pDecal, pDecal->GetCurQuadtreeNode() ) ) {
m_pDecalQuadtree->Remove( pDecal, NULL );
}
pDecal->SetCurQuadtreeNode( NULL );
m_pVecDecalList.erase( it );
}
DWORD CEtWorldSector::GetDecalCount()
{
return (DWORD)m_pVecDecalList.size();
}
CEtWorldDecal *CEtWorldSector::GetDecalFromIndex( DWORD dwIndex )
{
if( dwIndex >= m_pVecDecalList.size() ) return NULL;
return m_pVecDecalList[dwIndex];
}
bool CEtWorldSector::GenerationCollisionHeight( short *pCollisionHeight )
{
NavigationMesh *pNavMesh = GetNavMesh();
EtVector3 vOffset;
vOffset.x = ( m_pParentGrid->GetGridWidth() * 100.f ) / 2.f;
vOffset.z = ( m_pParentGrid->GetGridHeight() * 100.f ) / 2.f;
for( DWORD i=0; i<GetTileWidthCount(); i++ ) {
for( DWORD j=0; j<GetTileHeightCount(); j++ ) {
pCollisionHeight[j*GetTileWidthCount()+i] = m_pHeight[j*GetTileWidthCount()+i];
float fX = (float)( i * m_fTileSize );
float fZ = (float)( j * m_fTileSize );
DNVector(CEtWorldProp*) pVecProp;
float fHeight = GetHeight( fX, fZ );
fX -= vOffset.x;
fZ -= vOffset.z;
ScanProp( EtVector3( fX, fHeight, fZ ), 100.f, &pVecProp );
float fPropHeight = 0.f;
if( pNavMesh ) {
bool bFindCollision = false;
NavigationCell *pCell = pNavMesh->FindCell( EtVector3( fX, fHeight, fZ ) );
if( pCell ) {
if( pCell->GetType() == NavigationCell::CT_PROP ) {
fPropHeight = pCell->GetPlane()->SolveForY( fX, fZ );
bFindCollision = true;
}
}
if( bFindCollision ) {
fHeight = max( fHeight, fPropHeight );
}
}
SSegment Segment;
SCollisionResponse Response;
Segment.vOrigin = EtVector3( fX, fHeight + 100000.f, fZ );
Segment.vDirection = EtVector3( 0.f, -100000.f, 0.f );
fPropHeight = -100000.f;
for( DWORD k=0; k<pVecProp.size(); k++ ) {
EtObjectHandle hHandle = pVecProp[k]->GetObjectHandle();
if( !hHandle ) continue;
if( !hHandle->FindSegmentCollision( Segment, Response ) ) continue;
float fTemp = fHeight + ( 100000.f * ( 1.f - Response.fContactTime ) );
if( fTemp > fPropHeight ) fPropHeight = fTemp;
}
if( fPropHeight != FLT_MIN && fPropHeight > fHeight ) fHeight = fPropHeight;
int nTemp = (int)( fHeight / m_fHeightMultiply );
if( nTemp > SHRT_MAX ) nTemp = SHRT_MAX;
else if( nTemp < SHRT_MIN ) nTemp = SHRT_MIN;
pCollisionHeight[j*GetTileWidthCount()+i] = (short)nTemp;
}
}
return true;
}