Rewrote DB to use ORM, added all remaining features to LoginServer and refactored it

This commit is contained in:
kamilprzyb
2020-09-02 00:37:09 +02:00
parent 4f6c77be4f
commit 11801c1f89
18 changed files with 14108 additions and 23570 deletions

View File

@@ -1,424 +1,356 @@
#include "contrib/sqlite/sqlite3pp.h"
#include "contrib/bcrypt/BCrypt.hpp"
#include "CNProtocol.hpp"
#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 <regex>
#include <fstream>
#include "contrib/JSON.hpp"
#include "CNStructs.hpp"
#include "contrib/sqlite/sqlite_orm.h"
using namespace sqlite_orm;
//TODO: replace this sqlite wrapper with something better, clean up queries, get rid of json
# pragma region DatabaseScheme
auto db = make_storage("database.db",
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),
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("Body", &Database::DbPlayer::Body),
make_column("Class", &Database::DbPlayer::Class),
make_column("EquipFoot", &Database::DbPlayer::EquipFoot),
make_column("EquipLB", &Database::DbPlayer::EquipLB),
make_column("EquipUB", &Database::DbPlayer::EquipUB),
make_column("EquipWeapon1", &Database::DbPlayer::EquipWeapon1),
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_table("Inventory",
make_column("AccountID", &Database::Inventory::AccountID, primary_key())
)
);
sqlite3pp::database db;
# pragma endregion DatabaseScheme
void Database::open() {
//checking if database file exists
std::ifstream file;
file.open("data.db");
#pragma region LoginServer
if (file) {
file.close();
// if exists, assign it
db = sqlite3pp::database("data.db");
DEBUGLOG(std::cout << "[DB] Database in operation" << std::endl;)
}
else {
// if doesn't, create all the tables
DEBUGLOG(std::cout << "[DB] Creating new database" << std::endl;)
db = sqlite3pp::database("data.db");
// creates accounts
db.execute("CREATE TABLE Accounts(AccountID INTEGER PRIMARY KEY AUTOINCREMENT, Login TEXT NOT NULL, Password TEXT NOT NULL);");
// creates characters
db.execute("CREATE TABLE Players(PlayerID INTEGER PRIMARY KEY AUTOINCREMENT, AccountID INTEGER NOT NULL, Slot INTEGER NOT NULL, FirstName TEXT NOT NULL, LastName TEXT NOT NULL, CharData TEXT NOT NULL);");
DEBUGLOG(std::cout << "Done" << std::endl;)
}
void Database::open()
{
//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;
)
}
// verifies that the username & passwords are valid
bool Database::isLoginDataGood(std::string login, std::string password) {
std::regex loginRegex("^([A-Za-z\\d_\\-]){5,20}$");
std::regex passwordRegex("^([A-Za-z\\d_\\-@$!%*#?&,.+:;<=>]){2,20}$");
return (std::regex_match(login, loginRegex) && std::regex_match(password, passwordRegex));
int Database::addAccount(std::string login, std::string password)
{
password = BCrypt::generateHash(password);
Account x;
x.Login = login;
x.Password = password;
x.Selected = 1;
return db.insert(x);
}
void Database::addAccount(std::string login, std::string password) {
// generates prepared statment
sqlite3pp::command cmd(db, "INSERT INTO Accounts (Login, Password) VALUES (:login, :password)");
// generates a hashed password!
password = BCrypt::generateHash(password);
// binds args to the command
cmd.bind(":login", login, sqlite3pp::nocopy);
cmd.bind(":password", password, sqlite3pp::nocopy);
cmd.execute();
void Database::updateSelected(int accountId, int slot)
{
Account acc = db.get<Account>(accountId);
acc.Selected = slot;
db.update(acc);
}
bool Database::doesUserExist(std::string login) {
// generates prepared statement
sqlite3pp::query qry(db, "SELECT COUNT(AccountID) FROM Accounts WHERE Login = :login");
// binds to the query
qry.bind(":login", login, sqlite3pp::nocopy);
// executes
sqlite3pp::query::iterator i = qry.begin();
// grabs the first result (the count)
int result;
std::tie(result) = (*i).get_columns<int>(0);
// if there is more than 0 results, the user exists :eyes:
return (result > 0);
std::unique_ptr<Database::Account> Database::findAccount(std::string login)
{
//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::isPasswordCorrect(std::string login, std::string password) {
// generates prepared statement
sqlite3pp::query qry(db, "SELECT Password FROM Accounts WHERE Login = :login");
// binds username to the query
qry.bind(":login", login, sqlite3pp::nocopy);
// executes
sqlite3pp::query::iterator i = qry.begin();
// grabs the first result
const char* actual;
std::tie(actual) = (*i).get_columns<const char*>(0);
// validate password hash with provded password
return BCrypt::validatePassword(password, actual);
bool Database::isNameFree(sP_CL2LS_REQ_CHECK_CHAR_NAME* nameCheck)
{
//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::getUserID(std::string login) {
// generates prep statement
sqlite3pp::query qry(db, "SELECT AccountID FROM Accounts WHERE Login = :login");
// binds the username to the login param
qry.bind(":login", login, sqlite3pp::nocopy);
// executes the query
sqlite3pp::query::iterator i = qry.begin();
// grabs the first result of the query
int result;
std::tie(result) = (*i).get_columns<int>(0);
// returns the result
return result;
int Database::createCharacter(sP_CL2LS_REQ_SAVE_CHAR_NAME* save, int AccountID)
{
DbPlayer create;
//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.EquipFoot= 0;
create.EquipLB= 0;
create.EquipUB= 0;
create.EquipWeapon1= 0;
create.EquipWeapon2= 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.x_coordinates = settings::SPAWN_X;
create.y_coordinates= settings::SPAWN_Y;
create.z_coordinates= settings::SPAWN_Z;
return db.insert(create);
}
int Database::getUserSlotsNum(int AccountId) {
// generates the prepared statement
sqlite3pp::query qry(db, "SELECT COUNT(PlayerID) FROM Players WHERE AccountID = :ID");
// binds the ID to the param
qry.bind(":ID", AccountId);
// executes
sqlite3pp::query::iterator i = qry.begin();
// grabs the first result
int result;
std::tie(result) = (*i).get_columns<int>(0);
// returns the result
return result;
void Database::finishCharacter(sP_CL2LS_REQ_CHAR_CREATE* character)
{
DbPlayer finish = getDbPlayerById(character->PCStyle.iPC_UID);
finish.AppearanceFlag = 1;
finish.Body = character->PCStyle.iBody;
finish.Class = character->PCStyle.iClass;
finish.EquipFoot = character->sOn_Item.iEquipFootID;
finish.EquipLB = character->sOn_Item.iEquipLBID;
finish.EquipUB = character->sOn_Item.iEquipUBID;
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);
}
bool Database::isNameFree(std::string First, std::string Second) {
// generates the prepared statement
sqlite3pp::query qry(db, "SELECT COUNT(PlayerID) FROM Players WHERE FirstName = :First COLLATE nocase AND LastName = :Second COLLATE nocase");
// binds the params
qry.bind(":First", First, sqlite3pp::nocopy);
qry.bind(":Second", Second, sqlite3pp::nocopy);
// executes the query
sqlite3pp::query::iterator i = qry.begin();
// grabs the result
int result;
std::tie(result) = (*i).get_columns<int>(0);
// if no results return, the the username is unused
return (result == 0);
void Database::finishTutorial(int PlayerID)
{
DbPlayer finish = getDbPlayerById(PlayerID);
finish.TutorialFlag = 1;
//equip lightning gun
finish.EquipWeapon1 = 328;
db.update(finish);
}
void Database::createCharacter(sP_CL2LS_REQ_SAVE_CHAR_NAME* save, int AccountID) {
// generate the command
sqlite3pp::command cmd(db, "INSERT INTO Players (AccountID, Slot, FirstName, LastName, CharData) VALUES (:AccountID, :Slot, :FirstName, :LastName, :CharData)");
// generate character data
std::string charData = CharacterToJson(save);
std::string first = U16toU8(save->szFirstName);
std::string last = U16toU8(save->szLastName);
// bind to command
cmd.bind(":AccountID", AccountID);
cmd.bind(":Slot", save->iSlotNum);
cmd.bind(":CharData", charData, sqlite3pp::nocopy);
cmd.bind(":FirstName", first, sqlite3pp::nocopy);
cmd.bind(":LastName", last, sqlite3pp::nocopy);
// run
cmd.execute();
int Database::deleteCharacter(int characterID)
{
auto find =
db.get_all<DbPlayer>(where(c(&DbPlayer::PlayerID) == characterID));
int slot = find.front().slot;
db.remove<DbPlayer>(find.front().PlayerID);
return slot;
}
void Database::finishCharacter(sP_CL2LS_REQ_CHAR_CREATE* character) {
sqlite3pp::command cmd(db, "UPDATE Players SET CharData = :data WHERE PlayerID = :id");
// grab the data to add to the command
int id = character->PCStyle.iPC_UID;
std::string charData = CharacterToJson(character);
// bind to the command & execute
cmd.bind(":data", charData, sqlite3pp::nocopy);
cmd.bind(":id", id);
cmd.execute();
std::vector <Player> Database::getCharacters(int UserID)
{
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::finishTutorial(int PlayerID) {
sqlite3pp::query qry(db, "SELECT CharData FROM Players WHERE PlayerID = :ID");
// bind to the query and execute
qry.bind(":ID", PlayerID);
sqlite3pp::query::iterator i = qry.begin();
// grab the player json from the database
std::string json;
std::tie(json) = (*i).get_columns<std::string>(0);
// parse the json into a Player
Player player = JsonToPlayer(json, PlayerID);
// set the tutorial flag & equip lightning gun
player.PCStyle2.iTutorialFlag = 1;
player.Equip[0].iID = 328;
json = PlayerToJson(player);
// update the database
sqlite3pp::command cmd(db, "UPDATE Players SET CharData = :data WHERE PlayerID = :id");
cmd.bind(":data", json, sqlite3pp::nocopy);
cmd.bind(":id", PlayerID);
cmd.execute();
void Database::evaluateCustomName(int characterID, CUSTOMNAME decision) {
DbPlayer player = getDbPlayerById(characterID);
player.NameCheck = (int)decision;
db.update(player);
}
int Database::getCharacterID(int AccountID, int slot) {
// make the query
sqlite3pp::query qry(db, "SELECT PlayerID FROM Players WHERE AccountID = :ID AND Slot = :Slot");
// bind the params & execute
qry.bind(":ID", AccountID);
qry.bind(":Slot", slot);
sqlite3pp::query::iterator i = qry.begin();
// grab the result
int result;
std::tie(result) = (*i).get_columns<int>(0);
return result;
void Database::changeName(sP_CL2LS_REQ_CHANGE_CHAR_NAME* save) {
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);
}
int Database::deleteCharacter(int characterID, int accountID) {
// checking if requested player exist and is bound to the account
Database::DbPlayer Database::playerToDb(Player player)
{
DbPlayer result;
result.PlayerID = player.iID;
result.AccountID = player.accountId;
result.AppearanceFlag = player.PCStyle2.iAppearanceFlag;
result.Body = player.PCStyle.iBody;
result.Class = player.PCStyle.iClass;
//equipment
result.EyeColor = player.PCStyle.iEyeColor;
result.FaceStyle = player.PCStyle.iFaceStyle;
result.FirstName = U16toU8( player.PCStyle.szFirstName);
//fm
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;
//taros
result.TutorialFlag = player.PCStyle2.iTutorialFlag;
result.x_coordinates = player.x;
result.y_coordinates = player.y;
result.z_coordinates = player.z;
sqlite3pp::query qry(db, "SELECT COUNT(AccountID) FROM Players WHERE AccountID = :AccID AND PlayerID = :PID");
qry.bind(":AccID", accountID);
qry.bind(":PID", characterID);
sqlite3pp::query::iterator i = qry.begin();
int result;
std::tie(result) = (*i).get_columns<int>(0);
if (result > 0) {
// get player character slot
sqlite3pp::query qry(db, "SELECT Slot FROM Players WHERE PlayerID = :PID");
// bind & execute
qry.bind(":PID", characterID);
sqlite3pp::query::iterator i = qry.begin();
// grab the slot to return
int slot;
std::tie(slot) = (*i).get_columns<int>(0);
// actually delete the record
sqlite3pp::command cmd(db, "DELETE FROM Players WHERE PlayerID = :ID");
cmd.bind(":ID", characterID);
cmd.execute();
// finally, return the grabbed slot
return slot;
}
return -1;
return result;
}
// TODO: this should really be std::vector, but for the sake of compatibility with PRs, I'll change this after merging
std::list<Player> Database::getCharacters(int userID) {
std::list<Player> result = std::list<Player>();
Player Database::DbToPlayer(DbPlayer player) {
Player result;
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;
sqlite3pp::query qry(db, "SELECT * FROM Players WHERE AccountID = :ID");
//TODO:: implement all of below
result.SerialKey = 0;
result.money = 0;
result.fusionmatter = 0;
result.activeNano = 0;
result.iPCState = 0;
result.equippedNanos[0] = 1;
result.equippedNanos[1] = 0;
result.equippedNanos[2] = 0;
result.isTrading = false;
result.isTradeConfirm = false;
qry.bind(":ID", userID);
result.Nanos[1].iID = 1;
result.Nanos[1].iSkillID = 1;
result.Nanos[1].iStamina = 150;
// for each character owned by the account,
for (sqlite3pp::query::iterator i = qry.begin(); i != qry.end(); ++i) {
// grab the data
int ID, AccountID, slot;
char const* charData, * first, * second;
std::tie(ID, AccountID, slot, first, second, charData) =
(*i).get_columns<int, int, int, char const*, char const*, char const*>(0, 1, 2, 3, 4, 5);
for (int i = 2; i < 37; i++) {
result.Nanos[i].iID = 0;
result.Nanos[i].iSkillID = 0;
result.Nanos[i].iStamina = 0;
}
result.Equip[0].iID = player.EquipWeapon1;
result.Equip[0].iType = 0;
(player.EquipWeapon1) ? result.Equip[0].iOpt = 1 : result.Equip[0].iOpt = 0;
// convert to player
Player toadd = JsonToPlayer(charData, ID);
toadd.slot = slot;
result.Equip[1].iID = player.EquipUB;
result.Equip[1].iType = 1;
(player.EquipUB) ? result.Equip[1].iOpt = 1 : result.Equip[1].iOpt = 0;
// add it to the results
result.push_back(toadd);
}
return result;
result.Equip[2].iID = player.EquipLB;
result.Equip[2].iType = 2;
(player.EquipLB) ? result.Equip[2].iOpt = 1 : result.Equip[2].iOpt = 0;
result.Equip[3].iID = player.EquipFoot;
result.Equip[3].iType = 3;
(player.EquipFoot) ? result.Equip[3].iOpt = 1 : result.Equip[3].iOpt = 0;
for (int i = 4; i < AEQUIP_COUNT; i++) {
// empty equips
result.Equip[i].iID = 0;
result.Equip[i].iType = i;
result.Equip[i].iOpt = 0;
}
for (int i = 0; i < AINVEN_COUNT; i++) {
// setup inventories
result.Inven[i].iID = 0;
result.Inven[i].iType = 0;
result.Inven[i].iOpt = 0;
}
return result;
}
std::string Database::CharacterToJson(sP_CL2LS_REQ_SAVE_CHAR_NAME* save) {
nlohmann::json json = {
{"Level",36},
//to check
{"HP",1000},
{"NameCheck", 1},
{"FirstName",U16toU8(save->szFirstName)},
{"LastName",U16toU8(save->szLastName)},
{"Gender",rand() % 2 + 1 },
{"FaceStyle",1},
{"HairStyle",1},
{"HairColor",(rand() % 19) + 1},
{"SkinColor",(rand() % 13) + 1},
{"EyeColor",(rand() % 6) + 1},
{"Height",(rand() % 6)},
{"Body",(rand() % 4)},
{"Class",0},
{"AppearanceFlag",0},
{"PayzoneFlag",1},
{"TutorialFlag",0},
{"EquipUB", 217},
{"EquipLB", 203},
{"EquipFoot", 314},
{"EquipWeapon", 0},
{"x",settings::SPAWN_X},
{"y",settings::SPAWN_Y},
{"z",settings::SPAWN_Z},
{"isGM",false},
};
return json.dump();
Database::DbPlayer Database::getDbPlayerById(int id) {
return db.get_all<DbPlayer>(where(c(&DbPlayer::PlayerID) == id))
.front();
}
std::string Database::PlayerToJson(Player player) {
nlohmann::json json = {
{"Level",player.level},
//to check
{"HP",player.HP},
{"NameCheck", 1},
{"FirstName",U16toU8(player.PCStyle.szFirstName)},
{"LastName",U16toU8(player.PCStyle.szLastName)},
{"Gender",player.PCStyle.iGender},
{"FaceStyle",player.PCStyle.iFaceStyle},
{"HairStyle",player.PCStyle.iHairStyle},
{"HairColor",player.PCStyle.iHairColor},
{"SkinColor",player.PCStyle.iSkinColor},
{"EyeColor",player.PCStyle.iEyeColor},
{"Height",player.PCStyle.iHeight},
{"Body",player.PCStyle.iBody},
{"Class",player.PCStyle.iClass},
{"AppearanceFlag",player.PCStyle2.iAppearanceFlag},
{"PayzoneFlag",player.PCStyle2.iPayzoneFlag},
{"TutorialFlag",player.PCStyle2.iTutorialFlag},
{"EquipUB", player.Equip[1].iID},
{"EquipLB", player.Equip[2].iID},
{"EquipFoot", player.Equip[3].iID},
{"EquipWeapon", player.Equip[0].iID},
{"x",player.x},
{"y",player.y},
{"z",player.z},
{"isGM",false},
};
return json.dump();
}
Player Database::JsonToPlayer(std::string input, int PC_UID) {
std::string err;
const auto json = nlohmann::json::parse(input);
Player player;
player.PCStyle.iPC_UID = (int64_t)PC_UID;
player.level = std::stoi(json["Level"].dump());
player.HP = std::stoi(json["HP"].dump());
player.PCStyle.iNameCheck = std::stoi(json["NameCheck"].dump());
U8toU16(json["FirstName"].get<std::string>(), player.PCStyle.szFirstName);
U8toU16(json["LastName"].get<std::string>(), player.PCStyle.szLastName);
player.PCStyle.iGender = std::stoi(json["Gender"].dump());
player.PCStyle.iFaceStyle = std::stoi(json["FaceStyle"].dump());
player.PCStyle.iHairStyle = std::stoi(json["HairStyle"].dump());
player.PCStyle.iHairColor = std::stoi(json["HairColor"].dump());
player.PCStyle.iSkinColor = std::stoi(json["SkinColor"].dump());
player.PCStyle.iEyeColor = std::stoi(json["EyeColor"].dump());
player.PCStyle.iHeight = std::stoi(json["Height"].dump());
player.PCStyle.iBody = std::stoi(json["Body"].dump());
player.PCStyle.iClass = std::stoi(json["Class"].dump());
player.PCStyle2.iAppearanceFlag = std::stoi(json["AppearanceFlag"].dump());
player.PCStyle2.iPayzoneFlag = std::stoi(json["PayzoneFlag"].dump());
player.PCStyle2.iTutorialFlag = std::stoi(json["TutorialFlag"].dump());
player.Equip[0].iID = std::stoi(json["EquipWeapon"].dump());
if (player.Equip[0].iID != 0)
player.Equip[0].iOpt = 1;
else
player.Equip[0].iOpt = 0;
player.Equip[0].iType = 0;
player.Equip[1].iID = std::stoi(json["EquipUB"].dump());
player.Equip[1].iOpt = 1;
player.Equip[1].iType = 1;
player.Equip[2].iID = std::stoi(json["EquipLB"].dump());
player.Equip[2].iOpt = 1;
player.Equip[2].iType = 2;
player.Equip[3].iID = std::stoi(json["EquipFoot"].dump());
player.Equip[3].iOpt = 1;
player.Equip[3].iType = 3;
player.x = std::stoi(json["x"].dump());
player.y = std::stoi(json["y"].dump());
player.z = std::stoi(json["z"].dump());
return player;
}
std::string Database::CharacterToJson(sP_CL2LS_REQ_CHAR_CREATE* character) {
nlohmann::json json = {
{"Level",36},
//to check
{"HP",1000},
{"NameCheck", 1},
{"FirstName",U16toU8(character->PCStyle.szFirstName)},
{"LastName",U16toU8(character->PCStyle.szLastName)},
{"Gender",character->PCStyle.iGender},
{"FaceStyle",character->PCStyle.iFaceStyle},
{"HairStyle",character->PCStyle.iHairStyle},
{"HairColor",character->PCStyle.iHairColor},
{"SkinColor",character->PCStyle.iSkinColor},
{"EyeColor",character->PCStyle.iEyeColor},
{"Height",character->PCStyle.iHeight},
{"Body",character->PCStyle.iBody},
{"Class",character->PCStyle.iClass},
{"AppearanceFlag",1},
{"PayzoneFlag",1},
{"TutorialFlag",0},
{"EquipUB", character->sOn_Item.iEquipUBID},
{"EquipLB", character->sOn_Item.iEquipLBID},
{"EquipFoot", character->sOn_Item.iEquipFootID},
{"EquipWeapon", 0},
{"x",settings::SPAWN_X},
{"y",settings::SPAWN_Y},
{"z",settings::SPAWN_Z},
{"isGM",false},
};
return json.dump();
}
#pragma endregion LoginServer