Files
XRLib/Assets/Scripts/Simulator/Components/Conveyor/ConveyorManager.cs
2025-11-04 11:02:02 +09:00

217 lines
7.4 KiB
C#

using sc.modeling.splines.runtime;
using Simulator.Data;
using Simulator.Data.Transport;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Splines;
using UVC.Core;
using UVC.Data;
using UVC.Data.Core;
using UVC.Data.Mqtt;
public class ConveyorPathMeta : MonoBehaviour
{
public string Name;
public string From;
public string To;
public float Speed;
public float Length;
public int Capacity;
}
public class ConveyorManager : SingletonScene<ConveyorManager>
{
[Header("Root & Visual")]
[SerializeField] private Transform rootParent; // 생성될 경로의 부모(없으면 빌더 자신)
[SerializeField] private float tangentScale = 0.25f; // 곡률(탄젠트 길이 비율)
[SerializeField]
ConveyorComponent splineprefab;
[SerializeField]
GameObject cube;
public Dictionary<string, ConveyorNode> Nodes = new Dictionary<string, ConveyorNode>();
public Dictionary<(string,string), ConveyorComponent> Paths = new Dictionary<(string, string), ConveyorComponent>();
public DataMapper conveyorStartDataMapper;
public DataMapper conveyorCompleteDataMapper;
protected override void Init()
{
var conveyorStartDataMask = new DataMask();
conveyorStartDataMask.ObjectName = "conveyor"; // AGV 객체의 이름을 설정합니다.
conveyorStartDataMask.ObjectIdKey = "component_id"; // AGV의 고유 식별자로 사용할 키를 설정합니다.
conveyorStartDataMask["component_id"] = "";
conveyorStartDataMask["event_name"] = "";
conveyorStartDataMask["timestamp"] = new DateTime();
conveyorStartDataMask["data"] = new DataMask()
{
["entity_id_original"] = "",
["start_node"] = "",
["end_node"] = "",
["travel_time"]=0.0f
};
conveyorStartDataMapper=new DataMapper(conveyorStartDataMask);
var conveyorCompleteDataMask = new DataMask();
conveyorCompleteDataMask.ObjectName = "conveyor"; // AGV 객체의 이름을 설정합니다.
conveyorCompleteDataMask.ObjectIdKey = "component_id"; // AGV의 고유 식별자로 사용할 키를 설정합니다.
conveyorCompleteDataMask["component_id"] = "";
conveyorCompleteDataMask["event_name"] = "";
conveyorCompleteDataMask["timestamp"] = new DateTime();
conveyorCompleteDataMask["data"] = new DataMask()
{
["entity_id_original"] = "",
["start_node"] = "",
["end_node"] = "",
};
conveyorCompleteDataMapper = new DataMapper(conveyorCompleteDataMask);
}
public void Build(List<ConveyorDataClass> datas)
{
if (datas==null||datas.Count <= 0)
{
return;
}
var data = datas[0];
if (rootParent == null) rootParent = transform;
if (data.nodes != null)
{
foreach (var n in data.nodes)
{
Nodes[n.name] = n;
}
}
foreach (var path in data.paths)
{
CreatePathGOWithSpline(path, Nodes[path.from_node], Nodes[path.to_node]);
}
SpawnJunction();
SubscribeConveyor(data);
}
public void SubscribeConveyor(ConveyorDataClass data)
{
DataRepository.Instance.MqttReceiver.AddTopic($"simulation/{SimulationConfig.SimulationCode}/components/+/{data.name}/+/node_started");
var mqttConfigConveyorStart = new MqttSubscriptionConfig($"simulation/{SimulationConfig.SimulationCode}/components/+/{data.name}/+/node_started");
mqttConfigConveyorStart.SetDataMapper(conveyorStartDataMapper);
mqttConfigConveyorStart.SetHandler(OnSetData);
DataRepository.Instance.MqttReceiver.Add(mqttConfigConveyorStart);
/*
DataRepository.Instance.MqttReceiver.AddTopic($"simulation/{SimulationConfig.SimulationCode}/components/+/{data.name}/+/node_completed");
var mqttConfigConveyorComplete = new MqttSubscriptionConfig($"simulation/{SimulationConfig.SimulationCode}/components/+/{data.name}/+/node_completed");
mqttConfigConveyorComplete.SetDataMapper(conveyorCompleteDataMapper);
mqttConfigConveyorComplete.SetHandler(OnUnSetData);
DataRepository.Instance.MqttReceiver.Add(mqttConfigConveyorComplete);
*/
}
private void CreatePathGOWithSpline(ConveyorPath path, ConveyorNode fromNode, ConveyorNode toNode)
{
TryGetNodePos(fromNode.name, out Vector3 fromPos);
TryGetNodePos(toNode.name, out Vector3 toPos);
string goName = path.name;
var go = Instantiate(splineprefab);
Paths.Add((fromNode.name,toNode.name), go);
go.transform.SetParent(rootParent, worldPositionStays: false);
var container = go.GetComponent<SplineContainer>();
var spline = new Spline();
Vector3 dir = (toPos - fromPos);
float dist = dir.magnitude;
Vector3 dirNorm = dist > 1e-5f ? dir / dist : Vector3.forward;
Vector3 tan = dirNorm * dist * Mathf.Clamp01(tangentScale);
var k0 = new BezierKnot(fromPos)
{
TangentOut = tan,
TangentIn = Vector3.zero
};
var k1 = new BezierKnot(toPos)
{
TangentIn = -tan,
TangentOut = Vector3.zero
};
spline.Add(k0, TangentMode.Broken);
spline.Add(k1, TangentMode.Broken);
container.Spline = spline;
var mesher = go.GetComponent<SplineMesher>();
if(string.Equals(fromNode.node_type, "junction"))
{
mesher.DetachCap(0);
}
if (string.Equals(toNode.node_type, "junction"))
{
mesher.DetachCap(1);
}
mesher.UpdateCaps();
mesher.Rebuild();
}
private void SpawnJunction()
{
foreach(var node in Nodes)
{
if (string.Equals(node.Value.node_type, "junction"))
{
var module = Instantiate(cube);
module.transform.position=ToVector3(node.Value.position);
}
}
}
private void OnSetData(IDataObject idata)
{
if (idata == null) return;
DataObject? obj = idata as DataObject;
if (obj == null) return;
//Debug.Log($"OnUpdateData:{obj}, {obj["data"]}");
var data = obj.GetDataObject("data");
var fromNodeName = data.GetString("start_node");
var toNodeName = data.GetString("end_node");
ConveyorComponent? conveyor = Paths[(fromNodeName,toNodeName)];
conveyor.SetModelData(obj);
}
private void OnUnSetData(IDataObject idata)
{
if (idata == null) return;
DataObject? obj = idata as DataObject;
if (obj == null) return;
//Debug.Log($"OnUpdateData:{obj}, {obj["data"]}");
var data = obj.GetDataObject("data");
var fromNodeName = data.GetString("start_node");
var toNodeName = data.GetString("end_node");
ConveyorComponent? conveyor = Paths[(fromNodeName, toNodeName)];
conveyor.UnSetModelData(obj);
}
private bool TryGetNodePos(string nodeName, out Vector3 pos)
{
if (!string.IsNullOrWhiteSpace(nodeName) && Nodes.TryGetValue(nodeName, out ConveyorNode node))
{
pos = ToVector3(node.position);
return true;
}
pos = default;
return false;
}
private Vector3 ToVector3(Position p)
{
return new Vector3(p.x, p.z, p.y);
}
}