2021-03-17 19:07:40 +00:00
|
|
|
#include "core/Core.hpp"
|
|
|
|
#include "db/Database.hpp"
|
|
|
|
#include "servers/Monitor.hpp"
|
|
|
|
#include "servers/CNShardServer.hpp"
|
2020-08-18 20:42:30 +00:00
|
|
|
#include "PlayerManager.hpp"
|
2021-03-13 22:55:16 +00:00
|
|
|
#include "MobAI.hpp"
|
2021-03-17 19:07:40 +00:00
|
|
|
#include "core/CNShared.hpp"
|
2020-08-22 17:39:13 +00:00
|
|
|
#include "settings.hpp"
|
2020-10-06 19:53:21 +00:00
|
|
|
#include "TableData.hpp" // for flush()
|
2020-08-18 20:42:30 +00:00
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <sstream>
|
|
|
|
#include <cstdlib>
|
|
|
|
|
|
|
|
std::map<uint32_t, PacketHandler> CNShardServer::ShardPackets;
|
2020-08-24 21:11:40 +00:00
|
|
|
std::list<TimerEvent> CNShardServer::Timers;
|
2020-08-18 20:42:30 +00:00
|
|
|
|
|
|
|
CNShardServer::CNShardServer(uint16_t p) {
|
|
|
|
port = p;
|
|
|
|
pHandler = &CNShardServer::handlePacket;
|
2020-09-16 15:45:53 +00:00
|
|
|
REGISTER_SHARD_TIMER(keepAliveTimer, 4000);
|
2020-09-08 22:23:45 +00:00
|
|
|
REGISTER_SHARD_TIMER(periodicSaveTimer, settings::DBSAVEINTERVAL*1000);
|
2020-08-18 20:42:30 +00:00
|
|
|
init();
|
2020-12-06 00:44:37 +00:00
|
|
|
|
|
|
|
if (settings::MONITORENABLED)
|
|
|
|
fds.push_back({Monitor::init(), POLLIN});
|
2020-08-18 20:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CNShardServer::handlePacket(CNSocket* sock, CNPacketData* data) {
|
2021-03-19 01:32:07 +00:00
|
|
|
printPacket(data);
|
2020-08-22 17:39:13 +00:00
|
|
|
|
2022-07-23 00:00:40 +00:00
|
|
|
// if it's a valid packet
|
|
|
|
if (ShardPackets.find(data->type) != ShardPackets.end()) {
|
|
|
|
|
|
|
|
// reject gameplay packets if not yet fully connected
|
|
|
|
if (PlayerManager::players.find(sock) == PlayerManager::players.end()
|
|
|
|
&& data->type != P_CL2FE_REQ_PC_ENTER && data->type != P_CL2FE_REP_LIVE_CHECK) {
|
|
|
|
|
|
|
|
if (settings::VERBOSITY > 0) {
|
|
|
|
std::cerr << "OpenFusion: SHARD PKT OUT-OF-SEQ. PacketType: " <<
|
|
|
|
Packets::p2str(data->type) << " (" << data->type << ")" << std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// run the appropriate packet handler
|
2020-08-18 20:42:30 +00:00
|
|
|
ShardPackets[data->type](sock, data);
|
2022-07-23 00:00:40 +00:00
|
|
|
} else if (settings::VERBOSITY > 0) {
|
2021-03-19 01:32:07 +00:00
|
|
|
std::cerr << "OpenFusion: SHARD UNIMPLM ERR. PacketType: " << Packets::p2str(data->type) << " (" << data->type << ")" << std::endl;
|
2022-07-23 00:00:40 +00:00
|
|
|
}
|
2020-09-16 15:45:53 +00:00
|
|
|
|
2022-07-23 00:00:40 +00:00
|
|
|
/*
|
|
|
|
* We must re-check if the player is still connected in case
|
|
|
|
* they were dropped when handling the packet.
|
|
|
|
*/
|
2020-10-23 03:32:14 +00:00
|
|
|
if (PlayerManager::players.find(sock) != PlayerManager::players.end())
|
2020-11-17 23:16:16 +00:00
|
|
|
PlayerManager::players[sock]->lastHeartbeat = getTime();
|
2020-08-18 20:42:30 +00:00
|
|
|
}
|
|
|
|
|
2020-09-16 15:45:53 +00:00
|
|
|
void CNShardServer::keepAliveTimer(CNServer* serv, time_t currTime) {
|
2020-09-18 02:41:09 +00:00
|
|
|
for (auto& pair : PlayerManager::players) {
|
2020-11-17 23:16:16 +00:00
|
|
|
if (pair.second->lastHeartbeat != 0 && currTime - pair.second->lastHeartbeat > settings::TIMEOUT) {
|
2020-09-16 15:45:53 +00:00
|
|
|
// if the client hasn't responded in 60 seconds, its a dead connection so throw it out
|
2020-08-24 21:11:40 +00:00
|
|
|
pair.first->kill();
|
2020-11-17 23:16:16 +00:00
|
|
|
} else if (pair.second->lastHeartbeat != 0 && currTime - pair.second->lastHeartbeat > settings::TIMEOUT/2) {
|
2020-09-16 15:45:53 +00:00
|
|
|
// if the player hasn't responded in 30 seconds, send a live check
|
|
|
|
INITSTRUCT(sP_FE2CL_REQ_LIVE_CHECK, data);
|
|
|
|
pair.first->sendPacket((void*)&data, P_FE2CL_REQ_LIVE_CHECK, sizeof(sP_FE2CL_REQ_LIVE_CHECK));
|
2020-08-24 21:11:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-16 15:45:53 +00:00
|
|
|
void CNShardServer::periodicSaveTimer(CNServer* serv, time_t currTime) {
|
2020-10-02 18:31:22 +00:00
|
|
|
if (PlayerManager::players.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
std::cout << "[INFO] Saving " << PlayerManager::players.size() << " players to DB..." << std::endl;
|
2020-10-02 17:31:47 +00:00
|
|
|
|
2020-09-18 02:41:09 +00:00
|
|
|
for (auto& pair : PlayerManager::players) {
|
2020-11-17 23:16:16 +00:00
|
|
|
Database::updatePlayer(pair.second);
|
2020-09-14 13:20:55 +00:00
|
|
|
}
|
2020-10-02 17:31:47 +00:00
|
|
|
|
2020-10-06 19:53:21 +00:00
|
|
|
TableData::flush();
|
2020-10-02 17:31:47 +00:00
|
|
|
std::cout << "[INFO] Done." << std::endl;
|
2020-09-08 22:23:45 +00:00
|
|
|
}
|
|
|
|
|
2020-12-06 00:44:37 +00:00
|
|
|
bool CNShardServer::checkExtraSockets(int i) {
|
|
|
|
return Monitor::acceptConnection(fds[i].fd, fds[i].revents);
|
|
|
|
}
|
|
|
|
|
2020-08-22 23:31:09 +00:00
|
|
|
void CNShardServer::newConnection(CNSocket* cns) {
|
|
|
|
cns->setActiveKey(SOCKETKEY_E); // by default they accept keys encrypted with the default key
|
|
|
|
}
|
|
|
|
|
2020-10-01 23:37:50 +00:00
|
|
|
// must be static to be called from PlayerManager::exitDuplicate()
|
|
|
|
void CNShardServer::_killConnection(CNSocket* cns) {
|
2020-08-24 22:02:07 +00:00
|
|
|
// check if the player ever sent a REQ_PC_ENTER
|
|
|
|
if (PlayerManager::players.find(cns) == PlayerManager::players.end())
|
|
|
|
return;
|
|
|
|
|
2020-10-14 04:26:30 +00:00
|
|
|
PlayerManager::removePlayer(cns); // removes the player from the list and saves it to DB
|
2020-08-19 01:34:39 +00:00
|
|
|
}
|
|
|
|
|
2020-10-01 23:37:50 +00:00
|
|
|
void CNShardServer::killConnection(CNSocket *cns) {
|
|
|
|
_killConnection(cns);
|
|
|
|
}
|
|
|
|
|
2020-10-02 17:31:47 +00:00
|
|
|
// flush the DB when terminating the server
|
|
|
|
void CNShardServer::kill() {
|
|
|
|
periodicSaveTimer(nullptr, 0);
|
|
|
|
CNServer::kill();
|
|
|
|
}
|
|
|
|
|
2020-08-24 21:11:40 +00:00
|
|
|
void CNShardServer::onStep() {
|
2020-09-16 15:45:53 +00:00
|
|
|
time_t currTime = getTime();
|
2020-08-19 01:34:39 +00:00
|
|
|
|
2022-11-27 21:33:55 +00:00
|
|
|
// do not evaluate timers if the server is shutting down
|
|
|
|
if (!active)
|
|
|
|
return;
|
|
|
|
|
2020-08-24 21:11:40 +00:00
|
|
|
for (TimerEvent& event : Timers) {
|
|
|
|
if (event.scheduledEvent == 0) {
|
|
|
|
// event hasn't been queued yet, go ahead and do that
|
|
|
|
event.scheduledEvent = currTime + event.delta;
|
2020-08-19 01:34:39 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-08-24 21:11:40 +00:00
|
|
|
if (event.scheduledEvent < currTime) {
|
|
|
|
// timer needs to be called
|
|
|
|
event.handlr(this, currTime);
|
|
|
|
event.scheduledEvent = currTime + event.delta;
|
|
|
|
}
|
2020-08-19 01:34:39 +00:00
|
|
|
}
|
2020-08-22 17:19:46 +00:00
|
|
|
}
|