public static GameObject CreateGameObject( string blockName, bool disableGround = false, DaggerfallBillboardBatch natureBatch = null) { // Validate if (string.IsNullOrEmpty(blockName)) { return(null); } if (!blockName.ToUpper().EndsWith(".RMB")) { return(null); } DaggerfallUnity dfUnity = DaggerfallUnity.Instance; if (!dfUnity.IsReady) { return(null); } // Get block data DFBlock blockData = dfUnity.ContentReader.BlockFileReader.GetBlock(blockName); return(CreateGameObject(dfUnity, ref blockData, disableGround, natureBatch)); }
/// <summary> /// Add misc block flats. /// Batching is conditionally supported. /// </summary> public static void AddMiscBlockFlats( ref DFBlock blockData, Transform flatsParent, DaggerfallBillboardBatch animalsBillboardBatch = null, TextureAtlasBuilder miscBillboardsAtlas = null, DaggerfallBillboardBatch miscBillboardsBatch = null) { DaggerfallUnity dfUnity = DaggerfallUnity.Instance; if (!dfUnity.IsReady) { return; } // Add block flats foreach (DFBlock.RmbBlockFlatObjectRecord obj in blockData.RmbBlock.MiscFlatObjectRecords) { // Ignore lights as they are handled by AddLights() if (obj.TextureArchive == TextureReader.LightsTextureArchive) { continue; } // Calculate position Vector3 billboardPosition = new Vector3( obj.XPos, -obj.YPos + blockFlatsOffsetY, obj.ZPos + BlocksFile.RMBDimension) * MeshReader.GlobalScale; // Import custom 3d gameobject instead of flat if (MeshReplacement.ImportCustomFlatGameobject(obj.TextureArchive, obj.TextureRecord, billboardPosition, flatsParent) != null) { continue; } // Use misc billboard atlas where available if (miscBillboardsAtlas != null && miscBillboardsBatch != null) { TextureAtlasBuilder.AtlasItem item = miscBillboardsAtlas.GetAtlasItem(obj.TextureArchive, obj.TextureRecord); if (item.key != -1) { miscBillboardsBatch.AddItem(item.rect, item.textureItem.size, item.textureItem.scale, billboardPosition); continue; } } // Add to batch where available if (obj.TextureArchive == TextureReader.AnimalsTextureArchive && animalsBillboardBatch != null) { animalsBillboardBatch.AddItem(obj.TextureRecord, billboardPosition); continue; } // Add standalone billboard gameobject GameObject go = GameObjectHelper.CreateDaggerfallBillboardGameObject(obj.TextureArchive, obj.TextureRecord, flatsParent); go.transform.position = billboardPosition; AlignBillboardToBase(go); } }
/// <summary> /// Adds light flats and prefabs. /// </summary> public static void AddLights( ref DFBlock blockData, Transform flatsParent, Transform lightsParent, DaggerfallBillboardBatch billboardBatch = null) { DaggerfallUnity dfUnity = DaggerfallUnity.Instance; if (!dfUnity.IsReady) { return; } // Do nothing if import option not enabled or missing prefab if (!dfUnity.Option_ImportLightPrefabs || dfUnity.Option_CityLightPrefab == null) { return; } // Iterate block flats for lights foreach (DFBlock.RmbBlockFlatObjectRecord obj in blockData.RmbBlock.MiscFlatObjectRecords) { // Add point lights if (obj.TextureArchive == TextureReader.LightsTextureArchive) { // Calculate position Vector3 billboardPosition = new Vector3( obj.XPos, -obj.YPos + blockFlatsOffsetY, obj.ZPos + BlocksFile.RMBDimension) * MeshReader.GlobalScale; // Import custom 3d gameobject instead of flat if (MeshReplacement.ImportCustomFlatGameobject(obj.TextureArchive, obj.TextureRecord, billboardPosition, flatsParent) != null) { continue; } // Add billboard to batch or standalone if (billboardBatch != null) { billboardBatch.AddItem(obj.TextureRecord, billboardPosition); } else { GameObject go = GameObjectHelper.CreateDaggerfallBillboardGameObject(obj.TextureArchive, obj.TextureRecord, flatsParent); go.transform.position = billboardPosition; AlignBillboardToBase(go); } // Import light prefab AddLight(dfUnity, obj, lightsParent); } } }
/// <summary> /// Add nature billboards. /// </summary> public static void AddNatureFlats( ref DFBlock blockData, Transform flatsParent, DaggerfallBillboardBatch billboardBatch = null, ClimateNatureSets climateNature = ClimateNatureSets.TemperateWoodland, ClimateSeason climateSeason = ClimateSeason.Summer) { DaggerfallUnity dfUnity = DaggerfallUnity.Instance; if (!dfUnity.IsReady) { return; } for (int y = 0; y < 16; y++) { for (int x = 0; x < 16; x++) { // Get scenery item - ignore indices -1 (empty) and 0 (marker/waypoint of some kind) DFBlock.RmbGroundScenery scenery = blockData.RmbBlock.FldHeader.GroundData.GroundScenery[x, 15 - y]; if (scenery.TextureRecord < 1) { continue; } // Calculate position Vector3 billboardPosition = new Vector3( x * BlocksFile.TileDimension, natureFlatsOffsetY, y * BlocksFile.TileDimension + BlocksFile.TileDimension) * MeshReader.GlobalScale; // Get Archive int natureArchive = ClimateSwaps.GetNatureArchive(climateNature, climateSeason); // Import custom 3d gameobject instead of flat if (MeshReplacement.ImportCustomFlatGameobject(natureArchive, scenery.TextureRecord, billboardPosition, flatsParent) != null) { continue; } // Add billboard to batch or standalone if (billboardBatch != null) { billboardBatch.AddItem(scenery.TextureRecord, billboardPosition); } else { GameObject go = GameObjectHelper.CreateDaggerfallBillboardGameObject(natureArchive, scenery.TextureRecord, flatsParent); go.transform.position = billboardPosition; AlignBillboardToBase(go); } } } }
/// <summary> /// Create a billboard batch with custom material/ /// </summary> /// <param name="material">Custom atlas material.</param> /// <param name="parent">Parent transform.</param> /// <returns>Billboard batch GameObject.</returns> public static DaggerfallBillboardBatch CreateBillboardBatchGameObject(Material material, Transform parent = null) { // Create new billboard batch object parented to terrain GameObject billboardBatchObject = new GameObject(); billboardBatchObject.transform.parent = parent; billboardBatchObject.transform.localPosition = Vector3.zero; DaggerfallBillboardBatch c = billboardBatchObject.AddComponent <DaggerfallBillboardBatch>(); // Setup batch c.SetMaterial(material); return(c); }
public BaseDataObject( DaggerfallTerrain DFTerrain, DaggerfallBillboardBatch DFBillboardBatch, Terrain Terrain, float Scale, float Steepness, int X, int Y, float MaxTerrainHeight) { dfTerrain = DFTerrain; dfBillboardBatch = DFBillboardBatch; terrain = Terrain; scale = Scale; steepness = Steepness; x = X; y = Y; maxTerrainHeight = MaxTerrainHeight; }
/// <summary> /// Layout RMB block gamne object from name only. /// This will be missing information like building data and should only be used standalone. /// </summary> public static GameObject CreateRMBBlockGameObject( string blockName, int layoutX, int layoutY, bool addGroundPlane = true, DaggerfallRMBBlock cloneFrom = null, DaggerfallBillboardBatch natureBillboardBatch = null, DaggerfallBillboardBatch lightsBillboardBatch = null, DaggerfallBillboardBatch animalsBillboardBatch = null, TextureAtlasBuilder miscBillboardAtlas = null, DaggerfallBillboardBatch miscBillboardBatch = null, ClimateNatureSets climateNature = ClimateNatureSets.TemperateWoodland, ClimateSeason climateSeason = ClimateSeason.Summer) { // Get block data from name DFBlock blockData; if (!RMBLayout.GetBlockData(blockName, out blockData)) { return(null); } // Create base object from block data GameObject go = CreateRMBBlockGameObject( blockData, layoutX, layoutY, addGroundPlane, cloneFrom, natureBillboardBatch, lightsBillboardBatch, animalsBillboardBatch, miscBillboardAtlas, miscBillboardBatch, climateNature, climateSeason); return(go); }
public static void AddNatureFlatsToBatch( DaggerfallBillboardBatch batch, ref DFBlock blockData) { for (int y = 0; y < 16; y++) { for (int x = 0; x < 16; x++) { // Get scenery item DFBlock.RmbGroundScenery scenery = blockData.RmbBlock.FldHeader.GroundData.GroundScenery[x, 15 - y]; // Ignore 0 as this appears to be a marker/waypoint of some kind if (scenery.TextureRecord > 0) { Vector3 billboardPosition = new Vector3( x * BlocksFile.TileDimension, NatureFlatsOffsetY, y * BlocksFile.TileDimension + BlocksFile.TileDimension) * MeshReader.GlobalScale; batch.AddItem(scenery.TextureRecord, billboardPosition); } } } }
/// <summary> /// Add misc block flats. /// Batching is conditionally supported. /// </summary> public static void AddMiscBlockFlats( ref DFBlock blockData, Transform flatsParent, DaggerfallBillboardBatch animalsBillboardBatch = null, TextureAtlasBuilder miscBillboardsAtlas = null, DaggerfallBillboardBatch miscBillboardsBatch = null) { DaggerfallUnity dfUnity = DaggerfallUnity.Instance; if (!dfUnity.IsReady) { return; } // Add block flats foreach (DFBlock.RmbBlockFlatObjectRecord obj in blockData.RmbBlock.MiscFlatObjectRecords) { // Ignore lights as they are handled by AddLights() if (obj.TextureArchive == TextureReader.LightsTextureArchive) { continue; } // Calculate position Vector3 billboardPosition = new Vector3( obj.XPos, -obj.YPos + blockFlatsOffsetY, obj.ZPos + BlocksFile.RMBDimension) * MeshReader.GlobalScale; // Import custom 3d gameobject instead of flat if (MeshReplacement.ImportCustomFlatGameobject(obj.TextureArchive, obj.TextureRecord, billboardPosition, flatsParent) != null) { continue; } //// Use misc billboard atlas where available //if (miscBillboardsAtlas != null && miscBillboardsBatch != null) //{ // TextureAtlasBuilder.AtlasItem item = miscBillboardsAtlas.GetAtlasItem(obj.TextureArchive, obj.TextureRecord); // if (item.key != -1) // { // miscBillboardsBatch.AddItem(item.rect, item.textureItem.size, item.textureItem.scale, billboardPosition); // continue; // } //} // Add to batch where available //if (obj.TextureArchive == TextureReader.AnimalsTextureArchive && animalsBillboardBatch != null) //{ // animalsBillboardBatch.AddItem(obj.TextureRecord, billboardPosition); // continue; //} // Add standalone billboard gameobject GameObject go = GameObjectHelper.CreateDaggerfallBillboardGameObject(obj.TextureArchive, obj.TextureRecord, flatsParent); go.transform.position = billboardPosition; AlignBillboardToBase(go); // Add animal sound if (obj.TextureArchive == TextureReader.AnimalsTextureArchive) { AddAnimalAudioSource(go); } // If flat record has a non-zero faction id, then it's an exterior NPC if (obj.FactionID != 0) { // Add RMB data to billboard DaggerfallBillboard dfBillboard = go.GetComponent <DaggerfallBillboard>(); dfBillboard.SetRMBPeopleData(obj.FactionID, obj.Flags, obj.Position); // Add StaticNPC behaviour StaticNPC npc = go.AddComponent <StaticNPC>(); npc.SetLayoutData(obj); } } }
/// <summary> /// Layout a complete RMB block game object. /// Can be used standalone or as part of a city build. /// </summary> public static GameObject CreateRMBBlockGameObject( string blockName, bool addGroundPlane = true, DaggerfallRMBBlock cloneFrom = null, DaggerfallBillboardBatch natureBillboardBatch = null, DaggerfallBillboardBatch lightsBillboardBatch = null, DaggerfallBillboardBatch animalsBillboardBatch = null, TextureAtlasBuilder miscBillboardAtlas = null, DaggerfallBillboardBatch miscBillboardBatch = null, ClimateNatureSets climateNature = ClimateNatureSets.TemperateWoodland, ClimateSeason climateSeason = ClimateSeason.Summer) { // Get DaggerfallUnity DaggerfallUnity dfUnity = DaggerfallUnity.Instance; if (!dfUnity.IsReady) return null; // Create base object DFBlock blockData; GameObject go = RMBLayout.CreateBaseGameObject(blockName, out blockData, cloneFrom); // Create flats node GameObject flatsNode = new GameObject("Flats"); flatsNode.transform.parent = go.transform; // Create lights node GameObject lightsNode = new GameObject("Lights"); lightsNode.transform.parent = go.transform; // If billboard batching is enabled but user has not specified // a batch, then make our own auto batch for this block bool autoLightsBatch = false; bool autoNatureBatch = false; bool autoAnimalsBatch = false; if (dfUnity.Option_BatchBillboards) { if (natureBillboardBatch == null) { autoNatureBatch = true; int natureArchive = ClimateSwaps.GetNatureArchive(climateNature, climateSeason); natureBillboardBatch = GameObjectHelper.CreateBillboardBatchGameObject(natureArchive, flatsNode.transform); } if (lightsBillboardBatch == null) { autoLightsBatch = true; lightsBillboardBatch = GameObjectHelper.CreateBillboardBatchGameObject(TextureReader.LightsTextureArchive, flatsNode.transform); } if (animalsBillboardBatch == null) { autoAnimalsBatch = true; animalsBillboardBatch = GameObjectHelper.CreateBillboardBatchGameObject(TextureReader.AnimalsTextureArchive, flatsNode.transform); } } // Layout light billboards and gameobjects RMBLayout.AddLights(ref blockData, flatsNode.transform, lightsNode.transform, lightsBillboardBatch); // Layout nature billboards RMBLayout.AddNatureFlats(ref blockData, flatsNode.transform, natureBillboardBatch, climateNature, climateSeason); // Layout all other flats RMBLayout.AddMiscBlockFlats(ref blockData, flatsNode.transform, animalsBillboardBatch, miscBillboardAtlas, miscBillboardBatch); // Add ground plane if (addGroundPlane) RMBLayout.AddGroundPlane(ref blockData, go.transform); // Apply auto batches if (autoNatureBatch) natureBillboardBatch.Apply(); if (autoLightsBatch) lightsBillboardBatch.Apply(); if (autoAnimalsBatch) animalsBillboardBatch.Apply(); return go; }
/// <summary> /// Add nature billboards. /// </summary> public static void AddNatureFlats( ref DFBlock blockData, Transform flatsParent, DaggerfallBillboardBatch billboardBatch = null, ClimateNatureSets climateNature = ClimateNatureSets.TemperateWoodland, ClimateSeason climateSeason = ClimateSeason.Summer) { DaggerfallUnity dfUnity = DaggerfallUnity.Instance; if (!dfUnity.IsReady) return; for (int y = 0; y < 16; y++) { for (int x = 0; x < 16; x++) { // Get scenery item - ignore indices -1 (empty) and 0 (marker/waypoint of some kind) DFBlock.RmbGroundScenery scenery = blockData.RmbBlock.FldHeader.GroundData.GroundScenery[x, 15 - y]; if (scenery.TextureRecord < 1) continue; // Calculate position Vector3 billboardPosition = new Vector3( x * BlocksFile.TileDimension, natureFlatsOffsetY, y * BlocksFile.TileDimension + BlocksFile.TileDimension) * MeshReader.GlobalScale; // Add billboard to batch or standalone if (billboardBatch != null) { billboardBatch.AddItem(scenery.TextureRecord, billboardPosition); } else { int natureArchive = ClimateSwaps.GetNatureArchive(climateNature, climateSeason); GameObject go = GameObjectHelper.CreateDaggerfallBillboardGameObject(natureArchive, scenery.TextureRecord, flatsParent); go.transform.position = billboardPosition; } } } }
/// <summary> /// Add misc block flats. /// Batching is conditionally supported. /// </summary> public static void AddMiscBlockFlats( ref DFBlock blockData, Transform flatsParent, DaggerfallBillboardBatch animalsBillboardBatch = null, TextureAtlasBuilder miscBillboardsAtlas = null, DaggerfallBillboardBatch miscBillboardsBatch = null) { DaggerfallUnity dfUnity = DaggerfallUnity.Instance; if (!dfUnity.IsReady) return; // Add block flats foreach (DFBlock.RmbBlockFlatObjectRecord obj in blockData.RmbBlock.MiscFlatObjectRecords) { // Ignore lights as they are handled by AddLights() if (obj.TextureArchive == TextureReader.LightsTextureArchive) continue; // Calculate position Vector3 billboardPosition = new Vector3( obj.XPos, -obj.YPos + blockFlatsOffsetY, obj.ZPos + BlocksFile.RMBDimension) * MeshReader.GlobalScale; // Use misc billboard atlas where available if (miscBillboardsAtlas != null && miscBillboardsBatch != null) { TextureAtlasBuilder.AtlasItem item = miscBillboardsAtlas.GetAtlasItem(obj.TextureArchive, obj.TextureRecord); if (item.key != -1) { miscBillboardsBatch.AddItem(item.rect, item.textureItem.size, item.textureItem.scale, billboardPosition); continue; } } // Add to batch where available if (obj.TextureArchive == TextureReader.AnimalsTextureArchive && animalsBillboardBatch != null) { animalsBillboardBatch.AddItem(obj.TextureRecord, billboardPosition); } else { // Add standalone billboard gameobject GameObject go = GameObjectHelper.CreateDaggerfallBillboardGameObject(obj.TextureArchive, obj.TextureRecord, flatsParent); go.transform.position = billboardPosition; } } }
/// <summary> /// Adds light flats and prefabs. /// </summary> public static void AddLights( ref DFBlock blockData, Transform flatsParent, Transform lightsParent, DaggerfallBillboardBatch billboardBatch = null) { DaggerfallUnity dfUnity = DaggerfallUnity.Instance; if (!dfUnity.IsReady) return; // Do nothing if import option not enabled or missing prefab if (!dfUnity.Option_ImportLightPrefabs || dfUnity.Option_CityLightPrefab == null) return; // Iterate block flats for lights foreach (DFBlock.RmbBlockFlatObjectRecord obj in blockData.RmbBlock.MiscFlatObjectRecords) { // Add point lights if (obj.TextureArchive == TextureReader.LightsTextureArchive) { // Calculate position Vector3 billboardPosition = new Vector3( obj.XPos, -obj.YPos + blockFlatsOffsetY, obj.ZPos + BlocksFile.RMBDimension) * MeshReader.GlobalScale; // Add billboard to batch or standalone if (billboardBatch != null) { billboardBatch.AddItem(obj.TextureRecord, billboardPosition); } else { GameObject go = GameObjectHelper.CreateDaggerfallBillboardGameObject(obj.TextureArchive, obj.TextureRecord, flatsParent); go.transform.position = billboardPosition; } // Import light prefab AddLight(dfUnity, obj, lightsParent); } } }
/// <summary> /// Layout a complete RMB block game object. /// Can be used standalone or as part of a city build. /// </summary> public static GameObject CreateRMBBlockGameObject( string blockName, bool addGroundPlane = true, DaggerfallRMBBlock cloneFrom = null, DaggerfallBillboardBatch natureBillboardBatch = null, DaggerfallBillboardBatch lightsBillboardBatch = null, DaggerfallBillboardBatch animalsBillboardBatch = null, TextureAtlasBuilder miscBillboardAtlas = null, DaggerfallBillboardBatch miscBillboardBatch = null, ClimateNatureSets climateNature = ClimateNatureSets.TemperateWoodland, ClimateSeason climateSeason = ClimateSeason.Summer) { // Get DaggerfallUnity DaggerfallUnity dfUnity = DaggerfallUnity.Instance; if (!dfUnity.IsReady) { return(null); } // Create base object DFBlock blockData; GameObject go = RMBLayout.CreateBaseGameObject(blockName, out blockData, cloneFrom); // Create flats node GameObject flatsNode = new GameObject("Flats"); flatsNode.transform.parent = go.transform; // Create lights node GameObject lightsNode = new GameObject("Lights"); lightsNode.transform.parent = go.transform; // If billboard batching is enabled but user has not specified // a batch, then make our own auto batch for this block bool autoLightsBatch = false; bool autoNatureBatch = false; bool autoAnimalsBatch = false; if (dfUnity.Option_BatchBillboards) { if (natureBillboardBatch == null) { autoNatureBatch = true; int natureArchive = ClimateSwaps.GetNatureArchive(climateNature, climateSeason); natureBillboardBatch = GameObjectHelper.CreateBillboardBatchGameObject(natureArchive, flatsNode.transform); } if (lightsBillboardBatch == null) { autoLightsBatch = true; lightsBillboardBatch = GameObjectHelper.CreateBillboardBatchGameObject(TextureReader.LightsTextureArchive, flatsNode.transform); } if (animalsBillboardBatch == null) { autoAnimalsBatch = true; animalsBillboardBatch = GameObjectHelper.CreateBillboardBatchGameObject(TextureReader.AnimalsTextureArchive, flatsNode.transform); } } // Layout light billboards and gameobjects RMBLayout.AddLights(ref blockData, flatsNode.transform, lightsNode.transform, lightsBillboardBatch); // Layout nature billboards RMBLayout.AddNatureFlats(ref blockData, flatsNode.transform, natureBillboardBatch, climateNature, climateSeason); // Layout all other flats RMBLayout.AddMiscBlockFlats(ref blockData, flatsNode.transform, animalsBillboardBatch, miscBillboardAtlas, miscBillboardBatch); // Add ground plane if (addGroundPlane) { RMBLayout.AddGroundPlane(ref blockData, go.transform); } // Apply auto batches if (autoNatureBatch) { natureBillboardBatch.Apply(); } if (autoLightsBatch) { lightsBillboardBatch.Apply(); } if (autoAnimalsBatch) { animalsBillboardBatch.Apply(); } return(go); }
public static GameObject CreateGameObject( DaggerfallUnity dfUnity, ref DFBlock blockData, bool disableGround = false, DaggerfallBillboardBatch natureBatch = null) { // Create gameobject GameObject go = new GameObject(string.Format("DaggerfallBlock [Name={0}]", blockData.Name)); //go.AddComponent<DaggerfallBlock>(); // Setup combiner ModelCombiner combiner = null; if (dfUnity.Option_CombineRMB) { combiner = new ModelCombiner(); } // Lists to receive any doors found in this block List <StaticDoor> modelDoors; List <StaticDoor> propDoors; // Add models and props GameObject modelsNode = new GameObject("Models"); modelsNode.transform.parent = go.transform; AddModels(dfUnity, ref blockData, out modelDoors, combiner, modelsNode.transform); AddProps(dfUnity, ref blockData, out propDoors, combiner, modelsNode.transform); // Add doors List <StaticDoor> allDoors = new List <StaticDoor>(); if (modelDoors.Count > 0) { allDoors.AddRange(modelDoors); } if (propDoors.Count > 0) { allDoors.AddRange(propDoors); } if (allDoors.Count > 0) { AddDoors(allDoors.ToArray(), go); } // Add block flats GameObject flatsNode = new GameObject("Flats"); flatsNode.transform.parent = go.transform; AddBlockFlats(dfUnity, ref blockData, flatsNode.transform); // Add nature flats if (natureBatch == null) { AddNatureFlats(dfUnity, ref blockData, flatsNode.transform); } else { AddNatureFlatsToBatch(natureBatch, ref blockData); } // Add ground plane if (dfUnity.Option_SimpleGroundPlane && !disableGround) { AddSimpleGroundPlane(dfUnity, ref blockData, go.transform); } // Apply combiner if (combiner != null) { if (combiner.VertexCount > 0) { combiner.Apply(); GameObjectHelper.CreateCombinedMeshGameObject( combiner, "CombinedModels", modelsNode.transform, dfUnity.Option_SetStaticFlags); } } return(go); }
/// <summary> /// Add misc block flats. /// Batching is conditionally supported. /// </summary> public static void AddMiscBlockFlats( ref DFBlock blockData, Transform flatsParent, int mapId, int locationIndex, DaggerfallBillboardBatch animalsBillboardBatch = null, TextureAtlasBuilder miscBillboardsAtlas = null, DaggerfallBillboardBatch miscBillboardsBatch = null) { DaggerfallUnity dfUnity = DaggerfallUnity.Instance; if (!dfUnity.IsReady) { return; } // Add block flats foreach (DFBlock.RmbBlockFlatObjectRecord obj in blockData.RmbBlock.MiscFlatObjectRecords) { // Ignore lights as they are handled by AddLights() if (obj.TextureArchive == TextureReader.LightsTextureArchive) { continue; } // Calculate position Vector3 billboardPosition = new Vector3( obj.XPos, -obj.YPos + blockFlatsOffsetY, obj.ZPos + BlocksFile.RMBDimension) * MeshReader.GlobalScale; GameObject go = MeshReplacement.ImportCustomFlatGameobject(obj.TextureArchive, obj.TextureRecord, billboardPosition, flatsParent); if (go == null) { // Add standalone billboard gameobject go = GameObjectHelper.CreateDaggerfallBillboardGameObject(obj.TextureArchive, obj.TextureRecord, flatsParent); go.transform.position = billboardPosition; AlignBillboardToBase(go); } // Add animal sound if (obj.TextureArchive == TextureReader.AnimalsTextureArchive) { AddAnimalAudioSource(go, obj.TextureRecord); } // If flat record has a non-zero faction id, then it's an exterior NPC if (obj.FactionID != 0) { // Add RMB data to billboard Billboard dfBillboard = go.GetComponent <Billboard>(); if (dfBillboard != null) { dfBillboard.SetRMBPeopleData(obj.FactionID, obj.Flags, obj.Position); } // Add StaticNPC behaviour StaticNPC npc = go.AddComponent <StaticNPC>(); npc.SetLayoutData(obj, mapId, locationIndex); } } }