--- a/src/demo.cpp Sat Jun 06 23:06:14 2015 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,369 +0,0 @@ -/* - * ZCinema: Zandronum demo launcher - * Copyright (C) 2013-2015 Teemu Piippo - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <QFile> -#include <QDataStream> -#include <QMessageBox> -#include <QProcess> -#include "demo.h" -#include "misc.h" -#include "ui_demoprompt.h" -#include "prompts.h" -#include "config.h" -#include "version.h" - -// -// ------------------------------------------------------------------------------------------------- -// - -QString uncolorize (const QString& in) -{ - // TODO: Handle long-form colors like \c[Red] - QString out; - int skip = 0; - - for (QChar c : in) - { - if (skip-- > 0) - continue; - - if (c == QChar ('\034')) - { - skip = 1; - continue; - } - - out += c; - } - - return out; -} - -// -// ------------------------------------------------------------------------------------------------- -// - -static QString tr (const char* msg) -{ - return QObject::tr (msg); -} - -// -// ------------------------------------------------------------------------------------------------- -// - -static void error (QString msg) -{ - QMessageBox::critical (NULL, "Error", msg); -} - -// -// ------------------------------------------------------------------------------------------------- -// - -static ZandronumVersion findVersion (QString versionName) -{ - QList<QVariant> versions = Config::get ("versions").toList(); - - for (int i = 0; i < versions.size(); ++i) - { - if (not versions[i].canConvert<ZandronumVersion>()) - continue; - - ZandronumVersion version = versions[i].value<ZandronumVersion>(); - - if (version.name == versionName - or version.name + "M" == versionName - or version.name == versionName + "M") - { - return version; - } - } - - return ZandronumVersion(); -} - -// -// ------------------------------------------------------------------------------------------------- -// - -static QString findWAD (QString name) -{ - QStringList wadpaths = Config::get ("wadpaths").toStringList(); - - if (wadpaths.empty()) - { - error (tr ("No WAD paths configured!")); - - // Cannot just return an empty string here since that'd trigger another error prompt - skip - // ahead and exit. - exit (1); - } - - for (int i = 0; i < wadpaths.size(); ++i) - { - QString fullpath = QString ("%1/%2").arg (wadpaths[i]).arg (name); - QFile f (fullpath); - - if (f.exists()) - return fullpath; - } - - return ""; -} - -// -// ------------------------------------------------------------------------------------------------- -// - -QString readString (QDataStream& stream) -{ - QString out; - uint8 ch; - - for (stream >> ch; ch != 0; stream >> ch) - out += QChar (ch); - - return out; -} - -// -// ------------------------------------------------------------------------------------------------- -// - -struct UserInfo -{ - QString netname; - QString skin; - QString className; - uint32 color; - uint32 aimdist; - uint32 railcolor; - uint8 gender; - uint8 handicap; - uint8 unlagged; - uint8 respawnOnFire; - uint8 ticsPerUpdate; - uint8 connectionType; -}; - -struct DemoHeaders -{ - uint8 length; - uint8 version; - uint8 userInfo; - uint8 bodyStart; - uint8 wads; -}; - -int launchDemo (QString path) -{ - QFile f (path); - - if (not f.open (QIODevice::ReadOnly)) - { - error (tr ("Couldn't open '%1' for reading: %2").arg (path).arg (strerror (errno))); - return 1; - } - - QDataStream stream (&f); - stream.setByteOrder (QDataStream::LittleEndian); - - DemoHeaders headers; - uint32 length; - uint16 zanversionID, numWads; - uint32 longSink; - QString zanversion; - QStringList wads; - UserInfo userinfo; - - // Assume a release build if the build ID not supplied. The demo only got the "ZCLD" signature - // in the 1.1 release build, 1.1.1 had no testing binaries and the build ID is included in 1.2 - // onward. - BuildType buildID = ReleaseBuild; - - bool ready = false; - - // Check signature - { - uint32 demosignature; - stream >> demosignature; - - if (demosignature != makeByteID ('Z', 'C', 'L', 'D')) - { - error (tr ("'%1' is not a valid Zandronum demo file!").arg (path)); - return 1; - } - } - - stream >> headers.length; - stream >> length; - - // The remaining headers are variable and relative to the length header. - headers.version = headers.length + 1; - headers.userInfo = headers.length + 3, - headers.bodyStart = headers.length + 4; - headers.wads = headers.length + 10; - - // Read the demo header and get data - for (;;) - { - uint8 header; - stream >> header; - - if (header == headers.bodyStart) - { - ready = true; - break; - } - else if (header == headers.version) - { - stream >> zanversionID; - zanversion = readString (stream); - - if (not zanversion.startsWith ("1.1-") and not zanversion.startsWith ("1.1.1-")) - { - uint8 a; - stream >> a; - buildID = (BuildType) a; - } - - // The demo wads header accidentally changed in 1.3. :( - if (zanversion.left(1).toInt() >= 2 or zanversion.startsWith ("1.3")) - headers.wads = headers.length + 8; - - stream >> longSink; // rng seed - we don't need it - } - else if (header == headers.userInfo) - { - userinfo.netname = readString (stream); - stream >> userinfo.gender; - stream >> userinfo.color; - stream >> userinfo.aimdist; - userinfo.skin = readString (stream); - stream >> userinfo.railcolor; - stream >> userinfo.handicap; - stream >> userinfo.unlagged; - stream >> userinfo.respawnOnFire; - stream >> userinfo.ticsPerUpdate; - stream >> userinfo.connectionType; - userinfo.className = readString (stream); - } - else if (header == headers.wads) - { - QString sink; - stream >> numWads; - - for (uint8 i = 0; i < numWads; ++i) - { - QString wad = readString (stream); - wads << wad; - } - - // The demo has two checksum strings. We're not interested in them, though. - (sink = readString (stream)) = readString (stream); - } - else - { - error (tr ("Unknown header %1!\n").arg (int (header))); - return 1; - } - } - - if (not ready) - { - error (tr ("Incomplete demo header in '%s'!").arg (path)); - return 1; - } - - ZandronumVersion version = findVersion (zanversion); - - if (version.name.isNull()) - { - QDialog* prompt = new UnknownVersionPrompt (path, zanversion, (buildID == ReleaseBuild)); - - if (not prompt->exec()) - return 1; - } - - QString iwadpath; - QStringList pwadpaths; - - // Find the WADs - for (const QString& wad : wads) - { - QString path = findWAD (wad); - - // WAD names are case-sensitive under non-Windows and they can appear in uppercase - // so we need to test that too. - if (path.isEmpty()) - path = findWAD (wad.toUpper()); - - if (path.isEmpty()) - { - error (tr ("Couldn't find %1!").arg (wad)); - return 1; - } - - if (&wad == &wads.first()) - iwadpath = path; - else - pwadpaths << path; - } - - if (not Config::get ("noprompt").toBool()) - { - QString pwadtext; - - for (const QString& wad : wads) - { - if (&wad == &wads.first()) - continue; // skip the IWAD - - if (not pwadtext.isEmpty()) - pwadtext += "<br />"; - - pwadtext += wad; - } - - QDialog* dlg = new QDialog; - Ui_DemoPrompt ui; - ui.setupUi (dlg); - ui.demoNameLabel->setText (basename (path)); - ui.demoRecorder->setText (uncolorize (userinfo.netname)); - ui.versionLabel->setText (zanversion); - ui.iwadLabel->setText (wads[0]); - ui.pwadsLabel->setText (pwadtext); - dlg->setWindowTitle (versionSignature()); - - if (not dlg->exec()) - return 0; - } - - QStringList cmdlineList; - cmdlineList << "-playdemo" << path << "-iwad" << iwadpath; - - if (pwadpaths.size() > 0) - cmdlineList << "-file" << pwadpaths; - - // print ("Executing: %1 %2\n", binarypath, cmdlineList.join (" ")); - QProcess* proc = new QProcess; - proc->start (version.binaryPath, cmdlineList); - proc->waitForFinished (-1); - return 0; -}