* WMO Mesh file loader

* WMOs are not rotated correctly yet
* Stuffextract and MapMgr patched to display WMOs
* Also some small fixes to pacify GCC
This commit is contained in:
shlainn 2009-07-15 08:31:43 +00:00
parent 8bef509a21
commit 7c885d2b50
13 changed files with 755 additions and 65 deletions

View File

@ -0,0 +1,334 @@
#include <iostream>
#include <cstdarg>
#include "MemoryDataHolder.h"
#include "MemoryInterface.h"
#include "CWMOMeshFileLoader.h"
#include "SSkinnedMesh.h"
#include "common.h"
inline void flipcc(irr::u8 *fcc)
{
char t;
t=fcc[0];
fcc[0]=fcc[3];
fcc[3]=t;
t=fcc[1];
fcc[1]=fcc[2];
fcc[2]=t;
}
namespace irr
{
namespace scene
{
CWMOMeshFileLoader::CWMOMeshFileLoader(IrrlichtDevice* device, c8* texdir):Device(device), Texdir(texdir)
{
Mesh = NULL;
}
CWMOMeshFileLoader::~CWMOMeshFileLoader()
{
}
bool CWMOMeshFileLoader::isALoadableFileExtension(const c8* filename)const
{
return strstr(filename, ".wmo")!=0;
}
//! creates/loads an animated mesh from the file.
//! \return Pointer to the created mesh. Returns 0 if loading failed.
//! If you no longer need the mesh, you should call IAnimatedMesh::drop().
//! See IUnknown::drop() for more information.
IAnimatedMesh* CWMOMeshFileLoader::createMesh(io::IReadFile* file)
{
if(!file)
return 0;
MeshFile = file;
std::string filename=MeshFile->getFileName();
Mesh = new scene::CSkinnedMesh();
if ( load(true) )//We try loading a root file first!
{
for(u32 i=0;i<rootHeader.nGroups;i++)//On success, load all group files. This is getting slow as molasses for large files like Stormwind.wmo
{
char grpfilename[255];
sprintf(grpfilename,"%s_%03u.wmo",filename.substr(0,filename.length()-4).c_str(),i);
logdebug("%s",grpfilename);
MeshFile = io::IrrCreateIReadFileBasic(Device,grpfilename);
if(!MeshFile)
{
logerror("Could not read file %s!",grpfilename);
return 0;
}
load(false);
}
Mesh->recalculateBoundingBox();
Device->getSceneManager()->getMeshManipulator()->flipSurfaces(Mesh); //Fix inverted surfaces after the rotation
//Does this crash on windows?
Device->getSceneManager()->getMeshManipulator()->recalculateNormals(Mesh,true);//just to be sure
logdebug("Complete Mesh contains a total of %u submeshes!",Mesh->getMeshBufferCount());
}
else
{
Mesh->drop();
Mesh = 0;
}
return Mesh;
}
bool CWMOMeshFileLoader::load(bool _root)
{
bool isRootFile = _root;
u8 _cc[5];
u8 *fourcc = &_cc[0];
fourcc[4]=0;
u32 size;
u32 textureOffset;
logdebug("Trying to open file %s",MeshFile->getFileName());
while(MeshFile->getPos() < MeshFile->getSize())
{
printf("position 0x%lX ",MeshFile->getPos());
MeshFile->read(fourcc,4);
MeshFile->read(&size,4);
flipcc(fourcc);
printf("Reading Chunk: %s size %u\n", (char*)fourcc,size);
if(!strcmp((char*)fourcc,"MVER")){
logdebug("MVER Chunk: %s",(char*)fourcc);
MeshFile->seek(size,true);
}
//Start root file parsing
else if(!strcmp((char*)fourcc,"MOHD")){
MeshFile->read(&rootHeader,sizeof(RootHeader));
logdebug("Read Root Header: %u Textures, %u Groups, %u Models", rootHeader.nTextures, rootHeader.nGroups, rootHeader.nModels);
if(!isRootFile)//We should be reading a group file and found a root header, abort
return 0;
}
else if(!strcmp((char*)fourcc,"MOTX")){
textureOffset=MeshFile->getPos();
MeshFile->seek(size,true);
}
else if(!strcmp((char*)fourcc,"MOMT")){
if(WMOMTexDefinition.size()>0)
WMOMTexDefinition.clear();
MOMT_Data tempMOMT;
for(u32 i =0;i<(size/sizeof(MOMT_Data));i++)
{
MeshFile->read(&tempMOMT,sizeof(MOMT_Data));
WMOMTexDefinition.push_back(tempMOMT);
}
logdebug("Read %u/%u TextureDefinitions",WMOMTexDefinition.size(),(size/sizeof(MOMT_Data)));
u32 tempOffset = MeshFile->getPos();//Save current position for further reading until texture file names are read.
if(WMOMTextureFiles.size()>0)
WMOMTextureFiles.clear();
std::string tempTexName;
u32 texNameSize;
for(u32 i =0;i<WMOMTexDefinition.size();i++)
{
texNameSize = WMOMTexDefinition[i].endNameIndex-WMOMTexDefinition[i].startNameIndex; tempTexName.resize(texNameSize);
MeshFile->seek(textureOffset+WMOMTexDefinition[i].startNameIndex);
MeshFile->read((void*)tempTexName.c_str(),WMOMTexDefinition[i].endNameIndex-WMOMTexDefinition[i].startNameIndex);
logdebug("Texture %u: %s",i,tempTexName.c_str());
WMOMTextureFiles.push_back(tempTexName.c_str());
}
MeshFile->seek(tempOffset);
}
//Start Group file parsing
else if(!strcmp((char*)fourcc,"MOGP")){
logdebug("header okay: %s",(char*)fourcc);
MeshFile->seek(68,true);
if(isRootFile)//We should be reading a root file and found a Group header, abort
return 0;
}
else if(!strcmp((char*)fourcc,"MOPY")){//Texturing information (1 per triangle);
if(WMOMTexData.size()>0)
WMOMTexData.clear();
submeshes.clear();//Saves last vertex of submes
u16 previous_texid=999;//outside u8 space
MOPY_Data tempMOPY;
for(u32 i =0;i<(size/sizeof(MOPY_Data));i++)
{
MeshFile->read(&tempMOPY,sizeof(MOPY_Data));
if(previous_texid==999)
previous_texid=tempMOPY.textureID;//Initialize
WMOMTexData.push_back(tempMOPY);
if(previous_texid!=tempMOPY.textureID)
submeshes.push_back(i);
previous_texid=tempMOPY.textureID;
}
submeshes.push_back(WMOMTexData.size()-1);//last read entry
logdebug("Read %u/%u Texture Informations, counted %u submeshes",WMOMTexData.size(),(size/sizeof(MOPY_Data)),submeshes.size());
}
else if(!strcmp((char*)fourcc,"MOVI")){//Vertex indices (3 per triangle)
if(WMOMIndices.size()>0)
WMOMIndices.clear();
u16 tempWMOIndex;
for(u32 i =0;i<(size/sizeof(u16));i++)
{
MeshFile->read(&tempWMOIndex,sizeof(u16));
WMOMIndices.push_back(tempWMOIndex);
}
logdebug("Read %u/%u Indices",WMOMIndices.size(),(size/sizeof(u16)));
}
else if(!strcmp((char*)fourcc,"MOVT")){//Vertex coordinates
if(WMOMVertices.size()>0)
WMOMVertices.clear();
core::vector3df tempWMOVertex;
float tempYZ;
for(u32 i =0;i<(size/sizeof(core::vector3df));i++)
{
MeshFile->read(&tempWMOVertex,sizeof(core::vector3df));
tempYZ = tempWMOVertex.Y;
tempWMOVertex.Y=tempWMOVertex.Z;
tempWMOVertex.Z=tempYZ;
WMOMVertices.push_back(tempWMOVertex);
}
logdebug("Read %u/%u Vertex Coordinates",WMOMVertices.size(),(size/sizeof(core::vector3df)));
}
else if(!strcmp((char*)fourcc,"MONR")){//Normals
if(WMOMNormals.size()>0)
WMOMNormals.clear();
core::vector3df tempWMONormal;
float tempYZ;
for(u32 i =0;i<(size/sizeof(core::vector3df));i++)
{
MeshFile->read(&tempWMONormal,sizeof(core::vector3df));
tempYZ = tempWMONormal.Y;
tempWMONormal.Y=tempWMONormal.Z;
tempWMONormal.Z=tempYZ;
WMOMNormals.push_back(tempWMONormal);
}
logdebug("Read %u/%u Normal Coordinates",WMOMNormals.size(),(size/sizeof(core::vector3df)));
}
else if(!strcmp((char*)fourcc,"MOTV")){//TexCoord
if(WMOMTexcoord.size()>0)
WMOMTexcoord.clear();
core::vector2df tempWMOMTexcoord;
for(u32 i =0;i<(size/sizeof(core::vector2df));i++)
{
MeshFile->read(&tempWMOMTexcoord,sizeof(core::vector2df));
WMOMTexcoord.push_back(tempWMOMTexcoord);
}
logdebug("Read %u/%u Texture Coordinates",WMOMTexcoord.size(),(size/sizeof(core::vector2df)));
}
else if(!strcmp((char*)fourcc,"MOCV")){//Vertex colors!! Scaaaary!
if(WMOMVertexColor.size()>0)
WMOMVertexColor.clear();
WMOColor tempWMOMVertexColor;
for(u32 i =0;i<(size/sizeof(WMOColor));i++)
{
MeshFile->read(&tempWMOMVertexColor,sizeof(WMOColor));
WMOMVertexColor.push_back(video::SColor(tempWMOMVertexColor.a,tempWMOMVertexColor.r,tempWMOMVertexColor.g,tempWMOMVertexColor.b));
}
logdebug("Read %u/%u Vertex colors",WMOMVertexColor.size(),(size/sizeof(WMOColor)));
}
//End Group file parsing
else
MeshFile->seek(size,true);//Skip Chunk
}
if(!isRootFile)//If we just read a group file, add a mesh buffer to the main Mesh
{
if(WMOVertices.size()>0)
WMOVertices.clear();
for(u32 i=0;i<WMOMVertices.size();i++)
{
//WMOMVertices, Normals and stuff are not usable like this. Thus we build Vertices in irrlicht format
//rotation happens when reading from file, so swapping Y and Z here is no longer necessary
WMOVertices.push_back(video::S3DVertex(WMOMVertices[i],WMOMNormals[i], video::SColor(255,100,100,100),WMOMTexcoord[i]));
}
u32 lastindex=0;
for(u32 i=0;i<submeshes.size();i++)//The mesh has to be split into submeshes because irrlicht only handles 1 texture per meshbuffer (not quite correct but i am to lazy to explain now)
{
if(WMOMTexData[lastindex].textureID!=255)
{
scene::SSkinMeshBuffer *MeshBuffer = Mesh->createBuffer();
//Put the Indices and Vertices of the Submesh into a mesh buffer
for(u32 j=lastindex;j<submeshes[i];j++)
{
if((j*3+2)<WMOMIndices.size()&&WMOMTexData[j].textureID!=255)
{
MeshBuffer->Indices.push_back(WMOMIndices[j*3]);
MeshBuffer->Indices.push_back(WMOMIndices[j*3+1]);
MeshBuffer->Indices.push_back(WMOMIndices[j*3+2]);
}
}
logdebug("Inserted %u Indices/n",MeshBuffer->Indices.size());
for(u32 j=0;j<WMOVertices.size();j++)
{
MeshBuffer->Vertices_Standard.push_back(WMOVertices[j]);
}
logdebug("Inserted %u Vertices/n",MeshBuffer->Vertices_Standard.size());
std::string TexName=Texdir.c_str();
TexName+="/";
TexName+=WMOMTextureFiles[WMOMTexData[lastindex].textureID].c_str();
while(TexName.find('\\')<TexName.size())//Replace \ by /
{
TexName.replace(TexName.find('\\'),1,"/");
}
while(TexName.find(' ')<TexName.size())//Replace space by _
{
TexName.replace(TexName.find(' '),1,"_");
}
std::transform(TexName.begin(), TexName.end(), TexName.begin(), tolower);
MeshBuffer->getMaterial().setTexture(0,Device->getVideoDriver()->getTexture(TexName.c_str()));
if(WMOMTexDefinition[WMOMTexData[lastindex].textureID].blendMode==1)
MeshBuffer->getMaterial().MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL;
MeshBuffer->recalculateBoundingBox();
}
lastindex=submeshes[i];
}
WMOMIndices.clear();
WMOMVertices.clear();
WMOMNormals.clear();
WMOMTexcoord.clear();
WMOMVertexColor.clear();
WMOVertices.clear();
}
return true;
}
}
}

View File

@ -0,0 +1,132 @@
#include "irrlicht/irrlicht.h"
#include "irrlicht/IMeshLoader.h"
#include "SSkinnedMesh.h"
#include <string>
#include <vector>
#include <algorithm>
namespace irr
{
namespace scene
{
struct RootHeader {
/*000h*/ u32 nTextures;
/*004h*/ u32 nGroups;
/*008h*/ u32 nPortals;
/*00Ch*/ u32 nLights;
/*010h*/ u32 nModels;
/*014h*/ u32 nDoodads;
/*018h*/ u32 nSets;
/*01Ch*/ u8 colR;
/*01Dh*/ u8 colG;
/*01Eh*/ u8 colB;
/*01Fh*/ u8 colX;
/*020h*/ u32 wmoID;
/*024h*/ float bb1[3];
/*030h*/ float bb2[3];
/*03Ch*/ u32 nullish;
};
struct WMOColor{
u8 b,g,r,a;
};
struct MOPY_Data{
u8 flags,textureID;
};
struct MOMT_Data{
/*000h*/ u32 flags1;
/*004h*/ u32 flags2;
/*008h*/ u32 blendMode;
/*00Ch*/ u32 startNameIndex;
/*010h*/ u32 color;
/*014h*/ u32 unk1;
/*018h*/ u32 endNameIndex;
/*01Ch*/ u32 frameSidnColor[3];
/*020h*/
/*024h*/
/*028h*/ u32 envNameIndex;
/*02Ch*/ float diffColor[3];
/*030h*/
/*034h*/
/*038h*/ u32 groundType;
/*03Ch*/ u32 hMaps;
};
class CWMOMeshFileLoader : public IMeshLoader
{
public:
//! Constructor
CWMOMeshFileLoader(IrrlichtDevice* device, c8* texdir);
//! destructor
virtual ~CWMOMeshFileLoader();
//! returns true if the file maybe is able to be loaded by this class
//! based on the file extension (e.g. ".cob")
virtual bool isALoadableFileExtension(const c8* fileName)const;
//! creates/loads an animated mesh from the file.
//! \return Pointer to the created mesh. Returns 0 if loading failed.
//! If you no longer need the mesh, you should call IAnimatedMesh::drop().
//! See IUnknown::drop() for more information.
virtual scene::IAnimatedMesh* createMesh(io::IReadFile* file);
private:
bool load(bool _root);
IrrlichtDevice* Device;
core::stringc Texdir;
io::IReadFile* MeshFile;
CSkinnedMesh* Mesh;
//Stuff from root file
RootHeader rootHeader;
core::array<MOMT_Data> WMOMTexDefinition;
core::array<std::string> WMOMTextureFiles;
//Stuff from group file
core::array<u16> WMOMIndices;
core::array<core::vector3df> WMOMVertices;
core::array<core::vector3df> WMOMNormals;
core::array<core::vector2df> WMOMTexcoord;
core::array<video::SColor> WMOMVertexColor;
core::array<MOPY_Data> WMOMTexData;
core::array<u16> submeshes;
core::array<video::S3DVertex> WMOVertices;
SSkinMeshBuffer* MeshBuffer;
/*
ModelHeader header;
core::stringc WMOMeshName;
SMesh* Mesh;
//
//Taken from the Model file, thus m2M*
core::array<ModelVertex> WMOMVertices;
core::array<ModelView> WMOMViews;
core::array<u16> WMOMIndices;
core::array<u16> WMOMTriangles;
core::array<ModelViewSubmesh> WMOMSubmeshes;
core::array<u16> WMOMTextureLookup;
core::array<TextureDefinition> WMOMTextureDef;
core::array<std::string> WMOMTextureFiles;
core::array<TextureUnit> WMOMTextureUnit;
core::array<RenderFlags> WMOMRenderFlags;
core::array<Animation> WMOMAnimations;
core::array<Bone> WMOMBones;
//Used for the Mesh, thus m2_noM_*
core::array<video::S3DVertex> WMOVertices;
core::array<u16> WMOIndices;
core::array<scene::ISkinnedMesh::SJoint> WMOJoints;
*/
};
}//namespace scene
}//namespace irr

View File

@ -11,7 +11,8 @@ CM2MeshFileLoader.h MCamera.h SceneGuiStart.cpp SImage.cpp Scene
CIrrKlangAudioStreamLoaderMP3.cpp CIrrKlangAudioStreamLoaderMP3.h CIrrKlangAudioStreamMP3.cpp CIrrKlangAudioStreamMP3.h\
ikpMP3.cpp decoder/bits.c decoder/internal.h decoder/mpaudec.c decoder/mpaudec.h decoder/mpaudectab.h decoder/mpegaudio.h\
irrKlangSceneNode.cpp irrKlangSceneNode.h CBoneSceneNode.cpp CBoneSceneNode.h SSkinnedMesh.cpp SSkinnedMesh.h\
CMDHMemoryReadFile.cpp CMDHMemoryReadFile.h MemoryInterface.cpp MemoryInterface.h
CMDHMemoryReadFile.cpp CMDHMemoryReadFile.h MemoryInterface.cpp MemoryInterface.h\
CWMOMeshFileLoader.cpp CWMOMeshFileLoader.h
libgui_a_LIBADD = $(top_builddir)/src/shared/libshared.a $(top_builddir)/src/shared/Auth/libauth.a $(top_builddir)/src/shared/Network/libnetwork.a

View File

@ -1,6 +1,7 @@
#include "common.h"
#include "irrlicht/irrlicht.h"
#include "CM2MeshFileLoader.h"
#include "CWMOMeshFileLoader.h"
#include "CImageLoaderBLP.h"
#include "Object.h"
#include "DrawObject.h"
@ -132,6 +133,8 @@ void PseuGUI::_Init(void)
_driver->addExternalImageLoader(BLPloader);
scene::CM2MeshFileLoader* m2loader = new scene::CM2MeshFileLoader(_device, "./data/texture");
_smgr->addExternalMeshLoader(m2loader);
scene::CWMOMeshFileLoader* wmoloader = new scene::CWMOMeshFileLoader(_device, "./data/texture");
_smgr->addExternalMeshLoader(wmoloader);
_throttle=0;
_initialized = true;

View File

@ -57,6 +57,19 @@ namespace scene
//! set user axis aligned bounding box
virtual void setBoundingBox( const core::aabbox3df& box);
//! recalculates the bounding box
void recalculateBoundingBox()
{
if (LocalBuffers.size())
{
BoundingBox = LocalBuffers[0]->getBoundingBox();
for (u32 i=1; i<LocalBuffers.size(); ++i)
BoundingBox.addInternalBox(LocalBuffers[i]->getBoundingBox());
}
else
BoundingBox.reset(0.0f, 0.0f, 0.0f);
}
//! sets a flag of all contained materials to a new value
virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue);

View File

@ -112,7 +112,7 @@ private:
IGUIListBox *charlistbox; // temporary until something better found
//Character creation //temporary. maybe a whole new character creation scene should be used?
IGUIWindow *newcharwin;
IGUIComboBox *raceselect;
IGUIComboBox *raceselect;
IGUIComboBox *classselect;
IGUIEditBox *charname;
IGUIElement *msgbox; // display status/result of character creation
@ -167,6 +167,7 @@ private:
IGUIStaticText *debugText;
bool debugmode;
std::map<uint32,SceneNodeWithGridPos> _doodads;
std::map<uint32,SceneNodeWithGridPos> _wmos;
std::map<uint32,SceneNodeWithGridPos> _sound_emitters;
scene::ISceneNode *sky;
scene::ISceneNode *selectedNode, *oldSelectedNode, *focusedNode, *oldFocusedNode;

View File

@ -645,10 +645,10 @@ void SceneWorld::UpdateTerrain(void)
// here:
// doodad->setRotation(core::vector3df(-d->ox,0,-d->oz)); // rotated axes looks good
// doodad->setRotation(core::vector3df(0,-d->oy,0)); // same here
doodad->setRotation(core::vector3df(-d->ox,-d->oy,-d->oz)); // very ugly with some rotations, |ang|>360?
doodad->setRotation(core::vector3df(-d->ox,-d->oy,-d->oz)); // very ugly with some rotations, |ang|>360?
doodad->setScale(core::vector3df(d->scale, d->scale, d->scale));
// smgr->addTextSceneNode(this->device->getGUIEnvironment()->getBuiltInFont(), (irr::core::stringw(L"")+(float)d->uniqueid).c_str() , irr::video::SColor(255,255,255,255),doodad, irr::core::vector3df(0,5,0));
SceneNodeWithGridPos gp;
gp.gx = mapmgr->GetGridX() + tilex - 1;
@ -659,6 +659,49 @@ void SceneWorld::UpdateTerrain(void)
}
}
}
// create WorldMapObjects (WMOs)
logdebug("Loading %u WMOs for tile (%u, %u)", maptile->GetWMOCount(), tile_real_x, tile_real_y);
for(uint32 i = 0; i < maptile->GetWMOCount(); i++)
{
WorldMapObject *wmo = maptile->GetWMO(i);
if(_wmos.find(wmo->uniqueid) == _wmos.end()) // only add wmos that dont exist yet
{
scene::IAnimatedMesh *mesh = smgr->getMesh(wmo->model.c_str());
if(mesh)
{
scene::IAnimatedMeshSceneNode *wmo_node = smgr->addAnimatedMeshSceneNode(mesh);
if(wmo_node)
{
for(u32 m = 0; m < wmo_node->getMaterialCount(); m++)
{
wmo_node->getMaterial(m).setFlag(EMF_FOG_ENABLE, true);
}
wmo_node->setAutomaticCulling(EAC_BOX);
// this is causing the framerate to drop to ~1. better leave it disabled for now :/
//doodad->addShadowVolumeSceneNode();
wmo_node->setPosition(core::vector3df(-wmo->x, wmo->z, -wmo->y));
// Rotation problems
// MapTile.cpp - changed to
// d.ox = mddf.c; d.oy = mddf.b; d.oz = mddf.a;
// its nonsense to do d.oy = mddf.b-90; and rotation with -d->oy-90 = -(mddf.b-90)-90 = -mddf.b
// here:
// doodad->setRotation(core::vector3df(-d->ox,0,-d->oz)); // rotated axes looks good
// doodad->setRotation(core::vector3df(0,-d->oy,0)); // same here
//wmo_node->setRotation(core::vector3df(-wmo->ox,-wmo->oy,-wmo->oz)); // very ugly with some rotations, |ang|>360?
//wmo_node->setScale(core::vector3df(5,5,5));
// smgr->addTextSceneNode(this->device->getGUIEnvironment()->getBuiltInFont(), (irr::core::stringw(L"")+(float)d->uniqueid).c_str() , irr::video::SColor(255,255,255,255),doodad, irr::core::vector3df(0,5,0));
SceneNodeWithGridPos gp;
gp.gx = mapmgr->GetGridX() + tilex - 1;
gp.gy = mapmgr->GetGridY() + tiley - 1;
gp.scenenode = wmo_node;
_wmos[wmo->uniqueid] = gp;
}
}
}
}
// create sound emitters
logdebug("Loading %u sound emitters for tile (%u, %u)", maptile->GetSoundEmitterCount(), tile_real_x, tile_real_y);
uint32 fieldId[10]; // SCP: file1 - file10 (index 0 not used)

View File

@ -60,7 +60,7 @@ WorldSession::~WorldSession()
GetInstance()->Sleep(1); // (it can cause crash otherwise)
logdebug("~WorldSession(): ... world GUI deleted, continuing to close session");
}
_instance->GetScripts()->RunScriptIfExists("_onworldsessiondelete");
logdebug("~WorldSession(): %u packets left unhandled, and %u delayed. deleting.",pktQueue.size(),delayedPktQueue.size());
@ -108,7 +108,7 @@ void WorldSession::Start(void)
_sh.Select(3,0);
GetInstance()->Sleep(100);
}
logdev("WorldSession::Start() done, mustdie:%u, socket_ok:%u stopped:%u",MustDie(),_socket->IsOk(),GetInstance()->Stopped());
logdev("WorldSession::Start() done, mustdie:%u, socket_ok:%u stopped:%u",MustDie(),_socket->IsOk(),GetInstance()->Stopped());
}
void WorldSession::_LoadCache(void)
@ -263,7 +263,7 @@ void WorldSession::HandleWorldPacket(WorldPacket *packet)
logerror("Data: pktsize=%u, handler=0x%X queuesize=%u",packet->size(),table[hpos].handler,pktQueue.size());
logerror("Packet Hexdump:");
logerror("%s",toHexDump((uint8*)packet->contents(),packet->size(),true).c_str());
if(GetInstance()->GetConf()->dumpPackets)
DumpPacket(*packet, packet->rpos(), "unknown exception");
}
@ -399,7 +399,7 @@ void WorldSession::AddSendWorldPacket(WorldPacket& pkt)
if(pkt.size())
wp->append(pkt.contents(),pkt.size());
sendPktQueue.add(wp);
}
}
void WorldSession::SetTarget(uint64 guid)
{
@ -457,7 +457,7 @@ std::string WorldSession::DumpPacket(WorldPacket& pkt, int errpos, const char *e
s << "DATA-HEX:\n";
s << toHexDump((uint8*)pkt.contents(),pkt.size(),true,32);
s << "\n";
s << "DATA-TEXT:\n";
for(uint32 i = 0; i < pkt.size(); i++)
{
@ -508,7 +508,7 @@ std::string WorldSession::GetOrRequestPlayerName(uint64 guid)
}
return name;
}
@ -836,7 +836,7 @@ void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket)
recvPacket >> source_guid >> unk; // added in 2.1.0
if (type == CHAT_MSG_CHANNEL)
{
{
recvPacket >> channel; // extract channel name
}
recvPacket >> target_guid >> msglen >> msg;
@ -1334,11 +1334,11 @@ void WorldSession::_HandleCastSuccessOpcode(WorldPacket& recvPacket)
if (GetMyChar()->GetGUID() == casterGuid)
logdetail("Cast of spell %u successful.",spellId);
else
else
{
Object *caster = objmgr.GetObj(casterGuid);
if(caster)
logdetail("%s casted spell %u", caster->GetName(), spellId);
logdetail("%s casted spell %u", caster->GetName().c_str(), spellId);
else
logerror("Caster of spell %u (GUID "I64FMT") is unknown object!",spellId,casterGuid);
}
@ -1550,7 +1550,7 @@ void WorldSession::_HandleWhoOpcode(WorldPacket& recvPacket)
{
_whoList.clear(); // need to clear current list only if requesting more then one player name
}
}
}
for(uint32 i = 0; i < count; i++)
{
@ -1641,7 +1641,7 @@ void WorldSession::_HandleCreatureQueryResponseOpcode(WorldPacket& recvPacket)
objmgr.Add(ct);
objmgr.AssignNameToObj(entry, TYPEID_UNIT, ct->name);
}
void WorldSession::_HandleGameobjectQueryResponseOpcode(WorldPacket& recvPacket)
{
uint32 entry;

View File

@ -98,6 +98,24 @@ void MapTile::ImportFromADT(ADTFile *adt)
_doodads.push_back(d);
}
// copy over wmos and do some transformations
DEBUG(logdebug("%u wmos", adt->_wmosp.size()));
for(uint32 i = 0; i < adt->_wmosp.size(); i++)
{
WorldMapObject wmo;
MODF_chunk& modf = adt->_wmosp[i];
wmo.y = -(modf.x - ZEROPOINT);
wmo.z = modf.y;
wmo.x = -(modf.z - ZEROPOINT);
wmo.ox = modf.ox;
wmo.oy = modf.oy;
wmo.oz = modf.oz;
wmo.flags = modf.flags;
wmo.uniqueid = modf.uniqueid;
wmo.model = std::string("./data/wmo/") + NormalizeFilename(_PathToFileName(adt->_wmos[modf.id]));
_wmo_data.push_back(wmo);
}
// copy sound emitters
_soundemm = adt->_soundemm;
@ -115,7 +133,7 @@ void MapTileStorage::_DebugDump(void)
{
for(uint32 j=0; j<64; j++)
{
out += (_hasTile[i*64 + j] ? "1" : "0");
}
out += "\n";

View File

@ -35,6 +35,14 @@ struct Doodad
std::string model;
};
struct WorldMapObject
{
uint32 uniqueid;
float x,y,z,ox,oy,oz;
uint16 flags,doodadset;
std::string model;
};
// generic map tile class. stores the information previously stored in an ADT file
// in an easier to use form.
class MapTile
@ -53,6 +61,8 @@ public:
inline Doodad *GetDoodad(uint32 i) { return &_doodads[i]; }
inline uint32 GetSoundEmitterCount(void) { return _soundemm.size(); }
inline MCSE_chunk *GetSoundEmitter(uint32 i) { return &_soundemm[i]; }
inline uint32 GetWMOCount(void) { return _wmo_data.size(); }
inline WorldMapObject *GetWMO(uint32 i) { return &_wmo_data[i]; }
private:
MapChunk _chunks[256]; // 16x16
@ -60,6 +70,7 @@ private:
std::vector<std::string> _wmos;
std::vector<std::string> _models;
std::vector<Doodad> _doodads;
std::vector<WorldMapObject> _wmo_data;
std::vector<MCSE_chunk> _soundemm;
float _xbase,_ybase,_hbase;

View File

@ -13,6 +13,7 @@
#include "Locale.h"
#include "ProgressBar.h"
#include "../../Client/GUI/CM2MeshFileLoader.h"
#include "../../Client/GUI/CWMOMeshFileLoader.h"
int replaceSpaces (int i) { return i==(int)' ' ? (int)'_' : i; }
@ -21,11 +22,12 @@ std::map<uint32,std::string> mapNames;
std::set<NameAndAlt> texNames;
std::set<NameAndAlt> modelNames;
std::set<NameAndAlt> wmoNames;
std::set<NameAndAlt> wmoGroupNames;
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, doWmogroups=false, doModels=false, doMd5=true, doAutoclose=false;
@ -52,7 +54,7 @@ int main(int argc, char *argv[])
CreateDir("stuffextract/data");
ConvertDBC();
if(doMaps) ExtractMaps();
if(doTextures || doModels || doWmos) ExtractMapDependencies();
if(doTextures || doModels || doWmos || doWmogroups) ExtractMapDependencies();
if(doSounds) ExtractSoundFiles();
//...
if (!doAutoclose)
@ -96,6 +98,7 @@ void ProcessCmdArgs(int argc, char *argv[])
if (!stricmp(what,"maps")) doMaps = on;
else if(!stricmp(what,"textures")) doTextures = on;
else if(!stricmp(what,"wmos")) doWmos = on;
else if(!stricmp(what,"wmogroups")) doWmogroups = on;
else if(!stricmp(what,"models")) doModels = on;
else if(!stricmp(what,"sounds")) doSounds = on;
else if(!stricmp(what,"md5")) doMd5 = on;
@ -125,6 +128,11 @@ void ProcessCmdArgs(int argc, char *argv[])
{
doWmos = false;
}
if(!doWmos)
{
doWmogroups = false;
}
if(help)
{
PrintHelp();
@ -139,6 +147,7 @@ void PrintConfig(void)
printf("config: Do maps: %s\n",doMaps?"yes":"no");
printf("config: Do textures: %s\n",doTextures?"yes":"no");
printf("config: Do wmos: %s\n",doWmos?"yes":"no");
printf("config: Do wmogroups: %s\n",doWmogroups?"yes":"no");
printf("config: Do models: %s\n",doModels?"yes":"no");
printf("config: Do sounds: %s\n",doSounds?"yes":"no");
printf("config: Calc md5: %s\n",doMd5?"yes":"no");
@ -153,6 +162,7 @@ void PrintHelp(void)
printf("maps - map extraction\n");
printf("textures - extract textures\n");
printf("wmos - extract map WMOs (requires maps extraction)\n");
printf("wmogroups - extract map WMO group files (requires maps and wmos extraction)\n");
printf("models - extract models\n");
printf("sounds - extract sound files (wav/mp3)\n");
printf("md5 - write MD5 checksum lists of extracted files\n");
@ -515,12 +525,16 @@ bool ConvertDBC(void)
if(value.size()) // only store if not null
{
// TODO: add check for wmo model files ?
if(doModels)
if(doModels && stricmp(value.c_str()+value.length()-4,".wmo"))
modelNames.insert(NameAndAlt(value)); // we need to extract model later, store it
else
wmoNames.insert(NameAndAlt(value)); //this is a WMO
//Interestingly, some of the files referenced here have MDL extension - WTF?
std::string fn = _PathToFileName(value);
if(stricmp(fn.c_str()+fn.length()-4, "mdx"))
if(!stricmp(fn.c_str()+fn.length()-3, "mdx") or !stricmp(fn.c_str()+fn.length()-3, "mdl"))
fn = fn.substr(0,fn.length()-3) + "m2";
else
logdebug("This should be a WMO: %s\n",fn.c_str());
GameObjectDisplayInfoStorage[id].push_back(std::string(GameObjectDisplayInfoFieldNames[field]) + "=" + fn);
std::string texture = value.substr(0,value.length()-3) + "blp";
@ -709,12 +723,99 @@ void ExtractMapDependencies(void)
std::string pathmodel = path + "/model";
std::string pathwmo = path + "/wmo";
std::string mpqfn,realfn,altfn;
MD5FileMap md5Tex, md5Wmo, md5Model;
MD5FileMap md5Tex, md5Wmo, md5Wmogroup, md5Model;
CreateDir(pathtex.c_str());
CreateDir(pathmodel.c_str());
CreateDir(pathwmo.c_str());
uint32 wmosdone=0,texdone=0,mdone=0;
if(doWmos)
{
printf("Extracting WMOS...\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())
{
const ByteBuffer& bb = mpqwmo.ExtractFile((char*)mpqfn.c_str());
fh.write((const char*)bb.contents(),bb.size());
//Extract number of group files, Texture file names and M2s from WMO
if(doWmogroups || doTextures || doModels) WMO_Parse_Data(bb,mpqfn.c_str(),doWmogroups,doTextures,doModels);
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;
}
if(doWmogroups)
{
printf("Extracting WMO Group Files...\n");
bar = new barGoLink(wmoGroupNames.size(),true);
for(std::set<NameAndAlt>::iterator i = wmoGroupNames.begin(); i != wmoGroupNames.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())
{
const 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];
md5Wmogroup[_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(wmoGroupNames.size())
OutMD5((char*)pathwmo.c_str(),md5Wmogroup);
delete bar;
}
if(doModels)
{
printf("Extracting models...\n");
@ -858,46 +959,6 @@ void ExtractMapDependencies(void)
delete bar;
}
if(doWmos)
{
printf("Extracting WMOS...\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())
{
const 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;
}
}
@ -951,6 +1012,77 @@ void ExtractSoundFiles(void)
printf("\n");
}
void WMO_Parse_Data(ByteBuffer bb, const char* _filename, bool groups, bool textures, bool models)
{
bb.rpos(20); //Skip MVER chunk and header of MHDR
irr::scene::RootHeader header;
if (bb.size() < sizeof(header))
return;
bb.read((uint8*)&header, sizeof(header));
if(groups)
{
std::string filename=_filename;
for(uint32 i=0; i<header.nGroups; i++)
{
char grpfilename[255];
sprintf(grpfilename,"%s_%03lu.wmo",filename.substr(0,filename.length()-4).c_str(),i);
wmoGroupNames.insert(NameAndAlt(grpfilename));
}
}
if(models || textures)
{
uint32 size;
uint8 _cc[5];
uint8 *fourcc = &_cc[0];
fourcc[4]=0;
while(bb.rpos()<bb.size())
{
bb.read((uint8*)fourcc,4);
bb.read((uint8*)&size,4);
if(!strcmp((char*)fourcc,"XTOM") && textures)
{
std::string temp;
char c;
uint32 read=0;
while(read<size)
{
bb.read((uint8*)&c,sizeof(char));
if(c=='\x0' && temp.size()>0)
{
texNames.insert(NameAndAlt(temp));
temp.clear();
}
else if(c!=0)
temp += c;
read++;
}
}
else if(!strcmp((char*)fourcc,"NDOM") && models)
{
std::string temp;
char c;
uint32 read=0;
while(read<size)
{
bb.read((uint8*)&c,sizeof(char));
if(c=='\x0' && temp.size()>0)
{
modelNames.insert(NameAndAlt(temp));
temp.clear();
}
else if(c!=0)
temp += c;
read++;
}
}
else
bb.rpos(bb.rpos()+size);
}
}
}
void ADT_ExportStringSetByOffset(const uint8* data, uint32 off, std::set<NameAndAlt>& st,const char* stop)
{
data += ((uint32*)data)[off]; // seek to correct absolute offset

View File

@ -41,6 +41,8 @@ void ExtractSoundFiles(void);
void FetchTexturesFromModel(ByteBuffer);
void WMO_Parse_Data(ByteBuffer, const char*, bool, bool, bool);
void ADT_ExportStringSetByOffset(const uint8*, uint32, std::set<NameAndAlt>&, const char*);
void ADT_FillTextureData(const uint8*,std::set<NameAndAlt>&);
void ADT_FillWMOData(const uint8*,std::set<NameAndAlt>&);

View File

@ -67,9 +67,9 @@ public:
return reinterpret_cast<char*>(file.stringTable + stringOffset);
}
private:
Record(DBCFile &file, unsigned char *offset): file(file), offset(offset) {}
unsigned char *offset;
DBCFile &file;
unsigned char *offset;
Record(DBCFile &file, unsigned char *offset): file(file), offset(offset) {}
friend class DBCFile;
friend class DBCFile::Iterator;