#include "stdafx.h" #include "KCommandBuilder.h" #include #include #include "SBotManager.h" #include "SGameMessage.h" #include #include "LuaVM.h" extern SBotManager* g_pSBotMng; namespace { /* // 필터링 // : 우선처리 // 사용1) 타입에 관계없이 공통으로 사용하는 경우 // 사용2) sub Type 으로 정하기에는 너무 방대한 경우 // // ex) // 입력 : > ?opt.intf.MINIMAP_OPEN // 결과 : opt.intf.MINIMAP_OPEN 0; */ enum { FILTER_GET = 0, FILTER_RUN, }; const int g_nFilterTypeCount = 2; const char* g_szFilterType[g_nFilterTypeCount] = { "?", // get "!", // run old-style game command : 기존 커맨드 명령어를 지원하기 위해서 ENV 등록되지 않은 경우에라도 ! 를 붙이면 자동 등록. }; /* // 예약어 // : 우선처리 // : 히스토리에 남지 않는다. // 사용1) 출력용인 경우, list/history 등 // // ex) // 입력 : > history opt // 결과 : opt 에 관련된 history 출력된다. */ enum { RESERVED_HISTORY = 0, RESERVED_LIST, RESERVED_HELP, RESERVED_REFRESH, RESERVED_SET, RESERVED_GET, }; const int g_nReservdCount = 6; const char* g_szReserv[g_nReservdCount] = { "history", // history "list", // env key list "help", // help "refresh", // refresh -> 게임에 apply, update "set", "get", // ? <-- 로 처리 }; /* // 커맨드 키 // : 커맨드 키 카테고리 // : 작업자들은 새로운 카테고리 추가시 꼭 타입 추가 요망!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // // ex) // 입력 : > game.game_light_ambient 0 0 0 // 결과 : 입력문을 게임에 적용한 후 결과 출력 */ enum { KEY_GAME = 0, KEY_OPT, KEY_DEBUG, KEY_LUA, KEY_DB, }; const char* g_szKeyType[] = { "game", // 게임 "opt", // 옵션 "debug", // build 나 oprint 의 경우 env 에 등록된 얘들 등 "lua", // 스크립트 과련 "db", // 디비 관련 }; // 옵션 서브 타입 enum { OPT_KEY_INTF = 0, OPT_KEY_GP, OPT_KEY_SOUND, }; const char* g_szOptKeyType[] = { "intf", // 인터페이스 "gp", // 그래픽 "sound", // 사운드 }; // 디버거 서브 타입 enum { DEBUG_KEY_INTF = 0, }; const char* g_szDebugType[] = { "intf", // 인터페이스 관련 }; const int g_nMaxHistoryNum = 100; typedef struct tagHISTORY_DATA { std::string m_strType; std::string m_strData; } HISTORY_DATA; }; struct KCommandEnvReceiver : public XEnvStruct::XEnvEventReceiver { public: KCommandEnvReceiver() {}; ~KCommandEnvReceiver() { m_vecGameList.clear(); m_vecOptionList.clear(); m_vecDebugList.clear(); m_vecLuaList.clear(); m_vecDBList.clear(); m_vecENVKeyList.clear(); }; virtual void onEnvInsert( const char* szFullKey ) { m_vecENVKeyList.push_back( szFullKey ); onEnvUpdate(szFullKey); }; virtual void onEnvUpdate( const char* szFullKey ) { // key 에 따라 std::vector vecKeyList; XStringUtil::Split( szFullKey, vecKeyList, "." ); if( !_stricmp( szFullKey, "debug.mask" ) ) { _set_oprint_mask( ENV().GetString( "debug.mask", "" ).c_str() ); } if( vecKeyList.size() < 2 ) { onProcErrorConsole( szFullKey ); return; } onProcConsole( szFullKey ); }; // Priority processing of filtering bool onNotifyFilter( std::vector vecStringList ) { std::string strFilter = vecStringList[0].substr( 0, 1 ); std::string strKey = vecStringList[0].substr( 1, vecStringList[0].size()-1 ); // ? : 출력 if( ::_stricmp(strFilter.c_str(), g_szFilterType[FILTER_GET]) == 0 ) { std::vector vecValueList; if( ENV().IsExist(strKey.c_str()) ) vecValueList.push_back( ENV().GetString(strKey.c_str()) ); onProcConsole( vecStringList[0].c_str(), vecValueList, true ); } return true; }; // 예약어 우선 처리 bool onNotifyReservedType( std::vector vecStringList ) { // help 처리 if( ::_stricmp(vecStringList[0].c_str(), g_szReserv[RESERVED_HELP]/*help*/) == 0 ) return onHelpUpdate(); if( vecStringList.size() < 2 ) return onProcErrorConsole( vecStringList[0].c_str() ); std::string strKey; XStringUtil::Format( strKey, "%s.%s", vecStringList[0].c_str(), vecStringList[1].c_str() ); std::vector vecValueList; // get 처리 : ? 필터링 처리와 같다 if( ::_stricmp(vecStringList[0].c_str(), g_szReserv[RESERVED_GET]/*get*/) == 0 ) { std::string strEnvKey = vecStringList[1]; std::vector vecValueList; if( ENV().IsExist(strEnvKey.c_str()) ) vecValueList.push_back( ENV().GetString(strEnvKey.c_str()) ); onProcConsole( strKey.c_str(), vecValueList, true ); return true; } // history 처리 if( ::_stricmp(vecStringList[0].c_str(), g_szReserv[RESERVED_HISTORY]/*history*/) == 0 ) getHistoryList( vecStringList[1].c_str(), vecValueList ); // list 처리 else if( ::_stricmp(vecStringList[0].c_str(), g_szReserv[RESERVED_LIST]/*list*/) == 0 ) vecValueList.assign( m_vecENVKeyList.begin(), m_vecENVKeyList.end() ); // 서브가 있으면 서브까지 검사 if( !vecValueList.empty() ) checkSubList( vecStringList[1].c_str(), vecValueList ); bool bOut = true; // refresh 는 아무 처리 없이 넘기면 된다. if( ::_stricmp(vecStringList[0].c_str(), g_szReserv[RESERVED_REFRESH]/*refresh*/) == 0 ) bOut = false; onProcConsole( strKey.c_str(), vecValueList, bOut ); return true; }; // help bool onHelpUpdate( const char* szKey = NULL ) { std::string strValue; //if( szKey == NULL ) //{ strValue = "■ 예약어와 필터링
"; strValue += ": 출력용이거나 우선 처리되어야 하는 경우 정의
"; strValue += ": history 에 남지 않는다.
"; strValue += "
"; strValue += "▷ 예약어
"; strValue += ": history - 입력 로그 ex) history game, history opt.intf ..
"; strValue += ": list - ENV 에 등록된 커맨드 ex) list game, list opt.gp ..
"; strValue += ": help - 도움말 ex) help
"; strValue += ": refresh - 화면 갱신 ex) refresh opt.intf.MINIMAP_OPEN ..
"; strValue += ": set - ENV 최초 등록할 경우 사용 ex) set game.game_light_ambient 0 0 0
"; strValue += ": get - ENV 등록된 커맨드의 값 출력 ex) get game.game_light_ambient
"; strValue += "
"; strValue += "▷ 필터링
"; strValue += ": ? - 커맨드의 결과값 도출 ex) ?otp.intf.MINIAMP_OPEN -> MINIMAP_OPEN 의 결과값을 얻는다.
"; strValue += ": ! - 무조건 ENV 등록(기존 커맨드 사용위해 예외처리) ex) !otp.intf.MINIAMP_OPEN
"; strValue += "
"; strValue += "
"; strValue += "■ 커맨드 타입과 서브 타입
"; strValue += ": 커맨드는 타입별로 정의하여 사용하여야 한다. !작업자 필독 요망!
"; strValue += "
"; strValue += "▷ 커맨드 타입
"; strValue += " - game : 게임으로 분류된 커맨드
"; strValue += " - opt : 옵션으로 분류된 커맨드
"; strValue += " - debug : env 에 등록된 build 내용, oprint 내용 등
"; strValue += " - lua : 스크립트로 분류된 커맨드
"; strValue += " - db : database 의 내용 확인 등, ex) > db.isitemicon 1234 -> 1234 가 아이템 db 에 있는지 검사
"; strValue += "
"; strValue += "▷ 서브 타입
"; strValue += " - 리스트 관리를 위해서 각 커맨드 타입의 서브 타입을 정의해서 사용해야 함.
"; strValue += " ex) opt.intf, opt.gp, opt.sound ... opt 의 서브 타입들
"; //} //else //{ // std::vector vecKeyList; // XStringUtil::Split( szKey, vecKeyList, "." ); //} if( !strValue.empty() ) { std::vector vecValueList; vecValueList.push_back( strValue ); onProcConsole( "help", vecValueList, true ); } return true; }; // 커맨드 타입 int getCommandType( const char* szKey ) { std::vector vecKeyList; XStringUtil::Split( szKey, vecKeyList, "." ); if( ::_stricmp(vecKeyList[0].c_str(), g_szKeyType[SMSG_CONSOLE_BUILDER::TYPE_GAME]) == 0 ) return SMSG_CONSOLE_BUILDER::TYPE_GAME; else if( ::_stricmp(vecKeyList[0].c_str(), g_szKeyType[SMSG_CONSOLE_BUILDER::TYPE_OPTION]) == 0 )return SMSG_CONSOLE_BUILDER::TYPE_OPTION; else if( ::_stricmp(vecKeyList[0].c_str(), g_szKeyType[SMSG_CONSOLE_BUILDER::TYPE_DEBUG]) == 0 ) return SMSG_CONSOLE_BUILDER::TYPE_DEBUG; else if( ::_stricmp(vecKeyList[0].c_str(), g_szKeyType[SMSG_CONSOLE_BUILDER::TYPE_LUA]) == 0 ) return SMSG_CONSOLE_BUILDER::TYPE_LUA; else if( ::_stricmp(vecKeyList[0].c_str(), g_szKeyType[SMSG_CONSOLE_BUILDER::TYPE_DB]) == 0 ) return SMSG_CONSOLE_BUILDER::TYPE_DB; return SMSG_CONSOLE_BUILDER::TYPE_GAME; }; // 히스토리 리스트 void getHistoryList( const char* szKey, std::vector & vecHistoryList ) { std::vector vecKeyList; XStringUtil::Split( szKey, vecKeyList, "." ); std::vector vecHistoryDataList; if( ::_stricmp(vecKeyList[0].c_str(), g_szKeyType[SMSG_CONSOLE_BUILDER::TYPE_GAME]) == 0 ) vecHistoryDataList.assign(m_vecGameList.begin(), m_vecGameList.end()); if( ::_stricmp(vecKeyList[0].c_str(), g_szKeyType[SMSG_CONSOLE_BUILDER::TYPE_OPTION]) == 0 ) vecHistoryDataList.assign(m_vecOptionList.begin(), m_vecOptionList.end()); if( ::_stricmp(vecKeyList[0].c_str(), g_szKeyType[SMSG_CONSOLE_BUILDER::TYPE_DEBUG]) == 0 ) vecHistoryDataList.assign(m_vecDebugList.begin(), m_vecDebugList.end()); if( ::_stricmp(vecKeyList[0].c_str(), g_szKeyType[SMSG_CONSOLE_BUILDER::TYPE_LUA]) == 0 ) vecHistoryDataList.assign(m_vecLuaList.begin(), m_vecLuaList.end()); if( ::_stricmp(vecKeyList[0].c_str(), g_szKeyType[SMSG_CONSOLE_BUILDER::TYPE_DB]) == 0 ) vecHistoryDataList.assign(m_vecDBList.begin(), m_vecDBList.end()); if( vecHistoryDataList.empty() ) return; std::string strData; std::vector::iterator it = vecHistoryDataList.begin(); while( it != vecHistoryDataList.end() ) { HISTORY_DATA data = (*it); strData = data.m_strType; strData += " "; strData += data.m_strData; vecHistoryList.push_back( strData ); it++; } }; // 리스트에서 서브가 있으면 서브까지 일치할때 저장하고 서브가 없으면 리턴 void checkSubList( const char* szKey, std::vector & vecList ) { std::vector vecKeyList; XStringUtil::Split( szKey, vecKeyList, "." ); // 서브 카테고리 가지고 있는지 검사 bool bIsHasSub = ( vecKeyList.size() > 1 ) ? true : false; std::vector vecValueList; std::string strData; std::vector::iterator it = vecList.begin(); while( it != vecList.end() ) { std::vector vecDataList; XStringUtil::Split( (*it).c_str(), vecDataList ); std::string strKey = vecDataList[0]; std::vector vecDataKeyList; XStringUtil::Split( strKey.c_str(), vecDataKeyList, "." ); std::string str = vecDataKeyList[0]; if( vecDataKeyList.size() > 2 ) { str += "."; str += vecDataKeyList[1]; } std::string strDataKey = ( bIsHasSub ) ? str : vecDataKeyList[0]; if( ::_stricmp(strDataKey.c_str(), szKey) == 0 ) vecValueList.push_back( (*it) ); it++; } vecList.clear(); if( !vecValueList.empty() ) vecList.assign( vecValueList.begin(), vecValueList.end() ); }; // 에러 리턴 bool onProcErrorConsole( const char* szKey ) { SMSG_CONSOLE_BUILDER msg; msg.m_strKey = szKey; msg.m_bOut = true; msg.m_nCommandType = getCommandType(szKey); msg.m_vecValueList.clear(); msg.m_nValueCount = static_cast(msg.m_vecValueList.size()); if( g_pSBotMng ) g_pSBotMng->ProcConsole( &msg ); return true; }; void onProcConsole( const char* szKey ) { SMSG_CONSOLE_BUILDER msg; msg.m_strKey = szKey; msg.m_bOut = false; msg.m_nCommandType = getCommandType(szKey); std::string strKey = szKey; if( msg.m_nCommandType == SMSG_CONSOLE_BUILDER::TYPE_GAME ) { std::vector vecKeyList; XStringUtil::Split( szKey, vecKeyList, "." ); strKey = strKey.substr( vecKeyList[0].size()+1, strKey.size()-vecKeyList[0].size() ); msg.m_strKey = strKey; } if( ENV().IsExist( szKey ) ) { std::vector vecValueList; XStringUtil::Split( ENV().GetString(szKey).c_str(), vecValueList, ";" ); msg.m_vecValueList.assign( vecValueList.begin(), vecValueList.end() ); } msg.m_nValueCount = static_cast(msg.m_vecValueList.size()); // 히스토리 등록 AddHistory( szKey, msg.m_nCommandType ); if( g_pSBotMng ) g_pSBotMng->ProcConsole( &msg ); }; void onProcConsole( const char* szKey, std::vector vecValueList, bool bOut = false ) { SMSG_CONSOLE_BUILDER msg; msg.m_strKey = szKey; msg.m_bOut = bOut; msg.m_nCommandType = getCommandType(szKey); msg.m_nValueCount = static_cast(vecValueList.size()); msg.m_vecValueList.assign( vecValueList.begin(), vecValueList.end() ); if( g_pSBotMng ) g_pSBotMng->ProcConsole( &msg ); }; void AddHistory( const char* szKey, int nType ) { if( !ENV().IsExist(szKey) ) return; HISTORY_DATA data; data.m_strType = szKey; data.m_strData = ENV().GetString(szKey); switch(nType) { case SMSG_CONSOLE_BUILDER::TYPE_GAME: m_vecGameList.push_back( data ); return; case SMSG_CONSOLE_BUILDER::TYPE_OPTION: m_vecOptionList.push_back( data ); return; case SMSG_CONSOLE_BUILDER::TYPE_DEBUG: m_vecDebugList.push_back( data ); return; case SMSG_CONSOLE_BUILDER::TYPE_LUA: m_vecLuaList.push_back( data ); return; case SMSG_CONSOLE_BUILDER::TYPE_DB: m_vecDBList.push_back( data ); return; } } private: std::vector m_vecGameList; std::vector m_vecOptionList; std::vector m_vecDebugList; std::vector m_vecLuaList; std::vector m_vecDBList; std::vector m_vecENVKeyList; }; KCommandEnvBuilder& GetCommandBuilder() { static KCommandEnvBuilder builder; return builder; } KCommandEnvBuilder::KCommandEnvBuilder() { m_pEnvReceiver = new KCommandEnvReceiver; ENV().SetEventReceiver( m_pEnvReceiver ); } KCommandEnvBuilder::~KCommandEnvBuilder() { delete m_pEnvReceiver; m_pEnvReceiver = NULL; } // set void KCommandEnvBuilder::BuildCommand( std::vector vecStringList ) { if( vecStringList.empty() ) return; if( m_pEnvReceiver == NULL ) return; // 필터링 우선 처리 if( IsFiltering( vecStringList ) ) return; // 예약어 우선 처리 if( IsReservedType( vecStringList ) ) return; std::string strKey = vecStringList[0]; bool bCheck = true; // ! 인지 검사 bCheck = CheckFiltering( strKey ); // Set 인지 검사 if( bCheck ) bCheck = CheckReservedType( strKey, vecStringList ); int nType = CheckType( strKey ); // 찾는 키가 없으므로 에러 리턴 if( bCheck && !ENV().IsExist(strKey.c_str()) ) { m_pEnvReceiver->onProcErrorConsole( strKey.c_str() ); return; } // 이도 저도 아니면 타입에 따라 if( vecStringList.size() > 1 ) { std::string strValue; for( int i = 1; i < static_cast(vecStringList.size()); i++ ) { if( i != 1 ) strValue += ";"; strValue += vecStringList[i]; } ENV().Set( strKey.c_str(), strValue.c_str() ); } // 값이 없으면 실행만 하면 되므로 env 넣지 않고 바로 호출 else { // // NOTE! 이전의 똑같은 msg에서 env에 들어있던 값이 파라미터로 들어가는 수가 있다! // // 수정 by 최지영(2006-06-07) : 게임의 다른 부분에 영향???? // ENV().Remove(strKey.c_str()); // 따라서 삭제 m_pEnvReceiver->onEnvUpdate( strKey.c_str() ); } } const bool KCommandEnvBuilder::IsFiltering( std::vector vecStringList ) { std::string strFilter = vecStringList[0].substr( 0, 1 ); for( int i = 0; i < g_nFilterTypeCount; i++ ) { if( ::_stricmp(strFilter.c_str(), g_szFilterType[i]) == 0 ) { if( ::_stricmp(strFilter.c_str(), g_szFilterType[FILTER_RUN]) == 0 ) return false; return m_pEnvReceiver->onNotifyFilter( vecStringList ); } } return false; } const bool KCommandEnvBuilder::IsReservedType( std::vector vecStringList ) { for( int i = 0; i < g_nReservdCount; i++ ) { if( ::_stricmp(vecStringList[0].c_str(), g_szReserv[i]) == 0 ) { // Set 할 경우 등록시키는 절차로.. if( ::_stricmp(vecStringList[0].c_str(), g_szReserv[RESERVED_SET]) == 0 ) return false; return m_pEnvReceiver->onNotifyReservedType( vecStringList ); } } return false; } const int KCommandEnvBuilder::CheckType( std::string & strKey ) { std::vector vecStringList; XStringUtil::Split( strKey.c_str(), vecStringList, "." ); if( vecStringList.size() > 1 ) { if( ::_stricmp(vecStringList[0].c_str(), g_szKeyType[SMSG_CONSOLE_BUILDER::TYPE_OPTION]) == 0 ) return SMSG_CONSOLE_BUILDER::TYPE_OPTION; if( ::_stricmp(vecStringList[0].c_str(), g_szKeyType[SMSG_CONSOLE_BUILDER::TYPE_DEBUG]) == 0 ) return SMSG_CONSOLE_BUILDER::TYPE_DEBUG; if( ::_stricmp(vecStringList[0].c_str(), g_szKeyType[SMSG_CONSOLE_BUILDER::TYPE_LUA]) == 0 ) return SMSG_CONSOLE_BUILDER::TYPE_LUA; if( ::_stricmp(vecStringList[0].c_str(), g_szKeyType[SMSG_CONSOLE_BUILDER::TYPE_GAME]) == 0 ) return SMSG_CONSOLE_BUILDER::TYPE_GAME; } XStringUtil::Format( strKey, "%s.%s", g_szKeyType[SMSG_CONSOLE_BUILDER::TYPE_GAME], vecStringList[0].c_str() ); return SMSG_CONSOLE_BUILDER::TYPE_GAME; } // 예외 처리 : ! 인 경우는 key exist 유효성 검사 하지 않고 무조건 Set 해 주어야 한다. const bool KCommandEnvBuilder::CheckFiltering( std::string & strKey ) { std::string strFilter = strKey.substr( 0, 1 ); if( ::_stricmp(strFilter.c_str(), g_szFilterType[FILTER_RUN]) == 0 ) { strKey = strKey.substr( 1, strKey.size()-1 ); return false; } return true; } // Set 예약어 : key exist 유효성 검사 하지 않고 무조건 Set 해준다. const bool KCommandEnvBuilder::CheckReservedType( std::string & strKey, std::vector& vecStringList ) { if( ::_stricmp(strKey.c_str(), g_szReserv[RESERVED_SET]) == 0 && vecStringList.size() > 2 ) { strKey = vecStringList[1]; vecStringList.erase( vecStringList.begin() ); return false; } return true; }