diff options
| author | Markus Mittendrein <git@maxmitti.tk> | 2014-10-06 15:02:15 +0200 |
|---|---|---|
| committer | Markus Mittendrein <git@maxmitti.tk> | 2014-10-06 15:02:15 +0200 |
| commit | 3b58b5536935adff242928ed9f30e1c0262fbd7c (patch) | |
| tree | 62a2465f3cf45c13b6e46a56be3a6f44cd903d68 /crsm.cpp | |
| download | manager-3b58b5536935adff242928ed9f30e1c0262fbd7c.tar.gz manager-3b58b5536935adff242928ed9f30e1c0262fbd7c.zip | |
initial
Diffstat (limited to 'crsm.cpp')
| -rw-r--r-- | crsm.cpp | 649 |
1 files changed, 649 insertions, 0 deletions
diff --git a/crsm.cpp b/crsm.cpp new file mode 100644 index 0000000..004be22 --- /dev/null +++ b/crsm.cpp @@ -0,0 +1,649 @@ +#include "crsm.h" +#include <iostream> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <QThread> +#include <QTimer> + +#define CMD_SIGN "!" + +CRSM::CRSM(QObject *parent) : + QObject(parent) +{ + qout = new QTextStream(stdout,QIODevice::WriteOnly); + 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; + + readConfig(); + cleanUp(); + listC4Folders(); + readScenarios(); + + autoHost = settings["AutoHost"] == "true"; + + //QString fifopath(settings["ClonkDirectory"]+"Clonk.log"); + //mkfifo(fifopath.toUtf8(),0666); + + connect(serverprocess, SIGNAL(readyReadStandardOutput()), this, SLOT(readServerOutput())); + connect(serverprocess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(processError())); + connect(serverprocess, SIGNAL(finished(int)), this, SLOT(scenarioFinished())); + //int fp=open(fifopath.toUtf8(),O_RDONLY|O_NONBLOCK); + //logfile=new QFile(); + //logfile->open(fp,QIODevice::ReadOnly); + //QSocketNotifier *logNotifier = new QSocketNotifier(logfile->handle(),QSocketNotifier::Read,this); + QSocketNotifier *inNotifier = new QSocketNotifier(STDIN_FILENO,QSocketNotifier::Read,this); + connect(inNotifier, SIGNAL(activated(int)), this, SLOT(readInput())); + //connect(logNotifier,SIGNAL(activated(int)),this, SLOT(readLog())); + + QFile *reallog = new QFile(settings["ClonkDirectory"]+"CRSM.log"); + reallog->open(QIODevice::WriteOnly|QIODevice::Text); + logstream = new QTextStream(reallog); + + connection = new IrcConnection("irc.rbx.fr.euirc.net"); + connection->setUserName(settings["IrcNick"]); + connection->setNickName(settings["IrcNick"]); + connection->setRealName(settings["IrcRealName"]); + connection->sendCommand(IrcCommand::createJoin(settings["IrcChannel"])); + connection->setPassword(settings["IrcPassword"]); + //connection->sendCommand(IrcCommand::createMessage(settings["IrcChannel"], "Hi, kthxbye!")); + connection->open(); + connect(connection, SIGNAL(messageReceived(IrcMessage*)), this, SLOT(ircMessageReceived(IrcMessage*))); +} + +CRSM::~CRSM() +{ +} + +void CRSM::start() +{ + if(autoHost) + nextScen(); +} + +void CRSM::readServerOutput() +{ + QRegExp timeRemover("^>?\\s*\\[\\d\\d:\\d\\d:\\d\\d\\]\\s+(.*)$"); + //QString what(QTextCodec::codecForName("Windows-1250")->toUnicode(serverprocess->readAll())); + QString what(serverprocess->readAll()); + *qout << what.trimmed() << endl; + if(!timeRemover.exactMatch(what)) + return; + what=timeRemover.cap(1).trimmed(); + //*qout << what << endl; + QRegExp userexp("^<([^>]*)>\\s+(.*)"); + if(userexp.exactMatch(what)) + { + QString user = userexp.cap(1).trimmed(); + if(user!=settings["ServerNick"]) + { + QString msg = userexp.cap(2).trimmed(); + QRegExp commandExp("^\\" CMD_SIGN "([^ ]+)(\\s+(.*)\\s*)?$"); + if(commandExp.exactMatch(msg)) + { + QString command=commandExp.cap(1).trimmed(); + QString commandArgs=commandExp.cap(2).trimmed(); + if(command=="help") + serverprocess->write(CMD_SIGN"host <[Rundenordner.c4f/]Szenarioname.c4s> - Startet das gewaehlte Szenario, solange die Warteliste nicht zu gross ist.\n" + CMD_SIGN"queue - Zeigt die naechsten 3 Szenarien auf der Warteliste.\n" + "[Sachen in eckigen Klammern sind optional]\n" + "<Sachen in spitzen Klammern sind benoetigte Argumente>\n" + "Weitere Befehle folgen.\n"); + if(command=="host") + { + if(userlist.length()>=settings["UserListLength"].toInt()) + serverprocess->write(QString("Maximale Warteschlangenlänge von "+settings["UserListLength"]+" erreicht!\n").toLatin1()); + else + { + if(commandArgs=="") + serverprocess->write("Bitte gib einen Szenarionamen an!\n"); + else + { + //extractC4Folders(); + if(scenExists(commandArgs)) + { + userlist << commandArgs; + serverprocess->write(QString("Szenario "+commandArgs+" wurde der Warteschlange hinzugefügt.\n").toLatin1()); + if(userlist.length() == 1 && session["userwish"] != "true" && session["running"] != "true") + serverprocess->write(QString("Überrede alle Spieler zu leaven und dein Wunsch wird sofort gehostet ;-)\n").toLatin1()); + } + else + { + serverprocess->write(QString("Szenario "+commandArgs+" wurde nicht gefunden!\n").toLatin1()); + } + } + } + } + + if(command=="admin") + { + if(commandArgs!="") + { + if(session["admin"]==""||user==session["admin"] || lists["Moderators"].contains(user)) + { + session["admin"]=commandArgs.trimmed(); + serverprocess->write(QString("Spieler "+commandArgs+" wurde als Rundenadmin eingetragen.\n").toLatin1()); + } + else + { + serverprocess->write(QString(session["admin"]+" ist bereits Rundenadmin!\n").toLatin1()); + } + } + else + { + if(session["admin"]=="") + serverprocess->write(QString("Es gibt noch keinen Rundenadmin.\n").toLatin1()); + else + serverprocess->write(QString(session["admin"]+" ist Rundenadmin!\n").toLatin1()); + } + } + + if(command=="chatadmin") + { + if(commandArgs!="") + { + if(session["chatadmin"]==""||user==session["chatadmin"] || lists["Moderators"].contains(user)) + { + session["chatadmin"]=commandArgs.trimmed(); + serverprocess->write(QString("Spieler "+commandArgs+" wurde als Chat-Rundenadmin eingetragen.\n").toLatin1()); + } + else + { + serverprocess->write(QString(session["chatadmin"]+" ist bereits Chat-Rundenadmin!\n").toLatin1()); + } + } + else + { + if(session["chatadmin"]=="") + { + serverprocess->write(QString(user + " wurde als Chat-Rundenadmin eingetragen.\n").toLatin1()); + } + else + serverprocess->write(QString(session["admin"]+" ist Chat-Rundenadmin!\n").toLatin1()); + } + } + + if((command=="observer"||command=="deactivate"||command=="activate"||command=="kick"||command=="set"||command=="script"||command=="asyncctrl"||command=="centralctrl"||command=="decentralctrl"||command=="start"||command=="nodebug"||command=="stop"||command=="pause"||command=="unpause")&&(user==session["admin"] || user==session["chatadmin"] || lists["Moderators"].contains(user))) + { + if(!(command=="set"&&(commandArgs.simplified()=="faircrew on"||commandArgs.simplified()=="faircrew off")&&session["running"]!="true")) + serverprocess->write(QString("/"+command+" "+commandArgs+"\n").toLatin1()); + } + + if(command=="queue") + { + serverprocess->write("Folgende Szenarien befinden sich in der Warteschlange:\n"); + for(int i=0;i<settings["UserListLength"].toInt();i++) + { + /*if(userlist.length() + scenlist.length() < i) + break;*/ + serverprocess->write(QString("\t"+QString::number(i+1)+". "+(userlist.length()>i?userlist.at(i):scenlist.at((i-userlist.length() + current)%scenlist.length()) + " (auto)")+"\n").toLatin1()); + } + } + + if(command=="list") + { + serverprocess->write(listScenarios(commandArgs).toLatin1()); + } + } + if(msg.trimmed().toLower() == "hi" && !greeted.contains(user)) + { + serverprocess->write("Hallo " + user .toLatin1()+ "!\n"); + greeted.push_back(user); + } + } + } + + QRegExp joinExp("^Client (.+) (?:verbunden|connected)\\.\\s*$"); + joinExp.setMinimal(true); + if(joinExp.exactMatch(what)) + { + //waitinggreets << joinExp.cap(1); + ++clientcount; + } + + /*joinExp = QRegExp("^Client (.+) (?:aktiviert|activated)\\.\\s*$"); + joinExp.setMinimal(true); + if(joinExp.exactMatch(what)) + if(waitinggreets.contains(joinExp.cap(1))) + { + serverprocess->write(QString("Hallo "+joinExp.cap(1) +"!\n").toLatin1()); + waitinggreets.removeAll(joinExp.cap(1)); + }*/ + + QRegExp startExp("^Start!\\s*$"); + if(startExp.exactMatch(what)) + { + serverprocess->write(QString("/set maxplayer 0\n").toLatin1()); + session["running"]="true"; + } + + + QRegExp leaveExp("^Client (.+) (?:entfernt|removed)(.*)"); + //leaveExp.setMinimal(true); + if(leaveExp.exactMatch(what)) + { + serverprocess->write(QString(leaveExp.cap(1) +" ist ein L34V0R!\n").toLatin1()); + if(--clientcount == 0 && userlist.length() > 0 && session["userwish"] != "true") + { + serverprocess->closeWriteChannel(); + } + } +} + +void CRSM::processError() +{ + *qout << serverprocess->errorString() << endl; +} + +void CRSM::readInput() +{ + QString what(qin->readLine()); + if(what=="/exit") + { + serverprocess->closeWriteChannel(); + finish=true; + cleanUp(); + if(session["hosting"] != "true") + scenarioFinished(); + return; + } + if(what=="/exitafter") + { + finish=true; + return; + } + if(what=="/next") + { + serverprocess->closeWriteChannel(); + return; + } + + if(what=="/help") printAdditionalHelp(); + serverprocess->write(what.toLatin1()+"\n"); +} + +void CRSM::nextScen() +{ + session["hosting"] = "true"; + if(userlist.length()>0) + { + startScen(userlist.at(0), args); + userlist.removeFirst(); + session["userwish"] = "true"; + } + else + { + startScen(scenlist.at(current), args); + if(++current>=scenlist.length()) current = 0; + } +} + +void CRSM::printAdditionalHelp() +{ + *qout << "/exit stops the actual Clonk Server and exits the Server Manager.\n" + "/next stops the actual Clonk Server and starts a new one.\n" + "Clonk commands following..." << endl; +} + +void CRSM::readLog() +{ + QString temp(logfile->readLine().trimmed()); + if(temp!="") *logstream << temp << endl; +} + +void CRSM::scenarioFinished() +{ + if(finish) + { + connection->quit(settings["IrcQuitMessage"]); + connect(connection, SIGNAL(disconnected()), QCoreApplication::instance(), SLOT(quit())); + QTimer::singleShot(500, QCoreApplication::instance(), SLOT(quit())); + return; + } + session.clear(); + //waitinggreets.clear(); + greeted.clear(); + clientcount = 0; + if((autoHost || userlist.length() > 0) && !finish) + nextScen(); +} + +void CRSM::ircMessageReceived(IrcMessage *message) +{ + if(message->isOwn()) + return; + if(message->type() == IrcMessage::Private) + { + QString target = message->parameters().at(0); + QString mess = message->parameters().at(1).trimmed(); + if(mess.left(QString(CMD_SIGN).length()) == CMD_SIGN) + { + QStringList args = mess.right(mess.length() - QString(CMD_SIGN).length()).split(" ", QString::SkipEmptyParts); + QString cmd = args.first().trimmed(); + args.removeFirst(); + QString arg = args.join(" ").trimmed(); + if(cmd == "list") + { + /*foreach(const QString &line, listScenarios(arg).split('\n')) + connection->sendCommand(IrcCommand::createMessage(message->nick(), line));*/ + connection->sendCommand(IrcCommand::createMessage(target, "Szenarioliste ist zurzeit nur in der Lobby und im laufenden Spiel verfügbar.")); + } + else if(cmd == "autohost") + { + autoHost = true; + connection->sendCommand(IrcCommand::createMessage(target, "Automatisches Hosting aktiviert.")); + if(session["hosting"] != "true") + { + nextScen(); + } + } + else if(cmd == "noautohost") + { + autoHost = false; + connection->sendCommand(IrcCommand::createMessage(target, "Automatisches Hosting deaktiviert.")); + } + else if(cmd=="host") + { + if(userlist.length()>=settings["UserListLength"].toInt()) + connection->sendCommand(IrcCommand::createMessage(target, "Maximale Warteschlangenlänge von "+settings["UserListLength"]+" erreicht!")); + else + { + if(arg=="") + connection->sendCommand(IrcCommand::createMessage(target, "Bitte gib einen Szenarionamen an!")); + else + { + if(scenExists(arg)) + { + bool skipCurrent = false; + if(userlist.isEmpty() && session["userwish"] != "true") + skipCurrent = true; + userlist << arg; + connection->sendCommand(IrcCommand::createMessage(target, "Szenario " + arg + " wurde der Warteschlange hinzugefügt.")); + if(session["hosting"] != "true") + nextScen(); + else if(clientcount == 0 && skipCurrent) + { + serverprocess->closeWriteChannel(); + } + } + else + { + connection->sendCommand(IrcCommand::createMessage(target, "Szenario " + arg + " wurde nicht gefunden!")); + } + } + } + } + } + } + else if(message->type() == IrcMessage::Join) + { + connection->sendCommand(IrcCommand::createMessage(settings["IrcChannel"], "Hallo " + message->nick() + "!")); + } + else if(message->type() == IrcMessage::Kick) + { + if(message->parameters().at(1) == connection->nickName()) + { + connection->sendCommand(IrcCommand::createJoin(settings["IrcChannel"])); + } + } +} + +void CRSM::startScen(QString scen, QStringList argList) +{ + serverprocess->setWorkingDirectory(QDir::currentPath()); + serverprocess->start(settings["ServerExecutable"], argList << scen); +} + +void CRSM::readConfig() +{ + QFile config("CrServerManager.conf"); + if(!config.exists()||!config.open(QIODevice::ReadOnly | QIODevice::Text)) + { + config.open(QIODevice::WriteOnly | QIODevice::Text); + settings = defaultSettings(); + foreach(const QString &key, settings.keys()) + { + config.write(QString(key+" = "+settings.value(key)+"\n").toUtf8()); + } + } + else + { + QRegExp confExp("^([^=]+)=(.*)$"); + QRegExp confPlusExp("^([^=]+)\\+=(.*)$"); + for(QString line=config.readLine().trimmed(); !config.atEnd(); line=config.readLine().trimmed()) + { + if(confPlusExp.exactMatch(line)) + { + lists[confPlusExp.cap(1).trimmed()].push_back(confPlusExp.cap(2).trimmed()); + } + else if(confExp.exactMatch(line)) + { + settings.insert(confExp.cap(1).trimmed(),confExp.cap(2).trimmed()); + } + } + + *qout << "config:" << endl; + foreach(const QString &key, settings.keys()) + { + *qout << key << " = " << settings.value(key) << endl; + } + *qout << endl; + foreach(const QString &key, lists.keys()) + { + *qout << key << ":" << endl; + foreach(const QString &val, lists.value(key)) + { + *qout << "\t" << val << endl; + } + } + + args=settings["Arguments"].split(" "); + args << "/config:"+settings["ClonkConfig"]; + } + //settings["ClonkDirectory"]= QDir().absoluteFilePath(settings["ServerExecutable"]).replace(QRegExp("^(.*)"+QFileInfo(settings["ServerExecutable"]).fileName()+"$"),"\\1"); + settings["ClonkDirectory"] = QFileInfo(settings["ServerExecutable"]).absoluteDir().absolutePath()+QDir::separator(); + + QFile clonkconfig(settings["ClonkConfig"]); + if(!clonkconfig.exists()) + *qout << "WARNING: Clonk's config file is not existing!"; + else + { + clonkconfig.open(QFile::ReadOnly); + QRegExp nickexp("^\\s*Nick=\"(.*)\"\\s*$"); + foreach(const QString &line, QString(clonkconfig.readAll().trimmed()).split("\n")) + { + //*qout << line << endl; + if(nickexp.exactMatch(line)) + { + settings["ServerNick"]=nickexp.cap(1); + break; + } + } + *qout << "ClonkDirectory" << " = " << settings.value("ClonkDirectory") << endl; + *qout << "ServerNick" << " = " << settings.value("ServerNick") << endl; + } + *qout << endl; +} + +void CRSM::readScenarios() +{ + QFile scenfile("scenarios.lst"); + if(!scenfile.exists()) + { + *qout << "No scenarios.lst found!"; + scenfile.open(QFile::WriteOnly); + scenfile.write("Worlds.c4f/Goldmine.c4s"); + scenfile.close(); + } + scenfile.open(QFile::ReadOnly); + scenlist = QString(scenfile.readAll()).trimmed().split("\n",QString::SkipEmptyParts); + *qout << "Scenarios in list:" << endl; + foreach(const QString &scen, scenlist) + { + if(scenExists(scen)) + *qout << scen << endl; + else + *qout << "WARNING: Scenario " << scen << " not found!" << endl; + } + + *qout << endl; + + scenfile.close(); +} + +QMap<QString, QString> CRSM::defaultSettings() +{ + QMap<QString, QString> temp; + temp.insert("ServerExecutable","clonk-server"); + temp.insert("Arguments","/fullscreen /lobby:60 /nosignup"); + temp.insert("ClonkConfig","config"); + temp.insert("UserListLength","5"); + return temp; +} + +void CRSM::listC4Folders() +{ + /*// *qout << "Executable Setting: " << settings["ServerExecutable"] << endl; + // *qout << "Path: " << clonkdir << endl; + QDirIterator it(settings["ClonkDirectory"], QDirIterator::FollowSymlinks | QDirIterator::Subdirectories); + bool extracting=false; + for(;it.hasNext();it.next()) + { + if(it.fileInfo().suffix()=="c4f"&&!it.fileInfo().isDir()&&!it.fileInfo().absoluteFilePath().contains(settings["ClonkDirectory"]+"Network/")) + { + if(!extracting) + { + extracting=true; + *qout << endl << "Extracting scenario folders for hosting through Lobby..." << endl; + } + *qout << it.fileInfo().absoluteFilePath().replace(settings["ClonkDirectory"],"") << "..." << endl; + QProcess c4group(this); + QStringList c4gargs; + c4gargs << it.fileInfo().absoluteFilePath() << "-u"; + c4group.start(settings["ClonkDirectory"]+"c4group",c4gargs); + c4group.waitForFinished(); + } + } + if(extracting) *qout << endl;*/ //Old extracting is now replaced by listing the scenarios with c4group + *qout << "Listing Contents of C4Folders..."; + QDirIterator it(settings["ClonkDirectory"], QDirIterator::FollowSymlinks); + for(;it.hasNext();it.next()) + { + if((it.fileInfo().suffix() == "c4f" || (it.fileInfo().isDir() && !QDir(it.fileInfo().absoluteFilePath()).entryList(QStringList() << "*.c4f" << "*.c4s").isEmpty())) && it.fileName() != "." && it.fileName() != ".." && !lists["IgnoreFolders"].contains(it.fileInfo().baseName())) + { +#ifdef Q_OS_LINUX64 + QString executable = "c4group64"; +#else + QString executable = "c4group"; +#endif + QProcess c4group; + c4group.start(settings["ClonkDirectory"]+executable, QStringList() << it.filePath() << "-l", QProcess::ReadOnly); + c4group.waitForFinished(); + c4group.readLine(); + QRegExp finishExp("^\\d+ Entries, \\d+ Bytes$"); + QRegExp entryExp("^(.*\\.c4s)\\s+\\d+ Bytes\\s.*$"); + QFile listFile(it.filePath()+".lst"); + listFile.open(QFile::WriteOnly); + QString line; + while(!c4group.atEnd()) + { + line = c4group.readLine().trimmed(); + if(line.isEmpty()) + continue; + if(finishExp.exactMatch(line)) + break; + if(entryExp.exactMatch(line)) + listFile.write(entryExp.cap(1).toUtf8() + '\n'); + } + listFile.close(); + } + } + *qout << QString(3, '\b') << ": Finished" << endl; +} + +void CRSM::cleanUp() +{ + *qout << endl << "Cleaning up Clonk Folder..." << endl; + QDirIterator it(settings["ClonkDirectory"]+"Network/", QDirIterator::FollowSymlinks | QDirIterator::Subdirectories); + for(;it.hasNext();it.next()) + if(it.fileInfo().exists()) QFile(it.fileInfo().absoluteFilePath()).remove(); + /*QDirIterator lstIt(settings["ClonkDirectory"], QStringList() << "*.lst", QDir::NoFilter, QDirIterator::FollowSymlinks); + for(;lstIt.hasNext();lstIt.next()) + if(!lists["IgnoreFolders"].contains(lstIt.fileInfo().baseName())) + QFile(lstIt.fileInfo().absoluteFilePath()).remove();*/ + + *qout << endl; +} + +bool CRSM::scenExists(QString filePath) +{ + bool exists = QFile(settings["ClonkDirectory"]+filePath).exists(); + if(!exists) + { + QStringList split = filePath.split('/'); + if(split.length() == 2) + { + if(split.first().right(4) == ".c4f") + { + QFile lstFile(settings["ClonkDirectory"] + split.first() + ".lst"); + if(lstFile.exists()) + { + lstFile.open(QFile::ReadOnly); + while(!lstFile.atEnd()) + { + QString line = lstFile.readLine().trimmed(); + if(line == split.last()) + { + exists = true; + break; + } + } + } + lstFile.close(); + } + } + } + return exists; +} + +QString CRSM::listScenarios(QString commandArgs) +{ + QString ret; + if(commandArgs.isEmpty()) + { + ret += "Folgende Szenarien stehen zur Auswahl:\n"; + QDirIterator it(settings["ClonkDirectory"], QDirIterator::FollowSymlinks); + for(;it.hasNext();it.next()) + { + if(it.fileInfo().suffix()=="c4s"&&!it.fileInfo().absoluteFilePath().contains(settings["ClonkDirectory"]+"Network/")) + ret += QString(" "+it.fileInfo().absoluteFilePath().replace(settings["ClonkDirectory"],"")+"\n"); + } + ret += "-----------------------------------------------------------------\nFolgende Ordner stehen zur Auswahl:\n"; + QDirIterator folderIt(settings["ClonkDirectory"], QDirIterator::FollowSymlinks); + for(;folderIt.hasNext();folderIt.next()) + { + if(folderIt.fileInfo().suffix()=="lst"&&!folderIt.fileInfo().absoluteFilePath().contains(settings["ClonkDirectory"]+"Network/") && !lists["IgnoreFolders"].contains(folderIt.fileInfo().baseName())) + ret += QString(" "+folderIt.fileInfo().absoluteFilePath().left(folderIt.fileInfo().absoluteFilePath().length() - 4).replace(settings["ClonkDirectory"],"")+"\n"); + } + } + else + { + QFile file(settings["ClonkDirectory"] + commandArgs + ".lst"); + if(file.exists()) + { + ret += "Der Ordner \"" + commandArgs + QString("\" enthält folgende Szenarien:\n"); + file.open(QFile::ReadOnly); + while(!file.atEnd()) + ret += " " + QString::fromUtf8(file.readLine()).toLatin1().trimmed() + "\n"; + } + else + ret += "Der Ordner \"" + commandArgs + "\" wurde nicht gefunden!\n"; + } + return ret; +} |
