#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "CmdFunctionRef.hpp" #include "ProcessManager.hpp" #include "CRSMConfig.hpp" #include "CRSMSession.hpp" #include "CRSMStats.hpp" #include "CRSMPackCompatibility.hpp" #include "CRSMLogging.hpp" #include "ClonkInterface.hpp" #include "PatchedClonkParser.hpp" #include "PatchedClonkControl.hpp" #include "IrcIngameChat.hpp" #define CONFIG_FILE_NAME "CrServerManager.conf" #define SESSION_FILE_NAME "CrServerManager.session" #define CUR_SCEN_FILE_NAME "curscen.txt" #define LAST_SCEN_FILE_NAME "lastscen.txt" #define SCOREBOARD_FILE_NAME Config.Auto.Volatile.Clonk.Directory + "scoreboard.html" #define IRC_CHECK_CALLBACK(name) void name(const ClientInfo& requester, int status, const ClientInfo& subject) #define IRC_CHECK_CALLBACK_IMPL(name) void CRSM::name(const ClientInfo& requester, int status, const ClientInfo& subject) { (void)requester; (void)status; (void)subject; #ifdef Q_OS_LINUX64 #define C4GROUP_EXECUTABLE "c4group64" #else #define C4GROUP_EXECUTABLE "c4group" #endif class CRSM; using IrcCheckCallback = void (CRSM::*)(const ClientInfo&, int, const ClientInfo&); template<> class ConfigValue : public ConfigValueBase { ScenarioSettings& config; public: ConfigValue(ScenarioSettings& config) : config(config) { } void setValue(const QString& val) { QStringList parts = Util::splitEscaped(val, ':', '|'); if(parts.length() != 3) { throw ConfigException("Cannot read corrupt ScenarioSettings"); } else { config.name = ConfigValueBase::getValue(parts.first()); parts.removeFirst(); config.league = ConfigValueBase::getValue(parts.first()); parts.removeFirst(); config.randomLeague = false; config.wishClient = ConfigValueBase::getValue(parts.first()); } } QString value() { return Util::joinEscape({ConfigValueBase::getStringValue(config.name), ConfigValueBase::getStringValue(config.league), ConfigValueBase::getStringValue(config.wishClient)}, ':', '|'); } }; class CRSM : public QObject, public ClonkOutputInterface, public ClonkControllerInterface { friend CRSMSession::CRSMSession(CRSM *crsm); private: enum IrcModOperations { ModCheck, ModInfo, SkipScen, ClearUserList, SkipCurrentScen, Autohost, NoAutohost, ModHelp, Kill, IO, CheckOnly, NewAlias, AliasWishes, IngameChat }; enum RespondType { Normal, Notice, Private, PrivateNotice }; Q_OBJECT public: explicit CRSM(QObject *parent = 0); ~CRSM(); void start(); bool isOk(); bool lobbyCountdown(unsigned int seconds); bool lobbyCountdownAborted(); bool watchdog(const QString &id); bool clientMessage(ClientInfo &client, const QString &message, ClonkOutputInterface::MessageType type, const QTime& time); bool clientConnected(const ClientInfo &client); bool clientRemoved(const ClientInfo &client, const QString& reason); bool gameLoading(); bool gameStarted(); bool masterserverError(const QString &msg); bool raw(const QString& line); bool rawTimed(const QString& line, const QTime& time); bool playerRemoved(const QString &name); void sendIrcMessage(const QString& message, const QString& target, bool action, bool notice, bool noticeOrDCC = false); signals: private slots: void readServerOutput(); void nextScen(); void scenarioFinished(); void ircMessageReceived(IrcMessage* message); void ircConnected(); void greet(QString pcName); void newManagementConnection(); void newManagementData(); void managementConnectionDisconnected(); void dccChatRequest(const ClientInfo &client, QString extraArgs = ""); void newDCCConnection(); void newDCCData(); void disconnectedDCCConnection(); void updateNextAutoScens(); void reconnectIrc(); void enableAutoHosting(); void afkAdminTimeout(); void watchdog(); private: CRSMConfig Config; CRSMSession Session; CRSMStats Stats; CRSMPackCompatibility Packs; CRSMLogging Log; PatchedClonkParser parser; PatchedClonkControl control; IrcIngameChat ingameChat; QList userlist; QList autolist; QList nextAutoScens; QStringList args; QStringList ircModChecks; QStringList ircMods; QMap>> ircStatusFifos; QMap>> ircModFifos; QMap ircSayQueryFifos; QString aliasWishEditor = ""; QString currentAliasWish = ""; int current; bool finish; IrcConnection *connection = 0; bool autoHost = true; QSignalMapper greetMapper; QFile *logfile; QTextCodec *codec; QStringList ircModIOList; QList ircModWatchList; QString writtenToServer; QMap cmds; QStringList cmdGroups; ProcessManager* processManager = nullptr; QTcpServer managementServer; QMap managementConnections; QTimer gameRegisterFailTimer; QTimer afkAdminTimer; QTimer watchDogTimer; QString watchDogString; bool ok = false; bool hostingIsErrorDeactivated = false; struct DCCConnection { ClientInfo client; QTcpSocket* socket; }; QMap dccSocketConnections; QMap dccNickConnections; QMap dccConnectionIdentifiers; QTcpServer dccServer; void startScen(const ScenarioSettings& scen, QStringList); void readConfig(); void readScenarios(); void listC4Folders(); void cleanUp(); QString caseInsensitive(QString name, QString dir = "", QString trySuffix = ""); QString scenPath(QString scenName); QString listScenarios(QString commandArgs); QString printQueue(); void ircCheckModCmd(const QString &nick, CmdFunctionRef func, QString arg = ""); QString skipScen(int pos); bool skipCurrent(); void writeToServer(const QString& message); void writeConfig(); QString addAliasWish(const QString& param); void informModsAboutAliasWish(); void editAliasWishes(); void editAliasWishes(const QString &message); void stopAliasWishEditing(); QString ircActivateIngameChat(bool activated = true); QStringList listC4Folder(const QString &path); void ircSetIngameChannelTopic(); void setSessionState(CRSMSession::SessionState state); void unRegisterIngameChat(); void addCommand(const QString& name, CmdFunction func, int interfaces = Clonk | IRC, UserType userType = User, const QString& shortDescription = "", const QString &argList = "", const QString &longDescription = ""); inline void addCommandGroup(const QString& name, int interfaces = Clonk | IRC, UserType userType = User, const QString& shortDescription = "", const QString &longDescription = "", CmdFunction defaultFunc = &CRSM::groupinfo); bool cmdExists(const QString& name, ClientInterface interface); QStringList guessCmd(const QString& name, ClientInterface interface); CmdFunctionRef* findCommand(const QString& cmd, ClientInterface interface, QString& args, QStringList& corrections); CmdFunctionRef* findCommand(QStringList &&cmd, ClientInterface interface, QString& args, QStringList& corrections); QString cmdErrorText(const QString& command, const ClientInfo& client, bool& ret); bool cmd(const QString &cmd, const ClientInfo& client, QStringList& corrections); void rightsFailMessage(const ClientInfo& info, UserType minUserType); UserType clientUserType(const ClientInfo& client); void setupCmds(); void respond(const ClientInfo& client, const QString& message, const RespondType type = Normal, bool allowDCCNotice = false); void ircCheckUserStatus(const ClientInfo& requester, const ClientInfo& subject, IrcCheckCallback callback); void setIngameAdmin(const ClientInfo &client, const QString& newAdmin); QFile outputBuffer; void out(const QString& text); void replayOutputBuffer(QTcpSocket *socket, bool clear = true); void announceInfo(const QString& info, bool useOutgameChannel = true); bool scenAllowed(const ScenarioSettings& scen, const ClientInfo& client, UserType userType); void kick(const ClientInfo& client, const QString& reason = ""); void prepareAndConnectIrc(); ClientInfo& getClientInfo(const QString& pcName, int cuid, const QString& user); ClientInfo* parseClientInfo(QString& message); QString findClientByName(ClientInfo& info, const QString& name); void exit(); void applyConfig(); QString scenarioFileName(QString name); CmdResult callCommand(const CmdFunctionRef& func, const QString& args, const ClientInfo& client, UserType userType); void writeFiles(bool writeSession = false, bool writeNoConfig = false); void checkActivity(ClientInfo& client); int findWishFromUser(const ClientInfo& client); QString getCommand(const QString& message); bool isChannelName(const QString& name); void removeCommandSuffixes(QString& command); void substituteCommandAlias(QString& command); QString clientModName(const ClientInfo& client); GreetingSetting::Mode greetingSetting(const ClientInfo& client); void handleIrcMessage(const ClientInfo& client, QString message, const QString& target, bool privateMessage, bool action, bool own = false); CMD_FUNCTION(help); CMD_FUNCTION(passToClonk); CMD_FUNCTION(passToClonkGrouped); CMD_FUNCTION(passToClonkOnOff); CMD_FUNCTION(passToClonkNumeric); CMD_FUNCTION(passToClonkNumericOrEmpty); CMD_FUNCTION(afkAdmin); CMD_FUNCTION(admin); CMD_FUNCTION(getAdmin); CMD_FUNCTION(host); CMD_FUNCTION(list); CMD_FUNCTION(queue); CMD_FUNCTION(aliaswish); CMD_FUNCTION(ircchat); CMD_FUNCTION(autohost); CMD_FUNCTION(skip); CMD_FUNCTION(next); CMD_FUNCTION(kill); CMD_FUNCTION(clear); CMD_FUNCTION(aliaswishes); CMD_FUNCTION(newalias); CMD_FUNCTION(deletealias); CMD_FUNCTION(modinfo); CMD_FUNCTION(io); CMD_FUNCTION(passToClonkPcName); CMD_FUNCTION(passToClonkPcNameGrouped); CMD_FUNCTION(passToClonkCtrlMode); CMD_FUNCTION(ingameadmin); CMD_FUNCTION(ircadmin); CMD_FUNCTION(noadmin); CMD_FUNCTION(clientlist); CMD_FUNCTION(setRaw); CMD_FUNCTION(nodebug); CMD_FUNCTION(join); CMD_FUNCTION(leave); CMD_FUNCTION(exit); CMD_FUNCTION(exitDetach); CMD_FUNCTION(exitUpdate); CMD_FUNCTION(exitAfter); CMD_FUNCTION(reload); CMD_FUNCTION(saveConfig); CMD_FUNCTION(reconnectIrc); CMD_FUNCTION(groupinfo); CMD_FUNCTION(grouphelp); CMD_FUNCTION(relist); CMD_FUNCTION(getConfigValue); CMD_FUNCTION(setConfigValue); CMD_FUNCTION(ircSay); CMD_FUNCTION(ircWatch); CMD_FUNCTION(ircRaw); CMD_FUNCTION(packsList); CMD_FUNCTION(packsDirectory); CMD_FUNCTION(packsVersionsAdd); CMD_FUNCTION(packsVersionsDelete); CMD_FUNCTION(packsVersionsDefault); CMD_FUNCTION(packsScenariosAdd); CMD_FUNCTION(packsScenariosDelete); CMD_FUNCTION(packsScenariosList); CMD_FUNCTION(packsScenOptionsGet); CMD_FUNCTION(packsScenOptionsSet); CMD_FUNCTION(dccConnect); CMD_FUNCTION(dccDisconnect); CMD_FUNCTION(dccIdentify); IRC_CHECK_CALLBACK(ircSetAdmin); IRC_CHECK_CALLBACK(ircModCmd); IRC_CHECK_CALLBACK(ircSayQuery); };