OpenFusion/src/main.cpp
dongresource be6a4c0a5d Enforce minimum supported libsqlite version
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.
2023-03-19 01:41:07 +01:00

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;
}