1
0
Fork 0

[server] Add plane status and tweak soft loaded chunk limit

This commit is contained in:
Starbeamrainbowlabs 2017-12-16 12:01:07 +00:00
parent 3486a28759
commit 4397d90fe9
Signed by: sbrl
GPG Key ID: 1BE5172E637709C2
4 changed files with 104 additions and 14 deletions

View File

@ -61,10 +61,11 @@ namespace Nibriboard
await destination.WriteLineAsync("Nibriboard Server Command Console"); await destination.WriteLineAsync("Nibriboard Server Command Console");
await destination.WriteLineAsync("================================="); await destination.WriteLineAsync("=================================");
await destination.WriteLineAsync("Available commands:"); await destination.WriteLineAsync("Available commands:");
await destination.WriteLineAsync(" help Show this message"); await destination.WriteLineAsync(" help Show this message");
await destination.WriteLineAsync(" save Save the ripplespace to disk"); await destination.WriteLineAsync(" save Save the ripplespace to disk");
await destination.WriteLineAsync(" plane list List all the currently loaded planes"); await destination.WriteLineAsync(" plane list List all the currently loaded planes");
await destination.WriteLineAsync(" plane create {new-plane-name} [{chunkSize}] Create a new named plane, optionally with the specified chunk size."); await destination.WriteLineAsync(" plane create {new-plane-name} [{chunkSize}] Create a new named plane, optionally with the specified chunk size.");
await destination.WriteLineAsync(" plane status {plane-name} Show the statistics of the current plane.");
break; break;
case "save": case "save":
await destination.WriteAsync("Saving ripple space - "); await destination.WriteAsync("Saving ripple space - ");
@ -83,7 +84,7 @@ namespace Nibriboard
case "list": case "list":
await destination.WriteLineAsync("Planes:"); await destination.WriteLineAsync("Planes:");
foreach(Plane plane in server.PlaneManager.Planes) foreach(Plane plane in server.PlaneManager.Planes)
await destination.WriteLineAsync($" {plane.Name} @ {plane.ChunkSize} ({plane.LoadedChunks} / ~{plane.SoftLoadedChunkLimit} chunks loaded, {plane.UnloadableChunks} inactive)"); await destination.WriteLineAsync($" {plane.Name} @ {plane.ChunkSize} ({plane.LoadedChunks} / ~{plane.SoftLoadedChunkLimit} chunks loaded, {plane.UnloadableChunks} inactive, {plane.TotalChunks} total at last save)");
await destination.WriteLineAsync(); await destination.WriteLineAsync();
await destination.WriteLineAsync($"Total {server.PlaneManager.Planes.Count}"); await destination.WriteLineAsync($"Total {server.PlaneManager.Planes.Count}");
break; break;
@ -104,6 +105,29 @@ namespace Nibriboard
await destination.WriteLineAsync($"Created plane with name {newPlaneName} and chunk size {chunkSize}."); await destination.WriteLineAsync($"Created plane with name {newPlaneName} and chunk size {chunkSize}.");
break;
case "status":
if(commandParts.Length < 3) {
await destination.WriteLineAsync("Error: No plane name specified!");
return;
}
string targetPlaneName = commandParts[2].Trim();
Plane targetPlane = server.PlaneManager.GetByName(targetPlaneName);
if(targetPlane == null) {
await destination.WriteLineAsync($"Error: A plane with the name {targetPlaneName} doesn't exist.");
return;
}
await destination.WriteLineAsync($"Name: {targetPlane.Name}");
await destination.WriteLineAsync($"Chunk size: {targetPlane.ChunkSize}");
await destination.WriteLineAsync($"Loaded chunks: {targetPlane.LoadedChunks}");
await destination.WriteLineAsync($"Unloaded chunks: {targetPlane.TotalChunks - targetPlane.LoadedChunks}");
await destination.WriteLineAsync($"Total chunks: {targetPlane.TotalChunks}");
await destination.WriteLineAsync($"Primary chunk area size: {targetPlane.PrimaryChunkAreaSize}");
await destination.WriteLineAsync($"Min unloadeable chunks: {targetPlane.MinUnloadeableChunks}");
await destination.WriteLineAsync($"Soft loaded chunk limit: {targetPlane.SoftLoadedChunkLimit}");
break; break;
default: default:
await destination.WriteLineAsync($"Error: Unknown sub-action {subAction}."); await destination.WriteLineAsync($"Error: Unknown sub-action {subAction}.");
@ -111,6 +135,33 @@ namespace Nibriboard
} }
break; break;
/*case "chunk":
if(commandParts.Length < 2) {
await destination.WriteLineAsync("Error: No sub-action specified.");
break;
}
string chunkSubAction = commandParts[1].Trim();
switch(chunkSubAction)
{
case "list":
if(commandParts.Length < 3) {
await destination.WriteLineAsync("Error: No plane specified to list the chunks of!");
return;
}
Plane plane = server.PlaneManager.GetByName(commandParts[2].Trim());
foreach(Chunk chunk in plane.
break;
default:
await destination.WriteLineAsync($"Error: Unknown sub-action {chunkSubAction}.");
break;
}
break;*/
default: default:
await destination.WriteLineAsync($"Error: Unrecognised command {commandName}"); await destination.WriteLineAsync($"Error: Unrecognised command {commandName}");
break; break;

View File

@ -20,7 +20,7 @@ namespace Nibriboard.RippleSpace
} }
/// <summary> /// <summary>
/// Creates a new blank <see cref="Nibriboard.RippleSpace.ChunkReference" />. /// Creates a new blank <see cref="ChunkReference" />.
/// Don't use this yourself! This is only for Newtonsoft.Json to use when deserialising references. /// Don't use this yourself! This is only for Newtonsoft.Json to use when deserialising references.
/// </summary> /// </summary>
public ChunkReference() : base() public ChunkReference() : base()

View File

@ -43,7 +43,7 @@ namespace Nibriboard.RippleSpace
/// loaded. /// loaded.
/// Works like a radius. /// Works like a radius.
/// </summary> /// </summary>
public int PrimaryChunkAreaSize = 10; public int PrimaryChunkAreaSize = 5;
/// <summary> /// <summary>
/// The minimum number of potentially unloadable chunks that we should have /// The minimum number of potentially unloadable chunks that we should have
@ -95,6 +95,19 @@ namespace Nibriboard.RippleSpace
return result; return result;
} }
} }
/// <summary>
/// Calculates the total number of chunks created that are on this plane - including those
/// that are currently unloaded.
/// </summary>
/// <description>
/// This is, understandably, a rather expensive operation - so use with caution!
/// Also, this count is only accurate to the last save.
/// </description>
public int TotalChunks {
get {
return Directory.GetFileSystemEntries(StorageDirectory, "*.chunk").Length;
}
}
/// <summary> /// <summary>
/// Initialises a new plane. /// Initialises a new plane.
@ -110,7 +123,7 @@ namespace Nibriboard.RippleSpace
// Set the soft loaded chunk limit to double the number of chunks in the // Set the soft loaded chunk limit to double the number of chunks in the
// primary chunks area // primary chunks area
// Note that the primary chunk area is a radius around (0, 0) - not the diameter // Note that the primary chunk area is a radius around (0, 0) - not the diameter
SoftLoadedChunkLimit = PrimaryChunkAreaSize * PrimaryChunkAreaSize * 4; SoftLoadedChunkLimit = PrimaryChunkAreaSize * PrimaryChunkAreaSize * 16;
} }
private async Task LoadPrimaryChunks() private async Task LoadPrimaryChunks()
@ -131,7 +144,7 @@ namespace Nibriboard.RippleSpace
} }
} }
await FetchChunks(primaryChunkRefs); await FetchChunks(primaryChunkRefs, false);
} }
/// <summary> /// <summary>
@ -139,16 +152,24 @@ namespace Nibriboard.RippleSpace
/// </summary> /// </summary>
/// <param name="chunkRefs">The chunk references to fetch the attached chunks for.</param> /// <param name="chunkRefs">The chunk references to fetch the attached chunks for.</param>
/// <returns>The chunks attached to the specified chunk references.</returns> /// <returns>The chunks attached to the specified chunk references.</returns>
public async Task<List<Chunk>> FetchChunks(List<ChunkReference> chunkRefs) public async Task<List<Chunk>> FetchChunks(IEnumerable<ChunkReference> chunkRefs, bool autoCreate)
{ {
// todo Paralellise loading with https://www.nuget.org/packages/AsyncEnumerator // Todo Paralellise loading with https://www.nuget.org/packages/AsyncEnumerator
List<Chunk> chunks = new List<Chunk>(); List<Chunk> chunks = new List<Chunk>();
foreach(ChunkReference chunkRef in chunkRefs) foreach(ChunkReference chunkRef in chunkRefs) {
chunks.Add(await FetchChunk(chunkRef)); Chunk nextChunk = await FetchChunk(chunkRef, true);
if(nextChunk != null) // Might be null if we're not allowed to create new chunks
chunks.Add(nextChunk);
}
return chunks; return chunks;
} }
public async Task<List<Chunk>> FetchChunks(IEnumerable<ChunkReference> chunkRefs)
{
return await FetchChunks(chunkRefs, true);
}
public async Task<Chunk> FetchChunk(ChunkReference chunkLocation)
public async Task<Chunk> FetchChunk(ChunkReference chunkLocation, bool autoCreate)
{ {
// If the chunk is in the loaded chunk-space, then return it immediately // If the chunk is in the loaded chunk-space, then return it immediately
if(loadedChunkspace.ContainsKey(chunkLocation)) if(loadedChunkspace.ContainsKey(chunkLocation))
@ -162,13 +183,22 @@ namespace Nibriboard.RippleSpace
Chunk loadedChunk; Chunk loadedChunk;
if(File.Exists(chunkFilePath)) // If the chunk exists on disk, load it if(File.Exists(chunkFilePath)) // If the chunk exists on disk, load it
loadedChunk = await Chunk.FromFile(this, chunkFilePath); loadedChunk = await Chunk.FromFile(this, chunkFilePath);
else // Ooooh! It's a _new_, never-before-seen one! Create a brand new chunk :D else
{
// Ooooh! It's a _new_, never-before-seen one! Create a brand new chunk :D
// ....but only if we've been told it's ok to create new chunks.
if(!autoCreate) return null;
loadedChunk = new Chunk(this, ChunkSize, chunkLocation); loadedChunk = new Chunk(this, ChunkSize, chunkLocation);
}
loadedChunk.OnChunkUpdate += HandleChunkUpdate; loadedChunk.OnChunkUpdate += HandleChunkUpdate;
loadedChunkspace.Add(chunkLocation, loadedChunk); loadedChunkspace.Add(chunkLocation, loadedChunk);
return loadedChunk; return loadedChunk;
} }
public async Task<Chunk> FetchChunk(ChunkReference chunkLocation)
{
return await FetchChunk(chunkLocation, true);
}
/// <summary> /// <summary>
/// Works out whether a chunk currently exists. /// Works out whether a chunk currently exists.

View File

@ -116,6 +116,15 @@ namespace Nibriboard.RippleSpace
return newPlane; return newPlane;
} }
public Plane GetByName(string targetPlaneName)
{
foreach(Plane plane in Planes) {
if(plane.Name == targetPlaneName)
return plane;
}
return null;
}
public async Task StartMaintenanceMonkey() public async Task StartMaintenanceMonkey()
{ {
Log.WriteLine("[RippleSpace/Maintenance] Automated maintenance monkey created."); Log.WriteLine("[RippleSpace/Maintenance] Automated maintenance monkey created.");