public void Deserialize(BinaryReader reader) { Type = (Types)reader.ReadByte(); switch (Type) { case Types.Null: break; case Types.InternalLink: case Types.UUIDRef: GUID = BaseGGUUID.FromData(reader); break; case Types.ExternalLink: case Types.StreamingRef: GUID = BaseGGUUID.FromData(reader); // This could be a Filename instance - no way to determine the type ExternalFile.Deserialize(reader); break; default: throw new NotImplementedException(); } }
public static HwShader FromData(BinaryReader reader, GameType gameType) { var shader = new HwShader(); // shaderDataLength is discarded uint shaderDataLength = reader.ReadUInt32(); shader.ResourceDataHash = BaseGGUUID.FromData(reader); shader.Unknown1 = reader.ReadUInt32(); shader.TypeMask = (BaseProgramTypeMask)reader.ReadUInt32(); shader.Unknown2 = reader.ReadUInt32();// Related to type mask // Horizon Zero Dawn has it hardcoded for some reason uint shaderEntryCount = gameType switch { GameType.DS => reader.ReadUInt32(), GameType.HZD => 4, _ => throw new NotImplementedException(), }; shader.Programs = new List <ProgramEntry>((int)shaderEntryCount); for (uint i = 0; i < shaderEntryCount; i++) { shader.Programs.Add(ProgramEntry.FromData(reader, gameType)); } uint rootSignatureDataLength = reader.ReadUInt32(); shader.RootSignatureData = reader.ReadBytesStrict(rootSignatureDataLength); return(shader); }
public static GUIDTableContainer FromData(SaveState state) { var container = new GUIDTableContainer(); // Why do they try to keep GUID allocations balanced across 256 tables? I don't see the point for (int i = 0; i < HardcodedTableCount; i++) { int guidCount = state.ReadVariableLengthOffset(); for (int j = 0; j < guidCount; j++) { container._tables[i].Add(BaseGGUUID.FromData(state.Reader)); } } return(container); }
public static HwIndexArray FromData(BinaryReader reader, GameType gameType) { var array = new HwIndexArray(); uint indexElementCount = reader.ReadUInt32(); if (indexElementCount > 0) { array.Flags = reader.ReadUInt32(); var format = (BaseIndexFormat)reader.ReadUInt32(); var streamingMode = (BaseRenderDataStreamingMode)reader.ReadUInt32(); array.ResourceDataHash = BaseGGUUID.FromData(reader); array.Buffer = HwBuffer.FromIndexData(reader, gameType, format, streamingMode, indexElementCount); } return(array); }
public BaseGGUUID ReadIndexedGUID() { if (SaveVersion < 26) { // Inline read of 16 bytes return(BaseGGUUID.FromData(Reader)); } // GUID pool lookup short value = Reader.ReadInt16(); if (value == -1) { return(BaseGGUUID.Empty); } int index = (value >> 8) & 0xFF; int offset = value & 0xFF; return(_GUIDPool.LookupGUID(index, offset)); }
public static HwVertexArray FromData(BinaryReader reader, GameType gameType) { var array = new HwVertexArray(); array.VertexCount = reader.ReadUInt32(); uint streamCount = reader.ReadUInt32(); array.StreamingMode = (BaseRenderDataStreamingMode)reader.ReadByte(); array.Streams = new List <VertexStream>((int)streamCount); for (uint i = 0; i < streamCount; i++) { uint flags = reader.ReadUInt32(); uint byteStride = reader.ReadUInt32(); uint elementDescCount = reader.ReadUInt32(); var stream = new VertexStream(); stream.Flags = flags; stream.ElementInfo = new List <VertexElementDesc>((int)elementDescCount); for (uint j = 0; j < elementDescCount; j++) { stream.ElementInfo.Add(new VertexElementDesc() { ByteOffset = reader.ReadByte(), StorageType = (BaseVertexElementStorageType)reader.ReadByte(), ComponentCount = reader.ReadByte(), ElementType = (BaseVertexElement)reader.ReadByte(), }); } stream.ResourceDataHash = BaseGGUUID.FromData(reader); stream.Buffer = HwBuffer.FromVertexData(reader, gameType, array.StreamingMode, byteStride, array.VertexCount); array.Streams.Add(stream); } return(array); }
public static HwTexture FromData(BinaryReader reader, GameType gameType) { var texture = new HwTexture(); var header = new TextureHeader(); // 32 byte texture header header.Type = (BaseTextureType)reader.ReadByte(); // 0 _ = reader.ReadByte(); // 1 header.Width = reader.ReadUInt16(); // 2 header.Height = reader.ReadUInt16(); // 4 header.ArraySliceCount = 0; header.Depth3D = 0; switch (header.Type) { case BaseTextureType._2D: case BaseTextureType.CubeMap: _ = reader.ReadUInt16(); break; case BaseTextureType._3D: header.Depth3D = 1u << reader.ReadByte(); _ = reader.ReadByte(); break; case BaseTextureType._2DArray: header.ArraySliceCount = reader.ReadUInt16(); break; default: throw new NotImplementedException("Unknown texture type"); } header.MipCount = reader.ReadByte(); // 8 header.PixelFormat = (BasePixelFormat)reader.ReadByte(); // 9 header.Unknown1 = reader.ReadByte(); // 10 header.Unknown2 = reader.ReadByte(); // 11 header.Unknown3 = reader.ReadByte(); // 12 header.Flags = reader.ReadByte(); // 13 header.Unknown4 = reader.ReadByte(); // 14 Something to do with mips. Autogen? header.Unknown5 = reader.ReadByte(); // 15 header.ResourceDataHash = BaseGGUUID.FromData(reader); // 16 texture.Header = header; // Raw pixel data handling uint containerSize = reader.ReadUInt32(); // Size of the remaining data being read long containerEndPosition = reader.BaseStream.Position + containerSize; texture.EmbeddedDataSize = reader.ReadUInt32(); // Size of pixel data in this core object entry. This value is never used. if (a - b > 0) only. uint streamedDataSize = reader.ReadUInt32(); // Size of pixel data in external file. This value is never used. if (a > 0) only. texture.StreamedMipCount = reader.ReadUInt32(); // Number of mipmaps in external file if (gameType == GameType.DS) { texture.DeathStrandingUnknown = reader.ReadUInt64(); } if (streamedDataSize > 0) { texture.StreamHandle = BaseStreamHandle.FromData(reader, gameType); } // TODO: Something is wrong here. EmbeddedDataSize doesn't always match the actual length of the byte array. Why? Does it depend on header flags? if (texture.EmbeddedDataSize > 0) { texture.EmbeddedTextureData = reader.ReadBytesStrict((uint)(containerEndPosition - reader.BaseStream.Position)); } return(texture); }
private void ReadHeaderData() { Reader.BaseStream.Position = _saveDataOffset + _saveDataLength - 0x8; uint typeDataChunkOffset = Reader.ReadUInt32(); uint rawDataChunkOffset = Reader.ReadUInt32(); // String/GUID tables Reader.BaseStream.Position = _saveDataOffset + rawDataChunkOffset; { // UTF-8 strings _stringPool = StringTableContainer.FromData(this); // UTF-16 strings _wideStringPool = WideStringTableContainer.FromData(this); // GUIDs if (SaveVersion >= 26) { _GUIDPool = GUIDTableContainer.FromData(this); } } // Serialized type information and object instances Reader.BaseStream.Position = _saveDataOffset + typeDataChunkOffset; { // Create basic objects that are immediately registered with the engine int objectInstanceTypeCount = ReadVariableLengthOffset(); _localSaveObjects = new Dictionary <int, object>(); for (int i = 0; i < objectInstanceTypeCount; i++) { Type objectType = RTTI.GetTypeByName(ReadIndexedString()); int instanceCount = ReadVariableLengthOffset(); for (int j = 0; j < instanceCount; j++) { int objectId = ReadVariableLengthOffset(); _localSaveObjects.Add(objectId, RTTI.CreateObjectInstance(objectType)); } } // Handles to game data objects int gameDataObjectCount = ReadVariableLengthOffset(); _gameDataObjects = new Dictionary <int, BaseGGUUID>(); for (int i = 0; i < gameDataObjectCount; i++) { int objectId = ReadVariableLengthOffset(); var guid = BaseGGUUID.FromData(Reader); _gameDataObjects.Add(objectId, guid); } // RTTI/class member layouts _RTTIContainer = RTTIMapContainer.FromData(this); // File prefetch int prefetchFileCount = ReadVariableLengthOffset(); _prefetchFilePaths = new List <string>(prefetchFileCount); for (int i = 0; i < prefetchFileCount; i++) { _prefetchFilePaths.Add(ReadIndexedString()); } } Reader.BaseStream.Position = _saveDataOffset; }