This code might not work 100% or I might not have given all the code, but its good for testing purposes.
account.h
iologindata.cpp
protocollogin.cpp
add this to your schema CREATE TABLE IF NOT EXISTS `players` (
Add this to IOLoginData::loadPlayer
above
Find IOLoginData::savePlayer(Player* player) and add this
below
account.h
C++:
#ifndef FS_ACCOUNT_H_34817537BA2B4CB7B71AA562AFBB118F
#define FS_ACCOUNT_H_34817537BA2B4CB7B71AA562AFBB118F
#include "enums.h"
struct Account {
std::vector<std::string> characters;
std::string name;
std::vector<std::string> vocinitial;
std::vector<std::string> charlevel;
std::string key;
time_t lastDay = 0;
uint32_t id = 0;
uint16_t premiumDays = 0;
AccountType_t accountType = ACCOUNT_TYPE_NORMAL;
Account() = default;
};
#endif
iologindata.cpp
C++:
bool IOLoginData::loginserverAuthentication(const std::string& name, const std::string& password, Account& account)
{
Database* db = Database::getInstance();
std::ostringstream query;
query << "SELECT `id`, `name`, `password`, `secret`, `type`, `premdays`, `lastday` FROM `accounts` WHERE `name` = " << db.escapeString(name);
DBResult_ptr result = db.storeQuery(query.str());
if (!result) {
return false;
}
if (transformToSHA1(password) != result->getString("password")) {
return false;
}
account.id = result->getNumber<uint32_t>("id");
account.name = result->getString("name");
account.key = decodeSecret(result->getString("secret"));
account.accountType = static_cast<AccountType_t>(result->getNumber<int32_t>("type"));
account.premiumDays = result->getNumber<uint16_t>("premdays");
account.lastDay = result->getNumber<time_t>("lastday");
query.str(std::string());
query << "SELECT `name`, `deletion`, `initial`, `level` FROM `players` WHERE `account_id` = " << account.id;
result = db.storeQuery(query.str());
if (result) {
do {
if (result->getNumber<uint64_t>("deletion") == 0) {
account.charlevel.push_back(levelConversion(result->getNumber<uint32_t>("level")));
account.vocinitial.push_back(result->getString("initial"));
account.characters.push_back(result->getString("name"));
}
} while (result->next());
}
return true;
}
protocollogin.cpp
C++:
void ProtocolLogin::getCharacterList(const std::string& accountName, const std::string& password, uint16_t version)
{
Account account;
if (!IOLoginData::loginserverAuthentication(accountName, password, account)) {
disconnectClient("Account name or password is not correct.", version);
return;
}
auto output = OutputMessagePool::getOutputMessage();
//Update premium days
Game::updatePremium(account);
addWorldInfo(output, accountName, password, version);
uint8_t size = std::min<size_t>(std::numeric_limits<uint8_t>::max(), account.characters.size());
output->addByte(size);
for (uint8_t i = 0; i < size; i++) {
output->addByte(0);
const std::string achar = account.characters[i] + ":[ " + account.vocinitial[i] + " ][ " + account.charlevel[i] + " ] ";
output->addString(achar);
}
//Add premium days
output->addByte(0);
if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
output->addByte(1);
output->add<uint32_t>(0);
} else {
output->addByte(0);
output->add<uint32_t>(time(nullptr) + (account.premiumDays * 86400));
}
send(output);
disconnect();
}
add this to your schema CREATE TABLE IF NOT EXISTS `players` (
Code:
`initial` varchar(1) NOT NULL DEFAULT 'N',
Add this to IOLoginData::loadPlayer
C++:
player->setInitial(result->getString("initial"));
Code:
player->mana = result->getNumber<uint32_t>("mana");
Find IOLoginData::savePlayer(Player* player) and add this
C++:
query << "`initial` = '" << player->getInitial() << "',";
C++:
query << "`vocation` = " << player->getVocationId() << ',';
C++:
void ProtocolGame::sendToChannel(const Creature* creature, SpeakClasses type, const std::string& text, uint16_t channelId)
{
NetworkMessage msg;
msg.addByte(0xAA);
static uint32_t statementId = 0;
msg.add<uint32_t>(++statementId);
if (!creature) {
msg.add<uint32_t>(0x00);
}
else if (type == TALKTYPE_CHANNEL_R2) {
msg.add<uint32_t>(0x00);
type = TALKTYPE_CHANNEL_R1;
}
else {
// we want the player's name, their vocation and a summery of their level since its limited in range
if (auto c = creature->getCreature()) {
if (auto p = c->getPlayer()) {
std::string extension = "[" + p->getInitial() + "][" + p->getPlayerTypeString() + "][" + levelConversion(p->getLevel()) + "]";
const std::string tempName = getAbbreName(p->getName(), extension.size());
const std::string newName = tempName + extension;
msg.addString(newName);
}
else {
msg.addString(creature->getName());
}
}
msg.add<uint16_t>(0x00);
}
msg.addByte(type);
msg.add<uint16_t>(channelId);
msg.addString(text);
writeToOutputBuffer(msg);
}
C++:
const std::string getAbbreName(const std::string name, size_t x) {
if (name.size() > (x+2)) {
const std::string n = name.substr(0, (name.size() - (x+2))) + "~";
return n;
}
return name + " ";
}
C++:
void ProtocolGame::sendPrivateMessage(const Player* speaker, SpeakClasses type, const std::string& text)
{
NetworkMessage msg;
msg.addByte(0xAA);
static uint32_t statementId = 0;
msg.add<uint32_t>(++statementId);
if (speaker) {
// we want the player's name, their vocation and a summery of their level since its limited in range
if (auto c = speaker->getCreature()) {
if (auto p = c->getPlayer()) {
std::string extension = "[" + p->getInitial() + "][" + p->getPlayerTypeString() + "][" + levelConversion(p->getLevel()) + "]";
const std::string tempName = getAbbreName(p->getName(), extension.size());
const std::string newName = tempName + extension;
msg.addString(newName);
}
else {
msg.addString(speaker->getName());
}
}
msg.add<uint16_t>(0x00);
}
else {
msg.add<uint32_t>(0x00);
}
msg.addByte(type);
msg.addString(text);
writeToOutputBuffer(msg);
}
C++:
const std::string levelConversion(uint32_t value) {
double i = (double)value;
std::string l;
if (value >= 1000 && value <= 999999) {
l = std::to_string(i / 1000);
if (l.substr(l.find('.') + 1, l.find('.')) == "0") {
const std::string level = l.substr(0, l.find('.')) + "K";
return level;
}
else {
const std::string level = l.substr(0, l.find('.') + 2) + "K";
return level;
}
}
else if (value >= 1000000 && value <= 999999999) {
l = std::to_string(i / 1000000);
if (l.substr(l.find('.') + 1, l.find('.')) == "0") {
const std::string level = l.substr(0, l.find('.')) + "M";
return level;
}
else {
const std::string level = l.substr(0, l.find('.') + 2) + "M";
return level;
}
}
else if (value >= 999999999 && value <= 9999999999) {
l = std::to_string(i / 999999999);
if (l.substr(l.find('.') + 1, l.find('.')) == "0") {
const std::string level = l.substr(0, l.find('.')) + "B";
return level;
}
else {
const std::string level = l.substr(0, l.find('.') + 2) + "B";
return level;
}
}
const std::string level = std::to_string(value);
return level;
}