Sat, 06 Jun 2015 23:06:14 +0300
Compilation tweaks
/* * 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; }