* fix names (still use original string for title cards, just not internals and files)
 * link manually created icons (holidays, classes, races) to icon db
 * use newly linked icons instead of hardcoded values for classes/races
 * implement used-by-classes filter on icons listing
 * fix internal name of race 5 (undead) which fucked up icons
 * version bump to invalidate cache
This commit is contained in:
Sarjuuk 2025-12-04 14:44:45 +01:00
parent d6d589caba
commit 1e1ce29438
19 changed files with 180 additions and 27 deletions

View file

@ -106,6 +106,13 @@ class ClassBaseResponse extends TemplateResponse implements ICache
// id
$infobox[] = Lang::chrClass('id') . $this->typeId;
// icon
if ($_ = $this->subject->getField('iconId'))
{
$infobox[] = Util::ucFirst(Lang::game('icon')).Lang::main('colon').'[icondb='.$_.' name=true]';
$this->extendGlobalIds(Type::ICON, $_);
}
// original name
if (Lang::getLocale() != Locale::EN)
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
@ -119,7 +126,6 @@ class ClassBaseResponse extends TemplateResponse implements ICache
/****************/
$this->expansion = Util::$expansionString[$this->subject->getField('expansion')];
$this->headIcons = ['class_'.$cl->json()];
$this->redButtons = array(
BUTTON_LINKS => ['type' => $this->type, 'typeId' => $this->typeId],
BUTTON_WOWHEAD => true,
@ -127,6 +133,9 @@ class ClassBaseResponse extends TemplateResponse implements ICache
BUTTON_FORUM => false // todo (low): Cfg::get('BOARD_URL') + X
);
if ($_ = $this->subject->getField('iconString'))
$this->headIcons[] = $_;
/**************/
/* Extra Tabs */

View file

@ -95,6 +95,13 @@ class EventBaseResponse extends TemplateResponse implements ICache
if ($_holidayId && User::isInGroup(U_GROUP_STAFF))
$infobox[] = 'Holiday ID'.Lang::main('colon').$_holidayId;
// icon
if ($_ = $this->subject->getField('iconId'))
{
$infobox[] = Util::ucFirst(Lang::game('icon')).Lang::main('colon').'[icondb='.$_.' name=true]';
$this->extendGlobalIds(Type::ICON, $_);
}
// original name
if (Lang::getLocale() != Locale::EN)
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';

View file

@ -39,7 +39,7 @@ class IconBaseResponse extends TemplateResponse implements ICache
$this->extendGlobalData($this->subject->getJSGlobals());
$this->h1 = $this->subject->getField('name');
$this->h1 = $this->subject->getField('name_source');
$this->icon = $this->subject->getField('name', true, true);
$this->gPageInfo += array(

View file

@ -102,6 +102,26 @@ class RaceBaseResponse extends TemplateResponse implements ICache
// id
$infobox[] = Lang::race('id') . $this->typeId;
// icon
$mIcon = $this->subject->getField('iconId0');
$fIcon = $this->subject->getField('iconId1');
if ($mIcon || $fIcon)
{
$buff = '';
if ($mIcon)
{
$buff .= '[icondb='.$mIcon.(!$fIcon ? ' name=true': '').']';
$this->extendGlobalIds(Type::ICON, $mIcon);
}
if ($fIcon)
{
$buff .= '[icondb='.$fIcon.' name=true]';
$this->extendGlobalIds(Type::ICON, $fIcon);
}
$infobox[] = Util::ucFirst(Lang::game('icon')).Lang::main('colon').$buff;
}
// original name
if (Lang::getLocale() != Locale::EN)
$infobox[] = Util::ucFirst(Lang::lang(Locale::EN->value) . Lang::main('colon')) . '[copy button=false]'.$this->subject->getField('name_loc0').'[/copy][/li]';
@ -120,8 +140,10 @@ class RaceBaseResponse extends TemplateResponse implements ICache
BUTTON_LINKS => ['type' => $this->type, 'typeId' => $this->typeId]
);
if ($_ = $ra->json())
$this->headIcons = ['race_'.$_.'_male', 'race_'.$_.'_female'];
if ($_ = $this->subject->getField('iconStringMale'))
$this->headIcons[] = $_;
if ($_ = $this->subject->getField('iconStringFemale'))
$this->headIcons[] = $_;
/**************/

View file

@ -12,7 +12,11 @@ class CharClassList extends DBTypeList
public static string $brickFile = 'class';
public static string $dataTable = '?_classes';
protected string $queryBase = 'SELECT c.*, id AS ARRAY_KEY FROM ?_classes c';
protected string $queryBase = 'SELECT c.*, c.`id` AS ARRAY_KEY FROM ?_classes c';
protected array $queryOpts = array(
'c' => [['ic']],
'ic' => ['j' => ['?_icons ic ON ic.`id` = c.`iconId`', true], 's' => ', ic.`name` AS "iconString"']
);
public function __construct($conditions = [], array $miscData = [])
{

View file

@ -12,7 +12,12 @@ class CharRaceList extends DBTypeList
public static string $brickFile = 'race';
public static string $dataTable = '?_races';
protected string $queryBase = 'SELECT r.*, id AS ARRAY_KEY FROM ?_races r';
protected string $queryBase = 'SELECT r.*, r.`id` AS ARRAY_KEY FROM ?_races r';
protected array $queryOpts = array(
'r' => [['ic0', 'ic1']],
'ic0' => ['j' => ['?_icons ic0 ON ic0.`id` = r.`iconId0`', true], 's' => ', ic0.`name` AS "iconStringMale"'],
'ic1' => ['j' => ['?_icons ic1 ON ic1.`id` = r.`iconId1`', true], 's' => ', ic1.`name` AS "iconStringFemale"']
);
public function getListviewData() : array
{

View file

@ -66,7 +66,7 @@ class IconList extends DBTypeList
{
$data[$this->id] = array(
'id' => $this->id,
'name' => $this->getField('name', true, true),
'name' => $this->getField('name_source', true, true),
'icon' => $this->getField('name', true, true),
'itemcount' => (int)$this->getField('nItems'),
'spellcount' => (int)$this->getField('nSpells'),
@ -113,7 +113,7 @@ class IconListFilter extends Filter
// 8 => '', // garrisonbuildings [num]
9 => '?_pet', // hunterpets [num]
// 10 => '', // garrisonmissionthreats [num]
11 => '', // classes [num]
11 => '?_classes', // classes [num]
13 => '' // used [num]
);
@ -124,7 +124,7 @@ class IconListFilter extends Filter
3 => [parent::CR_CALLBACK, 'cbUsedBy' ], // achievements [num]
6 => [parent::CR_CALLBACK, 'cbUsedBy' ], // currencies [num]
9 => [parent::CR_CALLBACK, 'cbUsedBy' ], // hunterpets [num]
11 => [parent::CR_NYI_PH, null, 0 ], // classes [num]
11 => [parent::CR_CALLBACK, 'cbUsedBy' ], // classes [num]
13 => [parent::CR_CALLBACK, 'cbUsedBy', true] // used [num]
);

View file

@ -12,10 +12,11 @@ class WorldEventList extends DBTypeList
public static string $brickFile = 'event';
public static string $dataTable = '?_events';
protected string $queryBase = 'SELECT e.`holidayId`, e.`cuFlags`, e.`startTime`, e.`endTime`, e.`occurence`, e.`length`, e.`requires`, e.`description` AS "nameINT", e.`id` AS "eventId", e.`id` AS "ARRAY_KEY", h.* FROM ?_events e';
protected string $queryBase = 'SELECT e.`holidayId`, e.`cuFlags`, e.`startTime`, e.`endTime`, e.`occurence`, e.`length`, e.`requires`, e.`description` AS "nameINT", e.`id` AS "eventId", e.`id` AS ARRAY_KEY FROM ?_events e';
protected array $queryOpts = array(
'e' => [['h']],
'h' => ['j' => ['?_holidays h ON e.`holidayId` = h.`id`', true], 'o' => '-e.`id` ASC']
'e' => [['h', 'ic']],
'h' => ['j' => ['?_holidays h ON e.`holidayId` = h.`id`', true], 's' => ', h.*', 'o' => '-e.`id` ASC'],
'ic' => ['j' => ['?_icons ic ON ic.`id` = h.`iconId`', true], 's' => ', ic.`name` AS "iconString"']
);
public function __construct(array $conditions = [], array $miscData = [])

View file

@ -86,7 +86,7 @@ enum ChrRace : int
self::ORC => 'orc',
self::DWARF => 'dwarf',
self::NIGHTELF => 'nightelf',
self::UNDEAD => 'undead',
self::UNDEAD => 'scourge',
self::TAUREN => 'tauren',
self::GNOME => 'gnome',
self::TROLL => 'troll',

View file

@ -6,7 +6,7 @@ mb_internal_encoding('UTF-8');
error_reporting(E_ALL);
mysqli_report(MYSQLI_REPORT_ERROR);
define('AOWOW_REVISION', 43);
define('AOWOW_REVISION', 44);
define('OS_WIN', substr(PHP_OS, 0, 3) == 'WIN'); // OS_WIN as per compile info of php
define('CLI', PHP_SAPI === 'cli');
define('CLI_HAS_E', CLI && // WIN10 and later usually support ANSI escape sequences

View file

@ -404,6 +404,7 @@ DROP TABLE IF EXISTS `aowow_classes`;
CREATE TABLE `aowow_classes` (
`id` int(11) NOT NULL,
`fileString` varchar(128) DEFAULT NULL,
`iconId` smallint(5) unsigned NOT NULL DEFAULT 0,
`name_loc0` varchar(128) DEFAULT NULL,
`name_loc2` varchar(128) DEFAULT NULL,
`name_loc3` varchar(128) DEFAULT NULL,
@ -994,7 +995,7 @@ CREATE TABLE `aowow_holidays` (
`looping` tinyint(4) NOT NULL,
`scheduleType` tinyint(4) NOT NULL,
`textureString` varchar(30) NOT NULL DEFAULT '',
`iconString` varchar(51) NOT NULL DEFAULT '0',
`iconId` smallint(5) unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;
@ -2269,6 +2270,8 @@ CREATE TABLE `aowow_races` (
`baseLanguage` tinyint(3) unsigned NOT NULL,
`side` tinyint(3) unsigned NOT NULL,
`fileString` varchar(64) DEFAULT NULL,
`iconId0` smallint(5) unsigned NOT NULL DEFAULT 0 COMMENT 'male icon',
`iconId1` smallint(5) unsigned NOT NULL DEFAULT 0 COMMENT 'female icon',
`name_loc0` varchar(64) DEFAULT NULL,
`name_loc2` varchar(64) DEFAULT NULL,
`name_loc3` varchar(64) DEFAULT NULL,

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,7 @@
ALTER TABLE aowow_icons
ADD COLUMN `name_source` varchar(55) NOT NULL AFTER `name`;
UPDATE `aowow_dbversion` SET
`sql` = CONCAT(IFNULL(`sql`, ''), ' icons races classes holidays'),
`build` = CONCAT(IFNULL(`build`, ''), ' simpleimg')
;

View file

@ -0,0 +1,19 @@
-- drop obsolete custom data for holiday icons
DELETE FROM aowow_setup_custom_data WHERE `command` = 'holidays' AND `field` = 'iconString';
UPDATE aowow_holidays SET `iconString` = '';
-- support calendar_* icons
ALTER TABLE aowow_holidays
CHANGE COLUMN `iconString` `iconId` smallint(5) unsigned NOT NULL DEFAULT 0
;
-- support class_* icons
ALTER TABLE aowow_classes
ADD COLUMN `iconId` smallint(5) unsigned NOT NULL DEFAULT 0 AFTER `fileString`
;
-- support race_* icons
ALTER TABLE aowow_races
ADD COLUMN `iconId0` smallint(5) unsigned NOT NULL DEFAULT 0 COMMENT "male icon" AFTER `fileString`,
ADD COLUMN `iconId1` smallint(5) unsigned NOT NULL DEFAULT 0 COMMENT "female icon" AFTER `iconId0`
;

View file

@ -220,7 +220,7 @@ CLISetup::registerSetup("build", new class extends SetupScript
foreach ($row as $x => $name)
{
$j++;
$outFile = CLI::nicePath(($isIcon ? strtolower($name) : $name).'.'.$ext, $dest);
$outFile = CLI::nicePath(($isIcon ? $this->fixIconName($name) : $name).'.'.$ext, $dest);
$this->status = ' - '.str_pad($j.'/'.$nFiles, 12).str_pad('('.number_format($j * 100 / $nFiles, 2).'%)', 9);
@ -293,7 +293,7 @@ CLISetup::registerSetup("build", new class extends SetupScript
{
$j++;
$this->status = ' - '.str_pad($j.'/'.$nFiles, 12).str_pad('('.number_format($j * 100 / $nFiles, 2).'%)', 9);
$outFile = CLI::nicePath(($isIcon ? strtolower($img) : $img).'.'.$ext, $dest);
$outFile = CLI::nicePath(($isIcon ? $this->fixIconName($img) : $img).'.'.$ext, $dest);
if (!CLISetup::getOpt('force') && file_exists($outFile))
{
@ -381,6 +381,11 @@ CLISetup::registerSetup("build", new class extends SetupScript
return $this->success;
}
private function fixIconName(string $name) : string
{
return preg_replace('/[^a-z0-9_-]/', '-', strtolower($name));
}
});
?>

View file

@ -17,6 +17,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
'classes' => [[], CLISetup::ARGV_PARAM, 'Compiles data for type: PlayerClass from dbc.']
);
protected $setupAfter = [['icons'], []];
protected $dbcSourceFiles = ['spell', 'charbaseinfo', 'skillraceclassinfo', 'skilllineability', 'chrclasses'];
public function generate(array $ids = []) : bool
@ -34,6 +35,11 @@ CLISetup::registerSetup("sql", new class extends SetupScript
foreach ($skills as $classId => $skillStr)
$classes[$classId]['skills'] = $skillStr;
// collect iconIds
$iconIds = DB::Aowow()->selectCol('SELECT `id`, `name` AS ARRAY_KEY FROM ?_icons WHERE `name` IN (?a)', array_filter(array_map(fn($x) => 'class_'.strtolower($x['fileString']), $classes)));
foreach ($classes AS $id => $class)
$classes[$id]['iconId'] = $iconIds['class_'.strtolower($class['fileString'])] ?? 0;
// add weaponTypeMask & armorTypeMask
foreach ($classes as $id => &$data)
{

View file

@ -14,23 +14,41 @@ CLISetup::registerSetup("sql", new class extends SetupScript
{
use TrCustomData; // import custom data from DB
private const /* array */ CUSTOM_ICONS = array(
62 => 'calendar_fireworksstart', // has no texture in dbc but exists as blp
283 => 'inv_jewelry_necklace_21',
284 => 'inv_misc_rune_07',
285 => 'inv_jewelry_amulet_07',
353 => 'spell_nature_eyeofthestorm',
400 => 'achievement_bg_winsoa',
420 => 'achievement_bg_winwsg'
);
protected $info = array(
'holidays' => [[], CLISetup::ARGV_PARAM, 'Compiles supplemental data for type: Event from dbc.']
);
protected $setupAfter = [['icons'], []];
protected $dbcSourceFiles = ['holidays', 'holidaydescriptions', 'holidaynames'];
public function generate(array $ids = []) : bool
{
DB::Aowow()->query('TRUNCATE ?_holidays');
DB::Aowow()->query(
'INSERT INTO ?_holidays (id, name_loc0, name_loc2, name_loc3, name_loc4, name_loc6, name_loc8, description_loc0, description_loc2, description_loc3, description_loc4, description_loc6, description_loc8, looping, scheduleType, textureString)
SELECT h.id, n.name_loc0, n.name_loc2, n.name_loc3, n.name_loc4, n.name_loc6, n.name_loc8, d.description_loc0, d.description_loc2, d.description_loc3, d.description_loc4, d.description_loc6, d.description_loc8, h.looping, h.scheduleType, h.textureString
'INSERT INTO ?_holidays (`id`, `name_loc0`, `name_loc2`, `name_loc3`, `name_loc4`, `name_loc6`, `name_loc8`, `description_loc0`, `description_loc2`, `description_loc3`, `description_loc4`, `description_loc6`, `description_loc8`, `looping`, `scheduleType`, `textureString`)
SELECT h.`id`, n.`name_loc0`, n.`name_loc2`, n.`name_loc3`, n.`name_loc4`, n.`name_loc6`, n.`name_loc8`, d.`description_loc0`, d.`description_loc2`, d.`description_loc3`, d.`description_loc4`, d.`description_loc6`, d.`description_loc8`, h.`looping`, h.`scheduleType`, h.`textureString`
FROM dbc_holidays h
LEFT JOIN dbc_holidaynames n ON n.id = h.nameId
LEFT JOIN dbc_holidaydescriptions d ON d.id = h.descriptionId'
LEFT JOIN dbc_holidaynames n ON n.`id` = h.`nameId`
LEFT JOIN dbc_holidaydescriptions d ON d.`id` = h.`descriptionId`'
);
// set derived icons
DB::Aowow()->query('UPDATE ?_holidays h, ?_icons i SET h.`iconId` = i.`id` WHERE i.`name` LIKE CONCAT(LOWER(h.`textureString`), "%") AND h.`textureString` <> ""');
// set custom icons
foreach (self::CUSTOM_ICONS as $hId => $iconString)
DB::Aowow()->query('UPDATE ?_holidays h SET h.`iconId` = (SELECT i.`id` FROM ?_icons i WHERE `name` = ?) WHERE `id` = ?d', $iconString, $hId);
return true;
}
});

View file

@ -11,6 +11,26 @@ if (!CLI)
CLISetup::registerSetup("sql", new class extends SetupScript
{
private const /* array */ HOLIDAY_ICONS = array(
'calendar_winterveilstart',
'calendar_noblegardenstart',
'calendar_childrensweekstart',
'calendar_fishingextravaganzastart',
'calendar_harvestfestivalstart',
'calendar_hallowsendstart',
'calendar_lunarfestivalstart',
'calendar_loveintheairstart',
'calendar_midsummerstart',
'calendar_brewfeststart',
'calendar_darkmoonfaireelwynnstart',
'calendar_darkmoonfairemulgorestart',
'calendar_darkmoonfaireterokkarstart',
'calendar_piratesdaystart',
'calendar_wotlklaunchstart',
'calendar_dayofthedeadstart',
'calendar_fireworksstart'
);
protected $info = array(
'icons' => [[], CLISetup::ARGV_PARAM, 'Compiles data for type: Icons from dbc.']
);
@ -22,14 +42,37 @@ CLISetup::registerSetup("sql", new class extends SetupScript
DB::Aowow()->query('TRUNCATE ?_icons');
DB::Aowow()->query('ALTER TABLE ?_icons AUTO_INCREMENT = 1');
DB::Aowow()->query(
'INSERT INTO ?_icons (`name`) SELECT x FROM
'INSERT INTO ?_icons (`name`, `name_source`) SELECT x, x FROM
(
(SELECT LOWER(SUBSTRING_INDEX(iconPath, "\\\\", -1)) AS x FROM dbc_spellicon WHERE iconPath LIKE "%icons%") UNION
(SELECT LOWER(inventoryIcon1) AS x FROM dbc_itemdisplayinfo WHERE inventoryIcon1 <> "") UNION
(SELECT LOWER(SUBSTRING_INDEX(iconString, "\\\\", -1)) AS x FROM dbc_creaturefamily WHERE iconString LIKE "%icons%")
(SELECT LOWER(SUBSTRING_INDEX(`iconPath`, "\\\\", -1)) AS x FROM dbc_spellicon WHERE `iconPath` LIKE "%icons%") UNION
(SELECT LOWER(`inventoryIcon1`) AS x FROM dbc_itemdisplayinfo WHERE `inventoryIcon1` <> "") UNION
(SELECT LOWER(SUBSTRING_INDEX(`iconString`, "\\\\", -1)) AS x FROM dbc_creaturefamily WHERE `iconString` LIKE "%icons%")
) y GROUP BY x'
);
// fix icons with fucked up names
if ($errChars = DB::Aowow()->selectCol('SELECT `id` AS ARRAY_KEY, `name` FROM ?_icons WHERE `name` REGEXP "[^a-z0-9_-]"'))
foreach (preg_replace('/[^a-z0-9_-]/', '-', $errChars) as $id => $fixedName)
DB::Aowow()->query('UPDATE ?_icons SET `name` = ? WHERE `id` = ?d', $fixedName, $id);
// invent class icons
foreach (ChrClass::cases() as $cl)
DB::Aowow()->query('INSERT INTO ?_icons (`name`, `name_source`) VALUES (?, ?)', 'class_'.$cl->json(), 'class_'.$cl->json());
// invent race icons
foreach (ChrRace::cases() as $ra)
{
if ($na = $ra->json()) // unused races have no json
{
DB::Aowow()->query('INSERT INTO ?_icons (`name`, `name_source`) VALUES (?, ?)', 'race_'.$na.'_male', 'race_'.$na.'_male');
DB::Aowow()->query('INSERT INTO ?_icons (`name`, `name_source`) VALUES (?, ?)', 'race_'.$na.'_female', 'race_'.$na.'_female');
}
}
// halucinate holidays
foreach (self::HOLIDAY_ICONS as $h)
DB::Aowow()->query('INSERT INTO ?_icons (`name`, `name_source`) VALUES (?, ?)', $h, $h);
$this->reapplyCCFlags('icons', Type::ICON);
return true;

View file

@ -17,6 +17,7 @@ CLISetup::registerSetup("sql", new class extends SetupScript
'races' => [[], CLISetup::ARGV_PARAM, 'Compiles data for type: PlayerRace from dbc.']
);
protected $setupAfter = [['icons'], []];
protected $dbcSourceFiles = ['chrraces', 'charbaseinfo'];
public function generate(array $ids = []) : bool
@ -24,10 +25,13 @@ CLISetup::registerSetup("sql", new class extends SetupScript
DB::Aowow()->query('TRUNCATE ?_races');
DB::Aowow()->query(
'INSERT INTO ?_races
SELECT `id`, 0, `flags`, 0, `factionId`, 0, 0, `baseLanguage`, IF(`side` = 2, 0, `side` + 1), `fileString`, `name_loc0`, `name_loc2`, `name_loc3`, `name_loc4`, `name_loc6`, `name_loc8`, `expansion`
SELECT `id`, 0, `flags`, 0, `factionId`, 0, 0, `baseLanguage`, IF(`side` = 2, 0, `side` + 1), `fileString`, 0, 0, `name_loc0`, `name_loc2`, `name_loc3`, `name_loc4`, `name_loc6`, `name_loc8`, `expansion`
FROM dbc_chrraces'
);
// collect iconIds
DB::Aowow()->query('UPDATE ?_races r, ?_icons i0, ?_icons i1 SET r.iconId0 = i0.id, r.iconId1 = i1.id WHERE i0.name = CONCAT("race_", LOWER(r.fileString), "_male") AND i1.name = CONCAT("race_", LOWER(r.fileString), "_female")');
// add classMask
DB::Aowow()->query('UPDATE ?_races r JOIN (SELECT BIT_OR(1 << (`classId` - 1)) AS "classMask", `raceId` FROM dbc_charbaseinfo GROUP BY `raceId`) cbi ON cbi.`raceId` = r.id SET r.`classMask` = cbi.`classMask`');