* added custom mouse cursor handler

* stuffextract update (functional: extract CharSections and renamed some fields; visual: added progress bars)
This commit is contained in:
false_genesis 2008-04-05 23:39:45 +00:00
parent 24e62993df
commit 0397d33989
19 changed files with 486 additions and 205 deletions

BIN
bin/data/misc/cursor.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

View File

@ -3,6 +3,7 @@
#include "DrawObject.h" #include "DrawObject.h"
#include "PseuWoW.h" #include "PseuWoW.h"
#include "Object.h" #include "Object.h"
#include "Player.h"
using namespace irr; using namespace irr;
@ -36,6 +37,13 @@ void DrawObject::Unlink(void)
void DrawObject::_Init(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 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 uint32 displayid = _obj->IsUnit() ? _obj->GetUInt32Value(UNIT_FIELD_DISPLAYID) : 0; // TODO: in case its GO get it from proto data

View File

@ -190,11 +190,12 @@ void PseuGUI::Run(void)
_driver->beginScene(true, true, 0); _driver->beginScene(true, true, 0);
DrawCurrentScene();
_smgr->drawAll(); _smgr->drawAll();
_guienv->drawAll(); _guienv->drawAll();
if(_scene)
_scene->OnDraw();
_driver->endScene(); _driver->endScene();
} }
catch(...) catch(...)
@ -274,12 +275,6 @@ void PseuGUI::_UpdateSceneState(void)
} }
} }
void PseuGUI::DrawCurrentScene(void)
{
if(_scene && _initialized)
_scene->OnDraw();
}
// used to get our current WorldPosition // used to get our current WorldPosition
WorldPosition PseuGUI::GetWorldPosition(void) WorldPosition PseuGUI::GetWorldPosition(void)
{ {

View File

@ -93,7 +93,6 @@ public:
void NotifyObjectCreation(Object *o); void NotifyObjectCreation(Object *o);
// scenes // scenes
void DrawCurrentScene(void);
void SetSceneState(SceneState); void SetSceneState(SceneState);
// helpers // helpers

View File

@ -1,6 +1,7 @@
#include "common.h" #include "common.h"
#include "PseuGUI.h" #include "PseuGUI.h"
#include "PseuWoW.h" #include "PseuWoW.h"
#include "CCursorController.h"
#include "Scene.h" #include "Scene.h"
Scene::Scene(PseuGUI *g) Scene::Scene(PseuGUI *g)
@ -10,6 +11,9 @@ Scene::Scene(PseuGUI *g)
driver = gui->_driver; driver = gui->_driver;
smgr = gui->_smgr; smgr = gui->_smgr;
guienv = gui->_guienv; guienv = gui->_guienv;
cursor = new CCursorController(device->getCursorControl(), driver);
cursor->setOSCursorVisible(true);
cursor->setVisible(false);
} }
void Scene::OnDraw(void) void Scene::OnDraw(void)

View File

@ -12,6 +12,7 @@ using namespace gui;
class PseuGUI; class PseuGUI;
class CCursorController;
// base class // base class
class Scene class Scene
@ -32,6 +33,7 @@ protected:
irr::video::IVideoDriver* driver; irr::video::IVideoDriver* driver;
irr::scene::ISceneManager* smgr; irr::scene::ISceneManager* smgr;
irr::gui::IGUIEnvironment* guienv; irr::gui::IGUIEnvironment* guienv;
CCursorController *cursor;
SceneState _scenestate; SceneState _scenestate;
}; };
@ -80,6 +82,7 @@ private:
MapMgr *mapmgr; MapMgr *mapmgr;
IGUIStaticText *debugText; IGUIStaticText *debugText;
bool debugmode; bool debugmode;
gui::IGUIImage *icursor;
}; };

View File

@ -11,6 +11,7 @@
#include "MInput.h" #include "MInput.h"
#include "WorldSession.h" #include "WorldSession.h"
#include "World.h" #include "World.h"
#include "CCursorController.h"
SceneWorld::SceneWorld(PseuGUI *g) : Scene(g) 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); driver->setFog(video::SColor(0,100,101,190), true, fogdist, fogdist + 30, 0.02f);
// setup cursor // setup cursor
device->getCursorControl()->setVisible(false);
cursor->setOSCursorVisible(false);
cursor->addMouseCursorTexture("data/misc/cursor.png", true);
cursor->setVisible(true);
InitTerrain(); InitTerrain();
UpdateTerrain(); UpdateTerrain();
@ -67,6 +71,17 @@ void SceneWorld::OnUpdate(s32 timediff)
bool mouse_pressed_right = eventrecv->mouse.right_pressed(); bool mouse_pressed_right = eventrecv->mouse.right_pressed();
float timediff_f = timediff / 1000.0f; 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)) if(eventrecv->key.pressed(KEY_KEY_W) || (mouse_pressed_left && mouse_pressed_right))
camera->moveForward(50 * timediff_f); camera->moveForward(50 * timediff_f);
if(eventrecv->key.pressed(KEY_KEY_S)) if(eventrecv->key.pressed(KEY_KEY_S))
@ -131,9 +146,7 @@ void SceneWorld::OnUpdate(s32 timediff)
if(mouse_pressed_left || mouse_pressed_right) if(mouse_pressed_left || mouse_pressed_right)
{ {
//if(device->getCursorControl()->isVisible()) if(mouse_pos != cursor->getMousePos())
//device->getCursorControl()->setVisible(false);
if(mouse_pos != device->getCursorControl()->getPosition())
{ {
camera->turnRight(MOUSE_SENSIVITY * (device->getCursorControl()->getPosition().X - mouse_pos.X)); 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 // 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 else
{ {
device->getCursorControl()->setPosition(device->getCursorControl()->getPosition()); //device->getCursorControl()->setPosition(device->getCursorControl()->getPosition());
//if(!device->getCursorControl()->isVisible())
//device->getCursorControl()->setVisible(true);
mouse_pos = device->getCursorControl()->getPosition(); mouse_pos = device->getCursorControl()->getPosition();
} }
@ -177,14 +188,18 @@ void SceneWorld::OnUpdate(s32 timediff)
str += (int)terrain->getSectorsRendered(); str += (int)terrain->getSectorsRendered();
str += L" / "; str += L" / ";
str += (int)terrain->getSectorCount(); str += (int)terrain->getSectorCount();
str += L"\n";
str += device->getCursorControl()->isVisible() ? L"Cursor: VISIBLE" : L"Cursor: HIDDEN";
debugText->setText(str.c_str()); debugText->setText(str.c_str());
gui->domgr.Update(); // iterate over DrawObjects, draw them and clean up
} }
void SceneWorld::OnDraw(void) void SceneWorld::OnDraw(void)
{ {
// draw all objects cursor->render();
gui->domgr.Update(); // iterate over DrawObjects, draw them and clean up
} }
void SceneWorld::OnDelete(void) 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_LIGHTING, true);
terrain->getMaterial(0).setFlag(video::EMF_FOG_ENABLE, true); terrain->getMaterial(0).setFlag(video::EMF_FOG_ENABLE, true);
} }

View File

@ -167,7 +167,12 @@ class Player : public Unit
public: public:
Player(); Player();
void Create(uint64); 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: private:

View File

@ -417,6 +417,12 @@
<Filter <Filter
Name="GUI" Name="GUI"
Filter=""> Filter="">
<File
RelativePath=".\Client\Gui\CCursorController.cpp">
</File>
<File
RelativePath=".\Client\Gui\CCursorController.h">
</File>
<File <File
RelativePath=".\Client\Gui\CM2MeshFileLoader.cpp"> RelativePath=".\Client\Gui\CM2MeshFileLoader.cpp">
</File> </File>

View File

@ -144,6 +144,12 @@
<File <File
RelativePath=".\shared\log.h"> RelativePath=".\shared\log.h">
</File> </File>
<File
RelativePath=".\shared\ProgressBar.cpp">
</File>
<File
RelativePath=".\shared\ProgressBar.h">
</File>
<File <File
RelativePath=".\shared\SysDefs.h"> RelativePath=".\shared\SysDefs.h">
</File> </File>

View File

@ -303,46 +303,3 @@ bool ADTFile::LoadMem(ByteBuffer& buf)
} }
void ADT_ExportStringSetByOffset(const uint8* data, uint32 off, std::set<std::string>& 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<std::string>& st)
{
ADT_ExportStringSetByOffset(data,OFFSET_TEXTURES,st,"XDMM");
}
void ADT_FillWMOData(const uint8* data,std::set<std::string>& st)
{
ADT_ExportStringSetByOffset(data,OFFSET_WMOS,st,"DIWM");
}
void ADT_FillModelData(const uint8* data,std::set<std::string>& st)
{
ADT_ExportStringSetByOffset(data,OFFSET_MODELS,st,"DIMM");
}

View File

@ -25,9 +25,5 @@ public:
uint32 _version; uint32 _version;
}; };
void ADT_ExportStringSetByOffset(const uint8*, uint32, std::set<std::string>&, char*);
void ADT_FillTextureData(const uint8*,std::set<std::string>&);
void ADT_FillWMOData(const uint8*,std::set<std::string>&);
void ADT_FillModelData(const uint8*,std::set<std::string>&);
#endif #endif

View File

@ -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].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].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].basey = adt->_chunks[ch].hdr.ybase; // strange coords they use... :S
_chunks[ch].lqheight = adt->_chunks[ch].waterlevel;
uint32 fcnt=0, rcnt=0; uint32 fcnt=0, rcnt=0;
while(true) //9*9 + 8*8 while(true) //9*9 + 8*8
{ {
@ -42,6 +43,10 @@ void MapTile::ImportFromADT(ADTFile *adt)
fcnt++; fcnt++;
} }
} }
for(uint32 i = 0; i < 81; i++)
{
_chunks[ch].hmap_lq[i] = adt->_chunks[ch].lqvertex[i].h;
}
} }
_xbase = _chunks[0].basex; _xbase = _chunks[0].basex;
_ybase = _chunks[0].basey; _ybase = _chunks[0].basey;

View File

@ -18,7 +18,8 @@ public:
float hmap_rough[9*9]; float hmap_rough[9*9];
float hmap_fine[8*8]; float hmap_fine[8*8];
float hmap[17*17]; // combined rough and fine hmap 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 //... TODO: implement the rest of this
}; };

View File

@ -0,0 +1,80 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
*
* 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;
}
}

40
src/shared/ProgressBar.h Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
*
* 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 <stdio.h>
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

View File

@ -270,30 +270,31 @@ enum ItemDisplayInfoEnum
ITEMDISPLAYINFO_NAME_L = 3, // (internal name?) ITEMDISPLAYINFO_NAME_L = 3, // (internal name?)
ITEMDISPLAYINFO_NAME_R = 4, // (internal name?) ITEMDISPLAYINFO_NAME_R = 4, // (internal name?)
ITEMDISPLAYINFO_ICON = 5, // icon filename ITEMDISPLAYINFO_ICON = 5, // icon filename
ITEMDISPLAYINFO_FLAG1 = 6, // must be some kind of flag. 0 - 5. ITEMDISPLAYINFO_GEOSET_1 = 6, // Geoset, which M2 submeshes this item will cover when equipped, depeding on type
ITEMDISPLAYINFO_FLAG2 = 7, // some flag? 0, 1 or 2. ITEMDISPLAYINFO_GEOSET_2 = 7,
ITEMDISPLAYINFO_FLAG3 = 8, // some flag? 0 or 1. ITEMDISPLAYINFO_GEOSET_3 = 8,
ITEMDISPLAYINFO_FLAG4 = 9, // some flag? 0, 1 or 2. ITEMDISPLAYINFO_GEOSET_4 = 9, // some flag? 0, 1 or 2.
ITEMDISPLAYINFO_FLAG5 = 10, // some flag? mostly 0, sometimes other values (for ex. polearms have 4081 ?!) ITEMDISPLAYINFO_FLAG1 = 10, // some flag? mostly 0, sometimes other values (for ex. polearms have 4081 ?!)
ITEMDISPLAYINFO_FLAGS = 11, // these is NOT the inventorytype... ITEMDISPLAYINFO_ITEMGROUPSOUND = 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_HELM1 = 12, // reference to HelmetGeosetVisData. only set if item is a helm
ITEMDISPLAYINFO_HELM2 = 13, // ^ same. ITEMDISPLAYINFO_HELM2 = 13, // ^ - (this ID points to a nearer specification which face parts are covered by a helm)
ITEMDISPLAYINFO_AU = 14, // the following fields contain strings that end with AU, AL, HA, TU, etc. // -- the following fields store texture names for different body parts
ITEMDISPLAYINFO_AL = 15, // sometimes they are set, sometimes not. ITEMDISPLAYINFO_AU = 14, // arm upper
ITEMDISPLAYINFO_HA = 16, ITEMDISPLAYINFO_AL = 15, // arm lower
ITEMDISPLAYINFO_TU = 17, ITEMDISPLAYINFO_HA = 16, // hand
ITEMDISPLAYINFO_TL = 18, ITEMDISPLAYINFO_TU = 17, // torso upper
ITEMDISPLAYINFO_LU = 19, ITEMDISPLAYINFO_TL = 18, // torso lower
ITEMDISPLAYINFO_LL = 20, ITEMDISPLAYINFO_LU = 19, // leg upper
ITEMDISPLAYINFO_FO = 21, ITEMDISPLAYINFO_LL = 20, // leg lower
ITEMDISPLAYINFO_UNK = 22, // mostly 0. quite sure this is not a string. ITEMDISPLAYINFO_FO = 21, // foot
ITEMDISPLAYINFO_VISUAL = 22, // reference to ItemVisuals: specifies the ID of up to 5 glow effects
ITEMDISPLAYINFO_END = 23 ITEMDISPLAYINFO_END = 23
}; };
static const char *ItemDisplayInfoFieldNames[] = { static const char *ItemDisplayInfoFieldNames[] = {
"","model_l","model_r","name_l","name_r","icon","flag1","flag2","flag3","flag4", // 0-9 "","model_l","model_r","tex_l","tex_r","icon","geo1","geo2","geo3","geo4", // 0-9
"flag5","flags","helm1","helm2","AU","AL","HA","TU","TL","LU", // 10-19 "flag1","sound","helm1","helm2","AU","AL","HA","TU","TL","LU", // 10-19
"LL","FO","unk", // 20-22 "LL","FO","unk", // 20-22
"" ""
}; };
@ -372,6 +373,40 @@ static const char *NPCSoundsFormat = {
"iiiix" "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"
};

View File

@ -11,14 +11,18 @@
#include "StuffExtract.h" #include "StuffExtract.h"
#include "DBCFieldData.h" #include "DBCFieldData.h"
#include "Locale.h" #include "Locale.h"
#include "ProgressBar.h"
std::map<uint32,std::string> mapNames; std::map<uint32,std::string> mapNames;
std::set<std::string> texNames;
std::set<std::string> modelNames;
std::set<std::string> wmoNames;
std::set<std::string> soundFileSet;
// default config; SCPs are dont always std::set<NameAndAlt> texNames;
std::set<NameAndAlt> modelNames;
std::set<NameAndAlt> wmoNames;
std::set<NameAndAlt> soundFileSet;
// default config; SCPs are done always
bool doMaps=true, doSounds=false, doTextures=false, doWmos=false, doModels=false, doMd5=true, doAutoclose=false; 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!! // TODO: as soon as M2 model or WMO reading is done, extract those textures to, but independent from maps!!
if(!doMaps) if(!doMaps)
{ {
doTextures = false;
doWmos = false; doWmos = false;
} }
if(help) if(help)
@ -146,7 +149,7 @@ void PrintHelp(void)
printf("Use + or - to turn a feature on or off.\n"); printf("Use + or - to turn a feature on or off.\n");
printf("Features are:\n"); printf("Features are:\n");
printf("maps - map extraction\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("wmos - extract map WMOs (requires maps extraction)\n");
printf("models - extract models\n"); printf("models - extract models\n");
printf("sounds - extract sound files (wav/mp3)\n"); printf("sounds - extract sound files (wav/mp3)\n");
@ -250,9 +253,9 @@ bool ConvertDBC(void)
{ {
std::map<uint8,std::string> racemap; // needed to extract other dbc files correctly std::map<uint8,std::string> racemap; // needed to extract other dbc files correctly
SCPStorageMap EmoteDataStorage,RaceDataStorage,SoundDataStorage,MapDataStorage,ZoneDataStorage,ItemDisplayInfoStorage, 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, DBCFile EmotesText,EmotesTextData,EmotesTextSound,ChrRaces,SoundEntries,Map,AreaTable,ItemDisplayInfo,
CreatureModelData,CreatureDisplayInfo,NPCSounds; CreatureModelData,CreatureDisplayInfo,NPCSounds,CharSections;
printf("Opening DBC archive...\n"); printf("Opening DBC archive...\n");
MPQHelper mpq("dbc"); MPQHelper mpq("dbc");
@ -268,6 +271,7 @@ bool ConvertDBC(void)
CreatureModelData.openmem(mpq.ExtractFile("DBFilesClient\\CreatureModelData.dbc")); CreatureModelData.openmem(mpq.ExtractFile("DBFilesClient\\CreatureModelData.dbc"));
CreatureDisplayInfo.openmem(mpq.ExtractFile("DBFilesClient\\CreatureDisplayInfo.dbc")); CreatureDisplayInfo.openmem(mpq.ExtractFile("DBFilesClient\\CreatureDisplayInfo.dbc"));
NPCSounds.openmem(mpq.ExtractFile("DBFilesClient\\NPCSounds.dbc")); NPCSounds.openmem(mpq.ExtractFile("DBFilesClient\\NPCSounds.dbc"));
CharSections.openmem(mpq.ExtractFile("DBFilesClient\\CharSections.dbc"));
//... //...
printf("DBC files opened.\n"); 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 // fill up file storage. not necessary if we dont want to extract sounds
if(doSounds && field >= SOUNDENTRY_FILE_1 && field <= SOUNDENTRY_FILE_10) 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])) if(strlen(ItemDisplayInfoFieldNames[field]))
{ {
// TODO: need to get
std::string value = AutoGetDataString(it,ItemDisplayInfoFormat,field); std::string value = AutoGetDataString(it,ItemDisplayInfoFormat,field);
if(value.size()) // only store if not null if(value.size()) // only store if not null
ItemDisplayInfoStorage[id].push_back(std::string(ItemDisplayInfoFieldNames[field]) + "=" + value); 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(value.size()) // only store if not null
{ {
if(doModels) 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); std::string fn = _PathToFileName(value);
if(stricmp(fn.c_str()+fn.length()-4, "mdx")) if(stricmp(fn.c_str()+fn.length()-4, "mdx"))
fn = fn.substr(0,fn.length()-3) + "m2"; 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\<race>\<texture>
// 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("creaturemodeldata.."); OutSCP(SCPDIR "/creaturemodeldata.scp",CreatureModelStorage,"creaturemodeldata");
printf("creaturedisplayinfo.."); OutSCP(SCPDIR "/creaturedisplayinfo.scp",CreatureDisplayInfoStorage,"creaturedisplayinfo"); printf("creaturedisplayinfo.."); OutSCP(SCPDIR "/creaturedisplayinfo.scp",CreatureDisplayInfoStorage,"creaturedisplayinfo");
printf("npcsound.."); OutSCP(SCPDIR "/npcsound.scp",NPCSoundStorage,"npcsound"); printf("npcsound.."); OutSCP(SCPDIR "/npcsound.scp",NPCSoundStorage,"npcsound");
printf("charsections.."); OutSCP(SCPDIR "/charsections.scp",CharSectionStorage,"charsections");
//... //...
printf("DONE!\n"); printf("DONE!\n");
@ -579,6 +620,7 @@ void ExtractMaps(void)
void ExtractMapDependencies(void) void ExtractMapDependencies(void)
{ {
barGoLink *bar;
printf("\nExtracting map dependencies...\n\n"); printf("\nExtracting map dependencies...\n\n");
printf("- Preparing to read MPQ arcives...\n"); printf("- Preparing to read MPQ arcives...\n");
MPQHelper mpqmodel("model"); MPQHelper mpqmodel("model");
@ -588,124 +630,149 @@ void ExtractMapDependencies(void)
std::string pathtex = path + "/texture"; std::string pathtex = path + "/texture";
std::string pathmodel = path + "/model"; std::string pathmodel = path + "/model";
std::string pathwmo = path + "/wmo"; std::string pathwmo = path + "/wmo";
std::string mpqfn,realfn; std::string mpqfn,realfn,altfn;
MD5FileMap md5Tex, md5Wmo, md5Model; MD5FileMap md5Tex, md5Wmo, md5Model;
CreateDir(pathtex.c_str()); CreateDir(pathtex.c_str());
CreateDir(pathmodel.c_str()); CreateDir(pathmodel.c_str());
CreateDir(pathwmo.c_str()); CreateDir(pathwmo.c_str());
uint32 wmosdone=0,texdone=0,mdone=0; uint32 wmosdone=0,texdone=0,mdone=0;
for(std::set<std::string>::iterator i = texNames.begin(); i != texNames.end(); i++) if(doTextures)
{ {
mpqfn = *i; printf("Extracting textures...\n");
if(!mpqtex.FileExists((char*)mpqfn.c_str())) bar = new barGoLink(texNames.size(), true);
continue; for(std::set<NameAndAlt>::iterator i = texNames.begin(); i != texNames.end(); i++)
realfn = pathtex + "/" + _PathToFileName(mpqfn);
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()); bar->step();
fh.write((const char*)bb.contents(),bb.size()); mpqfn = i->name;
if(doMd5) altfn = i->alt;
{ if(altfn.empty())
MD5Hash h; altfn = mpqfn;
h.Update((uint8*)bb.contents(), bb.size()); if(!mpqtex.FileExists((char*)mpqfn.c_str()))
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<std::string>::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"));
continue; 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 else
{ printf("Could not write texture %s\n",realfn.c_str());
mpqfn = alt; fh.close();
DEBUG(printf(" success.\n"));
}
} }
realfn = pathmodel + "/" + _PathToFileName(mpqfn); printf("\n");
std::fstream fh; if(texNames.size())
fh.open(realfn.c_str(),std::ios_base::out | std::ios_base::binary); OutMD5((char*)pathtex.c_str(),md5Tex);
if(fh.is_open()) delete bar;
{
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(modelNames.size() && doModels)
OutMD5((char*)pathmodel.c_str(),md5Model);
for(std::set<std::string>::iterator i = wmoNames.begin(); i != wmoNames.end(); i++) if(doModels)
{ {
mpqfn = *i; printf("Extracting models...\n");
if(!mpqwmo.FileExists((char*)mpqfn.c_str())) bar = new barGoLink(modelNames.size(),true);
continue; for(std::set<NameAndAlt>::iterator i = modelNames.begin(); i != modelNames.end(); i++)
realfn = pathwmo + "/" + _PathToFileName(mpqfn);
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()); bar->step();
fh.write((const char*)bb.contents(),bb.size()); mpqfn = i->name;
if(doMd5) // 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; std::string alt = mpqfn.substr(0,mpqfn.length()-3) + "m2";
h.Update((uint8*)bb.contents(), bb.size()); if(!mpqmodel.FileExists((char*)alt.c_str()))
h.Finalize(); {
uint8 *md5ptr = new uint8[MD5_DIGEST_LENGTH]; printf("Failed to extract model: '%s'\n",alt.c_str());
md5Wmo[_PathToFileName(realfn)] = md5ptr; continue;
memcpy(md5ptr, h.GetDigest(), MD5_DIGEST_LENGTH); }
else
{
mpqfn = alt;
}
} }
wmosdone++; altfn = i->alt;
printf("- WMOs... %u\r",wmosdone); 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("\n");
printf("Could not write WMO %s\n",realfn.c_str()); if(modelNames.size())
fh.close(); OutMD5((char*)pathmodel.c_str(),md5Model);
delete bar;
}
if(doWmos)
{
printf("Extracting textures...\n");
bar = new barGoLink(wmoNames.size(),true);
for(std::set<NameAndAlt>::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()); printf("\nExtracting game audio files, %u found in DBC...\n",soundFileSet.size());
CreateDir(SOUNDDIR); CreateDir(SOUNDDIR);
MPQHelper smpq("sound"); MPQHelper smpq("sound");
std::string outfn; std::string outfn, altfn;
for(std::set<std::string>::iterator i = soundFileSet.begin(); i != soundFileSet.end(); i++) barGoLink bar(soundFileSet.size(),true);
for(std::set<NameAndAlt>::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; continue;
} }
altfn = i->alt.empty() ? _PathToFileName(i->name) : i->alt;
outfn = std::string(SOUNDDIR) + "/" + _PathToFileName(*i); outfn = std::string(SOUNDDIR) + "/" + altfn;
std::fstream fh; std::fstream fh;
fh.open(outfn.c_str(), std::ios_base::out | std::ios_base::binary); fh.open(outfn.c_str(), std::ios_base::out | std::ios_base::binary);
if(fh.is_open()) if(fh.is_open())
{ {
ByteBuffer& bb = smpq.ExtractFile((char*)(*i).c_str()); ByteBuffer& bb = smpq.ExtractFile((char*)i->name.c_str());
if(bb.size()) if(bb.size())
{ {
fh.write((const char*)bb.contents(),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.Update((uint8*)bb.contents(), bb.size());
h.Finalize(); h.Finalize();
uint8 *md5ptr = new uint8[MD5_DIGEST_LENGTH]; uint8 *md5ptr = new uint8[MD5_DIGEST_LENGTH];
md5data[_PathToFileName(*i)] = md5ptr; md5data[altfn] = md5ptr;
memcpy(md5ptr, h.GetDigest(), MD5_DIGEST_LENGTH); memcpy(md5ptr, h.GetDigest(), MD5_DIGEST_LENGTH);
} }
done++; done++;
printf("- %u files done.\r",done);
} }
} }
else else
@ -757,6 +826,44 @@ void ExtractSoundFiles(void)
printf("\n"); printf("\n");
} }
void ADT_ExportStringSetByOffset(const uint8* data, uint32 off, std::set<NameAndAlt>& 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<NameAndAlt>& st)
{
ADT_ExportStringSetByOffset(data,OFFSET_TEXTURES,st,"XDMM");
}
void ADT_FillWMOData(const uint8* data,std::set<NameAndAlt>& st)
{
ADT_ExportStringSetByOffset(data,OFFSET_WMOS,st,"DIWM");
}
void ADT_FillModelData(const uint8* data,std::set<NameAndAlt>& st)
{
ADT_ExportStringSetByOffset(data,OFFSET_MODELS,st,"DIMM");
}

View File

@ -14,6 +14,20 @@
typedef std::map< uint32,std::list<std::string> > SCPStorageMap; typedef std::map< uint32,std::list<std::string> > SCPStorageMap;
typedef std::map<std::string,uint8*> MD5FileMap; typedef std::map<std::string,uint8*> 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[]); int main(int argc, char *argv[]);
void ProcessCmdArgs(int argc, char *argv[]); void ProcessCmdArgs(int argc, char *argv[]);
void PrintConfig(void); void PrintConfig(void);
@ -25,4 +39,10 @@ void ExtractMaps(void);
void ExtractMapDependencies(void); void ExtractMapDependencies(void);
void ExtractSoundFiles(void); void ExtractSoundFiles(void);
void ADT_ExportStringSetByOffset(const uint8*, uint32, std::set<NameAndAlt>&, char*);
void ADT_FillTextureData(const uint8*,std::set<NameAndAlt>&);
void ADT_FillWMOData(const uint8*,std::set<NameAndAlt>&);
void ADT_FillModelData(const uint8*,std::set<NameAndAlt>&);
#endif #endif