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 0: Classic WoW 1.12.2 Build 6005
// Client 1: TBC 2.4.3 Build 8606
// Client 2: WoTLK 3.3.5 Build 12340
// Client 3: 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 1: Classic WoW 1.12.2 Build 6005
// Client 2: TBC 2.4.3 Build 8606
// Client 3: WoTLK 3.3.5 Build 12340
// Client 4: Cata 4.x.x Build XXX NOT IMPLEMENTED
Client=0
// Uncomment if you use Client=9
// ClientVersion=3.3.5
// ClientBuild=12340
ClientLanguage=enGB
// or change to enGB, deDE, ...

View File

@ -861,11 +861,11 @@ DefReturnResult DefScriptPackage::SCGetObjectValue(CmdSet &Set)
else
{
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")
return toString(o->GetUInt64Value(v));
return toString(o->GetUInt64Value((UpdateFieldName)v));
else
return toString((uint64)o->GetUInt32Value(v));
return toString((uint64)o->GetUInt32Value((UpdateFieldName)v));
}
}
return "";

View File

@ -1,3 +1,4 @@
// #define _DEBUG 1
#include <iostream>
#include "MemoryDataHolder.h"
#include "MemoryInterface.h"
@ -51,187 +52,288 @@ IAnimatedMesh* CM2MeshFileLoader::createMesh(io::IReadFile* file)
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()
{
DEBUG(logdebug("Trying to open file %s",MeshFile->getFileName()));
MeshFile->read(&header,sizeof(ModelHeader));
if (header.version[0] != 8 || header.version[1] != 1 || header.version[2] != 0 || header.version[3] != 0) {
logerror("M2: [%s] Wrong header! File version doesn't match or file is not a M2 file.",MeshFile->getFileName());
return 0;
}
else
{
DEBUG(logdebug("header okay"));
}
//Name -> not very important I think, but save it nontheless;
//M2MeshName.clear();
//M2MeshName.reserve(header.nameLength);
//file->seek(header.nameOfs);
//file->read(&M2MeshName[0],header.nameLength);
//std::cout << "Read name:"<<M2MeshName.c_str()<<"Size: "<< M2MeshName.size() <<"|"<<M2MeshName[0]<< "\n";
//logger->log("Mesh Name",M2MeshName.c_str(),ELL_INFORMATION);
//Now we load all kinds of data from the file
MeshFile->read(&header,20);
DEBUG(logdebug("M2 Version %X",header.version));
switch(header.version)
{
case 0x100:
case 0x104://HACK
case 0x105://HACK
case 0x106://HACK
case 0x107://HACK
{
MeshFile->read((u8*)&header+20,sizeof(ModelHeader)-20);
ReadVertices();
MeshFile->seek(header.ofsViews);
MeshFile->read(&currentView,sizeof(ModelView));
ReadViewData(MeshFile);
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
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));
// 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));
//Views (skins) == Sets of vertices. Usage yet unknown. Global data
std::string SkinName = MeshFile->getFileName();
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());
if (!SkinFile)
{
logerror("Error! Skin file not found: %s", SkinName.c_str());
return 0;
}
ModelView currentView;
SkinFile->read(&currentView, sizeof(ModelView));
//std::cout << "Skins "<<header.nViews<<" (views)\n";
DEBUG(logdebug("Using View 0 for all further operations"));
DEBUG(logdebug("This View has %u Submeshes",currentView.nSub));
//Vertex indices of a specific view.Local to View 0
if(M2MIndices.size()>0)
M2MIndices.clear();
u16 tempM2Index;
SkinFile->seek(currentView.ofsIndex);
for(u32 i =0;i<currentView.nIndex;i++)
{
SkinFile->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;
SkinFile->seek(currentView.ofsTris);
for(u32 i =0;i<currentView.nTris;i++)
{
SkinFile->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;
SkinFile->seek(currentView.ofsSub);
for(u32 i =0;i<currentView.nSub;i++)
{
SkinFile->read(&tempM2Submesh,sizeof(ModelViewSubmesh));
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();
}
SkinFile->seek(currentView.ofsTex);
for(u32 i=0;i<currentView.nTex;i++)
{
SkinFile->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()));
// std::string SkinName = MeshFile->getFileName();
// 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());
// if (!SkinFile)
// {
// logerror("Error! Skin file not found: %s", SkinName.c_str());
// return 0;
// }
//
// SkinFile->read(&currentView, sizeof(ModelView));
//
// //std::cout << "Skins "<<header.nViews<<" (views)\n";
//
// DEBUG(logdebug("Using View 0 for all further operations"));
// DEBUG(logdebug("This View has %u Submeshes",currentView.nSub));
//
// //Vertex indices of a specific view.Local to View 0
// if(M2MIndices.size()>0)
// M2MIndices.clear();
//
// u16 tempM2Index;
// SkinFile->seek(currentView.ofsIndex);
// for(u32 i =0;i<currentView.nIndex;i++)
// {
// SkinFile->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;
// SkinFile->seek(currentView.ofsTris);
// for(u32 i =0;i<currentView.nTris;i++)
// {
// SkinFile->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;
// SkinFile->seek(currentView.ofsSub);
// for(u32 i =0;i<currentView.nSub;i++)
// {
// SkinFile->read(&tempM2Submesh,sizeof(ModelViewSubmesh));
// 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();
// }
// SkinFile->seek(currentView.ofsTex);
// for(u32 i=0;i<currentView.nTex;i++)
// {
// SkinFile->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()));
//
//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 //
@ -440,6 +542,19 @@ if(M2MBones[i].scaling.header.nValues>0){
}
*/
//std::cout<<AnimatedMesh->getAllJoints()[1]->Children.size()<<" Children\n";
///////////////////////////
// EVERYTHING IS READ
///////////////////////////
//And M2MVertices are not usable like this. Thus we transform
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++)
{
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] << " ";
/* ANIMATION NEED FIX !!!
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<<'\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,(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
{
{
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+="/";
// if(i<M2MTextureUnit.size())
// 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);*/
char buf[1000];
MemoryDataHolder::MakeTextureFilename(buf,M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str());
io::IReadFile* TexFile = io::IrrCreateIReadFileBasic(Device, buf);
// logdebug("Texture %s loading",M2MTextureFiles[M2MTextureLookup[M2MTextureUnit[j].textureIndex]].c_str());
if (!TexFile)
video::ITexture* tex = Device->getVideoDriver()->findTexture(buf);
if(!tex)
{
logerror("CM2MeshFileLoader: Texture file not found: %s", buf);
continue;
}
io::IReadFile* TexFile = io::IrrCreateIReadFileBasic(Device, buf);
// 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());
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));
MeshBuffer->getMaterial().BackfaceCulling=(M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].flags & 0x04)?false:true;
if(M2MRenderFlags[M2MTextureUnit[j].renderFlagsIndex].blending==1)
MeshBuffer->getMaterial().MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL;
}
}
}
MeshBuffer->recalculateBoundingBox();
MeshBuffer->setHardwareMappingHint(EHM_STATIC);
//MeshBuffer->recalculateBoundingBox();
// Mesh->addMeshBuffer(MeshBuffer);
// Mesh->recalculateBoundingBox();
//MeshBuffer->drop();
@ -546,7 +668,7 @@ Device->getSceneManager()->getMeshManipulator()->flipSurfaces(AnimatedMesh); //F
AnimatedMesh->setInterpolationMode(scene::EIM_LINEAR);
SkinFile->drop();
// SkinFile->drop();
M2MTriangles.clear();
M2Vertices.clear();
M2Indices.clear();

View File

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

View File

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

View File

@ -60,7 +60,7 @@ IAnimatedMesh* CWMOMeshFileLoader::createMesh(io::IReadFile* file)
{
char grpfilename[255];
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);
if(!MeshFile)
{
@ -73,7 +73,7 @@ IAnimatedMesh* CWMOMeshFileLoader::createMesh(io::IReadFile* file)
Device->getSceneManager()->getMeshManipulator()->flipSurfaces(Mesh); //Fix inverted surfaces after the rotation
//Does this crash on windows?
Device->getSceneManager()->getMeshManipulator()->recalculateNormals(Mesh,true);//just to be sure
logdev("Complete Mesh contains a total of %u submeshes!",Mesh->getMeshBufferCount());
DEBUG(logdev("Complete Mesh contains a total of %u submeshes!",Mesh->getMeshBufferCount()));
}
else
{
@ -92,24 +92,24 @@ bool CWMOMeshFileLoader::load(bool _root)
u32 size;
u32 textureOffset;
logdev("Trying to open file %s",MeshFile->getFileName());
DEBUG(logdev("Trying to open file %s",MeshFile->getFileName()));
while(MeshFile->getPos() < MeshFile->getSize())
{
MeshFile->read(fourcc,4);
MeshFile->read(&size,4);
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")){
logdev("MVER Chunk: %s",(char*)fourcc);
DEBUG(logdev("MVER Chunk: %s",(char*)fourcc));
MeshFile->seek(size,true);
}
//Start root file parsing
else if(!strcmp((char*)fourcc,"MOHD")){
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
return 0;
}
@ -127,7 +127,7 @@ logdev("Reading Chunk: %s size %u", (char*)fourcc,size);
MeshFile->read(&tempMOMT,sizeof(MOMT_Data));
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.
@ -141,7 +141,7 @@ logdev("Reading Chunk: %s size %u", (char*)fourcc,size);
texNameSize = WMOMTexDefinition[i].endNameIndex-WMOMTexDefinition[i].startNameIndex; tempTexName.resize(texNameSize);
MeshFile->seek(textureOffset+WMOMTexDefinition[i].startNameIndex);
MeshFile->read((void*)tempTexName.c_str(),WMOMTexDefinition[i].endNameIndex-WMOMTexDefinition[i].startNameIndex);
logdev("Texture %u: %s",i,tempTexName.c_str());
DEBUG(logdev("Texture %u: %s",i,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
else if(!strcmp((char*)fourcc,"MOGP")){
logdev("header okay: %s",(char*)fourcc);
DEBUG(logdev("header okay: %s",(char*)fourcc));
MeshFile->seek(68,true);
if(isRootFile)//We should be reading a root file and found a Group header, abort
return 0;
@ -174,7 +174,7 @@ logdev("Reading Chunk: %s size %u", (char*)fourcc,size);
previous_texid=tempMOPY.textureID;
}
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)
@ -187,7 +187,7 @@ logdev("Reading Chunk: %s size %u", (char*)fourcc,size);
MeshFile->read(&tempWMOIndex,sizeof(u16));
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
@ -204,7 +204,7 @@ logdev("Reading Chunk: %s size %u", (char*)fourcc,size);
tempWMOVertex.Z=tempYZ;
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
@ -221,7 +221,7 @@ logdev("Reading Chunk: %s size %u", (char*)fourcc,size);
tempWMONormal.Z=tempYZ;
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
@ -234,7 +234,7 @@ logdev("Reading Chunk: %s size %u", (char*)fourcc,size);
MeshFile->read(&tempWMOMTexcoord,sizeof(core::vector2df));
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!
@ -248,7 +248,7 @@ logdev("Reading Chunk: %s size %u", (char*)fourcc,size);
MeshFile->read(&tempWMOMVertexColor,sizeof(WMOColor));
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
@ -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]);
}
}
logdev("Inserted %u Indices",MeshBuffer->Indices.size());
DEBUG(logdev("Inserted %u Indices",MeshBuffer->Indices.size()));
for(u32 j=0;j<WMOVertices.size();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();
// 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);
char buf[1000];
MemoryDataHolder::MakeTextureFilename(buf,WMOMTextureFiles[WMOMTexData[lastindex].textureID].c_str());
io::IReadFile* TexFile = io::IrrCreateIReadFileBasic(Device, buf);
if (!TexFile)
video::ITexture* tex = Device->getVideoDriver()->findTexture(buf);
if(!tex)
{
logerror("Error! Texture file not found: %s", buf);
continue;
io::IReadFile* TexFile = io::IrrCreateIReadFileBasic(Device, buf);
// 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)
MeshBuffer->getMaterial().MaterialType=video::EMT_TRANSPARENT_ALPHA_CHANNEL;
MeshBuffer->recalculateBoundingBox();
MeshBuffer->setHardwareMappingHint(EHM_STATIC);
}
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
{
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
{
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)
{
scene::IAnimatedMeshSceneNode *doodad = smgr->addAnimatedMeshSceneNode(mesh);
@ -677,6 +684,10 @@ void SceneWorld::UpdateTerrain(void)
_doodads[d->uniqueid] = gp;
}
}
else
{
logerror("No mesh provided");
}
}
}
// create WorldMapObjects (WMOs)
@ -695,14 +706,24 @@ void SceneWorld::UpdateTerrain(void)
{
filename= wmo->model.c_str();
}
// logdebug("loading WMO %s",filename.c_str());
io::IReadFile* modelfile = io::IrrCreateIReadFileBasic(device, filename.c_str());
if (!modelfile)
{
logerror("Error! WMO file not found: %s", wmo->MPQpath.c_str());
continue;
}
scene::IAnimatedMesh *mesh = smgr->getMesh(modelfile);
scene::IAnimatedMesh *mesh;
if(!smgr->getMeshCache()->isMeshLoaded(filename.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
{
mesh = smgr->getMeshCache()->getMeshByFilename(filename.c_str());
}
if(mesh)
{
scene::IAnimatedMeshSceneNode *wmo_node = smgr->addAnimatedMeshSceneNode(mesh);

View File

@ -87,13 +87,27 @@ namespace MemoryDataHolder
}
}
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)
sprintf(fn,"%s",fname.c_str());
else
{
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()
{
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)
{
@ -139,7 +153,7 @@ namespace MemoryDataHolder
delete mb;
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());
// fh.read((char*)mb->ptr, mb->size);
if(!bb.size())
@ -161,7 +175,7 @@ namespace MemoryDataHolder
_storage->Assign(_name, mb);
_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);
}
else
@ -194,7 +208,7 @@ namespace MemoryDataHolder
DoCallbacks(_name, MDH_FILE_ERROR);
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.close();
{
@ -202,7 +216,7 @@ namespace MemoryDataHolder
_storage->Assign(_name, mb);
_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);
}
}
@ -358,14 +372,14 @@ namespace MemoryDataHolder
{
if(*refcount > 0)
(*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)
{
refs.Delete(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();
storage.Delete(s);
return true;

View File

@ -54,6 +54,7 @@ namespace MemoryDataHolder
void MakeWDTFilename(char*,uint32,std::string);
void MakeTextureFilename(char*, std::string);
void MakeModelFilename(char*, std::string);
void MakeWMOFilename(char*, 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);

View File

@ -494,11 +494,6 @@ void PseuInstanceConf::ApplyFromVarSet(VarSet &v)
reconnect=atoi(v.Get("RECONNECT").c_str());
realmport=atoi(v.Get("REALMPORT").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");
realmname=v.Get("REALMNAME");
charname=v.Get("CHARNAME");
@ -524,25 +519,25 @@ void PseuInstanceConf::ApplyFromVarSet(VarSet &v)
switch(client)
{
case 0:
case CLIENT_CLASSIC_WOW:
{
clientbuild = 6005;
clientversion_string="1.12.2";
break;
}
case 1:
case CLIENT_TBC:
{
clientbuild = 8606;
clientversion_string="2.4.3";
break;
}
case 2:
case CLIENT_WOTLK:
{
clientbuild = 12340;
clientversion_string="3.3.5";
break;
}
case 3:
case CLIENT_CATA:
default:
{
logerror("Unknown client - check conf");

View File

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

View File

@ -248,9 +248,9 @@ void RealmSession::_HandleRealmList(ByteBuffer& pkt)
std::string realmAddr;
SRealmHeader rh;
uint16 cb = GetInstance()->GetConf()->clientbuild;
uint16 client = GetInstance()->GetConf()->client;
pkt >> rh.cmd >> rh.size >> rh.unknown;
if(cb<=6005)
if(client==CLIENT_CLASSIC_WOW)
{
uint8 count;
pkt >> count;
@ -272,7 +272,7 @@ void RealmSession::_HandleRealmList(ByteBuffer& pkt)
// readout realms
for(uint8 i=0;i<rh.count;i++)
{
if(cb<=6005)
if(client==CLIENT_CLASSIC_WOW)
{
uint32 icon;
pkt >> icon;
@ -539,9 +539,7 @@ void RealmSession::_HandleLogonChallenge(ByteBuffer& pkt)
packet.append(M1hash.GetDigest(),M1hash.GetLength());
packet.append(crc_hash,20);
packet << (uint8)0; // number of keys = 0
if(GetInstance()->GetConf()->clientbuild > 5302)
packet << (uint8)0; // 1.11.x compatibility (needs one more 0)
packet << (uint8)0; // 1.11.x compatibility (needs one more 0)
GetInstance()->SetSessionKey(_key);
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)
{
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)
{
logerror("AUTH_LOGON_PROOF: Recieved incorrect/unknown packet. Hexdump:");
@ -612,7 +610,7 @@ void RealmSession::_HandleLogonProof(ByteBuffer& pkt)
sAuthLogonProof_S lp;
if(GetInstance()->GetConf()->clientbuild<=6005)
if(GetInstance()->GetConf()->client==CLIENT_CLASSIC_WOW)
{
sAuthLogonProof_S_6005 lp6005;
pkt.read((uint8*)&lp6005, sizeof(sAuthLogonProof_S_6005));

View File

@ -2,13 +2,13 @@
Bag::Bag() : Item()
{
_type |= TYPE_CONTAINER;
_typeid = TYPEID_CONTAINER;
_valuescount = CONTAINER_END;
_slot = 0;
}
void Bag::Create(uint64 guid)
{
Item::Create(guid);
}
_type |= TYPE_CONTAINER;
_typeid = TYPEID_CONTAINER;
_valuescount = Object::maxvalues[_typeid];
_slot = 0;
}
void Bag::Create(uint64 guid)
{
Item::Create(guid);
}

View File

@ -81,9 +81,12 @@ void Channel::Join(std::string channel, std::string password)
// Send join channel request
WorldPacket worldPacket;
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
worldPacket << (uint8)0; // unk
worldPacket << (uint8)0; // unk, new since 2.2.x
if(_worldSession->GetInstance()->GetConf()->client > CLIENT_CLASSIC_WOW)
{
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;
_worldSession->SendWorldPacket(worldPacket);
}

View File

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

View File

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

View File

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

View File

@ -1,5 +1,4 @@
#include "WorldSession.h"
#include "UpdateFields.h"
#include "Item.h"
#include "Bag.h"
@ -18,7 +17,10 @@ void WorldSession::_HandleItemQuerySingleResponseOpcode(WorldPacket& recvPacket)
proto->Id = ItemID;
recvPacket >> proto->Class;
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 >> unk8;
recvPacket >> unk8;
@ -132,7 +134,7 @@ Item::Item()
_type |= TYPE_ITEM;
_typeid = TYPEID_ITEM;
_valuescount = ITEM_END;
_valuescount = Object::maxvalues[_typeid];
_slot = 0;
//_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.h Item.h ObjMgr.cpp UpdateData.cpp WorldSession.h\
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
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);
MemoryDataHolder::Delete(buf);
ADTFile *adt = new ADTFile();
adt->LoadMem(bb);
logdebug("MAPMGR: Loaded ADT '%s'",buf);
MapTile *tile = new MapTile();
tile->ImportFromADT(adt);
if(adt->LoadMem(bb))
{
logdebug("MAPMGR: Loaded ADT '%s'",buf);
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;
_tiles->SetTile(tile,gx,gy);
logdebug("MAPMGR: Imported MapTile (%u, %u) for map %u",gx,gy,m);
}
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 "MovementMgr.h"
#include "Player.h"
#include "MovementInfo.h"
MovementMgr::MovementMgr()
{
@ -33,32 +34,18 @@ void MovementMgr::SetInstance(PseuInstance *inst)
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
wp->appendPackGUID(_mychar->GetGUID());
*wp << _moveFlags;
*wp << (uint16)0; // flags2 , safe to set 0 for now (shlainn)
*wp << getMSTime();
*wp << _mychar->GetPosition();
// TODO: transport not yet handled/done
if(_moveFlags & MOVEMENTFLAG_ONTRANSPORT)
{
*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;
}
if(_instance->GetConf()->client > CLIENT_TBC)
wp->appendPackGUID(_mychar->GetGUID());
MovementInfo mi;
mi.SetMovementFlags(_moveFlags);
mi.time = getMSTime();
mi.pos = _mychar->GetPosition();
mi.fallTime = _falltime;
*wp << mi;
// TODO: transport not yet handled/done
// TODO: swimming not yet done
// TODO: jumping not done yet
// TODO: spline not yet done
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);
_moved = true;
_optime = getMSTime();
_falltime = 0; //HACK!!!!
}
@ -171,6 +160,12 @@ void MovementMgr::MoveStop(void)
_BuildPacket(MSG_MOVE_STOP);
}
void MovementMgr::MoveFallLand(void)
{
Update(true);
_BuildPacket(MSG_MOVE_FALL_LAND);
}
void MovementMgr::MoveStartForward(void)
{
if(_moveFlags & MOVEMENTFLAG_FORWARD)

View File

@ -2,7 +2,7 @@
#define MOVEMENTMGR_H
#include "common.h"
#include "UpdateData.h"
#include "MovementInfo.h"
#define MOVE_HEARTBEAT_DELAY 500
#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 IsWalking(void); // walking straight forward/backward?
bool IsStrafing(void); // strafing left/right?
inline void SetFallTime(uint32 falltime){_falltime = falltime; }
private:
@ -71,6 +71,7 @@ private:
uint8 _movemode; // automatic or manual
float _movespeed; // current xy movement speed
float _jumptime;
uint32 _falltime;
UnitMoveType _movetype; // index used for speed selection
bool _moved;

View File

@ -9,7 +9,7 @@ Object::Object()
_uint32values=NULL;
_type=TYPE_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()
@ -110,7 +110,9 @@ void WorldSession::_HandleDestroyObjectOpcode(WorldPacket& recvPacket)
uint64 guid;
uint8 dummy;
recvPacket >> guid >> dummy;
recvPacket >> guid;
if(GetInstance()->GetConf()->client > CLIENT_TBC)
recvPacket >> dummy;
logdebug("Destroy Object "I64FMT,guid);
// call script just before object removal

View File

@ -7,6 +7,14 @@
#include "HelperDefs.h"
#include "World.h"
struct UpdateField
{
UpdateField(){};
UpdateField(uint16 o, uint16 t):offset(o),type(t){};
uint16 offset;
uint16 type;
};
enum TYPE
{
TYPE_OBJECT = 1,
@ -32,16 +40,17 @@ enum TYPEID
TYPEID_DYNAMICOBJECT = 6,
TYPEID_CORPSE = 7,
TYPEID_AIGROUP = 8,
TYPEID_AREATRIGGER = 9
TYPEID_AREATRIGGER = 9,
TYPEID_MAX
};
class Object
{
public:
virtual ~Object();
inline const uint64 GetGUID() const { return GetUInt64Value(0); }
inline const uint32 GetGUIDLow() const { return GetUInt32Value(0); }
inline const uint32 GetGUIDHigh() const { return GetUInt32Value(1); }
inline const uint64 GetGUID() const { return GetUInt64Value(OBJECT_FIELD_GUID); }
inline const uint32 GetGUIDLow() const { return GetUInt32Value(OBJECT_FIELD_GUID_LOW); }
inline const uint32 GetGUIDHigh() const { return GetUInt32Value(OBJECT_FIELD_GUID_HIGH); }
inline uint32 GetEntry() const { return GetUInt32Value(OBJECT_FIELD_ENTRY); }
inline uint16 GetValuesCount(void) { return _valuescount; }
@ -57,35 +66,39 @@ public:
inline bool IsDynObject(void) { return _typeid == TYPEID_DYNAMICOBJECT; } // 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 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; }
@ -93,13 +106,16 @@ public:
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);
inline bool _IsDepleted(void) { return _depleted; }
inline void _SetDepleted(void) { _depleted = true; }
static uint32 maxvalues[];
static UpdateField updatefields[];
protected:
Object();
void _InitValues(void);
@ -114,8 +130,10 @@ protected:
uint8 _typeid;
std::string _name;
bool _depleted : 1; // true if the object was deleted from the objmgr, but not from memory
};
class WorldObject : public Object
{
public:
@ -145,17 +163,8 @@ protected:
inline uint32 GetValuesCountByTypeId(uint8 tid)
{
switch(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;
}
if(tid < TYPEID_MAX)
return Object::maxvalues[tid];
return 0;
}

View File

@ -13,7 +13,7 @@ Player::Player() : Unit()
{
_type |= TYPE_PLAYER;
_typeid = TYPEID_PLAYER;
_valuescount = PLAYER_END;
_valuescount = Object::maxvalues[_typeid];
}
void Player::Create(uint64 guid)
@ -71,4 +71,4 @@ uint16 MyCharacter::GetSpellSlot(uint32 spellid)
if(i->id == spellid)
return i->slot;
return 0;
}
}

View File

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

View File

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

View File

@ -2,7 +2,6 @@
#include "ZCompressor.h"
#include "WorldSession.h"
#include "UpdateData.h"
#include "UpdateFields.h"
#include "Object.h"
#include "Unit.h"
#include "Bag.h"
@ -11,6 +10,7 @@
#include "DynamicObject.h"
#include "ObjMgr.h"
#include "UpdateMask.h"
#include "MovementInfo.h"
void WorldSession::_HandleCompressedUpdateObjectOpcode(WorldPacket& recvPacket)
@ -37,11 +37,13 @@ void WorldSession::_HandleCompressedUpdateObjectOpcode(WorldPacket& recvPacket)
void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
{
uint8 utype;
//uint8 hasTransport;
uint8 hasTransport;
uint32 usize, ublocks, readblocks=0;
uint64 uguid;
recvPacket >> ublocks; // >> hasTransport;
//logdev("UpdateObject: blocks = %u, hasTransport = %u", ublocks, hasTransport);
if(GetInstance()->GetConf()->client <= CLIENT_TBC)
recvPacket >> hasTransport;
logdev("UpdateObject: blocks = %u", ublocks);
while((recvPacket.rpos() < recvPacket.size())&& (readblocks < ublocks))
{
@ -50,7 +52,7 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
{
case UPDATETYPE_VALUES:
{
uguid = recvPacket.GetPackedGuid();
uguid = recvPacket.readPackGUID();
_ValuesUpdate(uguid,recvPacket);
}
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_OBJECT: // will be sent on any other object creation
{
uguid = recvPacket.GetPackedGuid();
uguid = recvPacket.readPackGUID();
uint8 objtypeid;
recvPacket >> objtypeid;
logdebug("Create Object type %u with guid "I64FMT,objtypeid,uguid);
@ -127,6 +129,7 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
Unit *unit = new Unit();
unit->Create(uguid);
objmgr.Add(unit);
logdebug("Created Unit with guid "I64FMT,uguid);
break;
}
case TYPEID_PLAYER:
@ -136,6 +139,7 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
Player *player = new Player();
player->Create(uguid);
objmgr.Add(player);
logdebug("Created Player with guid "I64FMT,uguid);
break;
}
case TYPEID_GAMEOBJECT:
@ -143,6 +147,7 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
GameObject *go = new GameObject();
go->Create(uguid);
objmgr.Add(go);
logdebug("Created GO with guid "I64FMT,uguid);
break;
}
case TYPEID_CORPSE:
@ -150,6 +155,7 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
Corpse *corpse = new Corpse();
corpse->Create(uguid);
objmgr.Add(corpse);
logdebug("Created Corpse with guid "I64FMT,uguid);
break;
}
case TYPEID_DYNAMICOBJECT:
@ -157,6 +163,7 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
DynamicObject *dobj = new DynamicObject();
dobj->Create(uguid);
objmgr.Add(dobj);
logdebug("Created DynObj with guid "I64FMT,uguid);
break;
}
}
@ -180,6 +187,7 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
Set.defaultarg = toString(uguid);
Set.arg[0] = toString(objtypeid);
GetInstance()->GetScripts()->RunScript("_onobjectcreate", &Set);
}
// if our own character got finally created, we have successfully entered the world,
@ -192,7 +200,7 @@ void WorldSession::_HandleUpdateObjectOpcode(WorldPacket& recvPacket)
recvPacket >> usize;
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);
// 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
uint16 flags;
uint8 flags_6005;
// 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;
uint16 client = GetInstance()->GetConf()->client;
Object *obj = (Object*)objmgr.GetObj(uguid, true); // also depleted objects
Unit *u = NULL;
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);
}
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?)
if(flags & UPDATEFLAG_LIVING)
{
recvPacket >> mi.flags >> mi.unkFlags >> mi.time;
logdev("MovementUpdate: TypeID=%u GUID="I64FMT" pObj=%X flags=%u mi.flags=%u",objtypeid,uguid,obj,flags,mi.flags);
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);
recvPacket >> mi;
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);
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)
{
mi.t_guid = recvPacket.GetPackedGuid();
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);
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);
}
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);
}
recvPacket >> mi.fallTime;
logdev("MovementUpdate: FallTime = %u", mi.fallTime);
if(mi.flags & MOVEMENTFLAG_FALLING)
{
recvPacket >> mi.j_unk >> 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);
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);
}
if(mi.flags & MOVEMENTFLAG_SPLINE_ELEVATION)
{
recvPacket >> 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 >> speedWalkBack >> speedFly >> speedFlyBack >> speedTurn; // fly added in 2.0.x
recvPacket >> speedPitchRate;
recvPacket >> speedWalk >> speedRun >> speedSwimBack >> speedSwim >> speedWalkBack; // speedRun can also be mounted speed if player is mounted; WalkBack is called RunBack in Mangos
if(client > CLIENT_CLASSIC_WOW)
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);
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_RUN, speedRun);
u->SetSpeed(MOVE_SWIMBACK, speedSwimBack);
@ -329,7 +338,7 @@ void WorldSession::_MovementUpdate(uint8 objtypeid, uint64 uguid, WorldPacket& r
{
if(flags & UPDATEFLAG_POSITION)
{
uint64 pguid = recvPacket.GetPackedGuid();
uint64 pguid = recvPacket.readPackGUID();
float x,y,z,o,sx,sy,sz,so;
recvPacket >> x >> y >> z;
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;
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
// 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
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)
{
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);
}
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);
}
@ -405,8 +421,6 @@ void WorldSession::_ValuesUpdate(uint64 uguid, WorldPacket& recvPacket)
Object *obj = objmgr.GetObj(uguid);
uint8 blockcount,tyid;
uint32 value, masksize, valuesCount;
float fvalue;
uint64 value64;
if(obj)
{
@ -431,7 +445,6 @@ void WorldSession::_ValuesUpdate(uint64 uguid, WorldPacket& recvPacket)
umask.SetMask(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);
// 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
// more correct way if there is the need.
@ -442,25 +455,9 @@ void WorldSession::_ValuesUpdate(uint64 uguid, WorldPacket& recvPacket)
{
if(obj)
{
if(IsFloatField(obj->GetTypeMask(),i))
{
recvPacket >> fvalue;
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);
}
recvPacket >> value;
obj->SetUInt32Value(i, value); //It does not matter what type of value we are setting, just copy the bytes
DEBUG(logdev("%u %u",i,value));
}
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
bool IsFloatField(uint8 ty, uint32 f)
void MovementInfo::Read(ByteBuffer &data)
{
static uint32 floats_object[] =
data >> flags;
if(_c == CLIENT_WOTLK)
data >> flags2;
if(_c == CLIENT_TBC)
{
(uint32)OBJECT_FIELD_SCALE_X,
(uint32)-1
};
/*
static uint32 floats_item[] =
{
(uint32)-1
};
static uint32 floats_container[] =
{
(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
};
*/
uint8 tempFlags2;
data >> tempFlags2;
flags2 = tempFlags2;
}
data >> time;
data >> pos.x;
data >> pos.y;
data >> pos.z;
data >> pos.o;
if(ty & TYPE_OBJECT)
for(uint32 i = 0; floats_object[i] != (uint32)(-1); i++)
if(floats_object[i] == f)
return true;
/*
if(ty & TYPE_ITEM)
for(uint32 i = 0; floats_item[i] != (-1); i++)
if(floats_object[i] == f)
return true;
if(ty & TYPE_CONTAINER)
for(uint32 i = 0; floats_container[i] != (-1); i++)
if(floats_object[i] == f)
return true;
*/
if(ty & TYPE_UNIT)
for(uint32 i = 0; floats_unit[i] != (uint32)(-1); i++)
if(floats_unit[i] == f)
return true;
if(ty & TYPE_PLAYER)
for(uint32 i = 0; floats_player[i] != (uint32)(-1); i++)
if(floats_player[i] == f)
return true;
if(ty & TYPE_GAMEOBJECT)
for(uint32 i = 0; floats_gameobject[i] != (uint32)(-1); i++)
if(floats_gameobject[i] == f)
return true;
if(ty & TYPE_DYNAMICOBJECT)
for(uint32 i = 0; floats_dynobject[i] != (uint32)(-1); i++)
if(floats_dynobject[i] == f)
return true;
/*
if(ty & TYPE_CORPSE)
for(uint32 i = 0; floats_corpse[i] != (uint32)(-1); i++)
if(floats_corpse[i] == f)
return true;
*/
return false;
if(flags & (MOVEMENTFLAG_ONTRANSPORT))
{
if(_c < CLIENT_WOTLK)
data >> t_guid;
else
t_guid =data.readPackGUID();
data >> t_pos.x;
data >> t_pos.y;
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))
{
data >> s_angle;
}
data >> fallTime;
if(flags & (MOVEMENTFLAG_FALLING))
{
data >> j_velocity;
data >> j_sinAngle;
data >> j_cosAngle;
data >> j_xyspeed;
}
if(flags & (MOVEMENTFLAG_SPLINE_ELEVATION))
{
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,
(uint32)-1
};
static uint32 u64_item[] =
data << (uint8)flags2;
}
data << time;
data << pos.x;
data << pos.y;
data << pos.z;
data << pos.o;
if(flags & (MOVEMENTFLAG_ONTRANSPORT))
{
(uint32)ITEM_FIELD_OWNER,
(uint32)ITEM_FIELD_CONTAINED,
(uint32)ITEM_FIELD_CREATOR,
(uint32)ITEM_FIELD_GIFTCREATOR,
(uint32)-1
};
static uint32 u64_container[] =
if(_c < CLIENT_WOTLK)
data << t_guid;
else
data.appendPackGUID(t_guid);
data << t_pos.x;
data << t_pos.y;
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,
(uint32)-1
};
static uint32 u64_unit[] =
data << s_angle;
}
data << fallTime;
if(flags & (MOVEMENTFLAG_FALLING))
{
(uint32)UNIT_FIELD_CHARM,
(uint32)UNIT_FIELD_SUMMON,
(uint32)UNIT_FIELD_CRITTER,
(uint32)UNIT_FIELD_CHARMEDBY,
(uint32)UNIT_FIELD_SUMMONEDBY,
(uint32)UNIT_FIELD_CREATEDBY,
(uint32)UNIT_FIELD_TARGET,
(uint32)UNIT_FIELD_CHANNEL_OBJECT,
(uint32)-1
};
static uint32 u64_player[] =
data << j_velocity;
data << j_sinAngle;
data << j_cosAngle;
data << j_xyspeed;
}
if(flags & (MOVEMENTFLAG_SPLINE_ELEVATION))
{
(uint32)PLAYER_DUEL_ARBITER,
(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;
data << u_unk1;
}
}

View File

@ -26,78 +26,13 @@ enum OBJECT_UPDATE_FLAGS
UPDATEFLAG_ROTATION = 0x0200
};
enum MovementFlags
enum OBJECT_UPDATE_FLAGS_6005 //UPDATEFLAGS with different meaning in 1.12.x
{
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
UPDATEFLAG_FULLGUID_6005= 0x0004,//6005 Never used in MaNGOS
UPDATEFLAG_HIGHGUID_6005= 0x0008,//6005 Never used in MaNGOS
UPDATEFLAG_ALL_6005 = 0x0010 //6005
};
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
#define __UPDATEMASK_H
//#include "UpdateFields.h"
//#include "Errors.h"
class UpdateMask
{
public:

View File

@ -2,18 +2,4 @@
#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); }
inline void SetOpcode(uint16 opcode) { _opcode=opcode; }
inline uint16 GetOpcode(void) { return _opcode; }
uint64 GetPackedGuid(void);
private:
uint16 _opcode;
@ -21,4 +20,4 @@ private:
};
#endif
#endif

View File

@ -15,6 +15,8 @@
#include "RealmSession.h"
#include "WorldSession.h"
#include "MemoryDataHolder.h"
#include "MovementInfo.h"
#include "MovementMgr.h"
struct OpcodeHandler
{
@ -22,6 +24,10 @@ struct OpcodeHandler
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)
{
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;
//...
_SetupObjectFields();
MovementInfo::_c=in->GetConf()->client;
in->GetScripts()->RunScriptIfExists("_onworldsessioncreate");
DEBUG(logdebug("WorldSession 0x%X constructor finished",this));
@ -520,47 +529,62 @@ std::string WorldSession::GetOrRequestPlayerName(uint64 guid)
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);
uint32 sp;
recvPacket >> sp;
uint32 serverseed;
recvPacket >> serverseed;
logdebug("Auth: serverseed=0x%X",serverseed);
Sha1Hash digest;
digest.UpdateData(acc);
uint32 unk=0;
uint64 unk64=0;
digest.UpdateData((uint8*)&unk,sizeof(uint32));
BigNumber clientseed;
clientseed.SetRand(8*4);
uint32 clientseed_uint32=clientseed.AsDword();
digest.UpdateData((uint8*)&clientseed_uint32,sizeof(uint32));
digest.UpdateData((uint8*)&serverseed,sizeof(uint32));
digest.UpdateBigNumbers(GetInstance()->GetSessionKey(),NULL);
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
logdebug("Auth: serverseed=0x%X",serverseed);
Sha1Hash digest;
digest.UpdateData(acc);
uint32 unk=0;
uint64 unk64=0;
digest.UpdateData((uint8*)&unk,sizeof(uint32));
BigNumber clientseed;
clientseed.SetRand(8*4);
uint32 clientseed_uint32=clientseed.AsDword();
digest.UpdateData((uint8*)&clientseed_uint32,sizeof(uint32));
digest.UpdateData((uint8*)&serverseed,sizeof(uint32));
digest.UpdateBigNumbers(GetInstance()->GetSessionKey(),NULL);
digest.Finalize();
// 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);
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!
// so its not 100% correct to init the crypt here, but it should do the job if authing was correct
_socket->InitCrypt(GetInstance()->GetSessionKey());
// 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
_socket->InitCrypt(GetInstance()->GetSessionKey());
}
void WorldSession::_HandleAuthResponseOpcode(WorldPacket& recvPacket)
{
uint8 errcode;
uint8 dummy8, expansion; uint32 dummy32;
uint8 BillingPlanFlags, expansion; uint32 BillingTimeRemaining, BillingTimeRested;
recvPacket >> errcode;
recvPacket >> dummy32 >> dummy8 >> dummy32;
recvPacket >> expansion;
recvPacket >> BillingTimeRemaining >> BillingPlanFlags >> BillingTimeRested;
if(GetInstance()->GetConf()->client > CLIENT_CLASSIC_WOW)
recvPacket >> expansion;
// TODO: add data to generic_text.scp and use the strings here
if(errcode == AUTH_OK)
{
@ -570,7 +594,7 @@ void WorldSession::_HandleAuthResponseOpcode(WorldPacket& recvPacket)
}
else
{
logerror("World Authentication failed, errcode=0x%X",(unsigned char)errcode);
logerror("World Authentication failed, errcode=0x%X",(uint8)errcode);
SetMustDie();
}
}
@ -604,11 +628,11 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket)
recvPacket >> plr[i]._race;
recvPacket >> plr[i]._class;
recvPacket >> plr[i]._gender;
recvPacket >> plr[i]._bytes1;
recvPacket >> plr[i]._bytes2;
recvPacket >> plr[i]._bytes3;
recvPacket >> plr[i]._bytes4;
recvPacket >> plr[i]._bytesx;
recvPacket >> plr[i]._bytes1;//skin
recvPacket >> plr[i]._bytes2;//face
recvPacket >> plr[i]._bytes3;//hair style
recvPacket >> plr[i]._bytes4;//hair color
recvPacket >> plr[i]._bytesx;//facial hair
recvPacket >> plr[i]._level;
recvPacket >> plr[i]._zoneId;
recvPacket >> plr[i]._mapId;
@ -617,14 +641,21 @@ void WorldSession::_HandleCharEnumOpcode(WorldPacket& recvPacket)
recvPacket >> plr[i]._z;
recvPacket >> plr[i]._guildId;
recvPacket >> plr[i]._flags;
recvPacket >> dummy32; // at_login_customize
if(GetInstance()->GetConf()->client > CLIENT_TBC)
{
recvPacket >> dummy32; // at_login_customize
}
recvPacket >> dummy8;
recvPacket >> plr[i]._petInfoId;
recvPacket >> plr[i]._petLevel;
recvPacket >> plr[i]._petFamilyId;
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
@ -811,7 +842,7 @@ void WorldSession::_HandleAccountDataMD5Opcode(WorldPacket& recvPacket)
// packet structure not yet known
}
void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket)
void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket) //TODO: REWRITE ME!!!
{
uint8 type, chatTag;
uint32 lang;
@ -826,9 +857,11 @@ void WorldSession::_HandleMessageChatOpcode(WorldPacket& recvPacket)
if(lang == LANG_ADDON && GetInstance()->GetConf()->skipaddonchat)
return;
recvPacket >> source_guid;
recvPacket >> unk32;
if(GetInstance()->GetConf()->client > CLIENT_CLASSIC_WOW)
{
recvPacket >> source_guid;
recvPacket >> unk32;
}
switch(type)
{
@ -1016,13 +1049,19 @@ void WorldSession::_HandleNotificationOpcode(WorldPacket& recvPacket)
void WorldSession::_HandleNameQueryResponseOpcode(WorldPacket& recvPacket)
{
uint64 pguid;
uint8 unk;
uint8 realm;
std::string pname;
pguid = recvPacket.GetPackedGuid();
recvPacket >> unk >> pname;
uint32 prace, pgender, pclass;
if(GetInstance()->GetConf()->client > CLIENT_CLASSIC_WOW)
pguid = recvPacket.readPackGUID();
else
recvPacket >> pguid;
recvPacket >> pname >> realm >> prace >> pgender >> pclass;
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
}
// rest of the packet is not interesting for now
plrNameCache.Add(pguid,pname);
logdetail("CACHE: Assigned new player name: '%s' = " I64FMTD ,pname.c_str(),pguid);
@ -1064,27 +1103,26 @@ void WorldSession::_HandleGroupInviteOpcode(WorldPacket& recvPacket)
void WorldSession::_HandleMovementOpcode(WorldPacket& recvPacket)
{
uint32 flags, time, unk32;
float x, y, z, o;
uint64 guid;
uint16 flags2;
guid = recvPacket.GetPackedGuid();
recvPacket >> flags >> flags2 >> time >> x >> y >> z >> o >> unk32;
DEBUG(logdebug("MOVE: "I64FMT" -> time=%u flags=0x%X x=%.4f y=%.4f z=%.4f o=%.4f",guid,time,flags,x,y,z,o));
MovementInfo mi;
guid = recvPacket.readPackGUID();
recvPacket >> mi;
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);
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)
{
uint64 guid;
float x, y, z, o, speed;
uint32 unk32, movetype;
uint16 unk16;
float speed;
uint32 movetype;
MovementInfo mi;
switch(recvPacket.GetOpcode())
{
case MSG_MOVE_SET_WALK_SPEED:
@ -1128,19 +1166,15 @@ void WorldSession::_HandleSetSpeedOpcode(WorldPacket& recvPacket)
return;
}
guid = recvPacket.GetPackedGuid();
recvPacket >> unk32;
recvPacket >> unk16;
recvPacket >> unk32; /* getMSTime()*/
recvPacket >> x >> y >> z >> o;
recvPacket >> unk32; // falltime
guid = recvPacket.readPackGUID();
recvPacket >> mi;
recvPacket >> speed;
Object *obj = objmgr.GetObj(guid);
if(obj && obj->IsUnit())
{
((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;
}
guid = recvPacket.GetPackedGuid();
guid = recvPacket.readPackGUID();
recvPacket >> unk32;
if (movetype == MOVE_RUN)
recvPacket >> unk8;
@ -1209,47 +1243,44 @@ void WorldSession::_HandleForceSetSpeedOpcode(WorldPacket& recvPacket)
void WorldSession::_HandleTelePortAckOpcode(WorldPacket& recvPacket)
{
uint32 unk32,time, flags; // movement flags
uint32 unk32;
uint64 guid;
uint16 unk16;
float x, y, z, o;
MovementInfo mi;
guid = recvPacket.readPackGUID();
recvPacket >> unk32 >> mi;
guid = recvPacket.GetPackedGuid();
recvPacket >> unk32 >> flags >> unk16 >> time >> x >> y >> z >> o >> unk32;
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);
logdetail("Got teleported, data: x: %f, y: %f, z: %f, o: %f, guid: "I64FMT, x, y, z, o, guid);
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->UpdatePos(mi.pos.x,mi.pos.y);
_world->Update();
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"))
{
CmdSet Set;
Set.defaultarg = "false"; // teleported to other map = false
Set.arg[0] = DefScriptTools::toString(guid);
Set.arg[1] = DefScriptTools::toString(x);
Set.arg[2] = DefScriptTools::toString(y);
Set.arg[3] = DefScriptTools::toString(z);
Set.arg[4] = DefScriptTools::toString(o);
Set.arg[5] = DefScriptTools::toString(flags);
Set.arg[1] = DefScriptTools::toString(mi.pos.x);
Set.arg[2] = DefScriptTools::toString(mi.pos.y);
Set.arg[3] = DefScriptTools::toString(mi.pos.z);
Set.arg[4] = DefScriptTools::toString(mi.pos.o);
Set.arg[5] = DefScriptTools::toString(mi.flags);
GetInstance()->GetScripts()->RunScriptIfExists("_onteleport");
}
}
@ -1276,12 +1307,6 @@ void WorldSession::_HandleNewWorldOpcode(WorldPacket& recvPacket)
wp << GetGuid();
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);
@ -1297,6 +1322,9 @@ void WorldSession::_HandleNewWorldOpcode(WorldPacket& recvPacket)
my->ClearSpells(); // will be resent by server
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
@ -1333,7 +1361,7 @@ void WorldSession::_HandleCastSuccessOpcode(WorldPacket& recvPacket)
uint32 spellId;
uint64 casterGuid;
casterGuid = recvPacket.GetPackedGuid();
casterGuid = recvPacket.readPackGUID();
recvPacket >> spellId;
if (GetMyChar()->GetGUID() == casterGuid)
@ -1351,16 +1379,31 @@ void WorldSession::_HandleCastSuccessOpcode(WorldPacket& recvPacket)
void WorldSession::_HandleInitialSpellsOpcode(WorldPacket& recvPacket)
{
uint8 unk;
uint16 spellslot,count;
uint16 not_spellslot,count,spellid16;
uint32 spellid;
recvPacket >> unk >> 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;
logdebug("Initial Spell: id=%u slot=%u",spellid,spellslot);
GetMyChar()->AddSpell(spellid, spellslot);
for(uint16 i = 0; i < count; i++)
{
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)
@ -1612,7 +1655,7 @@ void WorldSession::_HandleCreatureQueryResponseOpcode(WorldPacket& recvPacket)
CreatureTemplate *ct = new CreatureTemplate();
std::string s;
//uint32 unk;
uint32 unk;
float unkf;
ct->entry = entry;
recvPacket >> ct->name;
@ -1620,24 +1663,43 @@ void WorldSession::_HandleCreatureQueryResponseOpcode(WorldPacket& recvPacket)
recvPacket >> s;
recvPacket >> s;
recvPacket >> ct->subname;
recvPacket >> ct->directions;
if(GetInstance()->GetConf()->client > CLIENT_CLASSIC_WOW)
recvPacket >> ct->directions;
recvPacket >> ct->flag1;
recvPacket >> ct->type;
recvPacket >> ct->family;
recvPacket >> ct->rank;
for(uint32 i = 0; i < MAX_KILL_CREDIT; i++)
recvPacket >> ct->killCredit[i];
recvPacket >> ct->displayid_A;
recvPacket >> ct->displayid_H;
recvPacket >> ct->displayid_AF;
recvPacket >> ct->displayid_HF;
recvPacket >> unkf;
recvPacket >> unkf;
recvPacket >> ct->RacialLeader;
for(uint32 i = 0; i < 4; i++)
recvPacket >> ct->questItems[i];
recvPacket >> ct->movementId;
if(GetInstance()->GetConf()->client > CLIENT_CLASSIC_WOW)
{
if(GetInstance()->GetConf()->client == CLIENT_WOTLK)
{
for(uint32 i = 0; i < MAX_KILL_CREDIT; i++)
recvPacket >> ct->killCredit[i];
}
recvPacket >> ct->displayid_A;
recvPacket >> ct->displayid_H;
recvPacket >> ct->displayid_AF;
recvPacket >> ct->displayid_HF;
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;
ss << "Got info for creature " << entry << ":" << ct->name;
if(!ct->subname.empty())
@ -1673,15 +1735,23 @@ void WorldSession::_HandleGameobjectQueryResponseOpcode(WorldPacket& recvPacket)
recvPacket >> other_names; // name1
recvPacket >> other_names; // name2
recvPacket >> other_names; // name3 (all unused)
recvPacket >> unks;
recvPacket >> go->castBarCaption;
recvPacket >> go->unk1;
if(GetInstance()->GetConf()->client > CLIENT_CLASSIC_WOW)
{
recvPacket >> unks;
recvPacket >> go->castBarCaption;
recvPacket >> go->unk1;
}
for(uint32 i = 0; i < GAMEOBJECT_DATA_FIELDS; i++)
recvPacket >> go->raw.data[i];
recvPacket >> go->size;
for(uint32 i = 0; i < 4; i++)
recvPacket >> go->questItems[i];
if(GetInstance()->GetConf()->client > CLIENT_CLASSIC_WOW)
{
recvPacket >> go->size;
if(GetInstance()->GetConf()->client > CLIENT_TBC)
{
for(uint32 i = 0; i < 4; i++)
recvPacket >> go->questItems[i];
}
}
std::stringstream ss;
ss << "Got info for gameobject " << entry << ":" << go->name;
ss << " type " << go->type;
@ -1723,7 +1793,7 @@ void WorldSession::_HandleCharCreateOpcode(WorldPacket& recvPacket)
void WorldSession::_HandleMonsterMoveOpcode(WorldPacket& recvPacket)
{
uint64 guid;
guid = recvPacket.GetPackedGuid();
guid = recvPacket.readPackGUID();
Object* obj = objmgr.GetObj(guid);
if (!obj || !obj->IsWorldObject())
@ -1732,7 +1802,10 @@ void WorldSession::_HandleMonsterMoveOpcode(WorldPacket& recvPacket)
uint8 unk, type;
uint32 time, flags, movetime, waypoints;
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(),
oldy = ((WorldObject*)obj)->GetY();

View File

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

View File

@ -4,11 +4,17 @@
#include "WorldSocket.h"
#include "Opcodes.h"
WorldSocket::WorldSocket(SocketHandler &h, WorldSession *s) : TcpSocket(h)
{
_session = s;
_gothdr = false;
_ok=false;
//Dummy functions for unencrypted packets on WorldSocket
pDecryptRecv = &AuthCrypt::DecryptRecvDummy;
pEncryptSend = &AuthCrypt::EncryptSendDummy;
}
bool WorldSocket::IsOk(void)
@ -78,31 +84,43 @@ void WorldSocket::OnRead()
break;
}
// read first byte and check if size is 3 or 2 bytes
uint8 firstSizeByte;
ibuf.Read((char*)&firstSizeByte, 1);
_crypt.DecryptRecv(&firstSizeByte, 1);
if (firstSizeByte & 0x80) // got large packet
if(GetSession()->GetInstance()->GetConf()->client > CLIENT_TBC)//Funny, old sources have this in TBC already...
{
ServerPktHeaderBig hdr;
ibuf.Read(((char*)&hdr) + 1, sizeof(ServerPktHeaderBig) - 1); // read *big* header, except first byte
_crypt.DecryptRecv(((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
// read first byte and check if size is 3 or 2 bytes
uint8 firstSizeByte;
ibuf.Read((char*)&firstSizeByte, 1);
(_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];
_remaining = realsize - 2;
_opcode = hdr.cmd;
uint32 realsize = ((hdr.size[0]&0x7F) << 16) | (hdr.size[1] << 8) | hdr.size[2];
_remaining = realsize - 2;
_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;
ibuf.Read(((char*)&hdr) + 1, sizeof(ServerPktHeader) - 1); // read header, except first byte
_crypt.DecryptRecv(((uint8*)&hdr) + 1, sizeof(ServerPktHeader) - 1); // decrypt all except first
hdr.size |= firstSizeByte; // add already decrypted first byte
ServerPktHeader hdr;
ibuf.Read(((char*)&hdr), sizeof(ServerPktHeader)); // read header
(_crypt.*pDecryptRecv)(((uint8*)&hdr), sizeof(ServerPktHeader)); // decrypt all
_remaining = ntohs(hdr.size) - 2;
_opcode = hdr.cmd;
_remaining = ntohs(hdr.size) - 2;
_opcode = hdr.cmd;
}
if(_opcode > MAX_OPCODE_ID)
@ -114,7 +132,6 @@ void WorldSocket::OnRead()
// TODO: invent some way how to recover the crypt (reconnect?)
return;
}
// 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)
{
@ -138,7 +155,7 @@ void WorldSocket::SendWorldPacket(WorldPacket &pkt)
memset(&hdr,0,sizeof(ClientPktHeader));
hdr.size = ntohs(pkt.size()+4);
hdr.cmd = pkt.GetOpcode();
_crypt.EncryptSend((uint8*)&hdr, 6);
(_crypt.*pEncryptSend)((uint8*)&hdr, 6);
ByteBuffer final(pkt.size()+6);
final.append((uint8*)&hdr,sizeof(ClientPktHeader));
if(pkt.size())
@ -148,7 +165,38 @@ void WorldSocket::SendWorldPacket(WorldPacket &pkt)
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();
logdebug("WorldSocket: Crypt initialized [%s]",hexstr);
OPENSSL_free((void*)hexstr);

View File

@ -7,6 +7,7 @@
class WorldSession;
class BigNumber;
#if defined( __GNUC__ )
#pragma pack(1)
#else
@ -60,6 +61,9 @@ public:
private:
WorldSession *_session;
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
uint16 _opcode; // stores the last recieved opcode
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"))
{
uint32 endpos = buf.rpos()+size;
_chunks[mcnkid].hdr = buf.read<ADTMapChunkHeader>();
uint8 _cc2[5];
uint8 *mfcc = &_cc2[0];
mfcc[4]=0;
uint32 msize;
bool mcal_compressed = false;
while(buf.rpos()<buf.size())
while(buf.rpos()<endpos)
{
buf.read(mfcc,4); flipcc(mfcc);
buf.read((uint8*)&msize,4);
@ -363,6 +364,7 @@ bool ADTFile::LoadMem(ByteBuffer& buf)
}
mcnkid++;
buf.rpos(endpos);
}
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 };
HmacHash serverEncryptHmac(SEED_KEY_SIZE, (uint8*)ClientDecryptionKey);
@ -60,7 +61,7 @@ void AuthCrypt::Init(BigNumber *K)
_initialized = true;
}
void AuthCrypt::DecryptRecv(uint8 *data, size_t len)
void AuthCrypt::DecryptRecv_12340(uint8 *data, size_t len)
{
if (!_initialized)
return;
@ -68,10 +69,84 @@ void AuthCrypt::DecryptRecv(uint8 *data, size_t len)
_decrypt.UpdateData(len, data);
}
void AuthCrypt::EncryptSend(uint8 *data, size_t len)
void AuthCrypt::EncryptSend_12340(uint8 *data, size_t len)
{
if (!_initialized)
return;
_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();
void Init(BigNumber *K);
void DecryptRecv(uint8 *, size_t);
void EncryptSend(uint8 *, size_t);
//Dummy
void DecryptRecvDummy(uint8 *, size_t){return;};
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; }
const static size_t CRYPTED_SEND_LEN_6005 = 6;
const static size_t CRYPTED_RECV_LEN_6005 = 4;
private:
bool _initialized;
//3.3.5
SARC4 _decrypt;
SARC4 _encrypt;
bool _initialized;
//1.12.2
std::vector<uint8> _key;
uint8 _send_i, _send_j, _recv_i, _recv_j;
};
#endif

View File

@ -272,6 +272,25 @@ class ByteBuffer
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)
{
if (_storage.size() < _wpos + sizeof(guid) + 1)

View File

@ -18,6 +18,19 @@ void MPQHelper::Init()
std::string ext = ".MPQ";
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
// ok maybe this is a bit too much but should work fine :)
_patches.push_front(dir+"common"+ext);

View File

@ -1,6 +1,7 @@
#include "common.h"
#include "MapTile.h"
#include "log.h"
#include "MemoryDataHolder.h"
MapTile::MapTile()
{
@ -12,13 +13,6 @@ MapTile::~MapTile()
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
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++)
{
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);
@ -90,7 +86,9 @@ void MapTile::ImportFromADT(ADTFile *adt)
d.flags = mddf.flags;
d.uniqueid = mddf.uniqueid;
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"
// d.model = d.model.substr(0, d.model.length() - 3) + "m2";
// 3.1.3 - no more .mdx in ADT
@ -115,7 +113,9 @@ void MapTile::ImportFromADT(ADTFile *adt)
wmo.flags = modf.flags;
wmo.uniqueid = modf.uniqueid;
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);
}

View File

@ -1146,7 +1146,7 @@ void FetchTexturesFromModel(ByteBuffer bb)
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!");
return;
}