简体   繁体   中英

Sending Mouse Coordinates to Unity Client via TCP Sockets in C#

So I am doing a project in which I send mouse position coordinates in an serialized JSON object to another computer that has a Unity Client application running. I will later translate these into relative movement positions in Unity so it's not super exaggerated. That's not the weird part about this one.

The problem seems to lie with the send and receive socket functions not blocking correctly. The coordinates are being sent in a loop on the other server application. What I want it to do is send the coordinates and then move an object relatively based on the start and changed positions I get from the server.

In Unity the timing seems all off. It only receives a few of the coordinate packages. I would think if it blocked it would have to wait for each and every one before it can continue. Though the Update() function in Unity is different seeing as it loops not as quickly as it can but based on the number of frames it currently is set to run at. It runs once per frame (or roughly 100 milliseconds).

It does not seem to block properly for some reason. Even though it runs per the number of frames, I still feel it should block until it receives something. I would like it to be nearly instantaneous when sending and receiving the coordinates.

If I could manipulate the GameObject in Unity with another thread besides the main thread then there may be an easier way to deal with this, since I could just have that thread only check for the coordinates and not be halting anything else or run based on the number of frames. I have some code here to show you. I have better async code, but I want to get the simple stuff working first before I implement any of that.

Here it is (Unity C#):

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.IO;
using System.Threading;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Linq;
using JsonFx.Json;
using PayLoad;

public class BasicBlocking : MonoBehaviour {

string path = @"DEBUGPATH";
public Texture[] myTextures = new Texture[4];
int packets;
GameObject guiTextureObjBorder;
GameObject guiTextObj;
GameObject guiTextObj2;
Vector3 coord;
public byte[] buffer;
public bool connected;
public Socket client;
public int port;
public string ip;
public IPEndPoint localEndPoint;
// Use this for initialization
void Start () {

    packets = 0;
    //guiTextObj = new GameObject ();
    guiTextObj = GameObject.Find ("gui");
    //guiTextObj2 = new GameObject ();
    guiTextObj2 = GameObject.Find ("packets");

    guiTextureObjBorder = GameObject.Find ("border");
    // default settings
    ip = "some_ip_address";
    port = 11000;
    localEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);
    // Create a TCP/IP socket.
    client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    connected = false;
    buffer = new byte[4096];

}

// Update is called once per frame
void Update () {

    // this starts the connection
    if (Input.GetKeyDown (KeyCode.Return) && !(connected)) {

            try {

                client.Connect (localEndPoint);
                connected = true; // only a temporary thing, very unsafe but its just for testing
                Debug.Log ("Connected to: " + client.RemoteEndPoint.ToString () + Environment.NewLine);
                guiTextureObjBorder.guiTexture.texture = myTextures[1]; // turns border green

            } 
            catch (Exception ex) {

                Debug.Log ("Couldn't Connect!");
                Application.Quit (); // just currently

            }

    } 
    // this ends the connection if it has already been started and still connected
    else if (Input.GetKeyDown (KeyCode.Return) && (connected)) {

        guiTextureObjBorder.guiTexture.texture = myTextures[2]; // turns border red
        Debug.Log ("Connection Was Closed on the Client-Side Manually!");
        client.Shutdown(SocketShutdown.Send);
        client.Close();

    }

    if (connected) {

        guiTextureObjBorder.guiTexture.texture = myTextures[1]; // turns border green

        try{

            // block and wait till data is received
            client.Receive(buffer);
            packets++; // keeps track of all the packets that have been received
            guiTextObj2.guiText.text = "Packets Sent: " + packets;

            StringBuilder result = new StringBuilder(Encoding.UTF8.GetString(buffer));

            Debug.Log ("JSON STRING: " + result.ToString() + Environment.NewLine);

            JsonReaderSettings settings = JsonDataReader.CreateSettings(true);
            settings.TypeHintName = "Package";
            JsonReader reader = new JsonReader(result);
            Package p = new Package();
            p = JsonReader.CoerceType<Package>(reader.Deserialize());

            float x = p.Changed.xPosition;
            float y = p.Changed.yPosition;

            guiTextObj.guiText.text = "Move X: " + x + Environment.NewLine + "Move Y: " + y;

            if(!File.Exists (path)){

                using (StreamWriter sw = File.CreateText (path)){

                    sw.WriteLine("Package" + Environment.NewLine + "Move X: " + x + Environment.NewLine + "Move Y: ");
                    sw.WriteLine("JSON STRING: " + result.ToString());

                }

            }
            else{

                using (StreamWriter sw = File.AppendText (path)){

                    sw.WriteLine("Package" + Environment.NewLine + "Move X: " + x + Environment.NewLine + "Move Y: " + y);
                    sw.WriteLine("JSON STRING: " + result.ToString());

                }

            }

            coord = new Vector3(p.Changed.xPosition, p.Changed.yPosition, 0.0f);
            this.transform.Translate(coord); // moves the ball

        }
        catch(Exception ex){

            guiTextureObjBorder.guiTexture.texture = myTextures[2]; // turns border red
            Debug.Log ("Connection Was Closed!");
            client.Shutdown(SocketShutdown.Send);
            client.Close();
            Application.Quit(); // just currently

        }

    }

}



}

Here's the PayLoad namespace if you want to see it also:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Threading;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Linq;
using JsonFx.Json;

// this namespace contains the class information for the Coordinate class and the    Package class that contains it
namespace PayLoad 
{

// this class holds 2D coordinate information
[JsonOptIn]
public class Coordinate {

    private float xPos; // holds the x coordinate
    // x coordinate accessor
    [JsonMember]
    public float xPosition{

        get{ return xPos; }
        set{ xPos = value; }

    }

    private float yPos; // holds the y coordinate
    // y coordinate accessor
    [JsonMember]
    public float yPosition{

        get{ return yPos; }
        set{ yPos = value; }

    }

    // default constructor
    public Coordinate(){

        xPos = 0;
        yPos = 0;

    }

    // specific contructor taking the floats as arguements
    public Coordinate(float x, float y){

        xPos = x;
        yPos = y;

    }

    public Coordinate(Coordinate c){

        xPos = c.xPosition;
        yPos = c.yPosition;

    }

    // you can add coordinates with this [for example to get the global position if you 'freeze' its position]
    public static Coordinate operator +(Coordinate c1, Coordinate c2){

        return new Coordinate(c1.xPos + c2.xPos, c1.yPos + c2.yPos);

    }

    // you can use this overloaded operator to subtract coordinate objects if you need to
    public static Coordinate operator -(Coordinate c1, Coordinate c2){

        return new Coordinate(c1.xPos - c2.xPos, c1.yPos - c2.yPos);

    }

}

// this class holds a coordinate object and various operations on said object
[JsonOptIn]
public class Package {

    private Coordinate start; // holds the start/initial position on each update [every time the mouse is moved the start gets se to the new location you moved to]
    // start coordinate accessor
    [JsonMember]
    public Coordinate Start{

        get{ return start; }
        set{ start = value; }

    }

    private Coordinate changed; // this is where the mouse moved away from the start/initial coordinate
    // changed coordinate accessor
    [JsonMember]
    public Coordinate Changed{

        get{ return changed; }
        set{ changed = value; }

    }

    // default constructor
    public Package(){

        start = new Coordinate ();
        changed = new Coordinate ();

    }

    // specific constructor that takes two coordinates as parameters
    public Package(Coordinate s, Coordinate c){

        start = new Coordinate(s);
        changed = new Coordinate(c);

    }

    public Package(Package p){

        start = new Coordinate (p.Start);
        changed = new Coordinate(p.Changed);

    }

    // this gets the relative movement from the start coordinate to the changed coordinate and returns it as a coordinate representing the change in x and y 
    public Coordinate getRelativeMovementCoordinate(){

        return changed - start; // this will get the difference from the start to the new position which will be the relative amount of movement that will be applied to the ball

    }


}

}

So I am trying to get it sent without any delays I have to set for it. It will only receive 2 out of 6 packets I send it. The server is using Socket.Send on its side on a separate thread. It should also be blocking like my receive.

It never seems to be an issue for me unless it involves Unity3D. The code above is the Unity code I wrote to just receive packages and then move a GameObject, in this case a sphere. Is there a reason it isn't blocking and being forced to receive every single package? Is it really being sent too fast?

I thought that if I block and the server blocks that it will force all the packages to be received in order and as quickly as possible.

Here's a little of the log file I use to help debug (JSON):

Package

Move X: 1

Move Y: -1

JSON STRING:

{
"Package": "PayLoad.Package, Server_Async",
"Start": 
    {
        "Package": "PayLoad.Coordinate, Server_Async",
        "xPosition": 0,
        "yPosition": 0
    },
"Changed": 
    {
        "Package": "PayLoad.Coordinate, Server_Async",
        "xPosition": 1,
        "yPosition": -1
    }
}

{
"Package": "PayLoad.Package, Server_Async",
"Start": 
    {
        "Package": "PayLoad.Coordinate, Server_Async",
        "xPosition": 0,
        "yPosition": 0
    },
"Changed": 
    {
        "Package": "PayLoad.Coordinate, Server_Async",
        "xPosition": -1,
        "yPosition": -1
    }
}

{
"Package": "PayLoad.Package, Server_Async",
"Start": 
    {
        "Package": "PayLoad.Coordinate, Server_Async",
        "xPosition": 0,
        "yPosition": 0
    },
"Changed": 
    {
        "Package": "PayLoad.Coordinate, Server_Async",
        "xPosition": -1,
        "yPosition": 0
    }
}

{
"Package": "PayLoad.Package, Server_Async",
"Start": 
    {
        "Package": "PayLoad.Coordinate, Server_Async",
        "xPosition": 0,
        "yPosition": 0
    },
"Changed": 
    {
        "Package": "PayLoad.Coordinate, Server_Async",
        "xPosition": -1,
        "yPosition": 1
    }
}

{
"Package": "PayLoad.Package, Server_Async",
"Start": 
    {
        "Package": "PayLoad.Coordinate, Server_Async",
        "xPosition": 0,
        "yPosition": 0
    },
"Changed": 
    {
        "Package": "PayLoad.Coordinate, Server_Async",
        "xPosition": 1,
        "yPosition": 1
    }
}      

JSON STRING: and above were things I printed out for debugging; everything below that is the JSON string I received. As you can see, it has a lot of them together instead of singular packages with one set of coordinates that were sent.

It's like it appends all the JSON strings together before it stops receiving the byte data. I only want to receive one "Package" at a time, not all at once. I am not sure if it is a JSON issue, sockets not blocking, some sort of Unity issue where the Update() function runs too slow. I am not really too sure.

Again to re-state what I want it to do: I want it to receive these coordinate packages I serialize with JSON and send using Sockets. I want to receive only one at a time and I want it to be nearly instant, or as close as it can be without manually calling Thread.Sleep(...) or something.

It needs to receive a set of coordinates (in this example I only use the changed coordinates currently just for testing) and then make the GameObject in Unity move the set amount, then wait to receive and do it again in a loop until I tell it to stop. I hvae tried (though not in my current code) to clear buffer as well each time and it doesn't seem to do anything at all. I could be a lot of things though I am confused as to which is causing the problem and how to go about fixing it.

It seems like you are receiving just one Package per frame ( Update runs once per frame).

Wrap that in a while loop checking if you have anything more to receive and process more than one Package per frame.


Also, why use json.net for this? It's a total overkill, unless you receive something more complex. You could send two ints etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM