src/demo.cpp

changeset 38
db677d321cf4
parent 37
c82a86ea87be
child 39
2c368cf5cc19
equal deleted inserted replaced
37:c82a86ea87be 38:db677d321cf4
72 72
73 // 73 //
74 // ------------------------------------------------------------------------------------------------- 74 // -------------------------------------------------------------------------------------------------
75 // 75 //
76 76
77 static bool isKnownVersion (QString ver) 77 static ZandronumVersion findVersion (QString versionName)
78 { 78 {
79 for (const QVariant& it : getVersions()) 79 for (const QVariant& it : getVersions())
80 { 80 {
81 if (it.toString() == ver || it.toString() + 'M' == ver) 81 ZandronumVersion version = it.value<ZandronumVersion>();
82 return true; 82
83 } 83 if (version.name == versionName
84 84 or version.name + "M" == versionName
85 return false; 85 or version.name == versionName + "M")
86 {
87 return version;
88 }
89 }
90
91 return ZandronumVersion();
86 } 92 }
87 93
88 // 94 //
89 // ------------------------------------------------------------------------------------------------- 95 // -------------------------------------------------------------------------------------------------
90 // 96 //
147 uint8 respawnOnFire; 153 uint8 respawnOnFire;
148 uint8 ticsPerUpdate; 154 uint8 ticsPerUpdate;
149 uint8 connectionType; 155 uint8 connectionType;
150 }; 156 };
151 157
158 struct DemoHeaders
159 {
160 uint8 length;
161 uint8 version;
162 uint8 userInfo;
163 uint8 bodyStart;
164 uint8 wads;
165 };
166
152 int launchDemo (QString path) 167 int launchDemo (QString path)
153 { 168 {
154 QFile f (path); 169 QFile f (path);
155 170
156 if (not f.open (QIODevice::ReadOnly)) 171 if (not f.open (QIODevice::ReadOnly))
159 return 1; 174 return 1;
160 } 175 }
161 176
162 QDataStream stream (&f); 177 QDataStream stream (&f);
163 stream.setByteOrder (QDataStream::LittleEndian); 178 stream.setByteOrder (QDataStream::LittleEndian);
164 179
165 uint8 offset; 180 DemoHeaders headers;
166 uint32 length; 181 uint32 length;
167 uint16 zanversionID, numWads; 182 uint16 zanversionID, numWads;
168 uint32 longSink; 183 uint32 longSink;
169 QString zanversion; 184 QString zanversion;
170 QStringList wads; 185 QStringList wads;
186 { 201 {
187 error (tr ("'%1' is not a valid Zandronum demo file!").arg (path)); 202 error (tr ("'%1' is not a valid Zandronum demo file!").arg (path));
188 return 1; 203 return 1;
189 } 204 }
190 } 205 }
191 206
192 // Zandronum stores CLD_DEMOLENGTH after the signature. This is also the 207 stream >> headers.length
193 // first demo enumerator, so we can determine the offset (which is variable!)
194 // from this byte
195 stream >> offset
196 >> length; 208 >> length;
209
210 // The remaining headers are variable and relative to the length header.
211 headers.version = headers.length + 1;
212 headers.userInfo = headers.length + 3,
213 headers.bodyStart = headers.length + 4;
214 headers.wads = headers.length + 10;
197 215
198 // Read the demo header and get data 216 // Read the demo header and get data
199 for (;;) 217 for (;;)
200 { 218 {
201 uint8 header; 219 uint8 header;
202 stream >> header; 220 stream >> header;
203 221
204 if (header == DemoBodyStart + offset) 222 if (header == headers.bodyStart)
205 { 223 {
206 ready = true; 224 ready = true;
207 break; 225 break;
208 } 226 }
209 else if (header == DemoVersion + offset) 227 else if (header == headers.version)
210 { 228 {
211 stream >> zanversionID; 229 stream >> zanversionID;
212 zanversion = readString (stream); 230 zanversion = readString (stream);
213 231
214 if (not zanversion.startsWith ("1.1-") and not zanversion.startsWith ("1.1.1-")) 232 if (not zanversion.startsWith ("1.1-") and not zanversion.startsWith ("1.1.1-"))
216 uint8 a; 234 uint8 a;
217 stream >> a; 235 stream >> a;
218 buildID = (BuildType) a; 236 buildID = (BuildType) a;
219 } 237 }
220 238
239 // The demo wads header accidentally changed in 1.3. :(
240 if (zanversion.left(1).toInt() >= 2 or zanversion.startsWith ("1.3"))
241 headers.wads = headers.length + 8;
242
221 stream >> longSink; // rng seed - we don't need it 243 stream >> longSink; // rng seed - we don't need it
222 } 244 }
223 else if (header == DemoUserInfo + offset) 245 else if (header == headers.userInfo)
224 { 246 {
225 userinfo.netname = readString (stream); 247 userinfo.netname = readString (stream);
226 stream >> userinfo.gender; 248 stream >> userinfo.gender;
227 stream >> userinfo.color; 249 stream >> userinfo.color;
228 stream >> userinfo.aimdist; 250 stream >> userinfo.aimdist;
233 stream >> userinfo.respawnOnFire; 255 stream >> userinfo.respawnOnFire;
234 stream >> userinfo.ticsPerUpdate; 256 stream >> userinfo.ticsPerUpdate;
235 stream >> userinfo.connectionType; 257 stream >> userinfo.connectionType;
236 userinfo.className = readString (stream); 258 userinfo.className = readString (stream);
237 } 259 }
238 else if (header == DemoWads + offset) 260 else if (header == headers.wads)
239 { 261 {
240 QString sink; 262 QString sink;
241 stream >> numWads; 263 stream >> numWads;
242 264
243 for (uint8 i = 0; i < numWads; ++i) { 265 for (uint8 i = 0; i < numWads; ++i)
266 {
244 QString wad = readString (stream); 267 QString wad = readString (stream);
245 wads << wad; 268 wads << wad;
246 } 269 }
247 270
248 // The demo has two checksum strings. We're not interested 271 // The demo has two checksum strings. We're not interested in them, though.
249 // in them though. Down the sink they go... 272 (sink = readString (stream)) = readString (stream);
250 for (int i = 0; i < 2; ++i)
251 sink = readString (stream);
252 } 273 }
253 else 274 else
254 { 275 {
255 error (tr ("Unknown header %1!\n").arg (int (header))); 276 error (tr ("Unknown header %1!\n").arg (int (header)));
256 return 1; 277 return 1;
260 if (not ready) 281 if (not ready)
261 { 282 {
262 error (tr ("Incomplete demo header in '%s'!").arg (path)); 283 error (tr ("Incomplete demo header in '%s'!").arg (path));
263 return 1; 284 return 1;
264 } 285 }
265 286
266 if (not isKnownVersion (zanversion)) 287 ZandronumVersion version = findVersion (zanversion);
288
289 if (version.name.isNull())
267 { 290 {
268 QDialog* prompt = new UnknownVersionPrompt (path, zanversion, (buildID == ReleaseBuild)); 291 QDialog* prompt = new UnknownVersionPrompt (path, zanversion, (buildID == ReleaseBuild));
269 292
270 if (not prompt->exec()) 293 if (not prompt->exec())
271 return 1; 294 return 1;
272 }
273
274 QString binarypath = Config::get ("binarypaths").toMap()[zanversion].toString();
275
276 if (binarypath.isEmpty())
277 {
278 error (tr ("No binary path specified for Zandronum version %1!").arg (zanversion));
279 return 1;
280 } 295 }
281 296
282 QString iwadpath; 297 QString iwadpath;
283 QStringList pwadpaths; 298 QStringList pwadpaths;
284 299
339 if (pwadpaths.size() > 0) 354 if (pwadpaths.size() > 0)
340 cmdlineList << "-file" << pwadpaths; 355 cmdlineList << "-file" << pwadpaths;
341 356
342 // print ("Executing: %1 %2\n", binarypath, cmdlineList.join (" ")); 357 // print ("Executing: %1 %2\n", binarypath, cmdlineList.join (" "));
343 QProcess* proc = new QProcess; 358 QProcess* proc = new QProcess;
344 proc->start (binarypath, cmdlineList); 359 proc->start (version.binaryPath, cmdlineList);
345 proc->waitForFinished (-1); 360 proc->waitForFinished (-1);
346 return 0; 361 return 0;
347 } 362 }

mercurial