5 Commits

Author SHA1 Message Date
d32dd4c319 added startScript() 2023-12-30 01:53:07 -06:00
c5de584762 define LuaManager::init 2023-12-30 01:00:27 -06:00
450cc78c9a added globalState; minor styling fixes 2023-12-30 00:56:06 -06:00
95f2920f5c start LuaManager
for now it runs a simple test script on init()
2023-12-13 16:42:40 -06:00
27ccda5b10 added Lua to vendor sources
- TODO: add Lua to our makefile eventually
2023-12-13 16:33:32 -06:00
39 changed files with 7898 additions and 7400 deletions

1
.dockerignore Normal file
View File

@@ -0,0 +1 @@
version.h

View File

@@ -1,38 +0,0 @@
name: Push Docker Image
on:
release:
types: [published]
jobs:
push-docker-image:
name: Push Docker Image
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
matrix:
platforms:
- linux/amd64
- linux/arm64
steps:
- uses: actions/checkout@v4
- name: Retrieve major version
uses: winterjung/split@v2
id: split
with:
msg: ${{ github.ref_name }}
separator: .
- name: Log in to registry
uses: docker/login-action@v3
with:
password: ${{ secrets.DOCKERHUB_TOKEN }}
username: ${{ secrets.DOCKERHUB_USERNAME }}
- name: Build and push the Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
platforms: ${{ matrix.platforms }}
push: true
tags: ${{ secrets.DOCKERHUB_REPOSITORY }}:${{ github.ref_name }},${{ secrets.DOCKERHUB_REPOSITORY }}:${{ steps.split.outputs._0 }},${{ secrets.DOCKERHUB_REPOSITORY }}:latest

3
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "tdata"]
path = tdata
url = https://github.com/OpenFusionProject/tabledata.git
[submodule "vendor/Lua"]
path = vendor/Lua
url = https://github.com/walterschell/Lua.git

View File

@@ -34,20 +34,28 @@ else()
set(BIN_NAME fusion)
endif()
# add lua
option(LUA_BUILD_COMPILER OFF)
option(LUA_ENABLE_SHARED OFF)
option(LUA_ENABLE_TESTING OFF)
add_subdirectory(vendor/Lua)
include_directories(src vendor)
file(GLOB_RECURSE SOURCES src/**.[ch]pp vendor/**.[ch]pp vendor/**.[ch] version.h)
file(GLOB_RECURSE VENDOR_SOURCES vendor/bcrypt/**.[ch] vendor/mingw/**.h vendor/INIReader.hpp vendor/JSON.hpp)
file(GLOB_RECURSE SOURCES src/**.[ch]pp version.h)
configure_file(version.h.in ${CMAKE_SOURCE_DIR}/version.h @ONLY)
add_executable(openfusion ${SOURCES})
add_executable(openfusion ${SOURCES} ${VENDOR_SOURCES})
set_target_properties(openfusion PROPERTIES OUTPUT_NAME ${BIN_NAME})
# find sqlite3 and use it
find_package(SQLite3 REQUIRED)
target_include_directories(openfusion PRIVATE ${SQLite3_INCLUDE_DIRS})
target_link_libraries(openfusion PRIVATE ${SQLite3_LIBRARIES})
target_link_libraries(openfusion PRIVATE lua_static ${SQLite3_LIBRARIES})
# Makes it so config, tdata, etc. get picked up when starting via the debugger in VS
set_property(TARGET openfusion PROPERTY VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}")

View File

@@ -1,5 +1,4 @@
# build
FROM debian:stable-slim as build
FROM debian:latest
WORKDIR /usr/src/app
@@ -9,24 +8,14 @@ clang \
make \
libsqlite3-dev
COPY src ./src
COPY vendor ./vendor
COPY .git ./.git
COPY Makefile CMakeLists.txt version.h.in ./
COPY . ./
RUN make -j8
# prod
FROM debian:stable-slim
# tabledata should be copied from the host;
# clone it there before building the container
#RUN git submodule update --init --recursive
WORKDIR /usr/src/app
CMD ["./bin/fusion"]
RUN apt-get -y update && apt-get install -y \
libsqlite3-dev
COPY --from=build /usr/src/app/bin/fusion /bin/fusion
COPY sql ./sql
CMD ["/bin/fusion"]
LABEL Name=openfusion Version=0.0.2
LABEL Name=openfusion Version=0.0.1

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2020-2024 OpenFusion Contributors
Copyright (c) 2020-2023 OpenFusion Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -95,6 +95,8 @@ CXXHDR=\
vendor/bcrypt/BCrypt.hpp\
vendor/INIReader.hpp\
vendor/JSON.hpp\
vendor/INIReader.hpp\
vendor/JSON.hpp\
src/Buffs.hpp\
src/Chat.hpp\
src/CustomCommands.hpp\

View File

@@ -66,9 +66,6 @@ motd=Welcome to OpenFusion!
# location of the database
#dbpath=database.db
# should there be a score cap for infected zone races?
#izracescorecapped=true
# should tutorial flags be disabled off the bat?
disablefirstuseflag=true

View File

@@ -6,10 +6,6 @@ services:
build:
context: .
dockerfile: ./Dockerfile
volumes:
- ./config.ini:/usr/src/app/config.ini
- ./database.db:/usr/src/app/database.db
- ./tdata:/usr/src/app/tdata
ports:
- "23000:23000"
- "23001:23001"

View File

@@ -30,7 +30,7 @@ static bool playerHasBuddyWithID(Player* plr, int buddyID) {
#pragma endregion
// Refresh buddy list
void Buddies::sendBuddyList(CNSocket* sock) {
void Buddies::refreshBuddyList(CNSocket* sock) {
Player* plr = PlayerManager::getPlayer(sock);
int buddyCnt = Database::getNumBuddies(plr);
@@ -277,6 +277,15 @@ static void reqFindNameBuddyAccept(CNSocket* sock, CNPacketData* data) {
// Getting buddy state
static void reqPktGetBuddyState(CNSocket* sock, CNPacketData* data) {
Player* plr = PlayerManager::getPlayer(sock);
/*
* If the buddy list wasn't synced a second time yet, sync it.
* Not sure why we have to do it again for the client not to trip up.
*/
if (!plr->buddiesSynced) {
refreshBuddyList(sock);
plr->buddiesSynced = true;
}
INITSTRUCT(sP_FE2CL_REP_GET_BUDDY_STATE_SUCC, resp);

View File

@@ -6,5 +6,5 @@ namespace Buddies {
void init();
// Buddy list
void sendBuddyList(CNSocket* sock);
void refreshBuddyList(CNSocket* sock);
}

View File

@@ -83,77 +83,7 @@ static void helpCommand(std::string full, std::vector<std::string>& args, CNSock
}
static void accessCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
if (args.size() < 2) {
Chat::sendServerMessage(sock, "Usage: /access <id> [new_level]");
Chat::sendServerMessage(sock, "Use . for id to select yourself");
return;
}
char *tmp;
Player* self = PlayerManager::getPlayer(sock);
int selfAccess = self->accountLevel;
Player* player;
if (args[1].compare(".") == 0) {
player = self;
} else {
int id = std::strtol(args[1].c_str(), &tmp, 10);
if (*tmp) {
Chat::sendServerMessage(sock, "Invalid player ID " + args[1]);
return;
}
player = PlayerManager::getPlayerFromID(id);
if (player == nullptr) {
Chat::sendServerMessage(sock, "Could not find player with ID " + std::to_string(id));
return;
}
// Messing with other players requires a baseline access of 30
if (player != self && selfAccess > 30) {
Chat::sendServerMessage(sock, "Can't check or change other players access levels (insufficient privileges)");
return;
}
}
std::string playerName = PlayerManager::getPlayerName(player);
int currentAccess = player->accountLevel;
if (args.size() < 3) {
// just check
Chat::sendServerMessage(sock, playerName + " has access level " + std::to_string(currentAccess));
return;
}
// Can't change the access level of someone with stronger privileges
// N.B. lower value = stronger privileges
if (currentAccess <= selfAccess) {
Chat::sendServerMessage(sock, "Can't change this player's access level (insufficient privileges)");
return;
}
int newAccess = std::strtol(args[2].c_str(), &tmp, 10);
if (*tmp) {
Chat::sendServerMessage(sock, "Invalid access level " + args[2]);
return;
}
// Can only assign an access level weaker than yours
if (newAccess <= selfAccess) {
Chat::sendServerMessage(sock, "Can only assign privileges weaker than your own");
return;
}
player->accountLevel = newAccess;
// Save to database
int accountId = Database::getAccountIdForPlayer(player->iID);
Database::updateAccountLevel(accountId, newAccess);
std::string msg = "Changed access level for " + playerName + " from " + std::to_string(currentAccess) + " to " + std::to_string(newAccess);
if (newAccess <= 50 && currentAccess > 50)
msg += " (they must log out and back in for some commands to be enabled)";
Chat::sendServerMessage(sock, msg);
Chat::sendServerMessage(sock, "Your access level is " + std::to_string(PlayerManager::getPlayer(sock)->accountLevel));
}
static void populationCommand(std::string full, std::vector<std::string>& args, CNSocket* sock) {
@@ -1270,7 +1200,7 @@ static void registerCommand(std::string cmd, int requiredLevel, CommandHandler h
void CustomCommands::init() {
registerCommand("help", 100, helpCommand, "list all unlocked server-side commands");
registerCommand("access", 100, accessCommand, "check or change access levels");
registerCommand("access", 100, accessCommand, "print your access level");
registerCommand("instance", 30, instanceCommand, "print or change your current instance");
registerCommand("mss", 30, mssCommand, "edit Monkey Skyway routes");
registerCommand("npcr", 30, npcRotateCommand, "rotate NPCs");

View File

@@ -325,13 +325,6 @@ static void emailSend(CNSocket* sock, CNPacketData* data) {
std::string logEmail = "[Email] " + PlayerManager::getPlayerName(plr, true) + " (to " + PlayerManager::getPlayerName(&otherPlr, true) + "): <" + email.SubjectLine + ">\n" + email.MsgBody;
std::cout << logEmail << std::endl;
dump.push_back(logEmail);
// notification to recipient if online
CNSocket* recipient = PlayerManager::getSockFromID(pkt->iTo_PCUID);
if (recipient != nullptr)
{
emailUpdateCheck(recipient, nullptr);
}
}
void Email::init() {

View File

@@ -16,9 +16,8 @@ EntityRef::EntityRef(CNSocket *s) {
EntityRef::EntityRef(int32_t i) {
id = i;
kind = EntityKind::INVALID;
if (NPCManager::NPCs.find(id) != NPCManager::NPCs.end())
kind = NPCManager::NPCs[id]->kind;
assert(NPCManager::NPCs.find(id) != NPCManager::NPCs.end());
kind = NPCManager::NPCs[id]->kind;
}
bool EntityRef::isValid() const {

View File

@@ -64,9 +64,6 @@ static void attachGroupData(std::vector<EntityRef>& pcs, std::vector<EntityRef>&
}
void Groups::addToGroup(Group* group, EntityRef member) {
if (group == nullptr)
return;
if (member.kind == EntityKind::PLAYER) {
Player* plr = PlayerManager::getPlayer(member.sock);
plr->group = group;
@@ -112,9 +109,6 @@ void Groups::addToGroup(Group* group, EntityRef member) {
}
bool Groups::removeFromGroup(Group* group, EntityRef member) {
if (group == nullptr)
return false;
if (member.kind == EntityKind::PLAYER) {
Player* plr = PlayerManager::getPlayer(member.sock);
plr->group = nullptr; // no dangling pointers here muahaahahah
@@ -174,9 +168,6 @@ bool Groups::removeFromGroup(Group* group, EntityRef member) {
}
void Groups::disbandGroup(Group* group) {
if (group == nullptr)
return;
// remove everyone from the group!!
bool done = false;
while(!done) {
@@ -261,9 +252,6 @@ static void leaveGroup(CNSocket* sock, CNPacketData* data) {
}
void Groups::sendToGroup(Group* group, void* buf, uint32_t type, size_t size) {
if (group == nullptr)
return;
auto players = group->filter(EntityKind::PLAYER);
for (EntityRef ref : players) {
ref.sock->sendPacket(buf, type, size);
@@ -271,9 +259,6 @@ void Groups::sendToGroup(Group* group, void* buf, uint32_t type, size_t size) {
}
void Groups::sendToGroup(Group* group, EntityRef excluded, void* buf, uint32_t type, size_t size) {
if (group == nullptr)
return;
auto players = group->filter(EntityKind::PLAYER);
for (EntityRef ref : players) {
if(ref != excluded) ref.sock->sendPacket(buf, type, size);
@@ -309,9 +294,6 @@ void Groups::groupTickInfo(CNSocket* sock) {
void Groups::groupKick(Group* group, EntityRef ref) {
if (group == nullptr)
return;
// if you are the group leader, destroy your own group and kick everybody
if (group->members[0] == ref) {
disbandGroup(group);

View File

@@ -416,9 +416,6 @@ static void itemDeleteHandler(CNSocket* sock, CNPacketData* data) {
Player* plr = PlayerManager::getPlayer(sock);
if (itemdel->iSlotNum < 0 || itemdel->iSlotNum >= AINVEN_COUNT)
return; // sanity check
resp.eIL = itemdel->eIL;
resp.iSlotNum = itemdel->iSlotNum;

View File

@@ -386,9 +386,6 @@ static void taskStart(CNSocket* sock, CNPacketData* data) {
static void taskEnd(CNSocket* sock, CNPacketData* data) {
sP_CL2FE_REQ_PC_TASK_END* missionData = (sP_CL2FE_REQ_PC_TASK_END*)data->buf;
if (Missions::Tasks.find(missionData->iTaskNum) == Missions::Tasks.end())
return;
TaskData* task = Missions::Tasks[missionData->iTaskNum];
// handle timed mission failure

View File

@@ -110,7 +110,7 @@ void Nanos::summonNano(CNSocket *sock, int slot, bool silent) {
}
static void setNanoSkill(CNSocket* sock, sP_CL2FE_REQ_NANO_TUNE* skill) {
if (skill == nullptr || skill->iNanoID >= NANO_COUNT || skill->iNanoID < 0)
if (skill->iNanoID >= NANO_COUNT)
return;
Player *plr = PlayerManager::getPlayer(sock);

View File

@@ -72,8 +72,8 @@ struct Player : public Entity, public ICombatant {
bool notify = false;
bool hidden = false;
bool unwarpable = false;
bool initialLoadDone = false;
bool buddiesSynced = false;
int64_t buddyIDs[50] = {};
bool isBuddyBlocked[50] = {};

View File

@@ -155,21 +155,16 @@ void PlayerManager::sendPlayerTo(CNSocket* sock, int X, int Y, int Z) {
* Nanos the player hasn't unlocked will (and should) be greyed out. Thus, all nanos should be accounted
* for in these packets, even if the player hasn't unlocked them.
*/
static void sendNanoBook(CNSocket *sock, Player *plr, bool resizeOnly) {
static void sendNanoBookSubset(CNSocket *sock) {
#ifdef ACADEMY
Player *plr = getPlayer(sock);
int16_t id = 0;
INITSTRUCT(sP_FE2CL_REP_NANO_BOOK_SUBSET, pkt);
pkt.PCUID = plr->iID;
pkt.bookSize = NANO_COUNT;
if (resizeOnly) {
// triggers nano array resizing without
// actually sending nanos
sock->sendPacket(pkt, P_FE2CL_REP_NANO_BOOK_SUBSET);
return;
}
while (id < NANO_COUNT) {
pkt.elementOffset = id;
@@ -217,7 +212,6 @@ static void enterPlayer(CNSocket* sock, CNPacketData* data) {
response.iID = plr->iID;
response.uiSvrTime = getTime();
response.PCLoadData2CL.iUserLevel = plr->accountLevel;
response.PCLoadData2CL.iHP = plr->HP;
response.PCLoadData2CL.iLevel = plr->level;
@@ -300,21 +294,27 @@ static void enterPlayer(CNSocket* sock, CNPacketData* data) {
sock->setFEKey(lm->FEKey);
sock->setActiveKey(SOCKETKEY_FE); // send all packets using the FE key from now on
// Academy builds receive nanos in a separate packet. An initial one with the size of the
// nano book needs to be sent before PC_ENTER_SUCC so the client can resize its nano arrays,
// and then proper packets with the nanos included must be sent after, while the game is loading.
sendNanoBook(sock, plr, true);
sock->sendPacket(response, P_FE2CL_REP_PC_ENTER_SUCC);
sendNanoBook(sock, plr, false);
// transmit MOTD after entering the game, so the client hopefully changes modes on time
Chat::sendServerMessage(sock, settings::MOTDSTRING);
// transfer ownership of Player object into the shard (still valid in this function though)
addPlayer(sock, plr);
// check if there is an expiring vehicle
Items::checkItemExpire(sock, plr);
// set player equip stats
Items::setItemStats(plr);
Missions::failInstancedMissions(sock);
sendNanoBookSubset(sock);
// initial buddy sync
Buddies::refreshBuddyList(sock);
for (auto& pair : players)
if (pair.second->notify)
Chat::sendServerMessage(pair.first, "[ADMIN]" + getPlayerName(plr) + " has joined.");
@@ -377,17 +377,6 @@ static void loadPlayer(CNSocket* sock, CNPacketData* data) {
sock->sendPacket(pkt, P_FE2CL_INSTANCE_MAP_INFO);
}
if (!plr->initialLoadDone) {
// these should be called only once, but not until after
// first load-in or else the client may ignore the packets
Chat::sendServerMessage(sock, settings::MOTDSTRING); // MOTD
Missions::failInstancedMissions(sock); // auto-fail missions
Buddies::sendBuddyList(sock); // buddy list
Items::checkItemExpire(sock, plr); // vehicle expiration
plr->initialLoadDone = true;
}
}
static void heartbeatPlayer(CNSocket* sock, CNPacketData* data) {

View File

@@ -106,11 +106,10 @@ static void racingEnd(CNSocket* sock, CNPacketData* data) {
int timeDiff = now - epRace.startTime;
int podsCollected = epRace.collectedRings.size();
int score = std::exp(
int score = std::min(epInfo.maxScore, (int)std::exp(
(epInfo.podFactor * podsCollected) / epInfo.maxPods
- (epInfo.timeFactor * timeDiff) / epInfo.maxTime
+ epInfo.scaleFactor);
score = (settings::IZRACESCORECAPPED && score > epInfo.maxScore) ? epInfo.maxScore : score;
+ epInfo.scaleFactor));
int fm = (1.0 + std::exp(epInfo.scaleFactor - 1.0) * epInfo.podFactor * podsCollected) / epInfo.maxPods;
// we submit the ranking first...
@@ -133,9 +132,8 @@ static void racingEnd(CNSocket* sock, CNPacketData* data) {
std::vector<int>* rankRewards = &EPRewards[epInfo.EPID].second;
// top ranking
int maxRank = rankScores->size() - 1;
int topRank = 0;
while (topRank < maxRank && rankScores->at(topRank) > topRankingPlayer.Score)
while (rankScores->at(topRank) > topRankingPlayer.Score)
topRank++;
resp.iEPTopRank = topRank + 1;
@@ -145,7 +143,7 @@ static void racingEnd(CNSocket* sock, CNPacketData* data) {
// this ranking
int rank = 0;
while (rank < maxRank && rankScores->at(rank) > postRanking.Score)
while (rankScores->at(rank) > postRanking.Score)
rank++;
resp.iEPRank = rank + 1;

View File

@@ -610,7 +610,7 @@ static void loadDrops(json& dropData) {
if (rankScores.size() != 5 || rankScores.size() != rankRewards.size()) {
char buff[255];
snprintf(buff, 255, "Race in EP %d doesn't have exactly 5 score/reward pairs", raceEPID);
sprintf(buff, "Race in EP %d doesn't have exactly 5 score/reward pairs", raceEPID);
throw TableException(std::string(buff));
}

View File

@@ -186,36 +186,6 @@ static void tradeOfferRefusal(CNSocket* sock, CNPacketData* data) {
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_OFFER_REFUSAL, sizeof(sP_FE2CL_REP_PC_TRADE_OFFER_REFUSAL));
}
static void tradeOfferCancel(CNSocket* sock, CNPacketData* data) {
sP_CL2FE_REQ_PC_TRADE_OFFER_CANCEL* pacdat = (sP_CL2FE_REQ_PC_TRADE_OFFER_CANCEL*)data->buf;
CNSocket* otherSock = PlayerManager::getSockFromID(pacdat->iID_From);
if (otherSock == nullptr)
return;
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_OFFER_CANCEL, resp);
resp.iID_Request = pacdat->iID_Request;
resp.iID_From = pacdat->iID_From;
resp.iID_To = pacdat->iID_To;
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_OFFER_CANCEL, sizeof(sP_FE2CL_REP_PC_TRADE_OFFER_CANCEL));
}
static void tradeOfferAbort(CNSocket* sock, CNPacketData* data) {
sP_CL2FE_REQ_PC_TRADE_OFFER_ABORT* pacdat = (sP_CL2FE_REQ_PC_TRADE_OFFER_ABORT*)data->buf;
CNSocket* otherSock = PlayerManager::getSockFromID(pacdat->iID_From);
if (otherSock == nullptr)
return;
INITSTRUCT(sP_FE2CL_REP_PC_TRADE_OFFER_ABORT, resp);
resp.iID_Request = pacdat->iID_Request;
resp.iID_From = pacdat->iID_From;
resp.iID_To = pacdat->iID_To;
otherSock->sendPacket((void*)&resp, P_FE2CL_REP_PC_TRADE_OFFER_ABORT, sizeof(sP_FE2CL_REP_PC_TRADE_OFFER_ABORT));
}
static void tradeConfirm(CNSocket* sock, CNPacketData* data) {
sP_CL2FE_REQ_PC_TRADE_CONFIRM* pacdat = (sP_CL2FE_REQ_PC_TRADE_CONFIRM*)data->buf;
@@ -460,8 +430,6 @@ void Trading::init() {
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_OFFER, tradeOffer);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_OFFER_ACCEPT, tradeOfferAccept);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_OFFER_REFUSAL, tradeOfferRefusal);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_OFFER_CANCEL, tradeOfferCancel);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_OFFER_ABORT, tradeOfferAbort);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_CONFIRM, tradeConfirm);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_CONFIRM_CANCEL, tradeConfirmCancel);
REGISTER_SHARD_PACKET(P_CL2FE_REQ_PC_TRADE_ITEM_REGISTER, tradeRegisterItem);

View File

@@ -50,15 +50,13 @@ time_t getTime();
time_t getTimestamp();
void terminate(int);
// The PROTOCOL_VERSION definition can be defined by the build system.
// The PROTOCOL_VERSION definition is defined by the build system.
#if !defined(PROTOCOL_VERSION)
#define PROTOCOL_VERSION 104
#endif
#if PROTOCOL_VERSION == 104
#include "structs/0104.hpp"
#elif PROTOCOL_VERSION == 728
#include "structs/0728.hpp"
#elif PROTOCOL_VERSION == 104
#include "structs/0104.hpp"
#elif PROTOCOL_VERSION == 1013
#include "structs/1013.hpp"
#else

View File

@@ -46,13 +46,9 @@ namespace Database {
void close();
void findAccount(Account* account, std::string login);
// return ID, 0 if something failed
int getAccountIdForPlayer(int playerId);
// returns ID, 0 if something failed
int addAccount(std::string login, std::string password);
void updateAccountLevel(int accountId, int accountLevel);
// interface for the /ban command
bool banPlayer(int playerId, std::string& reason);
bool unbanPlayer(int playerId);

View File

@@ -226,11 +226,10 @@ static void createTables() {
static int getTableSize(std::string tableName) {
std::lock_guard<std::mutex> lock(dbCrit); // XXX
// you aren't allowed to bind the table name
const char* sql = "SELECT COUNT(*) FROM ";
tableName.insert(0, sql);
const char* sql = "SELECT COUNT(*) FROM ?";
sqlite3_stmt* stmt;
sqlite3_prepare_v2(db, tableName.c_str(), -1, &stmt, NULL);
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
sqlite3_bind_text(stmt, 1, tableName.c_str(), -1, NULL);
sqlite3_step(stmt);
int result = sqlite3_column_int(stmt, 0);
sqlite3_finalize(stmt);
@@ -267,17 +266,17 @@ void Database::open() {
checkMetaTable();
createTables();
std::cout << "[INFO] Database in operation";
std::cout << "[INFO] Database in operation ";
int accounts = getTableSize("Accounts");
int players = getTableSize("Players");
std::string message = "";
if (accounts > 0) {
message += ": Found " + std::to_string(accounts) + " account";
message += ": Found " + std::to_string(accounts) + " Account";
if (accounts > 1)
message += "s";
}
if (players > 0) {
message += " and " + std::to_string(players) + " player";
message += " and " + std::to_string(players) + " Player Character";
if (players > 1)
message += "s";
}

View File

@@ -27,32 +27,6 @@ void Database::findAccount(Account* account, std::string login) {
sqlite3_finalize(stmt);
}
int Database::getAccountIdForPlayer(int playerId) {
std::lock_guard<std::mutex> lock(dbCrit);
const char* sql = R"(
SELECT AccountID
FROM Players
WHERE PlayerID = ?
LIMIT 1;
)";
sqlite3_stmt* stmt;
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
sqlite3_bind_int(stmt, 1, playerId);
int rc = sqlite3_step(stmt);
if (rc != SQLITE_ROW) {
std::cout << "[WARN] Database: couldn't get account id for player " << playerId << std::endl;
sqlite3_finalize(stmt);
return 0;
}
int accountId = sqlite3_column_int(stmt, 0);
sqlite3_finalize(stmt);
return accountId;
}
int Database::addAccount(std::string login, std::string password) {
std::lock_guard<std::mutex> lock(dbCrit);
@@ -78,26 +52,6 @@ int Database::addAccount(std::string login, std::string password) {
return sqlite3_last_insert_rowid(db);
}
void Database::updateAccountLevel(int accountId, int accountLevel) {
std::lock_guard<std::mutex> lock(dbCrit);
const char* sql = R"(
UPDATE Accounts SET
AccountLevel = ?
WHERE AccountID = ?;
)";
sqlite3_stmt* stmt;
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
sqlite3_bind_int(stmt, 1, accountLevel);
sqlite3_bind_int(stmt, 2, accountId);
int rc = sqlite3_step(stmt);
if (rc != SQLITE_DONE)
std::cout << "[WARN] Database fail on updateAccountLevel(): " << sqlite3_errmsg(db) << std::endl;
sqlite3_finalize(stmt);
}
void Database::updateSelected(int accountId, int slot) {
std::lock_guard<std::mutex> lock(dbCrit);

View File

@@ -208,8 +208,6 @@ void Database::addBlock(int playerId, int blockedPlayerId) {
}
void Database::removeBlock(int playerId, int blockedPlayerId) {
std::lock_guard<std::mutex> lock(dbCrit);
const char* sql = R"(
DELETE FROM Blocks
WHERE PlayerID = ? AND BlockedPlayerID = ?;

30
src/lua/Manager.cpp Normal file
View File

@@ -0,0 +1,30 @@
#include "lua/Manager.hpp"
#include <iostream>
using namespace LuaManager;
static lua_State *globalState = nullptr;
void LuaManager::init() {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
static LuaThread *startScript(const char *script) {
lua_State *L = lua_newthread(globalState);
LuaThread *T = new LuaThread(L, luaL_ref(L, LUA_REGISTRYINDEX));
if (luaL_dostring(L, script)) {
std::cout << "Lua error: " << lua_tostring(L, -1) << std::endl;
lua_pop(L, 1);
}
return T;
}
void LuaManager::init() {
globalState = luaL_newstate();
luaL_openlibs(globalState);
delete startScript("print(\"Hello from Lua!\")");
}

7
src/lua/Manager.hpp Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
#include "lua/Thread.hpp"
namespace LuaManager {
void init();
}

17
src/lua/Thread.hpp Normal file
View File

@@ -0,0 +1,17 @@
#pragma once
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
struct LuaThread {
lua_State *L;
int ref;
LuaThread(lua_State *L, int ref) : L(L), ref(ref) {}
~LuaThread() {
luaL_unref(L, LUA_REGISTRYINDEX, ref);
}
};

View File

@@ -24,6 +24,8 @@
#include "Eggs.hpp"
#include "Rand.hpp"
#include "lua/Manager.hpp"
#include "settings.hpp"
#include "sandbox/Sandbox.hpp"
@@ -138,6 +140,7 @@ int main() {
Trading::init();
Database::open();
LuaManager::init();
switch (settings::EVENTMODE) {
case 0: break; // no event

View File

@@ -67,9 +67,6 @@ int settings::MONITORINTERVAL = 5000;
// event mode settings
int settings::EVENTMODE = 0;
// race settings
bool settings::IZRACESCORECAPPED = true;
void settings::init() {
INIReader reader("config.ini");
@@ -114,7 +111,6 @@ void settings::init() {
EVENTMODE = reader.GetInteger("shard", "eventmode", EVENTMODE);
DISABLEFIRSTUSEFLAG = reader.GetBoolean("shard", "disablefirstuseflag", DISABLEFIRSTUSEFLAG);
ANTICHEAT = reader.GetBoolean("shard", "anticheat", ANTICHEAT);
IZRACESCORECAPPED = reader.GetBoolean("shard", "izracescorecapped", IZRACESCORECAPPED);
MONITORENABLED = reader.GetBoolean("monitor", "enabled", MONITORENABLED);
MONITORPORT = reader.GetInteger("monitor", "port", MONITORPORT);
MONITORINTERVAL = reader.GetInteger("monitor", "interval", MONITORINTERVAL);

View File

@@ -38,7 +38,6 @@ namespace settings {
extern int MONITORPORT;
extern int MONITORINTERVAL;
extern bool DISABLEFIRSTUSEFLAG;
extern bool IZRACESCORECAPPED;
void init();
}

14842
vendor/JSON.hpp vendored

File diff suppressed because it is too large Load Diff

1
vendor/Lua vendored Submodule

Submodule vendor/Lua added at 88246d621a

View File

@@ -22,13 +22,9 @@
#endif
#include <errno.h>
#if defined(_WIN32) || defined(_WIN64)
#ifdef _WIN32 || _WIN64
// On windows we need to generate random bytes differently.
#if defined(_WIN32) && !defined(_WIN64)
typedef __int32 ssize_t;
#elif defined(_WIN32) && defined(_WIN64)
typedef __int64 ssize_t;
#endif
#define BCRYPT_HASHSIZE 60
#include "bcrypt.h"
@@ -121,7 +117,7 @@ int bcrypt_gensalt(int factor, char salt[BCRYPT_HASHSIZE])
char *aux;
// Note: Windows does not have /dev/urandom sadly.
#if defined(_WIN32) || defined(_WIN64)
#ifdef _WIN32 || _WIN64
HCRYPTPROV p;
ULONG i;

View File

@@ -51,7 +51,7 @@
#endif
/* Just to make sure the prototypes match the actual definitions */
#if defined(_WIN32) || defined(_WIN64)
#ifdef _WIN32 || _WIN64
#include "crypt_blowfish.h"
#else
#include "crypt_blowfish.h"

View File

@@ -41,7 +41,7 @@
#define __SKIP_GNU
#endif
#if defined(_WIN32) || defined(_WIN64)
#ifdef _WIN32 | _WIN64
#include "ow-crypt.h"
#include "crypt_blowfish.h"
@@ -251,7 +251,7 @@ char *__crypt_gensalt_ra(const char *prefix, unsigned long count,
input, size, output, sizeof(output));
if (retval) {
#if defined(_WIN32) || defined(_WIN64)
#ifdef _WIN32 | _WIN64
retval = _strdup(retval);
#else
retval = strdup(retval);