diff --git a/Assets/Warlander/Deedplanner/Data/DataLoader.cs b/Assets/Warlander/Deedplanner/Data/DataLoader.cs index b88d15f2..ed9c042c 100644 --- a/Assets/Warlander/Deedplanner/Data/DataLoader.cs +++ b/Assets/Warlander/Deedplanner/Data/DataLoader.cs @@ -164,6 +164,7 @@ private void LoadGrounds(XmlDocument document) TextureReference tex3d = null; List categories = new List(); bool diagonal = false; + bool caveDoor = false; foreach (XmlElement child in element) { @@ -187,6 +188,7 @@ private void LoadGrounds(XmlDocument document) break; case "category": categories.Add(child.InnerText.Split('/')); + caveDoor = (child.InnerText == "Cave doors") ? true : false; break; case "diagonal": diagonal = true; @@ -199,7 +201,7 @@ private void LoadGrounds(XmlDocument document) Debug.LogWarning("No textures loaded, aborting"); } - GroundData data = new GroundData(name, shortName, categories.ToArray(), tex2d, tex3d, diagonal); + GroundData data = new GroundData(name, shortName, categories.ToArray(), tex2d, tex3d, diagonal, caveDoor); Database.Grounds[shortName] = data; Debug.Log("Ground data " + name + " loaded and ready to use!"); } diff --git a/Assets/Warlander/Deedplanner/Data/Grounds/DoorOrientation.cs b/Assets/Warlander/Deedplanner/Data/Grounds/DoorOrientation.cs new file mode 100644 index 00000000..6245fec9 --- /dev/null +++ b/Assets/Warlander/Deedplanner/Data/Grounds/DoorOrientation.cs @@ -0,0 +1,7 @@ +namespace Warlander.Deedplanner.Data.Grounds +{ + public enum DoorOrientation + { + N, E, S, W + } +} diff --git a/Assets/Warlander/Deedplanner/Data/Grounds/DoorOrientation.cs.meta b/Assets/Warlander/Deedplanner/Data/Grounds/DoorOrientation.cs.meta new file mode 100644 index 00000000..cdef26d6 --- /dev/null +++ b/Assets/Warlander/Deedplanner/Data/Grounds/DoorOrientation.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2e29b5fefd3d456c9267268085d70616 +timeCreated: 1769309513 \ No newline at end of file diff --git a/Assets/Warlander/Deedplanner/Data/Grounds/Ground.cs b/Assets/Warlander/Deedplanner/Data/Grounds/Ground.cs index 36e4f833..9a8381e8 100644 --- a/Assets/Warlander/Deedplanner/Data/Grounds/Ground.cs +++ b/Assets/Warlander/Deedplanner/Data/Grounds/Ground.cs @@ -20,7 +20,7 @@ public RoadDirection RoadDirection { get => roadDirection; set => Tile.Map.CommandManager.AddToActionAndExecute(new RoadDirectionChangeCommand(this, roadDirection, value)); } - + public Ground(Tile tile, GroundData data) { Tile = tile; diff --git a/Assets/Warlander/Deedplanner/Data/Grounds/GroundData.cs b/Assets/Warlander/Deedplanner/Data/Grounds/GroundData.cs index 7962eeb7..2759c3fc 100644 --- a/Assets/Warlander/Deedplanner/Data/Grounds/GroundData.cs +++ b/Assets/Warlander/Deedplanner/Data/Grounds/GroundData.cs @@ -13,8 +13,9 @@ public class GroundData public TextureReference Tex3d { get; } public bool Diagonal { get; } + public bool IsCaveDoor { get; } - public GroundData(string name, string shortName, string[][] categories, TextureReference tex2d, TextureReference tex3d, bool diagonal) + public GroundData(string name, string shortName, string[][] categories, TextureReference tex2d, TextureReference tex3d, bool diagonal, bool isCaveDoor) { Name = name; ShortName = shortName; @@ -22,6 +23,7 @@ public GroundData(string name, string shortName, string[][] categories, TextureR Tex2d = tex2d; Tex3d = tex3d; Diagonal = diagonal; + IsCaveDoor = isCaveDoor; } public override string ToString() diff --git a/Assets/Warlander/Deedplanner/Data/Grounds/GroundMesh.cs b/Assets/Warlander/Deedplanner/Data/Grounds/GroundMesh.cs index ce7f4382..5ed65adb 100644 --- a/Assets/Warlander/Deedplanner/Data/Grounds/GroundMesh.cs +++ b/Assets/Warlander/Deedplanner/Data/Grounds/GroundMesh.cs @@ -30,10 +30,12 @@ public class GroundMesh : MonoBehaviour public Mesh ColliderMesh { get; private set; } public int Width { get; private set; } public int Height { get; private set; } - + private int[,] slopesArray; private GroundData[,] dataArray; private RoadDirection[,] directionsArray; + private DoorOrientation[,] doorOrientationsArray; + private Map map; private Vector3[] renderVertices; private Vector2[] uv2; @@ -42,8 +44,9 @@ public class GroundMesh : MonoBehaviour private bool needsVerticesUpdate = false; private bool needsUvUpdate = false; - public void Initialize(int width, int height, OverlayMesh newOverlayMesh) + public void Initialize(Map map, int width, int height, OverlayMesh newOverlayMesh) { + this.map = map; gameObject.layer = LayerMasks.GroundLayer; if (groundTexturesArray == null) { @@ -82,6 +85,7 @@ public void Initialize(int width, int height, OverlayMesh newOverlayMesh) slopesArray = new int[Width + 1, Height + 1]; dataArray = new GroundData[Width, Height]; directionsArray = new RoadDirection[Width, Height]; + doorOrientationsArray = new DoorOrientation[Width, Height]; RenderMesh = new Mesh(); RenderMesh.name = "ground render mesh"; @@ -376,6 +380,49 @@ public int GetSlope(int x, int y) { return this[x, y]; } + + private void ApplyUvRotation(int x, int y, DoorOrientation doorOrientation) + { + int vertexIndex = (x * Height + y) * VerticesPerRenderTile; + Vector2[] meshUvs = RenderMesh.uv; + + // Corner vectors (DoorDirection.N) + Vector2 v00 = new Vector2(0, 0); + Vector2 v10 = new Vector2(1, 0); + Vector2 v01 = new Vector2(0, 1); + Vector2 v11 = new Vector2(1, 1); + Vector2 vCenter = new Vector2(0.5f, 0.5f); + + // Rotating vectors based on DoorDirection + + (v00, v10, v01, v11) = (doorOrientation) switch + { + DoorOrientation.E => (v10, v11, v00, v01), + DoorOrientation.S => (v11, v01, v10, v00), + DoorOrientation.W => (v01, v00, v11, v10), + _ => (v00, v10, v01, v11), + }; + + // Apply vectors + meshUvs[vertexIndex] = v00; + meshUvs[vertexIndex + 1] = v01; + meshUvs[vertexIndex + 2] = vCenter; + + meshUvs[vertexIndex + 3] = v01; + meshUvs[vertexIndex + 4] = v11; + meshUvs[vertexIndex + 5] = vCenter; + + meshUvs[vertexIndex + 6] = v11; + meshUvs[vertexIndex + 7] = v10; + meshUvs[vertexIndex + 8] = vCenter; + + meshUvs[vertexIndex + 9] = v10; + meshUvs[vertexIndex + 10] = v00; + meshUvs[vertexIndex + 11] = vCenter; + + RenderMesh.uv = meshUvs; + } + public void SetSlope(int x, int y, int slope) { @@ -549,14 +596,35 @@ public void SetGroundData(int x, int y, GroundData data, RoadDirection direction return; } - if (dataArray[x, y] == data && directionsArray[x, y] == direction) + DoorOrientation doorOrientation = DoorOrientation.N; + + if (data.IsCaveDoor) + { + Tile currentTile = map?[x, y]; + if (currentTile != null) + { + doorOrientation = currentTile.CalculateDoorOrientation(); + } + } + + bool wasCaveDoor = dataArray[x, y] != null && dataArray[x, y].IsCaveDoor; + bool isCaveDoor = data.IsCaveDoor; + bool orientationChanged = doorOrientationsArray[x, y] != doorOrientation;; + + if (dataArray[x, y] == data && directionsArray[x, y] == direction && doorOrientationsArray[x, y] == doorOrientation) { return; } dataArray[x, y] = data; directionsArray[x, y] = direction; + doorOrientationsArray[x, y] = doorOrientation; + if ((isCaveDoor && orientationChanged) || (wasCaveDoor && !isCaveDoor)) + { + ApplyUvRotation(x, y, doorOrientation); + } + UpdateUV2(x, y, true); UpdateUV2(x - 1, y, false); UpdateUV2(x + 1, y, false); @@ -587,16 +655,33 @@ private void UpdateUV2(int x, int y, bool primaryChangedTile) int vertexIndex = index * VerticesPerRenderTile; RoadDirection roadDirection = directionsArray[x, y]; + DoorOrientation doorOrientation = doorOrientationsArray[x, y]; Vector2Int selfCoords = new Vector2Int(x, y); + + var (wOffset, nOffset, eOffset, sOffset) = (data.IsCaveDoor ? doorOrientation : DoorOrientation.N) switch + { + DoorOrientation.E => (9, 0, 3, 6), + DoorOrientation.S => (6, 9, 0, 3), + DoorOrientation.W => (3, 6, 9, 0), + _ => (0, 3, 6, 9), + }; + int westSlot = vertexIndex + wOffset; + int northSlot = vertexIndex + nOffset; + int eastSlot = vertexIndex + eOffset; + int southSlot = vertexIndex + sOffset; + bool forceSelfDataWest = roadDirection.IsCenter() || roadDirection.IsWest(); - UpdateUV2Triangle(selfCoords, new Vector2Int(x - 1, y), vertexIndex, primaryChangedTile, forceSelfDataWest); + UpdateUV2Triangle(selfCoords, new Vector2Int(x - 1, y), westSlot, primaryChangedTile, forceSelfDataWest); + bool forceSelfDataNorth = roadDirection.IsCenter() || roadDirection.IsNorth(); - UpdateUV2Triangle(selfCoords, new Vector2Int(x, y + 1), vertexIndex + 3, primaryChangedTile, forceSelfDataNorth); + UpdateUV2Triangle(selfCoords, new Vector2Int(x, y + 1), northSlot, primaryChangedTile, forceSelfDataNorth); + bool forceSelfDataEast = roadDirection.IsCenter() || roadDirection.IsEast(); - UpdateUV2Triangle(selfCoords, new Vector2Int(x + 1, y), vertexIndex + 6, primaryChangedTile, forceSelfDataEast); + UpdateUV2Triangle(selfCoords, new Vector2Int(x + 1, y), eastSlot, primaryChangedTile, forceSelfDataEast); + bool forceSelfDataSouth = roadDirection.IsCenter() || roadDirection.IsSouth(); - UpdateUV2Triangle(selfCoords, new Vector2Int(x, y - 1), vertexIndex + 9, primaryChangedTile, forceSelfDataSouth); + UpdateUV2Triangle(selfCoords, new Vector2Int(x, y - 1), southSlot, primaryChangedTile, forceSelfDataSouth); } private void UpdateUV2Triangle(Vector2Int selfCoords, Vector2Int diagonalCoords, int uvIndex, bool primaryChangedTile, bool forceSelfData) diff --git a/Assets/Warlander/Deedplanner/Data/Map.cs b/Assets/Warlander/Deedplanner/Data/Map.cs index dbbbe839..57b30f2b 100644 --- a/Assets/Warlander/Deedplanner/Data/Map.cs +++ b/Assets/Warlander/Deedplanner/Data/Map.cs @@ -302,7 +302,7 @@ private void PreInitialize(int width, int height) GameObject groundObject = new GameObject("Ground Mesh", typeof(GroundMesh)); Ground = groundObject.GetComponent(); - Ground.Initialize(width, height, surfaceOverlayMesh); + Ground.Initialize(this, width, height, surfaceOverlayMesh); surfaceOverlayMesh.Initialize(Ground.ColliderMesh); AddEntityToMap(groundObject, 0); diff --git a/Assets/Warlander/Deedplanner/Data/Tile.cs b/Assets/Warlander/Deedplanner/Data/Tile.cs index 88306c17..3b4e980c 100644 --- a/Assets/Warlander/Deedplanner/Data/Tile.cs +++ b/Assets/Warlander/Deedplanner/Data/Tile.cs @@ -92,7 +92,45 @@ public Tile(Map map, int x, int y, IOutlineCoordinator outlineCoordinator) // Map.AddEntityToMap(caveObject, -1); // Cave.Initialize(this, Database.DefaultCaveData); } + + public DoorOrientation CalculateDoorOrientation() + { + if (X <= 0 || X + 1 >= Map.Width || Y <= 0 || Y + 1 >= Map.Height) return DoorOrientation.N; + + Tile nwTile = this.Map[X, Y + 1]; + Tile neTile = this.Map[X + 1, Y + 1]; + Tile seTile = this.Map[X + 1, Y]; + + if (nwTile == null || neTile == null || seTile == null) return DoorOrientation.N; + + int sw = SurfaceHeight; + int nw = this.Map[X, Y + 1].SurfaceHeight; + int ne = this.Map[X + 1, Y + 1].SurfaceHeight; + int se = this.Map[X + 1, Y].SurfaceHeight; + + float northAvg = (nw + ne) / 2f; + float eastAvg = (ne + se) / 2f; + float southAvg = (se + sw) / 2f; + float westAvg = (sw + nw) / 2f; + + float max = Mathf.Max(northAvg, eastAvg, southAvg, westAvg); + + if (max == northAvg) return DoorOrientation.N; + if (max == eastAvg) return DoorOrientation.E; + if (max == southAvg) return DoorOrientation.S; + if (max == westAvg) return DoorOrientation.W; + + return DoorOrientation.N; + } + public void RefreshDoorOrientation() + { + if (Ground.Data.IsCaveDoor) + { + Map.Ground.SetGroundData(X, Y, Ground.Data, Ground.RoadDirection); + } + } + public void PasteTile(Tile otherTile) { SurfaceHeight = otherTile.SurfaceHeight; @@ -1089,10 +1127,20 @@ public void Undo() private void Refresh() { tile.Map.Ground.SetSlope(tile.X, tile.Y, tile.surfaceHeight); + + Tile t10 = tile.Map.GetRelativeTile(tile, -1, 0); + Tile t01 = tile.Map.GetRelativeTile(tile, 0, -1); + Tile t11 = tile.Map.GetRelativeTile(tile, -1, -1); + tile.RefreshSurfaceEntities(); - tile.Map.GetRelativeTile(tile, -1, 0)?.RefreshSurfaceEntities(); - tile.Map.GetRelativeTile(tile, 0, -1)?.RefreshSurfaceEntities(); - tile.Map.GetRelativeTile(tile, -1, -1)?.RefreshSurfaceEntities(); + t10?.RefreshSurfaceEntities(); + t01?.RefreshSurfaceEntities(); + t11?.RefreshSurfaceEntities(); + + tile.RefreshDoorOrientation(); + t10?.RefreshDoorOrientation(); + t01?.RefreshDoorOrientation(); + t11?.RefreshDoorOrientation(); tile.Map.RecalculateSurfaceHeight(tile.X, tile.Y); }