Merge branch 'allinone'

This commit is contained in:
shlainn 2011-09-28 22:01:54 +02:00
commit f15bd457d3
46 changed files with 3037 additions and 1342 deletions

View File

@ -74,18 +74,11 @@ charname=Pseuwow
// Client emulation configuration // Client emulation configuration
// Client 0: Classic WoW 1.12.2 Build 6005 // Client 1: Classic WoW 1.12.2 Build 6005
// Client 1: TBC 2.4.3 Build 8606 // Client 2: TBC 2.4.3 Build 8606
// Client 2: WoTLK 3.3.5 Build 12340 // Client 3: WoTLK 3.3.5 Build 12340
// Client 3: Cata 4.x.x Build XXX NOT IMPLEMENTED // Client 4: Cata 4.x.x Build XXX NOT IMPLEMENTED
// !!!!
// !!!! WARNING!!!! For all of the above Client Version and Client Build are IGNORED
// !!!!
// Client 9: Custom Settings for Client Version and Client Build
Client=0 Client=0
// Uncomment if you use Client=9
// ClientVersion=3.3.5
// ClientBuild=12340
ClientLanguage=enGB ClientLanguage=enGB
// or change to enGB, deDE, ... // or change to enGB, deDE, ...

View File

@ -861,11 +861,11 @@ DefReturnResult DefScriptPackage::SCGetObjectValue(CmdSet &Set)
else else
{ {
if(DefScriptTools::stringToLower(Set.arg[1]) == "f") if(DefScriptTools::stringToLower(Set.arg[1]) == "f")
return toString((ldbl)o->GetFloatValue(v)); return toString((ldbl)o->GetFloatValue((UpdateFieldName)v));
else if(DefScriptTools::stringToLower(Set.arg[1]) == "i64") else if(DefScriptTools::stringToLower(Set.arg[1]) == "i64")
return toString(o->GetUInt64Value(v)); return toString(o->GetUInt64Value((UpdateFieldName)v));
else else
return toString((uint64)o->GetUInt32Value(v)); return toString((uint64)o->GetUInt32Value((UpdateFieldName)v));
} }
} }
return ""; return "";

View File

@ -1,3 +1,4 @@
// #define _DEBUG 1
#include <iostream> #include <iostream>
#include "MemoryDataHolder.h" #include "MemoryDataHolder.h"
#include "MemoryInterface.h" #include "MemoryInterface.h"
@ -51,187 +52,288 @@ IAnimatedMesh* CM2MeshFileLoader::createMesh(io::IReadFile* file)
return AnimatedMesh; return AnimatedMesh;
} }
void CM2MeshFileLoader::ReadVertices()
{
//Vertices. Global data
if(!M2MVertices.empty())
M2MVertices.clear();
ModelVertex tempM2MVert;
f32 tempYZ;
MeshFile->seek(header.ofsVertices);
for(u32 i =0;i<header.nVertices;i++)
{
MeshFile->read(&tempM2MVert,sizeof(ModelVertex));
tempYZ = tempM2MVert.pos.Y;
tempM2MVert.pos.Y=tempM2MVert.pos.Z;
tempM2MVert.pos.Z=tempYZ;
tempYZ = tempM2MVert.normal.Y;
tempM2MVert.normal.Y=tempM2MVert.normal.Z;
tempM2MVert.normal.Z=tempYZ;
M2MVertices.push_back(tempM2MVert);
}
DEBUG(logdebug("Read %u/%u Vertices",M2MVertices.size(),header.nVertices));
}
void CM2MeshFileLoader::ReadViewData(io::IReadFile* file)
{
//Vertex indices of a specific view.Local to View 0
if(M2MIndices.size()>0)
M2MIndices.clear();
u16 tempM2Index;
file->seek(currentView.ofsIndex);
for(u32 i =0;i<currentView.nIndex;i++)
{
file->read(&tempM2Index,sizeof(u16));
M2MIndices.push_back(tempM2Index);
}
DEBUG(logdebug("Read %u/%u Indices",M2MIndices.size(),currentView.nIndex));
//Triangles. Data Points point to the Vertex Indices, not the vertices themself. 3 Points = 1 Triangle, Local to View 0
if(M2MTriangles.size()>0)
M2MTriangles.clear();
u16 tempM2Triangle;
file->seek(currentView.ofsTris);
for(u32 i =0;i<currentView.nTris;i++)
{
file->read(&tempM2Triangle,sizeof(u16));
M2MTriangles.push_back(tempM2Triangle);
}
DEBUG(logdebug("Read %u/%u Triangles",M2MTriangles.size(),currentView.nTris));
//Submeshes, Local to View 0
if(M2MSubmeshes.size()>0)
M2MSubmeshes.clear();
ModelViewSubmesh tempM2Submesh;
file->seek(currentView.ofsSub);
for(u32 i =0;i<currentView.nSub;i++)
{
file->read(&tempM2Submesh,sizeof(ModelViewSubmesh)-(header.version==0x100?16:0));
M2MSubmeshes.push_back(tempM2Submesh);
// std::cout<< "Submesh " <<i<<" ID "<<tempM2Submesh.meshpartId<<" starts at V/T "<<tempM2Submesh.ofsVertex<<"/"<<tempM2Submesh.ofsTris<<" and has "<<tempM2Submesh.nVertex<<"/"<<tempM2Submesh.nTris<<" V/T\n";
}
DEBUG(logdebug("Read %u/%u Submeshes",M2MSubmeshes.size(),currentView.nSub));
//Texture units. Local to view 0
TextureUnit tempM2TexUnit;
if(!M2MTextureUnit.empty())
{
M2MTextureUnit.clear();
}
file->seek(currentView.ofsTex);
for(u32 i=0;i<currentView.nTex;i++)
{
file->read(&tempM2TexUnit,sizeof(TextureUnit));
M2MTextureUnit.push_back(tempM2TexUnit);
DEBUG(logdebug(" TexUnit %u: Submesh: %u %u Render Flag: %u TextureUnitNumber: %u %u TTU: %u",i,tempM2TexUnit.submeshIndex1,tempM2TexUnit.submeshIndex2, tempM2TexUnit.renderFlagsIndex, tempM2TexUnit.TextureUnitNumber, tempM2TexUnit.TextureUnitNumber2 ,tempM2TexUnit.textureIndex));
}
DEBUG(logdebug("Read %u Texture Unit entries for View 0",M2MTextureUnit.size()));
}
void CM2MeshFileLoader::ReadTextureDefinitions()
{
//Texture Lookup table. This is global data
u16 tempM2TexLookup;
if(!M2MTextureLookup.empty())
{
M2MTextureLookup.clear();
}
MeshFile->seek(header.ofsTexLookup);
for(u32 i=0;i<header.nTexLookup;i++)
{
MeshFile->read(&tempM2TexLookup,sizeof(u16));
M2MTextureLookup.push_back(tempM2TexLookup);
DEBUG(logdebug("Texture %u Type %u",i,tempM2TexLookup));
}
DEBUG(logdebug("Read %u Texture lookup entries",M2MTextureLookup.size()));
//Texture Definitions table. This is global data
TextureDefinition tempM2TexDef;
if(!M2MTextureDef.empty())
{
M2MTextureDef.clear();
}
MeshFile->seek(header.ofsTextures);
for(u32 i=0;i<header.nTextures;i++)
{
MeshFile->read(&tempM2TexDef,sizeof(TextureDefinition));
M2MTextureDef.push_back(tempM2TexDef);
DEBUG(logdebug("Texture %u Type %u",i,tempM2TexDef.texType));
}
DEBUG(logdebug("Read %u Texture Definition entries",M2MTextureDef.size()));
//Render Flags table. This is global data
RenderFlags tempM2RF;
if(!M2MRenderFlags.empty())
{
M2MRenderFlags.clear();
}
MeshFile->seek(header.ofsTexFlags);
for(u32 i=0;i<header.nTexFlags;i++)
{
MeshFile->read(&tempM2RF,sizeof(RenderFlags));
M2MRenderFlags.push_back(tempM2RF);
DEBUG(logdebug("Flag %u: (%u, %u)",i,tempM2RF.blending,tempM2RF.flags));
}
DEBUG(logdebug("Read %u Renderflags",M2MRenderFlags.size()));
if(!M2MTextureFiles.empty())
M2MTextureFiles.clear();
std::string tempTexFileName="";
M2MTextureFiles.reallocate(M2MTextureDef.size());
for(u32 i=0; i<M2MTextureDef.size(); i++)
{
tempTexFileName.resize(M2MTextureDef[i].texFileLen + 1);
MeshFile->seek(M2MTextureDef[i].texFileOfs);
MeshFile->read((void*)tempTexFileName.data(),M2MTextureDef[i].texFileLen);
M2MTextureFiles.push_back("");
M2MTextureFiles[i]=tempTexFileName.c_str();
DEBUG(logdebug("Texture: %u %u (%s/%s) @ %u(%u)",i,M2MTextureFiles.size(),M2MTextureFiles[i].c_str(),tempTexFileName.c_str(),M2MTextureDef[i].texFileOfs,M2MTextureDef[i].texFileLen));
}
}
bool CM2MeshFileLoader::load() bool CM2MeshFileLoader::load()
{ {
DEBUG(logdebug("Trying to open file %s",MeshFile->getFileName())); DEBUG(logdebug("Trying to open file %s",MeshFile->getFileName()));
MeshFile->read(&header,sizeof(ModelHeader)); MeshFile->read(&header,20);
if (header.version[0] != 8 || header.version[1] != 1 || header.version[2] != 0 || header.version[3] != 0) { DEBUG(logdebug("M2 Version %X",header.version));
logerror("M2: [%s] Wrong header! File version doesn't match or file is not a M2 file.",MeshFile->getFileName());
return 0; switch(header.version)
} {
else case 0x100:
{ case 0x104://HACK
DEBUG(logdebug("header okay")); case 0x105://HACK
} case 0x106://HACK
//Name -> not very important I think, but save it nontheless; case 0x107://HACK
//M2MeshName.clear(); {
//M2MeshName.reserve(header.nameLength); MeshFile->read((u8*)&header+20,sizeof(ModelHeader)-20);
//file->seek(header.nameOfs); ReadVertices();
//file->read(&M2MeshName[0],header.nameLength); MeshFile->seek(header.ofsViews);
//std::cout << "Read name:"<<M2MeshName.c_str()<<"Size: "<< M2MeshName.size() <<"|"<<M2MeshName[0]<< "\n"; MeshFile->read(&currentView,sizeof(ModelView));
//logger->log("Mesh Name",M2MeshName.c_str(),ELL_INFORMATION); ReadViewData(MeshFile);
//Now we load all kinds of data from the file ReadTextureDefinitions();
break;
}
case 0x108:
{
return 0;
break;
}
default:
{
logerror("M2: [%s] Wrong header %0X! File version doesn't match or file is not a M2 file.",MeshFile->getFileName(),header.version);
return 0;
}
}
//Vertices. Global data //Vertices. Global data
if(!M2MVertices.empty()) // if(!M2MVertices.empty())
M2MVertices.clear(); // M2MVertices.clear();
//
ModelVertex tempM2MVert; // ModelVertex tempM2MVert;
f32 tempYZ; // f32 tempYZ;
MeshFile->seek(header.ofsVertices); // MeshFile->seek(header.ofsVertices);
//
for(u32 i =0;i<header.nVertices;i++) // for(u32 i =0;i<header.nVertices;i++)
{ // {
MeshFile->read(&tempM2MVert,sizeof(ModelVertex)); // MeshFile->read(&tempM2MVert,sizeof(ModelVertex));
tempYZ = tempM2MVert.pos.Y; // tempYZ = tempM2MVert.pos.Y;
tempM2MVert.pos.Y=tempM2MVert.pos.Z; // tempM2MVert.pos.Y=tempM2MVert.pos.Z;
tempM2MVert.pos.Z=tempYZ; // tempM2MVert.pos.Z=tempYZ;
tempYZ = tempM2MVert.normal.Y; // tempYZ = tempM2MVert.normal.Y;
tempM2MVert.normal.Y=tempM2MVert.normal.Z; // tempM2MVert.normal.Y=tempM2MVert.normal.Z;
tempM2MVert.normal.Z=tempYZ; // tempM2MVert.normal.Z=tempYZ;
//
M2MVertices.push_back(tempM2MVert); // M2MVertices.push_back(tempM2MVert);
} // }
DEBUG(logdebug("Read %u/%u Vertices",M2MVertices.size(),header.nVertices)); // DEBUG(logdebug("Read %u/%u Vertices",M2MVertices.size(),header.nVertices));
//Views (skins) == Sets of vertices. Usage yet unknown. Global data //Views (skins) == Sets of vertices. Usage yet unknown. Global data
std::string SkinName = MeshFile->getFileName(); // std::string SkinName = MeshFile->getFileName();
SkinName = SkinName.substr(0, SkinName.length()-3) + "00.skin"; // FIX ME (and stuffextract) ! as we need more skins // SkinName = SkinName.substr(0, SkinName.length()-3) + "00.skin"; // FIX ME (and stuffextract) ! as we need more skins
io::IReadFile* SkinFile = io::IrrCreateIReadFileBasic(Device, SkinName.c_str()); // io::IReadFile* SkinFile = io::IrrCreateIReadFileBasic(Device, SkinName.c_str());
if (!SkinFile) // if (!SkinFile)
{ // {
logerror("Error! Skin file not found: %s", SkinName.c_str()); // logerror("Error! Skin file not found: %s", SkinName.c_str());
return 0; // return 0;
} // }
//
ModelView currentView; // SkinFile->read(&currentView, sizeof(ModelView));
SkinFile->read(&currentView, sizeof(ModelView)); //
// //std::cout << "Skins "<<header.nViews<<" (views)\n";
//std::cout << "Skins "<<header.nViews<<" (views)\n"; //
// DEBUG(logdebug("Using View 0 for all further operations"));
DEBUG(logdebug("Using View 0 for all further operations")); // DEBUG(logdebug("This View has %u Submeshes",currentView.nSub));
DEBUG(logdebug("This View has %u Submeshes",currentView.nSub)); //
// //Vertex indices of a specific view.Local to View 0
//Vertex indices of a specific view.Local to View 0 // if(M2MIndices.size()>0)
if(M2MIndices.size()>0) // M2MIndices.clear();
M2MIndices.clear(); //
// u16 tempM2Index;
u16 tempM2Index; // SkinFile->seek(currentView.ofsIndex);
SkinFile->seek(currentView.ofsIndex); // for(u32 i =0;i<currentView.nIndex;i++)
for(u32 i =0;i<currentView.nIndex;i++) // {
{ // SkinFile->read(&tempM2Index,sizeof(u16));
SkinFile->read(&tempM2Index,sizeof(u16)); // M2MIndices.push_back(tempM2Index);
M2MIndices.push_back(tempM2Index); // }
} // DEBUG(logdebug("Read %u/%u Indices",M2MIndices.size(),currentView.nIndex));
DEBUG(logdebug("Read %u/%u Indices",M2MIndices.size(),currentView.nIndex)); //
//
// //Triangles. Data Points point to the Vertex Indices, not the vertices themself. 3 Points = 1 Triangle, Local to View 0
//Triangles. Data Points point to the Vertex Indices, not the vertices themself. 3 Points = 1 Triangle, Local to View 0 // if(M2MTriangles.size()>0)
if(M2MTriangles.size()>0) // M2MTriangles.clear();
M2MTriangles.clear(); //
// u16 tempM2Triangle;
u16 tempM2Triangle; // SkinFile->seek(currentView.ofsTris);
SkinFile->seek(currentView.ofsTris); // for(u32 i =0;i<currentView.nTris;i++)
for(u32 i =0;i<currentView.nTris;i++) // {
{ // SkinFile->read(&tempM2Triangle,sizeof(u16));
SkinFile->read(&tempM2Triangle,sizeof(u16)); // M2MTriangles.push_back(tempM2Triangle);
M2MTriangles.push_back(tempM2Triangle); // }
} // DEBUG(logdebug("Read %u/%u Triangles",M2MTriangles.size(),currentView.nTris));
DEBUG(logdebug("Read %u/%u Triangles",M2MTriangles.size(),currentView.nTris)); // //Submeshes, Local to View 0
//Submeshes, Local to View 0 // if(M2MSubmeshes.size()>0)
if(M2MSubmeshes.size()>0) // M2MSubmeshes.clear();
M2MSubmeshes.clear(); //
// ModelViewSubmesh tempM2Submesh;
ModelViewSubmesh tempM2Submesh; // SkinFile->seek(currentView.ofsSub);
SkinFile->seek(currentView.ofsSub); // for(u32 i =0;i<currentView.nSub;i++)
for(u32 i =0;i<currentView.nSub;i++) // {
{ // SkinFile->read(&tempM2Submesh,sizeof(ModelViewSubmesh));
SkinFile->read(&tempM2Submesh,sizeof(ModelViewSubmesh)); // M2MSubmeshes.push_back(tempM2Submesh);
M2MSubmeshes.push_back(tempM2Submesh); // // std::cout<< "Submesh " <<i<<" ID "<<tempM2Submesh.meshpartId<<" starts at V/T "<<tempM2Submesh.ofsVertex<<"/"<<tempM2Submesh.ofsTris<<" and has "<<tempM2Submesh.nVertex<<"/"<<tempM2Submesh.nTris<<" V/T\n";
// std::cout<< "Submesh " <<i<<" ID "<<tempM2Submesh.meshpartId<<" starts at V/T "<<tempM2Submesh.ofsVertex<<"/"<<tempM2Submesh.ofsTris<<" and has "<<tempM2Submesh.nVertex<<"/"<<tempM2Submesh.nTris<<" V/T\n"; // }
} // DEBUG(logdebug("Read %u/%u Submeshes",M2MSubmeshes.size(),currentView.nSub));
DEBUG(logdebug("Read %u/%u Submeshes",M2MSubmeshes.size(),currentView.nSub)); //
// //Texture units. Local to view 0
//Texture units. Local to view 0 // TextureUnit tempM2TexUnit;
TextureUnit tempM2TexUnit; // if(!M2MTextureUnit.empty())
if(!M2MTextureUnit.empty()) // {
{ // M2MTextureUnit.clear();
M2MTextureUnit.clear(); // }
} // SkinFile->seek(currentView.ofsTex);
SkinFile->seek(currentView.ofsTex); // for(u32 i=0;i<currentView.nTex;i++)
for(u32 i=0;i<currentView.nTex;i++) // {
{ // SkinFile->read(&tempM2TexUnit,sizeof(TextureUnit));
SkinFile->read(&tempM2TexUnit,sizeof(TextureUnit)); // M2MTextureUnit.push_back(tempM2TexUnit);
M2MTextureUnit.push_back(tempM2TexUnit); // DEBUG(logdebug(" TexUnit %u: Submesh: %u %u Render Flag: %u TextureUnitNumber: %u %u TTU: %u",i,tempM2TexUnit.submeshIndex1,tempM2TexUnit.submeshIndex2, tempM2TexUnit.renderFlagsIndex, tempM2TexUnit.TextureUnitNumber, tempM2TexUnit.TextureUnitNumber2 ,tempM2TexUnit.textureIndex));
DEBUG(logdebug(" TexUnit %u: Submesh: %u %u Render Flag: %u TextureUnitNumber: %u %u TTU: %u",i,tempM2TexUnit.submeshIndex1,tempM2TexUnit.submeshIndex2, tempM2TexUnit.renderFlagsIndex, tempM2TexUnit.TextureUnitNumber, tempM2TexUnit.TextureUnitNumber2 ,tempM2TexUnit.textureIndex)); // }
} // DEBUG(logdebug("Read %u Texture Unit entries for View 0",M2MTextureUnit.size()));
DEBUG(logdebug("Read %u Texture Unit entries for View 0",M2MTextureUnit.size())); //
//Texture Lookup table. This is global data
u16 tempM2TexLookup;
if(!M2MTextureLookup.empty())
{
M2MTextureLookup.clear();
}
MeshFile->seek(header.ofsTexLookup);
for(u32 i=0;i<header.nTexLookup;i++)
{
MeshFile->read(&tempM2TexLookup,sizeof(u16));
M2MTextureLookup.push_back(tempM2TexLookup);
DEBUG(logdebug("Texture %u Type %u\n",i,tempM2TexLookup));
}
DEBUG(logdebug("Read %u Texture lookup entries",M2MTextureLookup.size()));
//Texture Definitions table. This is global data
TextureDefinition tempM2TexDef;
if(!M2MTextureDef.empty())
{
M2MTextureDef.clear();
}
MeshFile->seek(header.ofsTextures);
for(u32 i=0;i<header.nTextures;i++)
{
MeshFile->read(&tempM2TexDef,sizeof(TextureDefinition));
M2MTextureDef.push_back(tempM2TexDef);
DEBUG(logdebug("Texture %u Type %u\n",i,tempM2TexDef.texType));
}
DEBUG(logdebug("Read %u Texture Definition entries",M2MTextureDef.size()));
//Render Flags table. This is global data
RenderFlags tempM2RF;
if(!M2MRenderFlags.empty())
{
M2MRenderFlags.clear();
}
MeshFile->seek(header.ofsTexFlags);
for(u32 i=0;i<header.nTexFlags;i++)
{
MeshFile->read(&tempM2RF,sizeof(RenderFlags));
M2MRenderFlags.push_back(tempM2RF);
DEBUG(logdebug("Flag %u: (%u, %u)",i,tempM2RF.blending,tempM2RF.flags));
}
DEBUG(logdebug("Read %u Renderflags",M2MRenderFlags.size()));
if(!M2MTextureFiles.empty())
M2MTextureFiles.clear();
std::string tempTexFileName="";
M2MTextureFiles.reallocate(M2MTextureDef.size());
for(u32 i=0; i<M2MTextureDef.size(); i++)
{
tempTexFileName.resize(M2MTextureDef[i].texFileLen + 1);
MeshFile->seek(M2MTextureDef[i].texFileOfs);
MeshFile->read((void*)tempTexFileName.data(),M2MTextureDef[i].texFileLen);
M2MTextureFiles.push_back("");
M2MTextureFiles[i]=tempTexFileName.c_str();
DEBUG(logdebug("Texture: %u %u (%s/%s) @ %u(%u)",i,M2MTextureFiles.size(),M2MTextureFiles[i].c_str(),tempTexFileName.c_str(),M2MTextureDef[i].texFileOfs,M2MTextureDef[i].texFileLen));
}
/////////////////////////////////////// ///////////////////////////////////////
// Animation related stuff // // Animation related stuff //
@ -440,6 +542,19 @@ if(M2MBones[i].scaling.header.nValues>0){
} }
*/ */
//std::cout<<AnimatedMesh->getAllJoints()[1]->Children.size()<<" Children\n"; //std::cout<<AnimatedMesh->getAllJoints()[1]->Children.size()<<" Children\n";
///////////////////////////
// EVERYTHING IS READ
///////////////////////////
//And M2MVertices are not usable like this. Thus we transform //And M2MVertices are not usable like this. Thus we transform
if(M2Vertices.size()>0) if(M2Vertices.size()>0)
@ -468,8 +583,8 @@ for(u32 i=0; i < currentView.nSub;i++)//
for(u32 j=M2MSubmeshes[i].ofsVertex;j<M2MSubmeshes[i].ofsVertex+M2MSubmeshes[i].nVertex;j++) for(u32 j=M2MSubmeshes[i].ofsVertex;j<M2MSubmeshes[i].ofsVertex+M2MSubmeshes[i].nVertex;j++)
{ {
MeshBuffer->Vertices_Standard.push_back(M2Vertices[j]); MeshBuffer->Vertices_Standard.push_back(M2Vertices[j]);
for(u32 k=0; k<4; k++) // for(u32 k=0; k<4; k++)
{ // {
//std::cout << (u32)M2MVertices[j].bones[k] << " "; //std::cout << (u32)M2MVertices[j].bones[k] << " ";
/* ANIMATION NEED FIX !!! /* ANIMATION NEED FIX !!!
if((M2MVertices[j].weights[k]/255.0f)>0.0f) if((M2MVertices[j].weights[k]/255.0f)>0.0f)
@ -481,7 +596,7 @@ for(u32 i=0; i < currentView.nSub;i++)//
} }
*/ */
//std::cout<<weight->buffer_id << " " << weight->vertex_id << " " << weight->strength <<"|"; //std::cout<<weight->buffer_id << " " << weight->vertex_id << " " << weight->strength <<"|";
} // }
// std::cout<<'\n'; // std::cout<<'\n';
} }
//std::cout << i << ": " << MeshBuffer->Vertices_Standard.size() <<" "<<M2MSubmeshes[i].ofsVertex<<" "<<M2MSubmeshes[i].nVertex<< "\n"; //std::cout << i << ": " << MeshBuffer->Vertices_Standard.size() <<" "<<M2MSubmeshes[i].ofsVertex<<" "<<M2MSubmeshes[i].nVertex<< "\n";
@ -491,10 +606,10 @@ for(u32 i=0; i < currentView.nSub;i++)//
//MeshBuffer->getMaterial().DiffuseColor.set(255,255-(u32)(255/(M2MSubmeshes.size()))*i,(u32)(255/(M2MSubmeshes.size()))*i,0); //MeshBuffer->getMaterial().DiffuseColor.set(255,255-(u32)(255/(M2MSubmeshes.size()))*i,(u32)(255/(M2MSubmeshes.size()))*i,0);
//MeshBuffer->getMaterial().DiffuseColor.set(255,(M2MSubmeshes[i].meshpartId==0?0:255),(M2MSubmeshes[i].meshpartId==0?255:0),0); //MeshBuffer->getMaterial().DiffuseColor.set(255,(M2MSubmeshes[i].meshpartId==0?0:255),(M2MSubmeshes[i].meshpartId==0?255:0),0);
for(u32 j=0;j<M2MTextureUnit.size();j++)//Loop through texture units for(u32 j=0;j<M2MTextureUnit.size();j++)//Loop through texture units
{ {
if(M2MTextureUnit[j].submeshIndex1==i && !M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].empty())//if a texture unit belongs to this submesh if(M2MTextureUnit[j].submeshIndex1==i && !M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].empty())//if a texture unit belongs to this submesh
{ {
// std::string TexName=Texdir.c_str(); // std::string TexName=Texdir.c_str();
// TexName+="/"; // TexName+="/";
// if(i<M2MTextureUnit.size()) // if(i<M2MTextureUnit.size())
// TexName+=M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str(); // TexName+=M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str();
@ -509,26 +624,33 @@ for(u32 i=0; i < currentView.nSub;i++)//
std::transform(TexName.begin(), TexName.end(), TexName.begin(), tolower);*/ std::transform(TexName.begin(), TexName.end(), TexName.begin(), tolower);*/
char buf[1000]; char buf[1000];
MemoryDataHolder::MakeTextureFilename(buf,M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str()); MemoryDataHolder::MakeTextureFilename(buf,M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str());
io::IReadFile* TexFile = io::IrrCreateIReadFileBasic(Device, buf); video::ITexture* tex = Device->getVideoDriver()->findTexture(buf);
// logdebug("Texture %s loading",M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str()); if(!tex)
if (!TexFile)
{ {
logerror("CM2MeshFileLoader: Texture file not found: %s", buf); io::IReadFile* TexFile = io::IrrCreateIReadFileBasic(Device, buf);
continue; // logdebug("Texture %s loading",M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str());
} if (!TexFile)
{
logerror("CM2MeshFileLoader: Texture file not found: %s", buf);
continue;
}
// logdebug("Texture %s loaded",M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str()); // logdebug("Texture %s loaded",M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str());
MeshBuffer->getMaterial().setTexture(M2MTextureUnit[j].TextureUnitNumber,Device->getVideoDriver()->getTexture(TexFile)); tex = Device->getVideoDriver()->getTexture(TexFile);
TexFile->drop();
}
MeshBuffer->getMaterial().setTexture(M2MTextureUnit[j].TextureUnitNumber,tex);
DEBUG(logdebug("Render Flags: %u %u",M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].flags,M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].blending)); DEBUG(logdebug("Render Flags: %u %u",M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].flags,M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].blending));
MeshBuffer->getMaterial().BackfaceCulling=(M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].flags & 0x04)?false:true; MeshBuffer->getMaterial().BackfaceCulling=(M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].flags & 0x04)?false:true;
if(M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].blending==1) if(M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].blending==1)
MeshBuffer->getMaterial().MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL; MeshBuffer->getMaterial().MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL;
}
} }
}
MeshBuffer->recalculateBoundingBox();
MeshBuffer->setHardwareMappingHint(EHM_STATIC);
//MeshBuffer->recalculateBoundingBox();
// Mesh->addMeshBuffer(MeshBuffer); // Mesh->addMeshBuffer(MeshBuffer);
// Mesh->recalculateBoundingBox(); // Mesh->recalculateBoundingBox();
//MeshBuffer->drop(); //MeshBuffer->drop();
@ -546,7 +668,7 @@ Device->getSceneManager()->getMeshManipulator()->flipSurfaces(AnimatedMesh); //F
AnimatedMesh->setInterpolationMode(scene::EIM_LINEAR); AnimatedMesh->setInterpolationMode(scene::EIM_LINEAR);
SkinFile->drop(); // SkinFile->drop();
M2MTriangles.clear(); M2MTriangles.clear();
M2Vertices.clear(); M2Vertices.clear();
M2Indices.clear(); M2Indices.clear();

View File

@ -11,80 +11,86 @@ namespace scene
{ {
struct ModelHeader { struct ModelHeader {
c8 id[4]; c8 id[4]; //0x00
u8 version[4]; u32 version;
u32 nameLength; u32 nameLength;
u32 nameOfs; u32 nameOfs;
u32 type; u32 type; //0x10
//Anim Block @ 0x14
u32 nGlobalSequences; u32 nGlobalSequences;
u32 ofsGlobalSequences; u32 ofsGlobalSequences;
u32 nAnimations; u32 nAnimations;
u32 ofsAnimations; u32 ofsAnimations; //0x20
u32 nC; u32 nAnimationLookup;
u32 ofsC; u32 ofsAnimationLookup;
u32 nD;
u32 ofsD; //0x30
u32 nBones; u32 nBones;
u32 ofsBones; u32 ofsBones;
u32 nF; u32 nSkelBoneLookup;
u32 ofsF; u32 ofsSkelBoneLookup; //0x40
u32 nVertices; u32 nVertices; //0x44
u32 ofsVertices; u32 ofsVertices;
u32 nViews; // number of skins ? u32 nViews; // number of skins ?
u32 ofsViews; //0x50
u32 nColors; u32 nColors;
u32 ofsColors; u32 ofsColors;
u32 nTextures; u32 nTextures;
u32 ofsTextures; u32 ofsTextures; //0x60
u32 nTransparency; // H u32 nTransparency;
u32 ofsTransparency; u32 ofsTransparency;
u32 nTexAnims; // J u32 nI;
u32 ofsI; //0x70
u32 nTexAnims;
u32 ofsTexAnims; u32 ofsTexAnims;
u32 nTexReplace; u32 nTexReplace;
u32 ofsTexReplace; u32 ofsTexReplace; //0x80
u32 nTexFlags; u32 nTexFlags;
u32 ofsTexFlags; u32 ofsTexFlags;
u32 nY; u32 nY;
u32 ofsY; u32 ofsY; //0x90
u32 nTexLookup; u32 nTexLookup;
u32 ofsTexLookup; u32 ofsTexLookup;
u32 nTexUnitLookup; // L u32 nTexUnitLookup;
u32 ofsTexUnitLookup; u32 ofsTexUnitLookup; //0xa0
u32 nTransparencyLookup; // M u32 nTransparencyLookup;
u32 ofsTransparencyLookup; u32 ofsTransparencyLookup;
u32 nTexAnimLookup; u32 nTexAnimLookup;
u32 ofsTexAnimLookup; u32 ofsTexAnimLookup; //0xb0
f32 floats[14]; f32 floats[14];
u32 nBoundingTriangles; u32 nBoundingTriangles;
u32 ofsBoundingTriangles; u32 ofsBoundingTriangles; //0xf0
u32 nBoundingVertices; u32 nBoundingVertices;
u32 ofsBoundingVertices; u32 ofsBoundingVertices;
u32 nBoundingNormals; u32 nBoundingNormals;
u32 ofsBoundingNormals; u32 ofsBoundingNormals; //0x100
u32 nAttachments; // O u32 nAttachments;
u32 ofsAttachments; u32 ofsAttachments;
u32 nAttachLookup; // P u32 nAttachLookup;
u32 ofsAttachLookup; u32 ofsAttachLookup; //0x110
u32 nQ; // Q u32 nAttachments_2;
u32 ofsQ; u32 ofsAttachments_2;
u32 nLights; // R u32 nLights;
u32 ofsLights; u32 ofsLights; //0x120
u32 nCameras; // S u32 nCameras;
u32 ofsCameras; u32 ofsCameras;
u32 nT; u32 nCameraLookup;
u32 ofsT; u32 ofsnCameraLookup; //0x130
u32 nRibbonEmitters; // U u32 nRibbonEmitters;
u32 ofsRibbonEmitters; u32 ofsRibbonEmitters;
u32 nParticleEmitters; // V u32 nParticleEmitters;
u32 ofsParticleEmitters; u32 ofsParticleEmitters;//0x140
}; };
@ -106,13 +112,13 @@ struct ModelVertex {
}; };
struct ModelView { struct ModelView {
c8 id[4]; // always "SKIN" // c8 id[4]; // always "SKIN"
u32 nIndex, ofsIndex; // Vertices in this model (index into vertices[]) u32 nIndex, ofsIndex; // Vertices in this model (index into vertices[])
u32 nTris, ofsTris; // indices u32 nTris, ofsTris; // indices
u32 nProps, ofsProps; // additional vtx properties u32 nProps, ofsProps; // additional vtx properties
u32 nSub, ofsSub; // materials/renderops/submeshes u32 nSub, ofsSub; // materials/renderops/submeshes
u32 nTex, ofsTex; // material properties/textures u32 nTex, ofsTex; // material properties/textures
s32 lod; // LOD bias? u32 lod; // LOD bias?
}; };
struct ModelViewSubmesh { struct ModelViewSubmesh {
@ -212,17 +218,21 @@ public:
private: private:
bool load(); bool load();
void ReadVertices();
void ReadTextureDefinitions();
void ReadViewData(io::IReadFile* file);
IrrlichtDevice* Device; IrrlichtDevice *Device;
core::stringc Texdir; core::stringc Texdir;
io::IReadFile* MeshFile; io::IReadFile *MeshFile, *SkinFile;
CSkinnedMesh* AnimatedMesh; CSkinnedMesh *AnimatedMesh;
scene::CSkinnedMesh::SJoint* ParentJoint; scene::CSkinnedMesh::SJoint *ParentJoint;
ModelHeader header; ModelHeader header;
ModelView currentView;
core::stringc M2MeshName; core::stringc M2MeshName;
SMesh* Mesh; SMesh* Mesh;
//SSkinMeshBuffer* MeshBuffer; //SSkinMeshBuffer* MeshBuffer;

View File

@ -26,9 +26,8 @@ CMDHReadFile::CMDHReadFile(void* memory, long len, const c8* fileName)
CMDHReadFile::~CMDHReadFile() CMDHReadFile::~CMDHReadFile()
{ {
// We should not drop the memory here... this model will possibly be loaded more than once // Drop the Memory, Irrlicht keeps a Model Cache of loaded models
//if(getReferenceCount() <= 1) MemoryDataHolder::Delete(getFileName());
// MemoryDataHolder::Delete(getFileName());
} }

View File

@ -60,7 +60,7 @@ IAnimatedMesh* CWMOMeshFileLoader::createMesh(io::IReadFile* file)
{ {
char grpfilename[255]; char grpfilename[255];
sprintf(grpfilename,"%s_%03u.wmo",filename.substr(0,filename.length()-4).c_str(),i); sprintf(grpfilename,"%s_%03u.wmo",filename.substr(0,filename.length()-4).c_str(),i);
logdev("%s",grpfilename); DEBUG(logdev("%s",grpfilename));
MeshFile = io::IrrCreateIReadFileBasic(Device,grpfilename); MeshFile = io::IrrCreateIReadFileBasic(Device,grpfilename);
if(!MeshFile) if(!MeshFile)
{ {
@ -73,7 +73,7 @@ IAnimatedMesh* CWMOMeshFileLoader::createMesh(io::IReadFile* file)
Device->getSceneManager()->getMeshManipulator()->flipSurfaces(Mesh); //Fix inverted surfaces after the rotation Device->getSceneManager()->getMeshManipulator()->flipSurfaces(Mesh); //Fix inverted surfaces after the rotation
//Does this crash on windows? //Does this crash on windows?
Device->getSceneManager()->getMeshManipulator()->recalculateNormals(Mesh,true);//just to be sure Device->getSceneManager()->getMeshManipulator()->recalculateNormals(Mesh,true);//just to be sure
logdev("Complete Mesh contains a total of %u submeshes!",Mesh->getMeshBufferCount()); DEBUG(logdev("Complete Mesh contains a total of %u submeshes!",Mesh->getMeshBufferCount()));
} }
else else
{ {
@ -92,24 +92,24 @@ bool CWMOMeshFileLoader::load(bool _root)
u32 size; u32 size;
u32 textureOffset; u32 textureOffset;
logdev("Trying to open file %s",MeshFile->getFileName()); DEBUG(logdev("Trying to open file %s",MeshFile->getFileName()));
while(MeshFile->getPos() < MeshFile->getSize()) while(MeshFile->getPos() < MeshFile->getSize())
{ {
MeshFile->read(fourcc,4); MeshFile->read(fourcc,4);
MeshFile->read(&size,4); MeshFile->read(&size,4);
flipcc(fourcc); flipcc(fourcc);
logdev("Reading Chunk: %s size %u", (char*)fourcc,size); DEBUG(logdev("Reading Chunk: %s size %u", (char*)fourcc,size));
if(!strcmp((char*)fourcc,"MVER")){ if(!strcmp((char*)fourcc,"MVER")){
logdev("MVER Chunk: %s",(char*)fourcc); DEBUG(logdev("MVER Chunk: %s",(char*)fourcc));
MeshFile->seek(size,true); MeshFile->seek(size,true);
} }
//Start root file parsing //Start root file parsing
else if(!strcmp((char*)fourcc,"MOHD")){ else if(!strcmp((char*)fourcc,"MOHD")){
MeshFile->read(&rootHeader,sizeof(RootHeader)); MeshFile->read(&rootHeader,sizeof(RootHeader));
logdev("Read Root Header: %u Textures, %u Groups, %u Models", rootHeader.nTextures, rootHeader.nGroups, rootHeader.nModels); DEBUG(logdev("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 if(!isRootFile)//We should be reading a group file and found a root header, abort
return 0; return 0;
} }
@ -127,7 +127,7 @@ logdev("Reading Chunk: %s size %u", (char*)fourcc,size);
MeshFile->read(&tempMOMT,sizeof(MOMT_Data)); MeshFile->read(&tempMOMT,sizeof(MOMT_Data));
WMOMTexDefinition.push_back(tempMOMT); WMOMTexDefinition.push_back(tempMOMT);
} }
logdev("Read %u/%u TextureDefinitions",WMOMTexDefinition.size(),(size/sizeof(MOMT_Data))); DEBUG(logdev("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. u32 tempOffset = MeshFile->getPos();//Save current position for further reading until texture file names are read.
@ -141,7 +141,7 @@ logdev("Reading Chunk: %s size %u", (char*)fourcc,size);
texNameSize = WMOMTexDefinition[i].endNameIndex-WMOMTexDefinition[i].startNameIndex; tempTexName.resize(texNameSize); texNameSize = WMOMTexDefinition[i].endNameIndex-WMOMTexDefinition[i].startNameIndex; tempTexName.resize(texNameSize);
MeshFile->seek(textureOffset+WMOMTexDefinition[i].startNameIndex); MeshFile->seek(textureOffset+WMOMTexDefinition[i].startNameIndex);
MeshFile->read((void*)tempTexName.c_str(),WMOMTexDefinition[i].endNameIndex-WMOMTexDefinition[i].startNameIndex); MeshFile->read((void*)tempTexName.c_str(),WMOMTexDefinition[i].endNameIndex-WMOMTexDefinition[i].startNameIndex);
logdev("Texture %u: %s",i,tempTexName.c_str()); DEBUG(logdev("Texture %u: %s",i,tempTexName.c_str()));
WMOMTextureFiles.push_back(tempTexName.c_str()); WMOMTextureFiles.push_back(tempTexName.c_str());
} }
@ -152,7 +152,7 @@ logdev("Reading Chunk: %s size %u", (char*)fourcc,size);
//Start Group file parsing //Start Group file parsing
else if(!strcmp((char*)fourcc,"MOGP")){ else if(!strcmp((char*)fourcc,"MOGP")){
logdev("header okay: %s",(char*)fourcc); DEBUG(logdev("header okay: %s",(char*)fourcc));
MeshFile->seek(68,true); MeshFile->seek(68,true);
if(isRootFile)//We should be reading a root file and found a Group header, abort if(isRootFile)//We should be reading a root file and found a Group header, abort
return 0; return 0;
@ -174,7 +174,7 @@ logdev("Reading Chunk: %s size %u", (char*)fourcc,size);
previous_texid=tempMOPY.textureID; previous_texid=tempMOPY.textureID;
} }
submeshes.push_back(WMOMTexData.size()-1);//last read entry submeshes.push_back(WMOMTexData.size()-1);//last read entry
logdev("Read %u/%u Texture Informations, counted %u submeshes",WMOMTexData.size(),(size/sizeof(MOPY_Data)),submeshes.size()); DEBUG(logdev("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) else if(!strcmp((char*)fourcc,"MOVI")){//Vertex indices (3 per triangle)
@ -187,7 +187,7 @@ logdev("Reading Chunk: %s size %u", (char*)fourcc,size);
MeshFile->read(&tempWMOIndex,sizeof(u16)); MeshFile->read(&tempWMOIndex,sizeof(u16));
WMOMIndices.push_back(tempWMOIndex); WMOMIndices.push_back(tempWMOIndex);
} }
logdev("Read %u/%u Indices",WMOMIndices.size(),(size/sizeof(u16))); DEBUG(logdev("Read %u/%u Indices",WMOMIndices.size(),(size/sizeof(u16))));
} }
else if(!strcmp((char*)fourcc,"MOVT")){//Vertex coordinates else if(!strcmp((char*)fourcc,"MOVT")){//Vertex coordinates
@ -204,7 +204,7 @@ logdev("Reading Chunk: %s size %u", (char*)fourcc,size);
tempWMOVertex.Z=tempYZ; tempWMOVertex.Z=tempYZ;
WMOMVertices.push_back(tempWMOVertex); WMOMVertices.push_back(tempWMOVertex);
} }
logdev("Read %u/%u Vertex Coordinates",WMOMVertices.size(),(size/sizeof(core::vector3df))); DEBUG(logdev("Read %u/%u Vertex Coordinates",WMOMVertices.size(),(size/sizeof(core::vector3df))));
} }
else if(!strcmp((char*)fourcc,"MONR")){//Normals else if(!strcmp((char*)fourcc,"MONR")){//Normals
@ -221,7 +221,7 @@ logdev("Reading Chunk: %s size %u", (char*)fourcc,size);
tempWMONormal.Z=tempYZ; tempWMONormal.Z=tempYZ;
WMOMNormals.push_back(tempWMONormal); WMOMNormals.push_back(tempWMONormal);
} }
logdev("Read %u/%u Normal Coordinates",WMOMNormals.size(),(size/sizeof(core::vector3df))); DEBUG(logdev("Read %u/%u Normal Coordinates",WMOMNormals.size(),(size/sizeof(core::vector3df))));
} }
else if(!strcmp((char*)fourcc,"MOTV")){//TexCoord else if(!strcmp((char*)fourcc,"MOTV")){//TexCoord
@ -234,7 +234,7 @@ logdev("Reading Chunk: %s size %u", (char*)fourcc,size);
MeshFile->read(&tempWMOMTexcoord,sizeof(core::vector2df)); MeshFile->read(&tempWMOMTexcoord,sizeof(core::vector2df));
WMOMTexcoord.push_back(tempWMOMTexcoord); WMOMTexcoord.push_back(tempWMOMTexcoord);
} }
logdev("Read %u/%u Texture Coordinates",WMOMTexcoord.size(),(size/sizeof(core::vector2df))); DEBUG(logdev("Read %u/%u Texture Coordinates",WMOMTexcoord.size(),(size/sizeof(core::vector2df))));
} }
else if(!strcmp((char*)fourcc,"MOCV")){//Vertex colors!! Scaaaary! else if(!strcmp((char*)fourcc,"MOCV")){//Vertex colors!! Scaaaary!
@ -248,7 +248,7 @@ logdev("Reading Chunk: %s size %u", (char*)fourcc,size);
MeshFile->read(&tempWMOMVertexColor,sizeof(WMOColor)); MeshFile->read(&tempWMOMVertexColor,sizeof(WMOColor));
WMOMVertexColor.push_back(video::SColor(tempWMOMVertexColor.a,tempWMOMVertexColor.r,tempWMOMVertexColor.g,tempWMOMVertexColor.b)); WMOMVertexColor.push_back(video::SColor(tempWMOMVertexColor.a,tempWMOMVertexColor.r,tempWMOMVertexColor.g,tempWMOMVertexColor.b));
} }
logdev("Read %u/%u Vertex colors",WMOMVertexColor.size(),(size/sizeof(WMOColor))); DEBUG(logdev("Read %u/%u Vertex colors",WMOMVertexColor.size(),(size/sizeof(WMOColor))));
} }
//End Group file parsing //End Group file parsing
@ -287,14 +287,14 @@ for(u32 i=0;i<submeshes.size();i++)//The mesh has to be split into submeshes bec
MeshBuffer->Indices.push_back(WMOMIndices[j*3+2]); MeshBuffer->Indices.push_back(WMOMIndices[j*3+2]);
} }
} }
logdev("Inserted %u Indices",MeshBuffer->Indices.size()); DEBUG(logdev("Inserted %u Indices",MeshBuffer->Indices.size()));
for(u32 j=0;j<WMOVertices.size();j++) for(u32 j=0;j<WMOVertices.size();j++)
{ {
MeshBuffer->Vertices_Standard.push_back(WMOVertices[j]); MeshBuffer->Vertices_Standard.push_back(WMOVertices[j]);
} }
logdev("Inserted %u Vertices",MeshBuffer->Vertices_Standard.size()); DEBUG(logdev("Inserted %u Vertices",MeshBuffer->Vertices_Standard.size()));
// std::string TexName=Texdir.c_str(); // std::string TexName=Texdir.c_str();
// TexName+="/"; // TexName+="/";
@ -310,17 +310,26 @@ for(u32 i=0;i<submeshes.size();i++)//The mesh has to be split into submeshes bec
// std::transform(TexName.begin(), TexName.end(), TexName.begin(), tolower); // std::transform(TexName.begin(), TexName.end(), TexName.begin(), tolower);
char buf[1000]; char buf[1000];
MemoryDataHolder::MakeTextureFilename(buf,WMOMTextureFiles[WMOMTexData[lastindex].textureID].c_str()); MemoryDataHolder::MakeTextureFilename(buf,WMOMTextureFiles[WMOMTexData[lastindex].textureID].c_str());
io::IReadFile* TexFile = io::IrrCreateIReadFileBasic(Device, buf); video::ITexture* tex = Device->getVideoDriver()->findTexture(buf);
if (!TexFile) if(!tex)
{ {
logerror("Error! Texture file not found: %s", buf); io::IReadFile* TexFile = io::IrrCreateIReadFileBasic(Device, buf);
continue; // logdebug("Texture %s loading",M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str());
if (!TexFile)
{
logerror("CM2MeshFileLoader: Texture file not found: %s", buf);
continue;
}
// logdebug("Texture %s loaded",M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str());
tex = Device->getVideoDriver()->getTexture(TexFile);
TexFile->drop();
} }
MeshBuffer->getMaterial().setTexture(0,Device->getVideoDriver()->getTexture(TexFile)); MeshBuffer->getMaterial().setTexture(0,tex);
if(WMOMTexDefinition[WMOMTexData[lastindex].textureID].blendMode==1) if(WMOMTexDefinition[WMOMTexData[lastindex].textureID].blendMode==1)
MeshBuffer->getMaterial().MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL; MeshBuffer->getMaterial().MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL;
MeshBuffer->recalculateBoundingBox(); MeshBuffer->recalculateBoundingBox();
MeshBuffer->setHardwareMappingHint(EHM_STATIC);
} }
lastindex=submeshes[i]; lastindex=submeshes[i];

View File

@ -628,22 +628,29 @@ void SceneWorld::UpdateTerrain(void)
if(_doodads.find(d->uniqueid) == _doodads.end()) // only add doodads that dont exist yet if(_doodads.find(d->uniqueid) == _doodads.end()) // only add doodads that dont exist yet
{ {
std::string filename; std::string filename;
if(instance->GetConf()->useMPQ)
filename= d->model.c_str();//This is a hack and needs fixing at some point.
//Actually the point at which this will be fixed is when all art assets are loaded together
//because there is no point in loading them separately
// logdebug("loading Doodad %s",filename.c_str());
scene::IAnimatedMesh *mesh;
if(!smgr->getMeshCache()->isMeshLoaded(filename.c_str()))
{ {
filename= d->MPQpath.c_str(); io::IReadFile* modelfile = io::IrrCreateIReadFileBasic(device, filename.c_str());
if (!modelfile)
{
logerror("Error! modelfile not found: %s", filename.c_str());
continue;
}
mesh = smgr->getMesh(modelfile);
modelfile->drop();
} }
else else
{ {
filename= d->model.c_str(); mesh = smgr->getMeshCache()->getMeshByFilename(filename.c_str());
} }
// logdebug("loading Doodad %s",filename.c_str());
io::IReadFile* modelfile = io::IrrCreateIReadFileBasic(device, filename.c_str());
if (!modelfile)
{
logerror("Error! modelfile not found: %s", d->MPQpath.c_str());
continue;
}
scene::IAnimatedMesh *mesh = smgr->getMesh(modelfile);
if(mesh) if(mesh)
{ {
scene::IAnimatedMeshSceneNode *doodad = smgr->addAnimatedMeshSceneNode(mesh); scene::IAnimatedMeshSceneNode *doodad = smgr->addAnimatedMeshSceneNode(mesh);
@ -677,6 +684,10 @@ void SceneWorld::UpdateTerrain(void)
_doodads[d->uniqueid] = gp; _doodads[d->uniqueid] = gp;
} }
} }
else
{
logerror("No mesh provided");
}
} }
} }
// create WorldMapObjects (WMOs) // create WorldMapObjects (WMOs)
@ -695,14 +706,24 @@ void SceneWorld::UpdateTerrain(void)
{ {
filename= wmo->model.c_str(); filename= wmo->model.c_str();
} }
// logdebug("loading WMO %s",filename.c_str());
io::IReadFile* modelfile = io::IrrCreateIReadFileBasic(device, filename.c_str()); scene::IAnimatedMesh *mesh;
if (!modelfile) if(!smgr->getMeshCache()->isMeshLoaded(filename.c_str()))
{ {
logerror("Error! WMO file not found: %s", wmo->MPQpath.c_str()); io::IReadFile* modelfile = io::IrrCreateIReadFileBasic(device, filename.c_str());
continue; if (!modelfile)
} {
scene::IAnimatedMesh *mesh = smgr->getMesh(modelfile); logerror("Error! modelfile not found: %s", filename.c_str());
continue;
}
mesh = smgr->getMesh(modelfile);
modelfile->drop();
}
else
{
mesh = smgr->getMeshCache()->getMeshByFilename(filename.c_str());
}
if(mesh) if(mesh)
{ {
scene::IAnimatedMeshSceneNode *wmo_node = smgr->addAnimatedMeshSceneNode(mesh); scene::IAnimatedMeshSceneNode *wmo_node = smgr->addAnimatedMeshSceneNode(mesh);

View File

@ -87,13 +87,27 @@ namespace MemoryDataHolder
} }
} }
void MakeModelFilename(char* fn, std::string fname) void MakeModelFilename(char* fn, std::string fname)
{
if(fname.find(".mdx")!=std::string::npos)
fname.replace(fname.length()-3,3,"m2");
if(loadFromMPQ)
{
sprintf(fn,"%s",fname.c_str());
}
else
{
NormalizeFilename(_PathToFileName(fname));
sprintf(fn,"./data/model/%s",fname.c_str());
}
}
void MakeWMOFilename(char* fn, std::string fname)
{ {
if(loadFromMPQ) if(loadFromMPQ)
sprintf(fn,"%s",fname.c_str()); sprintf(fn,"%s",fname.c_str());
else else
{ {
NormalizeFilename(_PathToFileName(fname)); NormalizeFilename(_PathToFileName(fname));
sprintf(fn,"./data/model/%s",fname.c_str()); sprintf(fn,"./data/wmos/%s",fname.c_str());
} }
} }
@ -117,7 +131,7 @@ namespace MemoryDataHolder
} }
~DataLoaderRunnable() ~DataLoaderRunnable()
{ {
logdev("~DataLoaderRunnable(%s) 0x%X", _name.c_str(), this); DEBUG(logdev("~DataLoaderRunnable(%s) 0x%X", _name.c_str(), this));
} }
void SetStores(TypeStorage<memblock> *mem, TypeStorage<DataLoaderRunnable> *ldrs) void SetStores(TypeStorage<memblock> *mem, TypeStorage<DataLoaderRunnable> *ldrs)
{ {
@ -139,7 +153,7 @@ namespace MemoryDataHolder
delete mb; delete mb;
return; return;
} }
logdev("DataLoaderRunnable: Reading From MPQ'%s'... (%s)", _name.c_str(), FilesizeFormat(mb->size).c_str()); DEBUG(logdev("DataLoaderRunnable: Reading From MPQ'%s'... (%s)", _name.c_str(), FilesizeFormat(mb->size).c_str()));
const ByteBuffer& bb = mpq.ExtractFile(_name.c_str()); const ByteBuffer& bb = mpq.ExtractFile(_name.c_str());
// fh.read((char*)mb->ptr, mb->size); // fh.read((char*)mb->ptr, mb->size);
if(!bb.size()) if(!bb.size())
@ -161,7 +175,7 @@ namespace MemoryDataHolder
_storage->Assign(_name, mb); _storage->Assign(_name, mb);
_loaders->Unlink(_name); // must be unlinked after the file is fully loaded, but before the callbacks are processed! _loaders->Unlink(_name); // must be unlinked after the file is fully loaded, but before the callbacks are processed!
} }
logdev("DataLoaderRunnable: Done with '%s' (%s)", _name.c_str(), FilesizeFormat(mb->size).c_str()); DEBUG(logdev("DataLoaderRunnable: Done with '%s' (%s)", _name.c_str(), FilesizeFormat(mb->size).c_str()));
DoCallbacks(_name, MDH_FILE_OK | MDH_FILE_JUST_LOADED); DoCallbacks(_name, MDH_FILE_OK | MDH_FILE_JUST_LOADED);
} }
else else
@ -194,7 +208,7 @@ namespace MemoryDataHolder
DoCallbacks(_name, MDH_FILE_ERROR); DoCallbacks(_name, MDH_FILE_ERROR);
return; return;
} }
logdev("DataLoaderRunnable: Reading '%s'... (%s)", _name.c_str(), FilesizeFormat(mb->size).c_str()); DEBUG(logdev("DataLoaderRunnable: Reading '%s'... (%s)", _name.c_str(), FilesizeFormat(mb->size).c_str()));
fh.read((char*)mb->ptr, mb->size); fh.read((char*)mb->ptr, mb->size);
fh.close(); fh.close();
{ {
@ -202,7 +216,7 @@ namespace MemoryDataHolder
_storage->Assign(_name, mb); _storage->Assign(_name, mb);
_loaders->Unlink(_name); // must be unlinked after the file is fully loaded, but before the callbacks are processed! _loaders->Unlink(_name); // must be unlinked after the file is fully loaded, but before the callbacks are processed!
} }
logdev("DataLoaderRunnable: Done with '%s' (%s)", _name.c_str(), FilesizeFormat(mb->size).c_str()); DEBUG(logdev("DataLoaderRunnable: Done with '%s' (%s)", _name.c_str(), FilesizeFormat(mb->size).c_str()));
DoCallbacks(_name, MDH_FILE_OK | MDH_FILE_JUST_LOADED); DoCallbacks(_name, MDH_FILE_OK | MDH_FILE_JUST_LOADED);
} }
} }
@ -358,14 +372,14 @@ namespace MemoryDataHolder
{ {
if(*refcount > 0) if(*refcount > 0)
(*refcount)--; (*refcount)--;
logdev("MemoryDataHolder::Delete(\"%s\"): refcount dropped to %u", s.c_str(), *refcount); DEBUG(logdev("MemoryDataHolder::Delete(\"%s\"): refcount dropped to %u", s.c_str(), *refcount));
} }
if(!*refcount) if(!*refcount)
{ {
refs.Delete(s); refs.Delete(s);
if(memblock *mb = storage.GetNoCreate(s)) if(memblock *mb = storage.GetNoCreate(s))
{ {
logdev("MemoryDataHolder:: deleting 0x%X (size %s)", mb->ptr, FilesizeFormat(mb->size).c_str()); DEBUG(logdev("MemoryDataHolder:: deleting 0x%X (size %s)", mb->ptr, FilesizeFormat(mb->size).c_str()));
mb->free(); mb->free();
storage.Delete(s); storage.Delete(s);
return true; return true;

View File

@ -54,6 +54,7 @@ namespace MemoryDataHolder
void MakeWDTFilename(char*,uint32,std::string); void MakeWDTFilename(char*,uint32,std::string);
void MakeTextureFilename(char*, std::string); void MakeTextureFilename(char*, std::string);
void MakeModelFilename(char*, std::string); void MakeModelFilename(char*, std::string);
void MakeWMOFilename(char*, std::string);
bool FileExists(std::string); bool FileExists(std::string);
MemoryDataResult GetFile(std::string s, bool threaded = false, callback_func func = NULL,void *ptr = NULL, ZThread::Condition *cond = NULL, bool ref_counted = true); MemoryDataResult GetFile(std::string s, bool threaded = false, callback_func func = NULL,void *ptr = NULL, ZThread::Condition *cond = NULL, bool ref_counted = true);

View File

@ -494,11 +494,6 @@ void PseuInstanceConf::ApplyFromVarSet(VarSet &v)
reconnect=atoi(v.Get("RECONNECT").c_str()); reconnect=atoi(v.Get("RECONNECT").c_str());
realmport=atoi(v.Get("REALMPORT").c_str()); realmport=atoi(v.Get("REALMPORT").c_str());
client=atoi(v.Get("CLIENT").c_str()); client=atoi(v.Get("CLIENT").c_str());
if(client==9) //9 = Custom settings
{
clientversion_string=v.Get("CLIENTVERSION");
clientbuild=atoi(v.Get("CLIENTBUILD").c_str());
}
clientlang=v.Get("CLIENTLANGUAGE"); clientlang=v.Get("CLIENTLANGUAGE");
realmname=v.Get("REALMNAME"); realmname=v.Get("REALMNAME");
charname=v.Get("CHARNAME"); charname=v.Get("CHARNAME");
@ -524,25 +519,25 @@ void PseuInstanceConf::ApplyFromVarSet(VarSet &v)
switch(client) switch(client)
{ {
case 0: case CLIENT_CLASSIC_WOW:
{ {
clientbuild = 6005; clientbuild = 6005;
clientversion_string="1.12.2"; clientversion_string="1.12.2";
break; break;
} }
case 1: case CLIENT_TBC:
{ {
clientbuild = 8606; clientbuild = 8606;
clientversion_string="2.4.3"; clientversion_string="2.4.3";
break; break;
} }
case 2: case CLIENT_WOTLK:
{ {
clientbuild = 12340; clientbuild = 12340;
clientversion_string="3.3.5"; clientversion_string="3.3.5";
break; break;
} }
case 3: case CLIENT_CATA:
default: default:
{ {
logerror("Unknown client - check conf"); logerror("Unknown client - check conf");

View File

@ -29,6 +29,14 @@ enum InstanceConditions
COND_MAX COND_MAX
}; };
enum Client
{
CLIENT_UNKNOWN,
CLIENT_CLASSIC_WOW,
CLIENT_TBC,
CLIENT_WOTLK,
CLIENT_CATA
};
class PseuInstanceConf class PseuInstanceConf
{ {

View File

@ -248,9 +248,9 @@ void RealmSession::_HandleRealmList(ByteBuffer& pkt)
std::string realmAddr; std::string realmAddr;
SRealmHeader rh; SRealmHeader rh;
uint16 cb = GetInstance()->GetConf()->clientbuild; uint16 client = GetInstance()->GetConf()->client;
pkt >> rh.cmd >> rh.size >> rh.unknown; pkt >> rh.cmd >> rh.size >> rh.unknown;
if(cb<=6005) if(client==CLIENT_CLASSIC_WOW)
{ {
uint8 count; uint8 count;
pkt >> count; pkt >> count;
@ -272,7 +272,7 @@ void RealmSession::_HandleRealmList(ByteBuffer& pkt)
// readout realms // readout realms
for(uint8 i=0;i<rh.count;i++) for(uint8 i=0;i<rh.count;i++)
{ {
if(cb<=6005) if(client==CLIENT_CLASSIC_WOW)
{ {
uint32 icon; uint32 icon;
pkt >> icon; pkt >> icon;
@ -539,9 +539,7 @@ void RealmSession::_HandleLogonChallenge(ByteBuffer& pkt)
packet.append(M1hash.GetDigest(),M1hash.GetLength()); packet.append(M1hash.GetDigest(),M1hash.GetLength());
packet.append(crc_hash,20); packet.append(crc_hash,20);
packet << (uint8)0; // number of keys = 0 packet << (uint8)0; // number of keys = 0
packet << (uint8)0; // 1.11.x compatibility (needs one more 0)
if(GetInstance()->GetConf()->clientbuild > 5302)
packet << (uint8)0; // 1.11.x compatibility (needs one more 0)
GetInstance()->SetSessionKey(_key); GetInstance()->SetSessionKey(_key);
memcpy(this->_m2,M2hash.GetDigest(),M2hash.GetLength()); // save M2 to an extern var to check it later memcpy(this->_m2,M2hash.GetDigest(),M2hash.GetLength()); // save M2 to an extern var to check it later
@ -561,7 +559,7 @@ void RealmSession::_HandleLogonChallenge(ByteBuffer& pkt)
void RealmSession::_HandleLogonProof(ByteBuffer& pkt) void RealmSession::_HandleLogonProof(ByteBuffer& pkt)
{ {
PseuGUI *gui = GetInstance()->GetGUI(); PseuGUI *gui = GetInstance()->GetGUI();
logdebug("RealmSocket: Got AUTH_LOGON_PROOF [%u of %u bytes]",pkt.size(),(GetInstance()->GetConf()->clientbuild>6005 ? sizeof(sAuthLogonProof_S) : sizeof(sAuthLogonProof_S_6005))); logdebug("RealmSocket: Got AUTH_LOGON_PROOF [%u of %u bytes]",pkt.size(),(GetInstance()->GetConf()->client>CLIENT_CLASSIC_WOW ? sizeof(sAuthLogonProof_S) : sizeof(sAuthLogonProof_S_6005)));
if(pkt.size() < 2) if(pkt.size() < 2)
{ {
logerror("AUTH_LOGON_PROOF: Recieved incorrect/unknown packet. Hexdump:"); logerror("AUTH_LOGON_PROOF: Recieved incorrect/unknown packet. Hexdump:");
@ -612,7 +610,7 @@ void RealmSession::_HandleLogonProof(ByteBuffer& pkt)
sAuthLogonProof_S lp; sAuthLogonProof_S lp;
if(GetInstance()->GetConf()->clientbuild<=6005) if(GetInstance()->GetConf()->client==CLIENT_CLASSIC_WOW)
{ {
sAuthLogonProof_S_6005 lp6005; sAuthLogonProof_S_6005 lp6005;
pkt.read((uint8*)&lp6005, sizeof(sAuthLogonProof_S_6005)); pkt.read((uint8*)&lp6005, sizeof(sAuthLogonProof_S_6005));

View File

@ -4,7 +4,7 @@ Bag::Bag() : Item()
{ {
_type |= TYPE_CONTAINER; _type |= TYPE_CONTAINER;
_typeid = TYPEID_CONTAINER; _typeid = TYPEID_CONTAINER;
_valuescount = CONTAINER_END; _valuescount = Object::maxvalues[_typeid];
_slot = 0; _slot = 0;
} }

View File

@ -81,9 +81,12 @@ void Channel::Join(std::string channel, std::string password)
// Send join channel request // Send join channel request
WorldPacket worldPacket; WorldPacket worldPacket;
worldPacket.SetOpcode(CMSG_JOIN_CHANNEL); worldPacket.SetOpcode(CMSG_JOIN_CHANNEL);
worldPacket << (uint32)0; // new since 2.0.x, some channel ID? server answers us with that number later if channel joined if(_worldSession->GetInstance()->GetConf()->client > CLIENT_CLASSIC_WOW)
worldPacket << (uint8)0; // unk {
worldPacket << (uint8)0; // unk, new since 2.2.x worldPacket << (uint32)0; // new since 2.0.x, some channel ID? server answers us with that number later if channel joined
worldPacket << (uint8)0; // unk
worldPacket << (uint8)0; // unk, new since 2.2.x
}
worldPacket << channel << password; worldPacket << channel << password;
_worldSession->SendWorldPacket(worldPacket); _worldSession->SendWorldPacket(worldPacket);
} }

View File

@ -4,7 +4,7 @@ Corpse::Corpse()
{ {
_type=TYPE_CORPSE; _type=TYPE_CORPSE;
_typeid=TYPEID_CORPSE; _typeid=TYPEID_CORPSE;
_valuescount=CORPSE_END; _valuescount=Object::maxvalues[_typeid];
} }
void Corpse::Create(uint64 guid) void Corpse::Create(uint64 guid)

View File

@ -5,7 +5,7 @@ DynamicObject::DynamicObject() : WorldObject()
_uint32values=NULL; _uint32values=NULL;
_type=TYPE_DYNAMICOBJECT; _type=TYPE_DYNAMICOBJECT;
_typeid=TYPEID_DYNAMICOBJECT; _typeid=TYPEID_DYNAMICOBJECT;
_valuescount=DYNAMICOBJECT_END; _valuescount=Object::maxvalues[_typeid];
} }
void DynamicObject::Create(uint64 guid) void DynamicObject::Create(uint64 guid)

View File

@ -3,9 +3,9 @@
GameObject::GameObject() : WorldObject() GameObject::GameObject() : WorldObject()
{ {
_uint32values=NULL; _uint32values=NULL;
_type=TYPE_GAMEOBJECT; _type|=TYPE_GAMEOBJECT;
_typeid=TYPEID_GAMEOBJECT; _typeid=TYPEID_GAMEOBJECT;
_valuescount=GAMEOBJECT_END; _valuescount=Object::maxvalues[_typeid];
} }
void GameObject::Create(uint64 guid) void GameObject::Create(uint64 guid)

View File

@ -1,5 +1,4 @@
#include "WorldSession.h" #include "WorldSession.h"
#include "UpdateFields.h"
#include "Item.h" #include "Item.h"
#include "Bag.h" #include "Bag.h"
@ -18,7 +17,10 @@ void WorldSession::_HandleItemQuerySingleResponseOpcode(WorldPacket& recvPacket)
proto->Id = ItemID; proto->Id = ItemID;
recvPacket >> proto->Class; recvPacket >> proto->Class;
recvPacket >> proto->SubClass; recvPacket >> proto->SubClass;
recvPacket >> unk; // dont need that value? if(GetInstance()->GetConf()->client > CLIENT_CLASSIC_WOW)
{
recvPacket >> unk; // dont need that value?
}
recvPacket >> proto->Name; recvPacket >> proto->Name;
recvPacket >> unk8; recvPacket >> unk8;
recvPacket >> unk8; recvPacket >> unk8;
@ -132,7 +134,7 @@ Item::Item()
_type |= TYPE_ITEM; _type |= TYPE_ITEM;
_typeid = TYPEID_ITEM; _typeid = TYPEID_ITEM;
_valuescount = ITEM_END; _valuescount = Object::maxvalues[_typeid];
_slot = 0; _slot = 0;
//_bag = NULL; // not yet implemented //_bag = NULL; // not yet implemented
} }

View File

@ -9,7 +9,7 @@ CacheHandler.h GameObject.h ObjectDefines.h Unit.cpp WorldP
Channel.cpp Item.cpp Object.h Unit.h WorldSession.cpp\ Channel.cpp Item.cpp Object.h Unit.h WorldSession.cpp\
Channel.h Item.h ObjMgr.cpp UpdateData.cpp WorldSession.h\ Channel.h Item.h ObjMgr.cpp UpdateData.cpp WorldSession.h\
CMSGConstructor.cpp ObjMgr.h UpdateData.h WorldSocket.cpp\ CMSGConstructor.cpp ObjMgr.h UpdateData.h WorldSocket.cpp\
Corpse.cpp MapMgr.cpp Opcodes.cpp UpdateFields.h WorldSocket.h\ Corpse.cpp MapMgr.cpp Opcodes.cpp UpdateFields.cpp WorldSocket.h\
Corpse.h MapMgr.h Opcodes.h UpdateMask.h Corpse.h MapMgr.h Opcodes.h UpdateMask.h
libworld_a_LIBADD = ../../shared/libshared.a ../../shared/Auth/libauth.a ../../shared/Network/libnetwork.a libworld_a_LIBADD = ../../shared/libshared.a ../../shared/Auth/libauth.a ../../shared/Network/libnetwork.a

View File

@ -127,12 +127,18 @@ void MapMgr::_LoadTile(uint32 gx, uint32 gy, uint32 m)
bb.append(mdr.data.ptr,mdr.data.size); bb.append(mdr.data.ptr,mdr.data.size);
MemoryDataHolder::Delete(buf); MemoryDataHolder::Delete(buf);
ADTFile *adt = new ADTFile(); ADTFile *adt = new ADTFile();
adt->LoadMem(bb); if(adt->LoadMem(bb))
logdebug("MAPMGR: Loaded ADT '%s'",buf); {
MapTile *tile = new MapTile(); logdebug("MAPMGR: Loaded ADT '%s'",buf);
tile->ImportFromADT(adt); MapTile *tile = new MapTile();
tile->ImportFromADT(adt);
_tiles->SetTile(tile,gx,gy);
}
else
{
logerror("MAPMGR: Error loading ADT '%s'",buf);//This should not happen!!
}
delete adt; delete adt;
_tiles->SetTile(tile,gx,gy);
logdebug("MAPMGR: Imported MapTile (%u, %u) for map %u",gx,gy,m); logdebug("MAPMGR: Imported MapTile (%u, %u) for map %u",gx,gy,m);
} }
else else

View File

@ -0,0 +1,115 @@
#ifndef _MOVEMENTINFO_H
#define _MOVEMENTINFO_H
enum MovementFlags
{
MOVEMENTFLAG_NONE = 0x00000000,
MOVEMENTFLAG_FORWARD = 0x00000001,
MOVEMENTFLAG_BACKWARD = 0x00000002,
MOVEMENTFLAG_STRAFE_LEFT = 0x00000004,
MOVEMENTFLAG_STRAFE_RIGHT = 0x00000008,
MOVEMENTFLAG_TURN_LEFT = 0x00000010,
MOVEMENTFLAG_TURN_RIGHT = 0x00000020,
MOVEMENTFLAG_PITCH_UP = 0x00000040,
MOVEMENTFLAG_PITCH_DOWN = 0x00000080,
MOVEMENTFLAG_WALK_MODE = 0x00000100, // Walking
MOVEMENTFLAG_ONTRANSPORT = 0x00000200,
MOVEMENTFLAG_LEVITATING = 0x00000400,
MOVEMENTFLAG_ROOT = 0x00000800,
MOVEMENTFLAG_FALLING = 0x00001000,
MOVEMENTFLAG_FALLINGFAR = 0x00002000,
MOVEMENTFLAG_PENDINGSTOP = 0x00004000,
MOVEMENTFLAG_PENDINGSTRAFESTOP = 0x00008000,
MOVEMENTFLAG_PENDINGFORWARD = 0x00010000,
MOVEMENTFLAG_PENDINGBACKWARD = 0x00020000,
MOVEMENTFLAG_PENDINGSTRAFELEFT = 0x00040000,
MOVEMENTFLAG_PENDINGSTRAFERIGHT = 0x00080000,
MOVEMENTFLAG_PENDINGROOT = 0x00100000,
MOVEMENTFLAG_SWIMMING = 0x00200000, // appears with fly flag also
MOVEMENTFLAG_ASCENDING = 0x00400000, // swim up also
MOVEMENTFLAG_DESCENDING = 0x00800000, // swim down also
MOVEMENTFLAG_CAN_FLY = 0x01000000, // can fly in 3.3?
MOVEMENTFLAG_FLYING = 0x02000000, // Actual flying mode
MOVEMENTFLAG_SPLINE_ELEVATION = 0x04000000, // used for flight paths
MOVEMENTFLAG_SPLINE_ENABLED = 0x08000000, // used for flight paths
MOVEMENTFLAG_WATERWALKING = 0x10000000, // prevent unit from falling through water
MOVEMENTFLAG_SAFE_FALL = 0x20000000, // active rogue safe fall spell (passive)
MOVEMENTFLAG_HOVER = 0x40000000
};
enum MovementFlags2
{
MOVEMENTFLAG2_NONE = 0x0000,
MOVEMENTFLAG2_UNK1 = 0x0001,
MOVEMENTFLAG2_UNK2 = 0x0002,
MOVEMENTFLAG2_UNK3 = 0x0004,
MOVEMENTFLAG2_FULLSPEEDTURNING = 0x0008,
MOVEMENTFLAG2_FULLSPEEDPITCHING = 0x0010,
MOVEMENTFLAG2_ALLOW_PITCHING = 0x0020,
MOVEMENTFLAG2_UNK4 = 0x0040,
MOVEMENTFLAG2_UNK5 = 0x0080,
MOVEMENTFLAG2_UNK6 = 0x0100,
MOVEMENTFLAG2_UNK7 = 0x0200,
MOVEMENTFLAG2_INTERP_MOVEMENT = 0x0400,
MOVEMENTFLAG2_INTERP_TURNING = 0x0800,
MOVEMENTFLAG2_INTERP_PITCHING = 0x1000,
MOVEMENTFLAG2_UNK8 = 0x2000,
MOVEMENTFLAG2_UNK9 = 0x4000,
MOVEMENTFLAG2_UNK10 = 0x8000,
MOVEMENTFLAG2_INTERP_MASK = MOVEMENTFLAG2_INTERP_MOVEMENT | MOVEMENTFLAG2_INTERP_TURNING | MOVEMENTFLAG2_INTERP_PITCHING
};
struct MovementInfo
{
static uint8 _c; //Version switch helper
// Read/Write methods
void Read(ByteBuffer &data);
void Write(ByteBuffer &data) const;
// common
uint32 flags;
uint16 flags2;
uint32 time;
WorldPosition pos;
// transport
uint64 t_guid;
WorldPosition t_pos;
uint32 t_time, t_time2;
uint8 t_seat;
// swimming and unk
float s_angle;
// last fall time
uint32 fallTime;
// jumping
float j_velocity, j_sinAngle, j_cosAngle, j_xyspeed;
// spline
float u_unk1;
MovementInfo()
{
flags = time = t_time = fallTime = flags2 = 0;
t_seat = 0;
s_angle = j_velocity = j_sinAngle = j_cosAngle = j_xyspeed = u_unk1 = 0.0f;
t_guid = 0;
}
void SetMovementFlags(uint32 _flags)
{
flags = _flags;
}
};
inline ByteBuffer& operator<< (ByteBuffer& buf, MovementInfo const& mi)
{
mi.Write(buf);
return buf;
}
inline ByteBuffer& operator>> (ByteBuffer& buf, MovementInfo& mi)
{
mi.Read(buf);
return buf;
}
#endif

View File

@ -3,6 +3,7 @@
#include "World.h" #include "World.h"
#include "MovementMgr.h" #include "MovementMgr.h"
#include "Player.h" #include "Player.h"
#include "MovementInfo.h"
MovementMgr::MovementMgr() MovementMgr::MovementMgr()
{ {
@ -33,32 +34,18 @@ void MovementMgr::SetInstance(PseuInstance *inst)
void MovementMgr::_BuildPacket(uint16 opcode) void MovementMgr::_BuildPacket(uint16 opcode)
{ {
WorldPacket *wp = new WorldPacket(opcode,4+2+4+16); // it can be larger, if we are jumping, on transport or swimming WorldPacket *wp = new WorldPacket(opcode,4+2+4+16); // it can be larger, if we are jumping, on transport or swimming
wp->appendPackGUID(_mychar->GetGUID()); if(_instance->GetConf()->client > CLIENT_TBC)
*wp << _moveFlags; wp->appendPackGUID(_mychar->GetGUID());
*wp << (uint16)0; // flags2 , safe to set 0 for now (shlainn) MovementInfo mi;
*wp << getMSTime(); mi.SetMovementFlags(_moveFlags);
*wp << _mychar->GetPosition(); mi.time = getMSTime();
// TODO: transport not yet handled/done mi.pos = _mychar->GetPosition();
if(_moveFlags & MOVEMENTFLAG_ONTRANSPORT) mi.fallTime = _falltime;
{ *wp << mi;
*wp << (uint64)0; // transport guid
*wp << WorldPosition(); // transport position
*wp << getMSTime(); // transport time (??)
}
// TODO: swimming not yet done
if(_moveFlags & MOVEMENTFLAG_SWIMMING)
{
*wp << (float)0; // angle; 1.55=looking up, -1.55=looking down, 0=looking forward
}
*wp << (uint32)0; // last fall time (also used when jumping)
if(_moveFlags & MOVEMENTFLAG_PENDINGSTOP)
{
*wp << (float)0; //unk value, or as mangos calls it: j_unk ^^
*wp << sin(_mychar->GetO()+ (M_PI/2));
*wp << cos(_mychar->GetO()+ (M_PI/2));
*wp << _movespeed;
}
// TODO: transport not yet handled/done
// TODO: swimming not yet done
// TODO: jumping not done yet
// TODO: spline not yet done // TODO: spline not yet done
DEBUG(logdebug("Move flags: 0x%X (packet: %u bytes)",_moveFlags,wp->size())); DEBUG(logdebug("Move flags: 0x%X (packet: %u bytes)",_moveFlags,wp->size()));
@ -66,6 +53,8 @@ void MovementMgr::_BuildPacket(uint16 opcode)
_instance->GetWSession()->AddSendWorldPacket(wp); _instance->GetWSession()->AddSendWorldPacket(wp);
_moved = true; _moved = true;
_optime = getMSTime(); _optime = getMSTime();
_falltime = 0; //HACK!!!!
} }
@ -171,6 +160,12 @@ void MovementMgr::MoveStop(void)
_BuildPacket(MSG_MOVE_STOP); _BuildPacket(MSG_MOVE_STOP);
} }
void MovementMgr::MoveFallLand(void)
{
Update(true);
_BuildPacket(MSG_MOVE_FALL_LAND);
}
void MovementMgr::MoveStartForward(void) void MovementMgr::MoveStartForward(void)
{ {
if(_moveFlags & MOVEMENTFLAG_FORWARD) if(_moveFlags & MOVEMENTFLAG_FORWARD)

View File

@ -2,7 +2,7 @@
#define MOVEMENTMGR_H #define MOVEMENTMGR_H
#include "common.h" #include "common.h"
#include "UpdateData.h" #include "MovementInfo.h"
#define MOVE_HEARTBEAT_DELAY 500 #define MOVE_HEARTBEAT_DELAY 500
#define MOVE_TURN_UPDATE_DIFF 0.15f // not sure about original/real value, but this seems good #define MOVE_TURN_UPDATE_DIFF 0.15f // not sure about original/real value, but this seems good
@ -58,7 +58,7 @@ public:
bool IsTurning(void); // spinning around? bool IsTurning(void); // spinning around?
bool IsWalking(void); // walking straight forward/backward? bool IsWalking(void); // walking straight forward/backward?
bool IsStrafing(void); // strafing left/right? bool IsStrafing(void); // strafing left/right?
inline void SetFallTime(uint32 falltime){_falltime = falltime; }
private: private:
@ -71,6 +71,7 @@ private:
uint8 _movemode; // automatic or manual uint8 _movemode; // automatic or manual
float _movespeed; // current xy movement speed float _movespeed; // current xy movement speed
float _jumptime; float _jumptime;
uint32 _falltime;
UnitMoveType _movetype; // index used for speed selection UnitMoveType _movetype; // index used for speed selection
bool _moved; bool _moved;

View File

@ -9,7 +9,7 @@ Object::Object()
_uint32values=NULL; _uint32values=NULL;
_type=TYPE_OBJECT; _type=TYPE_OBJECT;
_typeid=TYPEID_OBJECT; _typeid=TYPEID_OBJECT;
_valuescount=OBJECT_END; // base class. this value will be set by derived classes _valuescount=Object::maxvalues[_typeid]; // base class. this value will be set by derived classes
} }
Object::~Object() Object::~Object()
@ -110,7 +110,9 @@ void WorldSession::_HandleDestroyObjectOpcode(WorldPacket& recvPacket)
uint64 guid; uint64 guid;
uint8 dummy; uint8 dummy;
recvPacket >> guid >> dummy; recvPacket >> guid;
if(GetInstance()->GetConf()->client > CLIENT_TBC)
recvPacket >> dummy;
logdebug("Destroy Object "I64FMT,guid); logdebug("Destroy Object "I64FMT,guid);
// call script just before object removal // call script just before object removal

View File

@ -7,6 +7,14 @@
#include "HelperDefs.h" #include "HelperDefs.h"
#include "World.h" #include "World.h"
struct UpdateField
{
UpdateField(){};
UpdateField(uint16 o, uint16 t):offset(o),type(t){};
uint16 offset;
uint16 type;
};
enum TYPE enum TYPE
{ {
TYPE_OBJECT = 1, TYPE_OBJECT = 1,
@ -32,16 +40,17 @@ enum TYPEID
TYPEID_DYNAMICOBJECT = 6, TYPEID_DYNAMICOBJECT = 6,
TYPEID_CORPSE = 7, TYPEID_CORPSE = 7,
TYPEID_AIGROUP = 8, TYPEID_AIGROUP = 8,
TYPEID_AREATRIGGER = 9 TYPEID_AREATRIGGER = 9,
TYPEID_MAX
}; };
class Object class Object
{ {
public: public:
virtual ~Object(); virtual ~Object();
inline const uint64 GetGUID() const { return GetUInt64Value(0); } inline const uint64 GetGUID() const { return GetUInt64Value(OBJECT_FIELD_GUID); }
inline const uint32 GetGUIDLow() const { return GetUInt32Value(0); } inline const uint32 GetGUIDLow() const { return GetUInt32Value(OBJECT_FIELD_GUID_LOW); }
inline const uint32 GetGUIDHigh() const { return GetUInt32Value(1); } inline const uint32 GetGUIDHigh() const { return GetUInt32Value(OBJECT_FIELD_GUID_HIGH); }
inline uint32 GetEntry() const { return GetUInt32Value(OBJECT_FIELD_ENTRY); } inline uint32 GetEntry() const { return GetUInt32Value(OBJECT_FIELD_ENTRY); }
inline uint16 GetValuesCount(void) { return _valuescount; } inline uint16 GetValuesCount(void) { return _valuescount; }
@ -57,35 +66,39 @@ public:
inline bool IsDynObject(void) { return _typeid == TYPEID_DYNAMICOBJECT; } // specific inline bool IsDynObject(void) { return _typeid == TYPEID_DYNAMICOBJECT; } // specific
inline bool IsGameObject(void) { return _typeid == TYPEID_GAMEOBJECT; } // specific inline bool IsGameObject(void) { return _typeid == TYPEID_GAMEOBJECT; } // specific
inline bool IsWorldObject(void) { return _type & (TYPE_PLAYER | TYPE_UNIT | TYPE_CORPSE | TYPE_DYNAMICOBJECT | TYPE_GAMEOBJECT); } inline bool IsWorldObject(void) { return _type & (TYPE_PLAYER | TYPE_UNIT | TYPE_CORPSE | TYPE_DYNAMICOBJECT | TYPE_GAMEOBJECT); }
inline const uint32 GetUInt32Value( uint16 index ) const inline const uint32 GetUInt32Value( UpdateFieldName index ) const
{ {
return _uint32values[ index ]; return _uint32values[ Object::updatefields[index].offset ];
} }
inline const uint64 GetUInt64Value( uint16 index ) const inline const uint64 GetUInt64Value( UpdateFieldName index ) const
{ {
return *((uint64*)&(_uint32values[ index ])); return *((uint64*)&(_uint32values[ Object::updatefields[index].offset ]));
} }
inline bool HasFlag( uint16 index, uint32 flag ) const inline bool HasFlag( UpdateFieldName index, uint32 flag ) const
{ {
return (_uint32values[ index ] & flag) != 0; return (_uint32values[ Object::updatefields[index].offset ] & flag) != 0;
} }
inline const float GetFloatValue( uint16 index ) const inline const float GetFloatValue( UpdateFieldName index ) const
{ {
return _floatvalues[ index ]; return _floatvalues[ Object::updatefields[index].offset ];
} }
inline void SetFloatValue( uint16 index, float value ) inline void SetFloatValue( UpdateFieldName index, float value )
{ {
_floatvalues[ index ] = value; _floatvalues[ Object::updatefields[index].offset ] = value;
} }
inline void SetUInt32Value( uint16 index, uint32 value ) inline void SetUInt32Value( UpdateFieldName index, uint32 value )
{ {
_uint32values[ index ] = value; _uint32values[ Object::updatefields[index].offset ] = value;
} }
inline void SetUInt64Value( uint16 index, uint64 value ) inline void SetUInt32Value( uint16 offset, uint32 value )
{ {
*((uint64*)&(_uint32values[ index ])) = value; _uint32values[ offset ] = value;
}
inline void SetUInt64Value( UpdateFieldName index, uint64 value )
{
*((uint64*)&(_uint32values[ Object::updatefields[index].offset ])) = value;
} }
inline void SetName(std::string name) { _name = name; } inline void SetName(std::string name) { _name = name; }
@ -93,13 +106,16 @@ public:
inline float GetObjectSize() const inline float GetObjectSize() const
{ {
return ( _valuescount > UNIT_FIELD_BOUNDINGRADIUS ) ? _floatvalues[UNIT_FIELD_BOUNDINGRADIUS] : 0.39f; return ( _valuescount > Object::updatefields[UNIT_FIELD_BOUNDINGRADIUS].offset ) ? _floatvalues[Object::updatefields[UNIT_FIELD_BOUNDINGRADIUS].offset] : 0.39f;
} }
void Create(uint64 guid); void Create(uint64 guid);
inline bool _IsDepleted(void) { return _depleted; } inline bool _IsDepleted(void) { return _depleted; }
inline void _SetDepleted(void) { _depleted = true; } inline void _SetDepleted(void) { _depleted = true; }
static uint32 maxvalues[];
static UpdateField updatefields[];
protected: protected:
Object(); Object();
void _InitValues(void); void _InitValues(void);
@ -114,8 +130,10 @@ protected:
uint8 _typeid; uint8 _typeid;
std::string _name; std::string _name;
bool _depleted : 1; // true if the object was deleted from the objmgr, but not from memory bool _depleted : 1; // true if the object was deleted from the objmgr, but not from memory
}; };
class WorldObject : public Object class WorldObject : public Object
{ {
public: public:
@ -145,17 +163,8 @@ protected:
inline uint32 GetValuesCountByTypeId(uint8 tid) inline uint32 GetValuesCountByTypeId(uint8 tid)
{ {
switch(tid) if(tid < TYPEID_MAX)
{ return Object::maxvalues[tid];
case TYPEID_OBJECT: return OBJECT_END;
case TYPEID_UNIT: return UNIT_END;
case TYPEID_PLAYER: return PLAYER_END;
case TYPEID_ITEM: return ITEM_END;
case TYPEID_CONTAINER: return CONTAINER_END;
case TYPEID_GAMEOBJECT: return GAMEOBJECT_END;
case TYPEID_DYNAMICOBJECT: return DYNAMICOBJECT_END;
case TYPEID_CORPSE: return CORPSE_END;
}
return 0; return 0;
} }

View File

@ -13,7 +13,7 @@ Player::Player() : Unit()
{ {
_type |= TYPE_PLAYER; _type |= TYPE_PLAYER;
_typeid = TYPEID_PLAYER; _typeid = TYPEID_PLAYER;
_valuescount = PLAYER_END; _valuescount = Object::maxvalues[_typeid];
} }
void Player::Create(uint64 guid) void Player::Create(uint64 guid)

View File

@ -5,7 +5,7 @@ Unit::Unit() : WorldObject()
{ {
_type |= TYPE_UNIT; _type |= TYPE_UNIT;
_typeid = TYPEID_UNIT; _typeid = TYPEID_UNIT;
_valuescount = UNIT_END; _valuescount = Object::maxvalues[_typeid];
} }
void Unit::Create(uint64 guid) void Unit::Create(uint64 guid)

View File

@ -66,6 +66,8 @@ struct CreatureTemplate
uint8 RacialLeader; uint8 RacialLeader;
uint32 questItems[4]; uint32 questItems[4];
uint32 movementId; uint32 movementId;
uint32 PetSpellDataId;
uint16 civilian;
}; };

View File

@ -2,7 +2,6 @@
#include "ZCompressor.h" #include "ZCompressor.h"
#include "WorldSession.h" #include "WorldSession.h"
#include "UpdateData.h" #include "UpdateData.h"
#include "UpdateFields.h"
#include "Object.h" #include "Object.h"
#include "Unit.h" #include "Unit.h"
#include "Bag.h" #include "Bag.h"
@ -11,6 +10,7 @@
#include "DynamicObject.h" #include "DynamicObject.h"
#include "ObjMgr.h" #include "ObjMgr.h"
#include "UpdateMask.h" #include "UpdateMask.h"
#include "MovementInfo.h"
void WorldSession::_HandleCompressedUpdateObjectOpcode(WorldPacket& recvPacket) void WorldSession::_HandleCompressedUpdateObjectOpcode(WorldPacket& recvPacket)
@ -37,11 +37,13 @@ void WorldSession::_HandleCompressedUpdateObjectOpcode(WorldPacket& recvPacket)
void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket) void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
{ {
uint8 utype; uint8 utype;
//uint8 hasTransport; uint8 hasTransport;
uint32 usize, ublocks, readblocks=0; uint32 usize, ublocks, readblocks=0;
uint64 uguid; uint64 uguid;
recvPacket >> ublocks; // >> hasTransport; recvPacket >> ublocks; // >> hasTransport;
//logdev("UpdateObject: blocks = %u, hasTransport = %u", ublocks, hasTransport); if(GetInstance()->GetConf()->client <= CLIENT_TBC)
recvPacket >> hasTransport;
logdev("UpdateObject: blocks = %u", ublocks); logdev("UpdateObject: blocks = %u", ublocks);
while((recvPacket.rpos() < recvPacket.size())&& (readblocks < ublocks)) while((recvPacket.rpos() < recvPacket.size())&& (readblocks < ublocks))
{ {
@ -50,7 +52,7 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
{ {
case UPDATETYPE_VALUES: case UPDATETYPE_VALUES:
{ {
uguid = recvPacket.GetPackedGuid(); uguid = recvPacket.readPackGUID();
_ValuesUpdate(uguid,recvPacket); _ValuesUpdate(uguid,recvPacket);
} }
break; break;
@ -76,7 +78,7 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
case UPDATETYPE_CREATE_OBJECT2: // will be sent when our very own character is created case UPDATETYPE_CREATE_OBJECT2: // will be sent when our very own character is created
case UPDATETYPE_CREATE_OBJECT: // will be sent on any other object creation case UPDATETYPE_CREATE_OBJECT: // will be sent on any other object creation
{ {
uguid = recvPacket.GetPackedGuid(); uguid = recvPacket.readPackGUID();
uint8 objtypeid; uint8 objtypeid;
recvPacket >> objtypeid; recvPacket >> objtypeid;
logdebug("Create Object type %u with guid "I64FMT,objtypeid,uguid); logdebug("Create Object type %u with guid "I64FMT,objtypeid,uguid);
@ -127,6 +129,7 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
Unit *unit = new Unit(); Unit *unit = new Unit();
unit->Create(uguid); unit->Create(uguid);
objmgr.Add(unit); objmgr.Add(unit);
logdebug("Created Unit with guid "I64FMT,uguid);
break; break;
} }
case TYPEID_PLAYER: case TYPEID_PLAYER:
@ -136,6 +139,7 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
Player *player = new Player(); Player *player = new Player();
player->Create(uguid); player->Create(uguid);
objmgr.Add(player); objmgr.Add(player);
logdebug("Created Player with guid "I64FMT,uguid);
break; break;
} }
case TYPEID_GAMEOBJECT: case TYPEID_GAMEOBJECT:
@ -143,6 +147,7 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
GameObject *go = new GameObject(); GameObject *go = new GameObject();
go->Create(uguid); go->Create(uguid);
objmgr.Add(go); objmgr.Add(go);
logdebug("Created GO with guid "I64FMT,uguid);
break; break;
} }
case TYPEID_CORPSE: case TYPEID_CORPSE:
@ -150,6 +155,7 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
Corpse *corpse = new Corpse(); Corpse *corpse = new Corpse();
corpse->Create(uguid); corpse->Create(uguid);
objmgr.Add(corpse); objmgr.Add(corpse);
logdebug("Created Corpse with guid "I64FMT,uguid);
break; break;
} }
case TYPEID_DYNAMICOBJECT: case TYPEID_DYNAMICOBJECT:
@ -157,6 +163,7 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
DynamicObject *dobj = new DynamicObject(); DynamicObject *dobj = new DynamicObject();
dobj->Create(uguid); dobj->Create(uguid);
objmgr.Add(dobj); objmgr.Add(dobj);
logdebug("Created DynObj with guid "I64FMT,uguid);
break; break;
} }
} }
@ -180,6 +187,7 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
Set.defaultarg = toString(uguid); Set.defaultarg = toString(uguid);
Set.arg[0] = toString(objtypeid); Set.arg[0] = toString(objtypeid);
GetInstance()->GetScripts()->RunScript("_onobjectcreate", &Set); GetInstance()->GetScripts()->RunScript("_onobjectcreate", &Set);
} }
// if our own character got finally created, we have successfully entered the world, // if our own character got finally created, we have successfully entered the world,
@ -192,7 +200,7 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
recvPacket >> usize; recvPacket >> usize;
for(uint16 i=0;i<usize;i++) for(uint16 i=0;i<usize;i++)
{ {
uguid = recvPacket.GetPackedGuid(); // not 100% sure if this is correct uguid = recvPacket.readPackGUID(); // not 100% sure if this is correct
logdebug("GUID "I64FMT" out of range",uguid); logdebug("GUID "I64FMT" out of range",uguid);
// call script just before object removal // call script just before object removal
@ -238,10 +246,13 @@ void WorldSession::_MovementUpdate(uint8 objtypeid, uint64 uguid, WorldPacket& r
{ {
MovementInfo mi; // TODO: use a reference to a MovementInfo in Unit/Player class once implemented MovementInfo mi; // TODO: use a reference to a MovementInfo in Unit/Player class once implemented
uint16 flags; uint16 flags;
uint8 flags_6005;
// uint64 fullguid; // see below // uint64 fullguid; // see below
float speedWalk, speedRun, speedSwimBack, speedSwim, speedWalkBack, speedTurn, speedFly, speedFlyBack, speedPitchRate; float speedWalk =0, speedRun =0, speedSwimBack =0, speedSwim =0, speedWalkBack =0, speedTurn =0, speedFly =0, speedFlyBack =0, speedPitchRate =0;
uint32 unk32; uint32 unk32;
uint16 client = GetInstance()->GetConf()->client;
Object *obj = (Object*)objmgr.GetObj(uguid, true); // also depleted objects Object *obj = (Object*)objmgr.GetObj(uguid, true); // also depleted objects
Unit *u = NULL; Unit *u = NULL;
if(obj) if(obj)
@ -256,57 +267,55 @@ void WorldSession::_MovementUpdate(uint8 objtypeid, uint64 uguid, WorldPacket& r
logerror("MovementUpdate for unknown object "I64FMT" typeid=%u",uguid,objtypeid); logerror("MovementUpdate for unknown object "I64FMT" typeid=%u",uguid,objtypeid);
} }
recvPacket >> flags; if(client > CLIENT_TBC)
recvPacket >> flags;
else
{
recvPacket >> flags_6005;
flags = flags_6005;
}
mi.flags = 0; // not sure if its correct to set it to 0 (needs some starting flag?) mi.flags = 0; // not sure if its correct to set it to 0 (needs some starting flag?)
if(flags & UPDATEFLAG_LIVING) if(flags & UPDATEFLAG_LIVING)
{ {
recvPacket >> mi.flags >> mi.unkFlags >> mi.time; recvPacket >> mi;
logdev("MovementUpdate: TypeID=%u GUID="I64FMT" pObj=%X flags=%u mi.flags=%u",objtypeid,uguid,obj,flags,mi.flags); logdev("MovementUpdate: TypeID=%u GUID="I64FMT" pObj=%X flags=%x mi.flags=%x",objtypeid,uguid,obj,flags,mi.flags);
logdev("FLOATS: x=%f y=%f z=%f o=%f",mi.pos.x, mi.pos.y, mi.pos.z ,mi.pos.o);
recvPacket >> mi.x >> mi.y >> mi.z >> mi.o;
logdev("FLOATS: x=%f y=%f z=%f o=%f",mi.x, mi.y, mi.z ,mi.o);
if(obj && obj->IsWorldObject()) if(obj && obj->IsWorldObject())
((WorldObject*)obj)->SetPosition(mi.x, mi.y, mi.z, mi.o); ((WorldObject*)obj)->SetPosition(mi.pos.x, mi.pos.y, mi.pos.z, mi.pos.o);
if(mi.flags & MOVEMENTFLAG_ONTRANSPORT) if(mi.flags & MOVEMENTFLAG_ONTRANSPORT)
{ {
mi.t_guid = recvPacket.GetPackedGuid(); logdev("TRANSPORT @ mi.flags: guid="I64FMT" x=%f y=%f z=%f o=%f", mi.t_guid, mi.t_pos.x, mi.t_pos.y, mi.t_pos.z, mi.t_pos.o);
recvPacket >> mi.t_x >> mi.t_y >> mi.t_z >> mi.t_o;
recvPacket >> mi.t_time; // added in 2.0.3
recvPacket >> mi.t_seat;
logdev("TRANSPORT @ mi.flags: guid="I64FMT" x=%f y=%f z=%f o=%f", mi.t_guid, mi.t_x, mi.t_y, mi.t_z, mi.t_o);
} }
if((mi.flags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) || (mi.unkFlags & 0x20)) //The last one is MOVEFLAG2_ALLOW_PITCHING in MaNGOS if((mi.flags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) || (mi.flags2 & MOVEMENTFLAG2_ALLOW_PITCHING))
{ {
recvPacket >> mi.s_angle;
logdev("MovementUpdate: MOVEMENTFLAG_SWIMMING or FLYING is set, angle = %f!", mi.s_angle); logdev("MovementUpdate: MOVEMENTFLAG_SWIMMING or FLYING is set, angle = %f!", mi.s_angle);
} }
recvPacket >> mi.fallTime;
logdev("MovementUpdate: FallTime = %u", mi.fallTime); logdev("MovementUpdate: FallTime = %u", mi.fallTime);
if(mi.flags & MOVEMENTFLAG_FALLING) if(mi.flags & MOVEMENTFLAG_FALLING)
{ {
recvPacket >> mi.j_unk >> mi.j_sinAngle >> mi.j_cosAngle >> mi.j_xyspeed; logdev("MovementUpdate: MOVEMENTFLAG_FALLING is set, velocity=%f sinA=%f cosA=%f xyspeed=%f = %u", mi.j_velocity, mi.j_sinAngle, mi.j_cosAngle, mi.j_xyspeed);
logdev("MovementUpdate: MOVEMENTFLAG_FALLING is set, unk=%f sinA=%f cosA=%f xyspeed=%f = %u", mi.j_unk, mi.j_sinAngle, mi.j_cosAngle, mi.j_xyspeed);
} }
if(mi.flags & MOVEMENTFLAG_SPLINE_ELEVATION) if(mi.flags & MOVEMENTFLAG_SPLINE_ELEVATION)
{ {
recvPacket >> mi.u_unk1;
logdev("MovementUpdate: MOVEMENTFLAG_SPLINE is set, got %u", mi.u_unk1); logdev("MovementUpdate: MOVEMENTFLAG_SPLINE is set, got %u", mi.u_unk1);
} }
recvPacket >> speedWalk >> speedRun >> speedSwimBack >> speedSwim; // speedRun can also be mounted speed if player is mounted recvPacket >> speedWalk >> speedRun >> speedSwimBack >> speedSwim >> speedWalkBack; // speedRun can also be mounted speed if player is mounted; WalkBack is called RunBack in Mangos
recvPacket >> speedWalkBack >> speedFly >> speedFlyBack >> speedTurn; // fly added in 2.0.x if(client > CLIENT_CLASSIC_WOW)
recvPacket >> speedPitchRate; recvPacket >> speedFly >> speedFlyBack; // fly added in 2.0.x
recvPacket >> speedTurn;
if(client > CLIENT_TBC)
recvPacket >> speedPitchRate;
logdev("MovementUpdate: Got speeds, walk=%f run=%f turn=%f", speedWalk, speedRun, speedTurn); logdev("MovementUpdate: Got speeds, walk=%f run=%f turn=%f", speedWalk, speedRun, speedTurn);
if(u) if(u)
{ {
u->SetPosition(mi.x, mi.y, mi.z, mi.o); u->SetPosition(mi.pos.x, mi.pos.y, mi.pos.z, mi.pos.o);
u->SetSpeed(MOVE_WALK, speedWalk); u->SetSpeed(MOVE_WALK, speedWalk);
u->SetSpeed(MOVE_RUN, speedRun); u->SetSpeed(MOVE_RUN, speedRun);
u->SetSpeed(MOVE_SWIMBACK, speedSwimBack); u->SetSpeed(MOVE_SWIMBACK, speedSwimBack);
@ -329,7 +338,7 @@ void WorldSession::_MovementUpdate(uint8 objtypeid, uint64 uguid, WorldPacket& r
{ {
if(flags & UPDATEFLAG_POSITION) if(flags & UPDATEFLAG_POSITION)
{ {
uint64 pguid = recvPacket.GetPackedGuid(); uint64 pguid = recvPacket.readPackGUID();
float x,y,z,o,sx,sy,sz,so; float x,y,z,o,sx,sy,sz,so;
recvPacket >> x >> y >> z; recvPacket >> x >> y >> z;
recvPacket >> sx >> sy >> sz; recvPacket >> sx >> sy >> sz;
@ -358,29 +367,36 @@ void WorldSession::_MovementUpdate(uint8 objtypeid, uint64 uguid, WorldPacket& r
} }
} }
if(flags & UPDATEFLAG_LOWGUID) if(client > CLIENT_CLASSIC_WOW && flags & UPDATEFLAG_LOWGUID)
{ {
recvPacket >> unk32; recvPacket >> unk32;
logdev("MovementUpdate: UPDATEFLAG_LOWGUID is set, got %X", unk32); logdev("MovementUpdate: UPDATEFLAG_LOWGUID is set, got %X", unk32);
} }
if(flags & UPDATEFLAG_HIGHGUID) if(client > CLIENT_CLASSIC_WOW && flags & UPDATEFLAG_HIGHGUID)
{ {
recvPacket >> unk32; // 2.0.6 - high guid was there, unk for 2.0.12 recvPacket >> unk32; // 2.0.6 - high guid was there, unk for 2.0.12
// not sure if this is correct, MaNGOS sends 0 always. // not sure if this is correct, MaNGOS sends 0 always.
//obj->SetUInt32Value(OBJECT_FIELD_GUID+1,higuid); // note that this sets only the high part of the guid //obj->SetUInt32Value(OBJECT_FIELD_GUID+1,higuid); // note that this sets only the high part of the guid
logdev("MovementUpdate: UPDATEFLAG_HIGHGUID is set, got %X", unk32); logdev("MovementUpdate: UPDATEFLAG_HIGHGUID is set, got %X", unk32);
} }
if(client == CLIENT_CLASSIC_WOW && flags & UPDATEFLAG_ALL_6005)
{
recvPacket >> unk32;
// MaNGOS sends 1 always.
logdev("MovementUpdate: UPDATEFLAG_ALL is set, got %X", unk32);
}
if(flags & UPDATEFLAG_HAS_TARGET) if(flags & UPDATEFLAG_HAS_TARGET)
{ {
uint64 unkguid = recvPacket.GetPackedGuid(); // MaNGOS sends uint8(0) always, but its probably be a packed guid uint64 unkguid = recvPacket.readPackGUID(); // MaNGOS sends uint8(0) always, but its probably be a packed guid
logdev("MovementUpdate: UPDATEFLAG_FULLGUID is set, got "I64FMT, unkguid); logdev("MovementUpdate: UPDATEFLAG_FULLGUID is set, got "I64FMT, unkguid);
} }
if(flags & UPDATEFLAG_TRANSPORT) if(flags & UPDATEFLAG_TRANSPORT)
{ {
recvPacket >> unk32; // whats this used for? recvPacket >> unk32; // mangos says: ms time
logdev("MovementUpdate: UPDATEFLAG_TRANSPORT is set, got %u", unk32); logdev("MovementUpdate: UPDATEFLAG_TRANSPORT is set, got %u", unk32);
} }
@ -405,8 +421,6 @@ void WorldSession::_ValuesUpdate(uint64 uguid, WorldPacket& recvPacket)
Object *obj = objmgr.GetObj(uguid); Object *obj = objmgr.GetObj(uguid);
uint8 blockcount,tyid; uint8 blockcount,tyid;
uint32 value, masksize, valuesCount; uint32 value, masksize, valuesCount;
float fvalue;
uint64 value64;
if(obj) if(obj)
{ {
@ -431,7 +445,6 @@ void WorldSession::_ValuesUpdate(uint64 uguid, WorldPacket& recvPacket)
umask.SetMask(updateMask); umask.SetMask(updateMask);
//delete [] updateMask; // will be deleted at ~UpdateMask() !!!! //delete [] updateMask; // will be deleted at ~UpdateMask() !!!!
logdev("ValuesUpdate TypeId=%u GUID="I64FMT" pObj=%X Blocks=%u Masksize=%u",tyid,uguid,obj,blockcount,masksize); logdev("ValuesUpdate TypeId=%u GUID="I64FMT" pObj=%X Blocks=%u Masksize=%u",tyid,uguid,obj,blockcount,masksize);
// just in case the object does not exist, and we have really a container instead of an item, and a value in // just in case the object does not exist, and we have really a container instead of an item, and a value in
// the container fields is set, THEN we have a problem. this should never be the case; it can be fixed in a // the container fields is set, THEN we have a problem. this should never be the case; it can be fixed in a
// more correct way if there is the need. // more correct way if there is the need.
@ -442,25 +455,9 @@ void WorldSession::_ValuesUpdate(uint64 uguid, WorldPacket& recvPacket)
{ {
if(obj) if(obj)
{ {
if(IsFloatField(obj->GetTypeMask(),i)) recvPacket >> value;
{ obj->SetUInt32Value(i, value); //It does not matter what type of value we are setting, just copy the bytes
recvPacket >> fvalue; DEBUG(logdev("%u %u",i,value));
obj->SetFloatValue(i, fvalue);
logdev("-> Field[%u] = %f",i,fvalue);
}
else if(IsUInt64Field(obj->GetTypeMask(),i) && umask.GetBit(i+1))
{
recvPacket >> value64;
obj->SetUInt64Value(i, value64);
logdev("-> Field[%u] = "I64FMT,i,value64);
i++;
}
else
{
recvPacket >> value;
obj->SetUInt32Value(i, value);
logdev("-> Field[%u] = %u",i,value);
}
} }
else else
{ {
@ -525,222 +522,117 @@ void WorldSession::_QueryObjectInfo(uint64 guid)
} }
} }
// helper to determine if an updatefield should store float or int values, depending on TypeId void MovementInfo::Read(ByteBuffer &data)
bool IsFloatField(uint8 ty, uint32 f)
{ {
static uint32 floats_object[] = data >> flags;
if(_c == CLIENT_WOTLK)
data >> flags2;
if(_c == CLIENT_TBC)
{ {
(uint32)OBJECT_FIELD_SCALE_X, uint8 tempFlags2;
(uint32)-1 data >> tempFlags2;
}; flags2 = tempFlags2;
/* }
static uint32 floats_item[] = data >> time;
{ data >> pos.x;
(uint32)-1 data >> pos.y;
}; data >> pos.z;
static uint32 floats_container[] = data >> pos.o;
{
(uint32)-1
};
*/
static uint32 floats_unit[] =
{
(uint32)UNIT_FIELD_BOUNDINGRADIUS,
(uint32)UNIT_FIELD_COMBATREACH,
(uint32)UNIT_FIELD_MINDAMAGE,
(uint32)UNIT_FIELD_MAXDAMAGE,
(uint32)UNIT_FIELD_MINOFFHANDDAMAGE,
(uint32)UNIT_FIELD_MINOFFHANDDAMAGE,
(uint32)UNIT_MOD_CAST_SPEED,
(uint32)UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER,
(uint32)UNIT_FIELD_ATTACK_POWER_MULTIPLIER,
(uint32)UNIT_FIELD_MINRANGEDDAMAGE,
(uint32)UNIT_FIELD_MAXRANGEDDAMAGE,
(uint32)UNIT_FIELD_POWER_COST_MULTIPLIER,
(uint32)UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER,
(uint32)UNIT_FIELD_POWER_REGEN_INTERRUPTED_FLAT_MODIFIER,
(uint32)UNIT_FIELD_MAXHEALTHMODIFIER,
(uint32)UNIT_FIELD_HOVERHEIGHT,
(uint32)-1
};
static uint32 floats_player[] =
{
(uint32)PLAYER_BLOCK_PERCENTAGE,
(uint32)PLAYER_DODGE_PERCENTAGE,
(uint32)PLAYER_PARRY_PERCENTAGE,
(uint32)PLAYER_RANGED_CRIT_PERCENTAGE,
(uint32)PLAYER_OFFHAND_CRIT_PERCENTAGE,
(uint32)PLAYER_SPELL_CRIT_PERCENTAGE1,
(uint32)PLAYER_CRIT_PERCENTAGE,
(uint32)PLAYER_SHIELD_BLOCK_CRIT_PERCENTAGE,
(uint32)PLAYER_FIELD_MOD_HEALING_PCT,
(uint32)PLAYER_FIELD_MOD_HEALING_DONE_PCT,
(uint32)PLAYER_RUNE_REGEN_1,
(uint32)-1
};
static uint32 floats_gameobject[] =
{
(uint32)GAMEOBJECT_PARENTROTATION,
(uint32)(GAMEOBJECT_PARENTROTATION + 1),
(uint32)(GAMEOBJECT_PARENTROTATION + 2),
(uint32)(GAMEOBJECT_PARENTROTATION + 3),
(uint32)-1
};
static uint32 floats_dynobject[] =
{
(uint32)DYNAMICOBJECT_RADIUS,
(uint32)-1
};
/*
static uint32 floats_corpse[] =
{
(uint32)-1
};
*/
if(ty & TYPE_OBJECT) if(flags & (MOVEMENTFLAG_ONTRANSPORT))
for(uint32 i = 0; floats_object[i] != (uint32)(-1); i++) {
if(floats_object[i] == f) if(_c < CLIENT_WOTLK)
return true; data >> t_guid;
/* else
if(ty & TYPE_ITEM) t_guid =data.readPackGUID();
for(uint32 i = 0; floats_item[i] != (-1); i++) data >> t_pos.x;
if(floats_object[i] == f) data >> t_pos.y;
return true; data >> t_pos.z;
if(ty & TYPE_CONTAINER) data >> t_pos.o;
for(uint32 i = 0; floats_container[i] != (-1); i++) if(_c > CLIENT_CLASSIC_WOW)
if(floats_object[i] == f) data >> t_time;
return true; if(_c > CLIENT_TBC)
*/ data >> t_seat;
if(ty & TYPE_UNIT)
for(uint32 i = 0; floats_unit[i] != (uint32)(-1); i++) if(_c > CLIENT_TBC && flags2 & MOVEMENTFLAG2_INTERP_MOVEMENT)
if(floats_unit[i] == f) data >> t_time2;
return true; }
if(ty & TYPE_PLAYER)
for(uint32 i = 0; floats_player[i] != (uint32)(-1); i++) if((flags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) || (flags2 & MOVEMENTFLAG2_ALLOW_PITCHING))
if(floats_player[i] == f) {
return true; data >> s_angle;
if(ty & TYPE_GAMEOBJECT) }
for(uint32 i = 0; floats_gameobject[i] != (uint32)(-1); i++)
if(floats_gameobject[i] == f) data >> fallTime;
return true;
if(ty & TYPE_DYNAMICOBJECT) if(flags & (MOVEMENTFLAG_FALLING))
for(uint32 i = 0; floats_dynobject[i] != (uint32)(-1); i++) {
if(floats_dynobject[i] == f) data >> j_velocity;
return true; data >> j_sinAngle;
/* data >> j_cosAngle;
if(ty & TYPE_CORPSE) data >> j_xyspeed;
for(uint32 i = 0; floats_corpse[i] != (uint32)(-1); i++) }
if(floats_corpse[i] == f)
return true; if(flags & (MOVEMENTFLAG_SPLINE_ELEVATION))
*/ {
return false; data >> u_unk1;
}
} }
bool IsUInt64Field(uint8 ty, uint32 f) void MovementInfo::Write(ByteBuffer &data) const
{ {
static uint32 u64_object[] = data << flags;
if(_c == CLIENT_WOTLK)
data << flags2;
if(_c == CLIENT_TBC)
{ {
(uint32)OBJECT_FIELD_GUID, data << (uint8)flags2;
(uint32)-1 }
}; data << time;
data << pos.x;
data << pos.y;
data << pos.z;
data << pos.o;
static uint32 u64_item[] = if(flags & (MOVEMENTFLAG_ONTRANSPORT))
{ {
(uint32)ITEM_FIELD_OWNER, if(_c < CLIENT_WOTLK)
(uint32)ITEM_FIELD_CONTAINED, data << t_guid;
(uint32)ITEM_FIELD_CREATOR, else
(uint32)ITEM_FIELD_GIFTCREATOR, data.appendPackGUID(t_guid);
(uint32)-1 data << t_pos.x;
}; data << t_pos.y;
static uint32 u64_container[] = data << t_pos.z;
data << t_pos.o;
if(_c > CLIENT_CLASSIC_WOW)
data << t_time;
if(_c > CLIENT_TBC)
data << t_seat;
if(_c > CLIENT_TBC && flags2 & MOVEMENTFLAG2_INTERP_MOVEMENT)
data << t_time2;
}
if((flags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLYING)) || (flags2 & MOVEMENTFLAG2_ALLOW_PITCHING))
{ {
(uint32)CONTAINER_FIELD_SLOT_1, data << s_angle;
(uint32)-1 }
};
static uint32 u64_unit[] = data << fallTime;
if(flags & (MOVEMENTFLAG_FALLING))
{ {
(uint32)UNIT_FIELD_CHARM, data << j_velocity;
(uint32)UNIT_FIELD_SUMMON, data << j_sinAngle;
(uint32)UNIT_FIELD_CRITTER, data << j_cosAngle;
(uint32)UNIT_FIELD_CHARMEDBY, data << j_xyspeed;
(uint32)UNIT_FIELD_SUMMONEDBY, }
(uint32)UNIT_FIELD_CREATEDBY,
(uint32)UNIT_FIELD_TARGET, if(flags & (MOVEMENTFLAG_SPLINE_ELEVATION))
(uint32)UNIT_FIELD_CHANNEL_OBJECT,
(uint32)-1
};
static uint32 u64_player[] =
{ {
(uint32)PLAYER_DUEL_ARBITER, data << u_unk1;
(uint32)PLAYER_FIELD_INV_SLOT_HEAD, }
(uint32)PLAYER_FIELD_PACK_SLOT_1,
(uint32)PLAYER_FIELD_BANK_SLOT_1,
(uint32)PLAYER_FIELD_BANKBAG_SLOT_1,
(uint32)PLAYER_FIELD_VENDORBUYBACK_SLOT_1,
(uint32)PLAYER_FIELD_KEYRING_SLOT_1,
(uint32)PLAYER_FIELD_CURRENCYTOKEN_SLOT_1,
(uint32)PLAYER_FARSIGHT,
(uint32)PLAYER__FIELD_KNOWN_TITLES,
(uint32)PLAYER__FIELD_KNOWN_TITLES1,
(uint32)PLAYER__FIELD_KNOWN_TITLES2,
(uint32)PLAYER_FIELD_KNOWN_CURRENCIES,
(uint32)-1
};
static uint32 u64_gameobject[] =
{
(uint32)OBJECT_FIELD_CREATED_BY,
(uint32)-1
};
static uint32 u64_dynobject[] =
{
(uint32)DYNAMICOBJECT_CASTER,
(uint32)-1
};
static uint32 u64_corpse[] =
{
(uint32)CORPSE_FIELD_OWNER,
(uint32)CORPSE_FIELD_PARTY,
(uint32)-1
};
if(ty & TYPE_OBJECT)
for(uint32 i = 0; u64_object[i] != (uint32)(-1); i++)
if(u64_object[i] == f)
return true;
if(ty & TYPE_ITEM)
for(uint32 i = 0; u64_item[i] != (uint32)(-1); i++)
if(u64_item[i] == f)
return true;
if(ty & TYPE_CONTAINER)
for(uint32 i = 0; u64_container[i] != (uint32)(-1); i++)
if(u64_container[i] == f)
return true;
if(ty & TYPE_UNIT)
for(uint32 i = 0; u64_unit[i] != (uint32)(-1); i++)
if(u64_unit[i] == f)
return true;
if(ty & TYPE_PLAYER)
for(uint32 i = 0; u64_player[i] != (uint32)(-1); i++)
if(u64_player[i] == f)
return true;
if(ty & TYPE_GAMEOBJECT)
for(uint32 i = 0; u64_gameobject[i] != (uint32)(-1); i++)
if(u64_gameobject[i] == f)
return true;
if(ty & TYPE_DYNAMICOBJECT)
for(uint32 i = 0; u64_dynobject[i] != (uint32)(-1); i++)
if(u64_dynobject[i] == f)
return true;
if(ty & TYPE_CORPSE)
for(uint32 i = 0; u64_corpse[i] != (uint32)(-1); i++)
if(u64_corpse[i] == f)
return true;
return false;
} }

View File

@ -26,78 +26,13 @@ enum OBJECT_UPDATE_FLAGS
UPDATEFLAG_ROTATION = 0x0200 UPDATEFLAG_ROTATION = 0x0200
}; };
enum MovementFlags enum OBJECT_UPDATE_FLAGS_6005 //UPDATEFLAGS with different meaning in 1.12.x
{ {
MOVEMENTFLAG_NONE = 0x00000000, UPDATEFLAG_FULLGUID_6005= 0x0004,//6005 Never used in MaNGOS
MOVEMENTFLAG_FORWARD = 0x00000001, UPDATEFLAG_HIGHGUID_6005= 0x0008,//6005 Never used in MaNGOS
MOVEMENTFLAG_BACKWARD = 0x00000002, UPDATEFLAG_ALL_6005 = 0x0010 //6005
MOVEMENTFLAG_STRAFE_LEFT = 0x00000004,
MOVEMENTFLAG_STRAFE_RIGHT = 0x00000008,
MOVEMENTFLAG_TURN_LEFT = 0x00000010,
MOVEMENTFLAG_TURN_RIGHT = 0x00000020,
MOVEMENTFLAG_PITCH_UP = 0x00000040,
MOVEMENTFLAG_PITCH_DOWN = 0x00000080,
MOVEMENTFLAG_WALK_MODE = 0x00000100, // Walking
MOVEMENTFLAG_ONTRANSPORT = 0x00000200,
MOVEMENTFLAG_LEVITATING = 0x00000400,
MOVEMENTFLAG_ROOT = 0x00000800,
MOVEMENTFLAG_FALLING = 0x00001000,
MOVEMENTFLAG_FALLINGFAR = 0x00002000,
MOVEMENTFLAG_PENDINGSTOP = 0x00004000,
MOVEMENTFLAG_PENDINGSTRAFESTOP = 0x00008000,
MOVEMENTFLAG_PENDINGFORWARD = 0x00010000,
MOVEMENTFLAG_PENDINGBACKWARD = 0x00020000,
MOVEMENTFLAG_PENDINGSTRAFELEFT = 0x00040000,
MOVEMENTFLAG_PENDINGSTRAFERIGHT = 0x00080000,
MOVEMENTFLAG_PENDINGROOT = 0x00100000,
MOVEMENTFLAG_SWIMMING = 0x00200000, // appears with fly flag also
MOVEMENTFLAG_ASCENDING = 0x00400000, // swim up also
MOVEMENTFLAG_DESCENDING = 0x00800000, // swim down also
MOVEMENTFLAG_CAN_FLY = 0x01000000, // can fly in 3.3?
MOVEMENTFLAG_FLYING = 0x02000000, // Actual flying mode
MOVEMENTFLAG_SPLINE_ELEVATION = 0x04000000, // used for flight paths
MOVEMENTFLAG_SPLINE_ENABLED = 0x08000000, // used for flight paths
MOVEMENTFLAG_WATERWALKING = 0x10000000, // prevent unit from falling through water
MOVEMENTFLAG_SAFE_FALL = 0x20000000, // active rogue safe fall spell (passive)
MOVEMENTFLAG_HOVER = 0x40000000
}; };
struct MovementInfo
{
// common
uint32 flags;
uint16 unkFlags;
uint32 time;
float x, y, z, o;
// transport
uint64 t_guid;
float t_x, t_y, t_z, t_o;
uint32 t_time;
uint8 t_seat;
// swimming and unk
float s_angle;
// last fall time
uint32 fallTime;
// jumping
float j_unk, j_sinAngle, j_cosAngle, j_xyspeed;
// spline
float u_unk1;
MovementInfo()
{
flags = time = t_time = fallTime = unkFlags = 0;
t_seat = 0;
x = y = z = o = t_x = t_y = t_z = t_o = s_angle = j_unk = j_sinAngle = j_cosAngle = j_xyspeed = u_unk1 = 0.0f;
t_guid = 0;
}
void SetMovementFlags(uint32 _flags)
{
flags = _flags;
}
};
bool IsFloatField(uint8, uint32);
bool IsUInt64Field(uint8, uint32);
#endif #endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -19,9 +19,6 @@
#ifndef __UPDATEMASK_H #ifndef __UPDATEMASK_H
#define __UPDATEMASK_H #define __UPDATEMASK_H
//#include "UpdateFields.h"
//#include "Errors.h"
class UpdateMask class UpdateMask
{ {
public: public:

View File

@ -2,18 +2,4 @@
#include "WorldPacket.h" #include "WorldPacket.h"
uint64 WorldPacket::GetPackedGuid(void)
{
uint8 mask;
*this >> mask;
uint64 guid=0;
for(uint8 i=0;i<8;i++)
{
if(mask & (1<<i) )
{
*this >> ((uint8*)&guid)[i];
}
}
return guid;
}

View File

@ -13,7 +13,6 @@ public:
WorldPacket(uint16 opcode) { _opcode=opcode; reserve(10); } WorldPacket(uint16 opcode) { _opcode=opcode; reserve(10); }
inline void SetOpcode(uint16 opcode) { _opcode=opcode; } inline void SetOpcode(uint16 opcode) { _opcode=opcode; }
inline uint16 GetOpcode(void) { return _opcode; } inline uint16 GetOpcode(void) { return _opcode; }
uint64 GetPackedGuid(void);
private: private:
uint16 _opcode; uint16 _opcode;

View File

@ -15,6 +15,8 @@
#include "RealmSession.h" #include "RealmSession.h"
#include "WorldSession.h" #include "WorldSession.h"
#include "MemoryDataHolder.h" #include "MemoryDataHolder.h"
#include "MovementInfo.h"
#include "MovementMgr.h"
struct OpcodeHandler struct OpcodeHandler
{ {
@ -22,6 +24,10 @@ struct OpcodeHandler
void (WorldSession::*handler)(WorldPacket& recvPacket); void (WorldSession::*handler)(WorldPacket& recvPacket);
}; };
uint32 Object::maxvalues[TYPEID_MAX];
UpdateField Object::updatefields[UPDATEFIELDS_NAME_COUNT];
uint8 MovementInfo::_c=CLIENT_UNKNOWN;
WorldSession::WorldSession(PseuInstance *in) WorldSession::WorldSession(PseuInstance *in)
{ {
logdebug("-> Starting WorldSession 0x%X from instance 0x%X",this,in); // should never output a null ptr logdebug("-> Starting WorldSession 0x%X from instance 0x%X",this,in); // should never output a null ptr
@ -37,6 +43,9 @@ WorldSession::WorldSession(PseuInstance *in)
_lag_ms = 0; _lag_ms = 0;
//... //...
_SetupObjectFields();
MovementInfo::_c=in->GetConf()->client;
in->GetScripts()->RunScriptIfExists("_onworldsessioncreate"); in->GetScripts()->RunScriptIfExists("_onworldsessioncreate");
DEBUG(logdebug("WorldSession 0x%X constructor finished",this)); DEBUG(logdebug("WorldSession 0x%X constructor finished",this));
@ -520,47 +529,62 @@ std::string WorldSession::GetOrRequestPlayerName(uint64 guid)
void WorldSession::_HandleAuthChallengeOpcode(WorldPacket& recvPacket) void WorldSession::_HandleAuthChallengeOpcode(WorldPacket& recvPacket)
{ {
//Read Packet
uint32 sp, serverseed;
if(GetInstance()->GetConf()->client > CLIENT_TBC)
{
recvPacket >> sp;
}
recvPacket >> serverseed;
// Do stuff with the data
std::string acc = stringToUpper(GetInstance()->GetConf()->accname); std::string acc = stringToUpper(GetInstance()->GetConf()->accname);
uint32 sp;
recvPacket >> sp;
uint32 serverseed;
recvPacket >> serverseed;
logdebug("Auth: serverseed=0x%X",serverseed); logdebug("Auth: serverseed=0x%X",serverseed);
Sha1Hash digest; Sha1Hash digest;
digest.UpdateData(acc); digest.UpdateData(acc);
uint32 unk=0; uint32 unk=0;
uint64 unk64=0; uint64 unk64=0;
digest.UpdateData((uint8*)&unk,sizeof(uint32)); digest.UpdateData((uint8*)&unk,sizeof(uint32));
BigNumber clientseed; BigNumber clientseed;
clientseed.SetRand(8*4); clientseed.SetRand(8*4);
uint32 clientseed_uint32=clientseed.AsDword(); uint32 clientseed_uint32=clientseed.AsDword();
digest.UpdateData((uint8*)&clientseed_uint32,sizeof(uint32)); digest.UpdateData((uint8*)&clientseed_uint32,sizeof(uint32));
digest.UpdateData((uint8*)&serverseed,sizeof(uint32)); digest.UpdateData((uint8*)&serverseed,sizeof(uint32));
digest.UpdateBigNumbers(GetInstance()->GetSessionKey(),NULL); digest.UpdateBigNumbers(GetInstance()->GetSessionKey(),NULL);
digest.Finalize(); digest.Finalize();
WorldPacket auth;
auth<<(uint32)(GetInstance()->GetConf()->clientbuild)<<unk<<acc<<unk<<clientseed_uint32<<unk<<unk<<unk<<unk64;
auth.append(digest.GetDigest(),20);
auth << (uint32)0; // TODO: this is not correct value, expected: 160 bytes of addon_data
auth.SetOpcode(CMSG_AUTH_SESSION); // Send Reply
WorldPacket auth;
if(GetInstance()->GetConf()->client<=CLIENT_TBC)
{
auth<<(uint32)(GetInstance()->GetConf()->clientbuild)<<unk<<acc<<clientseed_uint32;
auth.append(digest.GetDigest(),20);
}
else
{
auth<<(uint32)(GetInstance()->GetConf()->clientbuild)<<unk<<acc<<unk<<clientseed_uint32<<unk<<unk<<unk<<unk64;
auth.append(digest.GetDigest(),20);
}
auth << (uint32)0; // TODO: this is not correct value, expected: 160 bytes of addon_data
auth.SetOpcode(CMSG_AUTH_SESSION);
SendWorldPacket(auth); SendWorldPacket(auth);
// note that if the sessionkey/auth is wrong or failed, the server sends the following packet UNENCRYPTED! // note that if the sessionkey/auth is wrong or failed, the server sends the following packet UNENCRYPTED!
// so its not 100% correct to init the crypt here, but it should do the job if authing was correct // so its not 100% correct to init the crypt here, but it should do the job if authing was correct
_socket->InitCrypt(GetInstance()->GetSessionKey()); _socket->InitCrypt(GetInstance()->GetSessionKey());
} }
void WorldSession::_HandleAuthResponseOpcode(WorldPacket& recvPacket) void WorldSession::_HandleAuthResponseOpcode(WorldPacket& recvPacket)
{ {
uint8 errcode; uint8 errcode;
uint8 dummy8, expansion; uint32 dummy32; uint8 BillingPlanFlags, expansion; uint32 BillingTimeRemaining, BillingTimeRested;
recvPacket >> errcode; recvPacket >> errcode;
recvPacket >> dummy32 >> dummy8 >> dummy32; recvPacket >> BillingTimeRemaining >> BillingPlanFlags >> BillingTimeRested;
recvPacket >> expansion; if(GetInstance()->GetConf()->client > CLIENT_CLASSIC_WOW)
recvPacket >> expansion;
// TODO: add data to generic_text.scp and use the strings here // TODO: add data to generic_text.scp and use the strings here
if(errcode == AUTH_OK) if(errcode == AUTH_OK)
{ {
@ -570,7 +594,7 @@ void WorldSession::_HandleAuthResponseOpcode(WorldPacket& recvPacket)
} }
else else
{ {
logerror("World Authentication failed, errcode=0x%X",(unsigned char)errcode); logerror("World Authentication failed, errcode=0x%X",(uint8)errcode);
SetMustDie(); SetMustDie();
} }
} }
@ -604,11 +628,11 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket)
recvPacket >> plr[i]._race; recvPacket >> plr[i]._race;
recvPacket >> plr[i]._class; recvPacket >> plr[i]._class;
recvPacket >> plr[i]._gender; recvPacket >> plr[i]._gender;
recvPacket >> plr[i]._bytes1; recvPacket >> plr[i]._bytes1;//skin
recvPacket >> plr[i]._bytes2; recvPacket >> plr[i]._bytes2;//face
recvPacket >> plr[i]._bytes3; recvPacket >> plr[i]._bytes3;//hair style
recvPacket >> plr[i]._bytes4; recvPacket >> plr[i]._bytes4;//hair color
recvPacket >> plr[i]._bytesx; recvPacket >> plr[i]._bytesx;//facial hair
recvPacket >> plr[i]._level; recvPacket >> plr[i]._level;
recvPacket >> plr[i]._zoneId; recvPacket >> plr[i]._zoneId;
recvPacket >> plr[i]._mapId; recvPacket >> plr[i]._mapId;
@ -617,14 +641,21 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket)
recvPacket >> plr[i]._z; recvPacket >> plr[i]._z;
recvPacket >> plr[i]._guildId; recvPacket >> plr[i]._guildId;
recvPacket >> plr[i]._flags; recvPacket >> plr[i]._flags;
recvPacket >> dummy32; // at_login_customize if(GetInstance()->GetConf()->client > CLIENT_TBC)
{
recvPacket >> dummy32; // at_login_customize
}
recvPacket >> dummy8; recvPacket >> dummy8;
recvPacket >> plr[i]._petInfoId; recvPacket >> plr[i]._petInfoId;
recvPacket >> plr[i]._petLevel; recvPacket >> plr[i]._petLevel;
recvPacket >> plr[i]._petFamilyId; recvPacket >> plr[i]._petFamilyId;
for(unsigned int inv=0;inv<20;inv++) for(unsigned int inv=0;inv<20;inv++)
{ {
recvPacket >> plr[i]._items[inv].displayId >> plr[i]._items[inv].inventorytype >> dummy32; recvPacket >> plr[i]._items[inv].displayId >> plr[i]._items[inv].inventorytype ;
if(GetInstance()->GetConf()->client > CLIENT_CLASSIC_WOW)
{
recvPacket >> dummy32; //enchant aura id
}
} }
plrNameCache.Add(plr[i]._guid, plr[i]._name); // TODO: set after loadingscreen, after loading cache plrNameCache.Add(plr[i]._guid, plr[i]._name); // TODO: set after loadingscreen, after loading cache
@ -811,7 +842,7 @@ void WorldSession::_HandleAccountDataMD5Opcode(WorldPacket& recvPacket)
// packet structure not yet known // packet structure not yet known
} }
void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket) void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket) //TODO: REWRITE ME!!!
{ {
uint8 type, chatTag; uint8 type, chatTag;
uint32 lang; uint32 lang;
@ -826,9 +857,11 @@ void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket)
if(lang == LANG_ADDON && GetInstance()->GetConf()->skipaddonchat) if(lang == LANG_ADDON && GetInstance()->GetConf()->skipaddonchat)
return; return;
if(GetInstance()->GetConf()->client > CLIENT_CLASSIC_WOW)
recvPacket >> source_guid; {
recvPacket >> unk32; recvPacket >> source_guid;
recvPacket >> unk32;
}
switch(type) switch(type)
{ {
@ -1016,13 +1049,19 @@ void WorldSession::_HandleNotificationOpcode(WorldPacket& recvPacket)
void WorldSession::_HandleNameQueryResponseOpcode(WorldPacket& recvPacket) void WorldSession::_HandleNameQueryResponseOpcode(WorldPacket& recvPacket)
{ {
uint64 pguid; uint64 pguid;
uint8 unk; uint8 realm;
std::string pname; std::string pname;
uint32 prace, pgender, pclass;
pguid = recvPacket.GetPackedGuid(); if(GetInstance()->GetConf()->client > CLIENT_CLASSIC_WOW)
recvPacket >> unk >> pname; pguid = recvPacket.readPackGUID();
else
recvPacket >> pguid;
recvPacket >> pname >> realm >> prace >> pgender >> pclass;
if(pname.length()>MAX_PLAYERNAME_LENGTH || pname.length()<MIN_PLAYERNAME_LENGTH) if(pname.length()>MAX_PLAYERNAME_LENGTH || pname.length()<MIN_PLAYERNAME_LENGTH)
{
logerror("Playername Length outside bounds: %u",pname.length());
return; // playernames maxlen=12, minlen=2 return; // playernames maxlen=12, minlen=2
}
// rest of the packet is not interesting for now // rest of the packet is not interesting for now
plrNameCache.Add(pguid,pname); plrNameCache.Add(pguid,pname);
logdetail("CACHE: Assigned new player name: '%s' = " I64FMTD ,pname.c_str(),pguid); logdetail("CACHE: Assigned new player name: '%s' = " I64FMTD ,pname.c_str(),pguid);
@ -1064,26 +1103,25 @@ void WorldSession::_HandleGroupInviteOpcode(WorldPacket& recvPacket)
void WorldSession::_HandleMovementOpcode(WorldPacket& recvPacket) void WorldSession::_HandleMovementOpcode(WorldPacket& recvPacket)
{ {
uint32 flags, time, unk32;
float x, y, z, o;
uint64 guid; uint64 guid;
uint16 flags2; MovementInfo mi;
guid = recvPacket.GetPackedGuid(); guid = recvPacket.readPackGUID();
recvPacket >> flags >> flags2 >> time >> x >> y >> z >> o >> unk32; recvPacket >> mi;
DEBUG(logdebug("MOVE: "I64FMT" -> time=%u flags=0x%X x=%.4f y=%.4f z=%.4f o=%.4f",guid,time,flags,x,y,z,o)); DEBUG(logdebug("MOVE: "I64FMT" -> time=%u flags=0x%X x=%.4f y=%.4f z=%.4f o=%.4f",guid,mi.time,mi.flags,mi.pos.x,mi.pos.y,mi.pos.z,mi.pos.o));
Object *obj = objmgr.GetObj(guid); Object *obj = objmgr.GetObj(guid);
if(obj && obj->IsWorldObject()) if(obj && obj->IsWorldObject())
{ {
((WorldObject*)obj)->SetPosition(x,y,z,o); ((WorldObject*)obj)->SetPosition(mi.pos.x,mi.pos.y,mi.pos.z,mi.pos.o);
} }
//TODO: Eval rest of Packet!!
} }
void WorldSession::_HandleSetSpeedOpcode(WorldPacket& recvPacket) void WorldSession::_HandleSetSpeedOpcode(WorldPacket& recvPacket)
{ {
uint64 guid; uint64 guid;
float x, y, z, o, speed; float speed;
uint32 unk32, movetype; uint32 movetype;
uint16 unk16; MovementInfo mi;
switch(recvPacket.GetOpcode()) switch(recvPacket.GetOpcode())
{ {
@ -1128,19 +1166,15 @@ void WorldSession::_HandleSetSpeedOpcode(WorldPacket& recvPacket)
return; return;
} }
guid = recvPacket.GetPackedGuid(); guid = recvPacket.readPackGUID();
recvPacket >> unk32; recvPacket >> mi;
recvPacket >> unk16;
recvPacket >> unk32; /* getMSTime()*/
recvPacket >> x >> y >> z >> o;
recvPacket >> unk32; // falltime
recvPacket >> speed; recvPacket >> speed;
Object *obj = objmgr.GetObj(guid); Object *obj = objmgr.GetObj(guid);
if(obj && obj->IsUnit()) if(obj && obj->IsUnit())
{ {
((Unit*)obj)->SetSpeed(movetype, speed); ((Unit*)obj)->SetSpeed(movetype, speed);
((Unit*)obj)->SetPosition(x, y, z, o); ((Unit*)obj)->SetPosition(mi.pos.x, mi.pos.y, mi.pos.z, mi.pos.o);
} }
} }
@ -1194,7 +1228,7 @@ void WorldSession::_HandleForceSetSpeedOpcode(WorldPacket& recvPacket)
return; return;
} }
guid = recvPacket.GetPackedGuid(); guid = recvPacket.readPackGUID();
recvPacket >> unk32; recvPacket >> unk32;
if (movetype == MOVE_RUN) if (movetype == MOVE_RUN)
recvPacket >> unk8; recvPacket >> unk8;
@ -1209,47 +1243,44 @@ void WorldSession::_HandleForceSetSpeedOpcode(WorldPacket& recvPacket)
void WorldSession::_HandleTelePortAckOpcode(WorldPacket& recvPacket) void WorldSession::_HandleTelePortAckOpcode(WorldPacket& recvPacket)
{ {
uint32 unk32,time, flags; // movement flags uint32 unk32;
uint64 guid; uint64 guid;
uint16 unk16; MovementInfo mi;
float x, y, z, o; guid = recvPacket.readPackGUID();
recvPacket >> unk32 >> mi;
guid = recvPacket.GetPackedGuid(); logdetail("Got teleported, data: x: %f, y: %f, z: %f, o: %f, guid: "I64FMT, mi.pos.x, mi.pos.y, mi.pos.z, mi.pos.o, guid);
recvPacket >> unk32 >> flags >> unk16 >> time >> x >> y >> z >> o >> unk32;
logdetail("Got teleported, data: x: %f, y: %f, z: %f, o: %f, guid: "I64FMT, x, y, z, o, guid); _world->UpdatePos(mi.pos.x,mi.pos.y);
WorldPacket wp(MSG_MOVE_TELEPORT_ACK,8+4+4);
//GUID must be packed!
wp.appendPackGUID(guid);
wp << (uint32)0 << (uint32)getMSTime();
SendWorldPacket(wp);
// TODO: put this into a capsule class later, that autodetects movement flags etc.
WorldPacket response(MSG_MOVE_FALL_LAND,4+2+4+4+4+4+4+4);
response.appendPackGUID(guid);
response << uint32(0) << (uint16)0 << (uint32)getMSTime(); //flags and flags2
response << x << y << z << o << uint32(100); // simulate 100 msec fall time
SendWorldPacket(response);
_world->UpdatePos(x,y);
_world->Update(); _world->Update();
if(MyCharacter *my = GetMyChar()) if(MyCharacter *my = GetMyChar())
{ {
my->SetPosition(x,y,z,o); my->SetPosition(mi.pos.x,mi.pos.y,mi.pos.z,mi.pos.o);
} }
WorldPacket wp(MSG_MOVE_TELEPORT_ACK,8+4+4);
if(GetInstance()->GetConf()->client > CLIENT_TBC)
wp.appendPackGUID(guid); //GUID must be packed!
else
wp << guid;
wp << (uint32)0 << (uint32)getMSTime(); //First value is some counter
SendWorldPacket(wp);
_world->GetMoveMgr()->SetFallTime(100);
_world->GetMoveMgr()->MoveFallLand();
if(GetInstance()->GetScripts()->ScriptExists("_onteleport")) if(GetInstance()->GetScripts()->ScriptExists("_onteleport"))
{ {
CmdSet Set; CmdSet Set;
Set.defaultarg = "false"; // teleported to other map = false Set.defaultarg = "false"; // teleported to other map = false
Set.arg[0] = DefScriptTools::toString(guid); Set.arg[0] = DefScriptTools::toString(guid);
Set.arg[1] = DefScriptTools::toString(x); Set.arg[1] = DefScriptTools::toString(mi.pos.x);
Set.arg[2] = DefScriptTools::toString(y); Set.arg[2] = DefScriptTools::toString(mi.pos.y);
Set.arg[3] = DefScriptTools::toString(z); Set.arg[3] = DefScriptTools::toString(mi.pos.z);
Set.arg[4] = DefScriptTools::toString(o); Set.arg[4] = DefScriptTools::toString(mi.pos.o);
Set.arg[5] = DefScriptTools::toString(flags); Set.arg[5] = DefScriptTools::toString(mi.flags);
GetInstance()->GetScripts()->RunScriptIfExists("_onteleport"); GetInstance()->GetScripts()->RunScriptIfExists("_onteleport");
} }
} }
@ -1276,12 +1307,6 @@ void WorldSession::_HandleNewWorldOpcode(WorldPacket& recvPacket)
wp << GetGuid(); wp << GetGuid();
SendWorldPacket(wp); SendWorldPacket(wp);
// TODO: put this into a capsule class later, that autodetects movement flags etc.
WorldPacket response(MSG_MOVE_FALL_LAND,4+2+4+4+4+4+4+4);
response << uint32(0) << (uint16)0; // no flags; unk
response <<(uint32)getMSTime(); // time correct?
response << x << y << z << o << uint32(100); // simulate 100 msec fall time
SendWorldPacket(response);
@ -1298,6 +1323,9 @@ void WorldSession::_HandleNewWorldOpcode(WorldPacket& recvPacket)
my->SetPosition(x,y,z,o,mapid); my->SetPosition(x,y,z,o,mapid);
} }
_world->GetMoveMgr()->SetFallTime(100);
_world->GetMoveMgr()->MoveFallLand();//Must be sent after character was set to new position
// TODO: need to switch to SCENESTATE_LOGINSCREEN here, and after everything is loaded, back to SCENESTATE_WORLD // TODO: need to switch to SCENESTATE_LOGINSCREEN here, and after everything is loaded, back to SCENESTATE_WORLD
if(GetInstance()->GetScripts()->ScriptExists("_onteleport")) if(GetInstance()->GetScripts()->ScriptExists("_onteleport"))
@ -1333,7 +1361,7 @@ void WorldSession::_HandleCastSuccessOpcode(WorldPacket& recvPacket)
uint32 spellId; uint32 spellId;
uint64 casterGuid; uint64 casterGuid;
casterGuid = recvPacket.GetPackedGuid(); casterGuid = recvPacket.readPackGUID();
recvPacket >> spellId; recvPacket >> spellId;
if (GetMyChar()->GetGUID() == casterGuid) if (GetMyChar()->GetGUID() == casterGuid)
@ -1351,16 +1379,31 @@ void WorldSession::_HandleCastSuccessOpcode(WorldPacket& recvPacket)
void WorldSession::_HandleInitialSpellsOpcode(WorldPacket& recvPacket) void WorldSession::_HandleInitialSpellsOpcode(WorldPacket& recvPacket)
{ {
uint8 unk; uint8 unk;
uint16 spellslot,count; uint16 not_spellslot,count,spellid16;
uint32 spellid; uint32 spellid;
recvPacket >> unk >> count; recvPacket >> unk >> count;
logdebug("Got initial spells list, %u spells.",count); logdebug("Got initial spells list, %u spells.",count);
for(uint16 i = 0; i < count; i++) if(GetInstance()->GetConf()->client > CLIENT_TBC)
{ {
recvPacket >> spellid >> spellslot; for(uint16 i = 0; i < count; i++)
logdebug("Initial Spell: id=%u slot=%u",spellid,spellslot); {
GetMyChar()->AddSpell(spellid, spellslot); recvPacket >> spellid >> not_spellslot;
logdebug("Initial Spell: id=%u slot=%u",spellid,not_spellslot);
GetMyChar()->AddSpell(spellid, not_spellslot);
}
} }
else
{
for(uint16 i = 0; i < count; i++)
{
recvPacket >> spellid16 >> not_spellslot;
spellid = spellid16;
logdebug("Initial Spell: id=%u slot=%u",spellid,not_spellslot);
GetMyChar()->AddSpell(spellid, not_spellslot);
}
}
//TODO: Parse packet completely
} }
void WorldSession::_HandleLearnedSpellOpcode(WorldPacket& recvPacket) void WorldSession::_HandleLearnedSpellOpcode(WorldPacket& recvPacket)
@ -1612,7 +1655,7 @@ void WorldSession::_HandleCreatureQueryResponseOpcode(WorldPacket& recvPacket)
CreatureTemplate *ct = new CreatureTemplate(); CreatureTemplate *ct = new CreatureTemplate();
std::string s; std::string s;
//uint32 unk; uint32 unk;
float unkf; float unkf;
ct->entry = entry; ct->entry = entry;
recvPacket >> ct->name; recvPacket >> ct->name;
@ -1620,24 +1663,43 @@ void WorldSession::_HandleCreatureQueryResponseOpcode(WorldPacket& recvPacket)
recvPacket >> s; recvPacket >> s;
recvPacket >> s; recvPacket >> s;
recvPacket >> ct->subname; recvPacket >> ct->subname;
recvPacket >> ct->directions; if(GetInstance()->GetConf()->client > CLIENT_CLASSIC_WOW)
recvPacket >> ct->directions;
recvPacket >> ct->flag1; recvPacket >> ct->flag1;
recvPacket >> ct->type; recvPacket >> ct->type;
recvPacket >> ct->family; recvPacket >> ct->family;
recvPacket >> ct->rank; recvPacket >> ct->rank;
for(uint32 i = 0; i < MAX_KILL_CREDIT; i++) if(GetInstance()->GetConf()->client > CLIENT_CLASSIC_WOW)
recvPacket >> ct->killCredit[i]; {
recvPacket >> ct->displayid_A; if(GetInstance()->GetConf()->client == CLIENT_WOTLK)
recvPacket >> ct->displayid_H; {
recvPacket >> ct->displayid_AF; for(uint32 i = 0; i < MAX_KILL_CREDIT; i++)
recvPacket >> ct->displayid_HF; recvPacket >> ct->killCredit[i];
recvPacket >> unkf; }
recvPacket >> unkf; recvPacket >> ct->displayid_A;
recvPacket >> ct->RacialLeader; recvPacket >> ct->displayid_H;
for(uint32 i = 0; i < 4; i++) recvPacket >> ct->displayid_AF;
recvPacket >> ct->questItems[i]; recvPacket >> ct->displayid_HF;
recvPacket >> ct->movementId; recvPacket >> unkf;
recvPacket >> unkf;
recvPacket >> ct->RacialLeader;
if(GetInstance()->GetConf()->client == CLIENT_WOTLK)
{
for(uint32 i = 0; i < 4; i++)
recvPacket >> ct->questItems[i];
recvPacket >> ct->movementId;
}
}
else
{
recvPacket >> unk;
recvPacket >> ct->PetSpellDataId;
recvPacket >> ct->displayid_A;
ct->displayid_H = ct->displayid_A;
ct->displayid_AF = ct->displayid_A;
ct->displayid_HF = ct->displayid_A;
recvPacket >> ct->civilian;
}
std::stringstream ss; std::stringstream ss;
ss << "Got info for creature " << entry << ":" << ct->name; ss << "Got info for creature " << entry << ":" << ct->name;
if(!ct->subname.empty()) if(!ct->subname.empty())
@ -1673,15 +1735,23 @@ void WorldSession::_HandleGameobjectQueryResponseOpcode(WorldPacket& recvPacket)
recvPacket >> other_names; // name1 recvPacket >> other_names; // name1
recvPacket >> other_names; // name2 recvPacket >> other_names; // name2
recvPacket >> other_names; // name3 (all unused) recvPacket >> other_names; // name3 (all unused)
recvPacket >> unks; if(GetInstance()->GetConf()->client > CLIENT_CLASSIC_WOW)
recvPacket >> go->castBarCaption; {
recvPacket >> go->unk1; recvPacket >> unks;
recvPacket >> go->castBarCaption;
recvPacket >> go->unk1;
}
for(uint32 i = 0; i < GAMEOBJECT_DATA_FIELDS; i++) for(uint32 i = 0; i < GAMEOBJECT_DATA_FIELDS; i++)
recvPacket >> go->raw.data[i]; recvPacket >> go->raw.data[i];
recvPacket >> go->size; if(GetInstance()->GetConf()->client > CLIENT_CLASSIC_WOW)
for(uint32 i = 0; i < 4; i++) {
recvPacket >> go->questItems[i]; recvPacket >> go->size;
if(GetInstance()->GetConf()->client > CLIENT_TBC)
{
for(uint32 i = 0; i < 4; i++)
recvPacket >> go->questItems[i];
}
}
std::stringstream ss; std::stringstream ss;
ss << "Got info for gameobject " << entry << ":" << go->name; ss << "Got info for gameobject " << entry << ":" << go->name;
ss << " type " << go->type; ss << " type " << go->type;
@ -1723,7 +1793,7 @@ void WorldSession::_HandleCharCreateOpcode(WorldPacket& recvPacket)
void WorldSession::_HandleMonsterMoveOpcode(WorldPacket& recvPacket) void WorldSession::_HandleMonsterMoveOpcode(WorldPacket& recvPacket)
{ {
uint64 guid; uint64 guid;
guid = recvPacket.GetPackedGuid(); guid = recvPacket.readPackGUID();
Object* obj = objmgr.GetObj(guid); Object* obj = objmgr.GetObj(guid);
if (!obj || !obj->IsWorldObject()) if (!obj || !obj->IsWorldObject())
@ -1732,7 +1802,10 @@ void WorldSession::_HandleMonsterMoveOpcode(WorldPacket& recvPacket)
uint8 unk, type; uint8 unk, type;
uint32 time, flags, movetime, waypoints; uint32 time, flags, movetime, waypoints;
float x, y, z; float x, y, z;
recvPacket >> unk >> x >> y >> z >> time >> type; if(GetInstance()->GetConf()->client > CLIENT_TBC)
recvPacket >> unk;
recvPacket >> x >> y >> z >> time >> type;
float oldx = ((WorldObject*)obj)->GetX(), float oldx = ((WorldObject*)obj)->GetX(),
oldy = ((WorldObject*)obj)->GetY(); oldy = ((WorldObject*)obj)->GetY();

View File

@ -126,6 +126,7 @@ private:
void _DoTimedActions(void); void _DoTimedActions(void);
void _DelayWorldPacket(WorldPacket&, uint32); void _DelayWorldPacket(WorldPacket&, uint32);
void _HandleDelayedPackets(void); void _HandleDelayedPackets(void);
void _SetupObjectFields(void);
// Opcode Handlers // Opcode Handlers
void _HandleAuthChallengeOpcode(WorldPacket& recvPacket); void _HandleAuthChallengeOpcode(WorldPacket& recvPacket);

View File

@ -4,11 +4,17 @@
#include "WorldSocket.h" #include "WorldSocket.h"
#include "Opcodes.h" #include "Opcodes.h"
WorldSocket::WorldSocket(SocketHandler &h, WorldSession *s) : TcpSocket(h) WorldSocket::WorldSocket(SocketHandler &h, WorldSession *s) : TcpSocket(h)
{ {
_session = s; _session = s;
_gothdr = false; _gothdr = false;
_ok=false; _ok=false;
//Dummy functions for unencrypted packets on WorldSocket
pDecryptRecv = &AuthCrypt::DecryptRecvDummy;
pEncryptSend = &AuthCrypt::EncryptSendDummy;
} }
bool WorldSocket::IsOk(void) bool WorldSocket::IsOk(void)
@ -78,31 +84,43 @@ void WorldSocket::OnRead()
break; break;
} }
// read first byte and check if size is 3 or 2 bytes if(GetSession()->GetInstance()->GetConf()->client > CLIENT_TBC)//Funny, old sources have this in TBC already...
uint8 firstSizeByte;
ibuf.Read((char*)&firstSizeByte, 1);
_crypt.DecryptRecv(&firstSizeByte, 1);
if (firstSizeByte & 0x80) // got large packet
{ {
ServerPktHeaderBig hdr; // read first byte and check if size is 3 or 2 bytes
ibuf.Read(((char*)&hdr) + 1, sizeof(ServerPktHeaderBig) - 1); // read *big* header, except first byte uint8 firstSizeByte;
_crypt.DecryptRecv(((uint8*)&hdr) + 1, sizeof(ServerPktHeaderBig) - 1); // decrypt 2 of 3 bytes (first one already decrypted above) of size, and cmd ibuf.Read((char*)&firstSizeByte, 1);
hdr.size[0] = firstSizeByte; // assign missing first byte (_crypt.*pDecryptRecv)(&firstSizeByte, 1);
if (firstSizeByte & 0x80) // got large packet
{
ServerPktHeaderBig hdr;
ibuf.Read(((char*)&hdr) + 1, sizeof(ServerPktHeaderBig) - 1); // read *big* header, except first byte
(_crypt.*pDecryptRecv)(((uint8*)&hdr) + 1, sizeof(ServerPktHeaderBig) - 1); // decrypt 2 of 3 bytes (first one already decrypted above) of size, and cmd
hdr.size[0] = firstSizeByte; // assign missing first byte
uint32 realsize = ((hdr.size[0]&0x7F) << 16) | (hdr.size[1] << 8) | hdr.size[2]; uint32 realsize = ((hdr.size[0]&0x7F) << 16) | (hdr.size[1] << 8) | hdr.size[2];
_remaining = realsize - 2; _remaining = realsize - 2;
_opcode = hdr.cmd; _opcode = hdr.cmd;
}
else // "normal" packet
{
ServerPktHeader hdr;
ibuf.Read(((char*)&hdr) + 1, sizeof(ServerPktHeader) - 1); // read header, except first byte
(_crypt.*pDecryptRecv)(((uint8*)&hdr) + 1, sizeof(ServerPktHeader) - 1); // decrypt all except first
hdr.size |= firstSizeByte; // add already decrypted first byte
_remaining = ntohs(hdr.size) - 2;
_opcode = hdr.cmd;
}
} }
else // "normal" packet else
{ {
ServerPktHeader hdr; ServerPktHeader hdr;
ibuf.Read(((char*)&hdr) + 1, sizeof(ServerPktHeader) - 1); // read header, except first byte ibuf.Read(((char*)&hdr), sizeof(ServerPktHeader)); // read header
_crypt.DecryptRecv(((uint8*)&hdr) + 1, sizeof(ServerPktHeader) - 1); // decrypt all except first (_crypt.*pDecryptRecv)(((uint8*)&hdr), sizeof(ServerPktHeader)); // decrypt all
hdr.size |= firstSizeByte; // add already decrypted first byte
_remaining = ntohs(hdr.size) - 2;
_opcode = hdr.cmd;
_remaining = ntohs(hdr.size) - 2;
_opcode = hdr.cmd;
} }
if(_opcode > MAX_OPCODE_ID) if(_opcode > MAX_OPCODE_ID)
@ -114,7 +132,6 @@ void WorldSocket::OnRead()
// TODO: invent some way how to recover the crypt (reconnect?) // TODO: invent some way how to recover the crypt (reconnect?)
return; return;
} }
// the header is fine, now check if there are more data // the header is fine, now check if there are more data
if(_remaining == 0) // this is a packet with no data (like CMSG_NULL_ACTION) if(_remaining == 0) // this is a packet with no data (like CMSG_NULL_ACTION)
{ {
@ -138,7 +155,7 @@ void WorldSocket::SendWorldPacket(WorldPacket &pkt)
memset(&hdr,0,sizeof(ClientPktHeader)); memset(&hdr,0,sizeof(ClientPktHeader));
hdr.size = ntohs(pkt.size()+4); hdr.size = ntohs(pkt.size()+4);
hdr.cmd = pkt.GetOpcode(); hdr.cmd = pkt.GetOpcode();
_crypt.EncryptSend((uint8*)&hdr, 6); (_crypt.*pEncryptSend)((uint8*)&hdr, 6);
ByteBuffer final(pkt.size()+6); ByteBuffer final(pkt.size()+6);
final.append((uint8*)&hdr,sizeof(ClientPktHeader)); final.append((uint8*)&hdr,sizeof(ClientPktHeader));
if(pkt.size()) if(pkt.size())
@ -148,7 +165,38 @@ void WorldSocket::SendWorldPacket(WorldPacket &pkt)
void WorldSocket::InitCrypt(BigNumber *k) void WorldSocket::InitCrypt(BigNumber *k)
{ {
_crypt.Init(k); //As crypt
switch(GetSession()->GetInstance()->GetConf()->client)
{
case CLIENT_CLASSIC_WOW:
{
logdebug("Setting Crypt to Build 6005");
pInit = &AuthCrypt::Init_6005;
pDecryptRecv = &AuthCrypt::DecryptRecv_6005;
pEncryptSend = &AuthCrypt::EncryptSend_6005;
break;
}
case CLIENT_TBC:
{
logdebug("Setting Crypt to Build 8606");
pInit = &AuthCrypt::Init_8606;
pDecryptRecv = &AuthCrypt::DecryptRecv_6005;
pEncryptSend = &AuthCrypt::EncryptSend_6005;
break;
}
case CLIENT_WOTLK:
{
logdebug("Setting Crypt to Build 12340");
pInit = &AuthCrypt::Init_12340;
pDecryptRecv = &AuthCrypt::DecryptRecv_12340;
pEncryptSend = &AuthCrypt::EncryptSend_12340;
break;
}
default:
logerror("Error setting up Crypt - will crash now (check conf)");
break;
}
(_crypt.*pInit)(k);
const char *hexstr = k->AsHexStr(); const char *hexstr = k->AsHexStr();
logdebug("WorldSocket: Crypt initialized [%s]",hexstr); logdebug("WorldSocket: Crypt initialized [%s]",hexstr);
OPENSSL_free((void*)hexstr); OPENSSL_free((void*)hexstr);

View File

@ -7,6 +7,7 @@
class WorldSession; class WorldSession;
class BigNumber; class BigNumber;
#if defined( __GNUC__ ) #if defined( __GNUC__ )
#pragma pack(1) #pragma pack(1)
#else #else
@ -60,6 +61,9 @@ public:
private: private:
WorldSession *_session; WorldSession *_session;
AuthCrypt _crypt; AuthCrypt _crypt;
void (AuthCrypt::*pInit)(BigNumber *);
void (AuthCrypt::*pDecryptRecv)(uint8 *, size_t);
void (AuthCrypt::*pEncryptSend)(uint8 *, size_t);
bool _gothdr; // true if only the header was recieved yet bool _gothdr; // true if only the header was recieved yet
uint16 _opcode; // stores the last recieved opcode uint16 _opcode; // stores the last recieved opcode
uint32 _remaining; // bytes amount of the next data packet uint32 _remaining; // bytes amount of the next data packet

View File

@ -215,13 +215,14 @@ bool ADTFile::LoadMem(ByteBuffer& buf)
} }
else if(!strcmp((char*)fourcc,"MCNK")) else if(!strcmp((char*)fourcc,"MCNK"))
{ {
uint32 endpos = buf.rpos()+size;
_chunks[mcnkid].hdr = buf.read<ADTMapChunkHeader>(); _chunks[mcnkid].hdr = buf.read<ADTMapChunkHeader>();
uint8 _cc2[5]; uint8 _cc2[5];
uint8 *mfcc = &_cc2[0]; uint8 *mfcc = &_cc2[0];
mfcc[4]=0; mfcc[4]=0;
uint32 msize; uint32 msize;
bool mcal_compressed = false; bool mcal_compressed = false;
while(buf.rpos()<buf.size()) while(buf.rpos()<endpos)
{ {
buf.read(mfcc,4); flipcc(mfcc); buf.read(mfcc,4); flipcc(mfcc);
buf.read((uint8*)&msize,4); buf.read((uint8*)&msize,4);
@ -363,6 +364,7 @@ bool ADTFile::LoadMem(ByteBuffer& buf)
} }
mcnkid++; mcnkid++;
buf.rpos(endpos);
} }
else else
{ {

View File

@ -30,7 +30,8 @@ AuthCrypt::~AuthCrypt()
} }
void AuthCrypt::Init(BigNumber *K) // 3.3.5
void AuthCrypt::Init_12340(BigNumber *K)
{ {
uint8 ClientDecryptionKey[SEED_KEY_SIZE] = { 0xCC, 0x98, 0xAE, 0x04, 0xE8, 0x97, 0xEA, 0xCA, 0x12, 0xDD, 0xC0, 0x93, 0x42, 0x91, 0x53, 0x57 }; uint8 ClientDecryptionKey[SEED_KEY_SIZE] = { 0xCC, 0x98, 0xAE, 0x04, 0xE8, 0x97, 0xEA, 0xCA, 0x12, 0xDD, 0xC0, 0x93, 0x42, 0x91, 0x53, 0x57 };
HmacHash serverEncryptHmac(SEED_KEY_SIZE, (uint8*)ClientDecryptionKey); HmacHash serverEncryptHmac(SEED_KEY_SIZE, (uint8*)ClientDecryptionKey);
@ -60,7 +61,7 @@ void AuthCrypt::Init(BigNumber *K)
_initialized = true; _initialized = true;
} }
void AuthCrypt::DecryptRecv(uint8 *data, size_t len) void AuthCrypt::DecryptRecv_12340(uint8 *data, size_t len)
{ {
if (!_initialized) if (!_initialized)
return; return;
@ -68,10 +69,84 @@ void AuthCrypt::DecryptRecv(uint8 *data, size_t len)
_decrypt.UpdateData(len, data); _decrypt.UpdateData(len, data);
} }
void AuthCrypt::EncryptSend(uint8 *data, size_t len) void AuthCrypt::EncryptSend_12340(uint8 *data, size_t len)
{ {
if (!_initialized) if (!_initialized)
return; return;
_encrypt.UpdateData(len, data); _encrypt.UpdateData(len, data);
} }
void AuthCrypt::Init_8606(BigNumber *K)
{
uint8 *key = new uint8[SHA_DIGEST_LENGTH];
uint8 recvSeed[SEED_KEY_SIZE] = { 0x38, 0xA7, 0x83, 0x15, 0xF8, 0x92, 0x25, 0x30, 0x71, 0x98, 0x67, 0xB1, 0x8C, 0x4, 0xE2, 0xAA };
HmacHash recvHash(SEED_KEY_SIZE, (uint8*)recvSeed);
recvHash.UpdateBigNumber(K);
recvHash.Finalize();
memcpy(key, recvHash.GetDigest(), SHA_DIGEST_LENGTH);
_key.resize(SHA_DIGEST_LENGTH);
std::copy(key, key + SHA_DIGEST_LENGTH, _key.begin());
delete[] key;
_send_i = _send_j = _recv_i = _recv_j = 0;
_initialized = true;
}
//1.12.2
void AuthCrypt::Init_6005(BigNumber *K)
{
_send_i = _send_j = _recv_i = _recv_j = 0;
SetKey_6005(K->AsByteArray(),40);
_initialized = true;
}
void AuthCrypt::DecryptRecv_6005(uint8 *data, size_t len)
{
if (!_initialized)
return;
if (len < CRYPTED_RECV_LEN_6005)
return;
for (size_t t = 0; t < CRYPTED_RECV_LEN_6005; t++)
{
_recv_i %= _key.size();
uint8 x = (data[t] - _recv_j) ^ _key[_recv_i];
++_recv_i;
_recv_j = data[t];
data[t] = x;
}
}
void AuthCrypt::EncryptSend_6005(uint8 *data, size_t len)
{
if (!_initialized)
return;
if (len < CRYPTED_SEND_LEN_6005)
return;
for (size_t t = 0; t < CRYPTED_SEND_LEN_6005; t++)
{
_send_i %= _key.size();
uint8 x = (data[t] ^ _key[_send_i]) + _send_j;
++_send_i;
data[t] = _send_j = x;
}
}
void AuthCrypt::SetKey_6005(uint8 *key, size_t len)
{
_key.resize(len);
std::copy(key, key + len, _key.begin());
}

View File

@ -30,15 +30,38 @@ class AuthCrypt
AuthCrypt(); AuthCrypt();
~AuthCrypt(); ~AuthCrypt();
void Init(BigNumber *K); //Dummy
void DecryptRecv(uint8 *, size_t); void DecryptRecvDummy(uint8 *, size_t){return;};
void EncryptSend(uint8 *, size_t); void EncryptSendDummy(uint8 *, size_t){return;};
//3.3.5
void Init_12340(BigNumber *K);
void DecryptRecv_12340(uint8 *, size_t);
void EncryptSend_12340(uint8 *, size_t);
//2.4.3
void Init_8606(BigNumber *K);
//1.12.X
void Init_6005(BigNumber *K);
void SetKey_6005(uint8 *, size_t);
void DecryptRecv_6005(uint8 *, size_t);
void EncryptSend_6005(uint8 *, size_t);
bool IsInitialized() { return _initialized; } bool IsInitialized() { return _initialized; }
const static size_t CRYPTED_SEND_LEN_6005 = 6;
const static size_t CRYPTED_RECV_LEN_6005 = 4;
private: private:
bool _initialized;
//3.3.5
SARC4 _decrypt; SARC4 _decrypt;
SARC4 _encrypt; SARC4 _encrypt;
bool _initialized;
//1.12.2
std::vector<uint8> _key;
uint8 _send_i, _send_j, _recv_i, _recv_j;
}; };
#endif #endif

View File

@ -272,6 +272,25 @@ class ByteBuffer
if(buffer.size()) append(buffer.contents(),buffer.size()); if(buffer.size()) append(buffer.contents(),buffer.size());
} }
uint64 readPackGUID()
{
uint64 guid = 0;
uint8 guidmark = 0;
(*this) >> guidmark;
for(int i = 0; i < 8; ++i)
{
if(guidmark & (uint8(1) << i))
{
uint8 bit;
(*this) >> bit;
guid |= (uint64(bit) << (i * 8));
}
}
return guid;
}
void appendPackGUID(uint64 guid) void appendPackGUID(uint64 guid)
{ {
if (_storage.size() < _wpos + sizeof(guid) + 1) if (_storage.size() < _wpos + sizeof(guid) + 1)

View File

@ -18,6 +18,19 @@ void MPQHelper::Init()
std::string ext = ".MPQ"; std::string ext = ".MPQ";
std::string ldir = dir + GetLocale() + "/"; std::string ldir = dir + GetLocale() + "/";
//1.12.X files
_patches.push_front(dir+"base"+ext);
_patches.push_front(dir+"dbc"+ext);
_patches.push_front(dir+"fonts"+ext);
_patches.push_front(dir+"interface"+ext);
_patches.push_front(dir+"misc"+ext);
_patches.push_front(dir+"model"+ext);
_patches.push_front(dir+"sound"+ext);
_patches.push_front(dir+"speech"+ext);
_patches.push_front(dir+"terrain"+ext);
_patches.push_front(dir+"texture"+ext);
_patches.push_front(dir+"wmo"+ext);
// order goes from last opened to first opened file // order goes from last opened to first opened file
// ok maybe this is a bit too much but should work fine :) // ok maybe this is a bit too much but should work fine :)
_patches.push_front(dir+"common"+ext); _patches.push_front(dir+"common"+ext);

View File

@ -1,6 +1,7 @@
#include "common.h" #include "common.h"
#include "MapTile.h" #include "MapTile.h"
#include "log.h" #include "log.h"
#include "MemoryDataHolder.h"
MapTile::MapTile() MapTile::MapTile()
{ {
@ -12,13 +13,6 @@ MapTile::~MapTile()
void MapTile::ImportFromADT(ADTFile *adt) void MapTile::ImportFromADT(ADTFile *adt)
{ {
// strip the path name from the dependency files, just store the plain filename
for(std::vector<std::string>::iterator it = adt->_textures.begin(); it != adt->_textures.end(); it++)
this->_textures.push_back(_PathToFileName(*it));
for(std::vector<std::string>::iterator it = adt->_models.begin(); it != adt->_models.end(); it++)
this->_models.push_back(_PathToFileName(*it));
for(std::vector<std::string>::iterator it = adt->_wmos.begin(); it != adt->_wmos.end(); it++)
this->_wmos.push_back(_PathToFileName(*it));
// import the height map // import the height map
for(uint32 ch=0; ch<CHUNKS_PER_TILE; ch++) for(uint32 ch=0; ch<CHUNKS_PER_TILE; ch++)
@ -53,7 +47,9 @@ void MapTile::ImportFromADT(ADTFile *adt)
for(uint32 ly = 0; ly < adt->_chunks[ch].hdr.nLayers; ly++) for(uint32 ly = 0; ly < adt->_chunks[ch].hdr.nLayers; ly++)
{ {
uint32 texoffs = adt->_chunks[ch].layer[ly].textureId; uint32 texoffs = adt->_chunks[ch].layer[ly].textureId;
_chunks[ch].texlayer.push_back(std::string("data/texture/") + NormalizeFilename(std::string(adt->_textures[texoffs])).c_str()); char fname[255];
MemoryDataHolder::MakeTextureFilename(fname,adt->_textures[texoffs]);
_chunks[ch].texlayer.push_back(fname);
} }
memcpy(_chunks[ch].alphamap, adt->_chunks[ch].alphamap, adt->_chunks[ch].hdr.sizeAlpha - 8); memcpy(_chunks[ch].alphamap, adt->_chunks[ch].alphamap, adt->_chunks[ch].hdr.sizeAlpha - 8);
@ -90,7 +86,9 @@ void MapTile::ImportFromADT(ADTFile *adt)
d.flags = mddf.flags; d.flags = mddf.flags;
d.uniqueid = mddf.uniqueid; d.uniqueid = mddf.uniqueid;
d.MPQpath = adt->_models[mddf.id]; d.MPQpath = adt->_models[mddf.id];
d.model = std::string("./data/model/") + NormalizeFilename(_PathToFileName(adt->_models[mddf.id])); char fname[255];
MemoryDataHolder::MakeModelFilename(fname,adt->_models[mddf.id]);
d.model = fname;
// this .mdx -> .m2 transformation is annoying >.< - replace "mdx" and end of string with "m2" // this .mdx -> .m2 transformation is annoying >.< - replace "mdx" and end of string with "m2"
// d.model = d.model.substr(0, d.model.length() - 3) + "m2"; // d.model = d.model.substr(0, d.model.length() - 3) + "m2";
// 3.1.3 - no more .mdx in ADT // 3.1.3 - no more .mdx in ADT
@ -115,7 +113,9 @@ void MapTile::ImportFromADT(ADTFile *adt)
wmo.flags = modf.flags; wmo.flags = modf.flags;
wmo.uniqueid = modf.uniqueid; wmo.uniqueid = modf.uniqueid;
wmo.MPQpath = adt->_wmos[modf.id]; wmo.MPQpath = adt->_wmos[modf.id];
wmo.model = std::string("./data/wmo/") + NormalizeFilename(_PathToFileName(adt->_wmos[modf.id])); char fname[255];
MemoryDataHolder::MakeWMOFilename(fname,adt->_wmos[modf.id]);
wmo.model = fname;
_wmo_data.push_back(wmo); _wmo_data.push_back(wmo);
} }

View File

@ -1146,7 +1146,7 @@ void FetchTexturesFromModel(ByteBuffer bb)
bb.read((uint8*)&header, sizeof(header)); bb.read((uint8*)&header, sizeof(header));
if (header.version[0] != 8 || header.version[1] != 1 || header.version[2] != 0 || header.version[3] != 0) { if (header.version != 0x108) {
printf("Not M2 model file!"); printf("Not M2 model file!");
return; return;
} }