2021-12-05 17:54:36 +00:00
# include "RenderComponent.h"
# include <sstream>
# include <string>
# include <iomanip>
# include "Entity.h"
# include "PacketUtils.h"
# include "CDClientManager.h"
# include "GameMessages.h"
# include "Game.h"
# include "dLogger.h"
2023-03-20 13:10:52 +00:00
# include "CDAnimationsTable.h"
2021-12-05 17:54:36 +00:00
std : : unordered_map < int32_t , float > RenderComponent : : m_DurationCache { } ;
2023-03-20 13:10:52 +00:00
RenderComponent : : RenderComponent ( Entity * parent , int32_t componentId ) : Component ( parent ) {
2021-12-05 17:54:36 +00:00
m_Effects = std : : vector < Effect * > ( ) ;
2023-03-20 13:10:52 +00:00
m_LastAnimationName = " " ;
2023-03-26 10:09:04 +00:00
if ( componentId = = - 1 ) return ;
2023-03-20 13:10:52 +00:00
auto query = CDClientDatabase : : CreatePreppedStmt ( " SELECT * FROM RenderComponent WHERE id = ?; " ) ;
query . bind ( 1 , componentId ) ;
auto result = query . execQuery ( ) ;
2021-12-05 17:54:36 +00:00
2023-03-20 13:10:52 +00:00
if ( ! result . eof ( ) ) {
auto animationGroupIDs = std : : string ( result . getStringField ( " animationGroupIDs " , " " ) ) ;
if ( ! animationGroupIDs . empty ( ) ) {
auto * animationsTable = CDClientManager : : Instance ( ) . GetTable < CDAnimationsTable > ( ) ;
auto groupIdsSplit = GeneralUtils : : SplitString ( animationGroupIDs , ' , ' ) ;
for ( auto & groupId : groupIdsSplit ) {
int32_t groupIdInt ;
if ( ! GeneralUtils : : TryParse ( groupId , groupIdInt ) ) {
Game : : logger - > Log ( " RenderComponent " , " bad animation group Id %s " , groupId . c_str ( ) ) ;
continue ;
}
m_animationGroupIds . push_back ( groupIdInt ) ;
animationsTable - > CacheAnimationGroup ( groupIdInt ) ;
}
2021-12-05 17:54:36 +00:00
}
}
result . finalize ( ) ;
}
RenderComponent : : ~ RenderComponent ( ) {
for ( Effect * eff : m_Effects ) {
if ( eff ) {
delete eff ;
eff = nullptr ;
}
}
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
m_Effects . clear ( ) ;
}
2023-08-10 21:33:15 +00:00
void RenderComponent : : Serialize ( RakNet : : BitStream * outBitStream , bool bIsInitialUpdate ) {
2021-12-05 17:54:36 +00:00
if ( ! bIsInitialUpdate ) return ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
outBitStream - > Write < uint32_t > ( m_Effects . size ( ) ) ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
for ( Effect * eff : m_Effects ) {
2023-10-09 20:20:56 +00:00
// we still need to write 0 as the size for name if it is a nullptr
if ( ! eff ) {
outBitStream - > Write < uint8_t > ( 0 ) ;
continue ;
}
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
outBitStream - > Write < uint8_t > ( eff - > name . size ( ) ) ;
2023-10-09 20:20:56 +00:00
// if there is no name, then we don't write anything else
if ( eff - > name . empty ( ) ) continue ;
for ( const auto & value : eff - > name ) outBitStream - > Write < uint8_t > ( value ) ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
outBitStream - > Write ( eff - > effectID ) ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
outBitStream - > Write < uint8_t > ( eff - > type . size ( ) ) ;
2023-10-09 20:20:56 +00:00
for ( const auto & value : eff - > type ) outBitStream - > Write < uint16_t > ( value ) ;
2022-07-28 13:39:57 +00:00
2023-10-09 20:20:56 +00:00
outBitStream - > Write < float_t > ( eff - > priority ) ;
2021-12-05 17:54:36 +00:00
outBitStream - > Write < int64_t > ( eff - > secondary ) ;
}
}
2023-10-09 20:20:56 +00:00
Effect * RenderComponent : : AddEffect ( const int32_t effectId , const std : : string & name , const std : : u16string & type , const float priority ) {
2021-12-05 17:54:36 +00:00
auto * eff = new Effect ( ) ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
eff - > effectID = effectId ;
eff - > name = name ;
eff - > type = type ;
2023-10-09 20:20:56 +00:00
eff - > priority = priority ;
2021-12-05 17:54:36 +00:00
m_Effects . push_back ( eff ) ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
return eff ;
}
void RenderComponent : : RemoveEffect ( const std : : string & name ) {
uint32_t index = - 1 ;
for ( auto i = 0u ; i < m_Effects . size ( ) ; + + i ) {
auto * eff = m_Effects [ i ] ;
if ( eff - > name = = name ) {
index = i ;
delete eff ;
break ;
}
}
if ( index = = - 1 ) {
return ;
}
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
m_Effects . erase ( m_Effects . begin ( ) + index ) ;
}
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
void RenderComponent : : Update ( const float deltaTime ) {
std : : vector < Effect * > dead ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
for ( auto * effect : m_Effects ) {
if ( effect - > time = = 0 ) {
continue ; // Skip persistent effects
}
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
const auto result = effect - > time - deltaTime ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
if ( result < = 0 ) {
dead . push_back ( effect ) ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
continue ;
}
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
effect - > time = result ;
}
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
for ( auto * effect : dead ) {
// StopEffect(effect->name);
}
}
void RenderComponent : : PlayEffect ( const int32_t effectId , const std : : u16string & effectType , const std : : string & name , const LWOOBJID secondary , const float priority , const float scale , const bool serialize ) {
RemoveEffect ( name ) ;
GameMessages : : SendPlayFXEffect ( m_Parent , effectId , effectType , name , secondary , priority , scale , serialize ) ;
2023-10-09 20:20:56 +00:00
auto * effect = AddEffect ( effectId , name , effectType , priority ) ;
2021-12-05 17:54:36 +00:00
const auto & pair = m_DurationCache . find ( effectId ) ;
if ( pair ! = m_DurationCache . end ( ) ) {
effect - > time = pair - > second ;
2022-01-06 21:05:03 +00:00
return ;
2022-07-28 13:39:57 +00:00
}
2022-01-13 03:48:27 +00:00
const std : : string effectType_str = GeneralUtils : : UTF16ToWTF8 ( effectType ) ;
auto query = CDClientDatabase : : CreatePreppedStmt (
" SELECT animation_length FROM Animations WHERE animation_type IN (SELECT animationName FROM BehaviorEffect WHERE effectID = ? AND effectType = ?); " ) ;
query . bind ( 1 , effectId ) ;
query . bind ( 2 , effectType_str . c_str ( ) ) ;
2021-12-05 17:54:36 +00:00
auto result = query . execQuery ( ) ;
2022-01-06 21:05:03 +00:00
if ( result . eof ( ) | | result . fieldIsNull ( 0 ) ) {
2021-12-05 17:54:36 +00:00
result . finalize ( ) ;
m_DurationCache [ effectId ] = 0 ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
effect - > time = 0 ; // Persistent effect
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
return ;
}
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
effect - > time = static_cast < float > ( result . getFloatField ( 0 ) ) ;
2022-01-06 21:05:03 +00:00
2021-12-05 17:54:36 +00:00
result . finalize ( ) ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
m_DurationCache [ effectId ] = effect - > time ;
}
void RenderComponent : : StopEffect ( const std : : string & name , const bool killImmediate ) {
GameMessages : : SendStopFXEffect ( m_Parent , killImmediate , name ) ;
RemoveEffect ( name ) ;
}
std : : vector < Effect * > & RenderComponent : : GetEffects ( ) {
return m_Effects ;
}
2023-03-20 13:10:52 +00:00
float RenderComponent : : PlayAnimation ( Entity * self , const std : : u16string & animation , float priority , float scale ) {
if ( ! self ) return 0.0f ;
return RenderComponent : : PlayAnimation ( self , GeneralUtils : : UTF16ToWTF8 ( animation ) , priority , scale ) ;
}
float RenderComponent : : PlayAnimation ( Entity * self , const std : : string & animation , float priority , float scale ) {
if ( ! self ) return 0.0f ;
return RenderComponent : : DoAnimation ( self , animation , true , priority , scale ) ;
}
float RenderComponent : : GetAnimationTime ( Entity * self , const std : : u16string & animation ) {
if ( ! self ) return 0.0f ;
return RenderComponent : : GetAnimationTime ( self , GeneralUtils : : UTF16ToWTF8 ( animation ) ) ;
}
float RenderComponent : : GetAnimationTime ( Entity * self , const std : : string & animation ) {
if ( ! self ) return 0.0f ;
return RenderComponent : : DoAnimation ( self , animation , false ) ;
}
float RenderComponent : : DoAnimation ( Entity * self , const std : : string & animation , bool sendAnimation , float priority , float scale ) {
2023-03-26 10:09:04 +00:00
float returnlength = 0.0f ;
if ( ! self ) return returnlength ;
2023-03-20 13:10:52 +00:00
auto * renderComponent = self - > GetComponent < RenderComponent > ( ) ;
2023-03-26 10:09:04 +00:00
if ( ! renderComponent ) return returnlength ;
2023-03-20 13:10:52 +00:00
auto * animationsTable = CDClientManager : : Instance ( ) . GetTable < CDAnimationsTable > ( ) ;
for ( auto & groupId : renderComponent - > m_animationGroupIds ) {
auto animationGroup = animationsTable - > GetAnimation ( animation , renderComponent - > GetLastAnimationName ( ) , groupId ) ;
if ( animationGroup . FoundData ( ) ) {
auto data = animationGroup . Data ( ) ;
renderComponent - > SetLastAnimationName ( data . animation_name ) ;
2023-03-26 10:09:04 +00:00
returnlength = data . animation_length ;
2023-03-20 13:10:52 +00:00
}
}
2023-03-26 10:09:04 +00:00
if ( sendAnimation ) GameMessages : : SendPlayAnimation ( self , GeneralUtils : : ASCIIToUTF16 ( animation ) , priority , scale ) ;
if ( returnlength = = 0.0f ) Game : : logger - > Log ( " RenderComponent " , " WARNING: Unable to find animation %s for lot %i in any group. " , animation . c_str ( ) , self - > GetLOT ( ) ) ;
return returnlength ;
2023-03-20 13:10:52 +00:00
}