diff --git a/src/Client/GUI/CWMOMeshFileLoader.cpp b/src/Client/GUI/CWMOMeshFileLoader.cpp new file mode 100644 index 0000000..f7e68e4 --- /dev/null +++ b/src/Client/GUI/CWMOMeshFileLoader.cpp @@ -0,0 +1,334 @@ +#include +#include +#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;irecalculateBoundingBox(); + 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;iseek(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;icreateBuffer(); + + //Put the Indices and Vertices of the Submesh into a mesh buffer + for(u32 j=lastindex;jIndices.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;jVertices_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('\\')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; + +} + +} +} diff --git a/src/Client/GUI/CWMOMeshFileLoader.h b/src/Client/GUI/CWMOMeshFileLoader.h new file mode 100644 index 0000000..9f61bb0 --- /dev/null +++ b/src/Client/GUI/CWMOMeshFileLoader.h @@ -0,0 +1,132 @@ +#include "irrlicht/irrlicht.h" +#include "irrlicht/IMeshLoader.h" +#include "SSkinnedMesh.h" +#include +#include +#include + +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 WMOMTexDefinition; + core::array WMOMTextureFiles; + + +//Stuff from group file + core::array WMOMIndices; + core::array WMOMVertices; + core::array WMOMNormals; + core::array WMOMTexcoord; + core::array WMOMVertexColor; + core::array WMOMTexData; + core::array submeshes; + + core::array WMOVertices; + SSkinMeshBuffer* MeshBuffer; +/* + ModelHeader header; + core::stringc WMOMeshName; + SMesh* Mesh; + // + //Taken from the Model file, thus m2M* + core::array WMOMVertices; + core::array WMOMViews; + core::array WMOMIndices; + core::array WMOMTriangles; + core::array WMOMSubmeshes; + core::array WMOMTextureLookup; + core::array WMOMTextureDef; + core::array WMOMTextureFiles; + core::array WMOMTextureUnit; + core::array WMOMRenderFlags; + core::array WMOMAnimations; + core::array WMOMBones; + //Used for the Mesh, thus m2_noM_* + core::array WMOVertices; + core::array WMOIndices; + core::array WMOJoints; +*/ + +}; +}//namespace scene +}//namespace irr diff --git a/src/Client/GUI/Makefile.am b/src/Client/GUI/Makefile.am index 01413ce..6ee6576 100644 --- a/src/Client/GUI/Makefile.am +++ b/src/Client/GUI/Makefile.am @@ -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 diff --git a/src/Client/GUI/PseuGUI.cpp b/src/Client/GUI/PseuGUI.cpp index b33426b..d1d1eed 100644 --- a/src/Client/GUI/PseuGUI.cpp +++ b/src/Client/GUI/PseuGUI.cpp @@ -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; diff --git a/src/Client/GUI/SSkinnedMesh.h b/src/Client/GUI/SSkinnedMesh.h index dc3ddf5..6233ed1 100755 --- a/src/Client/GUI/SSkinnedMesh.h +++ b/src/Client/GUI/SSkinnedMesh.h @@ -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; igetBoundingBox()); + } + 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); diff --git a/src/Client/GUI/Scene.h b/src/Client/GUI/Scene.h index 9cca068..48d08b5 100644 --- a/src/Client/GUI/Scene.h +++ b/src/Client/GUI/Scene.h @@ -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 _doodads; + std::map _wmos; std::map _sound_emitters; scene::ISceneNode *sky; scene::ISceneNode *selectedNode, *oldSelectedNode, *focusedNode, *oldFocusedNode; diff --git a/src/Client/GUI/SceneWorld.cpp b/src/Client/GUI/SceneWorld.cpp index 0813909..5e11944 100644 --- a/src/Client/GUI/SceneWorld.cpp +++ b/src/Client/GUI/SceneWorld.cpp @@ -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) diff --git a/src/Client/World/WorldSession.cpp b/src/Client/World/WorldSession.cpp index e45a0c3..bf74bef 100644 --- a/src/Client/World/WorldSession.cpp +++ b/src/Client/World/WorldSession.cpp @@ -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; diff --git a/src/shared/MapTile.cpp b/src/shared/MapTile.cpp index 4cdd2fc..afeeb69 100644 --- a/src/shared/MapTile.cpp +++ b/src/shared/MapTile.cpp @@ -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"; diff --git a/src/shared/MapTile.h b/src/shared/MapTile.h index 02d90c5..9a7cef9 100644 --- a/src/shared/MapTile.h +++ b/src/shared/MapTile.h @@ -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 _wmos; std::vector _models; std::vector _doodads; + std::vector _wmo_data; std::vector _soundemm; float _xbase,_ybase,_hbase; diff --git a/src/tools/stuffextract/StuffExtract.cpp b/src/tools/stuffextract/StuffExtract.cpp index 9c0d732..1b23454 100644 --- a/src/tools/stuffextract/StuffExtract.cpp +++ b/src/tools/stuffextract/StuffExtract.cpp @@ -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 mapNames; std::set texNames; std::set modelNames; std::set wmoNames; +std::set wmoGroupNames; std::set 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::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::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::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; i0) + { + 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(read0) + { + 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& st,const char* stop) { data += ((uint32*)data)[off]; // seek to correct absolute offset diff --git a/src/tools/stuffextract/StuffExtract.h b/src/tools/stuffextract/StuffExtract.h index 8e58ccf..7c160cd 100644 --- a/src/tools/stuffextract/StuffExtract.h +++ b/src/tools/stuffextract/StuffExtract.h @@ -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&, const char*); void ADT_FillTextureData(const uint8*,std::set&); void ADT_FillWMOData(const uint8*,std::set&); diff --git a/src/tools/stuffextract/dbcfile.h b/src/tools/stuffextract/dbcfile.h index 03dfba3..636541b 100644 --- a/src/tools/stuffextract/dbcfile.h +++ b/src/tools/stuffextract/dbcfile.h @@ -67,9 +67,9 @@ public: return reinterpret_cast(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;