using UnityEngine; using System; using System.Collections.Generic; using UnityEngine.Events; using Octopus.Simulator.Networks; using Newtonsoft.Json; using Octopus.Simulator; #region class [Serializable] public class MoveDataClass_start { public string move_id; public string move_label; public string type; public float move_time; public int capacity; public int products_per_batch; public List input_queues; public string output_queue; public string defect_queue; public string required_resource; public float return_time; public int min_batch_size; public float loading_delay; public float unloading_delay; } [Serializable] public class MoveDataClass_loading { public string move_id; public string move_label; public int loaded_count; public List source_queues; public List source_stores; public float loading_delay; } [Serializable] public class MoveDataClass_Request_Resource { public string move_id; public string move_label; } [Serializable] public class MoveDataClass_Resource_Acquired { public string resource; } [Serializable] public class MoveDataClass_Speed_Factor_Applied { public float original; public float adjusted; } [Serializable] public class MoveDataClass_Move_Moving { public float time; public float loading_delay; public float unloading_delay; public MoveMovingInput input; public MoveMovingOutput output; } [Serializable] public class MoveMovingInput { public List queues; public List stores; } [Serializable] public class MoveMovingOutput { public string queue; public string store; public string defect_queue; public string defect_store; } [Serializable] public class MoveDataClass_Arrived { public int count; } [Serializable] public class MoveDataClass_Unloading_Defect { public string product_id; public string output_queue; public int output_queue_length; public float unloading_delay; } [Serializable] public class MoveDataClass_Unloading_Defect_Store { public string product_id; public string store_name; public int store_length; public float unloading_delay; } [Serializable] public class MoveDataClass_Unloading { public string product_id; public string output_queue; public int output_queue_length; public float unloading_delay; } [Serializable] public class MoveDataClass_Unloading_Store { public string product_id; public string store_name; public int store_queue_length; public float unloading_delay; } [Serializable] public class MoveDataClass_returning { public float return_time; } [Serializable] public class MoveDataClassStatistics { public statisticsMove statistics; } [Serializable] public class statisticsMove { public int total_moved; } #endregion public class SimulationModelMove : SimulationModel { string eventLoading = "move_loading"; string eventMove = "move_moving"; string eventUnloading = "move_unloading"; string eventSpeed = "move_speed_factor_applied"; string eventReturning = "move_returning"; [Header("Transport")] public List listProducts = new List(); public Transform productPos; public Vector3 productDistance = new Vector3(0, 0.321f, 0); int productCount = 0; int currentCount = 0; int totalMoved = 0; bool isFirstTransport = true; Transform origin = null; public Transform destination = null; public float arrivalTime = 0; public float elapsedTime = 0; Vector3 originalPos; Vector3 prevPos; void Update() { if (!simulationUI.isplaying) return; UpdateProductStacking(); UpdateMovement(); } private void UpdateProductStacking() { if (productCount != listProducts.Count) { productCount = listProducts.Count; // 단순하게 모두 같은 offset으로 배치 (필요 시 i 기반 offset으로 확장) foreach (var gb in listProducts) { if (gb != null) { gb.transform.localPosition = productDistance; } } } } private void UpdateMovement() { if (destination == null) return; elapsedTime += Time.deltaTime * WebParameters.speed; if (arrivalTime <= 0f) return; float t = elapsedTime / arrivalTime; if (t > 1f) { transform.position = destination.position; transform.forward = destination.forward; destination = null; } else { Vector3 newPos = Vector3.Lerp(originalPos, destination.position, t); transform.position = newPos; Vector3 dir = newPos - prevPos; dir.y = 0; if (dir.sqrMagnitude > 0.0001f) { dir.Normalize(); transform.forward = dir; } prevPos = newPos; } } public override void GetData(string data) { var wrapclass = JsonConvert.DeserializeObject(data); if (wrapclass == null || string.IsNullOrEmpty(wrapclass._event)) return; /* string eventLoading = "move_loading"; string eventMove = "move_moving"; string eventUnloading = "move_unloading"; string eventSpeed = "move_speed_factor_applied"; string eventReturning = "move_returning"; */ switch (wrapclass._event) { case "move_loading": LoadingCargo(wrapclass.data.ToString()); break; case "move_moving": Moving(wrapclass.data.ToString()); break; case "move_unloading": break; case "move_speed_factor_applied": break; case "move_returning": break; } if (wrapclass._event.Contains(eventMove)) { var moveData_Move = JsonConvert.DeserializeObject(wrapclass.data.ToString()); elapsedTime = 0; arrivalTime = moveData_Move.time; originalPos = transform.position; prevPos = transform.position; if (moveData_Move.input.queues != null && moveData_Move.input.queues.Count >= 1) { string queueID = moveData_Move.input.queues[0].ToString(); SimulationModel model = DataManager.I.GetModel(queueID); SimulationModelStore storeModel = model.GetComponent(); origin = storeModel.GetTransporterPosition(); } else if (moveData_Move.input.stores != null && moveData_Move.input.stores.Count >= 1) { string storeID = moveData_Move.input.stores[0].ToString(); SimulationModel model = DataManager.I.GetModel(storeID); SimulationModelStore storeModel = model.GetComponent(); origin = storeModel.GetTransporterPosition(); } if (!string.IsNullOrEmpty(moveData_Move.output.queue)) { SimulationModel model = DataManager.I.GetModel(moveData_Move.output.queue); SimulationModelStore storeModel = model.GetComponent(); destination = storeModel.GetTransporterPosition(); } else if (!string.IsNullOrEmpty(moveData_Move.output.store)) { SimulationModel model = DataManager.I.GetModel(moveData_Move.output.store); SimulationModelStore storeModel = model.GetComponent(); destination = storeModel.GetTransporterPosition(); } } else if (wrapclass._event.Contains(eventUnloading)) { string targetID = ""; if (wrapclass._event.Contains("defect_store")) { var moveData_unLoading = JsonConvert.DeserializeObject(wrapclass.data.ToString()); targetID = moveData_unLoading.store_name; } else if (wrapclass._event.Contains("defect")) { var moveData_unLoading = JsonConvert.DeserializeObject(wrapclass.data.ToString()); targetID = moveData_unLoading.output_queue; } else if (wrapclass._event.Contains("unloading_store")) { //Debug.Log(wrapclass.data.ToString()); var moveData_unLoading = JsonConvert.DeserializeObject(wrapclass.data.ToString()); targetID = moveData_unLoading.store_name; } else { var moveData_unLoading = JsonConvert.DeserializeObject(wrapclass.data.ToString()); targetID = moveData_unLoading.output_queue; } var model = DataManager.I.GetModel(targetID); if(model == null) { Debug.LogWarning($"Datamanager Model Null!!!!! TargetID:{targetID}"); return; } SimulationModelStore storeModel = model.GetComponent(); if (listProducts.Count > 0) { GameObject product = listProducts[0]; //storeModel.StoreProduct(product); listProducts.Remove(product); Destroy(product); } else { Debug.LogWarning("Trying to unload from empty transporter : " + nodeID); } } if (wrapclass._event.Contains("move_arrived")) { var moveData_arrived = JsonConvert.DeserializeObject(wrapclass.data.ToString()); currentCount -= moveData_arrived.count; SetBubble(currentCount); } if (wrapclass._event.Contains(eventSpeed)) { var moveData_Speed = JsonConvert.DeserializeObject(wrapclass.data.ToString()); float originalTime = moveData_Speed.original; float adjustedTime = moveData_Speed.adjusted; arrivalTime += adjustedTime - originalTime; elapsedTime = 0; originalPos = transform.position; prevPos = transform.position; } if (wrapclass._event.Contains(eventReturning)) { var moveData_Return = JsonConvert.DeserializeObject(wrapclass.data.ToString()); elapsedTime = 0; arrivalTime = moveData_Return.return_time; originalPos = transform.position; prevPos = transform.position; if (origin != null) { destination = origin; } } if (wrapclass._event.Contains("move_statistics_update")) { totalMoved = JsonConvert.DeserializeObject(wrapclass.data.ToString()).statistics.total_moved; SetBubble(totalMoved); } } private void LoadingCargo(string data) { var loading = JsonConvert.DeserializeObject(data); if (loading == null) return; currentCount = loading.loaded_count; SetBubble(currentCount); // 처음 운송이면 출발 위치 세팅 if (isFirstTransport) { string sourceId = GetFirstNonEmpty(loading.source_queues, loading.source_stores); if (!string.IsNullOrEmpty(sourceId)) { var sourceModel = DataManager.I.GetModel(sourceId) as SimulationModelStore; if (sourceModel != null) { transform.position = sourceModel.GetTransporterPosition()?.position ?? transform.position; } } isFirstTransport = false; } AddProducts(loading.loaded_count); } private void Moving(string data) { var moveData = JsonConvert.DeserializeObject(data); if (moveData == null) return; elapsedTime = 0f; arrivalTime = moveData.time; originalPos = transform.position; prevPos = transform.position; // origin 설정 (입력 큐 / 스토어) string inputId = GetFirstNonEmpty(moveData.input?.queues, moveData.input?.stores); if (!string.IsNullOrEmpty(inputId)) { var model = DataManager.I.GetModel(inputId) as SimulationModelStore; if (model != null) origin = model.GetTransporterPosition(); } // destination 설정 (출력 큐 / 스토어) if (!string.IsNullOrEmpty(moveData.output?.queue)) { var model = DataManager.I.GetModel(moveData.output.queue) as SimulationModelStore; if (model != null) destination = model.GetTransporterPosition(); } else if (!string.IsNullOrEmpty(moveData.output?.store)) { var model = DataManager.I.GetModel(moveData.output.store) as SimulationModelStore; if (model != null) destination = model.GetTransporterPosition(); } } private string GetFirstNonEmpty(List listA, List listB) { if (listA != null && listA.Count > 0) return listA[0]; if (listB != null && listB.Count > 0) return listB[0]; return string.Empty; } private void AddProducts(int count) { for (int i = 0; i < count; i++) { var product = ProductManager.Instance.SpawnProduct(); if (product == null) continue; product.GetComponent().SetParent(this.nodeID); product.transform.parent = productPos; product.transform.localPosition = Vector3.zero; product.transform.localRotation = Quaternion.identity; listProducts.Add(product); } } public override void SetBubble(object data) { string msg = $"{currentCount}/{totalMoved}"; if (currentBubble == null) { // 생성 currentBubble = Instantiate(bubbleUIPrefab, FindAnyObjectByType().transform); currentBubble.target = DataBubbleSocket; currentBubble.worldOffset = new Vector3(0, 2.0f, 0); // 필요에 따라 조절 currentBubble.GetComponent().SetAsFirstSibling(); } // 텍스트 갱신 currentBubble.SetMessage(msg); List datas = new List { currentCount.ToString(), totalMoved.ToString() }; currentBubble.SetDetail(datas, logicType.move, LogicUIManager.instance.GetItemLabelByID(nodeID)); } }