<?php mysql_connect("localhost", "hlstatsx", "1WHbqyE7SjUkV6pq"); mysql_select_db("hlstatsx"); $map = "ministry_coop"; //Maps array holds all map data $maps = array(); $map_objects = array(); //Get all map text files. This could probably be safer. $files = glob("maps/overviews/*.txt"); //Include key-value reader require_once "kvreader2.php"; $reader = new KVReader(); //Open all files and add gamemodes and other map info to array foreach ($files as $file) { $mapname = basename($file, ".txt"); $data = $reader->read(strtolower(file_get_contents("maps/{$mapname}.txt"))); $maps[$mapname]['gametypes'] = current($data); if (isset($maps[$mapname]['gametypes']['theater_conditions'])) { $maps[$mapname]['theater_conditions'] = $maps[$mapname]['gametypes']['theater_conditions']; unset($maps[$mapname]['gametypes']['theater_conditions']); } //Get overview information (file, position, scale) $lines = file("maps/overviews/{$mapname}.txt", FILE_IGNORE_NEW_LINES); foreach ($lines as $line) { $data = explode("\t", preg_replace('/\\s+/', "\t", str_replace('"', '', trim($line)))); if (isset($data[1])) { $maps[$mapname]['overview'][$data[0]] = $data[1]; //var_dump($data); } } }
function ParseMap($mapname, $force = 0) { global $datapath, $linebreak, $gametypelist, $mapdata_version; $entities_key = 'entities'; $points_key = 'points'; $controlpoints = array(); $map_objects = array(); $map = array(); $reader = new KVReader(); $dstfile = GetDataFile("maps/parsed/{$mapname}.json", null, null, -2); if (file_exists($dstfile)) { $dstdata = json_decode(file_get_contents($dstfile), true); } $srcfiles = array("CPSetup" => GetDataFile("maps/{$mapname}.txt"), "Overview" => GetDataFile("resource/overviews/{$mapname}.txt"), "VMF Source" => GetDataFile("maps/src/{$mapname}_d.vmf")); foreach ($srcfiles as $name => $file) { if (!file_exists($file)) { echo "FAIL: Missing {$name} \"{$file}\"!{$linebreak}"; return; } // Get MD5 of source file $map['source_files'][$name] = md5_file($file); } $map['mapdata_version'] = $mapdata_version; // TODO: Proper KeyValues parser!!! // Load cpsetup.txt //echo "loading cpsetup\n"; $data = $reader->read(strtolower(file_get_contents($srcfiles["CPSetup"]))); //echo "done loading cpsetup\n"; // Merge in bases foreach ($data as $name => $item) { if ($name == "#base") { //echo "found bases\n"; if (!is_array($item)) { $item = array($item); } foreach ($item as $base) { //echo "merging {$base}\n"; $data = array_merge_recursive($reader->read(strtolower(file_get_contents(GetDataFile("maps/{$base}")))), $data); } unset($data[$name]); } } //var_dump($data); // Process all nodes foreach ($data as $name => $item) { if (is_array($item)) { foreach ($item as $key => $val) { if (in_array($key, array_keys($gametypelist))) { $map['gametypes'][$key] = $val; } else { $map['CPSetup'][$key] = $val; } } } } //var_dump($map); // Load Overview //echo "starting load overview\n"; //Get overview information (file, position, scale) $lines = file($srcfiles["Overview"], FILE_IGNORE_NEW_LINES); foreach ($lines as $line) { $data = explode("\t", preg_replace('/\\s+/', "\t", str_replace('"', '', trim($line)))); if (isset($data[1])) { $map['overview'][$data[0]] = is_numeric($data[1]) ? (double) $data[1] : $data[1]; } } //echo "done load overview\n"; // Load VMF Source //Parse the decompiled VMF file if (file_exists($srcfiles["VMF Source"])) { //echo "start load vmf source\n"; // Remove non-printable characters to make processing easier // Change to lowercase to make array indexing simpler $data = preg_replace('/[\\x00-\\x08\\x14-\\x1f]+/', '', strtolower(file_get_contents($srcfiles["VMF Source"]))); // Quote all unquoted keys $data = preg_replace('/(\\s*)([a-zA-Z0-9]+)(\\s*{)/', '${1}"${2}"${3}', $data); // Get all nested objects preg_match_all('~[^{}]+ { ( (?>[^{}]+) | (?R) )* } ~x', $data, $matches); // Process entities //echo "start process entities\n"; //var_dump($matches[0]); foreach ($matches[0] as $rawent) { // Read in KV $object = $reader->read($rawent); $type = implode('', array_keys($object)); if ($type == "entity") { $entity = $object[$type]; } else { continue; } //Only interested in certain entities $classnames = array("trigger_capture_zone", "point_controlpoint", "obj_weapon_cache", "ins_spawnzone", "ins_blockzone"); if (in_array($entity['classname'], $classnames) !== false) { //echo "start processing {$entity['classname']} {$entity['id']}\n"; //Special processing for capture zone /* if ($entity['classname'] == "trigger_capture_zone") { // continue; $entity['targetname'] = $entity['controlpoint']; $entity['classname'] = 'point_controlpoint'; } */ // Create data structure for point $point = CreatePoint($entity, $map); $entname = $point['pos_name']; //if (!isset($point['pos_name'])) { //var_dump($point); //} //(isset($entity['controlpoint'])) ? $entity['controlpoint'] : $entity['targetname']; if (isset($entity['solid'])) { if (isset($entity['solid']['is_multiple_array'])) { $entity['solid'] = $entity['solid'][0]; //Temp hack for complex zones } $point['pos_type'] = 'area'; //This is silly, but I add together all the coordinates and average them to get the actual location on the map. // I think a better way is to actually calculate the difference and average that way. // TODO: Send all coord numbers into array, then sort and get min/max to average that way $path = array(); foreach ($entity['solid']['side'] as $side) { if (isset($side['plane'])) { preg_match_all('#\\(([^)]+)\\)#', $side['plane'], $coord); //Add coordinate to collection foreach ($coord[1] as $xyz) { $xyz = explode(' ', $xyz); $vector = round(abs(($xyz[0] - $map['overview']['pos_x']) / $map['overview']['scale'])) . ',' . round(abs(($xyz[1] - $map['overview']['pos_y']) / $map['overview']['scale'])); //.','.round($xyz[2]/$map['overview']['scale']); $path[$vector] = $vector; } } } //This is terrible logic that loops through the path points and calculates the high/low points for shape if (count($path)) { $min = array(0 => -1, 1 => -1); $max = array(0 => -1, 1 => -1); foreach ($path as $coord) { $vector = explode(',', $coord); $min[0] = $vector[0] < $min[0] || !isset($min[0]) || $min[0] < 0 ? $vector[0] : $min[0]; $min[1] = $vector[1] < $min[1] || !isset($min[1]) || $min[1] < 0 ? $vector[1] : $min[1]; $max[0] = $vector[0] > $max[0] || !isset($max[0]) ? $vector[0] : $max[0]; $max[1] = $vector[1] > $max[1] || !isset($max[1]) ? $vector[1] : $max[1]; } // Count the sides to see if this is a square or not. if (count($path) == 4) { $point['pos_x'] = (int) $min[0]; $point['pos_y'] = (int) $min[1]; $point['pos_width'] = (int) ($max[0] - $min[0]); $point['pos_height'] = (int) ($max[1] - $min[1]); $point['pos_shape'] = 'rect'; } else { $point['pos_shape'] = 'poly'; if ($point['pos_x'] < 1) { unset($path["{$min[0]},{$min[1]}"]); $point['pos_x'] = (int) $min[0]; $point['pos_y'] = (int) $min[1]; } $point['pos_points'] = implode(' ', $path); } } //echo "done processing {$entity['classname']} {$entity['id']}\n"; } //Hackly logic to allow merging of cache/control point data gracefully no matter what order the entities come in foreach ($point as $key => $val) { if (!isset($map[$points_key][$entname][$key])) { $map[$points_key][$entname][$key] = $val; } } } //echo "done process entities\n"; } //echo "done parse vmf\n"; } // Process combined data //Process game type data for this map foreach ($map['gametypes'] as $gtname => $gtdata) { //echo "start process gametypes\n"; //Create an array called cps with the names of all the control points for this mode if (!isset($gtdata['controlpoint'])) { continue; } if (!is_array($gtdata['controlpoint'])) { $map['gametypes'][$gtname]['controlpoint'] = array($gtdata['controlpoint']); } $cps = $map['gametypes'][$gtname]['controlpoint']; //Process any entities in the gamedata text file. $entlist = array(); if (!isset($gtdata[$entities_key])) { continue; } foreach ($gtdata[$entities_key] as $entname => $entity) { //var_dump($entname,$entity); //KV reader now handles multiple like-named resources by creating a numerically indexed array //When doing that, the is_multiple_array flag is set if (isset($entity['is_multiple_array'])) { //If multiple items, send each to the array foreach ($entity as $subent) { if (is_array($subent)) { $subent['classname'] = $entname; $entlist[] = CreatePoint($subent, $map); } } } else { //Otherwise, pack the single item $entity['classname'] = $entname; $entlist[] = CreatePoint($entity, $map); } } //Process all gamedata entities that are referenced by the controlpoints list foreach ($entlist as $id => $entity) { if (!isset($entity['pos_name'])) { continue; } $cp = $entity['pos_name']; //(isset($entity['controlpoint'])) ? $entity['controlpoint'] : $entity['targetname']; foreach ($entity as $key => $val) { if (!isset($map['gametypes'][$gtname][$points_key][$cp][$key]) || @$entity['targetname'] == $cp && $key != 'classname' || @$entity['targetname'] != $cp && $key == 'classname') { $map['gametypes'][$gtname][$points_key][$cp][$key] = $val; } } } /* //chr 65 is uppercase A. This lets me 'increment' letters $chr = 65; // Loop through control points and name them foreach ($cps as $idx => $cp) { $cpname = chr($chr); unset($map['gametypes'][$gtname]['controlpoint'][$idx]); $map['gametypes'][$gtname]['controlpoint'][$cpname] = (isset($map['gametypes'][$gtname][$points_key][$cp])) ? $map['gametypes'][$gtname][$points_key][$cp] : $map[$points_key][$cp]; //Set point name to the letter of the objective //$map['gametypes'][$gtname][$points_key][$cp] $map['gametypes'][$gtname]['controlpoint'][$cpname]['pos_name'] = $cpname; if (isset($gtdata['attackingteam'])) { $map['gametypes'][$gtname]['controlpoint'][$cpname]['pos_team'] = ($gtdata['attackingteam'] == 'security') ? 3 : 2; } $chr++; } */ //Bullshit to add teams to points, Skirmish game logic does it instead of saving it in the maps. if ($gtname == 'skirmish') { $map['gametypes'][$gtname]['controlpoint']['B']['pos_team'] = 2; $map['gametypes'][$gtname]['controlpoint']['D']['pos_team'] = 3; } //Same deal for Firefight if ($gtname == 'firefight') { $map['gametypes'][$gtname]['controlpoint']['A']['pos_team'] = 2; $map['gametypes'][$gtname]['controlpoint']['C']['pos_team'] = 3; } /* //Parse spawn zones. This is tricky because there will usually be two zones with the same targetname // but different teamnum. This is to allow spawning to move as the game changes I believe. if (isset($gtdata['spawnzones'])) { foreach ($gtdata['spawnzones'] as $szid => $szname) { if (is_numeric($szid)) { unset($map['gametypes'][$gtname]['spawnzones'][$szid]); $sz = array(); foreach (array('_team2','_team3') as $suffix) { if (isset($map[$points_key]["{$szname}{$suffix}"])) $sz["{$szname}{$suffix}"] = $map[$points_key]["{$szname}{$suffix}"]; } $map['gametypes'][$gtname]['spawnzones'][$szname] = $sz; } } } // Remove the points and entities sections from the finished data structure. We no longer need them. if (@is_array($map['gametypes'][$gtname][$points_key])) { unset($map['gametypes'][$gtname][$points_key]); } if (@is_array($map['gametypes'][$gtname][$entities_key])) { unset($map['gametypes'][$gtname][$entities_key]); } */ //echo "done parse gametypes\n"; } recur_ksort($map); $json = prettyPrint(json_encode($map)); file_put_contents($dstfile, $json); echo "OK: Parsed {$mapname}{$linebreak}"; // var_dump(array_merge_recursive($srcfiles,$map['source_files'])); }