public static FObjectExport ReadEntry(IOMemoryStream ms, UassetFile f) { //Read in FObjectExport g = new FObjectExport(); g.entryLocation = ms.position; g.id = ms.ReadInt(); g.unknown1 = ms.ReadInt(); g.unknown2 = ms.ReadInt(); g.unknown3 = ms.ReadInt(); g.type = ms.ReadNameTableEntry(f); g.unknown4 = ms.ReadInt(); g.unknown5 = ms.ReadInt(); g.LengthOffset = (int)ms.position; g.dataLength = ms.ReadInt(); g.dataLocation = ms.ReadInt(); g.unknown6 = ms.ReadInt(); g.unknown7 = ms.ReadInt(); g.unknown8 = ms.ReadInt(); g.unknown9 = ms.ReadInt(); g.unknown10 = ms.ReadInt(); g.unknown11 = ms.ReadInt(); g.unknown12 = ms.ReadInt(); g.unknown13 = ms.ReadInt(); g.unknown14 = ms.ReadInt(); g.unknown15 = ms.ReadInt(); g.unknown16 = ms.ReadInt(); g.unknown17 = ms.ReadInt(); g.unknown18 = ms.ReadInt(); g.unknown19 = ms.ReadInt(); g.unknown20 = ms.ReadInt(); g.unknown21 = ms.ReadInt(); g.unknown22 = ms.ReadInt(); long lastPos = ms.position; ms.position = g.dataLocation; g.data = ms.ReadBytes(g.dataLength); ms.position = lastPos; g.uassetFile = f; return(g); }
public static UTexture2D GetTextureFromUAsset(UassetFile uassetFile) { /*if (uassetFile.UE4Version != UE4Version.UE4__4_14) * throw new NotSupportedException($"Texture extraction from {uassetFile.UE4Version.ToString()} uasset files is not supported.");*/ TKContext.LogInner("INFO", $"Attempting to get a texture from file {uassetFile.Filename}"); try { FObjectExport export = uassetFile.ExportsTable[0]; EPixelFormat ePixelFormat = EPixelFormat.PF_Unknown; int pfOffset = 0x0; // TODO: Simplify this mess. for (int i = 0; i < uassetFile.NamesTable.Length; i++) { if (uassetFile.NamesTable[i].Name.ToUpper().StartsWith("PF_")) { if (!Enum.TryParse(uassetFile.NamesTable[i].Name, out ePixelFormat)) { TKContext.LogError("Pixel Format is not supported."); return(null); } } } UTexture2D uTexture2D = new UTexture2D(); //uTexture2D.USerializedData = uSerializedData; uTexture2D.UassetFile = uassetFile; TKContext.LogInner("INFO", $"Attempting to find {ePixelFormat.ToString()}"); pfOffset = ArrayExtensions.IndexOfPattern(export.data, Encoding.ASCII.GetBytes(ePixelFormat.ToString())); TKContext.LogInner("INFO", $"Pixel Format offset is 0x{pfOffset:X8}"); if (pfOffset == int.MaxValue) { TKContext.LogError("No texture was found."); return(null); } uTexture2D.PFOffset = pfOffset; uTexture2D.PixelFormat = ePixelFormat; uTexture2D.Height = BitConverter.ToInt32(ArrayExtensions.GetBytesFromByteArray(export.data, pfOffset - UASSET_RELATIVE_PF_HEIGHT, 4), 0); uTexture2D.Width = BitConverter.ToInt32(ArrayExtensions.GetBytesFromByteArray(export.data, pfOffset - UASSET_RELATIVE_PF_WIDTH, 4), 0); uTexture2D.UnknownValue = BitConverter.ToInt32(ArrayExtensions.GetBytesFromByteArray(export.data, pfOffset + 0x8, 4), 0); TKContext.LogInner("INFO", $"Texture resolution is {uTexture2D.Width}x{uTexture2D.Height}"); int[] offsets = ArrayExtensions.Locate(export.data, BitConverter.GetBytes(PF_SEPERATOR)); uTexture2D.MipMapCount = BitConverter.ToInt32(ArrayExtensions.GetBytesFromByteArray(export.data, offsets[0] - 0x4, 4), 0); uTexture2D.Mipmaps = new List <FTexture2DMipMap>(); TKContext.LogInner("INFO", $"Texture has {uTexture2D.MipMapCount} mipmaps"); uTexture2D.FirstSeperatorOffset = offsets[0]; for (int i = 0; i < uTexture2D.MipMapCount; i++) { FTexture2DMipMap fTexture2DMipMap = new FTexture2DMipMap(); fTexture2DMipMap.UncompressedSize = BitConverter.ToInt32(ArrayExtensions.GetBytesFromByteArray(export.data, offsets[i] + SEPERATOR_UNCOMPRESSED_SIZE_OFFSET, 4), 0); fTexture2DMipMap.TextureUassetOffset = BitConverter.ToInt32(ArrayExtensions.GetBytesFromByteArray(export.data, offsets[i] + SEPERATOR_TEXTURE_START_OFFSET_OFFSET, 4), 0); fTexture2DMipMap.UnknownValue = BitConverter.ToInt32(ArrayExtensions.GetBytesFromByteArray(export.data, offsets[i] + SEPERATOR_UNKNOWN_OFFSET, 4), 0); fTexture2DMipMap.Texture = ArrayExtensions.GetBytesFromByteArray(export.data, offsets[i] + SEPERATOR_TEXTURE_DATA, fTexture2DMipMap.UncompressedSize); fTexture2DMipMap.Width = BitConverter.ToInt32(ArrayExtensions.GetBytesFromByteArray(export.data, offsets[i] + SEPERATOR_TEXTURE_DATA + fTexture2DMipMap.UncompressedSize, 4), 0); fTexture2DMipMap.Height = BitConverter.ToInt32(ArrayExtensions.GetBytesFromByteArray(export.data, offsets[i] + SEPERATOR_TEXTURE_DATA + fTexture2DMipMap.UncompressedSize + 0x4, 4), 0); uTexture2D.Mipmaps.Add(fTexture2DMipMap); TKContext.LogInner("INFO", fTexture2DMipMap.ToString()); } return(uTexture2D); } catch (Exception ex) { TKContext.LogException(ex.ToString()); return(null); } }
public UassetFile(byte[] data, string fullPath) { Fullpath = fullPath; Filename = Path.GetFileNameWithoutExtension(Fullpath); //Create a stream stream = new IOMemoryStream(new MemoryStream(data), true); stream.position = 0; var signature = stream.ReadUInt(); // Check for the file's signature. if (signature != UNREAL_ASSET_MAGIC) { TKContext.LogError("The file provided is not a valid uasset file."); return; } Version = stream.ReadUInt(); stream.ReadBytes(0x10); UnkOffset = stream.ReadInt(); stream.ReadInt(); PackageGroup = Encoding.ASCII.GetString(stream.ReadBytes(0x4)); stream.ReadBytes(0x1); PackageFlags = stream.ReadUInt(); NamesCount = stream.ReadInt(); NamesOffset = stream.ReadInt(); stream.ReadBytes(0x8); ExportsCount = stream.ReadInt(); ExportsOffset = stream.ReadInt(); ImportsCount = stream.ReadInt(); ImportsOffset = stream.ReadInt(); stream.ReadBytes(0x8); UnkOffset2 = stream.ReadInt(); stream.ReadBytes(0x1C); NamesCount2 = stream.ReadInt(); stream.ReadBytes(0x2C); UnkOffset3 = stream.ReadInt(); EndOfFileOffset = stream.ReadInt(); stream.ReadBytes(0x10); UnkOffset4 = stream.ReadInt(); stream.position = NamesOffset; NamesTable = stream.ReadFNameEntries(NamesCount, UE4Version.UE4__4_14); for (int i = 0; i < NamesCount; i++) { TKContext.DebugLog("UassetFile", $"Name Table Entry {i}", NamesTable[i].Name, ConsoleColor.Yellow); } TKContext.LogInner("INFO", $"Uasset names count is {NamesCount}"); //Starts directly after the name table. Assume we're already there ImportsTable = new FObjectImport[ImportsCount]; for (int i = 0; i < ImportsCount; i++) { FObjectImport h = FObjectImport.ReadEntry(stream, this); ImportsTable[i] = h; DebugDump($"FObjectImport {i} @ {h.startPos}", ConsoleColor.Blue, "cType", h.coreType, "u1", h.unknown1.ToString(), "oType", h.objectType, "u2", h.unknown2.ToString(), "i", h.index.ToString(), "name", h.name, "u4", h.unknown4.ToString()); } TKContext.LogInner("INFO", $"Uasset import table size is {ImportsCount}"); //Starts directly after the referenced GameObject table. Assume we're already there ExportsTable = new FObjectExport[ExportsCount]; for (int i = 0; i < ExportsCount; i++) { ExportsTable[i] = FObjectExport.ReadEntry(stream, this); DebugDump($"FObjectExport {i} @ {ExportsTable[i].entryLocation}", ConsoleColor.Magenta, "id", ExportsTable[i].id.ToString(), "u2", ExportsTable[i].unknown2.ToString(), "u3", ExportsTable[i].unknown3.ToString(), "type", ExportsTable[i].type, "u4", ExportsTable[i].unknown4.ToString(), "u5", ExportsTable[i].unknown5.ToString(), "length", ExportsTable[i].dataLength.ToString(), "location", ExportsTable[i].dataLocation.ToString(), "u6", ExportsTable[i].unknown6.ToString(), "u7", ExportsTable[i].unknown7.ToString(), "u8", ExportsTable[i].unknown8.ToString(), "u9", ExportsTable[i].unknown9.ToString(), "u10", ExportsTable[i].unknown10.ToString(), "u11", ExportsTable[i].unknown11.ToString(), "u12", ExportsTable[i].unknown12.ToString(), "u13", ExportsTable[i].unknown13.ToString(), "u14", ExportsTable[i].unknown14.ToString(), "u15", ExportsTable[i].unknown15.ToString(), "u16", ExportsTable[i].unknown16.ToString(), "u17", ExportsTable[i].unknown17.ToString(), "u18", ExportsTable[i].unknown18.ToString(), "u19", ExportsTable[i].unknown19.ToString(), "u20", ExportsTable[i].unknown20.ToString(), "u21", ExportsTable[i].unknown21.ToString(), "u22", ExportsTable[i].unknown22.ToString()); } TKContext.LogInner("INFO", $"Uasset export table size is {ExportsCount}"); using (MemoryStream ms = new MemoryStream()) { stream.position = 0; stream.ms.CopyTo(ms); stream.Close(); FileData = ms.ToArray(); } }