Files
Leviathan/Client/Game/game/Env/SGameWeatherService.cpp
T
2026-06-01 12:46:52 +02:00

575 lines
18 KiB
C++

#include "stdafx.h"
#include "KRenderDeviceDX.h"
#include "SEnvPrimitive.h"
#include "K3DTypes.h"
#include "KSeqModel.h"
#include "K3DCamera.h"
#include "KResourceManager.h"
#include "KRenderObjectEtc.h"
#include <dump/XException.h>
#include <mmo/ArTime.h>
#include "TerrainPrimitive.h"
#include "SDebug_Util.h"
#include "SGameWorld.h"
#include "SCommandSystem.h"
#include <kfile/KFileManager.h>
#include "SGameSky.h"
#include "SGameWeather.h"
#include "SGameWeatherService.h"
#include "LuaVM.h"
#include <toolkit/XStringUtil.h>
#include "SGameMilesSoundMgr.h"
#include "SGameAvatarEx.h"
#include "SMessage.h"
#include "SGameMessage.h"
namespace env_fx {
class CParticleCollisionStrategy : public env_fx::ICollisionStrategy
{
public:
CParticleCollisionStrategy( SGame* pGame ) : m_pGame( pGame )
{
assert( pGame && "Collision strategy must have a game instance" );
}
virtual ~CParticleCollisionStrategy()
{
m_pGame = 0;
}
bool GetCollidePosition( float* out, float x, float y, float z )
{
float fTerrainHeight;
WORD wTile;
bool bFound = m_pGame->GetHeight( x, y, fTerrainHeight, wTile );
if( bFound )
{
out[ 0 ] = x; out[ 1 ] = y; out[ 2 ] = fTerrainHeight;
}
else
{
out[ 0 ] = x; out[ 1 ] = y; out[ 2 ] = -FLT_MAX;
}
return bFound;
}
bool GetCollideNormal( float* out_x, float* out_y, float* out_z, float x, float y, float z )
{
K3DVector _out( 0, 0, 0 );
K3DVector _1, _2, _3;
m_pGame->GetTerrainTriangle( x, y, _1, _2, _3 );
K3DVectorCross( _out, _3 - _1, _2 - _1 );
*out_x = _out.x;
*out_y = _out.y;
*out_z = _out.z;
return true;
}
private:
SGame* m_pGame;
};
}
SGameWeatherService::SGameWeatherService( SGame* pGame, SCommandSystem* pCommandSystem, SGameSky* pSky, SGameMilesSoundMgr* pSound, float fPrecipitationFactor )
: m_pGame ( pGame )
, m_pCommandSystem ( pCommandSystem )
, m_pSkyCtx ( pSky )
, m_pSoundMgr ( pSound )
, m_pCurrentState ( 0 )
, m_dwTime ( 0 )
, m_pRenderDevice ( 0 )
, m_pInfo ( 0 )
, m_pCollisionStrategy ( 0 )
, m_vCameraPosition ( 0, 0, 0 )
, m_vTargetPosition ( 0, 0, 0 )
, m_bActivity ( true )
, m_fQualityFactor ( 1.0f )
, m_fPrecipitationFactor( fPrecipitationFactor )
, m_bInDoor ( false )
{
assert( m_pGame && m_pSkyCtx && m_pSoundMgr && "there is null context in weather service" );
m_pCollisionStrategy = new env_fx::CParticleCollisionStrategy( pGame );
K3DMatrixIdentity( m_mView );
}
SGameWeatherService::~SGameWeatherService()
{
env_fx::util::wipe_seq( m_ctWeathers );
SAFE_DELETE( m_pInfo );
SAFE_DELETE( m_pCollisionStrategy );
}
void SGameWeatherService::Init( K3DRenderDeviceDX* pDevice, K3DIndexBuffer* pIndexBuf )
{
m_pRenderDevice = pDevice;
}
void SGameWeatherService::Process( DWORD dwTime )
{
if( this->IsActive() )
{
m_dwTime = dwTime;
for( WeatherStateVector::iterator it = m_ctWeathers.begin(); it != m_ctWeathers.end(); )
{
IGameWeatherState* pState = *it;
if( pState )
{
pState->Process( m_dwTime );
}
if( !pState || pState->IsGarbage() )
{
// garbages...
if( m_pCurrentState == pState )
m_pCurrentState = 0;
it = m_ctWeathers.erase( it );
SAFE_DELETE( pState );
}
else
{
++it;
}
}
}
}
void SGameWeatherService::Render( KViewportObject* pViewport )
{
if( this->IsActive() )
{
WeatherStateVector::iterator it = m_ctWeathers.begin(), itend = m_ctWeathers.end();
for( ; it != itend; ++it )
{
IGameWeatherState* pState = *it;
if( pState )
pState->Render( pViewport );
}
}
}
int SGameWeatherService::GetState() const
{
if( m_pCurrentState )
return m_pCurrentState->GetState();
return IGameWeatherState::WS_NONE;
}
void SGameWeatherService::SetPosition( const K3DVector& vCameraPos, const K3DVector& vTargetPos )
{
m_vCameraPosition = vCameraPos;
m_vTargetPosition = vTargetPos;
}
void SGameWeatherService::SetViewMatrix( const K3DMatrix& mView )
{
m_mView = mView;
}
DWORD SGameWeatherService::GetFadingTime() const
{
return IsFading() ? m_dwTime : 0;
}
void SGameWeatherService::ChangeInOut( bool bInDoor )
{
m_bInDoor = bInDoor;
}
void SGameWeatherService::ChangeState( int nThemeID, float fPrecipitationFactor, float fQualityFactor, bool bFader )
{
if( nThemeID < IGameWeatherState::WS_FINE || nThemeID >= IGameWeatherState::WS_NONE )
return;
if( m_pCurrentState && m_pCurrentState->GetState() == nThemeID && m_fPrecipitationFactor == fPrecipitationFactor && m_fQualityFactor == fQualityFactor )
return;
m_bFader = bFader;
m_fPrecipitationFactor = fPrecipitationFactor;
m_fQualityFactor = fQualityFactor;
// LOAD SCRIPT RESOURCE
std::string script_name =
KFileManager::Instance().CreateTemporaryFileFromResource( "weather_script.lua" );
if( script_name.length() > 0 )
{
LUA()->LoadScript( script_name.c_str() );
KFileManager::Instance().DeleteTemporaryFile( "weather_script.lua" );
}
std::string function_call;
XStringUtil::Format( function_call, "change_weather_theme( %d )", nThemeID );
LUA()->RunString( function_call.c_str() );
#ifdef DISTANCE_VIEW
// LOAD SCRIPT RESOURCE
script_name = KFileManager::Instance().CreateTemporaryFileFromResource( "skybox_script2.lua" );
// script_name = KFileManager::Instance().CreateTemporaryFileFromResource( "skybox_script.lua" );
if( script_name.length() > 0 )
{
LUA()->LoadScript( script_name.c_str() );
// KFileManager::Instance().DeleteTemporaryFile( "skybox_script.lua" );
KFileManager::Instance().DeleteTemporaryFile( "skybox_script2.lua" );
}
XStringUtil::Format( function_call, "change_skybox_theme_sky( %d )", nThemeID );
LUA()->RunString( function_call.c_str() );
//script_name = KFileManager::Instance().CreateTemporaryFileFromResource( "skybox_script.lua" );
//if( script_name.length() > 0 )
//{
// LUA()->LoadScript( script_name.c_str() );
// KFileManager::Instance().DeleteTemporaryFile( "skybox_script.lua" );
//}
//XStringUtil::Format( function_call, "change_skybox_theme( %d )", nThemeID );
//LUA()->RunString( function_call.c_str() );
#endif
#ifdef CLOUD_LUA
int k=0;
// 지역아이디에 따라 날씨를 바꿔준다
int l=0;
#endif
}
//void SGameWeatherService::ChangeCapacityFactor( float fCapacityFactor )
//{
// m_fCapacityFactor = fCapacityFactor;
// if( m_pCurrentState )
// ChangeState( m_pCurrentState->GetState(), GetPrecipitationFactor(), true );
//}
void SGameWeatherService::ChangeQuality( float fQualityFactor )
{
if( m_pCurrentState )
ChangeState( m_pCurrentState->GetState(), m_fPrecipitationFactor, fQualityFactor, true );
}
void SGameWeatherService::SetTheme( env_fx::SWeatherInfo* pInfo )
{
if( !pInfo ) return;
if( m_pCurrentState )
m_pCurrentState->OnLeave();
if( pInfo->m_nThemeID < 0 && pInfo->m_nThemeID >= IGameWeatherState::WS_NONE )
return;
SAFE_DELETE( m_pInfo );
m_pInfo = pInfo;
m_pCurrentState = _AppendWeatherState( static_cast< IGameWeatherState::EState >( pInfo->m_nThemeID ) );
if( m_pCurrentState )
m_pCurrentState->OnEnter();
}
IGameWeatherState* SGameWeatherService::_AppendWeatherState( IGameWeatherState::EState nState )
{
IGameWeatherState* pNewState = 0;
switch( nState )
{
case IGameWeatherState::WS_FINE:
pNewState = new SGameFineState( this );
break;
case IGameWeatherState::WS_CLOUDY:
pNewState = new SGameCloudyState( this );
break;
case IGameWeatherState::WS_FOGGY:
pNewState = new SGameFoggyState( this );
break;
case IGameWeatherState::WS_RAINY:
pNewState = new SGameRainyState( this );
break;
case IGameWeatherState::WS_SNOWY:
pNewState = new SGameSnowyState( this );
break;
default:
break;
}
if( pNewState )
m_ctWeathers.push_back( pNewState );
return pNewState;
}
void SGameWeatherService::ActivateThunder( bool bActivity )
{
m_pSkyCtx->SetThunderEnable( bActivity );
if( bActivity )
{
std::string function_call;
XStringUtil::Format( function_call, "get_thunder_attribute()" );
LUA()->RunString( function_call.c_str() );
}
}
void SGameWeatherService::ActivateLightning( bool bActivity )
{
m_pSkyCtx->SetLightningEnable( bActivity );
if( bActivity )
{
std::string function_call;
XStringUtil::Format( function_call, "get_lightning_attribute()" );
LUA()->RunString( function_call.c_str() );
}
}
// ===================================================================
// SGameFineState
// ===================================================================
void SGameFineState::OnEnter()
{
}
void SGameFineState::OnLeave()
{
m_bIsGarbage = true;
}
// ===================================================================
// SGameCloudyState
// ===================================================================
void SGameCloudyState::OnEnter()
{
}
void SGameCloudyState::OnLeave()
{
m_bIsGarbage = true;
}
// ===================================================================
// SGameFoggyState
// ===================================================================
void SGameFoggyState::OnEnter()
{
}
void SGameFoggyState::OnLeave()
{
m_bIsGarbage = true;
}
// ===================================================================
// SGameRainyState
// ===================================================================
void SGameRainyState::Process( DWORD dwTime )
{
if( !m_pService->IsInDoor() && m_pEmitter )
{
if( m_pEmitter->isActive() )
{
if( m_pService->m_pCommandSystem )
{
SGameAvatarEx* localAvatar = m_pService->m_pCommandSystem->GetLocalPlayer();
if( localAvatar && localAvatar->GetArClient() )
{
ArMoveVector& move = localAvatar->GetArClient()->GetMyPos();
float speed = (float)localAvatar->getMovingSpeed();
static K3DVector prevPosition = m_pService->m_vTargetPosition;
K3DVector moveDirection( m_pService->m_vTargetPosition.x - prevPosition.x, m_pService->m_vTargetPosition.y - prevPosition.y, 0.0f );
K3DVectorNormalize( moveDirection, moveDirection );
mVestige = moveDirection * ( speed / m_pEmitter->getAttribute().particle_velocity );
prevPosition = m_pService->m_vTargetPosition;
}
}
m_pEmitter->locate( m_pService->m_vTargetPosition, m_pService->m_vTargetPosition );
m_pEmitter->process( dwTime );
if( m_pAdditiveEmitter && m_pAdditiveEmitter->isActive() )
{
m_pAdditiveEmitter->locate( m_pService->m_vTargetPosition, m_pService->m_vTargetPosition );
m_pAdditiveEmitter->process( dwTime );
}
}
else
{
SAFE_DELETE( m_pEmitter );
SAFE_DELETE( m_pAdditiveEmitter );
m_bIsGarbage = true;
}
}
}
void SGameRainyState::Render( KViewportObject* pViewport )
{
if( !m_pService->IsInDoor() )
{
if( m_pEmitter && m_pEmitter->isActive() )
m_pEmitter->render( pViewport );
if( m_pAdditiveEmitter && m_pAdditiveEmitter->isActive() )
m_pAdditiveEmitter->render( pViewport );
}
}
void SGameRainyState::OnEnter()
{
if( 0 == m_pEmitter )
{
if( m_pService->m_pInfo->m_pWeatherAttr )
{
env_fx::SWeatherAttr* attribute = m_pService->m_pInfo->m_pWeatherAttr;
typedef env_fx::ZAxisBillboardTextureResource< env_fx::K3DVERTEX_WEATHER, env_fx::K3DINDEX_WEATHER > zaxis_billboard_resource_t;
typedef env_fx::NX3Resource nx3_resource_t;
env_fx::particle_op_unit_t* initor = new env_fx::particle_op_unit_t();
env_fx::particle_op_unit_t* action = new env_fx::particle_op_unit_t();
env_fx::particle_bundle_t* bundle = new env_fx::particle_bundle_t( initor, action );
env_fx::particle_resource_t* resource = 0;
if( attribute->resource_type == env_fx::SWeatherAttr::NX3 )
resource = new nx3_resource_t( attribute->resource );
else
resource = new zaxis_billboard_resource_t( attribute->resource, m_pService->m_pRenderDevice, mVestige );
initor->append( new env_fx::LifeFixedInitor( attribute->particle_life ) );
initor->append( new env_fx::VelocityFixedInitor( attribute->particle_direction.min * attribute->particle_velocity ) );
initor->append( new env_fx::RotationInitor( attribute->rotation_unit, attribute->rotation_speed ) );
initor->append( new env_fx::PositionFixedDistributionInitor( attribute->area_width, attribute->hori_density, attribute->area_height / 2 ) );
initor->append( new env_fx::VisibilityFixedInitor( 1.0f ) );
initor->append( new env_fx::ColorFixedInitor( K3DColor( 0xc4ffffff ) ) );
initor->append( new env_fx::SizeFixedInitor( attribute->particle_width, attribute->particle_height ) );
action->append( new env_fx::LifeDecreaseAction() );
action->append( new env_fx::VelocityAction() );
action->append( new env_fx::VelocityReactiveAction( m_pService->m_vTargetPosition ) );
//action->append( new env_fx::RotationAction() ); // sonador 1.1.19 파티클 스왑 오류 수정
action->append( new env_fx::PositionSwapAction( attribute->area_width / 2, attribute->area_width / 2 ) );
action->append( new env_fx::VisibilityFadeInOutAction( attribute->destroy_duration ) );
action->append( new env_fx::VisibilityFadeInOutOffsetAdditiveAction( attribute->area_width, attribute->area_width * 0.05f ) );
m_pEmitter = new weather_system_t( bundle, resource );
m_pEmitter->initialize( *attribute, m_pService->GetPrecipitationFactor() );
// additive
if( m_pEmitter && attribute->linked_attr )
{
SAFE_DELETE( m_pAdditiveEmitter );
attribute = attribute->linked_attr;
env_fx::particle_op_unit_t* initor = new env_fx::particle_op_unit_t();
env_fx::particle_op_unit_t* action = new env_fx::particle_op_unit_t();
env_fx::particle_bundle_t* bundle = new env_fx::particle_bundle_t( initor, action );
env_fx::particle_resource_t* resource = 0;
if( attribute->resource_type == env_fx::SWeatherAttr::NX3 )
resource = new nx3_resource_t( attribute->resource );
else
resource = new zaxis_billboard_resource_t( attribute->resource, m_pService->m_pRenderDevice, mVestige );
initor->append( new env_fx::LifeFixedInitor( attribute->particle_life ) );
initor->append( new env_fx::PositionNormalFixedDistributionOnTerrainInitor( m_pService->m_pCollisionStrategy, attribute->area_width, attribute->hori_density, m_pService->m_vTargetPosition ) );
initor->append( new env_fx::VisibilityFixedInitor( 1.0f ) );
initor->append( new env_fx::ColorFixedInitor( K3DColor( 0xffffffff ) ) );
action->append( new env_fx::LifeDecreaseAction() );
action->append( new env_fx::VelocityReactiveAction( m_pService->m_vTargetPosition ) );
action->append( new env_fx::VisibilityFadeInOutOffsetAdditiveAction( attribute->area_width, attribute->area_width * 0.05f ) );
m_pAdditiveEmitter = new weather_system_t( bundle, resource );
m_pAdditiveEmitter->initialize( *attribute, m_pService->GetPrecipitationFactor() );
}
}
}
if( m_pEmitter )
m_pEmitter->activate( m_pService->GetFadingTime(), true );
if( m_pAdditiveEmitter )
m_pAdditiveEmitter->activate( m_pService->GetFadingTime(), true );
// control sky context
if( m_pService->m_pSkyCtx )
m_pService->m_pSkyCtx->SetSkyType( m_pService->m_pInfo->m_nSkyType );
}
void SGameRainyState::OnLeave()
{
if( m_pEmitter )
m_pEmitter->activate( m_pService->GetFadingTime(), false );
if( m_pAdditiveEmitter )
m_pAdditiveEmitter->activate( m_pService->GetFadingTime(), false );
}
// ===================================================================
// SGameSnowState
// ===================================================================
void SGameSnowyState::Process( DWORD dwTime )
{
if( !m_pService->IsInDoor() && m_pEmitter )
{
if( m_pEmitter->isActive() )
{
m_pEmitter->locate( m_pService->m_vTargetPosition, m_pService->m_vTargetPosition );
m_pEmitter->process( dwTime );
}
else
{
SAFE_DELETE( m_pEmitter );
m_bIsGarbage = true;
}
}
}
void SGameSnowyState::Render( KViewportObject* pViewport )
{
if( !m_pService->IsInDoor() && m_pEmitter && m_pEmitter->isActive() )
m_pEmitter->render( pViewport );
}
void SGameSnowyState::OnEnter()
{
if( 0 == m_pEmitter )
{
typedef env_fx::BillboardTextureResource< env_fx::K3DVERTEX_WEATHER, env_fx::K3DINDEX_WEATHER > resource_t;
env_fx::particle_op_unit_t* initor = new env_fx::particle_op_unit_t();
env_fx::particle_op_unit_t* action = new env_fx::particle_op_unit_t();
env_fx::particle_bundle_t* bundle = new env_fx::particle_bundle_t( initor, action );
resource_t* resource = new resource_t( m_pService->m_pInfo->m_pWeatherAttr->resource, m_pService->m_pRenderDevice );
initor->append( new env_fx::LifeFixedInitor( m_pService->m_pInfo->m_pWeatherAttr->particle_life ) );
initor->append( new env_fx::VelocityFixedInitor( m_pService->m_pInfo->m_pWeatherAttr->particle_direction.min * m_pService->m_pInfo->m_pWeatherAttr->particle_velocity ) );
initor->append( new env_fx::RotationInitor( m_pService->m_pInfo->m_pWeatherAttr->rotation_unit, m_pService->m_pInfo->m_pWeatherAttr->rotation_speed ) );
initor->append( new env_fx::PositionFixedDistributionInitor( m_pService->m_pInfo->m_pWeatherAttr->area_width, m_pService->m_pInfo->m_pWeatherAttr->hori_density, m_pService->m_pInfo->m_pWeatherAttr->area_height / 2 ) );
initor->append( new env_fx::VisibilityFixedInitor( 1.0f ) );
initor->append( new env_fx::ColorFixedInitor( K3DColor( 0xffffffff ) ) );
initor->append( new env_fx::SizeFixedInitor( m_pService->m_pInfo->m_pWeatherAttr->particle_width, m_pService->m_pInfo->m_pWeatherAttr->particle_height ) );
action->append( new env_fx::LifeDecreaseAction() );
action->append( new env_fx::VelocityAction() );
action->append( new env_fx::VelocityReactiveAction( m_pService->m_vTargetPosition ) );
action->append( new env_fx::RotationAction() );
action->append( new env_fx::PositionSwapAction( m_pService->m_pInfo->m_pWeatherAttr->area_width / 2, m_pService->m_pInfo->m_pWeatherAttr->area_width / 2 ) );
action->append( new env_fx::VisibilityFadeInOutAction( m_pService->m_pInfo->m_pWeatherAttr->destroy_duration ) );
action->append( new env_fx::VisibilityFadeInOutOffsetAdditiveAction( m_pService->m_pInfo->m_pWeatherAttr->area_width, m_pService->m_pInfo->m_pWeatherAttr->area_width * 0.05f ) );
m_pEmitter = new weather_system_t( bundle, resource );
m_pEmitter->initialize( *m_pService->m_pInfo->m_pWeatherAttr, m_pService->GetPrecipitationFactor() );
}
if( m_pService->m_pInfo )
{
m_pEmitter->activate( m_pService->GetFadingTime(), true );
}
// control sky context
if( m_pService->m_pSkyCtx )
m_pService->m_pSkyCtx->SetSkyType( m_pService->m_pInfo->m_nSkyType );
}
void SGameSnowyState::OnLeave()
{
if( m_pEmitter )
m_pEmitter->activate( m_pService->GetFadingTime(), false );
}