forked from teamnwah/openmw-tes3coop
Merge pull request #309 from TES3MP/new-script-api
Add new-script-api commits
This commit is contained in:
commit
2bc79fcdf4
346 changed files with 10029 additions and 33656 deletions
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -1,3 +1,6 @@
|
|||
[submodule "extern/breakpad"]
|
||||
path = extern/breakpad
|
||||
url = https://chromium.googlesource.com/breakpad/breakpad
|
||||
[submodule "extern/sol"]
|
||||
path = extern/sol
|
||||
url = https://github.com/ThePhD/sol2
|
||||
|
|
|
@ -213,7 +213,6 @@ endif()
|
|||
IF(BUILD_OPENMW OR BUILD_OPENCS)
|
||||
|
||||
find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgParticle osgUtil osgFX)
|
||||
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS})
|
||||
|
||||
set(USED_OSG_PLUGINS
|
||||
osgdb_bmp
|
||||
|
@ -257,6 +256,8 @@ IF(BUILD_OPENMW OR BUILD_OPENCS)
|
|||
|
||||
ENDIF(BUILD_OPENMW OR BUILD_OPENCS)
|
||||
|
||||
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS}) # HACK: DON'T TOUCH IT!
|
||||
|
||||
|
||||
set(BOOST_COMPONENTS system filesystem program_options)
|
||||
if(WIN32)
|
||||
|
|
|
@ -5,7 +5,7 @@ TES3MP
|
|||
|
||||
TES3MP is a project aiming to add multiplayer functionality to [OpenMW](https://github.com/OpenMW/openmw), a free and open source engine recreation of the popular Bethesda Softworks game "The Elder Scrolls III: Morrowind".
|
||||
|
||||
* TES3MP version: 0.6.1
|
||||
* TES3MP version: 0.7-alpha
|
||||
* OpenMW version: 0.43.0
|
||||
* License: GPLv3 (see [LICENSE](https://github.com/TES3MP/openmw-tes3mp/blob/master/LICENSE) for more information)
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
connect(tblServerBrowser, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(play()));
|
||||
connect(cBoxNotFull, SIGNAL(toggled(bool)), this, SLOT(notFullSwitch(bool)));
|
||||
connect(cBoxWithPlayers, SIGNAL(toggled(bool)), this, SLOT(havePlayersSwitch(bool)));
|
||||
connect(cBBoxWOPass, SIGNAL(toggled(bool)), this, SLOT(noPasswordSwitch(bool)));
|
||||
connect(comboLatency, SIGNAL(currentIndexChanged(int)), this, SLOT(maxLatencyChanged(int)));
|
||||
connect(leGamemode, SIGNAL(textChanged(const QString &)), this, SLOT(gamemodeChanged(const QString &)));
|
||||
loadFavorites();
|
||||
|
@ -65,7 +66,7 @@ MainWindow::~MainWindow()
|
|||
delete mGameInvoker;
|
||||
}
|
||||
|
||||
void MainWindow::addServerAndUpdate(QString addr)
|
||||
void MainWindow::addServerAndUpdate(const QString &addr)
|
||||
{
|
||||
favorites->insertRow(0);
|
||||
QModelIndex mi = favorites->index(0, ServerData::ADDR);
|
||||
|
@ -142,7 +143,8 @@ void MainWindow::play()
|
|||
if (sm->myData[sourceId].GetPassword() == 1)
|
||||
{
|
||||
bool ok;
|
||||
QString passw = QInputDialog::getText(this, "Connecting to: " + sm->myData[sourceId].addr, "Password: ", QLineEdit::Password, "", &ok);
|
||||
QString passw = QInputDialog::getText(this, tr("Connecting to: ") + sm->myData[sourceId].addr, tr("Password: "),
|
||||
QLineEdit::Password, "", &ok);
|
||||
if (!ok)
|
||||
return;
|
||||
arguments.append(QLatin1String("--password=") + passw.toLatin1());
|
||||
|
@ -228,6 +230,11 @@ void MainWindow::havePlayersSwitch(bool state)
|
|||
proxyModel->filterEmptyServers(state);
|
||||
}
|
||||
|
||||
void MainWindow::noPasswordSwitch(bool state)
|
||||
{
|
||||
proxyModel->filterPassworded(state);
|
||||
}
|
||||
|
||||
void MainWindow::maxLatencyChanged(int index)
|
||||
{
|
||||
int maxLatency = index * 50;
|
||||
|
|
|
@ -17,11 +17,11 @@ class MainWindow : public QMainWindow, private Ui::MainWindow
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = 0);
|
||||
virtual ~MainWindow();
|
||||
explicit MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow() override;
|
||||
protected:
|
||||
void closeEvent(QCloseEvent * event) Q_DECL_OVERRIDE;
|
||||
void addServerAndUpdate(QString addr);
|
||||
void addServerAndUpdate(const QString &addr);
|
||||
protected slots:
|
||||
void tabSwitched(int index);
|
||||
void addServer();
|
||||
|
@ -31,6 +31,7 @@ protected slots:
|
|||
void serverSelected();
|
||||
void notFullSwitch(bool state);
|
||||
void havePlayersSwitch(bool state);
|
||||
void noPasswordSwitch(bool state);
|
||||
void maxLatencyChanged(int index);
|
||||
void gamemodeChanged(const QString &text);
|
||||
private:
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "ServerModel.hpp"
|
||||
|
||||
#include <qdebug.h>
|
||||
#include <apps/browser/netutils/Utils.hpp>
|
||||
|
||||
bool MySortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
||||
{
|
||||
|
@ -13,26 +14,49 @@ bool MySortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &
|
|||
QModelIndex pingIndex = sourceModel()->index(sourceRow, ServerData::PING, sourceParent);
|
||||
QModelIndex plIndex = sourceModel()->index(sourceRow, ServerData::PLAYERS, sourceParent);
|
||||
QModelIndex maxPlIndex = sourceModel()->index(sourceRow, ServerData::MAX_PLAYERS, sourceParent);
|
||||
QModelIndex passwordIndex = sourceModel()->index(sourceRow, ServerData::PASSW, sourceParent);
|
||||
|
||||
int ping = sourceModel()->data(pingIndex).toInt();
|
||||
bool pingOk;
|
||||
int ping = sourceModel()->data(pingIndex).toInt(&pingOk);
|
||||
int players = sourceModel()->data(plIndex).toInt();
|
||||
int maxPlayers = sourceModel()->data(maxPlIndex).toInt();
|
||||
|
||||
if (maxPing > 0 && (ping == -1 || ping > maxPing))
|
||||
if (maxPing > 0 && (ping == -1 || ping > maxPing || !pingOk))
|
||||
return false;
|
||||
if (filterEmpty && players == 0)
|
||||
return false;
|
||||
if (filterFull && players >= maxPlayers)
|
||||
return false;
|
||||
if(filterPasswEnabled && sourceModel()->data(passwordIndex).toString() == "Yes")
|
||||
return false;
|
||||
|
||||
return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent);
|
||||
}
|
||||
|
||||
bool MySortFilterProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
|
||||
{
|
||||
if(sortColumn() == ServerData::PING)
|
||||
{
|
||||
bool valid;
|
||||
|
||||
int pingright = sourceModel()->data(source_right).toInt(&valid);
|
||||
pingright = valid ? pingright : PING_UNREACHABLE;
|
||||
|
||||
int pingleft = sourceModel()->data(source_left).toInt(&valid);
|
||||
pingleft = valid ? pingleft : PING_UNREACHABLE;
|
||||
return pingleft < pingright;
|
||||
}
|
||||
else
|
||||
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
||||
}
|
||||
|
||||
MySortFilterProxyModel::MySortFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent)
|
||||
{
|
||||
filterEmpty = false;
|
||||
filterFull = false;
|
||||
filterPasswEnabled = false;
|
||||
maxPing = 0;
|
||||
setSortCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
|
||||
}
|
||||
|
||||
void MySortFilterProxyModel::filterEmptyServers(bool state)
|
||||
|
@ -52,3 +76,9 @@ void MySortFilterProxyModel::pingLessThan(int maxPing)
|
|||
this->maxPing = maxPing;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
void MySortFilterProxyModel::filterPassworded(bool state)
|
||||
{
|
||||
filterPasswEnabled = state;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
|
|
@ -13,13 +13,15 @@ class MySortFilterProxyModel : public QSortFilterProxyModel
|
|||
Q_OBJECT
|
||||
protected:
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const Q_DECL_FINAL;
|
||||
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const Q_DECL_FINAL;
|
||||
public:
|
||||
MySortFilterProxyModel(QObject *parent);
|
||||
explicit MySortFilterProxyModel(QObject *parent);
|
||||
void filterFullServer(bool state);
|
||||
void filterEmptyServers(bool state);
|
||||
void filterPassworded(bool state);
|
||||
void pingLessThan(int maxPing);
|
||||
private:
|
||||
bool filterEmpty, filterFull;
|
||||
bool filterEmpty, filterFull, filterPasswEnabled;
|
||||
int maxPing;
|
||||
};
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include <QDebug>
|
||||
#include "PingUpdater.hpp"
|
||||
|
||||
void PingHelper::Add(int row, AddrPair addrPair)
|
||||
void PingHelper::Add(int row, const AddrPair &addrPair)
|
||||
{
|
||||
pingUpdater->addServer(row, addrPair);
|
||||
if (!pingThread->isRunning())
|
||||
|
@ -35,9 +35,8 @@ PingHelper &PingHelper::Get()
|
|||
return helper;
|
||||
}
|
||||
|
||||
PingHelper::PingHelper()
|
||||
PingHelper::PingHelper() : QObject()
|
||||
{
|
||||
QObject();
|
||||
pingThread = new QThread;
|
||||
pingUpdater = new PingUpdater;
|
||||
pingUpdater->moveToThread(pingThread);
|
||||
|
@ -48,11 +47,4 @@ PingHelper::PingHelper()
|
|||
connect(this, SIGNAL(stop()), pingUpdater, SLOT(stop()));
|
||||
//connect(pingUpdater, SIGNAL(finished()), pingUpdater, SLOT(deleteLater()));
|
||||
connect(pingUpdater, SIGNAL(updateModel(int, unsigned)), this, SLOT(update(int, unsigned)));
|
||||
|
||||
|
||||
}
|
||||
|
||||
PingHelper::~PingHelper()
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -17,17 +17,16 @@ class PingHelper : public QObject
|
|||
Q_OBJECT
|
||||
public:
|
||||
|
||||
void Add(int row, AddrPair addrPair);
|
||||
void Add(int row, const AddrPair &addrPair);
|
||||
void Stop();
|
||||
void SetModel(QAbstractTableModel *model);
|
||||
//void UpdateImmedialy(PingUpdater::AddrPair addrPair);
|
||||
static PingHelper &Get();
|
||||
private:
|
||||
PingHelper();
|
||||
~PingHelper();
|
||||
|
||||
PingHelper(const PingHelper&) = delete;
|
||||
PingHelper& operator=(const PingHelper&) = delete;
|
||||
private:
|
||||
PingHelper();
|
||||
signals:
|
||||
void stop();
|
||||
public slots:
|
||||
|
|
|
@ -14,7 +14,7 @@ void PingUpdater::stop()
|
|||
run = false;
|
||||
}
|
||||
|
||||
void PingUpdater::addServer(int row, AddrPair addr)
|
||||
void PingUpdater::addServer(int row, const AddrPair &addr)
|
||||
{
|
||||
servers.push_back({row, addr});
|
||||
run = true;
|
||||
|
|
|
@ -14,7 +14,7 @@ class PingUpdater : public QObject
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
void addServer(int row, AddrPair addrPair);
|
||||
void addServer(int row, const AddrPair &addrPair);
|
||||
public slots:
|
||||
void stop();
|
||||
void process();
|
||||
|
|
|
@ -19,8 +19,8 @@ QueryHelper::QueryHelper(QAbstractItemModel *model)
|
|||
connect(queryThread, SIGNAL(started()), queryUpdate, SLOT(process()));
|
||||
connect(queryUpdate, SIGNAL(finished()), queryThread, SLOT(quit()));
|
||||
connect(queryUpdate, &QueryUpdate::finished, [this](){emit finished();});
|
||||
connect(queryUpdate, SIGNAL(updateModel(QString, unsigned short, QueryData)),
|
||||
this, SLOT(update(QString, unsigned short, QueryData)));
|
||||
connect(queryUpdate, SIGNAL(updateModel(const QString&, unsigned short, const QueryData&)),
|
||||
this, SLOT(update(const QString&, unsigned short, const QueryData&)));
|
||||
queryUpdate->moveToThread(queryThread);
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ void QueryHelper::terminate()
|
|||
queryThread->terminate();
|
||||
}
|
||||
|
||||
void QueryHelper::update(QString addr, unsigned short port, QueryData data)
|
||||
void QueryHelper::update(const QString &addr, unsigned short port, const QueryData& data)
|
||||
{
|
||||
ServerModel *model = ((ServerModel*)_model);
|
||||
model->insertRow(model->rowCount());
|
||||
|
@ -80,7 +80,7 @@ void QueryUpdate::process()
|
|||
return;
|
||||
}
|
||||
|
||||
for (auto server : data)
|
||||
for (const auto &server : data)
|
||||
emit updateModel(server.first.ToString(false), server.first.GetPort(), server.second);
|
||||
emit finished();
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ public slots:
|
|||
void refresh();
|
||||
void terminate();
|
||||
private slots:
|
||||
void update(QString addr, unsigned short port, QueryData data);
|
||||
void update(const QString &addr, unsigned short port, const QueryData& data);
|
||||
signals:
|
||||
void finished();
|
||||
void started();
|
||||
|
@ -38,7 +38,7 @@ class QueryUpdate : public QObject
|
|||
Q_OBJECT
|
||||
signals:
|
||||
void finished();
|
||||
void updateModel(QString addr, unsigned short port, QueryData data);
|
||||
void updateModel(const QString &addr, unsigned short port, const QueryData& data);
|
||||
public slots:
|
||||
void process();
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "ServerInfoDialog.hpp"
|
||||
#include <apps/browser/netutils/Utils.hpp>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
using namespace std;
|
||||
using namespace RakNet;
|
||||
|
@ -18,12 +19,7 @@ ServerInfoDialog::ServerInfoDialog(QWidget *parent): QDialog(parent)
|
|||
connect(btnRefresh, SIGNAL(clicked()), this, SLOT(refresh()));
|
||||
}
|
||||
|
||||
ServerInfoDialog::~ServerInfoDialog()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ServerInfoDialog::Server(QString addr)
|
||||
void ServerInfoDialog::Server(const QString &addr)
|
||||
{
|
||||
this->addr = addr;
|
||||
}
|
||||
|
@ -42,7 +38,7 @@ bool ServerInfoDialog::refresh()
|
|||
|
||||
listPlayers->clear();
|
||||
|
||||
for (auto player : sd.second.players)
|
||||
for (const auto &player : sd.second.players)
|
||||
listPlayers->addItem(QString::fromStdString(player));
|
||||
|
||||
listPlugins->clear();
|
||||
|
|
|
@ -11,9 +11,8 @@ class ServerInfoDialog : public QDialog, public Ui::Dialog
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ServerInfoDialog(QWidget *parent = 0);
|
||||
virtual ~ServerInfoDialog();
|
||||
void Server(QString addr);
|
||||
explicit ServerInfoDialog(QWidget *parent = nullptr);
|
||||
void Server(const QString &addr);
|
||||
public slots:
|
||||
bool refresh();
|
||||
private:
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
#include <qmessagebox.h>
|
||||
#include "ServerModel.hpp"
|
||||
#include <qdebug.h>
|
||||
#include <apps/browser/netutils/Utils.hpp>
|
||||
|
||||
ServerModel::ServerModel(QObject *parent) : QAbstractTableModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ServerModel::~ServerModel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*QHash<int, QByteArray> ServerModel::roleNames() const
|
||||
{
|
||||
return roles;
|
||||
|
@ -49,7 +44,7 @@ QVariant ServerModel::data(const QModelIndex &index, int role) const
|
|||
var = QString(sd.rules.at("name").str.c_str());
|
||||
break;
|
||||
case ServerData::PING:
|
||||
var = sd.ping;
|
||||
var = sd.ping == PING_UNREACHABLE ? QVariant("Unreachable") : sd.ping;
|
||||
break;
|
||||
case ServerData::MODNAME:
|
||||
if (sd.rules.at("gamemode").str == "")
|
||||
|
|
|
@ -29,8 +29,7 @@ class ServerModel: public QAbstractTableModel
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ServerModel(QObject *parent = 0);
|
||||
~ServerModel();
|
||||
explicit ServerModel(QObject *parent = nullptr);
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_FINAL;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_FINAL;
|
||||
int columnCount(const QModelIndex &parent) const Q_DECL_FINAL;
|
||||
|
|
|
@ -30,7 +30,7 @@ QueryClient::~QueryClient()
|
|||
RakPeerInterface::DestroyInstance(peer);
|
||||
}
|
||||
|
||||
void QueryClient::SetServer(std::string addr, unsigned short port)
|
||||
void QueryClient::SetServer(const string &addr, unsigned short port)
|
||||
{
|
||||
masterAddr = SystemAddress(addr.c_str(), port);
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ map<SystemAddress, QueryData> QueryClient::Query()
|
|||
return query;
|
||||
}
|
||||
|
||||
pair<SystemAddress, QueryData> QueryClient::Update(RakNet::SystemAddress addr)
|
||||
pair<SystemAddress, QueryData> QueryClient::Update(const RakNet::SystemAddress &addr)
|
||||
{
|
||||
qDebug() << "Locking mutex in QueryClient::Update(RakNet::SystemAddress addr)";
|
||||
pair<SystemAddress, QueryData> server;
|
||||
|
@ -179,7 +179,7 @@ ConnectionState QueryClient::Connect()
|
|||
{
|
||||
|
||||
ConnectionAttemptResult car = peer->Connect(masterAddr.ToString(false), masterAddr.GetPort(), TES3MP_MASTERSERVER_PASSW,
|
||||
strlen(TES3MP_MASTERSERVER_PASSW), 0, 0, 5, 500);
|
||||
strlen(TES3MP_MASTERSERVER_PASSW), nullptr, 0, 5, 500);
|
||||
|
||||
while (true)
|
||||
{
|
||||
|
|
|
@ -14,16 +14,16 @@
|
|||
|
||||
class QueryClient
|
||||
{
|
||||
private:
|
||||
public:
|
||||
QueryClient(QueryClient const &) = delete;
|
||||
QueryClient(QueryClient &&) = delete;
|
||||
QueryClient &operator=(QueryClient const &) = delete;
|
||||
QueryClient &operator=(QueryClient &&) = delete;
|
||||
public:
|
||||
|
||||
static QueryClient &Get();
|
||||
void SetServer(std::string addr, unsigned short port);
|
||||
void SetServer(const std::string &addr, unsigned short port);
|
||||
std::map<RakNet::SystemAddress, QueryData> Query();
|
||||
std::pair<RakNet::SystemAddress, QueryData> Update(RakNet::SystemAddress addr);
|
||||
std::pair<RakNet::SystemAddress, QueryData> Update(const RakNet::SystemAddress &addr);
|
||||
int Status();
|
||||
private:
|
||||
RakNet::ConnectionState Connect();
|
||||
|
|
|
@ -44,11 +44,15 @@ unsigned int PingRakNetServer(const char *addr, unsigned short port)
|
|||
break;
|
||||
case ID_CONNECTED_PING:
|
||||
case ID_UNCONNECTED_PONG:
|
||||
{
|
||||
RakNet::BitStream bsIn(&packet->data[1], packet->length, false);
|
||||
bsIn.Read(time);
|
||||
time = now - time;
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
peer->DeallocatePacket(packet);
|
||||
}
|
||||
|
@ -69,9 +73,9 @@ ServerExtendedData getExtendedData(const char *addr, unsigned short port)
|
|||
sstr << TES3MP_VERSION;
|
||||
sstr << TES3MP_PROTO_VERSION;
|
||||
|
||||
std::string msg = "";
|
||||
std::string msg;
|
||||
|
||||
if (peer->Connect(addr, port, sstr.str().c_str(), (int)(sstr.str().size()), 0, 0, 3, 500, 0) != RakNet::CONNECTION_ATTEMPT_STARTED)
|
||||
if (peer->Connect(addr, port, sstr.str().c_str(), (int)(sstr.str().size()), nullptr, 0, 3, 500, 0) != RakNet::CONNECTION_ATTEMPT_STARTED)
|
||||
msg = "Connection attempt failed.\n";
|
||||
|
||||
|
||||
|
@ -142,14 +146,14 @@ ServerExtendedData getExtendedData(const char *addr, unsigned short port)
|
|||
{
|
||||
RakNet::RakString str;
|
||||
bs.Read(str);
|
||||
data.players.push_back(str.C_String());
|
||||
data.players.emplace_back(str.C_String());
|
||||
}
|
||||
bs.Read(length);
|
||||
for (size_t i = 0; i < length; i++)
|
||||
{
|
||||
RakNet::RakString str;
|
||||
bs.Read(str);
|
||||
data.plugins.push_back(str.C_String());
|
||||
data.plugins.emplace_back(str.C_String());
|
||||
}
|
||||
done = true;
|
||||
}
|
||||
|
|
69
apps/master/AdminRest.cpp
Normal file
69
apps/master/AdminRest.cpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
//
|
||||
// Created by koncord on 04.09.17.
|
||||
//
|
||||
|
||||
#include "AdminRest.hpp"
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
|
||||
#include "RestUtils.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace chrono;
|
||||
using namespace boost::property_tree;
|
||||
|
||||
|
||||
AdminRest::AdminRest(const std::string &cert, const std::string &key, const std::string &verifyFile,
|
||||
unsigned short port, std::shared_ptr<MasterServer> master) : httpServer(cert, key, verifyFile), master(master)
|
||||
{
|
||||
httpServer.config.port = port;
|
||||
}
|
||||
|
||||
void AdminRest::start()
|
||||
{
|
||||
static const string AdminArea = "^/api/admin?";
|
||||
|
||||
httpServer.resource[AdminArea]["POST"] = [this](auto response, auto request) {
|
||||
cout << request->method << endl;
|
||||
cout << request->path << endl;
|
||||
cout << request->http_version << endl;
|
||||
|
||||
for (auto &header : request->header)
|
||||
cout << header.first << ": " << header.second << endl;
|
||||
|
||||
string resp;
|
||||
master->luaStuff([&request, &response, &resp](sol::state &state) {
|
||||
sol::protected_function func = state["OnAdminRequest"];
|
||||
|
||||
sol::protected_function_result result = func.call(request->remote_endpoint_address, request->content.string());
|
||||
if (result.valid())
|
||||
*response << result.get<string>();
|
||||
else
|
||||
{
|
||||
cerr << "Error: " << result.get<string>() << endl;
|
||||
*response << response500;
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
/*httpServer.on_error = [](auto request, const boost::system::error_code& err)
|
||||
{
|
||||
std::cerr << "Error: " << err.message() << " " << err.category().name() << std::endl;
|
||||
};*/
|
||||
|
||||
httpServer.default_resource["GET"] = [](auto response, auto /*request*/) {
|
||||
cout << "Default request" << endl;
|
||||
*response << response400;
|
||||
};
|
||||
|
||||
thr = thread([this](){httpServer.start();});
|
||||
}
|
||||
|
||||
void AdminRest::stop()
|
||||
{
|
||||
httpServer.stop();
|
||||
if(thr.joinable())
|
||||
thr.join();
|
||||
}
|
25
apps/master/AdminRest.hpp
Normal file
25
apps/master/AdminRest.hpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// Created by koncord on 04.09.17.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SimpleWeb/https_server.hpp"
|
||||
#include "MasterServer.hpp"
|
||||
|
||||
typedef SimpleWeb::Server<SimpleWeb::HTTPS> HttpsServer;
|
||||
|
||||
class AdminRest
|
||||
{
|
||||
public:
|
||||
AdminRest(const std::string &cert, const std::string &key, const std::string &verifyFile, unsigned short port, std::shared_ptr<MasterServer> master);
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
private:
|
||||
HttpsServer httpServer;
|
||||
std::shared_ptr<MasterServer> master;
|
||||
std::thread thr;
|
||||
};
|
||||
|
||||
|
|
@ -3,12 +3,15 @@ project(masterserver)
|
|||
#set(CMAKE_CXX_STANDARD 14)
|
||||
add_definitions(-std=gnu++14)
|
||||
|
||||
include_directories("./")
|
||||
find_package(LuaJit REQUIRED)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
|
||||
set(SOURCE_FILES main.cpp MasterServer.cpp MasterServer.hpp RestServer.cpp RestServer.hpp)
|
||||
include_directories("./" ${LUAJIT_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/extern/sol ${OPENSSL_INCLUDE_DIR})
|
||||
|
||||
set(SOURCE_FILES main.cpp MasterServer.cpp MasterServer.hpp RestServer.cpp RestServer.hpp AdminRest.cpp)
|
||||
|
||||
add_executable(masterserver ${SOURCE_FILES})
|
||||
target_link_libraries(masterserver ${RakNet_LIBRARY} components)
|
||||
target_link_libraries(masterserver ${RakNet_LIBRARY} ${LUAJIT_LIBRARY} ${OPENSSL_LIBRARIES} components)
|
||||
|
||||
option(BUILD_MASTER_TEST "build master server test program" OFF)
|
||||
|
||||
|
|
|
@ -12,19 +12,54 @@
|
|||
#include <components/openmw-mp/Master/PacketMasterUpdate.hpp>
|
||||
#include <components/openmw-mp/Master/PacketMasterAnnounce.hpp>
|
||||
#include <components/openmw-mp/Version.hpp>
|
||||
#include <components/openmw-mp/Utils.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
using namespace RakNet;
|
||||
using namespace std;
|
||||
using namespace mwmp;
|
||||
using namespace chrono;
|
||||
|
||||
MasterServer::MasterServer(unsigned short maxConnections, unsigned short port)
|
||||
MasterServer::MasterServer(const std::string &luaScript)
|
||||
{
|
||||
peer = RakPeerInterface::GetInstance();
|
||||
sockdescr = SocketDescriptor(port, 0);
|
||||
peer->Startup(maxConnections, &sockdescr, 1, 1000);
|
||||
state.open_libraries();
|
||||
|
||||
peer->SetMaximumIncomingConnections(maxConnections);
|
||||
boost::filesystem::path absPath = boost::filesystem::absolute(luaScript);
|
||||
|
||||
std::string package_path = state["package"]["path"];
|
||||
state["package"]["path"] = Utils::convertPath(absPath.parent_path().string() + "/?.lua") + ";" + package_path;
|
||||
|
||||
state.set_function("BanAddress", &MasterServer::ban, this);
|
||||
state.set_function("UnbanAddress", &MasterServer::unban, this);
|
||||
|
||||
state.script_file(luaScript);
|
||||
|
||||
sol::table config = state["config"];
|
||||
|
||||
if (config.get_type() != sol::type::table)
|
||||
throw runtime_error("config is not correct");
|
||||
|
||||
sol::object maxConnections = config["maxConnections"];
|
||||
if (maxConnections.get_type() != sol::type::number)
|
||||
throw runtime_error("config.maxConnections is not correct");
|
||||
|
||||
sol::object port = config["port"];
|
||||
if (port.get_type() != sol::type::number)
|
||||
throw runtime_error("config.port is not correct");
|
||||
|
||||
state.new_usertype<MasterServer::SServer>("Server",
|
||||
"name", sol::property(&MasterServer::SServer::GetName),
|
||||
"gamemode", sol::property(&MasterServer::SServer::GetGameMode),
|
||||
"version", sol::property(&MasterServer::SServer::GetVersion)
|
||||
);
|
||||
|
||||
|
||||
peer = RakPeerInterface::GetInstance();
|
||||
sockdescr = SocketDescriptor(port.as<unsigned short>(), nullptr);
|
||||
peer->Startup(maxConnections.as<unsigned short>(), &sockdescr, 1, 1000);
|
||||
peer->SetLimitIPConnectionFrequency(true);
|
||||
|
||||
peer->SetMaximumIncomingConnections(maxConnections.as<unsigned short>());
|
||||
peer->SetIncomingPassword(TES3MP_MASTERSERVER_PASSW, (int) strlen(TES3MP_MASTERSERVER_PASSW));
|
||||
run = false;
|
||||
}
|
||||
|
@ -52,6 +87,13 @@ void MasterServer::Thread()
|
|||
PacketMasterAnnounce pma(peer);
|
||||
pma.SetSendStream(&send);
|
||||
|
||||
luaStuff([](sol::state &state) {
|
||||
sol::protected_function func = state["OnInit"];
|
||||
sol::protected_function_result result = func.call();
|
||||
if (!result.valid())
|
||||
cerr << "Error: " << result.get<string>() << endl;
|
||||
});
|
||||
|
||||
while (run)
|
||||
{
|
||||
Packet *packet = peer->Receive();
|
||||
|
@ -67,9 +109,9 @@ void MasterServer::Thread()
|
|||
servers.erase(it++);
|
||||
else ++it;
|
||||
}
|
||||
for(auto id = pendingACKs.begin(); id != pendingACKs.end();)
|
||||
for (auto id = pendingACKs.begin(); id != pendingACKs.end();)
|
||||
{
|
||||
if(now - id->second >= 30s)
|
||||
if (now - id->second >= 30s)
|
||||
{
|
||||
cout << "timeout: " << peer->GetSystemAddressFromGuid(id->first).ToString() << endl;
|
||||
peer->CloseConnection(id->first, true);
|
||||
|
@ -113,7 +155,7 @@ void MasterServer::Thread()
|
|||
SystemAddress addr;
|
||||
data.Read(addr); // update 1 server
|
||||
|
||||
ServerIter it = servers.find(addr);
|
||||
auto it = servers.find(addr);
|
||||
if (it != servers.end())
|
||||
{
|
||||
pair<SystemAddress, QueryData> pairPtr(it->first, static_cast<QueryData>(it->second));
|
||||
|
@ -127,7 +169,7 @@ void MasterServer::Thread()
|
|||
}
|
||||
case ID_MASTER_ANNOUNCE:
|
||||
{
|
||||
ServerIter iter = servers.find(packet->systemAddress);
|
||||
auto iter = servers.find(packet->systemAddress);
|
||||
|
||||
pma.SetReadStream(&data);
|
||||
SServer server;
|
||||
|
@ -141,6 +183,26 @@ void MasterServer::Thread()
|
|||
pendingACKs[packet->guid] = steady_clock::now();
|
||||
};
|
||||
|
||||
auto isServerValid = [&](const SServer &sserver) {
|
||||
bool ret = false;
|
||||
auto addr = packet->systemAddress.ToString(false);
|
||||
|
||||
lock_guard<mutex> lock(banMutex);
|
||||
|
||||
if (peer->IsBanned(addr)) // check if address is banned
|
||||
return false;
|
||||
|
||||
luaStuff([&ret, &packet, &sserver, &addr](sol::state &state) {
|
||||
sol::protected_function func = state["OnServerAnnounce"];
|
||||
sol::protected_function_result result = func.call(addr, sserver);
|
||||
if (result.valid())
|
||||
ret = result.get<bool>();
|
||||
else
|
||||
cerr << "Error: " << result.get<string>() << endl;
|
||||
});
|
||||
return ret;
|
||||
};
|
||||
|
||||
if (iter != servers.end())
|
||||
{
|
||||
if (pma.GetFunc() == PacketMasterAnnounce::FUNCTION_DELETE)
|
||||
|
@ -152,9 +214,19 @@ void MasterServer::Thread()
|
|||
}
|
||||
else if (pma.GetFunc() == PacketMasterAnnounce::FUNCTION_ANNOUNCE)
|
||||
{
|
||||
cout << "Updated";
|
||||
iter->second = server;
|
||||
keepAliveFunc();
|
||||
|
||||
if (isServerValid(server))
|
||||
{
|
||||
cout << "Updated";
|
||||
iter->second = server;
|
||||
keepAliveFunc();
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Update rejected";
|
||||
servers.erase(iter);
|
||||
pendingACKs.erase(packet->guid);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -164,9 +236,14 @@ void MasterServer::Thread()
|
|||
}
|
||||
else if (pma.GetFunc() == PacketMasterAnnounce::FUNCTION_ANNOUNCE)
|
||||
{
|
||||
cout << "Added";
|
||||
iter = servers.insert({packet->systemAddress, server}).first;
|
||||
keepAliveFunc();
|
||||
if (isServerValid(server))
|
||||
{
|
||||
cout << "Added";
|
||||
iter = servers.insert({packet->systemAddress, server}).first;
|
||||
keepAliveFunc();
|
||||
}
|
||||
else
|
||||
cout << "Adding rejected";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -186,7 +263,8 @@ void MasterServer::Thread()
|
|||
peer->CloseConnection(packet->systemAddress, true);
|
||||
break;
|
||||
default:
|
||||
cout << "Wrong packet. id " << (unsigned) packet->data[0] << " packet length " << packet->length << " from " << packet->systemAddress.ToString() << endl;
|
||||
cout << "Wrong packet. id " << (unsigned) packet->data[0] << " packet length "
|
||||
<< packet->length << " from " << packet->systemAddress.ToString() << endl;
|
||||
peer->CloseConnection(packet->systemAddress, true);
|
||||
}
|
||||
}
|
||||
|
@ -234,3 +312,22 @@ MasterServer::ServerMap *MasterServer::GetServers()
|
|||
{
|
||||
return &servers;
|
||||
}
|
||||
|
||||
|
||||
void MasterServer::luaStuff(std::function<void(sol::state &)> f)
|
||||
{
|
||||
lock_guard<mutex> lock(luaMutex);
|
||||
f(state);
|
||||
}
|
||||
|
||||
void MasterServer::ban(const std::string &addr)
|
||||
{
|
||||
lock_guard<mutex> lock(banMutex);
|
||||
peer->AddToBanList(addr.c_str());
|
||||
}
|
||||
|
||||
void MasterServer::unban(const std::string &addr)
|
||||
{
|
||||
lock_guard<mutex> lock(banMutex);
|
||||
peer->RemoveFromBanList(addr.c_str());
|
||||
}
|
||||
|
|
|
@ -9,18 +9,12 @@
|
|||
#include <chrono>
|
||||
#include <RakPeerInterface.h>
|
||||
#include <components/openmw-mp/Master/MasterData.hpp>
|
||||
#include <extern/sol/sol.hpp>
|
||||
#include <mutex>
|
||||
|
||||
class MasterServer
|
||||
{
|
||||
public:
|
||||
struct Ban
|
||||
{
|
||||
RakNet::SystemAddress sa;
|
||||
bool permanent;
|
||||
struct Date
|
||||
{
|
||||
} date;
|
||||
};
|
||||
struct SServer : QueryData
|
||||
{
|
||||
std::chrono::steady_clock::time_point lastUpdate;
|
||||
|
@ -29,7 +23,7 @@ public:
|
|||
//typedef ServerMap::const_iterator ServerCIter;
|
||||
typedef ServerMap::iterator ServerIter;
|
||||
|
||||
MasterServer(unsigned short maxConnections, unsigned short port);
|
||||
explicit MasterServer(const std::string &luaScript);
|
||||
~MasterServer();
|
||||
|
||||
void Start();
|
||||
|
@ -38,6 +32,10 @@ public:
|
|||
void Wait();
|
||||
|
||||
ServerMap* GetServers();
|
||||
void luaStuff(std::function<void(sol::state &)> f);
|
||||
|
||||
void ban(const std::string &addr);
|
||||
void unban(const std::string &addr);
|
||||
|
||||
private:
|
||||
void Thread();
|
||||
|
@ -49,6 +47,9 @@ private:
|
|||
ServerMap servers;
|
||||
bool run;
|
||||
std::map<RakNet::RakNetGUID, std::chrono::steady_clock::time_point> pendingACKs;
|
||||
sol::state state;
|
||||
std::mutex luaMutex;
|
||||
std::mutex banMutex;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -7,22 +7,12 @@
|
|||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
|
||||
#include "RestUtils.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace chrono;
|
||||
using namespace boost::property_tree;
|
||||
|
||||
static string response201 = "HTTP/1.1 201 Created\r\nContent-Length: 7\r\n\r\nCreated";
|
||||
static string response202 = "HTTP/1.1 202 Accepted\r\nContent-Length: 8\r\n\r\nAccepted";
|
||||
static string response400 = "HTTP/1.1 400 Bad Request\r\nContent-Length: 11\r\n\r\nbad request";
|
||||
|
||||
inline void ResponseStr(HttpServer::Response &response, string content, string type = "", string code = "200 OK")
|
||||
{
|
||||
response << "HTTP/1.1 " << code << "\r\n";
|
||||
if (!type.empty())
|
||||
response << "Content-Type: " << type <<"\r\n";
|
||||
response << "Content-Length: " << content.length() << "\r\n\r\n" << content;
|
||||
}
|
||||
|
||||
inline void ptreeToServer(boost::property_tree::ptree &pt, MasterServer::SServer &server)
|
||||
{
|
||||
server.SetName(pt.get<string>("hostname").c_str());
|
||||
|
@ -70,7 +60,7 @@ void RestServer::start()
|
|||
auto port = (unsigned short)stoi(&(addr[addr.find(':')+1]));
|
||||
queryToStringStream(ss, "server", serverMap->at(RakNet::SystemAddress(addr.c_str(), port)));
|
||||
ss << "}";
|
||||
ResponseStr(*response, ss.str(), "application/json");
|
||||
ResponseStr<SimpleWeb::HTTP>(response, ss.str(), "application/json");
|
||||
}
|
||||
catch(out_of_range e)
|
||||
{
|
||||
|
@ -93,7 +83,7 @@ void RestServer::start()
|
|||
ss << ", ";
|
||||
}
|
||||
ss << "}}";
|
||||
ResponseStr(*response, ss.str(), "application/json");
|
||||
ResponseStr<SimpleWeb::HTTP>(response, ss.str(), "application/json");
|
||||
updatedCache = false;
|
||||
}
|
||||
*response << str;
|
||||
|
@ -110,7 +100,7 @@ void RestServer::start()
|
|||
MasterServer::SServer server;
|
||||
ptreeToServer(pt, server);
|
||||
|
||||
unsigned short port = pt.get<unsigned short>("port");
|
||||
auto port = pt.get<unsigned short>("port");
|
||||
server.lastUpdate = steady_clock::now();
|
||||
serverMap->insert({RakNet::SystemAddress(request->remote_endpoint_address.c_str(), port), server});
|
||||
updatedCache = true;
|
||||
|
@ -137,7 +127,6 @@ void RestServer::start()
|
|||
*response << response400;
|
||||
return;
|
||||
}
|
||||
|
||||
if (request->content.size() != 0)
|
||||
{
|
||||
try
|
||||
|
@ -171,14 +160,14 @@ void RestServer::start()
|
|||
ss << ", \"players\": " << players;
|
||||
ss << "}";
|
||||
|
||||
ResponseStr(*response, ss.str(), "application/json");
|
||||
ResponseStr<SimpleWeb::HTTP>(response, ss.str(), "application/json");
|
||||
};
|
||||
|
||||
httpServer.default_resource["GET"]=[](auto response, auto /*request*/) {
|
||||
*response << response400;
|
||||
};
|
||||
|
||||
httpServer.start();
|
||||
thr = thread([this](){httpServer.start();});
|
||||
}
|
||||
|
||||
void RestServer::cacheUpdated()
|
||||
|
@ -189,4 +178,6 @@ void RestServer::cacheUpdated()
|
|||
void RestServer::stop()
|
||||
{
|
||||
httpServer.stop();
|
||||
if(thr.joinable())
|
||||
thr.join();
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ private:
|
|||
HttpServer httpServer;
|
||||
MasterServer::ServerMap *serverMap;
|
||||
bool updatedCache = true;
|
||||
std::thread thr;
|
||||
};
|
||||
|
||||
|
||||
|
|
25
apps/master/RestUtils.hpp
Normal file
25
apps/master/RestUtils.hpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
//
|
||||
// Created by koncord on 04.09.17.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "SimpleWeb/base_server.hpp"
|
||||
|
||||
static std::string response201 = "HTTP/1.1 201 Created\r\nContent-Length: 7\r\n\r\nCreated";
|
||||
static std::string response202 = "HTTP/1.1 202 Accepted\r\nContent-Length: 8\r\n\r\nAccepted";
|
||||
static std::string response400 = "HTTP/1.1 400 Bad Request\r\nContent-Length: 11\r\n\r\nbad request";
|
||||
|
||||
static std::string response403 = "HTTP/1.1 403 Forbidden\r\nContent-Length: 9\r\n\r\nForbidden";
|
||||
static std::string response500 = "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 21\r\n\r\nInternal Server Error";
|
||||
|
||||
template <class Protocol>
|
||||
inline void ResponseStr(std::shared_ptr<typename SimpleWeb::ServerBase<Protocol>::Response> response,
|
||||
std::string content, std::string type = "", std::string code = "200 OK")
|
||||
{
|
||||
*response << "HTTP/1.1 " << code << "\r\n";
|
||||
if (!type.empty())
|
||||
*response << "Content-Type: " << type <<"\r\n";
|
||||
*response << "Content-Length: " << content.length() << "\r\n\r\n" << content;
|
||||
}
|
21
apps/master/SimpleWeb/LICENSE
Normal file
21
apps/master/SimpleWeb/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2016 Ole Christian Eidheim
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -1,72 +1,137 @@
|
|||
#ifndef BASE_SERVER_HPP
|
||||
#define BASE_SERVER_HPP
|
||||
#pragma once
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <thread>
|
||||
#include "utility.hpp"
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <unordered_set>
|
||||
#include <regex>
|
||||
|
||||
#ifndef CASE_INSENSITIVE_EQUALS_AND_HASH
|
||||
#define CASE_INSENSITIVE_EQUALS_AND_HASH
|
||||
|
||||
//Based on http://www.boost.org/doc/libs/1_60_0/doc/html/unordered/hash_equality.html
|
||||
struct case_insensitive_equals
|
||||
{
|
||||
bool operator()(const std::string &key1, const std::string &key2) const
|
||||
{
|
||||
return boost::algorithm::iequals(key1, key2);
|
||||
}
|
||||
};
|
||||
|
||||
struct case_insensitive_hash
|
||||
{
|
||||
size_t operator()(const std::string &key) const
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
for (auto &c: key)
|
||||
boost::hash_combine(seed, std::tolower(c));
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef USE_STANDALONE_ASIO
|
||||
#include <asio.hpp>
|
||||
#include <asio/steady_timer.hpp>
|
||||
namespace SimpleWeb {
|
||||
using error_code = std::error_code;
|
||||
using errc = std::errc;
|
||||
namespace make_error_code = std;
|
||||
} // namespace SimpleWeb
|
||||
#else
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
namespace SimpleWeb {
|
||||
namespace asio = boost::asio;
|
||||
using error_code = boost::system::error_code;
|
||||
namespace errc = boost::system::errc;
|
||||
namespace make_error_code = boost::system::errc;
|
||||
} // namespace SimpleWeb
|
||||
#endif
|
||||
|
||||
namespace SimpleWeb
|
||||
{
|
||||
template<class socket_type>
|
||||
namespace SimpleWeb {
|
||||
template <class socket_type>
|
||||
class Server;
|
||||
|
||||
template<class socket_type>
|
||||
class ServerBase
|
||||
{
|
||||
template <class socket_type>
|
||||
class ServerBase {
|
||||
protected:
|
||||
class Session;
|
||||
|
||||
public:
|
||||
virtual ~ServerBase()
|
||||
{}
|
||||
|
||||
class Response : public std::ostream
|
||||
{
|
||||
class Response : public std::enable_shared_from_this<Response>, public std::ostream {
|
||||
friend class ServerBase<socket_type>;
|
||||
friend class Server<socket_type>;
|
||||
|
||||
boost::asio::streambuf streambuf;
|
||||
asio::streambuf streambuf;
|
||||
|
||||
std::shared_ptr<socket_type> socket;
|
||||
std::shared_ptr<Session> session;
|
||||
long timeout_content;
|
||||
|
||||
Response(const std::shared_ptr<socket_type> &socket) : std::ostream(&streambuf), socket(socket)
|
||||
{}
|
||||
Response(std::shared_ptr<Session> session, long timeout_content) noexcept : std::ostream(&streambuf), session(std::move(session)), timeout_content(timeout_content) {}
|
||||
|
||||
template <typename size_type>
|
||||
void write_header(const CaseInsensitiveMultimap &header, size_type size) {
|
||||
bool content_length_written = false;
|
||||
bool chunked_transfer_encoding = false;
|
||||
for(auto &field : header) {
|
||||
if(!content_length_written && case_insensitive_equal(field.first, "content-length"))
|
||||
content_length_written = true;
|
||||
else if(!chunked_transfer_encoding && case_insensitive_equal(field.first, "transfer-encoding") && case_insensitive_equal(field.second, "chunked"))
|
||||
chunked_transfer_encoding = true;
|
||||
|
||||
*this << field.first << ": " << field.second << "\r\n";
|
||||
}
|
||||
if(!content_length_written && !chunked_transfer_encoding && !close_connection_after_response)
|
||||
*this << "Content-Length: " << size << "\r\n\r\n";
|
||||
else
|
||||
*this << "\r\n";
|
||||
}
|
||||
|
||||
public:
|
||||
size_t size()
|
||||
{
|
||||
size_t size() noexcept {
|
||||
return streambuf.size();
|
||||
}
|
||||
|
||||
/// Use this function if you need to recursively send parts of a longer message
|
||||
void send(const std::function<void(const error_code &)> &callback = nullptr) noexcept {
|
||||
session->connection->set_timeout(timeout_content);
|
||||
auto self = this->shared_from_this(); // Keep Response instance alive through the following async_write
|
||||
asio::async_write(*session->connection->socket, streambuf, [self, callback](const error_code &ec, size_t /*bytes_transferred*/) {
|
||||
self->session->connection->cancel_timeout();
|
||||
auto lock = self->session->connection->handler_runner->continue_lock();
|
||||
if(!lock)
|
||||
return;
|
||||
if(callback)
|
||||
callback(ec);
|
||||
});
|
||||
}
|
||||
|
||||
/// Write directly to stream buffer using std::ostream::write
|
||||
void write(const char_type *ptr, std::streamsize n) {
|
||||
std::ostream::write(ptr, n);
|
||||
}
|
||||
|
||||
/// Convenience function for writing status line, potential header fields, and empty content
|
||||
void write(StatusCode status_code = StatusCode::success_ok, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
||||
*this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n";
|
||||
write_header(header, 0);
|
||||
}
|
||||
|
||||
/// Convenience function for writing status line, header fields, and content
|
||||
void write(StatusCode status_code, const std::string &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
||||
*this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n";
|
||||
write_header(header, content.size());
|
||||
if(!content.empty())
|
||||
*this << content;
|
||||
}
|
||||
|
||||
/// Convenience function for writing status line, header fields, and content
|
||||
void write(StatusCode status_code, std::istream &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
||||
*this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n";
|
||||
content.seekg(0, std::ios::end);
|
||||
auto size = content.tellg();
|
||||
content.seekg(0, std::ios::beg);
|
||||
write_header(header, size);
|
||||
if(size)
|
||||
*this << content.rdbuf();
|
||||
}
|
||||
|
||||
/// Convenience function for writing success status line, header fields, and content
|
||||
void write(const std::string &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
||||
write(StatusCode::success_ok, content, header);
|
||||
}
|
||||
|
||||
/// Convenience function for writing success status line, header fields, and content
|
||||
void write(std::istream &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
||||
write(StatusCode::success_ok, content, header);
|
||||
}
|
||||
|
||||
/// Convenience function for writing success status line, and header fields
|
||||
void write(const CaseInsensitiveMultimap &header) {
|
||||
write(StatusCode::success_ok, std::string(), header);
|
||||
}
|
||||
|
||||
/// If true, force server to close the connection after the response have been sent.
|
||||
///
|
||||
/// This is useful when implementing a HTTP/1.0-server sending content
|
||||
|
@ -74,438 +139,399 @@ namespace SimpleWeb
|
|||
bool close_connection_after_response = false;
|
||||
};
|
||||
|
||||
class Content : public std::istream
|
||||
{
|
||||
class Content : public std::istream {
|
||||
friend class ServerBase<socket_type>;
|
||||
|
||||
public:
|
||||
size_t size()
|
||||
{
|
||||
size_t size() noexcept {
|
||||
return streambuf.size();
|
||||
}
|
||||
|
||||
std::string string()
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << rdbuf();
|
||||
return ss.str();
|
||||
/// Convenience function to return std::string. The stream buffer is consumed.
|
||||
std::string string() noexcept {
|
||||
try {
|
||||
std::stringstream ss;
|
||||
ss << rdbuf();
|
||||
return ss.str();
|
||||
}
|
||||
catch(...) {
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
boost::asio::streambuf &streambuf;
|
||||
|
||||
Content(boost::asio::streambuf &streambuf) : std::istream(&streambuf), streambuf(streambuf)
|
||||
{}
|
||||
asio::streambuf &streambuf;
|
||||
Content(asio::streambuf &streambuf) noexcept : std::istream(&streambuf), streambuf(streambuf) {}
|
||||
};
|
||||
|
||||
class Request
|
||||
{
|
||||
class Request {
|
||||
friend class ServerBase<socket_type>;
|
||||
|
||||
friend class Server<socket_type>;
|
||||
friend class Session;
|
||||
|
||||
public:
|
||||
std::string method, path, http_version;
|
||||
std::string method, path, query_string, http_version;
|
||||
|
||||
Content content;
|
||||
|
||||
std::unordered_multimap<std::string, std::string, case_insensitive_hash, case_insensitive_equals> header;
|
||||
CaseInsensitiveMultimap header;
|
||||
|
||||
std::smatch path_match;
|
||||
|
||||
std::string remote_endpoint_address;
|
||||
unsigned short remote_endpoint_port;
|
||||
|
||||
private:
|
||||
Request(const socket_type &socket) : content(streambuf)
|
||||
{
|
||||
try
|
||||
{
|
||||
remote_endpoint_address = socket.lowest_layer().remote_endpoint().address().to_string();
|
||||
remote_endpoint_port = socket.lowest_layer().remote_endpoint().port();
|
||||
}
|
||||
catch (...)
|
||||
{}
|
||||
/// Returns query keys with percent-decoded values.
|
||||
CaseInsensitiveMultimap parse_query_string() noexcept {
|
||||
return SimpleWeb::QueryString::parse(query_string);
|
||||
}
|
||||
|
||||
boost::asio::streambuf streambuf;
|
||||
private:
|
||||
asio::streambuf streambuf;
|
||||
|
||||
Request(const std::string &remote_endpoint_address = std::string(), unsigned short remote_endpoint_port = 0) noexcept
|
||||
: content(streambuf), remote_endpoint_address(remote_endpoint_address), remote_endpoint_port(remote_endpoint_port) {}
|
||||
};
|
||||
|
||||
class Config
|
||||
{
|
||||
protected:
|
||||
class Connection : public std::enable_shared_from_this<Connection> {
|
||||
public:
|
||||
template <typename... Args>
|
||||
Connection(std::shared_ptr<ScopeRunner> handler_runner, Args &&... args) noexcept : handler_runner(std::move(handler_runner)), socket(new socket_type(std::forward<Args>(args)...)) {}
|
||||
|
||||
std::shared_ptr<ScopeRunner> handler_runner;
|
||||
|
||||
std::unique_ptr<socket_type> socket; // Socket must be unique_ptr since asio::ssl::stream<asio::ip::tcp::socket> is not movable
|
||||
std::mutex socket_close_mutex;
|
||||
|
||||
std::unique_ptr<asio::steady_timer> timer;
|
||||
|
||||
void close() noexcept {
|
||||
error_code ec;
|
||||
std::unique_lock<std::mutex> lock(socket_close_mutex); // The following operations seems to be needed to run sequentially
|
||||
socket->lowest_layer().shutdown(asio::ip::tcp::socket::shutdown_both, ec);
|
||||
socket->lowest_layer().close(ec);
|
||||
}
|
||||
|
||||
void set_timeout(long seconds) noexcept {
|
||||
if(seconds == 0) {
|
||||
timer = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
timer = std::unique_ptr<asio::steady_timer>(new asio::steady_timer(socket->get_io_service()));
|
||||
timer->expires_from_now(std::chrono::seconds(seconds));
|
||||
auto self = this->shared_from_this();
|
||||
timer->async_wait([self](const error_code &ec) {
|
||||
if(!ec)
|
||||
self->close();
|
||||
});
|
||||
}
|
||||
|
||||
void cancel_timeout() noexcept {
|
||||
if(timer) {
|
||||
error_code ec;
|
||||
timer->cancel(ec);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Session {
|
||||
public:
|
||||
Session(std::shared_ptr<Connection> connection) noexcept : connection(std::move(connection)) {
|
||||
try {
|
||||
auto remote_endpoint = this->connection->socket->lowest_layer().remote_endpoint();
|
||||
request = std::shared_ptr<Request>(new Request(remote_endpoint.address().to_string(), remote_endpoint.port()));
|
||||
}
|
||||
catch(...) {
|
||||
request = std::shared_ptr<Request>(new Request());
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Connection> connection;
|
||||
std::shared_ptr<Request> request;
|
||||
};
|
||||
|
||||
public:
|
||||
class Config {
|
||||
friend class ServerBase<socket_type>;
|
||||
|
||||
Config(unsigned short port) : port(port)
|
||||
{}
|
||||
Config(unsigned short port) noexcept : port(port) {}
|
||||
|
||||
public:
|
||||
/// Port number to use. Defaults to 80 for HTTP and 443 for HTTPS.
|
||||
unsigned short port;
|
||||
/// Number of threads that the server will use when start() is called. Defaults to 1 thread.
|
||||
/// If io_service is not set, number of threads that the server will use when start() is called.
|
||||
/// Defaults to 1 thread.
|
||||
size_t thread_pool_size = 1;
|
||||
/// Timeout on request handling. Defaults to 5 seconds.
|
||||
size_t timeout_request = 5;
|
||||
long timeout_request = 5;
|
||||
/// Timeout on content handling. Defaults to 300 seconds.
|
||||
size_t timeout_content = 300;
|
||||
long timeout_content = 300;
|
||||
/// IPv4 address in dotted decimal form or IPv6 address in hexadecimal notation.
|
||||
/// If empty, the address will be any address.
|
||||
std::string address;
|
||||
/// Set to false to avoid binding the socket to an address that is already in use. Defaults to true.
|
||||
bool reuse_address = true;
|
||||
};
|
||||
|
||||
///Set before calling start().
|
||||
/// Set before calling start().
|
||||
Config config;
|
||||
|
||||
private:
|
||||
class regex_orderable : public std::regex
|
||||
{
|
||||
class regex_orderable : public std::regex {
|
||||
std::string str;
|
||||
|
||||
public:
|
||||
regex_orderable(const char *regex_cstr) : std::regex(regex_cstr), str(regex_cstr)
|
||||
{}
|
||||
|
||||
regex_orderable(const std::string ®ex_str) : std::regex(regex_str), str(regex_str)
|
||||
{}
|
||||
|
||||
bool operator<(const regex_orderable &rhs) const
|
||||
{
|
||||
regex_orderable(const char *regex_cstr) : std::regex(regex_cstr), str(regex_cstr) {}
|
||||
regex_orderable(std::string regex_str) : std::regex(regex_str), str(std::move(regex_str)) {}
|
||||
bool operator<(const regex_orderable &rhs) const noexcept {
|
||||
return str < rhs.str;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
/// Warning: do not add or remove resources after start() is called
|
||||
std::map<regex_orderable, std::map<std::string,
|
||||
std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>,
|
||||
std::shared_ptr<typename ServerBase<socket_type>::Request>)>>>
|
||||
resource;
|
||||
std::map<regex_orderable, std::map<std::string, std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::shared_ptr<typename ServerBase<socket_type>::Request>)>>> resource;
|
||||
|
||||
std::map<std::string,
|
||||
std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>,
|
||||
std::shared_ptr<typename ServerBase<socket_type>::Request>)>> default_resource;
|
||||
std::map<std::string, std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::shared_ptr<typename ServerBase<socket_type>::Request>)>> default_resource;
|
||||
|
||||
std::function<
|
||||
void(std::shared_ptr<typename ServerBase<socket_type>::Request>,
|
||||
const boost::system::error_code &)>
|
||||
on_error;
|
||||
std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Request>, const error_code &)> on_error;
|
||||
|
||||
std::function<void(std::shared_ptr<socket_type> socket,
|
||||
std::shared_ptr<typename ServerBase<socket_type>::Request>)> on_upgrade;
|
||||
std::function<void(std::unique_ptr<socket_type> &, std::shared_ptr<typename ServerBase<socket_type>::Request>)> on_upgrade;
|
||||
|
||||
virtual void start()
|
||||
{
|
||||
if (!io_service)
|
||||
io_service = std::make_shared<boost::asio::io_service>();
|
||||
/// If you have your own asio::io_service, store its pointer here before running start().
|
||||
std::shared_ptr<asio::io_service> io_service;
|
||||
|
||||
if (io_service->stopped())
|
||||
virtual void start() {
|
||||
if(!io_service) {
|
||||
io_service = std::make_shared<asio::io_service>();
|
||||
internal_io_service = true;
|
||||
}
|
||||
|
||||
if(io_service->stopped())
|
||||
io_service->reset();
|
||||
|
||||
boost::asio::ip::tcp::endpoint endpoint;
|
||||
if (config.address.size() > 0)
|
||||
endpoint = boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string(config.address),
|
||||
config.port);
|
||||
asio::ip::tcp::endpoint endpoint;
|
||||
if(config.address.size() > 0)
|
||||
endpoint = asio::ip::tcp::endpoint(asio::ip::address::from_string(config.address), config.port);
|
||||
else
|
||||
endpoint = boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), config.port);
|
||||
endpoint = asio::ip::tcp::endpoint(asio::ip::tcp::v4(), config.port);
|
||||
|
||||
if (!acceptor)
|
||||
acceptor = std::unique_ptr<boost::asio::ip::tcp::acceptor>(
|
||||
new boost::asio::ip::tcp::acceptor(*io_service));
|
||||
if(!acceptor)
|
||||
acceptor = std::unique_ptr<asio::ip::tcp::acceptor>(new asio::ip::tcp::acceptor(*io_service));
|
||||
acceptor->open(endpoint.protocol());
|
||||
acceptor->set_option(boost::asio::socket_base::reuse_address(config.reuse_address));
|
||||
acceptor->set_option(asio::socket_base::reuse_address(config.reuse_address));
|
||||
acceptor->bind(endpoint);
|
||||
acceptor->listen();
|
||||
|
||||
accept();
|
||||
|
||||
//If thread_pool_size>1, start m_io_service.run() in (thread_pool_size-1) threads for thread-pooling
|
||||
threads.clear();
|
||||
for (size_t c = 1; c < config.thread_pool_size; c++)
|
||||
{
|
||||
threads.emplace_back([this]()
|
||||
{
|
||||
io_service->run();
|
||||
});
|
||||
}
|
||||
if(internal_io_service) {
|
||||
// If thread_pool_size>1, start m_io_service.run() in (thread_pool_size-1) threads for thread-pooling
|
||||
threads.clear();
|
||||
for(size_t c = 1; c < config.thread_pool_size; c++) {
|
||||
threads.emplace_back([this]() {
|
||||
this->io_service->run();
|
||||
});
|
||||
}
|
||||
|
||||
//Main thread
|
||||
if (config.thread_pool_size > 0)
|
||||
io_service->run();
|
||||
// Main thread
|
||||
if(config.thread_pool_size > 0)
|
||||
io_service->run();
|
||||
|
||||
//Wait for the rest of the threads, if any, to finish as well
|
||||
for (auto &t: threads)
|
||||
{
|
||||
t.join();
|
||||
// Wait for the rest of the threads, if any, to finish as well
|
||||
for(auto &t : threads)
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
acceptor->close();
|
||||
if (config.thread_pool_size > 0)
|
||||
io_service->stop();
|
||||
/// Stop accepting new requests, and close current connections.
|
||||
void stop() noexcept {
|
||||
if(acceptor) {
|
||||
error_code ec;
|
||||
acceptor->close(ec);
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(*connections_mutex);
|
||||
for(auto &connection : *connections)
|
||||
connection->close();
|
||||
connections->clear();
|
||||
}
|
||||
|
||||
if(internal_io_service)
|
||||
io_service->stop();
|
||||
}
|
||||
}
|
||||
|
||||
///Use this function if you need to recursively send parts of a longer message
|
||||
void send(const std::shared_ptr<Response> &response,
|
||||
const std::function<void(const boost::system::error_code &)> &callback = nullptr) const
|
||||
{
|
||||
boost::asio::async_write(*response->socket, response->streambuf, [this, response, callback]
|
||||
(const boost::system::error_code &ec, size_t /*bytes_transferred*/)
|
||||
{
|
||||
if (callback)
|
||||
callback(ec);
|
||||
});
|
||||
virtual ~ServerBase() noexcept {
|
||||
handler_runner->stop();
|
||||
stop();
|
||||
}
|
||||
|
||||
/// If you have your own boost::asio::io_service, store its pointer here before running start().
|
||||
/// You might also want to set config.thread_pool_size to 0.
|
||||
std::shared_ptr<boost::asio::io_service> io_service;
|
||||
protected:
|
||||
std::unique_ptr<boost::asio::ip::tcp::acceptor> acceptor;
|
||||
bool internal_io_service = false;
|
||||
|
||||
std::unique_ptr<asio::ip::tcp::acceptor> acceptor;
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
ServerBase(unsigned short port) : config(port)
|
||||
{}
|
||||
std::shared_ptr<std::unordered_set<Connection *>> connections;
|
||||
std::shared_ptr<std::mutex> connections_mutex;
|
||||
|
||||
virtual void accept()=0;
|
||||
std::shared_ptr<ScopeRunner> handler_runner;
|
||||
|
||||
std::shared_ptr<boost::asio::deadline_timer>
|
||||
get_timeout_timer(const std::shared_ptr<socket_type> &socket, long seconds)
|
||||
{
|
||||
if (seconds == 0)
|
||||
return nullptr;
|
||||
ServerBase(unsigned short port) noexcept : config(port), connections(new std::unordered_set<Connection *>()), connections_mutex(new std::mutex()), handler_runner(new ScopeRunner()) {}
|
||||
|
||||
auto timer = std::make_shared<boost::asio::deadline_timer>(*io_service);
|
||||
timer->expires_from_now(boost::posix_time::seconds(seconds));
|
||||
timer->async_wait([socket](const boost::system::error_code &ec)
|
||||
{
|
||||
if (!ec)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
socket->lowest_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
|
||||
socket->lowest_layer().close();
|
||||
}
|
||||
});
|
||||
return timer;
|
||||
virtual void accept() = 0;
|
||||
|
||||
template <typename... Args>
|
||||
std::shared_ptr<Connection> create_connection(Args &&... args) noexcept {
|
||||
auto connections = this->connections;
|
||||
auto connections_mutex = this->connections_mutex;
|
||||
auto connection = std::shared_ptr<Connection>(new Connection(handler_runner, std::forward<Args>(args)...), [connections, connections_mutex](Connection *connection) {
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(*connections_mutex);
|
||||
auto it = connections->find(connection);
|
||||
if(it != connections->end())
|
||||
connections->erase(it);
|
||||
}
|
||||
delete connection;
|
||||
});
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(*connections_mutex);
|
||||
connections->emplace(connection.get());
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
void read_request_and_content(const std::shared_ptr<socket_type> &socket)
|
||||
{
|
||||
//Create new streambuf (Request::streambuf) for async_read_until()
|
||||
//shared_ptr is used to pass temporary objects to the asynchronous functions
|
||||
std::shared_ptr<Request> request(new Request(*socket));
|
||||
void read_request_and_content(const std::shared_ptr<Session> &session) {
|
||||
session->connection->set_timeout(config.timeout_request);
|
||||
asio::async_read_until(*session->connection->socket, session->request->streambuf, "\r\n\r\n", [this, session](const error_code &ec, size_t bytes_transferred) {
|
||||
session->connection->cancel_timeout();
|
||||
auto lock = session->connection->handler_runner->continue_lock();
|
||||
if(!lock)
|
||||
return;
|
||||
if(!ec) {
|
||||
// request->streambuf.size() is not necessarily the same as bytes_transferred, from Boost-docs:
|
||||
// "After a successful async_read_until operation, the streambuf may contain additional data beyond the delimiter"
|
||||
// The chosen solution is to extract lines from the stream directly when parsing the header. What is left of the
|
||||
// streambuf (maybe some bytes of the content) is appended to in the async_read-function below (for retrieving content).
|
||||
size_t num_additional_bytes = session->request->streambuf.size() - bytes_transferred;
|
||||
|
||||
//Set timeout on the following boost::asio::async-read or write function
|
||||
auto timer = this->get_timeout_timer(socket, config.timeout_request);
|
||||
|
||||
boost::asio::async_read_until(*socket, request->streambuf, "\r\n\r\n", [this, socket, request, timer]
|
||||
(const boost::system::error_code &ec,
|
||||
size_t bytes_transferred)
|
||||
{
|
||||
if (timer)
|
||||
timer->cancel();
|
||||
if (!ec)
|
||||
{
|
||||
//request->streambuf.size() is not necessarily the same as bytes_transferred, from Boost-docs:
|
||||
//"After a successful async_read_until operation, the streambuf may contain additional data beyond the delimiter"
|
||||
//The chosen solution is to extract lines from the stream directly when parsing the header. What is left of the
|
||||
//streambuf (maybe some bytes of the content) is appended to in the async_read-function below (for retrieving content).
|
||||
size_t num_additional_bytes =
|
||||
request->streambuf.size() - bytes_transferred;
|
||||
|
||||
if (!this->parse_request(request))
|
||||
if(!RequestMessage::parse(session->request->content, session->request->method, session->request->path,
|
||||
session->request->query_string, session->request->http_version, session->request->header)) {
|
||||
if(this->on_error)
|
||||
this->on_error(session->request, make_error_code::make_error_code(errc::protocol_error));
|
||||
return;
|
||||
}
|
||||
|
||||
//If content, read that as well
|
||||
auto it = request->header.find("Content-Length");
|
||||
if (it != request->header.end())
|
||||
{
|
||||
unsigned long long content_length;
|
||||
try
|
||||
{
|
||||
// If content, read that as well
|
||||
auto it = session->request->header.find("Content-Length");
|
||||
if(it != session->request->header.end()) {
|
||||
unsigned long long content_length = 0;
|
||||
try {
|
||||
content_length = stoull(it->second);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
if (on_error)
|
||||
on_error(request, boost::system::error_code(
|
||||
boost::system::errc::protocol_error,
|
||||
boost::system::generic_category()));
|
||||
catch(const std::exception &e) {
|
||||
if(this->on_error)
|
||||
this->on_error(session->request, make_error_code::make_error_code(errc::protocol_error));
|
||||
return;
|
||||
}
|
||||
if (content_length > num_additional_bytes)
|
||||
{
|
||||
//Set timeout on the following boost::asio::async-read or write function
|
||||
auto timer = this->get_timeout_timer(socket,
|
||||
config.timeout_content);
|
||||
boost::asio::async_read(*socket, request->streambuf,
|
||||
boost::asio::transfer_exactly(
|
||||
content_length -
|
||||
num_additional_bytes),
|
||||
[this, socket, request, timer]
|
||||
(const boost::system::error_code &ec,
|
||||
size_t /*bytes_transferred*/)
|
||||
{
|
||||
if (timer)
|
||||
timer->cancel();
|
||||
if (!ec)
|
||||
this->find_resource(socket,
|
||||
request);
|
||||
else if (on_error)
|
||||
on_error(request, ec);
|
||||
});
|
||||
if(content_length > num_additional_bytes) {
|
||||
session->connection->set_timeout(config.timeout_content);
|
||||
asio::async_read(*session->connection->socket, session->request->streambuf, asio::transfer_exactly(content_length - num_additional_bytes), [this, session](const error_code &ec, size_t /*bytes_transferred*/) {
|
||||
session->connection->cancel_timeout();
|
||||
auto lock = session->connection->handler_runner->continue_lock();
|
||||
if(!lock)
|
||||
return;
|
||||
if(!ec)
|
||||
this->find_resource(session);
|
||||
else if(this->on_error)
|
||||
this->on_error(session->request, ec);
|
||||
});
|
||||
}
|
||||
else
|
||||
this->find_resource(socket, request);
|
||||
this->find_resource(session);
|
||||
}
|
||||
else
|
||||
this->find_resource(socket, request);
|
||||
this->find_resource(session);
|
||||
}
|
||||
else if (on_error)
|
||||
on_error(request, ec);
|
||||
else if(this->on_error)
|
||||
this->on_error(session->request, ec);
|
||||
});
|
||||
}
|
||||
|
||||
bool parse_request(const std::shared_ptr<Request> &request) const
|
||||
{
|
||||
std::string line;
|
||||
getline(request->content, line);
|
||||
size_t method_end;
|
||||
if ((method_end = line.find(' ')) != std::string::npos)
|
||||
{
|
||||
size_t path_end;
|
||||
if ((path_end = line.find(' ', method_end + 1)) != std::string::npos)
|
||||
{
|
||||
request->method = line.substr(0, method_end);
|
||||
request->path = line.substr(method_end + 1, path_end - method_end - 1);
|
||||
|
||||
size_t protocol_end;
|
||||
if ((protocol_end = line.find('/', path_end + 1)) != std::string::npos)
|
||||
void find_resource(const std::shared_ptr<Session> &session) {
|
||||
// Upgrade connection
|
||||
if(on_upgrade) {
|
||||
auto it = session->request->header.find("Upgrade");
|
||||
if(it != session->request->header.end()) {
|
||||
// remove connection from connections
|
||||
{
|
||||
if (line.compare(path_end + 1, protocol_end - path_end - 1, "HTTP") != 0)
|
||||
return false;
|
||||
request->http_version = line.substr(protocol_end + 1, line.size() - protocol_end - 2);
|
||||
std::unique_lock<std::mutex> lock(*connections_mutex);
|
||||
auto it = connections->find(session->connection.get());
|
||||
if(it != connections->end())
|
||||
connections->erase(it);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
getline(request->content, line);
|
||||
size_t param_end;
|
||||
while ((param_end = line.find(':')) != std::string::npos)
|
||||
{
|
||||
size_t value_start = param_end + 1;
|
||||
if ((value_start) < line.size())
|
||||
{
|
||||
if (line[value_start] == ' ')
|
||||
value_start++;
|
||||
if (value_start < line.size())
|
||||
request->header.emplace(line.substr(0, param_end),
|
||||
line.substr(value_start, line.size() - value_start - 1));
|
||||
}
|
||||
|
||||
getline(request->content, line);
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void find_resource(const std::shared_ptr<socket_type> &socket, const std::shared_ptr<Request> &request)
|
||||
{
|
||||
//Upgrade connection
|
||||
if (on_upgrade)
|
||||
{
|
||||
auto it = request->header.find("Upgrade");
|
||||
if (it != request->header.end())
|
||||
{
|
||||
on_upgrade(socket, request);
|
||||
on_upgrade(session->connection->socket, session->request);
|
||||
return;
|
||||
}
|
||||
}
|
||||
//Find path- and method-match, and call write_response
|
||||
for (auto ®ex_method: resource)
|
||||
{
|
||||
auto it = regex_method.second.find(request->method);
|
||||
if (it != regex_method.second.end())
|
||||
{
|
||||
// Find path- and method-match, and call write_response
|
||||
for(auto ®ex_method : resource) {
|
||||
auto it = regex_method.second.find(session->request->method);
|
||||
if(it != regex_method.second.end()) {
|
||||
std::smatch sm_res;
|
||||
if (std::regex_match(request->path, sm_res, regex_method.first))
|
||||
{
|
||||
request->path_match = std::move(sm_res);
|
||||
write_response(socket, request, it->second);
|
||||
if(std::regex_match(session->request->path, sm_res, regex_method.first)) {
|
||||
session->request->path_match = std::move(sm_res);
|
||||
write_response(session, it->second);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto it = default_resource.find(request->method);
|
||||
if (it != default_resource.end())
|
||||
{
|
||||
write_response(socket, request, it->second);
|
||||
}
|
||||
auto it = default_resource.find(session->request->method);
|
||||
if(it != default_resource.end())
|
||||
write_response(session, it->second);
|
||||
}
|
||||
|
||||
void write_response(const std::shared_ptr<socket_type> &socket, const std::shared_ptr<Request> &request,
|
||||
std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>,
|
||||
std::shared_ptr<
|
||||
typename ServerBase<socket_type>::Request>)> &resource_function)
|
||||
{
|
||||
//Set timeout on the following boost::asio::async-read or write function
|
||||
auto timer = this->get_timeout_timer(socket, config.timeout_content);
|
||||
|
||||
auto response = std::shared_ptr<Response>(new Response(socket), [this, request, timer]
|
||||
(Response *response_ptr)
|
||||
{
|
||||
void write_response(const std::shared_ptr<Session> &session,
|
||||
std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::shared_ptr<typename ServerBase<socket_type>::Request>)> &resource_function) {
|
||||
session->connection->set_timeout(config.timeout_content);
|
||||
auto response = std::shared_ptr<Response>(new Response(session, config.timeout_content), [this](Response *response_ptr) {
|
||||
auto response = std::shared_ptr<Response>(response_ptr);
|
||||
this->send(response, [this, response, request, timer](
|
||||
const boost::system::error_code &ec)
|
||||
{
|
||||
if (timer)
|
||||
timer->cancel();
|
||||
if (!ec)
|
||||
{
|
||||
if (response->close_connection_after_response)
|
||||
response->send([this, response](const error_code &ec) {
|
||||
if(!ec) {
|
||||
if(response->close_connection_after_response)
|
||||
return;
|
||||
|
||||
auto range = request->header.equal_range(
|
||||
"Connection");
|
||||
for (auto it = range.first; it != range.second; it++)
|
||||
{
|
||||
if (boost::iequals(it->second, "close"))
|
||||
{
|
||||
auto range = response->session->request->header.equal_range("Connection");
|
||||
for(auto it = range.first; it != range.second; it++) {
|
||||
if(case_insensitive_equal(it->second, "close"))
|
||||
return;
|
||||
}
|
||||
else if (boost::iequals(it->second, "keep-alive"))
|
||||
{
|
||||
this->read_request_and_content(
|
||||
response->socket);
|
||||
else if(case_insensitive_equal(it->second, "keep-alive")) {
|
||||
auto new_session = std::make_shared<Session>(response->session->connection);
|
||||
this->read_request_and_content(new_session);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (request->http_version >= "1.1")
|
||||
this->read_request_and_content(response->socket);
|
||||
if(response->session->request->http_version >= "1.1") {
|
||||
auto new_session = std::make_shared<Session>(response->session->connection);
|
||||
this->read_request_and_content(new_session);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (on_error)
|
||||
on_error(request, ec);
|
||||
else if(this->on_error)
|
||||
this->on_error(response->session->request, ec);
|
||||
});
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
resource_function(response, request);
|
||||
try {
|
||||
resource_function(response, session->request);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
if (on_error)
|
||||
on_error(request, boost::system::error_code(boost::system::errc::operation_canceled,
|
||||
boost::system::generic_category()));
|
||||
catch(const std::exception &e) {
|
||||
if(on_error)
|
||||
on_error(session->request, make_error_code::make_error_code(errc::operation_canceled));
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif //BASE_SERVER_HPP
|
||||
}
|
|
@ -1,55 +1,42 @@
|
|||
/*
|
||||
* https://github.com/eidheim/Simple-Web-Server/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
* Copyright (c) 2014-2016 Ole Christian Eidheim
|
||||
*/
|
||||
|
||||
#ifndef SERVER_HTTP_HPP
|
||||
#define SERVER_HTTP_HPP
|
||||
#pragma once
|
||||
|
||||
#include "base_server.hpp"
|
||||
|
||||
namespace SimpleWeb
|
||||
{
|
||||
namespace SimpleWeb {
|
||||
|
||||
template<class socket_type>
|
||||
template <class socket_type>
|
||||
class Server : public ServerBase<socket_type> {};
|
||||
|
||||
typedef boost::asio::ip::tcp::socket HTTP;
|
||||
using HTTP = asio::ip::tcp::socket;
|
||||
|
||||
template<>
|
||||
class Server<HTTP> : public ServerBase<HTTP>
|
||||
{
|
||||
template <>
|
||||
class Server<HTTP> : public ServerBase<HTTP> {
|
||||
public:
|
||||
Server() : ServerBase<HTTP>::ServerBase(80)
|
||||
{}
|
||||
Server() noexcept : ServerBase<HTTP>::ServerBase(80) {}
|
||||
|
||||
protected:
|
||||
virtual void accept()
|
||||
{
|
||||
//Create new socket for this connection
|
||||
//Shared_ptr is used to pass temporary objects to the asynchronous functions
|
||||
auto socket = std::make_shared<HTTP>(*io_service);
|
||||
void accept() override {
|
||||
auto session = std::make_shared<Session>(create_connection(*io_service));
|
||||
|
||||
acceptor->async_accept(*socket, [this, socket](const boost::system::error_code &ec)
|
||||
{
|
||||
//Immediately start accepting a new connection (if io_service hasn't been stopped)
|
||||
if (ec != boost::asio::error::operation_aborted)
|
||||
accept();
|
||||
acceptor->async_accept(*session->connection->socket, [this, session](const error_code &ec) {
|
||||
auto lock = session->connection->handler_runner->continue_lock();
|
||||
if(!lock)
|
||||
return;
|
||||
|
||||
if (!ec)
|
||||
{
|
||||
boost::asio::ip::tcp::no_delay option(true);
|
||||
socket->set_option(option);
|
||||
// Immediately start accepting a new connection (unless io_service has been stopped)
|
||||
if(ec != asio::error::operation_aborted)
|
||||
this->accept();
|
||||
|
||||
this->read_request_and_content(socket);
|
||||
if(!ec) {
|
||||
asio::ip::tcp::no_delay option(true);
|
||||
error_code ec;
|
||||
session->connection->socket->set_option(option, ec);
|
||||
|
||||
this->read_request_and_content(session);
|
||||
}
|
||||
else if (on_error)
|
||||
on_error(std::shared_ptr<Request>(new Request(*socket)), ec);
|
||||
else if(this->on_error)
|
||||
this->on_error(session->request, ec);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif //SERVER_HTTP_HPP
|
||||
} // namespace SimpleWeb
|
||||
|
|
|
@ -1,91 +1,82 @@
|
|||
#ifndef HTTPS_SERVER_HPP
|
||||
#define HTTPS_SERVER_HPP
|
||||
#pragma once
|
||||
|
||||
#include "base_server.hpp"
|
||||
|
||||
#ifdef USE_STANDALONE_ASIO
|
||||
#include <asio/ssl.hpp>
|
||||
#else
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <openssl/ssl.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
namespace SimpleWeb
|
||||
{
|
||||
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> HTTPS;
|
||||
namespace SimpleWeb {
|
||||
using HTTPS = asio::ssl::stream<asio::ip::tcp::socket>;
|
||||
|
||||
template<>
|
||||
class Server<HTTPS> : public ServerBase<HTTPS>
|
||||
{
|
||||
template <>
|
||||
class Server<HTTPS> : public ServerBase<HTTPS> {
|
||||
std::string session_id_context;
|
||||
bool set_session_id_context = false;
|
||||
public:
|
||||
Server(const std::string &cert_file, const std::string &private_key_file,
|
||||
const std::string &verify_file = std::string()) : ServerBase<HTTPS>::ServerBase(443),
|
||||
context(boost::asio::ssl::context::tlsv12)
|
||||
{
|
||||
context.use_certificate_chain_file(cert_file);
|
||||
context.use_private_key_file(private_key_file, boost::asio::ssl::context::pem);
|
||||
|
||||
if (verify_file.size() > 0)
|
||||
{
|
||||
public:
|
||||
Server(const std::string &cert_file, const std::string &private_key_file, const std::string &verify_file = std::string())
|
||||
: ServerBase<HTTPS>::ServerBase(443), context(asio::ssl::context::tlsv12) {
|
||||
context.use_certificate_chain_file(cert_file);
|
||||
context.use_private_key_file(private_key_file, asio::ssl::context::pem);
|
||||
|
||||
if(verify_file.size() > 0) {
|
||||
context.load_verify_file(verify_file);
|
||||
context.set_verify_mode(boost::asio::ssl::verify_peer | boost::asio::ssl::verify_fail_if_no_peer_cert |
|
||||
boost::asio::ssl::verify_client_once);
|
||||
context.set_verify_mode(asio::ssl::verify_peer | asio::ssl::verify_fail_if_no_peer_cert | asio::ssl::verify_client_once);
|
||||
set_session_id_context = true;
|
||||
}
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
if (set_session_id_context)
|
||||
{
|
||||
void start() override {
|
||||
if(set_session_id_context) {
|
||||
// Creating session_id_context from address:port but reversed due to small SSL_MAX_SSL_SESSION_ID_LENGTH
|
||||
session_id_context = std::to_string(config.port) + ':';
|
||||
session_id_context.append(config.address.rbegin(), config.address.rend());
|
||||
SSL_CTX_set_session_id_context(context.native_handle(),
|
||||
reinterpret_cast<const unsigned char *>(session_id_context.data()),
|
||||
std::min<size_t>(session_id_context.size(),
|
||||
SSL_MAX_SSL_SESSION_ID_LENGTH));
|
||||
SSL_CTX_set_session_id_context(context.native_handle(), reinterpret_cast<const unsigned char *>(session_id_context.data()),
|
||||
std::min<size_t>(session_id_context.size(), SSL_MAX_SSL_SESSION_ID_LENGTH));
|
||||
}
|
||||
ServerBase::start();
|
||||
}
|
||||
|
||||
protected:
|
||||
boost::asio::ssl::context context;
|
||||
asio::ssl::context context;
|
||||
|
||||
virtual void accept()
|
||||
{
|
||||
//Create new socket for this connection
|
||||
//Shared_ptr is used to pass temporary objects to the asynchronous functions
|
||||
auto socket = std::make_shared<HTTPS>(*io_service, context);
|
||||
void accept() override {
|
||||
auto session = std::make_shared<Session>(create_connection(*io_service, context));
|
||||
|
||||
acceptor->async_accept((*socket).lowest_layer(), [this, socket](const boost::system::error_code &ec)
|
||||
{
|
||||
//Immediately start accepting a new connection (if io_service hasn't been stopped)
|
||||
if (ec != boost::asio::error::operation_aborted)
|
||||
accept();
|
||||
acceptor->async_accept(session->connection->socket->lowest_layer(), [this, session](const error_code &ec) {
|
||||
auto lock = session->connection->handler_runner->continue_lock();
|
||||
if(!lock)
|
||||
return;
|
||||
|
||||
if(ec != asio::error::operation_aborted)
|
||||
this->accept();
|
||||
|
||||
if (!ec)
|
||||
{
|
||||
boost::asio::ip::tcp::no_delay option(true);
|
||||
socket->lowest_layer().set_option(option);
|
||||
if(!ec) {
|
||||
asio::ip::tcp::no_delay option(true);
|
||||
error_code ec;
|
||||
session->connection->socket->lowest_layer().set_option(option, ec);
|
||||
|
||||
//Set timeout on the following boost::asio::ssl::stream::async_handshake
|
||||
auto timer = get_timeout_timer(socket, config.timeout_request);
|
||||
socket->async_handshake(boost::asio::ssl::stream_base::server, [this, socket, timer]
|
||||
(const boost::system::error_code &ec)
|
||||
{
|
||||
if (timer)
|
||||
timer->cancel();
|
||||
if (!ec)
|
||||
read_request_and_content(socket);
|
||||
else if (on_error)
|
||||
on_error(std::shared_ptr<Request>(new Request(*socket)), ec);
|
||||
session->connection->set_timeout(config.timeout_request);
|
||||
session->connection->socket->async_handshake(asio::ssl::stream_base::server, [this, session](const error_code &ec) {
|
||||
session->connection->cancel_timeout();
|
||||
auto lock = session->connection->handler_runner->continue_lock();
|
||||
if(!lock)
|
||||
return;
|
||||
if(!ec)
|
||||
this->read_request_and_content(session);
|
||||
else if(this->on_error)
|
||||
this->on_error(session->request, ec);
|
||||
});
|
||||
}
|
||||
else if (on_error)
|
||||
on_error(std::shared_ptr<Request>(new Request(*socket)), ec);
|
||||
else if(this->on_error)
|
||||
this->on_error(session->request, ec);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif //HTTPS_SERVER_HPP
|
||||
} // namespace SimpleWeb
|
||||
|
|
154
apps/master/SimpleWeb/status_code.hpp
Normal file
154
apps/master/SimpleWeb/status_code.hpp
Normal file
|
@ -0,0 +1,154 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace SimpleWeb {
|
||||
enum class StatusCode {
|
||||
unknown = 0,
|
||||
information_continue = 100,
|
||||
information_switching_protocols,
|
||||
information_processing,
|
||||
success_ok = 200,
|
||||
success_created,
|
||||
success_accepted,
|
||||
success_non_authoritative_information,
|
||||
success_no_content,
|
||||
success_reset_content,
|
||||
success_partial_content,
|
||||
success_multi_status,
|
||||
success_already_reported,
|
||||
success_im_used = 226,
|
||||
redirection_multiple_choices = 300,
|
||||
redirection_moved_permanently,
|
||||
redirection_found,
|
||||
redirection_see_other,
|
||||
redirection_not_modified,
|
||||
redirection_use_proxy,
|
||||
redirection_switch_proxy,
|
||||
redirection_temporary_redirect,
|
||||
redirection_permanent_redirect,
|
||||
client_error_bad_request = 400,
|
||||
client_error_unauthorized,
|
||||
client_error_payment_required,
|
||||
client_error_forbidden,
|
||||
client_error_not_found,
|
||||
client_error_method_not_allowed,
|
||||
client_error_not_acceptable,
|
||||
client_error_proxy_authentication_required,
|
||||
client_error_request_timeout,
|
||||
client_error_conflict,
|
||||
client_error_gone,
|
||||
client_error_length_required,
|
||||
client_error_precondition_failed,
|
||||
client_error_payload_too_large,
|
||||
client_error_uri_too_long,
|
||||
client_error_unsupported_media_type,
|
||||
client_error_range_not_satisfiable,
|
||||
client_error_expectation_failed,
|
||||
client_error_im_a_teapot,
|
||||
client_error_misdirection_required = 421,
|
||||
client_error_unprocessable_entity,
|
||||
client_error_locked,
|
||||
client_error_failed_dependency,
|
||||
client_error_upgrade_required = 426,
|
||||
client_error_precondition_required = 428,
|
||||
client_error_too_many_requests,
|
||||
client_error_request_header_fields_too_large = 431,
|
||||
client_error_unavailable_for_legal_reasons = 451,
|
||||
server_error_internal_server_error = 500,
|
||||
server_error_not_implemented,
|
||||
server_error_bad_gateway,
|
||||
server_error_service_unavailable,
|
||||
server_error_gateway_timeout,
|
||||
server_error_http_version_not_supported,
|
||||
server_error_variant_also_negotiates,
|
||||
server_error_insufficient_storage,
|
||||
server_error_loop_detected,
|
||||
server_error_not_extended = 510,
|
||||
server_error_network_authentication_required
|
||||
};
|
||||
|
||||
const static std::vector<std::pair<StatusCode, std::string>> &status_codes() noexcept {
|
||||
const static std::vector<std::pair<StatusCode, std::string>> status_codes = {
|
||||
{StatusCode::unknown, ""},
|
||||
{StatusCode::information_continue, "100 Continue"},
|
||||
{StatusCode::information_switching_protocols, "101 Switching Protocols"},
|
||||
{StatusCode::information_processing, "102 Processing"},
|
||||
{StatusCode::success_ok, "200 OK"},
|
||||
{StatusCode::success_created, "201 Created"},
|
||||
{StatusCode::success_accepted, "202 Accepted"},
|
||||
{StatusCode::success_non_authoritative_information, "203 Non-Authoritative Information"},
|
||||
{StatusCode::success_no_content, "204 No Content"},
|
||||
{StatusCode::success_reset_content, "205 Reset Content"},
|
||||
{StatusCode::success_partial_content, "206 Partial Content"},
|
||||
{StatusCode::success_multi_status, "207 Multi-Status"},
|
||||
{StatusCode::success_already_reported, "208 Already Reported"},
|
||||
{StatusCode::success_im_used, "226 IM Used"},
|
||||
{StatusCode::redirection_multiple_choices, "300 Multiple Choices"},
|
||||
{StatusCode::redirection_moved_permanently, "301 Moved Permanently"},
|
||||
{StatusCode::redirection_found, "302 Found"},
|
||||
{StatusCode::redirection_see_other, "303 See Other"},
|
||||
{StatusCode::redirection_not_modified, "304 Not Modified"},
|
||||
{StatusCode::redirection_use_proxy, "305 Use Proxy"},
|
||||
{StatusCode::redirection_switch_proxy, "306 Switch Proxy"},
|
||||
{StatusCode::redirection_temporary_redirect, "307 Temporary Redirect"},
|
||||
{StatusCode::redirection_permanent_redirect, "308 Permanent Redirect"},
|
||||
{StatusCode::client_error_bad_request, "400 Bad Request"},
|
||||
{StatusCode::client_error_unauthorized, "401 Unauthorized"},
|
||||
{StatusCode::client_error_payment_required, "402 Payment Required"},
|
||||
{StatusCode::client_error_forbidden, "403 Forbidden"},
|
||||
{StatusCode::client_error_not_found, "404 Not Found"},
|
||||
{StatusCode::client_error_method_not_allowed, "405 Method Not Allowed"},
|
||||
{StatusCode::client_error_not_acceptable, "406 Not Acceptable"},
|
||||
{StatusCode::client_error_proxy_authentication_required, "407 Proxy Authentication Required"},
|
||||
{StatusCode::client_error_request_timeout, "408 Request Timeout"},
|
||||
{StatusCode::client_error_conflict, "409 Conflict"},
|
||||
{StatusCode::client_error_gone, "410 Gone"},
|
||||
{StatusCode::client_error_length_required, "411 Length Required"},
|
||||
{StatusCode::client_error_precondition_failed, "412 Precondition Failed"},
|
||||
{StatusCode::client_error_payload_too_large, "413 Payload Too Large"},
|
||||
{StatusCode::client_error_uri_too_long, "414 URI Too Long"},
|
||||
{StatusCode::client_error_unsupported_media_type, "415 Unsupported Media Type"},
|
||||
{StatusCode::client_error_range_not_satisfiable, "416 Range Not Satisfiable"},
|
||||
{StatusCode::client_error_expectation_failed, "417 Expectation Failed"},
|
||||
{StatusCode::client_error_im_a_teapot, "418 I'm a teapot"},
|
||||
{StatusCode::client_error_misdirection_required, "421 Misdirected Request"},
|
||||
{StatusCode::client_error_unprocessable_entity, "422 Unprocessable Entity"},
|
||||
{StatusCode::client_error_locked, "423 Locked"},
|
||||
{StatusCode::client_error_failed_dependency, "424 Failed Dependency"},
|
||||
{StatusCode::client_error_upgrade_required, "426 Upgrade Required"},
|
||||
{StatusCode::client_error_precondition_required, "428 Precondition Required"},
|
||||
{StatusCode::client_error_too_many_requests, "429 Too Many Requests"},
|
||||
{StatusCode::client_error_request_header_fields_too_large, "431 Request Header Fields Too Large"},
|
||||
{StatusCode::client_error_unavailable_for_legal_reasons, "451 Unavailable For Legal Reasons"},
|
||||
{StatusCode::server_error_internal_server_error, "500 Internal Server Error"},
|
||||
{StatusCode::server_error_not_implemented, "501 Not Implemented"},
|
||||
{StatusCode::server_error_bad_gateway, "502 Bad Gateway"},
|
||||
{StatusCode::server_error_service_unavailable, "503 Service Unavailable"},
|
||||
{StatusCode::server_error_gateway_timeout, "504 Gateway Timeout"},
|
||||
{StatusCode::server_error_http_version_not_supported, "505 HTTP Version Not Supported"},
|
||||
{StatusCode::server_error_variant_also_negotiates, "506 Variant Also Negotiates"},
|
||||
{StatusCode::server_error_insufficient_storage, "507 Insufficient Storage"},
|
||||
{StatusCode::server_error_loop_detected, "508 Loop Detected"},
|
||||
{StatusCode::server_error_not_extended, "510 Not Extended"},
|
||||
{StatusCode::server_error_network_authentication_required, "511 Network Authentication Required"}};
|
||||
return status_codes;
|
||||
}
|
||||
|
||||
inline StatusCode status_code(const std::string &status_code_str) noexcept {
|
||||
for(auto &status_code : status_codes()) {
|
||||
if(status_code.second == status_code_str)
|
||||
return status_code.first;
|
||||
}
|
||||
return StatusCode::unknown;
|
||||
}
|
||||
|
||||
inline const std::string &status_code(StatusCode status_code_enum) noexcept {
|
||||
for(auto &status_code : status_codes()) {
|
||||
if(status_code.first == status_code_enum)
|
||||
return status_code.second;
|
||||
}
|
||||
return status_codes()[0].second;
|
||||
}
|
||||
} // namespace SimpleWeb
|
340
apps/master/SimpleWeb/utility.hpp
Normal file
340
apps/master/SimpleWeb/utility.hpp
Normal file
|
@ -0,0 +1,340 @@
|
|||
#pragma once
|
||||
|
||||
#include "status_code.hpp"
|
||||
#include <atomic>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace SimpleWeb {
|
||||
inline bool case_insensitive_equal(const std::string &str1, const std::string &str2) noexcept {
|
||||
return str1.size() == str2.size() &&
|
||||
std::equal(str1.begin(), str1.end(), str2.begin(), [](char a, char b) {
|
||||
return tolower(a) == tolower(b);
|
||||
});
|
||||
}
|
||||
class CaseInsensitiveEqual {
|
||||
public:
|
||||
bool operator()(const std::string &str1, const std::string &str2) const noexcept {
|
||||
return case_insensitive_equal(str1, str2);
|
||||
}
|
||||
};
|
||||
// Based on https://stackoverflow.com/questions/2590677/how-do-i-combine-hash-values-in-c0x/2595226#2595226
|
||||
class CaseInsensitiveHash {
|
||||
public:
|
||||
size_t operator()(const std::string &str) const noexcept {
|
||||
size_t h = 0;
|
||||
std::hash<int> hash;
|
||||
for(auto c : str)
|
||||
h ^= hash(tolower(c)) + 0x9e3779b9 + (h << 6) + (h >> 2);
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
using CaseInsensitiveMultimap = std::unordered_multimap<std::string, std::string, CaseInsensitiveHash, CaseInsensitiveEqual>;
|
||||
|
||||
/// Percent encoding and decoding
|
||||
class Percent {
|
||||
public:
|
||||
/// Returns percent-encoded string
|
||||
static std::string encode(const std::string &value) noexcept {
|
||||
static auto hex_chars = "0123456789ABCDEF";
|
||||
|
||||
std::string result;
|
||||
result.reserve(value.size()); // Minimum size of result
|
||||
|
||||
for(auto &chr : value) {
|
||||
if(chr == ' ')
|
||||
result += '+';
|
||||
else if(chr == '!' || chr == '#' || chr == '$' || (chr >= '&' && chr <= ',') || (chr >= '/' && chr <= ';') || chr == '=' || chr == '?' || chr == '@' || chr == '[' || chr == ']')
|
||||
result += std::string("%") + hex_chars[chr >> 4] + hex_chars[chr & 15];
|
||||
else
|
||||
result += chr;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Returns percent-decoded string
|
||||
static std::string decode(const std::string &value) noexcept {
|
||||
std::string result;
|
||||
result.reserve(value.size() / 3 + (value.size() % 3)); // Minimum size of result
|
||||
|
||||
for(size_t i = 0; i < value.size(); ++i) {
|
||||
auto &chr = value[i];
|
||||
if(chr == '%' && i + 2 < value.size()) {
|
||||
auto hex = value.substr(i + 1, 2);
|
||||
auto decoded_chr = static_cast<char>(std::strtol(hex.c_str(), nullptr, 16));
|
||||
result += decoded_chr;
|
||||
i += 2;
|
||||
}
|
||||
else if(chr == '+')
|
||||
result += ' ';
|
||||
else
|
||||
result += chr;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/// Query string creation and parsing
|
||||
class QueryString {
|
||||
public:
|
||||
/// Returns query string created from given field names and values
|
||||
static std::string create(const CaseInsensitiveMultimap &fields) noexcept {
|
||||
std::string result;
|
||||
|
||||
bool first = true;
|
||||
for(auto &field : fields) {
|
||||
result += (!first ? "&" : "") + field.first + '=' + Percent::encode(field.second);
|
||||
first = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Returns query keys with percent-decoded values.
|
||||
static CaseInsensitiveMultimap parse(const std::string &query_string) noexcept {
|
||||
CaseInsensitiveMultimap result;
|
||||
|
||||
if(query_string.empty())
|
||||
return result;
|
||||
|
||||
size_t name_pos = 0;
|
||||
auto name_end_pos = std::string::npos;
|
||||
auto value_pos = std::string::npos;
|
||||
for(size_t c = 0; c < query_string.size(); ++c) {
|
||||
if(query_string[c] == '&') {
|
||||
auto name = query_string.substr(name_pos, (name_end_pos == std::string::npos ? c : name_end_pos) - name_pos);
|
||||
if(!name.empty()) {
|
||||
auto value = value_pos == std::string::npos ? std::string() : query_string.substr(value_pos, c - value_pos);
|
||||
result.emplace(std::move(name), Percent::decode(value));
|
||||
}
|
||||
name_pos = c + 1;
|
||||
name_end_pos = std::string::npos;
|
||||
value_pos = std::string::npos;
|
||||
}
|
||||
else if(query_string[c] == '=') {
|
||||
name_end_pos = c;
|
||||
value_pos = c + 1;
|
||||
}
|
||||
}
|
||||
if(name_pos < query_string.size()) {
|
||||
auto name = query_string.substr(name_pos, name_end_pos - name_pos);
|
||||
if(!name.empty()) {
|
||||
auto value = value_pos >= query_string.size() ? std::string() : query_string.substr(value_pos);
|
||||
result.emplace(std::move(name), Percent::decode(value));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
class HttpHeader {
|
||||
public:
|
||||
/// Parse header fields
|
||||
static CaseInsensitiveMultimap parse(std::istream &stream) noexcept {
|
||||
CaseInsensitiveMultimap result;
|
||||
std::string line;
|
||||
getline(stream, line);
|
||||
size_t param_end;
|
||||
while((param_end = line.find(':')) != std::string::npos) {
|
||||
size_t value_start = param_end + 1;
|
||||
if(value_start < line.size()) {
|
||||
if(line[value_start] == ' ')
|
||||
value_start++;
|
||||
if(value_start < line.size())
|
||||
result.emplace(line.substr(0, param_end), line.substr(value_start, line.size() - value_start - 1));
|
||||
}
|
||||
|
||||
getline(stream, line);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
class RequestMessage {
|
||||
public:
|
||||
/// Parse request line and header fields
|
||||
static bool parse(std::istream &stream, std::string &method, std::string &path, std::string &query_string, std::string &version, CaseInsensitiveMultimap &header) noexcept {
|
||||
header.clear();
|
||||
std::string line;
|
||||
getline(stream, line);
|
||||
size_t method_end;
|
||||
if((method_end = line.find(' ')) != std::string::npos) {
|
||||
method = line.substr(0, method_end);
|
||||
|
||||
size_t query_start = std::string::npos;
|
||||
size_t path_and_query_string_end = std::string::npos;
|
||||
for(size_t i = method_end + 1; i < line.size(); ++i) {
|
||||
if(line[i] == '?' && (i + 1) < line.size())
|
||||
query_start = i + 1;
|
||||
else if(line[i] == ' ') {
|
||||
path_and_query_string_end = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(path_and_query_string_end != std::string::npos) {
|
||||
if(query_start != std::string::npos) {
|
||||
path = line.substr(method_end + 1, query_start - method_end - 2);
|
||||
query_string = line.substr(query_start, path_and_query_string_end - query_start);
|
||||
}
|
||||
else
|
||||
path = line.substr(method_end + 1, path_and_query_string_end - method_end - 1);
|
||||
|
||||
size_t protocol_end;
|
||||
if((protocol_end = line.find('/', path_and_query_string_end + 1)) != std::string::npos) {
|
||||
if(line.compare(path_and_query_string_end + 1, protocol_end - path_and_query_string_end - 1, "HTTP") != 0)
|
||||
return false;
|
||||
version = line.substr(protocol_end + 1, line.size() - protocol_end - 2);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
header = HttpHeader::parse(stream);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class ResponseMessage {
|
||||
public:
|
||||
/// Parse status line and header fields
|
||||
static bool parse(std::istream &stream, std::string &version, std::string &status_code, CaseInsensitiveMultimap &header) noexcept {
|
||||
header.clear();
|
||||
std::string line;
|
||||
getline(stream, line);
|
||||
size_t version_end = line.find(' ');
|
||||
if(version_end != std::string::npos) {
|
||||
if(5 < line.size())
|
||||
version = line.substr(5, version_end - 5);
|
||||
else
|
||||
return false;
|
||||
if((version_end + 1) < line.size())
|
||||
status_code = line.substr(version_end + 1, line.size() - (version_end + 1) - 1);
|
||||
else
|
||||
return false;
|
||||
|
||||
header = HttpHeader::parse(stream);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class ContentDisposition {
|
||||
public:
|
||||
/// Can be used to parse the Content-Disposition header field value when
|
||||
/// clients are posting requests with enctype="multipart/form-data"
|
||||
static CaseInsensitiveMultimap parse(const std::string &line) {
|
||||
CaseInsensitiveMultimap result;
|
||||
|
||||
size_t para_start_pos = 0;
|
||||
size_t para_end_pos = std::string::npos;
|
||||
size_t value_start_pos = std::string::npos;
|
||||
for(size_t c = 0; c < line.size(); ++c) {
|
||||
if(para_start_pos != std::string::npos) {
|
||||
if(para_end_pos == std::string::npos) {
|
||||
if(line[c] == ';') {
|
||||
result.emplace(line.substr(para_start_pos, c - para_start_pos), std::string());
|
||||
para_start_pos = std::string::npos;
|
||||
}
|
||||
else if(line[c] == '=')
|
||||
para_end_pos = c;
|
||||
}
|
||||
else {
|
||||
if(value_start_pos == std::string::npos) {
|
||||
if(line[c] == '"' && c + 1 < line.size())
|
||||
value_start_pos = c + 1;
|
||||
}
|
||||
else if(line[c] == '"') {
|
||||
result.emplace(line.substr(para_start_pos, para_end_pos - para_start_pos), line.substr(value_start_pos, c - value_start_pos));
|
||||
para_start_pos = std::string::npos;
|
||||
para_end_pos = std::string::npos;
|
||||
value_start_pos = std::string::npos;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(line[c] != ' ' && line[c] != ';')
|
||||
para_start_pos = c;
|
||||
}
|
||||
if(para_start_pos != std::string::npos && para_end_pos == std::string::npos)
|
||||
result.emplace(line.substr(para_start_pos), std::string());
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
} // namespace SimpleWeb
|
||||
|
||||
#ifdef __SSE2__
|
||||
#include <emmintrin.h>
|
||||
namespace SimpleWeb {
|
||||
inline void spin_loop_pause() noexcept { _mm_pause(); }
|
||||
} // namespace SimpleWeb
|
||||
// TODO: need verification that the following checks are correct:
|
||||
#elif defined(_MSC_VER) && _MSC_VER >= 1800 && (defined(_M_X64) || defined(_M_IX86))
|
||||
#include <intrin.h>
|
||||
namespace SimpleWeb {
|
||||
inline void spin_loop_pause() noexcept { _mm_pause(); }
|
||||
} // namespace SimpleWeb
|
||||
#else
|
||||
namespace SimpleWeb {
|
||||
inline void spin_loop_pause() noexcept {}
|
||||
} // namespace SimpleWeb
|
||||
#endif
|
||||
|
||||
namespace SimpleWeb {
|
||||
/// Makes it possible to for instance cancel Asio handlers without stopping asio::io_service
|
||||
class ScopeRunner {
|
||||
/// Scope count that is set to -1 if scopes are to be canceled
|
||||
std::atomic<long> count;
|
||||
|
||||
public:
|
||||
class SharedLock {
|
||||
friend class ScopeRunner;
|
||||
std::atomic<long> &count;
|
||||
SharedLock(std::atomic<long> &count) noexcept : count(count) {}
|
||||
SharedLock &operator=(const SharedLock &) = delete;
|
||||
SharedLock(const SharedLock &) = delete;
|
||||
|
||||
public:
|
||||
~SharedLock() noexcept {
|
||||
count.fetch_sub(1);
|
||||
}
|
||||
};
|
||||
|
||||
ScopeRunner() noexcept : count(0) {}
|
||||
|
||||
/// Returns nullptr if scope should be exited, or a shared lock otherwise
|
||||
std::unique_ptr<SharedLock> continue_lock() noexcept {
|
||||
long expected = count;
|
||||
while(expected >= 0 && !count.compare_exchange_weak(expected, expected + 1))
|
||||
spin_loop_pause();
|
||||
|
||||
if(expected < 0)
|
||||
return nullptr;
|
||||
else
|
||||
return std::unique_ptr<SharedLock>(new SharedLock(count));
|
||||
}
|
||||
|
||||
/// Blocks until all shared locks are released, then prevents future shared locks
|
||||
void stop() noexcept {
|
||||
long expected = 0;
|
||||
while(!count.compare_exchange_weak(expected, -1)) {
|
||||
if(expected < 0)
|
||||
return;
|
||||
expected = 0;
|
||||
spin_loop_pause();
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace SimpleWeb
|
|
@ -1,36 +1,74 @@
|
|||
#include <iostream>
|
||||
#include <Kbhit.h>
|
||||
#include <RakSleep.h>
|
||||
#include <extern/sol/sol.hpp>
|
||||
#include "MasterServer.hpp"
|
||||
#include "RestServer.hpp"
|
||||
#include "AdminRest.hpp"
|
||||
|
||||
using namespace RakNet;
|
||||
using namespace std;
|
||||
|
||||
unique_ptr<RestServer> restServer;
|
||||
unique_ptr<MasterServer> masterServer;
|
||||
bool run = true;
|
||||
shared_ptr<MasterServer> masterServer;
|
||||
unique_ptr<AdminRest> restAdminServer;
|
||||
|
||||
int main()
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
masterServer.reset(new MasterServer(2000, 25560));
|
||||
restServer.reset(new RestServer(8080, masterServer->GetServers()));
|
||||
if (argc != 2)
|
||||
return 1;
|
||||
|
||||
string luaScript(argv[1]);
|
||||
|
||||
masterServer = make_shared<MasterServer>(luaScript);
|
||||
masterServer->luaStuff([](sol::state &state)
|
||||
{
|
||||
sol::table config = state["config"];
|
||||
sol::object restPort = config["restPort"];
|
||||
if (restPort.get_type() != sol::type::number)
|
||||
throw runtime_error("config.restPort is not correct");
|
||||
|
||||
|
||||
restServer = make_unique<RestServer>(restPort.as<unsigned short>(), masterServer->GetServers());
|
||||
|
||||
sol::object restAdminCert = config["restAdminCert"];
|
||||
if (restAdminCert.get_type() != sol::type::string)
|
||||
throw runtime_error("config.restAdminCert is not correct");
|
||||
|
||||
sol::object restAdminKey = config["restAdminKey"];
|
||||
if (restAdminKey.get_type() != sol::type::string)
|
||||
throw runtime_error("config.restAdminKey is not correct");
|
||||
|
||||
sol::object restAdminVerifyFile = config["restAdminVerifyFile"];
|
||||
if (restAdminVerifyFile.get_type() != sol::type::string)
|
||||
throw runtime_error("config.restAdminVerifyFile is not correct");
|
||||
|
||||
sol::object restAdminPort = config["restAdminPort"];
|
||||
if (restAdminPort.get_type() != sol::type::number)
|
||||
throw runtime_error("config.restAdminPort is not correct");
|
||||
|
||||
restAdminServer = make_unique<AdminRest>(restAdminCert.as<string>(), restAdminKey.as<string>(),
|
||||
restAdminVerifyFile.as<string>(), restAdminPort.as<unsigned short>(), masterServer);
|
||||
});
|
||||
|
||||
auto onExit = [](int /*sig*/){
|
||||
restServer->stop();
|
||||
restAdminServer->stop();
|
||||
masterServer->luaStuff([](sol::state &state) {
|
||||
sol::protected_function func = state["OnExit"];
|
||||
if (func.valid())
|
||||
func.call();
|
||||
});
|
||||
masterServer->Stop(false);
|
||||
masterServer->Wait();
|
||||
run = false;
|
||||
};
|
||||
|
||||
signal(SIGINT, onExit);
|
||||
signal(SIGTERM, onExit);
|
||||
|
||||
masterServer->Start();
|
||||
|
||||
thread server_thread([]() { restServer->start(); });
|
||||
|
||||
server_thread.join();
|
||||
restServer->start();
|
||||
restAdminServer->start();
|
||||
masterServer->Wait();
|
||||
|
||||
return 0;
|
||||
|
|
281
apps/openmw-mp/Actors.cpp
Normal file
281
apps/openmw-mp/Actors.cpp
Normal file
|
@ -0,0 +1,281 @@
|
|||
//
|
||||
// Created by koncord on 25.08.17.
|
||||
//
|
||||
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
#include "Script/LuaState.hpp"
|
||||
#include "Networking.hpp"
|
||||
|
||||
#include "Actors.hpp"
|
||||
#include "Cell.hpp"
|
||||
#include "CellController.hpp"
|
||||
#include "Player.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void Actor::Init(LuaState &lua)
|
||||
{
|
||||
lua.getState()->new_usertype<Actor>("Actor",
|
||||
"getPosition", &NetActor::getPosition,
|
||||
"setPosition", &NetActor::setPosition,
|
||||
"getRotation", &NetActor::getRotation,
|
||||
"setRotation", &NetActor::setRotation,
|
||||
|
||||
"getHealth", &NetActor::getHealth,
|
||||
"setHealth", &NetActor::setHealth,
|
||||
"getMagicka", &NetActor::getMagicka,
|
||||
"setMagicka", &NetActor::setMagicka,
|
||||
"getFatigue", &NetActor::getFatigue,
|
||||
"setFatigue", &NetActor::setFatigue,
|
||||
|
||||
"getCell", &NetActor::getCell,
|
||||
"getInventory", &NetActor::getInventory,
|
||||
|
||||
"refId", sol::property(&Actor::getRefId, &Actor::setRefId),
|
||||
"refNumIndex", sol::property(&Actor::getRefNumIndex, &Actor::setRefNumIndex),
|
||||
"mpNum", sol::property(&Actor::getMpNum, &Actor::setMpNum)
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
Actor::Actor() : NetActor()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::string Actor::getRefId() const
|
||||
{
|
||||
return actor->refId;
|
||||
}
|
||||
|
||||
void Actor::setRefId(const std::string &refId)
|
||||
{
|
||||
actor->refId = refId;
|
||||
}
|
||||
|
||||
int Actor::getRefNumIndex() const
|
||||
{
|
||||
return actor->refNumIndex;
|
||||
}
|
||||
|
||||
void Actor::setRefNumIndex(int refNumIndex)
|
||||
{
|
||||
actor->refNumIndex = refNumIndex;
|
||||
}
|
||||
|
||||
int Actor::getMpNum() const
|
||||
{
|
||||
return actor->mpNum;
|
||||
}
|
||||
|
||||
void Actor::setMpNum(int mpNum)
|
||||
{
|
||||
actor->mpNum = mpNum;
|
||||
}
|
||||
|
||||
bool Actor::doesHavePosition() const
|
||||
{
|
||||
return actor->hasPositionData;
|
||||
}
|
||||
|
||||
bool Actor::doesHaveStatsDynamic() const
|
||||
{
|
||||
return actor->hasStatsDynamicData;
|
||||
}
|
||||
|
||||
void ActorController::Init(LuaState &lua)
|
||||
{
|
||||
sol::table playersTable = lua.getState()->create_named_table("Actors");
|
||||
|
||||
playersTable.set_function("createActor", [&lua](){
|
||||
return lua.getActorCtrl().createActor();
|
||||
});
|
||||
|
||||
playersTable.set_function("sendActors", [&lua](shared_ptr<Player> player, vector<shared_ptr<Actor>> actors,
|
||||
const std::string &cellDescription, bool sendToAll) {
|
||||
lua.getActorCtrl().sendActors(player, actors, Utils::getCellFromDescription(cellDescription), sendToAll);
|
||||
});
|
||||
|
||||
playersTable.set_function("sendList", [&lua](shared_ptr<Player> player, vector<shared_ptr<Actor>> actors,
|
||||
const std::string &cellDescription, bool sendToAll) {
|
||||
lua.getActorCtrl().sendList(player, actors, Utils::getCellFromDescription(cellDescription), sendToAll);
|
||||
});
|
||||
|
||||
playersTable.set_function("requestList", [&lua](shared_ptr<Player> player, const std::string &cellDescription){
|
||||
lua.getActorCtrl().requestList(player, Utils::getCellFromDescription(cellDescription));
|
||||
});
|
||||
|
||||
playersTable.set_function("getActors", [&lua](shared_ptr<Player> player, const std::string &cellDescription){
|
||||
lua.getActorCtrl().getActors(player, Utils::getCellFromDescription(cellDescription));
|
||||
});
|
||||
}
|
||||
|
||||
ActorController::ActorController()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ActorController::~ActorController()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<Actor> ActorController::createActor()
|
||||
{
|
||||
Actor *actor = new Actor();
|
||||
actor->actor.reset(new mwmp::BaseActor);
|
||||
|
||||
return shared_ptr<Actor>(actor);
|
||||
}
|
||||
|
||||
void ActorController::sendActors(std::shared_ptr<Player> player, std::vector<std::shared_ptr<Actor>> actors,
|
||||
const ESM::Cell &cell, bool sendToAll)
|
||||
{
|
||||
actorList.cell = cell;
|
||||
actorList.guid = player->guid;
|
||||
|
||||
bool positionChanged = false;
|
||||
bool statsChanged = false;
|
||||
/*bool attributesChanged = false;
|
||||
bool skillsChanged = false;
|
||||
bool baseInfoChanged = false;*/
|
||||
bool equipmentChanged = false;
|
||||
bool changedCell = false;
|
||||
|
||||
actorList.baseActors.clear();
|
||||
for (auto &actor : actors)
|
||||
{
|
||||
actorList.baseActors.push_back(actor->actor);
|
||||
|
||||
if (actor->positionChanged)
|
||||
positionChanged = true;
|
||||
if (actor->statsChanged)
|
||||
statsChanged = true;
|
||||
/*if (actor->attributesChanged)
|
||||
attributesChanged = true;
|
||||
if (actor->skillsChanged)
|
||||
skillsChanged = true;
|
||||
if (actor->baseInfoChanged)
|
||||
baseInfoChanged = true;*/
|
||||
if (actor->inventory.isEquipmentChanged())
|
||||
{
|
||||
equipmentChanged = true;
|
||||
actor->inventory.resetEquipmentFlag();
|
||||
}
|
||||
if (actor->cellAPI.isChangedCell())
|
||||
{
|
||||
changedCell = true;
|
||||
actor->cellAPI.resetChangedCell();
|
||||
}
|
||||
actor->resetUpdateFlags();
|
||||
}
|
||||
|
||||
auto actorCtrl = mwmp::Networking::get().getActorPacketController();
|
||||
Cell *serverCell = nullptr;
|
||||
|
||||
if (sendToAll)
|
||||
serverCell = CellController::get()->getCell(&actorList.cell);
|
||||
|
||||
if (positionChanged)
|
||||
{
|
||||
auto packet = actorCtrl->GetPacket(ID_ACTOR_POSITION);
|
||||
|
||||
packet->setActorList(&actorList);
|
||||
packet->Send(actorList.guid);
|
||||
|
||||
if (sendToAll)
|
||||
serverCell->sendToLoaded(packet, &actorList);
|
||||
}
|
||||
if (statsChanged)
|
||||
{
|
||||
auto packet = actorCtrl->GetPacket(ID_ACTOR_STATS_DYNAMIC);
|
||||
|
||||
packet->setActorList(&actorList);
|
||||
packet->Send(actorList.guid);
|
||||
|
||||
if (sendToAll)
|
||||
serverCell->sendToLoaded(packet, &actorList);
|
||||
|
||||
}
|
||||
/*if (attributesChanged)
|
||||
{
|
||||
auto packet = actorCtrl->GetPacket(ID_ACTOR_POSITION);
|
||||
|
||||
}
|
||||
if (skillsChanged)
|
||||
{
|
||||
auto packet = actorCtrl->GetPacket(ID_ACTOR_POSITION);
|
||||
|
||||
}
|
||||
if (baseInfoChanged)
|
||||
{
|
||||
auto packet = actorCtrl->GetPacket(ID_ACTOR_POSITION);
|
||||
|
||||
}*/
|
||||
|
||||
if (equipmentChanged)
|
||||
{
|
||||
auto packet = actorCtrl->GetPacket(ID_ACTOR_EQUIPMENT);
|
||||
packet->setActorList(&actorList);
|
||||
packet->Send(actorList.guid);
|
||||
|
||||
if (sendToAll)
|
||||
serverCell->sendToLoaded(packet, &actorList);
|
||||
}
|
||||
if (changedCell)
|
||||
{
|
||||
auto packet = actorCtrl->GetPacket(ID_ACTOR_CELL_CHANGE);
|
||||
packet->setActorList(&actorList);
|
||||
packet->Send(actorList.guid);
|
||||
|
||||
if (sendToAll)
|
||||
serverCell->sendToLoaded(packet, &actorList);
|
||||
}
|
||||
}
|
||||
|
||||
void ActorController::sendList(std::shared_ptr<Player> player, std::vector<std::shared_ptr<Actor>> actors,
|
||||
const ESM::Cell &cell, bool sendToAll)
|
||||
{
|
||||
actorList.cell = player->cell;
|
||||
actorList.guid = player->guid;
|
||||
actorList.action = mwmp::BaseActorList::SET;
|
||||
|
||||
for (auto &actor : actors)
|
||||
{
|
||||
actorList.baseActors.push_back(actor->actor);
|
||||
}
|
||||
|
||||
auto packet = mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_LIST);
|
||||
packet->setActorList(&actorList);
|
||||
packet->Send(actorList.guid);
|
||||
if (sendToAll)
|
||||
CellController::get()->getCell(&actorList.cell)->sendToLoaded(packet, &actorList);
|
||||
}
|
||||
|
||||
void ActorController::requestList(std::shared_ptr<Player> player, const ESM::Cell &cell)
|
||||
{
|
||||
actorList.cell = player->cell;
|
||||
actorList.guid = player->guid;
|
||||
actorList.action = mwmp::BaseActorList::REQUEST;
|
||||
|
||||
auto packet = mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_LIST);
|
||||
packet->setActorList(&actorList);
|
||||
packet->Send(actorList.guid);
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<Actor>> ActorController::getActors(std::shared_ptr<Player> player, const ESM::Cell &cell)
|
||||
{
|
||||
Cell *serverCell = CellController::get()->getCell(&player->cell);
|
||||
|
||||
std::vector<std::shared_ptr<Actor>> actorList;
|
||||
|
||||
for (auto actor : serverCell->getActorList()->baseActors)
|
||||
{
|
||||
Actor *a = new Actor;
|
||||
a->actor = actor;
|
||||
actorList.emplace_back(a);
|
||||
}
|
||||
|
||||
return actorList;
|
||||
}
|
55
apps/openmw-mp/Actors.hpp
Normal file
55
apps/openmw-mp/Actors.hpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
// Created by koncord on 25.08.17.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <components/openmw-mp/Base/BaseActor.hpp>
|
||||
#include "NetActor.hpp"
|
||||
|
||||
class LuaState;
|
||||
class Player;
|
||||
|
||||
class Actor: public NetActor
|
||||
{
|
||||
friend class ActorController;
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
public:
|
||||
Actor();
|
||||
std::string getRefId() const;
|
||||
void setRefId(const std::string &refId);
|
||||
|
||||
int getRefNumIndex() const;
|
||||
void setRefNumIndex(int refNumIndex);
|
||||
int getMpNum() const;
|
||||
void setMpNum(int mpNum);
|
||||
bool doesHavePosition() const; // ????
|
||||
bool doesHaveStatsDynamic() const; // ????
|
||||
|
||||
std::shared_ptr<mwmp::BaseActor> actor;
|
||||
};
|
||||
|
||||
class ActorController
|
||||
{
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
public:
|
||||
|
||||
ActorController();
|
||||
~ActorController();
|
||||
|
||||
std::shared_ptr<Actor> createActor();
|
||||
void sendActors(std::shared_ptr<Player> player, std::vector<std::shared_ptr<Actor>> actors, const ESM::Cell &cell, bool sendToAll = false);
|
||||
void sendList(std::shared_ptr<Player> player, std::vector<std::shared_ptr<Actor>> actors, const ESM::Cell &cell, bool sendToAll = false);
|
||||
|
||||
void requestList(std::shared_ptr<Player> player, const ESM::Cell &cell);
|
||||
|
||||
std::vector<std::shared_ptr<Actor>> getActors(std::shared_ptr<Player> player, const ESM::Cell &cell);
|
||||
|
||||
private:
|
||||
mwmp::BaseActorList actorList;
|
||||
};
|
||||
|
||||
|
69
apps/openmw-mp/Books.cpp
Normal file
69
apps/openmw-mp/Books.cpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
//
|
||||
// Created by koncord on 15.08.17.
|
||||
//
|
||||
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
#include "Script/LuaState.hpp"
|
||||
#include "Networking.hpp"
|
||||
|
||||
#include "Books.hpp"
|
||||
#include "Player.hpp"
|
||||
|
||||
void Books::Init(LuaState &lua)
|
||||
{
|
||||
lua.getState()->new_usertype<Books>("Books",
|
||||
"addBook", &Books::addBook,
|
||||
"getBookId", &Books::getBookId,
|
||||
"getChanges", &Books::getChanges,
|
||||
"reset", &Books::reset
|
||||
);
|
||||
}
|
||||
|
||||
Books::Books(Player *player) : player(player), changed(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Books::~Books()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Books::addBook(const std::string &bookId)
|
||||
{
|
||||
if (!changed)
|
||||
reset();
|
||||
player->bookChanges.books.push_back({bookId});
|
||||
changed = true;
|
||||
}
|
||||
|
||||
std::string Books::getBookId(unsigned i) const
|
||||
{
|
||||
if (i >= player->bookChanges.books.size())
|
||||
return "invalid";
|
||||
|
||||
return player->bookChanges.books.at(i).bookId;
|
||||
}
|
||||
|
||||
unsigned Books::getChanges() const
|
||||
{
|
||||
return player->bookChanges.books.size();
|
||||
}
|
||||
|
||||
void Books::reset()
|
||||
{
|
||||
player->bookChanges.books.clear();
|
||||
}
|
||||
|
||||
void Books::update()
|
||||
{
|
||||
if (!changed)
|
||||
return;
|
||||
changed = false;
|
||||
|
||||
auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_BOOK);
|
||||
|
||||
packet->setPlayer(player);
|
||||
packet->Send(/*toOthers*/ false);
|
||||
}
|
32
apps/openmw-mp/Books.hpp
Normal file
32
apps/openmw-mp/Books.hpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// Created by koncord on 15.08.17.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
class LuaState;
|
||||
class Player;
|
||||
|
||||
class Books
|
||||
{
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
public:
|
||||
|
||||
explicit Books(Player *player);
|
||||
~Books();
|
||||
|
||||
void addBook(const std::string &bookId);
|
||||
std::string getBookId(unsigned i) const;
|
||||
unsigned getChanges() const;
|
||||
void reset();
|
||||
|
||||
void update();
|
||||
private:
|
||||
Player *player;
|
||||
bool changed;
|
||||
};
|
||||
|
||||
|
|
@ -1,12 +1,5 @@
|
|||
project(tes3mp-server)
|
||||
|
||||
if(UNIX) #temporarily disabled for non-unix
|
||||
if(NOT (${CMAKE_CXX_COMPILER} MATCHES "aarch64" OR ${CMAKE_CXX_COMPILER} MATCHES "arm")) #temporarily disabled for arm
|
||||
find_package(CallFF REQUIRED)
|
||||
include_directories(${CallFF_INCLUDES})
|
||||
endif(NOT (${CMAKE_CXX_COMPILER} MATCHES "aarch64" OR ${CMAKE_CXX_COMPILER} MATCHES "arm"))
|
||||
endif(UNIX)
|
||||
|
||||
option(BUILD_WITH_PAWN "Enable Pawn language" OFF)
|
||||
option(ENABLE_BREAKPAD "Enable Google Breakpad for Crash reporting" OFF)
|
||||
|
||||
|
@ -22,89 +15,58 @@ if(ENABLE_BREAKPAD)
|
|||
include_directories(${CMAKE_SOURCE_DIR}/extern/breakpad/src ${Breakpad_Headers})
|
||||
endif(ENABLE_BREAKPAD)
|
||||
|
||||
if(BUILD_WITH_PAWN)
|
||||
|
||||
add_subdirectory(amx)
|
||||
|
||||
#set(Pawn_ROOT ${CMAKE_SOURCE_DIR}/external/pawn/)
|
||||
set(Pawn_INCLUDES ${Pawn_ROOT}/include)
|
||||
set(Pawn_LIBRARY ${Pawn_ROOT}/lib/libamx.a)
|
||||
set(PawnScript_Sources
|
||||
Script/LangPawn/LangPAWN.cpp
|
||||
Script/LangPawn/PawnFunc.cpp)
|
||||
set(PawnScript_Headers ${Pawn_INCLUDES}
|
||||
Script/LangPawn/LangPAWN.hpp
|
||||
)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DENABLE_PAWN -DPAWN_CELL_SIZE=64")
|
||||
#include_directories(${Pawn_INCLUDES})
|
||||
include_directories("./amx/linux")
|
||||
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 OR FORCE_LUA)
|
||||
find_package(Lua51 REQUIRED)
|
||||
MESSAGE(STATUS "Found LUA_LIBRARY: ${LUA_LIBRARY}")
|
||||
MESSAGE(STATUS "Found LUA_INCLUDE_DIR: ${LUA_INCLUDE_DIR}")
|
||||
else()
|
||||
find_package(Terra REQUIRED)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DENABLE_TERRA")
|
||||
endif()
|
||||
set(LuaScript_Sources
|
||||
Script/LangLua/LangLua.cpp
|
||||
Script/LangLua/LuaFunc.cpp)
|
||||
set(LuaScript_Headers ${Terra_INCLUDES} ${LUA_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/extern/LuaBridge ${CMAKE_SOURCE_DIR}/extern/LuaBridge/detail
|
||||
Script/LangLua/LangLua.hpp)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DENABLE_LUA")
|
||||
include_directories(${Terra_INCLUDES} ${LUA_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/extern/LuaBridge)
|
||||
endif(BUILD_WITH_LUA)
|
||||
|
||||
set(NativeScript_Sources
|
||||
Script/LangNative/LangNative.cpp
|
||||
)
|
||||
set(NativeScript_Headers
|
||||
Script/LangNative/LangNative.hpp
|
||||
)
|
||||
#set(Terra_ROOT ${CMAKE_SOURCE_DIR}/external/terra/)
|
||||
#if(WIN32 OR FORCE_LUA)
|
||||
find_package(LuaJit REQUIRED)
|
||||
#[[else()
|
||||
find_package(Terra REQUIRED)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DENABLE_TERRA")]]
|
||||
#endif()
|
||||
set(LuaScript_Headers ${Terra_INCLUDES} ${LUA_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/extern/sol/sol.hpp)
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DENABLE_LUA")
|
||||
include_directories(${Terra_INCLUDES} ${LUA_INCLUDE_DIR} ${LUAJIT_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/extern/sol)
|
||||
|
||||
|
||||
# local files
|
||||
set(SERVER
|
||||
main.cpp
|
||||
Player.cpp
|
||||
Player.cpp Players.cpp
|
||||
Networking.cpp
|
||||
MasterClient.cpp
|
||||
Cell.cpp
|
||||
CellController.cpp
|
||||
Utils.cpp
|
||||
Script/Script.cpp Script/ScriptFunction.cpp
|
||||
Script/ScriptFunctions.cpp
|
||||
|
||||
Script/Functions/Actors.cpp Script/Functions/World.cpp Script/Functions/Miscellaneous.cpp
|
||||
|
||||
Script/Functions/Books.cpp Script/Functions/Cells.cpp Script/Functions/CharClass.cpp
|
||||
Script/Functions/Chat.cpp Script/Functions/Dialogue.cpp Script/Functions/Factions.cpp
|
||||
Script/Functions/GUI.cpp Script/Functions/Items.cpp Script/Functions/Mechanics.cpp
|
||||
Script/Functions/Positions.cpp Script/Functions/Quests.cpp Script/Functions/Settings.cpp
|
||||
Script/Functions/Spells.cpp Script/Functions/Stats.cpp Script/Functions/Timer.cpp
|
||||
|
||||
Script/API/TimerAPI.cpp Script/API/PublicFnAPI.cpp
|
||||
${PawnScript_Sources}
|
||||
${LuaScript_Sources}
|
||||
${NativeScript_Sources}
|
||||
|
||||
CharClass.cpp
|
||||
Inventory.cpp
|
||||
Settings.cpp
|
||||
Timer.cpp
|
||||
Books.cpp
|
||||
GUI.cpp
|
||||
Dialogue.cpp
|
||||
Factions.cpp
|
||||
Cells.cpp
|
||||
Quests.cpp
|
||||
Spells.cpp
|
||||
Actors.cpp
|
||||
NetActor.cpp
|
||||
CellState.cpp
|
||||
Object.cpp
|
||||
stacktrace.cpp
|
||||
Window.cpp
|
||||
Script/CommandController.cpp Script/EventController.cpp Script/LuaState.cpp Script/luaUtils.cpp
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND SERVER stackwalker/StackWalker.cpp)
|
||||
endif()
|
||||
|
||||
set(SERVER_HEADER
|
||||
Script/Types.hpp Script/Script.hpp Script/SystemInterface.hpp
|
||||
Script/ScriptFunction.hpp Script/Platform.hpp Script/Language.hpp
|
||||
Script/ScriptFunctions.hpp Script/API/TimerAPI.hpp Script/API/PublicFnAPI.hpp
|
||||
${PawnScript_Headers}
|
||||
${LuaScript_Headers}
|
||||
${NativeScript_Headers}
|
||||
${CallFF_INCLUDES}
|
||||
|
||||
)
|
||||
source_group(tes3mp-server FILES ${SERVER} ${SERVER_HEADER})
|
||||
|
||||
|
@ -134,7 +96,7 @@ set(PROCESSORS_PLAYER
|
|||
processors/player/ProcessorPlayerResurrect.hpp processors/player/ProcessorPlayerShapeshift.hpp
|
||||
processors/player/ProcessorPlayerSkill.hpp processors/player/ProcessorPlayerSpeech.hpp
|
||||
processors/player/ProcessorPlayerSpellbook.hpp processors/player/ProcessorPlayerStatsDynamic.hpp
|
||||
processors/player/ProcessorPlayerTopic.hpp
|
||||
processors/player/ProcessorPlayerTopic.hpp processors/player/ProcessorGUIWindow.hpp
|
||||
)
|
||||
|
||||
source_group(tes3mp-server\\processors\\player FILES ${PROCESSORS_PLAYER})
|
||||
|
@ -171,7 +133,15 @@ add_executable(tes3mp-server
|
|||
${PROCESSORS_ACTOR} ${PROCESSORS_PLAYER} ${PROCESSORS_WORLD} ${PROCESSORS}
|
||||
${APPLE_BUNDLE_RESOURCES}
|
||||
)
|
||||
add_definitions(-std=gnu++14 -Wno-ignored-qualifiers)
|
||||
|
||||
# For Lua debugging
|
||||
target_compile_definitions(tes3mp-server PRIVATE $<$<CONFIG:Debug>:SOL_SAFE_FUNCTIONS> $<$<CONFIG:RelWithDebInfo>:SOL_SAFE_FUNCTIONS>)
|
||||
target_compile_definitions(tes3mp-server PRIVATE $<$<CONFIG:Debug>:SOL_SAFE_USERTYPE> $<$<CONFIG:RelWithDebInfo>:SOL_SAFE_USERTYPE>)
|
||||
target_compile_definitions(tes3mp-server PRIVATE $<$<CONFIG:Debug>:SERVER_DEBUG> $<$<CONFIG:RelWithDebInfo>:SERVER_DEBUG>)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
target_compile_options(tes3mp-server PRIVATE -std=gnu++14 -Wno-ignored-qualifiers -ftemplate-depth=2048)
|
||||
endif()
|
||||
|
||||
target_link_libraries(tes3mp-server
|
||||
#${Boost_SYSTEM_LIBRARY}
|
||||
|
@ -182,9 +152,8 @@ target_link_libraries(tes3mp-server
|
|||
components
|
||||
${Terra_LIBRARY}
|
||||
${LUA_LIBRARIES}
|
||||
${Pawn_LIBRARY}
|
||||
${LUAJIT_LIBRARY}
|
||||
${Breakpad_Library}
|
||||
${CallFF_LIBRARY}
|
||||
)
|
||||
|
||||
if (UNIX)
|
||||
|
|
|
@ -2,13 +2,14 @@
|
|||
// Created by koncord on 18.02.17.
|
||||
//
|
||||
|
||||
#include "Cell.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include "Script/EventController.hpp"
|
||||
#include "Networking.hpp"
|
||||
|
||||
#include "Cell.hpp"
|
||||
#include "Player.hpp"
|
||||
#include "Script/Script.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -48,7 +49,8 @@ void Cell::addPlayer(Player *player)
|
|||
|
||||
LOG_APPEND(Log::LOG_INFO, "- Adding %s to Cell %s", player->npc.mName.c_str(), getDescription().c_str());
|
||||
|
||||
Script::Call<Script::CallbackIdentity("OnCellLoad")>(player->getId(), getDescription().c_str());
|
||||
|
||||
mwmp::Networking::get().getState().getEventCtrl().Call<CoreEvent::ON_CELL_LOAD>(player, getDescription());
|
||||
|
||||
players.push_back(player);
|
||||
}
|
||||
|
@ -69,7 +71,8 @@ void Cell::removePlayer(Player *player)
|
|||
|
||||
LOG_APPEND(Log::LOG_INFO, "- Removing %s from Cell %s", player->npc.mName.c_str(), getDescription().c_str());
|
||||
|
||||
Script::Call<Script::CallbackIdentity("OnCellUnload")>(player->getId(), getDescription().c_str());
|
||||
|
||||
mwmp::Networking::get().getState().getEventCtrl().Call<CoreEvent::ON_CELL_UNLOAD>(player, getDescription());
|
||||
|
||||
players.erase(it);
|
||||
return;
|
||||
|
@ -81,27 +84,27 @@ void Cell::readActorList(unsigned char packetID, const mwmp::BaseActorList *newA
|
|||
{
|
||||
for (unsigned int i = 0; i < newActorList->count; i++)
|
||||
{
|
||||
mwmp::BaseActor newActor = newActorList->baseActors.at(i);
|
||||
auto &newActor = newActorList->baseActors.at(i);
|
||||
mwmp::BaseActor *cellActor;
|
||||
|
||||
if (containsActor(newActor.refNumIndex, newActor.mpNum))
|
||||
if (containsActor(newActor->refNumIndex, newActor->mpNum))
|
||||
{
|
||||
cellActor = getActor(newActor.refNumIndex, newActor.mpNum);
|
||||
cellActor = getActor(newActor->refNumIndex, newActor->mpNum);
|
||||
|
||||
switch (packetID)
|
||||
{
|
||||
case ID_ACTOR_POSITION:
|
||||
|
||||
cellActor->hasPositionData = true;
|
||||
cellActor->position = newActor.position;
|
||||
cellActor->position = newActor->position;
|
||||
break;
|
||||
|
||||
case ID_ACTOR_STATS_DYNAMIC:
|
||||
|
||||
cellActor->hasStatsDynamicData = true;
|
||||
cellActor->creatureStats.mDynamic[0] = newActor.creatureStats.mDynamic[0];
|
||||
cellActor->creatureStats.mDynamic[1] = newActor.creatureStats.mDynamic[1];
|
||||
cellActor->creatureStats.mDynamic[2] = newActor.creatureStats.mDynamic[2];
|
||||
cellActor->creatureStats.mDynamic[0] = newActor->creatureStats.mDynamic[0];
|
||||
cellActor->creatureStats.mDynamic[1] = newActor->creatureStats.mDynamic[1];
|
||||
cellActor->creatureStats.mDynamic[2] = newActor->creatureStats.mDynamic[2];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -116,9 +119,9 @@ bool Cell::containsActor(int refNumIndex, int mpNum)
|
|||
{
|
||||
for (unsigned int i = 0; i < cellActorList.baseActors.size(); i++)
|
||||
{
|
||||
mwmp::BaseActor actor = cellActorList.baseActors.at(i);
|
||||
auto &actor = cellActorList.baseActors.at(i);
|
||||
|
||||
if (actor.refNumIndex == refNumIndex && actor.mpNum == mpNum)
|
||||
if (actor->refNumIndex == refNumIndex && actor->mpNum == mpNum)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -128,28 +131,28 @@ mwmp::BaseActor *Cell::getActor(int refNumIndex, int mpNum)
|
|||
{
|
||||
for (unsigned int i = 0; i < cellActorList.baseActors.size(); i++)
|
||||
{
|
||||
mwmp::BaseActor *actor = &cellActorList.baseActors.at(i);
|
||||
auto &actor = cellActorList.baseActors.at(i);
|
||||
|
||||
if (actor->refNumIndex == refNumIndex && actor->mpNum == mpNum)
|
||||
return actor;
|
||||
return actor.get();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Cell::removeActors(const mwmp::BaseActorList *newActorList)
|
||||
{
|
||||
for (std::vector<mwmp::BaseActor>::iterator it = cellActorList.baseActors.begin(); it != cellActorList.baseActors.end();)
|
||||
for (auto it = cellActorList.baseActors.begin(); it != cellActorList.baseActors.end();)
|
||||
{
|
||||
int refNumIndex = (*it).refNumIndex;
|
||||
int mpNum = (*it).mpNum;
|
||||
int refNumIndex = (*it)->refNumIndex;
|
||||
int mpNum = (*it)->mpNum;
|
||||
|
||||
bool foundActor = false;
|
||||
|
||||
for (unsigned int i = 0; i < newActorList->count; i++)
|
||||
{
|
||||
mwmp::BaseActor newActor = newActorList->baseActors.at(i);
|
||||
auto &newActor = newActorList->baseActors.at(i);
|
||||
|
||||
if (newActor.refNumIndex == refNumIndex && newActor.mpNum == mpNum)
|
||||
if (newActor->refNumIndex == refNumIndex && newActor->mpNum == mpNum)
|
||||
{
|
||||
it = cellActorList.baseActors.erase(it);
|
||||
foundActor = true;
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
#include "CellController.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <apps/openmw-mp/Script/EventController.hpp>
|
||||
#include "Networking.hpp"
|
||||
|
||||
#include "CellController.hpp"
|
||||
#include "Cell.hpp"
|
||||
#include "Player.hpp"
|
||||
#include "Script/Script.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -50,7 +52,7 @@ Cell *CellController::getCell(ESM::Cell *esmCell)
|
|||
|
||||
Cell *CellController::getCellByXY(int x, int y)
|
||||
{
|
||||
auto it = find_if(cells.begin(), cells.end(), [x, y](const Cell *c)
|
||||
auto it = find_if (cells.begin(), cells.end(), [x, y](const Cell *c)
|
||||
{
|
||||
return c->cell.mData.mX == x && c->cell.mData.mY == y;
|
||||
});
|
||||
|
@ -66,7 +68,7 @@ Cell *CellController::getCellByXY(int x, int y)
|
|||
|
||||
Cell *CellController::getCellByName(std::string cellName)
|
||||
{
|
||||
auto it = find_if(cells.begin(), cells.end(), [cellName](const Cell *c)
|
||||
auto it = find_if (cells.begin(), cells.end(), [cellName](const Cell *c)
|
||||
{
|
||||
return c->cell.mName == cellName;
|
||||
});
|
||||
|
@ -83,7 +85,7 @@ Cell *CellController::getCellByName(std::string cellName)
|
|||
Cell *CellController::addCell(ESM::Cell cellData)
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "- Loaded cells: %d", cells.size());
|
||||
auto it = find_if(cells.begin(), cells.end(), [cellData](const Cell *c) {
|
||||
auto it = find_if (cells.begin(), cells.end(), [cellData](const Cell *c) {
|
||||
// Currently we cannot compare because plugin lists can be loaded in different order
|
||||
//return c->cell.sRecordId == cellData.sRecordId;
|
||||
if (c->cell.isExterior() && cellData.isExterior())
|
||||
|
@ -123,7 +125,8 @@ void CellController::removeCell(Cell *cell)
|
|||
{
|
||||
if (*it != nullptr && *it == cell)
|
||||
{
|
||||
Script::Call<Script::CallbackIdentity("OnCellDeletion")>(cell->getDescription().c_str());
|
||||
mwmp::Networking::get().getState().getEventCtrl().Call<CoreEvent::ON_CELL_DELETION>(cell->getDescription());
|
||||
|
||||
LOG_APPEND(Log::LOG_INFO, "- Removing %s from CellController", cell->getDescription().c_str());
|
||||
|
||||
delete *it;
|
||||
|
|
30
apps/openmw-mp/CellState.cpp
Normal file
30
apps/openmw-mp/CellState.cpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// Created by koncord on 25.08.17.
|
||||
//
|
||||
|
||||
#include "Script/LuaState.hpp"
|
||||
|
||||
#include "CellState.hpp"
|
||||
|
||||
void CellState::Init(LuaState &lua)
|
||||
{
|
||||
lua.getState()->new_usertype<CellState>("CellState",
|
||||
"type", sol::property(&CellState::getStateType),
|
||||
"description", sol::property(&CellState::getDescription)
|
||||
);
|
||||
}
|
||||
|
||||
CellState::CellState(mwmp::CellState state) : state(state)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int CellState::getStateType() const
|
||||
{
|
||||
return state.type;
|
||||
}
|
||||
|
||||
std::string CellState::getDescription() const
|
||||
{
|
||||
return state.cell.getDescription();
|
||||
}
|
24
apps/openmw-mp/CellState.hpp
Normal file
24
apps/openmw-mp/CellState.hpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// Created by koncord on 25.08.17.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <components/openmw-mp/Base/BasePlayer.hpp>
|
||||
|
||||
class LuaState;
|
||||
|
||||
class CellState
|
||||
{
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
|
||||
explicit CellState(mwmp::CellState state);
|
||||
public:
|
||||
int getStateType() const;
|
||||
std::string getDescription() const;
|
||||
|
||||
private:
|
||||
mwmp::CellState state;
|
||||
};
|
100
apps/openmw-mp/Cells.cpp
Normal file
100
apps/openmw-mp/Cells.cpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
//
|
||||
// Created by koncord on 25.08.17.
|
||||
//
|
||||
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
#include "Script/LuaState.hpp"
|
||||
#include "Networking.hpp"
|
||||
|
||||
#include "Cells.hpp"
|
||||
#include "NetActor.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void Cells::Init(LuaState &lua)
|
||||
{
|
||||
lua.getState()->new_usertype<Cells>("Cell",
|
||||
"description", sol::property(&Cells::getDescription, &Cells::setDescription),
|
||||
"getExterior", &Cells::getExterior,
|
||||
"setExterior", &Cells::setExterior,
|
||||
"getRegion", &Cells::getRegion,
|
||||
|
||||
"isExterior", &Cells::isExterior,
|
||||
"isChangingRegion", &Cells::isChangingRegion
|
||||
);
|
||||
}
|
||||
|
||||
Cells::Cells(NetActor *netActor) : netActor(netActor), changedCell(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Cells::~Cells()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Cells::update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::string Cells::getDescription() const
|
||||
{
|
||||
return netActor->getNetCreature()->cell.getDescription();
|
||||
}
|
||||
|
||||
void Cells::setDescription(const std::string &cellDescription)
|
||||
{
|
||||
/*LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Script is moving %s from %s to %s", netActor->getNetCreature()->npc.mName.c_str(),
|
||||
netActor->getNetCreature()->cell.getDescription().c_str(), cellDescription.c_str());*/
|
||||
|
||||
netActor->getNetCreature()->cell = Utils::getCellFromDescription(cellDescription);
|
||||
changedCell = true;
|
||||
}
|
||||
|
||||
std::tuple<int, int> Cells::getExterior() const
|
||||
{
|
||||
return make_tuple(netActor->getNetCreature()->cell.mData.mX, netActor->getNetCreature()->cell.mData.mY);
|
||||
}
|
||||
|
||||
void Cells::setExterior(int x, int y)
|
||||
{
|
||||
/*LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Script is moving %s from %s to %i,%i", netActor->getNetCreature()->npc.mName.c_str(),
|
||||
netActor->getNetCreature()->cell.getDescription().c_str(), x, y);*/
|
||||
|
||||
// If the player is currently in an interior, turn off the interior flag from the cell
|
||||
if (!netActor->getNetCreature()->cell.isExterior())
|
||||
netActor->getNetCreature()->cell.mData.mFlags &= ~ESM::Cell::Interior;
|
||||
|
||||
netActor->getNetCreature()->cell.mData.mX = x;
|
||||
netActor->getNetCreature()->cell.mData.mY = y;
|
||||
changedCell = true;
|
||||
}
|
||||
|
||||
bool Cells::isExterior() const
|
||||
{
|
||||
return netActor->getNetCreature()->cell.isExterior();
|
||||
}
|
||||
|
||||
bool Cells::isChangingRegion() const
|
||||
{
|
||||
return netActor->getNetCreature()->isChangingRegion;
|
||||
}
|
||||
|
||||
std::string Cells::getRegion() const
|
||||
{
|
||||
return netActor->getNetCreature()->cell.mRegion;
|
||||
}
|
||||
|
||||
bool Cells::isChangedCell() const
|
||||
{
|
||||
return changedCell;
|
||||
}
|
||||
|
||||
void Cells::resetChangedCell()
|
||||
{
|
||||
changedCell = false;
|
||||
}
|
||||
|
43
apps/openmw-mp/Cells.hpp
Normal file
43
apps/openmw-mp/Cells.hpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
//
|
||||
// Created by koncord on 25.08.17.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <components/openmw-mp/Base/BasePlayer.hpp>
|
||||
|
||||
class LuaState;
|
||||
class NetActor;
|
||||
|
||||
class Cells
|
||||
{
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
public:
|
||||
explicit Cells(NetActor *netActor);
|
||||
~Cells();
|
||||
|
||||
void update();
|
||||
|
||||
std::string getDescription() const;
|
||||
void setDescription(const std::string &cellDescription);
|
||||
|
||||
std::tuple<int, int> getExterior() const;
|
||||
void setExterior(int x, int y);
|
||||
|
||||
bool isExterior() const;
|
||||
bool isChangingRegion() const;
|
||||
|
||||
std::string getRegion() const;
|
||||
|
||||
bool isChangedCell() const;
|
||||
void resetChangedCell();
|
||||
|
||||
private:
|
||||
NetActor *netActor;
|
||||
bool changedCell;
|
||||
};
|
||||
|
||||
|
156
apps/openmw-mp/CharClass.cpp
Normal file
156
apps/openmw-mp/CharClass.cpp
Normal file
|
@ -0,0 +1,156 @@
|
|||
//
|
||||
// Created by koncord on 12.08.17.
|
||||
//
|
||||
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
#include "Script/LuaState.hpp"
|
||||
#include "Networking.hpp"
|
||||
|
||||
#include "CharClass.hpp"
|
||||
#include "Player.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void CharClass::Init(LuaState &lua)
|
||||
{
|
||||
lua.getState()->new_usertype<CharClass>("Class",
|
||||
//"__gc", sol::destructor(deleter),
|
||||
"default", sol::property(&CharClass::getDefault, &CharClass::setDefault),
|
||||
"isCustom", &CharClass::isCustom,
|
||||
|
||||
"name", sol::property(&CharClass::getName, &CharClass::setName),
|
||||
"description", sol::property(&CharClass::getDescription, &CharClass::setDescription),
|
||||
"specialization",
|
||||
sol::property(&CharClass::getSpecialization, &CharClass::setSpecialization),
|
||||
|
||||
"getMajorAttributes", &CharClass::getMajorAttributes,
|
||||
"setMajorAttributes", &CharClass::setMajorAttributes,
|
||||
|
||||
"getMinorSkills", &CharClass::getMinorSkills,
|
||||
"setMinorSkills", &CharClass::setMinorSkills,
|
||||
|
||||
"getMajorSkills", &CharClass::getMajorSkills,
|
||||
"setMajorSkills", &CharClass::setMajorSkills
|
||||
);
|
||||
}
|
||||
|
||||
CharClass::CharClass(Player *player) : player(player), changed(false)
|
||||
{
|
||||
printf("CharClass::CharClass()\n");
|
||||
}
|
||||
|
||||
CharClass::~CharClass()
|
||||
{
|
||||
printf("CharClass::~CharClass()\n");
|
||||
}
|
||||
|
||||
string CharClass::getDefault() const
|
||||
{
|
||||
return player->charClass.mId;
|
||||
}
|
||||
|
||||
void CharClass::setDefault(const string &className)
|
||||
{
|
||||
player->charClass.mId = className;
|
||||
changed = true;
|
||||
printf("CharClass::setDefault()\n");
|
||||
}
|
||||
|
||||
bool CharClass::isCustom() const
|
||||
{
|
||||
return player->charClass.mId.empty();
|
||||
}
|
||||
|
||||
void CharClass::setName(const string &className)
|
||||
{
|
||||
player->charClass.mName = className;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
string CharClass::getName() const
|
||||
{
|
||||
return player->charClass.mName;
|
||||
}
|
||||
|
||||
std::string CharClass::getDescription() const
|
||||
{
|
||||
return player->charClass.mDescription;
|
||||
}
|
||||
|
||||
void CharClass::setDescription(const string &desc)
|
||||
{
|
||||
player->charClass.mDescription = desc;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
std::tuple<int, int> CharClass::getMajorAttributes() const
|
||||
{
|
||||
const auto &data = player->charClass.mData;
|
||||
return make_tuple(data.mAttribute[0], data.mAttribute[1]);
|
||||
}
|
||||
|
||||
void CharClass::setMajorAttributes(int first, int second)
|
||||
{
|
||||
auto &data = player->charClass.mData;
|
||||
data.mAttribute[0] = first;
|
||||
data.mAttribute[1] = second;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
int CharClass::getSpecialization() const
|
||||
{
|
||||
return player->charClass.mData.mSpecialization;
|
||||
}
|
||||
|
||||
void CharClass::setSpecialization(int spec)
|
||||
{
|
||||
auto &data = player->charClass.mData;
|
||||
data.mSpecialization = spec;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
std::tuple<int, int, int, int, int> CharClass::getMinorSkills() const
|
||||
{
|
||||
const auto &data = player->charClass.mData;
|
||||
return make_tuple( data.mSkills[0][0], data.mSkills[1][0], data.mSkills[2][0], data.mSkills[3][0], data.mSkills[4][0]);
|
||||
}
|
||||
|
||||
void CharClass::setMinorSkills(int first, int second, int third, int fourth, int fifth)
|
||||
{
|
||||
auto &data = player->charClass.mData;
|
||||
data.mSkills[0][0] = first;
|
||||
data.mSkills[1][0] = second;
|
||||
data.mSkills[2][0] = third;
|
||||
data.mSkills[3][0] = fourth;
|
||||
data.mSkills[4][0] = fifth;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
std::tuple<int, int, int, int, int> CharClass::getMajorSkills() const
|
||||
{
|
||||
const auto &data = player->charClass.mData;
|
||||
return make_tuple( data.mSkills[0][1], data.mSkills[1][1], data.mSkills[2][1], data.mSkills[3][1], data.mSkills[4][1]);
|
||||
}
|
||||
|
||||
void CharClass::setMajorSkills(int first, int second, int third, int fourth, int fifth)
|
||||
{
|
||||
auto &data = player->charClass.mData;
|
||||
data.mSkills[0][1] = first;
|
||||
data.mSkills[1][1] = second;
|
||||
data.mSkills[2][1] = third;
|
||||
data.mSkills[3][1] = fourth;
|
||||
data.mSkills[4][1] = fifth;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
void CharClass::update()
|
||||
{
|
||||
if (!changed)
|
||||
return;
|
||||
changed = false;
|
||||
printf("CharClass::update()\n");
|
||||
auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_CHARCLASS);
|
||||
packet->setPlayer(player);
|
||||
packet->Send(false);
|
||||
}
|
50
apps/openmw-mp/CharClass.hpp
Normal file
50
apps/openmw-mp/CharClass.hpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
// Created by koncord on 12.08.17.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
class LuaState;
|
||||
class Player;
|
||||
|
||||
class CharClass
|
||||
{
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
|
||||
public:
|
||||
explicit CharClass(Player *player);
|
||||
~CharClass();
|
||||
void update();
|
||||
|
||||
std::string getDefault() const;
|
||||
void setDefault(const std::string &className);
|
||||
bool isCustom() const;
|
||||
|
||||
std::string getName() const;
|
||||
void setName(const std::string &className);
|
||||
|
||||
std::string getDescription() const;
|
||||
void setDescription(const std::string &desc);
|
||||
|
||||
std::tuple<int, int> getMajorAttributes() const;
|
||||
void setMajorAttributes(int first, int second);
|
||||
|
||||
int getSpecialization() const;
|
||||
void setSpecialization(int spec);
|
||||
|
||||
std::tuple<int, int, int, int, int> getMinorSkills() const;
|
||||
void setMinorSkills(int fisrt, int second, int third, int fourth, int fifth);
|
||||
|
||||
std::tuple<int, int, int, int, int> getMajorSkills() const;
|
||||
void setMajorSkills(int fisrt, int second, int third, int fourth, int fifth);
|
||||
private:
|
||||
// not controlled pointer
|
||||
Player *player;
|
||||
bool changed;
|
||||
};
|
||||
|
||||
|
63
apps/openmw-mp/Dialogue.cpp
Normal file
63
apps/openmw-mp/Dialogue.cpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// Created by koncord on 15.08.17.
|
||||
//
|
||||
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
#include "Script/LuaState.hpp"
|
||||
#include "Networking.hpp"
|
||||
|
||||
#include "Dialogue.hpp"
|
||||
#include "Player.hpp"
|
||||
|
||||
void Dialogue::Init(LuaState &lua)
|
||||
{
|
||||
lua.getState()->new_usertype<Dialogue>("Dialogue",
|
||||
"addTopic", &Dialogue::addTopic,
|
||||
"getTopicId", &Dialogue::getTopicId,
|
||||
"getChanges", &Dialogue::getChanges,
|
||||
"reset", &Dialogue::reset);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Dialogue::Dialogue(Player *player) : player(player), changed(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Dialogue::reset()
|
||||
{
|
||||
player->topicChanges.topics.clear();
|
||||
}
|
||||
|
||||
void Dialogue::update()
|
||||
{
|
||||
if (!changed)
|
||||
return;
|
||||
changed = false;
|
||||
|
||||
auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_TOPIC);
|
||||
|
||||
packet->setPlayer(player);
|
||||
packet->Send(/*toOthers*/ false);
|
||||
}
|
||||
|
||||
void Dialogue::addTopic(const std::string &topicId)
|
||||
{
|
||||
if (!changed)
|
||||
reset();
|
||||
changed = true;
|
||||
player->topicChanges.topics.push_back({topicId});
|
||||
}
|
||||
|
||||
std::string Dialogue::getTopicId(unsigned int i) const
|
||||
{
|
||||
return player->topicChanges.topics.at(i).topicId;
|
||||
}
|
||||
|
||||
unsigned int Dialogue::getChanges() const
|
||||
{
|
||||
return player->topicChanges.topics.size();
|
||||
}
|
30
apps/openmw-mp/Dialogue.hpp
Normal file
30
apps/openmw-mp/Dialogue.hpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// Created by koncord on 15.08.17.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
class LuaState;
|
||||
class Player;
|
||||
|
||||
class Dialogue
|
||||
{
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
public:
|
||||
explicit Dialogue(Player *player);
|
||||
|
||||
void addTopic(const std::string &topicId);
|
||||
std::string getTopicId(unsigned int i) const;
|
||||
unsigned int getChanges() const;
|
||||
|
||||
void reset();
|
||||
void update();
|
||||
private:
|
||||
Player *player;
|
||||
bool changed;
|
||||
};
|
||||
|
||||
|
155
apps/openmw-mp/Factions.cpp
Normal file
155
apps/openmw-mp/Factions.cpp
Normal file
|
@ -0,0 +1,155 @@
|
|||
//
|
||||
// Created by koncord on 17.08.17.
|
||||
//
|
||||
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
#include "Script/LuaState.hpp"
|
||||
#include "Networking.hpp"
|
||||
|
||||
#include "Factions.hpp"
|
||||
#include "Player.hpp"
|
||||
|
||||
void Factions::Init(LuaState &lua)
|
||||
{
|
||||
lua.getState()->new_usertype<Factions>("Factions",
|
||||
"addFaction", &Factions::addFaction,
|
||||
"changesAction", sol::property(&Factions::getFactionChangesAction, &Factions::setFactionChangesAction),
|
||||
"getFaction", &Factions::getFaction,
|
||||
"setFaction", &Factions::setFaction,
|
||||
"clear", &Factions::clear,
|
||||
"size", &Factions::size
|
||||
|
||||
);
|
||||
/*"InitializeFactionChanges", FactionFunctions::InitializeFactionChanges,
|
||||
"GetFactionChangesSize", FactionFunctions::GetFactionChangesSize,
|
||||
"GetFactionChangesAction", FactionFunctions::GetFactionChangesAction,
|
||||
"GetFactionId", FactionFunctions::GetFactionId,
|
||||
"GetFactionRank", FactionFunctions::GetFactionRank,
|
||||
"GetFactionExpulsionState", FactionFunctions::GetFactionExpulsionState,
|
||||
"GetFactionReputation", FactionFunctions::GetFactionReputation,
|
||||
"SetFactionChangesAction", FactionFunctions::SetFactionChangesAction,
|
||||
"SetFactionId", FactionFunctions::SetFactionId,
|
||||
"SetFactionRank", FactionFunctions::SetFactionRank,
|
||||
"SetFactionExpulsionState", FactionFunctions::SetFactionExpulsionState,
|
||||
"SetFactionReputation", FactionFunctions::SetFactionReputation,
|
||||
"AddFaction", FactionFunctions::AddFaction,
|
||||
"SendFactionChanges", FactionFunctions::SendFactionChanges*/
|
||||
}
|
||||
|
||||
Factions::Factions(Player *player): player(player), changed(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Factions::~Factions()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Factions::update()
|
||||
{
|
||||
if (!changed)
|
||||
return;
|
||||
changed = false;
|
||||
|
||||
auto packet =mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_FACTION);
|
||||
packet->setPlayer(player);
|
||||
packet->Send(/*toOthers*/ false);
|
||||
clear();
|
||||
}
|
||||
|
||||
int Factions::getFactionChangesAction() const
|
||||
{
|
||||
return player->factionChanges.action;
|
||||
}
|
||||
|
||||
void Factions::setFactionChangesAction(int action)
|
||||
{
|
||||
player->factionChanges.action = action;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
void Factions::addFaction(Faction faction)
|
||||
{
|
||||
player->factionChanges.factions.push_back(faction.faction);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
|
||||
Faction Factions::getFaction(int id) const
|
||||
{
|
||||
return Faction(player->factionChanges.factions.at(id));
|
||||
}
|
||||
|
||||
void Factions::setFaction(int id, Faction faction)
|
||||
{
|
||||
player->factionChanges.factions.at(id) = faction.faction;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
void Factions::clear()
|
||||
{
|
||||
player->factionChanges.factions.clear();
|
||||
changed = true;
|
||||
}
|
||||
|
||||
size_t Factions::size() const
|
||||
{
|
||||
return player->factionChanges.factions.size();
|
||||
}
|
||||
|
||||
void Faction::Init(LuaState &lua)
|
||||
{
|
||||
lua.getState()->new_usertype<Faction>("Faction",
|
||||
"factionId", sol::property(&Faction::getFactionId, &Faction::setFactionId),
|
||||
"rank", sol::property(&Faction::getFactionRank, &Faction::setFactionRank),
|
||||
"isExpelled", sol::property(&Faction::getFactionExpulsionState, &Faction::setFactionExpulsionState),
|
||||
"reputation", sol::property(&Faction::getFactionReputation, &Faction::setFactionReputation)
|
||||
);
|
||||
}
|
||||
|
||||
Faction::Faction(mwmp::Faction &faction): faction(faction)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::string Faction::getFactionId() const
|
||||
{
|
||||
return faction.factionId;
|
||||
}
|
||||
|
||||
void Faction::setFactionId(const std::string &factionId)
|
||||
{
|
||||
faction.factionId = factionId;
|
||||
}
|
||||
|
||||
int Faction::getFactionRank() const
|
||||
{
|
||||
return faction.rank;
|
||||
}
|
||||
|
||||
void Faction::setFactionRank(unsigned int rank)
|
||||
{
|
||||
faction.rank = rank;
|
||||
}
|
||||
|
||||
bool Faction::getFactionExpulsionState() const
|
||||
{
|
||||
return faction.isExpelled;
|
||||
}
|
||||
|
||||
void Faction::setFactionExpulsionState(bool expulsionState)
|
||||
{
|
||||
faction.isExpelled = expulsionState;
|
||||
}
|
||||
|
||||
int Faction::getFactionReputation() const
|
||||
{
|
||||
return faction.reputation;
|
||||
}
|
||||
|
||||
void Faction::setFactionReputation(int reputation)
|
||||
{
|
||||
faction.reputation = reputation;
|
||||
}
|
59
apps/openmw-mp/Factions.hpp
Normal file
59
apps/openmw-mp/Factions.hpp
Normal file
|
@ -0,0 +1,59 @@
|
|||
//
|
||||
// Created by koncord on 17.08.17.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <components/openmw-mp/Base/BasePlayer.hpp>
|
||||
|
||||
class LuaState;
|
||||
class Player;
|
||||
|
||||
class Faction
|
||||
{
|
||||
friend class Factions;
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
public:
|
||||
explicit Faction(mwmp::Faction &faction);
|
||||
|
||||
std::string getFactionId() const;
|
||||
void setFactionId(const std::string &factionId);
|
||||
|
||||
int getFactionRank() const;
|
||||
void setFactionRank(unsigned int rank);
|
||||
|
||||
bool getFactionExpulsionState() const;
|
||||
void setFactionExpulsionState(bool expulsionState);
|
||||
|
||||
int getFactionReputation() const;
|
||||
void setFactionReputation(int reputation);
|
||||
|
||||
mwmp::Faction faction;
|
||||
};
|
||||
|
||||
class Factions
|
||||
{
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
public:
|
||||
explicit Factions(Player *player);
|
||||
~Factions();
|
||||
|
||||
void update();
|
||||
|
||||
int getFactionChangesAction() const;
|
||||
void setFactionChangesAction(int action);
|
||||
|
||||
void addFaction(Faction faction);
|
||||
Faction getFaction(int id) const;
|
||||
void setFaction(int id, Faction faction);
|
||||
size_t size() const;
|
||||
void clear();
|
||||
|
||||
private:
|
||||
mwmp::Faction tempFaction;
|
||||
Player *player;
|
||||
bool changed;
|
||||
};
|
145
apps/openmw-mp/GUI.cpp
Normal file
145
apps/openmw-mp/GUI.cpp
Normal file
|
@ -0,0 +1,145 @@
|
|||
//
|
||||
// Created by koncord on 15.08.17.
|
||||
//
|
||||
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
#include "GUI.hpp"
|
||||
#include "Player.hpp"
|
||||
#include "Networking.hpp"
|
||||
|
||||
void GUI::Init(LuaState &lua)
|
||||
{
|
||||
lua.getState()->new_usertype<GUI>("GUI",
|
||||
"messageBox", &GUI::messageBox,
|
||||
"customMessageBox", &GUI::customMessageBox,
|
||||
"inputDialog", &GUI::inputDialog,
|
||||
"passwordDialog", &GUI::passwordDialog,
|
||||
"listBox", &GUI::listBox,
|
||||
"setMapVisibility", &GUI::setMapVisibility,
|
||||
"setMapVisibilityAll", &GUI::setMapVisibilityAll,
|
||||
"createWindow", &GUI::createWindow,
|
||||
"deleteWindow", &GUI::deleteWindow
|
||||
);
|
||||
Window::Init(lua);
|
||||
}
|
||||
|
||||
GUI::GUI(Player *player): player(player), changed(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
GUI::~GUI()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void GUI::update()
|
||||
{
|
||||
if (!changed)
|
||||
return;
|
||||
changed = false;
|
||||
|
||||
auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_GUI_MESSAGEBOX);
|
||||
packet->setPlayer(player);
|
||||
packet->Send(false);
|
||||
}
|
||||
|
||||
void GUI::messageBox(int id, const char *label)
|
||||
{
|
||||
player->guiMessageBox.id = id;
|
||||
player->guiMessageBox.label = label;
|
||||
player->guiMessageBox.type = Player::GUIMessageBox::MessageBox;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
void GUI::customMessageBox(int id, const char *label, const char *buttons)
|
||||
{
|
||||
player->guiMessageBox.id = id;
|
||||
player->guiMessageBox.label = label;
|
||||
player->guiMessageBox.buttons = buttons;
|
||||
player->guiMessageBox.type = Player::GUIMessageBox::CustomMessageBox;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
void GUI::inputDialog(int id, const char *label)
|
||||
{
|
||||
player->guiMessageBox.id = id;
|
||||
player->guiMessageBox.label = label;
|
||||
player->guiMessageBox.type = Player::GUIMessageBox::InputDialog;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
void GUI::passwordDialog(int id, const char *label, const char *note)
|
||||
{
|
||||
player->guiMessageBox.id = id;
|
||||
player->guiMessageBox.label = label;
|
||||
player->guiMessageBox.note = note;
|
||||
player->guiMessageBox.type = Player::GUIMessageBox::PasswordDialog;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
void GUI::listBox(int id, const char *label, const char *items)
|
||||
{
|
||||
player->guiMessageBox.id = id;
|
||||
player->guiMessageBox.label = label;
|
||||
player->guiMessageBox.data = items;
|
||||
player->guiMessageBox.type = Player::GUIMessageBox::ListBox;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
void GUI::setMapVisibility(unsigned short targetPID, unsigned short affectedPID, unsigned short state)
|
||||
{
|
||||
LOG_MESSAGE(Log::LOG_WARN, "stub");
|
||||
}
|
||||
|
||||
void GUI::setMapVisibilityAll(unsigned short targetPID, unsigned short state)
|
||||
{
|
||||
LOG_MESSAGE(Log::LOG_WARN, "stub");
|
||||
}
|
||||
|
||||
std::shared_ptr<Window> GUI::createWindow(short x, short y, sol::function fn, sol::this_environment te)
|
||||
{
|
||||
int id = 0;
|
||||
|
||||
for (auto &window : windows)
|
||||
{
|
||||
if (window.second == nullptr)
|
||||
{
|
||||
id = window.first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (id == 0)
|
||||
id = lastWindowId++;
|
||||
|
||||
auto window = std::make_shared<Window>(player, id);
|
||||
window->setSize(x, y);
|
||||
window->setCallback(fn);
|
||||
|
||||
windows[id] = window;
|
||||
return window;
|
||||
}
|
||||
|
||||
void GUI::deleteWindow(std::shared_ptr<Window> window)
|
||||
{
|
||||
auto it = windows.find(window->getID());
|
||||
if (it != windows.end())
|
||||
{
|
||||
it->second = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void GUI::onGUIWindowAction()
|
||||
{
|
||||
auto it = windows.find(player->guiWindow.id);
|
||||
if (it != windows.end() && it->second != nullptr)
|
||||
{
|
||||
it->second->call(player->guiWindow);
|
||||
}
|
||||
}
|
44
apps/openmw-mp/GUI.hpp
Normal file
44
apps/openmw-mp/GUI.hpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// Created by koncord on 15.08.17.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Window.hpp"
|
||||
|
||||
class LuaState;
|
||||
class Player;
|
||||
|
||||
class GUI
|
||||
{
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
public:
|
||||
explicit GUI(Player *player);
|
||||
~GUI();
|
||||
|
||||
void update();
|
||||
|
||||
void messageBox(int id, const char *label);
|
||||
|
||||
void customMessageBox(int id, const char *label, const char *buttons);
|
||||
void inputDialog(int id, const char *label);
|
||||
void passwordDialog(int id, const char *label, const char *note);
|
||||
|
||||
void listBox(int id, const char *label, const char *items);
|
||||
|
||||
//state 0 - disallow, 1 - allow
|
||||
void setMapVisibility(unsigned short targetPID, unsigned short affectedPID, unsigned short state);
|
||||
void setMapVisibilityAll(unsigned short targetPID, unsigned short state);
|
||||
|
||||
std::shared_ptr<Window> createWindow(short x, short y, sol::function fn, sol::this_environment te);
|
||||
void deleteWindow(std::shared_ptr<Window> window);
|
||||
void onGUIWindowAction();
|
||||
private:
|
||||
Player *player;
|
||||
bool changed;
|
||||
std::unordered_map<int, std::shared_ptr<Window>> windows;
|
||||
int lastWindowId;
|
||||
};
|
||||
|
||||
|
173
apps/openmw-mp/Inventory.cpp
Normal file
173
apps/openmw-mp/Inventory.cpp
Normal file
|
@ -0,0 +1,173 @@
|
|||
//
|
||||
// Created by koncord on 12.08.17.
|
||||
//
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
#include <apps/openmw/mwworld/inventorystore.hpp>
|
||||
|
||||
#include "Script/LuaState.hpp"
|
||||
#include "Networking.hpp"
|
||||
|
||||
#include "Inventory.hpp"
|
||||
#include "NetActor.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void Inventory::Init(LuaState &lua)
|
||||
{
|
||||
lua.getState()->new_usertype<Inventory>("Inventory",
|
||||
"getInventoryChangesSize", &Inventory::getChangesSize,
|
||||
"addItem", &Inventory::addItem,
|
||||
"removeItem", &Inventory::removeItem,
|
||||
"getInventoryItem", &Inventory::getInventoryItem,
|
||||
|
||||
"equipItem", &Inventory::equipItem,
|
||||
"unequipItem", &Inventory::unequipItem,
|
||||
"hasItemEquipped", &Inventory::hasItemEquipped,
|
||||
"getEquipmentItem", &Inventory::getEquipmentItem
|
||||
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
Inventory::Inventory(NetActor *actor) : netActor(actor), equipmentChanged(false), inventoryChanged(0)
|
||||
{
|
||||
printf("Inventory::Inventory()\n");
|
||||
}
|
||||
|
||||
Inventory::~Inventory()
|
||||
{
|
||||
printf("Inventory::~Inventory()\n");
|
||||
}
|
||||
|
||||
void Inventory::update()
|
||||
{
|
||||
printf("Inventory::update()");
|
||||
/*if (equipmentChanged)
|
||||
{
|
||||
auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_EQUIPMENT);
|
||||
packet->setPlayer(netActor->getNetCreature());
|
||||
packet->Send(false);
|
||||
packet->Send(true);
|
||||
}
|
||||
|
||||
if (inventoryChanged != 0)
|
||||
{
|
||||
auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_EQUIPMENT);
|
||||
packet->setPlayer(netActor->getNetCreature());
|
||||
packet->Send(false);
|
||||
}
|
||||
|
||||
equipmentChanged = false;
|
||||
inventoryChanged = 0;*/
|
||||
}
|
||||
|
||||
|
||||
void Inventory::InitializeInventoryChanges()
|
||||
{
|
||||
netActor->getNetCreature()->inventoryChanges.items.clear();
|
||||
netActor->getNetCreature()->inventoryChanges.action = mwmp::InventoryChanges::SET;
|
||||
}
|
||||
|
||||
int Inventory::getChangesSize() const
|
||||
{
|
||||
return netActor->getNetCreature()->inventoryChanges.items.size();
|
||||
}
|
||||
|
||||
void Inventory::equipItem(unsigned short slot, const std::string& refId, unsigned int count, int charge)
|
||||
{
|
||||
netActor->getNetCreature()->equipmentItems[slot].refId = refId;
|
||||
netActor->getNetCreature()->equipmentItems[slot].count = count;
|
||||
netActor->getNetCreature()->equipmentItems[slot].charge = charge;
|
||||
|
||||
if (!Utils::vectorContains(&netActor->getNetCreature()->equipmentIndexChanges, slot))
|
||||
netActor->getNetCreature()->equipmentIndexChanges.push_back(slot);
|
||||
|
||||
equipmentChanged = true;
|
||||
}
|
||||
|
||||
void Inventory::unequipItem( unsigned short slot)
|
||||
{
|
||||
equipItem(slot, "", 0, -1);
|
||||
}
|
||||
|
||||
|
||||
void Inventory::addItem(const std::string &refId, unsigned int count, int charge)
|
||||
{
|
||||
if (inventoryChanged == mwmp::InventoryChanges::REMOVE)
|
||||
return;
|
||||
if (inventoryChanged == 0)
|
||||
InitializeInventoryChanges();
|
||||
|
||||
mwmp::Item item;
|
||||
item.refId = refId;
|
||||
item.count = count;
|
||||
item.charge = charge;
|
||||
|
||||
netActor->getNetCreature()->inventoryChanges.items.push_back(item);
|
||||
netActor->getNetCreature()->inventoryChanges.action = mwmp::InventoryChanges::ADD;
|
||||
inventoryChanged = netActor->getNetCreature()->inventoryChanges.action;
|
||||
}
|
||||
|
||||
void Inventory::removeItem(const std::string &refId, unsigned short count)
|
||||
{
|
||||
if (inventoryChanged == mwmp::InventoryChanges::ADD)
|
||||
return;
|
||||
if (inventoryChanged == 0)
|
||||
InitializeInventoryChanges();
|
||||
|
||||
mwmp::Item item;
|
||||
item.refId = refId;
|
||||
item.count = count;
|
||||
|
||||
netActor->getNetCreature()->inventoryChanges.items.push_back(item);
|
||||
netActor->getNetCreature()->inventoryChanges.action = mwmp::InventoryChanges::REMOVE;
|
||||
inventoryChanged = netActor->getNetCreature()->inventoryChanges.action;
|
||||
}
|
||||
|
||||
bool Inventory::hasItemEquipped(const std::string &refId) const
|
||||
{
|
||||
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; slot++)
|
||||
if (Misc::StringUtils::ciEqual(netActor->getNetCreature()->equipmentItems[slot].refId, refId))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::tuple<std::string, int, int> Inventory::getEquipmentItem(unsigned short slot) const
|
||||
{
|
||||
const auto &item = netActor->getNetCreature()->equipmentItems[slot];
|
||||
return make_tuple(item.refId, item.count, item.charge);
|
||||
}
|
||||
|
||||
std::tuple<std::string, int, int> Inventory::getInventoryItem(unsigned int slot) const
|
||||
{
|
||||
const auto &item = netActor->getNetCreature()->inventoryChanges.items.at(slot);
|
||||
return make_tuple(item.refId, item.count, item.charge);
|
||||
}
|
||||
|
||||
void Inventory::resetEquipmentFlag()
|
||||
{
|
||||
equipmentChanged = false;
|
||||
|
||||
netActor->getNetCreature()->equipmentIndexChanges.clear();
|
||||
}
|
||||
|
||||
bool Inventory::isEquipmentChanged()
|
||||
{
|
||||
return equipmentChanged;
|
||||
}
|
||||
|
||||
void Inventory::resetInventoryFlag()
|
||||
{
|
||||
inventoryChanged = 0;
|
||||
}
|
||||
|
||||
int Inventory::inventoryChangeType()
|
||||
{
|
||||
return inventoryChanged;
|
||||
}
|
||||
|
||||
|
||||
|
63
apps/openmw-mp/Inventory.hpp
Normal file
63
apps/openmw-mp/Inventory.hpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// Created by koncord on 12.08.17.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
class LuaState;
|
||||
class NetActor;
|
||||
|
||||
class Inventory
|
||||
{
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
bool isEquipmentChanged();
|
||||
void resetEquipmentFlag();
|
||||
int inventoryChangeType();
|
||||
void resetInventoryFlag();
|
||||
public:
|
||||
explicit Inventory(NetActor *netActor);
|
||||
~Inventory();
|
||||
void update();
|
||||
|
||||
//inventory
|
||||
int getChangesSize() const;
|
||||
void addItem(const std::string& refId, unsigned int count, int charge);
|
||||
void removeItem(const std::string& refId, unsigned short count);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param slot
|
||||
* @return refid, count, charge
|
||||
*/
|
||||
std::tuple<std::string,int, int> getInventoryItem(unsigned int slot) const;
|
||||
|
||||
|
||||
// equipment
|
||||
void equipItem(unsigned short slot, const std::string& refId, unsigned int count, int charge);
|
||||
void unequipItem(unsigned short slot);
|
||||
|
||||
bool hasItemEquipped(const std::string& refId) const;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param slot
|
||||
* @return refid, count, charge
|
||||
*/
|
||||
std::tuple<std::string,int, int> getEquipmentItem(unsigned short slot) const;
|
||||
|
||||
|
||||
private:
|
||||
void InitializeInventoryChanges();
|
||||
|
||||
private:
|
||||
// not controlled pointer
|
||||
NetActor *netActor;
|
||||
bool equipmentChanged;
|
||||
int inventoryChanged;
|
||||
};
|
||||
|
||||
|
|
@ -2,18 +2,23 @@
|
|||
// Created by koncord on 14.08.16.
|
||||
//
|
||||
|
||||
#include <RakSleep.h>
|
||||
#include <Getche.h>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
#include <Getche.h>
|
||||
#include <RakPeerInterface.h>
|
||||
#include "MasterClient.hpp"
|
||||
#include <RakSleep.h>
|
||||
|
||||
#include <components/openmw-mp/Log.hpp>
|
||||
#include <components/openmw-mp/Version.hpp>
|
||||
#include <components/openmw-mp/Master/PacketMasterAnnounce.hpp>
|
||||
|
||||
#include "MasterClient.hpp"
|
||||
#include "Networking.hpp"
|
||||
|
||||
#include "Players.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace mwmp;
|
||||
using namespace RakNet;
|
||||
|
@ -32,7 +37,7 @@ MasterClient::MasterClient(RakNet::RakPeerInterface *peer, std::string queryAddr
|
|||
void MasterClient::SetPlayers(unsigned pl)
|
||||
{
|
||||
mutexData.lock();
|
||||
if (queryData.GetPlayers() != pl)
|
||||
if ((unsigned) queryData.GetPlayers() != pl)
|
||||
{
|
||||
queryData.SetPlayers(pl);
|
||||
updated = true;
|
||||
|
@ -43,7 +48,7 @@ void MasterClient::SetPlayers(unsigned pl)
|
|||
void MasterClient::SetMaxPlayers(unsigned pl)
|
||||
{
|
||||
mutexData.lock();
|
||||
if (queryData.GetMaxPlayers() != pl)
|
||||
if ((unsigned) queryData.GetMaxPlayers() != pl)
|
||||
{
|
||||
queryData.SetMaxPlayers(pl);
|
||||
updated = true;
|
||||
|
@ -108,7 +113,7 @@ void MasterClient::SetRuleValue(std::string key, double value)
|
|||
void MasterClient::PushPlugin(Plugin plugin)
|
||||
{
|
||||
mutexData.lock();
|
||||
queryData.plugins.push_back(plugin);
|
||||
queryData.plugins.push_back(move(plugin));
|
||||
updated = true;
|
||||
mutexData.unlock();
|
||||
}
|
||||
|
@ -128,6 +133,10 @@ bool MasterClient::Process(RakNet::Packet *packet)
|
|||
case ID_CONNECTION_REQUEST_ACCEPTED:
|
||||
case ID_DISCONNECTION_NOTIFICATION:
|
||||
break;
|
||||
case ID_CONNECTION_BANNED:
|
||||
Stop();
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_FATAL, "Your server was banned on the master server. Contact the master server administrator for details.");
|
||||
break;
|
||||
case ID_MASTER_QUERY:
|
||||
break;
|
||||
case ID_MASTER_ANNOUNCE:
|
||||
|
@ -148,7 +157,7 @@ bool MasterClient::Process(RakNet::Packet *packet)
|
|||
}
|
||||
break;
|
||||
default:
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Received wrong packet from master server with id: %d", packet->data[0]);
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_ERROR, "Received wrong packet from master server with id: %d", (int) packet->data[0]);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -195,22 +204,22 @@ void MasterClient::Thread()
|
|||
queryData.SetPassword((int) Networking::get().isPassworded());
|
||||
queryData.SetVersion(TES3MP_VERSION);
|
||||
|
||||
auto *players = Players::getPlayers();
|
||||
//auto *players = Players::getPlayers();
|
||||
while (sRun)
|
||||
{
|
||||
SetPlayers((int) players->size());
|
||||
SetPlayers((unsigned) Players::size());
|
||||
|
||||
auto pIt = players->begin();
|
||||
if (queryData.players.size() != players->size())
|
||||
auto pIt = Players::begin();
|
||||
if (queryData.players.size() != Players::size())
|
||||
{
|
||||
queryData.players.clear();
|
||||
updated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; pIt != players->end(); i++, pIt++)
|
||||
for (int i = 0; pIt != Players::end(); i++, pIt++)
|
||||
{
|
||||
if (queryData.players[i] != pIt->second->npc.mName)
|
||||
if (queryData.players[i] != (*pIt)->npc.mName)
|
||||
{
|
||||
queryData.players.clear();
|
||||
updated = true;
|
||||
|
@ -222,13 +231,12 @@ void MasterClient::Thread()
|
|||
if (updated)
|
||||
{
|
||||
updated = false;
|
||||
if (pIt != players->end())
|
||||
if (pIt != Players::end())
|
||||
{
|
||||
for (auto player : *players)
|
||||
{
|
||||
if (!player.second->npc.mName.empty())
|
||||
queryData.players.push_back(player.second->npc.mName);
|
||||
}
|
||||
Players::for_each([this](auto player) {
|
||||
if (!player->npc.mName.empty())
|
||||
queryData.players.push_back(player->npc.mName);
|
||||
});
|
||||
}
|
||||
Send(PacketMasterAnnounce::FUNCTION_ANNOUNCE);
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <components/openmw-mp/Master/MasterData.hpp>
|
||||
#include <RakString.h>
|
||||
#include <components/openmw-mp/Master/PacketMasterAnnounce.hpp>
|
||||
#include <atomic>
|
||||
|
||||
class MasterClient
|
||||
{
|
||||
|
@ -46,7 +47,7 @@ private:
|
|||
std::thread thrQuery;
|
||||
mwmp::PacketMasterAnnounce pma;
|
||||
RakNet::BitStream writeStream;
|
||||
bool updated;
|
||||
std::atomic<bool> updated;
|
||||
};
|
||||
|
||||
|
||||
|
|
111
apps/openmw-mp/NetActor.cpp
Normal file
111
apps/openmw-mp/NetActor.cpp
Normal file
|
@ -0,0 +1,111 @@
|
|||
//
|
||||
// Created by koncord on 25.08.17.
|
||||
//
|
||||
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
#include <components/openmw-mp/Base/BaseNetCreature.hpp>
|
||||
|
||||
#include "Script/LuaState.hpp"
|
||||
#include "Networking.hpp"
|
||||
|
||||
#include "NetActor.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
NetActor::NetActor() : inventory(this), cellAPI(this)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void NetActor::resetUpdateFlags()
|
||||
{
|
||||
baseInfoChanged = false;
|
||||
levelChanged = false;
|
||||
statsChanged = false;
|
||||
positionChanged = false;
|
||||
skillsChanged = false;
|
||||
attributesChanged = false;
|
||||
}
|
||||
|
||||
std::tuple<float, float, float> NetActor::getPosition() const
|
||||
{
|
||||
return make_tuple(netCreature->position.pos[0], netCreature->position.pos[1], netCreature->position.pos[2]);
|
||||
}
|
||||
|
||||
void NetActor::setPosition(float x, float y, float z)
|
||||
{
|
||||
netCreature->position.pos[0] = x;
|
||||
netCreature->position.pos[1] = y;
|
||||
netCreature->position.pos[2] = z;
|
||||
positionChanged = true;
|
||||
}
|
||||
|
||||
std::tuple<float, float> NetActor::getRotation() const
|
||||
{
|
||||
return make_tuple(netCreature->position.rot[0], netCreature->position.rot[2]);
|
||||
}
|
||||
|
||||
void NetActor::setRotation(float x, float z)
|
||||
{
|
||||
netCreature->position.rot[0] = x;
|
||||
netCreature->position.rot[2] = z;
|
||||
positionChanged = true;
|
||||
}
|
||||
|
||||
std::tuple<float, float> NetActor::getHealth() const
|
||||
{
|
||||
return make_tuple(netCreature->creatureStats.mDynamic[0].mBase, netCreature->creatureStats.mDynamic[0].mCurrent);
|
||||
}
|
||||
|
||||
void NetActor::setHealth(float base, float current)
|
||||
{
|
||||
netCreature->creatureStats.mDynamic[0].mBase = base;
|
||||
netCreature->creatureStats.mDynamic[0].mCurrent = current;
|
||||
|
||||
if (!Utils::vectorContains(&netCreature->statsDynamicIndexChanges, 0))
|
||||
netCreature->statsDynamicIndexChanges.push_back(0);
|
||||
|
||||
statsChanged = true;
|
||||
}
|
||||
|
||||
std::tuple<float, float> NetActor::getMagicka() const
|
||||
{
|
||||
return make_tuple(netCreature->creatureStats.mDynamic[1].mBase, netCreature->creatureStats.mDynamic[1].mCurrent);
|
||||
}
|
||||
|
||||
void NetActor::setMagicka(float base, float current)
|
||||
{
|
||||
netCreature->creatureStats.mDynamic[1].mBase = base;
|
||||
netCreature->creatureStats.mDynamic[1].mCurrent = current;
|
||||
|
||||
if (!Utils::vectorContains(&netCreature->statsDynamicIndexChanges, 1))
|
||||
netCreature->statsDynamicIndexChanges.push_back(1);
|
||||
|
||||
statsChanged = true;
|
||||
}
|
||||
|
||||
std::tuple<float, float> NetActor::getFatigue() const
|
||||
{
|
||||
return make_tuple(netCreature->creatureStats.mDynamic[2].mBase, netCreature->creatureStats.mDynamic[2].mCurrent);
|
||||
}
|
||||
|
||||
void NetActor::setFatigue(float base, float current)
|
||||
{
|
||||
netCreature->creatureStats.mDynamic[2].mBase = base;
|
||||
netCreature->creatureStats.mDynamic[2].mCurrent = current;
|
||||
|
||||
if (!Utils::vectorContains(&netCreature->statsDynamicIndexChanges, 2))
|
||||
netCreature->statsDynamicIndexChanges.push_back(2);
|
||||
|
||||
statsChanged = true;
|
||||
}
|
||||
|
||||
Inventory &NetActor::getInventory()
|
||||
{
|
||||
return inventory;
|
||||
}
|
||||
|
||||
Cells &NetActor::getCell()
|
||||
{
|
||||
return cellAPI;
|
||||
}
|
75
apps/openmw-mp/NetActor.hpp
Normal file
75
apps/openmw-mp/NetActor.hpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
//
|
||||
// Created by koncord on 25.08.17.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <RakNetTypes.h>
|
||||
#include <tuple>
|
||||
#include "Inventory.hpp"
|
||||
#include "Cells.hpp"
|
||||
|
||||
namespace mwmp
|
||||
{
|
||||
class BasePlayer;
|
||||
class BaseNetCreature;
|
||||
class BaseActor;
|
||||
}
|
||||
|
||||
class NetActor
|
||||
{
|
||||
public:
|
||||
NetActor();
|
||||
|
||||
void resetUpdateFlags();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return x, y, z
|
||||
*/
|
||||
|
||||
std::tuple<float, float, float> getPosition() const;
|
||||
void setPosition(float x, float y, float z);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return x, y
|
||||
*/
|
||||
std::tuple<float, float> getRotation() const;
|
||||
void setRotation(float x, float z);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return base, current
|
||||
*/
|
||||
std::tuple<float, float> getHealth() const;
|
||||
void setHealth(float base, float current);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return base, current
|
||||
*/
|
||||
std::tuple<float, float> getMagicka() const;
|
||||
void setMagicka(float base, float current);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return base, current
|
||||
*/
|
||||
std::tuple<float, float> getFatigue() const;
|
||||
void setFatigue(float base, float current);
|
||||
|
||||
Inventory &getInventory();
|
||||
Cells &getCell();
|
||||
|
||||
mwmp::BaseNetCreature *getNetCreature() { return netCreature; }
|
||||
protected:
|
||||
bool baseInfoChanged, levelChanged, statsChanged, positionChanged, attributesChanged, skillsChanged;
|
||||
mwmp::BasePlayer *basePlayer;
|
||||
mwmp::BaseNetCreature *netCreature;
|
||||
|
||||
Inventory inventory;
|
||||
Cells cellAPI;
|
||||
};
|
||||
|
||||
|
|
@ -2,10 +2,12 @@
|
|||
// Created by koncord on 12.01.16.
|
||||
//
|
||||
|
||||
#include "Player.hpp"
|
||||
#include "processors/ProcessorInitializer.hpp"
|
||||
#include <RakPeer.h>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#include <Kbhit.h>
|
||||
#include <RakPeer.h>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
@ -13,24 +15,23 @@
|
|||
#include <components/openmw-mp/Version.hpp>
|
||||
#include <components/openmw-mp/Packets/PacketPreInit.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <Script/Script.hpp>
|
||||
#include <Script/API/TimerAPI.hpp>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "Networking.hpp"
|
||||
#include "MasterClient.hpp"
|
||||
#include "Cell.hpp"
|
||||
#include "CellController.hpp"
|
||||
#include <Script/EventController.hpp>
|
||||
#include "processors/ProcessorInitializer.hpp"
|
||||
#include "processors/PlayerProcessor.hpp"
|
||||
#include "processors/ActorProcessor.hpp"
|
||||
#include "processors/WorldProcessor.hpp"
|
||||
|
||||
#include "Networking.hpp"
|
||||
#include "MasterClient.hpp"
|
||||
|
||||
#include "Cell.hpp"
|
||||
#include "CellController.hpp"
|
||||
#include "Players.hpp"
|
||||
|
||||
using namespace mwmp;
|
||||
using namespace std;
|
||||
|
||||
Networking *Networking::sThis = 0;
|
||||
Networking *Networking::sThis = nullptr;
|
||||
|
||||
static int currentMpNum = 0;
|
||||
|
||||
|
@ -38,7 +39,6 @@ Networking::Networking(RakNet::RakPeerInterface *peer) : mclient(nullptr)
|
|||
{
|
||||
sThis = this;
|
||||
this->peer = peer;
|
||||
players = Players::getPlayers();
|
||||
|
||||
CellController::create();
|
||||
|
||||
|
@ -47,15 +47,13 @@ Networking::Networking(RakNet::RakPeerInterface *peer) : mclient(nullptr)
|
|||
worldPacketController = new WorldPacketController(peer);
|
||||
|
||||
// Set send stream
|
||||
playerPacketController->SetStream(0, &bsOut);
|
||||
actorPacketController->SetStream(0, &bsOut);
|
||||
worldPacketController->SetStream(0, &bsOut);
|
||||
playerPacketController->SetStream(nullptr, &bsOut);
|
||||
actorPacketController->SetStream(nullptr, &bsOut);
|
||||
worldPacketController->SetStream(nullptr, &bsOut);
|
||||
|
||||
running = true;
|
||||
exitCode = 0;
|
||||
|
||||
Script::Call<Script::CallbackIdentity("OnServerInit")>();
|
||||
|
||||
serverPassword = TES3MP_DEFAULT_PASSW;
|
||||
|
||||
ProcessorInitializer();
|
||||
|
@ -63,11 +61,11 @@ Networking::Networking(RakNet::RakPeerInterface *peer) : mclient(nullptr)
|
|||
|
||||
Networking::~Networking()
|
||||
{
|
||||
Script::Call<Script::CallbackIdentity("OnServerExit")>(false);
|
||||
luaState.getEventCtrl().Call<CoreEvent::ON_EXIT>(false);
|
||||
|
||||
CellController::destroy();
|
||||
|
||||
sThis = 0;
|
||||
sThis = nullptr;
|
||||
delete playerPacketController;
|
||||
delete actorPacketController;
|
||||
delete worldPacketController;
|
||||
|
@ -85,13 +83,13 @@ bool Networking::isPassworded() const
|
|||
|
||||
void Networking::processPlayerPacket(RakNet::Packet *packet)
|
||||
{
|
||||
Player *player = Players::getPlayer(packet->guid);
|
||||
auto player = Players::getPlayerByGUID(packet->guid);
|
||||
|
||||
PlayerPacket *myPacket = playerPacketController->GetPacket(packet->data[0]);
|
||||
|
||||
if (packet->data[0] == ID_HANDSHAKE)
|
||||
{
|
||||
myPacket->setPlayer(player);
|
||||
myPacket->setPlayer(player.get());
|
||||
myPacket->Read();
|
||||
|
||||
if (player->isHandshaked())
|
||||
|
@ -116,7 +114,8 @@ void Networking::processPlayerPacket(RakNet::Packet *packet)
|
|||
if (!player->isHandshaked())
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Have not completed handshake with player %d", player->getId());
|
||||
//KickPlayer(player->guid);
|
||||
if (player->handshakeAttempts() > 5)
|
||||
kickPlayer(player->guid);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -124,15 +123,14 @@ void Networking::processPlayerPacket(RakNet::Packet *packet)
|
|||
{
|
||||
player->setLoadState(Player::LOADED);
|
||||
|
||||
static constexpr unsigned int ident = Script::CallbackIdentity("OnPlayerConnect");
|
||||
Script::CallBackReturn<ident> result = true;
|
||||
Script::Call<ident>(result, Players::getPlayer(packet->guid)->getId());
|
||||
bool result = luaState.getEventCtrl().Call<CoreEvent::ON_PLAYER_CONNECT, bool>(player);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
playerPacketController->GetPacket(ID_USER_DISCONNECTED)->setPlayer(Players::getPlayer(packet->guid));
|
||||
LOG_MESSAGE(Log::LOG_TRACE, "Player \"%s\" Disconnected by ON_PLAYER_CONNECT event", player->getName().c_str());
|
||||
playerPacketController->GetPacket(ID_USER_DISCONNECTED)->setPlayer(player.get());
|
||||
playerPacketController->GetPacket(ID_USER_DISCONNECTED)->Send(false);
|
||||
Players::deletePlayer(packet->guid);
|
||||
Players::deletePlayerByGUID(packet->guid);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +138,7 @@ void Networking::processPlayerPacket(RakNet::Packet *packet)
|
|||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Received ID_PLAYER_BASEINFO about %s", player->npc.mName.c_str());
|
||||
|
||||
myPacket->setPlayer(player);
|
||||
myPacket->setPlayer(player.get());
|
||||
myPacket->Read();
|
||||
myPacket->Send(true);
|
||||
}
|
||||
|
@ -156,43 +154,43 @@ void Networking::processPlayerPacket(RakNet::Packet *packet)
|
|||
|
||||
|
||||
if (!PlayerProcessor::Process(*packet))
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Unhandled PlayerPacket with identifier %i has arrived", packet->data[0]);
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Unhandled PlayerPacket with identifier %i has arrived", (int) packet->data[0]);
|
||||
|
||||
}
|
||||
|
||||
void Networking::processActorPacket(RakNet::Packet *packet)
|
||||
{
|
||||
Player *player = Players::getPlayer(packet->guid);
|
||||
auto player = Players::getPlayerByGUID(packet->guid);
|
||||
|
||||
if (!player->isHandshaked() || player->getLoadState() != Player::POSTLOADED)
|
||||
return;
|
||||
|
||||
if (!ActorProcessor::Process(*packet, baseActorList))
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Unhandled ActorPacket with identifier %i has arrived", packet->data[0]);
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Unhandled ActorPacket with identifier %i has arrived", (int) packet->data[0]);
|
||||
|
||||
}
|
||||
|
||||
void Networking::processWorldPacket(RakNet::Packet *packet)
|
||||
{
|
||||
Player *player = Players::getPlayer(packet->guid);
|
||||
auto player = Players::getPlayerByGUID(packet->guid);
|
||||
|
||||
if (!player->isHandshaked() || player->getLoadState() != Player::POSTLOADED)
|
||||
return;
|
||||
|
||||
if (!WorldProcessor::Process(*packet, baseEvent))
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Unhandled WorldPacket with identifier %i has arrived", packet->data[0]);
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Unhandled WorldPacket with identifier %i has arrived", (int) packet->data[0]);
|
||||
|
||||
}
|
||||
|
||||
void Networking::update(RakNet::Packet *packet)
|
||||
bool Networking::update(RakNet::Packet *packet)
|
||||
{
|
||||
Player *player = Players::getPlayer(packet->guid);
|
||||
auto player = Players::getPlayerByGUID(packet->guid);
|
||||
|
||||
RakNet::BitStream bsIn(&packet->data[1], packet->length, false);
|
||||
|
||||
bsIn.IgnoreBytes((unsigned int) RakNet::RakNetGUID::size()); // Ignore GUID from received packet
|
||||
|
||||
if (player == 0)
|
||||
if (player == nullptr)
|
||||
{
|
||||
if (packet->data[0] == ID_GAME_PREINIT)
|
||||
{
|
||||
|
@ -222,7 +220,6 @@ void Networking::update(RakNet::Packet *packet)
|
|||
// the server
|
||||
if (it == hashList.end())
|
||||
break;
|
||||
|
||||
}
|
||||
else // name is incorrect
|
||||
break;
|
||||
|
@ -244,33 +241,39 @@ void Networking::update(RakNet::Packet *packet)
|
|||
packetPreInit.setChecksums(&tmp);
|
||||
packetPreInit.Send(packet->systemAddress);
|
||||
}
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
playerPacketController->SetStream(&bsIn, 0);
|
||||
playerPacketController->SetStream(&bsIn, nullptr);
|
||||
|
||||
playerPacketController->GetPacket(ID_HANDSHAKE)->RequestData(packet->guid);
|
||||
Players::newPlayer(packet->guid);
|
||||
player = Players::getPlayer(packet->guid);
|
||||
return;
|
||||
player = Players::addPlayer(packet->guid);
|
||||
return false;
|
||||
}
|
||||
else if (playerPacketController->ContainsPacket(packet->data[0]))
|
||||
|
||||
if (playerPacketController->ContainsPacket(packet->data[0]))
|
||||
{
|
||||
playerPacketController->SetStream(&bsIn, 0);
|
||||
playerPacketController->SetStream(&bsIn, nullptr);
|
||||
processPlayerPacket(packet);
|
||||
return true;
|
||||
}
|
||||
else if (actorPacketController->ContainsPacket(packet->data[0]))
|
||||
|
||||
if (actorPacketController->ContainsPacket(packet->data[0]))
|
||||
{
|
||||
actorPacketController->SetStream(&bsIn, 0);
|
||||
actorPacketController->SetStream(&bsIn, nullptr);
|
||||
processActorPacket(packet);
|
||||
return true;
|
||||
}
|
||||
else if (worldPacketController->ContainsPacket(packet->data[0]))
|
||||
|
||||
if (worldPacketController->ContainsPacket(packet->data[0]))
|
||||
{
|
||||
worldPacketController->SetStream(&bsIn, 0);
|
||||
worldPacketController->SetStream(&bsIn, nullptr);
|
||||
processWorldPacket(packet);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Unhandled RakNet packet with identifier %i has arrived", packet->data[0]);
|
||||
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Unhandled RakNet packet with identifier %i has arrived", (int) packet->data[0]);
|
||||
return false;
|
||||
}
|
||||
|
||||
void Networking::newPlayer(RakNet::RakNetGUID guid)
|
||||
|
@ -283,27 +286,24 @@ void Networking::newPlayer(RakNet::RakNetGUID guid)
|
|||
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_WARN, "Sending info about other players to %lu", guid.g);
|
||||
|
||||
for (TPlayers::iterator pl = players->begin(); pl != players->end(); pl++) //sending other players to new player
|
||||
Players::for_each([this, &guid](auto pl) //sending other players to new player
|
||||
{
|
||||
// If we are iterating over the new player, don't send the packets below
|
||||
if (pl->first == guid) continue;
|
||||
if (pl->guid == guid) return;
|
||||
|
||||
// If an invalid key makes it into the Players map, ignore it
|
||||
else if (pl->first == RakNet::UNASSIGNED_RAKNET_GUID) continue;
|
||||
|
||||
// if player not fully connected
|
||||
else if (pl->second == nullptr) continue;
|
||||
else if (pl->guid == RakNet::UNASSIGNED_RAKNET_GUID) return;
|
||||
|
||||
// If we are iterating over a player who has inputted their name, proceed
|
||||
else if (pl->second->getLoadState() == Player::POSTLOADED)
|
||||
else if (pl->getLoadState() == Player::POSTLOADED)
|
||||
{
|
||||
playerPacketController->GetPacket(ID_PLAYER_BASEINFO)->setPlayer(pl->second);
|
||||
playerPacketController->GetPacket(ID_PLAYER_STATS_DYNAMIC)->setPlayer(pl->second);
|
||||
playerPacketController->GetPacket(ID_PLAYER_ATTRIBUTE)->setPlayer(pl->second);
|
||||
playerPacketController->GetPacket(ID_PLAYER_SKILL)->setPlayer(pl->second);
|
||||
playerPacketController->GetPacket(ID_PLAYER_POSITION)->setPlayer(pl->second);
|
||||
playerPacketController->GetPacket(ID_PLAYER_CELL_CHANGE)->setPlayer(pl->second);
|
||||
playerPacketController->GetPacket(ID_PLAYER_EQUIPMENT)->setPlayer(pl->second);
|
||||
playerPacketController->GetPacket(ID_PLAYER_BASEINFO)->setPlayer(pl.get());
|
||||
playerPacketController->GetPacket(ID_PLAYER_STATS_DYNAMIC)->setPlayer(pl.get());
|
||||
playerPacketController->GetPacket(ID_PLAYER_ATTRIBUTE)->setPlayer(pl.get());
|
||||
playerPacketController->GetPacket(ID_PLAYER_SKILL)->setPlayer(pl.get());
|
||||
playerPacketController->GetPacket(ID_PLAYER_POSITION)->setPlayer(pl.get());
|
||||
playerPacketController->GetPacket(ID_PLAYER_CELL_CHANGE)->setPlayer(pl.get());
|
||||
playerPacketController->GetPacket(ID_PLAYER_EQUIPMENT)->setPlayer(pl.get());
|
||||
|
||||
playerPacketController->GetPacket(ID_PLAYER_BASEINFO)->Send(guid);
|
||||
playerPacketController->GetPacket(ID_PLAYER_STATS_DYNAMIC)->Send(guid);
|
||||
|
@ -313,7 +313,7 @@ void Networking::newPlayer(RakNet::RakNetGUID guid)
|
|||
playerPacketController->GetPacket(ID_PLAYER_CELL_CHANGE)->Send(guid);
|
||||
playerPacketController->GetPacket(ID_PLAYER_EQUIPMENT)->Send(guid);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
LOG_APPEND(Log::LOG_WARN, "- Done");
|
||||
|
||||
|
@ -321,14 +321,15 @@ void Networking::newPlayer(RakNet::RakNetGUID guid)
|
|||
|
||||
void Networking::disconnectPlayer(RakNet::RakNetGUID guid)
|
||||
{
|
||||
Player *player = Players::getPlayer(guid);
|
||||
if (!player)
|
||||
auto player = Players::getPlayerByGUID(guid);
|
||||
if (player == nullptr)
|
||||
return;
|
||||
Script::Call<Script::CallbackIdentity("OnPlayerDisconnect")>(player->getId());
|
||||
|
||||
playerPacketController->GetPacket(ID_USER_DISCONNECTED)->setPlayer(player);
|
||||
luaState.getEventCtrl().Call<CoreEvent::ON_PLAYER_DISCONNECT>(player);
|
||||
|
||||
playerPacketController->GetPacket(ID_USER_DISCONNECTED)->setPlayer(player.get());
|
||||
playerPacketController->GetPacket(ID_USER_DISCONNECTED)->Send(true);
|
||||
Players::deletePlayer(guid);
|
||||
Players::deletePlayerByGUID(guid);
|
||||
}
|
||||
|
||||
PlayerPacketController *Networking::getPlayerPacketController() const
|
||||
|
@ -369,11 +370,11 @@ void Networking::setCurrentMpNum(int value)
|
|||
int Networking::incrementMpNum()
|
||||
{
|
||||
currentMpNum++;
|
||||
Script::Call<Script::CallbackIdentity("OnMpNumIncrement")>(currentMpNum);
|
||||
luaState.getEventCtrl().Call<CoreEvent::ON_MP_REFNUM>(currentMpNum);
|
||||
return currentMpNum;
|
||||
}
|
||||
|
||||
const Networking &Networking::get()
|
||||
Networking &Networking::get()
|
||||
{
|
||||
return *sThis;
|
||||
}
|
||||
|
@ -396,20 +397,18 @@ PacketPreInit::PluginContainer Networking::getPluginListSample()
|
|||
while (true)
|
||||
{
|
||||
unsigned field = 0;
|
||||
auto name = "";
|
||||
Script::Call<Script::CallbackIdentity("OnRequestPluginList")>(name, id, field++);
|
||||
if (strlen(name) == 0)
|
||||
auto name = luaState.getEventCtrl().Call<CoreEvent::ON_REQUEST_PLUGIN_LIST, string>(id, field++);
|
||||
if (name.empty())
|
||||
break;
|
||||
PacketPreInit::HashList hashList;
|
||||
while (true)
|
||||
{
|
||||
auto hash = "";
|
||||
Script::Call<Script::CallbackIdentity("OnRequestPluginList")>(hash, id, field++);
|
||||
if (strlen(hash) == 0)
|
||||
auto hash = luaState.getEventCtrl().Call<CoreEvent::ON_REQUEST_PLUGIN_LIST, string>(id, field++);
|
||||
if (hash.empty())
|
||||
break;
|
||||
hashList.push_back((unsigned)stoul(hash));
|
||||
}
|
||||
pls.push_back({name, hashList});
|
||||
pls.emplace_back(name, hashList);
|
||||
id++;
|
||||
}
|
||||
return pls;
|
||||
|
@ -425,8 +424,11 @@ int Networking::mainLoop()
|
|||
{
|
||||
RakNet::Packet *packet;
|
||||
|
||||
auto &timerCtrl = luaState.getTimerCtrl();
|
||||
|
||||
while (running)
|
||||
{
|
||||
bool updated = false;
|
||||
if (kbhit() && getch() == '\n')
|
||||
break;
|
||||
for (packet=peer->Receive(); packet; peer->DeallocatePacket(packet), packet=peer->Receive())
|
||||
|
@ -469,15 +471,22 @@ int Networking::mainLoop()
|
|||
case ID_UNCONNECTED_PING:
|
||||
break;
|
||||
default:
|
||||
update(packet);
|
||||
updated = update(packet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
TimerAPI::Tick();
|
||||
this_thread::sleep_for(chrono::milliseconds(1));
|
||||
timerCtrl.tick();
|
||||
if (updated)
|
||||
{
|
||||
// fixme: not good to call for_each every frame. Maybe for_each_Updated will be better
|
||||
Players::for_each([](shared_ptr<Player> pl) {
|
||||
pl->update();
|
||||
});
|
||||
}
|
||||
this_thread::sleep_for (chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
TimerAPI::Terminate();
|
||||
timerCtrl.terminate();
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
|
@ -516,14 +525,14 @@ MasterClient *Networking::getMasterClient()
|
|||
return mclient;
|
||||
}
|
||||
|
||||
void Networking::InitQuery(std::string queryAddr, unsigned short queryPort)
|
||||
void Networking::InitQuery(const std::string &queryAddr, unsigned short queryPort)
|
||||
{
|
||||
mclient = new MasterClient(peer, queryAddr, queryPort);
|
||||
}
|
||||
|
||||
void Networking::postInit()
|
||||
{
|
||||
Script::Call<Script::CallbackIdentity("OnServerPostInit")>();
|
||||
luaState.getEventCtrl().Call<CoreEvent::ON_POST_INIT>();
|
||||
samples = getPluginListSample();
|
||||
if (mclient)
|
||||
{
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <components/openmw-mp/Controllers/ActorPacketController.hpp>
|
||||
#include <components/openmw-mp/Controllers/WorldPacketController.hpp>
|
||||
#include <components/openmw-mp/Packets/PacketPreInit.hpp>
|
||||
#include "Player.hpp"
|
||||
#include <apps/openmw-mp/Script/LuaState.hpp>
|
||||
|
||||
class MasterClient;
|
||||
namespace mwmp
|
||||
|
@ -31,7 +31,7 @@ namespace mwmp
|
|||
void processPlayerPacket(RakNet::Packet *packet);
|
||||
void processActorPacket(RakNet::Packet *packet);
|
||||
void processWorldPacket(RakNet::Packet *packet);
|
||||
void update(RakNet::Packet *packet);
|
||||
bool update(RakNet::Packet *packet);
|
||||
|
||||
unsigned short numberOfConnections() const;
|
||||
unsigned int maxConnections() const;
|
||||
|
@ -45,6 +45,8 @@ namespace mwmp
|
|||
ActorPacketController *getActorPacketController() const;
|
||||
WorldPacketController *getWorldPacketController() const;
|
||||
|
||||
LuaState &getState() {return luaState;}
|
||||
|
||||
BaseActorList *getLastActorList();
|
||||
BaseEvent *getLastEvent();
|
||||
|
||||
|
@ -53,22 +55,22 @@ namespace mwmp
|
|||
int incrementMpNum();
|
||||
|
||||
MasterClient *getMasterClient();
|
||||
void InitQuery(std::string queryAddr, unsigned short queryPort);
|
||||
void InitQuery(const std::string &queryAddr, unsigned short queryPort);
|
||||
void setServerPassword(std::string passw) noexcept;
|
||||
bool isPassworded() const;
|
||||
|
||||
static const Networking &get();
|
||||
static Networking &get();
|
||||
static Networking *getPtr();
|
||||
|
||||
void postInit();
|
||||
private:
|
||||
LuaState luaState;
|
||||
PacketPreInit::PluginContainer getPluginListSample();
|
||||
std::string serverPassword;
|
||||
static Networking *sThis;
|
||||
|
||||
RakNet::RakPeerInterface *peer;
|
||||
RakNet::BitStream bsOut;
|
||||
TPlayers *players;
|
||||
MasterClient *mclient;
|
||||
|
||||
BaseActorList baseActorList;
|
||||
|
|
470
apps/openmw-mp/Object.cpp
Normal file
470
apps/openmw-mp/Object.cpp
Normal file
|
@ -0,0 +1,470 @@
|
|||
//
|
||||
// Created by koncord on 26.08.17.
|
||||
//
|
||||
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
#include "Networking.hpp"
|
||||
|
||||
#include "Object.hpp"
|
||||
#include "Player.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void Object::Init(LuaState &lua)
|
||||
{
|
||||
lua.getState()->new_usertype<Object>("Object",
|
||||
"refId", sol::property(&BaseObject::getRefId, &BaseObject::setRefId),
|
||||
"refNum", sol::property(&BaseObject::getRefNum, &BaseObject::setRefNum),
|
||||
"mpNum", sol::property(&BaseObject::getMpNum, &BaseObject::setMpNum),
|
||||
"getPosition", &Object::getPosition,
|
||||
"setPosition", &Object::setPosition,
|
||||
"getRotation", &Object::getRotation,
|
||||
"setRotation", &Object::setRotation,
|
||||
"count", sol::property(&Object::getCount, &Object::setCount),
|
||||
"goldValue", sol::property(&Object::getGoldValue, &Object::setGoldValue),
|
||||
"scale", sol::property(&Object::getScale, &Object::setScale),
|
||||
"state", sol::property(&Object::getState, &Object::setState),
|
||||
"doorState", sol::property(&Object::getDoorState, &Object::setDoorState),
|
||||
"lockLevel", sol::property(&Object::getLockLevel, &Object::setLockLevel),
|
||||
"setDisarmState", &Object::setDisarmState,
|
||||
"setMasterState", &Object::setMasterState
|
||||
);
|
||||
}
|
||||
|
||||
Object::Object()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Object::~Object()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Object::update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
tuple<float, float, float> Object::getPosition() const
|
||||
{
|
||||
return make_tuple(object.position.pos[0], object.position.pos[1], object.position.pos[2]);
|
||||
}
|
||||
|
||||
void Object::setPosition(float x, float y, float z)
|
||||
{
|
||||
object.position.pos[0] = x;
|
||||
object.position.pos[1] = y;
|
||||
object.position.pos[2] = z;
|
||||
changedObjectPlace = true;
|
||||
}
|
||||
|
||||
tuple<float, float, float> Object::getRotation() const
|
||||
{
|
||||
return make_tuple(object.position.rot[0], object.position.rot[1], object.position.rot[2]);
|
||||
}
|
||||
|
||||
void Object::setRotation(float x, float y, float z)
|
||||
{
|
||||
object.position.rot[0] = x;
|
||||
object.position.rot[1] = y;
|
||||
object.position.rot[2] = z;
|
||||
changedObjectPlace = true;
|
||||
}
|
||||
|
||||
BaseObject::BaseObject(): changedBase(false), copied(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
string BaseObject::getRefId() const
|
||||
{
|
||||
return object.refId;
|
||||
}
|
||||
|
||||
void BaseObject::setRefId(const string &refId)
|
||||
{
|
||||
changedBase = true;
|
||||
object.refId = refId;
|
||||
}
|
||||
|
||||
int BaseObject::getRefNum() const
|
||||
{
|
||||
return object.refNumIndex;
|
||||
}
|
||||
|
||||
void BaseObject::setRefNum(int refNum)
|
||||
{
|
||||
changedBase = true;
|
||||
object.refNumIndex = refNum;
|
||||
}
|
||||
|
||||
int BaseObject::getMpNum() const
|
||||
{
|
||||
return object.mpNum;
|
||||
}
|
||||
|
||||
void BaseObject::setMpNum(int mpNum)
|
||||
{
|
||||
changedBase = true;
|
||||
object.mpNum = mpNum;
|
||||
}
|
||||
|
||||
int Object::getCount() const
|
||||
{
|
||||
return object.count;
|
||||
}
|
||||
|
||||
void Object::setCount(int count)
|
||||
{
|
||||
changedObjectPlace = true;
|
||||
object.count = count;
|
||||
}
|
||||
|
||||
int Object::getCharge() const
|
||||
{
|
||||
return object.charge;
|
||||
}
|
||||
|
||||
void Object::setCharge(int charge)
|
||||
{
|
||||
changedObjectPlace = true;
|
||||
object.charge = charge;
|
||||
|
||||
}
|
||||
|
||||
int Object::getGoldValue() const
|
||||
{
|
||||
return object.goldValue;
|
||||
}
|
||||
|
||||
void Object::setGoldValue(int gold)
|
||||
{
|
||||
changedObjectPlace = true;
|
||||
object.goldValue = gold;
|
||||
}
|
||||
|
||||
float Object::getScale() const
|
||||
{
|
||||
return object.scale;
|
||||
}
|
||||
|
||||
void Object::setScale(float scale)
|
||||
{
|
||||
changedObjectScale = true;
|
||||
object.scale = scale;
|
||||
}
|
||||
|
||||
bool Object::getState() const
|
||||
{
|
||||
return object.objectState;
|
||||
}
|
||||
|
||||
void Object::setState(bool state)
|
||||
{
|
||||
changedObjectState = true;
|
||||
object.objectState = state;
|
||||
}
|
||||
|
||||
int Object::getDoorState() const
|
||||
{
|
||||
return object.doorState;
|
||||
}
|
||||
|
||||
void Object::setDoorState(int state)
|
||||
{
|
||||
changedDoorState = true;
|
||||
object.doorState = state;
|
||||
}
|
||||
|
||||
int Object::getLockLevel() const
|
||||
{
|
||||
return object.lockLevel;
|
||||
}
|
||||
|
||||
void Object::setLockLevel(int locklevel)
|
||||
{
|
||||
changedObjectLock = true;
|
||||
object.lockLevel = locklevel;
|
||||
}
|
||||
|
||||
void Object::setDisarmState(bool state)
|
||||
{
|
||||
changedObjectTrap = true;
|
||||
object.isDisarmed = state;
|
||||
}
|
||||
|
||||
void Object::setMasterState(bool state)
|
||||
{
|
||||
changedObjectSpawn = true;
|
||||
object.hasMaster = state;
|
||||
}
|
||||
|
||||
|
||||
void Container::Init(LuaState &lua)
|
||||
{
|
||||
lua.getState()->new_usertype<Container>("Container",
|
||||
"refId", sol::property(&BaseObject::getRefId, &BaseObject::setRefId),
|
||||
"refNum", sol::property(&BaseObject::getRefNum, &BaseObject::setRefNum),
|
||||
"mpNum", sol::property(&BaseObject::getMpNum, &BaseObject::setMpNum),
|
||||
"getItem", &Container::getItem,
|
||||
"addItem", &Container::addItem,
|
||||
"setItem", &Container::setItem,
|
||||
"getActionCount", &Container::getActionCount
|
||||
);
|
||||
}
|
||||
|
||||
Container::Container()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
tuple<string, int, int> Container::getItem(int i) const
|
||||
{
|
||||
auto &item = object.containerItems.at(i);
|
||||
return make_tuple(item.refId, item.count, item.charge);
|
||||
}
|
||||
|
||||
void Container::setItem(int i, const string &refId, int count, int charge)
|
||||
{
|
||||
auto &item = object.containerItems.at(i);
|
||||
item.refId = refId;
|
||||
item.count = count;
|
||||
item.charge = charge;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
void Container::addItem(const string &refId, int count, int charge)
|
||||
{
|
||||
mwmp::ContainerItem item;
|
||||
item.refId = refId;
|
||||
item.count = count;
|
||||
item.charge = charge;
|
||||
object.containerItems.push_back(item);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
int Container::getActionCount(int i) const
|
||||
{
|
||||
return object.containerItems.at(i).actionCount;
|
||||
}
|
||||
|
||||
size_t Container::size() const
|
||||
{
|
||||
return object.containerItems.size();
|
||||
}
|
||||
|
||||
void ObjectController::Init(LuaState &lua)
|
||||
{
|
||||
sol::table objectCtrl = lua.getState()->create_table("ObjectCtrl");
|
||||
|
||||
objectCtrl.set_function("sendObjects", [&lua](shared_ptr<Player> player, shared_ptr<vector<shared_ptr<Object>>> objects,
|
||||
const std::string &cellDescription) {
|
||||
return lua.getObjectCtrl().sendObjects(player, objects, Utils::getCellFromDescription(cellDescription));
|
||||
});
|
||||
|
||||
objectCtrl.set_function("sendContainers", [&lua](shared_ptr<Player> player, shared_ptr<vector<shared_ptr<Container>>> objects,
|
||||
const std::string &cellDescription) {
|
||||
return lua.getObjectCtrl().sendContainers(player, objects, Utils::getCellFromDescription(cellDescription));
|
||||
});
|
||||
|
||||
objectCtrl.set_function("requestContainers", [&lua](shared_ptr<Player> player) {
|
||||
lua.getObjectCtrl().requestContainers(player);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
shared_ptr<vector<shared_ptr<Object>>> ObjectController::copyObjects(mwmp::BaseEvent &event)
|
||||
{
|
||||
auto objects = make_shared<vector<shared_ptr<Object>>>();
|
||||
|
||||
for (auto &obj : event.worldObjects)
|
||||
{
|
||||
auto object = new Object;
|
||||
object->copied = true;
|
||||
object->object = obj;
|
||||
objects->emplace_back(object);
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
|
||||
shared_ptr<vector<shared_ptr<Container>>> ObjectController::copyContainers(mwmp::BaseEvent &event)
|
||||
{
|
||||
auto containers = make_shared<vector<shared_ptr<Container>>>();
|
||||
|
||||
for (auto &obj : event.worldObjects)
|
||||
{
|
||||
auto container = new Container;
|
||||
container->copied = true;
|
||||
container->object = obj;
|
||||
containers->emplace_back(container);
|
||||
}
|
||||
return containers;
|
||||
}
|
||||
|
||||
void ObjectController::sendObjects(shared_ptr<Player> player, shared_ptr<vector<shared_ptr<Object>>> objects, const ESM::Cell &cell)
|
||||
{
|
||||
enum Type
|
||||
{
|
||||
DOOR_STATE = 0,
|
||||
OBJECT_STATE,
|
||||
OBJECT_SCALE,
|
||||
OBJECT_TRAP,
|
||||
OBJECT_LOCK,
|
||||
OBJECT_DELETE,
|
||||
OBJECT_SPAWN,
|
||||
OBJECT_PLACE,
|
||||
LAST
|
||||
};
|
||||
mwmp::BaseEvent events[Type::LAST];
|
||||
bool changed[Type::LAST];
|
||||
|
||||
for (auto &e : events)
|
||||
{
|
||||
e.action = mwmp::BaseEvent::SET;
|
||||
e.guid = player->guid;
|
||||
e.cell = cell;
|
||||
}
|
||||
|
||||
|
||||
for (auto &object : *objects)
|
||||
{
|
||||
//sendObject(player.get(), object.get());
|
||||
|
||||
bool validNewObjOrCopy = (!object->copied && object->changedBase) || object->copied;
|
||||
|
||||
if (object->changedDoorState && validNewObjOrCopy)
|
||||
{
|
||||
changed[Type::DOOR_STATE] = true;
|
||||
events[Type::DOOR_STATE].worldObjects.push_back(object->object);
|
||||
}
|
||||
if (object->changedObjectState && validNewObjOrCopy)
|
||||
{
|
||||
changed[Type::OBJECT_STATE] = true;
|
||||
events[Type::OBJECT_STATE].worldObjects.push_back(object->object);
|
||||
}
|
||||
if (object->changedObjectScale && validNewObjOrCopy)
|
||||
{
|
||||
changed[Type::OBJECT_SCALE] = true;
|
||||
events[Type::OBJECT_SCALE].worldObjects.push_back(object->object);
|
||||
}
|
||||
if (object->changedObjectTrap && validNewObjOrCopy)
|
||||
{
|
||||
changed[Type::OBJECT_TRAP] = true;
|
||||
events[Type::OBJECT_TRAP].worldObjects.push_back(object->object);
|
||||
}
|
||||
if (object->changedObjectLock && validNewObjOrCopy)
|
||||
{
|
||||
changed[Type::OBJECT_LOCK] = true;
|
||||
events[Type::OBJECT_LOCK].worldObjects.push_back(object->object);
|
||||
}
|
||||
if (object->changedObjectDelete && validNewObjOrCopy)
|
||||
{
|
||||
changed[Type::OBJECT_DELETE] = true;
|
||||
events[Type::OBJECT_DELETE].worldObjects.push_back(object->object);
|
||||
}
|
||||
if (object->changedObjectSpawn && validNewObjOrCopy)
|
||||
{
|
||||
changed[Type::OBJECT_SPAWN] = true;
|
||||
events[Type::OBJECT_SPAWN].worldObjects.push_back(object->object);
|
||||
}
|
||||
if (object->changedObjectPlace && validNewObjOrCopy)
|
||||
{
|
||||
changed[Type::OBJECT_PLACE] = true;
|
||||
events[Type::OBJECT_PLACE].worldObjects.push_back(object->object);
|
||||
}
|
||||
}
|
||||
|
||||
auto worldCtrl = mwmp::Networking::get().getWorldPacketController();
|
||||
|
||||
if (changed[Type::DOOR_STATE])
|
||||
{
|
||||
auto packet = worldCtrl->GetPacket(ID_DOOR_STATE);
|
||||
auto &event = events[Type::DOOR_STATE];
|
||||
packet->setEvent(&event);
|
||||
packet->Send(event.guid);
|
||||
}
|
||||
if (changed[Type::OBJECT_STATE])
|
||||
{
|
||||
auto packet = worldCtrl->GetPacket(ID_OBJECT_STATE);
|
||||
auto &event = events[Type::OBJECT_STATE];
|
||||
packet->setEvent(&event);
|
||||
packet->Send(event.guid);
|
||||
}
|
||||
if (changed[Type::OBJECT_SCALE])
|
||||
{
|
||||
auto packet = worldCtrl->GetPacket(ID_OBJECT_SCALE);
|
||||
auto &event = events[Type::OBJECT_SCALE];
|
||||
packet->setEvent(&event);
|
||||
packet->Send(event.guid);
|
||||
}
|
||||
if (changed[Type::OBJECT_TRAP])
|
||||
{
|
||||
auto packet = worldCtrl->GetPacket(ID_OBJECT_TRAP);
|
||||
auto &event = events[Type::OBJECT_TRAP];
|
||||
packet->setEvent(&event);
|
||||
packet->Send(event.guid);
|
||||
}
|
||||
if (changed[Type::OBJECT_LOCK])
|
||||
{
|
||||
auto packet = worldCtrl->GetPacket(ID_OBJECT_LOCK);
|
||||
auto &event = events[Type::OBJECT_LOCK];
|
||||
packet->setEvent(&event);
|
||||
packet->Send(event.guid);
|
||||
}
|
||||
if (changed[Type::OBJECT_DELETE])
|
||||
{
|
||||
auto packet = worldCtrl->GetPacket(ID_OBJECT_DELETE);
|
||||
auto &event = events[Type::OBJECT_DELETE];
|
||||
packet->setEvent(&event);
|
||||
packet->Send(event.guid);
|
||||
}
|
||||
if (changed[Type::OBJECT_SCALE])
|
||||
{
|
||||
auto packet = worldCtrl->GetPacket(ID_OBJECT_SPAWN);
|
||||
auto &event = events[Type::OBJECT_SCALE];
|
||||
packet->setEvent(&event);
|
||||
packet->Send(event.guid);
|
||||
}
|
||||
if (changed[Type::OBJECT_PLACE])
|
||||
{
|
||||
auto packet = worldCtrl->GetPacket(ID_OBJECT_PLACE);
|
||||
auto &event = events[Type::OBJECT_PLACE];
|
||||
packet->setEvent(&event);
|
||||
packet->Send(event.guid);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectController::sendContainers(shared_ptr<Player> player, shared_ptr<vector<shared_ptr<Container>>> objects, const ESM::Cell &cell)
|
||||
{
|
||||
|
||||
mwmp::BaseEvent event;
|
||||
event.cell = cell;
|
||||
event.action = mwmp::BaseEvent::SET;
|
||||
event.guid = player->guid;
|
||||
|
||||
for (auto &object : *objects)
|
||||
{
|
||||
bool validNewObjOrCopy = (!object->copied && object->changedBase) || object->copied;
|
||||
if (object->changed && validNewObjOrCopy)
|
||||
event.worldObjects.push_back(object->object);
|
||||
}
|
||||
|
||||
auto packet = mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_CONTAINER);
|
||||
packet->setEvent(&event);
|
||||
packet->Send(event.guid);
|
||||
}
|
||||
|
||||
void ObjectController::requestContainers(shared_ptr<Player> player)
|
||||
{
|
||||
mwmp::BaseEvent event;
|
||||
event.action = mwmp::BaseEvent::REQUEST;
|
||||
event.guid = player->guid;
|
||||
event.cell = player->cell;
|
||||
|
||||
auto packet = mwmp::Networking::get().getWorldPacketController()->GetPacket(ID_CONTAINER);
|
||||
packet->setEvent(&event);
|
||||
packet->Send(event.guid);
|
||||
}
|
119
apps/openmw-mp/Object.hpp
Normal file
119
apps/openmw-mp/Object.hpp
Normal file
|
@ -0,0 +1,119 @@
|
|||
//
|
||||
// Created by koncord on 26.08.17.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <tuple>
|
||||
#include <components/openmw-mp/Base/BaseEvent.hpp>
|
||||
#include <memory>
|
||||
|
||||
class LuaState;
|
||||
class Player;
|
||||
|
||||
class BaseObject
|
||||
{
|
||||
public:
|
||||
BaseObject();
|
||||
std::string getRefId() const;
|
||||
void setRefId(const std::string &refId);
|
||||
|
||||
int getRefNum() const;
|
||||
void setRefNum(int refNum);
|
||||
|
||||
int getMpNum() const;
|
||||
void setMpNum(int mpNum);
|
||||
|
||||
//void setEventCell(const std::string &cellDescription);
|
||||
|
||||
|
||||
mwmp::WorldObject object;
|
||||
bool changedBase;
|
||||
bool copied;
|
||||
};
|
||||
|
||||
class Object : public BaseObject
|
||||
{
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
public:
|
||||
Object();
|
||||
~Object();
|
||||
|
||||
void update();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return x, y, z
|
||||
*/
|
||||
|
||||
std::tuple<float, float, float> getPosition() const;
|
||||
void setPosition(float x, float y, float z);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return x, y, z
|
||||
*/
|
||||
std::tuple<float, float, float> getRotation() const;
|
||||
void setRotation(float x, float y, float z);
|
||||
|
||||
int getCount() const;
|
||||
void setCount(int count);
|
||||
|
||||
int getCharge() const;
|
||||
void setCharge(int charge);
|
||||
|
||||
int getGoldValue() const;
|
||||
void setGoldValue(int gold);
|
||||
|
||||
float getScale() const;
|
||||
void setScale(float scale);
|
||||
|
||||
bool getState() const;
|
||||
void setState(bool state);
|
||||
|
||||
int getDoorState() const;
|
||||
void setDoorState(int state);
|
||||
|
||||
int getLockLevel() const;
|
||||
void setLockLevel(int locklevel);
|
||||
|
||||
void setDisarmState(bool state);
|
||||
void setMasterState(bool state);
|
||||
|
||||
bool changedDoorState, changedObjectState, changedObjectScale, changedObjectTrap, changedObjectLock,
|
||||
changedObjectDelete, changedObjectSpawn, changedObjectPlace;
|
||||
};
|
||||
|
||||
class Container : public BaseObject
|
||||
{
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
public:
|
||||
Container();
|
||||
|
||||
std::tuple<std::string, int, int> getItem(int i) const;
|
||||
void addItem(const std::string &refId, int count, int charge);
|
||||
|
||||
void setItem(int i, const std::string &refId, int count, int charge);
|
||||
int getActionCount(int i) const;
|
||||
|
||||
size_t size() const;
|
||||
bool changed;
|
||||
};
|
||||
|
||||
|
||||
class ObjectController
|
||||
{
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
public:
|
||||
|
||||
std::shared_ptr<std::vector<std::shared_ptr<Object>>> copyObjects(mwmp::BaseEvent &event);
|
||||
std::shared_ptr<std::vector<std::shared_ptr<Container>>> copyContainers(mwmp::BaseEvent &event);
|
||||
|
||||
void sendObjects(std::shared_ptr<Player> player, std::shared_ptr<std::vector<std::shared_ptr<Object>>> objects, const ESM::Cell &cell);
|
||||
void sendContainers(std::shared_ptr<Player> player, std::shared_ptr<std::vector<std::shared_ptr<Container>>> objects, const ESM::Cell &cell);
|
||||
|
||||
void requestContainers(std::shared_ptr<Player> player);
|
||||
};
|
|
@ -2,79 +2,218 @@
|
|||
// Created by koncord on 05.01.16.
|
||||
//
|
||||
|
||||
#include "Player.hpp"
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
#include "Networking.hpp"
|
||||
|
||||
TPlayers Players::players;
|
||||
TSlots Players::slots;
|
||||
#include "Player.hpp"
|
||||
#include "Inventory.hpp"
|
||||
#include "Settings.hpp"
|
||||
|
||||
void Players::deletePlayer(RakNet::RakNetGUID guid)
|
||||
using namespace std;
|
||||
|
||||
void Player::Init(LuaState &lua)
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Deleting player with guid %lu", guid.g);
|
||||
lua.getState()->new_usertype<Player>("Player",
|
||||
"getPosition", &NetActor::getPosition,
|
||||
"setPosition", &NetActor::setPosition,
|
||||
"getRotation", &NetActor::getRotation,
|
||||
"setRotation", &NetActor::setRotation,
|
||||
|
||||
if (players[guid] != 0)
|
||||
{
|
||||
CellController::get()->deletePlayer(players[guid]);
|
||||
"getHealth", &NetActor::getHealth,
|
||||
"setHealth", &NetActor::setHealth,
|
||||
"getMagicka", &NetActor::getMagicka,
|
||||
"setMagicka", &NetActor::setMagicka,
|
||||
"getFatigue", &NetActor::getFatigue,
|
||||
"setFatigue", &NetActor::setFatigue,
|
||||
|
||||
LOG_APPEND(Log::LOG_INFO, "- Emptying slot %i", players[guid]->getId());
|
||||
"getCell", &NetActor::getCell,
|
||||
"getInventory", &NetActor::getInventory,
|
||||
|
||||
slots[players[guid]->getId()] = 0;
|
||||
delete players[guid];
|
||||
players.erase(guid);
|
||||
}
|
||||
"getPreviousCellPos", &Player::getPreviousCellPos,
|
||||
|
||||
"kick", &Player::kick,
|
||||
"ban", &Player::ban,
|
||||
"address", sol::property(&Player::getIP),
|
||||
|
||||
"getAvgPing", &Player::getAvgPing,
|
||||
|
||||
"message", &Player::message,
|
||||
"cleanChat", &Player::cleanChat,
|
||||
|
||||
"pid", sol::readonly_property(&Player::id),
|
||||
"guid", sol::readonly_property(&Player::getGUID),
|
||||
|
||||
"name", sol::property(&Player::getName, &Player::setName),
|
||||
"setCharGenStages", &Player::setCharGenStages,
|
||||
"level", sol::property(&Player::getLevel, &Player::setLevel),
|
||||
"gender", sol::property(&Player::getGender, &Player::setGender),
|
||||
"race", sol::property(&Player::getRace, &Player::setRace),
|
||||
"head", sol::property(&Player::getHead, &Player::setHead),
|
||||
"hair", sol::property(&Player::getHair, &Player::setHair),
|
||||
"birthsign", sol::property(&Player::getBirthsign, &Player::setBirthsign),
|
||||
"bounty", sol::property(&Player::getBounty, &Player::setBounty),
|
||||
"levelProgress", sol::property(&Player::getLevelProgress, &Player::setLevelProgress),
|
||||
"creatureModel", sol::property(&Player::getCreatureModel, &Player::setCreatureModel),
|
||||
"isCreatureName", sol::property(&Player::isCreatureName, &Player::creatureName),
|
||||
|
||||
"resurrect", &Player::resurrect,
|
||||
"jail", &Player::jail,
|
||||
"werewolf", sol::property(&Player::getWerewolfState, &Player::setWerewolfState),
|
||||
|
||||
"getAttribute", &Player::getAttribute,
|
||||
"setAttribute", &Player::setAttribute,
|
||||
|
||||
"getSkill", &Player::getSkill,
|
||||
"setSkill", &Player::setSkill,
|
||||
|
||||
"getSkillIncrease", &Player::getSkillIncrease,
|
||||
"setSkillIncrease", &Player::setSkillIncrease,
|
||||
|
||||
"getClass", &Player::getCharClass,
|
||||
"getSettings", &Player::getSettings,
|
||||
"getBooks", &Player::getBooks,
|
||||
"getGUI", &Player::getGUI,
|
||||
"getDialogue", &Player::getDialogue,
|
||||
"getFactions", &Player::getFactions,
|
||||
"getQuests", &Player::getQuests,
|
||||
"getSpells", &Player::getSpells,
|
||||
|
||||
"getCellState", &Player::getCellState,
|
||||
"cellStateSize", &Player::cellStateSize,
|
||||
"addCellExplored", &Player::addCellExplored,
|
||||
"setAuthority", &Player::setAuthority,
|
||||
"customData", &Player::customData
|
||||
);
|
||||
}
|
||||
|
||||
void Players::newPlayer(RakNet::RakNetGUID guid)
|
||||
Player::Player(RakNet::RakNetGUID guid) : BasePlayer(guid), NetActor(), changedMap(false), cClass(this),
|
||||
settings(this), books(this), gui(this), dialogue(this), factions(this),
|
||||
quests(this), spells(this)
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Creating new player with guid %lu", guid.g);
|
||||
|
||||
players[guid] = new Player(guid);
|
||||
players[guid]->cell.blank();
|
||||
players[guid]->npc.blank();
|
||||
players[guid]->npcStats.blank();
|
||||
players[guid]->creatureStats.blank();
|
||||
players[guid]->charClass.blank();
|
||||
players[guid]->isWerewolf = false;
|
||||
|
||||
for (unsigned int i = 0; i < mwmp::Networking::get().maxConnections(); i++)
|
||||
{
|
||||
if (slots[i] == 0)
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "- Storing in slot %i", i);
|
||||
|
||||
slots[i] = players[guid];
|
||||
slots[i]->setId(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Player *Players::getPlayer(RakNet::RakNetGUID guid)
|
||||
{
|
||||
if (players.count(guid) == 0)
|
||||
return nullptr;
|
||||
return players[guid];
|
||||
}
|
||||
|
||||
TPlayers *Players::getPlayers()
|
||||
{
|
||||
return &players;
|
||||
}
|
||||
|
||||
unsigned short Players::getLastPlayerId()
|
||||
{
|
||||
return slots.rbegin()->first;
|
||||
}
|
||||
|
||||
Player::Player(RakNet::RakNetGUID guid) : BasePlayer(guid)
|
||||
{
|
||||
handshakeState = false;
|
||||
basePlayer = this;
|
||||
netCreature = this;
|
||||
printf("Player::Player()\n");
|
||||
handshakeCounter = 0;
|
||||
loadState = NOTLOADED;
|
||||
resetUpdateFlags();
|
||||
cell.blank();
|
||||
npc.blank();
|
||||
npcStats.blank();
|
||||
creatureStats.blank();
|
||||
charClass.blank();
|
||||
customData = mwmp::Networking::get().getState().getState()->create_table();
|
||||
}
|
||||
|
||||
Player::~Player()
|
||||
{
|
||||
printf("Player::~Player()\n");
|
||||
CellController::get()->deletePlayer(this);
|
||||
}
|
||||
|
||||
void Player::update()
|
||||
{
|
||||
auto plPCtrl = mwmp::Networking::get().getPlayerPacketController();
|
||||
|
||||
if (baseInfoChanged)
|
||||
{
|
||||
auto packet = plPCtrl->GetPacket(ID_PLAYER_BASEINFO);
|
||||
packet->setPlayer(basePlayer);
|
||||
packet->Send(false);
|
||||
packet->Send(true);
|
||||
}
|
||||
|
||||
// Make sure we send a cell change before we send the position so the position isn't overridden
|
||||
if (cellAPI.isChangedCell())
|
||||
{
|
||||
auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_CELL_CHANGE);
|
||||
packet->setPlayer(this);
|
||||
packet->Send(/*toOthers*/ false);
|
||||
cellAPI.resetChangedCell();
|
||||
}
|
||||
|
||||
if (positionChanged)
|
||||
{
|
||||
auto packet = plPCtrl->GetPacket(ID_PLAYER_POSITION);
|
||||
packet->setPlayer(basePlayer);
|
||||
packet->Send(false);
|
||||
}
|
||||
|
||||
// The character class can override values from below on the client, so send it first
|
||||
cClass.update();
|
||||
|
||||
if (levelChanged)
|
||||
{
|
||||
auto packet = plPCtrl->GetPacket(ID_PLAYER_LEVEL);
|
||||
packet->setPlayer(basePlayer);
|
||||
packet->Send(false);
|
||||
packet->Send(true);
|
||||
}
|
||||
|
||||
if (statsChanged)
|
||||
{
|
||||
auto packet = plPCtrl->GetPacket(ID_PLAYER_STATS_DYNAMIC);
|
||||
packet->setPlayer(basePlayer);
|
||||
packet->Send(false);
|
||||
packet->Send(true);
|
||||
|
||||
statsDynamicIndexChanges.clear();
|
||||
}
|
||||
|
||||
if (attributesChanged)
|
||||
{
|
||||
auto packet = plPCtrl->GetPacket(ID_PLAYER_ATTRIBUTE);
|
||||
packet->setPlayer(basePlayer);
|
||||
packet->Send(false);
|
||||
packet->Send(true);
|
||||
|
||||
attributeIndexChanges.clear();
|
||||
}
|
||||
|
||||
if (skillsChanged)
|
||||
{
|
||||
auto packet = plPCtrl->GetPacket(ID_PLAYER_SKILL);
|
||||
packet->setPlayer(basePlayer);
|
||||
packet->Send(false);
|
||||
packet->Send(true);
|
||||
|
||||
skillIndexChanges.clear();
|
||||
}
|
||||
|
||||
if (inventory.isEquipmentChanged())
|
||||
{
|
||||
auto packet = plPCtrl->GetPacket(ID_PLAYER_EQUIPMENT);
|
||||
packet->setPlayer(this);
|
||||
packet->Send(false);
|
||||
packet->Send(true);
|
||||
inventory.resetEquipmentFlag();
|
||||
}
|
||||
|
||||
if (inventory.inventoryChangeType() != 0)
|
||||
{
|
||||
auto packet = plPCtrl->GetPacket(ID_PLAYER_INVENTORY);
|
||||
packet->setPlayer(this);
|
||||
packet->Send(/*toOthers*/ false);
|
||||
inventory.resetInventoryFlag();
|
||||
}
|
||||
|
||||
if (changedMap)
|
||||
{
|
||||
auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_MAP);
|
||||
packet->setPlayer(this);
|
||||
packet->Send(/*toOthers*/ false);
|
||||
changedMap = false;
|
||||
}
|
||||
|
||||
settings.update();
|
||||
books.update();
|
||||
gui.update();
|
||||
dialogue.update();
|
||||
factions.update();
|
||||
quests.update();
|
||||
spells.update();
|
||||
|
||||
resetUpdateFlags();
|
||||
}
|
||||
|
||||
unsigned short Player::getId()
|
||||
|
@ -82,24 +221,24 @@ unsigned short Player::getId()
|
|||
return id;
|
||||
}
|
||||
|
||||
void Player::setId(unsigned short id)
|
||||
void Player::setId(unsigned short newId)
|
||||
{
|
||||
this->id = id;
|
||||
}
|
||||
|
||||
void Player::setHandshake()
|
||||
{
|
||||
handshakeState = true;
|
||||
this->id = newId;
|
||||
}
|
||||
|
||||
bool Player::isHandshaked()
|
||||
{
|
||||
return handshakeState;
|
||||
return handshakeCounter == numeric_limits<int>::max();
|
||||
}
|
||||
|
||||
void Player::setLoadState(int state)
|
||||
void Player::setHandshake()
|
||||
{
|
||||
loadState = state;
|
||||
handshakeCounter = numeric_limits<int>::max();
|
||||
}
|
||||
|
||||
int Player::handshakeAttempts()
|
||||
{
|
||||
return handshakeCounter++;
|
||||
}
|
||||
|
||||
int Player::getLoadState()
|
||||
|
@ -107,11 +246,9 @@ int Player::getLoadState()
|
|||
return loadState;
|
||||
}
|
||||
|
||||
Player *Players::getPlayer(unsigned short id)
|
||||
void Player::setLoadState(int state)
|
||||
{
|
||||
if (slots.find(id) == slots.end())
|
||||
return nullptr;
|
||||
return slots[id];
|
||||
loadState = state;
|
||||
}
|
||||
|
||||
CellController::TContainer *Player::getCells()
|
||||
|
@ -119,6 +256,29 @@ CellController::TContainer *Player::getCells()
|
|||
return &cells;
|
||||
}
|
||||
|
||||
void Player::forEachLoaded(std::function<void(Player *pl, Player *other)> func)
|
||||
{
|
||||
std::list <Player*> plList;
|
||||
|
||||
for (auto &&cell : cells)
|
||||
{
|
||||
for (auto &&pl : *cell)
|
||||
{
|
||||
if (pl != nullptr && !pl->npc.mName.empty())
|
||||
plList.push_back(pl);
|
||||
}
|
||||
}
|
||||
|
||||
plList.sort();
|
||||
plList.unique();
|
||||
|
||||
for (auto &&pl : plList)
|
||||
{
|
||||
if (pl == this) continue;
|
||||
func(this, pl);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::sendToLoaded(mwmp::PlayerPacket *myPacket)
|
||||
{
|
||||
std::list <Player*> plList;
|
||||
|
@ -138,25 +298,370 @@ void Player::sendToLoaded(mwmp::PlayerPacket *myPacket)
|
|||
}
|
||||
}
|
||||
|
||||
void Player::forEachLoaded(std::function<void(Player *pl, Player *other)> func)
|
||||
void Player::kick() const
|
||||
{
|
||||
std::list <Player*> plList;
|
||||
mwmp::Networking::getPtr()->kickPlayer(guid);
|
||||
}
|
||||
|
||||
for (auto cell : cells)
|
||||
void Player::ban() const
|
||||
{
|
||||
auto netCtrl = mwmp::Networking::getPtr();
|
||||
RakNet::SystemAddress addr = netCtrl->getSystemAddress(guid);
|
||||
netCtrl->banAddress(addr.ToString(false));
|
||||
}
|
||||
|
||||
void Player::cleanChat()
|
||||
{
|
||||
chatMessage.clear();
|
||||
|
||||
auto packet = mwmp::Networking::get().getPlayerPacketController();
|
||||
packet->GetPacket(ID_CHAT_MESSAGE)->setPlayer(this);
|
||||
packet->GetPacket(ID_CHAT_MESSAGE)->Send(false);
|
||||
}
|
||||
|
||||
std::string Player::getIP() const
|
||||
{
|
||||
RakNet::SystemAddress addr = mwmp::Networking::getPtr()->getSystemAddress(guid);
|
||||
return addr.ToString(false);
|
||||
}
|
||||
|
||||
int Player::getAvgPing()
|
||||
{
|
||||
return mwmp::Networking::get().getAvgPing(guid);
|
||||
}
|
||||
|
||||
std::string Player::getName()
|
||||
{
|
||||
return npc.mName;
|
||||
}
|
||||
|
||||
void Player::setName(const std::string &name)
|
||||
{
|
||||
npc.mName = name;
|
||||
baseInfoChanged = true;
|
||||
}
|
||||
|
||||
void Player::setCharGenStages(int currentStage, int endStage)
|
||||
{
|
||||
charGenState.currentStage = currentStage;
|
||||
charGenState.endStage = endStage;
|
||||
charGenState.isFinished = false;
|
||||
|
||||
auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_CHARGEN);
|
||||
packet->setPlayer(this);
|
||||
packet->Send(false);
|
||||
}
|
||||
|
||||
void Player::message(const std::string &message, bool toAll)
|
||||
{
|
||||
chatMessage = message;
|
||||
|
||||
auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_CHAT_MESSAGE);
|
||||
packet->setPlayer(this);
|
||||
|
||||
packet->Send(false);
|
||||
if (toAll)
|
||||
packet->Send(true);
|
||||
}
|
||||
|
||||
int Player::getLevel() const
|
||||
{
|
||||
return creatureStats.mLevel;
|
||||
}
|
||||
|
||||
void Player::setLevel(int level)
|
||||
{
|
||||
creatureStats.mLevel = level;
|
||||
levelChanged = true;
|
||||
}
|
||||
|
||||
int Player::getGender() const
|
||||
{
|
||||
return npc.isMale();
|
||||
}
|
||||
|
||||
void Player::setGender(int gender)
|
||||
{
|
||||
npc.setIsMale(gender);
|
||||
baseInfoChanged = true;
|
||||
}
|
||||
|
||||
std::string Player::getRace() const
|
||||
{
|
||||
return npc.mRace;
|
||||
}
|
||||
|
||||
void Player::setRace(const std::string &race)
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Setting race for %s: %s -> %s", npc.mName.c_str(), npc.mRace.c_str(), race.c_str());
|
||||
|
||||
npc.mRace = race;
|
||||
baseInfoChanged = true;
|
||||
}
|
||||
|
||||
std::string Player::getHead() const
|
||||
{
|
||||
return npc.mHead;
|
||||
}
|
||||
|
||||
void Player::setHead(const std::string &head)
|
||||
{
|
||||
npc.mHead = head;
|
||||
baseInfoChanged = true;
|
||||
}
|
||||
|
||||
std::string Player::getHair() const
|
||||
{
|
||||
return npc.mHair;
|
||||
}
|
||||
|
||||
void Player::setHair(const std::string &hair)
|
||||
{
|
||||
npc.mHair = hair;
|
||||
baseInfoChanged = true;
|
||||
}
|
||||
|
||||
std::string Player::getBirthsign() const
|
||||
{
|
||||
return birthsign;
|
||||
}
|
||||
|
||||
void Player::setBirthsign(const std::string &sign)
|
||||
{
|
||||
birthsign = sign;
|
||||
baseInfoChanged = true;
|
||||
}
|
||||
|
||||
int Player::getBounty() const
|
||||
{
|
||||
return npcStats.mBounty;
|
||||
}
|
||||
|
||||
void Player::setBounty(int bounty)
|
||||
{
|
||||
npcStats.mBounty = bounty;
|
||||
auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_BOUNTY);
|
||||
packet->setPlayer(this);
|
||||
packet->Send(false);
|
||||
packet->Send(true);
|
||||
}
|
||||
|
||||
int Player::getLevelProgress() const
|
||||
{
|
||||
return npcStats.mLevelProgress;
|
||||
}
|
||||
|
||||
void Player::setLevelProgress(int progress)
|
||||
{
|
||||
npcStats.mLevelProgress = progress;
|
||||
levelChanged = true;
|
||||
}
|
||||
|
||||
std::string Player::getCreatureModel() const
|
||||
{
|
||||
return creatureModel;
|
||||
}
|
||||
|
||||
void Player::setCreatureModel(const std::string &model)
|
||||
{
|
||||
creatureModel = model;
|
||||
baseInfoChanged = true;
|
||||
}
|
||||
|
||||
void Player::creatureName(bool useName)
|
||||
{
|
||||
useCreatureName = useName;
|
||||
baseInfoChanged = true;
|
||||
}
|
||||
|
||||
bool Player::isCreatureName() const
|
||||
{
|
||||
return useCreatureName;
|
||||
}
|
||||
|
||||
std::tuple<int, int> Player::getAttribute(unsigned short attributeId) const
|
||||
{
|
||||
if (attributeId >= ESM::Attribute::Length)
|
||||
return make_tuple(0, 0);
|
||||
|
||||
return make_tuple(creatureStats.mAttributes[attributeId].mBase, creatureStats.mAttributes[attributeId].mCurrent);
|
||||
}
|
||||
|
||||
void Player::setAttribute(unsigned short attributeId, int base, int current)
|
||||
{
|
||||
if (attributeId >= ESM::Attribute::Length)
|
||||
return;
|
||||
|
||||
creatureStats.mAttributes[attributeId].mBase = base;
|
||||
creatureStats.mAttributes[attributeId].mCurrent = current;
|
||||
|
||||
if (!Utils::vectorContains(&attributeIndexChanges, attributeId))
|
||||
attributeIndexChanges.push_back(attributeId);
|
||||
|
||||
attributesChanged = true;
|
||||
}
|
||||
|
||||
std::tuple<int, int, float> Player::getSkill(unsigned short skillId) const
|
||||
{
|
||||
if (skillId >= ESM::Skill::Length)
|
||||
return make_tuple(0, 0, 0.0f);
|
||||
|
||||
const auto &skill = npcStats.mSkills[skillId];
|
||||
|
||||
return make_tuple(skill.mBase, skill.mCurrent, skill.mProgress);
|
||||
}
|
||||
|
||||
void Player::setSkill(unsigned short skillId, int base, int current, float progress)
|
||||
{
|
||||
if (skillId >= ESM::Skill::Length)
|
||||
return;
|
||||
|
||||
auto &skill = npcStats.mSkills[skillId];
|
||||
skill.mBase = base;
|
||||
skill.mCurrent = current;
|
||||
skill.mProgress = progress;
|
||||
|
||||
if (!Utils::vectorContains(&skillIndexChanges, skillId))
|
||||
skillIndexChanges.push_back(skillId);
|
||||
|
||||
skillsChanged = true;
|
||||
}
|
||||
|
||||
int Player::getSkillIncrease(unsigned short attributeId) const
|
||||
{
|
||||
return npcStats.mSkillIncrease[attributeId];
|
||||
}
|
||||
|
||||
void Player::setSkillIncrease(unsigned short attributeId, int increase)
|
||||
{
|
||||
if (attributeId >= ESM::Attribute::Length)
|
||||
return;
|
||||
|
||||
npcStats.mSkillIncrease[attributeId] = increase;
|
||||
|
||||
if (!Utils::vectorContains(&attributeIndexChanges, attributeId))
|
||||
attributeIndexChanges.push_back(attributeId);
|
||||
|
||||
attributesChanged = true;
|
||||
}
|
||||
|
||||
CharClass &Player::getCharClass(sol::this_state thisState)
|
||||
{
|
||||
return cClass;
|
||||
}
|
||||
|
||||
GameSettings &Player::getSettings()
|
||||
{
|
||||
return settings;
|
||||
}
|
||||
|
||||
Books &Player::getBooks()
|
||||
{
|
||||
return books;
|
||||
}
|
||||
|
||||
GUI &Player::getGUI()
|
||||
{
|
||||
return gui;
|
||||
}
|
||||
|
||||
Dialogue &Player::getDialogue()
|
||||
{
|
||||
return dialogue;
|
||||
}
|
||||
|
||||
Factions &Player::getFactions()
|
||||
{
|
||||
return factions;
|
||||
}
|
||||
|
||||
Quests &Player::getQuests()
|
||||
{
|
||||
return quests;
|
||||
}
|
||||
|
||||
Spells &Player::getSpells()
|
||||
{
|
||||
return spells;
|
||||
}
|
||||
|
||||
std::tuple<float, float, float> Player::getPreviousCellPos() const
|
||||
{
|
||||
return make_tuple(previousCellPosition.pos[0], previousCellPosition.pos[1], previousCellPosition.pos[2]);
|
||||
}
|
||||
|
||||
void Player::resurrect(unsigned int type)
|
||||
{
|
||||
resurrectType = type;
|
||||
|
||||
auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_RESURRECT);
|
||||
packet->setPlayer(this);
|
||||
packet->Send(false);
|
||||
packet->Send(true);
|
||||
}
|
||||
|
||||
void Player::jail(int jailDays, bool ignoreJailTeleportation, bool ignoreJailSkillIncreases,
|
||||
const std::string &jailProgressText, const std::string &jailEndText)
|
||||
{
|
||||
this->jailDays = jailDays;
|
||||
this->ignoreJailTeleportation = ignoreJailTeleportation;
|
||||
this->ignoreJailSkillIncreases = ignoreJailSkillIncreases;
|
||||
this->jailProgressText = jailProgressText;
|
||||
this->jailEndText = jailEndText;
|
||||
|
||||
auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_JAIL);
|
||||
packet->setPlayer(this);
|
||||
packet->Send(false);
|
||||
}
|
||||
|
||||
bool Player::getWerewolfState() const
|
||||
{
|
||||
return isWerewolf;
|
||||
}
|
||||
|
||||
void Player::setWerewolfState(bool state)
|
||||
{
|
||||
isWerewolf = state;
|
||||
|
||||
auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_SHAPESHIFT);
|
||||
packet->setPlayer(this);
|
||||
packet->Send(false);
|
||||
packet->Send(true);
|
||||
}
|
||||
|
||||
size_t Player::cellStateSize() const
|
||||
{
|
||||
return cellStateChanges.cellStates.size();
|
||||
}
|
||||
|
||||
void Player::addCellExplored(const std::string &cellDescription)
|
||||
{
|
||||
auto cellExplored = Utils::getCellFromDescription(cellDescription);
|
||||
mapChanges.cellsExplored.push_back(cellExplored);
|
||||
changedMap = true;
|
||||
}
|
||||
|
||||
CellState Player::getCellState(int i)
|
||||
{
|
||||
return CellState(cellStateChanges.cellStates.at(i));
|
||||
}
|
||||
|
||||
void Player::setAuthority()
|
||||
{
|
||||
mwmp::BaseActorList writeActorList;
|
||||
writeActorList.cell = cell;
|
||||
writeActorList.guid = guid;
|
||||
|
||||
Cell *serverCell = CellController::get()->getCell(&cell);
|
||||
if (serverCell != nullptr)
|
||||
{
|
||||
for (auto pl : *cell)
|
||||
{
|
||||
if (pl != nullptr && !pl->npc.mName.empty())
|
||||
plList.push_back(pl);
|
||||
}
|
||||
}
|
||||
serverCell->setAuthority(guid);
|
||||
|
||||
plList.sort();
|
||||
plList.unique();
|
||||
mwmp::ActorPacket *authorityPacket = mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_AUTHORITY);
|
||||
authorityPacket->setActorList(&writeActorList);
|
||||
authorityPacket->Send(writeActorList.guid);
|
||||
|
||||
for (auto pl : plList)
|
||||
{
|
||||
if (pl == this) continue;
|
||||
func(this, pl);
|
||||
// Also send this to everyone else who has the cell loaded
|
||||
serverCell->sendToLoaded(authorityPacket, &writeActorList);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <map>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <RakNetTypes.h>
|
||||
|
||||
#include <components/esm/npcstats.hpp>
|
||||
|
@ -18,32 +19,30 @@
|
|||
#include <components/openmw-mp/Log.hpp>
|
||||
#include <components/openmw-mp/Base/BasePlayer.hpp>
|
||||
#include <components/openmw-mp/Packets/Player/PlayerPacket.hpp>
|
||||
#include <apps/openmw-mp/Script/LuaState.hpp>
|
||||
#include "Cell.hpp"
|
||||
#include "CellController.hpp"
|
||||
#include "CharClass.hpp"
|
||||
#include "Inventory.hpp"
|
||||
#include "Settings.hpp"
|
||||
#include "Books.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include "Dialogue.hpp"
|
||||
#include "Factions.hpp"
|
||||
#include "Cells.hpp"
|
||||
#include "Quests.hpp"
|
||||
#include "Spells.hpp"
|
||||
#include "NetActor.hpp"
|
||||
#include "CellState.hpp"
|
||||
|
||||
struct Player;
|
||||
typedef std::map<RakNet::RakNetGUID, Player*> TPlayers;
|
||||
typedef std::map<unsigned short, Player*> TSlots;
|
||||
|
||||
class Players
|
||||
{
|
||||
public:
|
||||
static void newPlayer(RakNet::RakNetGUID guid);
|
||||
static void deletePlayer(RakNet::RakNetGUID guid);
|
||||
static Player *getPlayer(RakNet::RakNetGUID guid);
|
||||
static Player *getPlayer(unsigned short id);
|
||||
static TPlayers *getPlayers();
|
||||
static unsigned short getLastPlayerId();
|
||||
|
||||
private:
|
||||
static TPlayers players;
|
||||
static TSlots slots;
|
||||
};
|
||||
|
||||
class Player : public mwmp::BasePlayer
|
||||
class Player : public mwmp::BasePlayer, public NetActor
|
||||
{
|
||||
friend class Cell;
|
||||
friend class Players;
|
||||
unsigned short id;
|
||||
uint64_t getGUID() const {return guid.g;}
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
public:
|
||||
|
||||
enum
|
||||
|
@ -52,12 +51,13 @@ public:
|
|||
LOADED,
|
||||
POSTLOADED
|
||||
};
|
||||
Player(RakNet::RakNetGUID guid);
|
||||
explicit Player(RakNet::RakNetGUID guid);
|
||||
|
||||
unsigned short getId();
|
||||
void setId(unsigned short id);
|
||||
|
||||
bool isHandshaked();
|
||||
int handshakeAttempts();
|
||||
void setHandshake();
|
||||
|
||||
void setLoadState(int state);
|
||||
|
@ -70,11 +70,129 @@ public:
|
|||
|
||||
void forEachLoaded(std::function<void(Player *pl, Player *other)> func);
|
||||
|
||||
void update();
|
||||
|
||||
public:
|
||||
void kick() const;
|
||||
void ban() const;
|
||||
void cleanChat();
|
||||
|
||||
int getAvgPing();
|
||||
|
||||
std::string getName();
|
||||
void setName(const std::string &name);
|
||||
void setCharGenStages(int currentStage, int endStage);
|
||||
void message(const std::string &message, bool toAll = false);
|
||||
int getGender() const;
|
||||
void setGender(int gender);
|
||||
std::string getRace() const;
|
||||
void setRace(const std::string &race);
|
||||
std::string getHead() const;
|
||||
void setHead(const std::string &head);
|
||||
std::string getHair() const;
|
||||
void setHair(const std::string &hair);
|
||||
std::string getBirthsign() const;
|
||||
void setBirthsign(const std::string &sign);
|
||||
|
||||
int getBounty() const;
|
||||
void setBounty(int bounty);
|
||||
int getLevel() const;
|
||||
void setLevel(int level);
|
||||
int getLevelProgress() const;
|
||||
void setLevelProgress(int progress);
|
||||
|
||||
/**
|
||||
* \brief Send a PlayerResurrect packet about a player.
|
||||
*
|
||||
* This sends the packet to all players connected to the server.
|
||||
*
|
||||
* \param type The type of resurrection (0 for REGULAR, 1 for IMPERIAL_SHRINE, 2 for TRIBUNAL_TEMPLE).
|
||||
*/
|
||||
void resurrect(unsigned int type);
|
||||
|
||||
/**
|
||||
* \brief Send a PlayerJail packet about a player.
|
||||
*
|
||||
* This is similar to the player being jailed by a guard, but provides extra parameters for
|
||||
* increased flexibility.
|
||||
*
|
||||
* It is only sent to the player being jailed, as the other players will be informed of the
|
||||
* jailing's actual consequences via other packets sent by the affected client.
|
||||
*
|
||||
* \param jailDays The number of days to spend jailed, where each day affects one skill point.
|
||||
* \param ignoreJailTeleportation Whether the player being teleported to the nearest jail
|
||||
* marker should be overridden.
|
||||
* \param ignoreJailSkillIncrease Whether the player's Sneak and Security skills should be
|
||||
* prevented from increasing as a result of the jailing,
|
||||
* overriding default behavior.
|
||||
* \param jailProgressText The text that should be displayed while jailed.
|
||||
* \param jailEndText The text that should be displayed once the jailing period is over.
|
||||
*/
|
||||
void jail(int jailDays, bool ignoreJailTeleportation, bool ignoreJailSkillIncreases,
|
||||
const std::string &jailProgressText, const std::string &jailEndText);
|
||||
|
||||
bool getWerewolfState() const;
|
||||
void setWerewolfState(bool state);
|
||||
|
||||
std::string getCreatureModel() const;
|
||||
void setCreatureModel(const std::string &model);
|
||||
void creatureName(bool useName);
|
||||
bool isCreatureName() const;
|
||||
|
||||
std::string getIP() const;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return x, y, z
|
||||
*/
|
||||
std::tuple<float, float, float> getPreviousCellPos() const;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return base, current
|
||||
*/
|
||||
std::tuple<int, int> getAttribute(unsigned short id) const;
|
||||
void setAttribute(unsigned short id, int base, int current);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return base, current, progress, increase
|
||||
*/
|
||||
std::tuple<int, int, float> getSkill(unsigned short id) const;
|
||||
void setSkill(unsigned short id, int base, int current, float progress);
|
||||
|
||||
int getSkillIncrease(unsigned short attributeId) const;
|
||||
void setSkillIncrease(unsigned short attributeId, int increase);
|
||||
|
||||
CellState getCellState(int i);
|
||||
size_t cellStateSize() const;
|
||||
void addCellExplored(const std::string &cellDescription);
|
||||
|
||||
CharClass &getCharClass(sol::this_state thisState);
|
||||
GameSettings &getSettings();
|
||||
Books &getBooks();
|
||||
GUI &getGUI();
|
||||
Dialogue &getDialogue();
|
||||
Factions &getFactions();
|
||||
Quests &getQuests();
|
||||
Spells &getSpells();
|
||||
|
||||
void setAuthority();
|
||||
|
||||
private:
|
||||
CellController::TContainer cells;
|
||||
bool handshakeState;
|
||||
int handshakeCounter;
|
||||
int loadState;
|
||||
|
||||
bool /*statsChanged, attributesChanged, skillsChanged, baseInfoChanged, positionChanged,*/ changedMap;
|
||||
CharClass cClass;
|
||||
GameSettings settings;
|
||||
Books books;
|
||||
GUI gui;
|
||||
Dialogue dialogue;
|
||||
Factions factions;
|
||||
Quests quests;
|
||||
Spells spells;
|
||||
sol::table customData;
|
||||
};
|
||||
|
||||
#endif //OPENMW_PLAYER_HPP
|
||||
|
|
115
apps/openmw-mp/Players.cpp
Normal file
115
apps/openmw-mp/Players.cpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
//
|
||||
// Created by koncord on 12.08.17.
|
||||
//
|
||||
|
||||
#include "Players.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
Players::Store Players::store;
|
||||
|
||||
void Players::Init(LuaState &lua)
|
||||
{
|
||||
sol::table playersTable = lua.getState()->create_named_table("Players");
|
||||
playersTable.set_function("getByPID", &Players::getPlayerByPID);
|
||||
playersTable.set_function("getByGUID", &Players::getPlayerByGUID);
|
||||
playersTable.set_function("for_each", [](sol::function func)
|
||||
{
|
||||
for (shared_ptr<Player> player : store)
|
||||
func(player);
|
||||
});
|
||||
|
||||
playersTable.set_function("size", &Players::size);
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<Player> Players::getPlayerByPID(int pid)
|
||||
{
|
||||
const auto &ls = store.get<ByID>();
|
||||
auto it = ls.find(pid);
|
||||
if (it != ls.end())
|
||||
return *it;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Player> Players::getPlayerByGUID(RakNet::RakNetGUID guid)
|
||||
{
|
||||
const auto &ls = store.get<ByGUID>();
|
||||
auto it = ls.find(guid.g);
|
||||
if (it != ls.end())
|
||||
return *it;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Player> Players::addPlayer(RakNet::RakNetGUID guid)
|
||||
{
|
||||
const int maxConnections = 65535;
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Creating new player with guid %lu", guid.g);
|
||||
|
||||
auto player = make_shared<Player>(guid);
|
||||
|
||||
unsigned short findPid = 0;
|
||||
const auto &ls = store.get<ByID>();
|
||||
for (; findPid < maxConnections; ++findPid) // find empty slot
|
||||
{
|
||||
auto it = ls.find(findPid);
|
||||
if (it == ls.end())
|
||||
break;
|
||||
}
|
||||
|
||||
if (findPid >= maxConnections)
|
||||
return nullptr;
|
||||
|
||||
LOG_APPEND(Log::LOG_INFO, "- Storing in slot %i", findPid);
|
||||
player->id = findPid;
|
||||
player->guid = guid;
|
||||
store.push_back(player);
|
||||
return player;
|
||||
}
|
||||
|
||||
void Players::deletePlayerByPID(int pid)
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Marking player (pid %i) for deletion", pid);
|
||||
auto &ls = store.get<ByID>();
|
||||
auto it = ls.find(pid);
|
||||
if (it != ls.end())
|
||||
{
|
||||
ls.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void Players::deletePlayerByGUID(RakNet::RakNetGUID guid)
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Marking player (guid %lu) for deletion", guid.g);
|
||||
auto &ls = store.get<ByGUID>();
|
||||
auto it = ls.find(guid.g);
|
||||
if (it != ls.end())
|
||||
{
|
||||
LOG_APPEND(Log::LOG_INFO, "- references: %d", it->use_count());
|
||||
ls.erase(it);
|
||||
LOG_APPEND(Log::LOG_INFO, "- references: %d", it->use_count());
|
||||
}
|
||||
}
|
||||
|
||||
void Players::for_each(std::function<void (std::shared_ptr<Player>)> func)
|
||||
{
|
||||
for (auto &player : store)
|
||||
func(player);
|
||||
}
|
||||
|
||||
Players::Store::const_iterator Players::begin()
|
||||
{
|
||||
return store.cbegin();
|
||||
}
|
||||
|
||||
Players::Store::const_iterator Players::end()
|
||||
{
|
||||
return store.cend();
|
||||
}
|
||||
|
||||
size_t Players::size()
|
||||
{
|
||||
return store.size();
|
||||
}
|
53
apps/openmw-mp/Players.hpp
Normal file
53
apps/openmw-mp/Players.hpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
//
|
||||
// Created by koncord on 12.08.17.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/ordered_index.hpp>
|
||||
#include <boost/multi_index/identity.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/multi_index/global_fun.hpp>
|
||||
#include <boost/multi_index/mem_fun.hpp>
|
||||
#include <boost/multi_index/random_access_index.hpp>
|
||||
#include "Player.hpp"
|
||||
|
||||
class LuaState;
|
||||
|
||||
|
||||
class Players
|
||||
{
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
public:
|
||||
Players() = delete; // static class
|
||||
protected:
|
||||
|
||||
struct ByID {};
|
||||
struct ByGUID {};
|
||||
|
||||
public:
|
||||
typedef boost::multi_index_container<std::shared_ptr<Player>,
|
||||
boost::multi_index::indexed_by<
|
||||
boost::multi_index::random_access<>,
|
||||
boost::multi_index::ordered_unique<boost::multi_index::tag<ByGUID>, BOOST_MULTI_INDEX_CONST_MEM_FUN(Player, uint64_t, getGUID)>,
|
||||
boost::multi_index::ordered_unique<boost::multi_index::tag<ByID>, boost::multi_index::member<Player, unsigned short, &Player::id> >
|
||||
> > Store;
|
||||
|
||||
|
||||
static std::shared_ptr<Player> getPlayerByPID(int pid);
|
||||
static std::shared_ptr<Player> getPlayerByGUID(RakNet::RakNetGUID guid);
|
||||
static std::shared_ptr<Player> addPlayer(RakNet::RakNetGUID guid);
|
||||
static void deletePlayerByPID(int pid);
|
||||
static void deletePlayerByGUID(RakNet::RakNetGUID guid);
|
||||
static Store::const_iterator begin();
|
||||
static Store::const_iterator end();
|
||||
static size_t size();
|
||||
|
||||
static void for_each(std::function<void(std::shared_ptr<Player>)> func);
|
||||
|
||||
private:
|
||||
static Store store;
|
||||
};
|
||||
|
157
apps/openmw-mp/Quests.cpp
Normal file
157
apps/openmw-mp/Quests.cpp
Normal file
|
@ -0,0 +1,157 @@
|
|||
//
|
||||
// Created by koncord on 25.08.17.
|
||||
//
|
||||
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
#include "Script/LuaState.hpp"
|
||||
#include "Networking.hpp"
|
||||
|
||||
#include "Quests.hpp"
|
||||
#include "Player.hpp"
|
||||
|
||||
void JournalItem::Init(LuaState &lua)
|
||||
{
|
||||
lua.getState()->new_usertype<JournalItem>("JournalItem",
|
||||
"quest", sol::property(&JournalItem::getQuest, &JournalItem::setQuest),
|
||||
"index", sol::property(&JournalItem::getIndex, &JournalItem::setIndex),
|
||||
"actorRefId", sol::property(&JournalItem::getActorRefId, &JournalItem::setActorRefId),
|
||||
"type", sol::property(&JournalItem::getType, &JournalItem::setType)
|
||||
);
|
||||
}
|
||||
|
||||
JournalItem::JournalItem(mwmp::JournalItem item) : item(item)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
JournalItem::~JournalItem()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::string JournalItem::getQuest() const
|
||||
{
|
||||
return item.quest;
|
||||
}
|
||||
|
||||
void JournalItem::setQuest(const std::string &quest)
|
||||
{
|
||||
item.quest = quest;
|
||||
}
|
||||
|
||||
int JournalItem::getIndex() const
|
||||
{
|
||||
return item.index;
|
||||
}
|
||||
|
||||
void JournalItem::setIndex(int index)
|
||||
{
|
||||
item.index = index;
|
||||
}
|
||||
|
||||
int JournalItem::getType() const
|
||||
{
|
||||
return item.type;
|
||||
}
|
||||
|
||||
void JournalItem::setType(int type)
|
||||
{
|
||||
item.type = type;
|
||||
}
|
||||
|
||||
std::string JournalItem::getActorRefId() const
|
||||
{
|
||||
return item.actorRefId;
|
||||
}
|
||||
|
||||
void JournalItem::setActorRefId(const std::string &refid)
|
||||
{
|
||||
item.actorRefId = refid;
|
||||
}
|
||||
|
||||
void Quests::Init(LuaState &lua)
|
||||
{
|
||||
lua.getState()->new_usertype<Quests>("Quests",
|
||||
"getJournalChangesSize", &Quests::getJournalChangesSize,
|
||||
"getKillChangesSize", &Quests::getKillChangesSize,
|
||||
|
||||
"addJournalItem", &Quests::addJournalItem,
|
||||
"setJournalItem", &Quests::setJournalItem,
|
||||
"getJournalItem", &Quests::getJournalItem,
|
||||
|
||||
"addKill", &Quests::addKill,
|
||||
"getKill", &Quests::getKill
|
||||
);
|
||||
}
|
||||
|
||||
Quests::Quests(Player *player) : player(player), changedKills(false), changedJournal(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Quests::~Quests()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Quests::update()
|
||||
{
|
||||
if (changedJournal)
|
||||
{
|
||||
changedJournal = false;
|
||||
auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_JOURNAL);
|
||||
|
||||
packet->setPlayer(player);
|
||||
packet->Send(/*toOthers*/ false);
|
||||
}
|
||||
|
||||
if (changedKills)
|
||||
{
|
||||
changedKills = false;
|
||||
auto packet = mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_KILL_COUNT);
|
||||
|
||||
packet->setPlayer(player);
|
||||
packet->Send(/*toOthers*/ false);
|
||||
}
|
||||
}
|
||||
|
||||
size_t Quests::getJournalChangesSize() const
|
||||
{
|
||||
return player->journalChanges.journalItems.size();
|
||||
}
|
||||
|
||||
size_t Quests::getKillChangesSize() const
|
||||
{
|
||||
return player->killChanges.kills.size();
|
||||
}
|
||||
|
||||
void Quests::addJournalItem(JournalItem item)
|
||||
{
|
||||
player->journalChanges.journalItems.push_back(item.item);
|
||||
changedJournal = true;
|
||||
|
||||
}
|
||||
|
||||
void Quests::setJournalItem(unsigned int id, JournalItem item)
|
||||
{
|
||||
player->journalChanges.journalItems.at(id) = item.item;
|
||||
changedJournal = true;
|
||||
}
|
||||
|
||||
JournalItem Quests::getJournalItem(unsigned int id)
|
||||
{
|
||||
return JournalItem(player->journalChanges.journalItems.at(id));
|
||||
}
|
||||
|
||||
void Quests::addKill(const std::string &refId, int number)
|
||||
{
|
||||
player->killChanges.kills.push_back({refId, number});
|
||||
changedKills = true;
|
||||
}
|
||||
|
||||
std::tuple<std::string, int> Quests::getKill(unsigned int i) const
|
||||
{
|
||||
auto & kill = player->killChanges.kills.at(i);
|
||||
return std::make_tuple(kill.refId, kill.number);
|
||||
}
|
62
apps/openmw-mp/Quests.hpp
Normal file
62
apps/openmw-mp/Quests.hpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
//
|
||||
// Created by koncord on 25.08.17.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <components/openmw-mp/Base/BasePlayer.hpp>
|
||||
|
||||
class LuaState;
|
||||
class Player;
|
||||
|
||||
class JournalItem
|
||||
{
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
public:
|
||||
explicit JournalItem(mwmp::JournalItem item);
|
||||
~JournalItem();
|
||||
|
||||
std::string getQuest() const;
|
||||
void setQuest(const std::string &quest);
|
||||
|
||||
int getIndex() const;
|
||||
void setIndex(int index);
|
||||
|
||||
int getType() const;
|
||||
void setType(int type);
|
||||
|
||||
std::string getActorRefId() const;
|
||||
void setActorRefId(const std::string &refid);
|
||||
|
||||
|
||||
mwmp::JournalItem item;
|
||||
};
|
||||
|
||||
class Quests
|
||||
{
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
public:
|
||||
explicit Quests(Player *player);
|
||||
~Quests();
|
||||
|
||||
void update();
|
||||
|
||||
size_t getJournalChangesSize() const;
|
||||
size_t getKillChangesSize() const;
|
||||
|
||||
void addJournalItem(JournalItem item);
|
||||
void setJournalItem(unsigned int id, JournalItem item);
|
||||
JournalItem getJournalItem(unsigned int id);
|
||||
|
||||
void addKill(const std::string &refId, int number);
|
||||
std::tuple<std::string, int> getKill(unsigned int i) const;
|
||||
|
||||
private:
|
||||
Player *player;
|
||||
bool changedKills, changedJournal;
|
||||
};
|
||||
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
//
|
||||
// Created by koncord on 14.05.16.
|
||||
//
|
||||
|
||||
#include <Script/ScriptFunction.hpp>
|
||||
#include "PublicFnAPI.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
unordered_map<string, Public *> Public::publics;
|
||||
|
||||
Public::~Public()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Public::Public(ScriptFunc _public, const std::string &name, char ret_type, const std::string &def) : ScriptFunction(_public, ret_type, def)
|
||||
{
|
||||
publics.emplace(name, this);
|
||||
}
|
||||
|
||||
Public::Public(ScriptFuncLua _public, lua_State *lua, const std::string &name, char ret_type, const std::string &def) : ScriptFunction(
|
||||
_public, lua, ret_type, def)
|
||||
{
|
||||
publics.emplace(name, this);
|
||||
}
|
||||
|
||||
#if defined(ENABLE_PAWN)
|
||||
Public::Public(ScriptFuncPAWN _public, AMX* amx, const std::string& name, char ret_type, const std::string& def): ScriptFunction(_public, amx, ret_type, def)
|
||||
{
|
||||
publics.emplace(name, this);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
boost::any Public::Call(const std::string &name, const std::vector<boost::any> &args)
|
||||
{
|
||||
auto it = publics.find(name);
|
||||
if (it == publics.end())
|
||||
throw runtime_error("Public with name \"" + name + "\" does not exist");
|
||||
|
||||
return it->second->ScriptFunction::Call(args);
|
||||
}
|
||||
|
||||
|
||||
const std::string &Public::GetDefinition(const std::string &name)
|
||||
{
|
||||
auto it = publics.find(name);
|
||||
|
||||
if (it == publics.end())
|
||||
throw runtime_error("Public with name \"" + name + "\" does not exist");
|
||||
|
||||
return it->second->def;
|
||||
}
|
||||
|
||||
|
||||
bool Public::IsLua(const std::string &name)
|
||||
{
|
||||
#if !defined(ENABLE_LUA)
|
||||
return false;
|
||||
#else
|
||||
auto it = publics.find(name);
|
||||
if (it == publics.end())
|
||||
throw runtime_error("Public with name \"" + name + "\" does not exist");
|
||||
|
||||
return it->second->script_type == SCRIPT_LUA;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Public::IsPAWN(const std::string &name)
|
||||
{
|
||||
#if !defined(ENABLE_PAWN)
|
||||
return false;
|
||||
#else
|
||||
auto it = publics.find(name);
|
||||
|
||||
if (it == publics.end())
|
||||
throw runtime_error("Public with name \"" + name + "\" does not exist");
|
||||
|
||||
return it->second->script_type == SCRIPT_PAWN;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void Public::DeleteAll()
|
||||
{
|
||||
for (auto it = publics.begin(); it != publics.end(); it++)
|
||||
{
|
||||
Public *_public = it->second;
|
||||
delete _public;
|
||||
publics.erase(it);
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
//
|
||||
// Created by koncord on 14.05.16.
|
||||
//
|
||||
|
||||
#ifndef PLUGINSYSTEM3_PUBLICFNAPI_HPP
|
||||
#define PLUGINSYSTEM3_PUBLICFNAPI_HPP
|
||||
|
||||
#include <unordered_map>
|
||||
#include <Script/ScriptFunction.hpp>
|
||||
|
||||
|
||||
class Public : public ScriptFunction
|
||||
{
|
||||
private:
|
||||
~Public();
|
||||
|
||||
static std::unordered_map<std::string, Public *> publics;
|
||||
|
||||
Public(ScriptFunc _public, const std::string &name, char ret_type, const std::string &def);
|
||||
#if defined(ENABLE_PAWN)
|
||||
Public(ScriptFuncPAWN _public, AMX* amx, const std::string& name, char ret_type, const std::string& def);
|
||||
#endif
|
||||
#if defined(ENABLE_LUA)
|
||||
Public(ScriptFuncLua _public, lua_State *lua, const std::string &name, char ret_type, const std::string &def);
|
||||
#endif
|
||||
|
||||
public:
|
||||
template<typename... Args>
|
||||
static void MakePublic(Args &&... args)
|
||||
{ new Public(std::forward<Args>(args)...); }
|
||||
|
||||
static boost::any Call(const std::string &name, const std::vector<boost::any> &args);
|
||||
|
||||
static const std::string& GetDefinition(const std::string& name);
|
||||
|
||||
static bool IsPAWN(const std::string &name);
|
||||
static bool IsLua(const std::string &name);
|
||||
|
||||
static void DeleteAll();
|
||||
};
|
||||
|
||||
#endif //PLUGINSYSTEM3_PUBLICFNAPI_HPP
|
|
@ -1,238 +0,0 @@
|
|||
//
|
||||
// Created by koncord on 15.03.16.
|
||||
//
|
||||
|
||||
#include "TimerAPI.hpp"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include <iostream>
|
||||
using namespace mwmp;
|
||||
using namespace std;
|
||||
|
||||
Timer::Timer(ScriptFunc callback, long msec, const std::string& def, std::vector<boost::any> args) : ScriptFunction(callback, 'v', def)
|
||||
{
|
||||
targetMsec = msec;
|
||||
this->args = args;
|
||||
end = true;
|
||||
}
|
||||
|
||||
#if defined(ENABLE_PAWN)
|
||||
Timer::Timer(AMX *amx, ScriptFuncPAWN callback, long msec, const std::string &def, std::vector<boost::any> args): ScriptFunction(callback, amx, 'v', def)
|
||||
{
|
||||
targetMsec = msec;
|
||||
this->args = args;
|
||||
end = true;
|
||||
}
|
||||
#endif
|
||||
#if defined(ENABLE_LUA)
|
||||
Timer::Timer(lua_State *lua, ScriptFuncLua callback, long msec, const std::string& def, std::vector<boost::any> args): ScriptFunction(callback, lua, 'v', def)
|
||||
{
|
||||
targetMsec = msec;
|
||||
this->args = args;
|
||||
end = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void Timer::Tick()
|
||||
{
|
||||
if (end)
|
||||
return;
|
||||
|
||||
const auto duration = chrono::system_clock::now().time_since_epoch();
|
||||
const auto time = chrono::duration_cast<chrono::milliseconds>(duration).count();
|
||||
|
||||
if (time - startTime >= targetMsec)
|
||||
{
|
||||
end = true;
|
||||
Call(args);
|
||||
}
|
||||
}
|
||||
|
||||
bool Timer::IsEnd()
|
||||
{
|
||||
return end;
|
||||
}
|
||||
|
||||
void Timer::Stop()
|
||||
{
|
||||
end = true;
|
||||
}
|
||||
|
||||
void Timer::Restart(int msec)
|
||||
{
|
||||
targetMsec = msec;
|
||||
Start();
|
||||
}
|
||||
|
||||
void Timer::Start()
|
||||
{
|
||||
end = false;
|
||||
|
||||
const auto duration = chrono::system_clock::now().time_since_epoch();
|
||||
const auto msec = chrono::duration_cast<chrono::milliseconds>(duration).count();
|
||||
startTime = msec;
|
||||
}
|
||||
|
||||
int TimerAPI::pointer = 0;
|
||||
std::unordered_map<int, Timer* > TimerAPI::timers;
|
||||
|
||||
#if defined(ENABLE_PAWN)
|
||||
int TimerAPI::CreateTimerPAWN(AMX *amx, ScriptFuncPAWN callback, long msec, const string& def, std::vector<boost::any> args)
|
||||
{
|
||||
int id = -1;
|
||||
|
||||
for (auto timer : timers)
|
||||
{
|
||||
if (timer.second != nullptr)
|
||||
continue;
|
||||
timer.second = new Timer(amx, callback, msec, def, args);
|
||||
id = timer.first;
|
||||
}
|
||||
|
||||
if (id == -1)
|
||||
{
|
||||
timers[pointer] = new Timer(amx, callback, msec, def, args);
|
||||
id = pointer;
|
||||
pointer++;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_LUA)
|
||||
int TimerAPI::CreateTimerLua(lua_State *lua, ScriptFuncLua callback, long msec, const std::string& def, std::vector<boost::any> args)
|
||||
{
|
||||
int id = -1;
|
||||
|
||||
for (auto timer : timers)
|
||||
{
|
||||
if (timer.second != nullptr)
|
||||
continue;
|
||||
timer.second = new Timer(lua, callback, msec, def, args);
|
||||
id = timer.first;
|
||||
}
|
||||
|
||||
if (id == -1)
|
||||
{
|
||||
timers[pointer] = new Timer(lua, callback, msec, def, args);
|
||||
id = pointer;
|
||||
pointer++;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int TimerAPI::CreateTimer(ScriptFunc callback, long msec, const std::string &def, std::vector<boost::any> args)
|
||||
{
|
||||
int id = -1;
|
||||
|
||||
for (auto timer : timers)
|
||||
{
|
||||
if (timer.second != nullptr)
|
||||
continue;
|
||||
timer.second = new Timer(callback, msec, def, args);
|
||||
id = timer.first;
|
||||
}
|
||||
|
||||
if (id == -1)
|
||||
{
|
||||
timers[pointer] = new Timer(callback, msec, def, args);
|
||||
id = pointer;
|
||||
pointer++;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void TimerAPI::FreeTimer(int timerid)
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
if (timers.at(timerid) != nullptr)
|
||||
{
|
||||
delete timers[timerid];
|
||||
timers[timerid] = nullptr;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
std::cerr << "Timer " << timerid << " not found!" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void TimerAPI::ResetTimer(int timerid, long msec)
|
||||
{
|
||||
try
|
||||
{
|
||||
timers.at(timerid)->Restart(msec);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
std::cerr << "Timer " << timerid << " not found!" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void TimerAPI::StartTimer(int timerid)
|
||||
{
|
||||
try
|
||||
{
|
||||
Timer *timer = timers.at(timerid);
|
||||
if (timer == nullptr)
|
||||
throw 1;
|
||||
timer->Start();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
std::cerr << "Timer " << timerid << " not found!" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void TimerAPI::StopTimer(int timerid)
|
||||
{
|
||||
try
|
||||
{
|
||||
timers.at(timerid)->Stop();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
std::cerr << "Timer " << timerid << " not found!" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
bool TimerAPI::IsEndTimer(int timerid)
|
||||
{
|
||||
bool ret = false;
|
||||
try
|
||||
{
|
||||
ret = timers.at(timerid)->IsEnd();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
std::cerr << "Timer " << timerid << " not found!" << endl;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void TimerAPI::Terminate()
|
||||
{
|
||||
for (auto timer : timers)
|
||||
{
|
||||
if (timer.second != nullptr)
|
||||
delete timer.second;
|
||||
timer.second = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void TimerAPI::Tick()
|
||||
{
|
||||
for (auto timer : timers)
|
||||
{
|
||||
if (timer.second != nullptr)
|
||||
timer.second->Tick();
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
//
|
||||
// Created by koncord on 15.03.16.
|
||||
//
|
||||
|
||||
#ifndef OPENMW_TIMERAPI_HPP
|
||||
#define OPENMW_TIMERAPI_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <Script/Script.hpp>
|
||||
#include <Script/ScriptFunction.hpp>
|
||||
|
||||
namespace mwmp
|
||||
{
|
||||
|
||||
class TimerAPI;
|
||||
|
||||
class Timer: public ScriptFunction
|
||||
{
|
||||
friend class TimerAPI;
|
||||
|
||||
public:
|
||||
|
||||
Timer(ScriptFunc callback, long msec, const std::string& def, std::vector<boost::any> args);
|
||||
#if defined(ENABLE_PAWN)
|
||||
Timer(AMX *amx, ScriptFuncPAWN callback, long msec, const std::string& def, std::vector<boost::any> args);
|
||||
#endif
|
||||
#if defined(ENABLE_LUA)
|
||||
Timer(lua_State *lua, ScriptFuncLua callback, long msec, const std::string& def, std::vector<boost::any> args);
|
||||
#endif
|
||||
void Tick();
|
||||
|
||||
bool IsEnd();
|
||||
void Stop();
|
||||
void Start();
|
||||
void Restart(int msec);
|
||||
private:
|
||||
double startTime, targetMsec;
|
||||
std::string publ, arg_types;
|
||||
std::vector<boost::any> args;
|
||||
Script *scr;
|
||||
bool end;
|
||||
};
|
||||
|
||||
class TimerAPI
|
||||
{
|
||||
public:
|
||||
#if defined(ENABLE_PAWN)
|
||||
static int CreateTimerPAWN(AMX *amx, ScriptFuncPAWN callback, long msec, const std::string& def, std::vector<boost::any> args);
|
||||
#endif
|
||||
#if defined(ENABLE_LUA)
|
||||
static int CreateTimerLua(lua_State *lua, ScriptFuncLua callback, long msec, const std::string& def, std::vector<boost::any> args);
|
||||
#endif
|
||||
static int CreateTimer(ScriptFunc callback, long msec, const std::string& def, std::vector<boost::any> args);
|
||||
static void FreeTimer(int timerid);
|
||||
static void ResetTimer(int timerid, long msec);
|
||||
static void StartTimer(int timerid);
|
||||
static void StopTimer(int timerid);
|
||||
static bool IsEndTimer(int timerid);
|
||||
|
||||
static void Terminate();
|
||||
|
||||
static void Tick();
|
||||
private:
|
||||
static std::unordered_map<int, Timer* > timers;
|
||||
static int pointer;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //OPENMW_TIMERAPI_HPP
|
102
apps/openmw-mp/Script/CommandController.cpp
Normal file
102
apps/openmw-mp/Script/CommandController.cpp
Normal file
|
@ -0,0 +1,102 @@
|
|||
//
|
||||
// Created by koncord on 08.08.17.
|
||||
//
|
||||
#include "CommandController.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/spirit/home/x3.hpp>
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include "Player.hpp"
|
||||
#include "LuaState.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void CommandController::Init(LuaState &lua)
|
||||
{
|
||||
sol::table cmdCtrlTable = lua.getState()->create_named_table("CommandController");
|
||||
|
||||
cmdCtrlTable["registerCommand"] = [&lua](const std::string &command, sol::function func, const std::string &helpMessage) {
|
||||
return lua.getCmdCtrl().registerCommand(Misc::StringUtils::lowerCase(command), func, helpMessage);
|
||||
};
|
||||
|
||||
cmdCtrlTable["unregisterCommand"] = [&lua](const std::string &command) {
|
||||
lua.getCmdCtrl().unregisterCommand(Misc::StringUtils::lowerCase(command));
|
||||
};
|
||||
|
||||
cmdCtrlTable["hasCommand"] = [&lua](const std::string &command) {
|
||||
return lua.getCmdCtrl().hasCommand(Misc::StringUtils::lowerCase(command));
|
||||
};
|
||||
|
||||
cmdCtrlTable["getHelpStrings"] = [&lua]() {
|
||||
auto &commands = lua.getCmdCtrl().commands;
|
||||
sol::table helpTable = lua.getState()->create_table(commands.size(), 0);
|
||||
|
||||
for (const auto &cmd : commands)
|
||||
helpTable.add(cmd.first, cmd.second.helpMessage);
|
||||
|
||||
return helpTable;
|
||||
};
|
||||
}
|
||||
|
||||
bool CommandController::registerCommand(const std::string &command, sol::function func, const std::string &helpMessage)
|
||||
{
|
||||
auto iter = commands.find(command);
|
||||
if (iter == commands.end())
|
||||
{
|
||||
commands.emplace(command, Command {std::move(func), helpMessage});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CommandController::unregisterCommand(const std::string &command)
|
||||
{
|
||||
commands.erase(command);
|
||||
}
|
||||
|
||||
bool CommandController::hasCommand(const std::string &command)
|
||||
{
|
||||
return commands.find(command) != commands.end();
|
||||
}
|
||||
|
||||
std::pair<CommandController::ExecResult, std::string> CommandController::exec(std::shared_ptr<Player> player, const std::string &message)
|
||||
{
|
||||
char cmdChar = message[0];
|
||||
if (message.size() < 2 || (cmdChar != '/' && cmdChar != '!'))
|
||||
return make_pair(ExecResult::NOT_CMD, "");
|
||||
|
||||
auto tokens = cmdParser(message);
|
||||
|
||||
auto cmd = commands.find(Misc::StringUtils::lowerCase(&tokens[0][1]));
|
||||
if (cmd != commands.end())
|
||||
{
|
||||
tokens.pop_front();
|
||||
bool result = cmd->second.func(player, sol::as_table(tokens));
|
||||
if (result)
|
||||
return make_pair(ExecResult::SUCCESS, "");
|
||||
|
||||
return make_pair(ExecResult::FAIL, cmd->second.helpMessage);
|
||||
}
|
||||
|
||||
return make_pair(ExecResult::NOT_FOUND, "");
|
||||
}
|
||||
|
||||
std::deque<std::string> CommandController::cmdParser(const std::string &message)
|
||||
{
|
||||
deque<string> ret;
|
||||
namespace x3 = boost::spirit::x3;
|
||||
auto const sep = ' ';
|
||||
auto const quoted = '"' >> *~x3::char_('"') >> '"';
|
||||
auto const unquoted = *~x3::char_(sep);
|
||||
auto const arguments = (quoted | unquoted) % sep;
|
||||
/*auto const command = '/' >> *~x3::char_(sep) >> sep;
|
||||
|
||||
if (!x3::phrase_parse(message.cbegin(), message.cend(), arguments, command, ret))
|
||||
throw runtime_error("failed to parse message: "+ message);*/
|
||||
|
||||
if (!x3::parse(message.cbegin(), message.cend(), arguments, ret))
|
||||
throw runtime_error("failed to parse message: " + message);
|
||||
|
||||
return ret;
|
||||
}
|
63
apps/openmw-mp/Script/CommandController.hpp
Normal file
63
apps/openmw-mp/Script/CommandController.hpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// Created by koncord on 08.08.17.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sol.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include <string>
|
||||
#include <deque>
|
||||
|
||||
class Player;
|
||||
class LuaState;
|
||||
|
||||
struct Command
|
||||
{
|
||||
sol::function func;
|
||||
std::string helpMessage;
|
||||
};
|
||||
|
||||
class CommandController
|
||||
{
|
||||
typedef std::unordered_map<std::string, Command> Container;
|
||||
typedef Container::iterator Iter;
|
||||
typedef Container::const_iterator CIter;
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
public:
|
||||
|
||||
enum class ExecResult : int
|
||||
{
|
||||
NOT_FOUND,
|
||||
SUCCESS,
|
||||
FAIL,
|
||||
NOT_CMD
|
||||
};
|
||||
|
||||
/**
|
||||
* Register new command. Only unique commands are allowed.
|
||||
* @param command name of command. Case sensitive. No need in command prefix ('/' or '!').
|
||||
* @param helpMessage help message. Shows in the '/help' command also appears if exec() fails.
|
||||
* @param callback Will be called when command is called.
|
||||
* @return false if the command already registered.
|
||||
*/
|
||||
bool registerCommand(const std::string &command, sol::function callback, const std::string &helpMessage);
|
||||
/**
|
||||
* Removes a registered command
|
||||
* @param command name of command.
|
||||
*/
|
||||
void unregisterCommand(const std::string &command);
|
||||
|
||||
/**
|
||||
* Check a command is exist.
|
||||
* @param command name of command
|
||||
* @return false if the command did not exist.
|
||||
*/
|
||||
bool hasCommand(const std::string &command);
|
||||
|
||||
std::pair<ExecResult, std::string> exec(std::shared_ptr<Player> player, const std::string &message);
|
||||
private:
|
||||
std::deque<std::string> cmdParser(const std::string &message);
|
||||
Container commands;
|
||||
};
|
152
apps/openmw-mp/Script/EventController.cpp
Normal file
152
apps/openmw-mp/Script/EventController.cpp
Normal file
|
@ -0,0 +1,152 @@
|
|||
//
|
||||
// Created by koncord on 30.07.17.
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include "EventController.hpp"
|
||||
|
||||
using namespace std;
|
||||
#define ADD_CORE_EVENT(event) #event, CoreEvent::event
|
||||
void EventController::Init(LuaState &lua)
|
||||
{
|
||||
sol::table eventsTable = lua.getState()->create_named_table("Event");
|
||||
|
||||
eventsTable["register"] = [&lua](int event, sol::function func, sol::this_environment te) {
|
||||
sol::environment& env = te;
|
||||
lua.getEventCtrl().registerEvent(event, env, func);
|
||||
};
|
||||
eventsTable["stop"] = [&lua](int event) {
|
||||
lua.getEventCtrl().stop(event);
|
||||
};
|
||||
eventsTable["create"] = [&lua]() {
|
||||
return lua.getEventCtrl().createEvent();
|
||||
};
|
||||
eventsTable["raise"] = [&lua](unsigned event, sol::table data) {
|
||||
lua.getEventCtrl().raiseEvent(event, data);
|
||||
};
|
||||
eventsTable["raiseSpecified"] = [&lua](unsigned event, const std::string &moduleName, sol::table data) {
|
||||
lua.getEventCtrl().raiseEvent(event, data, moduleName);
|
||||
};
|
||||
}
|
||||
|
||||
EventController::EventController(LuaState *luaCtrl)
|
||||
{
|
||||
this->luaCtrl = luaCtrl;
|
||||
|
||||
#ifdef SERVER_DEBUG
|
||||
luaCtrl->getState()->new_enum<false>
|
||||
#else
|
||||
luaCtrl->getState()->new_enum
|
||||
#endif
|
||||
("Events",
|
||||
ADD_CORE_EVENT(ON_POST_INIT),
|
||||
ADD_CORE_EVENT(ON_EXIT),
|
||||
ADD_CORE_EVENT(ON_PLAYER_CONNECT),
|
||||
ADD_CORE_EVENT(ON_PLAYER_DISCONNECT),
|
||||
ADD_CORE_EVENT(ON_PLAYER_DEATH),
|
||||
ADD_CORE_EVENT(ON_PLAYER_RESURRECT),
|
||||
ADD_CORE_EVENT(ON_PLAYER_CELLCHANGE),
|
||||
ADD_CORE_EVENT(ON_PLAYER_KILLCOUNT),
|
||||
ADD_CORE_EVENT(ON_PLAYER_ATTRIBUTE),
|
||||
ADD_CORE_EVENT(ON_PLAYER_SKILL),
|
||||
ADD_CORE_EVENT(ON_PLAYER_LEVEL),
|
||||
ADD_CORE_EVENT(ON_PLAYER_BOUNTY),
|
||||
ADD_CORE_EVENT(ON_PLAYER_EQUIPMENT),
|
||||
ADD_CORE_EVENT(ON_PLAYER_INVENTORY),
|
||||
ADD_CORE_EVENT(ON_PLAYER_JOURNAL),
|
||||
ADD_CORE_EVENT(ON_PLAYER_FACTION),
|
||||
ADD_CORE_EVENT(ON_PLAYER_SHAPESHIFT),
|
||||
ADD_CORE_EVENT(ON_PLAYER_SPELLBOOK),
|
||||
ADD_CORE_EVENT(ON_PLAYER_TOPIC),
|
||||
ADD_CORE_EVENT(ON_PLAYER_DISPOSITION),
|
||||
ADD_CORE_EVENT(ON_PLAYER_BOOK),
|
||||
ADD_CORE_EVENT(ON_PLAYER_MAP),
|
||||
ADD_CORE_EVENT(ON_PLAYER_REST),
|
||||
ADD_CORE_EVENT(ON_PLAYER_SENDMESSAGE),
|
||||
ADD_CORE_EVENT(ON_PLAYER_ENDCHARGEN),
|
||||
ADD_CORE_EVENT(ON_GUI_ACTION),
|
||||
ADD_CORE_EVENT(ON_REQUEST_PLUGIN_LIST),
|
||||
ADD_CORE_EVENT(ON_MP_REFNUM),
|
||||
ADD_CORE_EVENT(ON_ACTOR_EQUIPMENT),
|
||||
ADD_CORE_EVENT(ON_ACTOR_CELL_CHANGE),
|
||||
ADD_CORE_EVENT(ON_ACTOR_LIST),
|
||||
ADD_CORE_EVENT(ON_ACTOR_TEST),
|
||||
ADD_CORE_EVENT(ON_CELL_LOAD),
|
||||
ADD_CORE_EVENT(ON_CELL_UNLOAD),
|
||||
ADD_CORE_EVENT(ON_CELL_DELETION),
|
||||
ADD_CORE_EVENT(ON_CONTAINER),
|
||||
ADD_CORE_EVENT(ON_DOOR_STATE),
|
||||
ADD_CORE_EVENT(ON_OBJECT_PLACE),
|
||||
ADD_CORE_EVENT(ON_OBJECT_STATE),
|
||||
ADD_CORE_EVENT(ON_OBJECT_SPAWN),
|
||||
ADD_CORE_EVENT(ON_OBJECT_DELETE),
|
||||
ADD_CORE_EVENT(ON_OBJECT_LOCK),
|
||||
ADD_CORE_EVENT(ON_OBJECT_SCALE),
|
||||
ADD_CORE_EVENT(ON_OBJECT_TRAP)
|
||||
);
|
||||
|
||||
sol::state &state = *luaCtrl->getState();
|
||||
sol::table eventsEnum = state["Events"];
|
||||
for (int i = CoreEvent::FIRST; i < CoreEvent::LAST; ++i)
|
||||
{
|
||||
#ifdef SERVER_DEBUG
|
||||
bool found = false;
|
||||
eventsEnum.for_each([&found, &i](sol::object key, sol::object value){
|
||||
if (value.as<int>() == i)
|
||||
{
|
||||
found = true;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
if (!found)
|
||||
throw runtime_error("Event " + to_string(i) + " is not registered. Dear developer, please fix me :D");
|
||||
#endif
|
||||
events[i]; // create core event
|
||||
}
|
||||
}
|
||||
|
||||
void EventController::registerEvent(int event, sol::environment &env, sol::function& func)
|
||||
{
|
||||
auto iter = events.find(event);
|
||||
if (iter != events.end())
|
||||
iter->second.push(env, func);
|
||||
}
|
||||
|
||||
void EventController::stop(int event)
|
||||
{
|
||||
printf("EventController::stop\n");
|
||||
auto iter = events.find(event);
|
||||
if (iter != events.end())
|
||||
iter->second.stop();
|
||||
}
|
||||
|
||||
CallbackCollection &EventController::GetEvents(Event event)
|
||||
{
|
||||
return events.at(event);
|
||||
}
|
||||
|
||||
Event EventController::createEvent()
|
||||
{
|
||||
events[lastEvent];
|
||||
return lastEvent++;
|
||||
}
|
||||
|
||||
void EventController::raiseEvent(Event id, sol::table data, const string &moduleName)
|
||||
{
|
||||
auto iter = events.find(id);
|
||||
if (iter != events.end())
|
||||
{
|
||||
if (!moduleName.empty())
|
||||
{
|
||||
auto f = std::find_if (iter->second.begin(), iter->second.end(), [&moduleName](const auto &item){
|
||||
return item.first["ModuleName"]["name"] == moduleName;
|
||||
});
|
||||
if (f != iter->second.end())
|
||||
f->second.call(data); // call only specified mod
|
||||
}
|
||||
iter->second.call(CallbackCollection::type_tag<void>(), data); // call all registered events with this id
|
||||
}
|
||||
else
|
||||
cerr << "Event with id: " << id << " is not registered" << endl;
|
||||
}
|
155
apps/openmw-mp/Script/EventController.hpp
Normal file
155
apps/openmw-mp/Script/EventController.hpp
Normal file
|
@ -0,0 +1,155 @@
|
|||
//
|
||||
// Created by koncord on 30.07.17.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sol.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "LuaState.hpp"
|
||||
|
||||
typedef unsigned Event;
|
||||
|
||||
namespace CoreEvent
|
||||
{
|
||||
enum
|
||||
{
|
||||
ON_EXIT = 0,
|
||||
ON_POST_INIT,
|
||||
ON_REQUEST_PLUGIN_LIST,
|
||||
ON_PLAYER_CONNECT,
|
||||
ON_PLAYER_DISCONNECT,
|
||||
ON_PLAYER_DEATH,
|
||||
ON_PLAYER_RESURRECT,
|
||||
ON_PLAYER_CELLCHANGE,
|
||||
ON_PLAYER_KILLCOUNT,
|
||||
ON_PLAYER_ATTRIBUTE,
|
||||
ON_PLAYER_SKILL,
|
||||
ON_PLAYER_LEVEL,
|
||||
ON_PLAYER_BOUNTY,
|
||||
ON_PLAYER_EQUIPMENT,
|
||||
ON_PLAYER_INVENTORY,
|
||||
ON_PLAYER_JOURNAL,
|
||||
ON_PLAYER_FACTION,
|
||||
ON_PLAYER_SHAPESHIFT,
|
||||
ON_PLAYER_SPELLBOOK,
|
||||
ON_PLAYER_TOPIC,
|
||||
ON_PLAYER_DISPOSITION,
|
||||
ON_PLAYER_BOOK,
|
||||
ON_PLAYER_MAP,
|
||||
ON_PLAYER_REST,
|
||||
ON_PLAYER_SENDMESSAGE,
|
||||
ON_PLAYER_ENDCHARGEN,
|
||||
|
||||
ON_GUI_ACTION,
|
||||
ON_MP_REFNUM,
|
||||
|
||||
ON_ACTOR_EQUIPMENT,
|
||||
ON_ACTOR_CELL_CHANGE,
|
||||
ON_ACTOR_LIST,
|
||||
ON_ACTOR_TEST,
|
||||
|
||||
ON_CELL_LOAD,
|
||||
ON_CELL_UNLOAD,
|
||||
ON_CELL_DELETION,
|
||||
|
||||
ON_CONTAINER,
|
||||
ON_DOOR_STATE,
|
||||
ON_OBJECT_PLACE,
|
||||
ON_OBJECT_STATE,
|
||||
ON_OBJECT_SPAWN,
|
||||
ON_OBJECT_DELETE,
|
||||
ON_OBJECT_LOCK,
|
||||
ON_OBJECT_SCALE,
|
||||
ON_OBJECT_TRAP,
|
||||
|
||||
LAST,
|
||||
};
|
||||
const int FIRST = ON_EXIT;
|
||||
}
|
||||
|
||||
class CallbackCollection // todo: add sort by dependencies
|
||||
{
|
||||
public:
|
||||
typedef std::vector<std::pair<sol::environment, sol::function>> Container;
|
||||
typedef Container::iterator Iterator;
|
||||
typedef Container::const_iterator CIterator;
|
||||
|
||||
template<typename> struct type_tag {};
|
||||
|
||||
void push(sol::environment &env, sol::function &func) { functions.emplace_back(env, func); }
|
||||
CIterator begin() const { return functions.begin(); }
|
||||
CIterator end() const { return functions.end(); }
|
||||
|
||||
void stop() {_stop = true;}
|
||||
bool isStoped() const {return _stop;}
|
||||
CIterator stopedAt() const { return lastCalled; }
|
||||
|
||||
template<typename... Args>
|
||||
void call(type_tag<void>, Args&&... args)
|
||||
{
|
||||
lastCalled = functions.end();
|
||||
_stop = false;
|
||||
for (CIterator iter = functions.begin(); iter != functions.end(); ++iter)
|
||||
{
|
||||
if (!_stop)
|
||||
iter->second.call(std::forward<Args>(args)...);
|
||||
else
|
||||
{
|
||||
lastCalled = iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename R, typename... Args>
|
||||
decltype(auto) call(type_tag<R>, Args&&... args)
|
||||
{
|
||||
R ret;
|
||||
|
||||
lastCalled = functions.end();
|
||||
_stop = false;
|
||||
for (CIterator iter = functions.begin(); iter != functions.end(); ++iter)
|
||||
{
|
||||
if (!_stop)
|
||||
ret = iter->second.call(std::forward<Args>(args)...);
|
||||
else
|
||||
{
|
||||
lastCalled = iter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
Container functions;
|
||||
CIterator lastCalled;
|
||||
bool _stop = false;
|
||||
};
|
||||
|
||||
class EventController
|
||||
{
|
||||
public:
|
||||
static void Init(LuaState &lua);
|
||||
public:
|
||||
explicit EventController(LuaState *luaCtrl);
|
||||
typedef std::unordered_map<int, CallbackCollection> Container;
|
||||
|
||||
void registerEvent(int event, sol::environment &env, sol::function& func);
|
||||
CallbackCollection& GetEvents(Event event);
|
||||
Event createEvent();
|
||||
void raiseEvent(Event id, sol::table data, const std::string &moduleName = "");
|
||||
void stop(int event);
|
||||
|
||||
template<Event event, typename R = void, typename... Args>
|
||||
R Call(Args&&... args)
|
||||
{
|
||||
return events.at(event).call(CallbackCollection::type_tag<R>{}, std::forward<Args>(args)...);
|
||||
}
|
||||
private:
|
||||
Container events;
|
||||
Event lastEvent = CoreEvent::LAST;
|
||||
LuaState *luaCtrl;
|
||||
};
|
|
@ -1,330 +0,0 @@
|
|||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
#include <components/openmw-mp/Base/BaseActor.hpp>
|
||||
|
||||
#include <apps/openmw-mp/Networking.hpp>
|
||||
#include <apps/openmw-mp/Player.hpp>
|
||||
#include <apps/openmw-mp/Utils.hpp>
|
||||
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
|
||||
|
||||
#include <components/esm/creaturestats.hpp>
|
||||
|
||||
#include "Actors.hpp"
|
||||
|
||||
using namespace mwmp;
|
||||
|
||||
BaseActorList *readActorList;
|
||||
BaseActorList writeActorList;
|
||||
|
||||
BaseActor tempActor;
|
||||
const BaseActor emptyActor = {};
|
||||
|
||||
static std::string tempCellDescription;
|
||||
|
||||
void ActorFunctions::ReadLastActorList() noexcept
|
||||
{
|
||||
readActorList = mwmp::Networking::getPtr()->getLastActorList();
|
||||
}
|
||||
|
||||
void ActorFunctions::ReadCellActorList(const char* cellDescription) noexcept
|
||||
{
|
||||
ESM::Cell esmCell = Utils::getCellFromDescription(cellDescription);
|
||||
Cell *serverCell = CellController::get()->getCell(&esmCell);
|
||||
readActorList = serverCell->getActorList();
|
||||
}
|
||||
|
||||
void ActorFunctions::InitializeActorList(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
writeActorList.cell.blank();
|
||||
writeActorList.baseActors.clear();
|
||||
writeActorList.guid = player->guid;
|
||||
}
|
||||
|
||||
unsigned int ActorFunctions::GetActorListSize() noexcept
|
||||
{
|
||||
return readActorList->count;
|
||||
}
|
||||
|
||||
unsigned char ActorFunctions::GetActorListAction() noexcept
|
||||
{
|
||||
return readActorList->action;
|
||||
}
|
||||
|
||||
const char *ActorFunctions::GetActorCell(unsigned int i) noexcept
|
||||
{
|
||||
tempCellDescription = readActorList->baseActors.at(i).cell.getDescription();
|
||||
return tempCellDescription.c_str();
|
||||
}
|
||||
|
||||
const char *ActorFunctions::GetActorRefId(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).refId.c_str();
|
||||
}
|
||||
|
||||
int ActorFunctions::GetActorRefNumIndex(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).refNumIndex;
|
||||
}
|
||||
|
||||
int ActorFunctions::GetActorMpNum(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).mpNum;
|
||||
}
|
||||
|
||||
double ActorFunctions::GetActorPosX(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).position.pos[0];
|
||||
}
|
||||
|
||||
double ActorFunctions::GetActorPosY(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).position.pos[1];
|
||||
}
|
||||
|
||||
double ActorFunctions::GetActorPosZ(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).position.pos[2];
|
||||
}
|
||||
|
||||
double ActorFunctions::GetActorRotX(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).position.rot[0];
|
||||
}
|
||||
|
||||
double ActorFunctions::GetActorRotY(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).position.rot[1];
|
||||
}
|
||||
|
||||
double ActorFunctions::GetActorRotZ(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).position.rot[2];
|
||||
}
|
||||
|
||||
double ActorFunctions::GetActorHealthBase(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).creatureStats.mDynamic[0].mBase;
|
||||
}
|
||||
|
||||
double ActorFunctions::GetActorHealthCurrent(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).creatureStats.mDynamic[0].mCurrent;
|
||||
}
|
||||
|
||||
double ActorFunctions::GetActorHealthModified(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).creatureStats.mDynamic[0].mMod;
|
||||
}
|
||||
|
||||
double ActorFunctions::GetActorMagickaBase(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).creatureStats.mDynamic[1].mBase;
|
||||
}
|
||||
|
||||
double ActorFunctions::GetActorMagickaCurrent(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).creatureStats.mDynamic[1].mCurrent;
|
||||
}
|
||||
|
||||
double ActorFunctions::GetActorMagickaModified(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).creatureStats.mDynamic[1].mMod;
|
||||
}
|
||||
|
||||
double ActorFunctions::GetActorFatigueBase(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).creatureStats.mDynamic[2].mBase;
|
||||
}
|
||||
|
||||
double ActorFunctions::GetActorFatigueCurrent(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).creatureStats.mDynamic[2].mCurrent;
|
||||
}
|
||||
|
||||
double ActorFunctions::GetActorFatigueModified(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).creatureStats.mDynamic[2].mMod;
|
||||
}
|
||||
|
||||
const char *ActorFunctions::GetActorEquipmentItemRefId(unsigned int i, unsigned short slot) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).equipedItems[slot].refId.c_str();
|
||||
}
|
||||
|
||||
int ActorFunctions::GetActorEquipmentItemCount(unsigned int i, unsigned short slot) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).equipedItems[slot].count;
|
||||
}
|
||||
|
||||
int ActorFunctions::GetActorEquipmentItemCharge(unsigned int i, unsigned short slot) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).equipedItems[slot].charge;
|
||||
}
|
||||
|
||||
bool ActorFunctions::DoesActorHavePosition(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).hasPositionData;
|
||||
}
|
||||
|
||||
bool ActorFunctions::DoesActorHaveStatsDynamic(unsigned int i) noexcept
|
||||
{
|
||||
return readActorList->baseActors.at(i).hasStatsDynamicData;
|
||||
}
|
||||
|
||||
void ActorFunctions::SetActorListCell(const char* cellDescription) noexcept
|
||||
{
|
||||
writeActorList.cell = Utils::getCellFromDescription(cellDescription);
|
||||
}
|
||||
|
||||
void ActorFunctions::SetActorListAction(unsigned char action) noexcept
|
||||
{
|
||||
writeActorList.action = action;
|
||||
}
|
||||
|
||||
void ActorFunctions::SetActorCell(const char* cellDescription) noexcept
|
||||
{
|
||||
tempActor.cell = Utils::getCellFromDescription(cellDescription);
|
||||
}
|
||||
|
||||
void ActorFunctions::SetActorRefId(const char* refId) noexcept
|
||||
{
|
||||
tempActor.refId = refId;
|
||||
}
|
||||
|
||||
void ActorFunctions::SetActorRefNumIndex(int refNumIndex) noexcept
|
||||
{
|
||||
tempActor.refNumIndex = refNumIndex;
|
||||
}
|
||||
|
||||
void ActorFunctions::SetActorMpNum(int mpNum) noexcept
|
||||
{
|
||||
tempActor.mpNum = mpNum;
|
||||
}
|
||||
|
||||
void ActorFunctions::SetActorPosition(double x, double y, double z) noexcept
|
||||
{
|
||||
tempActor.position.pos[0] = x;
|
||||
tempActor.position.pos[1] = y;
|
||||
tempActor.position.pos[2] = z;
|
||||
}
|
||||
|
||||
void ActorFunctions::SetActorRotation(double x, double y, double z) noexcept
|
||||
{
|
||||
tempActor.position.rot[0] = x;
|
||||
tempActor.position.rot[1] = y;
|
||||
tempActor.position.rot[2] = z;
|
||||
}
|
||||
|
||||
void ActorFunctions::SetActorHealthBase(double value) noexcept
|
||||
{
|
||||
tempActor.creatureStats.mDynamic[0].mBase = value;
|
||||
}
|
||||
|
||||
void ActorFunctions::SetActorHealthCurrent(double value) noexcept
|
||||
{
|
||||
tempActor.creatureStats.mDynamic[0].mCurrent = value;
|
||||
}
|
||||
|
||||
void ActorFunctions::SetActorHealthModified(double value) noexcept
|
||||
{
|
||||
tempActor.creatureStats.mDynamic[0].mMod = value;
|
||||
}
|
||||
|
||||
void ActorFunctions::SetActorMagickaBase(double value) noexcept
|
||||
{
|
||||
tempActor.creatureStats.mDynamic[1].mBase = value;
|
||||
}
|
||||
|
||||
void ActorFunctions::SetActorMagickaCurrent(double value) noexcept
|
||||
{
|
||||
tempActor.creatureStats.mDynamic[1].mCurrent = value;
|
||||
}
|
||||
|
||||
void ActorFunctions::SetActorMagickaModified(double value) noexcept
|
||||
{
|
||||
tempActor.creatureStats.mDynamic[1].mMod = value;
|
||||
}
|
||||
|
||||
void ActorFunctions::SetActorFatigueBase(double value) noexcept
|
||||
{
|
||||
tempActor.creatureStats.mDynamic[2].mBase = value;
|
||||
}
|
||||
|
||||
void ActorFunctions::SetActorFatigueCurrent(double value) noexcept
|
||||
{
|
||||
tempActor.creatureStats.mDynamic[2].mCurrent = value;
|
||||
}
|
||||
|
||||
void ActorFunctions::SetActorFatigueModified(double value) noexcept
|
||||
{
|
||||
tempActor.creatureStats.mDynamic[2].mMod = value;
|
||||
}
|
||||
|
||||
void ActorFunctions::EquipActorItem(unsigned short slot, const char *refId, unsigned int count, int charge) noexcept
|
||||
{
|
||||
tempActor.equipedItems[slot].refId = refId;
|
||||
tempActor.equipedItems[slot].count = count;
|
||||
tempActor.equipedItems[slot].charge = charge;
|
||||
}
|
||||
|
||||
void ActorFunctions::UnequipActorItem(unsigned short slot) noexcept
|
||||
{
|
||||
ActorFunctions::EquipActorItem(slot, "", 0, -1);
|
||||
}
|
||||
|
||||
void ActorFunctions::AddActor() noexcept
|
||||
{
|
||||
writeActorList.baseActors.push_back(tempActor);
|
||||
|
||||
tempActor = emptyActor;
|
||||
}
|
||||
|
||||
void ActorFunctions::SendActorList() noexcept
|
||||
{
|
||||
mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_LIST)->setActorList(&writeActorList);
|
||||
mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_LIST)->Send(writeActorList.guid);
|
||||
}
|
||||
|
||||
void ActorFunctions::SendActorAuthority() noexcept
|
||||
{
|
||||
Cell *serverCell = CellController::get()->getCell(&writeActorList.cell);
|
||||
|
||||
if (serverCell != nullptr)
|
||||
{
|
||||
serverCell->setAuthority(writeActorList.guid);
|
||||
|
||||
mwmp::ActorPacket *authorityPacket = mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_AUTHORITY);
|
||||
authorityPacket->setActorList(&writeActorList);
|
||||
authorityPacket->Send(writeActorList.guid);
|
||||
|
||||
// Also send this to everyone else who has the cell loaded
|
||||
serverCell->sendToLoaded(authorityPacket, &writeActorList);
|
||||
}
|
||||
}
|
||||
|
||||
void ActorFunctions::SendActorPosition() noexcept
|
||||
{
|
||||
mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_POSITION)->setActorList(&writeActorList);
|
||||
mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_POSITION)->Send(writeActorList.guid);
|
||||
}
|
||||
|
||||
void ActorFunctions::SendActorStatsDynamic() noexcept
|
||||
{
|
||||
mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_STATS_DYNAMIC)->setActorList(&writeActorList);
|
||||
mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_STATS_DYNAMIC)->Send(writeActorList.guid);
|
||||
}
|
||||
|
||||
void ActorFunctions::SendActorEquipment() noexcept
|
||||
{
|
||||
mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_EQUIPMENT)->setActorList(&writeActorList);
|
||||
mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_EQUIPMENT)->Send(writeActorList.guid);
|
||||
}
|
||||
|
||||
void ActorFunctions::SendActorCellChange() noexcept
|
||||
{
|
||||
mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_CELL_CHANGE)->setActorList(&writeActorList);
|
||||
mwmp::Networking::get().getActorPacketController()->GetPacket(ID_ACTOR_CELL_CHANGE)->Send(writeActorList.guid);
|
||||
}
|
||||
|
|
@ -1,563 +0,0 @@
|
|||
#ifndef OPENMW_ACTORAPI_HPP
|
||||
#define OPENMW_ACTORAPI_HPP
|
||||
|
||||
#define ACTORAPI \
|
||||
{"ReadLastActorList", ActorFunctions::ReadLastActorList},\
|
||||
{"ReadCellActorList", ActorFunctions::ReadCellActorList},\
|
||||
{"InitializeActorList", ActorFunctions::InitializeActorList},\
|
||||
\
|
||||
{"GetActorListSize", ActorFunctions::GetActorListSize},\
|
||||
{"GetActorListAction", ActorFunctions::GetActorListAction},\
|
||||
\
|
||||
{"GetActorCell", ActorFunctions::GetActorCell},\
|
||||
{"GetActorRefId", ActorFunctions::GetActorRefId},\
|
||||
{"GetActorRefNumIndex", ActorFunctions::GetActorRefNumIndex},\
|
||||
{"GetActorMpNum", ActorFunctions::GetActorMpNum},\
|
||||
\
|
||||
{"GetActorPosX", ActorFunctions::GetActorPosX},\
|
||||
{"GetActorPosY", ActorFunctions::GetActorPosY},\
|
||||
{"GetActorPosZ", ActorFunctions::GetActorPosZ},\
|
||||
{"GetActorRotX", ActorFunctions::GetActorRotX},\
|
||||
{"GetActorRotY", ActorFunctions::GetActorRotY},\
|
||||
{"GetActorRotZ", ActorFunctions::GetActorRotZ},\
|
||||
\
|
||||
{"GetActorHealthBase", ActorFunctions::GetActorHealthBase},\
|
||||
{"GetActorHealthCurrent", ActorFunctions::GetActorHealthCurrent},\
|
||||
{"GetActorHealthModified", ActorFunctions::GetActorHealthModified},\
|
||||
{"GetActorMagickaBase", ActorFunctions::GetActorMagickaBase},\
|
||||
{"GetActorMagickaCurrent", ActorFunctions::GetActorMagickaCurrent},\
|
||||
{"GetActorMagickaModified", ActorFunctions::GetActorMagickaModified},\
|
||||
{"GetActorFatigueBase", ActorFunctions::GetActorFatigueBase},\
|
||||
{"GetActorFatigueCurrent", ActorFunctions::GetActorFatigueCurrent},\
|
||||
{"GetActorFatigueModified", ActorFunctions::GetActorFatigueModified},\
|
||||
\
|
||||
{"GetActorEquipmentItemRefId", ActorFunctions::GetActorEquipmentItemRefId},\
|
||||
{"GetActorEquipmentItemCount", ActorFunctions::GetActorEquipmentItemCount},\
|
||||
{"GetActorEquipmentItemCharge", ActorFunctions::GetActorEquipmentItemCharge},\
|
||||
\
|
||||
{"DoesActorHavePosition", ActorFunctions::DoesActorHavePosition},\
|
||||
{"DoesActorHaveStatsDynamic", ActorFunctions::DoesActorHaveStatsDynamic},\
|
||||
\
|
||||
{"SetActorListCell", ActorFunctions::SetActorListCell},\
|
||||
{"SetActorListAction", ActorFunctions::SetActorListAction},\
|
||||
\
|
||||
{"SetActorCell", ActorFunctions::SetActorCell},\
|
||||
{"SetActorRefId", ActorFunctions::SetActorRefId},\
|
||||
{"SetActorRefNumIndex", ActorFunctions::SetActorRefNumIndex},\
|
||||
{"SetActorMpNum", ActorFunctions::SetActorMpNum},\
|
||||
\
|
||||
{"SetActorPosition", ActorFunctions::SetActorPosition},\
|
||||
{"SetActorRotation", ActorFunctions::SetActorRotation},\
|
||||
\
|
||||
{"SetActorHealthBase", ActorFunctions::SetActorHealthBase},\
|
||||
{"SetActorHealthCurrent", ActorFunctions::SetActorHealthCurrent},\
|
||||
{"SetActorHealthModified", ActorFunctions::SetActorHealthModified},\
|
||||
{"SetActorMagickaBase", ActorFunctions::SetActorMagickaBase},\
|
||||
{"SetActorMagickaCurrent", ActorFunctions::SetActorMagickaCurrent},\
|
||||
{"SetActorMagickaModified", ActorFunctions::SetActorMagickaModified},\
|
||||
{"SetActorFatigueBase", ActorFunctions::SetActorFatigueBase},\
|
||||
{"SetActorFatigueCurrent", ActorFunctions::SetActorFatigueCurrent},\
|
||||
{"SetActorFatigueModified", ActorFunctions::SetActorFatigueModified},\
|
||||
\
|
||||
{"EquipActorItem", ActorFunctions::EquipActorItem},\
|
||||
{"UnequipActorItem", ActorFunctions::UnequipActorItem},\
|
||||
\
|
||||
{"AddActor", ActorFunctions::AddActor},\
|
||||
\
|
||||
{"SendActorList", ActorFunctions::SendActorList},\
|
||||
{"SendActorAuthority", ActorFunctions::SendActorAuthority},\
|
||||
{"SendActorPosition", ActorFunctions::SendActorPosition},\
|
||||
{"SendActorStatsDynamic", ActorFunctions::SendActorStatsDynamic},\
|
||||
{"SendActorEquipment", ActorFunctions::SendActorEquipment},\
|
||||
{"SendActorCellChange", ActorFunctions::SendActorCellChange}
|
||||
|
||||
class ActorFunctions
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Use the last actor list received by the server as the one being read.
|
||||
*
|
||||
* \return void
|
||||
*/
|
||||
static void ReadLastActorList() noexcept;
|
||||
|
||||
/**
|
||||
* \brief Use the temporary actor list stored for a cell as the one being read.
|
||||
*
|
||||
* This type of actor list is used to store actor positions and dynamic stats and is deleted
|
||||
* when the cell is unloaded.
|
||||
*
|
||||
* \param cellDescription The description of the cell whose actor list should be read.
|
||||
* \return void
|
||||
*/
|
||||
static void ReadCellActorList(const char* cellDescription) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Clear the data from the last actor list sent by the server.
|
||||
*
|
||||
* This is used to initialize the sending of new Actor packets.
|
||||
*
|
||||
* \param pid The player ID to whom the actor list should be attached.
|
||||
* \return void
|
||||
*/
|
||||
static void InitializeActorList(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the number of indexes in the read actor list.
|
||||
*
|
||||
* \return The number of indexes.
|
||||
*/
|
||||
static unsigned int GetActorListSize() noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the action type used in the read actor list.
|
||||
*
|
||||
* \return The action type (0 for SET, 1 for ADD, 2 for REMOVE, 3 for REQUEST).
|
||||
*/
|
||||
static unsigned char GetActorListAction() noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the cell description of the actor at a certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return The cell description.
|
||||
*/
|
||||
static const char *GetActorCell(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the refId of the actor at a certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return The refId.
|
||||
*/
|
||||
static const char *GetActorRefId(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the refNumIndex of the actor at a certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return The refNumIndex.
|
||||
*/
|
||||
static int GetActorRefNumIndex(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the mpNum of the actor at a certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return The mpNum.
|
||||
*/
|
||||
static int GetActorMpNum(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the X position of the actor at a certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return The X position.
|
||||
*/
|
||||
static double GetActorPosX(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the Y position of the actor at a certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return The Y position.
|
||||
*/
|
||||
static double GetActorPosY(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the Z position of the actor at a certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return The Z position.
|
||||
*/
|
||||
static double GetActorPosZ(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the X rotation of the actor at a certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return The X rotation.
|
||||
*/
|
||||
static double GetActorRotX(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the Y rotation of the actor at a certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return The Y rotation.
|
||||
*/
|
||||
static double GetActorRotY(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the Z rotation of the actor at a certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return The Z rotation.
|
||||
*/
|
||||
static double GetActorRotZ(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the base health of the actor at a certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return The base health.
|
||||
*/
|
||||
static double GetActorHealthBase(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the current health of the actor at a certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return The current health.
|
||||
*/
|
||||
static double GetActorHealthCurrent(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the modified health of the actor at a certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return The modified health.
|
||||
*/
|
||||
static double GetActorHealthModified(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the base magicka of the actor at a certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return The base magicka.
|
||||
*/
|
||||
static double GetActorMagickaBase(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the current magicka of the actor at a certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return The current magicka.
|
||||
*/
|
||||
static double GetActorMagickaCurrent(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the modified magicka of the actor at a certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return The modified magicka.
|
||||
*/
|
||||
static double GetActorMagickaModified(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the base fatigue of the actor at a certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return The base fatigue.
|
||||
*/
|
||||
static double GetActorFatigueBase(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the current fatigue of the actor at a certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return The current fatigue.
|
||||
*/
|
||||
static double GetActorFatigueCurrent(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the modified fatigue of the actor at a certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return The modified fatigue.
|
||||
*/
|
||||
static double GetActorFatigueModified(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the refId of the item in a certain slot of the equipment of the actor at a
|
||||
* certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \param slot The slot of the equipment item.
|
||||
* \return The refId.
|
||||
*/
|
||||
static const char *GetActorEquipmentItemRefId(unsigned int i, unsigned short slot) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the count of the item in a certain slot of the equipment of the actor at a
|
||||
* certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \param slot The slot of the equipment item.
|
||||
* \return The item count.
|
||||
*/
|
||||
static int GetActorEquipmentItemCount(unsigned int i, unsigned short slot) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the charge of the item in a certain slot of the equipment of the actor at a
|
||||
* certain index in the read actor list.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \param slot The slot of the equipment item.
|
||||
* \return The charge.
|
||||
*/
|
||||
static int GetActorEquipmentItemCharge(unsigned int i, unsigned short slot) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Check whether there is any positional data for the actor at a certain index in
|
||||
* the read actor list.
|
||||
*
|
||||
* This is only useful when reading the actor list data recorded for a particular cell.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return Whether the read actor list contains positional data.
|
||||
*/
|
||||
static bool DoesActorHavePosition(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Check whether there is any dynamic stats data for the actor at a certain index in
|
||||
* the read actor list.
|
||||
*
|
||||
* This is only useful when reading the actor list data recorded for a particular cell.
|
||||
*
|
||||
* \param i The index of the actor.
|
||||
* \return Whether the read actor list contains dynamic stats data.
|
||||
*/
|
||||
static bool DoesActorHaveStatsDynamic(unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the cell of the temporary actor list stored on the server.
|
||||
*
|
||||
* The cell is determined to be an exterior cell if it fits the pattern of a number followed
|
||||
* by a comma followed by another number.
|
||||
*
|
||||
* \param cellDescription The description of the cell.
|
||||
* \return void
|
||||
*/
|
||||
static void SetActorListCell(const char* cellDescription) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the action type of the temporary actor list stored on the server.
|
||||
*
|
||||
* \param action The action type (0 for SET, 1 for ADD, 2 for REMOVE, 3 for REQUEST).
|
||||
* \return void
|
||||
*/
|
||||
static void SetActorListAction(unsigned char action) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the cell of the temporary actor stored on the server.
|
||||
*
|
||||
* Used for ActorCellChange packets, where a specific actor's cell now differs from that of the
|
||||
* actor list.
|
||||
*
|
||||
* The cell is determined to be an exterior cell if it fits the pattern of a number followed
|
||||
* by a comma followed by another number.
|
||||
*
|
||||
* \param cellDescription The description of the cell.
|
||||
* \return void
|
||||
*/
|
||||
static void SetActorCell(const char* cellDescription) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the refId of the temporary actor stored on the server.
|
||||
*
|
||||
* \param refId The refId.
|
||||
* \return void
|
||||
*/
|
||||
static void SetActorRefId(const char* refId) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the refNumIndex of the temporary actor stored on the server.
|
||||
*
|
||||
* \param refNumIndex The refNumIndex.
|
||||
* \return void
|
||||
*/
|
||||
static void SetActorRefNumIndex(int refNumIndex) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the mpNum of the temporary actor stored on the server.
|
||||
*
|
||||
* \param mpNum The mpNum.
|
||||
* \return void
|
||||
*/
|
||||
static void SetActorMpNum(int mpNum) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the position of the temporary actor stored on the server.
|
||||
*
|
||||
* \param x The X position.
|
||||
* \param y The Y position.
|
||||
* \param z The Z position.
|
||||
* \return void
|
||||
*/
|
||||
static void SetActorPosition(double x, double y, double z) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the rotation of the temporary actor stored on the server.
|
||||
*
|
||||
* \param x The X rotation.
|
||||
* \param y The Y rotation.
|
||||
* \param z The Z rotation.
|
||||
* \return void
|
||||
*/
|
||||
static void SetActorRotation(double x, double y, double z) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the base health of the temporary actor stored on the server.
|
||||
*
|
||||
* \param value The new value.
|
||||
* \return void
|
||||
*/
|
||||
static void SetActorHealthBase(double value) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the current health of the temporary actor stored on the server.
|
||||
*
|
||||
* \param value The new value.
|
||||
* \return void
|
||||
*/
|
||||
static void SetActorHealthCurrent(double value) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the modified health of the temporary actor stored on the server.
|
||||
*
|
||||
* \param value The new value.
|
||||
* \return void
|
||||
*/
|
||||
static void SetActorHealthModified(double value) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the base magicka of the temporary actor stored on the server.
|
||||
*
|
||||
* \param value The new value.
|
||||
* \return void
|
||||
*/
|
||||
static void SetActorMagickaBase(double value) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the current magicka of the temporary actor stored on the server.
|
||||
*
|
||||
* \param value The new value.
|
||||
* \return void
|
||||
*/
|
||||
static void SetActorMagickaCurrent(double value) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the modified magicka of the temporary actor stored on the server.
|
||||
*
|
||||
* \param value The new value.
|
||||
* \return void
|
||||
*/
|
||||
static void SetActorMagickaModified(double value) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the base fatigue of the temporary actor stored on the server.
|
||||
*
|
||||
* \param value The new value.
|
||||
* \return void
|
||||
*/
|
||||
static void SetActorFatigueBase(double value) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the current fatigue of the temporary actor stored on the server.
|
||||
*
|
||||
* \param value The new value.
|
||||
* \return void
|
||||
*/
|
||||
static void SetActorFatigueCurrent(double value) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the modified fatigue of the temporary actor stored on the server.
|
||||
*
|
||||
* \param value The new value.
|
||||
* \return void
|
||||
*/
|
||||
static void SetActorFatigueModified(double value) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Equip an item in a certain slot of the equipment of the temporary actor stored
|
||||
* on the server.
|
||||
*
|
||||
* \param slot The equipment slot.
|
||||
* \param refId The refId of the item.
|
||||
* \param count The count of the item.
|
||||
* \param charge The charge of the item.
|
||||
* \return void
|
||||
*/
|
||||
static void EquipActorItem(unsigned short slot, const char* refId, unsigned int count, int charge) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Unequip the item in a certain slot of the equipment of the temporary actor stored
|
||||
* on the server.
|
||||
*
|
||||
* \param slot The equipment slot.
|
||||
* \return void
|
||||
*/
|
||||
static void UnequipActorItem(unsigned short slot) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Add a copy of the server's temporary actor to the server's temporary actor list.
|
||||
*
|
||||
* In the process, the server's temporary actor will automatically be cleared so a new
|
||||
* one can be set up.
|
||||
*
|
||||
* \return void
|
||||
*/
|
||||
static void AddActor() noexcept;
|
||||
|
||||
/**
|
||||
* \brief Send an ActorList packet.
|
||||
*
|
||||
* It is sent only to the player for whom the current actor list was initialized.
|
||||
*
|
||||
* \return void
|
||||
*/
|
||||
static void SendActorList() noexcept;
|
||||
|
||||
/**
|
||||
* \brief Send an ActorAuthority packet.
|
||||
*
|
||||
* The player for whom the current actor list was initialized is recorded in the server memory
|
||||
* as the new actor authority for the actor list's cell.
|
||||
*
|
||||
* The packet is sent to that player as well as all other players who have the cell loaded.
|
||||
*
|
||||
* \return void
|
||||
*/
|
||||
static void SendActorAuthority() noexcept;
|
||||
|
||||
/**
|
||||
* \brief Send an ActorPosition packet.
|
||||
*
|
||||
* It is sent only to the player for whom the current actor list was initialized.
|
||||
*
|
||||
* \return void
|
||||
*/
|
||||
static void SendActorPosition() noexcept;
|
||||
|
||||
/**
|
||||
* \brief Send an ActorStatsDynamic packet.
|
||||
*
|
||||
* It is sent only to the player for whom the current actor list was initialized.
|
||||
*
|
||||
* \return void
|
||||
*/
|
||||
static void SendActorStatsDynamic() noexcept;
|
||||
|
||||
/**
|
||||
* \brief Send an ActorEquipment packet.
|
||||
*
|
||||
* It is sent only to the player for whom the current actor list was initialized.
|
||||
*
|
||||
* \return void
|
||||
*/
|
||||
static void SendActorEquipment() noexcept;
|
||||
|
||||
/**
|
||||
* \brief Send an ActorCellChange packet.
|
||||
*
|
||||
* It is sent only to the player for whom the current actor list was initialized.
|
||||
*
|
||||
* \return void
|
||||
*/
|
||||
static void SendActorCellChange() noexcept;
|
||||
};
|
||||
|
||||
|
||||
#endif //OPENMW_ACTORAPI_HPP
|
|
@ -1,55 +0,0 @@
|
|||
#include "Books.hpp"
|
||||
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
|
||||
#include <apps/openmw-mp/Networking.hpp>
|
||||
|
||||
using namespace mwmp;
|
||||
|
||||
void BookFunctions::InitializeBookChanges(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
return player->bookChanges.books.clear();
|
||||
}
|
||||
|
||||
unsigned int BookFunctions::GetBookChangesSize(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
|
||||
return player->bookChanges.count;
|
||||
}
|
||||
|
||||
void BookFunctions::AddBook(unsigned short pid, const char* bookId) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
mwmp::Book book;
|
||||
book.bookId = bookId;
|
||||
|
||||
player->bookChanges.books.push_back(book);
|
||||
}
|
||||
|
||||
const char *BookFunctions::GetBookId(unsigned short pid, unsigned int i) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, "");
|
||||
|
||||
if (i >= player->bookChanges.count)
|
||||
return "invalid";
|
||||
|
||||
return player->bookChanges.books.at(i).bookId.c_str();
|
||||
}
|
||||
|
||||
void BookFunctions::SendBookChanges(unsigned short pid, bool toOthers) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_BOOK)->setPlayer(player);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_BOOK)->Send(toOthers);
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
#ifndef OPENMW_BOOKAPI_HPP
|
||||
#define OPENMW_BOOKAPI_HPP
|
||||
|
||||
#define BOOKAPI \
|
||||
{"InitializeBookChanges", BookFunctions::InitializeBookChanges},\
|
||||
\
|
||||
{"GetBookChangesSize", BookFunctions::GetBookChangesSize},\
|
||||
\
|
||||
{"AddBook", BookFunctions::AddBook},\
|
||||
\
|
||||
{"GetBookId", BookFunctions::GetBookId},\
|
||||
\
|
||||
{"SendBookChanges", BookFunctions::SendBookChanges}
|
||||
|
||||
class BookFunctions
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Clear the last recorded book changes for a player.
|
||||
*
|
||||
* This is used to initialize the sending of new PlayerBook packets.
|
||||
*
|
||||
* \param pid The player ID whose book changes should be used.
|
||||
* \return void
|
||||
*/
|
||||
static void InitializeBookChanges(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the number of indexes in a player's latest book changes.
|
||||
*
|
||||
* \param pid The player ID whose book changes should be used.
|
||||
* \return The number of indexes.
|
||||
*/
|
||||
static unsigned int GetBookChangesSize(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Add a new book to the book changes for a player.
|
||||
*
|
||||
* \param pid The player ID whose book changes should be used.
|
||||
* \param bookId The bookId of the book.
|
||||
* \return void
|
||||
*/
|
||||
static void AddBook(unsigned short pid, const char* bookId) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the bookId at a certain index in a player's latest book changes.
|
||||
*
|
||||
* \param pid The player ID whose book changes should be used.
|
||||
* \param i The index of the book.
|
||||
* \return The bookId.
|
||||
*/
|
||||
static const char *GetBookId(unsigned short pid, unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Send a PlayerBook packet with a player's recorded book changes.
|
||||
*
|
||||
* \param pid The player ID whose book changes should be used.
|
||||
* \param toOthers Whether this packet should be sent only to other players or
|
||||
* only to the player it is about.
|
||||
* \return void
|
||||
*/
|
||||
static void SendBookChanges(unsigned short pid, bool toOthers = false) noexcept;
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif //OPENMW_BOOKAPI_HPP
|
|
@ -1,151 +0,0 @@
|
|||
#include "Cells.hpp"
|
||||
|
||||
#include <components/openmw-mp/Log.hpp>
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
|
||||
#include <apps/openmw-mp/Player.hpp>
|
||||
#include <apps/openmw-mp/Networking.hpp>
|
||||
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
static std::string tempCellDescription;
|
||||
|
||||
void CellFunctions::InitializeMapChanges(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
player->mapChanges.cellsExplored.clear();
|
||||
}
|
||||
|
||||
unsigned int CellFunctions::GetCellStateChangesSize(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
|
||||
return player->cellStateChanges.count;
|
||||
}
|
||||
|
||||
unsigned int CellFunctions::GetCellStateType(unsigned short pid, unsigned int i) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
|
||||
return player->cellStateChanges.cellStates.at(i).type;
|
||||
}
|
||||
|
||||
const char *CellFunctions::GetCellStateDescription(unsigned short pid, unsigned int i) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, "");
|
||||
|
||||
if (i >= player->cellStateChanges.count)
|
||||
return "invalid";
|
||||
|
||||
tempCellDescription = player->cellStateChanges.cellStates.at(i).cell.getDescription();
|
||||
return tempCellDescription.c_str();
|
||||
}
|
||||
|
||||
const char *CellFunctions::GetCell(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
|
||||
tempCellDescription = player->cell.getDescription().c_str();
|
||||
return tempCellDescription.c_str();
|
||||
}
|
||||
|
||||
int CellFunctions::GetExteriorX(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
return player->cell.mData.mX;
|
||||
}
|
||||
|
||||
int CellFunctions::GetExteriorY(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
return player->cell.mData.mY;
|
||||
}
|
||||
|
||||
bool CellFunctions::IsInExterior(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, false);
|
||||
|
||||
return player->cell.isExterior();
|
||||
}
|
||||
|
||||
const char *CellFunctions::GetRegion(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
|
||||
return player->cell.mRegion.c_str();
|
||||
}
|
||||
|
||||
bool CellFunctions::IsChangingRegion(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, false);
|
||||
|
||||
return player->isChangingRegion;
|
||||
}
|
||||
|
||||
void CellFunctions::SetCell(unsigned short pid, const char *cellDescription) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Script is moving %s from %s to %s", player->npc.mName.c_str(),
|
||||
player->cell.getDescription().c_str(), cellDescription);
|
||||
|
||||
player->cell = Utils::getCellFromDescription(cellDescription);
|
||||
}
|
||||
|
||||
void CellFunctions::SetExteriorCell(unsigned short pid, int x, int y) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Script is moving %s from %s to %i,%i", player->npc.mName.c_str(),
|
||||
player->cell.getDescription().c_str(), x, y);
|
||||
|
||||
// If the player is currently in an interior, turn off the interior flag
|
||||
// from the cell
|
||||
if (!player->cell.isExterior())
|
||||
player->cell.mData.mFlags &= ~ESM::Cell::Interior;
|
||||
|
||||
player->cell.mData.mX = x;
|
||||
player->cell.mData.mY = y;
|
||||
}
|
||||
|
||||
void CellFunctions::AddCellExplored(unsigned short pid, const char* cellDescription) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
ESM::Cell cellExplored = Utils::getCellFromDescription(cellDescription);
|
||||
player->mapChanges.cellsExplored.push_back(cellExplored);
|
||||
}
|
||||
|
||||
void CellFunctions::SendCell(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_CELL_CHANGE)->setPlayer(player);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_CELL_CHANGE)->Send(false);
|
||||
}
|
||||
|
||||
void CellFunctions::SendMapChanges(unsigned short pid, bool toOthers) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_MAP)->setPlayer(player);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_MAP)->Send(toOthers);
|
||||
}
|
|
@ -1,179 +0,0 @@
|
|||
#ifndef OPENMW_CELLAPI_HPP
|
||||
#define OPENMW_CELLAPI_HPP
|
||||
|
||||
#include "../Types.hpp"
|
||||
|
||||
#define CELLAPI \
|
||||
{"InitializeMapChanges", CellFunctions::InitializeMapChanges},\
|
||||
\
|
||||
{"GetCellStateChangesSize", CellFunctions::GetCellStateChangesSize},\
|
||||
\
|
||||
{"GetCellStateType", CellFunctions::GetCellStateType},\
|
||||
{"GetCellStateDescription", CellFunctions::GetCellStateDescription},\
|
||||
\
|
||||
{"GetCell", CellFunctions::GetCell},\
|
||||
{"GetExteriorX", CellFunctions::GetExteriorX},\
|
||||
{"GetExteriorY", CellFunctions::GetExteriorY},\
|
||||
{"IsInExterior", CellFunctions::IsInExterior},\
|
||||
\
|
||||
{"GetRegion", CellFunctions::GetRegion},\
|
||||
{"IsChangingRegion", CellFunctions::IsChangingRegion},\
|
||||
\
|
||||
{"SetCell", CellFunctions::SetCell},\
|
||||
{"SetExteriorCell", CellFunctions::SetExteriorCell},\
|
||||
\
|
||||
{"AddCellExplored", CellFunctions::AddCellExplored},\
|
||||
\
|
||||
{"SendCell", CellFunctions::SendCell},\
|
||||
{"SendMapChanges", CellFunctions::SendMapChanges}
|
||||
|
||||
|
||||
class CellFunctions
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Clear the last recorded map changes for a player.
|
||||
*
|
||||
* This is used to initialize the sending of new PlayerMap packets.
|
||||
*
|
||||
* \param pid The player ID whose map changes should be used.
|
||||
* \return void
|
||||
*/
|
||||
static void InitializeMapChanges(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the number of indexes in a player's latest cell state changes.
|
||||
*
|
||||
* \param pid The player ID whose cell state changes should be used.
|
||||
* \return The number of indexes.
|
||||
*/
|
||||
static unsigned int GetCellStateChangesSize(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the cell state type at a certain index in a player's latest cell state changes.
|
||||
*
|
||||
* \param pid The player ID whose cell state changes should be used.
|
||||
* \param i The index of the cell state.
|
||||
* \return The cell state type (0 for LOAD, 1 for UNLOAD).
|
||||
*/
|
||||
static unsigned int GetCellStateType(unsigned short pid, unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the cell description at a certain index in a player's latest cell state changes.
|
||||
*
|
||||
* \param pid The player ID whose cell state changes should be used.
|
||||
* \param i The index of the cell state.
|
||||
* \return The cell description.
|
||||
*/
|
||||
static const char *GetCellStateDescription(unsigned short pid, unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the cell description of a player's cell.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \return The cell description.
|
||||
*/
|
||||
static const char *GetCell(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the X coordinate of the player's exterior cell.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \return The X coordinate of the cell.
|
||||
*/
|
||||
static int GetExteriorX(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the Y coordinate of the player's exterior cell.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \return The Y coordinate of the cell.
|
||||
*/
|
||||
static int GetExteriorY(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Check whether the player is in an exterior cell or not.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \return Whether the player is in an exterior cell.
|
||||
*/
|
||||
static bool IsInExterior(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the region of the player's exterior cell.
|
||||
*
|
||||
* A blank value will be returned if the player is in an interior.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \return The region.
|
||||
*/
|
||||
static const char *GetRegion(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Check whether the player's last cell change has involved a region change.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \return Whether the player has changed their region.
|
||||
*/
|
||||
static bool IsChangingRegion(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the cell of a player.
|
||||
*
|
||||
* This changes the cell recorded for that player in the server memory, but does not by itself
|
||||
* send a packet.
|
||||
*
|
||||
* The cell is determined to be an exterior cell if it fits the pattern of a number followed
|
||||
* by a comma followed by another number.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param cellDescription The cell description.
|
||||
* \return void
|
||||
*/
|
||||
static void SetCell(unsigned short pid, const char *cellDescription) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the cell of a player to an exterior cell.
|
||||
*
|
||||
* This changes the cell recorded for that player in the server memory, but does not by itself
|
||||
* send a packet.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param x The X coordinate of the cell.
|
||||
* \param y The Y coordinate of the cell.
|
||||
* \return void
|
||||
*/
|
||||
static void SetExteriorCell(unsigned short pid, int x, int y) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Add a new explored cell to the map changes for a player.
|
||||
*
|
||||
* \param pid The player ID whose map changes should be used.
|
||||
* \param cellDescription The cell description of the explored cell.
|
||||
* \return void
|
||||
*/
|
||||
static void AddCellExplored(unsigned short pid, const char* cellDescription) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Send a PlayerCellChange packet about a player.
|
||||
*
|
||||
* It is only sent to the affected player.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \return void
|
||||
*/
|
||||
static void SendCell(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Send a PlayerMap packet with a player's recorded map changes.
|
||||
*
|
||||
* \param pid The player ID whose map changes should be used.
|
||||
* \param toOthers Whether this packet should be sent only to other players or
|
||||
* only to the player it is about.
|
||||
* \return void
|
||||
*/
|
||||
static void SendMapChanges(unsigned short pid, bool toOthers = false) noexcept;
|
||||
};
|
||||
|
||||
#endif //OPENMW_CELLAPI_HPP
|
|
@ -1,137 +0,0 @@
|
|||
//
|
||||
// Created by koncord on 29.08.16.
|
||||
//
|
||||
|
||||
#include "CharClass.hpp"
|
||||
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
#include <apps/openmw-mp/Networking.hpp>
|
||||
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace ESM;
|
||||
|
||||
const char *CharClassFunctions::GetDefaultClass(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, "");
|
||||
return player->charClass.mId.c_str();
|
||||
}
|
||||
|
||||
const char *CharClassFunctions::GetClassName(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, "");
|
||||
return player->charClass.mName.c_str();
|
||||
}
|
||||
|
||||
const char *CharClassFunctions::GetClassDesc(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, "");
|
||||
return player->charClass.mDescription.c_str();
|
||||
}
|
||||
|
||||
int CharClassFunctions::GetClassMajorAttribute(unsigned short pid, unsigned char slot) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
if (slot > 1)
|
||||
throw invalid_argument("Incorrect attribute slot id");
|
||||
return player->charClass.mData.mAttribute[slot];
|
||||
}
|
||||
|
||||
int CharClassFunctions::GetClassSpecialization(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
return player->charClass.mData.mSpecialization;
|
||||
}
|
||||
|
||||
int CharClassFunctions::GetClassMajorSkill(unsigned short pid, unsigned char slot) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
if (slot > 4)
|
||||
throw invalid_argument("Incorrect skill slot id");
|
||||
return player->charClass.mData.mSkills[slot][1];
|
||||
}
|
||||
|
||||
int CharClassFunctions::GetClassMinorSkill(unsigned short pid, unsigned char slot) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
if (slot > 4)
|
||||
throw invalid_argument("Incorrect skill slot id");
|
||||
return player->charClass.mData.mSkills[slot][0];
|
||||
}
|
||||
|
||||
int CharClassFunctions::IsClassDefault(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
return !player->charClass.mId.empty(); // true if default
|
||||
}
|
||||
|
||||
void CharClassFunctions::SetDefaultClass(unsigned short pid, const char *id) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
player->charClass.mId = id;
|
||||
}
|
||||
void CharClassFunctions::SetClassName(unsigned short pid, const char *name) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
player->charClass.mName = name;
|
||||
player->charClass.mId = "";
|
||||
}
|
||||
void CharClassFunctions::SetClassDesc(unsigned short pid, const char *desc) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
player->charClass.mDescription = desc;
|
||||
}
|
||||
void CharClassFunctions::SetClassMajorAttribute(unsigned short pid, unsigned char slot, int attrId) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
|
||||
if (slot > 1)
|
||||
throw invalid_argument("Incorrect attribute slot id");
|
||||
|
||||
player->charClass.mData.mAttribute[slot] = attrId;
|
||||
|
||||
}
|
||||
void CharClassFunctions::SetClassSpecialization(unsigned short pid, int spec) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
player->charClass.mData.mSpecialization = spec;
|
||||
}
|
||||
void CharClassFunctions::SetClassMajorSkill(unsigned short pid, unsigned char slot, int skillId) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
if (slot > 4)
|
||||
throw invalid_argument("Incorrect skill slot id");
|
||||
player->charClass.mData.mSkills[slot][1] = skillId;
|
||||
}
|
||||
void CharClassFunctions::SetClassMinorSkill(unsigned short pid, unsigned char slot, int skillId) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
if (slot > 4)
|
||||
throw invalid_argument("Incorrect skill slot id");
|
||||
player->charClass.mData.mSkills[slot][0] = skillId;
|
||||
}
|
||||
|
||||
void CharClassFunctions::SendClass(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_CHARCLASS)->setPlayer(player);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_CHARCLASS)->Send(false);
|
||||
}
|
|
@ -1,181 +0,0 @@
|
|||
//
|
||||
// Created by koncord on 29.08.16.
|
||||
//
|
||||
|
||||
#ifndef OPENMW_CHARCLASSAPI_HPP
|
||||
#define OPENMW_CHARCLASSAPI_HPP
|
||||
|
||||
#include "../Types.hpp"
|
||||
|
||||
#define CHARCLASSAPI \
|
||||
{"GetDefaultClass", CharClassFunctions::GetDefaultClass},\
|
||||
{"GetClassName", CharClassFunctions::GetClassName},\
|
||||
{"GetClassDesc", CharClassFunctions::GetClassDesc},\
|
||||
{"GetClassMajorAttribute", CharClassFunctions::GetClassMajorAttribute},\
|
||||
{"GetClassSpecialization", CharClassFunctions::GetClassSpecialization},\
|
||||
{"GetClassMajorSkill", CharClassFunctions::GetClassMajorSkill},\
|
||||
{"GetClassMinorSkill", CharClassFunctions::GetClassMinorSkill},\
|
||||
{"IsClassDefault", CharClassFunctions::IsClassDefault},\
|
||||
\
|
||||
{"SetDefaultClass", CharClassFunctions::SetDefaultClass},\
|
||||
{"SetClassName", CharClassFunctions::SetClassName},\
|
||||
{"SetClassDesc", CharClassFunctions::SetClassDesc},\
|
||||
{"SetClassMajorAttribute", CharClassFunctions::SetClassMajorAttribute},\
|
||||
{"SetClassSpecialization", CharClassFunctions::SetClassSpecialization},\
|
||||
{"SetClassMajorSkill", CharClassFunctions::SetClassMajorSkill},\
|
||||
{"SetClassMinorSkill", CharClassFunctions::SetClassMinorSkill},\
|
||||
\
|
||||
{"SendClass", CharClassFunctions::SendClass}
|
||||
|
||||
|
||||
class CharClassFunctions
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Get the default class used by a player.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \return The ID of the default class.
|
||||
*/
|
||||
static const char *GetDefaultClass(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the name of the custom class used by a player.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \return The name of the custom class.
|
||||
*/
|
||||
static const char *GetClassName(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the description of the custom class used by a player.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \return The description of the custom class.
|
||||
*/
|
||||
static const char *GetClassDesc(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the ID of one of the two major attributes of a custom class used by a player.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param slot The slot of the major attribute (0 or 1).
|
||||
* \return The ID of the major attribute.
|
||||
*/
|
||||
static int GetClassMajorAttribute(unsigned short pid, unsigned char slot) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the specialization ID of the custom class used by a player.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \return The specialization ID of the custom class (0 for Combat, 1 for Magic, 2 for Stealth).
|
||||
*/
|
||||
static int GetClassSpecialization(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the ID of one of the five major skills of a custom class used by a player.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param slot The slot of the major skill (0 to 4).
|
||||
* \return The ID of the major skill.
|
||||
*/
|
||||
static int GetClassMajorSkill(unsigned short pid, unsigned char slot) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the ID of one of the five minor skills of a custom class used by a player.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param slot The slot of the minor skill (0 to 4).
|
||||
* \return The ID of the minor skill.
|
||||
*/
|
||||
static int GetClassMinorSkill(unsigned short pid, unsigned char slot) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Check whether the player is using a default class instead of a custom one.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \return Whether the player is using a default class.
|
||||
*/
|
||||
static int IsClassDefault(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the default class used by a player.
|
||||
*
|
||||
* If this is left blank, the custom class data set for the player will be used instead.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param id The ID of the default class.
|
||||
* \return void
|
||||
*/
|
||||
static void SetDefaultClass(unsigned short pid, const char *id) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the name of the custom class used by a player.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param name The name of the custom class.
|
||||
* \return void
|
||||
*/
|
||||
static void SetClassName(unsigned short pid, const char *name) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the description of the custom class used by a player.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param desc The description of the custom class.
|
||||
* \return void
|
||||
*/
|
||||
static void SetClassDesc(unsigned short pid, const char *desc) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the ID of one of the two major attributes of the custom class used by a player.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param slot The slot of the major attribute (0 or 1).
|
||||
* \param attrId The ID to use for the attribute.
|
||||
* \return void
|
||||
*/
|
||||
static void SetClassMajorAttribute(unsigned short pid, unsigned char slot, int attrId) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the specialization of the custom class used by a player.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param spec The specialization ID to use (0 for Combat, 1 for Magic, 2 for Stealth).
|
||||
* \return void
|
||||
*/
|
||||
static void SetClassSpecialization(unsigned short pid, int spec) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the ID of one of the five major skills of the custom class used by a player.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param slot The slot of the major skill (0 to 4).
|
||||
* \param skillId The ID to use for the skill.
|
||||
* \return void
|
||||
*/
|
||||
static void SetClassMajorSkill(unsigned short pid, unsigned char slot, int skillId) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the ID of one of the five minor skills of the custom class used by a player.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param slot The slot of the minor skill (0 to 4).
|
||||
* \param skillId The ID to use for the skill.
|
||||
* \return void
|
||||
*/
|
||||
static void SetClassMinorSkill(unsigned short pid, unsigned char slot, int skillId) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Send a PlayerCharClass packet about a player.
|
||||
*
|
||||
* It is only sent to the affected player.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \return void
|
||||
*/
|
||||
static void SendClass(unsigned short pid) noexcept;
|
||||
};
|
||||
|
||||
#endif //OPENMW_CHARCLASSAPI_HPP
|
|
@ -1,46 +0,0 @@
|
|||
//
|
||||
// Created by koncord on 29.04.16.
|
||||
//
|
||||
|
||||
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
|
||||
#include <apps/openmw-mp/Networking.hpp>
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
void ScriptFunctions::SendMessage(unsigned short pid, const char *message, bool broadcast) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
|
||||
player->chatMessage = message;
|
||||
|
||||
LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "System: %s", message);
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_CHAT_MESSAGE)->setPlayer(player);
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_CHAT_MESSAGE)->Send(false);
|
||||
if (broadcast)
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_CHAT_MESSAGE)->Send(true);
|
||||
}
|
||||
|
||||
void ScriptFunctions::CleanChatByPid(unsigned short pid)
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
|
||||
player->chatMessage.clear();
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_CHAT_MESSAGE)->setPlayer(player);
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_CHAT_MESSAGE)->Send(false);
|
||||
}
|
||||
|
||||
void ScriptFunctions::CleanChat()
|
||||
{
|
||||
for (auto player : *Players::getPlayers())
|
||||
{
|
||||
player.second->chatMessage.clear();
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_CHAT_MESSAGE)->setPlayer(player.second);
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_CHAT_MESSAGE)->Send(false);
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
#include "Dialogue.hpp"
|
||||
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
|
||||
#include <apps/openmw-mp/Networking.hpp>
|
||||
|
||||
using namespace mwmp;
|
||||
|
||||
void DialogueFunctions::InitializeTopicChanges(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
player->topicChanges.topics.clear();
|
||||
}
|
||||
|
||||
unsigned int DialogueFunctions::GetTopicChangesSize(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
|
||||
return player->topicChanges.count;
|
||||
}
|
||||
|
||||
void DialogueFunctions::AddTopic(unsigned short pid, const char* topicId) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
mwmp::Topic topic;
|
||||
topic.topicId = topicId;
|
||||
|
||||
player->topicChanges.topics.push_back(topic);
|
||||
}
|
||||
|
||||
const char *DialogueFunctions::GetTopicId(unsigned short pid, unsigned int i) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, "");
|
||||
|
||||
if (i >= player->topicChanges.count)
|
||||
return "invalid";
|
||||
|
||||
return player->topicChanges.topics.at(i).topicId.c_str();
|
||||
}
|
||||
|
||||
void DialogueFunctions::SendTopicChanges(unsigned short pid, bool toOthers) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_TOPIC)->setPlayer(player);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_TOPIC)->Send(toOthers);
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
#ifndef OPENMW_DIALOGUEAPI_HPP
|
||||
#define OPENMW_DIALOGUEAPI_HPP
|
||||
|
||||
#define DIALOGUEAPI \
|
||||
{"InitializeTopicChanges", DialogueFunctions::InitializeTopicChanges},\
|
||||
\
|
||||
{"GetTopicChangesSize", DialogueFunctions::GetTopicChangesSize},\
|
||||
\
|
||||
{"AddTopic", DialogueFunctions::AddTopic},\
|
||||
\
|
||||
{"GetTopicId", DialogueFunctions::GetTopicId},\
|
||||
\
|
||||
{"SendTopicChanges", DialogueFunctions::SendTopicChanges}
|
||||
|
||||
class DialogueFunctions
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Clear the last recorded topic changes for a player.
|
||||
*
|
||||
* This is used to initialize the sending of new PlayerTopic packets.
|
||||
*
|
||||
* \param pid The player ID whose topic changes should be used.
|
||||
* \return void
|
||||
*/
|
||||
static void InitializeTopicChanges(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the number of indexes in a player's latest topic changes.
|
||||
*
|
||||
* \param pid The player ID whose topic changes should be used.
|
||||
* \return The number of indexes.
|
||||
*/
|
||||
static unsigned int GetTopicChangesSize(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Add a new topic to the topic changes for a player.
|
||||
*
|
||||
* \param pid The player ID whose topic changes should be used.
|
||||
* \param topicId The topicId of the topic.
|
||||
* \return void
|
||||
*/
|
||||
static void AddTopic(unsigned short pid, const char* topicId) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the topicId at a certain index in a player's latest topic changes.
|
||||
*
|
||||
* \param pid The player ID whose topic changes should be used.
|
||||
* \param i The index of the topic.
|
||||
* \return The topicId.
|
||||
*/
|
||||
static const char *GetTopicId(unsigned short pid, unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Send a PlayerTopic packet with a player's recorded topic changes.
|
||||
*
|
||||
* \param pid The player ID whose topic changes should be used.
|
||||
* \param toOthers Whether this packet should be sent only to other players or
|
||||
* only to the player it is about.
|
||||
* \return void
|
||||
*/
|
||||
static void SendTopicChanges(unsigned short pid, bool toOthers = false) noexcept;
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif //OPENMW_DIALOGUEAPI_HPP
|
|
@ -1,118 +0,0 @@
|
|||
#include "Factions.hpp"
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
|
||||
#include <apps/openmw-mp/Networking.hpp>
|
||||
|
||||
using namespace mwmp;
|
||||
|
||||
Faction tempFaction;
|
||||
const Faction emptyFaction = {};
|
||||
|
||||
void FactionFunctions::InitializeFactionChanges(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
player->factionChanges.factions.clear();
|
||||
}
|
||||
|
||||
unsigned int FactionFunctions::GetFactionChangesSize(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
|
||||
return player->factionChanges.count;
|
||||
}
|
||||
|
||||
unsigned char FactionFunctions::GetFactionChangesAction(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
|
||||
return player->factionChanges.action;
|
||||
}
|
||||
|
||||
const char *FactionFunctions::GetFactionId(unsigned short pid, unsigned int i) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, "");
|
||||
|
||||
if (i >= player->factionChanges.count)
|
||||
return "invalid";
|
||||
|
||||
return player->factionChanges.factions.at(i).factionId.c_str();
|
||||
}
|
||||
|
||||
int FactionFunctions::GetFactionRank(unsigned short pid, unsigned int i) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
|
||||
return player->factionChanges.factions.at(i).rank;
|
||||
}
|
||||
|
||||
bool FactionFunctions::GetFactionExpulsionState(unsigned short pid, unsigned int i) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, false);
|
||||
|
||||
return player->factionChanges.factions.at(i).isExpelled;
|
||||
}
|
||||
|
||||
int FactionFunctions::GetFactionReputation(unsigned short pid, unsigned int i) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
|
||||
return player->factionChanges.factions.at(i).reputation;
|
||||
}
|
||||
|
||||
void FactionFunctions::SetFactionChangesAction(unsigned short pid, unsigned char action) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
player->factionChanges.action = action;
|
||||
}
|
||||
|
||||
void FactionFunctions::SetFactionId(const char* factionId) noexcept
|
||||
{
|
||||
tempFaction.factionId = factionId;
|
||||
}
|
||||
|
||||
void FactionFunctions::SetFactionRank(unsigned int rank) noexcept
|
||||
{
|
||||
tempFaction.rank = rank;
|
||||
}
|
||||
|
||||
void FactionFunctions::SetFactionExpulsionState(bool expulsionState) noexcept
|
||||
{
|
||||
tempFaction.isExpelled = expulsionState;
|
||||
}
|
||||
|
||||
void FactionFunctions::SetFactionReputation(int reputation) noexcept
|
||||
{
|
||||
tempFaction.reputation = reputation;
|
||||
}
|
||||
|
||||
void FactionFunctions::AddFaction(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
player->factionChanges.factions.push_back(tempFaction);
|
||||
|
||||
tempFaction = emptyFaction;
|
||||
}
|
||||
|
||||
void FactionFunctions::SendFactionChanges(unsigned short pid, bool toOthers) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_FACTION)->setPlayer(player);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_FACTION)->Send(toOthers);
|
||||
}
|
|
@ -1,156 +0,0 @@
|
|||
#ifndef OPENMW_FACTIONAPI_HPP
|
||||
#define OPENMW_FACTIONAPI_HPP
|
||||
|
||||
#define FACTIONAPI \
|
||||
{"InitializeFactionChanges", FactionFunctions::InitializeFactionChanges},\
|
||||
\
|
||||
{"GetFactionChangesSize", FactionFunctions::GetFactionChangesSize},\
|
||||
{"GetFactionChangesAction", FactionFunctions::GetFactionChangesAction},\
|
||||
\
|
||||
{"GetFactionId", FactionFunctions::GetFactionId},\
|
||||
{"GetFactionRank", FactionFunctions::GetFactionRank},\
|
||||
{"GetFactionExpulsionState", FactionFunctions::GetFactionExpulsionState},\
|
||||
{"GetFactionReputation", FactionFunctions::GetFactionReputation},\
|
||||
\
|
||||
{"SetFactionChangesAction", FactionFunctions::SetFactionChangesAction},\
|
||||
{"SetFactionId", FactionFunctions::SetFactionId},\
|
||||
{"SetFactionRank", FactionFunctions::SetFactionRank},\
|
||||
{"SetFactionExpulsionState", FactionFunctions::SetFactionExpulsionState},\
|
||||
{"SetFactionReputation", FactionFunctions::SetFactionReputation},\
|
||||
\
|
||||
{"AddFaction", FactionFunctions::AddFaction},\
|
||||
\
|
||||
{"SendFactionChanges", FactionFunctions::SendFactionChanges}
|
||||
|
||||
class FactionFunctions
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Clear the last recorded faction changes for a player.
|
||||
*
|
||||
* This is used to initialize the sending of new PlayerFaction packets.
|
||||
*
|
||||
* \param pid The player ID whose faction changes should be used.
|
||||
* \return void
|
||||
*/
|
||||
static void InitializeFactionChanges(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the number of indexes in a player's latest faction changes.
|
||||
*
|
||||
* \param pid The player ID whose faction changes should be used.
|
||||
* \return The number of indexes.
|
||||
*/
|
||||
static unsigned int GetFactionChangesSize(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the action type used in a player's latest faction changes.
|
||||
*
|
||||
* \param pid The player ID whose faction changes should be used.
|
||||
* \return The action type (0 for RANK, 1 for EXPULSION, 2 for REPUTATION).
|
||||
*/
|
||||
static unsigned char GetFactionChangesAction(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the factionId at a certain index in a player's latest faction changes.
|
||||
*
|
||||
* \param pid The player ID whose faction changes should be used.
|
||||
* \param i The index of the faction.
|
||||
* \return The factionId.
|
||||
*/
|
||||
static const char *GetFactionId(unsigned short pid, unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the rank at a certain index in a player's latest faction changes.
|
||||
*
|
||||
* \param pid The player ID whose faction changes should be used.
|
||||
* \param i The index of the faction.
|
||||
* \return The rank.
|
||||
*/
|
||||
static int GetFactionRank(unsigned short pid, unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the expulsion state at a certain index in a player's latest faction changes.
|
||||
*
|
||||
* \param pid The player ID whose faction changes should be used.
|
||||
* \param i The index of the faction.
|
||||
* \return The expulsion state.
|
||||
*/
|
||||
static bool GetFactionExpulsionState(unsigned short pid, unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the reputation at a certain index in a player's latest faction changes.
|
||||
*
|
||||
* \param pid The player ID whose faction changes should be used.
|
||||
* \param i The index of the faction.
|
||||
* \return The reputation.
|
||||
*/
|
||||
static int GetFactionReputation(unsigned short pid, unsigned int i) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the action type in a player's faction changes.
|
||||
*
|
||||
* \param pid The player ID whose faction changes should be used.
|
||||
* \param action The action (0 for RANK, 1 for EXPULSION, 2 for REPUTATION).
|
||||
* \return void
|
||||
*/
|
||||
static void SetFactionChangesAction(unsigned short pid, unsigned char action) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the factionId of the temporary faction stored on the server.
|
||||
*
|
||||
* \param factionId The factionId.
|
||||
* \return void
|
||||
*/
|
||||
static void SetFactionId(const char* factionId) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the rank of the temporary faction stored on the server.
|
||||
*
|
||||
* \param rank The rank.
|
||||
* \return void
|
||||
*/
|
||||
static void SetFactionRank(unsigned int rank) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the expulsion state of the temporary faction stored on the server.
|
||||
*
|
||||
* \param expulsionState The expulsion state.
|
||||
* \return void
|
||||
*/
|
||||
static void SetFactionExpulsionState(bool expulsionState) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the reputation of the temporary faction stored on the server.
|
||||
*
|
||||
* \param reputation The reputation.
|
||||
* \return void
|
||||
*/
|
||||
static void SetFactionReputation(int reputation) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Add the server's temporary faction to the faction changes for a player.
|
||||
*
|
||||
* In the process, the server's temporary faction will automatically be cleared so a new one
|
||||
* can be set up.
|
||||
*
|
||||
* \param pid The player ID whose faction changes should be used.
|
||||
* \return void
|
||||
*/
|
||||
static void AddFaction(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Send a PlayerFaction packet with a player's recorded faction changes.
|
||||
*
|
||||
* \param pid The player ID whose faction changes should be used.
|
||||
* \param toOthers Whether this packet should be sent only to other players or
|
||||
* only to the player it is about.
|
||||
* \return void
|
||||
*/
|
||||
static void SendFactionChanges(unsigned short pid, bool toOthers = false) noexcept;
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif //OPENMW_FACTIONAPI_HPP
|
|
@ -1,88 +0,0 @@
|
|||
//
|
||||
// Created by koncord on 23.07.16.
|
||||
//
|
||||
|
||||
#include "GUI.hpp"
|
||||
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
|
||||
#include <apps/openmw-mp/Networking.hpp>
|
||||
|
||||
void GUIFunctions::_MessageBox(unsigned short pid, int id, const char *label) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
|
||||
player->guiMessageBox.id = id;
|
||||
player->guiMessageBox.label = label;
|
||||
player->guiMessageBox.type = Player::GUIMessageBox::MessageBox;
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_GUI_MESSAGEBOX)->setPlayer(player);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_GUI_MESSAGEBOX)->Send(false);
|
||||
}
|
||||
|
||||
void GUIFunctions::CustomMessageBox(unsigned short pid, int id, const char *label, const char *buttons) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
|
||||
player->guiMessageBox.id = id;
|
||||
player->guiMessageBox.label = label;
|
||||
player->guiMessageBox.buttons = buttons;
|
||||
player->guiMessageBox.type = Player::GUIMessageBox::CustomMessageBox;
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_GUI_MESSAGEBOX)->setPlayer(player);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_GUI_MESSAGEBOX)->Send(false);
|
||||
}
|
||||
|
||||
void GUIFunctions::InputDialog(unsigned short pid, int id, const char *label) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
|
||||
player->guiMessageBox.id = id;
|
||||
player->guiMessageBox.label = label;
|
||||
player->guiMessageBox.type = Player::GUIMessageBox::InputDialog;
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_GUI_MESSAGEBOX)->setPlayer(player);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_GUI_MESSAGEBOX)->Send(false);
|
||||
}
|
||||
|
||||
void GUIFunctions::PasswordDialog(unsigned short pid, int id, const char *label, const char *note) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
|
||||
player->guiMessageBox.id = id;
|
||||
player->guiMessageBox.label = label;
|
||||
player->guiMessageBox.note = note;
|
||||
player->guiMessageBox.type = Player::GUIMessageBox::PasswordDialog;
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_GUI_MESSAGEBOX)->setPlayer(player);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_GUI_MESSAGEBOX)->Send(false);
|
||||
}
|
||||
|
||||
void GUIFunctions::ListBox(unsigned short pid, int id, const char *label, const char *items)
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
|
||||
player->guiMessageBox.id = id;
|
||||
player->guiMessageBox.label = label;
|
||||
player->guiMessageBox.data = items;
|
||||
player->guiMessageBox.type = Player::GUIMessageBox::ListBox;
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_GUI_MESSAGEBOX)->setPlayer(player);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_GUI_MESSAGEBOX)->Send(false);
|
||||
}
|
||||
|
||||
void GUIFunctions::SetMapVisibility(unsigned short targetPID, unsigned short affectedPID, unsigned short state) noexcept
|
||||
{
|
||||
LOG_MESSAGE(Log::LOG_WARN, "stub");
|
||||
}
|
||||
|
||||
void GUIFunctions::SetMapVisibilityAll(unsigned short targetPID, unsigned short state) noexcept
|
||||
{
|
||||
LOG_MESSAGE(Log::LOG_WARN, "stub");
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
//
|
||||
// Created by koncord on 30.08.16.
|
||||
//
|
||||
|
||||
#ifndef OPENMW_GUIAPI_HPP
|
||||
#define OPENMW_GUIAPI_HPP
|
||||
|
||||
#define GUIAPI \
|
||||
{"MessageBox", GUIFunctions::_MessageBox},\
|
||||
{"CustomMessageBox", GUIFunctions::CustomMessageBox},\
|
||||
{"InputDialog", GUIFunctions::InputDialog},\
|
||||
{"PasswordDialog", GUIFunctions::PasswordDialog},\
|
||||
{"ListBox", GUIFunctions::ListBox},\
|
||||
{"SetMapVisibility", GUIFunctions::SetMapVisibility},\
|
||||
{"SetMapVisibilityAll", GUIFunctions::SetMapVisibilityAll}
|
||||
|
||||
class GUIFunctions
|
||||
{
|
||||
public:
|
||||
/* Do not rename into MessageBox to not conflict with WINAPI's MessageBox */
|
||||
static void _MessageBox(unsigned short pid, int id, const char *label) noexcept;
|
||||
|
||||
static void CustomMessageBox(unsigned short pid, int id, const char *label, const char *buttons) noexcept;
|
||||
static void InputDialog(unsigned short pid, int id, const char *label) noexcept;
|
||||
static void PasswordDialog(unsigned short pid, int id, const char *label, const char *note) noexcept;
|
||||
|
||||
static void ListBox(unsigned short pid, int id, const char *label, const char *items);
|
||||
|
||||
//state 0 - disallow, 1 - allow
|
||||
static void SetMapVisibility(unsigned short targetPID, unsigned short affectedPID, unsigned short state) noexcept;
|
||||
static void SetMapVisibilityAll(unsigned short targetPID, unsigned short state) noexcept;
|
||||
};
|
||||
|
||||
#endif //OPENMW_GUIAPI_HPP
|
|
@ -1,162 +0,0 @@
|
|||
//
|
||||
// Created by koncord on 02.03.16.
|
||||
//
|
||||
|
||||
#include "Items.hpp"
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
|
||||
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
|
||||
#include <apps/openmw-mp/Networking.hpp>
|
||||
#include <apps/openmw/mwworld/inventorystore.hpp>
|
||||
|
||||
using namespace mwmp;
|
||||
|
||||
void ItemFunctions::InitializeInventoryChanges(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
player->inventoryChanges.items.clear();
|
||||
player->inventoryChanges.action = InventoryChanges::SET;
|
||||
}
|
||||
|
||||
int ItemFunctions::GetEquipmentSize() noexcept
|
||||
{
|
||||
return MWWorld::InventoryStore::Slots;
|
||||
}
|
||||
|
||||
unsigned int ItemFunctions::GetInventoryChangesSize(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
|
||||
return player->inventoryChanges.count;
|
||||
}
|
||||
|
||||
void ItemFunctions::EquipItem(unsigned short pid, unsigned short slot, const char *refId, unsigned int count, int charge) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
|
||||
player->equipedItems[slot].refId = refId;
|
||||
player->equipedItems[slot].count = count;
|
||||
player->equipedItems[slot].charge = charge;
|
||||
}
|
||||
|
||||
void ItemFunctions::UnequipItem(unsigned short pid, unsigned short slot) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
ItemFunctions::EquipItem(pid, slot, "", 0, -1);
|
||||
}
|
||||
|
||||
void ItemFunctions::AddItem(unsigned short pid, const char* refId, unsigned int count, int charge) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
Item item;
|
||||
item.refId = refId;
|
||||
item.count = count;
|
||||
item.charge = charge;
|
||||
|
||||
player->inventoryChanges.items.push_back(item);
|
||||
player->inventoryChanges.action = InventoryChanges::ADD;
|
||||
}
|
||||
|
||||
void ItemFunctions::RemoveItem(unsigned short pid, const char* refId, unsigned short count) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
Item item;
|
||||
item.refId = refId;
|
||||
item.count = count;
|
||||
|
||||
player->inventoryChanges.items.push_back(item);
|
||||
player->inventoryChanges.action = InventoryChanges::REMOVE;
|
||||
}
|
||||
|
||||
bool ItemFunctions::HasItemEquipped(unsigned short pid, const char* refId)
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, false);
|
||||
|
||||
for (int slot = 0; slot < MWWorld::InventoryStore::Slots; slot++)
|
||||
if (Misc::StringUtils::ciEqual(player->equipedItems[slot].refId, refId))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *ItemFunctions::GetEquipmentItemRefId(unsigned short pid, unsigned short slot) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
|
||||
return player->equipedItems[slot].refId.c_str();
|
||||
}
|
||||
|
||||
int ItemFunctions::GetEquipmentItemCount(unsigned short pid, unsigned short slot) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
|
||||
return player->equipedItems[slot].count;
|
||||
}
|
||||
|
||||
int ItemFunctions::GetEquipmentItemCharge(unsigned short pid, unsigned short slot) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
|
||||
return player->equipedItems[slot].charge;
|
||||
}
|
||||
|
||||
const char *ItemFunctions::GetInventoryItemRefId(unsigned short pid, unsigned int i) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, "");
|
||||
|
||||
if (i >= player->inventoryChanges.count)
|
||||
return "invalid";
|
||||
|
||||
return player->inventoryChanges.items.at(i).refId.c_str();
|
||||
}
|
||||
|
||||
int ItemFunctions::GetInventoryItemCount(unsigned short pid, unsigned int i) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
|
||||
return player->inventoryChanges.items.at(i).count;
|
||||
}
|
||||
|
||||
int ItemFunctions::GetInventoryItemCharge(unsigned short pid, unsigned int i) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
|
||||
return player->inventoryChanges.items.at(i).charge;
|
||||
}
|
||||
|
||||
void ItemFunctions::SendEquipment(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_EQUIPMENT)->setPlayer(player);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_EQUIPMENT)->Send(false);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_EQUIPMENT)->Send(true);
|
||||
}
|
||||
|
||||
void ItemFunctions::SendInventoryChanges(unsigned short pid, bool toOthers) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_INVENTORY)->setPlayer(player);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_INVENTORY)->Send(toOthers);
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
//
|
||||
// Created by koncord on 30.08.16.
|
||||
//
|
||||
|
||||
#ifndef OPENMW_ITEMAPI_HPP
|
||||
#define OPENMW_ITEMAPI_HPP
|
||||
|
||||
#define ITEMAPI \
|
||||
{"InitializeInventoryChanges", ItemFunctions::InitializeInventoryChanges},\
|
||||
\
|
||||
{"GetEquipmentSize", ItemFunctions::GetEquipmentSize},\
|
||||
{"GetInventoryChangesSize", ItemFunctions::GetInventoryChangesSize},\
|
||||
\
|
||||
{"EquipItem", ItemFunctions::EquipItem},\
|
||||
{"UnequipItem", ItemFunctions::UnequipItem},\
|
||||
\
|
||||
{"AddItem", ItemFunctions::AddItem},\
|
||||
{"RemoveItem", ItemFunctions::RemoveItem},\
|
||||
\
|
||||
{"HasItemEquipped", ItemFunctions::HasItemEquipped},\
|
||||
\
|
||||
{"GetEquipmentItemRefId", ItemFunctions::GetEquipmentItemRefId},\
|
||||
{"GetEquipmentItemCount", ItemFunctions::GetEquipmentItemCount},\
|
||||
{"GetEquipmentItemCharge", ItemFunctions::GetEquipmentItemCharge},\
|
||||
\
|
||||
{"GetInventoryItemRefId", ItemFunctions::GetInventoryItemRefId},\
|
||||
{"GetInventoryItemCount", ItemFunctions::GetInventoryItemCount},\
|
||||
{"GetInventoryItemCharge", ItemFunctions::GetInventoryItemCharge},\
|
||||
\
|
||||
{"SendEquipment", ItemFunctions::SendEquipment},\
|
||||
{"SendInventoryChanges", ItemFunctions::SendInventoryChanges}
|
||||
|
||||
class ItemFunctions
|
||||
{
|
||||
public:
|
||||
|
||||
static void InitializeInventoryChanges(unsigned short pid) noexcept;
|
||||
|
||||
static int GetEquipmentSize() noexcept;
|
||||
static unsigned int GetInventoryChangesSize(unsigned short pid) noexcept;
|
||||
|
||||
static void EquipItem(unsigned short pid, unsigned short slot, const char* refId, unsigned int count, int charge) noexcept;
|
||||
static void UnequipItem(unsigned short pid, unsigned short slot) noexcept;
|
||||
|
||||
static void AddItem(unsigned short pid, const char* refId, unsigned int count, int charge) noexcept;
|
||||
static void RemoveItem(unsigned short pid, const char* refId, unsigned short count) noexcept;
|
||||
|
||||
static bool HasItemEquipped(unsigned short pid, const char* refId);
|
||||
|
||||
static const char *GetEquipmentItemRefId(unsigned short pid, unsigned short slot) noexcept;
|
||||
static int GetEquipmentItemCount(unsigned short pid, unsigned short slot) noexcept;
|
||||
static int GetEquipmentItemCharge(unsigned short pid, unsigned short slot) noexcept;
|
||||
|
||||
static const char *GetInventoryItemRefId(unsigned short pid, unsigned int i) noexcept;
|
||||
static int GetInventoryItemCount(unsigned short pid, unsigned int i) noexcept;
|
||||
static int GetInventoryItemCharge(unsigned short pid, unsigned int i) noexcept;
|
||||
|
||||
static void SendEquipment(unsigned short pid) noexcept;
|
||||
static void SendInventoryChanges(unsigned short pid, bool toOthers = false) noexcept;
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
#endif //OPENMW_ITEMAPI_HPP
|
|
@ -1,64 +0,0 @@
|
|||
#include "Mechanics.hpp"
|
||||
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
#include <components/openmw-mp/Log.hpp>
|
||||
|
||||
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
|
||||
#include <apps/openmw-mp/Networking.hpp>
|
||||
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
bool MechanicsFunctions::IsWerewolf(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0);
|
||||
|
||||
return player->isWerewolf;
|
||||
}
|
||||
|
||||
void MechanicsFunctions::SetWerewolfState(unsigned short pid, bool isWerewolf)
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
player->isWerewolf = isWerewolf;
|
||||
}
|
||||
|
||||
void MechanicsFunctions::SendShapeshift(unsigned short pid)
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_SHAPESHIFT)->setPlayer(player);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_SHAPESHIFT)->Send(false);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_SHAPESHIFT)->Send(true);
|
||||
}
|
||||
|
||||
void MechanicsFunctions::Jail(unsigned short pid, int jailDays, bool ignoreJailTeleportation, bool ignoreJailSkillIncreases,
|
||||
const char* jailProgressText, const char* jailEndText) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
player->jailDays = jailDays;
|
||||
player->ignoreJailTeleportation = ignoreJailTeleportation;
|
||||
player->ignoreJailSkillIncreases = ignoreJailSkillIncreases;
|
||||
player->jailProgressText = jailProgressText;
|
||||
player->jailEndText = jailEndText;
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_JAIL)->setPlayer(player);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_JAIL)->Send(false);
|
||||
}
|
||||
|
||||
void MechanicsFunctions::Resurrect(unsigned short pid, unsigned int type) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
player->resurrectType = type;
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_RESURRECT)->setPlayer(player);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_RESURRECT)->Send(false);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_RESURRECT)->Send(true);
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
#ifndef OPENMW_MECHANICSAPI_HPP
|
||||
#define OPENMW_MECHANICSAPI_HPP
|
||||
|
||||
#include "../Types.hpp"
|
||||
|
||||
#define MECHANICSAPI \
|
||||
{"IsWerewolf", MechanicsFunctions::IsWerewolf},\
|
||||
\
|
||||
{"SetWerewolfState", MechanicsFunctions::SetWerewolfState},\
|
||||
\
|
||||
{"SendShapeshift", MechanicsFunctions::SendShapeshift},\
|
||||
\
|
||||
{"Jail", MechanicsFunctions::Jail},\
|
||||
{"Resurrect", MechanicsFunctions::Resurrect}
|
||||
|
||||
class MechanicsFunctions
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Check whether a player is a werewolf.
|
||||
*
|
||||
* This is based on the last PlayerShapeshift packet received or sent for that player.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \return The werewolf state.
|
||||
*/
|
||||
static bool IsWerewolf(unsigned short pid) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the werewolf state of a player.
|
||||
*
|
||||
* This changes the werewolf state recorded for that player in the server memory, but
|
||||
* does not by itself send a packet.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param bool The new werewolf state.
|
||||
* \return void
|
||||
*/
|
||||
static void SetWerewolfState(unsigned short pid, bool isWerewolf);
|
||||
|
||||
/**
|
||||
* \brief Send a PlayerShapeshift packet about a player.
|
||||
*
|
||||
* This sends the packet to all players connected to the server. It is currently used
|
||||
* only to communicate werewolf states.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \return void
|
||||
*/
|
||||
static void SendShapeshift(unsigned short pid);
|
||||
|
||||
/**
|
||||
* \brief Send a PlayerJail packet about a player.
|
||||
*
|
||||
* This is similar to the player being jailed by a guard, but provides extra parameters for
|
||||
* increased flexibility.
|
||||
*
|
||||
* It is only sent to the player being jailed, as the other players will be informed of the
|
||||
* jailing's actual consequences via other packets sent by the affected client.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param jailDays The number of days to spend jailed, where each day affects one skill point.
|
||||
* \param ignoreJailTeleportation Whether the player being teleported to the nearest jail
|
||||
* marker should be overridden.
|
||||
* \param ignoreJailSkillIncrease Whether the player's Sneak and Security skills should be
|
||||
* prevented from increasing as a result of the jailing,
|
||||
* overriding default behavior.
|
||||
* \param jailProgressText The text that should be displayed while jailed.
|
||||
* \param jailEndText The text that should be displayed once the jailing period is over.
|
||||
* \return void
|
||||
*/
|
||||
static void Jail(unsigned short pid, int jailDays, bool ignoreJailTeleportation = false, bool ignoreJailSkillIncreases = false,
|
||||
const char* jailProgressText = "", const char* jailEndText = "") noexcept;
|
||||
|
||||
/**
|
||||
* \brief Send a PlayerResurrect packet about a player.
|
||||
*
|
||||
* This sends the packet to all players connected to the server.
|
||||
*
|
||||
* \param pid The player ID.
|
||||
* \param type The type of resurrection (0 for REGULAR, 1 for IMPERIAL_SHRINE,
|
||||
* 2 for TRIBUNAL_TEMPLE).
|
||||
* \return void
|
||||
*/
|
||||
static void Resurrect(unsigned short pid, unsigned int type) noexcept;
|
||||
};
|
||||
|
||||
#endif //OPENMW_MECHANICSAPI_HPP
|
|
@ -1,54 +0,0 @@
|
|||
#include "Miscellaneous.hpp"
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
#include <components/openmw-mp/Log.hpp>
|
||||
|
||||
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
|
||||
#include <apps/openmw-mp/Networking.hpp>
|
||||
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
static std::string tempFilename;
|
||||
|
||||
const char *MiscellaneousFunctions::GetCaseInsensitiveFilename(const char *folderPath, const char *filename) noexcept
|
||||
{
|
||||
if (!boost::filesystem::exists(folderPath)) return "invalid";
|
||||
|
||||
boost::filesystem::directory_iterator end_itr; // default construction yields past-the-end
|
||||
|
||||
for (boost::filesystem::directory_iterator itr(folderPath); itr != end_itr; ++itr)
|
||||
{
|
||||
if (Misc::StringUtils::ciEqual(itr->path().filename().string(), filename))
|
||||
{
|
||||
tempFilename = itr->path().filename().string();
|
||||
return tempFilename.c_str();
|
||||
}
|
||||
}
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
unsigned int MiscellaneousFunctions::GetLastPlayerId() noexcept
|
||||
{
|
||||
return Players::getLastPlayerId();
|
||||
}
|
||||
|
||||
int MiscellaneousFunctions::GetCurrentMpNum() noexcept
|
||||
{
|
||||
return mwmp::Networking::getPtr()->getCurrentMpNum();
|
||||
}
|
||||
|
||||
void MiscellaneousFunctions::SetCurrentMpNum(int mpNum) noexcept
|
||||
{
|
||||
mwmp::Networking::getPtr()->setCurrentMpNum(mpNum);
|
||||
}
|
||||
|
||||
void MiscellaneousFunctions::LogMessage(unsigned short level, const char *message) noexcept
|
||||
{
|
||||
LOG_MESSAGE_SIMPLE(level, "[Script]: %s", message);
|
||||
}
|
||||
|
||||
void MiscellaneousFunctions::LogAppend(unsigned short level, const char *message) noexcept
|
||||
{
|
||||
LOG_APPEND(level, "[Script]: %s", message);
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
#ifndef OPENMW_MISCELLANEOUSAPI_HPP
|
||||
#define OPENMW_MISCELLANEOUSAPI_HPP
|
||||
|
||||
#include "../Types.hpp"
|
||||
|
||||
#define MISCELLANEOUSAPI \
|
||||
{"GetCaseInsensitiveFilename", MiscellaneousFunctions::GetCaseInsensitiveFilename},\
|
||||
\
|
||||
{"GetLastPlayerId", MiscellaneousFunctions::GetLastPlayerId},\
|
||||
\
|
||||
{"GetCurrentMpNum", MiscellaneousFunctions::GetCurrentMpNum},\
|
||||
{"SetCurrentMpNum", MiscellaneousFunctions::SetCurrentMpNum},\
|
||||
\
|
||||
{"LogMessage", MiscellaneousFunctions::LogMessage},\
|
||||
{"LogAppend", MiscellaneousFunctions::LogAppend}
|
||||
|
||||
class MiscellaneousFunctions
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* \brief Get the first filename in a folder that has a case insensitive match with the filename
|
||||
* argument.
|
||||
*
|
||||
* This is used to retain case insensitivity when opening data files on Linux.
|
||||
*
|
||||
* \return The filename that matches.
|
||||
*/
|
||||
static const char *GetCaseInsensitiveFilename(const char *folderPath, const char *filename) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the last player ID currently connected to the server.
|
||||
*
|
||||
* Every player receives a unique numerical index known as their player ID upon joining the
|
||||
* server.
|
||||
*
|
||||
* \return The player ID.
|
||||
*/
|
||||
static unsigned int GetLastPlayerId() noexcept;
|
||||
|
||||
/**
|
||||
* \brief Get the current (latest) mpNum generated by the server.
|
||||
*
|
||||
* Every object that did not exist in an .ESM or .ESP data file and has instead been placed or
|
||||
* spawned through a server-sent packet has a numerical index known as its mpNum.
|
||||
*
|
||||
* When ObjectPlace and ObjectSpawn packets are received from players, their objects lack mpNums,
|
||||
* so the server assigns them some based on incrementing the server's current mpNum, with the
|
||||
* operation's final mpNum becoming the server's new current mpNum.
|
||||
*
|
||||
* \return The mpNum.
|
||||
*/
|
||||
static int GetCurrentMpNum() noexcept;
|
||||
|
||||
/**
|
||||
* \brief Set the current (latest) mpNum generated by the server.
|
||||
*
|
||||
* When restarting a server, it is important to revert to the previous current (latest) mpNum
|
||||
* as stored in the server's data, so as to avoid starting over from 0 and ending up assigning
|
||||
* duplicate mpNums to objects.
|
||||
*
|
||||
* \param mpNum The number that should be used as the new current mpNum.
|
||||
* \return void
|
||||
*/
|
||||
static void SetCurrentMpNum(int mpNum) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Write a log message with its own timestamp.
|
||||
*
|
||||
* It will have "[Script]:" prepended to it so as to mark it as a script-generated log message.
|
||||
*
|
||||
* \param level The logging level used (0 for LOG_VERBOSE, 1 for LOG_INFO, 2 for LOG_WARN,
|
||||
* 3 for LOG_ERROR, 4 for LOG_FATAL).
|
||||
* \param message The message logged.
|
||||
* \return void
|
||||
*/
|
||||
static void LogMessage(unsigned short level, const char *message) noexcept;
|
||||
|
||||
/**
|
||||
* \brief Write a log message without its own timestamp.
|
||||
*
|
||||
* It will have "[Script]:" prepended to it so as to mark it as a script-generated log message.
|
||||
*
|
||||
* \param level The logging level used (0 for LOG_VERBOSE, 1 for LOG_INFO, 2 for LOG_WARN,
|
||||
* 3 for LOG_ERROR, 4 for LOG_FATAL).
|
||||
* \param message The message logged.
|
||||
* \return void
|
||||
*/
|
||||
static void LogAppend(unsigned short level, const char *message) noexcept;
|
||||
};
|
||||
|
||||
#endif //OPENMW_MISCELLANEOUSAPI_HPP
|
|
@ -1,128 +0,0 @@
|
|||
#include "Positions.hpp"
|
||||
#include <apps/openmw-mp/Script/ScriptFunctions.hpp>
|
||||
#include <components/openmw-mp/NetworkMessages.hpp>
|
||||
#include <apps/openmw-mp/Player.hpp>
|
||||
#include <apps/openmw-mp/Networking.hpp>
|
||||
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
void PositionFunctions::GetPos(unsigned short pid, float *x, float *y, float *z) noexcept
|
||||
{
|
||||
*x = 0.00;
|
||||
*y = 0.00;
|
||||
*z = 0.00;
|
||||
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
|
||||
*x = player->position.pos[0];
|
||||
*y = player->position.pos[1];
|
||||
*z = player->position.pos[2];
|
||||
}
|
||||
|
||||
double PositionFunctions::GetPosX(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0.0f);
|
||||
|
||||
return player->position.pos[0];
|
||||
}
|
||||
|
||||
double PositionFunctions::GetPosY(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0.0f);
|
||||
|
||||
return player->position.pos[1];
|
||||
}
|
||||
|
||||
double PositionFunctions::GetPosZ(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0.0f);
|
||||
|
||||
return player->position.pos[2];
|
||||
}
|
||||
|
||||
double PositionFunctions::GetPreviousCellPosX(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0.0f);
|
||||
|
||||
return player->previousCellPosition.pos[0];
|
||||
}
|
||||
|
||||
double PositionFunctions::GetPreviousCellPosY(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0.0f);
|
||||
|
||||
return player->previousCellPosition.pos[1];
|
||||
}
|
||||
|
||||
double PositionFunctions::GetPreviousCellPosZ(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0.0f);
|
||||
|
||||
return player->previousCellPosition.pos[2];
|
||||
}
|
||||
|
||||
void PositionFunctions::GetRot(unsigned short pid, float *x, float *y, float *z) noexcept
|
||||
{
|
||||
*x = 0.00;
|
||||
*y = 0.00;
|
||||
*z = 0.00;
|
||||
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
*x = player->position.rot[0];
|
||||
*y = player->position.rot[1];
|
||||
*z = player->position.rot[2];
|
||||
}
|
||||
|
||||
double PositionFunctions::GetRotX(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0.0f);
|
||||
|
||||
return player->position.rot[0];
|
||||
}
|
||||
|
||||
double PositionFunctions::GetRotZ(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, 0.0f);
|
||||
|
||||
return player->position.rot[2];
|
||||
}
|
||||
|
||||
void PositionFunctions::SetPos(unsigned short pid, double x, double y, double z) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player,);
|
||||
|
||||
player->position.pos[0] = x;
|
||||
player->position.pos[1] = y;
|
||||
player->position.pos[2] = z;
|
||||
}
|
||||
|
||||
void PositionFunctions::SetRot(unsigned short pid, double x, double z) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
player->position.rot[0] = x;
|
||||
player->position.rot[2] = z;
|
||||
}
|
||||
|
||||
void PositionFunctions::SendPos(unsigned short pid) noexcept
|
||||
{
|
||||
Player *player;
|
||||
GET_PLAYER(pid, player, );
|
||||
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_POSITION)->setPlayer(player);
|
||||
mwmp::Networking::get().getPlayerPacketController()->GetPacket(ID_PLAYER_POSITION)->Send(false);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue