Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

City generation stability improvements #2617

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Assets/Scripts/Game/StaticNPC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,11 @@ public void SetLayoutData(DFBlock.RmbBlockFlatObjectRecord obj, int mapId, int l
int flatID = FlatsFile.GetFlatID(obj.TextureArchive, obj.TextureRecord);
if (DaggerfallUnity.Instance.ContentReader.FlatsFileReader.GetFlatData(flatID, out FlatsFile.FlatData flatCFG))
{
if (flatCFG.gender.Contains("2"))
// We've had null reference exceptions in this function,
// which could only possibly be this gender field
if (flatCFG.gender == null)
Debug.LogError($"Flat '{obj.TextureArchive}_{obj.TextureRecord}' has invalid gender in FLATS.CFG");
else if (flatCFG.gender.Contains("2"))
obj.Flags |= 32;
else
obj.Flags &= 223;
Expand Down
201 changes: 114 additions & 87 deletions Assets/Scripts/Utility/RMBLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -339,42 +339,51 @@ public static void AddMiscBlockFlats(
// 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)
// If any error happens creating this object, try to avoid destroying the entire city
try
{
// Add standalone billboard gameobject
go = GameObjectHelper.CreateDaggerfallBillboardGameObject(obj.TextureArchive, obj.TextureRecord, flatsParent);
go.transform.position = billboardPosition;
AlignBillboardToBase(go);
}
// Ignore lights as they are handled by AddLights()
if (obj.TextureArchive == TextureReader.LightsTextureArchive)
continue;

// Add animal sound
if (obj.TextureArchive == TextureReader.AnimalsTextureArchive)
GameObjectHelper.AddAnimalAudioSource(go, obj.TextureRecord);
// Calculate position
Vector3 billboardPosition = new Vector3(
obj.XPos,
-obj.YPos + blockFlatsOffsetY,
obj.ZPos + BlocksFile.RMBDimension) * MeshReader.GlobalScale;

// 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);
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 StaticNPC behaviour
StaticNPC npc = go.AddComponent<StaticNPC>();
npc.SetLayoutData(obj, mapId, locationIndex);
// Add animal sound
if (obj.TextureArchive == TextureReader.AnimalsTextureArchive)
GameObjectHelper.AddAnimalAudioSource(go, obj.TextureRecord);

QuestMachine.Instance.SetupIndividualStaticNPC(go, obj.FactionID);
// 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);

QuestMachine.Instance.SetupIndividualStaticNPC(go, obj.FactionID);
}
}
catch(Exception ex)
{
Debug.LogError($"Error creating misc flat obj '{obj.Position}' of block '{blockData.Name}'");
Debug.LogException(ex);
}
}
}
Expand Down Expand Up @@ -404,69 +413,78 @@ public static void AddExteriorBlockFlats(

foreach (DFBlock.RmbBlockFlatObjectRecord obj in subRecord.Exterior.BlockFlatObjectRecords)
{
// Don't add building exterior editor flats since they can't be used by any DFU systems
int archive = obj.TextureArchive;
if (archive == TextureReader.EditorFlatsTextureArchive)
continue;
// If any error happens creating this object, try to avoid destroying the entire city
try
{
// Don't add building exterior editor flats since they can't be used by any DFU systems
int archive = obj.TextureArchive;
if (archive == TextureReader.EditorFlatsTextureArchive)
continue;

// Calculate position
Vector3 billboardPosition = new Vector3(
obj.XPos,
-obj.YPos + blockFlatsOffsetY,
obj.ZPos + BlocksFile.RMBDimension) * MeshReader.GlobalScale;
// Calculate position
Vector3 billboardPosition = new Vector3(
obj.XPos,
-obj.YPos + blockFlatsOffsetY,
obj.ZPos + BlocksFile.RMBDimension) * MeshReader.GlobalScale;

billboardPosition += subRecordPosition;
billboardPosition += subRecordPosition;

// Add natures using correct climate set archive
if (archive >= (int)DFLocation.ClimateTextureSet.Nature_RainForest && archive <= (int)DFLocation.ClimateTextureSet.Nature_Mountains_Snow)
{
archive = natureArchive;
billboardPosition.z = natureFlatsOffsetY;
}
// Add natures using correct climate set archive
if (archive >= (int)DFLocation.ClimateTextureSet.Nature_RainForest && archive <= (int)DFLocation.ClimateTextureSet.Nature_Mountains_Snow)
{
archive = natureArchive;
billboardPosition.z = natureFlatsOffsetY;
}

GameObject go = MeshReplacement.ImportCustomFlatGameobject(archive, obj.TextureRecord, billboardPosition, flatsParent);
bool isImported = go != null;
if (!isImported)
{
// Add standalone billboard gameobject
go = GameObjectHelper.CreateDaggerfallBillboardGameObject(archive, obj.TextureRecord, flatsParent);
go.transform.position = billboardPosition;
AlignBillboardToBase(go);
}
GameObject go = MeshReplacement.ImportCustomFlatGameobject(archive, obj.TextureRecord, billboardPosition, flatsParent);
bool isImported = go != null;
if (!isImported)
{
// Add standalone billboard gameobject
go = GameObjectHelper.CreateDaggerfallBillboardGameObject(archive, obj.TextureRecord, flatsParent);
go.transform.position = billboardPosition;
AlignBillboardToBase(go);
}

// Add animal sound
if (archive == TextureReader.AnimalsTextureArchive)
GameObjectHelper.AddAnimalAudioSource(go, obj.TextureRecord);
// Add animal sound
if (archive == TextureReader.AnimalsTextureArchive)
GameObjectHelper.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);
// 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);
// Add StaticNPC behaviour
StaticNPC npc = go.AddComponent<StaticNPC>();
npc.SetLayoutData(obj, mapId, locationIndex);

QuestMachine.Instance.SetupIndividualStaticNPC(go, obj.FactionID);
}
QuestMachine.Instance.SetupIndividualStaticNPC(go, obj.FactionID);
}

// If this is a light flat, import light prefab
if (archive == TextureReader.LightsTextureArchive && !isImported)
{
if (dfUnity.Option_CityLightPrefab == null)
return;
// If this is a light flat, import light prefab
if (archive == TextureReader.LightsTextureArchive && !isImported)
{
if (dfUnity.Option_CityLightPrefab == null)
return;

Vector2 size = dfUnity.MeshReader.GetScaledBillboardSize(210, obj.TextureRecord);
Vector3 position = new Vector3(
obj.XPos,
-obj.YPos + size.y,
obj.ZPos + BlocksFile.RMBDimension) * MeshReader.GlobalScale;
position += subRecordPosition;
Vector2 size = dfUnity.MeshReader.GetScaledBillboardSize(210, obj.TextureRecord);
Vector3 position = new Vector3(
obj.XPos,
-obj.YPos + size.y,
obj.ZPos + BlocksFile.RMBDimension) * MeshReader.GlobalScale;
position += subRecordPosition;

GameObjectHelper.InstantiatePrefab(dfUnity.Option_CityLightPrefab.gameObject, string.Empty, lightsParent, position);
GameObjectHelper.InstantiatePrefab(dfUnity.Option_CityLightPrefab.gameObject, string.Empty, lightsParent, position);
}
}
catch (Exception ex)
{
Debug.LogError($"Error creating exterior block flat obj '{obj.Position}' of block '{blockData.Name}'");
Debug.LogException(ex);
}
}
}
Expand Down Expand Up @@ -840,7 +858,7 @@ private static void AddModels(

// Get model data
ModelData modelData;
dfUnity.MeshReader.GetModelData(obj.ModelIdNum, out modelData);
bool hasModelData = dfUnity.MeshReader.GetModelData(obj.ModelIdNum, out modelData);

// Does this model have doors?
StaticDoor[] staticDoors = null;
Expand Down Expand Up @@ -875,10 +893,19 @@ private static void AddModels(
if (staticDoors != null && staticDoors.Length > 0)
CustomDoor.InitDoors(go, staticDoors, buildingKey, out dontCreateStaticDoors);
}
else if (combiner == null || IsCityGate(obj.ModelIdNum) || IsBulletinBoard(obj.ModelIdNum) || PlayerActivate.HasCustomActivation(obj.ModelIdNum))
AddStandaloneModel(dfUnity, ref modelData, modelMatrix, parent);
else
combiner.Add(ref modelData, modelMatrix);
{
if(!hasModelData)
{
Debug.LogError($"Could not load model '{obj.ModelIdNum}' in block '{blockData.Name}'");
continue;
}

if (combiner == null || IsCityGate(obj.ModelIdNum) || IsBulletinBoard(obj.ModelIdNum) || PlayerActivate.HasCustomActivation(obj.ModelIdNum))
AddStandaloneModel(dfUnity, ref modelData, modelMatrix, parent);
else
combiner.Add(ref modelData, modelMatrix);
}

if (modelData.Doors != null && !dontCreateStaticDoors)
doorsOut.AddRange(staticDoors);
Expand Down