285 lines
7.4 KiB
C++
285 lines
7.4 KiB
C++
#include "stdafx.h"
|
|
#include "GameClient.h"
|
|
#include <strsafe.h>
|
|
|
|
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<cyclone::TcpClient>(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<Game::LoginReply*>(message);
|
|
onServerLoginReply(conn, loginReply);
|
|
}
|
|
break;
|
|
|
|
case GAME_PROTO_SERVER_PACKET:
|
|
{
|
|
Game::ServerTickPacket* serverTickPacket = dynamic_cast<Game::ServerTickPacket*>(message);
|
|
onServerTickPacket(conn, serverTickPacket);
|
|
}
|
|
break;
|
|
|
|
case GAME_PROTO_UGC_REPLY:
|
|
{
|
|
Game::UGCReply* ugcReply = dynamic_cast<Game::UGCReply*>(message);
|
|
onServerUGCReply(conn, ugcReply);
|
|
}
|
|
break;
|
|
|
|
case GAME_PROTO_NETBAR_RES:
|
|
{
|
|
Game::NetbarStatusRes* netbarResponse = dynamic_cast<Game::NetbarStatusRes*>(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);
|
|
} |