Server browser

pull/133/head
Koncord 8 years ago
parent dfb87e9e0d
commit cb799ee446

@ -69,6 +69,7 @@ option(BUILD_OPENMW_MP "build OpenMW-MP" ON)
option(BUILD_BSATOOL "build BSA extractor" ON) option(BUILD_BSATOOL "build BSA extractor" ON)
option(BUILD_ESMTOOL "build ESM inspector" ON) option(BUILD_ESMTOOL "build ESM inspector" ON)
option(BUILD_LAUNCHER "build Launcher" ON) option(BUILD_LAUNCHER "build Launcher" ON)
option(BUILD_NETLAUNCHER "build Launcher" ON)
option(BUILD_MWINIIMPORTER "build MWiniImporter" ON) option(BUILD_MWINIIMPORTER "build MWiniImporter" ON)
option(BUILD_ESSIMPORTER "build ESS (Morrowind save game) importer" ON) option(BUILD_ESSIMPORTER "build ESS (Morrowind save game) importer" ON)
option(BUILD_OPENCS "build OpenMW Construction Set" ON) option(BUILD_OPENCS "build OpenMW Construction Set" ON)
@ -128,7 +129,7 @@ endif()
find_package(RakNet REQUIRED) find_package(RakNet REQUIRED)
include_directories(${RakNet_INCLUDES}) include_directories(${RakNet_INCLUDES})
if (NOT BUILD_LAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD) if (NOT BUILD_LAUNCHER AND NOT BUILD_NETLAUNCHER AND NOT BUILD_OPENCS AND NOT BUILD_WIZARD)
set(USE_QT FALSE) set(USE_QT FALSE)
else() else()
set(USE_QT TRUE) set(USE_QT TRUE)
@ -393,6 +394,9 @@ IF(NOT WIN32 AND NOT APPLE)
IF(BUILD_LAUNCHER) IF(BUILD_LAUNCHER)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-launcher" DESTINATION "${BINDIR}" ) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-launcher" DESTINATION "${BINDIR}" )
ENDIF(BUILD_LAUNCHER) ENDIF(BUILD_LAUNCHER)
IF(BUILD_NETLAUNCHER)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-netlauncher" DESTINATION "${BINDIR}" )
ENDIF(BUILD_NETLAUNCHER)
IF(BUILD_BSATOOL) IF(BUILD_BSATOOL)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" ) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" )
ENDIF(BUILD_BSATOOL) ENDIF(BUILD_BSATOOL)
@ -493,6 +497,9 @@ if(WIN32)
IF(BUILD_LAUNCHER) IF(BUILD_LAUNCHER)
SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-launcher;OpenMW Launcher") SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-launcher;OpenMW Launcher")
ENDIF(BUILD_LAUNCHER) ENDIF(BUILD_LAUNCHER)
IF(BUILD_NETLAUNCHER)
SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-netlauncher;tes3mp Launcher")
ENDIF(BUILD_NETLAUNCHER)
IF(BUILD_OPENCS) IF(BUILD_OPENCS)
SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-cs;OpenMW Construction Set") SET(CPACK_PACKAGE_EXECUTABLES "${CPACK_PACKAGE_EXECUTABLES};openmw-cs;OpenMW Construction Set")
ENDIF(BUILD_OPENCS) ENDIF(BUILD_OPENCS)
@ -579,6 +586,10 @@ if (BUILD_LAUNCHER)
add_subdirectory( apps/launcher ) add_subdirectory( apps/launcher )
endif() endif()
if (BUILD_NETLAUNCHER)
add_subdirectory( apps/netlauncher )
endif()
if (BUILD_MWINIIMPORTER) if (BUILD_MWINIIMPORTER)
add_subdirectory( apps/mwiniimporter ) add_subdirectory( apps/mwiniimporter )
endif() endif()
@ -712,6 +723,10 @@ if (WIN32)
set_target_properties(openmw-launcher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") set_target_properties(openmw-launcher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif() endif()
if (BUILD_NETLAUNCHER)
set_target_properties(openmw-netlauncher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif()
if (BUILD_MWINIIMPORTER) if (BUILD_MWINIIMPORTER)
set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}") set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif() endif()

@ -0,0 +1,90 @@
set(CMAKE_CXX_STANDARD 14)
set(NETLAUNCHER_UI
${CMAKE_SOURCE_DIR}/files/ui/Main.ui
${CMAKE_SOURCE_DIR}/files/ui/ServerInfo.ui
)
set(NETLAUNCHER
main.cpp
Main.cpp
ServerModel.cpp
NetController.cpp
ServerInfoDialog.cpp
netutils/HTTPNetwork.cpp
netutils/Utils.cpp
${CMAKE_SOURCE_DIR}/files/windows/launcher.rc
)
set(NETLAUNCHER_HEADER_MOC
Main.hpp
ServerModel.hpp
ServerInfoDialog.hpp
)
set(NETLAUNCHER_HEADER
${NETLAUNCHER_HEADER_MOC}
NetController.hpp
netutils/HTTPNetwork.hpp
netutils/Utils.hpp
)
source_group(netlauncher FILES ${NETLAUNCHER} ${NETLAUNCHER_HEADER})
set(QT_USE_QTGUI 1)
# Set some platform specific settings
if(WIN32)
set(GUI_TYPE WIN32)
set(QT_USE_QTMAIN TRUE)
endif(WIN32)
if (DESIRED_QT_VERSION MATCHES 4)
message(SEND_ERROR "QT4 is not supported.")
#include(${QT_USE_FILE})
#QT4_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/launcher/launcher.qrc)
#QT4_WRAP_CPP(MOC_SRCS ${NETLAUNCHER_HEADER_MOC})
#QT4_WRAP_UI(UI_HDRS ${NETLAUNCHER_UI})
else()
QT5_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/launcher/launcher.qrc)
QT5_WRAP_CPP(MOC_SRCS ${NETLAUNCHER_HEADER_MOC})
QT5_WRAP_UI(UI_HDRS ${NETLAUNCHER_UI})
endif()
include_directories(${CMAKE_CURRENT_BINARY_DIR})
if(NOT WIN32)
include_directories(${LIBUNSHIELD_INCLUDE_DIR})
endif(NOT WIN32)
# Main executable
add_executable(openmw-netlauncher
${GUI_TYPE}
${NETLAUNCHER}
${NETLAUNCHER_HEADER}
${RCC_SRCS}
${MOC_SRCS}
${UI_HDRS}
)
if (WIN32)
INSTALL(TARGETS openmw-netlauncher RUNTIME DESTINATION ".")
endif (WIN32)
target_link_libraries(openmw-netlauncher
${SDL2_LIBRARY_ONLY}
${RakNet_LIBRARY}
components
)
if (DESIRED_QT_VERSION MATCHES 4)
# target_link_libraries(openmw-netlauncher ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY})
# if(WIN32)
# target_link_libraries(openmw-netlauncher ${QT_QTMAIN_LIBRARY})
# endif(WIN32)
else()
qt5_use_modules(openmw-netlauncher Widgets Core)
endif()
if (BUILD_WITH_CODE_COVERAGE)
add_definitions (--coverage)
target_link_libraries(openmw-netlauncher gcov)
endif()

@ -0,0 +1,137 @@
//
// Created by koncord on 06.01.17.
//
#include "Main.hpp"
#include "NetController.hpp"
#include "ServerInfoDialog.hpp"
#include <qdebug.h>
#include <QInputDialog>
using namespace Process;
Main::Main(QWidget *parent)
{
setupUi(this);
mGameInvoker = new ProcessInvoker();
browser = new ServerModel;
favorites = new ServerModel;
proxyModel = new QSortFilterProxyModel;
proxyModel->setSourceModel(browser);
tblServerBrowser->setModel(proxyModel);
tblFavorites->setModel(proxyModel);
tblServerBrowser->hideColumn(ServerData::ADDR);
tblFavorites->hideColumn(ServerData::ADDR);
refresh();
connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabSwitched(int)));
connect(actionAdd, SIGNAL(triggered(bool)), this, SLOT(addServer()));
connect(actionAdd_by_IP, SIGNAL(triggered(bool)), this, SLOT(addServerByIP()));
connect(actionDelete, SIGNAL(triggered(bool)), this, SLOT(deleteServer()));
connect(actionRefresh, SIGNAL(triggered(bool)), this, SLOT(refresh()));
connect(actionPlay, SIGNAL(triggered(bool)), this, SLOT(play()));
connect(tblServerBrowser, SIGNAL(clicked(QModelIndex)), this, SLOT(serverSelected()));
connect(tblFavorites, SIGNAL(clicked(QModelIndex)), this, SLOT(serverSelected()));
}
Main::~Main()
{
delete mGameInvoker;
}
void Main::addServer()
{
int id = tblServerBrowser->selectionModel()->currentIndex().row();
if(id >= 0)
{
int sourceId = proxyModel->mapToSource(proxyModel->index(id, ServerData::ADDR)).row();
favorites->myData.push_back(browser->myData[sourceId]);
}
}
void Main::addServerByIP()
{
bool ok;
QString text = QInputDialog::getText(this, tr("Add Server by address"), tr("Address:"), QLineEdit::Normal, "", &ok);
if(ok && !text.isEmpty())
{
favorites->insertRows(0, 1);
QModelIndex mi = favorites->index(0, ServerData::ADDR);
favorites->setData(mi, text, Qt::EditRole);
NetController::get()->updateInfo(favorites, mi);
}
}
void Main::deleteServer()
{
if(tabWidget->currentIndex() != 1)
return;
int id = tblFavorites->selectionModel()->currentIndex().row();
if(id >= 0)
{
int sourceId = proxyModel->mapToSource(proxyModel->index(id, ServerData::ADDR)).row();
favorites->removeRow(sourceId);
if(favorites->myData.isEmpty())
actionPlay->setEnabled(false);
}
}
void Main::refresh()
{
NetController::get()->updateInfo(proxyModel->sourceModel());
/*tblServerBrowser->resizeColumnToContents(ServerData::HOSTNAME);
tblServerBrowser->resizeColumnToContents(ServerData::MODNAME);
tblFavorites->resizeColumnToContents(ServerData::HOSTNAME);
tblFavorites->resizeColumnToContents(ServerData::MODNAME);*/
}
void Main::play()
{
QTableView *curTable = tabWidget->currentIndex() ? tblFavorites : tblServerBrowser;
int id = curTable->selectionModel()->currentIndex().row();
if(id < 0)
return;
ServerInfoDialog infoDialog(this);
ServerModel *sm = ((ServerModel*)proxyModel->sourceModel());
int sourceId = proxyModel->mapToSource(proxyModel->index(id, ServerData::ADDR)).row();
NetController::get()->selectServer(&sm->myData[sourceId]);
infoDialog.refresh();
if(!infoDialog.exec())
return;
QStringList arguments;
arguments.append(QLatin1String("--connect=") + sm->myData[sourceId].addr.toLatin1());
if (mGameInvoker->startProcess(QLatin1String("tes3mp"), arguments, true))
return qApp->quit();
}
void Main::tabSwitched(int index)
{
if(index == 0)
{
proxyModel->setSourceModel(browser);
actionDelete->setEnabled(false);
}
else
{
proxyModel->setSourceModel(favorites);
actionDelete->setEnabled(true);
}
actionPlay->setEnabled(false);
actionAdd->setEnabled(false);
}
void Main::serverSelected()
{
actionPlay->setEnabled(true);
if(tabWidget->currentIndex() == 0)
actionAdd->setEnabled(true);
}

@ -0,0 +1,36 @@
//
// Created by koncord on 06.01.17.
//
#ifndef NEWLAUNCHER_MAIN_HPP
#define NEWLAUNCHER_MAIN_HPP
#include "ui_Main.h"
#include "ServerModel.hpp"
#include <QSortFilterProxyModel>
#include <components/process/processinvoker.hpp>
class Main : public QMainWindow, private Ui::MainWindow
{
Q_OBJECT
public:
explicit Main(QWidget *parent = 0);
virtual ~Main();
protected:
protected slots:
void tabSwitched(int index);
void addServer();
void addServerByIP();
void deleteServer();
void refresh();
void play();
void serverSelected();
private:
Process::ProcessInvoker *mGameInvoker;
ServerModel *browser, *favorites;
QSortFilterProxyModel *proxyModel;
};
#endif //NEWLAUNCHER_MAIN_HPP

@ -0,0 +1,215 @@
//
// Created by koncord on 07.01.17.
//
#include <cassert>
#include <QtCore/QTime>
#include "NetController.hpp"
#include "qdebug.h"
#include <RakPeer.h>
#include <RakSleep.h>
#include <sstream>
#include <QJsonDocument>
#include <QJsonArray>
#include <memory>
using namespace std;
NetController *NetController::mThis = nullptr;
NetController *NetController::get()
{
assert(mThis);
return mThis;
}
void NetController::Create()
{
assert(!mThis);
mThis = new NetController;
}
void NetController::Destroy()
{
assert(mThis);
delete mThis;
mThis = nullptr;
}
NetController::NetController() : httpNetwork("127.0.0.1", 8080)
{
}
NetController::~NetController()
{
}
struct pattern
{
pattern(QString value): value(value) {}
bool operator()(const ServerData &data)
{
return value == data.addr;
}
QString value;
};
void NetController::downloadInfo(QAbstractItemModel *pModel, QModelIndex index)
{
ServerModel *model = ((ServerModel *) pModel);
/*
* download stuff
*/
QString data;
while (true)
{
data = QString::fromStdString(httpNetwork.getData("/api/servers"));
if (!data.isEmpty() && data != "NO_CONTENT" && data != "LOST_CONNECTION")
break;
RakSleep(30);
}
qDebug() << "Content: " << data;
QJsonParseError err;
QJsonDocument jsonDocument = QJsonDocument::fromJson(data.toLatin1(), &err);
QMap<QString, QVariant> map = jsonDocument.toVariant().toMap()["list servers"].toMap();
for(QMap<QString, QVariant>::Iterator iter = map.begin(); iter != map.end(); iter++)
{
qDebug() << iter.key();
qDebug() << iter.value().toMap()["hostname"].toString();
qDebug() << iter.value().toMap()["modname"].toString();
qDebug() << iter.value().toMap()["players"].toInt();
qDebug() << iter.value().toMap()["max_players"].toInt();
QVector<ServerData>::Iterator value = std::find_if(model->myData.begin(), model->myData.end(), pattern(iter.key()));
if(value == model->myData.end())
model->insertRow(0);
QModelIndex mi = model->index(0, ServerData::ADDR);
model->setData(mi, iter.key());
mi = model->index(0, ServerData::PLAYERS);
model->setData(mi, iter.value().toMap()["players"].toInt());
mi = model->index(0, ServerData::MAX_PLAYERS);
model->setData(mi, iter.value().toMap()["max_players"].toInt());
mi = model->index(0, ServerData::HOSTNAME);
model->setData(mi, iter.value().toMap()["hostname"].toString());
mi = model->index(0, ServerData::MODNAME);
model->setData(mi, iter.value().toMap()["modname"].toString());
mi = model->index(0, ServerData::PING);
QStringList addr = iter.key().split(":");
model->setData(mi, PingRakNetServer(addr[0].toLatin1().data(), addr[1].toUShort()));
}
//qDebug() << data;
if (model->rowCount() != 0)
return;
/*model->insertRows(0, 6);
model->myData[0] = {"127.0.0.1:25565", 0, 20, 1, "Super Server"};
model->myData[1] = {"127.0.0.1:25565", 5, 20, 2, "Koncord's server"};
model->myData[2] = {"server.local:8888", 15, 15, 15, "tes3mp server", "custom mode"};
model->myData[3] = {"127.0.0.1:25562", 1, 2, 5, "Server"};
model->myData[4] = {"tes3mp.com:22222", 8, 9, 1000, "Antoher Server", "super duper mod"};
model->myData[5] = {"localhost:24", 1, 5, 5, "Test Server", "Another mod 0.1"};*/
}
void NetController::updateInfo(QAbstractItemModel *pModel, QModelIndex index)
{
qDebug() << "TODO: \"NetController::updateInfo(QAbstractItemModel *, QModelIndex)\" is not completed";
ServerModel *model = ((ServerModel*)pModel);
if (index.isValid() && index.row() >= 0)
{
//ServerData &sd = model->myData[index.row()];
//qDebug() << sd.addr;
downloadInfo(pModel, index);
}
else
{
for (QVector<ServerData>::Iterator iter = model->myData.begin(); iter != model->myData.end(); iter++)
{
qDebug() << iter->addr;
}
model->removeRows(0, model->rowCount(index));
downloadInfo(pModel, index);
}
}
void NetController::updateInfo()
{
QString data;
QString uri = "/api/servers/" + sd->addr;
while (true)
{
data = QString::fromStdString(httpNetwork.getData(uri.toLatin1()));
if (!data.isEmpty() && data != "NO_CONTENT" && data != "LOST_CONNECTION")
break;
RakSleep(30);
}
qDebug() << "Content: " << data;
QJsonParseError err;
QJsonDocument jsonDocument = QJsonDocument::fromJson(data.toLatin1(), &err);
QMap<QString, QVariant> map = jsonDocument.toVariant().toMap()["server"].toMap();
qDebug() << sd->addr;
qDebug() << map["hostname"].toString();
qDebug() << map["modname"].toString();
qDebug() << map["players"].toInt();
qDebug() << map["max_players"].toInt();
sd->hostName = map["hostname"].toString();
sd->modName = map["modname"].toString();
sd->players = map["players"].toInt();
sd->maxPlayers = map["max_players"].toInt();
QStringList addr = sd->addr.split(":");
sd->ping = PingRakNetServer(addr[0].toLatin1(), addr[1].toUShort());
sed = getExtendedData(addr[0].toLatin1(), addr[1].toUShort());
}
QStringList NetController::players()
{
QStringList listPlayers;
for(vector<string>::iterator player = sed.players.begin(); player != sed.players.end(); player++)
listPlayers.push_back(player->c_str());
return listPlayers;
}
QStringList NetController::plugins()
{
QStringList listPlugins;
for(vector<string>::iterator plugin = sed.plugins.begin(); plugin != sed.plugins.end(); plugin++)
listPlugins.push_back(plugin->c_str());
return listPlugins;
}
void NetController::selectServer(ServerData *pServerData)
{
sd = pServerData;
}
ServerData *NetController::selectedServer()
{
return sd;
}

@ -0,0 +1,41 @@
//
// Created by koncord on 07.01.17.
//
#ifndef NEWLAUNCHER_NETCONTROLLER_HPP
#define NEWLAUNCHER_NETCONTROLLER_HPP
#include "ServerModel.hpp"
#include "netutils/HTTPNetwork.hpp"
#include "netutils/Utils.hpp"
struct ServerModel;
class NetController
{
public:
static NetController *get();
static void Create();
static void Destroy();
void updateInfo(QAbstractItemModel *pModel, QModelIndex index= QModelIndex());
void updateInfo();
QStringList players();
QStringList plugins();
void selectServer(ServerData *pServerData);
ServerData *selectedServer();
protected:
NetController();
~NetController();
private:
NetController(const NetController &controller);
void downloadInfo(QAbstractItemModel *pModel, QModelIndex index);
static NetController *mThis;
ServerData *sd;
HTTPNetwork httpNetwork;
ServerExtendedData sed;
};
#endif //NEWLAUNCHER_NETCONTROLLER_HPP

@ -0,0 +1,36 @@
//
// Created by koncord on 07.01.17.
//
#include "qdebug.h"
#include "NetController.hpp"
#include "ServerInfoDialog.hpp"
ServerInfoDialog::ServerInfoDialog(QWidget *parent): QDialog(parent)
{
setupUi(this);
connect(btnRefresh, SIGNAL(clicked()), this, SLOT(refresh()));
}
ServerInfoDialog::~ServerInfoDialog()
{
}
void ServerInfoDialog::refresh()
{
NetController::get()->updateInfo();
ServerData *sd = NetController::get()->selectedServer();
leAddr->setText(sd->addr);
lblName->setText(sd->hostName);
lblPing->setNum(sd->ping);
listPlayers->clear();
QStringList players = NetController::get()->players();
listPlayers->addItems(players);
listPlugins->clear();
listPlugins->addItems(NetController::get()->plugins());
lblPlayers->setText(QString::number(players.size()) + " / " + QString::number(sd->maxPlayers));
}

@ -0,0 +1,21 @@
//
// Created by koncord on 07.01.17.
//
#ifndef NEWLAUNCHER_SERVERINFODIALOG_HPP
#define NEWLAUNCHER_SERVERINFODIALOG_HPP
#include "ui_ServerInfo.h"
class ServerInfoDialog : public QDialog, public Ui::Dialog
{
Q_OBJECT
public:
explicit ServerInfoDialog(QWidget *parent = 0);
virtual ~ServerInfoDialog();
public slots:
void refresh();
};
#endif //NEWLAUNCHER_SERVERINFODIALOG_HPP

@ -0,0 +1,178 @@
#include <qmessagebox.h>
#include "ServerModel.hpp"
#include <qdebug.h>
ServerModel::ServerModel(QObject *parent) : QAbstractTableModel(parent)
{
}
ServerModel::~ServerModel()
{
}
/*QHash<int, QByteArray> ServerModel::roleNames() const
{
return roles;
}*/
QVariant ServerModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (index.row() < 0 || index.row() > myData.size())
return QVariant();
const ServerData &sd = myData.at(index.row());
if(role == Qt::DisplayRole)
{
QVariant var;
switch (index.column())
{
case ServerData::ADDR:
var = sd.addr;
break;
case ServerData::PLAYERS:
var = sd.players;
break;
case ServerData::MAX_PLAYERS:
var = sd.maxPlayers;
break;
case ServerData::HOSTNAME:
var = sd.hostName;
break;
case ServerData::PING:
var = sd.ping;
break;
case ServerData::MODNAME:
if(sd.modName.isEmpty())
var = "default";
else
var = sd.modName;
break;
}
return var;
}
return QVariant();
}
QVariant ServerModel::headerData(int section, Qt::Orientation orientation, int role) const
{
QVariant var;
if (orientation == Qt::Horizontal)
{
if (role == Qt::SizeHintRole)
{
/*if(section == ServerData::HOSTNAME)
var = QSize(200, 25);*/
}
else if (role == Qt::DisplayRole)
{
switch (section)
{
case ServerData::ADDR:
var = "Address";
break;
case ServerData::HOSTNAME:
var = "Host name";
break;
case ServerData::PLAYERS:
var = "Players";
break;
case ServerData::MAX_PLAYERS:
var = "Player Max";
break;
case ServerData::PING:
var = "Ping";
break;
case ServerData::MODNAME:
var = "Game mode";
}
}
}
return var;
}
int ServerModel::rowCount(const QModelIndex &parent) const
{
return myData.size();
}
int ServerModel::columnCount(const QModelIndex &parent) const
{
return ServerData::LAST;
}
bool ServerModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.isValid() && role == Qt::EditRole)
{
int row = index.row();
int col = index.column();
ServerData &sd = myData[row];
bool ok = true;
switch(col)
{
case ServerData::ADDR:
sd.addr = value.toString();
ok = !sd.addr.isEmpty();
break;
case ServerData::PLAYERS:
sd.players = value.toInt(&ok);
break;
case ServerData::MAX_PLAYERS:
sd.maxPlayers = value.toInt(&ok);
break;
case ServerData::HOSTNAME:
sd.hostName = value.toString();
ok = !sd.addr.isEmpty();
break;
case ServerData::PING:
sd.ping = value.toInt(&ok);
break;
case ServerData::MODNAME:
sd.modName = value.toString();
break;
default:
return false;
}
if(ok)
emit(dataChanged(index, index));
return true;
}
return false;
}
bool ServerModel::insertRows(int position, int count, const QModelIndex &index)
{
Q_UNUSED(index);
beginInsertRows(QModelIndex(), position, position + count - 1);
for (int row = 0; row < count; ++row) {
ServerData sd {"", -1, -1, -1, ""};
myData.insert(position, sd);
}
endInsertRows();
return true;
}
bool ServerModel::removeRows(int position, int count, const QModelIndex &parent)
{
beginRemoveRows(parent, position, position + count - 1);
myData.erase(myData.begin()+position, myData.begin() + position + count);
endRemoveRows();
return true;
}
QModelIndex ServerModel::index(int row, int column, const QModelIndex &parent) const
{
QModelIndex index = QAbstractTableModel::index(row, column, parent);
//qDebug() << "Valid index? " << index.isValid() << " " << row << " " << column;
return index;
}

@ -0,0 +1,52 @@
#ifndef SERVERMODEL_FONTMODEL_HPP
#define SERVERMODEL_FONTMODEL_HPP
#include <QObject>
#include <vector>
#include <QString>
#include <QAbstractTableModel>
struct ServerData
{
QString addr;
int players, maxPlayers;
int ping;
QString hostName;
QString modName;
enum IDS
{
ADDR,
HOSTNAME,
PLAYERS,
MAX_PLAYERS,
MODNAME,
PING,
LAST
};
};
class ServerModel: public QAbstractTableModel
{
Q_OBJECT
public:
explicit ServerModel(QObject *parent = 0);
~ServerModel();
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent) const;
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
bool insertRows(int row, int count, const QModelIndex &index = QModelIndex());
bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
public:
//QHash<int, QByteArray> roles;
QVector<ServerData> myData;
};
#endif //SERVERMODEL_FONTMODEL_HPP

@ -0,0 +1,17 @@
#include <QApplication>
#include "Main.hpp"
#include "NetController.hpp"
int main(int argc, char *argv[])
{
// initialize resources, if needed
// Q_INIT_RESOURCE(resfile);
NetController::Create();
atexit(NetController::Destroy);
QApplication app(argc, argv);
Main d;
d.show();
// create and show your widgets here
return app.exec();
}

@ -0,0 +1,96 @@
//
// Created by koncord on 07.01.17.
//
#include <RakPeer.h>
#include <HTTPConnection2.h>
#include <TCPInterface.h>
#include <RakSleep.h>
#include <sstream>
#include "HTTPNetwork.hpp"
using namespace RakNet;
HTTPNetwork::HTTPNetwork(std::string addr, unsigned short port) : address(addr), port(port)
{
httpConnection = HTTPConnection2::GetInstance();
tcpInterface = new TCPInterface;
tcpInterface->Start(0, 64);
tcpInterface->AttachPlugin(httpConnection);
}
HTTPNetwork::~HTTPNetwork()
{
delete tcpInterface;
}
std::string HTTPNetwork::answer()
{
RakNet::SystemAddress sa;
RakNet::Packet *packet;
RakNet::SystemAddress hostReceived;
RakNet::RakString response;
RakNet::RakString transmitted, hostTransmitted;
int contentOffset = 0;
while (true)
{
// This is kind of crappy, but for TCP plugins, always do HasCompletedConnectionAttempt,
// then Receive(), then HasFailedConnectionAttempt(),HasLostConnection()
sa = tcpInterface->HasCompletedConnectionAttempt();
if (sa != RakNet::UNASSIGNED_SYSTEM_ADDRESS)
printf("Connected to master server: %s\n", sa.ToString());
sa = tcpInterface->HasFailedConnectionAttempt();
if (sa != RakNet::UNASSIGNED_SYSTEM_ADDRESS)
{
printf("Failed to connect to master server: %s\n", sa.ToString());
return "FAIL_CONNECT";
}
sa = tcpInterface->HasLostConnection();
if (sa != RakNet::UNASSIGNED_SYSTEM_ADDRESS)
{
printf("Lost connection to master server: %s\n", sa.ToString());
return "LOST_CONNECTION";
}
for (packet = tcpInterface->Receive(); packet; tcpInterface->DeallocatePacket(
packet), packet = tcpInterface->Receive());
if (httpConnection->GetResponse(transmitted, hostTransmitted, response, hostReceived, contentOffset))
{
if (contentOffset < 0)
return "NO_CONTENT"; // no content
tcpInterface->CloseConnection(sa);
return (response.C_String() + contentOffset);
}
RakSleep(30);
}
}
std::string HTTPNetwork::getData(const char *uri)
{
RakNet::RakString createRequest = RakNet::RakString::FormatForGET(uri);
httpConnection->TransmitRequest(createRequest, address.c_str(), port);
return answer();
}
std::string HTTPNetwork::getDataPOST(const char *uri, const char* body, const char* contentType)
{
RakNet::RakString createRequest = RakNet::RakString::FormatForPOST(uri, contentType, body);
httpConnection->TransmitRequest(createRequest, address.c_str(), port);
return answer();
}
std::string HTTPNetwork::getDataPUT(const char *uri, const char* body, const char* contentType)
{
RakNet::RakString createRequest = RakNet::RakString::FormatForPUT(uri, contentType, body);
httpConnection->TransmitRequest(createRequest, address.c_str(), port);
return answer();
}

@ -0,0 +1,35 @@
//
// Created by koncord on 07.01.17.
//
#ifndef NEWLAUNCHER_HTTPNETWORK_HPP
#define NEWLAUNCHER_HTTPNETWORK_HPP
#include <string>
namespace RakNet
{
class TCPInterface;
class HTTPConnection2;
}
class HTTPNetwork
{
public:
HTTPNetwork(std::string addr, unsigned short port);
~HTTPNetwork();
std::string getData(const char *uri);
std::string getDataPOST(const char *uri, const char* body, const char* contentType = "application/json");
std::string getDataPUT(const char *uri, const char* body, const char* contentType = "application/json");
protected:
RakNet::TCPInterface *tcpInterface;
RakNet::HTTPConnection2 *httpConnection;
std::string address;
unsigned short port;
std::string answer();
};
#endif //NEWLAUNCHER_HTTPNETWORK_HPP

@ -0,0 +1,151 @@
//
// Created by koncord on 07.01.17.
//
#include <RakPeer.h>
#include <MessageIdentifiers.h>
#include <RakSleep.h>
#include <GetTime.h>
#include <iostream>
#include <sstream>
#include <components/openmw-mp/Version.hpp>
#include "Utils.hpp"
using namespace std;
unsigned int PingRakNetServer(const char *addr, unsigned short port)
{
RakNet::Packet *packet;
bool done = false;
int attempts = 0;
RakNet::TimeMS time = 999;
RakNet::SocketDescriptor socketDescriptor = {0, ""};
RakNet::RakPeerInterface *peer = RakNet::RakPeerInterface::GetInstance();
peer->Startup(1,&socketDescriptor, 1);
peer->Ping(addr, port, false);
while (!done)
{
for (packet=peer->Receive(); packet; peer->DeallocatePacket(packet), packet=peer->Receive())
{
if(packet->data[0] == ID_UNCONNECTED_PONG)
{
RakNet::BitStream bsIn(&packet->data[1], packet->length, false);
bsIn.Read(time);
time = RakNet::GetTimeMS() - time - 5;
done = true;
break;
}
}
if (attempts >= 60) // wait 300 msec
done = true;
attempts++;
RakSleep(5);
}
RakNet::RakPeerInterface::DestroyInstance(peer);
return time;
}
ServerExtendedData getExtendedData(const char *addr, unsigned short port)
{
ServerExtendedData data;
RakNet::SocketDescriptor socketDescriptor = {0, ""};
RakNet::RakPeerInterface *peer = RakNet::RakPeerInterface::GetInstance();
peer->Startup(1, &socketDescriptor, 1);
stringstream sstr(TES3MP_VERSION);
sstr << TES3MP_PROTO_VERSION;
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)
msg = "Connection attempt failed.\n";
bool queue = true;
while (queue)
{
for (RakNet::Packet *packet = peer->Receive(); packet; peer->DeallocatePacket(
packet), packet = peer->Receive())
{
switch (packet->data[0])
{
case ID_CONNECTION_ATTEMPT_FAILED:
{
msg = "Connection failed.\n"
"Either the IP address is wrong or a firewall on either system is blocking\n"
"UDP packets on the port you have chosen.";
queue = false;
break;
}
case ID_INVALID_PASSWORD:
{
msg = "Connection failed.\n"
"The client or server is outdated.\n";
queue = false;
break;
}
case ID_CONNECTION_REQUEST_ACCEPTED:
{
msg = "Connection accepted.\n";
queue = false;
break;
}
case ID_DISCONNECTION_NOTIFICATION:
throw runtime_error("ID_DISCONNECTION_NOTIFICATION.\n");
case ID_CONNECTION_BANNED:
throw runtime_error("ID_CONNECTION_BANNED.\n");
case ID_CONNECTION_LOST:
throw runtime_error("ID_CONNECTION_LOST.\n");
default:
printf("Connection message with identifier %i has arrived in initialization.\n", packet->data[0]);
}
}
}
puts(msg.c_str());
{
RakNet::BitStream bs;
bs.Write((unsigned char) (ID_USER_PACKET_ENUM + 1));
peer->Send(&bs, HIGH_PRIORITY, RELIABLE_ORDERED, 0, RakNet::UNASSIGNED_SYSTEM_ADDRESS, true);
}
RakNet::Packet *packet;
bool done = false;
while (!done)
{
for (packet = peer->Receive(); packet; peer->DeallocatePacket(packet), packet = peer->Receive())
{
if(packet->data[0] == (ID_USER_PACKET_ENUM+1))
{
RakNet::BitStream bs(packet->data, packet->length, false);
bs.IgnoreBytes(1);
size_t length = 0;
bs.Read(length);
for(int i = 0; i < length; i++)
{
RakNet::RakString str;
bs.Read(str);
data.players.push_back(str.C_String());
}
bs.Read(length);
for(int i = 0; i < length; i++)
{
RakNet::RakString str;
bs.Read(str);
data.plugins.push_back(str.C_String());
}
done = true;
}
}
}
peer->Shutdown(1);
RakSleep(10);
RakNet::RakPeerInterface::DestroyInstance(peer);
return data;
}

@ -0,0 +1,22 @@
//
// Created by koncord on 07.01.17.
//
#ifndef NEWLAUNCHER_PING_HPP
#define NEWLAUNCHER_PING_HPP
#include <vector>
#include <string>
unsigned int PingRakNetServer(const char *addr, unsigned short port);
struct ServerExtendedData
{
std::vector<std::string> players;
std::vector<std::string> plugins;
};
ServerExtendedData getExtendedData(const char *addr, unsigned short port);
#endif //NEWLAUNCHER_PING_HPP

@ -0,0 +1,134 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tabBrowser">
<attribute name="title">
<string>Browser</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QTableView" name="tblServerBrowser">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabFavorites">
<attribute name="title">
<string>Favorites</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QTableView" name="tblFavorites">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QToolBar" name="toolBar">
<property name="enabled">
<bool>true</bool>
</property>
<property name="windowTitle">
<string>toolBar</string>
</property>
<property name="movable">
<bool>false</bool>
</property>
<property name="floatable">
<bool>false</bool>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="actionPlay"/>
<addaction name="separator"/>
<addaction name="actionAdd"/>
<addaction name="actionAdd_by_IP"/>
<addaction name="actionDelete"/>
<addaction name="separator"/>
<addaction name="actionRefresh"/>
</widget>
<action name="actionAdd">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Add</string>
</property>
</action>
<action name="actionDelete">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Delete</string>
</property>
</action>
<action name="actionRefresh">
<property name="text">
<string>Refresh</string>
</property>
</action>
<action name="actionPlay">
<property name="text">
<string>Play</string>
</property>
</action>
<action name="actionAdd_by_IP">
<property name="text">
<string>Add by address</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>

@ -0,0 +1,240 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>430</width>
<height>447</height>
</rect>
</property>
<property name="windowTitle">
<string>Connect</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Server Name:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblName">
<property name="text">
<string notr="true">TextLabel</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Address:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="leAddr">
<property name="text">
<string notr="true"/>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Players:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblPlayers">
<property name="text">
<string notr="true">0 / 0</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>Ping:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblPing">
<property name="text">
<string notr="true">-1</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Players:</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listPlayers">
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Plugins:</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="listPlugins">
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnCancel">
<property name="text">
<string>Cancel</string>
</property>
<property name="default">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnRefresh">
<property name="text">
<string>Refresh</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnConnect">
<property name="text">
<string>Connect</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>btnCancel</sender>
<signal>clicked()</signal>
<receiver>Dialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>489</x>
<y>524</y>
</hint>
<hint type="destinationlabel">
<x>316</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>btnConnect</sender>
<signal>clicked()</signal>
<receiver>Dialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>580</x>
<y>524</y>
</hint>
<hint type="destinationlabel">
<x>316</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
Loading…
Cancel
Save