示例#1
0
        public void InitPostLoad()
        {
            switch (type)
            {
            // Fill these in after loading
            case DsgVarInfoEntry.DsgVarType.Perso:
                SuperObject so = SuperObject.FromOffset(valuePointer);
                if (so != null)
                {
                    valuePerso = so.data as Perso;
                }
                break;

            case DsgVarInfoEntry.DsgVarType.Action:
                valueAction = State.FromOffset(valuePointer);
                break;

            case DsgVarInfoEntry.DsgVarType.SuperObject:
                valueSuperObject = SuperObject.FromOffset(valuePointer);
                break;
            }

            if (dsgMem != null)
            {
                RegisterReferences(dsgMem);
            }
        }
示例#2
0
        public void InitPostLoad()
        {
            switch (nodeType)
            {
            case NodeType.GraphRef:
                Graph graphRef = Graph.FromOffset(param_ptr);
                if (graphRef != null)
                {
                    graphRef.References.referencedByNodes.Add(this);
                }
                else
                {
                    Debug.LogWarning("Couldn't add ScriptNode reference to Graph offset " + param_ptr);
                }
                break;

            case NodeType.PersoRef:
                Perso persoRef = Perso.FromOffset(param_ptr);
                if (persoRef != null)
                {
                    persoRef.References.referencedByNodes.Add(this);
                }
                else
                {
                    Debug.LogWarning("Couldn't add ScriptNode reference to Perso offset " + param_ptr);
                }
                break;

            case NodeType.SectorRef:
                Sector sectorRef = Sector.FromOffset(param_ptr);
                if (sectorRef != null)
                {
                    sectorRef.References.referencedByNodes.Add(this);
                }
                else
                {
                    Debug.LogWarning("Couldn't add ScriptNode reference to Sector offset " + param_ptr);
                }
                break;

            case NodeType.SuperObjectRef:
                SuperObject superObjectRef = SuperObject.FromOffset(param_ptr);
                if (superObjectRef != null)
                {
                    superObjectRef.References.referencedByNodes.Add(this);
                }
                else
                {
                    Debug.LogWarning("Couldn't add ScriptNode reference to SuperObject offset " + param_ptr);
                }
                break;

            default: return;
            }
        }
示例#3
0
    public void Init()
    {
        if (MapLoader.Loader is OpenSpace.Loader.R3Loader)
        {
            MapLoader l = MapLoader.Loader;
            foreach (SuperObject so in l.superObjects)
            {
                if (so.type == SuperObject.Type.IPO_2)
                {
                    //Debug.LogWarning("TYPE 2 " + so.Gao.name);
                    Portal portal = new Portal()
                    {
                        containerSO  = so,
                        containerIPO = so.data as IPO
                    };
                    portal.cameraSO = SuperObject.FromOffset(portal.containerIPO.off_portalCamera);
                    GeometricObject geo = portal.containerIPO.data.visualSet[0].obj as GeometricObject;
                    portal.geometricObject = geo;
                    if (geo != null)
                    {
                        GeometricObjectElementTriangles el = geo.elements[0] as GeometricObjectElementTriangles;
                        portal.meshElement = el;
                        portal.material    = el.Gao.GetComponent <Renderer>().sharedMaterial;
                        //Debug.LogWarning(so.type + " - " + portal.containerIPO.offset + " - " + portal.containerIPO.off_portalCamera);
                        if (portal.cameraSO != null)
                        {
                            GameObject camGao = new GameObject("Portal Camera - " + portal.containerIPO.Gao.name + " - " + portal.cameraSO.Gao.name);
                            Camera     camera = camGao.AddComponent <Camera>();
                            camGao.transform.position   = portal.cameraSO.matrix.GetPosition(true);
                            camGao.transform.rotation   = portal.cameraSO.matrix.GetRotation(true) * Quaternion.Euler(-180, 0, 0);
                            camGao.transform.localScale = portal.cameraSO.matrix.GetScale(true);
                            camera.fieldOfView          = Camera.main.fieldOfView;
                            camera.enabled = false;
                            camGao.transform.SetParent(transform);
                            portal.camera = camera;
                            portals.Add(portal);
                        }
                        else
                        {
                            // it's a mirror
                            portal.isMirror = true;
                            GameObject camGao = new GameObject("Mirror Camera - " + portal.containerIPO.Gao.name);
                            Camera     camera = camGao.AddComponent <Camera>();
                            camGao.transform.position = geo.vertices[0];

                            /*camGao.transform.rotation = portal.cameraSO.matrix.GetRotation(true) * Quaternion.Euler(-180, 0, 0);
                             * camGao.transform.localScale = portal.cameraSO.matrix.GetScale(true);*/
                            camera.fieldOfView = Camera.main.fieldOfView;
                            camera.enabled     = false;
                            camGao.transform.SetParent(transform);
                            portal.camera = camera;
                            portals.Add(portal);
                        }

                        el.Gao.layer = LayerMask.NameToLayer("VisualMirror");
                        PortalBehaviour pb = el.Gao.AddComponent <PortalBehaviour>();
                        pb.m_ReflectLayers = (1 << LayerMask.NameToLayer("Visual")) | (1 << LayerMask.NameToLayer("VisualOnlyInMirror"));
                        pb.portal          = portal;
                        pb.textureIndex    = portal.material.GetInt("_NumTextures");
                        portal.material.SetInt("_NumTextures", pb.textureIndex + 1);
                    }
                }
            }
        }
        loaded = true;
    }
示例#4
0
        public string ToString(Perso perso, TranslatedScript.TranslationSettings ts, bool advanced = false)
        {
            MapLoader l    = MapLoader.Loader;
            short     mask = 0;

            AITypes aiTypes = Settings.s.aiTypes;

            Vector3 vector3 = new Vector3 {
                x = 0, y = 0, z = 0
            };

            switch (nodeType)
            {
            case ScriptNode.NodeType.KeyWord:                     // KeyWordFunctionPtr
                if (param < aiTypes.keywordTable.Length)
                {
                    if (ts.exportMode)
                    {
                        if (aiTypes.keywordTable[param] == "Me")
                        {
                            return("this");
                        }
                        if (aiTypes.keywordTable[param] == "MainActor")
                        {
                            return("Controller.MainActor");
                        }
                        if (aiTypes.keywordTable[param] == "Nobody" || aiTypes.keywordTable[param] == "NoInput" || aiTypes.keywordTable[param] == "Nowhere" || aiTypes.keywordTable[param] == "NoGraph" || aiTypes.keywordTable[param] == "NoAction" || aiTypes.keywordTable[param] == "CapsNull")
                        {
                            return("null");
                        }
                    }

                    return(aiTypes.keywordTable[param]);
                }
                return("UnknownKeyword_" + param);

            case ScriptNode.NodeType.Condition:                     // GetConditionFunctionPtr
                if (param < aiTypes.conditionTable.Length)
                {
                    return(aiTypes.conditionTable[param]);
                }
                return("UnknownCondition_" + param);

            case ScriptNode.NodeType.Operator:                     // GetOperatorFunctionPtr
                if (advanced)
                {
                    if (param < aiTypes.operatorTable.Length)
                    {
                        return(aiTypes.operatorTable[param] + " (" + param + ")");
                    }
                }
                if (param < aiTypes.operatorTable.Length)
                {
                    return(aiTypes.operatorTable[param]);
                }
                return("UnknownOperator_" + param);

            case ScriptNode.NodeType.Function:                     // GetFunctionFunctionPtr
                if (param < aiTypes.functionTable.Length)
                {
                    return(aiTypes.functionTable[param]);
                }
                return("UnknownFunction_" + param);

            case ScriptNode.NodeType.Procedure:                     // ProcedureFunctionReturn
                if (param < aiTypes.procedureTable.Length)
                {
                    return(aiTypes.procedureTable[param]);
                }
                return("UnknownProcedure_" + param);

            case ScriptNode.NodeType.MetaAction:                     // meta action
                if (param < aiTypes.metaActionTable.Length)
                {
                    return(aiTypes.metaActionTable[param]);
                }
                return("UnknownMetaAction_" + param);

            case ScriptNode.NodeType.BeginMacro:
                return("BeginMacro");

            case ScriptNode.NodeType.EndMacro:
                return("EndMacro");

            case ScriptNode.NodeType.Field:
                if (param < aiTypes.fieldTable.Length)
                {
                    return(aiTypes.fieldTable[param]);
                }
                return("UnknownField_" + param);

            case ScriptNode.NodeType.DsgVarRef:                     // Dsg Var
                if (perso != null && perso.brain != null && perso.brain.mind != null)
                {
                    Mind mind = perso.brain.mind;
                    if (mind.dsgMem != null && mind.dsgMem.dsgVar != null)
                    {
                        if (param < mind.dsgMem.dsgVar.dsgVarInfos.Length)
                        {
                            return(mind.dsgMem.dsgVar.dsgVarInfos[param].NiceVariableName);
                        }
                    }
                    else if (mind.AI_model != null && mind.AI_model.dsgVar != null)
                    {
                        if (param < mind.AI_model.dsgVar.dsgVarInfos.Length)
                        {
                            return(mind.AI_model.dsgVar.dsgVarInfos[param].NiceVariableName);
                        }
                    }
                }
                return("dsgVar_" + param);

            case ScriptNode.NodeType.Constant:
                if (advanced)
                {
                    return("Constant: " + BitConverter.ToInt32(BitConverter.GetBytes(param), 0));
                }
                return(BitConverter.ToInt32(BitConverter.GetBytes(param), 0).ToString());

            case ScriptNode.NodeType.Real:
                NumberFormatInfo nfi = new NumberFormatInfo()
                {
                    NumberDecimalSeparator = "."
                };
                if (advanced)
                {
                    return("Real: " + BitConverter.ToSingle(BitConverter.GetBytes(param), 0).ToString(nfi));
                }
                return(BitConverter.ToSingle(BitConverter.GetBytes(param), 0).ToString(nfi) + "f");

            case ScriptNode.NodeType.Button:     // Button/entryaction
                EntryAction ea = EntryAction.FromOffset(param_ptr);

                if (ea == null)
                {
                    return("ERR_ENTRYACTION_NOTFOUND");
                }

                string eaName = (advanced ? ea.ToString() : ea.ToBasicString());
                if (advanced)
                {
                    return("Button: " + eaName + "(" + param_ptr + ")");
                }

                if (!ts.expandEntryActions && ea != null)
                {
                    return("\"" + ea.ExportName + "\"");
                }
                return(eaName);

            case ScriptNode.NodeType.ConstantVector:
                return("Constant Vector: " + "0x" + param.ToString("x8"));    // TODO: get from address

            case ScriptNode.NodeType.Vector:
                return("new Vector3");    // TODO: same

            case ScriptNode.NodeType.Mask:
                mask = (short)param;     // TODO: as short
                if (advanced)
                {
                    return("Mask: " + (mask).ToString("x4"));
                }
                if (ts.exportMode)
                {
                    return("\"" + (mask).ToString("x4") + "\"");
                }
                return("Mask(" + (mask).ToString("x4") + ")");

            case ScriptNode.NodeType.ModuleRef:
                if (advanced)
                {
                    return("ModuleRef: " + "0x" + (param).ToString("x8"));
                }
                return("GetModule(" + (int)param + ")");

            case ScriptNode.NodeType.DsgVarId:
                if (advanced)
                {
                    return("DsgVarId: " + "0x" + (param).ToString("x8"));
                }
                return("DsgVarId(" + param + ")");

            case ScriptNode.NodeType.String:
                string str = "ERR_STRING_NOTFOUND";
                if (l.strings.ContainsKey(param_ptr))
                {
                    str = l.strings[param_ptr];
                }
                if (advanced)
                {
                    return("String: " + param_ptr + " (" + str + ")");
                }
                return("\"" + str + "\"");

            case ScriptNode.NodeType.LipsSynchroRef:
                return("LipsSynchroRef: " + param_ptr);

            case ScriptNode.NodeType.FamilyRef:
                if (advanced)
                {
                    return("FamilyRef: " + param_ptr);
                }
                Family f = Family.FromOffset(param_ptr);
                if (f != null)
                {
                    return("GetFamily(\"" + f.name + "\")");
                }
                else
                {
                    return("Family.FromOffset(\"" + param_ptr + "\")");
                }

            case ScriptNode.NodeType.PersoRef:
                Perso argPerso = Perso.FromOffset(param_ptr);
                if (argPerso != null && perso != null && argPerso.offset == perso.offset)
                {
                    if (advanced)
                    {
                        return("PersoRef: this");
                    }
                    return("this");
                }
                string persoName = argPerso == null ? "ERR_PERSO_NOTFOUND" : argPerso.fullName;
                if (advanced)
                {
                    return("PersoRef: " + param_ptr + " (" + persoName + ")");
                }
                if (argPerso?.brain?.mind?.AI_model != null)
                {
                    AIModel aiModel = argPerso.brain.mind.AI_model;
                    // Make sure to add a cast in case the AI Model is accessed
                    return("((" + aiModel.name + ")GetPerso(\"" + argPerso.namePerso + "\"))");
                }
                return("GetPerso(\"" + argPerso.namePerso + "\")");

            case ScriptNode.NodeType.ActionRef:
                State  state     = State.FromOffset(param_ptr);
                string stateName = state == null ? "ERR_STATE_NOTFOUND" : state.ShortName;
                if (advanced)
                {
                    return("ActionRef: " + param_ptr + " " + stateName);
                }
                if (ts.useStateIndex)
                {
                    return("GetAction(" + state.index.ToString() + ")");
                }
                return(stateName);

            case ScriptNode.NodeType.SuperObjectRef:
                if (advanced)
                {
                    return("SuperObjectRef: " + param_ptr);
                }
                SuperObject so = SuperObject.FromOffset(param_ptr);
                if (so != null)
                {
                    return("GetSuperObject(\"" + so.Gao.name + "\")");
                }
                else
                {
                    return("SuperObject.FromOffset(\"" + param_ptr + "\")");
                }

            case ScriptNode.NodeType.WayPointRef:
                if (advanced)
                {
                    return("WayPointRef: " + param_ptr);
                }
                return("WayPoint.FromOffset(\"" + param_ptr + "\")");

            case ScriptNode.NodeType.TextRef:
                if (l.localization == null)
                {
                    return("TextRef");
                }
                if (advanced)
                {
                    return("TextRef: " + param + " (" + l.localization.GetTextForHandleAndLanguageID((int)param, 0) + ")");
                }
                if (ts.expandStrings)
                {
                    return("\"" + l.localization.GetTextForHandleAndLanguageID((int)param, 0) + "\"");    // Preview in english
                }
                else
                {
                    return("new TextReference(" + (int)param + ")");
                }

            case ScriptNode.NodeType.ComportRef:
                Behavior comportRef = Behavior.FromOffset(param_ptr);

                if (comportRef == null)
                {
                    if (advanced)
                    {
                        return("ComportRef: " + param_ptr + " (null)");
                    }
                    return("null");
                }
                else
                {
                    return(comportRef.ShortName);
                    //string type = comportRef.type == Behavior.BehaviorType.Normal ? "normalBehavior" : "reflexBehavior";
                    //return type + "[" + script.behaviorOrMacro.aiModel.GetBehaviorIndex(comportRef) + "]";
                }

            case ScriptNode.NodeType.SoundEventRef:
                if (advanced)
                {
                    return("SoundEventRef: " + (int)param);
                }
                return("SoundEvent.FromID(0x" + ((int)param).ToString("X8") + ")");

            case ScriptNode.NodeType.ObjectTableRef:
                if (advanced)
                {
                    return("ObjectTableRef: " + param_ptr);
                }

                if (ts.useHashIdentifiers)
                {
                    string objectListJson = ObjectList.FromOffset(param_ptr).ToJSON();

                    string objectListHash = HashUtils.MD5Hash(objectListJson);
                    return("ObjectList.FromHash(\"" + objectListHash + "\")");
                }

                return("ObjectTable.FromOffset(\"" + param_ptr + "\")");

            case ScriptNode.NodeType.GameMaterialRef:
                if (advanced)
                {
                    return("GameMaterialRef: " + param_ptr);
                }
                if (ts.useHashIdentifiers)
                {
                    string gmtJson = GameMaterial.FromOffset(param_ptr).ToJSON();

                    string gmtHash = HashUtils.MD5Hash(gmtJson);
                    return("GameMaterial.FromHash(\"" + gmtHash + "\")");
                }
                return("GameMaterial.FromOffset(\"" + param_ptr + "\")");

            case ScriptNode.NodeType.ParticleGenerator:
                return("ParticleGenerator: " + "0x" + (param).ToString("x8"));

            case ScriptNode.NodeType.VisualMaterial:
                if (advanced)
                {
                    return("VisualMaterial: " + param_ptr);
                }

                if (ts.useHashIdentifiers)
                {
                    string vmtJson = VisualMaterial.FromOffset(param_ptr).ToJSON();

                    string vmtHash = HashUtils.MD5Hash(vmtJson);
                    return("VisualMaterial.FromHash(\"" + vmtHash + "\")");
                }

                return("VisualMaterial.FromOffset(\"" + param_ptr + "\")");

            case ScriptNode.NodeType.ModelRef:                     // ModelCast
                if (advanced)
                {
                    return("AIModel: " + param_ptr);
                }
                AIModel model = AIModel.FromOffset(param_ptr);
                return(model != null ? model.name : "null");

            case ScriptNode.NodeType.DataType42:
                if (advanced)
                {
                    return("EvalDataType42: " + "0x" + (param).ToString("x8"));
                }
                return("EvalDataType42(" + "0x" + (param).ToString("x8") + ")");

            case ScriptNode.NodeType.CustomBits:
                if (advanced)
                {
                    return("CustomBits: " + "0x" + (param).ToString("x8"));
                }
                if (ts.exportMode)
                {
                    return("0x" + (param).ToString("x8"));
                }
                return("CustomBits(" + "0x" + (param).ToString("x8") + ")");

            case ScriptNode.NodeType.Caps:
                if (advanced)
                {
                    return("Caps: " + "0x" + (param).ToString("x8"));
                }
                if (ts.exportMode)
                {
                    return("0x" + (param).ToString("x8"));
                }
                return("Caps(" + "0x" + (param).ToString("x8") + ")");

            case ScriptNode.NodeType.SubRoutine:
                if (advanced)
                {
                    return("Eval SubRoutine: " + param_ptr);
                }
                Macro macro = Macro.FromOffset(param_ptr);
                if (macro == null)
                {
                    return("null");
                }
                return("evalMacro(" + macro.ShortName + ");");

            case ScriptNode.NodeType.Null:
                return("null");

            case ScriptNode.NodeType.GraphRef:
                if (advanced)
                {
                    return("Graph: " + "0x" + (param).ToString("x8"));
                }
                return("Graph.FromOffset(\"" + param_ptr + "\")");
            }

            return("unknown");
        }
示例#5
0
    private JSONObject GetDsgVarJSON(Perso perso, DsgVarComponent.DsgVarEditableEntry dsg)
    {
        JSONObject dsgObj = new JSONObject();

        dsgObj["name"] = dsg.entry.NiceVariableName;
        dsgObj["type"] = dsg.entry.type.ToString();
        switch (dsg.entry.type)
        {
        case DsgVarInfoEntry.DsgVarType.Boolean: dsgObj["value"] = dsg.valueAsBool; break;

        case DsgVarInfoEntry.DsgVarType.Int: dsgObj["value"] = dsg.valueAsInt; break;

        case DsgVarInfoEntry.DsgVarType.UInt: dsgObj["value"] = dsg.valueAsUInt; break;

        case DsgVarInfoEntry.DsgVarType.Short: dsgObj["value"] = dsg.valueAsShort; break;

        case DsgVarInfoEntry.DsgVarType.UShort: dsgObj["value"] = dsg.valueAsUShort; break;

        case DsgVarInfoEntry.DsgVarType.Byte: dsgObj["value"] = dsg.valueAsByte; break;

        case DsgVarInfoEntry.DsgVarType.UByte: dsgObj["value"] = dsg.valueAsByte; break;

        case DsgVarInfoEntry.DsgVarType.Float: dsgObj["value"] = dsg.valueAsFloat; break;

        case DsgVarInfoEntry.DsgVarType.Text: dsgObj["value"] = dsg.valueAsString; break;

        case DsgVarInfoEntry.DsgVarType.Vector: dsgObj["value"] = dsg.valueAsVector; break;

        case DsgVarInfoEntry.DsgVarType.Perso:
            if (dsg.entry.value != null)
            {
                SuperObject so = SuperObject.FromOffset(dsg.entry.value as Pointer);
                if (so != null && so.type == SuperObject.Type.Perso && so.data != null)
                {
                    Perso p = so.data as Perso;
                    if (p != null)
                    {
                        JSONObject persoJSON = new JSONObject();
                        persoJSON["offset"]       = p.offset.ToString();
                        persoJSON["nameFamily"]   = p.nameFamily;
                        persoJSON["nameModel"]    = p.nameModel;
                        persoJSON["nameInstance"] = p.namePerso;
                        dsgObj["value"]           = persoJSON;
                    }
                }
            }
            break;

        case DsgVarInfoEntry.DsgVarType.SuperObject:
            SuperObject spo = SuperObject.FromOffset(dsg.entry.value as Pointer);
            if (spo != null)
            {
                JSONObject soJSON = new JSONObject();
                soJSON["offset"] = spo.offset.ToString();
                soJSON["type"]   = spo.type.ToString();
                soJSON["offset"] = spo.offset.ToString();
                if (spo.type == SuperObject.Type.Perso && spo.data != null)
                {
                    Perso p = spo.data as Perso;
                    if (p != null)
                    {
                        JSONObject persoJSON = new JSONObject();
                        persoJSON["offset"]       = p.offset.ToString();
                        persoJSON["nameFamily"]   = p.nameFamily;
                        persoJSON["nameModel"]    = p.nameModel;
                        persoJSON["nameInstance"] = p.namePerso;
                        soJSON["perso"]           = persoJSON;
                    }
                }
                dsgObj["value"] = soJSON;
            }
            break;
        }
        return(dsgObj);
    }
示例#6
0
        async Task LoadLVL()
        {
            loadingState = "Loading level memory";
            await WaitIfNecessary();

            files_array[Mem.Lvl].GotoHeader();
            Reader reader    = files_array[Mem.Lvl].reader;
            long   totalSize = reader.BaseStream.Length;

            //reader.ReadUInt32();
            if (Settings.s.game == Settings.Game.R3 &&
                (Settings.s.platform == Settings.Platform.PC ||
                 Settings.s.platform == Settings.Platform.Xbox ||
                 Settings.s.platform == Settings.Platform.Xbox360 ||
                 Settings.s.platform == Settings.Platform.PS3))
            {
                reader.ReadUInt32();                 // fix checksum?
            }
            reader.ReadUInt32();
            reader.ReadUInt32();
            reader.ReadUInt32();
            reader.ReadUInt32();
            if (Settings.s.platform == Settings.Platform.PC ||
                Settings.s.platform == Settings.Platform.Xbox ||
                Settings.s.platform == Settings.Platform.Xbox360 ||
                Settings.s.platform == Settings.Platform.PS3)
            {
                if (Settings.s.game == Settings.Game.R3)
                {
                    string timeStamp = reader.ReadString(0x18);
                    reader.ReadUInt32();
                    reader.ReadUInt32();
                    reader.ReadUInt32();
                    reader.ReadUInt32();
                    reader.ReadUInt32();
                    reader.ReadUInt32();
                    reader.ReadUInt32();
                }
                else if (Settings.s.game == Settings.Game.RM ||
                         Settings.s.game == Settings.Game.RA ||
                         Settings.s.game == Settings.Game.Dinosaur)
                {
                    reader.ReadUInt32();
                    reader.ReadUInt32();
                }
            }
            reader.ReadBytes(0x104);             // vignette
            if (Settings.s.game != Settings.Game.Dinosaur)
            {
                reader.ReadUInt32();
            }
            loadingState = "Loading level textures";
            await ReadTexturesLvl(reader, Pointer.Current(reader));

            if ((Settings.s.platform == Settings.Platform.PC ||
                 Settings.s.platform == Settings.Platform.Xbox ||
                 Settings.s.platform == Settings.Platform.Xbox360 ||
                 Settings.s.platform == Settings.Platform.PS3) &&
                !hasTransit && Settings.s.game != Settings.Game.Dinosaur)
            {
                Pointer off_lightMapTexture = Pointer.Read(reader);                 // g_p_stLMTexture
                Pointer.DoAt(ref reader, off_lightMapTexture, () => {
                    lightmapTexture = TextureInfo.Read(reader, off_lightMapTexture);
                });
                if (Settings.s.game == Settings.Game.R3)
                {
                    Pointer off_overlightTexture = Pointer.Read(reader);                     // *(_DWORD *)(GLI_BIG_GLOBALS + 370068)
                    Pointer.DoAt(ref reader, off_overlightTexture, () => {
                        overlightTexture = TextureInfo.Read(reader, off_overlightTexture);
                    });
                }
            }
            Pointer off_animBankLvl = null;

            if (Settings.s.game == Settings.Game.Dinosaur)
            {
                // animation bank is read right here.
                off_animBankLvl = Pointer.Current(reader);                 // Note: only one 0x104 bank in fix.
                print("Lvl animation bank address: " + off_animBankLvl);
                animationBanks = new AnimationBank[5];
                AnimationBank[] banks = AnimationBank.Read(reader, off_animBankLvl, 0, 1, files_array[Mem.LvlKeyFrames]);
                animationBanks[0] = banks[0];
            }
            loadingState = "Loading globals";
            await WaitIfNecessary();

            globals.off_transitDynamicWorld = null;
            globals.off_actualWorld         = Pointer.Read(reader);
            globals.off_dynamicWorld        = Pointer.Read(reader);
            if (Settings.s.game == Settings.Game.R3 &&
                (Settings.s.platform == Settings.Platform.PC ||
                 Settings.s.platform == Settings.Platform.Xbox ||
                 Settings.s.platform == Settings.Platform.Xbox360 ||
                 Settings.s.platform == Settings.Platform.PS3))
            {
                reader.ReadUInt32();                 // ???
            }
            globals.off_inactiveDynamicWorld = Pointer.Read(reader);
            globals.off_fatherSector         = Pointer.Read(reader);     // It is I, Father Sector.
            globals.off_firstSubMapPosition  = Pointer.Read(reader);
            globals.num_always      = reader.ReadUInt32();
            globals.spawnablePersos = LinkedList <Perso> .ReadHeader(reader, Pointer.Current(reader), LinkedList.Type.Double);

            globals.off_always_reusableSO       = Pointer.Read(reader);       // There are (num_always) empty SuperObjects starting with this one.
            globals.off_always_reusableUnknown1 = Pointer.Read(reader);       // (num_always) * 0x2c blocks
            globals.off_always_reusableUnknown2 = Pointer.Read(reader);       // (num_always) * 0x4 blocks

            // Read object types
            objectTypes = new ObjectType[3][];
            for (uint i = 0; i < 3; i++)
            {
                Pointer off_names_header = Pointer.Current(reader);
                Pointer off_names_first  = Pointer.Read(reader);
                Pointer off_names_last   = Pointer.Read(reader);
                uint    num_names        = reader.ReadUInt32();

                ReadObjectNamesTable(reader, off_names_first, num_names, i);
            }

            Pointer off_light = Pointer.Read(reader);             // the offset of a light. It's just an ordinary light.
            Pointer off_characterLaunchingSoundEvents = Pointer.Read(reader);
            Pointer off_collisionGeoObj       = Pointer.Read(reader);
            Pointer off_staticCollisionGeoObj = Pointer.Read(reader);

            if (!hasTransit)
            {
                reader.ReadUInt32();                 // viewport related <--- cameras in here
            }

            Pointer off_unknown_first = Pointer.Read(reader);
            Pointer off_unknown_last  = Pointer.Read(reader);
            uint    num_unknown       = reader.ReadUInt32();

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

            Pointer off_alwaysActiveCharacters_first = Pointer.Read(reader);
            Pointer off_alwaysActiveCharacters_last  = Pointer.Read(reader);
            uint    num_alwaysActiveChars            = reader.ReadUInt32();

            if (!hasTransit)
            {
                Pointer off_mainCharacters_first   = Pointer.Read(reader);
                Pointer off_mainCharacters_last    = Pointer.Read(reader);
                uint    num_mainCharacters_entries = reader.ReadUInt32();
            }

            reader.ReadUInt32();             // only used if there was no transit in the previous lvl. Always 00165214 in R3GC?
            reader.ReadUInt32();             // related to "SOL". What is this? Good question.
            reader.ReadUInt32();             // same
            if (Settings.s.game != Settings.Game.Dinosaur)
            {
                reader.ReadUInt32();                 // same
            }
            Pointer off_cineManager  = Pointer.Read(reader);
            byte    unk              = reader.ReadByte();
            byte    IPO_numRLItables = reader.ReadByte();

            reader.ReadUInt16();
            Pointer off_COL_taggedFacesTable = Pointer.Read(reader);
            uint    num_COL_maxTaggedFaces   = reader.ReadUInt32();

            off_collisionGeoObj       = Pointer.Read(reader);
            off_staticCollisionGeoObj = Pointer.Read(reader);

            // The ptrsTable seems to be related to sound events. Perhaps cuuids.
            reader.ReadUInt32();
            if (Settings.s.game == Settings.Game.Dinosaur)
            {
                for (int i = 0; i < 50; i++)
                {
                    reader.ReadUInt32();
                }
                // Actually, the previous uint is an amount for this array of uints, but it's padded to always be 50 long
            }
            uint num_ptrsTable = reader.ReadUInt32();

            if (Settings.s.game == Settings.Game.R3)
            {
                uint bool_ptrsTable = reader.ReadUInt32();
            }
            Pointer off_ptrsTable = Pointer.Read(reader);


            uint num_internalStructure = num_ptrsTable;

            if (Settings.s.mode == Settings.Mode.Rayman3GC)
            {
                reader.ReadUInt32();
            }
            Pointer off_internalStructure_first = Pointer.Read(reader);
            Pointer off_internalStructure_last  = Pointer.Read(reader);

            if (!hasTransit && Settings.s.game == Settings.Game.R3)
            {
                uint    num_geometric              = reader.ReadUInt32();
                Pointer off_array_geometric        = Pointer.Read(reader);
                Pointer off_array_geometric_RLI    = Pointer.Read(reader);
                Pointer off_array_transition_flags = Pointer.Read(reader);
            }
            else if (Settings.s.game == Settings.Game.RA ||
                     Settings.s.game == Settings.Game.RM ||
                     Settings.s.game == Settings.Game.Dinosaur ||
                     Settings.s.game == Settings.Game.DDPK)
            {
                uint    num_unk   = reader.ReadUInt32();
                Pointer unk_first = Pointer.Read(reader);
                if (Settings.s.game != Settings.Game.Dinosaur)
                {
                    Pointer unk_last = Pointer.Read(reader);
                }
            }
            uint    num_visual_materials       = reader.ReadUInt32();
            Pointer off_array_visual_materials = Pointer.Read(reader);

            if (Settings.s.mode != Settings.Mode.RaymanArenaGC &&
                Settings.s.mode != Settings.Mode.RaymanArenaGCDemo &&
                Settings.s.mode != Settings.Mode.DonaldDuckPKGC)
            {
                Pointer off_dynamic_so_list = Pointer.Read(reader);

                // Parse SO list
                Pointer.DoAt(ref reader, off_dynamic_so_list, () => {
                    LinkedList <SuperObject> .ReadHeader(reader, off_dynamic_so_list);

                    /*Pointer off_so_list_first = Pointer.Read(reader);
                     * Pointer off_so_list_last = Pointer.Read(reader);
                     * Pointer off_so_list_current = off_so_list_first;
                     * uint num_so_list = reader.ReadUInt32();*/
                    /*if (experimentalObjectLoading) {
                     * for (uint i = 0; i < num_so_list; i++) {
                     * R3Pointer.Goto(ref reader, off_so_list_current);
                     * R3Pointer off_so_list_next = R3Pointer.Read(reader);
                     * R3Pointer off_so_list_prev = R3Pointer.Read(reader);
                     * R3Pointer off_so_list_start = R3Pointer.Read(reader);
                     * R3Pointer off_so = R3Pointer.Read(reader);
                     * R3Pointer.Goto(ref reader, off_so);
                     * ParseSuperObject(reader, off_so, true, true);
                     * off_so_list_current = off_so_list_next;
                     * }
                     * }*/
                });
            }

            // Parse materials list
            loadingState = "Loading visual materials";
            await WaitIfNecessary();

            Pointer.DoAt(ref reader, off_array_visual_materials, () => {
                for (uint i = 0; i < num_visual_materials; i++)
                {
                    Pointer off_material = Pointer.Read(reader);
                    Pointer.DoAt(ref reader, off_material, () => {
                        //print(Pointer.Current(reader));
                        visualMaterials.Add(VisualMaterial.Read(reader, off_material));
                    });
                }
            });

            if (hasTransit)
            {
                loadingState = "Loading transit memory";
                await WaitIfNecessary();

                Pointer off_transit = new Pointer(16, files_array[Mem.Transit]);                 // It's located at offset 20 in transit
                Pointer.DoAt(ref reader, off_transit, () => {
                    if (Settings.s.platform == Settings.Platform.PC ||
                        Settings.s.platform == Settings.Platform.Xbox ||
                        Settings.s.platform == Settings.Platform.Xbox360 ||
                        Settings.s.platform == Settings.Platform.PS3)
                    {
                        Pointer off_lightMapTexture = Pointer.Read(reader);                         // g_p_stLMTexture
                        Pointer.DoAt(ref reader, off_lightMapTexture, () => {
                            lightmapTexture = TextureInfo.Read(reader, off_lightMapTexture);
                        });
                        if (Settings.s.game == Settings.Game.R3)
                        {
                            Pointer off_overlightTexture = Pointer.Read(reader);                             // *(_DWORD *)(GLI_BIG_GLOBALS + 370068)
                            Pointer.DoAt(ref reader, off_overlightTexture, () => {
                                overlightTexture = TextureInfo.Read(reader, off_overlightTexture);
                            });
                        }
                    }
                    globals.off_transitDynamicWorld  = Pointer.Read(reader);
                    globals.off_actualWorld          = Pointer.Read(reader);
                    globals.off_dynamicWorld         = Pointer.Read(reader);
                    globals.off_inactiveDynamicWorld = Pointer.Read(reader);
                });
            }

            // Parse actual world & always structure
            loadingState = "Loading families";
            await WaitIfNecessary();

            ReadFamilies(reader);
            loadingState = "Loading superobject hierarchy";
            await WaitIfNecessary();

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

            ReadAlways(reader);


            Pointer.DoAt(ref reader, off_cineManager, () => {
                cinematicsManager = CinematicsManager.Read(reader, off_cineManager);
            });

            // off_current should be after the dynamic SO list positions.

            // Parse transformation matrices and other settings(state? :o) for fix characters
            loadingState = "Loading settings for persos in fix";
            await WaitIfNecessary();

            uint num_perso_with_settings_in_fix = (uint)persoInFix.Length;

            if (Settings.s.game == Settings.Game.R3)
            {
                num_perso_with_settings_in_fix = reader.ReadUInt32();
            }
            for (int i = 0; i < num_perso_with_settings_in_fix; i++)
            {
                Pointer     off_perso_so_with_settings_in_fix = null, off_matrix = null;
                SuperObject so = null;
                Matrix      mat = null;
                if (Settings.s.game == Settings.Game.R3)
                {
                    off_perso_so_with_settings_in_fix = Pointer.Read(reader);
                    off_matrix = Pointer.Current(reader);
                    mat        = Matrix.Read(reader, off_matrix);
                    reader.ReadUInt32();                     // is one of these the state? doesn't appear to change tho
                    reader.ReadUInt32();
                    so = SuperObject.FromOffset(off_perso_so_with_settings_in_fix);
                }
                else if (Settings.s.game == Settings.Game.RA ||
                         Settings.s.game == Settings.Game.RM ||
                         Settings.s.game == Settings.Game.Dinosaur)
                {
                    off_matrix = Pointer.Current(reader);
                    mat        = Matrix.Read(reader, off_matrix);
                    so         = superObjects.FirstOrDefault(s => s.off_data == persoInFix[i]);
                }
                if (so != null)
                {
                    so.off_matrix = off_matrix;
                    so.matrix     = mat;
                    if (so.Gao != null)
                    {
                        so.Gao.transform.localPosition = mat.GetPosition(convertAxes: true);
                        so.Gao.transform.localRotation = mat.GetRotation(convertAxes: true);
                        so.Gao.transform.localScale    = mat.GetScale(convertAxes: true);
                    }
                }
            }
            if (Settings.s.platform == Settings.Platform.GC)
            {
                reader.ReadBytes(0x800);                 // floats
            }
            loadingState = "Loading animation banks";
            await WaitIfNecessary();

            if (Settings.s.game != Settings.Game.Dinosaur)
            {
                off_animBankLvl = Pointer.Read(reader);                 // Note: 4 0x104 banks in lvl.
                print("Lvl animation bank address: " + off_animBankLvl);
                animationBanks = new AnimationBank[5];
                if (off_animBankFix != off_animBankLvl)
                {
                    Pointer.DoAt(ref reader, off_animBankFix, () => {
                        animationBanks[0] = AnimationBank.Read(reader, off_animBankFix, 0, 1, files_array[Mem.FixKeyFrames])[0];
                    });
                }
                Pointer.DoAt(ref reader, off_animBankLvl, () => {
                    AnimationBank[] banks = AnimationBank.Read(reader, off_animBankLvl, 1, 4, files_array[Mem.LvlKeyFrames]);
                    for (int i = 0; i < 4; i++)
                    {
                        animationBanks[1 + i] = banks[i];
                    }
                });
                if (off_animBankFix == off_animBankLvl)
                {
                    animationBanks[0] = animationBanks[1];
                }
            }
            // Load additional animation banks
            string extraAnimFolder = "Anim/";

            if (Settings.s.mode == Settings.Mode.RaymanArenaGCDemo)
            {
                extraAnimFolder = lvlName + "/";
            }
            for (int i = 0; i < families.Count; i++)
            {
                if (families[i] != null && families[i].animBank > 4 && objectTypes[0][families[i].family_index].id != 0xFF)
                {
                    int animBank = families[i].animBank;
                    loadingState = "Loading additional animation bank " + animBank;
                    await WaitIfNecessary();

                    int animFileID = objectTypes[0][families[i].family_index].id;
                    if (Settings.s.mode == Settings.Mode.RaymanArenaGCDemo)
                    {
                        animFileID = animBank - 5;
                    }
                    string animName = extraAnimFolder + "ani" + animFileID.ToString();
                    string kfName   = extraAnimFolder + "key" + animFileID.ToString() + "kf";

                    //print(animBank + " - " + objectTypes[0][families[i].family_index].id);
                    int fileID   = animBank + 102;
                    int kfFileID = animBank + 2;                     // Anim bank will start at 5, so this will start at 7
                    if (Settings.s.game == Settings.Game.RM)
                    {
                        fileID = animBank;
                    }

                    // Prepare files for WebGL
                    await PrepareFile(gameDataBinFolder + animName + ".lvl");

                    if (FileSystem.FileExists(gameDataBinFolder + animName + ".lvl"))
                    {
                        await PrepareFile(gameDataBinFolder + animName + ".ptr");
                    }
                    await PrepareFile(gameDataBinFolder + kfName + ".lvl");

                    if (FileSystem.FileExists(gameDataBinFolder + kfName + ".lvl"))
                    {
                        await PrepareFile(gameDataBinFolder + kfName + ".ptr");
                    }

                    FileWithPointers animFile = InitExtraLVL(animName, fileID);
                    FileWithPointers kfFile   = InitExtraLVL(kfName, fileID);
                    if (animFile != null)
                    {
                        if (animBank >= animationBanks.Length)
                        {
                            Array.Resize(ref animationBanks, animBank + 1);
                        }
                        Pointer off_animBankExtra = new Pointer(0, animFile);
                        Pointer.DoAt(ref reader, off_animBankExtra, () => {
                            int alignBytes = reader.ReadInt32();
                            if (alignBytes > 0)
                            {
                                reader.Align(4, alignBytes);
                            }
                            off_animBankExtra        = Pointer.Current(reader);
                            animationBanks[animBank] = AnimationBank.Read(reader, off_animBankExtra, (uint)animBank, 1, kfFile)[0];
                        });
                    }
                }
            }

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

            ReadCrossReferences(reader);
        }