Files
Leviathan/Server/GameServer/CaptainHerlockServer.cpp
2026-06-01 12:46:52 +02:00

1762 lines
78 KiB
C++

#include <process.h>
#include <network/IAcceptor.h>
#include <network/IConnection.h>
#include <framework/ArcadiaFramework.h>
#include <mmo/ArcadiaServer.h>
#include <mmo/ArTime.h>
#include <logging/FileLog.h>
#include <toolkit/XBossWorker.h>
#include <toolkit/XConsole.h>
#include <toolkit/XEnv.h>
#include <toolkit/XModuleInfo.h>
#include <dump/XExceptionHandler.h>
#include <toolkit/XRandom.h>
#include <toolkit/XStringUtil.h>
#include <network/XNetworkUtil.h>
#include "LogClient/LogClient.h"
#include "LuaVM.h"
#include "ScriptNPC.h"
#include "ScriptItem.h"
#include "ScriptMisc.h"
#include "ScriptCommon.h"
#include "ScriptPlayer.h"
#include "ScriptGuild.h"
#include "ScriptQuest.h"
#include "StructPlayer.h"
#include "StructSummon.h"
#include "StructMonster.h"
#include "StructItem.h"
#include "AuctionManager.h"
#include "DungeonManager.h"
#include "FieldPropManager.h"
#include "ScheduledCommandManager.h"
#include "StructEventItemManager.h"
#include "RoamingManager.h"
#include "HuntaholicManager.h"
#include "CompeteManager.h"
#include "RankingManager.h"
#include "InstanceDungeonManager.h"
#include "BattleArenaManager.h"
#include "GameNetwork.h"
#include "CommunityLoader.h"
#include "ContentLoader.h"
#include "LocationLoader.h"
#include "GameAllocator.h"
#include "DBAllocator.h"
#include "SendMessage.h"
#include "XSecuritySolutionManager.h"
#include "DBPerformanceTracker.h"
#include "SchedulingPerformanceTracker.h"
#include "NetworkReceiverPerformanceTracker.h"
#include "ADOConnection.h"
#include <external_lib_include.h>
#include <internal_lib_all_include.h>
__declspec( thread ) XSEH::THREAD_INFO s_ThreadInfo;
volatile bool g_bPerformanceTracing = true;
volatile DWORD g_nIntervalTimeToLogPerformance = 10000; // default: 10초마다 기록
bool b_performanceUpdate;
unsigned __stdcall performanceLogFunc( void* );
void WriteHeapUsageInfo( HANDLE hFile )
{
DWORD dwWritten = 0;
std::string strMemoryPoolSize;
XStringUtil::Format( strMemoryPoolSize, "PlayerHeapSize : %d kb\r\n", GetPlayerHeapSize() );
WriteFile( hFile, strMemoryPoolSize.c_str(), static_cast< DWORD >( strMemoryPoolSize.length() ), &dwWritten, NULL );
XStringUtil::Format( strMemoryPoolSize, "MonsterHeapSize : %d kb\r\n", GetMonsterHeapSize() );
WriteFile( hFile, strMemoryPoolSize.c_str(), static_cast< DWORD >( strMemoryPoolSize.length() ), &dwWritten, NULL );
XStringUtil::Format( strMemoryPoolSize, "ItemHeapSize : %d kb\r\n", GetItemHeapSize() );
WriteFile( hFile, strMemoryPoolSize.c_str(), static_cast< DWORD >( strMemoryPoolSize.length() ), &dwWritten, NULL );
XStringUtil::Format( strMemoryPoolSize, "SummonHeapSize : %d kb\r\n", GetSummonHeapSize() );
WriteFile( hFile, strMemoryPoolSize.c_str(), static_cast< DWORD >( strMemoryPoolSize.length() ), &dwWritten, NULL );
XStringUtil::Format( strMemoryPoolSize, "PetHeapSize : %d kb\r\n", GetPetHeapSize() );
WriteFile( hFile, strMemoryPoolSize.c_str(), static_cast< DWORD >( strMemoryPoolSize.length() ), &dwWritten, NULL );
XStringUtil::Format( strMemoryPoolSize, "SkillHeapSize : %d kb\r\n", GetSkillHeapSize() );
WriteFile( hFile, strMemoryPoolSize.c_str(), static_cast< DWORD >( strMemoryPoolSize.length() ), &dwWritten, NULL );
XStringUtil::Format( strMemoryPoolSize, "QuestHeapSize : %d kb\r\n", GetQuestHeapSize() );
WriteFile( hFile, strMemoryPoolSize.c_str(), static_cast< DWORD >( strMemoryPoolSize.length() ), &dwWritten, NULL );
XStringUtil::Format( strMemoryPoolSize, "TitleHeapSize : %d kb\r\n", GetTitleHeapSize() );
WriteFile( hFile, strMemoryPoolSize.c_str(), static_cast< DWORD >( strMemoryPoolSize.length() ), &dwWritten, NULL );
XStringUtil::Format( strMemoryPoolSize, "TitleConditionHeapSize: %d kb\r\n", GetTitleConditionHeapSize() );
WriteFile( hFile, strMemoryPoolSize.c_str(), static_cast< DWORD >( strMemoryPoolSize.length() ), &dwWritten, NULL );
XStringUtil::Format( strMemoryPoolSize, "ProcHeapSize : %d kb\r\n", GetProcHeapSize() );
WriteFile( hFile, strMemoryPoolSize.c_str(), static_cast< DWORD >( strMemoryPoolSize.length() ), &dwWritten, NULL );
XStringUtil::Format( strMemoryPoolSize, "DBHeapSize : %d kb\r\n\r\n", GetDBHeap().GetAllocSize() >> 10 );
WriteFile( hFile, strMemoryPoolSize.c_str(), static_cast< DWORD >( strMemoryPoolSize.length() ), &dwWritten, NULL );
}
void WINAPI CaptainHerlockExceptionFilter( HANDLE hFile )
{
g_DBTracker.dump();
std::string strVersionInfo;
DWORD dwWritten;
XModuleInfo cModuleInfo;
cModuleInfo.Load( ::GetCurrentProcess() );
char szMyVersion[64] = "";
const WORD* pFileVerion = cModuleInfo.FileVersion();
s_sprintf( szMyVersion, _countof( szMyVersion ), "%d.%d.%d.%d", pFileVerion[0], pFileVerion[1], pFileVerion[2], pFileVerion[3] );
XStringUtil::Format( strVersionInfo, "Server Version : v%s\r\n", szMyVersion );
WriteFile( hFile, strVersionInfo.c_str(), static_cast< DWORD >( strVersionInfo.length() ), &dwWritten, NULL );
WriteHeapUsageInfo( hFile );
}
volatile int g_bUseLockDelayLogging = 0;
struct _HerlockIntf : ArcadiaFrameworkIntf
{
bool onInit( HWND hWnd );
bool onMessage( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
bool onKeyDown( int nVkCode );
bool onCommand( const char* szTarget,
const char* szFrom,
const char *szFullCmd,
std::vector< std::string > & vList,
ArcadiaCommandResultReceiver & receiver );
bool onDeInit();
void onDrawUser( HDC dc );
} myFrameworkIntf;
unsigned __stdcall initFunc( void* )
{
XSetThreadName( -1, "GameLoader" );
CoInitialize(NULL);
InitGameHeap();
InitDBHeap();
XSEH::SetUserFunc( CaptainHerlockExceptionFilter );
StructItem::InitItemSystem();
StructCreature::InitCreatureSystem();
XBossWorker worker;
void InitArcadia();
InitArcadia();
void LoadResource();
LoadResource();
ResourceManager::Init();
MonsterLoader monster_loader;
PetLoader pet_loader;
ItemLoader item_loader;
EventAreaHandlerLoader event_area_loader;
MapLoader map_loader;
SkillLoader skill_loader;
StringLoader string_loader;
MixLoader mix_loader;
BitmapLoader bitmap_loader;
PartyLoader party_loader;
GuildLoader guild_loader;
ETCLoader etc_loader;
QuestLoader quest_loader;
LocationLoader location_loader;
NPCLoader npc_loader;
ChannelLoader channel_loader;
FieldPropLoader prop_loader;
FieldPropSwitchingLoader prop_switching_loader;
FieldPropDataLoader prop_data_loader;
DungeonLoader dungeon_loader;
ScheduledCommandLoader scheduled_command_loader;
AuctionCategoryLoader auction_category_loader;
AutoAuctionLoader auto_auction_loader;
AutoAuctionRegistrationInfoLoader auto_auction_reg_info_loader;
AuctionLoader auction_loader;
RoamingLoader roaming_loader;
HuntaholicLoader huntaholic_loader;
RankingLoader ranking_loader;
DeathmatchLoader deathmatch_loader;
CreatureEnhanceLoader creature_enhance_loader;
CreatureFarmLoader creature_farm_loader;
InstanceDungeonLoader instance_dungeon_loader;
TitleLoader title_loader;
BattleArenaLoader battle_arena_loader;
AwakenLoader awaken_loader;
RandomItemLoader random_item_loader;
void thread_com_init_func( int nThreadNum );
// 워커 쓰레드 생성
worker.StartThread( "GameLoader", 4, THREAD_PRIORITY_NORMAL, thread_com_init_func );
// 스트링 테이블은 미리 읽어야함
string_loader.onProcess( 0 );
worker.Push( &skill_loader );
worker.Push( &item_loader );
worker.Push( &auction_category_loader );
worker.Push( &event_area_loader );
while( ( worker.GetActiveThreadCount() + worker.GetWaitingWorkCount() ) ) Sleep( 50 );
worker.Push( &monster_loader ); // skill_loader 완료 필요
worker.Push( &bitmap_loader );
worker.Push( &map_loader );
worker.Push( &auto_auction_loader ); // auction_category_loader 완료 필요
while( ( worker.GetActiveThreadCount() + worker.GetWaitingWorkCount() ) ) Sleep( 50 );
worker.Push( &etc_loader ); // skill_loader 완료 필요
worker.Push( &quest_loader );
worker.Push( &location_loader );
worker.Push( &auto_auction_reg_info_loader ); // auto_auction_loader 완료 필요
while( ( worker.GetActiveThreadCount() + worker.GetWaitingWorkCount() ) ) Sleep( 50 );
worker.Push( &guild_loader );
worker.Push( &channel_loader ); // map_loader 완료 필요
worker.Push( &dungeon_loader ); // map_loader 완료 필요
worker.Push( &mix_loader );
while( ( worker.GetActiveThreadCount() + worker.GetWaitingWorkCount() ) ) Sleep( 50 );
worker.Push( &prop_loader ); // channel_loader 완료 필요
worker.Push( &roaming_loader ); // channel_loader 완료 필요
worker.Push( &prop_switching_loader );
worker.Push( &creature_enhance_loader );
while( ( worker.GetActiveThreadCount() + worker.GetWaitingWorkCount() ) ) Sleep( 50 );
worker.Push( &party_loader );
worker.Push( &prop_data_loader ); // prop_loader, prop_switching_loader 완료 필요
worker.Push( &pet_loader );
while( ( worker.GetActiveThreadCount() + worker.GetWaitingWorkCount() ) ) Sleep( 50 );
worker.Push( &auction_loader ); // auction_category_loader, item_loader, skill_loader, state_loader, etc_loader(소환수 로딩 관련 스텟 정보 및 소환수 강화 정보 필요), pet loader, monster_loader 완료 필요
worker.Push( &scheduled_command_loader );
worker.Push( &npc_loader ); // string_loader, channel_loader, roaming_loader 완료 필요
worker.Push( &huntaholic_loader ); // channel_loader 완료 필요
while( ( worker.GetActiveThreadCount() + worker.GetWaitingWorkCount() ) ) Sleep( 50 );
worker.Push( &ranking_loader );
worker.Push( &deathmatch_loader );
worker.Push( &creature_farm_loader );
worker.Push( &instance_dungeon_loader );
while( ( worker.GetActiveThreadCount() + worker.GetWaitingWorkCount() ) ) Sleep( 50 );
worker.Push( &title_loader );
worker.Push( &battle_arena_loader );
worker.Push( &awaken_loader );
worker.Push( &random_item_loader );
while( ( worker.GetActiveThreadCount() + worker.GetWaitingWorkCount() ) ) Sleep( 50 );
// prop_data_loader의 로딩까지 완료된 후에 동작 시작해야 함
FieldPropManager::GetInstance().Init();
StructEventItemManager::GetInstance().Init(); // 이벤트 아이템 매니저도 로딩 함 해주고~
// 스크립트 로드
GameContent::LoadScript();
// 리스폰 정보 처리
map_loader.InitMapInfo();
// Call a first script on server initialization
LUA()->RunString( "on_server_init()" );
while( ( worker.GetActiveThreadCount() + worker.GetWaitingWorkCount() ) ) Sleep( 50 );
GameContent::AddNPCToWorld();
GameContent::AddRespawnObjectToWorld();
worker.EndThread();
ENV().Set( "game.loading", "complete" );
DungeonManager::Instance().Init();
AuctionManager::Instance().Init(); // AutoAuctionRegistrationInfoLoader 완료 전에는 호출되면 안 됨
RoamingManager::Instance().Init();
HuntaholicManager::Instance().Init();
BattleArenaManager::Instance().Init();
CompeteManager::Instance().Init();
RankingManager::Instance().Init();
InstanceDungeonManager::Instance().Init();
ArcadiaServer::Instance().SetObjectPriority( &g_DBTracker, ArSchedulerObject::UPDATE_PRIORITY_NORMAL );
InitMessageLogger();
return 0;
}
void InitDefaultEnv()
{
XModuleInfo cModuleInfo;
cModuleInfo.Load( ::GetCurrentProcess() );
char szMyVersion[64] = "";
const WORD* pFileVerion = cModuleInfo.FileVersion();
s_sprintf( szMyVersion, _countof( szMyVersion ), "%d.%d.%d.%d", pFileVerion[0], pFileVerion[1], pFileVerion[2], pFileVerion[3] );
ENV().Set( "game.server_version", szMyVersion );
ENV().SetReadOnly( "game.server_version" );
ENV().SetDefaultValue( "db.user.name", "Telecaster" );
ENV().SetDefaultValue( "db.user.server", "127.0.0.1" ); // Fraun changed cadb.nflavor.com to 127.0.0.1 to avoid leaks to galalab 8/16/2025
ENV().SetDefaultValue( "db.user.thread_total", 4 ),
ENV().SetDefaultValue( "db.user.account", "sa" );
ENV().SetDefaultValue( "db.user._password", "" );
ENV().SetDefaultValue( "db.c.name", "Arcadia" );
ENV().SetDefaultValue( "db.c.server", "127.0.0.1" ); // Fraun changed cadb.nflavor.com to 127.0.0.1 to avoid leaks to galalab 8/16/2025
ENV().SetDefaultValue( "db.c.account", "sa" );
ENV().SetDefaultValue( "db.c._password", "" );
ENV().Bind( "game.battle_arena_reconnect_wait_duration", (int*)&GameRule::nBattleArenaReconnectWaitDuration );
ENV().Bind( "game.mod", &GameRule::fPlyMod );
ENV().Bind( "game.user_count", (int*)&StructPlayer::GetPlayerCount() );
ENV().Bind( "game.party_exp_penalty_level", &GameRule::nPartyExpPenaltyLevel );
ENV().Bind( "game.party_exp_rate_0", &GameRule::fPartyEXPRate[ 0 ] );
ENV().Bind( "game.party_exp_rate_1", &GameRule::fPartyEXPRate[ 1 ] );
ENV().Bind( "game.party_exp_rate_2", &GameRule::fPartyEXPRate[ 2 ] );
ENV().Bind( "game.party_exp_rate_3", &GameRule::fPartyEXPRate[ 3 ] );
ENV().Bind( "game.party_exp_rate_4", &GameRule::fPartyEXPRate[ 4 ] );
ENV().Bind( "game.party_exp_rate_5", &GameRule::fPartyEXPRate[ 5 ] );
ENV().Bind( "game.party_exp_rate_6", &GameRule::fPartyEXPRate[ 6 ] );
ENV().Bind( "game.card_drop_rate", &GameRule::fCardDropRate );
ENV().Bind( "game.item_drop_rate", &GameRule::fItemDropRate );
ENV().Bind( "game.no_collision_check", &GameRule::bIsNoCollisionCheck );
ENV().Bind( "game.skip_loading_attribute", &GameRule::bSkipLoadingAttribute );
ENV().Bind( "game.gold_drop_rate", &GameRule::fGoldDropRate );
ENV().Bind( "game.min_speed", &GameRule::nMinSpeed);
ENV().Bind( "game.item_hold_time", &GameRule::nItemHoldTime);
ENV().Bind( "game.chaos_drop_rate", &GameRule::fChaosDropRate );
ENV().Bind( "game.exp_rate", &GameRule::fEXPRate );
ENV().Bind( "game.pvp_damage_rate_for_player", &GameRule::fPVPDamageRateForPlayer );
ENV().Bind( "game.pvp_damage_rate_for_summon", &GameRule::fPVPDamageRateForSummon );
ENV().Bind( "game.evp_boss_damage_rate", &GameRule::fEVPBossDamageRate);
ENV().Bind( "game.evs_boss_damage_rate", &GameRule::fEVSBossDamageRate);
ENV().Bind( "game.evp_damage_rate", &GameRule::fEVPDamageRate);
ENV().Bind( "game.evs_damage_rate", &GameRule::fEVSDamageRate);
ENV().Bind( "game.stamina_bonus_rate", &GameRule::fStaminaBonusRate );
ENV().Bind( "game.stamina_consume_rate", &GameRule::fStaminaConsumeRate );
ENV().Bind( "game.stamina_regen_rate", &GameRule::fStaminaRegenRate );
ENV().Bind( "game.super_save_bonus_rate", &GameRule::fSuperSaveBonusRate );
ENV().Bind( "game.super_save_level_min_limit_0", &GameRule::anSuperSaveLevelMinLimit[ 0 ] );
ENV().Bind( "game.super_save_level_min_limit_1", &GameRule::anSuperSaveLevelMinLimit[ 1 ] );
ENV().Bind( "game.super_save_level_min_limit_2", &GameRule::anSuperSaveLevelMinLimit[ 2 ] );
ENV().Bind( "game.super_save_level_min_limit_3", &GameRule::anSuperSaveLevelMinLimit[ 3 ] );
ENV().Bind( "game.super_save_level_min_limit_4", &GameRule::anSuperSaveLevelMinLimit[ 4 ] );
ENV().Bind( "game.super_save_level_min_limit_5", &GameRule::anSuperSaveLevelMinLimit[ 5 ] );
ENV().Bind( "game.super_save_level_min_limit_6", &GameRule::anSuperSaveLevelMinLimit[ 6 ] );
ENV().Bind( "game.super_save_level_max_limit_0", &GameRule::anSuperSaveLevelMaxLimit[ 0 ] );
ENV().Bind( "game.super_save_level_max_limit_1", &GameRule::anSuperSaveLevelMaxLimit[ 1 ] );
ENV().Bind( "game.super_save_level_max_limit_2", &GameRule::anSuperSaveLevelMaxLimit[ 2 ] );
ENV().Bind( "game.super_save_level_max_limit_3", &GameRule::anSuperSaveLevelMaxLimit[ 3 ] );
ENV().Bind( "game.super_save_level_max_limit_4", &GameRule::anSuperSaveLevelMaxLimit[ 4 ] );
ENV().Bind( "game.super_save_level_max_limit_5", &GameRule::anSuperSaveLevelMaxLimit[ 5 ] );
ENV().Bind( "game.super_save_level_max_limit_6", &GameRule::anSuperSaveLevelMaxLimit[ 6 ] );
ENV().Bind( "game.ally_pcbang_bonus_rate", &GameRule::fAllyPCBangBonusRate );
ENV().Bind( "game.ally_pcbang_chaos_bonus_rate", &GameRule::fAllyPCBangChaosBonusRate );
ENV().Bind( "game.premium_pcbang_bonus_rate", &GameRule::fPremiumPCBangBonusRate );
ENV().Bind( "game.premium_pcbang_chaos_bonus_rate", &GameRule::fPremiumPCBangChaosBonusRate );
ENV().Bind( "game.premium_pcbang_gold_bonus_drop_rate", &GameRule::fPremiumPCBangGoldBonusDropRate );
ENV().Bind( "game.premium_pcbang_item_bonus_drop_rate", &GameRule::fPremiumPCBangItemBonusDropRate );
ENV().Bind( "game.premium_pcbang_chaos_bonus_drop_rate", &GameRule::fPremiumPCBangChaosBonusDropRate );
ENV().Bind( "game.apply_stamina_bonus_in_premium_pcbang", &GameRule::bApplyStaminaBonusInPremiumPCBang );
ENV().Bind( "game.use_play_point", &GameRule::bUsePlayPoint );
ENV().Bind( "game.play_point_accumulate_term", &GameRule::nPlayPointAccumulateTerm );
ENV().Bind( "game.play_point_accumulate_amount", &GameRule::nPlayPointAccumulateAmount );
ENV().Bind( "game.premium_pcbang_play_point_bonus_rate", &GameRule::fPremiumPCBangPlayPointBonusRate );
ENV().Bind( "game.use_time_based_event_script", &GameRule::bUseTimeBasedEventScript );
ENV().Bind( "game.use_time_based_event_db", &GameRule::bUseTimeBasedEventDB );
ENV().Bind( "game.term_for_time_based_event_script", &GameRule::nTermForTimeBasedEventScript );
ENV().Bind( "game.term_for_time_based_event_db", &GameRule::nTermForTimeBasedEventDB );
ENV().Bind( "game.monster_wandering", &GameRule::bMonsterWandering );
ENV().Bind( "game.monster_collision_line", &GameRule::bMonsterCollisionToLine );
ENV().Bind( "game.monster_pathfinding", &GameRule::bMonsterPathFinding );
ENV().Bind( "game.log_monster_pathfinding", &GameRule::bLogMonsterPathFinding );
extern volatile LONG g_nMobLineCount;
extern volatile LONG g_nMobPathFindingCount;
extern volatile LONG g_nMobFindDuplicatePos;
extern volatile LONG g_nMobRandomMove;
extern volatile LONG g_nMobFirstLineCount;
ENV().Bind( "game.LineCount", (int*) &g_nMobLineCount );
ENV().Bind( "game.PathFindingCount", (int*) &g_nMobPathFindingCount );
ENV().Bind( "game.FindDuplicatePos", (int*) &g_nMobFindDuplicatePos );
ENV().Bind( "game.RandomMove", (int*) &g_nMobRandomMove );
ENV().Bind( "game.FirstLineCount", (int*) &g_nMobFirstLineCount );
ENV().Bind( "game.TracingGamePerformance", (bool*) &g_bPerformanceTracing );
ENV().Bind( "game.GamePerformanceLogingInterval", (int*) &g_nIntervalTimeToLogPerformance );
ENV().Bind( "game.log_scheduling_status", &GameRule::bLogSchedulingStatus );
ENV().Bind( "game.ProcessingPlayerCount", (int*) &g_PlayerPerformanceTracker.m_count );
ENV().Bind( "game.ProcessingSummonCount", (int*) &g_SummonPerformanceTracker.m_count );
ENV().Bind( "game.ProcessingMonsterCount", (int*) &g_MonsterPerformanceTracker.m_count );
ENV().Bind( "game.ProcessingPlayerTime", (int*) &g_PlayerPerformanceTracker.m_totalTime );
ENV().Bind( "game.ProcessingSummonTime", (int*) &g_SummonPerformanceTracker.m_totalTime );
ENV().Bind( "game.ProcessingMonsterTime", (int*) &g_MonsterPerformanceTracker.m_totalTime );
ENV().Bind( "game.no_skill_cooltime", &GameRule::bIgnoreSkillCoolTime );
ENV().Bind( "game.PKServer", &GameRule::bIsPKServer );
ENV().Bind( "game.PKPenaltyLevel", &GameRule::nPKPenaltyLevel );
ENV().Bind( "game.disable_pk_on", &GameRule::bDisablePKOn );
ENV().Bind( "game.AdultServer", &GameRule::bIsAdultServer );
ENV().Bind( "game.restrict_special_char", &GameRule::bRestrictSpeicialChar );
ENV().Bind( "game.allowed_special_char", &GameRule::strAllowedSpecialChar );
ENV().Bind( "game.AutoOpenOnly", &GameRule::bAutoOpen );
ENV().Bind( "game.disable_huntaholic", &GameRule::bDisableHuntaholic );
ENV().Bind( "game.use_auto_jail", &GameRule::bUseAutoJail );
ENV().Bind( "game.security_solution_type", &GameRule::nSecuritySolutionType );
ENV().Bind( "game.period_of_security_solution_check", (int *)&GameRule::nPeriodOfSecuritySolutionCheck );
ENV().Bind( "game.security_solution_response_timeout", (int *)&GameRule::nSecuritySolutionResponseTimeout );
ENV().Bind( "game.security_solution_exceptional_ip", &GameRule::strSecuritySolutionExceptionalIP );
ENV().Bind( "game.disable_dungeon_raid_siege", &GameRule::bDisableDungeonRaidSiege );
ENV().Bind( "game.cash_usable_server", &GameRule::bIsCashUsableServer );
ENV().Bind( "game.use_account_authority_db", &GameRule::bUseAccountAuthorityDB );
ENV().Bind( "game.cash_item_dropable", &GameRule::bCashItemDropable );
ENV().Bind( "game.use_auto_trap", &GameRule::bUseAutoTrap );
ENV().Bind( "game.max_level", &GameRule::nMaxLevel );
ENV().Bind( "game.max_creature_level", &GameRule::nMaxCreatureLevel);
ENV().Bind( "game.base_ethereal_durability_consumption_on_normal_attack", &GameRule::nEtherealDurabilityBaseConsumptionOnNormalAttack );
ENV().Bind( "game.base_ethereal_durability_consumption_on_skill_attack", &GameRule::nEtherealDurabilityBaseConsumptionOnSkillAttack );
ENV().Bind( "game.base_ethereal_durability_consumption_on_damage", &GameRule::nEtherealDurabilityBaseConsumptionOnDamage );
ENV().Bind( "game.base_ethereal_durability_consumption_rate", &GameRule::nEtherealDurabilityConsumptionRate );
ENV().Bind( "game.broadcast_event_item_pickup", &GameRule::bBroadcastEventItemPickup );
ENV().Bind( "game.use_guild_donation_point", &GameRule::bUseGuildDonationPoint );
ENV().Bind( "game.restrict_banword_for_booth", &GameRule::bRestrictBanWordForBooth );
ENV().Bind( "game.min_booth_startable_level", &GameRule::nMinBoothStartableLevel );
ENV().Bind( "game.limit_booth_openable_layer_to_zero", &GameRule::bLimitBoothOpenableLayerToZero );
ENV().Bind( "game.disable_buy_booth", &GameRule::bDisableBuyBooth );
ENV().Bind( "game.disable_booth", &GameRule::bDisableBooth );
ENV().Bind( "game.disable_trade", &GameRule::bDisableTrade );
ENV().Bind( "game.limit_adv_chat_count", &GameRule::bLimitAdvChatCount );
ENV().Bind( "game.min_global_chat_usable_level", &GameRule::nMinGlobalChatUsableLevel );
ENV().Bind( "game.max_storage_item_count", &GameRule::nMaxStorageItemCount );
ENV().Bind( "game.max_characters_per_account", &GameRule::nMaxCharactersPerAccount );
ENV().Bind( "game.auction_search_request_min_interval", (int *)&GameRule::nAuctionSearchRequestMinInterval );
ENV().Bind( "game.auction_process_request_min_interval", (int *)&GameRule::nAuctionProcessRequestMinInterval );
ENV().Bind( "game.use_security", &GameRule::bUseSecurityNo );
ENV().Bind( "game.use_storage_security", &GameRule::bUseSecurityNoForStorage );
ENV().Bind( "game.use_delete_security", &GameRule::bUseSecurityNoForDeletingCharacter );
ENV().Bind( "game.check_storage_security_always", &GameRule::bCheckStorageSecurityAlways );
ENV().Bind( "game.limit_field_logout", &GameRule::bLimitFieldLogout );
ENV().Bind( "game.logout_timer", (int *)&GameRule::nLogoutTimer );
ENV().Bind( "game.force_unregister_account_on_kick_fail", &GameRule::bForceUnregisterAccountOnKickFail );
ENV().Bind( "game.forbidden_script_init", &GameRule::bForbiddenScriptInitialized );
ENV().Bind( "game.forbidden_script", &GameRule::strForbiddenScript );
ENV().Bind( "game.use_login_logout_debug", &GameRule::bUseLoginLogoutDebug );
ENV().Bind( "game.log_vulcanus_dungeon", &GameRule::bLogVulcanusDungeon );
ENV().Bind( "game.limit_game_time" , &GameRule::bLimitGameTime );
ENV().Bind( "game.max_game_time_limited_age" , &GameRule::nMaxGameTimeLimitedAge );
ENV().Bind( "game.max_healthy_game_time" , (int *)&GameRule::nMaxHealthyGameTime );
ENV().Bind( "game.max_tired_game_time" , (int *)&GameRule::nMaxTiredGameTime );
ENV().Bind( "game.log_required_state_list", &GameRule::strLogRequiredStateList );
ENV().Bind( "game.log_required_item_list", &GameRule::strLogRequiredItemList );
ENV().Bind( "game.farm_normal_summon_exp", &GameRule::nFarmNormalSummonEXP );
ENV().Bind( "game.farm_growth_summon_exp", &GameRule::nFarmGrowthSummonEXP );
ENV().Bind( "game.farm_evolve_summon_exp", &GameRule::nFarmEvolveSummonEXP );
ENV().Bind( "game.premium_farm_normal_summon_exp", &GameRule::nPremiumFarmNormalSummonEXP );
ENV().Bind( "game.premium_farm_growth_summon_exp", &GameRule::nPremiumFarmGrowthSummonEXP );
ENV().Bind( "game.premium_farm_evolve_summon_exp", &GameRule::nPremiumFarmEvolveSummonEXP );
extern volatile LONG g_nDropRespawn;
extern volatile LONG g_nRespawnObjectCnt;
extern volatile LONG g_nRespawnCnt;
extern volatile LONG g_nRespawnTryCnt;
extern volatile int g_nCurrentLocalFlag;
extern volatile int g_bUseLockDelayLogging;
extern volatile int g_bIgnoreRandomDamage;
ENV().Bind( "game.monster_drop_respawn", (int *) &g_nDropRespawn );
ENV().Bind( "game.monster_respawn_object_cnt", (int *) &g_nRespawnObjectCnt );
ENV().Bind( "game.monster_respawn_cnt", (int *) &g_nRespawnCnt );
ENV().Bind( "game.monster_respawn_try_cnt", (int *) &g_nRespawnTryCnt );
ENV().Bind( "game.local_flag", (int *) &g_nCurrentLocalFlag );
ENV().Bind( "game.bUseLockDelayLogging", (int *) &g_bUseLockDelayLogging );
ENV().Bind( "game.ignore_random_damage", (int *) &g_bIgnoreRandomDamage );
ENV().Bind( "memory.player_heap_size", GetPlayerHeapSize );
ENV().Bind( "memory.monster_heap_size", GetMonsterHeapSize );
ENV().Bind( "memory.item_heap_size", GetItemHeapSize );
ENV().Bind( "memory.summon_heap_size", GetSummonHeapSize );
ENV().Bind( "game.HardcoreServer", &GameRule::bHardcore );
ENV().Bind( "game.HardcoreServerXPRate", &GameRule::fHardcoreExpRate );
ENV().Bind( "game.boss_effect", &GameRule::nBossEffect );
ENV().Bind( "game.killed_drop", &GameRule::fKilledDrop );
ENV().Bind( "game.crime_state", &GameRule::nCrimeState );
ENV().Bind( "game.crime_party", &GameRule::nCrimeParty );
ENV().Bind( "game.killed_exp_percentage", &GameRule::fKilledExpPercentage );
ENV().Bind( "game.kill_immoral_percentage", &GameRule::fKillImmoralPercentage );
ENV().Bind( "game.monster_regen_boss", &GameRule::fMonsterRegenBoss );
ENV().Bind( "game.monster_regen", &GameRule::fMonsterRegen );
ENV().Bind( "game.summon_exp_limit", &GameRule::fSummonExpLimit );
ENV().Bind( "game.summon_exp_penalty_level", &GameRule::nSummonExpPenaltyLevel );
ENV().Bind( "game.exception_arabic", &GameRule::nException_AR );
ENV().Bind( "game.exception_31109", &GameRule::fException_31109 );
ENV().Bind( "game.exception_31309", &GameRule::fException_31309 );
ENV().Bind( "game.stamina_consume_rate", &GameRule::fStaminaConsumeRate );
ENV().Bind( "game.stamina_regen_rate", &GameRule::fStaminaRegenRate );
ENV().Bind( "game.lak_guard", &GameRule::bIsLakGuard );
ENV().Bind( "game.forgotten_stamina_bonus_rate", &GameRule::fForgottenStaminaBonusRate );
ENV().Bind( "game.forgotten_stamina_consume_rate", &GameRule::fForgottenStaminaConsumeRate );
ENV().Bind( "game.item_expert_cube", &GameRule::nItemExpertCube );
ENV().Bind( "game.item_expert_grade", &GameRule::nItemExpertGrade );
ENV().Bind( "game.guild_buff_minute", &GameRule::nGuildBuffMinute ); // Guild buff duration
ENV().Bind( "game.guild_donate_gold", &GameRule::nGuildDonateGold ); // Basic price for donation for guild
ENV().Bind( "game.direct_inventory_loot", &GameRule::bDirectInventoryLoot); // Direct loot
ENV().Bind( "game.item_durability_switch", &GameRule::bItemDurabilitySwitch); // Credits to AziaMafia: Durability consumption switch
ENV().Bind( "game.playerkiller_bonus_rate", &GameRule::fPlayerKillerBonusRate); // AziaMafia TODO:Check this shit
}
void InitLua()
{
// Init Lua VM
_cprint( "LUA initialize... " );
if( LuaVM::Inst()->Init() )
{
_cprint( "ok\n" );
FILELOG( "LUA initialize... ok" );
}
else
{
_cprint( "Failed\n" );
FILELOG( "LUA initialize... failed" );
}
LUA()->RegisterFunction( "insert_item", SCRIPT_InsertItem );
LUA()->RegisterFunction( "insert_item_target", SCRIPT_InsertItemTarget );
LUA()->RegisterFunction( "insert_item_near", SCRIPT_InsertItemNear ); //TODO
LUA()->RegisterFunction( "insert_item_all", SCRIPT_InsertItemAll ); //TODO
LUA()->RegisterFunction( "delete_item", SCRIPT_DeleteItem );
LUA()->RegisterFunction( "putoff_item", SCRIPT_PutoffItem );
LUA()->RegisterFunction( "puton_item", SCRIPT_PutonItem);
LUA()->RegisterFunction( "putoff_skillcard", SCRIPT_Putoffskillcard);
LUA()->RegisterFunction( "puton_skillcard", SCRIPT_Putonskillcard);
LUA()->RegisterFunction( "get_wear_item_handle_creature", SCRIPT_GetWearItemHandleCreature);
LUA()->RegisterFunction( "get_item_weartype", SCRIPT_GetItemWearType);
LUA()->RegisterFunction( "get_item_group", SCRIPT_GetItemGroup);
LUA()->RegisterFunction( "get_item_list", SCRIPT_GetItemList);
LUA()->RegisterFunction( "get_item_list_group", SCRIPT_GetItemList_Group);
LUA()->RegisterFunction( "get_summon_id_by_monster_id", SCRIPT_GetSummonIDByMonsterID);
LUA()->RegisterFunction( "get_summon_name_code", SCRIPT_GetSummonNameCode);
LUA()->RegisterFunction( "get_main_summon", SCRIPT_GetMainSummon);
LUA()->RegisterFunction( "get_sub_summon", SCRIPT_GetSubSummon);
LUA()->RegisterFunction( "is_erasable_item", SCRIPT_IsErasableItem );
LUA()->RegisterFunction( "find_item", SCRIPT_FindItem );
LUA()->RegisterFunction( "drop_item", SCRIPT_DropItem );
LUA()->RegisterFunction( "drop_gold", SCRIPT_DropGold );
LUA()->RegisterFunction( "insert_gold", SCRIPT_InsertGold );
LUA()->RegisterFunction( "has_item", SCRIPT_HasItem );
LUA()->RegisterFunction( "get_item_handle", SCRIPT_GetItemHandle );
LUA()->RegisterFunction( "get_item_handle_list", SCRIPT_GetItemHandleList );
LUA()->RegisterFunction( "get_item_name", SCRIPT_GetItemName );
LUA()->RegisterFunction( "get_item_code", SCRIPT_GetItemCode );
LUA()->RegisterFunction( "get_item_count", SCRIPT_GetItemCount );
LUA()->RegisterFunction( "get_item_level", SCRIPT_GetItemLevel );
LUA()->RegisterFunction( "set_item_level", SCRIPT_SetItemLevel );
LUA()->RegisterFunction( "get_item_level", SCRIPT_GetItemLevel );
LUA()->RegisterFunction( "set_item_enhance", SCRIPT_SetItemEnhance );
LUA()->RegisterFunction( "set_item_enhance_fail", SCRIPT_SetItemEnhanceFail );
LUA()->RegisterFunction( "get_item_enhance", SCRIPT_GetItemEnhance );
LUA()->RegisterFunction( "get_item_grade", SCRIPT_GetItemGrade );
LUA()->RegisterFunction( "get_item_rank", SCRIPT_GetItemRank );
LUA()->RegisterFunction( "get_item_price", SCRIPT_GetItemPrice );
LUA()->RegisterFunction( "get_item_endurance", SCRIPT_GetItemEndurance );
LUA()->RegisterFunction( "set_item_endurance", SCRIPT_SetItemEndurance );
LUA()->RegisterFunction( "get_socket_info", SCRIPT_GetItemSocketCode );
LUA()->RegisterFunction( "set_socket_info", SCRIPT_SetItemSocketCode );
LUA()->RegisterFunction( "set_item_element", SCRIPT_SetItemElement );
LUA()->RegisterFunction( "set_item_element_parameter", SCRIPT_SetItemElementParameter );
LUA()->RegisterFunction( "get_item_name_by_code", SCRIPT_ItemName );
LUA()->RegisterFunction( "get_item_name_id", SCRIPT_GetItemNameId );
LUA()->RegisterFunction( "get_wear_item_handle", SCRIPT_GetWearItemHandle );
LUA()->RegisterFunction( "get_item_appearance_code",SCRIPT_GetItemAppearanceCode );
LUA()->RegisterFunction( "set_item_appearance_code",SCRIPT_SetItemAppearanceCode );
LUA()->RegisterFunction( "get_item_in_belt", SCRIPT_GetItemInBelt );
LUA()->RegisterFunction( "insert_awaken", SCRIPT_InsertAwakenOption );
LUA()->RegisterFunction( "delete_awaken", SCRIPT_DeleteAwakenOption );
LUA()->RegisterFunction( "identify_item", SCRIPT_IdentifyItemForRandomOption );
LUA()->RegisterFunction( "insert_summon_by_summon_id", SCRIPT_InsertSummonBySummonID );
LUA()->RegisterFunction( "insert_summon_by_monster_id", SCRIPT_InsertSummonByMonsterID );
LUA()->RegisterFunction( "change_item_code", SCRIPT_ChangeItemCode );
LUA()->RegisterFunction( "get_item_random_option", SCRIPT_GetItemIdentifiedOption );
LUA()->RegisterFunction( "get_item_awaken_option", SCRIPT_GetAwakenOption);
LUA()->RegisterFunction( "set_item_awaken_option", SCRIPT_SetItemAwakenOption);
LUA()->RegisterFunction( "set_item_random_option", SCRIPT_SetItemIdentifiedOption );
LUA()->RegisterFunction( "pick_item_in_drop_group", SCRIPT_PickItemInDropGroup );
LUA()->RegisterFunction( "donate_item", SCRIPT_DonateItem );
// 에테리얼 내구도 관련
LUA()->RegisterFunction( "get_item_ethereal_durability", SCRIPT_GetItemEtherealDurability );
LUA()->RegisterFunction( "set_item_ethereal_durability", SCRIPT_SetItemEtherealDurability );
LUA()->RegisterFunction( "get_max_item_ethereal_durability", SCRIPT_GetMaxItemEtherealDurability );
// 소울스톤 관련
LUA()->RegisterFunction( "show_soulstone_craft_window", SCRIPT_ShowSoulStoneCraftWindow );
LUA()->RegisterFunction( "get_item_soulstone_endurance", SCRIPT_GetItemSoulStoneEndurance );
LUA()->RegisterFunction( "get_max_item_soulstone_endurance", SCRIPT_GetMaxItemSoulStoneEndurance );
LUA()->RegisterFunction( "show_soulstone_repair_window", SCRIPT_ShowSoulStoneRepairWindow );
// 아이템 드랍 이벤트 관련
LUA()->RegisterFunction( "refresh_event_drop", SCRIPT_RefreshEventDropInfo );
LUA()->RegisterFunction( "start_event_drop", SCRIPT_StartEventDrop );
LUA()->RegisterFunction( "stop_event_drop", SCRIPT_StopEventDrop );
LUA()->RegisterFunction( "show_event_drop", SCRIPT_ShowEventDrop );
LUA()->RegisterFunction( "update_event_drop", SCRIPT_UpdateEventDrop );
LUA()->RegisterFunction( "insert_event_drop", SCRIPT_InsertEventDrop );
// 던전 드랍율 이벤트 관련
LUA()->RegisterFunction( "start_event_dungeon_droprate", SCRIPT_StartEventDungeonDroprate );
LUA()->RegisterFunction( "stop_event_dungeon_droprate", SCRIPT_StopEventDungeonDroprate );
LUA()->RegisterFunction( "refresh_event_dungeon_droprate", SCRIPT_RefreshEventDungeonDroprate );
// 아이템 지급 이벤트 관련
LUA()->RegisterFunction( "event_supply", SCRIPT_EventSupply );
LUA()->RegisterFunction( "refresh_event_supply", SCRIPT_RefreshEventSupplyInfo );
LUA()->RegisterFunction( "start_event_supply", SCRIPT_StartEventSupply );
LUA()->RegisterFunction( "stop_event_supply", SCRIPT_StopEventSupply );
LUA()->RegisterFunction( "supply_event_item", SCRIPT_SupplyEventItem );
// 프로퍼티 관련
LUA()->RegisterFunction( "get_target_value", SCRIPT_GetTargetValue );
LUA()->RegisterFunction( "gtv", SCRIPT_GetTargetValue );
LUA()->RegisterFunction( "get_handle_value", SCRIPT_GetHandleValue );
LUA()->RegisterFunction( "ghv", SCRIPT_GetHandleValue );
LUA()->RegisterFunction( "get_value", SCRIPT_GetValue );
LUA()->RegisterFunction( "add_value", SCRIPT_AddValue );
LUA()->RegisterFunction( "add_exp_jp", SCRIPT_AddExpJP );
LUA()->RegisterFunction( "get_exp_require", SCRIPT_GetExpRequire);
LUA()->RegisterFunction( "set_value", SCRIPT_SetValue );
LUA()->RegisterFunction( "echo_value", SCRIPT_EchoValue );
LUA()->RegisterFunction( "gv", SCRIPT_GetValue );
LUA()->RegisterFunction( "av", SCRIPT_AddValue );
LUA()->RegisterFunction( "sv", SCRIPT_SetValue );
LUA()->RegisterFunction( "ev", SCRIPT_EchoValue );
LUA()->RegisterFunction( "get_all_value", SCRIPT_GetAllValue );
LUA()->RegisterFunction( "set_creature_value", SCRIPT_SetCreatureValue );
LUA()->RegisterFunction( "get_creature_value", SCRIPT_GetCreatureValue );
LUA()->RegisterFunction( "change_creature_name", SCRIPT_ChangeCreatureName );
LUA()->RegisterFunction( "scv", SCRIPT_SetCreatureValue );
LUA()->RegisterFunction( "smcv", SCRIPT_SetMainCreatureValue );
LUA()->RegisterFunction( "gcv", SCRIPT_GetCreatureValue );
LUA()->RegisterFunction( "gmcv", SCRIPT_GetMainCreatureValue );
LUA()->RegisterFunction( "emcv", SCRIPT_EchoMainCreatureValue);
// 플레이어 플래그 관련
LUA()->RegisterFunction( "get_flag", SCRIPT_GetPlayerFlag );
LUA()->RegisterFunction( "set_flag", SCRIPT_SetPlayerFlag );
LUA()->RegisterFunction( "del_flag", SCRIPT_RemovePlayerFlag );
// 계정 플래그 관련
LUA()->RegisterFunction( "get_account_flag", SCRIPT_GetAccountFlag );
LUA()->RegisterFunction( "set_account_flag", SCRIPT_SetAccountFlag );
LUA()->RegisterFunction( "del_account_flag", SCRIPT_RemoveAccountFlag );
// 대기시간 없이 PK 모드 변경
LUA()->RegisterFunction( "set_pk_mode", SCRIPT_SetPKMode );
// 길드 연합 관련
LUA()->RegisterFunction( "is_alliance_leader", SCRIPT_IsAllianceLeader );
LUA()->RegisterFunction( "increase_max_alliance_member_count", SCRIPT_IncreaseMaxAllianceMemberCount );
LUA()->RegisterFunction( "get_max_alliance_member_count", SCRIPT_GetMaxAllianceMemberCount );
// NPC 대화 및 퀘스트 관련
LUA()->RegisterFunction( "dlg_title", SCRIPT_DialogTitle );
LUA()->RegisterFunction( "dlg_text", SCRIPT_DialogText );
LUA()->RegisterFunction( "dlg_menu", SCRIPT_DialogMenu );
LUA()->RegisterFunction( "dlg_show", SCRIPT_DialogShow );
LUA()->RegisterFunction( "quest_text_without_quest_menu", SCRIPT_QuestTextWithoutQuest);
LUA()->RegisterFunction( "dlg_text_without_quest_menu", SCRIPT_DialogTextWithoutQuest);
LUA()->RegisterFunction( "start_quest", SCRIPT_StartQuest );
LUA()->RegisterFunction( "force_start_quest", SCRIPT_ForceStartQuest );
LUA()->RegisterFunction( "add_pending_quest", SCRIPT_AddPendingQuest );
LUA()->RegisterFunction( "end_quest", SCRIPT_EndQuest );
LUA()->RegisterFunction( "drop_quest", SCRIPT_DropQuest );
LUA()->RegisterFunction( "quest_info", SCRIPT_QuestInfo );
LUA()->RegisterFunction( "show_quest_info_without_npc", SCRIPT_ShowQuestInfoWithoutNPC );
LUA()->RegisterFunction( "get_quest_progress", SCRIPT_GetQuestProgress );
LUA()->RegisterFunction( "get_quest_status", SCRIPT_GetQuestStatus );
LUA()->RegisterFunction( "set_quest_status", SCRIPT_SetQuestStatus );
LUA()->RegisterFunction( "get_last_accept_quest", SCRIPT_GetLastAcceptQuest );
LUA()->RegisterFunction( "reset_finished_quest", SCRIPT_ResetFinishedQuest );
// 다이얼로그 관련
LUA()->RegisterFunction( "dlg_general", SCRIPT_DialogGeneral );
LUA()->RegisterFunction( "dlg_special", SCRIPT_DialogSpecial );
LUA()->RegisterFunction( "dlg_special_menu", SCRIPT_SpecialMenu );
LUA()->RegisterFunction( "dlg_number", SCRIPT_DialogNumber );
LUA()->RegisterFunction( "kick", SCRIPT_Kick );
LUA()->RegisterFunction( "force_unregister_account", SCRIPT_ForceUnregisterAccount );
LUA()->RegisterFunction( "env", SCRIPT_GetEnv );
LUA()->RegisterFunction( "add_npc", SCRIPT_AddMonster );
LUA()->RegisterFunction( "add_monster", SCRIPT_AddMonster2 );
LUA()->RegisterFunction( "set_home", SCRIPT_SetHome );
LUA()->RegisterFunction( "add_instance_dungeon_monster", SCRIPT_AddInstanceDungeonMonster );
LUA()->RegisterFunction( "add_npc_to_world", SCRIPT_AddNPC );
LUA()->RegisterFunction( "add_field_prop", SCRIPT_AddFieldProp );
LUA()->RegisterFunction( "remove_field_prop", SCRIPT_RemoveFieldProp );
LUA()->RegisterFunction( "respawn", SCRIPT_AddRespawnInfo );
LUA()->RegisterFunction( "respawn_guardian", SCRIPT_AddDungeonGuardianRespawnInfo );
LUA()->RegisterFunction( "respawn_environmental_guardian", SCRIPT_AddDungeonEnvironmentalGuardianRespawnInfo );
LUA()->RegisterFunction( "respawn_rare_mob", SCRIPT_AddRareMobRespawnInfo );
LUA()->RegisterFunction( "respawn_roaming_mob", SCRIPT_AddRoamingMobRespawnInfo );
LUA()->RegisterFunction( "raid_respawn", SCRIPT_AddRaidRespawnInfo );
LUA()->RegisterFunction( "raid_respawn_rare_mob", SCRIPT_AddRaidRareMobRespawnInfo);
// 몬스터 랜덤 리젠
LUA()->RegisterFunction( "set_random_respawn", SCRIPT_SetRandomRespawnInfo );
LUA()->RegisterFunction( "add_random_area", SCRIPT_AddRandomAreaInfo );
LUA()->RegisterFunction( "add_random_monster", SCRIPT_AddRandomMonster );
// 랜덤 몬스터 그룹
LUA()->RegisterFunction( "add_random_monster_group", SCRIPT_AddRandomMonsterGroup );
LUA()->RegisterFunction( "kill", SCRIPT_Kill );
LUA()->RegisterFunction( "kill_target", SCRIPT_KillTarget );
// 시스템 날짜와 시간 관련 함수
LUA()->RegisterFunction( "get_os_time", SCRIPT_LuaSTDLib_Time );
LUA()->RegisterFunction( "get_os_date", SCRIPT_LuaSTDLib_Date );
LUA()->RegisterFunction( "get_os_second", SCRIPT_GetOsSecond );
LUA()->RegisterFunction( "get_minute", SCRIPT_GetMinute );
LUA()->RegisterFunction( "notice", SCRIPT_Notice );
LUA()->RegisterFunction( "private_notice", SCRIPT_PrivateNotice );
LUA()->RegisterFunction( "announce", SCRIPT_Announce );
LUA()->RegisterFunction( "whisper", SCRIPT_Whisper );
LUA()->RegisterFunction( "warp", SCRIPT_Warp );
LUA()->RegisterFunction( "force_warp", SCRIPT_ForceWarp );
LUA()->RegisterFunction( "recall_player", SCRIPT_RecallPlayer );
LUA()->RegisterFunction( "is_in_siege_dungeon", SCRIPT_IsInSiegeDungeon );
LUA()->RegisterFunction( "respawn_guardian_object", SCRIPT_RespawnGuardian );
LUA()->RegisterFunction( "show_dungeon_stone", SCRIPT_ShowDungeonStone );
LUA()->RegisterFunction( "change_tactical_position_owner", SCRIPT_ChangeTacticalPositionOwner );
LUA()->RegisterFunction( "request_dungeon_raid", SCRIPT_RequestDungeonRaid );
LUA()->RegisterFunction( "cancel_dungeon_raid", SCRIPT_CancelDungeonRaid );
// 숨겨진 던전
LUA()->RegisterFunction( "enter_secret_dungeon", SCRIPT_EnterSecretDungeon );
LUA()->RegisterFunction( "warp_to_secret_dungeon", SCRIPT_WarpToSecretDungeon );
// 인스턴스 던전
LUA()->RegisterFunction( "enter_instance_dungeon", SCRIPT_EnterInstanceDungeon );
LUA()->RegisterFunction( "enter_other_instance_dungeon", SCRIPT_EnterOtherInstanceDungeon);
LUA()->RegisterFunction( "warp_to_instance_dungeon", SCRIPT_WarpToInstanceDungeon );
LUA()->RegisterFunction( "leave_instance_dungeon", SCRIPT_LeaveInstanceDungeon );
LUA()->RegisterFunction( "quit_instance_dungeon", SCRIPT_QuitInstanceDungeon );
LUA()->RegisterFunction( "get_instance_dungeon_id", SCRIPT_GetInstanceDungeonID );
LUA()->RegisterFunction( "get_instance_dungeon_type_id", SCRIPT_GetInstanceDungeonTypeID );
LUA()->RegisterFunction( "set_instance_dungeon_flag", SCRIPT_SetInstanceDungeonFlag );
LUA()->RegisterFunction( "get_instance_dungeon_flag", SCRIPT_GetInstanceDungeonFlag );
LUA()->RegisterFunction( "get_alive_instance_respawn_group_monster_count", SCRIPT_GetAliveInstanceRespawnGroupMonsterCount );
LUA()->RegisterFunction( "do_each_player_in_instance_dungeon", SCRIPT_DoEachPlayerInInstanceDungeon );
// 인스턴스 던전 미션 관련(인던 진행상황 표시용 UI - 미션 UI라고 지칭함)
// * 미션에 관련된 데이터를 서버가 따로 보관하지는 않으며 InstanceDungeonFlag를 이용해서 스크립트에서 데이터를 관리하며
// 유저에게 방송만 함으로써 UI 갱신만 시켜주는 것으로, 데이터의 세팅/값 확인 등의 함수 없이 방송 함수만 있음
LUA()->RegisterFunction( "send_mission_title", SCRIPT_SendMissionTitle );
LUA()->RegisterFunction( "send_mission_reward", SCRIPT_SendMissionReward );
LUA()->RegisterFunction( "send_mission_objective", SCRIPT_SendMissionObjective );
LUA()->RegisterFunction( "send_mission_objective_progress", SCRIPT_SendMissionObjectiveProgress );
LUA()->RegisterFunction( "broadcast_mission_title", SCRIPT_BroadcastMissionTitle );
LUA()->RegisterFunction( "broadcast_mission_reward", SCRIPT_BroadcastMissionReward );
LUA()->RegisterFunction( "broadcast_mission_objective", SCRIPT_BroadcastMissionObjective );
LUA()->RegisterFunction( "broadcast_mission_objective_progress", SCRIPT_BroadcastMissionObjectiveProgress );
LUA()->RegisterFunction( "broadcast_notice", SCRIPT_BroadcastNotice );
// 배틀 아레나 관련
LUA()->RegisterFunction( "activate_battle_arena_prop", SCRIPT_ActivateBattleArenaProp );
LUA()->RegisterFunction( "set_battle_arena_instance_flag", SCRIPT_SetBattleArenaInstanceFlag );
LUA()->RegisterFunction( "get_battle_arena_instance_flag", SCRIPT_GetBattleArenaInstanceFlag );
LUA()->RegisterFunction( "do_each_player_in_battle_arena_instance", SCRIPT_DoEachPlayerInBattleArenaInstance );
LUA()->RegisterFunction( "do_each_player_in_battle_arena_team", SCRIPT_DoEachPlayerInBattleArenaTeam );
LUA()->RegisterFunction( "get_battle_arena_block_time", SCRIPT_GetBattleArenaBlockTime );
LUA()->RegisterFunction( "set_battle_arena_block_time", SCRIPT_SetBattleArenaBlockTime );
LUA()->RegisterFunction( "get_battle_arena_penalty_count", SCRIPT_GetBattleArenaPenaltyCount );
LUA()->RegisterFunction( "set_battle_arena_penalty_count", SCRIPT_SetBattleArenaPenaltyCount );
LUA()->RegisterFunction( "get_battle_arena_next_penalty_dec_time", SCRIPT_GetBattleArenaNextPenaltyDecTime );
LUA()->RegisterFunction( "set_battle_arena_next_penalty_dec_time", SCRIPT_SetBattleArenaNextPenaltyDecTime );
LUA()->RegisterFunction( "get_battle_arena_team_no", SCRIPT_GetBattleArenaTeamNo );
LUA()->RegisterFunction( "set_secroute_free_pass", SCRIPT_SetSecrouteFreePass );
LUA()->RegisterFunction( "set_chat_block_time", SCRIPT_SetChatBlockTime );
LUA()->RegisterFunction( "set_invisible", SCRIPT_SetInvisible );
LUA()->RegisterFunction( "rebirth", SCRIPT_Rebirth );
LUA()->RegisterFunction( "set_level", SCRIPT_SetLevel );
LUA()->RegisterFunction( "heal", SCRIPT_Heal );
LUA()->RegisterFunction( "enter_dungeon", SCRIPT_WarpToDungeon );
LUA()->RegisterFunction( "warp_to_stored_position", SCRIPT_WarpToStoredPosition );
LUA()->RegisterFunction( "begin_dungeon_raid", SCRIPT_BeginDungeonRaid );
LUA()->RegisterFunction( "drop_dungeon_owner_ship", SCRIPT_DropDungeonOwnership );
LUA()->RegisterFunction( "change_dungeon_owner", SCRIPT_ChangeDungeonOwner );
LUA()->RegisterFunction( "clear_dungeon_core_guardian", SCRIPT_ClearDungeonCoreGuardian );
LUA()->RegisterFunction( "get_own_dungeon_id", SCRIPT_GetOwnDungeonID );
LUA()->RegisterFunction( "get_siege_dungeon_id", SCRIPT_GetSiegeDungeonID );
LUA()->RegisterFunction( "stat", SCRIPT_Stat );
LUA()->RegisterFunction( "setspeed", SCRIPT_SetSpeed );
LUA()->RegisterFunction( "saveall", SCRIPT_SaveAllPlayer );
LUA()->RegisterFunction( "shutdown", SCRIPT_Shutdown );
LUA()->RegisterFunction( "delete_block_account", SCRIPT_DeleteFromBlockAccount );
LUA()->RegisterFunction( "save", SCRIPT_SavePlayer );
LUA()->RegisterFunction( "respawn_near_monster", SCRIPT_RespawnNearMonster);
LUA()->RegisterFunction( "monster_skill_cast", SCRIPT_MonsterSkillCast );
LUA()->RegisterFunction( "get_monster_skill_target_position", SCRIPT_GetMonsterSkillTargetPosition );
LUA()->RegisterFunction( "set_monster_skill_target_position", SCRIPT_SetMonsterSkillTargetPosition );
LUA()->RegisterFunction( "set_next_attackable_time", SCRIPT_SetNextAttackableTime );
LUA()->RegisterFunction( "get_monster_id", SCRIPT_GetMonsterID );
LUA()->RegisterFunction( "get_monster_info", SCRIPT_GetMonsterInfo);
LUA()->RegisterFunction( "get_monster_info_handle", SCRIPT_GetMonsterInfo_byHandle);
LUA()->RegisterFunction( "db_trace_dump", SCRIPT_DBTraceDump );
LUA()->RegisterFunction( "force_monster_proc_dead", SCRIPT_ForceMonsterProcDead );
LUA()->RegisterFunction( "open_market", SCRIPT_ShowMarket );
LUA()->RegisterFunction( "gametime", SCRIPT_GetGameTime );
LUA()->RegisterFunction( "refresh", SCRIPT_Reload );
LUA()->RegisterFunction( "learn_skill", SCRIPT_LearnSkill );
LUA()->RegisterFunction( "learn_all_skill", SCRIPT_LearnAllSkill );
LUA()->RegisterFunction( "learn_all_skill_no_levelup", SCRIPT_LearnAllSkill_no_levelup);
LUA()->RegisterFunction( "learn_creature_all_skill",SCRIPT_LearnCreatureAllSkill);
LUA()->RegisterFunction( "reset_skill", SCRIPT_ResetSkill );
LUA()->RegisterFunction( "set_job", SCRIPT_SetJob );
LUA()->RegisterFunction( "reset_job", SCRIPT_ResetJob );
LUA()->RegisterFunction( "set_race", SCRIPT_SetRace );
LUA()->RegisterFunction( "get_base_skill_level", SCRIPT_GetBaseSkillLevel );
LUA()->RegisterFunction( "get_cur_skill_level", SCRIPT_GetCurSkillLevel);
LUA()->RegisterFunction( "get_cur_skill_enchant", SCRIPT_GetCurSkillEnchant);
LUA()->RegisterFunction( "show_creature_dialog", SCRIPT_ShowCreatureDialog );
LUA()->RegisterFunction( "sconv", SCRIPT_Conv );
LUA()->RegisterFunction( "message", SCRIPT_Message );
LUA()->RegisterFunction( "is_changeable_job", SCRIPT_IsChangeableJob );
LUA()->RegisterFunction( "add_state", SCRIPT_AddState );
LUA()->RegisterFunction( "get_state_time", SCRIPT_GetStateTime);
LUA()->RegisterFunction( "get_state_level", SCRIPT_GetStateLevel );
LUA()->RegisterFunction( "remove_state", SCRIPT_RemoveState );
LUA()->RegisterFunction( "add_cstate", SCRIPT_AddCreatureState );
LUA()->RegisterFunction( "remove_cstate", SCRIPT_RemoveCreatureState );
LUA()->RegisterFunction( "add_event_state", SCRIPT_AddEventState );
LUA()->RegisterFunction( "remove_event_state", SCRIPT_RemoveEventState );
LUA()->RegisterFunction( "clear_event_state", SCRIPT_ClearEventState );
LUA()->RegisterFunction( "get_event_state_list", SCRIPT_GetEventStateList );
LUA()->RegisterFunction( "cast_world_state", SCRIPT_CastWorldState );
LUA()->RegisterFunction( "set_env", SCRIPT_SetEnv );
LUA()->RegisterFunction( "get_env", SCRIPT_GetEnv );
LUA()->RegisterFunction( "set_global_variable", SCRIPT_SetGlobalVariable );
LUA()->RegisterFunction( "get_global_variable", SCRIPT_GetGlobalVariable );
LUA()->RegisterFunction( "del_global_variable", SCRIPT_DeleteGlobalVariable );
LUA()->RegisterFunction( "sgv", SCRIPT_SetGlobalVariable );
LUA()->RegisterFunction( "ggv", SCRIPT_GetGlobalVariable );
LUA()->RegisterFunction( "dgv", SCRIPT_DeleteGlobalVariable );
//LUA()->RegisterFunction( "revival_summon", SCRIPT_ResurrectSummon );
LUA()->RegisterFunction( "get_string", SCRIPT_GetString );
LUA()->RegisterFunction( "get_creature_handle", SCRIPT_GetCreatureHandle );
LUA()->RegisterFunction( "open_storage", SCRIPT_ShowStorage );
LUA()->RegisterFunction( "get_user_count_near", SCRIPT_GetUserCountNear );
LUA()->RegisterFunction( "create_guild", SCRIPT_CreateGuild );
LUA()->RegisterFunction( "destroy_guild", SCRIPT_DestroyGuild );
LUA()->RegisterFunction( "show_guild_create", SCRIPT_ShowCreateGuild );
LUA()->RegisterFunction( "show_alliance_create", SCRIPT_ShowCreateAlliance );
LUA()->RegisterFunction( "force_change_guild_name", SCRIPT_ForceChangeGuildName );
LUA()->RegisterFunction( "force_promote_guild_leader", SCRIPT_ForcePromoteGuildLeader );
LUA()->RegisterFunction( "check_valid_guild_name", SCRIPT_CheckValidGuildName );
LUA()->RegisterFunction( "create_alliance", SCRIPT_CreateAlliance );
LUA()->RegisterFunction( "destroy_alliance", SCRIPT_DestroyAlliance );
LUA()->RegisterFunction( "check_valid_alliance_name", SCRIPT_CheckValidAllianceName );
LUA()->RegisterFunction( "get_npc_id", SCRIPT_GetNPCId );
LUA()->RegisterFunction( "get_npc_handle", SCRIPT_GetNPCHandle );
LUA()->RegisterFunction( "get_npc_type", SCRIPT_GetNPCType );
LUA()->RegisterFunction( "get_npc_name", SCRIPT_GetNPCName );
LUA()->RegisterFunction( "show_npc", SCRIPT_ShowNPC );
LUA()->RegisterFunction( "creature_evolution", SCRIPT_CreatureEvolution );
LUA()->RegisterFunction( "creature_enhance", SCRIPT_CreatureEnhance );
LUA()->RegisterFunction( "call_lc_In", SCRIPT_SetCurrentLocationId );
LUA()->RegisterFunction( "creature_learn_skill", SCRIPT_CreatureLearnSkill );
LUA()->RegisterFunction( "get_proper_channel_num", SCRIPT_GetProperChannelNo );
LUA()->RegisterFunction( "get_min_channel_num", SCRIPT_GetMinChannelNo );
LUA()->RegisterFunction( "get_max_channel_num", SCRIPT_GetMaxChannelNo );
LUA()->RegisterFunction( "get_user_count_in_channel",SCRIPT_GetUserCountInChannel);
LUA()->RegisterFunction( "get_layer_of_channel", SCRIPT_GetLayerOfChannel );
LUA()->RegisterFunction( "get_summon_name_id", SCRIPT_GetSummonNameId );
LUA()->RegisterFunction( "equip_summon_card", SCRIPT_EquipSummonCard );
LUA()->RegisterFunction( "show_channel_set", SCRIPT_ShowChannelSet );
LUA()->RegisterFunction( "update_guild_info", SCRIPT_UpdateGuildInfo );
LUA()->RegisterFunction( "update_guild_banner_info", SCRIPT_UpdateGuildBannerInfo );
LUA()->RegisterFunction( "is_guild_leader", SCRIPT_IsGuildLeader );
LUA()->RegisterFunction( "set_guild_block_time", SCRIPT_SetGuildBlockTime );
LUA()->RegisterFunction( "get_guild_block_time", SCRIPT_GetGuildBlockTime );
LUA()->RegisterFunction( "get_guild_name", SCRIPT_GetGuildName );
LUA()->RegisterFunction( "get_own_guild_name", SCRIPT_GetOwnGuildName );
LUA()->RegisterFunction( "get_dungeon_relation", SCRIPT_GetDungeonRelation );
LUA()->RegisterFunction( "get_tax_rate", SCRIPT_GetTaxRate );
LUA()->RegisterFunction( "set_tax_rate", SCRIPT_SetTaxRate );
LUA()->RegisterFunction( "get_tax_amount", SCRIPT_GetTaxAmount );
LUA()->RegisterFunction( "get_tax_chaos_amount", SCRIPT_GetTaxChaosAmount );
LUA()->RegisterFunction( "draw_tax", SCRIPT_DrawTax );
LUA()->RegisterFunction( "draw_tax_chaos", SCRIPT_DrawTaxChaos );
#ifndef _USE_NEW_ROAMING_ONLY
LUA()->RegisterFunction( "add_way_point", SCRIPT_AddWayPoint );
LUA()->RegisterFunction( "set_way_point_type", SCRIPT_SetWayPointType );
LUA()->RegisterFunction( "set_way_point_speed", SCRIPT_SetWayPointSpeed );
#endif
LUA()->RegisterFunction( "recall_feather", SCRIPT_RecallFeather );
LUA()->RegisterFunction( "warp_to_exit_position", SCRIPT_WarpToExitPosition );
LUA()->RegisterFunction( "warp_to_revive_position", SCRIPT_WarpToRevivePosition );
LUA()->RegisterFunction( "get_server_category", SCRIPT_GetServerCategory );
LUA()->RegisterFunction( "find_npc", SCRIPT_FindNPC );
LUA()->RegisterFunction( "set_auto_user", SCRIPT_SetAutoUser );
LUA()->RegisterFunction( "set_auto_account", SCRIPT_SetAutoAccount );
LUA()->RegisterFunction( "clear_auto_account", SCRIPT_ClearAutoAccount );
LUA()->RegisterFunction( "open_url", SCRIPT_OpenUrl );
LUA()->RegisterFunction( "open_popup", SCRIPT_OpenPopup );
LUA()->RegisterFunction( "open_popup_and_set_size", SCRIPT_OpenPopupAndSetSize );
LUA()->RegisterFunction( "get_local_info", SCRIPT_GetLocalInfo );
LUA()->RegisterFunction( "update_gold_chaos", SCRIPT_SendGoldChaosUpdate );
LUA()->RegisterFunction( "show_donation_prop", SCRIPT_ShowDonationMenu );
LUA()->RegisterFunction( "set_pcbang_user", SCRIPT_SetPCBangUser );
LUA()->RegisterFunction( "set_continuous_play_time", SCRIPT_SetContinuousPlayTime );
// NPC에 의한 소환수 이름 변경 기능 관련
LUA()->RegisterFunction( "get_creature_name_id", SCRIPT_GetCreatureNameID );
LUA()->RegisterFunction( "creature_name_change_box", SCRIPT_ShowCreatureNameChangeBox );
// NPC에 의한 소환수 스킬 초기화 기능 관련
LUA()->RegisterFunction( "reset_summon_skill", SCRIPT_ResetSummonSkill );
// NPC에 의한 소환수 농장 기능 관련
LUA()->RegisterFunction( "show_creature_farm_window", SCRIPT_ShowCreatureFarmWindow );
LUA()->RegisterFunction( "get_summon_list", SCRIPT_GetSummonList );
LUA()->RegisterFunction( "get_farmed_summon_list", SCRIPT_GetFarmedSummonList );
LUA()->RegisterFunction( "get_farmed_summon_count", SCRIPT_GetFarmedSummonCount );
LUA()->RegisterFunction( "get_farmed_summon_value", SCRIPT_GetFarmedSummonValue );
LUA()->RegisterFunction( "get_farmed_summon_level", SCRIPT_GetFarmedSummonLevel );
LUA()->RegisterFunction( "get_summon_rate", SCRIPT_GetSummonRate );
LUA()->RegisterFunction( "farm_summon", SCRIPT_FarmSummon );
LUA()->RegisterFunction( "regain_summon", SCRIPT_RegainSummon );
LUA()->RegisterFunction( "nurse_summon", SCRIPT_NurseSummon );
// 호칭 관련
LUA()->RegisterFunction( "open_title", SCRIPT_OpenTitle );
LUA()->RegisterFunction( "achieve_title", SCRIPT_AchieveTitle );
LUA()->RegisterFunction( "get_main_title", SCRIPT_GetMainTitle );
LUA()->RegisterFunction( "set_main_title", SCRIPT_SetMainTitle );
LUA()->RegisterFunction( "get_sub_title", SCRIPT_GetSubTitle );
LUA()->RegisterFunction( "set_sub_title", SCRIPT_SetSubTitle );
LUA()->RegisterFunction( "update_title_condition", SCRIPT_UpdateTitleCondition );
LUA()->RegisterFunction( "set_remain_title_time", SCRIPT_SetRemainTitleTime );
// 경매 관련
LUA()->RegisterFunction( "show_auction_window", SCRIPT_ShowAuctionWindow );
LUA()->RegisterFunction( "cancel_auction_by_seller", SCRIPT_CancelAuctionBySeller );
// 헌터홀릭 관련
LUA()->RegisterFunction( "show_huntaholic_lobby_window", SCRIPT_ShowHuntaholicLobbyWindow );
LUA()->RegisterFunction( "set_huntaholic_point", SCRIPT_SetHuntaholicPoint );
// 이벤트 영역 진입 횟수 기록 관련
LUA()->RegisterFunction( "get_event_area_enter_count", SCRIPT_GetEventAreaEnterCount );
LUA()->RegisterFunction( "set_event_area_enter_count", SCRIPT_SetEventAreaEnterCount );
// 서버 강제 덤프 생성 후 종료(카운트 및 유저 정보 저장 처리 없음)
LUA()->RegisterFunction( "suicide", SCRIPT_Suicide );
// ScheduledCommandManager priority 설정 함수
LUA()->RegisterFunction( "set_scheduled_command_manager_priority", SCRIPT_SetScheduledCommandManagerPriority );
// 인벤토리 아이템 삭제 (GM 본인 인벤토리 아이템 삭제)
LUA()->RegisterFunction( "clear_inventory", SCRIPT_ClearInventory );
// 계정 관련
LUA()->RegisterFunction( "set_account_authority", SCRIPT_SetAccountAuthority );
LUA()->RegisterFunction( "update_wear", SCRIPT_UpdateWear );
LUA()->RegisterFunction( "do_each_player_in_party", SCRIPT_DoEachPlayerInParty );
LUA()->RegisterFunction( "do_each_player_in_guild", SCRIPT_DoEachPlayerInGuild );
LUA()->RegisterFunction( "do_each_player_in_world", SCRIPT_DoEachPlayerInWorld );
LUA()->RegisterFunction( "do_player", SCRIPT_DoPlayer );
LUA()->RegisterFunction( "set_item_flag", SCRIPT_SetItemFlag);
LUA()->RegisterFunction( "get_item_flag", SCRIPT_GetItemFlag);
LUA()->RegisterFunction( "awaken_item_rdm", SCRIPT_AwakenItemForRandomOption);
LUA()->RegisterFunction( "exec_smp", SCRIPT_Exec_Smp); // Fraun stored procedures execution from lua 8/17/2025
LUA()->RegisterFunction( "re_identify_item", SCRIPT_Re_IdentifyItemForRandomOption);
LUA()->RegisterFunction( "ispartyleader", SCRIPT_ispartyleader);
LUA()->RegisterFunction( "partycount", SCRIPT_partycount);
LUA()->RegisterFunction( "loc_id", SCRIPT_loc_id);
LUA()->RegisterFunction( "creature_item_card_handle", SCRIPT_CreatureItemCardHandle);
// Fraun 7/12/2025 new functions
LUA()->RegisterFunction("get_server_time", SCRIPT_GetServerTime);
LUA()->RegisterFunction("get_location_id", SCRIPT_GetLocationID);
LUA()->RegisterFunction("get_location_type", SCRIPT_GetLocationType);
LUA()->RegisterFunction("get_item_class", SCRIPT_GetItemClass);
LUA()->RegisterFunction("get_awakening", SCRIPT_GetAwakening);
LUA()->RegisterFunction("set_specific_awaken", SCRIPT_SetSpecificAwakening);
StructSummon::BindProperty();
StructPlayer::BindProperty();
StructMonster::BindProperty();
// 출력방향 설정
LUA()->BindLogOutputFunction( ScriptLog );
}
bool _HerlockIntf::onInit( HWND hWnd )
{
SetWindowText( hWnd, ENV().GetString( "app.name", "Rappelz Server" ).c_str() );
FileLogHandler::Init();
g_DBTracker.init();
// init COM
CoInitialize(NULL);
// init random
srand( GetArTime() );
// init network
_cprint( "Network initialize... " );
if( XNetworkUtil::InitNetwork() )
{
_cprint( "ok\n" );
FILELOG( "Network initialize... ok" );
}
else
{
_cprint( "Failed\n" );
FILELOG( "Network initialize... failed" );
}
void InitNetwork();
InitNetwork();
// init script
InitLua();
if( !XSecuritySolutionManager::Instance().Init() )
{
return true;
}
unsigned id;
HANDLE hThread;
hThread = reinterpret_cast<HANDLE>( _beginthreadex( NULL, 0, initFunc, NULL, 0, &id ) );
CloseHandle( hThread );
b_performanceUpdate = true;
hThread = reinterpret_cast<HANDLE>( _beginthreadex( NULL, 0, performanceLogFunc, NULL, 0, &id ) );
CloseHandle( hThread );
// set timer
SetTimer( ArcadiaFrameworkIntf::GetViewWindow(), 0, 100, NULL );
// init log
LOG::Init( ENV().GetString( "app.name", "CA Game Server" ).c_str() );
LOG::Log11N4S( LM_SERVER_INFO, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", 0, "", 0, "", 0, "START", LOG::STR_NTS );
return true;
}
bool _HerlockIntf::onDeInit()
{
LOG::Log11N4S( LM_SERVER_INFO, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", 0, "", 0, "", 0, "END", LOG::STR_NTS );
KillTimer( ArcadiaFrameworkIntf::GetViewWindow(), 0 );
int nShutdownState = ShutdownManager::Instance().m_nShutdownState;
if( !( nShutdownState & ShutdownManager::SDS_WRAPUP_COMPLETE ) )
{
_lprint( "GameLog.txt", "onDeInit is called with SDS 0x%08X.\n", nShutdownState );
}
b_performanceUpdate = false;
g_DBTracker.dump();
void DeInitGame();
DeInitGame();
//LUA()->DeInitThread();
LUA()->DeInit();
LOG::DeInit();
FileLogHandler::DeInit();
return true;
}
bool _HerlockIntf::onKeyDown( int nVkCode )
{
return false;
}
void _HerlockIntf::onDrawUser( HDC dc )
{
static DWORD dwPrevTime = timeGetTime() - 1000;
if( dwPrevTime + 1000 < timeGetTime() )
{
void Draw();
Draw();
dwPrevTime = timeGetTime();
InvalidateRect( GetViewWindow(), NULL, false );
}
}
bool _HerlockIntf::onMessage( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
if( msg == WM_TIMER )
{
static bool bLoadingComplete = false;
if( !bLoadingComplete && ENV().GetString( "game.loading" ) == "complete" )
{
bLoadingComplete = true;
extern IStreamSocketConnection * g_pAuthConnection;
if( !g_pAuthConnection || !g_pAuthConnection->IsConnected() )
{
if( !ConnectToAuth() )
{
_cprint( "Connecting to the auth server failed. Check auth server status. IP:%s / PORT:%d\n", ENV().GetString( "io.auth.ip", "127.0.0.1" ).c_str(), ENV().GetInt( "io.auth.port", 4502 ) );
_cprint( "Enter 'connect auth' to retry.\n" );
FILELOG( "Connecting to the auth server failed. Check auth server status. IP:%s / PORT:%d", ENV().GetString( "io.auth.ip", "127.0.0.1" ).c_str(), ENV().GetInt( "io.auth.port", 4502 ) );
ENV().Remove( "game.loading" );
bLoadingComplete = false;
return true;
}
}
void SendGameServerLoginToAuth( const char * szServerName, const char * szServerScreenshotUrl, unsigned short nServerIdx, const char * szServerIP, int nServerPort );
SendGameServerLoginToAuth( ENV().GetString( "auth.server_name", "LeviathanServer" ).c_str(), ENV().GetString( "game.server_screenshot_url", "about:blank" ).c_str(), ENV().GetInt( "auth.server_idx", 1 ), ENV().GetString( "io.ip_address", "192.168.0.84" ).c_str(), ENV().GetInt( "io.port", 4514 ) );
while( 1 )
{
std::string strAuthConnectState = ENV().GetString( "auth.connect", "" );
if( strAuthConnectState.empty() )
Sleep( 1 );
else if( strAuthConnectState == "complete" )
break;
else if( strAuthConnectState == "failed" )
{
_cprint( "Registering this server to auth server with idx %d is failed.\n", ENV().GetInt( "auth.server_idx", 1 ) );
_cprint( "Enter 'connect auth' to retry.\n" );
FILELOG( "Registering this server to auth server with idx %d is failed.", ENV().GetInt( "auth.server_idx", 1 ) );
ENV().Remove( "game.loading" );
ENV().Remove( "auth.connect" );
bLoadingComplete = false;
return true;
}
}
std::string strUploadConnectState = ENV().GetString( "upload.connect", "" );
if( strUploadConnectState.empty() )
{
ENV().Set( "upload.connect", "failed" );
ConnectToUpload();
}
StartAccept();
// 접속을 받기 시작한 이후에 ScheduledCommand 실행을 시작
ScheduledCommandManager::Instance().Init();
}
#ifdef _MEM_USAGE_DEBUG
static DWORD dwPrevTime = GetTickCount();
DWORD dwCurrentTime = GetTickCount();
if( ENV().GetInt( "game.mem_usage_info_save_interval" ) && dwPrevTime + ENV().GetInt( "game.mem_usage_info_save_interval" ) < dwCurrentTime )
{
dwPrevTime = dwCurrentTime;
XSEH::WriteAllocCountInfo( "MemUsageInfo.txt" );
HANDLE hFile = INVALID_HANDLE_VALUE;
if ( (hFile = CreateFile( "MemUsageInfo.txt", GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL )) != INVALID_HANDLE_VALUE )
{
SetFilePointer( hFile, 0, NULL, FILE_END );
WriteHeapUsageInfo( hFile );
CloseHandle( hFile );
}
}
#endif
}
if( GetViewMode() == ArcadiaFrameworkIntf::VIEW_USER )
{
if( msg == WM_PAINT || msg == WM_TIMER )
{
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(hWnd, &ps);
onDrawUser( hdc );
EndPaint( hWnd, &ps );
return true;
}
}
if( GetViewMode() == ArcadiaFrameworkIntf::VIEW_LOG )
{
if( msg == WM_TIMER )
{
static DWORD dwPrevTime = GetTickCount();
if( GetTickCount() > dwPrevTime + 200 )
{
dwPrevTime = GetTickCount();
InvalidateRect( hWnd, NULL, false );
}
return true;
}
if( msg == WM_PAINT )
{
PAINTSTRUCT ps;
HDC hdc;
hdc = BeginPaint(hWnd, &ps);
onDrawLog( hdc );
EndPaint( hWnd, &ps );
return true;
}
}
return false;
}
struct _ProfilerScreenOutput
{
_ProfilerScreenOutput( ArcadiaCommandResultReceiver * pReceiver ) { m_pReceiver = pReceiver; }
void operator()( const char * szString, ... )
{
char p[2048];
va_list ap;
va_start(ap, szString);
s_vsprintf(p, _countof(p), szString, ap);
va_end(ap);
std::string str = p;
XStringUtil::Replace( str, "%", "%%" );
m_pReceiver->onWrite( str.c_str() );
}
ArcadiaCommandResultReceiver * m_pReceiver;
};
struct _ProfilerFileOutput
{
_ProfilerFileOutput( const char* szFileName )
{
fp = NULL;
fopen_s( &fp, szFileName, "a+" );
}
~_ProfilerFileOutput()
{
if( fp ) fclose( fp );
}
void operator()( const char * szString, ... )
{
char p[2048];
va_list ap;
va_start(ap, szString);
s_vsprintf(p, _countof(p), szString, ap);
va_end(ap);
if( fp ) fwrite( p, 1, strlen(p), fp );
}
FILE *fp;
};
bool _HerlockIntf::onCommand( const char* szTarget,
const char* szFrom,
const char *szFullCmd,
std::vector< std::string > & vList,
ArcadiaCommandResultReceiver & receiver )
{
LOG::Log11N4S( LM_CHEAT,
0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
szTarget, LOG::STR_NTS, szFrom, LOG::STR_NTS,
"", LOG::STR_NTS,
szFullCmd, LOG::STR_NTS );
if( !_stricmp( szFullCmd, "view" ) )
{
return true;
}
else if( szFullCmd[0] == '#' )
{
std::string strCmd = &szFullCmd[1];
XStringUtil::Trim( strCmd );
if( strCmd.size() > GameRule::CHAT_MAX_LENGTH )
{
receiver.onWrite( "The submitted message is too long. (Limit is %u characters.)\n", GameRule::CHAT_MAX_LENGTH );
return false;
}
std::string strResult;
LuaVM::GlobalInst()->RunString( strCmd.c_str(), &strResult );
if( !strResult.empty() && strResult != "nil" )
receiver.onWrite( strResult.c_str() );
return true;
}
else if( !_stricmp( vList[0].c_str(), "lua_do" ) )
{
if( vList.size() > 1 )
{
std::string strCmd = vList[1];
XStringUtil::Trim( strCmd );
if( strCmd.size() > GameRule::CHAT_MAX_LENGTH )
{
receiver.onWrite( "The submitted message is too long. (Limit is %u characters.)\n", GameRule::CHAT_MAX_LENGTH );
return false;
}
std::string strResult;
LuaVM::GlobalInst()->RunString( strCmd.c_str(), &strResult );
if( !strResult.empty() && strResult != "nil" )
receiver.onWrite( strResult.c_str() );
return true;
}
}
else if( !_stricmp( vList[0].c_str(), "lua_run" ) )
{
if( vList.size() > 1 )
{
std::string strCmd = vList[1];
XStringUtil::Trim( strCmd );
LuaVM::GlobalInst()->LoadScript( strCmd.c_str(), true );
return true;
}
}
else if( !_stricmp( vList[0].c_str(), "erase_auto" ) )
{
if( vList.size() > 1 )
{
StructPlayer::EraseFromAutoAccount( atoi( vList[1].c_str() ) );
}
return true;
}
else if( !_stricmp( vList[0].c_str(), "connect" ) )
{
if( vList.size() > 1 )
{
if( vList[1] == "auth" )
{
if( ENV().GetString( "game.loading" ) == "complete" || ENV().GetString( "auth.connect" ) == "complete" )
receiver.onWrite( "Already once connected to auth server.\n" );
else
ENV().Set( "game.loading", "complete" );
}
else if( vList[1] == "upload" )
{
ConnectToUpload();
}
}
return true;
}
else if( !_stricmp( vList[0].c_str(), "show_process_usage" ) )
{
receiver.onWrite( " - Network Processing Info - \n" );
auto it = g_NetworkReceiverPerformanceTracker.m_data.begin();
for( ; it != g_NetworkReceiverPerformanceTracker.m_data.end() ; ++it )
{
// 총 처리 시간 1초 미만인 경우 보여주지 않음.
if( (*it).second.m_totalTime < 1000 )
continue;
receiver.onWrite( "Packet ID[%u] - Count:%u, ElapsedTime:%ums\n",
(*it).first, (*it).second.m_count, (*it).second.m_totalTime );
}
receiver.onWrite( " - Scheduling Processing Info - \n" );
receiver.onWrite( "Scheduling[Player] - Count:%u, ElapsedTime:%ums\n",
g_PlayerPerformanceTracker.m_count, g_PlayerPerformanceTracker.m_totalTime );
receiver.onWrite( "Scheduling[Summon] - Count:%u, ElapsedTime:%ums\n",
g_SummonPerformanceTracker.m_count, g_SummonPerformanceTracker.m_totalTime );
receiver.onWrite( "Scheduling[Monster] - Count:%u, ElapsedTime:%ums\n",
g_MonsterPerformanceTracker.m_count, g_MonsterPerformanceTracker.m_totalTime );
return true;
}
return false;
}
XEnvStruct& CMD()
{
static XEnvStruct cmd;
return cmd;
}
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <string>
int TestLinuxConnection()
{
_cprint("Attempt to test conenction to linux server...\n");
int PORT = 4000;
const char* SERVER_HOST = "127.0.0.1";
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
_cprint("WSAStartup failed\n");
return 1;
}
// use getaddrinfo to resolve domain -> IP
addrinfo hints, *result = nullptr;;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET; // force IPv4 (or use AF_UNSPEC for v4/v6)
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
std::string portStr = std::to_string(static_cast<long long>(PORT));
int rc = getaddrinfo(SERVER_HOST, portStr.c_str(), &hints, &result);
if (rc != 0)
{
_cprint("getaddrinfo failed: %d\n", rc);
WSACleanup();
return 1;
}
// Create socket
ConnectSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ConnectSocket == INVALID_SOCKET)
{
_cprint("Error at socket(): %d\n", WSAGetLastError() );
FILELOG("Error at socket(): %d", WSAGetLastError() );
freeaddrinfo(result);
WSACleanup();
return 1;
}
// Connect to first resolved address
if (connect(ConnectSocket, result->ai_addr, (int)result->ai_addrlen) == SOCKET_ERROR)
{
_cprint("Unable to connect: %d\n", WSAGetLastError() );
//FILELOG("Unable to connect: %d", WSAGetLastError() );
closesocket(ConnectSocket);
freeaddrinfo(result);
WSACleanup();
return 1;
}
freeaddrinfo(result);
// Sending a packet with specific string here
std::string packet = "HELLO:GAME_SERVER";
send(ConnectSocket, packet.c_str(), (int)packet.size(), 0);
_cprint("Sent packet: %s\n", packet.c_str());
//FILELOG("Sent packet: %s", packet.c_str());
// receive response
char buffer[1024] = { 0 };
int bytesReceived = recv(ConnectSocket, buffer, sizeof(buffer), 0);
if (bytesReceived > 0)
{
std::string response(buffer, bytesReceived);
_cprint("Response: %s\n", response);
//FILELOG("Response: %s", response);
}
else
{
_cprint("No Responce!\n");
//FILELOG("No Responce!");
return 1;
}
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
void onInitArcadiaFramework()
{
// Fraun linux server coordinator 9/23/2025
int nResult = 0;
#ifdef FRAUN_COORDINATOR_SERVER
nResult = TestLinuxConnection();
#endif
if (nResult == 0)
{
_cprint("[Server start]: Authorized\n");
}
else
{
_cprint("[Server start]: Unauthorized. Exit!\n");
ExitProcess(1);
}
// init default environment
InitDefaultEnv();
// 파일에서 로드
CMD().LoadFromFile( "Commands.opt" );
ENV().LoadFromFile( "GameServer.eop", "*", true );
if(GameRule::bHardcore)
{
// hardcode server면 pkserver가 되어야한다
GameRule::bIsPKServer = true;
GameRule::fHardcoreExpRate = 1.0f;
}
// Handle concurrent use of GameServer.opt
// Only keys specified in game.local_setting_list are used.
// The values in game.local_setting_list must be in the format: [type keyName]|[type keyName]|...
// Example: game.local_setting_list: N game.max_level|S db.c.server|N db.c.port|S db.user.server|N db.user.port
std::string strLocalSettingList = ENV().GetString( "game.local_setting_list", "" );
if( !strLocalSettingList.empty() )
{
XEnvStruct envLocalSetting;
if( envLocalSetting.LoadFromFile( "GameServer.opt" ) )
{
std::vector< std::string > vLocalSetting;
XStringUtil::Split( strLocalSettingList.c_str(), vLocalSetting, "|" );
for( std::vector< std::string >::const_iterator it = vLocalSetting.begin() ; it != vLocalSetting.end() ; ++it )
{
const char * pszKey = (*it).c_str() + 2;
if( !envLocalSetting.IsExist( pszKey ) )
continue;
switch( *(*it).c_str() )
{
case 'S': ENV().Set( pszKey, envLocalSetting.GetString( pszKey ) ); break;
case 'F': ENV().Set( pszKey, envLocalSetting.GetFloat( pszKey ) ); break;
case 'V': ENV().Set( pszKey, envLocalSetting.GetVector( pszKey ) ); break;
case 'Q': ENV().Set( pszKey, envLocalSetting.GetQuaternion( pszKey ) ); break;
case 'N': ENV().Set( pszKey, envLocalSetting.GetInt( pszKey ) ); break;
case 'T': ENV().Set( pszKey, (short)envLocalSetting.GetInt( pszKey ) ); break;
}
}
}
ENV().Remove( "game.local_setting_list" );
}
// 패스워드 삭제
CMD().Remove( "db.billing.account" );
CMD().Remove( "db.billing._password" );
CMD().Remove( "db.c.account" );
CMD().Remove( "db.c._password" );
CMD().Remove( "db.user.account" );
CMD().Remove( "db.user._password" );
ENV().Remove( "db.billing.account" );
ENV().Remove( "db.billing._password" );
ENV().Remove( "db.c.account" );
ENV().Remove( "db.c._password" );
ENV().Remove( "db.user.account" );
ENV().Remove( "db.user._password" );
myFrameworkIntf.SetConsoleEopFileName( "GameServer.eop" );
// 읽기 전용 필드 설정
ENV().SetReadOnly( "game.party_exp_rate" );
ENV().SetReadOnly( "game.no_collision_check" );
ENV().SetReadOnly( "game.disable_dungeon_raid_siege" );
ENV().SetReadOnly( "game.limit_game_time" );
ENV().SetReadOnly( "game.max_healthy_game_time" );
ENV().SetReadOnly( "game.max_tired_game_time" );
ENV().SetReadOnly( "game.log_required_state_list" );
ENV().SetReadOnly( "game.log_required_item_list" );
ENV().SetReadOnly( "game.farm_normal_summon_exp" );
ENV().SetReadOnly( "game.farm_growth_summon_exp" );
ArcadiaFrameworkIntf::SetFrameworkInterface( &myFrameworkIntf );
ArcadiaFrameworkIntf::AddWatchList( "game.server_version" );
ArcadiaFrameworkIntf::AddWatchList( "engine.ar_time" );
ArcadiaFrameworkIntf::AddWatchList( "engine.count_client" );
ArcadiaFrameworkIntf::AddWatchList( "engine.count_movable" );
ArcadiaFrameworkIntf::AddWatchList( "engine.count_static" );
ArcadiaFrameworkIntf::AddWatchList( "game.user_count" );
ArcadiaFrameworkIntf::AddWatchList( "game.item_count" );
ArcadiaFrameworkIntf::AddWatchList( "io.connection" );
ArcadiaFrameworkIntf::AddWatchList( "iocp.dis_count" );
ArcadiaFrameworkIntf::AddWatchList( "io.send_count" );
ArcadiaFrameworkIntf::AddWatchList( "iocp.send_rest_bytes" );
ArcadiaFrameworkIntf::AddWatchList( "iocp.max_alloc_size" );
ArcadiaFrameworkIntf::AddWatchList( "io.recv_count" );
ArcadiaFrameworkIntf::AddWatchList( "db.user.work_active" );
ArcadiaFrameworkIntf::AddWatchList( "db.user.work_pending" );
ArcadiaFrameworkIntf::AddWatchList( "db.user.work_total" );
ArcadiaFrameworkIntf::AddWatchList( "db.user.exec_query" );
ArcadiaFrameworkIntf::AddWatchList( "db.user.remain_query" );
}
// 1초마다 서버 전체 성능을 기록
unsigned __stdcall performanceLogFunc( void* )
{
while( b_performanceUpdate )
{
if( g_bPerformanceTracing )
{
// Scheduling Thread 관련 성능 기록
FileLogHandler::GetFileLogHandler()->LogStringToFileEx( NULL, "PerformanceTrackingLog",
"%Y-%m-%d.log", "[Scheduling] Player Count[%u] Time[%ums]", g_PlayerPerformanceTracker.m_count, g_PlayerPerformanceTracker.m_totalTime );
FileLogHandler::GetFileLogHandler()->LogStringToFileEx( NULL, "PerformanceTrackingLog",
"%Y-%m-%d.log", "[Scheduling] Summon Count[%u] Time[%ums]", g_SummonPerformanceTracker.m_count, g_SummonPerformanceTracker.m_totalTime );
FileLogHandler::GetFileLogHandler()->LogStringToFileEx( NULL, "PerformanceTrackingLog",
"%Y-%m-%d.log", "[Scheduling] Monster Count[%u] Time[%ums]", g_MonsterPerformanceTracker.m_count, g_MonsterPerformanceTracker.m_totalTime );
// IOCP 관련 성능 기록
for( auto it = g_NetworkReceiverPerformanceTracker.m_data.begin() ; it != g_NetworkReceiverPerformanceTracker.m_data.end() ; ++it )
{
// 최소 0ms 이상 처리한 것들만 찍어준다.
if( (*it).second.m_totalTime == 0 )
continue;
FileLogHandler::GetFileLogHandler()->LogStringToFileEx( NULL, "PerformanceTrackingLog",
"%Y-%m-%d.log", "[IOCP] PacketID[%u] Count[%u] Time[%ums]", (*it).first, (*it).second.m_count, (*it).second.m_totalTime );
}
// Thread CPU사용량 관련 기록
// 현재 vWatchingThreadList에 Lock이 없어 쓰레드가 소멸되면 iterator 무효화가 일어날 수 있다..
// 지금은 게임 서버 꺼질 때 말고는 vWatchingThreadList에 삭제 처리를 하지 않는다. 보수해야할 코드.
{
THREAD_SYNCRONIZE( &XThreadMonitor::xWatchingThreadListCS );
for( auto it = XThreadMonitor::vWatchingThreadList.begin() ; it != XThreadMonitor::vWatchingThreadList.end() ; ++it )
{
FileLogHandler::GetFileLogHandler()->LogStringToFileEx( NULL, "PerformanceTrackingLog",
"%Y-%m-%d.log", "[Thread] ThreadName[%s] BouncingCount[%u]", (*it).GetThreadName(), (*it).GetBouncingCount() );
}
}
}
// 1초 후에 다시 수행
Sleep( g_nIntervalTimeToLogPerformance );
}
return 0;
}