mirror of
https://github.com/sbrl/Nibriboard.git
synced 2018-01-10 21:33:49 +00:00
[server] Continue wiring the ripplespace to nibri client, mainly by implementing the ChunkUpdateRequest message handler and all it's reuqired backend methods & classes.
This commit is contained in:
parent
22a03d9ab9
commit
77ce5b4d71
8 changed files with 244 additions and 13 deletions
93
Nibriboard/Client/ChunkCache.cs
Normal file
93
Nibriboard/Client/ChunkCache.cs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Nibriboard.RippleSpace;
|
||||||
|
|
||||||
|
namespace Nibriboard.Client
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a cache of chunk references. Useful for keeping track which chunks
|
||||||
|
/// a remote party is currently keeping in memory.
|
||||||
|
/// </summary>
|
||||||
|
public class ChunkCache
|
||||||
|
{
|
||||||
|
List<ChunkReference> cache;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new empty chunk cache.
|
||||||
|
/// </summary>
|
||||||
|
public ChunkCache()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a chunk reference to the cache.
|
||||||
|
/// If the chunk is already in the cache, then it won't be added again.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chunkRef">The chunk reference to add.</param>
|
||||||
|
public void Add(ChunkReference chunkRef)
|
||||||
|
{
|
||||||
|
// If this cache already contains the specified chunk reference, then we
|
||||||
|
// probably shouldn't add it to the cache twice
|
||||||
|
if(cache.Contains(chunkRef))
|
||||||
|
return;
|
||||||
|
|
||||||
|
cache.Add(chunkRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the given chunk references to the cache.
|
||||||
|
/// Quietly skips over duplicate chunk references.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chunkRefs">The chunk references to add.</param>
|
||||||
|
public void Add(IEnumerable<ChunkReference> chunkRefs)
|
||||||
|
{
|
||||||
|
foreach(ChunkReference chunkRef in chunkRefs)
|
||||||
|
Add(chunkRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remvoes a chunk reference from the cache.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chunkRef">The chunk reference to remove.</param>
|
||||||
|
public void Remove(ChunkReference chunkRef)
|
||||||
|
{
|
||||||
|
cache.Remove(chunkRef);
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a list of chunk references from the cache.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chunkRefs">The chunk references to remove.</param>
|
||||||
|
public void Remove(IEnumerable<ChunkReference> chunkRefs)
|
||||||
|
{
|
||||||
|
foreach(ChunkReference chunkRef in chunkRefs)
|
||||||
|
Remove(chunkRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether this cache contains the specified chunk reference.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chunkRef">The chunk reference to check for.</param>
|
||||||
|
/// <returns>Whether this cache contaisn the specified chunk reference..</returns>
|
||||||
|
public bool Contains(ChunkReference chunkRef)
|
||||||
|
{
|
||||||
|
return cache.Contains(chunkRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Given a list of chunk references, return another list of chunk references
|
||||||
|
/// that aren't in this chunk cache.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sourceChunkRefs">The list of chunk references to check against this chunk cache.</param>
|
||||||
|
/// <returns>The chunk references missing from this chunk cache.</returns>
|
||||||
|
public List<ChunkReference> FindMissing(IEnumerable<ChunkReference> sourceChunkRefs)
|
||||||
|
{
|
||||||
|
List<ChunkReference> result = new List<ChunkReference>();
|
||||||
|
foreach(ChunkReference sourceChunkRef in sourceChunkRefs)
|
||||||
|
{
|
||||||
|
if(!Contains(sourceChunkRef))
|
||||||
|
result.Add(sourceChunkRef);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
Nibriboard/Client/Messages/ChunkUpdateRequestMessage.cs
Normal file
19
Nibriboard/Client/Messages/ChunkUpdateRequestMessage.cs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Nibriboard.RippleSpace;
|
||||||
|
|
||||||
|
namespace Nibriboard.Client.Messages
|
||||||
|
{
|
||||||
|
public class ChunkUpdateRequestMessage : Message
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A list of chunks that the client has intentionally forgotten about, and will need
|
||||||
|
/// to be resent to the client.
|
||||||
|
/// </summary>
|
||||||
|
public List<ChunkReference> ForgottenChunks = new List<ChunkReference>();
|
||||||
|
|
||||||
|
public ChunkUpdateRequestMessage()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -50,11 +50,11 @@ namespace Nibriboard.Client
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly WebSocket client;
|
private readonly WebSocket client;
|
||||||
|
|
||||||
private static readonly Dictionary<string, Type> messageEventTypes = new Dictionary<string, Type>()
|
private static readonly Dictionary<string, Type> messageEventTypes = new Dictionary<string, Type>() {
|
||||||
{
|
|
||||||
["HandshakeRequest"] = typeof(HandshakeRequestMessage),
|
["HandshakeRequest"] = typeof(HandshakeRequestMessage),
|
||||||
["CursorPosition"] = typeof(CursorPositionMessage),
|
["CursorPosition"] = typeof(CursorPositionMessage),
|
||||||
["PlaneChange"] = typeof(PlaneChangeMessage)
|
["PlaneChange"] = typeof(PlaneChangeMessage),
|
||||||
|
["ChunkUpdateRequest"] = typeof(ChunkUpdateRequestMessage)
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -105,6 +105,11 @@ namespace Nibriboard.Client
|
||||||
/// This client's colour. Used to tell multiple clients apart visually.
|
/// This client's colour. Used to tell multiple clients apart visually.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly ColourHSL Colour = ColourHSL.RandomSaturated();
|
public readonly ColourHSL Colour = ColourHSL.RandomSaturated();
|
||||||
|
/// <summary>
|
||||||
|
/// The chunk cache. Keeps track of which chunks this client currently has.
|
||||||
|
/// </summary>
|
||||||
|
protected ChunkCache chunkCache = new ChunkCache();
|
||||||
|
|
||||||
|
|
||||||
#region Core Setup & Message Routing Logic
|
#region Core Setup & Message Routing Logic
|
||||||
|
|
||||||
|
@ -167,6 +172,7 @@ namespace Nibriboard.Client
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Message Sending
|
#region Message Sending
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -245,6 +251,7 @@ namespace Nibriboard.Client
|
||||||
return chunkArea.Overlap(CurrentViewPort);
|
return chunkArea.Overlap(CurrentViewPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#region Message Handlers
|
#region Message Handlers
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles an incoming handshake request. We should only receive one of these!
|
/// Handles an incoming handshake request. We should only receive one of these!
|
||||||
|
@ -289,6 +296,21 @@ namespace Nibriboard.Client
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async Task handleChunkUpdateRequestMessage(ChunkUpdateRequestMessage message)
|
||||||
|
{
|
||||||
|
chunkCache.Remove(message.ForgottenChunks);
|
||||||
|
|
||||||
|
ChunkUpdateMessage response = new ChunkUpdateMessage();
|
||||||
|
List<ChunkReference> missingChunks = ChunkTools.GetContainingChunkReferences(CurrentPlane, CurrentViewPort);
|
||||||
|
missingChunks = chunkCache.FindMissing(missingChunks);
|
||||||
|
|
||||||
|
response.Chunks = await CurrentPlane.FetchChunks(missingChunks);
|
||||||
|
|
||||||
|
Send(response);
|
||||||
|
|
||||||
|
chunkCache.Add(missingChunks);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles an incoming cursor position message from the client..
|
/// Handles an incoming cursor position message from the client..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -303,8 +325,10 @@ namespace Nibriboard.Client
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates an update message that contains information about the locations and states of all connected clients.
|
/// Generates an update message that contains information about the locations and states of all connected clients.
|
||||||
/// Automatically omits information about the current client, and clients on other planes.
|
/// Automatically omits information about the current client, and clients on other planes.
|
||||||
|
|
|
@ -92,6 +92,9 @@
|
||||||
<Compile Include="Client\Messages\ChunkUpdateMessage.cs" />
|
<Compile Include="Client\Messages\ChunkUpdateMessage.cs" />
|
||||||
<Compile Include="Client\Messages\PlaneChangeMessage.cs" />
|
<Compile Include="Client\Messages\PlaneChangeMessage.cs" />
|
||||||
<Compile Include="Client\Messages\ExceptionMessage.cs" />
|
<Compile Include="Client\Messages\ExceptionMessage.cs" />
|
||||||
|
<Compile Include="Utilities\ChunkTools.cs" />
|
||||||
|
<Compile Include="Client\Messages\ChunkUpdateRequestMessage.cs" />
|
||||||
|
<Compile Include="Client\ChunkCache.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="ClientFiles\index.html" />
|
<EmbeddedResource Include="ClientFiles\index.html" />
|
||||||
|
|
|
@ -9,6 +9,9 @@ namespace Nibriboard.RippleSpace
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class LocationReference : Reference
|
public class LocationReference : Reference
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The chunk that this location reference fall inside.
|
||||||
|
/// </summary>
|
||||||
public ChunkReference ContainingChunk {
|
public ChunkReference ContainingChunk {
|
||||||
get {
|
get {
|
||||||
return new ChunkReference(
|
return new ChunkReference(
|
||||||
|
|
|
@ -49,6 +49,18 @@ namespace Nibriboard.RippleSpace
|
||||||
|
|
||||||
StorageDirectory = $"./Planes/{Name}";
|
StorageDirectory = $"./Planes/{Name}";
|
||||||
}
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Fetches a list of chunks by a list of chunk refererences.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chunkRefs">The chunk references to fetch the attached chunks for.</param>
|
||||||
|
/// <returns>The chunks attached to the specified chunk references.</returns>
|
||||||
|
public async Task<List<Chunk>> FetchChunks(List<ChunkReference> chunkRefs)
|
||||||
|
{
|
||||||
|
List<Chunk> chunks = new List<Chunk>();
|
||||||
|
foreach(ChunkReference chunkRef in chunkRefs)
|
||||||
|
chunks.Add(await FetchChunk(chunkRef));
|
||||||
|
return chunks;
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<Chunk> FetchChunk(ChunkReference chunkLocation)
|
public async Task<Chunk> FetchChunk(ChunkReference chunkLocation)
|
||||||
{
|
{
|
||||||
|
|
45
Nibriboard/Utilities/ChunkTools.cs
Normal file
45
Nibriboard/Utilities/ChunkTools.cs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Nibriboard.RippleSpace;
|
||||||
|
using SBRL.Utilities;
|
||||||
|
|
||||||
|
namespace SBRL.Utilities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A collection of tools aid in the manipulation of chunks.
|
||||||
|
/// </summary>
|
||||||
|
public static class ChunkTools
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a list of chunk references that cross inside the specified rectangle.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="plane">The plane to operate on.</param>
|
||||||
|
/// <param name="area">The rectangle to find the containing chunks for.</param>
|
||||||
|
/// <returns>All the chunk references that fall inside the specified area.</returns>
|
||||||
|
public static List<ChunkReference> GetContainingChunkReferences(Plane plane, Rectangle area)
|
||||||
|
{
|
||||||
|
List<ChunkReference> result = new List<ChunkReference>();
|
||||||
|
|
||||||
|
Vector2 currentLocation = area.TopLeft;
|
||||||
|
while(currentLocation.X < area.BottomRight.X &&
|
||||||
|
currentLocation.Y < area.BottomRight.Y)
|
||||||
|
{
|
||||||
|
result.Add(new ChunkReference(
|
||||||
|
plane,
|
||||||
|
currentLocation.X,
|
||||||
|
currentLocation.Y
|
||||||
|
));
|
||||||
|
|
||||||
|
currentLocation.X += plane.ChunkSize;
|
||||||
|
|
||||||
|
if(currentLocation.X > area.Right)
|
||||||
|
{
|
||||||
|
currentLocation.X = area.Left;
|
||||||
|
currentLocation.Y += plane.ChunkSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -39,36 +39,36 @@ namespace SBRL.Utilities
|
||||||
/// The top-left corner of the rectangle.
|
/// The top-left corner of the rectangle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public Point TopLeft {
|
public Vector2 TopLeft {
|
||||||
get {
|
get {
|
||||||
return new Point(X, Y);
|
return new Vector2(X, Y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The top-right corner of the rectangle.
|
/// The top-right corner of the rectangle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public Point TopRight {
|
public Vector2 TopRight {
|
||||||
get {
|
get {
|
||||||
return new Point(X + Width, Y);
|
return new Vector2(X + Width, Y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The bottom-left corner of the rectangle.
|
/// The bottom-left corner of the rectangle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public Point BottomLeft {
|
public Vector2 BottomLeft {
|
||||||
get {
|
get {
|
||||||
return new Point(X, Y + Height);
|
return new Vector2(X, Y + Height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The bottom-right corner of the rectangle.
|
/// The bottom-right corner of the rectangle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public Point BottomRight {
|
public Vector2 BottomRight {
|
||||||
get {
|
get {
|
||||||
return new Point(X + Width, Y + Height);
|
return new Vector2(X + Width, Y + Height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -82,6 +82,9 @@ namespace SBRL.Utilities
|
||||||
get {
|
get {
|
||||||
return Y;
|
return Y;
|
||||||
}
|
}
|
||||||
|
set {
|
||||||
|
Y = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The Y coordinate of the bottom of the rectangle.
|
/// The Y coordinate of the bottom of the rectangle.
|
||||||
|
@ -91,6 +94,9 @@ namespace SBRL.Utilities
|
||||||
get {
|
get {
|
||||||
return Y + Height;
|
return Y + Height;
|
||||||
}
|
}
|
||||||
|
set {
|
||||||
|
Height = value - Y;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The X coordinate of the left side of the rectangle.
|
/// The X coordinate of the left side of the rectangle.
|
||||||
|
@ -100,6 +106,9 @@ namespace SBRL.Utilities
|
||||||
get {
|
get {
|
||||||
return X;
|
return X;
|
||||||
}
|
}
|
||||||
|
set {
|
||||||
|
X = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The X coordinate of the right side of the rectangle.
|
/// The X coordinate of the right side of the rectangle.
|
||||||
|
@ -109,6 +118,9 @@ namespace SBRL.Utilities
|
||||||
get {
|
get {
|
||||||
return X + Width;
|
return X + Width;
|
||||||
}
|
}
|
||||||
|
set {
|
||||||
|
Width = value - X;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -135,6 +147,26 @@ namespace SBRL.Utilities
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a Rectangle representing the area that this rectangle overlaps with another.
|
||||||
|
/// Returns an empty rectangle if the two don't overlap at all.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="otherRectangle">The other rectangle that overlaps this one.</param>
|
||||||
|
/// <returns>The area that this rectanagle overlaps with another.</returns>
|
||||||
|
public Rectangle OverlappingArea(Rectangle otherRectangle)
|
||||||
|
{
|
||||||
|
if(!Overlap(otherRectangle))
|
||||||
|
return Rectangle.Zero;
|
||||||
|
|
||||||
|
Rectangle result = new Rectangle();
|
||||||
|
result.Top = Math.Max(Top, otherRectangle.Top);
|
||||||
|
result.Left = Math.Max(Left, otherRectangle.Left);
|
||||||
|
result.Bottom = Math.Max(Bottom, otherRectangle.Bottom);
|
||||||
|
result.Right = Math.Max(Right, otherRectangle.Right);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue