mirror of
https://github.com/ErikasKontenis/SabrehavenServer.git
synced 2025-05-07 20:29:20 +02:00
issiauskinau kad checksum yra nahuj reikalingas ir kad onConnect turejo buti uzkomentuotas. Reikia issiaiskinti kodel luzta onLogin clientas. Kitus failus reikia perziureti ir isvalyti siuksles
This commit is contained in:
parent
f0e103a475
commit
3d05566759
@ -52,7 +52,7 @@ timeBetweenExActions = 1000
|
||||
|
||||
-- Map
|
||||
-- NOTE: set mapName WITHOUT .otbm at the end
|
||||
mapName = "map"
|
||||
mapName = "mymap"
|
||||
mapAuthor = "CipSoft"
|
||||
|
||||
-- MySQL
|
||||
|
2
data/world/mymap-house.xml
Normal file
2
data/world/mymap-house.xml
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<houses/>
|
2
data/world/mymap-spawn.xml
Normal file
2
data/world/mymap-spawn.xml
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<spawns/>
|
BIN
data/world/mymap.otbm
Normal file
BIN
data/world/mymap.otbm
Normal file
Binary file not shown.
@ -74,6 +74,7 @@ bool ConfigManager::load()
|
||||
boolean[FREE_PREMIUM] = getGlobalBoolean(L, "freePremium", false);
|
||||
boolean[REPLACE_KICK_ON_LOGIN] = getGlobalBoolean(L, "replaceKickOnLogin", true);
|
||||
boolean[ALLOW_CLONES] = getGlobalBoolean(L, "allowClones", false);
|
||||
boolean[STAMINA_SYSTEM] = getGlobalBoolean(L, "staminaSystem", true);
|
||||
boolean[WARN_UNSAFE_SCRIPTS] = getGlobalBoolean(L, "warnUnsafeScripts", true);
|
||||
boolean[CONVERT_UNSAFE_SCRIPTS] = getGlobalBoolean(L, "convertUnsafeScripts", true);
|
||||
boolean[TELEPORT_NEWBIES] = getGlobalBoolean(L, "teleportNewbies", true);
|
||||
|
@ -37,6 +37,7 @@ class ConfigManager
|
||||
ALLOW_CLONES,
|
||||
BIND_ONLY_GLOBAL_ADDRESS,
|
||||
OPTIMIZE_DATABASE,
|
||||
STAMINA_SYSTEM,
|
||||
WARN_UNSAFE_SCRIPTS,
|
||||
CONVERT_UNSAFE_SCRIPTS,
|
||||
TELEPORT_NEWBIES,
|
||||
|
@ -187,29 +187,13 @@ void Connection::parsePacket(const boost::system::error_code& error)
|
||||
return;
|
||||
}
|
||||
|
||||
//Check packet checksum
|
||||
uint32_t checksum;
|
||||
int32_t len = msg.getLength() - msg.getBufferPosition() - NetworkMessage::CHECKSUM_LENGTH;
|
||||
if (len > 0) {
|
||||
checksum = adlerChecksum(msg.getBuffer() + msg.getBufferPosition() + NetworkMessage::CHECKSUM_LENGTH, len);
|
||||
}
|
||||
else {
|
||||
checksum = 0;
|
||||
}
|
||||
|
||||
uint32_t recvChecksum = msg.get<uint32_t>();
|
||||
if (recvChecksum != checksum) {
|
||||
// it might not have been the checksum, step back
|
||||
msg.skipBytes(-NetworkMessage::CHECKSUM_LENGTH);
|
||||
}
|
||||
|
||||
if (!receivedFirst) {
|
||||
// First message received
|
||||
receivedFirst = true;
|
||||
|
||||
if (!protocol) {
|
||||
// Game protocol has already been created at this point
|
||||
protocol = service_port->make_protocol(recvChecksum == checksum, msg, shared_from_this());
|
||||
protocol = service_port->make_protocol(msg, shared_from_this());
|
||||
if (!protocol) {
|
||||
close(FORCE_CLOSE);
|
||||
return;
|
||||
@ -242,6 +226,7 @@ void Connection::parsePacket(const boost::system::error_code& error)
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Connection::send(const OutputMessage_ptr& msg)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lockClass(connectionLock);
|
||||
|
@ -188,7 +188,7 @@ bool IOLoginData::preloadPlayer(Player* player, const std::string& name)
|
||||
bool IOLoginData::loadPlayerById(Player* player, uint32_t id)
|
||||
{
|
||||
std::ostringstream query;
|
||||
query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `id` = " << id;
|
||||
query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `id` = " << id;
|
||||
return loadPlayer(player, Database::getInstance()->storeQuery(query.str()));
|
||||
}
|
||||
|
||||
@ -196,7 +196,7 @@ bool IOLoginData::loadPlayerByName(Player* player, const std::string& name)
|
||||
{
|
||||
Database* db = Database::getInstance();
|
||||
std::ostringstream query;
|
||||
query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `name` = " << db->escapeString(name);
|
||||
query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `name` = " << db->escapeString(name);
|
||||
return loadPlayer(player, db->storeQuery(query.str()));
|
||||
}
|
||||
|
||||
@ -296,6 +296,7 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
|
||||
player->defaultOutfit.lookBody = result->getNumber<uint16_t>("lookbody");
|
||||
player->defaultOutfit.lookLegs = result->getNumber<uint16_t>("looklegs");
|
||||
player->defaultOutfit.lookFeet = result->getNumber<uint16_t>("lookfeet");
|
||||
player->defaultOutfit.lookAddons = result->getNumber<uint16_t>("lookaddons");
|
||||
player->currentOutfit = player->defaultOutfit;
|
||||
|
||||
if (g_game.getWorldType() != WORLD_TYPE_PVP_ENFORCED) {
|
||||
@ -331,6 +332,8 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result)
|
||||
player->loginPosition = player->getTemplePosition();
|
||||
}
|
||||
|
||||
player->staminaMinutes = result->getNumber<uint16_t>("stamina");
|
||||
|
||||
static const std::string skillNames[] = {"skill_fist", "skill_club", "skill_sword", "skill_axe", "skill_dist", "skill_shielding", "skill_fishing"};
|
||||
static const std::string skillNameTries[] = {"skill_fist_tries", "skill_club_tries", "skill_sword_tries", "skill_axe_tries", "skill_dist_tries", "skill_shielding_tries", "skill_fishing_tries"};
|
||||
static constexpr size_t size = sizeof(skillNames) / sizeof(std::string);
|
||||
@ -616,6 +619,7 @@ bool IOLoginData::savePlayer(Player* player)
|
||||
query << "`lookhead` = " << static_cast<uint32_t>(player->defaultOutfit.lookHead) << ',';
|
||||
query << "`looklegs` = " << static_cast<uint32_t>(player->defaultOutfit.lookLegs) << ',';
|
||||
query << "`looktype` = " << player->defaultOutfit.lookType << ',';
|
||||
query << "`lookaddons` = " << static_cast<uint32_t>(player->defaultOutfit.lookAddons) << ',';
|
||||
query << "`maglevel` = " << player->magLevel << ',';
|
||||
query << "`mana` = " << player->mana << ',';
|
||||
query << "`manamax` = " << player->manaMax << ',';
|
||||
@ -654,6 +658,7 @@ bool IOLoginData::savePlayer(Player* player)
|
||||
|
||||
query << "`lastlogout` = " << player->getLastLogout() << ',';
|
||||
query << "`balance` = " << player->bankBalance << ',';
|
||||
query << "`stamina` = " << player->getStaminaMinutes() << ',';
|
||||
|
||||
query << "`skill_fist` = " << player->skills[SKILL_FIST].level << ',';
|
||||
query << "`skill_fist_tries` = " << player->skills[SKILL_FIST].tries << ',';
|
||||
|
@ -730,6 +730,8 @@ Position LuaScriptInterface::getPosition(lua_State* L, int32_t arg)
|
||||
Outfit_t LuaScriptInterface::getOutfit(lua_State* L, int32_t arg)
|
||||
{
|
||||
Outfit_t outfit;
|
||||
outfit.lookAddons = getField<uint8_t>(L, arg, "lookAddons");
|
||||
|
||||
outfit.lookFeet = getField<uint8_t>(L, arg, "lookFeet");
|
||||
outfit.lookLegs = getField<uint8_t>(L, arg, "lookLegs");
|
||||
outfit.lookBody = getField<uint8_t>(L, arg, "lookBody");
|
||||
@ -882,6 +884,7 @@ void LuaScriptInterface::pushOutfit(lua_State* L, const Outfit_t& outfit)
|
||||
setField(L, "lookBody", outfit.lookBody);
|
||||
setField(L, "lookLegs", outfit.lookLegs);
|
||||
setField(L, "lookFeet", outfit.lookFeet);
|
||||
setField(L, "lookAddons", outfit.lookAddons);
|
||||
}
|
||||
|
||||
#define registerEnum(value) { std::string enumName = #value; registerGlobalVariable(enumName.substr(enumName.find_last_of(':') + 1), value); }
|
||||
@ -1607,6 +1610,7 @@ void LuaScriptInterface::registerFunctions()
|
||||
registerEnumIn("configKeys", ConfigManager::ALLOW_CLONES)
|
||||
registerEnumIn("configKeys", ConfigManager::BIND_ONLY_GLOBAL_ADDRESS)
|
||||
registerEnumIn("configKeys", ConfigManager::OPTIMIZE_DATABASE)
|
||||
registerEnumIn("configKeys", ConfigManager::STAMINA_SYSTEM)
|
||||
registerEnumIn("configKeys", ConfigManager::WARN_UNSAFE_SCRIPTS)
|
||||
registerEnumIn("configKeys", ConfigManager::CONVERT_UNSAFE_SCRIPTS)
|
||||
registerEnumIn("configKeys", ConfigManager::TELEPORT_NEWBIES)
|
||||
@ -2008,6 +2012,9 @@ void LuaScriptInterface::registerFunctions()
|
||||
registerMethod("Player", "getGroup", LuaScriptInterface::luaPlayerGetGroup);
|
||||
registerMethod("Player", "setGroup", LuaScriptInterface::luaPlayerSetGroup);
|
||||
|
||||
registerMethod("Player", "getStamina", LuaScriptInterface::luaPlayerGetStamina);
|
||||
registerMethod("Player", "setStamina", LuaScriptInterface::luaPlayerSetStamina);
|
||||
|
||||
registerMethod("Player", "getSoul", LuaScriptInterface::luaPlayerGetSoul);
|
||||
registerMethod("Player", "addSoul", LuaScriptInterface::luaPlayerAddSoul);
|
||||
registerMethod("Player", "getMaxSoul", LuaScriptInterface::luaPlayerGetMaxSoul);
|
||||
@ -7757,6 +7764,35 @@ int LuaScriptInterface::luaPlayerSetGroup(lua_State* L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaScriptInterface::luaPlayerGetStamina(lua_State* L)
|
||||
{
|
||||
// player:getStamina()
|
||||
Player* player = getUserdata<Player>(L, 1);
|
||||
if (player) {
|
||||
lua_pushnumber(L, player->getStaminaMinutes());
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaScriptInterface::luaPlayerSetStamina(lua_State* L)
|
||||
{
|
||||
// player:setStamina(stamina)
|
||||
uint16_t stamina = getNumber<uint16_t>(L, 2);
|
||||
Player* player = getUserdata<Player>(L, 1);
|
||||
if (player) {
|
||||
player->staminaMinutes = std::min<uint16_t>(2520, stamina);
|
||||
player->sendStats();
|
||||
pushBoolean(L, true);
|
||||
}
|
||||
else {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int LuaScriptInterface::luaPlayerGetSoul(lua_State* L)
|
||||
{
|
||||
// player:getSoul()
|
||||
@ -10616,11 +10652,12 @@ int LuaScriptInterface::luaConditionSetSpeedDelta(lua_State* L)
|
||||
int LuaScriptInterface::luaConditionSetOutfit(lua_State* L)
|
||||
{
|
||||
// condition:setOutfit(outfit)
|
||||
// condition:setOutfit(lookTypeEx, lookType, lookHead, lookBody, lookLegs, lookFeet)
|
||||
// condition:setOutfit(lookTypeEx, lookType, lookHead, lookBody, lookLegs, lookFeet[, lookAddons])
|
||||
Outfit_t outfit;
|
||||
if (isTable(L, 2)) {
|
||||
outfit = getOutfit(L, 2);
|
||||
} else {
|
||||
outfit.lookAddons = getNumber<uint8_t>(L, 8, outfit.lookAddons);
|
||||
outfit.lookFeet = getNumber<uint8_t>(L, 7);
|
||||
outfit.lookLegs = getNumber<uint8_t>(L, 6);
|
||||
outfit.lookBody = getNumber<uint8_t>(L, 5);
|
||||
|
@ -849,6 +849,9 @@ class LuaScriptInterface
|
||||
static int luaPlayerGetGroup(lua_State* L);
|
||||
static int luaPlayerSetGroup(lua_State* L);
|
||||
|
||||
static int luaPlayerGetStamina(lua_State* L);
|
||||
static int luaPlayerSetStamina(lua_State* L);
|
||||
|
||||
static int luaPlayerGetSoul(lua_State* L);
|
||||
static int luaPlayerAddSoul(lua_State* L);
|
||||
static int luaPlayerGetMaxSoul(lua_State* L);
|
||||
|
@ -759,6 +759,10 @@ bool Monsters::loadMonster(const std::string& file, const std::string& monsterNa
|
||||
if ((attr = node.attribute("feet"))) {
|
||||
mType->info.outfit.lookFeet = pugi::cast<uint16_t>(attr.value());
|
||||
}
|
||||
|
||||
if ((attr = node.attribute("addons"))) {
|
||||
mType->info.outfit.lookAddons = pugi::cast<uint16_t>(attr.value());
|
||||
}
|
||||
} else if ((attr = node.attribute("typeex"))) {
|
||||
mType->info.outfit.lookTypeEx = pugi::cast<uint16_t>(attr.value());
|
||||
} else {
|
||||
|
@ -28,80 +28,76 @@ class Protocol;
|
||||
|
||||
class OutputMessage : public NetworkMessage
|
||||
{
|
||||
public:
|
||||
OutputMessage() = default;
|
||||
public:
|
||||
OutputMessage() = default;
|
||||
|
||||
// non-copyable
|
||||
OutputMessage(const OutputMessage&) = delete;
|
||||
OutputMessage& operator=(const OutputMessage&) = delete;
|
||||
// non-copyable
|
||||
OutputMessage(const OutputMessage&) = delete;
|
||||
OutputMessage& operator=(const OutputMessage&) = delete;
|
||||
|
||||
uint8_t* getOutputBuffer() {
|
||||
return buffer + outputBufferStart;
|
||||
}
|
||||
uint8_t* getOutputBuffer() {
|
||||
return buffer + outputBufferStart;
|
||||
}
|
||||
|
||||
void writeMessageLength() {
|
||||
add_header(info.length);
|
||||
}
|
||||
void writeMessageLength() {
|
||||
add_header(info.length);
|
||||
}
|
||||
|
||||
void addCryptoHeader(bool addChecksum) {
|
||||
if (addChecksum) {
|
||||
add_header(adlerChecksum(buffer + outputBufferStart, info.length));
|
||||
}
|
||||
void addCryptoHeader(bool addChecksum) {
|
||||
writeMessageLength();
|
||||
}
|
||||
|
||||
writeMessageLength();
|
||||
}
|
||||
inline void append(const NetworkMessage& msg) {
|
||||
auto msgLen = msg.getLength();
|
||||
memcpy(buffer + info.position, msg.getBuffer() + 4, msgLen);
|
||||
info.length += msgLen;
|
||||
info.position += msgLen;
|
||||
}
|
||||
|
||||
inline void append(const NetworkMessage& msg) {
|
||||
auto msgLen = msg.getLength();
|
||||
memcpy(buffer + info.position, msg.getBuffer() + 4, msgLen);
|
||||
info.length += msgLen;
|
||||
info.position += msgLen;
|
||||
}
|
||||
inline void append(const OutputMessage_ptr& msg) {
|
||||
auto msgLen = msg->getLength();
|
||||
memcpy(buffer + info.position, msg->getBuffer() + 4, msgLen);
|
||||
info.length += msgLen;
|
||||
info.position += msgLen;
|
||||
}
|
||||
|
||||
inline void append(const OutputMessage_ptr& msg) {
|
||||
auto msgLen = msg->getLength();
|
||||
memcpy(buffer + info.position, msg->getBuffer() + 4, msgLen);
|
||||
info.length += msgLen;
|
||||
info.position += msgLen;
|
||||
}
|
||||
protected:
|
||||
template <typename T>
|
||||
inline void add_header(T add) {
|
||||
assert(outputBufferStart >= sizeof(T));
|
||||
outputBufferStart -= sizeof(T);
|
||||
memcpy(buffer + outputBufferStart, &add, sizeof(T));
|
||||
//added header size to the message size
|
||||
info.length += sizeof(T);
|
||||
}
|
||||
|
||||
protected:
|
||||
template <typename T>
|
||||
inline void add_header(T add) {
|
||||
assert(outputBufferStart >= sizeof(T));
|
||||
outputBufferStart -= sizeof(T);
|
||||
memcpy(buffer + outputBufferStart, &add, sizeof(T));
|
||||
//added header size to the message size
|
||||
info.length += sizeof(T);
|
||||
}
|
||||
|
||||
MsgSize_t outputBufferStart = INITIAL_BUFFER_POSITION;
|
||||
MsgSize_t outputBufferStart = INITIAL_BUFFER_POSITION;
|
||||
};
|
||||
|
||||
class OutputMessagePool
|
||||
{
|
||||
public:
|
||||
// non-copyable
|
||||
OutputMessagePool(const OutputMessagePool&) = delete;
|
||||
OutputMessagePool& operator=(const OutputMessagePool&) = delete;
|
||||
public:
|
||||
// non-copyable
|
||||
OutputMessagePool(const OutputMessagePool&) = delete;
|
||||
OutputMessagePool& operator=(const OutputMessagePool&) = delete;
|
||||
|
||||
static OutputMessagePool& getInstance() {
|
||||
static OutputMessagePool instance;
|
||||
return instance;
|
||||
}
|
||||
static OutputMessagePool& getInstance() {
|
||||
static OutputMessagePool instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void sendAll();
|
||||
void scheduleSendAll();
|
||||
void sendAll();
|
||||
void scheduleSendAll();
|
||||
|
||||
static OutputMessage_ptr getOutputMessage();
|
||||
static OutputMessage_ptr getOutputMessage();
|
||||
|
||||
void addProtocolToAutosend(Protocol_ptr protocol);
|
||||
void removeProtocolFromAutosend(const Protocol_ptr& protocol);
|
||||
private:
|
||||
OutputMessagePool() = default;
|
||||
//NOTE: A vector is used here because this container is mostly read
|
||||
//and relatively rarely modified (only when a client connects/disconnects)
|
||||
std::vector<Protocol_ptr> bufferedProtocols;
|
||||
void addProtocolToAutosend(Protocol_ptr protocol);
|
||||
void removeProtocolFromAutosend(const Protocol_ptr& protocol);
|
||||
private:
|
||||
OutputMessagePool() = default;
|
||||
//NOTE: A vector is used here because this container is mostly read
|
||||
//and relatively rarely modified (only when a client connects/disconnects)
|
||||
std::vector<Protocol_ptr> bufferedProtocols;
|
||||
};
|
||||
|
||||
|
||||
|
@ -242,8 +242,6 @@ void ProtocolGame::onRecvFirstMessage(NetworkMessage& msg)
|
||||
OperatingSystem_t operatingSystem = static_cast<OperatingSystem_t>(msg.get<uint16_t>());
|
||||
version = msg.get<uint16_t>();
|
||||
|
||||
msg.skipBytes(7); // U32 client version, U8 client type, U16 dat revision
|
||||
|
||||
if (!Protocol::RSA_decrypt(msg)) {
|
||||
disconnect();
|
||||
return;
|
||||
@ -304,45 +302,24 @@ void ProtocolGame::onRecvFirstMessage(NetworkMessage& msg)
|
||||
disconnectClient("Account number or password is not correct.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Account account;
|
||||
if (!IOLoginData::loginserverAuthentication(accountNumber, password, account)) {
|
||||
disconnectClient("Account number or password is not correct.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//Update premium days
|
||||
Game::updatePremium(account);
|
||||
|
||||
g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::login, getThis(), characterName, accountId, operatingSystem)));
|
||||
|
||||
}
|
||||
|
||||
void ProtocolGame::onConnect()
|
||||
{
|
||||
auto output = OutputMessagePool::getOutputMessage();
|
||||
static std::random_device rd;
|
||||
static std::ranlux24 generator(rd());
|
||||
static std::uniform_int_distribution<uint16_t> randNumber(0x00, 0xFF);
|
||||
|
||||
// Skip checksum
|
||||
output->skipBytes(sizeof(uint32_t));
|
||||
|
||||
// Packet length & type
|
||||
output->add<uint16_t>(0x0006);
|
||||
output->addByte(0x1F);
|
||||
|
||||
// Add timestamp & random number
|
||||
challengeTimestamp = static_cast<uint32_t>(time(nullptr));
|
||||
output->add<uint32_t>(challengeTimestamp);
|
||||
|
||||
challengeRandom = randNumber(generator);
|
||||
output->addByte(challengeRandom);
|
||||
|
||||
// Go back and write checksum
|
||||
output->skipBytes(-12);
|
||||
output->add<uint32_t>(adlerChecksum(output->getOutputBuffer() + sizeof(uint32_t), 8));
|
||||
|
||||
send(output);
|
||||
}
|
||||
|
||||
void ProtocolGame::disconnectClient(const std::string& message) const
|
||||
@ -464,12 +441,15 @@ void ProtocolGame::parsePacket(NetworkMessage& msg)
|
||||
|
||||
void ProtocolGame::GetTileDescription(const Tile* tile, NetworkMessage& msg)
|
||||
{
|
||||
msg.add<uint16_t>(0x00); //environmental effects
|
||||
|
||||
int32_t count;
|
||||
Item* ground = tile->getGround();
|
||||
if (ground) {
|
||||
msg.addItem(ground);
|
||||
count = 1;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
count = 0;
|
||||
}
|
||||
|
||||
@ -478,7 +458,11 @@ void ProtocolGame::GetTileDescription(const Tile* tile, NetworkMessage& msg)
|
||||
for (auto it = items->getBeginTopItem(), end = items->getEndTopItem(); it != end; ++it) {
|
||||
msg.addItem(*it);
|
||||
|
||||
if (++count == 10) {
|
||||
count++;
|
||||
if (count == 9 && tile->getPosition() == player->getPosition()) {
|
||||
break;
|
||||
}
|
||||
else if (count == 10) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -486,11 +470,20 @@ void ProtocolGame::GetTileDescription(const Tile* tile, NetworkMessage& msg)
|
||||
|
||||
const CreatureVector* creatures = tile->getCreatures();
|
||||
if (creatures) {
|
||||
bool playerAdded = false;
|
||||
for (const Creature* creature : boost::adaptors::reverse(*creatures)) {
|
||||
if (!player->canSeeCreature(creature)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tile->getPosition() == player->getPosition() && count == 9 && !playerAdded) {
|
||||
creature = player;
|
||||
}
|
||||
|
||||
if (creature->getID() == player->getID()) {
|
||||
playerAdded = true;
|
||||
}
|
||||
|
||||
bool known;
|
||||
uint32_t removedKnown;
|
||||
checkCreatureAsKnown(creature->getID(), known, removedKnown);
|
||||
@ -1864,12 +1857,18 @@ void ProtocolGame::AddPlayerStats(NetworkMessage& msg)
|
||||
msg.add<uint16_t>(std::min<int32_t>(player->getMaxMana(), std::numeric_limits<uint16_t>::max()));
|
||||
|
||||
msg.addByte(std::min<uint32_t>(player->getMagicLevel(), std::numeric_limits<uint8_t>::max()));
|
||||
msg.addByte(std::min<uint32_t>(player->getBaseMagicLevel(), std::numeric_limits<uint8_t>::max()));
|
||||
msg.addByte(player->getMagicLevelPercent());
|
||||
|
||||
msg.addByte(player->getSoul());
|
||||
|
||||
msg.add<uint16_t>(player->getStaminaMinutes());
|
||||
|
||||
msg.add<uint16_t>(player->getBaseSpeed() / 2);
|
||||
|
||||
Condition* condition = player->getCondition(CONDITION_REGENERATION);
|
||||
msg.add<uint16_t>(condition ? condition->getTicks() / 1000 : 0x00);
|
||||
|
||||
msg.add<uint16_t>(0); // xp boost time (seconds)
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ void ProtocolLogin::disconnectClient(const std::string& message, uint16_t versio
|
||||
disconnect();
|
||||
}
|
||||
|
||||
void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string& password, const std::string& token, uint16_t version)
|
||||
void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string& password, uint16_t version)
|
||||
{
|
||||
Account account;
|
||||
if (!IOLoginData::loginserverAuthentication(accountNumber, password, account)) {
|
||||
@ -51,20 +51,7 @@ void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string&
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t ticks = time(nullptr) / AUTHENTICATOR_PERIOD;
|
||||
|
||||
auto output = OutputMessagePool::getOutputMessage();
|
||||
if (!std::to_string(accountNumber).empty()) {
|
||||
if (token.empty() || !(token == generateToken(std::to_string(accountNumber), ticks) || token == generateToken(std::to_string(accountNumber), ticks - 1) || token == generateToken(std::to_string(accountNumber), ticks + 1))) {
|
||||
output->addByte(0x0D);
|
||||
output->addByte(0);
|
||||
send(output);
|
||||
disconnect();
|
||||
return;
|
||||
}
|
||||
output->addByte(0x0C);
|
||||
output->addByte(0);
|
||||
}
|
||||
|
||||
//Update premium days
|
||||
Game::updatePremium(account);
|
||||
@ -79,38 +66,24 @@ void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string&
|
||||
output->addString(ss.str());
|
||||
}
|
||||
|
||||
//Add session key
|
||||
output->addByte(0x28);
|
||||
output->addString(std::to_string(accountNumber) + "\n" + password + "\n" + token + "\n" + std::to_string(ticks));
|
||||
|
||||
|
||||
//Add char list
|
||||
output->addByte(0x64);
|
||||
|
||||
output->addByte(1); // number of worlds
|
||||
|
||||
output->addByte(0); // world id
|
||||
output->addString(g_config.getString(ConfigManager::SERVER_NAME));
|
||||
output->addString(g_config.getString(ConfigManager::IP));
|
||||
output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));
|
||||
output->addByte(0);
|
||||
|
||||
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);
|
||||
output->addString(account.characters[i]);
|
||||
output->addString(g_config.getString(ConfigManager::SERVER_NAME));
|
||||
output->add<uint32_t>(inet_addr(g_config.getString(ConfigManager::IP).c_str()));
|
||||
output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));
|
||||
}
|
||||
|
||||
//Add premium days
|
||||
output->addByte(0);
|
||||
if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
|
||||
output->addByte(1);
|
||||
output->add<uint32_t>(0);
|
||||
output->add<uint16_t>(0xFFFF);
|
||||
}
|
||||
else {
|
||||
output->addByte(account.premiumDays > 0 ? 1 : 0);
|
||||
output->add<uint32_t>(time(nullptr) + (account.premiumDays * 86400));
|
||||
output->add<uint16_t>(account.premiumDays);
|
||||
}
|
||||
|
||||
send(output);
|
||||
@ -118,6 +91,7 @@ void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string&
|
||||
disconnect();
|
||||
}
|
||||
|
||||
|
||||
void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
|
||||
{
|
||||
if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
|
||||
@ -208,15 +182,6 @@ void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
|
||||
return;
|
||||
}
|
||||
|
||||
// read authenticator token and stay logged in flag from last 128 bytes
|
||||
msg.skipBytes((msg.getLength() - 128) - msg.getBufferPosition());
|
||||
if (!Protocol::RSA_decrypt(msg)) {
|
||||
disconnectClient("Invalid authentification token.", version);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string authToken = msg.getString();
|
||||
|
||||
auto thisPtr = std::static_pointer_cast<ProtocolLogin>(shared_from_this());
|
||||
g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountNumber, password, authToken, version)));
|
||||
g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountNumber, password, version)));
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ class ProtocolLogin : public Protocol
|
||||
private:
|
||||
void disconnectClient(const std::string& message, uint16_t version);
|
||||
|
||||
void getCharacterList(uint32_t accountNumber, const std::string& password, const std::string& token, uint16_t version);
|
||||
void getCharacterList(uint32_t accountNumber, const std::string& password, uint16_t version);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -56,7 +56,8 @@ void ServiceManager::stop()
|
||||
for (auto& servicePortIt : acceptors) {
|
||||
try {
|
||||
io_service.post(std::bind(&ServicePort::onStopServer, servicePortIt.second));
|
||||
} catch (boost::system::system_error& e) {
|
||||
}
|
||||
catch (boost::system::system_error& e) {
|
||||
std::cout << "[ServiceManager::stop] Network Error: " << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
@ -114,25 +115,28 @@ void ServicePort::onAccept(Connection_ptr connection, const boost::system::error
|
||||
Service_ptr service = services.front();
|
||||
if (service->is_single_socket()) {
|
||||
connection->accept(service->make_protocol(connection));
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
connection->accept();
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
connection->close(Connection::FORCE_CLOSE);
|
||||
}
|
||||
|
||||
accept();
|
||||
} else if (error != boost::asio::error::operation_aborted) {
|
||||
}
|
||||
else if (error != boost::asio::error::operation_aborted) {
|
||||
if (!pendingStart) {
|
||||
close();
|
||||
pendingStart = true;
|
||||
g_scheduler.addEvent(createSchedulerTask(15000,
|
||||
std::bind(&ServicePort::openAcceptor, std::weak_ptr<ServicePort>(shared_from_this()), serverPort)));
|
||||
std::bind(&ServicePort::openAcceptor, std::weak_ptr<ServicePort>(shared_from_this()), serverPort)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Protocol_ptr ServicePort::make_protocol(bool checksummed, NetworkMessage& msg, const Connection_ptr& connection) const
|
||||
Protocol_ptr ServicePort::make_protocol(NetworkMessage& msg, const Connection_ptr& connection) const
|
||||
{
|
||||
uint8_t protocolID = msg.getByte();
|
||||
for (auto& service : services) {
|
||||
@ -140,9 +144,7 @@ Protocol_ptr ServicePort::make_protocol(bool checksummed, NetworkMessage& msg, c
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((checksummed && service->is_checksummed()) || !service->is_checksummed()) {
|
||||
return service->make_protocol(connection);
|
||||
}
|
||||
return service->make_protocol(connection);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -169,21 +171,23 @@ void ServicePort::open(uint16_t port)
|
||||
try {
|
||||
if (g_config.getBoolean(ConfigManager::BIND_ONLY_GLOBAL_ADDRESS)) {
|
||||
acceptor.reset(new boost::asio::ip::tcp::acceptor(io_service, boost::asio::ip::tcp::endpoint(
|
||||
boost::asio::ip::address(boost::asio::ip::address_v4::from_string(g_config.getString(ConfigManager::IP))), serverPort)));
|
||||
} else {
|
||||
boost::asio::ip::address(boost::asio::ip::address_v4::from_string(g_config.getString(ConfigManager::IP))), serverPort)));
|
||||
}
|
||||
else {
|
||||
acceptor.reset(new boost::asio::ip::tcp::acceptor(io_service, boost::asio::ip::tcp::endpoint(
|
||||
boost::asio::ip::address(boost::asio::ip::address_v4(INADDR_ANY)), serverPort)));
|
||||
boost::asio::ip::address(boost::asio::ip::address_v4(INADDR_ANY)), serverPort)));
|
||||
}
|
||||
|
||||
acceptor->set_option(boost::asio::ip::tcp::no_delay(true));
|
||||
|
||||
accept();
|
||||
} catch (boost::system::system_error& e) {
|
||||
}
|
||||
catch (boost::system::system_error& e) {
|
||||
std::cout << "[ServicePort::open] Error: " << e.what() << std::endl;
|
||||
|
||||
pendingStart = true;
|
||||
g_scheduler.addEvent(createSchedulerTask(15000,
|
||||
std::bind(&ServicePort::openAcceptor, std::weak_ptr<ServicePort>(shared_from_this()), port)));
|
||||
std::bind(&ServicePort::openAcceptor, std::weak_ptr<ServicePort>(shared_from_this()), port)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,7 +201,7 @@ void ServicePort::close()
|
||||
|
||||
bool ServicePort::add_service(const Service_ptr& new_svc)
|
||||
{
|
||||
if (std::any_of(services.begin(), services.end(), [](const Service_ptr& svc) {return svc->is_single_socket();})) {
|
||||
if (std::any_of(services.begin(), services.end(), [](const Service_ptr& svc) {return svc->is_single_socket(); })) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
129
src/server.h
129
src/server.h
@ -27,98 +27,94 @@ class Protocol;
|
||||
|
||||
class ServiceBase
|
||||
{
|
||||
public:
|
||||
virtual bool is_single_socket() const = 0;
|
||||
virtual bool is_checksummed() const = 0;
|
||||
virtual uint8_t get_protocol_identifier() const = 0;
|
||||
virtual const char* get_protocol_name() const = 0;
|
||||
public:
|
||||
virtual bool is_single_socket() const = 0;
|
||||
virtual uint8_t get_protocol_identifier() const = 0;
|
||||
virtual const char* get_protocol_name() const = 0;
|
||||
|
||||
virtual Protocol_ptr make_protocol(const Connection_ptr& c) const = 0;
|
||||
virtual Protocol_ptr make_protocol(const Connection_ptr& c) const = 0;
|
||||
};
|
||||
|
||||
template <typename ProtocolType>
|
||||
class Service final : public ServiceBase
|
||||
{
|
||||
public:
|
||||
bool is_single_socket() const override {
|
||||
return ProtocolType::server_sends_first;
|
||||
}
|
||||
bool is_checksummed() const override {
|
||||
return ProtocolType::use_checksum;
|
||||
}
|
||||
uint8_t get_protocol_identifier() const override {
|
||||
return ProtocolType::protocol_identifier;
|
||||
}
|
||||
const char* get_protocol_name() const override {
|
||||
return ProtocolType::protocol_name();
|
||||
}
|
||||
public:
|
||||
bool is_single_socket() const final {
|
||||
return ProtocolType::server_sends_first;
|
||||
}
|
||||
uint8_t get_protocol_identifier() const final {
|
||||
return ProtocolType::protocol_identifier;
|
||||
}
|
||||
const char* get_protocol_name() const final {
|
||||
return ProtocolType::protocol_name();
|
||||
}
|
||||
|
||||
Protocol_ptr make_protocol(const Connection_ptr& c) const override {
|
||||
return std::make_shared<ProtocolType>(c);
|
||||
}
|
||||
Protocol_ptr make_protocol(const Connection_ptr& c) const final {
|
||||
return std::make_shared<ProtocolType>(c);
|
||||
}
|
||||
};
|
||||
|
||||
class ServicePort : public std::enable_shared_from_this<ServicePort>
|
||||
{
|
||||
public:
|
||||
explicit ServicePort(boost::asio::io_service& io_service) : io_service(io_service) {}
|
||||
~ServicePort();
|
||||
public:
|
||||
explicit ServicePort(boost::asio::io_service& io_service) : io_service(io_service) {}
|
||||
~ServicePort();
|
||||
|
||||
// non-copyable
|
||||
ServicePort(const ServicePort&) = delete;
|
||||
ServicePort& operator=(const ServicePort&) = delete;
|
||||
// non-copyable
|
||||
ServicePort(const ServicePort&) = delete;
|
||||
ServicePort& operator=(const ServicePort&) = delete;
|
||||
|
||||
static void openAcceptor(std::weak_ptr<ServicePort> weak_service, uint16_t port);
|
||||
void open(uint16_t port);
|
||||
void close();
|
||||
bool is_single_socket() const;
|
||||
std::string get_protocol_names() const;
|
||||
static void openAcceptor(std::weak_ptr<ServicePort> weak_service, uint16_t port);
|
||||
void open(uint16_t port);
|
||||
void close();
|
||||
bool is_single_socket() const;
|
||||
std::string get_protocol_names() const;
|
||||
|
||||
bool add_service(const Service_ptr& new_svc);
|
||||
Protocol_ptr make_protocol(bool checksummed, NetworkMessage& msg, const Connection_ptr& connection) const;
|
||||
bool add_service(const Service_ptr& new_svc);
|
||||
Protocol_ptr make_protocol(NetworkMessage& msg, const Connection_ptr& connection) const;
|
||||
|
||||
void onStopServer();
|
||||
void onAccept(Connection_ptr connection, const boost::system::error_code& error);
|
||||
void onStopServer();
|
||||
void onAccept(Connection_ptr connection, const boost::system::error_code& error);
|
||||
|
||||
protected:
|
||||
void accept();
|
||||
protected:
|
||||
void accept();
|
||||
|
||||
boost::asio::io_service& io_service;
|
||||
std::unique_ptr<boost::asio::ip::tcp::acceptor> acceptor;
|
||||
std::vector<Service_ptr> services;
|
||||
boost::asio::io_service& io_service;
|
||||
std::unique_ptr<boost::asio::ip::tcp::acceptor> acceptor;
|
||||
std::vector<Service_ptr> services;
|
||||
|
||||
uint16_t serverPort = 0;
|
||||
bool pendingStart = false;
|
||||
uint16_t serverPort = 0;
|
||||
bool pendingStart = false;
|
||||
};
|
||||
|
||||
class ServiceManager
|
||||
{
|
||||
public:
|
||||
ServiceManager() = default;
|
||||
~ServiceManager();
|
||||
public:
|
||||
ServiceManager() = default;
|
||||
~ServiceManager();
|
||||
|
||||
// non-copyable
|
||||
ServiceManager(const ServiceManager&) = delete;
|
||||
ServiceManager& operator=(const ServiceManager&) = delete;
|
||||
// non-copyable
|
||||
ServiceManager(const ServiceManager&) = delete;
|
||||
ServiceManager& operator=(const ServiceManager&) = delete;
|
||||
|
||||
void run();
|
||||
void stop();
|
||||
void run();
|
||||
void stop();
|
||||
|
||||
template <typename ProtocolType>
|
||||
bool add(uint16_t port);
|
||||
template <typename ProtocolType>
|
||||
bool add(uint16_t port);
|
||||
|
||||
bool is_running() const {
|
||||
return acceptors.empty() == false;
|
||||
}
|
||||
bool is_running() const {
|
||||
return acceptors.empty() == false;
|
||||
}
|
||||
|
||||
protected:
|
||||
void die();
|
||||
protected:
|
||||
void die();
|
||||
|
||||
std::unordered_map<uint16_t, ServicePort_ptr> acceptors;
|
||||
std::unordered_map<uint16_t, ServicePort_ptr> acceptors;
|
||||
|
||||
boost::asio::io_service io_service;
|
||||
boost::asio::deadline_timer death_timer { io_service };
|
||||
bool running = false;
|
||||
boost::asio::io_service io_service;
|
||||
boost::asio::deadline_timer death_timer{ io_service };
|
||||
bool running = false;
|
||||
};
|
||||
|
||||
template <typename ProtocolType>
|
||||
@ -137,13 +133,14 @@ bool ServiceManager::add(uint16_t port)
|
||||
service_port = std::make_shared<ServicePort>(io_service);
|
||||
service_port->open(port);
|
||||
acceptors[port] = service_port;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
service_port = foundServicePort->second;
|
||||
|
||||
if (service_port->is_single_socket() || ProtocolType::server_sends_first) {
|
||||
std::cout << "ERROR: " << ProtocolType::protocol_name() <<
|
||||
" and " << service_port->get_protocol_names() <<
|
||||
" cannot use the same port " << port << '.' << std::endl;
|
||||
" and " << service_port->get_protocol_names() <<
|
||||
" cannot use the same port " << port << '.' << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user