From f14183276d27b2ef9aade0d6fb95511a1cb7e0c0 Mon Sep 17 00:00:00 2001 From: kaczy Date: Wed, 29 Nov 2023 14:12:13 +0100 Subject: [PATCH] Reworked tiles management --- CentrED/Map/LandObject.cs | 5 +- CentrED/Map/MapManager.cs | 328 ++++++++++++++---------------- CentrED/Map/MapObject.cs | 15 ++ CentrED/Map/StaticObject.cs | 1 + CentrED/Tools/DrawTool.cs | 4 +- CentrED/Tools/ElevateTool.cs | 2 +- CentrED/UI/UIManager.cs | 2 +- CentrED/UI/Windows/DebugWindow.cs | 4 +- 8 files changed, 182 insertions(+), 179 deletions(-) diff --git a/CentrED/Map/LandObject.cs b/CentrED/Map/LandObject.cs index aed926b..b27c380 100644 --- a/CentrED/Map/LandObject.cs +++ b/CentrED/Map/LandObject.cs @@ -11,8 +11,9 @@ public class LandObject : TileObject { public LandTile LandTile; - public LandObject(CentrEDClient client, LandTile tile) + public LandObject(LandTile tile) { + ObjectId = GetNextId(); Tile = tile; LandTile = tile; ref var tileData = ref TileDataLoader.Instance.LandData[tile.Id]; @@ -26,7 +27,7 @@ public LandObject(CentrEDClient client, LandTile tile) } else { - cornerZ = GetCornerZ(client, tile); + cornerZ = GetCornerZ(Application.CEDClient, tile); } var posX = (tile.X - 1) * TILE_SIZE; diff --git a/CentrED/Map/MapManager.cs b/CentrED/Map/MapManager.cs index 1e8d2a4..2a898ae 100644 --- a/CentrED/Map/MapManager.cs +++ b/CentrED/Map/MapManager.cs @@ -95,10 +95,10 @@ public MapManager(GraphicsDevice gd) _background = CEDGame.Content.Load("background"); Client = CEDClient; - Client.LandTileReplaced += (tile, newId) => { LandTiles.Find(l => l.LandTile.Equals(tile))?.UpdateId(newId); }; + Client.LandTileReplaced += (tile, newId) => { LandTiles[tile.X, tile.Y].UpdateId(newId); }; Client.LandTileElevated += (tile, newZ) => { - Vector2[] offsets = + Point[] offsets = { new(0, 0), //top new(-1, 0), //right @@ -109,15 +109,10 @@ public MapManager(GraphicsDevice gd) for (var i = 0; i < offsets.Length; i++) { var offset = offsets[i]; - var landObject = LandTiles.Find - (l => l.LandTile.X == (ushort)(tile.X + offset.X) && l.LandTile.Y == (ushort)(tile.Y + offset.Y)); - if (landObject != null) - { - landObject.Vertices[i].Position.Z = newZ * MapObject.TILE_Z_SCALE; - landObject.UpdateId(landObject.LandTile.Id); //Just refresh ID to refresh if it's flat - } + var landObject = LandTiles[tile.X + offset.X, tile.Y + offset.Y]; + landObject.Vertices[i].Position.Z = newZ * MapObject.TILE_Z_SCALE; + landObject.UpdateId(landObject.LandTile.Id); //Just refresh ID to refresh if it's flat } - //We need to update normals too }; Client.BlockLoaded += block => { block.StaticBlock.SortTiles(ref TileDataLoader.Instance.StaticData); }; Client.BlockUnloaded += block => @@ -125,48 +120,51 @@ public MapManager(GraphicsDevice gd) var landTiles = block.LandBlock.Tiles; foreach (var landTile in landTiles) { - LandTiles.RemoveAll(lo => lo.LandTile.Equals(landTile)); + RemoveTile(landTile); } - var staticTiles = block.StaticBlock.AllTiles(); - foreach (var staticTile in staticTiles) + foreach (var staticTile in block.StaticBlock.AllTiles()) { - StaticTiles.RemoveAll(so => so.StaticTile.Equals(staticTile)); + RemoveTile(staticTile); } }; - Client.StaticTileRemoved += tile => { StaticTiles.RemoveAll(so => so.StaticTile.Equals(tile)); }; + Client.StaticTileRemoved += RemoveTile; Client.StaticTileAdded += tile => { tile.Block?.SortTiles(ref TileDataLoader.Instance.StaticData); - StaticTiles.Add(new StaticObject(tile)); + AddTile(tile); }; + //We probably can do these 3 by recalculating instead of remove and add Client.StaticTileMoved += (tile, newX, newY) => { - StaticTiles.RemoveAll(so => so.StaticTile.Equals(tile)); + RemoveTile(tile); var newTile = new StaticTile(tile.Id, newX, newY, tile.Z, tile.Hue, tile.Block); - StaticTiles.Add(new StaticObject(newTile)); + AddTile(newTile); }; Client.StaticTileElevated += (tile, newZ) => { - StaticTiles.RemoveAll(so => so.StaticTile.Equals(tile)); + RemoveTile(tile); var newTile = new StaticTile(tile.Id, tile.X, tile.Y, newZ, tile.Hue, tile.Block); - StaticTiles.Add(new StaticObject(newTile)); + AddTile(newTile); }; Client.StaticTileHued += (tile, newHue) => { - StaticTiles.First(so => so.StaticTile.Equals(tile)).Hue = newHue; + RemoveTile(tile); + var newTile = new StaticTile(tile.Id, tile.X, tile.Y, tile.Z, newHue, tile.Block); + AddTile(newTile); }; Client.Moved += (x, y) => Position = new Point(x,y); Client.Connected += () => { - LandTiles.Clear(); - StaticTiles.Clear(); + LandTiles = new LandObject[Client.Width * 8, Client.Height * 8]; + StaticTiles = new List[Client.Width * 8, Client.Height * 8]; VirtualLayer.Width = (ushort)(Client.Width * 8); VirtualLayer.Height = (ushort)(Client.Height * 8); }; Client.Disconnected += () => { - LandTiles.Clear(); - StaticTiles.Clear(); + LandTiles = new LandObject[0,0]; + StaticTiles = new List[0,0]; + AllTiles.Clear(); }; Camera.Position.X = 0; @@ -303,12 +301,64 @@ private MouseDirection ProcessMouseMovement(ref MouseState mouseState, out float } private readonly float WHEEL_DELTA = 1200f; - - public List LandTiles = new(); + + public List AllTiles = new(); + public LandObject[,] LandTiles; + public int LandTilesCount; public List GhostLandTiles = new(); - public List StaticTiles = new(); + public List[,] StaticTiles; + public int StaticTilesCount; public List GhostStaticTiles = new(); public VirtualLayerObject VirtualLayer = VirtualLayerObject.Instance; + + + public void AddTile(LandTile landTile) + { + var lo = new LandObject(landTile); + LandTiles[landTile.X, landTile.Y] = lo; + AllTiles.Add(lo); + LandTilesCount++; + } + public void RemoveTile(LandTile landTile) + { + var lo = LandTiles[landTile.X, landTile.Y]; + LandTiles[landTile.X, landTile.Y] = null; + AllTiles.Remove(lo); + LandTilesCount--; + } + + public void AddTile(StaticTile staticTile) + { + var so = new StaticObject(staticTile); + var x = staticTile.X; + var y = staticTile.Y; + var list = StaticTiles[x,y]; + if (list == null) + { + list = new(); + StaticTiles[x, y] = list; + } + list.Add(so); + AllTiles.Add(so); + StaticTilesCount++; + } + + public void RemoveTile(StaticTile staticTile) + { + var x = staticTile.X; + var y = staticTile.Y; + var list = StaticTiles[x, y]; + if (list == null || list.Count == 0) + return; + var found = list.Find(so => so.StaticTile.Equals(staticTile)); + if (found != null) + { + list.Remove(found); + AllTiles.Remove(found); + } + StaticTilesCount--; + } + private MouseState _prevMouseState = Mouse.GetState(); public Rectangle ViewRange { get; private set; } @@ -355,7 +405,13 @@ public void Update(GameTime gameTime, bool isActive, bool processMouse, bool pro if (mouse.ScrollWheelValue != _prevMouseState.ScrollWheelValue) { - Camera.ZoomIn((mouse.ScrollWheelValue - _prevMouseState.ScrollWheelValue) / WHEEL_DELTA); + var delta = (mouse.ScrollWheelValue - _prevMouseState.ScrollWheelValue) / WHEEL_DELTA; + Camera.ZoomIn(delta); + //It can get buggy when zooming in due to how BlockCache is working :( + //Just resetting is a safe way in cost of small performance spike and higher network traffic + //TODO: FreeBlocks that are out of view range + if(delta > 0) + Reset(); } if (_gfxDevice.Viewport.Bounds.Contains(new Point(mouse.X, mouse.Y))) @@ -366,7 +422,9 @@ public void Update(GameTime gameTime, bool isActive, bool processMouse, bool pro VirtualLayerTilePos = newTilePos; ActiveTool?.OnVirtualLayerTile(VirtualLayerTilePos); } + Metrics.Start("GetMouseSelection"); var newSelected = GetMouseSelection(mouse.X, mouse.Y); + Metrics.Stop("GetMouseSelection"); if (newSelected != Selected) { ActiveTool?.OnMouseLeave(Selected); @@ -432,22 +490,19 @@ public void Update(GameTime gameTime, bool isActive, bool processMouse, bool pro { Client.ResizeCache(newViewRange.Width * newViewRange.Height / 8); Client.LoadBlocks(requested); - } - - LandTiles.RemoveAll(o => !newViewRange.Contains(o.Tile.X, o.Tile.Y)); - StaticTiles.RemoveAll(o => !newViewRange.Contains(o.Tile.X, o.Tile.Y)); - - for (int x = newViewRange.Left; x < newViewRange.Right; x++) - { - for (int y = newViewRange.Top; y < newViewRange.Bottom; y++) + for (int x = newViewRange.Left; x < newViewRange.Right; x++) { - if (ViewRange.Contains(x, y)) - continue; - LandTiles.Add(new LandObject(Client, Client.GetLandTile(x, y))); - var staticTiles = Client.GetStaticTiles(x, y); - foreach (var staticTile in staticTiles) + for (int y = newViewRange.Top; y < newViewRange.Bottom; y++) { - StaticTiles.Add(new StaticObject(staticTile)); + if (LandTiles[x, y] == null) + { + AddTile(Client.GetLandTile(x, y)); + var staticTiles = Client.GetStaticTiles(x, y); + foreach (var staticTile in staticTiles) + { + AddTile(staticTile); + } + } } } } @@ -460,25 +515,26 @@ public void Update(GameTime gameTime, bool isActive, bool processMouse, bool pro public void Reset() { - LandTiles.Clear(); - StaticTiles.Clear(); + LandTiles = new LandObject[Client.Width * 8, Client.Height * 8]; + StaticTiles = new List[Client.Width * 8, Client.Height * 8]; + AllTiles.Clear(); ViewRange = Rectangle.Empty; Client.ResizeCache(0); + LandTilesCount = 0; + StaticTilesCount = 0; } public TileObject? Selected; - public TileObject? GetMouseSelection(int x, int y) + private TileObject? GetMouseSelection(int x, int y) { Color[] pixels = new Color[1]; _selectionBuffer.GetData(0, new Rectangle(x, y, 1, 1), pixels, 0, 1); var pixel = pixels[0]; var selectedIndex = pixel.R | (pixel.G << 8) | (pixel.B << 16); - if (selectedIndex < 1 || selectedIndex > LandTiles.Count + StaticTiles.Count) + if (selectedIndex < 1) return null; - if (selectedIndex > LandTiles.Count) - return StaticTiles[selectedIndex - 1 - LandTiles.Count]; - return LandTiles[selectedIndex - 1]; + return AllTiles.Find(t => t.ObjectId == selectedIndex); } private void CalculateViewRange(Camera camera, out Rectangle rect) @@ -521,93 +577,6 @@ public Vector3 Unproject(int x, int y, int z) ); } - private bool IsRock(ushort id) - { - switch (id) - { - case 4945: - case 4948: - case 4950: - case 4953: - case 4955: - case 4958: - case 4959: - case 4960: - case 4962: return true; - - default: return id >= 6001 && id <= 6012; - } - } - - private bool IsTree(ushort id) - { - switch (id) - { - case 3274: - case 3275: - case 3276: - case 3277: - case 3280: - case 3283: - case 3286: - case 3288: - case 3290: - case 3293: - case 3296: - case 3299: - case 3302: - case 3394: - case 3395: - case 3417: - case 3440: - case 3461: - case 3476: - case 3480: - case 3484: - case 3488: - case 3492: - case 3496: - case 3230: - case 3240: - case 3242: - case 3243: - case 3273: - case 3320: - case 3323: - case 3326: - case 3329: - case 4792: - case 4793: - case 4794: - case 4795: - case 12596: - case 12593: - case 3221: - case 3222: - case 12602: - case 12599: - case 3238: - case 3225: - case 3229: - case 12881: - case 3228: - case 3227: - case 39290: - case 39280: - case 39219: - case 39215: - case 39223: - case 39288: - case 39217: - case 39225: - case 39284: - case 46822: - case 14492: return true; - } - - return false; - } - private bool CanDrawStatic(ushort id) { if (id >= TileDataLoader.Instance.StaticData.Length) @@ -739,37 +708,42 @@ private void DrawSelectionBuffer() BlendState.AlphaBlend, null ); - //0 is no tile in selection buffer - var i = 1; - if (ShowLand) - { - foreach (var tile in LandTiles) - { - var color = new Color(i & 0xFF, (i >> 8) & 0xFF, (i >> 16) & 0xFF); - DrawLand(tile, color.ToVector3()); - i++; - } - } - if (ShowStatics) + for (var x = ViewRange.Left; x < ViewRange.Right; x++) { - foreach (var tile in StaticTiles) + for (var y = ViewRange.Top; y < ViewRange.Bottom; y++) { - var color = new Color(i & 0xFF, (i >> 8) & 0xFF, (i >> 16) & 0xFF); - DrawStatic(tile, color.ToVector3()); - i++; + var landTile = LandTiles[x, y]; + if (landTile != null && landTile.Visible) + { + var i = landTile.ObjectId; + var color = new Color(i & 0xFF, (i >> 8) & 0xFF, (i >> 16) & 0xFF); + DrawLand(landTile, color.ToVector3()); + } + + var tiles = StaticTiles[x, y]; + if(tiles == null) continue; + foreach (var tile in tiles) + { + if (tile.Visible) + { + var i = tile.ObjectId; + var color = new Color(i & 0xFF, (i >> 8) & 0xFF, (i >> 16) & 0xFF); + DrawStatic(tile, color.ToVector3()); + } + } } } _mapRenderer.End(); } - private void DrawStatics() + private void DrawLand() { - if (!ShowStatics) + if (!ShowLand) { return; } _mapEffect.WorldViewProj = Camera.WorldViewProj; - _mapEffect.CurrentTechnique = _mapEffect.Techniques["Statics"]; + _mapEffect.CurrentTechnique = _mapEffect.Techniques["Terrain"]; _mapRenderer.Begin ( _mapEffect, @@ -779,26 +753,31 @@ private void DrawStatics() BlendState.AlphaBlend, HuesManager.Instance.Texture ); - foreach (var tile in StaticTiles) + + for (var x = ViewRange.Left; x < ViewRange.Right; x++) { - if (tile.Visible) - DrawStatic(tile); + for (var y = ViewRange.Top; y < ViewRange.Bottom; y++) + { + var tile = LandTiles[x, y]; + if (tile != null && tile.Visible) + DrawLand(tile); + } } - foreach (var tile in GhostStaticTiles) + foreach (var tile in GhostLandTiles) { - DrawStatic(tile); + DrawLand(tile); } _mapRenderer.End(); } - private void DrawLand() + private void DrawStatics() { - if (!ShowLand) + if (!ShowStatics) { return; } _mapEffect.WorldViewProj = Camera.WorldViewProj; - _mapEffect.CurrentTechnique = _mapEffect.Techniques["Terrain"]; + _mapEffect.CurrentTechnique = _mapEffect.Techniques["Statics"]; _mapRenderer.Begin ( _mapEffect, @@ -808,15 +787,22 @@ private void DrawLand() BlendState.AlphaBlend, HuesManager.Instance.Texture ); - - foreach (var tile in LandTiles) + for (var x = ViewRange.Left; x < ViewRange.Right; x++) { - if (tile.Visible) - DrawLand(tile); + for (var y = ViewRange.Top; y < ViewRange.Bottom; y++) + { + var tiles = StaticTiles[x, y]; + if(tiles == null) continue; + foreach (var tile in tiles) + { + if (tile.Visible) + DrawStatic(tile); + } + } } - foreach (var tile in GhostLandTiles) + foreach (var tile in GhostStaticTiles) { - DrawLand(tile); + DrawStatic(tile); } _mapRenderer.End(); } @@ -904,7 +890,7 @@ public void OnWindowsResized(GameWindow window) _gfxDevice.PresentationParameters.BackBufferHeight, false, SurfaceFormat.Color, - DepthFormat.Depth24 + DepthFormat.None ); } } \ No newline at end of file diff --git a/CentrED/Map/MapObject.cs b/CentrED/Map/MapObject.cs index ac6d090..4a317d5 100644 --- a/CentrED/Map/MapObject.cs +++ b/CentrED/Map/MapObject.cs @@ -5,10 +5,25 @@ namespace CentrED.Map; public abstract class MapObject { + private static int NextObjectId = 1; + + public static int GetNextId() + { + var objectId = NextObjectId++; + //This is crap, but should work for now + if (NextObjectId < 0) + { + NextObjectId = 1; + Application.CEDGame.MapManager.Reset(); + } + return objectId; + } + public const float INVERSE_SQRT2 = 0.70711f; public const float TILE_SIZE = 31.11f; public const float TILE_Z_SCALE = 4.0f; + public int ObjectId { get; protected set; } public bool Visible = true; public Texture2D Texture; public MapVertex[] Vertices = new MapVertex[4]; diff --git a/CentrED/Map/StaticObject.cs b/CentrED/Map/StaticObject.cs index a2bcea1..93540db 100644 --- a/CentrED/Map/StaticObject.cs +++ b/CentrED/Map/StaticObject.cs @@ -10,6 +10,7 @@ public class StaticObject : TileObject public StaticObject(StaticTile tile) { + ObjectId = GetNextId(); Tile = tile; StaticTile = tile; diff --git a/CentrED/Tools/DrawTool.cs b/CentrED/Tools/DrawTool.cs index affab24..c4188d6 100644 --- a/CentrED/Tools/DrawTool.cs +++ b/CentrED/Tools/DrawTool.cs @@ -80,7 +80,7 @@ public override void OnVirtualLayerTile(Vector3 tilePos) { CEDGame.MapManager.GhostLandTiles.Clear(); var newTile = new LandTile((ushort)newId, (ushort)tilePos.X , (ushort)tilePos.Y, (sbyte)tilePos.Z); - CEDGame.MapManager.GhostLandTiles.Add(new LandObject(CEDClient, newTile)); + CEDGame.MapManager.GhostLandTiles.Add(new LandObject(newTile)); } else { @@ -116,7 +116,7 @@ public override void OnMouseEnter(TileObject? o) { lo.Visible = false; var newTile = new LandTile((ushort)newId, lo.Tile.X, lo.Tile.Y, lo.Tile.Z); - CEDGame.MapManager.GhostLandTiles.Add(new LandObject(CEDClient, newTile)); + CEDGame.MapManager.GhostLandTiles.Add(new LandObject(newTile)); } } else diff --git a/CentrED/Tools/ElevateTool.cs b/CentrED/Tools/ElevateTool.cs index ef429e4..7eca793 100644 --- a/CentrED/Tools/ElevateTool.cs +++ b/CentrED/Tools/ElevateTool.cs @@ -55,7 +55,7 @@ public override void OnMouseEnter(TileObject? o) var tile = lo.LandTile; lo.Visible = false; var newTile = new LandTile(tile.Id, tile.X, tile.Y, NewZ(tile)); - CEDGame.MapManager.GhostLandTiles.Add(new LandObject(CEDGame.MapManager.Client, newTile)); + CEDGame.MapManager.GhostLandTiles.Add(new LandObject(newTile)); } } diff --git a/CentrED/UI/UIManager.cs b/CentrED/UI/UIManager.cs index 4ebe96c..797a460 100644 --- a/CentrED/UI/UIManager.cs +++ b/CentrED/UI/UIManager.cs @@ -219,7 +219,7 @@ private void DrawContextMenu() if (ImGui.BeginPopup("MainPopup")) { var mousePos = ImGui.GetMousePosOnOpeningCurrentPopup(); - var selected = CEDGame.MapManager.GetMouseSelection((int)mousePos.X, (int)mousePos.Y); + var selected = CEDGame.MapManager.Selected; if (selected != null) { if (ImGui.Button("Grab TileId")) diff --git a/CentrED/UI/Windows/DebugWindow.cs b/CentrED/UI/Windows/DebugWindow.cs index 163d80a..c4be302 100644 --- a/CentrED/UI/Windows/DebugWindow.cs +++ b/CentrED/UI/Windows/DebugWindow.cs @@ -35,8 +35,8 @@ public override void Draw() ( $"Resolution: {uiManager._graphicsDevice.PresentationParameters.BackBufferWidth}x{uiManager._graphicsDevice.PresentationParameters.BackBufferHeight}" ); - ImGui.Text($"Land tiles: {mapManager.LandTiles.Count}"); - ImGui.Text($"Static tiles: {mapManager.StaticTiles.Count}"); + ImGui.Text($"Land tiles: {mapManager.LandTilesCount}"); + ImGui.Text($"Static tiles: {mapManager.StaticTilesCount}"); ImGui.Text($"Camera focus tile {mapManager.Camera.LookAt / mapManager.TILE_SIZE}"); ImGui.Separator();