mirror of
https://github.com/sbrl/Nibriboard.git
synced 2018-01-10 21:33:49 +00:00
Extensively refactor core to allow for loading. Also work on a bit of saving too.
Now I can see why they say that you should build this in from the beginning....
This commit is contained in:
parent
37fd8bff81
commit
34d74281e3
8 changed files with 137 additions and 30 deletions
|
@ -306,8 +306,9 @@ namespace Nibriboard.Client
|
|||
Log.WriteLine("[NibriClient#{0}] Changing to plane {1}.", Id, message.NewPlaneName);
|
||||
|
||||
// Create a new plane with the specified name if it doesn't exist already
|
||||
// future we might want to allow the user to specify the chunk size
|
||||
if(manager.SpaceManager[message.NewPlaneName] == default(Plane))
|
||||
manager.SpaceManager.CreatePlane(message.NewPlaneName);
|
||||
manager.SpaceManager.CreatePlane(new PlaneInfo(message.NewPlaneName));
|
||||
|
||||
// Remove the event listener from the old plane if there is indeed an old plane to remove it from
|
||||
if(CurrentPlane != null)
|
||||
|
|
|
@ -66,7 +66,6 @@
|
|||
<Compile Include="RippleSpace\ChunkReference.cs" />
|
||||
<Compile Include="RippleSpace\DrawnLine.cs" />
|
||||
<Compile Include="RippleSpace\Reference.cs" />
|
||||
<Compile Include="Utilities.cs" />
|
||||
<Compile Include="NibriboardServer.cs" />
|
||||
<Compile Include="Log.cs" />
|
||||
<Compile Include="Utilities\EmbeddedFiles.cs" />
|
||||
|
@ -108,6 +107,9 @@
|
|||
<Compile Include="Client\Messages\LineCompleteReflectionMessage.cs" />
|
||||
<Compile Include="Client\Messages\LineStartMessage.cs" />
|
||||
<Compile Include="Client\Messages\LineStartReflectionMessage.cs" />
|
||||
<Compile Include="Utilities\CalcPaths.cs" />
|
||||
<Compile Include="RippleSpace\PlaneInfo.cs" />
|
||||
<Compile Include="Utilities\BinaryIO.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="ClientFiles\index.html" />
|
||||
|
|
|
@ -6,6 +6,8 @@ using System.Collections;
|
|||
using System.Runtime.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
using Nibriboard.Utilities;
|
||||
|
||||
namespace Nibriboard.RippleSpace
|
||||
{
|
||||
public enum ChunkUpdateType
|
||||
|
@ -219,7 +221,7 @@ namespace Nibriboard.RippleSpace
|
|||
}
|
||||
public static async Task<Chunk> FromStream(Plane plane, Stream chunkSource)
|
||||
{
|
||||
Chunk loadedChunk = await Utilities.DeserialiseBinaryObject<Chunk>(chunkSource);
|
||||
Chunk loadedChunk = await BinaryIO.DeserialiseBinaryObject<Chunk>(chunkSource);
|
||||
loadedChunk.plane = plane;
|
||||
|
||||
return loadedChunk;
|
||||
|
|
|
@ -7,6 +7,8 @@ using System.Runtime.Serialization;
|
|||
using SharpCompress.Writers;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Readers;
|
||||
using Nibriboard.Utilities;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Nibriboard.RippleSpace
|
||||
{
|
||||
|
@ -79,7 +81,8 @@ namespace Nibriboard.RippleSpace
|
|||
public int UnloadableChunks {
|
||||
get {
|
||||
int result = 0;
|
||||
foreach(KeyValuePair<ChunkReference, Chunk> chunkEntry in loadedChunkspace) {
|
||||
foreach(KeyValuePair<ChunkReference, Chunk> chunkEntry in loadedChunkspace)
|
||||
{
|
||||
if(chunkEntry.Value.CouldUnload)
|
||||
result++;
|
||||
}
|
||||
|
@ -87,20 +90,21 @@ namespace Nibriboard.RippleSpace
|
|||
}
|
||||
}
|
||||
|
||||
public Plane(string inName, int inChunkSize, string inStorageDirectoryRoot)
|
||||
/// <summary>
|
||||
/// Initialises a new plane.
|
||||
/// </summary>
|
||||
/// <param name="inInfo">The settings to use to initialise the new plane.</param>
|
||||
/// <param name="inStorageDirectory">The storage directory in which we should store the plane's chunks (may be prepopulated).</param>
|
||||
public Plane(PlaneInfo inInfo, string inStorageDirectory)
|
||||
{
|
||||
Name = inName;
|
||||
ChunkSize = inChunkSize;
|
||||
Name = inInfo.Name;
|
||||
ChunkSize = inInfo.ChunkSize;
|
||||
StorageDirectory = inStorageDirectory;
|
||||
|
||||
// Set the soft loaded chunk limit to double the number of chunks in the
|
||||
// primary chunks area
|
||||
// Note that the primary chunk area is a radius around (0, 0) - not the diameter
|
||||
SoftLoadedChunkLimit = PrimaryChunkAreaSize * PrimaryChunkAreaSize * 4;
|
||||
|
||||
StorageDirectory = inStorageDirectoryRoot + Name;
|
||||
if(File.Exists(StorageDirectory))
|
||||
throw new InvalidOperationException($"Error: The unpacked storage directory {StorageDirectory} already exists!");
|
||||
Directory.CreateDirectory(StorageDirectory);
|
||||
}
|
||||
|
||||
private async Task LoadPrimaryChunks()
|
||||
|
@ -245,22 +249,39 @@ namespace Nibriboard.RippleSpace
|
|||
OnChunkUpdate(sender, eventArgs);
|
||||
}
|
||||
|
||||
public static async Task<Plane> FromFile(string inName, int inChunkSize, string inStorageDirectoryRoot, string sourceFilename)
|
||||
/// <summary>
|
||||
/// Loads a plane form a given nplane file.
|
||||
/// </summary>
|
||||
/// <param name="planeName">The name of the plane to load.</param>
|
||||
/// <param name="storageDirectoryRoot">The directory to which the plane should be unpacked.</param>
|
||||
/// <param name="sourceFilename">The path to the nplane file to load.</param>
|
||||
/// <param name="deleteSource">Whether the source file should be deleted once the plane has been loaded.</param>
|
||||
/// <returns>The loaded plane.</returns>
|
||||
public static async Task<Plane> FromFile(string planeName, string storageDirectoryRoot, string sourceFilename, bool deleteSource)
|
||||
{
|
||||
Plane loadedPlane = new Plane(inName, inChunkSize, inStorageDirectoryRoot);
|
||||
string targetUnpackingPath = CalcPaths.UnpackedPlaneDir(storageDirectoryRoot, planeName);
|
||||
|
||||
// Unpack the plane to the temporary directory
|
||||
using(Stream sourceStream = File.OpenRead(sourceFilename))
|
||||
using(IReader unpacker = ReaderFactory.Open(sourceStream))
|
||||
{
|
||||
unpacker.WriteAllToDirectory(loadedPlane.StorageDirectory);
|
||||
unpacker.WriteAllToDirectory(targetUnpackingPath);
|
||||
}
|
||||
|
||||
PlaneInfo planeInfo = JsonConvert.DeserializeObject<PlaneInfo>(
|
||||
File.ReadAllText(CalcPaths.UnpackedPlaneIndex(targetUnpackingPath))
|
||||
);
|
||||
planeInfo.Name = planeName;
|
||||
|
||||
Plane loadedPlane = new Plane(planeInfo, targetUnpackingPath);
|
||||
|
||||
// Load the primary chunks from disk inot the plane
|
||||
await loadedPlane.LoadPrimaryChunks();
|
||||
|
||||
if(deleteSource)
|
||||
File.Delete(sourceFilename);
|
||||
|
||||
return loadedPlane;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
23
Nibriboard/RippleSpace/PlaneInfo.cs
Normal file
23
Nibriboard/RippleSpace/PlaneInfo.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
|
||||
namespace Nibriboard.RippleSpace
|
||||
{
|
||||
public class PlaneInfo
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public int ChunkSize { get; set; }
|
||||
|
||||
public PlaneInfo()
|
||||
{
|
||||
}
|
||||
public PlaneInfo(string inName) : this(inName, 1024)
|
||||
{
|
||||
}
|
||||
public PlaneInfo(string inName, int inChunkSize)
|
||||
{
|
||||
Name = inName;
|
||||
ChunkSize = inChunkSize;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -3,7 +3,9 @@ using System.IO;
|
|||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using SharpCompress.Readers;
|
||||
using Nibriboard.Utilities;
|
||||
|
||||
namespace Nibriboard.RippleSpace
|
||||
{
|
||||
|
@ -71,16 +73,19 @@ namespace Nibriboard.RippleSpace
|
|||
/// <summary>
|
||||
/// Creates a new plane, adds it to this RippleSpaceManager, and then returns it.
|
||||
/// </summary>
|
||||
/// <param name="newPlaneName">The name of the new plane to create.</param>
|
||||
/// <param name="newPlaneInfo">The settings for the new plane to create.</param>
|
||||
/// <returns>The newly created plane.</returns>
|
||||
public Plane CreatePlane(string newPlaneName)
|
||||
public Plane CreatePlane(PlaneInfo newPlaneInfo)
|
||||
{
|
||||
if(this[newPlaneName] != null)
|
||||
throw new InvalidOperationException($"Error: A plane with the name '{newPlaneName}' already exists in this RippleSpaceManager.");
|
||||
if(this[newPlaneInfo.Name] != null)
|
||||
throw new InvalidOperationException($"Error: A plane with the name '{newPlaneInfo.Name}' already exists in this RippleSpaceManager.");
|
||||
|
||||
Log.WriteLine("[RippleSpace] Creating plane {0}", newPlaneName);
|
||||
Log.WriteLine("[RippleSpace] Creating plane {0}", newPlaneInfo.Name);
|
||||
|
||||
Plane newPlane = new Plane(newPlaneName, DefaultChunkSize);
|
||||
Plane newPlane = new Plane(
|
||||
newPlaneInfo,
|
||||
CalcPaths.UnpackedPlaneDir(UnpackedDirectory, newPlaneInfo.Name)
|
||||
);
|
||||
Planes.Add(newPlane);
|
||||
return newPlane;
|
||||
}
|
||||
|
@ -124,17 +129,29 @@ namespace Nibriboard.RippleSpace
|
|||
Log.WriteLine("[Core] Importing planes");
|
||||
|
||||
StreamReader planes = new StreamReader(rippleSpace.UnpackedDirectory + "index.list");
|
||||
List<Task> planeReaders = new List<Task>();
|
||||
List<Task<Plane>> planeReaders = new List<Task<Plane>>();
|
||||
string nextPlane;
|
||||
int planeCount = 0;
|
||||
while((nextPlane = await planes.ReadLineAsync()) != null)
|
||||
{
|
||||
planeReaders.Add(Plane.FromFile(rippleSpace.UnpackedDirectory + nextPlane));
|
||||
planeReaders.Add(Plane.FromFile(
|
||||
planeName: nextPlane,
|
||||
storageDirectoryRoot: rippleSpace.UnpackedDirectory,
|
||||
sourceFilename: CalcPaths.UnpackedPlaneFile(rippleSpace.UnpackedDirectory, nextPlane),
|
||||
deleteSource: true
|
||||
));
|
||||
planeCount++;
|
||||
}
|
||||
await Task.WhenAll(planeReaders);
|
||||
|
||||
Log.WriteLine("[Core] done!");
|
||||
rippleSpace.Planes.AddRange(
|
||||
planeReaders.Select((Task<Plane> planeReader) => planeReader.Result)
|
||||
);
|
||||
|
||||
Log.WriteLine("[Core] done! {0} planes loaded.", planeCount);
|
||||
|
||||
return rippleSpace;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
namespace Nibriboard
|
||||
|
||||
namespace Nibriboard.Utilities
|
||||
{
|
||||
public static class Utilities
|
||||
public static class BinaryIO
|
||||
{
|
||||
/// <summary>
|
||||
/// Deserialises an object from it's binary representation.
|
40
Nibriboard/Utilities/CalcPaths.cs
Normal file
40
Nibriboard/Utilities/CalcPaths.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
|
||||
namespace Nibriboard.Utilities
|
||||
{
|
||||
public static class CalcPaths
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the directory in which a plane's data should be unpacked to.
|
||||
/// </summary>
|
||||
/// <param name="unpackingRoot">The root directory to which everything is going to be unpacked.</param>
|
||||
/// <param name="planeName">The name of the plane that will be unpacked.</param>
|
||||
/// <returns>The directory to which a plane should unpack it's data to.</returns>
|
||||
public static string UnpackedPlaneDir(string unpackingRoot, string planeName)
|
||||
{
|
||||
string result = $"{unpackingRoot}/Planes/{planeName}/";
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the path to the plane index file given a directory that a plane has been unpacked to.
|
||||
/// </summary>
|
||||
/// <param name="unpackingPlaneDir">The directory to which a plane's data has been unpacked.</param>
|
||||
/// <returns>The path to the plane index file.</returns>
|
||||
public static string UnpackedPlaneIndex(string unpackingPlaneDir)
|
||||
{
|
||||
return $"{unpackingPlaneDir}/plane-index.json";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the path to a packed plane file.
|
||||
/// </summary>
|
||||
/// <param name="unpackingDir">The directory to which the nplane files were unpacked.</param>
|
||||
/// <param name="planeName">The name of the plane to fetch the filepath for.</param>
|
||||
/// <returns>The path to the packed plane file.</returns>
|
||||
public static string UnpackedPlaneFile(string unpackingDir, string planeName)
|
||||
{
|
||||
return $"{unpackingDir}/{planeName}.nplane";
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue