OpenFusion/src/Database.cpp

466 lines
15 KiB
C++
Raw Normal View History

#include "Database.hpp"
#include "contrib/bcrypt/BCrypt.hpp"
#include "CNProtocol.hpp"
#include <string>
#include "contrib/JSON.hpp"
#include "CNStructs.hpp"
#include "settings.hpp"
#include "Player.hpp"
#include "CNStructs.hpp"
#include "contrib/sqlite/sqlite_orm.h"
using namespace sqlite_orm;
# pragma region DatabaseScheme
auto db = make_storage("database.db",
2020-09-02 15:53:39 +00:00
make_table("Accounts",
make_column("AccountID", &Database::Account::AccountID, autoincrement(), primary_key()),
make_column("Login", &Database::Account::Login),
make_column("Password", &Database::Account::Password),
make_column("Selected", &Database::Account::Selected)
),
make_table("Players",
make_column("PlayerID", &Database::DbPlayer::PlayerID, autoincrement(), primary_key()),
make_column("AccountID", &Database::DbPlayer::AccountID),
make_column("Slot", &Database::DbPlayer::slot),
make_column("Firstname", &Database::DbPlayer::FirstName),
make_column("LastName", &Database::DbPlayer::LastName),
make_column("Level", &Database::DbPlayer::Level),
2020-09-07 00:16:44 +00:00
make_column("Nano1", &Database::DbPlayer::Nano1),
make_column("Nano2", &Database::DbPlayer::Nano2),
make_column("Nano3", &Database::DbPlayer::Nano3),
2020-09-02 15:53:39 +00:00
make_column("AppearanceFlag", &Database::DbPlayer::AppearanceFlag),
make_column("TutorialFlag", &Database::DbPlayer::TutorialFlag),
make_column("PayZoneFlag", &Database::DbPlayer::PayZoneFlag),
make_column("XCoordinates", &Database::DbPlayer::x_coordinates),
make_column("YCoordinates", &Database::DbPlayer::y_coordinates),
make_column("ZCoordinates", &Database::DbPlayer::z_coordinates),
make_column("Angle", &Database::DbPlayer::angle),
2020-09-02 15:53:39 +00:00
make_column("Body", &Database::DbPlayer::Body),
make_column("Class", &Database::DbPlayer::Class),
make_column("EyeColor", &Database::DbPlayer::EyeColor),
make_column("FaceStyle", &Database::DbPlayer::FaceStyle),
make_column("Gender", &Database::DbPlayer::Gender),
make_column("HP", &Database::DbPlayer::HP),
make_column("HairColor", &Database::DbPlayer::HairColor),
make_column("HairStyle", &Database::DbPlayer::HairStyle),
make_column("Height", &Database::DbPlayer::Height),
make_column("NameCheck", &Database::DbPlayer::NameCheck),
make_column("SkinColor", &Database::DbPlayer::SkinColor),
make_column("isGM", &Database::DbPlayer::isGM),
make_column("FusionMatter", &Database::DbPlayer::FusionMatter),
make_column("Taros", &Database::DbPlayer::Taros),
make_column("PCState", &Database::DbPlayer::PCState)
2020-09-02 15:53:39 +00:00
),
make_table("Inventory",
2020-09-07 00:16:44 +00:00
make_column("PlayerId", &Database::Inventory::playerId),
make_column("Slot", &Database::Inventory::slot),
make_column("Id", &Database::Inventory::id),
make_column("Type", &Database::Inventory::Type),
make_column("Opt", &Database::Inventory::Opt),
make_column("TimeLimit", &Database::Inventory::TimeLimit)
),
make_table("Nanos",
make_column("PlayerId", &Database::Nano::playerId),
make_column("Id", &Database::Nano::iID),
make_column("Skill", &Database::Nano::iSkillID),
make_column("Stamina", &Database::Nano::iStamina)
2020-09-02 15:53:39 +00:00
)
);
# pragma endregion DatabaseScheme
#pragma region LoginServer
void Database::open()
{
2020-09-02 15:53:39 +00:00
//this parameter means it will try to preserve data during migration
bool preserve = true;
db.sync_schema(preserve);
DEBUGLOG(
std::cout << "[DB] Database in operation" << std::endl;
)
}
int Database::addAccount(std::string login, std::string password)
{
2020-09-02 15:53:39 +00:00
password = BCrypt::generateHash(password);
2020-09-07 17:23:00 +00:00
Account x = {};
2020-09-02 15:53:39 +00:00
x.Login = login;
x.Password = password;
x.Selected = 1;
return db.insert(x);
}
void Database::updateSelected(int accountId, int slot)
{
2020-09-02 15:53:39 +00:00
Account acc = db.get<Account>(accountId);
acc.Selected = slot;
db.update(acc);
}
std::unique_ptr<Database::Account> Database::findAccount(std::string login)
{
2020-09-02 15:53:39 +00:00
//this is awful, I've tried everything to improve it
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::isNameFree(sP_CL2LS_REQ_CHECK_CHAR_NAME* nameCheck)
{
2020-09-02 15:53:39 +00:00
//TODO: add colate nocase
std::string First = U16toU8(nameCheck->szFirstName);
std::string Last = U16toU8(nameCheck->szLastName);
return
(db.get_all<DbPlayer>
(where((c(&DbPlayer::FirstName) == First)
and (c(&DbPlayer::LastName) == Last)))
.empty());
}
int Database::createCharacter(sP_CL2LS_REQ_SAVE_CHAR_NAME* save, int AccountID)
{
2020-09-03 20:29:29 +00:00
DbPlayer create = {};
2020-09-02 15:53:39 +00:00
//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.HP= 1000;
create.HairColor= 1;
create.HairStyle = 1;
create.Height= 0;
create.Level= 1;
create.SkinColor= 1;
create.isGM = false;
//commented and disabled for now
//if (U16toU8(save->szFirstName) == settings::GMPASS) {
// create.isGM = true;
//}
create.FusionMatter= 0;
create.Taros= 0;
create.PCState = 0;
2020-09-02 15:53:39 +00:00
create.x_coordinates = settings::SPAWN_X;
create.y_coordinates= settings::SPAWN_Y;
create.z_coordinates= settings::SPAWN_Z;
create.angle = 0;
2020-09-02 15:53:39 +00:00
return db.insert(create);
}
void Database::finishCharacter(sP_CL2LS_REQ_CHAR_CREATE* character)
{
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);
2020-09-07 00:16:44 +00:00
//clothes
Inventory Foot, LB, UB;
Foot.playerId = character->PCStyle.iPC_UID;
Foot.id = character->sOn_Item.iEquipFootID;
Foot.Type = 3;
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)
{
2020-09-07 00:16:44 +00:00
//set flag
2020-09-02 15:53:39 +00:00
DbPlayer finish = getDbPlayerById(PlayerID);
2020-09-07 00:16:44 +00:00
finish.TutorialFlag = 1;
//add Gun
Inventory LightningGun = {};
LightningGun.playerId = PlayerID;
LightningGun.id = 328;
LightningGun.slot = 0;
LightningGun.Type = 0;
LightningGun.Opt = 1;
db.insert(LightningGun);
//add Nano
Nano Buttercup = {};
Buttercup.playerId = PlayerID;
Buttercup.iID = 1;
Buttercup.iSkillID = 1;
Buttercup.iStamina = 150;
finish.Nano1 = 1;
db.insert(Buttercup);
2020-09-02 15:53:39 +00:00
db.update(finish);
}
int Database::deleteCharacter(int characterID)
{
2020-09-02 15:53:39 +00:00
auto find =
db.get_all<DbPlayer>(where(c(&DbPlayer::PlayerID) == characterID));
int slot = find.front().slot;
db.remove<DbPlayer>(find.front().PlayerID);
return slot;
}
std::vector <Player> Database::getCharacters(int UserID)
{
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
std::vector<Player> result = std::vector<Player>();
for (auto &character : characters) {
Player toadd = DbToPlayer(character);
result.push_back(
toadd
);
}
return result;
}
void Database::evaluateCustomName(int characterID, CUSTOMNAME decision) {
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) {
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)
{
2020-09-03 20:29:29 +00:00
DbPlayer result = {}; // fixes some weird memory errors, this zeros out the members (not the padding inbetween though)
2020-09-02 15:53:39 +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;
2020-09-02 15:53:39 +00:00
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.isGM = player.IsGM;
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;
2020-09-02 15:53:39 +00:00
result.TutorialFlag = player.PCStyle2.iTutorialFlag;
result.x_coordinates = player.x;
result.y_coordinates = player.y;
result.z_coordinates = player.z;
result.angle = player.angle;
2020-09-07 00:16:44 +00:00
result.Nano1 = player.equippedNanos[0];
result.Nano2 = player.equippedNanos[1];
result.Nano3 = player.equippedNanos[2];
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)
2020-09-02 15:53:39 +00:00
result.iID = player.PlayerID;
2020-09-02 15:53:39 +00:00
result.accountId = player.AccountID;
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;
U8toU16(player.FirstName, result.PCStyle.szFirstName);
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.IsGM = player.isGM;
U8toU16(player.LastName, result.PCStyle.szLastName);
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;
2020-09-07 00:16:44 +00:00
result.equippedNanos[0] = player.Nano1;
result.equippedNanos[1] = player.Nano2;
result.equippedNanos[2] = player.Nano3;
Database::getInventory(&result);
Database::getNanos(&result);
2020-09-02 15:53:39 +00:00
return result;
}
Database::DbPlayer Database::getDbPlayerById(int id) {
2020-09-02 15:53:39 +00:00
return db.get_all<DbPlayer>(where(c(&DbPlayer::PlayerID) == id))
.front();
}
2020-09-07 00:16:44 +00:00
Player Database::getPlayer(int id) {
return DbToPlayer(
getDbPlayerById(id)
);
}
#pragma endregion LoginServer
void Database::updatePlayer(Player player) {
DbPlayer toUpdate = playerToDb(player);
db.update(toUpdate);
2020-09-07 00:16:44 +00:00
updateInventory(player);
updateNanos(player);
}
void Database::updateInventory(Player player) {
//start transaction
db.begin_transaction();
//remove all previous items
db.remove_all<Inventory>(
where(c(&Inventory::playerId) == player.iID)
);
//insert equip
for (int i = 0; i < AEQUIP_COUNT; i++) {
if (player.Equip[i].iID != 0) {
sItemBase* next = &player.Equip[i];
Inventory toAdd = {};
toAdd.playerId = player.iID;
toAdd.slot = i;
toAdd.id = next->iID;
toAdd.Opt = next->iOpt;
toAdd.Type = next->iType;
toAdd.TimeLimit = next->iTimeLimit;
db.insert(toAdd);
}
}
//insert inventory
for (int i = 0; i < AINVEN_COUNT; i++) {
if (player.Inven[i].iID != 0) {
sItemBase* next = &player.Inven[i];
Inventory toAdd = {};
toAdd.playerId = player.iID;
toAdd.slot = i + AEQUIP_COUNT;
toAdd.id = next->iID;
toAdd.Opt = next->iOpt;
toAdd.Type = next->iType;
toAdd.TimeLimit = next->iTimeLimit;
db.insert(toAdd);
}
}
db.commit();
}
void Database::updateNanos(Player player) {
//start transaction
db.begin_transaction();
//remove all
db.remove_all<Nano>(
where(c(&Nano::playerId) == player.iID)
);
//insert
int i = 1;
while ((i<SIZEOF_NANO_BANK_SLOT)&&(player.Nanos[i]).iID!=0){
Nano toAdd = {};
sNano* next = &player.Nanos[i];
toAdd.playerId = player.iID;
toAdd.iID = next->iID;
toAdd.iSkillID = next->iSkillID;
toAdd.iStamina = next->iStamina;
db.insert(toAdd);
i++;
}
db.commit();
}
void Database::getInventory(Player* player) {
//get items from DB
auto items = db.get_all<Inventory>(
where(c(&Inventory::playerId) == player->iID)
);
//set items
for (const Inventory &current : items) {
sItemBase toSet = {};
toSet.iID = current.id;
toSet.iType = current.Type;
toSet.iOpt = current.Opt;
toSet.iTimeLimit = current.TimeLimit;
if (current.slot > AEQUIP_COUNT)
player->Inven[current.slot - AEQUIP_COUNT] = toSet;
else
player->Equip[current.slot] = toSet;
}
}
void Database::getNanos(Player* player) {
//get from DB
auto nanos = db.get_all<Nano>(
where(c(&Nano::playerId) == player->iID)
);
//set
for (const Nano& current : nanos) {
sNano *toSet = &player->Nanos[current.iID];
toSet->iID = current.iID;
toSet->iSkillID = current.iSkillID;
toSet->iStamina = current.iStamina;
}
}