using Simulator.Data; using System; using System.Collections.Generic; using UnityEngine; using UVC.UI.Window.PropertyWindow; using static Unity.VisualScripting.Member; public class RackProperty : MonoBehaviour { [SerializeField] private PropertyWindow propertyWindow; private void Awake() { propertyWindow.PropertyValueChanged += OnPropertyValueChanged; } public void SetProertyWindow(ComponentType type, ComponentDataBase data) { Debug.Log(data); InitRackProperty(data as RackDataClass); } void SaveChange(object source, object value, string name) { var path = PathIndexer.GetNodePath(source); Patch updateData = new Patch(); updateData.value = value; UpdateValueStack.AddPatch($"{path}.{name}", value); } public void InitRackProperty(RackDataClass rack) { List entries = new List { new StringProperty("name", "이름", rack.name) { IsReadOnly=true }, new StringProperty("label", "라벨", rack.label) { IsReadOnly=false }.Bind( setter: v => {rack.label = v;SaveChange(rack,v,"label"); } ), CreatePositionGroup(rack), new BoolProperty("limited","용량 무제한", rack.is_unlimited) { IsReadOnly=false }.Bind( setter: v => {rack.is_unlimited=v; SaveChange(rack,v,"is_unlimited"); } ), CreateRackLayoutGroup(rack), new IntProperty("entityperblock","칸당 개체 개수", rack.entity_count_per_block) { IsReadOnly=false }.Bind( setter: v => {rack.entity_count_per_block=v; SaveChange(rack,v,"entity_count_per_block"); } ), new ButtonProperty("InitializeButton","초기 재고 설정",""){ }.BindClick(()=>FindAnyObjectByType(FindObjectsInactive.Include).OpenRack(rack,PathIndexer.GetNodePath(rack))), new EnumProperty("display_mode_ReceicingTimePolicy", "입고 시간 정책",rack.receiving_time_policy.policy).Bind( setter: v=>{rack.receiving_time_policy=PolicyFactory.Create(v.ToString());SaveChange(rack,v.ToString(),"receiving_time_policy.type");} ), CreateReceivingTimePolicy_Constant(rack), CreateReceivingTimePolicy_Normal(rack), CreateReceivingTimePolicy_Uniform(rack), CreateReceivingTimePolicy_Exponential(rack), CreateReceivingTimePolicy_Triangular(rack), new EnumProperty("display_mode_ShippingTimePolicy", "출고 시간 정책",rack.shipping_time_policy.policy).Bind( setter: v=>{rack.shipping_time_policy=PolicyFactory.Create(v.ToString());SaveChange(rack,v.ToString(),"shipping_time_policy.type");} ), CreateShippingTimePolicy_Constant(rack), CreateShippingTimePolicy_Normal(rack), CreateShippingTimePolicy_Uniform(rack), CreateShippingTimePolicy_Exponential(rack), CreateShippingTimePolicy_Triangular(rack), new EnumProperty("display_mode_StorageCostPolicy", "보관 비용 정책",rack.storage_cost_policy.policy).Bind( setter: v=>{rack.storage_cost_policy=PolicyFactory.Create(v.ToString());SaveChange(rack,v.ToString(),"storage_cost_policy.type");} ), CreateStorageCostPolicy_Constant(rack), CreateStorageCostPolicy_Normal(rack), CreateStorageCostPolicy_Uniform(rack), CreateStorageCostPolicy_Exponential(rack), CreateStorageCostPolicy_Triangular(rack), new BoolProperty("fms_input_enabled","입력에 FMS 사용", rack.fms_input_enabled) { IsReadOnly=true }.Bind( setter: v => {rack.fms_input_enabled=v; SaveChange(rack,v,"fms_input_enabled"); } ), new BoolProperty("fms_output_enabled","출력에 FMS 사용", rack.fms_output_enabled) { IsReadOnly=true }.Bind( setter: v => {rack.fms_output_enabled=v; SaveChange(rack,v,"fms_output_enabled"); } ), }; propertyWindow.LoadMixedProperties(entries); HandleDisplayModeChanged_ReceivingTimePolicy(rack.receiving_time_policy.policy.ToString()); HandleDisplayModeChanged_ShippingTimePolicy(rack.shipping_time_policy.policy.ToString()); HandleDisplayModeChanged_StorageCostPolicy(rack.storage_cost_policy.policy.ToString()); } private void OnPropertyValueChanged(object sender, PropertyValueChangedEventArgs e) { Debug.Log($"[PropertyChanged] Id:{e.PropertyId}, Type:{e.PropertyType}, Value:{e.NewValue}"); // 동적 그룹 표시/비표시 테스트 if (e.PropertyId == "display_mode_ReceicingTimePolicy") { string selectedMode = e.NewValue.ToString(); HandleDisplayModeChanged_ReceivingTimePolicy(selectedMode); } if (e.PropertyId == "display_mode_ShippingTimePolicy") { string selectedMode = e.NewValue.ToString(); HandleDisplayModeChanged_ShippingTimePolicy(selectedMode); } if (e.PropertyId == "display_mode_StorageCostPolicy") { string selectedMode = e.NewValue.ToString(); HandleDisplayModeChanged_StorageCostPolicy(selectedMode); } if(e.PropertyId== "limited") { bool flag=Convert.ToBoolean(e.NewValue); propertyWindow.SetPropertyEnabled("x", !flag); propertyWindow.SetPropertyEnabled("z", !flag); propertyWindow.SetPropertyEnabled("entityperblock", !flag); propertyWindow.SetPropertyEnabled("InitializeButton", !flag); } } private PropertyGroup CreatePositionGroup(RackDataClass rack) { var group = new PropertyGroup("rack_position", "위치 및 회전", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("x_position", "X 좌표(m)", rack.physical.position.x) { }.Bind( setter: v => {rack.physical.position.x = v;SaveChange(rack,v,"physical.position.x"); } ), new FloatProperty("y_position", "y 좌표(m)", rack.physical.position.y) { }.Bind( setter: v => {rack.physical.position.y = v;SaveChange(rack,v,"physical.position.y"); } ), new FloatProperty("orientation", "회전(°)", rack.physical.orientation) { }.Bind( setter: v => {rack.physical.orientation = v;SaveChange(rack,v,"physical.orientation");propertyWindow.ApplyExternalValue("orientation",RotationSnap.snaporientaion(v),false); } ), }); return group; } private PropertyGroup CreateRackLayoutGroup(RackDataClass rack) { var group = new PropertyGroup("racklayout", "랙 구조", isExpanded: true); group.AddItems(new IPropertyItem[] { new IntProperty("x", "행 개수(x)", rack.rack_layout.x) { }.Bind( setter: v => {rack.rack_layout.x = v;SaveChange(rack,v,"rack_layout.x");CleanupByLayoutShrink(rack); } ), new IntProperty("y", "열 개수(y)", rack.rack_layout.z) { IsReadOnly=true }.Bind( setter: v => {rack.rack_layout.z = v;SaveChange(rack,v,"rack_layout.z");CleanupByLayoutShrink(rack); } ), new IntProperty("z", "층 수(z)", rack.rack_layout.y) { }.Bind( setter: v => {rack.rack_layout.y = v;SaveChange(rack,v,"rack_layout.y");CleanupByLayoutShrink(rack); } ), }); return group; } #region 입고 시간 정책 private PropertyGroup CreateReceivingTimePolicy_Constant(RackDataClass rack) { var group = new PropertyGroup("ReceivingTimePolicy_Constant", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("ReceivingTimePolicy_Constant_Value", "상수 값", (rack.receiving_time_policy as Policy_Constant)?.value??0f) { }.Bind( setter: v => {(rack.receiving_time_policy as Policy_Constant).value = v;SaveChange(rack,v,"receiving_time_policy.value"); } ), }); return group; } private PropertyGroup CreateReceivingTimePolicy_Normal(RackDataClass rack) { var group = new PropertyGroup("ReceivingTimePolicy_Normal", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("ReceivingTimePolicy_Normal_Mean", "정규 분포 표준치", (rack.receiving_time_policy as Policy_Normal) ?.mean ?? 0f) { }.Bind( setter: v => {(rack.receiving_time_policy as Policy_Normal).mean = v;SaveChange(rack,v,"receiving_time_policy.mean"); } ), new FloatProperty("ReceivingTimePolicy_Normal_Gap", "정규 분포 표준 편차", (rack.receiving_time_policy as Policy_Normal) ?.stddev ?? 0f) { }.Bind( setter: v => {(rack.receiving_time_policy as Policy_Normal).stddev = v;SaveChange(rack,v,"receiving_time_policy.stddev"); } ), }); return group; } private PropertyGroup CreateReceivingTimePolicy_Uniform(RackDataClass rack) { var group = new PropertyGroup("ReceivingTimePolicy_Uniform", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("ReceivingTimePolicy_Uniform_Min", "균등 분포 최소값", (rack.receiving_time_policy as Policy_Uniform) ?.min_val ?? 0f) { }.Bind( setter: v => {(rack.receiving_time_policy as Policy_Uniform).min_val = v;SaveChange(rack,v,"receiving_time_policy.min_val"); } ), new FloatProperty("ReceivingTimePolicy_Uniform_Max", "균등 분포 최대값", (rack.receiving_time_policy as Policy_Uniform) ?.max_val ?? 0f) { }.Bind( setter: v => {(rack.receiving_time_policy as Policy_Uniform).max_val = v;SaveChange(rack,v,"receiving_time_policy.max_val"); } ), }); return group; } private PropertyGroup CreateReceivingTimePolicy_Exponential(RackDataClass rack) { var group = new PropertyGroup("ReceivingTimePolicy_Exponential", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("ReceivingTimePolicy_Exponential_Mean", "지수 분포 평균치", (rack.receiving_time_policy as Policy_Exponential) ?.mean ?? 0f) { }.Bind( setter: v => {(rack.receiving_time_policy as Policy_Exponential).mean = v;SaveChange(rack,v,"receiving_time_policy.mean"); } ), }); return group; } private PropertyGroup CreateReceivingTimePolicy_Triangular(RackDataClass rack) { var group = new PropertyGroup("ReceivingTimePolicy_Triangular", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("ReceivingTimePolicy_Triangular_Min", "지수 분포 최소값", (rack.receiving_time_policy as Policy_Triangular) ?.min_val ?? 0f) { }.Bind( setter: v => {(rack.receiving_time_policy as Policy_Triangular).min_val = v;SaveChange(rack,v,"receiving_time_policy.min_val"); } ), new FloatProperty("ReceivingTimePolicy_Triangular_Mean", "지수 분포 최빈값", (rack.receiving_time_policy as Policy_Triangular) ?.mode ?? 0f) { }.Bind( setter: v => {(rack.receiving_time_policy as Policy_Triangular).mode = v;SaveChange(rack,v,"receiving_time_policy.mode"); } ), new FloatProperty("ReceivingTimePolicy_Triangular_Max", "지수 분포 최대값", (rack.receiving_time_policy as Policy_Triangular) ?.max_val ?? 0f) { }.Bind( setter: v => {(rack.receiving_time_policy as Policy_Triangular).max_val = v;SaveChange(rack,v,"receiving_time_policy.max_val"); } ), }); return group; } private void HandleDisplayModeChanged_ReceivingTimePolicy(string mode) { // 모든 조건부 그룹 숨김 propertyWindow.SetGroupVisibility("ReceivingTimePolicy_Constant", false); propertyWindow.SetGroupVisibility("ReceivingTimePolicy_Normal", false); propertyWindow.SetGroupVisibility("ReceivingTimePolicy_Uniform", false); propertyWindow.SetGroupVisibility("ReceivingTimePolicy_Exponential", false); propertyWindow.SetGroupVisibility("ReceivingTimePolicy_Triangular", false); // 선택된 모드에 따라 해당 그룹만 표시 switch (mode) { case "Constant": propertyWindow.SetGroupVisibility("ReceivingTimePolicy_Constant", true); break; case "Normal": propertyWindow.SetGroupVisibility("ReceivingTimePolicy_Normal", true); break; case "Uniform": propertyWindow.SetGroupVisibility("ReceivingTimePolicy_Uniform", true); break; case "Exponential": propertyWindow.SetGroupVisibility("ReceivingTimePolicy_Exponential", true); break; case "Triangular": propertyWindow.SetGroupVisibility("ReceivingTimePolicy_Triangular", true); break; } } #endregion #region 출고 시간 정책 private PropertyGroup CreateShippingTimePolicy_Constant(RackDataClass rack) { var group = new PropertyGroup("ShippingTimePolicy_Constant", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("ShippingTimePolicy_Constant_Value", "상수 값", (rack.shipping_time_policy as Policy_Constant)?.value??0f) { }.Bind( setter: v => {(rack.shipping_time_policy as Policy_Constant).value = v;SaveChange(rack,v,"shipping_time_policy.value"); } ), }); return group; } private PropertyGroup CreateShippingTimePolicy_Normal(RackDataClass rack) { var group = new PropertyGroup("ShippingTimePolicy_Normal", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("ShippingTimePolicy_Normal_Mean", "정규 분포 표준치", (rack.shipping_time_policy as Policy_Normal) ?.mean ?? 0f) { }.Bind( setter: v => {(rack.shipping_time_policy as Policy_Normal).mean = v;SaveChange(rack,v,"shipping_time_policy.mean"); } ), new FloatProperty("ShippingTimePolicy_Normal_Gap", "정규 분포 표준 편차", (rack.shipping_time_policy as Policy_Normal) ?.stddev ?? 0f) { }.Bind( setter: v => {(rack.shipping_time_policy as Policy_Normal).stddev = v;SaveChange(rack,v,"shipping_time_policy.stddev"); } ), }); return group; } private PropertyGroup CreateShippingTimePolicy_Uniform(RackDataClass rack) { var group = new PropertyGroup("ShippingTimePolicy_Uniform", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("ShippingTimePolicy_Uniform_Min", "균등 분포 최소값", (rack.shipping_time_policy as Policy_Uniform) ?.min_val ?? 0f) { }.Bind( setter: v => {(rack.shipping_time_policy as Policy_Uniform).min_val = v;SaveChange(rack,v,"shipping_time_policy.min_val"); } ), new FloatProperty("ShippingTimePolicy_Uniform_Max", "균등 분포 최대값", (rack.shipping_time_policy as Policy_Uniform) ?.max_val ?? 0f) { }.Bind( setter: v => {(rack.shipping_time_policy as Policy_Uniform).max_val = v;SaveChange(rack,v,"shipping_time_policy.max_val"); } ), }); return group; } private PropertyGroup CreateShippingTimePolicy_Exponential(RackDataClass rack) { var group = new PropertyGroup("ShippingTimePolicy_Exponential", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("ShippingTimePolicy_Exponential_Mean", "지수 분포 평균치", (rack.shipping_time_policy as Policy_Exponential) ?.mean ?? 0f) { }.Bind( setter: v => {(rack.shipping_time_policy as Policy_Exponential).mean = v;SaveChange(rack,v,"shipping_time_policy.mean"); } ), }); return group; } private PropertyGroup CreateShippingTimePolicy_Triangular(RackDataClass rack) { var group = new PropertyGroup("ShippingTimePolicy_Triangular", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("ShippingTimePolicy_Triangular_Min", "지수 분포 최소값", (rack.shipping_time_policy as Policy_Triangular) ?.min_val ?? 0f) { }.Bind( setter: v => {(rack.shipping_time_policy as Policy_Triangular).min_val = v;SaveChange(rack,v,"shipping_time_policy.min_val"); } ), new FloatProperty("ShippingTimePolicy_Triangular_Mean", "지수 분포 최빈값", (rack.shipping_time_policy as Policy_Triangular) ?.mode ?? 0f) { }.Bind( setter: v => {(rack.shipping_time_policy as Policy_Triangular).mode = v;SaveChange(rack,v,"shippin3g_time_policy.mode"); } ), new FloatProperty("ShippingTimePolicy_Triangular_Max", "지수 분포 최대값", (rack.shipping_time_policy as Policy_Triangular) ?.max_val ?? 0f) { }.Bind( setter: v => {(rack.shipping_time_policy as Policy_Triangular).max_val = v;SaveChange(rack,v,"shipping_time_policy.max_val"); } ), }); return group; } private void HandleDisplayModeChanged_ShippingTimePolicy(string mode) { // 모든 조건부 그룹 숨김 propertyWindow.SetGroupVisibility("ShippingTimePolicy_Constant", false); propertyWindow.SetGroupVisibility("ShippingTimePolicy_Normal", false); propertyWindow.SetGroupVisibility("ShippingTimePolicy_Uniform", false); propertyWindow.SetGroupVisibility("ShippingTimePolicy_Exponential", false); propertyWindow.SetGroupVisibility("ShippingTimePolicy_Triangular", false); // 선택된 모드에 따라 해당 그룹만 표시 switch (mode) { case "Constant": propertyWindow.SetGroupVisibility("ShippingTimePolicy_Constant", true); break; case "Normal": propertyWindow.SetGroupVisibility("ShippingTimePolicy_Normal", true); break; case "Uniform": propertyWindow.SetGroupVisibility("ShippingTimePolicy_Uniform", true); break; case "Exponential": propertyWindow.SetGroupVisibility("ShippingTimePolicy_Exponential", true); break; case "Triangular": propertyWindow.SetGroupVisibility("ShippingTimePolicy_Triangular", true); break; } } #endregion #region 보관 비용 정책 private PropertyGroup CreateStorageCostPolicy_Constant(RackDataClass rack) { var group = new PropertyGroup("StorageCostPolicy_Constant", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("StorageCostPolicy_Constant_Value", "상수 값", (rack.storage_cost_policy as Policy_Constant) ?.value ?? 0f) { }.Bind( setter: v => {(rack.storage_cost_policy as Policy_Constant).value = v;SaveChange(rack,v,"storage_cost_policy.value"); } ), }); return group; } private PropertyGroup CreateStorageCostPolicy_Normal(RackDataClass rack) { var group = new PropertyGroup("StorageCostPolicy_Normal", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("StorageCostPolicy_Normal_Mean", "정규 분포 표준치", (rack.storage_cost_policy as Policy_Normal) ?.mean ?? 0f) { }.Bind( setter: v => {(rack.storage_cost_policy as Policy_Normal).mean = v;SaveChange(rack,v,"storage_cost_policy.mean"); } ), new FloatProperty("StorageCostPolicy_Normal_Gap", "정규 분포 표준 편차", (rack.storage_cost_policy as Policy_Normal) ?.stddev ?? 0f) { }.Bind( setter: v => {(rack.storage_cost_policy as Policy_Normal).stddev = v;SaveChange(rack,v,"storage_cost_policy.stddev"); } ), }); return group; } private PropertyGroup CreateStorageCostPolicy_Uniform(RackDataClass rack) { var group = new PropertyGroup("StorageCostPolicy_Uniform", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("StorageCostPolicy_Uniform_Min", "균등 분포 최소값", (rack.storage_cost_policy as Policy_Uniform) ?.min_val ?? 0f) { }.Bind( setter: v => {(rack.storage_cost_policy as Policy_Uniform).min_val = v;SaveChange(rack,v,"storage_cost_policy.min_val"); } ), new FloatProperty("StorageCostPolicy_Uniform_Max", "균등 분포 최대값", (rack.storage_cost_policy as Policy_Uniform) ?.max_val ?? 0f) { }.Bind( setter: v => {(rack.storage_cost_policy as Policy_Uniform).max_val = v;SaveChange(rack,v,"storage_cost_policy.max_val"); } ), }); return group; } private PropertyGroup CreateStorageCostPolicy_Exponential(RackDataClass rack) { var group = new PropertyGroup("StorageCostPolicy_Exponential", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("StorageCostPolicy_Exponential_Mean", "지수 분포 평균치", (rack.storage_cost_policy as Policy_Exponential) ?.mean ?? 0f) { }.Bind( setter: v => {(rack.storage_cost_policy as Policy_Exponential).mean = v;SaveChange(rack,v,"storage_cost_policy.mean"); } ), }); return group; } private PropertyGroup CreateStorageCostPolicy_Triangular(RackDataClass rack) { var group = new PropertyGroup("StorageCostPolicy_Triangular", "", isExpanded: true); group.AddItems(new IPropertyItem[] { new FloatProperty("StorageCostPolicy_Triangular_Min", "지수 분포 최소값", (rack.storage_cost_policy as Policy_Triangular) ?.min_val ?? 0f) { }.Bind( setter: v => {(rack.storage_cost_policy as Policy_Triangular).min_val = v;SaveChange(rack,v,"storage_cost_policy.min_val"); } ), new FloatProperty("StorageCostPolicy_Triangular_Mean", "지수 분포 최빈값", (rack.storage_cost_policy as Policy_Triangular) ?.mode ?? 0f) { }.Bind( setter: v => {(rack.storage_cost_policy as Policy_Triangular).mode = v;SaveChange(rack,v,"storage_cost_policy.mode"); } ), new FloatProperty("StorageCostPolicy_Triangular_Max", "지수 분포 최대값", (rack.storage_cost_policy as Policy_Triangular) ?.max_val ?? 0f) { }.Bind( setter: v => {(rack.storage_cost_policy as Policy_Triangular).max_val = v;SaveChange(rack,v,"storage_cost_policy.max_val"); } ), }); return group; } private void HandleDisplayModeChanged_StorageCostPolicy(string mode) { // 모든 조건부 그룹 숨김 propertyWindow.SetGroupVisibility("StorageCostPolicy_Constant", false); propertyWindow.SetGroupVisibility("StorageCostPolicy_Normal", false); propertyWindow.SetGroupVisibility("StorageCostPolicy_Uniform", false); propertyWindow.SetGroupVisibility("StorageCostPolicy_Exponential", false); propertyWindow.SetGroupVisibility("StorageCostPolicy_Triangular", false); // 선택된 모드에 따라 해당 그룹만 표시 switch (mode) { case "Constant": propertyWindow.SetGroupVisibility("StorageCostPolicy_Constant", true); break; case "Normal": propertyWindow.SetGroupVisibility("StorageCostPolicy_Normal", true); break; case "Uniform": propertyWindow.SetGroupVisibility("StorageCostPolicy_Uniform", true); break; case "Exponential": propertyWindow.SetGroupVisibility("StorageCostPolicy_Exponential", true); break; case "Triangular": propertyWindow.SetGroupVisibility("StorageCostPolicy_Triangular", true); break; } } #endregion public void CleanupByLayoutShrink(RackDataClass rack) { if (rack == null) return; rack.initialize.RemoveAll(e => IsOutOfNewBounds(e, rack.rack_layout)); SaveChange(rack, rack.initialize, "initialize"); } private bool IsOutOfNewBounds(InitializeEntry e, rack_layout rack_layout) { if (e == null || e.from_position == null || e.to_position == null) return true; // 범위 정규화 var minX = Math.Min(e.from_position.x, e.to_position.x); var maxX = Math.Max(e.from_position.x, e.to_position.x); var minY = Math.Min(e.from_position.y, e.to_position.y); var maxY = Math.Max(e.from_position.y, e.to_position.y); var minZ = Math.Min(e.from_position.z, e.to_position.z); var maxZ = Math.Max(e.from_position.z, e.to_position.z); // 방어(원하면 0-based로 바꾸거나, min<1 허용 등 정책 조정) if (minX < 1 || minY < 1 || minZ < 1) return true; // “감소된(잘린) 영역과 겹치면 삭제” == “새 레이아웃 박스에 완전히 포함되지 않으면 삭제” if (maxX > rack_layout.x) return true; if (maxY > rack_layout.y) return true; if (maxZ > rack_layout.z) return true; return false; } }