private void CheckDoorwayCount(DungeonFlow flow, DungeonValidator validator) { var pathTileSets = new List <TileSet>(); foreach (var node in flow.Nodes) { if (node.NodeType != NodeType.Start && node.NodeType != NodeType.Goal) { pathTileSets.AddRange(node.TileSets); } } foreach (var line in flow.Lines) { foreach (var archetype in line.DungeonArchetypes) { pathTileSets.AddRange(archetype.TileSets); } } var pathTiles = pathTileSets.SelectMany(ts => ts.TileWeights.Weights.Select(w => w.Value)).Where(t => t != null); foreach (var tile in pathTiles) { int doorwayCount = tile.GetComponentsInChildren <Doorway>(true).Count(); if (doorwayCount < 2) { validator.AddError("Tile '{0}' does not have enough doorways. Two doorways are required for all tiles except those that appear exclusively as a start node, goal node, or branch cap", tile, tile.name); } } }
private void CheckArchetypes(DungeonFlow flow, DungeonValidator validator) { var archetypes = flow.GetUsedArchetypes(); foreach (var archetype in archetypes) { if (archetype == null) { continue; } if (archetype.TileSets.Count == 0) { validator.AddError("The archetype '{0}' has no tile sets assigned", archetype, archetype.name); } else { foreach (var tileSet in archetype.TileSets) { if (tileSet == null) { validator.AddError("The archetype '{0}' has a missing tile set", archetype, archetype.name); } } } foreach (var tileSet in archetype.BranchCapTileSets) { if (tileSet == null) { validator.AddError("Archetype '{0}' has a missing branch cap tile set", archetype, archetype.name); } } } }
private void CheckDoorwayForwardVectors(DungeonFlow flow, DungeonValidator validator, Dictionary <GameObject, Doorway[]> tileDoorways) { foreach (var pair in tileDoorways) { var tile = pair.Key; var bounds = UnityUtil.CalculateObjectBounds(tile, true, false); foreach (var doorway in pair.Value) { Vector3 forwardVector = doorway.transform.forward; if (!IsAxisAligned(forwardVector)) { validator.AddError("Doorway '{0}' in tile '{1}' has an invalid rotation. the forward vector is not axis-aligned", tile, doorway.name, tile.name); } else { Vector3 centerToDoorway = (doorway.transform.position - bounds.center).normalized; float angle = Vector3.Angle(centerToDoorway, forwardVector); if (angle > 85f) { validator.AddError("Doorway '{0}' in tile '{1}' is facing the wrong way. Doorways should face outwards from the tile (local z-axis, blue line)", tile, doorway.name, tile.name); } } } } }
private void CheckNodes(DungeonFlow flow, DungeonValidator validator) { if (flow.Nodes.Count < 2) { validator.AddError("The dungeon flow must contain at least two nodes"); } foreach (var node in flow.Nodes) { if (node.TileSets.Count == 0) { validator.AddError("The node '{0}' in the dungeon flow graph has no tile sets applied", node.Label); } else { foreach (var tileSet in node.TileSets) { if (tileSet == null) { validator.AddError("Node '{0}' in your dungeon flow graph has an unset tileset value", node.Label); } } } } }
private void CheckDoorwayUpVectors(DungeonFlow flow, DungeonValidator validator, Dictionary <GameObject, Doorway[]> tileDoorways) { var doorwaysByUpVector = new Dictionary <Vector3, List <DoorwayInfo> >(); foreach (var pair in tileDoorways) { foreach (var doorway in pair.Value) { Vector3 upVector = doorway.transform.up; List <DoorwayInfo> doorwaySet = null; foreach (var existingPair in doorwaysByUpVector) { if (Vector3.Angle(upVector, existingPair.Key) <= AngleThreshold) { doorwaySet = existingPair.Value; } } if (doorwaySet == null) { doorwaySet = new List <DoorwayInfo>(); doorwaysByUpVector[upVector] = doorwaySet; } doorwaySet.Add(new DoorwayInfo(doorway, pair.Key)); } } if (doorwaysByUpVector.Count > 1) { Vector3 mostCommonUpVector = doorwaysByUpVector.OrderByDescending(x => x.Value.Count).First().Key; if (!IsAxisAligned(mostCommonUpVector)) { validator.AddError("The most common doorway up vector is not axis-aligned"); } foreach (var pair in doorwaysByUpVector) { if (pair.Key == mostCommonUpVector) { continue; } foreach (var info in pair.Value) { validator.AddError("Doorway '{0}' in tile '{1}' has an invalid rotation. The most common up-vector among doorways is {2}", info.TilePrefab, info.Doorway.name, info.TilePrefab.name, mostCommonUpVector); } } } }
public void Validate(DungeonFlow flow, DungeonValidator validator) { // Check DungeonFlow if (flow == null) { validator.AddError("No DungeonFlow is assigned"); return; } CheckLineSegments(flow, validator); CheckNodes(flow, validator); CheckArchetypes(flow, validator); CheckTileSets(flow, validator); }
private void CheckDoorwaySockets(DungeonFlow flow, DungeonValidator validator, Dictionary <GameObject, Doorway[]> tileDoorways) { foreach (var pair in tileDoorways) { var tile = pair.Key; foreach (var doorway in pair.Value) { if (!doorway.HasSocketAssigned) { validator.AddWarning("Doorway '{0}' in tile '{1}' has no socket assigned. The default socket will be used.", tile, doorway.name, tile.name); } } } }
public void Validate(DungeonFlow flow, DungeonValidator validator) { var tiles = flow.GetUsedTileSets() .SelectMany(ts => ts.TileWeights.Weights.Select(w => w.Value)) .Where(t => t != null); var tileDoorways = new Dictionary <GameObject, Doorway[]>(); foreach (var tile in tiles) { tileDoorways[tile] = tile.GetComponentsInChildren <Doorway>(true); } CheckDoorwayCount(flow, validator); CheckDoorwayUpVectors(flow, validator, tileDoorways); CheckDoorwayForwardVectors(flow, validator, tileDoorways); CheckDoorwaySockets(flow, validator, tileDoorways); }
private void CheckTileSets(DungeonFlow flow, DungeonValidator validator) { var tileSets = flow.GetUsedTileSets(); foreach (var tileSet in tileSets) { if (tileSet == null) { continue; } foreach (var tileWeight in tileSet.TileWeights.Weights) { if (tileWeight.Value == null) { validator.AddWarning("The tile set '{0}' has a missing tile", tileSet, tileSet.name); } if (tileWeight.MainPathWeight <= 0f && tileWeight.BranchPathWeight <= 0f) { validator.AddWarning("Tile set '{0}' has a tile ({1}) set up with a main path weight and branch path weight of zero. This tile will never appear in the dungeon", tileSet, tileSet.name, (tileWeight.Value == null) ? "NULL" : tileWeight.Value.name); } if (tileWeight.DepthWeightScale != null) { bool hasNonZeroKeyframe = false; foreach (var key in tileWeight.DepthWeightScale.keys) { if (key.value > 0f) { hasNonZeroKeyframe = true; break; } } if (!hasNonZeroKeyframe) { validator.AddWarning("Tile set '{0}' has a tile ({1}) set up with a depth curve that will always return zero. This tile will never appear in the dungeon", tileSet, tileSet.name, tileWeight.Value.name); } } } } }
private void CheckLineSegments(DungeonFlow flow, DungeonValidator validator) { if (flow.Lines.Count < 1) { validator.AddError("The dungeon flow must contain at least one line segment"); } foreach (var line in flow.Lines) { if (line.DungeonArchetypes.Count == 0) { validator.AddError("A line segments in your dungeon flow graph has no archetype applied"); } foreach (var archetype in line.DungeonArchetypes) { if (archetype == null) { validator.AddError("A line segment in your dungeon flow graph has an unset archetype value"); } } } }