forked from mirror/openmw-tes3mp
commit
ba4b77f2c3
69 changed files with 866 additions and 227 deletions
16
README.md
16
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).
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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<ServerData>::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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1757,6 +1757,41 @@ namespace CSMWorld
|
|||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct GenderNpcColumn : public Column<ESXRecordT>
|
||||
{
|
||||
GenderNpcColumn()
|
||||
: Column<ESXRecordT>(Columns::ColumnId_GenderNpc, ColumnBase::Display_GenderNpc)
|
||||
{}
|
||||
|
||||
virtual QVariant get(const Record<ESXRecordT>& 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<ESXRecordT>& 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<typename ESXRecordT>
|
||||
struct EnchantmentTypeColumn : public Column<ESXRecordT>
|
||||
|
|
|
@ -363,7 +363,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
|
|||
mBodyParts.addColumn (new FixedRecordTypeColumn<ESM::BodyPart> (UniversalId::Type_BodyPart));
|
||||
mBodyParts.addColumn (new BodyPartTypeColumn<ESM::BodyPart>);
|
||||
mBodyParts.addColumn (new VampireColumn<ESM::BodyPart>);
|
||||
mBodyParts.addColumn (new FlagColumn<ESM::BodyPart> (Columns::ColumnId_Female, ESM::BodyPart::BPF_Female));
|
||||
mBodyParts.addColumn(new GenderNpcColumn<ESM::BodyPart>);
|
||||
mBodyParts.addColumn (new FlagColumn<ESM::BodyPart> (Columns::ColumnId_Playable,
|
||||
ESM::BodyPart::BPF_NotPlayable, ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, true));
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
223
apps/openmw-mp/Cell.cpp
Normal file
223
apps/openmw-mp/Cell.cpp
Normal file
|
@ -0,0 +1,223 @@
|
|||
//
|
||||
// Created by koncord on 18.02.17.
|
||||
//
|
||||
|
||||
#include "Cell.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#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 <Player*> 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();
|
||||
}
|
76
apps/openmw-mp/Cell.hpp
Normal file
76
apps/openmw-mp/Cell.hpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// Created by koncord on 18.02.17.
|
||||
//
|
||||
|
||||
#ifndef OPENMW_CELL_HPP
|
||||
#define OPENMW_CELL_HPP
|
||||
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <components/esm/records.hpp>
|
||||
#include <components/openmw-mp/Base/BaseEvent.hpp>
|
||||
#include <components/openmw-mp/Packets/World/WorldPacket.hpp>
|
||||
|
||||
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<Cell*> 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<Player*> 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
|
|
@ -10,6 +10,7 @@
|
|||
#include <RakPeerInterface.h>
|
||||
#include "MasterClient.hpp"
|
||||
#include <components/openmw-mp/Log.hpp>
|
||||
#include <components/openmw-mp/Version.hpp>
|
||||
#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();
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#include "Networking.hpp"
|
||||
#include "MasterClient.hpp"
|
||||
#include "Cell.hpp"
|
||||
#include <components/openmw-mp/Version.hpp>
|
||||
|
||||
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<Script::CallbackIdentity("OnServerInit")>();
|
||||
|
||||
serverPassword = TES3MP_DEFAULT_PASSW;
|
||||
}
|
||||
|
||||
Networking::~Networking()
|
||||
{
|
||||
Script::Call<Script::CallbackIdentity("OnServerExit")>(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<Script::CallbackIdentity("OnPlayerCellChange")>(player->getId());
|
||||
}
|
||||
else
|
||||
|
@ -180,6 +220,8 @@ void Networking::processPlayerPacket(RakNet::Packet *packet)
|
|||
|
||||
myPacket->Read(player);
|
||||
|
||||
CellController::get()->update(player);
|
||||
|
||||
Script::Call<Script::CallbackIdentity("OnPlayerCellState")>(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<Script::CallbackIdentity("OnPlayerAttributesChange")>(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<Script::CallbackIdentity("OnPlayerSkillsChange")>(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<Script::CallbackIdentity("OnPlayerLevelChange")>(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<Script::CallbackIdentity("OnPlayerEquipmentChange")>(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<Script::CallbackIdentity("OnContainer")>(
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 <Player*> 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<void(Player *pl, Player *other)> func)
|
||||
{
|
||||
std::list <Player*> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include <components/openmw-mp/Log.hpp>
|
||||
#include <components/openmw-mp/Base/BasePlayer.hpp>
|
||||
#include <components/openmw-mp/Packets/Player/PlayerPacket.hpp>
|
||||
#include "Cell.hpp"
|
||||
|
||||
struct Player;
|
||||
typedef std::map<RakNet::RakNetGUID, Player*> 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<void(Player *pl, Player *other)> func);
|
||||
|
||||
public:
|
||||
mwmp::InventoryChanges inventoryChangesBuffer;
|
||||
mwmp::SpellbookChanges spellbookChangesBuffer;
|
||||
mwmp::JournalChanges journalChangesBuffer;
|
||||
|
||||
private:
|
||||
CellController::TContainer cells;
|
||||
bool handshakeState;
|
||||
int loadState;
|
||||
unsigned short lastAttacker;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"))
|
||||
{
|
||||
|
|
|
@ -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<std::string>()));
|
||||
|
||||
// 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);
|
||||
|
||||
|
|
|
@ -84,7 +84,6 @@ namespace OMW
|
|||
osg::ref_ptr<osgViewer::ScreenCaptureHandler> mScreenCaptureHandler;
|
||||
std::string mCellName;
|
||||
std::vector<std::string> 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);
|
||||
|
||||
|
|
|
@ -100,9 +100,6 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
|
|||
("no-sound", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "disable all sounds")
|
||||
|
||||
("script-verbose", bpo::value<bool>()->implicit_value(true)
|
||||
->default_value(false), "verbose script output")
|
||||
|
||||
("script-all", bpo::value<bool>()->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<bool>());
|
||||
engine.setCompileAllDialogue(variables["script-all-dialogue"].as<bool>());
|
||||
engine.setScriptsVerbosity(variables["script-verbose"].as<bool>());
|
||||
engine.setScriptConsoleMode (variables["script-console"].as<bool>());
|
||||
engine.setStartupScript (variables["script-run"].as<Files::EscapeHashString>().toStdString());
|
||||
engine.setWarningsMode (variables["script-warn"].as<int>());
|
||||
|
|
|
@ -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<ESM::Activator> *ref = ptr.get<ESM::Activator>();
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<MWWorld::Action> Container::activate (const MWWorld::Ptr& ptr,
|
||||
const MWWorld::Ptr& actor) const
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1189,4 +1189,40 @@ namespace MWMechanics
|
|||
return true;
|
||||
}
|
||||
|
||||
std::string getSummonedCreature(int effectId)
|
||||
{
|
||||
static std::map<int, std::string> 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<int, std::string>::const_iterator it = summonMap.find(effectId);
|
||||
if (it == summonMap.end())
|
||||
return std::string();
|
||||
else
|
||||
return MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>().find(it->second)->getString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -40,32 +40,7 @@ namespace MWMechanics
|
|||
|
||||
void UpdateSummonedCreatures::process()
|
||||
{
|
||||
static std::map<int, std::string> 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<ESM::GameSetting>().find(creatureGmst)->getString();
|
||||
|
||||
std::string creatureID = getSummonedCreature(it->first);
|
||||
if (!creatureID.empty())
|
||||
{
|
||||
int creatureActorId = -1;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "../mwmechanics/spellcasting.hpp"
|
||||
#include <components/openmw-mp/Log.hpp>
|
||||
#include <cstdlib>
|
||||
#include <components/openmw-mp/Version.hpp>
|
||||
|
||||
#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<std::string>()->default_value(""),
|
||||
"connect to server (e.g. --connect=127.0.0.1:25565)");
|
||||
desc->add_options()
|
||||
("connect", bpo::value<std::string>()->default_value(""),
|
||||
"connect to server (e.g. --connect=127.0.0.1:25565)")
|
||||
("password", bpo::value<std::string>()->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<string>();
|
||||
Main::passw = variables["password"].as<string>();
|
||||
}
|
||||
|
||||
static Settings::CategorySettingValueMap saveUserSettings;
|
||||
|
@ -130,15 +136,19 @@ bool Main::init(std::vector<std::string> &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();
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace mwmp
|
|||
|
||||
private:
|
||||
static std::string addr;
|
||||
static std::string passw;
|
||||
Main (const Main&);
|
||||
///< not implemented
|
||||
Main& operator= (const Main&);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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<std::string>& 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<ESM::Script>().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<ESM::Script>().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());
|
||||
|
|
|
@ -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<std::string>& scriptBlacklist);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -304,6 +304,11 @@ namespace MWWorld
|
|||
return "";
|
||||
}
|
||||
|
||||
bool Class::useAnim() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Class::getModelsToPreload(const Ptr &ptr, std::vector<std::string> &models) const
|
||||
{
|
||||
std::string model = getModel(ptr);
|
||||
|
|
|
@ -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<std::string>& models) const;
|
||||
///< Get a list of models to preload that this object may use (directly or indirectly). default implementation: list getModel().
|
||||
|
||||
|
|
|
@ -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<ESM::Armor>()->mBase->mData.mType < test.get<ESM::Armor>()->mBase->mData.mType)
|
||||
continue;
|
||||
|
||||
if (old.get<ESM::Armor>()->mBase->mData.mType == test.get<ESM::Armor>()->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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ESM::MagicEffect>().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);
|
||||
|
||||
|
|
|
@ -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) {}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <SDL_mouse.h>
|
||||
#include <SDL_endian.h>
|
||||
|
@ -81,6 +82,8 @@ namespace
|
|||
|
||||
osg::ref_ptr<osg::Image> decompress (osg::ref_ptr<osg::Image> 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<osg::Geometry> 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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue