Skip to content

Instantly share code, notes, and snippets.

@alexjlockwood
Created June 9, 2023 22:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexjlockwood/71b087d9c3c244df768471b8aeef331d to your computer and use it in GitHub Desktop.
Save alexjlockwood/71b087d9c3c244df768471b8aeef331d to your computer and use it in GitHub Desktop.
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