// using System; using System.Collections.Generic; using System.IO; using System.Threading; using Microsoft.Xna.Framework; // using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; namespace tunnet.World; struct World { private class Tile // TODO: sprite, buildings[] { public int Id { get; } public Point point { get; } public Tile(int id) => Id = id; public static Tile FromId(int id) { return new Tile(id); } } private class Chunk { public const int Width = 32; public const int Height = 32; internal Tile[,] Tiles { get; private set; } public Chunk() { Tiles = new Tile[Width, Height]; } } private static class ChunkStorage { /// /// Saves the given chunk to disk in a compact binary format: /// Width×Height consecutive Int32 tile IDs. /// public static void Save(string filePath, Chunk chunk) { if (chunk == null) throw new System.ArgumentNullException(nameof(chunk)); Directory.CreateDirectory(Path.GetDirectoryName(filePath) ?? "."); using var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write); using var writer = new BinaryWriter(fs); for (int x = 0; x < Chunk.Width; x++) { for (int y = 0; y < Chunk.Height; y++) { // write each tile’s ID writer.Write(chunk.Tiles[x, y]?.Id ?? 0); } } } public static void Save(int chunkX, int chunkY, Chunk chunk) { Save($"{chunkX}_{chunkY}.chunk", chunk); } /// /// Loads a chunk from the binary file format produced by Save(). /// public static Chunk Load(string filePath) { if (!File.Exists(filePath)) throw new FileNotFoundException("Chunk file not found", filePath); //TODO generate chunk instead var chunk = new Chunk(); using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); using var reader = new BinaryReader(fs); for (int x = 0; x < Chunk.Width; x++) for (int y = 0; y < Chunk.Height; y++) { int id = reader.ReadInt32(); chunk.Tiles[x, y] = Tile.FromId(id); } return chunk; } public static Chunk Load(Point location) { var filePath = $"{location.X}_{location.Y}.chunk"; if (File.Exists(filePath)) return Load(filePath); return null; } } public class Map { private readonly Dictionary _loadedChunks = new Dictionary(); private IReadOnlyDictionary Chunks => _loadedChunks; private Mutex _loadWait = new(); private readonly int id; // private readonly int TileSize; // public Texture2D _defaultTile; public Map(int mapId) { id = mapId; // TileSize = 32; } // Load the map by ID public void LoadMap() { //TODO: Load map by ID } // Generate a new map private void GenerateMap() { //TODO: Implement map generation } // Get a chunk (load if not in memory) private Chunk GetChunk(Point location) { // var key = new Point(chunkX, chunkY); if (!_loadedChunks.TryGetValue(location, out Chunk chunk)) { chunk = ChunkStorage.Load(location);// LoadChunkFromDisk(chunkX, chunkY); // Or generate _loadedChunks[location] = chunk; } return chunk; } // Access a specific tile private Tile GetTile(int worldX, int worldY) { int chunkX = worldX / Chunk.Width; int chunkY = worldY / Chunk.Height; int tileX = worldX % Chunk.Width; int tileY = worldY % Chunk.Height; // Handle negative coordinates if (tileX < 0) tileX += Chunk.Width; if (tileY < 0) tileY += Chunk.Height; return GetChunk(new Point(chunkX, chunkY)).Tiles[tileX, tileY]; } // Unload distant chunks (memory management) public void UnloadChunks(Point currentChunk, int keepRadius) { var keysToRemove = new List(); foreach (var key in _loadedChunks.Keys) { if (System.Math.Abs(key.X - currentChunk.X) > keepRadius || System.Math.Abs(key.Y - currentChunk.Y) > keepRadius) { ChunkStorage.Save(key.X, key.Y, _loadedChunks[key]); // Persist if needed keysToRemove.Add(key); } } keysToRemove.ForEach(k => _loadedChunks.Remove(k)); } /*public class Draw(in SpriteBatch spriteBatch) { private SpriteBatch spriteBatch = spriteBatch; }*/ // private ref struct Draw // { // private ref SpriteBatch _spriteBatch; // public Draw(ref SpriteBatch spriteBatch) // { // _spriteBatch = ref spriteBatch; // } // } // private readonly IReadOnlyDictionary _chunks; /*public void Draw() { if (_chunks.Count == 0) { Console.WriteLine("No chunks loaded"); return; } foreach (var kvp in _chunks) { Point chunkCoord = kvp.Key; // var chunk = kvp.Value; for (int cx = 0; cx < Chunk.Width; cx++) { for (int cy = 0; cy < Chunk.Height; cy++) { // world‐space position in pixels Vector2 pos = new Vector2( (chunkCoord.X * Chunk.Width + cx) * TileSize, (chunkCoord.Y * Chunk.Height + cy) * TileSize ); // draw the default tile for now Console.WriteLine("Sprite location: ", pos); _spriteBatch.Draw(_defaultTile, pos, Color.White); } } } }*/ } }