Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- * The Forgotten Server - a free and open-source MMORPG server emulator
- * Copyright (C) 2015 Mark Samman <mark.samman@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
- #include "otpch.h"
- #include <boost/range/adaptor/reversed.hpp>
- #include "protocolgamebase.h"
- #include "game.h"
- #include "iologindata.h"
- #include "tile.h"
- #include "outputmessage.h"
- extern Game g_game;
- void ProtocolGameBase::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(std::move(output));
- }
- void ProtocolGameBase::AddOutfit(NetworkMessage& msg, const Outfit_t& outfit)
- {
- msg.add<uint16_t>(outfit.lookType);
- if (outfit.lookType != 0) {
- msg.addByte(outfit.lookHead);
- msg.addByte(outfit.lookBody);
- msg.addByte(outfit.lookLegs);
- msg.addByte(outfit.lookFeet);
- msg.addByte(outfit.lookAddons);
- } else {
- msg.addItemId(outfit.lookTypeEx);
- }
- msg.add<uint16_t>(outfit.lookMount);
- }
- void ProtocolGameBase::checkCreatureAsKnown(uint32_t id, bool& known, uint32_t& removedKnown)
- {
- auto result = knownCreatureSet.insert(id);
- if (!result.second) {
- known = true;
- return;
- }
- known = false;
- if (knownCreatureSet.size() > 1300) {
- // Look for a creature to remove
- for (std::unordered_set<uint32_t>::iterator it = knownCreatureSet.begin(), end = knownCreatureSet.end(); it != end; it) {
- Creature* creature = g_game.getCreatureByID(*it);
- if (!canSee(creature)) {
- removedKnown = *it;
- knownCreatureSet.erase(it);
- return;
- }
- }
- // Bad situation. Let's just remove anyone.
- std::unordered_set<uint32_t>::iterator it = knownCreatureSet.begin();
- if (*it == id) {
- it;
- }
- removedKnown = *it;
- knownCreatureSet.erase(it);
- } else {
- removedKnown = 0;
- }
- }
- void ProtocolGameBase::AddCreature(NetworkMessage& msg, const Creature* creature, bool known, uint32_t remove)
- {
- CreatureType_t creatureType = creature->getType();
- const Player* otherPlayer = creature->getPlayer();
- if (known) {
- msg.add<uint16_t>(0x62);
- msg.add<uint32_t>(creature->getID());
- } else {
- msg.add<uint16_t>(0x61);
- msg.add<uint32_t>(remove);
- msg.add<uint32_t>(creature->getID());
- msg.addByte(creatureType);
- msg.addString(creature->getName());
- }
- if (creature->isHealthHidden()) {
- msg.addByte(0x00);
- } else {
- msg.addByte(std::ceil((static_cast<double>(creature->getHealth()) / std::max<int32_t>(creature->getMaxHealth(), 1)) * 100));
- }
- msg.addByte(creature->getDirection());
- if (!creature->isInGhostMode() && !creature->isInvisible()) {
- AddOutfit(msg, creature->getCurrentOutfit());
- } else {
- static Outfit_t outfit;
- AddOutfit(msg, outfit);
- }
- LightInfo lightInfo;
- creature->getCreatureLight(lightInfo);
- msg.addByte(player->isAccessPlayer() ? 0xFF : lightInfo.level);
- msg.addByte(lightInfo.color);
- msg.add<uint16_t>(creature->getStepSpeed() / 2);
- msg.addByte(player->getSkullClient(creature));
- msg.addByte(player->getPartyShield(otherPlayer));
- if (!known) {
- msg.addByte(player->getGuildEmblem(otherPlayer));
- }
- if (creatureType == CREATURETYPE_MONSTER) {
- const Creature* master = creature->getMaster();
- if (master) {
- const Player* masterPlayer = master->getPlayer();
- if (masterPlayer) {
- if (masterPlayer == player) {
- creatureType = CREATURETYPE_SUMMON_OWN;
- } else {
- creatureType = CREATURETYPE_SUMMON_OTHERS;
- }
- }
- }
- }
- msg.addByte(creatureType); // Type (for summons)
- msg.addByte(creature->getSpeechBubble());
- msg.addByte(0xFF); // MARK_UNMARKED
- if (otherPlayer) {
- msg.add<uint16_t>(otherPlayer->getHelpers());
- } else {
- msg.add<uint16_t>(0x00);
- }
- msg.addByte(player->canWalkthroughEx(creature) ? 0x00 : 0x01);
- }
- void ProtocolGameBase::AddPlayerStats(NetworkMessage& msg)
- {
- msg.addByte(0xA0);
- msg.add<uint16_t>(std::min<int32_t>(player->getHealth(), std::numeric_limits<uint16_t>::max()));
- msg.add<uint16_t>(std::min<int32_t>(player->getPlayerInfo(PLAYERINFO_MAXHEALTH), std::numeric_limits<uint16_t>::max()));
- msg.add<uint32_t>(player->getFreeCapacity());
- msg.add<uint32_t>(player->getCapacity());
- msg.add<uint64_t>(player->getExperience());
- msg.add<uint16_t>(player->getLevel());
- msg.addByte(player->getPlayerInfo(PLAYERINFO_LEVELPERCENT));
- msg.addDouble(0, 3); // experience bonus
- msg.add<uint16_t>(std::min<int32_t>(player->getMana(), std::numeric_limits<uint16_t>::max()));
- msg.add<uint16_t>(std::min<int32_t>(player->getPlayerInfo(PLAYERINFO_MAXMANA), 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->getPlayerInfo(PLAYERINFO_MAGICLEVELPERCENT));
- 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>(player->getOfflineTrainingTime() / 60 / 1000);
- }
- void ProtocolGameBase::AddPlayerSkills(NetworkMessage& msg)
- {
- msg.addByte(0xA1);
- for (uint8_t i = SKILL_FIRST; i <= SKILL_LAST; i) {
- msg.add<uint16_t>(std::min<int32_t>(player->getSkillLevel(i), std::numeric_limits<uint16_t>::max()));
- msg.add<uint16_t>(player->getBaseSkill(i));
- msg.addByte(player->getSkillPercent(i));
- }
- }
- void ProtocolGameBase::AddWorldLight(NetworkMessage& msg, const LightInfo& lightInfo)
- {
- msg.addByte(0x82);
- msg.addByte((player->isAccessPlayer() ? 0xFF : lightInfo.level));
- msg.addByte(lightInfo.color);
- }
- void ProtocolGameBase::AddCreatureLight(NetworkMessage& msg, const Creature* creature)
- {
- LightInfo lightInfo;
- creature->getCreatureLight(lightInfo);
- msg.addByte(0x8D);
- msg.add<uint32_t>(creature->getID());
- msg.addByte((player->isAccessPlayer() ? 0xFF : lightInfo.level));
- msg.addByte(lightInfo.color);
- }
- bool ProtocolGameBase::canSee(const Creature* c) const
- {
- if (!c || !player || c->isRemoved()) {
- return false;
- }
- if (!player->canSeeCreature(c)) {
- return false;
- }
- return canSee(c->getPosition());
- }
- bool ProtocolGameBase::canSee(const Position& pos) const
- {
- return canSee(pos.x, pos.y, pos.z);
- }
- bool ProtocolGameBase::canSee(int32_t x, int32_t y, int32_t z) const
- {
- if (!player) {
- return false;
- }
- const Position& myPos = player->getPosition();
- if (myPos.z <= 7) {
- //we are on ground level or above (7 -> 0)
- //view is from 7 -> 0
- if (z > 7) {
- return false;
- }
- } else if (myPos.z >= 8) {
- //we are underground (8 -> 15)
- //view is /- 2 from the floor we stand on
- if (std::abs(myPos.getZ() - z) > 2) {
- return false;
- }
- }
- //negative offset means that the action taken place is on a lower floor than ourself
- int32_t offsetz = myPos.getZ() - z;
- if ((x >= myPos.getX() - 8 offsetz) && (x <= myPos.getX() 9 offsetz) &&
- (y >= myPos.getY() - 6 offsetz) && (y <= myPos.getY() 7 offsetz)) {
- return true;
- }
- return false;
- }
- //tile
- void ProtocolGameBase::RemoveTileThing(NetworkMessage& msg, const Position& pos, uint32_t stackpos)
- {
- if (stackpos >= 10) {
- return;
- }
- msg.addByte(0x6C);
- msg.addPosition(pos);
- msg.addByte(stackpos);
- }
- void ProtocolGameBase::sendUpdateTile(const Tile* tile, const Position& pos)
- {
- if (!canSee(pos)) {
- return;
- }
- NetworkMessage msg;
- msg.addByte(0x69);
- msg.addPosition(pos);
- if (tile) {
- GetTileDescription(tile, msg);
- msg.addByte(0x00);
- msg.addByte(0xFF);
- } else {
- msg.addByte(0x01);
- msg.addByte(0xFF);
- }
- writeToOutputBuffer(msg);
- }
- void ProtocolGameBase::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 {
- count = 0;
- }
- const TileItemVector* items = tile->getItemList();
- if (items) {
- for (auto it = items->getBeginTopItem(), end = items->getEndTopItem(); it != end; it) {
- msg.addItem(*it);
- if (count == 10) {
- return;
- }
- }
- }
- const CreatureVector* creatures = tile->getCreatures();
- if (creatures) {
- for (const Creature* creature : boost::adaptors::reverse(*creatures)) {
- if (!player->canSeeCreature(creature)) {
- continue;
- }
- bool known;
- uint32_t removedKnown;
- checkCreatureAsKnown(creature->getID(), known, removedKnown);
- AddCreature(msg, creature, known, removedKnown);
- if (count == 10) {
- return;
- }
- }
- }
- if (items) {
- for (auto it = items->getBeginDownItem(), end = items->getEndDownItem(); it != end; it) {
- msg.addItem(*it);
- if (count == 10) {
- return;
- }
- }
- }
- }
- void ProtocolGameBase::GetMapDescription(int32_t x, int32_t y, int32_t z, int32_t width, int32_t height, NetworkMessage& msg)
- {
- int32_t skip = -1;
- int32_t startz, endz, zstep;
- if (z > 7) {
- startz = z - 2;
- endz = std::min<int32_t>(MAP_MAX_LAYERS - 1, z 2);
- zstep = 1;
- } else {
- startz = 7;
- endz = 0;
- zstep = -1;
- }
- for (int32_t nz = startz; nz != endz zstep; nz = zstep) {
- GetFloorDescription(msg, x, y, nz, width, height, z - nz, skip);
- }
- if (skip >= 0) {
- msg.addByte(skip);
- msg.addByte(0xFF);
- }
- }
- void ProtocolGameBase::GetFloorDescription(NetworkMessage& msg, int32_t x, int32_t y, int32_t z, int32_t width, int32_t height, int32_t offset, int32_t& skip)
- {
- for (int32_t nx = 0; nx < width; nx) {
- for (int32_t ny = 0; ny < height; ny) {
- Tile* tile = g_game.map.getTile(x nx offset, y ny offset, z);
- if (tile) {
- if (skip >= 0) {
- msg.addByte(skip);
- msg.addByte(0xFF);
- }
- skip = 0;
- GetTileDescription(tile, msg);
- } else if (skip == 0xFE) {
- msg.addByte(0xFF);
- msg.addByte(0xFF);
- skip = -1;
- } else {
- skip;
- }
- }
- }
- }
- void ProtocolGameBase::sendContainer(uint8_t cid, const Container* container, bool hasParent, uint16_t firstIndex)
- {
- NetworkMessage msg;
- msg.addByte(0x6E);
- msg.addByte(cid);
- if (container->getID() == ITEM_BROWSEFIELD) {
- msg.addItem(1987, 1);
- msg.addString("Browse Field");
- } else {
- msg.addItem(container);
- msg.addString(container->getName());
- }
- msg.addByte(container->capacity());
- msg.addByte(hasParent ? 0x01 : 0x00);
- msg.addByte(container->isUnlocked() ? 0x01 : 0x00); // Drag and drop
- msg.addByte(container->hasPagination() ? 0x01 : 0x00); // Pagination
- uint32_t containerSize = container->size();
- msg.add<uint16_t>(containerSize);
- msg.add<uint16_t>(firstIndex);
- if (firstIndex < containerSize) {
- uint8_t itemsToSend = std::min<uint32_t>(std::min<uint32_t>(container->capacity(), containerSize - firstIndex), std::numeric_limits<uint8_t>::max());
- msg.addByte(itemsToSend);
- for (ItemDeque::const_iterator it = container->getItemList().begin() firstIndex, end = it itemsToSend; it != end; it) {
- msg.addItem(*it);
- }
- } else {
- msg.addByte(0x00);
- }
- writeToOutputBuffer(msg);
- }
- void ProtocolGameBase::sendChannel(uint16_t channelId, const std::string& channelName, const UsersMap* channelUsers, const InvitedMap* invitedUsers)
- {
- NetworkMessage msg;
- msg.addByte(0xAC);
- msg.add<uint16_t>(channelId);
- msg.addString(channelName);
- if (channelUsers) {
- msg.add<uint16_t>(channelUsers->size());
- for (const auto& it : *channelUsers) {
- msg.addString(it.second->getName());
- }
- } else {
- msg.add<uint16_t>(0x00);
- }
- if (invitedUsers) {
- msg.add<uint16_t>(invitedUsers->size());
- for (const auto& it : *invitedUsers) {
- msg.addString(it.second->getName());
- }
- } else {
- msg.add<uint16_t>(0x00);
- }
- writeToOutputBuffer(msg);
- }
- void ProtocolGameBase::sendMagicEffect(const Position& pos, uint8_t type)
- {
- if (!canSee(pos)) {
- return;
- }
- NetworkMessage msg;
- msg.addByte(0x83);
- msg.addPosition(pos);
- msg.addByte(type);
- writeToOutputBuffer(msg);
- }
- void ProtocolGameBase::sendAddCreature(const Creature* creature, const Position& pos, int32_t stackpos, bool isLogin)
- {
- if (!canSee(pos)) {
- return;
- }
- if (creature != player) {
- if (stackpos != -1) {
- NetworkMessage msg;
- msg.addByte(0x6A);
- msg.addPosition(pos);
- msg.addByte(stackpos);
- bool known;
- uint32_t removedKnown;
- checkCreatureAsKnown(creature->getID(), known, removedKnown);
- AddCreature(msg, creature, known, removedKnown);
- writeToOutputBuffer(msg);
- }
- if (isLogin) {
- sendMagicEffect(pos, CONST_ME_TELEPORT);
- }
- return;
- }
- NetworkMessage msg;
- msg.addByte(0x17);
- msg.add<uint32_t>(player->getID());
- msg.add<uint16_t>(0x32); // beat duration (50)
- msg.addDouble(Creature::speedA, 3);
- msg.addDouble(Creature::speedB, 3);
- msg.addDouble(Creature::speedC, 3);
- // can report bugs?
- if (player->getAccountType() >= ACCOUNT_TYPE_TUTOR) {
- msg.addByte(0x01);
- } else {
- msg.addByte(0x00);
- }
- msg.addByte(0x00); // can change pvp framing option
- msg.addByte(0x00); // expert mode button enabled
- writeToOutputBuffer(msg);
- sendPendingStateEntered();
- sendEnterWorld();
- sendMapDescription(pos);
- if (isLogin) {
- sendMagicEffect(pos, CONST_ME_TELEPORT);
- }
- sendInventoryItem(CONST_SLOT_HEAD, player->getInventoryItem(CONST_SLOT_HEAD));
- sendInventoryItem(CONST_SLOT_NECKLACE, player->getInventoryItem(CONST_SLOT_NECKLACE));
- sendInventoryItem(CONST_SLOT_BACKPACK, player->getInventoryItem(CONST_SLOT_BACKPACK));
- sendInventoryItem(CONST_SLOT_ARMOR, player->getInventoryItem(CONST_SLOT_ARMOR));
- sendInventoryItem(CONST_SLOT_RIGHT, player->getInventoryItem(CONST_SLOT_RIGHT));
- sendInventoryItem(CONST_SLOT_LEFT, player->getInventoryItem(CONST_SLOT_LEFT));
- sendInventoryItem(CONST_SLOT_LEGS, player->getInventoryItem(CONST_SLOT_LEGS));
- sendInventoryItem(CONST_SLOT_FEET, player->getInventoryItem(CONST_SLOT_FEET));
- sendInventoryItem(CONST_SLOT_RING, player->getInventoryItem(CONST_SLOT_RING));
- sendInventoryItem(CONST_SLOT_AMMO, player->getInventoryItem(CONST_SLOT_AMMO));
- sendStats();
- sendSkills();
- //gameworld light-settings
- LightInfo lightInfo;
- g_game.getWorldLightInfo(lightInfo);
- sendWorldLight(lightInfo);
- //player light level
- sendCreatureLight(creature);
- const std::forward_list<VIPEntry>& vipEntries = IOLoginData::getVIPEntries(player->getAccount());
- if (player->isAccessPlayer()) {
- for (const VIPEntry& entry : vipEntries) {
- VipStatus_t vipStatus;
- Player* vipPlayer = g_game.getPlayerByGUID(entry.guid);
- if (!vipPlayer) {
- vipStatus = VIPSTATUS_OFFLINE;
- } else {
- vipStatus = VIPSTATUS_ONLINE;
- }
- sendVIP(entry.guid, entry.name, entry.description, entry.icon, entry.notify, vipStatus);
- }
- } else {
- for (const VIPEntry& entry : vipEntries) {
- VipStatus_t vipStatus;
- Player* vipPlayer = g_game.getPlayerByGUID(entry.guid);
- if (!vipPlayer || vipPlayer->isInGhostMode()) {
- vipStatus = VIPSTATUS_OFFLINE;
- } else {
- vipStatus = VIPSTATUS_ONLINE;
- }
- sendVIP(entry.guid, entry.name, entry.description, entry.icon, entry.notify, vipStatus);
- }
- }
- sendBasicData();
- player->sendIcons();
- }
- void ProtocolGameBase::sendStats()
- {
- NetworkMessage msg;
- AddPlayerStats(msg);
- writeToOutputBuffer(msg);
- }
- void ProtocolGameBase::sendBasicData()
- {
- NetworkMessage msg;
- msg.addByte(0x9F);
- msg.addByte(player->isPremium() ? 0x01 : 0x00);
- msg.add<uint32_t>(std::numeric_limits<uint32_t>::max());
- msg.addByte(player->getVocation()->getClientId());
- msg.add<uint16_t>(0x00);
- writeToOutputBuffer(msg);
- }
- void ProtocolGameBase::sendPendingStateEntered()
- {
- NetworkMessage msg;
- msg.addByte(0x0A);
- writeToOutputBuffer(msg);
- }
- void ProtocolGameBase::sendEnterWorld()
- {
- NetworkMessage msg;
- msg.addByte(0x0F);
- writeToOutputBuffer(msg);
- }
- void ProtocolGameBase::sendInventoryItem(slots_t slot, const Item* item)
- {
- NetworkMessage msg;
- if (item) {
- msg.addByte(0x78);
- msg.addByte(slot);
- msg.addItem(item);
- } else {
- msg.addByte(0x79);
- msg.addByte(slot);
- }
- writeToOutputBuffer(msg);
- }
- void ProtocolGameBase::sendSkills()
- {
- NetworkMessage msg;
- AddPlayerSkills(msg);
- writeToOutputBuffer(msg);
- }
- void ProtocolGameBase::sendCreatureLight(const Creature* creature)
- {
- if (!canSee(creature)) {
- return;
- }
- NetworkMessage msg;
- AddCreatureLight(msg, creature);
- writeToOutputBuffer(msg);
- }
- void ProtocolGameBase::sendWorldLight(const LightInfo& lightInfo)
- {
- NetworkMessage msg;
- AddWorldLight(msg, lightInfo);
- writeToOutputBuffer(msg);
- }
- void ProtocolGameBase::sendMapDescription(const Position& pos)
- {
- NetworkMessage msg;
- msg.addByte(0x64);
- msg.addPosition(player->getPosition());
- GetMapDescription(pos.x - 8, pos.y - 6, pos.z, 18, 14, msg);
- writeToOutputBuffer(msg);
- }
- void ProtocolGameBase::sendVIP(uint32_t guid, const std::string& name, const std::string& description, uint32_t icon, bool notify, VipStatus_t status)
- {
- NetworkMessage msg;
- msg.addByte(0xD2);
- msg.add<uint32_t>(guid);
- msg.addString(name);
- msg.addString(description);
- msg.add<uint32_t>(std::min<uint32_t>(10, icon));
- msg.addByte(notify ? 0x01 : 0x00);
- msg.addByte(status);
- writeToOutputBuffer(msg);
- }
- void ProtocolGameBase::sendCancelWalk()
- {
- NetworkMessage msg;
- msg.addByte(0xB5);
- msg.addByte(player->getDirection());
- writeToOutputBuffer(msg);
- }
- void ProtocolGameBase::sendPing()
- {
- NetworkMessage msg;
- msg.addByte(0x1D);
- writeToOutputBuffer(msg, false);
- }
- void ProtocolGameBase::sendPingBack()
- {
- NetworkMessage msg;
- msg.addByte(0x1E);
- writeToOutputBuffer(msg, false);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement