/// <summary>
    /// Handles a call to a Python function.
    /// </summary>
    /// <param name="function">The Python function to call (start or update)</param>
    private void PythonCall(Header function)
    {
        if (!this.isSyncConnected)
        {
            this.HandleError("Not connected to a Python script.");
        }

        // Tell Python what function to call
        this.udpClient.Send(new byte[] { (byte)function }, 1);

        // Respond to API calls from Python until we receive a python_finished message
        bool pythonFinished = false;

        while (!pythonFinished)
        {
            // Receive a response from Python
            byte[] data = this.SafeRecieve();
            if (data == null)
            {
                break;
            }
            Header header = (Header)data[0];

            // Send the appropriate response if it was an API call, or break if it was a python_finished message
            byte[] sendData;
            switch (header)
            {
            case Header.error:
                HandleError("Error code sent from Python.");
                break;

            case Header.python_finished:
                pythonFinished = true;
                break;

            case Header.racecar_get_delta_time:
                sendData = BitConverter.GetBytes(Time.deltaTime);
                this.udpClient.Send(sendData, sendData.Length);
                break;

            case Header.camera_get_color_image:
                this.SendFragmented(this.racecar.Camera.ColorImageRaw, 32);
                break;

            case Header.camera_get_depth_image:
                sendData = this.racecar.Camera.DepthImageRaw;
                this.udpClient.Send(sendData, sendData.Length);
                break;

            case Header.camera_get_width:
                sendData = BitConverter.GetBytes(CameraModule.ColorWidth);
                this.udpClient.Send(sendData, sendData.Length);
                break;

            case Header.camera_get_height:
                sendData = BitConverter.GetBytes(CameraModule.ColorHeight);
                this.udpClient.Send(sendData, sendData.Length);
                break;

            case Header.controller_is_down:
                Controller.Button buttonDown = (Controller.Button)data[1];
                sendData = BitConverter.GetBytes(this.racecar.Controller.IsDown(buttonDown));
                this.udpClient.Send(sendData, sendData.Length);
                break;

            case Header.controller_was_pressed:
                Controller.Button buttonPressed = (Controller.Button)data[1];
                sendData = BitConverter.GetBytes(this.racecar.Controller.WasPressed(buttonPressed));
                this.udpClient.Send(sendData, sendData.Length);
                break;

            case Header.controller_was_released:
                Controller.Button buttonReleased = (Controller.Button)data[1];
                sendData = BitConverter.GetBytes(this.racecar.Controller.WasReleased(buttonReleased));
                this.udpClient.Send(sendData, sendData.Length);
                break;

            case Header.controller_get_trigger:
                Controller.Trigger trigger = (Controller.Trigger)data[1];
                sendData = BitConverter.GetBytes(this.racecar.Controller.GetTrigger(trigger));
                this.udpClient.Send(sendData, sendData.Length);
                break;

            case Header.controller_get_joystick:
                Controller.Joystick joystick       = (Controller.Joystick)data[1];
                Vector2             joystickValues = this.racecar.Controller.GetJoystick(joystick);
                sendData = new byte[sizeof(float) * 2];
                Buffer.BlockCopy(new float[] { joystickValues.x, joystickValues.y }, 0, sendData, 0, sendData.Length);
                this.udpClient.Send(sendData, sendData.Length);
                break;

            case Header.drive_set_speed_angle:
                this.racecar.Drive.Speed = BitConverter.ToSingle(data, 4);
                this.racecar.Drive.Angle = BitConverter.ToSingle(data, 8);
                break;

            case Header.drive_stop:
                this.racecar.Drive.Stop();
                break;

            case Header.drive_set_max_speed:
                this.racecar.Drive.MaxSpeed = BitConverter.ToSingle(data, 4);
                break;

            case Header.lidar_get_num_samples:
                sendData = BitConverter.GetBytes(Lidar.NumSamples);
                this.udpClient.Send(sendData, sendData.Length);
                break;

            case Header.lidar_get_samples:
                sendData = new byte[sizeof(float) * Lidar.NumSamples];
                Buffer.BlockCopy(this.racecar.Lidar.Samples, 0, sendData, 0, sendData.Length);
                this.udpClient.Send(sendData, sendData.Length);
                break;

            case Header.physics_get_linear_acceleration:
                Vector3 linearAcceleration = this.racecar.Physics.LinearAccceleration;
                sendData = new byte[sizeof(float) * 3];
                Buffer.BlockCopy(new float[] { linearAcceleration.x, linearAcceleration.y, linearAcceleration.z }, 0, sendData, 0, sendData.Length);
                this.udpClient.Send(sendData, sendData.Length);
                break;

            case Header.physics_get_angular_velocity:
                Vector3 angularVelocity = this.racecar.Physics.AngularVelocity;
                sendData = new byte[sizeof(float) * 3];
                Buffer.BlockCopy(new float[] { angularVelocity.x, angularVelocity.y, angularVelocity.z }, 0, sendData, 0, sendData.Length);
                this.udpClient.Send(sendData, sendData.Length);
                break;

            default:
                Debug.LogError($">> Error: The function {header} is not supported by RacecarSim.");
                break;
            }
        }
    }
Example #2
0
 /// <summary>
 /// Returns the value of a trigger.
 /// </summary>
 /// <param name="trigger">A trigger on an Xbox controller.</param>
 /// <returns>The value of the provided trigger, ranging from 0 (unpressed) to 1 (fully pressed).</returns>
 public float GetTrigger(Controller.Trigger trigger)
 {
     return(this.triggerValues[(int)trigger]);
 }
    /// <summary>
    /// Calls a Python function on all connected scripts.
    /// </summary>
    /// <param name="function">The Python function to call (start or update)</param>
    private void PythonCall(Header function)
    {
        for (int i = 0; i < this.pythonEndPoints.Count; i++)
        {
            if (this.pythonEndPoints[i] == null)
            {
                continue;
            }

            Racecar    racecar  = LevelManager.GetCar(i);
            IPEndPoint endPoint = this.pythonEndPoints[i];

            // Tell Python what function to call
            this.udpClient.Send(new byte[] { (byte)function }, 1, endPoint);

            // Respond to API calls from Python until we receive a python_finished message
            bool pythonFinished = false;
            while (!pythonFinished)
            {
                // Receive a response from Python
                byte[] data = this.SafeRecieve(endPoint);
                if (data == null)
                {
                    break;
                }
                Header header = (Header)data[0];

                bool shouldSendController = LevelManager.LevelManagerMode != LevelManagerMode.Race || Settings.CheatMode;

                // Send the appropriate response if it was an API call, or break if it was a python_finished message
                byte[] sendData;
                switch (header)
                {
                case Header.error:
                    Error errorCode = (Error)data[1];
                    HandleError($"Error code [{errorCode}] sent from the Python script controlling car {i}.", errorCode);
                    pythonFinished = true;
                    break;

                case Header.python_finished:
                    pythonFinished = true;
                    break;

                case Header.python_exit:
                    this.RemoveSyncClient(endPoint.Port);
                    pythonFinished = true;
                    break;

                case Header.racecar_get_delta_time:
                    sendData = BitConverter.GetBytes(Time.deltaTime);
                    this.udpClient.Send(sendData, sendData.Length, endPoint);
                    break;

                case Header.camera_get_color_image:
                    pythonFinished = !this.SendFragmented(racecar.Camera.ColorImageRaw, 32, endPoint);
                    break;

                case Header.camera_get_depth_image:
                    sendData = racecar.Camera.DepthImageRaw;
                    this.udpClient.Send(sendData, sendData.Length, endPoint);
                    break;

                case Header.camera_get_width:
                    sendData = BitConverter.GetBytes(CameraModule.ColorWidth);
                    this.udpClient.Send(sendData, sendData.Length, endPoint);
                    break;

                case Header.camera_get_height:
                    sendData = BitConverter.GetBytes(CameraModule.ColorHeight);
                    this.udpClient.Send(sendData, sendData.Length, endPoint);
                    break;

                // Always return null controller data when in race mode (except in cheat mode)
                case Header.controller_is_down:
                    Controller.Button buttonDown = (Controller.Button)data[1];
                    sendData = BitConverter.GetBytes(Controller.IsDown(buttonDown) && shouldSendController);
                    this.udpClient.Send(sendData, sendData.Length, endPoint);
                    break;

                case Header.controller_was_pressed:
                    Controller.Button buttonPressed = (Controller.Button)data[1];
                    sendData = BitConverter.GetBytes(Controller.WasPressed(buttonPressed) && shouldSendController);
                    this.udpClient.Send(sendData, sendData.Length, endPoint);
                    break;

                case Header.controller_was_released:
                    Controller.Button buttonReleased = (Controller.Button)data[1];
                    sendData = BitConverter.GetBytes(Controller.WasReleased(buttonReleased) && shouldSendController);
                    this.udpClient.Send(sendData, sendData.Length, endPoint);
                    break;

                case Header.controller_get_trigger:
                    Controller.Trigger trigger = (Controller.Trigger)data[1];
                    float triggerValue         = shouldSendController ? Controller.GetTrigger(trigger) : 0;
                    sendData = BitConverter.GetBytes(triggerValue);
                    this.udpClient.Send(sendData, sendData.Length, endPoint);
                    break;

                case Header.controller_get_joystick:
                    Controller.Joystick joystick       = (Controller.Joystick)data[1];
                    Vector2             joystickValues = shouldSendController ? Controller.GetJoystick(joystick) : Vector2.zero;
                    sendData = new byte[sizeof(float) * 2];
                    Buffer.BlockCopy(new float[] { joystickValues.x, joystickValues.y }, 0, sendData, 0, sendData.Length);
                    this.udpClient.Send(sendData, sendData.Length, endPoint);
                    break;

                case Header.drive_set_speed_angle:
                    racecar.Drive.Speed = BitConverter.ToSingle(data, 4);
                    racecar.Drive.Angle = BitConverter.ToSingle(data, 8);
                    break;

                case Header.drive_stop:
                    racecar.Drive.Stop();
                    break;

                case Header.drive_set_max_speed:
                    racecar.Drive.MaxSpeed = BitConverter.ToSingle(data, 4);
                    break;

                case Header.lidar_get_num_samples:
                    sendData = BitConverter.GetBytes(Lidar.NumSamples);
                    this.udpClient.Send(sendData, sendData.Length, endPoint);
                    break;

                case Header.lidar_get_samples:
                    sendData = new byte[sizeof(float) * Lidar.NumSamples];
                    Buffer.BlockCopy(racecar.Lidar.Samples, 0, sendData, 0, sendData.Length);
                    this.udpClient.Send(sendData, sendData.Length, endPoint);
                    break;

                case Header.physics_get_linear_acceleration:
                    Vector3 linearAcceleration = racecar.Physics.LinearAccceleration;
                    sendData = new byte[sizeof(float) * 3];
                    Buffer.BlockCopy(new float[] { linearAcceleration.x, linearAcceleration.y, linearAcceleration.z }, 0, sendData, 0, sendData.Length);
                    this.udpClient.Send(sendData, sendData.Length, endPoint);
                    break;

                case Header.physics_get_angular_velocity:
                    Vector3 angularVelocity = racecar.Physics.AngularVelocity;
                    sendData = new byte[sizeof(float) * 3];
                    Buffer.BlockCopy(new float[] { angularVelocity.x, angularVelocity.y, angularVelocity.z }, 0, sendData, 0, sendData.Length);
                    this.udpClient.Send(sendData, sendData.Length, endPoint);
                    break;

                default:
                    Debug.LogError($">> Error: The function {header} is not supported by RacecarSim.");
                    pythonFinished = true;
                    break;
                }
            }
        }
    }