tunnet_broken-repo/World/World.cs
2025-06-22 13:48:35 +03:00

210 lines
6.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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
{
/// <summary>
/// Saves the given chunk to disk in a compact binary format:
/// Width×Height consecutive Int32 tile IDs.
/// </summary>
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 tiles ID
writer.Write(chunk.Tiles[x, y]?.Id ?? 0);
}
}
}
public static void Save(int chunkX, int chunkY, Chunk chunk)
{
Save($"{chunkX}_{chunkY}.chunk", chunk);
}
/// <summary>
/// Loads a chunk from the binary file format produced by Save().
/// </summary>
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<Point, Chunk> _loadedChunks = new Dictionary<Point, Chunk>();
private IReadOnlyDictionary<Point, Chunk> 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<Point>();
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<Point, Chunk> _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++)
{
// worldspace 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);
}
}
}
}*/
}
}