Ill just drop my entire Grid rule code here for good measure:
using Pathfinding;
using Pathfinding.Jobs;
using Unity.Collections;
using Unity.Jobs;
using UnityEngine;
using UnityEngine.Tilemaps;
using Entities.Players;
using Tombstone;
using Pathfinding.Graphs.Grid.Rules;
using static Pathfinding.Graphs.Grid.GridIterationUtilities;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Mapping
{
public class DirectionalBlockGridRule : GridGraphRule
{
[System.Flags]
public enum Dir
{
None = 0,
Down = 1,
Right = 2,
DownRight = 3,
Up = 4,
DownUp = 5,
UpRight = 6,
Left = 8,
DownLeft = 9,
RightLeft = 10,
UpLeft = 12,
}
struct RemoveConnJob : IJob, IConnectionFilter
{
static Vector2Int NW = new(-1, 1);
static Vector2Int NE = new(1, 1);
static Vector2Int SW = new(-1, -1);
static Vector2Int SE = new(1, -1);
public IntBounds bounds;
public NativeArray<ulong> nodeConnections;
[WriteOnly] public NativeArray<bool> nodeWalkable;
[ReadOnly] public NativeArray<Vector3> nodePositions;
public bool layeredDataLayout;
[ReadOnly] public NativeArray<Dir> Dirs;
public void Execute()
{
FilterNodeConnections(bounds, nodeConnections, layeredDataLayout, ref this);
}
public bool IsValidConnection(int dataIndex, int dataX, int dataLayer, int dataZ,
int direction, int neighbourDataIndex)
{
// no directonal blocks, exit early
if (Dirs[dataIndex] == Dir.None) return true;
int? neighborIndex = GetNeighbourDataIndex(bounds, nodeConnections, layeredDataLayout,
dataX, dataLayer, dataZ, direction);
// Get our position and the adjacent node's position
Vector3 position = nodePositions[dataIndex];
Vector3 neighbourPosition = nodePositions[neighborIndex.Value];
Dir dir = Dirs[dataIndex];
// rounding float issue, need to floor them first before subtract
Vector2Int posDiffToNeighbor = Vector2Int.FloorToInt(neighbourPosition)
- Vector2Int.FloorToInt(position);
if (dir.HasFlag(Dir.Up) && posDiffToNeighbor == Vector2Int.up)
{
int a = 0;
}
if (dir.HasFlag(Dir.Up)
&& (posDiffToNeighbor == Vector2Int.up || posDiffToNeighbor == NW || posDiffToNeighbor == NE))
return false;
if (dir.HasFlag(Dir.Down)
&& (posDiffToNeighbor == Vector2Int.down || posDiffToNeighbor == SW || posDiffToNeighbor == SE))
return false;
if (dir.HasFlag(Dir.Left)
&& (posDiffToNeighbor == Vector2Int.left || posDiffToNeighbor == NW || posDiffToNeighbor == SW))
return false;
if (dir.HasFlag(Dir.Right)
&& (posDiffToNeighbor == Vector2Int.right || posDiffToNeighbor == NE || posDiffToNeighbor == SE))
return false;
// diagonal
if (dir.HasFlag(Dir.DownLeft) && posDiffToNeighbor == SW) return false;
if (dir.HasFlag(Dir.UpRight) && posDiffToNeighbor == NE) return false;
if (dir.HasFlag(Dir.UpLeft) && posDiffToNeighbor == NW) return false;
if (dir.HasFlag(Dir.DownRight) && posDiffToNeighbor == SE) return false;
return true;
}
}
public Tilemap[] FunctionalTilemaps;
void GetTilemaps()
{
TilemapManager tmMan;
if (Application.isPlaying)
{
if (Player.LocalPlayer == null)
{
Debug.LogWarning("Local player not loaded yet. This is probably fine?");
return;
}
var scene = Player.LocalPlayer.gameObject.scene;
if (!FishNetUtils.IsValidGameScene(scene.name)) return;
Debug.Log("TilemapGridRule, before conns, LocalPlayer scene: " + scene.name);
if (!TilemapManager.Instances.TryGetValue(scene, out tmMan))
{
Debug.LogWarning("No tilemap manager instance for scene: " + scene.name);
return;
}
}
else
{
tmMan = Object.FindAnyObjectByType<TilemapManager>();
}
FunctionalTilemaps = tmMan.FunctionMaps;
}
public override void Register(GridGraphRules rules)
{
base.Register(rules);
rules.AddMainThreadPass(Pass.PostProcess, context =>
{
GetTilemaps();
if (FunctionalTilemaps == null || FunctionalTilemaps.Length == 0) return;
NativeArray<Dir> dirs = new(context.data.nodePositions.Length, Allocator.TempJob);
for (int i = 0; i < context.data.nodePositions.Length; i++)
{
Dir dir = 0;
Vector2Int tilePos = Vector2Int.FloorToInt(context.data.nodePositions[i]);
// using tilemaps here is fine since this isnt actually on a diff thread, just the job is
foreach (Tilemap fnMap in FunctionalTilemaps)
{
if (fnMap == null) continue;
TileBase tile = fnMap.GetTile((Vector3Int)tilePos);
if (tile == null) continue;
string lowerTileName = tile.name.ToLower();
if (lowerTileName.Contains("up") && tilePos.y == 37)
{
int a = 0;
}
dir |= lowerTileName.Contains("down") ? Dir.Down
: lowerTileName.Contains("right") ? Dir.Right
: lowerTileName.Contains("up") ? Dir.Up
: lowerTileName.Contains("left") ? Dir.Left
: lowerTileName.Contains("nw") ? Dir.UpLeft
: lowerTileName.Contains("ne") ? Dir.UpRight
: lowerTileName.Contains("se") ? Dir.DownRight
: lowerTileName.Contains("sw") ? Dir.DownLeft
: Dir.None;
}
dirs[i] = dir;
}
RemoveConnJob job = new RemoveConnJob
{
bounds = context.data.bounds,
nodeConnections = context.data.nodeConnections,
nodeWalkable = context.data.nodeWalkable,
nodePositions = context.data.nodePositions,
layeredDataLayout = context.data.layeredDataLayout,
Dirs = dirs,
};
var handle = job.Schedule(context.tracker);
dirs.Dispose(handle);
});
rules.AddMainThreadPass(Pass.AfterConnections, context =>
{
GetTilemaps();
if (FunctionalTilemaps == null || FunctionalTilemaps.Length == 0) return;
for (int i = 0; i < context.data.nodePositions.Length; i++)
{
Vector2Int tilePos = Vector2Int.FloorToInt(context.data.nodePositions[i]);
foreach (var fnMap in FunctionalTilemaps)
{
if (fnMap == null) continue;
TileBase tile = fnMap.GetTile((Vector3Int)tilePos);
if (tile == null) continue;
if (tile.name.ToLower() == "block")
{
context.data.nodeWalkable[i] = false;
break;
}
}
}
});
}
}
#if UNITY_EDITOR
[CustomGridGraphRuleEditor(typeof(DirectionalBlockGridRule), "Directional Block Grid Rule")]
public class DirectionalBlockGridRuleEditor : IGridGraphRuleEditor
{
public void OnInspectorGUI(GridGraph graph, GridGraphRule rule)
{
DirectionalBlockGridRule target = rule as DirectionalBlockGridRule;
if (target.FunctionalTilemaps != null && target.FunctionalTilemaps.Length > 0)
for (int i = 0; i < target.FunctionalTilemaps.Length; i++)
target.FunctionalTilemaps[i] = (Tilemap)EditorGUILayout.ObjectField("Fn Tilemap " + i, target.FunctionalTilemaps[i], typeof(Tilemap), true);
}
public void OnSceneGUI(GridGraph graph, GridGraphRule rule)
{
}
}
#endif
}