protected override void ReadInternal(Reader reader)
        {
            flags = reader.ReadUInt32();
            //UnityEngine.Debug.LogWarning("GEO: " + Offset + " - " + flags);
            num_elements        = reader.ReadUInt32();
            off_visualMaterials = Pointer.Read(reader);
            Pointer.DoAt(ref reader, off_visualMaterials, () => {
                off_visualMaterials_array = new Pointer[num_elements];
                visualMaterials           = new VisualMaterial[num_elements];
                for (int i = 0; i < num_elements; i++)
                {
                    off_visualMaterials_array[i] = Pointer.Read(reader);
                    visualMaterials[i]           = VisualMaterial.FromOffsetOrRead(off_visualMaterials_array[i], reader);
                }
            });
            off_elements      = Pointer.Read(reader);
            off_uint1         = Pointer.Read(reader);
            off_num_triangles = Pointer.Read(reader);
            off_unk           = Pointer.Read(reader);
            unk1 = reader.ReadUInt32();
            unk2 = reader.ReadUInt32();

            Pointer.DoAt(ref reader, off_uint1, () => {
                uint1 = new uint[num_elements];
                for (int i = 0; i < num_elements; i++)
                {
                    uint1[i] = reader.ReadUInt32();
                }
            });
            Pointer.DoAt(ref reader, off_num_triangles, () => {
                num_triangles = new uint[num_elements];
                for (int i = 0; i < num_elements; i++)
                {
                    num_triangles[i] = reader.ReadUInt32();
                }
            });
            Pointer.DoAt(ref reader, off_elements, () => {
                off_elements_array = new Pointer[num_elements];
                for (int i = 0; i < num_elements; i++)
                {
                    off_elements_array[i] = Pointer.Read(reader);
                }
            });

            elements = new PS2OptimizedSDCStructureElement[num_elements];
            for (int i = 0; i < num_elements; i++)
            {
                Pointer.DoAt(ref reader, off_elements_array[i], () => {
                    elements[i] = new PS2OptimizedSDCStructureElement(this, i);
                    elements[i].Read(reader);
                });
            }
        }
Exemple #2
0
        public static ScriptNode Read(Reader reader, Pointer offset, Script script) {
            MapLoader l = MapLoader.Loader;
            ScriptNode sn = new ScriptNode(offset);

            sn.script = script;
            sn.param = reader.ReadUInt32();
            sn.param_ptr = Pointer.GetPointerAtOffset(offset); // if parameter is pointer
            if (Settings.s.platform == Settings.Platform.DC) reader.ReadUInt32();

            if (Settings.s.mode == Settings.Mode.Rayman3GC) {
                reader.ReadByte();
                reader.ReadByte();
                reader.ReadByte();
                sn.type = reader.ReadByte();

                reader.ReadByte();
                reader.ReadByte();
                sn.indent = reader.ReadByte();
                reader.ReadByte();
            } else {
                reader.ReadByte();
                reader.ReadByte();
                sn.indent = reader.ReadByte();
                sn.type = reader.ReadByte();
            }
            sn.nodeType = NodeType.Unknown;
            if (Settings.s.aiTypes != null) sn.nodeType = Settings.s.aiTypes.GetNodeType(sn.type);
			
            if (sn.param_ptr != null && sn.nodeType != NodeType.Unknown) {
				//l.print("ScriptNode " + offset + " - " + sn.nodeType + " (" + sn.type + ") - " + sn.param_ptr);
				if (sn.nodeType == NodeType.WayPointRef) {
					WayPoint waypoint = WayPoint.FromOffsetOrRead(sn.param_ptr, reader);
				} else if (sn.nodeType == NodeType.String) {
					Pointer.DoAt(ref reader, sn.param_ptr, () => {
						string str = reader.ReadNullDelimitedString();
						l.strings[sn.param_ptr] = str;
					});
				} else if (sn.nodeType == NodeType.ObjectTableRef) {
					// In R2 some objects have object tables that aren't listed normally, but are referenced through scripts.
				} else if (sn.nodeType == NodeType.Button) {
					EntryAction.FromOffsetOrRead(sn.param_ptr, reader);
				} else if (sn.nodeType == NodeType.GameMaterialRef) {
                    GameMaterial.FromOffsetOrRead(sn.param_ptr, reader);
                } else if (sn.nodeType == NodeType.VisualMaterial) {
                    VisualMaterial.FromOffsetOrRead(sn.param_ptr, reader);
                }
            }
            return sn;
        }
Exemple #3
0
        public void Read(Reader reader)
        {
            offset = Pointer.Current(reader);
            switch (type)
            {
            case DsgVarInfoEntry.DsgVarType.Boolean:
                valueBool = reader.ReadBoolean(); break;

            case DsgVarInfoEntry.DsgVarType.Byte:
                valueByte = reader.ReadSByte(); break;

            case DsgVarInfoEntry.DsgVarType.UByte:
                valueUByte = reader.ReadByte(); break;

            case DsgVarInfoEntry.DsgVarType.Float:
                valueFloat = reader.ReadSingle(); break;

            case DsgVarInfoEntry.DsgVarType.Int:
                valueInt = reader.ReadInt32(); break;

            case DsgVarInfoEntry.DsgVarType.UInt:
                valueUInt = reader.ReadUInt32(); break;

            case DsgVarInfoEntry.DsgVarType.Short:
                valueShort = reader.ReadInt16(); break;

            case DsgVarInfoEntry.DsgVarType.UShort:
                valueUShort = reader.ReadUInt16(); break;

            case DsgVarInfoEntry.DsgVarType.Vector:
                float x = reader.ReadSingle();
                float y = reader.ReadSingle();
                float z = reader.ReadSingle();
                valueVector = new Vector3(x, y, z);
                break;

            case DsgVarInfoEntry.DsgVarType.Text:
                valueText = reader.ReadInt32(); break;

            case DsgVarInfoEntry.DsgVarType.Graph:
                valuePointer = Pointer.Read(reader);
                valueGraph   = Graph.FromOffsetOrRead(valuePointer, reader);
                break;

            case DsgVarInfoEntry.DsgVarType.WayPoint:
                valuePointer  = Pointer.Read(reader);
                valueWayPoint = WayPoint.FromOffsetOrRead(valuePointer, reader);
                break;

            case DsgVarInfoEntry.DsgVarType.GameMaterial:
                valuePointer      = Pointer.Read(reader);
                valueGameMaterial = GameMaterial.FromOffsetOrRead(valuePointer, reader);
                break;

            case DsgVarInfoEntry.DsgVarType.VisualMaterial:
                valuePointer        = Pointer.Read(reader);
                valueVisualMaterial = VisualMaterial.FromOffsetOrRead(valuePointer, reader);
                break;

            case DsgVarInfoEntry.DsgVarType.ObjectList:
                valuePointer    = Pointer.Read(reader);
                valueObjectList = ObjectList.FromOffsetOrRead(valuePointer, reader);
                break;

            case DsgVarInfoEntry.DsgVarType.List:
                valueList = new List();
                valueList.Read(reader);
                break;

            case DsgVarInfoEntry.DsgVarType.Light:
                valuePointer = Pointer.Read(reader);
                valueLight   = MapLoader.Loader.FromOffsetOrRead <LightInfo>(reader, valuePointer);
                break;

            case DsgVarInfoEntry.DsgVarType.Comport:
                valuePointer = Pointer.Read(reader);
                valueComport = MapLoader.Loader.FromOffsetOrRead <Behavior>(reader, valuePointer);
                break;

            case DsgVarInfoEntry.DsgVarType.Input:
                valuePointer = Pointer.Read(reader);
                valueInput   = EntryAction.FromOffsetOrRead(valuePointer, reader);
                break;

            // Fill these in after loading
            case DsgVarInfoEntry.DsgVarType.Perso:
                valuePointer = Pointer.Read(reader);
                // Don't fill in perso yet
                MapLoader.Loader.onPostLoad.Add(InitPostLoad);
                break;

            case DsgVarInfoEntry.DsgVarType.Action:
                valuePointer = Pointer.Read(reader);
                // Don't fill in state yet
                MapLoader.Loader.onPostLoad.Add(InitPostLoad);
                break;

            case DsgVarInfoEntry.DsgVarType.SuperObject:
                valuePointer = Pointer.Read(reader);
                // Don't fill in SO yet
                MapLoader.Loader.onPostLoad.Add(InitPostLoad);
                break;

            // TODO: Figure these out
            case DsgVarInfoEntry.DsgVarType.Caps:
                valueCaps = reader.ReadUInt32(); break;

            case DsgVarInfoEntry.DsgVarType.SOLinks:
                valueSOLinks = reader.ReadUInt32(); break;

            case DsgVarInfoEntry.DsgVarType.SoundEvent:
                valueSoundEvent = reader.ReadUInt32(); break;

            case DsgVarInfoEntry.DsgVarType.Way:
                valueWay = reader.ReadUInt32(); break;

            // Arrays
            case DsgVarInfoEntry.DsgVarType.ActionArray:
            case DsgVarInfoEntry.DsgVarType.FloatArray:
            case DsgVarInfoEntry.DsgVarType.IntegerArray:
            case DsgVarInfoEntry.DsgVarType.PersoArray:
            case DsgVarInfoEntry.DsgVarType.SoundEventArray:
            case DsgVarInfoEntry.DsgVarType.SuperObjectArray:
            case DsgVarInfoEntry.DsgVarType.TextArray:
            case DsgVarInfoEntry.DsgVarType.TextRefArray:
            case DsgVarInfoEntry.DsgVarType.VectorArray:
            case DsgVarInfoEntry.DsgVarType.WayPointArray:
            case DsgVarInfoEntry.DsgVarType.GraphArray:
            case DsgVarInfoEntry.DsgVarType.Array11:
            case DsgVarInfoEntry.DsgVarType.Array9:
                ReadArray(reader); break;
            }
        }
Exemple #4
0
        public static Sector Read(Reader reader, Pointer offset, SuperObject so)
        {
            MapLoader l = MapLoader.Loader;
            Sector    s = new Sector(offset, so);

            s.name = "Sector @ " + offset + ", SPO @ " + so.offset;
            //l.print(s.name);
            if (Settings.s.engineVersion <= Settings.EngineVersion.Montreal)
            {
                if (Settings.s.game == Settings.Game.TTSE)
                {
                    reader.ReadUInt32();                                        // always 1 or 0. whether the sector is active or not?
                }
                Pointer off_collideObj = Pointer.Read(reader);
                Pointer.DoAt(ref reader, off_collideObj, () => {
                    //CollideMeshObject collider = CollideMeshObject.Read(reader, off_collideObj);
                    // This has the exact same structure as a CollideMeshObject but with a sector superobject as material for the collieMeshElements
                });
                LinkedList <int> .ReadHeader(reader, Pointer.Current(reader), type : LinkedList.Type.Double); // "environments list"

                LinkedList <int> .ReadHeader(reader, Pointer.Current(reader), type : LinkedList.Type.Double); // "surface list"
            }
            s.persos = LinkedList <Perso> .ReadHeader(reader, Pointer.Current(reader), type : LinkedList.Type.Double);

            s.staticLights = LinkedList <LightInfo> .Read(ref reader, Pointer.Current(reader),
                                                          (off_element) => {
                LightInfo li = l.FromOffsetOrRead <LightInfo>(reader, off_element);
                if (li != null)
                {
                    li.containingSectors.Add(s);
                }
                return(li);
            },
                                                          flags : LinkedList.Flags.ElementPointerFirst
                                                          | LinkedList.Flags.ReadAtPointer
                                                          | ((Settings.s.hasLinkedListHeaderPointers) ?
                                                             LinkedList.Flags.HasHeaderPointers :
                                                             LinkedList.Flags.NoPreviousPointersForDouble),
                                                          type : LinkedList.Type.Minimize
                                                          );

            s.dynamicLights = LinkedList <int> .ReadHeader(reader, Pointer.Current(reader), type : LinkedList.Type.Double);

            if (Settings.s.engineVersion <= Settings.EngineVersion.Montreal)
            {
                LinkedList <int> .ReadHeader(reader, Pointer.Current(reader)); // "streams list", probably related to water
            }
            s.neighbors = LinkedList <NeighborSector> .ReadHeader(reader, Pointer.Current(reader), type : LinkedList.Type.Minimize);

            s.sectors_unk1 = LinkedList <NeighborSector> .ReadHeader(reader, Pointer.Current(reader), type : LinkedList.Type.Minimize);

            s.sectors_unk2 = LinkedList <Sector> .ReadHeader(reader, Pointer.Current(reader), type : LinkedList.Type.Minimize);

            LinkedList <int> .ReadHeader(reader, Pointer.Current(reader)); // Placeholder

            LinkedList <int> .ReadHeader(reader, Pointer.Current(reader)); // Placeholder

            if (Settings.s.engineVersion > Settings.EngineVersion.Montreal)
            {
                s.sectorBorder = BoundingVolume.Read(reader, Pointer.Current(reader), BoundingVolume.Type.Box);
                reader.ReadUInt32();
                if (Settings.s.game == Settings.Game.R2Revolution || Settings.s.game == Settings.Game.LargoWinch)
                {
                    s.isSectorVirtual = reader.ReadByte();
                    reader.ReadByte();
                    s.sectorPriority = reader.ReadByte();
                    reader.ReadByte();
                }
                else
                {
                    s.isSectorVirtual = reader.ReadByte();
                    reader.ReadByte();
                    reader.ReadByte();
                    s.sectorPriority = reader.ReadByte();
                    if (Settings.s.engineVersion <= Settings.EngineVersion.R2)
                    {
                        s.off_skyMaterial = Pointer.Read(reader);
                        s.skyMaterial     = VisualMaterial.FromOffsetOrRead(s.off_skyMaterial, reader);
                    }
                    else
                    {
                        reader.ReadUInt32();
                    }
                    reader.ReadByte();
                    if (Settings.s.hasNames)
                    {
                        s.name = reader.ReadString(0x104);
                        l.print(s.name);
                    }
                }
            }
            else
            {
                if (Settings.s.engineVersion == Settings.EngineVersion.Montreal)
                {
                    reader.ReadUInt32();
                    reader.ReadUInt32();
                    reader.ReadUInt32();
                    reader.ReadUInt32();
                }
                if (Settings.s.game != Settings.Game.TTSE)
                {
                    reader.ReadUInt32();
                }
                Pointer off_name = Pointer.Read(reader);
                Pointer.DoAt(ref reader, off_name, () => {
                    s.name = reader.ReadNullDelimitedString() + " @ " + offset;
                });
            }

            /*if(num_subsectors_unk > 0 && off_subsector_unk_first != null) { // only for father sector
             *  R3Pointer off_subsector_next = off_subsector_unk_first;
             *  for (int i = 0; i < num_subsectors_unk; i++) {
             *      R3Pointer.Goto(ref reader, off_subsector_next);
             *      R3Pointer off_subsector = R3Pointer.Read(reader);
             *      off_subsector_next = R3Pointer.Read(reader);
             *      R3Pointer off_subsector_prev = R3Pointer.Read(reader);
             *      R3Pointer off_sector_start = R3Pointer.Read(reader);
             *      if (off_subsector != null) {
             *          sect.neighborsPointers.Add(off_subsector);
             *      }
             *  }
             * }*/

            l.sectors.Add(s);
            return(s);
        }
        async Task LoadPS2()
        {
            await WaitIfNecessary();

            textures = new TextureInfo[0];

            loadingState = "Loading fixed memory";
            await WaitIfNecessary();

            files_array[Mem.Fix].GotoHeader();
            Reader  reader       = files_array[Mem.Fix].reader;
            Pointer off_base_fix = Pointer.Current(reader);

            loadingState = "Loading input struct";
            await WaitIfNecessary();

            for (int i = 0; i < Settings.s.numEntryActions; i++)
            {
                Pointer.Read(reader);                 // 3DOS_EntryActions
            }

            inputStruct = InputStructure.Read(reader, Pointer.Current(reader));
            foreach (EntryAction ea in inputStruct.entryActions)
            {
                print(ea.ToString());
            }
            localization = FromOffsetOrRead <LocalizationStructure>(reader, Pointer.Current(reader), inline: true);

            /*
             * Pointer off_inputStructure = Pointer.Read(reader);
             * Pointer.DoAt(ref reader, off_inputStructure, () => {
             * inputStruct = InputStructure.Read(reader, off_inputStructure);
             *      foreach (EntryAction ea in inputStruct.entryActions) {
             *              print(ea.ToString());
             *      }
             * });*/


            /*uint base_language = reader.ReadUInt32(); //Pointer off_language = Pointer.Read(reader);
             * reader.ReadUInt32();
             * uint num_text_language = reader.ReadUInt32();
             * reader.ReadUInt16();
             * reader.ReadUInt16();
             * reader.ReadUInt32(); // base
             * Pointer off_text_general = Pointer.Read(reader);
             * Pointer.DoAt(ref reader, off_text_general, () => {
             * fontStruct = FontStructure.Read(reader, off_text_general);
             * });
             * Pointer off_inputStructure = Pointer.Read(reader);
             * Pointer.DoAt(ref reader, off_inputStructure, () => {
             * inputStruct = InputStructure.Read(reader, off_inputStructure);
             *      foreach (EntryAction ea in inputStruct.entryActions) {
             *              print(ea.ToString());
             *      }
             * });
             *
             * await WaitIfNecessary();
             * Pointer.Read(reader);
             * Pointer.Read(reader);
             * Pointer.Read(reader);
             * Pointer.Read(reader);
             * Pointer.Read(reader);
             * Pointer.Read(reader);
             * Pointer.Read(reader);
             * Pointer.Read(reader);
             * Pointer.Read(reader);
             * Pointer.Read(reader);
             * Pointer.Read(reader);
             * Pointer.Read(reader);
             * reader.ReadUInt32();
             * reader.ReadUInt32();
             * reader.ReadUInt32();
             * reader.ReadUInt32();
             * reader.ReadUInt32();
             * reader.ReadUInt32();
             * reader.ReadUInt32();
             * reader.ReadUInt32();
             * reader.ReadUInt32();
             * reader.ReadUInt32();
             * Pointer.Read(reader);
             * Pointer off_levelNames = Pointer.Read(reader);
             * Pointer off_languages = Pointer.Read(reader);
             * uint num_levelNames = reader.ReadUInt32();
             * uint num_languages = reader.ReadUInt32();
             * reader.ReadUInt32(); // same as num_levelNames
             * Pointer.DoAt(ref reader, off_levelNames, () => {
             * lvlNames = new string[num_levelNames];
             * for (uint i = 0; i < num_levelNames; i++) {
             * lvlNames[i] = reader.ReadString(0x1E);
             * }
             * });
             * Pointer.DoAt(ref reader, off_languages, () => {
             * ReadLanguages(reader, off_languages, num_languages);
             * });
             * if (languages != null && fontStruct != null) {
             * for (int i = 0; i < num_languages; i++) {
             * loadingState = "Loading text files: " + (i+1) + "/" + num_languages;
             * string langFilePath = gameDataBinFolder + "TEXTS/" + languages[i].ToUpper() + ".LNG";
             * await PrepareFile(langFilePath));
             * files_array[2] = new DCDAT(languages[i], langFilePath, 2);
             * ((DCDAT)files_array[2]).SetHeaderOffset(base_language);
             * files_array[2].GotoHeader();
             * fontStruct.ReadLanguageTableDreamcast(files_array[2].reader, i, (ushort)num_text_language);
             * files_array[2].Dispose();
             * }
             * }
             *
             * loadingState = "Loading fixed textures";
             * await WaitIfNecessary();
             * Pointer off_events_fix = Pointer.Read(reader);
             * uint num_events_fix = reader.ReadUInt32();
             * uint num_textures_fix = reader.ReadUInt32();
             * Pointer off_textures_fix = Pointer.Read(reader);
             * Pointer.DoAt(ref reader, off_textures_fix, () => {
             * Array.Resize(ref textures, (int)num_textures_fix);
             * for (uint i = 0; i < num_textures_fix; i++) {
             * Pointer off_texture = Pointer.Read(reader);
             * textures[i] = null;
             * Pointer.DoAt(ref reader, off_texture, () => {
             * textures[i] = TextureInfo.Read(reader, off_texture);
             * });
             * }
             * TEX tex = new TEX(tplPaths[0]);
             * for (uint i = 0; i < num_textures_fix; i++) {
             * if (textures[i] != null && tex.Count > i) {
             * textures[i].Texture = tex.textures[i];
             * }
             * }
             * });*/
            loadingState = "Loading level memory";
            await WaitIfNecessary();

            files_array[Mem.Lvl].GotoHeader();
            reader = files_array[Mem.Lvl].reader;
            string build = reader.ReadString(0x20);

            reader.ReadUInt32();
            reader.ReadUInt32();             // 0xc
            reader.ReadUInt32();             // 0
            Pointer.Read(reader);
            Pointer.Read(reader);

            // Globals
            globals.off_actualWorld  = Pointer.Read(reader);
            globals.off_dynamicWorld = Pointer.Read(reader);
            globals.off_fatherSector = Pointer.Read(reader);
            globals.num_always       = reader.ReadUInt32();
            globals.spawnablePersos  = LinkedList <Perso> .ReadHeader(reader, Pointer.Current(reader), LinkedList.Type.Double);

            //globals.spawnablePersos.FillPointers(reader, globals.spawnablePersos.off_tail, globals.spawnablePersos.offset);
            Pointer.Read(reader);                                 // format: (0x4 number, number * 0x4: null)
            globals.off_always_reusableSO = Pointer.Read(reader); // There are (num_always) empty SuperObjects starting with this one.
            Pointer.Read(reader);
            Pointer.Read(reader);
            Pointer.Read(reader);
            Pointer.Read(reader);
            Pointer.Read(reader);

            LinkedList <Perso> cameras = LinkedList <Perso> .ReadHeader(reader, Pointer.Current(reader), LinkedList.Type.Double);

            families = LinkedList <Family> .ReadHeader(reader, Pointer.Current(reader), type : LinkedList.Type.Double);

            LinkedList <Perso> mainChars = LinkedList <Perso> .ReadHeader(reader, Pointer.Current(reader), LinkedList.Type.Double);

            Pointer.Read(reader);                      // Rayman
            reader.ReadUInt32();
            globals.off_camera = Pointer.Read(reader); // Camera
            Pointer.Read(reader);
            Pointer.Read(reader);
            Pointer.Read(reader);

            uint numMeshes             = (uint)files_array[Mem.Lvl].extraData["numMeshes"];
            uint numMaterials          = (uint)files_array[Mem.Lvl].extraData["numMaterials"];
            uint numTextures           = (uint)files_array[Mem.Lvl].extraData["numTextures"];
            uint numLightmappedObjects = (uint)files_array[Mem.Lvl].extraData["numLightmappedObjects"];

            //print("numTextures " + numTextures + " - " + txds[0].Count + " - " + numMeshes + " - " + ato.numAtomics + " - " + numLightmappedObjects);


            textures = new TextureInfo[numTextures];
            Pointer[] off_meshes = new Pointer[numMeshes];
            off_materials = new Pointer[numMaterials];
            for (int i = 0; i < numMeshes; i++)
            {
                off_meshes[i] = Pointer.Read(reader);
            }
            for (int i = 0; i < numMaterials; i++)
            {
                off_materials[i] = Pointer.Read(reader);
            }
            for (int i = 0; i < numTextures; i++)
            {
                Pointer off_textureInfo = Pointer.Read(reader);
                int     texture_index   = reader.ReadInt32();
                Pointer.DoAt(ref reader, off_textureInfo, () => {
                    textures[i]         = TextureInfo.Read(reader, off_textureInfo);
                    textures[i].Texture = txds[0].Lookup(texture_index.ToString("D3"));
                    //textures[i].Texture = txds[0].textures[txds[0].Count - 1 - texture_index];
                });
            }
            Pointer.Read(reader);
            reader.ReadUInt32();
            reader.ReadUInt32();
            Pointer.Read(reader);
            uint num_unk = reader.ReadUInt32();

            for (int i = 0; i < num_unk; i++)
            {
                Pointer.Read(reader);
            }
            uint num_unk2 = reader.ReadUInt32();

            for (int i = 0; i < num_unk2; i++)
            {
                Pointer.Read(reader);
            }
            Pointer.Read(reader);
            reader.ReadSingle();             // a bounding volume most likely
            reader.ReadSingle();
            reader.ReadSingle();
            reader.ReadSingle();
            reader.ReadSingle();
            reader.ReadSingle();
            Pointer.Read(reader);
            reader.ReadUInt32();             // 2?
            uint    num_poTable = reader.ReadUInt32();
            Pointer off_poTable = Pointer.Read(reader);

            reader.ReadUInt32();             // 1. 10x 0
            reader.ReadUInt32();             // 2
            reader.ReadUInt32();             // 3
            reader.ReadUInt32();             // 4
            reader.ReadUInt32();             // 5
            reader.ReadUInt32();             // 6
            reader.ReadUInt32();             // 7
            reader.ReadUInt32();             // 8
            reader.ReadUInt32();             // 9
            reader.ReadUInt32();             // 10
            uint num_lightCookies = reader.ReadUInt32();

            lightCookieColors = new Color[num_lightCookies];
            for (int i = 0; i < num_lightCookies; i++)
            {
                reader.ReadUInt32();
                reader.ReadUInt32();
                reader.ReadUInt32();
                reader.ReadUInt32();
                byte b = reader.ReadByte();
                byte g = reader.ReadByte();
                byte r = reader.ReadByte();
                reader.ReadByte();
                lightCookieColors[i] = new Color(r / 255f, g / 255f, b / 255f, 1f);
                reader.ReadUInt32();
                reader.ReadInt32();
                reader.ReadUInt32();
            }
            for (int i = 0; i < num_lightCookies; i++)
            {
                reader.ReadByte();
            }
            reader.Align(0x4);
            Pointer off_lightCookieMaterial = Pointer.Read(reader);

            lightCookieMaterial = VisualMaterial.FromOffsetOrRead(off_lightCookieMaterial, reader);
            off_lightmapUV      = new Pointer[numLightmappedObjects];
            for (int i = 0; i < numLightmappedObjects; i++)
            {
                reader.ReadUInt32();
                reader.ReadUInt32();
                reader.ReadUInt32();
                off_lightmapUV[i] = Pointer.Read(reader);
            }



            for (int i = 0; i < numMaterials; i++)
            {
                VisualMaterial.FromOffsetOrRead(off_materials[i], reader);
            }
            for (int i = 0; i < numMeshes; i++)
            {
                Pointer.DoAt(ref reader, off_meshes[i], () => {
                    GeometricObject mesh = GeometricObject.Read(reader, off_meshes[i]);
                    meshObjects.Add(mesh);
                    //print("Mesh " + i + ": " + mesh.num_vertices + " - " + mesh.subblock_types[0] + " - " + mesh.num_subblocks);
                });
            }

            loadingState = "Loading families";
            await WaitIfNecessary();

            ReadFamilies(reader);
            //print("Families: " + families.Count);
            loadingState = "Loading superobject hierarchy";
            await WaitIfNecessary();

            ReadSuperObjects(reader);
            loadingState = "Loading always structure";
            await WaitIfNecessary();

            ReadAlways(reader);
            loadingState = "Filling in cross-references";
            await WaitIfNecessary();

            ReadCrossReferences(reader);
            await WaitIfNecessary();
        }