1
0
Fork 0

Fill things out a bit and star working on de/serialisation

This commit is contained in:
Starbeamrainbowlabs 2017-01-07 17:35:56 +00:00
parent 9ccd3239a1
commit 6e894f58fc
6 changed files with 166 additions and 22 deletions

View File

@ -7,7 +7,7 @@
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<RootNamespace>Nibriboard</RootNamespace> <RootNamespace>Nibriboard</RootNamespace>
<AssemblyName>Nibriboard</AssemblyName> <AssemblyName>Nibriboard</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion> <TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@ -40,6 +40,7 @@
<Compile Include="RippleSpace\ChunkReference.cs" /> <Compile Include="RippleSpace\ChunkReference.cs" />
<Compile Include="RippleSpace\DrawnLine.cs" /> <Compile Include="RippleSpace\DrawnLine.cs" />
<Compile Include="RippleSpace\Reference.cs" /> <Compile Include="RippleSpace\Reference.cs" />
<Compile Include="Utilities.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="RippleSpace\" /> <Folder Include="RippleSpace\" />

View File

@ -1,32 +1,34 @@
using System; using System;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Runtime.CompilerServices;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections; using System.Collections;
using System.Runtime.Serialization;
namespace Nibriboard.RippleSpace namespace Nibriboard.RippleSpace
{ {
/// <summary> /// <summary>
/// Represents a single chunk of an infinite <see cref="Nibriboard.RippleSpace.Plane" />. /// Represents a single chunk of an infinite <see cref="Nibriboard.RippleSpace.Plane" />.
/// </summary> /// </summary>
public class Chunk : IEnumerable<DrawnLine> [Serializable]
public class Chunk : IEnumerable<DrawnLine>, IDeserializationCallback
{ {
/// <summary> /// <summary>
/// The lines that this chunk currently contains. /// The lines that this chunk currently contains.
/// </summary> /// </summary>
private List<DrawnLine> lines = new List<DrawnLine>(); private List<DrawnLine> lines = new List<DrawnLine>();
/// <summary>
/// The plane that this chunk is located on.
/// </summary>
public readonly Plane Plane;
/// <summary> /// <summary>
/// The size of this chunk. /// The size of this chunk.
/// </summary> /// </summary>
public readonly int Size; public readonly int Size;
/// <summary>
/// The location of this chunk chunk on the plane.
/// </summary>
public readonly ChunkReference Location;
/// <summary> /// <summary>
/// The time at which this chunk was loaded. /// The time at which this chunk was loaded.
/// </summary> /// </summary>
@ -36,17 +38,80 @@ namespace Nibriboard.RippleSpace
/// </summary> /// </summary>
public DateTime TimeLastAccessed { get; private set; } = DateTime.Now; public DateTime TimeLastAccessed { get; private set; } = DateTime.Now;
public Chunk(Plane inPlane, int inSize) /// <summary>
/// Whether this <see cref="T:Nibriboard.RippleSpace.Chunk"/> is primary chunk.
/// Primary chunks are always loaded.
/// </summary>
public bool IsPrimaryChunk
{
get {
if(Location.X < Location.Plane.PrimaryChunkAreaSize &&
Location.X > -Location.Plane.PrimaryChunkAreaSize &&
Location.Y < Location.Plane.PrimaryChunkAreaSize &&
Location.Y > -Location.Plane.PrimaryChunkAreaSize)
{
return true;
}
return false;
}
}
/// <summary>
/// Whether this chunk is inactive or not.
/// </summary>
/// <remarks>
/// Note that even if a chunk is inactive, it's not guaranteed that
/// it will be unloaded. It's possible that the server will keep it
/// loaded anyway - it could be a primary chunk, or the server may not
/// have many chunks loaded at a particular time.
/// </remarks>
public bool Inactive
{
get {
// If the time we were last accessed + the inactive timer is
// still less than the current time, then we're inactive.
if (TimeLastAccessed.AddMilliseconds(Plane.InactiveMillisecs) < DateTime.Now)
return false;
return true;
}
}
/// <summary>
/// Whether this chunk could, theorectically, be unloaded. Of course,
/// the server may decide it doesn't need to unload us even if we're
/// inactive.
/// </summary>
public bool CouldUnload
{
get {
// If we're a primary chunk or not inactive, then we shouldn't
// unload it.
if (IsPrimaryChunk || !Inactive)
return false;
return true;
}
}
public Chunk(Plane inPlane, int inSize, ChunkReference inLocation)
{ {
Plane = inPlane; Plane = inPlane;
Size = inSize; Size = inSize;
Location = inLocation;
} }
/// <summary>
/// Updates the time the chunk was last accessed, thereby preventing it
/// from becoming inactive.
/// </summary>
public void UpdateAccessTime() public void UpdateAccessTime()
{ {
TimeLastAccessed = DateTime.Now; TimeLastAccessed = DateTime.Now;
} }
#region Enumerator
public DrawnLine this[int i] public DrawnLine this[int i]
{ {
get { get {
@ -70,25 +135,28 @@ namespace Nibriboard.RippleSpace
return GetEnumerator(); return GetEnumerator();
} }
#endregion
#region Serialisation
public static async Task<Chunk> FromFile(Plane plane, string filename) public static async Task<Chunk> FromFile(Plane plane, string filename)
{ {
StreamReader chunkSource = new StreamReader(filename); FileStream chunkSource = new FileStream(filename, FileMode.Open);
return await FromStream(plane, chunkSource); return await FromStream(plane, chunkSource);
} }
public static async Task<Chunk> FromStream(Plane plane, StreamReader chunkSource) public static async Task<Chunk> FromStream(Plane plane, Stream chunkSource)
{ {
Chunk result = new Chunk( Chunk loadedChunk = await Utilities.DeserialiseBinaryObject<Chunk>(chunkSource);
plane, loadedChunk.Plane = plane;
int.Parse(chunkSource.ReadLine())
);
string nextLine = string.Empty; return loadedChunk;
while((nextLine = await chunkSource.ReadLineAsync()) != null)
{
throw new NotImplementedException();
}
return result;
} }
public void OnDeserialization(object sender)
{
UpdateAccessTime();
}
#endregion
} }
} }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Security.Policy; using System.Security.Policy;
using System.IO;
namespace Nibriboard.RippleSpace namespace Nibriboard.RippleSpace
{ {
/// <summary> /// <summary>
@ -34,5 +35,23 @@ namespace Nibriboard.RippleSpace
{ {
return $"{Plane.Name}-{X},{Y}.chunk"; return $"{Plane.Name}-{X},{Y}.chunk";
} }
public static ChunkReference Parse(Plane plane, string source)
{
if (!source.StartsWith("ChunkReference:"))
throw new InvalidDataException($"Error: That isn't a valid chunk reference. Chunk references start with 'ChunkReference:'.");
// Trim the extras off the reference
source = source.Substring("ChunkReference:".Length);
source = source.Trim("() \v\t\r\n".ToCharArray());
int x = source.Substring(0, source.IndexOf(","));
int y = source.Substring(source.IndexOf(",") + 1);
return new ChunkReference(
plane,
x,
y
);
}
} }
} }

View File

@ -10,5 +10,24 @@ namespace Nibriboard.RippleSpace
{ {
} }
public static LocationReference Parse(Plane plane, string source)
{
// TODO: Decide if this is the format that we want to use for location references
if (!source.StartsWith("LocationReference:"))
throw new InvalidDataException($"Error: That isn't a valid location reference. Location references start with 'ChunkReference:'.");
// Trim the extras off the reference
source = source.Substring("LocationReference:".Length);
source = source.Trim("() \v\t\r\n".ToCharArray());
int x = source.Substring(0, source.IndexOf(","));
int y = source.Substring(source.IndexOf(",") + 1);
return new LocationReference(
plane,
x,
y
);
}
} }
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.IO;
namespace Nibriboard.RippleSpace namespace Nibriboard.RippleSpace
{ {
/// <summary> /// <summary>
@ -18,6 +19,23 @@ namespace Nibriboard.RippleSpace
/// </summary> /// </summary>
public readonly int ChunkSize; public readonly int ChunkSize;
/// <summary>
/// The path to the directory that the plane's information will be stored in.
/// </summary>
public readonly string StorageDirectory;
/// <summary>
/// The number of milliseconds that should pass since a chunk's last
/// access in order for it to be considered inactive.
/// </summary>
public int InactiveMillisecs = 60 * 1000;
/// <summary>
/// The number of chunks in a square around (0, 0) that should always be
/// loaded.
/// </summary>
public int PrimaryChunkAreaSize = 10;
/// <summary> /// <summary>
/// The chunkspace that holds the currently loaded and active chunks. /// The chunkspace that holds the currently loaded and active chunks.
/// </summary> /// </summary>
@ -27,6 +45,8 @@ namespace Nibriboard.RippleSpace
{ {
Name = inName; Name = inName;
ChunkSize = inChunkSize; ChunkSize = inChunkSize;
StorageDirectory = $"./Planes/{Name}";
} }
public async Task<Chunk> FetchChunk(ChunkReference chunkLocation) public async Task<Chunk> FetchChunk(ChunkReference chunkLocation)

17
Nibriboard/Utilities.cs Normal file
View File

@ -0,0 +1,17 @@
using System;
using System.Threading.Tasks;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace Nibriboard
{
public static class Utilities
{
public static async Task<T> DeserialiseBinaryObject<T>(Stream sourceStream)
{
return await Task.Run(() => {
BinaryFormatter formatter = new BinaryFormatter();
return (T)formatter.Deserialize(sourceStream);
});
}
}
}