diff --git a/includes/database.class.php b/includes/database.class.php
index fb39bf2e..9124dcbe 100644
--- a/includes/database.class.php
+++ b/includes/database.class.php
@@ -28,7 +28,7 @@ class DB
$options = &self::$optionsCache[$idx];
$interface = DbSimple_Generic::connect(self::createConnectSyntax($options));
- $interface->setErrorHandler(array('DB', 'errorHandler'));
+ $interface->setErrorHandler(['DB', 'errorHandler']);
if ($interface->error)
die('Failed to connect to database.');
@@ -46,9 +46,9 @@ class DB
if (!error_reporting())
return;
- echo "DB ERROR:
\n\n
";
- print_r($data);
- echo "
";
+ $error = "DB ERROR:
\n\n".print_r($data, true)."
";
+
+ echo CLI ? strip_tags($error) : $error;
exit;
}
diff --git a/includes/kernel.php b/includes/kernel.php
index 1cbbe965..6f0c33d4 100644
--- a/includes/kernel.php
+++ b/includes/kernel.php
@@ -4,18 +4,22 @@ if (!defined('AOWOW_REVISION'))
die('illegal access');
-require 'includes/defines.php';
-require '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)
-require 'includes/utilities.php'; // miscâ„¢ data 'n func
-require 'includes/ajaxHandler.class.php'; // handles ajax and jsonp requests
-require 'includes/user.class.php';
-require 'includes/markup.class.php'; // manipulate markup text
-require 'includes/database.class.php'; // wrap DBSimple
-require 'includes/community.class.php'; // handle comments, screenshots and videos
-require 'includes/loot.class.php'; // build lv-tabs containing loot-information
-require 'localization/lang.class.php';
-require 'pages/genericPage.class.php';
+if (file_exists('config/config.php'))
+ require_once 'config/config.php';
+else
+ $AoWoWconf = [];
+
+require_once 'includes/defines.php';
+require_once 'includes/libs/DbSimple/Generic.php'; // Libraray: http://en.dklab.ru/lib/DbSimple (using variant: https://github.com/ivan1986/DbSimple/tree/master)
+require_once 'includes/utilities.php'; // miscâ„¢ data 'n func
+require_once 'includes/ajaxHandler.class.php'; // handles ajax and jsonp requests
+require_once 'includes/user.class.php';
+require_once 'includes/markup.class.php'; // manipulate markup text
+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
@@ -31,24 +35,22 @@ spl_autoload_register(function ($class) {
if (strpos($class, 'list'))
{
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'))
- require 'includes/types/'.strtr($class, ['list' => '']).'.class.php';
+ require_once 'includes/types/'.strtr($class, ['list' => '']).'.class.php';
return;
}
if (file_exists('pages/'.strtr($class, ['page' => '']).'.php'))
- require 'pages/'.strtr($class, ['page' => '']).'.php';
+ require_once 'pages/'.strtr($class, ['page' => '']).'.php';
});
// Setup DB-Wrapper
if (!empty($AoWoWconf['aowow']['db']))
DB::load(DB_AOWOW, $AoWoWconf['aowow']);
-else
- die('no database credentials given for: aowow');
if (!empty($AoWoWconf['world']['db']))
DB::load(DB_WORLD, $AoWoWconf['world']);
@@ -56,15 +58,14 @@ if (!empty($AoWoWconf['world']['db']))
if (!empty($AoWoWconf['auth']['db']))
DB::load(DB_AUTH, $AoWoWconf['auth']);
-foreach ($AoWoWconf['characters'] as $realm => $charDBInfo)
- if (!empty($charDBInfo))
- DB::load(DB_CHARACTERS . $realm, $charDBInfo);
-
-unset($AoWoWconf); // link set up: delete passwords
+if (!empty($AoWoWconf['characters']))
+ foreach ($AoWoWconf['characters'] as $realm => $charDBInfo)
+ if (!empty($charDBInfo))
+ DB::load(DB_CHARACTERS . $realm, $charDBInfo);
// 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)
{
// this should not have been possible
@@ -80,7 +81,7 @@ foreach ($sets as $k => $v)
else if ($v['flags'] & CON_FLAG_TYPE_BOOL)
$val = (bool)$v['value'];
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
{
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;
-$protocoll = $secure ? 'https://' : 'http://';
+error_reporting($AoWoWconf && CFG_DEBUG ? (E_ALL & ~(E_DEPRECATED | E_USER_DEPRECATED | E_STRICT)) : 0);
-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)
-define('HOST_URL', substr($protocoll.$_SERVER['SERVER_NAME'].strtr($_SERVER['SCRIPT_NAME'], ['index.php' => '']), 0, -1)); // points js to executable files
+$secure = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || ($AoWoWconf && CFG_FORCE_SSL);
+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;
-error_reporting($e);
+if (defined('CFG_SITE_HOST')) // points js to executable files
+ define('HOST_URL', ($secure ? 'https://' : 'http://').CFG_SITE_HOST);
-// debug: measure execution times
-Util::execTime(CFG_DEBUG);
+if (!CLI)
+{
+ // Setup Session
+ session_set_cookie_params(15 * YEAR, '/', '', $secure, true);
+ session_cache_limiter('private');
+ session_start();
+ if ($AoWoWconf && User::init())
+ 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..?)
+ // all strings attached..
+ if ($AoWoWconf)
+ {
+ if (isset($_GET['locale']) && (CFG_LOCALES & (1 << (int)$_GET['locale'])))
+ User::useLocale($_GET['locale']);
+
+ Lang::load(User::$localeString);
+ }
+
+ // parse page-parameters .. sanitize before use!
+ @list($str, $trash) = explode('&', $_SERVER['QUERY_STRING'], 2);
+ @list($pageCall, $pageParam) = explode('=', $str, 2);
+ Util::$wowheadLink = 'http://'.Util::$subDomains[User::$localeId].'.wowhead.com/'.$str;
+}
+else if ($AoWoWconf)
+ Lang::load('enus');
-// Setup Session
-session_set_cookie_params(15 * YEAR, '/', '', $secure, true);
-session_cache_limiter('private');
-session_start();
-if (User::init())
- User::save(); // save user-variables in session
-
-// hard-override locale for this call (should this be here..?)
-// all strings attached..
-if (isset($_GET['locale']) && (CFG_LOCALES & (1 << (int)$_GET['locale'])))
- User::useLocale($_GET['locale']);
-
-Lang::load(User::$localeString);
-
-
-// parse page-parameters .. sanitize before use!
-@list($str, $trash) = explode('&', $_SERVER['QUERY_STRING'], 2);
-@list($pageCall, $pageParam) = explode('=', $str, 2);
-Util::$wowheadLink = 'http://'.Util::$subDomains[User::$localeId].'.wowhead.com/'.$str;
+$AoWoWconf = null; // empty auths
?>
diff --git a/index.php b/index.php
index b53b8506..d733e820 100644
--- a/index.php
+++ b/index.php
@@ -1,28 +1,39 @@
'.$r." was not found. Please see if it exists, using php -m\n\n";
+ $error .= 'Required Extension '.$r." was not found. Please check if it should exist, using \"php -m\"\n\n";
if (version_compare(PHP_VERSION, '5.5.0') < 0)
- $error .= 'PHP Version 5.5.0 or higher required! Your version is '.PHP_VERSION.".\nCore functions are unavailable!";
+ $error .= 'PHP Version 5.5.0 or higher required! Your version is '.PHP_VERSION.".\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)
- die(''.$error.'
');
+{
+ echo CLI ? strip_tags($error) : $error;
+ die();
+}
+
// 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 = '';
@@ -81,7 +92,8 @@ switch ($pageCall)
case 'talent': // tool: talent calculator
case 'title':
case 'titles':
- // case 'user': // tool: user profiles [nyi]
+ // case 'user': // tool: user profiles [nyi]
+ case 'video':
case 'zone':
case 'zones':
if (in_array($pageCall, ['admin', 'account', 'profile']))
@@ -134,7 +146,8 @@ switch ($pageCall)
case 'build':
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;
}
case 'sql':
@@ -143,12 +156,6 @@ switch ($pageCall)
require 'setup/tools/database/_'.$pageParam.'.php';
break;
}
- case 'setup':
- if (User::isInGroup(U_GROUP_EMPLOYEE))
- {
- require 'setup/syncronize.php';
- break;
- }
default: // unk parameter given -> ErrorPage
if (isset($_GET['power']))
die('$WowheadPower.register(0, '.User::$localeId.', {})');
diff --git a/pages/spell.php b/pages/spell.php
index 8d0a4eb9..9d2ae70c 100644
--- a/pages/spell.php
+++ b/pages/spell.php
@@ -221,6 +221,19 @@ class SpellPage extends GenericPage
if ($id == $this->typeId) // "Mode" seems to be multilingual acceptable
$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 */
@@ -236,8 +249,8 @@ class SpellPage extends GenericPage
$this->scaling = $this->createScalingData();
$this->items = $this->createRequiredItems();
$this->tools = $this->createTools();
- $this->effects = $this->createEffects($infobox, $redButtons);
- $this->infobox = $infobox ? '[ul]'.implode('', $infobox).'[/ul]' : null;
+ $this->effects = $effects;
+ $this->infobox = $infobox;
$this->powerCost = $this->subject->createPowerCostForCurrent();
$this->castTime = $this->subject->createCastTimeForCurrent(false, false);
$this->name = $this->subject->getField('name', true);
@@ -934,8 +947,8 @@ class SpellPage extends GenericPage
'params' => array(
'id' => 'teaches-spell',
'name' => '$LANG.tab_teaches',
- 'visibleCols' => '$'.json_encode($vis),
- 'hiddenCols' => $hid ? '$'.json_encode($hid) : null
+ 'visibleCols' => '$'.Util::toJSON($vis),
+ 'hiddenCols' => $hid ? '$'.Util::toJSON($hid) : null
)
);
}
@@ -1087,7 +1100,7 @@ class SpellPage extends GenericPage
{
$this->extendGlobalData($sc[1]);
$tab = "";
@@ -1116,12 +1129,12 @@ class SpellPage extends GenericPage
if ($tt = $this->subject->renderTooltip())
{
$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())
{
$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});";
diff --git a/setup/db_setup_3.zip b/setup/db_setup_3.zip
index 917a9d6e..94d0a701 100644
Binary files a/setup/db_setup_3.zip and b/setup/db_setup_3.zip differ
diff --git a/setup/setup.php b/setup/setup.php
new file mode 100644
index 00000000..9015024d
--- /dev/null
+++ b/setup/setup.php
@@ -0,0 +1,376 @@
+ 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!', '- '.str_replace($cwDir, '', $path).'\\'.implode($reqFiles, '.dbc
- '.str_replace($cwDir, '', $path).'\\').'.dbc
');
+}
+
+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:*/
+ 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';
+}
+*/
+
+
+?>
diff --git a/setup/tools/dbc.class.php b/setup/tools/dbc.class.php
new file mode 100644
index 00000000..72a72573
--- /dev/null
+++ b/setup/tools/dbc.class.php
@@ -0,0 +1,390 @@
+
+
+ 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 .
+*/
+
+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;
+ }
+}
+
+?>
diff --git a/setup/tools/filegen/complexImg.func.php b/setup/tools/filegen/complexImg.func.php
new file mode 100644
index 00000000..4674c3d3
--- /dev/null
+++ b/setup/tools/filegen/complexImg.func.php
@@ -0,0 +1,729 @@
+
+
+ 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 .
+*/
+
+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;
+ }
+
+?>
diff --git a/setup/tools/filegen/enchants.func.php b/setup/tools/filegen/enchants.func.php
index 2974a393..61a5bc4b 100644
--- a/setup/tools/filegen/enchants.func.php
+++ b/setup/tools/filegen/enchants.func.php
@@ -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",
$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 = [];
$successs = true;
$enchantSpells = new SpellList([['effect1Id', 53], ['name_loc0', 'QA%', '!'], CFG_SQL_LIMIT_NONE]); // enchantItemPermanent && !qualityAssurance
// check directory-structure
foreach (Util::$localeStrings as $dir)
- if (!writeDir('datasets/'.$dir, $log))
+ if (!FileGen::writeDir('datasets/'.$dir))
$success = false;
$enchIds = [];
@@ -73,7 +72,7 @@ if (!defined('AOWOW_REVISION'))
$enchMisc = [];
$enchJSON = Util::parseItemEnchantment($enchIds, false, $enchMisc);
- foreach ($locales as $lId)
+ foreach (FileGen::$localeIds as $lId)
{
set_time_limit(120);
@@ -135,11 +134,11 @@ if (!defined('AOWOW_REVISION'))
$ench['jsonequip']['requiredLevel'] = $enchMisc[$eId]['requiredLevel'];
// 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['source'][] = $enchantSpells->id;
- $ench['skill'] = $skill;
+ $ench['skill'] = $skills[0];
$ench['slots'][] = $slot;
}
@@ -209,12 +208,10 @@ if (!defined('AOWOW_REVISION'))
if (is_array($v) && count($v) == 1 && $k != 'jsonequip')
$ench[$k] = $v[0];
- $toFile = "var g_enchants = ";
- $toFile .= json_encode($enchantsOut, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK);
- $toFile .= ";";
- $file = 'datasets/'.User::$localeString.'/enchants';
+ $toFile = "var g_enchants = ".Util::toJSON($enchantsOut).";";
+ $file = 'datasets/'.User::$localeString.'/enchants';
- if (!writeFile($file, $toFile, $log))
+ if (!FileGen::writeFile($file, $toFile))
$success = false;
}
diff --git a/setup/tools/filegen/fileGen.class.php b/setup/tools/filegen/fileGen.class.php
new file mode 100644
index 00000000..41021881
--- /dev/null
+++ b/setup/tools/filegen/fileGen.class.php
@@ -0,0 +1,423 @@
+ 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 = '%s';
+
+ 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 "".$msg."
\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= [-h --help] [--log logfile] [-f --force] [--mpqDataDir=path/to/mpqData/] [--locales=]\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";
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/setup/tools/filegen/gems.func.php b/setup/tools/filegen/gems.func.php
index 6edc0f68..50bbc9bd 100644
--- a/setup/tools/filegen/gems.func.php
+++ b/setup/tools/filegen/gems.func.php
@@ -21,7 +21,7 @@ if (!defined('AOWOW_REVISION'))
},
*/
- function gems(&$log, $locales)
+ function gems()
{
// sketchy, but should work
// Id < 36'000 || ilevel < 70 ? BC : WOTLK
@@ -41,7 +41,7 @@ if (!defined('AOWOW_REVISION'))
// check directory-structure
foreach (Util::$localeStrings as $dir)
- if (!writeDir('datasets/'.$dir, $log))
+ if (!FileGen::writeDir('datasets/'.$dir))
$success = false;
$enchIds = [];
@@ -51,7 +51,7 @@ if (!defined('AOWOW_REVISION'))
$enchMisc = [];
$enchJSON = Util::parseItemEnchantment($enchIds, false, $enchMisc);
- foreach ($locales as $lId)
+ foreach (FileGen::$localeIds as $lId)
{
set_time_limit(5);
@@ -72,12 +72,10 @@ if (!defined('AOWOW_REVISION'))
);
}
- $toFile = "var g_gems = ";
- $toFile .= json_encode($gemsOut, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK);
- $toFile .= ";";
- $file = 'datasets/'.User::$localeString.'/gems';
+ $toFile = "var g_gems = ".Util::toJSON($gemsOut).";";
+ $file = 'datasets/'.User::$localeString.'/gems';
- if (!writeFile($file, $toFile, $log))
+ if (!FileGen::writeFile($file, $toFile))
$success = false;
}
diff --git a/setup/tools/filegen/glyphs.func.php b/setup/tools/filegen/glyphs.func.php
index a75a81d0..dbaf8b3a 100644
--- a/setup/tools/filegen/glyphs.func.php
+++ b/setup/tools/filegen/glyphs.func.php
@@ -20,7 +20,7 @@ if (!defined('AOWOW_REVISION'))
},
*/
- function glyphs(&$log, $locales)
+ function glyphs()
{
$success = true;
$glyphList = DB::Aowow()->Select(
@@ -42,12 +42,12 @@ if (!defined('AOWOW_REVISION'))
// check directory-structure
foreach (Util::$localeStrings as $dir)
- if (!writeDir('datasets/'.$dir, $log))
+ if (!FileGen::writeDir('datasets/'.$dir))
$success = false;
$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);
@@ -76,12 +76,10 @@ if (!defined('AOWOW_REVISION'))
);
}
- $toFile = "var g_glyphs = ";
- $toFile .= json_encode($glyphsOut, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK);
- $toFile .= ";";
- $file = 'datasets/'.User::$localeString.'/glyphs';
+ $toFile = "var g_glyphs = ".Util::toJSON($glyphsOut).";";
+ $file = 'datasets/'.User::$localeString.'/glyphs';
- if (!writeFile($file, $toFile, $log))
+ if (!FileGen::writeFile($file, $toFile))
$success = false;
}
diff --git a/setup/tools/filegen/itemsets.func.php b/setup/tools/filegen/itemsets.func.php
index c177420e..14820b00 100644
--- a/setup/tools/filegen/itemsets.func.php
+++ b/setup/tools/filegen/itemsets.func.php
@@ -29,7 +29,7 @@ if (!defined('AOWOW_REVISION'))
},
*/
- function itemsets(&$log, $locales)
+ function itemsets()
{
$success = true;
$setList = DB::Aowow()->Select('SELECT * FROM ?_itemset ORDER BY refSetId DESC');
@@ -37,10 +37,10 @@ if (!defined('AOWOW_REVISION'))
// check directory-structure
foreach (Util::$localeStrings as $dir)
- if (!writeDir('datasets/'.$dir, $log))
+ if (!FileGen::writeDir('datasets/'.$dir))
$success = false;
- foreach ($locales as $lId)
+ foreach (FileGen::$localeIds as $lId)
{
User::useLocale($lId);
Lang::load(Util::$localeStrings[$lId]);
@@ -120,12 +120,10 @@ if (!defined('AOWOW_REVISION'))
$itemsetOut[$setOut['id']] = $setOut;
}
- $toFile = "var g_itemsets = ";
- $toFile .= json_encode($itemsetOut, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK);
- $toFile .= ";";
- $file = 'datasets/'.User::$localeString.'/itemsets';
+ $toFile = "var g_itemsets = ".Util::toJSON($itemsetOut).";";
+ $file = 'datasets/'.User::$localeString.'/itemsets';
- if (!writeFile($file, $toFile, $log))
+ if (!FileGen::writeFile($file, $toFile))
$success = false;
}
diff --git a/setup/tools/filegen/locales.func.php b/setup/tools/filegen/locales.func.php
index 1ce9f2d7..24eb2a31 100644
--- a/setup/tools/filegen/locales.func.php
+++ b/setup/tools/filegen/locales.func.php
@@ -7,7 +7,7 @@ if (!defined('AOWOW_REVISION'))
// Create 'locale.js'-file in static/js
// available locales have to be set in aowow.aowow_config
- function locales(&$log, $locales)
+ function locales()
{
$result = [];
$available = array(
@@ -43,7 +43,7 @@ if (!defined('AOWOW_REVISION'))
" }",
);
- foreach ($locales as $l)
+ foreach (FileGen::$localeIds as $l)
if (isset($available[$l]))
$result[] = $available[$l];
diff --git a/setup/tools/filegen/pets.func.php b/setup/tools/filegen/pets.func.php
index 415ad9ab..af06d3ac 100644
--- a/setup/tools/filegen/pets.func.php
+++ b/setup/tools/filegen/pets.func.php
@@ -5,8 +5,6 @@ if (!defined('AOWOW_REVISION'))
// builds 'pets'-file for available locales
- // this script requires the following dbc-files to be parsed and available
- // CreatureFamily, CreatureDisplayInfo, FactionTemplate, AreaTable
/* Example data
30: {
@@ -25,7 +23,7 @@ if (!defined('AOWOW_REVISION'))
},
*/
- function pets(&$log, $locales)
+ function pets()
{
$success = true;
$locations = [];
@@ -38,22 +36,21 @@ if (!defined('AOWOW_REVISION'))
cr.rank AS classification,
cr.family,
cr.displayId1 AS displayId,
- cdi.skin1 AS skin,
- SUBSTRING_INDEX(cf.iconFile, "\\\\", -1) AS icon,
- cf.petTalentType AS type
+ cr.textureString AS skin,
+ p.iconString AS icon,
+ p.type
FROM ?_creature cr
JOIN ?_factiontemplate ft ON ft.Id = cr.faction
- JOIN dbc.creaturefamily cf ON cf.Id = cr.family
- JOIN dbc.creaturedisplayinfo cdi ON cdi.id = cr.displayId1
- WHERE cf.petTalentType <> -1 AND cr.typeFlags & 0x1 AND (cr.cuFlags & 0x2) = 0
+ JOIN ?_pet p ON p.id = cr.family
+ WHERE cr.typeFlags & 0x1 AND (cr.cuFlags & 0x2) = 0
ORDER BY cr.id ASC');
// check directory-structure
foreach (Util::$localeStrings as $dir)
- if (!writeDir('datasets/'.$dir, $log))
+ if (!FileGen::writeDir('datasets/'.$dir))
$success = false;
- foreach ($locales as $lId)
+ foreach (FileGen::$localeIds as $lId)
{
User::useLocale($lId);
Lang::load(Util::$localeStrings[$lId]);
@@ -82,12 +79,10 @@ if (!defined('AOWOW_REVISION'))
);
}
- $toFile = "var g_pets = ";
- $toFile .= json_encode($petsOut, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_NUMERIC_CHECK);
- $toFile .= ";";
- $file = 'datasets/'.User::$localeString.'/pets';
+ $toFile = "var g_pets = ".Util::toJSON($petsOut).";";
+ $file = 'datasets/'.User::$localeString.'/pets';
- if (!writeFile($file, $toFile, $log))
+ if (!FileGen::writeFile($file, $toFile))
$success = false;
}
diff --git a/setup/tools/filegen/profiler.func.php b/setup/tools/filegen/profiler.func.php
index 69654048..7ea99bc1 100644
--- a/setup/tools/filegen/profiler.func.php
+++ b/setup/tools/filegen/profiler.func.php
@@ -7,7 +7,7 @@ if (!defined('AOWOW_REVISION'))
// 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
- function profiler(&$log, $locales)
+ function profiler()
{
$success = true;
$scripts = [];
@@ -15,7 +15,7 @@ if (!defined('AOWOW_REVISION'))
/**********/
/* Quests */
/**********/
- $scripts[] = function(&$log) use ($locales)
+ $scripts[] = function()
{
$success = true;
$condition = [
@@ -35,7 +35,7 @@ if (!defined('AOWOW_REVISION'))
$relCurr = new CurrencyList(array(['id', $_]));
- foreach ($locales as $l)
+ foreach (FileGen::$localeIds as $l)
{
set_time_limit(20);
@@ -44,15 +44,15 @@ if (!defined('AOWOW_REVISION'))
$buff = "var _ = g_gatheredcurrencies;\n";
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";
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";
- if (!writeFile('datasets/'.User::$localeString.'/p-quests', $buff, $log))
+ if (!FileGen::writeFile('datasets/'.User::$localeString.'/p-quests', $buff))
$success = false;
}
@@ -62,7 +62,7 @@ if (!defined('AOWOW_REVISION'))
/****************/
/* Achievements */
/****************/
- $scripts[] = function(&$log) use ($locales)
+ $scripts[] = function()
{
$success = true;
$condition = array(
@@ -72,7 +72,7 @@ if (!defined('AOWOW_REVISION'))
);
$achievez = new AchievementList($condition);
- foreach ($locales as $l)
+ foreach (FileGen::$localeIds as $l)
{
set_time_limit(5);
@@ -84,7 +84,7 @@ if (!defined('AOWOW_REVISION'))
foreach ($achievez->getListviewData(ACHIEVEMENTINFO_PROFILE) as $id => $data)
{
$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
@@ -92,7 +92,7 @@ if (!defined('AOWOW_REVISION'))
// sum points
$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;
}
@@ -102,7 +102,7 @@ if (!defined('AOWOW_REVISION'))
/**********/
/* Titles */
/**********/
- $scripts[] = function(&$log) use ($locales)
+ $scripts[] = function()
{
$success = true;
$condition = array(
@@ -111,7 +111,7 @@ if (!defined('AOWOW_REVISION'))
);
$titlez = new TitleList($condition);
- foreach ($locales as $l)
+ foreach (FileGen::$localeIds as $l)
{
set_time_limit(5);
@@ -125,10 +125,10 @@ if (!defined('AOWOW_REVISION'))
{
$data['name'] = Util::localizedString($titlez->getEntry($id), $g ? 'female' : 'male');
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;
}
}
@@ -139,7 +139,7 @@ if (!defined('AOWOW_REVISION'))
/**********/
/* Mounts */
/**********/
- $scripts[] = function(&$log) use ($locales)
+ $scripts[] = function()
{
$success = true;
$condition = array(
@@ -149,7 +149,7 @@ if (!defined('AOWOW_REVISION'))
);
$mountz = new SpellList($condition);
- foreach ($locales as $l)
+ foreach (FileGen::$localeIds as $l)
{
set_time_limit(5);
@@ -161,10 +161,10 @@ if (!defined('AOWOW_REVISION'))
{
$data['quality'] = $data['name'][0];
$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;
}
@@ -174,7 +174,7 @@ if (!defined('AOWOW_REVISION'))
/**************/
/* Companions */
/**************/
- $scripts[] = function(&$log) use ($locales)
+ $scripts[] = function()
{
$success = true;
$condition = array(
@@ -184,7 +184,7 @@ if (!defined('AOWOW_REVISION'))
);
$companionz = new SpellList($condition);
- foreach ($locales as $l)
+ foreach (FileGen::$localeIds as $l)
{
set_time_limit(5);
@@ -196,10 +196,10 @@ if (!defined('AOWOW_REVISION'))
{
$data['quality'] = $data['name'][0];
$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;
}
@@ -209,7 +209,7 @@ if (!defined('AOWOW_REVISION'))
/************/
/* Factions */
/************/
- $scripts[] = function(&$log) use ($locales)
+ $scripts[] = function()
{
$success = true;
$condition = array( // todo (med): exclude non-gaining reputation-header
@@ -218,7 +218,7 @@ if (!defined('AOWOW_REVISION'))
);
$factionz = new FactionList($condition);
- foreach ($locales as $l)
+ foreach (FileGen::$localeIds as $l)
{
set_time_limit(5);
@@ -227,11 +227,11 @@ if (!defined('AOWOW_REVISION'))
$buff = "var _ = g_factions;\n";
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";
- if (!writeFile('datasets/'.User::$localeString.'/p-factions', $buff, $log))
+ if (!FileGen::writeFile('datasets/'.User::$localeString.'/p-factions', $buff))
$success = false;
}
@@ -241,7 +241,7 @@ if (!defined('AOWOW_REVISION'))
/***********/
/* 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
$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);
@@ -278,12 +278,12 @@ if (!defined('AOWOW_REVISION'))
$buff = '';
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)
{
// 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;
}
@@ -292,7 +292,7 @@ if (!defined('AOWOW_REVISION'))
if (is_array($s))
$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;
}
}
@@ -302,12 +302,12 @@ if (!defined('AOWOW_REVISION'))
// check directory-structure
foreach (Util::$localeStrings as $dir)
- if (!writeDir('datasets/'.$dir, $log))
+ if (!FileGen::writeDir('datasets/'.$dir))
$success = false;
// run scripts
foreach ($scripts as $func)
- if (!$func($log))
+ if (!$func())
$success = false;
return $success;
diff --git a/setup/tools/filegen/mnProfiles.func.php b/setup/tools/filegen/realmMenu.func.php
similarity index 51%
rename from setup/tools/filegen/mnProfiles.func.php
rename to setup/tools/filegen/realmMenu.func.php
index 8e68a3c4..ba9b90fb 100644
--- a/setup/tools/filegen/mnProfiles.func.php
+++ b/setup/tools/filegen/realmMenu.func.php
@@ -33,41 +33,39 @@ if (!defined('AOWOW_REVISION'))
];
*/
-function mnProfiles(/* &$log */)
-{
- $menu = [
- ["us", "US & Oceanic", null,[
- [Util::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP, null, []]
- ]],
- ["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');
- $set = 0x0;
-
- foreach ($rows as $row)
+ function realmMenu()
{
- if ($row['region'] == 'eu')
+ $subEU = [];
+ $subUS = [];
+ $menu = [
+ ['us', 'US & Oceanic', null,[[Util::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP, null, &$subEU]]],
+ ['eu', 'Europe', null,[[Util::urlize(CFG_BATTLEGROUP), CFG_BATTLEGROUP, null, &$subUS]]]
+ ];
+
+ $rows = DB::Auth()->select('SELECT name, IF(timezone IN (8, 9, 10, 11, 12), "eu", "us") AS region FROM realmlist WHERE allowedSecurityLevel = 0');
+ $set = 0x0;
+
+ foreach ($rows as $row)
{
- $set |= 0x1;
- $menu[1][3][0][3][] = [Util::urlize($row['name']),$row['name']];
- }
- else if ($row['region'] == 'us')
- {
- $set |= 0x2;
- $menu[0][3][0][3][] = [Util::urlize($row['name']),$row['name']];
+ if ($row['region'] == 'eu')
+ {
+ $set |= 0x1;
+ $subEU[] = [Util::urlize($row['name']), $row['name']];
+ }
+ else if ($row['region'] == 'us')
+ {
+ $set |= 0x2;
+ $subUS[] = [Util::urlize($row['name']), $row['name']];
+ }
}
+
+ if (!($set & 0x1))
+ array_shift($menu);
+
+ if (!($set & 0x2))
+ array_pop($menu);
+
+ return Util::toJSON($menu);
}
- if (!($set & 0x1))
- array_pop($menu);
-
- if (!($set & 0x2))
- array_shift($menu);
-
- return json_encode($menu, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
-}
-
?>
diff --git a/setup/tools/filegen/realms.func.php b/setup/tools/filegen/realms.func.php
index 201a0dd5..af251468 100644
--- a/setup/tools/filegen/realms.func.php
+++ b/setup/tools/filegen/realms.func.php
@@ -23,13 +23,14 @@ if (!defined('AOWOW_REVISION'))
},
*/
- function realms(&$log)
+ function realms()
{
- $file = 'datasets/realms';
- $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).';';
+ $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);
- return writeFile($file, $str, $log);
+ $toFile = "var g_realms = ".Util::toJSON($realms).";";
+ $file = 'datasets/realms';
+
+ return FileGen::writeFile($file, $toFile);
}
?>
diff --git a/setup/tools/filegen/scriptGen.php b/setup/tools/filegen/scriptGen.php
deleted file mode 100644
index 52482d56..00000000
--- a/setup/tools/filegen/scriptGen.php
+++ /dev/null
@@ -1,211 +0,0 @@
- 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:*/
- 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 "\n";
-foreach ($log as $l)
- if ($l)
- echo date('H:i:s', $l[0]) . ' ' . $l[1]."\n";
- else
- echo "\n";
-echo "\n";
-
-
-?>
\ No newline at end of file
diff --git a/setup/tools/filegen/simpleImg.func.php b/setup/tools/filegen/simpleImg.func.php
new file mode 100644
index 00000000..c19f36ab
--- /dev/null
+++ b/setup/tools/filegen/simpleImg.func.php
@@ -0,0 +1,428 @@
+ ['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;
+ }
diff --git a/setup/tools/filegen/statistics.func.php b/setup/tools/filegen/statistics.func.php
index 288fa571..084cdac7 100644
--- a/setup/tools/filegen/statistics.func.php
+++ b/setup/tools/filegen/statistics.func.php
@@ -5,11 +5,25 @@ if (!defined('AOWOW_REVISION'))
// Create 'statistics'-file in datasets
- // this script requires the following dbcs to be parsed and available
- // gtChanceToMeleeCrit.dbc, gtChanceToSpellCrit.dbc, gtChanceToMeleeCritBase.dbc, gtChanceToSpellCritBase.dbc, gtOCTRegenHP, gtRegenHPPperSpt.dbc, gtRegenMPPerSpt.dbc
+ // this script requires the following dbcs to be available
+ // 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()
{
// constants and mods taken from TrinityCore (Player.cpp, StatSystem.cpp)
@@ -42,7 +56,7 @@ if (!defined('AOWOW_REVISION'))
);
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;
};
@@ -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 ' .
'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.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.gtregenhpperspt extraHP5 ON extraHP5.idx = ((pls.class - 1) * 100) + (pls.level - 1) ' .
+ ' 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_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) ' .
'WHERE pls.race = ?d AND pls.class = ?d ORDER BY pls.level ASC',
$offset[0], $offset[1], $offset[2], $offset[3], $offset[4],
$mod,
@@ -114,7 +128,7 @@ if (!defined('AOWOW_REVISION'))
// identical across classes (just use one, that acutally has mana (offset: 100))
// 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()
@@ -135,15 +149,14 @@ if (!defined('AOWOW_REVISION'))
$out[$s] = $res;
if (!$res)
{
- $log[] = [time(), ' error: statistics - generator $'.$s.'() returned empty'];
+ FileGen::status('statistics - generator $'.$s.'() returned empty', MSG_LVL_WARN);
$success = false;
}
}
- $json = json_encode($out, JSON_NUMERIC_CHECK | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
- $toFile = 'g_statistics = '.preg_replace('/"\$([^$"]+)"/', '\1', $json).';';
+ $toFile = 'g_statistics = '.preg_replace('/"\$([^$"]+)"/', '\1', Util::toJSON($out)).';';
- if (!writeFile('datasets/statistics', $toFile, $log))
+ if (!FileGen::writeFile('datasets/statistics', $toFile))
$success = false;
return $success;
diff --git a/setup/tools/filegen/talentIcons.func.php b/setup/tools/filegen/talentIcons.func.php
index ca8a26b5..30546328 100644
--- a/setup/tools/filegen/talentIcons.func.php
+++ b/setup/tools/filegen/talentIcons.func.php
@@ -6,21 +6,35 @@ if (!defined('AOWOW_REVISION'))
// builds image-textures for the talent-calculator
// spellIcons must be extracted and converted to at least medium size
- // this script requires the following dbc-files to be parsed and available
- // Talent, TalentTab, Spell
+ // this script requires the following dbc-files to be available
+ // 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;
- $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
$filenames = ['icons', 'warrior', 'paladin', 'hunter', 'rogue', 'priest', 'deathknight', 'shaman', 'mage', 'warlock', null, 'druid'];
// create directory if missing
- if (!writeDir('static/images/wow/talents/icons', $log))
+ if (!FileGen::writeDir('static/images/wow/talents/icons'))
$success = false;
- if (!writeDir('static/images/wow/hunterpettalents', $log))
+ if (!FileGen::writeDir('static/images/wow/hunterpettalents'))
$success = false;
foreach ($filenames as $k => $v)
@@ -41,7 +55,7 @@ if (!defined('AOWOW_REVISION'))
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;
continue;
}
@@ -53,7 +67,7 @@ if (!defined('AOWOW_REVISION'))
$imgFile = 'static/images/wow/icons/medium/'.strtolower($icons[$i]).'.jpg';
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;
break;
}
@@ -77,17 +91,17 @@ if (!defined('AOWOW_REVISION'))
}
if (@imagejpeg($res, $outFile))
- $log[] = [time(), sprintf(ERR_NONE, $outFile)];
+ FileGen::status(sprintf(ERR_NONE, $outFile), MSG_LVL_OK);
else
{
$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
{
$success = false;
- $log[] = [time(), ' error: talentIcons - image resource not created'];
+ FileGen::status('talentIcons - image resource not created', MSG_LVL_ERROR);
continue;
}
}
diff --git a/setup/tools/filegen/talents.func.php b/setup/tools/filegen/talents.func.php
index efc656c7..6cbda54b 100644
--- a/setup/tools/filegen/talents.func.php
+++ b/setup/tools/filegen/talents.func.php
@@ -5,8 +5,8 @@ if (!defined('AOWOW_REVISION'))
// builds talent-tree-data for the talent-calculator
- // this script requires the following dbc-files to be parsed and available
- // Talent, TalentTab, Spell, CreatureFamily
+ // this script requires the following dbc-files to be available
+ // Talent.dbc, TalentTab.dbc
// talents
// i - int talentId (id of aowow_talent)
@@ -25,8 +25,22 @@ if (!defined('AOWOW_REVISION'))
// t - array of talent-objects
// 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;
$buildTree = function ($class) use (&$petFamIcons, &$tSpells)
{
@@ -35,19 +49,12 @@ if (!defined('AOWOW_REVISION'))
$mask = $class ? 1 << ($class - 1) : 0;
// 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 = [];
for ($l = 0; $l < count($tabs); $l++)
{
- $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']
- );
-
+ $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']);
$result[$l] = array(
'n' => Util::localizedString($tabs[$l], 'name'),
't' => []
@@ -163,13 +170,13 @@ if (!defined('AOWOW_REVISION'))
// check directory-structure
foreach (Util::$localeStrings as $dir)
- if (!writeDir('datasets/'.$dir, $log))
+ if (!FileGen::writeDir('datasets/'.$dir))
$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));
- foreach ($locales as $lId)
+ foreach (FileGen::$localeIds as $lId)
{
User::useLocale($lId);
Lang::load(Util::$localeStrings[$lId]);
@@ -181,9 +188,9 @@ if (!defined('AOWOW_REVISION'))
$cId = log($cMask, 2) + 1;
$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;
}
@@ -191,14 +198,14 @@ if (!defined('AOWOW_REVISION'))
if (empty($petIcons))
{
$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_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';
- if (!writeFile($file, $toFile, $log))
+ if (!FileGen::writeFile($file, $toFile))
$success = false;
}
diff --git a/setup/tools/filegen/templates/profile_all.js.in b/setup/tools/filegen/templates/profile_all.js.in
index f7ca0eda..d4e003e6 100644
--- a/setup/tools/filegen/templates/profile_all.js.in
+++ b/setup/tools/filegen/templates/profile_all.js.in
@@ -1,4 +1,4 @@
-var mn_profiles = /*setup:mnProfiles*/;
+var mn_profiles = /*setup:realmMenu*/;
var mn_guilds = $.extend(true,[],mn_profiles);
var mn_arenateams = $.extend(true,[],mn_profiles);
diff --git a/setup/tools/imagecreatefromblp.php b/setup/tools/imagecreatefromblp.php
new file mode 100644
index 00000000..4c319b56
--- /dev/null
+++ b/setup/tools/imagecreatefromblp.php
@@ -0,0 +1,318 @@
+
+
+ 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 .
+*/
+ // 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;
+ }
+?>