OpenFusion/src/Database.cpp

1081 lines
35 KiB
C++
Raw Normal View History

#include "Database.hpp"
#include "Database.hpp"
#include "contrib/bcrypt/BCrypt.hpp"
#include "CNProtocol.hpp"
#include <string>
#include "contrib/JSON.hpp"
2020-11-28 23:19:07 +00:00
#include "contrib/sqlite/sqlite3.h"
#include "CNStructs.hpp"
#include "settings.hpp"
#include "Player.hpp"
#include "CNStructs.hpp"
2020-09-13 18:45:51 +00:00
#include "MissionManager.hpp"
#if defined(__MINGW32__) && !defined(_GLIBCXX_HAS_GTHREADS)
#include "mingw/mingw.mutex.h"
#else
#include <mutex>
#endif
std::mutex dbCrit;
2020-11-28 23:31:00 +00:00
sqlite3* db;
#pragma region LoginServer
void Database::open() {
2020-11-28 23:31:00 +00:00
int rc = sqlite3_open(settings::DBPATH.c_str(), &db);
if (rc != SQLITE_OK) {
std::cout << "[FATAL] Cannot open database: " << sqlite3_errmsg(db) << std::endl;
terminate(0);
}
2020-11-30 12:44:43 +00:00
createTables();
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
std::cout << "[INFO] Database in operation ";
int accounts = getAccountsCount();
int players = getPlayersCount();
std::string message = "";
if (accounts > 0) {
message += ": Found " + std::to_string(accounts) + " Account";
if (accounts > 1)
message += "s";
}
if (players > 0) {
message += " and " + std::to_string(players) + " Player Character";
if (players > 1)
message += "s";
}
std::cout << message << std::endl;
}
2020-11-30 12:44:43 +00:00
void Database::createTables() {
char* errMsg = 0;
char* sql;
sql = R"(
CREATE TABLE IF NOT EXISTS "Accounts" (
"AccountID" INTEGER NOT NULL,
"Login" TEXT NOT NULL UNIQUE,
"Password" TEXT NOT NULL,
"Selected" INTEGER NOT NULL,
"Created" INTEGER NOT NULL,
"LastLogin" INTEGER NOT NULL,
PRIMARY KEY("AccountID" AUTOINCREMENT)
);
CREATE TABLE IF NOT EXISTS "Players" (
"PlayerID" INTEGER NOT NULL,
"AccountID" INTEGER NOT NULL,
"Slot" INTEGER NOT NULL,
"Firstname" TEXT NOT NULL COLLATE NOCASE,
"LastName" TEXT NOT NULL COLLATE NOCASE,
"Created" INTEGER NOT NULL,
"LastLogin" INTEGER NOT NULL,
"Level" INTEGER NOT NULL,
"Nano1" INTEGER NOT NULL,
"Nano2" INTEGER NOT NULL,
"Nano3" INTEGER NOT NULL,
"AppearanceFlag" INTEGER NOT NULL,
"TutorialFlag" INTEGER NOT NULL,
"PayZoneFlag" INTEGER NOT NULL,
"XCoordinates" INTEGER NOT NULL,
"YCoordinates" INTEGER NOT NULL,
"ZCoordinates" INTEGER NOT NULL,
"HP" INTEGER NOT NULL,
"NameCheck" INTEGER NOT NULL,
"AccountLevel" INTEGER NOT NULL,
"FusionMatter" INTEGER NOT NULL,
"Taros" INTEGER NOT NULL,
"Quests" BLOB NOT NULL,
"BatteryW" INTEGER NOT NULL,
"BatteryN" INTEGER NOT NULL,
"Mentor" INTEGER NOT NULL,
"WarpLocationFlag" INTEGER NOT NULL,
"SkywayLocationFlag1" INTEGER NOT NULL,
"SkywayLocationFlag2" INTEGER NOT NULL,
"CurrentMissionID" INTEGER NOT NULL,
PRIMARY KEY("PlayerID" AUTOINCREMENT),
FOREIGN KEY("AccountID") REFERENCES "Accounts"("AccountID") ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS "Appearances" (
"PlayerID" INTEGER NOT NULL,
"Angle" INTEGER NOT NULL,
"Body" INTEGER NOT NULL,
"EyeColor" INTEGER NOT NULL,
"FaceStyle" INTEGER NOT NULL,
"Gender" INTEGER NOT NULL,
"HairColor" INTEGER NOT NULL,
"HairStyle" INTEGER NOT NULL,
"Height" INTEGER NOT NULL,
"SkinColor" INTEGER NOT NULL,
FOREIGN KEY("PlayerID") REFERENCES "Players"("PlayerID") ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS "Inventory" (
"PlayerId" INTEGER NOT NULL,
"Slot" INTEGER NOT NULL,
"Id" INTEGER NOT NULL,
"Type" INTEGER NOT NULL,
"Opt" INTEGER NOT NULL,
"TimeLimit" INTEGER NOT NULL,
FOREIGN KEY("PlayerID") REFERENCES "Players"("PlayerID") ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS "Nanos" (
"PlayerId" INTEGER NOT NULL,
"Id" INTEGER NOT NULL,
"Skill" INTEGER NOT NULL,
"Stamina" INTEGER NOT NULL,
FOREIGN KEY("PlayerID") REFERENCES "Players"("PlayerID") ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS "RunningQuests" (
"PlayerId" INTEGER NOT NULL,
"TaskId" INTEGER NOT NULL,
"RemainingNPCCount1" INTEGER NOT NULL,
"RemainingNPCCount2" INTEGER NOT NULL,
"RemainingNPCCount3" INTEGER NOT NULL,
FOREIGN KEY("PlayerID") REFERENCES "Players"("PlayerID") ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS "Buddyships" (
"PlayerAId" INTEGER NOT NULL,
"PlayerBId" INTEGER NOT NULL,
"Status" INTEGER NOT NULL,
FOREIGN KEY("PlayerAId") REFERENCES "Players"("PlayerID") ON DELETE CASCADE,
FOREIGN KEY("PlayerBId") REFERENCES "Players"("PlayerID") ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS "EmailData" (
"PlayerId" INTEGER NOT NULL,
"MsgIndex" INTEGER NOT NULL,
"ReadFlag" INTEGER NOT NULL,
"ItemFlag" INTEGER NOT NULL,
"SenderId" INTEGER NOT NULL,
"SenderFirstName" TEXT NOT NULL COLLATE NOCASE,
"SenderLastName" TEXT NOT NULL COLLATE NOCASE,
"SubjectLine" TEXT NOT NULL,
"MsgBody" TEXT NOT NULL,
"Taros" INTEGER NOT NULL,
"SendTime" INTEGER NOT NULL,
"DeleteTime" INTEGER NOT NULL,
FOREIGN KEY("PlayerID") REFERENCES "Players"("PlayerID") ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS "EmailItems" (
"PlayerId" INTEGER NOT NULL,
"MsgIndex" INTEGER NOT NULL,
"Slot" INTEGER NOT NULL,
"Id" INTEGER NOT NULL,
"Type" INTEGER NOT NULL,
"Opt" INTEGER NOT NULL,
"TimeLimit" INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS "RaceResults"(
"EPID" INTEGER NOT NULL,
"PlayerID" INTEGER NOT NULL,
"Score" INTEGER NOT NULL,
"Timestamp" INTEGER NOT NULL,
FOREIGN KEY("PlayerID") REFERENCES "Players"("PlayerID") ON DELETE CASCADE
)
)";
int rc = sqlite3_exec(db, sql, 0, 0, &errMsg);
if (rc != SQLITE_OK) {
std::cout << "[FATAL] Database failed to create tables: " << errMsg << std::endl;
terminate(0);
}
}
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
int Database::getAccountsCount() {
2020-11-30 12:44:43 +00:00
int result;
char* sql = "SELECT COUNT(*) FROM Accounts";
rc = sqlite3_exec(db, sql, CBAccountsCount, result, &err_msg);
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
}
2020-11-30 12:44:43 +00:00
static int Database::CBAccountsCount(void* AccountsCount, int count, char** data, char** columns) {
*AccountsCount = (int)data[0];
}
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
int Database::getPlayersCount() {
return db.count<DbPlayer>();
}
int Database::addAccount(std::string login, std::string password) {
std::lock_guard<std::mutex> lock(dbCrit);
2020-09-02 15:53:39 +00:00
password = BCrypt::generateHash(password);
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
Account account = {};
account.Login = login;
account.Password = password;
account.Selected = 1;
account.Created = getTimestamp();
account.LastLogin = account.Created;
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
return db.insert(account);
}
void Database::updateSelected(int accountId, int slot) {
std::lock_guard<std::mutex> lock(dbCrit);
2020-09-02 15:53:39 +00:00
Account acc = db.get<Account>(accountId);
acc.Selected = slot;
// timestamp
acc.LastLogin = getTimestamp();
2020-09-02 15:53:39 +00:00
db.update(acc);
}
std::unique_ptr<Database::Account> Database::findAccount(std::string login) {
std::lock_guard<std::mutex> lock(dbCrit);
// this is awful, I've tried everything to improve it
2020-09-02 15:53:39 +00:00
auto find = db.get_all<Account>(
where(c(&Account::Login) == login), limit(1));
if (find.empty())
return nullptr;
return
std::unique_ptr<Account>(new Account(find.front()));
}
bool Database::validateCharacter(int characterID, int userID) {
return db.select(&DbPlayer::PlayerID,
where((c(&DbPlayer::PlayerID) == characterID) && (c(&DbPlayer::AccountID) == userID)))
.size() > 0;
}
bool Database::isNameFree(std::string firstName, std::string lastName) {
std::lock_guard<std::mutex> lock(dbCrit);
2020-09-02 15:53:39 +00:00
return
(db.get_all<DbPlayer>
(where((c(&DbPlayer::FirstName) == firstName)
and (c(&DbPlayer::LastName) == lastName)))
.empty());
}
bool Database::isSlotFree(int accountId, int slotNum) {
std::lock_guard<std::mutex> lock(dbCrit);
return
(db.get_all<DbPlayer>
(where((c(&DbPlayer::AccountID) == accountId)
and (c(&DbPlayer::slot) == slotNum)))
.empty());
}
int Database::createCharacter(sP_CL2LS_REQ_SAVE_CHAR_NAME* save, int AccountID) {
std::lock_guard<std::mutex> lock(dbCrit);
// fail if the player already has 4 or more characters
if (db.count<DbPlayer>(where(c(&DbPlayer::AccountID) == AccountID)) >= 4)
return -1;
DbPlayer create = {};
// set timestamp
create.Created = getTimestamp();
// save packet data
create.FirstName = U16toU8(save->szFirstName);
create.LastName = U16toU8(save->szLastName);
create.slot = save->iSlotNum;
create.AccountID = AccountID;
// set flags
create.AppearanceFlag = 0;
create.TutorialFlag = 0;
create.PayZoneFlag = 0;
// set namecheck based on setting
if (settings::APPROVEALLNAMES || save->iFNCode)
create.NameCheck = 1;
else
create.NameCheck = 0;
// create default body character
create.Body = 0;
create.Class = 0;
create.EyeColor = 1;
create.FaceStyle = 1;
create.Gender = 1;
create.Level = 1;
create.HP = PC_MAXHEALTH(create.Level);
create.HairColor = 1;
create.HairStyle = 1;
create.Height = 0;
create.SkinColor = 1;
create.AccountLevel = settings::ACCLEVEL;
create.x_coordinates = settings::SPAWN_X;
create.y_coordinates = settings::SPAWN_Y;
create.z_coordinates = settings::SPAWN_Z;
create.angle = settings::SPAWN_ANGLE;
// set mentor to computress
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
create.Mentor = 5;
// initialize the quest blob to 128 0-bytes
create.QuestFlag = std::vector<char>(128, 0);
return db.insert(create);
}
void Database::finishCharacter(sP_CL2LS_REQ_CHAR_CREATE* character) {
std::lock_guard<std::mutex> lock(dbCrit);
2020-09-02 15:53:39 +00:00
DbPlayer finish = getDbPlayerById(character->PCStyle.iPC_UID);
finish.AppearanceFlag = 1;
finish.Body = character->PCStyle.iBody;
finish.Class = character->PCStyle.iClass;
finish.EyeColor = character->PCStyle.iEyeColor;
finish.FaceStyle = character->PCStyle.iFaceStyle;
finish.Gender = character->PCStyle.iGender;
finish.HairColor = character->PCStyle.iHairColor;
finish.HairStyle = character->PCStyle.iHairStyle;
finish.Height = character->PCStyle.iHeight;
finish.Level = 1;
finish.SkinColor = character->PCStyle.iSkinColor;
db.update(finish);
// clothes
2020-09-07 00:16:44 +00:00
Inventory Foot, LB, UB;
Foot.playerId = character->PCStyle.iPC_UID;
Foot.id = character->sOn_Item.iEquipFootID;
Foot.Type = 3;
2020-09-07 00:16:44 +00:00
Foot.slot = 3;
Foot.Opt = 1;
Foot.TimeLimit = 0;
db.insert(Foot);
LB.playerId = character->PCStyle.iPC_UID;
LB.id = character->sOn_Item.iEquipLBID;
LB.Type = 2;
LB.slot = 2;
LB.Opt = 1;
LB.TimeLimit = 0;
db.insert(LB);
UB.playerId = character->PCStyle.iPC_UID;
UB.id = character->sOn_Item.iEquipUBID;
UB.Type = 1;
UB.slot = 1;
UB.Opt = 1;
UB.TimeLimit = 0;
db.insert(UB);
}
void Database::finishTutorial(int PlayerID) {
std::lock_guard<std::mutex> lock(dbCrit);
2020-09-13 18:45:51 +00:00
Player finish = getPlayer(PlayerID);
// set flag
finish.PCStyle2.iTutorialFlag= 1;
// add Gun
2020-09-07 00:16:44 +00:00
Inventory LightningGun = {};
LightningGun.playerId = PlayerID;
LightningGun.id = 328;
LightningGun.slot = 0;
LightningGun.Type = 0;
LightningGun.Opt = 1;
db.insert(LightningGun);
// add Nano
2020-09-07 00:16:44 +00:00
Nano Buttercup = {};
Buttercup.playerId = PlayerID;
Buttercup.iID = 1;
Buttercup.iSkillID = 1;
Buttercup.iStamina = 150;
2020-09-13 18:45:51 +00:00
finish.equippedNanos[0] = 1;
2020-09-07 00:16:44 +00:00
db.insert(Buttercup);
// save missions
2020-09-13 18:45:51 +00:00
MissionManager::saveMission(&finish, 0);
MissionManager::saveMission(&finish, 1);
db.update(playerToDb(&finish));
}
int Database::deleteCharacter(int characterID, int userID) {
std::lock_guard<std::mutex> lock(dbCrit);
2020-09-02 15:53:39 +00:00
auto find =
db.get_all<DbPlayer>(where(c(&DbPlayer::PlayerID) == characterID and c(&DbPlayer::AccountID)==userID));
2020-09-02 15:53:39 +00:00
int slot = find.front().slot;
db.remove<DbPlayer>(find.front().PlayerID);
db.remove_all<Inventory>(where(c(&Inventory::playerId) == characterID));
db.remove_all<Nano>(where(c(&Nano::playerId) == characterID));
2020-09-02 15:53:39 +00:00
return slot;
}
std::vector <Player> Database::getCharacters(int UserID) {
std::lock_guard<std::mutex> lock(dbCrit);
2020-09-02 15:53:39 +00:00
std::vector<DbPlayer>characters =
db.get_all<DbPlayer>(where
(c(&DbPlayer::AccountID) == UserID));
// parsing DbPlayer to Player
2020-09-02 15:53:39 +00:00
std::vector<Player> result = std::vector<Player>();
for (auto &character : characters) {
Player toadd = DbToPlayer(character);
2020-09-02 15:53:39 +00:00
result.push_back(
toadd
);
}
return result;
}
std::vector <sP_LS2CL_REP_CHAR_INFO> Database::getCharInfo(int userID) {
std::lock_guard<std::mutex> lock(dbCrit);
std::vector<DbPlayer>characters =
db.get_all<DbPlayer>(where
(c(&DbPlayer::AccountID) == userID));
std::vector<sP_LS2CL_REP_CHAR_INFO> result = std::vector<sP_LS2CL_REP_CHAR_INFO>();
for (auto& character : characters) {
sP_LS2CL_REP_CHAR_INFO toAdd = {};
toAdd.iX = character.x_coordinates;
toAdd.iY = character.y_coordinates;
toAdd.iZ = character.z_coordinates;
toAdd.iLevel = character.Level;
toAdd.iSlot = character.slot;
toAdd.sPC_Style.iBody = character.Body;
toAdd.sPC_Style.iClass = character.Class;
toAdd.sPC_Style.iEyeColor = character.EyeColor;
toAdd.sPC_Style.iFaceStyle = character.FaceStyle;
toAdd.sPC_Style.iGender = character.Gender;
toAdd.sPC_Style.iHairColor = character.HairColor;
toAdd.sPC_Style.iHairStyle = character.HairStyle;
toAdd.sPC_Style.iHeight = character.Height;
toAdd.sPC_Style.iNameCheck = character.NameCheck;
toAdd.sPC_Style.iPC_UID = character.PlayerID;
toAdd.sPC_Style.iSkinColor = character.SkinColor;
U8toU16(character.FirstName, toAdd.sPC_Style.szFirstName, sizeof(toAdd.sPC_Style.szFirstName));
U8toU16(character.LastName, toAdd.sPC_Style.szLastName, sizeof(toAdd.sPC_Style.szLastName));
toAdd.sPC_Style2.iAppearanceFlag = character.AppearanceFlag;
toAdd.sPC_Style2.iPayzoneFlag = character.PayZoneFlag;
toAdd.sPC_Style2.iTutorialFlag = character.TutorialFlag;
//get equipment
auto items = db.get_all<Inventory>(
where(c(&Inventory::playerId) == character.PlayerID && c(&Inventory::slot) < AEQUIP_COUNT));
for (auto& item : items) {
sItemBase addItem = {};
addItem.iID = item.id;
addItem.iType = item.Type;
addItem.iOpt = item.Opt;
addItem.iTimeLimit = item.TimeLimit;
toAdd.aEquip[item.slot] = addItem;
}
result.push_back(toAdd);
}
return result;
}
// XXX: This is never called?
void Database::evaluateCustomName(int characterID, CustomName decision) {
std::lock_guard<std::mutex> lock(dbCrit);
2020-09-02 15:53:39 +00:00
DbPlayer player = getDbPlayerById(characterID);
player.NameCheck = (int)decision;
db.update(player);
}
void Database::changeName(sP_CL2LS_REQ_CHANGE_CHAR_NAME* save) {
std::lock_guard<std::mutex> lock(dbCrit);
2020-09-02 15:53:39 +00:00
DbPlayer Player = getDbPlayerById(save->iPCUID);
Player.FirstName = U16toU8(save->szFirstName);
Player.LastName = U16toU8(save->szLastName);
if (settings::APPROVEALLNAMES || save->iFNCode)
Player.NameCheck = 1;
else
Player.NameCheck = 0;
db.update(Player);
}
Database::DbPlayer Database::playerToDb(Player *player) {
// TODO: move stuff that is never updated to separate table so it doesn't try to update it every time
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
DbPlayer result = {};
2020-09-03 20:29:29 +00:00
result.PlayerID = player->iID;
result.AccountID = player->accountId;
result.AppearanceFlag = player->PCStyle2.iAppearanceFlag;
result.Body = player->PCStyle.iBody;
result.Class = player->PCStyle.iClass;
result.EyeColor = player->PCStyle.iEyeColor;
result.FaceStyle = player->PCStyle.iFaceStyle;
result.FirstName = U16toU8( player->PCStyle.szFirstName);
result.FusionMatter = player->fusionmatter;
result.Gender = player->PCStyle.iGender;
result.HairColor = player->PCStyle.iHairColor;
result.HairStyle = player->PCStyle.iHairStyle;
result.Height = player->PCStyle.iHeight;
result.HP = player->HP;
result.AccountLevel = player->accountLevel;
result.LastName = U16toU8(player->PCStyle.szLastName);
result.Level = player->level;
result.NameCheck = player->PCStyle.iNameCheck;
result.PayZoneFlag = player->PCStyle2.iPayzoneFlag;
result.PlayerID = player->PCStyle.iPC_UID;
result.SkinColor = player->PCStyle.iSkinColor;
result.slot = player->slot;
result.Taros = player->money;
result.TutorialFlag = player->PCStyle2.iTutorialFlag;
2020-11-26 15:01:48 +00:00
if (player->instanceID == 0 && !player->onMonkey) { // only save coords if player isn't instanced
result.x_coordinates = player->x;
result.y_coordinates = player->y;
result.z_coordinates = player->z;
result.angle = player->angle;
} else {
result.x_coordinates = player->lastX;
result.y_coordinates = player->lastY;
result.z_coordinates = player->lastZ;
result.angle = player->lastAngle;
}
result.Nano1 = player->equippedNanos[0];
result.Nano2 = player->equippedNanos[1];
result.Nano3 = player->equippedNanos[2];
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
result.BatteryN = player->batteryN;
result.BatteryW = player->batteryW;
result.Mentor = player->mentor;
result.WarpLocationFlag = player->iWarpLocationFlag;
result.SkywayLocationFlag1 = player->aSkywayLocationFlag[0];
result.SkywayLocationFlag2 = player->aSkywayLocationFlag[1];
result.CurrentMissionID = player->CurrentMissionID;
// timestamp
result.LastLogin = getTimestamp();
result.Created = player->creationTime;
2020-09-13 18:45:51 +00:00
// save completed quests
result.QuestFlag = std::vector<char>((char*)player->aQuestFlag, (char*)player->aQuestFlag + 128);
2020-09-02 15:53:39 +00:00
return result;
}
Player Database::DbToPlayer(DbPlayer player) {
2020-09-03 20:29:29 +00:00
Player result = {}; // fixes some weird memory errors, this zeros out the members (not the padding inbetween though)
result.iID = player.PlayerID;
2020-09-02 15:53:39 +00:00
result.accountId = player.AccountID;
result.creationTime = player.Created;
2020-09-02 15:53:39 +00:00
result.PCStyle2.iAppearanceFlag = player.AppearanceFlag;
result.PCStyle.iBody = player.Body;
result.PCStyle.iClass = player.Class;
result.PCStyle.iEyeColor = player.EyeColor;
result.PCStyle.iFaceStyle = player.FaceStyle;
2020-10-04 17:50:58 +00:00
U8toU16(player.FirstName, result.PCStyle.szFirstName, sizeof(result.PCStyle.szFirstName));
2020-09-02 15:53:39 +00:00
result.PCStyle.iGender = player.Gender;
result.PCStyle.iHairColor = player.HairColor;
result.PCStyle.iHairStyle = player.HairStyle;
result.PCStyle.iHeight = player.Height;
result.HP = player.HP;
result.accountLevel = player.AccountLevel;
2020-10-04 17:50:58 +00:00
U8toU16(player.LastName, result.PCStyle.szLastName, sizeof(result.PCStyle.szLastName));
2020-09-02 15:53:39 +00:00
result.level = player.Level;
result.PCStyle.iNameCheck = player.NameCheck;
result.PCStyle2.iPayzoneFlag = player.PayZoneFlag;
result.iID = player.PlayerID;
result.PCStyle.iPC_UID = player.PlayerID;
result.PCStyle.iSkinColor = player.SkinColor;
result.slot = player.slot;
result.PCStyle2.iTutorialFlag = player.TutorialFlag;
result.x = player.x_coordinates;
result.y = player.y_coordinates;
result.z = player.z_coordinates;
result.angle = player.angle;
result.money = player.Taros;
result.fusionmatter = player.FusionMatter;
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
result.batteryN = player.BatteryN;
result.batteryW = player.BatteryW;
result.mentor = player.Mentor;
result.CurrentMissionID = player.CurrentMissionID;
2020-09-07 00:16:44 +00:00
result.equippedNanos[0] = player.Nano1;
result.equippedNanos[1] = player.Nano2;
result.equippedNanos[2] = player.Nano3;
result.inCombat = false;
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
result.iWarpLocationFlag = player.WarpLocationFlag;
result.aSkywayLocationFlag[0] = player.SkywayLocationFlag1;
result.aSkywayLocationFlag[1] = player.SkywayLocationFlag2;
2020-09-07 00:16:44 +00:00
Database::getInventory(&result);
Database::removeExpiredVehicles(&result);
2020-09-07 00:16:44 +00:00
Database::getNanos(&result);
Database::getQuests(&result);
2020-11-08 17:42:27 +00:00
Database::getBuddies(&result);
2020-09-13 18:45:51 +00:00
// load completed quests
memcpy(&result.aQuestFlag, player.QuestFlag.data(), std::min(sizeof(result.aQuestFlag), player.QuestFlag.size()));
2020-09-13 18:45:51 +00:00
2020-09-02 15:53:39 +00:00
return result;
}
Database::DbPlayer Database::getDbPlayerById(int id) {
auto player = db.get_all<DbPlayer>(where(c(&DbPlayer::PlayerID) == id));
if (player.size() < 1) {
// garbage collection
db.remove_all<Inventory>(where(c(&Inventory::playerId) == id));
db.remove_all<Nano>(where(c(&Nano::playerId) == id));
db.remove_all<DbQuest>(where(c(&DbQuest::PlayerId) == id));
db.remove_all<Buddyship>(where(c(&Buddyship::PlayerAId) == id || c(&Buddyship::PlayerBId) == id));
db.remove_all<EmailData>(where(c(&EmailData::PlayerId) == id));
db.remove_all<EmailItem>(where(c(&EmailItem::PlayerId) == id));
return DbPlayer{ -1 };
}
return player.front();
}
2020-09-07 00:16:44 +00:00
Player Database::getPlayer(int id) {
return DbToPlayer(
getDbPlayerById(id)
);
}
#pragma endregion LoginServer
#pragma region ShardServer
void Database::updatePlayer(Player *player) {
std::lock_guard<std::mutex> lock(dbCrit);
DbPlayer toUpdate = playerToDb(player);
db.update(toUpdate);
2020-09-07 00:16:44 +00:00
updateInventory(player);
updateNanos(player);
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
updateQuests(player);
//updateBuddies(player); we add/remove buddies explicitly now
2020-09-07 00:16:44 +00:00
}
void Database::updateInventory(Player *player){
// start transaction
2020-09-07 00:16:44 +00:00
db.begin_transaction();
// remove all
2020-09-07 00:16:44 +00:00
db.remove_all<Inventory>(
where(c(&Inventory::playerId) == player->iID)
2020-09-07 00:16:44 +00:00
);
// insert equip
2020-09-07 00:16:44 +00:00
for (int i = 0; i < AEQUIP_COUNT; i++) {
if (player->Equip[i].iID != 0) {
sItemBase* next = &player->Equip[i];
2020-09-07 00:16:44 +00:00
Inventory toAdd = {};
toAdd.playerId = player->iID;
2020-09-07 00:16:44 +00:00
toAdd.slot = i;
toAdd.id = next->iID;
toAdd.Opt = next->iOpt;
toAdd.Type = next->iType;
toAdd.TimeLimit = next->iTimeLimit;
db.insert(toAdd);
}
}
// insert inventory
2020-09-07 00:16:44 +00:00
for (int i = 0; i < AINVEN_COUNT; i++) {
if (player->Inven[i].iID != 0) {
sItemBase* next = &player->Inven[i];
2020-09-07 00:16:44 +00:00
Inventory toAdd = {};
toAdd.playerId = player->iID;
2020-09-07 00:16:44 +00:00
toAdd.slot = i + AEQUIP_COUNT;
toAdd.id = next->iID;
toAdd.Opt = next->iOpt;
toAdd.Type = next->iType;
toAdd.TimeLimit = next->iTimeLimit;
db.insert(toAdd);
}
}
// insert bank
for (int i = 0; i < ABANK_COUNT; i++) {
if (player->Bank[i].iID != 0) {
sItemBase* next = &player->Bank[i];
Inventory toAdd = {};
toAdd.playerId = player->iID;
toAdd.slot = i + AEQUIP_COUNT + AINVEN_COUNT;
toAdd.id = next->iID;
toAdd.Opt = next->iOpt;
toAdd.Type = next->iType;
toAdd.TimeLimit = next->iTimeLimit;
db.insert(toAdd);
}
}
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
// insert quest items
for (int i = 0; i < AQINVEN_COUNT; i++) {
if (player->QInven[i].iID != 0) {
sItemBase* next = &player->QInven[i];
Inventory toAdd = {};
toAdd.playerId = player->iID;
toAdd.slot = i + AEQUIP_COUNT + AINVEN_COUNT + ABANK_COUNT;
toAdd.id = next->iID;
toAdd.Opt = next->iOpt;
toAdd.Type = next->iType;
toAdd.TimeLimit = next->iTimeLimit;
db.insert(toAdd);
}
}
2020-09-07 00:16:44 +00:00
db.commit();
}
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
void Database::updateNanos(Player *player) {
// start transaction
2020-09-07 00:16:44 +00:00
db.begin_transaction();
// remove all
2020-09-07 00:16:44 +00:00
db.remove_all<Nano>(
where(c(&Nano::playerId) == player->iID)
2020-09-07 00:16:44 +00:00
);
// insert
for (int i=1; i < SIZEOF_NANO_BANK_SLOT; i++) {
if ((player->Nanos[i]).iID == 0)
continue;
2020-09-07 00:16:44 +00:00
Nano toAdd = {};
sNano* next = &player->Nanos[i];
toAdd.playerId = player->iID;
2020-09-07 00:16:44 +00:00
toAdd.iID = next->iID;
toAdd.iSkillID = next->iSkillID;
toAdd.iStamina = next->iStamina;
db.insert(toAdd);
}
db.commit();
}
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
void Database::updateQuests(Player* player) {
// start transaction
db.begin_transaction();
// remove all
db.remove_all<DbQuest>(
where(c(&DbQuest::PlayerId) == player->iID)
);
// insert
for (int i = 0; i < ACTIVE_MISSION_COUNT; i++) {
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
if (player->tasks[i] == 0)
continue;
DbQuest toAdd = {};
toAdd.PlayerId = player->iID;
toAdd.TaskId = player->tasks[i];
toAdd.RemainingNPCCount1 = player->RemainingNPCCount[i][0];
toAdd.RemainingNPCCount2 = player->RemainingNPCCount[i][1];
toAdd.RemainingNPCCount3 = player->RemainingNPCCount[i][2];
db.insert(toAdd);
}
db.commit();
}
// note: do not use. explicitly add/remove records instead.
2020-11-08 17:42:27 +00:00
void Database::updateBuddies(Player* player) {
db.begin_transaction();
db.remove_all<Buddyship>( // remove all buddyships with this player involved
where(c(&Buddyship::PlayerAId) == player->iID || c(&Buddyship::PlayerBId) == player->iID)
);
// iterate through player's buddies and add records for each non-zero entry
for (int i = 0; i < 50; i++) {
if (player->buddyIDs[i] != 0) {
Buddyship record;
record.PlayerAId = player->iID;
record.PlayerBId = player->buddyIDs[i];
record.Status = 0; // still not sure how we'll handle blocking
db.insert(record);
}
}
db.commit();
}
2020-09-07 00:16:44 +00:00
void Database::getInventory(Player* player) {
// get items from DB
2020-09-07 00:16:44 +00:00
auto items = db.get_all<Inventory>(
where(c(&Inventory::playerId) == player->iID)
);
// set items
2020-09-07 00:16:44 +00:00
for (const Inventory &current : items) {
sItemBase toSet = {};
toSet.iID = current.id;
toSet.iType = current.Type;
toSet.iOpt = current.Opt;
toSet.iTimeLimit = current.TimeLimit;
// assign to proper arrays
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
if (current.slot < AEQUIP_COUNT)
player->Equip[current.slot] = toSet;
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
else if (current.slot < (AEQUIP_COUNT + AINVEN_COUNT))
2020-09-07 00:16:44 +00:00
player->Inven[current.slot - AEQUIP_COUNT] = toSet;
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
else if (current.slot < (AEQUIP_COUNT + AINVEN_COUNT + ABANK_COUNT))
player->Bank[current.slot - AEQUIP_COUNT - AINVEN_COUNT] = toSet;
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
else
player->QInven[current.slot - AEQUIP_COUNT - AINVEN_COUNT - ABANK_COUNT] = toSet;
2020-09-07 00:16:44 +00:00
}
}
void Database::removeExpiredVehicles(Player* player) {
int32_t currentTime = getTimestamp();
// remove from bank immediately
for (int i = 0; i < ABANK_COUNT; i++) {
if (player->Bank[i].iType == 10 && player->Bank[i].iTimeLimit < currentTime)
player->Bank[i] = {};
}
// for the rest, we want to leave only 1 expired vehicle on player to delete it with the client packet
std::vector<sItemBase*> toRemove;
// equiped vehicle
if (player->Equip[8].iOpt > 0 && player->Equip[8].iTimeLimit < currentTime) {
toRemove.push_back(&player->Equip[8]);
player->toRemoveVehicle.eIL = 0;
player->toRemoveVehicle.iSlotNum = 8;
}
// inventory
for (int i = 0; i < AINVEN_COUNT; i++) {
if (player->Inven[i].iType == 10 && player->Inven[i].iTimeLimit < currentTime) {
toRemove.push_back(&player->Inven[i]);
player->toRemoveVehicle.eIL = 1;
player->toRemoveVehicle.iSlotNum = i;
}
}
// delete all but one vehicles, leave last one for ceremonial deletion
2020-09-22 11:41:28 +00:00
for (int i = 0; i < (int)toRemove.size()-1; i++) {
memset(toRemove[i], 0, sizeof(sItemBase));
}
2020-09-07 00:16:44 +00:00
}
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
2020-09-07 00:16:44 +00:00
void Database::getNanos(Player* player) {
// get from DB
2020-09-07 00:16:44 +00:00
auto nanos = db.get_all<Nano>(
where(c(&Nano::playerId) == player->iID)
);
// set
2020-09-07 00:16:44 +00:00
for (const Nano& current : nanos) {
sNano *toSet = &player->Nanos[current.iID];
toSet->iID = current.iID;
toSet->iSkillID = current.iSkillID;
toSet->iStamina = current.iStamina;
}
}
Database saving update (#104) * implemented saving BatteryN and BatteryW * implemented saving mentor * moved int64->blob parsing to a separate function * moved parsing blob->int64 to a separate function * added functions for parsing int32->blob and vice versa * added functions for parsing int16->blob and vice versa * WIP saving quest items and active tasks * Quest items are stored in inventory table instead of blob * added sanity check for missionId * saving active missions works * removed unneccesary include * implemented saving warplocationflag, skywaylocationflag and currentmissionid in database * INFO DB message now shows how many accounts and player characters are in the database * fixed dbsaveinterval being in [login] instead of [shard] * fixed mission quit: - fixed wrong json name, causing qitems not deleting properly - quitting mission now resets npc kill count * adjusted saving active missions * removed blob parsing functions that ended up being unused * removed accidentaly added include * removed sending PCStyle2 on Player Enter * added a sanity check in itemMoveHandler * removed MapNum from PCLoad, as client doesn't even read it * set BuddyWarpCooldown to 60s on PCLoad * fixed a bug causing EXIT DUPLICATE not working * added creation and last login timestamps to accounts and players * added a sanity check for P_CL2LS_REQ_PC_EXIT_DUPLICATE * implemented web api support, toggled by new setting (off by default) * add usewebapi to config Co-authored-by: Gent <gentsemaj@live.com>
2020-09-21 19:43:53 +00:00
void Database::getQuests(Player* player) {
// get from DB
auto quests = db.get_all<DbQuest>(
where(c(&DbQuest::PlayerId) == player->iID)
);
// set
int i = 0;
for (const DbQuest& current : quests) {
player->tasks[i] = current.TaskId;
player->RemainingNPCCount[i][0] = current.RemainingNPCCount1;
player->RemainingNPCCount[i][1] = current.RemainingNPCCount2;
player->RemainingNPCCount[i][2] = current.RemainingNPCCount3;
i++;
}
}
2020-11-08 17:42:27 +00:00
void Database::getBuddies(Player* player) {
auto buddies = db.get_all<Buddyship>( // player can be on either side
where(c(&Buddyship::PlayerAId) == player->iID || c(&Buddyship::PlayerBId) == player->iID)
);
// there should never be more than 50 buddyships per player, but just in case
for (int i = 0; i < 50 && i < buddies.size(); i++) {
// if the player is player A, then the buddy is player B, and vice versa
player->buddyIDs[i] = player->iID == buddies.at(i).PlayerAId
? buddies.at(i).PlayerBId : buddies.at(i).PlayerAId;
}
}
int Database::getNumBuddies(Player* player) {
std::lock_guard<std::mutex> lock(dbCrit);
auto buddies = db.get_all<Buddyship>( // player can be on either side
where(c(&Buddyship::PlayerAId) == player->iID || c(&Buddyship::PlayerBId) == player->iID)
);
// again, for peace of mind
return buddies.size() > 50 ? 50 : buddies.size();
}
// buddies
void Database::addBuddyship(int playerA, int playerB) {
std::lock_guard<std::mutex> lock(dbCrit);
db.begin_transaction();
Buddyship record;
record.PlayerAId = playerA;
record.PlayerBId = playerB;
record.Status = 0; // blocking ???
db.insert(record);
db.commit();
}
void Database::removeBuddyship(int playerA, int playerB) {
std::lock_guard<std::mutex> lock(dbCrit);
db.begin_transaction();
db.remove_all<Buddyship>(
where(c(&Buddyship::PlayerAId) == playerA && c(&Buddyship::PlayerBId) == playerB)
);
db.remove_all<Buddyship>( // the pair could be in either position
where(c(&Buddyship::PlayerAId) == playerB && c(&Buddyship::PlayerBId) == playerA)
);
db.commit();
}
// email
int Database::getUnreadEmailCount(int playerID) {
std::lock_guard<std::mutex> lock(dbCrit);
auto emailData = db.get_all<Database::EmailData>(
where(c(&Database::EmailData::PlayerId) == playerID && c(&Database::EmailData::ReadFlag) == 0)
);
return emailData.size();
}
std::vector<Database::EmailData> Database::getEmails(int playerID, int page) {
std::lock_guard<std::mutex> lock(dbCrit);
std::vector<Database::EmailData> emails;
auto emailData = db.get_all<Database::EmailData>(
where(c(&Database::EmailData::PlayerId) == playerID),
order_by(&Database::EmailData::MsgIndex).desc(),
limit(5 * (page - 1), 5)
);
int i = 0;
for (Database::EmailData email : emailData) {
emails.push_back(email);
i++;
}
return emails;
}
Database::EmailData Database::getEmail(int playerID, int index) {
std::lock_guard<std::mutex> lock(dbCrit);
auto emailData = db.get_all<Database::EmailData>(
where(c(&Database::EmailData::PlayerId) == playerID && c(&Database::EmailData::MsgIndex) == index)
);
if (emailData.size() > 1)
std::cout << "[WARN] Duplicate emails detected (player " << playerID << ", index " << index << ")" << std::endl;
return emailData.at(0);
}
sItemBase* Database::getEmailAttachments(int playerID, int index) {
std::lock_guard<std::mutex> lock(dbCrit);
sItemBase* items = new sItemBase[4];
for (int i = 0; i < 4; i++)
items[i] = { 0, 0, 0, 0 }; // zero out items
auto attachments = db.get_all<Database::EmailItem>(
where(c(&Database::EmailItem::PlayerId) == playerID && c(&Database::EmailItem::MsgIndex) == index)
);
if (attachments.size() > 4)
std::cout << "[WARN] Email has too many attachments (player " << playerID << ", index " << index << ")" << std::endl;
for (Database::EmailItem& item : attachments) {
items[item.Slot - 1] = { item.Type, item.Id, item.Opt, item.TimeLimit };
}
return items;
}
void Database::updateEmailContent(EmailData* data) {
std::lock_guard<std::mutex> lock(dbCrit);
db.begin_transaction();
auto attachments = db.get_all<Database::EmailItem>(
where(c(&Database::EmailItem::PlayerId) == data->PlayerId && c(&Database::EmailItem::MsgIndex) == data->MsgIndex)
);
data->ItemFlag = (data->Taros > 0 || attachments.size() > 0) ? 1 : 0; // set attachment flag dynamically
db.remove_all<Database::EmailData>(
where(c(&Database::EmailData::PlayerId) == data->PlayerId && c(&Database::EmailData::MsgIndex) == data->MsgIndex)
);
db.insert(*data);
db.commit();
}
void Database::deleteEmailAttachments(int playerID, int index, int slot) {
std::lock_guard<std::mutex> lock(dbCrit);
db.begin_transaction();
if (slot == -1) { // delete all
db.remove_all<Database::EmailItem>(
where(c(&Database::EmailItem::PlayerId) == playerID && c(&Database::EmailItem::MsgIndex) == index)
);
} else { // delete single by comparing slot num
db.remove_all<Database::EmailItem>(
where(c(&Database::EmailItem::PlayerId) == playerID && c(&Database::EmailItem::MsgIndex) == index
&& c(&Database::EmailItem::Slot) == slot)
);
}
db.commit();
}
void Database::deleteEmails(int playerID, int64_t* indices) {
std::lock_guard<std::mutex> lock(dbCrit);
db.begin_transaction();
for (int i = 0; i < 5; i++) {
db.remove_all<Database::EmailData>(
where(c(&Database::EmailData::PlayerId) == playerID && c(&Database::EmailData::MsgIndex) == indices[i])
); // no need to check if the index is 0, since an email will never have index < 1
}
db.commit();
}
int Database::getNextEmailIndex(int playerID) {
std::lock_guard<std::mutex> lock(dbCrit);
auto emailData = db.get_all<Database::EmailData>(
where(c(&Database::EmailData::PlayerId) == playerID),
order_by(&Database::EmailData::MsgIndex).desc(),
limit(1)
);
return (emailData.size() > 0 ? emailData.at(0).MsgIndex + 1 : 1);
}
void Database::sendEmail(EmailData* data, std::vector<sItemBase> attachments) {
std::lock_guard<std::mutex> lock(dbCrit);
db.begin_transaction();
db.insert(*data); // add email data to db
// add email attachments to db email inventory
int slot = 1;
for (sItemBase item : attachments) {
EmailItem dbItem = {
data->PlayerId,
data->MsgIndex,
slot++,
item.iType,
item.iID,
item.iOpt,
item.iTimeLimit
};
db.insert(dbItem);
}
db.commit();
}
#pragma endregion ShardServer