public static void HandleDataBlock(byte[] data, int index, Stream stream) { switch (data[0]) { case 0x4E: // N stream.Write(data, 1, data.Length - 1); break; case 0x5A: // Z Casc.CopyTo(BLTE_Decompress(data), stream); break; case 0x45: // E (encrypted) byte[] decrypted = BLTE.Decrypt(data, index); if (decrypted == null) { break; } HandleDataBlock(decrypted, index, stream); break; default: Debug.Log("Error: BLTE_ExtractData - Unknown byte at switch case : " + data[0]); //might need return break; } }
public static void Load(string mapName, Vector2 coords) { string dataPath = @"world\maptextures\" + mapName + @"\" + mapName + "_" + coords.x + "_" + coords.y + ".blp"; MapTextureBlock mapTextureBlock = new MapTextureBlock(); Texture2Ddata texture2Ddata = new Texture2Ddata(); string extractedTexturePath = Casc.GetFile(dataPath); using (Stream stream = File.Open(extractedTexturePath, FileMode.Open)) { BLP blp = new BLP(); byte[] data = blp.GetUncompressed(stream, true); BLPinfo info = blp.Info(); texture2Ddata.hasMipmaps = info.hasMipmaps; texture2Ddata.height = info.height; texture2Ddata.width = info.width; texture2Ddata.textureFormat = info.textureFormat; texture2Ddata.TextureData = data; mapTextureBlock.dataPath = dataPath; mapTextureBlock.mapName = mapName; mapTextureBlock.coords = coords; mapTextureBlock.data = texture2Ddata; if (ADT.working) { MapTextureDataQueue.Enqueue(mapTextureBlock); } MapTextureThreadRunning = false; } }
//////////////////// #region Map List Methods // Get a List of Maps from the ADT Maps Directory // public void GetMapList(string mapPath) { string[] list = Casc.GetFolderListFromFolder(mapPath); ExtractedMapList = new List <string>(); ExtractedMapList.AddRange(list); }
private static void ParseM2_Root(string dataPath, M2Data m2Data, M2Texture m2Tex) { StreamTools s = new StreamTools(); string path = Casc.GetFile(dataPath); byte[] M2MainData = File.ReadAllBytes(path); long streamPosition = 0; using (MemoryStream ms = new MemoryStream(M2MainData)) { while (streamPosition < ms.Length) { ms.Position = streamPosition; int chunkID = s.ReadLong(ms); int chunkSize = s.ReadLong(ms); streamPosition = ms.Position + chunkSize; switch (chunkID) { case (int)ChunkID.M2ChunkID.MD21: ReadMD21(ms, m2Data, m2Tex); break; default: SkipUnknownChunk(ms, chunkID, chunkSize); break; } } }; }
public static void Load_hTextures() { if (ADTTexData.textureBlockData.MTXP) { ADTTexData.textureBlockData.terrainHTextures = new Dictionary <string, ADTTexData.Texture2Ddata>(); foreach (string texturePath in ADTTexData.textureBlockData.terrainTexturePaths) { string noExtension = Path.GetFileNameWithoutExtension(texturePath); string directoryPath = Path.GetDirectoryName(texturePath); string hTexturePath = directoryPath + @"\" + noExtension + "_h" + ".blp"; if (Casc.FileExists(hTexturePath)) { string extractedPath = Casc.GetFile(hTexturePath); Stream stream = File.Open(extractedPath, FileMode.Open); BLP blp = new BLP(); byte[] data = blp.GetUncompressed(stream, true); BLPinfo info = blp.Info(); ADTTexData.Texture2Ddata texture2Ddata = new ADTTexData.Texture2Ddata(); texture2Ddata.hasMipmaps = info.hasMipmaps; texture2Ddata.width = info.width; texture2Ddata.height = info.height; if (info.width != info.height) // Unity doesn't support nonsquare mipmaps // sigh { texture2Ddata.hasMipmaps = false; } texture2Ddata.textureFormat = info.textureFormat; texture2Ddata.TextureData = data; ADTTexData.textureBlockData.terrainHTextures.Add(texturePath, texture2Ddata); stream.Close(); stream = null; } } } }
private static void ParseM2_Skin(string dataPath, M2Data m2Data) { // check how many skins files there are // string noExtension = Path.GetFileNameWithoutExtension(dataPath); string directoryPath = Path.GetDirectoryName(dataPath); int skinCount = 0; for (int i = 0; i <= 20; i++) { string fileNumber = i.ToString("00"); if (Casc.FileExists(directoryPath + @"\" + noExtension + fileNumber + ".skin")) { skinCount++; } else { break; } } if (skinCount > 0) { // Load only skin00 for now // string skinDataPath = directoryPath + @"\" + noExtension + "00" + ".skin"; string skinPath = Casc.GetFile(skinDataPath); byte[] M2SkinData = File.ReadAllBytes(skinPath); using (MemoryStream ms = new MemoryStream(M2SkinData)) { ParseSkin(ms, m2Data); } } }
// texture paths // public static void ReadMOTX(Stream WMOrootstream, int MOTXsize) { long currentPos = WMOrootstream.Position; while (WMOrootstream.Position < currentPos + MOTXsize) { int position = (int)(WMOrootstream.Position - currentPos); string path = ReadNullTerminatedString(WMOrootstream); if (path != "") //&& !wmoData.textureData.ContainsKey(path)) { //Debug.Log(path); wmoData.texturePaths.Add(position, path); string extractedPath = Casc.GetFile(path); Stream stream = File.Open(extractedPath, FileMode.Open); byte[] data = BLP.GetUncompressed(stream, true); BLPinfo info = BLP.Info(); Texture2Ddata texture2Ddata = new Texture2Ddata(); texture2Ddata.hasMipmaps = info.hasMipmaps; texture2Ddata.width = info.width; texture2Ddata.height = info.height; //if (info.width != info.height) // Unity doesn't support nonsquare mipmaps // sigh // texture2Ddata.hasMipmaps = false; texture2Ddata.textureFormat = info.textureFormat; texture2Ddata.TextureData = data; wmoData.textureData[path] = texture2Ddata; stream.Close(); stream = null; } } } // loaded
public static void Read(string fileName) { string dataPath = dbfilesclient + fileName; string path = Casc.GetFile(dataPath); byte[] fileData = File.ReadAllBytes(path); // Check DB2 Version // // WDC // if (fileData[0] == Convert.ToByte('W') && fileData[1] == Convert.ToByte('D') && fileData[2] == Convert.ToByte('C')) { // WDC 1 // if (fileData[3] == Convert.ToByte('1')) { WDC1.Read(fileName, fileData); } // WDC 2 // if (fileData[3] == Convert.ToByte('2')) { WDC2.Read(fileName, fileData); } } // WDB // else { Debug.LogWarning("Warning: " + "DB2 Format not supported: " + fileData[0] + fileData[1] + fileData[2] + fileData[3] + fileName); } }
// Terrain Texture Parser // private static void ParseADT_Tex(string Path, string MapName, Vector2 coords) { StreamTools s = new StreamTools(); ADTTex t = new ADTTex(); string ADTtexPath = Path + MapName + "_" + coords.x + "_" + coords.y + "_tex0" + ".adt"; string path = Casc.GetFile(ADTtexPath); byte[] ADTtexData = File.ReadAllBytes(path); int MCNKchunkNumber = 0; long streamPosition = 0; using (MemoryStream ms = new MemoryStream(ADTtexData)) { while (streamPosition < ms.Length) { ms.Position = streamPosition; int chunkID = s.ReadLong(ms); int chunkSize = s.ReadLong(ms); streamPosition = ms.Position + chunkSize; switch (chunkID) { case (int)ChunkID.ADT.MVER: t.ReadMVER(ms); // ADT file version break; case (int)ChunkID.ADT.MAMP: t.ReadMAMP(ms); // Single value - texture size = 64 break; case (int)ChunkID.ADT.MTEX: t.ReadMTEX(ms, chunkSize); // Texture Paths break; case (int)ChunkID.ADT.MCNK: { t.ReadMCNKtex(ms, MapName, MCNKchunkNumber, chunkSize); // Texture Data - 256chunks MCNKchunkNumber++; } break; case (int)ChunkID.ADT.MTXF: t.ReadMTXF(ms, chunkSize); // Texture Paths break; case (int)ChunkID.ADT.MTXP: t.ReadMTXP(ms, chunkSize); // Texture Paths break; default: t.SkipUnknownChunk(ms, chunkID, chunkSize); break; } } } ADTtexData = null; }
// Terrain Mesh Parser // private static void ParseADT_Main(string Path, string MapName, Vector2 coords) // MS version { StreamTools s = new StreamTools(); ADTRoot r = new ADTRoot(); ChunkID c = new ChunkID(); string ADTmainPath = Path + MapName + "_" + coords.x + "_" + coords.y + ".adt"; string path = Casc.GetFile(ADTmainPath); byte[] ADTmainData = File.ReadAllBytes(path); int MCNKchunkNumber = 0; long streamPosition = 0; using (MemoryStream ms = new MemoryStream(ADTmainData)) { while (streamPosition < ms.Length) { ms.Position = streamPosition; int chunkID = s.ReadLong(ms); int chunkSize = s.ReadLong(ms); streamPosition = ms.Position + chunkSize; switch (chunkID) { case (int)ChunkID.ADT.MVER: r.ReadMVER(ms); // ADT file version break; case (int)ChunkID.ADT.MHDR: r.ReadMHDR(ms); // Offsets for specific chunks 0000 if chunks don't exist. break; case (int)ChunkID.ADT.MH2O: r.ReadMH2O(ms, chunkSize); // Water Data break; case (int)ChunkID.ADT.MCNK: { r.ReadMCNK(ms, MCNKchunkNumber, chunkSize); // Terrain Data - 256chunks MCNKchunkNumber++; } break; case (int)ChunkID.ADT.MFBO: r.ReadMFBO(ms); // FlightBounds plane & Death plane break; default: r.SkipUnknownChunk(ms, chunkID, chunkSize); break; } } } ADTmainData = null; }
public bool CheckForMinimaps(string path) { if (Casc.FolderExists(path)) { return(true); } else { return(false); } }
public bool CheckForADTs(string path) { string[] files = Casc.GetFileListFromFolder(path); foreach (string file in files) { if (Path.GetExtension(file).ToLower() == ".adt") { return(true); } } return(false); }
private static void CASCInitThread() { while (ThreadRunning) { CurrentDataVersion = Settings.Data[3]; Working = true; EncryptionKeys.ParseKeyFile(Settings.ApplicationPath + @"\ListFiles\keys1.txt"); /// will need more keys maybe /// Casc.ClearData(); CurrentWorkerText = "Reading WoW Folder"; Casc.ReadWoWFolder(); // check for correct wow data path CurrentWorkerPercent = .05f; CurrentWorkerText = "Find Build Config"; Casc.FindWoWBuildConfig(); CurrentWorkerPercent = .10f; CurrentWorkerText = "Reading IDX files"; Casc.ReadWoWIDXfiles(); // read the IDX files Debug.Log("LocalIndexData Size : " + IndexBlockParser.LocalIndexData.Count); CurrentWorkerPercent = .25f; CurrentWorkerText = "Loading Encoding File"; Casc.LoadEncodingFile(); // Locate and extract encoding file from the data files using the MD5 found in build configuration file Debug.Log("Encoding File Size : " + Casc.EncodingData.Count); CurrentWorkerPercent = .40f; CurrentWorkerText = "Loading Root File"; Casc.LoadWoWRootFile(); Debug.Log("Root Data Size : " + Casc.MyRootData.Count); CurrentWorkerPercent = .55f; CurrentWorkerText = "Loading the Filelist"; Casc.LoadFilelist(); CurrentWorkerPercent = .75f; CurrentWorkerText = "Sorting the Filelist"; Casc.LoadTreeData(); CurrentWorkerPercent = .90f; Working_InitializationFinished = true; Initialized = true; TerrainImport.Initialized = false; CASCThread.Abort(); CASCThread = null; ThreadRunning = false; } }
// WDT files specify exactly which map tiles are present in a world, if any, and can also reference a "global" WMO. // They have a chunked file structure. public static void Load(string Path, string MapName) { string WDTpath = Path + MapName + ".wdt"; Stream WDTstream = Casc.GetFileStream(WDTpath); WDTflagsdata WDTflags = new WDTflagsdata(); ReadMVER(WDTstream); ReadMPHD(WDTstream, MapName, WDTflags); ReadMAIN(WDTstream, WDTflags); // wmo only worlds specific chunk parsing here : Flags.Add(MapName, WDTflags); WDTstream.Close(); WDTstream = null; }
private void AssignMinimapTexture(GameObject MinimapObject, string minimapName) { string path = @"world\minimaps\" + minimapName + @"\" + MinimapObject.name + ".blp"; string extractedPath = Casc.GetFile(path); Stream stream = File.Open(extractedPath, FileMode.Open); byte[] data = BLP.GetUncompressed(stream, false); BLPinfo info = BLP.Info(); Texture2D tex = new Texture2D(info.width, info.height, BLP.TxFormat(), false); tex.LoadRawTextureData(data); MinimapObject.GetComponent <RawImage>().texture = tex; MinimapObject.GetComponent <RawImage>().uvRect = new Rect(0, 0, 1, -1); tex.Apply(); stream.Close(); BLP.Close(); }
public void ReadMTEX(MemoryStream ADTtexstream, int MTEXsize) { if (ADTtexstream.Length == ADTtexstream.Position) { return; } // texture path strings, separated by 0 string texturePath = ""; int numberOfTextures = 0; for (int a = 0; a < MTEXsize; a++) { int b = ADTtexstream.ReadByte(); if (b != 0) { var stringSymbol = System.Convert.ToChar(b); texturePath = texturePath + stringSymbol; } else if (b == 0) { ADTTexData.textureBlockData.terrainTexturePaths.Add(texturePath); string extractedPath = Casc.GetFile(texturePath); using (Stream stream = File.Open(extractedPath, FileMode.Open)) { BLP blp = new BLP(); byte[] data = blp.GetUncompressed(stream, true); BLPinfo info = blp.Info(); ADTTexData.Texture2Ddata texture2Ddata = new ADTTexData.Texture2Ddata(); texture2Ddata.hasMipmaps = info.hasMipmaps; texture2Ddata.width = info.width; texture2Ddata.height = info.height; if (info.width != info.height) // Unity doesn't support nonsquare mipmaps // sigh { texture2Ddata.hasMipmaps = false; } texture2Ddata.textureFormat = info.textureFormat; texture2Ddata.TextureData = data; ADTTexData.textureBlockData.terrainTextures.Add(texturePath, texture2Ddata); texturePath = null; numberOfTextures++; } } } }
public static void Initialize() { // Check existing DB2 files // foreach (string fileName in fileNames) { if (Casc.FileExists(dbfilesclient + fileName)) { availableFiles.Add(fileName, true); Read(fileName); } else { availableFiles.Add(fileName, false); Debug.LogWarning("Warning: " + "Missing " + fileName); } } }
// WDT files specify exactly which map tiles are present in a world, if any, and can also reference a "global" WMO. // They have a chunked file structure. public static bool Load(string Path, string MapName) { string WDTpath = Path + MapName + ".wdt"; using (Stream WDTstream = Casc.GetFileStream(WDTpath)) { if (WDTstream != null) { WDTflagsdata WDTflags = new WDTflagsdata(); ReadMVER(WDTstream); ReadMPHD(WDTstream, MapName, WDTflags); ReadMAIN(WDTstream, WDTflags); // wmo only worlds specific chunk parsing here : Flags.Add(MapName, WDTflags); return(true); } return(false); } }
// Request a minimap image from the parser // private static void RequestBlock(Minimap.MinimapRequest minimapRequest) { string mapName = minimapRequest.mapName; string fileName = "map" + minimapRequest.coords.x + "_" + minimapRequest.coords.y + ".blp"; string path = @"world\minimaps\" + mapName + @"\" + fileName; string extractedPath = Casc.GetFile(path); using (Stream stream = File.Open(extractedPath, FileMode.Open)) { BLP blp = new BLP(); byte[] data = blp.GetUncompressed(stream, true); BLPinfo info = blp.Info(); MinimapData.MinimapBlockData blockData = new MinimapData.MinimapBlockData(); blockData.mapName = mapName; blockData.coords = minimapRequest.coords; blockData.textureInfo = info; blockData.minimapByteData = data; MinimapData.MinimapDataQueue.Enqueue(blockData); } }
public void LoadMinimaps(string minimapPath, string mapName) { // reset global variables // ClearData(); // update global list of minimap files : MinimapFileList // string[] FileList = Casc.GetFileListFromFolder(minimapPath); foreach (string file in FileList) { var fileName = Path.GetFileNameWithoutExtension(file); if (fileName.StartsWith("m")) { MinimapFileList.Add(fileName); } } // resize scroll area to encapsulate all minimap blocks // AdjustScrollableArea(); // Create minimap block instances // map_name = mapName; GenerateMinimaps(mapName); }
// texture paths // public static void ReadMOTX(Stream WMOrootstream, int MOTXsize) { long currentPos = WMOrootstream.Position; while (WMOrootstream.Position < currentPos + MOTXsize) { int position = (int)(WMOrootstream.Position - currentPos); string path = ReadNullTerminatedString(WMOrootstream); if (path != "") //&& !wmoData.textureData.ContainsKey(path)) { wmoData.texturePaths.Add(position, path); if (!LoadedBLPs.Contains(path)) { string extractedPath = Casc.GetFile(path); if (File.Exists(extractedPath)) { Stream stream = File.Open(extractedPath, FileMode.Open); BLP blp = new BLP(); byte[] data = blp.GetUncompressed(stream, true); BLPinfo info = blp.Info(); Texture2Ddata texture2Ddata = new Texture2Ddata(); texture2Ddata.hasMipmaps = info.hasMipmaps; texture2Ddata.width = info.width; texture2Ddata.height = info.height; texture2Ddata.textureFormat = info.textureFormat; texture2Ddata.TextureData = data; wmoData.textureData[path] = texture2Ddata; stream.Close(); stream.Dispose(); stream = null; } LoadedBLPs.Add(path); } } } } // loaded
// Build an array of available minimaps and maps // public static void CompileMapList(string mapName) { MinimapData.dataExists.WDT = false; if (!WDT.Flags.ContainsKey(mapName)) { MinimapData.dataExists.WDT = WDT.Load(@"world\maps\" + mapName + @"\", mapName); } else { MinimapData.dataExists.WDT = true; } MinimapData.dataExists.ADT = Casc.FolderExists(@"world\maps\" + mapName); MinimapData.dataExists.Minimap = Casc.FolderExists(@"world\minimaps\" + mapName); // sort data // MinimapData.mapAvailability = new MinimapData.MapAvailability[64, 64]; List <string> ADTs = new List <string>(); List <string> Minimaps = new List <string>(); if (MinimapData.dataExists.ADT) { ADTs = Casc.GetFileListFromFolder(@"world\maps\" + mapName); } if (MinimapData.dataExists.Minimap) { Minimaps = Casc.GetFileListFromFolder(@"world\minimaps\" + mapName); } for (int x = 0; x < 64; x++) { for (int y = 0; y < 64; y++) { // WDT data // if (MinimapData.dataExists.WDT) { MinimapData.mapAvailability[x, y].WDT = WDT.Flags[mapName].HasADT[x, y]; } // ADT files // if (MinimapData.dataExists.ADT) { if (ADTs.Contains(mapName + "_" + x + "_" + y + ".adt")) { MinimapData.mapAvailability[x, y].ADT = true; } else { MinimapData.mapAvailability[x, y].ADT = false; } } // Minimap files // if (MinimapData.dataExists.Minimap) { if (Minimaps.Contains("map" + x + "_" + y + ".blp")) { MinimapData.mapAvailability[x, y].Minimap = true; } else { MinimapData.mapAvailability[x, y].Minimap = false; } } } } }
// Terrain Models Parser // public static void ParseADT_Obj(string Path, string MapName, Vector2 coords) { StreamTools s = new StreamTools(); ADTObj o = new ADTObj(); string ADTobjPath = Path + MapName + "_" + coords.x + "_" + coords.y + "_obj0" + ".adt"; string path = Casc.GetFile(ADTobjPath); byte[] ADTobjData = File.ReadAllBytes(path); int MCNKchunkNumber = 0; long streamPosition = 0; using (MemoryStream ms = new MemoryStream(ADTobjData)) { while (streamPosition < ms.Length) { ms.Position = streamPosition; int chunkID = s.ReadLong(ms); int chunkSize = s.ReadLong(ms); streamPosition = ms.Position + chunkSize; switch (chunkID) { case (int)ChunkID.ADT.MVER: o.ReadMVER(ms); // ADT file version break; case (int)ChunkID.ADT.MMDX: o.ReadMMDX(ms, chunkSize); // List of filenames for M2 models break; case (int)ChunkID.ADT.MMID: o.ReadMMID(ms, chunkSize); // List of offsets of model filenames in the MMDX chunk. break; case (int)ChunkID.ADT.MWMO: o.ReadMWMO(ms, chunkSize); // List of filenames for WMOs (world map objects) that appear in this map tile. break; case (int)ChunkID.ADT.MWID: o.ReadMWID(ms, chunkSize); // List of offsets of WMO filenames in the MWMO chunk. break; case (int)ChunkID.ADT.MDDF: o.ReadMDDF(ms, chunkSize); // Placement information for doodads (M2 models). break; case (int)ChunkID.ADT.MODF: o.ReadMODF(ms, chunkSize); // Placement information for WMOs. break; case (int)ChunkID.ADT.MCNK: { o.ReadMCNKObj(ms, MapName, MCNKchunkNumber, chunkSize); // 256chunks MCNKchunkNumber++; } break; default: SkipUnknownChunk(ms, chunkID, chunkSize); break; } } } ADTobjData = null; }
public static void ReadMD21(MemoryStream ms, M2Data m2Data, M2Texture m2Tex) { long md20position = ms.Position; StreamTools s = new StreamTools(); int MD20 = s.ReadLong(ms); // "MD20". Legion uses a chunked file format starting with MD21. int version = s.ReadLong(ms); M2Array name = s.ReadM2Array(ms); // should be globally unique, used to reload by name in internal clients var flags = s.ReadLong(ms); M2Array global_loops = s.ReadM2Array(ms); // Timestamps used in global looping animations. M2Array sequences = s.ReadM2Array(ms); // Information about the animations in the model. M2Array sequences_lookups = s.ReadM2Array(ms); // Mapping of sequence IDs to the entries in the Animation sequences block. M2Array bones = s.ReadM2Array(ms); // MAX_BONES = 0x100 => Creature\SlimeGiant\GiantSlime.M2 has 312 bones(Wrath) M2Array key_bone_lookup = s.ReadM2Array(ms); // Lookup table for key skeletal bones. M2Array vertices = s.ReadM2Array(ms); int num_skin_profiles = s.ReadLong(ms); M2Array colors = s.ReadM2Array(ms); // Color and alpha animations definitions. M2Array textures = s.ReadM2Array(ms); M2Array texture_weights = s.ReadM2Array(ms); // Transparency of textures. M2Array texture_transforms = s.ReadM2Array(ms); M2Array replaceable_texture_lookup = s.ReadM2Array(ms); M2Array materials = s.ReadM2Array(ms); // Blending modes / render flags. M2Array bone_lookup_table = s.ReadM2Array(ms); M2Array texture_lookup_table = s.ReadM2Array(ms); M2Array tex_unit_lookup_table = s.ReadM2Array(ms); // ≥ Cata: unused M2Array transparency_lookup_table = s.ReadM2Array(ms); M2Array texture_transforms_lookup_table = s.ReadM2Array(ms); m2Data.bounding_box = s.ReadBoundingBox(ms); // min/max( [1].z, 2.0277779f ) - 0.16f seems to be the maximum camera height float bounding_sphere_radius = s.ReadFloat(ms); // detail doodad draw dist = clamp (bounding_sphere_radius * detailDoodadDensityFade * detailDoodadDist, …) BoundingBox collision_box = s.ReadBoundingBox(ms); float collision_sphere_radius = s.ReadFloat(ms); M2Array collision_triangles = s.ReadM2Array(ms); M2Array collision_vertices = s.ReadM2Array(ms); M2Array collision_normals = s.ReadM2Array(ms); M2Array attachments = s.ReadM2Array(ms); // position of equipped weapons or effects M2Array attachment_lookup_table = s.ReadM2Array(ms); M2Array events = s.ReadM2Array(ms); // Used for playing sounds when dying and a lot else. M2Array lights = s.ReadM2Array(ms); // Lights are mainly used in loginscreens but in wands and some doodads too. M2Array cameras = s.ReadM2Array(ms); // The cameras are present in most models for having a model in the character tab. M2Array camera_lookup_table = s.ReadM2Array(ms); M2Array ribbon_emitters = s.ReadM2Array(ms); // Things swirling around. See the CoT-entrance for light-trails. M2Array particle_emitters = s.ReadM2Array(ms); // Name // ms.Position = name.offset + md20position; for (int n = 0; n < name.size; n++) { m2Data.name += Convert.ToChar(ms.ReadByte()); } // Bones // ms.Position = bones.offset + md20position; M2TrackBase[] translationM2track = new M2TrackBase[bones.size]; M2TrackBase[] rotationM22track = new M2TrackBase[bones.size]; M2TrackBase[] scaleM22track = new M2TrackBase[bones.size]; for (int cb = 0; cb < bones.size; cb++) { M2CompBone m2CompBone = new M2CompBone(); m2CompBone.key_bone_id = s.ReadLong(ms); // Back-reference to the key bone lookup table. -1 if this is no key bone. m2CompBone.flags = s.ReadUint32(ms); m2CompBone.parent_bone = s.ReadShort(ms); m2CompBone.submesh_id = s.ReadUint16(ms); m2CompBone.uDistToFurthDesc = s.ReadUint16(ms); m2CompBone.uZRatioOfChain = s.ReadUint16(ms); translationM2track[cb] = s.ReadM2Track(ms); rotationM22track[cb] = s.ReadM2Track(ms); scaleM22track[cb] = s.ReadM2Track(ms); Vector3 pivotRaw = new Vector3(s.ReadFloat(ms) / Settings.worldScale, s.ReadFloat(ms) / Settings.worldScale, s.ReadFloat(ms) / Settings.worldScale); m2CompBone.pivot = new Vector3(-pivotRaw.x, pivotRaw.z, -pivotRaw.y); m2Data.m2CompBone.Add(m2CompBone); } // Animations // int numberOfAnimations = 0; for (int ab = 0; ab < bones.size; ab++) { List <Animation_Vector3> bone_position_animations = new List <Animation_Vector3>(); List <Animation_Quaternion> bone_rotation_animations = new List <Animation_Quaternion>(); List <Animation_Vector3> bone_scale_animations = new List <Animation_Vector3>(); // Position // int numberOfPositionAnimations = translationM2track[ab].Timestamps.size; if (numberOfAnimations < numberOfPositionAnimations) { numberOfAnimations = numberOfPositionAnimations; } for (int at = 0; at < numberOfPositionAnimations; at++) { Animation bone_animation = new Animation(); Animation_Vector3 positions = new Animation_Vector3(); // Timestamps // List <int> timeStamps = new List <int>(); ms.Position = translationM2track[ab].Timestamps.offset + md20position; M2Array m2AnimationOffset = s.ReadM2Array(ms); ms.Position = m2AnimationOffset.offset; for (int t = 0; t < m2AnimationOffset.size; t++) { timeStamps.Add(s.ReadLong(ms)); } positions.timeStamps = timeStamps; // Values // List <Vector3> values = new List <Vector3>(); ms.Position = translationM2track[ab].Values.offset + md20position; M2Array m2AnimationValues = s.ReadM2Array(ms); ms.Position = m2AnimationValues.offset; for (int t = 0; t < m2AnimationValues.size; t++) { Vector3 rawPosition = new Vector3(s.ReadFloat(ms) / Settings.worldScale, s.ReadFloat(ms) / Settings.worldScale, s.ReadFloat(ms) / Settings.worldScale); values.Add(new Vector3(-rawPosition.x, rawPosition.z, -rawPosition.y)); } positions.values = values; bone_position_animations.Add(positions); } // Rotation // int numberOfRotationAnimations = rotationM22track[ab].Timestamps.size; if (numberOfAnimations < numberOfRotationAnimations) { numberOfAnimations = numberOfRotationAnimations; } for (int ar = 0; ar < numberOfRotationAnimations; ar++) { Animation_Quaternion rotations = new Animation_Quaternion(); // Timestamps // List <int> timeStamps = new List <int>(); ms.Position = rotationM22track[ab].Timestamps.offset + md20position; M2Array m2AnimationOffset = s.ReadM2Array(ms); ms.Position = m2AnimationOffset.offset; for (int t = 0; t < m2AnimationOffset.size; t++) { timeStamps.Add(s.ReadLong(ms)); } rotations.timeStamps = timeStamps; // Values // List <Quaternion> values = new List <Quaternion>(); ms.Position = rotationM22track[ab].Values.offset + md20position; M2Array m2AnimationValues = s.ReadM2Array(ms); ms.Position = m2AnimationValues.offset; for (int t = 0; t < m2AnimationValues.size; t++) { Quaternion rawRotation = s.ReadQuaternion16(ms); values.Add(new Quaternion(rawRotation.x, rawRotation.y, rawRotation.z, rawRotation.w)); } rotations.values = values; bone_rotation_animations.Add(rotations); } // Scale // int numberOfScaleAnimations = scaleM22track[ab].Timestamps.size; if (numberOfAnimations < numberOfScaleAnimations) { numberOfAnimations = numberOfScaleAnimations; } for (int aS = 0; aS < numberOfScaleAnimations; aS++) { Animation_Vector3 scales = new Animation_Vector3(); // Timestamps // List <int> timeStamps = new List <int>(); ms.Position = scaleM22track[ab].Timestamps.offset + md20position; M2Array m2AnimationOffset = s.ReadM2Array(ms); ms.Position = m2AnimationOffset.offset; for (int t = 0; t < m2AnimationOffset.size; t++) { timeStamps.Add(s.ReadLong(ms)); } scales.timeStamps = timeStamps; // Values // List <Vector3> values = new List <Vector3>(); ms.Position = scaleM22track[ab].Values.offset + md20position; M2Array m2AnimationValues = s.ReadM2Array(ms); ms.Position = m2AnimationValues.offset; for (int t = 0; t < m2AnimationValues.size; t++) { Vector3 rawScale = new Vector3(s.ReadFloat(ms) / Settings.worldScale, s.ReadFloat(ms) / Settings.worldScale, s.ReadFloat(ms) / Settings.worldScale); values.Add(new Vector3(-rawScale.x, rawScale.z, -rawScale.y)); } scales.values = values; bone_scale_animations.Add(scales); } //Debug.Log(numberOfPositionAnimations + " " + numberOfRotationAnimations + " " + numberOfScaleAnimations); m2Data.position_animations.Add(bone_position_animations); m2Data.rotation_animations.Add(bone_rotation_animations); m2Data.scale_animations.Add(bone_scale_animations); } m2Data.numberOfAnimations = numberOfAnimations; // Bone Lookup Table // ms.Position = bone_lookup_table.offset + md20position; for (int blt = 0; blt < key_bone_lookup.size; blt++) { m2Data.bone_lookup_table.Add(s.ReadUint16(ms)); } // Key-Bone Lookup // ms.Position = key_bone_lookup.offset + md20position; for (int kbl = 0; kbl < key_bone_lookup.size; kbl++) { m2Data.key_bone_lookup.Add(s.ReadShort(ms)); } // Vertices // ms.Position = vertices.offset + md20position; m2Data.meshData = new MeshData(); for (int v = 0; v < vertices.size; v++) { Vector3 rawPosition = new Vector3(s.ReadFloat(ms) / Settings.worldScale, s.ReadFloat(ms) / Settings.worldScale, s.ReadFloat(ms) / Settings.worldScale); m2Data.meshData.pos.Add(new Vector3(-rawPosition.x, rawPosition.z, -rawPosition.y)); m2Data.meshData.bone_weights.Add(new float[] { ms.ReadByte() / 255.0f, ms.ReadByte() / 255.0f, ms.ReadByte() / 255.0f, ms.ReadByte() / 255.0f }); m2Data.meshData.bone_indices.Add(new int[] { ms.ReadByte(), ms.ReadByte(), ms.ReadByte(), ms.ReadByte() }); //Debug.Log(m2Data.meshData.bone_indices[v][0] + " " + m2Data.meshData.bone_indices[v][1] + " " + m2Data.meshData.bone_indices[v][2] + " " + m2Data.meshData.bone_indices[v][3]); Vector3 rawnormal = new Vector3(s.ReadFloat(ms) * Settings.worldScale, s.ReadFloat(ms) * Settings.worldScale, s.ReadFloat(ms) * Settings.worldScale); m2Data.meshData.normal.Add(new Vector3(-rawnormal.x, rawnormal.z, -rawnormal.y)); m2Data.meshData.tex_coords.Add(new Vector2(s.ReadFloat(ms), s.ReadFloat(ms))); m2Data.meshData.tex_coords2.Add(new Vector2(s.ReadFloat(ms), s.ReadFloat(ms))); } // Textures // ms.Position = textures.offset + md20position; for (int t = 0; t < textures.size; t++) { M2Texture m2Texture = new M2Texture(); m2Texture.type = s.ReadLong(ms); m2Texture.flags = s.ReadLong(ms); M2Array filename = s.ReadM2Array(ms); // seek to filename and read // long savePosition = ms.Position; ms.Position = filename.offset + md20position; string fileNameString = ""; for (int n = 0; n < filename.size; n++) { fileNameString += Convert.ToChar(ms.ReadByte()); } ms.Position = savePosition; string fileNameStringFix = fileNameString.TrimEnd(fileNameString[fileNameString.Length - 1]); m2Texture.filename = fileNameStringFix; Texture2Ddata texture2Ddata = new Texture2Ddata(); if (fileNameStringFix.Length > 1) { if (!LoadedBLPs.Contains(fileNameStringFix)) { string extractedPath = Casc.GetFile(fileNameStringFix); Stream stream = File.Open(extractedPath, FileMode.Open); BLP blp = new BLP(); byte[] data = blp.GetUncompressed(stream, true); BLPinfo info = blp.Info(); texture2Ddata.hasMipmaps = info.hasMipmaps; texture2Ddata.width = info.width; texture2Ddata.height = info.height; texture2Ddata.textureFormat = info.textureFormat; texture2Ddata.TextureData = data; m2Texture.texture2Ddata = texture2Ddata; stream.Close(); stream.Dispose(); stream = null; LoadedBLPs.Add(fileNameString); } } m2Data.m2Tex.Add(m2Texture); } // texture_lookup_table // ms.Position = texture_lookup_table.offset + md20position; for (int tl = 0; tl < texture_lookup_table.size; tl++) { m2Data.textureLookupTable.Add(s.ReadUint16(ms)); } }
private static void ParseWMO_Root(string dataPath) { Stream WMOrootstream = Casc.GetFileStream(dataPath); long streamPosition = 0; while (streamPosition < WMOrootstream.Length) { WMOrootstream.Position = streamPosition; int chunkID = ReadLong(WMOrootstream); int chunkSize = ReadLong(WMOrootstream); streamPosition = WMOrootstream.Position + chunkSize; switch (chunkID) { case (int)ChunkID.WMOChunkID.MVER: ReadMVER(WMOrootstream); // root file version break; case (int)ChunkID.WMOChunkID.MOHD: ReadMOHD(WMOrootstream); // root file header break; case (int)ChunkID.WMOChunkID.MOTX: ReadMOTX(WMOrootstream, chunkSize); // texture paths break; case (int)ChunkID.WMOChunkID.MOMT: ReadMOMT(WMOrootstream, chunkSize); // materials break; case (int)ChunkID.WMOChunkID.MOUV: ReadMOUV(WMOrootstream); // texture animation // optional break; case (int)ChunkID.WMOChunkID.MOGN: ReadMOGN(WMOrootstream, chunkSize); // list of group names break; case (int)ChunkID.WMOChunkID.MOGI: ReadMOGI(WMOrootstream); // Group information for WMO groups break; case (int)ChunkID.WMOChunkID.MOSB: ReadMOSB(WMOrootstream, chunkSize); // Skybox model filename break; case (int)ChunkID.WMOChunkID.MOPV: ReadMOPV(WMOrootstream, chunkSize); // Portal vertices break; case (int)ChunkID.WMOChunkID.MOPT: ReadMOPT(WMOrootstream); // Portal information break; case (int)ChunkID.WMOChunkID.MOPR: ReadMOPR(WMOrootstream, chunkSize); // Portal references from groups break; case (int)ChunkID.WMOChunkID.MOVV: ReadMOVV(WMOrootstream, chunkSize); // Visible block vertices break; case (int)ChunkID.WMOChunkID.MOVB: ReadMOVB(WMOrootstream, chunkSize); // Visible block list break; case (int)ChunkID.WMOChunkID.MOLT: ReadMOLT(WMOrootstream); // Lighting information. break; case (int)ChunkID.WMOChunkID.MODS: ReadMODS(WMOrootstream, chunkSize); // This chunk defines doodad sets. break; case (int)ChunkID.WMOChunkID.MODN: ReadMODN(WMOrootstream, chunkSize); //List of filenames for M2 break; case (int)ChunkID.WMOChunkID.MODD: ReadMODD(WMOrootstream, chunkSize); // Information for doodad instances. break; case (int)ChunkID.WMOChunkID.MFOG: ReadMFOG(WMOrootstream, chunkSize); // Fog information. break; case (int)ChunkID.WMOChunkID.MCVP: ReadMCVP(WMOrootstream, chunkSize); // Convex Volume Planes. break; case (int)ChunkID.WMOChunkID.GFID: ReadGFID(WMOrootstream, chunkSize); // required when WMO is loaded from fileID break; default: SkipUnknownChunk(WMOrootstream, chunkID, chunkSize); break; } } WMOrootstream.Close(); WMOrootstream = null; }
private static void ParseWMO_Groups(string dataPath) { wmoData.groupsData = new List <GroupData>(wmoData.Info.nGroups); string noExtension = Path.GetFileNameWithoutExtension(dataPath); string directoryPath = Path.GetDirectoryName(dataPath); //for (int grp = 0; grp < 1; grp++) for (int grp = 0; grp < wmoData.Info.nGroups; grp++) { groupDataBuffer = new GroupData(); string fileNumber = grp.ToString("000"); string fullPath = directoryPath + @"\" + noExtension + "_" + fileNumber + ".wmo"; Stream WMOgroupstream = Casc.GetFileStream(fullPath); int MVER = ReadLong(WMOgroupstream); int MVERsize = ReadLong(WMOgroupstream); ReadMVER(WMOgroupstream); // root file version int MOGP = ReadLong(WMOgroupstream); int MOGPsize = ReadLong(WMOgroupstream); ReadMOGP(WMOgroupstream); // group header (contains the rest of the chunks) int MOTVcount = 0; int MOCVcount = 0; long streamPosition = WMOgroupstream.Position; while (streamPosition < WMOgroupstream.Length) { WMOgroupstream.Position = streamPosition; int chunkID = ReadLong(WMOgroupstream); int chunkSize = ReadLong(WMOgroupstream); streamPosition = WMOgroupstream.Position + chunkSize; switch (chunkID) { case (int)ChunkID.WMOChunkID.MOPY: ReadMOPY(WMOgroupstream, chunkSize); // Material info for triangles break; case (int)ChunkID.WMOChunkID.MOVI: ReadMOVI(WMOgroupstream, chunkSize); // Vertex indices for triangles break; case (int)ChunkID.WMOChunkID.MOVT: ReadMOVT(WMOgroupstream, chunkSize); // Vertices chunk break; case (int)ChunkID.WMOChunkID.MONR: ReadMONR(WMOgroupstream, chunkSize); // Normals chunk break; case (int)ChunkID.WMOChunkID.MOTV: { MOTVcount++; if (MOTVcount == 1) { ReadMOTV(WMOgroupstream, chunkSize); // Texture coordinates } else if (MOTVcount == 2) { ReadMOTV2(WMOgroupstream, chunkSize); } else if (MOTVcount == 3) { ReadMOTV3(WMOgroupstream, chunkSize); } } break; case (int)ChunkID.WMOChunkID.MOBA: ReadMOBA(WMOgroupstream, chunkSize); // Render batches break; case (int)ChunkID.WMOChunkID.MOCV: { MOCVcount++; if (MOCVcount == 1) { ReadMOCV(WMOgroupstream, chunkSize); } else if (MOCVcount == 2) { ReadMOCV2(WMOgroupstream, chunkSize); } } break; default: SkipUnknownChunk(WMOgroupstream, chunkID, chunkSize); break; } } wmoData.groupsData.Add(groupDataBuffer); WMOgroupstream.Close(); WMOgroupstream = null; } }
public static MemoryStream ExtractData(Stream stream, int size) { if (size < 8) { Debug.Log("Error : BLTE block too small"); return(null); } BinaryReader reader = new BinaryReader(stream, Encoding.ASCII); MD5 md5 = MD5.Create(); MemoryStream Mstream = new MemoryStream(); // write to this one int magic = reader.ReadInt32(); // BLTE (raw) if (magic != 0x45544c42) { Debug.Log("Error: BLTE_ExtractData - Wrong BLTE Magic"); return(null); } else { int frameHeaderSize = Casc.ReadInt32BE(reader); int chunkCount = 0; int totalSize = 0; if (frameHeaderSize == 0) { totalSize = size - 8; chunkCount = 1; } else { byte unk1 = reader.ReadByte(); // byte if (unk1 != 0x0F) { Debug.Log("Error: BLTE_ExtractData - unk1 != 0x0F"); return(null); } byte v1 = reader.ReadByte(); byte v2 = reader.ReadByte(); byte v3 = reader.ReadByte(); chunkCount = v1 << 16 | v2 << 8 | v3 << 0; // 3-byte } if (chunkCount < 0) { Debug.Log("Error: BLTE_ExtractData - Possible error ({0}) at offset: {1:X8}"); return(null); } BLTEChunk[] chunks = new BLTEChunk[chunkCount]; for (int i = 0; i < chunkCount; i++) { chunks[i] = new BLTEChunk(); if (frameHeaderSize != 0) { chunks[i].CompSize = Casc.ReadInt32BE(reader); chunks[i].DecompSize = Casc.ReadInt32BE(reader); chunks[i].Hash = reader.ReadBytes(16); } else { chunks[i].CompSize = totalSize; chunks[i].DecompSize = totalSize - 1; chunks[i].Hash = null; } } for (int i1 = 0; i1 < chunkCount; i1++) { chunks[i1].Data = reader.ReadBytes(chunks[i1].CompSize); if (chunks[i1].Data.Length != chunks[i1].CompSize) { Debug.Log("Error: BLTE_ExtractData - chunks[i1].data.Length != chunks[i1].compSize"); //might need a return } if (frameHeaderSize != 0) { byte[] hh = md5.ComputeHash(chunks[i1].Data); if (!Casc.EqualsTo(hh, chunks[i1].Hash)) { Debug.Log("Error: BLTE_ExtractData - MD5 missmatch!"); //might need return } } HandleDataBlock(chunks[i1].Data, i1, Mstream); } } Mstream.Position = 0; return(Mstream); }