diff --git a/README.md b/README.md index 0d8a338cb..1f6602e55 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ TES3MP [![Build Status](https://travis-ci.org/TES3MP/openmw-tes3mp.svg?branch=master)](https://travis-ci.org/TES3MP/openmw-tes3mp) -TES3MP is a project aiming to add multiplayer functionality to [OpenMW](https://github.com/OpenMW/openmw), a free and open source recreation of the popular Bethesda Softworks' game "The Elder Scrolls III: Morrowind". +TES3MP is a project aiming to add multiplayer functionality to [OpenMW](https://github.com/OpenMW/openmw), a free and open source recreation of the popular Bethesda Softworks game "The Elder Scrolls III: Morrowind". -* Version: 0.4.2 +* Version: 0.5.0 * License: GPLv3 (see docs/license/GPL3.txt for more information) * Website: https://steamcommunity.com/groups/mwmulti @@ -17,14 +17,16 @@ Project Status [Version changelog](https://github.com/TES3MP/openmw-tes3mp/blob/master/tes3mp-changelog.md) -We are still in an early phase of development. At the moment we have synchronization of character appearance, character skills, stats, attributes and death as well as movement on interiors and exteriors, melee and ranged combat, picking up and dropping items in the world and using doors and levers. +Our project is not yet in a playable state, though we are getting close. At the moment we have synchronization of character appearance, character skills, stats, attributes and death, movement in interiors and exteriors, melee and ranged combat, spell casting, picking up and dropping items in the world, using doors and levers, and adding and removing items from containers, as well as [serverside Lua scripts](https://github.com/TES3MP/PluginExamples) used to save and load the state of most of the aforementioned. Contributing -------------- -Development has been somewhat fast, but any contribution regarding [code](https://github.com/TES3MP/openmw-tes3mp/blob/master/CONTRIBUTING.md), documentation, bug hunting, artwork or nice Jobasha's gift cards are greatly appreciated. -Test sessions are often advertised in our Steam Group, there is also a chat room there. -Feel free to contact any of the [team members](https://github.com/TES3MP/openmw-tes3mp/blob/master/tes3mp-credits.md) for any questions you might have. +Development has been relatively fast, but any contribution regarding [code](https://github.com/TES3MP/openmw-tes3mp/blob/master/CONTRIBUTING.md), documentation, bug hunting or video showcases is greatly appreciated. + +Test sessions are often advertised in [our Steam group](https://steamcommunity.com/groups/mwmulti) or [our Discord server](https://discord.gg/H8zhhuk). + +Feel free to contact the [team members](https://github.com/TES3MP/openmw-tes3mp/blob/master/tes3mp-credits.md) for any questions you might have. Getting Started --------------- @@ -36,4 +38,4 @@ Getting Started Donations --------------- -You can benefit the project by supporting OpenMW and or by [becoming Koncord's patron](https://www.patreon.com/Koncord). +You can benefit the project by supporting OpenMW and/or by [becoming Koncord's patron](https://www.patreon.com/Koncord). diff --git a/apps/browser/MainWindow.cpp b/apps/browser/MainWindow.cpp index 1edc8a606..0d896986b 100644 --- a/apps/browser/MainWindow.cpp +++ b/apps/browser/MainWindow.cpp @@ -125,6 +125,15 @@ void MainWindow::play() QStringList arguments; arguments.append(QLatin1String("--connect=") + sm->myData[sourceId].addr.toLatin1()); + if(sm->myData[sourceId].needPassw) + { + bool ok; + QString passw = QInputDialog::getText(this, "Connecting to: " + sm->myData[sourceId].addr, "Password: ", QLineEdit::Password, "", &ok); + if(!ok) + return; + arguments.append(QLatin1String("--password=") + passw.toLatin1()); + } + if (mGameInvoker->startProcess(QLatin1String("tes3mp"), arguments, true)) return qApp->quit(); } diff --git a/apps/browser/NetController.cpp b/apps/browser/NetController.cpp index e07f74f9f..e15c57800 100644 --- a/apps/browser/NetController.cpp +++ b/apps/browser/NetController.cpp @@ -78,6 +78,12 @@ void NetController::setData(QString address, QJsonObject server, ServerModel *mo mi = model->index(0, ServerData::MODNAME); model->setData(mi, server["modname"].toString()); + mi = model->index(0, ServerData::VERSION); + model->setData(mi, server["version"].toString()); + + mi = model->index(0, ServerData::PASSW); + model->setData(mi, server["passw"].toBool()); + mi = model->index(0, ServerData::PING); QStringList addr = address.split(":"); @@ -149,6 +155,8 @@ bool NetController::downloadInfo(QAbstractItemModel *pModel, QModelIndex index) qDebug() << server["modname"].toString(); qDebug() << server["players"].toInt(); qDebug() << server["max_players"].toInt(); + qDebug() << server["version"].toString(); + qDebug() << server["passw"].toBool(); QVector::Iterator value = std::find_if(model->myData.begin(), model->myData.end(), pattern(iter.key())); if(value == model->myData.end()) @@ -209,6 +217,8 @@ void NetController::updateInfo() qDebug() << map["modname"].toString(); qDebug() << map["players"].toInt(); qDebug() << map["max_players"].toInt(); + qDebug() << map["version"].toString(); + qDebug() << map["passw"].toBool(); sd->hostName = map["hostname"].toString(); sd->modName = map["modname"].toString(); diff --git a/apps/browser/ServerModel.cpp b/apps/browser/ServerModel.cpp index 8739075e6..1aaa9e88e 100644 --- a/apps/browser/ServerModel.cpp +++ b/apps/browser/ServerModel.cpp @@ -33,6 +33,12 @@ QVariant ServerModel::data(const QModelIndex &index, int role) const case ServerData::ADDR: var = sd.addr; break; + case ServerData::PASSW: + var = sd.needPassw ? "Yes" : "No"; + break; + case ServerData::VERSION: + var = sd.version; + break; case ServerData::PLAYERS: var = sd.players; break; @@ -75,6 +81,12 @@ QVariant ServerModel::headerData(int section, Qt::Orientation orientation, int r case ServerData::ADDR: var = "Address"; break; + case ServerData::PASSW: + var = "Password"; + break; + case ServerData::VERSION: + var = "Version"; + break; case ServerData::HOSTNAME: var = "Host name"; break; @@ -82,7 +94,7 @@ QVariant ServerModel::headerData(int section, Qt::Orientation orientation, int r var = "Players"; break; case ServerData::MAX_PLAYERS: - var = "Player Max"; + var = "Max players"; break; case ServerData::PING: var = "Ping"; @@ -120,6 +132,13 @@ bool ServerModel::setData(const QModelIndex &index, const QVariant &value, int r sd.addr = value.toString(); ok = !sd.addr.isEmpty(); break; + case ServerData::PASSW: + sd.needPassw = value.toBool(); + break; + case ServerData::VERSION: + sd.version = value.toString(); + ok = !sd.addr.isEmpty(); + break; case ServerData::PLAYERS: sd.players = value.toInt(&ok); break; @@ -152,7 +171,7 @@ bool ServerModel::insertRows(int position, int count, const QModelIndex &index) beginInsertRows(QModelIndex(), position, position + count - 1); for (int row = 0; row < count; ++row) { - ServerData sd {"", -1, -1, -1, "", ""}; + ServerData sd {"", -1, -1, -1, "", "", false, 0}; myData.insert(position, sd); } diff --git a/apps/browser/ServerModel.hpp b/apps/browser/ServerModel.hpp index bd9ffbb19..78f16501b 100644 --- a/apps/browser/ServerModel.hpp +++ b/apps/browser/ServerModel.hpp @@ -13,14 +13,18 @@ struct ServerData int ping; QString hostName; QString modName; + bool needPassw; + QString version; enum IDS { ADDR, HOSTNAME, PLAYERS, MAX_PLAYERS, + PASSW, MODNAME, PING, + VERSION, LAST }; }; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 4e608dbbd..33a71e97a 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -1757,6 +1757,41 @@ namespace CSMWorld return true; } }; + + template + struct GenderNpcColumn : public Column + { + GenderNpcColumn() + : Column(Columns::ColumnId_GenderNpc, ColumnBase::Display_GenderNpc) + {} + + virtual QVariant get(const Record& record) const + { + // Implemented this way to allow additional gender types in the future. + if ((record.get().mData.mFlags & ESM::BodyPart::BPF_Female) == ESM::BodyPart::BPF_Female) + return 1; + + return 0; + } + + virtual void set(Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + // Implemented this way to allow additional gender types in the future. + if (data.toInt() == 1) + record2.mData.mFlags = (record2.mData.mFlags & ~ESM::BodyPart::BPF_Female) | ESM::BodyPart::BPF_Female; + else + record2.mData.mFlags = record2.mData.mFlags & ~ESM::BodyPart::BPF_Female; + + record.setModified(record2); + } + + virtual bool isEditable() const + { + return true; + } + }; template struct EnchantmentTypeColumn : public Column diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index da4942eec..5a59f19f7 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -363,7 +363,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mBodyParts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_BodyPart)); mBodyParts.addColumn (new BodyPartTypeColumn); mBodyParts.addColumn (new VampireColumn); - mBodyParts.addColumn (new FlagColumn (Columns::ColumnId_Female, ESM::BodyPart::BPF_Female)); + mBodyParts.addColumn(new GenderNpcColumn); mBodyParts.addColumn (new FlagColumn (Columns::ColumnId_Playable, ESM::BodyPart::BPF_NotPlayable, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, true)); diff --git a/apps/openmw-mp/CMakeLists.txt b/apps/openmw-mp/CMakeLists.txt index 11863815f..abb770efb 100644 --- a/apps/openmw-mp/CMakeLists.txt +++ b/apps/openmw-mp/CMakeLists.txt @@ -35,9 +35,10 @@ if(BUILD_WITH_PAWN) endif(BUILD_WITH_PAWN) option(BUILD_WITH_LUA "Enable Terra/Lua language" ON) +option(FORCE_LUA "Use Lua instead Terra" OFF) if(BUILD_WITH_LUA) #set(Terra_ROOT ${CMAKE_SOURCE_DIR}/external/terra/) - if(WIN32) + if(WIN32 OR FORCE_LUA) find_package(Lua51 REQUIRED) MESSAGE(STATUS "Found LUA_LIBRARY: ${LUA_LIBRARY}") MESSAGE(STATUS "Found LUA_INCLUDE_DIR: ${LUA_INCLUDE_DIR}") @@ -69,6 +70,7 @@ set(SERVER Networking.cpp Utils.cpp MasterClient.cpp + Cell.cpp Script/Script.cpp Script/ScriptFunction.cpp Script/ScriptFunctions.cpp diff --git a/apps/openmw-mp/Cell.cpp b/apps/openmw-mp/Cell.cpp new file mode 100644 index 000000000..79d6fc98c --- /dev/null +++ b/apps/openmw-mp/Cell.cpp @@ -0,0 +1,223 @@ +// +// Created by koncord on 18.02.17. +// + +#include "Cell.hpp" + +#include +#include "Player.hpp" + +using namespace std; + +void Cell::addPlayer(Player *player) +{ + auto it = find(player->cells.begin(), player->cells.end(), this); + if (it == player->cells.end()) + player->cells.push_back(this); + players.push_back(player); +} + +void Cell::removePlayer(Player *player) +{ + for (Iterator it = begin(); it != end(); it++) + { + if (*it == player) + { + auto it2 = find(player->cells.begin(), player->cells.end(), this); + if (it2 != player->cells.end()) + player->cells.erase(it2); + players.erase(it); + return; + } + } +} + +Cell::TPlayers Cell::getPlayers() +{ + return players; +} + +void Cell::sendToLoaded(mwmp::WorldPacket *worldPacket, mwmp::BaseEvent *baseEvent) +{ + std::list plList; + + for (auto pl :getPlayers()) + plList.push_back(pl); + + plList.sort(); + plList.unique(); + + for (auto pl : plList) + { + if (pl->guid == baseEvent->guid) continue; + worldPacket->Send(baseEvent, pl->guid); + } +} + +std::string Cell::getDescription() const +{ + return cell.getDescription(); +} + +CellController::CellController() +{ + +} + +CellController::~CellController() +{ + +} + +CellController *CellController::sThis = nullptr; + +void CellController::create() +{ + sThis = new CellController; +} + +void CellController::destroy() +{ + assert(sThis); + delete sThis; + sThis = nullptr; +} + +CellController *CellController::get() +{ + return sThis; +} + +Cell *CellController::getCell(ESM::Cell *esmCell) +{ + if (esmCell->isExterior()) + return getCellByXY(esmCell->mData.mX, esmCell->mData.mY); + else + return getCellByName(esmCell->mName); +} + + +Cell *CellController::getCellByXY(int x, int y) +{ + auto it = find_if(cells.begin(), cells.end(), [x, y](const Cell *c) { + return c->cell.mData.mX == x && c->cell.mData.mY == y; + }); + if (it == cells.end()) + return nullptr; + return *it; +} + +Cell *CellController::getCellByName(std::string cellName) +{ + auto it = find_if(cells.begin(), cells.end(), [cellName](const Cell *c) { + return c->cell.mName == cellName; + }); + if (it == cells.end()) + return nullptr; + return *it; +} + +Cell *CellController::addCell(ESM::Cell cellData) +{ + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Loaded cells: %d", cells.size()); + auto it = find_if(cells.begin(), cells.end(), [cellData](const Cell *c) { + //return c->cell.sRecordId == cellData.sRecordId; // Currently we cannot compare because plugin lists can be loaded in different order + return c->cell.mData.mX == cellData.mData.mX && c->cell.mData.mY == cellData.mData.mY && + c->cell.mCellId.mWorldspace == cellData.mCellId.mWorldspace; + }); + Cell *cell; + if (it == cells.end()) + { + cell = new Cell(cellData); + cells.push_back(cell); + } + else + cell = *it; + return cell; + + +} + +void CellController::removeCell(Cell *cell) +{ + if (cell == nullptr) + return; + for (auto it = cells.begin(); it != cells.end();) + { + if (*it != nullptr && *it == cell) + { + delete *it; + it = cells.erase(it); + } + else + ++it; + } +} + +void CellController::removePlayer(Cell *cell, Player *player) +{ + cell->removePlayer(player); + + if (cell->players.empty()) + { + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Deleting empty cell from memory: %s", player->npc.mName.c_str(), + player->getId(), cell->cell.getDescription().c_str()); + auto it = find(cells.begin(), cells.end(), cell); + delete *it; + cells.erase(it); + } +} + +void CellController::deletePlayer(Player *player) +{ + + for_each(player->getCells()->begin(), player->getCells()->end(), [&player](Cell *cell) { + for (auto it = cell->begin(); it != cell->end(); ++it) + { + if (*it == player) + { + cell->players.erase(it); + break; + } + } + }); +} + +void CellController::update(Player *player) +{ + for (auto cell : player->cellStateChanges.cellStates) + { + if (cell.type == mwmp::CellState::LOAD) + { + Cell *c = addCell(cell.cell); + c->addPlayer(player); + } + else + { + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Player %s (%d) unloaded cell: %s", player->npc.mName.c_str(), player->getId(), cell.cell.getDescription().c_str()); + Cell *c; + if (!cell.cell.isExterior()) + c = getCellByName(cell.cell.mName); + else + c = getCellByXY(cell.cell.getGridX(), cell.cell.getGridY()); + + if (c != nullptr) + removePlayer(c, player); + } + } +} + +Cell::Cell(ESM::Cell cell): cell(cell) +{ + +} + +Cell::Iterator Cell::begin() const +{ + return players.begin(); +} + +Cell::Iterator Cell::end() const +{ + return players.end(); +} diff --git a/apps/openmw-mp/Cell.hpp b/apps/openmw-mp/Cell.hpp new file mode 100644 index 000000000..5ddeddbb4 --- /dev/null +++ b/apps/openmw-mp/Cell.hpp @@ -0,0 +1,76 @@ +// +// Created by koncord on 18.02.17. +// + +#ifndef OPENMW_CELL_HPP +#define OPENMW_CELL_HPP + +#include +#include +#include +#include +#include + +class Player; +class Cell; + + +class CellController +{ +private: + CellController(); + ~CellController(); + + CellController(CellController&); // not used +public: + static void create(); + static void destroy(); + static CellController *get(); +public: + typedef std::deque TContainer; + typedef TContainer::iterator TIter; + + Cell * addCell(ESM::Cell cell); + void removeCell(Cell *); + + void removePlayer(Cell *cell, Player *player); + void deletePlayer(Player *player); + + Cell *getCell(ESM::Cell *esmCell); + Cell *getCellByXY(int x, int y); + Cell *getCellByName(std::string cellName); + + void update(Player *player); + +private: + static CellController *sThis; + TContainer cells; +}; + +class Cell +{ + friend class CellController; +public: + Cell(ESM::Cell cell); + typedef std::deque TPlayers; + typedef TPlayers::const_iterator Iterator; + + Iterator begin() const; + Iterator end() const; + + void addPlayer(Player *player); + void removePlayer(Player *player); + + TPlayers getPlayers(); + void sendToLoaded(mwmp::WorldPacket *worldPacket, mwmp::BaseEvent *baseEvent); + + std::string getDescription() const; + + +private: + TPlayers players; + ESM::Cell cell; +}; + + +#endif //OPENMW_CELL_HPP diff --git a/apps/openmw-mp/MasterClient.cpp b/apps/openmw-mp/MasterClient.cpp index bdd915123..72a50af84 100644 --- a/apps/openmw-mp/MasterClient.cpp +++ b/apps/openmw-mp/MasterClient.cpp @@ -10,6 +10,7 @@ #include #include "MasterClient.hpp" #include +#include #include "Networking.hpp" using namespace std; @@ -69,7 +70,9 @@ MasterClient::Send(std::string hostname, std::string modname, unsigned maxPlayer sstr << "\"hostname\": \"" << hostname.c_str() << "\", "; sstr << "\"modname\": \"" << modname.c_str() << "\", "; sstr << "\"players\": " << players << ", "; - sstr << "\"max_players\": " << maxPlayers; + sstr << "\"max_players\": " << maxPlayers << ", "; + sstr << "\"version\": \"" << TES3MP_VERSION << "\", "; + sstr << "\"passw\": " << (mwmp::Networking::get().isPassworded() ? "true" : "false"); sstr << "}"; mutexData.unlock(); @@ -152,7 +155,7 @@ void MasterClient::Update() { LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Update rate is too low, and the master server has deleted information about" " the server. Trying low rate..."); - if((timeout - step_rate) >= step_rate) + if ((timeout - step_rate) >= step_rate) SetUpdateRate(timeout - step_rate); update = false; } @@ -177,10 +180,10 @@ void MasterClient::Start() void MasterClient::Stop() { - if(!sRun) + if (!sRun) return; sRun = false; - if(thrQuery.joinable()) + if (thrQuery.joinable()) thrQuery.join(); } diff --git a/apps/openmw-mp/Networking.cpp b/apps/openmw-mp/Networking.cpp index 0d3948df5..fded0c3e1 100644 --- a/apps/openmw-mp/Networking.cpp +++ b/apps/openmw-mp/Networking.cpp @@ -15,6 +15,8 @@ #include "Networking.hpp" #include "MasterClient.hpp" +#include "Cell.hpp" +#include using namespace mwmp; using namespace std; @@ -29,6 +31,8 @@ Networking::Networking(RakNet::RakPeerInterface *peer) this->peer = peer; players = Players::getPlayers(); + CellController::create(); + playerController = new PlayerPacketController(peer); worldController = new WorldPacketController(peer); @@ -40,17 +44,31 @@ Networking::Networking(RakNet::RakPeerInterface *peer) exitCode = 0; Script::Call(); + + serverPassword = TES3MP_DEFAULT_PASSW; } Networking::~Networking() { Script::Call(false); + CellController::destroy(); + sThis = 0; delete playerController; LOG_QUIT(); } +void Networking::setServerPassword(std::string passw) noexcept +{ + serverPassword = passw.empty() ? TES3MP_DEFAULT_PASSW : passw; +} + +bool Networking::isPassworded() const +{ + return serverPassword != TES3MP_DEFAULT_PASSW; +} + void Networking::processPlayerPacket(RakNet::Packet *packet) { Player *player = Players::getPlayer(packet->guid); @@ -59,7 +77,6 @@ void Networking::processPlayerPacket(RakNet::Packet *packet) if (packet->data[0] == ID_HANDSHAKE) { - string passw = "SuperPassword"; myPacket->Read(player); @@ -72,7 +89,7 @@ void Networking::processPlayerPacket(RakNet::Packet *packet) return; } - if (player->passw != passw) + if (player->passw != serverPassword) { LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Wrong server password for player %d, name: %s (pass: %s)", player->getId(), @@ -145,7 +162,10 @@ void Networking::processPlayerPacket(RakNet::Packet *packet) if (!player->creatureStats.mDead) { myPacket->Read(player); - myPacket->Send(player, true); //send to other clients + //myPacket->Send(player, true); //send to other clients + + player->sendToLoaded(myPacket); + } break; @@ -162,7 +182,27 @@ void Networking::processPlayerPacket(RakNet::Packet *packet) LOG_APPEND(Log::LOG_INFO, "- Moved to %s", player->cell.getDescription().c_str()); + player->forEachLoaded([this](Player *pl, Player *other) { + playerController->GetPacket(ID_PLAYER_DYNAMICSTATS)->Send(other, pl->guid); + playerController->GetPacket(ID_PLAYER_ATTRIBUTE)->Send(other, pl->guid); + playerController->GetPacket(ID_PLAYER_POS)->Send(other, pl->guid); + playerController->GetPacket(ID_PLAYER_SKILL)->Send(other, pl->guid); + playerController->GetPacket(ID_PLAYER_EQUIPMENT)->Send(other, pl->guid); + playerController->GetPacket(ID_PLAYER_DRAWSTATE)->Send(other, pl->guid); + + playerController->GetPacket(ID_PLAYER_DYNAMICSTATS)->Send(pl, other->guid); + playerController->GetPacket(ID_PLAYER_ATTRIBUTE)->Send(pl, other->guid); + playerController->GetPacket(ID_PLAYER_SKILL)->Send(pl, other->guid); + playerController->GetPacket(ID_PLAYER_EQUIPMENT)->Send(pl, other->guid); + playerController->GetPacket(ID_PLAYER_DRAWSTATE)->Send(pl, other->guid); + + LOG_APPEND(Log::LOG_INFO, "- Exchanged information with %s", + other->npc.mName.c_str()); + }); + + playerController->GetPacket(ID_PLAYER_POS)->Send(player); myPacket->Send(player, true); //send to other clients + Script::Call(player->getId()); } else @@ -180,6 +220,8 @@ void Networking::processPlayerPacket(RakNet::Packet *packet) myPacket->Read(player); + CellController::get()->update(player); + Script::Call(player->getId()); break; @@ -190,7 +232,9 @@ void Networking::processPlayerPacket(RakNet::Packet *packet) if (!player->creatureStats.mDead) { myPacket->Read(player); - myPacket->Send(player, true); + //myPacket->Send(player, true); + + player->sendToLoaded(myPacket); Script::Call(player->getId()); } @@ -203,7 +247,8 @@ void Networking::processPlayerPacket(RakNet::Packet *packet) if (!player->creatureStats.mDead) { myPacket->Read(player); - myPacket->Send(player, true); + //myPacket->Send(player, true); + player->sendToLoaded(myPacket); Script::Call(player->getId()); } @@ -216,7 +261,7 @@ void Networking::processPlayerPacket(RakNet::Packet *packet) if (!player->creatureStats.mDead) { myPacket->Read(player); - myPacket->Send(player, true); + //myPacket->Send(player, true); Script::Call(player->getId()); } @@ -228,7 +273,9 @@ void Networking::processPlayerPacket(RakNet::Packet *packet) DEBUG_PRINTF("ID_PLAYER_EQUIPMENT\n"); myPacket->Read(player); - myPacket->Send(player, true); + //myPacket->Send(player, true); + + player->sendToLoaded(myPacket); Script::Call(player->getId()); @@ -291,7 +338,8 @@ void Networking::processPlayerPacket(RakNet::Packet *packet) } } - myPacket->Send(player, true); + //myPacket->Send(player, true); + player->sendToLoaded(myPacket); playerController->GetPacket(ID_PLAYER_DYNAMICSTATS)->RequestData(player->attack.target); } break; @@ -301,7 +349,10 @@ void Networking::processPlayerPacket(RakNet::Packet *packet) { DEBUG_PRINTF("ID_PLAYER_DYNAMICSTATS\n"); myPacket->Read(player); - myPacket->Send(player, true); + //myPacket->Send(player, true); + + player->sendToLoaded(myPacket); + break; } @@ -352,7 +403,10 @@ void Networking::processPlayerPacket(RakNet::Packet *packet) { DEBUG_PRINTF("ID_PLAYER_DRAWSTATE\n"); myPacket->Read(player); - myPacket->Send(player, true); + //myPacket->Send(player, true); + + player->sendToLoaded(myPacket); + break; } @@ -558,7 +612,16 @@ void Networking::processWorldPacket(RakNet::Packet *packet) player->npc.mName.c_str()); myPacket->Read(baseEvent); - myPacket->Send(baseEvent, true); + + LOG_APPEND(Log::LOG_WARN, "- action: %i", baseEvent->action); + + // Until we have a timestamp-based system, send packets pertaining to more + // than one container (i.e. replies to server requests for container contents) + // only to players who have the container's cell loaded + if (baseEvent->action == BaseEvent::SET && baseEvent->objectChanges.count > 1) + CellController::get()->getCell(&baseEvent->cell)->sendToLoaded(myPacket, baseEvent); + else + myPacket->Send(baseEvent, true); Script::Call( player->getId(), @@ -817,7 +880,7 @@ int Networking::mainLoop() RakNet::BitStream bs; bs.Write((unsigned char) ID_MASTER_QUERY); bs.Write(Players::getPlayers()->size()); - for(auto player : *Players::getPlayers()) + for (auto player : *Players::getPlayers()) bs.Write(RakNet::RakString(player.second->npc.mName.c_str())); bs.Write(0); // plugins peer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false); diff --git a/apps/openmw-mp/Networking.hpp b/apps/openmw-mp/Networking.hpp index 24bac7775..046e46471 100644 --- a/apps/openmw-mp/Networking.hpp +++ b/apps/openmw-mp/Networking.hpp @@ -40,11 +40,14 @@ namespace mwmp MasterClient *getMasterClient(); void InitQuery(std::string queryAddr, unsigned short queryPort, std::string serverAddr, unsigned short serverPort); + void setServerPassword(std::string passw) noexcept; + bool isPassworded() const; static const Networking &get(); static Networking *getPtr(); private: + std::string serverPassword; static Networking *sThis; RakNet::RakPeerInterface *peer; RakNet::BitStream bsOut; diff --git a/apps/openmw-mp/Player.cpp b/apps/openmw-mp/Player.cpp index 666ed5282..db3e7b760 100644 --- a/apps/openmw-mp/Player.cpp +++ b/apps/openmw-mp/Player.cpp @@ -15,6 +15,8 @@ void Players::deletePlayer(RakNet::RakNetGUID guid) if (players[guid] != 0) { + CellController::get()->deletePlayer(players[guid]); + LOG_APPEND(Log::LOG_INFO, "- Emptying slot %i", players[guid]->getId()); @@ -52,7 +54,7 @@ void Players::newPlayer(RakNet::RakNetGUID guid) Player *Players::getPlayer(RakNet::RakNetGUID guid) { - if(players.count(guid) == 0) + if (players.count(guid) == 0) return nullptr; return players[guid]; } @@ -135,3 +137,44 @@ std::chrono::steady_clock::time_point Player::getLastAttackerTime() { return lastAttackerTime; } + +CellController::TContainer *Player::getCells() +{ + return &cells; +} + +void Player::sendToLoaded(mwmp::PlayerPacket *myPacket) +{ + std::list plList; + + for (auto cell : cells) + for (auto pl : *cell) + plList.push_back(pl); + + plList.sort(); + plList.unique(); + + for (auto pl : plList) + { + if (pl == this) continue; + myPacket->Send(this, pl->guid); + } +} + +void Player::forEachLoaded(std::function func) +{ + std::list plList; + + for (auto cell : cells) + for (auto pl : *cell) + plList.push_back(pl); + + plList.sort(); + plList.unique(); + + for (auto pl : plList) + { + if (pl == this) continue; + func(this, pl); + } +} diff --git a/apps/openmw-mp/Player.hpp b/apps/openmw-mp/Player.hpp index 3fdc0b2e3..cf83b9688 100644 --- a/apps/openmw-mp/Player.hpp +++ b/apps/openmw-mp/Player.hpp @@ -17,6 +17,8 @@ #include #include +#include +#include "Cell.hpp" struct Player; typedef std::map TPlayers; @@ -38,6 +40,7 @@ private: class Player : public mwmp::BasePlayer { + friend class Cell; unsigned short id; public: @@ -67,12 +70,18 @@ public: virtual ~Player(); + CellController::TContainer *getCells(); + void sendToLoaded(mwmp::PlayerPacket *myPacket); + + void forEachLoaded(std::function func); + public: mwmp::InventoryChanges inventoryChangesBuffer; mwmp::SpellbookChanges spellbookChangesBuffer; mwmp::JournalChanges journalChangesBuffer; private: + CellController::TContainer cells; bool handshakeState; int loadState; unsigned short lastAttacker; diff --git a/apps/openmw-mp/Script/Functions/World.cpp b/apps/openmw-mp/Script/Functions/World.cpp index 7bda0190d..713a56b43 100644 --- a/apps/openmw-mp/Script/Functions/World.cpp +++ b/apps/openmw-mp/Script/Functions/World.cpp @@ -132,12 +132,6 @@ int WorldFunctions::GetContainerItemCharge(unsigned int objectIndex, unsigned in .containerChanges.items.at(itemIndex).charge; } -int WorldFunctions::GetContainerItemGoldValue(unsigned int objectIndex, unsigned int itemIndex) noexcept -{ - return mwmp::Networking::getPtr()->getLastEvent()->objectChanges.objects.at(objectIndex) - .containerChanges.items.at(itemIndex).goldValue; -} - int WorldFunctions::GetContainerItemActionCount(unsigned int objectIndex, unsigned int itemIndex) noexcept { return mwmp::Networking::getPtr()->getLastEvent()->objectChanges.objects.at(objectIndex) diff --git a/apps/openmw-mp/Script/Functions/World.hpp b/apps/openmw-mp/Script/Functions/World.hpp index 1dcb8365e..21b5607da 100644 --- a/apps/openmw-mp/Script/Functions/World.hpp +++ b/apps/openmw-mp/Script/Functions/World.hpp @@ -26,7 +26,6 @@ {"GetContainerItemRefId", WorldFunctions::GetContainerItemRefId},\ {"GetContainerItemCount", WorldFunctions::GetContainerItemCount},\ {"GetContainerItemCharge", WorldFunctions::GetContainerItemCharge},\ - {"GetContainerItemGoldValue", WorldFunctions::GetContainerItemGoldValue},\ {"GetContainerItemActionCount", WorldFunctions::GetContainerItemActionCount},\ \ {"SetBaseEventCell", WorldFunctions::SetBaseEventCell},\ @@ -90,7 +89,6 @@ public: static const char *GetContainerItemRefId(unsigned int objectIndex, unsigned int itemIndex) noexcept; static int GetContainerItemCount(unsigned int objectIndex, unsigned int itemIndex) noexcept; static int GetContainerItemCharge(unsigned int objectIndex, unsigned int itemIndex) noexcept; - static int GetContainerItemGoldValue(unsigned int objectIndex, unsigned int itemIndex) noexcept; static int GetContainerItemActionCount(unsigned int objectIndex, unsigned int itemIndex) noexcept; static void SetBaseEventCell(const char* cellDescription) noexcept; diff --git a/apps/openmw-mp/Script/ScriptFunctions.cpp b/apps/openmw-mp/Script/ScriptFunctions.cpp index 42f9ec557..a4032238c 100644 --- a/apps/openmw-mp/Script/ScriptFunctions.cpp +++ b/apps/openmw-mp/Script/ScriptFunctions.cpp @@ -139,3 +139,8 @@ void ScriptFunctions::SetHostname(const char *name) noexcept { mwmp::Networking::getPtr()->getMasterClient()->SetHostname(name); } + +void ScriptFunctions::SetServerPassword(const char *passw) noexcept +{ + mwmp::Networking::getPtr()->setServerPassword(passw); +} diff --git a/apps/openmw-mp/Script/ScriptFunctions.hpp b/apps/openmw-mp/Script/ScriptFunctions.hpp index 2233f6c99..9d8817597 100644 --- a/apps/openmw-mp/Script/ScriptFunctions.hpp +++ b/apps/openmw-mp/Script/ScriptFunctions.hpp @@ -66,6 +66,7 @@ public: static int GetAvgPing(unsigned short pid) noexcept; static void SetModname(const char* name) noexcept; static void SetHostname(const char* name) noexcept; + static void SetServerPassword(const char *passw) noexcept; static constexpr ScriptFunctionData functions[]{ {"CreateTimer", ScriptFunctions::CreateTimer}, @@ -88,6 +89,7 @@ public: {"GetAvgPing", ScriptFunctions::GetAvgPing}, {"SetModname", ScriptFunctions::SetModname}, {"SetHostname", ScriptFunctions::SetHostname}, + {"SetServerPassword", ScriptFunctions::SetServerPassword}, POSITIONAPI, CELLAPI, diff --git a/apps/openmw-mp/main.cpp b/apps/openmw-mp/main.cpp index ee6b7e558..a0b127e45 100644 --- a/apps/openmw-mp/main.cpp +++ b/apps/openmw-mp/main.cpp @@ -44,7 +44,12 @@ void printVersion(string version, int protocol) #elif defined(__i386__) || defined(_M_I86) cout << "32-bit"; #elif defined(__arm__) - cout << "ARMv" << __ARM_ARCH << " " << (__aarch64__ ? "64-bit" : "32-bit"); + cout << "ARMv" << __ARM_ARCH << " "; + #ifdef __aarch64__ + cout << "64-bit"; + #else + cout << "32-bit"; + #endif #else cout << "Unknown architecture"; #endif @@ -183,6 +188,8 @@ int main(int argc, char *argv[]) string addr = mgr.getString("address", "General"); int port = mgr.getInt("port", "General"); + string passw = mgr.getString("password", "General"); + string plugin_home = mgr.getString("home", "Plugins"); string moddir = Utils::convertPath(plugin_home + "/data"); @@ -227,6 +234,7 @@ int main(int argc, char *argv[]) peer->SetMaximumIncomingConnections((unsigned short)(players)); Networking networking(peer); + networking.setServerPassword(passw); if ( mgr.getBool("enabled", "MasterServer")) { diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 1704577eb..e0de94805 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -209,7 +209,6 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) : mWindow(NULL) , mEncoding(ToUTF8::WINDOWS_1252) , mEncoder(NULL) - , mVerboseScripts (false) , mSkipMenu (false) , mUseSound (true) , mCompileAll (false) @@ -305,11 +304,6 @@ void OMW::Engine::addContentFile(const std::string& file) mContentFiles.push_back(file); } -void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity) -{ - mVerboseScripts = scriptsVerbosity; -} - void OMW::Engine::setSkipMenu (bool skipMenu, bool newGame) { mSkipMenu = skipMenu; @@ -555,8 +549,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) mScriptContext = new MWScript::CompilerContext (MWScript::CompilerContext::Type_Full); mScriptContext->setExtensions (&mExtensions); - mEnvironment.setScriptManager (new MWScript::ScriptManager (mEnvironment.getWorld()->getStore(), - mVerboseScripts, *mScriptContext, mWarningsMode, + mEnvironment.setScriptManager (new MWScript::ScriptManager (mEnvironment.getWorld()->getStore(), *mScriptContext, mWarningsMode, mScriptBlacklistUse ? mScriptBlacklist : std::vector())); // Create game mechanics system @@ -565,7 +558,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) // Create dialog system mEnvironment.setJournal (new MWDialogue::Journal); - mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage)); + mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mTranslationDataStorage)); // scripts if (mCompileAll) @@ -646,6 +639,8 @@ void OMW::Engine::go() if(!mwmp::Main::init(mContentFiles)) return; + std::cout << "OSG version: " << osgGetVersion() << std::endl; + mViewer = new osgViewer::Viewer; mViewer->setReleaseContextAtEndOfFrameHint(false); diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index 11b6ec0a6..d06ca594d 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -84,7 +84,6 @@ namespace OMW osg::ref_ptr mScreenCaptureHandler; std::string mCellName; std::vector mContentFiles; - bool mVerboseScripts; bool mSkipMenu; bool mUseSound; bool mCompileAll; @@ -158,9 +157,6 @@ namespace OMW */ void addContentFile(const std::string& file); - /// Enable or disable verbose script output - void setScriptsVerbosity(bool scriptsVerbosity); - /// Disable or enable all sounds void setSoundUsage(bool soundUsage); diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 96c478c9c..ca835ad51 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -100,9 +100,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("no-sound", bpo::value()->implicit_value(true) ->default_value(false), "disable all sounds") - ("script-verbose", bpo::value()->implicit_value(true) - ->default_value(false), "verbose script output") - ("script-all", bpo::value()->implicit_value(true) ->default_value(false), "compile all scripts (excluding dialogue scripts) at startup") @@ -242,7 +239,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat // scripts engine.setCompileAll(variables["script-all"].as()); engine.setCompileAllDialogue(variables["script-all-dialogue"].as()); - engine.setScriptsVerbosity(variables["script-verbose"].as()); engine.setScriptConsoleMode (variables["script-console"].as()); engine.setStartupScript (variables["script-run"].as().toStdString()); engine.setWarningsMode (variables["script-warn"].as()); diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index b3747f916..3e0ec366f 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -38,7 +38,6 @@ namespace MWClass { if(!model.empty()) physics.addObject(ptr, model); - MWBase::Environment::get().getMechanicsManager()->add(ptr); } std::string Activator::getModel(const MWWorld::ConstPtr &ptr) const @@ -52,6 +51,11 @@ namespace MWClass return ""; } + bool Activator::useAnim() const + { + return true; + } + std::string Activator::getName (const MWWorld::ConstPtr& ptr) const { const MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/activator.hpp b/apps/openmw/mwclass/activator.hpp index e90620cea..4fe4dda7e 100644 --- a/apps/openmw/mwclass/activator.hpp +++ b/apps/openmw/mwclass/activator.hpp @@ -39,6 +39,9 @@ namespace MWClass static void registerSelf(); virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; + + virtual bool useAnim() const; + ///< Whether or not to use animated variant of model (default false) }; } diff --git a/apps/openmw/mwclass/actor.cpp b/apps/openmw/mwclass/actor.cpp index d46729c1d..ecf089b35 100644 --- a/apps/openmw/mwclass/actor.cpp +++ b/apps/openmw/mwclass/actor.cpp @@ -34,7 +34,11 @@ namespace MWClass if (getCreatureStats(ptr).isDead()) MWBase::Environment::get().getWorld()->enableActorCollision(ptr, false); } - MWBase::Environment::get().getMechanicsManager()->add(ptr); + } + + bool Actor::useAnim() const + { + return true; } void Actor::block(const MWWorld::Ptr &ptr) const diff --git a/apps/openmw/mwclass/actor.hpp b/apps/openmw/mwclass/actor.hpp index 84b8f4ad8..c3720050c 100644 --- a/apps/openmw/mwclass/actor.hpp +++ b/apps/openmw/mwclass/actor.hpp @@ -26,6 +26,8 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; + virtual bool useAnim() const; + virtual void block(const MWWorld::Ptr &ptr) const; virtual osg::Vec3f getRotationVector(const MWWorld::Ptr& ptr) const; diff --git a/apps/openmw/mwclass/container.cpp b/apps/openmw/mwclass/container.cpp index 47e24f0d6..b0d3ca791 100644 --- a/apps/openmw/mwclass/container.cpp +++ b/apps/openmw/mwclass/container.cpp @@ -100,7 +100,6 @@ namespace MWClass { if(!model.empty()) physics.addObject(ptr, model); - MWBase::Environment::get().getMechanicsManager()->add(ptr); } std::string Container::getModel(const MWWorld::ConstPtr &ptr) const @@ -114,6 +113,11 @@ namespace MWClass return ""; } + bool Container::useAnim() const + { + return true; + } + boost::shared_ptr Container::activate (const MWWorld::Ptr& ptr, const MWWorld::Ptr& actor) const { diff --git a/apps/openmw/mwclass/container.hpp b/apps/openmw/mwclass/container.hpp index 3add65a7e..04223f264 100644 --- a/apps/openmw/mwclass/container.hpp +++ b/apps/openmw/mwclass/container.hpp @@ -70,6 +70,8 @@ namespace MWClass virtual void restock (const MWWorld::Ptr &ptr) const; virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; + + virtual bool useAnim() const; }; } diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 830ba258b..21e191931 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -74,8 +74,11 @@ namespace MWClass MWBase::Environment::get().getWorld()->activateDoor(ptr, customData.mDoorState); } } + } - MWBase::Environment::get().getMechanicsManager()->add(ptr); + bool Door::useAnim() const + { + return true; } std::string Door::getModel(const MWWorld::ConstPtr &ptr) const diff --git a/apps/openmw/mwclass/door.hpp b/apps/openmw/mwclass/door.hpp index 906b18511..3760f59c4 100644 --- a/apps/openmw/mwclass/door.hpp +++ b/apps/openmw/mwclass/door.hpp @@ -20,6 +20,8 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; + virtual bool useAnim() const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwclass/light.cpp b/apps/openmw/mwclass/light.cpp index 689419f44..e74b9da88 100644 --- a/apps/openmw/mwclass/light.cpp +++ b/apps/openmw/mwclass/light.cpp @@ -51,8 +51,11 @@ namespace MWClass MWBase::Environment::get().getSoundManager()->playSound3D(ptr, ref->mBase->mSound, 1.0, 1.0, MWBase::SoundManager::Play_TypeSfx, MWBase::SoundManager::Play_Loop); + } - MWBase::Environment::get().getMechanicsManager()->add(ptr); + bool Light::useAnim() const + { + return true; } std::string Light::getModel(const MWWorld::ConstPtr &ptr) const diff --git a/apps/openmw/mwclass/light.hpp b/apps/openmw/mwclass/light.hpp index 68fd2d2c7..284a7d817 100644 --- a/apps/openmw/mwclass/light.hpp +++ b/apps/openmw/mwclass/light.hpp @@ -16,6 +16,8 @@ namespace MWClass virtual void insertObject(const MWWorld::Ptr& ptr, const std::string& model, MWPhysics::PhysicsSystem& physics) const; + virtual bool useAnim() const; + virtual std::string getName (const MWWorld::ConstPtr& ptr) const; ///< \return name (the one that is to be presented to the user; not the internal one); /// can return an empty string. diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp index 830c2bcac..29bbc80f8 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.cpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.cpp @@ -48,7 +48,7 @@ namespace MWDialogue { - DialogueManager::DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose, Translation::Storage& translationDataStorage) : + DialogueManager::DialogueManager (const Compiler::Extensions& extensions, Translation::Storage& translationDataStorage) : mTranslationDataStorage(translationDataStorage) , mCompilerContext (MWScript::CompilerContext::Type_Dialogue) , mErrorStream(std::cout.rdbuf()) @@ -198,6 +198,8 @@ namespace MWDialogue { mErrorHandler.reset(); + mErrorHandler.setContext("[dialogue script]"); + std::istringstream input (cmd + "\n"); Compiler::Scanner scanner (mErrorHandler, input, mCompilerContext.getExtensions()); diff --git a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp index 086b5ef2f..bbe42975c 100644 --- a/apps/openmw/mwdialogue/dialoguemanagerimp.hpp +++ b/apps/openmw/mwdialogue/dialoguemanagerimp.hpp @@ -58,7 +58,7 @@ namespace MWDialogue public: - DialogueManager (const Compiler::Extensions& extensions, bool scriptVerbose, Translation::Storage& translationDataStorage); + DialogueManager (const Compiler::Extensions& extensions, Translation::Storage& translationDataStorage); virtual void clear(); diff --git a/apps/openmw/mwgui/container.cpp b/apps/openmw/mwgui/container.cpp index edfca1131..65a60d622 100644 --- a/apps/openmw/mwgui/container.cpp +++ b/apps/openmw/mwgui/container.cpp @@ -116,7 +116,6 @@ namespace MWGui containerItem.refId =itemPtr.getCellRef().getRefId(); containerItem.count = itemPtr.getRefData().getCount(); containerItem.charge = itemPtr.getCellRef().getCharge(); - containerItem.goldValue = itemPtr.getCellRef().getGoldValue(); containerItem.actionCount = count; worldObject.containerChanges.items.push_back(containerItem); @@ -176,9 +175,8 @@ namespace MWGui // Make sure we get the drag and drop count, not the count of the original item containerItem.count = mDragAndDrop->mDraggedCount; - + containerItem.charge = itemPtr.getCellRef().getCharge(); - containerItem.goldValue = itemPtr.getCellRef().getGoldValue(); worldObject.containerChanges.items.push_back(containerItem); event->addObject(worldObject); diff --git a/apps/openmw/mwmechanics/spellcasting.cpp b/apps/openmw/mwmechanics/spellcasting.cpp index 8fa850019..19c47cb5a 100644 --- a/apps/openmw/mwmechanics/spellcasting.cpp +++ b/apps/openmw/mwmechanics/spellcasting.cpp @@ -1189,4 +1189,40 @@ namespace MWMechanics return true; } + std::string getSummonedCreature(int effectId) + { + static std::map summonMap; + if (summonMap.empty()) + { + summonMap[ESM::MagicEffect::SummonAncestralGhost] = "sMagicAncestralGhostID"; + summonMap[ESM::MagicEffect::SummonBonelord] = "sMagicBonelordID"; + summonMap[ESM::MagicEffect::SummonBonewalker] = "sMagicLeastBonewalkerID"; + summonMap[ESM::MagicEffect::SummonCenturionSphere] = "sMagicCenturionSphereID"; + summonMap[ESM::MagicEffect::SummonClannfear] = "sMagicClannfearID"; + summonMap[ESM::MagicEffect::SummonDaedroth] = "sMagicDaedrothID"; + summonMap[ESM::MagicEffect::SummonDremora] = "sMagicDremoraID"; + summonMap[ESM::MagicEffect::SummonFabricant] = "sMagicFabricantID"; + summonMap[ESM::MagicEffect::SummonFlameAtronach] = "sMagicFlameAtronachID"; + summonMap[ESM::MagicEffect::SummonFrostAtronach] = "sMagicFrostAtronachID"; + summonMap[ESM::MagicEffect::SummonGoldenSaint] = "sMagicGoldenSaintID"; + summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "sMagicGreaterBonewalkerID"; + summonMap[ESM::MagicEffect::SummonHunger] = "sMagicHungerID"; + summonMap[ESM::MagicEffect::SummonScamp] = "sMagicScampID"; + summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "sMagicSkeletalMinionID"; + summonMap[ESM::MagicEffect::SummonStormAtronach] = "sMagicStormAtronachID"; + summonMap[ESM::MagicEffect::SummonWingedTwilight] = "sMagicWingedTwilightID"; + summonMap[ESM::MagicEffect::SummonWolf] = "sMagicCreature01ID"; + summonMap[ESM::MagicEffect::SummonBear] = "sMagicCreature02ID"; + summonMap[ESM::MagicEffect::SummonBonewolf] = "sMagicCreature03ID"; + summonMap[ESM::MagicEffect::SummonCreature04] = "sMagicCreature04ID"; + summonMap[ESM::MagicEffect::SummonCreature05] = "sMagicCreature05ID"; + } + + std::map::const_iterator it = summonMap.find(effectId); + if (it == summonMap.end()) + return std::string(); + else + return MWBase::Environment::get().getWorld()->getStore().get().find(it->second)->getString(); + } + } diff --git a/apps/openmw/mwmechanics/spellcasting.hpp b/apps/openmw/mwmechanics/spellcasting.hpp index 91bb6821a..8e48681b6 100644 --- a/apps/openmw/mwmechanics/spellcasting.hpp +++ b/apps/openmw/mwmechanics/spellcasting.hpp @@ -67,6 +67,8 @@ namespace MWMechanics /// @return Was the effect a tickable effect with a magnitude? bool effectTick(CreatureStats& creatureStats, const MWWorld::Ptr& actor, const MWMechanics::EffectKey& effectKey, float magnitude); + std::string getSummonedCreature(int effectId); + class CastSpell { private: diff --git a/apps/openmw/mwmechanics/summoning.cpp b/apps/openmw/mwmechanics/summoning.cpp index 3ff8cf667..e4a825efc 100644 --- a/apps/openmw/mwmechanics/summoning.cpp +++ b/apps/openmw/mwmechanics/summoning.cpp @@ -40,32 +40,7 @@ namespace MWMechanics void UpdateSummonedCreatures::process() { - static std::map summonMap; - if (summonMap.empty()) - { - summonMap[ESM::MagicEffect::SummonAncestralGhost] = "sMagicAncestralGhostID"; - summonMap[ESM::MagicEffect::SummonBonelord] = "sMagicBonelordID"; - summonMap[ESM::MagicEffect::SummonBonewalker] = "sMagicLeastBonewalkerID"; - summonMap[ESM::MagicEffect::SummonCenturionSphere] = "sMagicCenturionSphereID"; - summonMap[ESM::MagicEffect::SummonClannfear] = "sMagicClannfearID"; - summonMap[ESM::MagicEffect::SummonDaedroth] = "sMagicDaedrothID"; - summonMap[ESM::MagicEffect::SummonDremora] = "sMagicDremoraID"; - summonMap[ESM::MagicEffect::SummonFabricant] = "sMagicFabricantID"; - summonMap[ESM::MagicEffect::SummonFlameAtronach] = "sMagicFlameAtronachID"; - summonMap[ESM::MagicEffect::SummonFrostAtronach] = "sMagicFrostAtronachID"; - summonMap[ESM::MagicEffect::SummonGoldenSaint] = "sMagicGoldenSaintID"; - summonMap[ESM::MagicEffect::SummonGreaterBonewalker] = "sMagicGreaterBonewalkerID"; - summonMap[ESM::MagicEffect::SummonHunger] = "sMagicHungerID"; - summonMap[ESM::MagicEffect::SummonScamp] = "sMagicScampID"; - summonMap[ESM::MagicEffect::SummonSkeletalMinion] = "sMagicSkeletalMinionID"; - summonMap[ESM::MagicEffect::SummonStormAtronach] = "sMagicStormAtronachID"; - summonMap[ESM::MagicEffect::SummonWingedTwilight] = "sMagicWingedTwilightID"; - summonMap[ESM::MagicEffect::SummonWolf] = "sMagicCreature01ID"; - summonMap[ESM::MagicEffect::SummonBear] = "sMagicCreature02ID"; - summonMap[ESM::MagicEffect::SummonBonewolf] = "sMagicCreature03ID"; - summonMap[ESM::MagicEffect::SummonCreature04] = "sMagicCreature04ID"; - summonMap[ESM::MagicEffect::SummonCreature05] = "sMagicCreature05ID"; - } + MWMechanics::CreatureStats& creatureStats = mActor.getClass().getCreatureStats(mActor); @@ -89,10 +64,7 @@ namespace MWMechanics bool found = creatureMap.find(std::make_pair(it->first, it->second)) != creatureMap.end(); if (!found) { - const std::string& creatureGmst = summonMap[it->first]; - std::string creatureID = - MWBase::Environment::get().getWorld()->getStore().get().find(creatureGmst)->getString(); - + std::string creatureID = getSummonedCreature(it->first); if (!creatureID.empty()) { int creatureActorId = -1; diff --git a/apps/openmw/mwmp/LocalPlayer.cpp b/apps/openmw/mwmp/LocalPlayer.cpp index 880dc232b..ec11816c8 100644 --- a/apps/openmw/mwmp/LocalPlayer.cpp +++ b/apps/openmw/mwmp/LocalPlayer.cpp @@ -798,6 +798,13 @@ void LocalPlayer::setCell() MWWorld::Ptr player = world->getPlayerPtr(); ESM::Position pos; + // To avoid crashes, close any container menus this player may be in + if (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Container)) + { + MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Container); + MWBase::Environment::get().getWindowManager()->setDragDrop(false); + } + world->getPlayer().setTeleported(true); int x = cell.mData.mX; @@ -1057,7 +1064,9 @@ void LocalPlayer::sendJournalEntry(const std::string& quest, int index, const MW journalItem.quest = quest; journalItem.index = index; - journalItem.actorCell = *actor.getCell()->getCell(); + if (actor.getCell() != nullptr) + journalItem.actorCell = *actor.getCell()->getCell(); + journalItem.actorCellRef.mRefID = actor.getCellRef().getRefId(); journalItem.actorCellRef.mRefNum = actor.getCellRef().getRefNum(); diff --git a/apps/openmw/mwmp/Main.cpp b/apps/openmw/mwmp/Main.cpp index cb9bd4563..9d0de523c 100644 --- a/apps/openmw/mwmp/Main.cpp +++ b/apps/openmw/mwmp/Main.cpp @@ -25,6 +25,7 @@ #include "../mwmechanics/spellcasting.hpp" #include #include +#include #include "Networking.hpp" #include "LocalPlayer.hpp" @@ -37,6 +38,7 @@ using namespace std; Main *Main::pMain = 0; std::string Main::addr = ""; +std::string Main::passw = TES3MP_DEFAULT_PASSW; std::string loadSettings (Settings::Manager & settings) { @@ -85,13 +87,17 @@ Main::~Main() void Main::optionsDesc(boost::program_options::options_description *desc) { namespace bpo = boost::program_options; - desc->add_options()("connect", bpo::value()->default_value(""), - "connect to server (e.g. --connect=127.0.0.1:25565)"); + desc->add_options() + ("connect", bpo::value()->default_value(""), + "connect to server (e.g. --connect=127.0.0.1:25565)") + ("password", bpo::value()->default_value(TES3MP_DEFAULT_PASSW), + "сonnect to a secured server. (e.g. --password=AnyPassword"); } void Main::configure(const boost::program_options::variables_map &variables) { Main::addr = variables["connect"].as(); + Main::passw = variables["password"].as(); } static Settings::CategorySettingValueMap saveUserSettings; @@ -130,15 +136,19 @@ bool Main::init(std::vector &content) { pMain->server = mgr.getString("server", "General"); pMain->port = (unsigned short) mgr.getInt("port", "General"); + + passw = mgr.getString("password", "General"); + if (passw.empty()) + passw = TES3MP_DEFAULT_PASSW; } else { size_t delim_pos = addr.find(':'); pMain->server = addr.substr(0, delim_pos); pMain->port = atoi(addr.substr(delim_pos + 1).c_str()); - } - + get().mLocalPlayer->passw = passw; + pMain->mNetworking->connect(pMain->server, pMain->port); RestoreMgr(mgr); return pMain->mNetworking->isConnected(); diff --git a/apps/openmw/mwmp/Main.hpp b/apps/openmw/mwmp/Main.hpp index bc4635f00..673de61e8 100644 --- a/apps/openmw/mwmp/Main.hpp +++ b/apps/openmw/mwmp/Main.hpp @@ -34,6 +34,7 @@ namespace mwmp private: static std::string addr; + static std::string passw; Main (const Main&); ///< not implemented Main& operator= (const Main&); diff --git a/apps/openmw/mwmp/Networking.cpp b/apps/openmw/mwmp/Networking.cpp index b592f9fc3..6f91e9224 100644 --- a/apps/openmw/mwmp/Networking.cpp +++ b/apps/openmw/mwmp/Networking.cpp @@ -189,7 +189,6 @@ void Networking::processPlayerPacket(RakNet::Packet *packet) { case ID_HANDSHAKE: { - getLocalPlayer()->passw = "SuperPassword"; myPacket->Send(getLocalPlayer(), serverAddr); break; } @@ -746,7 +745,9 @@ void Networking::processWorldPacket(RakNet::Packet *packet) if (!ptrCellStore) return; - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_CONTAINER"); + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Received ID_CONTAINER about %s", + event->cell.getDescription().c_str()); + LOG_APPEND(Log::LOG_VERBOSE, "- action: %i", event->action); // If we've received a request for information, comply with it if (event->action == mwmp::BaseEvent::REQUEST) @@ -763,7 +764,8 @@ void Networking::processWorldPacket(RakNet::Packet *packet) if (!ptrCellStore) return; - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_OBJECT_PLACE"); + LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_OBJECT_PLACE about %s", + event->cell.getDescription().c_str()); event->placeObjects(ptrCellStore); break; @@ -774,7 +776,8 @@ void Networking::processWorldPacket(RakNet::Packet *packet) if (!ptrCellStore) return; - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_OBJECT_DELETE"); + LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_OBJECT_DELETE about %s", + event->cell.getDescription().c_str()); event->deleteObjects(ptrCellStore); break; @@ -785,7 +788,8 @@ void Networking::processWorldPacket(RakNet::Packet *packet) if (!ptrCellStore) return; - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_OBJECT_LOCK"); + LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_OBJECT_LOCK about %s", + event->cell.getDescription().c_str()); event->lockObjects(ptrCellStore); break; @@ -796,7 +800,8 @@ void Networking::processWorldPacket(RakNet::Packet *packet) if (!ptrCellStore) return; - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_OBJECT_UNLOCK"); + LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_OBJECT_UNLOCK about %s", + event->cell.getDescription().c_str()); event->unlockObjects(ptrCellStore); break; @@ -807,7 +812,8 @@ void Networking::processWorldPacket(RakNet::Packet *packet) if (!ptrCellStore) return; - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "%s", "Received ID_OBJECT_SCALE"); + LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_OBJECT_SCALE about %s", + event->cell.getDescription().c_str()); event->scaleObjects(ptrCellStore); break; @@ -818,7 +824,8 @@ void Networking::processWorldPacket(RakNet::Packet *packet) if (!ptrCellStore) return; - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_OBJECT_MOVE"); + LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_OBJECT_MOVE about %s", + event->cell.getDescription().c_str()); event->moveObjects(ptrCellStore); break; @@ -829,7 +836,8 @@ void Networking::processWorldPacket(RakNet::Packet *packet) if (!ptrCellStore) return; - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_OBJECT_ROTATE"); + LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_OBJECT_ROTATE about %s", + event->cell.getDescription().c_str()); event->rotateObjects(ptrCellStore); break; @@ -840,7 +848,8 @@ void Networking::processWorldPacket(RakNet::Packet *packet) if (!ptrCellStore) return; - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_OBJECT_ANIM_PLAY"); + LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_OBJECT_ANIM_PLAY about %s", + event->cell.getDescription().c_str()); event->animateObjects(ptrCellStore); break; @@ -851,7 +860,8 @@ void Networking::processWorldPacket(RakNet::Packet *packet) if (!ptrCellStore) return; - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_DOOR_STATE"); + LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_DOOR_STATE about %s", + event->cell.getDescription().c_str()); event->activateDoors(ptrCellStore); break; @@ -862,7 +872,8 @@ void Networking::processWorldPacket(RakNet::Packet *packet) if (!ptrCellStore) return; - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_SCRIPT_LOCAL_SHORT"); + LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_SCRIPT_LOCAL_SHORT about %s", + event->cell.getDescription().c_str()); event->setLocalShorts(ptrCellStore); break; @@ -873,7 +884,8 @@ void Networking::processWorldPacket(RakNet::Packet *packet) if (!ptrCellStore) return; - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_SCRIPT_LOCAL_FLOAT"); + LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Received ID_SCRIPT_LOCAL_FLOAT about %s", + event->cell.getDescription().c_str()); event->setLocalFloats(ptrCellStore); break; diff --git a/apps/openmw/mwmp/WorldController.cpp b/apps/openmw/mwmp/WorldController.cpp index 3596649f7..ffbb258ca 100644 --- a/apps/openmw/mwmp/WorldController.cpp +++ b/apps/openmw/mwmp/WorldController.cpp @@ -70,15 +70,20 @@ void mwmp::WorldController::closeContainer(const MWWorld::Ptr &container) { mwmp::Main::get().getLocalPlayer()->clearCurrentContainer(); - LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Container \"%s\" (%d) is closed.", - container.getCellRef().getRefId().c_str(), - container.getCellRef().getRefNum().mIndex); - - MWWorld::ContainerStore &cont = container.getClass().getContainerStore(container); - for (MWWorld::ContainerStoreIterator iter = cont.begin(); iter != cont.end(); iter++) + // If the player died while in a container, the container's Ptr could be invalid now + if (!container.isEmpty()) { - LOG_APPEND(Log::LOG_VERBOSE, " - Item. Refid: \"%s\" Count: %d", - iter->getCellRef().getRefId().c_str(), iter->getRefData().getCount()); + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Container \"%s\" (%d) is closed.", + container.getCellRef().getRefId().c_str(), + container.getCellRef().getRefNum().mIndex); + + MWWorld::ContainerStore &cont = container.getClass().getContainerStore(container); + for (MWWorld::ContainerStoreIterator iter = cont.begin(); iter != cont.end(); iter++) + { + LOG_APPEND(Log::LOG_VERBOSE, " - Item. Refid: \"%s\" Count: %d", + iter->getCellRef().getRefId().c_str(), iter->getRefData().getCount()); + } } + mwmp::Main::get().getLocalPlayer()->updateInventory(); } diff --git a/apps/openmw/mwmp/WorldEvent.cpp b/apps/openmw/mwmp/WorldEvent.cpp index a21398ae2..0239cf1e7 100644 --- a/apps/openmw/mwmp/WorldEvent.cpp +++ b/apps/openmw/mwmp/WorldEvent.cpp @@ -67,7 +67,6 @@ void WorldEvent::sendContainers(MWWorld::CellStore* cellStore) containerItem.refId = itemPtr.getCellRef().getRefId(); containerItem.count = itemPtr.getRefData().getCount(); containerItem.charge = itemPtr.getCellRef().getCharge(); - containerItem.goldValue = itemPtr.getCellRef().getGoldValue(); worldObject.containerChanges.items.push_back(containerItem); } @@ -86,16 +85,15 @@ void WorldEvent::editContainers(MWWorld::CellStore* cellStore) { worldObject = objectChanges.objects.at(i); - LOG_APPEND(Log::LOG_WARN, "- cellRef: %s, %i\n- cell: %s", + LOG_APPEND(Log::LOG_VERBOSE, "- cellRef: %s, %i", worldObject.refId.c_str(), - worldObject.refNumIndex, - cell.getDescription().c_str()); + worldObject.refNumIndex); MWWorld::Ptr ptrFound = cellStore->searchExact(worldObject.refId, worldObject.refNumIndex); if (ptrFound) { - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Found %s, %i", + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Found %s, %i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum()); @@ -122,8 +120,6 @@ void WorldEvent::editContainers(MWWorld::CellStore* cellStore) if (containerItem.charge > -1) newPtr.getCellRef().setCharge(containerItem.charge); - newPtr.getCellRef().setGoldValue(containerItem.goldValue); - containerStore.add(newPtr, containerItem.count, ownerPtr, true); } else if (action == BaseEvent::REMOVE) @@ -135,7 +131,6 @@ void WorldEvent::editContainers(MWWorld::CellStore* cellStore) if (Misc::StringUtils::ciEqual(iter->getCellRef().getRefId(), containerItem.refId)) { if (iter->getCellRef().getCharge() == containerItem.charge && - iter->getCellRef().getGoldValue() == containerItem.goldValue && iter->getRefData().getCount() == containerItem.count) { containerStore.remove(*iter, containerItem.actionCount, ownerPtr); @@ -169,10 +164,9 @@ void WorldEvent::placeObjects(MWWorld::CellStore* cellStore) { worldObject = objectChanges.objects.at(i); - LOG_APPEND(Log::LOG_WARN, "- cellRef: %s, %i\n- cell: %s\n- charge: %i\n- count: %i", + LOG_APPEND(Log::LOG_VERBOSE, "- cellRef: %s, %i\n- charge: %i\n- count: %i", worldObject.refId.c_str(), worldObject.refNumIndex, - cell.getDescription().c_str(), worldObject.charge, worldObject.count); @@ -206,16 +200,15 @@ void WorldEvent::deleteObjects(MWWorld::CellStore* cellStore) { worldObject = objectChanges.objects.at(i); - LOG_APPEND(Log::LOG_WARN, "- cellRef: %s, %i\n- cell: %s", + LOG_APPEND(Log::LOG_VERBOSE, "- cellRef: %s, %i", worldObject.refId.c_str(), - worldObject.refNumIndex, - cell.getDescription().c_str()); + worldObject.refNumIndex); MWWorld::Ptr ptrFound = cellStore->searchExact(worldObject.refId, worldObject.refNumIndex); if (ptrFound) { - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Found %s, %i", + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Found %s, %i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum()); @@ -232,16 +225,15 @@ void WorldEvent::lockObjects(MWWorld::CellStore* cellStore) { worldObject = objectChanges.objects.at(i); - LOG_APPEND(Log::LOG_WARN, "- cellRef: %s, %i\n- cell: %s", + LOG_APPEND(Log::LOG_VERBOSE, "- cellRef: %s, %i", worldObject.refId.c_str(), - worldObject.refNumIndex, - cell.getDescription().c_str()); + worldObject.refNumIndex); MWWorld::Ptr ptrFound = cellStore->searchExact(worldObject.refId, worldObject.refNumIndex); if (ptrFound) { - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Found %s, %i", + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Found %s, %i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum()); @@ -258,16 +250,15 @@ void WorldEvent::unlockObjects(MWWorld::CellStore* cellStore) { worldObject = objectChanges.objects.at(i); - LOG_APPEND(Log::LOG_WARN, "- cellRef: %s, %i\n- cell: %s", + LOG_APPEND(Log::LOG_VERBOSE, "- cellRef: %s, %i", worldObject.refId.c_str(), - worldObject.refNumIndex, - cell.getDescription().c_str()); + worldObject.refNumIndex); MWWorld::Ptr ptrFound = cellStore->searchExact(worldObject.refId, worldObject.refNumIndex); if (ptrFound) { - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Found %s, %i", + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Found %s, %i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum()); @@ -284,16 +275,15 @@ void WorldEvent::scaleObjects(MWWorld::CellStore* cellStore) { worldObject = objectChanges.objects.at(i); - LOG_APPEND(Log::LOG_WARN, "- cellRef: %s, %i\n- cell: %s", + LOG_APPEND(Log::LOG_VERBOSE, "- cellRef: %s, %i", worldObject.refId.c_str(), - worldObject.refNumIndex, - cell.getDescription().c_str()); + worldObject.refNumIndex); MWWorld::Ptr ptrFound = cellStore->searchExact(worldObject.refId, worldObject.refNumIndex); if (ptrFound) { - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Found %s, %i", + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Found %s, %i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum()); @@ -310,16 +300,15 @@ void WorldEvent::moveObjects(MWWorld::CellStore* cellStore) { worldObject = objectChanges.objects.at(i); - LOG_APPEND(Log::LOG_WARN, "- cellRef: %s, %i\n- cell: %s", + LOG_APPEND(Log::LOG_VERBOSE, "- cellRef: %s, %i", worldObject.refId.c_str(), - worldObject.refNumIndex, - cell.getDescription().c_str()); + worldObject.refNumIndex); MWWorld::Ptr ptrFound = cellStore->searchExact(worldObject.refId, worldObject.refNumIndex); if (ptrFound) { - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Found %s, %i", + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Found %s, %i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum()); @@ -337,16 +326,15 @@ void WorldEvent::rotateObjects(MWWorld::CellStore* cellStore) { worldObject = objectChanges.objects.at(i); - LOG_APPEND(Log::LOG_WARN, "- cellRef: %s, %i\n- cell: %s", + LOG_APPEND(Log::LOG_VERBOSE, "- cellRef: %s, %i", worldObject.refId.c_str(), - worldObject.refNumIndex, - cell.getDescription().c_str()); + worldObject.refNumIndex); MWWorld::Ptr ptrFound = cellStore->searchExact(worldObject.refId, worldObject.refNumIndex); if (ptrFound) { - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Found %s, %i", + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Found %s, %i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum()); @@ -364,16 +352,15 @@ void WorldEvent::animateObjects(MWWorld::CellStore* cellStore) { worldObject = objectChanges.objects.at(i); - LOG_APPEND(Log::LOG_WARN, "- cellRef: %s, %i\n- cell: %s", + LOG_APPEND(Log::LOG_VERBOSE, "- cellRef: %s, %i", worldObject.refId.c_str(), - worldObject.refNumIndex, - cell.getDescription().c_str()); + worldObject.refNumIndex); MWWorld::Ptr ptrFound = cellStore->searchExact(worldObject.refId, worldObject.refNumIndex); if (ptrFound) { - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Found %s, %i", + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Found %s, %i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum()); @@ -391,16 +378,15 @@ void WorldEvent::activateDoors(MWWorld::CellStore* cellStore) { worldObject = objectChanges.objects.at(i); - LOG_APPEND(Log::LOG_WARN, "- cellRef: %s, %i\n- cell: %s", + LOG_APPEND(Log::LOG_VERBOSE, "- cellRef: %s, %i", worldObject.refId.c_str(), - worldObject.refNumIndex, - cell.getDescription().c_str()); + worldObject.refNumIndex); MWWorld::Ptr ptrFound = cellStore->searchExact(worldObject.refId, worldObject.refNumIndex); if (ptrFound) { - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Found %s, %i", + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Found %s, %i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum()); @@ -418,7 +404,7 @@ void WorldEvent::playMusic() { worldObject = objectChanges.objects.at(i); - LOG_APPEND(Log::LOG_WARN, "- filename: %s", + LOG_APPEND(Log::LOG_VERBOSE, "- filename: %s", worldObject.filename.c_str()); MWBase::Environment::get().getSoundManager()->streamMusic(worldObject.filename); @@ -433,7 +419,7 @@ void WorldEvent::playVideo() { worldObject = objectChanges.objects.at(i); - LOG_APPEND(Log::LOG_WARN, "- filename: %s\n- allowSkipping: %s", + LOG_APPEND(Log::LOG_VERBOSE, "- filename: %s\n- allowSkipping: %s", worldObject.filename.c_str(), worldObject.allowSkipping ? "true" : "false"); @@ -449,10 +435,9 @@ void WorldEvent::setLocalShorts(MWWorld::CellStore* cellStore) { worldObject = objectChanges.objects.at(i); - LOG_APPEND(Log::LOG_WARN, "- cellRef: %s, %i\n- cell: %s\n- index: %i\n- shortVal: %i", + LOG_APPEND(Log::LOG_VERBOSE, "- cellRef: %s, %i\n- index: %i\n- shortVal: %i", worldObject.refId.c_str(), worldObject.refNumIndex, - cell.getDescription().c_str(), worldObject.index, worldObject.shortVal); @@ -460,7 +445,7 @@ void WorldEvent::setLocalShorts(MWWorld::CellStore* cellStore) if (ptrFound) { - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Found %s, %i", + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Found %s, %i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum()); @@ -477,10 +462,9 @@ void WorldEvent::setLocalFloats(MWWorld::CellStore* cellStore) { worldObject = objectChanges.objects.at(i); - LOG_APPEND(Log::LOG_WARN, "- cellRef: %s, %i\n- cell: %s\n- index: %i\n- floatVal: %f", + LOG_APPEND(Log::LOG_VERBOSE, "- cellRef: %s, %i\n- index: %i\n- floatVal: %f", worldObject.refId.c_str(), worldObject.refNumIndex, - cell.getDescription().c_str(), worldObject.index, worldObject.floatVal); @@ -488,7 +472,7 @@ void WorldEvent::setLocalFloats(MWWorld::CellStore* cellStore) if (ptrFound) { - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Found %s, %i", + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Found %s, %i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum()); @@ -505,7 +489,7 @@ void WorldEvent::setMemberShorts() { worldObject = objectChanges.objects.at(i); - LOG_APPEND(Log::LOG_WARN, "- cellRef: %s\n- index: %i\n- shortVal: %i\n", + LOG_APPEND(Log::LOG_VERBOSE, "- cellRef: %s\n- index: %i\n- shortVal: %i\n", worldObject.refId.c_str(), worldObject.index, worldObject.shortVal); @@ -515,7 +499,7 @@ void WorldEvent::setMemberShorts() if (!ptrFound.isEmpty()) { - LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Found %s, %i", + LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Found %s, %i", ptrFound.getCellRef().getRefId().c_str(), ptrFound.getCellRef().getRefNum()); @@ -537,7 +521,7 @@ void WorldEvent::setGlobalShorts() { worldObject = objectChanges.objects.at(i); - LOG_APPEND(Log::LOG_WARN, "- varName: %s\n- shortVal: %i", + LOG_APPEND(Log::LOG_VERBOSE, "- varName: %s\n- shortVal: %i", worldObject.varName.c_str(), worldObject.shortVal); diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index de8774cfd..ebf51a66e 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -531,7 +531,7 @@ namespace MWPhysics mShape = new btHeightfieldTerrainShape( sqrtVerts, sqrtVerts, heights, 1, minh, maxh, 2, - PHY_FLOAT, true + PHY_FLOAT, false ); mShape->setUseDiamondSubdivision(true); mShape->setLocalScaling(btVector3(triSize, triSize, 1)); diff --git a/apps/openmw/mwscript/cellextensions.cpp b/apps/openmw/mwscript/cellextensions.cpp index 43e8318b2..2cb76ef88 100644 --- a/apps/openmw/mwscript/cellextensions.cpp +++ b/apps/openmw/mwscript/cellextensions.cpp @@ -15,6 +15,7 @@ #include "../mwbase/world.hpp" #include "../mwworld/player.hpp" #include "../mwworld/cellstore.hpp" +#include "../mwworld/actionteleport.hpp" #include "../mwmechanics/actorutil.hpp" @@ -46,10 +47,9 @@ namespace MWScript ESM::Position pos; MWBase::World *world = MWBase::Environment::get().getWorld(); - world->getPlayer().setTeleported(true); if (world->findExteriorPosition(cell, pos)) { - world->changeToExteriorCell(pos, true); + MWWorld::ActionTeleport("", pos, false).execute(world->getPlayerPtr()); world->fixPosition(world->getPlayerPtr()); } else @@ -57,7 +57,7 @@ namespace MWScript // Change to interior even if findInteriorPosition() // yields false. In this case position will be zero-point. world->findInteriorPosition(cell, pos); - world->changeToInteriorCell(cell, pos, true); + MWWorld::ActionTeleport(cell, pos, false).execute(world->getPlayerPtr()); } } }; @@ -76,13 +76,13 @@ namespace MWScript ESM::Position pos; MWBase::World *world = MWBase::Environment::get().getWorld(); - world->getPlayer().setTeleported(true); + world->indexToPosition (x, y, pos.pos[0], pos.pos[1], true); pos.pos[2] = 0; pos.rot[0] = pos.rot[1] = pos.rot[2] = 0; - world->changeToExteriorCell (pos, true); + MWWorld::ActionTeleport("", pos, false).execute(world->getPlayerPtr()); world->fixPosition(world->getPlayerPtr()); } }; diff --git a/apps/openmw/mwscript/scriptmanagerimp.cpp b/apps/openmw/mwscript/scriptmanagerimp.cpp index b73c9a642..97ea19a63 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.cpp +++ b/apps/openmw/mwscript/scriptmanagerimp.cpp @@ -21,10 +21,10 @@ namespace MWScript { - ScriptManager::ScriptManager (const MWWorld::ESMStore& store, bool verbose, + ScriptManager::ScriptManager (const MWWorld::ESMStore& store, Compiler::Context& compilerContext, int warningsMode, const std::vector& scriptBlacklist) - : mErrorHandler (std::cerr), mStore (store), mVerbose (verbose), + : mErrorHandler (std::cerr), mStore (store), mCompilerContext (compilerContext), mParser (mErrorHandler, mCompilerContext), mOpcodesInstalled (false), mGlobalScripts (store) { @@ -44,8 +44,7 @@ namespace MWScript if (const ESM::Script *script = mStore.get().find (name)) { - if (mVerbose) - std::cout << "compiling script: " << name << std::endl; + mErrorHandler.setContext(name); bool Success = true; try @@ -74,8 +73,6 @@ namespace MWScript { std::cerr << "compiling failed: " << name << std::endl; - if (mVerbose) - std::cerr << script->mScriptText << std::endl << std::endl; } if (Success) @@ -172,13 +169,10 @@ namespace MWScript if (const ESM::Script *script = mStore.get().search (name2)) { - if (mVerbose) - std::cout - << "scanning script for local variable declarations: " << name2 - << std::endl; - Compiler::Locals locals; + mErrorHandler.setContext(name2 + "[local variables]"); + std::istringstream stream (script->mScriptText); Compiler::QuickFileParser parser (mErrorHandler, mCompilerContext, locals); Compiler::Scanner scanner (mErrorHandler, stream, mCompilerContext.getExtensions()); diff --git a/apps/openmw/mwscript/scriptmanagerimp.hpp b/apps/openmw/mwscript/scriptmanagerimp.hpp index e4a123b86..c22a5da81 100644 --- a/apps/openmw/mwscript/scriptmanagerimp.hpp +++ b/apps/openmw/mwscript/scriptmanagerimp.hpp @@ -36,7 +36,6 @@ namespace MWScript { Compiler::StreamErrorHandler mErrorHandler; const MWWorld::ESMStore& mStore; - bool mVerbose; Compiler::Context& mCompilerContext; Compiler::FileParser mParser; Interpreter::Interpreter mInterpreter; @@ -52,7 +51,7 @@ namespace MWScript public: - ScriptManager (const MWWorld::ESMStore& store, bool verbose, + ScriptManager (const MWWorld::ESMStore& store, Compiler::Context& compilerContext, int warningsMode, const std::vector& scriptBlacklist); diff --git a/apps/openmw/mwscript/statsextensions.cpp b/apps/openmw/mwscript/statsextensions.cpp index 5ac63016e..8b327f94a 100644 --- a/apps/openmw/mwscript/statsextensions.cpp +++ b/apps/openmw/mwscript/statsextensions.cpp @@ -449,7 +449,8 @@ namespace MWScript // Added by tes3mp // // LocalPlayer has gained a spell, so send a packet with it - mwmp::Main::get().getLocalPlayer()->sendSpellAddition(id); + if (ptr == MWMechanics::getPlayer()) + mwmp::Main::get().getLocalPlayer()->sendSpellAddition(id); } }; @@ -478,7 +479,8 @@ namespace MWScript // Added by tes3mp // // LocalPlayer has lost a spell, so send a packet with it - mwmp::Main::get().getLocalPlayer()->sendSpellRemoval(id); + if (ptr == MWMechanics::getPlayer()) + mwmp::Main::get().getLocalPlayer()->sendSpellRemoval(id); } }; diff --git a/apps/openmw/mwworld/actionteleport.cpp b/apps/openmw/mwworld/actionteleport.cpp index 5162cac66..93705f005 100644 --- a/apps/openmw/mwworld/actionteleport.cpp +++ b/apps/openmw/mwworld/actionteleport.cpp @@ -4,6 +4,8 @@ #include "../mwbase/world.hpp" #include "../mwbase/mechanicsmanager.hpp" +#include "../mwmechanics/creaturestats.hpp" + #include "../mwworld/class.hpp" #include "player.hpp" @@ -34,6 +36,7 @@ namespace MWWorld void ActionTeleport::teleport(const Ptr &actor) { MWBase::World* world = MWBase::Environment::get().getWorld(); + actor.getClass().getCreatureStats(actor).land(); if(actor == world->getPlayerPtr()) { world->getPlayer().setTeleported(true); diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 99545a64f..59fa1f5e2 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -650,7 +650,8 @@ namespace MWWorld loadRef (ref, deleted, refNumToID); } - setLastRefNumIndex(refNumToID.rbegin()->first.mIndex); + if(refNumToID.size() != 0) + setLastRefNumIndex(refNumToID.rbegin()->first.mIndex); updateMergedRefs(); } diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 7832c1066..72696e209 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -304,6 +304,11 @@ namespace MWWorld return ""; } + bool Class::useAnim() const + { + return false; + } + void Class::getModelsToPreload(const Ptr &ptr, std::vector &models) const { std::string model = getModel(ptr); diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 0b6c5e038..3b1ddb647 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -271,6 +271,9 @@ namespace MWWorld virtual std::string getModel(const MWWorld::ConstPtr &ptr) const; + virtual bool useAnim() const; + ///< Whether or not to use animated variant of model (default false) + virtual void getModelsToPreload(const MWWorld::Ptr& ptr, std::vector& models) const; ///< Get a list of models to preload that this object may use (directly or indirectly). default implementation: list getModel(). diff --git a/apps/openmw/mwworld/inventorystore.cpp b/apps/openmw/mwworld/inventorystore.cpp index 2e32debfa..34b6fcf69 100644 --- a/apps/openmw/mwworld/inventorystore.cpp +++ b/apps/openmw/mwworld/inventorystore.cpp @@ -297,9 +297,15 @@ void MWWorld::InventoryStore::autoEquip (const MWWorld::Ptr& actor) { if (old.getTypeName() == typeid(ESM::Armor).name()) { - if (old.getClass().getEffectiveArmorRating(old, actor) >= test.getClass().getEffectiveArmorRating(test, actor)) - // old armor had better armor rating + if (old.get()->mBase->mData.mType < test.get()->mBase->mData.mType) continue; + + if (old.get()->mBase->mData.mType == test.get()->mBase->mData.mType) + { + if (old.getClass().getEffectiveArmorRating(old, actor) >= test.getClass().getEffectiveArmorRating(test, actor)) + // old armor had better armor rating + continue; + } } // suitable armor should replace already equipped clothing } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index d1d2da683..a95ad05a6 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -56,15 +56,23 @@ namespace void addObject(const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering) { - std::string model = Misc::ResourceHelpers::correctActorModelPath(ptr.getClass().getModel(ptr), rendering.getResourceSystem()->getVFS()); + bool useAnim = ptr.getClass().useAnim(); + std::string model = ptr.getClass().getModel(ptr); + if (useAnim) + model = Misc::ResourceHelpers::correctActorModelPath(model, rendering.getResourceSystem()->getVFS()); + std::string id = ptr.getCellRef().getRefId(); if (id == "prisonmarker" || id == "divinemarker" || id == "templemarker" || id == "northmarker") model = ""; // marker objects that have a hardcoded function in the game logic, should be hidden from the player + ptr.getClass().insertObjectRendering(ptr, model, rendering); setNodeRotation(ptr, rendering, false); ptr.getClass().insertObject (ptr, model, physics); + if (useAnim) + MWBase::Environment::get().getMechanicsManager()->add(ptr); + if (ptr.getClass().isActor()) rendering.addWaterRippleEmitter(ptr); } @@ -303,7 +311,11 @@ namespace MWWorld // ... then references. This is important for adjustPosition to work correctly. /// \todo rescale depending on the state of a new GMST - insertCell (*cell, true, loadingListener); + + // Minor change done by tes3mp: + // Instead of always rescaling objects as in the original code, never rescale them + insertCell(*cell, false, loadingListener); + mRendering.addCell(cell); bool waterEnabled = cell->getCell()->hasWater() || cell->isExterior(); @@ -703,10 +715,14 @@ namespace MWWorld Resource::SceneManager* mSceneManager; }; - void Scene::preload(const std::string &mesh) + void Scene::preload(const std::string &mesh, bool useAnim) { - if (!mRendering.getResourceSystem()->getSceneManager()->checkLoaded(mesh, mRendering.getReferenceTime())) - mRendering.getWorkQueue()->addWorkItem(new PreloadMeshItem(mesh, mRendering.getResourceSystem()->getSceneManager())); + std::string mesh_ = mesh; + if (useAnim) + mesh_ = Misc::ResourceHelpers::correctActorModelPath(mesh_, mRendering.getResourceSystem()->getVFS()); + + if (!mRendering.getResourceSystem()->getSceneManager()->checkLoaded(mesh_, mRendering.getReferenceTime())) + mRendering.getWorkQueue()->addWorkItem(new PreloadMeshItem(mesh_, mRendering.getResourceSystem()->getSceneManager())); } void Scene::preloadCells(float dt) diff --git a/apps/openmw/mwworld/scene.hpp b/apps/openmw/mwworld/scene.hpp index cbceb14f5..5f17f8d59 100644 --- a/apps/openmw/mwworld/scene.hpp +++ b/apps/openmw/mwworld/scene.hpp @@ -133,7 +133,7 @@ namespace MWWorld Ptr searchPtrViaActorId (int actorId); - void preload(const std::string& mesh); + void preload(const std::string& mesh, bool useAnim=false); }; } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index a126e7e88..184a4ff60 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3481,10 +3481,16 @@ namespace MWWorld { if (obj.empty()) return; - MWWorld::ManualRef ref(store, obj); - std::string model = ref.getPtr().getClass().getModel(ref.getPtr()); - if (!model.empty()) - scene->preload(model); + try + { + MWWorld::ManualRef ref(store, obj); + std::string model = ref.getPtr().getClass().getModel(ref.getPtr()); + if (!model.empty()) + scene->preload(model, ref.getPtr().getClass().useAnim()); + } + catch(std::exception& e) + { + } } void World::preloadEffects(const ESM::EffectList *effectList) @@ -3493,6 +3499,12 @@ namespace MWWorld { const ESM::MagicEffect *effect = mStore.get().find(it->mEffectID); + if (MWMechanics::isSummoningEffect(it->mEffectID)) + { + preload(mWorldScene, mStore, "VFX_Summon_Start"); + preload(mWorldScene, mStore, MWMechanics::getSummonedCreature(it->mEffectID)); + } + preload(mWorldScene, mStore, effect->mCasting); preload(mWorldScene, mStore, effect->mHit); diff --git a/components/compiler/streamerrorhandler.cpp b/components/compiler/streamerrorhandler.cpp index 9ca8aa74b..04bee8adb 100644 --- a/components/compiler/streamerrorhandler.cpp +++ b/components/compiler/streamerrorhandler.cpp @@ -14,6 +14,9 @@ namespace Compiler else mStream << "warning "; + if (!mContext.empty()) + mStream << mContext << " "; + mStream << "line " << loc.mLine+1 << ", column " << loc.mColumn+1 << " (" << loc.mLiteral << ")" << std::endl @@ -34,5 +37,10 @@ namespace Compiler << " " << message << std::endl; } + void StreamErrorHandler::setContext(const std::string &context) + { + mContext = context; + } + StreamErrorHandler::StreamErrorHandler (std::ostream& ErrorStream) : mStream (ErrorStream) {} } diff --git a/components/compiler/streamerrorhandler.hpp b/components/compiler/streamerrorhandler.hpp index 85de1833a..d287833ee 100644 --- a/components/compiler/streamerrorhandler.hpp +++ b/components/compiler/streamerrorhandler.hpp @@ -13,6 +13,8 @@ namespace Compiler { std::ostream& mStream; + std::string mContext; + // not implemented StreamErrorHandler (const StreamErrorHandler&); @@ -26,6 +28,8 @@ namespace Compiler public: + void setContext(const std::string& context); + // constructors StreamErrorHandler (std::ostream& ErrorStream); diff --git a/components/openmw-mp/Base/BaseEvent.hpp b/components/openmw-mp/Base/BaseEvent.hpp index 28d4baf16..7ef655d84 100644 --- a/components/openmw-mp/Base/BaseEvent.hpp +++ b/components/openmw-mp/Base/BaseEvent.hpp @@ -12,13 +12,12 @@ namespace mwmp std::string refId; int count; int charge; - int goldValue; int actionCount; inline bool operator==(const ContainerItem& rhs) { - return refId == rhs.refId && count == rhs.count && charge == rhs.charge && goldValue && rhs.goldValue; + return refId == rhs.refId && count == rhs.count && charge == rhs.charge; } }; diff --git a/components/openmw-mp/Packets/World/PacketContainer.cpp b/components/openmw-mp/Packets/World/PacketContainer.cpp index af614a37c..74a273a43 100644 --- a/components/openmw-mp/Packets/World/PacketContainer.cpp +++ b/components/openmw-mp/Packets/World/PacketContainer.cpp @@ -60,7 +60,6 @@ void PacketContainer::Packet(RakNet::BitStream *bs, BaseEvent *event, bool send) RW(containerItem.refId, send); RW(containerItem.count, send); RW(containerItem.charge, send); - RW(containerItem.goldValue, send); RW(containerItem.actionCount, send); if (!send) diff --git a/components/openmw-mp/Version.hpp b/components/openmw-mp/Version.hpp index 3b4d57b7d..587b86056 100644 --- a/components/openmw-mp/Version.hpp +++ b/components/openmw-mp/Version.hpp @@ -5,7 +5,9 @@ #ifndef OPENMW_VERSION_HPP #define OPENMW_VERSION_HPP -#define TES3MP_VERSION "0.4.2" -#define TES3MP_PROTO_VERSION 5 +#define TES3MP_VERSION "0.5.0" +#define TES3MP_PROTO_VERSION 6 + +#define TES3MP_DEFAULT_PASSW "SuperPassword" #endif //OPENMW_VERSION_HPP diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index ee640d6cc..bd8ef8af4 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -374,7 +374,7 @@ namespace SceneUtil bool sortLights (const LightManager::LightSourceViewBound* left, const LightManager::LightSourceViewBound* right) { - return left->mViewBound.center().length2() - left->mViewBound.radius2()/4.f < right->mViewBound.center().length2() - right->mViewBound.radius2()/4.f; + return left->mViewBound.center().length2() - left->mViewBound.radius2()*81 < right->mViewBound.center().length2() - right->mViewBound.radius2()*81; } void LightListCallback::operator()(osg::Node *node, osg::NodeVisitor *nv) diff --git a/components/sdlutil/sdlcursormanager.cpp b/components/sdlutil/sdlcursormanager.cpp index ad03083de..411fb3694 100644 --- a/components/sdlutil/sdlcursormanager.cpp +++ b/components/sdlutil/sdlcursormanager.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -81,6 +82,8 @@ namespace osg::ref_ptr decompress (osg::ref_ptr source, float rotDegrees) { + // TODO: use software decompression once S3TC patent expires + int width = source->s(); int height = source->t(); @@ -130,9 +133,13 @@ namespace osg::ref_ptr geom; #if defined(__APPLE__) - // Extra flip needed on Intel graphics OS X systems due to a driver bug + // Extra flip needed on OS X systems due to a driver bug + const char* envval = getenv("OPENMW_CURSOR_WORKAROUND"); + bool workaround = !envval || envval == std::string("1"); std::string vendorString = (const char*)glGetString(GL_VENDOR); - if (vendorString.find("Intel") != std::string::npos) + if (!envval) + workaround = vendorString.find("Intel") != std::string::npos || vendorString.find("ATI") != std::string::npos || vendorString.find("AMD") != std::string::npos; + if (workaround) geom = osg::createTexturedQuadGeometry(osg::Vec3(-1,1,0), osg::Vec3(2,0,0), osg::Vec3(0,-2,0)); else #endif diff --git a/files/tes3mp/tes3mp-client-default.cfg b/files/tes3mp/tes3mp-client-default.cfg index 079f54148..ed7c4498b 100644 --- a/files/tes3mp/tes3mp-client-default.cfg +++ b/files/tes3mp/tes3mp-client-default.cfg @@ -1,6 +1,7 @@ [General] server = mp.tes3mp.com port = 25565 +password = # 0 - Verbose (spam), 1 - Info, 2 - Warnings, 3 - Errors, 4 - Only fatal errors loglevel = 0 diff --git a/files/tes3mp/tes3mp-server-default.cfg b/files/tes3mp/tes3mp-server-default.cfg index 85566f089..759c050a8 100644 --- a/files/tes3mp/tes3mp-server-default.cfg +++ b/files/tes3mp/tes3mp-server-default.cfg @@ -5,6 +5,7 @@ players = 64 hostname = My TES3MP server # 0 - Verbose (spam), 1 - Info, 2 - Warnings, 3 - Errors, 4 - Only fatal errors loglevel = 1 +password = [Plugins] #home = ~/local/openmw/tes3mp diff --git a/tes3mp-changelog.md b/tes3mp-changelog.md index d8df232db..bc9148901 100644 --- a/tes3mp-changelog.md +++ b/tes3mp-changelog.md @@ -1,13 +1,34 @@ +0.5.0 +----- + +* Server browser +* Synchronization of containers +* Reworked world packets allowing for the saving and loading of world state, including container state +* Bandwidth optimization by forwarding the most frequent player packets only to other players in the same loaded cells + +0.4.1 +----- + +* Packet for saving and loading spellbooks + +0.4.0 +----- + +* Synchronization of spells +* Packet for saving and loading inventories +* Being in a menu no longer prevents you from sending packets about your client +* Fixes to freezes and problems caused by players moving around in cells from expansions/plugins that are not loaded by others + 0.3.0 ----- -* Fixed client freezes related to players logging in at the same time -* Fixed server crashes related to sending information about invalid players -* Synchronization of world object removal, placement and scaling +* Synchronization of world object removal, placement, scaling, locking and unlocking * Synchronization of local, global and member script variables for specific scripts * Synchronization for the setdelete, placeat, setscale, lock and unlock console commands * Player markers on minimap * Death reasons in chat +* Fixes to client freezes related to players logging in at the same time +* Fixes to server crashes related to sending information about invalid players 0.2.0 ----- @@ -19,9 +40,9 @@ ------ * Synchronization of attributes and skills -* Fixed memory leaks related to player initialization on Windows servers -* Fixed various graphical glitches -* Disabled main menu buttons for starting, saving and loading games +* Fixes to memory leaks related to player initialization on Windows servers +* Fixes to various graphical glitches +* Main menu buttons for starting, saving and loading games are now disabled 0.0.1a ------ @@ -36,6 +57,7 @@ 0.0.1 ----- +* Initial networking and packet architecture * Synchronization of player character generation * Synchronization of player position * Synchronization of player attack states (unarmed, armed with a weapon, using a spell) diff --git a/tes3mp-credits.md b/tes3mp-credits.md index 7cbebc0eb..20868ffe0 100644 --- a/tes3mp-credits.md +++ b/tes3mp-credits.md @@ -4,20 +4,20 @@ tes3mp Credits Programmers ----------- - Stanislav Zhukov (Koncord) - The main loafer and Project Leader - David Cernat - The person pulling the strings in the shadows + Stanislav Zhukov (Koncord) - Overall architecture, networking & scripting systems, player sync, server browser + David Cernat - World sync & state saving/loading, player state saving/loading, general bug fixes Script developers ----------------- - Grim Kriegor + Grim Kriegor - Teleportation commands, various early script fixes Testers ------- - Volk Milit (Ja'Virr-Dar) - Team Manager, Debian Linux + Volk Milit (Ja'Virr-Dar) - Team manager, Debian Linux Shnatsel - Debian Linux Goodevil - Mint and Xubuntu Linux @@ -25,8 +25,8 @@ Testers Public Relations and Translations --------------------------------- - Volk Milit (Ja'Virr-Dar) - Public relations & News Writer - Shnatsel - Translator & News Writer + Volk Milit (Ja'Virr-Dar) - Public relations & news writer + Shnatsel - Translator & news writer Art