[General] Implement PlayerItemUse packet

Players can no longer unilaterally use items on themselves in their inventory. When they try to use an item, they send a PlayerItemUse packet to the server with the item's details. A serverside script can then check the item and either send the packet back to make the item use go through or drop it.
pull/471/head
David Cernat 6 years ago
parent 888e1dfff8
commit 8df08c7d10

@ -106,13 +106,14 @@ set(PROCESSORS_PLAYER
processors/player/ProcessorPlayerDeath.hpp processors/player/ProcessorPlayerDisposition.hpp
processors/player/ProcessorPlayerEquipment.hpp processors/player/ProcessorPlayerFaction.hpp
processors/player/ProcessorPlayerInput.hpp processors/player/ProcessorPlayerInventory.hpp
processors/player/ProcessorPlayerJournal.hpp processors/player/ProcessorWorldKillCount.hpp
processors/player/ProcessorPlayerLevel.hpp processors/player/ProcessorPlayerMiscellaneous.hpp
processors/player/ProcessorPlayerPosition.hpp processors/player/ProcessorPlayerQuickKeys.hpp
processors/player/ProcessorPlayerRest.hpp processors/player/ProcessorPlayerResurrect.hpp
processors/player/ProcessorPlayerShapeshift.hpp processors/player/ProcessorPlayerSkill.hpp
processors/player/ProcessorPlayerSpeech.hpp processors/player/ProcessorPlayerSpellbook.hpp
processors/player/ProcessorPlayerStatsDynamic.hpp processors/player/ProcessorPlayerTopic.hpp
processors/player/ProcessorPlayerItemUse.hpp processors/player/ProcessorPlayerJournal.hpp
processors/player/ProcessorWorldKillCount.hpp processors/player/ProcessorPlayerLevel.hpp
processors/player/ProcessorPlayerMiscellaneous.hpp processors/player/ProcessorPlayerPosition.hpp
processors/player/ProcessorPlayerQuickKeys.hpp processors/player/ProcessorPlayerRest.hpp
processors/player/ProcessorPlayerResurrect.hpp processors/player/ProcessorPlayerShapeshift.hpp
processors/player/ProcessorPlayerSkill.hpp processors/player/ProcessorPlayerSpeech.hpp
processors/player/ProcessorPlayerSpellbook.hpp processors/player/ProcessorPlayerStatsDynamic.hpp
processors/player/ProcessorPlayerTopic.hpp
)
source_group(tes3mp-server\\processors\\player FILES ${PROCESSORS_PLAYER})

@ -173,6 +173,46 @@ const char *ItemFunctions::GetInventoryItemSoul(unsigned short pid, unsigned int
return player->inventoryChanges.items.at(index).soul.c_str();
}
const char *ItemFunctions::GetUsedItemRefId(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, "");
return player->usedItem.refId.c_str();
}
int ItemFunctions::GetUsedItemCount(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0);
return player->usedItem.count;
}
int ItemFunctions::GetUsedItemCharge(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0);
return player->usedItem.charge;
}
double ItemFunctions::GetUsedItemEnchantmentCharge(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, 0);
return player->usedItem.enchantmentCharge;
}
const char *ItemFunctions::GetUsedItemSoul(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, "");
return player->usedItem.soul.c_str();
}
void ItemFunctions::SendEquipment(unsigned short pid) noexcept
{
Player *player;
@ -200,3 +240,14 @@ void ItemFunctions::SendInventoryChanges(unsigned short pid, bool sendToOtherPla
if (sendToOtherPlayers)
packet->Send(true);
}
void ItemFunctions::SendItemUse(unsigned short pid) noexcept
{
Player *player;
GET_PLAYER(pid, player, );
mwmp::PlayerPacket *packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_ITEM_USE);
packet->setPlayer(player);
packet->Send(false);
}

@ -26,8 +26,15 @@
{"GetInventoryItemEnchantmentCharge", ItemFunctions::GetInventoryItemEnchantmentCharge},\
{"GetInventoryItemSoul", ItemFunctions::GetInventoryItemSoul},\
\
{"GetUsedItemRefId", ItemFunctions::GetUsedItemRefId},\
{"GetUsedItemCount", ItemFunctions::GetUsedItemCount},\
{"GetUsedItemCharge", ItemFunctions::GetUsedItemCharge},\
{"GetUsedItemEnchantmentCharge", ItemFunctions::GetUsedItemEnchantmentCharge},\
{"GetUsedItemSoul", ItemFunctions::GetUsedItemSoul},\
\
{"SendEquipment", ItemFunctions::SendEquipment},\
{"SendInventoryChanges", ItemFunctions::SendInventoryChanges}
{"SendInventoryChanges", ItemFunctions::SendInventoryChanges},\
{"SendItemUse", ItemFunctions::SendItemUse}
class ItemFunctions
{
@ -206,6 +213,46 @@ public:
*/
static const char *GetInventoryItemSoul(unsigned short pid, unsigned int index) noexcept;
/**
* \brief Get the refId of the item last used by a player.
*
* \param pid The player ID.
* \return The refId.
*/
static const char *GetUsedItemRefId(unsigned short pid) noexcept;
/**
* \brief Get the count of the item last used by a player.
*
* \param pid The player ID.
* \return The item count.
*/
static int GetUsedItemCount(unsigned short pid) noexcept;
/**
* \brief Get the charge of the item last used by a player.
*
* \param pid The player ID.
* \return The charge.
*/
static int GetUsedItemCharge(unsigned short pid) noexcept;
/**
* \brief Get the enchantment charge of the item last used by a player.
*
* \param pid The player ID.
* \return The enchantment charge.
*/
static double GetUsedItemEnchantmentCharge(unsigned short pid) noexcept;
/**
* \brief Get the soul of the item last used by a player.
*
* \param pid The player ID.
* \return The soul.
*/
static const char *GetUsedItemSoul(unsigned short pid) noexcept;
/**
* \brief Send a PlayerEquipment packet with a player's equipment.
*
@ -227,6 +274,15 @@ public:
* \return void
*/
static void SendInventoryChanges(unsigned short pid, bool sendToOtherPlayers, bool skipAttachedPlayer) noexcept;
/**
* \brief Send a PlayerItemUse causing a player to use their recorded usedItem.
*
* \param pid The player ID affected.
* \return void
*/
static void SendItemUse(unsigned short pid) noexcept;
private:
};

@ -174,6 +174,7 @@ public:
{"OnPlayerTopic", Function<void, unsigned short>()},
{"OnPlayerDisposition", Function<void, unsigned short>()},
{"OnPlayerBook", Function<void, unsigned short>()},
{"OnPlayerItemUse", Function<void, unsigned short>()},
{"OnPlayerMiscellaneous", Function<void, unsigned short>()},
{"OnPlayerInput", Function<void, unsigned short>()},
{"OnPlayerRest", Function<void, unsigned short>()},

@ -21,6 +21,7 @@
#include "player/ProcessorPlayerEquipment.hpp"
#include "player/ProcessorPlayerFaction.hpp"
#include "player/ProcessorPlayerInventory.hpp"
#include "player/ProcessorPlayerItemUse.hpp"
#include "player/ProcessorPlayerJournal.hpp"
#include "player/ProcessorWorldKillCount.hpp"
#include "player/ProcessorPlayerInput.hpp"
@ -99,6 +100,7 @@ void ProcessorInitializer()
PlayerProcessor::AddProcessor(new ProcessorPlayerEquipment());
PlayerProcessor::AddProcessor(new ProcessorPlayerFaction());
PlayerProcessor::AddProcessor(new ProcessorPlayerInventory());
PlayerProcessor::AddProcessor(new ProcessorPlayerItemUse());
PlayerProcessor::AddProcessor(new ProcessorPlayerJournal());
PlayerProcessor::AddProcessor(new ProcessorWorldKillCount());
PlayerProcessor::AddProcessor(new ProcessorPlayerInput());

@ -0,0 +1,25 @@
#ifndef OPENMW_PROCESSORPLAYERITEMUSE_HPP
#define OPENMW_PROCESSORPLAYERITEMUSE_HPP
#include "../PlayerProcessor.hpp"
namespace mwmp
{
class ProcessorPlayerItemUse : public PlayerProcessor
{
public:
ProcessorPlayerItemUse()
{
BPP_INIT(ID_PLAYER_ITEM_USE)
}
void Do(PlayerPacket &packet, Player &player) override
{
DEBUG_PRINTF(strPacketID.c_str());
Script::Call<Script::CallbackIdentity("OnPlayerItemUse")>(player.getId());
}
};
}
#endif //OPENMW_PROCESSORPLAYERITEMUSE_HPP

@ -116,8 +116,8 @@ add_openmw_dir (mwmp/processors/player ProcessorChatMessage ProcessorGUIMessageB
ProcessorPlayerAttack ProcessorPlayerAttribute ProcessorPlayerBaseInfo ProcessorPlayerBehavior ProcessorPlayerBook
ProcessorPlayerBounty ProcessorPlayerCellChange ProcessorPlayerCellState ProcessorPlayerCharClass ProcessorPlayerCharGen
ProcessorPlayerDeath ProcessorPlayerDisposition ProcessorPlayerEquipment ProcessorPlayerFaction ProcessorPlayerInput
ProcessorPlayerInventory ProcessorPlayerJail ProcessorPlayerJournal ProcessorWorldKillCount ProcessorPlayerLevel
ProcessorPlayerMiscellaneous ProcessorPlayerMomentum ProcessorPlayerPosition ProcessorPlayerQuickKeys
ProcessorPlayerInventory ProcessorPlayerItemUse ProcessorPlayerJail ProcessorPlayerJournal ProcessorWorldKillCount
ProcessorPlayerLevel ProcessorPlayerMiscellaneous ProcessorPlayerMomentum ProcessorPlayerPosition ProcessorPlayerQuickKeys
ProcessorPlayerReputation ProcessorPlayerResurrect ProcessorPlayerShapeshift ProcessorPlayerSkill ProcessorPlayerSpeech
ProcessorPlayerSpellbook ProcessorPlayerStatsDynamic ProcessorPlayerTopic
)

@ -567,7 +567,17 @@ namespace MWGui
ptr = mDragAndDrop->mSourceModel->moveItem(mDragAndDrop->mItem, mDragAndDrop->mDraggedCount, mTradeModel);
}
useItem(ptr);
/*
Start of tes3mp change (major)
Instead of unilaterally using an item, send an ID_PLAYER_ITEM_USE packet and let the server
decide if the item actually gets used
*/
//useItem(ptr);
mwmp::Main::get().getLocalPlayer()->sendItemUse(ptr);
/*
End of tes3mp change (major)
*/
// If item is ingredient or potion don't stop drag and drop to simplify action of taking more than one 1 item
if ((ptr.getTypeName() == typeid(ESM::Potion).name() ||
@ -792,7 +802,17 @@ namespace MWGui
if (!found || selected == cycled)
return;
useItem(model.getItem(cycled).mBase);
/*
Start of tes3mp change (major)
Instead of unilaterally using an item, send an ID_PLAYER_ITEM_USE packet and let the server
decide if the item actually gets used
*/
//useItem(model.getItem(cycled).mBase);
mwmp::Main::get().getLocalPlayer()->sendItemUse(model.getItem(cycled).mBase);
/*
End of tes3mp change (major)
*/
}
void InventoryWindow::rebuildAvatar()

@ -1618,6 +1618,18 @@ void LocalPlayer::sendSelectedSpell(const std::string& newSelectedSpellId)
getNetworking()->getPlayerPacket(ID_PLAYER_MISCELLANEOUS)->Send();
}
void LocalPlayer::sendItemUse(const MWWorld::Ptr& itemPtr)
{
usedItem.refId = itemPtr.getCellRef().getRefId();
usedItem.count = itemPtr.getRefData().getCount();
usedItem.charge = itemPtr.getCellRef().getCharge();
usedItem.enchantmentCharge = itemPtr.getCellRef().getEnchantmentCharge();
usedItem.soul = itemPtr.getCellRef().getSoul();
getNetworking()->getPlayerPacket(ID_PLAYER_ITEM_USE)->setPlayer(this);
getNetworking()->getPlayerPacket(ID_PLAYER_ITEM_USE)->Send();
}
void LocalPlayer::clearCellStates()
{
cellStateChanges.cellStates.clear();

@ -87,6 +87,7 @@ namespace mwmp
void sendWerewolfState(bool isWerewolf);
void sendMarkLocation(const ESM::Cell& newMarkCell, const ESM::Position& newMarkPosition);
void sendSelectedSpell(const std::string& newSelectedSpellId);
void sendItemUse(const MWWorld::Ptr& itemPtr);
void clearCellStates();
void clearCurrentContainer();

@ -360,3 +360,18 @@ void MechanicsHelper::unequipItemsByEffect(const MWWorld::Ptr& ptr, short enchan
}
}
}
MWWorld::Ptr MechanicsHelper::getItemPtrFromStore(const mwmp::Item& item, MWWorld::ContainerStore& store)
{
for (MWWorld::ContainerStoreIterator storeIterator = store.begin(); storeIterator != store.end(); ++storeIterator)
{
if (Misc::StringUtils::ciEqual(item.refId, storeIterator->getCellRef().getRefId()) &&
item.count == storeIterator->getRefData().getCount() &&
item.charge == storeIterator->getCellRef().getCharge() &&
item.enchantmentCharge == storeIterator->getCellRef().getEnchantmentCharge() &&
Misc::StringUtils::ciEqual(item.soul, storeIterator->getCellRef().getSoul()))
{
return *storeIterator;
}
}
}

@ -3,6 +3,8 @@
#include <components/openmw-mp/Base/BaseStructs.hpp>
#include "../mwworld/containerstore.hpp"
#include <osg/Vec3f>
@ -30,6 +32,8 @@ namespace MechanicsHelper
bool doesEffectListContainEffect(const ESM::EffectList& effectList, short effectId, short attributeId = -1, short skillId = -1);
void unequipItemsByEffect(const MWWorld::Ptr& ptr, short enchantmentType, short effectId, short attributeId = -1, short skillId = -1);
MWWorld::Ptr getItemPtrFromStore(const mwmp::Item& item, MWWorld::ContainerStore& store);
}

@ -24,6 +24,7 @@
#include "player/ProcessorPlayerFaction.hpp"
#include "player/ProcessorPlayerInput.hpp"
#include "player/ProcessorPlayerInventory.hpp"
#include "player/ProcessorPlayerItemUse.hpp"
#include "player/ProcessorPlayerJail.hpp"
#include "player/ProcessorPlayerJournal.hpp"
#include "player/ProcessorWorldKillCount.hpp"
@ -123,6 +124,7 @@ void ProcessorInitializer()
PlayerProcessor::AddProcessor(new ProcessorPlayerFaction());
PlayerProcessor::AddProcessor(new ProcessorPlayerInput());
PlayerProcessor::AddProcessor(new ProcessorPlayerInventory());
PlayerProcessor::AddProcessor(new ProcessorPlayerItemUse());
PlayerProcessor::AddProcessor(new ProcessorPlayerJail());
PlayerProcessor::AddProcessor(new ProcessorPlayerJournal());
PlayerProcessor::AddProcessor(new ProcessorWorldKillCount());

@ -0,0 +1,44 @@
#ifndef OPENMW_PROCESSORPLAYERITEMUSE_HPP
#define OPENMW_PROCESSORPLAYERITEMUSE_HPP
#include "apps/openmw/mwbase/environment.hpp"
#include "apps/openmw/mwgui/inventorywindow.hpp"
#include "apps/openmw/mwgui/windowmanagerimp.hpp"
#include "apps/openmw/mwworld/inventorystore.hpp"
#include "../MechanicsHelper.hpp"
#include "../PlayerProcessor.hpp"
namespace mwmp
{
class ProcessorPlayerItemUse : public PlayerProcessor
{
public:
ProcessorPlayerItemUse()
{
BPP_INIT(ID_PLAYER_ITEM_USE)
}
virtual void Do(PlayerPacket &packet, BasePlayer *player)
{
if (!isLocal()) return;
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Received ID_PLAYER_ITEM_USE about LocalPlayer from server");
if (!isRequest())
{
LOG_APPEND(Log::LOG_INFO, "- refId: %s, count: %i, charge: %f, enchantmentCharge: %f, soul: %s",
player->usedItem.refId.c_str(), player->usedItem.count, player->usedItem.charge,
player->usedItem.enchantmentCharge, player->usedItem.soul.c_str());
MWWorld::Ptr &playerPtr = MWBase::Environment::get().getWorld()->getPlayerPtr();
MWWorld::InventoryStore &inventoryStore = playerPtr.getClass().getInventoryStore(playerPtr);
MWWorld::Ptr &itemPtr = MechanicsHelper::getItemPtrFromStore(player->usedItem, inventoryStore);
MWBase::Environment::get().getWindowManager()->getInventoryWindow()->useItem(itemPtr);
}
}
};
}
#endif //OPENMW_PROCESSORPLAYERITEMUSE_HPP

@ -1,9 +1,9 @@
#ifndef OPENMW_PROCESSORWORLDTIME_HPP
#define OPENMW_PROCESSORWORLDTIME_HPP
#include <apps/openmw/mwbase/world.hpp>
#include <apps/openmw/mwbase/environment.hpp>
#include "../WorldstateProcessor.hpp"
namespace mwmp

@ -181,10 +181,11 @@ add_component_dir (openmw-mp/Packets/Player
PacketPlayerBaseInfo PacketPlayerCharGen PacketPlayerActiveSkills PacketPlayerAnimFlags PacketPlayerAnimPlay
PacketPlayerAttack PacketPlayerAttribute PacketPlayerBehavior PacketPlayerBook PacketPlayerBounty
PacketPlayerCellChange PacketPlayerCellState PacketPlayerClass PacketPlayerDeath PacketPlayerEquipment
PacketPlayerFaction PacketPlayerInput PacketPlayerInventory PacketPlayerJail PacketPlayerJournal
PacketWorldKillCount PacketPlayerLevel PacketPlayerMiscellaneous PacketPlayerMomentum PacketPlayerPosition
PacketPlayerQuickKeys PacketPlayerReputation PacketPlayerRest PacketPlayerResurrect PacketPlayerShapeshift
PacketPlayerSkill PacketPlayerSpeech PacketPlayerSpellbook PacketPlayerStatsDynamic PacketPlayerTopic
PacketPlayerFaction PacketPlayerInput PacketPlayerInventory PacketPlayerItemUse PacketPlayerJail
PacketPlayerJournal PacketWorldKillCount PacketPlayerLevel PacketPlayerMiscellaneous PacketPlayerMomentum
PacketPlayerPosition PacketPlayerQuickKeys PacketPlayerReputation PacketPlayerRest PacketPlayerResurrect
PacketPlayerShapeshift PacketPlayerSkill PacketPlayerSpeech PacketPlayerSpellbook PacketPlayerStatsDynamic
PacketPlayerTopic
)
add_component_dir (openmw-mp/Packets/Object

@ -324,6 +324,8 @@ namespace mwmp
ESM::Position markPosition;
std::string selectedSpellId;
mwmp::Item usedItem;
bool isReceivingQuickKeys;
bool isPlayingAnimation;
bool diedSinceArrestAttempt;

@ -22,6 +22,7 @@
#include "../Packets/Player/PacketPlayerFaction.hpp"
#include "../Packets/Player/PacketPlayerInput.hpp"
#include "../Packets/Player/PacketPlayerInventory.hpp"
#include "../Packets/Player/PacketPlayerItemUse.hpp"
#include "../Packets/Player/PacketPlayerJail.hpp"
#include "../Packets/Player/PacketPlayerJournal.hpp"
#include "../Packets/Player/PacketWorldKillCount.hpp"
@ -77,6 +78,7 @@ mwmp::PlayerPacketController::PlayerPacketController(RakNet::RakPeerInterface *p
AddPacket<PacketPlayerFaction>(&packets, peer);
AddPacket<PacketPlayerInput>(&packets, peer);
AddPacket<PacketPlayerInventory>(&packets, peer);
AddPacket<PacketPlayerItemUse>(&packets, peer);
AddPacket<PacketPlayerJail>(&packets, peer);
AddPacket<PacketPlayerJournal>(&packets, peer);
AddPacket<PacketWorldKillCount>(&packets, peer);

@ -109,7 +109,9 @@ enum GameMessages
ID_WORLD_COLLISION_OVERRIDE,
ID_WORLD_MAP,
ID_WORLD_TIME,
ID_WORLD_WEATHER
ID_WORLD_WEATHER,
ID_PLAYER_ITEM_USE
};
enum OrderingChannel

@ -0,0 +1,21 @@
#include "PacketPlayerItemUse.hpp"
#include <components/openmw-mp/NetworkMessages.hpp>
using namespace mwmp;
PacketPlayerItemUse::PacketPlayerItemUse(RakNet::RakPeerInterface *peer) : PlayerPacket(peer)
{
packetID = ID_PLAYER_ITEM_USE;
}
void PacketPlayerItemUse::Packet(RakNet::BitStream *bs, bool send)
{
PlayerPacket::Packet(bs, send);
RW(player->usedItem.refId, send, true);
RW(player->usedItem.count, send);
RW(player->usedItem.charge, send);
RW(player->usedItem.enchantmentCharge, send);
RW(player->usedItem.soul, send, true);
}

@ -0,0 +1,17 @@
#ifndef OPENMW_PACKETPLAYERITEMUSE_HPP
#define OPENMW_PACKETPLAYERITEMUSE_HPP
#include <components/openmw-mp/Packets/Player/PlayerPacket.hpp>
namespace mwmp
{
class PacketPlayerItemUse : public PlayerPacket
{
public:
PacketPlayerItemUse(RakNet::RakPeerInterface *peer);
virtual void Packet(RakNet::BitStream *bs, bool send);
};
}
#endif //OPENMW_PACKETPLAYERITEMUSE_HPP
Loading…
Cancel
Save