using System;
using System.Collections.Generic;
using RidR.Exceptions;
using RidR.Extensions;
namespace RidR.Protocol
{
///
/// The type of the message recieved from the client.
///
public enum ClientMessageType
{
///
/// The PLAY command is send by a bot when regestering his team position:
/// PLAY [TeamName] [TeamRole]
///
Play,
///
/// The STARTPOS command is send by a bot when picking a starting location:
/// STARTPOS [PositionID] [xPos] [yPos] [Orientation]
///
StartPosition,
///
/// A MOVE command is send by a bot who wishes to move:
/// MOVE [Action] [MoveCode]
///
Move,
///
/// A SHOOT command is send by a bot firing his laser:
/// SHOOT [Range] [MoveCode]
///
Shoot,
///
/// A SPECTATE command, send by a visualizer:
/// SPECTATE
///
Spectate,
///
/// The command is not a RidR protocol command.
///
UnknownCommand
}
///
/// This class provides static methodes to help you format server messages and interpret client messages.
///
public static class ServerProtocolHelper
{
#region Reading Client Messages
///
/// Reads the message and determines the command.
///
/// The message string
/// The arguments passed with the message
/// Returns if the message was formated correctly
/// The type of the message
public static ClientMessageType GetMessageType(string message,
out string[] args,
out bool valid)
{
if (!String.IsNullOrWhiteSpace(message))
{
string[] split = message.Split();
args = split.RemoveAt(0);
switch (split[0])
{
case CommonProtocol.PLAY:
valid = args.Length == 2;
return ClientMessageType.Play;
case CommonProtocol.STARTPOS:
valid = args.Length == 4;
return ClientMessageType.StartPosition;
case CommonProtocol.MOVE:
valid = args.Length == 2;
return ClientMessageType.Move;
case CommonProtocol.SHOOT:
valid = args.Length == 2;
return ClientMessageType.Shoot;
case CommonProtocol.SPECTATE:
valid = true;
return ClientMessageType.Spectate;
}
}
args = new string[] { message };
valid = false;
return ClientMessageType.UnknownCommand;
}
///
/// Interprets the arguments of a PLAY command.
///
/// Argument list for the Play command.
/// The team name
/// The team role
/// Thrown when the args parameter does not conform to the RidR protocol.
public static void ReadPlayCommand(string[] args,
out string teamName,
out TeamRole role)
{
try
{
teamName = args[0];
role = (TeamRole)int.Parse(args[1]);
}
catch
{
throw new ProtocolException();
}
}
///
/// Interprets the arguments of a STARTPOS command.
///
/// Argument list for the Start Position command.
/// The ID of the start position set
/// The position
/// The desired starting orientation
/// Thrown when the args parameter does not conform to the RidR protocol.
public static void ReadStartPosCommand(string[] args,
out int PositionID,
out Position position,
out Orientation orientation)
{
try
{
PositionID = int.Parse(args[0]);
int xPos = int.Parse(args[1]);
int yPos = int.Parse(args[2]);
position = new Position(xPos, yPos);
orientation = (Orientation)int.Parse(args[3]);
}
catch
{
throw new ProtocolException();
}
}
///
/// Interprets the arguments of a MOVE command.
///
/// Argument list for the Move command.
/// The desired move
/// The move code
/// Thrown when the args parameter does not conform to the RidR protocol.
public static void ReadMoveCommand(string[] args,
out Move move,
out int moveCode)
{
try
{
move = (Move)int.Parse(args[0]);
moveCode = int.Parse(args[1]);
}
catch
{
throw new ProtocolException();
}
}
///
/// Interprets the arguments of a SHOOT command
///
/// Argument list for the Shoot command.
/// The desired range
/// The move code
/// Thrown when the args parameter does not conform to the RidR protocol.
public static void ReadShootCommand(string[] args,
out int range,
out int moveCode)
{
try
{
range = int.Parse(args[0]);
moveCode = int.Parse(args[1]);
}
catch
{
throw new ProtocolException();
}
}
#endregion
#region Format Server Messages
///
/// Formats an ACK message.
///
public static string FormatAcknowledgeCommand()
{
return CommonProtocol.ACK;
}
///
/// Formats a NAK message.
///
public static string FormatNotAcknowledgedCommand()
{
return CommonProtocol.NAK;
}
///
/// Formats a TEAM message (for clients).
///
/// Number of teams
/// ID of this team
public static string FormatTeamCommand(int TeamCount, int TeamNumber)
{
return CommonProtocol.TEAM + " " + TeamCount + " " + TeamNumber;
}
///
/// Formats a TEAM message (for spectators).
///
/// The name of the team
/// ID of this team
public static string FormatTeamCommand(string TeamName, int TeamNumber)
{
return CommonProtocol.TEAM + " " + TeamName + " " + TeamNumber;
}
///
/// Formats an INFO command.
///
/// Total time of this round in seconds
/// The radius in which clients can see
/// The amount of time it takes to charge 10 points of energy in milliseconds
/// The amount of time a laser persists in milliseconds
/// The amount of time a bot is stunned when hit in milliseconds
public static string FormatInfoCommand(int roundTime, int sightRadius, int chargeTime, int shootTime, int stunTime)
{
return CommonProtocol.INFO + " " + roundTime + " " + sightRadius + " " + chargeTime + " " + shootTime + " " + stunTime;
}
///
/// Formats a MAP command, consisting of a list of messages.
///
/// The current game map
public static string[] FormatMapCommandList(TileType[,] map)
{
List sTiles = new List();
int width = map.GetLength(0);
int height = map.GetLength(1);
for (int x = 0; x < width; ++x)
{
for (int y = 0; y < height; ++y)
{
if (map[x, y] != TileType.Floor)
{
string tileString = map[x, y].toChar() + " " + x + " " + y;
sTiles.Add(tileString);
}
}
}
int listCount = sTiles.Count;
string[] commandList = new string[listCount + 1];
commandList[0] = CommonProtocol.MAP + " " + width + " " + height + " " + listCount;
for (int i = 0; i < listCount; ++i)
{
commandList[i + 1] = sTiles[i];
}
return commandList;
}
///
/// Formats a STARTPOS command, consisting of a list of messages.
///
/// A list of possible start position sets
public static string[] FormatStartPositionCommandList(IList startList)
{
// Met dank aan Matthijs
int count = startList.Count;
string[] commandList = new string[count * 3 + 1];
commandList[0] = CommonProtocol.STARTPOS + " " + count;
int i = 1;
foreach (StartPositionSet sps in startList)
{
commandList[i++] = sps.PositionID + " " + sps.P1.ToString();
commandList[i++] = sps.PositionID + " " + sps.P2.ToString();
commandList[i++] = sps.PositionID + " " + sps.P3.ToString();
}
return commandList;
}
///
/// Formats a FALSE command.
///
public static string FormatFalseCommand()
{
return CommonProtocol.FALSE;
}
///
/// Formats a DISQUALIFIED command (for clients).
///
public static string FormatDisqualifiedCommand()
{
return CommonProtocol.DISQUALIFIED;
}
///
/// Formats a DISQUALIFIED command (for spectators).
///
/// The ID of the robot being disqualified
public static string FormatDisqualifiedCommand(int robotCode)
{
return CommonProtocol.DISQUALIFIED + " " + robotCode;
}
///
/// Formats a START command.
///
/// The first move code for this bot
public static string FormatStartCommand(int moveCode)
{
return CommonProtocol.START + " " + moveCode;
}
///
/// Formats a GAMESTATE command.
///
/// The move code for the bot's next move
/// A list of all the robots visable to the current bot, or, if this message is for a spectator, a list of all the bots in the game
/// A list of laser ranges which fall within the current bot's sight radius, or, if this message is for a spectator, a list of all the active lasers
/// A list of new scores since the last gamestate update
/// A list of hits on the current bot, or, if this message is for a spectator, a list of all hits throughout the game
/// Wheter this update is meant for a spectator
public static string[] FormatGameStateCommandList(int moveCode,
IList visableRobots,
IList visableLasers,
IList scores,
IList hits,
bool forSpectator = false)
{
int count = visableRobots.Count + visableLasers.Count + scores.Count + hits.Count;
string[] commandList = new string[count + 1];
commandList[0] = CommonProtocol.GAMESTATE + " " + count + " " + moveCode;
int c = 1;
for (int i = 0; i < visableRobots.Count; ++i)
{
commandList[c++] = CommonProtocol.ROBOT + " " + visableRobots[i].BotCode + " " + visableRobots[i].Position.ToString() + " " + (int)visableRobots[i].Orientation;
}
for (int i = 0; i < visableLasers.Count; ++i)
{
commandList[c++] = CommonProtocol.LASER + " " + visableLasers[i].ToString();
}
for (int i = 0; i < scores.Count; ++i)
{
commandList[c++] = CommonProtocol.CRYSTAL + " " + scores[i].ToString(); ;
}
for (int i = 0; i < hits.Count; ++i)
{
if (forSpectator)
{
commandList[c++] = CommonProtocol.HIT + " " + hits[i].BotCode;
}
else
{
commandList[c++] = CommonProtocol.HIT + " " + hits[i].RemainingStun;
}
}
return commandList;
}
///
/// Formats a WIN command.
///
/// ID of the winning team
public static string FormatWinCommand(int winningTeamId)
{
return CommonProtocol.WIN + " " + winningTeamId;
}
///
/// Formats a SCORE command.
///
/// Final score of team 1
/// Final score of team 2
/// Final score of team 3
/// Final score of team 4
public static string FormatScoreCommand(int scoreTeam1, int scoreTeam2, int scoreTeam3, int scoreTeam4)
{
return CommonProtocol.SCORE + " " + scoreTeam1 + " " + scoreTeam2 + " " + scoreTeam3 + " " + scoreTeam4;
}
///
/// Formats a GAMETIME command.
///
/// Amount of time this round lasted in ms
public static string FormatGameTimeCommand(int gameTime)
{
return CommonProtocol.GAMETIME + " " + gameTime;
}
///
/// Formats a FIRSTTOSCORE command.
///
/// ID of the team
/// Amount of time it took to score in ms
public static string FormatFirstToScoreCommand(int teamID, int gameTime)
{
return CommonProtocol.FIRSTTOSCORE + " " + teamID + " " + gameTime;
}
///
/// Formats a ROBOTSTAT command.
///
/// The robot ID
/// Messges per minute
/// Distance traveled by this bot
/// The amount of lasers fired by this bot
/// Amount of bots hit by this bot's lasers
/// Amount of times this bot was hit by a laser
public static string FormatRobotStatCommand(int robotCode, float msgPerMin, int distanceTraveled, int lasersFired, int botsHit, int beenHit)
{
return CommonProtocol.ROBOTSTAT + " " + robotCode + " " + msgPerMin + " " + distanceTraveled + " " + lasersFired + " " + botsHit + " " + beenHit;
}
#endregion
}
}