* 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 "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

View File

@ -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)
{

View File

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

View File

@ -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)

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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:

View File

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

View File

@ -144,6 +144,12 @@
<File
RelativePath=".\shared\log.h">
</File>
<File
RelativePath=".\shared\ProgressBar.cpp">
</File>
<File
RelativePath=".\shared\ProgressBar.h">
</File>
<File
RelativePath=".\shared\SysDefs.h">
</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;
};
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

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].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;

View File

@ -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
};

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_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"
};

View File

@ -11,14 +11,18 @@
#include "StuffExtract.h"
#include "DBCFieldData.h"
#include "Locale.h"
#include "ProgressBar.h"
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;
@ -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<uint8,std::string> 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\<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("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<std::string>::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<NameAndAlt>::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<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"));
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<std::string>::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<NameAndAlt>::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<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());
CreateDir(SOUNDDIR);
MPQHelper smpq("sound");
std::string outfn;
for(std::set<std::string>::iterator i = soundFileSet.begin(); i != soundFileSet.end(); i++)
std::string outfn, altfn;
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;
}
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<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<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[]);
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<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