I have a strange problem. I'm currently working on a Pong game, and I
want to add a multiplayer support / feature. First I made the whole
networking with strings (it's an old story, my friend wrote a net lib,
supports only strings, and he told me, to try it...). It worked fine
in most of the cases, but it was too slow, but I used strings only
because the compatibility (with the previous net lib) and I thought if
I change strings to dotNet types it'll work fine. I changed.
But then, it made a lot of strange things. I can connect to the
server, or if I'm the server the client can connect to me, but when I
start to send messages through Sequenced1 most of the cases I get an
error:
System.IndexOutOfRangeException: Index was outside the bounds of the
array.
at Lidgren.Library.Network.NetBitStreamUtil.ReadBytes(Byte[]
fromBuffer, Int32 numberOfBytes, Int32 readBitOffset, Byte[]
destination, Int32 destinationByteOffset)
at Lidgren.Library.Network.NetBuffer.ReadBytes(Int32 numberOfBytes)
at Lidgren.Library.Network.NetBuffer.ReadFloat()
at Lidgren.Library.Network.NetBuffer.ReadSingle()
at Lidgren.Library.Network.NetMessage.ReadSingle()
...
And when I get this error, it's always the first "game
message" (contains positions and vectors). In addition to this, the
game works sometimes! And during the game this error newer happens!
I'm totally at a loss...
> I have a strange problem. I'm currently working on a Pong game, and I
> want to add a multiplayer support / feature. First I made the whole
> networking with strings (it's an old story, my friend wrote a net lib,
> supports only strings, and he told me, to try it...). It worked fine
> in most of the cases, but it was too slow, but I used strings only
> because the compatibility (with the previous net lib) and I thought if
> I change strings to dotNet types it'll work fine. I changed.
> But then, it made a lot of strange things. I can connect to the
> server, or if I'm the server the client can connect to me, but when I
> start to send messages through Sequenced1 most of the cases I get an
> error:
> System.IndexOutOfRangeException: Index was outside the bounds of the
> array.
> at Lidgren.Library.Network.NetBitStreamUtil.ReadBytes(Byte[]
> fromBuffer, Int32 numberOfBytes, Int32 readBitOffset, Byte[]
> destination, Int32 destinationByteOffset)
> at Lidgren.Library.Network.NetBuffer.ReadBytes(Int32 numberOfBytes)
> at Lidgren.Library.Network.NetBuffer.ReadFloat()
> at Lidgren.Library.Network.NetBuffer.ReadSingle()
> at Lidgren.Library.Network.NetMessage.ReadSingle()
> ...
> And when I get this error, it's always the first "game
> message" (contains positions and vectors). In addition to this, the
> game works sometimes! And during the game this error newer happens!
> I'm totally at a loss...
First, thank you to the fast replay. Second, the code is:
public static void CollectToMessage(ref NetMessage ref_msg,
byte in_message_code)
{
PongGame.Log.WriteLine("CollecToMessage");
// player's name
ref_msg = new NetMessage();
ref_msg.Write(in_message_code);
ref_msg.Write((float)NetTime.Now);
//ref_msg.WriteSignedSingle((Single)NetTime.Now, 32);
if (GameDatas.PlayerType == ePlayers.One)
{
// bet positions (left and back) and velocities (left)
(only x and z coords)
XnaSerialization.Write(ref_msg, new
Vector4(mp_bet_left_z, mp_bet_back_x, mp_bet_left_velocity.X,
mp_bet_left_velocity.Z));
// bet velocities (back) and ball pos(x, z)
XnaSerialization.Write(ref_msg, new
Vector4(mp_bet_back_velocity.X, mp_bet_back_velocity.Z,
mp_ball_position.X, mp_ball_position.Z));
// ball velocity (x,z) + slave velocity (x, z)
XnaSerialization.Write(ref_msg, new
Vector4(mp_ball_velocity.X, mp_ball_velocity.Z,
mp_ball_slave_velocity.X, mp_ball_slave_velocity.Z));
/*_ret +=
string.Format(PongGame.SpecParser.FormatProvider, "{0}|{1}|{2}|{3}|{4}|
{5}",
mp_ball_position.X, mp_ball_position.Z,
mp_ball_velocity.X, mp_ball_velocity.Z,
mp_ball_slave_velocity.X,
mp_ball_slave_velocity.Z);*/
}
else
{
// bet positions (right(z) and front(x))
XnaSerialization.Write(ref_msg, new
Vector2(mp_bet_right_z, mp_bet_front_x));
// bet velocities (right and front) (only x and z
coords)
XnaSerialization.Write(ref_msg, new
Vector4(mp_bet_right_velocity.X, mp_bet_right_velocity.Z,
mp_bet_front_velocity.X, mp_bet_front_velocity.Z));
}
vec4 = XnaSerialization.ReadVector4(m_game_datas);
mp_ball_velocity.X = vec4.X;
mp_ball_velocity.Z = vec4.Y;
mp_ball_velocity.Y = 0.0f;
mp_ball_slave_velocity.X = vec4.Z;
mp_ball_slave_velocity.Z = vec4.W;
mp_ball_slave_velocity.Y = 0.0f;
}
}
Comment: I use my system like this: every game-update calls the
network.update -> it gets the messages and if it's not a game-message,
it do it in that update (e.g. a client disconnected message, or a
client connection request message, ...; they come in the
NetChannel.Ordered1) If it's a game-message (NetChannel.Sequenced1),
the network class gets a Single -> it's the time lable. If it's the
last message (biggest time label) it store it in a cache variable (the
whole NetMessage), and in the end of the network.update process the
last (cached) game-message (only the last). And here comes the
UpdateDatasFromMessage call, which get the NetMessage, and then read
the vectors from it and store in a shadred GameDatas class -> then the
game can refresh the game object datas from this shared GameDatas
class.
Anyway, the sending of the game datas is this way: every game.update
calls network.sendGameDatas, but it sends the game datas only if the
timer allow it (now it's 70ms -> about 14 times/sec). When it sends
the datas, it calls the CollectToMessage function, which gets the
datas from the shared GameDatas class (it's updated in every
game.update, because it's used in the collision detection too).
A game-message looks like: 1byte code (every type of the messages have
a non-zero code, game-message's code is: 1), 4 bytes (float) time-
label, and then the datas (it depends on the type of the player, a
server gets less datas and sends more datas, bacause the server watchs
not only the server-player's bets but the ball as well).
I made a logs every time (with client and with server too), and it
writes that the client sends 29 bytes and the server gets 29 bytes,
and that's why I'm totally lost, because the message is correct, and I
don't read more then I wrote.
But the strangest thing is that this is sometimes works! If it never
works i think i made something wrong, I read too much from the message
I sent, but it sometimes fine...
The code looks good; but i noticed you're writing/reading different
amount of data depending on
the PlayerType enum - could it be this variable gets out of sync
between coupled read/writes?
Also, I recommend using msg.WriteSendStamp() and msg.ReadSentStamp()
since
NetTime.Now only returns local time, which cannot be compared upon
receiving.
> vec4 = XnaSerialization.ReadVector4(m_game_datas);
> mp_ball_velocity.X = vec4.X;
> mp_ball_velocity.Z = vec4.Y;
> mp_ball_velocity.Y = 0.0f;
> mp_ball_slave_velocity.X = vec4.Z;
> mp_ball_slave_velocity.Z = vec4.W;
> mp_ball_slave_velocity.Y = 0.0f;
> }
> }
> Comment: I use my system like this: every game-update calls the
> network.update -> it gets the messages and if it's not a game-message,
> it do it in that update (e.g. a client disconnected message, or a
> client connection request message, ...; they come in the
> NetChannel.Ordered1) If it's a game-message (NetChannel.Sequenced1),
> the network class gets a Single -> it's the time lable. If it's the
> last message (biggest time label) it store it in a cache variable (the
> whole NetMessage), and in the end of the network.update process the
> last (cached) game-message (only the last). And here comes the
> UpdateDatasFromMessage call, which get the NetMessage, and then read
> the vectors from it and store in a shadred GameDatas class -> then the
> game can refresh the game object datas from this shared GameDatas
> class.
> Anyway, the sending of the game datas is this way: every game.update
> calls network.sendGameDatas, but it sends the game datas only if the
> timer allow it (now it's 70ms -> about 14 times/sec). When it sends
> the datas, it calls the CollectToMessage function, which gets the
> datas from the shared GameDatas class (it's updated in every
> game.update, because it's used in the collision detection too).
> A game-message looks like: 1byte code (every type of the messages have
> a non-zero code, game-message's code is: 1), 4 bytes (float) time-
> label, and then the datas (it depends on the type of the player, a
> server gets less datas and sends more datas, bacause the server watchs
> not only the server-player's bets but the ball as well).
> I made a logs every time (with client and with server too), and it
> writes that the client sends 29 bytes and the server gets 29 bytes,
> and that's why I'm totally lost, because the message is correct, and I
> don't read more then I wrote.
> But the strangest thing is that this is sometimes works! If it never
> works i think i made something wrong, I read too much from the message
> I sent, but it sometimes fine...
Yes, it was (tha PlayerType enum). Sometimes (if my pc is the slower,
and I'm the server) the PlayerType is not set to the correct player
type (when the game starts).
Thank you, you helped a lot!
On Dec 16, 1:35 pm, lidgren <lidg...@gmail.com> wrote:
> The code looks good; but i noticed you're writing/reading different
> amount of data depending on
> the PlayerType enum - could it be this variable gets out of sync
> between coupled read/writes?
> Also, I recommend using msg.WriteSendStamp() and msg.ReadSentStamp()
> since
> NetTime.Now only returns local time, which cannot be compared upon
> receiving.
> > vec4 = XnaSerialization.ReadVector4(m_game_datas);
> > mp_ball_velocity.X = vec4.X;
> > mp_ball_velocity.Z = vec4.Y;
> > mp_ball_velocity.Y = 0.0f;
> > mp_ball_slave_velocity.X = vec4.Z;
> > mp_ball_slave_velocity.Z = vec4.W;
> > mp_ball_slave_velocity.Y = 0.0f;
> > }
> > }
> > Comment: I use my system like this: every game-update calls the
> > network.update -> it gets the messages and if it's not a game-message,
> > it do it in that update (e.g. a client disconnected message, or a
> > client connection request message, ...; they come in the
> > NetChannel.Ordered1) If it's a game-message (NetChannel.Sequenced1),
> > the network class gets a Single -> it's the time lable. If it's the
> > last message (biggest time label) it store it in a cache variable (the
> > whole NetMessage), and in the end of the network.update process the
> > last (cached) game-message (only the last). And here comes the
> > UpdateDatasFromMessage call, which get the NetMessage, and then read
> > the vectors from it and store in a shadred GameDatas class -> then the
> > game can refresh the game object datas from this shared GameDatas
> > class.
> > Anyway, the sending of the game datas is this way: every game.update
> > calls network.sendGameDatas, but it sends the game datas only if the
> > timer allow it (now it's 70ms -> about 14 times/sec). When it sends
> > the datas, it calls the CollectToMessage function, which gets the
> > datas from the shared GameDatas class (it's updated in every
> > game.update, because it's used in the collision detection too).
> > A game-message looks like: 1byte code (every type of the messages have
> > a non-zero code, game-message's code is: 1), 4 bytes (float) time-
> > label, and then the datas (it depends on the type of the player, a
> > server gets less datas and sends more datas, bacause the server watchs
> > not only the server-player's bets but the ball as well).
> > I made a logs every time (with client and with server too), and it
> > writes that the client sends 29 bytes and the server gets 29 bytes,
> > and that's why I'm totally lost, because the message is correct, and I
> > don't read more then I wrote.
> > But the strangest thing is that this is sometimes works! If it never
> > works i think i made something wrong, I read too much from the message
> > I sent, but it sometimes fine...