public void ReadBinary(ArkArchive archive, ReadingOptions options)
        {
            readBinaryHeader(archive);

            if (SaveVersion > 5)
            {
                // Name table is located after the objects block, but will be needed to read the objects block
                readBinaryNameTable(archive);
            }

            readBinaryDataFiles(archive, options);
            readBinaryEmbeddedData(archive, options);
            readBinaryDataFilesObjectMap(archive, options);
            readBinaryObjects(archive, options);
            readBinaryObjectProperties(archive, options);

            if (SaveVersion > 6)
            {
                readBinaryHibernation(archive, options);
            }

            // Parse creatures in cryopods and soultraps (from the mod DinoStorageV2)
            foreach (var cryo in this.Objects.Where(x => x.ClassString.Contains("Cryop") || x.ClassString.Contains("SoulTrap_")).ToList())
            {
                ArkArrayStruct     customItemDatas = cryo.GetPropertyValue <IArkArray, ArkArrayStruct>("CustomItemDatas");
                StructPropertyList customDinoData  = (StructPropertyList)customItemDatas?.FirstOrDefault(cd => ((StructPropertyList)cd).GetTypedProperty <PropertyName>("CustomDataName").Value.Name == "Dino");
                PropertyStruct     customDataBytes = customDinoData?.Properties.FirstOrDefault(p => p.NameString == "CustomDataBytes") as PropertyStruct;
                PropertyArray      byteArrays      = (customDataBytes?.Value as StructPropertyList)?.Properties.FirstOrDefault(property => property.NameString == "ByteArrays") as PropertyArray;
                ArkArrayStruct     byteArraysValue = byteArrays?.Value as ArkArrayStruct;
                if (!(byteArraysValue?.Any() ?? false))
                {
                    continue;
                }

                ArkArrayUInt8 creatureBytes = ((byteArraysValue?[0] as StructPropertyList)?.Properties.FirstOrDefault(p => p.NameString == "Bytes") as PropertyArray)?.Value as ArkArrayUInt8;
                if (creatureBytes == null)
                {
                    continue;
                }

                var cryoStream = new System.IO.MemoryStream(creatureBytes.ToArray <byte>());

                using (ArkArchive cryoArchive = new ArkArchive(cryoStream))
                {
                    // number of serialized objects
                    int objCount = cryoArchive.ReadInt();
                    if (objCount == 0)
                    {
                        continue;
                    }

                    var storedGameObjects = new List <GameObject>(objCount);
                    for (int oi = 0; oi < objCount; oi++)
                    {
                        storedGameObjects.Add(new GameObject(cryoArchive));
                    }
                    foreach (var ob in storedGameObjects)
                    {
                        ob.LoadProperties(cryoArchive, new GameObject(), 0);
                    }

                    // assume the first object is the creature object
                    string creatureActorId = storedGameObjects[0].Names[0].ToString();
                    storedGameObjects[0].IsCryo = true;

                    // the tribe name is stored in `TamerString`, non-cryoed creatures have the property `TribeName` for that.
                    if (!storedGameObjects[0].HasAnyProperty("TribeName") && storedGameObjects[0].HasAnyProperty("TamerString"))
                    {
                        storedGameObjects[0].Properties.Add(new PropertyString("TribeName", storedGameObjects[0].GetPropertyValue <string>("TamerString")));
                    }

                    // add cryopod object as parent to all child objects of the creature object (ActorIDs are not unique across cryopodded and non-cryopodded creatures)
                    // assume that child objects are stored after their parent objects
                    foreach (var ob in storedGameObjects)
                    {
                        int nIndex = ob.Names.FindIndex(n => n.ToString() == creatureActorId);
                        if (nIndex != -1)
                        {
                            ob.Names.Insert(nIndex + 1, cryo.Names[0]);
                            addObject(ob, true);
                        }
                    }

                    // assign the created ID of the dinoStatusComponent to the creature's property.
                    var statusComponentObject = storedGameObjects.FirstOrDefault(ob => ob.ClassString?.StartsWith("DinoCharacterStatusComponent") ?? false);
                    if (statusComponentObject != null)
                    {
                        var statusComponentRef = storedGameObjects[0].GetTypedProperty <PropertyObject>("MyCharacterStatusComponent");
                        statusComponentRef.Value.ObjectId = statusComponentObject.Id;
                    }
                }
            }

            OldNameList    = archive.HasUnknownNames ? archive.NameTable : null;
            HasUnknownData = archive.HasUnknownData;
        }
        private void extractBinaryObjectCryopods(ReadingOptions options)
        {
            if (!options.CryopodCreatures)
            {
                return;
            }

            // Parse creatures in cryopods and soultraps (from the mod DinoStorageV2)
            var cryopods = Objects.Where(x => x.ClassString.Contains("Cryop") || x.ClassString.Contains("SoulTrap_")).ToArray();

            foreach (var cryo in cryopods)
            {
                ArkArrayStruct     customItemDatas = cryo.GetPropertyValue <IArkArray, ArkArrayStruct>("CustomItemDatas");
                StructPropertyList customDinoData  = (StructPropertyList)customItemDatas?.FirstOrDefault(cd => ((StructPropertyList)cd).GetTypedProperty <PropertyName>("CustomDataName").Value.Name == "Dino");
                PropertyStruct     customDataBytes = customDinoData?.Properties.FirstOrDefault(p => p.NameString == "CustomDataBytes") as PropertyStruct;
                PropertyArray      byteArrays      = (customDataBytes?.Value as StructPropertyList)?.Properties.FirstOrDefault(property => property.NameString == "ByteArrays") as PropertyArray;
                ArkArrayStruct     byteArraysValue = byteArrays?.Value as ArkArrayStruct;
                if (!(byteArraysValue?.Any() ?? false))
                {
                    continue;
                }

                ArkArrayUInt8 creatureBytes = ((byteArraysValue[0] as StructPropertyList)?.Properties.FirstOrDefault(p => p.NameString == "Bytes") as PropertyArray)?.Value as ArkArrayUInt8;
                if (creatureBytes == null)
                {
                    continue;
                }

                var cryoStream = new System.IO.MemoryStream(creatureBytes.ToArray <byte>());

                using (ArkArchive cryoArchive = new ArkArchive(cryoStream))
                {
                    // number of serialized objects
                    int objCount = cryoArchive.ReadInt();
                    if (objCount == 0)
                    {
                        continue;
                    }

                    var storedGameObjects = new List <GameObject>(objCount);
                    for (int oi = 0; oi < objCount; oi++)
                    {
                        storedGameObjects.Add(new GameObject(cryoArchive));
                    }
                    foreach (var ob in storedGameObjects)
                    {
                        ob.LoadProperties(cryoArchive, new GameObject(), 0);
                    }

                    // assume the first object is the creature object
                    string creatureActorId = storedGameObjects[0].Names[0].ToString();
                    storedGameObjects[0].IsCryo = true;

                    // the tribe name is stored in `TamerString`, non-cryoed creatures have the property `TribeName` for that.
                    if (!storedGameObjects[0].HasAnyProperty("TribeName") && storedGameObjects[0].HasAnyProperty("TamerString"))
                    {
                        storedGameObjects[0].Properties.Add(new PropertyString("TribeName", storedGameObjects[0].GetPropertyValue <string>("TamerString")));
                    }

                    // add cryopod object as parent to all child objects of the creature object (ActorIDs are not unique across cryopodded and non-cryopodded creatures)
                    // assume that child objects are stored after their parent objects
                    for (int i = 0; i < objCount; i++)
                    {
                        var ob     = storedGameObjects[i];
                        int nIndex = ob.Names.FindIndex(n => n.ToString() == creatureActorId);
                        if (nIndex != -1)
                        {
                            ob.Names.Insert(nIndex + 1, cryo.Names[0]);
                            addObject(ob, false); // processing the names can cause conflicts with reused ids
                        }

                        if (i == 0)
                        {
                            for (int ii = 1; ii < objCount; ii++)
                            {
                                ob.AddComponent(storedGameObjects[ii]);
                            }
                        }
                        else
                        {
                            ob.Parent = storedGameObjects[0];
                        }
                    }

                    // assign the created ID of the components to the creature's properties
                    AssignComponentId("DinoCharacterStatusComponent", "MyCharacterStatusComponent");
                    AssignComponentId("DinoTamedInventoryComponent", "MyInventoryComponent");

                    void AssignComponentId(string classStringStartsWith, string propertyName)
                    {
                        var statusComponentObject = storedGameObjects.FirstOrDefault(ob => ob.ClassString?.StartsWith(classStringStartsWith) ?? false);

                        if (statusComponentObject == null)
                        {
                            return;
                        }
                        var statusComponentRef = storedGameObjects[0].GetTypedProperty <PropertyObject>(propertyName);

                        if (statusComponentRef != null)
                        {
                            statusComponentRef.Value.ObjectId = statusComponentObject.Id;
                        }
                    }
                }
            }
        }