628 lines
23 KiB
C#
Executable File
628 lines
23 KiB
C#
Executable File
using System.Collections;
|
|
using UnityEngine;
|
|
using System;
|
|
using UnityEngine.UI;
|
|
using System.Globalization;
|
|
using UnityEngine.SceneManagement;
|
|
using UnityStandardAssets.ImageEffects;
|
|
using UnityEngine.AI;
|
|
using System.Collections.Generic;
|
|
|
|
namespace tk
|
|
{
|
|
|
|
public class TcpCarHandler : MonoBehaviour
|
|
{
|
|
|
|
public GameObject carObj;
|
|
public ICar car;
|
|
public CarSpawner carSpawner;
|
|
public PathManager pm;
|
|
public CarConfig conf;
|
|
|
|
// Sensors
|
|
public CameraSensor camSensor;
|
|
public CameraSensor camSensorB;
|
|
public Lidar lidar;
|
|
public Odometry[] odom;
|
|
|
|
private tk.JsonTcpClient client;
|
|
public Text ai_text;
|
|
string customOverlayText = "";
|
|
MapOverlay mapOverlay;
|
|
|
|
public float limitFPS = 20.0f;
|
|
float timeSinceLastCapture = 0.0f;
|
|
public float timeSinceLastMoved = 0.0f;
|
|
public Vector3 lastPos = Vector3.zero;
|
|
public float lastDistanceTraveled = 0.0f;
|
|
|
|
float steer_to_angle = 16.0f;
|
|
|
|
float ai_steering = 0.0f;
|
|
float ai_throttle = 0.0f;
|
|
float ai_brake = 0.0f;
|
|
|
|
int iActiveSpan = 0;
|
|
|
|
bool asynchronous = true;
|
|
float time_step = 0.1f;
|
|
bool bResetCar = false;
|
|
bool bExitScene = false;
|
|
|
|
public enum State
|
|
{
|
|
UnConnected,
|
|
SendTelemetry
|
|
}
|
|
|
|
public State state = State.UnConnected;
|
|
|
|
void Awake()
|
|
{
|
|
car = carObj.GetComponent<ICar>();
|
|
conf = carObj.GetComponent<CarConfig>();
|
|
pm = GameObject.FindObjectOfType<PathManager>();
|
|
carSpawner = GameObject.FindObjectOfType<CarSpawner>();
|
|
Canvas canvas = GameObject.FindObjectOfType<Canvas>();
|
|
GameObject go = CarSpawner.getChildGameObject(canvas.gameObject, "AISteering");
|
|
if (go != null)
|
|
ai_text = go.GetComponent<Text>();
|
|
|
|
if (pm != null && carObj != null)
|
|
{
|
|
iActiveSpan = pm.carPath.GetClosestSpanIndex(carObj.transform.position);
|
|
}
|
|
}
|
|
|
|
public void Init(tk.JsonTcpClient _client)
|
|
{
|
|
client = _client;
|
|
|
|
if (client == null)
|
|
return;
|
|
|
|
client.dispatchInMainThread = false; //too slow to wait.
|
|
client.dispatcher.Register("get_protocol_version", new tk.Delegates.OnMsgRecv(OnProtocolVersion));
|
|
client.dispatcher.Register("control", new tk.Delegates.OnMsgRecv(OnControlsRecv));
|
|
client.dispatcher.Register("exit_scene", new tk.Delegates.OnMsgRecv(OnExitSceneRecv));
|
|
client.dispatcher.Register("reset_car", new tk.Delegates.OnMsgRecv(OnResetCarRecv));
|
|
client.dispatcher.Register("step_mode", new tk.Delegates.OnMsgRecv(OnStepModeRecv));
|
|
client.dispatcher.Register("quit_app", new tk.Delegates.OnMsgRecv(OnQuitApp));
|
|
client.dispatcher.Register("regen_road", new tk.Delegates.OnMsgRecv(OnRegenRoad));
|
|
client.dispatcher.Register("set_ai_text", new tk.Delegates.OnMsgRecv(OnSetAiText));
|
|
client.dispatcher.Register("car_config", new tk.Delegates.OnMsgRecv(OnCarConfig));
|
|
client.dispatcher.Register("cam_config", new tk.Delegates.OnMsgRecv(OnCamConfig));
|
|
client.dispatcher.Register("cam_config_b", new tk.Delegates.OnMsgRecv(OnCamConfigB));
|
|
client.dispatcher.Register("lidar_config", new tk.Delegates.OnMsgRecv(OnLidarConfig));
|
|
client.dispatcher.Register("set_position", new tk.Delegates.OnMsgRecv(OnSetPosition));
|
|
client.dispatcher.Register("node_position", new tk.Delegates.OnMsgRecv(OnNodePositionRecv));
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
mapOverlay = gameObject.AddComponent<MapOverlay>();
|
|
SendCarLoaded();
|
|
state = State.SendTelemetry;
|
|
}
|
|
|
|
public tk.JsonTcpClient GetClient()
|
|
{
|
|
return client;
|
|
}
|
|
|
|
public void OnDestroy()
|
|
{
|
|
if (client != null && client.dispatcher != null)
|
|
client.dispatcher.Reset();
|
|
}
|
|
|
|
void Disconnect()
|
|
{
|
|
client.Disconnect();
|
|
}
|
|
|
|
public void Boot()
|
|
{
|
|
if (carSpawner != null)
|
|
{
|
|
if (client != null) { Disconnect(); }
|
|
carSpawner.RemoveCar(client);
|
|
}
|
|
}
|
|
|
|
void OnProtocolVersion(JSONObject msg)
|
|
{
|
|
JSONObject json = new JSONObject(JSONObject.Type.OBJECT);
|
|
json.AddField("msg_type", "protocol_version");
|
|
json.AddField("version", "2");
|
|
|
|
client.SendMsg(json);
|
|
}
|
|
|
|
void SendTelemetry()
|
|
{
|
|
if (client == null)
|
|
return;
|
|
|
|
JSONObject json = new JSONObject(JSONObject.Type.OBJECT);
|
|
json.AddField("msg_type", "telemetry");
|
|
|
|
json.AddField("steering_angle", car.GetSteering() / steer_to_angle);
|
|
json.AddField("throttle", car.GetThrottle());
|
|
|
|
json.AddField("image", Convert.ToBase64String(camSensor.GetImageBytes()));
|
|
|
|
if (camSensorB != null && camSensorB.gameObject.activeInHierarchy)
|
|
{
|
|
json.AddField("imageb", Convert.ToBase64String(camSensorB.GetImageBytes()));
|
|
}
|
|
|
|
if (lidar != null && lidar.gameObject.activeInHierarchy)
|
|
{
|
|
json.AddField("lidar", lidar.GetOutputAsJson());
|
|
}
|
|
|
|
foreach (Odometry o in odom)
|
|
{
|
|
json.AddField(o.Label, o.GetNumberRotations());
|
|
}
|
|
|
|
|
|
json.AddField("hit", car.GetLastCollision());
|
|
car.ClearLastCollision();
|
|
json.AddField("time", Time.timeSinceLevelLoad);
|
|
|
|
Vector3 velocity = car.GetVelocity() / 8.0f;
|
|
json.AddField("speed", velocity.magnitude);
|
|
|
|
Vector3 accel = car.GetAccel() / 8.0f;
|
|
json.AddField("accel_x", accel.x);
|
|
json.AddField("accel_y", accel.y);
|
|
json.AddField("accel_z", accel.z);
|
|
|
|
Vector3 gyro = car.GetGyro();
|
|
json.AddField("gyro_x", gyro.x);
|
|
json.AddField("gyro_y", gyro.y);
|
|
json.AddField("gyro_z", gyro.z);
|
|
|
|
Transform tm = car.GetTransform();
|
|
Vector3 eulerAngles = tm.rotation.eulerAngles;
|
|
json.AddField("pitch", eulerAngles.x);
|
|
json.AddField("yaw", eulerAngles.y);
|
|
json.AddField("roll", eulerAngles.z);
|
|
|
|
if (pm != null)
|
|
{
|
|
float cte = 0.0f;
|
|
pm.carPath.GetCrossTrackErr(tm.position, ref iActiveSpan, ref cte); // get distance to closest node
|
|
if (GlobalState.extendedTelemetry) { json.AddField("cte", cte); }
|
|
|
|
json.AddField("activeNode", iActiveSpan);
|
|
json.AddField("totalNodes", pm.carPath.nodes.Count);
|
|
}
|
|
|
|
// not intended to use in races, just to train
|
|
if (GlobalState.extendedTelemetry)
|
|
{
|
|
Vector3 pos = tm.position / 8.0f;
|
|
json.AddField("pos_x", pos.x);
|
|
json.AddField("pos_y", pos.y);
|
|
json.AddField("pos_z", pos.z);
|
|
|
|
json.AddField("vel_x", velocity.x);
|
|
json.AddField("vel_y", velocity.y);
|
|
json.AddField("vel_z", velocity.z);
|
|
}
|
|
client.SendMsg(json);
|
|
}
|
|
|
|
void SendCarLoaded()
|
|
{
|
|
if (client == null)
|
|
return;
|
|
|
|
JSONObject json = new JSONObject(JSONObject.Type.OBJECT);
|
|
json.AddField("msg_type", "car_loaded");
|
|
client.SendMsg(json);
|
|
Debug.Log("car loaded.");
|
|
}
|
|
|
|
float clamp(float val, float low, float high)
|
|
{
|
|
float ret = val;
|
|
if (val > high)
|
|
ret = high;
|
|
else if (val < low)
|
|
ret = low;
|
|
return ret;
|
|
}
|
|
|
|
void OnControlsRecv(JSONObject json)
|
|
{
|
|
try
|
|
{
|
|
ai_steering = float.Parse(json["steering"].str, CultureInfo.InvariantCulture.NumberFormat);
|
|
ai_throttle = float.Parse(json["throttle"].str, CultureInfo.InvariantCulture.NumberFormat);
|
|
ai_brake = float.Parse(json["brake"].str, CultureInfo.InvariantCulture.NumberFormat);
|
|
|
|
ai_steering = clamp(ai_steering, -1.0f, 1.0f);
|
|
ai_throttle = clamp(ai_throttle, -1.0f, 1.0f);
|
|
ai_brake = clamp(ai_brake, 0.0f, 1.0f);
|
|
|
|
ai_steering *= steer_to_angle;
|
|
|
|
car.RequestSteering(ai_steering);
|
|
car.RequestThrottle(ai_throttle);
|
|
car.RequestFootBrake(ai_brake);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.Log(e.ToString());
|
|
}
|
|
}
|
|
|
|
void OnExitSceneRecv(JSONObject json)
|
|
{
|
|
bExitScene = true;
|
|
}
|
|
|
|
void ExitScene()
|
|
{
|
|
SceneManager.LoadSceneAsync(0);
|
|
}
|
|
|
|
void OnResetCarRecv(JSONObject json)
|
|
{
|
|
bResetCar = true;
|
|
}
|
|
|
|
void OnRegenRoad(JSONObject json)
|
|
{
|
|
//This causes the track to be regenerated with the given settings.
|
|
//This only works in scenes that have random track generation enabled.
|
|
//For now that is only in scene road_generator.
|
|
//An index into our track options. 5 in scene RoadGenerator.
|
|
int road_style = int.Parse(json.GetField("road_style").str);
|
|
int rand_seed = int.Parse(json.GetField("rand_seed").str);
|
|
float turn_increment = float.Parse(json.GetField("turn_increment").str, CultureInfo.InvariantCulture);
|
|
|
|
//We get this callback in a worker thread, but need to make mainthread calls.
|
|
//so use this handy utility dispatcher from
|
|
// https://github.com/PimDeWitte/UnityMainThreadDispatcher
|
|
UnityMainThreadDispatcher.Instance().Enqueue(RegenRoad(road_style, rand_seed, turn_increment));
|
|
}
|
|
|
|
IEnumerator RegenRoad(int road_style, int rand_seed, float turn_increment)
|
|
{
|
|
TrainingManager train_mgr = GameObject.FindObjectOfType<TrainingManager>();
|
|
PathManager path_mgr = GameObject.FindObjectOfType<PathManager>();
|
|
RoadBuilder road_bld = GameObject.FindObjectOfType<RoadBuilder>();
|
|
|
|
// Apply optional turn increment override before seeding
|
|
if (turn_increment != 0.0f && path_mgr != null)
|
|
path_mgr.turnInc = turn_increment;
|
|
|
|
UnityEngine.Random.InitState(rand_seed);
|
|
|
|
if (train_mgr != null)
|
|
{
|
|
// Scenes with TrainingManager (e.g. generated_track): use the full flow
|
|
train_mgr.SetRoadStyle(road_style);
|
|
train_mgr.OnMenuRegenTrack();
|
|
}
|
|
else if (path_mgr != null)
|
|
{
|
|
// Scenes without TrainingManager (e.g. generated_road): drive regen directly.
|
|
// DestroyRoad removes old barriers/mesh; InitCarPath regenerates nodes
|
|
// and auto-notifies RoadBuilder via IWaitCarPath to rebuild geometry.
|
|
if (road_bld != null)
|
|
road_bld.DestroyRoad();
|
|
path_mgr.InitCarPath();
|
|
}
|
|
|
|
yield return null;
|
|
}
|
|
|
|
void OnSetAiText(JSONObject json)
|
|
{
|
|
customOverlayText = json.GetField("text").str;
|
|
}
|
|
|
|
void OnCarConfig(JSONObject json)
|
|
{
|
|
Debug.Log("Got car config message");
|
|
|
|
string body_style = json.GetField("body_style").str;
|
|
int body_r = int.Parse(json.GetField("body_r").str);
|
|
int body_g = int.Parse(json.GetField("body_g").str);
|
|
int body_b = int.Parse(json.GetField("body_b").str);
|
|
string car_name = json.GetField("car_name").str;
|
|
int font_size = 100;
|
|
|
|
if (json.GetField("font_size") != null)
|
|
font_size = int.Parse(json.GetField("font_size").str);
|
|
|
|
if (carObj != null && car_name != "Racer Name")
|
|
UnityMainThreadDispatcher.Instance().Enqueue(SetCarConfig(body_style, body_r, body_g, body_b, car_name, font_size));
|
|
}
|
|
|
|
IEnumerator SetCarConfig(string body_style, int body_r, int body_g, int body_b, string car_name, int font_size)
|
|
{
|
|
CarConfig conf = carObj.GetComponent<CarConfig>();
|
|
|
|
if (conf)
|
|
{
|
|
conf.SetStyle(body_style, body_r, body_g, body_b, car_name, font_size);
|
|
}
|
|
|
|
yield return null;
|
|
}
|
|
|
|
void OnCamConfig(JSONObject json)
|
|
{
|
|
ParseCamConfig(json, 0);
|
|
}
|
|
|
|
void OnCamConfigB(JSONObject json)
|
|
{
|
|
ParseCamConfig(json, 1);
|
|
}
|
|
|
|
void ParseCamConfig(JSONObject json, int iCamera)
|
|
{
|
|
float fov = float.Parse(json.GetField("fov").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
float offset_x = float.Parse(json.GetField("offset_x").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
float offset_y = float.Parse(json.GetField("offset_y").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
float offset_z = float.Parse(json.GetField("offset_z").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
float rot_x = float.Parse(json.GetField("rot_x").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
float rot_y = 0f;
|
|
float rot_z = 0f;
|
|
if (json.HasField("rot_y")) { rot_y = float.Parse(json.GetField("rot_y").str, CultureInfo.InvariantCulture.NumberFormat); }
|
|
if (json.HasField("rot_z")) { rot_z = float.Parse(json.GetField("rot_z").str, CultureInfo.InvariantCulture.NumberFormat); }
|
|
float fish_eye_x = float.Parse(json.GetField("fish_eye_x").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
float fish_eye_y = float.Parse(json.GetField("fish_eye_y").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
int img_w = int.Parse(json.GetField("img_w").str);
|
|
int img_h = int.Parse(json.GetField("img_h").str);
|
|
int img_d = int.Parse(json.GetField("img_d").str);
|
|
string img_enc = json.GetField("img_enc").str;
|
|
|
|
if (carObj != null)
|
|
UnityMainThreadDispatcher.Instance().Enqueue(SetCamConfig(iCamera, fov, offset_x, offset_y, offset_z, rot_x, rot_y, rot_z, img_w, img_h, img_d, img_enc, fish_eye_x, fish_eye_y));
|
|
}
|
|
|
|
IEnumerator SetCamConfig(int iCamera, float fov, float offset_x, float offset_y, float offset_z, float rot_x,
|
|
float rot_y, float rot_z, int img_w, int img_h, int img_d, string img_enc, float fish_eye_x, float fish_eye_y)
|
|
{
|
|
CameraSensor cam = null;
|
|
|
|
if (iCamera == 0)
|
|
cam = camSensor;
|
|
else
|
|
{
|
|
cam = camSensorB;
|
|
|
|
if (cam != null && !cam.gameObject.activeInHierarchy)
|
|
{
|
|
cam.gameObject.SetActive(true);
|
|
}
|
|
}
|
|
|
|
if (cam)
|
|
{
|
|
cam.SetConfig(fov, offset_x, offset_y, offset_z, rot_x, rot_y, rot_z, img_w, img_h, img_d, img_enc);
|
|
|
|
Fisheye fe = cam.gameObject.GetComponent<Fisheye>();
|
|
|
|
if (fe != null && (fish_eye_x != 0.0f || fish_eye_y != 0.0f))
|
|
{
|
|
fe.enabled = true;
|
|
fe.strengthX = fish_eye_x;
|
|
fe.strengthY = fish_eye_y;
|
|
}
|
|
}
|
|
|
|
yield return null;
|
|
}
|
|
|
|
void OnSetPosition(JSONObject json)
|
|
{
|
|
if (GlobalState.extendedTelemetry)
|
|
{
|
|
float pos_x = float.Parse(json.GetField("pos_x").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
float pos_y = float.Parse(json.GetField("pos_y").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
float pos_z = float.Parse(json.GetField("pos_z").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
Quaternion rot = Quaternion.identity;
|
|
if (json.GetField("Qx") != null && json.GetField("Qy") != null && json.GetField("Qz") != null && json.GetField("Qw") != null)
|
|
{
|
|
float qx = float.Parse(json.GetField("Qx").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
float qy = float.Parse(json.GetField("Qy").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
float qz = float.Parse(json.GetField("Qz").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
float qw = float.Parse(json.GetField("Qw").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
|
|
rot.x = qx;
|
|
rot.y = qy;
|
|
rot.z = qz;
|
|
rot.w = qw;
|
|
}
|
|
|
|
UnityMainThreadDispatcher.Instance().Enqueue(setCarPosition(pos_x, pos_y, pos_z, rot));
|
|
}
|
|
}
|
|
|
|
IEnumerator setCarPosition(float pos_x, float pos_y, float pos_z, Quaternion rot)
|
|
{
|
|
carObj.transform.position = new Vector3(pos_x, pos_y, pos_z);
|
|
carObj.transform.rotation = rot;
|
|
yield return null;
|
|
}
|
|
|
|
void OnLidarConfig(JSONObject json)
|
|
{
|
|
float offset_x = float.Parse(json.GetField("offset_x").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
float offset_y = float.Parse(json.GetField("offset_y").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
float offset_z = float.Parse(json.GetField("offset_z").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
float rot_x = float.Parse(json.GetField("rot_x").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
|
|
float degPerSweepInc = float.Parse(json.GetField("degPerSweepInc").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
float degAngDown = float.Parse(json.GetField("degAngDown").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
float degAngDelta = float.Parse(json.GetField("degAngDelta").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
float maxRange = float.Parse(json.GetField("maxRange").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
float noise = float.Parse(json.GetField("noise").str, CultureInfo.InvariantCulture.NumberFormat);
|
|
int numSweepsLevels = int.Parse(json.GetField("numSweepsLevels").str);
|
|
|
|
|
|
if (carObj != null)
|
|
UnityMainThreadDispatcher.Instance().Enqueue(SetLidarConfig(offset_x, offset_y, offset_z, rot_x, degPerSweepInc, degAngDown, degAngDelta, maxRange, noise, numSweepsLevels));
|
|
}
|
|
|
|
IEnumerator SetLidarConfig(float offset_x, float offset_y, float offset_z, float rot_x,
|
|
float degPerSweepInc, float degAngDown, float degAngDelta, float maxRange, float noise, int numSweepsLevels)
|
|
{
|
|
if (lidar != null)
|
|
{
|
|
if (!lidar.gameObject.activeInHierarchy)
|
|
lidar.gameObject.SetActive(true);
|
|
|
|
lidar.SetConfig(offset_x, offset_y, offset_z, rot_x, degPerSweepInc, degAngDown, degAngDelta, maxRange, noise, numSweepsLevels);
|
|
}
|
|
|
|
yield return null;
|
|
}
|
|
|
|
void OnStepModeRecv(JSONObject json)
|
|
{
|
|
string step_mode = json.GetField("step_mode").str;
|
|
float _time_step = float.Parse(json.GetField("time_step").str);
|
|
|
|
Debug.Log("got settings");
|
|
|
|
if (step_mode == "synchronous")
|
|
{
|
|
Debug.Log("setting mode to synchronous");
|
|
asynchronous = false;
|
|
this.time_step = _time_step;
|
|
Time.timeScale = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
Debug.Log("setting mode to asynchronous");
|
|
asynchronous = true;
|
|
}
|
|
}
|
|
|
|
public IEnumerator SendCollisionWithStartingLine(int startingLineIndex, float timeStamp)
|
|
{
|
|
if (client != null)
|
|
{
|
|
JSONObject json = new JSONObject(JSONObject.Type.OBJECT);
|
|
json.AddField("msg_type", "collision_with_starting_line");
|
|
json.AddField("starting_line_index", startingLineIndex);
|
|
json.AddField("timeStamp", timeStamp);
|
|
client.SendMsg(json);
|
|
}
|
|
|
|
yield return null;
|
|
}
|
|
|
|
public void OnNodePositionRecv(JSONObject json)
|
|
{
|
|
int index = int.Parse(json.GetField("index").str);
|
|
if (pm != null && index >= 0 && index < pm.carPath.nodes.Count)
|
|
{
|
|
PathNode node = pm.carPath.nodes[index];
|
|
UnityMainThreadDispatcher.Instance().Enqueue(SendNodePosition(index, node));
|
|
}
|
|
}
|
|
|
|
public IEnumerator SendNodePosition(int index, PathNode node)
|
|
{
|
|
|
|
JSONObject json = new JSONObject(JSONObject.Type.OBJECT);
|
|
json.AddField("msg_type", "node_position");
|
|
json.AddField("index", index);
|
|
json.AddField("pos_x", node.pos.x);
|
|
json.AddField("pos_y", node.pos.y);
|
|
json.AddField("pos_z", node.pos.z);
|
|
json.AddField("Qx", node.rotation.x);
|
|
json.AddField("Qy", node.rotation.y);
|
|
json.AddField("Qz", node.rotation.z);
|
|
json.AddField("Qw", node.rotation.w);
|
|
client.SendMsg(json);
|
|
yield return null;
|
|
}
|
|
|
|
void OnQuitApp(JSONObject json)
|
|
{
|
|
Application.Quit();
|
|
}
|
|
|
|
void FixedUpdate()
|
|
{
|
|
if (bExitScene)
|
|
{
|
|
bExitScene = false;
|
|
ExitScene();
|
|
}
|
|
|
|
if (state == State.SendTelemetry)
|
|
{
|
|
if (bResetCar)
|
|
{
|
|
car.RestorePosRot();
|
|
|
|
if (carObj != null)
|
|
{
|
|
//reset last controls
|
|
car.RequestSteering(0.0f);
|
|
car.RequestThrottle(0.0f);
|
|
car.RequestFootBrake(10.0f);
|
|
|
|
// Reset closest point of car path
|
|
if (pm)
|
|
iActiveSpan = 0;
|
|
}
|
|
|
|
bResetCar = false;
|
|
}
|
|
|
|
timeSinceLastCapture += Time.fixedDeltaTime;
|
|
if (timeSinceLastCapture >= 1.0f / limitFPS)
|
|
{
|
|
timeSinceLastCapture -= (1.0f / limitFPS);
|
|
SendTelemetry();
|
|
}
|
|
|
|
if (ai_text != null)
|
|
{
|
|
string steerLine = string.Format("Steer:{0,7:F3} Thr:{1:F2}", ai_steering / steer_to_angle, ai_throttle);
|
|
ai_text.text = customOverlayText.Length > 0 ? steerLine + "\n" + customOverlayText : steerLine;
|
|
}
|
|
|
|
Vector3 currentPos = car.GetTransform().position;
|
|
float distance = Vector3.Distance(currentPos, lastPos);
|
|
|
|
if (distance < 1f)
|
|
{
|
|
timeSinceLastMoved += Time.fixedDeltaTime;
|
|
}
|
|
else
|
|
{
|
|
timeSinceLastMoved = 0.0f;
|
|
lastPos = currentPos;
|
|
}
|
|
if (timeSinceLastMoved >= GlobalState.timeOut && carSpawner != null)
|
|
{
|
|
Boot();
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool IsGhostCar()
|
|
{
|
|
if (client == null) { return true; }
|
|
else { return false; }
|
|
}
|
|
}
|
|
}
|