diff --git a/README.md b/README.md index 06b36dc20..27bb18070 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ When it's combined with Mads Buvik Sandvei's [fork adding VR support to OpenMW]( * TES3MP version: 0.8.0 * OpenMW version: 0.47.0 -* License: GPLv3 (see [LICENSE](https://github.com/TES3MP/TES3MP/blob/master/LICENSE) for more information) +* License: GPLv3 with additional allowed terms (see [LICENSE](https://github.com/TES3MP/TES3MP/blob/master/LICENSE) for more information) Font Licenses: * DejaVuLGCSansMono.ttf: custom (see [files/mygui/DejaVuFontLicense.txt](https://github.com/TES3MP/TES3MP/blob/master/files/mygui/DejaVuFontLicense.txt) for more information) diff --git a/apps/openmw-mp/Networking.cpp b/apps/openmw-mp/Networking.cpp index d2b0c986c..1ff9cee3c 100644 --- a/apps/openmw-mp/Networking.cpp +++ b/apps/openmw-mp/Networking.cpp @@ -489,7 +489,7 @@ void signalHandler(int signum) { std::cout << "Interrupt signal (" << signum << ") received.\n"; //15 is SIGTERM(Normal OS stop call), 2 is SIGINT(Ctrl+C) - if(signum == 15 or signum == 2) + if(signum == 15 || signum == 2) { killLoop = true; } @@ -507,7 +507,7 @@ int Networking::mainLoop() sigIntHandler.sa_flags = 0; #endif - while (running and !killLoop) + while (running && !killLoop) { #ifndef _WIN32 sigaction(SIGTERM, &sigIntHandler, NULL); diff --git a/apps/openmw-mp/processors/actor/ProcessorActorCellChange.hpp b/apps/openmw-mp/processors/actor/ProcessorActorCellChange.hpp index 3edf48a97..e77698dd0 100644 --- a/apps/openmw-mp/processors/actor/ProcessorActorCellChange.hpp +++ b/apps/openmw-mp/processors/actor/ProcessorActorCellChange.hpp @@ -15,6 +15,7 @@ namespace mwmp void Do(ActorPacket &packet, Player &player, BaseActorList &actorList) override { + bool isAccepted = false; Cell *serverCell = CellController::get()->getCell(&actorList.cell); if (serverCell != nullptr) @@ -31,17 +32,26 @@ namespace mwmp } } - // Only accept regular cell changes from a cell's authority, but accept follower + // If the cell is loaded, only accept regular cell changes from a cell's authority, but accept follower // cell changes from other players if (*serverCell->getAuthority() == actorList.guid || isFollowerCellChange) { serverCell->removeActors(&actorList); + isAccepted = true; + } + } + // If the cell isn't loaded, the packet must be from dialogue or a script, so accept it + else + { + isAccepted = true; + } - Script::Call(player.getId(), actorList.cell.getShortDescription().c_str()); + if (isAccepted) + { + Script::Call(player.getId(), actorList.cell.getShortDescription().c_str()); - // Send this to everyone - packet.Send(true); - } + // Send this to everyone + packet.Send(true); } } }; diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 7eb22d30c..4b6941d5f 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -698,7 +698,15 @@ void OMW::Engine::createWindow(Settings::Manager& settings) { while (!mWindow) { - mWindow = SDL_CreateWindow("OpenMW", pos_x, pos_y, width, height, flags); + /* + Start of tes3mp change (major) + + Rename the window into TES3MP + */ + mWindow = SDL_CreateWindow("TES3MP", pos_x, pos_y, width, height, flags); + /* + End of tes3mp change (major) + */ if (!mWindow) { // Try with a lower AA @@ -776,7 +784,15 @@ void OMW::Engine::createWindow(Settings::Manager& settings) void OMW::Engine::setWindowIcon() { boost::filesystem::ifstream windowIconStream; - std::string windowIcon = (mResDir / "mygui" / "openmw.png").string(); + /* + Start of tes3mp change (major) + + Use TES3MP's logo for the window icon + */ + std::string windowIcon = (mResDir / "mygui" / "tes3mp_logo.png").string(); + /* + End of tes3mp change (major) + */ windowIconStream.open(windowIcon, std::ios_base::in | std::ios_base::binary); if (windowIconStream.fail()) Log(Debug::Error) << "Error: Failed to open " << windowIcon; diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 088ef261f..b71833a4c 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -279,11 +279,23 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat engine.setCompileAll(variables["script-all"].as()); engine.setCompileAllDialogue(variables["script-all-dialogue"].as()); engine.setScriptConsoleMode (variables["script-console"].as()); + + /* + Start of tes3mp change (major) + + Clients should not be allowed to set any of these unilaterally in multiplayer, so + disable them + */ + /* engine.setStartupScript (variables["script-run"].as().toStdString()); engine.setWarningsMode (variables["script-warn"].as()); engine.setScriptBlacklist (variables["script-blacklist"].as().toStdStringVector()); engine.setScriptBlacklistUse (variables["script-blacklist-use"].as()); engine.setSaveGameFile (variables["load-savegame"].as().mPath.string()); + */ + /* + End of tes3mp change (major) + */ // other settings Fallback::Map::init(variables["fallback"].as().mMap); diff --git a/apps/openmw/mwgui/charactercreation.cpp b/apps/openmw/mwgui/charactercreation.cpp index 7ebae6b6f..12c3fd9e2 100644 --- a/apps/openmw/mwgui/charactercreation.cpp +++ b/apps/openmw/mwgui/charactercreation.cpp @@ -17,6 +17,17 @@ #include "../mwworld/esmstore.hpp" #include "../mwworld/player.hpp" +/* + Start of tes3mp addition + + Include additional headers for multiplayer purposes +*/ +#include "../mwmp/Main.hpp" +#include "../mwmp/LocalPlayer.hpp" +/* + End of tes3mp addition +*/ + #include "textinput.hpp" #include "race.hpp" #include "class.hpp" @@ -329,6 +340,16 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); + + /* + Start of tes3mp addition + + Decrease the character generation stage tracked for the LocalPlayer + */ + mwmp::Main::get().getLocalPlayer()->charGenState.currentStage--; + /* + End of tes3mp addition + */ } void CharacterCreation::onReviewActivateDialog(int parDialog) @@ -381,6 +402,16 @@ namespace MWGui selectPickedClass(); handleDialogDone(CSE_ClassChosen, GM_Birth); + + /* + Start of tes3mp addition + + Increase the character generation stage tracked for the LocalPlayer + */ + mwmp::Main::get().getLocalPlayer()->charGenState.currentStage++; + /* + End of tes3mp addition + */ } void CharacterCreation::onPickClassDialogBack() @@ -411,6 +442,16 @@ namespace MWGui break; case ClassChoiceDialog::Class_Back: MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); + + /* + Start of tes3mp addition + + Decrease the character generation stage tracked for the LocalPlayer + */ + mwmp::Main::get().getLocalPlayer()->charGenState.currentStage--; + /* + End of tes3mp addition + */ break; }; @@ -439,6 +480,16 @@ namespace MWGui } handleDialogDone(CSE_NameChosen, GM_Race); + + /* + Start of tes3mp addition + + Increase the character generation stage tracked for the LocalPlayer + */ + mwmp::Main::get().getLocalPlayer()->charGenState.currentStage++; + /* + End of tes3mp addition + */ } void CharacterCreation::selectRace() @@ -477,6 +528,16 @@ namespace MWGui selectRace(); handleDialogDone(CSE_RaceChosen, GM_Class); + + /* + Start of tes3mp addition + + Increase the character generation stage tracked for the LocalPlayer + */ + mwmp::Main::get().getLocalPlayer()->charGenState.currentStage++; + /* + End of tes3mp addition + */ } void CharacterCreation::selectBirthSign() @@ -498,6 +559,16 @@ namespace MWGui selectBirthSign(); handleDialogDone(CSE_BirthSignChosen, GM_Review); + + /* + Start of tes3mp addition + + Increase the character generation stage tracked for the LocalPlayer + */ + mwmp::Main::get().getLocalPlayer()->charGenState.currentStage++; + /* + End of tes3mp addition + */ } void CharacterCreation::onBirthSignDialogBack() @@ -506,6 +577,16 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + + /* + Start of tes3mp addition + + Decrease the character generation stage tracked for the LocalPlayer + */ + mwmp::Main::get().getLocalPlayer()->charGenState.currentStage--; + /* + End of tes3mp addition + */ } void CharacterCreation::selectCreatedClass() @@ -547,6 +628,16 @@ namespace MWGui selectCreatedClass(); handleDialogDone(CSE_ClassChosen, GM_Birth); + + /* + Start of tes3mp addition + + Increase the character generation stage tracked for the LocalPlayer + */ + mwmp::Main::get().getLocalPlayer()->charGenState.currentStage++; + /* + End of tes3mp addition + */ } void CharacterCreation::onCreateClassDialogBack() @@ -556,6 +647,16 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); + + /* + Start of tes3mp addition + + Decrease the character generation stage tracked for the LocalPlayer + */ + mwmp::Main::get().getLocalPlayer()->charGenState.currentStage--; + /* + End of tes3mp addition + */ } void CharacterCreation::onClassQuestionChosen(int _index) @@ -748,6 +849,16 @@ namespace MWGui selectGeneratedClass(); handleDialogDone(CSE_ClassChosen, GM_Birth); + + /* + Start of tes3mp addition + + Increase the character generation stage tracked for the LocalPlayer + */ + mwmp::Main::get().getLocalPlayer()->charGenState.currentStage++; + /* + End of tes3mp addition + */ } CharacterCreation::~CharacterCreation() diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index 4dfc51d45..93fc797b2 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -301,27 +301,33 @@ namespace MWGui /* Start of tes3mp addition - Trigger crimes related to the attempted taking of these items, if applicable - Send an ID_CONTAINER packet every time the Take All button is used on a container */ + mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList(); + objectList->reset(); + objectList->packetOrigin = mwmp::CLIENT_GAMEPLAY; + objectList->cell = *mPtr.getCell()->getCell(); + objectList->action = mwmp::BaseObjectList::REMOVE; + objectList->containerSubAction = mwmp::BaseObjectList::TAKE_ALL; + mwmp::BaseObject baseObject = objectList->getBaseObjectFromPtr(mPtr); + for (size_t i = 0; i < mModel->getItemCount(); ++i) { const ItemStack& item = mModel->getItem(i); + // Trigger crimes related to the attempted taking of these items, if applicable if (!onTakeItem(item, item.mCount)) break; + + objectList->addContainerItem(baseObject, item, item.mCount, item.mCount); } - mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList(); - objectList->reset(); - objectList->packetOrigin = mwmp::CLIENT_GAMEPLAY; - objectList->cell = *mPtr.getCell()->getCell(); - objectList->action = mwmp::BaseObjectList::REMOVE; - objectList->containerSubAction = mwmp::BaseObjectList::TAKE_ALL; - objectList->addEntireContainer(mPtr); - objectList->sendContainer(); + if (baseObject.containerItems.size() > 0) + { + objectList->addBaseObject(baseObject); + objectList->sendContainer(); + } /* End of tes3mp addition */ diff --git a/apps/openmw/mwgui/dialogue.cpp b/apps/openmw/mwgui/dialogue.cpp index 54901eee5..d4db49696 100644 --- a/apps/openmw/mwgui/dialogue.cpp +++ b/apps/openmw/mwgui/dialogue.cpp @@ -469,10 +469,6 @@ namespace MWGui { if (dialogueChoiceType == mwmp::DialogueChoiceType::TOPIC) { - // If we're using a translated version of Morrowind, translate this topic from English into our language - if (MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation()) - topic = MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().getLocalizedTopicId(topic); - onTopicActivated(topic); } else if (dialogueChoiceType == mwmp::DialogueChoiceType::PERSUASION) diff --git a/apps/openmw/mwgui/quickkeysmenu.cpp b/apps/openmw/mwgui/quickkeysmenu.cpp index aee16ba3e..e19690b7d 100644 --- a/apps/openmw/mwgui/quickkeysmenu.cpp +++ b/apps/openmw/mwgui/quickkeysmenu.cpp @@ -514,22 +514,21 @@ namespace MWGui Instead of unilaterally using an item, send an ID_PLAYER_ITEM_USE packet and let the server decide if the item actually gets used */ + /* if (!item.getClass().getEquipmentSlots(item).first.empty() && !store.isEquipped(item)) { - - /* MWBase::Environment::get().getWindowManager()->useItem(item); // make sure that item was successfully equipped if (!store.isEquipped(item)) return; - */ - - mwmp::Main::get().getLocalPlayer()->sendItemUse(item, true, MWMechanics::DrawState_Spell); } - //store.setSelectedEnchantItem(it); - //MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Spell); + store.setSelectedEnchantItem(it); + MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Spell); + */ + + mwmp::Main::get().getLocalPlayer()->sendItemUse(item, true, MWMechanics::DrawState_Spell); /* End of tes3mp change (major) */ diff --git a/apps/openmw/mwgui/waitdialog.cpp b/apps/openmw/mwgui/waitdialog.cpp index 4832319de..58253090e 100644 --- a/apps/openmw/mwgui/waitdialog.cpp +++ b/apps/openmw/mwgui/waitdialog.cpp @@ -154,9 +154,10 @@ namespace MWGui Prevent resting and waiting if they have been disabled by the server for the local player */ - else if (canRest == MWBase::World::Rest_Allowed && !mwmp::Main::get().getLocalPlayer()->wildernessRestAllowed) + else if (canRest == MWBase::World::Rest_Allowed && !mwmp::Main::get().getLocalPlayer()->wildernessRestAllowed && + !mwmp::Main::get().getLocalPlayer()->isUsingBed) { - MWBase::Environment::get().getWindowManager()->messageBox("You are not allowed to rest in the wilderness."); + MWBase::Environment::get().getWindowManager()->messageBox("You are not allowed to rest without a bed."); MWBase::Environment::get().getWindowManager()->popGuiMode(); } else if (canRest == MWBase::World::Rest_OnlyWaiting && !mwmp::Main::get().getLocalPlayer()->waitAllowed && diff --git a/apps/openmw/mwinput/actionmanager.cpp b/apps/openmw/mwinput/actionmanager.cpp index 7116d8a0b..e6557a440 100644 --- a/apps/openmw/mwinput/actionmanager.cpp +++ b/apps/openmw/mwinput/actionmanager.cpp @@ -13,6 +13,7 @@ */ #include "../mwmp/Main.hpp" #include "../mwmp/LocalPlayer.hpp" +#include "../mwmp/GUIController.hpp" /* End of tes3mp addition */ @@ -366,6 +367,19 @@ namespace MWInput void ActionManager::toggleMainMenu() { + /* + Start of tes3mp addition + + Don't allow the main menu to be toggled while TES3MP listboxes are open + */ + if (MWBase::Environment::get().getWindowManager()->getMode() == mwmp::GUIController::GM_TES3MP_ListBox) + { + return; + } + /* + End of tes3mp addition + */ + if (MyGUI::InputManager::getInstance().isModalAny()) { MWBase::Environment::get().getWindowManager()->exitCurrentModal(); diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index e02a81c77..0bf28e47d 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -2479,24 +2479,24 @@ namespace MWMechanics void Actors::cleanupSummonedCreature (MWMechanics::CreatureStats& casterStats, int creatureActorId) { MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(creatureActorId); - if (!ptr.isEmpty()) - { - /* - Start of tes3mp change (major) - Send an ID_OBJECT_DELETE packet every time a summoned creature despawns - */ - if (mwmp::Main::get().getCellController()->hasLocalAuthority(*ptr.getCell()->getCell())) - { - mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList(); - objectList->reset(); - objectList->packetOrigin = mwmp::CLIENT_GAMEPLAY; - objectList->addObjectGeneric(ptr); - objectList->sendObjectDelete(); - } - /* - End of tes3mp change (major) - */ + /* + Start of tes3mp change (major) + + Do a cleanup here and send an ID_OBJECT_DELETE packet every time a summoned creature + despawns for the local player or for a local actor + */ + if (!ptr.isEmpty() && + (casterStats.getActorId() == getPlayer().getClass().getCreatureStats(getPlayer()).getActorId() || mwmp::Main::get().getCellController()->hasLocalAuthority(*ptr.getCell()->getCell()))) + { + mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList(); + objectList->reset(); + objectList->packetOrigin = mwmp::CLIENT_GAMEPLAY; + objectList->addObjectGeneric(ptr); + objectList->sendObjectDelete(); + /* + End of tes3mp change (major) + */ const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get() .search("VFX_Summon_End"); diff --git a/apps/openmw/mwmechanics/alchemy.cpp b/apps/openmw/mwmechanics/alchemy.cpp index 00676e4e6..de9709ba2 100644 --- a/apps/openmw/mwmechanics/alchemy.cpp +++ b/apps/openmw/mwmechanics/alchemy.cpp @@ -553,8 +553,20 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na if (readyStatus == Result_NoEffects) removeIngredients(); + /* + Start of tes3mp change (minor) + + Set avoidSendingInventoryPackets to false again if this has not been a successful + potion creation + */ if (readyStatus != Result_Success) + { + mwmp::Main::get().getLocalPlayer()->avoidSendingInventoryPackets = false; return readyStatus; + } + /* + End of tes3mp change (major) + */ Result result = Result_RandomFailure; int brewedCount = 0; diff --git a/apps/openmw/mwmp/Cell.cpp b/apps/openmw/mwmp/Cell.cpp index fe875d05a..8817da287 100644 --- a/apps/openmw/mwmp/Cell.cpp +++ b/apps/openmw/mwmp/Cell.cpp @@ -79,10 +79,24 @@ void Cell::updateLocal(bool forceUpdate) } else { - // Forcibly update this local actor if its data has never been sent before; - // otherwise, use the current forceUpdate value - if (actor->getPtr().getRefData().isEnabled() && !actor->getPtr().getRefData().isDeleted()) - actor->update(actor->hasSentData ? forceUpdate : true); + if (actor->getPtr().getRefData().isEnabled()) + { + if (actor->getPtr().getRefData().isDeleted()) + { + std::string mapIndex = it->first; + LOG_APPEND(TimedLog::LOG_VERBOSE, "- Deleting LocalActor %s whose reference has been deleted", + mapIndex.c_str(), getShortDescription().c_str()); + cellController->removeLocalActorRecord(mapIndex); + delete actor; + localActors.erase(it++); + } + else + { + // Forcibly update this local actor if its data has never been sent before; + // otherwise, use the current forceUpdate value + actor->update(actor->hasSentData ? forceUpdate : true); + } + } ++it; } @@ -531,7 +545,7 @@ void Cell::initializeDedicatedActors(ActorList& actorList) // If this key doesn't exist, create it if (dedicatedActors.count(mapIndex) == 0) { - MWWorld::Ptr ptrFound = store->searchExact(baseActor.refNum, baseActor.mpNum); + MWWorld::Ptr ptrFound = store->searchExact(baseActor.refNum, baseActor.mpNum, baseActor.refId, true); if (!ptrFound) continue; diff --git a/apps/openmw/mwmp/GUI/GUIChat.cpp b/apps/openmw/mwmp/GUI/GUIChat.cpp index 4d244d6e9..38c3ecd43 100644 --- a/apps/openmw/mwmp/GUI/GUIChat.cpp +++ b/apps/openmw/mwmp/GUI/GUIChat.cpp @@ -39,7 +39,7 @@ namespace mwmp mHistory->setNeedKeyFocus(false); - windowState = 0; + windowState = CHAT_DISABLED; mCommandLine->setVisible(0); delay = 3; // 3 sec. } @@ -49,7 +49,9 @@ namespace mwmp // Give keyboard focus to the combo box whenever the console is // turned on setEditState(0); - windowState = CHAT_ENABLED; + + if (windowState == CHAT_DISABLED) + windowState = CHAT_ENABLED; } void GUIChat::onClose() @@ -114,7 +116,7 @@ namespace mwmp void GUIChat::print(const std::string &msg, const std::string &color) { - if (windowState == 2 && !isVisible()) + if (windowState == CHAT_HIDDENMODE && !isVisible()) { setVisible(true); } diff --git a/apps/openmw/mwmp/GUIController.cpp b/apps/openmw/mwmp/GUIController.cpp index 80123b513..3dda6dc80 100644 --- a/apps/openmw/mwmp/GUIController.cpp +++ b/apps/openmw/mwmp/GUIController.cpp @@ -211,6 +211,11 @@ bool mwmp::GUIController::pressedKey(int key) return false; } +void mwmp::GUIController::changeChatMode() +{ + mChat->pressedChatMode(); +} + bool mwmp::GUIController::getChatEditState() { return mChat->editState; diff --git a/apps/openmw/mwmp/GUIController.hpp b/apps/openmw/mwmp/GUIController.hpp index ccd55bb1e..44dedc4af 100644 --- a/apps/openmw/mwmp/GUIController.hpp +++ b/apps/openmw/mwmp/GUIController.hpp @@ -45,11 +45,13 @@ namespace mwmp void showDialogList(const BasePlayer::GUIMessageBox &guiMessageBox); - bool getChatEditState(); - /// Returns 0 if there was no events bool pressedKey(int key); + void changeChatMode(); + + bool getChatEditState(); + void update(float dt); void processCustomMessageBoxInput(int pressedButton); diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 019a0c4f0..de496bf97 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -155,7 +155,6 @@ bool LocalPlayer::processCharGen() } getNetworking()->getPlayerPacket(ID_PLAYER_CHARGEN)->setPlayer(this); getNetworking()->getPlayerPacket(ID_PLAYER_CHARGEN)->Send(); - charGenState.currentStage++; return false; } diff --git a/apps/openmw/mwmp/ObjectList.cpp b/apps/openmw/mwmp/ObjectList.cpp index ad692816d..8136f9377 100644 --- a/apps/openmw/mwmp/ObjectList.cpp +++ b/apps/openmw/mwmp/ObjectList.cpp @@ -112,6 +112,22 @@ void ObjectList::addContainerItem(mwmp::BaseObject& baseObject, const MWWorld::P baseObject.containerItems.push_back(containerItem); } +void ObjectList::addContainerItem(mwmp::BaseObject& baseObject, const MWGui::ItemStack& itemStack, int itemCount, int actionCount) +{ + mwmp::ContainerItem containerItem; + containerItem.refId = itemStack.mBase.getCellRef().getRefId(); + containerItem.count = itemCount; + containerItem.charge = itemStack.mBase.getCellRef().getCharge(); + containerItem.enchantmentCharge = itemStack.mBase.getCellRef().getEnchantmentCharge(); + containerItem.soul = itemStack.mBase.getCellRef().getSoul(); + containerItem.actionCount = actionCount; + + LOG_APPEND(TimedLog::LOG_VERBOSE, "--- Adding container item %s to packet with count %i and actionCount %i", + containerItem.refId.c_str(), itemCount, actionCount); + + baseObject.containerItems.push_back(containerItem); +} + void ObjectList::addContainerItem(mwmp::BaseObject& baseObject, const std::string itemId, int itemCount, int actionCount) { mwmp::ContainerItem containerItem; @@ -163,7 +179,7 @@ void ObjectList::editContainers(MWWorld::CellStore* cellStore) LOG_APPEND(TimedLog::LOG_VERBOSE, "- container %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); - MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum); + MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { @@ -349,14 +365,7 @@ void ObjectList::activateObjects(MWWorld::CellStore* cellStore) else { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Activated object is %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); - if (baseObject.refId.empty()) - { - ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum); - } - else - { - ptrFound = cellStore->searchExactPlus(baseObject.refId, baseObject.refNum, baseObject.mpNum); - } + ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); } if (ptrFound) @@ -371,7 +380,7 @@ void ObjectList::activateObjects(MWWorld::CellStore* cellStore) } else { - activatingActorPtr = cellStore->searchExact(baseObject.activatingActor.refNum, baseObject.activatingActor.mpNum); + activatingActorPtr = cellStore->searchExact(baseObject.activatingActor.refNum, baseObject.activatingActor.mpNum, baseObject.activatingActor.refId); LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Object has been activated by actor %s %i-%i", activatingActorPtr.getCellRef().getRefId().c_str(), activatingActorPtr.getCellRef().getRefNum().mIndex, activatingActorPtr.getCellRef().getMpNum()); } @@ -491,7 +500,7 @@ void ObjectList::spawnObjects(MWWorld::CellStore* cellStore) if (baseObject.master.isPlayer) masterPtr = MechanicsHelper::getPlayerPtr(baseObject.master); else - masterPtr = cellStore->searchExact(baseObject.master.refNum, baseObject.master.mpNum); + masterPtr = cellStore->searchExact(baseObject.master.refNum, baseObject.master.mpNum, baseObject.master.refId); if (masterPtr) { @@ -541,6 +550,7 @@ void ObjectList::spawnObjects(MWWorld::CellStore* cellStore) foundSummonedCreature = true; break; } + ++it; } // If it is, update its creatureActorId @@ -570,7 +580,7 @@ void ObjectList::deleteObjects(MWWorld::CellStore* cellStore) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); - MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum); + MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { @@ -623,7 +633,7 @@ void ObjectList::lockObjects(MWWorld::CellStore* cellStore) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); - MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum); + MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { @@ -644,7 +654,7 @@ void ObjectList::triggerTrapObjects(MWWorld::CellStore* cellStore) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); - MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum); + MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { @@ -671,7 +681,7 @@ void ObjectList::scaleObjects(MWWorld::CellStore* cellStore) LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i, scale: %f", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum, baseObject.scale); - MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum); + MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { @@ -690,7 +700,7 @@ void ObjectList::setObjectStates(MWWorld::CellStore* cellStore) LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i, state: %s", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum, baseObject.objectState ? "true" : "false"); - MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum); + MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { @@ -720,7 +730,7 @@ void ObjectList::moveObjects(MWWorld::CellStore* cellStore) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); - MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum); + MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { @@ -739,7 +749,7 @@ void ObjectList::restockObjects(MWWorld::CellStore* cellStore) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); - MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum); + MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { @@ -765,7 +775,7 @@ void ObjectList::rotateObjects(MWWorld::CellStore* cellStore) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); - MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum); + MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { @@ -784,7 +794,7 @@ void ObjectList::animateObjects(MWWorld::CellStore* cellStore) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); - MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum); + MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { @@ -826,7 +836,7 @@ void ObjectList::playObjectSounds(MWWorld::CellStore* cellStore) else { objectDescription = baseObject.refId + " " + std::to_string(baseObject.refNum) + "-" + std::to_string(baseObject.mpNum); - ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum); + ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); } if (ptrFound) @@ -857,7 +867,7 @@ void ObjectList::setGoldPoolsForObjects(MWWorld::CellStore* cellStore) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); - MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum); + MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { @@ -889,7 +899,7 @@ void ObjectList::activateDoors(MWWorld::CellStore* cellStore) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); - MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum); + MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { @@ -910,7 +920,7 @@ void ObjectList::setDoorDestinations(MWWorld::CellStore* cellStore) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); - MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum); + MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { @@ -976,7 +986,7 @@ void ObjectList::runConsoleCommands(MWWorld::CellStore* cellStore) { LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Running on object %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); - MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum); + MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { @@ -998,16 +1008,8 @@ void ObjectList::makeDialogueChoices(MWWorld::CellStore* cellStore) for (const auto& baseObject : baseObjects) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); - MWWorld::Ptr ptrFound; - - if (baseObject.refId.empty()) - { - ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum); - } - else - { - ptrFound = cellStore->searchExactPlus(baseObject.refId, baseObject.refNum, baseObject.mpNum); - } + + MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { @@ -1036,7 +1038,33 @@ void ObjectList::makeDialogueChoices(MWWorld::CellStore* cellStore) LOG_APPEND(TimedLog::LOG_VERBOSE, "-- topic was %s", baseObject.topicId.c_str()); } - MWBase::Environment::get().getWindowManager()->getDialogueWindow()->activateDialogueChoice(baseObject.dialogueChoiceType, baseObject.topicId); + std::string topic = baseObject.topicId; + + if (MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation()) + { + char delimiter = '|'; + + // If we're using a translated version of Morrowind, we may have received a string that had the original + // topic delimited from its possible English translation by a | character, in which case we need to use + // the original topic here + if (topic.find(delimiter) != std::string::npos) + { + topic = topic.substr(0, topic.find(delimiter)); + } + // Alternatively, we may have received a topic that needs to be translated into the current language's + // version of it + else + { + std::string translatedTopic = MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().getLocalizedTopicId(topic); + + if (!translatedTopic.empty()) + { + topic = translatedTopic; + } + } + } + + MWBase::Environment::get().getWindowManager()->getDialogueWindow()->activateDialogueChoice(baseObject.dialogueChoiceType, topic); } else { @@ -1053,7 +1081,7 @@ void ObjectList::setClientLocals(MWWorld::CellStore* cellStore) { LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); - MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum); + MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { @@ -1163,7 +1191,7 @@ void ObjectList::addRequestedContainers(MWWorld::CellStore* cellStore, const std LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); - MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum); + MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId); if (ptrFound) { @@ -1329,7 +1357,7 @@ void ObjectList::addObjectDialogueChoice(const MWWorld::Ptr& ptr, std::string di // For translated versions of the game, make sure we translate the topic back into English first if (MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation()) - baseObject.topicId = MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().topicID(dialogueChoice); + baseObject.topicId = dialogueChoice + "|" + MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().topicID(dialogueChoice); else baseObject.topicId = dialogueChoice; } diff --git a/apps/openmw/mwmp/ObjectList.hpp b/apps/openmw/mwmp/ObjectList.hpp index 8ccf1be88..8fceed8cb 100644 --- a/apps/openmw/mwmp/ObjectList.hpp +++ b/apps/openmw/mwmp/ObjectList.hpp @@ -2,6 +2,7 @@ #define OPENMW_OBJECTLIST_HPP #include +#include "../mwgui/itemmodel.hpp" #include "../mwworld/worldimp.hpp" #include @@ -20,6 +21,7 @@ namespace mwmp void addBaseObject(BaseObject baseObject); mwmp::BaseObject getBaseObjectFromPtr(const MWWorld::Ptr& ptr); void addContainerItem(mwmp::BaseObject& baseObject, const MWWorld::Ptr& itemPtr, int itemCount, int actionCount); + void addContainerItem(mwmp::BaseObject& baseObject, const MWGui::ItemStack& itemStack, int itemCount, int actionCount); void addContainerItem(mwmp::BaseObject& baseObject, const std::string itemId, int itemCount, int actionCount); void addEntireContainer(const MWWorld::Ptr& ptr); diff --git a/apps/openmw/mwmp/RecordHelper.cpp b/apps/openmw/mwmp/RecordHelper.cpp index 4735d50bb..312cf4e7e 100644 --- a/apps/openmw/mwmp/RecordHelper.cpp +++ b/apps/openmw/mwmp/RecordHelper.cpp @@ -368,6 +368,18 @@ void RecordHelper::overrideRecord(const mwmp::CellRecord& record) world->unloadCell(finalData); world->clearCellStore(finalData); world->getModifiableStore().overrideRecord(finalData); + + // Create a Pathgrid record for this new Cell based on the base Cell's Pathgrid + // Note: This has to be done after the new Cell has been created so the Pathgrid override + // can correctly determine whether the Cell is an interior or an exterior + const ESM::Pathgrid* basePathgrid = world->getStore().get().search(record.baseId); + + if (basePathgrid) + { + ESM::Pathgrid finalPathgrid = *basePathgrid; + finalPathgrid.mCell = recordData.mName; + world->getModifiableStore().overrideRecord(finalPathgrid); + } } else { diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 199ff4ca6..5c6b2c8ea 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -195,21 +195,23 @@ namespace MWScript /* Start of tes3mp addition - Send an ID_OBJECT_STATE packet whenever an object is enabled, as long as - the player is logged in on the server, the object is still disabled, and our last - packet regarding its state did not already attempt to enable it (to prevent + Send an ID_OBJECT_STATE packet whenever an object should be enabled, as long as the + player is logged in on the server and — if triggered from a clientside script — our + last packet regarding its state did not already attempt to enable it (to prevent packet spam) */ if (mwmp::Main::get().getLocalPlayer()->isLoggedIn()) { - if (ptr.isInCell() && !ptr.getRefData().isEnabled() && - ptr.getRefData().getLastCommunicatedState() != MWWorld::RefData::StateCommunication::Enabled) + unsigned char packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType()); + + if (packetOrigin == Interpreter::Context::CONSOLE || packetOrigin == Interpreter::Context::DIALOGUE || + (ptr.isInCell() && ptr.getRefData().getLastCommunicatedState() != MWWorld::RefData::StateCommunication::Enabled)) { ptr.getRefData().setLastCommunicatedState(MWWorld::RefData::StateCommunication::Enabled); mwmp::ObjectList* objectList = mwmp::Main::get().getNetworking()->getObjectList(); objectList->reset(); - objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType()); + objectList->packetOrigin = packetOrigin; objectList->originClientScript = runtime.getContext().getCurrentScriptName(); objectList->addObjectState(ptr, true); objectList->sendObjectState(); @@ -244,21 +246,23 @@ namespace MWScript /* Start of tes3mp addition - Send an ID_OBJECT_STATE packet whenever an object should be disabled, as long as - the player is logged in on the server, the object is still enabled, and our last - packet regarding its state did not already attempt to disable it (to prevent + Send an ID_OBJECT_STATE packet whenever an object should be disabled, as long as the + player is logged in on the server and — if triggered from a clientside script — our + last packet regarding its state did not already attempt to disable it (to prevent packet spam) */ if (mwmp::Main::get().getLocalPlayer()->isLoggedIn()) { - if (ptr.isInCell() && ptr.getRefData().isEnabled() && - ptr.getRefData().getLastCommunicatedState() != MWWorld::RefData::StateCommunication::Disabled) + unsigned char packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType()); + + if (packetOrigin == Interpreter::Context::CONSOLE || packetOrigin == Interpreter::Context::DIALOGUE || + (ptr.isInCell() && ptr.getRefData().getLastCommunicatedState() != MWWorld::RefData::StateCommunication::Disabled)) { ptr.getRefData().setLastCommunicatedState(MWWorld::RefData::StateCommunication::Disabled); mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList(); objectList->reset(); - objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType()); + objectList->packetOrigin = packetOrigin; objectList->originClientScript = runtime.getContext().getCurrentScriptName(); objectList->addObjectState(ptr, false); objectList->sendObjectState(); @@ -423,9 +427,10 @@ namespace MWScript Start of tes3mp addition Send an ID_OBJECT_LOCK packet every time an object is locked - through a script + through a script, as long as the lock level being set is not + the one it already has */ - if (mwmp::Main::get().getLocalPlayer()->isLoggedIn()) + if (mwmp::Main::get().getLocalPlayer()->isLoggedIn() && ptr.getCellRef().getLockLevel() != lockLevel) { mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList(); objectList->reset(); @@ -471,9 +476,9 @@ namespace MWScript Start of tes3mp addition Send an ID_OBJECT_LOCK packet every time an object is unlocked - through a script + through a script, as long as it's not already unlocked */ - if (mwmp::Main::get().getLocalPlayer()->isLoggedIn()) + if (mwmp::Main::get().getLocalPlayer()->isLoggedIn() && ptr.getCellRef().getLockLevel() > 0) { mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList(); objectList->reset(); diff --git a/apps/openmw/mwscript/transformationextensions.cpp b/apps/openmw/mwscript/transformationextensions.cpp index a03b662aa..31b6a988e 100644 --- a/apps/openmw/mwscript/transformationextensions.cpp +++ b/apps/openmw/mwscript/transformationextensions.cpp @@ -12,6 +12,7 @@ #include "../mwmp/LocalPlayer.hpp" #include "../mwmp/PlayerList.hpp" #include "../mwmp/ObjectList.hpp" +#include "../mwmp/CellController.hpp" #include "../mwmp/ScriptController.hpp" /* End of tes3mp addition @@ -443,10 +444,52 @@ namespace MWScript } if(store) { + /* + Start of tes3mp addition + + Track the original cell of this object in case we need to use it when sending a packet + */ + ESM::Cell originalCell = *ptr.getCell()->getCell(); + /* + End of tes3mp addition + */ + MWWorld::Ptr base = ptr; ptr = MWBase::Environment::get().getWorld()->moveObject(ptr,store,x,y,z); dynamic_cast(runtime.getContext()).updatePtr(base,ptr); + /* + Start of tes3mp addition + + Send ActorCellChange packets when actors are moved here, regardless of whether we're + the cell authority or not; the server can decide if it wants to comply with them + */ + if (ptr.getClass().isActor() && !mwmp::Main::get().getCellController()->isSameCell(originalCell, *store->getCell())) + { + mwmp::BaseActor baseActor; + baseActor.refNum = ptr.getCellRef().getRefNum().mIndex; + baseActor.mpNum = ptr.getCellRef().getMpNum(); + baseActor.cell = *store->getCell(); + baseActor.position = ptr.getRefData().getPosition(); + baseActor.isFollowerCellChange = true; + + mwmp::ActorList* actorList = mwmp::Main::get().getNetworking()->getActorList(); + actorList->reset(); + actorList->cell = originalCell; + + LOG_MESSAGE_SIMPLE(TimedLog::LOG_INFO, "Sending ID_ACTOR_CELL_CHANGE about %s %i-%i to server", + ptr.getCellRef().getRefId().c_str(), baseActor.refNum, baseActor.mpNum); + + LOG_APPEND(TimedLog::LOG_INFO, "- Moved from %s to %s", actorList->cell.getDescription().c_str(), + baseActor.cell.getDescription().c_str()); + + actorList->addCellChangeActor(baseActor); + actorList->sendCellChangeActors(); + } + /* + End of tes3mp addition + */ + float ax = ptr.getRefData().getPosition().rot[0]; float ay = ptr.getRefData().getPosition().rot[1]; // Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south = 10800, west = 16200) diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 46a1dc7a7..7b2791773 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -605,47 +605,26 @@ namespace MWWorld { const unsigned int mRefNumToFind; const unsigned int mMpNumToFind; - public: - SearchExactVisitor(const unsigned int refNum, const unsigned int mpNum) : mRefNumToFind(refNum), mMpNumToFind(mpNum) {} - - Ptr mFound; - - bool operator()(const Ptr& ptr) - { - if (ptr.getCellRef().getRefNum().mIndex == mRefNumToFind && ptr.getCellRef().getMpNum() == mMpNumToFind) - { - mFound = ptr; - return false; - } - return true; - } - }; - /* - End of tes3mp addition - */ - - /* - Start of tes3mp addition - - A custom type of search visitor used to find objects by their reference numbers - while ensuring they have a certain refId - */ - class SearchExactPlusVisitor - { const std::string mRefIdToFind; - const unsigned int mRefNumToFind; - const unsigned int mMpNumToFind; + const bool mActorsOnly; public: - SearchExactPlusVisitor(const std::string refId, const unsigned int refNum, const unsigned int mpNum) : mRefIdToFind(refId), mRefNumToFind(refNum), mMpNumToFind(mpNum) {} + SearchExactVisitor(const unsigned int refNum, const unsigned int mpNum, const std::string refId, const bool actorsOnly) : + mRefNumToFind(refNum), mMpNumToFind(mpNum), mRefIdToFind(refId), mActorsOnly(actorsOnly) {} Ptr mFound; bool operator()(const Ptr& ptr) { - if (ptr.getCellRef().getRefNum().mIndex == mRefNumToFind && ptr.getCellRef().getMpNum() == mMpNumToFind && Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), mRefIdToFind)) + if (ptr.getCellRef().getRefNum().mIndex == mRefNumToFind && ptr.getCellRef().getMpNum() == mMpNumToFind) { - mFound = ptr; - return false; + if (!mActorsOnly || ptr.getClass().isActor()) + { + if (mRefIdToFind.empty() || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), mRefIdToFind)) + { + mFound = ptr; + return false; + } + } } return true; } @@ -659,33 +638,13 @@ namespace MWWorld Allow the searching of objects by their reference numbers */ - Ptr CellStore::searchExact (const unsigned int refNum, const unsigned int mpNum) - { - // Ensure that all objects searched for have a valid reference number - if (refNum == 0 && mpNum == 0) - return 0; - - SearchExactVisitor searchVisitor(refNum, mpNum); - forEach(searchVisitor); - return searchVisitor.mFound; - } - /* - End of tes3mp addition - */ - - /* - Start of tes3mp addition - - Allow the searching of objects by their reference numbers while ensuring - they have a certain refId - */ - Ptr CellStore::searchExactPlus(const std::string refId, const unsigned int refNum, const unsigned int mpNum) + Ptr CellStore::searchExact (const unsigned int refNum, const unsigned int mpNum, const std::string refId, bool actorsOnly) { // Ensure that all objects searched for have a valid reference number if (refNum == 0 && mpNum == 0) return 0; - SearchExactPlusVisitor searchVisitor(refId, refNum, mpNum); + SearchExactVisitor searchVisitor(refNum, mpNum, refId, actorsOnly); forEach(searchVisitor); return searchVisitor.mFound; } diff --git a/apps/openmw/mwworld/cellstore.hpp b/apps/openmw/mwworld/cellstore.hpp index ba0a78972..3e901f4b8 100644 --- a/apps/openmw/mwworld/cellstore.hpp +++ b/apps/openmw/mwworld/cellstore.hpp @@ -262,20 +262,10 @@ namespace MWWorld /* Start of tes3mp addition - Allow the searching of objects by their reference numbers + Allow the searching of objects by their reference numbers and, optionally, + their refIds */ - Ptr searchExact (unsigned int refNum, unsigned int mpNum); - /* - End of tes3mp addition - */ - - /* - Start of tes3mp addition - - Allow the searching of objects by their reference numbers while ensuring - they have a certain refId - */ - Ptr searchExactPlus (std::string refId, unsigned int refNum, unsigned int mpNum); + Ptr searchExact (unsigned int refNum, unsigned int mpNum, std::string refId = "", bool actorsOnly = false); /* End of tes3mp addition */ diff --git a/apps/openmw/mwworld/containerstore.cpp b/apps/openmw/mwworld/containerstore.cpp index d0d55aa4a..5bf25a2ba 100644 --- a/apps/openmw/mwworld/containerstore.cpp +++ b/apps/openmw/mwworld/containerstore.cpp @@ -331,7 +331,7 @@ MWWorld::ContainerStoreIterator MWWorld::ContainerStore::add (const Ptr& itemPtr Send an ID_PLAYER_INVENTORY packet every time an item gets added for a player here */ - if (actorPtr == player && this == &player.getClass().getContainerStore(player)) + if (this == &player.getClass().getContainerStore(player)) { mwmp::LocalPlayer *localPlayer = mwmp::Main::get().getLocalPlayer(); @@ -562,7 +562,7 @@ int MWWorld::ContainerStore::remove(const Ptr& item, int count, const Ptr& actor */ Ptr player = MWBase::Environment::get().getWorld()->getPlayerPtr(); - if (actor == player && this == &player.getClass().getContainerStore(player)) + if (this == &player.getClass().getContainerStore(player)) { mwmp::LocalPlayer *localPlayer = mwmp::Main::get().getLocalPlayer(); diff --git a/apps/openmw/mwworld/esmstore.hpp b/apps/openmw/mwworld/esmstore.hpp index 55528aed2..f9498e06a 100644 --- a/apps/openmw/mwworld/esmstore.hpp +++ b/apps/openmw/mwworld/esmstore.hpp @@ -276,7 +276,7 @@ namespace MWWorld /* Start of tes3mp addition - Make it possible to override a cell record similarly to how + Make it possible to override a Cell record similarly to how other types of records can be overridden */ template <> @@ -287,6 +287,20 @@ namespace MWWorld End of tes3mp addition */ + /* + Start of tes3mp addition + + Make it possible to override a Pathgrid record similarly to how + other types of records can be overridden + */ + template <> + inline const ESM::Pathgrid* ESMStore::overrideRecord(const ESM::Pathgrid& pathgrid) { + return mPathgrids.override(pathgrid); + } + /* + End of tes3mp addition + */ + template <> inline const ESM::Cell *ESMStore::insert(const ESM::Cell &cell) { return mCells.insert(cell); diff --git a/apps/openmw/mwworld/store.cpp b/apps/openmw/mwworld/store.cpp index 22da74811..66c6be35b 100644 --- a/apps/openmw/mwworld/store.cpp +++ b/apps/openmw/mwworld/store.cpp @@ -796,7 +796,7 @@ namespace MWWorld /* Start of tes3mp addition - Make it possible to override a cell record similarly to how + Make it possible to override a Cell record similarly to how other types of records can be overridden */ ESM::Cell *Store::override(const ESM::Cell &cell) @@ -949,6 +949,37 @@ namespace MWWorld return RecordId("", isDeleted); } + /* + Start of tes3mp addition + + Make it possible to override a Pathgrid record similarly to how + other types of records can be overridden + */ + ESM::Pathgrid* Store::override(const ESM::Pathgrid& pathgrid) + { + bool interior = mCells->search(pathgrid.mCell) != nullptr; + + // Try to overwrite existing record + if (interior) + { + std::pair ret = mInt.insert(std::make_pair(pathgrid.mCell, pathgrid)); + if (!ret.second) + ret.first->second = pathgrid; + + return &ret.first->second; + } + else + { + std::pair ret = mExt.insert(std::make_pair(std::make_pair(pathgrid.mData.mX, pathgrid.mData.mY), pathgrid)); + if (!ret.second) + ret.first->second = pathgrid; + + return &ret.first->second; + } + } + /* + End of tes3mp addition + */ size_t Store::getSize() const { return mInt.size() + mExt.size(); diff --git a/apps/openmw/mwworld/store.hpp b/apps/openmw/mwworld/store.hpp index 8a964f982..19f77c3f0 100644 --- a/apps/openmw/mwworld/store.hpp +++ b/apps/openmw/mwworld/store.hpp @@ -325,7 +325,7 @@ namespace MWWorld /* Start of tes3mp addition - Make it possible to override a cell record similarly to how + Make it possible to override a Cell record similarly to how other types of records can be overridden */ ESM::Cell *override(const ESM::Cell &cell); @@ -362,6 +362,17 @@ namespace MWWorld void setUp() override; + /* + Start of tes3mp addition + + Make it possible to override a Pathgrid record similarly to how + other types of records can be overridden + */ + ESM::Pathgrid* override(const ESM::Pathgrid& pathgrid); + /* + End of tes3mp addition + */ + const ESM::Pathgrid *search(int x, int y) const; const ESM::Pathgrid *search(const std::string& name) const; const ESM::Pathgrid *find(int x, int y) const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index e6e591e58..3eba91f2c 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3971,6 +3971,12 @@ namespace MWWorld MWWorld::Ptr player = getPlayerPtr(); player.getClass().getInventoryStore(player).rechargeItems(duration); + /* + Start of tes3mp change (major) + + Don't unilaterally recharge world items on clients + */ + /* if (activeOnly) { for (auto &cell : mWorldScene->getActiveCells()) @@ -3980,6 +3986,10 @@ namespace MWWorld } else mCells.recharge(duration); + */ + /* + End of tes3mp change (major) + */ } void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, diff --git a/components/openmw-mp/Base/BaseActor.hpp b/components/openmw-mp/Base/BaseActor.hpp index 4977ee559..1c2065f7d 100644 --- a/components/openmw-mp/Base/BaseActor.hpp +++ b/components/openmw-mp/Base/BaseActor.hpp @@ -19,7 +19,7 @@ namespace mwmp hasStatsDynamicData = false; } - std::string refId; + std::string refId = ""; unsigned int refNum; unsigned int mpNum; diff --git a/components/openmw-mp/Base/BaseObject.hpp b/components/openmw-mp/Base/BaseObject.hpp index f3d004923..94175a63d 100644 --- a/components/openmw-mp/Base/BaseObject.hpp +++ b/components/openmw-mp/Base/BaseObject.hpp @@ -26,7 +26,7 @@ namespace mwmp struct BaseObject { - std::string refId; + std::string refId = ""; unsigned int refNum; unsigned int mpNum; int count; diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 96f0a5abf..11c4a8437 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -106,6 +106,9 @@ set(MYGUI_FILES openmw_windows.skin.xml DejaVuLGCSansMono.ttf ../launcher/images/openmw.png + # Start of tes3mp addition + ../tes3mp/tes3mp_logo.png + # End of tes3mp addition OpenMWResourcePlugin.xml skins.xml