first commit
This commit is contained in:
commit
f1b3868d2c
6
.gitignore
vendored
Normal file
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
# Ignore Build/Benchmarks.
|
||||
/src/AdvChkSys.Benchmarks
|
||||
/docfx_project
|
||||
/src/AdvChkSys/bin
|
||||
/src/AdvChkSys/obj
|
||||
src/bindings/python/__pycache__/
|
||||
126
README.md
Normal file
126
README.md
Normal file
@ -0,0 +1,126 @@
|
||||
# AdvChkSys
|
||||
|
||||
**AdvChkSys** is a high-performance, extensible chunked world management library for .NET, designed for games, simulations, and voxel engines. It provides efficient memory management, chunk loading/unloading, resource tracking, event hooks, serialization, and optional constraints for 2D and 3D chunk-based worlds.
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
- **2D and 3D Chunk Management**
|
||||
Efficient, thread-safe managers for 2D and 3D chunks with support for custom data types.
|
||||
|
||||
- **Memory Efficiency**
|
||||
LRU caching, array pooling, and all-air chunk singletons minimize memory usage and maximize performance.
|
||||
|
||||
- **Resource Tracking**
|
||||
Built-in resource manager tracks allocated chunks and supports diagnostics and pooling.
|
||||
|
||||
- **Event System**
|
||||
Thread-safe events for chunk lifecycle: loading, unloading, saving, and more.
|
||||
|
||||
- **World Constraints**
|
||||
Optional constraints for world size and loaded chunk limits.
|
||||
|
||||
- **Serialization**
|
||||
Fast binary serialization/deserialization for chunk data.
|
||||
|
||||
- **Async Utilities**
|
||||
Helpers for running chunk tasks asynchronously.
|
||||
|
||||
- **Python/.NET Interop**
|
||||
Python bindings for scripting and integration.
|
||||
|
||||
---
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Requirements
|
||||
|
||||
- .NET Standard 2.1 or later
|
||||
|
||||
### Building
|
||||
|
||||
```bash
|
||||
dotnet build src/AdvChkSys/AdvChkSys.csproj
|
||||
```
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```csharp
|
||||
using AdvChkSys;
|
||||
using AdvChkSys.Manager;
|
||||
|
||||
// Create a 2D chunk manager
|
||||
var manager2D = AdvChkSys.AdvChkSys.Create2DManager();
|
||||
|
||||
// Create or load a chunk
|
||||
var chunk = manager2D.LoadOrCreateChunk(0, 0, 32, 32);
|
||||
|
||||
// Set a cell value
|
||||
chunk[0, 0] = 42;
|
||||
|
||||
// Unload a chunk
|
||||
manager2D.UnloadChunk(0, 0);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Python Bindings
|
||||
|
||||
Python bindings are available in `src/bindings/python/`.
|
||||
See [`src/bindings/python/README.md`](src/bindings/python/README.md) for usage.
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
advchksys/
|
||||
src/
|
||||
AdvChkSys/
|
||||
Chunk/
|
||||
Manager/
|
||||
Constraints/
|
||||
Events/
|
||||
Interfaces/
|
||||
Resources/
|
||||
Serialization/
|
||||
Threading/
|
||||
Util/
|
||||
AdvChkSys.csproj
|
||||
bindings/
|
||||
python/
|
||||
godot/
|
||||
tests/
|
||||
AdvChkSys.Tests/
|
||||
README.md
|
||||
LICENSE
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Documentation
|
||||
|
||||
- API documentation can be generated with [DocFX](https://dotnet.github.io/docfx/).
|
||||
- XML documentation is included in the build.
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License. See [LICENSE](LICENSE) for details.
|
||||
|
||||
---
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
- Inspired by voxel engines and chunked world systems such as Minecraft.
|
||||
- Uses [DocFX](https://dotnet.github.io/docfx/) for documentation generation.
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
Pull requests and issues are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) if available, or open an issue to discuss your ideas.
|
||||
|
||||
---
|
||||
79
src/AdvChkSys/AdvChkSys.cs
Normal file
79
src/AdvChkSys/AdvChkSys.cs
Normal file
@ -0,0 +1,79 @@
|
||||
#nullable enable
|
||||
using AdvChkSys.Constraints;
|
||||
using AdvChkSys.Manager;
|
||||
using AdvChkSys.Chunk;
|
||||
using AdvChkSys.Resources;
|
||||
|
||||
namespace AdvChkSys
|
||||
{
|
||||
/// <summary>
|
||||
/// Entry point and static facade for the AdvChkSys library.
|
||||
/// Provides version info, helpers for creating managers and constraints, and a basic self-test.
|
||||
/// </summary>
|
||||
public static class AdvChkSys
|
||||
{
|
||||
/// <summary>
|
||||
/// The current version of the AdvChkSys library.
|
||||
/// </summary>
|
||||
public static string Version => "0.1.0";
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new WorldConstraints object.
|
||||
/// </summary>
|
||||
public static WorldConstraints CreateDefaultConstraints() => new WorldConstraints();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new 2D chunk manager with optional constraints.
|
||||
/// </summary>
|
||||
public static ChunkManager2D<byte> Create2DManager(WorldConstraints? constraints = null) =>
|
||||
new ChunkManager2D<byte>(constraints);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new 3D chunk manager with optional constraints.
|
||||
/// </summary>
|
||||
public static ChunkManager3D<byte> Create3DManager(WorldConstraints? constraints = null) =>
|
||||
new ChunkManager3D<byte>(constraints);
|
||||
|
||||
/// <summary>
|
||||
/// Performs a basic self-test of the AdvChkSys core functionality.
|
||||
/// Returns true if all core systems are operational.
|
||||
/// </summary>
|
||||
public static bool SelfTest()
|
||||
{
|
||||
// Create constraints
|
||||
var constraints = new WorldConstraints
|
||||
{
|
||||
MinChunkX = 0,
|
||||
MinChunkY = 0,
|
||||
MaxChunkX = 2,
|
||||
MaxChunkY = 2,
|
||||
MaxLoadedChunks = 4
|
||||
};
|
||||
|
||||
// Create managers
|
||||
var manager2D = new ChunkManager2D<byte>(constraints);
|
||||
var manager3D = new ChunkManager3D<byte>(constraints);
|
||||
|
||||
// Test 2D chunk creation
|
||||
var chunk2D = manager2D.LoadOrCreateChunk(1, 1, 8, 8);
|
||||
chunk2D[0, 0] = 42;
|
||||
|
||||
// Test 3D chunk creation
|
||||
var chunk3D = manager3D.LoadOrCreateChunk(1, 1, 1, 4, 4, 4);
|
||||
chunk3D[0, 0, 0] = 99;
|
||||
|
||||
// Check resource manager tracking
|
||||
bool resourceTracking2D = ChunkResourceManager.AllocatedChunkCount >= 1;
|
||||
bool resourceTracking3D = ChunkResourceManager.AllocatedChunkCount >= 2;
|
||||
|
||||
// Check constraints enforcement
|
||||
bool constraintsWork = constraints.IsWithinBounds(1, 1) && constraints.IsWithinChunkLimit(2);
|
||||
|
||||
// Clean up
|
||||
manager2D.UnloadChunk(1, 1);
|
||||
manager3D.UnloadChunk(1, 1, 1);
|
||||
|
||||
return resourceTracking2D && resourceTracking3D && constraintsWork;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
src/AdvChkSys/AdvChkSys.csproj
Normal file
9
src/AdvChkSys/AdvChkSys.csproj
Normal file
@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>AdvChkSys</RootNamespace>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
134
src/AdvChkSys/Chunk/Chunk2D.cs
Normal file
134
src/AdvChkSys/Chunk/Chunk2D.cs
Normal file
@ -0,0 +1,134 @@
|
||||
#nullable enable
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using AdvChkSys.Interfaces;
|
||||
|
||||
namespace AdvChkSys.Chunk
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a 2D chunk of data in the world.
|
||||
/// Supports all-air singleton for memory efficiency and chunk array pooling.
|
||||
/// </summary>
|
||||
public class Chunk2D<T> : IChunk
|
||||
{
|
||||
// Flyweight: one all-air instance per size
|
||||
private static readonly Dictionary<(int, int), Chunk2D<T>> _allAirChunks = new();
|
||||
|
||||
// Array pool for chunk data arrays
|
||||
private static readonly ConcurrentBag<T[,]> _arrayPool = new();
|
||||
|
||||
/// <summary>
|
||||
/// Returns a singleton all-air chunk for the given size and position.
|
||||
/// </summary>
|
||||
public static Chunk2D<T> AllAir(int x, int y, int width, int height)
|
||||
{
|
||||
var key = (width, height);
|
||||
if (!_allAirChunks.TryGetValue(key, out var chunk))
|
||||
{
|
||||
chunk = new Chunk2D<T>(x, y, width, height, isAllAir: true);
|
||||
_allAirChunks[key] = chunk;
|
||||
}
|
||||
chunk.SetPosition(x, y); // Use explicit method for position update
|
||||
return chunk;
|
||||
}
|
||||
|
||||
private readonly bool _isAllAir;
|
||||
private T[,]? _data;
|
||||
|
||||
// Properties required by IChunk
|
||||
public int X { get; private set; }
|
||||
public int Y { get; private set; }
|
||||
public int Width { get; }
|
||||
public int Height { get; }
|
||||
public Dictionary<string, object> Metadata { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Normal constructor (private for singleton/factory).
|
||||
/// </summary>
|
||||
public Chunk2D(int x, int y, int width, int height, bool isAllAir = false)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Width = width;
|
||||
Height = height;
|
||||
_isAllAir = isAllAir;
|
||||
_data = isAllAir ? null : RentArray(width, height);
|
||||
Metadata = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Explicitly sets the chunk's position. Used internally for all-air singleton.
|
||||
/// </summary>
|
||||
internal void SetPosition(int x, int y)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value at the given local chunk coordinates.
|
||||
/// </summary>
|
||||
public T this[int localX, int localY]
|
||||
{
|
||||
get => _isAllAir ? default! : _data![localX, localY];
|
||||
set
|
||||
{
|
||||
if (_isAllAir)
|
||||
throw new System.InvalidOperationException("Cannot set cell in all-air chunk.");
|
||||
_data![localX, localY] = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fills the chunk with a specified value (no-op for all-air).
|
||||
/// </summary>
|
||||
public void Fill(T value)
|
||||
{
|
||||
if (_isAllAir) return;
|
||||
var data = _data!;
|
||||
for (int x = 0; x < Width; x++)
|
||||
for (int y = 0; y < Height; y++)
|
||||
data[x, y] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this chunk is the all-air singleton.
|
||||
/// </summary>
|
||||
public bool IsAllAir => _isAllAir;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the underlying data array (for pooling).
|
||||
/// </summary>
|
||||
internal T[,]? GetDataArray() => _data;
|
||||
|
||||
/// <summary>
|
||||
/// Releases the data array back to the pool (for chunk manager).
|
||||
/// </summary>
|
||||
internal void ReleaseDataArray()
|
||||
{
|
||||
if (_data != null)
|
||||
{
|
||||
ReturnArray(_data);
|
||||
_data = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rents an array from the pool or creates a new one.
|
||||
/// </summary>
|
||||
private static T[,] RentArray(int width, int height)
|
||||
{
|
||||
if (_arrayPool.TryTake(out var arr) && arr.GetLength(0) == width && arr.GetLength(1) == height)
|
||||
return arr;
|
||||
return new T[width, height];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an array to the pool.
|
||||
/// </summary>
|
||||
internal static void ReturnArray(T[,] arr)
|
||||
{
|
||||
_arrayPool.Add(arr);
|
||||
}
|
||||
}
|
||||
}
|
||||
68
src/AdvChkSys/Chunk/Chunk3D.cs
Normal file
68
src/AdvChkSys/Chunk/Chunk3D.cs
Normal file
@ -0,0 +1,68 @@
|
||||
using System.Collections.Generic;
|
||||
using AdvChkSys.Interfaces;
|
||||
|
||||
namespace AdvChkSys.Chunk
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a 3D chunk of data in the world.
|
||||
/// Perspective-agnostic and supports arbitrary data types and metadata.
|
||||
/// </summary>
|
||||
public class Chunk3D<T> : IChunk
|
||||
{
|
||||
/// <summary>
|
||||
/// The chunk's position in chunk coordinates (not world coordinates).
|
||||
/// </summary>
|
||||
public int X { get; }
|
||||
public int Y { get; }
|
||||
public int Z { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The width, height, and depth of the chunk (in cells/tiles/units).
|
||||
/// </summary>
|
||||
public int Width { get; }
|
||||
public int Height { get; }
|
||||
public int Depth { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The chunk's data array.
|
||||
/// </summary>
|
||||
private readonly T[,,] _data;
|
||||
|
||||
/// <summary>
|
||||
/// Metadata dictionary for arbitrary chunk information (e.g., biome, tags).
|
||||
/// </summary>
|
||||
public Dictionary<string, object> Metadata { get; }
|
||||
|
||||
public Chunk3D(int x, int y, int z, int width, int height, int depth)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
Width = width;
|
||||
Height = height;
|
||||
Depth = depth;
|
||||
_data = new T[width, height, depth];
|
||||
Metadata = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value at the given local chunk coordinates.
|
||||
/// </summary>
|
||||
public T this[int localX, int localY, int localZ]
|
||||
{
|
||||
get => _data[localX, localY, localZ];
|
||||
set => _data[localX, localY, localZ] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fills the chunk with a specified value.
|
||||
/// </summary>
|
||||
public void Fill(T value)
|
||||
{
|
||||
for (int x = 0; x < Width; x++)
|
||||
for (int y = 0; y < Height; y++)
|
||||
for (int z = 0; z < Depth; z++)
|
||||
_data[x, y, z] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
57
src/AdvChkSys/Constraints/WorldConstraints.cs
Normal file
57
src/AdvChkSys/Constraints/WorldConstraints.cs
Normal file
@ -0,0 +1,57 @@
|
||||
using System;
|
||||
|
||||
namespace AdvChkSys.Constraints
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents constraints and limits for the chunk world.
|
||||
/// Can be used to restrict world size, chunk counts, and other resource limits.
|
||||
/// </summary>
|
||||
public class WorldConstraints
|
||||
{
|
||||
/// <summary>
|
||||
/// If set, the minimum allowed chunk X coordinate (inclusive).
|
||||
/// </summary>
|
||||
public int? MinChunkX { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If set, the maximum allowed chunk X coordinate (inclusive).
|
||||
/// </summary>
|
||||
public int? MaxChunkX { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If set, the minimum allowed chunk Y coordinate (inclusive).
|
||||
/// </summary>
|
||||
public int? MinChunkY { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If set, the maximum allowed chunk Y coordinate (inclusive).
|
||||
/// </summary>
|
||||
public int? MaxChunkY { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If set, the maximum number of chunks allowed to be loaded in memory at once.
|
||||
/// </summary>
|
||||
public int? MaxLoadedChunks { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the given chunk coordinates are within the allowed world bounds.
|
||||
/// </summary>
|
||||
public bool IsWithinBounds(int chunkX, int chunkY)
|
||||
{
|
||||
if (MinChunkX.HasValue && chunkX < MinChunkX.Value) return false;
|
||||
if (MaxChunkX.HasValue && chunkX > MaxChunkX.Value) return false;
|
||||
if (MinChunkY.HasValue && chunkY < MinChunkY.Value) return false;
|
||||
if (MaxChunkY.HasValue && chunkY > MaxChunkY.Value) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the current number of loaded chunks is within the allowed limit.
|
||||
/// </summary>
|
||||
public bool IsWithinChunkLimit(int loadedChunkCount)
|
||||
{
|
||||
if (MaxLoadedChunks.HasValue && loadedChunkCount > MaxLoadedChunks.Value) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
126
src/AdvChkSys/Events/ChunkEvents.cs
Normal file
126
src/AdvChkSys/Events/ChunkEvents.cs
Normal file
@ -0,0 +1,126 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace AdvChkSys.Events
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides events for chunk lifecycle operations such as loading, unloading, saving, and more.
|
||||
/// Thread-safe event subscription and invocation.
|
||||
/// </summary>
|
||||
public static class ChunkEvents
|
||||
{
|
||||
// Backing fields for thread-safe event handling
|
||||
private static Action<Interfaces.IChunk>? _chunkLoaded;
|
||||
private static Action<Interfaces.IChunk>? _chunkUnloaded;
|
||||
private static Action<Interfaces.IChunk>? _chunkLoading;
|
||||
private static Action<Interfaces.IChunk>? _chunkUnloading;
|
||||
private static Action<Interfaces.IChunk>? _chunkSaving;
|
||||
private static Action<Interfaces.IChunk>? _chunkSaved;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a chunk has been loaded into memory.
|
||||
/// </summary>
|
||||
public static event Action<Interfaces.IChunk> ChunkLoaded
|
||||
{
|
||||
add => AddHandler(ref _chunkLoaded, value);
|
||||
remove => RemoveHandler(ref _chunkLoaded, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a chunk is about to be loaded into memory.
|
||||
/// </summary>
|
||||
public static event Action<Interfaces.IChunk> ChunkLoading
|
||||
{
|
||||
add => AddHandler(ref _chunkLoading, value);
|
||||
remove => RemoveHandler(ref _chunkLoading, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a chunk is about to be unloaded from memory.
|
||||
/// </summary>
|
||||
public static event Action<Interfaces.IChunk> ChunkUnloading
|
||||
{
|
||||
add => AddHandler(ref _chunkUnloading, value);
|
||||
remove => RemoveHandler(ref _chunkUnloading, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a chunk has been unloaded from memory.
|
||||
/// </summary>
|
||||
public static event Action<Interfaces.IChunk> ChunkUnloaded
|
||||
{
|
||||
add => AddHandler(ref _chunkUnloaded, value);
|
||||
remove => RemoveHandler(ref _chunkUnloaded, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a chunk is about to be saved.
|
||||
/// </summary>
|
||||
public static event Action<Interfaces.IChunk> ChunkSaving
|
||||
{
|
||||
add => AddHandler(ref _chunkSaving, value);
|
||||
remove => RemoveHandler(ref _chunkSaving, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a chunk has been saved.
|
||||
/// </summary>
|
||||
public static event Action<Interfaces.IChunk> ChunkSaved
|
||||
{
|
||||
add => AddHandler(ref _chunkSaved, value);
|
||||
remove => RemoveHandler(ref _chunkSaved, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises the ChunkLoading event.
|
||||
/// </summary>
|
||||
public static void OnChunkLoading(Interfaces.IChunk chunk) => _chunkLoading?.Invoke(chunk);
|
||||
|
||||
/// <summary>
|
||||
/// Raises the ChunkLoaded event.
|
||||
/// </summary>
|
||||
public static void OnChunkLoaded(Interfaces.IChunk chunk) => _chunkLoaded?.Invoke(chunk);
|
||||
|
||||
/// <summary>
|
||||
/// Raises the ChunkUnloading event.
|
||||
/// </summary>
|
||||
public static void OnChunkUnloading(Interfaces.IChunk chunk) => _chunkUnloading?.Invoke(chunk);
|
||||
|
||||
/// <summary>
|
||||
/// Raises the ChunkUnloaded event.
|
||||
/// </summary>
|
||||
public static void OnChunkUnloaded(Interfaces.IChunk chunk) => _chunkUnloaded?.Invoke(chunk);
|
||||
|
||||
/// <summary>
|
||||
/// Raises the ChunkSaving event.
|
||||
/// </summary>
|
||||
public static void OnChunkSaving(Interfaces.IChunk chunk) => _chunkSaving?.Invoke(chunk);
|
||||
|
||||
/// <summary>
|
||||
/// Raises the ChunkSaved event.
|
||||
/// </summary>
|
||||
public static void OnChunkSaved(Interfaces.IChunk chunk) => _chunkSaved?.Invoke(chunk);
|
||||
|
||||
// Thread-safe add/remove for event handlers
|
||||
private static void AddHandler(ref Action<Interfaces.IChunk>? field, Action<Interfaces.IChunk> handler)
|
||||
{
|
||||
Action<Interfaces.IChunk>? prevHandler, newHandler;
|
||||
do
|
||||
{
|
||||
prevHandler = field;
|
||||
newHandler = (Action<Interfaces.IChunk>?)Delegate.Combine(prevHandler, handler);
|
||||
} while (Interlocked.CompareExchange(ref field, newHandler, prevHandler) != prevHandler);
|
||||
}
|
||||
|
||||
private static void RemoveHandler(ref Action<Interfaces.IChunk>? field, Action<Interfaces.IChunk> handler)
|
||||
{
|
||||
Action<Interfaces.IChunk>? prevHandler, newHandler;
|
||||
do
|
||||
{
|
||||
prevHandler = field;
|
||||
newHandler = (Action<Interfaces.IChunk>?)Delegate.Remove(prevHandler, handler);
|
||||
} while (Interlocked.CompareExchange(ref field, newHandler, prevHandler) != prevHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
32
src/AdvChkSys/Interfaces/IChunk.cs
Normal file
32
src/AdvChkSys/Interfaces/IChunk.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AdvChkSys.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a generic chunk in the world.
|
||||
/// Provides basic properties for position, size, and metadata.
|
||||
/// </summary>
|
||||
public interface IChunk
|
||||
{
|
||||
/// <summary>
|
||||
/// The chunk's position in chunk-space coordinates.
|
||||
/// </summary>
|
||||
int X { get; }
|
||||
int Y { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The width of the chunk (in cells/tiles/units).
|
||||
/// </summary>
|
||||
int Width { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The height of the chunk (in cells/tiles/units).
|
||||
/// </summary>
|
||||
int Height { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Metadata dictionary for arbitrary chunk information (e.g., biome, tags).
|
||||
/// </summary>
|
||||
Dictionary<string, object> Metadata { get; }
|
||||
}
|
||||
}
|
||||
38
src/AdvChkSys/Interfaces/IChunkManager.cs
Normal file
38
src/AdvChkSys/Interfaces/IChunkManager.cs
Normal file
@ -0,0 +1,38 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AdvChkSys.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for managing chunks in memory.
|
||||
/// Provides methods for loading, unloading, and accessing chunks.
|
||||
/// </summary>
|
||||
public interface IChunkManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns true if the chunk at (x, y) is loaded.
|
||||
/// </summary>
|
||||
bool IsChunkLoaded(int x, int y);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the chunk at (x, y) if loaded, or null if not.
|
||||
/// </summary>
|
||||
IChunk? GetChunk(int x, int y);
|
||||
|
||||
/// <summary>
|
||||
/// Loads or creates a chunk at (x, y) with the given size.
|
||||
/// Returns the loaded or newly created chunk.
|
||||
/// </summary>
|
||||
IChunk LoadOrCreateChunk(int x, int y, int width, int height);
|
||||
|
||||
/// <summary>
|
||||
/// Unloads (removes) the chunk at (x, y) if loaded.
|
||||
/// </summary>
|
||||
bool UnloadChunk(int x, int y);
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates all loaded chunks.
|
||||
/// </summary>
|
||||
IEnumerable<IChunk> GetAllChunks();
|
||||
}
|
||||
}
|
||||
156
src/AdvChkSys/Manager/ChunkManager2D.cs
Normal file
156
src/AdvChkSys/Manager/ChunkManager2D.cs
Normal file
@ -0,0 +1,156 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using AdvChkSys.Chunk;
|
||||
using AdvChkSys.Events;
|
||||
using AdvChkSys.Interfaces;
|
||||
using AdvChkSys.Resources;
|
||||
using AdvChkSys.Constraints;
|
||||
using AdvChkSys.Util;
|
||||
using System;
|
||||
|
||||
namespace AdvChkSys.Manager
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages 2D chunks in memory. Handles loading, unloading, and access.
|
||||
/// </summary>
|
||||
public class ChunkManager2D<T> : IChunkManager
|
||||
{
|
||||
private readonly LRUCache<(int, int), Chunk2D<T>> _chunks;
|
||||
private readonly WorldConstraints? _constraints;
|
||||
private readonly int _capacity;
|
||||
|
||||
public ChunkManager2D(WorldConstraints? constraints = null, int capacity = 0, int chunkWidth = 32, int chunkHeight = 32)
|
||||
{
|
||||
_constraints = constraints;
|
||||
if (capacity <= 0)
|
||||
{
|
||||
// Use dynamic calculation
|
||||
int bytesPerChunk = chunkWidth * chunkHeight * System.Runtime.InteropServices.Marshal.SizeOf<T>();
|
||||
ulong availableBytes = MemoryHelper.GetAvailableMemoryBytes();
|
||||
_capacity = (int)(availableBytes * 0.8 / (ulong)bytesPerChunk);
|
||||
}
|
||||
else
|
||||
{
|
||||
_capacity = capacity;
|
||||
}
|
||||
_chunks = new LRUCache<(int, int), Chunk2D<T>>(_capacity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the chunk at (x, y) is loaded.
|
||||
/// </summary>
|
||||
public bool IsChunkLoaded(int x, int y) => _chunks.TryGet((x, y), out _);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the chunk at (x, y) if loaded, or null if not.
|
||||
/// </summary>
|
||||
public Chunk2D<T>? GetChunk(int x, int y)
|
||||
{
|
||||
_chunks.TryGet((x, y), out var chunk);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads or creates a chunk at (x, y) with the given size.
|
||||
/// Returns the loaded or newly created chunk.
|
||||
/// </summary>
|
||||
public Chunk2D<T> LoadOrCreateChunk(int x, int y, int width, int height)
|
||||
{
|
||||
if (_constraints != null)
|
||||
{
|
||||
if (!_constraints.IsWithinBounds(x, y))
|
||||
throw new InvalidOperationException("Chunk coordinates out of bounds.");
|
||||
if (!_constraints.IsWithinChunkLimit(_chunks.Count + 1))
|
||||
throw new InvalidOperationException("Chunk limit exceeded.");
|
||||
}
|
||||
|
||||
if (!_chunks.TryGet((x, y), out var chunk))
|
||||
{
|
||||
// If this region is all air, use the singleton
|
||||
if (ShouldBeAllAir(x, y, width, height))
|
||||
chunk = Chunk2D<T>.AllAir(x, y, width, height);
|
||||
else
|
||||
chunk = new Chunk2D<T>(x, y, width, height);
|
||||
|
||||
_chunks.Add((x, y), chunk, OnChunkEvicted);
|
||||
ChunkResourceManager.AllocateChunk(chunk);
|
||||
ChunkEvents.OnChunkLoaded(chunk);
|
||||
}
|
||||
return chunk;
|
||||
}
|
||||
|
||||
private void OnChunkEvicted((int, int) key, Chunk2D<T> chunk)
|
||||
{
|
||||
var arrField = chunk.GetType().GetField("_data", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
T[,]? arr = null;
|
||||
if (arrField != null)
|
||||
{
|
||||
arr = arrField.GetValue(chunk) as T[,];
|
||||
}
|
||||
if (!chunk.IsAllAir && arr != null)
|
||||
{
|
||||
Chunk2D<T>.ReturnArray(arr);
|
||||
}
|
||||
ChunkResourceManager.ReleaseChunk(chunk);
|
||||
ChunkEvents.OnChunkUnloaded(chunk);
|
||||
// Optionally: compress or persist chunk here
|
||||
}
|
||||
|
||||
// Example stub: you can implement your own logic for "all air"
|
||||
private bool ShouldBeAllAir(int x, int y, int width, int height)
|
||||
{
|
||||
// For now, always false. In a real system, check worldgen or disk.
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads or creates a chunk at (x, y) with the given size asynchronously.
|
||||
/// Returns the loaded or newly created chunk.
|
||||
/// </summary>
|
||||
public async Task<Chunk2D<T>> LoadOrCreateChunkAsync(int x, int y, int width, int height)
|
||||
{
|
||||
// Simulate async work (e.g., loading from disk/network)
|
||||
return await Task.Run(() => LoadOrCreateChunk(x, y, width, height));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unloads (removes) the chunk at (x, y) if loaded.
|
||||
/// </summary>
|
||||
public bool UnloadChunk(int x, int y)
|
||||
{
|
||||
if (_chunks.Remove((x, y), out var chunk))
|
||||
{
|
||||
var arr = chunk.GetDataArray();
|
||||
if (!chunk.IsAllAir && arr != null)
|
||||
{
|
||||
Chunk2D<T>.ReturnArray(arr);
|
||||
}
|
||||
ChunkResourceManager.ReleaseChunk(chunk);
|
||||
ChunkEvents.OnChunkUnloaded(chunk);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unloads (removes) the chunk at (x, y) if loaded asynchronously.
|
||||
/// </summary>
|
||||
public async Task<bool> UnloadChunkAsync(int x, int y)
|
||||
{
|
||||
return await Task.Run(() => UnloadChunk(x, y));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates all loaded chunks.
|
||||
/// </summary>
|
||||
public IEnumerable<Chunk2D<T>> GetAllChunks() => _chunks.Values;
|
||||
|
||||
// IChunkManager interface compatibility
|
||||
bool IChunkManager.IsChunkLoaded(int x, int y) => IsChunkLoaded(x, y);
|
||||
IChunk? IChunkManager.GetChunk(int x, int y) => GetChunk(x, y);
|
||||
IChunk IChunkManager.LoadOrCreateChunk(int x, int y, int width, int height) => LoadOrCreateChunk(x, y, width, height);
|
||||
bool IChunkManager.UnloadChunk(int x, int y) => UnloadChunk(x, y);
|
||||
IEnumerable<IChunk> IChunkManager.GetAllChunks() => _chunks.Values;
|
||||
}
|
||||
}
|
||||
102
src/AdvChkSys/Manager/ChunkManager3D.cs
Normal file
102
src/AdvChkSys/Manager/ChunkManager3D.cs
Normal file
@ -0,0 +1,102 @@
|
||||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using AdvChkSys.Chunk;
|
||||
using AdvChkSys.Events;
|
||||
using AdvChkSys.Interfaces;
|
||||
using AdvChkSys.Resources;
|
||||
using AdvChkSys.Constraints;
|
||||
using AdvChkSys.Util;
|
||||
using System;
|
||||
|
||||
namespace AdvChkSys.Manager
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages 3D chunks in memory. Handles loading, unloading, and access.
|
||||
/// </summary>
|
||||
public class ChunkManager3D<T> : IChunkManager
|
||||
{
|
||||
private readonly LRUCache<(int, int, int), Chunk3D<T>> _chunks;
|
||||
private readonly WorldConstraints? _constraints;
|
||||
private readonly int _capacity;
|
||||
|
||||
public ChunkManager3D(WorldConstraints? constraints = null, int capacity = 4096)
|
||||
{
|
||||
_constraints = constraints;
|
||||
_capacity = capacity;
|
||||
_chunks = new LRUCache<(int, int, int), Chunk3D<T>>(_capacity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the chunk at (x, y, z) is loaded.
|
||||
/// </summary>
|
||||
public bool IsChunkLoaded(int x, int y, int z) => _chunks.TryGet((x, y, z), out _);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the chunk at (x, y, z) if loaded, or null if not.
|
||||
/// </summary>
|
||||
public Chunk3D<T>? GetChunk(int x, int y, int z)
|
||||
{
|
||||
_chunks.TryGet((x, y, z), out var chunk);
|
||||
return chunk;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads or creates a chunk at (x, y, z) with the given size.
|
||||
/// Returns the loaded or newly created chunk.
|
||||
/// </summary>
|
||||
public Chunk3D<T> LoadOrCreateChunk(int x, int y, int z, int width, int height, int depth)
|
||||
{
|
||||
if (_constraints != null)
|
||||
{
|
||||
if (!_constraints.IsWithinBounds(x, y))
|
||||
throw new InvalidOperationException("Chunk coordinates out of bounds.");
|
||||
if (!_constraints.IsWithinChunkLimit(_chunks.Count + 1))
|
||||
throw new InvalidOperationException("Chunk limit exceeded.");
|
||||
}
|
||||
|
||||
if (!_chunks.TryGet((x, y, z), out var chunk))
|
||||
{
|
||||
chunk = new Chunk3D<T>(x, y, z, width, height, depth);
|
||||
_chunks.Add((x, y, z), chunk, OnChunkEvicted);
|
||||
ChunkResourceManager.AllocateChunk(chunk);
|
||||
ChunkEvents.OnChunkLoaded(chunk);
|
||||
}
|
||||
return chunk;
|
||||
}
|
||||
|
||||
private void OnChunkEvicted((int, int, int) key, Chunk3D<T> chunk)
|
||||
{
|
||||
ChunkResourceManager.ReleaseChunk(chunk);
|
||||
ChunkEvents.OnChunkUnloaded(chunk);
|
||||
// Optionally: compress or persist chunk here
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unloads (removes) the chunk at (x, y, z) if loaded.
|
||||
/// </summary>
|
||||
public bool UnloadChunk(int x, int y, int z)
|
||||
{
|
||||
if (_chunks.Remove((x, y, z), out var chunk))
|
||||
{
|
||||
ChunkResourceManager.ReleaseChunk(chunk);
|
||||
ChunkEvents.OnChunkUnloaded(chunk);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates all loaded chunks.
|
||||
/// </summary>
|
||||
public IEnumerable<Chunk3D<T>> GetAllChunks() => _chunks.Values;
|
||||
|
||||
// IChunkManager interface compatibility (for 2D interface)
|
||||
bool IChunkManager.IsChunkLoaded(int x, int y) => _chunks.TryGet((x, y, 0), out _);
|
||||
IChunk? IChunkManager.GetChunk(int x, int y) => _chunks.TryGet((x, y, 0), out var chunk) ? chunk : null;
|
||||
IChunk IChunkManager.LoadOrCreateChunk(int x, int y, int width, int height) =>
|
||||
LoadOrCreateChunk(x, y, 0, width, height, 1);
|
||||
bool IChunkManager.UnloadChunk(int x, int y) => UnloadChunk(x, y, 0);
|
||||
IEnumerable<IChunk> IChunkManager.GetAllChunks() => _chunks.Values;
|
||||
}
|
||||
}
|
||||
50
src/AdvChkSys/Resources/ChunkResourceManager.cs
Normal file
50
src/AdvChkSys/Resources/ChunkResourceManager.cs
Normal file
@ -0,0 +1,50 @@
|
||||
#nullable enable
|
||||
using AdvChkSys.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace AdvChkSys.Resources
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages allocation and release of chunk resources in memory.
|
||||
/// Can be extended to track resource usage, pooling, or implement custom memory strategies.
|
||||
/// </summary>
|
||||
public static class ChunkResourceManager
|
||||
{
|
||||
// Example: Track allocated chunks (for diagnostics, pooling, or resource limits)
|
||||
private static readonly ConcurrentDictionary<IChunk, DateTime> _allocatedChunks = new ConcurrentDictionary<IChunk, DateTime>();
|
||||
|
||||
/// <summary>
|
||||
/// Called when a chunk is allocated/loaded into memory.
|
||||
/// Tracks the chunk and can be extended for pooling or resource limits.
|
||||
/// </summary>
|
||||
public static void AllocateChunk(IChunk chunk)
|
||||
{
|
||||
_allocatedChunks[chunk] = DateTime.UtcNow;
|
||||
// Optionally: implement resource limits, pooling, or logging here.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a chunk is released/unloaded from memory.
|
||||
/// Removes the chunk from tracking and can be extended for pooling or cleanup.
|
||||
/// </summary>
|
||||
public static void ReleaseChunk(IChunk chunk)
|
||||
{
|
||||
_allocatedChunks.TryRemove(chunk, out _);
|
||||
// Optionally: implement cleanup, pooling, or logging here.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current number of allocated chunks.
|
||||
/// </summary>
|
||||
public static int AllocatedChunkCount => _allocatedChunks.Count;
|
||||
|
||||
/// <summary>
|
||||
/// Clears all tracked chunks (for diagnostics or shutdown).
|
||||
/// </summary>
|
||||
public static void Clear()
|
||||
{
|
||||
_allocatedChunks.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
170
src/AdvChkSys/Serialization/ChunkSerializer.cs
Normal file
170
src/AdvChkSys/Serialization/ChunkSerializer.cs
Normal file
@ -0,0 +1,170 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using AdvChkSys.Chunk;
|
||||
|
||||
namespace AdvChkSys.Serialization
|
||||
{
|
||||
// <summary>
|
||||
// Provides serialization and deserialization for chunk instances.
|
||||
// Supports Chunk2D<T> and Chunk3D<T> with primitive types (e.g., byte, int, float).
|
||||
// </summary>
|
||||
public static class ChunkSerializer
|
||||
{
|
||||
// -------- 2D --------
|
||||
|
||||
public static byte[] Serialize2D<T>(Chunk2D<T> chunk) where T : struct
|
||||
{
|
||||
using var ms = new MemoryStream();
|
||||
using var writer = new BinaryWriter(ms);
|
||||
|
||||
writer.Write(chunk.X);
|
||||
writer.Write(chunk.Y);
|
||||
writer.Write(chunk.Width);
|
||||
writer.Write(chunk.Height);
|
||||
|
||||
writer.Write(chunk.Metadata.Count);
|
||||
foreach (var kvp in chunk.Metadata)
|
||||
{
|
||||
writer.Write(kvp.Key);
|
||||
writer.Write(kvp.Value?.ToString() ?? "");
|
||||
}
|
||||
|
||||
for (int x = 0; x < chunk.Width; x++)
|
||||
for (int y = 0; y < chunk.Height; y++)
|
||||
WritePrimitive(writer, chunk[x, y]);
|
||||
|
||||
writer.Flush();
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
public static Chunk2D<T> Deserialize2D<T>(byte[] data) where T : struct
|
||||
{
|
||||
using var ms = new MemoryStream(data);
|
||||
using var reader = new BinaryReader(ms);
|
||||
|
||||
int x = reader.ReadInt32();
|
||||
int y = reader.ReadInt32();
|
||||
int width = reader.ReadInt32();
|
||||
int height = reader.ReadInt32();
|
||||
|
||||
var chunk = new Chunk2D<T>(x, y, width, height);
|
||||
|
||||
int metaCount = reader.ReadInt32();
|
||||
for (int i = 0; i < metaCount; i++)
|
||||
{
|
||||
string key = reader.ReadString();
|
||||
string value = reader.ReadString();
|
||||
chunk.Metadata[key] = value;
|
||||
}
|
||||
|
||||
for (int ix = 0; ix < width; ix++)
|
||||
for (int iy = 0; iy < height; iy++)
|
||||
chunk[ix, iy] = ReadPrimitive<T>(reader);
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
// -------- 3D --------
|
||||
|
||||
public static byte[] Serialize3D<T>(Chunk3D<T> chunk) where T : struct
|
||||
{
|
||||
using var ms = new MemoryStream();
|
||||
using var writer = new BinaryWriter(ms);
|
||||
|
||||
writer.Write(chunk.X);
|
||||
writer.Write(chunk.Y);
|
||||
writer.Write(chunk.Z);
|
||||
writer.Write(chunk.Width);
|
||||
writer.Write(chunk.Height);
|
||||
writer.Write(chunk.Depth);
|
||||
|
||||
writer.Write(chunk.Metadata.Count);
|
||||
foreach (var kvp in chunk.Metadata)
|
||||
{
|
||||
writer.Write(kvp.Key);
|
||||
writer.Write(kvp.Value?.ToString() ?? "");
|
||||
}
|
||||
|
||||
for (int x = 0; x < chunk.Width; x++)
|
||||
for (int y = 0; y < chunk.Height; y++)
|
||||
for (int z = 0; z < chunk.Depth; z++)
|
||||
WritePrimitive(writer, chunk[x, y, z]);
|
||||
|
||||
writer.Flush();
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
public static Chunk3D<T> Deserialize3D<T>(byte[] data) where T : struct
|
||||
{
|
||||
using var ms = new MemoryStream(data);
|
||||
using var reader = new BinaryReader(ms);
|
||||
|
||||
int x = reader.ReadInt32();
|
||||
int y = reader.ReadInt32();
|
||||
int z = reader.ReadInt32();
|
||||
int width = reader.ReadInt32();
|
||||
int height = reader.ReadInt32();
|
||||
int depth = reader.ReadInt32();
|
||||
|
||||
var chunk = new Chunk3D<T>(x, y, z, width, height, depth);
|
||||
|
||||
int metaCount = reader.ReadInt32();
|
||||
for (int i = 0; i < metaCount; i++)
|
||||
{
|
||||
string key = reader.ReadString();
|
||||
string value = reader.ReadString();
|
||||
chunk.Metadata[key] = value;
|
||||
}
|
||||
|
||||
for (int ix = 0; ix < width; ix++)
|
||||
for (int iy = 0; iy < height; iy++)
|
||||
for (int iz = 0; iz < depth; iz++)
|
||||
chunk[ix, iy, iz] = ReadPrimitive<T>(reader);
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
// -------- Helpers --------
|
||||
|
||||
private static void WritePrimitive<T>(BinaryWriter writer, T value) where T : struct
|
||||
{
|
||||
if (typeof(T) == typeof(byte))
|
||||
writer.Write((byte)(object)value);
|
||||
else if (typeof(T) == typeof(int))
|
||||
writer.Write((int)(object)value);
|
||||
else if (typeof(T) == typeof(float))
|
||||
writer.Write((float)(object)value);
|
||||
else if (typeof(T) == typeof(double))
|
||||
writer.Write((double)(object)value);
|
||||
else if (typeof(T) == typeof(short))
|
||||
writer.Write((short)(object)value);
|
||||
else if (typeof(T) == typeof(long))
|
||||
writer.Write((long)(object)value);
|
||||
else if (typeof(T) == typeof(bool))
|
||||
writer.Write((bool)(object)value);
|
||||
else
|
||||
throw new NotSupportedException($"Type {typeof(T)} is not supported for serialization.");
|
||||
}
|
||||
|
||||
private static T ReadPrimitive<T>(BinaryReader reader) where T : struct
|
||||
{
|
||||
if (typeof(T) == typeof(byte))
|
||||
return (T)(object)reader.ReadByte();
|
||||
else if (typeof(T) == typeof(int))
|
||||
return (T)(object)reader.ReadInt32();
|
||||
else if (typeof(T) == typeof(float))
|
||||
return (T)(object)reader.ReadSingle();
|
||||
else if (typeof(T) == typeof(double))
|
||||
return (T)(object)reader.ReadDouble();
|
||||
else if (typeof(T) == typeof(short))
|
||||
return (T)(object)reader.ReadInt16();
|
||||
else if (typeof(T) == typeof(long))
|
||||
return (T)(object)reader.ReadInt64();
|
||||
else if (typeof(T) == typeof(bool))
|
||||
return (T)(object)reader.ReadBoolean();
|
||||
else
|
||||
throw new NotSupportedException($"Type {typeof(T)} is not supported for deserialization.");
|
||||
}
|
||||
}
|
||||
}
|
||||
45
src/AdvChkSys/Threading/ChunkTaskScheduler.cs
Normal file
45
src/AdvChkSys/Threading/ChunkTaskScheduler.cs
Normal file
@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AdvChkSys.Threading
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides utilities for running chunk-related tasks asynchronously.
|
||||
/// Supports scheduling, cancellation, and custom task options.
|
||||
/// </summary>
|
||||
public static class ChunkTaskScheduler
|
||||
{
|
||||
/// <summary>
|
||||
/// Runs the given action asynchronously on the thread pool.
|
||||
/// </summary>
|
||||
public static Task RunAsync(Action action, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.Run(action, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the given function asynchronously on the thread pool and returns a result.
|
||||
/// </summary>
|
||||
public static Task<TResult> RunAsync<TResult>(Func<TResult> func, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.Run(func, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the given asynchronous function.
|
||||
/// </summary>
|
||||
public static Task RunAsync(Func<Task> func, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.Run(func, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the given asynchronous function and returns a result.
|
||||
/// </summary>
|
||||
public static Task<TResult> RunAsync<TResult>(Func<Task<TResult>> func, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.Run(func, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/AdvChkSys/Util/CacheCapacityHelper.cs
Normal file
27
src/AdvChkSys/Util/CacheCapacityHelper.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AdvChkSys.Util
|
||||
{
|
||||
public static class CacheCapacityHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Calculates the maximum number of chunks that can fit in available memory.
|
||||
/// </summary>
|
||||
/// <param name="chunkWidth">Chunk width (cells)</param>
|
||||
/// <param name="chunkHeight">Chunk height (cells)</param>
|
||||
/// <param name="elementSize">Size of a single element in bytes (e.g., use sizeof(byte) or Marshal.SizeOf(typeof(T)))</param>
|
||||
/// <param name="safetyFactor">Fraction of available memory to use (0.8 = 80%)</param>
|
||||
public static int CalculateChunkCapacity(int chunkWidth, int chunkHeight, int elementSize, double safetyFactor = 0.8)
|
||||
{
|
||||
ulong availableBytes = MemoryHelper.GetAvailableMemoryBytes();
|
||||
ulong usableBytes = (ulong)(availableBytes * safetyFactor);
|
||||
|
||||
int bytesPerChunk = chunkWidth * chunkHeight * elementSize;
|
||||
if (bytesPerChunk == 0) bytesPerChunk = 1; // avoid div by zero
|
||||
|
||||
ulong maxChunks = usableBytes / (ulong)bytesPerChunk;
|
||||
return (int)Math.Max(1, Math.Min(maxChunks, int.MaxValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
107
src/AdvChkSys/Util/LRUCache.cs
Normal file
107
src/AdvChkSys/Util/LRUCache.cs
Normal file
@ -0,0 +1,107 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AdvChkSys.Util
|
||||
{
|
||||
/// <summary>
|
||||
/// Thread-safe LRU (Least Recently Used) cache.
|
||||
/// </summary>
|
||||
public class LRUCache<TKey, TValue>
|
||||
where TKey : notnull
|
||||
{
|
||||
private readonly int _capacity;
|
||||
private readonly Dictionary<TKey, LinkedListNode<(TKey key, TValue value)>> _map;
|
||||
private readonly LinkedList<(TKey key, TValue value)> _lruList;
|
||||
private readonly object _lock = new();
|
||||
|
||||
public LRUCache(int capacity)
|
||||
{
|
||||
if (capacity <= 0) throw new ArgumentOutOfRangeException(nameof(capacity));
|
||||
_capacity = capacity;
|
||||
_map = new Dictionary<TKey, LinkedListNode<(TKey, TValue)>>();
|
||||
_lruList = new LinkedList<(TKey, TValue)>();
|
||||
}
|
||||
|
||||
public bool TryGet(TKey key, out TValue value)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_map.TryGetValue(key, out var node))
|
||||
{
|
||||
_lruList.Remove(node);
|
||||
_lruList.AddFirst(node);
|
||||
value = node.Value.value;
|
||||
return true;
|
||||
}
|
||||
value = default!;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(TKey key, TValue value, Action<TKey, TValue>? onEvict = null)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_map.TryGetValue(key, out var node))
|
||||
{
|
||||
_lruList.Remove(node);
|
||||
_lruList.AddFirst(node);
|
||||
node.Value = (key, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_map.Count >= _capacity)
|
||||
{
|
||||
var last = _lruList.Last;
|
||||
if (last != null)
|
||||
{
|
||||
_map.Remove(last.Value.key);
|
||||
onEvict?.Invoke(last.Value.key, last.Value.value);
|
||||
_lruList.RemoveLast();
|
||||
}
|
||||
}
|
||||
var newNode = new LinkedListNode<(TKey, TValue)>((key, value));
|
||||
_lruList.AddFirst(newNode);
|
||||
_map[key] = newNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(TKey key, out TValue? value)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_map.TryGetValue(key, out var node))
|
||||
{
|
||||
value = node.Value.value;
|
||||
_lruList.Remove(node);
|
||||
_map.Remove(key);
|
||||
return true;
|
||||
}
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<TValue> Values
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
foreach (var node in _lruList)
|
||||
yield return node.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lock) { return _map.Count; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
94
src/AdvChkSys/Util/MemoryHelper.cs
Normal file
94
src/AdvChkSys/Util/MemoryHelper.cs
Normal file
@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AdvChkSys.Util
|
||||
{
|
||||
public static class MemoryHelper
|
||||
{
|
||||
public static ulong GetAvailableMemoryBytes()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
return GetAvailableMemoryWindows();
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
return GetAvailableMemoryLinux();
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
||||
{
|
||||
return GetAvailableMemoryMac();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback: unknown, assume 1GB
|
||||
return 1UL << 30;
|
||||
}
|
||||
}
|
||||
|
||||
private static ulong GetAvailableMemoryWindows()
|
||||
{
|
||||
var memStatus = new MEMORYSTATUSEX();
|
||||
memStatus.dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
|
||||
if (GlobalMemoryStatusEx(ref memStatus))
|
||||
{
|
||||
return memStatus.ullAvailPhys;
|
||||
}
|
||||
return 1UL << 30;
|
||||
}
|
||||
|
||||
private static ulong GetAvailableMemoryLinux()
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] lines = System.IO.File.ReadAllLines("/proc/meminfo");
|
||||
ulong memFree = 0, buffers = 0, cached = 0;
|
||||
foreach (var line in lines)
|
||||
{
|
||||
if (line.StartsWith("MemAvailable:"))
|
||||
memFree = ParseKb(line);
|
||||
else if (line.StartsWith("Buffers:"))
|
||||
buffers = ParseKb(line);
|
||||
else if (line.StartsWith("Cached:"))
|
||||
cached = ParseKb(line);
|
||||
}
|
||||
return memFree > 0 ? memFree * 1024 : (buffers + cached) * 1024;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return 1UL << 30;
|
||||
}
|
||||
}
|
||||
|
||||
private static ulong GetAvailableMemoryMac()
|
||||
{
|
||||
// macOS: fallback to 1GB (implementing this is complex and rarely needed)
|
||||
return 1UL << 30;
|
||||
}
|
||||
|
||||
private static ulong ParseKb(string line)
|
||||
{
|
||||
var parts = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length >= 2 && ulong.TryParse(parts[1], out var kb))
|
||||
return kb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
private struct MEMORYSTATUSEX
|
||||
{
|
||||
public uint dwLength;
|
||||
public uint dwMemoryLoad;
|
||||
public ulong ullTotalPhys;
|
||||
public ulong ullAvailPhys;
|
||||
public ulong ullTotalPageFile;
|
||||
public ulong ullAvailPageFile;
|
||||
public ulong ullTotalVirtual;
|
||||
public ulong ullAvailVirtual;
|
||||
public ulong ullAvailExtendedVirtual;
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);
|
||||
}
|
||||
}
|
||||
338
src/AdvChkSys/advchksys.md
Normal file
338
src/AdvChkSys/advchksys.md
Normal file
@ -0,0 +1,338 @@
|
||||
AdvChkSys API Documentation
|
||||
Overview
|
||||
AdvChkSys is a high-performance, extensible chunked world management library for .NET. It provides efficient memory management, chunk loading/unloading, resource tracking, event hooks, serialization, and optional constraints for 2D and 3D chunk-based worlds. The system is suitable for games, simulations, and voxel engines.
|
||||
|
||||
Namespaces
|
||||
AdvChkSys
|
||||
AdvChkSys.Chunk
|
||||
AdvChkSys.Manager
|
||||
AdvChkSys.Interfaces
|
||||
AdvChkSys.Events
|
||||
AdvChkSys.Resources
|
||||
AdvChkSys.Constraints
|
||||
AdvChkSys.Serialization
|
||||
AdvChkSys.Threading
|
||||
AdvChkSys.Util
|
||||
AdvChkSys (Root)
|
||||
public static class AdvChkSys
|
||||
Entry point and static facade for the AdvChkSys library.
|
||||
|
||||
Properties
|
||||
string Version
|
||||
The current version of the AdvChkSys library.
|
||||
Methods
|
||||
WorldConstraints CreateDefaultConstraints()
|
||||
Creates a new WorldConstraints object with default settings.
|
||||
|
||||
ChunkManager2D<byte> Create2DManager(WorldConstraints? constraints = null)
|
||||
Creates a new 2D chunk manager with optional constraints.
|
||||
|
||||
ChunkManager3D<byte> Create3DManager(WorldConstraints? constraints = null)
|
||||
Creates a new 3D chunk manager with optional constraints.
|
||||
|
||||
bool SelfTest()
|
||||
Performs a basic self-test of the AdvChkSys core functionality. Returns true if all core systems are operational.
|
||||
|
||||
AdvChkSys.Chunk
|
||||
public class Chunk2D<T> : IChunk
|
||||
Represents a 2D chunk of data in the world. Supports all-air singleton for memory efficiency and chunk array pooling.
|
||||
|
||||
Constructors
|
||||
Chunk2D(int x, int y, int width, int height, bool isAllAir = false)
|
||||
Static Methods
|
||||
Chunk2D<T> AllAir(int x, int y, int width, int height)
|
||||
Returns a singleton all-air chunk for the given size and position.
|
||||
Properties
|
||||
int X
|
||||
The chunk's X position in chunk-space coordinates.
|
||||
|
||||
int Y
|
||||
The chunk's Y position in chunk-space coordinates.
|
||||
|
||||
int Width
|
||||
The width of the chunk (in cells/tiles/units).
|
||||
|
||||
int Height
|
||||
The height of the chunk (in cells/tiles/units).
|
||||
|
||||
Dictionary<string, object> Metadata
|
||||
Metadata dictionary for arbitrary chunk information (e.g., biome, tags).
|
||||
|
||||
bool IsAllAir
|
||||
Returns true if this chunk is the all-air singleton.
|
||||
|
||||
Indexers
|
||||
T this[int localX, int localY]
|
||||
Gets or sets the value at the given local chunk coordinates.
|
||||
Methods
|
||||
void Fill(T value)
|
||||
Fills the chunk with a specified value (no-op for all-air).
|
||||
|
||||
T[,]? GetDataArray()
|
||||
Returns the underlying data array (for pooling).
|
||||
|
||||
void ReleaseDataArray()
|
||||
Releases the data array back to the pool (for chunk manager).
|
||||
|
||||
public class Chunk3D<T> : IChunk
|
||||
Represents a 3D chunk of data in the world. Perspective-agnostic and supports arbitrary data types and metadata.
|
||||
|
||||
Constructors
|
||||
Chunk3D(int x, int y, int z, int width, int height, int depth)
|
||||
Properties
|
||||
int X
|
||||
The chunk's X position in chunk-space coordinates.
|
||||
|
||||
int Y
|
||||
The chunk's Y position in chunk-space coordinates.
|
||||
|
||||
int Z
|
||||
The chunk's Z position in chunk-space coordinates.
|
||||
|
||||
int Width
|
||||
The width of the chunk (in cells/tiles/units).
|
||||
|
||||
int Height
|
||||
The height of the chunk (in cells/tiles/units).
|
||||
|
||||
int Depth
|
||||
The depth of the chunk (in cells/tiles/units).
|
||||
|
||||
Dictionary<string, object> Metadata
|
||||
Metadata dictionary for arbitrary chunk information (e.g., biome, tags).
|
||||
|
||||
Indexers
|
||||
T this[int localX, int localY, int localZ]
|
||||
Gets or sets the value at the given local chunk coordinates.
|
||||
Methods
|
||||
void Fill(T value)
|
||||
Fills the chunk with a specified value.
|
||||
AdvChkSys.Manager
|
||||
public class ChunkManager2D<T> : IChunkManager
|
||||
Manages 2D chunks in memory. Handles loading, unloading, and access. Uses an LRU cache for memory efficiency.
|
||||
|
||||
Constructors
|
||||
ChunkManager2D(WorldConstraints? constraints = null, int capacity = 4096)
|
||||
Methods
|
||||
bool IsChunkLoaded(int x, int y)
|
||||
Returns true if the chunk at (x, y) is loaded.
|
||||
|
||||
Chunk2D<T>? GetChunk(int x, int y)
|
||||
Gets the chunk at (x, y) if loaded, or null if not.
|
||||
|
||||
Chunk2D<T> LoadOrCreateChunk(int x, int y, int width, int height)
|
||||
Loads or creates a chunk at (x, y) with the given size.
|
||||
|
||||
Task<Chunk2D<T>> LoadOrCreateChunkAsync(int x, int y, int width, int height)
|
||||
Loads or creates a chunk asynchronously.
|
||||
|
||||
bool UnloadChunk(int x, int y)
|
||||
Unloads (removes) the chunk at (x, y) if loaded.
|
||||
|
||||
Task<bool> UnloadChunkAsync(int x, int y)
|
||||
Unloads the chunk asynchronously.
|
||||
|
||||
IEnumerable<Chunk2D<T>> GetAllChunks()
|
||||
Enumerates all loaded chunks.
|
||||
|
||||
public class ChunkManager3D<T> : IChunkManager
|
||||
Manages 3D chunks in memory. Handles loading, unloading, and access.
|
||||
|
||||
Constructors
|
||||
ChunkManager3D(WorldConstraints? constraints = null, int capacity = 4096)
|
||||
Methods
|
||||
bool IsChunkLoaded(int x, int y, int z)
|
||||
Returns true if the chunk at (x, y, z) is loaded.
|
||||
|
||||
Chunk3D<T>? GetChunk(int x, int y, int z)
|
||||
Gets the chunk at (x, y, z) if loaded, or null if not.
|
||||
|
||||
Chunk3D<T> LoadOrCreateChunk(int x, int y, int z, int width, int height, int depth)
|
||||
Loads or creates a chunk at (x, y, z) with the given size.
|
||||
|
||||
bool UnloadChunk(int x, int y, int z)
|
||||
Unloads (removes) the chunk at (x, y, z) if loaded.
|
||||
|
||||
IEnumerable<Chunk3D<T>> GetAllChunks()
|
||||
Enumerates all loaded chunks.
|
||||
|
||||
AdvChkSys.Interfaces
|
||||
public interface IChunk
|
||||
Represents a generic chunk in the world. Provides basic properties for position, size, and metadata.
|
||||
|
||||
Properties
|
||||
int X { get; }
|
||||
int Y { get; }
|
||||
int Width { get; }
|
||||
int Height { get; }
|
||||
Dictionary<string, object> Metadata { get; }
|
||||
public interface IChunkManager
|
||||
Interface for managing chunks in memory. Provides methods for loading, unloading, and accessing chunks.
|
||||
|
||||
Methods
|
||||
bool IsChunkLoaded(int x, int y)
|
||||
IChunk? GetChunk(int x, int y)
|
||||
IChunk LoadOrCreateChunk(int x, int y, int width, int height)
|
||||
bool UnloadChunk(int x, int y)
|
||||
IEnumerable<IChunk> GetAllChunks()
|
||||
AdvChkSys.Events
|
||||
public static class ChunkEvents
|
||||
Provides events for chunk lifecycle operations such as loading, unloading, saving, and more. Thread-safe event subscription and invocation.
|
||||
|
||||
Events
|
||||
event Action<IChunk> ChunkLoaded
|
||||
Occurs when a chunk has been loaded into memory.
|
||||
|
||||
event Action<IChunk> ChunkLoading
|
||||
Occurs when a chunk is about to be loaded into memory.
|
||||
|
||||
event Action<IChunk> ChunkUnloading
|
||||
Occurs when a chunk is about to be unloaded from memory.
|
||||
|
||||
event Action<IChunk> ChunkUnloaded
|
||||
Occurs when a chunk has been unloaded from memory.
|
||||
|
||||
event Action<IChunk> ChunkSaving
|
||||
Occurs when a chunk is about to be saved.
|
||||
|
||||
event Action<IChunk> ChunkSaved
|
||||
Occurs when a chunk has been saved.
|
||||
|
||||
Methods
|
||||
void OnChunkLoading(IChunk chunk)
|
||||
Raises the ChunkLoading event.
|
||||
|
||||
void OnChunkLoaded(IChunk chunk)
|
||||
Raises the ChunkLoaded event.
|
||||
|
||||
void OnChunkUnloading(IChunk chunk)
|
||||
Raises the ChunkUnloading event.
|
||||
|
||||
void OnChunkUnloaded(IChunk chunk)
|
||||
Raises the ChunkUnloaded event.
|
||||
|
||||
void OnChunkSaving(IChunk chunk)
|
||||
Raises the ChunkSaving event.
|
||||
|
||||
void OnChunkSaved(IChunk chunk)
|
||||
Raises the ChunkSaved event.
|
||||
|
||||
AdvChkSys.Resources
|
||||
public static class ChunkResourceManager
|
||||
Manages allocation and release of chunk resources in memory. Can be extended to track resource usage, pooling, or implement custom memory strategies.
|
||||
|
||||
Methods
|
||||
void AllocateChunk(IChunk chunk)
|
||||
Called when a chunk is allocated/loaded into memory. Tracks the chunk and can be extended for pooling or resource limits.
|
||||
|
||||
void ReleaseChunk(IChunk chunk)
|
||||
Called when a chunk is released/unloaded from memory. Removes the chunk from tracking and can be extended for pooling or cleanup.
|
||||
|
||||
int AllocatedChunkCount
|
||||
Gets the current number of allocated chunks.
|
||||
|
||||
void Clear()
|
||||
Clears all tracked chunks (for diagnostics or shutdown).
|
||||
|
||||
AdvChkSys.Constraints
|
||||
public class WorldConstraints
|
||||
Represents constraints and limits for the chunk world. Can be used to restrict world size, chunk counts, and other resource limits.
|
||||
|
||||
Properties
|
||||
int? MinChunkX
|
||||
The minimum allowed chunk X coordinate (inclusive).
|
||||
|
||||
int? MaxChunkX
|
||||
The maximum allowed chunk X coordinate (inclusive).
|
||||
|
||||
int? MinChunkY
|
||||
The minimum allowed chunk Y coordinate (inclusive).
|
||||
|
||||
int? MaxChunkY
|
||||
The maximum allowed chunk Y coordinate (inclusive).
|
||||
|
||||
int? MaxLoadedChunks
|
||||
The maximum number of chunks allowed to be loaded in memory at once.
|
||||
|
||||
Methods
|
||||
bool IsWithinBounds(int chunkX, int chunkY)
|
||||
Checks if the given chunk coordinates are within the allowed world bounds.
|
||||
|
||||
bool IsWithinChunkLimit(int loadedChunkCount)
|
||||
Checks if the current number of loaded chunks is within the allowed limit.
|
||||
|
||||
AdvChkSys.Serialization
|
||||
public static class ChunkSerializer
|
||||
Provides serialization and deserialization for chunk instances. Supports Chunk2D<T> and Chunk3D<T> with primitive types (e.g., byte, int, float).
|
||||
|
||||
Methods
|
||||
byte[] Serialize2D<T>(Chunk2D<T> chunk) where T : struct
|
||||
Serializes a Chunk2D<T> to a byte array.
|
||||
|
||||
Chunk2D<T> Deserialize2D<T>(byte[] data) where T : struct
|
||||
Deserializes a Chunk2D<T> from a byte array.
|
||||
|
||||
byte[] Serialize3D<T>(Chunk3D<T> chunk) where T : struct
|
||||
Serializes a Chunk3D<T> to a byte array.
|
||||
|
||||
Chunk3D<T> Deserialize3D<T>(byte[] data) where T : struct
|
||||
Deserializes a Chunk3D<T> from a byte array.
|
||||
|
||||
AdvChkSys.Threading
|
||||
public static class ChunkTaskScheduler
|
||||
Provides utilities for running chunk-related tasks asynchronously. Supports scheduling, cancellation, and custom task options.
|
||||
|
||||
Methods
|
||||
Task RunAsync(Action action, CancellationToken cancellationToken = default)
|
||||
Runs the given action asynchronously on the thread pool.
|
||||
|
||||
Task<TResult> RunAsync<TResult>(Func<TResult> func, CancellationToken cancellationToken = default)
|
||||
Runs the given function asynchronously and returns a result.
|
||||
|
||||
Task RunAsync(Func<Task> func, CancellationToken cancellationToken = default)
|
||||
Runs the given asynchronous function.
|
||||
|
||||
Task<TResult> RunAsync<TResult>(Func<Task<TResult>> func, CancellationToken cancellationToken = default)
|
||||
Runs the given asynchronous function and returns a result.
|
||||
|
||||
AdvChkSys.Util
|
||||
public class LRUCache<TKey, TValue> where TKey : notnull
|
||||
Thread-safe LRU (Least Recently Used) cache. Used for chunk memory management.
|
||||
|
||||
Constructors
|
||||
LRUCache(int capacity)
|
||||
Methods
|
||||
bool TryGet(TKey key, out TValue value)
|
||||
Tries to get a value by key and marks it as recently used.
|
||||
|
||||
void Add(TKey key, TValue value, Action<TKey, TValue>? onEvict = null)
|
||||
Adds a value to the cache, evicting the least recently used if over capacity.
|
||||
|
||||
bool Remove(TKey key, out TValue? value)
|
||||
Removes a value by key.
|
||||
|
||||
Properties
|
||||
IEnumerable<TValue> Values
|
||||
Enumerates all values in the cache.
|
||||
|
||||
int Count
|
||||
Gets the number of items in the cache.
|
||||
|
||||
Python Bindings (src/bindings/python/advchksys.py)
|
||||
Provides Python access to AdvChkSys via .NET interop.
|
||||
|
||||
Functions
|
||||
get_version()
|
||||
Returns the AdvChkSys library version.
|
||||
|
||||
create_2d_manager(constraints=None)
|
||||
Creates a 2D chunk manager (byte type).
|
||||
|
||||
create_3d_manager(constraints=None)
|
||||
Creates a 3D chunk manager (byte type).
|
||||
|
||||
create_constraints(min_x=None, max_x=None, min_y=None, max_y=None, max_loaded=None)
|
||||
Creates a WorldConstraints object.
|
||||
|
||||
Summary
|
||||
AdvChkSys provides a modular, high-performance, and extensible API for chunked world management in .NET, with robust support for memory pooling, resource tracking, event hooks, serialization, constraints, and async operations. It is suitable for games, simulations, and any application requiring efficient spatial partitioning and management of large worlds.
|
||||
36
src/bindings/python/README.md
Normal file
36
src/bindings/python/README.md
Normal file
@ -0,0 +1,36 @@
|
||||
# AdvChkSys Python Bindings
|
||||
|
||||
These bindings allow you to use the AdvChkSys C# chunk system from Python via [pythonnet](https://github.com/pythonnet/pythonnet).
|
||||
|
||||
## Requirements
|
||||
|
||||
- .NET 6.0+ or .NET Core 3.1+ (to build AdvChkSys)
|
||||
- Python 3.8+
|
||||
- `pythonnet` (`pip install pythonnet`)
|
||||
|
||||
## Usage
|
||||
|
||||
1. **Build the AdvChkSys C# library** (DLL must be present in `src/AdvChkSys/bin/Debug/netstandard2.1/AdvChkSys.dll`).
|
||||
|
||||
2. **Install pythonnet:**
|
||||
```bash
|
||||
pip install pythonnet
|
||||
```
|
||||
|
||||
3. **Use the bindings in Python:**
|
||||
```python
|
||||
from advchksys import get_version, create_2d_manager, create_constraints
|
||||
|
||||
print("AdvChkSys version:", get_version())
|
||||
|
||||
constraints = create_constraints(min_x=0, max_x=10, min_y=0, max_y=10, max_loaded=100)
|
||||
manager = create_2d_manager(constraints)
|
||||
chunk = manager.LoadOrCreateChunk(1, 1, 16, 16)
|
||||
chunk[0, 0] = 42
|
||||
print("Chunk value at (0,0):", chunk[0, 0])
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- You can access all public methods and properties of the C# classes.
|
||||
- For advanced usage, see the [pythonnet documentation](https://pythonnet.github.io/pythonnet/).
|
||||
71
src/bindings/python/advchksys.py
Normal file
71
src/bindings/python/advchksys.py
Normal file
@ -0,0 +1,71 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
import clr # type: ignore
|
||||
|
||||
# Path to the compiled AdvChkSys .NET DLL (adjust as needed)
|
||||
DLL_PATH = os.path.abspath(
|
||||
os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"..",
|
||||
"..",
|
||||
"AdvChkSys",
|
||||
"bin",
|
||||
"Debug",
|
||||
"netstandard2.1",
|
||||
"AdvChkSys.dll",
|
||||
)
|
||||
)
|
||||
|
||||
if not os.path.exists(DLL_PATH):
|
||||
raise FileNotFoundError(f"Could not find AdvChkSys.dll at {DLL_PATH}")
|
||||
|
||||
sys.path.append(os.path.dirname(DLL_PATH))
|
||||
clr.AddReference("AdvChkSys")
|
||||
|
||||
# Import .NET types
|
||||
|
||||
from System import Byte # type: ignore # noqa: E402
|
||||
|
||||
import AdvChkSys # type: ignore # noqa: E402
|
||||
import AdvChkSys.Manager # type: ignore # noqa: E402
|
||||
import AdvChkSys.Constraints # type: ignore # noqa: E402
|
||||
|
||||
|
||||
def get_version():
|
||||
"""Return the AdvChkSys library version."""
|
||||
return AdvChkSys.AdvChkSys.Version # type: ignore
|
||||
|
||||
|
||||
def create_2d_manager(constraints=None):
|
||||
"""Create a 2D chunk manager (byte type)."""
|
||||
if constraints is None:
|
||||
constraints = AdvChkSys.Constraints.WorldConstraints() # type: ignore
|
||||
# Use generic type with System.Byte
|
||||
return AdvChkSys.Manager.ChunkManager2D[Byte](constraints) # type: ignore
|
||||
|
||||
|
||||
def create_3d_manager(constraints=None):
|
||||
"""Create a 3D chunk manager (byte type)."""
|
||||
if constraints is None:
|
||||
constraints = AdvChkSys.Constraints.WorldConstraints() # type: ignore
|
||||
# Use generic type with System.Byte
|
||||
return AdvChkSys.Manager.ChunkManager3D[Byte](constraints) # type: ignore
|
||||
|
||||
|
||||
def create_constraints(
|
||||
min_x=None, max_x=None, min_y=None, max_y=None, max_loaded=None
|
||||
):
|
||||
"""Create a WorldConstraints object."""
|
||||
wc = AdvChkSys.Constraints.WorldConstraints() # type: ignore
|
||||
if min_x is not None:
|
||||
wc.MinChunkX = min_x
|
||||
if max_x is not None:
|
||||
wc.MaxChunkX = max_x
|
||||
if min_y is not None:
|
||||
wc.MinChunkY = min_y
|
||||
if max_y is not None:
|
||||
wc.MaxChunkY = max_y
|
||||
if max_loaded is not None:
|
||||
wc.MaxLoadedChunks = max_loaded
|
||||
return wc
|
||||
Loading…
x
Reference in New Issue
Block a user