mirror of
https://github.com/Sarjuuk/aowow.git
synced 2025-11-29 15:58:16 +08:00
Setup/DBC
* move dbc structures to separate files and allow loading a specific build * handle localized single string fields * add cli option for output table name * add cli option for wowbuild
This commit is contained in:
@@ -51,21 +51,14 @@ switch ($cmd) // we accept only on
|
||||
sync($s, $b);
|
||||
finish();
|
||||
case 'dbc':
|
||||
foreach (CLISetup::getOpt('dbc') as $n)
|
||||
{
|
||||
if (empty($n))
|
||||
continue;
|
||||
require_once 'setup/tools/clisetup/dbc.func.php';
|
||||
|
||||
$dbc = new DBC(trim($n), ['temporary' => false]);
|
||||
if ($dbc->error)
|
||||
return false;
|
||||
$args = [];
|
||||
foreach ($argv as $i => $str)
|
||||
if ($i && $str[0] != '-')
|
||||
$args[] = $str;
|
||||
|
||||
if (!$dbc->readFile())
|
||||
{
|
||||
CLI::write('CLISetup::loadDBC() - DBC '.$n.'.dbc could not be written to DB!', CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
dbc($args);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
118
setup/tools/clisetup/dbc.func.php
Normal file
118
setup/tools/clisetup/dbc.func.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
if (!defined('AOWOW_REVISION'))
|
||||
die('illegal access');
|
||||
|
||||
if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/************************************************/
|
||||
/* Create content from world tables / dbc files */
|
||||
/************************************************/
|
||||
|
||||
function dbc($args) : bool
|
||||
{
|
||||
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 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)
|
||||
{
|
||||
CLI::write('[dbc] required DBC '.CLI::bold($n).'.dbc not found!', CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
function writeCLIHelp() : bool
|
||||
{
|
||||
CLI::write(' usage: php aowow --dbc=<dbcfileList,..> [--locales=<regionCodes,..>] [tablename [wowbuild]]', -1, false);
|
||||
CLI::write();
|
||||
CLI::write(' Extract dbc files from mpqDataDir into sql table. If the dbc file contains a locale block, data from all available locales gets merged into the same table.', -1, false);
|
||||
CLI::write();
|
||||
CLI::write(' Known WoW builds:', -1, false);
|
||||
|
||||
foreach (glob('setup/tools/dbc/*.ini') as $f)
|
||||
{
|
||||
$a = $b = [];
|
||||
preg_match('/(\d+)\.ini$/', $f, $a);
|
||||
if ($h = fopen($f, 'r'))
|
||||
{
|
||||
preg_match('/(\d\.\d.\d\.?\d*)/', fgets($h), $b);
|
||||
fclose($h);
|
||||
}
|
||||
|
||||
CLI::write(' '.CLI::bold($a[1]).' > '.$b[1], -1, false);
|
||||
}
|
||||
|
||||
CLI::write();
|
||||
CLI::write(' Known DBC files:', -1, false);
|
||||
|
||||
$defs = DBC::getDefinitions();
|
||||
$letter = '';
|
||||
$buff = [];
|
||||
|
||||
asort($defs);
|
||||
|
||||
foreach ($defs as $d)
|
||||
{
|
||||
if (!$letter)
|
||||
$letter = $d[0];
|
||||
else if ($letter != $d[0])
|
||||
{
|
||||
CLI::write(' '.CLI::bold(Util::ucFirst($letter)).':', -1, false);
|
||||
foreach (explode("\n", Lang::breakTextClean(implode(', ', $buff), 120, Lang::FMT_RAW)) as $line)
|
||||
CLI::write(' '.$line, -1, false);
|
||||
|
||||
$buff = [$d];
|
||||
$letter = $d[0];
|
||||
}
|
||||
else
|
||||
$buff[] = $d;
|
||||
}
|
||||
|
||||
CLI::write(' '.CLI::bold(Util::ucFirst($letter)).':', -1, false);
|
||||
foreach (explode("\n", Lang::breakTextClean(implode(', ', $buff), 120, Lang::FMT_RAW)) as $line)
|
||||
CLI::write(' '.$line, -1, false);
|
||||
|
||||
CLI::write();
|
||||
CLI::write();
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
?>
|
||||
@@ -26,238 +26,8 @@ if (!CLI)
|
||||
die('not in cli mode');
|
||||
|
||||
|
||||
/*
|
||||
Supported format characters:
|
||||
x - not used/unknown, 4 bytes
|
||||
X - not used/unknown, 1 byte
|
||||
s - char*
|
||||
f - float, 4 bytes (rounded to 4 digits after comma)
|
||||
u - unsigned int, 4 bytes
|
||||
i - signed int, 4 bytes
|
||||
b - unsigned char, 1 byte
|
||||
d - sorted by this field, not included in array
|
||||
n - same, but field included in array
|
||||
*/
|
||||
class DBC
|
||||
{
|
||||
private $_formats = array( // locales block for copy pasta: sxsssxsxsxxxxxxxx | xxxxxxxxxxxxxxxxx
|
||||
'achievement' => 'niiisxsssxsxsxxxxxxxxsxsssxsxsxxxxxxxxiiiiisxsssxsxsxxxxxxxxii',
|
||||
'achievement_category' => 'nixxxxxxxxxxxxxxxxxx',
|
||||
'achievement_criteria' => 'niiiiiiiisxsssxsxsxxxxxxxxiixii',
|
||||
'areatable' => 'niixixxiiixsxsssxsxsxxxxxxxxixxxxxxx',
|
||||
'areatrigger' => 'niffxxxxxf',
|
||||
'battlemasterlist' => 'niixxxxxxixxxxxxxxxxxxxxxxxxixii',
|
||||
'charbaseinfo' => 'bb',
|
||||
'charstartoutfit' => 'nbbbXiiiiiiiiiiiiiiiiiiiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
|
||||
'chartitles' => 'nxsxsssxsxsxxxxxxxxsxsssxsxsxxxxxxxxi',
|
||||
'chrclasses' => 'nxixsxsssxsxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxsxixi',
|
||||
'chrraces' => 'niixxxxixxxsxisxsssxsxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxi',
|
||||
'creaturedisplayinfo' => 'niiixxssssxxixxx',
|
||||
'creaturedisplayinfoextra' => 'nxxxxxxxxxxxxxxxxxxxs',
|
||||
'creaturefamily' => 'nxxxxixiiisxsssxsxsxxxxxxxxs',
|
||||
'creaturemodeldata' => 'nxxxxxxxxxxxxixxxxxxxxxxxxxx',
|
||||
'creaturesounddata' => 'niiiixiiiiiiiiixxxxixxxxixiiiiixxiiiix',
|
||||
'currencytypes' => 'niix',
|
||||
'declinedword' => 'ns',
|
||||
'declinedwordcases' => 'niis',
|
||||
'dungeonmap' => 'niiffffi',
|
||||
'durabilitycosts' => 'niiiiiiiiixiiiiiiiiiiixiiiixix',
|
||||
'durabilityquality' => 'nf',
|
||||
'dungeonencounter' => 'niiiisxsssxsxsxxxxxxxxx',
|
||||
'emotes' => 'nsiiiii',
|
||||
'emotestext' => 'nsiiiixixixiixxixxx',
|
||||
'emotestextdata' => 'nsxsssxsxsxxxxxxxx',
|
||||
'emotestextsound' => 'niiii',
|
||||
'faction' => 'niiiiiiiiiiiiiixxxiffixsxsssxsxsxxxxxxxxxxxxxxxxxxxxxxxxx',
|
||||
'factiontemplate' => 'nixiiiiiiiiiii',
|
||||
'gemproperties' => 'nixxi',
|
||||
'glyphproperties' => 'niii',
|
||||
'gtchancetomeleecrit' => 'f',
|
||||
'gtchancetomeleecritbase' => 'f',
|
||||
'gtchancetospellcrit' => 'f',
|
||||
'gtchancetospellcritbase' => 'f',
|
||||
'gtcombatratings' => 'f',
|
||||
'gtoctclasscombatratingscalar' => 'nf',
|
||||
'gtoctregenhp' => 'f',
|
||||
'gtregenmpperspt' => 'f',
|
||||
'gtregenhpperspt' => 'f',
|
||||
'holidays' => 'nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxixxxxxxxxxxiisxix',
|
||||
'holidaydescriptions' => 'nsxsssxsxsxxxxxxxx',
|
||||
'holidaynames' => 'nsxsssxsxsxxxxxxxx',
|
||||
'item' => 'niiiiiii',
|
||||
'itemdisplayinfo' => 'nssxxsxxxxxiixxxxxxxxxxxx',
|
||||
'itemgroupsounds' => 'niixx',
|
||||
'itemextendedcost' => 'niiiiiiiiiiiiiix',
|
||||
'itemlimitcategory' => 'nsxsssxsxsxxxxxxxxii',
|
||||
'itemrandomproperties' => 'nsiiiiisxsssxsxsxxxxxxxx',
|
||||
'itemrandomsuffix' => 'nsxsssxsxsxxxxxxxxsiiiiiiiiii',
|
||||
'itemset' => 'nsxsssxsxsxxxxxxxxxxxxxxxxxxxxxxxxxiiiiiiiiiiiiiiiiii',
|
||||
'itemsubclass' => 'iixxxxxxxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
|
||||
'lfgdungeons' => 'nsxsssxsxsxxxxxxxxiiiiiiixiixixixxxxxxxxxxxxxxxxx',
|
||||
'lock' => 'niiiiixxxiiiiixxxiiiiixxxxxxxxxxx',
|
||||
'locktype' => 'nsxsssxsxsxxxxxxxxsxsssxsxsxxxxxxxxsxsssxsxsxxxxxxxxs',
|
||||
'mailtemplate' => 'nsxsssxsxsxxxxxxxxsxsssxsxsxxxxxxxx',
|
||||
'map' => 'nsixisxsssxsxsxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiffxixi',
|
||||
'mapdifficulty' => 'niixxxxxxxxxxxxxxxxxxis',
|
||||
'material' => 'nxxii',
|
||||
'npcsounds' => 'niiix',
|
||||
'overridespelldata' => 'niiiixixxxxx',
|
||||
'powerdisplay' => 'nisbbb',
|
||||
'questfactionreward' => 'niiiiiiiiii',
|
||||
'questsort' => 'nsxsssxsxsxxxxxxxx',
|
||||
'questxp' => 'niiiiiiiiii',
|
||||
'randproppoints' => 'niiiiiiiiiiiiiii',
|
||||
'scalingstatdistribution' => 'niiiiiiiiiiiiiiiiiiiii',
|
||||
'scalingstatvalues' => 'xniiiiiiiiiiiiiiiiiiiiii',
|
||||
'screeneffect' => 'nsxxxxxxii',
|
||||
'skillline' => 'nixsxsssxsxsxxxxxxxxsxsssxsxsxxxxxxxxixxxxxxxxxxxxxxxxxx',
|
||||
'skilllineability' => 'niiiixxixiiixx',
|
||||
'skilllinecategory' => 'nsxsssxsxsxxxxxxxxi',
|
||||
'skillraceclassinfo' => 'niiiiixx',
|
||||
'soundambience' => 'nii',
|
||||
'soundemitters' => 'nffxxxxiix',
|
||||
'soundentries' => 'nisssssssssssxxxxxxxxxxsxixxxx',
|
||||
'spell' => 'niiiuuuuuuuuixixixixxxxxxxxxiiixxxxiiiiiiiiiiiixxiiiiiiiiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiiiiiiiifffiiiiiiiiiiiiiiifffiiiiiiiiiiiiixsxsssxsxsxxxxxxxxsxsssxsxsxxxxxxxxsxsssxsxsxxxxxxxxsxsssxsxsxxxxxxxxiiiiiiiiiixxfffxxxiixiixifffii',
|
||||
'spellcasttimes' => 'nixx',
|
||||
'spelldescriptionvariables' => 'ns',
|
||||
'spelldifficulty' => 'xiiii',
|
||||
'spellduration' => 'nixx',
|
||||
'spellfocusobject' => 'nsxsssxsxsxxxxxxxx',
|
||||
'spellicon' => 'ns',
|
||||
'spellitemenchantment' => 'niiiiiiixxxiiisxsssxsxsxxxxxxxxxxxiiii',
|
||||
'spellitemenchantmentcondition' => 'nbbbbbxxxxxbbbbbbbbbbiiiiiXXXXX',
|
||||
'spellradius' => 'nfxf',
|
||||
'spellrange' => 'nffffisxsssxsxsxxxxxxxxxxxxxxxxxxxxxxxxx',
|
||||
'spellrunecost' => 'niiii',
|
||||
'spellshapeshiftform' => 'nxsxsssxsxsxxxxxxxxiixxiixxiiiiiiii',
|
||||
'spellvisual' => 'niiiiiixxxxiixiixxxxxxiiiixxxxxx',
|
||||
'spellvisualkit' => 'nxxxxxxxxxxxxxxixxxxxxxxxxxxxxxxxxxxxx',
|
||||
'talent' => 'niiiiiiiixxxxixxixxixii',
|
||||
'talenttab' => 'nsxsssxsxsxxxxxxxxiiiiis',
|
||||
'taxinodes' => 'niffxsxsssxsxsxxxxxxxxxx',
|
||||
'taxipath' => 'niix',
|
||||
'taxipathnode' => 'niiiffxxxxx',
|
||||
'totemcategory' => 'nsxsssxsxsxxxxxxxxiu',
|
||||
'vocaluisounds' => 'nxiiixx',
|
||||
'weaponimpactsounds' => 'nixiiiiiiiiiiiiiiiiiiii',
|
||||
'weaponswingsounds2' => 'nixi',
|
||||
'worldmaparea' => 'niisffffxix', // 4.x - niisffffxixxxx
|
||||
'worldmapoverlay' => 'niixxxxxsiiiixxxx', // 4.x - niixxxsiiiixxxx
|
||||
'worldmaptransforms' => 'niffffiffi',
|
||||
'worldstatezonesounds' => 'iiiiiiix',
|
||||
'zoneintromusictable' => 'nxixx',
|
||||
'zonemusic' => 'nxxxxxii'
|
||||
);
|
||||
|
||||
private $_fields = array(
|
||||
'achievement' => 'id,faction,map,previous,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8,description_loc0,description_loc2,description_loc3,description_loc4,description_loc6,description_loc8,category,points,orderInGroup,flags,iconId,reward_loc0,reward_loc2,reward_loc3,reward_loc4,reward_loc6,reward_loc8,reqCriteriaCount,refAchievement',
|
||||
'achievement_category' => 'id,parentCategory',
|
||||
'achievement_criteria' => 'id,refAchievementId,type,value1,value2,value3,value4,value5,value6,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8,completionFlags,groupFlags,timeLimit,order',
|
||||
'areatable' => 'id,mapId,areaTable,flags,soundAmbience,zoneMusic,zoneIntroMusic,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8,factionGroupMask',
|
||||
'areatrigger' => 'id,mapId,posY,posX,orientation',
|
||||
'battlemasterlist' => 'id,mapId,moreMapId,areaType,maxPlayers,minLevel,maxLevel',
|
||||
'charbaseinfo' => 'raceId,classId',
|
||||
'charstartoutfit' => 'id,raceId,classId,gender,item1,item2,item3,item4,item5,item6,item7,item8,item9,item10,item11,item12,item13,item14,item15,item16,item17,item18,item19,item20',
|
||||
'chartitles' => 'id,male_loc0,male_loc2,male_loc3,male_loc4,male_loc6,male_loc8,female_loc0,female_loc2,female_loc3,female_loc4,female_loc6,female_loc8,bitIdx',
|
||||
'chrclasses' => 'id,powerType,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8,fileString,flags,expansion',
|
||||
'chrraces' => 'id,flags,factionId,baseLanguage,fileString,side,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8,expansion',
|
||||
'creaturedisplayinfo' => 'id,modelId,creatureSoundId,extraInfoId,skin1,skin2,skin3,iconString,npcSoundId',
|
||||
'creaturedisplayinfoextra' => 'id,textureString',
|
||||
'creaturefamily' => 'id,skillLine1,petFoodMask,petTalentType,categoryEnumID,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8,iconString',
|
||||
'creaturemodeldata' => 'id,creatureSoundId',
|
||||
'creaturesounddata' => 'id,exertion,exertionCritical,injury,injuryCritical,death,stun,stand,footstepTerrainId,aggro,wingFlap,wingGlide,alert,fidget,customAttack,loop,jumpStart,jumpEnd,petAttack,petOrder,petDismiss,birth,spellcast,submerge,submerged',
|
||||
'currencytypes' => 'id,itemId,category',
|
||||
'declinedword' => 'id,word',
|
||||
'declinedwordcases' => 'id,wordId,caseIdx,word',
|
||||
'dungeonmap' => 'id,mapId,floor,minY,maxY,minX,maxX,areaId',
|
||||
'durabilitycosts' => 'id,w0,w1,w2,w3,w4,w5,w6,w7,w8,w10,w11,w12,w13,w14,w15,w16,w17,w18,w19,w20,a1,a2,a3,a4,a6',
|
||||
'durabilityquality' => 'id,mod',
|
||||
'dungeonencounter' => 'id,map,mode,order,bit,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8',
|
||||
'emotes' => 'id,name,animationId,flags,state,stateParam,soundId',
|
||||
'emotestext' => 'id,command,emoteId,etd0,etd1,etd2,etd4,etd6,etd8,etd9,etd12',
|
||||
'emotestextsound' => 'id,emotesTextId,raceId,gender,soundId',
|
||||
'emotestextdata' => 'id,text_loc0,text_loc2,text_loc3,text_loc4,text_loc6,text_loc8',
|
||||
'faction' => 'id,repIdx,baseRepRaceMask1,baseRepRaceMask2,baseRepRaceMask3,baseRepRaceMask4,baseRepClassMask1,baseRepClassMask2,baseRepClassMask3,baseRepClassMask4,baseRepValue1,baseRepValue2,baseRepValue3,baseRepValue4,repFlags1,parentFaction,spilloverRateIn,spilloverRateOut,spilloverMaxRank,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8',
|
||||
'factiontemplate' => 'id,factionId,ourMask,friendlyMask,hostileMask,enemyFactionId1,enemyFactionId2,enemyFactionId3,enemyFactionId4,friendFactionId1,friendFactionId2,friendFactionId3,friendFactionId4',
|
||||
'gemproperties' => 'id,enchantmentId,colorMask',
|
||||
'glyphproperties' => 'id,spellId,typeFlags,iconId',
|
||||
'gtchancetomeleecrit' => 'chance',
|
||||
'gtchancetomeleecritbase' => 'chance',
|
||||
'gtchancetospellcrit' => 'chance',
|
||||
'gtchancetospellcritbase' => 'chance',
|
||||
'gtcombatratings' => 'ratio',
|
||||
'gtoctclasscombatratingscalar' => 'idx,ratio',
|
||||
'gtoctregenhp' => 'ratio',
|
||||
'gtregenmpperspt' => 'ratio',
|
||||
'gtregenhpperspt' => 'ratio',
|
||||
'holidays' => 'id,looping,nameId,descriptionId,textureString,scheduleType',
|
||||
'holidaydescriptions' => 'id,description_loc0,description_loc2,description_loc3,description_loc4,description_loc6,description_loc8',
|
||||
'holidaynames' => 'id,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8',
|
||||
'item' => 'id,classId,subClassId,soundOverride,material,displayInfoId,inventoryType,sheatheType',
|
||||
'itemdisplayinfo' => 'id,leftModelName,rightModelName,inventoryIcon1,spellVisualId,groupSoundId',
|
||||
'itemgroupsounds' => 'id,pickUpSoundId,dropDownSoundId',
|
||||
'itemextendedcost' => 'id,reqHonorPoints,reqArenaPoints,reqArenaSlot,reqItemId1,reqItemId2,reqItemId3,reqItemId4,reqItemId5,itemCount1,itemCount2,itemCount3,itemCount4,itemCount5,reqPersonalRating',
|
||||
'itemlimitcategory' => 'id,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8,count,isGem',
|
||||
'itemrandomproperties' => 'id,nameINT,enchantId1,enchantId2,enchantId3,enchantId4,enchantId5,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8',
|
||||
'itemrandomsuffix' => 'id,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8,nameINT,enchantId1,enchantId2,enchantId3,enchantId4,enchantId5,allocationPct1,allocationPct2,allocationPct3,allocationPct4,allocationPct5',
|
||||
'itemset' => 'id,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8,spellId1,spellId2,spellId3,spellId4,spellId5,spellId6,spellId7,spellId8,itemCount1,itemCount2,itemCount3,itemCount4,itemCount5,itemCount6,itemCount7,itemCount8,reqSkillId,reqSkillLevel',
|
||||
'itemsubclass' => 'class,subClass,weaponSize',
|
||||
'lfgdungeons' => 'id,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8,levelMin,levelMax,targetLevel,targetLevelMin,targetLevelMax,mapId,difficulty,type,faction,expansion,groupId',
|
||||
'lock' => 'id,type1,type2,type3,type4,type5,properties1,properties2,properties3,properties4,properties5,reqSkill1,reqSkill2,reqSkill3,reqSkill4,reqSkill5',
|
||||
'locktype' => 'id,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8,state_loc0,state_loc2,state_loc3,state_loc4,state_loc6,state_loc8,process_loc0,process_loc2,process_loc3,process_loc4,process_loc6,process_loc8,strref',
|
||||
'mailtemplate' => 'id,subject_loc0,subject_loc2,subject_loc3,subject_loc4,subject_loc6,subject_loc8,text_loc0,text_loc2,text_loc3,text_loc4,text_loc6,text_loc8',
|
||||
'map' => 'id,nameINT,areaType,isBG,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8,parentMapId,parentX,parentY,expansion,maxPlayers',
|
||||
'mapdifficulty' => 'id,mapId,difficulty,nPlayer,nPlayerString',
|
||||
'material' => 'id,sheatheSoundId,unsheatheSoundId',
|
||||
'npcsounds' => 'id,greetSoundId,byeSoundId,angrySoundId',
|
||||
'overridespelldata' => 'id,spellId1,spellId2,spellId3,spellId4,spellId5',
|
||||
'powerdisplay' => 'id,realType,globalString,r,g,b',
|
||||
'questfactionreward' => 'id,field1,field2,field3,field4,field5,field6,field7,field8,field9,field10',
|
||||
'questsort' => 'id,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8',
|
||||
'questxp' => 'id,field1,field2,field3,field4,field5,field6,field7,field8,field9,field10',
|
||||
'randproppoints' => 'id,epic1,epic2,epic3,epic4,epic5,rare1,rare2,rare3,rare4,rare5,uncommon1,uncommon2,uncommon3,uncommon4,uncommon5',
|
||||
'scalingstatdistribution' => 'id,statMod1,statMod2,statMod3,statMod4,statMod5,statMod6,statMod7,statMod8,statMod9,statMod10,modifier1,modifier2,modifier3,modifier4,modifier5,modifier6,modifier7,modifier8,modifier9,modifier10,maxLevel',
|
||||
'scalingstatvalues' => 'id,shoulderMultiplier,trinketMultiplier,weaponMultiplier,rangedMultiplier,clothShoulderArmor,leatherShoulderArmor,mailShoulderArmor,plateShoulderArmor,weaponDPS1H,weaponDPS2H,casterDPS1H,casterDPS2H,rangedDPS,wandDPS,spellPower,primBudged,tertBudged,clothCloakArmor,clothChestArmor,leatherChestArmor,mailChestArmor,plateChestArmor',
|
||||
'screeneffect' => 'id,name,soundAmbienceId,zoneMusicId',
|
||||
'skillline' => 'id,categoryId,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8,description_loc0,description_loc2,description_loc3,description_loc4,description_loc6,description_loc8,iconId',
|
||||
'skilllineability' => 'id,skillLineId,spellId,reqRaceMask,reqClassMask,reqSkillLevel,acquireMethod,skillLevelGrey,skillLevelYellow',
|
||||
'skilllinecategory' => 'id,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8,index',
|
||||
'skillraceclassinfo' => 'id,skillLine,raceMask,classMask,flags,reqLevel',
|
||||
'soundambience' => 'id,soundIdDay,soundIdNight',
|
||||
'soundemitters' => 'id,posY,posX,soundId,mapId',
|
||||
'soundentries' => 'id,type,name,file1,file2,file3,file4,file5,file6,file7,file8,file9,file10,path,flags',
|
||||
'spell' => 'id,category,dispelType,mechanic,attributes0,attributes1,attributes2,attributes3,attributes4,attributes5,attributes6,attributes7,stanceMask,stanceMaskNot,targets,spellFocus,castTimeId,recoveryTime,recoveryTimeCategory,procChance,procCharges,maxLevel,baseLevel,spellLevel,durationId,powerType,powerCost,powerCostPerLevel,powerPerSecond,powerPerSecondPerLevel,rangeId,stackAmount,tool1,tool2,reagent1,reagent2,reagent3,reagent4,reagent5,reagent6,reagent7,reagent8,reagentCount1,reagentCount2,reagentCount3,reagentCount4,reagentCount5,reagentCount6,reagentCount7,reagentCount8,equippedItemClass,equippedItemSubClassMask,equippedItemInventoryTypeMask,effect1Id,effect2Id,effect3Id,effect1DieSides,effect2DieSides,effect3DieSides,effect1RealPointsPerLevel,effect2RealPointsPerLevel,effect3RealPointsPerLevel,effect1BasePoints,effect2BasePoints,effect3BasePoints,effect1Mechanic,effect2Mechanic,effect3Mechanic,effect1ImplicitTargetA,effect2ImplicitTargetA,effect3ImplicitTargetA,effect1ImplicitTargetB,effect2ImplicitTargetB,effect3ImplicitTargetB,effect1RadiusId,effect2RadiusId,effect3RadiusId,effect1AuraId,effect2AuraId,effect3AuraId,effect1Periode,effect2Periode,effect3Periode,effect1ValueMultiplier,effect2ValueMultiplier,effect3ValueMultiplier,effect1ChainTarget,effect2ChainTarget,effect3ChainTarget,effect1CreateItemId,effect2CreateItemId,effect3CreateItemId,effect1MiscValue,effect2MiscValue,effect3MiscValue,effect1MiscValueB,effect2MiscValueB,effect3MiscValueB,effect1TriggerSpell,effect2TriggerSpell,effect3TriggerSpell,effect1PointsPerComboPoint,effect2PointsPerComboPoint,effect3PointsPerComboPoint,effect1SpellClassMaskA,effect2SpellClassMaskA,effect3SpellClassMaskA,effect1SpellClassMaskB,effect2SpellClassMaskB,effect3SpellClassMaskB,effect1SpellClassMaskC,effect2SpellClassMaskC,effect3SpellClassMaskC,spellVisualId1,spellVisualId2,iconId,iconIdActive,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8,rank_loc0,rank_loc2,rank_loc3,rank_loc4,rank_loc6,rank_loc8,description_loc0,description_loc2,description_loc3,description_loc4,description_loc6,description_loc8,buff_loc0,buff_loc2,buff_loc3,buff_loc4,buff_loc6,buff_loc8,powerCostPercent,startRecoveryCategory,startRecoveryTime,maxTargetLevel,spellFamilyId,spellFamilyFlags1,spellFamilyFlags2,spellFamilyFlags3,maxAffectedTargets,damageClass,effect1DamageMultiplier,effect2DamageMultiplier,effect3DamageMultiplier,toolCategory1,toolCategory2,schoolMask,runeCostId,powerDisplayId,effect1BonusMultiplier,effect2BonusMultiplier,effect3BonusMultiplier,spellDescriptionVariable,spellDifficulty',
|
||||
'spellcasttimes' => 'id,baseTime',
|
||||
'spelldescriptionvariables' => 'id,vars',
|
||||
'spellduration' => 'id,baseTime',
|
||||
'spelldifficulty' => 'normal10,normal25,heroic10,heroic25',
|
||||
'spellfocusobject' => 'id,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8',
|
||||
'spellicon' => 'id,iconPath',
|
||||
'spellitemenchantment' => 'id,charges,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',
|
||||
'spellitemenchantmentcondition' => 'id,color1,color2,color3,color4,color5,comparator1,comparator2,comparator3,comparator4,comparator5,cmpColor1,cmpColor2,cmpColor3,cmpColor4,cmpColor5,value1,value2,value3,value4,value5',
|
||||
'spellradius' => 'id,radiusMin,radiusMax',
|
||||
'spellrange' => 'id,rangeMinHostile,rangeMinFriend,rangeMaxHostile,rangeMaxFriend,rangeType,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8',
|
||||
'spellrunecost' => 'id,costBlood,costUnholy,costFrost,runicPowerGain',
|
||||
'spellshapeshiftform' => 'id,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8,flags,creatureType,displayIdA,displayIdH,spellId1,spellId2,spellId3,spellId4,spellId5,spellId6,spellId7,spellId8',
|
||||
'spellvisual' => 'id,precastKitId,castKitId,impactKitId,stateKitId,statedoneKitId,channelKitId,missileSoundId,animationSoundId,casterImpactKitId,targetImpactKitId,missileTargetingKitId,instantAreaKitId,impactAreaKitId,persistentAreaKitId',
|
||||
'spellvisualkit' => 'id,soundId',
|
||||
'talent' => 'id,tabId,row,column,rank1,rank2,rank3,rank4,rank5,reqTalent,reqRank,talentSpell,petCategory1,petCategory2',
|
||||
'talenttab' => 'id,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8,iconId,raceMask,classMask,creatureFamilyMask,tabNumber,textureFile',
|
||||
'taxinodes' => 'id,mapId,posX,posY,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8',
|
||||
'taxipath' => 'id,startNodeId,endNodeId',
|
||||
'taxipathnode' => 'id,pathId,nodeIdx,mapId,posX,posY',
|
||||
'totemcategory' => 'id,name_loc0,name_loc2,name_loc3,name_loc4,name_loc6,name_loc8,category,categoryMask',
|
||||
'vocaluisounds' => 'id,raceId,soundIdMale,soundIdFemale',
|
||||
'weaponimpactsounds' => 'id,subClass,hit1,hit2,hit3,hit4,hit5,hit6,hit7,hit8,hit9,hit10,crit1,crit2,crit3,crit4,crit5,crit6,crit7,crit8,crit9,crit10',
|
||||
'weaponswingsounds2' => 'id,weaponSize,soundId',
|
||||
'worldmaparea' => 'id,mapId,areaId,nameINT,left,right,top,bottom,defaultDungeonMapId',
|
||||
'worldmapoverlay' => 'id,worldMapAreaId,areaTableId,textureString,w,h,x,y',
|
||||
'worldmaptransforms' => 'id,sourceMapId,minX,minY,maxX,maxY,targetMapId,offsetX,offsetY,dungeonMapId',
|
||||
'worldstatezonesounds' => 'stateId,value,areaId,wmoAreaId,zoneIntroMusicId,zoneMusicId,soundAmbienceId',
|
||||
'zoneintromusictable' => 'id,soundId',
|
||||
'zonemusic' => 'id,soundIdDay,soundIdNight'
|
||||
);
|
||||
|
||||
private $isGameTable = false;
|
||||
private $localized = false;
|
||||
private $tempTable = true;
|
||||
@@ -266,42 +36,66 @@ class DBC
|
||||
private $dataBuffer = [];
|
||||
private $bufferSize = 500;
|
||||
|
||||
private static $structs = [];
|
||||
|
||||
private $fileRefs = [];
|
||||
private $curFile = '';
|
||||
|
||||
public $error = true;
|
||||
public $fields = [];
|
||||
public $format = '';
|
||||
public $format = [];
|
||||
public $file = '';
|
||||
|
||||
private $macro = array(
|
||||
'LOC' => 'sxsssxsxsxxxxxxxx', // pre 4.x locale block (in use)
|
||||
'X_LOC' => 'xxxxxxxxxxxxxxxxx' // pre 4.x locale block (unused)
|
||||
);
|
||||
|
||||
public function __construct($file, $opts = [])
|
||||
private $unpackFmt = array( // Supported format characters:
|
||||
'x' => 'x/x/x/x', // x - not used/unknown, 4 bytes
|
||||
'X' => 'x', // X - not used/unknown, 1 byte
|
||||
's' => 'V', // s - string block index, 4 bytes
|
||||
'S' => 'V', // S - string block index, 4 bytes - localized; autofill
|
||||
'f' => 'f', // f - float, 4 bytes (rounded to 4 digits after comma)
|
||||
'i' => 'l', // i - signed int, 4 bytes
|
||||
'u' => 'V', // u - unsigned int, 4 bytes
|
||||
'b' => 'C', // b - unsigned char, 1 byte
|
||||
'd' => 'x4', // d - ordered by this field, not included in array
|
||||
'n' => 'V' // n - int, 4 bytes, ordered by this field
|
||||
);
|
||||
|
||||
public const DEFAULT_WOW_BUILD = '12340';
|
||||
private const INI_FILE_PATH = 'setup/tools/dbc/%s.ini';
|
||||
|
||||
public function __construct($file, $opts = [], string $wowBuild = self::DEFAULT_WOW_BUILD)
|
||||
{
|
||||
self::loadStructs($wowBuild);
|
||||
|
||||
$file = strtolower($file);
|
||||
if (empty($this->_fields[$file]) || empty($this->_formats[$file]))
|
||||
if (empty(self::$structs[$file]))
|
||||
{
|
||||
CLI::write('no structure known for '.$file.'.dbc, aborting.', CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
CLI::write('no structure known for '.$file.'.dbc, build '.$wowBuild, CLI::LOG_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!DB::isConnected(DB_AOWOW))
|
||||
foreach (self::$structs[$file] as $name => $type)
|
||||
{
|
||||
CLI::write('not connected to db, aborting.', CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
return;
|
||||
// resolove locale macro
|
||||
if (isset($this->macro[$type]))
|
||||
{
|
||||
$this->localized = true;
|
||||
for ($i = 0; $i < strlen($this->macro[$type]); $i++)
|
||||
$this->format[$name.'_loc'.$i] = $this->macro[$type][$i];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->format[$name] = $type;
|
||||
if ($type == 'S')
|
||||
$this->localized = true;
|
||||
}
|
||||
}
|
||||
|
||||
$this->fields = explode(',', $this->_fields[$file]);
|
||||
$this->format = $this->_formats[$file];
|
||||
$this->file = $file;
|
||||
$this->localized = !!strstr($this->format, 'sxsssxsxsxxxxxxxx');
|
||||
|
||||
if (count($this->fields) != strlen(str_ireplace('x', '', $this->format)))
|
||||
{
|
||||
CLI::write('known field types ['.count($this->fields).'] and names ['.strlen(str_ireplace('x', '', $this->format)).'] do not match for '.$file.'.dbc, aborting.', CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
return;
|
||||
}
|
||||
$this->file = $file;
|
||||
|
||||
if (is_bool($opts['temporary']))
|
||||
$this->tempTable = $opts['temporary'];
|
||||
@@ -313,7 +107,7 @@ class DBC
|
||||
|
||||
// gameTable-DBCs don't have an index and are accessed through value order
|
||||
// allas, you cannot do this with mysql, so we add a 'virtual' index
|
||||
$this->isGameTable = $this->format == 'f' && substr($file, 0, 2) == 'gt';
|
||||
$this->isGameTable = array_values($this->format) == ['f'] && substr($file, 0, 2) == 'gt';
|
||||
|
||||
$foundMask = 0x0;
|
||||
foreach (CLISetup::$expectedPaths as $locStr => $locId)
|
||||
@@ -336,7 +130,6 @@ class DBC
|
||||
if (!$this->fileRefs)
|
||||
{
|
||||
CLI::write('no suitable files found for '.$file.'.dbc, aborting.', CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -346,21 +139,18 @@ class DBC
|
||||
if (count($x) != 1)
|
||||
{
|
||||
CLI::write('some DBCs have differenct record counts ('.implode(', ', $x).' respectively). cannot merge!', CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
return;
|
||||
}
|
||||
$x = array_unique(array_column($headers, 'fieldCount'));
|
||||
if (count($x) != 1)
|
||||
{
|
||||
CLI::write('some DBCs have differenct field counts ('.implode(', ', $x).' respectively). cannot merge!', CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
return;
|
||||
}
|
||||
$x = array_unique(array_column($headers, 'recordSize'));
|
||||
if (count($x) != 1)
|
||||
{
|
||||
CLI::write('some DBCs have differenct record sizes ('.implode(', ', $x).' respectively). cannot merge!', CLI::LOG_ERROR);
|
||||
CLI::write();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -375,9 +165,9 @@ class DBC
|
||||
$this->createTable();
|
||||
|
||||
if ($this->localized)
|
||||
CLI::write(' - reading and merging '.$this->file.'.dbc for locales '.implode(', ', array_keys($this->fileRefs)));
|
||||
CLI::write(' - DBC: reading and merging '.$this->file.'.dbc for locales '.Lang::concat(array_intersect_key(Util::$localeStrings, $this->fileRefs), true, 'CLI::bold'));
|
||||
else
|
||||
CLI::write(' - reading '.$this->file.'.dbc');
|
||||
CLI::write(' - DBC: reading '.$this->file.'.dbc');
|
||||
|
||||
if (!$this->read())
|
||||
{
|
||||
@@ -388,6 +178,32 @@ class DBC
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getTableName() : string
|
||||
{
|
||||
return $this->tableName;
|
||||
}
|
||||
|
||||
public static function getDefinitions() : array
|
||||
{
|
||||
if (empty(self::$structs))
|
||||
self::loadStructs();
|
||||
|
||||
return array_keys(self::$structs);
|
||||
}
|
||||
|
||||
private static function loadStructs(string $wowBuild = self::DEFAULT_WOW_BUILD) : void
|
||||
{
|
||||
$structFile = sprintf(self::INI_FILE_PATH, $wowBuild);
|
||||
|
||||
if (!file_exists($structFile))
|
||||
{
|
||||
CLI::write('no structure file found for wow build '.$wowBuild, CLI::LOG_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
self::$structs = parse_ini_file($structFile, true);
|
||||
}
|
||||
|
||||
private function endClean()
|
||||
{
|
||||
foreach ($this->fileRefs as &$ref)
|
||||
@@ -443,9 +259,9 @@ class DBC
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($header['fieldCount'] != strlen($this->format))
|
||||
if ($header['fieldCount'] != count($this->format))
|
||||
{
|
||||
CLI::write('incorrect format string ('.$this->format.') specified for file '.$this->curFile.' fieldCount='.$header['fieldCount'], CLI::LOG_ERROR);
|
||||
CLI::write('incorrect format ('.implode('', $this->format).') specified for file '.$this->curFile.' fieldCount='.$header['fieldCount'], CLI::LOG_ERROR);
|
||||
fclose($handle);
|
||||
return false;
|
||||
}
|
||||
@@ -460,40 +276,47 @@ class DBC
|
||||
if ($this->error)
|
||||
return;
|
||||
|
||||
$n = 0;
|
||||
$pKey = '';
|
||||
$query = 'CREATE '.($this->tempTable ? 'TEMPORARY' : '').' TABLE `'.$this->tableName.'` (';
|
||||
|
||||
if ($this->isGameTable)
|
||||
{
|
||||
$query .= '`idx` BIGINT(20) NOT NULL, ';
|
||||
$query .= '`idx` INT SIGNED NOT NULL, ';
|
||||
$pKey = 'idx';
|
||||
}
|
||||
|
||||
foreach (str_split($this->format) as $idx => $f)
|
||||
foreach ($this->format as $name => $type)
|
||||
{
|
||||
switch ($f)
|
||||
switch ($type)
|
||||
{
|
||||
case 'f':
|
||||
$query .= '`'.$this->fields[$n].'` FLOAT NOT NULL, ';
|
||||
$query .= '`'.$name.'` FLOAT NOT NULL, ';
|
||||
break;
|
||||
case 'S':
|
||||
for ($l = 0; $l < strlen($this->macro['LOC']); $l++)
|
||||
if ($this->macro['LOC'][$l] == 's')
|
||||
$query .= '`'.$name.'_loc'.$l.'` TEXT NULL, ';
|
||||
|
||||
break;
|
||||
case 's':
|
||||
$query .= '`'.$this->fields[$n].'` TEXT NOT NULL, ';
|
||||
$query .= '`'.$name.'` TEXT NULL, ';
|
||||
break;
|
||||
case 'b':
|
||||
$query .= '`'.$name.'` TINYINT UNSIGNED NOT NULL, ';
|
||||
break;
|
||||
case 'i':
|
||||
case 'n':
|
||||
case 'b':
|
||||
$query .= '`'.$name.'` INT SIGNED NOT NULL, ';
|
||||
break;
|
||||
case 'u':
|
||||
$query .= '`'.$this->fields[$n].'` BIGINT(20) NOT NULL, ';
|
||||
$query .= '`'.$name.'` INT UNSIGNED NOT NULL, ';
|
||||
break;
|
||||
default: // 'x', 'X', 'd'
|
||||
continue 2;
|
||||
}
|
||||
|
||||
if ($f == 'n')
|
||||
$pKey = $this->fields[$n];
|
||||
|
||||
$n++;
|
||||
if ($type == 'n')
|
||||
$pKey = $name;
|
||||
}
|
||||
|
||||
if ($pKey)
|
||||
@@ -512,53 +335,57 @@ class DBC
|
||||
if (!$this->dataBuffer || $this->error)
|
||||
return;
|
||||
|
||||
// make inserts more manageable
|
||||
$fields = $this->fields;
|
||||
$cols = [];
|
||||
foreach ($this->format as $n => $type)
|
||||
{
|
||||
switch ($type)
|
||||
{
|
||||
case 'x':
|
||||
case 'X':
|
||||
case 'd':
|
||||
continue 2;
|
||||
case 'S':
|
||||
for ($l = 0; $l < strlen($this->macro['LOC']); $l++)
|
||||
if ($this->macro['LOC'][$l] == 's')
|
||||
$cols[] = $n.'_loc'.$l;
|
||||
break;
|
||||
default:
|
||||
$cols[] = $n;
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isGameTable)
|
||||
array_unshift($fields, 'idx');
|
||||
array_unshift($cols, 'idx');
|
||||
|
||||
DB::Aowow()->query('INSERT INTO ?# (?#) VALUES (?a)', $this->tableName, $fields, $this->dataBuffer);
|
||||
DB::Aowow()->query('INSERT INTO ?# (?#) VALUES (?a)', $this->tableName, $cols, $this->dataBuffer);
|
||||
$this->dataBuffer = [];
|
||||
}
|
||||
|
||||
private function read()
|
||||
{
|
||||
// l - signed long (always 32 bit, machine byte order)
|
||||
// V - unsigned long (always 32 bit, little endian byte order)
|
||||
$unpackStr = '';
|
||||
$unpackFmt = array(
|
||||
'x' => 'x/x/x/x',
|
||||
'X' => 'x',
|
||||
's' => 'V',
|
||||
'f' => 'f',
|
||||
'i' => 'l', // not sure if 'l' or 'V' should be used here
|
||||
'u' => 'V',
|
||||
'b' => 'C',
|
||||
'd' => 'x4',
|
||||
'n' => 'V'
|
||||
);
|
||||
|
||||
// Check that record size also matches
|
||||
$recSize = 0;
|
||||
for ($i = 0; $i < strlen($this->format); $i++)
|
||||
$itr = 0;
|
||||
$recSize = 0;
|
||||
$unpackStr = '';
|
||||
foreach ($this->format as $ch)
|
||||
{
|
||||
$ch = $this->format[$i];
|
||||
if ($ch == 'X' || $ch == 'b')
|
||||
$recSize += 1;
|
||||
else
|
||||
$recSize += 4;
|
||||
|
||||
if (!isset($unpackFmt[$ch]))
|
||||
if (!isset($this->unpackFmt[$ch]))
|
||||
{
|
||||
CLI::write('unknown format parameter \''.$ch.'\' in format string', CLI::LOG_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
$unpackStr .= '/'.$unpackFmt[$ch];
|
||||
$unpackStr .= '/'.$this->unpackFmt[$ch];
|
||||
|
||||
if ($ch != 'X' && $ch != 'x')
|
||||
$unpackStr .= 'f'.$i;
|
||||
$unpackStr .= 'f'.$itr; // output can't have numeric key as it gets interpreted as repeat factor here
|
||||
|
||||
$itr++;
|
||||
}
|
||||
|
||||
$unpackStr = substr($unpackStr, 1);
|
||||
@@ -567,7 +394,6 @@ class DBC
|
||||
while (preg_match('/(x\/)+x/', $unpackStr, $r))
|
||||
$unpackStr = substr_replace($unpackStr, 'x'.((strlen($r[0]) + 1) / 2), strpos($unpackStr, $r[0]), strlen($r[0]));
|
||||
|
||||
|
||||
// we asserted all DBCs to be identical in structure. pick first header for checks
|
||||
$header = reset($this->fileRefs)[2];
|
||||
|
||||
@@ -578,13 +404,9 @@ class DBC
|
||||
}
|
||||
|
||||
// And, finally, extract the records
|
||||
$strings = [];
|
||||
$rSize = $header['recordSize'];
|
||||
$rCount = $header['recordCount'];
|
||||
$fCount = strlen($this->format);
|
||||
$strBlock = 4 + 16 + $header['recordSize'] * $header['recordCount'];
|
||||
|
||||
for ($i = 0; $i < $rCount; $i++)
|
||||
for ($i = 0; $i < $header['recordCount']; $i++)
|
||||
{
|
||||
$row = [];
|
||||
$idx = $i;
|
||||
@@ -597,19 +419,33 @@ class DBC
|
||||
{
|
||||
$rec = unpack($unpackStr, fread($handle, $header['recordSize']));
|
||||
|
||||
$n = -1;
|
||||
for ($j = 0; $j < $fCount; $j++)
|
||||
$offset = 0;
|
||||
foreach (array_values($this->format) as $j => $type)
|
||||
{
|
||||
if (!isset($rec['f'.$j]))
|
||||
continue;
|
||||
|
||||
if (!empty($row[$j]))
|
||||
$outIdx = $j + $offset;
|
||||
|
||||
if (isset($row[$outIdx]) && $type != 'S')
|
||||
continue;
|
||||
|
||||
$n++;
|
||||
|
||||
switch ($this->format[$j])
|
||||
switch ($type)
|
||||
{
|
||||
case 'S': // localized String - autofill
|
||||
$offset = substr_count($this->macro['LOC'], 's');
|
||||
|
||||
for ($k = 0; $k < strlen($this->macro['LOC']); $k++)
|
||||
{
|
||||
if ($this->macro['LOC'][$k] != 's')
|
||||
continue;
|
||||
|
||||
if (!isset($row[$j + $k])) // prep locale fields
|
||||
$row[$j + $k] = null;
|
||||
}
|
||||
|
||||
// provide outIdx for passthrough
|
||||
$outIdx = $j + $locId;
|
||||
case 's':
|
||||
$curPos = ftell($handle);
|
||||
fseek($handle, $strBlock + $rec['f'.$j]);
|
||||
@@ -623,15 +459,15 @@ class DBC
|
||||
while ($chr != "\000");
|
||||
|
||||
fseek($handle, $curPos);
|
||||
$row[$j] = $str;
|
||||
$row[$outIdx] = $str;
|
||||
break;
|
||||
case 'f':
|
||||
$row[$j] = round($rec['f'.$j], 8);
|
||||
$row[$outIdx] = round($rec['f'.$j], 8);
|
||||
break;
|
||||
case 'n': // DO NOT BREAK!
|
||||
$idx = $rec['f'.$j];
|
||||
default: // nothing special .. 'i', 'u' and the likes
|
||||
$row[$j] = $rec['f'.$j];
|
||||
$row[$outIdx] = $rec['f'.$j];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1527
setup/tools/dbc/12340.ini
Normal file
1527
setup/tools/dbc/12340.ini
Normal file
File diff suppressed because it is too large
Load Diff
89
setup/tools/dbc/13623.ini
Normal file
89
setup/tools/dbc/13623.ini
Normal file
@@ -0,0 +1,89 @@
|
||||
; DBC structure - 4.0.6.13623
|
||||
;
|
||||
; x - not used/unknown, 4 bytes
|
||||
; X - not used/unknown, 1 byte
|
||||
; s - string block index, 4 bytes
|
||||
; S - string block index, 4 bytes - localized; autofill
|
||||
; f - float, 4 bytes (rounded to 4 digits after comma)
|
||||
; u - unsigned int, 4 bytes
|
||||
; i - signed int, 4 bytes
|
||||
; b - unsigned char, 1 byte
|
||||
; d - sorted by this field, not included in array
|
||||
; n - same, but field included in array
|
||||
;
|
||||
; LOC - used locale strings macro [sxsssxsxsxxxxxxxx]
|
||||
; X_LOC - unused locale strings macro [xxxxxxxxxxxxxxxxx]
|
||||
|
||||
[areatable]
|
||||
id = n
|
||||
mapId = i
|
||||
areaTable = i
|
||||
areaBit = x
|
||||
flags = i
|
||||
UNK1 = i
|
||||
soundProviderPref = x
|
||||
soundProviderPrefWater = x
|
||||
soundAmbience = i
|
||||
zoneMusic = i
|
||||
nameINT = s
|
||||
zoneIntroMusic = i
|
||||
explorationLevel = x
|
||||
name = S
|
||||
factionGroupMask = i
|
||||
liquidType1 = x
|
||||
liquidType2 = x
|
||||
liquidType3 = x
|
||||
liquidType4 = x
|
||||
minElevation = x
|
||||
ambientMultiplier = x
|
||||
lightId = x
|
||||
mountFLags = x
|
||||
uwIntroSound = x
|
||||
uwZoneMusic = x
|
||||
uwAmbience = x
|
||||
worldPvpId = x
|
||||
pvpCombatWorldStateId = x
|
||||
|
||||
[dungeonmap]
|
||||
id = n
|
||||
mapId = i
|
||||
floor = i
|
||||
minY = f ; maxY ?
|
||||
maxY = f ; maxX ?
|
||||
minX = f ; minY ?
|
||||
maxX = f ; minX ?
|
||||
worldMapAreaId = i
|
||||
|
||||
[worldmaparea]
|
||||
id = n
|
||||
mapId = i
|
||||
areaId = i
|
||||
nameINT = s
|
||||
left = f
|
||||
right = f
|
||||
top = f
|
||||
bottom = f
|
||||
displayMapId = x
|
||||
defaultDungeonMapId = i
|
||||
parentWorldMapId = x
|
||||
flags = i
|
||||
levelMin = x
|
||||
levelMax = x
|
||||
|
||||
[worldmapoverlay]
|
||||
id = n
|
||||
worldMapAreaId = i
|
||||
areaTableId = i
|
||||
UNUSED3 = x
|
||||
UNUSED4 = x
|
||||
UNUSED5 = x
|
||||
textureString = s
|
||||
w = i
|
||||
h = i
|
||||
x = i
|
||||
y = i
|
||||
UNUSED11 = x
|
||||
UNUSED12 = x
|
||||
UNUSED13 = x
|
||||
UNUSED14 = x
|
||||
playerConditionId = x
|
||||
2177
setup/tools/dbc/15595.ini
Normal file
2177
setup/tools/dbc/15595.ini
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user