From 528bd26a3b494e20192372c8313769edc93d9b9f Mon Sep 17 00:00:00 2001 From: David Cernat Date: Fri, 13 Jul 2018 21:27:29 +0300 Subject: [PATCH] [General] Allow followers to follow non-authority players through cells --- .../actor/ProcessorActorCellChange.hpp | 27 ++++-- apps/openmw/mwmp/LocalActor.cpp | 1 + apps/openmw/mwscript/aiextensions.cpp | 4 +- apps/openmw/mwworld/actionteleport.cpp | 83 +++++++++++++------ components/openmw-mp/Base/BaseActor.hpp | 2 + .../Packets/Actor/PacketActorCellChange.cpp | 2 + 6 files changed, 88 insertions(+), 31 deletions(-) diff --git a/apps/openmw-mp/processors/actor/ProcessorActorCellChange.hpp b/apps/openmw-mp/processors/actor/ProcessorActorCellChange.hpp index 311786121..98d74e4cb 100644 --- a/apps/openmw-mp/processors/actor/ProcessorActorCellChange.hpp +++ b/apps/openmw-mp/processors/actor/ProcessorActorCellChange.hpp @@ -17,14 +17,31 @@ namespace mwmp { Cell *serverCell = CellController::get()->getCell(&actorList.cell); - if (serverCell != nullptr && *serverCell->getAuthority() == actorList.guid) + if (serverCell != nullptr) { - serverCell->removeActors(&actorList); + bool isFollowerCellChange = false; - Script::Call(player.getId(), actorList.cell.getDescription().c_str()); + // TODO: Move this check on the Lua side + for (unsigned int i = 0; i < actorList.count; i++) + { + if (actorList.baseActors.at(i).isFollowerCellChange) + { + isFollowerCellChange = true; + break; + } + } - // Send this to everyone - packet.Send(true); + // 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); + + Script::Call(player.getId(), actorList.cell.getDescription().c_str()); + + // Send this to everyone + packet.Send(true); + } } } }; diff --git a/apps/openmw/mwmp/LocalActor.cpp b/apps/openmw/mwmp/LocalActor.cpp index ca0e22656..f58bd657d 100644 --- a/apps/openmw/mwmp/LocalActor.cpp +++ b/apps/openmw/mwmp/LocalActor.cpp @@ -72,6 +72,7 @@ void LocalActor::updateCell() cell = *ptr.getCell()->getCell(); position = ptr.getRefData().getPosition(); + isFollowerCellChange = false; mwmp::Main::get().getNetworking()->getActorList()->addCellChangeActor(*this); } diff --git a/apps/openmw/mwscript/aiextensions.cpp b/apps/openmw/mwscript/aiextensions.cpp index 86af5249f..947b9281f 100644 --- a/apps/openmw/mwscript/aiextensions.cpp +++ b/apps/openmw/mwscript/aiextensions.cpp @@ -351,7 +351,7 @@ namespace MWScript baseActor.aiTarget = MechanicsHelper::getTarget(targetPtr); LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_ACTOR_AI about %s %i-%i to server", - ptr.getCellRef().getRefId(), baseActor.refNum, baseActor.mpNum); + ptr.getCellRef().getRefId().c_str(), baseActor.refNum, baseActor.mpNum); if (baseActor.aiTarget.isPlayer) { @@ -361,7 +361,7 @@ namespace MWScript else { LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "- Following actor %s %i-%i", - targetPtr.getCellRef().getRefId(), baseActor.aiTarget.refNum, baseActor.aiTarget.mpNum); + targetPtr.getCellRef().getRefId().c_str(), baseActor.aiTarget.refNum, baseActor.aiTarget.mpNum); } mwmp::ActorList *actorList = mwmp::Main::get().getNetworking()->getActorList(); diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index f69dd3415..3ceff70ec 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -8,6 +8,8 @@ #include #include "../mwbase/windowmanager.hpp" #include "../mwmp/Main.hpp" +#include "../mwmp/Networking.hpp" +#include "../mwmp/ActorList.hpp" #include "../mwmp/CellController.hpp" /* End of tes3mp addition @@ -41,17 +43,6 @@ namespace MWWorld for (std::set::iterator it = followers.begin(); it != followers.end(); ++it) teleport(*it); - - /* - Start of tes3mp addition - - Update LocalActors before we unload their cells, so packets with their cell changes - can be sent - */ - mwmp::Main::get().getCellController()->updateLocal(true); - /* - End of tes3mp addition - */ } teleport(actor); @@ -72,34 +63,78 @@ namespace MWWorld else { /* - Start of tes3mp change (major) + Start of tes3mp addition - Only allow LocalActors to teleport across cells + Track the original cell of this actor so we can use it when sending a packet */ - if (!mwmp::Main::get().getCellController()->isLocalActor(actor)) - { - MWBase::Environment::get().getWindowManager()->messageBox("That NPC can't follow you because their AI is running on another player's client."); - return; - } - else - { - LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Teleporting actor %s-%i-%i to new cell", actor.getCellRef().getRefId().c_str(), - actor.getCellRef().getRefNum().mIndex, actor.getCellRef().getMpNum()); - } + ESM::Cell originalCell = *actor.getCell()->getCell(); /* - End of tes3mp change (major) + End of tes3mp addition + */ + + /* + Start of tes3mp change (minor) + + If this is a DedicatedActor, get their new cell and override their stored cell with it + so their cell change is approved in World::moveObject() */ + MWWorld::CellStore *newCellStore; + mwmp::CellController *cellController = mwmp::Main::get().getCellController(); if (mCellName.empty()) { int cellX; int cellY; world->positionToIndex(mPosition.pos[0],mPosition.pos[1],cellX,cellY); + + newCellStore = world->getExterior(cellX, cellY); + if (cellController->isDedicatedActor(actor)) + cellController->getDedicatedActor(actor)->cell = *newCellStore->getCell(); + world->moveObject(actor,world->getExterior(cellX,cellY), mPosition.pos[0],mPosition.pos[1],mPosition.pos[2]); } else + { + newCellStore = world->getInterior(mCellName); + if (cellController->isDedicatedActor(actor)) + cellController->getDedicatedActor(actor)->cell = *newCellStore->getCell(); + world->moveObject(actor,world->getInterior(mCellName),mPosition.pos[0],mPosition.pos[1],mPosition.pos[2]); + } + /* + Start of tes3mp change (minor) + */ + + /* + Start of tes3mp addition + + Send ActorCellChange packets when an actor follows us across cells, regardless of + whether we're the cell authority or not; the server can decide if it wants to comply + with them + */ + mwmp::BaseActor baseActor; + baseActor.refNum = actor.getCellRef().getRefNum().mIndex; + baseActor.mpNum = actor.getCellRef().getMpNum(); + baseActor.cell = *newCellStore->getCell(); + baseActor.position = actor.getRefData().getPosition(); + baseActor.isFollowerCellChange = true; + + mwmp::ActorList *actorList = mwmp::Main::get().getNetworking()->getActorList(); + actorList->reset(); + actorList->cell = originalCell; + + LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Sending ID_ACTOR_CELL_CHANGE about %s %i-%i to server", + actor.getCellRef().getRefId().c_str(), baseActor.refNum, baseActor.mpNum); + + LOG_APPEND(Log::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 + */ } } diff --git a/components/openmw-mp/Base/BaseActor.hpp b/components/openmw-mp/Base/BaseActor.hpp index 0474104ea..030322081 100644 --- a/components/openmw-mp/Base/BaseActor.hpp +++ b/components/openmw-mp/Base/BaseActor.hpp @@ -41,6 +41,8 @@ namespace mwmp Target killer; + bool isFollowerCellChange; + bool hasAiTarget; Target aiTarget; unsigned int aiAction; diff --git a/components/openmw-mp/Packets/Actor/PacketActorCellChange.cpp b/components/openmw-mp/Packets/Actor/PacketActorCellChange.cpp index d6e9fc8fc..7dfecedd5 100644 --- a/components/openmw-mp/Packets/Actor/PacketActorCellChange.cpp +++ b/components/openmw-mp/Packets/Actor/PacketActorCellChange.cpp @@ -16,4 +16,6 @@ void PacketActorCellChange::Actor(BaseActor &actor, bool send) RW(actor.position, send, true); RW(actor.direction, send, true); + + RW(actor.isFollowerCellChange, send); }