using BestHTTP;
using EasyInject.Attributes;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Playables;
using static UnityEditor.FilePathAttribute;
using UnityEngine.UIElements;
///
/// 叉车AGV
///
[GameObjectBean(ENameType.GameObjectName)]
public class ForkAgvDevice : AbstractDevice, ICar
{
[Autowired]
private AgvPopUI agvPopUI;
///
/// 设备位置解析服务
///
[Autowired("DeviceParseService")]
private readonly DeviceParseService deviceParseService;
///
/// 提供网络服务
///
[Autowired]
private readonly NetWorkComponent netWorkComponent;
///
/// 车辆管理服务
///
[Autowired]
private readonly AgvCarManage carManage;
[Autowired]
private ContainersManage containersManage;
///
/// 路线高亮服务
///
private LineRenderer lineRenderer;
[SerializeField]
private bool initialize = false;
[SerializeField]
private float _speed;
[Header("货叉")]
[SerializeField]
private GameObject forkCargo;
[Header("申请取货位置")]
[SerializeField]
private List applyTakePosition = new();
[Header("申请放货位置")]
[SerializeField]
private List applyPutPosition = new();
[Header("目标是设备角度设置")]
[SerializeField]
private List forkAgvRotationSets = new();
[Header("目标是库位角度设置")]
[SerializeField]
public float shelfRotation = -90;
public string CarName => name;
[Header("可用巷道")]
public List _allowRows = new List();
[SerializeField]
private bool _hasTask;
[SerializeField]
private string _region;
[Header("路线颜色")]
[SerializeField]
private Color pathColor;
///
/// 代理组件
///
private NavMeshAgent agent;
///
/// 时间轴组件
///
private PlayableDirector playable;
///
/// 当前agv任务
///
[SerializeField]
private AgvTaskData taskData;
///
/// 当前反馈状态
///
[SerializeField]
private AgvCarManage.CarTaskStatusEnum currentFeedBackStatus;
private List paths = new List();
public bool hasTask => _hasTask;
public string Region => _region;
public List AllowRows => _allowRows;
public override Transform Transform => transform;
public override string DeviceCode => name;
public override string DeviceType => "AGV";
public bool Initialize => initialize;
public bool HasGood{ get{ return forkCargo.GetComponentInChildren() != null;} }
float ICar.Speed { get => _speed; set { agent.speed = value; _speed = value; } }
public override DeviceData DeviceData => throw new NotImplementedException();
private AgvData _data = new();
private bool isOpenPop;
[Header("模拟反馈")]
[SerializeField]
private bool debugFeedBack;
//保存当前动画状态
public double animationTime;
public double animationSpeed;
public PlayState playState;
public Boolean agentIsStoping;
public Boolean agentRotationUpdate;
public Vector3 agentTarget;
[System.Serializable]
public class ForkAgvRotationSet
{
//设备
public List device;
//非库位取或放,agv保持的角度
public float deviceRotation;
}
private void Start()
{
agent = GetComponent();
agent.speed = _speed;
playable = GetComponent();
playable.Pause();
lineRenderer = transform.GetOrAddComponent();
lineRenderer.positionCount = 0;
lineRenderer.startColor = pathColor;
lineRenderer.endColor = pathColor;
_data.deviecCode = name;
}
private void FixedUpdate()
{
//设备没初始化
if (!initialize)
{
return;
}
if (!hasTask)
{
return;
}
UpdateTask();
//当任务状态是下发状态是,执行
if (taskData.agvTaskStatus == AgvCarManage.CarTaskStatusEnum.SENT)
{
if (currentFeedBackStatus != AgvCarManage.CarTaskStatusEnum.TAKING)
{
currentFeedBackStatus = AgvCarManage.CarTaskStatusEnum.TAKING;
}
//多次申请
FeedBackTaskStatus(currentFeedBackStatus);
}
//取货中
if (taskData.agvTaskStatus == AgvCarManage.CarTaskStatusEnum.TAKING)
{
agent.isStopped = false;
//开始代理
StartAgent(taskData.fromLocation);
// 起点旋转位置
if (applyTakePosition.Count > 0)
{
Vector3 applyTakeVector = LastPosition(applyTakePosition,taskData.fromLocation);
//抵达后,申请取货流程
Vector3 targetPosition = new Vector3(applyTakeVector.x, transform.position.y, applyTakeVector.z);
if (Vector3.Distance(transform.position, targetPosition) <= 0.1f)
{
agent.isStopped = true;
agent.updateRotation = false;
currentFeedBackStatus = AgvCarManage.CarTaskStatusEnum.APPLY_TAKE;
FeedBackTaskStatus(currentFeedBackStatus);
}
}
}
//申请取货
if (taskData.agvTaskStatus == AgvCarManage.CarTaskStatusEnum.APPLY_TAKE)
{
//抵达终点
if (Vector3.Distance(transform.position, agent.destination) <= 0.1f)
{
//获取库位容器模型,绑定到货叉上
GameObject game = deviceParseService.GameObjectByDevice(taskData.fromLocation);
if (game != null)
{
Container container = game.GetComponentInChildren();
if (container != null)
{
container.transform.parent = forkCargo.transform;
playable.Play();
}
}
//反馈取货完成
currentFeedBackStatus = AgvCarManage.CarTaskStatusEnum.TAKE_FINISHED;
FeedBackTaskStatus(currentFeedBackStatus);
}
Quaternion targetRotation = RotationByDevice(taskData.fromDevice);
if (transform.localRotation == targetRotation)
{
//校验起点是设备,需要提升货叉到高位
if (!IsShelf(taskData.fromLocation))
{
if(playable.time <= 1.3)
{
playable.Play();
}
else
{
playable.Pause();
}
}
if(playable.state == PlayState.Paused)
{
agent.isStopped = false;
}
}
else
{
transform.localRotation = Quaternion.RotateTowards(transform.localRotation, targetRotation, _speed * 2);
}
}
//取货完成
if (taskData.agvTaskStatus == AgvCarManage.CarTaskStatusEnum.TAKE_FINISHED)
{
if (HasGood)
{
//是库位取货方式
if (IsShelf(taskData.fromDevice))
{
if (playable.time >= 0.4)
{
OnMinFPS();
}
if (playable.state == PlayState.Paused)
{
agent.updateRotation = true;
currentFeedBackStatus = AgvCarManage.CarTaskStatusEnum.PUTTING;
FeedBackTaskStatus(currentFeedBackStatus);
}
}
else
{
//接驳点取货方式
//需要回退到指定位置做货叉下降动作
Vector3 target = LastPosition(applyTakePosition, taskData.fromDevice);
agent.isStopped = false;
//开始代理
StartAgent(target);
Vector3 targetPosition = new Vector3(target.x, transform.position.y, target.z);
//到位后,开始下降货叉
if (Vector3.Distance(transform.position, targetPosition) <= 0.1f)
{
if (playable.time >= 0.4)
{
playable.playableGraph.GetRootPlayable(0).SetSpeed(-1);
playable.Play();
}
else
{
playable.Pause();
agent.updateRotation = true;
currentFeedBackStatus = AgvCarManage.CarTaskStatusEnum.PUTTING;
FeedBackTaskStatus(currentFeedBackStatus);
}
}
else
{
//货叉升到满叉才执行后续动作
if (playable.time < 1.99)
{
playable.Play();
}
}
}
}
else
{
GameObject game = deviceParseService.GameObjectByDevice(taskData.fromLocation);
if (game != null)
{
Container container = game.GetComponentInChildren();
if (container != null)
{
container.Agent.enabled = false;
container.transform.parent = forkCargo.transform;
playable.Play();
}
}
}
return;
}
//放货中
if (taskData.agvTaskStatus == AgvCarManage.CarTaskStatusEnum.PUTTING)
{
//未代理开始代理
StartAgent(taskData.toLocation);
// 起点旋转位置
if (applyPutPosition.Count > 0)
{
Vector3 applyPutVector = LastPosition(applyPutPosition, taskData.toLocation);
//抵达后,申请取货流程
Vector3 targetPosition = new Vector3(applyPutVector.x, transform.position.y, applyPutVector.z);
if (Vector3.Distance(transform.position, targetPosition) <= 0.1f)
{
agent.isStopped = true;
agent.updateRotation = false;
currentFeedBackStatus = AgvCarManage.CarTaskStatusEnum.APPLY_PUT;
FeedBackTaskStatus(currentFeedBackStatus);
}
}
}
//申请放货
if (taskData.agvTaskStatus == AgvCarManage.CarTaskStatusEnum.APPLY_PUT && currentFeedBackStatus == AgvCarManage.CarTaskStatusEnum.APPLY_PUT)
{
//抵达终点
if (Vector3.Distance(transform.position, agent.destination) <= 0.1f)
{
currentFeedBackStatus = AgvCarManage.CarTaskStatusEnum.PUT_FINISHED;
}
Quaternion targetRotation = RotationByDevice(taskData.toDevice);
if (transform.localRotation == targetRotation)
{
//启用代理
agent.isStopped = false;
//如果是设备将货叉提升完
if(!IsShelf(taskData.toLocation))
{
playable.Play();
}
}
else
{
transform.localRotation = Quaternion.RotateTowards(transform.localRotation, targetRotation, _speed * 2);
}
}
if (currentFeedBackStatus == AgvCarManage.CarTaskStatusEnum.PUT_FINISHED)
{
if (HasGood)
{
//校验是库位还是设备
if(IsShelf(taskData.toLocation))
{
Debug.LogWarning("放货持续");
if (playable.time > 0)
{
playable.playableGraph.GetRootPlayable(0).SetSpeed(-1);
playable.Play();
}
else
{
//暂停播放
//playable.Pause();
////解绑容器
//Container container = forkCargo.transform.GetComponentInChildren();
//container.transform.parent = null;
OnMaxFPS();
}
}
else
{
if (playable.time > 1.5f)
{
playable.playableGraph.GetRootPlayable(0).SetSpeed(-1);
playable.Play();
}
else
{
OnMaxFPS();
}
}
}
else
{
if(!IsShelf(taskData.toLocation))
{
//当后退完成后最终下降完货叉,并重置agv状态
Vector3 position = LastPosition(applyPutPosition, taskData.toLocation);
Vector3 targetPosition = new Vector3(position.x, transform.position.y, position.z);
if (Vector3.Distance(transform.position, targetPosition) <= 0.1f)
{
if(playable.time > 0)
{
playable.Play();
}
else
{
playable.Pause();
FeedBackTaskStatus(currentFeedBackStatus);
Rest();
}
}
}
else
{
Vector3 position = LastPosition(applyPutPosition, taskData.toLocation);
Vector3 targetPosition = new Vector3(position.x, transform.position.y, position.z);
if (Vector3.Distance(transform.position, targetPosition) <= 0.1f)
{
GameObject game = deviceParseService.GameObjectByDevice(taskData.toLocation);
Container container = containersManage.GetContainerByCode(taskData.containerCode);
container.transform.parent = game.transform;
container.transform.localPosition = new Vector3(0, -0.2472343f, 0.0006999969f);
container.Agent.enabled = true;
FeedBackTaskStatus(currentFeedBackStatus);
Rest();
}
}
}
}
}
///
/// 重置设备状态
///
public void Rest()
{
taskData = new AgvTaskData();
_hasTask = false;
paths.Clear();
currentFeedBackStatus =AgvCarManage.CarTaskStatusEnum.STANDBY;
agent.ResetPath();
agent.isStopped = false;
agent.updateRotation = true;
playable.playableGraph.GetRootPlayable(0).SetSpeed(1);
playable.time = 0;
playable.Pause();
}
///
/// 反馈任务状态
///
public void FeedBackTaskStatus(AgvCarManage.CarTaskStatusEnum status,string feedBacklocation = "")
{
if(debugFeedBack)
{
taskData.agvTaskStatus = status;
}
FeedBackEntity feedBackDTO = new FeedBackEntity();
feedBackDTO.feedbackStatus = status.ToString();
feedBackDTO.feedbackLocation = feedBacklocation;
feedBackDTO.taskCode = taskData.instructionCode;
feedBackDTO.carId = taskData.carId;
netWorkComponent.RemoteFeedBackAgvTaskStatus(feedBackDTO, OnFeedBack);
}
///
/// 接受反馈回调信息
///
private void OnFeedBack(HTTPRequest originalRequest, HTTPResponse response)
{
if(response == null)
{
return;
}
//请求成功
if (response.IsSuccess)
{
try
{
//解析反馈
JObject result = JObject.Parse(response.DataAsText);
bool isSuccesss = bool.Parse(result["success"].ToString());
//后台处理反馈成功
if (isSuccesss)
{
//更新当前任务状态,懒更新
// taskData.agvTaskStatus = currentFeedBackStatus;
//agent.isStopped = true;
}
else
{
Debug.LogError(name + " 反馈 =" + response.DataAsText);
}
}
catch(Exception ex)
{
}
}
}
private void Reset()
{
taskData = null;
_hasTask = false;
agent.ResetPath();
}
public void SendTask(AgvTaskData taskData)
{
//if (!Initialize)
//{
// return;
//}
this.taskData = taskData;
_hasTask = true;
}
///
/// 检查数据并初始化
///
private void CheckValueAndInit(HTTPRequest originalRequest, HTTPResponse response)
{
//响应成功
if (response.IsSuccess)
{
try
{
JObject result = JObject.Parse(response.DataAsText);
if (result["object"] == null)
{
Debug.LogWarning("检查数据并初始化" + $"{response.DataAsText}");
return;
}
string json = result["object"].ToString();
CarStatusEntity statusEntity = JsonConvert.DeserializeObject(json);
if (statusEntity != null && statusEntity.task != null)
{
//任务存在的时候才运行初始位置
if (carManage.Contains(statusEntity.task))
{
}
Debug.LogWarning(name + "agv 初始化赋值 =" + JsonConvert.SerializeObject(statusEntity.task));
//agv本体
this.SendTask(statusEntity.task);
this.transform.localPosition = statusEntity.posistion.ToVector();
this.transform.localRotation = statusEntity.roation.ToQuaternion();
this.transform.localScale = statusEntity.scale.ToVector();
this.currentFeedBackStatus = statusEntity.currentFeedBackStatus;
//货叉
if (statusEntity.cargoStatus != null)
{
//forkCargo.transform.localPosition = statusEntity.cargoStatus.posistion.ToVector();
//forkCargo.transform.localRotation = statusEntity.cargoStatus.roation.ToQuaternion();
//forkCargo.transform.localScale = statusEntity.cargoStatus.scale.ToVector();
playable.time = statusEntity.cargoStatus.animationTime;
if (statusEntity.cargoStatus.playState == PlayState.Playing)
{
playable.Play();
}
if (statusEntity.cargoStatus.playState == PlayState.Paused)
{
playable.Pause();
}
playable.RebuildGraph();
playable.playableGraph.GetRootPlayable(0).SetSpeed(statusEntity.cargoStatus.animationSpeed);
}
//容器
if (statusEntity.containerStatus != null)
{
Container container = ApplicationBoot.Instance.GetBean(statusEntity.containerStatus.deviceCode);
container.transform.localPosition = statusEntity.containerStatus.posistion.ToVector();
container.transform.localRotation = statusEntity.containerStatus.roation.ToQuaternion();
container.transform.localScale = statusEntity.containerStatus.scale.ToVector();
container.transform.parent = forkCargo.transform;
}
initialize = true;
}
}catch(Exception x) { }
}
else
{
// Debug.LogWarning(name + ":获取缓存数据响应=" + response.DataAsText);
// Debug.LogWarning(string.Format("【url:{0}】", originalRequest.CurrentUri));
}
initialize = true;
}
private void OnDestroy()
{
Shutdown();
}
public void Shutdown()
{
//当前agv的设备信息
CarStatusEntity carStatus = new();
carStatus.scale = Utils.ToSerializationVectorByVector(transform.localScale);
carStatus.posistion = Utils.ToSerializationVectorByVector(transform.localPosition);
carStatus.roation = Utils.ToSerializationVectorByVector(transform.localRotation.eulerAngles);
carStatus.deviceCode = DeviceCode;
carStatus.modelId = GetInstanceID();
carStatus.currentFeedBackStatus = currentFeedBackStatus;
carStatus.agentIsStoping = this.agentIsStoping;
carStatus.agentRotationUpdate = this.agentRotationUpdate;
carStatus.target = Utils.ToSerializationVectorByVector(this.agentTarget);
//货叉设备信息
CarStatusEntity cargo = new()
{
scale = Utils.ToSerializationVectorByVector(forkCargo.transform.localScale),
posistion = Utils.ToSerializationVectorByVector(forkCargo.transform.localPosition),
roation = Utils.ToSerializationVectorByVector(forkCargo.transform.localRotation.eulerAngles),
modelId = forkCargo.GetInstanceID(),
deviceCode = forkCargo.name,
animationTime = animationTime,
animationSpeed = animationSpeed,
playState = this.playState
};
//有货
if (HasGood)
{
CarStatusEntity containerStatus = new();
Container container = forkCargo.GetComponentInChildren();
containerStatus.scale = Utils.ToSerializationVectorByVector(container.transform.localScale);
containerStatus.posistion = Utils.ToSerializationVectorByVector(container.transform.localPosition);
containerStatus.roation = Utils.ToSerializationVectorByVector(container.transform.localRotation.eulerAngles);
carStatus.containerStatus = containerStatus;
}
carStatus.cargoStatus = cargo;
if(taskData != null && taskData.instructionId != 0)
{
carStatus.task = taskData;
}
//保存当前设备数据
netWorkComponent.RemoteSaveData(name, carStatus, SaveResult);
}
private void SaveResult(HTTPRequest originalRequest, HTTPResponse response)
{
if (response == null)
{
return;
}
if (response.IsSuccess)
{
Debug.Log("保存返回= " + response.DataAsText);
}
else
{
Debug.Log("保存返回= " + response.DataAsText);
}
}
///
/// 开始代理
///
///
public void StartAgent(string deviceName)
{
//未代理开始代理
if (!paths.Contains(deviceName))
{
Vector3 targetPosistion = deviceParseService.PositionByDevice(deviceName);
agent.SetDestination(targetPosistion);
lineRenderer.positionCount = 0;
lineRenderer.SetPositions(agent.path.corners);
paths.Add(taskData.fromLocation);
}
}
///
/// 开始代理
///
///
public void StartAgent(Vector3 target)
{
agent.SetDestination(target);
}
///
/// 取货完成
///
public void OnTakeFinish()
{
currentFeedBackStatus = AgvCarManage.CarTaskStatusEnum.TAKE_FINISHED;
}
public void MouseLeftDown()
{
CameraFollow cameraFollow = transform.GetComponent();
if (cameraFollow)
{
cameraFollow.OnEnter();
}
}
///
/// 更新任务
///
public void UpdateTask()
{
_data.feedBack = currentFeedBackStatus.ToString();
if(taskData != null)
{
AgvTaskData task = carManage.GetTaskByCode(taskData.instructionCode);
try
{
animationSpeed = playable.playableGraph.GetRootPlayable(0).GetSpeed();
}
catch (Exception e)
{
}
animationTime = playable.time;
playState = playable.state;
agentIsStoping = agent.isStopped;
agentRotationUpdate = agent.updateRotation;
agentTarget = agent.destination;
if (task != null)
{
taskData = task;
_data.container = taskData.containerCode;
_data.startDevice = taskData.fromLocation;
_data.endDevice = taskData.toLocation;
_data.currentAction = taskData.agvTaskStatus.ToString();
}
else
{
Rest();
}
}
}
public void OnInit()
{
//获取远程缓存
netWorkComponent.RemoteGetDataByLable(name, CheckValueAndInit);
}
///
/// 任务状态反馈实体
///
private class FeedBackEntity
{
public string systemCode = "DT";
public string houseCode = "DT";
public long taskCode;
public string carId;
public string taskType;
public string feedbackStatus;
public string feedbackLocation;
}
///
/// 车辆状态实体
///
[System.Serializable]
private class CarStatusEntity : DeviceStatus
{
public AgvTaskData task;
public AgvCarManage.CarTaskStatusEnum currentFeedBackStatus;
public Boolean agentIsStoping;
public Boolean agentRotationUpdate;
public SerializationVector target;
public DeviceStatus cargoStatus;
public DeviceStatus containerStatus;
}
///
/// 解析申请取放货坐标
///
///
///
///
///
public Vector3 LastPosition(List objects, string name)
{
//如果的库位
if (name.Contains("-"))
{
string[] str = name.Split('-');
GameObject game = objects.Find(v => string.Equals(v.name, "row_" + str[0]));
if (game != null)
{
return new Vector3(game.transform.position.x, transform.position.y, game.transform.position.z);
}
}
else
{
//设备
GameObject game = objects.Find(v => string.Equals(v.name, "device_" +name));
if (game != null)
{
return new Vector3(game.transform.position.x,transform.position.y,game.transform.position.z);
}
}
throw new Exception(string.Format("【{0}】未配置申请取放货坐标【{1}】",this.name,name));
}
private Quaternion RotationByDevice(string name)
{
if(name.Contains("shelf"))
{
return Quaternion.Euler(0,shelfRotation , 0);
}
else
{
foreach (var itme in forkAgvRotationSets)
{
GameObject obj = itme.device.Find(v => string.Equals(v.name, name));
if (obj != null)
{
return Quaternion.Euler(0, itme.deviceRotation, 0);
}
}
}
throw new Exception(string.Format("未找到该设备【{0}】旋转角度",name));
}
///
/// 在动画指定最小帧时触发
///
public void OnMinFPS()
{
//有货停止播放
if (HasGood)
{
playable.Pause();
}
}
public void OnMaxFPS()
{
if (currentFeedBackStatus == AgvCarManage.CarTaskStatusEnum.PUT_FINISHED)
{
//暂停播放
playable.Pause();
//解绑容器
Container container = forkCargo.transform.GetComponentInChildren();
container.transform.parent = null;
container.Agent.enabled = true;
//agv得退出一段距离
//倒退位置坐标
Vector3 applyPutVector = LastPosition(applyPutPosition, taskData.toLocation);
//开始代理
StartAgent(applyPutVector);
}
}
///
/// 校验当前目标是否是库位
///
///
public bool IsShelf(string name)
{
return name.Contains("-") || name.Contains("shelf");
}
public override void DataHandle(object data, object other = null)
{
}
public override void ProcessCompleted()
{
}
public override T DynamicData()
{
return (T)(object) _data;
}
public override void MouseSingleClick()
{
base.MouseSingleClick();
isOpenPop = !isOpenPop;
agvPopUI.Open(this, isOpenPop);
}
}