1 /* bzflag
2 * Copyright (c) 1993-2021 Tim Riker
3 *
4 * This package is free software; you can redistribute it and/or
5 * modify it under the terms of the license found in the file
6 * named COPYING that should have accompanied this file.
7 *
8 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
9 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
10 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
11 */
12
13 // get our interface
14 #include "bzflag.h"
15
16 /* system headers */
17 #include <assert.h>
18 #include <ctype.h>
19 #include <fstream>
20 #include <stdarg.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <string>
25 #include <sys/types.h>
26 #include <time.h>
27 #include <vector>
28 #if defined(_WIN32)
29 # include <shlobj.h>
30 # include <sys/types.h>
31 # include <sys/stat.h>
32 # include <direct.h>
33 #else
34 # include <pwd.h>
35 # include <dirent.h>
36 #endif /* defined(_WIN32) */
37
38 /* common headers */
39 #include "Address.h"
40 #include "AresHandler.h"
41 #include "BZDBCache.h"
42 #include "BZDBLocal.h"
43 #include "BundleMgr.h"
44 #include "BzfMedia.h"
45 #include "BzfVisual.h"
46 #include "BzfWindow.h"
47 #include "CommandManager.h"
48 #include "CommandsStandard.h"
49 #include "ConfigFileManager.h"
50 #include "DirectoryNames.h"
51 #include "ErrorHandler.h"
52 #include "FileManager.h"
53 #include "FontManager.h"
54 #include "GUIOptionsMenu.h"
55 #include "KeyManager.h"
56 #include "OSFile.h"
57 #include "OpenGLGState.h"
58 #include "PlatformFactory.h"
59 #include "Protocol.h"
60 #include "ServerListCache.h"
61 #include "StateDatabase.h"
62 #include "Team.h"
63 #include "TextUtils.h"
64 #include "TextureManager.h"
65 #include "WordFilter.h"
66 #include "World.h"
67 #include "bzfSDL.h"
68 #include "bzfgl.h"
69 #include "bzfio.h"
70
71 /* local headers */
72 #include "ActionBinding.h"
73 #include "ServerStartMenu.h"
74 #include "callbacks.h"
75 #include "playing.h"
76 #include "sound.h"
77 #include "playing.h"
78
79 // invoke incessant rebuilding for build versioning
80 #include "version.h"
81
82 // defaults for bzdb
83 #include "defaultBZDB.h"
84
85 // client prefrences
86 #include "clientConfig.h"
87
88 int beginendCount = 0;
89
90 const char* argv0;
91 std::string alternateConfig;
92 static bool noAudio = false;
93 struct tm userTime;
94 bool echoToConsole = false;
95 bool echoAnsi = false;
96 int debugLevel = 0;
97
98 static BzfDisplay* display = NULL;
99
100
101
102 #ifdef ROBOT
103 // ROBOT -- tidy up
104 int numRobotTanks = 0;
105 #endif
106
107
108 //
109 // application initialization
110 //
111
112 // so that Windows can kill the wsa stuff if needed
bail(int returnCode)113 int bail ( int returnCode )
114 {
115 #ifdef _WIN32
116 WSACleanup();
117 #endif
118 return returnCode;
119 }
120
setVisual(BzfVisual * visual)121 static void setVisual(BzfVisual* visual)
122 {
123 // sine qua non
124 visual->setLevel(0);
125 visual->setDoubleBuffer(true);
126 visual->setRGBA(1, 1, 1, 0);
127
128 // ask for a zbuffer if not disabled. we might
129 // choose not to use it if we do ask for it.
130 if (!BZDB.isSet("zbuffer") || (BZDB.get("zbuffer") != "disable"))
131 {
132 int depthLevel = 16;
133 if (BZDB.isSet("forceDepthBits"))
134 depthLevel = BZDB.evalInt("forceDepthBits");
135 visual->setDepth(depthLevel);
136 }
137
138 // optional
139 visual->setStencil(4);
140 #if defined(DEBUG_RENDERING)
141 visual->setStencil(4);
142 #else
143 visual->setStencil(1);
144 #endif
145 #ifdef USE_GL_STEREO
146 if (BZDB.isSet("view") && BZDB.get("view") == configViewValues[1])
147 visual->setStereo(true);
148 #endif
149 visual->setVerticalSync(BZDB.evalInt("saveEnergy") == 2);
150 }
151
usage()152 static void usage()
153 {
154 printFatalError("usage: %s"
155 " [-badwords <filterfile>]"
156 " [-config <configfile>]"
157 " [-configdir <config dir name>]"
158 " [-d | -debug]"
159 #ifdef DEBUG
160 " [-date mm/dd/yyyy]"
161 #endif
162 " [{-dir | -directory} <data-directory>]"
163 " [-e | -echo]"
164 " [-ea | -echoAnsi]"
165 " [-eyesep separation]"
166 " [-focal distance]"
167 " [-h | -help | --help]"
168 " [-latitude <latitude>] [-longitude <longitude>]"
169 " [-list <list-server-url>] [-nolist]"
170 " [-locale <locale>]"
171 " [-m | -mute]"
172 " [-motd <motd-url>] [-nomotd]"
173 " [-multisample]"
174 #ifdef ROBOT
175 " [-solo <num-robots>]"
176 #endif
177 " [-team {red|green|blue|purple|rogue|observer}]"
178 " [-time hh:mm:ss] [-notime]"
179 " [-v | -version | --version]"
180 " [-view {normal|stereo|stacked|three|anaglyph|interlaced}]"
181 " [-window <geometry-spec>]"
182 " [-zbuffer {on|off}]"
183 " [callsign[:password]@]server[:port]\n\nExiting.", argv0);
184 if (display != NULL)
185 {
186 delete display;
187 display=NULL;
188 }
189 exit(1);
190 }
191
checkArgc(int & i,int argc,const char * option,const char * type="Missing")192 static void checkArgc(int& i, int argc, const char* option, const char *type = "Missing")
193 {
194 if ((i+1) == argc)
195 {
196 printFatalError("%s argument for %s\n", type, option);
197 usage();
198 }
199 i++; // just skip the option argument string
200 }
201
parse(int argc,char ** argv)202 static void parse(int argc, char** argv)
203 {
204 // = 9;
205 for (int i = 1; i < argc; i++)
206 {
207 if (strcmp(argv[i], "-config") == 0)
208 {
209 checkArgc(i, argc, argv[i]);
210 // the setting has already been done in parseConfigName()
211 }
212 else if (strcmp(argv[i], "-configdir") == 0)
213 {
214 checkArgc(i, argc, argv[i]);
215 // the setting has already been done in parseConfigName()
216 }
217 else if ((strcmp(argv[i], "-dir") == 0) ||
218 (strcmp(argv[i], "-directory") == 0))
219 {
220 checkArgc(i, argc, argv[i]);
221 if (strlen(argv[i]) == 0)
222 BZDB.unset("directory");
223 else
224 BZDB.set("directory", argv[i]);
225 }
226 else if (strcmp(argv[i], "-e") == 0 || strcmp(argv[i], "-echo") == 0)
227 echoToConsole = true;
228 else if (strcmp(argv[i], "-ea") == 0 || strcmp(argv[i], "-echoAnsi") == 0)
229 {
230 echoToConsole = true;
231 echoAnsi = true;
232 }
233 else if (strcmp(argv[i], "-h") == 0 ||
234 strcmp(argv[i], "-help") == 0 ||
235 strcmp(argv[i], "--help") == 0)
236 usage();
237 else if (strcmp(argv[i], "-latitude") == 0)
238 {
239 checkArgc(i, argc, argv[i]);
240 double latitude = atof(argv[i]);
241 if (latitude < -90.0 || latitude > 90.0)
242 {
243 printFatalError("Invalid argument for %s.", argv[i-1]);
244 usage();
245 }
246 BZDB.set("latitude", argv[i]);
247 }
248 else if (strcmp(argv[i], "-longitude") == 0)
249 {
250 checkArgc(i, argc, argv[i]);
251 double longitude = atof(argv[i]);
252 if (longitude < -180.0 || longitude > 180.0)
253 {
254 printFatalError("Invalid argument for %s.", argv[i-1]);
255 usage();
256 }
257 BZDB.set("longitude", argv[i]);
258 }
259 else if (strcmp(argv[i], "-list") == 0)
260 {
261 checkArgc(i, argc, argv[i]);
262 if (strcmp(argv[i], "default") == 0)
263 BZDB.set("list", BZDB.getDefault("list"));
264 else
265 {
266 startupInfo.listServerURL = argv[i];
267 BZDB.set("list", argv[i]);
268 }
269 }
270 else if (strcmp(argv[i], "-locale") == 0)
271 {
272 checkArgc(i, argc, argv[i]);
273 BZDB.set("locale", argv[i]);
274 }
275 else if (strcmp(argv[i], "-motd") == 0)
276 {
277 checkArgc(i, argc, argv[i]);
278 if (strcmp(argv[i], "default") == 0)
279 BZDB.set("motdServer", BZDB.getDefault("motdServer"));
280 else
281 BZDB.set("motdServer", argv[i]);
282 BZDB.unset("disableMOTD");
283 }
284 else if (strcmp(argv[i], "-nomotd") == 0)
285 BZDB.set("disableMOTD", "1");
286 else if (strcmp(argv[i], "-nolist") == 0)
287 {
288 startupInfo.listServerURL = "";
289 BZDB.set("list", "");
290 }
291 else if (strcmp(argv[i], "-m") == 0 ||
292 strcmp(argv[i], "-mute") == 0)
293 noAudio = true;
294 else if (strcmp(argv[i], "-multisample") == 0)
295 {
296 BZDB.set("_multisample", "1");
297 #ifdef ROBOT
298 }
299 else if (strcmp(argv[i], "-solo") == 0)
300 {
301 checkArgc(i, argc, argv[i]);
302 numRobotTanks = atoi(argv[i]);
303 if (numRobotTanks < 1 || numRobotTanks > MAX_ROBOTS)
304 {
305 printFatalError("Invalid argument for %s.", argv[i-1]);
306 usage();
307 }
308 #endif
309 }
310 else if (strcmp(argv[i], "-team") == 0)
311 {
312 checkArgc(i, argc, argv[i]);
313 if ((strcmp(argv[i], "a") == 0) ||
314 (strcmp(argv[i], "auto") == 0) ||
315 (strcmp(argv[i], "automatic") == 0))
316 startupInfo.team = AutomaticTeam;
317 else if (strcmp(argv[i], "r") == 0 || strcmp(argv[i], "red") == 0)
318 startupInfo.team = RedTeam;
319 else if (strcmp(argv[i], "g") == 0 || strcmp(argv[i], "green") == 0)
320 startupInfo.team = GreenTeam;
321 else if (strcmp(argv[i], "b") == 0 || strcmp(argv[i], "blue") == 0)
322 startupInfo.team = BlueTeam;
323 else if (strcmp(argv[i], "p") == 0 || strcmp(argv[i], "purple") == 0)
324 startupInfo.team = PurpleTeam;
325 else if (strcmp(argv[i], "z") == 0 || strcmp(argv[i], "rogue") == 0)
326 startupInfo.team = RogueTeam;
327 else if (strcmp(argv[i], "o") == 0 || strcmp(argv[i], "observer") == 0)
328 startupInfo.team = ObserverTeam;
329 else
330 {
331 printFatalError("Invalid argument for %s.", argv[i-1]);
332 usage();
333 }
334 }
335 else if (strcmp(argv[i], "-v") == 0 ||
336 strcmp(argv[i], "-version") == 0 ||
337 strcmp(argv[i], "--version") == 0)
338 {
339 printFatalError("BZFlag client %s (protocol %s) http://BZFlag.org/\n%s",
340 getAppVersion(),
341 getProtocolVersion(),
342 bzfcopyright);
343 bail(0);
344 exit(0);
345 }
346 else if (strcmp(argv[i], "-window") == 0)
347 {
348 BZDB.set("_window", "1");
349 checkArgc(i, argc, argv[i]);
350 int w, h, x, y, count;
351 char xs ='+', ys='+';
352 if (strcmp(argv[i], "default") != 0
353 && (((count = sscanf(argv[i], "%dx%d%c%d%c%d", &w, &h, &xs, &x, &ys, &y)) != 6 && count != 2)
354 || (xs != '-' && xs != '+')
355 || (ys != '-' && ys != '+')))
356 {
357 printFatalError("Invalid argument for %s. \nCorrect format is <width>x<height>[+|-]<x>[+|-].", argv[i-1]);
358 usage();
359 }
360 BZDB.set("geometry", argv[i]);
361 #ifdef DEBUG
362 }
363 else if (strcmp(argv[i], "-date") == 0)
364 {
365 checkArgc(i, argc, argv[i]);
366 int month, day, year;
367 // FIXME: should use iso yyyy.mm.dd format
368 if (sscanf(argv[i], "%d/%d/%d", &month, &day, &year) != 3 ||
369 day < 1 || day > 31 || // FIXME -- upper limit loose
370 month < 1 || month > 12 ||
371 (year < 0 || (year > 100 && (year < 1970 || year > 2100))))
372 {
373 printFatalError("Invalid argument for %s.", argv[i-1]);
374 usage();
375 }
376 if (year > 100) year = year - 1900;
377 else if (year < 70) year += 100;
378 userTime.tm_mday = day;
379 userTime.tm_mon = month - 1;
380 userTime.tm_year = year;
381 #endif
382 }
383 else if (strcmp(argv[i], "-time") == 0)
384 {
385 checkArgc(i, argc, argv[i]);
386 BZDB.set("fixedTime", argv[i]);
387 }
388 else if (strcmp(argv[i], "-notime") == 0)
389 BZDB.unset("fixedTime");
390 else if (strcmp(argv[i], "-view") == 0)
391 {
392 checkArgc(i, argc, argv[i]);
393 BZDB.set("view", argv[i]);
394 }
395 else if (strcmp(argv[i], "-zbuffer") == 0)
396 {
397 checkArgc(i, argc, argv[i]);
398 if (strcmp(argv[i], "on") == 0)
399 BZDB.set("zbuffer", "1");
400 else if (strcmp(argv[i], "off") == 0)
401 BZDB.set("zbuffer", "disable");
402 else
403 {
404 printFatalError("Invalid argument for %s.", argv[i-1]);
405 usage();
406 }
407 }
408 else if (strcmp(argv[i], "-eyesep") == 0)
409 {
410 checkArgc(i, argc, argv[i]);
411 BZDB.set("eyesep", argv[i]);
412 }
413 else if (strcmp(argv[i], "-focal") == 0)
414 {
415 checkArgc(i, argc, argv[i]);
416 BZDB.set("focal", argv[i]);
417 }
418 else if (strncmp(argv[i], "-psn", 4) == 0)
419 {
420 std::vector<std::string> args;
421 args.push_back(argv[i]);
422 printError("Ignoring Finder argument \"{1}\"", &args);
423 // ignore process serial number argument (-psn_x_xxxx for MacOS X
424 }
425 else if (strcmp(argv[i], "-badwords") == 0)
426 {
427 checkArgc(i, argc, argv[i], "Missing bad word filter file");
428 BZDB.set("filterFilename", argv[i], StateDatabase::ReadOnly);
429 }
430 else if (argv[i][0] != '-')
431 {
432 if (i == (argc - 1))
433 {
434 // argv[i] = username:password@server:port
435 // variables to store
436 std::string serverName, callsign, password;
437 int port;
438
439 // start splitting stuff
440 const std::string argument = std::string(argv[i]);
441 const size_t atSplit = argument.find("@");
442 const size_t portSplit = argument.rfind(":");
443 const size_t passSplit = argument.find(":");
444
445 if (atSplit != std::string::npos) // we found an "@"
446 {
447 if (portSplit != std::string::npos) // we have a port
448 {
449 serverName = argument.substr(atSplit + 1, portSplit - atSplit - 1);
450 port = atoi(argument.substr(portSplit + 1, argument.length() - portSplit).c_str());
451
452 if (port < 1 || port > 65535) // invalid port
453 {
454 printFatalError("Bad port, using default %d.", ServerPort);
455 port = ServerPort;
456 }
457 }
458 else //we don't have a port
459 {
460 serverName = argument.substr(atSplit + 1, argument.length() - atSplit);
461 port = ServerPort;
462 }
463
464 if (portSplit != passSplit) // there's a password to parse
465 {
466 callsign = argument.substr(0, passSplit);
467 password = argument.substr(passSplit + 1, atSplit - passSplit - 1);
468 }
469 else // just a username
470 {
471 callsign = argument.substr(0, atSplit);
472 password = "";
473 }
474
475 // length checks and always truncate everything after the max length
476 if (callsign.length() > sizeof(startupInfo.callsign))
477 {
478 callsign.erase(sizeof(startupInfo.callsign) - 1, std::string::npos);
479 printFatalError("Callsign truncated after %d characters.", sizeof(startupInfo.callsign));
480 }
481 if (password.length() > sizeof(startupInfo.password))
482 {
483 password.erase(sizeof(startupInfo.password) - 1, std::string::npos);
484 printFatalError("Password truncated after %d characters.", sizeof(startupInfo.password));
485 }
486 if (serverName.length() > sizeof(startupInfo.serverName))
487 {
488 serverName.erase(sizeof(startupInfo.serverName) - 1, std::string::npos);
489 printFatalError("Server name truncated after %d characters.", sizeof(startupInfo.serverName));
490 }
491
492 // assign variables with strcpy because char[] can't be assigned
493 strcpy(startupInfo.callsign, callsign.c_str());
494 strcpy(startupInfo.password, password.c_str());
495 strcpy(startupInfo.serverName, serverName.c_str());
496 startupInfo.serverPort = port;
497 }
498 else // there is no callsign/password so only a destination
499 {
500 if (portSplit != std::string::npos) // we have a port
501 {
502 serverName = argument.substr(atSplit + 1, portSplit - atSplit - 1);
503 port = atoi(argument.substr(portSplit + 1, argument.length() - portSplit).c_str());
504
505 if (port < 1 || port > 65535) // invalid port
506 {
507 printFatalError("Bad port, using default %d.", ServerPort);
508 port = ServerPort;
509 }
510 }
511 else //we don't have a port
512 {
513 serverName = argument.substr(atSplit + 1, argument.length() - atSplit);
514 port = ServerPort;
515 }
516
517 // sanity check for length
518 if (serverName.length() > sizeof(startupInfo.serverName))
519 {
520 serverName.erase(sizeof(startupInfo.serverName) - 1, std::string::npos);
521 printFatalError("Server name truncated after %d characters.", sizeof(startupInfo.serverName));
522 }
523
524 strcpy(startupInfo.serverName, serverName.c_str());
525 startupInfo.serverPort = port;
526 }
527
528 startupInfo.autoConnect = true; // automatically connect on start up
529 }
530 else
531 printFatalError("Unexpected: %s. Server must go after all options.", argv[i]);
532 }
533 else if (strcmp(argv[i], "-debug") == 0)
534 debugLevel++;
535 #ifdef __APPLE__
536 else if (strcmp(argv[i], "-NSDocumentRevisionsDebugMode") == 0)
537 // ignore this option that is appended when running from inside Xcode
538 checkArgc(i, argc, argv[i]);
539 #endif // __APPLE__
540 // has to be the last option that starts with -d
541 else if (strncmp(argv[i], "-d", 2) == 0)
542 {
543 const char num = argv[i][2];
544 if ((num >= '0') && (num <= '9') && (argv[i][3] == 0))
545 debugLevel = num - '0';
546 else
547 {
548 const char* c = argv[i] + 2;
549 while (*c != 0)
550 {
551 if (*c != 'd')
552 {
553 printFatalError("Unknown option %s.", argv[i]);
554 usage();
555 }
556 c++;
557 }
558 debugLevel += (int)((c - argv[i]) - 1);
559 }
560 }
561 else
562 {
563 printFatalError("Unknown option %s.", argv[i]);
564 usage();
565 }
566 }
567 }
568
parseConfigName(int argc,char ** argv)569 static void parseConfigName(int argc, char** argv)
570 {
571 for (int i = 1; i < argc; i++)
572 {
573 if (strcmp(argv[i], "-configdir") == 0)
574 {
575 checkArgc(i, argc, argv[i]);
576 setCustomConfigDir(argv[i]);
577 }
578 }
579 for (int i = 1; i < argc; i++)
580 {
581 if (strcmp(argv[i], "-config") == 0)
582 {
583 checkArgc(i, argc, argv[i]);
584 alternateConfig = getConfigDirName();
585 alternateConfig += argv[i];
586 }
587 }
588 }
589
590 //
591 // resource database dumping. used during initial startup to save
592 // preferences in case anything catastrophic goes wrong afterwards
593 // (so user won't have to wait through performance testing again).
594 //
595
dumpResources()596 void dumpResources()
597 {
598 // collect new configuration
599
600 // only dump username and password if we're allowed to, otherwise
601 // erase them if they exist
602 if (BZDB.eval("saveIdentity") > 0)
603 BZDB.set("callsign", startupInfo.callsign);
604 else
605 BZDB.set("callsign", "");
606 if (BZDB.eval("saveIdentity") > 1)
607 BZDB.set("password", startupInfo.password);
608 else
609 BZDB.set("password", "");
610
611 BZDB.set("team", Team::getName(startupInfo.team));
612 BZDB.set("server", startupInfo.serverName);
613 if (startupInfo.serverPort != ServerPort)
614 BZDB.set("port", TextUtils::format("%d", startupInfo.serverPort));
615 else
616 BZDB.unset("port");
617 BZDB.set("list", startupInfo.listServerURL);
618 if (isSoundOpen())
619 BZDB.set("volume", TextUtils::format("%d", getSoundVolume()));
620
621 if (RENDERER.getWindow().getWindow()->hasGammaControl())
622 {
623 BZDB.set("gamma",
624 TextUtils::format("%f", RENDERER.getWindow().getWindow()->getGamma()));
625 }
626
627 BZDB.set("quality", configQualityValues[RENDERER.useQuality()]);
628 if (!BZDB.isSet("_window") && display->getResolution() != -1 &&
629 display->getResolution(display->getResolution()))
630 BZDB.set("resolution", display->getResolution(display->getResolution())->name);
631 BZDB.set("startcode", ServerStartMenu::getSettings());
632
633 BZDB.set("panelopacity", TextUtils::format("%f", RENDERER.getPanelOpacity()));
634
635 BZDB.set("radaropacity", TextUtils::format("%f", RENDERER.getRadarOpacity()));
636
637 BZDB.set("mouseboxsize", TextUtils::format("%d", RENDERER.getMaxMotionFactor()));
638
639 // don't save these configurations
640 BZDB.setPersistent("_window", false);
641 BZDB.setPersistent("_multisample", false);
642
643 const std::vector<std::string> list = getSilenceList();
644
645 // add entries silencedPerson0 silencedPerson1 etc..
646 // to the database. Stores silenceList
647 // By only allowing up to a certain # of people can prevent
648 // the vague chance of buffer overrun.
649 const int bufferLength = 30;
650 int maxListSize = 1000000; //do even that many play bzflag?
651 char buffer [bufferLength];
652
653 if ((int)list.size() < maxListSize) maxListSize = list.size();
654 for (int i = 0; i < maxListSize; i++)
655 {
656 sprintf(buffer, "silencedPerson%d", i);
657 BZDB.set(TextUtils::format("silencedPerson%d", i), list[i]);
658 }
659
660 BZDB.set("motto", startupInfo.motto);
661
662 BZDB.set("serverCacheAge", TextUtils::format("%1d", (long)(ServerListCache::get())->getMaxCacheAge()));
663
664 (ServerListCache::get())->saveCache();
665 }
666
needsFullscreen()667 static bool needsFullscreen()
668 {
669 // fullscreen if not in a window
670 if (!BZDB.isSet("_window")) return true;
671
672 // not fullscreen if view is default (normal)
673 if (!BZDB.isSet("view")) return false;
674
675 // fullscreen if view is not default
676 std::string value = BZDB.get("view");
677 for (int i = 1; i < (int)configViewValues.size(); i++)
678 if (value == configViewValues[i])
679 return true;
680
681 // bogus view, default to normal so no fullscreen
682 return false;
683 }
684
createCacheSignature()685 static void createCacheSignature ()
686 {
687 // This file is to be used by archiving and mirroring tools avoid
688 // this directory (and any of its sub-directories). Please see:
689 // < http://www.brynosaurus.com/cachedir/ >
690
691 const char cacheSignature[] = "Signature: 8a477f597d28d172789f06886806bc55\n";
692 const char cacheComment[] =
693 "# This file is a cache directory tag created by BZFlag.\n"
694 "# For information about cache directory tags, see:\n"
695 "# http://www.brynosaurus.com/cachedir/\n";
696 std::string cacheTagName = getCacheDirName();
697 cacheTagName += "CACHEDIR.TAG";
698 std::ostream* cacheTag = FILEMGR.createDataOutStream(cacheTagName, true, true);
699 if (cacheTag != NULL)
700 {
701 cacheTag->write(cacheSignature, strlen(cacheSignature)); // Flawfinder: ignore
702 cacheTag->write(cacheComment, strlen(cacheComment)); // Flawfinder: ignore
703 }
704 delete cacheTag;
705
706 return;
707 }
708
709
710 //
711 // main()
712 // initialize application and enter event loop
713 //
714
715 #if defined(_WIN32) && !defined(HAVE_SDL)
myMain(int argc,char ** argv)716 int myMain(int argc, char** argv)
717 #else /* defined(_WIN32) */
718 int main(int argc, char** argv)
719 #endif /* defined(_WIN32) */
720 {
721 #ifdef _WIN32
722 // startup winsock
723 static const int major = 2, minor = 2;
724 WSADATA wsaData;
725 if (WSAStartup(MAKEWORD(major, minor), &wsaData))
726 {
727 printFatalError("Failed to initialize winsock. Terminating.\n");
728 return 1;
729 }
730 if (LOBYTE(wsaData.wVersion) != major || HIBYTE(wsaData.wVersion) != minor)
731 {
732 printFatalError("Version mismatch in winsock;"
733 " got %d.%d, expected %d.%d. Terminating.\n",
734 (int)LOBYTE(wsaData.wVersion),
735 (int)HIBYTE(wsaData.wVersion),
736 major, minor);
737 return bail(1);
738 }
739 #endif
740
741 initGlobalAres();
742
743 WordFilter *filter = (WordFilter *)NULL;
744
745 argv0 = argv[0];
746
747 // init libs
748
749 //init_packetcompression();
750
751 // initialize global objects and classes
752 bzfsrand((unsigned int)time(0));
753
754 // set default DB entries
755 for (unsigned int gi = 0; gi < numGlobalDBItems; ++gi)
756 {
757 assert(globalDBItems[gi].name != NULL);
758 if (globalDBItems[gi].value != NULL)
759 {
760 BZDB.set(globalDBItems[gi].name, globalDBItems[gi].value);
761 BZDB.setDefault(globalDBItems[gi].name, globalDBItems[gi].value);
762 }
763 BZDB.setPersistent(globalDBItems[gi].name, globalDBItems[gi].persistent);
764 BZDB.setPermission(globalDBItems[gi].name, globalDBItems[gi].permission);
765 }
766
767 BZDBCache::init();
768 BZDBLOCAL.init();
769
770 Flags::init();
771
772 time_t timeNow;
773 time(&timeNow);
774 userTime = *localtime(&timeNow);
775
776 CommandsStandard::add();
777 unsigned int i;
778
779 initConfigData();
780 loadBZDBDefaults();
781
782 // parse for the config filename
783 // the rest of the options are parsed after the config file
784 // has been loaded to allow for command line overrides
785 parseConfigName(argc, argv);
786
787 // read resources
788 if (alternateConfig != "")
789 {
790 if (CFGMGR.read(alternateConfig))
791 startupInfo.hasConfiguration = true;
792 }
793 if (!startupInfo.hasConfiguration)
794 {
795 findConfigFile();
796 if (CFGMGR.read(getCurrentConfigFileName()))
797 {
798 startupInfo.hasConfiguration = true;
799 updateConfigFile();
800 }
801 }
802
803 // Create the cache signature
804 createCacheSignature();
805
806 if (startupInfo.hasConfiguration)
807 ActionBinding::instance().getFromBindings();
808 else
809 // bind default keys
810 ActionBinding::instance().resetBindings();
811
812 ServerListCache::get()->loadCache();
813
814 // restore some configuration (command line overrides these)
815 if (startupInfo.hasConfiguration)
816 {
817 if (BZDB.isSet("callsign"))
818 {
819 // Flawfinder: ignore
820 strncpy(startupInfo.callsign, BZDB.get("callsign").c_str(),
821 sizeof(startupInfo.callsign) - 1);
822 startupInfo.callsign[sizeof(startupInfo.callsign) - 1] = '\0';
823 }
824 if (BZDB.isSet("password"))
825 {
826 // Flawfinder: ignore
827 strncpy(startupInfo.password, BZDB.get("password").c_str(),
828 sizeof(startupInfo.password) - 1);
829 startupInfo.password[sizeof(startupInfo.password) - 1] = '\0';
830 }
831
832 if (BZDB.isSet("team"))
833 {
834 std::string value = BZDB.get("team");
835 startupInfo.team = Team::getTeam(value);
836 }
837 if (BZDB.isSet("server"))
838 {
839 // Flawfinder: ignore
840 strncpy(startupInfo.serverName, BZDB.get("server").c_str(),
841 sizeof(startupInfo.serverName) - 1);
842 startupInfo.serverName[sizeof(startupInfo.serverName) - 1] = '\0';
843 }
844 if (BZDB.isSet("port"))
845 startupInfo.serverPort = atoi(BZDB.get("port").c_str());
846
847 // ignore window name in config file (it's used internally)
848 BZDB.unset("_window");
849 BZDB.unset("_multisample");
850
851
852 // however, if the "__window" setting is enabled, let it through
853 if (BZDB.isSet("__window"))
854 if (BZDB.isTrue("__window"))
855 BZDB.set("_window", "1");
856 }
857
858 // use UDP? yes
859 startupInfo.useUDPconnection=true;
860
861 // parse arguments
862 parse(argc, argv);
863
864 #ifdef _WIN32
865 // this is cheap but it will work on windows
866 // clear out the stdout file
867 if (echoToConsole)
868 {
869 std::string filename = getConfigDirName() + "stdout.txt";
870 FILE *fp = fopen (filename.c_str(), "w");
871 if (fp)
872 {
873 fprintf(fp,"stdout started\r\n" );
874 fclose(fp);
875 }
876 }
877 #endif
878
879 if (BZDB.isSet("directory"))
880 {
881 //Convert to unix paths so that escaping isn't an issue
882 std::string directory = BZDB.get("directory");
883 OSFileOSToStdDir(directory);
884 BZDB.set("directory", directory);
885 }
886
887 if (debugLevel >= 4)
888 BZDB.setDebug(true);
889
890 // set time from BZDB
891 if (BZDB.isSet("fixedTime"))
892 {
893 int hours, minutes, seconds;
894 char dbTime[256];
895 // Flawfinder: ignore
896 strncpy(dbTime, BZDB.get("fixedTime").c_str(), sizeof(dbTime) - 1);
897 dbTime[sizeof(dbTime) - 1] = '\0';
898 if (sscanf(dbTime, "%d:%d:%d", &hours, &minutes, &seconds) != 3 ||
899 hours < 0 || hours > 23 ||
900 minutes < 0 || minutes > 59 ||
901 seconds < 0 || seconds > 59)
902 printFatalError("Invalid argument for fixedTime = %s", dbTime);
903 userTime.tm_sec = seconds;
904 userTime.tm_min = minutes;
905 userTime.tm_hour = hours;
906 }
907
908 // see if there is a _default_ badwords file
909 if (!BZDB.isSet("filterFilename"))
910 {
911 std::string name;
912 name = getConfigDirName();
913 name += "badwords.txt";
914
915 // get a handle on a filter object to attempt a load
916 if (BZDB.isSet("filter"))
917 {
918 filter = (WordFilter *)BZDB.getPointer("filter");
919 if (filter == NULL)
920 filter = new WordFilter();
921 }
922 else
923 {
924 // filter is not set
925 filter = new WordFilter();
926 }
927 // XXX should stat the file first and load with interactive feedback
928 unsigned int count = filter->loadFromFile(name, false);
929 if (count > 0)
930 std::cout << "Loaded " << count << " words from \"" << name << "\"" << std::endl;
931 }
932
933 // load the bad word filter, regardless of a default, if it was set
934 if (BZDB.isSet("filterFilename"))
935 {
936 std::string filterFilename = BZDB.get("filterFilename");
937 std::cout << "Filter file name specified is \"" << filterFilename << "\"" << std::endl;
938 if (filterFilename.length() != 0)
939 {
940 if (filter == NULL)
941 filter = new WordFilter();
942 std::cout << "Loading " << filterFilename << std::endl;
943 unsigned int count = filter->loadFromFile(filterFilename, true);
944 std::cout << "Loaded " << count << " words" << std::endl;
945
946 // stash the filter into the database for retrieval later
947 BZDB.setPointer("filter", (void *)filter, StateDatabase::ReadOnly );
948 BZDB.setPersistent("filter", false);
949 }
950 else
951 std::cerr << "WARNING: A proper file name was not given for the -badwords argument" << std::endl;
952 }
953
954 // use empty motto string unless previously set
955 std::string motto = BZDB.get("motto");
956 motto = motto.substr(0, sizeof(startupInfo.motto) - 1);
957 //Flawfinder: ignore
958 strcpy(startupInfo.motto, motto.c_str());
959
960 // load the default values for shot colors
961 Team::updateShotColors();
962
963 // make platform factory
964 PlatformFactory* platformFactory = PlatformFactory::getInstance();
965
966 // open display
967 display = platformFactory->createDisplay(NULL, NULL);
968 if (!display)
969 {
970 printFatalError("Can't open display. Exiting.");
971 return bail(1);
972 }
973
974 // choose visual
975 BzfVisual* visual = platformFactory->createVisual(display);
976 setVisual(visual);
977
978 // make the window
979 BzfWindow* window = platformFactory->createWindow(display, visual);
980 if (!window->isValid())
981 {
982 printFatalError("Can't create window. Exiting.");
983 return bail(1);
984 }
985 window->setTitle("bzflag");
986
987 // create the joystick
988 BzfJoystick* joystick = platformFactory->createJoystick();
989
990 // Change audio driver if requested
991 if (BZDB.isSet("audioDriver"))
992 PlatformFactory::getMedia()->setDriver(BZDB.get("audioDriver"));
993 // Change audio device if requested
994 if (BZDB.isSet("audioDevice"))
995 PlatformFactory::getMedia()->setDevice(BZDB.get("audioDevice"));
996
997 // set data directory if user specified
998 if (BZDB.isSet("directory"))
999 {
1000 /* already specified, so just set/use it */
1001 PlatformFactory::getMedia()->setMediaDirectory(BZDB.get("directory"));
1002 }
1003 else
1004 {
1005
1006 #if (defined(_WIN32) || defined(WIN32))
1007 char exePath[MAX_PATH];
1008 char dataPath[MAX_PATH];
1009 GetModuleFileName(NULL,exePath,MAX_PATH);
1010 char* last = strrchr(exePath,'\\');
1011 if (last)
1012 *last = '\0';
1013
1014 strcpy(dataPath,exePath);
1015
1016 char temp[MAX_PATH];
1017 getcwd(temp,MAX_PATH);
1018
1019 // find the data dir
1020 strcat(dataPath,"\\data");
1021
1022 if (chdir(dataPath) != 0)
1023 {
1024 strcpy(dataPath,exePath);
1025
1026 char* last = strrchr(dataPath,'\\');
1027 if (last)
1028 *last = '\0';
1029
1030 strcat(dataPath,"\\data");
1031 }
1032
1033 chdir(temp);
1034 BzfMedia *media = PlatformFactory::getMedia();
1035 if (media)
1036 media->setMediaDirectory(dataPath);
1037
1038 FileManager::instance().setDataPath(std::string(dataPath));
1039 #else
1040 // It's only checking existence of l10n directory
1041 std::string mediadir = DEFAULT_MEDIA_DIR;
1042 mediadir += "/l10n";
1043 DIR *localedir = opendir(mediadir.c_str());
1044 if (localedir != NULL)
1045 {
1046 /* found 'data' dir */
1047 BzfMedia *media = PlatformFactory::getMedia();
1048 if (media)
1049 media->setMediaDirectory(DEFAULT_MEDIA_DIR);
1050 closedir(localedir);
1051 }
1052 else
1053 {
1054 /* bah, just set the compile-time path */
1055 PlatformFactory::getMedia()->setMediaDirectory(INSTALL_DATA_DIR);
1056 }
1057 #endif
1058 }
1059
1060 // initialize font system
1061 FontManager &fm = FontManager::instance();
1062 // load fonts from data directory
1063 fm.loadAll(PlatformFactory::getMedia()->getMediaDirectory() + "/fonts");
1064 // try to get a font - only returns -1 if there are no fonts at all
1065 if (fm.getFaceID(BZDB.get("consoleFont")) < 0)
1066 {
1067 printFatalError("No fonts found (the -directory option may help). Exiting");
1068 return bail(1);
1069 }
1070
1071 // initialize locale system
1072
1073 BundleMgr *bm = new BundleMgr(PlatformFactory::getMedia()->getMediaDirectory(), "bzflag");
1074 World::setBundleMgr(bm);
1075
1076 std::string locale = BZDB.isSet("locale") ? BZDB.get("locale") : "default";
1077 World::setLocale(locale);
1078 bm->getBundle(World::getLocale());
1079
1080 bool setPosition = false, setSize = false;
1081 int x = 0, y = 0, w = 0, h = 0;
1082
1083 // set window size (we do it here because the OpenGL context isn't yet bound)
1084
1085 if (BZDB.isSet("geometry"))
1086 {
1087 char xs, ys;
1088 const std::string geometry = BZDB.get("geometry");
1089 const int count = sscanf(geometry.c_str(), "%dx%d%c%d%c%d", &w, &h, &xs, &x, &ys, &y);
1090
1091 if (geometry == "default" || (count != 6 && count != 2) || w < 0 || h < 0)
1092 BZDB.unset("geometry");
1093 else if (count == 6 && ((xs != '-' && xs != '+') || (ys != '-' && ys != '+')))
1094 BZDB.unset("geometry");
1095 else
1096 {
1097 setSize = true;
1098 if (w < 256)
1099 w = 256;
1100 if (h < 192)
1101 h = 192;
1102 if (count == 6)
1103 {
1104 if (xs == '-')
1105 x = display->getWidth() - x - w;
1106 if (ys == '-')
1107 y = display->getHeight() - y - h;
1108 setPosition = true;
1109 }
1110 // must call this before setFullscreen() is called
1111 display->setPassthroughSize(w, h);
1112 }
1113 }
1114
1115 // set window size (we do it here because the OpenGL context isn't yet
1116 // bound.)
1117 const bool useFullscreen = needsFullscreen();
1118 if (useFullscreen)
1119 {
1120 #ifndef HAVE_SDL
1121 // tell window to be fullscreen
1122 window->setFullscreen(true);
1123 #endif
1124
1125 // set the size if one was requested. this overrides the default
1126 // size (which is the display or passthrough size).
1127 if (setSize)
1128 window->setSize(w, h);
1129 }
1130 else if (setSize)
1131 window->setSize(w, h);
1132 else
1133 window->setSize(640, 480);
1134 if (setPosition)
1135 window->setPosition(x, y);
1136
1137 // now make the main window wrapper. this'll cause the OpenGL context
1138 // to be bound for the first time.
1139 MainWindow* pmainWindow = new MainWindow(window, joystick);
1140 if (pmainWindow->isInFault())
1141 {
1142 printFatalError("Error creating window - Exiting");
1143 return bail(1);
1144 }
1145
1146 std::string videoFormat;
1147 int format = -1;
1148 if (BZDB.isSet("resolution"))
1149 {
1150 videoFormat = BZDB.get("resolution");
1151 if (videoFormat.length() != 0)
1152 {
1153 format = display->findResolution(videoFormat.c_str());
1154 if (format >= 0)
1155 display->setFullScreenFormat(format);
1156 }
1157 };
1158 // set fullscreen again so MainWindow object knows it's full screen
1159 if (useFullscreen)
1160 // this will also call window create
1161 pmainWindow->setFullscreen();
1162 else
1163 window->create();
1164
1165 // set main window's minimum size (arbitrary but should be big enough
1166 // to see stuff in control panel)
1167 pmainWindow->setMinSize(256, 192);
1168
1169 // enable vsync if needed
1170 pmainWindow->getWindow()->setVerticalSync(BZDB.evalInt("saveEnergy") == 2);
1171
1172 // get sound files. must do this after creating the window because
1173 // DirectSound is a bonehead API.
1174 if (!noAudio)
1175 {
1176 openSound("bzflag");
1177 if (startupInfo.hasConfiguration && BZDB.isSet("volume"))
1178 setSoundVolume(static_cast<int>(BZDB.eval("volume")));
1179 }
1180
1181 // Initialize the joystick
1182 joystick->initJoystick(BZDB.get("joystickname").c_str());
1183 joystick->setXAxis(BZDB.get("jsXAxis"));
1184 joystick->setYAxis(BZDB.get("jsYAxis"));
1185
1186 // initialize graphics state
1187 pmainWindow->getWindow()->makeCurrent();
1188 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1189 glClearStencil(0);
1190 glMatrixMode(GL_PROJECTION);
1191 glLoadIdentity();
1192 glMatrixMode(GL_MODELVIEW);
1193 glLoadIdentity();
1194 glEnable(GL_SCISSOR_TEST);
1195 // glEnable(GL_CULL_FACE);
1196 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
1197 if (!OpenGLGState::haveGLContext())
1198 {
1199 // DIE
1200 printFatalError("ERROR: Unable to initialize an OpenGL context");
1201 if (display != NULL)
1202 {
1203 delete display;
1204 display=NULL;
1205 }
1206 bail(1);
1207 exit(1);
1208 }
1209 OpenGLGState::init();
1210
1211 // sanity check - make sure OpenGL was actually initialized or
1212 // there's no sense in continuing.
1213 const char* const glRenderer = (const char*)glGetString(GL_RENDERER);
1214 if (!glRenderer)
1215 {
1216 // bad code, no doughnut for you
1217
1218 GLenum error = GL_NO_ERROR;
1219 while ((error = glGetError()) != GL_NO_ERROR)
1220 {
1221 switch (error)
1222 {
1223 case GL_INVALID_ENUM:
1224 std::cerr << "ERROR: GL_INVALID_ENUM" << std::endl;
1225 break;
1226 case GL_INVALID_VALUE:
1227 std::cerr << "ERROR: GL_INVALID_VALUE" << std::endl;
1228 break;
1229 case GL_INVALID_OPERATION:
1230 std::cerr << "ERROR: GL_INVALID_OPERATION" << std::endl;
1231 break;
1232 case GL_STACK_OVERFLOW:
1233 std::cerr << "ERROR: GL_STACK_OVERFLOW" << std::endl;
1234 break;
1235 case GL_STACK_UNDERFLOW:
1236 std::cerr << "ERROR: GL_STACK_UNDERFLOW" << std::endl;
1237 break;
1238 case GL_OUT_OF_MEMORY:
1239 std::cerr << "ERROR: GL_OUT_OF_MEMORY" << std::endl;
1240 break;
1241 #ifdef GL_VERSION_1_2
1242 case GL_TABLE_TOO_LARGE:
1243 std::cerr << "ERROR: GL_TABLE_TOO_LARGE" << std::endl;
1244 break;
1245 #endif
1246 case GL_NO_ERROR:
1247 // should not reach
1248 std::cerr << "ERROR: GL_NO_ERROR" << std::endl;
1249 break;
1250 default:
1251 // should not reach
1252 std::cerr << "ERROR: UNKNOWN CODE: " << error << std::endl;
1253 }
1254 }
1255
1256 // DIE
1257 printFatalError("ERROR: Unable to initialize an OpenGL renderer");
1258 if (display != NULL)
1259 {
1260 delete display;
1261 display=NULL;
1262 }
1263 bail(1);
1264 exit(1);
1265
1266 }
1267
1268 // add the zbuffer callback here, after the OpenGL context is initialized
1269 BZDB.addCallback("zbuffer", setDepthBuffer, NULL);
1270
1271 //add a fake cursor. Let the defaults file override this, though.
1272 if (!BZDB.isSet("fakecursor"))
1273 {
1274 // check that the glrenderer is Mesa Glide
1275 if ((glRenderer != NULL) && (strncmp(glRenderer, "Mesa Glide", 10) == 0))
1276 BZDB.set("fakecursor", "1");
1277 }
1278
1279 // set gamma if set in resources and we have gamma control
1280 if (BZDB.isSet("gamma"))
1281 {
1282 if (pmainWindow->getWindow()->hasGammaControl())
1283 pmainWindow->getWindow()->setGamma
1284 ((float)atof(BZDB.get("gamma").c_str()));
1285 }
1286
1287 // set the scene renderer's window
1288 RENDERER.setWindow(pmainWindow);
1289
1290 // restore rendering configuration
1291 if (startupInfo.hasConfiguration)
1292 {
1293 if (BZDB.isSet("zbuffersplit"))
1294 RENDERER.setZBufferSplit(BZDB.isTrue("zbuffersplit"));
1295 if (BZDB.isSet("quality"))
1296 {
1297 std::string value = BZDB.get("quality");
1298 const int qualityLevels = (int)configQualityValues.size();
1299 for (int j = 0; j < qualityLevels; j++)
1300 {
1301 if (value == configQualityValues[j])
1302 {
1303 RENDERER.setQuality(j);
1304 break;
1305 }
1306 }
1307 }
1308
1309 TextureManager& tm = TextureManager::instance();
1310 tm.setMaxFilter(BZDB.get("texture"));
1311 BZDB.set("texture", tm.getMaxFilterName());
1312
1313 BZDB.set("texturereplace", (!BZDBCache::lighting &&
1314 RENDERER.useQuality() < 2) ? "1" : "0");
1315 BZDB.setPersistent("texturereplace", false);
1316 if (BZDB.isSet("view"))
1317 {
1318 RENDERER.setViewType(SceneRenderer::Normal);
1319 std::string value = BZDB.get("view");
1320 for (i = 0; i < configViewValues.size(); i++)
1321 if (value == configViewValues[i])
1322 {
1323 RENDERER.setViewType((SceneRenderer::ViewType)i);
1324 break;
1325 }
1326 }
1327
1328 if (BZDB.isSet("startcode"))
1329 ServerStartMenu::setSettings(BZDB.get("startcode").c_str());
1330
1331 if (BZDB.isSet("panelopacity"))
1332 RENDERER.setPanelOpacity(BZDB.eval("panelopacity"));
1333
1334 if (BZDB.isSet("radaropacity"))
1335 RENDERER.setRadarOpacity(BZDB.eval("radaropacity"));
1336
1337 if (BZDB.isSet("radarsize"))
1338 RENDERER.setRadarSize(BZDB.getIntClamped("radarsize", 0, GUIOptionsMenu::maxRadarSize));
1339
1340 if (BZDB.isSet("panelheight"))
1341 RENDERER.setPanelHeight(BZDB.getIntClamped("panelheight", 0, GUIOptionsMenu::maxRadarSize));
1342
1343 if (BZDB.isSet("mouseboxsize"))
1344 RENDERER.setMaxMotionFactor(atoi(BZDB.get("mouseboxsize").c_str()));
1345 }
1346
1347 // grab the mouse only if allowed
1348 if (BZDB.isSet("mousegrab") && !BZDB.isTrue("mousegrab"))
1349 {
1350 pmainWindow->setNoMouseGrab();
1351 pmainWindow->enableGrabMouse(false);
1352 }
1353 else
1354 pmainWindow->enableGrabMouse(true);
1355
1356 // set window quadrant
1357 if (RENDERER.getViewType() == SceneRenderer::ThreeChannel)
1358 pmainWindow->setQuadrant(MainWindow::UpperRight);
1359 else if (RENDERER.getViewType() == SceneRenderer::Stacked)
1360 pmainWindow->setQuadrant(MainWindow::LowerHalf);
1361 #ifndef USE_GL_STEREO
1362 else if (RENDERER.getViewType() == SceneRenderer::Stereo)
1363 pmainWindow->setQuadrant(MainWindow::UpperRight);
1364 #endif
1365
1366 // clear the grid graphics if they are not accessible
1367 #if !defined(DEBUG_RENDERING)
1368 if (debugLevel <= 0)
1369 {
1370 BZDB.set("showCullingGrid", "0");
1371 BZDB.set("showCollisionGrid", "0");
1372 }
1373 #endif
1374
1375 // set server list URL
1376 if (BZDB.isSet("list"))
1377 startupInfo.listServerURL = BZDB.get("list");
1378
1379 // setup silence list
1380 std::vector<std::string>& list = getSilenceList();
1381
1382 // search for entries silencedPerson0 silencedPerson1 etc..
1383 // to the database. Stores silenceList
1384 // By only allowing up to a certain # of people can prevent
1385 // the vague chance of buffer overrun.
1386 const int bufferLength = 30;
1387 const int maxListSize = 1000000; // do even that many play bzflag?
1388 char buffer [bufferLength];
1389 bool keepGoing = true;
1390
1391 for (int s = 0; keepGoing && (s < maxListSize); s++)
1392 {
1393 sprintf(buffer,"silencedPerson%d",s); // could do %-10d
1394
1395 if (BZDB.isSet(buffer))
1396 {
1397 list.push_back(BZDB.get(buffer));
1398 // remove the value from the database so when we save
1399 // it saves the list's new values in order
1400 BZDB.unset(buffer);
1401 }
1402 else
1403 keepGoing = false;
1404 }
1405
1406 if (BZDB.isSet("serverCacheAge"))
1407 (ServerListCache::get())->setMaxCacheAge(atoi(BZDB.get("serverCacheAge").c_str()));
1408
1409 // start playing
1410 startPlaying(display, RENDERER);
1411
1412 // save resources
1413 if (BZDB.isTrue("saveSettings"))
1414 {
1415 dumpResources();
1416 if (alternateConfig == "")
1417 CFGMGR.write(getCurrentConfigFileName());
1418 else
1419 CFGMGR.write(alternateConfig);
1420 }
1421
1422 // shut down
1423
1424
1425 killGlobalAres();
1426 AresHandler::globalShutdown();
1427
1428 if (filter != NULL)
1429 delete filter;
1430 filter = NULL;
1431 display->setDefaultResolution();
1432 delete pmainWindow;
1433 delete joystick;
1434 delete window;
1435 delete visual;
1436 closeSound();
1437 delete display;
1438 delete platformFactory;
1439 delete bm;
1440 Flags::kill();
1441
1442 #ifdef _WIN32
1443 // clean up
1444 WSACleanup();
1445 #endif
1446
1447 // clean up singletons
1448 // delete FILEMGR;
1449 // delete CMDMGR;
1450 // delete BZDB;
1451
1452 return 0;
1453 }
1454 //
1455 #if defined(_WIN32) && !defined(HAVE_SDL)
1456
1457 //
1458 // WinMain()
1459 // windows entry point. forward to main()
1460 //
1461
WinMain(HINSTANCE instance,HINSTANCE,LPSTR _cmdLine,int)1462 int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR _cmdLine, int)
1463 {
1464 // convert command line to argc and argv. note that it's too late
1465 // to do this right because spaces that were embedded in a single
1466 // argument now look like like normal spaces. not much we can do
1467 // about that.
1468 // FIXME -- argc and argv can be accessible; use them instead of this.
1469 char* cmdLine = strdup(_cmdLine);
1470
1471 // count number of arguments
1472 int argc = 1;
1473 char* scan = cmdLine;
1474 while (isspace(*scan) && *scan != 0) scan++;
1475 while (*scan)
1476 {
1477 argc++;
1478 while (!isspace(*scan) && *scan != 0) scan++;
1479 while (isspace(*scan) && *scan != 0) scan++;
1480 }
1481
1482 // get path to application. this is ridiculously simple.
1483 char appName[MAX_PATH];
1484 GetModuleFileName(instance,appName,MAX_PATH);
1485
1486 // make argument list and assign arguments
1487 char** argv = new char*[argc];
1488 argc = 0;
1489 argv[argc++] = appName;
1490 scan = cmdLine;
1491 while (isspace(*scan) && *scan != 0) scan++;
1492 while (*scan)
1493 {
1494 argv[argc++] = scan;
1495 while (!isspace(*scan) && *scan != 0) scan++;
1496 if (*scan) *scan++ = 0;
1497 while (isspace(*scan) && *scan != 0) scan++;
1498 }
1499
1500 const int exitCode = myMain(argc, argv);
1501
1502 // clean up and return exit code
1503 delete[] argv;
1504 free(cmdLine);
1505 return exitCode;
1506 }
1507
1508 #endif /* defined(_WIN32) */
1509
1510
1511 // Local Variables: ***
1512 // mode: C++ ***
1513 // tab-width: 4 ***
1514 // c-basic-offset: 4 ***
1515 // indent-tabs-mode: nil ***
1516 // End: ***
1517 // ex: shiftwidth=4 tabstop=4
1518