2 Commits

Author SHA1 Message Date
3cfecd9644 Refuse to run if the specified build name isn't in the patch map 2023-06-26 06:48:12 +02:00
6537e38987 Replace enabledpatches config option with patchmap.json
This should make it a lot easier to manage patch directories when we add
support for each known client build.
2023-06-26 05:42:57 +02:00
10 changed files with 63 additions and 129 deletions

26
.vscode/launch.json vendored
View File

@@ -1,26 +0,0 @@
{
"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}"
}
]
}

View File

@@ -44,7 +44,7 @@ add_executable(openfusion ${SOURCES})
set_target_properties(openfusion PROPERTIES OUTPUT_NAME ${BIN_NAME}) set_target_properties(openfusion PROPERTIES OUTPUT_NAME ${BIN_NAME})
# find sqlite3 and use it # find sqlite3 and use it
find_package(SQLite3 REQUIRED) find_package(sqlite3 REQUIRED)
target_include_directories(openfusion PRIVATE ${SQLite3_INCLUDE_DIRS}) target_include_directories(openfusion PRIVATE ${SQLite3_INCLUDE_DIRS})
target_link_libraries(openfusion PRIVATE ${SQLite3_LIBRARIES}) 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... # 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") 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) find_package(Threads REQUIRED)
target_link_libraries(openfusion PRIVATE pthread) target_link_libraries(openfusion pthread)
endif() endif()

View File

@@ -1,21 +0,0 @@
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

View File

@@ -1,3 +1,8 @@
# name of the client build the server is targetting.
# used for determining which patches to apply.
# default is beta-20111013 for Academy, beta-20100104 otherwise.
#buildname=beta-20100104
# verbosity level # verbosity level
# 0 = mostly silence # 0 = mostly silence
# 1 = debug prints and unknown packets # 1 = debug prints and unknown packets
@@ -46,16 +51,6 @@ motd=Welcome to OpenFusion!
# location of the patch folder # location of the patch folder
#patchdir=tdata/patch/ #patchdir=tdata/patch/
# Space-separated list of patch folders in patchdir to load from.
# If you uncomment this, note that Academy builds *must* contain 1013,
# and pre-Academy builds must *not* contain it.
#enabledpatches=1013
# Use Original FusionFall's racing score and reward calculation?
# Set false to use Retro's calculation, make sure you have the correct
# patch(es) loaded.
#ogracingscores=true
# xdt json filename # xdt json filename
#xdtdata=xdt.json #xdtdata=xdt.json
# NPC json filename # NPC json filename
@@ -66,6 +61,8 @@ motd=Welcome to OpenFusion!
#pathdata=paths.json #pathdata=paths.json
# drop json filename # drop json filename
#dropdata=drops.json #dropdata=drops.json
# patchmap json filename
#patchmapdata=patchmap.json
# gruntwork output filename (this is what you submit) # gruntwork output filename (this is what you submit)
#gruntwork=gruntwork.json #gruntwork=gruntwork.json
# location of the database # location of the database

View File

@@ -1,12 +0,0 @@
version: '3.4'
services:
openfusion:
image: openfusion
build:
context: .
dockerfile: ./Dockerfile
ports:
- "23000:23000"
- "23001:23001"
- "8003:8003"

View File

@@ -97,43 +97,31 @@ static void racingEnd(CNSocket* sock, CNPacketData* data) {
if (EPData.find(mapNum) == EPData.end() || EPData[mapNum].EPID == 0) if (EPData.find(mapNum) == EPData.end() || EPData[mapNum].EPID == 0)
return; // IZ not found return; // IZ not found
EPInfo& epInfo = EPData[mapNum];
EPRace& epRace = EPRaces[sock];
uint64_t now = getTime() / 1000; uint64_t now = getTime() / 1000;
int timeDiff = now - epRace.startTime;
int podsCollected = epRace.collectedRings.size();
int score = 0, fm = 0;
if (settings::OGRACINGSCORES) { int timeDiff = now - EPRaces[sock].startTime;
score = std::min(epInfo.maxScore, (int)std::exp( int score = 500 * EPRaces[sock].collectedRings.size() - 10 * timeDiff;
(epInfo.podFactor * podsCollected) / epInfo.maxPods if (score < 0) score = 0; // lol
- (epInfo.timeFactor * timeDiff) / epInfo.maxTime int fm = score * plr->level * (1.0f / 36) * 0.3f;
+ epInfo.scaleFactor));
fm = (1.0 + std::exp(epInfo.scaleFactor - 1.0) * epInfo.podFactor * podsCollected) / epInfo.maxPods;
} else {
score = std::max(0, 500 * podsCollected - 10 * timeDiff);
fm = score * plr->level * (1.0f / 36) * 0.3f;
}
// we submit the ranking first... // we submit the ranking first...
Database::RaceRanking postRanking = {}; Database::RaceRanking postRanking = {};
postRanking.EPID = epInfo.EPID; postRanking.EPID = EPData[mapNum].EPID;
postRanking.PlayerID = plr->iID; postRanking.PlayerID = plr->iID;
postRanking.RingCount = podsCollected; postRanking.RingCount = EPRaces[sock].collectedRings.size();
postRanking.Score = score; postRanking.Score = score;
postRanking.Time = timeDiff; postRanking.Time = timeDiff;
postRanking.Timestamp = getTimestamp(); postRanking.Timestamp = getTimestamp();
Database::postRaceRanking(postRanking); Database::postRaceRanking(postRanking);
// ...then we get the top ranking, which may or may not be what we just submitted // ...then we get the top ranking, which may or may not be what we just submitted
Database::RaceRanking topRankingPlayer = Database::getTopRaceRanking(epInfo.EPID, plr->iID); Database::RaceRanking topRankingPlayer = Database::getTopRaceRanking(EPData[mapNum].EPID, plr->iID);
INITSTRUCT(sP_FE2CL_REP_EP_RACE_END_SUCC, resp); INITSTRUCT(sP_FE2CL_REP_EP_RACE_END_SUCC, resp);
// get rank scores and rewards // get rank scores and rewards
std::vector<int>* rankScores = &EPRewards[epInfo.EPID].first; std::vector<int>* rankScores = &EPRewards[EPData[mapNum].EPID].first;
std::vector<int>* rankRewards = &EPRewards[epInfo.EPID].second; std::vector<int>* rankRewards = &EPRewards[EPData[mapNum].EPID].second;
// top ranking // top ranking
int topRank = 0; int topRank = 0;

View File

@@ -5,11 +5,7 @@
#include "servers/CNShardServer.hpp" #include "servers/CNShardServer.hpp"
struct EPInfo { struct EPInfo {
// available through XDT (maxScore may be updated by drops) int zoneX, zoneY, EPID, maxScore, maxTime;
int zoneX, zoneY, EPID, maxScore;
// (maybe) available through drops
int maxTime = 0, maxPods = 0;
double scaleFactor = 0.0, podFactor = 0.0, timeFactor = 0.0;
}; };
struct EPRace { struct EPRace {

View File

@@ -572,19 +572,8 @@ static void loadDrops(json& dropData) {
continue; continue;
} }
EPInfo& epInfo = Racing::EPData[EPMap];
// time limit isn't stored in the XDT, so we include it in the reward table instead // time limit isn't stored in the XDT, so we include it in the reward table instead
epInfo.maxTime = (int)race["TimeLimit"]; Racing::EPData[EPMap].maxTime = race["TimeLimit"];
// the following has to be present based on the score calculation method
if (settings::OGRACINGSCORES) {
epInfo.maxScore = (int)race["ScoreCap"];
epInfo.maxPods = (int)race["TotalPods"];
epInfo.scaleFactor = (double)race["ScaleFactor"];
epInfo.podFactor = (double)race["PodFactor"];
epInfo.timeFactor = (double)race["TimeFactor"];
}
// score cutoffs // score cutoffs
std::vector<int> rankScores; std::vector<int> rankScores;
@@ -1097,6 +1086,33 @@ static void patchJSON(json* base, json* patch) {
void TableData::init() { void TableData::init() {
int32_t nextId = INT32_MAX; // next dynamic ID to hand out int32_t nextId = INT32_MAX; // next dynamic ID to hand out
json patchmap;
// load patch map
{
std::fstream fstream;
fstream.open(settings::TDATADIR + "/" + settings::PATCHMAPJSON);
if (fstream.fail()) {
std::cerr << "[FATAL] Critical tdata file missing: " << settings::PATCHMAPJSON << std::endl;
exit(1);
}
if (fstream.peek() == std::ifstream::traits_type::eof()) {
std::cerr << "[FATAL] Critical tdata file is empty: " << settings::PATCHMAPJSON << std::endl;
exit(1);
}
fstream >> patchmap;
fstream.close();
}
// ensure that there is a patch list for the current build
if (patchmap["patchmap"].find(settings::BUILDNAME) == patchmap["patchmap"].end()) {
std::cerr << "[FATAL] Build name " << settings::BUILDNAME << " not found in " <<
settings::PATCHMAPJSON << std::endl;
exit(1);
}
// base JSON tables // base JSON tables
json xdt, paths, drops, eggs, npcs, mobs, gruntwork; json xdt, paths, drops, eggs, npcs, mobs, gruntwork;
@@ -1145,15 +1161,13 @@ void TableData::init() {
fstream >> *table.first; fstream >> *table.first;
} }
// patching: load each patch directory specified in the config file // patching: load each patch directory specified in patchmap.json
// split config field into individual patch entries
std::stringstream ss(settings::ENABLEDPATCHES);
std::istream_iterator<std::string> begin(ss);
std::istream_iterator<std::string> end;
// fetch list of patches that need to be applied for the current build
json patch; json patch;
for (auto it = begin; it != end; it++) { json patchlist = patchmap["patchmap"][settings::BUILDNAME];
for (auto it = patchlist.begin(); it != patchlist.end(); it++) {
// this is the theoretical path of a corresponding patch for this file // this is the theoretical path of a corresponding patch for this file
std::string patchModuleName = *it; std::string patchModuleName = *it;
std::string patchFile = settings::PATCHDIR + patchModuleName + "/" + table.second; std::string patchFile = settings::PATCHDIR + patchModuleName + "/" + table.second;

View File

@@ -47,12 +47,13 @@ std::string settings::GRUNTWORKJSON = "gruntwork.json";
std::string settings::MOTDSTRING = "Welcome to OpenFusion!"; std::string settings::MOTDSTRING = "Welcome to OpenFusion!";
std::string settings::DROPSJSON = "drops.json"; std::string settings::DROPSJSON = "drops.json";
std::string settings::PATHJSON = "paths.json"; std::string settings::PATHJSON = "paths.json";
std::string settings::PATCHMAPJSON = "patchmap.json";
#ifdef ACADEMY #ifdef ACADEMY
std::string settings::XDTJSON = "xdt1013.json"; std::string settings::XDTJSON = "xdt1013.json";
std::string settings::ENABLEDPATCHES = "1013"; std::string settings::BUILDNAME = "beta-20111013";
#else #else
std::string settings::XDTJSON = "xdt.json"; std::string settings::XDTJSON = "xdt.json";
std::string settings::ENABLEDPATCHES = ""; std::string settings::BUILDNAME = "beta-20100104";
#endif // ACADEMY #endif // ACADEMY
int settings::ACCLEVEL = 1; int settings::ACCLEVEL = 1;
@@ -66,9 +67,6 @@ int settings::MONITORINTERVAL = 5000;
// event mode settings // event mode settings
int settings::EVENTMODE = 0; int settings::EVENTMODE = 0;
// racing score mode
bool settings::OGRACINGSCORES = true;
void settings::init() { void settings::init() {
INIReader reader("config.ini"); INIReader reader("config.ini");
@@ -81,6 +79,7 @@ void settings::init() {
return; return;
} }
BUILDNAME = reader.Get("", "buildname", BUILDNAME);
VERBOSITY = reader.GetInteger("", "verbosity", VERBOSITY); VERBOSITY = reader.GetInteger("", "verbosity", VERBOSITY);
SANDBOX = reader.GetBoolean("", "sandbox", SANDBOX); SANDBOX = reader.GetBoolean("", "sandbox", SANDBOX);
LOGINPORT = reader.GetInteger("login", "port", LOGINPORT); LOGINPORT = reader.GetInteger("login", "port", LOGINPORT);
@@ -108,12 +107,11 @@ void settings::init() {
DBPATH = reader.Get("shard", "dbpath", DBPATH); DBPATH = reader.Get("shard", "dbpath", DBPATH);
TDATADIR = reader.Get("shard", "tdatadir", TDATADIR); TDATADIR = reader.Get("shard", "tdatadir", TDATADIR);
PATCHDIR = reader.Get("shard", "patchdir", PATCHDIR); PATCHDIR = reader.Get("shard", "patchdir", PATCHDIR);
ENABLEDPATCHES = reader.Get("shard", "enabledpatches", ENABLEDPATCHES); PATCHMAPJSON = reader.Get("shard", "patchmapdata", PATCHMAPJSON);
ACCLEVEL = reader.GetInteger("shard", "accountlevel", ACCLEVEL); ACCLEVEL = reader.GetInteger("shard", "accountlevel", ACCLEVEL);
EVENTMODE = reader.GetInteger("shard", "eventmode", EVENTMODE); EVENTMODE = reader.GetInteger("shard", "eventmode", EVENTMODE);
DISABLEFIRSTUSEFLAG = reader.GetBoolean("shard", "disablefirstuseflag", DISABLEFIRSTUSEFLAG); DISABLEFIRSTUSEFLAG = reader.GetBoolean("shard", "disablefirstuseflag", DISABLEFIRSTUSEFLAG);
ANTICHEAT = reader.GetBoolean("shard", "anticheat", ANTICHEAT); ANTICHEAT = reader.GetBoolean("shard", "anticheat", ANTICHEAT);
OGRACINGSCORES = reader.GetBoolean("shard", "ogracingscores", OGRACINGSCORES);
MONITORENABLED = reader.GetBoolean("monitor", "enabled", MONITORENABLED); MONITORENABLED = reader.GetBoolean("monitor", "enabled", MONITORENABLED);
MONITORPORT = reader.GetInteger("monitor", "port", MONITORPORT); MONITORPORT = reader.GetInteger("monitor", "port", MONITORPORT);
MONITORINTERVAL = reader.GetInteger("monitor", "interval", MONITORINTERVAL); MONITORINTERVAL = reader.GetInteger("monitor", "interval", MONITORINTERVAL);

View File

@@ -29,14 +29,14 @@ namespace settings {
extern std::string GRUNTWORKJSON; extern std::string GRUNTWORKJSON;
extern std::string DBPATH; extern std::string DBPATH;
extern std::string PATCHDIR; extern std::string PATCHDIR;
extern std::string ENABLEDPATCHES; extern std::string PATCHMAPJSON;
extern std::string BUILDNAME;
extern std::string TDATADIR; extern std::string TDATADIR;
extern int EVENTMODE; extern int EVENTMODE;
extern bool MONITORENABLED; extern bool MONITORENABLED;
extern int MONITORPORT; extern int MONITORPORT;
extern int MONITORINTERVAL; extern int MONITORINTERVAL;
extern bool DISABLEFIRSTUSEFLAG; extern bool DISABLEFIRSTUSEFLAG;
extern bool OGRACINGSCORES;
void init(); void init();
} }