• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!

[c# Xna] Networking with SystemLink problems

Status
Not open for further replies.
Level 1
Joined
Nov 20, 2013
Messages
5
Hello, my name is Eric and I have a little problem with networking in c#

this is my update method code:

C#:
protected override void Update(GameTime gameTime)
{
    // Allows the game to exit
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
        this.Exit();

    switch (gameState)
    {
        case (GameState.PlayingAsHost):
            session.Update();

            while (session.LocalGamers[0].IsDataAvailable) //Recieve data
            {
                NetworkGamer sender;
                PacketReader reader = new PacketReader();

                session.LocalGamers[0].ReceiveData(reader, out sender);

                guestPaddle.Position = reader.ReadVector2();
            }

            hostPaddle.Update(); //Update paddle position

            var packetWriter = new PacketWriter(); //Send data
            packetWriter.Write(new Vector2(hostPaddle.Position.X, 50));
            session.LocalGamers[0].SendData(packetWriter, SendDataOptions.InOrder);

            if (session.AllGamers.Count < 2) //has a player dissconnected?
            {
                session.Dispose();
                gameState = GameState.NotSignedIn;
            }
            break;

        case (GameState.PlayingAsGuest):
            session.Update();

            while (session.LocalGamers[0].IsDataAvailable)//Recieve data
            {
                NetworkGamer sender;
                PacketReader reader = new PacketReader();

                session.LocalGamers[0].ReceiveData(reader, out sender);

                hostPaddle.Position = reader.ReadVector2();
            }

            guestPaddle.Update(); //Update paddle position

            var packetWriter = new PacketWriter(); //Send data
            packetWriter.Write(new Vector2(guestPaddle.Position.X, 50));
           session.LocalGamers[0].SendData(packetWriter,                             SendDataOptions.InOrder);

            if (session.AllGamers.Count < 2)
            {
                session.Dispose();
                gameState = GameState.NotSignedIn;
            }
            break;
    }
}
The Paddle.Update method:
C#:
internal void Update()
        {
            MathHelper.Clamp((float)Position.X, 0, 800);

            Position = new Vector2(Mouse.GetState().X, Position.Y);

            Hitbox = new Rectangle((int)Position.X, (int)Position.Y, Texture.Width, Texture.Height);
        }
This is going to be a pong multiplayer game (therefore the paddle names). Before when the guest was sending it's package before recieving, the code worked except for that when playing as the guest the host's X position was set to the guest's X position. I was testing if changing so that the guest and host recieved data before sending it would solve the problem.
By doing so the host gets the error message: "Unable to read beyond the end of the stream". How do I solve this problem?
 
Last edited:
Level 29
Joined
Jul 29, 2007
Messages
5,174
The first step would be to put your code in a [code=csharp][/code] (or if csharp isn't valid, cpp) block and put proper indentation.

Before issuing your problem, do note that you don't have to have two nearly identical blocks of logic.
This is because it doesn't matter who the host and who the client is for the movement logic, you update the opposite player with data you receive from him.

As to your problem, if you are trying to receive data before anything was sent, then obviously there will be no data. Generally speaking you should handle the case when there is indeed no data (I never used C#, but I am assuming there is an exception catching mechanism).
If you are getting bad positions, that's something wrong with your logic code. Without seeing the rest, I can only assume session.LocalGamers[0] refers to the guest for both host and guest, so getting your position from there will return the guest's position.
 
Level 1
Joined
Nov 20, 2013
Messages
5
The first step would be to put your code in a [code=csharp][/code] (or if csharp isn't valid, cpp) block and put proper indentation.

Before issuing your problem, do note that you don't have to have two nearly identical blocks of logic.
This is because it doesn't matter who the host and who the client is for the movement logic, you update the opposite player with data you receive from him.

As to your problem, if you are trying to receive data before anything was sent, then obviously there will be no data. Generally speaking you should handle the case when there is indeed no data (I never used C#, but I am assuming there is an exception catching mechanism).
If you are getting bad positions, that's something wrong with your logic code. Without seeing the rest, I can only assume session.LocalGamers[0] refers to the guest for both host and guest, so getting your position from there will return the guest's position.

I have these 2 cases between being a host and being a guest becuase the host is going to have all the code for all the other updating such as the ball,sounds etc. and I do have code for when there is no data:
"while (session.LocalGamers[0].IsDataAvailable)"

so there must be some available data, the question is why the data is incomplete.
 
Level 15
Joined
Oct 18, 2008
Messages
1,588
"Unable to read beyond the end of the stream". How do I solve this problem?

C#:
reader.BaseStream.Seek(0);

The problem is that streams read through the buffer, then reach the end - they won't move back to the front of the stream without you telling it to do so. You are probably using the same stream.

Before when the guest was sending it's package before recieving, the code worked except for that when playing as the guest the host's X position was set to the guest's X position.

That is a logical problem in your code, you should check what you assign to where.

Also, for a pong game it's fine, but in bigger projects I can only advise against using the PacketWriter and PacketReader. You should rather just use the BinaryFormatter to serialize objects. (In case of non-peer-to-peer applications, this needs you to export your data model into a separate library and include that in both the server and the client, since BinaryFormatter requires the exact same DLL).
 
Level 1
Joined
Nov 20, 2013
Messages
5
C#:
reader.BaseStream.Seek(0);

The problem is that streams read through the buffer, then reach the end - they won't move back to the front of the stream without you telling it to do so. You are probably using the same stream.


You never told me where to put this code so I tried different solutions:

C#:
while (session.LocalGamers[0].IsDataAvailable)
                        {
                            NetworkGamer sender;
                            PacketReader reader = new PacketReader();

                            reader.BaseStream.Seek(0, System.IO.SeekOrigin.Begin);

                            session.LocalGamers[0].ReceiveData(reader, out sender);

                            guestPaddle.Position = reader.ReadVector2();
                        }
C#:
while (session.LocalGamers[0].IsDataAvailable)
                        {
                            NetworkGamer sender;
                            PacketReader reader = new PacketReader();

                            session.LocalGamers[0].ReceiveData(reader, out sender);
                            reader.BaseStream.Seek(0, System.IO.SeekOrigin.Begin);

                            guestPaddle.Position = reader.ReadVector2();
                        }

C#:
while (session.LocalGamers[0].IsDataAvailable)
                        {
                            NetworkGamer sender;
                            PacketReader reader = new PacketReader();

                            session.LocalGamers[0].ReceiveData(reader, out sender);

                            guestPaddle.Position = reader.ReadVector2();
                            reader.BaseStream.Seek(0, System.IO.SeekOrigin.Begin);
                        }

None of these worked, so I am wondering, where should I put this code exactly? I have only changed the reading for the host so if that's a problem I would like to know.
 
Level 15
Joined
Oct 18, 2008
Messages
1,588
1) Add [code=csharp][/code] tags to your main post, makes debugging easier for us

2) You add the code that I posted before the line that pops the error (the debugger should show you which line causes the problem.) and replace "reader" with whatever variable causes it.

3) Show us the Paddle.Update(); function

4) As stated before, I'm think as well that session.LocalGamers[0] refers to the host at any time
 
Level 1
Joined
Nov 20, 2013
Messages
5
1) Add [code=csharp][/code] tags to your main post, makes debugging easier for us

2) You add the code that I posted before the line that pops the error (the debugger should show you which line causes the problem.) and replace "reader" with whatever variable causes it.

3) Show us the Paddle.Update(); function

4) As stated before, I'm think as well that session.LocalGamers[0] refers to the host at any time

I have added csharp highlights on my original post,sorry.
The LocalGamers array is a list of all other player on the local network, so the one hosting should not refer to itself.
 
Level 1
Joined
Nov 20, 2013
Messages
5
1) Add [code=csharp][/code] tags to your main post, makes debugging easier for us

2) You add the code that I posted before the line that pops the error (the debugger should show you which line causes the problem.) and replace "reader" with whatever variable causes it.

3) Show us the Paddle.Update(); function

4) As stated before, I'm think as well that session.LocalGamers[0] refers to the host at any time

I have added csharp highlights on my original post as well as the paddle update method,sorry.
The LocalGamers array is a list of all other player on the local network, so the one hosting should not refer to itself.

The line that props the error is:
C#:
session.LocalGamers[0].ReceiveData(reader, out sender);

I am sorry if I am being unclear with my posts.
 
Level 15
Joined
Oct 18, 2008
Messages
1,588
You are differentiating between the host and the guest paddle for no reason, making it harder for yourself. The opponent's paddle is always on top, the local player's paddle is always on bottom (or left and right) accordig to your code, so there is really no reason to put that part into the switch and handle the two differently, creating duplicated code and possibly confusing yourself.

This way it also won't be able to mix up the two players.

Also, you have to close serializers and streams after using them, the best way is with the using statement, or with reader.Close(); reader.Dispose();

C#:
if (gameState != GameState.NotSignedIn)
{
	session.Update();
	while (session.LocalGamers[0].IsDataAvailable)//Recieve data
		{
			NetworkGamer sender;
			using (PacketReader reader = new PacketReader())
			{
				session.LocalGamers[0].ReceiveData(reader, out sender);

				opponentPaddle.Position = reader.ReadVector2();
			}
		}

		myPaddle.Update(); //Update paddle position

		using (PacketWriter packetWriter = new PacketWriter())
		{
			packetWriter.Write(new Vector2(myPaddle.Position.X, 50));
			session.LocalGamers[0].SendData(packetWriter, SendDataOptions.InOrder);
		}
		
		if (session.AllGamers.Count < 2) //has a player dissconnected?
		{
			session.Dispose();
			gameState = GameState.NotSignedIn;
		}

		switch(gameState)
		{
			//Case handling comes here
		}
}

The using statement as used here initializes an IDisposable (such as streams and data serializers), and disposes of them when the block ends. You can also do this manually, as stated above, with reader.Close(); and reader.Dispose();
 
Status
Not open for further replies.
Top