mirror of
https://github.com/OpenFusionProject/OpenFusion.git
synced 2025-10-15 02:10:06 +00:00
Compare commits
15 Commits
a9af8713bc
...
1.5
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ab480d88f1 | ||
![]() |
89772d763b | ||
bd0cc3c212 | |||
c636c538eb | |||
d3bef95a7f | |||
![]() |
650f947451 | ||
![]() |
b12aecad63 | ||
![]() |
5bf0c8f3ea | ||
![]() |
2ddc956c9b | ||
![]() |
4f0ae027a5 | ||
23ab908366 | |||
be6a4c0a5d | |||
8eb1af20c8 | |||
e73daa0865 | |||
743a39c125 |
1
.dockerignore
Normal file
1
.dockerignore
Normal file
@@ -0,0 +1 @@
|
||||
version.h
|
4
.github/workflows/check-builds.yaml
vendored
4
.github/workflows/check-builds.yaml
vendored
@@ -53,7 +53,7 @@ jobs:
|
||||
- name: Upload build artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: 'ubuntu20_04-bin-x64-${{ env.SHORT_SHA }}'
|
||||
name: 'ubuntu22_04-bin-x64-${{ env.SHORT_SHA }}'
|
||||
path: bin
|
||||
|
||||
windows-build:
|
||||
@@ -112,7 +112,7 @@ jobs:
|
||||
|
||||
copy-artifacts:
|
||||
if: github.event_name != 'pull_request' && github.ref == 'refs/heads/master'
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [windows-build, ubuntu-build]
|
||||
env:
|
||||
BOT_SSH_KEY: ${{ secrets.BOT_SSH_KEY }}
|
||||
|
26
.vscode/launch.json
vendored
Normal file
26
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug (Linux)",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/bin/fusion",
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"name": "Debug (Windows)",
|
||||
"type": "cppvsdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/bin/Debug/winfusion.exe",
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"name": "Release (Windows)",
|
||||
"type": "cppvsdbg",
|
||||
"request": "launch",
|
||||
"program": "${workspaceFolder}/bin/Release/winfusion.exe",
|
||||
"cwd": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
@@ -44,7 +44,7 @@ add_executable(openfusion ${SOURCES})
|
||||
set_target_properties(openfusion PROPERTIES OUTPUT_NAME ${BIN_NAME})
|
||||
|
||||
# find sqlite3 and use it
|
||||
find_package(sqlite3 REQUIRED)
|
||||
find_package(SQLite3 REQUIRED)
|
||||
target_include_directories(openfusion PRIVATE ${SQLite3_INCLUDE_DIRS})
|
||||
target_link_libraries(openfusion PRIVATE ${SQLite3_LIBRARIES})
|
||||
|
||||
@@ -56,5 +56,5 @@ set_property(TARGET openfusion PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_S
|
||||
# It's not something you should do, but it's there if you need it...
|
||||
if (NOT CMAKE_GENERATOR MATCHES "Visual Studio" AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND NOT CMAKE_GENERATOR MATCHES "MinGW Makefiles")
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(openfusion pthread)
|
||||
target_link_libraries(openfusion PRIVATE pthread)
|
||||
endif()
|
||||
|
21
Dockerfile
Normal file
21
Dockerfile
Normal file
@@ -0,0 +1,21 @@
|
||||
FROM debian:latest
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
RUN apt-get -y update && apt-get install -y \
|
||||
git \
|
||||
clang \
|
||||
make \
|
||||
libsqlite3-dev
|
||||
|
||||
COPY . ./
|
||||
|
||||
RUN make -j8
|
||||
|
||||
# tabledata should be copied from the host;
|
||||
# clone it there before building the container
|
||||
#RUN git submodule update --init --recursive
|
||||
|
||||
CMD ["./bin/fusion"]
|
||||
|
||||
LABEL Name=openfusion Version=0.0.1
|
@@ -13,13 +13,13 @@ OpenFusion is a reverse-engineered server for FusionFall. It primarily targets v
|
||||
|
||||
### Getting Started
|
||||
#### Method A: Installer (Easiest)
|
||||
1. Download the client installer by clicking [here](https://github.com/OpenFusionProject/OpenFusion/releases/download/1.4/OpenFusionClient-1.4-Installer.exe) - choose to run the file.
|
||||
1. Download the client installer by clicking [here](https://github.com/OpenFusionProject/OpenFusion/releases/download/1.5/OpenFusionClient-1.5-Installer.exe) - choose to run the file.
|
||||
2. After a few moments, the client should open: you will be given a choice between two public servers by default. Select the one you wish to play and click connect.
|
||||
3. To create an account, simply enter the details you wish to use at the login screen then click Log In. Do *not* click register, as this will just lead to a blank screen.
|
||||
4. Make a new character, and enjoy the game! Your progress will be saved automatically, and you can resume playing by entering the login details you used in step 3.
|
||||
|
||||
#### Method B: Standalone .zip file
|
||||
1. Download the client from [here](https://github.com/OpenFusionProject/OpenFusion/releases/download/1.4/OpenFusionClient-1.4.zip).
|
||||
1. Download the client from [here](https://github.com/OpenFusionProject/OpenFusion/releases/download/1.5/OpenFusionClient-1.5.zip).
|
||||
2. Extract it to a folder of your choice. Note: if you are upgrading from an older version, it is preferable to start with a fresh folder rather than overwriting a previous install.
|
||||
3. Run OpenFusionClient.exe - you will be given a choice between two public servers by default. Select the one you wish to play and click connect.
|
||||
4. To create an account, simply enter the details you wish to use at the login screen then click Log In. Do *not* click register, as this will just lead to a blank screen.
|
||||
@@ -29,7 +29,7 @@ Instructions for getting the client to run on Linux through Wine can be found [h
|
||||
|
||||
### Hosting a server
|
||||
|
||||
1. Grab `OpenFusionServer-1.4-original.zip` or `OpenFusionServer-1.4-academy.zip` from [here](https://github.com/OpenFusionProject/OpenFusion/releases/tag/1.4).
|
||||
1. Grab `OpenFusionServer-1.5-original.zip` or `OpenFusionServer-1.5-academy.zip` from [here](https://github.com/OpenFusionProject/OpenFusion/releases/tag/1.5).
|
||||
2. Extract it to a folder of your choice, then run `winfusion.exe` (Windows) or `fusion` (Linux) to start the server.
|
||||
3. Add a new server to the client's list:
|
||||
1. For Description, enter anything you want. This is what will show up in the server list.
|
||||
@@ -83,7 +83,7 @@ This just works if you're all under the same LAN, but if you want to play over t
|
||||
|
||||
## Compiling
|
||||
|
||||
OpenFusion has one external dependency: SQLite. You can install it on Windows using `vcpkg`, and on Unix/Linux using your distribution's package manager. For a more indepth guide on how to set up vcpkg, [read this guide on the wiki](https://github.com/OpenFusionProject/OpenFusion/wiki/Installing-SQLite-on-Windows-using-vcpkg).
|
||||
OpenFusion has one external dependency: SQLite. The oldest compatible version is `3.33.0`. You can install it on Windows using `vcpkg`, and on Unix/Linux using your distribution's package manager. For a more indepth guide on how to set up vcpkg, [read this guide on the wiki](https://github.com/OpenFusionProject/OpenFusion/wiki/Installing-SQLite-on-Windows-using-vcpkg).
|
||||
|
||||
You have two choices for compiling OpenFusion: the included Makefile and the included CMakeLists file.
|
||||
|
||||
|
12
docker-compose.yml
Normal file
12
docker-compose.yml
Normal file
@@ -0,0 +1,12 @@
|
||||
version: '3.4'
|
||||
|
||||
services:
|
||||
openfusion:
|
||||
image: openfusion
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./Dockerfile
|
||||
ports:
|
||||
- "23000:23000"
|
||||
- "23001:23001"
|
||||
- "8003:8003"
|
@@ -69,31 +69,41 @@ static void setValuePlayer(CNSocket* sock, CNPacketData* data) {
|
||||
|
||||
// Handle serverside value-changes
|
||||
switch (setData->iSetValueType) {
|
||||
case 1:
|
||||
plr->HP = setData->iSetValue;
|
||||
case CN_GM_SET_VALUE_TYPE__HP:
|
||||
response.iSetValue = plr->HP = setData->iSetValue;
|
||||
break;
|
||||
case 2:
|
||||
case CN_GM_SET_VALUE_TYPE__WEAPON_BATTERY :
|
||||
plr->batteryW = setData->iSetValue;
|
||||
|
||||
// caps
|
||||
if (plr->batteryW > 9999)
|
||||
plr->batteryW = 9999;
|
||||
|
||||
response.iSetValue = plr->batteryW;
|
||||
break;
|
||||
case 3:
|
||||
case CN_GM_SET_VALUE_TYPE__NANO_BATTERY:
|
||||
plr->batteryN = setData->iSetValue;
|
||||
|
||||
// caps
|
||||
if (plr->batteryN > 9999)
|
||||
plr->batteryN = 9999;
|
||||
|
||||
response.iSetValue = plr->batteryN;
|
||||
break;
|
||||
case 4:
|
||||
case CN_GM_SET_VALUE_TYPE__FUSION_MATTER:
|
||||
Missions::updateFusionMatter(sock, setData->iSetValue - plr->fusionmatter);
|
||||
response.iSetValue = plr->fusionmatter;
|
||||
break;
|
||||
case 5:
|
||||
plr->money = setData->iSetValue;
|
||||
case CN_GM_SET_VALUE_TYPE__CANDY:
|
||||
response.iSetValue = plr->money = setData->iSetValue;
|
||||
break;
|
||||
case CN_GM_SET_VALUE_TYPE__SPEED:
|
||||
case CN_GM_SET_VALUE_TYPE__JUMP:
|
||||
response.iSetValue = setData->iSetValue;
|
||||
break;
|
||||
}
|
||||
|
||||
response.iPC_ID = setData->iPC_ID;
|
||||
response.iSetValue = setData->iSetValue;
|
||||
response.iSetValueType = setData->iSetValueType;
|
||||
|
||||
sock->sendPacket(response, P_FE2CL_GM_REP_PC_SET_VALUE);
|
||||
|
@@ -358,23 +358,19 @@ static void npcRotateCommand(std::string full, std::vector<std::string>& args, C
|
||||
int angle = (plr->angle + 180) % 360;
|
||||
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, npc->x, npc->y, npc->z, npc->instanceID, angle);
|
||||
|
||||
// if it's a gruntwork NPC, rotate in-place
|
||||
if (TableData::RunningMobs.find(npc->appearanceData.iNPC_ID) != TableData::RunningMobs.end()) {
|
||||
NPCManager::updateNPCPosition(npc->appearanceData.iNPC_ID, npc->x, npc->y, npc->z, npc->instanceID, angle);
|
||||
bool isGruntworkNpc = true;
|
||||
|
||||
Chat::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for gruntwork NPC "
|
||||
+ std::to_string(npc->appearanceData.iNPC_ID));
|
||||
} else {
|
||||
// add a rotation entry to the gruntwork file, unless it's already a gruntwork NPC
|
||||
if (TableData::RunningMobs.find(npc->appearanceData.iNPC_ID) == TableData::RunningMobs.end()) {
|
||||
TableData::RunningNPCRotations[npc->appearanceData.iNPC_ID] = angle;
|
||||
|
||||
Chat::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) + " for NPC "
|
||||
+ std::to_string(npc->appearanceData.iNPC_ID));
|
||||
isGruntworkNpc = false;
|
||||
}
|
||||
|
||||
// update rotation clientside
|
||||
INITSTRUCT(sP_FE2CL_NPC_ENTER, pkt);
|
||||
pkt.NPCAppearanceData = npc->appearanceData;
|
||||
sock->sendPacket(pkt, P_FE2CL_NPC_ENTER);
|
||||
Chat::sendServerMessage(sock, "[NPCR] Successfully set angle to " + std::to_string(angle) +
|
||||
" for " + (isGruntworkNpc ? "gruntwork " : "") + "NPC " + std::to_string(npc->appearanceData.iNPC_ID));
|
||||
|
||||
// update rotation clientside by refreshing the player's chunks (same as the /refresh command)
|
||||
PlayerManager::updatePlayerPositionForWarp(sock, plr->x, plr->y, plr->z, plr->instanceID);
|
||||
}
|
||||
|
||||
static void refreshCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
|
||||
|
@@ -37,6 +37,22 @@ public:
|
||||
const char *what() const throw() { return msg.c_str(); }
|
||||
};
|
||||
|
||||
/*
|
||||
* We must refuse to run if an invalid NPC type is found in the JSONs, especially
|
||||
* the gruntwork file. If we were to just skip loading invalid NPCs, they would get
|
||||
* silently dropped from the gruntwork file, which would be confusing in situations
|
||||
* where a gruntwork file for the wrong game build was accidentally loaded.
|
||||
*/
|
||||
static void ensureValidNPCType(int type, std::string filename) {
|
||||
// last known NPC type
|
||||
int npcLimit = NPCManager::NPCData.back()["m_iNpcNumber"];
|
||||
|
||||
if (type > npcLimit) {
|
||||
std::cout << "[FATAL] " << filename << " contains an invalid NPC type: " << type << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a full and properly-paced path by interpolating between keyframes.
|
||||
*/
|
||||
@@ -662,6 +678,8 @@ static void loadEggs(json& eggData, int32_t* nextId) {
|
||||
* Load gruntwork output, if it exists
|
||||
*/
|
||||
static void loadGruntworkPre(json& gruntwork, int32_t* nextId) {
|
||||
if (gruntwork.is_null())
|
||||
return;
|
||||
|
||||
try {
|
||||
auto paths = gruntwork["paths"];
|
||||
@@ -711,8 +729,8 @@ static void loadGruntworkPre(json& gruntwork, int32_t* nextId) {
|
||||
}
|
||||
|
||||
static void loadGruntworkPost(json& gruntwork, int32_t* nextId) {
|
||||
|
||||
if (gruntwork.is_null()) return;
|
||||
if (gruntwork.is_null())
|
||||
return;
|
||||
|
||||
try {
|
||||
// skyway paths
|
||||
@@ -764,6 +782,8 @@ static void loadGruntworkPost(json& gruntwork, int32_t* nextId) {
|
||||
int id = (*nextId)--;
|
||||
uint64_t instanceID = mob.find("iMapNum") == mob.end() ? INSTANCE_OVERWORLD : (int)mob["iMapNum"];
|
||||
|
||||
ensureValidNPCType((int)mob["iNPCType"], settings::GRUNTWORKJSON);
|
||||
|
||||
if (NPCManager::NPCData[(int)mob["iNPCType"]]["m_iTeam"] == 2) {
|
||||
npc = new Mob(mob["iX"], mob["iY"], mob["iZ"], instanceID, mob["iNPCType"],
|
||||
NPCManager::NPCData[(int)mob["iNPCType"]], id);
|
||||
@@ -783,6 +803,9 @@ static void loadGruntworkPost(json& gruntwork, int32_t* nextId) {
|
||||
auto groups = gruntwork["groups"];
|
||||
for (auto _group = groups.begin(); _group != groups.end(); _group++) {
|
||||
auto leader = _group.value();
|
||||
|
||||
ensureValidNPCType((int)leader["iNPCType"], settings::GRUNTWORKJSON);
|
||||
|
||||
auto td = NPCManager::NPCData[(int)leader["iNPCType"]];
|
||||
uint64_t instanceID = leader.find("iMapNum") == leader.end() ? INSTANCE_OVERWORLD : (int)leader["iMapNum"];
|
||||
|
||||
@@ -803,6 +826,9 @@ static void loadGruntworkPost(json& gruntwork, int32_t* nextId) {
|
||||
int followerCount = 0;
|
||||
for (json::iterator _fol = followers.begin(); _fol != followers.end(); _fol++) {
|
||||
auto follower = _fol.value();
|
||||
|
||||
ensureValidNPCType((int)follower["iNPCType"], settings::GRUNTWORKJSON);
|
||||
|
||||
auto tdFol = NPCManager::NPCData[(int)follower["iNPCType"]];
|
||||
Mob* tmpFol = new Mob((int)leader["iX"] + (int)follower["iOffsetX"], (int)leader["iY"] + (int)follower["iOffsetY"], leader["iZ"], leader["iAngle"], instanceID, follower["iNPCType"], tdFol, *nextId);
|
||||
|
||||
@@ -859,10 +885,9 @@ static void loadNPCs(json& npcData) {
|
||||
npcID += NPC_ID_OFFSET;
|
||||
int instanceID = npc.find("iMapNum") == npc.end() ? INSTANCE_OVERWORLD : (int)npc["iMapNum"];
|
||||
int type = (int)npc["iNPCType"];
|
||||
if (NPCManager::NPCData[type].is_null()) {
|
||||
std::cout << "[WARN] NPC type " << type << " not found; skipping (json#" << _npc.key() << ")" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
ensureValidNPCType(type, settings::NPCJSON);
|
||||
|
||||
#ifdef ACADEMY
|
||||
// do not spawn NPCs in the future
|
||||
if (npc["iX"] > 512000 && npc["iY"] < 256000)
|
||||
@@ -904,10 +929,9 @@ static void loadMobs(json& npcData, int32_t* nextId) {
|
||||
int npcID = std::strtol(_npc.key().c_str(), nullptr, 10); // parse ID string to integer
|
||||
npcID += MOB_ID_OFFSET;
|
||||
int type = (int)npc["iNPCType"];
|
||||
if (NPCManager::NPCData[type].is_null()) {
|
||||
std::cout << "[WARN] NPC type " << type << " not found; skipping (json#" << _npc.key() << ")" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
ensureValidNPCType(type, settings::MOBJSON);
|
||||
|
||||
auto td = NPCManager::NPCData[type];
|
||||
uint64_t instanceID = npc.find("iMapNum") == npc.end() ? INSTANCE_OVERWORLD : (int)npc["iMapNum"];
|
||||
|
||||
@@ -935,7 +959,10 @@ static void loadMobs(json& npcData, int32_t* nextId) {
|
||||
for (json::iterator _group = groupData.begin(); _group != groupData.end(); _group++) {
|
||||
auto leader = _group.value();
|
||||
int leadID = std::strtol(_group.key().c_str(), nullptr, 10); // parse ID string to integer
|
||||
|
||||
leadID += MOB_GROUP_ID_OFFSET;
|
||||
ensureValidNPCType(leader["iNPCType"], settings::MOBJSON);
|
||||
|
||||
auto td = NPCManager::NPCData[(int)leader["iNPCType"]];
|
||||
uint64_t instanceID = leader.find("iMapNum") == leader.end() ? INSTANCE_OVERWORLD : (int)leader["iMapNum"];
|
||||
auto followers = leader["aFollowers"];
|
||||
@@ -965,6 +992,9 @@ static void loadMobs(json& npcData, int32_t* nextId) {
|
||||
int followerCount = 0;
|
||||
for (json::iterator _fol = followers.begin(); _fol != followers.end(); _fol++) {
|
||||
auto follower = _fol.value();
|
||||
|
||||
ensureValidNPCType(follower["iNPCType"], settings::MOBJSON);
|
||||
|
||||
auto tdFol = NPCManager::NPCData[(int)follower["iNPCType"]];
|
||||
Mob* tmpFol = new Mob((int)leader["iX"] + (int)follower["iOffsetX"], (int)leader["iY"] + (int)follower["iOffsetY"], leader["iZ"], leader["iAngle"], instanceID, follower["iNPCType"], tdFol, *nextId);
|
||||
|
||||
@@ -1070,19 +1100,39 @@ void TableData::init() {
|
||||
};
|
||||
|
||||
// load JSON data into tables
|
||||
std::ifstream fstream;
|
||||
for (int i = 0; i < 7; i++) {
|
||||
std::pair<json*, std::string>& table = tables[i];
|
||||
fstream.open(settings::TDATADIR + "/" + table.second); // open file
|
||||
if (!fstream.fail()) {
|
||||
fstream >> *table.first; // load file contents into table
|
||||
} else {
|
||||
if (table.first != &gruntwork) { // gruntwork isn't critical
|
||||
|
||||
// scope for fstream
|
||||
{
|
||||
std::ifstream fstream;
|
||||
fstream.open(settings::TDATADIR + "/" + table.second); // open file
|
||||
|
||||
// did we fail to open the file?
|
||||
if (fstream.fail()) {
|
||||
// gruntwork isn't critical
|
||||
if (table.first == &gruntwork)
|
||||
continue;
|
||||
|
||||
std::cerr << "[FATAL] Critical tdata file missing: " << table.second << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// is the file empty?
|
||||
if (fstream.peek() == std::ifstream::traits_type::eof()) {
|
||||
// tolerate empty gruntwork file
|
||||
if (table.first == &gruntwork) {
|
||||
std::cout << "[WARN] The gruntwork file is empty" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::cerr << "[FATAL] Critical tdata file is empty: " << table.second << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// load file contents into table
|
||||
fstream >> *table.first;
|
||||
}
|
||||
fstream.close();
|
||||
|
||||
// patching: load each patch directory specified in the config file
|
||||
|
||||
@@ -1097,11 +1147,11 @@ void TableData::init() {
|
||||
std::string patchModuleName = *it;
|
||||
std::string patchFile = settings::PATCHDIR + patchModuleName + "/" + table.second;
|
||||
try {
|
||||
std::ifstream fstream;
|
||||
fstream.open(patchFile);
|
||||
fstream >> patch; // load into temporary json object
|
||||
std::cout << "[INFO] Patching " << patchFile << std::endl;
|
||||
patchJSON(table.first, &patch); // patch
|
||||
fstream.close();
|
||||
} catch (const std::exception& err) {
|
||||
// no-op
|
||||
}
|
||||
|
@@ -41,6 +41,7 @@ namespace Database {
|
||||
uint64_t Timestamp;
|
||||
};
|
||||
|
||||
void init();
|
||||
void open();
|
||||
void close();
|
||||
|
||||
|
@@ -236,7 +236,20 @@ static int getTableSize(std::string tableName) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void Database::init() {
|
||||
std::cout << "[INFO] Built with libsqlite " SQLITE_VERSION << std::endl;
|
||||
|
||||
if (sqlite3_libversion_number() != SQLITE_VERSION_NUMBER)
|
||||
std::cout << "[INFO] Using libsqlite " << std::string(sqlite3_libversion()) << std::endl;
|
||||
|
||||
if (sqlite3_libversion_number() < MIN_SUPPORTED_SQLITE_NUMBER) {
|
||||
std::cerr << "[FATAL] Runtime sqlite version too old. Minimum compatible version: " MIN_SUPPORTED_SQLITE << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void Database::open() {
|
||||
|
||||
// XXX: move locks here
|
||||
int rc = sqlite3_open(settings::DBPATH.c_str(), &db);
|
||||
if (rc != SQLITE_OK) {
|
||||
|
@@ -3,6 +3,15 @@
|
||||
#include "db/Database.hpp"
|
||||
#include <sqlite3.h>
|
||||
|
||||
#define MIN_SUPPORTED_SQLITE_NUMBER 3033000
|
||||
#define MIN_SUPPORTED_SQLITE "3.33.0"
|
||||
// we can't use this in #error, since it doesn't expand macros
|
||||
|
||||
// Compile-time libsqlite version check
|
||||
#if SQLITE_VERSION_NUMBER < MIN_SUPPORTED_SQLITE_NUMBER
|
||||
#error libsqlite version too old. Minimum compatible version: 3.33.0
|
||||
#endif
|
||||
|
||||
extern std::mutex dbCrit;
|
||||
extern sqlite3 *db;
|
||||
|
||||
|
16
src/main.cpp
16
src/main.cpp
@@ -98,6 +98,9 @@ void initsignals() {
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -105,15 +108,15 @@ int main() {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
initsignals();
|
||||
settings::init();
|
||||
|
||||
std::cout << "[INFO] OpenFusion v" GIT_VERSION << std::endl;
|
||||
std::cout << "[INFO] Protocol version: " << PROTOCOL_VERSION << std::endl;
|
||||
std::cout << "[INFO] Intializing Packet Managers..." << std::endl;
|
||||
|
||||
Database::init();
|
||||
Rand::init(getTime());
|
||||
TableData::init();
|
||||
|
||||
std::cout << "[INFO] Intializing Packet Managers..." << std::endl;
|
||||
|
||||
PlayerManager::init();
|
||||
PlayerMovement::init();
|
||||
BuiltinCommands::init();
|
||||
@@ -132,9 +135,10 @@ int main() {
|
||||
Email::init();
|
||||
Groups::init();
|
||||
Racing::init();
|
||||
Database::open();
|
||||
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;
|
||||
|
Reference in New Issue
Block a user