Are you trying to tell us you got the game working in 3D or VR? (yea I know the frame rate would be deadly [ugh])
Maybe I did [wacky]
Are you trying to tell us you got the game working in 3D or VR? (yea I know the frame rate would be deadly [ugh])
After spending several days staring at a hex editor I have made a few discoveries.
1) Do not use Cobra Overlay Extractor. It might give some insight as to where to start looking. Apart from that it has some major flaws.
2) I am 99% sure that I can display the structure of all OVL files in a hex editor. This is what has taken the most amount of time to establish.
3) The structure of the ovl files follows the same pattern, but what sections each ovl file contains can very widely. Drilling down into these differences will be my next step, along with writing a procedure to display this info in a viable format.
4) The OVL file does tell you when there will be an associated OVS file. Now to figure out why some files have them and others do not.
I know it does not seem like there is much here and while it may not allow us to get any UGC into the game. It may provide us the means by which to modify the behavior of existing content. It would also be cool to find out how the ovl files are wired into the game and is it possible to get a new ovl file to be accepted by the game.
// OVLHeader
public uint magicNumber;
public byte VersionOrGame;/// Seems to always be 0x8
public byte Unknown1a; // always 18 (12h)
public byte BigEndian; //
public byte Unknown1c; // always 1 //
public byte Unknown2a; // always 148 //
public byte Unknown2b; // always 32 //
public byte Unknown2c; // always 0 //
public byte Unknown2d; // always 0 //
public uint Unknown3; // always 0 //
public uint StringTableSize;
public uint Unknown4; // always 0
public uint OtherCount;
public ushort DirCount;
public ushort LoaderCount;
public uint LoaderSymbolCount1;
public uint LoaderSymbolCount2; /// Same as LoaderSymbolCount1??
public uint PartCount;
public uint ArchiveCount;
public uint archiveHeaderTotal1;
public uint archiveHeaderTotal2; // ???
public uint fsUnk1CountCombined;
public uint fsUnk2CountCombined;
public uint UnknownCount;
public ushort Unknown16a; // always 0
public ushort Unknown16b; // always 0
public ushort Unknown17a; // always 0
public ushort Unknown17b; // always 0
public uint Unknown18; // always 0
public uint ArchiveNamesLength; // Archive Names
public uint FileCount3; /// Same as LoaderSymbolCount1 and LoaderSymbolCount 2??
public uint TypeNamesLength;
public uint Unknown22; // always 0
public uint Unknown23; // always 0
public uint Unknown24; // always 0
public uint Unknown25; // always 0
public uint Unknown26; // always 0
public uint Unknown27; // always 0
public uint Unknown28; // always 0
public uint Unknown29; // always 0
public uint Unknown30; // always 0
public uint Unknown31; // always 0
public uint Unknown32; // always 0
public uint Unknown33; // always 0
public uint Unknown34; // always 0
// OVLLoader
public uint NameStringPointer;
public uint Unknown1;
public uint Hash;
public uint LoaderType;
public uint SymbolStart;
public uint SymbolsToResolve;
// OVLLoaderSymbol
public uint StringPointer;
public uint Hash;
public byte Type;
public byte Unknown2;
public byte LoaderIndex;
public byte Unknown4;
// OVLArchiveHeader
public uint nameIndex;
public uint Block1a;
public uint Block1b;
public uint Block2a;
public uint Block2b;
public uint headerSubTypeCnt;
public uint Block3b;
public uint fsUnk1Count;
public uint headerTypeCnt;
public uint Block5a;
public uint Block5b;
public uint fsUnk2Count;
public uint Block6b;
public uint fsUnk4Count;
public uint fsUnk3Count;
public uint compressedDataStart;
public uint Unknown1;
public uint CompressedDataSize;
public uint DecompressedDataSize;
public uint Unknown2;
public uint Unknown3;
public uint Header2Size;
public uint Unknown5;
// OVLDir
uint nameIndex;
// OVLPart
public uint hash;
public uint nameIndex;
public uint unknown08;
public uint unknown0C;
public uint unknown10;
public uint offset;
// OVLOther
public uint unknown00;
public uint nameIndex;
public uint unknown08;
public uint offset;
// OVLUnknown
public uint unknown00;
public uint unknown04;
public uint unknown08;
public uint offset;
// OVLArchive2
public uint unknown00;
public uint dataSsize;
public int hdrType = 0;
public int subTypeCount = 0;
public int offset = 0;
public uint fileNo;
public uint type;
public uint size1;
public uint unk4;
public uint size2;
public uint unk6;
public uint fileNum = 0;
public uint section = 0;
public uint offset = 0;
public uint section1 = 0;
public uint offset1 = 0;
public uint section2 = 0;
public uint offset2 = 0;
unk1 = br.ReadUInt32();
unk2 = br.ReadUInt32();
long vvv = br.ReadInt64();
Debug.Assert(vvv == 72624977462935551, "Error in OVS!");
br.BaseStream.Position -= 16;
long ttt1 = archiveHeader.Unknown1;
extraHeader = new byte[ttt1];
Array.Copy(pMem, br.BaseStream.Position, extraHeader, 0, ttt1);
br.BaseStream.Position += ttt1;
I have a feeling I am reinventing the wheel here. I am not sure why some people are waiting for me to figure it all out on my own before they contribute their findings.
I kind of stopped working on it once I heard rumors of UGC being added which was my main goal for figuring out the formats. I just realized I didn't include the compressed parts so here those are. It's even more incomplete than the OVL stuff but hopefully it will help some.
I spent a couple of days looking into the ovl and ovs files a while back and was able to load both of them but was sidetracked before spending too much time working on actually dumping the data files out of them. I can tell you that the ovl file header does tell you if it has an ovs file and how many 'archives' are actually in it. So far every file I've looked at has between 1 and 3 archive sections for lack of a better term. The first section is part of the .ovl file itself and the other two are part of the .ovs file. Below are some of the structures in c#. First is the OVLHeader, that is followed by the string table (uses StringTableSize), an array of 'loader' structures (file types, uses LoaderCount), then an array of the loader symbols (files, uses SymbolsToResolve). The archive names come after that (uses ArchiveNamesLength). After that is the archive header (uses ArchiveCount) then the 'dir' structures (uses DirCount). Four more structure arrays follow and use PartCount, OtherCount, UnknownCount, and ArchiveCount again. If you've done that stuff correctly then next part should be the compressed archive data. There's a ton of unknown entries in the structures listed below but hopefully it will help some
Code:// OVLArchiveHeader public uint nameIndex; public uint Block1a; public uint Block1b; public uint Block2a; public uint Block2b; public uint headerSubTypeCnt; public uint Block3b; public uint fsUnk1Count; public uint headerTypeCnt; public uint Block5a; public uint Block5b; public uint fsUnk2Count; public uint Block6b; public uint fsUnk4Count; public uint fsUnk3Count; public uint compressedDataStart; public uint Unknown1; public uint CompressedDataSize; public uint DecompressedDataSize; public uint Unknown2; public uint Unknown3; public uint Header2Size; public uint Unknown5;
uint name_offset
short unknown_04
short padding_06
uint unknown_08
uint unknown_0C
short unknown_10
short unknown_12
uint padding_14
uint unknown_18
uint file_count
uint symbol_count
uint compressed_data_start
uint unknown_28
uint compressed_data_size
uint uncompressed_data_size
uint padding_34
uint unknown_38
uint header2_size
uint unknown_40
char id[4];
ubyte game;
ubyte version; // 12
ubyte BigEndian; // 1 if file uses big-endian, otherwise it uses little-endian
ubyte Unknown_1c; // Seen 1
ubyte Unknown_2a; // Seen 148
ubyte Unknown_2b; // Seen 32
ubyte Unknown_2c; // Seen 0
ubyte Unknown_2d; // Seen 0
uint Unknown_3;
nameIndex = reader.ReadUInt32();
name = stringTable.StringPointer(nameIndex);
Block1a = reader.ReadUInt16();
Block1b = reader.ReadUInt16();
Block2a = reader.ReadUInt16();
Block2b = reader.ReadUInt16();
headerSubTypeCnt = reader.ReadUInt16();
Block3b = reader.ReadUInt16();
fsUnk1Count = reader.ReadUInt16();
headerTypeCnt = reader.ReadUInt16();
Block5a = reader.ReadUInt16();
Block5b = reader.ReadUInt16();
fsUnk2Count = reader.ReadUInt16();
Block6b = reader.ReadUInt16();
fsUnk4Count = reader.ReadUInt32();
fsUnk3Count = reader.ReadUInt32();
compressedDataStart = reader.ReadUInt32();
Unknown1 = reader.ReadUInt32();
CompressedDataSize = reader.ReadUInt32();
DecompressedDataSize = reader.ReadUInt32();
Unknown2 = reader.ReadUInt32();
Unknown3 = reader.ReadUInt32();
Header2Size = reader.ReadUInt32();
Unknown5 = reader.ReadUInt32();
You do know C# has a built in DeflateStream right? [wink]
No I did not know that. I will look into it
The IONIC.ZLIB.DLL is now included with the app.
I will look into the built in stream to see how it works and what it is capable of, Thanks for the heads up .
It's been slow at work lately so I've had time to dig in a little more. So far I'm able to load txt, xml, databases, lua, and some textures. For the textures, the formats vary but they are usually DDS files with the header information removed. So far I've found BC1 and BC3 files, along with some non-compressed RGBA8 and RGBAF32 formats. There's a few formats I haven't had time to figure out like the normal maps. Some other notes, lua scripts appear to be compiled with a custom lua engine, the LUAC_FORMAT value is 2 instead of 0 and it's missing some size information.
The OVSFileSection4 section I posted earlier is actually a patch table. It is used to insert the correct offsets into the structure information pointed to by OVSFileSection3. The first section/offset pair is the location to patch and the second is the value to patch in. Similarly, in the OVL file, The OVLUnknown section actually links the textures in the first compressed section to the LOD versions in the second and third compressed sections. The first value is the offset and the second where to patch it in. The 3rd value appears to always be 0 so I suspect the second and third is really one 64bit entry.
Finally, the OVSFileSection3 usually points to a structure that has more information specific to the type of file. As an example, for lua files it has size information and the start and end offset of the script name. For others such as textures, it has an offset to yet another structure that contains dimensions and mipmap information. I must admit that section3 had me really confused until I figured out the patch table part [happy]
I've considered posting my code somewhere and would prefer to hear something official on it before doing so. I have some concerns, especially in the DLC area since the flags for that appear to be really obvious.
Naah, nothing much should be included in the init overlays - certainly anything you need to edit to add new objects will live either in the main overlay itself (where the databases still live), or creating new overlays per object (which is still supported). I've been quiet on this as I need to check exactly what I'm allowed to say on the matter, but I promise the very select data we store in the newly encrypted init overlays is not important for modding.For those who have been looking into the formats, be aware that the 1.4 update changed the init.ovl files for each content pack. Now they are encrypted which takes care of the DLC for free issue but also probably makes it very difficult to add new objects to the game. Changing or tweaking existing objects should still be doable though.