diff options
| author | Markus Mittendrein <git@maxmitti.tk> | 2015-03-18 17:38:51 +0100 |
|---|---|---|
| committer | Markus Mittendrein <git@maxmitti.tk> | 2015-03-18 17:38:51 +0100 |
| commit | 8983d3b38421843db67a05edee180028959c1b51 (patch) | |
| tree | 904305965e9ba3baa27680d5d8b2a7b8dbea213e | |
| parent | fbe3c5fbe1327fd81e2eb8fe30a75c4cf5d7b35c (diff) | |
| download | manager-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.pro | 6 | ||||
| -rw-r--r-- | ProcessManager.cpp | 245 | ||||
| -rw-r--r-- | ProcessManager.hpp | 75 | ||||
| -rw-r--r-- | crsm.cpp | 255 | ||||
| -rw-r--r-- | crsm.hpp | 25 | ||||
| -rw-r--r-- | main.cpp | 2 |
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 @@ -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); + } } } @@ -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); @@ -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(); } |
