Reputation: 61
I am trying to learn about sockets in C# and decided to create a multiplayer game for practice. While I have gotten quite far in the socket sending, I'm having a strange problem with a boolean always turning true after receiving and deserializing my class from the other client.
The problem arises here:
void OnDataReceived(object sender, ConnectionEventArgs e)
{
Connection con = (Connection)e.SyncResult.AsyncState;
Game.ScoreBoard[currentPlayer] = Serializer.ToScoreCard(con.buffer); //Here
...
}
Game.ScoreBoard[currentPlayer].Local always becomes true, and I'm not sure at all what the problem is. The other values seem to work fine. Connection is a class containing IP, sockets and manages connections and so on. Buffer size is currently 30 000, as I tried enlarging it to make sure that wasn't the problem.
Here's relevant info from the class:
public ScoreCard(SerializationInfo info, StreamingContext context)
{
name = (string)info.GetValue("Name", typeof(string));
played = (bool[])info.GetValue("Played", typeof(bool[]));
scores = (int[])info.GetValue("Scores", typeof(int[]));
bonusScore = (int)info.GetValue("bonusScore", typeof(int));
local = (bool)info.GetValue("Local", typeof(bool));
}
And
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Scores", scores, typeof(int[]));
info.AddValue("Played", played, typeof(bool[]));
info.AddValue("Name", name, typeof(string));
info.AddValue("bonusScore", bonusScore, typeof(int));
info.AddValue("Local", local, typeof(bool));
}
And here is the serializer class:
static class Serializer
{
public static byte[] ToArray(object data)
{
MemoryStream stream = new MemoryStream();
BinaryFormatter b = new BinaryFormatter();
b.Serialize(stream, data);
return stream.ToArray();
}
public static ScoreCard ToScoreCard(byte[] data)
{
ScoreCard sc;
MemoryStream stream = new MemoryStream(data);
BinaryFormatter b = new BinaryFormatter();
sc = (ScoreCard)b.Deserialize(stream);
return sc;
}
}
I have no idea what to do, or even if the information provided is enough for you to be able to solve my problem. If necessary, I could provide more information. I just find it strange that seemingly only that boolean is unable to work correctly.
Edit: I found the problem and, as usual, it was a simple stupid mistake. oh well, I learnt to make my own binaryformatters at least. Thanks guys :)
Upvotes: 2
Views: 691
Reputation: 2678
The performance of BinaryFormatter is terrible. Every object it serializes has a ton of overhead, and in my experience a formatter that takes > 40 seconds to serialize an object in binary can be done in < 1 second by a custom binary writer.
You might want to consider this:
static class Serializer
{
public static byte[] MakePacket(ScoreCard data)
{
MemoryStream stream = new MemoryStream();
using (StreamWriter sw = new StreamWriter(stream)) {
sw.Write(1); // This indicates "version one" of your data format - you can modify the code to support multiple versions by using this
sw.Write(data.Name);
sw.Write(data.scores.Length);
foreach (int score in data.scores) {
sw.Write(score);
}
sw.Write(data.played.Length);
foreach (bool played in data.played) {
sw.Write(played );
}
sw.Write(data.bonusScore);
sw.Write(data.local);
}
return stream.ToArray();
}
public static ScoreCard ReadPacket(byte[] data)
{
ScoreCard sc = new ScoreCard();
MemoryStream stream = new MemoryStream(data);
using (StreamReader sr = new StreamReader(stream)) {
int ver = sr.ReadInt32();
switch (ver) {
case 1:
sc.name = sr.ReadString();
sc.scores = new int[sr.ReadInt32()];
for (int i = 0; i < sc.scores.Length; i++) {
sc.scores[i] = sr.ReadInt32();
}
sc.played = new bool[sr.ReadInt32()];
for (int i = 0; i < sc.scores.Length; i++) {
sc.played [i] = sr.ReadBool();
}
sc.BonusScore = sr.ReadInt32();
sc.Local = sr.ReadBool();
break;
default:
throw new Exception("Unrecognized network protocol");
}
}
return sc;
}
}
Upvotes: 1