Created
June 9, 2023 22:17
-
-
Save alexjlockwood/71b087d9c3c244df768471b8aeef331d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using FG.Common; | |
using Levels.ProceduralGeneration; | |
using MPG.Utility; | |
using UnityEngine; | |
namespace Levels.CrownMaze | |
{ | |
// Token: 0x020004BE RID: 1214 | |
public class CrownMazeGrid : FGBehaviour | |
{ | |
// Token: 0x06001C04 RID: 7172 RVA: 0x0005D8E7 File Offset: 0x0005BAE7 | |
public void Awake() | |
{ | |
this.InitialiseGrid(); | |
this.GeneratePathOnLoad(); | |
} | |
// Token: 0x06001C05 RID: 7173 RVA: 0x0005D8F8 File Offset: 0x0005BAF8 | |
private void GeneratePathOnLoad() | |
{ | |
if (!this._usePredeterminedSeed) | |
{ | |
this.seed = base.GameState.RoundRandomSeed; | |
} | |
if (!this.GeneratePath(false)) | |
{ | |
if (this._usePredeterminedSeed) | |
{ | |
Debug.LogError(string.Format("[CrownMaze] Path generation failed with predetermined seed {0}. DO NOT IGNORE, PREDETERMINED SHOULD BE A VALID SEED.", this.seed)); | |
} | |
else if (!this._incrementIfSeedFails && !this._useFallbackSeed) | |
{ | |
Debug.LogError(string.Format("[CrownMaze] Path generation failed with seed {0}.", this.seed)); | |
} | |
if (this._incrementIfSeedFails) | |
{ | |
this.ResetPaths(); | |
this.seed++; | |
if (this.GeneratePath(false)) | |
{ | |
return; | |
} | |
Debug.LogError(string.Format("[CrownMaze] Path generation failed with incremented seed {0}.", this.seed)); | |
} | |
if (this._useFallbackSeed) | |
{ | |
this.ResetPaths(); | |
this.seed = this.fallbackSeed; | |
if (!this.GeneratePath(false)) | |
{ | |
Debug.LogError(string.Format("[CrownMaze] Path generation failed with fallback seed {0}. DO NOT IGNORE, FALLBACK SHOULD BE A VALID SEED.", this.seed)); | |
return; | |
} | |
return; | |
} | |
} | |
} | |
// Token: 0x06001C06 RID: 7174 RVA: 0x0005D9FC File Offset: 0x0005BBFC | |
public void InitialiseGrid() | |
{ | |
int count = this._rowParents.Count; | |
this._segmentGrid = new CrownMazeGridSegment[count, count]; | |
this._nodeGrid = new AStar.PathNode[count, count]; | |
for (int i = 0; i < count; i++) | |
{ | |
int num = 0; | |
foreach (object obj in this._rowParents[i].transform) | |
{ | |
Transform transform = (Transform)obj; | |
this._segmentGrid[i, num] = transform.GetComponentInChildren<CrownMazeGridSegment>(); | |
this._segmentGrid[i, num].name = string.Format("Tile ({0}, {1})", i, num); | |
this._segmentGrid[i, num].Coordinate = new Vector2Int(i, num); | |
this._nodeGrid[i, num] = new AStar.PathNode(i, num, this._segmentGrid[i, num].PassableDirections, true); | |
num++; | |
} | |
} | |
this._startNode = new AStar.PathNode(this._startingSegment.Coordinate.x, this._startingSegment.Coordinate.y, this._startingSegment.PassableDirections, true); | |
this._endNode = new AStar.PathNode(this._crownSegment.Coordinate.x, this._crownSegment.Coordinate.y, this._crownSegment.PassableDirections, true); | |
} | |
// Token: 0x06001C07 RID: 7175 RVA: 0x0005DB8C File Offset: 0x0005BD8C | |
public bool GeneratePath(bool editorGeneration = false) | |
{ | |
Debug.Log(string.Format("[CrownMaze] Generating maze for Crown Maze with seed: {0}", this.seed)); | |
UnityEngine.Random.InitState(this.seed); | |
this._randomCrownDirection = (AStar.Direction)RandomUtils.GetRangeExcept(0, 3, (int)this._crownSegmentExitDirection); | |
this.ResetCrownNodeTraversableDirection(); | |
List<Vector2Int> rooms = (from w in this._waypointRooms | |
select w.Coordinate).ToList<Vector2Int>(); | |
List<Vector2Int> randomMidRooms = this.GetRandomMidRooms(rooms, 2); | |
randomMidRooms.Shuffle<Vector2Int>(); | |
List<List<AStar.PathNode>> list; | |
bool flag = this.TryGenerateFullPath(out list, randomMidRooms); | |
if (flag && list != null) | |
{ | |
List<AStar.PathNode> path = list[0].Concat(list[1]).Concat(list[2]).ToList<AStar.PathNode>(); | |
this.SetDoorsBreakability(path, editorGeneration); | |
} | |
return flag; | |
} | |
// Token: 0x06001C08 RID: 7176 RVA: 0x0005DC54 File Offset: 0x0005BE54 | |
private List<CrownMazeGridSegment> GetSegmentsFromPathNodes(List<AStar.PathNode> nodes) | |
{ | |
List<CrownMazeGridSegment> list = new List<CrownMazeGridSegment>(); | |
foreach (AStar.PathNode pathNode in nodes) | |
{ | |
list.Add(this._segmentGrid[pathNode.Coordinate.x, pathNode.Coordinate.y]); | |
} | |
return list; | |
} | |
// Token: 0x06001C09 RID: 7177 RVA: 0x0005DCCC File Offset: 0x0005BECC | |
private void ResetCrownNodeTraversableDirection() | |
{ | |
this._endNode.SetOnlyTravelDirection(this._randomCrownDirection); | |
this._endNode.SetTraversableDirection(this._crownSegmentExitDirection, true); | |
} | |
// Token: 0x06001C0A RID: 7178 RVA: 0x0005DCF4 File Offset: 0x0005BEF4 | |
private List<Vector2Int> GetRandomMidRooms(List<Vector2Int> rooms, int amount) | |
{ | |
int count = rooms.Count; | |
int[] array = new int[count]; | |
for (int i = 0; i < count; i++) | |
{ | |
array[i] = i; | |
} | |
array.Shuffle<int>(); | |
List<Vector2Int> list = new List<Vector2Int> | |
{ | |
rooms[array[0]] | |
}; | |
for (int j = 1; j < count; j++) | |
{ | |
int num = Mathf.Abs(list[0].x - rooms[array[j]].x); | |
int num2 = Mathf.Abs(list[0].y - rooms[array[j]].y); | |
if ((num + num2).IsBetween(this.minNodeDistance, this.maxNodeDistance, true) && num > 0) | |
{ | |
list.Add(rooms[array[j]]); | |
if (list.Count == amount) | |
{ | |
break; | |
} | |
} | |
} | |
int num3 = list.Count; | |
while (list.Count < amount) | |
{ | |
list.Add(rooms[array[num3]]); | |
num3++; | |
} | |
return list; | |
} | |
// Token: 0x06001C0B RID: 7179 RVA: 0x0005DE0C File Offset: 0x0005C00C | |
private bool TryGenerateFullPath(out List<List<AStar.PathNode>> path, List<Vector2Int> waypoints) | |
{ | |
bool result = true; | |
Vector2Int coordinate = this._startNode.Coordinate; | |
Vector2Int coordinate2 = this._endNode.Coordinate; | |
this._nodeGrid[coordinate.x, coordinate.y].State = AStar.PathNode.NodeState.Impassible; | |
if (!this.TryNavigatePath(out this._midPath1, this._nodeGrid, waypoints[0], waypoints[1])) | |
{ | |
Debug.LogError("[CrownMaze] Could not find first path between mid waypoints 0 and 1"); | |
path = null; | |
return false; | |
} | |
this.SetPathAsImpassible(this._nodeGrid, this._midPath1); | |
this._nodeGrid[coordinate.x, coordinate.y].State = AStar.PathNode.NodeState.Impassible; | |
if (!this.TryNavigatePath(out this._midPath2, this._nodeGrid, waypoints[1], waypoints[0])) | |
{ | |
Debug.LogError("[CrownMaze] Could not find second path between mid waypoints 1 and 0"); | |
path = null; | |
return false; | |
} | |
List<AStar.PathNode> list = this._midPath1.Concat(this._midPath2).ToList<AStar.PathNode>(); | |
this.SetGridPath(this._nodeGrid, list); | |
if (!this.TryConnectStartAndEndPoints(out this._startPath, out this._endPath, coordinate, coordinate2, waypoints[0], waypoints[1])) | |
{ | |
this.ResetCrownNodeTraversableDirection(); | |
this.SetGridPath(this._nodeGrid, list); | |
if (!this.TryConnectStartAndEndPoints(out this._startPath, out this._endPath, coordinate, coordinate2, waypoints[1], waypoints[0])) | |
{ | |
result = false; | |
} | |
} | |
path = new List<List<AStar.PathNode>> | |
{ | |
this._startPath, | |
list, | |
this._endPath | |
}; | |
return result; | |
} | |
// Token: 0x06001C0C RID: 7180 RVA: 0x0005DF90 File Offset: 0x0005C190 | |
private bool TryConnectStartAndEndPoints(out List<AStar.PathNode> startPath, out List<AStar.PathNode> endPath, Vector2Int start, Vector2Int end, Vector2Int waypoint1, Vector2Int waypoint2) | |
{ | |
startPath = new List<AStar.PathNode>(); | |
endPath = new List<AStar.PathNode>(); | |
bool flag = this.TryNavigatePath(out startPath, this._nodeGrid, waypoint1, this._startNode.Coordinate); | |
bool flag2 = false; | |
if (flag) | |
{ | |
flag2 = this.TryNavigatePath(out endPath, this._nodeGrid, waypoint2, this._endNode.Coordinate); | |
if (!flag2) | |
{ | |
this._endNode.SetAllDirectionsTraversable(true); | |
flag2 = this.TryNavigatePath(out endPath, this._nodeGrid, waypoint2, this._endNode.Coordinate); | |
} | |
} | |
return flag && flag2; | |
} | |
// Token: 0x06001C0D RID: 7181 RVA: 0x0005E014 File Offset: 0x0005C214 | |
private void SetDoorsBreakability(List<AStar.PathNode> path, bool editorGeneration = false) | |
{ | |
this._startingDoor.IsBreakable = true; | |
for (int i = 0; i < path.Count - 1; i++) | |
{ | |
AStar.Direction? directionToNode = path[i].GetDirectionToNode(path[i + 1].Coordinate); | |
if (directionToNode != null) | |
{ | |
Vector2Int coordinate = path[i].Coordinate; | |
Vector2Int coordinate2 = path[i + 1].Coordinate; | |
CrownMazeGridSegment crownMazeGridSegment = this._segmentGrid[coordinate.x, coordinate.y]; | |
CrownMazeGridSegment crownMazeGridSegment2 = this._segmentGrid[coordinate2.x, coordinate2.y]; | |
bool isBreakable = this.CanBreakDoor(path[i], directionToNode.Value); | |
switch (directionToNode.Value) | |
{ | |
case AStar.Direction.North: | |
if (crownMazeGridSegment.NorthDoor != null) | |
{ | |
crownMazeGridSegment.NorthDoor.IsBreakable = isBreakable; | |
} | |
if (crownMazeGridSegment2.SouthDoor != null) | |
{ | |
crownMazeGridSegment2.SouthDoor.IsBreakable = isBreakable; | |
} | |
break; | |
case AStar.Direction.East: | |
if (crownMazeGridSegment.EastDoor != null) | |
{ | |
crownMazeGridSegment.EastDoor.IsBreakable = isBreakable; | |
} | |
if (crownMazeGridSegment2.WestDoor != null) | |
{ | |
crownMazeGridSegment2.WestDoor.IsBreakable = isBreakable; | |
} | |
break; | |
case AStar.Direction.South: | |
if (crownMazeGridSegment.SouthDoor != null) | |
{ | |
crownMazeGridSegment.SouthDoor.IsBreakable = isBreakable; | |
} | |
if (crownMazeGridSegment2.NorthDoor != null) | |
{ | |
crownMazeGridSegment2.NorthDoor.IsBreakable = isBreakable; | |
} | |
break; | |
case AStar.Direction.West: | |
if (crownMazeGridSegment.WestDoor != null) | |
{ | |
crownMazeGridSegment.WestDoor.IsBreakable = isBreakable; | |
} | |
if (crownMazeGridSegment2.EastDoor != null) | |
{ | |
crownMazeGridSegment2.EastDoor.IsBreakable = isBreakable; | |
} | |
break; | |
} | |
} | |
} | |
if (!editorGeneration) | |
{ | |
for (int j = 0; j < this._segmentGrid.GetLength(0); j++) | |
{ | |
for (int k = 0; k < this._segmentGrid.GetLength(1); k++) | |
{ | |
this._segmentGrid[j, k].InitDoors(); | |
} | |
} | |
} | |
} | |
// Token: 0x06001C0E RID: 7182 RVA: 0x0005E24C File Offset: 0x0005C44C | |
private bool CanBreakDoor(AStar.PathNode room, AStar.Direction direction) | |
{ | |
if (room.IsPath && AStar.PathGenerator.CanTravelDirection(this._nodeGrid, room, direction)) | |
{ | |
AStar.PathNode surroundNode = AStar.PathGenerator.GetSurroundNode(this._nodeGrid, room.Coordinate, direction); | |
return surroundNode.IsPath && AStar.PathGenerator.CanTravelDirection(this._nodeGrid, surroundNode, AStar.GetOppositeDirection(direction)); | |
} | |
return false; | |
} | |
// Token: 0x06001C0F RID: 7183 RVA: 0x0005E2A4 File Offset: 0x0005C4A4 | |
private bool TryNavigatePath(out List<AStar.PathNode> path, AStar.PathNode[,] grid, Vector2Int start, Vector2Int end) | |
{ | |
Stack<AStar.PathNode> stack = AStar.PathGenerator.GeneratePathBetweenPoints(grid, start, end, 1f, 0f); | |
if (stack != null) | |
{ | |
path = stack.ToArray().ToList<AStar.PathNode>(); | |
} | |
else | |
{ | |
path = null; | |
} | |
return stack != null; | |
} | |
// Token: 0x06001C10 RID: 7184 RVA: 0x0005E2E0 File Offset: 0x0005C4E0 | |
private void ResetGrid(AStar.PathNode[,] grid) | |
{ | |
for (int i = 0; i < grid.GetLength(0); i++) | |
{ | |
for (int j = 0; j < grid.GetLength(1); j++) | |
{ | |
grid[i, j].ResetNode(i, j); | |
} | |
} | |
} | |
// Token: 0x06001C11 RID: 7185 RVA: 0x0005E320 File Offset: 0x0005C520 | |
private void SetGridPath(AStar.PathNode[,] grid, List<AStar.PathNode> pathNodes) | |
{ | |
this.ResetGrid(grid); | |
if (pathNodes != null) | |
{ | |
foreach (AStar.PathNode pathNode in pathNodes) | |
{ | |
grid[pathNode.Coordinate.x, pathNode.Coordinate.y].IsPath = true; | |
} | |
} | |
} | |
// Token: 0x06001C12 RID: 7186 RVA: 0x0005E394 File Offset: 0x0005C594 | |
private void SetPathAsImpassible(AStar.PathNode[,] grid, List<AStar.PathNode> pathNodes) | |
{ | |
this.ResetGrid(grid); | |
if (pathNodes != null) | |
{ | |
foreach (AStar.PathNode pathNode in pathNodes) | |
{ | |
grid[pathNode.Coordinate.x, pathNode.Coordinate.y].State = AStar.PathNode.NodeState.Impassible; | |
} | |
} | |
} | |
// Token: 0x06001C13 RID: 7187 RVA: 0x0005E408 File Offset: 0x0005C608 | |
public void ResetPaths() | |
{ | |
this._startPath = null; | |
this._midPath1 = null; | |
this._midPath2 = null; | |
this._endPath = null; | |
this.InitialiseGrid(); | |
} | |
// Token: 0x06001C14 RID: 7188 RVA: 0x0005E42C File Offset: 0x0005C62C | |
private void OnDrawGizmos() | |
{ | |
if (this._segmentGrid != null) | |
{ | |
if (this._startPath != null) | |
{ | |
this.DrawPathLineGizmo(this._startPath, Color.black); | |
} | |
if (this._midPath1 != null) | |
{ | |
this.DrawPathLineGizmo(this._midPath1, Color.green); | |
} | |
if (this._midPath2 != null) | |
{ | |
this.DrawPathLineGizmo(this._midPath2, Color.blue); | |
} | |
if (this._endPath != null) | |
{ | |
this.DrawPathLineGizmo(this._endPath, Color.magenta); | |
} | |
} | |
} | |
// Token: 0x06001C15 RID: 7189 RVA: 0x0005E4A8 File Offset: 0x0005C6A8 | |
private void DrawPathLineGizmo(List<AStar.PathNode> path, Color color) | |
{ | |
Transform transform = this._segmentGrid[path[0].Coordinate.x, path[0].Coordinate.y].transform; | |
for (int i = 0; i < path.Count - 1; i++) | |
{ | |
Component component = transform; | |
AStar.PathNode pathNode = path[i + 1]; | |
transform = this._segmentGrid[pathNode.Coordinate.x, pathNode.Coordinate.y].transform; | |
Debug.DrawLine(component.transform.position, transform.transform.position, Color.black); | |
} | |
} | |
// Token: 0x04001ABF RID: 6847 | |
[Header("References")] | |
[SerializeField] | |
private List<GameObject> _rowParents; | |
// Token: 0x04001AC0 RID: 6848 | |
[SerializeField] | |
private CrownMazeDoor _startingDoor; | |
// Token: 0x04001AC1 RID: 6849 | |
[SerializeField] | |
private CrownMazeGridSegment _startingSegment; | |
// Token: 0x04001AC2 RID: 6850 | |
[SerializeField] | |
private CrownMazeGridSegment _crownSegment; | |
// Token: 0x04001AC3 RID: 6851 | |
[SerializeField] | |
private List<CrownMazeGridSegment> _waypointRooms; | |
// Token: 0x04001AC4 RID: 6852 | |
[Header("Generation Settings")] | |
[SerializeField] | |
private AStar.Direction _crownSegmentExitDirection; | |
// Token: 0x04001AC5 RID: 6853 | |
[Range(2f, 8f)] | |
public int minNodeDistance = 2; | |
// Token: 0x04001AC6 RID: 6854 | |
[Range(2f, 8f)] | |
public int maxNodeDistance = 8; | |
// Token: 0x04001AC7 RID: 6855 | |
[Tooltip("Only use if you want to hardcode a specific seed/generation.")] | |
[SerializeField] | |
private bool _usePredeterminedSeed; | |
// Token: 0x04001AC8 RID: 6856 | |
[ShowIf("_usePredeterminedSeed")] | |
public int seed; | |
// Token: 0x04001AC9 RID: 6857 | |
[SerializeField] | |
[Tooltip("If the generation fails the first time, increment the seed by 1 and then try again.")] | |
private bool _incrementIfSeedFails; | |
// Token: 0x04001ACA RID: 6858 | |
[SerializeField] | |
[Tooltip("If the generation fails, use a fallback seed instead.")] | |
private bool _useFallbackSeed; | |
// Token: 0x04001ACB RID: 6859 | |
[ShowIf("_useFallbackSeed")] | |
public int fallbackSeed; | |
// Token: 0x04001ACC RID: 6860 | |
private CrownMazeGridSegment[,] _segmentGrid; | |
// Token: 0x04001ACD RID: 6861 | |
private AStar.PathNode[,] _nodeGrid; | |
// Token: 0x04001ACE RID: 6862 | |
private AStar.PathNode _startNode; | |
// Token: 0x04001ACF RID: 6863 | |
private AStar.PathNode _endNode; | |
// Token: 0x04001AD0 RID: 6864 | |
private List<AStar.PathNode> _startPath; | |
// Token: 0x04001AD1 RID: 6865 | |
private List<AStar.PathNode> _midPath1; | |
// Token: 0x04001AD2 RID: 6866 | |
private List<AStar.PathNode> _midPath2; | |
// Token: 0x04001AD3 RID: 6867 | |
private List<AStar.PathNode> _endPath; | |
// Token: 0x04001AD4 RID: 6868 | |
private AStar.Direction _randomCrownDirection; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment