Split tasks and implemented an ID
This commit is contained in:
parent
f0c7980e9f
commit
c8ac4ef579
@ -24,28 +24,39 @@ namespace RBG_Server
|
|||||||
/// Image data is stored in memory in a dictionary collection. Each byte[] represents an image file, compressed according to its file type;
|
/// Image data is stored in memory in a dictionary collection. Each byte[] represents an image file, compressed according to its file type;
|
||||||
/// which helps save space in memory. Uses a CachedByteArray; essentially a normal byte array but automatically stored on disk if it is larger
|
/// which helps save space in memory. Uses a CachedByteArray; essentially a normal byte array but automatically stored on disk if it is larger
|
||||||
/// than a set size.
|
/// than a set size.
|
||||||
/// This limit can be changed at any time
|
/// This limit can be changed at any time, if memory is required to be freed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ConcurrentDictionary<string, CachedByteArray> ImageCollection { get; } = new();
|
public ConcurrentDictionary<string, CachedByteArray> ImageCollection { get; } = new();
|
||||||
|
|
||||||
public List<Player> Players { get; } = new List<Player>();
|
public List<Player> Players { get; } = new List<Player>();
|
||||||
|
|
||||||
public List<string> ImageList { get; } = new();
|
public List<string> ImageList { get; } = new();
|
||||||
|
|
||||||
public string BoardName { get; set; }
|
public string BoardName { get; set; }
|
||||||
|
|
||||||
public IPAddress IpAddress { get; set; }
|
public IPAddress IpAddress { get; set; }
|
||||||
|
|
||||||
public short Port { get; set; }
|
public short Port { get; set; }
|
||||||
|
|
||||||
private TcpClient stateRetriever { get; set; }
|
private TcpClient stateRetriever { get; set; }
|
||||||
|
|
||||||
private TcpClient dataRetriever { get; set; }
|
private TcpClient dataRetriever { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public int ColumnCount { get;private set; }
|
public int ColumnCount { get;private set; }
|
||||||
|
|
||||||
public int RowCount { get;private set; }
|
public int RowCount { get;private set; }
|
||||||
|
|
||||||
public int ColumnZoomStart { get;private set; }
|
public int ColumnZoomStart { get;private set; }
|
||||||
|
|
||||||
public int RowZoomStart { get;private set; }
|
public int RowZoomStart { get;private set; }
|
||||||
|
|
||||||
public int ColumnZoomSpan { get;private set; }
|
public int ColumnZoomSpan { get;private set; }
|
||||||
|
|
||||||
public int RowZoomSpan { get;private set; }
|
public int RowZoomSpan { get;private set; }
|
||||||
|
|
||||||
public int StartingColumn { get;private set; }
|
public int StartingColumn { get;private set; }
|
||||||
|
|
||||||
public int StartingRow { get;private set; }
|
public int StartingRow { get;private set; }
|
||||||
|
|
||||||
public void InitialiseServer()
|
public void InitialiseServer()
|
||||||
@ -73,13 +84,11 @@ namespace RBG_Server
|
|||||||
AcceptConnections(client);
|
AcceptConnections(client);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// At this point, the ImageCollection will have already been initialised.
|
|
||||||
// The name of the board will also be set to <boardname>{0}.<extension>.
|
|
||||||
// Server logic, such as accepting players and maintaining communication goes in here
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AcceptConnections(TcpClient client)
|
private void AcceptConnections(TcpClient client)
|
||||||
{
|
{
|
||||||
|
// Handle actual connections here
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,55 +98,7 @@ namespace RBG_Server
|
|||||||
NetworkStream stateStream = stateRetriever.GetStream();
|
NetworkStream stateStream = stateRetriever.GetStream();
|
||||||
Task stateLoader = new Task(async () =>
|
Task stateLoader = new Task(async () =>
|
||||||
{
|
{
|
||||||
// Get game board details
|
|
||||||
byte[] buffer = new byte[] { 1, 0, 0, 0, 1 };
|
|
||||||
stateStream.Write(buffer, 0, buffer.Length);
|
|
||||||
// Response size
|
|
||||||
var stateResponse = await GetResponse(stateStream, 4);
|
|
||||||
// Response data
|
|
||||||
stateResponse = await GetResponse(stateStream, GetInt32(stateResponse)); // Get the full response data
|
|
||||||
// Board state data
|
|
||||||
int playerID = GetInt32(stateResponse[..4]);
|
|
||||||
ColumnCount = GetInt32(stateResponse[..8]);
|
|
||||||
RowCount = GetInt32(stateResponse[8..12]);
|
|
||||||
ColumnZoomStart = GetInt32(stateResponse[12..16]);
|
|
||||||
RowZoomStart = GetInt32(stateResponse[16..20]);
|
|
||||||
ColumnZoomSpan = GetInt32(stateResponse[20..24]);
|
|
||||||
RowZoomSpan = GetInt32(stateResponse[24..28]);
|
|
||||||
StartingColumn = GetInt32(stateResponse[28..32]);
|
|
||||||
StartingRow = GetInt32(stateResponse[32..36]);
|
|
||||||
// Basic board data loaded; fetch players
|
|
||||||
buffer = new byte[] { 1, 0, 0, 0, 2};
|
|
||||||
stateStream.Write(buffer, 0, buffer.Length);
|
|
||||||
stateResponse = await GetResponse(stateStream, 4);
|
|
||||||
stateResponse = await GetResponse(stateStream, GetInt32(stateResponse));
|
|
||||||
// state response contains a player list;
|
|
||||||
// Player ID (Int32)
|
|
||||||
// Player Name (null-terminated string)
|
|
||||||
// Player Sprite (null-terminated string)
|
|
||||||
// Player Column (Int32)
|
|
||||||
// Player Row (Int32)
|
|
||||||
int start = 0;
|
|
||||||
while (start < stateResponse.Length)
|
|
||||||
{
|
|
||||||
int pos = start + 4;
|
|
||||||
int responsePlayerID = GetInt32(stateResponse[start..pos]);
|
|
||||||
start = pos;
|
|
||||||
while (stateResponse[pos++] != 0); // skip the bytes that aren't null
|
|
||||||
string responsePlayerName = Encoding.UTF8.GetString(stateResponse[start..pos]);
|
|
||||||
start = pos;
|
|
||||||
while (stateResponse[pos++] != 0); // skip the bytes that aren't null
|
|
||||||
string responsePlayerSprite = Encoding.UTF8.GetString(stateResponse[start..pos]);
|
|
||||||
start = pos;
|
|
||||||
pos += 4;
|
|
||||||
int playerColumn = GetInt32(stateResponse[start..pos]);
|
|
||||||
start = pos;
|
|
||||||
pos += 4;
|
|
||||||
int playerRow = GetInt32(stateResponse[start..pos]);
|
|
||||||
start = pos;
|
|
||||||
Player player = new Player(responsePlayerName, responsePlayerSprite, playerRow, playerColumn);
|
|
||||||
Players.Add(player);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -145,41 +106,13 @@ namespace RBG_Server
|
|||||||
NetworkStream dataStream = dataRetriever.GetStream();
|
NetworkStream dataStream = dataRetriever.GetStream();
|
||||||
Task dataLoader = new Task(async () =>
|
Task dataLoader = new Task(async () =>
|
||||||
{
|
{
|
||||||
byte[] buffer = new byte[] { 2, 0, 0, 0, 128, 0 }; // Get image collection names
|
|
||||||
dataStream.Write(buffer, 0, buffer.Length);
|
|
||||||
var dataResponse = await GetResponse(stateStream, 4);
|
|
||||||
|
|
||||||
dataResponse = await GetResponse(dataStream, GetInt32(dataResponse));
|
|
||||||
List<byte> data = new List<byte>();
|
|
||||||
int start = 0;
|
|
||||||
while (start < dataResponse.Length)
|
|
||||||
{
|
|
||||||
int pos = start;
|
|
||||||
while (dataResponse[pos++] != 0);
|
|
||||||
ImageList.Add(Encoding.UTF8.GetString(dataResponse[start..pos]));
|
|
||||||
start = pos;
|
|
||||||
}
|
|
||||||
// Load all low-resolution images
|
|
||||||
foreach (string item in ImageList)
|
|
||||||
{
|
|
||||||
byte[] strBytes = Encoding.ASCII.GetBytes(item);
|
|
||||||
buffer = new byte[strBytes.Length + 6];
|
|
||||||
byte[] lenBytes = GetBytes(strBytes.Length + 6);
|
|
||||||
lenBytes.CopyTo(buffer, 0);
|
|
||||||
buffer[4] = 129; // Download image
|
|
||||||
buffer[5] = 0; // mip_low
|
|
||||||
strBytes.CopyTo(buffer, 6);
|
|
||||||
dataStream.Write(buffer, 0, buffer.Length);
|
|
||||||
// Read the length, then the data
|
|
||||||
dataResponse = await GetResponse(dataStream);
|
|
||||||
dataResponse = await GetResponse(dataStream, GetInt32(dataResponse));
|
|
||||||
ImageCollection.TryAdd(item + "_mip_low", (CachedByteArray)dataResponse);
|
|
||||||
|
|
||||||
}
|
|
||||||
// At this point, the minimal amount of work required by the data thread has been done (load all thumbs)
|
// At this point, the minimal amount of work required by the data thread has been done (load all thumbs)
|
||||||
// When an asset is needed from here, queue a load
|
// When an asset is needed from here, queue a load
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// start the tasks; they should have
|
||||||
|
|
||||||
dataLoader.Start();
|
dataLoader.Start();
|
||||||
stateLoader.Start();
|
stateLoader.Start();
|
||||||
|
|
||||||
@ -202,6 +135,141 @@ namespace RBG_Server
|
|||||||
// Then load the low of each unused image (for quick retrieval)
|
// Then load the low of each unused image (for quick retrieval)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ProgressData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Current activity being processed
|
||||||
|
/// </summary>
|
||||||
|
public enum Activity
|
||||||
|
{
|
||||||
|
Idle,
|
||||||
|
MessageSent,
|
||||||
|
MessageReceived,
|
||||||
|
ProcessingMessage,
|
||||||
|
MessageProcessed,
|
||||||
|
CollectionRecieved,
|
||||||
|
// ----- Image stuffs
|
||||||
|
ImageDownloaded,
|
||||||
|
// ----- Gameplay stuffs
|
||||||
|
Finished,
|
||||||
|
}
|
||||||
|
public Activity CurrentActivity;
|
||||||
|
|
||||||
|
public int Progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialises data loader
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dataStream"></param>
|
||||||
|
/// <param name="progressUpdates"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task InitDataLoader(NetworkStream dataStream, IProgress<ProgressData> progressUpdates)
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[] { 2, 0, 0, 0, 128, 0 }; // Get image collection names
|
||||||
|
dataStream.Write(buffer, 0, buffer.Length);
|
||||||
|
// Notify Data was sent
|
||||||
|
progressUpdates.Report(new ProgressData()
|
||||||
|
{
|
||||||
|
CurrentActivity = ProgressData.Activity.MessageSent,
|
||||||
|
Progress = 0,
|
||||||
|
});
|
||||||
|
var dataResponse = await GetResponse(dataStream, 4);
|
||||||
|
// Notify Data was recieved
|
||||||
|
progressUpdates.Report(new ProgressData()
|
||||||
|
{
|
||||||
|
CurrentActivity = ProgressData.Activity.MessageReceived,
|
||||||
|
Progress = 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
dataResponse = await GetResponse(dataStream, GetInt32(dataResponse));
|
||||||
|
List<byte> data = new List<byte>();
|
||||||
|
int start = 0;
|
||||||
|
while (start < dataResponse.Length)
|
||||||
|
{
|
||||||
|
int pos = start;
|
||||||
|
while (dataResponse[pos++] != 0) ;
|
||||||
|
ImageList.Add(Encoding.UTF8.GetString(dataResponse[start..pos]));
|
||||||
|
start = pos;
|
||||||
|
}
|
||||||
|
// Load all low-resolution images
|
||||||
|
for (int i = 0; i < ImageList.Count; i++)
|
||||||
|
{
|
||||||
|
string item = ImageList[i];
|
||||||
|
byte[] strBytes = Encoding.ASCII.GetBytes(item);
|
||||||
|
buffer = new byte[strBytes.Length + 6];
|
||||||
|
byte[] lenBytes = GetBytes(strBytes.Length + 6);
|
||||||
|
lenBytes.CopyTo(buffer, 0);
|
||||||
|
buffer[4] = 129; // Download image
|
||||||
|
buffer[5] = 0; // mip_low
|
||||||
|
strBytes.CopyTo(buffer, 6);
|
||||||
|
dataStream.Write(buffer, 0, buffer.Length);
|
||||||
|
// Read the length, then the data
|
||||||
|
dataResponse = await GetResponse(dataStream);
|
||||||
|
dataResponse = await GetResponse(dataStream, GetInt32(dataResponse));
|
||||||
|
ImageCollection.TryAdd(item + "_mip_low", (CachedByteArray)dataResponse);
|
||||||
|
progressUpdates.Report(new ProgressData()
|
||||||
|
{
|
||||||
|
CurrentActivity = ProgressData.Activity.MessageReceived,
|
||||||
|
Progress = i,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task InitGameLoader(NetworkStream stateStream, IProgress<ProgressData> progressUpdates)
|
||||||
|
{
|
||||||
|
// Get game board details
|
||||||
|
byte[] buffer = new byte[] { 1, 0, 0, 0, 1 };
|
||||||
|
stateStream.Write(buffer, 0, buffer.Length);
|
||||||
|
// Response size
|
||||||
|
var stateResponse = await GetResponse(stateStream, 4);
|
||||||
|
// Response data
|
||||||
|
stateResponse = await GetResponse(stateStream, GetInt32(stateResponse)); // Get the full response data
|
||||||
|
// Board state data
|
||||||
|
int playerID = GetInt32(stateResponse[..4]);
|
||||||
|
ColumnCount = GetInt32(stateResponse[..8]);
|
||||||
|
RowCount = GetInt32(stateResponse[8..12]);
|
||||||
|
ColumnZoomStart = GetInt32(stateResponse[12..16]);
|
||||||
|
RowZoomStart = GetInt32(stateResponse[16..20]);
|
||||||
|
ColumnZoomSpan = GetInt32(stateResponse[20..24]);
|
||||||
|
RowZoomSpan = GetInt32(stateResponse[24..28]);
|
||||||
|
StartingColumn = GetInt32(stateResponse[28..32]);
|
||||||
|
StartingRow = GetInt32(stateResponse[32..36]);
|
||||||
|
// Basic board data loaded; fetch players
|
||||||
|
buffer = new byte[] { 1, 0, 0, 0, 2 };
|
||||||
|
stateStream.Write(buffer, 0, buffer.Length);
|
||||||
|
stateResponse = await GetResponse(stateStream, 4);
|
||||||
|
stateResponse = await GetResponse(stateStream, GetInt32(stateResponse));
|
||||||
|
// state response contains a player list;
|
||||||
|
// Player ID (Int32)
|
||||||
|
// Player Name (null-terminated string)
|
||||||
|
// Player Sprite (null-terminated string)
|
||||||
|
// Player Column (Int32)
|
||||||
|
// Player Row (Int32)
|
||||||
|
int start = 0;
|
||||||
|
while (start < stateResponse.Length)
|
||||||
|
{
|
||||||
|
|
||||||
|
int pos = start + 4;
|
||||||
|
int responsePlayerID = GetInt32(stateResponse[start..pos]);
|
||||||
|
start = pos;
|
||||||
|
while (stateResponse[pos++] != 0) ; // skip the bytes that aren't null
|
||||||
|
string responsePlayerName = Encoding.UTF8.GetString(stateResponse[start..pos]);
|
||||||
|
start = pos;
|
||||||
|
while (stateResponse[pos++] != 0) ; // skip the bytes that aren't null
|
||||||
|
string responsePlayerSprite = Encoding.UTF8.GetString(stateResponse[start..pos]);
|
||||||
|
start = pos;
|
||||||
|
pos += 4;
|
||||||
|
int playerColumn = GetInt32(stateResponse[start..pos]);
|
||||||
|
start = pos;
|
||||||
|
pos += 4;
|
||||||
|
int playerRow = GetInt32(stateResponse[start..pos]);
|
||||||
|
start = pos;
|
||||||
|
Player player = new Player(responsePlayerName, responsePlayerSprite, playerRow, playerColumn);
|
||||||
|
Players.Add(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Idea is that each response is prefaced by a 4 byte stream length specifier.
|
/// Idea is that each response is prefaced by a 4 byte stream length specifier.
|
||||||
/// This requires a busy wait to achieve, if not all recieved at once.
|
/// This requires a busy wait to achieve, if not all recieved at once.
|
||||||
|
@ -54,9 +54,10 @@ namespace RBG_Server
|
|||||||
|
|
||||||
// public Image sprite; // Sprite is now set as the implementation of this class
|
// public Image sprite; // Sprite is now set as the implementation of this class
|
||||||
|
|
||||||
public Player(string name, string sprite, int row, int column) : base() // Call the base constructor at the same time; inits a Grid()
|
public Player(string name, string sprite, byte[] identifier, int row, int column) : base() // Call the base constructor at the same time; inits a Grid()
|
||||||
{
|
{
|
||||||
PlayerName = name;
|
PlayerName = name;
|
||||||
|
hashCode = identifier;
|
||||||
Sprite = sprite;
|
Sprite = sprite;
|
||||||
Row = row;
|
Row = row;
|
||||||
Column = column;
|
Column = column;
|
||||||
@ -71,20 +72,19 @@ namespace RBG_Server
|
|||||||
|
|
||||||
public new bool Equals(object obj)
|
public new bool Equals(object obj)
|
||||||
{
|
{
|
||||||
return (obj as Player).GetHashCode() == GetHashCode();
|
return (obj as Player).hashCode == hashCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private byte[] hashCode;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// TODO:
|
/// TODO:
|
||||||
/// Replace this with something that is connection-agnostic
|
/// The simplest way to auth a PC is using the computer name.
|
||||||
/// I.e. the combo of name, position, linked sprite etc. should
|
/// We don't need the textual version; just using the hash-code of the PC name is fine
|
||||||
/// allow us to reconnect disconnected players
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public new int GetHashCode()
|
public new int GetHashCode()
|
||||||
{
|
{
|
||||||
int res = (base.GetHashCode() + PlayerName.GetHashCode()) >> 8; // Right-shift the original hashcode by one byte & use our row & column
|
return hashCode.GetHashCode();
|
||||||
int rcByte = ((Row & 0xF) << 4) | (Column & 0xF);
|
|
||||||
return (rcByte << 24) | res;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user