Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

894 lines
21 KiB

  1. #========= Copyright 1996-2008, Valve Corporation, All rights reserved. ==========
  2. #
  3. # Master script for performing automated compiles of bsp's with cubemaps, reslists,
  4. # and nodegraphs. Compiles can be triggered manually by adding the vmf's absolute
  5. # path to mapbuild\forcelist.txt, or by adding the "autocompile" keyword
  6. # to the checkin comments for a vmf.
  7. #
  8. #=================================================================================
  9. use strict;
  10. use warnings;
  11. use Net::SMTP;
  12. my $maxCompiles = 3; # Maximum number of simultaneous compiles.
  13. my $running = 0;
  14. my @g_CompileList;
  15. my @finalizeList;
  16. my @g_Finalizing;
  17. my @g_CompileThreads;
  18. my %g_ToolArgs;
  19. my %g_RunningCompiles;
  20. my @g_OutputFiles;
  21. my $g_FilenameIdx = 0;
  22. my @g_MainDirs;
  23. my $g_MainDirIdx = 0;
  24. my @g_MapsToBuild;
  25. my $buildbsp = 1; # Compile the bsp with vbsp, vvis, and vrad
  26. my $buildreslists = 1; # Build reslists for the map
  27. my $buildnodegraphs = 1; # Build the nodegraph (.ain) for the map
  28. my $rootdir = "..\\..\\..\\.."; # Relative path from this script to one level above the "main" directory
  29. system( "echo. > finalize.txt" );
  30. $SIG{CHLD}='IGNORE';
  31. # Generate filenames for the compile output files
  32. for ( my $ct = 0; $ct < $maxCompiles * 2; ++$ct )
  33. {
  34. my $filename = join( '', "$rootdir\\main1\\src\\devtools\\mapbuild\\buildqueue", $g_FilenameIdx++, ".txt" );
  35. push( @g_OutputFiles, $filename );
  36. }
  37. # Generate main directory names for each simultaneous compile
  38. for ( my $ct = 1; $ct <= $maxCompiles; ++$ct )
  39. {
  40. my $filename = join( '', "main", $ct );
  41. push( @g_MainDirs, $filename );
  42. }
  43. # Loop for infinity. If changes are made to this script, the process needs to
  44. # be killed and restarted for those changes to take effect. Note, any maps that
  45. # are compiling or waiting in the queue will NOT be picked up again when the script
  46. # is restarted. Any maps that were compiling or waiting to compile when the process
  47. # was stopped will need to be started manually by adding the vmf absolute path
  48. # to forcelist.txt. A map can be manually added to the queue at any time while the script
  49. # is running by adding the vmf absolute path to forcelist.txt.
  50. while ( 1 )
  51. {
  52. # Generate a list of maps that need to be built. For vmf's that have been changed in
  53. # Perforce, the checkin comments are parsed and if the word "autocompile"
  54. # is found then that map will be added to the build list. All maps that are listed in
  55. # forcelist.txt are also added to the build list.
  56. syncChangedMaps();
  57. # Append the maps to the build queue while filtering out duplicates. We only
  58. # want to filter duplicates out of the queue - if a map is already compiling
  59. # then it's reasonable to add it to the queue again because it must have changed
  60. # since the current build began.
  61. my $updated = 0;
  62. for my $map ( @g_MapsToBuild )
  63. {
  64. if ( $map =~ /(\w*.vmf)/ )
  65. {
  66. # make sure it's not already in the queue
  67. my $duplicate = 0;
  68. my $testname = $1;
  69. for ( @g_CompileList )
  70. {
  71. if ( /$testname/ )
  72. {
  73. $duplicate = 1;
  74. last;
  75. }
  76. }
  77. system( "echo. >> log.txt" );
  78. if ( $duplicate != 1 )
  79. {
  80. print( "Adding to compile list $map\n" );
  81. system( "echo Adding to compile list $map >> log.txt" );
  82. push( @g_CompileList, $map );
  83. $updated = 1;
  84. }
  85. else
  86. {
  87. print( "Duplicate map found: $testname\n" );
  88. system( "echo Duplicate map found: $testname >> log.txt" );
  89. }
  90. }
  91. }
  92. splice( @g_MapsToBuild );
  93. # If there is a build slot open, start building the next map
  94. StartCompiles();
  95. sleep( 60 ); # Time is arbitrary - just don't spam Perforce
  96. # Load in the finalize queue
  97. open( INFILE, "<finalize.txt" );
  98. my @finalizeList = <INFILE>;
  99. close( INFILE );
  100. system( "echo. > finalize.txt" );
  101. # Finalize the maps (cubemaps, reslist, nodegraph, and checkin). The finalize list
  102. # also contains the compile output (times,args,etc.) that need to go in the checkin comments.
  103. my $maindir = "";
  104. my $mod = "";
  105. my $mapname = "";
  106. my $strTime = "";
  107. my $vbspargs = "";
  108. my $vvisargs = "";
  109. my $vradargs = "";
  110. my $outfile = "";
  111. for ( @finalizeList )
  112. {
  113. if ( /Finalize: (\w*) (\w*)/ )
  114. {
  115. $mod = $1;
  116. $mapname = $2;
  117. next;
  118. }
  119. elsif ( /maindir: (.*)/ )
  120. {
  121. $maindir = $1;
  122. next;
  123. }
  124. elsif ( /vbspargs: (.*)/ )
  125. {
  126. $vbspargs = $1;
  127. next;
  128. }
  129. elsif ( /vvisargs: (.*)/ )
  130. {
  131. $vvisargs = $1;
  132. next;
  133. }
  134. elsif ( /vradargs: (.*)/ )
  135. {
  136. $vradargs = $1;
  137. next;
  138. }
  139. elsif ( /time: (.*)/ )
  140. {
  141. $strTime = $1;
  142. next;
  143. }
  144. elsif ( /outfile: (.*)/ )
  145. {
  146. # This is the final entry for a map
  147. $outfile = $1;
  148. }
  149. else
  150. {
  151. next;
  152. }
  153. print( "\nFinalizing $mod\\$mapname.bsp\n" );
  154. system( "echo Finalizing $mapname.bsp >> log.txt" );
  155. # A compile slot has opened up
  156. --$running;
  157. push( @g_Finalizing, $mapname );
  158. # Let another compile start in the just-emptied slot.
  159. StartCompiles();
  160. my $ldrResult = 0;
  161. my $hdrResult = 0;
  162. # HACK: Make sure a zombie process can't hold up the system
  163. system( "taskkill /im hl2.exe /f" );
  164. chdir( "$rootdir\\$maindir\\src\\devtools\\mapbuild" );
  165. # Get the Perforce client and owner names for the checkin file
  166. my $g_client;
  167. my $g_owner;
  168. my @clientspec = readpipe "p4 client -o";
  169. for ( @clientspec )
  170. {
  171. if ( /^Client:[\s*](.*)/ )
  172. {
  173. $g_client = $1;
  174. print( "Using client $g_client\n" );
  175. }
  176. elsif ( /^Owner:[\s*](.*)/ )
  177. {
  178. $g_owner = $1;
  179. print( "Using owner $g_owner\n" );
  180. }
  181. }
  182. if ( $buildbsp == 1 )
  183. {
  184. # Build cubemaps
  185. system( "echo. >> $outfile" );
  186. system( "time /t >> $outfile" );
  187. system( "echo Building cubemaps for $mapname. >> $outfile" );
  188. if ( $vradargs =~ /-hdr|-both/ )
  189. {
  190. $hdrResult = system( "$rootdir\\$maindir\\game\\hl2.exe -allowdebug -game $mod -window -w 1152 -h 864 +mat_picmip 0 -dev +mat_hdr_level 2 +sv_cheats 1 +map $mapname -buildcubemaps" );
  191. }
  192. if ( $vradargs =~ /-ldr|-both/ )
  193. {
  194. $ldrResult = system( "$rootdir\\$maindir\\game\\hl2.exe -allowdebug -game $mod -window -w 1152 -h 864 +mat_picmip 0 -dev +mat_hdr_level 0 +sv_cheats 1 +map $mapname -buildcubemaps" );
  195. }
  196. }
  197. if ( $buildreslists == 1 )
  198. {
  199. system( "echo. >> $outfile" );
  200. system( "time /t >> $outfile" );
  201. system( "echo Building reslists and nodegraph for $mapname. >> $outfile" );
  202. system( "del /s $rootdir\\$maindir\\game\\$mod\\reslists_temp\\*.lst" );
  203. system( "p4 edit $rootdir\\$maindir\\game\\$mod\\reslists_xbox\\$mapname.lst" );
  204. system( "p4 add $rootdir\\$maindir\\game\\$mod\\reslists_xbox\\$mapname.lst" );
  205. system( "del $rootdir\\$maindir\\game\\$mod\\reslists_xbox\\$mapname.lst" );
  206. my $extraflags = "";
  207. # if ( $mod =~ /portal/ )
  208. # {
  209. # $extraflags = "-tempcontent";
  210. # }
  211. system( "del \/s $rootdir\\$maindir\\game\\modelsounds.cache" );
  212. system( "$rootdir\\$maindir\\game\\hl2.exe -allowdebug -game $mod -window -dev -makereslists makereslists_xbox.txt $extraflags +map $mapname" );
  213. }
  214. elsif ( $buildnodegraphs == 1 )
  215. {
  216. # system( "p4 edit $rootdir\\$maindir\\game\\$mod\\maps\\graphs\\$mapname.ain >> log.txt" );
  217. # TODO: Build nodegraphs method. Currently we get this for free when building reslists.
  218. }
  219. # Generate the checkin file
  220. system( "echo. >> $outfile" );
  221. system( "time /t >> $outfile" );
  222. system( "echo Submitting to Perforce. >> $outfile" );
  223. open( OUTFILE, ">checkin.txt" );
  224. print( OUTFILE "Change: new\n\n" );
  225. print( OUTFILE "Client: $g_client\n\n" );
  226. print( OUTFILE "User: $g_owner\n\n" );
  227. print( OUTFILE "Status: new\n\n" );
  228. print( OUTFILE "Description: Autobuild for map $mapname.bsp\n" );
  229. print( OUTFILE "\n" );
  230. if ( $hdrResult == 1 )
  231. {
  232. print( OUTFILE "\tWARNING! There was an error while building HDR cubemaps.\n" );
  233. print( OUTFILE "\tHDR Cubemaps may need to be rebuilt before using this map.\n\n" );
  234. }
  235. if ( $ldrResult == 1 )
  236. {
  237. print( OUTFILE "\tWARNING! There was an error while building LDR cubemaps.\n" );
  238. print( OUTFILE "\tLDR Cubemaps may need to be rebuilt before using this map.\n\n" );
  239. }
  240. if ( $buildbsp == 1 )
  241. {
  242. print( OUTFILE "\tCOMPILE ARGS\n" );
  243. print( OUTFILE "\tvbsp:\t",$vbspargs,"\n" );
  244. print( OUTFILE "\tvvis:\t",$vvisargs,"\n" );
  245. print( OUTFILE "\tvrad:\t",$vradargs,"\n" );
  246. print( OUTFILE "\n" );
  247. print( OUTFILE "\tBuild time: $strTime\n" );
  248. print( OUTFILE "\n" );
  249. }
  250. # Add the comments from the last checkin of this map
  251. system( "p4 changes -m 1 -s submitted -l $rootdir\\$maindir\\content\\$mod\\maps\\$mapname.vmf > comments.txt" );
  252. open(INFILE, "comments.txt");
  253. my @comments = <INFILE>;
  254. close(INFILE);
  255. if ( $buildbsp == 1 )
  256. {
  257. print( OUTFILE "\tCheckin Comments: " );
  258. print( OUTFILE @comments,"\n\n" );
  259. print( OUTFILE "\tRebuilt bsp\n" );
  260. }
  261. if ( $buildnodegraphs == 1 )
  262. {
  263. print( OUTFILE "\n\tRebuilt nodegraph\n" );
  264. }
  265. if ( $buildreslists == 1 )
  266. {
  267. print( OUTFILE "\n\tRebuilt reslist\n" );
  268. }
  269. print( OUTFILE "Files:\n" );
  270. if ( $buildbsp == 1 )
  271. {
  272. print( OUTFILE "\t//ValveGames/staging/game/$mod/maps/$mapname.bsp\n" );
  273. }
  274. if ( $buildnodegraphs == 1 )
  275. {
  276. # Copy up to fileserver
  277. system( "copy $rootdir\\$maindir\\game\\$mod\\maps\\graphs\\$mapname.ain \"\\\\fileserver\\user\\xbox\\xbox_orange\\graphs\\$mod\\$mapname.ain\"" );
  278. }
  279. if ( $buildreslists == 1 )
  280. {
  281. print( OUTFILE "\t//ValveGames/staging/game/$mod/reslists_xbox/$mapname.lst\n" );
  282. }
  283. close( OUTFILE );
  284. # Check in the map
  285. system( "p4 submit -i < checkin.txt >> log.txt" );
  286. # Send the build output in an email to the submitter
  287. my $email = "kerry\@valvesoftware.com";
  288. for ( @comments )
  289. {
  290. if ( /Change \d* on \S* by (\w*)@/ )
  291. {
  292. $email = join( '@', $1, "valvesoftware.com" );
  293. }
  294. }
  295. open(INFILE, "$outfile");
  296. my @compileoutput = <INFILE>;
  297. close(INFILE);
  298. my$smtp;
  299. $smtp = Net::SMTP->new('exchange2.valvesoftware.com');
  300. $smtp->mail("Mapbuilder");
  301. $smtp->to("$email");
  302. $smtp->data();
  303. $smtp->datasend( "To: $email\n" );
  304. $smtp->datasend( "Subject: $mapname has finished compiling.\n" );
  305. $smtp->datasend( @comments );
  306. $smtp->datasend( @compileoutput );
  307. $smtp->dataend();
  308. $smtp->quit;
  309. delete( $g_RunningCompiles{$outfile} );
  310. splice( @g_Finalizing );
  311. chdir( "$rootdir\\main1\\src\\devtools\\mapbuild" );
  312. }
  313. } # end while(1)
  314. #----------------------------------------
  315. # Start a compile if there is an open slot
  316. #----------------------------------------
  317. sub StartCompiles
  318. {
  319. my $idx = 0;
  320. print( "Current maplist:\n" );
  321. for ( @g_CompileList )
  322. {
  323. print( "$_\n" );
  324. }
  325. my $skipCt = 0;
  326. while ( @g_CompileList > $skipCt && $running < $maxCompiles )
  327. {
  328. my $nextMap = splice( @g_CompileList, 0, 1 );
  329. # Make sure this map isn't already compiling in another slot
  330. my $duplicate = 0;
  331. for ( values %g_RunningCompiles )
  332. {
  333. $nextMap =~ /(\w*).vmf/;
  334. if ( /^$1$/ )
  335. {
  336. system( "echo $nextMap already compiling - skipping for now. >> log.txt" );
  337. push @g_CompileList, $nextMap;
  338. ++$skipCt;
  339. $duplicate = 1;
  340. last;
  341. }
  342. }
  343. if ( $duplicate == 0 )
  344. {
  345. Compile( $nextMap );
  346. ++$running;
  347. ++$idx;
  348. my $mapct = @g_CompileList;
  349. system( "echo Maps waiting: $mapct >> log.txt" );
  350. }
  351. }
  352. UpdateStats();
  353. }
  354. #-----------------------------------------------------------
  355. # Compile a single map - this subroutine forks the process
  356. #-----------------------------------------------------------
  357. sub Compile
  358. {
  359. # sync the rest of the content and bins.
  360. my $maindir = $g_MainDirs[$g_MainDirIdx];
  361. $g_MainDirIdx = ( $g_MainDirIdx + 1 ) % $maxCompiles;
  362. chdir( "$rootdir\\$maindir\\src\\devtools\\mapbuild" );
  363. system( "p4 sync $rootdir\\$maindir\\game\\..." );
  364. system( "p4 sync $rootdir\\$maindir\\src\\..." );
  365. # parse the map and mod name from the full path
  366. my $fullpath = shift;
  367. my $mod;
  368. my $mapname;
  369. if ( $fullpath =~ /(\w*)\\maps\\(\w*).vmf/ )
  370. {
  371. $mod = $1;
  372. $mapname = $2;
  373. }
  374. else
  375. {
  376. print( "Error getting map name and mod\n" );
  377. exit();
  378. }
  379. # Get the next output file. All output from the build tools
  380. # (vbsp,vvis,vrad) will be redirected to this file.
  381. my $outfile = undef;
  382. for ( @g_OutputFiles )
  383. {
  384. unless ( defined $g_RunningCompiles{$_} )
  385. {
  386. $outfile = $_;
  387. last;
  388. }
  389. }
  390. unless ( defined $outfile )
  391. {
  392. my $filename = join( '', "buildqueue", $g_FilenameIdx++, ".txt" );
  393. push( @g_OutputFiles, $filename );
  394. $outfile = $filename;
  395. }
  396. $g_RunningCompiles{$outfile} = $mapname;
  397. # Force-sync the vmf and bsp
  398. system( "echo Compiling $mod\\$mapname.bsp > $outfile" );
  399. system( "echo. >> log.txt" );
  400. system( "date /t >> log.txt" );
  401. system( "time /t >> log.txt" );
  402. system( "echo Compling $mod\\$mapname.bsp >> log.txt" );
  403. system( "p4 sync -f ..\\..\\..\\content\\$mod\\maps\\$mapname.vmf >> log.txt" );
  404. system( "p4 sync -f $rootdir\\$maindir\\content\\$mod\\maps\\$mapname.vmf >> log.txt" );
  405. system( "p4 sync -f $rootdir\\$maindir\\game\\$mod\\maps\\$mapname.bsp >> log.txt" );
  406. if ( $buildbsp == 1 )
  407. {
  408. print "\nCompiling $mod\\$mapname.bsp\n";
  409. # load the map compile args for this mod
  410. if( !open( INFILE, "$rootdir\\$maindir\\game\\$mod\\scripts\\mapautocompile.txt") )
  411. {
  412. print( "Error opening autocompile.txt\n" );
  413. }
  414. my @lines = <INFILE>;
  415. close (INFILE);
  416. my $tool;
  417. my $rest;
  418. my $toolmap;
  419. for ( @lines )
  420. {
  421. if ( /map: (.*)/ )
  422. {
  423. $toolmap = $1;
  424. }
  425. elsif ( /\s+(.+)/ )
  426. {
  427. ($tool, $rest) = split ( /:\s*/, $1, 2 );
  428. $g_ToolArgs{$toolmap}{$tool} = $rest;
  429. }
  430. }
  431. # Open the bsp for edit
  432. system( "p4 edit $rootdir\\$maindir\\game\\$mod\\maps\\$mapname.bsp" );
  433. system( "p4 add $rootdir\\$maindir\\game\\$mod\\maps\\$mapname.bsp" );
  434. system( "del $rootdir\\$maindir\\game\\$mod\\maps\\$mapname.bsp" );
  435. }
  436. chdir( "$rootdir\\main1\\src\\devtools\\mapbuild" );
  437. #--------------------------------------
  438. # fork this compile to a new process
  439. #--------------------------------------
  440. my $pid = fork();
  441. print "fork failed!" unless defined $pid;
  442. if ( $pid != 0 )
  443. {
  444. # I am the parent
  445. return;
  446. }
  447. my $strTime = "";
  448. my $vbspargs = "";
  449. my $vvisargs = "";
  450. my $vradargs = "";
  451. chdir( "$rootdir\\$maindir\\src\\devtools\\mapbuild" );
  452. if ( $buildbsp == 1 )
  453. {
  454. # Compile
  455. # delete the bsp to ensure that vbsp succeeded
  456. system( "del $rootdir\\$maindir\\content\\$mod\\maps\\$mapname.bsp" );
  457. my $startTime = time;
  458. $vbspargs = compileTool( $maindir, $mod, $mapname, "vbsp", $outfile );
  459. $vvisargs = compileTool( $maindir, $mod, $mapname, "vvis", $outfile );
  460. $vradargs = compileTool( $maindir, $mod, $mapname, "vrad", $outfile );
  461. my $totalTime = time - $startTime;
  462. my $hours = int($totalTime / 3600);
  463. $totalTime -= ($hours * 3600);
  464. my $minutes = int( $totalTime / 60 );
  465. $totalTime -= ($minutes * 60);
  466. my $seconds = $totalTime;
  467. $strTime = sprintf( "%02d:%02d:%02d", $hours, $minutes, $seconds );
  468. }
  469. chdir( "$rootdir\\main1\\src\\devtools\\mapbuild" );
  470. # Add the map's name to the finalize list
  471. while( !open( OUTFILE, ">>finalize.txt" ) ) {}
  472. print OUTFILE "Finalize: $mod $mapname\n";
  473. print OUTFILE "maindir: $maindir\n";
  474. if ( $buildbsp == 1 )
  475. {
  476. # Output the compile args and time
  477. print OUTFILE "vbspargs: $vbspargs\n";
  478. print OUTFILE "vvisargs: $vvisargs\n";
  479. print OUTFILE "vradargs: $vradargs\n";
  480. print OUTFILE "time: $strTime\n";
  481. }
  482. print OUTFILE "outfile: $outfile\n";
  483. close( OUTFILE );
  484. # This child is finished
  485. exit();
  486. }
  487. #----------------------------------------
  488. # Run a map build tool (vbsp, vvis, vrad)
  489. #----------------------------------------
  490. sub compileTool
  491. {
  492. my $maindir = shift;
  493. my $mod = shift;
  494. my $map = shift;
  495. my $tool = shift;
  496. my $outfile = shift;
  497. # Load the compile arguments that were parsed from mapautocompile.txt.
  498. # If the map has its own custom args, then use those - otherwise,
  499. # just use the default set.
  500. my $toolArgs = $g_ToolArgs{"default"}{$tool};
  501. if ( exists $g_ToolArgs{$map}{$tool} )
  502. {
  503. $toolArgs = $g_ToolArgs{$map}{$tool};
  504. }
  505. system( "echo. >> $outfile" );
  506. system( "time /t >> $outfile" );
  507. system( "echo Starting $tool for $map >> $outfile" );
  508. system( "echo. >> $outfile" );
  509. # HACK: There is a crash bug when using -both in vrad. If the -both
  510. # flags is present, remove it and do two vrad compiles with -ldr and -hdr.
  511. if ( $tool =~ /vrad/ && $toolArgs =~ /-both/ )
  512. {
  513. system( "echo Found -both argument. Splitting into -ldr and -hdr >> $outfile" );
  514. my $newArgs = $toolArgs;
  515. $newArgs =~ s/-both //;
  516. system( "$rootdir\\$maindir\\game\\bin\\$tool -vproject $rootdir\\$maindir\\game\\$mod $newArgs -ldr $rootdir\\$maindir\\content\\$mod\\maps\\$map >> $outfile" );
  517. system( "$rootdir\\$maindir\\game\\bin\\$tool -vproject $rootdir\\$maindir\\game\\$mod $newArgs -hdr $rootdir\\$maindir\\content\\$mod\\maps\\$map >> $outfile" );
  518. }
  519. else
  520. {
  521. system( "$rootdir\\$maindir\\game\\bin\\$tool -vproject $rootdir\\$maindir\\game\\$mod $toolArgs $rootdir\\$maindir\\content\\$mod\\maps\\$map >> $outfile" );
  522. }
  523. # copy the new bsp into the maps directory
  524. system( "copy /Y $rootdir\\$maindir\\content\\$mod\\maps\\$map.bsp $rootdir\\$maindir\\game\\$mod\\maps" );
  525. system( "echo. >> $outfile" );
  526. system( "echo Finished >> $outfile" );
  527. return $toolArgs;
  528. }
  529. #-----------------------------------
  530. # Check if this map should build now
  531. #-----------------------------------
  532. sub syncChangedMaps
  533. {
  534. # TODO: Get these mod names from a file?
  535. my @mods = ( "ep2", "portal", "episodic", "hl2", "tf" );
  536. # Query perforce for changed maps by doing a speculative sync. This generates a list
  537. # of files that it WOULD sync, without actually doing the sync.
  538. # BUG: This doesn't return new files that have been added - don't know why yet.
  539. my @maps;
  540. for my $mod ( @mods )
  541. {
  542. push ( @maps, readpipe "p4 sync -n ..\\..\\..\\content\\$mod\\maps\\*.vmf" );
  543. }
  544. # forcelist.txt allows maps to be manually added to the build.
  545. open(INFILE, "forcelist.txt");
  546. my @forcemaps = <INFILE>;
  547. close( INFILE );
  548. system( "echo. > forcelist.txt" );
  549. # Run through the list of maps to see if any should be built
  550. for( @maps)
  551. {
  552. if( /updating (.*)|adding (.*)/ )
  553. {
  554. # Check if this map should be built now
  555. if ( shouldBuild( $1 ) == 0 )
  556. {
  557. next;
  558. }
  559. # Add this map name to the build list
  560. system( "p4 sync -f $1" );
  561. push( @g_MapsToBuild, $1 );
  562. system( "echo Adding to the build list: $1 >> log.txt" );
  563. }
  564. }
  565. for( @forcemaps )
  566. {
  567. if ( /\.vmf/ )
  568. {
  569. # Add this map name to the build list
  570. $_ =~ /(.*)/;
  571. system( "p4 sync -f $1" );
  572. push( @g_MapsToBuild, $1 );
  573. system( "echo Forcing add to the build list: $1 >> log.txt" );
  574. }
  575. }
  576. }
  577. #-----------------------------------
  578. # Check if this map should build now
  579. #-----------------------------------
  580. sub shouldBuild
  581. {
  582. my $map = shift;
  583. # if the map line contains the force flag, build the map
  584. if ( $map =~ /-forcebuild/ )
  585. {
  586. return 1;
  587. }
  588. # Get the comments from the last checkin of this map
  589. # and look for the autocompile keyword
  590. my @comments = readpipe "p4 changes -m 1 -s submitted -l $map";
  591. for( @comments )
  592. {
  593. if ( /autocompile/i )
  594. {
  595. return 1;
  596. }
  597. }
  598. return 0;
  599. }
  600. #----------------------------------------------------------------------------------
  601. # Hacky little routine to build an html file that contains the current state
  602. # of the autocompiler (running, maps building, maps waiting, etc.) and a frameset
  603. # that shows the compile output for each map that's currently building. This way
  604. # users of the autocompiler can keep an eye on their map's progress.
  605. #----------------------------------------------------------------------------------
  606. sub UpdateStats
  607. {
  608. my $noCompiles = 0;
  609. my $noWaiting = 0;
  610. if ( keys( %g_RunningCompiles ) == 0 && @g_Finalizing == 0 )
  611. {
  612. $noCompiles = 1;
  613. }
  614. if ( @g_CompileList == 0 )
  615. {
  616. $noWaiting = 1;
  617. }
  618. # Start building the main html page
  619. open( OUTFILE, ">buildlist.htm" );
  620. print( OUTFILE "<html>\n" );
  621. print( OUTFILE "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"10; URL=buildlist.htm\">\n" );
  622. print( OUTFILE "Mapbuilder state: <font color=#009900><b>" );
  623. if ( $noCompiles == 1 && $noWaiting == 1 )
  624. {
  625. print( OUTFILE "Ready</b></font><br>\n" );
  626. }
  627. else
  628. {
  629. print( OUTFILE "RUNNING</b></font><br>\n" );
  630. }
  631. print( OUTFILE "Max simultaneous compiles: $maxCompiles\n" );
  632. print( OUTFILE "<p>\n" );
  633. print( OUTFILE "<b>Active:</b>\n<p>\n" );
  634. # Show a list of maps that are currently compiling
  635. my $filect = 0;
  636. if ( $noCompiles == 1 )
  637. {
  638. print( OUTFILE "None" );
  639. }
  640. else
  641. {
  642. for ( @g_OutputFiles )
  643. {
  644. if ( defined( $g_RunningCompiles{$_} ) )
  645. {
  646. my $testname = $g_RunningCompiles{$_};
  647. my $filename = $_;
  648. if ( $filename =~ /(\w*\.txt)/ )
  649. {
  650. $filename = $1;
  651. }
  652. my $finishing = 0;
  653. for ( @g_Finalizing )
  654. {
  655. if ( /$testname/ )
  656. {
  657. $finishing = 1;
  658. }
  659. }
  660. print( OUTFILE "<a href=\"$filename\" TARGET=\"_parent\">$testname.bsp</a>" );
  661. ++$filect;
  662. if ( $finishing == 1 )
  663. {
  664. print( OUTFILE " - Finishing (cubemaps, reslist, nodegraph.)\n<br>\n" );
  665. }
  666. else
  667. {
  668. print( OUTFILE " - Compiling\n<br>\n" );
  669. }
  670. }
  671. }
  672. }
  673. # Show a list of maps that are waiting to compile
  674. print( OUTFILE "<p>\n<b>Waiting:</b>\n<p>\n" );
  675. if ( $noWaiting == 1 )
  676. {
  677. print( OUTFILE "None" );
  678. }
  679. else
  680. {
  681. for ( @g_CompileList )
  682. {
  683. /(\w*).vmf/;
  684. print( OUTFILE "$1.bsp\n<br>\n" );
  685. }
  686. }
  687. print( OUTFILE "</html>\n" );
  688. close( OUTFILE );
  689. # create the main page
  690. open( OUTFILE, ">buildqueue.htm" );
  691. print( OUTFILE "<html>\n" );
  692. print( OUTFILE "<META HTTP-EQUIV=\"Refresh\" CONTENT=\"30; URL=buildqueue.htm\">\n" );
  693. my $size = 0;
  694. if ( $filect != 0 )
  695. {
  696. print( OUTFILE "<frameset rows=\"30%" );
  697. $size = 70 / $filect;
  698. }
  699. else
  700. {
  701. print( OUTFILE "<frameset rows=\"100%" );
  702. }
  703. for ( my $ct = 0; $ct < $filect; ++$ct )
  704. {
  705. print( OUTFILE ",$size%" );
  706. }
  707. print( OUTFILE "\">\n" );
  708. print( OUTFILE "<frame src=\"buildlist.htm\">\n" );
  709. for ( @g_OutputFiles )
  710. {
  711. if ( defined( $g_RunningCompiles{$_} ) )
  712. {
  713. my $filename = $_;
  714. if ( $filename =~ /(\w*\.txt)/ )
  715. {
  716. $filename = $1;
  717. }
  718. print( OUTFILE "<frame src=\"$filename\">\n" );
  719. }
  720. }
  721. print( OUTFILE "</frameset>\n" );
  722. print( OUTFILE "</html>\n" );
  723. close( OUTFILE );
  724. }