diff --git a/bin/data/misc/cursor.png b/bin/data/misc/cursor.png new file mode 100644 index 0000000..a119c23 Binary files /dev/null and b/bin/data/misc/cursor.png differ diff --git a/src/Client/GUI/DrawObject.cpp b/src/Client/GUI/DrawObject.cpp index 3c2b5c4..f00f1f3 100644 --- a/src/Client/GUI/DrawObject.cpp +++ b/src/Client/GUI/DrawObject.cpp @@ -3,6 +3,7 @@ #include "DrawObject.h" #include "PseuWoW.h" #include "Object.h" +#include "Player.h" using namespace irr; @@ -36,6 +37,13 @@ void DrawObject::Unlink(void) void DrawObject::_Init(void) { + if(_obj->IsPlayer()) + { + Player *p = (Player*)_obj; + DEBUG(logdebug("Player: race=%u gender=%u face=%u skin=%u traits=%u hair=%u haircol=%u", + p->GetRace(),p->GetGender(),p->GetFaceId(),p->GetSkinId(),p->GetFaceTraitsId(),p->GetHairStyleId(),p->GetHairColorId())); + } + if(!cube && _obj->IsWorldObject()) // only world objects have coords and can be drawn { uint32 displayid = _obj->IsUnit() ? _obj->GetUInt32Value(UNIT_FIELD_DISPLAYID) : 0; // TODO: in case its GO get it from proto data diff --git a/src/Client/GUI/PseuGUI.cpp b/src/Client/GUI/PseuGUI.cpp index 7c8b3bd..ca7d81f 100644 --- a/src/Client/GUI/PseuGUI.cpp +++ b/src/Client/GUI/PseuGUI.cpp @@ -190,11 +190,12 @@ void PseuGUI::Run(void) _driver->beginScene(true, true, 0); - DrawCurrentScene(); - _smgr->drawAll(); _guienv->drawAll(); + if(_scene) + _scene->OnDraw(); + _driver->endScene(); } catch(...) @@ -274,12 +275,6 @@ void PseuGUI::_UpdateSceneState(void) } } -void PseuGUI::DrawCurrentScene(void) -{ - if(_scene && _initialized) - _scene->OnDraw(); -} - // used to get our current WorldPosition WorldPosition PseuGUI::GetWorldPosition(void) { diff --git a/src/Client/GUI/PseuGUI.h b/src/Client/GUI/PseuGUI.h index d6c42fb..d3b6e56 100644 --- a/src/Client/GUI/PseuGUI.h +++ b/src/Client/GUI/PseuGUI.h @@ -93,7 +93,6 @@ public: void NotifyObjectCreation(Object *o); // scenes - void DrawCurrentScene(void); void SetSceneState(SceneState); // helpers diff --git a/src/Client/GUI/Scene.cpp b/src/Client/GUI/Scene.cpp index b99b314..3a74fc3 100644 --- a/src/Client/GUI/Scene.cpp +++ b/src/Client/GUI/Scene.cpp @@ -1,6 +1,7 @@ #include "common.h" #include "PseuGUI.h" #include "PseuWoW.h" +#include "CCursorController.h" #include "Scene.h" Scene::Scene(PseuGUI *g) @@ -10,6 +11,9 @@ Scene::Scene(PseuGUI *g) driver = gui->_driver; smgr = gui->_smgr; guienv = gui->_guienv; + cursor = new CCursorController(device->getCursorControl(), driver); + cursor->setOSCursorVisible(true); + cursor->setVisible(false); } void Scene::OnDraw(void) diff --git a/src/Client/GUI/Scene.h b/src/Client/GUI/Scene.h index 9360437..4c21fa1 100644 --- a/src/Client/GUI/Scene.h +++ b/src/Client/GUI/Scene.h @@ -12,6 +12,7 @@ using namespace gui; class PseuGUI; +class CCursorController; // base class class Scene @@ -32,6 +33,7 @@ protected: irr::video::IVideoDriver* driver; irr::scene::ISceneManager* smgr; irr::gui::IGUIEnvironment* guienv; + CCursorController *cursor; SceneState _scenestate; }; @@ -80,6 +82,7 @@ private: MapMgr *mapmgr; IGUIStaticText *debugText; bool debugmode; + gui::IGUIImage *icursor; }; diff --git a/src/Client/GUI/SceneWorld.cpp b/src/Client/GUI/SceneWorld.cpp index 1c1b027..ffc36b9 100644 --- a/src/Client/GUI/SceneWorld.cpp +++ b/src/Client/GUI/SceneWorld.cpp @@ -11,6 +11,7 @@ #include "MInput.h" #include "WorldSession.h" #include "World.h" +#include "CCursorController.h" SceneWorld::SceneWorld(PseuGUI *g) : Scene(g) { @@ -48,7 +49,10 @@ SceneWorld::SceneWorld(PseuGUI *g) : Scene(g) driver->setFog(video::SColor(0,100,101,190), true, fogdist, fogdist + 30, 0.02f); // setup cursor - device->getCursorControl()->setVisible(false); + + cursor->setOSCursorVisible(false); + cursor->addMouseCursorTexture("data/misc/cursor.png", true); + cursor->setVisible(true); InitTerrain(); UpdateTerrain(); @@ -67,6 +71,17 @@ void SceneWorld::OnUpdate(s32 timediff) bool mouse_pressed_right = eventrecv->mouse.right_pressed(); float timediff_f = timediff / 1000.0f; + if( (mouse_pressed_right || mouse_pressed_left) && cursor->isVisible()) + { + // TODO: if mouse is hovering over a gui element, do not hide + cursor->setVisible(false); + } + else if( !(mouse_pressed_right || mouse_pressed_left) && !cursor->isVisible()) + { + cursor->setVisible(true); + } + + if(eventrecv->key.pressed(KEY_KEY_W) || (mouse_pressed_left && mouse_pressed_right)) camera->moveForward(50 * timediff_f); if(eventrecv->key.pressed(KEY_KEY_S)) @@ -131,9 +146,7 @@ void SceneWorld::OnUpdate(s32 timediff) if(mouse_pressed_left || mouse_pressed_right) { - //if(device->getCursorControl()->isVisible()) - //device->getCursorControl()->setVisible(false); - if(mouse_pos != device->getCursorControl()->getPosition()) + if(mouse_pos != cursor->getMousePos()) { camera->turnRight(MOUSE_SENSIVITY * (device->getCursorControl()->getPosition().X - mouse_pos.X)); // check if new camera pitch would cause camera to flip over; if thats the case keep current pitch @@ -148,9 +161,7 @@ void SceneWorld::OnUpdate(s32 timediff) } else { - device->getCursorControl()->setPosition(device->getCursorControl()->getPosition()); - //if(!device->getCursorControl()->isVisible()) - //device->getCursorControl()->setVisible(true); + //device->getCursorControl()->setPosition(device->getCursorControl()->getPosition()); mouse_pos = device->getCursorControl()->getPosition(); } @@ -177,14 +188,18 @@ void SceneWorld::OnUpdate(s32 timediff) str += (int)terrain->getSectorsRendered(); str += L" / "; str += (int)terrain->getSectorCount(); + str += L"\n"; + str += device->getCursorControl()->isVisible() ? L"Cursor: VISIBLE" : L"Cursor: HIDDEN"; debugText->setText(str.c_str()); + + gui->domgr.Update(); // iterate over DrawObjects, draw them and clean up + } void SceneWorld::OnDraw(void) { - // draw all objects - gui->domgr.Update(); // iterate over DrawObjects, draw them and clean up + cursor->render(); } void SceneWorld::OnDelete(void) @@ -214,7 +229,6 @@ void SceneWorld::InitTerrain(void) terrain->getMaterial(0).setFlag(video::EMF_LIGHTING, true); terrain->getMaterial(0).setFlag(video::EMF_FOG_ENABLE, true); - } diff --git a/src/Client/World/Player.h b/src/Client/World/Player.h index 06a88c7..52ed714 100644 --- a/src/Client/World/Player.h +++ b/src/Client/World/Player.h @@ -167,7 +167,12 @@ class Player : public Unit public: Player(); void Create(uint64); - uint8 GetGender() { return GetUInt32Value(PLAYER_BYTES_3); } + inline uint8 GetGender() { return GetUInt32Value(PLAYER_BYTES_3); } + inline uint8 GetSkinId() { return (GetUInt32Value(PLAYER_BYTES) & 0x000000FF); } + inline uint8 GetFaceId() { return (GetUInt32Value(PLAYER_BYTES) & 0x0000FF00) >> 8; } + inline uint8 GetHairStyleId() { return (GetUInt32Value(PLAYER_BYTES) & 0x00FF0000) >> 16; } + inline uint8 GetHairColorId() { return (GetUInt32Value(PLAYER_BYTES) & 0xFF000000) >> 24; } + inline uint8 GetFaceTraitsId() { return (GetUInt32Value(PLAYER_BYTES_2) & 0x000000FF); } private: diff --git a/src/PseuWoW.vcproj b/src/PseuWoW.vcproj index 2ca2ff9..ef7f51b 100644 --- a/src/PseuWoW.vcproj +++ b/src/PseuWoW.vcproj @@ -417,6 +417,12 @@ + + + + diff --git a/src/shared.vcproj b/src/shared.vcproj index ed5cdc5..b41400b 100644 --- a/src/shared.vcproj +++ b/src/shared.vcproj @@ -144,6 +144,12 @@ + + + + diff --git a/src/shared/ADTFile.cpp b/src/shared/ADTFile.cpp index e2fcbc0..18b4f89 100644 --- a/src/shared/ADTFile.cpp +++ b/src/shared/ADTFile.cpp @@ -303,46 +303,3 @@ bool ADTFile::LoadMem(ByteBuffer& buf) } - - - - -void ADT_ExportStringSetByOffset(const uint8* data, uint32 off, std::set& st, char* stop) -{ - data += ((uint32*)data)[off]; // seek to correct absolute offset - data += 28; // move ptr to real start of data - uint32 offset=0; - std::string s; - char c; - while(memcmp(data+offset,stop,4)) - { - c = data[offset]; - if(!c) - { - if(s.length()) - { - DEBUG(printf("DEP: %s\n",s.c_str())); - st.insert(s); - s.clear(); - } - } - else - s += c; - offset++; - } -} - -void ADT_FillTextureData(const uint8* data,std::set& st) -{ - ADT_ExportStringSetByOffset(data,OFFSET_TEXTURES,st,"XDMM"); -} - -void ADT_FillWMOData(const uint8* data,std::set& st) -{ - ADT_ExportStringSetByOffset(data,OFFSET_WMOS,st,"DIWM"); -} - -void ADT_FillModelData(const uint8* data,std::set& st) -{ - ADT_ExportStringSetByOffset(data,OFFSET_MODELS,st,"DIMM"); -} diff --git a/src/shared/ADTFile.h b/src/shared/ADTFile.h index 4d66642..bc5484b 100644 --- a/src/shared/ADTFile.h +++ b/src/shared/ADTFile.h @@ -25,9 +25,5 @@ public: uint32 _version; }; -void ADT_ExportStringSetByOffset(const uint8*, uint32, std::set&, char*); -void ADT_FillTextureData(const uint8*,std::set&); -void ADT_FillWMOData(const uint8*,std::set&); -void ADT_FillModelData(const uint8*,std::set&); #endif diff --git a/src/shared/MapTile.cpp b/src/shared/MapTile.cpp index 479ecd5..53d2c8f 100644 --- a/src/shared/MapTile.cpp +++ b/src/shared/MapTile.cpp @@ -26,6 +26,7 @@ void MapTile::ImportFromADT(ADTFile *adt) _chunks[ch].baseheight = adt->_chunks[ch].hdr.zbase; // ADT files store (x/z) as ground coords and (y) as the height! _chunks[ch].basex = adt->_chunks[ch].hdr.xbase; // here converting it to (x/y) on ground and basehight as actual height. _chunks[ch].basey = adt->_chunks[ch].hdr.ybase; // strange coords they use... :S + _chunks[ch].lqheight = adt->_chunks[ch].waterlevel; uint32 fcnt=0, rcnt=0; while(true) //9*9 + 8*8 { @@ -42,6 +43,10 @@ void MapTile::ImportFromADT(ADTFile *adt) fcnt++; } } + for(uint32 i = 0; i < 81; i++) + { + _chunks[ch].hmap_lq[i] = adt->_chunks[ch].lqvertex[i].h; + } } _xbase = _chunks[0].basex; _ybase = _chunks[0].basey; diff --git a/src/shared/MapTile.h b/src/shared/MapTile.h index 7ea185e..421f6af 100644 --- a/src/shared/MapTile.h +++ b/src/shared/MapTile.h @@ -18,7 +18,8 @@ public: float hmap_rough[9*9]; float hmap_fine[8*8]; float hmap[17*17]; // combined rough and fine hmap - float basex,basey,baseheight; + float basex,basey,baseheight,lqheight; + float hmap_lq[9*9]; // liquid (water, lava) height map //... TODO: implement the rest of this }; diff --git a/src/shared/ProgressBar.cpp b/src/shared/ProgressBar.cpp new file mode 100644 index 0000000..20c8525 --- /dev/null +++ b/src/shared/ProgressBar.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "ProgressBar.h" + +barGoLink::~barGoLink() +{ + printf( "\n" ); + fflush(stdout); +} + +barGoLink::barGoLink( int row_count, bool fast_upd ) +{ + rec_no = 0; + rec_pos = 0; + indic_len = 50; + num_rec = row_count; + fast_update = fast_upd; + empty = " "; + #ifdef _WIN32 + full = "\x3D"; + #else + full = "*"; + #endif + #ifdef _WIN32 + printf( "\x3D" ); + #else + printf( "[" ); + #endif + for ( int i = 0; i < indic_len; i++ ) printf( empty ); + #ifdef _WIN32 + printf( "\x3D 0%%\r\x3D" ); + #else + printf( "] 0%%\r[" ); + #endif + fflush(stdout); +} + +void barGoLink::step( void ) +{ + int i, n; + + if ( num_rec == 0 ) return; + ++rec_no; + n = rec_no * indic_len / num_rec; + if ( fast_update || (n != rec_pos) ) + { + #ifdef _WIN32 + printf( "\r\x3D" ); + #else + printf( "\r[" ); + #endif + for ( i = 0; i < n; i++ ) printf( full ); + for ( ; i < indic_len; i++ ) printf( empty ); + float percent = (((float)n/(float)indic_len)*100); + #ifdef _WIN32 + printf( "\x3D %i%% (%i/%i)\r\x3D", (int)percent, rec_no, num_rec); + #else + printf( "] %i%% (%i/%i)\r[", (int)percent, rec_no, num_rec); + #endif + fflush(stdout); + + rec_pos = n; + } +} diff --git a/src/shared/ProgressBar.h b/src/shared/ProgressBar.h new file mode 100644 index 0000000..71d4497 --- /dev/null +++ b/src/shared/ProgressBar.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef MANGOSSERVER_PROGRESSBAR_H +#define MANGOSSERVER_PROGRESSBAR_H + +#include + +class barGoLink +{ + char const * empty; + char const * full; + + int rec_no; + int rec_pos; + int num_rec; + int indic_len; + bool fast_update; + + public: + + void step( void ); + barGoLink( int, bool ); + ~barGoLink(); +}; +#endif diff --git a/src/tools/stuffextract/DBCFieldData.h b/src/tools/stuffextract/DBCFieldData.h index cc1356e..d970564 100644 --- a/src/tools/stuffextract/DBCFieldData.h +++ b/src/tools/stuffextract/DBCFieldData.h @@ -270,30 +270,31 @@ enum ItemDisplayInfoEnum ITEMDISPLAYINFO_NAME_L = 3, // (internal name?) ITEMDISPLAYINFO_NAME_R = 4, // (internal name?) ITEMDISPLAYINFO_ICON = 5, // icon filename - ITEMDISPLAYINFO_FLAG1 = 6, // must be some kind of flag. 0 - 5. - ITEMDISPLAYINFO_FLAG2 = 7, // some flag? 0, 1 or 2. - ITEMDISPLAYINFO_FLAG3 = 8, // some flag? 0 or 1. - ITEMDISPLAYINFO_FLAG4 = 9, // some flag? 0, 1 or 2. - ITEMDISPLAYINFO_FLAG5 = 10, // some flag? mostly 0, sometimes other values (for ex. polearms have 4081 ?!) - ITEMDISPLAYINFO_FLAGS = 11, // these is NOT the inventorytype... - ITEMDISPLAYINFO_HELM1 = 12, // only set if model is a helm. might be related to hair/ears/traits showing on or off. - ITEMDISPLAYINFO_HELM2 = 13, // ^ same. - ITEMDISPLAYINFO_AU = 14, // the following fields contain strings that end with AU, AL, HA, TU, etc. - ITEMDISPLAYINFO_AL = 15, // sometimes they are set, sometimes not. - ITEMDISPLAYINFO_HA = 16, - ITEMDISPLAYINFO_TU = 17, - ITEMDISPLAYINFO_TL = 18, - ITEMDISPLAYINFO_LU = 19, - ITEMDISPLAYINFO_LL = 20, - ITEMDISPLAYINFO_FO = 21, - ITEMDISPLAYINFO_UNK = 22, // mostly 0. quite sure this is not a string. + ITEMDISPLAYINFO_GEOSET_1 = 6, // Geoset, which M2 submeshes this item will cover when equipped, depeding on type + ITEMDISPLAYINFO_GEOSET_2 = 7, + ITEMDISPLAYINFO_GEOSET_3 = 8, + ITEMDISPLAYINFO_GEOSET_4 = 9, // some flag? 0, 1 or 2. + ITEMDISPLAYINFO_FLAG1 = 10, // some flag? mostly 0, sometimes other values (for ex. polearms have 4081 ?!) + ITEMDISPLAYINFO_ITEMGROUPSOUND = 11, // these is NOT the inventorytype... + ITEMDISPLAYINFO_HELM1 = 12, // reference to HelmetGeosetVisData. only set if item is a helm + ITEMDISPLAYINFO_HELM2 = 13, // ^ - (this ID points to a nearer specification which face parts are covered by a helm) + // -- the following fields store texture names for different body parts + ITEMDISPLAYINFO_AU = 14, // arm upper + ITEMDISPLAYINFO_AL = 15, // arm lower + ITEMDISPLAYINFO_HA = 16, // hand + ITEMDISPLAYINFO_TU = 17, // torso upper + ITEMDISPLAYINFO_TL = 18, // torso lower + ITEMDISPLAYINFO_LU = 19, // leg upper + ITEMDISPLAYINFO_LL = 20, // leg lower + ITEMDISPLAYINFO_FO = 21, // foot + ITEMDISPLAYINFO_VISUAL = 22, // reference to ItemVisuals: specifies the ID of up to 5 glow effects ITEMDISPLAYINFO_END = 23 }; static const char *ItemDisplayInfoFieldNames[] = { - "","model_l","model_r","name_l","name_r","icon","flag1","flag2","flag3","flag4", // 0-9 - "flag5","flags","helm1","helm2","AU","AL","HA","TU","TL","LU", // 10-19 + "","model_l","model_r","tex_l","tex_r","icon","geo1","geo2","geo3","geo4", // 0-9 + "flag1","sound","helm1","helm2","AU","AL","HA","TU","TL","LU", // 10-19 "LL","FO","unk", // 20-22 "" }; @@ -372,6 +373,40 @@ static const char *NPCSoundsFormat = { "iiiix" }; +enum CharSectionsEnum +{ + CHARSECTIONS_ID = 0, // the sectionID, not sure if this is a reference from/to other fields + CHARSECTIONS_RACE_ID = 1, + CHARSECTIONS_GENDER = 2, // 0=male, 1=female + CHARSECTIONS_TYPE = 3, // 0=base skin, 1=face, 2=facial traits, 3=hair, 4=underwear + CHARSECTIONS_SECTION = 4, // depends, see table below + CHARSECTIONS_COLOR = 5, // skin/hair color + CHARSECTIONS_TEXTURE1 = 6, + CHARSECTIONS_TEXTURE2 = 7, + CHARSECTIONS_TEXTURE3 = 8, + CHARSECTIONS_IS_SPECIAL_NPC = 9, // 0=player, 1=special npc + CHARSECTIONS_END +}; +/* +Type Description Section Color Texture 1 Texture 2 Texture 3 +0 Base skin - Skin color Skin texture Fur texture (Tauren only) - +1 Face Face type Skin color Face lower texture Face upper texture - +2 Facial hair / decoration Facial hair type Hair color Face lower texture Face upper texture - +3 Hair Hair style Hair color Hair texture Face lower texture Face upper texture +4 Underwear - Skin color Legs upper texture Chest upper texture - +The textures are all overlaid on the base skin texture, according to the alpha channel in the sub textures. The texture region positions and sizes are fixed. +*/ + +static const char *CharSectionsFieldNames[] = { + "","race","gender","type","section","color","tex1","tex2","tex3","special", // 0-9 + "" +}; + +static const char *CharSectionsFormat = { + "iiiiiisssi" +}; + + diff --git a/src/tools/stuffextract/StuffExtract.cpp b/src/tools/stuffextract/StuffExtract.cpp index 66f6974..9b49d75 100644 --- a/src/tools/stuffextract/StuffExtract.cpp +++ b/src/tools/stuffextract/StuffExtract.cpp @@ -11,14 +11,18 @@ #include "StuffExtract.h" #include "DBCFieldData.h" #include "Locale.h" +#include "ProgressBar.h" + std::map mapNames; -std::set texNames; -std::set modelNames; -std::set wmoNames; -std::set soundFileSet; -// default config; SCPs are dont always +std::set texNames; +std::set modelNames; +std::set wmoNames; +std::set soundFileSet; + + +// default config; SCPs are done always bool doMaps=true, doSounds=false, doTextures=false, doWmos=false, doModels=false, doMd5=true, doAutoclose=false; @@ -117,7 +121,6 @@ void ProcessCmdArgs(int argc, char *argv[]) // TODO: as soon as M2 model or WMO reading is done, extract those textures to, but independent from maps!! if(!doMaps) { - doTextures = false; doWmos = false; } if(help) @@ -146,7 +149,7 @@ void PrintHelp(void) printf("Use + or - to turn a feature on or off.\n"); printf("Features are:\n"); printf("maps - map extraction\n"); - printf("textures - extract textures (requires maps extraction, for now)\n"); + printf("textures - extract textures\n"); printf("wmos - extract map WMOs (requires maps extraction)\n"); printf("models - extract models\n"); printf("sounds - extract sound files (wav/mp3)\n"); @@ -250,9 +253,9 @@ bool ConvertDBC(void) { std::map racemap; // needed to extract other dbc files correctly SCPStorageMap EmoteDataStorage,RaceDataStorage,SoundDataStorage,MapDataStorage,ZoneDataStorage,ItemDisplayInfoStorage, - CreatureModelStorage,CreatureDisplayInfoStorage,NPCSoundStorage; // will store the converted data from dbc files + CreatureModelStorage,CreatureDisplayInfoStorage,NPCSoundStorage,CharSectionStorage; // will store the converted data from dbc files DBCFile EmotesText,EmotesTextData,EmotesTextSound,ChrRaces,SoundEntries,Map,AreaTable,ItemDisplayInfo, - CreatureModelData,CreatureDisplayInfo,NPCSounds; + CreatureModelData,CreatureDisplayInfo,NPCSounds,CharSections; printf("Opening DBC archive...\n"); MPQHelper mpq("dbc"); @@ -268,6 +271,7 @@ bool ConvertDBC(void) CreatureModelData.openmem(mpq.ExtractFile("DBFilesClient\\CreatureModelData.dbc")); CreatureDisplayInfo.openmem(mpq.ExtractFile("DBFilesClient\\CreatureDisplayInfo.dbc")); NPCSounds.openmem(mpq.ExtractFile("DBFilesClient\\NPCSounds.dbc")); + CharSections.openmem(mpq.ExtractFile("DBFilesClient\\CharSections.dbc")); //... printf("DBC files opened.\n"); //... @@ -361,7 +365,7 @@ bool ConvertDBC(void) // fill up file storage. not necessary if we dont want to extract sounds if(doSounds && field >= SOUNDENTRY_FILE_1 && field <= SOUNDENTRY_FILE_10) - soundFileSet.insert(path + value); + soundFileSet.insert(NameAndAlt(path + value)); } } } @@ -406,6 +410,7 @@ bool ConvertDBC(void) { if(strlen(ItemDisplayInfoFieldNames[field])) { + // TODO: need to get std::string value = AutoGetDataString(it,ItemDisplayInfoFormat,field); if(value.size()) // only store if not null ItemDisplayInfoStorage[id].push_back(std::string(ItemDisplayInfoFieldNames[field]) + "=" + value); @@ -425,7 +430,7 @@ bool ConvertDBC(void) if(value.size()) // only store if not null { if(doModels) - modelNames.insert(value); // we need to extract model later, store it + modelNames.insert(NameAndAlt(value)); // we need to extract model later, store it std::string fn = _PathToFileName(value); if(stricmp(fn.c_str()+fn.length()-4, "mdx")) fn = fn.substr(0,fn.length()-3) + "m2"; @@ -465,6 +470,41 @@ bool ConvertDBC(void) } } + printf("charsections.."); + for(DBCFile::Iterator it = CharSections.begin(); it != CharSections.end(); ++it) + { + uint32 id = it->getUInt(CHARSECTIONS_ID); + for(uint32 field=CHARSECTIONS_ID; field < CHARSECTIONS_END; field++) + { + if(strlen(CharSectionsFieldNames[field])) + { + std::string value = AutoGetDataString(it,CharSectionsFormat,field); + if(value.size()) // only store if not null + { + // ok we have a little problem here: + // some textures used for different races have the same file name, but we are storing them all + // in one directory. Texture path format is: "Character\\ + // so we have to use good names to store all textures without overwriting each other + if(field >= CHARSECTIONS_TEXTURE1 && field <= CHARSECTIONS_TEXTURE3) + { + char buf[100]; + sprintf(buf,"charsection_%u_%u_%u_%u_%u_%u.blp", + it->getUInt(CHARSECTIONS_RACE_ID), + it->getUInt(CHARSECTIONS_GENDER), + it->getUInt(CHARSECTIONS_TYPE), + it->getUInt(CHARSECTIONS_SECTION), + it->getUInt(CHARSECTIONS_COLOR), + field - CHARSECTIONS_TEXTURE1); // texture ID + texNames.insert(NameAndAlt(value,buf)); + value = buf; + + } + CharSectionStorage[id].push_back(std::string(CharSectionsFieldNames[field]) + "=" + value); + } + } + } + } + //... @@ -483,6 +523,7 @@ bool ConvertDBC(void) printf("creaturemodeldata.."); OutSCP(SCPDIR "/creaturemodeldata.scp",CreatureModelStorage,"creaturemodeldata"); printf("creaturedisplayinfo.."); OutSCP(SCPDIR "/creaturedisplayinfo.scp",CreatureDisplayInfoStorage,"creaturedisplayinfo"); printf("npcsound.."); OutSCP(SCPDIR "/npcsound.scp",NPCSoundStorage,"npcsound"); + printf("charsections.."); OutSCP(SCPDIR "/charsections.scp",CharSectionStorage,"charsections"); //... printf("DONE!\n"); @@ -579,6 +620,7 @@ void ExtractMaps(void) void ExtractMapDependencies(void) { + barGoLink *bar; printf("\nExtracting map dependencies...\n\n"); printf("- Preparing to read MPQ arcives...\n"); MPQHelper mpqmodel("model"); @@ -588,124 +630,149 @@ void ExtractMapDependencies(void) std::string pathtex = path + "/texture"; std::string pathmodel = path + "/model"; std::string pathwmo = path + "/wmo"; - std::string mpqfn,realfn; + std::string mpqfn,realfn,altfn; MD5FileMap md5Tex, md5Wmo, md5Model; CreateDir(pathtex.c_str()); CreateDir(pathmodel.c_str()); CreateDir(pathwmo.c_str()); uint32 wmosdone=0,texdone=0,mdone=0; - for(std::set::iterator i = texNames.begin(); i != texNames.end(); i++) + if(doTextures) { - mpqfn = *i; - if(!mpqtex.FileExists((char*)mpqfn.c_str())) - continue; - realfn = pathtex + "/" + _PathToFileName(mpqfn); - std::fstream fh; - fh.open(realfn.c_str(),std::ios_base::out | std::ios_base::binary); - if(fh.is_open()) + printf("Extracting textures...\n"); + bar = new barGoLink(texNames.size(), true); + for(std::set::iterator i = texNames.begin(); i != texNames.end(); i++) { - ByteBuffer& bb = mpqtex.ExtractFile((char*)mpqfn.c_str()); - fh.write((const char*)bb.contents(),bb.size()); - if(doMd5) - { - MD5Hash h; - h.Update((uint8*)bb.contents(), bb.size()); - h.Finalize(); - uint8 *md5ptr = new uint8[MD5_DIGEST_LENGTH]; - md5Tex[_PathToFileName(realfn)] = md5ptr; - memcpy(md5ptr, h.GetDigest(), MD5_DIGEST_LENGTH); - } - texdone++; - printf("- textures... %u\r",texdone); - } - else - printf("Could not write texture %s\n",realfn.c_str()); - fh.close(); - } - printf("\n"); - if(texNames.size() && doTextures) - OutMD5((char*)pathtex.c_str(),md5Tex); - - for(std::set::iterator i = modelNames.begin(); i != modelNames.end(); i++) - { - mpqfn = *i; - // no idea what bliz intended by this. the ADT files refer to .mdx models, - // however there are only .m2 files in the MPQ archives. - // so we just need to check if there is a .m2 file instead of the .mdx file, and load that one. - if(!mpqmodel.FileExists((char*)mpqfn.c_str())) - { - std::string alt = i->substr(0,i->length()-3) + "m2"; - DEBUG(printf("MDX model not found, trying M2 file.")); - if(!mpqmodel.FileExists((char*)alt.c_str())) - { - DEBUG(printf(" fail.\n")); + bar->step(); + mpqfn = i->name; + altfn = i->alt; + if(altfn.empty()) + altfn = mpqfn; + if(!mpqtex.FileExists((char*)mpqfn.c_str())) continue; + realfn = pathtex + "/" + _PathToFileName(altfn); + std::fstream fh; + fh.open(realfn.c_str(),std::ios_base::out | std::ios_base::binary); + if(fh.is_open()) + { + ByteBuffer& bb = mpqtex.ExtractFile((char*)mpqfn.c_str()); + fh.write((const char*)bb.contents(),bb.size()); + if(doMd5) + { + MD5Hash h; + h.Update((uint8*)bb.contents(), bb.size()); + h.Finalize(); + uint8 *md5ptr = new uint8[MD5_DIGEST_LENGTH]; + md5Tex[_PathToFileName(realfn)] = md5ptr; + memcpy(md5ptr, h.GetDigest(), MD5_DIGEST_LENGTH); + } + texdone++; } else - { - mpqfn = alt; - DEBUG(printf(" success.\n")); - } + printf("Could not write texture %s\n",realfn.c_str()); + fh.close(); } - realfn = pathmodel + "/" + _PathToFileName(mpqfn); - std::fstream fh; - fh.open(realfn.c_str(),std::ios_base::out | std::ios_base::binary); - if(fh.is_open()) - { - ByteBuffer& bb = mpqmodel.ExtractFile((char*)mpqfn.c_str()); - fh.write((const char*)bb.contents(),bb.size()); - if(doMd5) - { - MD5Hash h; - h.Update((uint8*)bb.contents(), bb.size()); - h.Finalize(); - uint8 *md5ptr = new uint8[MD5_DIGEST_LENGTH]; - md5Model[_PathToFileName(realfn)] = md5ptr; - memcpy(md5ptr, h.GetDigest(), MD5_DIGEST_LENGTH); - } - mdone++; - printf("- models... %u\r",mdone); - } - else - printf("Could not write model %s\n",realfn.c_str()); - fh.close(); + printf("\n"); + if(texNames.size()) + OutMD5((char*)pathtex.c_str(),md5Tex); + delete bar; } - printf("\n"); - if(modelNames.size() && doModels) - OutMD5((char*)pathmodel.c_str(),md5Model); - for(std::set::iterator i = wmoNames.begin(); i != wmoNames.end(); i++) + if(doModels) { - mpqfn = *i; - if(!mpqwmo.FileExists((char*)mpqfn.c_str())) - continue; - realfn = pathwmo + "/" + _PathToFileName(mpqfn); - std::fstream fh; - fh.open(realfn.c_str(),std::ios_base::out | std::ios_base::binary); - if(fh.is_open()) + printf("Extracting models...\n"); + bar = new barGoLink(modelNames.size(),true); + for(std::set::iterator i = modelNames.begin(); i != modelNames.end(); i++) { - ByteBuffer& bb = mpqwmo.ExtractFile((char*)mpqfn.c_str()); - fh.write((const char*)bb.contents(),bb.size()); - if(doMd5) + bar->step(); + mpqfn = i->name; + // no idea what bliz intended by this. the ADT files refer to .mdx models, + // however there are only .m2 files in the MPQ archives. + // so we just need to check if there is a .m2 file instead of the .mdx file, and load that one. + if(!mpqmodel.FileExists((char*)mpqfn.c_str())) { - MD5Hash h; - h.Update((uint8*)bb.contents(), bb.size()); - h.Finalize(); - uint8 *md5ptr = new uint8[MD5_DIGEST_LENGTH]; - md5Wmo[_PathToFileName(realfn)] = md5ptr; - memcpy(md5ptr, h.GetDigest(), MD5_DIGEST_LENGTH); + std::string alt = mpqfn.substr(0,mpqfn.length()-3) + "m2"; + if(!mpqmodel.FileExists((char*)alt.c_str())) + { + printf("Failed to extract model: '%s'\n",alt.c_str()); + continue; + } + else + { + mpqfn = alt; + } } - wmosdone++; - printf("- WMOs... %u\r",wmosdone); + altfn = i->alt; + if(altfn.empty()) + altfn = mpqfn; + realfn = pathmodel + "/" + _PathToFileName(altfn); + std::fstream fh; + fh.open(realfn.c_str(),std::ios_base::out | std::ios_base::binary); + if(fh.is_open()) + { + ByteBuffer& bb = mpqmodel.ExtractFile((char*)mpqfn.c_str()); + fh.write((const char*)bb.contents(),bb.size()); + if(doMd5) + { + MD5Hash h; + h.Update((uint8*)bb.contents(), bb.size()); + h.Finalize(); + uint8 *md5ptr = new uint8[MD5_DIGEST_LENGTH]; + md5Model[_PathToFileName(realfn)] = md5ptr; + memcpy(md5ptr, h.GetDigest(), MD5_DIGEST_LENGTH); + } + mdone++; + } + else + printf("Could not write model %s\n",realfn.c_str()); + fh.close(); } - else - printf("Could not write WMO %s\n",realfn.c_str()); - fh.close(); + printf("\n"); + if(modelNames.size()) + OutMD5((char*)pathmodel.c_str(),md5Model); + delete bar; + } + + if(doWmos) + { + printf("Extracting textures...\n"); + bar = new barGoLink(wmoNames.size(),true); + for(std::set::iterator i = wmoNames.begin(); i != wmoNames.end(); i++) + { + bar->step(); + mpqfn = i->name; + altfn = i->alt; + if(altfn.empty()) + altfn = mpqfn; + if(!mpqwmo.FileExists((char*)mpqfn.c_str())) + continue; + realfn = pathwmo + "/" + _PathToFileName(altfn); + std::fstream fh; + fh.open(realfn.c_str(),std::ios_base::out | std::ios_base::binary); + if(fh.is_open()) + { + ByteBuffer& bb = mpqwmo.ExtractFile((char*)mpqfn.c_str()); + fh.write((const char*)bb.contents(),bb.size()); + if(doMd5) + { + MD5Hash h; + h.Update((uint8*)bb.contents(), bb.size()); + h.Finalize(); + uint8 *md5ptr = new uint8[MD5_DIGEST_LENGTH]; + md5Wmo[_PathToFileName(realfn)] = md5ptr; + memcpy(md5ptr, h.GetDigest(), MD5_DIGEST_LENGTH); + } + wmosdone++; + } + else + printf("Could not write WMO %s\n",realfn.c_str()); + fh.close(); + } + printf("\n"); + if(wmoNames.size()) + OutMD5((char*)pathwmo.c_str(),md5Wmo); + delete bar; } - printf("\n"); - if(wmoNames.size() && doWmos) - OutMD5((char*)pathwmo.c_str(),md5Wmo); } @@ -716,21 +783,24 @@ void ExtractSoundFiles(void) printf("\nExtracting game audio files, %u found in DBC...\n",soundFileSet.size()); CreateDir(SOUNDDIR); MPQHelper smpq("sound"); - std::string outfn; - for(std::set::iterator i = soundFileSet.begin(); i != soundFileSet.end(); i++) + std::string outfn, altfn; + barGoLink bar(soundFileSet.size(),true); + for(std::set::iterator i = soundFileSet.begin(); i != soundFileSet.end(); i++) { - if(!smpq.FileExists((char*)(*i).c_str())) + bar.step(); + if(!smpq.FileExists((char*)i->name.c_str())) { - DEBUG( printf("MPQ: File not found: '%s'\n",(*i).c_str()) ); + DEBUG( printf("MPQ: File not found: '%s'\n",i->name.c_str()) ); continue; } + altfn = i->alt.empty() ? _PathToFileName(i->name) : i->alt; - outfn = std::string(SOUNDDIR) + "/" + _PathToFileName(*i); + outfn = std::string(SOUNDDIR) + "/" + altfn; std::fstream fh; fh.open(outfn.c_str(), std::ios_base::out | std::ios_base::binary); if(fh.is_open()) { - ByteBuffer& bb = smpq.ExtractFile((char*)(*i).c_str()); + ByteBuffer& bb = smpq.ExtractFile((char*)i->name.c_str()); if(bb.size()) { fh.write((const char*)bb.contents(),bb.size()); @@ -740,11 +810,10 @@ void ExtractSoundFiles(void) h.Update((uint8*)bb.contents(), bb.size()); h.Finalize(); uint8 *md5ptr = new uint8[MD5_DIGEST_LENGTH]; - md5data[_PathToFileName(*i)] = md5ptr; + md5data[altfn] = md5ptr; memcpy(md5ptr, h.GetDigest(), MD5_DIGEST_LENGTH); } done++; - printf("- %u files done.\r",done); } } else @@ -757,6 +826,44 @@ void ExtractSoundFiles(void) printf("\n"); } - +void ADT_ExportStringSetByOffset(const uint8* data, uint32 off, std::set& st, char* stop) +{ + data += ((uint32*)data)[off]; // seek to correct absolute offset + data += 28; // move ptr to real start of data + uint32 offset=0; + std::string s; + char c; + while(memcmp(data+offset,stop,4)) + { + c = data[offset]; + if(!c) + { + if(s.length()) + { + DEBUG(printf("DEP: %s\n",s.c_str())); + st.insert(NameAndAlt(s)); + s.clear(); + } + } + else + s += c; + offset++; + } +} + +void ADT_FillTextureData(const uint8* data,std::set& st) +{ + ADT_ExportStringSetByOffset(data,OFFSET_TEXTURES,st,"XDMM"); +} + +void ADT_FillWMOData(const uint8* data,std::set& st) +{ + ADT_ExportStringSetByOffset(data,OFFSET_WMOS,st,"DIWM"); +} + +void ADT_FillModelData(const uint8* data,std::set& st) +{ + ADT_ExportStringSetByOffset(data,OFFSET_MODELS,st,"DIMM"); +} diff --git a/src/tools/stuffextract/StuffExtract.h b/src/tools/stuffextract/StuffExtract.h index 11d3416..5f3a6d0 100644 --- a/src/tools/stuffextract/StuffExtract.h +++ b/src/tools/stuffextract/StuffExtract.h @@ -14,6 +14,20 @@ typedef std::map< uint32,std::list > SCPStorageMap; typedef std::map MD5FileMap; +// this struct is used to resolve conflicting names when extracting archives. +// the problem is that some files stored in different folders in mpq archives will be extracted into one folder, +// overwriting each other. +// thus thats resolved by putting the mpq file name into `name` and the name it should be saved as in `alt`. +// leave `empty` to use filename specified in `name` +struct NameAndAlt +{ + NameAndAlt(std::string a) { name=a; } + NameAndAlt(std::string a, std::string b) { name=a; alt=b; } + bool operator<(NameAndAlt const & other) const { return name < other.name; } // required to be used in std::set + std::string name; + std::string alt; +}; + int main(int argc, char *argv[]); void ProcessCmdArgs(int argc, char *argv[]); void PrintConfig(void); @@ -25,4 +39,10 @@ void ExtractMaps(void); void ExtractMapDependencies(void); void ExtractSoundFiles(void); + +void ADT_ExportStringSetByOffset(const uint8*, uint32, std::set&, char*); +void ADT_FillTextureData(const uint8*,std::set&); +void ADT_FillWMOData(const uint8*,std::set&); +void ADT_FillModelData(const uint8*,std::set&); + #endif \ No newline at end of file