리팩토링 중
This commit is contained in:
249
.editorconfig
Normal file
249
.editorconfig
Normal file
@@ -0,0 +1,249 @@
|
||||
# 상위 디렉터리에서 .editorconfig 설정을 상속하려면 아래 행을 제거하세요.
|
||||
root = true
|
||||
|
||||
# C# 파일
|
||||
[*.cs]
|
||||
|
||||
#### 코어 EditorConfig 옵션 ####
|
||||
|
||||
# 들여쓰기 및 간격
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
tab_width = 4
|
||||
|
||||
# 새 줄 기본 설정
|
||||
end_of_line = crlf
|
||||
insert_final_newline = false
|
||||
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
#### .NET 코드 작업 ####
|
||||
|
||||
# 멤버 입력
|
||||
dotnet_hide_advanced_members = false
|
||||
dotnet_member_insertion_location = with_other_members_of_the_same_kind
|
||||
dotnet_property_generation_behavior = prefer_throwing_properties
|
||||
|
||||
# 기호 검색
|
||||
dotnet_search_reference_assemblies = true
|
||||
|
||||
#### .NET 코딩 규칙 ####
|
||||
|
||||
# Using 구성
|
||||
dotnet_separate_import_directive_groups = false
|
||||
dotnet_sort_system_directives_first = false
|
||||
file_header_template = unset
|
||||
|
||||
# this. 및 Me. 기본 설정
|
||||
dotnet_style_qualification_for_event = false
|
||||
dotnet_style_qualification_for_field = false
|
||||
dotnet_style_qualification_for_method = false
|
||||
dotnet_style_qualification_for_property = false
|
||||
|
||||
# 언어 키워드 및 BCL 형식 기본 설정
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true
|
||||
dotnet_style_predefined_type_for_member_access = true
|
||||
|
||||
# 괄호 기본 설정
|
||||
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
|
||||
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
|
||||
dotnet_style_parentheses_in_other_operators = never_if_unnecessary
|
||||
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity
|
||||
|
||||
# 한정자 기본 설정
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members
|
||||
|
||||
# 식 수준 기본 설정
|
||||
dotnet_prefer_system_hash_code = true
|
||||
dotnet_style_coalesce_expression = true
|
||||
dotnet_style_collection_initializer = true
|
||||
dotnet_style_explicit_tuple_names = true
|
||||
dotnet_style_namespace_match_folder = true
|
||||
dotnet_style_null_propagation = true
|
||||
dotnet_style_object_initializer = true
|
||||
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||
dotnet_style_prefer_auto_properties = true
|
||||
dotnet_style_prefer_collection_expression = when_types_loosely_match
|
||||
dotnet_style_prefer_compound_assignment = true
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true
|
||||
dotnet_style_prefer_conditional_expression_over_return = true
|
||||
dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true
|
||||
dotnet_style_prefer_inferred_tuple_names = true
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true
|
||||
dotnet_style_prefer_simplified_boolean_expressions = true
|
||||
dotnet_style_prefer_simplified_interpolation = true
|
||||
|
||||
# 필드 기본 설정
|
||||
dotnet_style_readonly_field = true
|
||||
|
||||
# 매개 변수 기본 설정
|
||||
dotnet_code_quality_unused_parameters = all
|
||||
|
||||
# 비표시 오류(Suppression) 기본 설정
|
||||
dotnet_remove_unnecessary_suppression_exclusions = none
|
||||
|
||||
# 새 줄 기본 설정
|
||||
dotnet_style_allow_multiple_blank_lines_experimental = true
|
||||
dotnet_style_allow_statement_immediately_after_block_experimental = true
|
||||
|
||||
#### C# 코딩 규칙 ####
|
||||
|
||||
# var 기본 설정
|
||||
csharp_style_var_elsewhere = false
|
||||
csharp_style_var_for_built_in_types = false
|
||||
csharp_style_var_when_type_is_apparent = false
|
||||
|
||||
# 식 본문 멤버
|
||||
csharp_style_expression_bodied_accessors = true
|
||||
csharp_style_expression_bodied_constructors = false
|
||||
csharp_style_expression_bodied_indexers = true
|
||||
csharp_style_expression_bodied_lambdas = true
|
||||
csharp_style_expression_bodied_local_functions = false
|
||||
csharp_style_expression_bodied_methods = false
|
||||
csharp_style_expression_bodied_operators = false
|
||||
csharp_style_expression_bodied_properties = true
|
||||
|
||||
# 패턴 일치 기본 설정
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true
|
||||
csharp_style_prefer_extended_property_pattern = true
|
||||
csharp_style_prefer_not_pattern = true
|
||||
csharp_style_prefer_pattern_matching = true
|
||||
csharp_style_prefer_switch_expression = true
|
||||
|
||||
# Null 검사 기본 설정
|
||||
csharp_style_conditional_delegate_call = true
|
||||
|
||||
# 한정자 기본 설정
|
||||
csharp_prefer_static_anonymous_function = true
|
||||
csharp_prefer_static_local_function = true
|
||||
csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async
|
||||
csharp_style_prefer_readonly_struct = true
|
||||
csharp_style_prefer_readonly_struct_member = true
|
||||
|
||||
# 코드 블록 기본 설정
|
||||
csharp_prefer_braces = true
|
||||
csharp_prefer_simple_using_statement = true
|
||||
csharp_prefer_system_threading_lock = true
|
||||
csharp_style_namespace_declarations = block_scoped
|
||||
csharp_style_prefer_method_group_conversion = true
|
||||
csharp_style_prefer_primary_constructors = true
|
||||
csharp_style_prefer_top_level_statements = true
|
||||
|
||||
# 식 수준 기본 설정
|
||||
csharp_prefer_simple_default_expression = true
|
||||
csharp_style_deconstructed_variable_declaration = true
|
||||
csharp_style_implicit_object_creation_when_type_is_apparent = true
|
||||
csharp_style_inlined_variable_declaration = true
|
||||
csharp_style_prefer_implicitly_typed_lambda_expression = true
|
||||
csharp_style_prefer_index_operator = true
|
||||
csharp_style_prefer_local_over_anonymous_function = true
|
||||
csharp_style_prefer_null_check_over_type_check = true
|
||||
csharp_style_prefer_range_operator = true
|
||||
csharp_style_prefer_tuple_swap = true
|
||||
csharp_style_prefer_unbound_generic_type_in_nameof = true
|
||||
csharp_style_prefer_utf8_string_literals = true
|
||||
csharp_style_throw_expression = true
|
||||
csharp_style_unused_value_assignment_preference = discard_variable
|
||||
csharp_style_unused_value_expression_statement_preference = discard_variable
|
||||
|
||||
# 'using' 지시문 기본 설정
|
||||
csharp_using_directive_placement = outside_namespace
|
||||
|
||||
# 새 줄 기본 설정
|
||||
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true
|
||||
csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true
|
||||
csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true
|
||||
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true
|
||||
csharp_style_allow_embedded_statements_on_same_line_experimental = true
|
||||
|
||||
#### C# 서식 설정 규칙 ####
|
||||
|
||||
# 새 줄 기본 설정
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_new_line_between_query_expression_clauses = true
|
||||
|
||||
# 들여쓰기 기본 설정
|
||||
csharp_indent_block_contents = true
|
||||
csharp_indent_braces = false
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_case_contents_when_block = true
|
||||
csharp_indent_labels = one_less_than_current
|
||||
csharp_indent_switch_labels = true
|
||||
|
||||
# 공간 기본 설정
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
csharp_space_after_comma = true
|
||||
csharp_space_after_dot = false
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_after_semicolon_in_for_statement = true
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_around_declaration_statements = false
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
csharp_space_before_comma = false
|
||||
csharp_space_before_dot = false
|
||||
csharp_space_before_open_square_brackets = false
|
||||
csharp_space_before_semicolon_in_for_statement = false
|
||||
csharp_space_between_empty_square_brackets = false
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_parentheses = false
|
||||
csharp_space_between_square_brackets = false
|
||||
|
||||
# 기본 설정 래핑
|
||||
csharp_preserve_single_line_blocks = true
|
||||
csharp_preserve_single_line_statements = true
|
||||
|
||||
#### 명명 스타일 ####
|
||||
|
||||
# 명명 규칙
|
||||
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||
|
||||
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||
|
||||
# 기호 사양
|
||||
|
||||
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.interface.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.types.required_modifiers =
|
||||
|
||||
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||
|
||||
# 명명 스타일
|
||||
|
||||
dotnet_naming_style.pascal_case.required_prefix =
|
||||
dotnet_naming_style.pascal_case.required_suffix =
|
||||
dotnet_naming_style.pascal_case.word_separator =
|
||||
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||
|
||||
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||
dotnet_naming_style.begins_with_i.required_suffix =
|
||||
dotnet_naming_style.begins_with_i.word_separator =
|
||||
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||
@@ -62,6 +62,8 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: 836d6527858b7494297e122eb69601fd, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
inputField: {fileID: 4095973766915737330}
|
||||
searchButton: {fileID: 3154601933036176681}
|
||||
--- !u!114 &1278875195337434962
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -69,20 +71,20 @@ MonoBehaviour:
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1928778550412568362}
|
||||
m_Enabled: 0
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 0}
|
||||
m_RaycastTarget: 0
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 694507160, guid: fe40b90c67f2f75419562a6fe1003d5b, type: 3}
|
||||
m_Sprite: {fileID: 0}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
||||
@@ -390,7 +390,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 887145076, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
||||
@@ -198,7 +198,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 887145076, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
@@ -340,7 +340,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: -27720893, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
@@ -521,7 +521,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 887145076, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
||||
@@ -198,7 +198,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 887145076, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
@@ -275,7 +275,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: -27720893, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
@@ -394,7 +394,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: -27720893, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
||||
@@ -10,9 +10,8 @@ GameObject:
|
||||
m_Component:
|
||||
- component: {fileID: 3316965954832882549}
|
||||
- component: {fileID: 3078805581424071851}
|
||||
- component: {fileID: 3314964221659757925}
|
||||
- component: {fileID: 4097232251975178814}
|
||||
- component: {fileID: 5836275117983516284}
|
||||
- component: {fileID: 4097232251975178814}
|
||||
m_Layer: 5
|
||||
m_Name: UILoading
|
||||
m_TagString: Untagged
|
||||
@@ -29,7 +28,7 @@ RectTransform:
|
||||
m_GameObject: {fileID: 3247177050376678973}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 88171281312113102}
|
||||
@@ -53,26 +52,8 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: 0575433bbc705184a91373cc1596e713, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!222 &3314964221659757925
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3247177050376678973}
|
||||
m_CullTransparentMesh: 0
|
||||
--- !u!225 &4097232251975178814
|
||||
CanvasGroup:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3247177050376678973}
|
||||
m_Enabled: 1
|
||||
m_Alpha: 1
|
||||
m_Interactable: 1
|
||||
m_BlocksRaycasts: 1
|
||||
m_IgnoreParentGroups: 0
|
||||
canvasGroup: {fileID: 4097232251975178814}
|
||||
loadinImage: {fileID: 5537735754607583444}
|
||||
--- !u!223 &5836275117983516284
|
||||
Canvas:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -94,8 +75,20 @@ Canvas:
|
||||
m_AdditionalShaderChannelsFlag: 0
|
||||
m_UpdateRectTransformForStandalone: 0
|
||||
m_SortingLayerID: 0
|
||||
m_SortingOrder: 0
|
||||
m_SortingOrder: 100
|
||||
m_TargetDisplay: 0
|
||||
--- !u!225 &4097232251975178814
|
||||
CanvasGroup:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3247177050376678973}
|
||||
m_Enabled: 1
|
||||
m_Alpha: 1
|
||||
m_Interactable: 1
|
||||
m_BlocksRaycasts: 1
|
||||
m_IgnoreParentGroups: 0
|
||||
--- !u!1 &3720191927695001841
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -131,7 +124,7 @@ RectTransform:
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 128, y: 128}
|
||||
m_SizeDelta: {x: 32, y: 32}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &7648764534251572644
|
||||
CanvasRenderer:
|
||||
|
||||
@@ -926,7 +926,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 887145076, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
||||
@@ -926,7 +926,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 887145076, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
||||
@@ -138,7 +138,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 887145076, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
||||
@@ -173,7 +173,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 887145076, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
||||
@@ -281,7 +281,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: -27720893, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
||||
@@ -145,7 +145,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: -27720893, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
@@ -172,7 +172,7 @@ GameObject:
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &117691393038772277
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -281,7 +281,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: -27720893, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
||||
@@ -162,7 +162,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 887145076, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
||||
@@ -145,7 +145,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: -27720893, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
||||
@@ -173,7 +173,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 887145076, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
||||
@@ -145,7 +145,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: -27720893, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
||||
@@ -281,7 +281,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: -27720893, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
||||
@@ -162,7 +162,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 887145076, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
||||
@@ -145,7 +145,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: -27720893, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
||||
@@ -66,7 +66,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: -27720893, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: e5829cbc100001646956a9c3ed4e33c5, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
@@ -345,7 +345,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 887145076, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Sprite: {fileID: 21300000, guid: 4cf3568ca3f55f64cb11447d139d7a3d, type: 3}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
|
||||
@@ -39,6 +39,8 @@ namespace SampleProject
|
||||
{
|
||||
if (AppConfig.LoadConfig())
|
||||
{
|
||||
Application.targetFrameRate = AppConfig.Config.TargetFrameRate;
|
||||
|
||||
//기본 언어 설정
|
||||
bool success = LocalizationManager.Instance.LoadDefaultLocalizationData(AppConfig.Config.Language);
|
||||
Debug.Log($"LocalizationManager: LoadDefaultLocalizationData success: {success}");
|
||||
@@ -56,7 +58,7 @@ namespace SampleProject
|
||||
private void SetNetworkConfig()
|
||||
{
|
||||
|
||||
URLList.Add("baseinfo", "http://localhost:8888/baseinfo/00:00");
|
||||
URLList.Add("baseinfo", "http://localhost:8888/baseinfo");
|
||||
|
||||
var agvDataMask = new DataMask();
|
||||
agvDataMask.ObjectName = "AGV"; // AGV 객체의 이름을 설정합니다.
|
||||
|
||||
@@ -43,6 +43,12 @@ namespace SampleProject.Config
|
||||
[JsonProperty("language")]
|
||||
public string Language { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 목표 프레임 레이트 설정입니다.
|
||||
/// </summary>
|
||||
[JsonProperty("targetFrameRate")]
|
||||
public int TargetFrameRate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 애플리케이션의 창 관련 설정입니다.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UVC.Core;
|
||||
@@ -6,7 +6,9 @@ using UVC.Data;
|
||||
using UVC.Data.Core;
|
||||
using UVC.Data.Http;
|
||||
using UVC.Factory.Alarm;
|
||||
using UVC.Factory.Component;
|
||||
using UVC.Factory.Playback;
|
||||
using UVC.UI.Loading;
|
||||
using UVC.UI.Tooltip;
|
||||
|
||||
namespace SampleProject
|
||||
@@ -33,13 +35,19 @@ namespace SampleProject
|
||||
/// <remarks>이 메서드는 AGV 관리자 생성과 관련된 필요한 초기화 또는 설정 작업을 수행하기 위한 것입니다.
|
||||
/// 내부적으로 호출되며 외부 코드에서 직접 사용하도록 의도된 것이 아닙니다.
|
||||
///</remarks>
|
||||
internal void OnAGVManagerCreated()
|
||||
internal void OnAGVCreated()
|
||||
{
|
||||
AlarmManager.Instance.Run();
|
||||
}
|
||||
|
||||
private async void OnAppInitialized()
|
||||
{
|
||||
|
||||
// AGVManager 생성 시 이벤트 처리
|
||||
AGVManager.Instance.OnAGVCreated += OnAGVCreated;
|
||||
|
||||
PlaybackService.Instance.OnStopPlayback += OnStopPlayback;
|
||||
|
||||
await requestDataAsync();
|
||||
|
||||
if (Initialized != null)
|
||||
@@ -47,21 +55,23 @@ namespace SampleProject
|
||||
Initialized.Invoke();
|
||||
}
|
||||
|
||||
PlaybackService.Instance.OnStopPlayback += OnStopPlayback;
|
||||
//MqttReceiver 시작
|
||||
DataRepository.Instance.MqttReceiver.Start();
|
||||
}
|
||||
|
||||
private async Task requestDataAsync()
|
||||
{
|
||||
var httpFetcher = DataRepository.Instance.HttpFetcher;
|
||||
var splitRequest = new HttpRequestConfig(URLList.Get("baseinfo"))
|
||||
.setSplitResponseByKey(true) // 응답을 키별로 분할
|
||||
.AddSplitConfig("AGV", DataMapperValidator.Get("AGV")) // "AGV" 키에 대한 매퍼, Validator 설정
|
||||
.AddSplitConfig("ALARM", DataMapperValidator.Get("ALARM")); // "ALARM" 키에 대한 매퍼, Validator 설정
|
||||
httpFetcher.Add("baseInfo", splitRequest);
|
||||
await httpFetcher.Excute("baseInfo");
|
||||
|
||||
//MqttReceiver 시작
|
||||
DataRepository.Instance.MqttReceiver.Start();
|
||||
UILoading.Show();
|
||||
//Debug.Log("Requesting BaseInfo data...");
|
||||
//var httpFetcher = DataRepository.Instance.HttpFetcher;
|
||||
//var splitRequest = new HttpRequestConfig(URLList.Get("baseinfo"))
|
||||
// .setSplitResponseByKey(true) // 응답을 키별로 분할
|
||||
// .AddSplitConfig("AGV", DataMapperValidator.Get("AGV")) // "AGV" 키에 대한 매퍼, Validator 설정
|
||||
// .AddSplitConfig("ALARM", DataMapperValidator.Get("ALARM")); // "ALARM" 키에 대한 매퍼, Validator 설정
|
||||
//httpFetcher.Add("baseInfo", splitRequest);
|
||||
//await httpFetcher.Excute("baseInfo");
|
||||
//Debug.Log("BaseInfo data request completed.");
|
||||
UILoading.Hide();
|
||||
}
|
||||
|
||||
private async void OnStopPlayback()
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
#nullable enable
|
||||
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UVC.Data.Core;
|
||||
using UVC.Data.Http;
|
||||
using UVC.Data.Mqtt;
|
||||
@@ -28,7 +31,7 @@ namespace UVC.Data
|
||||
/// <summary>
|
||||
/// 외부에서의 인스턴스 생성을 방지하는 보호된 생성자입니다.
|
||||
/// </summary>
|
||||
protected DataRepository()
|
||||
protected DataRepository()
|
||||
{
|
||||
// Best MQTT 초기화 작업을 Main 스레드에서 호출 해야 한다.
|
||||
Best.HTTP.Shared.HTTPManager.Setup();
|
||||
@@ -56,7 +59,7 @@ namespace UVC.Data
|
||||
private Dictionary<string, Action<IDataObject>> dataUpdateHandlers = new Dictionary<string, Action<IDataObject>>();
|
||||
|
||||
private HttpDataFetcher httpFetcher = new HttpDataFetcher();
|
||||
public HttpDataFetcher HttpFetcher => httpFetcher;
|
||||
public HttpDataFetcher HttpFetcher => httpFetcher;
|
||||
|
||||
private MqttDataReceiver mqttReceiver = new MqttDataReceiver();
|
||||
public MqttDataReceiver MqttReceiver => mqttReceiver;
|
||||
@@ -81,10 +84,9 @@ namespace UVC.Data
|
||||
{
|
||||
if (!dataObjects.ContainsKey(key))
|
||||
{
|
||||
var newData = dataObject.Clone(fromPool: false);
|
||||
|
||||
dataObjects.Add(key, newData);
|
||||
dataObject.MarkAllAsUpdated();
|
||||
var newData = dataObject.Clone(fromPool: false);
|
||||
dataObjects.Add(key, newData);
|
||||
NotifyDataUpdate(key, newData);
|
||||
return dataObject;
|
||||
}
|
||||
@@ -101,7 +103,8 @@ namespace UVC.Data
|
||||
{
|
||||
newDataObject = dataObject;
|
||||
}
|
||||
NotifyDataUpdate(key, obj);
|
||||
bool shouldInvoke = !updatedDataOnly || newDataObject.UpdatedCount > 0;
|
||||
if(shouldInvoke) NotifyDataUpdate(key, newDataObject);
|
||||
return newDataObject;
|
||||
}
|
||||
}
|
||||
@@ -130,7 +133,7 @@ namespace UVC.Data
|
||||
/// </summary>
|
||||
/// <param name="key">검색할 데이터 객체의 키</param>
|
||||
/// <returns>키가 존재하면 해당 데이터 객체, 존재하지 않으면 null</returns>
|
||||
public IDataObject GetData(string key)
|
||||
public IDataObject? GetData(string key)
|
||||
{
|
||||
if (string.IsNullOrEmpty(key))
|
||||
throw new ArgumentNullException(nameof(key), "키는 null이거나 빈 문자열일 수 없습니다.");
|
||||
@@ -233,6 +236,7 @@ namespace UVC.Data
|
||||
throw new ArgumentNullException(nameof(key), "키는 null이거나 빈 문자열일 수 없습니다.");
|
||||
if (dataObject == null)
|
||||
throw new ArgumentNullException(nameof(dataObject), "데이터 객체는 null일 수 없습니다.");
|
||||
//Debug.Log($"NotifyDataUpdate: {key}, {dataObject.GetType().Name}");
|
||||
lock (syncLock)
|
||||
{
|
||||
if (dataUpdateHandlers.ContainsKey(key))
|
||||
|
||||
@@ -183,24 +183,24 @@ namespace UVC.Data.Http
|
||||
{
|
||||
if (!infoList.ContainsKey(key))
|
||||
{
|
||||
throw new KeyNotFoundException($"No HTTP request found with key '{key}'.");
|
||||
Debug.LogError($"No HTTP request found with key '{key}'.");
|
||||
return;
|
||||
}
|
||||
|
||||
Debug.Log($"Executing HTTP request for key: {key}");
|
||||
|
||||
HttpRequestConfig info = infoList[key];
|
||||
|
||||
// 반복 설정에 관계없이 이전에 실행 중인 반복 작업이 있다면 중지
|
||||
await StopRepeat(key);
|
||||
|
||||
// 스레드풀에서 요청 처리 실행
|
||||
await UniTask.SwitchToThreadPool();
|
||||
|
||||
try
|
||||
{
|
||||
if (!info.Repeat)
|
||||
{
|
||||
// 단일 실행 로직 호출
|
||||
await ExecuteSingle(key, info);
|
||||
await UniTask.SwitchToMainThread();
|
||||
await UniTask.RunOnThreadPool(() => ExecuteSingle(key, info));
|
||||
Debug.Log($"HTTP request '{key}' executed successfully.");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -211,8 +211,6 @@ namespace UVC.Data.Http
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 예외가 발생한 경우에도 메인 스레드로 복귀
|
||||
await UniTask.SwitchToMainThread();
|
||||
throw; // 예외 재발생
|
||||
}
|
||||
}
|
||||
@@ -234,7 +232,6 @@ namespace UVC.Data.Http
|
||||
/// <exception cref="Exception">HTTP 요청 중 다른 예외가 발생한 경우</exception>
|
||||
private async UniTask ExecuteSingle(string key, HttpRequestConfig info, CancellationToken cancellationToken = default)
|
||||
{
|
||||
|
||||
int retryCount = 0;
|
||||
Exception lastException = null;
|
||||
|
||||
@@ -264,11 +261,10 @@ namespace UVC.Data.Http
|
||||
{
|
||||
result = await HttpRequester.Request<string>(info.Url, info.Method, info.Body, info.Headers);
|
||||
}
|
||||
|
||||
Debug.Log($"HTTP request '{key}' completed");
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
await HttpDataProcessor.ProcessResponseAsync(key, info, result, cancellationToken);
|
||||
|
||||
HttpDataProcessor.ProcessResponse(key, info, result, cancellationToken);
|
||||
Debug.Log($"HTTP request '{key}' processed successfully");
|
||||
return;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
@@ -349,7 +345,7 @@ namespace UVC.Data.Http
|
||||
try
|
||||
{
|
||||
// 단일 실행 로직 호출
|
||||
await ExecuteSingle(key, info, cts.Token);
|
||||
await UniTask.RunOnThreadPool(() => ExecuteSingle(key, info, cts.Token));
|
||||
|
||||
// 지정된 횟수만큼 반복한 경우 중지
|
||||
if (info.RepeatCount > 0)
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
#nullable enable
|
||||
#nullable enable
|
||||
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
using UVC.Data.Core;
|
||||
using UVC.Log;
|
||||
|
||||
@@ -39,7 +41,7 @@ namespace UVC.Data.Http
|
||||
/// 5. 설정에 따라 성공(`SuccessHandler`) 또는 실패(`FailHandler`) 핸들러를 메인 스레드에서 호출하여 UI 업데이트 등을 안전하게 처리할 수 있도록 합니다.
|
||||
/// 6. 모든 과정에서 발생하는 예외(JSON 파싱, 작업 취소 등)를 처리하고 로그를 남깁니다.
|
||||
/// </remarks>
|
||||
public static async UniTask ProcessResponseAsync(string key, HttpRequestConfig info, string responseContent, CancellationToken cancellationToken)
|
||||
public static void ProcessResponse(string key, HttpRequestConfig info, string responseContent, CancellationToken cancellationToken)
|
||||
{
|
||||
// 매핑된 최종 데이터 객체를 담을 변수입니다. try-finally 블록에서 자원 해제를 위해 외부에 선언합니다.
|
||||
IDataObject? mappedObject = null;
|
||||
@@ -54,12 +56,10 @@ namespace UVC.Data.Http
|
||||
// 핸들러는 UI와 상호작용할 수 있으므로 메인 스레드에서 호출합니다.
|
||||
if (info.FailHandler != null)
|
||||
{
|
||||
await UniTask.SwitchToMainThread();
|
||||
info.FailHandler.Invoke("Response content is null or empty.");
|
||||
UniTask.Post(() => info.FailHandler.Invoke("Response content is null or empty."));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// ResponseMask를 사용해 응답이 성공적인지 확인하고, 실제 데이터 부분을 추출합니다.
|
||||
// 예를 들어, 응답이 {"status":"OK", "data":{...}} 형태일 때, "status"가 "OK"인지 확인하고 "data" 부분만 가져옵니다.
|
||||
HttpResponseResult responseResult = info.ResponseMask.Apply(responseContent);
|
||||
@@ -68,34 +68,30 @@ namespace UVC.Data.Http
|
||||
if (info.FailHandler != null)
|
||||
{
|
||||
string errorMessage = responseResult.Message!;
|
||||
await UniTask.SwitchToMainThread();
|
||||
info.FailHandler.Invoke(errorMessage);
|
||||
UniTask.Post(() => info.FailHandler.Invoke(errorMessage));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 마스크를 통해 추출된 실제 데이터
|
||||
responseContent = responseResult.Data!.Trim();
|
||||
|
||||
// 응답을 최상위 키를 기준으로 분할 처리해야 하는 경우
|
||||
if (info.SplitResponseByKey && responseContent.StartsWith("{"))
|
||||
{
|
||||
await ProcessSplitResponse(info, responseContent, cancellationToken);
|
||||
ProcessSplitResponse(info, responseContent, cancellationToken);
|
||||
return; // 분할 처리가 완료되면 이 메서드의 나머지 로직은 실행하지 않습니다.
|
||||
}
|
||||
// 응답이 JSON 객체 형태인 경우 (e.g., {"id": 1, "name": "item"})
|
||||
else if (responseContent.StartsWith("{"))
|
||||
{
|
||||
mappedObject = await ProcessObjectResponse(info, responseContent, cancellationToken);
|
||||
mappedObject = ProcessObjectResponse(info, responseContent, cancellationToken);
|
||||
if (mappedObject == null) return;
|
||||
}
|
||||
// 응답이 JSON 배열 형태인 경우 (e.g., [{"id": 1}, {"id": 2}])
|
||||
else if (responseContent.StartsWith("["))
|
||||
{
|
||||
mappedObject = await ProcessArrayResponse(info, responseContent, cancellationToken);
|
||||
mappedObject = ProcessArrayResponse(info, responseContent, cancellationToken);
|
||||
if (mappedObject == null) return;
|
||||
}
|
||||
|
||||
// 핸들러 호출 전 작업 취소 요청이 있었는지 다시 확인합니다.
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
@@ -108,7 +104,6 @@ namespace UVC.Data.Http
|
||||
// 만약 반환된 객체가 원본과 같다면, 핸들러에 전달하기 위해 복제본을 만듭니다.
|
||||
if (repoObject == mappedObject) repoObject = mappedObject.Clone(fromPool: false);
|
||||
}
|
||||
|
||||
// 'UpdatedDataOnly' 옵션이 켜져 있고, 실제로 데이터가 업데이트되었을 때만 핸들러를 호출합니다.
|
||||
if (info.UpdatedDataOnly)
|
||||
{
|
||||
@@ -117,21 +112,18 @@ namespace UVC.Data.Http
|
||||
if (info.SuccessHandler != null)
|
||||
{
|
||||
var handlerData = repoObject;
|
||||
await UniTask.SwitchToMainThread();
|
||||
info.SuccessHandler.Invoke(handlerData);
|
||||
UniTask.Post(() => info.SuccessHandler.Invoke(handlerData));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 최종적으로 처리된 데이터가 있는 경우 성공 핸들러를 호출합니다.
|
||||
if (repoObject != null)
|
||||
{
|
||||
if (info.SuccessHandler != null)
|
||||
{
|
||||
var handlerData = repoObject;
|
||||
await UniTask.SwitchToMainThread();
|
||||
info.SuccessHandler.Invoke(handlerData);
|
||||
UniTask.Post(() => info.SuccessHandler.Invoke(handlerData));
|
||||
}
|
||||
}
|
||||
// 처리된 데이터가 없는 경우 실패 핸들러를 호출합니다.
|
||||
@@ -139,8 +131,7 @@ namespace UVC.Data.Http
|
||||
{
|
||||
if (info.FailHandler != null)
|
||||
{
|
||||
await UniTask.SwitchToMainThread();
|
||||
info.FailHandler.Invoke("Data is Null");
|
||||
UniTask.Post(() => info.FailHandler.Invoke("Data is Null"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,8 +141,7 @@ namespace UVC.Data.Http
|
||||
ULog.Error($"JSON parsing error for {key}: {ex.Message}\nResponse: {responseContent}", ex);
|
||||
if (info.FailHandler != null)
|
||||
{
|
||||
await UniTask.SwitchToMainThread();
|
||||
info.FailHandler.Invoke($"JSON parsing error: {ex.Message}");
|
||||
UniTask.Post(() => info.FailHandler.Invoke($"JSON parsing error: {ex.Message}"));
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
@@ -165,8 +155,7 @@ namespace UVC.Data.Http
|
||||
ULog.Error($"Error processing response for {key}: {ex.Message}", ex);
|
||||
if (info.FailHandler != null)
|
||||
{
|
||||
await UniTask.SwitchToMainThread();
|
||||
info.FailHandler.Invoke($"Error processing response: {ex.Message}");
|
||||
UniTask.Post(() => info.FailHandler.Invoke($"Error processing response: {ex.Message}"));
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -188,7 +177,7 @@ namespace UVC.Data.Http
|
||||
/// "AGV"와 "ALARM"을 각각 별개의 데이터로 간주하고 처리합니다.
|
||||
/// 각 키에 대해 별도의 DataMapper나 Validator를 `HttpRequestConfig`에 설정할 수 있습니다.
|
||||
/// </remarks>
|
||||
public static async UniTask ProcessSplitResponse(HttpRequestConfig info, string jsonResponse, CancellationToken? cancellationToken = null)
|
||||
public static void ProcessSplitResponse(HttpRequestConfig info, string jsonResponse, CancellationToken? cancellationToken = null)
|
||||
{
|
||||
JObject responseObject = JObject.Parse(jsonResponse);
|
||||
// JSON 객체의 모든 프로퍼티(키-값 쌍)를 순회합니다.
|
||||
@@ -197,6 +186,7 @@ namespace UVC.Data.Http
|
||||
cancellationToken?.ThrowIfCancellationRequested();
|
||||
|
||||
string subKey = property.Name; // "AGV", "ALARM" 등
|
||||
|
||||
JToken subToken = property.Value; // `[...]` 또는 `{...}`
|
||||
IDataObject? subMappedObject = null;
|
||||
|
||||
@@ -208,19 +198,24 @@ namespace UVC.Data.Http
|
||||
var subKeyDataMapper = splitConfig?.DataMapper;
|
||||
var subKeyValidator = splitConfig?.Validator;
|
||||
|
||||
//매퍼가 null인 경우, 해당 키는 처리하지 않습니다.
|
||||
if (subKeyDataMapper == null) continue;
|
||||
|
||||
try
|
||||
{
|
||||
// 하위 데이터가 배열 또는 객체 형태인지에 따라 적절한 처리 메서드를 호출합니다.
|
||||
if (subToken is JArray)
|
||||
if (subToken is JArray && subToken.Count() > 0)
|
||||
{
|
||||
// 분할 처리 중 개별 항목의 실패가 전체 실패로 이어지지 않도록 `invokeFailHandler`를 false로 설정합니다.
|
||||
subMappedObject = await ProcessArrayResponse(info, subToken.ToString(), cancellationToken, subKeyDataMapper, subKeyValidator, invokeFailHandler: false);
|
||||
subMappedObject = ProcessArrayResponse(info, subToken.ToString(), cancellationToken, subKeyDataMapper, subKeyValidator, invokeFailHandler: false);
|
||||
}
|
||||
else if (subToken is JObject)
|
||||
else if (subToken is JObject && subToken.Count() > 0)
|
||||
{
|
||||
subMappedObject = await ProcessObjectResponse(info, subToken.ToString(), cancellationToken, subKeyDataMapper, subKeyValidator, invokeFailHandler: false);
|
||||
subMappedObject = ProcessObjectResponse(info, subToken.ToString(), cancellationToken, subKeyDataMapper, subKeyValidator, invokeFailHandler: false);
|
||||
}
|
||||
|
||||
//Debug.Log($"Processing split response for key: {subKey}, {subToken.Count()}. {subToken.GetType().Name} subMappedObject == null:{subMappedObject == null}");
|
||||
|
||||
// 매핑된 결과가 없으면 (예: 유효성 검사 실패) 다음 키로 넘어갑니다.
|
||||
if (subMappedObject == null)
|
||||
{
|
||||
@@ -236,10 +231,10 @@ namespace UVC.Data.Http
|
||||
if (shouldInvokeHandler && info.SuccessHandler != null)
|
||||
{
|
||||
var handlerData = repoObject.Clone(fromPool: false);
|
||||
await UniTask.SwitchToMainThread();
|
||||
info.SuccessHandler.Invoke(handlerData);
|
||||
//await UniTask.SwitchToMainThread();
|
||||
UniTask.Post(() => info.SuccessHandler.Invoke(handlerData));
|
||||
// 다음 키 처리를 위해 다시 스레드 풀로 전환합니다.
|
||||
await UniTask.SwitchToThreadPool();
|
||||
//await UniTask.SwitchToThreadPool();
|
||||
}
|
||||
}
|
||||
finally
|
||||
@@ -250,10 +245,10 @@ namespace UVC.Data.Http
|
||||
}
|
||||
}
|
||||
|
||||
private static async UniTask<IDataObject?> ProcessObjectResponse(HttpRequestConfig info, string jsonResponse, CancellationToken? cancellationToken, DataMapper? dataMapper = null, DataValidator? validator = null, bool invokeFailHandler = true)
|
||||
private static IDataObject? ProcessObjectResponse(HttpRequestConfig info, string jsonResponse, CancellationToken? cancellationToken, DataMapper? dataMapper = null, DataValidator? validator = null, bool invokeFailHandler = true)
|
||||
{
|
||||
Action<string>? failHandler = invokeFailHandler ? info.FailHandler : null;
|
||||
return await ProcessObjectResponse(jsonResponse, cancellationToken, dataMapper ?? info.DataMapper, validator ?? info.Validator, failHandler);
|
||||
return ProcessObjectResponse(jsonResponse, cancellationToken, dataMapper ?? info.DataMapper, validator ?? info.Validator, failHandler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -270,7 +265,7 @@ namespace UVC.Data.Http
|
||||
/// 통과하면 `DataMapper`를 사용해 JSON을 `IDataObject`로 변환합니다.
|
||||
/// 대용량 JSON의 경우 메모리 효율을 위해 스트림 기반 파싱을 지원합니다.
|
||||
/// </remarks>
|
||||
public static async UniTask<IDataObject?> ProcessObjectResponse(string jsonResponse, CancellationToken? cancellationToken, DataMapper? dataMapper, DataValidator? validator, Action<string>? failHandler)
|
||||
public static IDataObject? ProcessObjectResponse(string jsonResponse, CancellationToken? cancellationToken, DataMapper? dataMapper, DataValidator? validator, Action<string>? failHandler)
|
||||
{
|
||||
// 유효성 검사기가 설정된 경우
|
||||
if (validator != null)
|
||||
@@ -293,8 +288,7 @@ namespace UVC.Data.Http
|
||||
{
|
||||
if (failHandler != null)
|
||||
{
|
||||
await UniTask.SwitchToMainThread();
|
||||
failHandler.Invoke("Data is not Valid");
|
||||
UniTask.Post(() => failHandler.Invoke("Data is not Valid"));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -324,10 +318,10 @@ namespace UVC.Data.Http
|
||||
}
|
||||
}
|
||||
|
||||
private static async UniTask<IDataObject?> ProcessArrayResponse(HttpRequestConfig info, string jsonResponse, CancellationToken? cancellationToken, DataMapper? dataMapper = null, DataValidator? validator = null, bool invokeFailHandler = true)
|
||||
private static IDataObject? ProcessArrayResponse(HttpRequestConfig info, string jsonResponse, CancellationToken? cancellationToken, DataMapper? dataMapper = null, DataValidator? validator = null, bool invokeFailHandler = true)
|
||||
{
|
||||
Action<string>? failHandler = invokeFailHandler ? info.FailHandler : null;
|
||||
return await ProcessArrayResponse(jsonResponse, cancellationToken, dataMapper ?? info.DataMapper, validator ?? info.Validator, failHandler);
|
||||
return ProcessArrayResponse(jsonResponse, cancellationToken, dataMapper ?? info.DataMapper, validator ?? info.Validator, failHandler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -343,7 +337,7 @@ namespace UVC.Data.Http
|
||||
/// `DataValidator`를 통해 배열의 각 항목을 필터링하여 유효한 데이터만 포함하는 새 배열을 만들 수 있습니다.
|
||||
/// 그 후 `DataMapper`를 통해 배열 전체를 `DataArray` 객체로 변환합니다.
|
||||
/// </remarks>
|
||||
public static async UniTask<IDataObject?> ProcessArrayResponse(string jsonResponse, CancellationToken? cancellationToken, DataMapper? dataMapper, DataValidator? validator, Action<string>? failHandler)
|
||||
public static IDataObject? ProcessArrayResponse(string jsonResponse, CancellationToken? cancellationToken, DataMapper? dataMapper, DataValidator? validator, Action<string>? failHandler)
|
||||
{
|
||||
JArray? sourceArray;
|
||||
|
||||
@@ -366,8 +360,7 @@ namespace UVC.Data.Http
|
||||
{
|
||||
if (failHandler != null)
|
||||
{
|
||||
await UniTask.SwitchToMainThread();
|
||||
failHandler.Invoke("Data is not Valid or empty after validation");
|
||||
UniTask.Post(() => failHandler.Invoke("Data is not Valid or empty after validation"));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#nullable enable
|
||||
#nullable enable
|
||||
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SampleProject.Config;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
using UVC.Data.Core;
|
||||
using UVC.Data.Http;
|
||||
using UVC.Log;
|
||||
@@ -91,7 +93,7 @@ namespace UVC.Data.Mqtt
|
||||
/// <summary>
|
||||
/// 토픽별 파이프라인 정보를 저장하는 딕셔너리
|
||||
/// </summary>
|
||||
private Dictionary<string, MqttSubscriptionConfig> infoList;
|
||||
private ConcurrentDictionary<string, MqttSubscriptionConfig> configList;
|
||||
|
||||
private MqttWorker mqttWorker;
|
||||
|
||||
@@ -103,7 +105,7 @@ namespace UVC.Data.Mqtt
|
||||
public MqttDataReceiver()
|
||||
{
|
||||
mqttWorker = new MqttWorker();
|
||||
infoList = new Dictionary<string, MqttSubscriptionConfig>();
|
||||
configList = new ConcurrentDictionary<string, MqttSubscriptionConfig>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -141,14 +143,7 @@ namespace UVC.Data.Mqtt
|
||||
/// </remarks>
|
||||
public void Add(MqttSubscriptionConfig info)
|
||||
{
|
||||
if (!infoList.ContainsKey(info.Topic))
|
||||
{
|
||||
infoList.Add(info.Topic, info);
|
||||
}
|
||||
else
|
||||
{
|
||||
infoList[info.Topic] = info;
|
||||
}
|
||||
configList[info.Topic] = info;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -157,10 +152,7 @@ namespace UVC.Data.Mqtt
|
||||
/// <param name="topic">제거할 토픽 이름</param>
|
||||
public void Remove(string topic)
|
||||
{
|
||||
if (infoList.ContainsKey(topic))
|
||||
{
|
||||
infoList.Remove(topic);
|
||||
}
|
||||
configList.TryRemove(topic, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -181,7 +173,7 @@ namespace UVC.Data.Mqtt
|
||||
{
|
||||
// Mockup 모드인 경우 MockMQTTService를 사용하여 테스트 환경을 설정합니다.
|
||||
mockupMQTT = new MockMQTTService();
|
||||
foreach (var topic in infoList.Keys)
|
||||
foreach (var topic in configList.Keys)
|
||||
{
|
||||
mockupMQTT.AddTopicHandler(topic, OnTopicMessage);
|
||||
}
|
||||
@@ -231,38 +223,39 @@ namespace UVC.Data.Mqtt
|
||||
/// 등록된 데이터 매퍼를 통해 메시지를 변환한 후, 해당 토픽에 등록된 핸들러에게 전달합니다.
|
||||
/// 'UpdatedDataOnly' 설정에 따라 데이터가 변경된 경우에만 핸들러를 호출할 수도 있습니다.
|
||||
/// </remarks>
|
||||
private async void OnTopicMessageLogic(string topic, string message)
|
||||
private void OnTopicMessageLogic(string topic, string message)
|
||||
{
|
||||
//Debug.Log($"OnTopicMessageLogic topic: {topic}, configList.ContainsKey(topic): {configList.ContainsKey(topic)}");
|
||||
// 토픽이 infoList와 readyHandlerList에 존재하고, 준비 상태가 true인 경우에만 처리합니다.
|
||||
if (infoList.ContainsKey(topic))
|
||||
if (configList.TryGetValue(topic, out var config))
|
||||
{
|
||||
MqttSubscriptionConfig info = infoList[topic];
|
||||
IDataObject? mappedObject = null;
|
||||
message = message.Trim();
|
||||
|
||||
if (!string.IsNullOrEmpty(message))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (message.StartsWith("{"))
|
||||
{
|
||||
mappedObject = await HttpDataProcessor.ProcessObjectResponse(message, null, info.DataMapper, info.Validator, null);
|
||||
mappedObject = HttpDataProcessor.ProcessObjectResponse(message, null, config.DataMapper, config.Validator, null);
|
||||
}
|
||||
else if (message.StartsWith("["))
|
||||
{
|
||||
mappedObject = await HttpDataProcessor.ProcessArrayResponse(message, null, info.DataMapper, info.Validator, null);
|
||||
mappedObject = HttpDataProcessor.ProcessArrayResponse(message, null, config.DataMapper, config.Validator, null);
|
||||
}
|
||||
|
||||
//Debug.Log($"OnTopicMessageLogic topic: {topic}, mappedObject == null: {mappedObject == null}, config.DataMapper:{config.DataMapper == null}, config.Validator:{config.Validator == null}");
|
||||
if (mappedObject == null) return;
|
||||
// DataRepository는 내부적으로 데이터를 복사/업데이트하므로, mappedObject는 여기서 임시 객체가 됩니다.
|
||||
var repoObject = DataRepository.Instance.AddOrUpdateData(topic, mappedObject, info.UpdatedDataOnly);
|
||||
var repoObject = DataRepository.Instance.AddOrUpdateData(topic, mappedObject, config.UpdatedDataOnly);
|
||||
if (repoObject == mappedObject) repoObject = mappedObject.Clone(fromPool: false);
|
||||
// 핸들러 호출이 필요한지 확인
|
||||
bool shouldInvoke = !info.UpdatedDataOnly || (repoObject != null && repoObject.UpdatedCount > 0);
|
||||
if (shouldInvoke)
|
||||
bool shouldInvoke = !config.UpdatedDataOnly || (repoObject != null && repoObject.UpdatedCount > 0);
|
||||
if (shouldInvoke && config.Handler != null)
|
||||
{
|
||||
var handlerData = repoObject;
|
||||
// 핸들러를 메인 스레드에서 안전하게 호출
|
||||
UniTask.Post(() => info.Handler?.Invoke(handlerData));
|
||||
UniTask.Post(() => config.Handler?.Invoke(handlerData));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -292,7 +285,7 @@ namespace UVC.Data.Mqtt
|
||||
if (!UseMockup)
|
||||
{
|
||||
if (!mqttWorker.IsRunning) return;
|
||||
foreach (var topic in infoList.Keys)
|
||||
foreach (var topic in configList.Keys)
|
||||
{
|
||||
mqttWorker.RemoveListener(topic, OnTopicPacketMessage);
|
||||
}
|
||||
@@ -314,7 +307,7 @@ namespace UVC.Data.Mqtt
|
||||
{
|
||||
if (!UseMockup) mqttWorker.Dispose();
|
||||
else mockupMQTT?.Disconnect();
|
||||
infoList.Clear();
|
||||
configList.Clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
namespace UVC.Event
|
||||
{
|
||||
/// <summary>
|
||||
/// 비동기 이벤트 처리를 위한 제네릭 델리게이트
|
||||
/// UniTask를 반환하는 이벤트 핸들러를 정의하여 비동기 작업을 이벤트 기반으로 처리할 수 있게 함
|
||||
/// 비동기 이벤트 처리를 위한 델리게이트입니다.
|
||||
/// UniTask를 반환하는 이벤트 핸들러를 정의하여, 비동기 작업을 이벤트 기반으로 처리할 수 있게 합니다.
|
||||
/// </summary>
|
||||
/// <typeparam name="TEventArgs">이벤트 데이터를 포함하는 제네릭 타입 매개변수</typeparam>
|
||||
/// <param name="sender">이벤트를 발생시킨 객체</param>
|
||||
/// <param name="e">이벤트와 관련된 데이터</param>
|
||||
/// <returns>비동기 작업을 나타내는 UniTask</returns>
|
||||
/// <typeparam name="TEventArgs">이벤트 데이터를 담는 제네릭 타입 매개변수</typeparam>
|
||||
/// <param name="sender">이벤트를 발생시킨 객체</param>
|
||||
/// <param name="e">이벤트에 포함된 데이터</param>
|
||||
/// <returns>비동기 작업을 나타내는 UniTask</returns>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// // 이벤트 선언 예시
|
||||
/// // 이벤트 정의 예시
|
||||
/// public class NetworkManager
|
||||
/// {
|
||||
/// // UniTaskEventHandler 타입의 이벤트 선언
|
||||
/// // UniTaskEventHandler 타입의 이벤트 선언
|
||||
/// public event UniTaskEventHandler<DataReceivedEventArgs> OnDataReceived;
|
||||
///
|
||||
/// // 이벤트 발생 메소드
|
||||
/// // 이벤트 발생 메서드
|
||||
/// public async UniTask RaiseDataReceivedEvent(DataReceivedEventArgs args)
|
||||
/// {
|
||||
/// if (OnDataReceived != null)
|
||||
/// {
|
||||
/// // 모든 등록된 핸들러를 순차적으로 실행
|
||||
/// // 모든 등록된 핸들러를 비동기적으로 실행
|
||||
/// foreach (var handler in OnDataReceived.GetInvocationList())
|
||||
/// {
|
||||
/// await ((UniTaskEventHandler<DataReceivedEventArgs>)handler).Invoke(this, args);
|
||||
@@ -32,7 +32,7 @@ namespace UVC.Event
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// // 이벤트 구독 예시
|
||||
/// // 이벤트 구독 예시
|
||||
/// public class DataProcessor
|
||||
/// {
|
||||
/// public void Initialize(NetworkManager networkManager)
|
||||
@@ -42,17 +42,17 @@ namespace UVC.Event
|
||||
///
|
||||
/// private async UniTask HandleDataReceived(object sender, DataReceivedEventArgs e)
|
||||
/// {
|
||||
/// // 비동기 이벤트 처리 로직
|
||||
/// // 비동기 이벤트 처리 로직
|
||||
/// await ProcessDataAsync(e.Data);
|
||||
/// }
|
||||
///
|
||||
/// private async UniTask ProcessDataAsync(byte[] data)
|
||||
/// private async UniTask ProcessDataAsync(byte[] buffers)
|
||||
/// {
|
||||
/// await UniTask.Delay(100); // 예시 비동기 작업
|
||||
/// // 데이터 처리 로직
|
||||
/// await UniTask.Delay(100); // 예시 비동기 작업
|
||||
/// // 데이터 처리 로직
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </example>
|
||||
public delegate UniTask UniTaskEventHandler<TEventArgs>(object sender, TEventArgs e);
|
||||
}
|
||||
}
|
||||
@@ -4,28 +4,28 @@ using UnityEngine;
|
||||
namespace UVC.Extension
|
||||
{
|
||||
/// <summary>
|
||||
/// RectTransform에 대한 유용한 확장 메서드를 제공하는 클래스입니다.
|
||||
/// RectTransform에 대한 확장 메서드를 제공하는 클래스입니다.
|
||||
/// </summary>
|
||||
public static class RectTransformEx
|
||||
{
|
||||
/// <summary>
|
||||
/// RectTransform의 마진을 설정합니다. 부모 요소의 전체 영역을 기준으로 상하좌우 여백을 지정합니다.
|
||||
/// 앵커는 자동으로 모서리에 설정됩니다(anchorMin=[0,0], anchorMax=[1,1]).
|
||||
/// RectTransform의 여백을 설정합니다. 부모를 기준으로 모든 방향의 여백을 설정하여 크기를 조절합니다.
|
||||
/// 앵커는 부모의 전체를 채우도록 설정됩니다(anchorMin=[0,0], anchorMax=[1,1]).
|
||||
/// </summary>
|
||||
/// <param name="trans">대상 RectTransform</param>
|
||||
/// <param name="left">왼쪽 여백</param>
|
||||
/// <param name="right">오른쪽 여백</param>
|
||||
/// <param name="top">위쪽 여백</param>
|
||||
/// <param name="bottom">아래쪽 여백</param>
|
||||
/// <param name="trans">대상 RectTransform</param>
|
||||
/// <param name="left">왼쪽 여백</param>
|
||||
/// <param name="right">오른쪽 여백</param>
|
||||
/// <param name="top">위쪽 여백</param>
|
||||
/// <param name="bottom">아래쪽 여백</param>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// // 게임 오브젝트의 RectTransform에 여백 적용
|
||||
/// // 패널 RectTransform의 여백 설정
|
||||
/// RectTransform panelRect = panel.GetComponent<RectTransform>();
|
||||
/// panelRect.SetRectMargin(10f, 10f, 10f, 10f); // 사방 10픽셀 여백 설정
|
||||
/// panelRect.SetRectMargin(10f, 10f, 10f, 10f); // 모든 방향에 10의 여백 설정
|
||||
///
|
||||
/// // UI 요소를 부모 컨테이너에 맞추되 여백 주기
|
||||
/// // 자식 UI 요소의 여백 다르게 설정
|
||||
/// RectTransform childRect = childObject.GetComponent<RectTransform>();
|
||||
/// childRect.SetRectMargin(5f, 5f, 20f, 5f); // 상단에 더 큰 여백 설정
|
||||
/// childRect.SetRectMargin(5f, 5f, 20f, 5f); // 위쪽에 더 많은 여백 설정
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static void SetRectMargin(this RectTransform trans, float left, float right, float top, float bottom)
|
||||
@@ -37,14 +37,14 @@ namespace UVC.Extension
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RectTransform의 너비를 설정합니다.
|
||||
/// RectTransform의 너비를 설정합니다.
|
||||
/// </summary>
|
||||
/// <param name="trans">대상 RectTransform</param>
|
||||
/// <param name="width">설정할 너비</param>
|
||||
/// <param name="trans">대상 RectTransform</param>
|
||||
/// <param name="width">설정할 너비</param>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// // 버튼의 너비를 200으로 설정
|
||||
/// RectTransform buttonRect = button.GetComponent<RectTransform>();
|
||||
/// // 버튼의 너비를 200으로 설정
|
||||
/// RectTransform buttonRect = searchButton.GetComponent<RectTransform>();
|
||||
/// buttonRect.SetWidth(200f);
|
||||
/// </code>
|
||||
/// </example>
|
||||
@@ -54,13 +54,13 @@ namespace UVC.Extension
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RectTransform의 높이를 설정합니다.
|
||||
/// RectTransform의 높이를 설정합니다.
|
||||
/// </summary>
|
||||
/// <param name="trans">대상 RectTransform</param>
|
||||
/// <param name="height">설정할 높이</param>
|
||||
/// <param name="trans">대상 RectTransform</param>
|
||||
/// <param name="height">설정할 높이</param>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// // 패널의 높이를 150으로 설정
|
||||
/// // 패널의 높이를 150으로 설정
|
||||
/// RectTransform panelRect = panel.GetComponent<RectTransform>();
|
||||
/// panelRect.SetHeight(150f);
|
||||
/// </code>
|
||||
@@ -71,13 +71,13 @@ namespace UVC.Extension
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RectTransform의 크기를 설정합니다.
|
||||
/// RectTransform의 크기를 설정합니다.
|
||||
/// </summary>
|
||||
/// <param name="trans">대상 RectTransform</param>
|
||||
/// <param name="size">설정할 크기 (너비, 높이)</param>
|
||||
/// <param name="trans">대상 RectTransform</param>
|
||||
/// <param name="size">설정할 크기 (너비, 높이)</param>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// // 이미지의 크기를 100x100으로 설정
|
||||
/// // 이미지의 크기를 100x100으로 설정
|
||||
/// RectTransform imageRect = image.GetComponent<RectTransform>();
|
||||
/// imageRect.SetSize(new Vector2(100f, 100f));
|
||||
/// </code>
|
||||
@@ -89,15 +89,15 @@ namespace UVC.Extension
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RectTransform의 앵커를 중앙에 위치시키고 피벗도 중앙으로 설정합니다.
|
||||
/// RectTransform의 앵커와 피벗을 중앙으로 설정합니다.
|
||||
/// </summary>
|
||||
/// <param name="trans">대상 RectTransform</param>
|
||||
/// <param name="trans">대상 RectTransform</param>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// // 버튼을 화면 중앙에 위치시키기
|
||||
/// RectTransform buttonRect = button.GetComponent<RectTransform>();
|
||||
/// // 버튼의 기준점을 중앙으로 설정
|
||||
/// RectTransform buttonRect = searchButton.GetComponent<RectTransform>();
|
||||
/// buttonRect.SetAnchorsToCenter();
|
||||
/// buttonRect.anchoredPosition = Vector2.zero; // 중앙 위치에 배치
|
||||
/// buttonRect.anchoredPosition = Vector2.zero; // 중앙에 배치
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static void SetAnchorsToCenter(this RectTransform trans)
|
||||
@@ -108,15 +108,15 @@ namespace UVC.Extension
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RectTransform의 앵커와 피벗을 왼쪽 상단으로 설정합니다.
|
||||
/// RectTransform의 앵커와 피벗을 왼쪽 상단으로 설정합니다.
|
||||
/// </summary>
|
||||
/// <param name="trans">대상 RectTransform</param>
|
||||
/// <param name="trans">대상 RectTransform</param>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// // UI 요소를 왼쪽 상단에 위치시키기
|
||||
/// // UI 요소의 기준점을 왼쪽 상단으로 설정
|
||||
/// RectTransform elementRect = element.GetComponent<RectTransform>();
|
||||
/// elementRect.SetAnchorsToTopLeft();
|
||||
/// elementRect.anchoredPosition = new Vector2(10f, -10f); // 약간의 여백 추가
|
||||
/// elementRect.anchoredPosition = new Vector2(10f, -10f); // 왼쪽 상단에서 오프셋 설정
|
||||
/// </code>
|
||||
/// </example>
|
||||
public static void SetAnchorsToTopLeft(this RectTransform trans)
|
||||
@@ -127,12 +127,12 @@ namespace UVC.Extension
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RectTransform을 부모 영역에 꽉 차게 설정합니다(마진 없음).
|
||||
/// RectTransform을 부모의 크기에 맞게 늘립니다 (모든 여백 0).
|
||||
/// </summary>
|
||||
/// <param name="trans">대상 RectTransform</param>
|
||||
/// <param name="trans">대상 RectTransform</param>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// // 배경 이미지를 패널 전체에 채우기
|
||||
/// // 배경 이미지를 부모 패널에 꽉 채우기
|
||||
/// RectTransform backgroundRect = backgroundImage.GetComponent<RectTransform>();
|
||||
/// backgroundRect.StretchToParentEdges();
|
||||
/// </code>
|
||||
@@ -143,13 +143,13 @@ namespace UVC.Extension
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RectTransform의 위치를 부모 RectTransform 내의 상대 위치(0~1)로 설정합니다.
|
||||
/// RectTransform의 위치를 부모 RectTransform 내의 정규화된 좌표(0~1)로 설정합니다.
|
||||
/// </summary>
|
||||
/// <param name="trans">대상 RectTransform</param>
|
||||
/// <param name="normalizedPosition">정규화된 위치 (0,0=왼쪽 하단, 1,1=오른쪽 상단)</param>
|
||||
/// <param name="trans">대상 RectTransform</param>
|
||||
/// <param name="normalizedPosition">정규화된 위치 (0,0=왼쪽 하단, 1,1=오른쪽 상단)</param>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// // 요소를 부모의 오른쪽 상단에 배치
|
||||
/// // UI 요소를 부모의 오른쪽 상단 근처에 배치
|
||||
/// RectTransform elementRect = element.GetComponent<RectTransform>();
|
||||
/// elementRect.SetNormalizedPosition(new Vector2(0.95f, 0.95f));
|
||||
/// </code>
|
||||
@@ -170,13 +170,13 @@ namespace UVC.Extension
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RectTransform의 사각형 정보를 월드 좌표로 반환합니다.
|
||||
/// RectTransform의 월드 좌표 기준 사각 영역을 가져옵니다.
|
||||
/// </summary>
|
||||
/// <param name="trans">대상 RectTransform</param>
|
||||
/// <returns>월드 좌표계의 사각형 경계</returns>
|
||||
/// <param name="trans">대상 RectTransform</param>
|
||||
/// <returns>월드 좌표계에서의 Rect</returns>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// // UI 요소가 특정 월드 좌표를 포함하는지 확인
|
||||
/// // 마우스가 UI 요소 위에 있는지 확인
|
||||
/// RectTransform elementRect = element.GetComponent<RectTransform>();
|
||||
/// Rect worldRect = elementRect.GetWorldRect();
|
||||
/// Vector3 worldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
#nullable enable
|
||||
#nullable enable
|
||||
|
||||
using SampleProject;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.LightTransport;
|
||||
using UVC.Core;
|
||||
using UVC.Data;
|
||||
using UVC.Data.Core;
|
||||
@@ -34,7 +35,7 @@ namespace UVC.Factory.Alarm
|
||||
// 알람 데이터에 포함된 설비 ID를 이용해 실제 3D 객체를 찾기 위해 사용됩니다.
|
||||
private FactoryObjectManager? dataManager;
|
||||
|
||||
private bool testMode = true; // 테스트 모드 여부를 나타내는 플래그입니다.
|
||||
private bool testMode = false; // 테스트 모드 여부를 나타내는 플래그입니다.
|
||||
|
||||
// 테스트용으로 사용할 AGV 이름 리스트입니다.
|
||||
private List<string> agvNames = new List<string>();
|
||||
@@ -45,6 +46,10 @@ namespace UVC.Factory.Alarm
|
||||
// 테스트용으로, 새로 발생하는 알람에 AGV ID를 순차적으로 할당하기 위한 인덱스입니다.
|
||||
private int agvIdx = 50;
|
||||
|
||||
private List<IDataObject> buffers = new List<IDataObject>();
|
||||
|
||||
private bool runned = false;
|
||||
|
||||
/// <summary>
|
||||
/// AlarmManager의 초기화 메서드입니다.
|
||||
/// Awake 메서드에서 호출되며, MonoBehaviour가 생성될 때 한 번만 실행됩니다.
|
||||
@@ -54,6 +59,9 @@ namespace UVC.Factory.Alarm
|
||||
// SceneMain의 초기화가 완료되었을 때 OnSceneInitialized 메서드를 호출하도록 이벤트에 등록합니다.
|
||||
// 이를 통해 필요한 다른 매니저들이 준비된 후에 로직을 실행할 수 있습니다.
|
||||
SceneMain.Instance.Initialized += OnSceneInitialized;
|
||||
|
||||
//playback에서도 데이터를 업데이트 하기에 DataRepository에 핸들러를 추가합니다.
|
||||
DataRepository.Instance.AddDataUpdateHandler("ALARM", OnUpdateData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -81,7 +89,8 @@ namespace UVC.Factory.Alarm
|
||||
/// 이 메서드는 외부에서 호출되어야 알람 데이터 수신이 시작됩니다.
|
||||
/// </summary>
|
||||
public void Run()
|
||||
{
|
||||
{
|
||||
Debug.Log($"AlarmManager Run. buffers.Count:{buffers.Count}");
|
||||
// MQTT 파이프라인 정보(MqttSubscriptionConfig) 생성:
|
||||
// - "ALARM" 토픽을 구독합니다.
|
||||
// - 위에서 정의한 dataMask를 사용해 수신된 JSON 데이터를 DataObject로 변환합니다.
|
||||
@@ -96,10 +105,30 @@ namespace UVC.Factory.Alarm
|
||||
// 4. 생성한 파이프라인을 전역 MQTT 파이프라인에 추가하여 데이터 수신을 시작합니다.
|
||||
DataRepository.Instance.MqttReceiver.Add(pipelineInfo);
|
||||
|
||||
//playback에서도 데이터를 업데이트 하기에 DataRepository에 핸들러를 추가합니다.
|
||||
DataRepository.Instance.AddDataUpdateHandler("ALARM", OnUpdateData);
|
||||
runned = true;
|
||||
|
||||
// 초기 데이터가 있다면 즉시 업데이트를 수행합니다.
|
||||
if (buffers.Count == 0) {
|
||||
var buffer = DataRepository.Instance.GetData("ALARM");
|
||||
Debug.Log($"AlarmManager Run. buffer == null:{buffer == null}");
|
||||
if (buffer != null)
|
||||
{
|
||||
OnUpdateData(buffer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 초기 데이터가 있다면, OnUpdateData를 호출하여 기존 데이터를 처리합니다.
|
||||
foreach (var buffer in buffers)
|
||||
{
|
||||
OnUpdateData(buffer);
|
||||
}
|
||||
buffers.Clear(); // 초기 데이터 처리가 끝나면 버퍼를 비웁니다.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// MQTT 파이프라인으로부터 데이터가 업데이트될 때마다 호출되는 메인 핸들러입니다.
|
||||
/// 수신된 알람 데이터 배열을 분석하여 추가, 수정, 제거된 알람을 각각 처리합니다.
|
||||
@@ -113,12 +142,21 @@ namespace UVC.Factory.Alarm
|
||||
DataArray? arr = data as DataArray;
|
||||
if (arr == null || arr.Count == 0) return;
|
||||
|
||||
//Debug.Log($"AlarmManager OnUpdateData: count:{arr.Count}, Added={arr.AddedItems.Count}, Removed={arr.RemovedItems.Count}, Modified={arr.ModifiedList.Count}");
|
||||
|
||||
//3d 객체가 생성 된 후 호출 되도록 하기 위해
|
||||
// Run으로 호출 된 후 호출 되도록
|
||||
if (!runned)
|
||||
{
|
||||
buffers.Add(data);
|
||||
return;
|
||||
}
|
||||
|
||||
// 데이터 배열에서 추가, 제거, 수정된 항목 리스트를 가져옵니다.
|
||||
var AddedItems = arr.AddedItems;
|
||||
var RemovedItems = new List<DataObject>(arr.RemovedItems);
|
||||
var ModifiedList = arr.ModifiedList;
|
||||
|
||||
//Debug.Log($"AlarmManager OnUpdateData: Added={AddedItems.Count}, Removed={RemovedItems.Count}, Modified={ModifiedList.Count}");
|
||||
|
||||
// 'CLEAR_TIME'이 설정된 항목은 '해제된 알람'으로 간주하고, 제거 리스트에 추가합니다.
|
||||
// AddedItems나 ModifiedList에 포함되어 있더라도 CLEAR_TIME이 있으면 즉시 해제 처리하기 위함입니다.
|
||||
|
||||
@@ -7,16 +7,15 @@ using UnityEngine.UI;
|
||||
using UVC.Factory.Component;
|
||||
using UVC.Locale;
|
||||
using UVC.UI.Modal;
|
||||
using UVC.Util;
|
||||
|
||||
namespace UVC.Factory.Buttons
|
||||
{
|
||||
public class UISearchInput : MonoBehaviour
|
||||
{
|
||||
[SerializeField]
|
||||
private TMP_InputField inputField;
|
||||
|
||||
private Button button;
|
||||
private GameObject textArea;
|
||||
[SerializeField]
|
||||
private Button searchButton;
|
||||
|
||||
private bool initialized = false;
|
||||
|
||||
@@ -27,31 +26,23 @@ namespace UVC.Factory.Buttons
|
||||
SceneMain.Instance.Initialized += OnSceneInitialized;
|
||||
}
|
||||
|
||||
private void OnSceneInitialized()
|
||||
private void OnSceneInitialized()
|
||||
{
|
||||
inputField = GetComponent<TMP_InputField>();
|
||||
|
||||
button = GetComponentInChildren<Button>();
|
||||
button.onClick.AddListener(() =>
|
||||
searchButton.onClick.AddListener(() =>
|
||||
{
|
||||
isClicked = !isClicked;
|
||||
if (isClicked)
|
||||
{
|
||||
//button.image.color = ColorUtil.FromHex("#00B0B0");
|
||||
//textArea.gameObject.SetActive(true);
|
||||
inputField.Select();
|
||||
}
|
||||
else
|
||||
{
|
||||
Location(inputField.text);
|
||||
//button.image.color = Color.white;
|
||||
//textArea.gameObject.SetActive(false);
|
||||
inputField.OnDeselect(null);
|
||||
}
|
||||
});
|
||||
textArea = transform.Find("Text Area").gameObject;
|
||||
|
||||
inputField.onEndEdit.AddListener(OnFindLocation);
|
||||
//textArea.gameObject.SetActive(false);
|
||||
|
||||
Init();
|
||||
}
|
||||
@@ -64,8 +55,7 @@ namespace UVC.Factory.Buttons
|
||||
{
|
||||
Location(locationID);
|
||||
isClicked = false;
|
||||
button.image.color = Color.white;
|
||||
//textArea.gameObject.SetActive(false);
|
||||
searchButton.image.color = Color.white;
|
||||
inputField.OnDeselect(null);
|
||||
}
|
||||
}
|
||||
@@ -92,7 +82,6 @@ namespace UVC.Factory.Buttons
|
||||
inputField.placeholder.GetComponent<TextMeshProUGUI>().text = LocalizationManager.Instance.GetString("search_location");
|
||||
initialized = true;
|
||||
}
|
||||
//textArea.gameObject.SetActive(false);
|
||||
isClicked = false;
|
||||
}
|
||||
|
||||
@@ -106,10 +95,10 @@ namespace UVC.Factory.Buttons
|
||||
inputField = null;
|
||||
}
|
||||
|
||||
if (button != null)
|
||||
if (searchButton != null)
|
||||
{
|
||||
button.onClick.RemoveAllListeners();
|
||||
button = null;
|
||||
searchButton.onClick.RemoveAllListeners();
|
||||
searchButton = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,10 +109,9 @@ namespace UVC.Factory.Buttons
|
||||
{
|
||||
if (EventSystem.current.currentSelectedGameObject != null)
|
||||
return;
|
||||
//textArea.gameObject.SetActive(false);
|
||||
inputField.OnDeselect(null);
|
||||
inputField.text = "";
|
||||
button.image.color = Color.white;
|
||||
searchButton.image.color = Color.white;
|
||||
isClicked = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UVC.Data.Core;
|
||||
|
||||
@@ -35,11 +35,17 @@ namespace UVC.Factory.Component
|
||||
[Tooltip("이 거리(미터)를 초과하면 보간 없이 즉시 위치를 변경합니다.")]
|
||||
public float teleportDistanceThreshold = 5.0f; // 5미터 이상 차이나면 순간이동
|
||||
|
||||
|
||||
private Renderer renderer;
|
||||
|
||||
/// <summary>
|
||||
/// AGV 객체가 생성될 때 처음 한 번 호출되는 초기화 메서드입니다.
|
||||
/// </summary>
|
||||
private void Start()
|
||||
{
|
||||
|
||||
renderer = modelObject.GetComponent<Renderer>();
|
||||
|
||||
// 시작 시에는 현재 위치를 목표 위치로 설정하여 의도치 않은 움직임을 방지합니다.
|
||||
targetPosition = transform.position;
|
||||
targetRotation = transform.rotation;
|
||||
@@ -81,15 +87,15 @@ namespace UVC.Factory.Component
|
||||
}
|
||||
else // 이미 데이터가 있는 경우 (업데이트)
|
||||
{
|
||||
|
||||
if (data.Id == "HFF09CNA8061") Debug.Log($"AGV: {newData}");
|
||||
|
||||
// 새 데이터를 기반으로 목표 위치와 회전을 갱신합니다.
|
||||
UpdatePositionAndRotation(newData);
|
||||
// 기존 데이터(data)에 새로운 데이터(newData)의 내용을 덮어씁니다.
|
||||
foreach (var keyValue in newData)
|
||||
{
|
||||
if (data.ContainsKey(keyValue.Key))
|
||||
{
|
||||
data[keyValue.Key] = keyValue.Value;
|
||||
}
|
||||
{
|
||||
data[keyValue.Key] = keyValue.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,11 +117,14 @@ namespace UVC.Factory.Component
|
||||
}
|
||||
else // 이후 업데이트의 경우
|
||||
{
|
||||
bool isTeleport = false;
|
||||
|
||||
bool changed = false;
|
||||
|
||||
bool isTeleport = false;
|
||||
|
||||
float? newX = newData.GetFloat("X");
|
||||
float? newY = newData.GetFloat("Y");
|
||||
if (data.Id == "HFF09CNA8061") Debug.Log($"AGV newX.HasValue:{newX.HasValue}, newY.HasValue:{newY.HasValue}");
|
||||
if (newX.HasValue || newY.HasValue)
|
||||
{
|
||||
float x = data.GetFloat("X").Value;
|
||||
@@ -124,12 +133,13 @@ namespace UVC.Factory.Component
|
||||
Vector3 newTargetPosition = transform.position;
|
||||
if (newX.HasValue && x != newX) newTargetPosition.x = newX.Value * scaleFactor;
|
||||
if (newY.HasValue && y != newY) newTargetPosition.z = newY.Value * scaleFactor;
|
||||
|
||||
if (newTargetPosition != transform.position)
|
||||
// 현재 위치와 새로운 목표 위치 사이의 거리를 계산합니다.
|
||||
float distanceToTarget = Vector3.Distance(transform.position, newTargetPosition);
|
||||
if (data.Id == "HFF09CNA8061") Debug.Log($"AGV distanceToTarget:{distanceToTarget}, x:{newTargetPosition.x}_{transform.position.x}, z:{newTargetPosition.z}_{transform.position.z}, y:{newTargetPosition.y}_{transform.position.y}");
|
||||
if (distanceToTarget > 0)
|
||||
{
|
||||
|
||||
// 현재 위치와 새로운 목표 위치 사이의 거리를 계산합니다.
|
||||
float distanceToTarget = Vector3.Distance(transform.position, newTargetPosition);
|
||||
//Debug.Log($"AGV {data.GetString("VHL_NAME")} moving to new position: {newTargetPosition} (Distance: {distanceToTarget})");
|
||||
|
||||
// 거리가 설정된 임계값을 초과하면, 보간을 건너뛰고 즉시 위치을 설정합니다.
|
||||
if (distanceToTarget > teleportDistanceThreshold)
|
||||
@@ -141,6 +151,7 @@ namespace UVC.Factory.Component
|
||||
// 새로운 목표 지점을 설정합니다.
|
||||
// (순간이동을 했든 안 했든, 다음 프레임부터의 보간을 위해 목표 지점은 항상 갱신되어야 합니다.)
|
||||
this.targetPosition = newTargetPosition;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,12 +168,28 @@ namespace UVC.Factory.Component
|
||||
// 새로운 목표 지점을 설정합니다.
|
||||
// (순간이동을 했든 안 했든, 다음 프레임부터의 보간을 위해 목표 지점은 항상 갱신되어야 합니다.)
|
||||
this.targetRotation = newTargetRotation;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (data.Id == "HFF09CNA8061") Debug.Log($"AGV changed: {changed}");
|
||||
|
||||
if (changed)
|
||||
{
|
||||
ChangeColor(Color.red);
|
||||
}
|
||||
else
|
||||
{
|
||||
//ChangeColor(Color.white);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ChangeColor(Color color)
|
||||
{
|
||||
renderer.material.color = color;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unity에 의해 매 프레임마다 호출되는 메서드입니다.
|
||||
/// AGV의 현재 위치/회전을 목표 위치/회전으로 부드럽게 이동시키는 시각적 처리를 담당합니다.
|
||||
@@ -173,7 +200,7 @@ namespace UVC.Factory.Component
|
||||
if (transform.position != targetPosition)
|
||||
{
|
||||
// 목표 지점과의 거리가 매우 가까우면 (0.01미터 미만) 그냥 목표 위치로 설정하여 미세한 떨림을 방지합니다.
|
||||
if (Vector3.Distance(transform.position, targetPosition) < 0.1f)
|
||||
if (Vector3.Distance(transform.position, targetPosition) < 0.01f)
|
||||
{
|
||||
// 현재 위치와 목표 위치 사이의 거리가 임계값을 초과하면 순간이동합니다.
|
||||
transform.position = targetPosition;
|
||||
@@ -190,7 +217,7 @@ namespace UVC.Factory.Component
|
||||
if (transform.rotation != targetRotation)
|
||||
{
|
||||
// 목표 회전과의 각도 차이가 매우 작으면 (0.1도 미만) 그냥 목표 회전으로 설정합니다.
|
||||
if (Quaternion.Angle(transform.rotation, targetRotation) < 0.1f)
|
||||
if (Quaternion.Angle(transform.rotation, targetRotation) < 0.01f)
|
||||
{
|
||||
transform.rotation = targetRotation;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#nullable enable
|
||||
#nullable enable
|
||||
using Cysharp.Threading.Tasks;
|
||||
using SampleProject;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Unity.Burst.Intrinsics;
|
||||
using UnityEngine;
|
||||
using UVC.Core;
|
||||
using UVC.Data;
|
||||
@@ -94,6 +95,9 @@ namespace UVC.Factory.Component
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Action? OnAGVCreated;
|
||||
|
||||
private bool created = false;
|
||||
|
||||
/// <summary>
|
||||
@@ -102,28 +106,32 @@ namespace UVC.Factory.Component
|
||||
/// </summary>
|
||||
protected override void Init()
|
||||
{
|
||||
SceneMain.Instance.Initialized += OnSceneInitializedAsync;
|
||||
InitializePoolAsync().ContinueWith(() =>
|
||||
{
|
||||
//playback에서도 데이터를 업데이트 하기에 DataRepository에 핸들러를 추가합니다.
|
||||
DataRepository.Instance.AddDataUpdateHandler("AGV", OnUpdateData);
|
||||
|
||||
var pipelineInfo = new MqttSubscriptionConfig("AGV");
|
||||
var dataMapperValidator = DataMapperValidator.Get("AGV");
|
||||
if (dataMapperValidator?.DataMapper != null) pipelineInfo.setDataMapper(dataMapperValidator.DataMapper);
|
||||
if (dataMapperValidator?.Validator != null) pipelineInfo.setValidator(dataMapperValidator.Validator);
|
||||
|
||||
// 생성한 파이프라인 정보를 전역 MQTT 파이프라인에 추가합니다.
|
||||
DataRepository.Instance.MqttReceiver.Add(pipelineInfo);
|
||||
|
||||
SceneMain.Instance.Initialized += OnSceneInitialized;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 씬이 완전히 초기화된 후 호출됩니다.
|
||||
/// AGV 데이터를 수신하기 위한 MQTT 파이프라인을 설정합니다.
|
||||
/// </summary>
|
||||
private async void OnSceneInitializedAsync()
|
||||
private void OnSceneInitialized()
|
||||
{
|
||||
await InitializePoolAsync();
|
||||
|
||||
var pipelineInfo = new MqttSubscriptionConfig("AGV");
|
||||
|
||||
var dataMapperValidator = DataMapperValidator.Get("AGV");
|
||||
if (dataMapperValidator?.DataMapper != null) pipelineInfo.setDataMapper(dataMapperValidator.DataMapper);
|
||||
if (dataMapperValidator?.Validator != null) pipelineInfo.setValidator(dataMapperValidator.Validator);
|
||||
|
||||
// 생성한 파이프라인 정보를 전역 MQTT 파이프라인에 추가합니다.
|
||||
DataRepository.Instance.MqttReceiver.Add(pipelineInfo);
|
||||
|
||||
//playback에서도 데이터를 업데이트 하기에 DataRepository에 핸들러를 추가합니다.
|
||||
DataRepository.Instance.AddDataUpdateHandler("AGV", OnUpdateData);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -152,7 +160,7 @@ namespace UVC.Factory.Component
|
||||
{
|
||||
if (data == null || agvPool == null) return;
|
||||
|
||||
DataArray? arr = data as DataArray;
|
||||
DataArray ? arr = data as DataArray;
|
||||
if (arr == null || arr.Count == 0) return;
|
||||
|
||||
// 데이터 배열에서 추가, 제거, 수정된 항목 리스트를 가져옵니다.
|
||||
@@ -160,7 +168,7 @@ namespace UVC.Factory.Component
|
||||
var RemovedItems = arr.RemovedItems;
|
||||
var ModifiedList = arr.ModifiedList;
|
||||
|
||||
//Debug.Log($"AGVManager received data: Added={AddedItems.Count}, Removed={RemovedItems.Count}, Modified={ModifiedList.Count}");
|
||||
Debug.Log($"AGVManager received data: count:{arr.Count}, Added={AddedItems.Count}, Removed={RemovedItems.Count}, Modified={ModifiedList.Count}");
|
||||
|
||||
// 새로 추가된 AGV 처리
|
||||
foreach (var item in AddedItems.ToList())
|
||||
@@ -172,7 +180,7 @@ namespace UVC.Factory.Component
|
||||
continue;
|
||||
}
|
||||
agv.Info = new FactoryObjectInfo(
|
||||
item.GetString("NODE_ID"),
|
||||
item.GetString("VHL_NAME"),
|
||||
item.GetString("VHL_NAME"),
|
||||
"",
|
||||
"",
|
||||
@@ -207,7 +215,8 @@ namespace UVC.Factory.Component
|
||||
{
|
||||
created = true;
|
||||
// 씬이 처음 초기화될 때 AGVManager가 생성되었음을 알립니다.
|
||||
SceneMain.Instance.OnAGVManagerCreated();
|
||||
Debug.Log("AGVManager created and initialized.");
|
||||
OnAGVCreated?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,9 +227,10 @@ namespace UVC.Factory.Component
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
SceneMain.Instance.Initialized -= OnSceneInitializedAsync;
|
||||
SceneMain.Instance.Initialized -= OnSceneInitialized;
|
||||
DataRepository.Instance.RemoveDataUpdateHandler("AGV", OnUpdateData);
|
||||
agvPool?.ClearRecycledItems();
|
||||
OnAGVCreated = null; // 이벤트 핸들러 초기화
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace UVC.Factory.Playback
|
||||
httpRequestConfig.AddSplitConfig("ALARM", DataMapperValidator.Get("ALARM"));
|
||||
foreach (var item in list)
|
||||
{
|
||||
await HttpDataProcessor.ProcessSplitResponse(httpRequestConfig, item.data);
|
||||
HttpDataProcessor.ProcessSplitResponse(httpRequestConfig, item.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ namespace UVC.Factory.Playback
|
||||
httpRequestConfig.AddSplitConfig("ALARM", DataMapperValidator.Get("ALARM"));
|
||||
foreach (var item in list)
|
||||
{
|
||||
await HttpDataProcessor.ProcessSplitResponse(httpRequestConfig, item.data);
|
||||
HttpDataProcessor.ProcessSplitResponse(httpRequestConfig, item.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,6 +224,7 @@ namespace UVC.Network
|
||||
/// <returns>지정된 타입으로 변환된 응답 데이터</returns>
|
||||
private static async UniTask<T> Request_<T>(string url, string body = null, string methodString = "post", Dictionary<string, string> header = null, bool useAuth = false)
|
||||
{
|
||||
|
||||
HTTPMethods method = StringToMethod(methodString);
|
||||
|
||||
if (!url.Contains("http")) url = $"{Domain}{url}";
|
||||
@@ -249,11 +250,13 @@ namespace UVC.Network
|
||||
//Debug.Log($"Request APIToken :{AuthService.Instance.Entiti.accessToken}");
|
||||
if (body != null)
|
||||
{
|
||||
request.UploadSettings.UploadStream =
|
||||
new MemoryStream(Encoding.UTF8.GetBytes(body));
|
||||
request.UploadSettings.UploadStream = new MemoryStream(Encoding.UTF8.GetBytes(body));
|
||||
}
|
||||
|
||||
bool isMainThread = PlayerLoopHelper.IsMainThread;
|
||||
//var response = await request.GetFromJsonResultAsync<T>();
|
||||
var response = await request.GetAsStringAsync();
|
||||
if(!isMainThread) await UniTask.SwitchToThreadPool();
|
||||
log.ResponseData = response;
|
||||
log.ResponseDate = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
|
||||
ServerLog.LogHttpResponse(log);
|
||||
@@ -418,7 +421,9 @@ namespace UVC.Network
|
||||
HttpLogEntry log = ServerLog.LogHttpRequest(url, methodString, headerObject.ToString(Formatting.None), body, DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"));
|
||||
//var response = await request.GetFromJsonResultAsync<T>();
|
||||
var now = DateTime.UtcNow;
|
||||
bool isMainThread = PlayerLoopHelper.IsMainThread;
|
||||
var response = await request.GetAsStringAsync();
|
||||
if (!isMainThread) await UniTask.SwitchToThreadPool();
|
||||
var diff = DateTime.UtcNow - now;
|
||||
log.ResponseData = response;
|
||||
log.ResponseDate = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#nullable enable
|
||||
#nullable enable
|
||||
|
||||
using Cysharp.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
@@ -192,11 +192,11 @@ namespace UVC.Tests.Data
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HttpDataFetcher의 private infoList 필드 가져오기
|
||||
/// HttpDataFetcher의 private configList 필드 가져오기
|
||||
/// </summary>
|
||||
private Dictionary<string, HttpRequestConfig> GetInfoListField()
|
||||
{
|
||||
var fieldInfo = typeof(HttpDataFetcher).GetField("infoList",
|
||||
var fieldInfo = typeof(HttpDataFetcher).GetField("configList",
|
||||
BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
|
||||
return (Dictionary<string, HttpRequestConfig>)fieldInfo.GetValue(pipeLine);
|
||||
|
||||
@@ -31,24 +31,23 @@ namespace UVC.UI.Loading
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[SerializeField]
|
||||
private CanvasGroup canvasGroup;
|
||||
private float target = 0;
|
||||
[SerializeField]
|
||||
private Image loadinImage;
|
||||
|
||||
private float duration = 0.25f;
|
||||
private float target = 0;
|
||||
private float alpha = 1;
|
||||
private bool animatting = false;
|
||||
private Image loadinImage;
|
||||
private Transform loadingImageTransform;
|
||||
|
||||
private float loadingSpeed = 1.5f;
|
||||
private float rotationSpeed = 1.0f;
|
||||
private float rotationSpeed = -1.0f;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
canvasGroup = GetComponent<CanvasGroup>();
|
||||
loadinImage = transform.Find("loadingImage").GetComponent<Image>();
|
||||
{
|
||||
loadingImageTransform = loadinImage.transform;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UVC.Data.Core;
|
||||
using UVC.Factory.Component;
|
||||
using UVC.Factory.Playback;
|
||||
using UVC.Locale;
|
||||
using UVC.Log;
|
||||
using UVC.UI.Commands;
|
||||
@@ -216,7 +217,7 @@ namespace UVC.UI.Menu
|
||||
MenuItemData.CreateSeparator("file_sep2"), // 또 다른 구분선 추가
|
||||
new MenuItemData("file_exit", "menu_file_exit", new QuitApplicationCommand()) // 애플리케이션 종료 명령 연결
|
||||
}));
|
||||
|
||||
model.MenuItems.Add(new MenuItemData("Playback", "Playback", new PlaybackCommand()));
|
||||
// pool 로그
|
||||
model.MenuItems.Add(new MenuItemData("log", "Log", subMenuItems: new List<MenuItemData>
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"language": "ko",
|
||||
"targetFrameRate": 60,
|
||||
"fullScreenResolution": null,
|
||||
"window": {
|
||||
"fullScreenResolution": {
|
||||
|
||||
Reference in New Issue
Block a user