2020-08-28 18:02:03 +00:00
|
|
|
#include "Database.hpp"
|
2020-09-03 02:25:09 +00:00
|
|
|
#include "contrib/bcrypt/BCrypt.hpp"
|
2020-09-01 22:37:09 +00:00
|
|
|
#include "CNProtocol.hpp"
|
|
|
|
#include <string>
|
|
|
|
#include "contrib/JSON.hpp"
|
2020-08-28 18:02:03 +00:00
|
|
|
#include "CNStructs.hpp"
|
|
|
|
#include "settings.hpp"
|
|
|
|
#include "Player.hpp"
|
2020-09-01 22:37:09 +00:00
|
|
|
#include "CNStructs.hpp"
|
|
|
|
#include "contrib/sqlite/sqlite_orm.h"
|
2020-09-13 18:45:51 +00:00
|
|
|
#include "MissionManager.hpp"
|
2020-09-01 22:37:09 +00:00
|
|
|
|
|
|
|
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),
|
2020-09-21 19:43:53 +00:00
|
|
|
make_column("Selected", &Database::Account::Selected),
|
|
|
|
make_column("Created", &Database::Account::Created),
|
|
|
|
make_column("LastLogin", &Database::Account::LastLogin)
|
2020-09-02 15:53:39 +00:00
|
|
|
),
|
|
|
|
make_table("Players",
|
|
|
|
make_column("PlayerID", &Database::DbPlayer::PlayerID, autoincrement(), primary_key()),
|
|
|
|
make_column("AccountID", &Database::DbPlayer::AccountID),
|
|
|
|
make_column("Slot", &Database::DbPlayer::slot),
|
2020-09-09 12:36:35 +00:00
|
|
|
make_column("Firstname", &Database::DbPlayer::FirstName, collate_nocase()),
|
|
|
|
make_column("LastName", &Database::DbPlayer::LastName, collate_nocase()),
|
2020-09-21 19:43:53 +00:00
|
|
|
make_column("Created", &Database::DbPlayer::Created),
|
|
|
|
make_column("LastLogin", &Database::DbPlayer::LastLogin),
|
2020-09-02 15:53:39 +00:00
|
|
|
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),
|
2020-09-02 22:22:00 +00:00
|
|
|
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),
|
2020-09-08 20:41:02 +00:00
|
|
|
make_column("Height", &Database::DbPlayer::Height),
|
|
|
|
make_column("NameCheck", &Database::DbPlayer::NameCheck),
|
|
|
|
make_column("SkinColor", &Database::DbPlayer::SkinColor),
|
2020-09-22 02:26:12 +00:00
|
|
|
make_column("AccountLevel", &Database::DbPlayer::AccountLevel),
|
2020-09-02 15:53:39 +00:00
|
|
|
make_column("FusionMatter", &Database::DbPlayer::FusionMatter),
|
2020-09-02 22:22:00 +00:00
|
|
|
make_column("Taros", &Database::DbPlayer::Taros),
|
2020-09-21 19:43:53 +00:00
|
|
|
make_column("Quests", &Database::DbPlayer::QuestFlag),
|
|
|
|
make_column("BatteryW", &Database::DbPlayer::BatteryW),
|
|
|
|
make_column("BatteryN", &Database::DbPlayer::BatteryN),
|
|
|
|
make_column("Mentor", &Database::DbPlayer::Mentor),
|
|
|
|
make_column("WarpLocationFlag", &Database::DbPlayer::WarpLocationFlag),
|
|
|
|
make_column("SkywayLocationFlag1", &Database::DbPlayer::SkywayLocationFlag1),
|
|
|
|
make_column("SkywayLocationFlag2", &Database::DbPlayer::SkywayLocationFlag2),
|
|
|
|
make_column("CurrentMissionID", &Database::DbPlayer::CurrentMissionID)
|
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-21 19:43:53 +00:00
|
|
|
),
|
|
|
|
make_table("RunningQuests",
|
|
|
|
make_column("PlayerId", &Database::DbQuest::PlayerId),
|
|
|
|
make_column("TaskId", &Database::DbQuest::TaskId),
|
|
|
|
make_column("RemainingNPCCount1", &Database::DbQuest::RemainingNPCCount1),
|
|
|
|
make_column("RemainingNPCCount2", &Database::DbQuest::RemainingNPCCount2),
|
|
|
|
make_column("RemainingNPCCount3", &Database::DbQuest::RemainingNPCCount3)
|
2020-09-02 15:53:39 +00:00
|
|
|
)
|
2020-09-01 22:37:09 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
# pragma endregion DatabaseScheme
|
|
|
|
|
|
|
|
#pragma region LoginServer
|
|
|
|
|
2020-09-14 13:53:48 +00:00
|
|
|
void Database::open()
|
2020-09-01 22:37:09 +00:00
|
|
|
{
|
2020-09-14 14:03:30 +00:00
|
|
|
// this parameter means it will try to preserve data during migration
|
2020-09-02 15:53:39 +00:00
|
|
|
bool preserve = true;
|
|
|
|
db.sync_schema(preserve);
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Database::getAccountsCount() {
|
|
|
|
return db.count<Account>();
|
|
|
|
}
|
|
|
|
|
|
|
|
int Database::getPlayersCount() {
|
|
|
|
return db.count<DbPlayer>();
|
2020-08-28 18:02:03 +00:00
|
|
|
}
|
|
|
|
|
2020-09-14 13:53:48 +00:00
|
|
|
int Database::addAccount(std::string login, std::string password)
|
2020-09-01 22:37:09 +00:00
|
|
|
{
|
2020-09-02 15:53:39 +00:00
|
|
|
password = BCrypt::generateHash(password);
|
2020-09-21 19:43:53 +00:00
|
|
|
Account account = {};
|
|
|
|
account.Login = login;
|
|
|
|
account.Password = password;
|
|
|
|
account.Selected = 1;
|
|
|
|
account.Created = getTime();
|
|
|
|
return db.insert(account);
|
2020-08-28 18:02:03 +00:00
|
|
|
}
|
|
|
|
|
2020-09-01 22:37:09 +00:00
|
|
|
void Database::updateSelected(int accountId, int slot)
|
|
|
|
{
|
2020-09-02 15:53:39 +00:00
|
|
|
Account acc = db.get<Account>(accountId);
|
|
|
|
acc.Selected = slot;
|
2020-09-21 19:43:53 +00:00
|
|
|
//timestamp
|
|
|
|
acc.LastLogin = getTime();
|
2020-09-02 15:53:39 +00:00
|
|
|
db.update(acc);
|
2020-08-28 18:02:03 +00:00
|
|
|
}
|
|
|
|
|
2020-09-14 13:53:48 +00:00
|
|
|
std::unique_ptr<Database::Account> Database::findAccount(std::string login)
|
2020-09-01 22:37:09 +00:00
|
|
|
{
|
2020-09-14 14:03:30 +00:00
|
|
|
// 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
|
2020-09-14 13:53:48 +00:00
|
|
|
std::unique_ptr<Account>(new Account(find.front()));
|
2020-08-28 18:02:03 +00:00
|
|
|
}
|
|
|
|
|
2020-09-01 22:37:09 +00:00
|
|
|
bool Database::isNameFree(sP_CL2LS_REQ_CHECK_CHAR_NAME* nameCheck)
|
|
|
|
{
|
2020-09-02 15:53:39 +00:00
|
|
|
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)))
|
2020-09-08 20:41:02 +00:00
|
|
|
.empty());
|
2020-08-28 18:02:03 +00:00
|
|
|
}
|
|
|
|
|
2020-09-14 13:53:48 +00:00
|
|
|
int Database::createCharacter(sP_CL2LS_REQ_SAVE_CHAR_NAME* save, int AccountID)
|
2020-09-01 22:37:09 +00:00
|
|
|
{
|
2020-09-14 13:20:55 +00:00
|
|
|
// fail if the player already has 4 or more characters
|
|
|
|
if (db.count<DbPlayer>(where(c(&DbPlayer::AccountID) == AccountID)) >= 4)
|
2020-09-13 20:29:30 +00:00
|
|
|
return -1;
|
2020-09-14 13:20:55 +00:00
|
|
|
|
|
|
|
DbPlayer create = {};
|
2020-09-21 19:43:53 +00:00
|
|
|
|
|
|
|
//set timestamp
|
|
|
|
create.Created = getTime();
|
2020-09-14 14:03:30 +00:00
|
|
|
// save packet data
|
2020-09-14 13:20:55 +00:00
|
|
|
create.FirstName = U16toU8(save->szFirstName);
|
|
|
|
create.LastName = U16toU8(save->szLastName);
|
|
|
|
create.slot = save->iSlotNum;
|
|
|
|
create.AccountID = AccountID;
|
|
|
|
|
2020-09-14 14:03:30 +00:00
|
|
|
// set flags
|
2020-09-14 13:20:55 +00:00
|
|
|
create.AppearanceFlag = 0;
|
|
|
|
create.TutorialFlag = 0;
|
|
|
|
create.PayZoneFlag = 0;
|
|
|
|
|
2020-09-14 14:03:30 +00:00
|
|
|
// set namecheck based on setting
|
2020-09-14 13:20:55 +00:00
|
|
|
if (settings::APPROVEALLNAMES || save->iFNCode)
|
|
|
|
create.NameCheck = 1;
|
|
|
|
else
|
|
|
|
create.NameCheck = 0;
|
|
|
|
|
2020-09-14 14:03:30 +00:00
|
|
|
// create default body character
|
2020-09-14 13:20:55 +00:00
|
|
|
create.Body = 0;
|
|
|
|
create.Class = 0;
|
|
|
|
create.EyeColor = 1;
|
|
|
|
create.FaceStyle = 1;
|
|
|
|
create.Gender = 1;
|
2020-09-21 16:03:25 +00:00
|
|
|
create.Level = 1;
|
|
|
|
create.HP = PC_MAXHEALTH(create.Level);
|
2020-09-14 13:20:55 +00:00
|
|
|
create.HairColor = 1;
|
|
|
|
create.HairStyle = 1;
|
|
|
|
create.Height = 0;
|
|
|
|
create.SkinColor = 1;
|
2020-09-22 02:26:12 +00:00
|
|
|
create.AccountLevel = settings::ACCLEVEL;
|
2020-09-14 13:20:55 +00:00
|
|
|
create.x_coordinates = settings::SPAWN_X;
|
|
|
|
create.y_coordinates = settings::SPAWN_Y;
|
|
|
|
create.z_coordinates = settings::SPAWN_Z;
|
|
|
|
create.angle = settings::SPAWN_ANGLE;
|
|
|
|
create.QuestFlag = std::vector<char>();
|
2020-09-21 19:43:53 +00:00
|
|
|
//set mentor to computress
|
|
|
|
create.Mentor = 5;
|
2020-09-14 13:20:55 +00:00
|
|
|
|
|
|
|
return db.insert(create);
|
2020-08-28 18:02:03 +00:00
|
|
|
}
|
|
|
|
|
2020-09-14 13:53:48 +00:00
|
|
|
void Database::finishCharacter(sP_CL2LS_REQ_CHAR_CREATE* character)
|
2020-09-01 22:37:09 +00:00
|
|
|
{
|
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-14 14:03:30 +00:00
|
|
|
// 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;
|
2020-09-14 13:53:48 +00:00
|
|
|
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);
|
2020-08-28 18:02:03 +00:00
|
|
|
}
|
|
|
|
|
2020-09-14 13:53:48 +00:00
|
|
|
void Database::finishTutorial(int PlayerID)
|
2020-09-01 22:37:09 +00:00
|
|
|
{
|
2020-09-13 18:45:51 +00:00
|
|
|
Player finish = getPlayer(PlayerID);
|
2020-09-14 14:03:30 +00:00
|
|
|
// set flag
|
2020-09-14 13:53:48 +00:00
|
|
|
finish.PCStyle2.iTutorialFlag= 1;
|
2020-09-14 14:03:30 +00:00
|
|
|
// 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);
|
2020-09-14 14:03:30 +00:00
|
|
|
// 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);
|
2020-09-14 14:03:30 +00:00
|
|
|
// save missions
|
2020-09-13 18:45:51 +00:00
|
|
|
MissionManager::saveMission(&finish, 0);
|
|
|
|
MissionManager::saveMission(&finish, 1);
|
|
|
|
|
2020-09-14 13:20:55 +00:00
|
|
|
db.update(playerToDb(&finish));
|
2020-08-28 18:02:03 +00:00
|
|
|
}
|
|
|
|
|
2020-09-14 13:53:48 +00:00
|
|
|
int Database::deleteCharacter(int characterID, int userID)
|
2020-09-01 22:37:09 +00:00
|
|
|
{
|
2020-09-02 15:53:39 +00:00
|
|
|
auto find =
|
2020-09-13 20:29:30 +00:00
|
|
|
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);
|
2020-09-08 20:41:02 +00:00
|
|
|
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;
|
2020-08-28 18:02:03 +00:00
|
|
|
}
|
|
|
|
|
2020-09-14 13:53:48 +00:00
|
|
|
std::vector <Player> Database::getCharacters(int UserID)
|
2020-09-01 22:37:09 +00:00
|
|
|
{
|
2020-09-02 15:53:39 +00:00
|
|
|
std::vector<DbPlayer>characters =
|
|
|
|
db.get_all<DbPlayer>(where
|
|
|
|
(c(&DbPlayer::AccountID) == UserID));
|
2020-09-14 14:03:30 +00:00
|
|
|
// parsing DbPlayer to Player
|
2020-09-02 15:53:39 +00:00
|
|
|
std::vector<Player> result = std::vector<Player>();
|
|
|
|
for (auto &character : characters) {
|
2020-09-14 13:53:48 +00:00
|
|
|
Player toadd = DbToPlayer(character);
|
2020-09-02 15:53:39 +00:00
|
|
|
result.push_back(
|
|
|
|
toadd
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return result;
|
2020-08-28 18:02:03 +00:00
|
|
|
}
|
|
|
|
|
2020-09-14 13:20:55 +00:00
|
|
|
// XXX: This is never called?
|
|
|
|
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);
|
2020-08-28 18:02:03 +00:00
|
|
|
}
|
|
|
|
|
2020-09-01 22:37:09 +00:00
|
|
|
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);
|
2020-08-28 18:02:03 +00:00
|
|
|
}
|
|
|
|
|
2020-09-14 13:20:55 +00:00
|
|
|
Database::DbPlayer Database::playerToDb(Player *player)
|
2020-09-01 22:37:09 +00:00
|
|
|
{
|
2020-09-21 19:43:53 +00:00
|
|
|
//TODO: move stuff that is never updated to separate table so it doesn't try to update it every time
|
|
|
|
DbPlayer result = {};
|
2020-09-03 20:29:29 +00:00
|
|
|
|
2020-09-14 13:20:55 +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;
|
2020-09-22 02:26:12 +00:00
|
|
|
result.AccountLevel = player->accountLevel;
|
2020-09-14 13:20:55 +00:00
|
|
|
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;
|
|
|
|
result.x_coordinates = player->x;
|
|
|
|
result.y_coordinates = player->y;
|
|
|
|
result.z_coordinates = player->z;
|
|
|
|
result.angle = player->angle;
|
|
|
|
result.Nano1 = player->equippedNanos[0];
|
|
|
|
result.Nano2 = player->equippedNanos[1];
|
|
|
|
result.Nano3 = player->equippedNanos[2];
|
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;
|
|
|
|
|
|
|
|
// finished quests: parsing to blob
|
2020-09-13 18:45:51 +00:00
|
|
|
result.QuestFlag = std::vector<char>();
|
|
|
|
for (int i=0; i<16; i++)
|
|
|
|
{
|
2020-09-21 19:43:53 +00:00
|
|
|
int64_t flag = player->aQuestFlag[i];
|
|
|
|
appendBlob(&result.QuestFlag, flag);
|
2020-09-13 18:45:51 +00:00
|
|
|
}
|
2020-09-21 19:43:53 +00:00
|
|
|
//timestamp
|
|
|
|
result.LastLogin = getTime();
|
|
|
|
result.Created = getDbPlayerById(player->iID).Created;
|
2020-09-13 18:45:51 +00:00
|
|
|
|
2020-09-02 15:53:39 +00:00
|
|
|
return result;
|
2020-08-28 18:02:03 +00:00
|
|
|
}
|
|
|
|
|
2020-09-01 22:37:09 +00:00
|
|
|
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-14 13:53:48 +00:00
|
|
|
|
2020-09-02 22:22:00 +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;
|
2020-09-22 02:26:12 +00:00
|
|
|
result.accountLevel = player.AccountLevel;
|
2020-09-02 15:53:39 +00:00
|
|
|
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;
|
2020-09-02 22:22:00 +00:00
|
|
|
result.angle = player.angle;
|
|
|
|
result.money = player.Taros;
|
|
|
|
result.fusionmatter = player.FusionMatter;
|
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-01 22:37:09 +00:00
|
|
|
|
2020-09-07 00:16:44 +00:00
|
|
|
result.equippedNanos[0] = player.Nano1;
|
|
|
|
result.equippedNanos[1] = player.Nano2;
|
|
|
|
result.equippedNanos[2] = player.Nano3;
|
2020-09-14 13:53:48 +00:00
|
|
|
|
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);
|
2020-09-22 11:16:09 +00:00
|
|
|
Database::removeExpiredVehicles(&result);
|
2020-09-07 00:16:44 +00:00
|
|
|
Database::getNanos(&result);
|
2020-09-22 11:16:09 +00:00
|
|
|
Database::getQuests(&result);
|
2020-09-13 18:45:51 +00:00
|
|
|
|
|
|
|
std::vector<char>::iterator it = player.QuestFlag.begin();
|
|
|
|
for (int i = 0; i < 16; i++)
|
|
|
|
{
|
|
|
|
if (it == player.QuestFlag.end())
|
|
|
|
break;
|
2020-09-21 19:43:53 +00:00
|
|
|
result.aQuestFlag[i] = blobToInt64(it);
|
|
|
|
//move iterator to the next flag
|
|
|
|
it += 8;
|
2020-09-13 18:45:51 +00:00
|
|
|
}
|
|
|
|
|
2020-09-02 15:53:39 +00:00
|
|
|
return result;
|
2020-08-28 18:02:03 +00:00
|
|
|
}
|
|
|
|
|
2020-09-01 22:37:09 +00:00
|
|
|
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-08-28 18:02:03 +00:00
|
|
|
}
|
|
|
|
|
2020-09-07 00:16:44 +00:00
|
|
|
Player Database::getPlayer(int id) {
|
|
|
|
return DbToPlayer(
|
|
|
|
getDbPlayerById(id)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-09-01 22:37:09 +00:00
|
|
|
#pragma endregion LoginServer
|
2020-09-02 22:22:00 +00:00
|
|
|
|
2020-09-09 12:36:35 +00:00
|
|
|
#pragma region ShardServer
|
|
|
|
|
2020-09-14 13:20:55 +00:00
|
|
|
void Database::updatePlayer(Player *player) {
|
2020-09-02 22:22:00 +00:00
|
|
|
DbPlayer toUpdate = playerToDb(player);
|
|
|
|
db.update(toUpdate);
|
2020-09-07 00:16:44 +00:00
|
|
|
updateInventory(player);
|
|
|
|
updateNanos(player);
|
2020-09-21 19:43:53 +00:00
|
|
|
updateQuests(player);
|
2020-09-07 00:16:44 +00:00
|
|
|
}
|
|
|
|
|
2020-09-14 13:20:55 +00:00
|
|
|
void Database::updateInventory(Player *player){
|
2020-09-14 14:03:30 +00:00
|
|
|
// start transaction
|
2020-09-07 00:16:44 +00:00
|
|
|
db.begin_transaction();
|
2020-09-14 14:03:30 +00:00
|
|
|
// remove all
|
2020-09-07 00:16:44 +00:00
|
|
|
db.remove_all<Inventory>(
|
2020-09-14 13:20:55 +00:00
|
|
|
where(c(&Inventory::playerId) == player->iID)
|
2020-09-07 00:16:44 +00:00
|
|
|
);
|
2020-09-14 14:03:30 +00:00
|
|
|
// insert equip
|
2020-09-07 00:16:44 +00:00
|
|
|
for (int i = 0; i < AEQUIP_COUNT; i++) {
|
2020-09-14 13:20:55 +00:00
|
|
|
if (player->Equip[i].iID != 0) {
|
|
|
|
sItemBase* next = &player->Equip[i];
|
2020-09-07 00:16:44 +00:00
|
|
|
Inventory toAdd = {};
|
2020-09-14 13:20:55 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2020-09-14 14:03:30 +00:00
|
|
|
// insert inventory
|
2020-09-07 00:16:44 +00:00
|
|
|
for (int i = 0; i < AINVEN_COUNT; i++) {
|
2020-09-14 13:20:55 +00:00
|
|
|
if (player->Inven[i].iID != 0) {
|
|
|
|
sItemBase* next = &player->Inven[i];
|
2020-09-07 00:16:44 +00:00
|
|
|
Inventory toAdd = {};
|
2020-09-14 13:20:55 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2020-09-14 14:03:30 +00:00
|
|
|
// insert bank
|
2020-09-09 20:42:55 +00:00
|
|
|
for (int i = 0; i < ABANK_COUNT; i++) {
|
2020-09-14 13:20:55 +00:00
|
|
|
if (player->Bank[i].iID != 0) {
|
|
|
|
sItemBase* next = &player->Bank[i];
|
2020-09-09 20:42:55 +00:00
|
|
|
Inventory toAdd = {};
|
2020-09-14 13:20:55 +00:00
|
|
|
toAdd.playerId = player->iID;
|
2020-09-09 20:42:55 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
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();
|
|
|
|
}
|
2020-09-21 19:43:53 +00:00
|
|
|
|
2020-09-14 13:20:55 +00:00
|
|
|
void Database::updateNanos(Player *player) {
|
2020-09-14 14:03:30 +00:00
|
|
|
// start transaction
|
2020-09-07 00:16:44 +00:00
|
|
|
db.begin_transaction();
|
2020-09-14 14:03:30 +00:00
|
|
|
// remove all
|
2020-09-07 00:16:44 +00:00
|
|
|
db.remove_all<Nano>(
|
2020-09-14 13:20:55 +00:00
|
|
|
where(c(&Nano::playerId) == player->iID)
|
2020-09-07 00:16:44 +00:00
|
|
|
);
|
2020-09-14 14:03:30 +00:00
|
|
|
// insert
|
2020-09-08 20:41:02 +00:00
|
|
|
for (int i=1; i < SIZEOF_NANO_BANK_SLOT; i++)
|
2020-09-14 13:53:48 +00:00
|
|
|
{
|
2020-09-14 13:20:55 +00:00
|
|
|
if ((player->Nanos[i]).iID == 0)
|
2020-09-08 20:41:02 +00:00
|
|
|
continue;
|
2020-09-07 00:16:44 +00:00
|
|
|
Nano toAdd = {};
|
2020-09-14 13:20:55 +00:00
|
|
|
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();
|
|
|
|
}
|
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++)
|
|
|
|
{
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2020-09-07 00:16:44 +00:00
|
|
|
void Database::getInventory(Player* player) {
|
2020-09-14 14:03:30 +00:00
|
|
|
// get items from DB
|
2020-09-07 00:16:44 +00:00
|
|
|
auto items = db.get_all<Inventory>(
|
|
|
|
where(c(&Inventory::playerId) == player->iID)
|
|
|
|
);
|
2020-09-14 14:03:30 +00:00
|
|
|
// set items
|
2020-09-07 00:16:44 +00:00
|
|
|
for (const Inventory ¤t : items) {
|
|
|
|
sItemBase toSet = {};
|
|
|
|
toSet.iID = current.id;
|
|
|
|
toSet.iType = current.Type;
|
|
|
|
toSet.iOpt = current.Opt;
|
|
|
|
toSet.iTimeLimit = current.TimeLimit;
|
2020-09-14 14:03:30 +00:00
|
|
|
// assign to proper arrays
|
2020-09-21 19:43:53 +00:00
|
|
|
if (current.slot < AEQUIP_COUNT)
|
2020-09-14 13:53:48 +00:00
|
|
|
player->Equip[current.slot] = toSet;
|
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;
|
2020-09-21 19:43:53 +00:00
|
|
|
else if (current.slot < (AEQUIP_COUNT + AINVEN_COUNT + ABANK_COUNT))
|
2020-09-09 20:42:55 +00:00
|
|
|
player->Bank[current.slot - AEQUIP_COUNT - AINVEN_COUNT] = toSet;
|
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
|
|
|
}
|
|
|
|
|
2020-09-22 11:16:09 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Database::removeExpiredVehicles(Player* player) {
|
|
|
|
uint64_t currentTime = getTime();
|
|
|
|
//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-22 11:16:09 +00:00
|
|
|
}
|
2020-09-07 00:16:44 +00:00
|
|
|
}
|
2020-09-21 19:43:53 +00:00
|
|
|
|
2020-09-07 00:16:44 +00:00
|
|
|
void Database::getNanos(Player* player) {
|
2020-09-14 14:03:30 +00:00
|
|
|
// get from DB
|
2020-09-07 00:16:44 +00:00
|
|
|
auto nanos = db.get_all<Nano>(
|
|
|
|
where(c(&Nano::playerId) == player->iID)
|
|
|
|
);
|
2020-09-14 14:03:30 +00:00
|
|
|
// 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;
|
|
|
|
}
|
2020-09-02 22:22:00 +00:00
|
|
|
}
|
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-09-09 12:36:35 +00:00
|
|
|
#pragma endregion ShardServer
|
2020-09-21 19:43:53 +00:00
|
|
|
|
|
|
|
#pragma region parsingBlobs
|
|
|
|
|
|
|
|
void Database::appendBlob(std::vector<char> *blob, int64_t input) {
|
|
|
|
for (int i = 0; i < 8; i++) {
|
|
|
|
char toadd = (input >> (8 * (7 - i)));
|
|
|
|
blob->push_back(toadd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t Database::blobToInt64(std::vector<char>::iterator it) {
|
|
|
|
int64_t result = 0;
|
|
|
|
for (int i = 0; i < 8; i++) {
|
|
|
|
int64_t toAdd = ((int64_t)*it << (8 * (7 - i)));
|
|
|
|
result += toAdd;
|
|
|
|
it++;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma endregion parsingBlobs
|