From 8c47d63b08b7210db424f5d94ebfce2f7d503201 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Mon, 23 Oct 2017 20:22:29 +0300 Subject: [PATCH 01/29] [General] Update version to 0.6.2 --- README.md | 2 +- components/openmw-mp/Version.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6a9dec268..3e4df6472 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ TES3MP TES3MP is a project aiming to add multiplayer functionality to [OpenMW](https://github.com/OpenMW/openmw), a free and open source recreation of the popular Bethesda Softworks game "The Elder Scrolls III: Morrowind". -* Version: 0.6.1 +* Version: 0.6.2 * License: GPLv3 (see docs/license/GPL3.txt for more information) Font Licenses: diff --git a/components/openmw-mp/Version.hpp b/components/openmw-mp/Version.hpp index 10aba5c55..09cd8ab43 100644 --- a/components/openmw-mp/Version.hpp +++ b/components/openmw-mp/Version.hpp @@ -5,7 +5,7 @@ #ifndef OPENMW_VERSION_HPP #define OPENMW_VERSION_HPP -#define TES3MP_VERSION "0.6.1" +#define TES3MP_VERSION "0.6.2" #define TES3MP_PROTO_VERSION 7 #define TES3MP_DEFAULT_PASSW "SuperPassword" From 50d5fffb7feab547f4c9714f5c5c43385c1e7d5a Mon Sep 17 00:00:00 2001 From: David Cernat Date: Wed, 25 Oct 2017 07:21:00 +0300 Subject: [PATCH 02/29] [General] Add and implement PlayerQuickKeys packet --- apps/openmw-mp/CMakeLists.txt | 10 +- apps/openmw-mp/Script/Functions/GUI.cpp | 71 +++++++++++++++ apps/openmw-mp/Script/Functions/GUI.hpp | 91 +++++++++++++++++-- apps/openmw-mp/Script/Functions/Spells.hpp | 32 +++---- apps/openmw-mp/Script/ScriptFunctions.hpp | 1 + .../processors/ProcessorInitializer.cpp | 2 + .../player/ProcessorPlayerQuickKeys.hpp | 26 ++++++ apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwbase/windowmanager.hpp | 10 ++ apps/openmw/mwgui/quickkeysmenu.cpp | 86 ++++++++++++++++++ apps/openmw/mwgui/quickkeysmenu.hpp | 20 ++++ apps/openmw/mwgui/windowmanagerimp.cpp | 30 ++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 10 ++ apps/openmw/mwmp/LocalPlayer.cpp | 70 ++++++++++++++ apps/openmw/mwmp/LocalPlayer.hpp | 2 + .../mwmp/processors/ProcessorInitializer.cpp | 2 + .../player/ProcessorPlayerQuickKeys.hpp | 32 +++++++ components/CMakeLists.txt | 6 +- components/openmw-mp/Base/BasePlayer.hpp | 24 +++++ .../Controllers/PlayerPacketController.cpp | 2 + components/openmw-mp/NetworkMessages.hpp | 1 + .../Packets/Player/PacketPlayerQuickKeys.cpp | 40 ++++++++ .../Packets/Player/PacketPlayerQuickKeys.hpp | 17 ++++ 23 files changed, 556 insertions(+), 33 deletions(-) create mode 100644 apps/openmw-mp/processors/player/ProcessorPlayerQuickKeys.hpp create mode 100644 apps/openmw/mwmp/processors/player/ProcessorPlayerQuickKeys.hpp create mode 100644 components/openmw-mp/Packets/Player/PacketPlayerQuickKeys.cpp create mode 100644 components/openmw-mp/Packets/Player/PacketPlayerQuickKeys.hpp diff --git a/apps/openmw-mp/CMakeLists.txt b/apps/openmw-mp/CMakeLists.txt index fc9ee0527..1d4386511 100644 --- a/apps/openmw-mp/CMakeLists.txt +++ b/apps/openmw-mp/CMakeLists.txt @@ -130,11 +130,11 @@ set(PROCESSORS_PLAYER processors/player/ProcessorPlayerFaction.hpp processors/player/ProcessorPlayerInventory.hpp processors/player/ProcessorPlayerJournal.hpp processors/player/ProcessorPlayerKillCount.hpp processors/player/ProcessorPlayerLevel.hpp processors/player/ProcessorPlayerMap.hpp - processors/player/ProcessorPlayerPosition.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/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}) diff --git a/apps/openmw-mp/Script/Functions/GUI.cpp b/apps/openmw-mp/Script/Functions/GUI.cpp index fcf5860f8..259845000 100644 --- a/apps/openmw-mp/Script/Functions/GUI.cpp +++ b/apps/openmw-mp/Script/Functions/GUI.cpp @@ -77,6 +77,77 @@ void GUIFunctions::ListBox(unsigned short pid, int id, const char *label, const mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_GUI_MESSAGEBOX)->Send(false); } +void GUIFunctions::InitializeQuickKeyChanges(unsigned short pid) noexcept +{ + Player *player; + GET_PLAYER(pid, player, ); + + player->quickKeyChanges.quickKeys.clear(); +} + +unsigned int GUIFunctions::GetQuickKeyChangesSize(unsigned short pid) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + return player->quickKeyChanges.count; +} + +int GUIFunctions::GetQuickKeySlot(unsigned short pid, unsigned int i) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + if (i >= player->quickKeyChanges.count) + return 0; + + return player->quickKeyChanges.quickKeys.at(i).slot; +} + +int GUIFunctions::GetQuickKeyType(unsigned short pid, unsigned int i) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + if (i >= player->quickKeyChanges.count) + return 0; + + return player->quickKeyChanges.quickKeys.at(i).type; +} + +const char *GUIFunctions::GetQuickKeyItemId(unsigned short pid, unsigned int i) noexcept +{ + Player *player; + GET_PLAYER(pid, player, ""); + + if (i >= player->quickKeyChanges.count) + return "invalid"; + + return player->quickKeyChanges.quickKeys.at(i).itemId.c_str(); +} + +void GUIFunctions::AddQuickKey(unsigned short pid, unsigned short slot, int type, const char* itemId) noexcept +{ + Player *player; + GET_PLAYER(pid, player, ); + + mwmp::QuickKey quickKey; + quickKey.slot = slot; + quickKey.type = type; + quickKey.itemId = itemId; + + player->quickKeyChanges.quickKeys.push_back(quickKey); +} + +void GUIFunctions::SendQuickKeyChanges(unsigned short pid) noexcept +{ + Player *player; + GET_PLAYER(pid, player, ); + + mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_QUICKKEYS)->setPlayer(player); + mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_QUICKKEYS)->Send(false); +} + void GUIFunctions::SetMapVisibility(unsigned short targetPID, unsigned short affectedPID, unsigned short state) noexcept { LOG_MESSAGE(Log::LOG_WARN, "stub"); diff --git a/apps/openmw-mp/Script/Functions/GUI.hpp b/apps/openmw-mp/Script/Functions/GUI.hpp index f76fda70a..f30ae0aad 100644 --- a/apps/openmw-mp/Script/Functions/GUI.hpp +++ b/apps/openmw-mp/Script/Functions/GUI.hpp @@ -6,13 +6,26 @@ #define OPENMW_GUIAPI_HPP #define GUIAPI \ - {"MessageBox", GUIFunctions::_MessageBox},\ - {"CustomMessageBox", GUIFunctions::CustomMessageBox},\ - {"InputDialog", GUIFunctions::InputDialog},\ - {"PasswordDialog", GUIFunctions::PasswordDialog},\ - {"ListBox", GUIFunctions::ListBox},\ - {"SetMapVisibility", GUIFunctions::SetMapVisibility},\ - {"SetMapVisibilityAll", GUIFunctions::SetMapVisibilityAll} + {"MessageBox", GUIFunctions::_MessageBox},\ + {"CustomMessageBox", GUIFunctions::CustomMessageBox},\ + {"InputDialog", GUIFunctions::InputDialog},\ + {"PasswordDialog", GUIFunctions::PasswordDialog},\ + {"ListBox", GUIFunctions::ListBox},\ + \ + {"InitializeQuickKeyChanges", GUIFunctions::InitializeQuickKeyChanges},\ + \ + {"GetQuickKeyChangesSize", GUIFunctions::GetQuickKeyChangesSize},\ + \ + {"GetQuickKeySlot", GUIFunctions::GetQuickKeySlot},\ + {"GetQuickKeyType", GUIFunctions::GetQuickKeyType},\ + {"GetQuickKeyItemId", GUIFunctions::GetQuickKeyItemId},\ + \ + {"AddQuickKey", GUIFunctions::AddQuickKey},\ + \ + {"SendQuickKeyChanges", GUIFunctions::SendQuickKeyChanges},\ + \ + {"SetMapVisibility", GUIFunctions::SetMapVisibility},\ + {"SetMapVisibilityAll", GUIFunctions::SetMapVisibilityAll} class GUIFunctions { @@ -26,6 +39,70 @@ public: static void ListBox(unsigned short pid, int id, const char *label, const char *items); + /** + * \brief Clear the last recorded quick key changes for a player. + * + * This is used to initialize the sending of new PlayerQuickKeys packets. + * + * \param pid The player ID whose quick key changes should be used. + * \return void + */ + static void InitializeQuickKeyChanges(unsigned short pid) noexcept; + + /** + * \brief Get the number of indexes in a player's latest quick key changes. + * + * \param pid The player ID whose quick key changes should be used. + * \return The number of indexes. + */ + static unsigned int GetQuickKeyChangesSize(unsigned short pid) noexcept; + + /** + * \brief Add a new quick key to the quick key changes for a player. + * + * \param pid The player ID whose quick key changes should be used. + * \param slot The slot to be used. + * \param slot The type of the quick key (0 for ITEM, 1 for ITEM_MAGIC, 2 for MAGIC, 3 for UNASSIGNED). + * \param itemId The itemId of the item. + * \return void + */ + static void AddQuickKey(unsigned short pid, unsigned short slot, int type, const char* itemId = "") noexcept; + + /** + * \brief Get the slot of the quick key at a certain index in a player's latest quick key changes. + * + * \param pid The player ID whose quick key changes should be used. + * \param i The index of the quick key in the quick key changes vector. + * \return The slot. + */ + static int GetQuickKeySlot(unsigned short pid, unsigned int i) noexcept; + + /** + * \brief Get the type of the quick key at a certain index in a player's latest quick key changes. + * + * \param pid The player ID whose quick key changes should be used. + * \param i The index of the quick key in the quick key changes vector. + * \return The quick key type. + */ + static int GetQuickKeyType(unsigned short pid, unsigned int i) noexcept; + + /** + * \brief Get the itemId at a certain index in a player's latest quick key changes. + * + * \param pid The player ID whose quick key changes should be used. + * \param i The index of the quick key in the quick key changes vector. + * \return The itemId. + */ + static const char *GetQuickKeyItemId(unsigned short pid, unsigned int i) noexcept; + + /** + * \brief Send a PlayerQuickKeys packet with a player's recorded quick key changes. + * + * \param pid The player ID whose quick key changes should be used. + * \return void + */ + static void SendQuickKeyChanges(unsigned short pid) noexcept; + //state 0 - disallow, 1 - allow static void SetMapVisibility(unsigned short targetPID, unsigned short affectedPID, unsigned short state) noexcept; static void SetMapVisibilityAll(unsigned short targetPID, unsigned short state) noexcept; diff --git a/apps/openmw-mp/Script/Functions/Spells.hpp b/apps/openmw-mp/Script/Functions/Spells.hpp index 6984a8455..f1d8ecbed 100644 --- a/apps/openmw-mp/Script/Functions/Spells.hpp +++ b/apps/openmw-mp/Script/Functions/Spells.hpp @@ -9,24 +9,24 @@ \ {"SetSpellbookChangesAction", SpellFunctions::SetSpellbookChangesAction},\ {"AddSpell", SpellFunctions::AddSpell},\ - {"AddCustomSpell", SpellFunctions::AddCustomSpell},\ - {"AddCustomSpellData", SpellFunctions::AddCustomSpellData},\ - {"AddCustomSpellEffect", SpellFunctions::AddCustomSpellEffect},\ + {"AddCustomSpell", SpellFunctions::AddCustomSpell},\ + {"AddCustomSpellData", SpellFunctions::AddCustomSpellData},\ + {"AddCustomSpellEffect", SpellFunctions::AddCustomSpellEffect},\ \ {"GetSpellId", SpellFunctions::GetSpellId},\ - {"GetSpellName", SpellFunctions::GetSpellName},\ - {"GetSpellType", SpellFunctions::GetSpellType},\ - {"GetSpellCost", SpellFunctions::GetSpellCost},\ - {"GetSpellFlags", SpellFunctions::GetSpellFlags},\ - {"GetSpellEffectCount", SpellFunctions::GetSpellEffectCount},\ - {"GetSpellEffectId", SpellFunctions::GetSpellEffectId},\ - {"GetSpellEffectSkill", SpellFunctions::GetSpellEffectSkill},\ - {"GetSpellEffectAttribute", SpellFunctions::GetSpellEffectAttribute},\ - {"GetSpellEffectRange", SpellFunctions::GetSpellEffectRange},\ - {"GetSpellEffectArea", SpellFunctions::GetSpellEffectArea},\ - {"GetSpellEffectDuration", SpellFunctions::GetSpellEffectDuration},\ - {"GetSpellEffectMagnMin", SpellFunctions::GetSpellEffectMagnMin},\ - {"GetSpellEffectMagnMax", SpellFunctions::GetSpellEffectMagnMax},\ + {"GetSpellName", SpellFunctions::GetSpellName},\ + {"GetSpellType", SpellFunctions::GetSpellType},\ + {"GetSpellCost", SpellFunctions::GetSpellCost},\ + {"GetSpellFlags", SpellFunctions::GetSpellFlags},\ + {"GetSpellEffectCount", SpellFunctions::GetSpellEffectCount},\ + {"GetSpellEffectId", SpellFunctions::GetSpellEffectId},\ + {"GetSpellEffectSkill", SpellFunctions::GetSpellEffectSkill},\ + {"GetSpellEffectAttribute", SpellFunctions::GetSpellEffectAttribute},\ + {"GetSpellEffectRange", SpellFunctions::GetSpellEffectRange},\ + {"GetSpellEffectArea", SpellFunctions::GetSpellEffectArea},\ + {"GetSpellEffectDuration", SpellFunctions::GetSpellEffectDuration},\ + {"GetSpellEffectMagnMin", SpellFunctions::GetSpellEffectMagnMin},\ + {"GetSpellEffectMagnMax", SpellFunctions::GetSpellEffectMagnMax},\ \ {"SendSpellbookChanges", SpellFunctions::SendSpellbookChanges} diff --git a/apps/openmw-mp/Script/ScriptFunctions.hpp b/apps/openmw-mp/Script/ScriptFunctions.hpp index c46cd8917..bf6d3558c 100644 --- a/apps/openmw-mp/Script/ScriptFunctions.hpp +++ b/apps/openmw-mp/Script/ScriptFunctions.hpp @@ -154,6 +154,7 @@ public: {"OnPlayerFaction", Function()}, {"OnPlayerShapeshift", Function()}, {"OnPlayerSpellbook", Function()}, + {"OnPlayerQuickKeys", Function()}, {"OnPlayerTopic", Function()}, {"OnPlayerDisposition", Function()}, {"OnPlayerBook", Function()}, diff --git a/apps/openmw-mp/processors/ProcessorInitializer.cpp b/apps/openmw-mp/processors/ProcessorInitializer.cpp index 62257b63e..c2cad7ecf 100644 --- a/apps/openmw-mp/processors/ProcessorInitializer.cpp +++ b/apps/openmw-mp/processors/ProcessorInitializer.cpp @@ -31,6 +31,7 @@ #include "player/ProcessorPlayerLevel.hpp" #include "player/ProcessorPlayerMap.hpp" #include "player/ProcessorPlayerPosition.hpp" +#include "player/ProcessorPlayerQuickKeys.hpp" #include "player/ProcessorPlayerRest.hpp" #include "player/ProcessorPlayerResurrect.hpp" #include "player/ProcessorPlayerShapeshift.hpp" @@ -100,6 +101,7 @@ void ProcessorInitializer() PlayerProcessor::AddProcessor(new ProcessorPlayerLevel()); PlayerProcessor::AddProcessor(new ProcessorPlayerMap()); PlayerProcessor::AddProcessor(new ProcessorPlayerPosition()); + PlayerProcessor::AddProcessor(new ProcessorPlayerQuickKeys()); PlayerProcessor::AddProcessor(new ProcessorPlayerRest()); PlayerProcessor::AddProcessor(new ProcessorPlayerResurrect()); PlayerProcessor::AddProcessor(new ProcessorPlayerShapeshift()); diff --git a/apps/openmw-mp/processors/player/ProcessorPlayerQuickKeys.hpp b/apps/openmw-mp/processors/player/ProcessorPlayerQuickKeys.hpp new file mode 100644 index 000000000..9f5265b00 --- /dev/null +++ b/apps/openmw-mp/processors/player/ProcessorPlayerQuickKeys.hpp @@ -0,0 +1,26 @@ +#ifndef OPENMW_PROCESSORPLAYERQUICKKEYS_HPP +#define OPENMW_PROCESSORPLAYERQUICKKEYS_HPP + +#include "../PlayerProcessor.hpp" + +namespace mwmp +{ + class ProcessorPlayerQuickKeys : public PlayerProcessor + { + public: + ProcessorPlayerQuickKeys() + { + BPP_INIT(ID_PLAYER_QUICKKEYS) + } + + void Do(PlayerPacket &packet, Player &player) override + { + DEBUG_PRINTF(strPacketID.c_str()); + + Script::Call(player.getId()); + } + }; +} + + +#endif //OPENMW_PROCESSORPLAYERQUICKKEYS_HPP diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 92fa5da2d..d71c9d5f3 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -117,8 +117,8 @@ add_openmw_dir (mwmp/processors/player ProcessorChatMessage ProcessorGUIMessageB ProcessorPlayerBook ProcessorPlayerBounty ProcessorPlayerCellChange ProcessorPlayerCellState ProcessorPlayerCharClass ProcessorPlayerCharGen ProcessorPlayerDeath ProcessorPlayerDisposition ProcessorPlayerEquipment ProcessorPlayerFaction ProcessorPlayerInventory ProcessorPlayerJail ProcessorPlayerJournal ProcessorPlayerKillCount ProcessorPlayerLevel - ProcessorPlayerMap ProcessorPlayerPosition ProcessorPlayerResurrect ProcessorPlayerShapeshift ProcessorPlayerSkill - ProcessorPlayerSpeech ProcessorPlayerSpellbook ProcessorPlayerStatsDynamic ProcessorPlayerTopic + ProcessorPlayerMap ProcessorPlayerPosition ProcessorPlayerQuickKeys ProcessorPlayerResurrect ProcessorPlayerShapeshift + ProcessorPlayerSkill ProcessorPlayerSpeech ProcessorPlayerSpellbook ProcessorPlayerStatsDynamic ProcessorPlayerTopic ) add_openmw_dir (mwmp/processors/world BaseObjectProcessor ProcessorConsoleCommand ProcessorContainer ProcessorDoorState diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index aa4cdf22c..b6cd36e19 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -227,6 +227,16 @@ namespace MWBase /// update activated quick key state (if action executing was delayed for some reason) virtual void updateActivatedQuickKey () = 0; + /* + Start of tes3mp addition + + Make it possible to add quickKeys from elsewhere in the code + */ + virtual void setQuickKey(int slot, int quickKeyType, MWWorld::Ptr item, const std::string& spellId = "") = 0; + /* + End of tes3mp addition + */ + virtual std::string getSelectedSpell() = 0; virtual void setSelectedSpell(const std::string& spellId, int successChancePercent) = 0; virtual void setSelectedEnchantItem(const MWWorld::Ptr& item) = 0; diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index e912193bf..6198372e0 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -8,6 +8,18 @@ #include #include +/* + Start of tes3mp addition + + Include additional headers for multiplayer purposes +*/ +#include +#include "../mwmp/Main.hpp" +#include "../mwmp/LocalPlayer.hpp" +/* + End of tes3mp addition +*/ + #include "../mwworld/inventorystore.hpp" #include "../mwworld/class.hpp" #include "../mwworld/player.hpp" @@ -111,8 +123,36 @@ namespace MWGui textBox->setCaption (MyGUI::utility::toString(index+1)); textBox->setNeedMouseFocus (false); } + + /* + Start of tes3mp addition + + Send a PLAYER_QUICKKEYS packet whenever a key is unassigned, but only if the player + has finished character generation, so as to avoid doing anything doing startup when all + quick keys get unassigned by default + */ + if (mwmp::Main::get().getLocalPlayer()->hasFinishedCharGen() && !mwmp::Main::get().getLocalPlayer()->isReceivingQuickKeys) + { + mwmp::Main::get().getLocalPlayer()->sendQuickKey(index, Type_Unassigned); + } + /* + End of tes3mp addition + */ } + /* + Start of tes3mp addition + + Allow unassigning an index directly from elsewhere in the code + */ + void QuickKeysMenu::unassignIndex(int index) + { + unassign(mQuickKeyButtons[index], index); + } + /* + End of tes3mp addition + */ + void QuickKeysMenu::onQuickKeyButtonClicked(MyGUI::Widget* sender) { int index = -1; @@ -193,6 +233,17 @@ namespace MWGui if (mItemSelectionDialog) mItemSelectionDialog->setVisible(false); + + /* + Start of tes3mp addition + + Send a PLAYER_QUICKKEYS packet whenever a key is assigned to an item + */ + if (!mwmp::Main::get().getLocalPlayer()->isReceivingQuickKeys) + mwmp::Main::get().getLocalPlayer()->sendQuickKey(mSelectedIndex, Type_Item, item.getCellRef().getRefId()); + /* + End of tes3mp addition + */ } void QuickKeysMenu::onAssignItemCancel() @@ -217,6 +268,17 @@ namespace MWGui if (mMagicSelectionDialog) mMagicSelectionDialog->setVisible(false); + + /* + Start of tes3mp addition + + Send a PLAYER_QUICKKEYS packet whenever a key is assigned to an item's magic + */ + if (!mwmp::Main::get().getLocalPlayer()->isReceivingQuickKeys) + mwmp::Main::get().getLocalPlayer()->sendQuickKey(mSelectedIndex, Type_MagicItem, item.getCellRef().getRefId()); + /* + End of tes3mp addition + */ } void QuickKeysMenu::onAssignMagic (const std::string& spellId) @@ -251,6 +313,17 @@ namespace MWGui if (mMagicSelectionDialog) mMagicSelectionDialog->setVisible(false); + + /* + Start of tes3mp addition + + Send a PLAYER_QUICKKEYS packet whenever a key is assigned to a spell + */ + if (!mwmp::Main::get().getLocalPlayer()->isReceivingQuickKeys) + mwmp::Main::get().getLocalPlayer()->sendQuickKey(mSelectedIndex, Type_Magic, spellId); + /* + End of tes3mp addition + */ } void QuickKeysMenu::onAssignMagicCancel () @@ -402,6 +475,19 @@ namespace MWGui } } + /* + Start of tes3mp addition + + Make it possible to add quickKeys from elsewhere in the code + */ + void QuickKeysMenu::setSelectedIndex(int index) + { + mSelectedIndex = index; + } + /* + End of tes3mp addition + */ + // --------------------------------------------------------------------------------------------------------- QuickKeysMenuAssign::QuickKeysMenuAssign (QuickKeysMenu* parent) diff --git a/apps/openmw/mwgui/quickkeysmenu.hpp b/apps/openmw/mwgui/quickkeysmenu.hpp index 64db9043e..e89da52a6 100644 --- a/apps/openmw/mwgui/quickkeysmenu.hpp +++ b/apps/openmw/mwgui/quickkeysmenu.hpp @@ -38,6 +38,16 @@ namespace MWGui void activateQuickKey(int index); void updateActivatedQuickKey(); + /* + Start of tes3mp addition + + Allow the setting of the selected index from elsewhere in the code + */ + void setSelectedIndex(int index); + /* + End of tes3mp addition + */ + /// @note This enum is serialized, so don't move the items around! enum QuickKeyType { @@ -52,6 +62,16 @@ namespace MWGui void readRecord (ESM::ESMReader& reader, uint32_t type); void clear(); + /* + Start of tes3mp addition + + Allow unassigning an index directly from elsewhere in the code + */ + void unassignIndex(int index); + /* + End of tes3mp addition + */ + private: MyGUI::EditBox* mInstructionLabel; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 73acd3c2f..8d98e55d9 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -25,6 +25,7 @@ Include additional headers for multiplayer purposes */ +#include #include "../mwmp/Main.hpp" #include "../mwmp/GUIController.hpp" /* @@ -1589,6 +1590,35 @@ namespace MWGui mQuickKeysMenu->activateQuickKey(index); } + /* + Start of tes3mp addition + + Make it possible to add quickKeys from elsewhere in the code + */ + void WindowManager::setQuickKey(int slot, int quickKeyType, MWWorld::Ptr item, const std::string& spellId) + { + mQuickKeysMenu->setSelectedIndex(slot); + + switch (quickKeyType) + { + case QuickKeysMenu::Type_Unassigned: + mQuickKeysMenu->unassignIndex(slot); + break; + case QuickKeysMenu::Type_Item: + mQuickKeysMenu->onAssignItem(item); + break; + case QuickKeysMenu::Type_MagicItem: + mQuickKeysMenu->onAssignMagicItem(item); + break; + case QuickKeysMenu::Type_Magic: + mQuickKeysMenu->onAssignMagic(spellId); + break; + } + } + /* + End of tes3mp addition + */ + bool WindowManager::getSubtitlesEnabled () { return mSubtitlesEnabled; diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index de9898b34..4f5ff1275 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -256,6 +256,16 @@ namespace MWGui /// update activated quick key state (if action executing was delayed for some reason) virtual void updateActivatedQuickKey (); + /* + Start of tes3mp addition + + Make it possible to add quickKeys from elsewhere in the code + */ + virtual void setQuickKey(int slot, int quickKeyType, MWWorld::Ptr item, const std::string& spellId = ""); + /* + End of tes3mp addition + */ + virtual std::string getSelectedSpell() { return mSelectedSpell; } virtual void setSelectedSpell(const std::string& spellId, int successChancePercent); virtual void setSelectedEnchantItem(const MWWorld::Ptr& item); diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 16a3d4441..71d1de8f7 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -65,6 +65,7 @@ LocalPlayer::LocalPlayer() isWerewolf = false; diedSinceArrestAttempt = false; + isReceivingQuickKeys = false; } LocalPlayer::~LocalPlayer() @@ -993,6 +994,57 @@ void LocalPlayer::setSpellbook() addSpells(); } +void LocalPlayer::setQuickKeys() +{ + MWWorld::Ptr ptrPlayer = getPlayerPtr(); + + LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Received ID_PLAYER_QUICKKEYS from server"); + + // Because we send QuickKeys packets from the same OpenMW methods that we use to set received ones with, + // we need a boolean to prevent their sending here + isReceivingQuickKeys = true; + + for (const auto &quickKey : quickKeyChanges.quickKeys) + { + LOG_APPEND(Log::LOG_INFO, "- slot: %i, type: %i, itemId: %s", quickKey.slot, quickKey.type, quickKey.itemId.c_str()); + + if (quickKey.type == QuickKey::ITEM || quickKey.type == QuickKey::ITEM_MAGIC) + { + MWWorld::InventoryStore &ptrInventory = ptrPlayer.getClass().getInventoryStore(ptrPlayer); + + auto it = find_if(ptrInventory.begin(), ptrInventory.end(), [&quickKey](const MWWorld::Ptr &inventoryItem) { + return Misc::StringUtils::ciEqual(inventoryItem.getCellRef().getRefId(), quickKey.itemId); + }); + + if (it != ptrInventory.end()) + MWBase::Environment::get().getWindowManager()->setQuickKey(quickKey.slot, quickKey.type, (*it)); + } + else if (quickKey.type == QuickKey::MAGIC) + { + MWMechanics::Spells &ptrSpells = ptrPlayer.getClass().getCreatureStats(ptrPlayer).getSpells(); + bool hasSpell = false; + + MWMechanics::Spells::TIterator iter = ptrSpells.begin(); + for (; iter != ptrSpells.end(); iter++) + { + const ESM::Spell *spell = iter->first; + if (Misc::StringUtils::ciEqual(spell->mId, quickKey.itemId)) + { + hasSpell = true; + break; + } + } + + if (hasSpell) + MWBase::Environment::get().getWindowManager()->setQuickKey(quickKey.slot, quickKey.type, 0, quickKey.itemId); + } + else + MWBase::Environment::get().getWindowManager()->setQuickKey(quickKey.slot, quickKey.type, 0); + } + + isReceivingQuickKeys = false; +} + void LocalPlayer::setFactions() { MWWorld::Ptr ptrPlayer = getPlayerPtr(); @@ -1199,6 +1251,24 @@ void LocalPlayer::sendSpellRemoval(const ESM::Spell &spell) */ } +void LocalPlayer::sendQuickKey(unsigned short slot, int type, const std::string& itemId) +{ + quickKeyChanges.quickKeys.clear(); + + mwmp::QuickKey quickKey; + quickKey.slot = slot; + quickKey.type = type; + quickKey.itemId = itemId; + + LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_PLAYER_QUICKKEYS", itemId.c_str()); + LOG_APPEND(Log::LOG_INFO, "- slot: %i, type: %i, itemId: %s", quickKey.slot, quickKey.type, quickKey.itemId.c_str()); + + quickKeyChanges.quickKeys.push_back(quickKey); + + getNetworking()->getPlayerPacket(ID_PLAYER_QUICKKEYS)->setPlayer(this); + getNetworking()->getPlayerPacket(ID_PLAYER_QUICKKEYS)->Send(); +} + void LocalPlayer::sendJournalEntry(const std::string& quest, int index, const MWWorld::Ptr& actor) { journalChanges.journalItems.clear(); diff --git a/apps/openmw/mwmp/LocalPlayer.hpp b/apps/openmw/mwmp/LocalPlayer.hpp index 23308428c..56302fa31 100644 --- a/apps/openmw/mwmp/LocalPlayer.hpp +++ b/apps/openmw/mwmp/LocalPlayer.hpp @@ -58,6 +58,7 @@ namespace mwmp void setEquipment(); void setInventory(); void setSpellbook(); + void setQuickKeys(); void setFactions(); void setKills(); void setBooks(); @@ -72,6 +73,7 @@ namespace mwmp void sendSpellAddition(const ESM::Spell &spell); void sendSpellRemoval(std::string id); void sendSpellRemoval(const ESM::Spell &spell); + void sendQuickKey(unsigned short slot, int type, const std::string& itemId = ""); void sendJournalEntry(const std::string& quest, int index, const MWWorld::Ptr& actor); void sendJournalIndex(const std::string& quest, int index); void sendFactionRank(const std::string& factionId, int rank); diff --git a/apps/openmw/mwmp/processors/ProcessorInitializer.cpp b/apps/openmw/mwmp/processors/ProcessorInitializer.cpp index 537177970..254655b18 100644 --- a/apps/openmw/mwmp/processors/ProcessorInitializer.cpp +++ b/apps/openmw/mwmp/processors/ProcessorInitializer.cpp @@ -35,6 +35,7 @@ #include "player/ProcessorPlayerLevel.hpp" #include "player/ProcessorPlayerMap.hpp" #include "player/ProcessorPlayerPosition.hpp" +#include "player/ProcessorPlayerQuickKeys.hpp" #include "player/ProcessorPlayerRegionAuthority.hpp" #include "player/ProcessorPlayerRest.hpp" #include "player/ProcessorPlayerResurrect.hpp" @@ -113,6 +114,7 @@ void ProcessorInitializer() PlayerProcessor::AddProcessor(new ProcessorPlayerLevel()); PlayerProcessor::AddProcessor(new ProcessorPlayerMap()); PlayerProcessor::AddProcessor(new ProcessorPlayerPosition()); + PlayerProcessor::AddProcessor(new ProcessorPlayerQuickKeys()); PlayerProcessor::AddProcessor(new ProcessorPlayerRegionAuthority()); PlayerProcessor::AddProcessor(new ProcessorPlayerRest()); PlayerProcessor::AddProcessor(new ProcessorPlayerResurrect()); diff --git a/apps/openmw/mwmp/processors/player/ProcessorPlayerQuickKeys.hpp b/apps/openmw/mwmp/processors/player/ProcessorPlayerQuickKeys.hpp new file mode 100644 index 000000000..5515162a6 --- /dev/null +++ b/apps/openmw/mwmp/processors/player/ProcessorPlayerQuickKeys.hpp @@ -0,0 +1,32 @@ +#ifndef OPENMW_PROCESSORPLAYERQUICKKEYS_HPP +#define OPENMW_PROCESSORPLAYERQUICKKEYS_HPP + + +#include "../PlayerProcessor.hpp" + +namespace mwmp +{ + class ProcessorPlayerQuickKeys : public PlayerProcessor + { + public: + ProcessorPlayerQuickKeys() + { + BPP_INIT(ID_PLAYER_QUICKKEYS) + } + + virtual void Do(PlayerPacket &packet, BasePlayer *player) + { + if (!isLocal()) return; + + LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Received ID_PLAYER_QUICKKEYS about LocalPlayer from server"); + + if (!isRequest()) + { + LocalPlayer &localPlayer = static_cast(*player); + localPlayer.setQuickKeys(); + } + } + }; +} + +#endif //OPENMW_PROCESSORPLAYERQUICKKEYS_HPP diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index b25adbbd1..f57f1353d 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -181,9 +181,9 @@ add_component_dir (openmw-mp/Packets/Player PacketPlayerAttack PacketPlayerAttribute PacketPlayerBook PacketPlayerBounty PacketPlayerCellChange PacketPlayerCellState PacketPlayerClass PacketPlayerDeath PacketPlayerEquipment PacketPlayerFaction PacketPlayerInventory PacketPlayerJail PacketPlayerJournal PacketPlayerKillCount PacketPlayerLevel - PacketPlayerMap PacketPlayerPosition PacketPlayerRegionAuthority PacketPlayerRest PacketPlayerResurrect - PacketPlayerShapeshift PacketPlayerSkill PacketPlayerSpeech PacketPlayerSpellbook PacketPlayerStatsDynamic - PacketPlayerTopic + PacketPlayerMap PacketPlayerPosition PacketPlayerQuickKeys PacketPlayerRegionAuthority PacketPlayerRest + PacketPlayerResurrect PacketPlayerShapeshift PacketPlayerSkill PacketPlayerSpeech PacketPlayerSpellbook + PacketPlayerStatsDynamic PacketPlayerTopic ) add_component_dir (openmw-mp/Packets/World diff --git a/components/openmw-mp/Base/BasePlayer.hpp b/components/openmw-mp/Base/BasePlayer.hpp index 0b3a2cc9a..a3fcf3e22 100644 --- a/components/openmw-mp/Base/BasePlayer.hpp +++ b/components/openmw-mp/Base/BasePlayer.hpp @@ -65,6 +65,22 @@ namespace mwmp std::string bookId; }; + struct QuickKey + { + std::string itemId; + + enum QUICKKEY_TYPE + { + ITEM = 0, + MAGIC = 1, + ITEM_MAGIC = 2, + UNASSIGNED = 3 + }; + + unsigned short slot; + int type; + }; + struct CellState { ESM::Cell cell; @@ -149,6 +165,12 @@ namespace mwmp int action; // 0 - Clear and set in entirety, 1 - Add spell, 2 - Remove spell }; + struct QuickKeyChanges + { + std::vector quickKeys; + unsigned int count; + }; + struct CellStateChanges { std::vector cellStates; @@ -212,6 +234,7 @@ namespace mwmp InventoryChanges inventoryChanges; SpellbookChanges spellbookChanges; + QuickKeyChanges quickKeyChanges; JournalChanges journalChanges; FactionChanges factionChanges; TopicChanges topicChanges; @@ -265,6 +288,7 @@ namespace mwmp unsigned int resurrectType; bool diedSinceArrestAttempt; + bool isReceivingQuickKeys; }; } diff --git a/components/openmw-mp/Controllers/PlayerPacketController.cpp b/components/openmw-mp/Controllers/PlayerPacketController.cpp index d155b5066..897e1f8df 100644 --- a/components/openmw-mp/Controllers/PlayerPacketController.cpp +++ b/components/openmw-mp/Controllers/PlayerPacketController.cpp @@ -28,6 +28,7 @@ #include "../Packets/Player/PacketPlayerLevel.hpp" #include "../Packets/Player/PacketPlayerMap.hpp" #include "../Packets/Player/PacketPlayerPosition.hpp" +#include "../Packets/Player/PacketPlayerQuickKeys.hpp" #include "../Packets/Player/PacketPlayerRegionAuthority.hpp" #include "../Packets/Player/PacketPlayerRest.hpp" #include "../Packets/Player/PacketPlayerResurrect.hpp" @@ -81,6 +82,7 @@ mwmp::PlayerPacketController::PlayerPacketController(RakNet::RakPeerInterface *p AddPacket(&packets, peer); AddPacket(&packets, peer); AddPacket(&packets, peer); + AddPacket(&packets, peer); AddPacket(&packets, peer); AddPacket(&packets, peer); AddPacket(&packets, peer); diff --git a/components/openmw-mp/NetworkMessages.hpp b/components/openmw-mp/NetworkMessages.hpp index 7c4823a15..ad5a34235 100644 --- a/components/openmw-mp/NetworkMessages.hpp +++ b/components/openmw-mp/NetworkMessages.hpp @@ -44,6 +44,7 @@ enum GameMessages ID_PLAYER_LEVEL, ID_PLAYER_MAP, ID_PLAYER_POSITION, + ID_PLAYER_QUICKKEYS, ID_PLAYER_REGION_AUTHORITY, ID_PLAYER_RESURRECT, ID_PLAYER_REST, diff --git a/components/openmw-mp/Packets/Player/PacketPlayerQuickKeys.cpp b/components/openmw-mp/Packets/Player/PacketPlayerQuickKeys.cpp new file mode 100644 index 000000000..0be42e565 --- /dev/null +++ b/components/openmw-mp/Packets/Player/PacketPlayerQuickKeys.cpp @@ -0,0 +1,40 @@ +#include +#include "PacketPlayerQuickKeys.hpp" + +using namespace std; +using namespace mwmp; + +PacketPlayerQuickKeys::PacketPlayerQuickKeys(RakNet::RakPeerInterface *peer) : PlayerPacket(peer) +{ + packetID = ID_PLAYER_QUICKKEYS; +} + +void PacketPlayerQuickKeys::Packet(RakNet::BitStream *bs, bool send) +{ + PlayerPacket::Packet(bs, send); + + if (send) + player->quickKeyChanges.count = (unsigned int) (player->quickKeyChanges.quickKeys.size()); + else + player->quickKeyChanges.quickKeys.clear(); + + RW(player->quickKeyChanges.count, send); + + for (unsigned int i = 0; i < player->quickKeyChanges.count; i++) + { + QuickKey quickKey; + + if (send) + quickKey = player->quickKeyChanges.quickKeys.at(i); + + RW(quickKey.type, send); + RW(quickKey.slot, send); + + if (quickKey.type != QuickKey::UNASSIGNED) + RW(quickKey.itemId, send); + + if (!send) + player->quickKeyChanges.quickKeys.push_back(quickKey); + } + +} diff --git a/components/openmw-mp/Packets/Player/PacketPlayerQuickKeys.hpp b/components/openmw-mp/Packets/Player/PacketPlayerQuickKeys.hpp new file mode 100644 index 000000000..26a6f64b0 --- /dev/null +++ b/components/openmw-mp/Packets/Player/PacketPlayerQuickKeys.hpp @@ -0,0 +1,17 @@ +#ifndef OPENMW_PACKETPLAYERQUICKKEYS_HPP +#define OPENMW_PACKETPLAYERQUICKKEYS_HPP + +#include + +namespace mwmp +{ + class PacketPlayerQuickKeys : public PlayerPacket + { + public: + PacketPlayerQuickKeys(RakNet::RakPeerInterface *peer); + + virtual void Packet(RakNet::BitStream *bs, bool send); + }; +} + +#endif //OPENMW_PACKETPLAYERQUICKKEYS_HPP From 413893aa51f63631cba0c83812959ed2328d22f3 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Fri, 27 Oct 2017 09:10:29 +0300 Subject: [PATCH 03/29] [General] Implement PlayerAnimPlay packet --- apps/openmw-mp/Script/Functions/Dialogue.cpp | 15 +++++++++++++++ apps/openmw-mp/Script/Functions/Dialogue.hpp | 7 ++++++- apps/openmw-mp/Script/Functions/Positions.hpp | 2 +- apps/openmw-mp/Script/Functions/Stats.hpp | 2 +- apps/openmw/mwmp/DedicatedPlayer.cpp | 6 ++++++ apps/openmw/mwmp/DedicatedPlayer.hpp | 2 ++ apps/openmw/mwmp/LocalPlayer.cpp | 6 ++++++ apps/openmw/mwmp/LocalPlayer.hpp | 2 ++ .../processors/player/ProcessorPlayerAnimPlay.hpp | 8 +++++++- components/openmw-mp/Base/BasePlayer.hpp | 2 ++ .../Packets/Player/PacketPlayerAnimPlay.cpp | 5 ++++- 11 files changed, 52 insertions(+), 5 deletions(-) diff --git a/apps/openmw-mp/Script/Functions/Dialogue.cpp b/apps/openmw-mp/Script/Functions/Dialogue.cpp index 13f9811c1..02339cca5 100644 --- a/apps/openmw-mp/Script/Functions/Dialogue.cpp +++ b/apps/openmw-mp/Script/Functions/Dialogue.cpp @@ -53,3 +53,18 @@ void DialogueFunctions::SendTopicChanges(unsigned short pid, bool toOthers) noex mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_TOPIC)->setPlayer(player); mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_TOPIC)->Send(toOthers); } + +void DialogueFunctions::PlayAnimation(unsigned short pid, const char* groupname, int mode, int count, bool persist) noexcept +{ + Player *player; + GET_PLAYER(pid, player, ); + + player->animation.groupname = groupname; + player->animation.mode = mode; + player->animation.count = count; + player->animation.persist = persist; + + mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_ANIM_PLAY)->setPlayer(player); + mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_ANIM_PLAY)->Send(false); + mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_ANIM_PLAY)->Send(true); +} diff --git a/apps/openmw-mp/Script/Functions/Dialogue.hpp b/apps/openmw-mp/Script/Functions/Dialogue.hpp index 1813e7ed7..70a1731b0 100644 --- a/apps/openmw-mp/Script/Functions/Dialogue.hpp +++ b/apps/openmw-mp/Script/Functions/Dialogue.hpp @@ -10,7 +10,9 @@ \ {"GetTopicId", DialogueFunctions::GetTopicId},\ \ - {"SendTopicChanges", DialogueFunctions::SendTopicChanges} + {"SendTopicChanges", DialogueFunctions::SendTopicChanges},\ + \ + {"PlayAnimation", DialogueFunctions::PlayAnimation} class DialogueFunctions { @@ -61,6 +63,9 @@ public: * \return void */ static void SendTopicChanges(unsigned short pid, bool toOthers = false) noexcept; + + static void PlayAnimation(unsigned short pid, const char* groupname, int mode = 0, int count = 1, bool persist = false) noexcept; + private: }; diff --git a/apps/openmw-mp/Script/Functions/Positions.hpp b/apps/openmw-mp/Script/Functions/Positions.hpp index ae8b8a768..49cb9f863 100644 --- a/apps/openmw-mp/Script/Functions/Positions.hpp +++ b/apps/openmw-mp/Script/Functions/Positions.hpp @@ -11,7 +11,7 @@ \ {"GetPreviousCellPosX", PositionFunctions::GetPreviousCellPosX},\ {"GetPreviousCellPosY", PositionFunctions::GetPreviousCellPosY},\ - {"GetPreviousCellPosZ", PositionFunctions::GetPreviousCellPosZ},\ + {"GetPreviousCellPosZ", PositionFunctions::GetPreviousCellPosZ},\ \ {"GetRot", PositionFunctions::GetRot},\ {"GetRotX", PositionFunctions::GetRotX},\ diff --git a/apps/openmw-mp/Script/Functions/Stats.hpp b/apps/openmw-mp/Script/Functions/Stats.hpp index 8ee0421d7..e046ffb6a 100644 --- a/apps/openmw-mp/Script/Functions/Stats.hpp +++ b/apps/openmw-mp/Script/Functions/Stats.hpp @@ -133,7 +133,7 @@ public: static void SetLevel(unsigned short pid, int value) noexcept; static void SetLevelProgress(unsigned short pid, int value) noexcept; - static void SetHealthBase(unsigned short pid, double value) noexcept; + static void SetHealthBase(unsigned short pid, double value) noexcept; static void SetHealthCurrent(unsigned short pid, double value) noexcept; static void SetMagickaBase(unsigned short pid, double value) noexcept; static void SetMagickaCurrent(unsigned short pid, double value) noexcept; diff --git a/apps/openmw/mwmp/DedicatedPlayer.cpp b/apps/openmw/mwmp/DedicatedPlayer.cpp index f5f8d3bfd..a3e39fff0 100644 --- a/apps/openmw/mwmp/DedicatedPlayer.cpp +++ b/apps/openmw/mwmp/DedicatedPlayer.cpp @@ -283,6 +283,12 @@ void DedicatedPlayer::setMarkerState(bool state) removeMarker(); } +void DedicatedPlayer::playAnimation() +{ + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(getPtr(), + animation.groupname, animation.mode, animation.count, animation.persist); +} + MWWorld::Ptr DedicatedPlayer::getPtr() { return ptr; diff --git a/apps/openmw/mwmp/DedicatedPlayer.hpp b/apps/openmw/mwmp/DedicatedPlayer.hpp index 212279852..d016b63b1 100644 --- a/apps/openmw/mwmp/DedicatedPlayer.hpp +++ b/apps/openmw/mwmp/DedicatedPlayer.hpp @@ -43,6 +43,8 @@ namespace mwmp void removeMarker(); void setMarkerState(bool state); + void playAnimation(); + MWWorld::Ptr getPtr(); MWWorld::Ptr getLiveCellPtr(); MWWorld::ManualRef* getRef(); diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 71d1de8f7..c7ecf8bf2 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -1446,3 +1446,9 @@ void LocalPlayer::storeCurrentContainer(const MWWorld::Ptr &container, bool loot currentContainer.mpNum = container.getCellRef().getMpNum(); currentContainer.loot = loot; } + +void LocalPlayer::playAnimation() +{ + MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(getPlayerPtr(), + animation.groupname, animation.mode, animation.count, animation.persist); +} diff --git a/apps/openmw/mwmp/LocalPlayer.hpp b/apps/openmw/mwmp/LocalPlayer.hpp index 56302fa31..fc4d9aaf0 100644 --- a/apps/openmw/mwmp/LocalPlayer.hpp +++ b/apps/openmw/mwmp/LocalPlayer.hpp @@ -90,6 +90,8 @@ namespace mwmp void storeCellState(ESM::Cell cell, int stateType); void storeCurrentContainer(const MWWorld::Ptr& container, bool loot); + void playAnimation(); + private: Networking *getNetworking(); MWWorld::Ptr getPlayerPtr(); diff --git a/apps/openmw/mwmp/processors/player/ProcessorPlayerAnimPlay.hpp b/apps/openmw/mwmp/processors/player/ProcessorPlayerAnimPlay.hpp index e8b360e5a..d5e022d04 100644 --- a/apps/openmw/mwmp/processors/player/ProcessorPlayerAnimPlay.hpp +++ b/apps/openmw/mwmp/processors/player/ProcessorPlayerAnimPlay.hpp @@ -15,7 +15,13 @@ namespace mwmp virtual void Do(PlayerPacket &packet, BasePlayer *player) { - // Placeholder to be filled in later + if (isLocal()) + { + LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Received ID_PLAYER_ANIM_PLAY about LocalPlayer from server"); + static_cast(player)->playAnimation(); + } + else if (player != 0) + static_cast(player)->playAnimation(); } }; } diff --git a/components/openmw-mp/Base/BasePlayer.hpp b/components/openmw-mp/Base/BasePlayer.hpp index a3fcf3e22..2a877202f 100644 --- a/components/openmw-mp/Base/BasePlayer.hpp +++ b/components/openmw-mp/Base/BasePlayer.hpp @@ -271,6 +271,8 @@ namespace mwmp CGStage charGenStage; std::string passw; + Animation animation; + bool isWerewolf; std::string creatureModel; bool useCreatureName; diff --git a/components/openmw-mp/Packets/Player/PacketPlayerAnimPlay.cpp b/components/openmw-mp/Packets/Player/PacketPlayerAnimPlay.cpp index 34c601673..bcc7562e8 100644 --- a/components/openmw-mp/Packets/Player/PacketPlayerAnimPlay.cpp +++ b/components/openmw-mp/Packets/Player/PacketPlayerAnimPlay.cpp @@ -10,5 +10,8 @@ void mwmp::PacketPlayerAnimPlay::Packet(RakNet::BitStream *bs, bool send) { PlayerPacket::Packet(bs, send); - // Placeholder to be filled in later + RW(player->animation.groupname, send); + RW(player->animation.mode, send); + RW(player->animation.count, send); + RW(player->animation.persist, send); } From 605b06c303b21afb632528614a39eb90062d0b4b Mon Sep 17 00:00:00 2001 From: David Cernat Date: Mon, 30 Oct 2017 11:06:09 +0200 Subject: [PATCH 04/29] [General] Find actor speech captions instead of sending them in packets --- apps/openmw/mwbase/dialoguemanager.hpp | 10 +++++++ apps/openmw/mwdialogue/dialoguemanagerimp.cpp | 29 ++++++++++++++++++- apps/openmw/mwdialogue/dialoguemanagerimp.hpp | 10 +++++++ apps/openmw/mwmp/Cell.cpp | 1 - apps/openmw/mwmp/DedicatedActor.cpp | 4 ++- components/openmw-mp/Base/BaseActor.hpp | 1 - .../Packets/Actor/PacketActorSpeech.cpp | 1 - 7 files changed, 51 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwbase/dialoguemanager.hpp b/apps/openmw/mwbase/dialoguemanager.hpp index 2aedb48fc..f489e4cb2 100644 --- a/apps/openmw/mwbase/dialoguemanager.hpp +++ b/apps/openmw/mwbase/dialoguemanager.hpp @@ -102,6 +102,16 @@ namespace MWBase /* End of tes3mp addition */ + + /* + Start of tes3mp addition + + Make it possible to get the caption of a voice dialogue + */ + virtual std::string getVoiceCaption(const std::string& sound) const = 0; + /* + End of tes3mp addition + */ }; } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index abb6ebd89..480415e38 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -711,7 +711,6 @@ namespace MWDialogue if (mwmp::Main::get().getCellController()->isLocalActor(actor)) { mwmp::LocalActor *localActor = mwmp::Main::get().getCellController()->getLocalActor(actor); - localActor->response = info->mResponse; localActor->sound = info->mSound; } /* @@ -816,4 +815,32 @@ namespace MWDialogue mLastTopic, actor.getClass().getName(actor)); } } + + /* + Start of tes3mp addition + + Make it possible to get the caption of a voice dialogue + */ + std::string DialogueManager::getVoiceCaption(const std::string& sound) const + { + const MWWorld::Store& dialogues = MWBase::Environment::get().getWorld()->getStore().get(); + + for (MWWorld::Store::iterator dialogueIter = dialogues.begin(); dialogueIter != dialogues.end(); ++dialogueIter) + { + if (dialogueIter->mType == ESM::Dialogue::Voice) + { + for (ESM::Dialogue::InfoContainer::const_iterator infoIter = dialogueIter->mInfo.begin(); + infoIter != dialogueIter->mInfo.end(); ++infoIter) + { + if (!infoIter->mSound.empty() && Misc::StringUtils::ciEqual(sound, infoIter->mSound)) + return infoIter->mResponse; + } + } + } + + return "???"; + } + /* + End of tes3mp addition + */ } diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 00dbf5c05..12fbff796 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -114,6 +114,16 @@ namespace MWDialogue /// Removes the last added topic response for the given actor from the journal virtual void clearInfoActor (const MWWorld::Ptr& actor) const; + + /* + Start of tes3mp addition + + Make it possible to get the caption of a voice dialogue + */ + virtual std::string getVoiceCaption(const std::string& sound) const; + /* + End of tes3mp addition + */ }; } diff --git a/apps/openmw/mwmp/Cell.cpp b/apps/openmw/mwmp/Cell.cpp index c8d610366..625c390ec 100644 --- a/apps/openmw/mwmp/Cell.cpp +++ b/apps/openmw/mwmp/Cell.cpp @@ -237,7 +237,6 @@ void Cell::readSpeech(ActorList& actorList) if (dedicatedActors.count(mapIndex) > 0) { DedicatedActor *actor = dedicatedActors[mapIndex]; - actor->response = baseActor.response; actor->sound = baseActor.sound; } } diff --git a/apps/openmw/mwmp/DedicatedActor.cpp b/apps/openmw/mwmp/DedicatedActor.cpp index 01ad37743..e0f18b816 100644 --- a/apps/openmw/mwmp/DedicatedActor.cpp +++ b/apps/openmw/mwmp/DedicatedActor.cpp @@ -4,6 +4,8 @@ #include "../mwbase/soundmanager.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwdialogue/dialoguemanagerimp.hpp" + #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/mechanicsmanagerimp.hpp" #include "../mwmechanics/movement.hpp" @@ -217,7 +219,7 @@ void DedicatedActor::playSound() MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager(); if (winMgr->getSubtitlesEnabled()) - winMgr->messageBox(response, MWGui::ShowInDialogueMode_Never); + winMgr->messageBox(MWBase::Environment::get().getDialogueManager()->getVoiceCaption(sound), MWGui::ShowInDialogueMode_Never); sound.clear(); } diff --git a/components/openmw-mp/Base/BaseActor.hpp b/components/openmw-mp/Base/BaseActor.hpp index c4b55b4e6..be8f50e28 100644 --- a/components/openmw-mp/Base/BaseActor.hpp +++ b/components/openmw-mp/Base/BaseActor.hpp @@ -32,7 +32,6 @@ namespace mwmp char drawState; bool isFlying; - std::string response; std::string sound; SimpleCreatureStats creatureStats; diff --git a/components/openmw-mp/Packets/Actor/PacketActorSpeech.cpp b/components/openmw-mp/Packets/Actor/PacketActorSpeech.cpp index 565097ccf..20fe76a47 100644 --- a/components/openmw-mp/Packets/Actor/PacketActorSpeech.cpp +++ b/components/openmw-mp/Packets/Actor/PacketActorSpeech.cpp @@ -11,6 +11,5 @@ PacketActorSpeech::PacketActorSpeech(RakNet::RakPeerInterface *peer) : ActorPack void PacketActorSpeech::Actor(BaseActor &actor, bool send) { - RW(actor.response, send); RW(actor.sound, send); } From be25decee27a0a5a037fb4a7c44913b36770e87b Mon Sep 17 00:00:00 2001 From: David Cernat Date: Tue, 31 Oct 2017 15:19:14 +0200 Subject: [PATCH 05/29] [General] Implement PlayerSpeech packet --- apps/openmw-mp/Script/Functions/Dialogue.cpp | 12 ++++++++++++ apps/openmw-mp/Script/Functions/Dialogue.hpp | 4 +++- apps/openmw/mwmp/DedicatedPlayer.cpp | 16 ++++++++++++++-- apps/openmw/mwmp/DedicatedPlayer.hpp | 1 + apps/openmw/mwmp/LocalPlayer.cpp | 10 ++++++++++ apps/openmw/mwmp/LocalPlayer.hpp | 1 + .../processors/player/ProcessorPlayerSpeech.hpp | 8 +++++++- components/openmw-mp/Base/BasePlayer.hpp | 1 + .../Packets/Player/PacketPlayerSpeech.cpp | 2 +- 9 files changed, 50 insertions(+), 5 deletions(-) diff --git a/apps/openmw-mp/Script/Functions/Dialogue.cpp b/apps/openmw-mp/Script/Functions/Dialogue.cpp index 02339cca5..eacf21dcb 100644 --- a/apps/openmw-mp/Script/Functions/Dialogue.cpp +++ b/apps/openmw-mp/Script/Functions/Dialogue.cpp @@ -68,3 +68,15 @@ void DialogueFunctions::PlayAnimation(unsigned short pid, const char* groupname, mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_ANIM_PLAY)->Send(false); mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_ANIM_PLAY)->Send(true); } + +void DialogueFunctions::PlaySpeech(unsigned short pid, const char* sound) noexcept +{ + Player *player; + GET_PLAYER(pid, player, ); + + player->sound = sound; + + mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_SPEECH)->setPlayer(player); + mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_SPEECH)->Send(false); + mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_SPEECH)->Send(true); +} diff --git a/apps/openmw-mp/Script/Functions/Dialogue.hpp b/apps/openmw-mp/Script/Functions/Dialogue.hpp index 70a1731b0..fe135e5a5 100644 --- a/apps/openmw-mp/Script/Functions/Dialogue.hpp +++ b/apps/openmw-mp/Script/Functions/Dialogue.hpp @@ -12,7 +12,8 @@ \ {"SendTopicChanges", DialogueFunctions::SendTopicChanges},\ \ - {"PlayAnimation", DialogueFunctions::PlayAnimation} + {"PlayAnimation", DialogueFunctions::PlayAnimation},\ + {"PlaySpeech", DialogueFunctions::PlaySpeech} class DialogueFunctions { @@ -65,6 +66,7 @@ public: static void SendTopicChanges(unsigned short pid, bool toOthers = false) noexcept; static void PlayAnimation(unsigned short pid, const char* groupname, int mode = 0, int count = 1, bool persist = false) noexcept; + static void PlaySpeech(unsigned short pid, const char* sound) noexcept; private: diff --git a/apps/openmw/mwmp/DedicatedPlayer.cpp b/apps/openmw/mwmp/DedicatedPlayer.cpp index a3e39fff0..d4fddab80 100644 --- a/apps/openmw/mwmp/DedicatedPlayer.cpp +++ b/apps/openmw/mwmp/DedicatedPlayer.cpp @@ -7,11 +7,14 @@ #include #include "../mwbase/environment.hpp" - -#include "../mwgui/windowmanagerimp.hpp" +#include "../mwbase/soundmanager.hpp" #include "../mwclass/npc.hpp" +#include "../mwdialogue/dialoguemanagerimp.hpp" + +#include "../mwgui/windowmanagerimp.hpp" + #include "../mwinput/inputmanagerimp.hpp" #include "../mwmechanics/actor.hpp" @@ -289,6 +292,15 @@ void DedicatedPlayer::playAnimation() animation.groupname, animation.mode, animation.count, animation.persist); } +void DedicatedPlayer::playSpeech() +{ + MWBase::Environment::get().getSoundManager()->say(getPtr(), sound); + + MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager(); + if (winMgr->getSubtitlesEnabled()) + winMgr->messageBox(MWBase::Environment::get().getDialogueManager()->getVoiceCaption(sound), MWGui::ShowInDialogueMode_Never); +} + MWWorld::Ptr DedicatedPlayer::getPtr() { return ptr; diff --git a/apps/openmw/mwmp/DedicatedPlayer.hpp b/apps/openmw/mwmp/DedicatedPlayer.hpp index d016b63b1..781748fb8 100644 --- a/apps/openmw/mwmp/DedicatedPlayer.hpp +++ b/apps/openmw/mwmp/DedicatedPlayer.hpp @@ -44,6 +44,7 @@ namespace mwmp void setMarkerState(bool state); void playAnimation(); + void playSpeech(); MWWorld::Ptr getPtr(); MWWorld::Ptr getLiveCellPtr(); diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index c7ecf8bf2..956bad587 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -7,6 +7,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/journal.hpp" +#include "../mwbase/soundmanager.hpp" #include "../mwclass/creature.hpp" #include "../mwclass/npc.hpp" @@ -1452,3 +1453,12 @@ void LocalPlayer::playAnimation() MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(getPlayerPtr(), animation.groupname, animation.mode, animation.count, animation.persist); } + +void LocalPlayer::playSpeech() +{ + MWBase::Environment::get().getSoundManager()->say(getPlayerPtr(), sound); + + MWBase::WindowManager *winMgr = MWBase::Environment::get().getWindowManager(); + if (winMgr->getSubtitlesEnabled()) + winMgr->messageBox(MWBase::Environment::get().getDialogueManager()->getVoiceCaption(sound), MWGui::ShowInDialogueMode_Never); +} diff --git a/apps/openmw/mwmp/LocalPlayer.hpp b/apps/openmw/mwmp/LocalPlayer.hpp index fc4d9aaf0..30b3f9aab 100644 --- a/apps/openmw/mwmp/LocalPlayer.hpp +++ b/apps/openmw/mwmp/LocalPlayer.hpp @@ -91,6 +91,7 @@ namespace mwmp void storeCurrentContainer(const MWWorld::Ptr& container, bool loot); void playAnimation(); + void playSpeech(); private: Networking *getNetworking(); diff --git a/apps/openmw/mwmp/processors/player/ProcessorPlayerSpeech.hpp b/apps/openmw/mwmp/processors/player/ProcessorPlayerSpeech.hpp index b4e2bab8a..ace5174df 100644 --- a/apps/openmw/mwmp/processors/player/ProcessorPlayerSpeech.hpp +++ b/apps/openmw/mwmp/processors/player/ProcessorPlayerSpeech.hpp @@ -15,7 +15,13 @@ namespace mwmp virtual void Do(PlayerPacket &packet, BasePlayer *player) { - // Placeholder to be filled in later + if (isLocal()) + { + LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Received ID_PLAYER_SPEECH about LocalPlayer from server"); + static_cast(player)->playSpeech(); + } + else if (player != 0) + static_cast(player)->playSpeech(); } }; } diff --git a/components/openmw-mp/Base/BasePlayer.hpp b/components/openmw-mp/Base/BasePlayer.hpp index 2a877202f..d96936a6d 100644 --- a/components/openmw-mp/Base/BasePlayer.hpp +++ b/components/openmw-mp/Base/BasePlayer.hpp @@ -271,6 +271,7 @@ namespace mwmp CGStage charGenStage; std::string passw; + std::string sound; Animation animation; bool isWerewolf; diff --git a/components/openmw-mp/Packets/Player/PacketPlayerSpeech.cpp b/components/openmw-mp/Packets/Player/PacketPlayerSpeech.cpp index 38b30be5f..7f4a24cfc 100644 --- a/components/openmw-mp/Packets/Player/PacketPlayerSpeech.cpp +++ b/components/openmw-mp/Packets/Player/PacketPlayerSpeech.cpp @@ -10,5 +10,5 @@ void mwmp::PacketPlayerSpeech::Packet(RakNet::BitStream *bs, bool send) { PlayerPacket::Packet(bs, send); - // Placeholder to be filled in later + RW(player->sound, send); } From 2ca40173711a1b191896021472df1c0d3a61347f Mon Sep 17 00:00:00 2001 From: David Cernat Date: Wed, 1 Nov 2017 22:00:54 +0200 Subject: [PATCH 06/29] [Client] Force position updates for players in animations --- apps/openmw/mwmp/LocalPlayer.cpp | 13 +++++++++++++ components/openmw-mp/Base/BasePlayer.hpp | 1 + 2 files changed, 14 insertions(+) diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 956bad587..98a6497b0 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -67,6 +67,7 @@ LocalPlayer::LocalPlayer() diedSinceArrestAttempt = false; isReceivingQuickKeys = false; + isPlayingAnimation = false; } LocalPlayer::~LocalPlayer() @@ -339,6 +340,16 @@ void LocalPlayer::updatePosition(bool forceUpdate) bool posIsChanging = (direction.pos[0] != 0 || direction.pos[1] != 0 || position.rot[0] != oldRot[0] || position.rot[2] != oldRot[1]); + // Animations can change a player's position without actually creating directional movement, + // so update positions accordingly + if (!posIsChanging && isPlayingAnimation) + { + if (MWBase::Environment::get().getMechanicsManager()->checkAnimationPlaying(ptrPlayer, animation.groupname)) + posIsChanging = true; + else + isPlayingAnimation = false; + } + if (forceUpdate || posIsChanging || posWasChanged) { oldRot[0] = position.rot[0]; @@ -1452,6 +1463,8 @@ void LocalPlayer::playAnimation() { MWBase::Environment::get().getMechanicsManager()->playAnimationGroup(getPlayerPtr(), animation.groupname, animation.mode, animation.count, animation.persist); + + isPlayingAnimation = true; } void LocalPlayer::playSpeech() diff --git a/components/openmw-mp/Base/BasePlayer.hpp b/components/openmw-mp/Base/BasePlayer.hpp index d96936a6d..b6c3d5630 100644 --- a/components/openmw-mp/Base/BasePlayer.hpp +++ b/components/openmw-mp/Base/BasePlayer.hpp @@ -292,6 +292,7 @@ namespace mwmp bool diedSinceArrestAttempt; bool isReceivingQuickKeys; + bool isPlayingAnimation; }; } From 6668b9ab4294922882e0236c9290fc851c0f8c80 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Thu, 23 Nov 2017 00:21:47 +0200 Subject: [PATCH 07/29] [General] Implement ConsoleCommand packet --- apps/openmw-mp/Script/Functions/World.cpp | 20 +++++++++ apps/openmw-mp/Script/Functions/World.hpp | 32 +++++++++++++ apps/openmw/mwbase/windowmanager.hpp | 10 +++++ apps/openmw/mwgui/windowmanagerimp.cpp | 13 ++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 10 +++++ apps/openmw/mwmp/LocalPlayer.hpp | 3 +- apps/openmw/mwmp/WorldEvent.cpp | 45 +++++++++++++++++++ apps/openmw/mwmp/WorldEvent.hpp | 1 + .../mwmp/processors/ProcessorInitializer.cpp | 1 + .../world/ProcessorConsoleCommand.hpp | 9 ++-- components/openmw-mp/Base/BaseEvent.hpp | 4 ++ .../Packets/World/PacketConsoleCommand.cpp | 24 +++++++++- .../Packets/World/PacketConsoleCommand.hpp | 2 +- 13 files changed, 166 insertions(+), 8 deletions(-) diff --git a/apps/openmw-mp/Script/Functions/World.cpp b/apps/openmw-mp/Script/Functions/World.cpp index b8403155a..f5cd6962d 100644 --- a/apps/openmw-mp/Script/Functions/World.cpp +++ b/apps/openmw-mp/Script/Functions/World.cpp @@ -163,6 +163,11 @@ void WorldFunctions::SetEventAction(unsigned char action) noexcept writeEvent.action = action; } +void WorldFunctions::SetEventConsoleCommand(const char* consoleCommand) noexcept +{ + writeEvent.consoleCommand = consoleCommand; +} + void WorldFunctions::SetObjectRefId(const char* refId) noexcept { tempWorldObject.refId = refId; @@ -237,6 +242,15 @@ void WorldFunctions::SetObjectRotation(double x, double y, double z) noexcept tempWorldObject.position.rot[2] = z; } +void WorldFunctions::SetPlayerAsObject(unsigned short pid) noexcept +{ + Player *player; + GET_PLAYER(pid, player, ); + + tempWorldObject.guid = player->guid; + tempWorldObject.isPlayer = true; +} + void WorldFunctions::SetContainerItemRefId(const char* refId) noexcept { tempContainerItem.refId = refId; @@ -320,6 +334,12 @@ void WorldFunctions::SendContainer() noexcept mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_CONTAINER)->Send(writeEvent.guid); } +void WorldFunctions::SendConsoleCommand() noexcept +{ + mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_CONSOLE_COMMAND)->setEvent(&writeEvent); + mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_CONSOLE_COMMAND)->Send(writeEvent.guid); +} + void WorldFunctions::SetHour(unsigned short pid, double hour) noexcept { Player *player; diff --git a/apps/openmw-mp/Script/Functions/World.hpp b/apps/openmw-mp/Script/Functions/World.hpp index cfed8953c..7b343301f 100644 --- a/apps/openmw-mp/Script/Functions/World.hpp +++ b/apps/openmw-mp/Script/Functions/World.hpp @@ -33,6 +33,7 @@ \ {"SetEventCell", WorldFunctions::SetEventCell},\ {"SetEventAction", WorldFunctions::SetEventAction},\ + {"SetEventConsoleCommand", WorldFunctions::SetEventConsoleCommand},\ \ {"SetObjectRefId", WorldFunctions::SetObjectRefId},\ {"SetObjectRefNumIndex", WorldFunctions::SetObjectRefNumIndex},\ @@ -48,6 +49,7 @@ {"SetObjectMasterState", WorldFunctions::SetObjectMasterState},\ {"SetObjectPosition", WorldFunctions::SetObjectPosition},\ {"SetObjectRotation", WorldFunctions::SetObjectRotation},\ + {"SetPlayerAsObject", WorldFunctions::SetPlayerAsObject},\ \ {"SetContainerItemRefId", WorldFunctions::SetContainerItemRefId},\ {"SetContainerItemCount", WorldFunctions::SetContainerItemCount},\ @@ -65,6 +67,7 @@ {"SendObjectState", WorldFunctions::SendObjectState},\ {"SendDoorState", WorldFunctions::SendDoorState},\ {"SendContainer", WorldFunctions::SendContainer},\ + {"SendConsoleCommand", WorldFunctions::SendConsoleCommand},\ \ {"SetHour", WorldFunctions::SetHour},\ {"SetMonth", WorldFunctions::SetMonth},\ @@ -313,6 +316,17 @@ public: */ static void SetEventAction(unsigned char action) noexcept; + /** + * \brief Set the console command of the temporary event stored on the server. + * + * When sent, the command will run once on every object added to the event. If no objects + * have been added, it will run once without any object reference. + * + * \param consoleCommand The console command. + * \return void + */ + static void SetEventConsoleCommand(const char* consoleCommand) noexcept; + /** * \brief Set the refId of the temporary world object stored on the server. * @@ -457,6 +471,15 @@ public: */ static void SetObjectRotation(double x, double y, double z) noexcept; + /** + * \brief Set a player as the object in the temporary world object stored on the server. + * Currently only used for ConsoleCommand packets. + * + * \param pid The pid of the player. + * \return void + */ + static void SetPlayerAsObject(unsigned short pid) noexcept; + /** * \brief Set the refId of the temporary container item stored on the server. * @@ -583,6 +606,15 @@ public: */ static void SendContainer() noexcept; + /** + * \brief Send a ConsoleCommand packet. + * + * It is sent only to the player for whom the current event was initialized. + * + * \return void + */ + static void SendConsoleCommand() noexcept; + /** * \brief Set the game hour for a player and send a GameTime packet to that player. * diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index b6cd36e19..4ae470a1c 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -305,6 +305,16 @@ namespace MWBase virtual void executeInConsole (const std::string& path) = 0; + /* + Start of tes3mp addition + + Allow the execution of console commands from elsewhere in the code + */ + virtual void executeCommandInConsole(const std::string& command) = 0; + /* + End of tes3mp addition + */ + virtual void enableRest() = 0; virtual bool getRestEnabled() = 0; virtual bool getJournalAllowed() = 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 8d98e55d9..87476f2a3 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1450,6 +1450,19 @@ namespace MWGui mConsole->executeFile (path); } + /* + Start of tes3mp addition + + Allow the execution of console commands from elsewhere in the code + */ + void WindowManager::executeCommandInConsole(const std::string& command) + { + mConsole->execute(command); + } + /* + End of tes3mp addition + */ + MWGui::DialogueWindow* WindowManager::getDialogueWindow() { return mDialogueWindow; } MWGui::InventoryWindow* WindowManager::getInventoryWindow() { return mInventoryWindow; } MWGui::CountDialog* WindowManager::getCountDialog() { return mCountDialog; } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 4f5ff1275..3eab95587 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -334,6 +334,16 @@ namespace MWGui virtual void executeInConsole (const std::string& path); + /* + Start of tes3mp addition + + Allow the execution of console commands from elsewhere in the code + */ + virtual void executeCommandInConsole(const std::string& command); + /* + End of tes3mp addition + */ + virtual void enableRest() { mRestAllowed = true; } virtual bool getRestEnabled(); diff --git a/apps/openmw/mwmp/LocalPlayer.hpp b/apps/openmw/mwmp/LocalPlayer.hpp index 30b3f9aab..558d45f1c 100644 --- a/apps/openmw/mwmp/LocalPlayer.hpp +++ b/apps/openmw/mwmp/LocalPlayer.hpp @@ -93,9 +93,10 @@ namespace mwmp void playAnimation(); void playSpeech(); + MWWorld::Ptr getPlayerPtr(); + private: Networking *getNetworking(); - MWWorld::Ptr getPlayerPtr(); }; } diff --git a/apps/openmw/mwmp/WorldEvent.cpp b/apps/openmw/mwmp/WorldEvent.cpp index c7f304ec1..10f57b8aa 100644 --- a/apps/openmw/mwmp/WorldEvent.cpp +++ b/apps/openmw/mwmp/WorldEvent.cpp @@ -432,6 +432,51 @@ void WorldEvent::activateDoors(MWWorld::CellStore* cellStore) } } +void WorldEvent::runConsoleCommands(MWWorld::CellStore* cellStore) +{ + MWBase::WindowManager *windowManager = MWBase::Environment::get().getWindowManager(); + + LOG_APPEND(Log::LOG_VERBOSE, "- console command: %s", consoleCommand.c_str()); + + if (worldObjects.empty()) + { + LOG_APPEND(Log::LOG_VERBOSE, "-- running with no object reference"); + windowManager->executeCommandInConsole(consoleCommand); + } + else + { + for (const auto &worldObject : worldObjects) + { + if (worldObject.isPlayer) + { + LOG_APPEND(Log::LOG_VERBOSE, "-- running on player %s"); + + if (worldObject.guid != Main::get().getLocalPlayer()->guid) + windowManager->setConsoleSelectedObject(PlayerList::getPlayer(worldObject.guid)->getPtr()); + else + windowManager->setConsoleSelectedObject(Main::get().getLocalPlayer()->getPlayerPtr()); + + windowManager->executeCommandInConsole(consoleCommand); + } + else + { + LOG_APPEND(Log::LOG_VERBOSE, "-- running on cellRef: %s, %i, %i", worldObject.refId.c_str(), worldObject.refNumIndex, worldObject.mpNum); + + MWWorld::Ptr ptrFound = cellStore->searchExact(worldObject.refNumIndex, worldObject.mpNum); + + if (ptrFound) + { + LOG_APPEND(Log::LOG_VERBOSE, "-- Found %s, %i, %i", ptrFound.getCellRef().getRefId().c_str(), + ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); + + windowManager->setConsoleSelectedObject(ptrFound); + windowManager->executeCommandInConsole(consoleCommand); + } + } + } + } +} + void WorldEvent::setLocalShorts(MWWorld::CellStore* cellStore) { for (const auto &worldObject : worldObjects) diff --git a/apps/openmw/mwmp/WorldEvent.hpp b/apps/openmw/mwmp/WorldEvent.hpp index fb9650644..a9b1b4429 100644 --- a/apps/openmw/mwmp/WorldEvent.hpp +++ b/apps/openmw/mwmp/WorldEvent.hpp @@ -31,6 +31,7 @@ namespace mwmp void rotateObjects(MWWorld::CellStore* cellStore); void animateObjects(MWWorld::CellStore* cellStore); void activateDoors(MWWorld::CellStore* cellStore); + void runConsoleCommands(MWWorld::CellStore* cellStore); void setLocalShorts(MWWorld::CellStore* cellStore); void setLocalFloats(MWWorld::CellStore* cellStore); diff --git a/apps/openmw/mwmp/processors/ProcessorInitializer.cpp b/apps/openmw/mwmp/processors/ProcessorInitializer.cpp index 254655b18..f0b994486 100644 --- a/apps/openmw/mwmp/processors/ProcessorInitializer.cpp +++ b/apps/openmw/mwmp/processors/ProcessorInitializer.cpp @@ -125,6 +125,7 @@ void ProcessorInitializer() PlayerProcessor::AddProcessor(new ProcessorPlayerStatsDynamic()); PlayerProcessor::AddProcessor(new ProcessorPlayerTopic()); + WorldProcessor::AddProcessor(new ProcessorConsoleCommand()); WorldProcessor::AddProcessor(new ProcessorContainer()); WorldProcessor::AddProcessor(new ProcessorDoorState()); WorldProcessor::AddProcessor(new ProcessorMusicPlay()); diff --git a/apps/openmw/mwmp/processors/world/ProcessorConsoleCommand.hpp b/apps/openmw/mwmp/processors/world/ProcessorConsoleCommand.hpp index 9d6229a89..bf8492733 100644 --- a/apps/openmw/mwmp/processors/world/ProcessorConsoleCommand.hpp +++ b/apps/openmw/mwmp/processors/world/ProcessorConsoleCommand.hpp @@ -1,11 +1,11 @@ #ifndef OPENMW_PROCESSORCONSOLECOMMAND_HPP #define OPENMW_PROCESSORCONSOLECOMMAND_HPP -#include "../WorldProcessor.hpp" +#include "BaseObjectProcessor.hpp" namespace mwmp { - class ProcessorConsoleCommand : public WorldProcessor + class ProcessorConsoleCommand : public BaseObjectProcessor { public: ProcessorConsoleCommand() @@ -15,8 +15,9 @@ namespace mwmp virtual void Do(WorldPacket &packet, WorldEvent &event) { - LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Received %s", strPacketID.c_str()); - //event.runConsoleCommand(); + BaseObjectProcessor::Do(packet, event); + + event.runConsoleCommands(ptrCellStore); } }; } diff --git a/components/openmw-mp/Base/BaseEvent.hpp b/components/openmw-mp/Base/BaseEvent.hpp index 6adb60b7a..19f7e6ea3 100644 --- a/components/openmw-mp/Base/BaseEvent.hpp +++ b/components/openmw-mp/Base/BaseEvent.hpp @@ -55,6 +55,9 @@ namespace mwmp std::vector containerItems; unsigned int containerItemCount; + + RakNet::RakNetGUID guid; // only for events that can also affect players + bool isPlayer; }; class BaseEvent @@ -85,6 +88,7 @@ namespace mwmp unsigned int worldObjectCount; ESM::Cell cell; + std::string consoleCommand; unsigned char action; // 0 - Clear and set in entirety, 1 - Add item, 2 - Remove item, 3 - Request items diff --git a/components/openmw-mp/Packets/World/PacketConsoleCommand.cpp b/components/openmw-mp/Packets/World/PacketConsoleCommand.cpp index 796f7988e..a4f9f8517 100644 --- a/components/openmw-mp/Packets/World/PacketConsoleCommand.cpp +++ b/components/openmw-mp/Packets/World/PacketConsoleCommand.cpp @@ -8,7 +8,27 @@ PacketConsoleCommand::PacketConsoleCommand(RakNet::RakPeerInterface *peer) : Wor packetID = ID_CONSOLE_COMMAND; } -void PacketConsoleCommand::Object(WorldObject &worldObject, bool send) +void PacketConsoleCommand::Packet(RakNet::BitStream *bs, bool send) { - WorldPacket::Object(worldObject, send); + if (!PacketHeader(bs, send)) + return; + + RW(event->consoleCommand, send); + + WorldObject worldObject; + for (unsigned int i = 0; i < event->worldObjectCount; i++) + { + if (send) + worldObject = event->worldObjects.at(i); + + RW(worldObject.isPlayer, send); + + if (worldObject.isPlayer) + RW(worldObject.guid, send); + else + Object(worldObject, send); + + if (!send) + event->worldObjects.push_back(worldObject); + } } diff --git a/components/openmw-mp/Packets/World/PacketConsoleCommand.hpp b/components/openmw-mp/Packets/World/PacketConsoleCommand.hpp index f04d2c247..52f6c6943 100644 --- a/components/openmw-mp/Packets/World/PacketConsoleCommand.hpp +++ b/components/openmw-mp/Packets/World/PacketConsoleCommand.hpp @@ -10,7 +10,7 @@ namespace mwmp public: PacketConsoleCommand(RakNet::RakPeerInterface *peer); - virtual void Object(WorldObject &obj, bool send); + virtual void Packet(RakNet::BitStream *bs, bool send); }; } From 300ca905fcfe15d8c5152aa2148b00e49ce75936 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sat, 25 Nov 2017 13:32:43 +0200 Subject: [PATCH 08/29] [Client] Don't pause game when minimizing window, despite MyGUI issues --- apps/openmw/engine.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 5072cacda..1b4af0592 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -120,8 +120,17 @@ void OMW::Engine::frame(float frametime) // When the window is minimized, pause the game. Currently this *has* to be here to work around a MyGUI bug. // If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures (fixed in MyGUI 3.3.2), // and destroyed widgets will not be deleted (not fixed yet, https://github.com/MyGUI/mygui/issues/21) - if (!mEnvironment.getInputManager()->isWindowVisible()) - return; + + /* + Start of tes3mp change (major) + + The game cannot be paused in multiplayer, so prevent that from happening even here + */ + //if (!mEnvironment.getInputManager()->isWindowVisible()) + // return; + /* + End of tes3mp change (major) + */ // sound if (mUseSound) From 3508a168366c6ef6511cbe49519cf408468764d5 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Mon, 27 Nov 2017 07:39:02 +0200 Subject: [PATCH 09/29] [General] Use GameSettings packet to set ability to rest and wait --- apps/openmw-mp/Script/Functions/Settings.cpp | 24 ++++++++-- apps/openmw-mp/Script/Functions/Settings.hpp | 44 +++++++++++++++---- apps/openmw/mwinput/inputmanagerimp.cpp | 22 ++++++++++ apps/openmw/mwmp/LocalPlayer.cpp | 4 +- .../player/ProcessorGameSettings.hpp | 6 +++ apps/openmw/mwscript/guiextensions.cpp | 28 +++++++++++- components/openmw-mp/Base/BasePlayer.hpp | 4 +- .../Packets/Player/PacketGameSettings.cpp | 4 +- 8 files changed, 118 insertions(+), 18 deletions(-) diff --git a/apps/openmw-mp/Script/Functions/Settings.cpp b/apps/openmw-mp/Script/Functions/Settings.cpp index 36486b17f..c158a282d 100644 --- a/apps/openmw-mp/Script/Functions/Settings.cpp +++ b/apps/openmw-mp/Script/Functions/Settings.cpp @@ -9,7 +9,15 @@ #include using namespace std; -void SettingFunctions::SetConsoleAllow(unsigned short pid, bool state) +void SettingFunctions::SetDifficulty(unsigned short pid, int difficulty) +{ + Player *player; + GET_PLAYER(pid, player, ); + + player->difficulty = difficulty; +} + +void SettingFunctions::SetConsoleAllowed(unsigned short pid, bool state) { Player *player; GET_PLAYER(pid, player,); @@ -17,12 +25,20 @@ void SettingFunctions::SetConsoleAllow(unsigned short pid, bool state) player->consoleAllowed = state; } -void SettingFunctions::SetDifficulty(unsigned short pid, int difficulty) +void SettingFunctions::SetRestAllowed(unsigned short pid, bool state) { Player *player; - GET_PLAYER(pid, player,); + GET_PLAYER(pid, player, ); - player->difficulty = difficulty; + player->restAllowed = state; +} + +void SettingFunctions::SetWaitAllowed(unsigned short pid, bool state) +{ + Player *player; + GET_PLAYER(pid, player, ); + + player->waitAllowed = state; } void SettingFunctions::SendSettings(unsigned short pid) noexcept diff --git a/apps/openmw-mp/Script/Functions/Settings.hpp b/apps/openmw-mp/Script/Functions/Settings.hpp index 62e6d05d3..7c4e9a032 100644 --- a/apps/openmw-mp/Script/Functions/Settings.hpp +++ b/apps/openmw-mp/Script/Functions/Settings.hpp @@ -4,15 +4,29 @@ #include "../Types.hpp" #define SETTINGSAPI \ - {"SetConsoleAllow", SettingFunctions::SetConsoleAllow},\ - {"SetDifficulty", SettingFunctions::SetDifficulty},\ + {"SetDifficulty", SettingFunctions::SetDifficulty},\ + {"SetConsoleAllowed", SettingFunctions::SetConsoleAllowed},\ + {"SetRestAllowed", SettingFunctions::SetRestAllowed},\ + {"SetWaitAllowed", SettingFunctions::SetWaitAllowed},\ \ - {"SendSettings", SettingFunctions::SendSettings} + {"SendSettings", SettingFunctions::SendSettings} class SettingFunctions { public: + /** + * \brief Set the difficulty for a player. + * + * This changes the difficulty for that player in the server memory, but does not by itself + * send a packet. + * + * \param pid The player ID. + * \param bool The difficulty. + * \return void + */ + static void SetDifficulty(unsigned short pid, int difficulty); + /** * \brief Set whether the console is allowed for a player. * @@ -23,19 +37,31 @@ public: * \param bool The console permission state. * \return void */ - static void SetConsoleAllow(unsigned short pid, bool state); + static void SetConsoleAllowed(unsigned short pid, bool state); /** - * \brief Set the difficulty for a player. + * \brief Set whether resting is allowed for a player. * - * This changes the difficulty for that player in the server memory, but does not by itself - * send a packet. + * This changes the resting permission for that player in the server memory, but does not + * by itself send a packet. * * \param pid The player ID. - * \param bool The difficulty. + * \param bool The resting permission state. * \return void */ - static void SetDifficulty(unsigned short pid, int difficulty); + static void SetRestAllowed(unsigned short pid, bool state); + + /** + * \brief Set whether waiting is allowed for a player. + * + * This changes the waiting permission for that player in the server memory, but does not + * by itself send a packet. + * + * \param pid The player ID. + * \param bool The waiting permission state. + * \return void + */ + static void SetWaitAllowed(unsigned short pid, bool state); /** * \brief Send a PlayerSettings packet to the player affected by it. diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 301a73d6f..6e4cd4a97 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1011,6 +1011,28 @@ namespace MWInput MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage2}"); //Nope, return; } + + /* + Start of tes3mp addition + + Prevent resting and waiting if they have been disabled by the server for the local player + */ + int canRest = MWBase::Environment::get().getWorld()->canRest(); + + if (canRest == 0 && !mwmp::Main::get().getLocalPlayer()->restAllowed) + { + MWBase::Environment::get().getWindowManager()->messageBox("You are not allowed to rest."); + return; + } + else if (canRest == 1 && !mwmp::Main::get().getLocalPlayer()->waitAllowed) + { + MWBase::Environment::get().getWindowManager()->messageBox("You are not allowed to wait."); + return; + } + /* + End of tes3mp addition + */ + MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_Rest); //Open rest GUI } diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 98a6497b0..ed578035d 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -48,8 +48,10 @@ LocalPlayer::LocalPlayer() charGenStage.current = 0; charGenStage.end = 1; - consoleAllowed = false; difficulty = 0; + consoleAllowed = false; + restAllowed = true; + waitAllowed = true; ignorePosPacket = false; ignoreJailTeleportation = false; diff --git a/apps/openmw/mwmp/processors/player/ProcessorGameSettings.hpp b/apps/openmw/mwmp/processors/player/ProcessorGameSettings.hpp index a17d92f13..3fa2d71b4 100644 --- a/apps/openmw/mwmp/processors/player/ProcessorGameSettings.hpp +++ b/apps/openmw/mwmp/processors/player/ProcessorGameSettings.hpp @@ -26,6 +26,12 @@ namespace mwmp { MWBase::Environment::get().getWindowManager()->popGuiMode(); } + else if ((MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Rest || + MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_RestBed) && + (!player->restAllowed || !player->waitAllowed)) + { + MWBase::Environment::get().getWindowManager()->popGuiMode(); + } } } } diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index 254da56d6..eeeb102a6 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -1,5 +1,16 @@ #include "guiextensions.hpp" +/* + Start of tes3mp addition + + Include additional headers for multiplayer purposes +*/ +#include "../mwmp/Main.hpp" +#include "../mwmp/LocalPlayer.hpp" +/* + End of tes3mp addition +*/ + #include #include @@ -56,8 +67,21 @@ namespace MWScript MWWorld::Ptr bed = R()(runtime, false); if (bed.isEmpty() || !MWBase::Environment::get().getMechanicsManager()->sleepInBed(MWMechanics::getPlayer(), - bed)) - MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_RestBed); + bed)) + /* + Start of tes3mp change (minor) + + Prevent resting if it has been disabled by the server for the local player + */ + { + if (!mwmp::Main::get().getLocalPlayer()->restAllowed) + MWBase::Environment::get().getWindowManager()->messageBox("You are not allowed to rest."); + else + MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_RestBed); + } + /* + End of tes3mp change (minor) + */ } }; diff --git a/components/openmw-mp/Base/BasePlayer.hpp b/components/openmw-mp/Base/BasePlayer.hpp index b6c3d5630..24b3e20cc 100644 --- a/components/openmw-mp/Base/BasePlayer.hpp +++ b/components/openmw-mp/Base/BasePlayer.hpp @@ -246,8 +246,10 @@ namespace mwmp ESM::ActiveSpells activeSpells; CurrentContainer currentContainer; - bool consoleAllowed; int difficulty; + bool consoleAllowed; + bool restAllowed; + bool waitAllowed; bool ignorePosPacket; diff --git a/components/openmw-mp/Packets/Player/PacketGameSettings.cpp b/components/openmw-mp/Packets/Player/PacketGameSettings.cpp index 4e90d6c34..baee27ab2 100644 --- a/components/openmw-mp/Packets/Player/PacketGameSettings.cpp +++ b/components/openmw-mp/Packets/Player/PacketGameSettings.cpp @@ -13,6 +13,8 @@ void PacketGameSettings::Packet(RakNet::BitStream *bs, bool send) { PlayerPacket::Packet(bs, send); - RW(player->consoleAllowed, send); RW(player->difficulty, send); + RW(player->consoleAllowed, send); + RW(player->restAllowed, send); + RW(player->waitAllowed, send); } From c9c363ebef612d6ce32bf8a606518b43525a5321 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Thu, 30 Nov 2017 12:18:15 +0200 Subject: [PATCH 10/29] [General] Allow GameSettings to set bed & wilderness resting separately --- apps/openmw-mp/Script/Functions/Settings.cpp | 12 +++++++-- apps/openmw-mp/Script/Functions/Settings.hpp | 27 ++++++++++++++----- apps/openmw/mwinput/inputmanagerimp.cpp | 4 +-- apps/openmw/mwmp/LocalPlayer.cpp | 3 ++- .../player/ProcessorGameSettings.hpp | 11 +++----- apps/openmw/mwscript/guiextensions.cpp | 4 +-- components/openmw-mp/Base/BasePlayer.hpp | 3 ++- .../Packets/Player/PacketGameSettings.cpp | 3 ++- 8 files changed, 44 insertions(+), 23 deletions(-) diff --git a/apps/openmw-mp/Script/Functions/Settings.cpp b/apps/openmw-mp/Script/Functions/Settings.cpp index c158a282d..24e914036 100644 --- a/apps/openmw-mp/Script/Functions/Settings.cpp +++ b/apps/openmw-mp/Script/Functions/Settings.cpp @@ -25,12 +25,20 @@ void SettingFunctions::SetConsoleAllowed(unsigned short pid, bool state) player->consoleAllowed = state; } -void SettingFunctions::SetRestAllowed(unsigned short pid, bool state) +void SettingFunctions::SetBedRestAllowed(unsigned short pid, bool state) { Player *player; GET_PLAYER(pid, player, ); - player->restAllowed = state; + player->bedRestAllowed = state; +} + +void SettingFunctions::SetWildernessRestAllowed(unsigned short pid, bool state) +{ + Player *player; + GET_PLAYER(pid, player, ); + + player->wildernessRestAllowed = state; } void SettingFunctions::SetWaitAllowed(unsigned short pid, bool state) diff --git a/apps/openmw-mp/Script/Functions/Settings.hpp b/apps/openmw-mp/Script/Functions/Settings.hpp index 7c4e9a032..e0db786fe 100644 --- a/apps/openmw-mp/Script/Functions/Settings.hpp +++ b/apps/openmw-mp/Script/Functions/Settings.hpp @@ -4,12 +4,13 @@ #include "../Types.hpp" #define SETTINGSAPI \ - {"SetDifficulty", SettingFunctions::SetDifficulty},\ - {"SetConsoleAllowed", SettingFunctions::SetConsoleAllowed},\ - {"SetRestAllowed", SettingFunctions::SetRestAllowed},\ - {"SetWaitAllowed", SettingFunctions::SetWaitAllowed},\ + {"SetDifficulty", SettingFunctions::SetDifficulty},\ + {"SetConsoleAllowed", SettingFunctions::SetConsoleAllowed},\ + {"SetBedRestAllowed", SettingFunctions::SetBedRestAllowed},\ + {"SetWildernessRestAllowed", SettingFunctions::SetWildernessRestAllowed},\ + {"SetWaitAllowed", SettingFunctions::SetWaitAllowed},\ \ - {"SendSettings", SettingFunctions::SendSettings} + {"SendSettings", SettingFunctions::SendSettings} class SettingFunctions { @@ -40,7 +41,7 @@ public: static void SetConsoleAllowed(unsigned short pid, bool state); /** - * \brief Set whether resting is allowed for a player. + * \brief Set whether resting in beds is allowed for a player. * * This changes the resting permission for that player in the server memory, but does not * by itself send a packet. @@ -49,7 +50,19 @@ public: * \param bool The resting permission state. * \return void */ - static void SetRestAllowed(unsigned short pid, bool state); + static void SetBedRestAllowed(unsigned short pid, bool state); + + /** + * \brief Set whether resting in the wilderness is allowed for a player. + * + * This changes the resting permission for that player in the server memory, but does not + * by itself send a packet. + * + * \param pid The player ID. + * \param bool The resting permission state. + * \return void + */ + static void SetWildernessRestAllowed(unsigned short pid, bool state); /** * \brief Set whether waiting is allowed for a player. diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 6e4cd4a97..6ce192559 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -1019,9 +1019,9 @@ namespace MWInput */ int canRest = MWBase::Environment::get().getWorld()->canRest(); - if (canRest == 0 && !mwmp::Main::get().getLocalPlayer()->restAllowed) + if (canRest == 0 && !mwmp::Main::get().getLocalPlayer()->wildernessRestAllowed) { - MWBase::Environment::get().getWindowManager()->messageBox("You are not allowed to rest."); + MWBase::Environment::get().getWindowManager()->messageBox("You are not allowed to rest in the wilderness."); return; } else if (canRest == 1 && !mwmp::Main::get().getLocalPlayer()->waitAllowed) diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index ed578035d..3f464958d 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -50,7 +50,8 @@ LocalPlayer::LocalPlayer() difficulty = 0; consoleAllowed = false; - restAllowed = true; + bedRestAllowed = true; + wildernessRestAllowed = true; waitAllowed = true; ignorePosPacket = false; diff --git a/apps/openmw/mwmp/processors/player/ProcessorGameSettings.hpp b/apps/openmw/mwmp/processors/player/ProcessorGameSettings.hpp index 3fa2d71b4..c668dc897 100644 --- a/apps/openmw/mwmp/processors/player/ProcessorGameSettings.hpp +++ b/apps/openmw/mwmp/processors/player/ProcessorGameSettings.hpp @@ -23,15 +23,12 @@ namespace mwmp if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Console && !player->consoleAllowed) - { MWBase::Environment::get().getWindowManager()->popGuiMode(); - } - else if ((MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Rest || - MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_RestBed) && - (!player->restAllowed || !player->waitAllowed)) - { + else if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Rest && + (!player->wildernessRestAllowed || !player->waitAllowed)) + MWBase::Environment::get().getWindowManager()->popGuiMode(); + else if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_RestBed && !player->bedRestAllowed) MWBase::Environment::get().getWindowManager()->popGuiMode(); - } } } } diff --git a/apps/openmw/mwscript/guiextensions.cpp b/apps/openmw/mwscript/guiextensions.cpp index eeeb102a6..cea502d2e 100644 --- a/apps/openmw/mwscript/guiextensions.cpp +++ b/apps/openmw/mwscript/guiextensions.cpp @@ -74,8 +74,8 @@ namespace MWScript Prevent resting if it has been disabled by the server for the local player */ { - if (!mwmp::Main::get().getLocalPlayer()->restAllowed) - MWBase::Environment::get().getWindowManager()->messageBox("You are not allowed to rest."); + if (!mwmp::Main::get().getLocalPlayer()->bedRestAllowed) + MWBase::Environment::get().getWindowManager()->messageBox("You are not allowed to rest in beds."); else MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_RestBed); } diff --git a/components/openmw-mp/Base/BasePlayer.hpp b/components/openmw-mp/Base/BasePlayer.hpp index 24b3e20cc..480eb9351 100644 --- a/components/openmw-mp/Base/BasePlayer.hpp +++ b/components/openmw-mp/Base/BasePlayer.hpp @@ -248,7 +248,8 @@ namespace mwmp int difficulty; bool consoleAllowed; - bool restAllowed; + bool bedRestAllowed; + bool wildernessRestAllowed; bool waitAllowed; bool ignorePosPacket; diff --git a/components/openmw-mp/Packets/Player/PacketGameSettings.cpp b/components/openmw-mp/Packets/Player/PacketGameSettings.cpp index baee27ab2..c02527e8d 100644 --- a/components/openmw-mp/Packets/Player/PacketGameSettings.cpp +++ b/components/openmw-mp/Packets/Player/PacketGameSettings.cpp @@ -15,6 +15,7 @@ void PacketGameSettings::Packet(RakNet::BitStream *bs, bool send) RW(player->difficulty, send); RW(player->consoleAllowed, send); - RW(player->restAllowed, send); + RW(player->bedRestAllowed, send); + RW(player->wildernessRestAllowed, send); RW(player->waitAllowed, send); } From e8d636ebc3624d1db10b052419aa87cbc2dff8b6 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Thu, 30 Nov 2017 22:37:06 +0200 Subject: [PATCH 11/29] [Server] Rework Get/SetAttributeCurrent into Get/SetAttributeModifier As seen here, attributes don't use the concept of current values, but rather of value modifiers and value damage: https://github.com/OpenMW/openmw/blob/master/apps/openmw/mwmechanics/stat.cpp#L217 --- apps/openmw-mp/Script/Functions/Stats.cpp | 8 ++++---- apps/openmw-mp/Script/Functions/Stats.hpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw-mp/Script/Functions/Stats.cpp b/apps/openmw-mp/Script/Functions/Stats.cpp index 4c5deec13..fd9216469 100644 --- a/apps/openmw-mp/Script/Functions/Stats.cpp +++ b/apps/openmw-mp/Script/Functions/Stats.cpp @@ -217,7 +217,7 @@ int StatsFunctions::GetAttributeBase(unsigned short pid, unsigned short attribut return player->creatureStats.mAttributes[attribute].mBase; } -int StatsFunctions::GetAttributeCurrent(unsigned short pid, unsigned short attribute) noexcept +int StatsFunctions::GetAttributeModifier(unsigned short pid, unsigned short attribute) noexcept { Player *player; GET_PLAYER(pid, player, 0); @@ -225,7 +225,7 @@ int StatsFunctions::GetAttributeCurrent(unsigned short pid, unsigned short attri if (attribute >= Attribute::Length) return 0; - return player->creatureStats.mAttributes[attribute].mCurrent; + return player->creatureStats.mAttributes[attribute].mMod; } int StatsFunctions::GetSkillBase(unsigned short pid, unsigned short skill) noexcept @@ -431,7 +431,7 @@ void StatsFunctions::SetAttributeBase(unsigned short pid, unsigned short attribu player->creatureStats.mAttributes[attribute].mBase = value; } -void StatsFunctions::SetAttributeCurrent(unsigned short pid, unsigned short attribute, int value) noexcept +void StatsFunctions::SetAttributeModifier(unsigned short pid, unsigned short attribute, int value) noexcept { Player *player; GET_PLAYER(pid, player,); @@ -439,7 +439,7 @@ void StatsFunctions::SetAttributeCurrent(unsigned short pid, unsigned short attr if (attribute >= Attribute::Length) return; - player->creatureStats.mAttributes[attribute].mCurrent = value; + player->creatureStats.mAttributes[attribute].mMod = value; } void StatsFunctions::SetSkillBase(unsigned short pid, unsigned short skill, int value) noexcept //TODO: need packet for one value diff --git a/apps/openmw-mp/Script/Functions/Stats.hpp b/apps/openmw-mp/Script/Functions/Stats.hpp index e046ffb6a..6f844aeed 100644 --- a/apps/openmw-mp/Script/Functions/Stats.hpp +++ b/apps/openmw-mp/Script/Functions/Stats.hpp @@ -36,7 +36,7 @@ {"GetFatigueCurrent", StatsFunctions::GetFatigueCurrent},\ \ {"GetAttributeBase", StatsFunctions::GetAttributeBase},\ - {"GetAttributeCurrent", StatsFunctions::GetAttributeCurrent},\ + {"GetAttributeModifier", StatsFunctions::GetAttributeModifier},\ \ {"GetSkillBase", StatsFunctions::GetSkillBase},\ {"GetSkillCurrent", StatsFunctions::GetSkillCurrent},\ @@ -64,7 +64,7 @@ {"SetFatigueCurrent", StatsFunctions::SetFatigueCurrent},\ \ {"SetAttributeBase", StatsFunctions::SetAttributeBase},\ - {"SetAttributeCurrent", StatsFunctions::SetAttributeCurrent},\ + {"SetAttributeModifier", StatsFunctions::SetAttributeModifier},\ \ {"SetSkillBase", StatsFunctions::SetSkillBase},\ {"SetSkillCurrent", StatsFunctions::SetSkillCurrent},\ @@ -113,7 +113,7 @@ public: static double GetFatigueCurrent(unsigned short pid) noexcept; static int GetAttributeBase(unsigned short pid, unsigned short attribute) noexcept; - static int GetAttributeCurrent(unsigned short pid, unsigned short attribute) noexcept; + static int GetAttributeModifier(unsigned short pid, unsigned short attribute) noexcept; static int GetSkillBase(unsigned short pid, unsigned short skill) noexcept; static int GetSkillCurrent(unsigned short pid, unsigned short skill) noexcept; @@ -141,7 +141,7 @@ public: static void SetFatigueCurrent(unsigned short pid, double value) noexcept; static void SetAttributeBase(unsigned short pid, unsigned short attribute, int value) noexcept; - static void SetAttributeCurrent(unsigned short pid, unsigned short attribute, int value) noexcept; + static void SetAttributeModifier(unsigned short pid, unsigned short attribute, int value) noexcept; static void SetSkillBase(unsigned short pid, unsigned short skill, int value) noexcept; static void SetSkillCurrent(unsigned short pid, unsigned short skill, int value) noexcept; From ef6dc61797816dd71d1c8cccb21082f044ef2a6e Mon Sep 17 00:00:00 2001 From: David Cernat Date: Thu, 30 Nov 2017 23:03:34 +0200 Subject: [PATCH 12/29] [Client] Send PlayerAttribute packets when attribute modifiers change --- apps/openmw/mwmp/LocalPlayer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 3f464958d..ba2115969 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -243,7 +243,8 @@ void LocalPlayer::updateAttributes(bool forceUpdate) for (int i = 0; i < 8; ++i) { - if (ptrNpcStats.getAttribute(i).getBase() != creatureStats.mAttributes[i].mBase) + if (ptrNpcStats.getAttribute(i).getBase() != creatureStats.mAttributes[i].mBase || + ptrNpcStats.getAttribute(i).getModifier() != creatureStats.mAttributes[i].mMod) { ptrNpcStats.getAttribute(i).writeState(creatureStats.mAttributes[i]); attributesChanged = true; From 2944be18ae281f44de1436e106b2c2010b1a1cb3 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sat, 2 Dec 2017 09:19:33 +0200 Subject: [PATCH 13/29] [Server] Actually, turn SetAttributeModifier into ClearAttributeModifier There's no way SetAttributeModifier() was going to make sense if, say, a player had drunk 3 different potions fortifying the same attribute and was wearing equipment fortifying it as well. How would one change the sum modifier of those while accounting for each specific effect's duration and magnitude? The only workable solution is to allow the server to clear the modifier. --- apps/openmw-mp/Script/Functions/Stats.cpp | 4 ++-- apps/openmw-mp/Script/Functions/Stats.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/openmw-mp/Script/Functions/Stats.cpp b/apps/openmw-mp/Script/Functions/Stats.cpp index fd9216469..4a18208e0 100644 --- a/apps/openmw-mp/Script/Functions/Stats.cpp +++ b/apps/openmw-mp/Script/Functions/Stats.cpp @@ -431,7 +431,7 @@ void StatsFunctions::SetAttributeBase(unsigned short pid, unsigned short attribu player->creatureStats.mAttributes[attribute].mBase = value; } -void StatsFunctions::SetAttributeModifier(unsigned short pid, unsigned short attribute, int value) noexcept +void StatsFunctions::ClearAttributeModifier(unsigned short pid, unsigned short attribute) noexcept { Player *player; GET_PLAYER(pid, player,); @@ -439,7 +439,7 @@ void StatsFunctions::SetAttributeModifier(unsigned short pid, unsigned short att if (attribute >= Attribute::Length) return; - player->creatureStats.mAttributes[attribute].mMod = value; + player->creatureStats.mAttributes[attribute].mMod = 0; } void StatsFunctions::SetSkillBase(unsigned short pid, unsigned short skill, int value) noexcept //TODO: need packet for one value diff --git a/apps/openmw-mp/Script/Functions/Stats.hpp b/apps/openmw-mp/Script/Functions/Stats.hpp index 6f844aeed..9259b4df4 100644 --- a/apps/openmw-mp/Script/Functions/Stats.hpp +++ b/apps/openmw-mp/Script/Functions/Stats.hpp @@ -64,7 +64,7 @@ {"SetFatigueCurrent", StatsFunctions::SetFatigueCurrent},\ \ {"SetAttributeBase", StatsFunctions::SetAttributeBase},\ - {"SetAttributeModifier", StatsFunctions::SetAttributeModifier},\ + {"ClearAttributeModifier", StatsFunctions::ClearAttributeModifier},\ \ {"SetSkillBase", StatsFunctions::SetSkillBase},\ {"SetSkillCurrent", StatsFunctions::SetSkillCurrent},\ @@ -141,7 +141,7 @@ public: static void SetFatigueCurrent(unsigned short pid, double value) noexcept; static void SetAttributeBase(unsigned short pid, unsigned short attribute, int value) noexcept; - static void SetAttributeModifier(unsigned short pid, unsigned short attribute, int value) noexcept; + static void ClearAttributeModifier(unsigned short pid, unsigned short attribute) noexcept; static void SetSkillBase(unsigned short pid, unsigned short skill, int value) noexcept; static void SetSkillCurrent(unsigned short pid, unsigned short skill, int value) noexcept; From 047ad40b96a5610e71322e9ed5714e1d28038f91 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sat, 2 Dec 2017 09:22:36 +0200 Subject: [PATCH 14/29] [Client] Clear FortifyAttribute effects when server sets modifier to 0 --- apps/openmw/mwmechanics/activespells.cpp | 24 ++++++++++++++++++++++++ apps/openmw/mwmechanics/activespells.hpp | 10 ++++++++++ apps/openmw/mwmp/LocalPlayer.cpp | 7 +++++++ 3 files changed, 41 insertions(+) diff --git a/apps/openmw/mwmechanics/activespells.cpp b/apps/openmw/mwmechanics/activespells.cpp index 90d29f686..9d8fe60c3 100644 --- a/apps/openmw/mwmechanics/activespells.cpp +++ b/apps/openmw/mwmechanics/activespells.cpp @@ -295,6 +295,30 @@ namespace MWMechanics mSpellsChanged = true; } + /* + Start of tes3mp addition + + Allow the purging of an effect for a specific arg (attribute or skill) + */ + void ActiveSpells::purgeEffectByArg(short effectId, int effectArg) + { + for (TContainer::iterator it = mSpells.begin(); it != mSpells.end(); ++it) + { + for (std::vector::iterator effectIt = it->second.mEffects.begin(); + effectIt != it->second.mEffects.end();) + { + if (effectIt->mEffectId == effectId && effectIt->mArg == effectArg) + effectIt = it->second.mEffects.erase(effectIt); + else + ++effectIt; + } + } + mSpellsChanged = true; + } + /* + End of tes3mp addition + */ + void ActiveSpells::clear() { mSpells.clear(); diff --git a/apps/openmw/mwmechanics/activespells.hpp b/apps/openmw/mwmechanics/activespells.hpp index a19c8a51d..7f4c8ea3f 100644 --- a/apps/openmw/mwmechanics/activespells.hpp +++ b/apps/openmw/mwmechanics/activespells.hpp @@ -94,6 +94,16 @@ namespace MWMechanics /// Remove all effects with CASTER_LINKED flag that were cast by \a casterActorId void purge (int casterActorId); + /* + Start of tes3mp addition + + Allow the purging of an effect for a specific arg (attribute or skill) + */ + void purgeEffectByArg(short effectId, int effectArg); + /* + End of tes3mp addition + */ + /// Remove all spells void clear(); diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index ba2115969..b6eb85711 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -19,6 +19,7 @@ #include "../mwinput/inputmanagerimp.hpp" +#include "../mwmechanics/activespells.hpp" #include "../mwmechanics/aitravel.hpp" #include "../mwmechanics/creaturestats.hpp" #include "../mwmechanics/mechanicsmanagerimp.hpp" @@ -790,6 +791,12 @@ void LocalPlayer::setAttributes() for (int i = 0; i < 8; ++i) { + // If the server wants to clear our attribute's non-zero modifier, we need to remove + // the spell effect causing it, to avoid an infinite loop where the effect keeps resetting + // the modifier + if (creatureStats.mAttributes[i].mMod == 0 && ptrCreatureStats->getAttribute(i).getModifier() > 0) + ptrCreatureStats->getActiveSpells().purgeEffectByArg(ESM::MagicEffect::FortifyAttribute, i); + attributeValue.readState(creatureStats.mAttributes[i]); ptrCreatureStats->setAttribute(i, attributeValue); } From e97c9f72a27e4dfcaa541e75395170fed8d6a181 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Mon, 4 Dec 2017 15:06:27 +0200 Subject: [PATCH 15/29] [General] Rework getting/clearing of skill modifiers as with attributes --- apps/openmw-mp/Script/Functions/Stats.cpp | 10 +++++----- apps/openmw-mp/Script/Functions/Stats.hpp | 8 ++++---- apps/openmw/mwmp/LocalPlayer.cpp | 9 ++++++++- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/apps/openmw-mp/Script/Functions/Stats.cpp b/apps/openmw-mp/Script/Functions/Stats.cpp index 4a18208e0..141425246 100644 --- a/apps/openmw-mp/Script/Functions/Stats.cpp +++ b/apps/openmw-mp/Script/Functions/Stats.cpp @@ -239,7 +239,7 @@ int StatsFunctions::GetSkillBase(unsigned short pid, unsigned short skill) noexc return player->npcStats.mSkills[skill].mBase; } -int StatsFunctions::GetSkillCurrent(unsigned short pid, unsigned short skill) noexcept +int StatsFunctions::GetSkillModifier(unsigned short pid, unsigned short skill) noexcept { Player *player; GET_PLAYER(pid, player, 0); @@ -247,7 +247,7 @@ int StatsFunctions::GetSkillCurrent(unsigned short pid, unsigned short skill) no if (skill >= Skill::Length) return 0; - return player->npcStats.mSkills[skill].mCurrent; + return player->npcStats.mSkills[skill].mMod; } double StatsFunctions::GetSkillProgress(unsigned short pid, unsigned short skill) noexcept @@ -442,7 +442,7 @@ void StatsFunctions::ClearAttributeModifier(unsigned short pid, unsigned short a player->creatureStats.mAttributes[attribute].mMod = 0; } -void StatsFunctions::SetSkillBase(unsigned short pid, unsigned short skill, int value) noexcept //TODO: need packet for one value +void StatsFunctions::SetSkillBase(unsigned short pid, unsigned short skill, int value) noexcept { Player *player; GET_PLAYER(pid, player,); @@ -453,7 +453,7 @@ void StatsFunctions::SetSkillBase(unsigned short pid, unsigned short skill, int player->npcStats.mSkills[skill].mBase = value; } -void StatsFunctions::SetSkillCurrent(unsigned short pid, unsigned short skill, int value) noexcept //TODO: need packet for one value +void StatsFunctions::ClearSkillModifier(unsigned short pid, unsigned short skill) noexcept { Player *player; GET_PLAYER(pid, player,); @@ -461,7 +461,7 @@ void StatsFunctions::SetSkillCurrent(unsigned short pid, unsigned short skill, i if (skill >= Skill::Length) return; - player->npcStats.mSkills[skill].mCurrent = value; + player->npcStats.mSkills[skill].mMod = 0; } void StatsFunctions::SetSkillProgress(unsigned short pid, unsigned short skill, double value) noexcept diff --git a/apps/openmw-mp/Script/Functions/Stats.hpp b/apps/openmw-mp/Script/Functions/Stats.hpp index 9259b4df4..ff2421ef7 100644 --- a/apps/openmw-mp/Script/Functions/Stats.hpp +++ b/apps/openmw-mp/Script/Functions/Stats.hpp @@ -39,7 +39,7 @@ {"GetAttributeModifier", StatsFunctions::GetAttributeModifier},\ \ {"GetSkillBase", StatsFunctions::GetSkillBase},\ - {"GetSkillCurrent", StatsFunctions::GetSkillCurrent},\ + {"GetSkillModifier", StatsFunctions::GetSkillModifier},\ {"GetSkillProgress", StatsFunctions::GetSkillProgress},\ {"GetSkillIncrease", StatsFunctions::GetSkillIncrease},\ \ @@ -67,7 +67,7 @@ {"ClearAttributeModifier", StatsFunctions::ClearAttributeModifier},\ \ {"SetSkillBase", StatsFunctions::SetSkillBase},\ - {"SetSkillCurrent", StatsFunctions::SetSkillCurrent},\ + {"ClearSkillModifier", StatsFunctions::ClearSkillModifier},\ {"SetSkillProgress", StatsFunctions::SetSkillProgress},\ {"SetSkillIncrease", StatsFunctions::SetSkillIncrease},\ \ @@ -116,7 +116,7 @@ public: static int GetAttributeModifier(unsigned short pid, unsigned short attribute) noexcept; static int GetSkillBase(unsigned short pid, unsigned short skill) noexcept; - static int GetSkillCurrent(unsigned short pid, unsigned short skill) noexcept; + static int GetSkillModifier(unsigned short pid, unsigned short skill) noexcept; static double GetSkillProgress(unsigned short pid, unsigned short skill) noexcept; static int GetSkillIncrease(unsigned short pid, unsigned int pos) noexcept; @@ -144,7 +144,7 @@ public: static void ClearAttributeModifier(unsigned short pid, unsigned short attribute) noexcept; static void SetSkillBase(unsigned short pid, unsigned short skill, int value) noexcept; - static void SetSkillCurrent(unsigned short pid, unsigned short skill, int value) noexcept; + static void ClearSkillModifier(unsigned short pid, unsigned short skill) noexcept; static void SetSkillProgress(unsigned short pid, unsigned short skill, double value) noexcept; static void SetSkillIncrease(unsigned short pid, unsigned int pos, int value) noexcept; diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index b6eb85711..696bb9155 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -275,7 +275,8 @@ void LocalPlayer::updateSkills(bool forceUpdate) for (int i = 0; i < 27; ++i) { - if (ptrNpcStats.getSkill(i).getBase() != npcStats.mSkills[i].mBase) + if (ptrNpcStats.getSkill(i).getBase() != npcStats.mSkills[i].mBase || + ptrNpcStats.getSkill(i).getModifier() != npcStats.mSkills[i].mMod) { ptrNpcStats.getSkill(i).writeState(npcStats.mSkills[i]); skillsChanged = true; @@ -812,6 +813,12 @@ void LocalPlayer::setSkills() for (int i = 0; i < 27; ++i) { + // If the server wants to clear our skill's non-zero modifier, we need to remove + // the spell effect causing it, to avoid an infinite loop where the effect keeps resetting + // the modifier + if (npcStats.mSkills[i].mMod == 0 && ptrNpcStats->getSkill(i).getModifier() > 0) + ptrNpcStats->getActiveSpells().purgeEffectByArg(ESM::MagicEffect::FortifySkill, i); + skillValue.readState(npcStats.mSkills[i]); ptrNpcStats->setSkill(i, skillValue); } From 0ad9c99cf4c2908a8857f2ac775b896d42ecc14d Mon Sep 17 00:00:00 2001 From: David Cernat Date: Tue, 12 Dec 2017 15:18:56 +0200 Subject: [PATCH 16/29] [Client] Send PlayerInventory packet after completing a vendor trade --- apps/openmw/mwgui/hud.cpp | 14 +++++++------- apps/openmw/mwgui/tradewindow.cpp | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwgui/hud.cpp b/apps/openmw/mwgui/hud.cpp index 9fd6d3ed2..9d6c548d7 100644 --- a/apps/openmw/mwgui/hud.cpp +++ b/apps/openmw/mwgui/hud.cpp @@ -1,5 +1,12 @@ #include "hud.hpp" +#include +#include +#include +#include +#include +#include + /* Start of tes3mp addition @@ -14,13 +21,6 @@ End of tes3mp addition */ -#include -#include -#include -#include -#include -#include - #include #include diff --git a/apps/openmw/mwgui/tradewindow.cpp b/apps/openmw/mwgui/tradewindow.cpp index ca0bb48e8..34b1dc473 100644 --- a/apps/openmw/mwgui/tradewindow.cpp +++ b/apps/openmw/mwgui/tradewindow.cpp @@ -6,6 +6,17 @@ #include #include +/* + Start of tes3mp addition + + Include additional headers for multiplayer purposes +*/ +#include "../mwmp/Main.hpp" +#include "../mwmp/LocalPlayer.hpp" +/* + End of tes3mp addition +*/ + #include #include "../mwbase/environment.hpp" @@ -350,6 +361,16 @@ namespace MWGui mPtr.getClass().getCreatureStats(mPtr).getGoldPool() - mCurrentBalance ); } + /* + Start of tes3mp addition + + Send an ID_PLAYER_INVENTORY packet every time a player completes a trade + */ + mwmp::Main::get().getLocalPlayer()->sendInventory(); + /* + End of tes3mp addition + */ + MWBase::Environment::get().getWindowManager()->getDialogueWindow()->addResponse( MWBase::Environment::get().getWorld()->getStore().get().find("sBarterDialog5")->getString()); From ebf88d12a33565628bc727ba73f0dcda78aef5bf Mon Sep 17 00:00:00 2001 From: David Cernat Date: Wed, 13 Dec 2017 05:46:48 +0200 Subject: [PATCH 17/29] [Client] Send PlayerInventory packet after buying skill training --- apps/openmw/mwgui/trainingwindow.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/apps/openmw/mwgui/trainingwindow.cpp b/apps/openmw/mwgui/trainingwindow.cpp index 82218fef1..5c4980de8 100644 --- a/apps/openmw/mwgui/trainingwindow.cpp +++ b/apps/openmw/mwgui/trainingwindow.cpp @@ -2,6 +2,17 @@ #include +/* + Start of tes3mp addition + + Include additional headers for multiplayer purposes +*/ +#include "../mwmp/Main.hpp" +#include "../mwmp/LocalPlayer.hpp" +/* + End of tes3mp addition +*/ + #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -168,6 +179,16 @@ namespace MWGui // remove gold player.getClass().getContainerStore(player).remove(MWWorld::ContainerStore::sGoldId, price, player); + /* + Start of tes3mp addition + + Send an ID_PLAYER_INVENTORY packet every time a player buys training + */ + mwmp::Main::get().getLocalPlayer()->sendInventory(); + /* + End of tes3mp addition + */ + // add gold to NPC trading gold pool npcStats.setGoldPool(npcStats.getGoldPool() + price); From 535fba0cb35d7f0e1c2f26b0ea63bda95975a77d Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sat, 16 Dec 2017 07:21:02 +0200 Subject: [PATCH 18/29] [Client] Finish drag and drops when arrested or teleported by server --- apps/openmw/mwbase/windowmanager.hpp | 11 +++++++++++ apps/openmw/mwgui/windowmanagerimp.cpp | 14 ++++++++++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 11 +++++++++++ apps/openmw/mwmechanics/aipursue.cpp | 6 ++++-- apps/openmw/mwmp/LocalPlayer.cpp | 21 +++++++++++---------- apps/openmw/mwmp/LocalPlayer.hpp | 2 ++ 6 files changed, 53 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 4ae470a1c..f77134b68 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -198,6 +198,17 @@ namespace MWBase virtual void getMousePosition(int &x, int &y) = 0; virtual void getMousePosition(float &x, float &y) = 0; virtual void setDragDrop(bool dragDrop) = 0; + + /* + Start of tes3mp addition + + Allow the completion of a drag and drop from elsewhere in the code + */ + virtual void finishDragDrop() = 0; + /* + End of tes3mp addition + */ + virtual bool getWorldMouseOver() = 0; virtual bool toggleFogOfWar() = 0; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 87476f2a3..19ef989eb 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -1204,6 +1204,20 @@ namespace MWGui MWBase::Environment::get().getInputManager()->setDragDrop(dragDrop); } + /* + Start of tes3mp addition + + Allow the completion of a drag and drop from elsewhere in the code + */ + void WindowManager::finishDragDrop() + { + if (mDragAndDrop->mIsOnDragAndDrop) + mDragAndDrop->finish(); + } + /* + End of tes3mp addition + */ + void WindowManager::setCursorVisible(bool visible) { mCursorVisible = visible; diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 3eab95587..82df6534c 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -231,6 +231,17 @@ namespace MWGui virtual void getMousePosition(int &x, int &y); virtual void getMousePosition(float &x, float &y); virtual void setDragDrop(bool dragDrop); + + /* + Start of tes3mp addition + + Allow the completion of a drag and drop from elsewhere in the code + */ + virtual void finishDragDrop(); + /* + End of tes3mp addition + */ + virtual bool getWorldMouseOver(); virtual bool toggleFogOfWar(); diff --git a/apps/openmw/mwmechanics/aipursue.cpp b/apps/openmw/mwmechanics/aipursue.cpp index 50a68c8e6..f7e529cfe 100644 --- a/apps/openmw/mwmechanics/aipursue.cpp +++ b/apps/openmw/mwmechanics/aipursue.cpp @@ -83,18 +83,20 @@ bool AiPursue::execute (const MWWorld::Ptr& actor, CharacterController& characte if (pathTo(actor, dest, duration, 100)) { - target.getClass().activate(target,actor).get()->execute(actor); //Arrest player when reached - /* Start of tes3mp addition Record that the player has not died since the last attempt to arrest them + + Close the player's inventory or open container and cancel any drag and drops */ LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "After being pursued by %s, diedSinceArrestAttempt is now false", actor.getCellRef().getRefId().c_str()); mwmp::Main::get().getLocalPlayer()->diedSinceArrestAttempt = false; + mwmp::Main::get().getLocalPlayer()->closeInventoryWindows(); /* End of tes3mp addition */ + target.getClass().activate(target,actor).get()->execute(actor); //Arrest player when reached return true; } diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 696bb9155..9cf6c1df4 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -1,7 +1,3 @@ -// -// Created by koncord on 14.01.16. -// - #include #include @@ -765,6 +761,15 @@ void LocalPlayer::removeSpells() } } +void LocalPlayer::closeInventoryWindows() +{ + if (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Container) || + MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Inventory)) + MWBase::Environment::get().getWindowManager()->popGuiMode(); + + MWBase::Environment::get().getWindowManager()->cancelDragDrop(); +} + void LocalPlayer::setDynamicStats() { MWBase::World *world = MWBase::Environment::get().getWorld(); @@ -877,12 +882,8 @@ void LocalPlayer::setCell() MWWorld::Ptr ptrPlayer = world->getPlayerPtr(); ESM::Position pos; - // To avoid crashes, close any container menus this player may be in - if (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Container)) - { - MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); - MWBase::Environment::get().getWindowManager()->setDragDrop(false); - } + // To avoid crashes, close container windows this player may be in + closeInventoryWindows(); world->getPlayer().setTeleported(true); diff --git a/apps/openmw/mwmp/LocalPlayer.hpp b/apps/openmw/mwmp/LocalPlayer.hpp index 558d45f1c..b39ffab01 100644 --- a/apps/openmw/mwmp/LocalPlayer.hpp +++ b/apps/openmw/mwmp/LocalPlayer.hpp @@ -47,6 +47,8 @@ namespace mwmp void removeItems(); void removeSpells(); + void closeInventoryWindows(); + void setDynamicStats(); void setAttributes(); void setSkills(); From fef6bddc68423eeebf9ff605e9ee16fde90b52b7 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sat, 16 Dec 2017 23:19:54 +0200 Subject: [PATCH 19/29] [Client] Fix typo related to drag and dropping --- apps/openmw/mwmp/LocalPlayer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 9cf6c1df4..13211f61b 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -767,7 +767,7 @@ void LocalPlayer::closeInventoryWindows() MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Inventory)) MWBase::Environment::get().getWindowManager()->popGuiMode(); - MWBase::Environment::get().getWindowManager()->cancelDragDrop(); + MWBase::Environment::get().getWindowManager()->finishDragDrop(); } void LocalPlayer::setDynamicStats() From 993081ba1e980a033d2ee9c1e57117c8bb16322a Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sat, 23 Dec 2017 13:16:38 +0200 Subject: [PATCH 20/29] [General] Add enchantmentCharge to worldObjects and items --- apps/openmw-mp/Script/Functions/Actors.cpp | 10 +- apps/openmw-mp/Script/Functions/Actors.hpp | 128 +++++++------- apps/openmw-mp/Script/Functions/Items.cpp | 24 ++- apps/openmw-mp/Script/Functions/Items.hpp | 40 +++-- apps/openmw-mp/Script/Functions/World.cpp | 21 +++ apps/openmw-mp/Script/Functions/World.hpp | 164 +++++++++++------- apps/openmw/mwmp/LocalPlayer.cpp | 10 +- apps/openmw/mwmp/WorldEvent.cpp | 21 ++- components/openmw-mp/Base/BaseEvent.hpp | 4 +- components/openmw-mp/Base/BaseStructs.hpp | 3 +- .../Packets/Actor/PacketActorEquipment.cpp | 1 + .../Packets/Player/PacketPlayerInventory.cpp | 1 + .../Packets/World/PacketContainer.cpp | 1 + .../Packets/World/PacketObjectPlace.cpp | 1 + 14 files changed, 277 insertions(+), 152 deletions(-) diff --git a/apps/openmw-mp/Script/Functions/Actors.cpp b/apps/openmw-mp/Script/Functions/Actors.cpp index baa71faf9..1f50cbf55 100644 --- a/apps/openmw-mp/Script/Functions/Actors.cpp +++ b/apps/openmw-mp/Script/Functions/Actors.cpp @@ -163,6 +163,11 @@ int ActorFunctions::GetActorEquipmentItemCharge(unsigned int i, unsigned short s return readActorList->baseActors.at(i).equipedItems[slot].charge; } +int ActorFunctions::GetActorEquipmentItemEnchantmentCharge(unsigned int i, unsigned short slot) noexcept +{ + return readActorList->baseActors.at(i).equipedItems[slot].enchantmentCharge; +} + bool ActorFunctions::DoesActorHavePosition(unsigned int i) noexcept { return readActorList->baseActors.at(i).hasPositionData; @@ -262,16 +267,17 @@ void ActorFunctions::SetActorFatigueModified(double value) noexcept tempActor.creatureStats.mDynamic[2].mMod = value; } -void ActorFunctions::EquipActorItem(unsigned short slot, const char *refId, unsigned int count, int charge) noexcept +void ActorFunctions::EquipActorItem(unsigned short slot, const char *refId, unsigned int count, int charge, int enchantmentCharge) noexcept { tempActor.equipedItems[slot].refId = refId; tempActor.equipedItems[slot].count = count; tempActor.equipedItems[slot].charge = charge; + tempActor.equipedItems[slot].enchantmentCharge = enchantmentCharge; } void ActorFunctions::UnequipActorItem(unsigned short slot) noexcept { - ActorFunctions::EquipActorItem(slot, "", 0, -1); + ActorFunctions::EquipActorItem(slot, "", 0, -1, -1); } void ActorFunctions::AddActor() noexcept diff --git a/apps/openmw-mp/Script/Functions/Actors.hpp b/apps/openmw-mp/Script/Functions/Actors.hpp index e95d006f4..c1ae6bce2 100644 --- a/apps/openmw-mp/Script/Functions/Actors.hpp +++ b/apps/openmw-mp/Script/Functions/Actors.hpp @@ -2,76 +2,77 @@ #define OPENMW_ACTORAPI_HPP #define ACTORAPI \ - {"ReadLastActorList", ActorFunctions::ReadLastActorList},\ - {"ReadCellActorList", ActorFunctions::ReadCellActorList},\ - {"InitializeActorList", ActorFunctions::InitializeActorList},\ + {"ReadLastActorList", ActorFunctions::ReadLastActorList},\ + {"ReadCellActorList", ActorFunctions::ReadCellActorList},\ + {"InitializeActorList", ActorFunctions::InitializeActorList},\ \ - {"GetActorListSize", ActorFunctions::GetActorListSize},\ - {"GetActorListAction", ActorFunctions::GetActorListAction},\ + {"GetActorListSize", ActorFunctions::GetActorListSize},\ + {"GetActorListAction", ActorFunctions::GetActorListAction},\ \ - {"GetActorCell", ActorFunctions::GetActorCell},\ - {"GetActorRefId", ActorFunctions::GetActorRefId},\ - {"GetActorRefNumIndex", ActorFunctions::GetActorRefNumIndex},\ - {"GetActorMpNum", ActorFunctions::GetActorMpNum},\ + {"GetActorCell", ActorFunctions::GetActorCell},\ + {"GetActorRefId", ActorFunctions::GetActorRefId},\ + {"GetActorRefNumIndex", ActorFunctions::GetActorRefNumIndex},\ + {"GetActorMpNum", ActorFunctions::GetActorMpNum},\ \ - {"GetActorPosX", ActorFunctions::GetActorPosX},\ - {"GetActorPosY", ActorFunctions::GetActorPosY},\ - {"GetActorPosZ", ActorFunctions::GetActorPosZ},\ - {"GetActorRotX", ActorFunctions::GetActorRotX},\ - {"GetActorRotY", ActorFunctions::GetActorRotY},\ - {"GetActorRotZ", ActorFunctions::GetActorRotZ},\ + {"GetActorPosX", ActorFunctions::GetActorPosX},\ + {"GetActorPosY", ActorFunctions::GetActorPosY},\ + {"GetActorPosZ", ActorFunctions::GetActorPosZ},\ + {"GetActorRotX", ActorFunctions::GetActorRotX},\ + {"GetActorRotY", ActorFunctions::GetActorRotY},\ + {"GetActorRotZ", ActorFunctions::GetActorRotZ},\ \ - {"GetActorHealthBase", ActorFunctions::GetActorHealthBase},\ - {"GetActorHealthCurrent", ActorFunctions::GetActorHealthCurrent},\ - {"GetActorHealthModified", ActorFunctions::GetActorHealthModified},\ - {"GetActorMagickaBase", ActorFunctions::GetActorMagickaBase},\ - {"GetActorMagickaCurrent", ActorFunctions::GetActorMagickaCurrent},\ - {"GetActorMagickaModified", ActorFunctions::GetActorMagickaModified},\ - {"GetActorFatigueBase", ActorFunctions::GetActorFatigueBase},\ - {"GetActorFatigueCurrent", ActorFunctions::GetActorFatigueCurrent},\ - {"GetActorFatigueModified", ActorFunctions::GetActorFatigueModified},\ + {"GetActorHealthBase", ActorFunctions::GetActorHealthBase},\ + {"GetActorHealthCurrent", ActorFunctions::GetActorHealthCurrent},\ + {"GetActorHealthModified", ActorFunctions::GetActorHealthModified},\ + {"GetActorMagickaBase", ActorFunctions::GetActorMagickaBase},\ + {"GetActorMagickaCurrent", ActorFunctions::GetActorMagickaCurrent},\ + {"GetActorMagickaModified", ActorFunctions::GetActorMagickaModified},\ + {"GetActorFatigueBase", ActorFunctions::GetActorFatigueBase},\ + {"GetActorFatigueCurrent", ActorFunctions::GetActorFatigueCurrent},\ + {"GetActorFatigueModified", ActorFunctions::GetActorFatigueModified},\ \ - {"GetActorEquipmentItemRefId", ActorFunctions::GetActorEquipmentItemRefId},\ - {"GetActorEquipmentItemCount", ActorFunctions::GetActorEquipmentItemCount},\ - {"GetActorEquipmentItemCharge", ActorFunctions::GetActorEquipmentItemCharge},\ + {"GetActorEquipmentItemRefId", ActorFunctions::GetActorEquipmentItemRefId},\ + {"GetActorEquipmentItemCount", ActorFunctions::GetActorEquipmentItemCount},\ + {"GetActorEquipmentItemCharge", ActorFunctions::GetActorEquipmentItemCharge},\ + {"GetActorEquipmentItemEnchantmentCharge", ActorFunctions::GetActorEquipmentItemEnchantmentCharge},\ \ - {"DoesActorHavePosition", ActorFunctions::DoesActorHavePosition},\ - {"DoesActorHaveStatsDynamic", ActorFunctions::DoesActorHaveStatsDynamic},\ + {"DoesActorHavePosition", ActorFunctions::DoesActorHavePosition},\ + {"DoesActorHaveStatsDynamic", ActorFunctions::DoesActorHaveStatsDynamic},\ \ - {"SetActorListCell", ActorFunctions::SetActorListCell},\ - {"SetActorListAction", ActorFunctions::SetActorListAction},\ + {"SetActorListCell", ActorFunctions::SetActorListCell},\ + {"SetActorListAction", ActorFunctions::SetActorListAction},\ \ - {"SetActorCell", ActorFunctions::SetActorCell},\ - {"SetActorRefId", ActorFunctions::SetActorRefId},\ - {"SetActorRefNumIndex", ActorFunctions::SetActorRefNumIndex},\ - {"SetActorMpNum", ActorFunctions::SetActorMpNum},\ + {"SetActorCell", ActorFunctions::SetActorCell},\ + {"SetActorRefId", ActorFunctions::SetActorRefId},\ + {"SetActorRefNumIndex", ActorFunctions::SetActorRefNumIndex},\ + {"SetActorMpNum", ActorFunctions::SetActorMpNum},\ \ - {"SetActorPosition", ActorFunctions::SetActorPosition},\ - {"SetActorRotation", ActorFunctions::SetActorRotation},\ + {"SetActorPosition", ActorFunctions::SetActorPosition},\ + {"SetActorRotation", ActorFunctions::SetActorRotation},\ \ - {"SetActorHealthBase", ActorFunctions::SetActorHealthBase},\ - {"SetActorHealthCurrent", ActorFunctions::SetActorHealthCurrent},\ - {"SetActorHealthModified", ActorFunctions::SetActorHealthModified},\ - {"SetActorMagickaBase", ActorFunctions::SetActorMagickaBase},\ - {"SetActorMagickaCurrent", ActorFunctions::SetActorMagickaCurrent},\ - {"SetActorMagickaModified", ActorFunctions::SetActorMagickaModified},\ - {"SetActorFatigueBase", ActorFunctions::SetActorFatigueBase},\ - {"SetActorFatigueCurrent", ActorFunctions::SetActorFatigueCurrent},\ - {"SetActorFatigueModified", ActorFunctions::SetActorFatigueModified},\ + {"SetActorHealthBase", ActorFunctions::SetActorHealthBase},\ + {"SetActorHealthCurrent", ActorFunctions::SetActorHealthCurrent},\ + {"SetActorHealthModified", ActorFunctions::SetActorHealthModified},\ + {"SetActorMagickaBase", ActorFunctions::SetActorMagickaBase},\ + {"SetActorMagickaCurrent", ActorFunctions::SetActorMagickaCurrent},\ + {"SetActorMagickaModified", ActorFunctions::SetActorMagickaModified},\ + {"SetActorFatigueBase", ActorFunctions::SetActorFatigueBase},\ + {"SetActorFatigueCurrent", ActorFunctions::SetActorFatigueCurrent},\ + {"SetActorFatigueModified", ActorFunctions::SetActorFatigueModified},\ \ - {"EquipActorItem", ActorFunctions::EquipActorItem},\ - {"UnequipActorItem", ActorFunctions::UnequipActorItem},\ + {"EquipActorItem", ActorFunctions::EquipActorItem},\ + {"UnequipActorItem", ActorFunctions::UnequipActorItem},\ \ - {"AddActor", ActorFunctions::AddActor},\ + {"AddActor", ActorFunctions::AddActor},\ \ - {"SendActorList", ActorFunctions::SendActorList},\ - {"SendActorAuthority", ActorFunctions::SendActorAuthority},\ - {"SendActorPosition", ActorFunctions::SendActorPosition},\ - {"SendActorStatsDynamic", ActorFunctions::SendActorStatsDynamic},\ - {"SendActorEquipment", ActorFunctions::SendActorEquipment},\ - {"SendActorCellChange", ActorFunctions::SendActorCellChange} - -class ActorFunctions + {"SendActorList", ActorFunctions::SendActorList},\ + {"SendActorAuthority", ActorFunctions::SendActorAuthority},\ + {"SendActorPosition", ActorFunctions::SendActorPosition},\ + {"SendActorStatsDynamic", ActorFunctions::SendActorStatsDynamic},\ + {"SendActorEquipment", ActorFunctions::SendActorEquipment},\ + {"SendActorCellChange", ActorFunctions::SendActorCellChange} + +class ActorFunctions { public: @@ -299,6 +300,16 @@ public: */ static int GetActorEquipmentItemCharge(unsigned int i, unsigned short slot) noexcept; + /** + * \brief Get the enchantment charge of the item in a certain slot of the equipment of the actor at a + * certain index in the read actor list. + * + * \param i The index of the actor. + * \param slot The slot of the equipment item. + * \return The enchantment charge. + */ + static int GetActorEquipmentItemEnchantmentCharge(unsigned int i, unsigned short slot) noexcept; + /** * \brief Check whether there is any positional data for the actor at a certain index in * the read actor list. @@ -478,9 +489,10 @@ public: * \param refId The refId of the item. * \param count The count of the item. * \param charge The charge of the item. + * \param enchantmentCharge The enchantment charge of the item. * \return void */ - static void EquipActorItem(unsigned short slot, const char* refId, unsigned int count, int charge) noexcept; + static void EquipActorItem(unsigned short slot, const char* refId, unsigned int count, int charge, int enchantmentCharge = -1) noexcept; /** * \brief Unequip the item in a certain slot of the equipment of the temporary actor stored diff --git a/apps/openmw-mp/Script/Functions/Items.cpp b/apps/openmw-mp/Script/Functions/Items.cpp index 44d957ef5..7ff6fc8e7 100644 --- a/apps/openmw-mp/Script/Functions/Items.cpp +++ b/apps/openmw-mp/Script/Functions/Items.cpp @@ -35,7 +35,7 @@ unsigned int ItemFunctions::GetInventoryChangesSize(unsigned short pid) noexcept return player->inventoryChanges.count; } -void ItemFunctions::EquipItem(unsigned short pid, unsigned short slot, const char *refId, unsigned int count, int charge) noexcept +void ItemFunctions::EquipItem(unsigned short pid, unsigned short slot, const char *refId, unsigned int count, int charge, int enchantmentCharge) noexcept { Player *player; GET_PLAYER(pid, player,); @@ -43,6 +43,7 @@ void ItemFunctions::EquipItem(unsigned short pid, unsigned short slot, const cha player->equipedItems[slot].refId = refId; player->equipedItems[slot].count = count; player->equipedItems[slot].charge = charge; + player->equipedItems[slot].enchantmentCharge = enchantmentCharge; } void ItemFunctions::UnequipItem(unsigned short pid, unsigned short slot) noexcept @@ -50,10 +51,10 @@ void ItemFunctions::UnequipItem(unsigned short pid, unsigned short slot) noexcep Player *player; GET_PLAYER(pid, player, ); - ItemFunctions::EquipItem(pid, slot, "", 0, -1); + ItemFunctions::EquipItem(pid, slot, "", 0, -1, -1); } -void ItemFunctions::AddItem(unsigned short pid, const char* refId, unsigned int count, int charge) noexcept +void ItemFunctions::AddItem(unsigned short pid, const char* refId, unsigned int count, int charge, int enchantmentCharge) noexcept { Player *player; GET_PLAYER(pid, player, ); @@ -62,6 +63,7 @@ void ItemFunctions::AddItem(unsigned short pid, const char* refId, unsigned int item.refId = refId; item.count = count; item.charge = charge; + item.enchantmentCharge = enchantmentCharge; player->inventoryChanges.items.push_back(item); player->inventoryChanges.action = InventoryChanges::ADD; @@ -115,6 +117,14 @@ int ItemFunctions::GetEquipmentItemCharge(unsigned short pid, unsigned short slo return player->equipedItems[slot].charge; } +int ItemFunctions::GetEquipmentItemEnchantmentCharge(unsigned short pid, unsigned short slot) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + return player->equipedItems[slot].enchantmentCharge; +} + const char *ItemFunctions::GetInventoryItemRefId(unsigned short pid, unsigned int i) noexcept { Player *player; @@ -142,6 +152,14 @@ int ItemFunctions::GetInventoryItemCharge(unsigned short pid, unsigned int i) no return player->inventoryChanges.items.at(i).charge; } +int ItemFunctions::GetInventoryItemEnchantmentCharge(unsigned short pid, unsigned int i) noexcept +{ + Player *player; + GET_PLAYER(pid, player, 0); + + return player->inventoryChanges.items.at(i).enchantmentCharge; +} + void ItemFunctions::SendEquipment(unsigned short pid) noexcept { Player *player; diff --git a/apps/openmw-mp/Script/Functions/Items.hpp b/apps/openmw-mp/Script/Functions/Items.hpp index 6bc87a981..9350be896 100644 --- a/apps/openmw-mp/Script/Functions/Items.hpp +++ b/apps/openmw-mp/Script/Functions/Items.hpp @@ -6,29 +6,31 @@ #define OPENMW_ITEMAPI_HPP #define ITEMAPI \ - {"InitializeInventoryChanges", ItemFunctions::InitializeInventoryChanges},\ + {"InitializeInventoryChanges", ItemFunctions::InitializeInventoryChanges},\ \ - {"GetEquipmentSize", ItemFunctions::GetEquipmentSize},\ - {"GetInventoryChangesSize", ItemFunctions::GetInventoryChangesSize},\ + {"GetEquipmentSize", ItemFunctions::GetEquipmentSize},\ + {"GetInventoryChangesSize", ItemFunctions::GetInventoryChangesSize},\ \ - {"EquipItem", ItemFunctions::EquipItem},\ - {"UnequipItem", ItemFunctions::UnequipItem},\ + {"EquipItem", ItemFunctions::EquipItem},\ + {"UnequipItem", ItemFunctions::UnequipItem},\ \ - {"AddItem", ItemFunctions::AddItem},\ - {"RemoveItem", ItemFunctions::RemoveItem},\ + {"AddItem", ItemFunctions::AddItem},\ + {"RemoveItem", ItemFunctions::RemoveItem},\ \ - {"HasItemEquipped", ItemFunctions::HasItemEquipped},\ + {"HasItemEquipped", ItemFunctions::HasItemEquipped},\ \ - {"GetEquipmentItemRefId", ItemFunctions::GetEquipmentItemRefId},\ - {"GetEquipmentItemCount", ItemFunctions::GetEquipmentItemCount},\ - {"GetEquipmentItemCharge", ItemFunctions::GetEquipmentItemCharge},\ + {"GetEquipmentItemRefId", ItemFunctions::GetEquipmentItemRefId},\ + {"GetEquipmentItemCount", ItemFunctions::GetEquipmentItemCount},\ + {"GetEquipmentItemCharge", ItemFunctions::GetEquipmentItemCharge},\ + {"GetEquipmentItemEnchantmentCharge", ItemFunctions::GetEquipmentItemEnchantmentCharge},\ \ - {"GetInventoryItemRefId", ItemFunctions::GetInventoryItemRefId},\ - {"GetInventoryItemCount", ItemFunctions::GetInventoryItemCount},\ - {"GetInventoryItemCharge", ItemFunctions::GetInventoryItemCharge},\ + {"GetInventoryItemRefId", ItemFunctions::GetInventoryItemRefId},\ + {"GetInventoryItemCount", ItemFunctions::GetInventoryItemCount},\ + {"GetInventoryItemCharge", ItemFunctions::GetInventoryItemCharge},\ + {"GetInventoryItemEnchantmentCharge", ItemFunctions::GetInventoryItemEnchantmentCharge},\ \ - {"SendEquipment", ItemFunctions::SendEquipment},\ - {"SendInventoryChanges", ItemFunctions::SendInventoryChanges} + {"SendEquipment", ItemFunctions::SendEquipment},\ + {"SendInventoryChanges", ItemFunctions::SendInventoryChanges} class ItemFunctions { @@ -39,10 +41,10 @@ public: static int GetEquipmentSize() noexcept; static unsigned int GetInventoryChangesSize(unsigned short pid) noexcept; - static void EquipItem(unsigned short pid, unsigned short slot, const char* refId, unsigned int count, int charge) noexcept; + static void EquipItem(unsigned short pid, unsigned short slot, const char* refId, unsigned int count, int charge, int enchantmentCharge = -1) noexcept; static void UnequipItem(unsigned short pid, unsigned short slot) noexcept; - static void AddItem(unsigned short pid, const char* refId, unsigned int count, int charge) noexcept; + static void AddItem(unsigned short pid, const char* refId, unsigned int count, int charge, int enchantmentCharge = -1) noexcept; static void RemoveItem(unsigned short pid, const char* refId, unsigned short count) noexcept; static bool HasItemEquipped(unsigned short pid, const char* refId); @@ -50,10 +52,12 @@ public: static const char *GetEquipmentItemRefId(unsigned short pid, unsigned short slot) noexcept; static int GetEquipmentItemCount(unsigned short pid, unsigned short slot) noexcept; static int GetEquipmentItemCharge(unsigned short pid, unsigned short slot) noexcept; + static int GetEquipmentItemEnchantmentCharge(unsigned short pid, unsigned short slot) noexcept; static const char *GetInventoryItemRefId(unsigned short pid, unsigned int i) noexcept; static int GetInventoryItemCount(unsigned short pid, unsigned int i) noexcept; static int GetInventoryItemCharge(unsigned short pid, unsigned int i) noexcept; + static int GetInventoryItemEnchantmentCharge(unsigned short pid, unsigned int i) noexcept; static void SendEquipment(unsigned short pid) noexcept; static void SendInventoryChanges(unsigned short pid, bool toOthers = false) noexcept; diff --git a/apps/openmw-mp/Script/Functions/World.cpp b/apps/openmw-mp/Script/Functions/World.cpp index f5cd6962d..5c0f3cc5c 100644 --- a/apps/openmw-mp/Script/Functions/World.cpp +++ b/apps/openmw-mp/Script/Functions/World.cpp @@ -69,6 +69,11 @@ int WorldFunctions::GetObjectCharge(unsigned int i) noexcept return readEvent->worldObjects.at(i).charge; } +int WorldFunctions::GetObjectEnchantmentCharge(unsigned int i) noexcept +{ + return readEvent->worldObjects.at(i).enchantmentCharge; +} + int WorldFunctions::GetObjectGoldValue(unsigned int i) noexcept { return readEvent->worldObjects.at(i).goldValue; @@ -147,6 +152,12 @@ int WorldFunctions::GetContainerItemCharge(unsigned int objectIndex, unsigned in .containerItems.at(itemIndex).charge; } +int WorldFunctions::GetContainerItemEnchantmentCharge(unsigned int objectIndex, unsigned int itemIndex) noexcept +{ + return readEvent->worldObjects.at(objectIndex) + .containerItems.at(itemIndex).enchantmentCharge; +} + int WorldFunctions::GetContainerItemActionCount(unsigned int objectIndex, unsigned int itemIndex) noexcept { return readEvent->worldObjects.at(objectIndex) @@ -193,6 +204,11 @@ void WorldFunctions::SetObjectCharge(int charge) noexcept tempWorldObject.charge = charge; } +void WorldFunctions::SetObjectEnchantmentCharge(int enchantmentCharge) noexcept +{ + tempWorldObject.enchantmentCharge = enchantmentCharge; +} + void WorldFunctions::SetObjectGoldValue(int goldValue) noexcept { tempWorldObject.goldValue = goldValue; @@ -266,6 +282,11 @@ void WorldFunctions::SetContainerItemCharge(int charge) noexcept tempContainerItem.charge = charge; } +void WorldFunctions::SetContainerItemEnchantmentCharge(int enchantmentCharge) noexcept +{ + tempContainerItem.enchantmentCharge = enchantmentCharge; +} + void WorldFunctions::AddWorldObject() noexcept { writeEvent.worldObjects.push_back(tempWorldObject); diff --git a/apps/openmw-mp/Script/Functions/World.hpp b/apps/openmw-mp/Script/Functions/World.hpp index 7b343301f..c3f901bb5 100644 --- a/apps/openmw-mp/Script/Functions/World.hpp +++ b/apps/openmw-mp/Script/Functions/World.hpp @@ -2,78 +2,82 @@ #define OPENMW_WORLDAPI_HPP #define WORLDAPI \ - {"ReadLastEvent", WorldFunctions::ReadLastEvent},\ - {"InitializeEvent", WorldFunctions::InitializeEvent},\ + {"ReadLastEvent", WorldFunctions::ReadLastEvent},\ + {"InitializeEvent", WorldFunctions::InitializeEvent},\ \ - {"GetObjectChangesSize", WorldFunctions::GetObjectChangesSize},\ - {"GetEventAction", WorldFunctions::GetEventAction},\ + {"GetObjectChangesSize", WorldFunctions::GetObjectChangesSize},\ + {"GetEventAction", WorldFunctions::GetEventAction},\ \ - {"GetObjectRefId", WorldFunctions::GetObjectRefId},\ - {"GetObjectRefNumIndex", WorldFunctions::GetObjectRefNumIndex},\ - {"GetObjectMpNum", WorldFunctions::GetObjectMpNum},\ - {"GetObjectCount", WorldFunctions::GetObjectCount},\ - {"GetObjectCharge", WorldFunctions::GetObjectCharge},\ - {"GetObjectGoldValue", WorldFunctions::GetObjectGoldValue},\ - {"GetObjectScale", WorldFunctions::GetObjectScale},\ - {"GetObjectState", WorldFunctions::GetObjectState},\ - {"GetObjectDoorState", WorldFunctions::GetObjectDoorState},\ - {"GetObjectLockLevel", WorldFunctions::GetObjectLockLevel},\ - {"GetObjectPosX", WorldFunctions::GetObjectPosX},\ - {"GetObjectPosY", WorldFunctions::GetObjectPosY},\ - {"GetObjectPosZ", WorldFunctions::GetObjectPosZ},\ - {"GetObjectRotX", WorldFunctions::GetObjectRotX},\ - {"GetObjectRotY", WorldFunctions::GetObjectRotY},\ - {"GetObjectRotZ", WorldFunctions::GetObjectRotZ},\ + {"GetObjectRefId", WorldFunctions::GetObjectRefId},\ + {"GetObjectRefNumIndex", WorldFunctions::GetObjectRefNumIndex},\ + {"GetObjectMpNum", WorldFunctions::GetObjectMpNum},\ + {"GetObjectCount", WorldFunctions::GetObjectCount},\ + {"GetObjectCharge", WorldFunctions::GetObjectCharge},\ + {"GetObjectEnchantmentCharge", WorldFunctions::GetObjectEnchantmentCharge},\ + {"GetObjectGoldValue", WorldFunctions::GetObjectGoldValue},\ + {"GetObjectScale", WorldFunctions::GetObjectScale},\ + {"GetObjectState", WorldFunctions::GetObjectState},\ + {"GetObjectDoorState", WorldFunctions::GetObjectDoorState},\ + {"GetObjectLockLevel", WorldFunctions::GetObjectLockLevel},\ + {"GetObjectPosX", WorldFunctions::GetObjectPosX},\ + {"GetObjectPosY", WorldFunctions::GetObjectPosY},\ + {"GetObjectPosZ", WorldFunctions::GetObjectPosZ},\ + {"GetObjectRotX", WorldFunctions::GetObjectRotX},\ + {"GetObjectRotY", WorldFunctions::GetObjectRotY},\ + {"GetObjectRotZ", WorldFunctions::GetObjectRotZ},\ \ - {"GetContainerChangesSize", WorldFunctions::GetContainerChangesSize},\ - {"GetContainerItemRefId", WorldFunctions::GetContainerItemRefId},\ - {"GetContainerItemCount", WorldFunctions::GetContainerItemCount},\ - {"GetContainerItemCharge", WorldFunctions::GetContainerItemCharge},\ - {"GetContainerItemActionCount", WorldFunctions::GetContainerItemActionCount},\ + {"GetContainerChangesSize", WorldFunctions::GetContainerChangesSize},\ + {"GetContainerItemRefId", WorldFunctions::GetContainerItemRefId},\ + {"GetContainerItemCount", WorldFunctions::GetContainerItemCount},\ + {"GetContainerItemCharge", WorldFunctions::GetContainerItemCharge},\ + {"GetContainerItemEnchantmentCharge", WorldFunctions::GetContainerItemEnchantmentCharge},\ + {"GetContainerItemActionCount", WorldFunctions::GetContainerItemActionCount},\ \ - {"SetEventCell", WorldFunctions::SetEventCell},\ - {"SetEventAction", WorldFunctions::SetEventAction},\ - {"SetEventConsoleCommand", WorldFunctions::SetEventConsoleCommand},\ + {"SetEventCell", WorldFunctions::SetEventCell},\ + {"SetEventAction", WorldFunctions::SetEventAction},\ + {"SetEventConsoleCommand", WorldFunctions::SetEventConsoleCommand},\ \ - {"SetObjectRefId", WorldFunctions::SetObjectRefId},\ - {"SetObjectRefNumIndex", WorldFunctions::SetObjectRefNumIndex},\ - {"SetObjectMpNum", WorldFunctions::SetObjectMpNum},\ - {"SetObjectCount", WorldFunctions::SetObjectCount},\ - {"SetObjectCharge", WorldFunctions::SetObjectCharge},\ - {"SetObjectGoldValue", WorldFunctions::SetObjectGoldValue},\ - {"SetObjectScale", WorldFunctions::SetObjectScale},\ - {"SetObjectState", WorldFunctions::SetObjectState},\ - {"SetObjectDoorState", WorldFunctions::SetObjectDoorState},\ - {"SetObjectLockLevel", WorldFunctions::SetObjectLockLevel},\ - {"SetObjectDisarmState", WorldFunctions::SetObjectDisarmState},\ - {"SetObjectMasterState", WorldFunctions::SetObjectMasterState},\ - {"SetObjectPosition", WorldFunctions::SetObjectPosition},\ - {"SetObjectRotation", WorldFunctions::SetObjectRotation},\ - {"SetPlayerAsObject", WorldFunctions::SetPlayerAsObject},\ + {"SetObjectRefId", WorldFunctions::SetObjectRefId},\ + {"SetObjectRefNumIndex", WorldFunctions::SetObjectRefNumIndex},\ + {"SetObjectMpNum", WorldFunctions::SetObjectMpNum},\ + {"SetObjectCount", WorldFunctions::SetObjectCount},\ + {"SetObjectCharge", WorldFunctions::SetObjectCharge},\ + {"SetObjectEnchantmentCharge", WorldFunctions::SetObjectEnchantmentCharge},\ + {"SetObjectGoldValue", WorldFunctions::SetObjectGoldValue},\ + {"SetObjectScale", WorldFunctions::SetObjectScale},\ + {"SetObjectState", WorldFunctions::SetObjectState},\ + {"SetObjectDoorState", WorldFunctions::SetObjectDoorState},\ + {"SetObjectLockLevel", WorldFunctions::SetObjectLockLevel},\ + {"SetObjectDisarmState", WorldFunctions::SetObjectDisarmState},\ + {"SetObjectMasterState", WorldFunctions::SetObjectMasterState},\ + {"SetObjectPosition", WorldFunctions::SetObjectPosition},\ + {"SetObjectRotation", WorldFunctions::SetObjectRotation},\ + {"SetPlayerAsObject", WorldFunctions::SetPlayerAsObject},\ \ - {"SetContainerItemRefId", WorldFunctions::SetContainerItemRefId},\ - {"SetContainerItemCount", WorldFunctions::SetContainerItemCount},\ - {"SetContainerItemCharge", WorldFunctions::SetContainerItemCharge},\ + {"SetContainerItemRefId", WorldFunctions::SetContainerItemRefId},\ + {"SetContainerItemCount", WorldFunctions::SetContainerItemCount},\ + {"SetContainerItemCharge", WorldFunctions::SetContainerItemCharge},\ + {"SetContainerItemEnchantmentCharge", WorldFunctions::SetContainerItemEnchantmentCharge},\ \ - {"AddWorldObject", WorldFunctions::AddWorldObject},\ - {"AddContainerItem", WorldFunctions::AddContainerItem},\ + {"AddWorldObject", WorldFunctions::AddWorldObject},\ + {"AddContainerItem", WorldFunctions::AddContainerItem},\ \ - {"SendObjectPlace", WorldFunctions::SendObjectPlace},\ - {"SendObjectSpawn", WorldFunctions::SendObjectSpawn},\ - {"SendObjectDelete", WorldFunctions::SendObjectDelete},\ - {"SendObjectLock", WorldFunctions::SendObjectLock},\ - {"SendObjectTrap", WorldFunctions::SendObjectTrap},\ - {"SendObjectScale", WorldFunctions::SendObjectScale},\ - {"SendObjectState", WorldFunctions::SendObjectState},\ - {"SendDoorState", WorldFunctions::SendDoorState},\ - {"SendContainer", WorldFunctions::SendContainer},\ - {"SendConsoleCommand", WorldFunctions::SendConsoleCommand},\ + {"SendObjectPlace", WorldFunctions::SendObjectPlace},\ + {"SendObjectSpawn", WorldFunctions::SendObjectSpawn},\ + {"SendObjectDelete", WorldFunctions::SendObjectDelete},\ + {"SendObjectLock", WorldFunctions::SendObjectLock},\ + {"SendObjectTrap", WorldFunctions::SendObjectTrap},\ + {"SendObjectScale", WorldFunctions::SendObjectScale},\ + {"SendObjectState", WorldFunctions::SendObjectState},\ + {"SendDoorState", WorldFunctions::SendDoorState},\ + {"SendContainer", WorldFunctions::SendContainer},\ + {"SendConsoleCommand", WorldFunctions::SendConsoleCommand},\ \ - {"SetHour", WorldFunctions::SetHour},\ - {"SetMonth", WorldFunctions::SetMonth},\ - {"SetDay", WorldFunctions::SetDay} + {"SetHour", WorldFunctions::SetHour},\ + {"SetMonth", WorldFunctions::SetMonth},\ + {"SetDay", WorldFunctions::SetDay} -class WorldFunctions +class WorldFunctions { public: @@ -148,6 +152,14 @@ public: */ static int GetObjectCharge(unsigned int i) noexcept; + /** + * \brief Get the enchantment charge of the object at a certain index in the read event's object changes. + * + * \param i The index of the object. + * \return The enchantment charge. + */ + static int GetObjectEnchantmentCharge(unsigned int i) noexcept; + /** * \brief Get the gold value of the object at a certain index in the read event's object * changes. @@ -287,6 +299,16 @@ public: */ static int GetContainerItemCharge(unsigned int objectIndex, unsigned int itemIndex) noexcept; + /** + * \brief Get the enchantment charge of the container item at a certain itemIndex in the container changes + * of the object at a certain objectIndex in the read event's object changes. + * + * \param objectIndex The index of the object. + * \param itemIndex The index of the container item. + * \return The enchantment charge. + */ + static int GetContainerItemEnchantmentCharge(unsigned int objectIndex, unsigned int itemIndex) noexcept; + /** * \brief Get the action count of the container item at a certain itemIndex in the container * changes of the object at a certain objectIndex in the read event's object changes. @@ -384,6 +406,16 @@ public: */ static void SetObjectCharge(int charge) noexcept; + /** + * \brief Set the enchantment charge of the temporary world object stored on the server. + * + * Object durabilities are set through this value. + * + * \param charge The enchantment charge. + * \return void + */ + static void SetObjectEnchantmentCharge(int enchantmentCharge) noexcept; + /** * \brief Set the gold value of the temporary world object stored on the server. * @@ -504,6 +536,14 @@ public: */ static void SetContainerItemCharge(int charge) noexcept; + /** + * \brief Set the enchantment charge of the temporary container item stored on the server. + * + * \param charge The enchantment charge. + * \return void + */ + static void SetContainerItemEnchantmentCharge(int enchantmentCharge) noexcept; + /** * \brief Add a copy of the server's temporary world object to the server's temporary event. * diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 13211f61b..62e8c7727 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -450,6 +450,8 @@ void LocalPlayer::updateEquipment(bool forceUpdate) item.refId = it->getCellRef().getRefId(); item.charge = it->getCellRef().getCharge(); + item.enchantmentCharge = it->getCellRef().getEnchantmentCharge(); + if (slot == MWWorld::InventoryStore::Slot_CarriedRight) { MWMechanics::WeaponType weaptype; @@ -467,7 +469,8 @@ void LocalPlayer::updateEquipment(bool forceUpdate) equipmentChanged = true; item.refId = ""; item.count = 0; - item.charge = 0; + item.charge = -1; + item.enchantmentCharge = -1; } } @@ -496,6 +499,7 @@ void LocalPlayer::updateInventory(bool forceUpdate) return true; item.count = iter.getRefData().getCount(); item.charge = iter.getCellRef().getCharge(); + item.enchantmentCharge = iter.getCellRef().getEnchantmentCharge(); return false; }; @@ -671,6 +675,9 @@ void LocalPlayer::addItems() MWWorld::Ptr itemPtr = *ptrStore.add(item.refId, item.count, ptrPlayer); if (item.charge != -1) itemPtr.getCellRef().setCharge(item.charge); + + if (item.enchantmentCharge != -1) + itemPtr.getCellRef().setEnchantmentCharge(item.enchantmentCharge); } catch (std::exception&) { @@ -1188,6 +1195,7 @@ void LocalPlayer::sendInventory() item.count = iter.getRefData().getCount(); item.charge = iter.getCellRef().getCharge(); + item.enchantmentCharge = iter.getCellRef().getEnchantmentCharge(); inventoryChanges.items.push_back(item); } diff --git a/apps/openmw/mwmp/WorldEvent.cpp b/apps/openmw/mwmp/WorldEvent.cpp index 10f57b8aa..7e87d4821 100644 --- a/apps/openmw/mwmp/WorldEvent.cpp +++ b/apps/openmw/mwmp/WorldEvent.cpp @@ -95,6 +95,9 @@ void WorldEvent::editContainers(MWWorld::CellStore* cellStore) if (containerItem.charge > -1) newPtr.getCellRef().setCharge(containerItem.charge); + if (containerItem.enchantmentCharge > -1) + newPtr.getCellRef().setEnchantmentCharge(containerItem.enchantmentCharge); + containerStore.add(newPtr, containerItem.count, ownerPtr, true); } else if (action == BaseEvent::REMOVE) @@ -105,8 +108,9 @@ void WorldEvent::editContainers(MWWorld::CellStore* cellStore) { if (Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), containerItem.refId)) { - if (ptr.getCellRef().getCharge() == containerItem.charge && - ptr.getRefData().getCount() == containerItem.count) + if (ptr.getRefData().getCount() == containerItem.count && + ptr.getCellRef().getCharge() == containerItem.charge && + ptr.getCellRef().getEnchantmentCharge() == containerItem.enchantmentCharge) { // Is this an actor's container? If so, unequip this item if it was equipped if (ptrFound.getClass().isActor()) @@ -153,8 +157,8 @@ void WorldEvent::placeObjects(MWWorld::CellStore* cellStore) { for (const auto &worldObject : worldObjects) { - LOG_APPEND(Log::LOG_VERBOSE, "- cellRef: %s, %i, %i, charge: %i, count: %i", worldObject.refId.c_str(), - worldObject.refNumIndex, worldObject.mpNum, worldObject.charge, worldObject.count); + LOG_APPEND(Log::LOG_VERBOSE, "- cellRef: %s, %i, %i, count: %i, charge: %i, enchantmentCharge: %i", worldObject.refId.c_str(), + worldObject.refNumIndex, worldObject.mpNum, worldObject.count, worldObject.charge, worldObject.enchantmentCharge); MWWorld::Ptr ptrFound = cellStore->searchExact(0, worldObject.mpNum); @@ -164,11 +168,14 @@ void WorldEvent::placeObjects(MWWorld::CellStore* cellStore) MWWorld::ManualRef ref(MWBase::Environment::get().getWorld()->getStore(), worldObject.refId, 1); MWWorld::Ptr newPtr = ref.getPtr(); + if (worldObject.count > 1) + newPtr.getRefData().setCount(worldObject.count); + if (worldObject.charge > -1) newPtr.getCellRef().setCharge(worldObject.charge); - if (worldObject.count > 1) - newPtr.getRefData().setCount(worldObject.count); + if (worldObject.enchantmentCharge > -1) + newPtr.getCellRef().setEnchantmentCharge(worldObject.enchantmentCharge); newPtr.getCellRef().setGoldValue(worldObject.goldValue); newPtr = MWBase::Environment::get().getWorld()->placeObject(newPtr, cellStore, worldObject.position); @@ -580,6 +587,7 @@ void WorldEvent::addObjectPlace(const MWWorld::Ptr& ptr) worldObject.refNumIndex = ptr.getCellRef().getRefNum().mIndex; worldObject.mpNum = 0; worldObject.charge = ptr.getCellRef().getCharge(); + worldObject.enchantmentCharge = ptr.getCellRef().getEnchantmentCharge(); // Make sure we send the RefData position instead of the CellRef one, because that's what // we actually see on this client @@ -944,6 +952,7 @@ void WorldEvent::sendContainers(MWWorld::CellStore* cellStore) containerItem.refId = itemPtr.getCellRef().getRefId(); containerItem.count = itemPtr.getRefData().getCount(); containerItem.charge = itemPtr.getCellRef().getCharge(); + containerItem.enchantmentCharge = itemPtr.getCellRef().getEnchantmentCharge(); worldObject.containerItems.push_back(containerItem); } diff --git a/components/openmw-mp/Base/BaseEvent.hpp b/components/openmw-mp/Base/BaseEvent.hpp index 19f7e6ea3..f7718412c 100644 --- a/components/openmw-mp/Base/BaseEvent.hpp +++ b/components/openmw-mp/Base/BaseEvent.hpp @@ -12,12 +12,13 @@ namespace mwmp std::string refId; int count; int charge; + int enchantmentCharge; int actionCount; inline bool operator==(const ContainerItem& rhs) { - return refId == rhs.refId && count == rhs.count && charge == rhs.charge; + return refId == rhs.refId && count == rhs.count && charge == rhs.charge && enchantmentCharge == rhs.enchantmentCharge; } }; @@ -28,6 +29,7 @@ namespace mwmp int mpNum; int count; int charge; + int enchantmentCharge; int goldValue; ESM::Position position; diff --git a/components/openmw-mp/Base/BaseStructs.hpp b/components/openmw-mp/Base/BaseStructs.hpp index 951ba4222..b915a903c 100644 --- a/components/openmw-mp/Base/BaseStructs.hpp +++ b/components/openmw-mp/Base/BaseStructs.hpp @@ -12,10 +12,11 @@ namespace mwmp std::string refId; int count; int charge; + int enchantmentCharge; inline bool operator==(const Item& rhs) { - return refId == rhs.refId && count == rhs.count && charge == rhs.charge; + return refId == rhs.refId && count == rhs.count && charge == rhs.charge && enchantmentCharge == rhs.enchantmentCharge; } }; diff --git a/components/openmw-mp/Packets/Actor/PacketActorEquipment.cpp b/components/openmw-mp/Packets/Actor/PacketActorEquipment.cpp index 513fd2833..3e613c78d 100644 --- a/components/openmw-mp/Packets/Actor/PacketActorEquipment.cpp +++ b/components/openmw-mp/Packets/Actor/PacketActorEquipment.cpp @@ -16,5 +16,6 @@ void PacketActorEquipment::Actor(BaseActor &actor, bool send) RW(actor.equipedItems[j].refId, send); RW(actor.equipedItems[j].count, send); RW(actor.equipedItems[j].charge, send); + RW(actor.equipedItems[j].enchantmentCharge, send); } } diff --git a/components/openmw-mp/Packets/Player/PacketPlayerInventory.cpp b/components/openmw-mp/Packets/Player/PacketPlayerInventory.cpp index e48c28941..3cb960f33 100644 --- a/components/openmw-mp/Packets/Player/PacketPlayerInventory.cpp +++ b/components/openmw-mp/Packets/Player/PacketPlayerInventory.cpp @@ -36,6 +36,7 @@ void PacketPlayerInventory::Packet(RakNet::BitStream *bs, bool send) RW(item.refId, send, 1); RW(item.count, send); RW(item.charge, send); + RW(item.enchantmentCharge, send); if (!send) player->inventoryChanges.items.push_back(item); diff --git a/components/openmw-mp/Packets/World/PacketContainer.cpp b/components/openmw-mp/Packets/World/PacketContainer.cpp index e35af088a..2e272b523 100644 --- a/components/openmw-mp/Packets/World/PacketContainer.cpp +++ b/components/openmw-mp/Packets/World/PacketContainer.cpp @@ -48,6 +48,7 @@ void PacketContainer::Packet(RakNet::BitStream *bs, bool send) RW(containerItem.refId, send); RW(containerItem.count, send); RW(containerItem.charge, send); + RW(containerItem.enchantmentCharge, send); RW(containerItem.actionCount, send); if (!send) diff --git a/components/openmw-mp/Packets/World/PacketObjectPlace.cpp b/components/openmw-mp/Packets/World/PacketObjectPlace.cpp index 7a13964cb..031913074 100644 --- a/components/openmw-mp/Packets/World/PacketObjectPlace.cpp +++ b/components/openmw-mp/Packets/World/PacketObjectPlace.cpp @@ -14,6 +14,7 @@ void PacketObjectPlace::Object(WorldObject &worldObject, bool send) WorldPacket::Object(worldObject, send); RW(worldObject.count, send); RW(worldObject.charge, send); + RW(worldObject.enchantmentCharge, send); RW(worldObject.goldValue, send); RW(worldObject.position, send); } From 06daddbd278cd77a12c4ebcaee67cdaed7ae519a Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sun, 24 Dec 2017 21:39:38 +0200 Subject: [PATCH 21/29] [Documentation] Update changelog for 0.6.2 --- tes3mp-changelog.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tes3mp-changelog.md b/tes3mp-changelog.md index 3a7aaf3ed..3478edf1b 100644 --- a/tes3mp-changelog.md +++ b/tes3mp-changelog.md @@ -1,3 +1,19 @@ +0.6.2 +----- + +* Packet for quick keys +* Packet for player sounds +* Packet for player animations +* Packet for console commands +* Enchantment charge values are now included in item and object placement packets +* Settings packet can now be used to separately enable or disable resting in beds, resting in the wilderness and waiting +* Changes in attribute and skill modifiers now send their respective packets +* Attribute and skill packets using 0 as a modifier can now remove all attribute or skill fortification effects from a player +* Completion of vendor trades and skill training now sends inventory packets +* Item drag and dropping is now finished when arrested or when moved to another cell by the server +* Window minimization no longer pauses the game +* Actor speech captions are now searched for in dialogues instead of being sent in packets + 0.6.1 ----- From 4f1df7c0c506c307d9d637cdc9d06eb360d4778d Mon Sep 17 00:00:00 2001 From: David Cernat Date: Mon, 25 Dec 2017 03:25:33 +0200 Subject: [PATCH 22/29] [Documentation] Update credits --- tes3mp-credits.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tes3mp-credits.md b/tes3mp-credits.md index ad603c16f..0569e4a00 100644 --- a/tes3mp-credits.md +++ b/tes3mp-credits.md @@ -23,6 +23,13 @@ Community administrators Testman +Community moderators +-------------------- + + Capostrophic + Michael Fitzmayer (mupf) + + Art --- @@ -33,8 +40,7 @@ Special thanks (in alphabetical order) -------------------------------------- Camul - Capostrophic - Dave + David Wery DestinedToDie Gluka Goodevil @@ -45,6 +51,7 @@ Special thanks (in alphabetical order) Jeremiah Lewis Sadlier Luc Keating + Malseph Michael Zagar (Zoops) Olaxan psi29a From bed96e5a3d59dee6b36a8cc5939109eb49dc390d Mon Sep 17 00:00:00 2001 From: David Cernat Date: Mon, 25 Dec 2017 03:26:28 +0200 Subject: [PATCH 23/29] [Client] Remove check of GM_RestBed GUI mode that no longer exists --- apps/openmw/mwmp/processors/player/ProcessorGameSettings.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/openmw/mwmp/processors/player/ProcessorGameSettings.hpp b/apps/openmw/mwmp/processors/player/ProcessorGameSettings.hpp index c668dc897..f5e5aaebd 100644 --- a/apps/openmw/mwmp/processors/player/ProcessorGameSettings.hpp +++ b/apps/openmw/mwmp/processors/player/ProcessorGameSettings.hpp @@ -25,9 +25,7 @@ namespace mwmp if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Console && !player->consoleAllowed) MWBase::Environment::get().getWindowManager()->popGuiMode(); else if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Rest && - (!player->wildernessRestAllowed || !player->waitAllowed)) - MWBase::Environment::get().getWindowManager()->popGuiMode(); - else if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_RestBed && !player->bedRestAllowed) + (!player->bedRestAllowed || !player->wildernessRestAllowed || !player->waitAllowed)) MWBase::Environment::get().getWindowManager()->popGuiMode(); } } From 40e70ebf9cb854c278693445cb8c9bdc0f01c0bb Mon Sep 17 00:00:00 2001 From: David Cernat Date: Mon, 25 Dec 2017 05:08:36 +0200 Subject: [PATCH 24/29] [Client] Fix key focus for chat window --- apps/openmw/mwmp/GUI/GUIChat.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwmp/GUI/GUIChat.cpp b/apps/openmw/mwmp/GUI/GUIChat.cpp index 414f40269..aae62e020 100644 --- a/apps/openmw/mwmp/GUI/GUIChat.cpp +++ b/apps/openmw/mwmp/GUI/GUIChat.cpp @@ -41,6 +41,8 @@ namespace mwmp mHistory->setTextShadow(true); mHistory->setTextShadowColour(MyGUI::Colour::Black); + mHistory->setNeedKeyFocus(false); + windowState = 0; mCommandLine->setVisible(0); delay = 3; // 3 sec. From 5fd9079b26a60d3a8a52299d0ea8146b85323339 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Mon, 25 Dec 2017 05:41:13 +0200 Subject: [PATCH 25/29] [Client] Stop drag and drop when setting player inventory --- apps/openmw/mwmp/LocalPlayer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 674726ef8..b19189429 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -993,6 +993,9 @@ void LocalPlayer::setInventory() MWWorld::Ptr ptrPlayer = getPlayerPtr(); MWWorld::ContainerStore &ptrStore = ptrPlayer.getClass().getContainerStore(ptrPlayer); + // Ensure no item is being drag and dropped + MWBase::Environment::get().getWindowManager()->finishDragDrop(); + // Clear items in inventory ptrStore.clear(); From db0e0d376ed25ab569ce8c6f57a81173946898dc Mon Sep 17 00:00:00 2001 From: David Cernat Date: Tue, 26 Dec 2017 15:04:28 +0200 Subject: [PATCH 26/29] [Client] Use new code to set the console's Ptrs from server scripts Previously, reusing the console's object selection code made it so using the same Ptr twice in a row was akin to clicking on the same object twice in the console window, i.e. the object was deselected the second time around. Additionally, that same code was setting key focus to the hidden console window, preventing players from moving until they activated another window (such as their inventory or chat window). --- apps/openmw/mwbase/windowmanager.hpp | 23 ++++++++++++++++++++ apps/openmw/mwgui/console.cpp | 15 +++++++++++++ apps/openmw/mwgui/console.hpp | 12 +++++++++++ apps/openmw/mwgui/windowmanagerimp.cpp | 29 +++++++++++++++++++++++++ apps/openmw/mwgui/windowmanagerimp.hpp | 23 ++++++++++++++++++++ apps/openmw/mwmp/WorldEvent.cpp | 30 ++++++++++++++++++++------ 6 files changed, 125 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index 52d637c64..11d96f16c 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -152,6 +152,29 @@ namespace MWBase virtual void setConsoleSelectedObject(const MWWorld::Ptr& object) = 0; + /* + Start of tes3mp addition + + Allow the direct setting of a console's Ptr, without the assumption that an object + was clicked and that key focus should be restored to the console window, for console + commands executed via server scripts + */ + virtual void setConsolePtr(const MWWorld::Ptr& object) = 0; + /* + End of tes3mp addition + */ + + /* + Start of tes3mp addition + + Allow the clearing of the console's Ptr from elsewhere in the code, so that + Ptrs used in console commands run from server scripts do not stay selected + */ + virtual void clearConsolePtr() = 0; + /* + End of tes3mp addition + */ + /// Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value) = 0; virtual void setValue (int parSkill, const MWMechanics::SkillValue& value) = 0; diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index e8ac33f6d..b5937ce80 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -439,6 +439,21 @@ namespace MWGui } } + /* + Start of tes3mp addition + + Allow the direct setting of a console's Ptr, without the assumption that an object + was clicked and that key focus should be restored to the console window, for console + commands executed via server scripts + */ + void Console::setPtr(const MWWorld::Ptr& object) + { + mPtr = object; + } + /* + End of tes3mp addition + */ + void Console::onReferenceUnavailable() { setSelectedObject(MWWorld::Ptr()); diff --git a/apps/openmw/mwgui/console.hpp b/apps/openmw/mwgui/console.hpp index bbff34c8d..1848705fc 100644 --- a/apps/openmw/mwgui/console.hpp +++ b/apps/openmw/mwgui/console.hpp @@ -27,6 +27,18 @@ namespace MWGui /// Set the implicit object for script execution void setSelectedObject(const MWWorld::Ptr& object); + /* + Start of tes3mp addition + + Allow the direct setting of a console's Ptr, without the assumption that an object + was clicked and that key focus should be restored to the console window, for console + commands executed via server scripts + */ + void setPtr(const MWWorld::Ptr& object); + /* + End of tes3mp addition + */ + MyGUI::EditBox* mCommandLine; MyGUI::EditBox* mHistory; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index 30cbd6758..a5c3a3b2a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -2021,6 +2021,35 @@ namespace MWGui mConsole->setSelectedObject(object); } + /* + Start of tes3mp addition + + Allow the direct setting of a console's Ptr, without the assumption that an object + was clicked and that key focus should be restored to the console window, for console + commands executed via server scripts + */ + void WindowManager::setConsolePtr(const MWWorld::Ptr &object) + { + mConsole->setPtr(object); + } + /* + End of tes3mp addition + */ + + /* + Start of tes3mp addition + + Allow the clearing of the console's Ptr from elsewhere in the code, so that + Ptrs used in console commands run from server scripts do not stay selected + */ + void WindowManager::clearConsolePtr() + { + mConsole->resetReference(); + } + /* + End of tes3mp addition + */ + std::string WindowManager::correctIconPath(const std::string& path) { return Misc::ResourceHelpers::correctIconPath(path, mResourceSystem->getVFS()); diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 04af36ed1..f1fa3e7c5 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -191,6 +191,29 @@ namespace MWGui virtual void setConsoleSelectedObject(const MWWorld::Ptr& object); + /* + Start of tes3mp addition + + Allow the direct setting of a console's Ptr, without the assumption that an object + was clicked and that key focus should be restored to the console window, for console + commands executed via server scripts + */ + virtual void setConsolePtr(const MWWorld::Ptr& object); + /* + End of tes3mp addition + */ + + /* + Start of tes3mp addition + + Allow the clearing of the console's Ptr from elsewhere in the code, so that + Ptrs used in console commands run from server scripts do not stay selected + */ + virtual void clearConsolePtr(); + /* + End of tes3mp addition + */ + ///< Set value for the given ID. virtual void setValue (const std::string& id, const MWMechanics::AttributeValue& value); virtual void setValue (int parSkill, const MWMechanics::SkillValue& value); diff --git a/apps/openmw/mwmp/WorldEvent.cpp b/apps/openmw/mwmp/WorldEvent.cpp index be39c458a..6e4e0b2eb 100644 --- a/apps/openmw/mwmp/WorldEvent.cpp +++ b/apps/openmw/mwmp/WorldEvent.cpp @@ -447,6 +447,8 @@ void WorldEvent::runConsoleCommands(MWWorld::CellStore* cellStore) if (worldObjects.empty()) { + windowManager->clearConsolePtr(); + LOG_APPEND(Log::LOG_VERBOSE, "-- running with no object reference"); windowManager->executeCommandInConsole(consoleCommand); } @@ -454,16 +456,28 @@ void WorldEvent::runConsoleCommands(MWWorld::CellStore* cellStore) { for (const auto &worldObject : worldObjects) { + windowManager->clearConsolePtr(); + if (worldObject.isPlayer) { - LOG_APPEND(Log::LOG_VERBOSE, "-- running on player %s"); + BasePlayer *player = 0; + + if (worldObject.guid == Main::get().getLocalPlayer()->guid) + { + player = Main::get().getLocalPlayer(); - if (worldObject.guid != Main::get().getLocalPlayer()->guid) - windowManager->setConsoleSelectedObject(PlayerList::getPlayer(worldObject.guid)->getPtr()); - else - windowManager->setConsoleSelectedObject(Main::get().getLocalPlayer()->getPlayerPtr()); + LOG_APPEND(Log::LOG_VERBOSE, "-- running on local player"); + windowManager->setConsolePtr(static_cast(player)->getPlayerPtr()); + windowManager->executeCommandInConsole(consoleCommand); + } + else if (player != 0) + { + player = PlayerList::getPlayer(guid); - windowManager->executeCommandInConsole(consoleCommand); + LOG_APPEND(Log::LOG_VERBOSE, "-- running on player %s", player->npc.mName.c_str()); + windowManager->setConsolePtr(static_cast(player)->getPtr()); + windowManager->executeCommandInConsole(consoleCommand); + } } else { @@ -476,11 +490,13 @@ void WorldEvent::runConsoleCommands(MWWorld::CellStore* cellStore) LOG_APPEND(Log::LOG_VERBOSE, "-- Found %s, %i, %i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum(), ptrFound.getCellRef().getMpNum()); - windowManager->setConsoleSelectedObject(ptrFound); + windowManager->setConsolePtr(ptrFound); windowManager->executeCommandInConsole(consoleCommand); } } } + + windowManager->clearConsolePtr(); } } From 2f4cd6b713fbb5abfd701110ba5dd247c3bb347a Mon Sep 17 00:00:00 2001 From: David Cernat Date: Tue, 26 Dec 2017 19:27:13 +0200 Subject: [PATCH 27/29] [Client] Revert "Merge pull request #1529 from drummyfish/animfix" This reverts commit 45993d3da21105879507772f53a9a25baaf54795, reversing changes made to 3d347730dcdfacb4a9e63b5bbad060abc3c438d8. That commit made players have to wait around 1.5 seconds after each jump before doing a new one. It will be reinstated once its accompanying OpenMW issue at https://bugs.openmw.org/issues/4250 is fixed. --- apps/openmw/mwmechanics/character.cpp | 34 ++++++++------------------- 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 6e6570b00..fbcb7371a 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -390,29 +390,21 @@ void CharacterController::refreshJumpAnims(const WeaponInfo* weap, JumpingState } } - if (!mCurrentJump.empty()) - { - mAnimation->disable(mCurrentJump); - mCurrentJump.clear(); - } - if(mJumpState == JumpState_InAir) { - if (mAnimation->hasAnimation(jumpAnimName)) - { - mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, false, + mAnimation->disable(mCurrentJump); + mCurrentJump = jumpAnimName; + if (mAnimation->hasAnimation("jump")) + mAnimation->play(mCurrentJump, Priority_Jump, jumpmask, false, 1.0f, (startAtLoop?"loop start":"start"), "stop", 0.0f, ~0ul); - mCurrentJump = jumpAnimName; - } } - else if (mJumpState == JumpState_Landing) + else { - if (mAnimation->hasAnimation(jumpAnimName)) - { + mAnimation->disable(mCurrentJump); + mCurrentJump.clear(); + if (mAnimation->hasAnimation("jump")) mAnimation->play(jumpAnimName, Priority_Jump, jumpmask, true, 1.0f, "loop stop", "stop", 0.0f, 0); - mCurrentJump = jumpAnimName; - } } } } @@ -1833,6 +1825,7 @@ void CharacterController::update(float duration) mHasMovedInXY = std::abs(vec.x())+std::abs(vec.y()) > 0.0f; isrunning = isrunning && mHasMovedInXY; + // advance athletics if(mHasMovedInXY && mPtr == getPlayer()) { @@ -1987,8 +1980,7 @@ void CharacterController::update(float duration) } else { - jumpstate = mAnimation->isPlaying(mCurrentJump) ? JumpState_Landing : JumpState_None; - + jumpstate = JumpState_None; vec.z() = 0.0f; inJump = false; @@ -2018,15 +2010,9 @@ void CharacterController::update(float duration) else if(rot.z() != 0.0f && !sneak && !(mPtr == getPlayer() && MWBase::Environment::get().getWorld()->isFirstPerson())) { if(rot.z() > 0.0f) - { movestate = inwater ? CharState_SwimTurnRight : CharState_TurnRight; - mAnimation->disable(mCurrentJump); - } else if(rot.z() < 0.0f) - { movestate = inwater ? CharState_SwimTurnLeft : CharState_TurnLeft; - mAnimation->disable(mCurrentJump); - } } } From 1e2517698d6a6c5a5fb1057f9c4f33e98bc0ddb1 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Fri, 29 Dec 2017 06:17:45 +0200 Subject: [PATCH 28/29] [Server] Send player speech and animation packets only to nearby players --- apps/openmw-mp/Script/Functions/Dialogue.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/openmw-mp/Script/Functions/Dialogue.cpp b/apps/openmw-mp/Script/Functions/Dialogue.cpp index eacf21dcb..fe0380f46 100644 --- a/apps/openmw-mp/Script/Functions/Dialogue.cpp +++ b/apps/openmw-mp/Script/Functions/Dialogue.cpp @@ -64,9 +64,10 @@ void DialogueFunctions::PlayAnimation(unsigned short pid, const char* groupname, player->animation.count = count; player->animation.persist = persist; - mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_ANIM_PLAY)->setPlayer(player); - mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_ANIM_PLAY)->Send(false); - mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_ANIM_PLAY)->Send(true); + mwmp::PlayerPacket *packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_ANIM_PLAY); + packet->setPlayer(player); + packet->Send(false); + player->sendToLoaded(packet); } void DialogueFunctions::PlaySpeech(unsigned short pid, const char* sound) noexcept @@ -76,7 +77,8 @@ void DialogueFunctions::PlaySpeech(unsigned short pid, const char* sound) noexce player->sound = sound; - mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_SPEECH)->setPlayer(player); - mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_SPEECH)->Send(false); - mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_SPEECH)->Send(true); + mwmp::PlayerPacket *packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_SPEECH); + packet->setPlayer(player); + packet->Send(false); + player->sendToLoaded(packet); } From 47a3dc9ff244c916ecc6cf871c12e08ed45fadd9 Mon Sep 17 00:00:00 2001 From: David Cernat Date: Sat, 30 Dec 2017 21:52:30 +0200 Subject: [PATCH 29/29] [Server] Add broadcast argument to functions for sending WorldPackets --- apps/openmw-mp/Script/Functions/Chat.cpp | 1 + apps/openmw-mp/Script/Functions/World.cpp | 100 +++++++++++++++------- apps/openmw-mp/Script/Functions/World.hpp | 50 ++++++----- 3 files changed, 101 insertions(+), 50 deletions(-) diff --git a/apps/openmw-mp/Script/Functions/Chat.cpp b/apps/openmw-mp/Script/Functions/Chat.cpp index 143421e5b..47a3a99fb 100644 --- a/apps/openmw-mp/Script/Functions/Chat.cpp +++ b/apps/openmw-mp/Script/Functions/Chat.cpp @@ -18,6 +18,7 @@ void ScriptFunctions::SendMessage(unsigned short pid, const char *message, bool mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_CHAT_MESSAGE)->setPlayer(player); mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_CHAT_MESSAGE)->Send(false); + if (broadcast) mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_CHAT_MESSAGE)->Send(true); } diff --git a/apps/openmw-mp/Script/Functions/World.cpp b/apps/openmw-mp/Script/Functions/World.cpp index 5c0f3cc5c..871582051 100644 --- a/apps/openmw-mp/Script/Functions/World.cpp +++ b/apps/openmw-mp/Script/Functions/World.cpp @@ -301,64 +301,104 @@ void WorldFunctions::AddContainerItem() noexcept tempContainerItem = emptyContainerItem; } -void WorldFunctions::SendObjectPlace() noexcept +void WorldFunctions::SendObjectPlace(bool broadcast) noexcept { - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_PLACE)->setEvent(&writeEvent); - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_PLACE)->Send(writeEvent.guid); + mwmp::WorldPacket *packet = mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_PLACE); + packet->setEvent(&writeEvent); + packet->Send(false); + + if (broadcast) + packet->Send(true); } -void WorldFunctions::SendObjectSpawn() noexcept +void WorldFunctions::SendObjectSpawn(bool broadcast) noexcept { - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_SPAWN)->setEvent(&writeEvent); - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_SPAWN)->Send(writeEvent.guid); + mwmp::WorldPacket *packet = mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_SPAWN); + packet->setEvent(&writeEvent); + packet->Send(false); + + if (broadcast) + packet->Send(true); } -void WorldFunctions::SendObjectDelete() noexcept +void WorldFunctions::SendObjectDelete(bool broadcast) noexcept { - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_DELETE)->setEvent(&writeEvent); - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_DELETE)->Send(writeEvent.guid); + mwmp::WorldPacket *packet = mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_DELETE); + packet->setEvent(&writeEvent); + packet->Send(false); + + if (broadcast) + packet->Send(true); } -void WorldFunctions::SendObjectLock() noexcept +void WorldFunctions::SendObjectLock(bool broadcast) noexcept { - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_LOCK)->setEvent(&writeEvent); - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_LOCK)->Send(writeEvent.guid); + mwmp::WorldPacket *packet = mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_LOCK); + packet->setEvent(&writeEvent); + packet->Send(false); + + if (broadcast) + packet->Send(true); } -void WorldFunctions::SendObjectTrap() noexcept +void WorldFunctions::SendObjectTrap(bool broadcast) noexcept { - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_TRAP)->setEvent(&writeEvent); - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_TRAP)->Send(writeEvent.guid); + mwmp::WorldPacket *packet = mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_TRAP); + packet->setEvent(&writeEvent); + packet->Send(false); + + if (broadcast) + packet->Send(true); } -void WorldFunctions::SendObjectScale() noexcept +void WorldFunctions::SendObjectScale(bool broadcast) noexcept { - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_SCALE)->setEvent(&writeEvent); - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_SCALE)->Send(writeEvent.guid); + mwmp::WorldPacket *packet = mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_SCALE); + packet->setEvent(&writeEvent); + packet->Send(false); + + if (broadcast) + packet->Send(true); } -void WorldFunctions::SendObjectState() noexcept +void WorldFunctions::SendObjectState(bool broadcast) noexcept { - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_STATE)->setEvent(&writeEvent); - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_STATE)->Send(writeEvent.guid); + mwmp::WorldPacket *packet = mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_OBJECT_STATE); + packet->setEvent(&writeEvent); + packet->Send(false); + + if (broadcast) + packet->Send(true); } -void WorldFunctions::SendDoorState() noexcept +void WorldFunctions::SendDoorState(bool broadcast) noexcept { - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_DOOR_STATE)->setEvent(&writeEvent); - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_DOOR_STATE)->Send(writeEvent.guid); + mwmp::WorldPacket *packet = mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_DOOR_STATE); + packet->setEvent(&writeEvent); + packet->Send(false); + + if (broadcast) + packet->Send(true); } -void WorldFunctions::SendContainer() noexcept +void WorldFunctions::SendContainer(bool broadcast) noexcept { - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_CONTAINER)->setEvent(&writeEvent); - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_CONTAINER)->Send(writeEvent.guid); + mwmp::WorldPacket *packet = mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_CONTAINER); + packet->setEvent(&writeEvent); + packet->Send(false); + + if (broadcast) + packet->Send(true); } -void WorldFunctions::SendConsoleCommand() noexcept +void WorldFunctions::SendConsoleCommand(bool broadcast) noexcept { - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_CONSOLE_COMMAND)->setEvent(&writeEvent); - mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_CONSOLE_COMMAND)->Send(writeEvent.guid); + mwmp::WorldPacket *packet = mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_CONSOLE_COMMAND); + packet->setEvent(&writeEvent); + packet->Send(false); + + if (broadcast) + packet->Send(true); } void WorldFunctions::SetHour(unsigned short pid, double hour) noexcept diff --git a/apps/openmw-mp/Script/Functions/World.hpp b/apps/openmw-mp/Script/Functions/World.hpp index c3f901bb5..485d3a365 100644 --- a/apps/openmw-mp/Script/Functions/World.hpp +++ b/apps/openmw-mp/Script/Functions/World.hpp @@ -568,92 +568,102 @@ public: /** * \brief Send an ObjectPlace packet. * - * It is sent only to the player for whom the current event was initialized. + * \param broadcast Whether this packet should be sent only to the player for whom the current + * event was initialized or to everyone on the server. * * \return void */ - static void SendObjectPlace() noexcept; + static void SendObjectPlace(bool broadcast = false) noexcept; /** * \brief Send an ObjectSpawn packet. * - * It is sent only to the player for whom the current event was initialized. + * \param broadcast Whether this packet should be sent only to the player for whom the current + * event was initialized or to everyone on the server. * * \return void */ - static void SendObjectSpawn() noexcept; + static void SendObjectSpawn(bool broadcast = false) noexcept; /** * \brief Send an ObjectDelete packet. * - * It is sent only to the player for whom the current event was initialized. + * \param broadcast Whether this packet should be sent only to the player for whom the current + * event was initialized or to everyone on the server. * * \return void */ - static void SendObjectDelete() noexcept; + static void SendObjectDelete(bool broadcast = false) noexcept; /** * \brief Send an ObjectLock packet. * - * It is sent only to the player for whom the current event was initialized. + * \param broadcast Whether this packet should be sent only to the player for whom the current + * event was initialized or to everyone on the server. * * \return void */ - static void SendObjectLock() noexcept; + static void SendObjectLock(bool broadcast = false) noexcept; /** * \brief Send an ObjectTrap packet. * - * It is sent only to the player for whom the current event was initialized. + * \param broadcast Whether this packet should be sent only to the player for whom the current + * event was initialized or to everyone on the server. * * \return void */ - static void SendObjectTrap() noexcept; + static void SendObjectTrap(bool broadcast = false) noexcept; /** * \brief Send an ObjectScale packet. * - * It is sent only to the player for whom the current event was initialized. + * \param broadcast Whether this packet should be sent only to the player for whom the current + * event was initialized or to everyone on the server. * * \return void */ - static void SendObjectScale() noexcept; + static void SendObjectScale(bool broadcast = false) noexcept; /** * \brief Send an ObjectState packet. * - * It is sent only to the player for whom the current event was initialized. + * \param broadcast Whether this packet should be sent only to the player for whom the current + * event was initialized or to everyone on the server. * * \return void */ - static void SendObjectState() noexcept; + static void SendObjectState(bool broadcast = false) noexcept; /** * \brief Send a DoorState packet. * - * It is sent only to the player for whom the current event was initialized. + * \param broadcast Whether this packet should be sent only to the player for whom the current + * event was initialized or to everyone on the server. * * \return void */ - static void SendDoorState() noexcept; + static void SendDoorState(bool broadcast = false) noexcept; /** * \brief Send a Container packet. * - * It is sent only to the player for whom the current event was initialized. + * \param broadcast Whether this packet should be sent only to the player for whom the current + * event was initialized or to everyone on the server. * * \return void */ - static void SendContainer() noexcept; + static void SendContainer(bool broadcast = false) noexcept; /** * \brief Send a ConsoleCommand packet. * - * It is sent only to the player for whom the current event was initialized. + * \param broadcast Whether this packet should be sent only to the player for whom the current + * event was initialized or to everyone on the server. * * \return void */ - static void SendConsoleCommand() noexcept; + static void SendConsoleCommand(bool broadcast = false) noexcept; /** * \brief Set the game hour for a player and send a GameTime packet to that player.