diff --git a/apps/openmw-mp/Networking.cpp b/apps/openmw-mp/Networking.cpp index ed5506820..b78c16642 100644 --- a/apps/openmw-mp/Networking.cpp +++ b/apps/openmw-mp/Networking.cpp @@ -371,6 +371,12 @@ void Networking::Update(RakNet::Packet *packet) myPacket->Read(player); break; } + case ID_GAME_INVENTORY: + { + DEBUG_PRINTF("ID_GAME_INVENTORY\n"); + myPacket->Read(player); + break; + } default: printf("Message with identifier %i has arrived.\n", packet->data[0]); diff --git a/apps/openmw-mp/Player.hpp b/apps/openmw-mp/Player.hpp index 9eecfbf92..09959c9c5 100644 --- a/apps/openmw-mp/Player.hpp +++ b/apps/openmw-mp/Player.hpp @@ -62,6 +62,8 @@ public: unsigned short getLastAttackerID(); virtual ~Player(); +public: + mwmp::Inventory inventorySendBuffer; private: bool handshake; int loaded; diff --git a/apps/openmw-mp/Script/Functions/Items.cpp b/apps/openmw-mp/Script/Functions/Items.cpp index 812854201..8b3a0ae44 100644 --- a/apps/openmw-mp/Script/Functions/Items.cpp +++ b/apps/openmw-mp/Script/Functions/Items.cpp @@ -8,22 +8,30 @@ #include #include +using namespace mwmp; -void ItemFunctions::AddItem(unsigned short pid, const char* itemName, unsigned short count) noexcept +void ItemFunctions::AddItem(unsigned short pid, const char* itemName, unsigned int count, int health) noexcept { Player *player; GET_PLAYER(pid, player,); - LOG_MESSAGE(Log::LOG_WARN, "%s", "stub"); + Item item; + item.refid = itemName; + item.count = count; + item.health = health; + + player->inventorySendBuffer.items.push_back(item); + player->inventorySendBuffer.action = Inventory::ADDITEM; } -void ItemFunctions::EquipItem(unsigned short pid, unsigned short slot, const char *itemName, unsigned short count) noexcept +void ItemFunctions::EquipItem(unsigned short pid, unsigned short slot, const char *itemName, unsigned int count, int health) noexcept { Player *player; GET_PLAYER(pid, player,); player->EquipedItem(slot)->refid = itemName; player->EquipedItem(slot)->count = count; + player->EquipedItem(slot)->health = health; } void ItemFunctions::UnequipItem(unsigned short pid, unsigned short slot) noexcept @@ -53,13 +61,54 @@ bool ItemFunctions::HasItemEquipped(unsigned short pid, const char* itemName) void ItemFunctions::RemoveItem(unsigned short pid, const char* itemName, unsigned short count) noexcept { - LOG_MESSAGE(Log::LOG_WARN, "%s", "stub"); + Player *player; + GET_PLAYER(pid, player,); + + Item item; + item.refid = itemName; + item.count = count; + + player->inventorySendBuffer.items.clear(); + player->inventorySendBuffer.items.push_back(item); + player->inventorySendBuffer.action = Inventory::REMOVEITEM; } void ItemFunctions::GetItemCount(unsigned short pid, const char* itemName) noexcept { LOG_MESSAGE(Log::LOG_WARN, "%s", "stub"); } +const char *ItemFunctions::GetItemName(unsigned short pid, unsigned int i) noexcept +{ + Player *player; + GET_PLAYER(pid, player, ""); + + return player->inventory.items.at(i).refid.c_str(); +} + +int ItemFunctions::GetItemCount2(unsigned short pid, unsigned int i) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + return player->inventory.items.at(i).count; +} + +int ItemFunctions::GetItemHealth(unsigned short pid, unsigned int i) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + return player->inventory.items.at(i).health; +} + +unsigned int ItemFunctions::GetInventorySize(unsigned short pid) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + return player->inventory.count; +} + void ItemFunctions::SendEquipment(unsigned short pid) noexcept { Player *player; @@ -68,3 +117,13 @@ void ItemFunctions::SendEquipment(unsigned short pid) noexcept mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_EQUIPMENT)->Send(player, false); mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_EQUIPMENT)->Send(player, true); } + +void ItemFunctions::SendInventory(unsigned short pid) noexcept +{ + Player *player; + GET_PLAYER(pid, player, ); + std::swap(player->inventory, player->inventorySendBuffer); + mwmp::Networking::Get().GetController()->GetPacket(ID_GAME_INVENTORY)->Send(player, false); + player->inventory = std::move(player->inventorySendBuffer); + player->inventorySendBuffer.items.clear(); +} diff --git a/apps/openmw-mp/Script/Functions/Items.hpp b/apps/openmw-mp/Script/Functions/Items.hpp index 59fcd331f..0a9acf723 100644 --- a/apps/openmw-mp/Script/Functions/Items.hpp +++ b/apps/openmw-mp/Script/Functions/Items.hpp @@ -8,27 +8,38 @@ #define ITEMAPI \ {"AddItem", ItemFunctions::AddItem},\ {"RemoveItem", ItemFunctions::RemoveItem},\ - {"GetItemCount", ItemFunctions::GetItemCount},\ + {"GetItemCount", ItemFunctions::GetItemCount2},\ {"EquipItem", ItemFunctions::EquipItem},\ {"UnequipItem", ItemFunctions::UnequipItem},\ {"GetItemSlot", ItemFunctions::GetItemSlot},\ {"HasItemEquipped", ItemFunctions::HasItemEquipped},\ + {"GetItemName", ItemFunctions::GetItemName},\ + {"GetItemHealth", ItemFunctions::GetItemHealth},\ + {"GetInventorySize", ItemFunctions::GetInventorySize},\ \ - {"SendEquipment", ItemFunctions::SendEquipment}\ - + {"SendEquipment", ItemFunctions::SendEquipment},\ + {"SendInventory", ItemFunctions::SendInventory}\ class ItemFunctions { public: - static void AddItem(unsigned short pid, const char* itemName, unsigned short count) noexcept; + static void AddItem(unsigned short pid, const char* itemName, unsigned int count, int health) noexcept; static void RemoveItem(unsigned short pid, const char* itemName, unsigned short count) noexcept; static void GetItemCount(unsigned short pid, const char* itemName) noexcept; - static void EquipItem(unsigned short pid, unsigned short slot, const char* itemName, unsigned short count) noexcept; + static void EquipItem(unsigned short pid, unsigned short slot, const char* itemName, unsigned int count, int health) noexcept; static void UnequipItem(unsigned short pid, unsigned short slot) noexcept; static bool HasItemEquipped(unsigned short pid, const char* itemName); static const char *GetItemSlot(unsigned short pid, unsigned short slot) noexcept; + static const char *GetItemName(unsigned short pid, unsigned int i) noexcept; + static int GetItemCount2(unsigned short pid, unsigned int i) noexcept; + static int GetItemHealth(unsigned short pid, unsigned int i) noexcept; + static unsigned int GetInventorySize(unsigned short pid) noexcept; + static void SendEquipment(unsigned short pid) noexcept; + static void SendInventory(unsigned short pid) noexcept; +private: + }; #endif //OPENMW_ITEMS_HPP diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index ccb0b74d7..f79dd399d 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -58,11 +58,12 @@ void LocalPlayer::Update() updateDrawStateAndFlags(); updateAttackState(); updateDeadState(); - updateInventory(); + updateEquipped(); updateDynamicStats(); updateAttributes(); updateSkills(); updateLevel(); + updateInventory(); } void LocalPlayer::charGen(int stageFirst, int stageEnd) @@ -355,15 +356,14 @@ void LocalPlayer::updateChar() MWBase::Environment::get().getWindowManager()->getInventoryWindow()->rebuildAvatar(); } -void LocalPlayer::updateInventory(bool forceUpdate) +void LocalPlayer::updateEquipped(bool forceUpdate) { MWWorld::Ptr player = GetPlayerPtr(); - static bool invChanged = false; + static bool equipChanged = false; if (forceUpdate) - invChanged = true; - + equipChanged = true; MWWorld::InventoryStore &invStore = player.getClass().getInventoryStore(player); for (int slot = 0; slot < MWWorld::InventoryStore::Slots; slot++) @@ -371,9 +371,10 @@ void LocalPlayer::updateInventory(bool forceUpdate) MWWorld::ContainerStoreIterator it = invStore.getSlot(slot); if (it != invStore.end() && !::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), EquipedItem(slot)->refid)) { - invChanged = true; + equipChanged = true; EquipedItem(slot)->refid = it->getCellRef().getRefId(); + EquipedItem(slot)->health = it->getCellRef().getCharge(); if (slot == MWWorld::InventoryStore::Slot_CarriedRight) { MWMechanics::WeaponType weaptype; @@ -386,20 +387,101 @@ void LocalPlayer::updateInventory(bool forceUpdate) } else if (it == invStore.end() && !EquipedItem(slot)->refid.empty()) { - invChanged = true; + equipChanged = true; EquipedItem(slot)->refid = ""; EquipedItem(slot)->count = 0; + EquipedItem(slot)->health = 0; } } - if (invChanged) + if (equipChanged) { RakNet::BitStream bs; bs.ResetWritePointer(); GetNetworking()->GetPacket((RakNet::MessageID) ID_GAME_EQUIPMENT)->Packet(&bs, this, true); GetNetworking()->SendData(&bs); - invChanged = false; + equipChanged = false; + } +} + +void LocalPlayer::updateInventory(bool forceUpdate) +{ + static bool invChanged = false; + if (forceUpdate) + invChanged = true; + + MWWorld::Ptr player = GetPlayerPtr(); + MWWorld::InventoryStore &invStore = player.getClass().getInventoryStore(player); + mwmp::Item item; + + if(!invChanged) + for (vector::iterator iter = inventory.items.begin(); iter != inventory.items.end(); ++iter) + { + MWWorld::ContainerStoreIterator result(invStore.begin()); + for (; result != invStore.end(); ++result) + { + item.refid = result->getCellRef().getRefId(); + if(item.refid.find("$dynamic") != string::npos) // skip generated items (self enchanted for e.g.) + continue; + + item.count = result->getRefData().getCount(); + item.health = result->getCellRef().getCharge(); + + if(item == (*iter)) + break; + } + if(result == invStore.end()) + { + invChanged = true; + break; + } + } + if (!invChanged) + for (MWWorld::ContainerStoreIterator iter(invStore.begin()); iter != invStore.end(); ++iter) + { + item.refid = iter->getCellRef().getRefId(); + if (item.refid.find("$dynamic") != string::npos) // skip generated items (self enchanted for e.g.) + continue; + + item.count = iter->getRefData().getCount(); + item.health = iter->getCellRef().getCharge(); + + vector::iterator result = inventory.items.begin(); + + for (; result != inventory.items.end(); result++) + { + if ((*result) == item) + break; + } + + if (result == inventory.items.end()) + { + invChanged = true; + break; + } + } + + if (!invChanged) + return; + + invChanged = false; + + inventory.items.clear(); + for (MWWorld::ContainerStoreIterator iter(invStore.begin()); iter != invStore.end(); ++iter) + { + item.refid = iter->getCellRef().getRefId(); + if (item.refid.find("$dynamic") != string::npos) // skip generated items (self enchanted for e.g.) + continue; + + item.count = iter->getRefData().getCount(); + item.health = iter->getCellRef().getCharge(); + + inventory.items.push_back(item); } + + inventory.count = (unsigned int) inventory.items.size(); + inventory.action = Inventory::UPDATE; + Main::get().getNetworking()->GetPacket(ID_GAME_INVENTORY)->Send(this); } void LocalPlayer::updateAttackState(bool forceUpdate) @@ -664,17 +746,23 @@ void LocalPlayer::setInventory() MWWorld::Ptr ptrPlayer = GetPlayerPtr(); MWWorld::InventoryStore &ptrInventory = ptrPlayer.getClass().getInventoryStore(ptrPlayer); - ptrInventory.clear(); for (int slot = 0; slot < MWWorld::InventoryStore::Slots; slot++) { mwmp::Item *currentItem = EquipedItem(slot); - //printf("Setting currentItem: %s in slot %i\n", currentItem->refid, slot); - if (!currentItem->refid.empty()) { - ptrInventory.equip(slot, ptrInventory.ContainerStore::add(EquipedItem(slot)->refid.c_str(), 1, ptrPlayer), ptrPlayer); + MWWorld::ContainerStoreIterator it = ptrInventory.begin(); + for (; it != ptrInventory.end(); ++it) // find item in inventory + { + if (::Misc::StringUtils::ciEqual(it->getCellRef().getRefId(), currentItem->refid)) + break; + } + if (it == ptrInventory.end()) // if not exists add item + ptrInventory.equip(slot, ptrInventory.ContainerStore::add(EquipedItem(slot)->refid.c_str(), 1, ptrPlayer), ptrPlayer); + else + ptrInventory.equip(slot, it, ptrPlayer); } } } diff --git a/apps/openmw/mwmp/LocalPlayer.hpp b/apps/openmw/mwmp/LocalPlayer.hpp index 30eeb37c3..d0d084165 100644 --- a/apps/openmw/mwmp/LocalPlayer.hpp +++ b/apps/openmw/mwmp/LocalPlayer.hpp @@ -30,6 +30,7 @@ namespace mwmp void updatePosition(bool forceUpdate = false); void updateCell(bool forceUpdate = false); void updateChar(); + void updateEquipped(bool forceUpdate = false); void updateInventory(bool forceUpdate = false); void updateAttackState(bool forceUpdate = false); void updateDeadState(bool forceUpdate = false); diff --git a/apps/openmw/mwmp/Networking.cpp b/apps/openmw/mwmp/Networking.cpp index d14945545..baa6c36dc 100644 --- a/apps/openmw/mwmp/Networking.cpp +++ b/apps/openmw/mwmp/Networking.cpp @@ -261,7 +261,7 @@ void Networking::ReceiveMessage(RakNet::Packet *packet) { if (packet->length == myPacket->headerSize()) { - getLocalPlayer()->updateInventory(true); + getLocalPlayer()->updateEquipped(true); } else { @@ -613,6 +613,56 @@ void Networking::ReceiveMessage(RakNet::Packet *packet) world->setMonth(getLocalPlayer()->month); } } + case ID_GAME_INVENTORY: + { + if (id == myid) + { + if (packet->length == myPacket->headerSize()) + { + printf("ID_GAME_INVENTORY update only\n"); + getLocalPlayer()->updateInventory(true); + GetPacket(ID_GAME_INVENTORY)->Send(getLocalPlayer()); + } + else + { + myPacket->Packet(&bsIn, getLocalPlayer(), false); + MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->getPlayerPtr(); + MWWorld::ContainerStore &conStore = ptr.getClass().getContainerStore(ptr); + if (getLocalPlayer()->inventory.action == Inventory::ADDITEM) + { + for (unsigned int i = 0; i < getLocalPlayer()->inventory.count; i++) + { + mwmp::Item item = getLocalPlayer()->inventory.items[i]; + MWWorld::Ptr itemPtr = *conStore.add(item.refid, item.count, ptr); + if(item.health != -1) + itemPtr.getCellRef().setCharge(item.health); + } + } + else if (getLocalPlayer()->inventory.action == Inventory::REMOVEITEM) + { + for (unsigned int i = 0; i < getLocalPlayer()->inventory.count; i++) + { + mwmp::Item item = getLocalPlayer()->inventory.items[i]; + conStore.remove(item.refid, item.count, ptr); + } + } + else // update + { + conStore.clear(); + for (unsigned int i = 0; i < getLocalPlayer()->inventory.count; i++) + { + mwmp::Item item = getLocalPlayer()->inventory.items[i]; + MWWorld::Ptr itemPtr = *conStore.add(item.refid, item.count, ptr); + if(item.health != -1) + itemPtr.getCellRef().setCharge(item.health); + printf("%s %d %d\n", item.refid.c_str(), item.count, item.health); + } + getLocalPlayer()->setInventory(); // restore equipped items + } + } + } + break; + } default: LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Custom message with identifier %i has arrived in initialization.", packet->data[0]); } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index a5574e106..0edaa8c7f 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -151,7 +151,7 @@ add_component_dir (openmw-mp Packets/PlayerPacket Packets/PacketBaseInfo Packets/PacketPosition Packets/PacketEquipment Packets/PacketAttack Packets/PacketDynamicStats Packets/PacketCell Packets/PacketDrawState Packets/PacketChatMessage Packets/PacketCharGen Packets/PacketAttribute Packets/PacketSkill Packets/PacketLevel Packets/PacketHandshake - Packets/PacketGUIBoxes Packets/PacketClass Packets/PacketTime) + Packets/PacketGUIBoxes Packets/PacketClass Packets/PacketTime Packets/PacketInventory) add_component_dir (fallback fallback validate diff --git a/components/openmw-mp/Base/BasePlayer.hpp b/components/openmw-mp/Base/BasePlayer.hpp index f0dbec72f..19044efb9 100644 --- a/components/openmw-mp/Base/BasePlayer.hpp +++ b/components/openmw-mp/Base/BasePlayer.hpp @@ -32,6 +32,24 @@ namespace mwmp { std::string refid; int count; + int health; + inline bool operator==(const Item& rhs) + { + return refid == rhs.refid && count == rhs.count && health == rhs.health; + } + }; + + struct Inventory + { + std::vector items; + unsigned int count; + enum ACTION_TYPE + { + UPDATE = 0, + ADDITEM, + REMOVEITEM + }; + int action; //0 - FullUpdate, 1 - AddItem, 2 - RemoveItem }; class BasePlayer @@ -62,7 +80,8 @@ namespace mwmp BasePlayer(RakNet::RakNetGUID guid) : guid(guid) { - + inventory.action = 0; + inventory.count = 0; } BasePlayer() @@ -147,6 +166,7 @@ namespace mwmp int month; int day; double hour; + Inventory inventory; protected: ESM::Position pos; @@ -164,7 +184,6 @@ namespace mwmp std::string chatMessage; CGStage stage; std::string passw; - }; } diff --git a/components/openmw-mp/NetworkMessages.hpp b/components/openmw-mp/NetworkMessages.hpp index d6177a7d2..7611ef955 100644 --- a/components/openmw-mp/NetworkMessages.hpp +++ b/components/openmw-mp/NetworkMessages.hpp @@ -30,7 +30,8 @@ enum GameMessages ID_HANDSHAKE, ID_LOADED, ID_GUI_MESSAGEBOX, - ID_GAME_TIME + ID_GAME_TIME, + ID_GAME_INVENTORY }; diff --git a/components/openmw-mp/Packets/PacketEquipment.cpp b/components/openmw-mp/Packets/PacketEquipment.cpp index 48a93103b..28fb1bdfc 100644 --- a/components/openmw-mp/Packets/PacketEquipment.cpp +++ b/components/openmw-mp/Packets/PacketEquipment.cpp @@ -20,5 +20,6 @@ void PacketEquipment::Packet(RakNet::BitStream *bs, BasePlayer *player, bool sen { RW(player->EquipedItem(i)->refid, send); RW(player->EquipedItem(i)->count, send); + RW(player->EquipedItem(i)->health, send); } } diff --git a/components/openmw-mp/Packets/PacketInventory.cpp b/components/openmw-mp/Packets/PacketInventory.cpp new file mode 100644 index 000000000..ece0e3697 --- /dev/null +++ b/components/openmw-mp/Packets/PacketInventory.cpp @@ -0,0 +1,44 @@ +// +// Created by koncord on 22.10.16. +// + +#include +#include "PacketInventory.hpp" + +using namespace std; +using namespace mwmp; + +PacketInventory::PacketInventory(RakNet::RakPeerInterface *peer) : BasePacket(peer) +{ + packetID = ID_GAME_INVENTORY; +} + +void PacketInventory::Packet(RakNet::BitStream *bs, BasePlayer *player, bool send) +{ + BasePacket::Packet(bs, player, send); + + RW(player->inventory.action, send); + if (!send) + player->inventory.items.clear(); + else + player->inventory.count = (unsigned int) (player->inventory.items.size()); + RW(player->inventory.count, send); + for (int i = 0; i < player->inventory.count; i++) + { + Item item; + if (send) + { + item = player->inventory.items[i]; + RW(item.refid, send); + RW(item.count, send); + RW(item.health, send); + } + else + { + RW(item.refid, send); + RW(item.count, send); + RW(item.health, send); + player->inventory.items.push_back(item); + } + } +} diff --git a/components/openmw-mp/Packets/PacketInventory.hpp b/components/openmw-mp/Packets/PacketInventory.hpp new file mode 100644 index 000000000..88ff97f11 --- /dev/null +++ b/components/openmw-mp/Packets/PacketInventory.hpp @@ -0,0 +1,22 @@ +// +// Created by koncord on 22.10.16. +// + +#ifndef OPENMW_PACKETINVENTORY_HPP +#define OPENMW_PACKETINVENTORY_HPP + +#include + +namespace mwmp +{ + class PacketInventory : public BasePacket + { + public: + PacketInventory(RakNet::RakPeerInterface *peer); + + virtual void Packet(RakNet::BitStream *bs, BasePlayer *player, bool send); + }; +} + + +#endif //OPENMW_PACKETINVENTORY_HPP diff --git a/components/openmw-mp/PacketsController.cpp b/components/openmw-mp/PacketsController.cpp index e27f33c4d..1b89bb5ad 100644 --- a/components/openmw-mp/PacketsController.cpp +++ b/components/openmw-mp/PacketsController.cpp @@ -27,6 +27,7 @@ #include "Packets/PacketGUIBoxes.hpp" #include "Packets/PacketTime.hpp" #include "Packets/PacketLoaded.hpp" +#include "Packets/PacketInventory.hpp" #include "PacketsController.hpp" @@ -65,6 +66,7 @@ mwmp::PacketsController::PacketsController(RakNet::RakPeerInterface *peer) AddPacket(&packets, peer); AddPacket(&packets, peer); AddPacket(&packets, peer); + AddPacket(&packets, peer); }