mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2024-11-05 15:00:06 +00:00
dongresource
be6a4c0a5d
The server now checks the libsqlite both at compile time and on server startup. The version the executable was built with and the one it's running with may be different, so long as they're both at or above the minimum supported version. One or both version numbers are printed on startup, depending on if they're identical or not. The compile-time ("Built with") version depends on the sqlite3.h header used during compilation, while the runtime ("Using") version depends on either: * The sqlite3.c version used during compilation, if statically linked. (Which may be different from the header version and still compile and run fine.) * The version of the libsqlite3.so or sqlite3.dll that the server loaded, if dynamically linked. Version mismatches here are normal, especially on Unix systems with their own system libraries. The current minimum version is 3.33.0, from 2020-08-14, as that's the one that introduced the UPDATE-FROM syntax used during login by Database::updateSelectedByPlayerId(). Also rearranged the prints and initialization calls in main() slightly.
239 lines
5.9 KiB
C++
239 lines
5.9 KiB
C++
#include "servers/CNLoginServer.hpp"
|
|
#include "servers/CNShardServer.hpp"
|
|
#include "PlayerManager.hpp"
|
|
#include "PlayerMovement.hpp"
|
|
#include "BuiltinCommands.hpp"
|
|
#include "Buddies.hpp"
|
|
#include "CustomCommands.hpp"
|
|
#include "Combat.hpp"
|
|
#include "Items.hpp"
|
|
#include "Missions.hpp"
|
|
#include "Nanos.hpp"
|
|
#include "NPCManager.hpp"
|
|
#include "Transport.hpp"
|
|
#include "Buddies.hpp"
|
|
#include "db/Database.hpp"
|
|
#include "TableData.hpp"
|
|
#include "Groups.hpp"
|
|
#include "servers/Monitor.hpp"
|
|
#include "Racing.hpp"
|
|
#include "Trading.hpp"
|
|
#include "Email.hpp"
|
|
#include "Vendors.hpp"
|
|
#include "Chat.hpp"
|
|
#include "Eggs.hpp"
|
|
#include "Rand.hpp"
|
|
|
|
#include "settings.hpp"
|
|
#include "sandbox/Sandbox.hpp"
|
|
|
|
#include "../version.h"
|
|
|
|
#if defined(__MINGW32__) && !defined(_GLIBCXX_HAS_GTHREADS)
|
|
#include "mingw/mingw.thread.h"
|
|
#else
|
|
#include <thread>
|
|
#endif
|
|
#include <string>
|
|
#include <chrono>
|
|
#include <signal.h>
|
|
|
|
// HACK
|
|
#ifdef __has_feature
|
|
#if __has_feature(address_sanitizer)
|
|
#define __SANITIZE_ADDRESS__ 1
|
|
#endif
|
|
#endif
|
|
|
|
CNShardServer *shardServer = nullptr;
|
|
std::thread *shardThread = nullptr;
|
|
|
|
void startShard(CNShardServer* server) {
|
|
server->start();
|
|
}
|
|
|
|
// terminate gracefully on SIGINT (for gprof & DB saving)
|
|
void terminate(int arg) {
|
|
std::cout << "OpenFusion: terminating." << std::endl;
|
|
|
|
if (shardServer != nullptr && shardThread != nullptr)
|
|
shardServer->kill();
|
|
|
|
Database::close();
|
|
exit(0);
|
|
}
|
|
|
|
#ifdef _WIN32
|
|
static BOOL winTerminate(DWORD arg) {
|
|
terminate(0);
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
void initsignals() {
|
|
#ifdef _WIN32
|
|
if (!SetConsoleCtrlHandler(winTerminate, TRUE)) {
|
|
std::cerr << "[FATAL] Failed to set control handler" << std::endl;
|
|
exit(1);
|
|
}
|
|
#else
|
|
struct sigaction act;
|
|
|
|
memset((void*)&act, 0, sizeof(act));
|
|
sigemptyset(&act.sa_mask);
|
|
|
|
// tell the OS to not kill us if you use a broken pipe, just let us know thru recv() or send()
|
|
act.sa_handler = SIG_IGN;
|
|
if (sigaction(SIGPIPE, &act, NULL) < 0) {
|
|
perror("sigaction");
|
|
exit(1);
|
|
}
|
|
|
|
act.sa_handler = terminate;
|
|
if (sigaction(SIGINT, &act, NULL) < 0) {
|
|
perror("sigaction");
|
|
exit(1);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int main() {
|
|
std::cout << "[INFO] OpenFusion v" GIT_VERSION << std::endl;
|
|
std::cout << "[INFO] Protocol version: " << PROTOCOL_VERSION << std::endl;
|
|
|
|
#ifdef _WIN32
|
|
WSADATA wsaData;
|
|
if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
|
|
std::cerr << "OpenFusion: WSAStartup failed" << std::endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
#endif
|
|
|
|
initsignals();
|
|
settings::init();
|
|
Database::init();
|
|
Rand::init(getTime());
|
|
TableData::init();
|
|
|
|
std::cout << "[INFO] Intializing Packet Managers..." << std::endl;
|
|
|
|
PlayerManager::init();
|
|
PlayerMovement::init();
|
|
BuiltinCommands::init();
|
|
Buddies::init();
|
|
CustomCommands::init();
|
|
Combat::init();
|
|
Chat::init();
|
|
Items::init();
|
|
Eggs::init();
|
|
Missions::init();
|
|
Nanos::init();
|
|
NPCManager::init();
|
|
Vendors::init();
|
|
Transport::init();
|
|
Buddies::init();
|
|
Email::init();
|
|
Groups::init();
|
|
Racing::init();
|
|
Trading::init();
|
|
|
|
Database::open();
|
|
|
|
switch (settings::EVENTMODE) {
|
|
case 0: break; // no event
|
|
case 1: std::cout << "[INFO] Event active. Hey, Hey It's Knishmas!" << std::endl; break;
|
|
case 2: std::cout << "[INFO] Event active. Wishing you a spook-tacular Halloween!" << std::endl; break;
|
|
case 3: std::cout << "[INFO] Event active. Have a very hoppy Easter!" << std::endl; break;
|
|
default:
|
|
std::cout << "[FATAL] Unknown event set in config file." << std::endl;
|
|
exit(1);
|
|
/* not reached */
|
|
}
|
|
|
|
std::cout << "[INFO] Starting Server Threads..." << std::endl;
|
|
CNLoginServer loginServer(settings::LOGINPORT);
|
|
shardServer = new CNShardServer(settings::SHARDPORT);
|
|
|
|
shardThread = new std::thread(startShard, (CNShardServer*)shardServer);
|
|
|
|
sandbox_start();
|
|
|
|
loginServer.start();
|
|
|
|
shardServer->kill();
|
|
shardThread->join();
|
|
|
|
#ifdef _WIN32
|
|
WSACleanup();
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
// helper functions
|
|
|
|
std::string U16toU8(char16_t* src, size_t max) {
|
|
src[max-1] = '\0'; // force a NULL terminator
|
|
try {
|
|
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
|
|
std::string ret = convert.to_bytes(src);
|
|
|
|
if (ret.size() >= max)
|
|
ret.resize(max-2);
|
|
|
|
return ret;
|
|
} catch(const std::exception& e) {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
// returns number of char16_t that was written at des
|
|
size_t U8toU16(std::string src, char16_t* des, size_t max) {
|
|
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
|
|
std::u16string tmp = convert.from_bytes(src);
|
|
|
|
// copy utf16 string to buffer
|
|
if (sizeof(char16_t) * tmp.length() > max) // make sure we don't write outside the buffer
|
|
memcpy(des, tmp.c_str(), sizeof(char16_t) * max);
|
|
else
|
|
memcpy(des, tmp.c_str(), sizeof(char16_t) * tmp.length());
|
|
des[tmp.length()] = '\0';
|
|
|
|
return tmp.length();
|
|
}
|
|
|
|
time_t getTime() {
|
|
using namespace std::chrono;
|
|
|
|
milliseconds value = duration_cast<milliseconds>((time_point_cast<milliseconds>(steady_clock::now())).time_since_epoch());
|
|
|
|
return (time_t)value.count();
|
|
}
|
|
|
|
// returns system time in seconds
|
|
time_t getTimestamp() {
|
|
using namespace std::chrono;
|
|
|
|
seconds value = duration_cast<seconds>((time_point_cast<seconds>(system_clock::now())).time_since_epoch());
|
|
|
|
return (time_t)value.count();
|
|
}
|
|
|
|
// convert integer timestamp (in s) to FF systime struct
|
|
sSYSTEMTIME timeStampToStruct(uint64_t time) {
|
|
|
|
const time_t timeProper = time;
|
|
tm ts = *localtime(&timeProper);
|
|
|
|
sSYSTEMTIME systime;
|
|
systime.wMilliseconds = 0;
|
|
systime.wSecond = ts.tm_sec;
|
|
systime.wMinute = ts.tm_min;
|
|
systime.wHour = ts.tm_hour;
|
|
systime.wDay = ts.tm_mday;
|
|
systime.wDayOfWeek = ts.tm_wday + 1;
|
|
systime.wMonth = ts.tm_mon + 1;
|
|
systime.wYear = ts.tm_year + 1900;
|
|
|
|
return systime;
|
|
}
|