diff --git a/CMakeLists.txt b/CMakeLists.txt index 75172af..b90f648 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.15) project(dnf-utils) +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + add_subdirectory(bsdiff) add_subdirectory(bzip2) add_subdirectory(libnpk) @@ -10,3 +12,4 @@ add_subdirectory(lua) add_subdirectory(luatinker) add_subdirectory(sgutil) add_subdirectory(updater) +add_subdirectory(ace_test) diff --git a/ace_test/CMakeLists.txt b/ace_test/CMakeLists.txt new file mode 100644 index 0000000..35a2e40 --- /dev/null +++ b/ace_test/CMakeLists.txt @@ -0,0 +1,25 @@ +set(WTL_DIR $ENV{LIBRARIES_SDK_ROOT}/wtl) + +set(CYCLONE_DIR $ENV{CYCLONE_SDK_ROOT}) + +set(RapidJSON_DIR $ENV{LIBRARIES_SDK_ROOT}/rapidjson/cmake) +find_package(RapidJSON REQUIRED) + +set(OPENSSL_ROOT_DIR $ENV{LIBRARIES_SDK_ROOT}/openssl) + +set(ZLIB_USE_STATIC_LIBS True) +set(ZLIB_ROOT $ENV{LIBRARIES_SDK_ROOT}/zlib) + +set(CURL_DIR $ENV{LIBRARIES_SDK_ROOT}/libcurl/lib/cmake/CURL) +find_package(CURL CONFIG REQUIRED) + +set(GAME_PROTO_DIR ${CMAKE_CURRENT_SOURCE_DIR}/aCommon/proto) +set(ACE_CLIENT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/aCommon/ace_sdk/client) +set(ACE_SERVER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/aCommon/ace_sdk/server) + +set(Protobuf_DIR $ENV{LIBRARIES_SDK_ROOT}/protobuf/cmake) +find_package(Protobuf CONFIG REQUIRED) + +add_subdirectory(aClient) +add_subdirectory(aCommon) +add_subdirectory(aServer) diff --git a/ace_test/aClient/AceClientInterface.cpp b/ace_test/aClient/AceClientInterface.cpp new file mode 100644 index 0000000..18dace3 --- /dev/null +++ b/ace_test/aClient/AceClientInterface.cpp @@ -0,0 +1,123 @@ +#include "stdafx.h" +#include "AceClientInterface.h" + +#include +#include +#include + +bool AceClientInterface::init() +{ + //init ace sdk client protocol binding + m_protoBindingInitRetCode = AceProtocolBindingSDK::__ace_sdk_protocol_binding_init(); + if (m_protoBindingInitRetCode != ACE_SDK_RESULT_OK) + { + printf(">>ACE fail to init ace sdk client proto binding, ret : %d\n", m_protoBindingInitRetCode); + //continue even failed... + } + printf(">>ACE SDK client proto binding init success.\n"); + + //init ace sdk + AceSdkResult ret = ace_sdk_client_init(); + if(ret!= ACE_SDK_RESULT_OK) + { + printf(">>ACE fail to init ace sdk client, ret : %d\n", ret); + return false; + } + return true; +} + +void AceClientInterface::deinit() +{ + AceSdkResult ret = ace_sdk_client_deinit(); +} + +bool AceClientInterface::onServerLoginReply(const char* accountID, uint32_t worldID, + const char* loginToken, + const char* lightFeatureName, uint32_t lightFeatureDataCRC, + const uint8_t* lightFeatureData, uint32_t lightFeatureDataLengh) +{ + //call ace client login + AceSdkResult ret = ace_sdk_client_log_in( + accountID, ACE_SDK_ACCOUNT_TYPE_QQ, + worldID, loginToken + ); + if(ret != ACE_SDK_RESULT_OK) + { + printf(">>ACE fail to call ace_sdk_client_log_in, ret : %d\n", ret); + return false; + } + + //call ace client light feature data + AceProtocolBindingSDK::g__ace_sdk_on_receive_signature( + lightFeatureName, + lightFeatureData, + lightFeatureDataLengh, + lightFeatureDataCRC + ); + return true; +} + +void AceClientInterface::onServerLogout() +{ + AceSdkResult ret = ace_sdk_client_log_out(); + if(ret != ACE_SDK_RESULT_OK) + { + printf(">>ACE fail to call ace_sdk_client_log_out, ret : %d\n", ret); + } +} + + +void AceClientInterface::getClientTickPacket(uint8_t* out_buffer, uint32_t& out_len) +{ + int64_t timeNow = cyclone::sys_api::utc_time_now(); + if(timeNow - m_lastTickTime < 100ll*1000ll) + { + out_len = 0; + return; + } + m_lastTickTime = timeNow; + AceSdkClientPacket packet; + AceSdkResult ret = ace_sdk_client_get_packet(&packet); + if (ret == ACE_SDK_RESULT_OK) + { + printf(">>ACE ace_sdk_client_get_packet, len : %d\n", packet.len); + out_len = packet.len; + memcpy(out_buffer, packet.buffer, packet.len); + } + else + { + out_len = 0; + return; + } +} + +void AceClientInterface::onServerTickPacket(const uint8_t* input_buffer, uint32_t input_len) +{ + AceSdkResult ret = ace_sdk_client_on_packet_received(input_buffer, input_len); + if(ret != ACE_SDK_RESULT_OK) + { + printf(">>ACE fail to call ace_sdk_client_on_packet_received, ret : %d\n", ret); + } +} + +uint32_t AceClientInterface::getProtoBindingData(uint8_t* bindDataBuf, uint32_t buffSize) +{ + AceProtocolBindingSDK::AceSdkAntiDataInfo bindingData; + memset(&bindingData, 0, sizeof(bindingData)); + + AceProtocolBindingSDK::g__ace_sdk_get_report_data3(&bindingData); + uint32_t dataLength = bindingData.anti_data_len_; + + if (bindingData.anti_data_len_ <= buffSize) + { + memcpy(bindDataBuf, bindingData.anti_data_, bindingData.anti_data_len_); + } + else + { + printf(">>ACE fail to get proto binding data, buffer size too small!\n"); + } + + AceProtocolBindingSDK::g__ace_sdk_del_report_data(&bindingData); + return dataLength; +} + diff --git a/ace_test/aClient/AceClientInterface.h b/ace_test/aClient/AceClientInterface.h new file mode 100644 index 0000000..90fcca1 --- /dev/null +++ b/ace_test/aClient/AceClientInterface.h @@ -0,0 +1,26 @@ +#pragma once + +class AceClientInterface +{ +public: + bool init(); + void deinit(); + + uint32_t getPbRetCode() const { + return m_protoBindingInitRetCode; + } + + bool onServerLoginReply(const char* accountID, uint32_t worldID, + const char* loginToken, + const char* lightFeatureName, uint32_t lightFeatureDataCRC, + const uint8_t* lightFeatureData, uint32_t lightFeatureDataLengh); + void onServerLogout(); + + void getClientTickPacket(uint8_t* out_buffer, uint32_t& out_len); + void onServerTickPacket(const uint8_t* input_buffer, uint32_t input_len); + uint32_t getProtoBindingData(uint8_t* bindDataBuf, uint32_t buffSize); + +protected: + uint32_t m_protoBindingInitRetCode = 0; + int64_t m_lastTickTime = 0; +}; diff --git a/ace_test/aClient/AceReportInterface.cpp b/ace_test/aClient/AceReportInterface.cpp new file mode 100644 index 0000000..fa06227 --- /dev/null +++ b/ace_test/aClient/AceReportInterface.cpp @@ -0,0 +1,85 @@ +#include "stdafx.h" +#include "AceReportInterface.h" +#include "GameProto.h" +#include "GameProto.pb.h" +#include "GameClient.h" + +struct ACEReportStruct +{ + int32_t id; + Game::GameReportReq reportRequest; + ACEReport::CallbackFunction callback; +}; + + +ACEReport::ACEReport() +{ + m_nextID = 1; +} + +ACEReport::~ACEReport() +{ +} + +void ACEReport::init(GameClient* client) +{ + m_client = client; +} + +ACEReportContext ACEReport::createReportContext( + const char* account, + int32_t worldID, + const char* reported_name, + const char* reported_roldid, + ACEReportScene scene, + ACEReportCategory category, + const ACEReportReasonArray& reasons, + DNFReportEntranceID entranceID +) +{ + ACEReportStruct* ctx = new ACEReportStruct(); + ctx->id = m_nextID++; + ctx->callback = nullptr; + ctx->reportRequest.set_ctx_id(ctx->id); + ctx->reportRequest.set_reported_account_id(account); + ctx->reportRequest.set_reported_world_id(worldID); + ctx->reportRequest.set_reported_name(reported_name); + ctx->reportRequest.set_reported_roleid(reported_roldid); + ctx->reportRequest.set_report_scene(static_cast(scene)); + ctx->reportRequest.set_report_category(static_cast(category)); + ctx->reportRequest.set_report_entrance(static_cast(entranceID)); + for(ACEReportReason reason: reasons) + { + ctx->reportRequest.add_report_reason(static_cast(reason)); + } + + m_reportStructMap.insert(std::make_pair(ctx->id, ctx)); + return ctx; +} + +ACEReportStruct* ACEReport::getReport(ACEReportContext ctx) +{ + if (ctx == nullptr) return nullptr; + ReportStructMap::iterator it = m_reportStructMap.find(ctx->id); + if (it == m_reportStructMap.end()) return nullptr; + + return it->second; +} + +bool ACEReport::uploadReport(ACEReportContext ctx, CallbackFunction callback) +{ + ACEReportStruct* report = getReport(ctx); + if (report == nullptr) return false; + + Game::GameReportReq& reportReq = report->reportRequest; + if(reportReq.report_reason_size() == 0) + { + return false; + } + + report->callback = callback; + + m_client->sendProtobufMessage(GAME_PROTO_REPORT_REQ, &reportReq); + + return true; +} \ No newline at end of file diff --git a/ace_test/aClient/AceReportInterface.h b/ace_test/aClient/AceReportInterface.h new file mode 100644 index 0000000..15433ad --- /dev/null +++ b/ace_test/aClient/AceReportInterface.h @@ -0,0 +1,161 @@ +#pragma once + +#include +#include +#include + +enum ACEReportScene +{ + REPORT_SCENE_UGC = 1, + REPORT_SCENE_INFORMATION=2, + REPORT_SCENE_BATTLE=3, + REPORT_SCENE_ARTICLE=4, + REPORT_SCENE_COMMENT=5, + REPORT_SCENE_IMAGE=6, + REPORT_SCENE_ORGANIZE=7, + REPORT_SCENE_OTHER=8, +}; + +enum ACEReportCategory +{ + REPORT_CATEGORY_ILLEGAL = 1, + REPORT_CATEGORY_BEHAVIOR = 2, + REPORT_CATEGORY_CHEAT = 3, + REPORT_CATEGORY_STUDIO = 4, + + REPORT_CATEGORY_UGC = 7, + REPORT_CATEGORY_ORGANIZE = 8, + REPORT_CATEGORY_PERSONAL = 9, +}; + +enum ACEReportReason +{ + //发布违规信息 REPORT_CATEGORY_ILLEGAL + REPORT_REASON_ILLEGAL_ABUSE = 101, + REPORT_REASON_ILLEGAL_ADVERTISEMENT = 102, + REPORT_REASON_ILLEGAL_PORN = 103, + REPORT_REASON_ILLEGAL_POLITICS = 104, + REPORT_REASON_ILLEGAL_HARASS = 105, + REPORT_REASON_ILLEGAL_VIOLENT = 106, + REPORT_REASON_ILLEGAL_GAMBLE = 107, + REPORT_REASON_ILLEGAL_CHEAT = 108, + REPORT_REASON_ILLEGAL_PRIVACY_LEAKS = 109, + REPORT_REASON_IULEGAL_INFRINGEMENT = 110, + REPORT_REASON_ILLEGAL_OTHER = 199, + + //恶意游戏行为 REPORT_CATEGORY BEHAVIOR + REPORT_REASON_BEHAVIOR_FRIENDLYFIRE = 201, + REPORT_REASON_BEHAVIOR_FORM_CHEATER_TEAM = 202, + REPORT_REASON_BEHAVIOR_JOIN_CHEATER_TEAM = 203, + REPORT_REASON_BEHAVIOR_GUARDED_BY_CHEATER = 204, + REPORT_REASON_BEHAVIOR_EXPLOITING = 205, + REPORT_REASON_BEHAVIOR_AUTO_ROBOT = 206, + REPORT_REASON_BEHAVIOR_PASSIVE_PLAY = 207, + REPORT_REASON_BEHAVIOR_MALICIOUS_REPEAT = 208, + REPORT_REASON_BEHAVIOR_REFUSE_COOPERATE = 210, + REPORT_REASON_BEHAVIOR_OTHER=299, + + //使用作弊工具REPORT_CATEGORY_CHEAT + REPORT_REASON_CHEAT_SEE_THROUTH = 301, + REPORT_REASON_CHEAT_AUTO_AIM = 302, + REPORT_REASON_CHEAT_NO_RECOIL = 303, + REPORT_REASON_CHEAT_SPEED_UP = 304, + REPORT_REASON_CHEAT_DAMAGE_RANGE = 305, + REPORT_REASON_CHEAT_WALL_THROUGH = 306, + REPORT_REASON_CHEAT_FLYING = 307, + REPORT_REASON_CHEAT_TELEPORT = 308, + REPORT_REASON_CHEAT_INSTANT_KILLING = 309, + REPORT_REASON_CHEAT_AUTO_FIRING = 310, + REPORT_REASON_CHEAT_MACRO = 311, + REPORT_REASON_CHEAT_INF_PROJECTILES = 312, + REPORT_REASON_CHEAT_SHOOTING_SPEED = 313, + REPORT_REASON_CHEAT_INF_BULLETS = 314, + REPORT_REASON_CHEAT_EXTERNAL_DEVICE = 315, + REPORT_REASON_CHEAT_REMOTE_PICKING = 316, + REPORT_REASON_CHEAT_REMOTE_KILLING = 317, + REPORT_REASON_CHEAT_OTHER=399, + + //工作室行为REPORT_CATEGORY_STUDIO + REPORT_REASON_STUDIO_COMPETE_RESOURCE = 401, + REPORT_REASON_STUDIO_OFFLINE_DEAL = 402, + REPORT_REASON_STUDIO_ILLEGAL_BENEFITS = 403, + REPORT_REASON_STUDIO_TEAM = 404, + REPORT_REASON_STUDIO_MULTI_PLAVING = 405, + REPORT_REASON_STUDIO_OTHER=499, + + //自定义内容违规REPORT_CATEGORY_UGC + REPORT_REASON_UGC_ILLEGAL_NAME = 701, + REPORT_REASON_UGC_ILLEGAL_BRIEF = 702, + REPORT_REASON_UGC_PORN_CONTENT = 703, + REPORT_REASON_UGC_POLITICAL_CONTENT = 704, + REPORT_REASON_UGC_ABUSIVE_CONTENT = 705, + REPORT_REASON_UGC_FRAUDULENT_CONTENT = 706, + REPORT_REASON_UGC_OTHER=799, +}; + +enum DNFReportEntranceID +{ + DNF_REPORT_ENTRANCE_TEST = 0, +}; + +typedef std::vector ACEReportReasonArray; +struct ACEReportStruct; +typedef ACEReportStruct* ACEReportContext; + +class GameClient; + +class ACEReport +{ +public: + ACEReport(); + ~ACEReport(); + + void init(GameClient* client); + +public: + ACEReportContext createReportContext( + const char* account, + int32_t worldID, + const char* reported_name, + const char* reported_roldid, + + ACEReportScene scene, + ACEReportCategory category, + const ACEReportReasonArray& reasons, + DNFReportEntranceID entranceID = DNF_REPORT_ENTRANCE_TEST + ); + + //设置对局ID和时间,如果要举报和战局有关的信息,这两条必须同时设置 + void setReportBattleID(ACEReportContext ctx, const char* battle_id, int32_t battle_time); + //设置举报的描述信息,这里举报者自己描述的文本信息 + void setReportDesc(ACEReportContext ctx, const char* desc); + //设置举报内容,这里是指要举报的目标内容 + void setContent(ACEReportContext ctx, const char* content); + //设置举报的公会、战队、房间等组织的ID和名称 + void setGroupID(ACEReportContext ctx, const char* groupID, const char* groupName); + //设置举报者的头像URL,最大长度4096字寸,要求外网或者IDC个的多访问下载 + void setReportedProfileUrl(ACEReportContext ctx, const char* profileURL); + //添加举报的图片URL,可以添加多个(最多12个),单条最人长度4096字节,要求外网或者IDC能够访问下载 + void addReportedPictureURL(ACEReportContext ctx, const char* profileURL); + //添加举报的视频URL,可以添加多个(最务1个),单条最人长度4096字节,要求外网或者IDC能够访问下载 + void addReportedVideoURL(ACEReportContext ctx, const char* profileuRL); + //添加举报的语音URL,可以添加多个(最多12个),单条最大长度409 + void addReportedVoiceURL(ACEReportContext tx, const char* profileURL); + //添加其他需要添加的ID,例如文章T,房间T0等,每种类型都可以添加多个, addReportcontent(ctx, "room id",“123456"); + void addReportIDContent(ACEReportContext ctx, const char* idTyne, const char* idContent); + + //上报结果回调 + typedef std::function CallbackFunction; + bool uploadReport(ACEReportContext ctx, CallbackFunction callback); + +private: + void onReportResult(int32_t reportID, uint32_t result, const char* errorMessage); + ACEReportStruct* getReport(ACEReportContext ctx); + +private: + GameClient* m_client = nullptr; + + typedef std::map ReportStructMap; + ReportStructMap m_reportStructMap; + int32_t m_nextID = 0; +}; \ No newline at end of file diff --git a/ace_test/aClient/CMakeLists.txt b/ace_test/aClient/CMakeLists.txt new file mode 100644 index 0000000..122f4b4 --- /dev/null +++ b/ace_test/aClient/CMakeLists.txt @@ -0,0 +1,71 @@ + + +set(ACLIENT_SOURCE_FILES + stdafx.h + main.cpp + MainDialog.h + MainDialog.cpp + GameClient.h + GameClient.cpp + AceClientInterface.h + AceClientInterface.cpp + AceReportInterface.h + AceReportInterface.cpp + NetbarInterface.h + NetbarInterface.cpp +) + +set(ACLIENT_RC_FILES + aClient.rc +) + +source_group("Resource Files" FILES ${ACLIENT_RC_FILES}) + +set(ACLIENT_PRECOMPILE_FILE + stdafx.cpp +) + +foreach(filename ${ACLIENT_SOURCE_FILES}) + get_filename_component(ext ${filename} LAST_EXT ABSOLUTE) + string(TOLOWER ${ext} ext_lower) + if(${ext_lower} STREQUAL ".cpp" ) + set_source_files_properties( + ${filename} + PROPERTIES + COMPILE_FLAGS "/Yustdafx.h" + ) + endif() +endforeach() + +set_source_files_properties(${ACLIENT_PRECOMPILE_FILE} + PROPERTIES + COMPILE_FLAGS "/Ycstdafx.h" +) + +add_executable(aClient WIN32 + ${ACLIENT_SOURCE_FILES} + ${ACLIENT_RC_FILES} + ${ACLIENT_PRECOMPILE_FILE} +) + +target_include_directories(aClient +PRIVATE + ${ACE_CLIENT_DIR}/include + ${WTL_DIR}/include + ${CYCLONE_DIR}/include + ${GAME_PROTO_DIR} +) + +target_link_directories(aClient +PRIVATE + ${CYCLONE_DIR}/lib +) + +target_link_libraries(aClient +PRIVATE + aGameProto + cyclone.lib + ws2_32.lib + shlwapi.lib + winmm.lib +) diff --git a/ace_test/aClient/GameClient.cpp b/ace_test/aClient/GameClient.cpp new file mode 100644 index 0000000..26fef6c --- /dev/null +++ b/ace_test/aClient/GameClient.cpp @@ -0,0 +1,285 @@ +#include "stdafx.h" +#include "GameClient.h" +#include + +const char* GameClient::s_default_account_id = "979591"; +const uint32_t GameClient::s_default_world_id = 160; + +GameClient::GameClient() + : m_status(STATUS_DISCONNECTED) + , m_client(nullptr) + , m_looper(nullptr) +{ + m_clientTickBuffer = new uint8_t[2048]; +} + +GameClient::~GameClient() +{ + m_client = nullptr; + cyclone::Looper::destroy_looper(m_looper); + m_looper = nullptr; + delete[] m_clientTickBuffer; + m_clientTickBuffer = nullptr; +} + +bool GameClient::init() +{ + assert(m_status == STATUS_DISCONNECTED); + m_reportInterface.init(this); + m_clientNetbarInterface.init(this); + return m_aceClientInterface.init(); +} + +void GameClient::deinit() +{ + m_aceClientInterface.deinit(); +} + +void GameClient::connectToGameServer(const std::string& server_ip, uint16_t server_port) +{ + assert(m_status == STATUS_DISCONNECTED); + + m_server_ip = server_ip; + m_server_port = server_port; + CY_LOG(cyclone::L_DEBUG, "connect to %s:%d...", server_ip.c_str(), server_port); + + m_looper = cyclone::Looper::create_looper(); + + m_client = std::make_shared(m_looper, nullptr); + m_client->m_listener.on_connected = std::bind(&GameClient::onConnected, this, std::placeholders::_1, std::placeholders::_3); + m_client->m_listener.on_message = std::bind(&GameClient::onMessage, this, std::placeholders::_2); + m_client->m_listener.on_close = std::bind(&GameClient::onClose, this); + + m_client->connect(cyclone::Address(m_server_ip.c_str(), m_server_port)); + + m_status = STATUS_CONNECTING; +} + +void GameClient::disconnectFromGameServer() +{ + if (m_client) + { + m_client->disconnect(); + m_status = STATUS_LOGGING_OUT; + } +} + +void GameClient::tick() +{ + if (m_looper) + { + m_looper->step(); + } + + if (m_status == STATUS_LOGGED_IN) + { + uint32_t packetLen = 0; + m_aceClientInterface.getClientTickPacket(m_clientTickBuffer, packetLen); + if (packetLen > 0) + { + Game::ClientTickPacket clientTickPacket; + clientTickPacket.mutable_client_packet()->assign((const char*)m_clientTickBuffer, packetLen); + + cyclone::Packet packet; + serializeProtoMessage(GAME_PROTO_CLIENT_PACKET, &clientTickPacket, packet); + m_client->send(packet.get_memory_buf(), packet.get_memory_size()); + } + + sendHeartBeat(); + } + + m_clientNetbarInterface.tick(); +} + +uint32_t GameClient::onConnected(cyclone::TcpClientPtr client, bool success) +{ + assert(m_status == STATUS_CONNECTING); + + CY_LOG(cyclone::L_DEBUG, "connect to %s:%d %s.", + client->get_server_address().get_ip(), client->get_server_address().get_port(), + success ? "OK" : "FAILED"); + + if (success) + { + m_status = STATUS_CONNECTED; + sendLoginRequest(s_default_account_id, s_default_world_id); + return 0; + } + else + { + return 1000 * 5; + } +} +void GameClient::sendLoginRequest(const char* accountID, int32_t worldID) +{ + assert(m_status == STATUS_CONNECTED); + + Game::LoginRequest loginRequest; + loginRequest.set_accound_id(accountID); + loginRequest.set_world_id(worldID); + loginRequest.set_pb_retcode(m_aceClientInterface.getPbRetCode()); + + cyclone::Packet packet; + serializeProtoMessage(GAME_PROTO_LOGIN_REQUEST, &loginRequest, packet); + m_client->send(packet.get_memory_buf(), packet.get_memory_size()); + + m_status = STATUS_LOGGING_IN; +} + + +void GameClient::onMessage(cyclone::TcpConnectionPtr conn) +{ + cyclone::RingBuf& buf = conn->get_input_buf(); + + for (;;) + { + cyclone::Packet packet; + if (!packet.build_from_ringbuf(GAME_PACKET_HEAD_SIZE, buf)) return; + + ::google::protobuf::Message* message = parserProtoMessage(packet); + switch (packet.get_packet_id()) + { + case GAME_PROTO_LOGIN_REPLY: + { + Game::LoginReply* loginReply = dynamic_cast(message); + onServerLoginReply(conn, loginReply); + } + break; + + case GAME_PROTO_SERVER_PACKET: + { + Game::ServerTickPacket* serverTickPacket = dynamic_cast(message); + onServerTickPacket(conn, serverTickPacket); + } + break; + + case GAME_PROTO_UGC_REPLY: + { + Game::UGCReply* ugcReply = dynamic_cast(message); + onServerUGCReply(conn, ugcReply); + } + break; + + case GAME_PROTO_NETBAR_RES: + { + Game::NetbarStatusRes* netbarResponse = dynamic_cast(message); + onServerNetbarResponse(conn, netbarResponse); + } + break; + } + } + +} + +void GameClient::onServerLoginReply(cyclone::TcpConnectionPtr conn, Game::LoginReply* reply) +{ + assert(m_status == STATUS_LOGGING_IN); + m_aceClientInterface.onServerLoginReply(s_default_account_id, s_default_world_id, + reply->ace_token().c_str(), + reply->light_feature().name().c_str(), + reply->light_feature().data_crc(), + (const uint8_t*)reply->light_feature().data().data(), + (uint32_t)reply->light_feature().data().size() + ); + + m_status = STATUS_LOGGED_IN; +} + +void GameClient::onServerTickPacket(cyclone::TcpConnectionPtr conn, Game::ServerTickPacket* reply) +{ + assert(m_status == STATUS_LOGGED_IN || m_status==STATUS_LOGGING_IN); + m_aceClientInterface.onServerTickPacket( + (const uint8_t*)(reply->server_packet().data()), + (uint32_t)(reply->server_packet().size()) + ); +} + +void GameClient::sendHeartBeat() +{ + assert(m_status == STATUS_LOGGED_IN); + + uint64_t timeNow = cyclone::sys_api::utc_time_now(); + if(timeNow-m_lastHeartBeatTime < 60 * 1000ll*1000ll) + { + return; + } + m_lastHeartBeatTime = timeNow; + + uint8_t bindBuffer[1024]; + uint32_t bindDataLength = m_aceClientInterface.getProtoBindingData(bindBuffer, sizeof(bindBuffer)); + + Game::HeartBeat heartBeat; + heartBeat.set_timestamp((int32_t)timeGetTime()); + heartBeat.mutable_pb_data()->assign((const char*)bindBuffer, bindDataLength); + + cyclone::Packet packet; + serializeProtoMessage(GAME_PROTO_HEART_BEAT, &heartBeat, packet); + m_client->send(packet.get_memory_buf(), packet.get_memory_size()); +} + +void GameClient::onServerUGCReply(cyclone::TcpConnectionPtr conn, Game::UGCReply* reply) +{ + assert(m_status == STATUS_LOGGED_IN); + + wchar_t wszTemp[2048]; + + UINT btn = MB_OK; + if (reply->result() == 0) + { + StringCchPrintfW(wszTemp, sizeof(wszTemp)/sizeof(wszTemp[0]), + L"UGC Reply: ContextID=%d, ErrorCode=%d, Result=%d", + reply->ugc_ctx_id(), + reply->error_code(), + reply->result() + ); + } + else + { + btn = MB_OK | MB_ICONERROR; + + wchar_t wszFiltedContent[1024]; + ::MultiByteToWideChar(CP_UTF8, 0, reply->filted_content().c_str(), -1, + wszFiltedContent, sizeof(wszFiltedContent) / sizeof(wszFiltedContent[0])); + + StringCchPrintfW(wszTemp, sizeof(wszTemp)/sizeof(wszTemp[0]), + L"UGC Reply: ContextID=%d, ErrorCode=%d, Result=%d, FiltedText='%s'", + reply->ugc_ctx_id(), + reply->error_code(), + reply->result(), + wszFiltedContent + ); + } + MessageBoxW(NULL, wszTemp, L"UGC Reply", btn); +} + +void GameClient::sendUGCContent(int32_t ugcSceneID, const char* content) +{ + assert(m_status == STATUS_LOGGED_IN); + + Game::UGCRequest ugcRequest; + ugcRequest.set_ugc_ctx_id(m_nextUGCContextID++); + ugcRequest.set_ugc_scene_id(ugcSceneID); + ugcRequest.set_ugc_content(content); + + cyclone::Packet packet; + serializeProtoMessage(GAME_PROTO_UGC_REQUEST, &ugcRequest, packet); + m_client->send(packet.get_memory_buf(), packet.get_memory_size()); +} + +void GameClient::onClose(void) +{ + m_aceClientInterface.onServerLogout(); + m_status = STATUS_LOGGED_OUT; +} + +void GameClient::sendProtobufMessage(uint16_t id, ::google::protobuf::Message* message) +{ + cyclone::Packet packet; + serializeProtoMessage(id, message, packet); + m_client->send(packet.get_memory_buf(), packet.get_memory_size()); +} + +void GameClient::onServerNetbarResponse(cyclone::TcpConnectionPtr conn, Game::NetbarStatusRes* reply) +{ + m_clientNetbarInterface.onReceiveNetbarReportRequest(reply); +} \ No newline at end of file diff --git a/ace_test/aClient/GameClient.h b/ace_test/aClient/GameClient.h new file mode 100644 index 0000000..f3392d3 --- /dev/null +++ b/ace_test/aClient/GameClient.h @@ -0,0 +1,81 @@ +#pragma once + +#include "GameProto.h" +#include "GameProto.pb.h" +#include "AceClientInterface.h" +#include "AceReportInterface.h" +#include "NetbarInterface.h" + +class GameClient +{ +public: + enum Status + { + STATUS_DISCONNECTED = 0, + //call connectToGameServer... + STATUS_CONNECTING, + //onConnected + STATUS_CONNECTED, + //call sendLoginRequest... + STATUS_LOGGING_IN, + //onServerLoginReply + STATUS_LOGGED_IN, + + //call sendLogoutRequest... + + STATUS_LOGGING_OUT, + //socket closed + STATUS_LOGGED_OUT, + + STATUS_FAILED, + }; + + const static char* s_default_account_id; + const static uint32_t s_default_world_id; + +public: + bool init(); + void deinit(); + void connectToGameServer(const std::string& server_ip, uint16_t server_port); + void disconnectFromGameServer(); + + void sendProtobufMessage(uint16_t id, ::google::protobuf::Message* message); + void sendUGCContent(int32_t ugcSceneID, const char* content); + + ACEReport* getAceReportInterface(void) { return &m_reportInterface; } + TencentNetbarInterface* getNetbarInterface(void) { return &m_clientNetbarInterface; } + + void tick(); + cyclone::TcpClientPtr get_client(void) { return m_client; } + +protected: + uint32_t onConnected(cyclone::TcpClientPtr client, bool success); + void onMessage(cyclone::TcpConnectionPtr conn); + void onClose(void); + +protected: + void sendLoginRequest(const char* accountID, int32_t worldID); + void onServerLoginReply(cyclone::TcpConnectionPtr conn, Game::LoginReply* reply); + void onServerTickPacket(cyclone::TcpConnectionPtr conn, Game::ServerTickPacket* reply); + void onServerUGCReply(cyclone::TcpConnectionPtr conn, Game::UGCReply* reply); + void onServerNetbarResponse(cyclone::TcpConnectionPtr conn, Game::NetbarStatusRes* reply); + void sendHeartBeat(); +private: + Status m_status = STATUS_DISCONNECTED; + cyclone::TcpClientPtr m_client; + cyclone::Looper* m_looper; + std::string m_server_ip; + uint16_t m_server_port; + uint64_t m_lastHeartBeatTime = 0; + + AceClientInterface m_aceClientInterface; + uint8_t* m_clientTickBuffer = nullptr; + + ACEReport m_reportInterface; + int32_t m_nextUGCContextID = 1; + + TencentNetbarInterface m_clientNetbarInterface; +public: + GameClient(); + ~GameClient(); +}; diff --git a/ace_test/aClient/MainDialog.cpp b/ace_test/aClient/MainDialog.cpp new file mode 100644 index 0000000..573629b --- /dev/null +++ b/ace_test/aClient/MainDialog.cpp @@ -0,0 +1,170 @@ +#include "stdafx.h" +#include "MainDialog.h" + +#include "AceReportInterface.h" + +#include +#include + +LRESULT CMainDialog::OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) +{ + CenterWindow(GetParent()); + if(m_gameClient.init()==false) + { + MessageBoxA("Failed to init Ace SDK client interface!", "Error", MB_OK|MB_ICONERROR); + CloseDialog(IDCANCEL); + return FALSE; + } + return TRUE; +} + +LRESULT CMainDialog::OnOK(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + CloseDialog(wID); + return 0; +} + +LRESULT CMainDialog::OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + CloseDialog(wID); + return 0; +} + +void CMainDialog::CloseDialog(int nVal) +{ + m_gameClient.deinit(); + DestroyWindow(); + ::PostQuitMessage(nVal); +} + +LRESULT CMainDialog::OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) +{ + if(wParam==101) + { + m_gameClient.tick(); + } + return 0; +} + +LRESULT CMainDialog::OnConnectToGameServer(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + m_gameClient.connectToGameServer("127.0.0.1", 2025); + this->SetTimer(101, 100, NULL); + return 0; +} + +LRESULT CMainDialog::OnDisconnectToGameServer(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + this->KillTimer(101); + m_gameClient.disconnectFromGameServer(); + return 0; +} + +LRESULT CMainDialog::OnSendUGCContent(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + // To be implemented + wchar_t wszUgcContent[2048]; + ::GetDlgItemTextW(m_hWnd, IDC_EDIT_UGC_CONTENT, wszUgcContent, sizeof(wszUgcContent)/sizeof(wchar_t)); + + char szUtf8UgcContent[2048] = { 0 }; + ::WideCharToMultiByte(CP_UTF8, 0, wszUgcContent, -1, szUtf8UgcContent, sizeof(szUtf8UgcContent), NULL, NULL); + + m_gameClient.sendUGCContent(101, szUtf8UgcContent); + return 0; +} + +LRESULT CMainDialog::OnSendReport(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + ACEReport* reportInterface = m_gameClient.getAceReportInterface(); + + auto ctx = reportInterface->createReportContext( + "reporter_account", + 1, + "reported_name", + "reported_roleid", + ACEReportScene::REPORT_SCENE_UGC, + ACEReportCategory::REPORT_CATEGORY_BEHAVIOR, + ACEReportReasonArray{ ACEReportReason::REPORT_REASON_ILLEGAL_ABUSE, ACEReportReason::REPORT_REASON_ILLEGAL_ADVERTISEMENT }, + DNF_REPORT_ENTRANCE_TEST + ); + + reportInterface->uploadReport(ctx, [this](ACEReportContext ctx, int32_t result, const char* error_message) { + if (result == 0) { + ::MessageBoxA(m_hWnd, "Report uploaded successfully!", "Info", MB_OK | MB_ICONINFORMATION); + } + else { + ::MessageBoxA(m_hWnd, error_message, "Error", MB_OK | MB_ICONERROR); + } + } + ); + return 0; +} + +LRESULT CMainDialog::OnNetbarClientLoad(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + TencentNetbarInterface* netbarInterface = m_gameClient.getNetbarInterface(); + netbarInterface->beginRequestNetbarStatus( + [this](TencentNetbarInterface::RequestStatus status) + { + // Handle the request status update here + switch (status) { + case TencentNetbarInterface::RS_RequestDone: + ::MessageBoxA(m_hWnd, "Netbar status request completed successfully!", "Info", MB_OK | MB_ICONINFORMATION); + break; + case TencentNetbarInterface::RS_ReqestFailed: + ::MessageBoxA(m_hWnd, "Netbar status request failed!", "Error", MB_OK | MB_ICONERROR); + break; + default: + // Other statuses can be handled as needed + break; + } + }); + return 0; +} + +bool IsProcessRunning(DWORD pid) +{ + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnapshot == INVALID_HANDLE_VALUE) { + return false; + } + + PROCESSENTRY32 pe; + pe.dwSize = sizeof(PROCESSENTRY32); + + bool isRunning = false; + if (Process32First(hSnapshot, &pe)) { + do { + if (pe.th32ProcessID == pid) { + isRunning = true; + break; + } + } while (Process32Next(hSnapshot, &pe)); + } + + CloseHandle(hSnapshot); + return isRunning; +} + +LRESULT CMainDialog::OnCheckMainPlayProcess(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) +{ + wchar_t wszPid[64]; + ::GetDlgItemTextW(m_hWnd, IDC_EDIT_MAINPLAY_PID, wszPid, sizeof(wszPid)/sizeof(wchar_t)); + DWORD pid = _wtoi(wszPid); + if (pid == 0) + { + ::MessageBoxA(m_hWnd, "Invalid PID!", "Error", MB_OK | MB_ICONERROR); + return 0; + } + + bool isRunning = IsProcessRunning(pid); + if (isRunning) + { + ::MessageBoxA(m_hWnd, "MainPlay process is running.", "Info", MB_OK | MB_ICONINFORMATION); + } + else + { + ::MessageBoxA(m_hWnd, "MainPlay process is not running.", "Info", MB_OK | MB_ICONSTOP); + } + return 0; +} diff --git a/ace_test/aClient/MainDialog.h b/ace_test/aClient/MainDialog.h new file mode 100644 index 0000000..f5eb1d4 --- /dev/null +++ b/ace_test/aClient/MainDialog.h @@ -0,0 +1,47 @@ +#pragma once +#include "resource.h" + +#include "GameClient.h" + +class CMainDialog : public CDialogImpl +{ +public: + enum { IDD = IDD_DIALOG_MAIN }; + + BEGIN_MSG_MAP(CMainDialog) + MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog) + COMMAND_ID_HANDLER(IDOK, OnOK) + COMMAND_ID_HANDLER(IDCANCEL, OnCancel) + + MESSAGE_HANDLER(WM_TIMER, OnTimer) + COMMAND_ID_HANDLER(IDC_BUTTON_CONNECT_GAME_SERVER, OnConnectToGameServer) + COMMAND_ID_HANDLER(IDC_BUTTON_DISCONNECT_GAME_SERVER, OnDisconnectToGameServer) + COMMAND_ID_HANDLER(IDC_BUTTON_UGC_SEND, OnSendUGCContent) + COMMAND_ID_HANDLER(IDC_BUTTON_REPORT_SEND, OnSendReport) + COMMAND_ID_HANDLER(IDC_BUTTON_NETBAR_CLIENTLOAD, OnNetbarClientLoad) + COMMAND_ID_HANDLER(IDC_BUTTON_CHECK_MAINPLAY_PROCESS, OnCheckMainPlayProcess) + END_MSG_MAP() + + virtual BOOL PreTranslateMessage(MSG* pMsg) + { + return ::IsDialogMessage(m_hWnd, pMsg); + } + +private: + LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); + LRESULT OnOK(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnCancel(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnTimer(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/); + LRESULT OnConnectToGameServer(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnDisconnectToGameServer(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnSendUGCContent(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnSendReport(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnNetbarClientLoad(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + LRESULT OnCheckMainPlayProcess(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/); + + void CloseDialog(int nVal); + +protected: + GameClient m_gameClient; +}; + diff --git a/ace_test/aClient/NetbarInterface.cpp b/ace_test/aClient/NetbarInterface.cpp new file mode 100644 index 0000000..11d9e79 --- /dev/null +++ b/ace_test/aClient/NetbarInterface.cpp @@ -0,0 +1,177 @@ +#include "stdafx.h" +#include "NetbarInterface.h" +#include "iigw_api_client.h" +#include "GameProto.h" +#include "GameProto.pb.h" +#include "GameClient.h" + +TencentNetbarInterface::TencentNetbarInterface() +{ + m_requestStatus.store(RS_NotRequest); + m_workThread = NULL; + m_netbarStatus = NS_Unknown; + m_clientErrorCode = 0; + m_serverErrorCode = 0; + m_serverErrorMessage.clear(); + m_netbarLevel = -1; + m_clientNetbarReq = new Game::NetbaraStatusReq(); +} + +TencentNetbarInterface::~TencentNetbarInterface() +{ + delete m_clientNetbarReq; + m_clientNetbarReq = nullptr; +} + +void TencentNetbarInterface::init(GameClient* client) +{ + m_client = client; +} + +void TencentNetbarInterface::tick() +{ + switch (m_requestStatus) + { + case RequestStatus::RS_ClientRequest_Done: + { + m_client->sendProtobufMessage(GameProto::GAME_PROTO_NETBAR_REQ, m_clientNetbarReq); + m_requestStatus = RequestStatus::RS_ServerRequesting; + } + break; + + case RequestStatus::RS_ClientRequest_Failed: + { + m_requestStatus = RequestStatus::RS_ReqestFailed; + } + break; + } +} + +bool TencentNetbarInterface::beginRequestNetbarStatus(RequestCallback callback) +{ + if(m_requestStatus==RequestStatus::RS_RequestDone || m_requestStatus==RequestStatus::RS_ReqestFailed) + { + //already done + if(callback) + { + callback(m_requestStatus.load()); + } + return true; + } + + if(m_requestStatus != RequestStatus::RS_NotRequest) + { + //already requesting + return false; + } + + m_requestStatus = RequestStatus::RS_ClientRequesting; + + unsigned int threadID = 0; + m_workThread = (HANDLE)_beginthreadex(NULL, 0, TencentNetbarInterface::_workingThreadEntry, this, 0,&threadID); + if(m_workThread == NULL) + { + m_requestStatus = RequestStatus::RS_ClientRequest_Failed; + return false; + } + m_requestCallback = callback; + return true; +} + +unsigned int TencentNetbarInterface::_workingThreadEntry(void* param) +{ + TencentNetbarInterface* pThis = (TencentNetbarInterface*)param; + if(pThis) + { + pThis->workThreadEntry(); + } + ::CloseHandle(pThis->m_workThread); + pThis->m_workThread = NULL; + return 0; +} + +bool TencentNetbarInterface::workThreadEntry() +{ + HMODULE hNetbarDllHandle = NULL; + bool isSuccess = false; + + do { + hNetbarDllHandle = ::LoadLibraryW(L"iigw_client_api.dll"); + if (hNetbarDllHandle == NULL) + { + m_clientErrorCode = GetLastError(); + m_requestStatus = RequestStatus::RS_ClientRequest_Failed; + break; + } + + //create interface + iepm_qqwb::IQQNetbarIIGWPlugin *pProxy = iepm_qqwb::CreateQQNetbarIIGWPlugin(hNetbarDllHandle); + if(pProxy == nullptr) + { + m_requestStatus = RequestStatus::RS_ClientRequest_Failed; + break; + } + + //call client interfae + int ret = pProxy->IsNetbarMachine(TENCENT_NETBAR_DNF_CLIENT_GAME_ID, GameClient::s_default_account_id, iepm_qqwb::at_qq); + bool isNetbar = (ret == IIGW_MSG_STATUS_NETBAR_PC); + + iepm_qqwb::NetbarLv netbarlv = {0}; + memset(&netbarlv, 0, sizeof(netbarlv)); + + m_clientErrorCode = pProxy->ReqNetbarLv2( + TENCENT_NETBAR_DNF_CLIENT_GAME_ID, + GameClient::s_default_world_id, + GameClient::s_default_account_id, + iepm_qqwb::at_qq, + nullptr, + 0, + &netbarlv, + 5000 + ); + + if (m_clientErrorCode != 0 || netbarlv.tokenLen<=0 ) + { + m_requestStatus = RequestStatus::RS_ClientRequest_Failed; + break; + } + + m_clientNetbarReq->Clear(); + m_clientNetbarReq->set_is_netbar_machine(isNetbar); + m_clientNetbarReq->set_token((const char*)netbarlv.tokenBuff, (size_t)netbarlv.tokenLen); + m_clientNetbarReq->set_macs(netbarlv.macs); + + m_requestStatus = RequestStatus::RS_ClientRequest_Done; + + isSuccess = true; + } while (false); + + if(hNetbarDllHandle) + { + ::FreeLibrary(hNetbarDllHandle); + hNetbarDllHandle = NULL; + } + return isSuccess; +} + +void TencentNetbarInterface::onReceiveNetbarReportRequest(Game::NetbarStatusRes* response) +{ + m_netbarLevel = response->netbar_level(); + m_serverErrorCode = response->error_code(); + m_serverErrorMessage = response->error_message(); + + if (m_serverErrorCode == 0) + { + m_serverErrorCode = NetbarStatus::NS_Netbar; + } + else + { + m_serverErrorCode = NetbarStatus::NS_ServerFailed; + } + m_requestStatus = RequestStatus::RS_RequestDone; + + if (m_requestCallback) + { + m_requestCallback(m_requestStatus); + } +} diff --git a/ace_test/aClient/NetbarInterface.h b/ace_test/aClient/NetbarInterface.h new file mode 100644 index 0000000..e92cd54 --- /dev/null +++ b/ace_test/aClient/NetbarInterface.h @@ -0,0 +1,69 @@ +#pragma once +#include + +namespace Game +{ + class NetbaraStatusReq; + class NetbarStatusRes; +}; +class GameClient; + +class TencentNetbarInterface +{ +public: + TencentNetbarInterface(); + ~TencentNetbarInterface(); +public: + enum RequestStatus + { + RS_NotRequest=0, + RS_ClientRequesting, + RS_ClientRequest_Done, + RS_ClientRequest_Failed, + RS_ServerRequesting, + + RS_ReqestFailed, + RS_RequestDone, + }; + + enum NetbarStatus + { + NS_Unknown = 0, + NS_Netbar, + + NS_ClientFailed, + NS_ServerFailed, + }; + + typedef std::function RequestCallback; + bool beginRequestNetbarStatus(RequestCallback callback); + + void onReceiveNetbarReportRequest(Game::NetbarStatusRes* response); + + void init(GameClient* client); + void tick(); +private: + static unsigned int _workingThreadEntry(void* param); + bool workThreadEntry(); + +private: + enum { TENCENT_NETBAR_DNF_CLIENT_GAME_ID = 20 }; + +private: + GameClient* m_client = nullptr; + + std::atomic m_requestStatus; + HANDLE m_workThread; + + NetbarStatus m_netbarStatus; + + int32_t m_clientErrorCode; + + int32_t m_serverErrorCode; + std::string m_serverErrorMessage; + + int32_t m_netbarLevel; + RequestCallback m_requestCallback; + + Game::NetbaraStatusReq* m_clientNetbarReq = nullptr; +}; \ No newline at end of file diff --git a/ace_test/aClient/aClient.aps b/ace_test/aClient/aClient.aps new file mode 100644 index 0000000..a2e8574 Binary files /dev/null and b/ace_test/aClient/aClient.aps differ diff --git a/ace_test/aClient/aClient.rc b/ace_test/aClient/aClient.rc new file mode 100644 index 0000000..7e972a4 Binary files /dev/null and b/ace_test/aClient/aClient.rc differ diff --git a/ace_test/aClient/iigw_api_client.h b/ace_test/aClient/iigw_api_client.h new file mode 100644 index 0000000..bec9ecb --- /dev/null +++ b/ace_test/aClient/iigw_api_client.h @@ -0,0 +1,580 @@ +/************************************************************ + Copyright (C), 2008-2018, Tencent Tech. Co., Ltd. + FileName: iigw_api_client.h + Author: cooperli Version : 1.0 Date: 2008-03-25 + Description: 信息网关API头文件 + + History: +