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

323 lines
8.5 KiB
C++

#include "stdafx.h"
#include "SNpcResourceDB.h"
#include <Windows.h>
#include "KTypes.h"
#include <kfile/KStream.h>
#include <kfile/KFileManager.h>
#include <toolkit/XStringUtil.h>
#include "SkillBaseFile.h"
#include "ContentStruct.h"
#include "SStringDB.h"
#include "ItemBase.h"
#include "SDebug_Util.h"
extern HWND g_hWnd;
static std::vector< NpcEventPeriodResourceBase > s_vNpcEventPeriodInfo;
SNpcResourceDB* SNpcResourceDB::m_pThis = NULL;
SNpcResourceDB & GetNpcResourceDB()
{
if( NULL == SNpcResourceDB::m_pThis )
SNpcResourceDB::m_pThis = new SNpcResourceDB;
return *SNpcResourceDB::m_pThis;
// static SNpcResourceDB NpcResourceDB;
// return NpcResourceDB;
}
SNpcResourceDB::SNpcResourceDB() : m_hashNpcResource( 1 ), m_hashNpcEventPeriodResource( 1 )
{
Init();
}
SNpcResourceDB::~SNpcResourceDB()
{
Destroy();
}
void SNpcResourceDB::Init()
{
Load();
}
void SNpcResourceDB::Load()
{
// NPC Resource를 로딩할 때 국가별 이벤트 NPC 제어를 같이 하기 위해 EventPeriodResource도 로딩한다.
KStream * pRess = KFileManager::Instance().CreateStreamFromResource( "db_NPCEventPeriodResource.rdb" );
if( !pRess )
return;
KStream * pRes = KFileManager::Instance().CreateStreamFromResource( "db_NPCResource.rdb" );
if( !pRes )
{
KFileManager::Instance().DeleteStream( pRess );
return;
}
GAME_DB db_hdrs, db_hdr;
pRess->Read( &db_hdrs, sizeof(db_hdrs) );
pRes->Read( &db_hdr, sizeof(db_hdr) );
#ifdef _DEV_RDB_
// RDB 와 Header의 사이즈 비교.
int fileSize = pRes->Size() - ( STR_DATE_BUFFER + sizeof( int ) );
int headerSize = sizeof(NpcResourceBase) * db_hdr.nCount;
if( fileSize != headerSize )
{
char str[512] = { NULL, };
sprintf( str, "*** RDB Error !!! ***\n\n생성날짜%s\n파일:%s\n파일사이즈:%d\n헤더사이즈:%d\n ",
db_hdr.szDate,
__FILE__,
fileSize,
headerSize
);
::MessageBox( g_hWnd, str, "Error", MB_OK );
if( ::MessageBox( g_hWnd, "RDB와 클라이언트가 맞지않습니다. 강제종료하시겠습니까?", "Error", MB_YESNO ) == IDYES )
{
exit( 1 );
}
}
#endif
for( int i(0); db_hdrs.nCount>i; i++ )
{
NpcEventPeriodResourceBase *pResource = new NpcEventPeriodResourceBase;
pRess->Read( pResource, sizeof( NpcEventPeriodResourceBase ) );
if( !( pResource->local_flag & GameRule::GetCurrentLocalBitSet() ) )
{
delete pResource;
continue;
}
NpcEventPeriodResourceBase *pFindNpc = NULL;
if( m_hashNpcEventPeriodResource.lookup( pResource->id, pFindNpc ) == false )
{
m_hashNpcEventPeriodResource.add( pResource->id, pResource );
}
else
{
_oprint( "!!!!Data Error NpcEventPeriodResource Code 가 중복되었습니다.!!!! \n" );
assert(0); //기획팀에 알려 주세여. 바로 수정 해야 합니다.
delete pResource;
}
}
for( int i(0); db_hdr.nCount>i; i++ )
{
NpcResourceClient * pItem = new NpcResourceClient;
memset( pItem, 0, sizeof(NpcResourceBase) );
pRes->Read( pItem, sizeof(NpcResourceBase) );
// 끝난 기간 Npc면 로딩조차 안할거임. 또한 hashNpcEventPeriodResource에 로컬 플래그가 만족되면 NpcResource의 로컬 플래그는 무시.
bool bNoUseLocalFlag = false;
NpcEventPeriodResourceBase *pFindNpc = NULL;
if( m_hashNpcEventPeriodResource.lookup( pItem->id, pFindNpc ) == true )
{
time_t nowtime;
time(&nowtime);
/*if( pFindNpc->end_of_period < nowtime )
{
if( m_hashNpcEventPeriodResource.erase( pItem->id ) )
delete pFindNpc;
delete pItem;
continue;
}*/ // 클라에서 시간 체크 제거
bNoUseLocalFlag = true;
}
// NPC 제외 국가 플래그에 의한 필터링, 단 EventPeriodResource에 ID가 있다면 필터링 안 함
if( ( pItem->local_flag & GameRule::GetCurrentLocalBitSet() ) && !bNoUseLocalFlag )
{
delete pItem;
continue;
}
pItem->real_uid = pItem->id;
pItem->id = XFastRandom();
NpcResourceClient* pFindItem = NULL;
// _oprint( "SNpcResourceDB : NPC ID : %d\n", pItem->id );
if( m_hashNpcResource.lookup( pItem->real_uid, pFindItem ) == false )
{
m_hashNpcResource.add( pItem->real_uid, pItem );
}
else
{
_oprint( "Data Error: NpcResource Code is duplicated: %i\n", (int)pItem->id ); // Fraun adjusting logs
assert(0); // Please inform the planning team. It needs to be fixed immediately.
delete pItem;
}
}
KFileManager::Instance().DeleteStream( pRes );
KFileManager::Instance().DeleteStream( pRess );
}
void SNpcResourceDB::Destroy()
{
NpcResourceClient* pItem = NULL;
bool res = false;
res = m_hashNpcResource.get_first_value( pItem );
while ( res )
{
if ( pItem != NULL )
{
delete pItem;
}
res = m_hashNpcResource.get_next_value( pItem );
}
m_hashNpcResource.clear();
NpcEventPeriodResourceBase* pRes = NULL;
res = false;
res = m_hashNpcEventPeriodResource.get_first_value( pRes );
while ( res )
{
if ( pRes != NULL )
{
delete pRes;
}
res = m_hashNpcEventPeriodResource.get_next_value( pRes );
}
m_hashNpcEventPeriodResource.clear();
}
void SNpcResourceDB::EnumNPC( std::vector< NPCRenderInfo > * pList )
{
NpcResourceClient* pNPCInfo = NULL;
bool res;
res = m_hashNpcResource.get_first_value( pNPCInfo );
while ( res )
{
std::string strNPCName = GetStringDB().GetString( pNPCInfo->text_id );
strNPCName += " ";
strNPCName += GetStringDB().GetString( pNPCInfo->name_text_id );
bool bIsPeriodic = false;
int nBeginPeriod = 0, nEndPeriod = 0;
NpcEventPeriodResourceBase *pFindNPCPeriod = NULL;
if( m_hashNpcEventPeriodResource.lookup( pNPCInfo->real_uid, pFindNPCPeriod ) )
{
bIsPeriodic = true;
nBeginPeriod = pFindNPCPeriod->begin_of_period;
nEndPeriod = pFindNPCPeriod->end_of_period;
}
// 나중에 뚫린다면...이녀석 때문일까....ㅠ.ㅠ 고칠 엄두가 안난다....ㅠㅠ by P.Lotos
pList->push_back( SNpcResourceDB::NPCRenderInfo( pNPCInfo->real_uid, strNPCName.c_str(), pNPCInfo->x, pNPCInfo->y, bIsPeriodic, nBeginPeriod, nEndPeriod, pNPCInfo->type ) );
res = m_hashNpcResource.get_next_value( pNPCInfo );
}
}
vector<NPCIDENTITYFORDEV> SNpcResourceDB::GetNpcIdentityList( string strFindNpcName )
{
vector<NPCIDENTITYFORDEV> vecNpcIdentity;
#ifdef _DEV
KHash< struct NpcResourceClient*, hashPr_mod_ENC_INT>::node* _node = NULL;
bool bResult = m_hashNpcResource.get_first_node( _node );
while ( bResult )
{
NpcResourceClient* pNpc( _node->value );
if( pNpc )
{
string strNpcName( S( pNpc->name_text_id ) );
size_t found = strNpcName.find( strFindNpcName );
if (found != string::npos)
{
NPCIDENTITYFORDEV stNpcIdentityForDev;
stNpcIdentityForDev.m_uNpcID = pNpc->real_uid.value();
stNpcIdentityForDev.m_strNpcName = strNpcName;
vecNpcIdentity.push_back( stNpcIdentityForDev );
}
}
bResult = m_hashNpcResource.get_next_node( _node );
}
#endif
return vecNpcIdentity;
}
int SNpcResourceDB::GetNpcItemCode( int nWearType, NpcResourceBase* pNpcResource )
{
if( pNpcResource == NULL )
{
// if( !m_hashNpcResource.lookup( nWearType, pNpcResource ) )
// {
return 0;
// }
}
/* WEAR_WEAPON = 0, // 오른손전용 (방패라던가)
WEAR_SHIELD = 1, // 왼손전용
WEAR_ARMOR = 2, // 갑옷
WEAR_HELM = 3, // 투구
WEAR_GLOVE = 4, // 장갑
WEAR_BOOTS = 5, // 부츠
WEAR_BELT = 6, // 벨트
WEAR_MANTLE = 7, // 망토
WEAR_ARMULET = 8, // 목걸이
WEAR_RING = 9, // 반지
// 10 은 반지 두번째 슬롯을 위해 예약
WEAR_EAR = 11, // 귀걸이
WEAR_EYE = 12, // 눈
WEAR_DECO_HAIR = 13, // 입
WEAR_EAR_EYE = 90, // 귀+눈
WEAR_EAR_MOUTH = 91, // 귀+입
WEAR_EYE_MOUTH = 92, // 눈+입
WEAR_EYE_EAR_MOUTH = 93, // 눈+귀+입
WEAR_TWOFINGER_RING = 94, // 반지 두칸 소모
WEAR_TWOHAND = 99, // 투핸드
WEAR_SKILL = 100, // 스킬*/
switch( nWearType )
{
case ItemBase::WEAR_WEAPON: return pNpcResource->weapon_item_id;
case ItemBase::WEAR_SHIELD: return pNpcResource->shield_item_id;
case ItemBase::WEAR_ARMOR: return pNpcResource->body_id;
//의상? 이건 뭐지
//case ItemBase:: return pNpcResource->clothes_item_id;
case ItemBase::WEAR_HELM: return pNpcResource->helm_item_id;
case ItemBase::WEAR_GLOVE: return pNpcResource->gloves_item_id;
case ItemBase::WEAR_BOOTS: return pNpcResource->boots_item_id;
case ItemBase::WEAR_BELT: return pNpcResource->belt_item_id;
case ItemBase::WEAR_MANTLE: return pNpcResource->mantle_item_id;
case ItemBase::WEAR_ARMULET: return pNpcResource->necklace_item_id;
case ItemBase::WEAR_EAR: return pNpcResource->earring_item_id;
case ItemBase::WEAR_RING: return pNpcResource->ring1_item_id;
//링2
case 10: return pNpcResource->ring2_item_id;
}
return 0;
}