mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
Core/Setup
* rewritten to be able to dynamicly load it's components
- CLISetup -> checks for UtilityScripts (config, setup, dbc reader, etc.) -> checks for SetupScripts (individual sql/file generators)
- each step may now have a help prompt attached. If none are provided, the containing script may provide it's help.
- all Scripts are self contained modules. No more editing of 3+ files if some component is added/removed
* removed intermediaries FileGen & SqlGen
* functional changes
- allow providing CLI arguments to siteconfig and account UtilityScript and skip the interactive prompts
- set slot for consumable enchantment items so they are filtrable
- zones dataset is now localized and generated from GlobalStrings.lua and DungeonMap.dbc. Related data dumps removed.
- 'aowow' and 'prQueue' executables now have shebangs
WARNING - command line options have been renamed!
This commit is contained in:
14
aowow
14
aowow
@@ -1,12 +1,12 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
require 'includes/kernel.php';
|
||||
|
||||
if (!CLI)
|
||||
if (PHP_SAPI !== 'cli')
|
||||
die("this script must be run from CLI\n");
|
||||
if (CLI && getcwd().DIRECTORY_SEPARATOR.'aowow' != __FILE__)
|
||||
die("this script must be run from root directory\n");
|
||||
else
|
||||
require 'setup/setup.php';
|
||||
if (PHP_SAPI === 'cli' && getcwd().DIRECTORY_SEPARATOR.'aowow' != __FILE__)
|
||||
die("this script must be run from the aowow root directory\n");
|
||||
|
||||
require 'includes/kernel.php';
|
||||
require 'setup/setup.php';
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
Mapper.multiLevelZones = {
|
||||
206: ['206-1', '206-2', '206-3'],
|
||||
209: ['209-1', '209-2', '209-3', '209-4', '209-5', '209-6', '209-7'],
|
||||
616: ['616-1', '616_1', '616_2'],
|
||||
719: ['719-1', '719-2', '719-3'],
|
||||
721: ['721-1', '721-2', '721-3', '721-4'],
|
||||
796: ['796-1', '796-2', '796-3', '796-4'],
|
||||
1196: ['1196-1', '1196-2'],
|
||||
1337: ['1337-1', '1337-2'],
|
||||
1581: ['1581-1', '1581-2'],
|
||||
1583: ['1583-1', '1583-2', '1583-3', '1583-4', '1583-5', '1583-6', '1583-7'],
|
||||
1584: ['1584-1', '1584-2'],
|
||||
2017: ['2017-1', '2017-2'],
|
||||
2057: ['2057-1', '2057-2', '2057-3', '2057-4'],
|
||||
2100: ['2100-1', '2100-2'],
|
||||
2557: ['2557-1', '2557-2', '2557-3', '2557-4', '2557-5', '2557-6'],
|
||||
2677: ['2677-1', '2677-2', '2677-3', '2677-4'],
|
||||
3959: ['3959', '3959-1', '3959-2', '3959-3', '3959-4', '3959-5', '3959-6', '3959-7'],
|
||||
3428: ['3428-1', '3428-2', '3428-3'],
|
||||
3456: ['3456-1', '3456-2', '3456-3', '3456-4', '3456-5', '3456-6'],
|
||||
3457: ['3457-1', '3457-2', '3457-3', '3457-4', '3457-5', '3457-6', '3457-7', '3457-8', '3457-9', '3457-10', '3457-11', '3457-12', '3457-13', '3457-14', '3457-15', '3457-16', '3457-17'],
|
||||
3477: ['3477-1', '3477-2', '3477-3'],
|
||||
3715: ['3715-1', '3715-2'],
|
||||
3790: ['3790-1', '3790-2'],
|
||||
3791: ['3791-1', '3791-2'],
|
||||
3848: ['3848-1', '3848-2', '3848-3'],
|
||||
3849: ['3849-1', '3849-2'],
|
||||
4075: ['4075', '4075-1'],
|
||||
4100: ['4100-1', '4100-2'],
|
||||
4131: ['4131-1', '4131-2'],
|
||||
4196: ['4196-1', '4196-2'],
|
||||
4228: ['4228-1', '4228-2', '4228-3', '4228-4'],
|
||||
4272: ['4272-1', '4272-2'],
|
||||
4273: ['4273-0', '4273-1', '4273-2', '4273-3', '4273-4', '4273-5'],
|
||||
4277: ['4277-1', '4277-2', '4277-3'],
|
||||
4395: ['4395-1', '4395-2'],
|
||||
4494: ['4494-1', '4494-2'],
|
||||
4714: ['4714-1', '4714_1', '4714_2', '4714_3'],
|
||||
4722: ['4722-1', '4722-2'],
|
||||
4812: ['4812-1', '4812-2', '4812-3', '4812-4', '4812-5', '4812-6', '4812-7', '4812-8'],
|
||||
};
|
||||
|
||||
/*
|
||||
var g_zone_areas = {};
|
||||
in locale files
|
||||
*/
|
||||
@@ -81,7 +81,6 @@ class AjaxData extends AjaxHandler
|
||||
break;
|
||||
// locale independant
|
||||
case 'quick-excludes':
|
||||
case 'zones':
|
||||
case 'weight-presets':
|
||||
case 'item-scaling':
|
||||
case 'realms':
|
||||
@@ -102,6 +101,7 @@ class AjaxData extends AjaxHandler
|
||||
case 'enchants':
|
||||
case 'itemsets':
|
||||
case 'pets':
|
||||
case 'zones':
|
||||
if (!Util::loadStaticFile($set, $result, true) && Cfg::get('DEBUG'))
|
||||
$result .= "alert('could not fetch static data: ".$set." for locale: ".User::$localeString."');";
|
||||
|
||||
|
||||
@@ -671,7 +671,7 @@ trait spawnHelper
|
||||
$floors = [];
|
||||
foreach ($points as $p)
|
||||
{
|
||||
if (isset(Game::$areaFloors[$p['areaId']]))
|
||||
if ($p['floor'])
|
||||
$floors[$p['areaId']][] = $p['floor'];
|
||||
|
||||
if (isset($menu[$p['areaId']]))
|
||||
|
||||
@@ -140,13 +140,6 @@ class Game
|
||||
null, 4, 10, 9, 8, 6, 15, 11, 3, 5, null, 7
|
||||
);
|
||||
|
||||
public static $areaFloors = array(
|
||||
206 => 3, 209 => 7, 719 => 3, 721 => 4, 796 => 4, 1196 => 2, 1337 => 2, 1581 => 2, 1583 => 7, 1584 => 2,
|
||||
2017 => 2, 2057 => 4, 2100 => 2, 2557 => 6, 2677 => 4, 3428 => 3, 3457 => 17, 3790 => 2, 3791 => 2, 3959 => 8,
|
||||
3456 => 6, 3715 => 2, 3848 => 3, 3849 => 2, 4075 => 2, 4100 => 2, 4131 => 2, 4196 => 2, 4228 => 4, 4272 => 2,
|
||||
4273 => 6, 4277 => 3, 4395 => 2, 4494 => 2, 4722 => 2, 4812 => 8
|
||||
);
|
||||
|
||||
public static function sideByRaceMask($race)
|
||||
{
|
||||
// Any
|
||||
|
||||
@@ -1188,44 +1188,6 @@ $lang = array(
|
||||
'cat' => array(
|
||||
"Östliche Königreiche", "Kalimdor", "Dungeons", "Schlachtzüge", "Unbenutzt", null,
|
||||
"Schlachtfelder", null, "Scherbenwelt", "Arenen", "Nordend"
|
||||
),
|
||||
'floors' => array(
|
||||
206 => ["Vorbereitung der Norndir", "Aufstieg der Drachenschinder", "Tyrs Terrasse"],
|
||||
209 => ["Der Hof", "Speisesaal", "Die Verwaiste Höhle", "Das Tiefere Observatorium", "Das Obere Observatorium", "Lord Godfreys Kammer", "Der Wehrgang"],
|
||||
719 => ["Der Teich von Ask'Ar", "Mondschreinsanktum", "Der Vergessene Teich"],
|
||||
721 => ["Die Halle der Zahnräder", "Der Schlafsaal", "Startrampe", "Tüftlerhof"],
|
||||
796 => ["Friedhof", "Bibliothek", "Waffenkammer", "Kathedrale"],
|
||||
1196 => ["Untere Spitze", "Obere Spitze"],
|
||||
1337 => ["Halle der Bewahrer", "Khaz'goroths Sitz"],
|
||||
1581 => ["Die Todesminen", "Eiserne Bucht"],
|
||||
1583 => ["Tazz'Alaor", "Listspinnertunnel", "Hordemar", "Schwarzfausthalle", "Drachenspitzhalle", "Der Krähenhorst", "Schwarzfelsstadion"],
|
||||
1584 => ["Gefängnisblock", "Die Schattenschmiede"],
|
||||
2017 => ["Kreuzzüglerplatz", "Der Spießrutenlauf"],
|
||||
2057 => ["Das Reliquiarium", "Kammer der Beschwörung", "Das Arbeitszimmer des Direktors", "Familiengruft der Barovs"],
|
||||
2100 => ["Höhlen von Maraudon", "Zaetars Grab"],
|
||||
2557 => ["Gordokhallen", "Hauptstadtgärten", "Hof der Hochgeborenen", "Das Gefängnis von Immol'thar", "Wucherborkenviertel", "Der Schrein von Eldretharr"],
|
||||
2677 => ["Garnison des Drachenmals", "Hallen des Zwists", "Die Blutroten Labore", "Nefarians Unterschlupf"],
|
||||
3428 => ["Untergrund des Schwarmbaus", "Die Tempeltore", "Höhle von C'Thun"],
|
||||
3457 => ["Bedienstetenunterkünfte", "Obere Nobelställe", "Der Bankettsaal", "Die Gästezimmer", "Balkon des Opernsaals", "Die Terrasse des Meisters", "Untere Eingestürzte Treppe", "Obere Eingestürzte Treppe", "Die Menagerie", "Bibliothek des Wächters", "Das Warenlager", "Obere Bibliothek", "Die Himmelswacht", "Halle der Spiele", "Medivhs Gemächer", "Die Energiekammer", "Netherraum"],
|
||||
3790 => ["Hallen des Jenseits", "Brücke der Seelen"],
|
||||
3791 => ["Sethekkversteck", "Hallen der Trauer"],
|
||||
3959 => ["Ausbildungsgelände der Illidari", "Kanäle von Karabor", "Zuflucht der Schatten", "Hallen der Pein", "Blutschattens Wacht", "Hof der Irdischen Gelüste", "Kommandoraum", "Tempelspitze"],
|
||||
3456 => ["Das Konstruktviertel", "Das Arachnidenviertel", "Das Militärviertel", "Das Seuchenviertel", "Übersicht", "Frostwyrmhort"],
|
||||
3715 => ["Die Dampfkammer", "Die Kühlteiche"],
|
||||
3848 => ["Stasisblock: Trion", "Stasisblock: Maximus", "Eindämmungskern"],
|
||||
3849 => ["Die Mechanar", "Berechnungskammer"],
|
||||
4075 => ["Sonnenbrunnenplateau", "Schrein der Finsternis"],
|
||||
4100 => ["Außerhalb von Stratholme", "Stratholme"],
|
||||
4131 => ["Zuflucht des Großmagisters", "Beobachtungsplatz"],
|
||||
4196 => ["Die Vorhallen von Drak'Tharon", "Aussichtspunkt von Drak'Tharon"],
|
||||
4228 => ["Band der Varianz", "Band der Akzeleration", "Band der Transmutation", "Band der Angleichung"],
|
||||
4272 => ["Die unnachgiebige Garnison", "Straße der Schöpfer"],
|
||||
4273 => ["Der große Vorstoß", "Die Vorkammer von Ulduar", "Das innere Sanktum von Ulduar", "Das Gefängnis von Yogg-Saron", "Der Funke der Imagination", "Das Gedankenauge"],
|
||||
4277 => ["Die Brutgrube", "Hadronox' Hort", "Das vergoldete Tor"],
|
||||
4395 => ["Dalaran", "Die Schattenseite"],
|
||||
4494 => ["Ahn'kahet", "2. Stockwerk"],
|
||||
4722 => ["Kolosseum der Kreuzfahrer", "Die eisigen Tiefen"],
|
||||
4812 => ["Die untere Zitadelle", "Das Schädelbollwerk", "Dom des Todbringers", "Hort der Frostkönigin", "Der obere Bereich", "Königliche Quartiere", "Der Frostthron", "Frostgram"]
|
||||
)
|
||||
),
|
||||
'quest' => array(
|
||||
|
||||
@@ -1189,44 +1189,6 @@ $lang = array(
|
||||
'cat' => array(
|
||||
"Eastern Kingdoms", "Kalimdor", "Dungeons", "Raids", "Unused", null,
|
||||
"Battlegrounds", null, "Outland", "Arenas", "Northrend"
|
||||
),
|
||||
'floors' => array(
|
||||
206 => ["Norndir Preparation", "Dragonflayer Ascent", "Tyr's Terrace"],
|
||||
209 => ["The Courtyard", "Dining Hall", "The Vacant Den", "Lower Observatory", "Upper Observatory", "Lord Godfrey's Chamber", "The Wall Walk"],
|
||||
719 => ["The Pool of Ask'Ar", "Moonshrine Sanctum", "The Forgotten Pool"],
|
||||
721 => ["The Hall of Gears", "The Dormitory", "Launch Bay", "Tinkers' Court"],
|
||||
796 => ["Graveyard", "Library", "Armory", "Cathedral"],
|
||||
1196 => ["Lower Pinnacle", "Upper Pinnacle"],
|
||||
1337 => ["Hall of the Keepers", "Khaz'Goroth's Seat"],
|
||||
1581 => ["The Deadmines", "Ironclad Cove"],
|
||||
1583 => ["Tazz'Alaor", "Skitterweb Tunnels", "Hordemar City", "Hall of Blackhand", "Dragonspire Hall", "The Rookery", "Blackrock Stadium"],
|
||||
1584 => ["Detention Block", "Shadowforge City"],
|
||||
2017 => ["Crusader's Square", "The Gauntlet"],
|
||||
2057 => ["The Reliquary", "Chamber of Summoning", "The Headmaster's Study", "Barov Family Vault"],
|
||||
2100 => ["Caverns of Maraudon", "Zaetar's Grave"],
|
||||
2557 => ["Gordok Commons", "Capital Gardens", "Court of the Highborne", "Prison of Immol'Thar", "Warpwood Quarter", "The Shrine of Eldretharr"],
|
||||
2677 => ["Dragonmaw Garrison", "Halls of Strife", "Crimson Laboratories", "Nefarian's Lair"],
|
||||
3428 => ["The Hive Undergrounds", "The Temple Gates", "Vault of C'Thun"],
|
||||
3456 => ["The Construct Quarter", "The Arachnid Quarter", "The Military Quarter", "The Plague Quarter", "Overview", "Frostwyrm Lair"],
|
||||
3457 => ["Servant's Quarters", "Upper Livery Stables", "The Banquet Hall", "The Guest Chambers", "Opera Hall Balcony", "Master's Terrace", "Lower Broken Stair", "Upper Broken Stair", "The Menagerie", "Guardian's Library", "The Repository", "Upper Library", "The Celestial Watch", "Gamesman's Hall", "Medivh's Chambers", "The Power Station", "Netherspace"],
|
||||
3715 => ["The Steamvault", "The Cooling Pools"],
|
||||
3790 => ["Halls of the Hereafter", "Bridge of Souls"],
|
||||
3791 => ["Veil Sethekk", "Halls of Mourning"],
|
||||
3848 => ["Stasis Block: Trion", "Stasis Block: Maximus", "Containment Core"],
|
||||
3849 => ["The Mechanar", "Calculation Chamber"],
|
||||
3959 => ["Illidari Training Grounds", "Karabor Sewers", "Sanctuary of Shadows", "Halls of Anguish", "Gorefiend's Vigil", "Den of Mortal Delights", "Chamber of Command", "Temple Summit"],
|
||||
4075 => ["Sunwell Plateau", "Shrine of the Eclipse"],
|
||||
4100 => ["Outside Stratholme", "Stratholme City"],
|
||||
4131 => ["Grand Magister's Asylum", "Observation Grounds"],
|
||||
4196 => ["The Vestibules of Drak'Tharon", "Drak'Tharon Overlook"],
|
||||
4228 => ["Band of Variance", "Band of Acceleration", "Band of Transmutation", "Band of Alignment"],
|
||||
4272 => ["Unyielding Garrison", "Walk of the Makers"],
|
||||
4273 => ["The Grand Approach", "The Antechamber of Ulduar", "The Inner Sanctum of Ulduar", "The Prison of Yogg-Saron", "The Spark of Imagination", "The Mind's Eye"],
|
||||
4277 => ["The Brood Pit", "Hadronox's Lair", "The Gilded Gate"],
|
||||
4395 => ["Dalaran City", "The Underbelly"],
|
||||
4494 => ["Ahn'Kahet", "Level 2"],
|
||||
4722 => ["Crusaders' Coliseum", "The Icy Depths"],
|
||||
4812 => ["The Lower Citadel", "The Rampart of Skulls", "Deathbringer's Rise", "The Frost Queen's Lair", "The Upper Reaches", "Royal Quarters", "The Frozen Throne", "Frostmourne"]
|
||||
)
|
||||
),
|
||||
'quest' => array(
|
||||
|
||||
@@ -1188,44 +1188,6 @@ $lang = array(
|
||||
'cat' => array(
|
||||
"Reinos del Este", "Kalimdor", "Mazmorras", "Bandas", "No las uso", null,
|
||||
"Campos de batalla", null, "Terrallende", "Arenas", "Rasganorte"
|
||||
),
|
||||
'floors' => array(
|
||||
206 => ["Preparación Norndir", "Ascenso de los Desuelladragones", "Bancal de Tyr"],
|
||||
209 => ["El Patio", "Comedor", "El Cubil Vacío", "Observatorio inferior", "Observatorio superior", "Cámara de Lord Godfrey", "El Camino de la Muralla"],
|
||||
719 => ["La Alberca de Ask'ar", "Sagrario Lunar", "Las Charcas del Olvido"],
|
||||
721 => ["La Sala de Máquinas", "Los Dormitorios", "Aeropuerto", "Cámara Manitas"],
|
||||
796 => ["[Cementerio]", "[Biblioteca]", "[Armería]", "[Catedral]"],
|
||||
1196 => ["Pináculo inferior", "Pináculo superior"],
|
||||
1337 => ["Sala de los Guardianes", "Trono de Khaz'goroth"],
|
||||
1581 => ["Las Minas de la Muerte", "Cala del Acorazado"],
|
||||
1583 => ["Tazz'Alaor", "Túneles de Arácnidas", "Ciudad Hordemar", "Sala de Puño Negro", "Sala Dracopico", "El Grajero", "Estadio de Roca Negra"],
|
||||
1584 => ["Bloque de Detención", "Ciudad Forjatiniebla"],
|
||||
2017 => ["Plaza de los Cruzados", "El Guantelete"],
|
||||
2057 => ["El Relicario", "Cámara de la Invocación", "Sala Rectoral", "[Barov Family Vault]"],
|
||||
2100 => ["Cavernas de Maraudon", "Tumba de Zaetar"],
|
||||
2557 => ["Ágora de Gordok", "Jardines de la Capital", "Corte de los Altonato", "Prisión de Immol'thar", "Barrio Alabeo", "Santuario de Eldretharr"],
|
||||
2677 => ["Cuartel Faucedraco", "Salas de los Conflictos", "Laboratorios Carmesí", "Guarida de Nefarian"],
|
||||
3428 => ["El Subterráneo de la Colmena", "Las Puertas del Templo", "Cámara de C'Thun"],
|
||||
3456 => ["El arrabal de los ensamblajes", "El arrabal arácnido", "El arrabal militar", "El arrabal de la peste", "La Necrópolis inferior", "La Necrópolis superior"],
|
||||
3457 => ["Alcobas de los Sirvientes", "Caballerizas superiores", "La Sala de Banquetes", "Los Aposentos de los Invitados", "Balcón de la Sala de la Ópera", "El Bancal del Maestro", "La Escalera Quebrada inferior", "La Escalera Quebrada superior", "La Sala de las Fieras", "Biblioteca del Guardián", "El Repositorio", "La Biblioteca superior", "El Mirador Celestial", "Sala del Tablero", "Estancias de Medivh", "La Central Eléctrica", "Espacio Abisal"],
|
||||
3715 => ["La Cámara de Vapor", "Las Charcas Refrescantes"],
|
||||
3790 => ["Salas del Más Allá", "Puente de las Almas"],
|
||||
3791 => ["Velo Sethekk", "Salas del Luto"],
|
||||
3848 => ["Bloque de Estasis: Trion", "Bloque de Estasis: Maximus", "Pabellón de Aislamiento"],
|
||||
3849 => ["El Mechanar", "Estancias de Calculación"],
|
||||
3959 => ["Campo de entrenamiento Illidari", "Cloacas de Karabor", "Santuario de las Sombras", "Salas de Angustia", "Vigilia de Sanguino", "Guarida de los Placeres Mortales", "Cámara de Mando", "Cima del Templo"],
|
||||
4075 => ["Meseta de La Fuente del Sol", "Santuario del Eclipse"],
|
||||
4100 => ["El Camino a Stratholme", "Stratholme"],
|
||||
4131 => ["Asilo del Gran Magister", "Sector de Observación"],
|
||||
4196 => ["El vestíbulo de Drak'Tharon", "Centinela de Drak'Tharon"],
|
||||
4228 => ["Sortija de discrepancia", "Sortija de Aceleración", "Sortija de transmutación", "Sortija de alineación"],
|
||||
4272 => ["El Cuartel Implacable", "Camino de los Creadores"],
|
||||
4273 => ["El Gran Acceso", "La Antecámara de Ulduar", "El Sagrario Interior de Ulduar", "La Prisión de Yogg-Saron", "La Chispa de la Imaginación", "El Ojo de la Mente"],
|
||||
4277 => ["El Foso del Linaje", "Guarida de Hadronox", "La Puerta dorada"],
|
||||
4395 => ["Ciudad de Dalaran", "Los Bajos Fondos"],
|
||||
4494 => ["Ahn'kahet", "Nivel 2"],
|
||||
4722 => ["El Coliseo Argenta", "Las profundidades heladas"],
|
||||
4812 => ["La ciudadela inferior", "La Muralla de las Calaveras", "Ascenso del Libramorte", "La guarida de la Reina de Escarcha", "Los Confines superiores", "Cuarteles Reales", "El Trono Helado", "Agonía de Escarcha"]
|
||||
)
|
||||
),
|
||||
'quest' => array(
|
||||
|
||||
@@ -1188,44 +1188,6 @@ $lang = array(
|
||||
'cat' => array(
|
||||
"Royaumes de l'est", "Kalimdor", "Donjons", "Raids", "Inutilisées", null,
|
||||
"Champs de bataille", null, "Outreterre", "Arènes", "Norfendre"
|
||||
),
|
||||
'floors' => array(
|
||||
206 => ["Préparation de Norndir", "Ascension d'Écorche-dragon", "Terrasse de Tyr"],
|
||||
209 => ["La cour", "Salle à manger", "Antre Vacant", "Observatoire Inférieur", "Observatoire Supérieur", "Chambre du seigneur Godfrey", "Le chemin de ronde"],
|
||||
719 => ["Le Bassin d'Ask'ar", "Sanctuaire d’Écrin-de-Lune", "Les bassins Oubliés"],
|
||||
721 => ["Le Hall des engrenages", "Le dortoir", "Baie de lancement", "Cour du Bricoleur"],
|
||||
796 => ["[Cimetière]", "[Bibliothèque]", "[Armurerie]", "[Cathédrale]"],
|
||||
1196 => ["Pinnacle inférieur", "Pinacle Supérieur"],
|
||||
1337 => ["Hall des Gardiens", "Siège de Khaz'goroth"],
|
||||
1581 => ["Les Mortemines", "Crique du Cuirassé"],
|
||||
1583 => ["Tazz'Alaor", "Tunnels de Toile-grouillante", "Cité d'Hordemar", "Hall de Main-noire", "Hall de la Flèche des dragons", "La colonie", "Stade Rochenoire"],
|
||||
1584 => ["Le mitard", "Ville des Ombreforges"],
|
||||
2017 => ["Place des Croisés", "Le Défi"],
|
||||
2057 => ["Le Reliquaire", "Chambre d'invocation", "Bureau du proviseur", "[Barov Family Vault]"],
|
||||
2100 => ["Cavernes de Maraudon", "Tombe de Zaetar"],
|
||||
2557 => ["Communs gordok", "Grands jardins", "Cours des Bien-nés", "Prison d'Immol'Thar", "Quartier de Crochebois", "Le sanctuaire d'Eldretharr"],
|
||||
2677 => ["Garnison des Gueules-de-dragon", "Halls des conflits", "Laboratoires Cramoisis", "Antre de Nefarian"],
|
||||
3428 => ["Les souterrains de la ruche", "Portes du Temple", "Caveau de C'Thun"],
|
||||
3456 => ["Le quartier des Assemblages", "Le Quartier des Arachnide", "Le Quartier Militaire", "Le quartier de la Peste", "La Nécropole Inférieure", "La Nécropole Supérieure"],
|
||||
3457 => ["Quartiers des serviteurs", "Écuries supérieures", "La salle de banquet", "Les Appartements des hôtes", "Balcon de l’Opéra", "Terrasse du maître", "Partie inférieure de l’Escalier brisé", "Partie supérieure de l’Escalier brisé", "La Ménagerie", "Bibliothèque du Gardien", "Le Dépôt", "Bibliothèque supérieure", "Le Guet céleste", "Hall du Flambeur", "Appartements de Medivh", "Centrale électrique", "Néantespace"],
|
||||
3715 => ["Le caveau de la Vapeur", "Les bassins de refroidissement"],
|
||||
3790 => ["Les salles de l’Après-vie", "Le pont des âmes"],
|
||||
3791 => ["Voile Sethekk", "Les salles du Deuil"],
|
||||
3848 => ["Bloc de stase : Trion", "Bloc de stase : Maximus", "Cœur de confinement"],
|
||||
3849 => ["Le Méchanar", "Chambre des Calculs"],
|
||||
3959 => ["Terrain d'entraînement Illidari", "Égouts de Karabor", "Sanctuaire des ombres", "Les salles de l’Angoisse", "Veillée de Fielsang", "Tanière des délices mortels", "Chambre de commandement", "Sommet du temple"],
|
||||
4075 => ["Plateau du Puits de soleil", "Sanctuaire de l’eclipse"],
|
||||
4100 => ["La Route de Stratholme", "Stratholme"],
|
||||
4131 => ["Asile du grand magistère", "Terrain d’observation"],
|
||||
4196 => ["Le Vestibule de Drak'Tharon", "Surplombe de Drak'Tharon"],
|
||||
4228 => ["Bande d'Écart", "Bande d'Accélération", "Bande de Transmutation", "Bande d'Alignement"],
|
||||
4272 => ["La garnison inflexible", "Promenade des Faiseurs"],
|
||||
4273 => ["Le Grand abord", "L'antichambre d'Ulduar", "Le sanctum intérieur d'Ulduar", "La prison de Yogg-Saron", "L'Étincelle d'imagination", "La Vue de l'esprit"],
|
||||
4277 => ["La Fosse des couvées", "Antre d'Hadronox", "La Porte de la Daurade"],
|
||||
4395 => ["Dalaran", "Les Entrailles"],
|
||||
4494 => ["Ahn'kahet", "Plancher 2"],
|
||||
4722 => ["L'colisée d'Argent", "Les Profondeurs Glacées"],
|
||||
4812 => ["La Citadelle Inférieure", "Le Rempart des Cranes", "Ascension de Porte-mort", "Le repaire de la reine du Givre", "Les étages supérieurs", "Quartiers Royaux", "Le Trône Gelé", "Deuillegivre"]
|
||||
)
|
||||
),
|
||||
'quest' => array(
|
||||
|
||||
@@ -1188,44 +1188,6 @@ $lang = array(
|
||||
'cat' => array(
|
||||
"Восточные королевства", "Калимдор", "Подземелья", "Рейды", "Неактивно", null,
|
||||
"Поля боя", null, "Запределье", "Арены", "Нордскол"
|
||||
),
|
||||
'floors' => array(
|
||||
206 => ["Подготовка Норндира", "Подъем Укротителей драконов", "Терраса Тира"],
|
||||
209 => ["Внутренний двор", "Обеденный зал", "Свободная берлога", "Нижняя обсерватория", "Верхняя обсерватория", "Палата лорда Годфри", "Крепостной вал"],
|
||||
719 => ["Пруд Аск'ара", "Алтарь святилища Луны", "Забытый пруд"],
|
||||
721 => ["Машинный зал", "Спальни", "Пусковая установка", "Двор Механиков"],
|
||||
796 => ["[Кладбище]", "[Библиотека]", "[Арсенал]", "[Собор]"],
|
||||
1196 => ["Подножие", "Вершина"],
|
||||
1337 => ["Зал Хранителей", "Трон Каз'горота"],
|
||||
1581 => ["Мертвые копи", "Потайная бухта"],
|
||||
1583 => ["Тазз'Алаор", "Паучий лабиринт", "Ордамар", "Зал Чернорука", "Зал Драконов", "Гнездовье", "Стадион Черной горы"],
|
||||
1584 => ["Тюремный блок", "Тенегорн"],
|
||||
2017 => ["Площадь рыцарей", "Улица Испытаний"],
|
||||
2057 => ["Хранилище реликвий", "Чертог Призыва", "Кабинет ректора", "[Barov Family Vault]"],
|
||||
2100 => ["Пещеры Мародона", "Могила Зейтара"],
|
||||
2557 => ["Палаты Гордока", "Центральный сад", "Двор высокорожденных", "Тюрьма Бессмер'тера", "Квартал Криводревов", "Святилище Элдретарра"],
|
||||
2677 => ["Гарнизон Драконьей Пасти", "Залы Раздора", "Багровые лаборатории", "Логово Нефариана"],
|
||||
3428 => ["Подземелье улья", "Ворота храма", "Обитель К'Туна"],
|
||||
3456 => ["Квартал Мерзости", "Паучий квартал", "Военный квартал", "Чумной квартал", "Нижний некрополь", "Верхний некрополь"],
|
||||
3457 => ["Комнаты cлуг", "Cтойла", "Пиршественный зал", "Гостевые комнаты", "Балкон в опере", "Терраса Мастера", "Низ разрушенной лестницы", "Верх разрушенной лестницы", "Галерея", "Библиотека Стража", "Хранилище", "Верхний ярус библиотеки", "Обсерватория", "Игровой зал", "Покои Медива", "Энергетический блок", "Пустомарь"],
|
||||
3715 => ["Паровое подземелье", "Охладительные резервуары"],
|
||||
3790 => ["Потусторонние залы", "Мост Душ"],
|
||||
3791 => ["Гнездовье Сетекк", "Залы Плача"],
|
||||
3848 => ["Изоляционная камера: Трион", "Изоляционная камера: Максимус", "Ядро Сдерживания"],
|
||||
3849 => ["Механар", "Комната Вычислений"],
|
||||
3959 => ["Campo de Treinamento Illidari", "Esgotos de Karabor", "Santuário das Sombras", "Salões da Angústia", "Vigia do Sanguinávido", "Covil dos Prazeres Mortais", "Câmara de Comando", "Ápice do Templo"],
|
||||
4075 => ["Плато Солнечного Колодца", "Святилище Затмения"],
|
||||
4100 => ["Дорога к Стратхольму", "Стратхольм"],
|
||||
4131 => ["Пристанище Великого Магистра", "Обзорная площадка"],
|
||||
4196 => ["Залы крепости Драк'Тарон", "Дозорное укрепление Драк'Тарона"],
|
||||
4228 => ["Кольцо отклонения", "Кольцо ускорения", "Кольцо трансмутации", "Кольцо управления"],
|
||||
4272 => ["Стойкий гарнизон", "Галерея Творцов"],
|
||||
4273 => ["Большой переход", "Вестибюль Ульдуара", "Внутреннее святилище Ульдуара", "Темница Йогг-Сарона", "Искра Воображения", "Око разума"],
|
||||
4277 => ["Родовая яма", "Логово Хадронокса", "Золоченые врата"],
|
||||
4395 => ["Даларан", "Клоака"],
|
||||
4494 => ["Ан'кахет", "Уровень 2"],
|
||||
4722 => ["Колизей Серебряного Авангарда", "Ледяные глубины"],
|
||||
4812 => ["Нижний ярус", "Черепной вал", "Подъем Смертоносного", "Логово Королевы Льда", "Верхний ярус", "Королевские палаты", "Ледяной Трон", "Ледяная Скорбь"]
|
||||
)
|
||||
),
|
||||
'quest' => array(
|
||||
|
||||
@@ -1188,44 +1188,6 @@ $lang = array(
|
||||
'cat' => array(
|
||||
"东部王国", "卡利姆多", "地下城", "团队副本", "未使用", null,
|
||||
"战场", null, "外域", "竞技场", "诺森德"
|
||||
),
|
||||
'floors' => array(
|
||||
206 => ["诺迪尔备战区", "掠龙氏族高台", "提尔之台"],
|
||||
209 => ["庭院", "饭厅", "空巢", "下层瞭望台", "上层瞭望台", "高弗雷勋爵的大厅", "城墙走道"],
|
||||
719 => ["阿斯卡之池", "月神圣地密室", "遗忘之池"],
|
||||
721 => ["齿轮大厅", "宿舍", "发射台", "工匠议会"],
|
||||
796 => ["墓地", "图书馆", "军械库", "大教堂"],
|
||||
1196 => ["尖塔下层", "尖塔上层"],
|
||||
1337 => ["守护者大厅", "卡兹格罗斯之座"],
|
||||
1581 => ["死亡矿井", "铁甲湾"],
|
||||
1583 => ["塔萨洛尔", "蛛网隧道", "霍德玛尔城", "黑手大厅", "龙塔大厅", "孵化间", "黑石竞技场"],
|
||||
1584 => ["禁闭室", "暗炉城"],
|
||||
2017 => ["十字军广场", "街巷"],
|
||||
2057 => ["遗骨之穴", "召唤大厅", "书房上层", "院长的书房"],
|
||||
2100 => ["玛拉顿的洞穴", "扎尔塔之墓"],
|
||||
2557 => ["戈多克议会", "中心花园", "上层精灵庭院", "伊莫塔尔的牢笼", "扭木广场", "艾德雷斯神殿"],
|
||||
2677 => ["龙喉兵营", "征战大厅", "血色实验室", "奈法利安的巢穴"],
|
||||
3428 => ["地下虫巢", "神殿大门", "克苏恩地穴"],
|
||||
3456 => ["构造区", "蜘蛛区", "军事区", "瘟疫区", "大墓地下层", "大墓地上层"],
|
||||
3457 => ["仆役宿舍", "上层马厩", "宴会厅", "会客间", "歌剧院楼座", "主宰的露台", "下层断阶", "上层断阶", "展览馆", "守护者的图书馆", "储藏室", "上层图书馆", "观星大厅", "象棋大厅", "麦迪文的房间", "能量站", "虚空异界"],
|
||||
3715 => ["蒸汽地窟", "冷却池"],
|
||||
3790 => ["转生大厅", "灵魂之桥"],
|
||||
3791 => ["塞泰克鸦巢", "哀悼大厅"],
|
||||
3848 => ["静止隔间:特雷奥", "静止隔间:玛克希姆", "密封核心"],
|
||||
3849 => ["能源舰", "计算密室"],
|
||||
3959 => ["伊利达雷训练场", "卡拉波下水道", "暗影圣殿", "苦痛大厅", "血魔之厅", "欢愉之园", "命令大厅", "神殿之巅"],
|
||||
4075 => ["太阳之井高地", "日蚀神殿"],
|
||||
4100 => ["斯坦索姆外围", "斯坦索姆城"],
|
||||
4131 => ["大魔导师的圣堂", "观测台"],
|
||||
4196 => ["达克萨隆前庭", "达克萨隆悬崖"],
|
||||
4228 => ["突变之环", "加速之环", "转化之环", "校准之环"],
|
||||
4272 => ["坚韧军营", "造物者步道"],
|
||||
4273 => ["壮阔大道", "奥杜尔的前厅", "奥杜尔的内部圣殿", "尤格-萨隆的监狱", "思想火花", "心灵之眼"],
|
||||
4277 => ["孵化深渊", "哈多诺克斯之巢", "镀金之门"],
|
||||
4395 => ["达拉然城", "达拉然下水道"],
|
||||
4494 => ["安卡赫特", '被亵渎的祭坛'],
|
||||
4722 => ["银色演武场", "寒冰深渊"],
|
||||
4812 => ["堡垒下层", "颅骨之墙", "死亡使者之台", "冰霜女王的巢穴", "上层区域", "皇家区", "冰封王座", "霜之哀伤"]
|
||||
)
|
||||
),
|
||||
'quest' => array(
|
||||
|
||||
@@ -7,59 +7,25 @@ if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
require_once 'setup/tools/CLISetup.class.php';
|
||||
require_once 'setup/tools/setupScript.class.php';
|
||||
require_once 'setup/tools/utilityScript.class.php';
|
||||
require_once 'setup/tools/CLISetup.class.php';
|
||||
require_once 'setup/tools/dbc.class.php';
|
||||
require_once 'setup/tools/imagecreatefromblp.func.php';
|
||||
|
||||
function finish() : void
|
||||
{
|
||||
if (CLISetup::getOpt('delete')) // generated with TEMPORARY keyword. Manual deletion is not needed
|
||||
CLI::write('generated dbc_* - tables have been deleted.', CLI::LOG_INFO);
|
||||
|
||||
die("\n");
|
||||
}
|
||||
|
||||
CLISetup::init();
|
||||
CLISetup::loadScripts();
|
||||
|
||||
if (!CLISetup::getOpt(0x3))
|
||||
die(CLISetup::optHelp(0x7));
|
||||
if (CLISetup::getOpt('help'))
|
||||
die(CLISetup::writeCLIHelp(true));
|
||||
else if (!CLISetup::getOpt(1 << CLISetup::OPT_GRP_SETUP | 1 << CLISetup::OPT_GRP_UTIL))
|
||||
die(CLISetup::writeCLIHelp());
|
||||
|
||||
$cmd = CLISetup::getOpt(0x3)[0]; // get arguments present in argGroup 1 or 2, if set. Pick first.
|
||||
$s = [];
|
||||
$b = [];
|
||||
switch ($cmd) // we accept only one main parameter
|
||||
{
|
||||
case 'setup':
|
||||
case 'sql':
|
||||
case 'build':
|
||||
case 'account':
|
||||
case 'dbconfig':
|
||||
case 'siteconfig':
|
||||
require_once 'setup/tools/clisetup/'.$cmd.'.func.php';
|
||||
$cmd();
|
||||
finish();
|
||||
case 'update':
|
||||
require_once 'setup/tools/clisetup/update.func.php';
|
||||
if (CLISetup::getOpt('delete')) // generated with TEMPORARY keyword. Manual deletion is not needed
|
||||
CLI::write('generated dbc_* - tables have been deleted.', CLI::LOG_INFO);
|
||||
|
||||
update($s, $b); // return true if we do not rebuild stuff
|
||||
if (!$s && !$b)
|
||||
finish();
|
||||
case 'sync':
|
||||
require_once 'setup/tools/clisetup/sync.func.php';
|
||||
CLISetup::runInitial();
|
||||
|
||||
sync($s, $b);
|
||||
finish();
|
||||
case 'dbc':
|
||||
require_once 'setup/tools/clisetup/dbc.func.php';
|
||||
|
||||
$args = [];
|
||||
foreach ($argv as $i => $str)
|
||||
if ($i && $str[0] != '-')
|
||||
$args[] = $str;
|
||||
|
||||
dbc($args);
|
||||
break;
|
||||
}
|
||||
die("\n");
|
||||
|
||||
?>
|
||||
|
||||
@@ -20,123 +20,404 @@ class CLISetup
|
||||
'frFR' => LOCALE_FR,
|
||||
'deDE' => LOCALE_DE,
|
||||
'zhCN' => LOCALE_CN, 'enCN' => LOCALE_CN,
|
||||
'esES' => LOCALE_ES, 'esMX' => LOCALE_ES,
|
||||
'esES' => LOCALE_ES,
|
||||
'ruRU' => LOCALE_RU
|
||||
);
|
||||
|
||||
public const SQL_BATCH = 1000; // max. n items per sql insert
|
||||
|
||||
public const LOCK_OFF = 0;
|
||||
public const LOCK_ON = 1;
|
||||
public const LOCK_RESTORE = 2;
|
||||
|
||||
private static $lock = 1;
|
||||
private static $lock = self::LOCK_ON;
|
||||
|
||||
private const ARGV_REQUIRED = 0x01;
|
||||
private const ARGV_OPTIONAL = 0x02;
|
||||
private const ARGV_ARRAY = 0x10;
|
||||
public const ARGV_NONE = 0x00;
|
||||
public const ARGV_REQUIRED = 0x01;
|
||||
public const ARGV_OPTIONAL = 0x02;
|
||||
public const ARGV_PARAM = 0x04; // parameter to another argument
|
||||
public const ARGV_ARRAY = 0x10; // arg accepts list of values
|
||||
|
||||
public const OPT_GRP_SETUP = 0;
|
||||
public const OPT_GRP_UTIL = 1;
|
||||
public const OPT_GRP_MISC = 2;
|
||||
|
||||
private const GLOBALSTRINGS_LUA = '%s%sinterface/framexml/globalstrings.lua';
|
||||
|
||||
private static $opts = [];
|
||||
private static $optGroups = ['AoWoW Setup', 'Utility Functions', 'Additional Options', 'Additional arguments specific to --build=simpleImg', 'Additional arguments specific to --build=complexImg'];
|
||||
private static $optDefs = array( // cmd => [groupId, aliasses[], flags, description, appendix]
|
||||
'setup' => [0, ['s', 'firstrun'], 0x00, 'Step by step initial setup. Resumes if interrupted.', '' ],
|
||||
'update' => [0, ['u'], 0x00, 'Apply new sql updates fetched from Github and run --sync as needed.', '' ],
|
||||
'dbconfig' => [1, [], 0x00, 'Set up DB connection.', '' ],
|
||||
'siteconfig' => [1, [], 0x00, 'Set up site variables.', '' ],
|
||||
'account' => [1, [], 0x00, 'Create an account with admin privileges.', '' ],
|
||||
'sql' => [1, [], 0x12, 'Generate DB content from your world tables.', '=<subScriptList,>' ],
|
||||
'build' => [1, [], 0x12, 'Compile image files and data dumps.', '=<subScriptList,>' ],
|
||||
'sync' => [1, [], 0x12, 'Regenerate tables/files that depend on given world DB table.', '=<worldTableList,>'],
|
||||
'dbc' => [1, [], 0x11, 'Extract dbc files from mpqDataDir into sql table. Structure must be defined in setup/dbc.class.php.', '=<dbcfileList,>' ],
|
||||
'delete' => [2, ['d'], 0x00, 'Delete dbc_* tables generated by this prompt when done.', '' ],
|
||||
'log' => [2, [], 0x01, 'Write CLI ouput to file.', '=logfile' ],
|
||||
'help' => [2, ['h'], 0x00, 'Display contextual help, if available.', '' ],
|
||||
'force' => [2, ['f'], 0x00, 'Force existing files to be overwritten.', '' ],
|
||||
'locales' => [2, [], 0x12, 'Limit setup to enUS, frFR, deDE, zhCN, esES and/or ruRU. (does not override config settings)', '=<regionCodes,>' ],
|
||||
'mpqDataDir' => [2, [], 0x02, 'Manually point to directory with extracted mpq files. This is limited to setup/ (default: setup/mpqData/)', '=path/' ],
|
||||
'icons' => [3, ['1'], 0x00, 'Generate icons for spells, items, classes, races, ect.', '' ],
|
||||
'glyphs' => [3, ['2'], 0x00, 'Generate decorative glyph symbols displayed on related item and spell pages.', '' ],
|
||||
'pagetexts' => [3, ['3'], 0x00, 'Generate images contained in text on readable items and gameobjects.', '' ],
|
||||
'loadingscreens' => [3, ['4'], 0x00, 'Generate loading screen images (not used on page; skipped by default)', '' ],
|
||||
'talentbgs' => [4, ['1'], 0x00, 'Generate backgrounds for the talent calculator.', '' ],
|
||||
'maps' => [4, ['2'], 0x00, 'Generate zone and continental maps.', '' ],
|
||||
'spawn-maps' => [4, ['3'], 0x00, 'Fallback to generate alpha masks for each zone to match creature and gameobject spawn points.', '' ],
|
||||
'artwork' => [4, ['4'], 0x00, 'Generate images from /glues/credits (not used on page; skipped by default))', '' ],
|
||||
'area-maps' => [4, ['5'], 0x00, 'Generate additional area maps with highlighting for subzones (optional; skipped by default)', '' ]
|
||||
private static $optGroups = ['AoWoW Setup', 'Utility Functions', 'Additional Options'];
|
||||
private static $optDefs = array( // cmd => [groupId, aliases[], argvFlags, description, appendix]
|
||||
'delete' => [self::OPT_GRP_MISC, ['d'], self::ARGV_NONE, 'Delete dbc_* tables generated by this prompt when done. (not recommended)', '' ],
|
||||
'log' => [self::OPT_GRP_MISC, [], self::ARGV_REQUIRED, 'Write CLI ouput to file.', '=logfile' ],
|
||||
'help' => [self::OPT_GRP_MISC, ['h'], self::ARGV_NONE, 'Display contextual help, if available.', '' ],
|
||||
'force' => [self::OPT_GRP_MISC, ['f'], self::ARGV_NONE, 'Force existing files to be overwritten.', '' ],
|
||||
'locales' => [self::OPT_GRP_MISC, [], self::ARGV_ARRAY | self::ARGV_OPTIONAL, 'Limit setup to enUS, frFR, deDE, zhCN, esES and/or ruRU. (does not override config settings)', '=<regionCodes,>'],
|
||||
'datasrc' => [self::OPT_GRP_MISC, [], self::ARGV_OPTIONAL, 'Manually point to directory with extracted mpq files. This is limited to setup/ (default: setup/mpqdata/)', '=path/' ],
|
||||
);
|
||||
|
||||
private static $utilScriptRefs = [];
|
||||
private static $setupScriptRefs = [];
|
||||
private static $tmpStore = [];
|
||||
private static $gsFiles = [];
|
||||
|
||||
/**************************/
|
||||
/* command line arguments */
|
||||
/**************************/
|
||||
public static function registerUtility(UtilityScript $us) : void
|
||||
{
|
||||
if (isset(self::$optDefs[$us::COMMAND]) || isset(self::$utilScriptRefs[$us::COMMAND]))
|
||||
{
|
||||
CLI::write(' Utility function '.CLI::bold($us::COMMAND).' already defined.', CLI::LOG_ERROR);
|
||||
return;
|
||||
}
|
||||
self::$optDefs[$us::COMMAND] = [$us->optGroup, $us->argvOpts, $us->argvFlags, $us::DESCRIPTION, $us::APPENDIX];
|
||||
self::$utilScriptRefs[$us::COMMAND] = $us;
|
||||
}
|
||||
|
||||
public static function registerSetup(string $invoker, SetupScript $ss) : void
|
||||
{
|
||||
if (isset(self::$optDefs[$invoker]) || isset(self::$utilScriptRefs[$invoker]))
|
||||
{
|
||||
CLI::write(' Utility function '.CLI::bold($invoker).' not defined. Can\'t attach Subscript '.CLI::bold($ss->getName()).', invoker is missing. Skipping...', CLI::LOG_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset(self::$setupScriptRefs[$invoker][$ss->getName()]))
|
||||
{
|
||||
CLI::write(' Subscript function '.CLI::bold($ss->getName()).' already defined for invoker '.CLI::bold($invoker).'. Skipping...', CLI::LOG_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($childArgs = $ss->getSubCommands())
|
||||
{
|
||||
if ($duplicates = array_intersect(array_keys($childArgs), array_keys(self::$optDefs)))
|
||||
{
|
||||
CLI::write(' Subscript function '.CLI::bold($ss->getName()).'\'s child arguments --'.implode(', --', $duplicates).' are already defined. Skipping...', CLI::LOG_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
$newIdx = count(self::$optGroups);
|
||||
self::$optGroups[] = '--' . $invoker . '=' . $ss->getName();
|
||||
|
||||
foreach ($childArgs as $cmd => [$aliases, $argFlags, $description])
|
||||
self::$optDefs[$cmd] = [$newIdx, $aliases, $argFlags, $description, ''];
|
||||
}
|
||||
|
||||
// checks done ... store SetupScript
|
||||
if (self::checkDependencies($ss))
|
||||
{
|
||||
self::$setupScriptRefs[] = [$invoker, $ss->getName(), $ss];
|
||||
|
||||
// recheck temp stored dependencies
|
||||
foreach (self::$tmpStore as $idx => [$invoker, $ts])
|
||||
{
|
||||
if (!self::checkDependencies($ts))
|
||||
continue;
|
||||
|
||||
self::$setupScriptRefs[] = [$invoker, $ts->getName(), $ts];
|
||||
unset(self::$tmpStore[$idx]);
|
||||
}
|
||||
}
|
||||
else // if dependencies haven't been stored yet, put aside for later use
|
||||
self::$tmpStore[] = [$invoker, $ss];
|
||||
}
|
||||
|
||||
private static function checkDependencies(SetupScript &$ss) : bool
|
||||
{
|
||||
if ($ss->isOptional) // optional scripts should no depend on anything
|
||||
return true;
|
||||
|
||||
[$sDep, $bDep] = $ss->getSelfDependencies();
|
||||
|
||||
return ((!$sDep || $sDep == array_intersect($sDep, array_column(array_filter(self::$setupScriptRefs, function($x) { return $x[0] == 'sql'; }), 1))) &&
|
||||
(!$bDep || $bDep == array_intersect($bDep, array_column(array_filter(self::$setupScriptRefs, function($x) { return $x[0] == 'build'; }), 1))));
|
||||
}
|
||||
|
||||
public static function loadScripts() : void
|
||||
{
|
||||
foreach (glob('setup/tools/clisetup/*.us.php') as $file)
|
||||
include_once $file;
|
||||
|
||||
if (self::$tmpStore)
|
||||
{
|
||||
CLI::write('Some SubScripts have unresolved dependencies and have not been loaded', CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
$tbl = [['Name', '--sql dep.', '--build dep.']];
|
||||
foreach (self::$tmpStore as [$_, $ssRef])
|
||||
{
|
||||
[$sDep, $bDep] = $ssRef->getSelfDependencies();
|
||||
|
||||
$missS = array_intersect($sDep, array_column(array_filter(self::$setupScriptRefs, function($x) { return $x[0] == 'sql'; }), 1));
|
||||
$missB = array_intersect($sDep, array_column(array_filter(self::$setupScriptRefs, function($x) { return $x[0] == 'build'; }), 1));
|
||||
|
||||
array_walk($sDep, function (&$x) use($missS) { $x = in_array($x, $missS) ? $x : CLI::red($x); });
|
||||
array_walk($bDep, function (&$x) use($missB) { $x = in_array($x, $missB) ? $x : CLI::red($x); });
|
||||
|
||||
$tbl[] = [$ssRef->getName(), implode(', ', $sDep), implode(', ', $bDep)];
|
||||
}
|
||||
|
||||
CLI::writeTable($tbl);
|
||||
}
|
||||
|
||||
// link SubScipts back to UtilityScript after all UtilityScripts have been loaded
|
||||
foreach (self::$utilScriptRefs as $name => $us)
|
||||
if (in_array('TrSubScripts', class_uses($us)))
|
||||
$us->assignGenerators($name);
|
||||
|
||||
self::evalOpts();
|
||||
}
|
||||
|
||||
public static function getSubScripts(string $invoker = '') : generator
|
||||
{
|
||||
foreach (self::$setupScriptRefs as [$src, $name, $ref])
|
||||
if (!$invoker || $src == $invoker)
|
||||
yield $name => [$src, $ref];
|
||||
}
|
||||
|
||||
public static function init() : void
|
||||
{
|
||||
$short = '';
|
||||
$long = [];
|
||||
$alias = [];
|
||||
|
||||
foreach (self::$optDefs as $opt => [$idx, $aliasses, $flags, , ])
|
||||
{
|
||||
if ($flags & self::ARGV_REQUIRED)
|
||||
$opt .= ':';
|
||||
else if ($flags & self::ARGV_OPTIONAL)
|
||||
$opt .= '::';
|
||||
|
||||
$long[] = $opt;
|
||||
foreach ($aliasses as $a)
|
||||
{
|
||||
if ($flags & self::ARGV_REQUIRED) // neither should be set with shortOpts
|
||||
$_a = $a.':';
|
||||
else if ($flags & self::ARGV_OPTIONAL)
|
||||
$_a = $a.'::';
|
||||
else
|
||||
$_a = $a;
|
||||
|
||||
$alias[$a] = $opt;
|
||||
if (strlen($a) == 1)
|
||||
$short .= $_a;
|
||||
else
|
||||
$long[] = $_a;
|
||||
}
|
||||
}
|
||||
|
||||
if ($opts = getopt($short, $long))
|
||||
foreach ($opts as $o => $v)
|
||||
self::$opts[$alias[$o] ?? $o] = (self::$optDefs[$alias[$o] ?? $o][2] & self::ARGV_ARRAY) ? ($v ? explode(',', $v) : []) : ($v ?: true);
|
||||
self::evalOpts();
|
||||
|
||||
// optional logging
|
||||
if (isset(self::$opts['log']))
|
||||
CLI::initLogFile(trim(self::$opts['log']));
|
||||
|
||||
// alternative data source (no quotes, use forward slash)
|
||||
if (isset(self::$opts['mpqDataDir']))
|
||||
self::$srcDir = CLI::nicePath(self::$opts['mpqDataDir']);
|
||||
if (isset(self::$opts['datasrc']))
|
||||
self::$srcDir = CLI::nicePath(self::$opts['datasrc']);
|
||||
|
||||
// optional limit handled locales
|
||||
if (isset(self::$opts['locales']))
|
||||
{
|
||||
// engb and enus are identical for all intents and purposes
|
||||
$from = ['engb', 'esmx', 'encn'];
|
||||
$to = ['enus', 'eses', 'zhcn'];
|
||||
$opts['locales'] = str_ireplace($from, $to, strtolower($opts['locales']));
|
||||
$from = ['engb', 'encn'];
|
||||
$to = ['enus', 'zhcn'];
|
||||
|
||||
self::$locales = array_intersect(Util::$localeStrings, explode(',', $opts['locales']));
|
||||
self::$opts['locales'] = str_ireplace($from, $to, self::$opts['locales']);
|
||||
|
||||
self::$locales = array_intersect(Util::$localeStrings, array_map('strtolower', self::$opts['locales']));
|
||||
}
|
||||
if (!self::$locales)
|
||||
self::$locales = array_filter(Util::$localeStrings);
|
||||
|
||||
// restrict actual locales
|
||||
foreach (self::$locales as $idx => $str)
|
||||
foreach (self::$locales as $idx => $_)
|
||||
{
|
||||
if (!($l = Cfg::get('LOCALES')) || ($l & (1 << $idx)))
|
||||
self::$localeIds[] = $idx;
|
||||
else
|
||||
unset(self::$locales[$idx]);
|
||||
}
|
||||
|
||||
if (!self::$localeIds)
|
||||
CLI::write('No valid locale specified. Check your config or --locales parameter, if used', CLI::LOG_ERROR);
|
||||
|
||||
// get site status
|
||||
if (DB::isConnected(DB_AOWOW))
|
||||
self::$lock = (int)Cfg::get('MAINTENANCE');
|
||||
self::$lock = Cfg::get('MAINTENANCE');
|
||||
else
|
||||
self::$lock = self::LOCK_ON;
|
||||
}
|
||||
|
||||
public static function getOpt(...$args)
|
||||
public static function writeCLIHelp(bool $full = false) : void
|
||||
{
|
||||
$cmd = self::getOpt(1 << self::OPT_GRP_SETUP | 1 << self::OPT_GRP_UTIL);
|
||||
if (!$cmd || !self::$utilScriptRefs[$cmd[0]]->writeCLIHelp())
|
||||
{
|
||||
$lines = [];
|
||||
|
||||
foreach (self::$optGroups as $idx => $og)
|
||||
{
|
||||
if (!$full && $idx > self::OPT_GRP_SETUP)
|
||||
continue;
|
||||
|
||||
$lines[] = [$og, ''];
|
||||
|
||||
foreach (self::$optDefs as $opt => [$group, $alias, , $desc, $app])
|
||||
{
|
||||
if ($group != $idx)
|
||||
continue;
|
||||
|
||||
$cmd = ' --'.$opt;
|
||||
foreach ($alias as $a)
|
||||
$cmd .= ' | '.(strlen($a) == 1 ? '-'.$a : '--'.$a);
|
||||
|
||||
$lines[] = [$cmd.$app, $desc];
|
||||
}
|
||||
}
|
||||
|
||||
CLI::writeTable($lines);
|
||||
CLI::write();
|
||||
}
|
||||
}
|
||||
|
||||
// called from Setup
|
||||
public static function runInitial() : void
|
||||
{
|
||||
global $argc, $argv; // todo .. find better way? argv, argc are effectivley already global
|
||||
|
||||
// get arguments present in argGroup 1 or 2, if set. Pick first.
|
||||
$cmd = self::getOpt(1 << self::OPT_GRP_SETUP | 1 << self::OPT_GRP_UTIL)[0];
|
||||
$us = &self::$utilScriptRefs[$cmd];
|
||||
$inOut = [null, null, null, null];
|
||||
$allOk = true;
|
||||
|
||||
$i = 0;
|
||||
if ($us::USE_CLI_ARGS)
|
||||
foreach ($argv as $n => $arg)
|
||||
{
|
||||
if (!$n || ($arg && $arg[0] == '-')) // not parent; not handled by getOpt()
|
||||
continue;
|
||||
|
||||
$inOut[$i++] = $arg;
|
||||
|
||||
if ($i > 3)
|
||||
break;
|
||||
}
|
||||
|
||||
if ($dbError = array_filter($us::REQUIRED_DB, function ($x) { return !DB::isConnected($x); }))
|
||||
{
|
||||
CLI::write('Database on index '.implode(', ', $dbError).' not yet set up!', CLI::LOG_ERROR);
|
||||
CLI::write('Please use '.CLI::bold('"php aowow --db"').' for setup', CLI::LOG_BLANK);
|
||||
CLI::write();
|
||||
return;
|
||||
}
|
||||
|
||||
if ($us::LOCK_SITE != self::LOCK_OFF)
|
||||
self::siteLock(self::LOCK_ON);
|
||||
|
||||
if ($us::NOTE_START)
|
||||
CLI::write($us::NOTE_START);
|
||||
|
||||
if (!$us->run($inOut))
|
||||
$allOk = false;
|
||||
|
||||
$error = [];
|
||||
if ($allOk && !$us->test($error))
|
||||
{
|
||||
if ($us::NOTE_ERROR)
|
||||
CLI::write($us::NOTE_ERROR, CLI::LOG_ERROR);
|
||||
|
||||
foreach ($error as $e)
|
||||
CLI::write($e, CLI::LOG_BLANK);
|
||||
|
||||
CLI::write();
|
||||
$allOk = false;
|
||||
}
|
||||
|
||||
if ($allOk)
|
||||
if ($ff = $us->followupFn)
|
||||
if (array_filter($inOut))
|
||||
self::run($ff, $inOut);
|
||||
|
||||
self::siteLock($us::LOCK_SITE == self::LOCK_RESTORE ? self::LOCK_RESTORE : self::LOCK_OFF);
|
||||
|
||||
// end
|
||||
if ($us::NOTE_END_OK && $allOk)
|
||||
CLI::write($us::NOTE_END_OK, CLI::LOG_OK);
|
||||
else if($us::NOTE_END_FAIL && !$allOk)
|
||||
CLI::write($us::NOTE_END_FAIL, CLI::LOG_ERROR);
|
||||
}
|
||||
|
||||
// consecutive calls
|
||||
public static function run(string $cmd, &$args) : bool
|
||||
{
|
||||
if (!isset(self::$utilScriptRefs[$cmd]))
|
||||
return false;
|
||||
|
||||
$us = &self::$utilScriptRefs[$cmd];
|
||||
|
||||
if ($dbError = array_filter($us::REQUIRED_DB, function ($x) { return !DB::isConnected($x); }))
|
||||
{
|
||||
CLI::write('Database on index '.implode(', ', $dbError).' not yet set up!', CLI::LOG_ERROR);
|
||||
CLI::write('Please use '.CLI::bold('"php aowow --db"').' for setup', CLI::LOG_BLANK);
|
||||
CLI::write();
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($us::PROMPT)
|
||||
{
|
||||
CLI::write($us::PROMPT, -1, false);
|
||||
CLI::write();
|
||||
|
||||
if (!CLI::read(['x' => ['Press any key to continue', true, true]], $_)) // we don't actually care about the input
|
||||
return false;
|
||||
}
|
||||
|
||||
$args = array_pad($args, 4, []);
|
||||
|
||||
$success = $us->run($args);
|
||||
|
||||
$error = [];
|
||||
if ($us::NOTE_ERROR && $success && !$us->test($error))
|
||||
{
|
||||
CLI::write($us::NOTE_ERROR, CLI::LOG_ERROR);
|
||||
foreach ($error as $e)
|
||||
CLI::write($e, CLI::LOG_BLANK);
|
||||
|
||||
CLI::write();
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($success)
|
||||
if ($ff = $us->followupFn)
|
||||
if (array_filter($args))
|
||||
if (!self::run($ff, $args))
|
||||
$success = false;
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
|
||||
/**************************/
|
||||
/* command line arguments */
|
||||
/**************************/
|
||||
|
||||
public static function evalOpts() : void
|
||||
{
|
||||
$short = '';
|
||||
$long = [];
|
||||
$alias = [];
|
||||
|
||||
foreach (self::$optDefs as $opt => [, $aliases, $flags, , ])
|
||||
{
|
||||
foreach ($aliases as $i => $a)
|
||||
{
|
||||
if (isset($alias[$a]))
|
||||
$alias[$a][] = $opt;
|
||||
else
|
||||
$alias[$a] = [$opt];
|
||||
|
||||
if ($flags & self::ARGV_REQUIRED)
|
||||
$a .= ':';
|
||||
else if ($flags & self::ARGV_OPTIONAL)
|
||||
$a .= '::';
|
||||
|
||||
if (strlen($aliases[$i]) == 1)
|
||||
$short .= $a;
|
||||
else
|
||||
$long[] = $a;
|
||||
}
|
||||
|
||||
if ($flags & self::ARGV_REQUIRED)
|
||||
$opt .= ':';
|
||||
else if ($flags & self::ARGV_OPTIONAL)
|
||||
$opt .= '::';
|
||||
|
||||
$long[] = $opt;
|
||||
}
|
||||
|
||||
if ($opts = getopt($short, $long))
|
||||
{
|
||||
foreach ($opts as $o => $v)
|
||||
{
|
||||
if (!isset($alias[$o]))
|
||||
self::$opts[$o] = (self::$optDefs[$o][2] & self::ARGV_ARRAY) ? ($v ? explode(',', $v) : []) : ($v ?: true);
|
||||
else
|
||||
foreach ($alias[$o] as $a)
|
||||
self::$opts[$a] = (self::$optDefs[$a][2] & self::ARGV_ARRAY) ? ($v ? explode(',', $v) : []) : ($v ?: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function getOpt(/* string|int */ ...$args) // : bool|array|string
|
||||
{
|
||||
if (!$args)
|
||||
return false;
|
||||
@@ -165,39 +446,12 @@ class CLISetup
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function optHelp(int $groupMask = 0x0) : void
|
||||
{
|
||||
$lines = [];
|
||||
|
||||
foreach (self::$optGroups as $idx => $og)
|
||||
{
|
||||
if ($groupMask && !($groupMask & (1 << $idx)))
|
||||
continue;
|
||||
|
||||
$lines[] = [$og, ''];
|
||||
|
||||
foreach (self::$optDefs as $opt => [$group, $alias, , $desc, $app])
|
||||
{
|
||||
if ($group != $idx)
|
||||
continue;
|
||||
|
||||
$cmd = ' --'.$opt;
|
||||
foreach ($alias as $a)
|
||||
$cmd .= ' | '.(strlen($a) == 1 ? '-'.$a : '--'.$a);
|
||||
|
||||
$lines[] = [$cmd.$app, $desc];
|
||||
}
|
||||
}
|
||||
|
||||
CLI::writeTable($lines);
|
||||
}
|
||||
|
||||
|
||||
/*******************/
|
||||
/* web page access */
|
||||
/*******************/
|
||||
|
||||
public static function siteLock(int $mode = self::LOCK_RESTORE) : void
|
||||
private static function siteLock(int $mode = self::LOCK_RESTORE) : void
|
||||
{
|
||||
if (DB::isConnected(DB_AOWOW))
|
||||
Cfg::set('MAINTENANCE', $mode == self::LOCK_RESTORE ? self::$lock : $mode);
|
||||
@@ -216,8 +470,7 @@ class CLISetup
|
||||
*/
|
||||
private static function buildFileList() : bool
|
||||
{
|
||||
CLI::write();
|
||||
CLI::write('indexing game data from '.self::$srcDir.' for first time use...');
|
||||
CLI::write('indexing game data from '.self::$srcDir.' for first time use...', CLI::LOG_INFO, true, true);
|
||||
|
||||
$setupDirs = glob('setup/*');
|
||||
foreach ($setupDirs as $sd)
|
||||
@@ -246,8 +499,7 @@ class CLISetup
|
||||
self::$mpqFiles[strtolower($_)] = $_;
|
||||
}
|
||||
|
||||
CLI::write('done');
|
||||
CLI::write();
|
||||
CLI::write('indexing game data from '.self::$srcDir.' for first time use... done!', CLI::LOG_INFO);
|
||||
}
|
||||
catch (UnexpectedValueException $e)
|
||||
{
|
||||
@@ -258,7 +510,7 @@ class CLISetup
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function fileExists(&$file)
|
||||
public static function fileExists(string &$file) : bool
|
||||
{
|
||||
// read mpq source file structure to tree
|
||||
if (!self::$mpqFiles)
|
||||
@@ -281,7 +533,7 @@ class CLISetup
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function filesInPath($path, $useRegEx = false)
|
||||
public static function filesInPath(string $path, bool $useRegEx = false) : array
|
||||
{
|
||||
$result = [];
|
||||
|
||||
@@ -304,12 +556,82 @@ class CLISetup
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function filesInPathLocalized(string $pathPattern, ?bool &$status = true, bool $matchAll = true) : array
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach (self::$expectedPaths as $xp => $locId)
|
||||
{
|
||||
if (!in_array($locId, self::$localeIds))
|
||||
continue;
|
||||
|
||||
if (isset($result[$locId]))
|
||||
continue;
|
||||
|
||||
if ($xp) // if in subDir add trailing slash
|
||||
$xp .= '/';
|
||||
|
||||
$path = sprintf($pathPattern, $xp);
|
||||
if (self::fileExists($path))
|
||||
{
|
||||
$result[$locId] = $path;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$matchAll && !$result)
|
||||
$status = false;
|
||||
|
||||
if ($matchAll && array_diff(self::$localeIds, array_keys($result)))
|
||||
$status = false;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function loadGlobalStrings() : bool
|
||||
{
|
||||
CLI::write('loading required GlobalStrings', CLI::LOG_INFO);
|
||||
|
||||
// try to load globalstrings for all selected locales
|
||||
foreach (self::$expectedPaths as $xp => $lId)
|
||||
{
|
||||
if (isset(self::$gsFiles[$lId]))
|
||||
continue;
|
||||
|
||||
if ($xp)
|
||||
$xp .= '/';
|
||||
|
||||
$gsFile = sprintf(self::GLOBALSTRINGS_LUA, self::$srcDir, $xp);
|
||||
if (self::fileExists($gsFile))
|
||||
self::$gsFiles[$lId] = file($gsFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
}
|
||||
|
||||
if ($missing = array_diff(self::$localeIds, array_keys(self::$gsFiles)))
|
||||
{
|
||||
ClI::write('GlobalStrings.lua not found for locale '. Lang::concat($missing), CLI::LOG_WARN);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function searchGlobalStrings(string $pattern) : generator
|
||||
{
|
||||
if (!self::$gsFiles)
|
||||
return;
|
||||
|
||||
foreach (self::$gsFiles as $lId => $globalStrings)
|
||||
foreach ($globalStrings as $gs)
|
||||
if (preg_match($pattern, $gs, $result))
|
||||
yield $lId => $result;
|
||||
}
|
||||
|
||||
|
||||
/*****************/
|
||||
/* file handling */
|
||||
/*****************/
|
||||
|
||||
public static function writeFile($file, $content)
|
||||
public static function writeFile(string $file, string $content) : bool
|
||||
{
|
||||
if (Util::writeFile($file, $content))
|
||||
{
|
||||
@@ -322,17 +644,23 @@ class CLISetup
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function writeDir($dir)
|
||||
public static function writeDir(string $dir, bool &$exist = true) : bool
|
||||
{
|
||||
if (Util::writeDir($dir))
|
||||
if (Util::writeDir($dir, $exist))
|
||||
return true;
|
||||
|
||||
CLI::write(error_get_last()['message'].' '.CLI::bold($dir), CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function loadDBC($name)
|
||||
public static function loadDBC( string $name) : bool
|
||||
{
|
||||
if (!DB::isConnected(DB_AOWOW))
|
||||
{
|
||||
CLI::write('CLISetup::loadDBC() - not connected to DB. Cannot write results!', CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DB::Aowow()->selectCell('SHOW TABLES LIKE ?', 'dbc_'.$name) && DB::Aowow()->selectCell('SELECT count(1) FROM ?#', 'dbc_'.$name))
|
||||
return true;
|
||||
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/********************/
|
||||
/* Account creation */
|
||||
/********************/
|
||||
|
||||
function account() : void
|
||||
{
|
||||
$fields = array(
|
||||
'name' => ['Username', false],
|
||||
'pass1' => ['Enter Password', true ],
|
||||
'pass2' => ['Confirm Password', true ]
|
||||
);
|
||||
|
||||
if (!DB::isConnected(DB_AOWOW))
|
||||
{
|
||||
CLI::write('Database not yet set up!', CLI::LOG_WARN);
|
||||
CLI::write('Please use '.CLI::bold('"php aowow --dbconfig"').' for setup', CLI::LOG_BLANK);
|
||||
CLI::write();
|
||||
return;
|
||||
}
|
||||
|
||||
User::useLocale(LOCALE_EN);
|
||||
Lang::load(LOCALE_EN);
|
||||
|
||||
if (CLI::read($fields, $uiAccount))
|
||||
{
|
||||
CLI::write();
|
||||
|
||||
if (!User::isValidName($uiAccount['name'], $e))
|
||||
CLI::write(Lang::account($e == 1 ? 'errNameLength' : 'errNameChars'), CLI::LOG_ERROR);
|
||||
else if (!User::isValidPass($uiAccount['pass1'], $e))
|
||||
CLI::write(Lang::account($e == 1 ? 'errPassLength' : 'errPassChars'), CLI::LOG_ERROR);
|
||||
else if ($uiAccount['pass1'] != $uiAccount['pass2'])
|
||||
CLI::write(Lang::account('passMismatch'), CLI::LOG_ERROR);
|
||||
else if ($_ = DB::Aowow()->SelectCell('SELECT 1 FROM ?_account WHERE user = ? AND (status <> ?d OR (status = ?d AND statusTimer > UNIX_TIMESTAMP()))', $uiAccount['name'], ACC_STATUS_NEW, ACC_STATUS_NEW))
|
||||
CLI::write(Lang::account('nameInUse'), CLI::LOG_ERROR);
|
||||
else
|
||||
{
|
||||
// write to db
|
||||
$ok = DB::Aowow()->query('REPLACE INTO ?_account (user, passHash, displayName, joindate, email, allowExpire, userGroups, userPerms) VALUES (?, ?, ?, UNIX_TIMESTAMP(), ?, 0, ?d, 1)',
|
||||
$uiAccount['name'],
|
||||
User::hashCrypt($uiAccount['pass1']),
|
||||
Util::ucFirst($uiAccount['name']),
|
||||
Cfg::get('CONTACT_EMAIL'),
|
||||
U_GROUP_ADMIN
|
||||
);
|
||||
if ($ok)
|
||||
{
|
||||
$newId = DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE user = ?', $uiAccount['name']);
|
||||
Util::gainSiteReputation($newId, SITEREP_ACTION_REGISTER);
|
||||
|
||||
CLI::write("account ".$uiAccount['name']." created successfully", CLI::LOG_OK);
|
||||
}
|
||||
else // something went wrong
|
||||
CLI::write(Lang::main('intError'), CLI::LOG_ERROR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CLI::write();
|
||||
CLI::write("account creation aborted", CLI::LOG_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
130
setup/tools/clisetup/account.us.php
Normal file
130
setup/tools/clisetup/account.us.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/********************/
|
||||
/* Account creation */
|
||||
/********************/
|
||||
|
||||
CLISetup::registerUtility(new class extends UtilityScript
|
||||
{
|
||||
public $argvOpts = ['a'];
|
||||
public $optGroup = CLISetup::OPT_GRP_SETUP;
|
||||
|
||||
public const COMMAND = 'account';
|
||||
public const DESCRIPTION = 'Create an account with admin privileges.';
|
||||
public const APPENDIX = ' [name [password [email]]]';
|
||||
public const PROMPT = 'Please create your admin account.';
|
||||
public const NOTE_ERROR = 'There is no user with administrator privileges in the DB.';
|
||||
|
||||
public const REQUIRED_DB = [DB_AOWOW];
|
||||
|
||||
public const USE_CLI_ARGS = true;
|
||||
|
||||
public $runArgs = ['name', 'passw', 'email'];
|
||||
|
||||
private $fields = array(
|
||||
'name' => ['Username', false],
|
||||
'pass1' => ['Enter Password', true ],
|
||||
'pass2' => ['Confirm Password', true ],
|
||||
'email' => ['Email (optional)', false]
|
||||
);
|
||||
|
||||
// args: username, password, email, null // iiin
|
||||
public function run(&$args) : bool
|
||||
{
|
||||
User::useLocale(LOCALE_EN);
|
||||
Lang::load(LOCALE_EN);
|
||||
|
||||
$name = $args[0] ?? '';
|
||||
$passw = $args[1] ?? '';
|
||||
$email = $args[2];
|
||||
|
||||
if ($name && User::isValidName($name))
|
||||
unset($this->fields['name']);
|
||||
else
|
||||
$name = '';
|
||||
|
||||
if ($passw && User::isValidPass($passw))
|
||||
{
|
||||
unset($this->fields['pass1']);
|
||||
unset($this->fields['pass2']);
|
||||
}
|
||||
else
|
||||
$passw = '';
|
||||
|
||||
if (is_string($email) && (!strlen($email) || Util::isValidEmail($email)))
|
||||
unset($this->fields['email']);
|
||||
else
|
||||
$email = '';
|
||||
|
||||
if ($this->fields && CLI::read($this->fields, $uiAccount))
|
||||
{
|
||||
CLI::write();
|
||||
|
||||
if (!$name && !User::isValidName($uiAccount['name'], $e))
|
||||
CLI::write(Lang::account($e == 1 ? 'errNameLength' : 'errNameChars'), CLI::LOG_ERROR);
|
||||
else if (!$name)
|
||||
$name = $uiAccount['name'];
|
||||
|
||||
if (!$passw && !User::isValidPass($uiAccount['pass1'], $e))
|
||||
CLI::write(Lang::account($e == 1 ? 'errPassLength' : 'errPassChars'), CLI::LOG_ERROR);
|
||||
else if (!$passw && $uiAccount['pass1'] != $uiAccount['pass2'])
|
||||
CLI::write(Lang::account('passMismatch'), CLI::LOG_ERROR);
|
||||
else if (!$passw)
|
||||
$passw = $uiAccount['pass1'];
|
||||
|
||||
if (!$email && Util::isValidEmail($uiAccount['email']))
|
||||
$email = $uiAccount['email'];
|
||||
else if (!$email && $uiAccount['email'])
|
||||
CLI::write('[account] email invalid ... using default: ' . Cfg::get('CONTACT_EMAIL'), CLI::LOG_INFO);
|
||||
}
|
||||
else if ($this->fields)
|
||||
{
|
||||
CLI::write();
|
||||
CLI::write("[account] admin creation aborted", CLI::LOG_INFO);
|
||||
CLI::write();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (DB::Aowow()->SelectCell('SELECT 1 FROM ?_account WHERE user = ? AND (status <> ?d OR (status = ?d AND statusTimer > UNIX_TIMESTAMP()))', $name, ACC_STATUS_NEW, ACC_STATUS_NEW))
|
||||
{
|
||||
CLI::write('[account] ' . Lang::account('nameInUse'), CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$name || !$passw)
|
||||
return false;
|
||||
|
||||
if (DB::Aowow()->query('REPLACE INTO ?_account (user, passHash, displayName, joindate, email, allowExpire, userGroups, userPerms) VALUES (?, ?, ?, UNIX_TIMESTAMP(), ?, 0, ?d, 1)',
|
||||
$name, User::hashCrypt($passw), Util::ucFirst($name), $email ?: Cfg::get('CONTACT_EMAIL'), U_GROUP_ADMIN))
|
||||
{
|
||||
$newId = DB::Aowow()->selectCell('SELECT id FROM ?_account WHERE user = ?', $name);
|
||||
Util::gainSiteReputation($newId, SITEREP_ACTION_REGISTER);
|
||||
|
||||
CLI::write("[account] admin ".$name." created successfully", CLI::LOG_OK);
|
||||
CLI::write();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CLI::write('[account] ' . Lang::main('intError'), CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function test(?array &$error = []) : bool
|
||||
{
|
||||
$error = [];
|
||||
return !!DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE `userPerms` = 1');
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,102 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/*************************/
|
||||
/* Create required files */
|
||||
/*************************/
|
||||
|
||||
function build($syncMe = null) : array
|
||||
{
|
||||
if (!DB::isConnected(DB_AOWOW) || !DB::isConnected(DB_WORLD))
|
||||
{
|
||||
CLI::write('Database not yet set up!', CLI::LOG_WARN);
|
||||
CLI::write('Please use '.CLI::bold('"php aowow --dbconfig"').' for setup', CLI::LOG_BLANK);
|
||||
CLI::write();
|
||||
return [];
|
||||
}
|
||||
|
||||
require_once 'setup/tools/fileGen.class.php';
|
||||
|
||||
if(!FileGen::init($syncMe !== null ? FileGen::MODE_UPDATE : FileGen::MODE_NORMAL, $syncMe ?: []))
|
||||
return [];
|
||||
|
||||
$done = [];
|
||||
if (FileGen::$subScripts)
|
||||
{
|
||||
CLISetup::siteLock(CLISetup::LOCK_ON);
|
||||
$allOk = true;
|
||||
|
||||
// start file generation
|
||||
CLI::write('begin generation of '. implode(', ', FileGen::$subScripts));
|
||||
CLI::write();
|
||||
|
||||
// files with template
|
||||
foreach (FileGen::$tplFiles as $name => [$file, $destPath, $deps])
|
||||
{
|
||||
$reqDBC = [];
|
||||
|
||||
if (!in_array($name, FileGen::$subScripts))
|
||||
continue;
|
||||
|
||||
if (!file_exists(FileGen::$tplPath.$file.'.in'))
|
||||
{
|
||||
CLI::write(sprintf(ERR_MISSING_FILE, FileGen::$tplPath.$file.'.in'), CLI::LOG_ERROR);
|
||||
$allOk = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!CLISetup::writeDir($destPath))
|
||||
continue;
|
||||
|
||||
$syncIds = []; // todo: fetch what exactly must be regenerated
|
||||
|
||||
$ok = FileGen::generate($name, $syncIds);
|
||||
if (!$ok)
|
||||
$allOk = false;
|
||||
else
|
||||
$done[] = $name;
|
||||
|
||||
CLI::write(' - subscript \''.$file.'\' returned '.($ok ? 'successfully' : 'with errors'), $ok ? CLI::LOG_OK : CLI::LOG_ERROR);
|
||||
set_time_limit(FileGen::$defaultExecTime); // reset to default for the next script
|
||||
}
|
||||
|
||||
// files without template
|
||||
foreach (FileGen::$datasets as $file => $deps)
|
||||
{
|
||||
if (!in_array($file, FileGen::$subScripts))
|
||||
continue;
|
||||
|
||||
$syncIds = []; // todo: fetch what exactly must be regenerated
|
||||
|
||||
$ok = FileGen::generate($file, $syncIds);
|
||||
if (!$ok)
|
||||
$allOk = false;
|
||||
else
|
||||
$done[] = $file;
|
||||
|
||||
CLI::write(' - subscript \''.$file.'\' returned '.($ok ? 'successfully' : 'with errors'), $ok ? CLI::LOG_OK : CLI::LOG_ERROR);
|
||||
set_time_limit(FileGen::$defaultExecTime); // reset to default for the next script
|
||||
}
|
||||
|
||||
// end
|
||||
CLI::write();
|
||||
if ($allOk)
|
||||
CLI::write('successfully finished file generation', CLI::LOG_OK);
|
||||
else
|
||||
CLI::write('finished file generation with errors', CLI::LOG_ERROR);
|
||||
|
||||
CLISetup::siteLock(CLISetup::LOCK_RESTORE);
|
||||
}
|
||||
else if (FileGen::getMode() == FileGen::MODE_NORMAL)
|
||||
CLI::write('no valid script names supplied', CLI::LOG_ERROR);
|
||||
|
||||
return $done;
|
||||
}
|
||||
|
||||
?>
|
||||
159
setup/tools/clisetup/datagen.us.php
Normal file
159
setup/tools/clisetup/datagen.us.php
Normal file
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/************************************************/
|
||||
/* Create content from world tables / dbc files */
|
||||
/************************************************/
|
||||
|
||||
CLISetup::registerUtility(new class extends UtilityScript
|
||||
{
|
||||
use TrSubScripts;
|
||||
|
||||
public $argvFlags = CLISetup::ARGV_ARRAY | CLISetup::ARGV_OPTIONAL;
|
||||
public $optGroup = CLISetup::OPT_GRP_UTIL;
|
||||
|
||||
public const COMMAND = 'sql';
|
||||
public const DESCRIPTION = 'Generate DB content from your world tables.';
|
||||
public const APPENDIX = '=<SetupScriptList,>';
|
||||
public const NOTE_START = '[sql] begin generation of:';
|
||||
public const NOTE_END_OK = 'successfully finished sql generation';
|
||||
public const NOTE_END_FAIL = 'finished sql generation with errors';
|
||||
|
||||
public const REQUIRED_DB = [DB_AOWOW, DB_WORLD];
|
||||
|
||||
public const LOCK_SITE = CLISetup::LOCK_RESTORE;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
if ($this->inited)
|
||||
return true;
|
||||
|
||||
$this->defaultExecTime = ini_get('max_execution_time');
|
||||
|
||||
// register subscripts to CLISetup
|
||||
foreach (glob('setup/tools/sqlgen/*.ss.php') as $file)
|
||||
include_once $file;
|
||||
|
||||
$this->inited = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// args: scriptToDo, scriptSuccess, null, null // ionn
|
||||
public function run(&$args) : bool
|
||||
{
|
||||
$todo = &$args['doSql'];
|
||||
$done = &$args['doneSql'];
|
||||
|
||||
if (!$this->inited)
|
||||
return false;
|
||||
|
||||
// check passed subscript names; limit to real scriptNames
|
||||
if (($sqlArgs = CLISetup::getOpt('sql')) !== false)
|
||||
{
|
||||
if ($sqlArgs === []) // used --sql without arguments
|
||||
$todo = array_keys($this->generators); // do everything
|
||||
else if ($_ = array_intersect(array_keys($this->generators), $sqlArgs))
|
||||
$todo = $_;
|
||||
else
|
||||
{
|
||||
CLI::write('[sql] no valid script names supplied', CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// supplement self::NOTE_START
|
||||
CLI::write(' - '.Lang::concat($todo), CLI::LOG_BLANK, false);
|
||||
CLI::write();
|
||||
}
|
||||
else if ($todo)
|
||||
{
|
||||
$todo = array_intersect(array_keys($this->generators), is_array($todo) ? $todo : [$todo]);
|
||||
if (!$todo)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
$allOk = true;
|
||||
|
||||
// start file generation
|
||||
foreach ($todo as $cmd)
|
||||
{
|
||||
$syncIds = []; // todo: fetch what exactly must be regenerated
|
||||
$success = false;
|
||||
$scriptRef = &$this->generators[$cmd];
|
||||
|
||||
CLI::write('[sql] filling aowow_'.$cmd.' with data');
|
||||
|
||||
if ($scriptRef->fulfillRequirements())
|
||||
{
|
||||
if ($scriptRef->generate($syncIds))
|
||||
{
|
||||
if (method_exists($scriptRef, 'applyCustomData'))
|
||||
$success = $scriptRef->applyCustomData();
|
||||
|
||||
$success = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$success)
|
||||
$allOk = false;
|
||||
else
|
||||
$done[] = $cmd;
|
||||
|
||||
CLI::write('[sql] subscript \''.$cmd.'\' returned '.($success ? 'successfully' : 'with errors'), $success ? CLI::LOG_OK : CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
set_time_limit($this->defaultExecTime); // reset to default for the next script
|
||||
}
|
||||
|
||||
return $allOk;
|
||||
}
|
||||
|
||||
public function writeCLIHelp() : bool
|
||||
{
|
||||
if ($args = CLISetup::getOpt('sql'))
|
||||
{
|
||||
$anyHelp = false;
|
||||
foreach ($args as $cmd)
|
||||
if (isset($this->generators[$cmd]) && $this->generators[$cmd]->writeCLIHelp())
|
||||
$anyHelp = true;
|
||||
|
||||
if ($anyHelp)
|
||||
return true;
|
||||
}
|
||||
|
||||
CLI::write(' usage: php aowow --sql=<SetupScriptList,> [--mpqDataDir: --locales:]', -1, false);
|
||||
CLI::write();
|
||||
CLI::write(' Regenerates DB table content for a given SetupScript. Dependencies are taken into account by the triggered calls of --sync and --update', -1, false);
|
||||
CLI::write();
|
||||
|
||||
ksort($this->generators);
|
||||
|
||||
$lines = [['Command', 'TC dependencies', 'AoWoW dependencies', 'Info']];
|
||||
foreach ($this->generators as $cmd => $ssRef)
|
||||
{
|
||||
$tcDeps = explode("\n", Lang::breakTextClean(implode(', ', $ssRef->getRemoteDependencies() ), 35, Lang::FMT_RAW));
|
||||
$aoDeps = explode("\n", Lang::breakTextClean(implode(', ', $ssRef->getSelfDependencies()[0]), 35, Lang::FMT_RAW));
|
||||
|
||||
for ($i = 0; $i < max(count($tcDeps), count($aoDeps)); $i++)
|
||||
$lines[] = array(
|
||||
$i ? '' : $cmd,
|
||||
$tcDeps[$i] ?? '',
|
||||
$aoDeps[$i] ?? '',
|
||||
$i ? '' : $ssRef->getInfo()
|
||||
);
|
||||
}
|
||||
|
||||
CLI::writeTable($lines);
|
||||
CLI::write();
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -11,53 +11,54 @@ if (!CLI)
|
||||
/* Create content from world tables / dbc files */
|
||||
/************************************************/
|
||||
|
||||
function dbc($args) : bool
|
||||
CLISetup::registerUtility(new class extends UtilityScript
|
||||
{
|
||||
if (!DB::isConnected(DB_AOWOW))
|
||||
public $argvFlags = CLISetup::ARGV_ARRAY | CLISetup::ARGV_REQUIRED;
|
||||
public $optGroup = CLISetup::OPT_GRP_UTIL;
|
||||
|
||||
public const COMMAND = 'dbc';
|
||||
public const DESCRIPTION = 'Extract dbc files from mpqDataDir into sql table. Structural ini file must be defined in setup/tools/dbc/.';
|
||||
public const APPENDIX = '=<dbcfileList,> [tablename [wowbuild]]';
|
||||
|
||||
public const REQUIRED_DB = [DB_AOWOW];
|
||||
|
||||
public const USE_CLI_ARGS = true;
|
||||
|
||||
// args: tblName, wowbuild, null, null // iinn
|
||||
public function run(&$args) : bool
|
||||
{
|
||||
CLI::write('Database not yet set up!', CLI::LOG_WARN);
|
||||
CLI::write('Please use '.CLI::bold('"php aowow --dbconfig"').' for setup', CLI::LOG_BLANK);
|
||||
CLI::write();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CLISetup::getOpt('dbc'))
|
||||
return writeCLIHelp();
|
||||
|
||||
foreach (CLISetup::getOpt('dbc') as $n)
|
||||
{
|
||||
$n = str_ireplace('.dbc', '', trim($n));
|
||||
|
||||
if (empty($n))
|
||||
continue;
|
||||
|
||||
$opts = ['temporary' => false];
|
||||
if ($args[0])
|
||||
$opts['tableName'] = $args[0];
|
||||
|
||||
$dbc = new DBC(strtolower($n), $opts, $args[1] ?: DBC::DEFAULT_WOW_BUILD);
|
||||
if ($dbc->error)
|
||||
foreach (CLISetup::getOpt('dbc') as $n)
|
||||
{
|
||||
CLI::write('[dbc] required DBC '.CLI::bold($n).'.dbc not found!', CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
return false;
|
||||
$n = str_ireplace('.dbc', '', trim($n));
|
||||
|
||||
if (empty($n))
|
||||
continue;
|
||||
|
||||
$opts = ['temporary' => false];
|
||||
if ($args[0])
|
||||
$opts['tableName'] = $args[0];
|
||||
|
||||
$dbc = new DBC(strtolower($n), $opts, $args[1] ?: DBC::DEFAULT_WOW_BUILD);
|
||||
if ($dbc->error)
|
||||
{
|
||||
CLI::write('[dbc] required DBC '.CLI::bold($n).'.dbc not found!', CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$dbc->readFile())
|
||||
{
|
||||
CLI::write('[dbc] DBC '.CLI::bold($n).'.dbc could not be written to DB!', CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
$self = DB::Aowow()->selectCell('SELECT DATABASE()');
|
||||
CLI::write('[dbc] DBC '.CLI::bold($n).'.dbc written to '.CLI::bold('`'.($self ?? 'NULL').'`.`'.$dbc->getTableName().'`').'!', CLI::LOG_OK);
|
||||
}
|
||||
|
||||
if (!$dbc->readFile())
|
||||
{
|
||||
CLI::write('[dbc] DBC '.CLI::bold($n).'.dbc could not be written to DB!', CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
return false;
|
||||
}
|
||||
|
||||
$self = DB::Aowow()->selectCell('SELECT DATABASE()');
|
||||
CLI::write('[dbc] DBC '.CLI::bold($n).'.dbc written to '.CLI::bold('`'.($self ?? 'NULL').'`.`'.$dbc->getTableName().'`').'!', CLI::LOG_OK);
|
||||
CLI::write();
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
function writeCLIHelp() : bool
|
||||
public function writeCLIHelp() : bool
|
||||
{
|
||||
CLI::write(' usage: php aowow --dbc=<dbcfileList,..> [--locales=<regionCodes,..>] [tablename [wowbuild]]', -1, false);
|
||||
CLI::write();
|
||||
@@ -113,6 +114,6 @@ function dbc($args) : bool
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,207 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/**************************/
|
||||
/* Configure DB connection*/
|
||||
/**************************/
|
||||
|
||||
function dbconfig() : void
|
||||
{
|
||||
$databases = ['aowow', 'world', 'auth', 'characters'];
|
||||
$AoWoWconf = [];
|
||||
$dbFields = array(
|
||||
'host' => ['Hostname / IP', false],
|
||||
'user' => ['User', false],
|
||||
'pass' => ['Password', true ],
|
||||
'db' => ['Database Name', false],
|
||||
'prefix' => ['Table prefix', false]
|
||||
);
|
||||
$testDB = function($idx, $name, $dbInfo)
|
||||
{
|
||||
$buff = ['['.CLI::bold($idx).']', $name];
|
||||
|
||||
if ($dbInfo['host'])
|
||||
{
|
||||
$result = CLI::green('OK');
|
||||
$note = '';
|
||||
|
||||
if (DB::test($dbInfo, $note))
|
||||
{
|
||||
DB::load($idx, $dbInfo);
|
||||
|
||||
$ok = false;
|
||||
switch ($idx)
|
||||
{
|
||||
case DB_AOWOW:
|
||||
if (DB::Aowow()->selectCell('SHOW TABLES LIKE ?', 'aowow_dbversion'))
|
||||
{
|
||||
if ($date = DB::Aowow()->selectCell('SELECT `date` FROM ?_dbversion'))
|
||||
{
|
||||
$note = 'AoWoW DB version @ ' . date(Util::$dateFormatInternal, $date);
|
||||
$ok = true;
|
||||
}
|
||||
else
|
||||
$note = CLI::yellow('AoWoW DB version empty! Import of DB dump failed?');
|
||||
}
|
||||
else
|
||||
$note = CLI::yellow('DB test failed to find dbversion table. setup/db_structure.sql not yet imported?');
|
||||
break;
|
||||
case DB_WORLD:
|
||||
if (DB::World()->selectCell('SHOW TABLES LIKE ?', 'version'))
|
||||
{
|
||||
[$vString, $vNo] = DB::World()->selectRow('SELECT `db_version` AS "0", `cache_id` AS "1" FROM `version`');
|
||||
if (strpos($vString, 'TDB') === 0)
|
||||
{
|
||||
if ($vNo < TDB_WORLD_MINIMUM_VER)
|
||||
$note = CLI::yellow('DB test found TrinityDB version older than rev. ').CLI::bold(TDB_WORLD_MINIMUM_VER).CLI::yellow('. Please update to at least rev. ').CLI::bold(TDB_WORLD_MINIMUM_VER);
|
||||
else if ($vNo > TDB_WORLD_EXPECTED_VER)
|
||||
$note = CLI::yellow('DB test found TrinityDB version newer than rev. ').CLI::bold(TDB_WORLD_EXPECTED_VER).CLI::yellow('. Be advised! DB structure may diverge!');
|
||||
else
|
||||
{
|
||||
$note = 'TrinityDB version @ ' . $vString;
|
||||
$ok = true;
|
||||
}
|
||||
}
|
||||
else if (strpos($vString, 'ACDB') === 0)
|
||||
$note = CLI::yellow('DB test found AzerothCore DB version. AzerothCore DB structure is not supported!');
|
||||
else
|
||||
$note = CLI::yellow('DB test found unexpected vendor in expected version table. Uhh.. Good Luck..!?');
|
||||
}
|
||||
else if (DB::World()->selectCell('SHOW TABLES LIKE ?', 'db_version'))
|
||||
$note = CLI::yellow('DB test found MaNGOS styled version table. MaNGOS DB structure is not supported!');
|
||||
else
|
||||
$note = CLI::yellow('DB test failed to find version table. TrinityDB world not yet imported?');
|
||||
break;
|
||||
default:
|
||||
$ok = true; // no tests right now
|
||||
}
|
||||
|
||||
if (!$ok)
|
||||
$result = CLI::yellow('WARN');
|
||||
}
|
||||
else
|
||||
$result = CLI::red('ERR');
|
||||
|
||||
$buff[] = $result;
|
||||
$buff[] = 'mysqli://'.$dbInfo['user'].':'.($dbInfo['pass'] ? '**********' : '').'@'.$dbInfo['host'].'/'.$dbInfo['db'];
|
||||
$buff[] = $dbInfo['prefix'] ? 'pre.: '.$dbInfo['prefix'] : '';
|
||||
$buff[] = $note;
|
||||
|
||||
}
|
||||
else
|
||||
$buff[] = CLI::bold('<empty>');
|
||||
|
||||
return $buff;
|
||||
};
|
||||
|
||||
if (file_exists('config/config.php'))
|
||||
require 'config/config.php';
|
||||
|
||||
foreach ($databases as $idx => $name)
|
||||
if (empty($AoWoWconf[$name]) && $name != 'characters' )
|
||||
$AoWoWconf[$name] = array_combine(array_keys($dbFields), ['', '', '', '', '']);
|
||||
|
||||
while (true)
|
||||
{
|
||||
CLI::write('select an index to use the corresponding entry', -1, false);
|
||||
|
||||
$nCharDBs = 0;
|
||||
$tblRows = [];
|
||||
foreach ($databases as $idx => $name)
|
||||
{
|
||||
if ($idx != DB_CHARACTERS)
|
||||
$tblRows[] = $testDB($idx, $name, $AoWoWconf[$name]);
|
||||
else if (!empty($AoWoWconf[$name]))
|
||||
foreach ($AoWoWconf[$name] as $charIdx => $dbInfo)
|
||||
$tblRows[] = $testDB($idx + $nCharDBs++, $name.' ['.$charIdx.']', $AoWoWconf[$name][$charIdx]);
|
||||
}
|
||||
|
||||
$tblRows[] = ['['.CLI::bold('N').']', 'new characters DB'];
|
||||
$tblRows[] = ['['.CLI::bold('R').']', 'retest / reload DBs'];
|
||||
CLI::writeTable($tblRows, false, true);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (CLI::read(['idx' => ['', true, true, '/\d|R|N/i']], $uiIndex) && $uiIndex)
|
||||
{
|
||||
if (strtoupper($uiIndex['idx']) == 'R')
|
||||
continue 2;
|
||||
else if (($uiIndex['idx'] >= DB_AOWOW && $uiIndex['idx'] < (DB_CHARACTERS + $nCharDBs)) || strtoupper($uiIndex['idx']) == 'N')
|
||||
{
|
||||
$curFields = $uiIndex['idx'] ? $dbFields : array_slice($dbFields, 0, 4);
|
||||
|
||||
if (strtoupper($uiIndex['idx']) == 'N') // add new characters DB
|
||||
$curFields['realmId'] = ['Realm Id', false, false, '/\d{1,3}/'];
|
||||
|
||||
if (CLI::read($curFields, $uiRealm))
|
||||
{
|
||||
if ($uiIndex['idx'] == DB_AOWOW && $uiRealm)
|
||||
$uiRealm['prefix'] = 'aowow_';
|
||||
|
||||
if (strtoupper($uiIndex['idx']) == 'N') // new char DB
|
||||
{
|
||||
if ($uiRealm)
|
||||
{
|
||||
$_ = $uiRealm['realmId'];
|
||||
unset($uiRealm['realmId']);
|
||||
$AoWoWconf[$databases[DB_CHARACTERS]][$_] = $uiRealm;
|
||||
}
|
||||
}
|
||||
else if ($uiIndex['idx'] < DB_CHARACTERS) // auth, world or aowow
|
||||
$AoWoWconf[$databases[$uiIndex['idx']]] = $uiRealm ?: array_combine(array_keys($dbFields), ['', '', '', '', '']);
|
||||
else // existing char DB
|
||||
{
|
||||
$i = 0;
|
||||
foreach ($AoWoWconf[$databases[DB_CHARACTERS]] as $realmId => &$dbInfo)
|
||||
{
|
||||
if ($uiIndex['idx'] - DB_CHARACTERS != $i++)
|
||||
continue;
|
||||
|
||||
if ($uiRealm)
|
||||
$dbInfo = $uiRealm;
|
||||
else
|
||||
unset($AoWoWconf[$databases[DB_CHARACTERS]][$realmId]);
|
||||
}
|
||||
}
|
||||
|
||||
// write config file
|
||||
$buff = "<?php\n\nif (!defined('AOWOW_REVISION'))\n die('illegal access');\n\n\n";
|
||||
foreach ($databases as $db)
|
||||
{
|
||||
if ($db != 'characters')
|
||||
$buff .= '$AoWoWconf[\''.$db.'\'] = '.var_export($AoWoWconf[$db], true).";\n\n";
|
||||
else if (isset($AoWoWconf[$db]))
|
||||
foreach ($AoWoWconf[$db] as $idx => $charInfo)
|
||||
$buff .= '$AoWoWconf[\''.$db.'\'][\''.$idx.'\'] = '.var_export($AoWoWconf[$db][$idx], true).";\n\n";
|
||||
}
|
||||
$buff .= "?>\n";
|
||||
CLI::write();
|
||||
CLISetup::writeFile('config/config.php', $buff);
|
||||
continue 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
CLI::write("edit canceled! returning to list...", CLI::LOG_INFO);
|
||||
CLI::write();
|
||||
sleep(1);
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CLI::write("leaving db setup...", CLI::LOG_INFO);
|
||||
CLI::write();
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
327
setup/tools/clisetup/dbconfig.us.php
Normal file
327
setup/tools/clisetup/dbconfig.us.php
Normal file
@@ -0,0 +1,327 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/**************************/
|
||||
/* Configure DB connection*/
|
||||
/**************************/
|
||||
|
||||
CLISetup::registerUtility(new class extends UtilityScript
|
||||
{
|
||||
public $argvOpts = ['db'];
|
||||
public $optGroup = CLISetup::OPT_GRP_SETUP;
|
||||
|
||||
public const COMMAND = 'database';
|
||||
public const DESCRIPTION = 'Set up DB connection.';
|
||||
public const PROMPT = 'Please enter your database credentials.';
|
||||
public const NOTE_ERROR = 'could not establish connection to:';
|
||||
|
||||
private const CONFIG_FILE = 'config/config.php';
|
||||
|
||||
private $databases = ['aowow', 'world', 'auth', 'characters'];
|
||||
private $config = [];
|
||||
private $dbFields = array(
|
||||
'host' => ['Server Host', false],
|
||||
'user' => ['User', false],
|
||||
'pass' => ['Password', true ],
|
||||
'db' => ['Database Name', false],
|
||||
'prefix' => ['Table prefix', false]
|
||||
);
|
||||
|
||||
private $icons = ['Normal[0]', 'PvP', null, null, 'Normal[4]', 'RP', null, 'RP-PvP'];
|
||||
private $regions = array(
|
||||
null, 'Development', 'United States', 'Oceanic', 'Latin America', 'Tournament (Americas)', 'Korea', 'Tournament (Korea)', 'English', 'German', 'French', 'Spanish', 'Russian', 'Tournament (EU)', 'Taiwan', 'Tournament (Taiwan)', 'China',
|
||||
25 => 'Tournament (China)', 26 => 'Test Server', 27 => 'Tournament (Test Server)', 28 => 'QA Server', 30 => 'Test Server 2'
|
||||
);
|
||||
|
||||
// args: null, null, null, null // nnnn
|
||||
public function run(&$args) : bool
|
||||
{
|
||||
if (!$this->config && file_exists(self::CONFIG_FILE))
|
||||
{
|
||||
require self::CONFIG_FILE;
|
||||
$this->config = $AoWoWconf;
|
||||
unset($AoWoWconf);
|
||||
}
|
||||
|
||||
foreach ($this->databases as $idx => $name)
|
||||
if (empty($this->config[$name]) && $name != 'characters' )
|
||||
$this->config[$name] = array_combine(array_keys($this->dbFields), ['', '', '', '', '']);
|
||||
|
||||
while (true)
|
||||
{
|
||||
CLI::write("select an index to use the corresponding entry", -1, false);
|
||||
|
||||
$nCharDBs = 0;
|
||||
$tblRows = [];
|
||||
foreach ($this->databases as $idx => $name)
|
||||
{
|
||||
if ($idx != DB_CHARACTERS)
|
||||
$tblRows[] = $this->testDB($idx, $name, $this->config[$name]);
|
||||
else if (!empty($this->config[$name]))
|
||||
foreach ($this->config[$name] as $charIdx => $dbInfo)
|
||||
$tblRows[] = $this->testDB($idx + $nCharDBs++, $name.' ['.$charIdx.']', $this->config[$name][$charIdx]);
|
||||
}
|
||||
|
||||
$tblRows[] = ['['.CLI::bold('N').']', 'new characters DB'];
|
||||
$tblRows[] = ['['.CLI::bold('S').']', 'show available realms'];
|
||||
$tblRows[] = ['['.CLI::bold('R').']', 'retest / reload DBs'];
|
||||
CLI::writeTable($tblRows, false, true);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (CLI::read(['idx' => ['', true, true, '/\d|R|N|S/i']], $uiIndex) && $uiIndex)
|
||||
{
|
||||
if (strtoupper($uiIndex['idx']) == 'R')
|
||||
continue 2;
|
||||
else if (strtoupper($uiIndex['idx']) == 'S')
|
||||
{
|
||||
CLI::write();
|
||||
if (!DB::isConnectable(DB_AUTH) || !$this->test())
|
||||
CLI::write('[db] auth server not yet set up.', CLI::LOG_ERROR);
|
||||
else if ($realms = DB::Auth()->select('SELECT id AS "0", name AS "1", icon AS "2", timezone AS "3", isRestricted AS "4" FROM realmlist'))
|
||||
{
|
||||
$tbl = [['Realm Id', 'Name', 'Type', 'Region', 'GMLevel', 'Status']];
|
||||
foreach ($realms as [$id, $name, $icon, $region, $level])
|
||||
{
|
||||
$status = [];
|
||||
$hasRegion = false;
|
||||
foreach (Profiler::REGIONS as $n => $valid)
|
||||
if ($hasRegion = in_array($region, $valid))
|
||||
{
|
||||
if ($n == 'dev')
|
||||
$status[] = 'Restricted region (staff only)';
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$hasRegion && !$status)
|
||||
$status[] = 'Unsupported region';
|
||||
if ($level > 0)
|
||||
$status[] = 'GM-Level locked';
|
||||
if (DB::isConnectable(DB_CHARACTERS . $id))
|
||||
$status[] = 'Already in use';
|
||||
|
||||
$tbl[] = [$id, $name, $this->icons[$icon] ?? '<UNK:'.$icon.'>', $this->regions[$region] ?? '<UNK:'.$region.'>', $level, $status ? CLI::yellow(implode(', ', $status)) : CLI::green('Usable')];
|
||||
}
|
||||
|
||||
CLI::writeTable($tbl);
|
||||
}
|
||||
else
|
||||
CLI::write('[db] table `realmlist` is empty.', CLI::LOG_WARN);
|
||||
|
||||
CLI::write();
|
||||
|
||||
continue 2;
|
||||
}
|
||||
else if (($uiIndex['idx'] >= DB_AOWOW && $uiIndex['idx'] < (DB_CHARACTERS + $nCharDBs)) || strtoupper($uiIndex['idx']) == 'N')
|
||||
{
|
||||
$curFields = $uiIndex['idx'] ? $this->dbFields : array_slice($this->dbFields, 0, 4);
|
||||
|
||||
if (strtoupper($uiIndex['idx']) == 'N') // add new characters DB
|
||||
$curFields['realmId'] = ['Realm Id', false, false, '/\d{1,3}/'];
|
||||
|
||||
if (CLI::read($curFields, $uiRealm))
|
||||
{
|
||||
if ($uiIndex['idx'] == DB_AOWOW && $uiRealm)
|
||||
$uiRealm['prefix'] = 'aowow_';
|
||||
|
||||
if (strtoupper($uiIndex['idx']) == 'N') // new char DB
|
||||
{
|
||||
if ($uiRealm)
|
||||
{
|
||||
$_ = $uiRealm['realmId'];
|
||||
unset($uiRealm['realmId']);
|
||||
$this->config[$this->databases[DB_CHARACTERS]][$_] = $uiRealm;
|
||||
}
|
||||
}
|
||||
else if ($uiIndex['idx'] < DB_CHARACTERS) // auth, world or aowow
|
||||
$this->config[$this->databases[$uiIndex['idx']]] = $uiRealm ?: array_combine(array_keys($this->dbFields), ['', '', '', '', '']);
|
||||
else // existing char DB
|
||||
{
|
||||
$i = 0;
|
||||
foreach ($this->config[$this->databases[DB_CHARACTERS]] as $realmId => &$dbInfo)
|
||||
{
|
||||
if ($uiIndex['idx'] - DB_CHARACTERS != $i++)
|
||||
continue;
|
||||
|
||||
if ($uiRealm)
|
||||
$dbInfo = $uiRealm;
|
||||
else
|
||||
unset($this->config[$this->databases[3]][$realmId]);
|
||||
}
|
||||
}
|
||||
|
||||
// write config file
|
||||
$buff = "<?php\n\nif (!defined('AOWOW_REVISION'))\n die('illegal access');\n\n\n";
|
||||
foreach ($this->databases as $db)
|
||||
{
|
||||
if ($db != 'characters')
|
||||
$buff .= '$AoWoWconf[\''.$db.'\'] = '.var_export($this->config[$db], true).";\n\n";
|
||||
else if (isset($this->config[$db]))
|
||||
foreach ($this->config[$db] as $idx => $charInfo)
|
||||
$buff .= '$AoWoWconf[\''.$db.'\'][\''.$idx.'\'] = '.var_export($this->config[$db][$idx], true).";\n\n";
|
||||
}
|
||||
$buff .= "?>\n";
|
||||
CLI::write();
|
||||
CLISetup::writeFile(self::CONFIG_FILE, $buff);
|
||||
continue 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
CLI::write("[db] edit canceled! returning to list...", CLI::LOG_INFO);
|
||||
CLI::write();
|
||||
sleep(1);
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CLI::write("[db] leaving db config...", CLI::LOG_INFO);
|
||||
CLI::write();
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function test(?array &$error = []) : bool
|
||||
{
|
||||
if (!$this->config)
|
||||
{
|
||||
require self::CONFIG_FILE;
|
||||
$this->config = $AoWoWconf;
|
||||
unset($AoWoWconf);
|
||||
}
|
||||
|
||||
$error = [];
|
||||
foreach (['aowow', 'world', 'auth'] as $idx => $what)
|
||||
{
|
||||
if ($what == 'auth' && (empty($this->config['auth']) || empty($this->config['auth']['host'])))
|
||||
continue;
|
||||
|
||||
// init proper access for further setup
|
||||
if (DB::test($this->config[$what], $err))
|
||||
{
|
||||
DB::load($idx, $this->config[$what]);
|
||||
switch ($idx)
|
||||
{
|
||||
case DB_AOWOW:
|
||||
if (DB::Aowow()->selectCell('SHOW TABLES LIKE ?', 'aowow_dbversion'))
|
||||
Cfg::load(); // first time load after successful db setup
|
||||
else
|
||||
$error[] = ' * '.$what.': doesn\'t seem to contain aowow tables!';
|
||||
break;
|
||||
case DB_WORLD:
|
||||
if (!DB::World()->selectCell('SHOW TABLES LIKE ?', 'version'))
|
||||
$error[] = ' * '.$what.': doesn\'t seem to contain TrinityCore world tables!';
|
||||
else if (DB::World()->selectCell('SELECT `cache_id` FROM `version`') < TDB_WORLD_MINIMUM_VER)
|
||||
$error[] = ' * '.$what.': TDB world db is structurally outdated! (min rev.: '.CLI::bold(TDB_WORLD_MINIMUM_VER).')';
|
||||
break;
|
||||
default:
|
||||
// no further checks at this time
|
||||
}
|
||||
}
|
||||
else
|
||||
$error[] = ' * '.$what.': '.$err;
|
||||
}
|
||||
|
||||
return empty($error);
|
||||
}
|
||||
|
||||
private function testDB($idx, $name, $dbInfo)
|
||||
{
|
||||
$buff = ['['.CLI::bold($idx).']', $name];
|
||||
|
||||
if ($dbInfo['host'])
|
||||
{
|
||||
$result = CLI::green('OK');
|
||||
$note = '';
|
||||
|
||||
if (DB::test($dbInfo, $note))
|
||||
{
|
||||
DB::load($idx, $dbInfo);
|
||||
|
||||
$ok = false;
|
||||
switch ($idx)
|
||||
{
|
||||
case DB_AOWOW:
|
||||
if (DB::Aowow()->selectCell('SHOW TABLES LIKE ?', 'aowow_dbversion'))
|
||||
{
|
||||
if ($date = DB::Aowow()->selectCell('SELECT `date` FROM ?_dbversion'))
|
||||
{
|
||||
$note = 'AoWoW DB version @ ' . date(Util::$dateFormatInternal, $date);
|
||||
$ok = true;
|
||||
}
|
||||
else
|
||||
$note = CLI::yellow('AoWoW DB version empty! Import of DB dump failed?');
|
||||
}
|
||||
else
|
||||
$note = CLI::yellow('DB test failed to find dbversion table. setup/db_structure.sql not yet imported?');
|
||||
break;
|
||||
case DB_WORLD:
|
||||
if (DB::World()->selectCell('SHOW TABLES LIKE ?', 'version'))
|
||||
{
|
||||
[$vString, $vNo] = DB::World()->selectRow('SELECT `db_version` AS "0", `cache_id` AS "1" FROM `version`');
|
||||
if (strpos($vString, 'TDB') === 0)
|
||||
{
|
||||
if ($vNo < TDB_WORLD_MINIMUM_VER)
|
||||
$note = CLI::yellow('DB test found TrinityDB version older than rev. ').CLI::bold(TDB_WORLD_MINIMUM_VER).CLI::yellow('. Please update to at least rev. ').CLI::bold(TDB_WORLD_MINIMUM_VER);
|
||||
else if ($vNo > TDB_WORLD_EXPECTED_VER)
|
||||
$note = CLI::yellow('DB test found TrinityDB version newer than rev. ').CLI::bold(TDB_WORLD_EXPECTED_VER).CLI::yellow('. Be advised! DB structure may diverge!');
|
||||
else
|
||||
{
|
||||
$note = 'TrinityDB version @ ' . $vString;
|
||||
$ok = true;
|
||||
}
|
||||
}
|
||||
else if (strpos($vString, 'ACDB') === 0)
|
||||
$note = CLI::yellow('DB test found AzerothCore DB version. AzerothCore DB structure is not supported!');
|
||||
else
|
||||
$note = CLI::yellow('DB test found unexpected vendor in expected version table. Uhh.. Good Luck..!?');
|
||||
}
|
||||
else if (DB::World()->selectCell('SHOW TABLES LIKE ?', 'db_version'))
|
||||
$note = CLI::yellow('DB test found MaNGOS styled version table. MaNGOS DB structure is not supported!');
|
||||
else
|
||||
$note = CLI::yellow('DB test failed to find version table. TrinityDB world not yet imported?');
|
||||
break;
|
||||
default:
|
||||
$ok = true; // no tests right now
|
||||
}
|
||||
|
||||
if (!$ok)
|
||||
$result = CLI::yellow('WARN');
|
||||
}
|
||||
else
|
||||
$result = CLI::red('ERR');
|
||||
|
||||
$buff[] = $result;
|
||||
$buff[] = 'mysqli://'.$dbInfo['user'].':'.($dbInfo['pass'] ? '**********' : '').'@'.$dbInfo['host'].'/'.$dbInfo['db'];
|
||||
$buff[] = $dbInfo['prefix'] ? 'pre.: '.$dbInfo['prefix'] : '';
|
||||
$buff[] = $note;
|
||||
}
|
||||
else
|
||||
$buff[] = CLI::bold('<empty>');
|
||||
|
||||
return $buff;
|
||||
}
|
||||
|
||||
public function writeCLIHelp() : bool
|
||||
{
|
||||
CLI::write(' Remember to use the correct Realm Id from '.CLI::bold('`logon`.`realmlist`').' when connecting to your characters DB.', -1, false);
|
||||
CLI::write(' To remove a db entry edit it and leave all fields empty.', -1, false);
|
||||
CLI::write();
|
||||
CLI::write();
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
173
setup/tools/clisetup/filegen.us.php
Normal file
173
setup/tools/clisetup/filegen.us.php
Normal file
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/*************************/
|
||||
/* Create required files */
|
||||
/*************************/
|
||||
|
||||
CLISetup::registerUtility(new class extends UtilityScript
|
||||
{
|
||||
use TrSubScripts;
|
||||
|
||||
public $argvFlags = CLISetup::ARGV_ARRAY | CLISetup::ARGV_OPTIONAL;
|
||||
public $optGroup = CLISetup::OPT_GRP_UTIL;
|
||||
|
||||
public const COMMAND = 'build';
|
||||
public const DESCRIPTION = 'Compile image files and data dumps.';
|
||||
public const APPENDIX = '=<SetupScriptList,>';
|
||||
public const NOTE_START = '[build] begin generation of:';
|
||||
public const NOTE_END_OK = 'successfully finished file generation';
|
||||
public const NOTE_END_FAIL = 'finished file generation with errors';
|
||||
|
||||
public const REQUIRED_DB = [DB_AOWOW, DB_WORLD];
|
||||
|
||||
public const LOCK_SITE = CLISetup::LOCK_RESTORE;
|
||||
|
||||
private $uploadDirs = array( // stuff that should be writable by www-data and isn't directly created by setup steps
|
||||
'static/uploads/screenshots/normal/',
|
||||
'static/uploads/screenshots/pending/',
|
||||
'static/uploads/screenshots/resized/',
|
||||
'static/uploads/screenshots/temp/',
|
||||
'static/uploads/screenshots/thumb/',
|
||||
'static/uploads/temp/',
|
||||
'static/uploads/guide/images/',
|
||||
);
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
if ($this->inited)
|
||||
return true;
|
||||
|
||||
$this->defaultExecTime = ini_get('max_execution_time');
|
||||
|
||||
// register subscripts to CLISetup
|
||||
foreach (glob('setup/tools/filegen/*.ss.php') as $file)
|
||||
include_once $file;
|
||||
|
||||
$this->inited = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// args: scriptToDo, scriptSuccess, null, null // ionn
|
||||
public function run(&$args) : bool
|
||||
{
|
||||
$todo = &$args['doBuild'];
|
||||
$done = &$args['doneBuild'];
|
||||
|
||||
if (!$this->inited)
|
||||
return false;
|
||||
|
||||
|
||||
// check passed subscript names; limit to real scriptNames
|
||||
if (($buildArgs = CLISetup::getOpt('build')) !== false)
|
||||
{
|
||||
if ($buildArgs === []) // used --build without arguments
|
||||
$todo = array_keys($this->generators); // do everything
|
||||
else if ($_ = array_intersect(array_keys($this->generators), $buildArgs))
|
||||
$todo = $_;
|
||||
else
|
||||
{
|
||||
CLI::write('[build] no valid script names supplied', CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// supplement self::NOTE_START
|
||||
CLI::write(' - '.Lang::concat($todo), CLI::LOG_BLANK, false);
|
||||
CLI::write();
|
||||
}
|
||||
else if ($todo)
|
||||
{
|
||||
$todo = array_intersect(array_keys($this->generators), is_array($todo) ? $todo : [$todo]);
|
||||
if (!$todo)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
// create user upload dir structure
|
||||
foreach ($this->uploadDirs as $ud)
|
||||
{
|
||||
if (CLISetup::writeDir($ud))
|
||||
continue;
|
||||
|
||||
CLI::write('[build] could not create directory: '.CLI::bold($ud), CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
$done = [];
|
||||
$allOk = true;
|
||||
|
||||
// start file generation
|
||||
foreach ($todo as $cmd)
|
||||
{
|
||||
$success = false;
|
||||
$scriptRef = &$this->generators[$cmd];
|
||||
|
||||
CLI::write('[build] gathering data for '.$cmd);
|
||||
|
||||
if ($scriptRef->fulfillRequirements())
|
||||
$success = $scriptRef->generate();
|
||||
|
||||
if (!$success)
|
||||
$allOk = false;
|
||||
else
|
||||
$done[] = $cmd;
|
||||
|
||||
CLI::write('[build] subscript \''.$cmd.'\' returned '.($success ? 'successfully' : 'with errors'), $success ? CLI::LOG_OK : CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
|
||||
set_time_limit($this->defaultExecTime); // reset to default for the next script
|
||||
}
|
||||
|
||||
return $allOk;
|
||||
}
|
||||
|
||||
public function writeCLIHelp() : bool
|
||||
{
|
||||
if ($args = CLISetup::getOpt('build'))
|
||||
{
|
||||
$anyHelp = false;
|
||||
foreach ($args as $cmd)
|
||||
if (isset($this->generators[$cmd]) && $this->generators[$cmd]->writeCLIHelp())
|
||||
$anyHelp = true;
|
||||
|
||||
if ($anyHelp)
|
||||
return true;
|
||||
}
|
||||
|
||||
CLI::write(' usage: php aowow --build=<SetupScriptList,> [--mpqDataDir: --locales:]', -1, false);
|
||||
CLI::write();
|
||||
CLI::write(' Compiles files for a given SetupScript. Existing files are kept by default. Dependencies are taken into account by the triggered calls of --sync --update', -1, false);
|
||||
CLI::write();
|
||||
|
||||
ksort($this->generators);
|
||||
|
||||
$lines = [['Command', 'TC dependencies', 'AoWoW dependencies', 'Info']];
|
||||
foreach ($this->generators as $cmd => $ssRef)
|
||||
{
|
||||
$tcDeps = explode("\n", Lang::breakTextClean(implode(', ', $ssRef->getRemoteDependencies() ), 35, Lang::FMT_RAW));
|
||||
$aoDeps = explode("\n", Lang::breakTextClean(implode(', ', $ssRef->getSelfDependencies()[0]), 35, Lang::FMT_RAW));
|
||||
|
||||
for ($i = 0; $i < max(count($tcDeps), count($aoDeps)); $i++)
|
||||
$lines[] = array(
|
||||
$i ? '' : $cmd,
|
||||
$tcDeps[$i] ?? '',
|
||||
$aoDeps[$i] ?? '',
|
||||
$i ? '' : $ssRef->getInfo()
|
||||
);
|
||||
}
|
||||
|
||||
CLI::writeTable($lines);
|
||||
CLI::write();
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,376 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/*********************************************/
|
||||
/* string setup steps together for first use */
|
||||
/*********************************************/
|
||||
|
||||
function setup() : void
|
||||
{
|
||||
require_once 'setup/tools/sqlGen.class.php';
|
||||
require_once 'setup/tools/fileGen.class.php';
|
||||
|
||||
SqlGen::init(SqlGen::MODE_FIRSTRUN);
|
||||
FileGen::init(FileGen::MODE_FIRSTRUN);
|
||||
|
||||
|
||||
/****************/
|
||||
/* define steps */
|
||||
/****************/
|
||||
|
||||
$upd = [[], []]; // ref to pass commands from 'update' to 'sync'
|
||||
$steps = array(
|
||||
// clisetup, params, test function, introText, errorText
|
||||
['dbconfig', [null, null], 'testDB', 'Please enter your database credentials.', 'could not establish connection to:'],
|
||||
['siteconfig', [null, null], 'testSelf', 'SITE_HOST and STATIC_HOST '.CLI::bold('must').' be set. Also enable FORCE_SSL if needed. You may also want to change other variables such as NAME, NAME_SHORT or LOCALES.', 'could not access:'],
|
||||
// sql- and build- stuff here
|
||||
['SqlGen::generate', 'dungeonmap', null, null, null],
|
||||
['SqlGen::generate', 'skilllineability', null, null, null],
|
||||
['SqlGen::generate', 'soundemitters', null, null, null],
|
||||
['SqlGen::generate', 'worldmaparea', null, null, null],
|
||||
['SqlGen::generate', 'areatrigger', null, null, null],
|
||||
['SqlGen::generate', 'achievementcriteria', null, null, null],
|
||||
['SqlGen::generate', 'glyphproperties', null, null, null],
|
||||
['SqlGen::generate', 'itemenchantment', null, null, null],
|
||||
['SqlGen::generate', 'itemenchantmentcondition', null, null, null],
|
||||
['SqlGen::generate', 'itemextendedcost', null, null, null],
|
||||
['SqlGen::generate', 'itemlimitcategory', null, null, null],
|
||||
['SqlGen::generate', 'itemrandomproppoints', null, null, null],
|
||||
['SqlGen::generate', 'lock', null, null, null],
|
||||
['SqlGen::generate', 'mails', null, null, null],
|
||||
['SqlGen::generate', 'scalingstatdistribution', null, null, null],
|
||||
['SqlGen::generate', 'scalingstatvalues', null, null, null],
|
||||
['SqlGen::generate', 'spellfocusobject', null, null, null],
|
||||
['SqlGen::generate', 'spellrange', null, null, null],
|
||||
['SqlGen::generate', 'spellvariables', null, null, null],
|
||||
['SqlGen::generate', 'totemcategory', null, null, null],
|
||||
['SqlGen::generate', 'talents', null, null, null],
|
||||
['SqlGen::generate', 'classes', null, null, null],
|
||||
['SqlGen::generate', 'factions', null, null, null],
|
||||
['SqlGen::generate', 'factiontemplate', null, null, null],
|
||||
['SqlGen::generate', 'holidays', null, null, null],
|
||||
['SqlGen::generate', 'icons', null, null, null],
|
||||
['SqlGen::generate', 'itemrandomenchant', null, null, null],
|
||||
['SqlGen::generate', 'races', null, null, null],
|
||||
['SqlGen::generate', 'shapeshiftforms', null, null, null],
|
||||
['SqlGen::generate', 'skillline', null, null, null],
|
||||
['SqlGen::generate', 'emotes', null, null, null],
|
||||
['SqlGen::generate', 'achievement', null, null, null],
|
||||
['SqlGen::generate', 'creature', null, null, null],
|
||||
['SqlGen::generate', 'currencies', null, null, null],
|
||||
['SqlGen::generate', 'events', null, null, null],
|
||||
['SqlGen::generate', 'objects', null, null, null],
|
||||
['SqlGen::generate', 'pet', null, null, null],
|
||||
['SqlGen::generate', 'quests', null, null, null],
|
||||
['SqlGen::generate', 'quests_startend', null, null, null],
|
||||
['SqlGen::generate', 'spell', null, null, null],
|
||||
['SqlGen::generate', 'spelldifficulty', null, null, null],
|
||||
['SqlGen::generate', 'taxi', null, null, null],
|
||||
['SqlGen::generate', 'titles', null, null, null],
|
||||
['SqlGen::generate', 'items', null, null, null],
|
||||
['FileGen::generate', 'complexImg', null, null, null], // alphamaps generated here are requires for spawns/waypoints
|
||||
['SqlGen::generate', 'zones', null, null, null],
|
||||
['SqlGen::generate', 'spawns', null, null, null], // this one ^_^
|
||||
['SqlGen::generate', 'itemset', null, null, null],
|
||||
['SqlGen::generate', 'item_stats', null, null, null],
|
||||
['SqlGen::generate', 'source', null, null, null],
|
||||
['SqlGen::generate', 'sounds', null, null, null],
|
||||
['SqlGen::generate', 'declinedwords', null, null, null],
|
||||
['FileGen::generate', 'soundfiles', null, null, null],
|
||||
['FileGen::generate', 'searchplugin', null, null, null],
|
||||
['FileGen::generate', 'power', null, null, null],
|
||||
['FileGen::generate', 'searchboxScript', null, null, null],
|
||||
['FileGen::generate', 'demo', null, null, null],
|
||||
['FileGen::generate', 'searchboxBody', null, null, null],
|
||||
['FileGen::generate', 'realmMenu', null, null, null],
|
||||
['FileGen::generate', 'locales', null, null, null],
|
||||
['FileGen::generate', 'itemScaling', null, null, null],
|
||||
['FileGen::generate', 'realms', null, null, null],
|
||||
['FileGen::generate', 'statistics', null, null, null],
|
||||
['FileGen::generate', 'simpleImg', null, null, null],
|
||||
['FileGen::generate', 'talentCalc', null, null, null],
|
||||
['FileGen::generate', 'pets', null, null, null],
|
||||
['FileGen::generate', 'talentIcons', null, null, null],
|
||||
['FileGen::generate', 'glyphs', null, null, null],
|
||||
['FileGen::generate', 'itemsets', null, null, null],
|
||||
['FileGen::generate', 'enchants', null, null, null],
|
||||
['FileGen::generate', 'gems', null, null, null],
|
||||
['FileGen::generate', 'profiler', null, null, null],
|
||||
['FileGen::generate', 'weightPresets', null, null, null],
|
||||
['FileGen::generate', 'markup', null, null, null],
|
||||
// apply sql-updates from repository
|
||||
['update', &$upd, null, null, null],
|
||||
['sync', &$upd, null, null, null],
|
||||
['account', [null, null], 'testAcc', 'Please create your admin account.', 'There is no user with administrator privileges in the DB.']
|
||||
);
|
||||
|
||||
|
||||
/**********/
|
||||
/* helper */
|
||||
/**********/
|
||||
|
||||
$saveProgress = function(int $nStep) : void
|
||||
{
|
||||
$h = fopen('cache/firstrun', 'w');
|
||||
fwrite($h, AOWOW_REVISION."\n".($nStep + 1)."\n");
|
||||
fclose($h);
|
||||
};
|
||||
|
||||
function testDB(array &$error) : bool
|
||||
{
|
||||
require 'config/config.php';
|
||||
|
||||
$error = [];
|
||||
foreach (['aowow', 'world', 'auth'] as $idx => $what)
|
||||
{
|
||||
if ($what == 'auth' && (empty($AoWoWconf['auth']) || empty($AoWoWconf['auth']['host'])))
|
||||
continue;
|
||||
|
||||
// init proper access for further setup
|
||||
if (DB::test($AoWoWconf[$what], $err))
|
||||
{
|
||||
DB::load($idx, $AoWoWconf[$what]);
|
||||
switch ($idx)
|
||||
{
|
||||
case DB_AOWOW:
|
||||
if (DB::Aowow()->selectCell('SHOW TABLES LIKE ?', 'aowow_dbversion'))
|
||||
Cfg::load(); // first time load after successful db setup
|
||||
else
|
||||
$error[] = ' * '.$what.': doesn\'t seem to contain aowow tables!';
|
||||
break;
|
||||
case DB_WORLD:
|
||||
if (!DB::World()->selectCell('SHOW TABLES LIKE ?', 'version'))
|
||||
$error[] = ' * '.$what.': doesn\'t seem to contain TrinityCore world tables!';
|
||||
else if (DB::World()->selectCell('SELECT `cache_id` FROM `version`') < TDB_WORLD_MINIMUM_VER)
|
||||
$error[] = ' * '.$what.': TDB world db is structurally outdated! (min rev.: '.CLI::bold(TDB_WORLD_MINIMUM_VER).')';
|
||||
break;
|
||||
default:
|
||||
// no further checks at this time
|
||||
}
|
||||
}
|
||||
else
|
||||
$error[] = ' * '.$what.': '.$err;
|
||||
}
|
||||
|
||||
return empty($error);
|
||||
}
|
||||
|
||||
function testSelf(array &$error) : bool
|
||||
{
|
||||
$error = [];
|
||||
$test = function(&$protocol, &$host, $testFile, &$rCode)
|
||||
{
|
||||
$res = get_headers($protocol.$host.$testFile, true);
|
||||
|
||||
if (!preg_match("/HTTP\/[0-9\.]+\s+([0-9]+)/", $res[0], $m))
|
||||
return false;
|
||||
|
||||
$rCode = $m[1];
|
||||
|
||||
if ($rCode == 200)
|
||||
return true;
|
||||
|
||||
if ($rCode == 301 || $rCode == 302)
|
||||
{
|
||||
if (!empty($res['Location']) && preg_match("/(https?:\/\/)(.*)".strtr($testFile, ['/' => '\/', '.' => '\.'])."/i", is_array($res['Location']) ? array_pop($res['Location']) : $res['Location'], $n))
|
||||
{
|
||||
$protocol = $n[1];
|
||||
$host = $n[2];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$rCode = 0;
|
||||
return false;
|
||||
};
|
||||
|
||||
if (!DB::isConnected(DB_AOWOW))
|
||||
{
|
||||
$error[] = ' * not connected to DB';
|
||||
return false;
|
||||
}
|
||||
|
||||
$prot = Cfg::get('FORCE_SSL') ? 'https://' : 'http://';
|
||||
$cases = array(
|
||||
'site_host' => [$prot, Cfg::get('SITE_HOST'), '/README.md'],
|
||||
'static_host' => [$prot, Cfg::get('STATIC_HOST'), '/css/aowow.css']
|
||||
);
|
||||
|
||||
foreach ($cases as $conf => [$protocol, $host, $testFile])
|
||||
{
|
||||
if ($host)
|
||||
{
|
||||
if (!$test($protocol, $host, $testFile, $resp))
|
||||
{
|
||||
if ($resp == 301 || $resp == 302)
|
||||
{
|
||||
CLI::write('self test received status '.CLI::bold($resp).' (page moved) for '.$conf.', pointing to: '.$protocol.$host.$testFile, CLI::LOG_WARN);
|
||||
if (!CLI::read(['x' => ['should '.CLI::bold($conf).' be set to '.CLI::bold($host).' and force_ssl be updated? (y/n)', true, true, '/y|n/i']], $uiYN) || !$uiYN || strtolower($uiYN['x']) == 'n')
|
||||
$error[] = ' * '.$protocol.$host.$testFile.' ['.$resp.']';
|
||||
else
|
||||
{
|
||||
Cfg::set($conf, $host);
|
||||
Cfg::set('FORCE_SSL', $protocol == 'https://');
|
||||
}
|
||||
|
||||
CLI::write();
|
||||
}
|
||||
else
|
||||
$error[] = ' * '.$protocol.$host.$testFile.' ['.$resp.']';
|
||||
}
|
||||
}
|
||||
else
|
||||
$error[] = ' * '.strtoupper($conf).' is empty';
|
||||
}
|
||||
|
||||
return empty($error);
|
||||
}
|
||||
|
||||
function testAcc(array &$error) : bool
|
||||
{
|
||||
$error = [];
|
||||
return !!DB::Aowow()->selectCell('SELECT `id` FROM ?_account WHERE `userPerms` = 1');
|
||||
}
|
||||
|
||||
|
||||
/********************/
|
||||
/* get current step */
|
||||
/********************/
|
||||
|
||||
$startStep = 0;
|
||||
if (file_exists('cache/firstrun'))
|
||||
{
|
||||
$rows = file('cache/firstrun');
|
||||
if ((int)$rows[0] == AOWOW_REVISION)
|
||||
$startStep = (int)$rows[1];
|
||||
}
|
||||
|
||||
if (CLISetup::getOpt('help'))
|
||||
{
|
||||
CLI::write();
|
||||
CLI::write(' usage: php aowow --setup [--locales: --mpqDataDir:]', -1, false);
|
||||
CLI::write();
|
||||
CLI::write(' Initially essential connection information are set up and basic connectivity tests are run afterwards.', -1, false);
|
||||
CLI::write(' In the main stage dbc and world data is compiled into the database and required sound, image and data files are generated.', -1, false);
|
||||
CLI::write(' This does not require further input and will take about 15-20 minutes, plus 10 minutes per additional locale.', -1, false);
|
||||
CLI::write(' Lastly pending updates are applied and you are prompted to create an administrator account.', -1, false);
|
||||
|
||||
if ($startStep)
|
||||
{
|
||||
CLI::write();
|
||||
CLI::write(' You are currently on step '.($startStep + 1).' / '.count($steps).'. You can resume or restart the setup process.', -1, false);
|
||||
}
|
||||
|
||||
CLI::write();
|
||||
return;
|
||||
}
|
||||
|
||||
if ($startStep)
|
||||
{
|
||||
|
||||
CLI::write('Found firstrun progression info. (Halted on subscript '.($steps[$startStep][1][0] ? $steps[$startStep][1] : $steps[$startStep][0]).')', CLI::LOG_INFO);
|
||||
$msg = '';
|
||||
if (!CLI::read(['x' => ['continue setup? (y/n)', true, true, '/y|n/i']], $uiYN) || !$uiYN || strtolower($uiYN['x']) == 'n')
|
||||
{
|
||||
$msg = 'Starting setup from scratch...';
|
||||
$startStep = 0;
|
||||
}
|
||||
else
|
||||
$msg = 'Resuming setup from step '.$startStep.'...';
|
||||
|
||||
CLI::write();
|
||||
CLI::write($msg);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
|
||||
/*******/
|
||||
/* run */
|
||||
/*******/
|
||||
|
||||
CLISetup::siteLock(CLISetup::LOCK_ON);
|
||||
|
||||
foreach ($steps as $idx => $step)
|
||||
{
|
||||
if ($startStep > $idx)
|
||||
continue;
|
||||
|
||||
if (!strpos($step[0], '::') && !is_callable($step[0]))
|
||||
require_once 'setup/tools/clisetup/'.$step[0].'.func.php';
|
||||
|
||||
if ($step[3])
|
||||
{
|
||||
CLI::write($step[3]);
|
||||
|
||||
if (!CLI::read([['Press any key to continue', true]])) // we don't actually care about the input
|
||||
return;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (strpos($step[0], '::'))
|
||||
$res = call_user_func($step[0], $step[1]);
|
||||
else
|
||||
{
|
||||
$args = &$step[1]; // see: https://github.com/php/php-src/issues/14202
|
||||
$res = $step[0]($args[0], $args[1]);
|
||||
}
|
||||
|
||||
// check script result
|
||||
if ($step[2])
|
||||
{
|
||||
$errors = [];
|
||||
if (!$step[2]($errors))
|
||||
{
|
||||
CLI::write($step[4], CLI::LOG_ERROR);
|
||||
foreach ($errors as $e)
|
||||
CLI::write($e);
|
||||
}
|
||||
else
|
||||
{
|
||||
$saveProgress($idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ($res !== false)
|
||||
{
|
||||
$saveProgress($idx);
|
||||
break;
|
||||
}
|
||||
|
||||
if (CLI::read(['x' => ['['.CLI::bold('c').']ontinue anyway? ['.CLI::bold('r').']etry? ['.CLI::bold('a').']bort?', true, true, '/c|r|a/i']], $uiCRA) && $uiCRA)
|
||||
{
|
||||
CLI::write();
|
||||
switch(strtolower($uiCRA['x']))
|
||||
{
|
||||
case 'c':
|
||||
$saveProgress($idx);
|
||||
break 2;
|
||||
case 'r':
|
||||
break;
|
||||
case 'a':
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CLI::write();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unlink('cache/firstrun');
|
||||
CLISetup::siteLock(CLISetup::LOCK_OFF);
|
||||
CLI::write('setup finished', CLI::LOG_OK);
|
||||
return;
|
||||
}
|
||||
|
||||
?>
|
||||
184
setup/tools/clisetup/setup.us.php
Normal file
184
setup/tools/clisetup/setup.us.php
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/*********************************************/
|
||||
/* string setup steps together for first use */
|
||||
/*********************************************/
|
||||
|
||||
CLISetup::registerUtility(new class extends UtilityScript
|
||||
{
|
||||
public $argvOpts = ['s'];
|
||||
public $optGroup = CLISetup::OPT_GRP_SETUP;
|
||||
|
||||
public const COMMAND = 'setup';
|
||||
public const DESCRIPTION = 'Step by step initial setup. Resumes if interrupted.';
|
||||
public const NOTE_END_OK = 'setup finished successfully';
|
||||
public const NOTE_END_FAIL = 'setup finished with errors';
|
||||
|
||||
public const SITE_LOCK = CLISetup::LOCK_ON;
|
||||
|
||||
private $startStep = 0;
|
||||
private $dynArgs = ['doSql' => [], 'doBuild' => []]; // ref to pass commands from 'update' to 'sync'
|
||||
private $steps = array(
|
||||
// [staticUS, $name, [...args]]
|
||||
['database', '', []],
|
||||
['configure', '', []],
|
||||
// sql- and build- stuff here
|
||||
['update', '', []],
|
||||
['sync', '', []],
|
||||
['account', '', []]
|
||||
);
|
||||
|
||||
private const STEP_FILE = 'cache/setup/firstrun';
|
||||
|
||||
// Note! Must be loaded after all SetupScripts have been registered
|
||||
public function __construct()
|
||||
{
|
||||
/********************/
|
||||
/* get current step */
|
||||
/********************/
|
||||
|
||||
if (file_exists(self::STEP_FILE))
|
||||
{
|
||||
$rows = file(self::STEP_FILE);
|
||||
if ((int)$rows[0] == AOWOW_REVISION)
|
||||
$this->startStep = (int)$rows[1];
|
||||
}
|
||||
|
||||
|
||||
/****************/
|
||||
/* define steps */
|
||||
/****************/
|
||||
|
||||
# link required steps with param
|
||||
$this->steps[2][2] = &$this->dynArgs; // update
|
||||
$this->steps[3][2] = &$this->dynArgs; // sync
|
||||
|
||||
# from /sqlgen + /filegen .. already sorted by CLISetup
|
||||
foreach (CLISetup::getSubScripts() as $name => [$invoker, $ssRef])
|
||||
{
|
||||
if ($ssRef->isOptional)
|
||||
continue;
|
||||
|
||||
if ($invoker == 'sql')
|
||||
array_splice($this->steps, -3, 0, [[$invoker, $name, ['doSql' => $name]]]);
|
||||
else if ($invoker == 'build')
|
||||
array_splice($this->steps, -3, 0, [[$invoker, $name, ['doBuild' => $name]]]);
|
||||
}
|
||||
}
|
||||
|
||||
// args: null, null, null, null // nnnn
|
||||
public function run(&$args) : bool
|
||||
{
|
||||
if ($this->startStep)
|
||||
{
|
||||
CLI::write('[setup] found firstrun progression info. (Halted on subscript: '.($this->steps[$this->startStep][1] ?: $this->steps[$this->startStep][0]).')', CLI::LOG_INFO);
|
||||
$msg = '';
|
||||
if (!CLI::read(['x' => ['continue setup? (y/n)', true, true, '/y|n/i']], $uiN) || !$uiN || strtolower($uiN['x']) == 'n')
|
||||
{
|
||||
$msg = '[setup] starting from scratch...';
|
||||
$this->startStep = 0;
|
||||
}
|
||||
else
|
||||
$msg = '[setup] resuming from step '.($this->startStep + 1).'...';
|
||||
|
||||
CLI::write();
|
||||
CLI::write($msg);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
// init temp setup dir
|
||||
if ($info = new SplFileInfo(self::STEP_FILE))
|
||||
CLISetup::writeDir($info->getPath());
|
||||
|
||||
|
||||
/*******/
|
||||
/* run */
|
||||
/*******/
|
||||
|
||||
foreach ($this->steps as $idx => [$usName, , $param])
|
||||
{
|
||||
if ($this->startStep > $idx)
|
||||
continue;
|
||||
|
||||
while (true)
|
||||
{
|
||||
CLI::write('[setup] step '.($idx + 1).' / '.count($this->steps));
|
||||
if (CLISetup::run($usName, $param))
|
||||
{
|
||||
$this->saveProgress($idx);
|
||||
break;
|
||||
}
|
||||
|
||||
if (CLI::read(['x' => ['['.CLI::bold('c').']ontinue anyway? ['.CLI::bold('r').']etry? ['.CLI::bold('a').']bort?', true, true, '/c|r|a/i']], $uiCRA) && $uiCRA)
|
||||
{
|
||||
CLI::write();
|
||||
switch(strtolower($uiCRA['x']))
|
||||
{
|
||||
case 'c':
|
||||
$this->saveProgress($idx);
|
||||
break 2;
|
||||
case 'r':
|
||||
break;
|
||||
case 'a':
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CLI::write();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unlink(self::STEP_FILE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function writeCLIHelp() : bool
|
||||
{
|
||||
CLI::write(' usage: php aowow --setup [--locales: --mpqDataDir:]', -1, false);
|
||||
CLI::write();
|
||||
CLI::write(' Initially essential connection information are set up and basic connectivity tests run afterwards.', -1, false);
|
||||
CLI::write(' In the main stage dbc and world data is compiled into the database and required sound, image and data files are generated.', -1, false);
|
||||
CLI::write(' This should not require further input and will take about 15-20 minutes, plus 10 minutes per additional locale.', -1, false);
|
||||
CLI::write(' Lastly pending updates are applied and you are prompted to create an administrator account.', -1, false);
|
||||
|
||||
if ($this->startStep)
|
||||
{
|
||||
CLI::write();
|
||||
CLI::write(' You are currently on step '.($this->startStep + 1).' / '.count($this->steps).' ('.($this->steps[$this->startStep][1] ?: $this->steps[$this->startStep][0][1]).'). You can resume or restart the setup process.', -1, false);
|
||||
}
|
||||
|
||||
CLI::write();
|
||||
CLI::write();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**********/
|
||||
/* helper */
|
||||
/**********/
|
||||
|
||||
private function saveProgress (int $nStep) : void
|
||||
{
|
||||
if ($h = fopen(self::STEP_FILE, 'w'))
|
||||
{
|
||||
fwrite($h, AOWOW_REVISION."\n".($nStep + 1)."\n");
|
||||
fclose($h);
|
||||
}
|
||||
else
|
||||
CLI::write(' * UtilScript::setup - Could not access step file', CLI::LOG_ERROR);
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,315 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/****************************/
|
||||
/* Configure Site variables */
|
||||
/****************************/
|
||||
|
||||
function siteconfig() : void
|
||||
{
|
||||
$updScripts = [];
|
||||
|
||||
if (!DB::isConnected(DB_AOWOW))
|
||||
{
|
||||
CLI::write('Database not yet set up!', CLI::LOG_WARN);
|
||||
CLI::write('Please use '.CLI::bold('"php aowow --dbconfig"').' for setup', CLI::LOG_BLANK);
|
||||
CLI::write();
|
||||
return;
|
||||
}
|
||||
|
||||
function toOptList(string $options, $curVal, bool $bitmask = false) : string
|
||||
{
|
||||
$result = '';
|
||||
foreach (explode(', ', $options) as $opt)
|
||||
{
|
||||
[$val, $name] = explode(':', $opt);
|
||||
$equal = $bitmask ? ($curVal & (1 << $val)) : $curVal == $val;
|
||||
|
||||
$result .= '['.($equal ? 'x' : ' ').']'.$name.' ';
|
||||
}
|
||||
|
||||
return substr($result, 0, -1);
|
||||
}
|
||||
|
||||
function formatValue($value, $flags, $opts) : string
|
||||
{
|
||||
if ($flags & Cfg::FLAG_TYPE_BOOL)
|
||||
return '[bool] '.($value ? '<Enabled>' : '<Disabled>');
|
||||
|
||||
if ($flags & Cfg::FLAG_OPT_LIST)
|
||||
return '[opt] '.toOptList($opts, $value, false);
|
||||
|
||||
if ($flags & Cfg::FLAG_BITMASK)
|
||||
return '[mask] '.toOptList($opts, $value, true);
|
||||
|
||||
if ($flags & Cfg::FLAG_TYPE_FLOAT)
|
||||
return '[float] '.floatVal($value);
|
||||
|
||||
if ($flags & Cfg::FLAG_TYPE_INT)
|
||||
return '[int] '.intVal($value);
|
||||
|
||||
// if ($flags & Cfg::FLAG_TYPE_STRING)
|
||||
if ($value === '')
|
||||
return '[str] '.(($flags & Cfg::FLAG_REQUIRED) ? CLI::red('<empty>') : CLI::grey('<empty>'));
|
||||
else
|
||||
return '[str] "'.$value.'"';
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
CLI::write('select a numerical index or name to use the corresponding entry');
|
||||
CLI::write();
|
||||
|
||||
$sumNum = 0;
|
||||
$cfgList = [];
|
||||
$hasEmpty = false;
|
||||
$listBuff = [];
|
||||
|
||||
foreach (Cfg::$categories as $idx => $cat)
|
||||
{
|
||||
$listBuff[] = '===== '.$cat.' =====';
|
||||
|
||||
foreach (Cfg::forCategory($idx) as $key => [$value, $flags, $catg, $default, $comment])
|
||||
{
|
||||
$isPhp = $flags & Cfg::FLAG_PHP;
|
||||
|
||||
if ($value === '' && ($flags & Cfg::FLAG_REQUIRED))
|
||||
$hasEmpty = true;
|
||||
|
||||
$cfgList[$sumNum] = strtolower($key);
|
||||
|
||||
$row = '['.CLI::bold($sumNum).'] '.(($sumNum) > 9 ? '' : ' ').($isPhp ? ' PHP ' : ' AOWOW ');
|
||||
$row .= str_pad($isPhp ? strtolower($key) : strtoupper($key), 35);
|
||||
|
||||
$opts = explode(' - ', $comment);
|
||||
$row .= formatValue($value, $flags, $opts[1] ?? '');
|
||||
|
||||
$listBuff[] = $row;
|
||||
$sumNum++;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($listBuff as $b)
|
||||
CLI::write($b);
|
||||
|
||||
CLI::write(str_pad('['.CLI::bold($sumNum).']', 21).'add another php configuration');
|
||||
CLI::write();
|
||||
|
||||
if ($hasEmpty)
|
||||
{
|
||||
CLI::write('please configure the required empty settings', CLI::LOG_WARN);
|
||||
CLI::write();
|
||||
}
|
||||
|
||||
if (CLI::read(['idx' => ['', false, false, Cfg::PATTERN_CONF_KEY]], $uiIndex) && $uiIndex && $uiIndex['idx'] !== '')
|
||||
{
|
||||
$idx = array_search(strtolower($uiIndex['idx']), $cfgList);
|
||||
if ($idx === false)
|
||||
$idx = intVal($uiIndex['idx']);
|
||||
|
||||
// add new php setting
|
||||
if ($idx == $sumNum)
|
||||
{
|
||||
CLI::write('Adding additional php configuration.');
|
||||
CLI::write();
|
||||
|
||||
while (true)
|
||||
{
|
||||
$setting = array(
|
||||
'key' => ['option name', false, false, Cfg::PATTERN_CONF_KEY],
|
||||
'val' => ['value', ]
|
||||
);
|
||||
if (CLI::read($setting, $uiSetting) && $uiSetting)
|
||||
{
|
||||
$key = strtolower($uiSetting['key']);
|
||||
if ($err = Cfg::add($key, $uiSetting['val']))
|
||||
CLI::write($err, CLI::LOG_ERROR);
|
||||
else
|
||||
CLI::write('new php configuration added', CLI::LOG_OK);
|
||||
|
||||
sleep(1);
|
||||
CLI::write();
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
CLI::write('edit canceled! returning to list...', CLI::LOG_INFO);
|
||||
CLI::write();
|
||||
sleep(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// edit existing setting
|
||||
else if ($idx >= 0 && $idx < $sumNum)
|
||||
{
|
||||
[$value, $flags, , $default, $comment] = Cfg::get($cfgList[$idx], false, true);
|
||||
$key = $cfgList[$idx];
|
||||
$info = explode(' - ', $comment);
|
||||
$buff = '';
|
||||
|
||||
$buff .= $flags & Cfg::FLAG_PHP ? 'PHP: ' : 'AOWOW: ';
|
||||
$buff .= $flags & Cfg::FLAG_PHP ? $key : 'Cfg::'.strtoupper($key);
|
||||
|
||||
if (!empty($info[0]))
|
||||
$buff .= ' - '.$info[0];
|
||||
|
||||
CLI::write($buff);
|
||||
CLI::write();
|
||||
CLI::write('VALUE: '.formatValue($value, $flags, $info[1] ?? ''));
|
||||
CLI::write();
|
||||
CLI::write('['.CLI::bold('E').']dit');
|
||||
|
||||
if (!($flags & Cfg::FLAG_PERSISTENT))
|
||||
CLI::write('['.CLI::bold('D').']elete');
|
||||
|
||||
if ($default)
|
||||
CLI::write('['.CLI::bold('R').']estore Default - '.$default);
|
||||
|
||||
CLI::write();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (CLI::read(['idx' => ['', true, true, '/[edr]/i']], $uiEDR) && $uiEDR)
|
||||
{
|
||||
switch (strtoupper($uiEDR['idx']))
|
||||
{
|
||||
case 'E': // edit value
|
||||
$pattern = false;
|
||||
$single = false;
|
||||
$prompt = ['idx' => ['Select new value', false, &$single, &$pattern]];
|
||||
|
||||
if ($flags & Cfg::FLAG_OPT_LIST)
|
||||
{
|
||||
foreach (explode(', ', $info[1]) as $option)
|
||||
{
|
||||
[$val, $name] = explode(':', $option);
|
||||
CLI::write('['.CLI::bold($val).'] '.$name);
|
||||
}
|
||||
$single = true;
|
||||
$pattern = '/\d/';
|
||||
}
|
||||
else if ($flags & Cfg::FLAG_BITMASK)
|
||||
{
|
||||
CLI::write('Bitmask: sum fields to select multiple options');
|
||||
foreach (explode(', ', $info[1]) as $option)
|
||||
{
|
||||
[$val, $name] = explode(':', $option);
|
||||
CLI::write('['.CLI::bold(1 << $val).']'.str_pad('', 6 - strlen(1 << $val)).$name);
|
||||
}
|
||||
$pattern = '/\d+/';
|
||||
}
|
||||
else if ($flags & Cfg::FLAG_TYPE_BOOL)
|
||||
{
|
||||
CLI::write('['.CLI::bold(0).'] Disabled');
|
||||
CLI::write('['.CLI::bold(1).'] Enabled');
|
||||
|
||||
$single = true;
|
||||
$pattern = '/[01]/';
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (CLI::read($prompt, $uiValue))
|
||||
{
|
||||
CLI::write();
|
||||
|
||||
$inp = $uiValue['idx'] ?? '';
|
||||
|
||||
if ($err = Cfg::set($key, $inp, $updScripts))
|
||||
{
|
||||
CLI::write($err, CLI::LOG_ERROR);
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
CLI::write('setting updated', CLI::LOG_OK);
|
||||
sleep(1);
|
||||
break 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CLI::write('edit canceled! returning to selection...', CLI::LOG_INFO);
|
||||
sleep(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break 2;
|
||||
case 'R': // restore default
|
||||
if (!$default)
|
||||
continue 2;
|
||||
|
||||
if ($err = Cfg::reset($key, $updScripts))
|
||||
CLI::write($err, CLI::LOG_ERROR);
|
||||
else
|
||||
CLI::write('default value restored', CLI::LOG_OK);
|
||||
|
||||
sleep(1);
|
||||
break 2;
|
||||
case 'D': // delete config pair
|
||||
if ($flags & Cfg::FLAG_PERSISTENT)
|
||||
continue 2;
|
||||
|
||||
if ($err = Cfg::delete($key))
|
||||
CLI::write($err, CLI::LOG_ERROR);
|
||||
else
|
||||
CLI::write("php setting deleted ['".$key."': '".$value."']", CLI::LOG_OK);
|
||||
|
||||
sleep(1);
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CLI::write('edit canceled! returning to list...', CLI::LOG_INFO);
|
||||
CLI::write();
|
||||
sleep(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CLI::write('invalid selection', CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CLI::write('leaving site configuration...', CLI::LOG_INFO);
|
||||
CLI::write();
|
||||
break;
|
||||
}
|
||||
|
||||
// propagate changes to static files
|
||||
if ($updScripts && (!class_exists('FileGen') || FileGen::getMode() != FileGen::MODE_FIRSTRUN))
|
||||
{
|
||||
require_once 'setup/tools/clisetup/build.func.php';
|
||||
CLI::write();
|
||||
CLI::write('regenerating affected static content', CLI::LOG_INFO);
|
||||
CLI::write();
|
||||
sleep(1);
|
||||
|
||||
if ($_ = array_diff($updScripts, build($updScripts)))
|
||||
{
|
||||
CLI::write(' - the following updates returned with errors, please recheck those - '.implode(', ', $_), CLI::LOG_ERROR);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
sleep(1);
|
||||
$updScripts = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
468
setup/tools/clisetup/siteconfig.us.php
Normal file
468
setup/tools/clisetup/siteconfig.us.php
Normal file
@@ -0,0 +1,468 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/****************************/
|
||||
/* Configure Site variables */
|
||||
/****************************/
|
||||
|
||||
CLISetup::registerUtility(new class extends UtilityScript
|
||||
{
|
||||
public $argvOpts = ['c'];
|
||||
public $optGroup = CLISetup::OPT_GRP_SETUP;
|
||||
public $followupFn = 'build';
|
||||
|
||||
public const COMMAND = 'configure';
|
||||
public const APPENDIX = ' [action<E|R|N|D> cfgName [newValue]]';
|
||||
public const DESCRIPTION = 'Configure site variables.';
|
||||
public const PROMPT = 'SITE_HOST and STATIC_HOST *must* be set. Also enable FORCE_SSL if needed. You may also want to change other variables such as NAME, NAME_SHORT or LOCALES.';
|
||||
public const NOTE_ERROR = 'could not access:';
|
||||
|
||||
public const REQUIRED_DB = [DB_AOWOW];
|
||||
|
||||
public const USE_CLI_ARGS = true;
|
||||
|
||||
private const HTTP_STATUS_OK = 200;
|
||||
private const HTTP_STATUS_MOVED_PERM = 301;
|
||||
private const HTTP_STATUS_MOVED_TEMP = 302;
|
||||
|
||||
private $updScripts = [];
|
||||
|
||||
// args: action, configName, configValue, pendingUpdates[] // iiio
|
||||
public function run(&$args) : bool
|
||||
{
|
||||
$action = $args[0] ?? '';
|
||||
$name = $args[1] ?? '';
|
||||
$value = $args[2] ?? '';
|
||||
|
||||
$result = true;
|
||||
switch (strtoupper($action))
|
||||
{
|
||||
case 'E':
|
||||
$result = $this->doEdit($name, $value);
|
||||
break;
|
||||
case 'R':
|
||||
$result = $this->doRestore($name);
|
||||
break;
|
||||
case 'N':
|
||||
$result = $this->doNew($name, $value);
|
||||
break;
|
||||
case 'D':
|
||||
$result = $this->doDelete($name);
|
||||
break;
|
||||
default:
|
||||
$this->showConfigList();
|
||||
}
|
||||
|
||||
$args['doBuild'] = $this->updScripts; // push files to rebuild one level up
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function showConfigList() : void
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
CLI::write('select a numerical index or name to use the corresponding entry', -1, false);
|
||||
CLI::write();
|
||||
|
||||
$sumNum = 0;
|
||||
$cfgList = [];
|
||||
$hasEmpty = false;
|
||||
$listBuff = [];
|
||||
|
||||
foreach (Cfg::$categories as $idx => $cat)
|
||||
{
|
||||
$listBuff[] = '===== '.$cat.' =====';
|
||||
|
||||
foreach (Cfg::forCategory($idx) as $key => [$value, $flags, $catg, $default, $comment])
|
||||
{
|
||||
$isPhp = $flags & Cfg::FLAG_PHP;
|
||||
|
||||
if ($value === '' && ($flags & Cfg::FLAG_REQUIRED))
|
||||
$hasEmpty = true;
|
||||
|
||||
$cfgList[$sumNum] = strtolower($key);
|
||||
|
||||
$row = '['.CLI::bold($sumNum).'] '.(($sumNum) > 9 ? '' : ' ').($isPhp ? ' PHP ' : ' AOWOW ');
|
||||
$row .= str_pad($isPhp ? strtolower($key) : strtoupper($key), 35);
|
||||
|
||||
$opts = explode(' - ', $comment);
|
||||
$row .= $this->formatValue($value, $flags, $opts[1] ?? '');
|
||||
|
||||
$listBuff[] = $row;
|
||||
$sumNum++;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($listBuff as $b)
|
||||
CLI::write($b, -1, false);
|
||||
|
||||
CLI::write(str_pad('['.CLI::bold($sumNum).']', 21).'add another php configuration', -1, false);
|
||||
CLI::write();
|
||||
|
||||
if ($hasEmpty)
|
||||
{
|
||||
CLI::write('please configure the required empty settings', CLI::LOG_WARN);
|
||||
CLI::write();
|
||||
}
|
||||
|
||||
if (CLI::read(['idx' => ['', false, false, Cfg::PATTERN_CONF_KEY]], $uiIndex) && $uiIndex && $uiIndex['idx'] !== '')
|
||||
{
|
||||
$idx = array_search(strtolower($uiIndex['idx']), $cfgList);
|
||||
if ($idx === false)
|
||||
$idx = intVal($uiIndex['idx']);
|
||||
|
||||
// add new php setting
|
||||
if ($idx == $sumNum)
|
||||
$this->showNewConfig();
|
||||
// edit existing setting
|
||||
else if ($idx >= 0 && $idx < $sumNum)
|
||||
$this->showEditConfig($cfgList[$idx] ?? '');
|
||||
else
|
||||
CLI::write('invalid selection', CLI::LOG_ERROR);
|
||||
|
||||
CLI::write();
|
||||
sleep(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
CLI::write('leaving site configuration...', CLI::LOG_INFO);
|
||||
CLI::write();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function showNewConfig() : void
|
||||
{
|
||||
CLI::write('Adding additional php configuration.');
|
||||
CLI::write();
|
||||
|
||||
$setting = array(
|
||||
'key' => ['option name', false, false, Cfg::PATTERN_CONF_KEY],
|
||||
'val' => ['value', ]
|
||||
);
|
||||
if (CLI::read($setting, $uiSetting) && $uiSetting)
|
||||
$this->doNew($uiSetting['key'], $uiSetting['val']);
|
||||
else
|
||||
CLI::write('edit canceled! returning to list...', CLI::LOG_INFO);
|
||||
}
|
||||
|
||||
private function showEditConfig(string $key) : void
|
||||
{
|
||||
[$value, $flags, , $default, $comment] = Cfg::get($key, false, true);
|
||||
$info = explode(' - ', $comment);
|
||||
$buff = '';
|
||||
|
||||
$buff .= $flags & Cfg::FLAG_PHP ? 'PHP: ' : 'AOWOW: ';
|
||||
$buff .= $flags & Cfg::FLAG_PHP ? $key : 'Cfg::'.strtoupper($key);
|
||||
|
||||
if (!empty($info[0]))
|
||||
$buff .= ' - '.$info[0];
|
||||
|
||||
CLI::write($buff);
|
||||
CLI::write();
|
||||
|
||||
CLI::write('VALUE: '.$this->formatValue($value, $flags, $info[1] ?? ''));
|
||||
CLI::write();
|
||||
CLI::write('['.CLI::bold('E').']dit');
|
||||
|
||||
if (!($flags & Cfg::FLAG_PERSISTENT))
|
||||
CLI::write('['.CLI::bold('D').']elete');
|
||||
|
||||
if ($default)
|
||||
CLI::write('['.CLI::bold('R').']estore Default - '.$default);
|
||||
|
||||
CLI::write();
|
||||
|
||||
while (true)
|
||||
{
|
||||
CLI::write();
|
||||
sleep(1);
|
||||
|
||||
if (CLI::read(['idx' => ['', true, true, '/[edr]/i']], $uiEDR) && $uiEDR)
|
||||
{
|
||||
switch (strtoupper($uiEDR['idx']))
|
||||
{
|
||||
case 'E': // edit value
|
||||
if (!$this->doEdit($key))
|
||||
continue 2;
|
||||
break 2;
|
||||
case 'R': // restore default
|
||||
if (!$this->doRestore($key))
|
||||
continue 2;
|
||||
break 2;
|
||||
case 'D': // delete config pair
|
||||
if (!$this->doDelete($key))
|
||||
continue 2;
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CLI::write('edit canceled! returning to list...', CLI::LOG_INFO);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function doEdit(string $key, ?string $newVal = null) : bool
|
||||
{
|
||||
[, $flags, , , $comment] = Cfg::get($key, false, true);
|
||||
$info = explode(' - ', $comment);
|
||||
|
||||
$pattern = '/.*/';
|
||||
$single = false;
|
||||
$typeHint = [];
|
||||
|
||||
if ($flags & Cfg::FLAG_OPT_LIST)
|
||||
{
|
||||
foreach (explode(', ', $info[1]) as $option)
|
||||
{
|
||||
[$val, $name] = explode(':', $option);
|
||||
CLI::write('['.CLI::bold($val).'] '.$name);
|
||||
}
|
||||
$single = true;
|
||||
$pattern = '/^\d$/';
|
||||
}
|
||||
else if ($flags & Cfg::FLAG_BITMASK)
|
||||
{
|
||||
$typeHint[] = 'Bitmask: sum fields to select multiple options';
|
||||
foreach (explode(', ', $info[1]) as $option)
|
||||
{
|
||||
[$val, $name] = explode(':', $option);
|
||||
CLI::write('['.CLI::bold(1 << $val).']'.str_pad('', 6 - strlen(1 << $val)).$name);
|
||||
}
|
||||
$pattern = '/^\d+$/';
|
||||
}
|
||||
else if ($flags & Cfg::FLAG_TYPE_BOOL)
|
||||
{
|
||||
$typeHint[] = '['.CLI::bold(0).'] Disabled';
|
||||
$typeHint[] = '['.CLI::bold(1).'] Enabled';
|
||||
|
||||
$single = true;
|
||||
$pattern = '/^[01]$/';
|
||||
}
|
||||
else if ($flags & Cfg::FLAG_TYPE_INT)
|
||||
$pattern = '/^-?\d+$/';
|
||||
else if ($flags & Cfg::FLAG_TYPE_FLOAT)
|
||||
$pattern = '/^-?\d*(,|.)?\d+$/i';
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!isset($newVal))
|
||||
foreach ($typeHint as $th)
|
||||
CLI::write($th);
|
||||
|
||||
if ((isset($newVal) && preg_match($pattern, $newVal)) || CLI::read(['idx' => ['Select new value', false, $single, $pattern]], $uiValue))
|
||||
{
|
||||
CLI::write();
|
||||
|
||||
$val = $newVal ?? $uiValue['idx'] ?? '';
|
||||
if ($err = Cfg::set($key, $val, $this->updScripts))
|
||||
{
|
||||
CLI::write($err, CLI::LOG_ERROR);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
CLI::write('setting updated', CLI::LOG_OK);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CLI::write('edit canceled! returning to selection...', CLI::LOG_INFO);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function doRestore(string $key) : bool
|
||||
{
|
||||
if ($err = Cfg::reset($key, $this->updScripts))
|
||||
{
|
||||
CLI::write($err, CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
CLI::write('default value restored', CLI::LOG_OK);
|
||||
return true;
|
||||
}
|
||||
|
||||
private function doNew(string $key, string $val) : bool
|
||||
{
|
||||
if ($err = Cfg::add($key, $val))
|
||||
{
|
||||
CLI::write($err, CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
CLI::write('new php configuration added', CLI::LOG_OK);
|
||||
return true;
|
||||
}
|
||||
|
||||
private function doDelete(string $key) : bool
|
||||
{
|
||||
if ($err = Cfg::delete($key))
|
||||
{
|
||||
CLI::write($err, CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
CLI::write('php setting deleted: '.$key, CLI::LOG_OK);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/******************/
|
||||
/* Unit formating */
|
||||
/******************/
|
||||
|
||||
private function toOptList(string $options, $curVal, bool $bitmask = false) : string
|
||||
{
|
||||
$result = '';
|
||||
foreach (explode(', ', $options) as $opt)
|
||||
{
|
||||
[$val, $name] = explode(':', $opt);
|
||||
$equal = $bitmask ? ($curVal & (1 << $val)) : $curVal == $val;
|
||||
|
||||
$result .= '['.($equal ? 'x' : ' ').']'.$name.' ';
|
||||
}
|
||||
|
||||
return substr($result, 0, -1);
|
||||
}
|
||||
|
||||
private function formatValue($value, int $flags, string $opts) : string
|
||||
{
|
||||
if ($flags & Cfg::FLAG_TYPE_BOOL)
|
||||
return '[bool] '.($value ? '<Enabled>' : '<Disabled>');
|
||||
|
||||
if ($flags & Cfg::FLAG_OPT_LIST)
|
||||
return '[opt] '.$this->toOptList($opts, $value, false);
|
||||
|
||||
if ($flags & Cfg::FLAG_BITMASK)
|
||||
return '[mask] '.$this->toOptList($opts, $value, true);
|
||||
|
||||
if ($flags & Cfg::FLAG_TYPE_FLOAT)
|
||||
return '[float] '.floatVal($value);
|
||||
|
||||
if ($flags & Cfg::FLAG_TYPE_INT)
|
||||
return '[int] '.intVal($value);
|
||||
|
||||
// if ($flags & Cfg::FLAG_TYPE_STRING)
|
||||
if ($value === '')
|
||||
return '[str] '.(($flags & Cfg::FLAG_REQUIRED) ? CLI::red('<empty>') : CLI::grey('<empty>'));
|
||||
else
|
||||
return '[str] "'.$value.'"';
|
||||
}
|
||||
|
||||
|
||||
/****************/
|
||||
/* Help display */
|
||||
/****************/
|
||||
|
||||
public function writeCLIHelp(string ...$ss) : bool
|
||||
{
|
||||
CLI::write(' usage: php aowow --configure [action cfgName [newValue]]', -1, false);
|
||||
CLI::write();
|
||||
CLI::write(' Configures site and php variables. If incomplete parameters are passed an interactive prompt will open.', -1, false);
|
||||
CLI::write();
|
||||
CLI::write(' action:', -1, false);
|
||||
CLI::write(' E - Edit variable named '.CLI::bold('cfgName').'. Optionally directly pass a new value.', -1, false);
|
||||
CLI::write(' R - Restore default value of a variable '.CLI::bold('cfgName').'.', -1, false);
|
||||
CLI::write(' N - Create a new php config value. Must be a valid php directive. Optionally directly pass a new value.', -1, false);
|
||||
CLI::write(' D - Delete an existing php config value.', -1, false);
|
||||
CLI::write();
|
||||
CLI::write();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/***********/
|
||||
/* DB test */
|
||||
/***********/
|
||||
|
||||
public function test(?array &$error = []) : bool
|
||||
{
|
||||
$error = [];
|
||||
|
||||
if (!DB::isConnected(DB_AOWOW))
|
||||
{
|
||||
$error[] = ' * not connected to DB';
|
||||
return false;
|
||||
}
|
||||
|
||||
$prot = Cfg::get('FORCE_SSL') ? 'https://' : 'http://';
|
||||
$cases = array(
|
||||
'site_host' => [$prot, Cfg::get('SITE_HOST'), '/robots.txt'],
|
||||
'static_host' => [$prot, Cfg::get('STATIC_HOST'), '/css/aowow.css']
|
||||
);
|
||||
|
||||
foreach ($cases as $conf => [$protocol, $host, $testFile])
|
||||
{
|
||||
if ($host)
|
||||
{
|
||||
$resp = 0;
|
||||
if (!$this->testCase($protocol, $host, $testFile, $resp))
|
||||
{
|
||||
if ($resp == self::HTTP_STATUS_MOVED_PERM || $resp == self::HTTP_STATUS_MOVED_TEMP)
|
||||
{
|
||||
CLI::write('self test received status '.CLI::bold($resp).' (page moved) for '.$conf.', pointing to: '.$protocol.$host.$testFile, CLI::LOG_WARN);
|
||||
if (!CLI::read(['x' => ['should '.CLI::bold($conf).' be set to '.CLI::bold($host).' and force_ssl be updated? (y/n)', true, true, '/y|n/i']], $uiN) || !$uiN || strtolower($uiN['x']) == 'n')
|
||||
$error[] = ' * '.$protocol.$host.$testFile.' ['.$resp.']';
|
||||
else
|
||||
{
|
||||
Cfg::set($conf, $host);
|
||||
Cfg::set('FORCE_SSL', $protocol == 'https://');
|
||||
}
|
||||
|
||||
CLI::write();
|
||||
}
|
||||
else
|
||||
$error[] = ' * '.$protocol.$host.$testFile.' ['.$resp.']';
|
||||
}
|
||||
}
|
||||
else
|
||||
$error[] = ' * '.strtoupper($conf).' is empty';
|
||||
}
|
||||
|
||||
return empty($error);
|
||||
}
|
||||
|
||||
private function testCase(&$protocol, &$host, $testFile, &$status) : bool
|
||||
{
|
||||
$res = get_headers($protocol.$host.$testFile, true);
|
||||
|
||||
if (!preg_match('/HTTP\/[0-9\.]+\s+([0-9]+)/', $res[0], $m))
|
||||
return false;
|
||||
|
||||
$status = $m[1];
|
||||
|
||||
if ($status == self::HTTP_STATUS_OK)
|
||||
return true;
|
||||
|
||||
if ($status == self::HTTP_STATUS_MOVED_PERM || $status == self::HTTP_STATUS_MOVED_TEMP)
|
||||
{
|
||||
if (!empty($res['Location']) && preg_match('/(https?:\/\/)(.*)'.strtr($testFile, ['/' => '\/', '.' => '\.']).'/i', is_array($res['Location']) ? $res['Location'][0] : $res['Location'], $n))
|
||||
{
|
||||
$protocol = $n[1];
|
||||
$host = $n[2];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$status = 0;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,68 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/************************************************/
|
||||
/* Create content from world tables / dbc files */
|
||||
/************************************************/
|
||||
|
||||
function sql($syncMe = null) : array
|
||||
{
|
||||
if (!DB::isConnected(DB_AOWOW) || !DB::isConnected(DB_WORLD))
|
||||
{
|
||||
CLI::write('Database not yet set up!', CLI::LOG_WARN);
|
||||
CLI::write('Please use '.CLI::bold('"php aowow --dbconfig"').' for setup', CLI::LOG_BLANK);
|
||||
CLI::write();
|
||||
return [];
|
||||
}
|
||||
|
||||
require_once 'setup/tools/sqlGen.class.php';
|
||||
|
||||
if (!SqlGen::init($syncMe !== null ? SqlGen::MODE_UPDATE : SqlGen::MODE_NORMAL, $syncMe ?: []))
|
||||
return [];
|
||||
|
||||
$done = [];
|
||||
if (SqlGen::$subScripts)
|
||||
{
|
||||
CLISetup::siteLock(CLISetup::LOCK_ON);
|
||||
$allOk = true;
|
||||
|
||||
// start file generation
|
||||
CLI::write('begin generation of '. implode(', ', SqlGen::$subScripts));
|
||||
CLI::write();
|
||||
|
||||
foreach (SqlGen::$subScripts as $tbl)
|
||||
{
|
||||
$syncIds = []; // todo: fetch what exactly must be regenerated
|
||||
|
||||
$ok = SqlGen::generate($tbl, $syncIds);
|
||||
if (!$ok)
|
||||
$allOk = false;
|
||||
else
|
||||
$done[] = $tbl;
|
||||
|
||||
CLI::write(' - subscript \''.$tbl.'\' returned '.($ok ? 'successfully' : 'with errors'), $ok ? CLI::LOG_OK : CLI::LOG_ERROR);
|
||||
set_time_limit(SqlGen::$defaultExecTime); // reset to default for the next script
|
||||
}
|
||||
|
||||
// end
|
||||
CLI::write();
|
||||
if ($allOk)
|
||||
CLI::write('successfully finished sql generation', CLI::LOG_OK);
|
||||
else
|
||||
CLI::write('finished sql generation with errors', CLI::LOG_ERROR);
|
||||
|
||||
CLISetup::siteLock(CLISetup::LOCK_RESTORE);
|
||||
}
|
||||
else if (SqlGen::getMode() == SqlGen::MODE_NORMAL)
|
||||
CLI::write('no valid script names supplied', CLI::LOG_ERROR);
|
||||
|
||||
return $done;
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/************************************************/
|
||||
/* automaticly synchronize with TC world tables */
|
||||
/************************************************/
|
||||
|
||||
|
||||
require_once 'setup/tools/clisetup/sql.func.php';
|
||||
require_once 'setup/tools/clisetup/build.func.php';
|
||||
|
||||
function sync(array $s = [], array $b = []) : void
|
||||
{
|
||||
if ((!$s && !$b && !CLISetup::getOpt('sync') && !CLISetup::getOpt('setup')) || CLISetup::getOpt('help'))
|
||||
{
|
||||
CLI::write();
|
||||
CLI::write(' usage: php aowow --sync=<tableList,> [--locales: --mpqDataDir: --force -f]', -1, false);
|
||||
CLI::write();
|
||||
CLI::write(' Truncates and recreates AoWoW tables and static data files that depend on the given TC world table. Use this command after you updated your world database.', -1, false);
|
||||
CLI::write();
|
||||
CLI::write(' e.g.: "php aowow --sync=creature_queststarter" causes the table aowow_quests_startend to be recreated.', -1, false);
|
||||
CLI::write(' Also quest-related profiler files will be recreated as they depend on aowow_quests_startend and thus indirectly on creature_queststarter.', -1, false);
|
||||
CLI::write();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!DB::isConnected(DB_AOWOW) || !DB::isConnected(DB_WORLD))
|
||||
{
|
||||
CLI::write('Database not yet set up!', CLI::LOG_WARN);
|
||||
CLI::write('Please use '.CLI::bold('"php aowow --dbconfig"').' for setup', CLI::LOG_BLANK);
|
||||
CLI::write();
|
||||
return;
|
||||
}
|
||||
|
||||
$_s = sql($s);
|
||||
if ($s)
|
||||
{
|
||||
$_ = array_diff($s, $_s);
|
||||
DB::Aowow()->query('UPDATE ?_dbversion SET `sql` = ?', $_ ? implode(' ', $_) : '');
|
||||
}
|
||||
|
||||
$_b = build($b);
|
||||
if ($b)
|
||||
{
|
||||
$_ = array_diff($b, $_b);
|
||||
DB::Aowow()->query('UPDATE ?_dbversion SET `build` = ?', $_ ? implode(' ', $_) : '');
|
||||
}
|
||||
|
||||
if (!$s && !$_s && !$b && !$_b && !CLISetup::getOpt('setup'))
|
||||
CLI::write('no valid table names supplied', CLI::LOG_ERROR);
|
||||
}
|
||||
|
||||
?>
|
||||
104
setup/tools/clisetup/sync.us.php
Normal file
104
setup/tools/clisetup/sync.us.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/************************************************/
|
||||
/* automaticly synchronize with TC world tables */
|
||||
/************************************************/
|
||||
|
||||
CLISetup::registerUtility(new class extends UtilityScript
|
||||
{
|
||||
public $argvFlags = CLISetup::ARGV_ARRAY | CLISetup::ARGV_OPTIONAL;
|
||||
public $optGroup = CLISetup::OPT_GRP_UTIL;
|
||||
|
||||
public const COMMAND = 'sync';
|
||||
public const DESCRIPTION = 'Regenerate tables/files that depend on given world DB table.';
|
||||
public const APPENDIX = '=<worldTableList,>';
|
||||
|
||||
public const REQUIRED_DB = [DB_AOWOW, DB_WORLD];
|
||||
|
||||
// sqlToDo, buildToDo, null, null // iinn
|
||||
public function run(&$args) : bool
|
||||
{
|
||||
$s = &$args['doSql'];
|
||||
$b = &$args['doBuild'];
|
||||
|
||||
// called manually
|
||||
if ($s === null && $b === null)
|
||||
{
|
||||
[$s, $b] = $this->handleCLIOpt();
|
||||
if (!$s && !$b && !CLISetup::getOpt('setup'))
|
||||
{
|
||||
CLI::write('[sync] no valid table names supplied', CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($s)
|
||||
{
|
||||
$io = ['doSql' => $s, 'doneSql' => []];
|
||||
CLISetup::run('sql', $io);
|
||||
DB::Aowow()->query('UPDATE ?_dbversion SET `sql` = ?', implode(' ', array_diff($io['doSql'], $io['doneSql'])));
|
||||
}
|
||||
|
||||
if ($b)
|
||||
{
|
||||
$io = ['doBuild' => $b, 'doneBuild' => []];
|
||||
CLISetup::run('build', $io);
|
||||
DB::Aowow()->query('UPDATE ?_dbversion SET `build` = ?', implode(' ', array_diff($io['doBuild'], $io['doneBuild'])));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function handleCLIOpt() : array
|
||||
{
|
||||
$sql = [];
|
||||
$build = [];
|
||||
|
||||
$sync = CLISetup::getOpt('sync');
|
||||
if (!$sync)
|
||||
return [$sql, $build];
|
||||
|
||||
foreach (CLISetup::getSubScripts() as $name => [$invoker, $ssRef])
|
||||
if (array_intersect($ssRef->getRemoteDependencies(), $sync))
|
||||
$$invoker[] = $name;
|
||||
|
||||
do
|
||||
{
|
||||
$n = count($sql);
|
||||
foreach (CLISetup::getSubScripts('sql') as $name => [, $ssRef])
|
||||
if (!in_array($name, $sql) && array_intersect($ssRef->getSelfDependencies()[0], $sql))
|
||||
$sql[] = $name;
|
||||
}
|
||||
while ($n != count($sql));
|
||||
|
||||
if ($sql)
|
||||
foreach (CLISetup::getSubScripts('build') as $name => [, $ssRef])
|
||||
if (array_intersect($ssRef->getSelfDependencies()[0], $sql))
|
||||
$build[] = $name;
|
||||
|
||||
return [array_unique($sql), array_unique($build)];
|
||||
}
|
||||
|
||||
public function writeCLIHelp() : bool
|
||||
{
|
||||
CLI::write(' usage: php aowow --sync=<tableList,> [--locales: --mpqDataDir: --force -f]', -1, false);
|
||||
CLI::write();
|
||||
CLI::write(' Truncates and recreates AoWoW tables and static data files that depend on the given TC world table. Use this command after you updated your world database.', -1, false);
|
||||
CLI::write();
|
||||
CLI::write(' e.g.: "php aowow --sync=creature_queststarter" causes the table aowow_quests_startend to be recreated.', -1, false);
|
||||
CLI::write(' Also quest-related profiler files will be recreated as they depend on aowow_quests_startend and thus indirectly on creature_queststarter.', -1, false);
|
||||
CLI::write();
|
||||
CLI::write();
|
||||
|
||||
return true;
|
||||
}
|
||||
})
|
||||
|
||||
?>
|
||||
@@ -1,99 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/*********************************/
|
||||
/* automaticly apply sql-updates */
|
||||
/*********************************/
|
||||
|
||||
function update(?array &$sql = [], ?array &$build = []) : void
|
||||
{
|
||||
if (!DB::isConnected(DB_AOWOW))
|
||||
{
|
||||
CLI::write('Database not yet set up!', CLI::LOG_WARN);
|
||||
CLI::write('Please use '.CLI::bold('"php aowow --dbconfig"').' for setup', CLI::LOG_BLANK);
|
||||
CLI::write();
|
||||
return;
|
||||
}
|
||||
|
||||
[$date, $part] = array_values(DB::Aowow()->selectRow('SELECT `date`, `part` FROM ?_dbversion'));
|
||||
|
||||
if (CLISetup::getOpt('help'))
|
||||
{
|
||||
CLI::write();
|
||||
CLI::write(' usage: php aowow --update', -1, false);
|
||||
CLI::write();
|
||||
CLI::write(' Checks /setup/updates for new *.sql files and applies them. If required by an applied update, the --sql and --build command are triggered afterwards.', -1, false);
|
||||
CLI::write(' Use this after fetching the latest rev. from Github.', -1, false);
|
||||
CLI::write();
|
||||
CLI::write(' Last Update: '.date(Util::$dateFormatInternal, $date).' (Part #'.$part.')', -1, false);
|
||||
CLI::write();
|
||||
return;
|
||||
}
|
||||
|
||||
CLI::write('checking sql updates');
|
||||
CLISetup::siteLock(CLISetup::LOCK_ON);
|
||||
|
||||
$nFiles = 0;
|
||||
foreach (glob('setup/updates/*.sql') as $file)
|
||||
{
|
||||
$pi = pathinfo($file);
|
||||
[$fDate, $fPart] = explode('_', $pi['filename']);
|
||||
|
||||
$fDate = intVal($fDate);
|
||||
|
||||
if ($date && $fDate < $date)
|
||||
continue;
|
||||
else if ($part && $date && $fDate == $date && $fPart <= $part)
|
||||
continue;
|
||||
|
||||
$nFiles++;
|
||||
|
||||
$updQuery = '';
|
||||
$nQuerys = 0;
|
||||
foreach (file($file) as $line)
|
||||
{
|
||||
// skip comments
|
||||
if (substr($line, 0, 2) == '--' || $line == '')
|
||||
continue;
|
||||
|
||||
$updQuery .= $line;
|
||||
|
||||
// semicolon at the end -> end of query
|
||||
if (substr(trim($line), -1, 1) == ';')
|
||||
{
|
||||
if (DB::Aowow()->query($updQuery))
|
||||
$nQuerys++;
|
||||
|
||||
$updQuery = '';
|
||||
}
|
||||
}
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_dbversion SET `date`= ?d, `part` = ?d', $fDate, $fPart);
|
||||
CLI::write(' -> '.date('d.m.Y', $fDate).' #'.$fPart.': '.$nQuerys.' queries applied', CLI::LOG_OK);
|
||||
}
|
||||
|
||||
CLISetup::siteLock(CLISetup::LOCK_RESTORE);
|
||||
CLI::write($nFiles ? 'applied '.$nFiles.' update(s)' : 'db is already up to date', CLI::LOG_OK);
|
||||
|
||||
// fetch sql/build after applying updates, as they may contain sync-prompts
|
||||
[$sql, $build] = array_values(DB::Aowow()->selectRow('SELECT `sql`, `build` FROM ?_dbversion'));
|
||||
|
||||
sleep(1);
|
||||
|
||||
$sql = trim($sql) ? array_unique(explode(' ', trim(preg_replace('/[^a-z_]+/i', ' ', $sql)))) : [];
|
||||
$build = trim($build) ? array_unique(explode(' ', trim(preg_replace('/[^a-z_]+/i', ' ', $build)))) : [];
|
||||
|
||||
if ($sql)
|
||||
CLI::write('The following table(s) require syncing: '.implode(', ', $sql));
|
||||
|
||||
if ($build)
|
||||
CLI::write('The following file(s) require syncing: '.implode(', ', $build));
|
||||
}
|
||||
|
||||
?>
|
||||
121
setup/tools/clisetup/update.us.php
Normal file
121
setup/tools/clisetup/update.us.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/*********************************/
|
||||
/* automaticly apply sql-updates */
|
||||
/*********************************/
|
||||
|
||||
CLISetup::registerUtility(new class extends UtilityScript
|
||||
{
|
||||
public $argvOpts = ['u'];
|
||||
public $optGroup = CLISetup::OPT_GRP_SETUP;
|
||||
public $followupFn = 'sync';
|
||||
|
||||
public const COMMAND = 'update';
|
||||
public const DESCRIPTION = 'Apply new sql updates fetched from Github and run --sync as needed.';
|
||||
|
||||
public const REQUIRED_DB = [DB_AOWOW];
|
||||
|
||||
public const SITE_LOCK = CLISetup::LOCK_RESTORE;
|
||||
|
||||
private $date = 0;
|
||||
private $part = 0;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
if (DB::isConnected(DB_AOWOW))
|
||||
[$this->date, $this->part] = array_values(DB::Aowow()->selectRow('SELECT `date`, `part` FROM ?_dbversion'));
|
||||
}
|
||||
|
||||
// args: null, null, sqlToDo, buildToDo // nnoo
|
||||
public function run(&$args) : bool
|
||||
{
|
||||
$sql = &$args['doSql'];
|
||||
$build = &$args['doBuild'];
|
||||
|
||||
CLI::write('[update] checking for sql updates...');
|
||||
|
||||
$nFiles = 0;
|
||||
foreach (glob('setup/updates/*.sql') as $file)
|
||||
{
|
||||
$pi = pathinfo($file);
|
||||
|
||||
// invalid file
|
||||
if (!preg_match('/(\d{10})_(\d{2})/', $pi['filename'], $m))
|
||||
continue;
|
||||
|
||||
$fDate = intVal($m[1]);
|
||||
$fPart = intVal($m[2]);
|
||||
|
||||
if ($this->date && $fDate < $this->date)
|
||||
continue;
|
||||
else if ($this->part && $this->date && $fDate == $this->date && $fPart <= $this->part)
|
||||
continue;
|
||||
|
||||
$nFiles++;
|
||||
|
||||
$updQuery = '';
|
||||
$nQuerys = 0;
|
||||
foreach (file($file) as $line)
|
||||
{
|
||||
// skip comments
|
||||
if (substr($line, 0, 2) == '--' || $line == '')
|
||||
continue;
|
||||
|
||||
$updQuery .= $line;
|
||||
|
||||
// semicolon at the end -> end of query
|
||||
if (substr(trim($line), -1, 1) == ';')
|
||||
{
|
||||
if (DB::Aowow()->query($updQuery))
|
||||
$nQuerys++;
|
||||
|
||||
$updQuery = '';
|
||||
}
|
||||
}
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_dbversion SET `date`= ?d, `part` = ?d', $fDate, $fPart);
|
||||
CLI::write(' -> '.date('d.m.Y', $fDate).' #'.$fPart.': '.$nQuerys.' queries applied', CLI::LOG_OK);
|
||||
}
|
||||
|
||||
CLI::write('[update] ' . ($nFiles ? 'applied '.$nFiles.' update(s)' : 'db is already up to date'), CLI::LOG_OK);
|
||||
|
||||
// fetch sql/build after applying updates, as they may contain sync-prompts
|
||||
[$sql, $build] = DB::Aowow()->selectRow('SELECT `sql` AS "0", `build` AS "1" FROM ?_dbversion');
|
||||
|
||||
$sql = trim($sql) ? array_unique(explode(' ', trim(preg_replace('/[^a-z]+/i', ' ', $sql)))) : [];
|
||||
$build = trim($build) ? array_unique(explode(' ', trim(preg_replace('/[^a-z]+/i', ' ', $build)))) : [];
|
||||
|
||||
sleep(1);
|
||||
|
||||
if ($sql)
|
||||
CLI::write('[update] The following sql scripts have been scheduled: '.implode(', ', $sql));
|
||||
|
||||
if ($build)
|
||||
CLI::write('[update] The following build scripts have been scheduled: '.implode(', ', $build));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function writeCLIHelp() : bool
|
||||
{
|
||||
CLI::write(' usage: php aowow --update', -1, false);
|
||||
CLI::write();
|
||||
CLI::write(' Checks /setup/updates for new *.sql files and applies them. If required by an applied update, the --sql and --build command are triggered afterwards.', -1, false);
|
||||
CLI::write(' Use this after fetching the latest rev. from Github.', -1, false);
|
||||
CLI::write();
|
||||
CLI::write(' Last Update: '.date(Util::$dateFormatInternal, $this->date).' (Part #'.$this->part.')', -1, false);
|
||||
CLI::write();
|
||||
CLI::write();
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,243 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
class FileGen
|
||||
{
|
||||
const MODE_NORMAL = 1;
|
||||
const MODE_FIRSTRUN = 2;
|
||||
const MODE_UPDATE = 3;
|
||||
|
||||
private static $mode = 0;
|
||||
|
||||
public static $tplPath = 'setup/tools/filegen/templates/';
|
||||
|
||||
public static $subScripts = [];
|
||||
public static $tplFiles = array( // name => [file, path, TCDeps]
|
||||
'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/', ['realmlist']],
|
||||
'locales' => ['locale.js', 'static/js/', []],
|
||||
'markup' => ['Markup.js', 'static/js/', []],
|
||||
'itemScaling' => ['item-scaling', 'datasets/', []]
|
||||
);
|
||||
public static $datasets = array( // name => [AowowDeps, TCDeps, info]
|
||||
'realms' => [null, ['realmlist'], 'datasets/realms'],
|
||||
'statistics' => [null, ['player_levelstats', 'player_classlevelstats'], 'datasets/statistics'],
|
||||
'simpleImg' => [null, null, 'static/images/wow/[icons, Interface, ]/*'],
|
||||
'complexImg' => [null, null, 'static/images/wow/[maps, talents/backgrounds, ]/*'],
|
||||
'talentCalc' => [null, null, 'datasets/<locale>/talents-*'],
|
||||
'pets' => [['spawns', 'creature'], null, 'datasets/<locale>/pets'],
|
||||
'talentIcons' => [null, null, 'static/images/wow/talents/icons/*'],
|
||||
'glyphs' => [['items', 'spell'], null, 'datasets/<locale>/glyphs'],
|
||||
'itemsets' => [['itemset', 'spell'], null, 'datasets/<locale>/itemsets'],
|
||||
'enchants' => [['items', 'spell', 'itemenchantment'], null, 'datasets/<locale>/enchants'],
|
||||
'gems' => [['items', 'spell', 'itemenchantment'], null, 'datasets/<locale>/gems'],
|
||||
'profiler' => [['quests', 'quests_startend', 'spell', 'currencies', 'achievement', 'titles'], null, 'datasets/<locale>/p-*'],
|
||||
'weightPresets' => [null, null, 'datasets/weight-presets'],
|
||||
'soundfiles' => [['sounds'], null, 'static/wowsounds/*']
|
||||
);
|
||||
|
||||
public static $defaultExecTime = 30;
|
||||
|
||||
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/',
|
||||
'static/uploads/guide/images/',
|
||||
'static/download/searchplugins/',
|
||||
'static/wowsounds/'
|
||||
);
|
||||
|
||||
public static function init(int $mode = self::MODE_NORMAL, array $updScripts = []) : bool
|
||||
{
|
||||
self::$defaultExecTime = ini_get('max_execution_time');
|
||||
self::$mode = $mode;
|
||||
|
||||
if (!CLISetup::$localeIds)
|
||||
{
|
||||
CLI::write('No valid locale specified. Check your config or --locales parameter, if used', CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// create directory structure
|
||||
CLI::write('FileGen::init() - creating required directories');
|
||||
$pathOk = 0;
|
||||
foreach (self::$reqDirs as $rd)
|
||||
if (CLISetup::writeDir($rd))
|
||||
$pathOk++;
|
||||
|
||||
CLI::write('created '.$pathOk.' extra paths'.($pathOk == count(self::$reqDirs) ? '' : ' with errors'));
|
||||
CLI::write();
|
||||
|
||||
// handle command prompts
|
||||
if (!self::handleCLIOpts($doScripts) && !$updScripts)
|
||||
return false;
|
||||
|
||||
// check passed subscript names; limit to real scriptNames
|
||||
self::$subScripts = array_merge(array_keys(self::$tplFiles), array_keys(self::$datasets));
|
||||
if ($doScripts || $updScripts)
|
||||
self::$subScripts = array_intersect($doScripts ?: $updScripts, self::$subScripts);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static function handleCLIOpts(?array &$doScripts) : bool
|
||||
{
|
||||
$doScripts = [];
|
||||
|
||||
if (CLISetup::getOpt('help') && self::$mode == self::MODE_NORMAL)
|
||||
{
|
||||
if (in_array('simpleImg', CLISetup::getOpt('build')))
|
||||
CLISetup::optHelp(1 << 3);
|
||||
else if (in_array('complexImg', CLISetup::getOpt('build')))
|
||||
CLISetup::optHelp(1 << 4);
|
||||
else
|
||||
self::printCLIHelp();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// required subScripts
|
||||
if ($sync = CLISetup::getOpt('sync'))
|
||||
{
|
||||
foreach (self::$tplFiles as $name => $info)
|
||||
if (!empty($info[2]) && array_intersect($sync, $info[2]))
|
||||
$doScripts[] = $name;
|
||||
|
||||
foreach (self::$datasets as $name => $info)
|
||||
{
|
||||
// recursive deps from SqlGen
|
||||
if (!empty($info[0]) && array_intersect(SqlGen::$subScripts, $info[0]))
|
||||
$doScripts[] = $name;
|
||||
else if (!empty($info[1]) && array_intersect($sync, $info[1]))
|
||||
$doScripts[] = $name;
|
||||
}
|
||||
|
||||
if (!$doScripts)
|
||||
return false;
|
||||
|
||||
$doScripts = array_unique($doScripts);
|
||||
return true;
|
||||
}
|
||||
else if (is_array($_ = CLISetup::getOpt('build')))
|
||||
{
|
||||
$doScripts = $_;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function printCLIHelp()
|
||||
{
|
||||
CLI::write();
|
||||
CLI::write(' usage: php aowow --build=<subScriptList,> [--mpqDataDir: --locales:]', -1, false);
|
||||
CLI::write();
|
||||
CLI::write(' Compiles files for a given subScript. Existing files are kept by default. Dependencies are taken into account by the triggered calls of --sync and --update', -1, false);
|
||||
|
||||
$lines = [['available subScripts', 'affected files', 'TC dependencies', 'AoWoW dependencies']];
|
||||
foreach (array_merge(array_keys(self::$tplFiles), array_keys(self::$datasets)) as $s)
|
||||
$lines[] = array(
|
||||
' * '.$s,
|
||||
isset(self::$tplFiles[$s]) ? self::$tplFiles[$s][1].self::$tplFiles[$s][0] : self::$datasets[$s][2],
|
||||
!empty(self::$tplFiles[$s][2]) ? implode(' ', self::$tplFiles[$s][2]) : (!empty(self::$datasets[$s][1]) ? implode(' ', self::$datasets[$s][1]) : ''),
|
||||
!empty(self::$datasets[$s][0]) ? implode(' ', self::$datasets[$s][0]) : ''
|
||||
);
|
||||
|
||||
CLI::writeTable($lines);
|
||||
}
|
||||
|
||||
public static function generate($key, array $updateIds = [])
|
||||
{
|
||||
$success = false;
|
||||
$reqDBC = [];
|
||||
|
||||
if (file_exists('setup/tools/filegen/'.$key.'.func.php'))
|
||||
require_once 'setup/tools/filegen/'.$key.'.func.php';
|
||||
else if (empty(self::$tplFiles[$key]))
|
||||
{
|
||||
CLI::write(sprintf(ERR_MISSING_INCL, $key, 'setup/tools/filegen/'.$key.'.func.php', CLI::LOG_ERROR));
|
||||
return false;
|
||||
}
|
||||
|
||||
CLI::write('FileGen::generate() - gathering data for '.$key);
|
||||
|
||||
if (!empty(self::$tplFiles[$key]))
|
||||
{
|
||||
[$file, $destPath, $deps] = self::$tplFiles[$key];
|
||||
|
||||
if ($content = file_get_contents(self::$tplPath.$file.'.in'))
|
||||
{
|
||||
// replace constants
|
||||
$content = Cfg::applyToString($content);
|
||||
|
||||
// check for required auxiliary DBC files
|
||||
foreach ($reqDBC as $req)
|
||||
if (!CLISetup::loadDBC($req))
|
||||
continue;
|
||||
|
||||
// must generate content
|
||||
// PH format: /*setup:<setupFunc>*/
|
||||
$funcOK = true;
|
||||
if (preg_match_all('/\/\*setup:([\w\-_]+)\*\//i', $content, $m))
|
||||
{
|
||||
foreach ($m[1] as $func)
|
||||
{
|
||||
if (function_exists($func))
|
||||
$content = str_replace('/*setup:'.$func.'*/', $func(), $content);
|
||||
else
|
||||
{
|
||||
$funcOK = false;
|
||||
CLI::write('No function for was registered for placeholder '.$func.'().', CLI::LOG_ERROR);
|
||||
if (!array_reduce(get_included_files(), function ($inArray, $itr) use ($func) { return $inArray || false !== strpos($itr, $func); }, false))
|
||||
CLI::write('Also, expected include setup/tools/filegen/'.$name.'.func.php was not found.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($content && $funcOK)
|
||||
if (CLISetup::writeFile($destPath.$file, $content))
|
||||
$success = true;
|
||||
}
|
||||
else
|
||||
CLI::write(sprintf(ERR_READ_FILE, CLI::bold(self::$tplPath.$file.'.in')), CLI::LOG_ERROR);
|
||||
}
|
||||
else if (!empty(self::$datasets[$key]))
|
||||
{
|
||||
if (function_exists($key))
|
||||
{
|
||||
// check for required auxiliary DBC files
|
||||
foreach ($reqDBC as $req)
|
||||
if (!CLISetup::loadDBC($req))
|
||||
return false;
|
||||
|
||||
$success = $key($updateIds);
|
||||
}
|
||||
else
|
||||
CLI::write(' - subscript \''.$key.'\' not defined in included file', CLI::LOG_ERROR);
|
||||
}
|
||||
|
||||
set_time_limit(self::$defaultExecTime); // reset to default for the next script
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
public static function getMode()
|
||||
{
|
||||
return self::$mode;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,749 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
generate maps - code for extracting regular maps for AoWoW
|
||||
This file is a part of AoWoW project.
|
||||
Copyright (C) 2010 Mix <ru-mangos.ru>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
// note: for the sake of simplicity, this function handles all images, that must be stitched together (which are mostly maps)
|
||||
|
||||
$reqDBC = ['talenttab', 'chrclasses', 'worldmapoverlay', 'worldmaparea'];
|
||||
|
||||
function complexImg()
|
||||
{
|
||||
$mapWidth = 1002;
|
||||
$mapHeight = 668;
|
||||
$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
|
||||
$runTime = ini_get('max_execution_time');
|
||||
$locStr = null;
|
||||
$imgPath = CLISetup::$srcDir.'%sInterface/';
|
||||
$destDir = 'static/images/wow/';
|
||||
$success = true;
|
||||
$modeMask = 0x7; // talentBGs, regular maps, spawn-related alphaMaps
|
||||
$paths = array(
|
||||
0x16 => ['WorldMap/', true, null],
|
||||
0x01 => ['TalentFrame/', false, null],
|
||||
0x08 => ['Glues/Credits/',false, null]
|
||||
);
|
||||
|
||||
$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);
|
||||
|
||||
imagecolortransparent($img, $bgColor);
|
||||
imagealphablending($img, true);
|
||||
|
||||
imagecolordeallocate($img, $bgColor);
|
||||
|
||||
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 (CLISetup::fileExists($file))
|
||||
{
|
||||
CLI::write('manually converted png file present for '.$path.'.', CLI::LOG_INFO);
|
||||
$result = imagecreatefrompng($file);
|
||||
}
|
||||
|
||||
if (!$result)
|
||||
{
|
||||
$file = $path.'.blp';
|
||||
if (CLISetup::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)
|
||||
{
|
||||
CLI::write(' - complexImg: tile '.$baseName.$suffix.'.blp missing.', CLI::LOG_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:
|
||||
CLI::write($done.' - unsupported file fromat: '.$ext, CLI::LOG_WARN);
|
||||
}
|
||||
|
||||
imagedestroy($dest);
|
||||
|
||||
if ($ok)
|
||||
{
|
||||
chmod($name.'.'.$ext, Util::FILE_ACCESS);
|
||||
CLI::write($done.' - image '.$name.'.'.$ext.' written', CLI::LOG_OK, true, true);
|
||||
}
|
||||
else
|
||||
CLI::write($done.' - could not create image '.$name.'.'.$ext, CLI::LOG_ERROR);
|
||||
|
||||
return $ok;
|
||||
};
|
||||
|
||||
$createSpawnMap = function($img, $zoneId) use ($mapHeight, $mapWidth, $threshold)
|
||||
{
|
||||
CLI::write(' - 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 < $threshold ? $cfg : $cbg);
|
||||
}
|
||||
}
|
||||
|
||||
imagepng($tmp, 'setup/generated/alphaMaps/' . $zoneId . '.png');
|
||||
|
||||
imagecolordeallocate($tmp, $cbg);
|
||||
imagecolordeallocate($tmp, $cfg);
|
||||
imagedestroy($tmp);
|
||||
};
|
||||
|
||||
$checkSourceDirs = function($sub) use ($imgPath, &$paths, $modeMask)
|
||||
{
|
||||
$hasMissing = false;
|
||||
foreach ($paths as $idx => [$subDir, $isLocalized, $realPath])
|
||||
{
|
||||
if ($realPath && !$isLocalized)
|
||||
continue;
|
||||
|
||||
$p = sprintf($imgPath, $sub).$subDir;
|
||||
if (CLISetup::fileExists($p))
|
||||
{
|
||||
if ($isLocalized)
|
||||
$paths[$idx][2][substr($sub, 0, -1)] = $p;
|
||||
else
|
||||
$paths[$idx][2] = $p;
|
||||
}
|
||||
else
|
||||
$hasMissing = true;
|
||||
}
|
||||
|
||||
return !$hasMissing;
|
||||
};
|
||||
|
||||
// do not change order of params!
|
||||
$o = CLISetup::getOpt('talentbgs', 'maps', 'spawn-maps', 'artwork', 'area-maps');
|
||||
$m = 0x0;
|
||||
$i = 0;
|
||||
foreach ($o as $k => $v)
|
||||
{
|
||||
if ($v)
|
||||
$m |= 1 << $i;
|
||||
$i++;
|
||||
}
|
||||
|
||||
if ($m)
|
||||
$modeMask = $m;
|
||||
|
||||
foreach ($paths as $mode => $__)
|
||||
if (!($mode & $modeMask))
|
||||
unset($paths[$mode]);
|
||||
|
||||
foreach (CLISetup::$expectedPaths as $xp => $locId)
|
||||
{
|
||||
if (!in_array($locId, CLISetup::$localeIds))
|
||||
continue;
|
||||
|
||||
if ($xp) // if in subDir add trailing slash
|
||||
$xp .= '/';
|
||||
|
||||
$checkSourceDirs($xp); // do not break; maps are localized
|
||||
}
|
||||
|
||||
$locList = [];
|
||||
foreach (CLISetup::$expectedPaths as $xp => $locId)
|
||||
if (in_array($locId, CLISetup::$localeIds))
|
||||
$locList[] = $xp;
|
||||
|
||||
CLI::write('required resources overview:', CLI::LOG_INFO);
|
||||
foreach ($paths as [$path, $isLocalized, $realPath])
|
||||
{
|
||||
if (!$realPath)
|
||||
CLI::write(CLI::red('MISSING').' - '.str_pad($path, 14).' @ '.sprintf($imgPath, '['.implode(',', $locList).']/').$path);
|
||||
else if ($isLocalized)
|
||||
{
|
||||
$foundLoc = [];
|
||||
foreach (CLISetup::$localeIds as $locId)
|
||||
foreach (CLISetup::$expectedPaths as $xp => $lId)
|
||||
if ($locId == $lId && isset($realPath[$xp]) && !isset($foundLoc[$locId]))
|
||||
$foundLoc[$locId] = $xp;
|
||||
|
||||
if ($diff = array_diff(CLISetup::$localeIds, array_keys($foundLoc)))
|
||||
{
|
||||
$buff = [];
|
||||
foreach ($diff as $d)
|
||||
$buff[] = CLI::yellow(Util::$localeStrings[$d]);
|
||||
foreach ($foundLoc as $str)
|
||||
$buff[] = CLI::green($str);
|
||||
|
||||
CLI::write(CLI::yellow('PARTIAL').' - '.str_pad($path, 14).' @ '.sprintf($imgPath, '['.implode(',', $buff).']/').$path);
|
||||
}
|
||||
else
|
||||
CLI::write(CLI::green(' FOUND ').' - '.str_pad($path, 14).' @ '.sprintf($imgPath, '['.implode(',', $foundLoc).']/').$path);
|
||||
}
|
||||
else
|
||||
CLI::write(CLI::green(' FOUND ').' - '.str_pad($path, 14).' @ '.$realPath);
|
||||
}
|
||||
|
||||
CLI::write();
|
||||
|
||||
// if no subdir had sufficient data, diaf
|
||||
if (count(array_filter(array_column($paths, 2))) != count($paths))
|
||||
{
|
||||
CLI::write('one or more required directories are missing:', CLI::LOG_ERROR);
|
||||
return;
|
||||
}
|
||||
else
|
||||
sleep(1);
|
||||
|
||||
/**************/
|
||||
/* TalentTabs */
|
||||
/**************/
|
||||
|
||||
if ($modeMask & 0x01)
|
||||
{
|
||||
if (CLISetup::writeDir($destDir.'hunterpettalents/') && CLISetup::writeDir($destDir.'talents/backgrounds/'))
|
||||
{
|
||||
// [classMask, creatureFamilyMask, tabNr, textureStr]
|
||||
|
||||
$tTabs = DB::Aowow()->select('SELECT tt.creatureFamilyMask, tt.textureFile, tt.tabNumber, cc.fileString FROM dbc_talenttab tt LEFT JOIN dbc_chrclasses cc ON cc.id = (LOG(2, tt.classMask) + 1)');
|
||||
$order = array(
|
||||
['-TopLeft', '-TopRight'],
|
||||
['-BottomLeft', '-BottomRight']
|
||||
);
|
||||
|
||||
if ($tTabs)
|
||||
{
|
||||
$sum = 0;
|
||||
$total = count($tTabs);
|
||||
CLI::write('Processing '.$total.' files from TalentFrame/ ...');
|
||||
|
||||
foreach ($tTabs 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($tt['fileString']).'_'.($tt['tabNumber'] + 1);
|
||||
}
|
||||
|
||||
if (!CLISetup::getOpt('force') && file_exists($name.'.jpg'))
|
||||
{
|
||||
CLI::write($done.' - file '.$name.'.jpg was already processed', CLI::LOG_BLANK, true, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
$im = $assembleImage($paths[0x1][2].'/'.$tt['textureFile'], $order, 256 + 44, 256 + 75);
|
||||
if (!$im)
|
||||
{
|
||||
CLI::write(' - could not assemble file '.$tt['textureFile'], CLI::LOG_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, 149],
|
||||
['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
|
||||
);
|
||||
|
||||
$wmo = DB::Aowow()->select('SELECT *, worldMapAreaId AS ARRAY_KEY, id AS ARRAY_KEY2 FROM dbc_worldmapoverlay WHERE textureString <> ""');
|
||||
$wma = DB::Aowow()->select('SELECT * FROM dbc_worldmaparea');
|
||||
if (!$wma || !$wmo)
|
||||
{
|
||||
$success = false;
|
||||
CLI::write(' - could not read required dbc files: WorldMapArea.dbc ['.count($wma).' entries]; WorldMapOverlay.dbc ['.count($wmo).' entries]', CLI::LOG_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
// fixups...
|
||||
foreach ($wma as &$a)
|
||||
{
|
||||
if ($a['areaId'])
|
||||
continue;
|
||||
|
||||
switch ($a['id'])
|
||||
{
|
||||
case 13: $a['areaId'] = -6; break; // Kalimdor
|
||||
case 14: $a['areaId'] = -3; break; // Eastern Kingdoms
|
||||
case 466: $a['areaId'] = -2; break; // Outland
|
||||
case 485: $a['areaId'] = -5; break; // Northrend
|
||||
}
|
||||
}
|
||||
array_unshift($wma, ['id' => -1, 'areaId' => -1, 'nameINT' => 'World'], ['id' => -4, 'areaId' => -4, 'nameINT' => 'Cosmic']);
|
||||
|
||||
$sumMaps = count(CLISetup::$localeIds) * count($wma);
|
||||
|
||||
CLI::write('Processing '.$sumMaps.' files from WorldMap/ ...');
|
||||
|
||||
foreach (CLISetup::$localeIds as $progressLoc => $l)
|
||||
{
|
||||
// create destination directories
|
||||
$dirError = false;
|
||||
foreach ($mapDirs as $md)
|
||||
if (!CLISetup::writeDir($destDir . sprintf($md[0], strtolower(Util::$localeStrings[$l]).'/')))
|
||||
$dirError = true;
|
||||
|
||||
if ($modeMask & 0x04)
|
||||
if (!CLISetup::writeDir('setup/generated/alphaMaps'))
|
||||
$dirError = true;
|
||||
|
||||
if ($dirError)
|
||||
{
|
||||
$success = false;
|
||||
CLI::write(' - complexImg: could not create map directories for locale '.$l.'. skipping...', CLI::LOG_ERROR);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// source for mapFiles
|
||||
$mapSrcDir = null;
|
||||
$locDirs = array_reverse(array_filter(CLISetup::$expectedPaths, function($var) use ($l) { return !$var || $var == $l; }), true);
|
||||
foreach ($locDirs as $mapLoc => $__)
|
||||
{
|
||||
if(!isset($paths[0x16][2][$mapLoc]))
|
||||
continue;
|
||||
|
||||
$p = sprintf($imgPath, $mapLoc.'/').$paths[0x16][0];
|
||||
if (CLISetup::fileExists($p))
|
||||
{
|
||||
CLI::write(' - using files from '.($mapLoc ?: '/').' for locale '.Util::$localeStrings[$l], CLI::LOG_INFO);
|
||||
$mapSrcDir = $p.'/';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($mapSrcDir === null)
|
||||
{
|
||||
$success = false;
|
||||
CLI::write(' - no suitable localized map files found for locale '.$l, CLI::LOG_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 (!CLISetup::fileExists($path))
|
||||
{
|
||||
$success = false;
|
||||
CLI::write('worldmap file '.$path.' missing for selected locale '.Util::$localeStrings[$l], CLI::LOG_ERROR);
|
||||
continue;
|
||||
}
|
||||
|
||||
$fmt = array(
|
||||
[1, 2, 3, 4],
|
||||
[5, 6, 7, 8],
|
||||
[9, 10, 11, 12]
|
||||
);
|
||||
|
||||
CLI::write($textureStr . " [" . $zoneId . "]");
|
||||
|
||||
$overlay = $createAlphaImage($mapWidth, $mapHeight);
|
||||
|
||||
// zone has overlays (is in open world; is not multiLeveled)
|
||||
if (isset($wmo[$wmaId]))
|
||||
{
|
||||
CLI::write(' - 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)
|
||||
{
|
||||
CLI::write(' - complexImg: tile '.$path.'/'.$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 ($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) < $threshold)
|
||||
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 (!CLISetup::filesInPath('/'.$textureStr.'\/'.$textureStr.($multiLevel + 1).'_\d\.(blp|png)/i', true))
|
||||
break;
|
||||
|
||||
$multiLevel++;
|
||||
$multiLeveled = true;
|
||||
}
|
||||
while ($multiLevel < 18); // Karazhan has 17 frickin floors
|
||||
|
||||
// check if we can create base map anyway
|
||||
$png = $path.'/'.$textureStr.'1.png';
|
||||
$blp = $path.'/'.$textureStr.'1.blp';
|
||||
$hasBaseMap = CLISetup::fileExists($blp) || CLISetup::fileExists($png);
|
||||
|
||||
CLI::write(' - 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 (!CLISetup::getOpt('force') && file_exists($outFile[$idx].'.'.$info[1]))
|
||||
{
|
||||
CLI::write($progress.' - file '.$outFile[$idx].'.'.$info[1].' was already processed', CLI::LOG_BLANK, true, true);
|
||||
$doSkip |= (1 << $idx);
|
||||
}
|
||||
}
|
||||
|
||||
if ($doSkip == 0xF)
|
||||
continue;
|
||||
|
||||
$map = $assembleImage($file, $fmt, $mapWidth, $mapHeight);
|
||||
if (!$map)
|
||||
{
|
||||
$success = false;
|
||||
CLI::write(' - could not create image resource for map '.$zoneId.($multiLevel ? ' level '.$i : ''));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$multiLeveled)
|
||||
{
|
||||
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 (!CLISetup::getOpt('force') && file_exists($outFile[$idx].'.'.$info[1]))
|
||||
{
|
||||
CLI::write($progress.' - file '.$outFile[$idx].'.'.$info[1].' was already processed', CLI::LOG_BLANK, true, true);
|
||||
$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);
|
||||
|
||||
// this takes a while; ping mysql just in case
|
||||
DB::Aowow()->selectCell('SELECT 1');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***********/
|
||||
/* Credits */
|
||||
/***********/
|
||||
|
||||
if ($modeMask & 0x08) // optional tidbits (not used by default)
|
||||
{
|
||||
if (CLISetup::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 = [];
|
||||
$files = CLISetup::filesInPath('/'.str_replace('/', '\\/', $paths[0x8][2]).'/i', true);
|
||||
foreach ($files as $f)
|
||||
{
|
||||
if (preg_match('/([^\/]+)(\d).(blp|png)/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;
|
||||
|
||||
CLI::write('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 (!CLISetup::getOpt('force') && file_exists($name.'.png'))
|
||||
{
|
||||
CLI::write($done.' - file '.$name.'.png was already processed', CLI::LOG_BLANK, true, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($order[$fmt]))
|
||||
{
|
||||
CLI::write(' - pattern for file '.$name.' not set. skipping', CLI::LOG_WARN);
|
||||
continue;
|
||||
}
|
||||
|
||||
$im = $assembleImage($paths[0x8][2].'/'.$file, $order[$fmt], count($order[$fmt][0]) * 256, count($order[$fmt]) * 256);
|
||||
if (!$im)
|
||||
{
|
||||
CLI::write(' - could not assemble file '.$name, CLI::LOG_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;
|
||||
}
|
||||
|
||||
?>
|
||||
22
setup/tools/filegen/demo.ss.php
Normal file
22
setup/tools/filegen/demo.ss.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
use TrTemplateFile;
|
||||
|
||||
protected $info = array(
|
||||
'demo' => [[], CLISetup::ARGV_PARAM, 'Fills powered tooltip demo page (static/widgets/power/demo.html) with site variables.']
|
||||
);
|
||||
|
||||
protected $fileTemplateSrc = ['demo.html.in'];
|
||||
protected $fileTemplateDest = ['static/widgets/power/demo.html'];
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -7,91 +7,95 @@ if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
// Create 'enchants'-file for available locales
|
||||
// this script requires the following dbc-files to be parsed and available
|
||||
// Spells, SkillLineAbility, SpellItemEnchantment
|
||||
/* Examples
|
||||
15: {
|
||||
name:'Leichtes Rüstungsset',
|
||||
quality:1,
|
||||
icon:'INV_Misc_ArmorKit_17',
|
||||
source:-2304,
|
||||
skill:-1,
|
||||
slots:525008,
|
||||
enchantment:'Verstärkt (+8 Rüstung)',
|
||||
jsonequip:{"armor":8,"reqlevel":1},
|
||||
temp:0,
|
||||
classes:0,
|
||||
gearscore:1
|
||||
},
|
||||
2928: {
|
||||
name:'Ring - Zaubermacht',
|
||||
quality:-1,
|
||||
icon:'INV_Misc_Note_01',
|
||||
source:27924,
|
||||
skill:333,
|
||||
slots:1024,
|
||||
enchantment:'+12 Zaubermacht',
|
||||
jsonequip:{"splpwr":12},
|
||||
temp:0,
|
||||
classes:0,
|
||||
gearscore:15
|
||||
},
|
||||
3231: {
|
||||
name:['Handschuhe - Waffenkunde','Armschiene - Waffenkunde'],
|
||||
quality:-1,
|
||||
icon:'spell_holy_greaterheal',
|
||||
source:[44484,44598],
|
||||
skill:333,
|
||||
slots:[512,256],
|
||||
enchantment:'+15 Waffenkundewertung',
|
||||
jsonequip:{reqlevel:60,"exprtng":15},
|
||||
temp:0,
|
||||
classes:0,
|
||||
gearscore:20 // fuck, i'm doing this..
|
||||
},
|
||||
*/
|
||||
|
||||
/* Examples
|
||||
15: {
|
||||
name:'Leichtes Rüstungsset',
|
||||
quality:1,
|
||||
icon:'INV_Misc_ArmorKit_17',
|
||||
source:-2304,
|
||||
skill:-1,
|
||||
slots:525008,
|
||||
enchantment:'Verstärkt (+8 Rüstung)',
|
||||
jsonequip:{"armor":8,"reqlevel":1},
|
||||
temp:0,
|
||||
classes:0,
|
||||
gearscore:1
|
||||
},
|
||||
2928: {
|
||||
name:'Ring - Zaubermacht',
|
||||
quality:-1,
|
||||
icon:'INV_Misc_Note_01',
|
||||
source:27924,
|
||||
skill:333,
|
||||
slots:1024,
|
||||
enchantment:'+12 Zaubermacht',
|
||||
jsonequip:{"splpwr":12},
|
||||
temp:0,
|
||||
classes:0,
|
||||
gearscore:15
|
||||
},
|
||||
3231: {
|
||||
name:['Handschuhe - Waffenkunde','Armschiene - Waffenkunde'],
|
||||
quality:-1,
|
||||
icon:'spell_holy_greaterheal',
|
||||
source:[44484,44598],
|
||||
skill:333,
|
||||
slots:[512,256],
|
||||
enchantment:'+15 Waffenkundewertung',
|
||||
jsonequip:{reqlevel:60,"exprtng":15},
|
||||
temp:0,
|
||||
classes:0,
|
||||
gearscore:20 // fuck, i'm doing this..
|
||||
},
|
||||
*/
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
protected $info = array(
|
||||
'enchants' => [[], CLISetup::ARGV_PARAM, 'Compiles enchantment effects to file for the item comparison tool and profiler tool.']
|
||||
);
|
||||
|
||||
function enchants()
|
||||
protected $setupAfter = [['items', 'spell', 'itemenchantment', 'icons', 'source'], []];
|
||||
protected $requiredDirs = ['datasets/'];
|
||||
protected $localized = true;
|
||||
|
||||
public function generate() : bool
|
||||
{
|
||||
// from g_item_slots: 13:"One-Hand", 15:"Ranged", 17:"Two-Hand",
|
||||
$slotPointer = [13, 17, 15, 15, 13, 17, 17, 13, 17, null, 17, null, null, 13, null, 13, null, null, null, null, 17];
|
||||
$castItems = [];
|
||||
$successs = true;
|
||||
$enchantSpells = DB::Aowow()->select('
|
||||
SELECT
|
||||
s.id AS ARRAY_KEY,
|
||||
effect1MiscValue,
|
||||
equippedItemClass, equippedItemInventoryTypeMask, equippedItemSubClassMask,
|
||||
skillLine1,
|
||||
IFNULL(i.name, ?) AS iconString,
|
||||
name_loc0, name_loc2, name_loc3, name_loc4, name_loc6, name_loc8
|
||||
FROM
|
||||
?_spell s
|
||||
LEFT JOIN
|
||||
?_icons i ON i.id = s.iconId
|
||||
WHERE
|
||||
effect1Id = ?d AND
|
||||
name_loc0 NOT LIKE "QA%"'
|
||||
,DEFAULT_ICON, SPELL_EFFECT_ENCHANT_ITEM);
|
||||
|
||||
// check directory-structure
|
||||
foreach (Util::$localeStrings as $dir)
|
||||
if (!CLISetup::writeDir('datasets/'.$dir))
|
||||
$success = false;
|
||||
$castItems = [];
|
||||
$enchantSpells = DB::Aowow()->select(
|
||||
'SELECT s.id AS ARRAY_KEY,
|
||||
effect1MiscValue,
|
||||
equippedItemClass, equippedItemInventoryTypeMask, equippedItemSubClassMask,
|
||||
skillLine1,
|
||||
IFNULL(i.name, ?) AS iconString,
|
||||
name_loc0, name_loc2, name_loc3, name_loc4, name_loc6, name_loc8
|
||||
FROM ?_spell s
|
||||
LEFT JOIN ?_icons i ON i.id = s.iconId
|
||||
WHERE effect1Id = ?d AND
|
||||
name_loc0 NOT LIKE "QA%"',
|
||||
DEFAULT_ICON, SPELL_EFFECT_ENCHANT_ITEM
|
||||
);
|
||||
|
||||
$enchIds = array_column($enchantSpells, 'effect1MiscValue');
|
||||
|
||||
$enchantments = new EnchantmentList(array(['id', $enchIds], Cfg::get('SQL_LIMIT_NONE')));
|
||||
if ($enchantments->error)
|
||||
{
|
||||
CLI::write('Required table ?_itemenchantment seems to be empty! Leaving enchants()...', CLI::LOG_ERROR);
|
||||
CLI::write('[enchants] Required table ?_itemenchantment seems to be empty!', CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
return false;
|
||||
}
|
||||
|
||||
$castItems = new ItemList(array(['spellId1', array_keys($enchantSpells)], ['src.typeId', null, '!'], Cfg::get('SQL_LIMIT_NONE')));
|
||||
if ($castItems->error)
|
||||
{
|
||||
CLI::write('[enchants] Required table ?_items seems to be empty!', CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (CLISetup::$localeIds as $lId)
|
||||
{
|
||||
@@ -106,20 +110,20 @@ if (!CLI)
|
||||
$eId = $es['effect1MiscValue'];
|
||||
if (!$enchantments->getEntry($eId))
|
||||
{
|
||||
CLI::write(' * could not find enchantment #'.$eId.' referenced by spell #'.$esId, CLI::LOG_WARN);
|
||||
CLI::write('[enchants] * could not find enchantment #'.$eId.' referenced by spell #'.$esId, CLI::LOG_WARN);
|
||||
continue;
|
||||
}
|
||||
|
||||
// slots have to be recalculated
|
||||
$slot = 0;
|
||||
if ($es['equippedItemClass'] == 4) // armor
|
||||
if ($es['equippedItemClass'] == ITEM_CLASS_ARMOR)
|
||||
{
|
||||
if ($invType = $es['equippedItemInventoryTypeMask'])
|
||||
$slot = $invType >> 1;
|
||||
else /* if (equippedItemSubClassMask == 64) */ // shields have it their own way <_<
|
||||
$slot = (1 << (14 - 1));
|
||||
}
|
||||
else if ($es['equippedItemClass'] == 2) // weapon
|
||||
else if ($es['equippedItemClass'] == ITEM_CLASS_WEAPON)
|
||||
{
|
||||
foreach ($slotPointer as $i => $sp)
|
||||
{
|
||||
@@ -253,10 +257,11 @@ if (!CLI)
|
||||
$file = 'datasets/'.User::$localeString.'/enchants';
|
||||
|
||||
if (!CLISetup::writeFile($file, $toFile))
|
||||
$success = false;
|
||||
$this->success = false;
|
||||
}
|
||||
|
||||
return $successs;
|
||||
return $this->success;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,104 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
// Create 'gems'-file for available locales
|
||||
// this script requires the following dbc-files to be parsed and available
|
||||
// ItemEnchantment, GemProperties, Spells, Icons
|
||||
|
||||
/* Example
|
||||
22460: {
|
||||
name:'Prismatic Sphere',
|
||||
quality:3,
|
||||
icon:'INV_Enchant_PrismaticSphere',
|
||||
enchantment:'+3 Resist All',
|
||||
jsonequip:{"arcres":3,"avgbuyout":242980,"firres":3,"frores":3,"holres":3,"natres":3,"shares":3},
|
||||
colors:14,
|
||||
expansion:1
|
||||
gearscore:8 // if only..
|
||||
},
|
||||
*/
|
||||
|
||||
function gems()
|
||||
{
|
||||
// sketchy, but should work
|
||||
// id < 36'000 || ilevel < 70 ? BC : WOTLK
|
||||
$gems = DB::Aowow()->Select(
|
||||
'SELECT i.id AS itemId,
|
||||
i.name_loc0, i.name_loc2, i.name_loc3, i.name_loc4, i.name_loc6, i.name_loc8,
|
||||
IF (i.id < 36000 OR i.itemLevel < 70, ?d, ?d) AS expansion,
|
||||
i.quality,
|
||||
ic.name AS icon,
|
||||
i.gemEnchantmentId AS enchId,
|
||||
i.gemColorMask AS colors,
|
||||
i.requiredSkill,
|
||||
i.itemLevel
|
||||
FROM ?_items i
|
||||
JOIN ?_icons ic ON ic.id = i.iconId
|
||||
WHERE i.gemEnchantmentId <> 0
|
||||
ORDER BY i.id DESC',
|
||||
EXP_BC, EXP_WOTLK
|
||||
);
|
||||
$success = true;
|
||||
|
||||
// check directory-structure
|
||||
foreach (Util::$localeStrings as $dir)
|
||||
if (!CLISetup::writeDir('datasets/'.$dir))
|
||||
$success = false;
|
||||
|
||||
$enchIds = [];
|
||||
foreach ($gems as $pop)
|
||||
$enchIds[] = $pop['enchId'];
|
||||
|
||||
$enchantments = new EnchantmentList(array(['id', $enchIds], Cfg::get('SQL_LIMIT_NONE')));
|
||||
if ($enchantments->error)
|
||||
{
|
||||
CLI::write('Required table ?_itemenchantment seems to be empty! Leaving gems()...', CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (CLISetup::$localeIds as $lId)
|
||||
{
|
||||
set_time_limit(5);
|
||||
|
||||
User::useLocale($lId);
|
||||
Lang::load($lId);
|
||||
|
||||
$gemsOut = [];
|
||||
foreach ($gems as $pop)
|
||||
{
|
||||
if (!$enchantments->getEntry($pop['enchId']))
|
||||
{
|
||||
CLI::write(' * could not find enchantment #'.$pop['enchId'].' referenced by item #'.$pop['itemId'], CLI::LOG_WARN);
|
||||
continue;
|
||||
}
|
||||
|
||||
$gemsOut[$pop['itemId']] = array(
|
||||
'name' => Util::localizedString($pop, 'name'),
|
||||
'quality' => $pop['quality'],
|
||||
'icon' => strToLower($pop['icon']),
|
||||
'enchantment' => $enchantments->getField('name', true),
|
||||
'jsonequip' => $enchantments->getStatGainForCurrent(),
|
||||
'colors' => $pop['colors'],
|
||||
'expansion' => $pop['expansion'],
|
||||
'gearscore' => Util::getGemScore($pop['itemLevel'], $pop['quality'], $pop['requiredSkill'] == SKILL_JEWELCRAFTING, $pop['itemId'])
|
||||
);
|
||||
}
|
||||
|
||||
$toFile = "var g_gems = ".Util::toJSON($gemsOut).";";
|
||||
$file = 'datasets/'.User::$localeString.'/gems';
|
||||
|
||||
if (!CLISetup::writeFile($file, $toFile))
|
||||
$success = false;
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
?>
|
||||
101
setup/tools/filegen/gems.ss.php
Normal file
101
setup/tools/filegen/gems.ss.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/* Example
|
||||
22460: {
|
||||
name:'Prismatic Sphere',
|
||||
quality:3,
|
||||
icon:'INV_Enchant_PrismaticSphere',
|
||||
enchantment:'+3 Resist All',
|
||||
jsonequip:{"arcres":3,"avgbuyout":242980,"firres":3,"frores":3,"holres":3,"natres":3,"shares":3},
|
||||
colors:14,
|
||||
expansion:1
|
||||
gearscore:8 // if only..
|
||||
},
|
||||
*/
|
||||
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
protected $info = array(
|
||||
'gems' => [[], CLISetup::ARGV_PARAM, 'Compiles gems to file for the item comparison tool and profiler tool.']
|
||||
);
|
||||
|
||||
protected $setupAfter = [['items', 'itemenchantment', 'icons'], []];
|
||||
protected $requiredDirs = ['datasets/'];
|
||||
protected $localized = true;
|
||||
|
||||
public function generate() : bool
|
||||
{
|
||||
// sketchy, but should work
|
||||
// id < 36'000 || ilevel < 70 ? BC : WOTLK
|
||||
$gems = DB::Aowow()->select(
|
||||
'SELECT i.id AS itemId,
|
||||
i.name_loc0, i.name_loc2, i.name_loc3, i.name_loc4, i.name_loc6, i.name_loc8,
|
||||
IF (i.id < 36000 OR i.itemLevel < 70, ?d, ?d) AS expansion,
|
||||
i.quality,
|
||||
ic.name AS icon,
|
||||
i.gemEnchantmentId AS enchId,
|
||||
i.gemColorMask AS colors,
|
||||
i.requiredSkill,
|
||||
i.itemLevel
|
||||
FROM ?_items i
|
||||
JOIN ?_icons ic ON ic.id = i.iconId
|
||||
WHERE i.gemEnchantmentId <> 0
|
||||
ORDER BY i.id DESC',
|
||||
EXP_BC, EXP_WOTLK
|
||||
);
|
||||
|
||||
$enchantments = new EnchantmentList(array(['id', array_column($gems, 'enchId')], Cfg::get('SQL_LIMIT_NONE')));
|
||||
if ($enchantments->error)
|
||||
{
|
||||
CLI::write('[gems] Required table ?_itemenchantment seems to be empty!', CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (CLISetup::$localeIds as $lId)
|
||||
{
|
||||
set_time_limit(5);
|
||||
|
||||
User::useLocale($lId);
|
||||
Lang::load($lId);
|
||||
|
||||
$gemsOut = [];
|
||||
foreach ($gems as $g)
|
||||
{
|
||||
if (!$enchantments->getEntry($g['enchId']))
|
||||
{
|
||||
CLI::write('[gems] * could not find enchantment #'.$g['enchId'].' referenced by item #'.$g['itemId'], CLI::LOG_WARN);
|
||||
continue;
|
||||
}
|
||||
|
||||
$gemsOut[$g['itemId']] = array(
|
||||
'name' => Util::localizedString($g, 'name'),
|
||||
'quality' => $g['quality'],
|
||||
'icon' => strToLower($g['icon']),
|
||||
'enchantment' => $enchantments->getField('name', true),
|
||||
'jsonequip' => $enchantments->getStatGainForCurrent(),
|
||||
'colors' => $g['colors'],
|
||||
'expansion' => $g['expansion'],
|
||||
'gearscore' => Util::getGemScore($g['itemLevel'], $g['quality'], $g['requiredSkill'] == SKILL_JEWELCRAFTING, $g['itemId'])
|
||||
);
|
||||
}
|
||||
|
||||
$toFile = "var g_gems = ".Util::toJSON($gemsOut).";";
|
||||
$file = 'datasets/'.User::$localeString.'/gems';
|
||||
|
||||
if (!CLISetup::writeFile($file, $toFile))
|
||||
$this->success = false;
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -7,24 +7,30 @@ if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/* Example
|
||||
40896: {
|
||||
"name":"Glyph of Frenzied Regeneration",
|
||||
"description":"For 6 sec after activating Frenzied Regeneration, healing effects on you are 40% more powerful. However, your Frenzied Regeneration now always costs 60 Rage and no longer converts Rage into health.",
|
||||
"icon":"ability_bullrush",
|
||||
"type":1,
|
||||
"classs":11,
|
||||
"skill":798,
|
||||
"level":25,
|
||||
},
|
||||
*/
|
||||
/* Example
|
||||
40896: {
|
||||
"name":"Glyph of Frenzied Regeneration",
|
||||
"description":"For 6 sec after activating Frenzied Regeneration, healing effects on you are 40% more powerful. However, your Frenzied Regeneration now always costs 60 Rage and no longer converts Rage into health.",
|
||||
"icon":"ability_bullrush",
|
||||
"type":1,
|
||||
"classs":11,
|
||||
"skill":798,
|
||||
"level":25,
|
||||
},
|
||||
*/
|
||||
|
||||
// Create 'glyphs'-file for available locales
|
||||
// this script requires the following dbc-files to be parsed and available
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
protected $info = array(
|
||||
'glyphs' => [[], CLISetup::ARGV_PARAM, 'Compiles glyphs to file for the talent calculator tool.']
|
||||
);
|
||||
|
||||
function glyphs()
|
||||
protected $setupAfter = [['items', 'spell', 'glyphproperties', 'icons'], []];
|
||||
protected $requiredDirs = ['datasets/'];
|
||||
protected $localized = true;
|
||||
|
||||
public function generate() : bool
|
||||
{
|
||||
$success = true;
|
||||
$glyphList = DB::Aowow()->Select(
|
||||
'SELECT i.id AS itemId,
|
||||
i.*,
|
||||
@@ -41,12 +47,8 @@ if (!CLI)
|
||||
JOIN ?_glyphproperties g ON g.id = s1.effect1MiscValue
|
||||
JOIN ?_spell s2 ON s2.id = g.spellId
|
||||
JOIN ?_icons ic ON ic.id = s1.iconIdAlt
|
||||
WHERE i.classBak = 16');
|
||||
|
||||
// check directory-structure
|
||||
foreach (Util::$localeStrings as $dir)
|
||||
if (!CLISetup::writeDir('datasets/'.$dir))
|
||||
$success = false;
|
||||
WHERE i.classBak = ?d',
|
||||
ITEM_CLASS_GLYPH);
|
||||
|
||||
$glyphSpells = new SpellList(array(['s.id', array_keys($glyphList)], Cfg::get('SQL_LIMIT_NONE')));
|
||||
|
||||
@@ -83,9 +85,11 @@ if (!CLI)
|
||||
$file = 'datasets/'.User::$localeString.'/glyphs';
|
||||
|
||||
if (!CLISetup::writeFile($file, $toFile))
|
||||
$success = false;
|
||||
$this->success = false;
|
||||
}
|
||||
|
||||
return $success;
|
||||
return $this->success;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
130
setup/tools/filegen/img-artwork.ss.php
Normal file
130
setup/tools/filegen/img-artwork.ss.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
use TrComplexImage;
|
||||
|
||||
protected $info = array(
|
||||
'img-artwork' => [[], CLISetup::ARGV_PARAM, 'Generate images from /glues/credits (not used on page)'],
|
||||
);
|
||||
|
||||
public $isOptional = true;
|
||||
|
||||
private const TILEORDER = array(
|
||||
1 => [ [1] ],
|
||||
2 => [ [1],
|
||||
[2] ],
|
||||
4 => [ [1, 2],
|
||||
[3, 4] ],
|
||||
6 => [ [1, 2, 3],
|
||||
[4, 5, 6] ],
|
||||
8 => [ [1, 2, 3, 4],
|
||||
[5, 6, 7, 8] ],
|
||||
9 => [ [1, 2, 3],
|
||||
[4, 5, 6],
|
||||
[7, 8, 9] ]
|
||||
);
|
||||
|
||||
// src, resourcePath, localized, [tileOrder], [[dest, destW, destH]]
|
||||
private $genSteps = array(
|
||||
['Glues/Credits/', null, false, self::TILEORDER, [['cache/Artworks/', 0, 0]]]
|
||||
);
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->imgPath = CLISetup::$srcDir.$this->imgPath;
|
||||
$this->maxExecTime = ini_get('max_execution_time');
|
||||
|
||||
foreach ($this->genSteps[0][self::$GEN_IDX_DEST_INFO] as $dir)
|
||||
$this->requiredDirs[] = $dir[0];
|
||||
}
|
||||
|
||||
public function generate() : bool
|
||||
{
|
||||
if (!$this->checkSourceDirs())
|
||||
{
|
||||
CLI::write('one or more source directories are missing:', CLI::LOG_ERROR);
|
||||
$this->success = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
sleep(2);
|
||||
|
||||
[, $realPath, , $tileOrder, $outInfo] = $this->genSteps[0];
|
||||
|
||||
$sum = 0;
|
||||
$imgGroups = [];
|
||||
$files = CLISetup::filesInPath('/'.str_replace('/', '\\/', $realPath).'/i', true);
|
||||
$fileTpl = $outInfo[0][0].'%s.png';
|
||||
|
||||
foreach ($files as $f)
|
||||
{
|
||||
if (preg_match('/([^\/]+)(\d).blp/i', $f, $m))
|
||||
{
|
||||
if (!$m[1] || !$m[2])
|
||||
continue;
|
||||
|
||||
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
|
||||
if (isset($imgGroups['Desolace']))
|
||||
$imgGroups['Desolace'] = 4;
|
||||
|
||||
$total = count($imgGroups);
|
||||
|
||||
CLI::write('Processing '.$total.' files from '.$realPath.' ...');
|
||||
|
||||
foreach ($imgGroups as $name => $fmt)
|
||||
{
|
||||
ini_set('max_execution_time', $this->maxExecTime);
|
||||
|
||||
$sum++;
|
||||
$this->status = ' - '.str_pad($sum.'/'.$total, 8).str_pad('('.number_format($sum * 100 / $total, 2).'%)', 9);
|
||||
$file = sprintf($fileTpl, $name);
|
||||
|
||||
if (!CLISetup::getOpt('force') && file_exists($file))
|
||||
{
|
||||
CLI::write($this->status.' - file '.$file.' was already processed', CLI::LOG_BLANK, true, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($tileOrder[$fmt]))
|
||||
{
|
||||
CLI::write(' - pattern for file '.$name.' not set. skipping', CLI::LOG_WARN);
|
||||
$this->success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
$order = $tileOrder[$fmt];
|
||||
|
||||
$im = $this->assembleImage($realPath.'/'.$name, $order, count($order[0]) * 256, count($order) * 256);
|
||||
if (!$im)
|
||||
{
|
||||
CLI::write(' - could not assemble file '.$name, CLI::LOG_ERROR);
|
||||
$this->success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$this->writeImageFile($im, $file, count($order[0]) * 256, count($order) * 256))
|
||||
$this->success = false;
|
||||
}
|
||||
|
||||
ini_set('max_execution_time', $this->maxExecTime);
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
1082
setup/tools/filegen/img-maps.ss.php
Normal file
1082
setup/tools/filegen/img-maps.ss.php
Normal file
File diff suppressed because it is too large
Load Diff
110
setup/tools/filegen/img-talentcalc.ss.php
Normal file
110
setup/tools/filegen/img-talentcalc.ss.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
use TrComplexImage;
|
||||
|
||||
protected $info = array(
|
||||
'img-talentcalc' => [[], CLISetup::ARGV_PARAM, 'Generate backgrounds for the talent calculator.'],
|
||||
);
|
||||
|
||||
protected $dbcSourceFiles = ['talenttab', 'chrclasses'];
|
||||
|
||||
private const DEST_DIRS = array(
|
||||
['static/images/wow/hunterpettalents/', 0, 0],
|
||||
['static/images/wow/talents/backgrounds/', 0, 0]
|
||||
);
|
||||
|
||||
private const TILEORDER = array(
|
||||
['-TopLeft', '-TopRight'],
|
||||
['-BottomLeft', '-BottomRight']
|
||||
);
|
||||
|
||||
// src, resourcePath, localized, [tileOrder], [[dest, destW, destH]]
|
||||
private $genSteps = array(
|
||||
['TalentFrame/', null, false, self::TILEORDER, self::DEST_DIRS]
|
||||
);
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->imgPath = CLISetup::$srcDir.$this->imgPath;
|
||||
$this->maxExecTime = ini_get('max_execution_time');
|
||||
|
||||
// init directories
|
||||
foreach (self::DEST_DIRS as $dir)
|
||||
$this->requiredDirs[] = $dir[0];
|
||||
}
|
||||
|
||||
public function generate() : bool
|
||||
{
|
||||
if (!$this->checkSourceDirs())
|
||||
{
|
||||
CLI::write('one or more source directories are missing:', CLI::LOG_ERROR);
|
||||
$this->success = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
sleep(2);
|
||||
|
||||
$tTabs = DB::Aowow()->select('SELECT tt.creatureFamilyMask, tt.textureFile, tt.tabNumber, cc.fileString FROM dbc_talenttab tt LEFT JOIN dbc_chrclasses cc ON cc.id = (LOG(2, tt.classMask) + 1)');
|
||||
if (!$tTabs)
|
||||
{
|
||||
CLI::write(' - TalentTab.dbc or ChrClasses.dbc is empty...?', CLI::LOG_ERROR);
|
||||
$this->success = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
$sum = 0;
|
||||
$total = count($tTabs);
|
||||
[, $realPath, , $tileOrder, $outInfo] = $this->genSteps[0];
|
||||
|
||||
CLI::write('Processing '.$total.' files from '.$realPath.' ...');
|
||||
foreach ($tTabs as $tt)
|
||||
{
|
||||
ini_set('max_execution_time', $this->maxExecTime);
|
||||
$sum++;
|
||||
$this->status = ' - '.str_pad($sum.'/'.$total, 8).str_pad('('.number_format($sum * 100 / $total, 2).'%)', 9);
|
||||
|
||||
if ($tt['creatureFamilyMask']) // is PetCalc
|
||||
{
|
||||
$size = [244, 364];
|
||||
$outFile = sprintf($outInfo[0][0].'bg_%d.jpg', log($tt['creatureFamilyMask'], 2) + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
$size = [204, 554];
|
||||
$outFile = sprintf($outInfo[1][0].'%s_%d.jpg', strtolower($tt['fileString']), $tt['tabNumber'] + 1);
|
||||
}
|
||||
|
||||
if (!CLISetup::getOpt('force') && file_exists($outFile))
|
||||
{
|
||||
CLI::write($this->status.' - file '.$outFile.' was already processed', CLI::LOG_BLANK, true, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
$im = $this->assembleImage($realPath.'/'.$tt['textureFile'], $tileOrder, 256 + 44, 256 + 75);
|
||||
if (!$im)
|
||||
{
|
||||
CLI::write(' - could not assemble file '.$tt['textureFile'], CLI::LOG_ERROR);
|
||||
$this->success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$this->writeImageFile($im, $outFile, $size[0], $size[1]))
|
||||
$this->success = false;
|
||||
}
|
||||
|
||||
ini_set('max_execution_time', $this->maxExecTime);
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,114 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
// Create 'item-scaling'-file in datasets;
|
||||
$reqDBC = ['scalingstatdistribution', 'scalingstatvalues', 'gtoctclasscombatratingscalar', 'gtcombatratings'];
|
||||
|
||||
function debugify($data)
|
||||
{
|
||||
$buff = [];
|
||||
foreach ($data as $id => $row)
|
||||
{
|
||||
foreach ($row as &$r)
|
||||
$r = str_pad($r, 5, " ", STR_PAD_LEFT);
|
||||
|
||||
$buff[] = str_pad($id, 7, " ", STR_PAD_LEFT).": [".implode(', ', $row)."]";
|
||||
}
|
||||
|
||||
return "{\r\n".implode(",\r\n", $buff)."\r\n}";
|
||||
}
|
||||
|
||||
function itemScalingRB()
|
||||
{
|
||||
$ratings = array(
|
||||
12 => 1, // ITEM_MOD_DEFENSE_SKILL_RATING => CR_DEFENSE_SKILL
|
||||
13 => 2, // ITEM_MOD_DODGE_RATING => CR_DODGE
|
||||
14 => 3, // ITEM_MOD_PARRY_RATING => CR_PARRY
|
||||
15 => 4, // ITEM_MOD_BLOCK_RATING => CR_BLOCK
|
||||
16 => 5, // ITEM_MOD_HIT_MELEE_RATING => CR_HIT_MELEE
|
||||
17 => 6, // ITEM_MOD_HIT_RANGED_RATING => CR_HIT_RANGED
|
||||
18 => 7, // ITEM_MOD_HIT_SPELL_RATING => CR_HIT_SPELL
|
||||
19 => 8, // ITEM_MOD_CRIT_MELEE_RATING => CR_CRIT_MELEE
|
||||
20 => 9, // ITEM_MOD_CRIT_RANGED_RATING => CR_CRIT_RANGED
|
||||
21 => 10, // ITEM_MOD_CRIT_SPELL_RATING => CR_CRIT_SPELL
|
||||
22 => 11, // ITEM_MOD_HIT_TAKEN_MELEE_RATING => CR_HIT_TAKEN_MELEE
|
||||
23 => 12, // ITEM_MOD_HIT_TAKEN_RANGED_RATING => CR_HIT_TAKEN_RANGED
|
||||
24 => 13, // ITEM_MOD_HIT_TAKEN_SPELL_RATING => CR_HIT_TAKEN_SPELL
|
||||
25 => 14, // ITEM_MOD_CRIT_TAKEN_MELEE_RATING => CR_CRIT_TAKEN_MELEE [may be forced 0]
|
||||
26 => 15, // ITEM_MOD_CRIT_TAKEN_RANGED_RATING => CR_CRIT_TAKEN_RANGED [may be forced 0]
|
||||
27 => 16, // ITEM_MOD_CRIT_TAKEN_SPELL_RATING => CR_CRIT_TAKEN_SPELL [may be forced 0]
|
||||
28 => 17, // ITEM_MOD_HASTE_MELEE_RATING => CR_HASTE_MELEE
|
||||
29 => 18, // ITEM_MOD_HASTE_RANGED_RATING => CR_HASTE_RANGED
|
||||
30 => 19, // ITEM_MOD_HASTE_SPELL_RATING => CR_HASTE_SPELL
|
||||
31 => 5, // ITEM_MOD_HIT_RATING => [backRef]
|
||||
32 => 8, // ITEM_MOD_CRIT_RATING => [backRef]
|
||||
33 => 11, // ITEM_MOD_HIT_TAKEN_RATING => [backRef] [may be forced 0]
|
||||
34 => 14, // ITEM_MOD_CRIT_TAKEN_RATING => [backRef] [may be forced 0]
|
||||
35 => 14, // ITEM_MOD_RESILIENCE_RATING => [backRef]
|
||||
36 => 17, // ITEM_MOD_HASTE_RATING => [backRef]
|
||||
37 => 23, // ITEM_MOD_EXPERTISE_RATING => CR_EXPERTISE
|
||||
44 => 24 // ITEM_MOD_ARMOR_PENETRATION_RATING => CR_ARMOR_PENETRATION
|
||||
);
|
||||
|
||||
$data = $ratings;
|
||||
|
||||
$offsets = array_map(function ($v) { // LookupEntry(cr*GT_MAX_LEVEL+level-1)
|
||||
return $v * 100 + 60 - 1;
|
||||
}, $ratings);
|
||||
$base = DB::Aowow()->selectCol('SELECT CAST((idx + 1 - 60) / 100 AS UNSIGNED) AS ARRAY_KEY, ratio FROM dbc_gtcombatratings WHERE idx IN (?a)', $offsets);
|
||||
|
||||
$offsets = array_map(function ($v) { // LookupEntry((getClass()-1)*GT_MAX_RATING+cr+1)
|
||||
return (CLASS_WARRIOR - 1) * 32 + $v + 1;
|
||||
}, $ratings);
|
||||
$mods = DB::Aowow()->selectCol('SELECT idx - 1 AS ARRAY_KEY, ratio FROM dbc_gtoctclasscombatratingscalar WHERE idx IN (?a)', $offsets);
|
||||
|
||||
foreach ($data as $itemMod => &$val)
|
||||
$val = Cfg::get('DEBUG') ? $base[$val].' / '.$mods[$val] : $base[$val] / $mods[$val];
|
||||
|
||||
if (!Cfg::get('DEBUG'))
|
||||
return Util::toJSON($data);
|
||||
|
||||
$buff = [];
|
||||
foreach ($data as $k => $v)
|
||||
$buff[] = $k.': '.$v;
|
||||
|
||||
return "{\r\n ".implode(",\r\n ", $buff)."\r\n}";
|
||||
}
|
||||
|
||||
function itemScalingSV()
|
||||
{
|
||||
/* so the javascript expects a slightly different structure, than the dbc provides .. f*** it
|
||||
e.g.
|
||||
dbc - 80: 97 97 56 41 210 395 878 570 120 156 86 112 108 220 343 131 73 140 280 527 1171 2093
|
||||
expected - 80: 97 97 56 131 41 210 395 878 1570 120 156 86 112 108 220 343 0 0 73 140 280 527 1171 2093
|
||||
*/
|
||||
$fields = Util::$ssdMaskFields;
|
||||
array_walk($fields, function(&$v, $k) {
|
||||
$v = $v ?: '0 AS idx'.$k; // NULL => 0 (plus some index so we can have 2x 0)
|
||||
});
|
||||
|
||||
$data = DB::Aowow()->select('SELECT id AS ARRAY_KEY, '.implode(', ', $fields).' FROM dbc_scalingstatvalues');
|
||||
foreach ($data as &$d)
|
||||
$d = array_values($d); // strip indizes
|
||||
|
||||
return Cfg::get('DEBUG') ? debugify($data) : Util::toJSON($data);
|
||||
}
|
||||
|
||||
function itemScalingSD()
|
||||
{
|
||||
$data = DB::Aowow()->select('SELECT *, id AS ARRAY_KEY FROM dbc_scalingstatdistribution');
|
||||
foreach ($data as &$row)
|
||||
{
|
||||
$row = array_values($row);
|
||||
array_splice($row, 0, 1);
|
||||
}
|
||||
|
||||
return Cfg::get('DEBUG') ? debugify($data) : Util::toJSON($data);
|
||||
}
|
||||
?>
|
||||
136
setup/tools/filegen/itemscaling.ss.php
Normal file
136
setup/tools/filegen/itemscaling.ss.php
Normal file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
use TrTemplateFile;
|
||||
|
||||
protected $info = array(
|
||||
'itemscaling' => [[], CLISetup::ARGV_PARAM, 'Compiles item scaling data to file to make heirloom tooltips interactive.']
|
||||
);
|
||||
|
||||
protected $fileTemplateDest = ['datasets/item-scaling'];
|
||||
protected $fileTemplateSrc = ['item-scaling.in'];
|
||||
|
||||
protected $dbcSourceFiles = ['scalingstatdistribution', 'scalingstatvalues', 'gtoctclasscombatratingscalar', 'gtcombatratings'];
|
||||
|
||||
private function debugify(array $data) : string
|
||||
{
|
||||
$buff = [];
|
||||
foreach ($data as $id => $row)
|
||||
{
|
||||
foreach ($row as &$r)
|
||||
$r = str_pad($r, 5, " ", STR_PAD_LEFT);
|
||||
|
||||
$buff[] = str_pad($id, 7, " ", STR_PAD_LEFT).": [".implode(', ', $row)."]";
|
||||
}
|
||||
|
||||
return "{\r\n".implode(",\r\n", $buff)."\r\n}";
|
||||
}
|
||||
|
||||
private function itemScalingRB() : string
|
||||
{
|
||||
// data and format observed via wayback machine. Not entirely sure about the redunacy within the combat ratings though.
|
||||
$ratings = array(
|
||||
Stat::DEFENSE_RTG => CR_DEFENSE_SKILL,
|
||||
Stat::DODGE_RTG => CR_DODGE,
|
||||
Stat::PARRY_RTG => CR_PARRY,
|
||||
Stat::BLOCK_RTG => CR_BLOCK,
|
||||
Stat::MELEE_HIT_RTG => CR_HIT_MELEE,
|
||||
Stat::RANGED_HIT_RTG => CR_HIT_RANGED,
|
||||
Stat::SPELL_HIT_RTG => CR_HIT_SPELL,
|
||||
Stat::MELEE_CRIT_RTG => CR_CRIT_MELEE,
|
||||
Stat::RANGED_CRIT_RTG => CR_CRIT_RANGED,
|
||||
Stat::SPELL_CRIT_RTG => CR_CRIT_SPELL,
|
||||
Stat::MELEE_HIT_TAKEN_RTG => CR_HIT_TAKEN_MELEE,
|
||||
Stat::RANGED_HIT_TAKEN_RTG => CR_HIT_TAKEN_RANGED,
|
||||
Stat::SPELL_HIT_TAKEN_RTG => CR_HIT_TAKEN_SPELL,
|
||||
Stat::MELEE_CRIT_TAKEN_RTG => CR_CRIT_TAKEN_MELEE, // may be forced 0
|
||||
Stat::RANGED_CRIT_TAKEN_RTG => CR_CRIT_TAKEN_RANGED, // may be forced 0
|
||||
Stat::SPELL_CRIT_TAKEN_RTG => CR_CRIT_TAKEN_SPELL, // may be forced 0
|
||||
Stat::MELEE_HASTE_RTG => CR_HASTE_MELEE,
|
||||
Stat::RANGED_HASTE_RTG => CR_HASTE_RANGED,
|
||||
Stat::SPELL_HASTE_RTG => CR_HASTE_SPELL,
|
||||
Stat::HIT_RTG => CR_HIT_MELEE,
|
||||
Stat::CRIT_RTG => CR_CRIT_MELEE,
|
||||
Stat::HIT_TAKEN_RTG => CR_HIT_TAKEN_MELEE, // may be forced 0
|
||||
Stat::CRIT_TAKEN_RTG => CR_CRIT_TAKEN_MELEE, // may be forced 0
|
||||
Stat::RESILIENCE_RTG => CR_CRIT_TAKEN_MELEE,
|
||||
Stat::HASTE_RTG => CR_HASTE_MELEE,
|
||||
Stat::EXPERTISE_RTG => CR_EXPERTISE,
|
||||
Stat::ARMOR_PENETRATION_RTG => CR_ARMOR_PENETRATION
|
||||
);
|
||||
|
||||
$data = $ratings;
|
||||
|
||||
$offsets = array_map(function ($v) { // LookupEntry(cr*GT_MAX_LEVEL+level-1)
|
||||
return $v * 100 + 60 - 1; // combat rating where introduced during the transition vanilla > burnig crusade. So at level 60 (at the time) the rating on the item was equal to 1% effect and is still the baseline in 3.3.5a.
|
||||
}, $ratings);
|
||||
$base = DB::Aowow()->selectCol('SELECT CAST((idx + 1 - 60) / 100 AS UNSIGNED) AS ARRAY_KEY, ratio FROM dbc_gtcombatratings WHERE idx IN (?a)', $offsets);
|
||||
|
||||
/* non-1 scaler in 3.3.5.12340
|
||||
| ratingId | classId | ratio |
|
||||
| 17 | 2 | 1.3 |
|
||||
| 17 | 6 | 1.3 |
|
||||
| 17 | 7 | 1.3 |
|
||||
| 17 | 11 | 1.3 |
|
||||
| 24 | < all > | 1.1 |
|
||||
*/
|
||||
|
||||
$offsets = array_map(function ($v) { // LookupEntry((getClass()-1)*GT_MAX_RATING+cr+1)
|
||||
return (CLASS_WARRIOR - 1) * 32 + $v + 1; // should this be dynamic per pinned character? ITEM_MOD HASTE has a worse scaler for a subset of classes (see table)
|
||||
}, $ratings);
|
||||
$mods = DB::Aowow()->selectCol('SELECT idx - 1 AS ARRAY_KEY, ratio FROM dbc_gtoctclasscombatratingscalar WHERE idx IN (?a)', $offsets);
|
||||
|
||||
foreach ($data as &$val)
|
||||
$val = Cfg::get('DEBUG') ? $base[$val].' / '.$mods[$val] : $base[$val] / $mods[$val];
|
||||
|
||||
if (!Cfg::get('DEBUG'))
|
||||
return Util::toJSON($data);
|
||||
|
||||
$buff = [];
|
||||
foreach ($data as $k => $v)
|
||||
$buff[] = $k.': '.$v;
|
||||
|
||||
return "{\r\n ".implode(",\r\n ", $buff)."\r\n}";
|
||||
}
|
||||
|
||||
private function itemScalingSV() : string
|
||||
{
|
||||
/* so the javascript expects a slightly different structure, than the dbc provides .. f*** it
|
||||
e.g.
|
||||
dbc - 80: 97 97 56 41 210 395 878 570 120 156 86 112 108 220 343 131 73 140 280 527 1171 2093
|
||||
expected - 80: 97 97 56 131 41 210 395 878 1570 120 156 86 112 108 220 343 0 0 73 140 280 527 1171 2093
|
||||
*/
|
||||
$fields = Util::$ssdMaskFields;
|
||||
array_walk($fields, function(&$v, $k) {
|
||||
$v = $v ?: '0 AS idx'.$k; // NULL => 0 (plus some index so we can have 2x 0)
|
||||
});
|
||||
|
||||
$data = DB::Aowow()->select('SELECT id AS ARRAY_KEY, '.implode(', ', $fields).' FROM dbc_scalingstatvalues');
|
||||
foreach ($data as &$d)
|
||||
$d = array_values($d); // strip indizes
|
||||
|
||||
return Cfg::get('DEBUG') ? $this->debugify($data) : Util::toJSON($data);
|
||||
}
|
||||
|
||||
private function itemScalingSD() : string
|
||||
{
|
||||
$data = DB::Aowow()->select('SELECT *, id AS ARRAY_KEY FROM dbc_scalingstatdistribution');
|
||||
foreach ($data as &$row)
|
||||
{
|
||||
$row = array_values($row);
|
||||
array_splice($row, 0, 1);
|
||||
}
|
||||
|
||||
return Cfg::get('DEBUG') ? $this->debugify($data) : Util::toJSON($data);
|
||||
}
|
||||
})
|
||||
|
||||
?>
|
||||
@@ -7,41 +7,43 @@ if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/* Example
|
||||
"-447": { // internal id, freely chosen
|
||||
"classes":["6"], // array
|
||||
"elite":true,
|
||||
"heroic":false,
|
||||
"id":"-447",
|
||||
"idbak":"924", // actual setId
|
||||
"maxlevel":"390",
|
||||
"minlevel":"390",
|
||||
"name":"3Cataclysmic Gladiator's Desecration",
|
||||
"note":"37", // contentGroup
|
||||
"pieces":["73742","73741","73740","73739","73738"],
|
||||
"reqclass":"32", // mask
|
||||
"type":"4",
|
||||
"setbonus":{
|
||||
"2":{"resirtng":"400","str":"70"},
|
||||
"4":{"str":"90"}
|
||||
}
|
||||
},
|
||||
*/
|
||||
/* Example
|
||||
"-447": { // internal id, freely chosen
|
||||
"classes":["6"], // array
|
||||
"elite":true,
|
||||
"heroic":false,
|
||||
"id":"-447",
|
||||
"idbak":"924", // actual setId
|
||||
"maxlevel":"390",
|
||||
"minlevel":"390",
|
||||
"name":"3Cataclysmic Gladiator's Desecration",
|
||||
"note":"37", // contentGroup
|
||||
"pieces":["73742","73741","73740","73739","73738"],
|
||||
"reqclass":"32", // mask
|
||||
"type":"4",
|
||||
"setbonus":{
|
||||
"2":{"resirtng":"400","str":"70"},
|
||||
"4":{"str":"90"}
|
||||
}
|
||||
},
|
||||
*/
|
||||
|
||||
// Create 'itemsets'-file for available locales
|
||||
// this script requires the following dbc-files to be parsed and available
|
||||
// Create 'itemsets'-file for available locales
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
protected $info = array(
|
||||
'itemsets' => [[], CLISetup::ARGV_PARAM, 'Compiles available item sets used throughout the page to file.']
|
||||
);
|
||||
|
||||
function itemsets()
|
||||
protected $setupAfter = [['itemset', 'spell'], []];
|
||||
protected $requiredDirs = ['datasets/'];
|
||||
protected $localized = true;
|
||||
|
||||
public function generate() : bool
|
||||
{
|
||||
$success = true;
|
||||
$setList = DB::Aowow()->Select('SELECT * FROM ?_itemset ORDER BY refSetId DESC');
|
||||
$jsonBonus = [];
|
||||
|
||||
// check directory-structure
|
||||
foreach (Util::$localeStrings as $dir)
|
||||
if (!CLISetup::writeDir('datasets/'.$dir))
|
||||
$success = false;
|
||||
|
||||
foreach (CLISetup::$localeIds as $lId)
|
||||
{
|
||||
User::useLocale($lId);
|
||||
@@ -55,7 +57,7 @@ if (!CLI)
|
||||
$setOut = array(
|
||||
'id' => $set['id'],
|
||||
'idbak' => $set['refSetId'],
|
||||
'name' => (7 - $set['quality']).Util::jsEscape(Util::localizedString($set, 'name')),
|
||||
'name' => (ITEM_QUALITY_HEIRLOOM - $set['quality']).Util::jsEscape(Util::localizedString($set, 'name')),
|
||||
'pieces' => [],
|
||||
'heroic' => !!$set['heroic'], // should be bool
|
||||
'maxlevel' => $set['maxLevel'],
|
||||
@@ -84,7 +86,7 @@ if (!CLI)
|
||||
$_spells = [];
|
||||
for ($i = 1; $i < 9; $i++)
|
||||
{
|
||||
if (!$set['spell'.$i] || isset($jsonBonus[$set['spell'.$i]]))
|
||||
if (!$set['bonus'.$i] || isset($jsonBonus[$set['spell'.$i]]))
|
||||
continue;
|
||||
|
||||
$_spells[] = $set['spell'.$i];
|
||||
@@ -121,9 +123,11 @@ if (!CLI)
|
||||
$file = 'datasets/'.User::$localeString.'/itemsets';
|
||||
|
||||
if (!CLISetup::writeFile($file, $toFile))
|
||||
$success = false;
|
||||
$this->success = false;
|
||||
}
|
||||
|
||||
return $success;
|
||||
return $this->success;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -7,12 +7,22 @@ if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
// Create 'locale.js'-file in static/js
|
||||
// available locales have to be set in aowow.aowow_config
|
||||
// Create 'locale.js'-file in static/js
|
||||
// available locales have to be set in aowow.aowow_config
|
||||
|
||||
function locales()
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
use TrTemplateFile;
|
||||
|
||||
protected $info = array(
|
||||
'locales' => [[], CLISetup::ARGV_PARAM, 'Compiles the Locale Object (static/js/locale.js) with available languages.']
|
||||
);
|
||||
|
||||
protected $fileTemplateDest = ['static/js/locale.js'];
|
||||
protected $fileTemplateSrc = ['locale.js.in'];
|
||||
|
||||
private function locales() : string
|
||||
{
|
||||
$result = [];
|
||||
$available = array(
|
||||
LOCALE_EN => " 0: { // English\r\n" .
|
||||
" id: LOCALE_ENUS,\r\n" .
|
||||
@@ -52,11 +62,13 @@ if (!CLI)
|
||||
" }",
|
||||
);
|
||||
|
||||
$result = [];
|
||||
foreach (CLISetup::$localeIds as $l)
|
||||
if (isset($available[$l]))
|
||||
$result[] = $available[$l];
|
||||
|
||||
return implode(",\r\n", $result);
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
22
setup/tools/filegen/markup.ss.php
Normal file
22
setup/tools/filegen/markup.ss.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
use TrTemplateFile;
|
||||
|
||||
protected $info = array(
|
||||
'markup' => [[], CLISetup::ARGV_PARAM, 'Fills the markup parser (static/js/Markup.js) with site variables.']
|
||||
);
|
||||
|
||||
protected $fileTemplateSrc = ['Markup.js.in'];
|
||||
protected $fileTemplateDest = ['static/js/Markup.js'];
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,97 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
// builds 'pets'-file for available locales
|
||||
|
||||
/* Example data
|
||||
30: {
|
||||
id:30,
|
||||
name:'Forest Spider',
|
||||
minlevel:5,
|
||||
maxlevel:6,
|
||||
location:[12], // master-AreaTableId's (?)
|
||||
react:[-1,-1],
|
||||
classification:0, // 0:"Normal", 1:"Elite", 2:"Rar Elite", 3:"Boss", 4:"Rar"
|
||||
family:3, // creatureFamily
|
||||
displayId:382,
|
||||
skin:'TarantulaSkinOrange',
|
||||
icon:'Ability_Hunter_Pet_Spider', // from creatureFamily.dbc
|
||||
type:2 // 0:Ferocity, 1:Tenacity, 2:Cunning
|
||||
},
|
||||
*/
|
||||
|
||||
$reqDBC = ['creaturefamily'];
|
||||
|
||||
function pets()
|
||||
{
|
||||
$success = true;
|
||||
$locations = [];
|
||||
$petList = DB::Aowow()->Select(
|
||||
'SELECT cr.id,
|
||||
cr.name_loc0, cr.name_loc2, cr.name_loc3, cr.name_loc4, cr.name_loc6, cr.name_loc8,
|
||||
cr.minLevel,
|
||||
cr.maxLevel,
|
||||
ft.A,
|
||||
ft.H,
|
||||
cr.rank AS classification,
|
||||
cr.family,
|
||||
cr.displayId1 AS displayId,
|
||||
cr.textureString AS skin,
|
||||
LOWER(SUBSTRING_INDEX(cf.iconString, "\\\\", -1)) AS icon,
|
||||
cf.petTalentType AS type
|
||||
FROM ?_creature cr
|
||||
JOIN ?_factiontemplate ft ON ft.id = cr.faction
|
||||
JOIN dbc_creaturefamily cf ON cf.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 (!CLISetup::writeDir('datasets/'.$dir))
|
||||
$success = false;
|
||||
|
||||
foreach (CLISetup::$localeIds as $lId)
|
||||
{
|
||||
User::useLocale($lId);
|
||||
Lang::load($lId);
|
||||
|
||||
$petsOut = [];
|
||||
foreach ($petList as $pet)
|
||||
{
|
||||
// get locations
|
||||
// again: caching will save you time and nerves
|
||||
if (!isset($locations[$pet['id']]))
|
||||
$locations[$pet['id']] = DB::Aowow()->SelectCol('SELECT DISTINCT areaId FROM ?_spawns WHERE type = ?d AND typeId = ?d', Type::NPC, $pet['id']);
|
||||
|
||||
$petsOut[$pet['id']] = array(
|
||||
'id' => $pet['id'],
|
||||
'name' => Util::localizedString($pet, 'name'),
|
||||
'minlevel' => $pet['minLevel'],
|
||||
'maxlevel' => $pet['maxLevel'],
|
||||
'location' => $locations[$pet['id']],
|
||||
'react' => [$pet['A'], $pet['H']],
|
||||
'classification' => $pet['classification'],
|
||||
'family' => $pet['family'],
|
||||
'displayId' => $pet['displayId'],
|
||||
'skin' => $pet['skin'],
|
||||
'icon' => $pet['icon'],
|
||||
'type' => $pet['type']
|
||||
);
|
||||
}
|
||||
|
||||
$toFile = "var g_pets = ".Util::toJSON($petsOut).";";
|
||||
$file = 'datasets/'.User::$localeString.'/pets';
|
||||
|
||||
if (!CLISetup::writeFile($file, $toFile))
|
||||
$success = false;
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
?>
|
||||
95
setup/tools/filegen/pets.ss.php
Normal file
95
setup/tools/filegen/pets.ss.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/* Example data
|
||||
30: {
|
||||
id:30,
|
||||
name:'Forest Spider',
|
||||
minlevel:5,
|
||||
maxlevel:6,
|
||||
location:[12], // master-AreaTableId's (?)
|
||||
react:[-1,-1],
|
||||
classification:0, // 0:"Normal", 1:"Elite", 2:"Rar Elite", 3:"Boss", 4:"Rar"
|
||||
family:3, // creatureFamily
|
||||
displayId:382,
|
||||
skin:'TarantulaSkinOrange',
|
||||
icon:'Ability_Hunter_Pet_Spider', // from creatureFamily.dbc
|
||||
type:2 // 0:Ferocity, 1:Tenacity, 2:Cunning
|
||||
},
|
||||
*/
|
||||
|
||||
// builds 'pets'-file for available locales
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
protected $info = array(
|
||||
'pets' => [[], CLISetup::ARGV_PARAM, 'Compiles tameable hunter pets to file for the talent calculator tool.']
|
||||
);
|
||||
|
||||
protected $dbcSourceFiles = ['creaturefamily'];
|
||||
protected $setupAfter = [['creature', 'factions', 'spawns'], []];
|
||||
protected $requiredDirs = ['datasets/'];
|
||||
protected $localized = true;
|
||||
|
||||
public function generate() : bool
|
||||
{
|
||||
$petList = DB::Aowow()->Select(
|
||||
'SELECT cr.id,
|
||||
cr.name_loc0, cr.name_loc2, cr.name_loc3, cr.name_loc4, cr.name_loc6, cr.name_loc8,
|
||||
cr.minLevel, cr.maxLevel,
|
||||
ft.A, ft.H,
|
||||
cr.rank AS classification,
|
||||
cr.family,
|
||||
cr.displayId1 AS displayId,
|
||||
cr.textureString AS skin,
|
||||
LOWER(SUBSTRING_INDEX(cf.iconString, "\\\\", -1)) AS icon,
|
||||
cf.petTalentType AS type
|
||||
FROM ?_creature cr
|
||||
JOIN ?_factiontemplate ft ON ft.id = cr.faction
|
||||
JOIN dbc_creaturefamily cf ON cf.id = cr.family
|
||||
WHERE cr.typeFlags & 0x1 AND (cr.cuFlags & 0x2) = 0
|
||||
ORDER BY cr.id ASC');
|
||||
|
||||
$locations = DB::Aowow()->selectCol('SELECT `typeId` AS ARRAY_KEY, `areaId` AS ARRAY_KEY2, `areaId` FROM ?_spawns WHERE `type` = ?d AND `typeId` IN (?a) GROUP BY `typeId`, `areaId`', Type::NPC, array_column($petList, 'id'));
|
||||
|
||||
foreach (CLISetup::$localeIds as $lId)
|
||||
{
|
||||
User::useLocale($lId);
|
||||
Lang::load($lId);
|
||||
|
||||
$petsOut = [];
|
||||
foreach ($petList as $pet)
|
||||
{
|
||||
$petsOut[$pet['id']] = array(
|
||||
'id' => $pet['id'],
|
||||
'name' => Util::localizedString($pet, 'name'),
|
||||
'minlevel' => $pet['minLevel'],
|
||||
'maxlevel' => $pet['maxLevel'],
|
||||
'location' => $locations[$pet['id']] ?? [],
|
||||
'react' => [$pet['A'], $pet['H']],
|
||||
'classification' => $pet['classification'],
|
||||
'family' => $pet['family'],
|
||||
'displayId' => $pet['displayId'],
|
||||
'skin' => $pet['skin'],
|
||||
'icon' => $pet['icon'],
|
||||
'type' => $pet['type']
|
||||
);
|
||||
}
|
||||
|
||||
$toFile = "var g_pets = ".Util::toJSON($petsOut).";";
|
||||
$file = 'datasets/'.User::$localeString.'/pets';
|
||||
|
||||
if (!CLISetup::writeFile($file, $toFile))
|
||||
$this->success = false;
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,473 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
// 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()
|
||||
{
|
||||
$success = true;
|
||||
$scripts = [];
|
||||
$exclusions = [];
|
||||
|
||||
$exAdd = function ($type, $typeId, $groups, $comment = '') use(&$exclusions)
|
||||
{
|
||||
$k = $type.'-'.$typeId;
|
||||
|
||||
if (!isset($exclusions[$k]))
|
||||
$exclusions[$k] = ['type' => $type, 'typeId' => $typeId, 'groups' => $groups, 'comment' => $comment];
|
||||
else
|
||||
{
|
||||
$exclusions[$k]['groups'] |= $groups;
|
||||
if ($comment)
|
||||
$exclusions[$k]['comment'] .= '; '.$comment;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
$sumTotal = function(array &$sumArr, int $raceMask = -1, int $classMask= -1)
|
||||
{
|
||||
for ($i = 0; $i < RACE_MASK_ALL; $i++)
|
||||
{
|
||||
if (!((1 << $i) & $raceMask) || !((1 << $i) & RACE_MASK_ALL))
|
||||
continue;
|
||||
|
||||
for ($j = 0; $j < CLASS_MASK_ALL; $j++)
|
||||
{
|
||||
if (!((1 << $j) & $classMask) || !((1 << $j) & CLASS_MASK_ALL))
|
||||
continue;
|
||||
|
||||
if (!isset($sumArr[$i+1][$j+1]))
|
||||
$sumArr[$i+1][$j+1] = 1;
|
||||
else
|
||||
$sumArr[$i+1][$j+1]++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
$spellFactions = DB::World()->selectCol('SELECT `alliance_id` AS ARRAY_KEY, 1 FROM player_factionchange_spells UNION SELECT `horde_id` AS ARRAY_KEY, 2 FROM player_factionchange_spells');
|
||||
|
||||
/**********/
|
||||
/* Quests */
|
||||
/**********/
|
||||
$scripts[] = function() use ($exAdd, $sumTotal)
|
||||
{
|
||||
$success = true;
|
||||
$questorder = [];
|
||||
$questtotal = [];
|
||||
$condition = [
|
||||
Cfg::get('SQL_LIMIT_NONE'),
|
||||
'AND',
|
||||
[['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW | CUSTOM_UNAVAILABLE | CUSTOM_DISABLED, '&'], 0],
|
||||
[['flags', QUEST_FLAG_DAILY | QUEST_FLAG_WEEKLY | QUEST_FLAG_REPEATABLE | QUEST_FLAG_AUTO_REWARDED, '&'], 0],
|
||||
[['specialFlags', QUEST_FLAG_SPECIAL_REPEATABLE | QUEST_FLAG_SPECIAL_DUNGEON_FINDER | QUEST_FLAG_SPECIAL_MONTHLY, '&'], 0]
|
||||
];
|
||||
|
||||
foreach (Game::$questClasses as $cat2 => $cat)
|
||||
{
|
||||
if ($cat2 < 0)
|
||||
continue;
|
||||
|
||||
$cond = array_merge($condition, [['zoneOrSort', $cat]]);
|
||||
$questz = new QuestList($cond);
|
||||
if ($questz->error)
|
||||
continue;
|
||||
|
||||
$questorder[] = $cat2;
|
||||
$questtotal[$cat2] = [];
|
||||
|
||||
// get quests for exclusion
|
||||
foreach ($questz->iterate() as $id => $__)
|
||||
{
|
||||
$sumTotal($questtotal[$cat2], $questz->getField('reqRaceMask') ?: -1, $questz->getField('reqClassMask') ?: -1);
|
||||
|
||||
switch ($questz->getField('reqSkillId'))
|
||||
{
|
||||
case 356:
|
||||
$exAdd(Type::QUEST, $id, PR_EXCLUDE_GROUP_REQ_FISHING);
|
||||
break;
|
||||
case 202:
|
||||
$exAdd(Type::QUEST, $id, PR_EXCLUDE_GROUP_REQ_ENGINEERING);
|
||||
break;
|
||||
case 197:
|
||||
$exAdd(Type::QUEST, $id, PR_EXCLUDE_GROUP_REQ_TAILORING);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$_ = [];
|
||||
$currencies = array_column($questz->rewards, Type::CURRENCY);
|
||||
foreach ($currencies as $curr)
|
||||
foreach ($curr as $cId => $qty)
|
||||
$_[] = $cId;
|
||||
|
||||
$relCurr = new CurrencyList(array(['id', $_]));
|
||||
|
||||
foreach (CLISetup::$localeIds as $l)
|
||||
{
|
||||
set_time_limit(20);
|
||||
|
||||
User::useLocale($l);
|
||||
Lang::load($l);
|
||||
|
||||
if (!$relCurr->error)
|
||||
{
|
||||
$buff = "var _ = g_gatheredcurrencies;\n";
|
||||
foreach ($relCurr->getListviewData() as $id => $data)
|
||||
$buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
|
||||
}
|
||||
|
||||
$buff .= "var _ = g_quests;\n";
|
||||
foreach ($questz->getListviewData() as $id => $data)
|
||||
$buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
|
||||
|
||||
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-quests-'.$cat2, $buff))
|
||||
$success = false;
|
||||
}
|
||||
}
|
||||
|
||||
$buff = "g_quest_catorder = ".Util::toJSON($questorder).";\n";
|
||||
$buff .= "g_quest_catorder_total = {};\n";
|
||||
foreach ($questtotal as $cat => $totals)
|
||||
$buff .= "g_quest_catorder_total[".$cat."] = ".Util::toJSON($totals).";\n";
|
||||
|
||||
if (!CLISetup::writeFile('datasets/p-quests', $buff))
|
||||
$success = false;
|
||||
|
||||
return $success;
|
||||
};
|
||||
|
||||
/**********/
|
||||
/* Titles */
|
||||
/**********/
|
||||
$scripts[] = function() use ($exAdd)
|
||||
{
|
||||
$success = true;
|
||||
$condition = array(
|
||||
Cfg::get('SQL_LIMIT_NONE'),
|
||||
[['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0],
|
||||
);
|
||||
$titlez = new TitleList($condition);
|
||||
|
||||
// get titles for exclusion
|
||||
foreach ($titlez->iterate() as $id => $__)
|
||||
if (empty($titlez->sources[$id][4]) && empty($titlez->sources[$id][12]))
|
||||
$exAdd(Type::TITLE, $id, PR_EXCLUDE_GROUP_UNAVAILABLE);
|
||||
|
||||
foreach (CLISetup::$localeIds as $l)
|
||||
{
|
||||
set_time_limit(5);
|
||||
|
||||
User::useLocale($l);
|
||||
Lang::load($l);
|
||||
|
||||
foreach ([0, 1] as $g) // gender
|
||||
{
|
||||
$buff = "var _ = g_titles;\n";
|
||||
foreach ($titlez->getListviewData() as $id => $data)
|
||||
{
|
||||
$data['name'] = Util::localizedString($titlez->getEntry($id), $g ? 'female' : 'male');
|
||||
unset($data['namefemale']);
|
||||
$buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
|
||||
}
|
||||
|
||||
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-titles-'.$g, $buff))
|
||||
$success = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $success;
|
||||
};
|
||||
|
||||
/**********/
|
||||
/* Mounts */
|
||||
/**********/
|
||||
$scripts[] = function() use ($exAdd, $spellFactions)
|
||||
{
|
||||
$success = true;
|
||||
$condition = array(
|
||||
Cfg::get('SQL_LIMIT_NONE'),
|
||||
[['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0],
|
||||
['typeCat', -5],
|
||||
['castTime', 0, '!']
|
||||
);
|
||||
$mountz = new SpellList($condition);
|
||||
|
||||
$conditionSet = DB::World()->selectCol('SELECT SourceEntry AS ARRAY_KEY, ConditionValue1 FROM conditions WHERE SourceTypeOrReferenceId = ?d AND ConditionTypeOrReference = ?d AND SourceEntry IN (?a)', Conditions::SRC_SPELL, Conditions::SKILL, $mountz->getFoundIDs());
|
||||
|
||||
// get mounts for exclusion
|
||||
foreach ($conditionSet as $mount => $skill)
|
||||
{
|
||||
if ($skill == 202)
|
||||
$exAdd(Type::SPELL, $mount, PR_EXCLUDE_GROUP_REQ_ENGINEERING);
|
||||
else if ($skill == 197)
|
||||
$exAdd(Type::SPELL, $mount, PR_EXCLUDE_GROUP_REQ_TAILORING);
|
||||
}
|
||||
|
||||
foreach ($mountz->iterate() as $id => $_)
|
||||
if (!$mountz->getSources())
|
||||
$exAdd(Type::SPELL, $id, PR_EXCLUDE_GROUP_UNAVAILABLE);
|
||||
|
||||
foreach (CLISetup::$localeIds as $l)
|
||||
{
|
||||
set_time_limit(5);
|
||||
|
||||
User::useLocale($l);
|
||||
Lang::load($l);
|
||||
|
||||
$buff = "var _ = g_spells;\n";
|
||||
foreach ($mountz->getListviewData(ITEMINFO_MODEL) as $id => $data)
|
||||
{
|
||||
// two cases where the spell is unrestricted but the castitem has class restriction (too lazy to formulate ruleset)
|
||||
if ($id == 66906) // Argent Charger
|
||||
$data['reqclass'] = CLASS_PALADIN;
|
||||
else if ($id == 54729) // Winged Steed of the Ebon Blade
|
||||
$data['reqclass'] = CLASS_DEATHKNIGHT;
|
||||
|
||||
rsort($data['skill']); // riding (777) expected at pos 0
|
||||
|
||||
$data['side'] = $spellFactions[$id] ?? SIDE_BOTH;
|
||||
$data['quality'] = $data['name'][0];
|
||||
$data['name'] = mb_substr($data['name'], 1);
|
||||
$buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
|
||||
}
|
||||
|
||||
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-mounts', $buff))
|
||||
$success = false;
|
||||
}
|
||||
|
||||
return $success;
|
||||
};
|
||||
|
||||
/**************/
|
||||
/* Companions */
|
||||
/**************/
|
||||
$scripts[] = function() use ($exAdd, $spellFactions)
|
||||
{
|
||||
$success = true;
|
||||
$condition = array(
|
||||
Cfg::get('SQL_LIMIT_NONE'),
|
||||
[['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0],
|
||||
['typeCat', -6]
|
||||
);
|
||||
$companionz = new SpellList($condition);
|
||||
$legit = DB::Aowow()->selectCol('SELECT `spellId2` FROM ?_items WHERE `class` = ?d AND `subClass` = ?d AND `spellId1` IN (?a) AND `spellId2` IN (?a)', ITEM_CLASS_MISC, 2, LEARN_SPELLS, $companionz->getFoundIDs());
|
||||
|
||||
foreach ($companionz->iterate() as $id => $_)
|
||||
if (!$companionz->getSources())
|
||||
$exAdd(Type::SPELL, $id, PR_EXCLUDE_GROUP_UNAVAILABLE);
|
||||
|
||||
foreach (CLISetup::$localeIds as $l)
|
||||
{
|
||||
set_time_limit(5);
|
||||
|
||||
User::useLocale($l);
|
||||
Lang::load($l);
|
||||
|
||||
$buff = "var _ = g_spells;\n";
|
||||
foreach ($companionz->getListviewData(ITEMINFO_MODEL) as $id => $data)
|
||||
{
|
||||
if (!in_array($id, $legit))
|
||||
continue;
|
||||
|
||||
$data['side'] = $spellFactions[$id] ?? SIDE_BOTH;
|
||||
$data['quality'] = $data['name'][0];
|
||||
$data['name'] = mb_substr($data['name'], 1);
|
||||
$buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
|
||||
}
|
||||
|
||||
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-companions', $buff))
|
||||
$success = false;
|
||||
}
|
||||
|
||||
return $success;
|
||||
};
|
||||
|
||||
/************/
|
||||
/* Factions */
|
||||
/************/
|
||||
$scripts[] = function() use ($exAdd)
|
||||
{
|
||||
$success = true;
|
||||
$condition = array( // todo (med): exclude non-gaining reputation-header
|
||||
Cfg::get('SQL_LIMIT_NONE'),
|
||||
[['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0]
|
||||
);
|
||||
$factionz = new FactionList($condition);
|
||||
|
||||
foreach (CLISetup::$localeIds as $l)
|
||||
{
|
||||
set_time_limit(5);
|
||||
|
||||
User::useLocale($l);
|
||||
Lang::load($l);
|
||||
|
||||
$buff = "var _ = g_factions;\n";
|
||||
foreach ($factionz->getListviewData() as $id => $data)
|
||||
$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 (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-factions', $buff))
|
||||
$success = false;
|
||||
}
|
||||
|
||||
return $success;
|
||||
};
|
||||
|
||||
/***********/
|
||||
/* Recipes */
|
||||
/***********/
|
||||
$scripts[] = function() use ($exAdd, $spellFactions)
|
||||
{
|
||||
// special case: secondary skills are always requested, so put them in one single file (185, 129, 356); it also contains g_skill_order
|
||||
$skills = array_merge(SKILLS_TRADE_PRIMARY, [[185, 129, 356]]);
|
||||
$success = true;
|
||||
$baseCnd = array(
|
||||
Cfg::get('SQL_LIMIT_NONE'),
|
||||
[['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0],
|
||||
['effect1Id', [6, 45, 57, 127, 33, 158, 99, 28, 95], '!'], // aura, tradeSkill, Tracking, Prospecting, Decipher, Milling, Disenchant, Summon (Engineering), Skinning
|
||||
['effect2Id', [118, 60], '!'], // not the skill itself
|
||||
['OR', ['typeCat', 9], ['typeCat', 11]]
|
||||
);
|
||||
|
||||
foreach ($skills as $s)
|
||||
{
|
||||
$file = is_array($s) ? 'sec' : (string)$s;
|
||||
$cnd = array_merge($baseCnd, [['skillLine1', $s]]);
|
||||
$recipez = new SpellList($cnd);
|
||||
$created = '';
|
||||
foreach ($recipez->iterate() as $id => $__)
|
||||
{
|
||||
if (!$recipez->getSources())
|
||||
$exAdd(Type::SPELL, $id, PR_EXCLUDE_GROUP_UNAVAILABLE);
|
||||
|
||||
foreach ($recipez->canCreateItem() as $idx)
|
||||
{
|
||||
$id = $recipez->getField('effect'.$idx.'CreateItemId');
|
||||
$created .= "g_items.add(".$id.", {'icon':'".$recipez->relItems->getEntry($id)['iconString']."'});\n";
|
||||
}
|
||||
}
|
||||
|
||||
foreach (CLISetup::$localeIds as $l)
|
||||
{
|
||||
set_time_limit(10);
|
||||
|
||||
User::useLocale($l);
|
||||
Lang::load($l);
|
||||
|
||||
$buff = '';
|
||||
foreach ($recipez->getListviewData() as $id => $data)
|
||||
{
|
||||
$data['side'] = $spellFactions[$id] ?? SIDE_BOTH;
|
||||
$buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
|
||||
}
|
||||
|
||||
if (!$buff)
|
||||
{
|
||||
// this behaviour is intended, do not create an error
|
||||
CLI::write('profiler - file datasets/'.User::$localeString.'/p-recipes-'.$file.' has no content => skipping', CLI::LOG_INFO);
|
||||
continue;
|
||||
}
|
||||
|
||||
$buff = $created."\nvar _ = g_spells;\n".$buff;
|
||||
|
||||
if (is_array($s))
|
||||
$buff .= "\ng_skill_order = [171, 164, 333, 202, 182, 773, 755, 165, 186, 393, 197, 185, 129, 356];\n";
|
||||
|
||||
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-recipes-'.$file, $buff))
|
||||
$success = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $success;
|
||||
};
|
||||
|
||||
/****************/
|
||||
/* Achievements */
|
||||
/****************/
|
||||
$scripts[] = function() use ($exAdd)
|
||||
{
|
||||
$success = true;
|
||||
$condition = array(
|
||||
Cfg::get('SQL_LIMIT_NONE'),
|
||||
[['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0],
|
||||
[['flags', 1, '&'], 0], // no statistics
|
||||
);
|
||||
$achievez = new AchievementList($condition);
|
||||
|
||||
foreach (CLISetup::$localeIds as $l)
|
||||
{
|
||||
set_time_limit(5);
|
||||
|
||||
User::useLocale($l);
|
||||
Lang::load($l);
|
||||
|
||||
$sumPoints = 0;
|
||||
$buff = "var _ = g_achievements;\n";
|
||||
foreach ($achievez->getListviewData(ACHIEVEMENTINFO_PROFILE) as $id => $data)
|
||||
{
|
||||
$sumPoints += $data['points'];
|
||||
$buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
|
||||
}
|
||||
|
||||
// categories to sort by
|
||||
$buff .= "\ng_achievement_catorder = [92, 14863, 97, 169, 170, 171, 172, 14802, 14804, 14803, 14801, 95, 161, 156, 165, 14806, 14921, 96, 201, 160, 14923, 14808, 14805, 14778, 14865, 14777, 14779, 155, 14862, 14861, 14864, 14866, 158, 162, 14780, 168, 14881, 187, 14901, 163, 14922, 159, 14941, 14961, 14962, 14981, 15003, 15002, 15001, 15041, 15042, 81]";
|
||||
// sum points
|
||||
$buff .= "\ng_achievement_points = [".$sumPoints."];\n";
|
||||
|
||||
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/achievements', $buff))
|
||||
$success = false;
|
||||
}
|
||||
|
||||
return $success;
|
||||
};
|
||||
|
||||
/******************/
|
||||
/* Quick Excludes */
|
||||
/******************/
|
||||
$scripts[] = function() use (&$exclusions)
|
||||
{
|
||||
set_time_limit(2);
|
||||
|
||||
CLI::write('applying '.count($exclusions).' baseline exclusions');
|
||||
DB::Aowow()->query('DELETE FROM ?_profiler_excludes WHERE comment = ""');
|
||||
|
||||
foreach ($exclusions as $ex)
|
||||
DB::Aowow()->query('REPLACE INTO ?_profiler_excludes (?#) VALUES (?a)', array_keys($ex), array_values($ex));
|
||||
|
||||
// excludes; type => [excludeGroupBit => [typeIds]]
|
||||
$excludes = [];
|
||||
|
||||
$exData = DB::Aowow()->selectCol('SELECT `type` AS ARRAY_KEY, `typeId` AS ARRAY_KEY2, `groups` FROM ?_profiler_excludes');
|
||||
for ($i = 0; (1 << $i) < PR_EXCLUDE_GROUP_ANY; $i++)
|
||||
foreach ($exData as $type => $data)
|
||||
if ($ids = array_keys(array_filter($data, function ($x) use ($i) { return $x & (1 << $i); } )))
|
||||
$excludes[$type][$i + 1] = $ids;
|
||||
|
||||
$buff = "g_excludes = ".Util::toJSON($excludes ?: (new Stdclass)).";\n";
|
||||
|
||||
return CLISetup::writeFile('datasets/quick-excludes', $buff);
|
||||
};
|
||||
|
||||
// check directory-structure
|
||||
foreach (Util::$localeStrings as $dir)
|
||||
if (!CLISetup::writeDir('datasets/'.$dir))
|
||||
$success = false;
|
||||
|
||||
// run scripts
|
||||
foreach ($scripts as $func)
|
||||
if (!$func())
|
||||
$success = false;
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
?>
|
||||
447
setup/tools/filegen/profiler.ss.php
Normal file
447
setup/tools/filegen/profiler.ss.php
Normal file
@@ -0,0 +1,447 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
protected $info = array(
|
||||
'profiler' => [[ ], CLISetup::ARGV_PARAM, 'Generates data dumps and completion exclusion filters for the profiler tool.'],
|
||||
'quests' => [['1'], CLISetup::ARGV_OPTIONAL, '...available quests by category'],
|
||||
'titles' => [['2'], CLISetup::ARGV_OPTIONAL, '...available titles by gender'],
|
||||
'mounts' => [['3'], CLISetup::ARGV_OPTIONAL, '...available mounts'],
|
||||
'companions' => [['4'], CLISetup::ARGV_OPTIONAL, '...available companions'],
|
||||
'factions' => [['5'], CLISetup::ARGV_OPTIONAL, '...available factions'],
|
||||
'recipes' => [['6'], CLISetup::ARGV_OPTIONAL, '...available recipes by skill'],
|
||||
'achievements' => [['7'], CLISetup::ARGV_OPTIONAL, '...available achievements'],
|
||||
'quickexcludes' => [['9'], CLISetup::ARGV_OPTIONAL, '...unobtainable items, mutually exclusive recipes, factions, etc.'],
|
||||
);
|
||||
|
||||
protected $localized = true;
|
||||
protected $requiredDirs = ['datasets/'];
|
||||
protected $worldDependency = ['player_factionchange_spells', 'conditions'];
|
||||
protected $setupAfter = [['quests', 'quests_startend', 'items', 'currencies', 'titles', 'spell', 'factions', 'achievement'], []];
|
||||
|
||||
private $spellFactions = [];
|
||||
private $exclusions = [];
|
||||
private $opts = [];
|
||||
|
||||
public function generate() : bool
|
||||
{
|
||||
$anyOpt = array_keys($this->info);
|
||||
$this->opts = CLISetup::getOpt(...$anyOpt);
|
||||
|
||||
$this->opts = array_filter($this->opts);
|
||||
if (!$this->opts) // none were set -> use default (all)
|
||||
$this->opts = array_fill_keys(array_slice($anyOpt, 1), true);
|
||||
|
||||
|
||||
$this->spellFactions = DB::World()->selectCol('SELECT `alliance_id` AS ARRAY_KEY, 1 FROM player_factionchange_spells UNION SELECT `horde_id` AS ARRAY_KEY, 2 FROM player_factionchange_spells');
|
||||
|
||||
|
||||
foreach ($this->opts as $fn => $_)
|
||||
$this->$fn();
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function quests() : void
|
||||
{
|
||||
$questorder = [];
|
||||
$questtotal = [];
|
||||
$condition = [
|
||||
Cfg::get('SQL_LIMIT_NONE'),
|
||||
'AND',
|
||||
[['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW | CUSTOM_UNAVAILABLE | CUSTOM_DISABLED, '&'], 0],
|
||||
[['flags', QUEST_FLAG_DAILY | QUEST_FLAG_WEEKLY | QUEST_FLAG_REPEATABLE | QUEST_FLAG_AUTO_REWARDED, '&'], 0],
|
||||
[['specialFlags', QUEST_FLAG_SPECIAL_REPEATABLE | QUEST_FLAG_SPECIAL_DUNGEON_FINDER | QUEST_FLAG_SPECIAL_MONTHLY, '&'], 0]
|
||||
];
|
||||
|
||||
foreach (Game::$questClasses as $cat2 => $cat)
|
||||
{
|
||||
if ($cat2 < 0)
|
||||
continue;
|
||||
|
||||
$cond = array_merge($condition, [['zoneOrSort', $cat]]);
|
||||
$questz = new QuestList($cond);
|
||||
if ($questz->error)
|
||||
continue;
|
||||
|
||||
$questorder[] = $cat2;
|
||||
$questtotal[$cat2] = [];
|
||||
|
||||
// get quests for exclusion
|
||||
foreach ($questz->iterate() as $id => $__)
|
||||
{
|
||||
$this->sumTotal($questtotal[$cat2], $questz->getField('reqRaceMask') ?: -1, $questz->getField('reqClassMask') ?: -1);
|
||||
if ($skillEx = $this->getExcludeForSkill($questz->getField('reqSkillId')))
|
||||
$this->addExclusion(Type::QUEST, $id, $skillEx);
|
||||
}
|
||||
|
||||
$_ = [];
|
||||
$currencies = array_column($questz->rewards, Type::CURRENCY);
|
||||
foreach ($currencies as $curr)
|
||||
foreach ($curr as $cId => $qty)
|
||||
$_[] = $cId;
|
||||
|
||||
$relCurr = new CurrencyList(array(['id', $_]));
|
||||
|
||||
foreach (CLISetup::$localeIds as $l)
|
||||
{
|
||||
set_time_limit(20);
|
||||
|
||||
User::useLocale($l);
|
||||
Lang::load($l);
|
||||
|
||||
if (!$relCurr->error)
|
||||
{
|
||||
$buff = "var _ = g_gatheredcurrencies;\n";
|
||||
foreach ($relCurr->getListviewData() as $id => $data)
|
||||
$buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
|
||||
}
|
||||
|
||||
$buff .= "var _ = g_quests;\n";
|
||||
foreach ($questz->getListviewData() as $id => $data)
|
||||
$buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
|
||||
|
||||
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-quests-'.$cat2, $buff))
|
||||
$this->success = false;
|
||||
}
|
||||
}
|
||||
|
||||
$buff = "g_quest_catorder = ".Util::toJSON($questorder).";\n";
|
||||
$buff .= "g_quest_catorder_total = {};\n";
|
||||
foreach ($questtotal as $cat => $totals)
|
||||
$buff .= "g_quest_catorder_total[".$cat."] = ".Util::toJSON($totals).";\n";
|
||||
|
||||
if (!CLISetup::writeFile('datasets/p-quests', $buff))
|
||||
$this->success = false;
|
||||
}
|
||||
|
||||
private function titles(): void
|
||||
{
|
||||
$condition = array(
|
||||
Cfg::get('SQL_LIMIT_NONE'),
|
||||
[['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0],
|
||||
);
|
||||
$titlez = new TitleList($condition);
|
||||
|
||||
// get titles for exclusion
|
||||
foreach ($titlez->iterate() as $id => $__)
|
||||
if (empty($titlez->sources[$id][4]) && empty($titlez->sources[$id][12]))
|
||||
$this->addExclusion(Type::TITLE, $id, PR_EXCLUDE_GROUP_UNAVAILABLE);
|
||||
|
||||
foreach (CLISetup::$localeIds as $l)
|
||||
{
|
||||
set_time_limit(5);
|
||||
|
||||
User::useLocale($l);
|
||||
Lang::load($l);
|
||||
|
||||
foreach ([GENDER_MALE, GENDER_FEMALE] as $g)
|
||||
{
|
||||
$buff = "var _ = g_titles;\n";
|
||||
foreach ($titlez->getListviewData() as $id => $data)
|
||||
{
|
||||
$data['name'] = Util::localizedString($titlez->getEntry($id), $g ? 'female' : 'male');
|
||||
unset($data['namefemale']);
|
||||
$buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
|
||||
}
|
||||
|
||||
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-titles-'.$g, $buff))
|
||||
$this->success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function mounts() : void
|
||||
{
|
||||
$condition = array(
|
||||
Cfg::get('SQL_LIMIT_NONE'),
|
||||
[['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0],
|
||||
['typeCat', -5],
|
||||
['castTime', 0, '!']
|
||||
);
|
||||
$mountz = new SpellList($condition);
|
||||
|
||||
$conditionSet = DB::World()->selectCol('SELECT SourceEntry AS ARRAY_KEY, ConditionValue1 FROM conditions WHERE SourceTypeOrReferenceId = ?d AND ConditionTypeOrReference = ?d AND SourceEntry IN (?a)', Conditions::SRC_SPELL, Conditions::SKILL, $mountz->getFoundIDs());
|
||||
|
||||
// get mounts for exclusion
|
||||
foreach ($conditionSet as $mount => $skill)
|
||||
if ($skillEx = $this->getExcludeForSkill($skill))
|
||||
$this->addExclusion(Type::SPELL, $mount, $skillEx);
|
||||
|
||||
foreach ($mountz->iterate() as $id => $_)
|
||||
if (!$mountz->getSources())
|
||||
$this->addExclusion(Type::SPELL, $id, PR_EXCLUDE_GROUP_UNAVAILABLE);
|
||||
|
||||
foreach (CLISetup::$localeIds as $l)
|
||||
{
|
||||
set_time_limit(5);
|
||||
|
||||
User::useLocale($l);
|
||||
Lang::load($l);
|
||||
|
||||
$buff = "var _ = g_spells;\n";
|
||||
foreach ($mountz->getListviewData(ITEMINFO_MODEL) as $id => $data)
|
||||
{
|
||||
// two cases where the spell is unrestricted but the castitem has class restriction (too lazy to formulate ruleset)
|
||||
if ($id == 66906) // Argent Charger
|
||||
$data['reqclass'] = CLASS_PALADIN;
|
||||
else if ($id == 54729) // Winged Steed of the Ebon Blade
|
||||
$data['reqclass'] = CLASS_DEATHKNIGHT;
|
||||
|
||||
rsort($data['skill']); // riding (777) expected at pos 0
|
||||
|
||||
$data['side'] = $this->spellFactions[$id] ?? SIDE_BOTH;
|
||||
$data['quality'] = $data['name'][0];
|
||||
$data['name'] = mb_substr($data['name'], 1);
|
||||
$buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
|
||||
}
|
||||
|
||||
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-mounts', $buff))
|
||||
$this->success = false;
|
||||
}
|
||||
}
|
||||
|
||||
private function companions() : void
|
||||
{
|
||||
$condition = array(
|
||||
Cfg::get('SQL_LIMIT_NONE'),
|
||||
[['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0],
|
||||
['typeCat', -6]
|
||||
);
|
||||
$companionz = new SpellList($condition);
|
||||
$legit = DB::Aowow()->selectCol('SELECT `spellId2` FROM ?_items WHERE `class` = ?d AND `subClass` = ?d AND `spellId1` IN (?a) AND `spellId2` IN (?a)', ITEM_CLASS_MISC, 2, LEARN_SPELLS, $companionz->getFoundIDs());
|
||||
|
||||
foreach ($companionz->iterate() as $id => $_)
|
||||
if (!$companionz->getSources())
|
||||
$this->addExclusion(Type::SPELL, $id, PR_EXCLUDE_GROUP_UNAVAILABLE);
|
||||
|
||||
foreach (CLISetup::$localeIds as $l)
|
||||
{
|
||||
set_time_limit(5);
|
||||
|
||||
User::useLocale($l);
|
||||
Lang::load($l);
|
||||
|
||||
$buff = "var _ = g_spells;\n";
|
||||
foreach ($companionz->getListviewData(ITEMINFO_MODEL) as $id => $data)
|
||||
{
|
||||
if (!in_array($id, $legit))
|
||||
continue;
|
||||
|
||||
$data['side'] = $this->spellFactions[$id] ?? SIDE_BOTH;
|
||||
$data['quality'] = $data['name'][0];
|
||||
$data['name'] = mb_substr($data['name'], 1);
|
||||
$buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
|
||||
}
|
||||
|
||||
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-companions', $buff))
|
||||
$this->success = false;
|
||||
}
|
||||
}
|
||||
|
||||
private function factions() : void
|
||||
{
|
||||
$condition = array(
|
||||
Cfg::get('SQL_LIMIT_NONE'),
|
||||
[['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0]
|
||||
);
|
||||
$factionz = new FactionList($condition);
|
||||
|
||||
foreach (CLISetup::$localeIds as $l)
|
||||
{
|
||||
set_time_limit(5);
|
||||
|
||||
User::useLocale($l);
|
||||
Lang::load($l);
|
||||
|
||||
$buff = "var _ = g_factions;\n";
|
||||
foreach ($factionz->getListviewData() as $id => $data)
|
||||
$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 (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-factions', $buff))
|
||||
$this->success = false;
|
||||
}
|
||||
}
|
||||
|
||||
private function recipes() : void
|
||||
{
|
||||
// special case: secondary skills are always requested, so put them in one single file (185, 129, 356); it also contains g_skill_order
|
||||
$skills = array(
|
||||
SKILL_ALCHEMY, SKILL_BLACKSMITHING, SKILL_ENCHANTING, SKILL_ENGINEERING, SKILL_HERBALISM,
|
||||
SKILL_INSCRIPTION, SKILL_JEWELCRAFTING, SKILL_LEATHERWORKING, SKILL_MINING, SKILL_SKINNING,
|
||||
SKILL_TAILORING, [SKILL_COOKING, SKILL_FIRST_AID, SKILL_FISHING]
|
||||
);
|
||||
|
||||
$baseCnd = array(
|
||||
Cfg::get('SQL_LIMIT_NONE'),
|
||||
[['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0],
|
||||
['effect1Id', [6, 45, 57, 127, 33, 158, 99, 28, 95], '!'], // aura, tradeSkill, Tracking, Prospecting, Decipher, Milling, Disenchant, Summon (Engineering), Skinning
|
||||
['effect2Id', [118, 60], '!'], // not the skill itself
|
||||
['OR', ['typeCat', 9], ['typeCat', 11]]
|
||||
);
|
||||
|
||||
foreach ($skills as $s)
|
||||
{
|
||||
$file = is_array($s) ? 'sec' : (string)$s;
|
||||
$cnd = array_merge($baseCnd, [['skillLine1', $s]]);
|
||||
$recipez = new SpellList($cnd);
|
||||
$created = '';
|
||||
foreach ($recipez->iterate() as $id => $_)
|
||||
{
|
||||
if (!$recipez->getSources())
|
||||
$this->addExclusion(Type::SPELL, $id, PR_EXCLUDE_GROUP_UNAVAILABLE);
|
||||
|
||||
foreach ($recipez->canCreateItem() as $idx)
|
||||
{
|
||||
$id = $recipez->getField('effect'.$idx.'CreateItemId');
|
||||
$created .= "g_items.add(".$id.", {'icon':'".$recipez->relItems->getEntry($id)['iconString']."'});\n";
|
||||
}
|
||||
}
|
||||
|
||||
foreach (CLISetup::$localeIds as $l)
|
||||
{
|
||||
set_time_limit(10);
|
||||
|
||||
User::useLocale($l);
|
||||
Lang::load($l);
|
||||
|
||||
$buff = '';
|
||||
foreach ($recipez->getListviewData() as $id => $data)
|
||||
{
|
||||
$data['side'] = $this->spellFactions[$id] ?? SIDE_BOTH;
|
||||
$buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
|
||||
}
|
||||
|
||||
if (!$buff)
|
||||
{
|
||||
// this behaviour is intended, do not create an error
|
||||
CLI::write('[profiler] - file datasets/'.User::$localeString.'/p-recipes-'.$file.' has no content => skipping', CLI::LOG_INFO);
|
||||
continue;
|
||||
}
|
||||
|
||||
$buff = $created."\nvar _ = g_spells;\n".$buff;
|
||||
|
||||
if (is_array($s))
|
||||
$buff .= "\ng_skill_order = [171, 164, 333, 202, 182, 773, 755, 165, 186, 393, 197, 185, 129, 356];\n";
|
||||
|
||||
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/p-recipes-'.$file, $buff))
|
||||
$this->success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function achievements() : void
|
||||
{
|
||||
$condition = array(
|
||||
Cfg::get('SQL_LIMIT_NONE'),
|
||||
[['cuFlags', CUSTOM_EXCLUDE_FOR_LISTVIEW, '&'], 0],
|
||||
[['flags', 1, '&'], 0], // no statistics
|
||||
);
|
||||
$achievez = new AchievementList($condition);
|
||||
|
||||
foreach (CLISetup::$localeIds as $l)
|
||||
{
|
||||
set_time_limit(5);
|
||||
|
||||
User::useLocale($l);
|
||||
Lang::load($l);
|
||||
|
||||
$sumPoints = 0;
|
||||
$buff = "var _ = g_achievements;\n";
|
||||
foreach ($achievez->getListviewData(ACHIEVEMENTINFO_PROFILE) as $id => $data)
|
||||
{
|
||||
$sumPoints += $data['points'];
|
||||
$buff .= '_['.$id.'] = '.Util::toJSON($data).";\n";
|
||||
}
|
||||
|
||||
// categories to sort by
|
||||
$buff .= "\ng_achievement_catorder = [92, 14863, 97, 169, 170, 171, 172, 14802, 14804, 14803, 14801, 95, 161, 156, 165, 14806, 14921, 96, 201, 160, 14923, 14808, 14805, 14778, 14865, 14777, 14779, 155, 14862, 14861, 14864, 14866, 158, 162, 14780, 168, 14881, 187, 14901, 163, 14922, 159, 14941, 14961, 14962, 14981, 15003, 15002, 15001, 15041, 15042, 81]";
|
||||
// sum points
|
||||
$buff .= "\ng_achievement_points = [".$sumPoints."];\n";
|
||||
|
||||
if (!CLISetup::writeFile('datasets/'.User::$localeString.'/achievements', $buff))
|
||||
$this->success = false;
|
||||
}
|
||||
}
|
||||
|
||||
private function quickexcludes() : void
|
||||
{
|
||||
set_time_limit(2);
|
||||
|
||||
CLI::write('[profiler] applying '.count($this->exclusions).' baseline exclusions');
|
||||
DB::Aowow()->query('DELETE FROM ?_profiler_excludes WHERE comment = ""');
|
||||
|
||||
foreach ($this->exclusions as $ex)
|
||||
DB::Aowow()->query('REPLACE INTO ?_profiler_excludes (?#) VALUES (?a)', array_keys($ex), array_values($ex));
|
||||
|
||||
// excludes; type => [excludeGroupBit => [typeIds]]
|
||||
$excludes = [];
|
||||
|
||||
$exData = DB::Aowow()->selectCol('SELECT `type` AS ARRAY_KEY, `typeId` AS ARRAY_KEY2, `groups` FROM ?_profiler_excludes');
|
||||
for ($i = 0; (1 << $i) < PR_EXCLUDE_GROUP_ANY; $i++)
|
||||
foreach ($exData as $type => $data)
|
||||
if ($ids = array_keys(array_filter($data, function ($x) use ($i) { return $x & (1 << $i); } )))
|
||||
$excludes[$type][$i + 1] = $ids;
|
||||
|
||||
$buff = "g_excludes = ".Util::toJSON($excludes ?: (new Stdclass)).";\n";
|
||||
|
||||
if (!CLISetup::writeFile('datasets/quick-excludes', $buff))
|
||||
$this->success = false;
|
||||
}
|
||||
|
||||
private function getExcludeForSkill(int $skillId) : int
|
||||
{
|
||||
switch ($skillId)
|
||||
{
|
||||
case SKILL_FISHING: return PR_EXCLUDE_GROUP_REQ_FISHING;
|
||||
case SKILL_ENGINEERING: return PR_EXCLUDE_GROUP_REQ_ENGINEERING;
|
||||
case SKILL_TAILORING: return PR_EXCLUDE_GROUP_REQ_TAILORING;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private function addExclusion(int $type, int $typeId, int $groups, string $comment = '') : void
|
||||
{
|
||||
$k = $type.'-'.$typeId;
|
||||
|
||||
if (!isset($this->exclusions[$k]))
|
||||
$this->exclusions[$k] = ['type' => $type, 'typeId' => $typeId, 'groups' => $groups, 'comment' => $comment];
|
||||
else
|
||||
{
|
||||
$this->exclusions[$k]['groups'] |= $groups;
|
||||
if ($comment)
|
||||
$this->exclusions[$k]['comment'] .= '; '.$comment;
|
||||
}
|
||||
}
|
||||
|
||||
private function sumTotal (array &$sumArr, int $raceMask = -1, int $classMask= -1) : void
|
||||
{
|
||||
for ($i = 0; $i < RACE_MASK_ALL; $i++)
|
||||
{
|
||||
if (!((1 << $i) & $raceMask) || !((1 << $i) & RACE_MASK_ALL))
|
||||
continue;
|
||||
|
||||
for ($j = 0; $j < CLASS_MASK_ALL; $j++)
|
||||
{
|
||||
if (!((1 << $j) & $classMask) || !((1 << $j) & CLASS_MASK_ALL))
|
||||
continue;
|
||||
|
||||
if (!isset($sumArr[$i+1][$j+1]))
|
||||
$sumArr[$i+1][$j+1] = 1;
|
||||
else
|
||||
$sumArr[$i+1][$j+1]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,72 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
// Create 'profile_all.js'-file in static/js;
|
||||
// this script requires all realms in use to be defined in auth.realmlist
|
||||
// battlegroups has to be set in config file
|
||||
|
||||
/* Example
|
||||
var mn_profiles = [
|
||||
["us","US & Oceanic",,[
|
||||
["bloodlust","Bloodlust",,[
|
||||
["amanthul","Aman'Thul"],
|
||||
["barthilas","Barthilas"]
|
||||
]],
|
||||
["cyclone","Cyclone",,[
|
||||
["azjol-nerub","Azjol-Nerub"],
|
||||
["bloodscalp","Bloodscalp"]
|
||||
]]
|
||||
]],
|
||||
["eu","Europe",,[
|
||||
["blackout","Blackout",,[
|
||||
["agamaggan","Agamaggan"],
|
||||
["aggramar","Aggramar"]
|
||||
]],
|
||||
["blutdurst","Blutdurst",,[
|
||||
["aegwynn","Aegwynn"],
|
||||
["destromath","Destromath"]
|
||||
]]
|
||||
]]
|
||||
];
|
||||
*/
|
||||
|
||||
function realmMenu()
|
||||
{
|
||||
$subs = [];
|
||||
$set = 0x0;
|
||||
$menu = [
|
||||
// skip usage of battlegroup
|
||||
// ['us', Lang::profiler('regions', 'us'), null,[[Profiler::urlize(Cfg::get('BATTLEGROUP')), Cfg::get('BATTLEGROUP'), null, &$subUS]]],
|
||||
// ['eu', Lang::profiler('regions', 'eu'), null,[[Profiler::urlize(Cfg::get('BATTLEGROUP')), Cfg::get('BATTLEGROUP'), null, &$subEU]]]
|
||||
];
|
||||
|
||||
foreach (Util::$regions as $idx => $n)
|
||||
$subs[$idx] = [];
|
||||
|
||||
foreach (Profiler::getRealms() as $row)
|
||||
{
|
||||
$idx = array_search($row['region'], Util::$regions);
|
||||
if ($idx !== false)
|
||||
{
|
||||
$set |= (1 << $idx);
|
||||
$subs[$idx][] = [Profiler::urlize($row['name'], true), $row['name'], null, null, $row['access'] ? ['requiredAccess' => $row['access']] : null];
|
||||
}
|
||||
|
||||
}
|
||||
if (!$set)
|
||||
CLI::write(' - realmMenu: Auth-DB not set up .. realm menu will be empty', CLI::LOG_WARN);
|
||||
|
||||
// why is this file not localized!?
|
||||
foreach (Util::$regions as $idx => $n)
|
||||
if ($set & (1 << $idx))
|
||||
$menu[] = [$n, Lang::profiler('regions', $n), null, &$subs[$idx]];
|
||||
|
||||
return Util::toJSON($menu);
|
||||
}
|
||||
?>
|
||||
85
setup/tools/filegen/realmmenu.ss.php
Normal file
85
setup/tools/filegen/realmmenu.ss.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/* Example
|
||||
var mn_profiles = [
|
||||
["us","US & Oceanic",,[
|
||||
["bloodlust","Bloodlust",,[
|
||||
["amanthul","Aman'Thul"],
|
||||
["barthilas","Barthilas"]
|
||||
]],
|
||||
["cyclone","Cyclone",,[
|
||||
["azjol-nerub","Azjol-Nerub"],
|
||||
["bloodscalp","Bloodscalp"]
|
||||
]]
|
||||
]],
|
||||
["eu","Europe",,[
|
||||
["blackout","Blackout",,[
|
||||
["agamaggan","Agamaggan"],
|
||||
["aggramar","Aggramar"]
|
||||
]],
|
||||
["blutdurst","Blutdurst",,[
|
||||
["aegwynn","Aegwynn"],
|
||||
["destromath","Destromath"]
|
||||
]]
|
||||
]]
|
||||
];
|
||||
*/
|
||||
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
use TrTemplateFile;
|
||||
|
||||
protected $info = array(
|
||||
'realmmenu' => [[], CLISetup::ARGV_PARAM, 'Generates \'profile_all.js\'-file that extends the profiler menus.']
|
||||
);
|
||||
|
||||
protected $fileTemplateSrc = ['profile_all.js.in'];
|
||||
protected $fileTemplateDest = ['static/js/profile_all.js'];
|
||||
protected $worldDependency = ['realmlist'];
|
||||
|
||||
private function realmMenu() : string
|
||||
{
|
||||
$subs = [];
|
||||
$set = 0x0;
|
||||
$menu = [
|
||||
// skip usage of battlegroup
|
||||
// ['us', Lang::profiler('regions', 'us'), null,[[Profiler::urlize(Cfg::get('BATTLEGROUP')), Cfg::get('BATTLEGROUP'), null, &$subUS]]],
|
||||
// ['eu', Lang::profiler('regions', 'eu'), null,[[Profiler::urlize(Cfg::get('BATTLEGROUP')), Cfg::get('BATTLEGROUP'), null, &$subEU]]]
|
||||
];
|
||||
|
||||
foreach (Util::$regions as $idx => $n)
|
||||
$subs[$idx] = [];
|
||||
|
||||
if (!DB::isConnectable(DB_AUTH))
|
||||
CLI::write('[realmmenu] Auth DB not set up .. realm menu will be empty', CLI::LOG_WARN);
|
||||
else
|
||||
foreach (Profiler::getRealms() as $row)
|
||||
{
|
||||
$idx = array_search($row['region'], Util::$regions);
|
||||
if ($idx === false)
|
||||
continue;
|
||||
|
||||
$set |= (1 << $idx);
|
||||
$subs[$idx][] = [Profiler::urlize($row['name'], true), $row['name'], null, null, $row['access'] ? ['requiredAccess' => $row['access']] : null];
|
||||
}
|
||||
|
||||
if (!$set)
|
||||
CLI::write('[realmmenu] no viable realms found .. realm menu will be empty', CLI::LOG_WARN);
|
||||
|
||||
// why is this file not localized!?
|
||||
foreach (Util::$regions as $idx => $n)
|
||||
if ($set & (1 << $idx))
|
||||
$menu[] = [$n, Lang::profiler('regions', $n), null, &$subs[$idx]];
|
||||
|
||||
return Util::toJSON($menu);
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,47 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
// Create 'realms'-file in datasets
|
||||
// this script requires all realms in use to be defined in auth.realmlist
|
||||
// battlegroups has to be set in aowow.aowow_config
|
||||
|
||||
/* seems to be unused, was located in the same file as g_realms
|
||||
var g_regions = {
|
||||
us => 'www.wowarmory.com',
|
||||
eu => 'eu.wowarmory.com'
|
||||
};
|
||||
*/
|
||||
|
||||
/* Examples
|
||||
1 => {
|
||||
name:'Eldre\'Thalas',
|
||||
battlegroup:'Reckoning',
|
||||
region:'us'
|
||||
},
|
||||
*/
|
||||
|
||||
function realms()
|
||||
{
|
||||
$realms = Profiler::getRealms();
|
||||
if (!$realms)
|
||||
CLI::write(' - realms: Auth-DB not set up .. static data g_realms will be empty', CLI::LOG_WARN);
|
||||
// else
|
||||
// foreach ($realms as &$r)
|
||||
// $r['battlegroup'] = Cfg::get('BATTLEGROUP');
|
||||
|
||||
// remove access column
|
||||
array_walk($realms, function (&$x) { unset($x['access']); });
|
||||
|
||||
$toFile = "var g_realms = ".Util::toJSON($realms).";";
|
||||
$file = 'datasets/realms';
|
||||
|
||||
return CLISetup::writeFile($file, $toFile);
|
||||
}
|
||||
|
||||
?>
|
||||
56
setup/tools/filegen/realms.ss.php
Normal file
56
setup/tools/filegen/realms.ss.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/* seems to be unused, was located in the same file as g_realms
|
||||
var g_regions = {
|
||||
us => 'www.wowarmory.com',
|
||||
eu => 'eu.wowarmory.com'
|
||||
};
|
||||
*/
|
||||
|
||||
/* Examples
|
||||
1 => {
|
||||
name:'Eldre\'Thalas',
|
||||
battlegroup:'Reckoning',
|
||||
region:'us'
|
||||
},
|
||||
*/
|
||||
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
protected $info = array(
|
||||
'realms' => [[], CLISetup::ARGV_PARAM, 'Generates \'realms\'-file to be referenced by the profiler tool.']
|
||||
);
|
||||
|
||||
protected $worldDependency = ['realmlist'];
|
||||
protected $requiredDirs = ['datasets/'];
|
||||
|
||||
public function generate() : bool
|
||||
{
|
||||
$realms = [];
|
||||
|
||||
if (!DB::isConnectable(DB_AUTH))
|
||||
CLI::write('[realms] Auth DB not set up .. static data g_realms will be empty', CLI::LOG_WARN);
|
||||
else if (!($realms = Profiler::getRealms()))
|
||||
CLI::write('[realms] no viable realms found .. static data g_realms will be empty', CLI::LOG_WARN);
|
||||
// else
|
||||
// foreach ($realms as &$r)
|
||||
// $r['battlegroup'] = Cfg::get('BATTLEGROUP');
|
||||
|
||||
// remove access column
|
||||
array_walk($realms, function (&$x) { unset($x['access']); });
|
||||
|
||||
$toFile = "var g_realms = ".Util::toJSON($realms).";";
|
||||
$file = 'datasets/realms';
|
||||
|
||||
return CLISetup::writeFile($file, $toFile);
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
22
setup/tools/filegen/searchbox.ss.php
Normal file
22
setup/tools/filegen/searchbox.ss.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
use TrTemplateFile;
|
||||
|
||||
protected $info = array(
|
||||
'searchbox' => [[], CLISetup::ARGV_PARAM, 'Fills search widget files (static/widgets/searchbox*) with site variables.']
|
||||
);
|
||||
|
||||
protected $fileTemplateSrc = ['searchbox.js.in', 'searchbox.html.in'];
|
||||
protected $fileTemplateDest = ['static/widgets/searchbox.js', 'static/widgets/searchbox/searchbox.html'];
|
||||
});
|
||||
|
||||
?>
|
||||
23
setup/tools/filegen/searchplugin.ss.php
Normal file
23
setup/tools/filegen/searchplugin.ss.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
use TrTemplateFile;
|
||||
|
||||
protected $info = array(
|
||||
'searchplugin' => [[], CLISetup::ARGV_PARAM, 'Fills browser opensearch plugin (static/download/searchplugins/aowow.xml) with site variables.']
|
||||
);
|
||||
|
||||
protected $fileTemplateSrc = ['aowow.xml.in'];
|
||||
protected $fileTemplateDest = ['static/download/searchplugins/aowow.xml'];
|
||||
protected $requiredDirs = ['static/download/searchplugins/'];
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,480 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
// note: for the sake of simplicity, this function handles all whole images (which are mostly icons)
|
||||
// quest icons from GossipFrame have an alphaChannel that cannot be handled by this script
|
||||
// lfgFrame/lfgIcon*.blp .. candidates for zonePage, but in general too detailed to scale them down from 128 to 56, 36, ect
|
||||
|
||||
$reqDBC = ['holidays', 'spellicon', 'itemdisplayinfo'];
|
||||
|
||||
function simpleImg()
|
||||
{
|
||||
// prefer manually converted PNG files (as the imagecreatefromblp-script has issues with some formats)
|
||||
// see: https://github.com/Kanma/BLPConverter
|
||||
$loadImageFile = function($path)
|
||||
{
|
||||
$result = null;
|
||||
|
||||
if (in_array(mb_substr($path, -4, 4), ['.png', '.blp', '.BLP', '.PNG']))
|
||||
$path = mb_substr($path, 0, mb_strlen($path) - 4);
|
||||
|
||||
$file = $path.'.png';
|
||||
if (CLISetup::fileExists($file))
|
||||
{
|
||||
CLI::write('manually converted png file present for: '.$path, CLI::LOG_INFO);
|
||||
$result = imagecreatefrompng($file);
|
||||
}
|
||||
|
||||
if (!$result)
|
||||
{
|
||||
$file = $path.'.blp';
|
||||
if (CLISetup::fileExists($file))
|
||||
$result = imagecreatefromblp($file);
|
||||
}
|
||||
|
||||
return $result;
|
||||
};
|
||||
|
||||
$groups = [];
|
||||
$imgPath = CLISetup::$srcDir.'%sInterface/';
|
||||
$destDir = 'static/images/wow/';
|
||||
$success = true;
|
||||
$iconDirs = array(
|
||||
['icons/large/', '.jpg', 0, 56, 4],
|
||||
['icons/medium/', '.jpg', 0, 36, 4],
|
||||
['icons/small/', '.jpg', 0, 18, 4],
|
||||
['icons/tiny/', '.gif', 0, 15, 4]
|
||||
);
|
||||
$calendarDirs = array(
|
||||
['icons/large/', '.jpg', 90, 56, 4],
|
||||
['icons/medium/', '.jpg', 90, 36, 4],
|
||||
['icons/small/', '.jpg', 90, 18, 4],
|
||||
['icons/tiny/', '.gif', 90, 15, 4]
|
||||
);
|
||||
$loadScreenDirs = array(
|
||||
['loadingscreens/large/', '.jpg', 0, 1024, 0],
|
||||
['loadingscreens/medium/', '.jpg', 0, 488, 0],
|
||||
['loadingscreens/original/', '.png', 0, 0, 0],
|
||||
['loadingscreens/small/', '.jpg', 0, 244, 0]
|
||||
);
|
||||
$paths = array( // src, [dest, ext, srcSize, destSize, borderOffset], pattern, isIcon, tileSize, resourcePath
|
||||
0 => ['Icons/', $iconDirs, '/.*\.(blp|png)$', true, 0, null],
|
||||
1 => ['Spellbook/', [['Interface/Spellbook/', '.png', 0, 0, 0]], '/UI-Glyph-Rune-?\d+.(blp|png)$', true, 0, null],
|
||||
2 => ['PaperDoll/', array_slice($iconDirs, 0, 3), '/UI-(Backpack|PaperDoll)-.*\.(blp|png)$', true, 0, null],
|
||||
3 => ['GLUES/CHARACTERCREATE/', $iconDirs, '/UI-CharacterCreate-Races.(blp|png)', true, 64, null],
|
||||
4 => ['GLUES/CHARACTERCREATE/', $iconDirs, '/UI-CharacterCreate-CLASSES.(blp|png)', true, 64, null],
|
||||
5 => ['GLUES/CHARACTERCREATE/', $iconDirs, '/UI-CharacterCreate-Factions.(blp|png)', true, 64, null],
|
||||
// 6 => ['Minimap/', [['icons/tiny/', '.gif', 0, 16, 2]], '/OBJECTICONS.(BLP|png)', true, 32, null],
|
||||
7 => ['FlavorImages/', [['Interface/FlavorImages/', '.png', 0, 0, 0]], '/.*\.(blp|png)$', false, 0, null],
|
||||
8 => ['Pictures/', [['Interface/Pictures/', '.png', 0, 0, 0]], '/.*\.(blp|png)$', false, 0, null],
|
||||
9 => ['PvPRankBadges/', [['Interface/PvPRankBadges/', '.png', 0, 0, 0]], '/.*\.(blp|png)$', false, 0, null],
|
||||
10 => ['Calendar/Holidays/', $calendarDirs, '/.*(start|[ayhs])\.(blp|png)$', true, 0, null],
|
||||
11 => ['GLUES/LOADINGSCREENS/', $loadScreenDirs, '/lo.*\.(blp|png)$', false, 0, null],
|
||||
12 => ['PVPFrame/', array_map(function($x) { $x[4] = 2; return $x; }, $iconDirs), '/PVP-(ArenaPoints|Currency).*\.(blp|png)$', true, 0, null]
|
||||
);
|
||||
// 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( // uses nameINT from ChrRaces.dbc
|
||||
['race_human_male', 'race_dwarf_male', 'race_gnome_male', 'race_nightelf_male', 'race_draenei_male' ],
|
||||
['race_tauren_male', 'race_scourge_male', 'race_troll_male', 'race_orc_male', 'race_bloodelf_male' ],
|
||||
['race_human_female', 'race_dwarf_female', 'race_gnome_female', 'race_nightelf_female', 'race_draenei_female' ],
|
||||
['race_tauren_female', 'race_scourge_female', 'race_troll_female', 'race_orc_female', 'race_bloodelf_female']
|
||||
),
|
||||
4 => array( // uses nameINT from ChrClasses.dbc
|
||||
['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);
|
||||
if ($ext == '.png')
|
||||
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:
|
||||
CLI::write($done.' - unsupported file fromat: '.$ext, CLI::LOG_WARN);
|
||||
}
|
||||
|
||||
imagedestroy($dest);
|
||||
|
||||
if ($ok)
|
||||
{
|
||||
chmod($name.$ext, Util::FILE_ACCESS);
|
||||
CLI::write($done.' - image '.$name.$ext.' written', CLI::LOG_OK, true, true);
|
||||
}
|
||||
else
|
||||
CLI::write($done.' - could not create image '.$name.$ext, CLI::LOG_ERROR);
|
||||
|
||||
return $ok;
|
||||
};
|
||||
|
||||
$checkSourceDirs = function($sub) use ($imgPath, &$paths)
|
||||
{
|
||||
$hasMissing = false;
|
||||
foreach ($paths as $pathIdx => [$subDir, , , , , $realPath])
|
||||
{
|
||||
if ($realPath)
|
||||
continue;
|
||||
|
||||
$p = sprintf($imgPath, $sub).$subDir;
|
||||
if (CLISetup::fileExists($p))
|
||||
$paths[$pathIdx][5] = $p;
|
||||
else
|
||||
$hasMissing = true;
|
||||
}
|
||||
|
||||
return !$hasMissing;
|
||||
};
|
||||
|
||||
if (CLISetup::getOpt('icons'))
|
||||
array_push($groups, 0, 2, 3, 4, 5, 10, 12);
|
||||
if (CLISetup::getOpt('glyphs'))
|
||||
$groups[] = 1;
|
||||
if (CLISetup::getOpt('pagetexts'))
|
||||
array_push($groups, 7, 8, 9);
|
||||
if (CLISetup::getOpt('loadingscreens'))
|
||||
$groups[] = 11;
|
||||
|
||||
// filter by passed 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 (CLISetup::$expectedPaths as $xp => $locId)
|
||||
{
|
||||
if (!in_array($locId, CLISetup::$localeIds))
|
||||
continue;
|
||||
|
||||
if ($xp) // if in subDir add trailing slash
|
||||
$xp .= '/';
|
||||
|
||||
if ($checkSourceDirs($xp))
|
||||
break;
|
||||
}
|
||||
|
||||
$locList = [];
|
||||
foreach (CLISetup::$expectedPaths as $xp => $locId)
|
||||
if (in_array($locId, CLISetup::$localeIds))
|
||||
$locList[] = $xp;
|
||||
|
||||
CLI::write('required resources overview:', CLI::LOG_INFO);
|
||||
foreach ($paths as [$path, , , , , $realPath])
|
||||
{
|
||||
if ($realPath)
|
||||
CLI::write(CLI::green(' FOUND ').' - '.str_pad($path, 53).' @ '.$realPath);
|
||||
else
|
||||
CLI::write(CLI::red('MISSING').' - '.str_pad($path, 53).' @ '.sprintf($imgPath, '['.implode(',', $locList).']/').$path);
|
||||
}
|
||||
|
||||
CLI::write();
|
||||
|
||||
// if no subdir had sufficient data, diaf
|
||||
if (count(array_filter(array_column($paths, 5))) != count($paths))
|
||||
{
|
||||
CLI::write('one or more required directories are missing:', CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
sleep(1);
|
||||
|
||||
// init directories
|
||||
foreach (array_column($paths, 1) as $subDirs)
|
||||
foreach ($subDirs as $sd)
|
||||
if (!CLISetup::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
|
||||
{
|
||||
if (isset($paths[0]) && !isset($paths[1]))
|
||||
$siRows = DB::Aowow()->selectCol('SELECT iconPath FROM dbc_spellicon WHERE iconPath NOT LIKE "%glyph-rune%"');
|
||||
else if (!isset($paths[0]) && isset($paths[1]))
|
||||
$siRows = DB::Aowow()->selectCol('SELECT iconPath FROM dbc_spellicon WHERE iconPath LIKE "%glyph-rune%"');
|
||||
else
|
||||
$siRows = DB::Aowow()->selectCol('SELECT iconPath FROM dbc_spellicon');
|
||||
|
||||
foreach ($siRows as $icon)
|
||||
{
|
||||
// Icons/
|
||||
if (isset($paths[0]) && stristr($icon, $paths[0][0]))
|
||||
$dbcEntries[] = strtolower($paths[0][5].substr(strrchr($icon, '\\'), 1));
|
||||
// Spellbook/
|
||||
else if (isset($paths[1]) && stristr($icon, $paths[1][0]))
|
||||
$dbcEntries[] = strtolower($paths[1][5].substr(strrchr($icon, '\\'), 1));
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($paths[0]))
|
||||
{
|
||||
$itemIcons = DB::Aowow()->selectCol('SELECT inventoryIcon1 FROM dbc_itemdisplayinfo WHERE inventoryIcon1 <> ""');
|
||||
foreach ($itemIcons as $icon)
|
||||
$dbcEntries[] = strtolower($paths[0][5].'/'.$icon);
|
||||
|
||||
$eventIcons = DB::Aowow()->selectCol('SELECT textureString FROM dbc_holidays WHERE textureString <> ""');
|
||||
foreach ($eventIcons as $icon)
|
||||
$dbcEntries[] = strtolower($paths[10][5].'/'.$icon.'start');
|
||||
}
|
||||
|
||||
// case-insensitive array_unique *vomits silently into a corner*
|
||||
$dbcEntries = array_intersect_key($dbcEntries, array_unique($dbcEntries));
|
||||
|
||||
$allPaths = [];
|
||||
foreach ($paths as $i => [$inPath, $outInfo, $pattern, $isIcon, $tileSize, $path])
|
||||
{
|
||||
$search = $path.$pattern;
|
||||
if ($pattern)
|
||||
$search = '/'.str_replace('/', '\\/', $search).'/i';
|
||||
|
||||
$files = CLISetup::filesInPath($search, !!$pattern);
|
||||
$allPaths = array_merge($allPaths, array_map(function ($x) { return substr($x, 0, -4); }, $files));
|
||||
|
||||
if (!$files)
|
||||
{
|
||||
CLI::write('source directory "'.CLI::bold($search).'" does not contain files matching "'.CLI::bold($pattern), CLI::LOG_ERROR);
|
||||
$success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
CLI::write('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;
|
||||
$na = explode('/', $f);
|
||||
$img = explode('.', array_pop($na));
|
||||
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 (!$tileSize)
|
||||
{
|
||||
$j += count($outInfo);
|
||||
CLI::write('skipping extraneous file '.$img.' (+'.count($outInfo).')');
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$nFiles = count($outInfo) * ($tileSize ? array_sum(array_map('count', $cuNames[$i])) : count($files));
|
||||
|
||||
foreach ($outInfo as [$dest, $ext, $srcSize, $destSize, $borderOffset])
|
||||
{
|
||||
if ($tileSize)
|
||||
{
|
||||
foreach ($cuNames[$i] as $y => $row)
|
||||
{
|
||||
foreach ($row as $x => $name)
|
||||
{
|
||||
$j++;
|
||||
$img = $isIcon ? strtolower($name) : $name;
|
||||
$done = ' - '.str_pad($j.'/'.$nFiles, 12).str_pad('('.number_format($j * 100 / $nFiles, 2).'%)', 9);
|
||||
|
||||
if (!CLISetup::getOpt('force') && file_exists($destDir.$dest.$img.$ext))
|
||||
{
|
||||
CLI::write($done.' - file '.$dest.$img.$ext.' was already processed', CLI::LOG_BLANK, true, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$src)
|
||||
$src = $loadImageFile($f);
|
||||
|
||||
if (!$src) // error should be created by imagecreatefromblp
|
||||
continue;
|
||||
|
||||
/*
|
||||
ready for some major bullshitery? well, here it comes anyway!
|
||||
the class-icon tile [idx: 4] isn't 64x64 but 63x64 .. the right side border is 1px short
|
||||
so if we don't watch out, the icons start to shift over and show the border
|
||||
also the icon border is displaced by 1px
|
||||
*/
|
||||
$from = array(
|
||||
'x' => $borderOffset + 1 + ($tileSize - ($i == 4 ? 1 : 0)) * $x,
|
||||
'y' => $borderOffset + 1 + $tileSize * $y,
|
||||
'w' => ($tileSize - ($i == 4 ? 1 : 0)) - $borderOffset * 2,
|
||||
'h' => $tileSize - $borderOffset * 2
|
||||
);
|
||||
$to = array(
|
||||
'x' => 0,
|
||||
'y' => 0,
|
||||
'w' => $destSize,
|
||||
'h' => $destSize
|
||||
);
|
||||
|
||||
if (!$writeImage($destDir.$dest.$img, $ext, $src, $from, $to, $done))
|
||||
$success = false;
|
||||
}
|
||||
}
|
||||
|
||||
// custom handle for combined icon 'quest_startend'
|
||||
/* not used due to alphaChannel issues
|
||||
if ($tileSize == 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.$dest.'quest_startend.gif'))
|
||||
CLI::write(' extra - image '.$destDir.$dest.'quest_startend.gif written', CLI::LOG_OK);
|
||||
else
|
||||
{
|
||||
CLI::write(' extra - could not create image '.$destDir.$dest.'quest_startend.gif', CLI::LOG_ERROR);
|
||||
$success = false;
|
||||
}
|
||||
|
||||
imagedestroy($dest);
|
||||
}
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
// icon -> lowercase
|
||||
if ($isIcon)
|
||||
$img = strtolower($img);
|
||||
|
||||
$j++;
|
||||
$done = ' - '.str_pad($j.'/'.$nFiles, 12).str_pad('('.number_format($j * 100 / $nFiles, 2).'%)', 9);
|
||||
|
||||
if (!CLISetup::getOpt('force') && file_exists($destDir.$dest.$img.$ext))
|
||||
{
|
||||
CLI::write($done.' - file '.$dest.$img.$ext.' was already processed', CLI::LOG_BLANK, true, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$src)
|
||||
$src = $loadImageFile($f);
|
||||
|
||||
if (!$src) // error should be created by imagecreatefromblp
|
||||
continue;
|
||||
|
||||
$from = array(
|
||||
'x' => $borderOffset,
|
||||
'y' => $borderOffset,
|
||||
'w' => ($srcSize ?: imagesx($src)) - $borderOffset * 2,
|
||||
'h' => ($srcSize ?: imagesy($src)) - $borderOffset * 2
|
||||
);
|
||||
$to = array(
|
||||
'x' => 0,
|
||||
'y' => 0,
|
||||
'w' => $destSize ?: imagesx($src),
|
||||
'h' => $destSize ?: imagesy($src)
|
||||
);
|
||||
|
||||
if (!$writeImage($destDir.$dest.$img, $ext, $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)))
|
||||
{
|
||||
// hide affected icons from listviews
|
||||
$iconNames = array_map(function($path) {
|
||||
preg_match('/\/([^\/]+)\.blp$/i', $path, $m);
|
||||
return $m ? $m[1] : null;
|
||||
}, $missing);
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_icons SET cuFlags = cuFlags | ?d WHERE name IN (?a)', CUSTOM_EXCLUDE_FOR_LISTVIEW, $iconNames);
|
||||
|
||||
asort($missing);
|
||||
CLI::write('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.', CLI::LOG_WARN);
|
||||
foreach ($missing as $m)
|
||||
CLI::write(' - '.$m);
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
376
setup/tools/filegen/simpleimg.ss.php
Normal file
376
setup/tools/filegen/simpleimg.ss.php
Normal file
@@ -0,0 +1,376 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
// quest icons from GossipFrame have an alphaChannel that cannot be handled by this script
|
||||
// lfgFrame/lfgIcon-*.blp .. candidates for zonePage, but in general too detailed to scale them down from 128 to 56, 36, ect
|
||||
// linked by lfgDungeons.dbc/28 ?
|
||||
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
use TrImageProcessor;
|
||||
|
||||
protected $info = array(
|
||||
'simpleimg' => [[ ], CLISetup::ARGV_PARAM, 'Converts and resizes BLP2 images smaller than 255x255 into required formats (mostly icons)'],
|
||||
'icons' => [['1'], CLISetup::ARGV_OPTIONAL, 'Generate icons for spells, items, classes, races, ect.'],
|
||||
'glyphs' => [['2'], CLISetup::ARGV_OPTIONAL, 'Generate decorative glyph symbols displayed on related item and spell pages.'],
|
||||
'pagetexts' => [['3'], CLISetup::ARGV_OPTIONAL, 'Generate images contained in text on readable items and gameobjects.'],
|
||||
'loadingscreens' => [['4'], CLISetup::ARGV_OPTIONAL, 'Generate loading screen images (not used on page; skipped by default)']
|
||||
);
|
||||
|
||||
protected $dbcSourceFiles = ['holidays', 'spellicon', 'itemdisplayinfo'];
|
||||
protected $setupAfter = [['icons'], []];
|
||||
|
||||
private const ICON_DIRS = array(
|
||||
['static/images/wow/icons/large/', 'jpg', 0, 56, 4],
|
||||
['static/images/wow/icons/medium/', 'jpg', 0, 36, 4],
|
||||
['static/images/wow/icons/small/', 'jpg', 0, 18, 4],
|
||||
['static/images/wow/icons/tiny/', 'gif', 0, 15, 4]
|
||||
);
|
||||
|
||||
private $genSteps = array(
|
||||
// srcPath, realPath, localized, [pattern, isIcon, tileSize, localized], [[dest, ext, srcSize, destSize, borderOffset]]
|
||||
0 => ['Icons/', null, false, ['/.*\.(blp|png)$', true, 0], self::ICON_DIRS, ],
|
||||
1 => ['Spellbook/', null, false, ['/UI-Glyph-Rune-?\d+.(blp|png)$', false, 0], [['static/images/wow/Interface/Spellbook/', 'png', 0, 0, 0]]],
|
||||
2 => ['PaperDoll/', null, false, ['/UI-(Backpack|PaperDoll)-.*\.(blp|png)$', true, 0], self::ICON_DIRS, ],
|
||||
3 => ['GLUES/CHARACTERCREATE/', null, false, ['/UI-CharacterCreate-Races.(blp|png)', true, 64], self::ICON_DIRS, ],
|
||||
4 => ['GLUES/CHARACTERCREATE/', null, false, ['/UI-CharacterCreate-CLASSES.(blp|png)', true, 64], self::ICON_DIRS, ],
|
||||
5 => ['GLUES/CHARACTERCREATE/', null, false, ['/UI-CharacterCreate-Factions.(blp|png)', true, 64], self::ICON_DIRS, ],
|
||||
// 6 => ['Minimap/' , null, false, ['/OBJECTICONS.(BLP|png)', true, 32], [['static/images/wow/icons/tiny/', 'gif', 0, 16, 2]]],
|
||||
7 => ['FlavorImages/', null, false, ['/.*\.(blp|png)$', false, 0], [['static/images/wow/Interface/FlavorImages/', 'png', 0, 0, 0]]],
|
||||
8 => ['Pictures/', null, false, ['/.*\.(blp|png)$', false, 0], [['static/images/wow/Interface/Pictures/', 'png', 0, 0, 0]]],
|
||||
9 => ['PvPRankBadges/', null, false, ['/.*\.(blp|png)$', false, 0], [['static/images/wow/Interface/PvPRankBadges/', 'png', 0, 0, 0]]],
|
||||
10 => ['Calendar/Holidays/', null, false, ['/.*(start|[ayhs])\.(blp|png)$', true, 0], self::ICON_DIRS, ],
|
||||
11 => ['GLUES/LOADINGSCREENS/', null, false, ['/lo.*\.(blp|png)$', false, 0], [['cache/loadingscreens/', 'png', 0, 0, 0]]],
|
||||
12 => ['PVPFrame/', null, false, ['/PVP-(ArenaPoints|Currency).*\.(blp|png)$', true, 0], self::ICON_DIRS, ]
|
||||
);
|
||||
|
||||
// textures are composed of 64x64 icons
|
||||
// numeric indexed arrays mimick the position on the texture
|
||||
private $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( // uses nameINT from ChrRaces.dbc
|
||||
['race_human_male', 'race_dwarf_male', 'race_gnome_male', 'race_nightelf_male', 'race_draenei_male' ],
|
||||
['race_tauren_male', 'race_scourge_male', 'race_troll_male', 'race_orc_male', 'race_bloodelf_male' ],
|
||||
['race_human_female', 'race_dwarf_female', 'race_gnome_female', 'race_nightelf_female', 'race_draenei_female' ],
|
||||
['race_tauren_female', 'race_scourge_female', 'race_troll_female', 'race_orc_female', 'race_bloodelf_female']
|
||||
),
|
||||
4 => array( // uses nameINT from ChrClasses.dbc
|
||||
['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'
|
||||
)
|
||||
);
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->imgPath = CLISetup::$srcDir.$this->imgPath;
|
||||
$this->maxExecTime = ini_get('max_execution_time');
|
||||
|
||||
// init directories to be checked when registered
|
||||
foreach (array_column($this->genSteps, self::$GEN_IDX_DEST_INFO) as $subDirs)
|
||||
foreach ($subDirs as $sd)
|
||||
$this->requiredDirs[] = $sd[0];
|
||||
|
||||
// fix genSteps 2 [icons] - no tiny inventory backgrounds
|
||||
$this->genSteps[2][self::$GEN_IDX_DEST_INFO] = array_slice($this->genSteps[2][self::$GEN_IDX_DEST_INFO], 0, 3);
|
||||
|
||||
// fix genSteps 12 [pvp money icons] - smaller border offset for pvp currency icons
|
||||
array_walk($this->genSteps[12][self::$GEN_IDX_DEST_INFO], function(&$x) { $x[4] = 2; });
|
||||
|
||||
// fix genSteps 10 [holoday icons] - img src size is 90px
|
||||
array_walk($this->genSteps[10][self::$GEN_IDX_DEST_INFO], function(&$x) { $x[2] = 90; });
|
||||
}
|
||||
|
||||
public function generate() : bool
|
||||
{
|
||||
// find out what to generate
|
||||
$groups = [];
|
||||
if (CLISetup::getOpt('icons'))
|
||||
array_push($groups, 0, 2, 3, 4, 5, 10, 12);
|
||||
if (CLISetup::getOpt('glyphs'))
|
||||
$groups[] = 1;
|
||||
if (CLISetup::getOpt('pagetexts'))
|
||||
array_push($groups, 7, 8, 9);
|
||||
if (CLISetup::getOpt('loadingscreens'))
|
||||
$groups[] = 11;
|
||||
|
||||
if (!$groups) // by default do not generate loadingscreens
|
||||
$groups = [0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 12];
|
||||
|
||||
// removed unused generators
|
||||
foreach ($this->genSteps as $idx => $_)
|
||||
if (!in_array($idx, $groups))
|
||||
unset($this->genSteps[$idx]);
|
||||
|
||||
if (!$this->checkSourceDirs())
|
||||
{
|
||||
CLI::write('[simpleimg] one or more required directories are missing:', CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
sleep(2);
|
||||
|
||||
$allPaths = [];
|
||||
foreach ($this->genSteps as $i => [, $path, , [$pattern, $isIcon, $tileSize], $outInfo])
|
||||
{
|
||||
$search = $path.$pattern;
|
||||
if ($pattern)
|
||||
$search = '/'.str_replace('/', '\\/', $search).'/i';
|
||||
|
||||
$files = CLISetup::filesInPath($search, !!$pattern);
|
||||
$allPaths = array_merge($allPaths, array_map(function ($x) { return substr($x, 0, -4); }, $files));
|
||||
|
||||
if (!$files)
|
||||
{
|
||||
CLI::write('[simpleimg] source directory "'.CLI::bold($search).'" does not contain files matching "'.CLI::bold($pattern), CLI::LOG_ERROR);
|
||||
$this->success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
CLI::write('[simpleimg] processing '.count($files).' files in '.$path.'...');
|
||||
|
||||
$j = 0;
|
||||
foreach ($files as $f)
|
||||
{
|
||||
ini_set('max_execution_time', $this->maxExecTime);
|
||||
|
||||
$src = null;
|
||||
$na = explode('/', $f);
|
||||
$img = explode('.', array_pop($na));
|
||||
array_pop($img); // there are a hand full of images with multiple file endings or random dots in the name
|
||||
$img = implode('.', $img);
|
||||
|
||||
if (!empty($this->cuNames[$i])) // file not from dbc -> name from array or skip file
|
||||
{
|
||||
if (!empty($this->cuNames[$i][strtolower($img)]))
|
||||
$img = $this->cuNames[$i][strtolower($img)];
|
||||
else if (!$tileSize)
|
||||
{
|
||||
$j += count($outInfo);
|
||||
CLI::write('[simpleimg] skipping extraneous file '.$img.' (+'.count($outInfo).')');
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
$nFiles = count($outInfo) * ($tileSize ? array_sum(array_map('count', $this->cuNames[$i])) : count($files));
|
||||
|
||||
foreach ($outInfo as [$dest, $ext, $srcSize, $destSize, $borderOffset])
|
||||
{
|
||||
if ($tileSize)
|
||||
{
|
||||
foreach ($this->cuNames[$i] as $y => $row)
|
||||
{
|
||||
foreach ($row as $x => $name)
|
||||
{
|
||||
$j++;
|
||||
$outFile = $dest.($isIcon ? strtolower($name) : $name).'.'.$ext;
|
||||
|
||||
$this->status = ' - '.str_pad($j.'/'.$nFiles, 12).str_pad('('.number_format($j * 100 / $nFiles, 2).'%)', 9);
|
||||
|
||||
if (!CLISetup::getOpt('force') && file_exists($outFile))
|
||||
{
|
||||
CLI::write('[simpleimg] '.$this->status.' - file '.$outFile.' was already processed', CLI::LOG_BLANK, true, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$src)
|
||||
$src = $this->loadImageFile($f);
|
||||
|
||||
if (!$src) // error should be created by imagecreatefromblp
|
||||
{
|
||||
$this->success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
ready for some major bullshitery? well, here it comes anyway!
|
||||
the class-icon tile [idx: 4] isn't 64x64 but 63x64 .. the right side border is 1px short
|
||||
so if we don't watch out, the icons start to shift over and show the border
|
||||
also the icon border is displaced by 1px
|
||||
*/
|
||||
$from = array(
|
||||
'x' => $borderOffset + 1 + ($tileSize - ($i == 4 ? 1 : 0)) * $x,
|
||||
'y' => $borderOffset + 1 + $tileSize * $y,
|
||||
'w' => ($tileSize - ($i == 4 ? 1 : 0)) - $borderOffset * 2,
|
||||
'h' => $tileSize - $borderOffset * 2
|
||||
);
|
||||
$to = array(
|
||||
'x' => 0,
|
||||
'y' => 0,
|
||||
'w' => $destSize,
|
||||
'h' => $destSize
|
||||
);
|
||||
|
||||
if (!$this->writeImageFile($src, $outFile, $from, $to))
|
||||
$this->success = false;
|
||||
}
|
||||
}
|
||||
|
||||
// custom handle for combined icon 'quest_startend'
|
||||
/* not used due to alphaChannel issues
|
||||
if ($tileSize == 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, $dest.'quest_startend.gif'))
|
||||
CLI::write(' extra - image '.$dest.'quest_startend.gif written', CLI::LOG_OK);
|
||||
else
|
||||
{
|
||||
CLI::write(' extra - could not create image '.$dest.'quest_startend.gif', CLI::LOG_ERROR);
|
||||
$this->success = false;
|
||||
}
|
||||
|
||||
imagedestroy($dest);
|
||||
}
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
$j++;
|
||||
$this->status = ' - '.str_pad($j.'/'.$nFiles, 12).str_pad('('.number_format($j * 100 / $nFiles, 2).'%)', 9);
|
||||
$outFile = $dest.($isIcon ? strtolower($img) : $img).'.'.$ext;
|
||||
|
||||
if (!CLISetup::getOpt('force') && file_exists($outFile))
|
||||
{
|
||||
CLI::write('[simpleimg] '.$this->status.' - file '.$outFile.' was already processed', CLI::LOG_BLANK, true, true);
|
||||
continue;
|
||||
}
|
||||
|
||||
$src = $this->loadImageFile($f);
|
||||
if (!$src) // error should be created by imagecreatefromblp
|
||||
{
|
||||
$this->success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
$from = array(
|
||||
'x' => $borderOffset,
|
||||
'y' => $borderOffset,
|
||||
'w' => ($srcSize ?: imagesx($src)) - $borderOffset * 2,
|
||||
'h' => ($srcSize ?: imagesy($src)) - $borderOffset * 2
|
||||
);
|
||||
$to = array(
|
||||
'x' => 0,
|
||||
'y' => 0,
|
||||
'w' => $destSize ?: imagesx($src),
|
||||
'h' => $destSize ?: imagesy($src)
|
||||
);
|
||||
|
||||
if (!$this->writeImageFile($src, $outFile, $from, $to))
|
||||
$this->success = false;
|
||||
}
|
||||
}
|
||||
|
||||
unset($src);
|
||||
}
|
||||
}
|
||||
|
||||
// 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 = [];
|
||||
$gens = array_keys($this->genSteps);
|
||||
|
||||
if (in_array(0, $gens)) // generates icons
|
||||
{
|
||||
if ($siRows = DB::Aowow()->selectCol('SELECT `iconPath` FROM dbc_spellicon WHERE `iconPath` NOT LIKE "%glyph-rune%"'))
|
||||
foreach ($siRows as $icon)
|
||||
if (stristr($icon, $this->genSteps[0][self::$GEN_IDX_SRC_PATH])) // Icons/
|
||||
$dbcEntries[] = strtolower($this->genSteps[0][self::$GEN_IDX_SRC_REAL].substr(strrchr($icon, '\\'), 1));
|
||||
|
||||
if ($itemIcons = DB::Aowow()->selectCol('SELECT `inventoryIcon1` FROM dbc_itemdisplayinfo WHERE `inventoryIcon1` <> ""'))
|
||||
foreach ($itemIcons as $icon)
|
||||
$dbcEntries[] = strtolower($this->genSteps[0][self::$GEN_IDX_SRC_REAL].'/'.$icon);
|
||||
}
|
||||
|
||||
if (in_array(1, $gens)) // generates glyphs
|
||||
if ($siRows = DB::Aowow()->selectCol('SELECT `iconPath` FROM dbc_spellicon WHERE `iconPath` LIKE "%glyph-rune%"'))
|
||||
foreach ($siRows as $icon)
|
||||
if (stristr($icon, $this->genSteps[1][self::$GEN_IDX_SRC_PATH])) // Spellbook/
|
||||
$dbcEntries[] = strtolower($this->genSteps[1][self::$GEN_IDX_SRC_REAL].substr(strrchr($icon, '\\'), 1));
|
||||
|
||||
if (in_array(10, $gens)) // generates holiday icons
|
||||
if ($eventIcons = DB::Aowow()->selectCol('SELECT `textureString` FROM dbc_holidays WHERE `textureString` <> ""'))
|
||||
foreach ($eventIcons as $icon)
|
||||
$dbcEntries[] = strtolower($this->genSteps[10][self::$GEN_IDX_SRC_REAL].'/'.$icon.'start');
|
||||
|
||||
// case-insensitive array_unique *vomits silently into a corner*
|
||||
$dbcEntries = array_intersect_key($dbcEntries, array_unique($dbcEntries));
|
||||
|
||||
if ($missing = array_diff(array_map('strtolower', $dbcEntries), array_map('strtolower', $allPaths)))
|
||||
{
|
||||
// hide affected icons from listviews
|
||||
$iconNames = array_map(function($path) {
|
||||
preg_match('/\/([^\/]+)\.blp$/i', $path, $m);
|
||||
return $m ? $m[1] : null;
|
||||
}, $missing);
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_icons SET `cuFlags` = `cuFlags` | ?d WHERE `name` IN (?a)', CUSTOM_EXCLUDE_FOR_LISTVIEW, $iconNames);
|
||||
|
||||
CLI::write('[simpleimg] 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.', CLI::LOG_WARN);
|
||||
foreach ($missing as $m)
|
||||
CLI::write(' - '.$m);
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -6,28 +6,31 @@ if (!defined('AOWOW_REVISION'))
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
function soundfiles()
|
||||
{
|
||||
$ok = true;
|
||||
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
protected $info = array(
|
||||
'soundfiles' => [[], CLISetup::ARGV_PARAM, 'Links converted sound files to database and moves them to destination.']
|
||||
);
|
||||
|
||||
protected $requiredDirs = ['static/wowsounds/'];
|
||||
protected $setupAfter = [['sounds'], []];
|
||||
|
||||
public function generate() : bool
|
||||
{
|
||||
// ALL files
|
||||
$files = DB::Aowow()->selectCol('SELECT ABS(id) AS ARRAY_KEY, CONCAT(path, "/", `file`) FROM ?_sounds_files');
|
||||
$nFiles = count($files);
|
||||
$qtLen = strlen($nFiles);
|
||||
$sum = 0;
|
||||
|
||||
$intv = 0.5;
|
||||
$time = microtime(true);
|
||||
$sum = 0;
|
||||
$time = new Timer(500);
|
||||
|
||||
foreach ($files as $fileId => $filePath)
|
||||
{
|
||||
$sum++;
|
||||
$newTime = microtime(true);
|
||||
if ($newTime > $time + $intv)
|
||||
if ($time->update())
|
||||
{
|
||||
CLI::write(sprintf(' * %'.$qtLen.'d / %d (%4.1f%%)', $sum, $nFiles, round(100 * $sum / $nFiles, 1)), CLI::LOG_BLANK, true, true);
|
||||
$time = $newTime;
|
||||
CLI::write(sprintf('[soundfiles] * %'.$qtLen.'d / %d (%4.1f%%)', $sum, $nFiles, round(100 * $sum / $nFiles, 1)), CLI::LOG_BLANK, true, true);
|
||||
DB::Aowow()->selectCell('SELECT 1'); // keep mysql busy or it may go away
|
||||
}
|
||||
|
||||
@@ -45,9 +48,9 @@ if (!CLI)
|
||||
// copy over to static/wowsounds/
|
||||
if (!copy($p, 'static/wowsounds/'.$fileId))
|
||||
{
|
||||
$ok = false;
|
||||
CLI::write(' - could not copy '.CLI::bold($p).' into '.CLI::bold('static/wowsounds/'.$fileId), CLI::LOG_ERROR);
|
||||
$time = 0;
|
||||
$this->success = false;
|
||||
CLI::write('[soundfiles] - could not copy '.CLI::bold($p).' into '.CLI::bold('static/wowsounds/'.$fileId), CLI::LOG_ERROR);
|
||||
$time->reset();
|
||||
break 2;
|
||||
}
|
||||
|
||||
@@ -55,14 +58,14 @@ if (!CLI)
|
||||
}
|
||||
}
|
||||
|
||||
CLI::write(' - did not find file: '.CLI::bold(CLI::nicePath($filePath, CLISetup::$srcDir, '['.implode(',', CLISetup::$locales).']')), CLI::LOG_WARN);
|
||||
$time = 0;
|
||||
CLI::write('[soundfiles] - did not find file: '.CLI::bold(CLI::nicePath($filePath, CLISetup::$srcDir, '['.implode(',', CLISetup::$locales).']')), CLI::LOG_WARN);
|
||||
$time->reset();
|
||||
// flag as unusable in DB
|
||||
DB::Aowow()->query('UPDATE ?_sounds_files SET id = ?d WHERE ABS(id) = ?d', -$fileId, $fileId);
|
||||
}
|
||||
|
||||
return $ok;
|
||||
return $this->success;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,201 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/* deps:
|
||||
* player_classlevelstats
|
||||
* player_levelstats
|
||||
*/
|
||||
|
||||
// Create 'statistics'-file in datasets
|
||||
// this script requires the following dbcs to be available
|
||||
$reqDBC = ['gtchancetomeleecrit', 'gtchancetomeleecritbase', 'gtchancetospellcrit', 'gtchancetospellcritbase', 'gtoctregenhp', 'gtregenmpperspt', 'gtregenhpperspt'];
|
||||
|
||||
function statistics()
|
||||
{
|
||||
$classs = function()
|
||||
{
|
||||
// constants and mods taken from TrinityCore (Player.cpp, StatSystem.cpp)
|
||||
|
||||
/* content per Index
|
||||
mleatkpwr[base, strMultiplier, agiMultiplier, levelMultiplier]
|
||||
rngatkpwr[base, strMultiplier, agiMultiplier, levelMultiplier]
|
||||
baseCritPct[phys, spell]
|
||||
diminishingConstant
|
||||
baseDodgePct
|
||||
DodgeCap
|
||||
baseParryPct
|
||||
ParryCap
|
||||
baseBlockPct
|
||||
classMod1 applies mod directly only one class having something worth mentioning: DK
|
||||
classMod2 applies mod directly so what were they originally used for..?
|
||||
*/
|
||||
|
||||
$dataz = array(
|
||||
1 => [[-20, 2, 0, 3], [-10, 0, 1, 1], null, 0.9560, 3.6640, 88.129021, 5, 47.003525, 5, [], []],
|
||||
2 => [[-20, 2, 0, 3], [-10, 0, 1, 0], null, 0.9560, 3.4943, 88.129021, 5, 47.003525, 5, [], []],
|
||||
3 => [[-20, 1, 1, 2], [-10, 0, 1, 2], null, 0.9880, -4.0873, 145.560408, 5, 145.560408, 0, [], []],
|
||||
4 => [[-20, 1, 1, 2], [-10, 0, 1, 1], null, 0.9880, 2.0957, 145.560408, 5, 145.560408, 0, [], []],
|
||||
5 => [[-10, 1, 0, 0], [-10, 0, 1, 0], null, 0.9830, 3.4178, 150.375940, 0, 0.0, 0, [], []],
|
||||
6 => [[-20, 2, 0, 3], [-10, 0, 1, 0], null, 0.9560, 3.6640, 88.129021, 5, 47.003525, 0, [], ['parryrtng' => [0.25, 'percentOf', 'str']]], // Forcefull Deflection (49410)
|
||||
7 => [[-20, 1, 1, 2], [-10, 0, 1, 0], null, 0.9880, 2.1080, 145.560408, 0, 145.560408, 5, [], []],
|
||||
8 => [[-10, 1, 0, 0], [-10, 0, 1, 0], null, 0.9830, 3.6587, 150.375940, 0, 0.0, 0, [], []],
|
||||
9 => [[-10, 1, 0, 0], [-10, 0, 1, 0], null, 0.9830, 2.4211, 150.375940, 0, 0.0, 0, [], []],
|
||||
11 => [[-20, 2, 0, 0], [-10, 0, 1, 0], null, 0.9720, 5.6097, 116.890707, 0, 0.0, 0, [], []]
|
||||
);
|
||||
|
||||
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));
|
||||
|
||||
return $dataz;
|
||||
};
|
||||
|
||||
$race = function()
|
||||
{
|
||||
// { str, agi, sta, int, spi, raceMod1, raceMod2 }
|
||||
$raceData = DB::World()->select('SELECT `race` AS ARRAY_KEY, MIN(`str`), MIN(`agi`), MIN(`sta`), MIN(`inte`), MIN(`spi`) FROM player_levelstats WHERE `level` = 1 GROUP BY `race` ORDER BY `race` ASC');
|
||||
foreach ($raceData as &$rd)
|
||||
$rd = array_values($rd + [[], []]);
|
||||
|
||||
$racials = new SpellList(array(['typeCat', -4], ['reqClassMask', 0]));
|
||||
$allMods = $racials->getProfilerMods();
|
||||
foreach ($allMods as $spellId => $mods)
|
||||
{
|
||||
if (!$mods)
|
||||
continue;
|
||||
|
||||
// if there is ever a case where a racial is shared between races i don't want to know about it!
|
||||
$raceId = log($racials->getEntry($spellId)['reqRaceMask'], 2) + 1;
|
||||
if (!isset($raceData[$raceId]))
|
||||
continue;
|
||||
|
||||
foreach ($mods as $jsonStat => $mod)
|
||||
{
|
||||
if (empty($raceData[$raceId][5][$jsonStat]))
|
||||
$raceData[$raceId][5][$jsonStat] = $mod;
|
||||
else
|
||||
$raceData[$raceId][6][$jsonStat] = $mod;
|
||||
}
|
||||
}
|
||||
|
||||
return $raceData;
|
||||
};
|
||||
|
||||
$combo = function()
|
||||
{
|
||||
$result = [];
|
||||
$critToDodge = array(
|
||||
1 => 0.85/1.15, 2 => 1.00/1.15, 3 => 1.11/1.15,
|
||||
4 => 2.00/1.15, 5 => 1.00/1.15, 6 => 0.85/1.15,
|
||||
7 => 1.60/1.15, 8 => 1.00/1.15, 9 => 0.97/1.15, 11 => 2.00/1.15
|
||||
);
|
||||
|
||||
// TrinityCore claims, DodgePerAgi per level and class can be constituted from critPerAgi (and level (and class))
|
||||
// who am i to argue
|
||||
// rebase stats to a specific race. chosen human as all stats are 20 and tauren for hunter, shaman and druid
|
||||
// the stat gain per level is only dependant on the class. The race only determines the initial stats at level 0
|
||||
// level:{ str, agi, sta, int, spi, hp, mana, mleCrt%Agi, splCrt%Int, dodge%Agi, HealthRegenModToBaseStat, HealthRegenModToBonusStat }
|
||||
|
||||
foreach ($critToDodge as $class => $mod)
|
||||
{
|
||||
// humans can't be hunter, shaman, druids (use tauren here)
|
||||
if (in_array($class, [3, 7, 11]))
|
||||
$offset = array_values(DB::World()->selectRow('SELECT MIN(`str`), MIN(`agi`), MIN(`sta`), MIN(`inte`), MIN(`spi`) FROM player_levelstats WHERE `level` = 1 AND `race` = 6'));
|
||||
else
|
||||
$offset = array_values(DB::World()->selectRow('SELECT MIN(`str`), MIN(`agi`), MIN(`sta`), MIN(`inte`), MIN(`spi`) FROM player_levelstats WHERE `level` = 1 AND `race` = 1'));
|
||||
|
||||
$gtData = DB::Aowow()->select('
|
||||
SELECT mlecrt.idx - ?d AS ARRAY_KEY, mlecrt.chance * 100, splcrt.chance * 100, mlecrt.chance * 100 * ?f, baseHP5.ratio * 1, extraHP5.ratio * 1
|
||||
FROM dbc_gtchancetomeleecrit mlecrt
|
||||
JOIN dbc_gtchancetospellcrit splcrt ON splcrt.idx = mlecrt.idx
|
||||
JOIN dbc_gtoctregenhp baseHP5 ON baseHP5.idx = mlecrt.idx
|
||||
JOIN dbc_gtregenhpperspt extraHP5 ON extraHP5.idx = mlecrt.idx
|
||||
WHERE mlecrt.idx BETWEEN ?d AND ?d',
|
||||
(($class - 1) * 100) - 1, // class-offset
|
||||
$mod,
|
||||
(($class - 1) * 100) + 0, // lvl 1
|
||||
(($class - 1) * 100) + 79 // lvl 80
|
||||
);
|
||||
|
||||
$rows = DB::World()->select('
|
||||
SELECT
|
||||
pls.level AS ARRAY_KEY,
|
||||
pls.str - ?d, pls.agi - ?d, pls.sta - ?d, pls.inte - ?d, pls.spi - ?d,
|
||||
pcls.basehp, IF(pcls.basemana <> 0, pcls.basemana, 100)
|
||||
FROM
|
||||
player_levelstats pls
|
||||
JOIN
|
||||
player_classlevelstats pcls ON pls.level = pcls.level AND pls.class = pcls.class
|
||||
WHERE
|
||||
pls.race = ?d AND pls.class = ?d ORDER BY pls.level ASC',
|
||||
$offset[0], $offset[1], $offset[2], $offset[3], $offset[4],
|
||||
in_array($class, [3, 7, 11]) ? 6 : 1,
|
||||
$class
|
||||
);
|
||||
|
||||
$result[$class] = [];
|
||||
foreach ($rows as $lvl => $row)
|
||||
$result[$class][$lvl] = array_values(array_merge($row, $gtData[$lvl]));
|
||||
}
|
||||
|
||||
return $result;
|
||||
};
|
||||
|
||||
$level = function()
|
||||
{
|
||||
// base mana regeneration per level
|
||||
// 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);
|
||||
};
|
||||
|
||||
$skills = function()
|
||||
{
|
||||
// profession perks ... too lazy to formulate a search algorithm for two occurences
|
||||
return array(
|
||||
SKILL_MINING => array( // mining / toughness
|
||||
75 => ['sta' => 3],
|
||||
150 => ['sta' => 5],
|
||||
225 => ['sta' => 7],
|
||||
300 => ['sta' => 10],
|
||||
375 => ['sta' => 30],
|
||||
450 => ['sta' => 60],
|
||||
),
|
||||
SKILL_SKINNING => array( // skinning / master of anatomy
|
||||
75 => ['critstrkrtng' => 3],
|
||||
150 => ['critstrkrtng' => 6],
|
||||
225 => ['critstrkrtng' => 9],
|
||||
300 => ['critstrkrtng' => 12],
|
||||
375 => ['critstrkrtng' => 20],
|
||||
450 => ['critstrkrtng' => 40],
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
$sub = ['classs', 'race', 'combo', 'level', 'skills'];
|
||||
$out = [];
|
||||
$success = true;
|
||||
|
||||
foreach ($sub as $s)
|
||||
{
|
||||
$res = $$s();
|
||||
$out[$s] = $res;
|
||||
if (!$res)
|
||||
CLI::write('statistics - generator $'.$s.'() returned empty', CLI::LOG_WARN);
|
||||
}
|
||||
|
||||
$toFile = 'g_statistics = '.preg_replace('/"\$([^$"]+)"/', '\1', Util::toJSON($out)).';';
|
||||
|
||||
if (!CLISetup::writeFile('datasets/statistics', $toFile))
|
||||
$success = false;
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
?>
|
||||
209
setup/tools/filegen/statistics.ss.php
Normal file
209
setup/tools/filegen/statistics.ss.php
Normal file
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
// Create 'statistics'-file in datasets
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
protected $info = array(
|
||||
'statistics' => [[], CLISetup::ARGV_PARAM, 'Compiles player stats into file for the character profiler tool.']
|
||||
);
|
||||
|
||||
protected $worldDependency = ['player_levelstats', 'player_classlevelstats'];
|
||||
protected $dbcSourceFiles = ['gtchancetomeleecrit', 'gtchancetomeleecritbase', 'gtchancetospellcrit', 'gtchancetospellcritbase', 'gtoctregenhp', 'gtregenmpperspt', 'gtregenhpperspt'];
|
||||
protected $requiredDirs = ['datasets/'];
|
||||
|
||||
public function generate() : bool
|
||||
{
|
||||
$sub = ['classs', 'race', 'combo', 'level', 'skills'];
|
||||
$out = [];
|
||||
|
||||
foreach ($sub as $s)
|
||||
{
|
||||
if ($out[$s] = $this->$s())
|
||||
continue;
|
||||
|
||||
CLI::write('[statistics] generator '.$s.'() returned empty', CLI::LOG_WARN);
|
||||
$this->success = false;
|
||||
}
|
||||
|
||||
$toFile = 'g_statistics = '.preg_replace('/"\$([^$"]+)"/', '\1', Util::toJSON($out)).';';
|
||||
|
||||
if (!CLISetup::writeFile('datasets/statistics', $toFile))
|
||||
$this->success = false;
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
// constants and mods taken from TrinityCore (Player.cpp, StatSystem.cpp)
|
||||
private function classs() : array
|
||||
{
|
||||
/* content per Index
|
||||
mleatkpwr[base, strMultiplier, agiMultiplier, levelMultiplier]
|
||||
rngatkpwr[base, strMultiplier, agiMultiplier, levelMultiplier]
|
||||
baseCritPct[phys, spell]
|
||||
diminishingConstant
|
||||
baseDodgePct
|
||||
DodgeCap
|
||||
baseParryPct
|
||||
ParryCap
|
||||
baseBlockPct
|
||||
classMod1 applies mod directly only one class having something worth mentioning: DK
|
||||
classMod2 applies mod directly so what were they originally used for..?
|
||||
*/
|
||||
|
||||
$dataz = array(
|
||||
1 => [[-20, 2, 0, 3], [-10, 0, 1, 1], null, 0.9560, 3.6640, 88.129021, 5, 47.003525, 5, [], []],
|
||||
2 => [[-20, 2, 0, 3], [-10, 0, 1, 0], null, 0.9560, 3.4943, 88.129021, 5, 47.003525, 5, [], []],
|
||||
3 => [[-20, 1, 1, 2], [-10, 0, 1, 2], null, 0.9880, -4.0873, 145.560408, 5, 145.560408, 0, [], []],
|
||||
4 => [[-20, 1, 1, 2], [-10, 0, 1, 1], null, 0.9880, 2.0957, 145.560408, 5, 145.560408, 0, [], []],
|
||||
5 => [[-10, 1, 0, 0], [-10, 0, 1, 0], null, 0.9830, 3.4178, 150.375940, 0, 0.0, 0, [], []],
|
||||
6 => [[-20, 2, 0, 3], [-10, 0, 1, 0], null, 0.9560, 3.6640, 88.129021, 5, 47.003525, 0, [], ['parryrtng' => [0.25, 'percentOf', 'str']]], // Forcefull Deflection (49410)
|
||||
7 => [[-20, 1, 1, 2], [-10, 0, 1, 0], null, 0.9880, 2.1080, 145.560408, 0, 145.560408, 5, [], []],
|
||||
8 => [[-10, 1, 0, 0], [-10, 0, 1, 0], null, 0.9830, 3.6587, 150.375940, 0, 0.0, 0, [], []],
|
||||
9 => [[-10, 1, 0, 0], [-10, 0, 1, 0], null, 0.9830, 2.4211, 150.375940, 0, 0.0, 0, [], []],
|
||||
11 => [[-20, 2, 0, 0], [-10, 0, 1, 0], null, 0.9720, 5.6097, 116.890707, 0, 0.0, 0, [], []]
|
||||
);
|
||||
|
||||
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));
|
||||
|
||||
return $dataz;
|
||||
}
|
||||
|
||||
// { str, agi, sta, int, spi, raceMod1, raceMod2 }
|
||||
private function race() : array
|
||||
{
|
||||
$raceData = DB::World()->select('SELECT `race` AS ARRAY_KEY, MIN(`str`), MIN(`agi`), MIN(`sta`), MIN(`inte`), MIN(`spi`) FROM player_levelstats WHERE `level` = 1 GROUP BY `race` ORDER BY `race` ASC');
|
||||
foreach ($raceData as &$rd)
|
||||
$rd = array_values($rd + [[], []]);
|
||||
|
||||
$racials = new SpellList(array(['typeCat', -4], ['reqClassMask', 0]));
|
||||
$allMods = $racials->getProfilerMods();
|
||||
foreach ($allMods as $spellId => $mods)
|
||||
{
|
||||
if (!$mods)
|
||||
continue;
|
||||
|
||||
// if there is ever a case where a racial is shared between races i don't want to know about it!
|
||||
$raceId = log($racials->getEntry($spellId)['reqRaceMask'], 2) + 1;
|
||||
if (!isset($raceData[$raceId]))
|
||||
continue;
|
||||
|
||||
foreach ($mods as $jsonStat => $mod)
|
||||
{
|
||||
if (empty($raceData[$raceId][5][$jsonStat]))
|
||||
$raceData[$raceId][5][$jsonStat] = $mod;
|
||||
else
|
||||
$raceData[$raceId][6][$jsonStat] = $mod;
|
||||
}
|
||||
}
|
||||
|
||||
return $raceData;
|
||||
}
|
||||
|
||||
// TrinityCore claims, DodgePerAgi per level and class can be constituted from critPerAgi (and level (and class))
|
||||
// who am i to argue
|
||||
// rebase stats to a specific race. chosen human as all stats are 20 and tauren for hunter, shaman and druid
|
||||
// level:{ str, agi, sta, int, spi, hp, mana, mleCrt%Agi, splCrt%Int, dodge%Agi, HealthRegenModToBaseStat, HealthRegenModToBonusStat }
|
||||
private function combo() : array
|
||||
{
|
||||
$result = [];
|
||||
$critToDodge = array(
|
||||
1 => 0.85/1.15, 2 => 1.00/1.15, 3 => 1.11/1.15,
|
||||
4 => 2.00/1.15, 5 => 1.00/1.15, 6 => 0.85/1.15,
|
||||
7 => 1.60/1.15, 8 => 1.00/1.15, 9 => 0.97/1.15, 11 => 2.00/1.15
|
||||
);
|
||||
|
||||
foreach ($critToDodge as $class => $mod)
|
||||
{
|
||||
// humans can't be hunter, shaman, druids (use tauren here)
|
||||
if (in_array($class, [3, 7, 11]))
|
||||
$offset = array_values(DB::World()->selectRow('SELECT MIN(`str`), MIN(`agi`), MIN(`sta`), MIN(`inte`), MIN(`spi`) FROM player_levelstats WHERE `level` = 1 AND `race` = 6'));
|
||||
else
|
||||
$offset = array_values(DB::World()->selectRow('SELECT MIN(`str`), MIN(`agi`), MIN(`sta`), MIN(`inte`), MIN(`spi`) FROM player_levelstats WHERE `level` = 1 AND `race` = 1'));
|
||||
|
||||
$gtData = DB::Aowow()->select(
|
||||
'SELECT mlecrt.idx - ?d AS ARRAY_KEY, mlecrt.chance * 100, splcrt.chance * 100, mlecrt.chance * 100 * ?f, baseHP5.ratio * 1, extraHP5.ratio * 1
|
||||
FROM dbc_gtchancetomeleecrit mlecrt
|
||||
JOIN dbc_gtchancetospellcrit splcrt ON splcrt.idx = mlecrt.idx
|
||||
JOIN dbc_gtoctregenhp baseHP5 ON baseHP5.idx = mlecrt.idx
|
||||
JOIN dbc_gtregenhpperspt extraHP5 ON extraHP5.idx = mlecrt.idx
|
||||
WHERE mlecrt.idx BETWEEN ?d AND ?d',
|
||||
(($class - 1) * 100) - 1, // class-offset
|
||||
$mod,
|
||||
(($class - 1) * 100) + 0, // lvl 1
|
||||
(($class - 1) * 100) + 79 // lvl 80
|
||||
);
|
||||
|
||||
$rows = DB::World()->select(
|
||||
'SELECT pls.level AS ARRAY_KEY,
|
||||
pls.str - ?d, pls.agi - ?d, pls.sta - ?d, pls.inte - ?d, pls.spi - ?d,
|
||||
pcls.basehp, IF(pcls.basemana <> 0, pcls.basemana, 100)
|
||||
FROM player_levelstats pls
|
||||
JOIN player_classlevelstats pcls ON pls.level = pcls.level AND pls.class = pcls.class
|
||||
WHERE pls.race = ?d AND
|
||||
pls.class = ?d
|
||||
ORDER BY pls.level ASC',
|
||||
$offset[0], $offset[1], $offset[2], $offset[3], $offset[4],
|
||||
in_array($class, [3, 7, 11]) ? 6 : 1,
|
||||
$class
|
||||
);
|
||||
|
||||
$result[$class] = [];
|
||||
foreach ($rows as $lvl => $row)
|
||||
$result[$class][$lvl] = array_values(array_merge($row, $gtData[$lvl]));
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// base mana regeneration per level
|
||||
// identical across classes (just use one, that acutally has mana (offset: 100))
|
||||
// content of gtRegenMPPerSpt.dbc
|
||||
private function level() : array
|
||||
{
|
||||
return DB::Aowow()->selectCol('SELECT idx-99 AS ARRAY_KEY, ratio FROM dbc_gtregenmpperspt WHERE idx >= 100 AND idx < 100 + ?d', MAX_LEVEL);
|
||||
}
|
||||
|
||||
// profession perks ... too lazy to formulate a search algorithm for two occurences
|
||||
private function skills() : array
|
||||
{
|
||||
// DB::Aowow()->select(
|
||||
// 'SELECT sk.id AS "skillId", sla.reqSkillLevel, s.effect1AuraId AS "auraId", s.effect1MiscValue, s.effect1BasePoints + s.effect1DieSides AS "qty"
|
||||
// FROM dbc_skilllineability sla
|
||||
// JOIN dbc_skillline sk ON sk.id = sla.skilllineid
|
||||
// JOIN dbc_spell s ON s.id = sla.spellId
|
||||
// WHERE sla.acquiremethod = 1 AND // learn on skillup
|
||||
// sk.categoryId = 11 AND // primary profession
|
||||
// s.effect1Id = 6 AND // ApplyAura
|
||||
// s.effect1AuraId IN (29, 189) // ModStatFlat, ModRating (need more?)
|
||||
// ');
|
||||
|
||||
return array(
|
||||
SKILL_MINING => array( // mining / toughness
|
||||
75 => ['sta' => 3],
|
||||
150 => ['sta' => 5],
|
||||
225 => ['sta' => 7],
|
||||
300 => ['sta' => 10],
|
||||
375 => ['sta' => 30],
|
||||
450 => ['sta' => 60],
|
||||
),
|
||||
SKILL_SKINNING => array( // skinning / master of anatomy
|
||||
75 => ['critstrkrtng' => 3],
|
||||
150 => ['critstrkrtng' => 6],
|
||||
225 => ['critstrkrtng' => 9],
|
||||
300 => ['critstrkrtng' => 12],
|
||||
375 => ['critstrkrtng' => 20],
|
||||
450 => ['critstrkrtng' => 40],
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,211 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
// talents
|
||||
// i - int talentId (id of aowow_talent)
|
||||
// n - str name (spellname of aowow_spell for spellID = rank1)
|
||||
// m - int number of ranks (6+ are empty)
|
||||
// s - array:int spells to ranks (rank1, rank2, ..., rank5 of aowow_talent)
|
||||
// d - array:str description of spells
|
||||
// x - int column (col from aowow_talent)
|
||||
// y - int row (row of aowow_talent)
|
||||
// r - array:int on what the talent depends on: "r:[u, v]", u - nth talent in tree, v - required rank of u
|
||||
// f - array:int [pets only] creatureFamilies, that use this spell
|
||||
// t - array:str if the talent teaches a spell, this is the upper tooltip-table containing castTime, cost, cooldown
|
||||
// j - array of modifier-arrays per rank for the Profiler [nyi]
|
||||
// tabs
|
||||
// n - name of the tab
|
||||
// t - array of talent-objects
|
||||
// f - array:int [pets only] creatureFamilies in that category
|
||||
|
||||
// builds talent-tree-data for the talent-calculator
|
||||
// this script requires the following dbc-files to be available
|
||||
$reqDBC = ['talenttab', 'talent', 'spell', 'creaturefamily', 'spellicon'];
|
||||
|
||||
function talentCalc()
|
||||
{
|
||||
$success = true;
|
||||
$spellMods = (new SpellList(array(['typeCat', -2], Cfg::get('SQL_LIMIT_NONE'))))->getProfilerMods();
|
||||
|
||||
$buildTree = function ($class) use (&$petFamIcons, &$tSpells, $spellMods)
|
||||
{
|
||||
$petCategories = [];
|
||||
|
||||
$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);
|
||||
$result = [];
|
||||
|
||||
for ($tabIdx = 0; $tabIdx < count($tabs); $tabIdx++)
|
||||
{
|
||||
$talents = DB::Aowow()->select('SELECT t.id AS tId, t.*, s.name_loc0, s.name_loc2, s.name_loc3, s.name_loc4, s.name_loc6, s.name_loc8, LOWER(SUBSTRING_INDEX(si.iconPath, "\\\\", -1)) AS iconString FROM dbc_talent t, dbc_spell s, dbc_spellicon si WHERE si.`id` = s.`iconId` AND t.`tabId`= ?d AND s.`id` = t.`rank1` ORDER by t.`row`, t.`column`', $tabs[$tabIdx]['id']);
|
||||
$result[$tabIdx] = array(
|
||||
'n' => Util::localizedString($tabs[$tabIdx], 'name'),
|
||||
't' => []
|
||||
);
|
||||
|
||||
if (!$class)
|
||||
{
|
||||
$petFamId = log($tabs[$tabIdx]['creatureFamilyMask'], 2);
|
||||
$result[$tabIdx]['icon'] = $petFamIcons[$petFamId];
|
||||
$petCategories = DB::Aowow()->SelectCol('SELECT id AS ARRAY_KEY, categoryEnumID FROM dbc_creaturefamily WHERE petTalentType = ?d', $petFamId);
|
||||
$result[$tabIdx]['f'] = array_keys($petCategories);
|
||||
}
|
||||
|
||||
// talent dependencies go here
|
||||
$depLinks = [];
|
||||
$tNums = [];
|
||||
|
||||
for ($talentIdx = 0; $talentIdx < count($talents); $talentIdx++)
|
||||
{
|
||||
$tNums[$talents[$talentIdx]['tId']] = $talentIdx;
|
||||
|
||||
$d = [];
|
||||
$s = [];
|
||||
$i = $talents[$talentIdx]['tId'];
|
||||
$n = Util::localizedString($talents[$talentIdx], 'name');
|
||||
$x = $talents[$talentIdx]['column'];
|
||||
$y = $talents[$talentIdx]['row'];
|
||||
$r = null;
|
||||
$t = [];
|
||||
$j = [];
|
||||
$icon = $talents[$talentIdx]['iconString'];
|
||||
$m = $talents[$talentIdx]['rank2'] == 0 ? 1 : (
|
||||
$talents[$talentIdx]['rank3'] == 0 ? 2 : (
|
||||
$talents[$talentIdx]['rank4'] == 0 ? 3 : (
|
||||
$talents[$talentIdx]['rank5'] == 0 ? 4 : 5
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// duplet handling
|
||||
$f = [];
|
||||
foreach ($petCategories as $k => $v)
|
||||
{
|
||||
// cant handle 64bit integer .. split
|
||||
if ($v >= 32 && ((1 << ($v - 32)) & $talents[$talentIdx]['petCategory2']))
|
||||
$f[] = $k;
|
||||
else if ($v < 32 && ((1 << $v) & $talents[$talentIdx]['petCategory1']))
|
||||
$f[] = $k;
|
||||
}
|
||||
|
||||
for ($itr = 0; $itr <= ($m - 1); $itr++)
|
||||
{
|
||||
if (!$tSpells->getEntry($talents[$talentIdx]['rank'.($itr + 1)]))
|
||||
continue;
|
||||
|
||||
$d[] = $tSpells->parseText()[0];
|
||||
$s[] = $talents[$talentIdx]['rank'.($itr + 1)];
|
||||
if (isset($spellMods[$talents[$talentIdx]['rank'.($itr + 1)]]))
|
||||
$j[] = $spellMods[$talents[$talentIdx]['rank'.($itr + 1)]];
|
||||
else
|
||||
$j[] = null;
|
||||
|
||||
if ($talents[$talentIdx]['talentSpell'])
|
||||
$t[] = $tSpells->getTalentHeadForCurrent();
|
||||
}
|
||||
|
||||
if ($talents[$talentIdx]['reqTalent'])
|
||||
{
|
||||
// we didn't encounter the required talent yet => create reference
|
||||
if (!isset($tNums[$talents[$talentIdx]['reqTalent']]))
|
||||
$depLinks[$talents[$talentIdx]['reqTalent']] = $talentIdx;
|
||||
|
||||
$r = [$tNums[$talents[$talentIdx]['reqTalent']] ?? 0, $talents[$talentIdx]['reqRank'] + 1];
|
||||
}
|
||||
|
||||
$result[$tabIdx]['t'][$talentIdx] = array(
|
||||
'i' => $i, // talent id
|
||||
'n' => $n, // talent name
|
||||
'm' => $m, // maxRank
|
||||
'd' => $d, // [descriptions]
|
||||
's' => $s, // [spellIds]
|
||||
'x' => $x, // col #
|
||||
'y' => $y, // row #
|
||||
'j' => $j // spell mods applied when used in profiler
|
||||
);
|
||||
|
||||
if (isset($r)) // [reqTalentId, reqRank]
|
||||
$result[$tabIdx]['t'][$talentIdx]['r'] = $r;
|
||||
|
||||
if (!empty($t)) // talentspell tooltip
|
||||
$result[$tabIdx]['t'][$talentIdx]['t'] = $t;
|
||||
|
||||
if (!empty($f)) // [petFamilyId]
|
||||
$result[$tabIdx]['t'][$talentIdx]['f'] = $f;
|
||||
|
||||
if ($class)
|
||||
$result[$tabIdx]['t'][$talentIdx]['iconname'] = $icon;
|
||||
|
||||
// If this talent is a reference, add it to the array of talent dependencies
|
||||
if (isset($depLinks[$talents[$talentIdx]['tId']]))
|
||||
{
|
||||
$result[$tabIdx]['t'][$depLinks[$talents[$talentIdx]['tId']]]['r'][0] = $talentIdx;
|
||||
unset($depLinks[$talents[$talentIdx]['tId']]);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all dependencies for which the talent has not been found
|
||||
foreach ($depLinks as $dep_link)
|
||||
unset($result[$tabIdx]['t'][$dep_link]['r']);
|
||||
}
|
||||
|
||||
return $result;
|
||||
};
|
||||
|
||||
// my neighbour is noisy as fuck and my head hurts, so ..
|
||||
$petFamIcons = ['Ability_Druid_KingoftheJungle', 'Ability_Druid_DemoralizingRoar', 'Ability_EyeOfTheOwl']; // .. i've no idea where to fetch these from
|
||||
$classes = [CLASS_WARRIOR, CLASS_PALADIN, CLASS_HUNTER, CLASS_ROGUE, CLASS_PRIEST, CLASS_DEATHKNIGHT, CLASS_SHAMAN, CLASS_MAGE, CLASS_WARLOCK, CLASS_DRUID];
|
||||
$petIcons = '';
|
||||
|
||||
// check directory-structure
|
||||
foreach (Util::$localeStrings as $dir)
|
||||
if (!CLISetup::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');
|
||||
$tSpells = new SpellList(array(['s.id', $tSpellIds], Cfg::get('SQL_LIMIT_NONE')));
|
||||
|
||||
foreach (CLISetup::$localeIds as $lId)
|
||||
{
|
||||
User::useLocale($lId);
|
||||
Lang::load($lId);
|
||||
|
||||
// TalentCalc
|
||||
foreach ($classes as $cMask)
|
||||
{
|
||||
set_time_limit(20);
|
||||
|
||||
$cId = log($cMask, 2) + 1;
|
||||
$file = 'datasets/'.User::$localeString.'/talents-'.$cId;
|
||||
$toFile = '$WowheadTalentCalculator.registerClass('.$cId.', '.Util::toJSON($buildTree($cId)).')';
|
||||
|
||||
if (!CLISetup::writeFile($file, $toFile))
|
||||
$success = false;
|
||||
}
|
||||
|
||||
// PetCalc
|
||||
if (empty($petIcons))
|
||||
{
|
||||
$pets = DB::Aowow()->SelectCol('SELECT id AS ARRAY_KEY, LOWER(SUBSTRING_INDEX(iconString, "\\\\", -1)) AS iconString FROM dbc_creaturefamily WHERE petTalentType IN (0, 1, 2)');
|
||||
$petIcons = Util::toJSON($pets);
|
||||
}
|
||||
|
||||
$toFile = "var g_pet_icons = ".$petIcons.";\n\n";
|
||||
$toFile .= 'var g_pet_talents = '.Util::toJSON($buildTree(0)).';';
|
||||
$file = 'datasets/'.User::$localeString.'/pet-talents';
|
||||
|
||||
if (!CLISetup::writeFile($file, $toFile))
|
||||
$success = false;
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
?>
|
||||
@@ -1,102 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
// 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 available
|
||||
$reqDBC = ['talenttab', 'talent', 'spell'];
|
||||
|
||||
function talentIcons()
|
||||
{
|
||||
$success = true;
|
||||
$query = 'SELECT ic.name AS iconString FROM ?_icons ic JOIN ?_spell s ON s.iconId = ic.id 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 ASC, s.id DESC';
|
||||
$dims = 36; //v-pets
|
||||
$filenames = ['icons', 'warrior', 'paladin', 'hunter', 'rogue', 'priest', 'deathknight', 'shaman', 'mage', 'warlock', null, 'druid'];
|
||||
|
||||
// create directory if missing
|
||||
if (!CLISetup::writeDir('static/images/wow/talents/icons'))
|
||||
$success = false;
|
||||
|
||||
if (!CLISetup::writeDir('static/images/wow/hunterpettalents'))
|
||||
$success = false;
|
||||
|
||||
foreach ($filenames as $k => $v)
|
||||
{
|
||||
if (!$v)
|
||||
continue;
|
||||
|
||||
set_time_limit(10);
|
||||
|
||||
for ($tree = 0; $tree < 3; $tree++)
|
||||
{
|
||||
$what = $k ? 'classMask' : 'creatureFamilyMask';
|
||||
$set = $k ? 1 << ($k - 1) : 1 << $tree;
|
||||
$subset = $k ? $tree : 0;
|
||||
$path = $k ? 'talents/icons' : 'hunterpettalents';
|
||||
$outFile = 'static/images/wow/'.$path.'/'.$v.'_'.($tree + 1).'.jpg';
|
||||
$icons = DB::Aowow()->SelectCol($query, $what, $set, $subset);
|
||||
|
||||
if (empty($icons))
|
||||
{
|
||||
CLI::write('talentIcons - query for '.$v.' tree: '.$k.' returned empty', CLI::LOG_ERROR);
|
||||
$success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($res = imageCreateTrueColor(count($icons) * $dims, 2 * $dims))
|
||||
{
|
||||
for ($i = 0; $i < count($icons); $i++)
|
||||
{
|
||||
$imgFile = 'static/images/wow/icons/medium/'.strtolower($icons[$i]).'.jpg';
|
||||
if (!file_exists($imgFile))
|
||||
{
|
||||
CLI::write('talentIcons - raw image '.CLI::bold($imgFile). ' not found', CLI::LOG_ERROR);
|
||||
$success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
$im = imagecreatefromjpeg($imgFile);
|
||||
|
||||
// colored
|
||||
imagecopymerge($res, $im, $i * $dims, 0, 0, 0, imageSX($im), imageSY($im), 100);
|
||||
|
||||
// grayscale
|
||||
if (imageistruecolor($im))
|
||||
imagetruecolortopalette($im, false, 256);
|
||||
|
||||
for ($j = 0; $j < imagecolorstotal($im); $j++)
|
||||
{
|
||||
$color = imagecolorsforindex($im, $j);
|
||||
$gray = round(0.299 * $color['red'] + 0.587 * $color['green'] + 0.114 * $color['blue']);
|
||||
imagecolorset($im, $j, $gray, $gray, $gray);
|
||||
}
|
||||
imagecopymerge($res, $im, $i * $dims, $dims, 0, 0, imageSX($im), imageSY($im), 100);
|
||||
}
|
||||
|
||||
if (@imagejpeg($res, $outFile))
|
||||
CLI::write(sprintf(ERR_NONE, CLI::bold($outFile)), CLI::LOG_OK, true, true);
|
||||
else
|
||||
{
|
||||
$success = false;
|
||||
CLI::write('talentIcons - '.CLI::bold($outFile.'.jpg').' could not be written', CLI::LOG_ERROR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$success = false;
|
||||
CLI::write('talentIcons - image resource not created', CLI::LOG_ERROR);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
?>
|
||||
192
setup/tools/filegen/talentcalc.ss.php
Normal file
192
setup/tools/filegen/talentcalc.ss.php
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
// talents
|
||||
// i - int talentId (id of aowow_talent)
|
||||
// n - str name (spellname of aowow_spell for spellID = rank1)
|
||||
// m - int number of ranks (6+ are empty)
|
||||
// s - array:int spells to ranks (rank1, rank2, ..., rank5 of aowow_talent)
|
||||
// d - array:str description of spells
|
||||
// x - int column (col from aowow_talent)
|
||||
// y - int row (row of aowow_talent)
|
||||
// r - array:int on what the talent depends on: "r:[u, v]", u - nth talent in tree, v - required rank of u
|
||||
// f - array:int [pets only] creatureFamilies, that use this spell
|
||||
// t - array:str if the talent teaches a spell, this is the upper tooltip-table containing castTime, cost, cooldown
|
||||
// j - array of modifier-arrays per rank for the Profiler
|
||||
// tabs
|
||||
// n - name of the tab
|
||||
// t - array of talent-objects
|
||||
// f - array:int [pets only] creatureFamilies in that category
|
||||
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
protected $info = array(
|
||||
'talentcalc' => [[], CLISetup::ARGV_PARAM, 'Compiles talent tree data to file for the talent calculator tool.']
|
||||
);
|
||||
|
||||
protected $dbcSourceFiles = ['talenttab', 'talent', 'spell', 'creaturefamily', 'spellicon'];
|
||||
protected $setupAfter = [['spell'], []];
|
||||
protected $requiredDirs = ['datasets/'];
|
||||
protected $localized = true;
|
||||
|
||||
private $petFamIcons = [];
|
||||
private $tSpells = null;
|
||||
private $spellMods = [];
|
||||
|
||||
public function generate() : bool
|
||||
{
|
||||
// target direcotries are missing
|
||||
if (!$this->success)
|
||||
return false;
|
||||
|
||||
// my neighbour is noisy as fuck and my head hurts, so ..
|
||||
$this->petFamIcons = ['Ability_Druid_KingoftheJungle', 'Ability_Druid_DemoralizingRoar', 'Ability_EyeOfTheOwl']; // .. i've no idea where to fetch these from
|
||||
$this->spellMods = (new SpellList(array(['typeCat', -2], Cfg::get('SQL_LIMIT_NONE'))))->getProfilerMods();
|
||||
|
||||
$petIcons = Util::toJSON(DB::Aowow()->SelectCol('SELECT id AS ARRAY_KEY, LOWER(SUBSTRING_INDEX(iconString, "\\\\", -1)) AS iconString FROM dbc_creaturefamily WHERE petTalentType IN (0, 1, 2)'));
|
||||
|
||||
$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');
|
||||
$this->tSpells = new SpellList(array(['s.id', $tSpellIds], Cfg::get('SQL_LIMIT_NONE')));
|
||||
|
||||
foreach (CLISetup::$localeIds as $lId)
|
||||
{
|
||||
User::useLocale($lId);
|
||||
Lang::load($lId);
|
||||
|
||||
// TalentCalc
|
||||
for ($i = 1; (1 << ($i - 1)) < CLASS_MASK_ALL; $i++ )
|
||||
{
|
||||
if (!((1 << ($i - 1)) & CLASS_MASK_ALL))
|
||||
continue;
|
||||
|
||||
set_time_limit(20);
|
||||
|
||||
$file = 'datasets/'.User::$localeString.'/talents-'.$i;
|
||||
$toFile = '$WowheadTalentCalculator.registerClass('.$i.', '.Util::toJSON($this->buildTree(1 << ($i - 1))).')';
|
||||
|
||||
if (!CLISetup::writeFile($file, $toFile))
|
||||
$this->success = false;
|
||||
}
|
||||
|
||||
// PetCalc
|
||||
$toFile = "var g_pet_icons = ".$petIcons.";\n\n";
|
||||
$toFile .= 'var g_pet_talents = '.Util::toJSON($this->buildTree(0)).';';
|
||||
$file = 'datasets/'.User::$localeString.'/pet-talents';
|
||||
|
||||
if (!CLISetup::writeFile($file, $toFile))
|
||||
$this->success = false;
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function buildTree(int $classMask) : array
|
||||
{
|
||||
$petCategories = [];
|
||||
|
||||
// All "tabs" of a given class talent
|
||||
$tabs = DB::Aowow()->select('SELECT * FROM dbc_talenttab WHERE classMask = ?d ORDER BY `tabNumber`, `creatureFamilyMask`', $classMask);
|
||||
$result = [];
|
||||
|
||||
for ($tabIdx = 0; $tabIdx < count($tabs); $tabIdx++)
|
||||
{
|
||||
$talents = DB::Aowow()->select('SELECT t.id AS tId, t.*, IF(t.rank5, 5, IF(t.rank4, 4, IF(t.rank3, 3, IF(t.rank2, 2, 1)))) AS maxRank, s.name_loc0, s.name_loc2, s.name_loc3, s.name_loc4, s.name_loc6, s.name_loc8, LOWER(SUBSTRING_INDEX(si.iconPath, "\\\\", -1)) AS iconString FROM dbc_talent t, dbc_spell s, dbc_spellicon si WHERE si.`id` = s.`iconId` AND t.`tabId`= ?d AND s.`id` = t.`rank1` ORDER by t.`row`, t.`column`', $tabs[$tabIdx]['id']);
|
||||
$result[$tabIdx] = array(
|
||||
'n' => Util::localizedString($tabs[$tabIdx], 'name'),
|
||||
't' => []
|
||||
);
|
||||
|
||||
if (!$classMask)
|
||||
{
|
||||
$petFamId = log($tabs[$tabIdx]['creatureFamilyMask'], 2);
|
||||
$result[$tabIdx]['icon'] = $this->petFamIcons[$petFamId];
|
||||
$petCategories = DB::Aowow()->SelectCol('SELECT id AS ARRAY_KEY, categoryEnumID FROM dbc_creaturefamily WHERE petTalentType = ?d', $petFamId);
|
||||
$result[$tabIdx]['f'] = array_keys($petCategories);
|
||||
}
|
||||
|
||||
// talent dependencies go here
|
||||
$depLinks = [];
|
||||
$tNums = [];
|
||||
|
||||
for ($talentIdx = 0; $talentIdx < count($talents); $talentIdx++)
|
||||
{
|
||||
$tNums[$talents[$talentIdx]['tId']] = $talentIdx;
|
||||
|
||||
$talent = array(
|
||||
'i' => $talents[$talentIdx]['tId'], // talent id
|
||||
'n' => Util::localizedString($talents[$talentIdx], 'name'), // talent name
|
||||
'm' => $talents[$talentIdx]['maxRank'], // maxRank
|
||||
'd' => [], // [descriptions]
|
||||
's' => [], // [spellIds]
|
||||
'x' => $talents[$talentIdx]['column'], // col #
|
||||
'y' => $talents[$talentIdx]['row'], // row #
|
||||
'j' => [] // [spellMods] that are applied when used in profiler
|
||||
// 'r' => [] // [reqTalentId, reqRank] (can be omitted)
|
||||
// 't' => [] // talentspell tooltip (can be omitted)
|
||||
// 'f' => [] // [petFamilyIds] (can be omitted)
|
||||
);
|
||||
|
||||
if ($classMask)
|
||||
$talent['iconname'] = $talents[$talentIdx]['iconString'];
|
||||
|
||||
for ($itr = 0; $itr <= ($talent['m'] - 1); $itr++)
|
||||
{
|
||||
$spell = $talents[$talentIdx]['rank'.($itr + 1)];
|
||||
if (!$this->tSpells->getEntry($spell))
|
||||
continue;
|
||||
|
||||
$talent['d'][] = $this->tSpells->parseText()[0];
|
||||
$talent['s'][] = $talents[$talentIdx]['rank'.($itr + 1)];
|
||||
|
||||
if ($classMask && isset($this->spellMods[$spell]))
|
||||
if ($mod = $this->spellMods[$spell])
|
||||
$talent['j'][] = $mod;
|
||||
|
||||
if ($talents[$talentIdx]['talentSpell'])
|
||||
$talent['t'][] = $this->tSpells->getTalentHeadForCurrent();
|
||||
}
|
||||
|
||||
foreach ($petCategories as $k => $v)
|
||||
{
|
||||
// cant handle 64bit integer .. split
|
||||
if ($v >= 32 && ((1 << ($v - 32)) & $talents[$talentIdx]['petCategory2']))
|
||||
$talent['f'][] = $k;
|
||||
else if ($v < 32 && ((1 << $v) & $talents[$talentIdx]['petCategory1']))
|
||||
$talent['f'][] = $k;
|
||||
}
|
||||
|
||||
if ($talents[$talentIdx]['reqTalent'])
|
||||
{
|
||||
// we didn't encounter the required talent yet => create reference
|
||||
if (!isset($tNums[$talents[$talentIdx]['reqTalent']]))
|
||||
$depLinks[$talents[$talentIdx]['reqTalent']] = $talentIdx;
|
||||
|
||||
$talent['r'] = [$tNums[$talents[$talentIdx]['reqTalent']] ?? 0, $talents[$talentIdx]['reqRank'] + 1];
|
||||
}
|
||||
|
||||
$result[$tabIdx]['t'][$talentIdx] = $talent;
|
||||
|
||||
// If this talent is a reference, add it to the array of talent dependencies
|
||||
if (isset($depLinks[$talents[$talentIdx]['tId']]))
|
||||
{
|
||||
$result[$tabIdx]['t'][$depLinks[$talents[$talentIdx]['tId']]]['r'][0] = $talentIdx;
|
||||
unset($depLinks[$talents[$talentIdx]['tId']]);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all dependencies for which the talent has not been found
|
||||
foreach ($depLinks as $dep_link)
|
||||
unset($result[$tabIdx]['t'][$dep_link]['r']);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
107
setup/tools/filegen/talenticons.ss.php
Normal file
107
setup/tools/filegen/talenticons.ss.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
protected $info = array(
|
||||
'talenticons' => [[], CLISetup::ARGV_PARAM, 'Generates icon textures for the talent calculator tool.']
|
||||
);
|
||||
|
||||
protected $dbcSourceFiles = ['talenttab', 'talent', 'spell'];
|
||||
protected $setupAfter = [['icons', 'spell'], ['simpleimg']];
|
||||
protected $requiredDirs = ['static/images/wow/talents/icons', 'static/images/wow/hunterpettalents'];
|
||||
|
||||
private const ICON_SIZE = 36; // px
|
||||
|
||||
private $filenames = ['icons', 'warrior', 'paladin', 'hunter', 'rogue', 'priest', 'deathknight', 'shaman', 'mage', 'warlock', null, 'druid'];
|
||||
|
||||
public function generate() : bool
|
||||
{
|
||||
foreach ($this->filenames as $k => $v)
|
||||
{
|
||||
if (!$v)
|
||||
continue;
|
||||
|
||||
set_time_limit(10);
|
||||
|
||||
for ($tree = 0; $tree < 3; $tree++)
|
||||
{
|
||||
$what = $k ? 'classMask' : 'creatureFamilyMask';
|
||||
$set = $k ? 1 << ($k - 1) : 1 << $tree;
|
||||
$subset = $k ? $tree : 0;
|
||||
$path = $k ? 'talents/icons' : 'hunterpettalents';
|
||||
$outFile = 'static/images/wow/'.$path.'/'.$v.'_'.($tree + 1).'.jpg';
|
||||
$icons = DB::Aowow()->SelectCol(
|
||||
'SELECT ic.name AS iconString
|
||||
FROM ?_icons ic
|
||||
JOIN ?_spell s ON s.iconId = ic.id
|
||||
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 ASC, s.id DESC',
|
||||
$what, $set, $subset);
|
||||
|
||||
if (empty($icons))
|
||||
{
|
||||
CLI::write('[talenticons] - query for '.$v.' tree: '.$k.' returned empty', CLI::LOG_ERROR);
|
||||
$this->success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
$res = imageCreateTrueColor(count($icons) * self::ICON_SIZE, 2 * self::ICON_SIZE);
|
||||
if (!$res)
|
||||
{
|
||||
$this->success = false;
|
||||
CLI::write('[talenticons] - image resource not created', CLI::LOG_ERROR);
|
||||
continue;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < count($icons); $i++)
|
||||
{
|
||||
$imgFile = 'static/images/wow/icons/medium/'.strtolower($icons[$i]).'.jpg';
|
||||
if (!file_exists($imgFile))
|
||||
{
|
||||
CLI::write('[talenticons] - raw image '.CLI::bold($imgFile). ' not found', CLI::LOG_ERROR);
|
||||
$this->success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
$im = imagecreatefromjpeg($imgFile);
|
||||
|
||||
// colored
|
||||
imagecopymerge($res, $im, $i * self::ICON_SIZE, 0, 0, 0, imageSX($im), imageSY($im), 100);
|
||||
|
||||
// grayscale
|
||||
if (imageistruecolor($im))
|
||||
imagetruecolortopalette($im, false, 256);
|
||||
|
||||
for ($j = 0; $j < imagecolorstotal($im); $j++)
|
||||
{
|
||||
$color = imagecolorsforindex($im, $j);
|
||||
$gray = round(0.299 * $color['red'] + 0.587 * $color['green'] + 0.114 * $color['blue']);
|
||||
imagecolorset($im, $j, $gray, $gray, $gray);
|
||||
}
|
||||
imagecopymerge($res, $im, $i * self::ICON_SIZE, self::ICON_SIZE, 0, 0, imageSX($im), imageSY($im), 100);
|
||||
}
|
||||
|
||||
if (@imagejpeg($res, $outFile))
|
||||
CLI::write('[talenticons] '.sprintf(ERR_NONE, CLI::bold($outFile)), CLI::LOG_OK, true, true);
|
||||
else
|
||||
{
|
||||
$this->success = false;
|
||||
CLI::write('[talenticons] - '.CLI::bold($outFile.'.jpg').' could not be written', CLI::LOG_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
28
setup/tools/filegen/tooltips.ss.php
Normal file
28
setup/tools/filegen/tooltips.ss.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
use TrTemplateFile;
|
||||
|
||||
protected $info = array(
|
||||
'tooltips' => [[], CLISetup::ARGV_PARAM, 'Fills powered tooltips (static/widgets/power.js) with site variables.']
|
||||
);
|
||||
|
||||
protected $fileTemplateSrc = ['power.js.in'];
|
||||
protected $fileTemplateDest = ['static/widgets/power.js'];
|
||||
|
||||
public function generate() : bool
|
||||
{
|
||||
$this->templateFill();
|
||||
return $this->success;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -7,14 +7,17 @@ if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
// Creates 'weight-presets'-file
|
||||
// Creates 'weight-presets'-file
|
||||
CLISetup::registerSetup("build", new class extends SetupScript
|
||||
{
|
||||
protected $info = array(
|
||||
'weightpresets' => [[], CLISetup::ARGV_PARAM, 'Generates stat weight presets file for the item comparison tool.']
|
||||
);
|
||||
|
||||
function weightPresets()
|
||||
protected $requiredDirs = ['datasets/'];
|
||||
|
||||
public function generate() : bool
|
||||
{
|
||||
// check directory-structure
|
||||
if (!CLISetup::writeDir('datasets/'))
|
||||
return false;
|
||||
|
||||
$wtPresets = [];
|
||||
$scales = DB::Aowow()->select('SELECT id, name, icon, class FROM ?_account_weightscales WHERE userId = 0 ORDER BY class, id ASC');
|
||||
|
||||
@@ -24,7 +27,7 @@ if (!CLI)
|
||||
$wtPresets[$s['class']]['pve'][$s['name']] = array_merge(['__icon' => $s['icon']], $weights);
|
||||
else
|
||||
{
|
||||
CLI::write('WeightScale \''.CLI::bold($s['name']).'\' has no data set.', CLI::LOG_WARN);
|
||||
CLI::write('[weightpresets] Scale \''.CLI::bold($s['name']).'\' has no data set.', CLI::LOG_WARN);
|
||||
$wtPresets[$s['class']]['pve'][$s['name']] = ['__icon' => $s['icon']];
|
||||
}
|
||||
}
|
||||
@@ -37,4 +40,6 @@ if (!CLI)
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -9,17 +9,24 @@ if (!CLI)
|
||||
|
||||
trait TrDBCcopy
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->info = array(
|
||||
$this->command => [[], CLISetup::ARGV_PARAM, 'COPY: ' . $this->dbcSourceFiles[0] . '.dbc -> aowow_'.$this->command],
|
||||
);
|
||||
}
|
||||
|
||||
public function generate() : bool
|
||||
{
|
||||
if (!$this->dbcSourceFiles)
|
||||
{
|
||||
CLI::write(' SetupScript '.$this->command.' is set up for DBCcopy but has no source set!', CLI::LOG_ERROR);
|
||||
CLI::write('[sql] SetupScript '.$this->command.' is set up for DBCcopy but has no source set!', CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
else if (count($this->dbcSourceFiles) != 1)
|
||||
CLI::write(' SetupScript '.$this->command.' is set up for DBCcopy but has multiple sources set!', CLI::LOG_WARN);
|
||||
CLI::write('[sql] SetupScript '.$this->command.' is set up for DBCcopy but has multiple sources set!', CLI::LOG_WARN);
|
||||
|
||||
CLI::write('SqlGen::generate() - copying '.$this->dbcSourceFiles[0].'.dbc into aowow_'.$this->command);
|
||||
CLI::write('[sql] copying '.$this->dbcSourceFiles[0].'.dbc into aowow_'.$this->command);
|
||||
|
||||
$dbc = new DBC($this->dbcSourceFiles[0], ['temporary' => false, 'tableName' => 'aowow_'.$this->command]);
|
||||
if ($dbc->error)
|
||||
@@ -36,18 +43,18 @@ trait TrCustomData
|
||||
{
|
||||
$ok = true;
|
||||
$this->customData = $this->customData ?? [];
|
||||
if ($cd = DB::Aowow()->selectCol('SELECT `entry` AS ARRAY_KEY, `field` AS ARRAY_KEY2, `value` FROM ?_setup_custom_data WHERE `command` = ?', $this->command))
|
||||
if ($cd = DB::Aowow()->selectCol('SELECT `entry` AS ARRAY_KEY, `field` AS ARRAY_KEY2, `value` FROM ?_setup_custom_data WHERE `command` = ?', $this->getName()))
|
||||
$this->customData += $cd;
|
||||
|
||||
foreach ($this->customData as $id => $data)
|
||||
{
|
||||
try
|
||||
{
|
||||
DB::Aowow()->query('UPDATE ?_'.$this->command.' SET ?a WHERE id = ?d', $data, $id);
|
||||
DB::Aowow()->query('UPDATE ?_'.$this->getName().' SET ?a WHERE id = ?d', $data, $id);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
trigger_error('Custom Data for entry #'.$id.': '.$e->getMessage(), E_USER_ERROR);
|
||||
trigger_error('custom data for entry #'.$id.': '.$e->getMessage(), E_USER_ERROR);
|
||||
$ok = false;
|
||||
}
|
||||
}
|
||||
@@ -56,17 +63,351 @@ trait TrCustomData
|
||||
}
|
||||
}
|
||||
|
||||
trait TrTemplateFile
|
||||
{
|
||||
public function generate() : bool
|
||||
{
|
||||
$this->templateFill();
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function &templateCopy() : iterable
|
||||
{
|
||||
if (!$this->fileTemplateSrc || count($this->fileTemplateSrc) != count($this->fileTemplateDest))
|
||||
{
|
||||
CLI::write('[build] template file definitions missing or malformed', CLI::LOG_ERROR);
|
||||
$this->success = false;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->fileTemplateSrc as $idx => $srcFile)
|
||||
{
|
||||
$file = $this->fileTemplatePath.$srcFile;
|
||||
|
||||
if (!file_exists($file))
|
||||
{
|
||||
CLI::write('[build] template file is missing - '.CLI::bold($file), CLI::LOG_ERROR);
|
||||
$this->success = false;
|
||||
return;
|
||||
}
|
||||
|
||||
$content = file_get_contents($file);
|
||||
if (!$content)
|
||||
{
|
||||
CLI::write('[build] template file is not readable - '.CLI::bold($file), CLI::LOG_ERROR);
|
||||
$this->success = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// replace constants
|
||||
$content = Cfg::applyToString($content);
|
||||
|
||||
yield $content;
|
||||
|
||||
if (CLISetup::writeFile($this->fileTemplateDest[$idx], $content))
|
||||
continue;
|
||||
|
||||
$this->success = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private function templateFill() : void
|
||||
{
|
||||
foreach ($this->templateCopy() as &$content)
|
||||
{
|
||||
if (!$this->success) //templateCopy() fucked up somehow?
|
||||
return;
|
||||
|
||||
// PH format: /*setup:<setupFunc>*/
|
||||
if (preg_match_all('/\/\*setup:([\w\-_]+)\*\//i', $content, $m))
|
||||
{
|
||||
foreach ($m[1] as $func)
|
||||
{
|
||||
if (method_exists($this, $func))
|
||||
$content = str_replace('/*setup:'.$func.'*/', $this->$func(), $content);
|
||||
else
|
||||
{
|
||||
CLI::write('['.$this->getName().'] No function for was registered for placeholder '.$func.'().', CLI::LOG_ERROR);
|
||||
$this->success = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait TrImageProcessor
|
||||
{
|
||||
private $imgPath = '%sInterface/';
|
||||
private $status = '';
|
||||
private $maxExecTime = 30;
|
||||
|
||||
private static $GEN_IDX_SRC_PATH = 0; // php v8.0 make static > const
|
||||
private static $GEN_IDX_SRC_REAL = 1;
|
||||
private static $GEN_IDX_LOCALE = 2;
|
||||
private static $GEN_IDX_SRC_INFO = 3;
|
||||
private static $GEN_IDX_DEST_INFO = 4;
|
||||
|
||||
private static $JPEG_QUALITY = 85; // 0: worst - 100: best
|
||||
|
||||
private function checkSourceDirs() : bool
|
||||
{
|
||||
$outTblLen = 0;
|
||||
$foundCache = [];
|
||||
|
||||
foreach ($this->genSteps as $i => [$subDir, $realPaths, $localized, , ])
|
||||
{
|
||||
if ($realPaths)
|
||||
continue;
|
||||
|
||||
// multiple genSteps can require the same resource
|
||||
if (isset($foundCache[$subDir]))
|
||||
{
|
||||
$this->genSteps[$i][self::$GEN_IDX_SRC_REAL] = $foundCache[$subDir];
|
||||
continue;
|
||||
}
|
||||
|
||||
$outTblLen = max($outTblLen, strlen($subDir));
|
||||
|
||||
$path = $this->imgPath.$subDir;
|
||||
if ($p = CLISetup::filesInPathLocalized($path, $this->success, $localized))
|
||||
{
|
||||
$foundCache[$subDir] = $p;
|
||||
$this->genSteps[$i][self::$GEN_IDX_SRC_REAL] = $p; // pvp v7.3+ - make $realPaths areferene
|
||||
}
|
||||
else
|
||||
$this->success = false;
|
||||
}
|
||||
|
||||
$locList = [];
|
||||
foreach (CLISetup::$expectedPaths as $xp => $locId)
|
||||
if (in_array($locId, CLISetup::$localeIds))
|
||||
$locList[] = $xp;
|
||||
|
||||
CLI::write('[img-proc] required resources overview:', CLI::LOG_INFO);
|
||||
|
||||
$foundCache = [];
|
||||
foreach ($this->genSteps as [$subDir, $realPaths, $localized, , ])
|
||||
{
|
||||
// one line per unique resource
|
||||
if (isset($foundCache[$subDir]))
|
||||
continue;
|
||||
|
||||
$foundCache[$subDir] = true;
|
||||
|
||||
if (!$realPaths)
|
||||
{
|
||||
CLI::write(CLI::red('MISSING').' - '.str_pad($subDir, 14).' @ '.sprintf($this->imgPath, '['.implode('/,', $locList).'/]').$subDir);
|
||||
$this->success = false;
|
||||
}
|
||||
else if ($localized)
|
||||
{
|
||||
$foundLoc = [];
|
||||
foreach (CLISetup::$expectedPaths as $xp => $lId)
|
||||
if (in_array($lId, CLISetup::$localeIds))
|
||||
if (isset($realPaths[$lId]) && ($n = stripos($realPaths[$lId], '/'.$xp.'/')))
|
||||
$foundLoc[$lId] = substr($realPaths[$lId], $n + 1, 4);
|
||||
|
||||
if ($diff = array_diff(CLISetup::$localeIds, array_keys($foundLoc)))
|
||||
{
|
||||
$buff = [];
|
||||
foreach ($diff as $d)
|
||||
$buff[] = CLI::red(Util::$localeStrings[$d]);
|
||||
foreach ($foundLoc as $str)
|
||||
$buff[] = CLI::green($str);
|
||||
|
||||
CLI::write(CLI::yellow('PARTIAL').' - '.str_pad($subDir, $outTblLen).' @ '.sprintf($this->imgPath, '['.implode('/,', $buff).'/]').$subDir);
|
||||
}
|
||||
else
|
||||
CLI::write(CLI::green('FOUND ').' - '.str_pad($subDir, $outTblLen).' @ '.sprintf($this->imgPath, '['.implode('/,', $foundLoc).'/]').$subDir);
|
||||
}
|
||||
else
|
||||
CLI::write(CLI::green('FOUND ').' - '.str_pad($subDir, $outTblLen).' @ '.reset($realPaths));
|
||||
}
|
||||
|
||||
CLI::write();
|
||||
|
||||
// if not localized directly return result
|
||||
foreach ($this->genSteps as $i => [$subDir, $realPaths, $localized, , ])
|
||||
if (!$localized)
|
||||
$this->genSteps[$i][self::$GEN_IDX_SRC_REAL] = reset($realPaths);
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
// 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
|
||||
private function loadImageFile(string $path) // : ?GdImage
|
||||
{
|
||||
$result = null;
|
||||
$path = preg_replace('/\.(png|blp)$/i', '', $path);
|
||||
|
||||
$file = $path.'.png';
|
||||
if (CLISetup::fileExists($file))
|
||||
{
|
||||
CLI::write('[img-proc] manually converted png file present for '.$file, CLI::LOG_INFO);
|
||||
$result = imagecreatefrompng($file);
|
||||
}
|
||||
|
||||
if (!$result)
|
||||
{
|
||||
$file = $path.'.blp';
|
||||
if (CLISetup::fileExists($file))
|
||||
$result = imagecreatefromblp($file);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function writeImageFile(/* GdImage */ $src, string $outFile, array $srcDims, array $destDims) : bool
|
||||
{
|
||||
$success = false;
|
||||
$outRes = imagecreatetruecolor($destDims['w'], $destDims['h']);
|
||||
$ext = substr($outFile, -3, 3);
|
||||
|
||||
imagesavealpha($outRes, true);
|
||||
if ($ext == 'png')
|
||||
{
|
||||
imagealphablending($outRes, false);
|
||||
$transparentindex = imagecolorallocatealpha($outRes, 255, 255, 255, 127);
|
||||
imagefill($outRes, 0, 0, $transparentindex);
|
||||
}
|
||||
|
||||
imagecopyresampled($outRes, $src, $destDims['x'], $destDims['x'], $srcDims['x'], $srcDims['y'], $destDims['w'], $destDims['h'], $srcDims['w'], $srcDims['h']);
|
||||
|
||||
switch ($ext)
|
||||
{
|
||||
case 'jpg':
|
||||
$success = imagejpeg($outRes, $outFile, self::$JPEG_QUALITY);
|
||||
break;
|
||||
case 'gif':
|
||||
$success = imagegif($outRes, $outFile);
|
||||
break;
|
||||
case 'png':
|
||||
$success = imagepng($outRes, $outFile);
|
||||
break;
|
||||
default:
|
||||
CLI::write('[img-proc] '.$this->status.' - unsupported file fromat: '.$ext, CLI::LOG_WARN);
|
||||
}
|
||||
|
||||
imagedestroy($outRes);
|
||||
|
||||
if ($success)
|
||||
{
|
||||
chmod($outFile, Util::FILE_ACCESS);
|
||||
CLI::write('[img-proc] '.$this->status.' - image '.$outFile.' written', CLI::LOG_OK, true, true);
|
||||
}
|
||||
else
|
||||
CLI::write('[img-proc] '.$this->status.' - could not create image '.$outFile, CLI::LOG_ERROR);
|
||||
|
||||
return $success;
|
||||
}
|
||||
}
|
||||
|
||||
trait TrComplexImage
|
||||
{
|
||||
use TrImageProcessor { TrImageProcessor::writeImageFile as _writeImageFile; }
|
||||
|
||||
private function writeImageFile(/* GdImage */ $src, string $outFile, int $w, int $h) : bool
|
||||
{
|
||||
$srcDims = array(
|
||||
'x' => 0,
|
||||
'y' => 0,
|
||||
'w' => imagesx($src),
|
||||
'h' => imagesy($src)
|
||||
);
|
||||
$destDims = array(
|
||||
'x' => 0,
|
||||
'y' => 0,
|
||||
'w' => $w,
|
||||
'h' => $h
|
||||
);
|
||||
|
||||
return $this->_writeImageFile($src, $outFile, $srcDims, $destDims);
|
||||
}
|
||||
|
||||
private function createAlphaImage(int $w, int $h) //: ?GdImage
|
||||
{
|
||||
$img = imagecreatetruecolor($w, $h);
|
||||
if (!$img)
|
||||
return null;
|
||||
|
||||
imagesavealpha($img, true);
|
||||
imagealphablending($img, false);
|
||||
|
||||
$bgColor = imagecolorallocatealpha($img, 0, 0, 0, 127);
|
||||
imagefilledrectangle($img, 0, 0, imagesx($img) - 1, imagesy($img) - 1, $bgColor);
|
||||
|
||||
imagecolortransparent($img, $bgColor);
|
||||
imagealphablending($img, true);
|
||||
|
||||
imagecolordeallocate($img, $bgColor);
|
||||
|
||||
return $img;
|
||||
}
|
||||
|
||||
private function assembleImage(string $baseName, array $tileData, int $destW, int $destH) //: ?GdImage
|
||||
{
|
||||
$dest = imagecreatetruecolor($destW, $destH);
|
||||
if (!$dest)
|
||||
return null;
|
||||
|
||||
imagesavealpha($dest, true);
|
||||
imagealphablending($dest, false);
|
||||
|
||||
$tileH = $destH;
|
||||
foreach ($tileData as $y => $row)
|
||||
{
|
||||
$tileW = $destW;
|
||||
foreach ($row as $x => $suffix)
|
||||
{
|
||||
$src = $this->loadImageFile($baseName.$suffix);
|
||||
if (!$src)
|
||||
{
|
||||
CLI::write('[img-proc-c] tile '.$baseName.$suffix.'.blp missing.', CLI::LOG_ERROR);
|
||||
unset($dest);
|
||||
return null;
|
||||
}
|
||||
|
||||
imagecopyresampled($dest, $src, 256 * $x, 256 * $y, 0, 0, min($tileW, 256), min($tileH, 256), min($tileW, 256), min($tileH, 256));
|
||||
$tileW -= 256;
|
||||
|
||||
unset($src);
|
||||
}
|
||||
$tileH -= 256;
|
||||
}
|
||||
|
||||
return $dest;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SetupScript
|
||||
{
|
||||
protected $fileTemplatePath = '';
|
||||
protected $fileTemplateFile = '';
|
||||
// FileGen
|
||||
protected $requiredDirs = [];
|
||||
protected $fileTemplateDest = [];
|
||||
protected $fileTemplatePath = 'setup/tools/filegen/templates/';
|
||||
protected $fileTemplateSrc = [];
|
||||
|
||||
protected $tblDependencyAowow = [];
|
||||
protected $tblDependencyTC = [];
|
||||
// SQLGen
|
||||
protected $result = '';
|
||||
|
||||
protected $dbcSourceFiles = [];
|
||||
// FileGen + SQLGen
|
||||
protected $dbcSourceFiles = []; // relies on these dbc files. Read into db if related table is missing
|
||||
protected $worldDependency = []; // query when this table changed (--sync command)
|
||||
|
||||
protected $info = []; // arr: 0 => self, n => genSteps cmd => [[arr<str>:optionalArgs], int:argFlags, str:description]
|
||||
protected $setupAfter = [[], []]; // [[sqlgen], [filegen]] used to sort scripts that rely on each other being executed in the right order (script names are not nessecarily the same as their table names)
|
||||
|
||||
protected $success = true;
|
||||
protected $localized = false; // push locale directories onto $requiredDirs?
|
||||
protected $useGlobalStrings = false; // uses data from interface/framexml/globalstrings.lua
|
||||
|
||||
public $isOptional = false; // not a part of the setup chain
|
||||
|
||||
// abstract protected $command;
|
||||
|
||||
abstract public function generate() : bool;
|
||||
|
||||
@@ -75,23 +416,107 @@ abstract class SetupScript
|
||||
return $this->dbcSourceFiles;
|
||||
}
|
||||
|
||||
public function getDependencies(bool $aowow) : array
|
||||
public function getSelfDependencies() : array
|
||||
{
|
||||
return $aowow ? $this->tblDependencyAowow : $this->tblDependencyTC;
|
||||
return $this->setupAfter;
|
||||
}
|
||||
|
||||
public function getRemoteDependencies() : array
|
||||
{
|
||||
return $this->worldDependency;
|
||||
}
|
||||
|
||||
public function getName() : string
|
||||
{
|
||||
return $this->command;
|
||||
reset($this->info);
|
||||
return key($this->info);
|
||||
}
|
||||
|
||||
public function getInfo() // : string|int
|
||||
{
|
||||
// info: name => [param, paramFlags, description]
|
||||
return (reset($this->info)[2] ?? '').($this->isOptional ? ' - '.Cli::yellow('[omitted by setup]') : '');
|
||||
}
|
||||
|
||||
public function getSubCommands() : array
|
||||
{
|
||||
$sub = [];
|
||||
|
||||
if (count($this->info) > 1)
|
||||
$sub = array_slice($this->info, 1, 10, true);
|
||||
|
||||
return $sub;
|
||||
}
|
||||
|
||||
public function getRequiredDirs(): array
|
||||
{
|
||||
return $this->requiredDirs;
|
||||
}
|
||||
|
||||
public function fulfillRequirements() : bool
|
||||
{
|
||||
// create directory structure
|
||||
$newDirs = 0;
|
||||
$existed = false;
|
||||
foreach ($this->getRequiredDirs() as $dir)
|
||||
{
|
||||
$dirs = [];
|
||||
if (!$this->localized)
|
||||
$dirs[] = $dir;
|
||||
else
|
||||
foreach (CLISetup::$locales as $str)
|
||||
$dirs[] = $dir . $str . '/';
|
||||
|
||||
foreach ($dirs as $d)
|
||||
{
|
||||
if (!CLISetup::writeDir($d, $existed))
|
||||
{
|
||||
CLI::write('[build] could not create directory: '.CLI::bold($d), CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$newDirs += ($existed ? 0 : 1);
|
||||
}
|
||||
|
||||
if ($newDirs)
|
||||
CLI::write('[build] created '.$newDirs.' extra paths');
|
||||
|
||||
// load DBC files
|
||||
if (!in_array('TrDBCcopy', class_uses($this)))
|
||||
{
|
||||
foreach ($this->getRequiredDBCs() as $req)
|
||||
{
|
||||
if (CLISetup::loadDBC($req))
|
||||
continue;
|
||||
|
||||
CLI::write('[sql/build] '. $this->getName() . ' is missing dbc file ' . $req . '. Skipping...', CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->useGlobalStrings)
|
||||
if (!CLISetup::loadGlobalStrings())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function writeCLIHelp() : bool
|
||||
{
|
||||
// CLI::write('example info', -1, false); // some info
|
||||
// CLI::write(); // empty new line
|
||||
// return true; // help was provided, skip help in parent
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function reapplyCCFlags(string $tbl, int $type) : void
|
||||
{
|
||||
// reaply flags for community content as these are lost when the table is rebuild
|
||||
// reapply flags for community content as these are lost when the table is rebuild
|
||||
|
||||
if (preg_match('/[^a-z]/i', $tbl))
|
||||
if (preg_match('/\W/i', $tbl))
|
||||
{
|
||||
trigger_error('SetupScript::reapplyCCFlags() - invalid table name');
|
||||
trigger_error('[sql] reapplyCCFlags() - invalid table name');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -101,4 +526,4 @@ abstract class SetupScript
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -1,256 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
class SqlGen
|
||||
{
|
||||
const MODE_NORMAL = 1;
|
||||
const MODE_FIRSTRUN = 2;
|
||||
const MODE_UPDATE = 3;
|
||||
|
||||
private static $mode = 0;
|
||||
|
||||
private static $tables = [];
|
||||
private static $tmpStore = [];
|
||||
|
||||
public static $subScripts = [];
|
||||
|
||||
public static $defaultExecTime = 30;
|
||||
public static $sqlBatchSize = 1000;
|
||||
|
||||
public static function init(int $mode = self::MODE_NORMAL, array $updScripts = []) : bool
|
||||
{
|
||||
self::$defaultExecTime = ini_get('max_execution_time');
|
||||
self::$mode = $mode;
|
||||
|
||||
if (!CLISetup::$localeIds)
|
||||
{
|
||||
CLI::write('No valid locale specified. Check your config or --locales parameter, if used', CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
// register subscripts
|
||||
foreach (glob('setup/tools/sqlgen/*.func.php') as $file)
|
||||
include_once $file;
|
||||
|
||||
while (self::$tmpStore)
|
||||
{
|
||||
$nDepsMissing = count(self::$tmpStore);
|
||||
|
||||
foreach (self::$tmpStore as $idx => $ts)
|
||||
{
|
||||
$depsOK = true;
|
||||
foreach ($ts->getDependencies(true) as $d)
|
||||
{
|
||||
if (isset(self::$tables[$d]))
|
||||
continue;
|
||||
|
||||
$depsOK = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if ($depsOK)
|
||||
{
|
||||
if (isset(self::$tables[$ts->getName()]))
|
||||
{
|
||||
CLI::write('a SetupScript named '.CLI::bold($ts->getName()).' was already registered. Skipping...', CLI::LOG_WARN);
|
||||
unset(self::$tmpStore[$idx]);
|
||||
continue;
|
||||
}
|
||||
|
||||
self::$tables[$ts->getName()] = $ts;
|
||||
unset(self::$tmpStore[$idx]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($nDepsMissing == count(self::$tmpStore))
|
||||
{
|
||||
CLI::write('the following SetupScripts have unresolved dependencies and have not been registered:', CLI::LOG_ERROR);
|
||||
foreach (self::$tmpStore as $ts)
|
||||
CLI::write(' * '.CLI::bold($ts->getName()).' => '.implode(', ', $ts->getDependencies(true)));
|
||||
|
||||
self::$tmpStore = [];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// handle command prompts
|
||||
if (!self::handleCLIOpts($doScripts) && !$updScripts)
|
||||
return false;
|
||||
|
||||
// check passed subscript names; limit to real scriptNames
|
||||
self::$subScripts = array_keys(self::$tables);
|
||||
if ($doScripts || $updScripts)
|
||||
self::$subScripts = array_intersect($doScripts ?: $updScripts, self::$subScripts);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function register(SetupScript $ssRef) : void
|
||||
{
|
||||
// if dependencies haven't been stored yet, put aside for later use
|
||||
foreach ($ssRef->getDependencies(true) as $d)
|
||||
{
|
||||
if (isset(self::$tables[$d]))
|
||||
continue;
|
||||
|
||||
self::$tmpStore[] = $ssRef;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset(self::$tables[$ssRef->getName()]))
|
||||
{
|
||||
CLI::write('a SetupScript named '.CLI::bold($ssRef->getName()).' was already registered. Skipping...', CLI::LOG_WARN);
|
||||
return;
|
||||
}
|
||||
|
||||
self::$tables[$ssRef->getName()] = $ssRef;
|
||||
|
||||
// recheck temp stored dependencies
|
||||
foreach (self::$tmpStore as $idx => $ts)
|
||||
{
|
||||
$depsOK = true;
|
||||
foreach ($ts->getDependencies(true) as $d)
|
||||
{
|
||||
if (isset(self::$tables[$d]))
|
||||
continue;
|
||||
|
||||
$depsOK = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if ($depsOK)
|
||||
{
|
||||
self::$tables[$ts->getName()] = $ts;
|
||||
unset(self::$tmpStore[$idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static function handleCLIOpts(?array &$doTbls) : bool
|
||||
{
|
||||
$doTbls = [];
|
||||
|
||||
if (CLISetup::getOpt('help') && self::$mode == self::MODE_NORMAL)
|
||||
{
|
||||
self::printCLIHelp();
|
||||
return false;
|
||||
}
|
||||
|
||||
// required subScripts
|
||||
if ($sync = CLISetup::getOpt('sync'))
|
||||
{
|
||||
foreach (self::$tables as $name => &$ssRef)
|
||||
if (array_intersect($sync, $ssRef->getDependencies(false)))
|
||||
$doTbls[] = $name;
|
||||
|
||||
// recursive dependencies
|
||||
foreach (self::$tables as $name => &$ssRef)
|
||||
if (array_intersect($sync, $ssRef->getDependencies(true)))
|
||||
$doTbls[] = $name;
|
||||
|
||||
if (!$doTbls)
|
||||
return false;
|
||||
|
||||
$doTbls = array_unique($doTbls);
|
||||
return true;
|
||||
}
|
||||
else if (is_array($_ = CLISetup::getOpt('sql')))
|
||||
{
|
||||
$doTbls = $_;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function printCLIHelp() : void
|
||||
{
|
||||
CLI::write();
|
||||
CLI::write(' usage: php aowow --sql=<subScriptList,> [--mpqDataDir: --locales:]', -1, false);
|
||||
CLI::write();
|
||||
CLI::write(' Regenerates DB table content for a given subScript. Dependencies are taken into account by the triggered calls of --sync and --update', -1, false);
|
||||
|
||||
$lines = [['available subScripts', 'TC dependencies', 'AoWoW dependencies']];
|
||||
foreach (self::$tables as $tbl => &$ssRef)
|
||||
{
|
||||
$aoRef = $ssRef->getDependencies(true);
|
||||
$len = 0;
|
||||
$first = true;
|
||||
|
||||
$row = [" * ".$tbl, '', ''];
|
||||
|
||||
if ($tc = $ssRef->getDependencies(false))
|
||||
{
|
||||
$len = 0;
|
||||
foreach ($tc as $t)
|
||||
{
|
||||
$n = strlen($t) + 1;
|
||||
if ($n + $len > 60)
|
||||
{
|
||||
// max 2 tables, no multi-row shenanigans required
|
||||
if ($first && $aoRef)
|
||||
$row[2] = implode(' ', $aoRef);
|
||||
|
||||
$lines[] = $row;
|
||||
$row = ['', '', ''];
|
||||
$len = $n;
|
||||
$first = false;
|
||||
}
|
||||
else
|
||||
$len += $n;
|
||||
|
||||
$row[1] .= $t." ";
|
||||
}
|
||||
}
|
||||
|
||||
if ($first && $aoRef)
|
||||
$row[2] = implode(' ', $aoRef);
|
||||
|
||||
$lines[] = $row;
|
||||
}
|
||||
|
||||
CLI::writeTable($lines);
|
||||
}
|
||||
|
||||
public static function generate(string $tableName, array $updateIds = []) : bool
|
||||
{
|
||||
if (!isset(self::$tables[$tableName]))
|
||||
{
|
||||
CLI::write('SqlGen::generate - invalid table given', CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
$ssRef = &self::$tables[$tableName];
|
||||
|
||||
CLI::write('SqlGen::generate() - filling aowow_'.$tableName.' with data');
|
||||
|
||||
// check for required auxiliary DBC files
|
||||
if (!in_array('TrDBCcopy', class_uses($ssRef)))
|
||||
foreach ($ssRef->getRequiredDBCs() as $req)
|
||||
if (!CLISetup::loadDBC($req))
|
||||
return false;
|
||||
|
||||
if ($ssRef->generate($updateIds))
|
||||
{
|
||||
if (method_exists($ssRef, 'applyCustomData'))
|
||||
return $ssRef->applyCustomData();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function getMode() : int
|
||||
{
|
||||
return self::$mode;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,132 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
{
|
||||
use TrCustomData; // import custom data from DB
|
||||
|
||||
protected $command = 'achievement';
|
||||
|
||||
protected $tblDependencyAowow = ['icons'];
|
||||
protected $tblDependencyTC = ['dbc_achievement', 'disables'];
|
||||
protected $dbcSourceFiles = ['achievement_category', 'achievement', 'spellicon'];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
/**************/
|
||||
/* categories */
|
||||
/**************/
|
||||
|
||||
CLI::write(' - resolving categories');
|
||||
|
||||
DB::Aowow()->query('REPLACE INTO ?_achievementcategory SELECT ac.id, IFNULL(ac.parentcategory, 0), IFNULL(ac1.parentcategory, 0)
|
||||
FROM dbc_achievement_category ac LEFT JOIN dbc_achievement_category ac1 ON ac1.id = ac.parentCategory');
|
||||
|
||||
/************/
|
||||
/* dbc data */
|
||||
/************/
|
||||
|
||||
CLI::write(' - basic dbc data');
|
||||
|
||||
DB::Aowow()->query('
|
||||
REPLACE INTO
|
||||
?_achievement
|
||||
SELECT
|
||||
a.id,
|
||||
2 - a.faction,
|
||||
a.map,
|
||||
0,
|
||||
0,
|
||||
a.category,
|
||||
ac.parentCategory,
|
||||
a.points,
|
||||
a.orderInGroup,
|
||||
IFNULL(i.id, 0),
|
||||
a.iconId,
|
||||
a.flags,
|
||||
a.reqCriteriaCount,
|
||||
a.refAchievement,
|
||||
0,
|
||||
0,
|
||||
a.name_loc0, a.name_loc2, a.name_loc3, a.name_loc4, a.name_loc6, a.name_loc8,
|
||||
a.description_loc0, a.description_loc2, a.description_loc3, a.description_loc4, a.description_loc6, a.description_loc8,
|
||||
a.reward_loc0, a.reward_loc2, a.reward_loc3, a.reward_loc4, a.reward_loc6, a.reward_loc8
|
||||
FROM
|
||||
dbc_achievement a
|
||||
LEFT JOIN
|
||||
dbc_achievement_category ac ON ac.id = a.category
|
||||
LEFT JOIN
|
||||
dbc_spellicon si ON si.id = a.iconId
|
||||
LEFT JOIN
|
||||
?_icons i ON LOWER(SUBSTRING_INDEX(si.iconPath, "\\\\", -1)) = i.name
|
||||
{ WHERE a.id IN (?a) }
|
||||
', $ids ?: DBSIMPLE_SKIP);
|
||||
|
||||
|
||||
/*******************/
|
||||
/* serverside data */
|
||||
/*******************/
|
||||
|
||||
CLI::write(' - serverside achievement data');
|
||||
|
||||
$serverAchievements = DB::World()->select('SELECT ID, IF(requiredFaction = -1, 3, IF(requiredFaction = 0, 2, 1)) AS "faction", mapID, points, flags, count, refAchievement FROM achievement_dbc{ WHERE id IN (?a)}',
|
||||
$ids ?: DBSIMPLE_SKIP
|
||||
);
|
||||
foreach ($serverAchievements as $sa)
|
||||
DB::Aowow()->query('REPLACE INTO ?_achievement (id, faction, map, points, flags, reqCriteriaCount, refAchievement, cuFlags, name_loc0, name_loc2, name_loc3, name_loc4, name_loc6, name_loc8) VALUES (?d, ?d, ?d, ?d, ?d, ?d, ?d, ?d, ?, ?, ?, ?, ?, ?)',
|
||||
$sa['ID'], $sa['faction'], $sa['mapID'], $sa['points'], $sa['flags'], $sa['count'], $sa['refAchievement'], CUSTOM_SERVERSIDE,
|
||||
'Serverside - #'.$sa['ID'], 'Serverside - #'.$sa['ID'], 'Serverside - #'.$sa['ID'], 'Serverside - #'.$sa['ID'], 'Serverside - #'.$sa['ID'], 'Serverside - #'.$sa['ID']
|
||||
);
|
||||
|
||||
|
||||
/********************************/
|
||||
/* create chain of achievements */
|
||||
/********************************/
|
||||
|
||||
CLI::write(' - linking achievements to chain');
|
||||
|
||||
$chainIdx = 0;
|
||||
$parents = DB::Aowow()->selectCol('SELECT a.id FROM dbc_achievement a JOIN dbc_achievement b ON b.previous = a.id WHERE a.previous = 0');
|
||||
foreach ($parents as $chainId => $next)
|
||||
{
|
||||
$tree = [null, $next];
|
||||
while ($next = DB::Aowow()->selectCell('SELECT id FROM dbc_achievement WHERE previous = ?d', $next))
|
||||
$tree[] = $next;
|
||||
|
||||
foreach ($tree as $idx => $aId)
|
||||
{
|
||||
if (!$aId)
|
||||
continue;
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_achievement SET cuFlags = cuFlags | ?d, chainId = ?d, chainPos = ?d WHERE id = ?d',
|
||||
$idx == 1 ? ACHIEVEMENT_CU_FIRST_SERIES : (count($tree) == $idx + 1 ? ACHIEVEMENT_CU_LAST_SERIES : 0),
|
||||
$chainId + 1,
|
||||
$idx,
|
||||
$aId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************/
|
||||
/* applying disables */
|
||||
/*********************/
|
||||
|
||||
CLI::write(' - disabling disabled achievements from table disables');
|
||||
|
||||
if ($criteria = DB::World()->selectCol('SELECT entry FROM disables WHERE sourceType = 4'))
|
||||
DB::Aowow()->query('UPDATE aowow_achievement a JOIN aowow_achievementcriteria ac ON a.id = ac.refAchievementId SET a.cuFlags = ?d WHERE ac.id IN (?a)', CUSTOM_DISABLED, $criteria);
|
||||
|
||||
$this->reapplyCCFlags('achievement', Type::ACHIEVEMENT);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
138
setup/tools/sqlgen/achievement.ss.php
Normal file
138
setup/tools/sqlgen/achievement.ss.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
CLISetup::registerSetup('sql', new class extends SetupScript
|
||||
{
|
||||
use TrCustomData; // import custom data from DB
|
||||
|
||||
protected $info = array(
|
||||
'achievement' => [[], CLISetup::ARGV_PARAM, 'Compiles data for type: Achievement from dbc and world db.']
|
||||
);
|
||||
|
||||
protected $dbcSourceFiles = ['achievement_category', 'achievement', 'spellicon'];
|
||||
protected $worldDependency = ['dbc_achievement', 'disables'];
|
||||
protected $setupAfter = [['icons'], []];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
DB::Aowow()->query('TRUNCATE ?_achievement');
|
||||
DB::Aowow()->query('TRUNCATE ?_achievementcategory');
|
||||
|
||||
/**************/
|
||||
/* categories */
|
||||
/**************/
|
||||
|
||||
CLI::write('[achievement] - resolving categories');
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_achievementcategory SELECT ac.id, GREATEST(ac.parentcategory, 0), GREATEST(IFNULL(ac1.parentcategory, 0), 0) FROM dbc_achievement_category ac LEFT JOIN dbc_achievement_category ac1 ON ac1.id = ac.parentCategory');
|
||||
|
||||
/************/
|
||||
/* dbc data */
|
||||
/************/
|
||||
|
||||
CLI::write('[achievement] - basic dbc data');
|
||||
|
||||
DB::Aowow()->query(
|
||||
'INSERT INTO ?_achievement
|
||||
SELECT a.id,
|
||||
2 - a.faction,
|
||||
a.map,
|
||||
0,
|
||||
0,
|
||||
a.category,
|
||||
ac.parentCategory,
|
||||
a.points,
|
||||
a.orderInGroup,
|
||||
IFNULL(i.id, 0),
|
||||
a.iconId,
|
||||
a.flags,
|
||||
a.reqCriteriaCount,
|
||||
a.refAchievement,
|
||||
0,
|
||||
0,
|
||||
a.name_loc0, a.name_loc2, a.name_loc3, a.name_loc4, a.name_loc6, a.name_loc8,
|
||||
a.description_loc0, a.description_loc2, a.description_loc3, a.description_loc4, a.description_loc6, a.description_loc8,
|
||||
a.reward_loc0, a.reward_loc2, a.reward_loc3, a.reward_loc4, a.reward_loc6, a.reward_loc8
|
||||
FROM dbc_achievement a
|
||||
LEFT JOIN dbc_achievement_category ac ON ac.id = a.category
|
||||
LEFT JOIN dbc_spellicon si ON si.id = a.iconId
|
||||
LEFT JOIN ?_icons i ON LOWER(SUBSTRING_INDEX(si.iconPath, "\\\\", -1)) = i.name
|
||||
{ WHERE a.id IN (?a) }',
|
||||
$ids ?: DBSIMPLE_SKIP
|
||||
);
|
||||
|
||||
|
||||
/*******************/
|
||||
/* serverside data */
|
||||
/*******************/
|
||||
|
||||
CLI::write('[achievement] - serverside achievement data');
|
||||
|
||||
$serverAchievements = DB::World()->select('SELECT ID AS "id", IF(requiredFaction = -1, 3, IF(requiredFaction = 0, 2, 1)) AS "faction", mapID AS "map", points, flags, count AS "reqCriteriaCount", refAchievement FROM achievement_dbc{ WHERE id IN (?a)}',
|
||||
$ids ?: DBSIMPLE_SKIP
|
||||
);
|
||||
|
||||
foreach ($serverAchievements as &$sa)
|
||||
{
|
||||
$sa['cuFlags'] = CUSTOM_SERVERSIDE;
|
||||
foreach (Util::$localeStrings as $i => $_)
|
||||
if ($_)
|
||||
$sa['name_loc'.$i] = 'Serverside - #'.$sa['id'];
|
||||
}
|
||||
|
||||
unset($sa);
|
||||
|
||||
foreach ($serverAchievements as $sa)
|
||||
DB::Aowow()->query('INSERT INTO ?_achievement (?#) VALUES (?a)', array_keys($sa), array_values($sa));
|
||||
|
||||
|
||||
/********************************/
|
||||
/* create chain of achievements */
|
||||
/********************************/
|
||||
|
||||
CLI::write('[achievement] - linking achievements to chain');
|
||||
|
||||
$parents = DB::Aowow()->selectCol('SELECT a.id FROM dbc_achievement a JOIN dbc_achievement b ON b.previous = a.id WHERE a.previous = 0');
|
||||
foreach ($parents as $chainId => $next)
|
||||
{
|
||||
$tree = [null, $next];
|
||||
while ($next = DB::Aowow()->selectCell('SELECT id FROM dbc_achievement WHERE previous = ?d', $next))
|
||||
$tree[] = $next;
|
||||
|
||||
foreach ($tree as $idx => $aId)
|
||||
{
|
||||
if (!$aId)
|
||||
continue;
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_achievement SET cuFlags = cuFlags | ?d, chainId = ?d, chainPos = ?d WHERE id = ?d',
|
||||
$idx == 1 ? ACHIEVEMENT_CU_FIRST_SERIES : (count($tree) == $idx + 1 ? ACHIEVEMENT_CU_LAST_SERIES : 0),
|
||||
$chainId + 1,
|
||||
$idx,
|
||||
$aId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************/
|
||||
/* applying disables */
|
||||
/*********************/
|
||||
|
||||
CLI::write('[achievement] - disabling disabled achievements from table disables');
|
||||
|
||||
if ($criteria = DB::World()->selectCol('SELECT entry FROM disables WHERE sourceType = 4'))
|
||||
DB::Aowow()->query('UPDATE ?_achievement a JOIN ?_achievementcriteria ac ON a.id = ac.refAchievementId SET a.cuFlags = ?d WHERE ac.id IN (?a)', CUSTOM_DISABLED, $criteria);
|
||||
|
||||
$this->reapplyCCFlags('achievement', Type::ACHIEVEMENT);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
{
|
||||
use TrDBCcopy;
|
||||
|
||||
protected $command = 'achievementcriteria';
|
||||
protected $dbcSourceFiles = ['achievement_criteria'];
|
||||
});
|
||||
|
||||
?>
|
||||
18
setup/tools/sqlgen/achievementcriteria.ss.php
Normal file
18
setup/tools/sqlgen/achievementcriteria.ss.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
CLISetup::registerSetup('sql', new class extends SetupScript
|
||||
{
|
||||
use TrDBCcopy;
|
||||
|
||||
protected $command = 'achievementcriteria';
|
||||
protected $dbcSourceFiles = ['achievement_criteria'];
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -7,12 +7,15 @@ if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
CLISetup::registerSetup('sql', new class extends SetupScript
|
||||
{
|
||||
protected $command = 'areatrigger';
|
||||
protected $info = array(
|
||||
'areatrigger' => [[], CLISetup::ARGV_PARAM, 'Compiles data for type: Areatrigger from dbc and world db.']
|
||||
);
|
||||
|
||||
protected $tblDependencyTC = ['areatrigger_involvedrelation', 'areatrigger_scripts', 'areatrigger_tavern', 'areatrigger_teleport', 'quest_template', 'quest_template_addon'];
|
||||
protected $dbcSourceFiles = ['areatrigger', 'worldmaparea', 'dungeonmap'];
|
||||
protected $dbcSourceFiles = ['areatrigger'];
|
||||
protected $worldDependency = ['areatrigger_involvedrelation', 'areatrigger_scripts', 'areatrigger_tavern', 'areatrigger_teleport', 'quest_template', 'quest_template_addon'];
|
||||
protected $setupAfter = [['dungeonmap', 'worldmaparea'], []];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
@@ -25,22 +28,22 @@ SqlGen::register(new class extends SetupScript
|
||||
*/
|
||||
|
||||
// 1: Taverns
|
||||
CLI::write(' - fetching taverns');
|
||||
CLI::write('[areatrigger] - fetching taverns');
|
||||
|
||||
$addData = DB::World()->select('SELECT `id` AS ARRAY_KEY, `name`, ?d AS `type` FROM areatrigger_tavern', AT_TYPE_TAVERN);
|
||||
foreach ($addData as $id => $ad)
|
||||
DB::Aowow()->query('UPDATE ?_areatrigger SET ?a WHERE `id` = ?d', $ad, $id);
|
||||
|
||||
// 2: Teleporter + teleporting 4: Smart Trigger
|
||||
CLI::write(' - calculation teleporter coordinates');
|
||||
CLI::write('[areatrigger] - calculation teleporter coordinates');
|
||||
|
||||
$addData = DB::World()->select(
|
||||
'SELECT `ID` AS ARRAY_KEY, `Name` AS `name`, `target_map` AS `map`, `target_position_x` AS `posY`, `target_position_y` AS `posX`, `target_orientation` AS `orientation`
|
||||
'SELECT ID AS ARRAY_KEY, Name AS `name`, target_map AS `map`, target_position_x AS `posY`, target_position_y AS `posX`, target_orientation AS `orientation`
|
||||
FROM areatrigger_teleport
|
||||
UNION
|
||||
SELECT `entryorguid` AS ARRAY_KEY, "TBD" AS `name`, `action_param1` AS `map`, `target_x` AS `posY`, `target_y` AS `posX`, `target_o` AS `orientation`
|
||||
SELECT entryorguid AS ARRAY_KEY, "TBD" AS `name`, action_param1 AS `map`, target_x AS `posY`, target_y AS `posX`, target_o AS `orientation`
|
||||
FROM smart_scripts
|
||||
WHERE `source_type` = 2 AND `action_type` = 62'
|
||||
WHERE source_type = 2 AND action_type = 62'
|
||||
);
|
||||
|
||||
foreach ($addData as $id => $ad)
|
||||
@@ -48,7 +51,7 @@ SqlGen::register(new class extends SetupScript
|
||||
$points = Game::worldPosToZonePos($ad['map'], $ad['posX'], $ad['posY']);
|
||||
if (!$points)
|
||||
{
|
||||
CLI::write(' * AT '.$id.' teleporter endpoint '.CLI::bold($ad['name']).' could not be matched to displayable area [M:'.$ad['map'].'; X:'.$ad['posY'].'; Y:'.$ad['posX'].']', CLI::LOG_WARN);
|
||||
CLI::write('[areatrigger] '.str_pad('['.$id.']', 8).' teleporter endpoint '.CLI::bold($ad['name']).' could not be matched to displayable area [M:'.$ad['map'].'; X:'.$ad['posY'].'; Y:'.$ad['posX'].']', CLI::LOG_WARN);
|
||||
DB::Aowow()->query('UPDATE ?_areatrigger SET `name` = ?, `type` = ?d WHERE `id` = ?d', $ad['name'], AT_TYPE_TELEPORT, $id);
|
||||
continue;
|
||||
}
|
||||
@@ -67,19 +70,19 @@ SqlGen::register(new class extends SetupScript
|
||||
}
|
||||
|
||||
// 3: Quest Objectives
|
||||
CLI::write(' - satisfying quest objectives');
|
||||
CLI::write('[areatrigger] - satisfying quest objectives');
|
||||
|
||||
$addData = DB::World()->select('SELECT atir.`id` AS ARRAY_KEY, qt.`ID` AS `quest`, NULLIF(qt.AreaDescription, "") AS `name`, qta.`SpecialFlags` FROM quest_template qt LEFT JOIN quest_template_addon qta ON qta.`ID` = qt.`ID` JOIN areatrigger_involvedrelation atir ON atir.`quest` = qt.`ID`');
|
||||
$addData = DB::World()->select('SELECT atir.`id` AS ARRAY_KEY, `qt`.ID AS `quest`, NULLIF(qt.`AreaDescription`, "") AS `name`, qta.`SpecialFlags` FROM quest_template qt LEFT JOIN quest_template_addon qta ON qta.`ID` = qt.`ID` JOIN areatrigger_involvedrelation atir ON atir.`quest` = qt.`ID`');
|
||||
foreach ($addData as $id => $ad)
|
||||
{
|
||||
if (!($ad['SpecialFlags'] & QUEST_FLAG_SPECIAL_EXT_COMPLETE))
|
||||
CLI::write(' * Areatrigger '.CLI::bold($id).' is involved in quest '.CLI::bold($ad['quest']).', but quest is not flagged for external completion (SpecialFlags & '.Util::asHex(QUEST_FLAG_SPECIAL_EXT_COMPLETE).')', CLI::LOG_WARN);
|
||||
CLI::write('[areatrigger] '.str_pad('['.$id.']', 8).' is involved in quest '.CLI::bold($ad['quest']).', but quest is not flagged for external completion (SpecialFlags & '.Util::asHex(QUEST_FLAG_SPECIAL_EXT_COMPLETE).')', CLI::LOG_WARN);
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_areatrigger SET `name` = ?, `type` = ?d, `quest` = ?d WHERE `id` = ?d', $ad['name'], AT_TYPE_OBJECTIVE, $ad['quest'], $id);
|
||||
DB::Aowow()->query('UPDATE ?_areatrigger SET `name` = ?, type = ?d, `quest` = ?d WHERE `id` = ?d', $ad['name'], AT_TYPE_OBJECTIVE, $ad['quest'], $id);
|
||||
}
|
||||
|
||||
// 4/5 Scripted
|
||||
CLI::write(' - assigning scripts');
|
||||
CLI::write('[areatrigger] - assigning scripts');
|
||||
|
||||
$addData = DB::World()->select('SELECT `entry` AS ARRAY_KEY, IF(`ScriptName` = "SmartTrigger", NULL, `ScriptName`) AS `name`, IF(`ScriptName` = "SmartTrigger", 4, 5) AS `type` FROM areatrigger_scripts');
|
||||
foreach ($addData as $id => $ad)
|
||||
@@ -7,16 +7,20 @@ if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
{
|
||||
use TrCustomData; // import custom data from DB
|
||||
|
||||
protected $command = 'classes';
|
||||
protected $info = array(
|
||||
'classes' => [[], CLISetup::ARGV_PARAM, 'Compiles data for type: PlayerClass from dbc.']
|
||||
);
|
||||
|
||||
protected $dbcSourceFiles = ['spell', 'charbaseinfo', 'skillraceclassinfo', 'skilllineability', 'chrclasses'];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
DB::Aowow()->query('TRUNCATE ?_classes');
|
||||
|
||||
$classes = DB::Aowow()->select('SELECT *, id AS ARRAY_KEY FROM dbc_chrclasses');
|
||||
|
||||
// add raceMask
|
||||
@@ -36,7 +40,7 @@ SqlGen::register(new class extends SetupScript
|
||||
}
|
||||
|
||||
foreach ($classes as $cl)
|
||||
DB::Aowow()->query('REPLACE INTO ?_classes (?#) VALUES (?a)', array_keys($cl), array_values($cl));
|
||||
DB::Aowow()->query('INSERT INTO ?_classes (?#) VALUES (?a)', array_keys($cl), array_values($cl));
|
||||
|
||||
$this->reapplyCCFlags('classes', Type::CHR_CLASS);
|
||||
|
||||
@@ -1,185 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
{
|
||||
protected $command = 'creature';
|
||||
|
||||
protected $tblDependencyTC = ['creature_template', 'creature_template_locale', 'creature_template_resistance', 'creature_template_spell', 'creature_classlevelstats', 'instance_encounters'];
|
||||
protected $dbcSourceFiles = ['creaturedisplayinfo', 'creaturedisplayinfoextra'];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
$baseQuery = '
|
||||
SELECT
|
||||
ct.entry,
|
||||
IF(ie.creditEntry IS NULL, 0, ?d) AS cuFlags, -- cuFlags
|
||||
difficulty_entry_1, difficulty_entry_2, difficulty_entry_3,
|
||||
KillCredit1, KillCredit2,
|
||||
modelid1, modelid2, modelid3, modelid4,
|
||||
"" AS textureString, -- textureString
|
||||
0 AS modelId, -- modelId
|
||||
0 AS humanoid, -- uses creaturedisplayinfoextra
|
||||
"" AS iconString, -- iconString
|
||||
ct.name, IFNULL(ctl2.`Name`, "") AS n2, IFNULL(ctl3.`Name`, "") AS n3, IFNULL(ctl4.`Name`, "") AS n4, IFNULL(ctl6.`Name`, "") AS n6, IFNULL(ctl8.`Name`, "") AS n8,
|
||||
subname, IFNULL(ctl2.`Title`, "") AS t2, IFNULL(ctl3.`Title`, "") AS t3, IFNULL(ctl4.`Title`, "") AS t4, IFNULL(ctl6.`Title`, "") AS t6, IFNULL(ctl8.`Title`, "") AS t8,
|
||||
minLevel, maxLevel,
|
||||
exp,
|
||||
faction,
|
||||
npcflag,
|
||||
IF(`rank` > 4, 0, `rank`),
|
||||
dmgSchool,
|
||||
DamageModifier,
|
||||
BaseAttackTime,
|
||||
RangeAttackTime,
|
||||
BaseVariance,
|
||||
RangeVariance,
|
||||
unit_class,
|
||||
unit_flags, unit_flags2, dynamicflags,
|
||||
family,
|
||||
IFNULL(t.Type, 0),
|
||||
IFNULL(t.Requirement, 0),
|
||||
(CASE ct.exp WHEN 0 THEN min.damage_base WHEN 1 THEN min.damage_exp1 ELSE min.damage_exp2 END) AS dmgMin,
|
||||
(CASE ct.exp WHEN 0 THEN max.damage_base WHEN 1 THEN max.damage_exp1 ELSE max.damage_exp2 END) AS dmgMax,
|
||||
min.attackpower AS mleAtkPwrMin,
|
||||
max.attackpower AS mleAtkPwrMax,
|
||||
min.rangedattackpower AS rmgAtkPwrMin,
|
||||
max.rangedattackpower AS rmgAtkPwrMax,
|
||||
ct.type,
|
||||
type_flags,
|
||||
lootid, pickpocketloot, skinloot,
|
||||
IFNULL(cts0.Spell, 0), IFNULL(cts1.Spell, 0), IFNULL(cts2.Spell, 0), IFNULL(cts3.Spell, 0), IFNULL(cts4.Spell, 0), IFNULL(cts5.Spell, 0), IFNULL(cts6.Spell, 0), IFNULL(cts7.Spell, 0),
|
||||
PetSpellDataId,
|
||||
VehicleId,
|
||||
mingold, maxgold,
|
||||
AIName,
|
||||
(CASE ct.exp WHEN 0 THEN min.basehp0 WHEN 1 THEN min.basehp1 ELSE min.basehp2 END) * ct.HealthModifier AS healthMin,
|
||||
(CASE ct.exp WHEN 0 THEN max.basehp0 WHEN 1 THEN max.basehp1 ELSE max.basehp2 END) * ct.HealthModifier AS healthMax,
|
||||
min.basemana * ct.ManaModifier AS manaMin,
|
||||
max.basemana * ct.ManaModifier AS manaMax,
|
||||
min.basearmor * ct.ArmorModifier AS armorMin,
|
||||
max.basearmor * ct.ArmorModifier AS armorMax,
|
||||
IFNULL(ctr1.Resistance, 0), IFNULL(ctr2.Resistance, 0), IFNULL(ctr3.Resistance, 0), IFNULL(ctr4.Resistance, 0), IFNULL(ctr5.Resistance, 0), IFNULL(ctr6.Resistance, 0),
|
||||
RacialLeader,
|
||||
mechanic_immune_mask,
|
||||
flags_extra,
|
||||
ScriptName
|
||||
FROM
|
||||
creature_template ct
|
||||
JOIN
|
||||
creature_classlevelstats min ON ct.unit_class = min.class AND ct.minlevel = min.level
|
||||
JOIN
|
||||
creature_classlevelstats max ON ct.unit_class = max.class AND ct.maxlevel = max.level
|
||||
LEFT JOIN
|
||||
creature_default_trainer cdt ON cdt.CreatureId = ct.entry
|
||||
LEFT JOIN
|
||||
trainer t ON t.Id = cdt.TrainerId
|
||||
LEFT JOIN
|
||||
creature_template_locale ctl2 ON ct.entry = ctl2.entry AND ctl2.`locale` = "frFR"
|
||||
LEFT JOIN
|
||||
creature_template_locale ctl3 ON ct.entry = ctl3.entry AND ctl3.`locale` = "deDE"
|
||||
LEFT JOIN
|
||||
creature_template_locale ctl4 ON ct.entry = ctl4.entry AND ctl4.`locale` = "zhCN"
|
||||
LEFT JOIN
|
||||
creature_template_locale ctl6 ON ct.entry = ctl6.entry AND ctl6.`locale` = "esES"
|
||||
LEFT JOIN
|
||||
creature_template_locale ctl8 ON ct.entry = ctl8.entry AND ctl8.`locale` = "ruRU"
|
||||
LEFT JOIN
|
||||
(SELECT creditEntry FROM instance_encounters WHERE creditType = 0 GROUP BY creditEntry) ie ON ie.creditEntry = ct.entry
|
||||
LEFT JOIN
|
||||
creature_template_spell cts0 ON ct.entry = cts0.CreatureID AND cts0.Index = 0
|
||||
LEFT JOIN
|
||||
creature_template_spell cts1 ON ct.entry = cts1.CreatureID AND cts1.Index = 1
|
||||
LEFT JOIN
|
||||
creature_template_spell cts2 ON ct.entry = cts2.CreatureID AND cts2.Index = 2
|
||||
LEFT JOIN
|
||||
creature_template_spell cts3 ON ct.entry = cts3.CreatureID AND cts3.Index = 3
|
||||
LEFT JOIN
|
||||
creature_template_spell cts4 ON ct.entry = cts4.CreatureID AND cts4.Index = 4
|
||||
LEFT JOIN
|
||||
creature_template_spell cts5 ON ct.entry = cts5.CreatureID AND cts5.Index = 5
|
||||
LEFT JOIN
|
||||
creature_template_spell cts6 ON ct.entry = cts6.CreatureID AND cts6.Index = 6
|
||||
LEFT JOIN
|
||||
creature_template_spell cts7 ON ct.entry = cts7.CreatureID AND cts7.Index = 7
|
||||
LEFT JOIN
|
||||
creature_template_resistance ctr1 ON ct.entry = ctr1.CreatureID AND ctr1.School = 1
|
||||
LEFT JOIN
|
||||
creature_template_resistance ctr2 ON ct.entry = ctr2.CreatureID AND ctr2.School = 2
|
||||
LEFT JOIN
|
||||
creature_template_resistance ctr3 ON ct.entry = ctr3.CreatureID AND ctr3.School = 3
|
||||
LEFT JOIN
|
||||
creature_template_resistance ctr4 ON ct.entry = ctr4.CreatureID AND ctr4.School = 4
|
||||
LEFT JOIN
|
||||
creature_template_resistance ctr5 ON ct.entry = ctr5.CreatureID AND ctr5.School = 5
|
||||
LEFT JOIN
|
||||
creature_template_resistance ctr6 ON ct.entry = ctr6.CreatureID AND ctr6.School = 6
|
||||
{
|
||||
WHERE
|
||||
ct.entry IN (?a)
|
||||
}
|
||||
LIMIT
|
||||
?d, ?d';
|
||||
|
||||
$dummyQuery = '
|
||||
UPDATE
|
||||
?_creature a
|
||||
JOIN
|
||||
(
|
||||
SELECT b.difficultyEntry1 AS dummy FROM ?_creature b UNION
|
||||
SELECT c.difficultyEntry2 AS dummy FROM ?_creature c UNION
|
||||
SELECT d.difficultyEntry3 AS dummy FROM ?_creature d
|
||||
) j
|
||||
SET
|
||||
a.cuFlags = a.cuFlags | ?d
|
||||
WHERE
|
||||
a.id = j.dummy';
|
||||
|
||||
$displayInfoQuery = '
|
||||
UPDATE
|
||||
?_creature c
|
||||
JOIN
|
||||
dbc_creaturedisplayinfo cdi ON c.displayId1 = cdi.id
|
||||
LEFT JOIN
|
||||
dbc_creaturedisplayinfoextra cdie ON cdi.extraInfoId = cdie.id
|
||||
SET
|
||||
c.textureString = IFNULL(cdie.textureString, cdi.skin1),
|
||||
c.modelId = cdi.modelId,
|
||||
c.iconString = cdi.iconString,
|
||||
c.humanoid = IF(cdie.id IS NULL, 0, 1)';
|
||||
|
||||
$i = 0;
|
||||
DB::Aowow()->query('TRUNCATE ?_creature');
|
||||
while ($npcs = DB::World()->select($baseQuery, NPC_CU_INSTANCE_BOSS, $ids ?: DBSIMPLE_SKIP, SqlGen::$sqlBatchSize * $i, SqlGen::$sqlBatchSize))
|
||||
{
|
||||
CLI::write(' * batch #' . ++$i . ' (' . count($npcs) . ')', CLI::LOG_BLANK, true, true);
|
||||
|
||||
foreach ($npcs as $npc)
|
||||
DB::Aowow()->query('INSERT INTO ?_creature VALUES (?a)', array_values($npc));
|
||||
}
|
||||
|
||||
// apply "textureString", "modelId" and "iconSring"
|
||||
DB::Aowow()->query($displayInfoQuery);
|
||||
|
||||
// apply cuFlag: difficultyDummy
|
||||
DB::Aowow()->query($dummyQuery, NPC_CU_DIFFICULTY_DUMMY | CUSTOM_EXCLUDE_FOR_LISTVIEW);
|
||||
|
||||
// apply cuFlag: excludeFromListview [for trigger-creatures]
|
||||
DB::Aowow()->query('UPDATE ?_creature SET cuFlags = cuFlags | ?d WHERE flagsExtra & ?d', CUSTOM_EXCLUDE_FOR_LISTVIEW, 0x80);
|
||||
|
||||
// apply cuFlag: exCludeFromListview [for nameparts indicating internal usage]
|
||||
DB::Aowow()->query('UPDATE ?_creature SET cuFlags = cuFlags | ?d WHERE name_loc0 LIKE "%[%" OR name_loc0 LIKE "%(%" OR name_loc0 LIKE "%visual%" OR name_loc0 LIKE "%trigger%" OR name_loc0 LIKE "%credit%" OR name_loc0 LIKE "%marker%"', CUSTOM_EXCLUDE_FOR_LISTVIEW);
|
||||
|
||||
$this->reapplyCCFlags('creature', Type::NPC);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
146
setup/tools/sqlgen/creature.ss.php
Normal file
146
setup/tools/sqlgen/creature.ss.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
{
|
||||
protected $info = array(
|
||||
'creature' => [[], CLISetup::ARGV_PARAM, 'Compiles data for type: NPC from dbc and world db.']
|
||||
);
|
||||
|
||||
protected $dbcSourceFiles = ['creaturedisplayinfo', 'creaturedisplayinfoextra'];
|
||||
protected $worldDependency = ['creature_template', 'creature_template_locale', 'creature_template_resistance', 'creature_template_spell', 'creature_classlevelstats', 'creature_default_trainer', 'trainer', 'instance_encounters'];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
$baseQuery =
|
||||
'SELECT ct.entry,
|
||||
IF(ie.creditEntry IS NULL, 0, ?d) AS cuFlags,
|
||||
difficulty_entry_1, difficulty_entry_2, difficulty_entry_3,
|
||||
KillCredit1, KillCredit2,
|
||||
modelid1, modelid2, modelid3, modelid4,
|
||||
"" AS textureString,
|
||||
0 AS modelId,
|
||||
0 AS humanoid, -- uses creaturedisplayinfoextra
|
||||
"" AS iconString,
|
||||
ct.name, IFNULL(ctl2.`Name`, "") AS n2, IFNULL(ctl3.`Name`, "") AS n3, IFNULL(ctl4.`Name`, "") AS n4, IFNULL(ctl6.`Name`, "") AS n6, IFNULL(ctl8.`Name`, "") AS n8,
|
||||
subname, IFNULL(ctl2.`Title`, "") AS t2, IFNULL(ctl3.`Title`, "") AS t3, IFNULL(ctl4.`Title`, "") AS t4, IFNULL(ctl6.`Title`, "") AS t6, IFNULL(ctl8.`Title`, "") AS t8,
|
||||
minLevel, maxLevel,
|
||||
exp,
|
||||
faction,
|
||||
npcflag,
|
||||
IF(`rank` > 4, 0, `rank`),
|
||||
dmgSchool,
|
||||
DamageModifier,
|
||||
BaseAttackTime,
|
||||
RangeAttackTime,
|
||||
BaseVariance,
|
||||
RangeVariance,
|
||||
unit_class,
|
||||
unit_flags, unit_flags2, dynamicflags,
|
||||
family,
|
||||
IFNULL(t.Type, 0),
|
||||
IFNULL(t.Requirement, 0),
|
||||
(CASE ct.exp WHEN 0 THEN min.damage_base WHEN 1 THEN min.damage_exp1 ELSE min.damage_exp2 END) AS dmgMin,
|
||||
(CASE ct.exp WHEN 0 THEN max.damage_base WHEN 1 THEN max.damage_exp1 ELSE max.damage_exp2 END) AS dmgMax,
|
||||
min.attackpower AS mleAtkPwrMin,
|
||||
max.attackpower AS mleAtkPwrMax,
|
||||
min.rangedattackpower AS rmgAtkPwrMin,
|
||||
max.rangedattackpower AS rmgAtkPwrMax,
|
||||
ct.type,
|
||||
type_flags,
|
||||
lootid, pickpocketloot, skinloot,
|
||||
IFNULL(cts0.Spell, 0), IFNULL(cts1.Spell, 0), IFNULL(cts2.Spell, 0), IFNULL(cts3.Spell, 0), IFNULL(cts4.Spell, 0), IFNULL(cts5.Spell, 0), IFNULL(cts6.Spell, 0), IFNULL(cts7.Spell, 0),
|
||||
PetSpellDataId,
|
||||
VehicleId,
|
||||
mingold, maxgold,
|
||||
AIName,
|
||||
(CASE ct.exp WHEN 0 THEN min.basehp0 WHEN 1 THEN min.basehp1 ELSE min.basehp2 END) * ct.HealthModifier AS healthMin,
|
||||
(CASE ct.exp WHEN 0 THEN max.basehp0 WHEN 1 THEN max.basehp1 ELSE max.basehp2 END) * ct.HealthModifier AS healthMax,
|
||||
min.basemana * ct.ManaModifier AS manaMin,
|
||||
max.basemana * ct.ManaModifier AS manaMax,
|
||||
min.basearmor * ct.ArmorModifier AS armorMin,
|
||||
max.basearmor * ct.ArmorModifier AS armorMax,
|
||||
IFNULL(ctr1.Resistance, 0), IFNULL(ctr2.Resistance, 0), IFNULL(ctr3.Resistance, 0), IFNULL(ctr4.Resistance, 0), IFNULL(ctr5.Resistance, 0), IFNULL(ctr6.Resistance, 0),
|
||||
RacialLeader,
|
||||
mechanic_immune_mask,
|
||||
flags_extra,
|
||||
ScriptName
|
||||
FROM creature_template ct
|
||||
JOIN creature_classlevelstats min ON ct.unit_class = min.class AND ct.minlevel = min.level
|
||||
JOIN creature_classlevelstats max ON ct.unit_class = max.class AND ct.maxlevel = max.level
|
||||
LEFT JOIN creature_default_trainer cdt ON cdt.CreatureId = ct.entry
|
||||
LEFT JOIN trainer t ON t.Id = cdt.TrainerId
|
||||
LEFT JOIN creature_template_locale ctl2 ON ct.entry = ctl2.entry AND ctl2.`locale` = "frFR"
|
||||
LEFT JOIN creature_template_locale ctl3 ON ct.entry = ctl3.entry AND ctl3.`locale` = "deDE"
|
||||
LEFT JOIN creature_template_locale ctl4 ON ct.entry = ctl4.entry AND ctl4.`locale` = "zhCN"
|
||||
LEFT JOIN creature_template_locale ctl6 ON ct.entry = ctl6.entry AND ctl6.`locale` = "esES"
|
||||
LEFT JOIN creature_template_locale ctl8 ON ct.entry = ctl8.entry AND ctl8.`locale` = "ruRU"
|
||||
LEFT JOIN (SELECT creditEntry FROM instance_encounters WHERE creditType = 0 GROUP BY creditEntry) ie ON ie.creditEntry = ct.entry
|
||||
LEFT JOIN creature_template_spell cts0 ON ct.entry = cts0.CreatureID AND cts0.Index = 0
|
||||
LEFT JOIN creature_template_spell cts1 ON ct.entry = cts1.CreatureID AND cts1.Index = 1
|
||||
LEFT JOIN creature_template_spell cts2 ON ct.entry = cts2.CreatureID AND cts2.Index = 2
|
||||
LEFT JOIN creature_template_spell cts3 ON ct.entry = cts3.CreatureID AND cts3.Index = 3
|
||||
LEFT JOIN creature_template_spell cts4 ON ct.entry = cts4.CreatureID AND cts4.Index = 4
|
||||
LEFT JOIN creature_template_spell cts5 ON ct.entry = cts5.CreatureID AND cts5.Index = 5
|
||||
LEFT JOIN creature_template_spell cts6 ON ct.entry = cts6.CreatureID AND cts6.Index = 6
|
||||
LEFT JOIN creature_template_spell cts7 ON ct.entry = cts7.CreatureID AND cts7.Index = 7
|
||||
LEFT JOIN creature_template_resistance ctr1 ON ct.entry = ctr1.CreatureID AND ctr1.School = 1
|
||||
LEFT JOIN creature_template_resistance ctr2 ON ct.entry = ctr2.CreatureID AND ctr2.School = 2
|
||||
LEFT JOIN creature_template_resistance ctr3 ON ct.entry = ctr3.CreatureID AND ctr3.School = 3
|
||||
LEFT JOIN creature_template_resistance ctr4 ON ct.entry = ctr4.CreatureID AND ctr4.School = 4
|
||||
LEFT JOIN creature_template_resistance ctr5 ON ct.entry = ctr5.CreatureID AND ctr5.School = 5
|
||||
LEFT JOIN creature_template_resistance ctr6 ON ct.entry = ctr6.CreatureID AND ctr6.School = 6
|
||||
{ WHERE ct.entry IN (?a) }
|
||||
LIMIT ?d, ?d';
|
||||
|
||||
$i = 0;
|
||||
DB::Aowow()->query('TRUNCATE ?_creature');
|
||||
while ($npcs = DB::World()->select($baseQuery, NPC_CU_INSTANCE_BOSS, $ids ?: DBSIMPLE_SKIP, CLISetup::SQL_BATCH * $i, CLISetup::SQL_BATCH))
|
||||
{
|
||||
CLI::write(' * batch #' . ++$i . ' (' . count($npcs) . ')', CLI::LOG_BLANK, true, true);
|
||||
|
||||
foreach ($npcs as $npc)
|
||||
DB::Aowow()->query('INSERT INTO ?_creature VALUES (?a)', array_values($npc));
|
||||
}
|
||||
|
||||
// apply "textureString", "modelId" and "iconSring"
|
||||
DB::Aowow()->query(
|
||||
'UPDATE ?_creature c
|
||||
JOIN dbc_creaturedisplayinfo cdi ON c.displayId1 = cdi.id
|
||||
LEFT JOIN dbc_creaturedisplayinfoextra cdie ON cdi.extraInfoId = cdie.id
|
||||
SET c.textureString = IFNULL(cdie.textureString, cdi.skin1),
|
||||
c.modelId = cdi.modelId,
|
||||
c.iconString = cdi.iconString,
|
||||
c.humanoid = IF(cdie.id IS NULL, 0, 1)'
|
||||
);
|
||||
|
||||
// apply cuFlag: difficultyDummy
|
||||
DB::Aowow()->query(
|
||||
'UPDATE ?_creature a
|
||||
JOIN (SELECT b.difficultyEntry1 AS dummy FROM ?_creature b UNION
|
||||
SELECT c.difficultyEntry2 AS dummy FROM ?_creature c UNION
|
||||
SELECT d.difficultyEntry3 AS dummy FROM ?_creature d) j
|
||||
SET a.cuFlags = a.cuFlags | ?d
|
||||
WHERE a.id = j.dummy',
|
||||
NPC_CU_DIFFICULTY_DUMMY | CUSTOM_EXCLUDE_FOR_LISTVIEW
|
||||
);
|
||||
|
||||
// apply cuFlag: excludeFromListview [for trigger-creatures]
|
||||
DB::Aowow()->query('UPDATE ?_creature SET cuFlags = cuFlags | ?d WHERE flagsExtra & ?d', CUSTOM_EXCLUDE_FOR_LISTVIEW, 0x80);
|
||||
|
||||
// apply cuFlag: exCludeFromListview [for nameparts indicating internal usage]
|
||||
DB::Aowow()->query('UPDATE ?_creature SET cuFlags = cuFlags | ?d WHERE name_loc0 LIKE "%[%" OR name_loc0 LIKE "%(%" OR name_loc0 LIKE "%visual%" OR name_loc0 LIKE "%trigger%" OR name_loc0 LIKE "%credit%" OR name_loc0 LIKE "%marker%"', CUSTOM_EXCLUDE_FOR_LISTVIEW);
|
||||
|
||||
$this->reapplyCCFlags('creature', Type::NPC);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,84 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
{
|
||||
use TrCustomData; // import custom data from DB
|
||||
|
||||
protected $command = 'currencies';
|
||||
|
||||
protected $tblDependencyAowow = ['icons'];
|
||||
protected $tblDependencyTC = ['item_template', 'item_template_locale'];
|
||||
protected $dbcSourceFiles = ['itemdisplayinfo', 'currencytypes'];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
if (!$ids)
|
||||
DB::Aowow()->query('REPLACE INTO ?_currencies (`id`, `category`, `itemId`) SELECT `id`, LEAST(`category`, 41), `itemId` FROM dbc_currencytypes');
|
||||
|
||||
$moneyItems = DB::Aowow()->selectCol('SELECT `id` AS ARRAY_KEY, `itemId` FROM dbc_currencytypes{ WHERE `id` IN (?a)}', $ids ?: DBSIMPLE_SKIP);
|
||||
|
||||
// apply names & cap
|
||||
$moneyNames = DB::World()->select('
|
||||
SELECT
|
||||
it.entry AS ARRAY_KEY,
|
||||
it.name AS name_loc0, IFNULL(itl2.Name, "") AS name_loc2, IFNULL(itl3.Name, "") AS name_loc3, IFNULL(itl4.Name, "") AS name_loc4, IFNULL(itl6.Name, "") AS name_loc6, IFNULL(itl8.Name, "") AS name_loc8,
|
||||
it.maxCount AS cap
|
||||
FROM
|
||||
item_template it
|
||||
LEFT JOIN
|
||||
item_template_locale itl2 ON it.entry = itl2.ID AND itl2.locale = "frFR"
|
||||
LEFT JOIN
|
||||
item_template_locale itl3 ON it.entry = itl3.ID AND itl3.locale = "deDE"
|
||||
LEFT JOIN
|
||||
item_template_locale itl4 ON it.entry = itl4.ID AND itl4.locale = "zhCN"
|
||||
LEFT JOIN
|
||||
item_template_locale itl6 ON it.entry = itl6.ID AND itl6.locale = "esES"
|
||||
LEFT JOIN
|
||||
item_template_locale itl8 ON it.entry = itl8.ID AND itl8.locale = "ruRU"
|
||||
WHERE
|
||||
it.entry IN (?a)',
|
||||
$moneyItems);
|
||||
|
||||
foreach ($moneyItems as $cId => $itemId)
|
||||
{
|
||||
if (!empty($moneyNames[$itemId]))
|
||||
$strings = $moneyNames[$itemId];
|
||||
else
|
||||
{
|
||||
CLI::write('item #'.$itemId.' referenced by currency #'.$cId.' not in item_template', CLI::LOG_WARN);
|
||||
$strings = ['name_loc0' => 'Item #'.$itemId.' not in DB', 'iconId' => 0, 'cuFlags' => CUSTOM_EXCLUDE_FOR_LISTVIEW, 'category' => 3];
|
||||
}
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_currencies SET ?a WHERE itemId = ?d', $strings, $itemId);
|
||||
}
|
||||
|
||||
// apply icons
|
||||
$displayIds = DB::World()->selectCol('SELECT entry AS ARRAY_KEY, displayid FROM item_template WHERE entry IN (?a)', $moneyItems);
|
||||
foreach ($displayIds as $itemId => $iconId)
|
||||
DB::Aowow()->query('
|
||||
UPDATE
|
||||
?_currencies c,
|
||||
?_icons i,
|
||||
dbc_itemdisplayinfo idi
|
||||
SET
|
||||
c.iconId = i.id
|
||||
WHERE
|
||||
i.name = LOWER(idi.inventoryIcon1) AND
|
||||
idi.id = ?d AND
|
||||
c.itemId = ?d
|
||||
', $iconId, $itemId);
|
||||
|
||||
$this->reapplyCCFlags('currencies', Type::CURRENCY);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
73
setup/tools/sqlgen/currencies.ss.php
Normal file
73
setup/tools/sqlgen/currencies.ss.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
{
|
||||
use TrCustomData; // import custom data from DB
|
||||
|
||||
protected $info = array(
|
||||
'currencies' => [[], CLISetup::ARGV_PARAM, 'Compiles data for type: Currency from dbc and world db.']
|
||||
);
|
||||
|
||||
protected $dbcSourceFiles = ['itemdisplayinfo', 'currencytypes'];
|
||||
protected $worldDependency = ['item_template', 'item_template_locale'];
|
||||
protected $setupAfter = [['icons'], []];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
DB::Aowow()->query('TRUNCATE ?_currencies');
|
||||
DB::Aowow()->query('INSERT INTO ?_currencies (`id`, `category`, `itemId`) SELECT `id`, LEAST(`category`, 41), `itemId` FROM dbc_currencytypes');
|
||||
|
||||
$moneyItems = DB::Aowow()->selectCol('SELECT `id` AS ARRAY_KEY, `itemId` FROM dbc_currencytypes{ WHERE `id` IN (?a)}', $ids ?: DBSIMPLE_SKIP);
|
||||
|
||||
// apply names & cap
|
||||
$moneyNames = DB::World()->select(
|
||||
'SELECT it.`entry` AS ARRAY_KEY,
|
||||
it.`name` AS `name_loc0`, IFNULL(itl2.`Name`, "") AS `name_loc2`, IFNULL(itl3.`Name`, "") AS `name_loc3`, IFNULL(itl4.`Name`, "") AS `name_loc4`, IFNULL(itl6.`Name`, "") AS `name_loc6`, IFNULL(itl8.`Name`, "") AS `name_loc8`,
|
||||
it.`maxCount` AS `cap`
|
||||
FROM item_template it
|
||||
LEFT JOIN item_template_locale itl2 ON it.entry = itl2.ID AND itl2.locale = "frFR"
|
||||
LEFT JOIN item_template_locale itl3 ON it.entry = itl3.ID AND itl3.locale = "deDE"
|
||||
LEFT JOIN item_template_locale itl4 ON it.entry = itl4.ID AND itl4.locale = "zhCN"
|
||||
LEFT JOIN item_template_locale itl6 ON it.entry = itl6.ID AND itl6.locale = "esES"
|
||||
LEFT JOIN item_template_locale itl8 ON it.entry = itl8.ID AND itl8.locale = "ruRU"
|
||||
WHERE it.entry IN (?a)',
|
||||
$moneyItems
|
||||
);
|
||||
|
||||
foreach ($moneyItems as $cId => $itemId)
|
||||
{
|
||||
if (!empty($moneyNames[$itemId]))
|
||||
$strings = $moneyNames[$itemId];
|
||||
else
|
||||
{
|
||||
CLI::write('[currencies] '.str_pad('['.$cId.']', 6).' referenced item '.CLI::bold($itemId).' is not in item_template', CLI::LOG_WARN);
|
||||
$strings = ['name_loc0' => 'Item #'.$itemId.' not in DB', 'iconId' => 0, 'cuFlags' => CUSTOM_EXCLUDE_FOR_LISTVIEW, 'category' => 3];
|
||||
}
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_currencies SET ?a WHERE itemId = ?d', $strings, $itemId);
|
||||
}
|
||||
|
||||
// apply icons
|
||||
$displayIds = DB::World()->selectCol('SELECT `entry` AS ARRAY_KEY, `displayid` FROM item_template WHERE `entry` IN (?a)', $moneyItems);
|
||||
foreach ($displayIds as $itemId => $iconId)
|
||||
DB::Aowow()->query(
|
||||
'UPDATE ?_currencies c, ?_icons i, dbc_itemdisplayinfo idi
|
||||
SET c.`iconId` = i.`id`
|
||||
WHERE i.`name` = LOWER(idi.`inventoryIcon1`) AND idi.`id` = ?d AND c.`itemId` = ?d',
|
||||
$iconId, $itemId
|
||||
);
|
||||
|
||||
$this->reapplyCCFlags('currencies', Type::CURRENCY);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -7,18 +7,21 @@ if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
{
|
||||
protected $command = 'declinedwords';
|
||||
protected $info = array(
|
||||
'declinedwords' => [[], CLISetup::ARGV_PARAM, 'Compiles data for type: Enchantment from dbc and world db.']
|
||||
);
|
||||
|
||||
protected $dbcSourceFiles = ['declinedword', 'declinedwordcases'];
|
||||
|
||||
public function generate() : bool
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
CLI::write('SqlGen::generate() - copying declinedword.dbc into aowow_declinedword');
|
||||
CLI::write('[declinedwords] - copying declinedword.dbc into aowow_declinedword');
|
||||
DB::Aowow()->query('TRUNCATE ?_declinedword');
|
||||
DB::Aowow()->query('INSERT INTO ?_declinedword SELECT * FROM dbc_declinedword');
|
||||
|
||||
CLI::write('SqlGen::generate() - copying declinedwordcases.dbc into aowow_declinedwordcases');
|
||||
CLI::write('[declinedwords] - copying declinedwordcases.dbc into aowow_declinedwordcases');
|
||||
DB::Aowow()->query('TRUNCATE ?_declinedwordcases');
|
||||
DB::Aowow()->query('INSERT INTO ?_declinedwordcases SELECT `wordId`, `caseIdx`, `word` FROM dbc_declinedwordcases');
|
||||
|
||||
@@ -7,7 +7,7 @@ if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
CLISetup::registerSetup('sql', new class extends SetupScript
|
||||
{
|
||||
use TrDBCcopy;
|
||||
|
||||
@@ -7,14 +7,113 @@ if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
{
|
||||
protected $command = 'emotes';
|
||||
protected $info = array(
|
||||
'emotes' => [[], CLISetup::ARGV_PARAM, 'Compiles data for type: Emote from dbc and GlobalStrings.lua.']
|
||||
);
|
||||
|
||||
protected $dbcSourceFiles = ['emotes', 'emotestext', 'emotestextdata'];
|
||||
protected $useGlobalStrings = true;
|
||||
protected $dbcSourceFiles = ['emotes', 'emotestext', 'emotestextdata'];
|
||||
|
||||
private $textData = [];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
$globStrPath = CLISetup::$srcDir.'%sInterface/FrameXML/GlobalStrings.lua';
|
||||
$allOK = true;
|
||||
$locPath = CLISetup::filesInPathLocalized($globStrPath, $allOK);
|
||||
|
||||
if ($x = array_diff(CLISetup::$localeIds, array_keys($locPath)))
|
||||
{
|
||||
$locs = array_intersect_key(CLISetup::$locales, array_flip($x));
|
||||
CLI::write('[emotes] '.sprintf($globStrPath, CLI::bold('['.implode('/,', $locs).'/]')) . ' not found!', CLI::LOG_WARN);
|
||||
CLI::write(' Emote aliasses can not be generated for affected locales!', CLI::LOG_WARN);
|
||||
}
|
||||
|
||||
DB::Aowow()->query('TRUNCATE ?_emotes');
|
||||
DB::Aowow()->query('TRUNCATE ?_emotes_aliasses');
|
||||
|
||||
|
||||
/*********************/
|
||||
/* Player controlled */
|
||||
/*********************/
|
||||
|
||||
/* EmotesText Data offsets
|
||||
gender seenBy hasTarget mergedWith example
|
||||
0 male others yes 8 %s raises <his/her> fist in anger at %s.
|
||||
1 male self yes 9 %s raises <his/her> fist in anger at you.
|
||||
2 self self yes You raise your fist in anger at %s.
|
||||
4 male others no 12 %s raises <his/her> fist in anger.
|
||||
6 self self no You raise your fist in anger.
|
||||
8 female others yes 0 -
|
||||
9 female self yes 1 -
|
||||
12 female others no 4 -
|
||||
*/
|
||||
|
||||
$this->textData = DB::Aowow()->select('SELECT id AS ARRAY_KEY, text_loc0 AS "0", text_loc2 AS "2", text_loc3 AS "3", text_loc4 AS "4", text_loc6 AS "6", text_loc8 AS "8" FROM dbc_emotestextdata');
|
||||
|
||||
$texts = DB::Aowow()->select('SELECT et.id AS ARRAY_KEY, LOWER(command) AS `cmd`, IF(e.animationId, 1, 0) AS `anim`, -emoteId AS "parent", e.soundId, etd0, etd1, etd2, etd4, etd6, etd8, etd9, etd12 FROM dbc_emotestext et LEFT JOIN dbc_emotes e ON e.id = et.emoteId');
|
||||
foreach ($texts AS $id => $t)
|
||||
{
|
||||
DB::Aowow()->query(
|
||||
'INSERT INTO ?_emotes (
|
||||
`id`, `cmd`, `isAnimated`, `parentEmote`, `soundId`,
|
||||
`extToExt_loc0`, `extToMe_loc0`, `meToExt_loc0`, `extToNone_loc0`, `meToNone_loc0`,
|
||||
`extToExt_loc2`, `extToMe_loc2`, `meToExt_loc2`, `extToNone_loc2`, `meToNone_loc2`,
|
||||
`extToExt_loc3`, `extToMe_loc3`, `meToExt_loc3`, `extToNone_loc3`, `meToNone_loc3`,
|
||||
`extToExt_loc4`, `extToMe_loc4`, `meToExt_loc4`, `extToNone_loc4`, `meToNone_loc4`,
|
||||
`extToExt_loc6`, `extToMe_loc6`, `meToExt_loc6`, `extToNone_loc6`, `meToNone_loc6`,
|
||||
`extToExt_loc8`, `extToMe_loc8`, `meToExt_loc8`, `extToNone_loc8`, `meToNone_loc8`)
|
||||
VALUES
|
||||
(?d, ?, ?d, ?d, ?d, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
$id, $t['cmd'], $t['anim'], $t['parent'], $t['soundId'],
|
||||
$this->mergeGenderedStrings($t['etd0'], $t['etd8'], LOCALE_EN), $this->mergeGenderedStrings($t['etd1'], $t['etd9'], LOCALE_EN), $this->mergeGenderedStrings($t['etd4'], $t['etd12'], LOCALE_EN), $this->textData[$t['etd2']][LOCALE_EN] ?? '', $this->textData[$t['etd6']][LOCALE_EN] ?? '',
|
||||
$this->mergeGenderedStrings($t['etd0'], $t['etd8'], LOCALE_FR), $this->mergeGenderedStrings($t['etd1'], $t['etd9'], LOCALE_FR), $this->mergeGenderedStrings($t['etd4'], $t['etd12'], LOCALE_FR), $this->textData[$t['etd2']][LOCALE_FR] ?? '', $this->textData[$t['etd6']][LOCALE_FR] ?? '',
|
||||
$this->mergeGenderedStrings($t['etd0'], $t['etd8'], LOCALE_DE), $this->mergeGenderedStrings($t['etd1'], $t['etd9'], LOCALE_DE), $this->mergeGenderedStrings($t['etd4'], $t['etd12'], LOCALE_DE), $this->textData[$t['etd2']][LOCALE_DE] ?? '', $this->textData[$t['etd6']][LOCALE_DE] ?? '',
|
||||
$this->mergeGenderedStrings($t['etd0'], $t['etd8'], LOCALE_CN), $this->mergeGenderedStrings($t['etd1'], $t['etd9'], LOCALE_CN), $this->mergeGenderedStrings($t['etd4'], $t['etd12'], LOCALE_CN), $this->textData[$t['etd2']][LOCALE_CN] ?? '', $this->textData[$t['etd6']][LOCALE_CN] ?? '',
|
||||
$this->mergeGenderedStrings($t['etd0'], $t['etd8'], LOCALE_ES), $this->mergeGenderedStrings($t['etd1'], $t['etd9'], LOCALE_ES), $this->mergeGenderedStrings($t['etd4'], $t['etd12'], LOCALE_ES), $this->textData[$t['etd2']][LOCALE_ES] ?? '', $this->textData[$t['etd6']][LOCALE_ES] ?? '',
|
||||
$this->mergeGenderedStrings($t['etd0'], $t['etd8'], LOCALE_RU), $this->mergeGenderedStrings($t['etd1'], $t['etd9'], LOCALE_RU), $this->mergeGenderedStrings($t['etd4'], $t['etd12'], LOCALE_RU), $this->textData[$t['etd2']][LOCALE_RU] ?? '', $this->textData[$t['etd6']][LOCALE_RU] ?? ''
|
||||
);
|
||||
}
|
||||
|
||||
// i have no idea, how the indexing in this file works.
|
||||
// sometimes the \d+ after EMOTE is the emoteTextId, but not nearly often enough
|
||||
$aliasses = [];
|
||||
foreach (CLISetup::searchGlobalStrings('/^EMOTE(\d+)_CMD\d+\s=\s\"\/([^"]+)\";$/') as $lId => $match)
|
||||
$aliasses[$match[1]][] = [$lId, $match[2]];
|
||||
|
||||
$emotes = DB::Aowow()->selectCol('SELECT id AS ARRAY_KEY, cmd FROM ?_emotes');
|
||||
|
||||
foreach($emotes as $eId => $cmd)
|
||||
{
|
||||
foreach ($aliasses as $data)
|
||||
{
|
||||
if (!in_array($cmd, array_column($data, 1)))
|
||||
continue;
|
||||
|
||||
foreach ($data as $d)
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_emotes_aliasses VALUES (?d, ?d, ?) ON DUPLICATE KEY UPDATE locales = locales | ?d', $eId, (1 << $d[0]), strtolower($d[1]), (1 << $d[0]));
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_emotes SET `cuFlags` = `cuFlags` | ?d WHERE `id` = ?d', CUSTOM_EXCLUDE_FOR_LISTVIEW | EMOTE_CU_MISSING_CMD, $eId);
|
||||
}
|
||||
|
||||
|
||||
/*********************/
|
||||
/* Server controlled */
|
||||
/*********************/
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_emotes (`id`, `cmd`, `flags`, `isAnimated`, `parentEmote`, `soundId`, `state`, `stateParam`, `cuFlags`) SELECT -`id`, `name`, `flags`, IF(`animationId`, 1, 0), 0, `soundId`, `state`, `stateParam`, ?d FROM dbc_emotes WHERE 1', CUSTOM_EXCLUDE_FOR_LISTVIEW);
|
||||
|
||||
|
||||
$this->reapplyCCFlags('emotes', Type::EMOTE);
|
||||
|
||||
return $allOK;
|
||||
}
|
||||
|
||||
private function mergeGenderedStrings(int $maleTextId, int $femaleTextId, int $locale) : string
|
||||
{
|
||||
$maleText = $this->textData[$maleTextId][$locale] ?? '';
|
||||
@@ -77,121 +176,6 @@ SqlGen::register(new class extends SetupScript
|
||||
|
||||
return implode(' ', array_merge($front, [$mid], array_reverse($back)));
|
||||
}
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
/**********/
|
||||
/* Basics */
|
||||
/**********/
|
||||
|
||||
$globStrPath = CLISetup::$srcDir.'%sInterface/FrameXML/GlobalStrings.lua';
|
||||
$allOK = true;
|
||||
$locPath = [];
|
||||
|
||||
DB::Aowow()->query('TRUNCATE ?_emotes');
|
||||
DB::Aowow()->query('TRUNCATE ?_emotes_aliasses');
|
||||
|
||||
/*********************/
|
||||
/* Player controlled */
|
||||
/*********************/
|
||||
|
||||
foreach (CLISetup::$localeIds as $lId)
|
||||
{
|
||||
foreach (CLISetup::$expectedPaths as $xp => $locId)
|
||||
{
|
||||
if ($lId != $locId)
|
||||
continue;
|
||||
|
||||
if ($xp) // if in subDir add trailing slash
|
||||
$xp .= '/';
|
||||
|
||||
$path = sprintf($globStrPath, $xp);
|
||||
if (CLISetup::fileExists($path))
|
||||
{
|
||||
$locPath[$lId] = $path;
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
CLI::write('GlobalStrings.lua not found for selected locale '.CLI::bold(Util::$localeStrings[$lId]), CLI::LOG_WARN);
|
||||
$allOK = false;
|
||||
}
|
||||
|
||||
/* EmotesText Data offsets
|
||||
gender seenBy hasTarget mergedWith example
|
||||
0 male others yes 8 %s raises <his/her> fist in anger at %s.
|
||||
1 male self yes 9 %s raises <his/her> fist in anger at you.
|
||||
2 self self yes You raise your fist in anger at %s.
|
||||
4 male others no 12 %s raises <his/her> fist in anger.
|
||||
6 self self no You raise your fist in anger.
|
||||
8 female others yes 0 -
|
||||
9 female self yes 1 -
|
||||
12 female others no 4 -
|
||||
*/
|
||||
|
||||
$this->textData = DB::Aowow()->select('SELECT id AS ARRAY_KEY, text_loc0 AS "0", text_loc2 AS "2", text_loc3 AS "3", text_loc4 AS "4", text_loc6 AS "6", text_loc8 AS "8" FROM dbc_emotestextdata');
|
||||
|
||||
$texts = DB::Aowow()->select('SELECT et.id AS ARRAY_KEY, LOWER(command) AS `cmd`, IF(e.animationId, 1, 0) AS `anim`, -emoteId AS "parent", e.soundId, etd0, etd1, etd2, etd4, etd6, etd8, etd9, etd12 FROM dbc_emotestext et LEFT JOIN dbc_emotes e ON e.id = et.emoteId');
|
||||
foreach ($texts AS $id => $t)
|
||||
{
|
||||
DB::Aowow()->query(
|
||||
'INSERT INTO ?_emotes (
|
||||
`id`, `cmd`, `isAnimated`, `parentEmote`, `soundId`,
|
||||
`extToExt_loc0`, `extToMe_loc0`, `meToExt_loc0`, `extToNone_loc0`, `meToNone_loc0`,
|
||||
`extToExt_loc2`, `extToMe_loc2`, `meToExt_loc2`, `extToNone_loc2`, `meToNone_loc2`,
|
||||
`extToExt_loc3`, `extToMe_loc3`, `meToExt_loc3`, `extToNone_loc3`, `meToNone_loc3`,
|
||||
`extToExt_loc4`, `extToMe_loc4`, `meToExt_loc4`, `extToNone_loc4`, `meToNone_loc4`,
|
||||
`extToExt_loc6`, `extToMe_loc6`, `meToExt_loc6`, `extToNone_loc6`, `meToNone_loc6`,
|
||||
`extToExt_loc8`, `extToMe_loc8`, `meToExt_loc8`, `extToNone_loc8`, `meToNone_loc8`)
|
||||
VALUES
|
||||
(?d, ?, ?d, ?d, ?d, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
$id, $t['cmd'], $t['anim'], $t['parent'], $t['soundId'],
|
||||
$this->mergeGenderedStrings($t['etd0'], $t['etd8'], LOCALE_EN), $this->mergeGenderedStrings($t['etd1'], $t['etd9'], LOCALE_EN), $this->mergeGenderedStrings($t['etd4'], $t['etd12'], LOCALE_EN), $this->textData[$t['etd2']][LOCALE_EN] ?? '', $this->textData[$t['etd6']][LOCALE_EN] ?? '',
|
||||
$this->mergeGenderedStrings($t['etd0'], $t['etd8'], LOCALE_FR), $this->mergeGenderedStrings($t['etd1'], $t['etd9'], LOCALE_FR), $this->mergeGenderedStrings($t['etd4'], $t['etd12'], LOCALE_FR), $this->textData[$t['etd2']][LOCALE_FR] ?? '', $this->textData[$t['etd6']][LOCALE_FR] ?? '',
|
||||
$this->mergeGenderedStrings($t['etd0'], $t['etd8'], LOCALE_DE), $this->mergeGenderedStrings($t['etd1'], $t['etd9'], LOCALE_DE), $this->mergeGenderedStrings($t['etd4'], $t['etd12'], LOCALE_DE), $this->textData[$t['etd2']][LOCALE_DE] ?? '', $this->textData[$t['etd6']][LOCALE_DE] ?? '',
|
||||
$this->mergeGenderedStrings($t['etd0'], $t['etd8'], LOCALE_CN), $this->mergeGenderedStrings($t['etd1'], $t['etd9'], LOCALE_CN), $this->mergeGenderedStrings($t['etd4'], $t['etd12'], LOCALE_CN), $this->textData[$t['etd2']][LOCALE_CN] ?? '', $this->textData[$t['etd6']][LOCALE_CN] ?? '',
|
||||
$this->mergeGenderedStrings($t['etd0'], $t['etd8'], LOCALE_ES), $this->mergeGenderedStrings($t['etd1'], $t['etd9'], LOCALE_ES), $this->mergeGenderedStrings($t['etd4'], $t['etd12'], LOCALE_ES), $this->textData[$t['etd2']][LOCALE_ES] ?? '', $this->textData[$t['etd6']][LOCALE_ES] ?? '',
|
||||
$this->mergeGenderedStrings($t['etd0'], $t['etd8'], LOCALE_RU), $this->mergeGenderedStrings($t['etd1'], $t['etd9'], LOCALE_RU), $this->mergeGenderedStrings($t['etd4'], $t['etd12'], LOCALE_RU), $this->textData[$t['etd2']][LOCALE_RU] ?? '', $this->textData[$t['etd6']][LOCALE_RU] ?? ''
|
||||
);
|
||||
}
|
||||
|
||||
// i have no idea, how the indexing in this file works.
|
||||
// sometimes the \d+ after EMOTE is the emoteTextId, but not nearly often enough
|
||||
$aliasses = [];
|
||||
foreach ($locPath as $lId => $path)
|
||||
foreach (file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) as $line)
|
||||
if (preg_match('/^EMOTE(\d+)_CMD\d+\s=\s\"\/([^"]+)\";$/', $line, $m))
|
||||
$aliasses[$m[1]][] = [$lId, $m[2]];
|
||||
|
||||
$emotes = DB::Aowow()->selectCol('SELECT id AS ARRAY_KEY, cmd FROM ?_emotes');
|
||||
|
||||
foreach($emotes as $eId => $cmd)
|
||||
{
|
||||
foreach ($aliasses as $data)
|
||||
{
|
||||
if (in_array($cmd, array_column($data, 1)))
|
||||
{
|
||||
foreach ($data as $d)
|
||||
DB::Aowow()->query('INSERT IGNORE INTO ?_emotes_aliasses VALUES (?d, ?d, ?) ON DUPLICATE KEY UPDATE locales = locales | ?d', $eId, (1 << $d[0]), strtolower($d[1]), (1 << $d[0]));
|
||||
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_emotes SET `cuFlags` = `cuFlags` | ?d WHERE `id` = ?d', CUSTOM_EXCLUDE_FOR_LISTVIEW | EMOTE_CU_MISSING_CMD, $eId);
|
||||
}
|
||||
|
||||
/*********************/
|
||||
/* Server controlled */
|
||||
/*********************/
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?_emotes (`id`, `cmd`, `flags`, `isAnimated`, `parentEmote`, `soundId`, `state`, `stateParam`, `cuFlags`) SELECT -`id`, `name`, `flags`, IF(`animationId`, 1, 0), 0, `soundId`, `state`, `stateParam`, ?d FROM dbc_emotes WHERE 1', CUSTOM_EXCLUDE_FOR_LISTVIEW);
|
||||
|
||||
|
||||
$this->reapplyCCFlags('emotes', Type::EMOTE);
|
||||
|
||||
return $allOK;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
{
|
||||
protected $command = 'events';
|
||||
|
||||
protected $tblDependencyTC = ['game_event', 'game_event_prerequisite'];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
$eventQuery = '
|
||||
SELECT
|
||||
ge.eventEntry,
|
||||
holiday,
|
||||
0, -- cuFlags
|
||||
IFNULL(UNIX_TIMESTAMP(start_time), 0),
|
||||
IFNULL(UNIX_TIMESTAMP(end_time), 0),
|
||||
occurence * 60,
|
||||
length * 60,
|
||||
IF (gep.eventEntry IS NOT NULL, GROUP_CONCAT(prerequisite_event SEPARATOR " "), NULL),
|
||||
description
|
||||
FROM
|
||||
game_event ge
|
||||
LEFT JOIN
|
||||
game_event_prerequisite gep ON gep.eventEntry = ge.eventEntry
|
||||
{
|
||||
WHERE
|
||||
ge.eventEntry IN (?a)
|
||||
}
|
||||
GROUP BY
|
||||
ge.eventEntry';
|
||||
|
||||
$events = DB::World()->select($eventQuery, $ids ?: DBSIMPLE_SKIP);
|
||||
|
||||
foreach ($events as $e)
|
||||
DB::Aowow()->query('REPLACE INTO ?_events VALUES (?a)', array_values($e));
|
||||
|
||||
$this->reapplyCCFlags('events', Type::WORLDEVENT);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
48
setup/tools/sqlgen/events.ss.php
Normal file
48
setup/tools/sqlgen/events.ss.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
{
|
||||
protected $info = array(
|
||||
'events' => [[], CLISetup::ARGV_PARAM, 'Compiles data for type: Event from world db.']
|
||||
);
|
||||
|
||||
protected $worldDependency = ['game_event', 'game_event_prerequisite'];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
DB::Aowow()->query('TRUNCATE ?_events');
|
||||
|
||||
$events = DB::World()->select(
|
||||
'SELECT ge.eventEntry,
|
||||
holiday,
|
||||
0, -- cuFlags
|
||||
IFNULL(UNIX_TIMESTAMP(start_time), 0),
|
||||
IFNULL(UNIX_TIMESTAMP(end_time), 0),
|
||||
occurence * 60,
|
||||
length * 60,
|
||||
IF (gep.eventEntry IS NOT NULL, GROUP_CONCAT(prerequisite_event SEPARATOR " "), NULL),
|
||||
description
|
||||
FROM game_event ge
|
||||
LEFT JOIN game_event_prerequisite gep ON gep.eventEntry = ge.eventEntry
|
||||
{ WHERE ge.eventEntry IN (?a) }
|
||||
GROUP BY ge.eventEntry',
|
||||
$ids ?: DBSIMPLE_SKIP
|
||||
);
|
||||
|
||||
foreach ($events as $e)
|
||||
DB::Aowow()->query('INSERT INTO ?_events VALUES (?a)', array_values($e));
|
||||
|
||||
$this->reapplyCCFlags('events', Type::WORLDEVENT);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,105 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
{
|
||||
use TrCustomData; // import custom data from DB
|
||||
|
||||
protected $command = 'factions';
|
||||
|
||||
protected $dbcSourceFiles = ['faction', 'factiontemplate'];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
$factionQuery = '
|
||||
REPLACE INTO
|
||||
?_factions
|
||||
SELECT
|
||||
f.id,
|
||||
f.repIdx,
|
||||
baseRepRaceMask1, baseRepRaceMask2, baseRepRaceMask3, baseRepRaceMask4,
|
||||
baseRepClassMask1, baseRepClassMask2, baseRepClassMask3, baseRepClassMask4,
|
||||
baseRepValue1, baseRepValue2, baseRepValue3, baseRepValue4,
|
||||
IF(SUM(ft.ourMask & 0x6) / COUNT(1) = 0x4, 2, IF(SUM(ft.ourMask & 0x6) / COUNT(1) = 0x2, 1, 0)) as side,
|
||||
0, -- expansion
|
||||
"", -- quartermasterNpcIds
|
||||
"", -- factionTemplateIds
|
||||
0, -- cuFlags
|
||||
parentFaction,
|
||||
spilloverRateIn, spilloverRateOut, spilloverMaxRank,
|
||||
name_loc0, name_loc2, name_loc3, name_loc4, name_loc6, name_loc8
|
||||
FROM
|
||||
dbc_faction f
|
||||
LEFT JOIN
|
||||
dbc_factiontemplate ft ON ft.factionid = f.id
|
||||
GROUP BY
|
||||
f.id';
|
||||
|
||||
$templateQuery = '
|
||||
UPDATE
|
||||
?_factions f
|
||||
JOIN
|
||||
(SELECT ft.factionId, GROUP_CONCAT(ft.id SEPARATOR " ") AS tplIds FROM dbc_factiontemplate ft GROUP BY ft.factionId) temp ON f.id = temp.factionId
|
||||
SET
|
||||
f.templateIds = temp.tplIds';
|
||||
|
||||
$recursiveUpdateQuery = '
|
||||
UPDATE
|
||||
?_factions top
|
||||
JOIN
|
||||
(SELECT id, parentFactionId FROM ?_factions) mid ON mid.parentFactionId IN (?a)
|
||||
LEFT JOIN
|
||||
(SELECT id, parentFactionId FROM ?_factions) low ON low.parentFactionId = mid.id
|
||||
SET
|
||||
?a
|
||||
WHERE
|
||||
repIdx > 0 AND (
|
||||
top.id IN (?a) OR
|
||||
top.id = mid.id OR
|
||||
top.id = low.id
|
||||
)';
|
||||
|
||||
$excludeQuery = '
|
||||
UPDATE
|
||||
?_factions x
|
||||
JOIN
|
||||
dbc_faction f ON f.id = x.id
|
||||
LEFT JOIN
|
||||
dbc_factiontemplate ft ON f.id = ft.factionId
|
||||
SET
|
||||
cuFlags = cuFlags | ?d
|
||||
WHERE
|
||||
f.repIdx < 0 OR
|
||||
(
|
||||
f.repIdx > 0 AND
|
||||
(f.repFlags1 & 0x8 OR ft.id IS NULL) AND
|
||||
(f.repFlags1 & 0x80) = 0
|
||||
)';
|
||||
|
||||
$pairs = array(
|
||||
[[980], ['expansion' => 1]],
|
||||
[[1097], ['expansion' => 2]],
|
||||
[[469, 891, 1037], ['side' => 1]],
|
||||
[[ 67, 892, 1052], ['side' => 2]],
|
||||
);
|
||||
|
||||
DB::Aowow()->query($factionQuery);
|
||||
DB::Aowow()->query($templateQuery);
|
||||
DB::Aowow()->query($excludeQuery, CUSTOM_EXCLUDE_FOR_LISTVIEW);
|
||||
|
||||
foreach ($pairs as $p)
|
||||
DB::Aowow()->query($recursiveUpdateQuery, $p[0], $p[1], $p[0]);
|
||||
|
||||
$this->reapplyCCFlags('factions', Type::FACTION);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
94
setup/tools/sqlgen/factions.ss.php
Normal file
94
setup/tools/sqlgen/factions.ss.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
{
|
||||
use TrCustomData; // import custom data from DB
|
||||
|
||||
protected $info = array(
|
||||
'factions' => [[], CLISetup::ARGV_PARAM, 'Compiles data for type: Faction from dbc.']
|
||||
);
|
||||
|
||||
protected $dbcSourceFiles = ['faction', 'factiontemplate'];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
DB::Aowow()->query('TRUNCATE ?_factions');
|
||||
DB::Aowow()->query('TRUNCATE ?_factiontemplate');
|
||||
|
||||
DB::Aowow()->query(
|
||||
'INSERT INTO ?_factions
|
||||
SELECT f.id,
|
||||
f.repIdx,
|
||||
baseRepRaceMask1, baseRepRaceMask2, baseRepRaceMask3, baseRepRaceMask4,
|
||||
baseRepClassMask1, baseRepClassMask2, baseRepClassMask3, baseRepClassMask4,
|
||||
baseRepValue1, baseRepValue2, baseRepValue3, baseRepValue4,
|
||||
IF(SUM(ft.ourMask & 0x6) / COUNT(1) = 0x4, 2, IF(SUM(ft.ourMask & 0x6) / COUNT(1) = 0x2, 1, 0)) as side,
|
||||
0, -- expansion
|
||||
"", -- quartermasterNpcIds
|
||||
"", -- factionTemplateIds
|
||||
0, -- cuFlags
|
||||
parentFaction,
|
||||
spilloverRateIn, spilloverRateOut, spilloverMaxRank,
|
||||
name_loc0, name_loc2, name_loc3, name_loc4, name_loc6, name_loc8
|
||||
FROM dbc_faction f
|
||||
LEFT JOIN dbc_factiontemplate ft ON ft.factionid = f.id
|
||||
GROUP BY f.id'
|
||||
);
|
||||
|
||||
DB::Aowow()->query(
|
||||
'INSERT INTO ?_factiontemplate
|
||||
SELECT id,
|
||||
factionId,
|
||||
IF(friendFactionId1 = 1 OR friendFactionId2 = 1 OR friendFactionId3 = 1 OR friendFactionId4 = 1 OR friendlyMask & 0x3, 1,
|
||||
IF(enemyFactionId1 = 1 OR enemyFactionId2 = 1 OR enemyFactionId3 = 1 OR enemyFactionId4 = 1 OR hostileMask & 0x3, -1, 0)),
|
||||
IF(friendFactionId1 = 2 OR friendFactionId2 = 2 OR friendFactionId3 = 2 OR friendFactionId4 = 2 OR friendlyMask & 0x5, 1,
|
||||
IF(enemyFactionId1 = 2 OR enemyFactionId2 = 2 OR enemyFactionId3 = 2 OR enemyFactionId4 = 2 OR hostileMask & 0x5, -1, 0))
|
||||
FROM dbc_factiontemplate'
|
||||
);
|
||||
|
||||
DB::Aowow()->query(
|
||||
'UPDATE ?_factions f
|
||||
JOIN (SELECT ft.factionId, GROUP_CONCAT(ft.id SEPARATOR " ") AS tplIds FROM dbc_factiontemplate ft GROUP BY ft.factionId) temp ON f.id = temp.factionId
|
||||
SET f.templateIds = temp.tplIds'
|
||||
);
|
||||
|
||||
DB::Aowow()->query(
|
||||
'UPDATE ?_factions x
|
||||
JOIN dbc_faction f ON f.id = x.id
|
||||
LEFT JOIN dbc_factiontemplate ft ON f.id = ft.factionId
|
||||
SET cuFlags = cuFlags | ?d
|
||||
WHERE f.repIdx < 0 OR ( f.repIdx > 0 AND (f.repFlags1 & 0x8 OR ft.id IS NULL) AND (f.repFlags1 & 0x80) = 0 )',
|
||||
CUSTOM_EXCLUDE_FOR_LISTVIEW
|
||||
);
|
||||
|
||||
$pairs = array(
|
||||
[[980], ['expansion' => 1]],
|
||||
[[1097], ['expansion' => 2]],
|
||||
[[469, 891, 1037], ['side' => 1]],
|
||||
[[ 67, 892, 1052], ['side' => 2]],
|
||||
);
|
||||
|
||||
foreach ($pairs as $p)
|
||||
DB::Aowow()->query(
|
||||
'UPDATE ?_factions top
|
||||
JOIN (SELECT id, parentFactionId FROM ?_factions) mid ON mid.parentFactionId IN (?a)
|
||||
LEFT JOIN (SELECT id, parentFactionId FROM ?_factions) low ON low.parentFactionId = mid.id
|
||||
SET ?a
|
||||
WHERE repIdx > 0 AND (top.id IN (?a) OR top.id = mid.id OR top.id = low.id)',
|
||||
$p[0], $p[1], $p[0]
|
||||
);
|
||||
|
||||
$this->reapplyCCFlags('factions', Type::FACTION);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,41 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
{
|
||||
protected $command = 'factiontemplate';
|
||||
|
||||
protected $dbcSourceFiles = ['factiontemplate'];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
$query = '
|
||||
REPLACE INTO
|
||||
?_factiontemplate
|
||||
SELECT
|
||||
id,
|
||||
factionId,
|
||||
IF(friendFactionId1 = 1 OR friendFactionId2 = 1 OR friendFactionId3 = 1 OR friendFactionId4 = 1 OR friendlyMask & 0x3,
|
||||
1,
|
||||
IF(enemyFactionId1 = 1 OR enemyFactionId2 = 1 OR enemyFactionId3 = 1 OR enemyFactionId4 = 1 OR hostileMask & 0x3, -1, 0)
|
||||
),
|
||||
IF(friendFactionId1 = 2 OR friendFactionId2 = 2 OR friendFactionId3 = 2 OR friendFactionId4 = 2 OR friendlyMask & 0x5,
|
||||
1,
|
||||
IF(enemyFactionId1 = 2 OR enemyFactionId2 = 2 OR enemyFactionId3 = 2 OR enemyFactionId4 = 2 OR hostileMask & 0x5, -1, 0)
|
||||
)
|
||||
FROM
|
||||
dbc_factiontemplate';
|
||||
|
||||
DB::Aowow()->query($query);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
{
|
||||
protected $command = 'glyphproperties';
|
||||
|
||||
protected $tblDependencyAowow = ['icons'];
|
||||
protected $dbcSourceFiles = ['glyphproperties', 'spellicon'];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
DB::Aowow()->query('REPLACE INTO ?_glyphproperties SELECT id, spellId, typeFlags, 0, iconId FROM dbc_glyphproperties');
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_glyphproperties gp, ?_icons ic, dbc_spellicon si SET gp.iconId = ic.id WHERE gp.iconIdBak = si.id AND ic.name = LOWER(SUBSTRING_INDEX(si.iconPath, "\\\\", -1))');
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
30
setup/tools/sqlgen/glyphproperties.ss.php
Normal file
30
setup/tools/sqlgen/glyphproperties.ss.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
{
|
||||
protected $info = array(
|
||||
'glyphproperties' => [[], CLISetup::ARGV_PARAM, 'Compiles supplemental data for type: Item & Spell from dbc.']
|
||||
);
|
||||
|
||||
protected $dbcSourceFiles = ['glyphproperties', 'spellicon'];
|
||||
protected $setupAfter = [['icons'], []];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
DB::Aowow()->query('TRUNCATE ?_glyphproperties');
|
||||
DB::Aowow()->query('INSERT INTO ?_glyphproperties SELECT id, spellId, typeFlags, 0, iconId FROM dbc_glyphproperties');
|
||||
|
||||
DB::Aowow()->query('UPDATE ?_glyphproperties gp, ?_icons ic, dbc_spellicon si SET gp.iconId = ic.id WHERE gp.iconIdBak = si.id AND ic.name = LOWER(SUBSTRING_INDEX(si.iconPath, "\\\\", -1))');
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
{
|
||||
use TrCustomData; // import custom data from DB
|
||||
|
||||
protected $command = 'holidays';
|
||||
|
||||
protected $dbcSourceFiles = ['holidays', 'holidaydescriptions', 'holidaynames'];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
$query = '
|
||||
REPLACE 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';
|
||||
|
||||
DB::Aowow()->query($query);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
36
setup/tools/sqlgen/holidays.ss.php
Normal file
36
setup/tools/sqlgen/holidays.ss.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
// really should be part of events.func.php, but applying the custom data prevents this for now
|
||||
CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
{
|
||||
use TrCustomData; // import custom data from DB
|
||||
|
||||
protected $info = array(
|
||||
'holidays' => [[], CLISetup::ARGV_PARAM, 'Compiles supplemental data for type: Event from dbc.']
|
||||
);
|
||||
|
||||
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
|
||||
FROM dbc_holidays h
|
||||
LEFT JOIN dbc_holidaynames n ON n.id = h.nameId
|
||||
LEFT JOIN dbc_holidaydescriptions d ON d.id = h.descriptionId'
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -7,9 +7,11 @@ if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
{
|
||||
protected $command = 'icons';
|
||||
protected $info = array(
|
||||
'icons' => [[], CLISetup::ARGV_PARAM, 'Compiles data for type: Icons from dbc.']
|
||||
);
|
||||
|
||||
protected $dbcSourceFiles = ['spellicon', 'itemdisplayinfo', 'creaturefamily'];
|
||||
|
||||
@@ -17,20 +19,14 @@ SqlGen::register(new class extends SetupScript
|
||||
{
|
||||
DB::Aowow()->query('TRUNCATE ?_icons');
|
||||
DB::Aowow()->query('ALTER TABLE ?_icons AUTO_INCREMENT = 1');
|
||||
|
||||
$baseQuery = '
|
||||
INSERT INTO ?_icons (`name`) SELECT x FROM
|
||||
DB::Aowow()->query(
|
||||
'INSERT INTO ?_icons (`name`) SELECT 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%")
|
||||
) y
|
||||
GROUP BY
|
||||
x';
|
||||
|
||||
DB::Aowow()->query($baseQuery);
|
||||
(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'
|
||||
);
|
||||
|
||||
$this->reapplyCCFlags('icons', Type::ICON);
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
{
|
||||
protected $command = 'itemenchantment';
|
||||
|
||||
protected $tblDependencyTC = ['spell_enchant_proc_data'];
|
||||
protected $dbcSourceFiles = ['spellitemenchantment'];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
$baseQuery = '
|
||||
REPLACE INTO
|
||||
?_itemenchantment
|
||||
SELECT
|
||||
Id, charges, 0, 0, 0, type1, type2, type3, amount1, amount2, amount3, object1, object2, object3, name_loc0, name_loc2, name_loc3, name_loc4, name_loc6, name_loc8, conditionId, skillLine, skillLevel, requiredLevel
|
||||
FROM
|
||||
dbc_spellitemenchantment';
|
||||
|
||||
DB::Aowow()->query($baseQuery);
|
||||
|
||||
$cuProcs = DB::World()->select('SELECT EnchantID AS ARRAY_KEY, Chance AS procChance, ProcsPerMinute AS ppmRate FROM spell_enchant_proc_data');
|
||||
foreach ($cuProcs as $id => $vals)
|
||||
DB::Aowow()->query('UPDATE ?_itemenchantment SET ?a WHERE id = ?d', $vals, $id);
|
||||
|
||||
// hide strange stuff
|
||||
DB::Aowow()->query('UPDATE ?_itemenchantment SET cuFlags = ?d WHERE type1 = 0 AND type2 = 0 AND type3 = 0', CUSTOM_EXCLUDE_FOR_LISTVIEW);
|
||||
DB::Aowow()->query('UPDATE ?_itemenchantment SET cuFlags = ?d WHERE name_loc0 LIKE "%test%"', CUSTOM_EXCLUDE_FOR_LISTVIEW);
|
||||
|
||||
$this->reapplyCCFlags('itemenchantment', Type::ENCHANTMENT);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
42
setup/tools/sqlgen/itemenchantment.ss.php
Normal file
42
setup/tools/sqlgen/itemenchantment.ss.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
{
|
||||
protected $info = array(
|
||||
'itemenchantment' => [[], CLISetup::ARGV_PARAM, 'Compiles data for type: Enchantment from dbc and world db.']
|
||||
);
|
||||
|
||||
protected $dbcSourceFiles = ['spellitemenchantment'];
|
||||
protected $worldDependency = ['spell_enchant_proc_data'];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
DB::Aowow()->query('TRUNCATE ?_itemenchantment');
|
||||
DB::Aowow()->query(
|
||||
'INSERT INTO ?_itemenchantment
|
||||
SELECT `Id`, `charges`, 0, 0, 0, `type1`, `type2`, `type3`, `amount1`, `amount2`, `amount3`, `object1`, `object2`, `object3`, `name_loc0`, `name_loc2`, `name_loc3`, `name_loc4`, `name_loc6`, `name_loc8`, `conditionId`, `skillLine`, `skillLevel`, `requiredLevel`
|
||||
FROM dbc_spellitemenchantment'
|
||||
);
|
||||
|
||||
$cuProcs = DB::World()->select('SELECT `EnchantID` AS ARRAY_KEY, `Chance` AS `procChance`, `ProcsPerMinute` AS `ppmRate` FROM spell_enchant_proc_data');
|
||||
foreach ($cuProcs as $id => $vals)
|
||||
DB::Aowow()->query('UPDATE ?_itemenchantment SET ?a WHERE `id` = ?d', $vals, $id);
|
||||
|
||||
// hide strange stuff
|
||||
DB::Aowow()->query('UPDATE ?_itemenchantment SET `cuFlags` = ?d WHERE `type1` = 0 AND `type2` = 0 AND `type3` = 0', CUSTOM_EXCLUDE_FOR_LISTVIEW);
|
||||
DB::Aowow()->query('UPDATE ?_itemenchantment SET `cuFlags` = ?d WHERE `name_loc0` LIKE "%test%"', CUSTOM_EXCLUDE_FOR_LISTVIEW);
|
||||
|
||||
$this->reapplyCCFlags('itemenchantment', Type::ENCHANTMENT);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
@@ -7,7 +7,7 @@ if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
{
|
||||
use TrDBCcopy;
|
||||
|
||||
@@ -7,7 +7,7 @@ if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
{
|
||||
use TrDBCcopy;
|
||||
|
||||
@@ -7,7 +7,7 @@ if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
{
|
||||
use TrDBCcopy;
|
||||
|
||||
@@ -7,21 +7,22 @@ if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
{
|
||||
protected $command = 'itemrandomenchant';
|
||||
protected $info = array(
|
||||
'itemrandomenchant' => [[], CLISetup::ARGV_PARAM, 'Compiles supplemental data for type: Item from dbc.']
|
||||
);
|
||||
|
||||
protected $dbcSourceFiles = ['itemrandomsuffix', 'itemrandomproperties'];
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
$query = '
|
||||
REPLACE INTO ?_itemrandomenchant
|
||||
SELECT -id, name_loc0, name_loc2, name_loc3, name_loc4, name_loc6, name_loc8, nameINT, enchantId1, enchantId2, enchantId3, enchantId4, enchantId5, allocationPct1, allocationPct2, allocationPct3, allocationPct4, allocationPct5 FROM dbc_itemrandomsuffix
|
||||
UNION
|
||||
SELECT id, name_loc0, name_loc2, name_loc3, name_loc4, name_loc6, name_loc8, nameINT, enchantId1, enchantId2, enchantId3, enchantId4, enchantId5, 0, 0, 0, 0, 0 FROM dbc_itemrandomproperties';
|
||||
|
||||
DB::Aowow()->query($query);
|
||||
DB::Aowow()->query('TRUNCATE ?_itemrandomenchant');
|
||||
DB::Aowow()->query(
|
||||
'INSERT INTO ?_itemrandomenchant
|
||||
SELECT -id, name_loc0, name_loc2, name_loc3, name_loc4, name_loc6, name_loc8, nameINT, enchantId1, enchantId2, enchantId3, enchantId4, enchantId5, allocationPct1, allocationPct2, allocationPct3, allocationPct4, allocationPct5 FROM dbc_itemrandomsuffix UNION
|
||||
SELECT id, name_loc0, name_loc2, name_loc3, name_loc4, name_loc6, name_loc8, nameINT, enchantId1, enchantId2, enchantId3, enchantId4, enchantId5, 0, 0, 0, 0, 0 FROM dbc_itemrandomproperties'
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -7,7 +7,7 @@ if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
CLISetup::registerSetup("sql", new class extends SetupScript
|
||||
{
|
||||
use TrDBCcopy;
|
||||
|
||||
@@ -1,265 +0,0 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
SqlGen::register(new class extends SetupScript
|
||||
{
|
||||
use TrCustomData; // import custom data from DB
|
||||
|
||||
protected $command = 'items';
|
||||
|
||||
protected $tblDependencyAowow = ['icons'];
|
||||
protected $tblDependencyTC = ['item_template', 'item_template_locale', 'spell_group', 'game_event'];
|
||||
protected $dbcSourceFiles = ['gemproperties', 'itemdisplayinfo', 'spell', 'glyphproperties', 'durabilityquality', 'durabilitycosts'];
|
||||
|
||||
private $skill2cat = array(
|
||||
SKILL_INSCRIPTION => 11,
|
||||
SKILL_FISHING => 9,
|
||||
SKILL_MINING => 12,
|
||||
SKILL_COOKING => 5,
|
||||
SKILL_ALCHEMY => 6
|
||||
);
|
||||
|
||||
public function generate(array $ids = []) : bool
|
||||
{
|
||||
$baseQuery = '
|
||||
SELECT
|
||||
it.entry,
|
||||
class, class as classBak,
|
||||
subclass, subclass AS subClassBak,
|
||||
SoundOverrideSubclass,
|
||||
IFNULL(sg.id, 0) AS subSubClass,
|
||||
it.name, IFNULL(itl2.Name, ""), IFNULL(itl3.Name, ""), IFNULL(itl4.Name, ""), IFNULL(itl6.Name, ""), IFNULL(itl8.Name, ""),
|
||||
0 AS iconId,
|
||||
displayid,
|
||||
0 AS spellVisualId,
|
||||
Quality,
|
||||
Flags, FlagsExtra,
|
||||
BuyCount, BuyPrice, SellPrice,
|
||||
0 AS repairPrice,
|
||||
InventoryType AS slot, InventoryType AS slotBak,
|
||||
AllowableClass, AllowableRace,
|
||||
ItemLevel,
|
||||
RequiredLevel,
|
||||
RequiredSkill, RequiredSkillRank,
|
||||
requiredspell,
|
||||
requiredhonorrank,
|
||||
RequiredCityRank,
|
||||
RequiredReputationFaction,
|
||||
RequiredReputationRank,
|
||||
maxcount,
|
||||
0 AS cuFlags,
|
||||
0 AS model,
|
||||
stackable,
|
||||
ContainerSlots,
|
||||
stat_type1, stat_value1,
|
||||
stat_type2, stat_value2,
|
||||
stat_type3, stat_value3,
|
||||
stat_type4, stat_value4,
|
||||
stat_type5, stat_value5,
|
||||
stat_type6, stat_value6,
|
||||
stat_type7, stat_value7,
|
||||
stat_type8, stat_value8,
|
||||
stat_type9, stat_value9,
|
||||
stat_type10, stat_value10,
|
||||
ScalingStatDistribution,
|
||||
ScalingStatValue,
|
||||
dmg_min1, dmg_max1, dmg_type1,
|
||||
dmg_min2, dmg_max2, dmg_type2,
|
||||
delay,
|
||||
armor, ArmorDamageModifier,
|
||||
block,
|
||||
holy_res, fire_res, nature_res, frost_res, shadow_res, arcane_res,
|
||||
ammo_type,
|
||||
RangedModRange,
|
||||
spellid_1, spelltrigger_1, spellcharges_1, spellppmRate_1, spellcooldown_1, spellcategory_1, spellcategorycooldown_1,
|
||||
spellid_2, spelltrigger_2, spellcharges_2, spellppmRate_2, spellcooldown_2, spellcategory_2, spellcategorycooldown_2,
|
||||
spellid_3, spelltrigger_3, spellcharges_3, spellppmRate_3, spellcooldown_3, spellcategory_3, spellcategorycooldown_3,
|
||||
spellid_4, spelltrigger_4, spellcharges_4, spellppmRate_4, spellcooldown_4, spellcategory_4, spellcategorycooldown_4,
|
||||
spellid_5, spelltrigger_5, spellcharges_5, spellppmRate_5, spellcooldown_5, spellcategory_5, spellcategorycooldown_5,
|
||||
bonding,
|
||||
it.description, IFNULL(itl2.Description, ""), IFNULL(itl3.Description, ""), IFNULL(itl4.Description, ""), IFNULL(itl6.Description, ""), IFNULL(itl8.Description, ""),
|
||||
PageText,
|
||||
LanguageID,
|
||||
startquest,
|
||||
lockid,
|
||||
Material,
|
||||
IF(RandomProperty > 0, RandomProperty, -RandomSuffix) AS randomEnchant,
|
||||
itemset,
|
||||
MaxDurability,
|
||||
area,
|
||||
Map,
|
||||
BagFamily,
|
||||
TotemCategory,
|
||||
socketColor_1, socketContent_1,
|
||||
socketColor_2, socketContent_2,
|
||||
socketColor_3, socketContent_3,
|
||||
socketBonus,
|
||||
GemProperties,
|
||||
RequiredDisenchantSkill,
|
||||
DisenchantID,
|
||||
duration,
|
||||
ItemLimitCategory,
|
||||
IFNULL(ge.eventEntry, 0),
|
||||
ScriptName,
|
||||
FoodType,
|
||||
0 AS gemEnchantmentId,
|
||||
minMoneyLoot, maxMoneyLoot,
|
||||
0 AS pickUpSoundId,
|
||||
0 AS dropDownSoundId,
|
||||
0 AS sheatheSoundId,
|
||||
0 AS unsheatheSoundId,
|
||||
flagsCustom
|
||||
FROM
|
||||
item_template it
|
||||
LEFT JOIN
|
||||
item_template_locale itl2 ON it.entry = itl2.ID AND itl2.locale = "frFR"
|
||||
LEFT JOIN
|
||||
item_template_locale itl3 ON it.entry = itl3.ID AND itl3.locale = "deDE"
|
||||
LEFT JOIN
|
||||
item_template_locale itl4 ON it.entry = itl4.ID AND itl4.locale = "zhCN"
|
||||
LEFT JOIN
|
||||
item_template_locale itl6 ON it.entry = itl6.ID AND itl6.locale = "esES"
|
||||
LEFT JOIN
|
||||
item_template_locale itl8 ON it.entry = itl8.ID AND itl8.locale = "ruRU"
|
||||
LEFT JOIN
|
||||
spell_group sg ON sg.spell_id = it.spellid_1 AND it.class = 0 AND it.subclass = 2 AND sg.id IN (1, 2)
|
||||
LEFT JOIN
|
||||
game_event ge ON ge.holiday = it.HolidayId AND it.HolidayId > 0
|
||||
{
|
||||
WHERE
|
||||
it.entry IN (?a)
|
||||
}
|
||||
LIMIT
|
||||
?d, ?d';
|
||||
|
||||
$i = 0;
|
||||
DB::Aowow()->query('TRUNCATE ?_items');
|
||||
while ($items = DB::World()->select($baseQuery, $ids ?: DBSIMPLE_SKIP, SqlGen::$sqlBatchSize * $i, SqlGen::$sqlBatchSize))
|
||||
{
|
||||
CLI::write(' * batch #' . ++$i . ' (' . count($items) . ')', CLI::LOG_BLANK, true, true);
|
||||
|
||||
foreach ($items as $item)
|
||||
DB::Aowow()->query('INSERT INTO ?_items VALUES (?a)', array_values($item));
|
||||
}
|
||||
|
||||
// merge with gemProperties
|
||||
DB::Aowow()->query('UPDATE ?_items i, dbc_gemproperties gp SET i.gemEnchantmentId = gp.enchantmentId, i.gemColorMask = gp.colorMask WHERE i.gemColorMask = gp.id');
|
||||
|
||||
// get modelString
|
||||
DB::Aowow()->query('UPDATE ?_items i, dbc_itemdisplayinfo idi SET i.model = IF(idi.leftModelName = "", idi.rightModelName, idi.leftModelName) WHERE i.displayId = idi.id');
|
||||
|
||||
// get iconId
|
||||
DB::Aowow()->query('UPDATE ?_items i, dbc_itemdisplayinfo idi, ?_icons ic SET i.iconId = ic.id WHERE i.displayId = idi.id AND LOWER(idi.inventoryIcon1) = ic.name');
|
||||
|
||||
// unify slots: Robes => Chest; Ranged (right) => Ranged
|
||||
DB::Aowow()->query('UPDATE ?_items SET slot = 15 WHERE slotbak = 26');
|
||||
DB::Aowow()->query('UPDATE ?_items SET slot = 5 WHERE slotbak = 20');
|
||||
|
||||
// custom sub-classes
|
||||
DB::Aowow()->query('
|
||||
UPDATE ?_items SET subclass = IF(
|
||||
slotbak = 4, -8, IF( -- shirt
|
||||
slotbak = 19, -7, IF( -- tabard
|
||||
slotbak = 16, -6, IF( -- cloak
|
||||
slotbak = 23, -5, IF( -- held in offhand
|
||||
slotbak = 12, -4, IF( -- trinket
|
||||
slotbak = 2, -3, IF( -- amulet
|
||||
slotbak = 11, -2, subClassBak -- ring
|
||||
))))))) WHERE class = 4');
|
||||
|
||||
// move alchemist stones to trinkets (Armor)
|
||||
DB::Aowow()->query('UPDATE ?_items SET class = 4, subClass = -4 WHERE classBak = 7 AND subClassBak = 11 AND slotBak = 12');
|
||||
|
||||
// mark keys as key (if not quest items)
|
||||
DB::Aowow()->query('UPDATE ?_items SET class = 13, subClass = 0 WHERE classBak IN (0, 15) AND bagFamily & 0x100');
|
||||
|
||||
// set subSubClass for Glyphs (major/minor)
|
||||
DB::Aowow()->query('UPDATE ?_items i, dbc_spell s, dbc_glyphproperties gp SET i.subSubClass = IF(gp.typeFlags & 0x1, 2, 1) WHERE i.spellId1 = s.id AND s.effect1MiscValue = gp.id AND i.classBak = 16');
|
||||
|
||||
// filter misc(class:15) junk(subclass:0) to appropriate categories
|
||||
|
||||
// assign pets and mounts to category
|
||||
DB::Aowow()->query('UPDATE ?_items i, dbc_spell s SET subClass = IF(effect1AuraId <> 78, 2, IF(effect2AuraId = 207 OR effect3AuraId = 207 OR (s.id <> 65917 AND effect2AuraId = 4 AND effect3Id = 77), -7, 5)) WHERE s.id = spellId2 AND class = 15 AND spellId1 IN (?a)', LEARN_SPELLS);
|
||||
|
||||
// more corner cases (mounts that are not actualy learned)
|
||||
DB::Aowow()->query('UPDATE ?_items i, dbc_spell s SET i.subClass = -7 WHERE (effect1Id = 64 OR (effect1AuraId = 78 AND effect2AuraId = 4 AND effect3Id = 77) OR effect1AuraId = 207 OR effect2AuraId = 207 OR effect3AuraId = 207) AND s.id = i.spellId1 AND i.class = 15 AND i.subClass = 5');
|
||||
DB::Aowow()->query('UPDATE ?_items i, dbc_spell s SET i.subClass = 5 WHERE s.effect1AuraId = 78 AND s.id = i.spellId1 AND i.class = 15 AND i.subClass = 0');
|
||||
|
||||
// move some permanent enchantments to own category
|
||||
DB::Aowow()->query('UPDATE ?_items i, dbc_spell s SET i.class = 0, i.subClass = 6 WHERE s.effect1Id = 53 AND s.id = i.spellId1 AND i.class = 15');
|
||||
|
||||
// move temporary enchantments to own category
|
||||
DB::Aowow()->query('UPDATE ?_items i, dbc_spell s SET i.subClass = -3 WHERE s.effect1Id = 54 AND s.id = i.spellId1 AND i.class = 0 AND i.subClassBak = 8');
|
||||
|
||||
// move armor tokens to own category
|
||||
DB::Aowow()->query('UPDATE ?_items SET subClass = -2 WHERE quality = 4 AND class = 15 AND subClassBak = 0 AND requiredClass AND (requiredClass & 0x5FF) <> 0x5FF');
|
||||
|
||||
// move some junk to holiday if it requires one
|
||||
DB::Aowow()->query('UPDATE ?_items SET subClass = 3 WHERE classBak = 15 AND subClassBak = 0 AND eventId <> 0');
|
||||
|
||||
// move misc items that start quests to class: quest (except Sayges scrolls for consistency)
|
||||
DB::Aowow()->query('UPDATE ?_items SET class = 12 WHERE classBak = 15 AND startQuest <> 0 AND name_loc0 NOT LIKE "sayge\'s fortune%"');
|
||||
|
||||
// move perm. enchantments into appropriate cat/subcat
|
||||
DB::Aowow()->query('UPDATE ?_items i, dbc_spell s SET i.class = 0, i.subClass = 6 WHERE s.id = i.spellId1 AND s.effect1Id = 53 AND i.classBak = 12');
|
||||
|
||||
// move some generic recipes into appropriate sub-categories
|
||||
foreach ($this->skill2cat as $skill => $cat)
|
||||
DB::Aowow()->query('UPDATE ?_items SET subClass = ?d WHERE classBak = 9 AND subClassBak = 0 AND requiredSkill = ?d', $cat, $skill);
|
||||
|
||||
// calculate durabilityCosts
|
||||
DB::Aowow()->query('
|
||||
UPDATE
|
||||
?_items i
|
||||
JOIN
|
||||
dbc_durabilityquality dq ON dq.id = ((i.quality + 1) * 2)
|
||||
JOIN
|
||||
dbc_durabilitycosts dc ON dc.id = i.itemLevel
|
||||
SET
|
||||
i.repairPrice = (durability* dq.mod * IF(i.classBak = 2,
|
||||
CASE i.subClassBak
|
||||
WHEN 0 THEN w0 WHEN 1 THEN w1 WHEN 2 THEN w2 WHEN 3 THEN w3 WHEN 4 THEN w4
|
||||
WHEN 5 THEN w5 WHEN 6 THEN w6 WHEN 7 THEN w7 WHEN 8 THEN w8 WHEN 10 THEN w10
|
||||
WHEN 11 THEN w11 WHEN 12 THEN w12 WHEN 13 THEN w13 WHEN 14 THEN w14 WHEN 15 THEN w15
|
||||
WHEN 16 THEN w16 WHEN 17 THEN w17 WHEN 18 THEN w18 WHEN 19 THEN w19 WHEN 20 THEN w20
|
||||
END,
|
||||
CASE i.subClassBak
|
||||
WHEN 1 THEN a1 WHEN 2 THEN a2 WHEN 3 THEN a3 WHEN 4 THEN a4 WHEN 6 THEN a6
|
||||
END
|
||||
))
|
||||
WHERE
|
||||
durability > 0 AND ((classBak = 4 AND subClassBak IN (1, 2, 3, 4, 6)) OR (classBak = 2 AND subClassBak <> 9))');
|
||||
|
||||
// hide some nonsense
|
||||
DB::Aowow()->query('UPDATE ?_items SET `cuFlags` = `cuFlags` | ?d WHERE
|
||||
`name_loc0` LIKE "Monster - %" OR `name_loc0` LIKE "Creature - %" OR
|
||||
`name_loc0` LIKE "%[PH]%" OR `name_loc0` LIKE "% PH %" OR
|
||||
`name_loc0` LIKE "%(new)%" OR `name_loc0` LIKE "%(old)%" OR
|
||||
`name_loc0` LIKE "%deprecated%" OR `name_loc0` LIKE "%obsolete%" OR
|
||||
`name_loc0` LIKE "%1H%" OR `name_loc0` LIKE "%QA%" OR
|
||||
`name_loc0` LIKE "%(test)%" OR `name_loc0` LIKE "test %" OR (`name_loc0` LIKE "% test %" AND `class` > 0)',
|
||||
CUSTOM_EXCLUDE_FOR_LISTVIEW
|
||||
);
|
||||
|
||||
// sanity check weapon class and invtype relation
|
||||
$checks = array(
|
||||
[[INVTYPE_WEAPONOFFHAND, INVTYPE_WEAPONMAINHAND, INVTYPE_WEAPON], [0, 4, 7, 13, 14, 15]],
|
||||
[[INVTYPE_2HWEAPON], [1, 5, 6, 8, 10, 14, 20]],
|
||||
[[INVTYPE_RANGED, INVTYPE_RANGEDRIGHT], [2, 3, 16, 18, 14, 19]]
|
||||
);
|
||||
foreach ($checks as [$slots, $subclasses])
|
||||
DB::Aowow()->query('UPDATE ?_items SET `cuFlags` = `cuFlags` | ?d WHERE `class`= ?d AND `slotBak` IN (?a) AND `subClass` NOT IN (?a)', CUSTOM_EXCLUDE_FOR_LISTVIEW, ITEM_CLASS_WEAPON, $slots, $subclasses);
|
||||
|
||||
$this->reapplyCCFlags('items', Type::ITEM);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
?>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user