Example #1
0
        private RefCellObjInfo[] GetRefCellObjInfos(CELLRecord CELL)
        {
            RefCellObjInfo[] refCellObjInfos = new RefCellObjInfo[CELL.refObjDataGroups.Count];
            for (int i = 0; i < CELL.refObjDataGroups.Count; i++)
            {
                var refObjInfo = new RefCellObjInfo();
                refObjInfo.refObjDataGroup = CELL.refObjDataGroups[i];

                // Get the record the RefObjDataGroup references.
                dataReader.MorrowindESMFile.objectsByIDString.TryGetValue(refObjInfo.refObjDataGroup.NAME.value, out refObjInfo.referencedRecord);

                if (refObjInfo.referencedRecord != null)
                {
                    var modelFileName = ESM.RecordUtils.GetModelFileName(refObjInfo.referencedRecord);

                    // If the model file name is valid, store the model file path.
                    if (!string.IsNullOrEmpty(modelFileName))
                    {
                        refObjInfo.modelFilePath = "meshes\\" + modelFileName;
                    }
                }

                refCellObjInfos[i] = refObjInfo;
            }

            return(refCellObjInfos);
        }
Example #2
0
        /// <summary>
        /// Instantiates an object in a cell. Called by InstantiateCellObjectsCoroutine after the object's assets have been pre-loaded.
        /// </summary>
        private void InstantiateCellObject(CELLRecord CELL, GameObject parent, RefCellObjInfo refCellObjInfo)
        {
            if (refCellObjInfo.referencedRecord != null)
            {
                GameObject modelObj = null;

                // If the object has a model, instantiate it.
                if (refCellObjInfo.modelFilePath != null)
                {
                    modelObj = nifManager.InstantiateNIF(refCellObjInfo.modelFilePath);
                    PostProcessInstantiatedCellObject(modelObj, refCellObjInfo);

                    modelObj.transform.parent = parent.transform;
                }

                // If the object has a light, instantiate it.
                if (refCellObjInfo.referencedRecord is LIGHRecord)
                {
                    var lightObj = InstantiateLight((LIGHRecord)refCellObjInfo.referencedRecord, CELL.isInterior);

                    // If the object also has a model, parent the model to the light.
                    if (modelObj != null)
                    {
                        // Some NIF files have nodes named "AttachLight". Parent it to the light if it exists.
                        GameObject attachLightObj = GameObjectUtils.FindChildRecursively(modelObj, "AttachLight");

                        if (attachLightObj == null)
                        {
                            //attachLightObj = GameObjectUtils.FindChildWithNameSubstringRecursively(modelObj, "Emitter");
                            attachLightObj = modelObj;
                        }

                        if (attachLightObj != null)
                        {
                            lightObj.transform.position = attachLightObj.transform.position;
                            lightObj.transform.rotation = attachLightObj.transform.rotation;

                            lightObj.transform.parent = attachLightObj.transform;
                        }
                        else // If there is no "AttachLight", center the light in the model's bounds.
                        {
                            lightObj.transform.position = GameObjectUtils.CalcVisualBoundsRecursive(modelObj).center;
                            lightObj.transform.rotation = modelObj.transform.rotation;

                            lightObj.transform.parent = modelObj.transform;
                        }
                    }
                    else // If the light has no associated model, instantiate the light as a standalone object.
                    {
                        PostProcessInstantiatedCellObject(lightObj, refCellObjInfo);
                        lightObj.transform.parent = parent.transform;
                    }
                }
            }
            else
            {
                Debug.Log("Unknown Object: " + refCellObjInfo.refObjDataGroup.NAME.value);
            }
        }
Example #3
0
        private void ProcessObjectType <RecordType>(GameObject gameObject, RefCellObjInfo info, string tag) where RecordType : Record
        {
            var record = info.referencedRecord;

            if (record is RecordType)
            {
                var obj = GameObjectUtils.FindTopLevelObject(gameObject);
                if (obj == null)
                {
                    return;
                }

                var component = GenericObjectComponent.Create(obj, record, tag);

                //only door records need access to the cell object data group so far
                if (record is DOORRecord)
                {
                    ((DoorComponent)component).refObjDataGroup = info.refObjDataGroup;
                }
            }
        }
Example #4
0
        /// <summary>
        /// Finishes initializing an instantiated cell object.
        /// </summary>
        private void PostProcessInstantiatedCellObject(GameObject gameObject, RefCellObjInfo refCellObjInfo)
        {
            var refObjDataGroup = refCellObjInfo.refObjDataGroup;

            // Handle object transforms.
            if (refObjDataGroup.XSCL != null)
            {
                gameObject.transform.localScale = Vector3.one * refObjDataGroup.XSCL.value;
            }

            gameObject.transform.position += NIFUtils.NifPointToUnityPoint(refObjDataGroup.DATA.position);
            gameObject.transform.rotation *= NIFUtils.NifEulerAnglesToUnityQuaternion(refObjDataGroup.DATA.eulerAngles);

            var tagTarget = gameObject;
            var coll      = gameObject.GetComponentInChildren <Collider>(); // if the collider is on a child object and not on the object with the component, we need to set that object's tag instead.

            if (coll != null)
            {
                tagTarget = coll.gameObject;
            }

            ProcessObjectType <DOORRecord>(tagTarget, refCellObjInfo, "Door");
            ProcessObjectType <ACTIRecord>(tagTarget, refCellObjInfo, "Activator");
            ProcessObjectType <CONTRecord>(tagTarget, refCellObjInfo, "Container");
            ProcessObjectType <LIGHRecord>(tagTarget, refCellObjInfo, "Light");
            ProcessObjectType <LOCKRecord>(tagTarget, refCellObjInfo, "Lock");
            ProcessObjectType <PROBRecord>(tagTarget, refCellObjInfo, "Probe");
            ProcessObjectType <REPARecord>(tagTarget, refCellObjInfo, "RepairTool");
            ProcessObjectType <WEAPRecord>(tagTarget, refCellObjInfo, "Weapon");
            ProcessObjectType <CLOTRecord>(tagTarget, refCellObjInfo, "Clothing");
            ProcessObjectType <ARMORecord>(tagTarget, refCellObjInfo, "Armor");
            ProcessObjectType <INGRRecord>(tagTarget, refCellObjInfo, "Ingredient");
            ProcessObjectType <ALCHRecord>(tagTarget, refCellObjInfo, "Alchemical");
            ProcessObjectType <APPARecord>(tagTarget, refCellObjInfo, "Apparatus");
            ProcessObjectType <BOOKRecord>(tagTarget, refCellObjInfo, "Book");
            ProcessObjectType <MISCRecord>(tagTarget, refCellObjInfo, "MiscObj");
            ProcessObjectType <CREARecord>(tagTarget, refCellObjInfo, "Creature");
            ProcessObjectType <NPC_Record>(tagTarget, refCellObjInfo, "NPC");
        }
Example #5
0
        /// <summary>
        /// A coroutine that instantiates the terrain for, and all objects in, a cell.
        /// </summary>
        private IEnumerator InstantiateCellObjectsCoroutine(CELLRecord CELL, LANDRecord LAND, GameObject cellObj, GameObject cellObjectsContainer)
        {
            // Return before doing any work to provide an IEnumerator handle to the coroutine.
            yield return(null);

            // Instantiate terrain.
            if (LAND != null)
            {
                var instantiateLANDTaskEnumerator = InstantiateLANDCoroutine(LAND, cellObj);

                // Run the LAND instantiation coroutine.
                while (instantiateLANDTaskEnumerator.MoveNext())
                {
                    // Yield every time InstantiateLANDCoroutine does to avoid doing too much work in one frame.
                    yield return(null);
                }

                // Yield after InstantiateLANDCoroutine has finished to avoid doing too much work in one frame.
                yield return(null);
            }

            // Extract information about referenced objects. Do this all at once because it's fast.
            RefCellObjInfo[] refCellObjInfos = new RefCellObjInfo[CELL.refObjDataGroups.Count];

            for (int i = 0; i < CELL.refObjDataGroups.Count; i++)
            {
                var refObjInfo = new RefCellObjInfo();
                refObjInfo.refObjDataGroup = CELL.refObjDataGroups[i];

                // Get the record the RefObjDataGroup references.
                dataReader.MorrowindESMFile.objectsByIDString.TryGetValue(refObjInfo.refObjDataGroup.NAME.value, out refObjInfo.referencedRecord);

                if (refObjInfo.referencedRecord != null)
                {
                    var modelFileName = ESM.RecordUtils.GetModelFileName(refObjInfo.referencedRecord);

                    // If the model file name is valid, store the model file path.
                    if ((modelFileName != null) && (modelFileName != ""))
                    {
                        refObjInfo.modelFilePath = "meshes\\" + modelFileName;
                    }
                }

                refCellObjInfos[i] = refObjInfo;
            }

            yield return(null);

            // Start loading all required assets in background threads.
            foreach (var refCellObjInfo in refCellObjInfos)
            {
                if (refCellObjInfo.modelFilePath != null)
                {
                    theNIFManager.PreLoadNIFAsync(refCellObjInfo.modelFilePath);

                    yield return(null);
                }
            }

            yield return(null);

            // Instantiate objects when they are done loading, or if they don't need to load.
            int instantiatedObjectCount = 0;

            while (instantiatedObjectCount < refCellObjInfos.Length)
            {
                foreach (var refCellObjInfo in refCellObjInfos)
                {
                    // Ignore objects that have already been instantiated.
                    if (refCellObjInfo.isInstantiated)
                    {
                        continue;
                    }

                    // If the referenced object has a model and it has just finished pre-loading, instantiate the model.
                    if (refCellObjInfo.modelFilePath != null)
                    {
                        Debug.Assert(!refCellObjInfo.isDonePreLoading);

                        // Update isDonePreloading.
                        refCellObjInfo.isDonePreLoading = theNIFManager.IsDonePreLoading(refCellObjInfo.modelFilePath);

                        // If the model just finished pre-loading, instantiate it.
                        if (refCellObjInfo.isDonePreLoading)
                        {
                            InstantiatePreLoadedCellObject(CELL, cellObjectsContainer, refCellObjInfo);
                            refCellObjInfo.isInstantiated = true;

                            instantiatedObjectCount++;

                            yield return(null);
                        }
                    }
                    else // If the referenced object doesn't have a model, there is no loading to be done, so try to instantiate it.
                    {
                        InstantiatePreLoadedCellObject(CELL, cellObjectsContainer, refCellObjInfo);
                        refCellObjInfo.isInstantiated = true;

                        instantiatedObjectCount++;

                        yield return(null);
                    }
                }

                // Yield after every foreach to prevent spinning if all models are loading.
                yield return(null);
            }
        }