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); }
/// <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); } }
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; } } }
/// <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"); }
/// <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); } }