From 615c203c7a89176b5da977a87bd680e57162f6e7 Mon Sep 17 00:00:00 2001 From: Sarjuuk Date: Fri, 21 Jun 2024 15:40:29 +0200 Subject: [PATCH] Setup/img-maps * script cleanup * fixed subzone generation and made color less garish * fixed alphamap generation and alphamapcheck not pointing to the same path * fixed padding UtilityScript args with unexpected var types --- .gitignore | 4 +- includes/game.php | 2 +- localization/locale_dede.php | 1 + localization/locale_enus.php | 1 + localization/locale_eses.php | 1 + localization/locale_frfr.php | 1 + localization/locale_ruru.php | 1 + localization/locale_zhcn.php | 3 +- setup/tools/CLISetup.class.php | 2 +- setup/tools/dbc.class.php | 2 +- setup/tools/filegen/img-maps.ss.php | 461 ++++++++-------------------- 11 files changed, 139 insertions(+), 340 deletions(-) diff --git a/.gitignore b/.gitignore index 92491133..d4c2da01 100644 --- a/.gitignore +++ b/.gitignore @@ -3,8 +3,8 @@ # cache /cache/template/* -/setup/generated/alphaMaps/*.png -/cache/firstrun +/cache/alphaMaps/* +/cache/setup/* # extract from MPQ /setup/mpqdata/* diff --git a/includes/game.php b/includes/game.php index 2754a88f..58b4ef43 100644 --- a/includes/game.php +++ b/includes/game.php @@ -244,7 +244,7 @@ class Game private static function alphaMapCheck(int $areaId, array &$set) : bool { - $file = 'setup/generated/alphaMaps/'.$areaId.'.png'; + $file = 'cache/alphaMaps/'.$areaId.'.png'; if (!file_exists($file)) // file does not exist (probably instanced area) return false; diff --git a/localization/locale_dede.php b/localization/locale_dede.php index cbb8bc7f..c9804703 100644 --- a/localization/locale_dede.php +++ b/localization/locale_dede.php @@ -1151,6 +1151,7 @@ $lang = array( 'Miscellaneous' => "Diverse", 'Azeroth' => "Azeroth", 'CosmicMap' => "Kosmische Karte", + 'floorN' => "%d. Stockwerk" ), 'privileges' => array( 'main' => "Auf unserer Seite könnt Ihr Ruf erringen. Hauptsächlich erringt man Ruf dadurch, dass Eure Kommentare positiv bewertet werden.

Das heißt, Euer Ruf hängt in gewissem Maße davon ab, wie sehr Ihr der Community beiträgt.

Mit dem Sammeln von Ruf verdient Ihr Euch auch das Vertrauen der Gemeinschaft ein, und Ihr erhält Privilegien. Unten könnt Ihr eine vollständige Liste einsehen.", diff --git a/localization/locale_enus.php b/localization/locale_enus.php index 832188af..02bbac72 100644 --- a/localization/locale_enus.php +++ b/localization/locale_enus.php @@ -1152,6 +1152,7 @@ $lang = array( 'Miscellaneous' => "Miscellaneous", 'Azeroth' => "Azeroth", 'CosmicMap' => "Cosmic Map", + 'floorN' => "Level %d" ), 'privileges' => array( 'main' => "Here on our Site you can generate reputation. The main way to generate it is to get your comments upvotes.

So, reputation is a rough measure of how much you contributed to the community.

As you amass reputation you earn the community's trust and you will be granted with additional privileges. You can find a full list below.", diff --git a/localization/locale_eses.php b/localization/locale_eses.php index b09e3133..f3beb028 100644 --- a/localization/locale_eses.php +++ b/localization/locale_eses.php @@ -1151,6 +1151,7 @@ $lang = array( 'Miscellaneous' => "Miscelánea", 'Azeroth' => "Azeroth", 'CosmicMap' => "Mapa cósmico", + 'floorN' => "Nivel %d" ), 'privileges' => array( 'main' => "Aquí, en AoWoW, puedes conseguir reputación. La forma principal de conseguirla es conseguir que tus comentarios sean votados de forma positiva.

Así pues, la reputación es algo que mide, más o menos, cúanto has contribuido a la comunidad.

Conforme consigues reputación, te ganas la confianza de la comunidad y tendrás privilegios adicionales. Puedes encontrar una lista completa debajo.", diff --git a/localization/locale_frfr.php b/localization/locale_frfr.php index d8061936..8e713580 100644 --- a/localization/locale_frfr.php +++ b/localization/locale_frfr.php @@ -1151,6 +1151,7 @@ $lang = array( 'Miscellaneous' => "Divers", 'Azeroth' => "Azeroth", 'CosmicMap' => "Carte cosmique", + 'floorN' => "Plancher %d" ), 'privileges' => array( 'main' => "Sur AoWoW, vous pouvez accumuler de la réputation. Le principal moyen d'en accumuler est d'avoir un score élevé pour vos commentaires.

Ainsi, la réputation est une vision sommaire de vos contributions à la communauté.

En amassant de la réputation, vous gagnez le respect de la communauté et vous obtiendrez certains privilèges. Vous pouvez en trouver la liste complète ci-dessous.", diff --git a/localization/locale_ruru.php b/localization/locale_ruru.php index c76ad93c..f57fa81a 100644 --- a/localization/locale_ruru.php +++ b/localization/locale_ruru.php @@ -1151,6 +1151,7 @@ $lang = array( 'Miscellaneous' => "Разное", 'Azeroth' => "Азерот", 'CosmicMap' => "Звёздная карта", + 'floorN' => "Уровень %d" ), 'privileges' => array( 'main' => "Здесь на AoWoW вы можете зарабатывать репутацию. Основной источник получения репутации — увеличение рейтинга ваших комментариев другими пользователями.

Репутация примерно измеряет количество вашего вклада в сообщество.

По мере того, как вы зарабатываете репутацию, вы получаете доверие сообщества и особые привилегии. Полный список привилегий расположен ниже.", diff --git a/localization/locale_zhcn.php b/localization/locale_zhcn.php index 4d76f8ad..e2d7be4d 100644 --- a/localization/locale_zhcn.php +++ b/localization/locale_zhcn.php @@ -1150,7 +1150,8 @@ $lang = array( 'Battlegrounds' => "战场", 'Miscellaneous' => "其他", 'Azeroth' => "艾泽拉斯", - 'CosmicMap' => "宇宙地图" + 'CosmicMap' => "宇宙地图", + 'floorN' => "[Level %d]" ), 'privileges' => array( 'main' => "在我们的网站上,你可以通过 声望. 来获取特权。获取声望的主要途径是获得评论的赞同。

因此,声望是衡量你对社区的贡献程度的一个大致指标。

随着声望的积累,你将获得社区的信任,并被赋予额外的特权。以下是完整的特权列表。", diff --git a/setup/tools/CLISetup.class.php b/setup/tools/CLISetup.class.php index 7a5daad5..929ab315 100644 --- a/setup/tools/CLISetup.class.php +++ b/setup/tools/CLISetup.class.php @@ -341,7 +341,7 @@ class CLISetup return false; } - $args = array_pad($args, 4, []); + $args = array_pad($args, 4, null); $success = $us->run($args); diff --git a/setup/tools/dbc.class.php b/setup/tools/dbc.class.php index 16a47fc0..c2d74290 100644 --- a/setup/tools/dbc.class.php +++ b/setup/tools/dbc.class.php @@ -483,7 +483,7 @@ class DBC $this->writeToDB(); - $this->endCLean(); + $this->endClean(); return true; } diff --git a/setup/tools/filegen/img-maps.ss.php b/setup/tools/filegen/img-maps.ss.php index 4e05757c..66034f46 100644 --- a/setup/tools/filegen/img-maps.ss.php +++ b/setup/tools/filegen/img-maps.ss.php @@ -34,7 +34,7 @@ CLISetup::registerSetup("build", new class extends SetupScript private const A_THRESHOLD = 95; // alpha threshold to define subZones: set it too low and you have unspawnable areas inside a zone; set it too high and the border regions overlap private const COLOR_WHITE = [255, 255, 255]; // rgb private const COLOR_BLACK = [ 0, 0, 0]; // rgb - private const COLOR_SUBZONE = [255, 64, 192, 64]; // rgba + private const COLOR_SUBZONE = [ 0, 230, 255, 74]; // rgba - note: rgb is 0-255, a is 0-127 private const AREA_FLAG_DEFAULT_FLOOR_TERRAIN = 0x004; // Default Dungeon Floor is Terrain private const AREA_FLAG_NO_DEFAULT_FLOOR = 0x100; // Don't use Default Dungeon Floor (typically 1) @@ -54,22 +54,13 @@ CLISetup::registerSetup("build", new class extends SetupScript [9, 10, 11, 12] ); - private const LEVEL_N = array( // todo: move this hackfix to locales? - LOCALE_EN => 'Level %d', - LOCALE_FR => 'Plancher %d', - LOCALE_DE => '%d. Stockwerk', - LOCALE_CN => '[Level %d]', - LOCALE_ES => 'Nivel %d', - LOCALE_RU => 'Уровень %d' - ); - private const MAP_FILE_PATTERN = '/((\w{4})\/interface\/worldmap(?:\/microdungeon\/([^\/]+))?\/([^\/]+)\/)(\4)(?:(\d{1,2})_)?(\d{1,2})\.(?:blp|png)/i'; // src, resourcePath, localized, [tileOrder], [[dest, destW, destH]] private $genSteps = array( - self::M_MAPS => ['WorldMap/', null, true, self::TILEORDER, self::DEST_DIRS ], - self::M_SPAWNS => ['WorldMap/', null, true, self::TILEORDER, [['cache/setup/alphaMaps/', 0, 0]]], - self::M_SUBZONES => ['WorldMap/', null, true, self::TILEORDER, self::DEST_DIRS ] + self::M_MAPS => ['WorldMap/', null, true, self::TILEORDER, self::DEST_DIRS ], + self::M_SPAWNS => ['WorldMap/', null, true, self::TILEORDER, [['cache/alphaMaps/', 0, 0]]], + self::M_SUBZONES => ['WorldMap/', null, true, self::TILEORDER, self::DEST_DIRS ] ); private $progress = 0; @@ -114,8 +105,8 @@ CLISetup::registerSetup("build", new class extends SetupScript $mask |= self::M_MAPS; // unless manually prompted drop spawnmap generation if 90% of spawns have core generated area info - $npcPct = DB::World()->selectCell('SELECT SUM(IF(zoneId > 0, 1, 0)) / COUNT(*) FROM creature') ?? 0; - $goPct = DB::World()->selectCell('SELECT SUM(IF(zoneId > 0, 1, 0)) / COUNT(*) FROM gameobject') ?? 0; + $npcPct = DB::World()->selectCell('SELECT SUM(IF(`zoneId` > 0, 1, 0)) / COUNT(*) FROM creature') ?? 0; + $goPct = DB::World()->selectCell('SELECT SUM(IF(`zoneId` > 0, 1, 0)) / COUNT(*) FROM gameobject') ?? 0; if (!($mask & self::M_SPAWNS) && $npcPct > 0.9 && $goPct > 0.9) $this->modeMask &= ~self::M_SPAWNS; @@ -132,7 +123,7 @@ CLISetup::registerSetup("build", new class extends SetupScript if (!$this->checkSourceDirs()) { - CLI::write('one or more source directories are missing:', CLI::LOG_ERROR); + CLI::write('[img-maps] One or more source directories are missing.', CLI::LOG_ERROR); $this->success = false; return false; } @@ -190,15 +181,15 @@ CLISetup::registerSetup("build", new class extends SetupScript { ksort($floorData); - $overlay = null; + $resOverlay = null; if (!$isMultilevel) - $overlay = $this->generateOverlay($wmaId, $name, $basePath); + $resOverlay = $this->generateOverlay($wmaId, $name, $basePath); // create spawn-maps if wanted - if ($overlay && $this->modeMask & self::M_SPAWNS) + if ($resOverlay && $this->modeMask & self::M_SPAWNS) { $outFile = $this->genSteps[self::M_SPAWNS][self::$GEN_IDX_DEST_INFO][0][0] . $zoneId . '.png'; - if (!$this->generateSpawnMap($overlay, $outFile)) + if (!$this->buildSpawnMap($resOverlay, $outFile)) $this->success = false; } @@ -293,84 +284,16 @@ CLISetup::registerSetup("build", new class extends SetupScript continue; } - $overlay = null; + $resOverlay = null; // zone has overlays (is in open world; is not multilevel) if (isset($this->wmOverlays[$wmaId])) { - $overlay = $this->createAlphaImage(self::MAP_W, self::MAP_H); - - foreach ($this->wmOverlays[$wmaId] as &$row) - { - $i = 1; - $y = 0; - while ($y < $row['h']) - { - $x = 0; - while ($x < $row['w']) - { - $img = $this->loadImageFile($srcPath . '/' . $row['textureString'] . $i); - if (!$img) - { - CLI::write(' - complexImg: tile '.$srcPath.'/'.$row['textureString'].$i.'.blp missing.', CLI::LOG_ERROR); - break 2; - } - - imagecopy($overlay, $img, $row['x'] + $x, $row['y'] + $y, 0, 0, imagesx($img), imagesy($img)); - - // prepare subzone image - if ($this->modeMask & self::M_SUBZONES) - { - if (!isset($row['maskimage'])) - { - $row['maskimage'] = $this->createAlphaImage($row['w'], $row['h']); - $row['maskcolor'] = imagecolorallocatealpha($row['maskimage'], ...self::COLOR_SUBZONE); - } - - for ($my = 0; $my < imagesy($img); $my++) - for ($mx = 0; $mx < imagesx($img); $mx++) - if ((imagecolorat($img, $mx, $my) >> 24) < self::A_THRESHOLD) - imagesetpixel($row['maskimage'], $x + $mx, $y + $my, $row['maskcolor']); - } - - imagedestroy($img); - - $x += 256; - $i++; - } - $y += 256; - } - } + $resOverlay = $this->generateOverlay($wmaId, $srcPath); // create spawn-maps if wanted if ($this->modeMask & self::M_SPAWNS) - { - $outFile = $this->genSteps[self::M_SPAWNS][self::$GEN_IDX_DEST_INFO][0][0] . $zoneId . '.png'; - - if (CLISetup::getOpt('force') || !file_exists($outFile)) - { - $tmp = imagecreate(self::SPAWNMAP_WH, self::SPAWNMAP_WH); - $cbg = imagecolorallocate($tmp, ...self::COLOR_WHITE); - $cfg = imagecolorallocate($tmp, ...self::COLOR_BLACK); - - for ($y = 0; $y < self::SPAWNMAP_WH; $y++) - { - for ($x = 0; $x < self::SPAWNMAP_WH; $x++) - { - $a = imagecolorat($overlay, ($x * self::MAP_W) / self::SPAWNMAP_WH, ($y * self::MAP_H) / self::SPAWNMAP_WH) >> 24; - imagesetpixel($tmp, $x, $y, $a < self::A_THRESHOLD ? $cfg : $cbg); - } - } - - imagecolordeallocate($tmp, $cbg); - imagecolordeallocate($tmp, $cfg); - - if (!$this->writeImageFile($tmp, $outFile, self::SPAWNMAP_WH, self::SPAWNMAP_WH)) - $this->success = false; - } - else - CLI::write($this->status.' - file '.$outFile.' was already processed', CLI::LOG_BLANK, true, true); - } + $this->buildSpawnMap($resOverlay, $zoneId); } if (!($this->modeMask & self::M_MAPS)) @@ -385,7 +308,7 @@ CLISetup::registerSetup("build", new class extends SetupScript if ($zoneId == 4494) $floors[] = 2; - $map = null; + $resMap = null; foreach ($floors as $floorIdx) { ini_set('max_execution_time', $this->maxExecTime); @@ -430,18 +353,18 @@ CLISetup::registerSetup("build", new class extends SetupScript if ($doSkip == 0xF) continue; - $map = $this->assembleImage($file, self::TILEORDER, self::MAP_W, self::MAP_H); - if (!$map) + $resMap = $this->assembleImage($file, self::TILEORDER, self::MAP_W, self::MAP_H); + if (!$resMap) { CLI::write(' - could not create image resource for zone '.$zoneId.($nFloors ? ' floor '.$floorIdx : ''), CLI::LOG_ERROR); $this->success = false; continue; } - if ($overlay && !$floorIdx) + if ($resOverlay && !$floorIdx) { - imagecopymerge($map, $overlay, 0, 0, 0, 0, imagesx($overlay), imagesy($overlay), 100); - imagedestroy($overlay); + imagecopymerge($resMap, $resOverlay, 0, 0, 0, 0, imagesx($resOverlay), imagesy($resOverlay), 100); + imagedestroy($resOverlay); } // create map @@ -452,52 +375,18 @@ CLISetup::registerSetup("build", new class extends SetupScript if ($doSkip & (1 << $sizeIdx)) continue; - if (!$this->writeImageFile($map, $outFile[$sizeIdx], $width ?: self::MAP_W, $height ?: self::MAP_H)) + if (!$this->writeImageFile($resMap, $outFile[$sizeIdx], $width ?: self::MAP_W, $height ?: self::MAP_H)) $this->success = false; } } } // also create subzone-maps - if ($map && isset($this->wmOverlays[$wmaId]) && $this->modeMask & self::M_SUBZONES) - { - foreach ($this->wmOverlays[$wmaId] as &$row) - { - $doSkip = 0x0; - $outFile = []; + if ($resMap && isset($this->wmOverlays[$wmaId]) && $this->modeMask & self::M_SUBZONES) + $this->buildSubZones($resMap, $wmaId, $l); - foreach (self::DEST_DIRS as $sizeIdx => [$path, , ]) - { - $outFile[$sizeIdx] = sprintf($path, strtolower(Util::$localeStrings[$l]).'/') . $row['areaTableId'].'.jpg'; - if (!CLISetup::getOpt('force') && file_exists($outFile[$sizeIdx])) - { - CLI::write($this->status.' - file '.$outFile[$sizeIdx].' was already processed', CLI::LOG_BLANK, true, true); - $doSkip |= (1 << $sizeIdx); - } - } - - if ($doSkip == 0xF) - continue; - - $subZone = imagecreatetruecolor(self::MAP_W, self::MAP_H); - 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 (self::DEST_DIRS as $sizeIdx => [, $width, $height]) - { - if ($doSkip & (1 << $sizeIdx)) - continue; - - if (!$this->writeImageFile($subZone, $outFile[$sizeIdx], $width ?: self::MAP_W, $height ?: self::MAP_H)) - $this->success = false; - } - - imagedestroy($subZone); - } - } - - if ($map) - imagedestroy($map); + if ($resMap) + imagedestroy($resMap); // this takes a while; ping mysql just in case DB::Aowow()->selectCell('SELECT 1'); @@ -512,7 +401,7 @@ CLISetup::registerSetup("build", new class extends SetupScript $this->dmFloorData = DB::Aowow()->select('SELECT IF(`mapId` IN (?a), -`worldMapAreaId`, `mapId`) AS ARRAY_KEY, GROUP_CONCAT(DISTINCT `floor` SEPARATOR " ") AS "0", COUNT(DISTINCT `floor`) AS "1" FROM dbc_dungeonmap WHERE `worldMapAreaId` <> 0 GROUP BY ARRAY_KEY', self::CONTINENTS); if (!$this->wmOverlays || !$this->wmAreas || !$this->dmFloorData) { - CLI::write(' - could not read required dbc files: WorldMapArea.dbc ['.count($this->wmAreas ?: []).' entries]; WorldMapOverlay.dbc ['.count($this->wmOverlays ?: []).'] entries; DungeonMap.dbc ['.count($this->dmFloorData ?: []).' entries]', CLI::LOG_ERROR); + CLI::write('[img-maps] - could not read required dbc files: WorldMapArea.dbc ['.count($this->wmAreas ?: []).' entries]; WorldMapOverlay.dbc ['.count($this->wmOverlays ?: []).'] entries; DungeonMap.dbc ['.count($this->dmFloorData ?: []).' entries]', CLI::LOG_ERROR); $this->success = false; return false; } @@ -616,7 +505,7 @@ CLISetup::registerSetup("build", new class extends SetupScript $sumAreas = count($this->wmAreas); $sumMaps = count(CLISetup::$localeIds) * ($sumAreas + $sumFloors); - CLI::write('Processing '.$sumAreas.' zone maps and '.$sumFloors.' dungeon maps from Interface/WorldMap/ for locale: '.Lang::concat(array_intersect_key(Util::$localeStrings, array_flip(CLISetup::$localeIds)))); + CLI::write('[img-maps] Processing '.$sumAreas.' zone maps and '.$sumFloors.' dungeon maps from Interface/WorldMap/ for locale: '.Lang::concat(array_intersect_key(Util::$localeStrings, array_flip(CLISetup::$localeIds)))); foreach (CLISetup::$localeIds as $l) { @@ -630,13 +519,16 @@ CLISetup::registerSetup("build", new class extends SetupScript $mapSrcDir = $this->genSteps[self::M_MAPS][1][$l] ?? ''; if (!$mapSrcDir) { + CLI::write('[img-maps] - No suitable localized map files found for locale ['.$l.': '.Util::$localeStrings[$l].'].', CLI::LOG_ERROR); $this->success = false; - CLI::write(' - no suitable localized map files found for locale '.$l, CLI::LOG_ERROR); continue; } foreach ($this->wmAreas as $areaEntry) { + $resOverlay = null; + $resMap = null; + $wmaId = $areaEntry['id']; $zoneId = $areaEntry['areaId']; $mapId = $areaEntry['mapId']; @@ -672,109 +564,40 @@ CLISetup::registerSetup("build", new class extends SetupScript $srcPath = $mapSrcDir.'/'.$textureStr; if (!CLISetup::fileExists($srcPath)) { + CLI::write('[img-maps] - WorldMap file path '.$srcPath.' missing for selected locale '.Util::$localeStrings[$l], CLI::LOG_ERROR); $this->success = false; - CLI::write('worldmap file path '.$srcPath.' missing for selected locale '.Util::$localeStrings[$l], CLI::LOG_ERROR); continue; } - $overlay = null; + $srcPath .= '/'; // zone has overlays (is in open world; is not multilevel) if (isset($this->wmOverlays[$wmaId]) && ($this->modeMask & (self::M_MAPS | self::M_SPAWNS | self::M_SUBZONES))) { - $overlay = $this->createAlphaImage(self::MAP_W, self::MAP_H); - - foreach ($this->wmOverlays[$wmaId] as &$row) - { - $i = 1; - $y = 0; - while ($y < $row['h']) - { - $x = 0; - while ($x < $row['w']) - { - $img = $this->loadImageFile($srcPath . '/' . $row['textureString'] . $i); - if (!$img) - { - CLI::write(' - complexImg: tile '.$srcPath.'/'.$row['textureString'].$i.'.blp missing.', CLI::LOG_ERROR); - break 2; - } - - imagecopy($overlay, $img, $row['x'] + $x, $row['y'] + $y, 0, 0, imagesx($img), imagesy($img)); - - // prepare subzone image - if ($this->modeMask & self::M_SUBZONES) - { - if (!isset($row['maskimage'])) - { - $row['maskimage'] = $this->createAlphaImage($row['w'], $row['h']); - $row['maskcolor'] = imagecolorallocatealpha($row['maskimage'], ...self::COLOR_SUBZONE); - } - - for ($my = 0; $my < imagesy($img); $my++) - for ($mx = 0; $mx < imagesx($img); $mx++) - if ((imagecolorat($img, $mx, $my) >> 24) < self::A_THRESHOLD) - imagesetpixel($row['maskimage'], $x + $mx, $y + $my, $row['maskcolor']); - } - - imagedestroy($img); - - $x += 256; - $i++; - } - $y += 256; - } - } + $resOverlay = $this->generateOverlay($wmaId, $srcPath); // create spawn-maps if wanted - if ($this->modeMask & self::M_SPAWNS) - { - $outFile = $this->genSteps[self::M_SPAWNS][self::$GEN_IDX_DEST_INFO][0][0] . $zoneId . '.png'; - - if (CLISetup::getOpt('force') || !file_exists($outFile)) - { - $tmp = imagecreate(self::SPAWNMAP_WH, self::SPAWNMAP_WH); - $cbg = imagecolorallocate($tmp, ...self::COLOR_WHITE); - $cfg = imagecolorallocate($tmp, ...self::COLOR_BLACK); - - for ($y = 0; $y < self::SPAWNMAP_WH; $y++) - { - for ($x = 0; $x < self::SPAWNMAP_WH; $x++) - { - $a = imagecolorat($overlay, ($x * self::MAP_W) / self::SPAWNMAP_WH, ($y * self::MAP_H) / self::SPAWNMAP_WH) >> 24; - imagesetpixel($tmp, $x, $y, $a < self::A_THRESHOLD ? $cfg : $cbg); - } - } - - imagecolordeallocate($tmp, $cbg); - imagecolordeallocate($tmp, $cfg); - - if (!$this->writeImageFile($tmp, $outFile, self::SPAWNMAP_WH, self::SPAWNMAP_WH)) - $this->success = false; - } - else - CLI::write($this->status.' - file '.$outFile.' was already processed', CLI::LOG_BLANK, true, true); - } + if ($resOverlay && ($this->modeMask & self::M_SPAWNS)) + $this->buildSpawnMap($resOverlay, $zoneId); } // check if we can create base map anyway - $png = $srcPath.'/'.$textureStr.'1.png'; - $blp = $srcPath.'/'.$textureStr.'1.blp'; + $png = $srcPath.$textureStr.'1.png'; + $blp = $srcPath.$textureStr.'1.blp'; $hasBaseMap = CLISetup::fileExists($blp) || CLISetup::fileExists($png); - $map = null; foreach ($dmFloors as $srcFloorIdx => $outFloorIdx) { ini_set('max_execution_time', $this->maxExecTime); $doSkip = 0x0; $outPaths = []; - $srcFile = $srcPath.'/'.$textureStr; + $srcFile = $srcPath.$textureStr; $outFile = $zoneId; if (!$srcFloorIdx && !$hasBaseMap) { - CLI::Write('[img-maps] zone has no base floor, but it is referenced with base floor in dmFloors? Smells like an error. areaId: '.$zoneId, CLI::LOG_WARN); + CLI::write('[img-maps] - Zone has no base floor, but is referenced with base floor in dmFloors.', CLI::LOG_WARN); continue; } @@ -802,21 +625,22 @@ CLISetup::registerSetup("build", new class extends SetupScript } } - if ($doSkip == 0xF) + // can't skip map creation if we are to generate subzones later. although they may already exist and get skipped anyway *shrug* + if ($doSkip == 0xF && !($this->modeMask & self::M_SUBZONES)) continue; - $map = $this->assembleImage($srcFile, self::TILEORDER, self::MAP_W, self::MAP_H); - if (!$map) + $resMap = $this->assembleImage($srcFile, self::TILEORDER, self::MAP_W, self::MAP_H); + if (!$resMap) { - CLI::write(' - could not create image resource for zone '.$zoneId.($nFloors ? ' floor '.$srcFloorIdx : '')); + CLI::write('[img-maps] - Could not create image resource for '.($nFloors ? 'floor '.$srcFloorIdx : 'base level'), CLI::LOG_ERROR); $this->success = false; continue; } - if ($overlay && !$nFloors) + if ($resOverlay && !$nFloors) { - imagecopymerge($map, $overlay, 0, 0, 0, 0, imagesx($overlay), imagesy($overlay), 100); - imagedestroy($overlay); + imagecopymerge($resMap, $resOverlay, 0, 0, 0, 0, imagesx($resOverlay), imagesy($resOverlay), 100); + imagedestroy($resOverlay); } // create map @@ -827,52 +651,18 @@ CLISetup::registerSetup("build", new class extends SetupScript if ($doSkip & (1 << $sizeIdx)) continue; - if (!$this->writeImageFile($map, $outPaths[$sizeIdx], $width ?: self::MAP_W, $height ?: self::MAP_H)) + if (!$this->writeImageFile($resMap, $outPaths[$sizeIdx], $width ?: self::MAP_W, $height ?: self::MAP_H)) $this->success = false; } } } // also create subzone-maps - if ($map && isset($this->wmOverlays[$wmaId]) && $this->modeMask & self::M_SUBZONES) - { - foreach ($this->wmOverlays[$wmaId] as &$row) - { - $doSkip = 0x0; - $outFiles = []; + if ($resMap && isset($this->wmOverlays[$wmaId]) && $this->modeMask & self::M_SUBZONES) + $this->buildSubZones($resMap, $wmaId, $l); - foreach (self::DEST_DIRS as $sizeIdx => [$path, , ]) - { - $outFile[$sizeIdx] = sprintf($path, strtolower(Util::$localeStrings[$l]).'/') . $row['areaTableId'].'.jpg'; - if (!CLISetup::getOpt('force') && file_exists($outFiles[$sizeIdx])) - { - CLI::write($this->status.' - file '.$outFiles[$sizeIdx].' was already processed', CLI::LOG_BLANK, true, true); - $doSkip |= (1 << $sizeIdx); - } - } - - if ($doSkip == 0xF) - continue; - - $subZone = imagecreatetruecolor(self::MAP_W, self::MAP_H); - 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 (self::DEST_DIRS as $sizeIdx => [, $width, $height]) - { - if ($doSkip & (1 << $sizeIdx)) - continue; - - if (!$this->writeImageFile($subZone, $outFiles[$sizeIdx], $width ?: self::MAP_W, $height ?: self::MAP_H)) - $this->success = false; - } - - imagedestroy($subZone); - } - } - - if ($map) - imagedestroy($map); + if ($resMap) + imagedestroy($resMap); // this takes a while; ping mysql just in case DB::Aowow()->selectCell('SELECT 1'); @@ -880,7 +670,7 @@ CLISetup::registerSetup("build", new class extends SetupScript } } - private function buildZonesFile() : bool + private function buildZonesFile() : void { $areaNames = array_combine( array_column($this->wmAreas, 'areaId'), @@ -910,14 +700,16 @@ CLISetup::registerSetup("build", new class extends SetupScript $zoneAreas[$lId][$zId][$floor] = $nameLOC; } else - CLI::write('[img-maps] internal zone name from GlobalStrings.lua not found in WorldMapArea.dbc ['.$nameINT.']', CLI::LOG_WARN); + CLI::write('[img-maps] ['.$nameINT.'] from GlobalStrings.lua not found in WorldMapArea.dbc', CLI::LOG_WARN); } foreach (CLISetup::$locales as $lId => $loc) { + Lang::load($lId); + // "custom" - show second level of Ahn'Kahet not shown but present in-game if (isset($zoneAreas[$lId][4494])) - $zoneAreas[$lId][4494][2] = sprintf(self::LEVEL_N[$lId], 2); + $zoneAreas[$lId][4494][2] = Lang::maps('floorN', [2]); foreach ($zoneAreas[$lId] as $zoneId => $floorData) { @@ -927,7 +719,7 @@ CLISetup::registerSetup("build", new class extends SetupScript continue; // todo: just note for now, try to compensate later? - CLI::write('[img-maps] floor count mismatch for zone #'.$zoneId.' GlobalStrings: '.$nStrings.' image files: '.$nFloors, CLI::LOG_WARN); + CLI::write('[img-maps] ['.$loc.'] '.str_pad('['.$zoneId.']', 7).'floor count mismatch between GlobalStrings: '.$nStrings.' and image files: '.$nFloors, CLI::LOG_WARN); } ksort($zoneAreas[$lId]); @@ -942,75 +734,24 @@ CLISetup::registerSetup("build", new class extends SetupScript if (!CLISetup::writeFile($file, $toFile)) $this->success = false; } - - return $this->success; } - private function generateOverlay(int $wmaId, string $name, string $basePath) // : ?GdImage - { - if (!isset($this->wmOverlays[$wmaId])) - return null; - - $overlay = $this->createAlphaImage(self::MAP_W, self::MAP_H); - - foreach ($this->wmOverlays[$wmaId] as &$this->wmOverlays) - { - $i = 1; - $y = 0; - while ($y < $this->wmOverlays['h']) - { - $x = 0; - while ($x < $this->wmOverlays['w']) - { - $img = $this->loadImageFile($basePath . $name . $i); - if (!$img) - { - CLI::write(' - complexImg: tile '.$basePath.$name.$i.'.blp missing.', CLI::LOG_ERROR); - break 2; - } - - imagecopy($overlay, $img, $this->wmOverlays['x'] + $x, $this->wmOverlays['y'] + $y, 0, 0, imagesx($img), imagesy($img)); - - // prepare subzone image - if ($this->modeMask & self::M_SUBZONES) - { - if (!isset($this->wmOverlays['maskimage'])) - { - $this->wmOverlays['maskimage'] = $this->createAlphaImage($this->wmOverlays['w'], $this->wmOverlays['h']); - $this->wmOverlays['maskcolor'] = imagecolorallocatealpha($this->wmOverlays['maskimage'], ...self::COLOR_SUBZONE); - } - - for ($my = 0; $my < imagesy($img); $my++) - for ($mx = 0; $mx < imagesx($img); $mx++) - if ((imagecolorat($img, $mx, $my) >> 24) < self::A_THRESHOLD) - imagesetpixel($this->wmOverlays['maskimage'], $x + $mx, $y + $my, $this->wmOverlays['maskcolor']); - } - - imagedestroy($img); - - $x += 256; - $i++; - } - $y += 256; - } - } - - return $overlay; - } - - private function generateSpawnMap(/*GdImage*/ $overlay, string $outFile) : bool + private function buildSpawnMap(/*GdImage*/ $resOverlay, int $zoneId) : void { // GdImage: < 8.0 resource; >= 8.0 object - if (gettype($overlay) != 'resource' && gettype($overlay) != 'object') + if (gettype($resOverlay) != 'resource' && gettype($resOverlay) != 'object') { - CLI::write('[img-maps] no GdImage passed to generateSpawnMap', CLI::LOG_ERROR); - return false; + CLI::write('[img-maps] - no GdImage passed to buildSpawnMap', CLI::LOG_ERROR); + $this->success = false; + return; } + $outFile = $this->genSteps[self::M_SPAWNS][self::$GEN_IDX_DEST_INFO][0][0] . $zoneId . '.png'; + if (!CLISetup::getOpt('force') && file_exists($outFile)) { CLI::write($this->status.' - file '.$outFile.' was already processed', CLI::LOG_BLANK, true, true); - return true; + return; } $tmp = imagecreate(self::SPAWNMAP_WH, self::SPAWNMAP_WH); @@ -1021,7 +762,7 @@ CLISetup::registerSetup("build", new class extends SetupScript { for ($x = 0; $x < self::SPAWNMAP_WH; $x++) { - $a = imagecolorat($overlay, ($x * self::MAP_W) / self::SPAWNMAP_WH, ($y * self::MAP_H) / self::SPAWNMAP_WH) >> 24; + $a = imagecolorat($resOverlay, ($x * self::MAP_W) / self::SPAWNMAP_WH, ($y * self::MAP_H) / self::SPAWNMAP_WH) >> 24; imagesetpixel($tmp, $x, $y, $a < self::A_THRESHOLD ? $cfg : $cbg); } } @@ -1029,16 +770,18 @@ CLISetup::registerSetup("build", new class extends SetupScript imagecolordeallocate($tmp, $cbg); imagecolordeallocate($tmp, $cfg); - return $this->writeImageFile($tmp, $outFile, self::SPAWNMAP_WH, self::SPAWNMAP_WH); + if (!$this->writeImageFile($tmp, $outFile, self::SPAWNMAP_WH, self::SPAWNMAP_WH)) + $this->success = false; } - private function generateSubZones(/*GdImage*/ $map, int $wmaId, int $locId) : bool + private function buildSubZones(/*GdImage*/ $resMap, int $wmaId, int $locId) : void { // GdImage: < 8.0 resource; >= 8.0 object - if (gettype($map) != 'resource' && gettype($map) != 'object') + if (gettype($resMap) != 'resource' && gettype($resMap) != 'object') { - CLI::write('[img-maps] no GdImage passed to generateSubZones', CLI::LOG_ERROR); - return false; + CLI::write('[img-maps] - no GdImage passed to buildSubZones()', CLI::LOG_ERROR); + $this->success = false; + return; } foreach ($this->wmOverlays[$wmaId] as &$row) @@ -1060,7 +803,7 @@ CLISetup::registerSetup("build", new class extends SetupScript continue; $subZone = imagecreatetruecolor(self::MAP_W, self::MAP_H); - imagecopy($subZone, $map, 0, 0, 0, 0, imagesx($map), imagesy($map)); + imagecopy($subZone, $resMap, 0, 0, 0, 0, imagesx($resMap), imagesy($resMap)); imagecopy($subZone, $row['maskimage'], $row['x'], $row['y'], 0, 0, imagesx($row['maskimage']), imagesy($row['maskimage'])); foreach (self::DEST_DIRS as $sizeIdx => [, $width, $height]) @@ -1074,8 +817,58 @@ CLISetup::registerSetup("build", new class extends SetupScript imagedestroy($subZone); } + } - return true; + private function generateOverlay(int $wmaId, string $basePath) // : ?GdImage + { + if (!isset($this->wmOverlays[$wmaId])) + return null; + + $resOverlay = $this->createAlphaImage(self::MAP_W, self::MAP_H); + + foreach ($this->wmOverlays[$wmaId] as &$row) + { + $i = 1; + $y = 0; + while ($y < $row['h']) + { + $x = 0; + while ($x < $row['w']) + { + $img = $this->loadImageFile($basePath . $row['textureString'] . $i); + if (!$img) + { + CLI::write('[img-maps] - overlay tile ' . $basePath . $row['textureString'] . $i . '.blp missing.', CLI::LOG_ERROR); + break 2; + } + + imagecopy($resOverlay, $img, $row['x'] + $x, $row['y'] + $y, 0, 0, imagesx($img), imagesy($img)); + + // prepare subzone image + if ($this->modeMask & self::M_SUBZONES) + { + if (!isset($row['maskimage'])) + { + $row['maskimage'] = $this->createAlphaImage($row['w'], $row['h']); + $row['maskcolor'] = imagecolorallocatealpha($row['maskimage'], ...self::COLOR_SUBZONE); + } + + for ($my = 0; $my < imagesy($img); $my++) + for ($mx = 0; $mx < imagesx($img); $mx++) + if ((imagecolorat($img, $mx, $my) >> 24) < self::A_THRESHOLD) + imagesetpixel($row['maskimage'], $x + $mx, $y + $my, $row['maskcolor']); + } + + imagedestroy($img); + + $x += 256; + $i++; + } + $y += 256; + } + } + + return $resOverlay; } });