- setup can now be run from CLI. Use "> php index.php --help" to start off
- updated logging for use with CLI
- added generators for client imagery (icons, maps, talents, ect)
DBC:
- parsed DBCs are now expected in the Aowow-DB, prefixed with dbc_* (they are joined with
  these tables, so its easier to have them here altogether)
- setup/db_setup_3.zip may be reapplied (optionally)
- alternatively aowow will now extract you own DBCs alongside your textures.
  They will be parsed and saved to DB, as needed.
Misc:
 * HOST_URL and STATIC_URL will now be determined automaticly once and
 * then saved to ?_config (setup by CLI requires these to be set)
Spell:
 * added glyph-symbol to infobox for glyph-related spells
This commit is contained in:
Sarjuuk
2015-01-18 19:55:13 +01:00
parent 1dc63e2b6d
commit acbe969b8d
25 changed files with 2975 additions and 460 deletions

View File

@@ -28,7 +28,7 @@ class DB
$options = &self::$optionsCache[$idx]; $options = &self::$optionsCache[$idx];
$interface = DbSimple_Generic::connect(self::createConnectSyntax($options)); $interface = DbSimple_Generic::connect(self::createConnectSyntax($options));
$interface->setErrorHandler(array('DB', 'errorHandler')); $interface->setErrorHandler(['DB', 'errorHandler']);
if ($interface->error) if ($interface->error)
die('Failed to connect to database.'); die('Failed to connect to database.');
@@ -46,9 +46,9 @@ class DB
if (!error_reporting()) if (!error_reporting())
return; return;
echo "DB ERROR:<br /><br />\n\n<pre>"; $error = "DB ERROR:<br /><br />\n\n<pre>".print_r($data, true)."</pre>";
print_r($data);
echo "</pre>"; echo CLI ? strip_tags($error) : $error;
exit; exit;
} }

View File

@@ -4,18 +4,22 @@ if (!defined('AOWOW_REVISION'))
die('illegal access'); die('illegal access');
require 'includes/defines.php'; if (file_exists('config/config.php'))
require 'config/config.php'; require_once 'config/config.php';
require 'includes/libs/DbSimple/Generic.php'; // Libraray: http://en.dklab.ru/lib/DbSimple (using variant: https://github.com/ivan1986/DbSimple/tree/master) else
require 'includes/utilities.php'; // misc™ data 'n func $AoWoWconf = [];
require 'includes/ajaxHandler.class.php'; // handles ajax and jsonp requests
require 'includes/user.class.php'; require_once 'includes/defines.php';
require 'includes/markup.class.php'; // manipulate markup text require_once 'includes/libs/DbSimple/Generic.php'; // Libraray: http://en.dklab.ru/lib/DbSimple (using variant: https://github.com/ivan1986/DbSimple/tree/master)
require 'includes/database.class.php'; // wrap DBSimple require_once 'includes/utilities.php'; // misc™ data 'n func
require 'includes/community.class.php'; // handle comments, screenshots and videos require_once 'includes/ajaxHandler.class.php'; // handles ajax and jsonp requests
require 'includes/loot.class.php'; // build lv-tabs containing loot-information require_once 'includes/user.class.php';
require 'localization/lang.class.php'; require_once 'includes/markup.class.php'; // manipulate markup text
require 'pages/genericPage.class.php'; require_once 'includes/database.class.php'; // wrap DBSimple
require_once 'includes/community.class.php'; // handle comments, screenshots and videos
require_once 'includes/loot.class.php'; // build lv-tabs containing loot-information
require_once 'localization/lang.class.php';
require_once 'pages/genericPage.class.php';
// autoload List-classes, associated filters and pages // autoload List-classes, associated filters and pages
@@ -31,24 +35,22 @@ spl_autoload_register(function ($class) {
if (strpos($class, 'list')) if (strpos($class, 'list'))
{ {
if (!class_exists('BaseType')) if (!class_exists('BaseType'))
require 'includes/types/basetype.class.php'; require_once 'includes/types/basetype.class.php';
if (file_exists('includes/types/'.strtr($class, ['list' => '']).'.class.php')) if (file_exists('includes/types/'.strtr($class, ['list' => '']).'.class.php'))
require 'includes/types/'.strtr($class, ['list' => '']).'.class.php'; require_once 'includes/types/'.strtr($class, ['list' => '']).'.class.php';
return; return;
} }
if (file_exists('pages/'.strtr($class, ['page' => '']).'.php')) if (file_exists('pages/'.strtr($class, ['page' => '']).'.php'))
require 'pages/'.strtr($class, ['page' => '']).'.php'; require_once 'pages/'.strtr($class, ['page' => '']).'.php';
}); });
// Setup DB-Wrapper // Setup DB-Wrapper
if (!empty($AoWoWconf['aowow']['db'])) if (!empty($AoWoWconf['aowow']['db']))
DB::load(DB_AOWOW, $AoWoWconf['aowow']); DB::load(DB_AOWOW, $AoWoWconf['aowow']);
else
die('no database credentials given for: aowow');
if (!empty($AoWoWconf['world']['db'])) if (!empty($AoWoWconf['world']['db']))
DB::load(DB_WORLD, $AoWoWconf['world']); DB::load(DB_WORLD, $AoWoWconf['world']);
@@ -56,15 +58,14 @@ if (!empty($AoWoWconf['world']['db']))
if (!empty($AoWoWconf['auth']['db'])) if (!empty($AoWoWconf['auth']['db']))
DB::load(DB_AUTH, $AoWoWconf['auth']); DB::load(DB_AUTH, $AoWoWconf['auth']);
if (!empty($AoWoWconf['characters']))
foreach ($AoWoWconf['characters'] as $realm => $charDBInfo) foreach ($AoWoWconf['characters'] as $realm => $charDBInfo)
if (!empty($charDBInfo)) if (!empty($charDBInfo))
DB::load(DB_CHARACTERS . $realm, $charDBInfo); DB::load(DB_CHARACTERS . $realm, $charDBInfo);
unset($AoWoWconf); // link set up: delete passwords
// load config to constants // load config to constants
$sets = DB::Aowow()->select('SELECT `key` AS ARRAY_KEY, `value`, `flags` FROM ?_config'); $sets = DB::isConnectable(DB_AOWOW) ? DB::Aowow()->select('SELECT `key` AS ARRAY_KEY, `value`, `flags` FROM ?_config') : [];
foreach ($sets as $k => $v) foreach ($sets as $k => $v)
{ {
// this should not have been possible // this should not have been possible
@@ -80,7 +81,7 @@ foreach ($sets as $k => $v)
else if ($v['flags'] & CON_FLAG_TYPE_BOOL) else if ($v['flags'] & CON_FLAG_TYPE_BOOL)
$val = (bool)$v['value']; $val = (bool)$v['value'];
else if ($v['flags'] & CON_FLAG_TYPE_STRING) else if ($v['flags'] & CON_FLAG_TYPE_STRING)
$val = preg_replace('/[^\p{L}0-9\s_\-\'\.,]/ui', '', $v['value']); $val = preg_replace('/[^\p{L}0-9~\s_\-\'\/\.,]/ui', '', $v['value']);
else else
{ {
Util::addNote(U_GROUP_ADMIN | U_GROUP_DEV, 'Kernel: '.($php ? 'PHP' : 'Aowow').' config value '.($php ? strtolower($k) : 'CFG_'.strtoupper($k)).' has no type set. Value forced to 0!'); Util::addNote(U_GROUP_ADMIN | U_GROUP_DEV, 'Kernel: '.($php ? 'PHP' : 'Aowow').' config value '.($php ? strtolower($k) : 'CFG_'.strtoupper($k)).' has no type set. Value forced to 0!');
@@ -94,38 +95,60 @@ foreach ($sets as $k => $v)
} }
$secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || CFG_FORCE_SSL; error_reporting($AoWoWconf && CFG_DEBUG ? (E_ALL & ~(E_DEPRECATED | E_USER_DEPRECATED | E_STRICT)) : 0);
$protocoll = $secure ? 'https://' : 'http://';
define('STATIC_URL', substr($protocoll.$_SERVER['SERVER_NAME'].strtr($_SERVER['SCRIPT_NAME'], ['index.php' => '']), 0, -1).'/static'); // points js to images & scripts (change here if you want to use a separate subdomain) $secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || ($AoWoWconf && CFG_FORCE_SSL);
define('HOST_URL', substr($protocoll.$_SERVER['SERVER_NAME'].strtr($_SERVER['SCRIPT_NAME'], ['index.php' => '']), 0, -1)); // points js to executable files if (defined('CFG_STATIC_HOST')) // points js to images & scripts
define('STATIC_URL', ($secure ? 'https://' : 'http://').CFG_STATIC_HOST);
$e = CFG_DEBUG ? (E_ALL & ~(E_DEPRECATED | E_USER_DEPRECATED | E_STRICT)) : 0; if (defined('CFG_SITE_HOST')) // points js to executable files
error_reporting($e); define('HOST_URL', ($secure ? 'https://' : 'http://').CFG_SITE_HOST);
// debug: measure execution times
Util::execTime(CFG_DEBUG);
if (!CLI)
{
// Setup Session // Setup Session
session_set_cookie_params(15 * YEAR, '/', '', $secure, true); session_set_cookie_params(15 * YEAR, '/', '', $secure, true);
session_cache_limiter('private'); session_cache_limiter('private');
session_start(); session_start();
if (User::init()) if ($AoWoWconf && User::init())
User::save(); // save user-variables in session User::save(); // save user-variables in session
// todo: (low) - move to setup web-interface (when it begins its existance)
if (!defined('CFG_SITE_HOST') || !defined('CFG_STATIC_HOST'))
{
$host = substr($_SERVER['SERVER_NAME'].strtr($_SERVER['SCRIPT_NAME'], ['index.php' => '']), 0, -1);
define('HOST_URL', ($secure ? 'https://' : 'http://').$host);
define('STATIC_URL', ($secure ? 'https://' : 'http://').$host.'/static');
if (User::isInGroup(U_GROUP_ADMIN) && $AoWoWconf) // initial set
{
DB::Aowow()->query('INSERT IGNORE INTO ?_config VALUES (?, ?, ?d, ?), (?, ?, ?d, ?)',
'site_host', $host, CON_FLAG_TYPE_STRING | CON_FLAG_PERSISTENT, 'default: '.$host.' - points js to executable files (automaticly set on first run)',
'static_host', $host.'/static', CON_FLAG_TYPE_STRING | CON_FLAG_PERSISTENT, 'default: '.$host.'/static - points js to images & scripts (automaticly set on first run)'
);
}
}
// hard-override locale for this call (should this be here..?) // hard-override locale for this call (should this be here..?)
// all strings attached.. // all strings attached..
if ($AoWoWconf)
{
if (isset($_GET['locale']) && (CFG_LOCALES & (1 << (int)$_GET['locale']))) if (isset($_GET['locale']) && (CFG_LOCALES & (1 << (int)$_GET['locale'])))
User::useLocale($_GET['locale']); User::useLocale($_GET['locale']);
Lang::load(User::$localeString); Lang::load(User::$localeString);
}
// parse page-parameters .. sanitize before use! // parse page-parameters .. sanitize before use!
@list($str, $trash) = explode('&', $_SERVER['QUERY_STRING'], 2); @list($str, $trash) = explode('&', $_SERVER['QUERY_STRING'], 2);
@list($pageCall, $pageParam) = explode('=', $str, 2); @list($pageCall, $pageParam) = explode('=', $str, 2);
Util::$wowheadLink = 'http://'.Util::$subDomains[User::$localeId].'.wowhead.com/'.$str; Util::$wowheadLink = 'http://'.Util::$subDomains[User::$localeId].'.wowhead.com/'.$str;
}
else if ($AoWoWconf)
Lang::load('enus');
$AoWoWconf = null; // empty auths
?> ?>

View File

@@ -1,28 +1,39 @@
<?php <?php
define('AOWOW_REVISION', 12); define('AOWOW_REVISION', 12);
define('CLI', PHP_SAPI === 'cli');
if (!file_exists('config/config.php'))
{
$cwDir = /*$_SERVER['DOCUMENT_ROOT']; //*/getcwd();
require 'setup/setup.php';
exit;
}
$reqExt = ['SimpleXML', 'gd', 'mysqli', 'mbstring', 'mcrypt']; $reqExt = ['SimpleXML', 'gd', 'mysqli', 'mbstring'];
$error = ''; $error = '';
foreach ($reqExt as $r) foreach ($reqExt as $r)
if (!extension_loaded($r)) if (!extension_loaded($r))
$error .= 'Required Extension <b>'.$r."</b> was not found. Please see if it exists, using <i>php -m</i>\n\n"; $error .= 'Required Extension <b>'.$r."</b> was not found. Please check if it should exist, using \"<i>php -m</i>\"\n\n";
if (version_compare(PHP_VERSION, '5.5.0') < 0) if (version_compare(PHP_VERSION, '5.5.0') < 0)
$error .= 'PHP Version <b>5.5.0</b> or higher required! Your version is <b>'.PHP_VERSION."</b>.\nCore functions are unavailable!"; $error .= 'PHP Version <b>5.5.0</b> or higher required! Your version is <b>'.PHP_VERSION."</b>.\nCore functions are unavailable!\n";
// not in root dir
if (CLI && getcwd().DIRECTORY_SEPARATOR.'index.php' != __FILE__)
$error .= "Aowow must be used from root directory\n";
if ($error) if ($error)
die('<pre>'.$error.'</pre>'); {
echo CLI ? strip_tags($error) : $error;
die();
}
// include all necessities, set up basics // include all necessities, set up basics
require 'includes/kernel.php'; require_once 'includes/kernel.php';
if (CLI || !file_exists('config/config.php'))
{
$cwDir = /*$_SERVER['DOCUMENT_ROOT']; //*/getcwd();
require 'setup/setup.php';
die();
}
$altClass = ''; $altClass = '';
@@ -82,6 +93,7 @@ switch ($pageCall)
case 'title': case 'title':
case 'titles': case 'titles':
// case 'user': // tool: user profiles [nyi] // case 'user': // tool: user profiles [nyi]
case 'video':
case 'zone': case 'zone':
case 'zones': case 'zones':
if (in_array($pageCall, ['admin', 'account', 'profile'])) if (in_array($pageCall, ['admin', 'account', 'profile']))
@@ -134,7 +146,8 @@ switch ($pageCall)
case 'build': case 'build':
if (User::isInGroup(U_GROUP_EMPLOYEE)) if (User::isInGroup(U_GROUP_EMPLOYEE))
{ {
require 'setup/tools/filegen/scriptGen.php'; define('TMP_BUILD', 1); // todo (med): needs better solution
require 'setup/setup.php';
break; break;
} }
case 'sql': case 'sql':
@@ -143,12 +156,6 @@ switch ($pageCall)
require 'setup/tools/database/_'.$pageParam.'.php'; require 'setup/tools/database/_'.$pageParam.'.php';
break; break;
} }
case 'setup':
if (User::isInGroup(U_GROUP_EMPLOYEE))
{
require 'setup/syncronize.php';
break;
}
default: // unk parameter given -> ErrorPage default: // unk parameter given -> ErrorPage
if (isset($_GET['power'])) if (isset($_GET['power']))
die('$WowheadPower.register(0, '.User::$localeId.', {})'); die('$WowheadPower.register(0, '.User::$localeId.', {})');

View File

@@ -221,6 +221,19 @@ class SpellPage extends GenericPage
if ($id == $this->typeId) // "Mode" seems to be multilingual acceptable if ($id == $this->typeId) // "Mode" seems to be multilingual acceptable
$infobox[] = '[li]Mode'.Lang::$main['colon'].Lang::$game['modes'][$n].'[/li]'; $infobox[] = '[li]Mode'.Lang::$main['colon'].Lang::$game['modes'][$n].'[/li]';
$effects = $this->createEffects($infobox, $redButtons);
$infobox = $infobox ? '[ul]'.implode('', $infobox).'[/ul]' : '';
// append glyph symbol if available
$glyphId = 0;
for ($i = 1; $i < 4; $i++)
if ($this->subject->getField('effect'.$i.'Id') == 74)
$glyphId = $this->subject->getField('effect'.$i.'MiscValue');
if ($_ = DB::Aowow()->selectCell('SELECT si.iconString FROM ?_glyphproperties gp JOIN ?_spellicon si ON gp.iconId = si.id WHERE gp.spellId = ?d { OR gp.id = ?d }', $this->typeId, $glyphId ?: DBSIMPLE_SKIP))
if (file_exists('static/images/wow/interface/Spellbook/'.$_.'.png'))
$infobox .= '[img src='.STATIC_URL.'/images/wow/interface/Spellbook/'.$_.'.png border=0 float=center margin=15]';
/****************/ /****************/
/* Main Content */ /* Main Content */
@@ -236,8 +249,8 @@ class SpellPage extends GenericPage
$this->scaling = $this->createScalingData(); $this->scaling = $this->createScalingData();
$this->items = $this->createRequiredItems(); $this->items = $this->createRequiredItems();
$this->tools = $this->createTools(); $this->tools = $this->createTools();
$this->effects = $this->createEffects($infobox, $redButtons); $this->effects = $effects;
$this->infobox = $infobox ? '[ul]'.implode('', $infobox).'[/ul]' : null; $this->infobox = $infobox;
$this->powerCost = $this->subject->createPowerCostForCurrent(); $this->powerCost = $this->subject->createPowerCostForCurrent();
$this->castTime = $this->subject->createCastTimeForCurrent(false, false); $this->castTime = $this->subject->createCastTimeForCurrent(false, false);
$this->name = $this->subject->getField('name', true); $this->name = $this->subject->getField('name', true);
@@ -934,8 +947,8 @@ class SpellPage extends GenericPage
'params' => array( 'params' => array(
'id' => 'teaches-spell', 'id' => 'teaches-spell',
'name' => '$LANG.tab_teaches', 'name' => '$LANG.tab_teaches',
'visibleCols' => '$'.json_encode($vis), 'visibleCols' => '$'.Util::toJSON($vis),
'hiddenCols' => $hid ? '$'.json_encode($hid) : null 'hiddenCols' => $hid ? '$'.Util::toJSON($hid) : null
) )
); );
} }
@@ -1087,7 +1100,7 @@ class SpellPage extends GenericPage
{ {
$this->extendGlobalData($sc[1]); $this->extendGlobalData($sc[1]);
$tab = "<script type=\"text/javascript\">\n" . $tab = "<script type=\"text/javascript\">\n" .
"var markup = ConditionList.createTab(".json_encode($sc[0], JSON_NUMERIC_CHECK).");\n" . "var markup = ConditionList.createTab(".Util::toJSON($sc[0]).");\n" .
"Markup.printHtml(markup, 'tab-conditions', { allow: Markup.CLASS_STAFF })" . "Markup.printHtml(markup, 'tab-conditions', { allow: Markup.CLASS_STAFF })" .
"</script>"; "</script>";
@@ -1116,12 +1129,12 @@ class SpellPage extends GenericPage
if ($tt = $this->subject->renderTooltip()) if ($tt = $this->subject->renderTooltip())
{ {
$pt[] = "\ttooltip_".User::$localeString.": '".Util::jsEscape($tt[0])."'"; $pt[] = "\ttooltip_".User::$localeString.": '".Util::jsEscape($tt[0])."'";
$pt[] = "\tspells_".User::$localeString.": ".json_encode($tt[1], JSON_UNESCAPED_UNICODE); $pt[] = "\tspells_".User::$localeString.": ".Util::toJSON($tt[1]);
} }
if ($btt = $this->subject->renderBuff()) if ($btt = $this->subject->renderBuff())
{ {
$pt[] = "\tbuff_".User::$localeString.": '".Util::jsEscape($btt[0])."'"; $pt[] = "\tbuff_".User::$localeString.": '".Util::jsEscape($btt[0])."'";
$pt[] = "\tbuffspells_".User::$localeString.": ".json_encode($btt[1], JSON_UNESCAPED_UNICODE);; $pt[] = "\tbuffspells_".User::$localeString.": ".Util::toJSON($btt[1]);;
} }
$x .= implode(",\n", $pt)."\n});"; $x .= implode(",\n", $pt)."\n});";

Binary file not shown.

376
setup/setup.php Normal file
View File

@@ -0,0 +1,376 @@
<?php
if (!defined('AOWOW_REVISION'))
die('invalid access');
function buildDirStruct($dir, &$idx = 1, $parent = [], $depths = 0) {
$struct = [];
if ($depths > 3)
return 'null';
$iterator = new RecursiveDirectoryIterator($dir);
$iterator->setFlags(RecursiveDirectoryIterator::SKIP_DOTS);
$basePath = '';
foreach ($iterator as $path)
{
$path = $path->getPathname();
if (!is_dir($path) || $path[0] == '.') // also skip hidden dirs
continue;
$idx++;
$newParent = $parent;
$newParent[] = basename($path);
$struct[] = "[".$idx.", \"".basename($path)."\", setPath.bind(this, el, '/".implode($newParent, '/')."'), ".buildDirStruct($path, $idx, $newParent, $depths + 1)."]";
}
return empty($struct) ? 'null' : '['.implode($struct, ",").']';
}
function checkDbcDir($dir, $reqFiles) {
$handle = opendir($dir);
$content = array();
while (false !== ($entry = readdir($handle))) {
if (is_dir($dir.'\\'.$entry))
continue;
$file = explode('.', $entry);
if ($file[1] == 'dbc')
$content[] = strToLower($file[0]);
}
if (empty($content))
return array(-4, null); // arbitrary directory .. silent death
foreach ($reqFiles as $k => $v) {
if (in_array(strToLower($v), $content))
unset($reqFiles[$k]);
}
if (empty($reqFiles)) {
$f = fopen($dir.'\\Resistances.dbc', 'rb');
if (fread($f, 4) != "WDBC" || filesize($dir.'\\Resistances.dbc') < 20)
return array(-1, 'File looks like DBC but is not in proper format!');
$parse = dbc2array($dir.'\\Resistances.dbc', "xxxsssssssssxxxxxxxx");
for ($i = 0; $i <= 8; $i++) {
if (empty($parse[0][$i]))
continue;
if (in_array($i, array(0, 2, 3, 6, 8))) // en, X, fr, de, X, X, es, ru
return array($i, count($content));
else
return array(-2, 'locale ":$i." not supported!');
}
}
$path = array_pop(explode('\\', $dir));
return array(-3, 'Requird files are missing!', '<div>- '.str_replace($cwDir, '', $path).'\\'.implode($reqFiles, '.dbc<br />- '.str_replace($cwDir, '', $path).'\\').'.dbc</div>');
}
if (CLI || defined('TMP_BUILD'))
{
require_once 'tools/filegen/fileGen.class.php';
require_once 'tools/dbc.class.php';
require_once 'tools/imagecreatefromblp.php';
FileGen::init(@$pageParam ?: '');
if (FileGen::$subScripts)
{
// start file generation
FileGen::status('begin generation of '. implode(', ', FileGen::$subScripts));
FileGen::status();
// files with template
foreach (FileGen::$tplFiles as $name => list($file, $destPath))
{
if (!in_array($name, FileGen::$subScripts))
continue;
if (!file_exists(FileGen::$tplPath.$file.'.in'))
{
FileGen::status(sprintf(ERR_MISSING_FILE, FileGen::$tplPath.$file.'.in'), MSG_LVL_ERROR);
continue;
}
if (!FileGen::writeDir($destPath))
continue;
if ($content = file_get_contents(FileGen::$tplPath.$file.'.in'))
{
if ($dest = @fOpen($destPath.$file, "w"))
{
// replace constants
$content = strtr($content, FileGen::$txtConstants);
// must generate content
// PH format: /*setup:<setupFunc>*/
if (preg_match('/\/\*setup:([\w\d_-]+)\*\//i', $content, $m))
{
if (file_exists('setup/tools/filegen/'.$m[1].'.func.php'))
require_once 'setup/tools/filegen/'.$m[1].'.func.php';
else
{
FileGen::status(sprintf(ERR_MISSING_INCL, $m[1], 'setup/tools/filegen/'.$m[1].'.func.php'), MSG_LVL_ERROR);
continue;
}
if (function_exists($m[1]))
$content = str_replace('/*setup:'.$m[1].'*/', $m[1](), $content);
else
{
$content = '';
FileGen::status('Placeholder in template file does not match any known function name.', MSG_LVL_ERROR);
}
}
if (fWrite($dest, $content))
FileGen::status(sprintf(ERR_NONE, $destPath.$file), MSG_LVL_OK);
else
FileGen::status(sprintf(ERR_WRITE_FILE, $destPath.$file, MSG_LVL_ERROR));
fClose($dest);
}
else
FileGen::status(sprintf(ERR_CREATE_FILE, $destPath.$file), MSG_LVL_ERROR);
}
else
FileGen::status(sprintf(ERR_READ_FILE, FileGen::$tplPath.$file.'.in'), MSG_LVL_ERROR);
}
// files without template
foreach (FileGen::$datasets as $file)
{
if (!in_array($file, FileGen::$subScripts))
continue;
if (file_exists('setup/tools/filegen/'.$file.'.func.php'))
{
require_once 'setup/tools/filegen/'.$file.'.func.php';
if (function_exists($file))
FileGen::status(' - subscript \''.$file.'\' returned '.($file() ? 'sucessfully' : 'with errors'));
else
FileGen::status(' - subscript \''.$file.'\' not defined in included file', MSG_LVL_ERROR);
set_time_limit(FileGen::$defaultExecTime); // reset to default for the next script
}
else
FileGen::status(sprintf(ERR_MISSING_INCL, $file, 'setup/tools/filegen/'.$file.'.func.php', MSG_LVL_ERROR));
}
// end
FileGen::status();
FileGen::status('finished file generation');
}
else
FileGen::status('no valid script names supplied');
}
/*
else
{
if (isset($_GET['pathMenu'])) {
// set_time_limit(240); // parsing directory-structures seems to be costy...
die(buildDirStruct($cwDir.'/setup', $c));
}
$step = @intVal($_GET['step']);
$fields = @explode(';', $_GET['fields']);
if ($step == 1) {
// unset saved credentials
$_SESSION['step1']['progress'] &= ~(1 << $fields[0]);
$_SESSION['step1'][$fields[0]] = array($fields[1], $fields[3], $fields[4], $fields[2]);
// try to connect to db with data provided
$link = @mysql_connect($fields[1], $fields[3], $fields[4], true);
if ($link) {
switch ($fields[0]) {
case 0:
if (mysql_select_db($fields[2], $link)) {
if (mysql_fetch_row(mysql_query("SHOW TABLES FROM ".$fields[2]." LIKE '".$fields[5]."glyphpropperties'")))
die('{"errno":-1, "errstr":"Tables already present in this database will be overwritten!"}');
else {
$_SESSION['step1']['progress'] |= 0x1;
die('{"errno":0, "errstr":""}');
}
}
else if (mysql_errno() == 1044) // why doesn't this occur earlier?
die('{"errno":'.mysql_errno().', "errstr":"'.mysql_error().'"}');
else {
$_SESSION['step1']['progress'] |= 0x1;
die('{"errno":-1, "errstr":"Database will be created during installation!"}');
}
case 1:
if (mysql_select_db($fields[2], $link)) {
if (mysql_fetch_row(mysql_query("SHOW TABLES FROM ".$fields[2]." LIKE '".$fields[5]."item_template'"))) {
$_SESSION['step1']['progress'] |= 0x2;
die('{"errno":0, "errstr":""}');
}
}
break;
case 2:
if (mysql_select_db($fields[2], $link)) {
if (mysql_fetch_row(mysql_query("SHOW TABLES FROM ".$fields[2]." LIKE '".$fields[5]."account'"))) {
$_SESSION['step1']['progress'] |= 0x4;
die('{"errno":0, "errstr":""}');
}
}
break;
case 3:
if (mysql_select_db($fields[2], $link)) {
if (mysql_fetch_row(mysql_query("SHOW TABLES FROM ".$fields[2]." LIKE '".$fields[5]."characters'"))) {
$_SESSION['step1']['progress'] |= 0x8;
die('{"errno":0, "errstr":""}');
}
}
break;
}
if(!mysql_errno())
die('{"errno":-1, "errstr":"Required table not found in selected database!"}');
else
die('{"errno":'.mysql_errno().', "errstr":"'.mysql_error().'"}');
}
else
die('{"errno":'.mysql_errno().', "errstr":"'.mysql_error().'"}');
}
else if ($step == 2) {
$final = array();
// sanitize .. clamp dir-choice to DOCUMENT_ROOT
$dir = $cwDir.'/setup'.str_replace(['/..', '/.', '../', './'], '', str_replace(',', '/', $fields[1]));
// unset saved credentials
$_SESSION['step2']['progress'] &= ~(1 << $fields[0]);
$_SESSION['step2'][$fields[0]] = $dir;
if (!is_dir($dir))
die(json_encode(array(str_replace($cwDir, '', $dir) => array("errno" => 5, "errstr" => "Not a directory!"))));
$handle = opendir($dir);
switch ($fields[0]) {
case 0: {
$reqDBCs = array_keys($dbcStructure);
// check this directory
$result = checkDbcDir($dir, $reqDBCs);
if ($result[0] < 0 && isset($result[1]))
$final[str_replace($cwDir, '', $dir)] = array('errno' => -$result[0], 'errstr' => $result[1], 'tooltip' => $result[2]);
else if ($result[0] >= 0) {
if ($result[1] == 246)
$final[str_replace($cwDir, '', $dir)] = array('locale' => $result[0], 'errno' => 0, 'errstr' => '');
else
$final[str_replace($cwDir, '', $dir)] = array('locale' => $result[0], 'errno' => -1, 'errstr' => (246 - $result[1]).' optional files missing.');
}
// check first-level child direcotries
while (false !== ($entry = readdir($handle))) {
if ($entry == "." || $entry == "..")
continue;
if (is_dir($dir.'\\'.$entry) === true) {
$result = checkDbcDir($dir.'\\'.$entry, $reqDBCs);
if ($result[0] < 0 && isset($result[1]))
$final[$entry] = array('errno' => -$result[0], 'errstr' => $result[1], 'tooltip' => $result[2]);
else if ($result[0] >= 0) {
if ($result[1] == 246)
$final[$entry] = array('locale' => $result[0], 'errno' => 0, 'errstr' => '');
else
$final[$entry] = array('locale' => $result[0], 'errno' => -1, 'errstr' => (246 - $result[1]).' optional files missing.');
}
}
}
foreach ($final as $v)
if ($v['errno'] <= 0)
$_SESSION['step2']['progress'] |= 0x1;
die(json_encode($final));
}
case 1: {
$loc = array('enUS' => 0, 'enGB' => 0, 'frFR' => 2, 'deDE' => 3, 'esES' => 6, 'esMX' => 6, 'ruRU' => 8);
$expectDir = array('Icons' => array(6308, "/[\w\d\_]+[\.tga|\s|\.]?.blp/i"), 'Spellbook' => array(20, "/UI\-Glyph\-Rune\-[0-9]+\.blp/i"), 'Worldmap' => array(117));
foreach ($loc as $k => $v) {
if (!is_dir($dir.'\\'.$k))
continue;
if (isset($final[$v]))
continue;
$final[$v] = array();
$j = 0;
foreach ($expectDir as $sk => $sv) {
if (!is_dir($dir.'\\'.$k.'\\'.$sk))
break;
$handle = opendir($dir.'\\'.$k.'\\'.$sk);
$i = 0;
while (false !== ($entry = readdir($handle))) {
if (isset($sv[1])) {
if (is_dir($dir.'\\'.$k.'\\'.$sk.'\\'.$entry) === true)
continue;
if (preg_match($sv[1], $entry, $result))
$i++;
}
else {
if (is_dir($dir.'\\'.$k.'\\'.$sk.'\\'.$entry) === false || $entry == '.' || $entry == '..')
continue;
$i++;
}
}
if ($i == $sv[0]) {
$final[$v][$sk] = array('errno' => 0, 'errstr' => '');
$final['total'] |= (1 << $j);
}
else
$final[$v][$sk] = array('errno' => 1, 'errstr' => ($sv[0] - $i).' files missing in '.$k.'\\'.$sk.'!');
$j++;
}
if (empty($final[$v]))
$final[$v] = array('errno' => 3, 'errstr' => 'locale directory '.$k.' is empty!');
}
if ($final['total'] == 0x7)
$_SESSION['step2']['progress'] |= 0x2;
die(json_encode($final));
}
case 2: {
while (false !== ($entry = readdir($handle))) {
if (is_dir($entry) === true)
continue;
$file = explode('.', $entry);
if ($file[1] != 'sql')
continue;
$fRes = fopen($dir."\\".$entry, 'rb');
if (preg_match('/\/\* AoWoW 3\.3\.5 (en|fr|de|es|ru)[a-z]{2} locales \*\//i', fread($fRes, 30), $result))
$final[$result[1]] = str_replace($cwDir, '', $dir).'\\'.$entry;
}
if (!empty($final))
$_SESSION['step2']['progress'] |= 0x4;
die(json_encode($final));
}
}
}
include 'setup.tpl.php';
}
*/
?>

390
setup/tools/dbc.class.php Normal file
View File

@@ -0,0 +1,390 @@
<?php
/*
DBC::read - PHP function for loading DBC file into array
This file is a part of AoWoW project.
Copyright (C) 2009-2010 Mix <ru-mangos.ru>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('AOWOW_REVISION'))
die('illegal access');
class DBC
{
private $_formats = array(
'talent' => 'niiiiiiiixxxxixxixxixii',
'talenttab' => 'nsxssxxsxsxxxxxxxxiiiiis',
'gtchancetomeleecrit' => 'f',
'gtchancetomeleecritbase' => 'f',
'gtchancetospellcrit' => 'f',
'gtchancetospellcritbase' => 'f',
'gtoctregenhp' => 'f',
'gtregenmpperspt' => 'f',
'gtregenhpperspt' => 'f',
'spellicon' => 'ns',
'itemdisplayinfo' => 'nssxxsxxxxxxxxxxxxxxxxxxx',
'holidays' => 'nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixxxxxxxxxxiisxix',
'chrclasses' => 'nxixsxssxxsxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxsxixi',
'worldmaparea' => 'niisffffxix', // 4.x - niisffffxixxxx
'worldmapoverlay' => 'niixxxxxsiiiixxxx', // 4.x - niixxxsiiiixxxx
);
private $_fields = array(
'talent' => 'Id,tabId,row,column,rank1,rank2,rank3,rank4,rank5,reqTalent,reqRank,talentSpell,petCategory1,petCategory2',
'talenttab' => 'Id,nameEN,nameFR,nameDE,nameES,nameRU,iconId,raceMask,classMask,creatureFamilyMask,tabNumber,textureFile',
'gtchancetomeleecrit' => 'chance',
'gtchancetomeleecritbase' => 'chance',
'gtchancetospellcrit' => 'chance',
'gtchancetospellcritbase' => 'chance',
'gtoctregenhp' => 'ratio',
'gtregenmpperspt' => 'ratio',
'gtregenhpperspt' => 'ratio',
'spellicon' => 'Id,iconPath',
'itemdisplayinfo' => 'Id,leftModelName,rightModelName,inventoryIcon1',
'holidays' => 'Id,looping,nameId,descriptionId,textureString,scheduleType',
'chrclasses' => 'Id,powerType,nameMaleEN,nameMaleFR,nameMaleDE,nameMaleES,nameMaleRU,nameINT,flags,addon',
'worldmaparea' => 'Id,mapId,areaId,nameINT,left,right,top,bottom,defaultDungeonMapId',
'worldmapoverlay' => 'Id,worldMapAreaId,areaTableId,textureString,w,h,x,y',
);
private $isGameTable = false;
public $result = [];
public $fields = [];
public $format = '';
public $file = '';
public function __construct($file)
{
$file = strtolower($file);
if (empty($this->_fields[$file]) || empty($this->_formats[$file]))
{
FileGen::status('no structure known for '.$file.'.dbc, aborting.', MSG_LVL_ERROR);
return;
}
$this->fields = explode(',', $this->_fields[$file]);
$this->format = $this->_formats[$file];
$this->file = $file;
// gameTable-DBCs don't have an index and are accessed through value order
// allas, you cannot do this with mysql, so we add a 'virtual' index
$this->isGameTable = $this->format == 'f' && substr($file, 0, 2) == 'gt';
}
public function writeToDB()
{
if (!$this->result)
return false;
$n = 0;
$pKey = $this->fields[0];
$query = 'CREATE TABLE `dbc_'.$this->file.'` (';
if ($this->isGameTable)
{
$query .= '`idx` BIGINT(20) NOT NULL, ';
$pKey = 'idx';
}
foreach (str_split($this->format) as $idx => $f)
{
if ($f == 'f')
$query .= '`'.$this->fields[$n].'` FLOAT NOT NULL, ';
else if ($f == 's' || $f == 'b')
$query .= '`'.$this->fields[$n].'` TEXT NOT NULL, ';
else if ($f == 'i' || $f == 'n')
$query .= '`'.$this->fields[$n].'` BIGINT(20) NOT NULL, ';
if ($f == 'n')
$pKey = $this->fields[$n];
if ($f != 'x')
$n++;
}
$query .= 'PRIMARY KEY (`'.$pKey.'`)) COLLATE=\'utf8_general_ci\' ENGINE=MyISAM';
DB::Aowow()->query('DROP TABLE IF EXISTS ?#', 'dbc_'.$this->file);
DB::Aowow()->query($query);
// make inserts more manageable
$offset = 0;
$limit = 1000;
$fields = $this->fields;
if ($this->isGameTable)
array_unshift($fields, 'idx');
while (($offset * $limit) < count($this->result))
DB::Aowow()->query('INSERT INTO ?# (?#) VALUES (?a)', 'dbc_'.$this->file, $fields, array_slice($this->result, $offset++ * $limit, $limit));
return true;
}
public function readFiltered(Closure $filterFunc = null, $localized = false, $safeIf = true)
{
$result = $this->readArbitrary($localized, $safeIf);
if (is_object($filterFunc))
foreach ($result as $key => &$val)
if (!$filterFunc($val, $key))
unset($result[$key]);
return $result;
}
public function readArbitrary($localized = false, $safeIf = true)
{
// try DB first
if (!$this->result)
$this->readFromDB();
// try file second
if (!$this->result)
if ($this->readFromFile($localized) && $safeIf)
$this->writeToDB();
return $this->getIndexed();
}
public function readFromDB()
{
if (!DB::Aowow()->selectCell('SHOW TABLES LIKE ?', 'dbc_'.$this->file))
return [];
$key = strstr($this->format, 'n') ? $this->fields[strpos($this->format, 'n')] : '';
$this->result = DB::Aowow()->select('SELECT '.($key ? 'tbl.`'.$key.'` AS ARRAY_KEY, ' : '').'tbl.* FROM ?# tbl', 'dbc_'.$this->file);
return $this->result;
}
public function readFromFile($localized = false)
{
if (!$this->file)
return [];
$foundMask = 0x0;
foreach (FileGen::$expectedPaths as $locStr => $locId)
{
if ($foundMask & (1 << $locId))
continue;
$fullpath = FileGen::$srcDir.($locStr ? $locStr.'/' : '').'DBFilesClient/'.$this->file.'.dbc';
if (!FileGen::fileExists($fullpath))
continue;
FileGen::status(' - reading '.($localized ? 'and merging ' : '').'data from '.$fullpath);
if (!$this->read($fullpath, $localized))
FileGen::status(' - DBC::read() returned with error', MSG_LVL_ERROR);
else
$foundMask |= (1 << $locId);
if (!$localized) // one match is enough
break;
}
return $this->getIndexed();
}
/*
Convert DBC file content into a 2-dimentional array
$filename - name of the file
$format - format string, that contains 1 character for each field
Supported format characters:
x - not used/unknown, 4 bytes
X - not used/unknown, 1 byte
s - char*
f - float, 4 bytes (rounded to 4 digits after comma)
i - unsigned int, 4 bytes
b - unsigned char, 1 byte
d - sorted by this field, not included in array
n - same, but field included in array
*/
private function read($filename, $mergeStrings = false)
{
$file = fopen($filename, 'rb');
if (!$file)
{
FileGen::status('cannot open file '.$filename, MSG_LVL_ERROR);
return false;
}
$filesize = filesize($filename);
if ($filesize < 20)
{
FileGen::status('file '.$filename.' is too small for a DBC file', MSG_LVL_ERROR);
return false;
}
if (fread($file, 4) != 'WDBC')
{
FileGen::status('file '.$filename.' has incorrect magic bytes', MSG_LVL_ERROR);
return false;
}
$header = unpack('VrecordCount/VfieldCount/VrecordSize/VstringSize', fread($file, 16));
// Different debug checks to be sure, that file was opened correctly
$debugStr = '(recordCount='.$header['recordCount'].
' fieldCount=' .$header['fieldCount'] .
' recordSize=' .$header['recordSize'] .
' stringSize=' .$header['stringSize'] .')';
if ($header['recordCount'] * $header['recordSize'] + $header['stringSize'] + 20 != $filesize)
{
FileGen::status('file '.$filename.' has incorrect size '.$filesize.': '.$debugstr, MSG_LVL_ERROR);
return false;
}
if ($header['fieldCount'] != strlen($this->format))
{
FileGen::status('incorrect format string ('.$this->format.') specified for file '.$filename.' fieldCount='.$header['fieldCount'], MSG_LVL_ERROR);
return false;
}
$unpackStr = '';
$unpackFmt = array(
'x' => 'x/x/x/x',
'X' => 'x',
's' => 'V',
'f' => 'f',
'i' => 'V',
'b' => 'C',
'd' => 'x4',
'n' => 'V'
);
// Check that record size also matches
$recSize = 0;
for ($i = 0; $i < strlen($this->format); $i++)
{
$ch = $this->format[$i];
if ($ch == 'X' || $ch == 'b')
$recSize += 1;
else
$recSize += 4;
if (!isset($unpackFmt[$ch]))
{
FileGen::status('unknown format parameter \''.$ch.'\' in format string', MSG_LVL_ERROR);
return false;
}
$unpackStr .= '/'.$unpackFmt[$ch];
if ($ch != 'X' && $ch != 'x')
$unpackStr .= 'f'.$i;
}
$unpackStr = substr($unpackStr, 1);
// Optimizing unpack string: 'x/x/x/x/x/x' => 'x6'
while (preg_match('/(x\/)+x/', $unpackStr, $r))
$unpackStr = substr_replace($unpackStr, 'x'.((strlen($r[0]) + 1) / 2), strpos($unpackStr, $r[0]), strlen($r[0]));
// The last debug check (most of the code in this function is for debug checks)
if ($recSize != $header['recordSize'])
{
FileGen::status('format string size ('.$recSize.') for file '.$filename.' does not match actual size ('.$header['recordSize'].') '.$debugstr, MSG_LVL_ERROR);
return false;
}
// Cache the data to make it faster
$data = fread($file, $header['recordCount'] * $header['recordSize']);
$strings = fread($file, $header['stringSize']);
fclose($file);
// And, finally, extract the records
$cache = [];
$rSize = $header['recordSize'];
$rCount = $header['recordCount'];
$fCount = strlen($this->format);
for ($i = 0; $i < $rCount; $i++)
{
$row = [];
$idx = $i;
$record = unpack($unpackStr, substr($data, $i * $rSize, $rSize));
// add 'virtual' enumerator for gt*-dbcs
if ($this->isGameTable)
$row[] = $i;
for ($j = 0; $j < $fCount; $j++)
{
if (!isset($record['f'.$j]))
continue;
$value = $record['f'.$j];
if ($this->format[$j] == 's')
{
if (isset($cache[$value]))
$value = $cache[$value];
else
{
$s = substr($strings, $value);
$s = substr($s, 0, strpos($s, "\000"));
$cache[$value] = $s;
$value = $s;
}
}
else if ($this->format[$j] == 'f')
$value = round($value, 8);
$row[] = $value;
if ($this->format[$j] == 'n')
$idx = $value;
}
if (!$mergeStrings || empty($this->result[$idx]))
$this->result[$idx] = $row;
else
{
$n = 0;
for ($j = 0; $j < $fCount; $j++)
{
if ($this->format[$j] == 's')
if (!$this->result[$idx][$n] && $row[$n])
$this->result[$idx][$n] = $row[$n];
if ($this->format[$j] != 'x')
$n++;
}
}
}
return !empty($this->result);
}
private function getIndexed()
{
$result = $this->result;
$fields = $this->fields;
if ($this->isGameTable)
array_unshift($fields, 'idx');
foreach ($result as &$row)
$row = array_combine($fields, $row);
return $result;
}
}
?>

View File

@@ -0,0 +1,729 @@
<?php
/*
generate maps - code for extracting regular maps for AoWoW
This file is a part of AoWoW project.
Copyright (C) 2010 Mix <ru-mangos.ru>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('AOWOW_REVISION'))
die('illegal access');
// note: for the sake of simplicity, this function handles all images, that must be stitched together (which are mostly maps)
function complexImg()
{
if (isset(FileGen::$cliOpts['help']))
{
echo "\n";
echo "available options for subScript 'complexImg':\n"; // modeMask
echo "--talentbgs (backgrounds for talent calculator)\n"; // 0x01
echo "--maps (generates worldmaps)\n"; // 0x02
echo "--spawn-maps (creates alphaMasks of each zone to check spawns against)\n"; // 0x04
echo "--artwork (optional: imagery from /glues/credits (not used, skipped by default))\n"; // 0x08
echo "--area-maps (optional: renders maps with highlighted subZones for each area)\n"; // 0x10
return true;
}
if (!class_exists('DBC'))
{
FileGen::status(' - simpleImg: required class DBC was not included', MSG_LVL_ERROR);
return false;
}
if (!function_exists('imagecreatefromblp'))
{
FileGen::status(' - complexImg: required include imagecreatefromblp() was not included', MSG_LVL_ERROR);
return false;
}
$mapWidth = 1002;
$mapHeight = 668;
$runTime = ini_get('max_execution_time');
$locStr = null;
$dbcPath = FileGen::$srcDir.'%sDBFilesClient/';
$imgPath = FileGen::$srcDir.'%sInterface/';
$destDir = 'static/images/wow/';
$success = true;
$paths = ['WorldMap/', 'TalentFrame/', 'Glues/Credits/'];
$modeMask = 0x7; // talentBGs, regular maps, spawn-related alphaMaps
$createAlphaImage = function($w, $h)
{
$img = imagecreatetruecolor($w, $h);
imagesavealpha($img, true);
imagealphablending($img, false);
$bgColor = imagecolorallocatealpha($img, 0, 0, 0, 127);
imagefilledrectangle($img, 0, 0, imagesx($img) - 1, imagesy($img) - 1, $bgColor);
imagecolordeallocate($img, $bgColor);
imagealphablending($img, true);
return $img;
};
// prefer manually converted PNG files (as the imagecreatefromblp-script has issues with some formats)
// alpha channel issues observed with locale deDE Hilsbrad and Elwynn - maps
// see: https://github.com/Kanma/BLPConverter
$loadImageFile = function($path)
{
$result = null;
$file = $path.'.png';
if (FileGen::fileExists($file))
$result = imagecreatefrompng($file);
if (!$result)
{
$file = $path.'.blp';
if (FileGen::fileExists($file))
$result = imagecreatefromblp($file);
}
return $result;
};
$assembleImage = function($baseName, $order, $w, $h) use ($loadImageFile)
{
$dest = imagecreatetruecolor($w, $h);
imagesavealpha($dest, true);
imagealphablending($dest, false);
$_h = $h;
foreach ($order as $y => $row)
{
$_w = $w;
foreach ($row as $x => $suffix)
{
$src = $loadImageFile($baseName.$suffix);
if (!$src)
{
FileGen::status(' - complexImg: tile '.$baseName.$suffix.'.blp missing.', MSG_LVL_ERROR);
unset($dest);
return null;
}
imagecopyresampled($dest, $src, 256 * $x, 256 * $y, 0, 0, min($_w, 256), min($_h, 256), min($_w, 256), min($_h, 256));
$_w -= 256;
unset($src);
}
$_h -= 256;
}
return $dest;
};
$writeImage = function($name, $ext, $src, $w, $h, $done)
{
$ok = false;
$dest = imagecreatetruecolor($w, $h);
imagesavealpha($dest, true);
imagealphablending($dest, false);
imagecopyresampled($dest, $src, 0, 0, 0, 0, $w, $h, imagesx($src), imagesy($src));
switch ($ext)
{
case 'jpg':
$ok = imagejpeg($dest, $name.'.'.$ext, 85);
break;
case 'png':
$ok = imagepng($dest, $name.'.'.$ext);
break;
default:
FileGen::status($done.' - unsupported file fromat: '.$ext, MSG_LVL_WARN);
}
imagedestroy($dest);
if ($ok)
{
chmod($name.'.'.$ext, FileGen::$accessMask);
FileGen::status($done.' - image '.$name.'.'.$ext.' written', MSG_LVL_OK);
}
else
FileGen::status($done.' - could not create image '.$name.'.'.$ext, MSG_LVL_ERROR);
return $ok;
};
$createSpawnMap = function($img, $zoneId) use ($mapHeight, $mapWidth)
{
FileGen::status(' - creating spawn map');
$tmp = imagecreate(1000, 1000);
$cbg = imagecolorallocate($tmp, 255, 255, 255);
$cfg = imagecolorallocate($tmp, 0, 0, 0);
for ($y = 0; $y < 1000; $y++)
{
for ($x = 0; $x < 1000; $x++)
{
$a = imagecolorat($img, ($x * $mapWidth) / 1000, ($y * $mapHeight) / 1000) >> 24;
imagesetpixel($tmp, $x, $y, $a < 30 ? $cfg : $cbg);
}
}
imagepng($tmp, 'cache/alphaMaps/' . $zoneId . '.png');
imagecolordeallocate($tmp, $cbg);
imagecolordeallocate($tmp, $cfg);
imagedestroy($tmp);
};
$checkSourceDirs = function($sub, &$missing = []) use ($imgPath, $dbcPath, $paths, &$modeMask)
{
$incomplete = false;
foreach ($paths as $idx => $subDir)
{
if ($idx == 0 && !($modeMask & 0x16)) // map related
continue;
else if ($idx == 1 && !($modeMask & 0x1)) // talentBGs
continue;
else if ($idx == 2 && !($modeMask & 0x8)) // artwork
continue;
$p = sprintf($imgPath, $sub).$subDir;
if (!FileGen::fileExists($p))
{
$missing[] = $p;
$incomplete = true;
}
}
if ($modeMask & 0x17)
{
$p = sprintf($dbcPath, $sub);
if (!FileGen::fileExists($p))
{
$missing[] = $p;
$incomplete = true;
}
}
return !$incomplete;
};
// do not change order of params!
if ($_ = FileGen::hasOpt('talentbgs', 'maps', 'spawn-maps', 'artwork', 'area-maps'))
$modeMask = $_;
foreach (FileGen::$expectedPaths as $xp => $__)
{
if ($xp) // if sun subDir add trailing slash
$xp .= '/';
if ($checkSourceDirs($xp, $missing))
{
$locStr = $xp;
break;
}
}
// if no subdir had sufficient data, diaf
if ($locStr === null)
{
FileGen::status('one or more required directories are missing:', MSG_LVL_ERROR);
foreach ($missing as $m)
FileGen::status(' - '.$m, MSG_LVL_ERROR);
return;
}
/**************/
/* TalentTabs */
/**************/
if ($modeMask & 0x01)
{
if (FileGen::writeDir($destDir.'hunterpettalents/') && FileGen::writeDir($destDir.'talents/backgrounds/'))
{
// [classMask, creatureFamilyMask, tabNr, textureStr]
$talentTab = (new DBC('TalentTab'))->readArbitrary();
$chrClass = (new DBC('ChrClasses'))->readArbitrary();
$order = array(
['-TopLeft', '-TopRight'],
['-BottomLeft', '-BottomRight']
);
if ($chrClass && $talentTab)
{
$sum = 0;
$total = count($talentTab);
FileGen::status('Processing '.$total.' files from TalentFrame/ ...');
foreach ($talentTab as $tt)
{
ini_set('max_execution_time', 30); // max 30sec per image (loading takes the most time)
$sum++;
$done = ' - '.str_pad($sum.'/'.$total, 8).str_pad('('.number_format($sum * 100 / $total, 2).'%)', 9);
if ($tt['creatureFamilyMask']) // is PetCalc
{
$size = [244, 364];
$name = $destDir.'hunterpettalents/bg_'.(log($tt['creatureFamilyMask'], 2) + 1);
}
else
{
$size = [204, 554];
$name = $destDir.'talents/backgrounds/'.strtolower($chrClass[log($tt['classMask'], 2) + 1]['nameINT']).'_'.($tt['tabNumber'] + 1);
}
if (!isset(FileGen::$cliOpts['force']) && file_exists($name.'.jpg'))
{
FileGen::status($done.' - file '.$name.'.jpg was already processed');
continue;
}
$im = $assembleImage(sprintf($imgPath, $locStr).'TalentFrame/'.$tt['textureFile'], $order, 256 + 44, 256 + 75);
if (!$im)
{
FileGen::status(' - could not assemble file '.$tt['textureFile'], MSG_LVL_ERROR);
continue;
}
if (!$writeImage($name, 'jpg', $im, $size[0], $size[1], $done))
$success = false;
}
}
else
$success = false;
ini_set('max_execution_time', $runTime);
}
else
$success = false;
}
/************/
/* Worldmap */
/************/
if ($modeMask & 0x16)
{
$mapDirs = array(
['maps/%snormal/', 'jpg', 488, 325],
['maps/%soriginal/', 'jpg', 0, 0], // 1002, 668
['maps/%ssmall/', 'jpg', 224, 163],
['maps/%szoom/', 'jpg', 772, 515]
);
// as the js expects them
$baseLevelFix = array(
// WotLK maps
// Halls of Stone; The Nexus; Violet Hold; Gundrak; Obsidian Sanctum; Eye of Eternity; Vault of Archavon; Trial of the Champion; The Forge of Souls; Pit of Saron; Halls of Reflection
4264 => 1, 4265 => 1, 4415 => 1, 4416 => 1, 4493 => 0, 4500 => 1, 4603 => 1, 4723 => 1, 4809 => 1, 4813 => 1, 4820 => 1,
// Cata maps for WotLK instances
// TheStockade; TheBloodFurnace; Ragefire; TheUnderbog; TheBotanica; WailingCaverns; TheSlavePens; TheShatteredHalls; HellfireRamparts; RazorfenDowns; RazorfenKraul; ManaTombs
// ShadowLabyrinth; TheTempleOfAtalHakkar (simplified layout); BlackTemple; TempestKeep; MoltenCore; GruulsLair; CoilfangReservoir; MagtheridonsLair; OnyxiasLair; SunwellPlateau;
717 => 1, 3713 => 1, 2437 => 1, 3716 => 1, 3847 => 1, 718 => 1, 3717 => 1, 3714 => 1, 3562 => 1, 722 => 1, 491 => 1, 3792 => 1,
3789 => 1, 1477 => 1, 3959 => 0, 3845 => 1, 2717 => 1, 3923 => 1, 3607 => 1, 3836 => 1, 2159 => 1, 4075 => 0
);
$tmp = (new DBC('WorldMapArea'))->readArbitrary();
$wma = [];
foreach ($tmp as $row)
{
// fixups...
if (!$row['areaId'])
{
switch ($row['Id'])
{
case 13: $row['areaId'] = -6; break; // Kalimdor
case 14: $row['areaId'] = -3; break; // Eastern Kingdoms
case 466: $row['areaId'] = -2; break; // Outland
case 485: $row['areaId'] = -5; break; // Northrend
}
}
$wma[] = $row;
}
$tmp = (new DBC('WorldMapOverlay'))->readFiltered(function(&$val) { return !empty($val['textureString']); });
$wmo = [];
foreach ($tmp as $row)
$wmo[$row['worldMapAreaId']][] = $row;
if (!$wma || !$wmo)
{
$success = false;
FileGen::status(' - could not read required dbc files: WorldMapArea.dbc ['.count($wma).' entries]; WorldMapOverlay.dbc ['.count($wmo).' entries]', MSG_LVL_ERROR);
return;
}
// more fixups to WorldMapArea
array_unshift($wma, ['Id' => -1, 'areaId' => -1, 'nameINT' => 'World'], ['Id' => -4, 'areaId' => -4, 'nameINT' => 'Cosmic']);
$sumMaps = count(FileGen::$localeIds) * count($wma);
FileGen::status('Processing '.$sumMaps.' files from WorldMap/ ...');
foreach (FileGen::$localeIds as $progressLoc => $l)
{
// create destination directories
$dirError = false;
foreach ($mapDirs as $md)
if (!FileGen::writeDir($destDir . sprintf($md[0], strtolower(Util::$localeStrings[$l]).'/')))
$dirError = true;
if ($modeMask & 0x04)
if (!FileGen::writeDir('cache/alphaMaps'))
$dirError = true;
if ($dirError)
{
$success = false;
FileGen::status(' - complexImg: could not create map directories for locale '.$l.'. skipping...', MSG_LVL_ERROR);
continue;
}
// source for mapFiles
$mapSrcDir = null;
$locDirs = array_filter(FileGen::$expectedPaths, function($var) use ($l) { return !$var || $var == $l; });
foreach ($locDirs as $mapLoc => $__)
{
if ($mapLoc) // and trailing slash again
$mapLoc .= '/';
$p = sprintf($imgPath, $mapLoc).$paths[0];
if (FileGen::fileExists($p))
{
FileGen::status(' - using files from '.($mapLoc ?: '/').' for locale '.Util::$localeStrings[$l], MSG_LVL_WARN);
$mapSrcDir = $p.'/';
break;
}
}
if ($mapSrcDir === null)
{
$success = false;
FileGen::status(' - no suitable localized map files found for locale '.$l, MSG_LVL_ERROR);
continue;
}
foreach ($wma as $progressArea => $areaEntry)
{
$curMap = $progressArea + count($wma) * $progressLoc;
$progress = ' - ' . str_pad($curMap.'/'.($sumMaps), 10) . str_pad('('.number_format($curMap * 100 / $sumMaps, 2).'%)', 9);
$wmaId = $areaEntry['Id'];
$zoneId = $areaEntry['areaId'];
$textureStr = $areaEntry['nameINT'];
$path = $mapSrcDir.$textureStr;
if (!FileGen::fileExists($path))
{
$success = false;
FileGen::status('worldmap file '.$path.' missing for selected locale '.Util::$localeStrings[$l], MSG_LVL_ERROR);
continue;
}
$fmt = array(
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]
);
FileGen::status($textureStr . " [" . $zoneId . "]");
$overlay = $createAlphaImage($mapWidth, $mapHeight);
// zone has overlays (is in open world; is not multiLeveled)
if (isset($wmo[$wmaId]))
{
FileGen::status(' - area has '.count($wmo[$wmaId]).' overlays');
foreach ($wmo[$wmaId] as &$row)
{
$i = 1;
$y = 0;
while ($y < $row['h'])
{
$x = 0;
while ($x < $row['w'])
{
$img = $loadImageFile($path . '/' . $row['textureString'] . $i);
if (!$img)
{
FileGen::status(' - complexImg: tile '.$path.'/'.$row['textureString'].$i.'.blp missing.', MSG_LVL_ERROR);
break 2;
}
imagecopy($overlay, $img, $row['x'] + $x, $row['y'] + $y, 0, 0, imagesx($img), imagesy($img));
// prepare subzone image
if ($modeMask & 0x10)
{
if (!isset($row['maskimage']))
{
$row['maskimage'] = $createAlphaImage($row['w'], $row['h']);
$row['maskcolor'] = imagecolorallocatealpha($row['maskimage'], 255, 64, 192, 64);
}
for ($my = 0; $my < imagesy($img); $my++)
for ($mx = 0; $mx < imagesx($img); $mx++)
if ((imagecolorat($img, $mx, $my) >> 24) < 30)
imagesetpixel($row['maskimage'], $x + $mx, $y + $my, $row['maskcolor']);
}
imagedestroy($img);
$x += 256;
$i++;
}
$y += 256;
}
}
// create spawn-maps if wanted
if ($modeMask & 0x04)
$createSpawnMap($overlay, $zoneId);
}
// check, if the current zone is multiLeveled
// if there are also files present without layer-suffix assume them as layer: 0
$multiLeveled = false;
$multiLevel = 0;
do
{
if (!FileGen::filesInPath('/'.$textureStr.'\/'.$textureStr.($multiLevel + 1).'_\d\.blp/i', true))
break;
$multiLevel++;
$multiLeveled = true;
}
while ($multiLevel < 18); // Karazhan has 17 frickin floors
// check if we can create base map anyway
$file = $path.'/'.$textureStr.'1.blp';
$hasBaseMap = FileGen::fileExists($file);
FileGen::status(' - area has '.($multiLeveled ? $multiLevel . ' levels' : 'only base level'));
$map = null;
for ($i = 0; $i <= $multiLevel; $i++)
{
ini_set('max_execution_time', 120); // max 120sec per image
$file = $path.'/'.$textureStr;
if (!$i && !$hasBaseMap)
continue;
// if $multiLeveled also suffix -0 to baseMap if it exists
if ($i && $multiLeveled)
$file .= $i.'_';
$doSkip = 0x0;
$outFile = [];
foreach ($mapDirs as $idx => $info)
{
$outFile[$idx] = $destDir . sprintf($info[0], strtolower(Util::$localeStrings[$l]).'/') . $zoneId;
$floor = $i;
if ($zoneId == 4100) // ToCStratholme: map order fix
$floor += 1;
if ($multiLeveled && !(isset($baseLevelFix[$zoneId]) && $i == $baseLevelFix[$zoneId]))
$outFile[$idx] .= '-'.$floor;
if (!isset(FileGen::$cliOpts['force']) && file_exists($outFile[$idx].'.'.$info[1]))
{
FileGen::status($progress.' - file '.$outFile[$idx].'.'.$info[1].' was already processed');
$doSkip |= (1 << $idx);
}
}
if ($doSkip == 0xF)
continue;
$map = $assembleImage($file, $fmt, $mapWidth, $mapHeight);
if (!$map)
{
$success = false;
FileGen::status(' - could not create image resource for map '.$zoneId.($multiLevel ? ' level '.$i : ''));
continue;
}
if (!$multiLeveled)
{
imagecolortransparent($overlay, imagecolorat($overlay, imagesx($overlay)-1, imagesy($overlay)-1));
imagecopymerge($map, $overlay, 0, 0, 0, 0, imagesx($overlay), imagesy($overlay), 100);
imagedestroy($overlay);
}
// create map
if ($modeMask & 0x02)
{
foreach ($mapDirs as $idx => $info)
{
if ($doSkip & (1 << $idx))
continue;
if (!$writeImage($outFile[$idx], $info[1], $map, $info[2] ?: $mapWidth, $info[3] ?: $mapHeight, $progress))
$success = false;
}
}
}
// also create subzone-maps
if ($map && isset($wmo[$wmaId]) && $modeMask & 0x10)
{
foreach ($wmo[$wmaId] as &$row)
{
$doSkip = 0x0;
$outFile = [];
foreach ($mapDirs as $idx => $info)
{
$outFile[$idx] = $destDir . sprintf($info[0], strtolower(Util::$localeStrings[$l]).'/') . $row['areaTableId'];
if (!isset(FileGen::$cliOpts['force']) && file_exists($outFile[$idx].'.'.$info[1]))
{
FileGen::status($progress.' - file '.$outFile[$idx].'.'.$info[1].' was already processed');
$doSkip |= (1 << $idx);
}
}
if ($doSkip == 0xF)
continue;
$subZone = imagecreatetruecolor($mapWidth, $mapHeight);
imagecopy($subZone, $map, 0, 0, 0, 0, imagesx($map), imagesy($map));
imagecopy($subZone, $row['maskimage'], $row['x'], $row['y'], 0, 0, imagesx($row['maskimage']), imagesy($row['maskimage']));
foreach ($mapDirs as $idx => $info)
{
if ($doSkip & (1 << $idx))
continue;
if (!$writeImage($outFile[$idx], $info[1], $subZone, $info[2] ?: $mapWidth, $info[3] ?: $mapHeight, $progress))
$success = false;
}
imagedestroy($subZone);
}
}
if ($map)
imagedestroy($map);
}
}
}
/***********/
/* Credits */
/***********/
if ($modeMask & 0x08) // optional tidbits (not used by default)
{
if (FileGen::writeDir($destDir.'interface/Glues/Credits/'))
{
// tile ordering
$order = array(
1 => array(
[1]
),
2 => array(
[1],
[2]
),
4 => array(
[1, 2],
[3, 4]
),
6 => array(
[1, 2, 3],
[4, 5, 6]
),
8 => array(
[1, 2, 3, 4],
[5, 6, 7, 8]
)
);
$imgGroups = [];
$srcPath = sprintf($imgPath, $locStr).'Glues/Credits/';
$files = FileGen::filesInPath($srcPath);
foreach ($files as $f)
{
if (preg_match('/([^\/]+)(\d).blp/i', $f, $m))
{
if ($m[1] && $m[2])
{
if (!isset($imgGroups[$m[1]]))
$imgGroups[$m[1]] = $m[2];
else if ($imgGroups[$m[1]] < $m[2])
$imgGroups[$m[1]] = $m[2];
}
}
}
// errör-korrekt
$imgGroups['Desolace'] = 4;
$imgGroups['BloodElf_Female'] = 6;
$total = count($imgGroups);
$sum = 0;
FileGen::status('Processing '.$total.' files from Glues/Credits/...');
foreach ($imgGroups as $file => $fmt)
{
ini_set('max_execution_time', 30); // max 30sec per image (loading takes the most time)
$sum++;
$done = ' - '.str_pad($sum.'/'.$total, 8).str_pad('('.number_format($sum * 100 / $total, 2).'%)', 9);
$name = $destDir.'interface/Glues/Credits/'.$file;
if (!isset(FileGen::$cliOpts['force']) && file_exists($name.'.png'))
{
FileGen::status($done.' - file '.$name.'.png was already processed');
continue;
}
if (!isset($order[$fmt]))
{
FileGen::status(' - pattern for file '.$name.' not set. skipping', MSG_LVL_WARN);
continue;
}
$im = $assembleImage($srcPath.$file, $order[$fmt], count($order[$fmt][0]) * 256, count($order[$fmt]) * 256);
if (!$im)
{
FileGen::status(' - could not assemble file '.$name, MSG_LVL_ERROR);
continue;
}
if (!$writeImage($name, 'png', $im, count($order[$fmt][0]) * 256, count($order[$fmt]) * 256, $done))
$success = false;
}
ini_set('max_execution_time', $runTime);
}
else
$success = false;
}
return $success;
}
?>

View File

@@ -52,18 +52,17 @@ if (!defined('AOWOW_REVISION'))
}, },
*/ */
function enchants(&$log, $locales) function enchants()
{ {
// from g_item_slots: 13:"One-Hand", 26:"Ranged", 17:"Two-Hand", // from g_item_slots: 13:"One-Hand", 26:"Ranged", 17:"Two-Hand",
$slotPointer = [13, 17, 26, 26, 13, 17, 17, 13, 17, null, 17, null, null, 13, null, 13, null, null, null, null, 17]; $slotPointer = [13, 17, 26, 26, 13, 17, 17, 13, 17, null, 17, null, null, 13, null, 13, null, null, null, null, 17];
$locales = [LOCALE_EN, LOCALE_FR, LOCALE_DE, LOCALE_ES, LOCALE_RU];
$castItems = []; $castItems = [];
$successs = true; $successs = true;
$enchantSpells = new SpellList([['effect1Id', 53], ['name_loc0', 'QA%', '!'], CFG_SQL_LIMIT_NONE]); // enchantItemPermanent && !qualityAssurance $enchantSpells = new SpellList([['effect1Id', 53], ['name_loc0', 'QA%', '!'], CFG_SQL_LIMIT_NONE]); // enchantItemPermanent && !qualityAssurance
// check directory-structure // check directory-structure
foreach (Util::$localeStrings as $dir) foreach (Util::$localeStrings as $dir)
if (!writeDir('datasets/'.$dir, $log)) if (!FileGen::writeDir('datasets/'.$dir))
$success = false; $success = false;
$enchIds = []; $enchIds = [];
@@ -73,7 +72,7 @@ if (!defined('AOWOW_REVISION'))
$enchMisc = []; $enchMisc = [];
$enchJSON = Util::parseItemEnchantment($enchIds, false, $enchMisc); $enchJSON = Util::parseItemEnchantment($enchIds, false, $enchMisc);
foreach ($locales as $lId) foreach (FileGen::$localeIds as $lId)
{ {
set_time_limit(120); set_time_limit(120);
@@ -135,11 +134,11 @@ if (!defined('AOWOW_REVISION'))
$ench['jsonequip']['requiredLevel'] = $enchMisc[$eId]['requiredLevel']; $ench['jsonequip']['requiredLevel'] = $enchMisc[$eId]['requiredLevel'];
// check if the spell has an entry in skill_line_ability -> Source:Profession // check if the spell has an entry in skill_line_ability -> Source:Profession
if ($skill = DB::Aowow()->SelectCell('SELECT skillLineId FROM dbc.skilllineability WHERE spellId = ?d', $enchantSpells->id)) if ($skills = $enchantSpells->getField('skillLines'))
{ {
$ench['name'][] = $enchantSpells->getField('name', true); $ench['name'][] = $enchantSpells->getField('name', true);
$ench['source'][] = $enchantSpells->id; $ench['source'][] = $enchantSpells->id;
$ench['skill'] = $skill; $ench['skill'] = $skills[0];
$ench['slots'][] = $slot; $ench['slots'][] = $slot;
} }
@@ -209,12 +208,10 @@ if (!defined('AOWOW_REVISION'))
if (is_array($v) && count($v) == 1 && $k != 'jsonequip') if (is_array($v) && count($v) == 1 && $k != 'jsonequip')
$ench[$k] = $v[0]; $ench[$k] = $v[0];
$toFile = "var g_enchants = "; $toFile = "var g_enchants = ".Util::toJSON($enchantsOut).";";
$toFile .= json_encode($enchantsOut, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK);
$toFile .= ";";
$file = 'datasets/'.User::$localeString.'/enchants'; $file = 'datasets/'.User::$localeString.'/enchants';
if (!writeFile($file, $toFile, $log)) if (!FileGen::writeFile($file, $toFile))
$success = false; $success = false;
} }

View File

@@ -0,0 +1,423 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
// shared strings
define('ERR_CREATE_FILE', 'could not create file at destination %s' );
define('ERR_WRITE_FILE', 'could not write to file at destination %s' );
define('ERR_READ_FILE', 'file %s could not be read' );
define('ERR_MISSING_FILE', 'file %s not found' );
define('ERR_NONE', 'created file %s' );
define('ERR_MISSING_INCL', 'required function %s() could not be found at %s');
define('MSG_LVL_OK', 0);
define('MSG_LVL_WARN', 1);
define('MSG_LVL_ERROR', 2);
class FileGen
{
public static $success = false;
public static $srcDir = 'setup/mpqData/';
public static $tplPath = 'setup/tools/filegen/templates/';
// update paths [yes, you can have en empty string as key]
public static $expectedPaths = array(
'frFR' => 2,
'deDE' => 3,
'esES' => 6, 'esMX' => 6,
'ruRU' => 8,
'' => 0, 'enGB' => 0, 'enUS' => 0,
);
public static $cliOpts = [];
private static $shortOpts = 'fh';
private static $longOpts = array(
'build:', 'log::', 'help', 'locales::', 'force', 'mpqDataDir::', // general
'icons', 'glyphs', 'pagetexts', 'loadingscreens', // whole images
'artwork', 'talentbgs', 'maps', 'spawn-maps', 'area-maps' // images from image parts
);
public static $subScripts = [];
public static $tplFiles = array(
'searchplugin' => ['aowow.xml', 'static/download/searchplugins/'],
'power' => ['power.js', 'static/widgets/' ],
'searchboxScript' => ['searchbox.js', 'static/widgets/' ],
'demo' => ['demo.html', 'static/widgets/power/' ],
'searchboxBody' => ['searchbox.html', 'static/widgets/searchbox/' ],
'realmMenu' => ['profile_all.js', 'static/js/' ],
'locales' => ['locale.js', 'static/js/' ],
// 'itemScaling => ['item-scaling', 'datasets/' ], # provided 'as is', as dbc-content doesn't usualy change
);
public static $datasets = array(
'pets', 'simpleImg', 'complexImg',
'realms', 'statistics', 'profiler', // profiler related
'talents', 'talentIcons', 'glyphs', // talentCalc related
'itemsets', 'enchants', 'gems' // comparison related
);
public static $defaultExecTime = 30;
public static $accessMask = 0755;
private static $logFile = '';
private static $logHandle = null;
private static $mpqFiles = [];
private static $locales = [];
public static $localeIds = [];
private static $reqDirs = array(
'static/uploads/screenshots/normal',
'static/uploads/screenshots/pending',
'static/uploads/screenshots/resized',
'static/uploads/screenshots/temp',
'static/uploads/screenshots/thumb',
'static/uploads/temp/'
);
public static $txtConstants = array(
'CFG_NAME' => CFG_NAME,
'CFG_NAME_SHORT' => CFG_NAME_SHORT,
'HOST_URL' => HOST_URL,
'STATIC_URL' => STATIC_URL
);
public static function init($scriptList = '')
{
self::$defaultExecTime = ini_get('max_execution_time');
$doScripts = [];
if (CLI)
{
if (getopt(self::$shortOpts, self::$longOpts))
self::handleCLIOpts($doScripts);
else
{
self::printCLIHelp(array_merge(array_keys(self::$tplFiles), self::$datasets));
exit;
}
}
else
{
$doScripts = explode(',', $scriptList);
self::$locales = Util::$localeStrings;
}
// check passed subscript names; limit to real scriptNames
self::$subScripts = array_merge(array_keys(self::$tplFiles), self::$datasets);
if ($doScripts)
self::$subScripts = array_intersect($doScripts, self::$subScripts);
// restrict actual locales
foreach (self::$locales as $idx => $str)
{
if (!$str)
continue;
if (!defined('CFG_LOCALES'))
self::$localeIds[] = $idx;
else if (CFG_LOCALES & (1 << $idx))
self::$localeIds[] = $idx;
}
if (!self::$localeIds)
{
self::status('No valid locale specified. Check your config or --locales parameter, if used', MSG_LVL_ERROR);
exit;
}
// create directory structure
self::status('FileGen::init() - creating required directories');
$pathOk = 0;
foreach (self::$reqDirs as $rd)
if (self::writeDir($rd))
$pathOk++;
FileGen::status('created '.$pathOk.' extra paths'.($pathOk == count(self::$reqDirs) ? '' : ' with errors'));
FileGen::status();
}
// shared funcs
public static function writeFile($file, $content)
{
$success = false;
if ($handle = @fOpen($file, "w"))
{
if (fWrite($handle, $content))
{
$success = true;
self::status(sprintf(ERR_NONE, $file), MSG_LVL_OK);
}
else
self::status(sprintf(ERR_WRITE_FILE, $file), MSG_LVL_ERROR);
fClose($handle);
}
else
self::status(sprintf(ERR_CREATE_FILE, $file), MSG_LVL_ERROR);
if ($success)
@chmod($file, FileGen::$accessMask);
return $success;
}
public static function writeDir($dir)
{
if (is_dir($dir))
{
if (!is_writable($dir) && !@chmod($dir, FileGen::$accessMask))
self::status('cannot write into output directory '.$dir, MSG_LVL_ERROR);
return is_writable($dir);
}
if (@mkdir($dir, FileGen::$accessMask, true))
return true;
self::status('could not create output directory '.$dir, MSG_LVL_ERROR);
return false;
}
public static function status($txt = '', $lvl = -1)
{
if (isset(self::$cliOpts['help']))
return;
$cliColor = "\033[%sm%s\033[0m";
$htmlColor = '<span style="color:%s;">%s</span>';
if (self::$logFile && !self::$logHandle)
{
if (!file_exists(self::$logFile))
self::$logHandle = fopen(self::$logFile, 'w');
else
{
$logFileParts = pathinfo(self::$logFile);
$i = 1;
while (file_exists($logFileParts['dirname'].'/'.$logFileParts['filename'].$i.'.'.$logFileParts['extension']))
$i++;
self::$logFile = $logFileParts['dirname'].'/'.$logFileParts['filename'].$i.'.'.$logFileParts['extension'];
self::$logHandle = fopen(self::$logFile, 'w');
}
}
$msg = $raw = "\n";
if ($txt)
{
$msg = $raw = str_pad(date('H:i:s'), 10);
switch ($lvl)
{
case MSG_LVL_ERROR: // red error
$str = 'Error: ';
$raw .= $str;
$msg .= CLI ? sprintf($cliColor, '0;31', $str) : sprintf($htmlColor, 'darkred', $str);
break;
case MSG_LVL_WARN: // yellow warn
$str = 'Notice: ';
$raw .= $str;
$msg .= CLI ? sprintf($cliColor, '0;33', $str) : sprintf($htmlColor, 'orange', $str);
break;
case MSG_LVL_OK: // green success
$str = 'Success:';
$raw = $raw . $str;
$msg .= CLI ? sprintf($cliColor, '0;32', $str) : sprintf($htmlColor, 'darkgreen', $str);
break;
default:
$msg .= ' ';
$raw .= ' ';
}
$msg .= ' '.$txt."\n";
$raw .= ' '.$txt."\n";
}
if (CLI)
{
// maybe for future use: writing \x08 deletes the last char, use to repeatedly update single line (and even WIN should be able to handle it)
echo substr(PHP_OS, 0, 3) == 'WIN' ? $raw : $msg;
if (self::$logHandle)
fwrite(self::$logHandle, $raw);
@ob_flush();
flush();
@ob_end_flush();
}
else
echo "<pre>".$msg."</pre>\n";
}
private static function handleCLIOpts(&$doScripts)
{
$_ = getopt(self::$shortOpts, self::$longOpts);
if ((isset($_['help']) || isset($_['h'])) && empty($_['build']))
{
self::printCLIHelp(array_merge(array_keys(self::$tplFiles), self::$datasets));
exit;
}
// required subScripts
if (!empty($_['build']))
$doScripts = explode(',', $_['build']);
// optional logging
if (!empty($_['log']))
self::$logFile = trim($_['log']);
// optional, overwrite existing files
if (isset($_['f']))
self::$cliOpts['force'] = true;
// alternative data source (no quotes, use forward slash)
if (!empty($_['mpqDataDir']))
self::$srcDir = str_replace(['\\', '"', '\''], ['/', '', ''], $_['mpqDataDir']);
if (isset($_['h']))
self::$cliOpts['help'] = true;
// optional limit handled locales
if (!empty($_['locales']))
{
// engb and enus are identical for all intents and purposes
$from = ['engb', 'esmx'];
$to = ['enus', 'eses'];
$_['locales'] = str_replace($from, $to, strtolower($_['locales']));
self::$locales = array_intersect(Util::$localeStrings, explode(',', $_['locales']));
}
else
self::$locales = Util::$localeStrings;
// mostly build-instructions from longOpts
foreach (self::$longOpts as $opt)
if (!strstr($opt, ':') && isset($_[$opt]))
self::$cliOpts[$opt] = true;
}
public static function hasOpt(/* ...$opt */)
{
$result = 0x0;
foreach (func_get_args() as $idx => $arg)
{
if (!is_string($arg))
continue;
if (isset(self::$cliOpts[$arg]))
$result |= (1 << $idx);
}
return $result;
}
/* the problem
1) paths provided in dbc files are case-insensitive and random
2) paths to the actual textures contained in the mpq archives are case-insensitive and random
unix systems will throw a fit if you try to get from one to the other, so lets save the paths from 2) and cast it to lowecase
lookups will be done in lowercase. A successfull match will return the real path.
*/
private static function buildFileList()
{
self::status('FileGen::init() - reading MPQdata from '.self::$srcDir.' to list for first time use...');
$setupDirs = glob('setup/*');
foreach ($setupDirs as $sd)
{
if (substr(self::$srcDir, -1) == '/')
self::$srcDir = substr(self::$srcDir, 0, -1);
if (substr($sd, -1) == '/')
$sd = substr($sd, 0, -1);
if (strtolower($sd) == strtolower(self::$srcDir))
{
self::$srcDir = $sd.'/';
break;
}
}
try
{
$iterator = new RecursiveDirectoryIterator(self::$srcDir);
$iterator->setFlags(RecursiveDirectoryIterator::SKIP_DOTS);
foreach (new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::SELF_FIRST) as $path)
{
$_ = str_replace('\\', '/', $path->getPathname());
self::$mpqFiles[strtolower($_)] = $_;
}
self::status('done');
self::status();
}
catch (UnexpectedValueException $e) { self::status('- mpqData dir '.self::$srcDir.' does not exist', MSG_LVL_ERROR); }
}
public static function fileExists(&$file)
{
// read mpq source file structure to tree
if (!self::$mpqFiles)
self::buildFileList();
// backslash to forward slash
$_ = strtolower(str_replace('\\', '/', $file));
// remove trailing slash
if (substr($_, -1, 1) == '/')
$_ = substr($_, 0, -1);
if (isset(self::$mpqFiles[$_]))
{
$file = self::$mpqFiles[$_];
return true;
}
return false;
}
public static function filesInPath($path, $useRegEx = false)
{
$result = [];
// read mpq source file structure to tree
if (!self::$mpqFiles)
self::buildFileList();
// backslash to forward slash
$_ = strtolower(str_replace('\\', '/', $path));
foreach (self::$mpqFiles as $lowerFile => $realFile)
{
if (!$useRegEx && strstr($lowerFile, $_))
$result[] = $realFile;
else if ($useRegEx && preg_match($path, $lowerFile))
$result[] = $realFile;
}
return $result;
}
public static function printCLIHelp($scripts)
{
echo "usage: php index.php --build=<subScriptList,> [-h --help] [--log logfile] [-f --force] [--mpqDataDir=path/to/mpqData/] [--locales=<regionCodes,>]\n\n";
echo "build -> available subScripts:\n";
foreach ($scripts as $s)
echo " - ".str_pad($s, 20).(isset(self::$tplFiles[$s]) ? self::$tplFiles[$s][1].self::$tplFiles[$s][0] : 'static data file')."\n";
echo "help -> shows this info\n";
echo "log -> writes ouput to file\n";
echo "force -> enforces overwriting existing files\n";
echo "locales -> limits setup to enUS, frFR, deDE, esES and/or ruRU (does not override config settings)\n";
echo "mpqDataDir -> manually point to directory with extracted mpq data (default: setup/mpqData/)\n";
}
}
?>

View File

@@ -21,7 +21,7 @@ if (!defined('AOWOW_REVISION'))
}, },
*/ */
function gems(&$log, $locales) function gems()
{ {
// sketchy, but should work // sketchy, but should work
// Id < 36'000 || ilevel < 70 ? BC : WOTLK // Id < 36'000 || ilevel < 70 ? BC : WOTLK
@@ -41,7 +41,7 @@ if (!defined('AOWOW_REVISION'))
// check directory-structure // check directory-structure
foreach (Util::$localeStrings as $dir) foreach (Util::$localeStrings as $dir)
if (!writeDir('datasets/'.$dir, $log)) if (!FileGen::writeDir('datasets/'.$dir))
$success = false; $success = false;
$enchIds = []; $enchIds = [];
@@ -51,7 +51,7 @@ if (!defined('AOWOW_REVISION'))
$enchMisc = []; $enchMisc = [];
$enchJSON = Util::parseItemEnchantment($enchIds, false, $enchMisc); $enchJSON = Util::parseItemEnchantment($enchIds, false, $enchMisc);
foreach ($locales as $lId) foreach (FileGen::$localeIds as $lId)
{ {
set_time_limit(5); set_time_limit(5);
@@ -72,12 +72,10 @@ if (!defined('AOWOW_REVISION'))
); );
} }
$toFile = "var g_gems = "; $toFile = "var g_gems = ".Util::toJSON($gemsOut).";";
$toFile .= json_encode($gemsOut, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK);
$toFile .= ";";
$file = 'datasets/'.User::$localeString.'/gems'; $file = 'datasets/'.User::$localeString.'/gems';
if (!writeFile($file, $toFile, $log)) if (!FileGen::writeFile($file, $toFile))
$success = false; $success = false;
} }

View File

@@ -20,7 +20,7 @@ if (!defined('AOWOW_REVISION'))
}, },
*/ */
function glyphs(&$log, $locales) function glyphs()
{ {
$success = true; $success = true;
$glyphList = DB::Aowow()->Select( $glyphList = DB::Aowow()->Select(
@@ -42,12 +42,12 @@ if (!defined('AOWOW_REVISION'))
// check directory-structure // check directory-structure
foreach (Util::$localeStrings as $dir) foreach (Util::$localeStrings as $dir)
if (!writeDir('datasets/'.$dir, $log)) if (!FileGen::writeDir('datasets/'.$dir))
$success = false; $success = false;
$glyphSpells = new SpellList(array(['s.id', array_keys($glyphList)], CFG_SQL_LIMIT_NONE)); $glyphSpells = new SpellList(array(['s.id', array_keys($glyphList)], CFG_SQL_LIMIT_NONE));
foreach ($locales as $lId) foreach (FileGen::$localeIds as $lId)
{ {
set_time_limit(30); set_time_limit(30);
@@ -76,12 +76,10 @@ if (!defined('AOWOW_REVISION'))
); );
} }
$toFile = "var g_glyphs = "; $toFile = "var g_glyphs = ".Util::toJSON($glyphsOut).";";
$toFile .= json_encode($glyphsOut, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK);
$toFile .= ";";
$file = 'datasets/'.User::$localeString.'/glyphs'; $file = 'datasets/'.User::$localeString.'/glyphs';
if (!writeFile($file, $toFile, $log)) if (!FileGen::writeFile($file, $toFile))
$success = false; $success = false;
} }

View File

@@ -29,7 +29,7 @@ if (!defined('AOWOW_REVISION'))
}, },
*/ */
function itemsets(&$log, $locales) function itemsets()
{ {
$success = true; $success = true;
$setList = DB::Aowow()->Select('SELECT * FROM ?_itemset ORDER BY refSetId DESC'); $setList = DB::Aowow()->Select('SELECT * FROM ?_itemset ORDER BY refSetId DESC');
@@ -37,10 +37,10 @@ if (!defined('AOWOW_REVISION'))
// check directory-structure // check directory-structure
foreach (Util::$localeStrings as $dir) foreach (Util::$localeStrings as $dir)
if (!writeDir('datasets/'.$dir, $log)) if (!FileGen::writeDir('datasets/'.$dir))
$success = false; $success = false;
foreach ($locales as $lId) foreach (FileGen::$localeIds as $lId)
{ {
User::useLocale($lId); User::useLocale($lId);
Lang::load(Util::$localeStrings[$lId]); Lang::load(Util::$localeStrings[$lId]);
@@ -120,12 +120,10 @@ if (!defined('AOWOW_REVISION'))
$itemsetOut[$setOut['id']] = $setOut; $itemsetOut[$setOut['id']] = $setOut;
} }
$toFile = "var g_itemsets = "; $toFile = "var g_itemsets = ".Util::toJSON($itemsetOut).";";
$toFile .= json_encode($itemsetOut, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK);
$toFile .= ";";
$file = 'datasets/'.User::$localeString.'/itemsets'; $file = 'datasets/'.User::$localeString.'/itemsets';
if (!writeFile($file, $toFile, $log)) if (!FileGen::writeFile($file, $toFile))
$success = false; $success = false;
} }

View File

@@ -7,7 +7,7 @@ if (!defined('AOWOW_REVISION'))
// Create 'locale.js'-file in static/js // Create 'locale.js'-file in static/js
// available locales have to be set in aowow.aowow_config // available locales have to be set in aowow.aowow_config
function locales(&$log, $locales) function locales()
{ {
$result = []; $result = [];
$available = array( $available = array(
@@ -43,7 +43,7 @@ if (!defined('AOWOW_REVISION'))
" }", " }",
); );
foreach ($locales as $l) foreach (FileGen::$localeIds as $l)
if (isset($available[$l])) if (isset($available[$l]))
$result[] = $available[$l]; $result[] = $available[$l];

View File

@@ -5,8 +5,6 @@ if (!defined('AOWOW_REVISION'))
// builds 'pets'-file for available locales // builds 'pets'-file for available locales
// this script requires the following dbc-files to be parsed and available
// CreatureFamily, CreatureDisplayInfo, FactionTemplate, AreaTable
/* Example data /* Example data
30: { 30: {
@@ -25,7 +23,7 @@ if (!defined('AOWOW_REVISION'))
}, },
*/ */
function pets(&$log, $locales) function pets()
{ {
$success = true; $success = true;
$locations = []; $locations = [];
@@ -38,22 +36,21 @@ if (!defined('AOWOW_REVISION'))
cr.rank AS classification, cr.rank AS classification,
cr.family, cr.family,
cr.displayId1 AS displayId, cr.displayId1 AS displayId,
cdi.skin1 AS skin, cr.textureString AS skin,
SUBSTRING_INDEX(cf.iconFile, "\\\\", -1) AS icon, p.iconString AS icon,
cf.petTalentType AS type p.type
FROM ?_creature cr FROM ?_creature cr
JOIN ?_factiontemplate ft ON ft.Id = cr.faction JOIN ?_factiontemplate ft ON ft.Id = cr.faction
JOIN dbc.creaturefamily cf ON cf.Id = cr.family JOIN ?_pet p ON p.id = cr.family
JOIN dbc.creaturedisplayinfo cdi ON cdi.id = cr.displayId1 WHERE cr.typeFlags & 0x1 AND (cr.cuFlags & 0x2) = 0
WHERE cf.petTalentType <> -1 AND cr.typeFlags & 0x1 AND (cr.cuFlags & 0x2) = 0
ORDER BY cr.id ASC'); ORDER BY cr.id ASC');
// check directory-structure // check directory-structure
foreach (Util::$localeStrings as $dir) foreach (Util::$localeStrings as $dir)
if (!writeDir('datasets/'.$dir, $log)) if (!FileGen::writeDir('datasets/'.$dir))
$success = false; $success = false;
foreach ($locales as $lId) foreach (FileGen::$localeIds as $lId)
{ {
User::useLocale($lId); User::useLocale($lId);
Lang::load(Util::$localeStrings[$lId]); Lang::load(Util::$localeStrings[$lId]);
@@ -82,12 +79,10 @@ if (!defined('AOWOW_REVISION'))
); );
} }
$toFile = "var g_pets = "; $toFile = "var g_pets = ".Util::toJSON($petsOut).";";
$toFile .= json_encode($petsOut, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK);
$toFile .= ";";
$file = 'datasets/'.User::$localeString.'/pets'; $file = 'datasets/'.User::$localeString.'/pets';
if (!writeFile($file, $toFile, $log)) if (!FileGen::writeFile($file, $toFile))
$success = false; $success = false;
} }

View File

@@ -7,7 +7,7 @@ if (!defined('AOWOW_REVISION'))
// gatheres quasi-static data used in profiler: all available quests, achievements, titles, mounts, companions, factions, recipes // gatheres quasi-static data used in profiler: all available quests, achievements, titles, mounts, companions, factions, recipes
// this script requires a fully set up database and is expected to be run last // this script requires a fully set up database and is expected to be run last
function profiler(&$log, $locales) function profiler()
{ {
$success = true; $success = true;
$scripts = []; $scripts = [];
@@ -15,7 +15,7 @@ if (!defined('AOWOW_REVISION'))
/**********/ /**********/
/* Quests */ /* Quests */
/**********/ /**********/
$scripts[] = function(&$log) use ($locales) $scripts[] = function()
{ {
$success = true; $success = true;
$condition = [ $condition = [
@@ -35,7 +35,7 @@ if (!defined('AOWOW_REVISION'))
$relCurr = new CurrencyList(array(['id', $_])); $relCurr = new CurrencyList(array(['id', $_]));
foreach ($locales as $l) foreach (FileGen::$localeIds as $l)
{ {
set_time_limit(20); set_time_limit(20);
@@ -44,15 +44,15 @@ if (!defined('AOWOW_REVISION'))
$buff = "var _ = g_gatheredcurrencies;\n"; $buff = "var _ = g_gatheredcurrencies;\n";
foreach ($relCurr->getListviewData() as $id => $data) foreach ($relCurr->getListviewData() as $id => $data)
$buff .= '_['.$id.'] = '.json_encode($data, JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK).";\n"; $buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
$buff .= "\n\nvar _ = g_quests;\n"; $buff .= "\n\nvar _ = g_quests;\n";
foreach ($questz->getListviewData() as $id => $data) foreach ($questz->getListviewData() as $id => $data)
$buff .= '_['.$id.'] = '.json_encode($data, JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK).";\n"; $buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
$buff .= "\ng_quest_catorder = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n"; $buff .= "\ng_quest_catorder = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n";
if (!writeFile('datasets/'.User::$localeString.'/p-quests', $buff, $log)) if (!FileGen::writeFile('datasets/'.User::$localeString.'/p-quests', $buff))
$success = false; $success = false;
} }
@@ -62,7 +62,7 @@ if (!defined('AOWOW_REVISION'))
/****************/ /****************/
/* Achievements */ /* Achievements */
/****************/ /****************/
$scripts[] = function(&$log) use ($locales) $scripts[] = function()
{ {
$success = true; $success = true;
$condition = array( $condition = array(
@@ -72,7 +72,7 @@ if (!defined('AOWOW_REVISION'))
); );
$achievez = new AchievementList($condition); $achievez = new AchievementList($condition);
foreach ($locales as $l) foreach (FileGen::$localeIds as $l)
{ {
set_time_limit(5); set_time_limit(5);
@@ -84,7 +84,7 @@ if (!defined('AOWOW_REVISION'))
foreach ($achievez->getListviewData(ACHIEVEMENTINFO_PROFILE) as $id => $data) foreach ($achievez->getListviewData(ACHIEVEMENTINFO_PROFILE) as $id => $data)
{ {
$sumPoints += $data['points']; $sumPoints += $data['points'];
$buff .= '_['.$id.'] = '.json_encode($data, JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK).";\n"; $buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
} }
// categories to sort by // categories to sort by
@@ -92,7 +92,7 @@ if (!defined('AOWOW_REVISION'))
// sum points // sum points
$buff .= "\ng_achievement_points = [".$sumPoints."];\n"; $buff .= "\ng_achievement_points = [".$sumPoints."];\n";
if (!writeFile('datasets/'.User::$localeString.'/p-achievements', $buff, $log)) if (!FileGen::writeFile('datasets/'.User::$localeString.'/p-achievements', $buff))
$success = false; $success = false;
} }
@@ -102,7 +102,7 @@ if (!defined('AOWOW_REVISION'))
/**********/ /**********/
/* Titles */ /* Titles */
/**********/ /**********/
$scripts[] = function(&$log) use ($locales) $scripts[] = function()
{ {
$success = true; $success = true;
$condition = array( $condition = array(
@@ -111,7 +111,7 @@ if (!defined('AOWOW_REVISION'))
); );
$titlez = new TitleList($condition); $titlez = new TitleList($condition);
foreach ($locales as $l) foreach (FileGen::$localeIds as $l)
{ {
set_time_limit(5); set_time_limit(5);
@@ -125,10 +125,10 @@ if (!defined('AOWOW_REVISION'))
{ {
$data['name'] = Util::localizedString($titlez->getEntry($id), $g ? 'female' : 'male'); $data['name'] = Util::localizedString($titlez->getEntry($id), $g ? 'female' : 'male');
unset($data['namefemale']); unset($data['namefemale']);
$buff .= '_['.$id.'] = '.json_encode($data, JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK).";\n"; $buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
} }
if (!writeFile('datasets/'.User::$localeString.'/p-titles-'.$g, $buff, $log)) if (!FileGen::writeFile('datasets/'.User::$localeString.'/p-titles-'.$g, $buff))
$success = false; $success = false;
} }
} }
@@ -139,7 +139,7 @@ if (!defined('AOWOW_REVISION'))
/**********/ /**********/
/* Mounts */ /* Mounts */
/**********/ /**********/
$scripts[] = function(&$log) use ($locales) $scripts[] = function()
{ {
$success = true; $success = true;
$condition = array( $condition = array(
@@ -149,7 +149,7 @@ if (!defined('AOWOW_REVISION'))
); );
$mountz = new SpellList($condition); $mountz = new SpellList($condition);
foreach ($locales as $l) foreach (FileGen::$localeIds as $l)
{ {
set_time_limit(5); set_time_limit(5);
@@ -161,10 +161,10 @@ if (!defined('AOWOW_REVISION'))
{ {
$data['quality'] = $data['name'][0]; $data['quality'] = $data['name'][0];
$data['name'] = substr($data['name'], 1); $data['name'] = substr($data['name'], 1);
$buff .= '_['.$id.'] = '.json_encode($data, JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK).";\n"; $buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
} }
if (!writeFile('datasets/'.User::$localeString.'/p-mounts', $buff, $log)) if (!FileGen::writeFile('datasets/'.User::$localeString.'/p-mounts', $buff))
$success = false; $success = false;
} }
@@ -174,7 +174,7 @@ if (!defined('AOWOW_REVISION'))
/**************/ /**************/
/* Companions */ /* Companions */
/**************/ /**************/
$scripts[] = function(&$log) use ($locales) $scripts[] = function()
{ {
$success = true; $success = true;
$condition = array( $condition = array(
@@ -184,7 +184,7 @@ if (!defined('AOWOW_REVISION'))
); );
$companionz = new SpellList($condition); $companionz = new SpellList($condition);
foreach ($locales as $l) foreach (FileGen::$localeIds as $l)
{ {
set_time_limit(5); set_time_limit(5);
@@ -196,10 +196,10 @@ if (!defined('AOWOW_REVISION'))
{ {
$data['quality'] = $data['name'][0]; $data['quality'] = $data['name'][0];
$data['name'] = substr($data['name'], 1); $data['name'] = substr($data['name'], 1);
$buff .= '_['.$id.'] = '.json_encode($data, JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK).";\n"; $buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
} }
if (!writeFile('datasets/'.User::$localeString.'/p-companions', $buff, $log)) if (!FileGen::writeFile('datasets/'.User::$localeString.'/p-companions', $buff))
$success = false; $success = false;
} }
@@ -209,7 +209,7 @@ if (!defined('AOWOW_REVISION'))
/************/ /************/
/* Factions */ /* Factions */
/************/ /************/
$scripts[] = function(&$log) use ($locales) $scripts[] = function()
{ {
$success = true; $success = true;
$condition = array( // todo (med): exclude non-gaining reputation-header $condition = array( // todo (med): exclude non-gaining reputation-header
@@ -218,7 +218,7 @@ if (!defined('AOWOW_REVISION'))
); );
$factionz = new FactionList($condition); $factionz = new FactionList($condition);
foreach ($locales as $l) foreach (FileGen::$localeIds as $l)
{ {
set_time_limit(5); set_time_limit(5);
@@ -227,11 +227,11 @@ if (!defined('AOWOW_REVISION'))
$buff = "var _ = g_factions;\n"; $buff = "var _ = g_factions;\n";
foreach ($factionz->getListviewData() as $id => $data) foreach ($factionz->getListviewData() as $id => $data)
$buff .= '_['.$id.'] = '.json_encode($data, JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK).";\n"; $buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
$buff .= "\ng_faction_order = [0, 469, 891, 1037, 1118, 67, 1052, 892, 936, 1117, 169, 980, 1097];\n"; $buff .= "\ng_faction_order = [0, 469, 891, 1037, 1118, 67, 1052, 892, 936, 1117, 169, 980, 1097];\n";
if (!writeFile('datasets/'.User::$localeString.'/p-factions', $buff, $log)) if (!FileGen::writeFile('datasets/'.User::$localeString.'/p-factions', $buff))
$success = false; $success = false;
} }
@@ -241,7 +241,7 @@ if (!defined('AOWOW_REVISION'))
/***********/ /***********/
/* Recipes */ /* Recipes */
/***********/ /***********/
$scripts[] = function(&$log) use ($locales) $scripts[] = function()
{ {
// special case: secondary skills are always requested, so put them in one single file (185, 129, 356); it also contains g_skill_order // special case: secondary skills are always requested, so put them in one single file (185, 129, 356); it also contains g_skill_order
$skills = [171, 164, 333, 202, 182, 773, 755, 165, 186, 393, 197, [185, 129, 356]]; $skills = [171, 164, 333, 202, 182, 773, 755, 165, 186, 393, 197, [185, 129, 356]];
@@ -269,7 +269,7 @@ if (!defined('AOWOW_REVISION'))
} }
} }
foreach ($locales as $l) foreach (FileGen::$localeIds as $l)
{ {
set_time_limit(10); set_time_limit(10);
@@ -278,12 +278,12 @@ if (!defined('AOWOW_REVISION'))
$buff = ''; $buff = '';
foreach ($recipez->getListviewData() as $id => $data) foreach ($recipez->getListviewData() as $id => $data)
$buff .= '_['.$id.'] = '.json_encode($data, JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK).";\n"; $buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
if (!$buff) if (!$buff)
{ {
// this behaviour is intended, do not create an error // this behaviour is intended, do not create an error
$log[] = [time(), ' notice: profiler - file datasets/'.User::$localeString.'/p-recipes-'.$file.' has no content => skipping']; FileGen::status('profiler - file datasets/'.User::$localeString.'/p-recipes-'.$file.' has no content => skipping', MSG_LVL_WARN);
continue; continue;
} }
@@ -292,7 +292,7 @@ if (!defined('AOWOW_REVISION'))
if (is_array($s)) if (is_array($s))
$buff .= "\ng_skill_order = [171, 164, 333, 202, 182, 773, 755, 165, 186, 393, 197, 185, 129, 356];\n"; $buff .= "\ng_skill_order = [171, 164, 333, 202, 182, 773, 755, 165, 186, 393, 197, 185, 129, 356];\n";
if (!writeFile('datasets/'.User::$localeString.'/p-recipes-'.$file, $buff, $log)) if (!FileGen::writeFile('datasets/'.User::$localeString.'/p-recipes-'.$file, $buff))
$success = false; $success = false;
} }
} }
@@ -302,12 +302,12 @@ if (!defined('AOWOW_REVISION'))
// check directory-structure // check directory-structure
foreach (Util::$localeStrings as $dir) foreach (Util::$localeStrings as $dir)
if (!writeDir('datasets/'.$dir, $log)) if (!FileGen::writeDir('datasets/'.$dir))
$success = false; $success = false;
// run scripts // run scripts
foreach ($scripts as $func) foreach ($scripts as $func)
if (!$func($log)) if (!$func())
$success = false; $success = false;
return $success; return $success;

View File

@@ -33,15 +33,13 @@ if (!defined('AOWOW_REVISION'))
]; ];
*/ */
function mnProfiles(/* &$log */) function realmMenu()
{ {
$subEU = [];
$subUS = [];
$menu = [ $menu = [
["us", "US & Oceanic", null,[ ['us', 'US & Oceanic', null,[[Util::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP, null, &$subEU]]],
[Util::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP, null, []] ['eu', 'Europe', null,[[Util::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP, null, &$subUS]]]
]],
["eu", "Europe", null,[
[Util::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP, null, []]
]]
]; ];
$rows = DB::Auth()->select('SELECT name, IF(timezone IN (8, 9, 10, 11, 12), "eu", "us") AS region FROM realmlist WHERE allowedSecurityLevel = 0'); $rows = DB::Auth()->select('SELECT name, IF(timezone IN (8, 9, 10, 11, 12), "eu", "us") AS region FROM realmlist WHERE allowedSecurityLevel = 0');
@@ -52,22 +50,22 @@ function mnProfiles(/* &$log */)
if ($row['region'] == 'eu') if ($row['region'] == 'eu')
{ {
$set |= 0x1; $set |= 0x1;
$menu[1][3][0][3][] = [Util::urlize($row['name']),$row['name']]; $subEU[] = [Util::urlize($row['name']), $row['name']];
} }
else if ($row['region'] == 'us') else if ($row['region'] == 'us')
{ {
$set |= 0x2; $set |= 0x2;
$menu[0][3][0][3][] = [Util::urlize($row['name']),$row['name']]; $subUS[] = [Util::urlize($row['name']), $row['name']];
} }
} }
if (!($set & 0x1)) if (!($set & 0x1))
array_pop($menu);
if (!($set & 0x2))
array_shift($menu); array_shift($menu);
return json_encode($menu, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); if (!($set & 0x2))
array_pop($menu);
return Util::toJSON($menu);
} }
?> ?>

View File

@@ -23,13 +23,14 @@ if (!defined('AOWOW_REVISION'))
}, },
*/ */
function realms(&$log) function realms()
{ {
$file = 'datasets/realms'; $realms = DB::Auth()->select('SELECT id AS ARRAY_KEY, name, ? AS battlegroup, IF(timezone IN (8, 9, 10, 11, 12), "eu", "us") AS region FROM realmlist WHERE allowedSecurityLevel = 0', CFG_BATTLEGROUP);
$rows = DB::Auth()->select('SELECT id AS ARRAY_KEY, name, ? AS battlegroup, IF(timezone IN (8, 9, 10, 11, 12), "eu", "us") AS region FROM realmlist WHERE allowedSecurityLevel = 0', CFG_BATTLEGROUP);
$str = 'var g_realms = '.json_encode($rows, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE).';';
return writeFile($file, $str, $log); $toFile = "var g_realms = ".Util::toJSON($realms).";";
$file = 'datasets/realms';
return FileGen::writeFile($file, $toFile);
} }
?> ?>

View File

@@ -1,211 +0,0 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
// shared funcs
function writeFile($file, $content, &$log)
{
$success = false;
if ($handle = @fOpen($file, "w"))
{
if (fWrite($handle, $content))
{
$success = true;
$log[] = [time(), sprintf(ERR_NONE, $file)];
}
else
$log[] = [time(), sprintf(ERR_WRITE_FILE, $file)];
fClose($handle);
}
else
$log[] = [time(), sprintf(ERR_CREATE_FILE, $file)];
if ($success)
@chmod($file, 0766);
return $success;
}
function writeDir($dir, &$log)
{
if (is_dir($dir))
{
if (!is_writable($dir))
$log[] = [time(), ' error: cannot write into output directory '.$dir];
return is_writable($dir);
}
if (@mkdir($dir, 0766, true))
return true;
$log[] = [time(), ' error: could not create output directory '.$dir];
return false;
}
// shared strings
define('ERR_CREATE_FILE', ' error: could not create file at destination %s');
define('ERR_WRITE_FILE', ' error: could not write to file at destination %s');
define('ERR_READ_FILE', ' error: file %s could not be read');
define('ERR_MISSING_FILE', ' error: file %s not found');
define('ERR_NONE', 'success: created file(s) %s');
define('ERR_MISSING_INCL', ' error: required function %s() could not be found at %s');
$log = [];
$locales = [];
$tplPath = 'setup/tools/filegen/templates/';
$pairs = array(
'CFG_NAME' => CFG_NAME,
'CFG_NAME_SHORT' => CFG_NAME_SHORT,
'HOST_URL' => HOST_URL,
'STATIC_URL' => STATIC_URL
);
$tplFiles = array(
'searchplugin' => ['aowow.xml', 'static/download/searchplugins/'],
'power' => ['power.js', 'static/widgets/' ],
'searchboxScript' => ['searchbox.js', 'static/widgets/' ],
'demo' => ['demo.html', 'static/widgets/power/' ],
'searchboxBody' => ['searchbox.html', 'static/widgets/searchbox/' ],
'realmMenu' => ['profile_all.js', 'static/js/' ],
'locales' => ['locale.js', 'static/js/' ],
// 'itemScaling => ['item-scaling', 'datasets/' ], # provided 'as is', as dbc-content doesn't usualy change
);
$datasets = array(
'realms', 'statistics', 'profiler', // profiler related
'talents', 'talentIcons', 'glyphs', // talentCalc related
'itemsets', 'enchants', 'gems', // comparison related
'pets',
);
$reqDirs = array(
'static/uploads/screenshots/normal',
'static/uploads/screenshots/pending',
'static/uploads/screenshots/resized',
'static/uploads/screenshots/temp',
'static/uploads/screenshots/thumb',
'static/uploads/temp/'
);
// restrict actual locales
foreach (Util::$localeStrings as $idx => $str)
if ($str && (CFG_LOCALES & (1 << $idx)))
$locales[] = $idx;
// check $pageParam; limit to real scriptNames
$scList = array_merge(array_keys($tplFiles), $datasets);
if ($pageParam)
$scList = array_intersect(explode(';', $pageParam), $scList);
if ($scList)
{
// create directory structure
$log[] = [time(), 'begin creation of directory structure'];
$pathOk = 0;
foreach ($reqDirs as $d)
if (writeDir($d, $log))
$pathOk++;
$log[] = [time(), 'finished directory structure.'];
$log[] = [time(), 'created '.$pathOk.' extra paths'.($pathOk == count($reqDirs) ? '' : ' with errors')];
$log[] = null;
// start file generation
$log[] = [time(), 'begin generation of '. implode(', ', $scList)];
$log[] = null;
// files with template
foreach ($tplFiles as $name => list($file, $destPath))
{
if ($scList && !in_array($name, $scList))
continue;
if (!file_exists($tplPath.$file.'.in'))
{
$log[] = [time(), sprintf(ERR_MISSING_FILE, $tplPath.$file.'.in')];
continue;
}
if (!writeDir($destPath, $log))
continue;
if ($content = file_get_contents($tplPath.$file.'.in'))
{
if ($dest = @fOpen($destPath.$file, "w"))
{
// replace constants
$content = strtr($content, $pairs);
// must generate content
// PH format: /*setup:<setupFunc>*/
if (preg_match('/\/\*setup:([\w\d_-]+)\*\//i', $content, $m))
{
$res = '';
if (file_exists('setup/tools/filegen/'.$m[1].'.func.php'))
{
include 'setup/tools/filegen/'.$m[1].'.func.php';
$res = $m[1]($log, $locales);
}
else
$log[] = [time(), sprintf(ERR_MISSING_INCL, $m[1], 'setup/tools/filegen/'.$m[1].'.func.php')];
$content = str_replace('/*setup:'.$m[1].'*/', $res, $content);
}
if (fWrite($dest, $content))
$log[] = [time(), sprintf(ERR_NONE, $destPath.$file)];
else
$log[] = [time(), sprintf(ERR_WRITE_FILE, $destPath.$file)];
fClose($dest);
}
else
$log[] = [time(), sprintf(ERR_CREATE_FILE, $destPath.$file)];
}
else
$log[] = [time(), sprintf(ERR_READ_FILE, $tplPath.$file.'.in')];
}
// files without template
foreach ($datasets as $file)
{
if ($scList && !in_array($file, $scList))
continue;
if (file_exists('setup/tools/filegen/'.$file.'.func.php'))
{
include 'setup/tools/filegen/'.$file.'.func.php';
if ($file($log, $locales))
$log[] = [time(), ' - subscript returned sucessfully'];
else
$log[] = [time(), ' - subscript returned with errors'];
set_time_limit(30); // reset to default for the next script
}
else
$log[] = [time(), sprintf(ERR_MISSING_INCL, $file, 'setup/tools/filegen/'.$file.'.func.php')];
}
// end
$log[] = null;
$log[] = [time(), 'finished file generation'];
}
else
$log[] = [time(), 'no valid script names supplied'];
// print accumulated log
echo "<pre>\n";
foreach ($log as $l)
if ($l)
echo date('H:i:s', $l[0]) . ' ' . $l[1]."\n";
else
echo "\n";
echo "</pre>\n";
?>

View File

@@ -0,0 +1,428 @@
<?php
if (!defined('AOWOW_REVISION'))
die('illegal access');
// note: for the sake of simplicity, this function handles all whole images (which are mostly icons)
// quest icons from GossipFrame have an alphaChannel that cannot be handled by this script
// lfgFrame/lfgIcon*.blp .. candidates for zonePage, but in general too detailed to scale them down from 128 to 56, 36, ect
function simpleImg()
{
if (isset(FileGen::$cliOpts['help']))
{
echo "\n";
echo "available Options for subScript 'simpleImg':\n";
echo " --icons (generates square icons that are used for basicly everything)\n";
echo " --glyphs (decorative tidbit displayed on Infobox for Glyph Spells)\n";
echo " --pagetexts (imagery contained in PageTexts on readable GameObjects or Items)\n";
echo " --loadingscreens (loadingscreens (not used, skipped by default))\n";
return true;
}
if (!class_exists('DBC'))
{
FileGen::status(' - simpleImg: required class DBC was not included', MSG_LVL_ERROR);
return false;
}
if (!function_exists('imagecreatefromblp'))
{
FileGen::status(' - simpleImg: required include imagecreatefromblp() was not included', MSG_LVL_ERROR);
return false;
}
$locStr = '';
$groups = [];
$dbcPath = FileGen::$srcDir.'%sDBFilesClient/';
$imgPath = FileGen::$srcDir.'%sInterface/';
$destDir = 'static/images/wow/';
$success = true;
$iconDirs = array(
['icons/large/', 'jpg', 0, 56, 4],
['icons/medium/', 'jpg', 0, 36, 4],
['icons/small/', 'jpg', 0, 18, 4],
['icons/tiny/', 'gif', 0, 15, 4]
);
$calendarDirs = array(
['icons/large/', 'jpg', 90, 56, 4],
['icons/medium/', 'jpg', 90, 36, 4],
['icons/small/', 'jpg', 90, 18, 4],
['icons/tiny/', 'gif', 90, 15, 4]
);
$loadScreenDirs = array(
['loadingscreens/large/', 'jpg', 0, 1024, 0],
['loadingscreens/medium/', 'jpg', 0, 488, 0],
['loadingscreens/original/', 'png', 0, 0, 0],
['loadingscreens/small/', 'jpg', 0, 244, 0]
);
$paths = array( // src, [dest, ext, srcSize, destSize, borderOffset], pattern, isIcon, tileSize
0 => ['Icons/', $iconDirs, '/*.[bB][lL][pP]', true, 0],
1 => ['Spellbook/', [['Interface/Spellbook/', 'png', 0, 0, 0]], '/UI-Glyph-Rune*.blp', true, 0],
2 => ['PaperDoll/', array_slice($iconDirs, 0, 3), '/UI-{Backpack,PaperDoll}-*.blp', true, 0],
3 => ['GLUES/CHARACTERCREATE/UI-CharacterCreate-Races.blp', $iconDirs, '', true, 64],
4 => ['GLUES/CHARACTERCREATE/UI-CharacterCreate-CLASSES.blp', $iconDirs, '', true, 64],
5 => ['GLUES/CHARACTERCREATE/UI-CharacterCreate-Factions.blp', $iconDirs, '', true, 64],
// 6 => ['Minimap/OBJECTICONS.BLP', [['icons/tiny/', 'gif', 0, 16, 2]], '', true, 32],
7 => ['FlavorImages/', [['Interface/FlavorImages/', 'png', 0, 0, 0]], '/*.[bB][lL][pP]', false, 0],
8 => ['Pictures/', [['Interface/Pictures/', 'png', 0, 0, 0]], '/*.[bB][lL][pP]', false, 0],
9 => ['PvPRankBadges/', [['Interface/PvPRankBadges/', 'png', 0, 0, 0]], '/*.[bB][lL][pP]', false, 0],
10 => ['Calendar/Holidays/', $calendarDirs, '/*{rt,a,y,h,s}.[bB][lL][pP]', true, 0],
11 => ['GLUES/LOADINGSCREENS/', $loadScreenDirs, '/[lL][oO]*.[bB][lL][pP]', false, 0]
);
// textures are composed of 64x64 icons
// numeric indexed arrays mimick the position on the texture
$cuNames = array(
2 => array(
'ui-paperdoll-slot-chest' => 'inventoryslot_chest',
'ui-backpack-emptyslot' => 'inventoryslot_empty',
'ui-paperdoll-slot-feet' => 'inventoryslot_feet',
'ui-paperdoll-slot-finger' => 'inventoryslot_finger',
'ui-paperdoll-slot-hands' => 'inventoryslot_hands',
'ui-paperdoll-slot-head' => 'inventoryslot_head',
'ui-paperdoll-slot-legs' => 'inventoryslot_legs',
'ui-paperdoll-slot-mainhand' => 'inventoryslot_mainhand',
'ui-paperdoll-slot-neck' => 'inventoryslot_neck',
'ui-paperdoll-slot-secondaryhand' => 'inventoryslot_offhand',
'ui-paperdoll-slot-ranged' => 'inventoryslot_ranged',
'ui-paperdoll-slot-relic' => 'inventoryslot_relic',
'ui-paperdoll-slot-shirt' => 'inventoryslot_shirt',
'ui-paperdoll-slot-shoulder' => 'inventoryslot_shoulder',
'ui-paperdoll-slot-tabard' => 'inventoryslot_tabard',
'ui-paperdoll-slot-trinket' => 'inventoryslot_trinket',
'ui-paperdoll-slot-waist' => 'inventoryslot_waist',
'ui-paperdoll-slot-wrists' => 'inventoryslot_wrists'
),
3 => array(
['race_human_male', 'race_dwarf_male', 'race_gnome_male', 'race_nightelf_male', 'race_draenai_male' ],
['race_tauren_male', 'race_undead_male', 'race_troll_male', 'race_orc_male', 'race_bloodelf_male' ],
['race_human_female', 'race_dwarf_female', 'race_gnome_female', 'race_nightelf_female', 'race_draenai_female' ],
['race_tauren_female', 'race_undead_female', 'race_troll_female', 'race_orc_female', 'race_bloodelf_female']
),
4 => array(
['class_warrior', 'class_mage', 'class_rogue', 'class_druid' ],
['class_hunter', 'class_shaman', 'class_priest', 'class_warlock'],
['class_paladin', 'class_deathknight' ]
),
5 => array(
['faction_alliance', 'faction_horde']
),
6 => array(
[],
[null, 'quest_start', 'quest_end', 'quest_start_daily', 'quest_end_daily']
),
10 => array( // really should have read holidays.dbc...
'calendar_winterveilstart' => 'calendar_winterveilstart',
'calendar_noblegardenstart' => 'calendar_noblegardenstart',
'calendar_childrensweekstart' => 'calendar_childrensweekstart',
'calendar_fishingextravaganza' => 'calendar_fishingextravaganzastart',
'calendar_harvestfestivalstart' => 'calendar_harvestfestivalstart',
'calendar_hallowsendstart' => 'calendar_hallowsendstart',
'calendar_lunarfestivalstart' => 'calendar_lunarfestivalstart',
'calendar_loveintheairstart' => 'calendar_loveintheairstart',
'calendar_midsummerstart' => 'calendar_midsummerstart',
'calendar_brewfeststart' => 'calendar_brewfeststart',
'calendar_darkmoonfaireelwynnstart' => 'calendar_darkmoonfaireelwynnstart',
'calendar_darkmoonfairemulgorestart' => 'calendar_darkmoonfairemulgorestart',
'calendar_darkmoonfaireterokkarstart' => 'calendar_darkmoonfaireterokkarstart',
'calendar_piratesday' => 'calendar_piratesdaystart',
'calendar_wotlklaunch' => 'calendar_wotlklaunchstart',
'calendar_dayofthedeadstart' => 'calendar_dayofthedeadstart',
'calendar_fireworks' => 'calendar_fireworksstart'
)
);
$writeImage = function($name, $ext, $src, $srcDims, $destDims, $done)
{
$ok = false;
$dest = imagecreatetruecolor($destDims['w'], $destDims['h']);
imagesavealpha($dest, true);
imagealphablending($dest, false);
imagecopyresampled($dest, $src, $destDims['x'], $destDims['x'], $srcDims['x'], $srcDims['y'], $destDims['w'], $destDims['h'], $srcDims['w'], $srcDims['h']);
switch ($ext)
{
case 'jpg':
$ok = imagejpeg($dest, $name.'.'.$ext, 85);
break;
case 'gif':
$ok = imagegif($dest, $name.'.'.$ext);
break;
case 'png':
$ok = imagepng($dest, $name.'.'.$ext);
break;
default:
FileGen::status($done.' - unsupported file fromat: '.$ext, MSG_LVL_WARN);
}
imagedestroy($dest);
if ($ok)
{
chmod($name.'.'.$ext, FileGen::$accessMask);
FileGen::status($done.' - image '.$name.'.'.$ext.' written', MSG_LVL_OK);
}
else
FileGen::status($done.' - could not create image '.$name.'.'.$ext, MSG_LVL_ERROR);
return $ok;
};
$checkSourceDirs = function($sub, &$missing = []) use ($imgPath, $dbcPath, $paths)
{
foreach (array_column($paths, 0) as $subDir)
{
$p = sprintf($imgPath, $sub).$subDir;
if (!FileGen::fileExists($p))
$missing[] = $p;
}
$p = sprintf($dbcPath, $sub);
if (!FileGen::fileExists($p))
$missing[] = $p;
return !$missing;
};
if (isset(FileGen::$cliOpts['icons']))
array_push($groups, 0, 2, 3, 4, 5, 10);
if (isset(FileGen::$cliOpts['glyphs']))
$groups[] = 1;
if (isset(FileGen::$cliOpts['pagetexts']))
array_push($groups, 7, 8, 9);
if (isset(FileGen::$cliOpts['loadingscreens']))
$groups[] = 11;
// filter by pasaed options
if (!$groups) // by default do not generate loadingscreens
unset($paths[11]);
else
foreach (array_keys($paths) as $k)
if (!in_array($k, $groups))
unset($paths[$k]);
foreach (FileGen::$localeIds as $l)
{
if ($checkSourceDirs(Util::$localeStrings[$l].'/'))
{
$locStr = Util::$localeStrings[$l].'/';
break;
}
}
// manually check for enGB
if (!$locStr && $checkSourceDirs('enGB/'))
$locStr = 'enGB/';
// if no subdir had sufficient data, check mpq-root
if (!$locStr && !$checkSourceDirs('', $missing))
{
FileGen::status('one or more required directories are missing:', MSG_LVL_ERROR);
foreach ($missing as $m)
FileGen::status(' - '.$m, MSG_LVL_ERROR);
return;
}
// init directories
foreach (array_column($paths, 1) as $subDirs)
foreach ($subDirs as $sd)
if (!FileGen::writeDir($destDir.$sd[0]))
$success = false;
// ok, departure from std::procedure here
// scan ItemDisplayInfo.dbc and SpellIcon.dbc for expected images and save them to an array
// load all icon paths into another array and xor these two
// excess entries for the directory are fine, excess entries for the dbc's are not
$dbcEntries = [];
if (isset($paths[0]) || isset($paths[1])) // generates icons or glyphs
{
$spellIcon = new DBC('SpellIcon');
if (isset($paths[0]) && !isset($paths[1]))
$siRows = $spellIcon->readFiltered(function(&$val) { return !stripos($val['iconPath'], 'glyph-rune'); });
else if (!isset($paths[0]) && isset($paths[1]))
$siRows = $spellIcon->readFiltered(function(&$val) { return stripos($val['iconPath'], 'glyph-rune'); });
else
$siRows = $spellIcon->readArbitrary();
foreach ($siRows as $row)
$dbcEntries[] = sprintf('setup/mpqdata/%s', $locStr).strtr($row['iconPath'], ['\\' => '/']).'.blp';
}
if (isset($paths[0]))
{
$itemDisplayInfo = new DBC('ItemDisplayInfo');
foreach ($itemDisplayInfo->readArbitrary() as $row)
$dbcEntries[] = sprintf($imgPath, $locStr).'Icons/'.$row['inventoryIcon1'].'.blp';
$holidays = new DBC('Holidays');
$holiRows = $holidays->readFiltered(function(&$val) { return !empty($val['textureString']); });
foreach ($holiRows as $row)
$dbcEntries[] = sprintf($imgPath, $locStr).'Calendar/Holidays/'.$row['textureString'].'Start.blp';
}
// case-insensitive array_unique *vomits silently into a corner*
$dbcEntries = array_intersect_key($dbcEntries, array_unique(array_map('strtolower',$dbcEntries)));
$allPaths = [];
foreach ($paths as $i => $p)
{
$path = sprintf($imgPath, $locStr).$p[0];
if (!FileGen::fileExists($path))
continue;
$files = glob($path.$p[2], GLOB_BRACE);
$allPaths = array_merge($allPaths, $files);
FileGen::status('processing '.count($files).' files in '.$path.'...');
$j = 0;
foreach ($files as $f)
{
ini_set('max_execution_time', 30); // max 30sec per image (loading takes the most time)
$src = null;
$img = explode('.', array_pop(explode('/', $f)));
array_pop($img); // there are a hand full of images with multiple file endings or random dots in the name
$img = implode('.', $img);
// file not from dbc -> name from array or skip file
if (!empty($cuNames[$i]))
{
if (!empty($cuNames[$i][strtolower($img)]))
$img = $cuNames[$i][strtolower($img)];
else if (!$p[4])
{
$j += count($p[1]);
FileGen::status('skipping extraneous file '.$img.' (+'.count($p[1]).')');
continue;
}
}
$nFiles = count($p[1]) * ($p[4] ? array_sum(array_map('count', $cuNames[$i])) : count($files));
foreach ($p[1] as $info)
{
if ($p[4])
{
foreach ($cuNames[$i] as $y => $row)
{
foreach ($row as $x => $name)
{
$j++;
$img = $p[3] ? strtolower($name) : $name;
$done = ' - '.str_pad($j.'/'.$nFiles, 12).str_pad('('.number_format($j * 100 / $nFiles, 2).'%)', 9);
if (!isset(FileGen::$cliOpts['force']) && file_exists($destDir.$info[0].$img.'.'.$info[1]))
{
FileGen::status($done.' - file '.$info[0].$img.'.'.$info[1].' was already processed');
continue;
}
if (!$src)
$src = imagecreatefromblp($f);
if (!$src) // error should be created by imagecreatefromblp
continue;
$from = array(
'x' => $info[4] + $p[4] * $x,
'y' => $info[4] + $p[4] * $y,
'w' => $p[4] - $info[4] * 2,
'h' => $p[4] - $info[4] * 2
);
$to = array(
'x' => 0,
'y' => 0,
'w' => $info[3],
'h' => $info[3]
);
if (!$writeImage($destDir.$info[0].$img, $info[1], $src, $from, $to, $done))
$success = false;
}
}
// custom handle for combined icon 'quest_startend'
/* not used due to alphaChannel issues
if ($p[4] == 32)
{
$dest = imagecreatetruecolor(19, 16);
imagesavealpha($dest, true);
imagealphablending($dest, true);
// excalmationmark, questionmark
imagecopyresampled($dest, $src, 0, 1, 32 + 5, 32 + 2, 8, 15, 18, 30);
imagecopyresampled($dest, $src, 5, 0, 64 + 1, 32 + 1, 10, 16, 18, 28);
if (imagegif($dest, $destDir.$info[0].'quest_startend.gif'))
FileGen::status(' extra - image '.$destDir.$info[0].'quest_startend.gif written', MSG_LVL_OK);
else
{
FileGen::status(' extra - could not create image '.$destDir.$info[0].'quest_startend.gif', MSG_LVL_ERROR);
$success = false;
}
imagedestroy($dest);
}
*/
}
else
{
// icon -> lowercase
if ($p[3])
$img = strtolower($img);
$j++;
$done = ' - '.str_pad($j.'/'.$nFiles, 12).str_pad('('.number_format($j * 100 / $nFiles, 2).'%)', 9);
if (!isset(FileGen::$cliOpts['force']) && file_exists($destDir.$info[0].$img.'.'.$info[1]))
{
FileGen::status($done.' - file '.$info[0].$img.'.'.$info[1].' was already processed');
continue;
}
if (!$src)
$src = imagecreatefromblp($f);
if (!$src) // error should be created by imagecreatefromblp
continue;
$from = array(
'x' => $info[4],
'y' => $info[4],
'w' => ($info[2] ?: imagesx($src)) - $info[4] * 2,
'h' => ($info[2] ?: imagesy($src)) - $info[4] * 2
);
$to = array(
'x' => 0,
'y' => 0,
'w' => $info[3] ?: imagesx($src),
'h' => $info[3] ?: imagesy($src)
);
if (!$writeImage($destDir.$info[0].$img, $info[1], $src, $from, $to, $done))
$success = false;
}
}
unset($src);
}
}
// reset execTime
ini_set('max_execution_time', FileGen::$defaultExecTime);
if ($missing = array_diff(array_map('strtolower', $dbcEntries), array_map('strtolower', $allPaths)))
{
asort($missing);
FileGen::status('the following '.count($missing).' images where referenced by DBC but not in the mpqData directory. They may need to be converted by hand later on.', MSG_LVL_WARN);
foreach ($missing as $m)
FileGen::status(' - '.$m);
}
return $success;
}

View File

@@ -5,11 +5,25 @@ if (!defined('AOWOW_REVISION'))
// Create 'statistics'-file in datasets // Create 'statistics'-file in datasets
// this script requires the following dbcs to be parsed and available // this script requires the following dbcs to be available
// gtChanceToMeleeCrit.dbc, gtChanceToSpellCrit.dbc, gtChanceToMeleeCritBase.dbc, gtChanceToSpellCritBase.dbc, gtOCTRegenHP, gtRegenHPPperSpt.dbc, gtRegenMPPerSpt.dbc // gtChanceToMeleeCrit.dbc, gtChanceToSpellCrit.dbc, gtChanceToMeleeCritBase.dbc, gtChanceToSpellCritBase.dbc, gtOCTRegenHP.dbc, gtRegenMPPerSpt.dbc, gtRegenHPPerSpt.dbc
function statistics(&$log) function statistics()
{ {
// expected dbcs
$req = ['dbc_gtchancetomeleecrit', 'dbc_gtchancetomeleecritbase', 'dbc_gtchancetospellcrit', 'dbc_gtchancetospellcritbase', 'dbc_gtoctregenhp', 'dbc_gtregenmpperspt', 'dbc_gtregenhpperspt'];
$found = DB::Aowow()->selectCol('SHOW TABLES LIKE "dbc_%"');
if ($missing = array_diff($req, $found))
{
foreach ($missing as $m)
{
$file = explode('_', $m)[1];
$dbc = new DBC($file);
if ($dbc->readFromFile())
$dbc->writeToDB();
}
}
$classs = function() $classs = function()
{ {
// constants and mods taken from TrinityCore (Player.cpp, StatSystem.cpp) // constants and mods taken from TrinityCore (Player.cpp, StatSystem.cpp)
@@ -42,7 +56,7 @@ if (!defined('AOWOW_REVISION'))
); );
foreach ($dataz as $class => &$data) foreach ($dataz as $class => &$data)
$data[2] = array_values(DB::Aowow()->selectRow('SELECT mle.chance*100 cMle, spl.chance*100 cSpl FROM dbc.gtchancetomeleecritbase mle, dbc.gtchancetospellcritbase spl WHERE mle.idx = spl.idx AND mle.idx = ?d', $class - 1)); $data[2] = array_values(DB::Aowow()->selectRow('SELECT mle.chance*100 cMle, spl.chance*100 cSpl FROM dbc_gtchancetomeleecritbase mle, dbc_gtchancetospellcritbase spl WHERE mle.idx = spl.idx AND mle.idx = ?d', $class - 1));
return $dataz; return $dataz;
}; };
@@ -89,10 +103,10 @@ if (!defined('AOWOW_REVISION'))
$rows = DB::Aowow()->select('SELECT pls.level AS ARRAY_KEY, str-?d, agi-?d, sta-?d, inte-?d, spi-?d, basehp, IF(basemana <> 0, basemana, 100), mlecrt.chance*100, splcrt.chance*100, mlecrt.chance*100 * ?f, baseHP5.ratio*1, extraHP5.ratio*1 ' . $rows = DB::Aowow()->select('SELECT pls.level AS ARRAY_KEY, str-?d, agi-?d, sta-?d, inte-?d, spi-?d, basehp, IF(basemana <> 0, basemana, 100), mlecrt.chance*100, splcrt.chance*100, mlecrt.chance*100 * ?f, baseHP5.ratio*1, extraHP5.ratio*1 ' .
'FROM player_levelstats pls JOIN player_classlevelstats pcls ON pls.level = pcls.level AND pls.class = pcls.class JOIN' . 'FROM player_levelstats pls JOIN player_classlevelstats pcls ON pls.level = pcls.level AND pls.class = pcls.class JOIN' .
' dbc.gtchancetomeleecrit mlecrt ON mlecrt.idx = ((pls.class - 1) * 100) + (pls.level - 1) JOIN' . ' dbc_gtchancetomeleecrit mlecrt ON mlecrt.idx = ((pls.class - 1) * 100) + (pls.level - 1) JOIN' .
' dbc.gtchancetospellcrit splcrt ON splcrt.idx = ((pls.class - 1) * 100) + (pls.level - 1) JOIN' . ' dbc_gtchancetospellcrit splcrt ON splcrt.idx = ((pls.class - 1) * 100) + (pls.level - 1) JOIN' .
' dbc.gtoctregenhp baseHP5 ON baseHP5.idx = ((pls.class - 1) * 100) + (pls.level - 1) JOIN' . ' dbc_gtoctregenhp baseHP5 ON baseHP5.idx = ((pls.class - 1) * 100) + (pls.level - 1) JOIN' .
' dbc.gtregenhpperspt extraHP5 ON extraHP5.idx = ((pls.class - 1) * 100) + (pls.level - 1) ' . ' dbc_gtregenhpperspt extraHP5 ON extraHP5.idx = ((pls.class - 1) * 100) + (pls.level - 1) ' .
'WHERE pls.race = ?d AND pls.class = ?d ORDER BY pls.level ASC', 'WHERE pls.race = ?d AND pls.class = ?d ORDER BY pls.level ASC',
$offset[0], $offset[1], $offset[2], $offset[3], $offset[4], $offset[0], $offset[1], $offset[2], $offset[3], $offset[4],
$mod, $mod,
@@ -114,7 +128,7 @@ if (!defined('AOWOW_REVISION'))
// identical across classes (just use one, that acutally has mana (offset: 100)) // identical across classes (just use one, that acutally has mana (offset: 100))
// content of gtRegenMPPerSpt.dbc // content of gtRegenMPPerSpt.dbc
return DB::Aowow()->selectCol('SELECT idx-99 AS ARRAY_KEY, ratio FROM dbc.gtregenmpperspt WHERE idx >= 100 AND idx < 100 + ?d', MAX_LEVEL); return DB::Aowow()->selectCol('SELECT idx-99 AS ARRAY_KEY, ratio FROM dbc_gtregenmpperspt WHERE idx >= 100 AND idx < 100 + ?d', MAX_LEVEL);
}; };
$skills = function() $skills = function()
@@ -135,15 +149,14 @@ if (!defined('AOWOW_REVISION'))
$out[$s] = $res; $out[$s] = $res;
if (!$res) if (!$res)
{ {
$log[] = [time(), ' error: statistics - generator $'.$s.'() returned empty']; FileGen::status('statistics - generator $'.$s.'() returned empty', MSG_LVL_WARN);
$success = false; $success = false;
} }
} }
$json = json_encode($out, JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); $toFile = 'g_statistics = '.preg_replace('/"\$([^$"]+)"/', '\1', Util::toJSON($out)).';';
$toFile = 'g_statistics = '.preg_replace('/"\$([^$"]+)"/', '\1', $json).';';
if (!writeFile('datasets/statistics', $toFile, $log)) if (!FileGen::writeFile('datasets/statistics', $toFile))
$success = false; $success = false;
return $success; return $success;

View File

@@ -6,21 +6,35 @@ if (!defined('AOWOW_REVISION'))
// builds image-textures for the talent-calculator // builds image-textures for the talent-calculator
// spellIcons must be extracted and converted to at least medium size // spellIcons must be extracted and converted to at least medium size
// this script requires the following dbc-files to be parsed and available // this script requires the following dbc-files to be available
// Talent, TalentTab, Spell // Talent.dbc, TalentTab.dbc
function talentIcons(&$log) function talentIcons()
{ {
// expected dbcs
$req = ['dbc_talenttab', 'dbc_talent'];
$found = DB::Aowow()->selectCol('SHOW TABLES LIKE "dbc_%"');
if ($missing = array_diff($req, $found))
{
foreach ($missing as $m)
{
$file = explode('_', $m)[1];
$dbc = new DBC($file);
if ($dbc->readFromFile($file == 'talenttab'))
$dbc->writeToDB();
}
}
$success = true; $success = true;
$query = 'SELECT s.iconString FROM ?_spell s JOIN dbc.talent t ON t.rank1 = s.Id JOIN dbc.talenttab tt ON tt.Id = t.tabId WHERE tt.?# = ?d AND tt.tabNumber = ?d ORDER BY t.row, t.column, t.petCategory1 ASC;'; $query = 'SELECT s.iconString FROM ?_spell s JOIN dbc_talent t ON t.rank1 = s.Id JOIN dbc_talenttab tt ON tt.Id = t.tabId WHERE tt.?# = ?d AND tt.tabNumber = ?d ORDER BY t.row, t.column, t.petCategory1 ASC;';
$dims = 36; //v-pets $dims = 36; //v-pets
$filenames = ['icons', 'warrior', 'paladin', 'hunter', 'rogue', 'priest', 'deathknight', 'shaman', 'mage', 'warlock', null, 'druid']; $filenames = ['icons', 'warrior', 'paladin', 'hunter', 'rogue', 'priest', 'deathknight', 'shaman', 'mage', 'warlock', null, 'druid'];
// create directory if missing // create directory if missing
if (!writeDir('static/images/wow/talents/icons', $log)) if (!FileGen::writeDir('static/images/wow/talents/icons'))
$success = false; $success = false;
if (!writeDir('static/images/wow/hunterpettalents', $log)) if (!FileGen::writeDir('static/images/wow/hunterpettalents'))
$success = false; $success = false;
foreach ($filenames as $k => $v) foreach ($filenames as $k => $v)
@@ -41,7 +55,7 @@ if (!defined('AOWOW_REVISION'))
if (empty($icons)) if (empty($icons))
{ {
$log[] = [time(), ' error: talentIcons - query for '.$v.' tree: '.$k.' empty']; FileGen::status('talentIcons - query for '.$v.' tree: '.$k.' returned empty', MSG_LVL_ERROR);
$success = false; $success = false;
continue; continue;
} }
@@ -53,7 +67,7 @@ if (!defined('AOWOW_REVISION'))
$imgFile = 'static/images/wow/icons/medium/'.strtolower($icons[$i]).'.jpg'; $imgFile = 'static/images/wow/icons/medium/'.strtolower($icons[$i]).'.jpg';
if (!file_exists($imgFile)) if (!file_exists($imgFile))
{ {
$log[] = [time(), ' error: talentIcons - raw image '.$imgFile. ' not found']; FileGen::status('talentIcons - raw image '.$imgFile. ' not found', MSG_LVL_ERROR);
$success = false; $success = false;
break; break;
} }
@@ -77,17 +91,17 @@ if (!defined('AOWOW_REVISION'))
} }
if (@imagejpeg($res, $outFile)) if (@imagejpeg($res, $outFile))
$log[] = [time(), sprintf(ERR_NONE, $outFile)]; FileGen::status(sprintf(ERR_NONE, $outFile), MSG_LVL_OK);
else else
{ {
$success = false; $success = false;
$log[] = [time(), ' error: talentIcons - '.$outFile.'.jpg could not be written!']; FileGen::status('talentIcons - '.$outFile.'.jpg could not be written', MSG_LVL_ERROR);
} }
} }
else else
{ {
$success = false; $success = false;
$log[] = [time(), ' error: talentIcons - image resource not created']; FileGen::status('talentIcons - image resource not created', MSG_LVL_ERROR);
continue; continue;
} }
} }

View File

@@ -5,8 +5,8 @@ if (!defined('AOWOW_REVISION'))
// builds talent-tree-data for the talent-calculator // builds talent-tree-data for the talent-calculator
// this script requires the following dbc-files to be parsed and available // this script requires the following dbc-files to be available
// Talent, TalentTab, Spell, CreatureFamily // Talent.dbc, TalentTab.dbc
// talents // talents
// i - int talentId (id of aowow_talent) // i - int talentId (id of aowow_talent)
@@ -25,8 +25,22 @@ if (!defined('AOWOW_REVISION'))
// t - array of talent-objects // t - array of talent-objects
// f - array:int [pets only] creatureFamilies in that category // f - array:int [pets only] creatureFamilies in that category
function talents(&$log, $locales) function talents()
{ {
// expected dbcs
$req = ['dbc_talenttab', 'dbc_talent'];
$found = DB::Aowow()->selectCol('SHOW TABLES LIKE "dbc_%"');
if ($missing = array_diff($req, $found))
{
foreach ($missing as $m)
{
$file = explode('_', $m)[1];
$dbc = new DBC($file);
if ($dbc->readFromFile($file == 'talenttab'))
$dbc->writeToDB();
}
}
$success = true; $success = true;
$buildTree = function ($class) use (&$petFamIcons, &$tSpells) $buildTree = function ($class) use (&$petFamIcons, &$tSpells)
{ {
@@ -35,19 +49,12 @@ if (!defined('AOWOW_REVISION'))
$mask = $class ? 1 << ($class - 1) : 0; $mask = $class ? 1 << ($class - 1) : 0;
// All "tabs" of a given class talent // All "tabs" of a given class talent
$tabs = DB::Aowow()->select('SELECT * FROM dbc.talenttab WHERE classMask = ?d ORDER BY `tabNumber`, `creatureFamilyMask`', $mask); $tabs = DB::Aowow()->select('SELECT * FROM dbc_talenttab WHERE classMask = ?d ORDER BY `tabNumber`, `creatureFamilyMask`', $mask);
$result = []; $result = [];
for ($l = 0; $l < count($tabs); $l++) for ($l = 0; $l < count($tabs); $l++)
{ {
$talents = DB::Aowow()->select(' $talents = DB::Aowow()->select('SELECT t.id AS tId, t.*, s.* FROM dbc_talent t, ?_spell s WHERE t.`tabId`= ?d AND s.`Id` = t.`rank1` ORDER by t.`row`, t.`column`', $tabs[$l]['Id']);
SELECT t.id AS tId, t.*, s.*
FROM dbc.talent t, ?_spell s
WHERE t.`tabId`= ?d AND s.`Id` = t.`rank1`
ORDER by t.`row`, t.`column`',
$tabs[$l]['Id']
);
$result[$l] = array( $result[$l] = array(
'n' => Util::localizedString($tabs[$l], 'name'), 'n' => Util::localizedString($tabs[$l], 'name'),
't' => [] 't' => []
@@ -163,13 +170,13 @@ if (!defined('AOWOW_REVISION'))
// check directory-structure // check directory-structure
foreach (Util::$localeStrings as $dir) foreach (Util::$localeStrings as $dir)
if (!writeDir('datasets/'.$dir, $log)) if (!FileGen::writeDir('datasets/'.$dir))
$success = false; $success = false;
$tSpellIds = DB::Aowow()->selectCol('SELECT rank1 FROM dbc.talent UNION SELECT rank2 FROM dbc.talent UNION SELECT rank3 FROM dbc.talent UNION SELECT rank4 FROM dbc.talent UNION SELECT rank5 FROM dbc.talent'); $tSpellIds = DB::Aowow()->selectCol('SELECT rank1 FROM dbc_talent UNION SELECT rank2 FROM dbc_talent UNION SELECT rank3 FROM dbc_talent UNION SELECT rank4 FROM dbc_talent UNION SELECT rank5 FROM dbc_talent');
$tSpells = new SpellList(array(['s.id', $tSpellIds], CFG_SQL_LIMIT_NONE)); $tSpells = new SpellList(array(['s.id', $tSpellIds], CFG_SQL_LIMIT_NONE));
foreach ($locales as $lId) foreach (FileGen::$localeIds as $lId)
{ {
User::useLocale($lId); User::useLocale($lId);
Lang::load(Util::$localeStrings[$lId]); Lang::load(Util::$localeStrings[$lId]);
@@ -181,9 +188,9 @@ if (!defined('AOWOW_REVISION'))
$cId = log($cMask, 2) + 1; $cId = log($cMask, 2) + 1;
$file = 'datasets/'.User::$localeString.'/talents-'.$cId; $file = 'datasets/'.User::$localeString.'/talents-'.$cId;
$toFile = '$WowheadTalentCalculator.registerClass('.$cId.', '.json_encode($buildTree($cId), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK).')'; $toFile = '$WowheadTalentCalculator.registerClass('.$cId.', '.Util::toJSON($buildTree($cId)).')';
if (!writeFile($file, $toFile, $log)) if (!FileGen::writeFile($file, $toFile))
$success = false; $success = false;
} }
@@ -191,14 +198,14 @@ if (!defined('AOWOW_REVISION'))
if (empty($petIcons)) if (empty($petIcons))
{ {
$pets = DB::Aowow()->SelectCol('SELECT Id AS ARRAY_KEY, iconString FROM ?_pet'); $pets = DB::Aowow()->SelectCol('SELECT Id AS ARRAY_KEY, iconString FROM ?_pet');
$petIcons = json_encode($pets, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK); $petIcons = Util::toJSON($pets);
} }
$toFile = "var g_pet_icons = ".$petIcons.";\n\n"; $toFile = "var g_pet_icons = ".$petIcons.";\n\n";
$toFile .= 'var g_pet_talents = '.json_encode($buildTree(0), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK).';'; $toFile .= 'var g_pet_talents = '.Util::toJSON($buildTree(0)).';';
$file = 'datasets/'.User::$localeString.'/pet-talents'; $file = 'datasets/'.User::$localeString.'/pet-talents';
if (!writeFile($file, $toFile, $log)) if (!FileGen::writeFile($file, $toFile))
$success = false; $success = false;
} }

View File

@@ -1,4 +1,4 @@
var mn_profiles = /*setup:mnProfiles*/; var mn_profiles = /*setup:realmMenu*/;
var mn_guilds = $.extend(true,[],mn_profiles); var mn_guilds = $.extend(true,[],mn_profiles);
var mn_arenateams = $.extend(true,[],mn_profiles); var mn_arenateams = $.extend(true,[],mn_profiles);

View File

@@ -0,0 +1,318 @@
<?php
/*
imagecreatefromblp - a PHP function which loads images from BLP files
This file is a part of AoWoW project.
Copyright (C) 2010 Mix <ru-mangos.ru>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Usage example:
// $img = imagecreatefromblp("fileName.blp");
// imagejpeg($img);
// imagedestroy($img);
function imagecreatefromblp($fileName, $imgId = 0)
{
if (!FileGen::fileExists($fileName))
{
FileGen::status('file '.$fileName.' could not be found', MSG_LVL_ERROR);
return;
}
$file = fopen($fileName, 'rb');
if (!$file)
{
FileGen::status('could not open file '.$fileName, MSG_LVL_ERROR);
return;
}
$fileSize = fileSize($fileName);
if ($fileSize < 16)
{
FileGen::status('file '.$fileName.' is too small for a BLP file', MSG_LVL_ERROR);
return;
}
$data = fread($file, $fileSize);
fclose($file);
// predict replacement patch files
// ref: http://www.zezula.net/en/mpq/patchfiles.html
if (substr($data, 0x0, 0x4) == "PTCH")
{
// strip patch header
if (substr($data, 0x40, 0x43) == "COPY")
$data = substr($data, 0x44);
else
{
FileGen::status('file '.$fileName.' is an incremental patch file and cannot be used by this script.', MSG_LVL_ERROR);
return;
}
}
if (substr($data, 0, 4) != "BLP2")
{
FileGen::status('file '.$fileName.' has incorrect/unsupported magic bytes', MSG_LVL_ERROR);
return;
}
$header = unpack("Vformat/Ctype/CalphaBits/CalphaType/Cmips/Vwidth/Vheight", substr($data, 4, 16));
$header['mipsOffs'] = unpack("V16", substr($data, 20, 64));
$header['mipsSize'] = unpack("V16", substr($data, 84, 64));
$debugStr = ' header = '.print_r($header, true);
if ($header['format'] != 1)
{
FileGen::status('file '.$fileName.' has unsupported format'.$debugStr, MSG_LVL_ERROR);
return;
}
$offs = $header['mipsOffs'][$imgId + 1];
$size = $header['mipsSize'][$imgId + 1];
while ($imgId > 0)
{
$header['width'] /= 2;
$header['height'] /= 2;
$imgId--;
}
if ($size == 0)
{
FileGen::status('file '.$fileName.' contains zeroes in a mips table'.$debugStr, MSG_LVL_ERROR);
return;
}
if ($offs + $size > $fileSize)
{
FileGen::status('file '.$fileName.' is corrupted/incomplete'.$debugStr, MSG_LVL_ERROR);
return;
}
if ($header['type'] == 1)
$img = icfb1($header['width'], $header['height'], substr($data, 148, 1024), substr($data, $offs, $size));
else if ($header['type'] == 2)
$img = icfb2($header['width'], $header['height'], substr($data, $offs, $size), $header['alphaBits'], $header['alphaType']);
else if ($header['type'] == 3)
$img = icfb3($header['width'], $header['height'], substr($data, $offs, $size));
else
{
FileGen::status('file '.$fileName.' has unsupported type'.$debugStr, MSG_LVL_ERROR);
return;
}
return $img;
}
// uncompressed
function icfb1($width, $height, $palette, $data)
{
$img = imagecreatetruecolor($width, $height);
imagesavealpha($img, true);
imagealphablending($img, false);
$t = unpack("V256", $palette);
$i = unpack("C*", $data);
for ($y = 0; $y < $height; $y++)
{
for ($x = 0; $x < $width; $x++)
{
$c = $t[$i[$x + $y * $width+ 1 ] + 1];
$c = imagecolorallocatealpha($img, ($c >> 16) & 255, ($c >> 8) & 255, $c & 255, (($c >> 24) & 255) >> 1);
imagesetpixel($img, $x, $y, $c);
imagecolordeallocate($img, $c);
}
}
return $img;
}
// DXTC
function icfb2($width, $height, $data, $alphaBits, $alphaType)
{
if (!in_array($alphaBits * 10 + $alphaType, [0, 10, 41, 81, 87, 88]))
{
FileGen::status('unsupported compression type', MSG_LVL_ERROR);
return;
}
$img = imagecreatetruecolor($width, $height);
imagesavealpha($img, true);
imagealphablending($img, false);
$offset = 0;
for ($offy = 0; $offy < $height; $offy += 4)
{
for ($offx = 0; $offx < $width; $offx += 4)
{
$alpha = [];
if ($alphaBits > 1)
{
if ($alphaType <= 1)
{
$a = unpack("V2", substr($data, $offset, 8));
$a1 = $a[1];
$a2 = $a[2];
for ($i = 0; $i < 8; $i++, $a1 >>= 4)
$alpha[$i] = (($a1 & 15) << 4) | ($a1 & 15);
for ($i = 8; $i < 16; $i++, $a2 >>= 4)
$alpha[$i] = (($a2 & 15) << 4) | ($a2 & 15);
}
else
{
$c = unpack("C2", substr($data, $offset, 2));
$t = [$c[1], $c[2]];
if ($t[0] <= $t[1])
{
$t[2] = (4 * $t[0] + $t[1]) / 5;
$t[3] = (3 * $t[0] + 2 * $t[1]) / 5;
$t[4] = (2 * $t[0] + 3 * $t[1]) / 5;
$t[5] = ( $t[0] + 4 * $t[1]) / 5;
$t[6] = 0;
$t[7] = 255;
}
else
{
$t[2] = (6 * $t[0] + $t[1]) / 7;
$t[3] = (5 * $t[0] + 2 * $t[1]) / 7;
$t[4] = (4 * $t[0] + 3 * $t[1]) / 7;
$t[5] = (3 * $t[0] + 4 * $t[1]) / 7;
$t[6] = (2 * $t[0] + 5 * $t[1]) / 7;
$t[7] = ( $t[0] + 6 * $t[1]) / 7;
}
$a = unpack("C6", substr($data, $offset + 2, 6));
$a1 = $a[1] | ($a[2] << 8) | ($a[3] << 16);
$a2 = $a[4] | ($a[5] << 8) | ($a[6] << 16);
for ($i = 0; $i < 8; $i++, $a1 >>= 3)
$alpha[$i] = $t[$a1 & 7];
for ($i = 8; $i < 16; $i++, $a2 >>= 3)
$alpha[$i] = $t[$a2 & 7];
}
$offset += 8;
}
$c0 = unpack("v", substr($data, $offset, 2))[1];
$t = [];
$t[0] = array(
'r' => (($c0 >> 8) & 0xF8) | (($c0 >> 13) & 7),
'g' => (($c0 >> 3) & 0xFC) | (($c0 >> 9) & 3),
'b' => (($c0 << 3) & 0xF8) | (($c0 >> 2) & 7),
'a' => 0
);
$c1 = unpack("v", substr($data, $offset + 2, 2))[1];
$t[1] = array(
'r' => (($c1 >> 8) & 0xF8) | (($c1 >> 13) & 7),
'g' => (($c1 >> 3) & 0xFC) | (($c1 >> 9) & 3),
'b' => (($c1 << 3) & 0xF8) | (($c1 >> 2) & 7),
'a' => 0
);
if (($c0 <= $c1) && ($alphaBits <= 1))
{
$t[2] = array(
'r' => ($t[0]['r'] + $t[1]['r']) / 2,
'g' => ($t[0]['g'] + $t[1]['g']) / 2,
'b' => ($t[0]['b'] + $t[1]['b']) / 2,
'a' => 0
);
if ($alphaBits == 1)
$t[3] = ['r' => 0, 'g' => 0, 'b' => 0, 'a' => 255];
else
$t[3] = ['r' => 0, 'g' => 0, 'b' => 0, 'a' => 0];
}
else
{
$t[2] = array(
'r' => (2 * $t[0]['r'] + $t[1]['r']) / 3,
'g' => (2 * $t[0]['g'] + $t[1]['g']) / 3,
'b' => (2 * $t[0]['b'] + $t[1]['b']) / 3,
'a' => 0
);
$t[3] = array(
'r' => ($t[0]['r'] + 2 * $t[1]['r']) / 3,
'g' => ($t[0]['g'] + 2 * $t[1]['g']) / 3,
'b' => ($t[0]['b'] + 2 * $t[1]['b']) / 3,
'a' => 0
);
}
if ($alphaBits > 1)
{
$i = unpack("V", substr($data, $offset + 4, 4))[1];
for ($y = 0; $y < 4; $y++)
{
for ($x = 0; $x < 4; $x++, $i >>= 2)
{
$color = imagecolorallocatealpha($img, $t[$i & 3]['r'], $t[$i & 3]['g'], $t[$i & 3]['b'], (255 - $alpha[$x + $y * 4]) / 2);
imagesetpixel($img, $offx + $x, $offy + $y, $color);
imagecolordeallocate($img, $color);
}
}
}
else
{
$c = [];
for ($i = 0; $i < 4; $i++)
$c[$i] = imagecolorallocatealpha($img, $t[$i]['r'], $t[$i]['g'], $t[$i]['b'], $t[$i]['a'] / 2);
$i = unpack("V", substr($data, $offset + 4, 4))[1];
for ($y = 0; $y < 4; $y++)
for ($x = 0; $x < 4; $x++, $i >>= 2)
imagesetpixel($img, $offx + $x, $offy + $y, $c[$i & 3]);
for ($i = 0; $i < 4; $i++)
imagecolordeallocate($img, $c[$i]);
}
$offset += 8;
}
}
return $img;
}
// plain
function icfb3($width, $height, $data)
{
$img = imagecreatetruecolor($width, $height);
$i = unpack("V*", $data);
for ($y = 0; $y < $height; $y++)
{
for ($x = 0; $x < $width; $x++)
{
$c = $i[$x + $y * $width + 1];
$c = imagecolorallocate($img, ($c >> 16) & 255, ($c >> 8) & 255, $c & 255);
imagesetpixel($img, $x, $y, $c);
imagecolordeallocate($img, $c);
}
}
return $img;
}
?>