/// <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; } } }
/// <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; } } } }