#include "bots.h"
#include "clientobject.h"
#include "network/common.h"
#include "network/message_handler.h"
#include "network/tcp_packet.h"
#include "network/bundle.h"
#include "network/fixed_messages.h"
#include "thread/threadpool.h"
#include "server/components.h"
#include "server/serverconfig.h"
#include "entitydef/scriptdef_module.h"
#include "entitydef/entitydef.h"
#include "client_lib/client_interface.h"
#include "common/kbeversion.h"
#include <algorithm>
#include "baseapp/baseapp_interface.h"
#include "cellapp/cellapp_interface.h"
#include "baseappmgr/baseappmgr_interface.h"
#include "cellappmgr/cellappmgr_interface.h"
#include "loginapp/loginapp_interface.h"
namespace KBEngine{
SCRIPT_METHOD_DECLARE_BEGIN(ClientObject)
SCRIPT_METHOD_DECLARE_END()
SCRIPT_MEMBER_DECLARE_BEGIN(ClientObject)
SCRIPT_MEMBER_DECLARE_END()
SCRIPT_GETSET_DECLARE_BEGIN(ClientObject)
SCRIPT_GETSET_DECLARE_END()
SCRIPT_INIT(ClientObject, 0, 0, 0, 0, 0)
ClientObject::ClientObject(std::string name, Network::NetworkInterface& ninterface):
ClientObjectBase(ninterface, getScriptType()),
error_(C_ERROR_NONE),
state_(C_STATE_INIT),
pBlowfishFilter_(0),
pTCPPacketSenderEx_(NULL),
pTCPPacketReceiverEx_(NULL),
pKCPPacketSenderEx_(NULL),
pKCPPacketReceiverEx_(NULL)
{
name_ = name;
typeClient_ = CLIENT_TYPE_BOTS;
clientDatas_ = "bots";
password_ = ServerConfig::getSingleton().getBots().bots_account_passwd;
}
ClientObject::~ClientObject()
{
SAFE_RELEASE(pBlowfishFilter_);
}
void ClientObject::finalise(void)
{
reset();
ClientObjectBase::finalise();
}
void ClientObject::reset(void)
{
deregisterReceiverEndPoint(pTCPPacketReceiverEx_);
deregisterReceiverEndPoint(pKCPPacketReceiverEx_);
if(pServerChannel_ && pServerChannel_->pEndPoint())
{
pServerChannel_->fina_kcp();
pServerChannel_->stopSend();
pServerChannel_->pPacketSender(NULL);
pServerChannel_->pPacketReceiver(NULL);
pServerChannel_->id(0);
pServerChannel_->protocoltype(Network::PROTOCOL_TCP);
pServerChannel_->protocolSubtype(Network::SUB_PROTOCOL_DEFAULT);
pServerChannel_->setFlags(false, Network::Channel::FLAG_HANDSHAKE);
}
SAFE_RELEASE(pTCPPacketSenderEx_);
SAFE_RELEASE(pTCPPacketReceiverEx_);
SAFE_RELEASE(pKCPPacketSenderEx_);
SAFE_RELEASE(pKCPPacketReceiverEx_);
std::string name = name_;
std::string passwd = password_;
ClientObjectBase::reset();
name_ = name;
password_ = passwd;
clientDatas_ = "bots";
state_ = C_STATE_INIT;
connectedBaseapp_ = false;
}
void ClientObject::onNetworkError(const std::string& err)
{
DEBUG_MSG(fmt::format("ClientObject::onNetworkError: {} state={} err={}\n",
name_, static_cast<int>(state_), err));
deregisterReceiverEndPoint(pTCPPacketReceiverEx_, true);
deregisterReceiverEndPoint(pKCPPacketReceiverEx_, true);
if (pServerChannel_ != NULL && !pServerChannel_->isDestroyed())
{
pServerChannel_->destroy();
return;
}
destroy();
}
void ClientObject::deregisterReceiverEndPoint(Network::PacketReceiver* pPacketReceiver, bool detachEndPoint)
{
if (pPacketReceiver == NULL || pPacketReceiver->pEndPoint() == NULL)
{
return;
}
Network::EndPoint* pEndPoint = pPacketReceiver->pEndPoint();
if (pEndPoint->good())
{
Bots::getSingleton().networkInterface().dispatcher().deregisterReadFileDescriptor(*pEndPoint);
}
if (detachEndPoint)
{
pPacketReceiver->pEndPoint(NULL);
}
}
void ClientObject::sendBaseappActiveTick(bool force)
{
if (!connectedBaseapp_ || pServerChannel_ == NULL || pServerChannel_->pEndPoint() == NULL ||
pServerChannel_->isDestroyed() || pServerChannel_->condemn() > 0)
{
return;
}
uint64 interval = stampsPerSecond() * 10;
if (Network::g_channelExternalTimeout > 0.f)
{
interval = KBE_MAX<uint64>(stampsPerSecond(), uint64(Network::g_channelExternalTimeout * stampsPerSecond()) / 4);
interval = KBE_MIN<uint64>(interval, stampsPerSecond() * 10);
}
if (!force && timestamp() - lastSentActiveTickTime_ < interval)
{
return;
}
lastSentActiveTickTime_ = timestamp();
Network::Bundle* pBundle = Network::Bundle::createPoolObject(OBJECTPOOL_POINT);
(*pBundle).newMessage(BaseappInterface::onClientActiveTick);
pServerChannel_->send(pBundle);
}
void ClientObject::clearStates(void)
{
deregisterReceiverEndPoint(pTCPPacketReceiverEx_);
deregisterReceiverEndPoint(pKCPPacketReceiverEx_);
pServerChannel_->fina_kcp();
pServerChannel_->stopSend();
pServerChannel_->pPacketSender(NULL);
pServerChannel_->pPacketReceiver(NULL);
SAFE_RELEASE(pTCPPacketSenderEx_);
SAFE_RELEASE(pTCPPacketReceiverEx_);
SAFE_RELEASE(pKCPPacketSenderEx_);
SAFE_RELEASE(pKCPPacketReceiverEx_);
if (pServerChannel_->pEndPoint())
{
pServerChannel_->pEndPoint()->destroySSL();
pServerChannel_->pEndPoint()->close();
pServerChannel_->pEndPoint(NULL);
}
}
bool ClientObject::initCreate()
{
clearStates();
Network::EndPoint* pEndpoint = Network::EndPoint::createPoolObject(OBJECTPOOL_POINT);
pEndpoint->socket(SOCK_STREAM);
if (!pEndpoint->good())
{
ERROR_MSG("ClientObject::initNetwork: couldn't create a socket\n");
Network::EndPoint::reclaimPoolObject(pEndpoint);
error_ = C_ERROR_INIT_NETWORK_FAILED;
return false;
}
ENGINE_COMPONENT_INFO& infos = g_kbeSrvConfig.getBots();
if (infos.login_port_max > infos.login_port_min)
{
infos.login_port = infos.login_port_min + (rand() % (infos.login_port_max - infos.login_port_min + 1));
}
u_int32_t address;
Network::Address::string2ip(infos.login_ip, address);
if(pEndpoint->connect(htons(infos.login_port), address) == -1)
{
ERROR_MSG(fmt::format("ClientObject::initNetwork({1}): connect server({2}:{3}) error({0})!\n",
kbe_strerror(), name_, infos.login_ip, infos.login_port));
Network::EndPoint::reclaimPoolObject(pEndpoint);
state_ = C_STATE_INIT;
return false;
}
pServerChannel_->protocoltype(Network::PROTOCOL_TCP);
pServerChannel_->protocolSubtype(Network::SUB_PROTOCOL_DEFAULT);
pServerChannel_->setFlags(false, Network::Channel::FLAG_HANDSHAKE);
Network::Address addr(infos.login_ip, infos.login_port);
pEndpoint->addr(addr);
pServerChannel_->pEndPoint(pEndpoint);
pEndpoint->setnonblocking(true);
pEndpoint->setnodelay(true);
pServerChannel_->pMsgHandlers(&ClientInterface::messageHandlers);
pTCPPacketSenderEx_ = new Network::TCPPacketSenderEx(*pEndpoint, this->networkInterface_, this);
pTCPPacketReceiverEx_ = new Network::TCPPacketReceiverEx(*pEndpoint, this->networkInterface_, this);
Bots::getSingleton().networkInterface().dispatcher().registerReadFileDescriptor((*pEndpoint), pTCPPacketReceiverEx_);
pServerChannel_->pPacketSender(pTCPPacketSenderEx_);
Network::Bundle* pBundle = Network::Bundle::createPoolObject(OBJECTPOOL_POINT);
(*pBundle).newMessage(LoginappInterface::hello);
(*pBundle) << KBEVersion::versionString() << KBEVersion::scriptVersionString();
if(Network::g_channelExternalEncryptType == 1)
{
pBlowfishFilter_ = new Network::BlowfishFilter();
(*pBundle).appendBlob(pBlowfishFilter_->key());
}
else
{
std::string key = "";
(*pBundle).appendBlob(key);
}
pEndpoint->send(pBundle);
Network::Bundle::reclaimPoolObject(pBundle);
return true;
}
bool ClientObject::initLoginBaseapp()
{
clearStates();
deregisterReceiverEndPoint(pTCPPacketReceiverEx_);
deregisterReceiverEndPoint(pKCPPacketReceiverEx_);
pServerChannel_->fina_kcp();
pServerChannel_->stopSend();
pServerChannel_->pPacketSender(NULL);
pServerChannel_->pPacketReceiver(NULL);
SAFE_RELEASE(pTCPPacketSenderEx_);
SAFE_RELEASE(pTCPPacketReceiverEx_);
SAFE_RELEASE(pKCPPacketSenderEx_);
SAFE_RELEASE(pKCPPacketReceiverEx_);
u_int32_t srv_address;
Network::Address::string2ip(ip_.c_str(), srv_address);
connectedBaseapp_ = false;
pServerChannel_->id(0);
if (udp_port_ > 0)
{
Network::EndPoint* pUdpEndpoint = Network::EndPoint::createPoolObject(OBJECTPOOL_POINT);
pUdpEndpoint->socket(SOCK_DGRAM);
if (!pUdpEndpoint->good())
{
ERROR_MSG("ClientObject::initLogin: couldn't create a udp-socket\n");
Network::EndPoint::reclaimPoolObject(pUdpEndpoint);
error_ = C_ERROR_INIT_NETWORK_FAILED;
return false;
}
Network::Address udp_addr(ip_.c_str(), udp_port_);
pUdpEndpoint->addr(udp_addr);
pServerChannel_->pEndPoint(pUdpEndpoint);
pUdpEndpoint->setnonblocking(true);
pUdpEndpoint->setnodelay(true);
if (pUdpEndpoint->sendto((void*)Network::UDP_HELLO, static_cast<int>(strlen(Network::UDP_HELLO))) != -1)
{
Network::UDPPacket* pHelloAckUDPPacket = Network::UDPPacket::createPoolObject(OBJECTPOOL_POINT);
bool ret = Network::kbe_poll(int(*pUdpEndpoint));
if (!ret)
{
Network::UDPPacket::reclaimPoolObject(pHelloAckUDPPacket);
ERROR_MSG("ClientObject::initLogin: recvfrom timeout!\n");
state_ = C_STATE_LOGIN_BASEAPP_CREATE;
return false;
}
sockaddr_in remoteAddr;
int bytes_rcvd = pUdpEndpoint->recvfrom(pHelloAckUDPPacket->data(), static_cast<int>(pHelloAckUDPPacket->size()), remoteAddr);
if (bytes_rcvd > 0)
{
std::string helloAck, versionString;
uint32 channelID = 0;
pHelloAckUDPPacket->wpos(bytes_rcvd);
(*pHelloAckUDPPacket) >> helloAck >> versionString >> channelID;
Network::UDPPacket::reclaimPoolObject(pHelloAckUDPPacket);
if (Network::UDP_HELLO_ACK == helloAck)
{
if (versionString != KBEVersion::versionString())
{
ERROR_MSG(fmt::format("ClientObject::initLogin: Version mismatch! {} != serverVersionString({})\n",
KBEVersion::versionString(), versionString));
error_ = C_ERROR_INIT_NETWORK_FAILED;
return false;
}
pKCPPacketSenderEx_ = new Network::KCPPacketSenderEx(*pUdpEndpoint, this->networkInterface_, this);
pKCPPacketReceiverEx_ = new Network::KCPPacketReceiverEx(*pUdpEndpoint, this->networkInterface_, this);
connectedBaseapp_ = true;
pServerChannel_->id(channelID);
pServerChannel_->protocoltype(Network::PROTOCOL_UDP);
pServerChannel_->protocolSubtype(Network::SUB_PROTOCOL_KCP);
pServerChannel_->pPacketSender(pKCPPacketSenderEx_);
pServerChannel_->pPacketReceiver(pKCPPacketReceiverEx_);
pServerChannel_->setFlags(true, Network::Channel::FLAG_HANDSHAKE);
if (!pServerChannel_->init_kcp())
{
ERROR_MSG(fmt::format("ClientObject::initLogin: KCP error! channelID={}\n",
pServerChannel_->id()));
error_ = C_ERROR_INIT_NETWORK_FAILED;
return false;
}
Bots::getSingleton().networkInterface().dispatcher().registerReadFileDescriptor((*pUdpEndpoint), pKCPPacketReceiverEx_);
Network::Bundle* pBundle = Network::Bundle::createPoolObject(OBJECTPOOL_POINT);
(*pBundle).newMessage(BaseappInterface::hello);
(*pBundle) << KBEVersion::versionString() << KBEVersion::scriptVersionString();
if (Network::g_channelExternalEncryptType == 1)
{
pBlowfishFilter_ = new Network::BlowfishFilter();
(*pBundle).appendBlob(pBlowfishFilter_->key());
pServerChannel_->pFilter(NULL);
}
else
{
std::string key = "";
(*pBundle).appendBlob(key);
}
pServerChannel_->sendto(true, pBundle);
}
}
else
{
Network::UDPPacket::reclaimPoolObject(pHelloAckUDPPacket);
ERROR_MSG(fmt::format("ClientObject::initLogin: recvfrom error({})\n", kbe_lasterror()));
}
}
else
{
ERROR_MSG(fmt::format("ClientObject::initLogin: sendto error({})\n", kbe_lasterror()));
}
}
if (!connectedBaseapp_ && tcp_port_ > 0)
{
Network::EndPoint* pTcpEndpoint = Network::EndPoint::createPoolObject(OBJECTPOOL_POINT);
pTcpEndpoint->socket(SOCK_STREAM);
if (!pTcpEndpoint->good())
{
ERROR_MSG("ClientObject::initLogin: couldn't create a tcp-socket\n");
Network::EndPoint::reclaimPoolObject(pTcpEndpoint);
error_ = C_ERROR_INIT_NETWORK_FAILED;
return false;
}
if (pTcpEndpoint->connect(htons(tcp_port_), srv_address) == -1)
{
ERROR_MSG(fmt::format("ClientObject::initLogin({}): connect server error({})!\n",
kbe_strerror(), name_));
Network::EndPoint::reclaimPoolObject(pTcpEndpoint);
state_ = C_STATE_LOGIN_BASEAPP_CREATE;
return false;
}
pServerChannel_->protocoltype(Network::PROTOCOL_TCP);
pServerChannel_->protocolSubtype(Network::SUB_PROTOCOL_DEFAULT);
Network::Address tcp_addr(ip_.c_str(), tcp_port_);
pTcpEndpoint->addr(tcp_addr);
pServerChannel_->pEndPoint(pTcpEndpoint);
pTcpEndpoint->setnonblocking(true);
pTcpEndpoint->setnodelay(true);
pTCPPacketSenderEx_ = new Network::TCPPacketSenderEx(*pTcpEndpoint, this->networkInterface_, this);
pTCPPacketReceiverEx_ = new Network::TCPPacketReceiverEx(*pTcpEndpoint, this->networkInterface_, this);
Bots::getSingleton().networkInterface().dispatcher().registerReadFileDescriptor((*pTcpEndpoint), pTCPPacketReceiverEx_);
pServerChannel_->pPacketSender(pTCPPacketSenderEx_);
Network::Bundle* pBundle = Network::Bundle::createPoolObject(OBJECTPOOL_POINT);
(*pBundle).newMessage(BaseappInterface::hello);
(*pBundle) << KBEVersion::versionString() << KBEVersion::scriptVersionString();
if (Network::g_channelExternalEncryptType == 1)
{
pBlowfishFilter_ = new Network::BlowfishFilter();
(*pBundle).appendBlob(pBlowfishFilter_->key());
pServerChannel_->pFilter(NULL);
}
else
{
std::string key = "";
(*pBundle).appendBlob(key);
}
pTcpEndpoint->send(pBundle);
Network::Bundle::reclaimPoolObject(pBundle);
connectedBaseapp_ = true;
}
return true;
}
void ClientObject::gameTick()
{
if(pServerChannel()->pEndPoint())
{
if(pServerChannel()->condemn() > 0)
{
destroy();
return;
}
pServerChannel()->updateTick(NULL);
}
else
{
if(connectedBaseapp_)
{
EventData_ServerCloased eventdata;
eventHandler_.fire(&eventdata);
connectedBaseapp_ = false;
canReset_ = true;
state_ = C_STATE_INIT;
DEBUG_MSG(fmt::format("ClientObject({})::tickSend: serverCloased! name({})!\n",
this->appID(), this->name()));
}
}
if(locktime() > 0 && timestamp() < locktime())
{
return;
}
switch(state_)
{
case C_STATE_INIT:
state_ = C_STATE_PLAY;
if(!initCreate())
return;
break;
case C_STATE_CREATE:
state_ = C_STATE_PLAY;
if(!createAccount())
return;
break;
case C_STATE_LOGIN:
state_ = C_STATE_PLAY;
if(!login())
return;
break;
case C_STATE_LOGIN_BASEAPP_CREATE:
state_ = C_STATE_PLAY;
if(!initLoginBaseapp())
return;
break;
case C_STATE_LOGIN_BASEAPP:
state_ = C_STATE_PLAY;
if(!loginBaseapp())
return;
break;
case C_STATE_PLAY:
break;
case C_STATE_DESTROYED:
return;
default:
KBE_ASSERT(false);
break;
};
sendBaseappActiveTick(false);
tickSend();
}
void ClientObject::onHelloCB_(Network::Channel* pChannel, const std::string& verInfo,
const std::string& scriptVerInfo, const std::string& protocolMD5, const std::string& entityDefMD5,
COMPONENT_TYPE componentType)
{
if(Network::g_channelExternalEncryptType == 1)
{
pServerChannel_->pFilter(pBlowfishFilter_);
pBlowfishFilter_ = NULL;
}
if(componentType == LOGINAPP_TYPE)
{
state_ = C_STATE_CREATE;
}
else
{
connectedBaseapp_ = true;
sendBaseappActiveTick(true);
state_ = C_STATE_LOGIN_BASEAPP;
}
}
void ClientObject::onCreateAccountResult(Network::Channel * pChannel, MemoryStream& s)
{
SERVER_ERROR_CODE retcode;
s >> retcode;
s.readBlob(serverDatas_);
if(retcode != 0)
{
state_ = C_STATE_LOGIN;
INFO_MSG(fmt::format("ClientObject::onCreateAccountResult: {} create is failed! code={}.\n",
name_, SERVER_ERR_STR[retcode]));
return;
}
state_ = C_STATE_LOGIN;
INFO_MSG(fmt::format("ClientObject::onCreateAccountResult: {} create is successfully!\n", name_));
}
void ClientObject::onLoginSuccessfully(Network::Channel * pChannel, MemoryStream& s)
{
std::string accountName;
s >> accountName;
s >> ip_;
s >> tcp_port_;
s >> udp_port_;
s.readBlob(serverDatas_);
INFO_MSG(fmt::format("ClientObject::onLoginSuccessfully: {} addr={}:{}|{}!\n",
name_, ip_, tcp_port_, udp_port_));
state_ = C_STATE_LOGIN_BASEAPP_CREATE;
}
void ClientObject::onLoginFailed(Network::Channel * pChannel, MemoryStream& s)
{
SERVER_ERROR_CODE failedcode;
s >> failedcode;
s.readBlob(serverDatas_);
INFO_MSG(fmt::format("ClientObject::onLoginFailed: {} failedcode={}!\n",
name_, SERVER_ERR_STR[failedcode]));
state_ = C_STATE_LOGIN;
}
void ClientObject::onLoginBaseappFailed(Network::Channel * pChannel, SERVER_ERROR_CODE failedcode)
{
ClientObjectBase::onLoginBaseappFailed(pChannel, failedcode);
destroy();
}
void ClientObject::onLogin(Network::Bundle* pBundle)
{
}
}