Add TES3MP 0.8.0 commits up to 28 Apr 2022

# Conflicts:
#	apps/openmw/mwclass/creature.cpp
#	apps/openmw/mwclass/npc.cpp
0.8.0-vr
David Cernat 3 years ago
commit a032c8d399

@ -10,7 +10,7 @@ When it's combined with Mads Buvik Sandvei's [fork adding VR support to OpenMW](
* TES3MP version: 0.8.0 * TES3MP version: 0.8.0
* OpenMW version: 0.47.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: Font Licenses:
* DejaVuLGCSansMono.ttf: custom (see [files/mygui/DejaVuFontLicense.txt](https://github.com/TES3MP/TES3MP/blob/master/files/mygui/DejaVuFontLicense.txt) for more information) * DejaVuLGCSansMono.ttf: custom (see [files/mygui/DejaVuFontLicense.txt](https://github.com/TES3MP/TES3MP/blob/master/files/mygui/DejaVuFontLicense.txt) for more information)

@ -489,7 +489,7 @@ void signalHandler(int signum)
{ {
std::cout << "Interrupt signal (" << signum << ") received.\n"; std::cout << "Interrupt signal (" << signum << ") received.\n";
//15 is SIGTERM(Normal OS stop call), 2 is SIGINT(Ctrl+C) //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; killLoop = true;
} }
@ -507,7 +507,7 @@ int Networking::mainLoop()
sigIntHandler.sa_flags = 0; sigIntHandler.sa_flags = 0;
#endif #endif
while (running and !killLoop) while (running && !killLoop)
{ {
#ifndef _WIN32 #ifndef _WIN32
sigaction(SIGTERM, &sigIntHandler, NULL); sigaction(SIGTERM, &sigIntHandler, NULL);

@ -15,6 +15,7 @@ namespace mwmp
void Do(ActorPacket &packet, Player &player, BaseActorList &actorList) override void Do(ActorPacket &packet, Player &player, BaseActorList &actorList) override
{ {
bool isAccepted = false;
Cell *serverCell = CellController::get()->getCell(&actorList.cell); Cell *serverCell = CellController::get()->getCell(&actorList.cell);
if (serverCell != nullptr) 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 // cell changes from other players
if (*serverCell->getAuthority() == actorList.guid || isFollowerCellChange) if (*serverCell->getAuthority() == actorList.guid || isFollowerCellChange)
{ {
serverCell->removeActors(&actorList); 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<Script::CallbackIdentity("OnActorCellChange")>(player.getId(), actorList.cell.getShortDescription().c_str()); if (isAccepted)
{
Script::Call<Script::CallbackIdentity("OnActorCellChange")>(player.getId(), actorList.cell.getShortDescription().c_str());
// Send this to everyone // Send this to everyone
packet.Send(true); packet.Send(true);
}
} }
} }
}; };

@ -698,7 +698,15 @@ void OMW::Engine::createWindow(Settings::Manager& settings)
{ {
while (!mWindow) 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) if (!mWindow)
{ {
// Try with a lower AA // Try with a lower AA
@ -776,7 +784,15 @@ void OMW::Engine::createWindow(Settings::Manager& settings)
void OMW::Engine::setWindowIcon() void OMW::Engine::setWindowIcon()
{ {
boost::filesystem::ifstream windowIconStream; 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); windowIconStream.open(windowIcon, std::ios_base::in | std::ios_base::binary);
if (windowIconStream.fail()) if (windowIconStream.fail())
Log(Debug::Error) << "Error: Failed to open " << windowIcon; Log(Debug::Error) << "Error: Failed to open " << windowIcon;

@ -279,11 +279,23 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
engine.setCompileAll(variables["script-all"].as<bool>()); engine.setCompileAll(variables["script-all"].as<bool>());
engine.setCompileAllDialogue(variables["script-all-dialogue"].as<bool>()); engine.setCompileAllDialogue(variables["script-all-dialogue"].as<bool>());
engine.setScriptConsoleMode (variables["script-console"].as<bool>()); engine.setScriptConsoleMode (variables["script-console"].as<bool>());
/*
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<Files::EscapeHashString>().toStdString()); engine.setStartupScript (variables["script-run"].as<Files::EscapeHashString>().toStdString());
engine.setWarningsMode (variables["script-warn"].as<int>()); engine.setWarningsMode (variables["script-warn"].as<int>());
engine.setScriptBlacklist (variables["script-blacklist"].as<Files::EscapeStringVector>().toStdStringVector()); engine.setScriptBlacklist (variables["script-blacklist"].as<Files::EscapeStringVector>().toStdStringVector());
engine.setScriptBlacklistUse (variables["script-blacklist-use"].as<bool>()); engine.setScriptBlacklistUse (variables["script-blacklist-use"].as<bool>());
engine.setSaveGameFile (variables["load-savegame"].as<Files::EscapePath>().mPath.string()); engine.setSaveGameFile (variables["load-savegame"].as<Files::EscapePath>().mPath.string());
*/
/*
End of tes3mp change (major)
*/
// other settings // other settings
Fallback::Map::init(variables["fallback"].as<FallbackMap>().mMap); Fallback::Map::init(variables["fallback"].as<FallbackMap>().mMap);

@ -17,6 +17,17 @@
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
#include "../mwworld/player.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 "textinput.hpp"
#include "race.hpp" #include "race.hpp"
#include "class.hpp" #include "class.hpp"
@ -329,6 +340,16 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->popGuiMode();
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Birth); 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) void CharacterCreation::onReviewActivateDialog(int parDialog)
@ -381,6 +402,16 @@ namespace MWGui
selectPickedClass(); selectPickedClass();
handleDialogDone(CSE_ClassChosen, GM_Birth); 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() void CharacterCreation::onPickClassDialogBack()
@ -411,6 +442,16 @@ namespace MWGui
break; break;
case ClassChoiceDialog::Class_Back: case ClassChoiceDialog::Class_Back:
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Race); 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; break;
}; };
@ -439,6 +480,16 @@ namespace MWGui
} }
handleDialogDone(CSE_NameChosen, GM_Race); 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() void CharacterCreation::selectRace()
@ -477,6 +528,16 @@ namespace MWGui
selectRace(); selectRace();
handleDialogDone(CSE_RaceChosen, GM_Class); 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() void CharacterCreation::selectBirthSign()
@ -498,6 +559,16 @@ namespace MWGui
selectBirthSign(); selectBirthSign();
handleDialogDone(CSE_BirthSignChosen, GM_Review); 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() void CharacterCreation::onBirthSignDialogBack()
@ -506,6 +577,16 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->popGuiMode();
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); 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() void CharacterCreation::selectCreatedClass()
@ -547,6 +628,16 @@ namespace MWGui
selectCreatedClass(); selectCreatedClass();
handleDialogDone(CSE_ClassChosen, GM_Birth); 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() void CharacterCreation::onCreateClassDialogBack()
@ -556,6 +647,16 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->popGuiMode(); MWBase::Environment::get().getWindowManager()->popGuiMode();
MWBase::Environment::get().getWindowManager()->pushGuiMode(GM_Class); 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) void CharacterCreation::onClassQuestionChosen(int _index)
@ -748,6 +849,16 @@ namespace MWGui
selectGeneratedClass(); selectGeneratedClass();
handleDialogDone(CSE_ClassChosen, GM_Birth); 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() CharacterCreation::~CharacterCreation()

@ -301,27 +301,33 @@ namespace MWGui
/* /*
Start of tes3mp addition 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 Send an ID_CONTAINER packet every time the Take All button is used on
a container 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) for (size_t i = 0; i < mModel->getItemCount(); ++i)
{ {
const ItemStack& item = mModel->getItem(i); const ItemStack& item = mModel->getItem(i);
// Trigger crimes related to the attempted taking of these items, if applicable
if (!onTakeItem(item, item.mCount)) if (!onTakeItem(item, item.mCount))
break; break;
objectList->addContainerItem(baseObject, item, item.mCount, item.mCount);
} }
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList(); if (baseObject.containerItems.size() > 0)
objectList->reset(); {
objectList->packetOrigin = mwmp::CLIENT_GAMEPLAY; objectList->addBaseObject(baseObject);
objectList->cell = *mPtr.getCell()->getCell(); objectList->sendContainer();
objectList->action = mwmp::BaseObjectList::REMOVE; }
objectList->containerSubAction = mwmp::BaseObjectList::TAKE_ALL;
objectList->addEntireContainer(mPtr);
objectList->sendContainer();
/* /*
End of tes3mp addition End of tes3mp addition
*/ */

@ -469,10 +469,6 @@ namespace MWGui
{ {
if (dialogueChoiceType == mwmp::DialogueChoiceType::TOPIC) 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); onTopicActivated(topic);
} }
else if (dialogueChoiceType == mwmp::DialogueChoiceType::PERSUASION) else if (dialogueChoiceType == mwmp::DialogueChoiceType::PERSUASION)

@ -514,22 +514,21 @@ namespace MWGui
Instead of unilaterally using an item, send an ID_PLAYER_ITEM_USE packet and let the server Instead of unilaterally using an item, send an ID_PLAYER_ITEM_USE packet and let the server
decide if the item actually gets used decide if the item actually gets used
*/ */
/*
if (!item.getClass().getEquipmentSlots(item).first.empty() && !store.isEquipped(item)) if (!item.getClass().getEquipmentSlots(item).first.empty() && !store.isEquipped(item))
{ {
/*
MWBase::Environment::get().getWindowManager()->useItem(item); MWBase::Environment::get().getWindowManager()->useItem(item);
// make sure that item was successfully equipped // make sure that item was successfully equipped
if (!store.isEquipped(item)) if (!store.isEquipped(item))
return; return;
*/
mwmp::Main::get().getLocalPlayer()->sendItemUse(item, true, MWMechanics::DrawState_Spell);
} }
//store.setSelectedEnchantItem(it); store.setSelectedEnchantItem(it);
//MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Spell); MWBase::Environment::get().getWorld()->getPlayer().setDrawState(MWMechanics::DrawState_Spell);
*/
mwmp::Main::get().getLocalPlayer()->sendItemUse(item, true, MWMechanics::DrawState_Spell);
/* /*
End of tes3mp change (major) End of tes3mp change (major)
*/ */

@ -154,9 +154,10 @@ namespace MWGui
Prevent resting and waiting if they have been disabled by the server for the local player 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(); MWBase::Environment::get().getWindowManager()->popGuiMode();
} }
else if (canRest == MWBase::World::Rest_OnlyWaiting && !mwmp::Main::get().getLocalPlayer()->waitAllowed && else if (canRest == MWBase::World::Rest_OnlyWaiting && !mwmp::Main::get().getLocalPlayer()->waitAllowed &&

@ -13,6 +13,7 @@
*/ */
#include "../mwmp/Main.hpp" #include "../mwmp/Main.hpp"
#include "../mwmp/LocalPlayer.hpp" #include "../mwmp/LocalPlayer.hpp"
#include "../mwmp/GUIController.hpp"
/* /*
End of tes3mp addition End of tes3mp addition
*/ */
@ -366,6 +367,19 @@ namespace MWInput
void ActionManager::toggleMainMenu() 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()) if (MyGUI::InputManager::getInstance().isModalAny())
{ {
MWBase::Environment::get().getWindowManager()->exitCurrentModal(); MWBase::Environment::get().getWindowManager()->exitCurrentModal();

@ -2479,24 +2479,24 @@ namespace MWMechanics
void Actors::cleanupSummonedCreature (MWMechanics::CreatureStats& casterStats, int creatureActorId) void Actors::cleanupSummonedCreature (MWMechanics::CreatureStats& casterStats, int creatureActorId)
{ {
MWWorld::Ptr ptr = MWBase::Environment::get().getWorld()->searchPtrViaActorId(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 /*
*/ Start of tes3mp change (major)
if (mwmp::Main::get().getCellController()->hasLocalAuthority(*ptr.getCell()->getCell()))
{ Do a cleanup here and send an ID_OBJECT_DELETE packet every time a summoned creature
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList(); despawns for the local player or for a local actor
objectList->reset(); */
objectList->packetOrigin = mwmp::CLIENT_GAMEPLAY; if (!ptr.isEmpty() &&
objectList->addObjectGeneric(ptr); (casterStats.getActorId() == getPlayer().getClass().getCreatureStats(getPlayer()).getActorId() || mwmp::Main::get().getCellController()->hasLocalAuthority(*ptr.getCell()->getCell())))
objectList->sendObjectDelete(); {
} mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
/* objectList->reset();
End of tes3mp change (major) 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<ESM::Static>() const ESM::Static* fx = MWBase::Environment::get().getWorld()->getStore().get<ESM::Static>()
.search("VFX_Summon_End"); .search("VFX_Summon_End");

@ -553,8 +553,20 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na
if (readyStatus == Result_NoEffects) if (readyStatus == Result_NoEffects)
removeIngredients(); removeIngredients();
/*
Start of tes3mp change (minor)
Set avoidSendingInventoryPackets to false again if this has not been a successful
potion creation
*/
if (readyStatus != Result_Success) if (readyStatus != Result_Success)
{
mwmp::Main::get().getLocalPlayer()->avoidSendingInventoryPackets = false;
return readyStatus; return readyStatus;
}
/*
End of tes3mp change (major)
*/
Result result = Result_RandomFailure; Result result = Result_RandomFailure;
int brewedCount = 0; int brewedCount = 0;

@ -79,10 +79,24 @@ void Cell::updateLocal(bool forceUpdate)
} }
else else
{ {
// Forcibly update this local actor if its data has never been sent before; if (actor->getPtr().getRefData().isEnabled())
// otherwise, use the current forceUpdate value {
if (actor->getPtr().getRefData().isEnabled() && !actor->getPtr().getRefData().isDeleted()) if (actor->getPtr().getRefData().isDeleted())
actor->update(actor->hasSentData ? forceUpdate : true); {
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; ++it;
} }
@ -531,7 +545,7 @@ void Cell::initializeDedicatedActors(ActorList& actorList)
// If this key doesn't exist, create it // If this key doesn't exist, create it
if (dedicatedActors.count(mapIndex) == 0) 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; if (!ptrFound) continue;

@ -39,7 +39,7 @@ namespace mwmp
mHistory->setNeedKeyFocus(false); mHistory->setNeedKeyFocus(false);
windowState = 0; windowState = CHAT_DISABLED;
mCommandLine->setVisible(0); mCommandLine->setVisible(0);
delay = 3; // 3 sec. delay = 3; // 3 sec.
} }
@ -49,7 +49,9 @@ namespace mwmp
// Give keyboard focus to the combo box whenever the console is // Give keyboard focus to the combo box whenever the console is
// turned on // turned on
setEditState(0); setEditState(0);
windowState = CHAT_ENABLED;
if (windowState == CHAT_DISABLED)
windowState = CHAT_ENABLED;
} }
void GUIChat::onClose() void GUIChat::onClose()
@ -114,7 +116,7 @@ namespace mwmp
void GUIChat::print(const std::string &msg, const std::string &color) void GUIChat::print(const std::string &msg, const std::string &color)
{ {
if (windowState == 2 && !isVisible()) if (windowState == CHAT_HIDDENMODE && !isVisible())
{ {
setVisible(true); setVisible(true);
} }

@ -211,6 +211,11 @@ bool mwmp::GUIController::pressedKey(int key)
return false; return false;
} }
void mwmp::GUIController::changeChatMode()
{
mChat->pressedChatMode();
}
bool mwmp::GUIController::getChatEditState() bool mwmp::GUIController::getChatEditState()
{ {
return mChat->editState; return mChat->editState;

@ -45,11 +45,13 @@ namespace mwmp
void showDialogList(const BasePlayer::GUIMessageBox &guiMessageBox); void showDialogList(const BasePlayer::GUIMessageBox &guiMessageBox);
bool getChatEditState();
/// Returns 0 if there was no events /// Returns 0 if there was no events
bool pressedKey(int key); bool pressedKey(int key);
void changeChatMode();
bool getChatEditState();
void update(float dt); void update(float dt);
void processCustomMessageBoxInput(int pressedButton); void processCustomMessageBoxInput(int pressedButton);

@ -155,7 +155,6 @@ bool LocalPlayer::processCharGen()
} }
getNetworking()->getPlayerPacket(ID_PLAYER_CHARGEN)->setPlayer(this); getNetworking()->getPlayerPacket(ID_PLAYER_CHARGEN)->setPlayer(this);
getNetworking()->getPlayerPacket(ID_PLAYER_CHARGEN)->Send(); getNetworking()->getPlayerPacket(ID_PLAYER_CHARGEN)->Send();
charGenState.currentStage++;
return false; return false;
} }

@ -112,6 +112,22 @@ void ObjectList::addContainerItem(mwmp::BaseObject& baseObject, const MWWorld::P
baseObject.containerItems.push_back(containerItem); 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) void ObjectList::addContainerItem(mwmp::BaseObject& baseObject, const std::string itemId, int itemCount, int actionCount)
{ {
mwmp::ContainerItem containerItem; 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); 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) if (ptrFound)
{ {
@ -349,14 +365,7 @@ void ObjectList::activateObjects(MWWorld::CellStore* cellStore)
else else
{ {
LOG_APPEND(TimedLog::LOG_VERBOSE, "-- Activated object is %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); 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, baseObject.refId);
{
ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum);
}
else
{
ptrFound = cellStore->searchExactPlus(baseObject.refId, baseObject.refNum, baseObject.mpNum);
}
} }
if (ptrFound) if (ptrFound)
@ -371,7 +380,7 @@ void ObjectList::activateObjects(MWWorld::CellStore* cellStore)
} }
else 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(), 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()); activatingActorPtr.getCellRef().getRefNum().mIndex, activatingActorPtr.getCellRef().getMpNum());
} }
@ -491,7 +500,7 @@ void ObjectList::spawnObjects(MWWorld::CellStore* cellStore)
if (baseObject.master.isPlayer) if (baseObject.master.isPlayer)
masterPtr = MechanicsHelper::getPlayerPtr(baseObject.master); masterPtr = MechanicsHelper::getPlayerPtr(baseObject.master);
else else
masterPtr = cellStore->searchExact(baseObject.master.refNum, baseObject.master.mpNum); masterPtr = cellStore->searchExact(baseObject.master.refNum, baseObject.master.mpNum, baseObject.master.refId);
if (masterPtr) if (masterPtr)
{ {
@ -541,6 +550,7 @@ void ObjectList::spawnObjects(MWWorld::CellStore* cellStore)
foundSummonedCreature = true; foundSummonedCreature = true;
break; break;
} }
++it;
} }
// If it is, update its creatureActorId // 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); 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) 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); 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) 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); 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) 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, LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i, scale: %f", baseObject.refId.c_str(), baseObject.refNum,
baseObject.mpNum, baseObject.scale); 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) 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, LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i, state: %s", baseObject.refId.c_str(), baseObject.refNum,
baseObject.mpNum, baseObject.objectState ? "true" : "false"); 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) 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); 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) 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); 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) 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); 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) 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); 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) if (ptrFound)
{ {
@ -826,7 +836,7 @@ void ObjectList::playObjectSounds(MWWorld::CellStore* cellStore)
else else
{ {
objectDescription = baseObject.refId + " " + std::to_string(baseObject.refNum) + "-" + std::to_string(baseObject.mpNum); 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) 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); 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) 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); 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) 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); 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) 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); 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) if (ptrFound)
{ {
@ -998,16 +1008,8 @@ void ObjectList::makeDialogueChoices(MWWorld::CellStore* cellStore)
for (const auto& baseObject : baseObjects) for (const auto& baseObject : baseObjects)
{ {
LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum); LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(), baseObject.refNum, baseObject.mpNum);
MWWorld::Ptr ptrFound;
MWWorld::Ptr ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum, baseObject.refId);
if (baseObject.refId.empty())
{
ptrFound = cellStore->searchExact(baseObject.refNum, baseObject.mpNum);
}
else
{
ptrFound = cellStore->searchExactPlus(baseObject.refId, baseObject.refNum, baseObject.mpNum);
}
if (ptrFound) if (ptrFound)
{ {
@ -1036,7 +1038,33 @@ void ObjectList::makeDialogueChoices(MWWorld::CellStore* cellStore)
LOG_APPEND(TimedLog::LOG_VERBOSE, "-- topic was %s", baseObject.topicId.c_str()); 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 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); 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) 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(), LOG_APPEND(TimedLog::LOG_VERBOSE, "- cellRef: %s %i-%i", baseObject.refId.c_str(),
baseObject.refNum, baseObject.mpNum); 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) 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 // For translated versions of the game, make sure we translate the topic back into English first
if (MWBase::Environment::get().getWindowManager()->getTranslationDataStorage().hasTranslation()) 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 else
baseObject.topicId = dialogueChoice; baseObject.topicId = dialogueChoice;
} }

@ -2,6 +2,7 @@
#define OPENMW_OBJECTLIST_HPP #define OPENMW_OBJECTLIST_HPP
#include <components/openmw-mp/Base/BaseObject.hpp> #include <components/openmw-mp/Base/BaseObject.hpp>
#include "../mwgui/itemmodel.hpp"
#include "../mwworld/worldimp.hpp" #include "../mwworld/worldimp.hpp"
#include <RakNetTypes.h> #include <RakNetTypes.h>
@ -20,6 +21,7 @@ namespace mwmp
void addBaseObject(BaseObject baseObject); void addBaseObject(BaseObject baseObject);
mwmp::BaseObject getBaseObjectFromPtr(const MWWorld::Ptr& ptr); 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 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 addContainerItem(mwmp::BaseObject& baseObject, const std::string itemId, int itemCount, int actionCount);
void addEntireContainer(const MWWorld::Ptr& ptr); void addEntireContainer(const MWWorld::Ptr& ptr);

@ -368,6 +368,18 @@ void RecordHelper::overrideRecord(const mwmp::CellRecord& record)
world->unloadCell(finalData); world->unloadCell(finalData);
world->clearCellStore(finalData); world->clearCellStore(finalData);
world->getModifiableStore().overrideRecord(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<ESM::Pathgrid>().search(record.baseId);
if (basePathgrid)
{
ESM::Pathgrid finalPathgrid = *basePathgrid;
finalPathgrid.mCell = recordData.mName;
world->getModifiableStore().overrideRecord(finalPathgrid);
}
} }
else else
{ {

@ -195,21 +195,23 @@ namespace MWScript
/* /*
Start of tes3mp addition Start of tes3mp addition
Send an ID_OBJECT_STATE packet whenever an object is enabled, as long as Send an ID_OBJECT_STATE packet whenever an object should be enabled, as long as the
the player is logged in on the server, the object is still disabled, and our last player is logged in on the server and if triggered from a clientside script our
packet regarding its state did not already attempt to enable it (to prevent last packet regarding its state did not already attempt to enable it (to prevent
packet spam) packet spam)
*/ */
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn()) if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
{ {
if (ptr.isInCell() && !ptr.getRefData().isEnabled() && unsigned char packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
ptr.getRefData().getLastCommunicatedState() != MWWorld::RefData::StateCommunication::Enabled)
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); ptr.getRefData().setLastCommunicatedState(MWWorld::RefData::StateCommunication::Enabled);
mwmp::ObjectList* objectList = mwmp::Main::get().getNetworking()->getObjectList(); mwmp::ObjectList* objectList = mwmp::Main::get().getNetworking()->getObjectList();
objectList->reset(); objectList->reset();
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType()); objectList->packetOrigin = packetOrigin;
objectList->originClientScript = runtime.getContext().getCurrentScriptName(); objectList->originClientScript = runtime.getContext().getCurrentScriptName();
objectList->addObjectState(ptr, true); objectList->addObjectState(ptr, true);
objectList->sendObjectState(); objectList->sendObjectState();
@ -244,21 +246,23 @@ namespace MWScript
/* /*
Start of tes3mp addition Start of tes3mp addition
Send an ID_OBJECT_STATE packet whenever an object should be disabled, as long as Send an ID_OBJECT_STATE packet whenever an object should be disabled, as long as the
the player is logged in on the server, the object is still enabled, and our last player is logged in on the server and if triggered from a clientside script our
packet regarding its state did not already attempt to disable it (to prevent last packet regarding its state did not already attempt to disable it (to prevent
packet spam) packet spam)
*/ */
if (mwmp::Main::get().getLocalPlayer()->isLoggedIn()) if (mwmp::Main::get().getLocalPlayer()->isLoggedIn())
{ {
if (ptr.isInCell() && ptr.getRefData().isEnabled() && unsigned char packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType());
ptr.getRefData().getLastCommunicatedState() != MWWorld::RefData::StateCommunication::Disabled)
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); ptr.getRefData().setLastCommunicatedState(MWWorld::RefData::StateCommunication::Disabled);
mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList(); mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
objectList->reset(); objectList->reset();
objectList->packetOrigin = ScriptController::getPacketOriginFromContextType(runtime.getContext().getContextType()); objectList->packetOrigin = packetOrigin;
objectList->originClientScript = runtime.getContext().getCurrentScriptName(); objectList->originClientScript = runtime.getContext().getCurrentScriptName();
objectList->addObjectState(ptr, false); objectList->addObjectState(ptr, false);
objectList->sendObjectState(); objectList->sendObjectState();
@ -423,9 +427,10 @@ namespace MWScript
Start of tes3mp addition Start of tes3mp addition
Send an ID_OBJECT_LOCK packet every time an object is locked 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(); mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
objectList->reset(); objectList->reset();
@ -471,9 +476,9 @@ namespace MWScript
Start of tes3mp addition Start of tes3mp addition
Send an ID_OBJECT_LOCK packet every time an object is unlocked 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(); mwmp::ObjectList *objectList = mwmp::Main::get().getNetworking()->getObjectList();
objectList->reset(); objectList->reset();

@ -12,6 +12,7 @@
#include "../mwmp/LocalPlayer.hpp" #include "../mwmp/LocalPlayer.hpp"
#include "../mwmp/PlayerList.hpp" #include "../mwmp/PlayerList.hpp"
#include "../mwmp/ObjectList.hpp" #include "../mwmp/ObjectList.hpp"
#include "../mwmp/CellController.hpp"
#include "../mwmp/ScriptController.hpp" #include "../mwmp/ScriptController.hpp"
/* /*
End of tes3mp addition End of tes3mp addition
@ -443,10 +444,52 @@ namespace MWScript
} }
if(store) 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; MWWorld::Ptr base = ptr;
ptr = MWBase::Environment::get().getWorld()->moveObject(ptr,store,x,y,z); ptr = MWBase::Environment::get().getWorld()->moveObject(ptr,store,x,y,z);
dynamic_cast<MWScript::InterpreterContext&>(runtime.getContext()).updatePtr(base,ptr); dynamic_cast<MWScript::InterpreterContext&>(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 ax = ptr.getRefData().getPosition().rot[0];
float ay = ptr.getRefData().getPosition().rot[1]; 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) // Note that you must specify ZRot in minutes (1 degree = 60 minutes; north = 0, east = 5400, south = 10800, west = 16200)

@ -605,47 +605,26 @@ namespace MWWorld
{ {
const unsigned int mRefNumToFind; const unsigned int mRefNumToFind;
const unsigned int mMpNumToFind; 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 std::string mRefIdToFind;
const unsigned int mRefNumToFind; const bool mActorsOnly;
const unsigned int mMpNumToFind;
public: 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; Ptr mFound;
bool operator()(const Ptr& ptr) 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; if (!mActorsOnly || ptr.getClass().isActor())
return false; {
if (mRefIdToFind.empty() || Misc::StringUtils::ciEqual(ptr.getCellRef().getRefId(), mRefIdToFind))
{
mFound = ptr;
return false;
}
}
} }
return true; return true;
} }
@ -659,33 +638,13 @@ namespace MWWorld
Allow the searching of objects by their reference numbers Allow the searching of objects by their reference numbers
*/ */
Ptr CellStore::searchExact (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;
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)
{ {
// Ensure that all objects searched for have a valid reference number // Ensure that all objects searched for have a valid reference number
if (refNum == 0 && mpNum == 0) if (refNum == 0 && mpNum == 0)
return 0; return 0;
SearchExactPlusVisitor searchVisitor(refId, refNum, mpNum); SearchExactVisitor searchVisitor(refNum, mpNum, refId, actorsOnly);
forEach(searchVisitor); forEach(searchVisitor);
return searchVisitor.mFound; return searchVisitor.mFound;
} }

@ -262,20 +262,10 @@ namespace MWWorld
/* /*
Start of tes3mp addition 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); Ptr searchExact (unsigned int refNum, unsigned int mpNum, std::string refId = "", bool actorsOnly = false);
/*
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);
/* /*
End of tes3mp addition End of tes3mp addition
*/ */

@ -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 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(); 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(); 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(); mwmp::LocalPlayer *localPlayer = mwmp::Main::get().getLocalPlayer();

@ -276,7 +276,7 @@ namespace MWWorld
/* /*
Start of tes3mp addition 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 other types of records can be overridden
*/ */
template <> template <>
@ -287,6 +287,20 @@ namespace MWWorld
End of tes3mp addition 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<ESM::Pathgrid>(const ESM::Pathgrid& pathgrid) {
return mPathgrids.override(pathgrid);
}
/*
End of tes3mp addition
*/
template <> template <>
inline const ESM::Cell *ESMStore::insert<ESM::Cell>(const ESM::Cell &cell) { inline const ESM::Cell *ESMStore::insert<ESM::Cell>(const ESM::Cell &cell) {
return mCells.insert(cell); return mCells.insert(cell);

@ -796,7 +796,7 @@ namespace MWWorld
/* /*
Start of tes3mp addition 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 other types of records can be overridden
*/ */
ESM::Cell *Store<ESM::Cell>::override(const ESM::Cell &cell) ESM::Cell *Store<ESM::Cell>::override(const ESM::Cell &cell)
@ -949,6 +949,37 @@ namespace MWWorld
return RecordId("", isDeleted); 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<ESM::Pathgrid>::override(const ESM::Pathgrid& pathgrid)
{
bool interior = mCells->search(pathgrid.mCell) != nullptr;
// Try to overwrite existing record
if (interior)
{
std::pair<Interior::iterator, bool> ret = mInt.insert(std::make_pair(pathgrid.mCell, pathgrid));
if (!ret.second)
ret.first->second = pathgrid;
return &ret.first->second;
}
else
{
std::pair<Exterior::iterator, bool> 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<ESM::Pathgrid>::getSize() const size_t Store<ESM::Pathgrid>::getSize() const
{ {
return mInt.size() + mExt.size(); return mInt.size() + mExt.size();

@ -325,7 +325,7 @@ namespace MWWorld
/* /*
Start of tes3mp addition 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 other types of records can be overridden
*/ */
ESM::Cell *override(const ESM::Cell &cell); ESM::Cell *override(const ESM::Cell &cell);
@ -362,6 +362,17 @@ namespace MWWorld
void setUp() override; 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(int x, int y) const;
const ESM::Pathgrid *search(const std::string& name) const; const ESM::Pathgrid *search(const std::string& name) const;
const ESM::Pathgrid *find(int x, int y) const; const ESM::Pathgrid *find(int x, int y) const;

@ -3971,6 +3971,12 @@ namespace MWWorld
MWWorld::Ptr player = getPlayerPtr(); MWWorld::Ptr player = getPlayerPtr();
player.getClass().getInventoryStore(player).rechargeItems(duration); player.getClass().getInventoryStore(player).rechargeItems(duration);
/*
Start of tes3mp change (major)
Don't unilaterally recharge world items on clients
*/
/*
if (activeOnly) if (activeOnly)
{ {
for (auto &cell : mWorldScene->getActiveCells()) for (auto &cell : mWorldScene->getActiveCells())
@ -3980,6 +3986,10 @@ namespace MWWorld
} }
else else
mCells.recharge(duration); mCells.recharge(duration);
*/
/*
End of tes3mp change (major)
*/
} }
void World::teleportToClosestMarker (const MWWorld::Ptr& ptr, void World::teleportToClosestMarker (const MWWorld::Ptr& ptr,

@ -19,7 +19,7 @@ namespace mwmp
hasStatsDynamicData = false; hasStatsDynamicData = false;
} }
std::string refId; std::string refId = "";
unsigned int refNum; unsigned int refNum;
unsigned int mpNum; unsigned int mpNum;

@ -26,7 +26,7 @@ namespace mwmp
struct BaseObject struct BaseObject
{ {
std::string refId; std::string refId = "";
unsigned int refNum; unsigned int refNum;
unsigned int mpNum; unsigned int mpNum;
int count; int count;

@ -106,6 +106,9 @@ set(MYGUI_FILES
openmw_windows.skin.xml openmw_windows.skin.xml
DejaVuLGCSansMono.ttf DejaVuLGCSansMono.ttf
../launcher/images/openmw.png ../launcher/images/openmw.png
# Start of tes3mp addition
../tes3mp/tes3mp_logo.png
# End of tes3mp addition
OpenMWResourcePlugin.xml OpenMWResourcePlugin.xml
skins.xml skins.xml

Loading…
Cancel
Save