summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Mittendrein <git@maxmitti.tk>2015-03-18 17:38:51 +0100
committerMarkus Mittendrein <git@maxmitti.tk>2015-03-18 17:38:51 +0100
commit8983d3b38421843db67a05edee180028959c1b51 (patch)
tree904305965e9ba3baa27680d5d8b2a7b8dbea213e
parentfbe3c5fbe1327fd81e2eb8fe30a75c4cf5d7b35c (diff)
downloadmanager-8983d3b38421843db67a05edee180028959c1b51.tar.gz
manager-8983d3b38421843db67a05edee180028959c1b51.zip
Added ProcessManager, so Clonk can run independently from CRSM.
Added support for league with --league flag for !host.
-rw-r--r--CrServerManager.pro6
-rw-r--r--ProcessManager.cpp245
-rw-r--r--ProcessManager.hpp75
-rw-r--r--crsm.cpp255
-rw-r--r--crsm.hpp25
-rw-r--r--main.cpp2
6 files changed, 546 insertions, 62 deletions
diff --git a/CrServerManager.pro b/CrServerManager.pro
index 40f76a6..d41e1c5 100644
--- a/CrServerManager.pro
+++ b/CrServerManager.pro
@@ -18,12 +18,14 @@ TEMPLATE = app
SOURCES += main.cpp \
- crsm.cpp
+ crsm.cpp \
+ ProcessManager.cpp
HEADERS += \
CmdFunctionRef.hpp \
ClientInfo.hpp \
- crsm.hpp
+ crsm.hpp \
+ ProcessManager.hpp
equals(QT_ARCH, "x86_64"):linux-*: DEFINES += Q_OS_LINUX64
QMAKE_CXXFLAGS *= -std=c++11
diff --git a/ProcessManager.cpp b/ProcessManager.cpp
new file mode 100644
index 0000000..6d2efe8
--- /dev/null
+++ b/ProcessManager.cpp
@@ -0,0 +1,245 @@
+#include "ProcessManager.hpp"
+
+#include <QProcess>
+#include <QDebug>
+
+ProcessManager::ProcessManager(const QString &newPrefix, const QString &newId, bool useStdErr, QObject *parent) : QObject(parent), prefix(newPrefix), id(newId), useStdErr(useStdErr)
+{
+ if(id.isEmpty())
+ {
+ id = QString::number(qrand()) + "-";
+ }
+ stdIn.setFileName(prefix + id + "stdin");
+ stdOut.setFileName(prefix + id + "stdout");
+ stdErr.setFileName(prefix + id + "stderr");
+ ctrlIn.setFileName(prefix + id + "ctrlin");
+ ctrlOut.setFileName(prefix + id + "ctrlout");
+ bool reattaching = false;
+ if(!ctrlIn.exists())
+ {
+ if(!QProcess::startDetached("ProcessManager", QStringList() << prefix + id))
+ {
+ return;
+ }
+ qDebug() << "Started new ProcessManager";
+ qDebug() << "Waiting for ctrl-files";
+ while(!ctrlIn.exists() || !ctrlOut.exists());
+ }
+ else
+ {
+ qDebug() << "Reattaching";
+ reattaching = true;
+ }
+ if(!ctrlIn.open(QFile::WriteOnly | QFile::Unbuffered))
+ {
+ qDebug() << "ctrlin not open" << ctrlIn.errorString();
+ return;
+ }
+ qDebug() << "Opened ctrlin";
+ ctrlIn.write("HELLO\n");
+ if(!ctrlOut.open(QFile::ReadOnly))
+ {
+ qDebug() << "ctrlout not open" << ctrlOut.errorString();
+ return;
+ }
+ qDebug() << "Opened ctrlout";
+ if(ctrlOut.readLine() != "HELLO\n")
+ {
+ qDebug() << "not HELLO";
+ return;
+ }
+ qDebug() << "HELLO";
+ ctrlOutNotifier = new QSocketNotifier(ctrlOut.handle(), QSocketNotifier::Read, this);
+ connect(ctrlOutNotifier, SIGNAL(activated(int)), this, SLOT(ctrlOutReadyRead()));
+ ok = true;
+ if(reattaching)
+ {
+ ctrlIn.write("STATUS\n");
+ QByteArray status = ctrlOut.readLine();
+ if(status != "NOTRUNNING\n")
+ {
+ QRegExp runningExp("^RUNNING: (\\d+)\n$");
+ if(runningExp.exactMatch(QString::fromUtf8(status)))
+ {
+ pid = runningExp.cap(1).toInt();
+ running = connectToIO();
+ }
+ }
+ }
+}
+
+ProcessManager::~ProcessManager()
+{
+
+}
+
+bool ProcessManager::isOk()
+{
+ return ok;
+}
+
+bool ProcessManager::isRunning()
+{
+ return ok && running;
+}
+
+bool ProcessManager::start(const QString &program, QStringList args)
+{
+ if(!ok || running)
+ {
+ return false;
+ }
+ for(int i = 0; i < args.length(); ++i)
+ {
+ args[i] = args[i].replace('\\', "\\\\").replace(' ', "\\ ");
+ }
+ ctrlIn.write("START " + program.toUtf8() + " " + args.join(' ').toUtf8() + "\n");
+ QRegExp runningExp("^RUNNING: (\\d+)\n$");
+ if(!runningExp.exactMatch(ctrlOut.readLine()))
+ {
+ return false;
+ }
+ else
+ {
+ pid = runningExp.cap(1).toInt();
+ return running = connectToIO();
+ }
+}
+
+QByteArray ProcessManager::readAll()
+{
+ return stdOut.readAll();
+}
+
+QByteArray ProcessManager::readLine()
+{
+ return stdOut.readLine();
+}
+
+qint64 ProcessManager::write(const QByteArray &data)
+{
+ if(stdIn.isWritable())
+ {
+ return stdIn.write(data);
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+bool ProcessManager::isWritable()
+{
+ return ok && running && stdIn.isOpen() && stdIn.isWritable();
+}
+
+bool ProcessManager::setWorkingDirectory(const QString &path)
+{
+ if(!ok || !ctrlIn.isWritable() || running)
+ {
+ return false;
+ }
+ ctrlIn.write("CD " + path.toUtf8() + "\n");
+ if(ctrlOut.readLine() != "CHANGED\n")
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+void ProcessManager::kill()
+{
+ if(ok && running && ctrlIn.isWritable())
+ {
+ ctrlIn.write("KILL\n");
+ }
+}
+
+void ProcessManager::exit()
+{
+ ctrlIn.write("EXIT\n");
+}
+
+void ProcessManager::closeProgFifos()
+{
+ ctrlIn.write("CLOSE\n");
+ stdIn.close();
+ stdOut.close();
+ stdErr.close();
+ DELETE_SAVE(stdOutNotifier);
+ DELETE_SAVE(stdErrNotifier);
+}
+
+QString ProcessManager::ID()
+{
+ return id;
+}
+
+void ProcessManager::ctrlOutReadyRead()
+{
+ QString what = QString::fromUtf8(ctrlOut.readLine());
+ QRegExp quitExp("^QUIT: (\\d+)\n");
+ if(quitExp.exactMatch(what))
+ {
+ exitCode = quitExp.cap(1).toInt();
+ running = false;
+ stdOut.close();
+ stdErr.close();
+ stdIn.close();
+ DELETE_SAVE(stdOutNotifier);
+ DELETE_SAVE(stdErrNotifier);
+ emit finished(exitCode);
+ }
+}
+
+void ProcessManager::_stdOutReadyRead()
+{
+ if(!stdOut.isOpen())
+ {
+ DELETE_SAVE(stdOutNotifier);
+ }
+ emit readyRead();
+}
+
+void ProcessManager::_stdErrReadyRead()
+{
+ if(!stdErr.isOpen())
+ {
+ DELETE_SAVE(stdErrNotifier);
+ }
+ emit stdErrReadyRead();
+}
+
+bool ProcessManager::connectToIO()
+{
+ if(!stdOut.open(QFile::ReadOnly))
+ {
+ qDebug() << "stdout not open" << stdOut.errorString();
+ return false;
+ }
+ qDebug() << "Opened stdout";
+ if(!stdErr.open(QFile::ReadOnly))
+ {
+ qDebug() << "stderr not open" << stdOut.errorString();
+ return false;
+ }
+ qDebug() << "Opened stderr";
+ if(!stdIn.open(QFile::WriteOnly | QFile::Unbuffered))
+ {
+ qDebug() << "stdin not open" << stdOut.errorString();
+ return false;
+ }
+ qDebug() << "Opened stdin";
+ stdOutNotifier = new QSocketNotifier(stdOut.handle(), QSocketNotifier::Read, this);
+ connect(stdOutNotifier, SIGNAL(activated(int)), this, SLOT(_stdOutReadyRead()));
+ if(useStdErr)
+ {
+ stdErrNotifier = new QSocketNotifier(stdErr.handle(), QSocketNotifier::Read, this);
+ connect(stdErrNotifier, SIGNAL(activated(int)), this, SLOT(_stdErrReadyRead()));
+ }
+ return true;
+}
+
diff --git a/ProcessManager.hpp b/ProcessManager.hpp
new file mode 100644
index 0000000..7782cb3
--- /dev/null
+++ b/ProcessManager.hpp
@@ -0,0 +1,75 @@
+#ifndef PROCESSMANAGER_HPP
+#define PROCESSMANAGER_HPP
+
+#define DELETE_SAVE(x) if(x != 0) \
+{\
+ delete x;\
+ x = 0;\
+}
+
+#include <QObject>
+#include <QFile>
+#include <QSocketNotifier>
+
+class ProcessManager : public QObject
+{
+ Q_OBJECT
+public:
+ explicit ProcessManager(const QString& prefix, const QString& id = "", bool useStdErr = false, QObject *parent = 0);
+ ~ProcessManager();
+
+ bool isOk();
+ bool isRunning();
+ bool start(const QString& program, QStringList args);
+
+ QByteArray readAll();
+ QByteArray readLine();
+ qint64 write(const QByteArray& data);
+ bool isWritable();
+ bool setWorkingDirectory(const QString& path);
+
+ void kill();
+ void exit();
+
+ void closeProgFifos();
+
+ QString ID();
+
+signals:
+ void readyRead();
+ void stdErrReadyRead();
+ void finished(int);
+
+public slots:
+
+private slots:
+ void ctrlOutReadyRead();
+ void _stdOutReadyRead();
+ void _stdErrReadyRead();
+
+private:
+ QString prefix;
+ QString id;
+
+ QFile ctrlIn;
+ QFile ctrlOut;
+ QFile stdIn;
+ QFile stdOut;
+ QFile stdErr;
+
+ QSocketNotifier* ctrlOutNotifier = 0;
+ QSocketNotifier* stdOutNotifier = 0;
+ QSocketNotifier* stdErrNotifier = 0;
+
+ bool useStdErr = false;
+
+ bool ok = false;
+ bool running = false;
+
+ int pid = 0;
+ int exitCode = 0;
+
+ bool connectToIO();
+};
+
+#endif // PROCESSMANAGER_HPP
diff --git a/crsm.cpp b/crsm.cpp
index 2a4a1b8..69af23b 100644
--- a/crsm.cpp
+++ b/crsm.cpp
@@ -17,7 +17,6 @@ CRSM::CRSM(QObject *parent) :
qin = new QTextStream(stdin, QIODevice::ReadOnly);
qout->setCodec(QTextCodec::codecForName("UTF-8"));
- serverprocess = new QProcess;
args << "/fullscreen" << "/config:config" << "/lobby:60" << "/nosignup";
current = 0;
finish = false;
@@ -27,16 +26,42 @@ CRSM::CRSM(QObject *parent) :
listC4Folders();
readScenarios();
+ if(settings.contains("ReattachId"))
+ {
+ processManager = new ProcessManager("CRSM-Clonkserver-", settings["ReattachId"]);
+ }
+ else
+ {
+ processManager = new ProcessManager("CRSM-Clonkserver-");
+ }
+
+
+ if(!processManager->isOk())
+ {
+ *qout << "Could not start Process Manager!" << endl;
+ settings.remove("ReattachId");
+ writeConfig();
+ return;
+ }
+
+ settings["ReattachId"] = processManager->ID();
+ writeConfig();
+
+ if(processManager->isRunning())
+ {
+ writeToServer("Server Manager läuft wieder.\n");
+ }
+
setupCmds();
connect(&greetMapper, SIGNAL(mapped(QString)), this, SLOT(greet(QString)));
autoHost = settings["AutoHost"] == "true";
- connect(serverprocess, SIGNAL(readyRead()), this, SLOT(readServerOutput()));
- connect(serverprocess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError()));
- connect(serverprocess, SIGNAL(finished(int)), this, SLOT(scenarioFinished()));
- QSocketNotifier *inNotifier = new QSocketNotifier(STDIN_FILENO,QSocketNotifier::Read,this);
+ connect(processManager, SIGNAL(readyRead()), this, SLOT(readServerOutput()));
+ //connect(processManager, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError()));
+ connect(processManager, SIGNAL(finished(int)), this, SLOT(scenarioFinished()));
+ QSocketNotifier *inNotifier = new QSocketNotifier(STDIN_FILENO, QSocketNotifier::Read,this);
connect(inNotifier, SIGNAL(activated(int)), this, SLOT(readInput()));
QFile *reallog = new QFile(settings["ClonkDirectory"]+"CRSM.log");
@@ -69,6 +94,8 @@ CRSM::CRSM(QObject *parent) :
{
settings["IrcUseIngameChat"] = "false";
}
+
+ ok = true;
}
CRSM::~CRSM()
@@ -77,14 +104,19 @@ CRSM::~CRSM()
void CRSM::start()
{
- if(autoHost)
+ if(autoHost && !processManager->isRunning())
nextScen();
}
+bool CRSM::isOk()
+{
+ return ok;
+}
+
void CRSM::readServerOutput()
{
QRegExp timeRemover("^>?\\s*\\[\\d\\d:\\d\\d:\\d\\d\\]\\s+(.*)$");
- QString what(serverprocess->readAll());
+ QString what(processManager->readLine());
if(settings["ServerUsesReadline"] == "true")
{
@@ -116,12 +148,12 @@ void CRSM::readServerOutput()
return;
what = timeRemover.cap(1).trimmed();
- QRegExp userexp("^>?\\s*<(.*)\\|(\\d+)\\|([^>]*)>\\s+(.*)$");
+ QRegExp userexp("^\\s*<(.*)\\|(\\d+)\\|([^>]*)>\\s+(.*)$");
if(userexp.exactMatch(what))
{
QString user = userexp.cap(3);
QString pcName = userexp.cap(1);
- QString cuid = userexp.cap(2);
+ //QString cuid = userexp.cap(2);
ClientInfo& info = clients[pcName];
if(user != settings["ServerNick"])
{
@@ -204,24 +236,35 @@ void CRSM::readServerOutput()
}
if(--clientcount == 0 && userlist.length() > 0 && session["userwish"] != "true")
{
- serverprocess->closeWriteChannel();
+ processManager->closeProgFifos();
}
}
}
-void CRSM::processError()
+/*void CRSM::processError()
{
- *qout << serverprocess->errorString() << endl;
-}
+ *qout << processManager->errorString() << endl;
+}*/
void CRSM::readInput()
{
QString what(qin->readLine());
+ if(what == "/exitdetach" || what == "/exitupdate")
+ {
+ if(what == "/exitupdate")
+ {
+ writeToServer("Der Server Manager wird upgedatet. Befehle funktionieren temporär nicht.\n");
+ }
+ settings["ReattachId"] = processManager->ID();
+ writeConfig();
+ QCoreApplication::quit();
+ return;
+ }
if(what == "/exit")
{
- serverprocess->closeWriteChannel();
+ processManager->closeProgFifos();
+ settings.remove("ReattachId");
finish = true;
- cleanUp();
if(session["hosting"] != "true")
scenarioFinished();
return;
@@ -304,6 +347,7 @@ void CRSM::scenarioFinished()
if(finish)
{
writeConfig();
+ processManager->exit();
if(connection != 0)
{
connection->quit(settings["IrcQuitMessage"]);
@@ -346,7 +390,11 @@ void CRSM::ircMessageReceived(IrcMessage *message)
if(message->nick() == "NickServ")
{
QStringList split = message->parameters().at(1).split(' ', QString::SkipEmptyParts);
- if(split.first() == "STATUS")
+ if(((IrcNoticeMessage*)message)->content().contains("nickname is registered"))
+ {
+ connection->sendCommand(IrcCommand::createMessage("NickServ", "IDENTIFY " + settings["IrcNick"] + " " + settings["IrcPassword"]));
+ }
+ else if(split.first() == "STATUS")
{
QString statusNick = split.at(1);
int status = split.at(2).toInt();
@@ -463,8 +511,9 @@ void CRSM::greet(QString pcName)
writeToServer(QString("Hallo " + info.nick + "!\n"));
}
-void CRSM::startScen(QString scen, QStringList argList)
+void CRSM::startScen(const ScenarioSettings &scen, QStringList argList)
{
+ QString filename;
QFile lastScenFile(LAST_SCEN_FILE_NAME);
QFile curScenFile(CUR_SCEN_FILE_NAME);
curScenFile.open(QFile::ReadOnly);
@@ -473,22 +522,33 @@ void CRSM::startScen(QString scen, QStringList argList)
lastScenFile.close();
curScenFile.close();
curScenFile.open(QFile::WriteOnly);
- curScenFile.write(scen.toUtf8());
+ curScenFile.write(scen.name.toUtf8());
curScenFile.close();
QFile scoreboardFile(SCOREBOARD_FILE_NAME);
scoreboardFile.open(QFile::WriteOnly);
scoreboardFile.close();
- session["scenname"] = scen;
+ session["scenname"] = scen.name;
session["IrcUseIngameChat"] = settings["IrcUseIngameChat"];
if(settings["IrcUseIngameChat"] == "true" && !settings["IrcIngameChannel"].isEmpty())
{
connection->sendCommand(IrcCommand::createTopic(settings["IrcIngameChannel"], "Aktuelles Szenario: " + session["scenname"] + " | Ingamechat ist " + (session["IrcUseIngameChat"] == "true" ? "" : "de") + "aktviert."));
}
- while(maps["Alias"].contains(scen))
- scen = maps["Alias"].value(scen);
- serverprocess->setWorkingDirectory(QDir::currentPath());
- serverprocess->start(settings["ServerExecutable"], argList << scen);
+ filename = scen.name;
+ while(maps["Alias"].contains(filename))
+ filename = maps["Alias"].value(filename);
+ //processManager->setWorkingDirectory(QDir::currentPath());
+ if(scen.league)
+ {
+ argList << "/league";
+ }
+ else
+ {
+ argList << "/noleague";
+ }
+ argList << filename;
+ processManager->setWorkingDirectory(settings["ClonkDirectory"]);
+ processManager->start(settings["ServerExecutable"], argList);
}
void CRSM::readConfig()
@@ -624,6 +684,7 @@ QMap<QString, QString> CRSM::defaultSettings()
void CRSM::listC4Folders()
{
*qout << "Listing Contents of C4Folders...";
+ qout->flush();
QDirIterator it(settings["ClonkDirectory"], QDirIterator::FollowSymlinks);
for(; it.hasNext(); it.next())
{
@@ -667,7 +728,8 @@ bool CRSM::scenExists(QString filePath)
if(!exists)
{
QStringList split = filePath.split('/');
- if(split.length() == 2)
+ QString name = filePath.right(filePath.length() - split.first().length() - 1);
+ if(split.length() >= 2)
{
if(split.first().right(4) == ".c4f")
{
@@ -678,7 +740,7 @@ bool CRSM::scenExists(QString filePath)
while(!lstFile.atEnd())
{
QString line = lstFile.readLine().trimmed();
- if(line == split.last())
+ if(line == name)
{
exists = true;
break;
@@ -740,21 +802,23 @@ QString CRSM::printQueue()
{
QString ret;
if(userlist.length() == 0 && !autoHost)
+ {
return "Die Warteschlange ist leer.\n";
+ }
+ ret = "Folgende Szenarien befinden sich in der Warteschlange:\n";
if(autoHost)
{
- ret = "Folgende Szenarien befinden sich in der Warteschlange:\n";
for(int i = 0; i<settings["UserListLength"].toInt(); i++)
{
- ret += "\t"+QString::number(i+1)+". "+(userlist.length()>i?userlist.at(i):scenlist.at((i-userlist.length() + current)%scenlist.length()) + " (auto)")+"\n";
+ ret += "\t"+QString::number(i+1)+". "+(userlist.length()>i?userlist.at(i).name + " (" + userlist.at(i).wishClient.toString() + ")" + (userlist.at(i).league ? " in der Liga" : ""):scenlist.at((i-userlist.length() + current)%scenlist.length()) + " (auto)")+"\n";
}
}
else
{
int i = 1;
- foreach(const QString& scen, userlist)
+ foreach(const ScenarioSettings& scen, userlist)
{
- ret += "\t" + QString::number(i) + ". " + scen + "\n";
+ ret += "\t" + QString::number(i) + ". " + scen.name + " (" + scen.wishClient.toString() + ")" + (scen.league ? " in der Liga" : "") + "\n";
++i;
}
}
@@ -771,7 +835,7 @@ QString CRSM::skipScen()
{
if(userlist.length() > 0)
{
- QString skipped = userlist.first();
+ QString skipped = userlist.first().name + " (" + userlist.first().wishClient.toString() + ")";
userlist.removeFirst();
return skipped;
}
@@ -779,14 +843,19 @@ QString CRSM::skipScen()
return "";
}
-void CRSM::skipCurrent()
+bool CRSM::skipCurrent()
{
- serverprocess->closeWriteChannel();
+ if(processManager->isRunning())
+ {
+ processManager->closeProgFifos();
+ return true;
+ }
+ return false;
}
void CRSM::writeToServer(const QString &message)
{
- if(!serverprocess->isWritable())
+ if(!processManager->isWritable())
return;
int i = 0;
QStringList split = message.split('\n', QString::KeepEmptyParts);
@@ -813,7 +882,7 @@ void CRSM::writeToServer(const QString &message)
linePart += "-";
}
linePart += "\n";
- serverprocess->write(codec->fromUnicode(linePart));
+ processManager->write(codec->fromUnicode(linePart));
if(settings["ServerUsesReadline"] == "true")
{
if(writtenToServer.length() > settings["ReadlineRereadLimit"].toInt())
@@ -821,7 +890,7 @@ void CRSM::writeToServer(const QString &message)
writtenToServer += codec->fromUnicode(linePart);
}
}
- serverprocess->write(codec->fromUnicode(line));
+ processManager->write(codec->fromUnicode(line));
if(settings["ServerUsesReadline"] == "true")
{
if(writtenToServer.length() > settings["ReadlineRereadLimit"].toInt())
@@ -1052,7 +1121,7 @@ bool CRSM::cmd(const QString &name, const QString &args, const ClientInfo &clien
void CRSM::rightsFailMessage(const ClientInfo &info, UserType minUserType)
{
- respond(info, "Nur ein " + userTypeStrings.value(minUserType) + " kann diesen Befehl verwenden.\n", RespondType::Private);
+ respond(info, "Nur ein " + userTypeStrings.value(minUserType) + " kann diesen Befehl verwenden.\n", RespondType::PrivateNotice);
}
UserType CRSM::clientUserType(const ClientInfo &client)
@@ -1090,7 +1159,7 @@ void CRSM::setupCmds()
addCommand("ingamechat", &CRSM::ircchat, IRC, Admin, "Schaltet den Irc-Ingame-Chat ein bzw. aus.", "<on¦off>");
}
addCommand("queue", &CRSM::queue, Clonk | IRC, User, "Zeigt die nächsten " + settings["UserListLength"] + " Szenarien auf der Warteliste.");
- addCommand("host", &CRSM::host, Clonk | IRC, User, "Nimmt das angegebene Szenario in die Wunschliste auf.", "<Szenarioname¦Alias>");
+ addCommand("host", &CRSM::host, Clonk | IRC, User, "Nimmt das angegebene Szenario in die Wunschliste auf. Optional in der Liga, wenn \"--league\" angegeben wird.", "[--league] <Szenarioname¦Alias>");
addCommand("list", &CRSM::list, Clonk | IRC, User, "Listet alle definierten Aliase oder alle möglichen Szenarien und Ordner auf, bzw. alle Szenarien im Ordner oder Rundenordner.", "[Aliase¦Rundenordner[.c4f]]");
addCommand("clientlist", &CRSM::clientlist, Clonk | IRC, User, "Listet alle verbundenen Clients mit PC-Name und Chatnick auf.");
addCommand("help", &CRSM::help, Clonk | IRC, User, "Zeigt die Hilfe an.", "[long¦Befehlsname]", "Listet alle verfügbaren Befehle auf. Mit long werden alle verfügbaren Befehle mit Kurzbeschreibung aufgelistet.");
@@ -1100,8 +1169,6 @@ void CRSM::setupCmds()
addCommand("plrteam", &CRSM::passToClonk, Clonk | IRC, Admin, "Ändert das Team eines Spielers.", "<Spieler> <neues Team>", "Verschiebt <Spieler> in das <neue Team>.");
addCommand("pause", &CRSM::passToClonk, Clonk | IRC, Admin, "Pausiert das Spiel.");
addCommand("unpause", &CRSM::passToClonk, Clonk | IRC, Admin, "Setzt das pausierte Spiel fort.");
- addCommand("teamcolorson", &CRSM::passToClonk, Clonk | IRC, Admin, "Schaltet Teamfarben ein.");
- addCommand("teamcolorsoff", &CRSM::passToClonk, Clonk | IRC, Admin, "Schaltet Teamfarben aus.");
addCommand("observer", &CRSM::pcNamePassToClonk, Clonk | IRC, Admin, "Der angegebene Host muss zuschauen.", "<PC-Name¦Chatnick>");
addCommand("deactivate", &CRSM::pcNamePassToClonk, Clonk | IRC, Admin, "Deaktiviert den angegebenen Host.", "<PC-Name¦Chatnick>");
addCommand("activate", &CRSM::pcNamePassToClonk, Clonk | IRC, Admin, "Aktiviert den angegebenen Host.", "<PC-Name¦Chatnick>");
@@ -1113,10 +1180,11 @@ void CRSM::setupCmds()
addCommand("nodebug", &CRSM::passToClonk, Clonk | IRC, Admin, "Deaktiviert den Debug-Modus zwingend für alle.");
addCommand("autohost", &CRSM::autohost, Clonk | IRC, Moderator, "Deaktiviert den Debug-Modus zwingend für alle.");
addCommand("noautohost", &CRSM::autohost, Clonk | IRC, Moderator, "Deaktiviert den Debug-Modus zwingend für alle.");
+ addCommand("set", &CRSM::set, Clonk | IRC, Admin, "Setzt diverse Einstellungen entsprechend dem /set Befehl von Clonk.", "<maxplayer¦password¦faircrew¦teamcolors¦runtimejoin> [on¦off¦<Passwort>¦<Spieleranzahl>]");
addCommand("skip", &CRSM::skip, Clonk | IRC, Moderator, "Entfernt das nächste Szenario aus der Wunschliste.");
addCommand("next", &CRSM::next, Clonk | IRC, Moderator, "Versucht das aktuelle Szenario zu überspringen.");
- addCommand("kill", &CRSM::kill, IRC, Moderator, "Tötet den Clonk-Server, vorausgesetzt es läuft einer.", "Tötet den Clonk-Server, vorausgesetzt es läuft einer. Bitte nur verwenden wenn " CMD_SIGN "next nicht funktioniert.");
+ addCommand("kill", &CRSM::kill, IRC, Moderator, "Tötet den Clonk-Server, vorausgesetzt es läuft einer.", "", "Tötet den Clonk-Server, vorausgesetzt es läuft einer. Bitte nur verwenden wenn " CMD_SIGN "next nicht funktioniert.");
addCommand("clear", &CRSM::clear, Clonk | IRC, Moderator, "Löscht die Wunschliste.");
addCommand("aliaswishes", &CRSM::aliaswishes, IRC, Moderator, "Zum geführten Bearbeiten der Aliaswünsche.");
addCommand("newalias", &CRSM::newalias, IRC, Moderator, "Trägt <Alias> als Alias für <Szenario> ein.", "<Alias> = <Szenario>");
@@ -1161,7 +1229,12 @@ void CRSM::setIngameAdmin(const ClientInfo &client, const QString& newAdmin)
{
if(clients.contains(newAdmin))
{
- sessionAdmin = clients.value(newAdmin);
+ const ClientInfo& info = clients.value(newAdmin);
+ if(sessionAdmin == info)
+ {
+ respond(client, info.toString() + " ist bereits Rundenadmin.\n");
+ }
+ sessionAdmin = info;
}
else
{
@@ -1266,12 +1339,17 @@ CMD_FUNCTION_IMPL(admin)
return;
}
ClientInfo& interfaceAdmin = *interfaceAdminPtr;
- if(ircAdmin != ClientInfo() && userType < Admin)
+ if(args.isEmpty() && interfaceAdmin == client)
+ {
+ respond(client, "Du ist bereits Rundenadmin!\n");
+ return;
+ }
+ else if((ircAdmin != ClientInfo() || sessionAdmin != ClientInfo()) && userType < Admin)
{
respond(client, ircAdmin.toString() + (!ircAdmin.nick.isEmpty() && !sessionAdmin.nick.isEmpty() ? " und " : "") + sessionAdmin.toString() + " ist bereits Rundenadmin!\n");
return;
}
- else if(args == "")
+ else if(args.isEmpty())
{
interfaceAdmin = client;
respond(client, client.toString() + " wurde als Rundenadmin eingetragen!\n");
@@ -1293,16 +1371,28 @@ CMD_FUNCTION_IMPL(host)
respond(client, "Maximale Warteschlangenlänge von "+settings["UserListLength"]+" erreicht!\n");
else
{
- if(args == "")
- writeToServer("Bitte gib einen Szenarionamen an!\n");
+ if(args.trimmed().isEmpty())
+ respond(client, "Bitte gib einen Szenarionamen an!\n");
else
{
- if(scenExists(args))
+ ScenarioSettings scen(args, client);
+ QStringList argList = args.split(' ', QString::KeepEmptyParts);
+ if(argList.first().trimmed() == "--league")
{
- userlist << args;
- respond(client, "Szenario " + args + " wurde der Warteschlange hinzugefügt.\n");
- if(userlist.length() == 1 && session["userwish"] != "true" && session["running"] != "true")
+ argList.removeFirst();
+ scen.league = true;
+ scen.name = argList.join(' ');
+ }
+ if(scenExists(scen.name))
+ {
+ userlist << scen;
+ respond(client, "Szenario " + scen.name + " wurde der Warteschlange" + (scen.league ? " mit Liga" : "") + " hinzugefügt.\n");
+ if(userlist.length() == 1 && session["userwish"] != "true" && session["running"] != "true" && session["hosting"] == "true")
respond(client, "Überrede alle Spieler zu leaven und dein Wunsch wird sofort gehostet ;-)\n");
+ else if(session["hosting"] != "true")
+ {
+ nextScen();
+ }
}
else
{
@@ -1373,13 +1463,15 @@ CMD_FUNCTION_IMPL(skip)
CMD_FUNCTION_IMPL(next)
{
- skipCurrent();
- respond(client, "Versuche zu überspringen...\n");
+ if(skipCurrent())
+ {
+ respond(client, "Versuche zu überspringen...\n");
+ }
}
CMD_FUNCTION_IMPL(kill)
{
- serverprocess->kill();
+ processManager->kill();
respond(client, "Clonk-Server wurde gekillt.\n");
}
@@ -1534,6 +1626,56 @@ CMD_FUNCTION_IMPL(clientlist)
respond(client, response + "\n");
}
+CMD_FUNCTION_IMPL(set)
+{
+ QString what = args.left(args.indexOf(QRegExp("\\s"))).trimmed();
+ QString newArgs = args.right(args.length() - args.indexOf(QRegExp("\\s"))).trimmed();
+
+ if(what == "teamcolors" || what == "runtimejoin" || what == "faircrew")
+ {
+ if(newArgs != "on" && newArgs != "off")
+ {
+ respond(client, what + " kann nur auf on oder off gesetzt werden.\n");
+ }
+ else
+ {
+ writeToServer("/set " + what + " " + newArgs + "\n");
+ }
+ }
+ else if(what == "maxplayer")
+ {
+ bool ok;
+ int max = newArgs.toInt(&ok);
+ if(!ok)
+ {
+ respond(client, "maxplayer muss eine Zahl sein!\n");
+ }
+ else
+ {
+ writeToServer("/set maxplayer " + QString::number(max) + "\n");
+ }
+ }
+ else if(what == "password")
+ {
+ writeToServer("/set password " + newArgs + "\n");
+ }
+ else if(what == "comment")
+ {
+ if(userType < Moderator)
+ {
+ rightsFailMessage(client, Moderator);
+ }
+ else
+ {
+ writeToServer("/set comment " + newArgs + "\n");
+ }
+ }
+ else
+ {
+ respond(client, "Unbekannte Option: \"" + what + "\"\n");
+ }
+}
+
IRC_CHECK_CALLBACK_IMPL(ircSetAdmin)
{
if(status <= 0)
@@ -1549,7 +1691,7 @@ IRC_CHECK_CALLBACK_IMPL(ircSetAdmin)
IRC_CHECK_CALLBACK_IMPL(ircModCmd)
{
- if(status == 3)
+ if(status == 3 && lists["IrcModerators"].contains(subject.nick))
{
ircMods.append(subject.nick);
QList<QPair<CmdFunctionRef, QString>> &fifo = ircModFifos[subject.nick];
@@ -1566,7 +1708,10 @@ IRC_CHECK_CALLBACK_IMPL(ircModCmd)
}
else
{
- rightsFailMessage(subject, ircModFifos[subject.nick].first().first.userType);
- ircModFifos.remove(subject.nick);
+ if(ircModFifos.contains(subject.nick))
+ {
+ rightsFailMessage(subject, ircModFifos[subject.nick].first().first.userType);
+ ircModFifos.remove(subject.nick);
+ }
}
}
diff --git a/crsm.hpp b/crsm.hpp
index de90241..06407e8 100644
--- a/crsm.hpp
+++ b/crsm.hpp
@@ -17,6 +17,7 @@
#include <QSignalMapper>
#include "CmdFunctionRef.hpp"
+#include "ProcessManager.hpp"
#define CONFIG_FILE_NAME "CrServerManager.conf"
#define CUR_SCEN_FILE_NAME "curscen.txt"
@@ -35,6 +36,16 @@
class CRSM;
typedef void (CRSM::*IrcCheckCallback)(const ClientInfo&, int, const ClientInfo&);
+class ScenarioSettings {
+public:
+ QString name;
+ bool league = false;
+ ClientInfo wishClient;
+
+ ScenarioSettings(const QString& name, bool league = false) : name(name), league(league) {}
+ ScenarioSettings(const QString& name, const ClientInfo& client, bool league = false) : name(name), league(league), wishClient(client) {}
+};
+
class CRSM : public QObject
{
private:
@@ -67,12 +78,13 @@ public:
explicit CRSM(QObject *parent = 0);
~CRSM();
void start();
+ bool isOk();
signals:
private slots:
void readServerOutput();
- void processError();
+ //void processError();
void readInput();
void nextScen();
void printAdditionalHelp();
@@ -82,9 +94,8 @@ private slots:
void greet(QString pcName);
private:
- QProcess *serverprocess;
QStringList scenlist;
- QStringList userlist;
+ QList<ScenarioSettings> userlist;
QStringList args;
QStringList ircModChecks;
QStringList ircMods;
@@ -115,8 +126,11 @@ private:
QStringList ircModIOList;
QString writtenToServer;
QMap<QString, CmdFunctionRef> cmds;
+ ProcessManager* processManager;
+
+ bool ok = false;
- void startScen(QString, QStringList);
+ void startScen(const ScenarioSettings& scen, QStringList);
void readConfig();
void readScenarios();
QMap<QString, QString> defaultSettings();
@@ -127,7 +141,7 @@ private:
QString printQueue();
void ircCheckModCmd(const QString &nick, CmdFunctionRef func, QString arg = "");
QString skipScen();
- void skipCurrent();
+ bool skipCurrent();
void writeToServer(const QString& message);
void writeConfig();
QString addAliasWish(const QString& param);
@@ -172,6 +186,7 @@ private:
CMD_FUNCTION(ircadmin);
CMD_FUNCTION(noadmin);
CMD_FUNCTION(clientlist);
+ CMD_FUNCTION(set);
IRC_CHECK_CALLBACK(ircSetAdmin);
IRC_CHECK_CALLBACK(ircModCmd);
diff --git a/main.cpp b/main.cpp
index 5eed945..d69a266 100644
--- a/main.cpp
+++ b/main.cpp
@@ -6,6 +6,8 @@ int main(int argc, char *argv[])
QCoreApplication a(argc, argv);
CRSM *CrServerManager=new CRSM(&a);
+ if(!CrServerManager->isOk())
+ return 1;
CrServerManager->start();
return a.exec();
}