I feel like people stopped paying attention to this topic but what the hell. I changed some parts of the script to prevent texture replacement so that i could find the textures i needed to port. Also found the difference between iw engine's and source engine's unit size and added an extra function to fix the it. Also added some extra lines to add the models. After converting a .vmf file to a .map file, this is what i got after fixing the texture alignments.
All i had to do was convert the models to .obj files, then convert the models and textures for waw, then convert the .vmf file to a .map file. Here's the script that i've edited. Note that this one below doesn't change the texture names and stuff. You'll need to get the texture names and convert them for whatever cod version you have and it'll work just fine.
Code:
<?php
function convertunit($origin) {
$exp = explode(' ',$origin);
foreach($exp as $unit) {
$origin .= trim($unit)*1.3344.' ';
}
return trim($origin);
}
function parseVMF($vmfString)
{
$debug = false;
$len = strlen($vmfString);
if ($debug) $len = 2098;
$stack = array();
$isInQuote = false;
$key = "";
$value = "";
$quoteKey = "";
$quoteValue = "";
$quoteWhat = "key";
for ($i=0; $i<$len; $i++)
{
$c = $vmfString{$i}; // current char
switch ($c)
{
case "\r":
break;
case "\n":
if (strlen(trim($key))) {
//echo "new key: \"$key\"";
$stack[] = $key;
$key = "";
}
//echo "\n";
break;
case "\"":
if ($isInQuote) // so we are CLOSING key or value
{
if (strlen($quoteKey) && strlen($quoteValue))
{
//echo "(NEW PAIR \"$quoteKey\"->\"$quoteValue\")";
$stack[] = array($quoteKey=>$quoteValue);
$quoteKey = "";
$quoteValue = "";
}
if ($quoteWhat == "key")
$quoteWhat = "value";
else if ($quoteWhat == "value")
$quoteWhat = "key";
}
$isInQuote = !$isInQuote;
break;
case "{":
$stack[] = "ENTER-GROUP";
if ($debug) echo "{";
break;
case "}":
$stack[] = "LEAVE-GROUP";
if ($debug) echo "}";
break;
case "\t":
break;
//case " ":
// break;
default:
if (!$isInQuote && strlen(trim($c)))
{
$key .= $c;
}
if ($isInQuote)
if ($quoteWhat == "key")
$quoteKey .= $c;
else
$quoteValue .= $c;
//echo $c;
}
}
if ($debug) echo "<hr>";
$vmf = array();
//$addTo = undefined;
$depth = 0;
$parent = &$vmf;
$history = array();
$groupname = "not init";
foreach ($stack as $element)
{
if (!is_array($element)) // is groupname or GROUP-indicator
{
/*
if (!isset($vmf[$element]))
$vmf[$element] = array();
$vmf[$element][] = array();
//$addTo = &$
*/
if ($element == "ENTER-GROUP")
{
if ($debug) echo "ENTER GROUP depth=$depth\n";
continue;
}
if ($element == "LEAVE-GROUP")
{
if ($debug) echo "LEAVE GROUP\n";
$depth--;
$parent = &$history[$depth];
continue;
}
$groupname = $element;
if (!isset($parent[$groupname]))
{
$parent[$groupname] = array();
//$parent[$groupname][] = array();
}
$history[$depth] = &$parent;
$parent = &$parent[$groupname][];
$depth++;
//$i = count($parent[$groupname]);
//$parent[$groupname][$i] = $groupname . $i;
//$parent = &$parent[$groupname][$i];
if ($debug) echo "NEW GROUP $groupname\n";
} else {
$keys = array_keys($element);
$key = $keys[0];
$val = $element[$key];
$n = count($parent);
//echo $n . "\n";
//$parent[$n] = $groupname . $n;
$parent[$key] = $val;
//echo $key . "->" . $element[$key];
}
//echo "\n";
}
if ($debug) echo "<hr>";
if ($debug) var_dump($vmf);
return $vmf;
}
function fixWaterBrush(&$solid)
{
$isOnlyWaterAndNodraw = true;
$watername = "";
foreach ($solid["side"] as $side)
if (strpos(strtoupper($side["material"]), "WATER")!==false || strpos(strtoupper($side["material"]), "TOOLSNODRAW")!==false) {
if (strpos(strtoupper($side["material"]), "WATER")!==false)
$watername = $side["material"];
} else
return false;
if (trim($watername) == "") // its completely nodraw
return false;
foreach ($solid["side"] as &$side)
$side["material"] = $watername;
return true;
}
function exportVMFasGSC($vmf)
{
$gsc = "main()\n{\n";
foreach ($vmf["entity"] as $entity)
{
if (
$entity["classname"] != "item_ammopack_medium"
&& $entity["classname"] != "item_healthkit_medium"
&& $entity["classname"] != "item_ammopack_small"
&& $entity["classname"] != "item_healthkit_small"
)
continue;
$classname = $entity["classname"];
$origin = str_replace(" ", ",", convertunit($entity["origin"]));
$angles = str_replace(" ", ",", $entity["angles"]);
$gsc .= "\tstd\item::addItem(\"$classname\", ($origin), ($angles));\n";
}
$gsc .= "\n";
foreach ($vmf["entity"] as $entity)
{
if ( ! isset($entity["model"]))
continue;
if ($entity["classname"] != "prop_dynamic" && $entity["model"] != "models/props_gameplay/resupply_locker.mdl")
continue;
$name = $entity["targetname"];
$origin = str_replace(" ", ",", convertunit($entity["origin"]));
$angles = str_replace(" ", ",", $entity["angles"]);
$gsc .= "\tstd\item::addItem(\"$name\", ($origin), ($angles));\n";
}
$gsc .= "}";
return $gsc;
}
function exportVMFasMAP($vmf, $extend_map)
{
$map = "";
$map .= "iwmap 4\n";
// PRINT NORMAL BRUSHES
$map .= "{\n";
$map .= "\t\"classname\" \"worldspawn\"\n";
// some brushes are in world
foreach ($vmf["world"][0]["solid"] as $solid)
{
if ($solid["side"][0]["material"] == "TOOLS/TOOLSPLAYERCLIP") // ONLY FOR SURF_UTOPIA
continue;
if ($solid["side"][0]["material"] == "TOOLS/TOOLSSKYBOX") // ONLY FOR SURF_UTOPIA
continue;
if (fixWaterBrush($solid) && 0)
echo "Fixed Water on Brush Solid-ID=" . $solid["id"] . "\n";
$map .= "\t{\n";
foreach ($solid["side"] as $side)
{
//$map .= "\t\t" . $side["plane"] . " " .getNewMaterial($side["material"]). " 64 64 0 0 0 0 lightmap_gray -248 192 -96 120 0 0 \n";
$map .= "\t\t" . $side["plane"] . " " .getNewMaterial($side["material"]). " 64 64 0 0 0 0 lightmap_gray 16384 16384 0 0 0 0 \n";
}
$map .= "\t}\n";
}
// others are func_detail-entities
foreach ($vmf["entity"] as $entity)
{
if (
$entity["classname"] != "func_detail"
&& $entity["classname"] != "func_brush"
&& $entity["classname"] != "func_illusionary" /*could be detail also but who cares*/ /*later: lol this one would to to many nodes: no compile*/
)
continue;
// if illusionary: add clip_player PLUS normal textures as non-colliding.
// so ppl can shoot through but cant go through.
if ($entity["classname"] == "func_illusionary")
{
foreach ($entity["solid"] as $solid)
{
$map .= "\t// func_illusionary\n";
$map .= "\t{\n";
foreach ($solid["side"] as $side)
{
$map .= "\t\t" . $side["plane"] . " clip 64 64 -88 8 0 0 lightmap_gray 16384 16384 0 0 0 0\n";
}
$map .= "\t}\n";
}
}
foreach ($entity["solid"] as $solid)
{
if ($solid["side"][0]["material"] == "TOOLS/TOOLSPLAYERCLIP") // ONLY FOR SURF_UTOPIA
continue;
if ($solid["side"][0]["material"] == "TOOLS/TOOLSSKYBOX") // ONLY FOR SURF_UTOPIA
continue;
if (fixWaterBrush($solid) && 0)
echo "Fixed Water on Brush Entity-ID=" . $entity["id"] . "\n";
$map .= "\t{\n";
if ($entity["classname"] == "func_illusionary")
{
//break;
//contents detail;
//contents nonColliding;
//$map .= "\tcontents detail;\n";
$map .= "\tcontents nonColliding;\n";
}
foreach ($solid["side"] as $side)
{
//$map .= "\t\t" . $side["plane"] . " " .getNewMaterial($side["material"]). " 64 64 0 0 0 0 lightmap_gray -248 192 -96 120 0 0 \n";
$map .= "\t\t" . $side["plane"] . " " .getNewMaterial($side["material"]). " 64 64 0 0 0 0 lightmap_gray 16384 16384 0 0 0 0 \n";
}
$map .= "\t}\n";
}
}
$map .= $extend_map;
$map .= "}\n\n"; // all brushes are in worldspawn
// now the entities:
// spawnpoints
foreach ($vmf["entity"] as $entity)
{
if ($entity["classname"] != "info_player_teamspawn")
continue;
if ( ! isset($entity["TeamNum"]))
continue;
if ($entity["TeamNum"] == "2")
$classname = "mp_ctf_spawn_allied";
else
$classname = "mp_ctf_spawn_axis";
$origin = convertunit($entity["origin"]);
$angles = $entity["angles"];
$map .= "{\n";
$map .= "\t\"origin\" \"$origin\"\n";
$map .= "\t\"classname\" \"$classname\"\n";
$map .= "\t\"angles\" \"$angles\"\n";
$map .= "}\n";
}
foreach ($vmf["entity"] as $entity)
{
if ($entity["classname"] != "info_player_counterterrorist")
continue;
$origin = convertunit($entity["origin"]);
$angles = $entity["angles"];
$map .= "{\n";
$map .= "\t\"origin\" \"$origin\"\n";
$map .= "\t\"classname\" \"mp_ctf_spawn_allied\"\n";
$map .= "\t\"angles\" \"$angles\"\n";
$map .= "}\n";
}
foreach ($vmf["entity"] as $entity)
{
if ($entity["classname"] != "info_player_terrorist")
continue;
$origin = convertunit($entity["origin"]);
$angles = $entity["angles"];
$map .= "{\n";
$map .= "\t\"origin\" \"$origin\"\n";
$map .= "\t\"classname\" \"mp_ctf_spawn_axis\"\n";
$map .= "\t\"angles\" \"$angles\"\n";
$map .= "}\n";
}
//
foreach ($vmf["entity"] as $entity)
{
if (
$entity["classname"] != "trigger_teleport"
&& $entity["classname"] != "trigger_push"
&& $entity["classname"] != "func_regenerate"
&& $entity["classname"] != "func_respawnroom"
)
continue;
foreach ($entity["solid"] as $solid)
{
$map .= "{\n";
$map .= "\t\"classname\" \"trigger_multiple\"\n";
$map .= "\t\"targetname\" \"{$entity["classname"]}\"\n";
if (isset($entity["target"])) $map .= "\t\"target\" \"{$entity["target"]}\"\n";
$count = 0;
if (isset($entity["speed"])) { $map .= "\t\"speed\" \"{$entity["speed"]}\"\n"; $count++; }
if (isset($entity["pushdir"])) { $map .= "\t\"pushdir\" \"{$entity["pushdir"]}\"\n"; $count++; }
if ($count == 2) // hack... add later support for other key-values inside server
{
$map .= "\t\"target\" \"{$entity["speed"]}|{$entity["pushdir"]}\"\n";
}
if (isset($entity["TeamNum"])) { $map .= "\t\"target\" \"{$entity["TeamNum"]}\"\n"; $count++; }
$map .= "\t{\n";
foreach ($solid["side"] as $side)
{
//$map .= "\t\t" . $side["plane"] . " " .getNewMaterial($side["material"]). " 64 64 0 0 0 0 lightmap_gray -248 192 -96 120 0 0 \n";
$map .= "\t\t" . $side["plane"] . " " .getNewMaterial($side["material"]). " 64 64 0 0 0 0 lightmap_gray 16384 16384 0 0 0 0 \n";
}
$map .= "\t}\n";
$map .= "}\n";
}
}
// global intermissions
foreach ($vmf["cameras"][0]["camera"] as $camera)
{
$origin = substr($camera["position"], 1, -1);
$map .= "{\n";
$map .= "\t\"classname\" \"mp_global_intermission\"\n";
$map .= "\t\"origin\" \"$origin\"\n";
$map .= "\t\"angles\" \"0 0 0\"\n";
$map .= "}\n";
}
// origins
foreach ($vmf["entity"] as $entity)
{
if ($entity["classname"] != "info_teleport_destination")
continue;
$origin = convertunit($entity["origin"]);
$targetname = $entity["targetname"];
$map .= "{\n";
$map .= "\t\"classname\" \"script_origin\"\n";
$map .= "\t\"origin\" \"$origin\"\n";
$map .= "\t\"angles\" \"" . $entity["angles"] . "\"\n";
$map .= "\t\"targetname\" \"$targetname\"\n";
$map .= "}\n";
// HACK HACK HACK -> otherwise those rooms are invisible
$map .= "{\n";
$map .= "\t\"classname\" \"mp_global_intermission\"\n";
$map .= "\t\"origin\" \"$origin\"\n";
$map .= "\t\"angles\" \"0 0 0\"\n";
$map .= "}\n";
}
foreach($vmf['entity'] as $entity) {
$model = $entity['model'];
$model = str_replace('-','_',$model);
$model = str_replace('.mdl,'_',$model);
if(preg_match('#.mdl#si',$model)) {
$origin = convertunit($entity['origin']);
$angles = $entity['angles'];
$model = explode('/',$model);
$model = $model[count($model)-1];
$map .= "{\n";
$map .= '"classname" "misc_model"';
$map .= '"model" "'.$model.'"';
$map .= '"origin" "'.$origin.'"';
$map .= '"angles" "'.$angles.'"';
$map .= "}\n";
}
}
return $map;
}
function getNewMaterial($materialname)
{
return $materialname;
}
ini_set("memory_limit", "500M");
$maps = array("cs_assault_d");
foreach ($maps as $name)
{
$missingTextures = array(); // global used to detect every missing texture only once
echo "Converting $name.vmf!\n";
$vmfString = file_get_contents("$name.vmf");
$vmf = parseVMF($vmfString);
$map = exportVMFasMAP($vmf, $extend_map);
$gsc = exportVMFasGSC($vmf);
//$map = convertVMF2Map($name . ".vmf");
if (!$map)
die("ERROR: Converting failed.\n");
if (count($missingTextures))
{
$textureNames = array_keys($missingTextures);
foreach ($textureNames as $textureName)
echo "WARNING: no texture for $textureName\n";
}
file_put_contents($name.".map", $map);
}