diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..718f17fa --- /dev/null +++ b/.editorconfig @@ -0,0 +1,684 @@ +[*] +charset = utf-8 +end_of_line = crlf +indent_size = 4 +indent_style = space +insert_final_newline = false +max_line_length = 120 +tab_width = 4 +trim_trailing_whitespace = false +ij_continuation_indent_size = 8 +ij_formatter_off_tag = @formatter:off +ij_formatter_on_tag = @formatter:on +ij_formatter_tags_enabled = false +ij_smart_tabs = false +ij_visual_guides = none +ij_wrap_on_typing = false + +[*.css] +ij_css_align_closing_brace_with_properties = false +ij_css_blank_lines_around_nested_selector = 1 +ij_css_blank_lines_between_blocks = 1 +ij_css_block_comment_add_space = false +ij_css_brace_placement = end_of_line +ij_css_enforce_quotes_on_format = false +ij_css_hex_color_long_format = false +ij_css_hex_color_lower_case = false +ij_css_hex_color_short_format = false +ij_css_hex_color_upper_case = false +ij_css_keep_blank_lines_in_code = 2 +ij_css_keep_indents_on_empty_lines = false +ij_css_keep_single_line_blocks = false +ij_css_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_css_space_after_colon = true +ij_css_space_before_opening_brace = true +ij_css_use_double_quotes = true +ij_css_value_alignment = do_not_align + +[*.less] +indent_size = 2 +ij_less_align_closing_brace_with_properties = false +ij_less_blank_lines_around_nested_selector = 1 +ij_less_blank_lines_between_blocks = 1 +ij_less_block_comment_add_space = false +ij_less_brace_placement = 0 +ij_less_enforce_quotes_on_format = false +ij_less_hex_color_long_format = false +ij_less_hex_color_lower_case = false +ij_less_hex_color_short_format = false +ij_less_hex_color_upper_case = false +ij_less_keep_blank_lines_in_code = 2 +ij_less_keep_indents_on_empty_lines = false +ij_less_keep_single_line_blocks = false +ij_less_line_comment_add_space = false +ij_less_line_comment_at_first_column = false +ij_less_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_less_space_after_colon = true +ij_less_space_before_opening_brace = true +ij_less_use_double_quotes = true +ij_less_value_alignment = 0 + +[*.properties] +ij_properties_align_group_field_declarations = false +ij_properties_keep_blank_lines = false +ij_properties_key_value_delimiter = equals +ij_properties_spaces_around_key_value_delimiter = false + +[*.sass] +indent_size = 2 +ij_sass_align_closing_brace_with_properties = false +ij_sass_blank_lines_around_nested_selector = 1 +ij_sass_blank_lines_between_blocks = 1 +ij_sass_brace_placement = 0 +ij_sass_enforce_quotes_on_format = false +ij_sass_hex_color_long_format = false +ij_sass_hex_color_lower_case = false +ij_sass_hex_color_short_format = false +ij_sass_hex_color_upper_case = false +ij_sass_keep_blank_lines_in_code = 2 +ij_sass_keep_indents_on_empty_lines = false +ij_sass_keep_single_line_blocks = false +ij_sass_line_comment_add_space = false +ij_sass_line_comment_at_first_column = false +ij_sass_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_sass_space_after_colon = true +ij_sass_space_before_opening_brace = true +ij_sass_use_double_quotes = true +ij_sass_value_alignment = 0 + +[*.scss] +indent_size = 2 +ij_scss_align_closing_brace_with_properties = false +ij_scss_blank_lines_around_nested_selector = 1 +ij_scss_blank_lines_between_blocks = 1 +ij_scss_block_comment_add_space = false +ij_scss_brace_placement = 0 +ij_scss_enforce_quotes_on_format = false +ij_scss_hex_color_long_format = false +ij_scss_hex_color_lower_case = false +ij_scss_hex_color_short_format = false +ij_scss_hex_color_upper_case = false +ij_scss_keep_blank_lines_in_code = 2 +ij_scss_keep_indents_on_empty_lines = false +ij_scss_keep_single_line_blocks = false +ij_scss_line_comment_add_space = false +ij_scss_line_comment_at_first_column = false +ij_scss_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_scss_space_after_colon = true +ij_scss_space_before_opening_brace = true +ij_scss_use_double_quotes = true +ij_scss_value_alignment = 0 + +[*.styl] +indent_size = 2 +ij_stylus_align_closing_brace_with_properties = false +ij_stylus_blank_lines_around_nested_selector = 1 +ij_stylus_blank_lines_between_blocks = 1 +ij_stylus_brace_placement = 0 +ij_stylus_enforce_quotes_on_format = false +ij_stylus_hex_color_long_format = false +ij_stylus_hex_color_lower_case = false +ij_stylus_hex_color_short_format = false +ij_stylus_hex_color_upper_case = false +ij_stylus_keep_blank_lines_in_code = 2 +ij_stylus_keep_indents_on_empty_lines = false +ij_stylus_keep_single_line_blocks = false +ij_stylus_properties_order = font,font-family,font-size,font-weight,font-style,font-variant,font-size-adjust,font-stretch,line-height,position,z-index,top,right,bottom,left,display,visibility,float,clear,overflow,overflow-x,overflow-y,clip,zoom,align-content,align-items,align-self,flex,flex-flow,flex-basis,flex-direction,flex-grow,flex-shrink,flex-wrap,justify-content,order,box-sizing,width,min-width,max-width,height,min-height,max-height,margin,margin-top,margin-right,margin-bottom,margin-left,padding,padding-top,padding-right,padding-bottom,padding-left,table-layout,empty-cells,caption-side,border-spacing,border-collapse,list-style,list-style-position,list-style-type,list-style-image,content,quotes,counter-reset,counter-increment,resize,cursor,user-select,nav-index,nav-up,nav-right,nav-down,nav-left,transition,transition-delay,transition-timing-function,transition-duration,transition-property,transform,transform-origin,animation,animation-name,animation-duration,animation-play-state,animation-timing-function,animation-delay,animation-iteration-count,animation-direction,text-align,text-align-last,vertical-align,white-space,text-decoration,text-emphasis,text-emphasis-color,text-emphasis-style,text-emphasis-position,text-indent,text-justify,letter-spacing,word-spacing,text-outline,text-transform,text-wrap,text-overflow,text-overflow-ellipsis,text-overflow-mode,word-wrap,word-break,tab-size,hyphens,pointer-events,opacity,color,border,border-width,border-style,border-color,border-top,border-top-width,border-top-style,border-top-color,border-right,border-right-width,border-right-style,border-right-color,border-bottom,border-bottom-width,border-bottom-style,border-bottom-color,border-left,border-left-width,border-left-style,border-left-color,border-radius,border-top-left-radius,border-top-right-radius,border-bottom-right-radius,border-bottom-left-radius,border-image,border-image-source,border-image-slice,border-image-width,border-image-outset,border-image-repeat,outline,outline-width,outline-style,outline-color,outline-offset,background,background-color,background-image,background-repeat,background-attachment,background-position,background-position-x,background-position-y,background-clip,background-origin,background-size,box-decoration-break,box-shadow,text-shadow +ij_stylus_space_after_colon = true +ij_stylus_space_before_opening_brace = true +ij_stylus_use_double_quotes = true +ij_stylus_value_alignment = 0 + +[*.vue] +indent_size = 2 +tab_width = 2 +ij_continuation_indent_size = 4 +ij_vue_indent_children_of_top_level = template +ij_vue_interpolation_new_line_after_start_delimiter = true +ij_vue_interpolation_new_line_before_end_delimiter = true +ij_vue_interpolation_wrap = off +ij_vue_keep_indents_on_empty_lines = false +ij_vue_spaces_within_interpolation_expressions = true + +[.editorconfig] +ij_editorconfig_align_group_field_declarations = false +ij_editorconfig_space_after_colon = false +ij_editorconfig_space_after_comma = true +ij_editorconfig_space_before_colon = false +ij_editorconfig_space_before_comma = false +ij_editorconfig_spaces_around_assignment_operators = true + +[{*.ant,*.appxmanifest,*.axml,*.cscfg,*.csdef,*.disco,*.filelayout,*.fxml,*.jhm,*.jnlp,*.jrxml,*.manifest,*.myapp,*.nuspec,*.rng,*.stylecop,*.svcmap,*.tld,*.tps,*.wadcfgx,*.webref,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul,StyleCop.Cache}] +ij_xml_align_attributes = true +ij_xml_align_text = false +ij_xml_attribute_wrap = normal +ij_xml_block_comment_add_space = false +ij_xml_block_comment_at_first_column = true +ij_xml_keep_blank_lines = 2 +ij_xml_keep_indents_on_empty_lines = false +ij_xml_keep_line_breaks = true +ij_xml_keep_line_breaks_in_text = true +ij_xml_keep_whitespaces = false +ij_xml_keep_whitespaces_around_cdata = preserve +ij_xml_keep_whitespaces_inside_cdata = false +ij_xml_line_comment_at_first_column = true +ij_xml_space_after_tag_name = false +ij_xml_space_around_equals_in_attribute = false +ij_xml_space_inside_empty_tag = false +ij_xml_text_wrap = normal + +[{*.ats,*.cts,*.mts,*.ts}] +ij_continuation_indent_size = 4 +ij_typescript_align_imports = false +ij_typescript_align_multiline_array_initializer_expression = false +ij_typescript_align_multiline_binary_operation = false +ij_typescript_align_multiline_chained_methods = false +ij_typescript_align_multiline_extends_list = false +ij_typescript_align_multiline_for = true +ij_typescript_align_multiline_parameters = true +ij_typescript_align_multiline_parameters_in_calls = false +ij_typescript_align_multiline_ternary_operation = false +ij_typescript_align_object_properties = 0 +ij_typescript_align_union_types = false +ij_typescript_align_var_statements = 0 +ij_typescript_array_initializer_new_line_after_left_brace = false +ij_typescript_array_initializer_right_brace_on_new_line = false +ij_typescript_array_initializer_wrap = off +ij_typescript_assignment_wrap = off +ij_typescript_binary_operation_sign_on_next_line = false +ij_typescript_binary_operation_wrap = off +ij_typescript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/** +ij_typescript_blank_lines_after_imports = 1 +ij_typescript_blank_lines_around_class = 1 +ij_typescript_blank_lines_around_field = 0 +ij_typescript_blank_lines_around_field_in_interface = 0 +ij_typescript_blank_lines_around_function = 1 +ij_typescript_blank_lines_around_method = 1 +ij_typescript_blank_lines_around_method_in_interface = 1 +ij_typescript_block_brace_style = end_of_line +ij_typescript_block_comment_add_space = false +ij_typescript_block_comment_at_first_column = true +ij_typescript_call_parameters_new_line_after_left_paren = false +ij_typescript_call_parameters_right_paren_on_new_line = false +ij_typescript_call_parameters_wrap = off +ij_typescript_catch_on_new_line = false +ij_typescript_chained_call_dot_on_new_line = true +ij_typescript_class_brace_style = end_of_line +ij_typescript_comma_on_new_line = false +ij_typescript_do_while_brace_force = never +ij_typescript_else_on_new_line = false +ij_typescript_enforce_trailing_comma = keep +ij_typescript_enum_constants_wrap = on_every_item +ij_typescript_extends_keyword_wrap = off +ij_typescript_extends_list_wrap = off +ij_typescript_field_prefix = _ +ij_typescript_file_name_style = relaxed +ij_typescript_finally_on_new_line = false +ij_typescript_for_brace_force = never +ij_typescript_for_statement_new_line_after_left_paren = false +ij_typescript_for_statement_right_paren_on_new_line = false +ij_typescript_for_statement_wrap = off +ij_typescript_force_quote_style = false +ij_typescript_force_semicolon_style = false +ij_typescript_function_expression_brace_style = end_of_line +ij_typescript_if_brace_force = never +ij_typescript_import_merge_members = global +ij_typescript_import_prefer_absolute_path = global +ij_typescript_import_sort_members = true +ij_typescript_import_sort_module_name = false +ij_typescript_import_use_node_resolution = true +ij_typescript_imports_wrap = on_every_item +ij_typescript_indent_case_from_switch = true +ij_typescript_indent_chained_calls = true +ij_typescript_indent_package_children = 0 +ij_typescript_jsdoc_include_types = false +ij_typescript_jsx_attribute_value = braces +ij_typescript_keep_blank_lines_in_code = 2 +ij_typescript_keep_first_column_comment = true +ij_typescript_keep_indents_on_empty_lines = false +ij_typescript_keep_line_breaks = true +ij_typescript_keep_simple_blocks_in_one_line = false +ij_typescript_keep_simple_methods_in_one_line = false +ij_typescript_line_comment_add_space = true +ij_typescript_line_comment_at_first_column = false +ij_typescript_method_brace_style = end_of_line +ij_typescript_method_call_chain_wrap = off +ij_typescript_method_parameters_new_line_after_left_paren = false +ij_typescript_method_parameters_right_paren_on_new_line = false +ij_typescript_method_parameters_wrap = off +ij_typescript_object_literal_wrap = on_every_item +ij_typescript_parentheses_expression_new_line_after_left_paren = false +ij_typescript_parentheses_expression_right_paren_on_new_line = false +ij_typescript_place_assignment_sign_on_next_line = false +ij_typescript_prefer_as_type_cast = false +ij_typescript_prefer_explicit_types_function_expression_returns = false +ij_typescript_prefer_explicit_types_function_returns = false +ij_typescript_prefer_explicit_types_vars_fields = false +ij_typescript_prefer_parameters_wrap = false +ij_typescript_reformat_c_style_comments = false +ij_typescript_space_after_colon = true +ij_typescript_space_after_comma = true +ij_typescript_space_after_dots_in_rest_parameter = false +ij_typescript_space_after_generator_mult = true +ij_typescript_space_after_property_colon = true +ij_typescript_space_after_quest = true +ij_typescript_space_after_type_colon = true +ij_typescript_space_after_unary_not = false +ij_typescript_space_before_async_arrow_lparen = true +ij_typescript_space_before_catch_keyword = true +ij_typescript_space_before_catch_left_brace = true +ij_typescript_space_before_catch_parentheses = true +ij_typescript_space_before_class_lbrace = true +ij_typescript_space_before_class_left_brace = true +ij_typescript_space_before_colon = true +ij_typescript_space_before_comma = false +ij_typescript_space_before_do_left_brace = true +ij_typescript_space_before_else_keyword = true +ij_typescript_space_before_else_left_brace = true +ij_typescript_space_before_finally_keyword = true +ij_typescript_space_before_finally_left_brace = true +ij_typescript_space_before_for_left_brace = true +ij_typescript_space_before_for_parentheses = true +ij_typescript_space_before_for_semicolon = false +ij_typescript_space_before_function_left_parenth = true +ij_typescript_space_before_generator_mult = false +ij_typescript_space_before_if_left_brace = true +ij_typescript_space_before_if_parentheses = true +ij_typescript_space_before_method_call_parentheses = false +ij_typescript_space_before_method_left_brace = true +ij_typescript_space_before_method_parentheses = false +ij_typescript_space_before_property_colon = false +ij_typescript_space_before_quest = true +ij_typescript_space_before_switch_left_brace = true +ij_typescript_space_before_switch_parentheses = true +ij_typescript_space_before_try_left_brace = true +ij_typescript_space_before_type_colon = false +ij_typescript_space_before_unary_not = false +ij_typescript_space_before_while_keyword = true +ij_typescript_space_before_while_left_brace = true +ij_typescript_space_before_while_parentheses = true +ij_typescript_spaces_around_additive_operators = true +ij_typescript_spaces_around_arrow_function_operator = true +ij_typescript_spaces_around_assignment_operators = true +ij_typescript_spaces_around_bitwise_operators = true +ij_typescript_spaces_around_equality_operators = true +ij_typescript_spaces_around_logical_operators = true +ij_typescript_spaces_around_multiplicative_operators = true +ij_typescript_spaces_around_relational_operators = true +ij_typescript_spaces_around_shift_operators = true +ij_typescript_spaces_around_unary_operator = false +ij_typescript_spaces_within_array_initializer_brackets = false +ij_typescript_spaces_within_brackets = false +ij_typescript_spaces_within_catch_parentheses = false +ij_typescript_spaces_within_for_parentheses = false +ij_typescript_spaces_within_if_parentheses = false +ij_typescript_spaces_within_imports = false +ij_typescript_spaces_within_interpolation_expressions = false +ij_typescript_spaces_within_method_call_parentheses = false +ij_typescript_spaces_within_method_parentheses = false +ij_typescript_spaces_within_object_literal_braces = false +ij_typescript_spaces_within_object_type_braces = true +ij_typescript_spaces_within_parentheses = false +ij_typescript_spaces_within_switch_parentheses = false +ij_typescript_spaces_within_type_assertion = false +ij_typescript_spaces_within_union_types = true +ij_typescript_spaces_within_while_parentheses = false +ij_typescript_special_else_if_treatment = true +ij_typescript_ternary_operation_signs_on_next_line = false +ij_typescript_ternary_operation_wrap = off +ij_typescript_union_types_wrap = on_every_item +ij_typescript_use_chained_calls_group_indents = false +ij_typescript_use_double_quotes = true +ij_typescript_use_explicit_js_extension = auto +ij_typescript_use_path_mapping = always +ij_typescript_use_public_modifier = false +ij_typescript_use_semicolon_after_statement = true +ij_typescript_var_declaration_wrap = normal +ij_typescript_while_brace_force = never +ij_typescript_while_on_new_line = false +ij_typescript_wrap_comments = false + +[{*.bash,*.sh,*.zsh}] +indent_size = 2 +tab_width = 2 +ij_shell_binary_ops_start_line = false +ij_shell_keep_column_alignment_padding = false +ij_shell_minify_program = false +ij_shell_redirect_followed_by_space = false +ij_shell_switch_cases_indented = false +ij_shell_use_unix_line_separator = true + +[{*.cjs,*.js}] +ij_continuation_indent_size = 4 +ij_javascript_align_imports = false +ij_javascript_align_multiline_array_initializer_expression = false +ij_javascript_align_multiline_binary_operation = false +ij_javascript_align_multiline_chained_methods = false +ij_javascript_align_multiline_extends_list = false +ij_javascript_align_multiline_for = true +ij_javascript_align_multiline_parameters = true +ij_javascript_align_multiline_parameters_in_calls = false +ij_javascript_align_multiline_ternary_operation = false +ij_javascript_align_object_properties = 0 +ij_javascript_align_union_types = false +ij_javascript_align_var_statements = 0 +ij_javascript_array_initializer_new_line_after_left_brace = false +ij_javascript_array_initializer_right_brace_on_new_line = false +ij_javascript_array_initializer_wrap = off +ij_javascript_assignment_wrap = off +ij_javascript_binary_operation_sign_on_next_line = false +ij_javascript_binary_operation_wrap = off +ij_javascript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/** +ij_javascript_blank_lines_after_imports = 1 +ij_javascript_blank_lines_around_class = 1 +ij_javascript_blank_lines_around_field = 0 +ij_javascript_blank_lines_around_function = 1 +ij_javascript_blank_lines_around_method = 1 +ij_javascript_block_brace_style = end_of_line +ij_javascript_block_comment_add_space = false +ij_javascript_block_comment_at_first_column = true +ij_javascript_call_parameters_new_line_after_left_paren = false +ij_javascript_call_parameters_right_paren_on_new_line = false +ij_javascript_call_parameters_wrap = off +ij_javascript_catch_on_new_line = false +ij_javascript_chained_call_dot_on_new_line = true +ij_javascript_class_brace_style = end_of_line +ij_javascript_comma_on_new_line = false +ij_javascript_do_while_brace_force = never +ij_javascript_else_on_new_line = false +ij_javascript_enforce_trailing_comma = keep +ij_javascript_extends_keyword_wrap = off +ij_javascript_extends_list_wrap = off +ij_javascript_field_prefix = _ +ij_javascript_file_name_style = relaxed +ij_javascript_finally_on_new_line = false +ij_javascript_for_brace_force = never +ij_javascript_for_statement_new_line_after_left_paren = false +ij_javascript_for_statement_right_paren_on_new_line = false +ij_javascript_for_statement_wrap = off +ij_javascript_force_quote_style = false +ij_javascript_force_semicolon_style = false +ij_javascript_function_expression_brace_style = end_of_line +ij_javascript_if_brace_force = never +ij_javascript_import_merge_members = global +ij_javascript_import_prefer_absolute_path = global +ij_javascript_import_sort_members = true +ij_javascript_import_sort_module_name = false +ij_javascript_import_use_node_resolution = true +ij_javascript_imports_wrap = on_every_item +ij_javascript_indent_case_from_switch = true +ij_javascript_indent_chained_calls = true +ij_javascript_indent_package_children = 0 +ij_javascript_jsx_attribute_value = braces +ij_javascript_keep_blank_lines_in_code = 2 +ij_javascript_keep_first_column_comment = true +ij_javascript_keep_indents_on_empty_lines = false +ij_javascript_keep_line_breaks = true +ij_javascript_keep_simple_blocks_in_one_line = false +ij_javascript_keep_simple_methods_in_one_line = false +ij_javascript_line_comment_add_space = true +ij_javascript_line_comment_at_first_column = false +ij_javascript_method_brace_style = end_of_line +ij_javascript_method_call_chain_wrap = off +ij_javascript_method_parameters_new_line_after_left_paren = false +ij_javascript_method_parameters_right_paren_on_new_line = false +ij_javascript_method_parameters_wrap = off +ij_javascript_object_literal_wrap = on_every_item +ij_javascript_parentheses_expression_new_line_after_left_paren = false +ij_javascript_parentheses_expression_right_paren_on_new_line = false +ij_javascript_place_assignment_sign_on_next_line = false +ij_javascript_prefer_as_type_cast = false +ij_javascript_prefer_explicit_types_function_expression_returns = false +ij_javascript_prefer_explicit_types_function_returns = false +ij_javascript_prefer_explicit_types_vars_fields = false +ij_javascript_prefer_parameters_wrap = false +ij_javascript_reformat_c_style_comments = false +ij_javascript_space_after_colon = true +ij_javascript_space_after_comma = true +ij_javascript_space_after_dots_in_rest_parameter = false +ij_javascript_space_after_generator_mult = true +ij_javascript_space_after_property_colon = true +ij_javascript_space_after_quest = true +ij_javascript_space_after_type_colon = true +ij_javascript_space_after_unary_not = false +ij_javascript_space_before_async_arrow_lparen = true +ij_javascript_space_before_catch_keyword = true +ij_javascript_space_before_catch_left_brace = true +ij_javascript_space_before_catch_parentheses = true +ij_javascript_space_before_class_lbrace = true +ij_javascript_space_before_class_left_brace = true +ij_javascript_space_before_colon = true +ij_javascript_space_before_comma = false +ij_javascript_space_before_do_left_brace = true +ij_javascript_space_before_else_keyword = true +ij_javascript_space_before_else_left_brace = true +ij_javascript_space_before_finally_keyword = true +ij_javascript_space_before_finally_left_brace = true +ij_javascript_space_before_for_left_brace = true +ij_javascript_space_before_for_parentheses = true +ij_javascript_space_before_for_semicolon = false +ij_javascript_space_before_function_left_parenth = true +ij_javascript_space_before_generator_mult = false +ij_javascript_space_before_if_left_brace = true +ij_javascript_space_before_if_parentheses = true +ij_javascript_space_before_method_call_parentheses = false +ij_javascript_space_before_method_left_brace = true +ij_javascript_space_before_method_parentheses = false +ij_javascript_space_before_property_colon = false +ij_javascript_space_before_quest = true +ij_javascript_space_before_switch_left_brace = true +ij_javascript_space_before_switch_parentheses = true +ij_javascript_space_before_try_left_brace = true +ij_javascript_space_before_type_colon = false +ij_javascript_space_before_unary_not = false +ij_javascript_space_before_while_keyword = true +ij_javascript_space_before_while_left_brace = true +ij_javascript_space_before_while_parentheses = true +ij_javascript_spaces_around_additive_operators = true +ij_javascript_spaces_around_arrow_function_operator = true +ij_javascript_spaces_around_assignment_operators = true +ij_javascript_spaces_around_bitwise_operators = true +ij_javascript_spaces_around_equality_operators = true +ij_javascript_spaces_around_logical_operators = true +ij_javascript_spaces_around_multiplicative_operators = true +ij_javascript_spaces_around_relational_operators = true +ij_javascript_spaces_around_shift_operators = true +ij_javascript_spaces_around_unary_operator = false +ij_javascript_spaces_within_array_initializer_brackets = false +ij_javascript_spaces_within_brackets = false +ij_javascript_spaces_within_catch_parentheses = false +ij_javascript_spaces_within_for_parentheses = false +ij_javascript_spaces_within_if_parentheses = false +ij_javascript_spaces_within_imports = false +ij_javascript_spaces_within_interpolation_expressions = false +ij_javascript_spaces_within_method_call_parentheses = false +ij_javascript_spaces_within_method_parentheses = false +ij_javascript_spaces_within_object_literal_braces = false +ij_javascript_spaces_within_object_type_braces = true +ij_javascript_spaces_within_parentheses = false +ij_javascript_spaces_within_switch_parentheses = false +ij_javascript_spaces_within_type_assertion = false +ij_javascript_spaces_within_union_types = true +ij_javascript_spaces_within_while_parentheses = false +ij_javascript_special_else_if_treatment = true +ij_javascript_ternary_operation_signs_on_next_line = false +ij_javascript_ternary_operation_wrap = off +ij_javascript_union_types_wrap = on_every_item +ij_javascript_use_chained_calls_group_indents = false +ij_javascript_use_double_quotes = true +ij_javascript_use_explicit_js_extension = auto +ij_javascript_use_path_mapping = always +ij_javascript_use_public_modifier = false +ij_javascript_use_semicolon_after_statement = true +ij_javascript_var_declaration_wrap = normal +ij_javascript_while_brace_force = never +ij_javascript_while_on_new_line = false +ij_javascript_wrap_comments = false + +[{*.cjsx,*.coffee}] +indent_size = 2 +tab_width = 2 +ij_continuation_indent_size = 2 +ij_coffeescript_align_function_body = false +ij_coffeescript_align_imports = false +ij_coffeescript_align_multiline_array_initializer_expression = true +ij_coffeescript_align_multiline_parameters = true +ij_coffeescript_align_multiline_parameters_in_calls = false +ij_coffeescript_align_object_properties = 0 +ij_coffeescript_align_union_types = false +ij_coffeescript_align_var_statements = 0 +ij_coffeescript_array_initializer_new_line_after_left_brace = false +ij_coffeescript_array_initializer_right_brace_on_new_line = false +ij_coffeescript_array_initializer_wrap = normal +ij_coffeescript_blacklist_imports = rxjs/Rx,node_modules/**,**/node_modules/**,@angular/material,@angular/material/typings/** +ij_coffeescript_blank_lines_around_function = 1 +ij_coffeescript_call_parameters_new_line_after_left_paren = false +ij_coffeescript_call_parameters_right_paren_on_new_line = false +ij_coffeescript_call_parameters_wrap = normal +ij_coffeescript_chained_call_dot_on_new_line = true +ij_coffeescript_comma_on_new_line = false +ij_coffeescript_enforce_trailing_comma = keep +ij_coffeescript_field_prefix = _ +ij_coffeescript_file_name_style = relaxed +ij_coffeescript_force_quote_style = false +ij_coffeescript_force_semicolon_style = false +ij_coffeescript_function_expression_brace_style = end_of_line +ij_coffeescript_import_merge_members = global +ij_coffeescript_import_prefer_absolute_path = global +ij_coffeescript_import_sort_members = true +ij_coffeescript_import_sort_module_name = false +ij_coffeescript_import_use_node_resolution = true +ij_coffeescript_imports_wrap = on_every_item +ij_coffeescript_indent_chained_calls = true +ij_coffeescript_indent_package_children = 0 +ij_coffeescript_jsx_attribute_value = braces +ij_coffeescript_keep_blank_lines_in_code = 2 +ij_coffeescript_keep_first_column_comment = true +ij_coffeescript_keep_indents_on_empty_lines = false +ij_coffeescript_keep_line_breaks = true +ij_coffeescript_keep_simple_methods_in_one_line = false +ij_coffeescript_method_parameters_new_line_after_left_paren = false +ij_coffeescript_method_parameters_right_paren_on_new_line = false +ij_coffeescript_method_parameters_wrap = off +ij_coffeescript_object_literal_wrap = on_every_item +ij_coffeescript_prefer_as_type_cast = false +ij_coffeescript_prefer_explicit_types_function_expression_returns = false +ij_coffeescript_prefer_explicit_types_function_returns = false +ij_coffeescript_prefer_explicit_types_vars_fields = false +ij_coffeescript_reformat_c_style_comments = false +ij_coffeescript_space_after_comma = true +ij_coffeescript_space_after_dots_in_rest_parameter = false +ij_coffeescript_space_after_generator_mult = true +ij_coffeescript_space_after_property_colon = true +ij_coffeescript_space_after_type_colon = true +ij_coffeescript_space_after_unary_not = false +ij_coffeescript_space_before_async_arrow_lparen = true +ij_coffeescript_space_before_class_lbrace = true +ij_coffeescript_space_before_comma = false +ij_coffeescript_space_before_function_left_parenth = true +ij_coffeescript_space_before_generator_mult = false +ij_coffeescript_space_before_property_colon = false +ij_coffeescript_space_before_type_colon = false +ij_coffeescript_space_before_unary_not = false +ij_coffeescript_spaces_around_additive_operators = true +ij_coffeescript_spaces_around_arrow_function_operator = true +ij_coffeescript_spaces_around_assignment_operators = true +ij_coffeescript_spaces_around_bitwise_operators = true +ij_coffeescript_spaces_around_equality_operators = true +ij_coffeescript_spaces_around_logical_operators = true +ij_coffeescript_spaces_around_multiplicative_operators = true +ij_coffeescript_spaces_around_relational_operators = true +ij_coffeescript_spaces_around_shift_operators = true +ij_coffeescript_spaces_around_unary_operator = false +ij_coffeescript_spaces_within_array_initializer_braces = false +ij_coffeescript_spaces_within_array_initializer_brackets = false +ij_coffeescript_spaces_within_imports = false +ij_coffeescript_spaces_within_index_brackets = false +ij_coffeescript_spaces_within_interpolation_expressions = false +ij_coffeescript_spaces_within_method_call_parentheses = false +ij_coffeescript_spaces_within_method_parentheses = false +ij_coffeescript_spaces_within_object_braces = false +ij_coffeescript_spaces_within_object_literal_braces = false +ij_coffeescript_spaces_within_object_type_braces = true +ij_coffeescript_spaces_within_range_brackets = false +ij_coffeescript_spaces_within_type_assertion = false +ij_coffeescript_spaces_within_union_types = true +ij_coffeescript_union_types_wrap = on_every_item +ij_coffeescript_use_chained_calls_group_indents = false +ij_coffeescript_use_double_quotes = true +ij_coffeescript_use_explicit_js_extension = auto +ij_coffeescript_use_path_mapping = always +ij_coffeescript_use_public_modifier = false +ij_coffeescript_use_semicolon_after_statement = false +ij_coffeescript_var_declaration_wrap = normal + +[{*.har,*.inputactions,*.jsb2,*.jsb3,*.json,.babelrc,.eslintrc,.stylelintrc,bowerrc,jest.config}] +indent_size = 2 +ij_json_keep_blank_lines_in_code = 0 +ij_json_keep_indents_on_empty_lines = false +ij_json_keep_line_breaks = true +ij_json_space_after_colon = true +ij_json_space_after_comma = true +ij_json_space_before_colon = true +ij_json_space_before_comma = false +ij_json_spaces_within_braces = false +ij_json_spaces_within_brackets = false +ij_json_wrap_long_lines = false + +[{*.htm,*.html,*.ng,*.sht,*.shtm,*.shtml}] +ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3 +ij_html_align_attributes = true +ij_html_align_text = false +ij_html_attribute_wrap = normal +ij_html_block_comment_add_space = false +ij_html_block_comment_at_first_column = true +ij_html_do_not_align_children_of_min_lines = 0 +ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p +ij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot +ij_html_enforce_quotes = false +ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var +ij_html_keep_blank_lines = 2 +ij_html_keep_indents_on_empty_lines = false +ij_html_keep_line_breaks = true +ij_html_keep_line_breaks_in_text = true +ij_html_keep_whitespaces = false +ij_html_keep_whitespaces_inside = span,pre,textarea +ij_html_line_comment_at_first_column = true +ij_html_new_line_after_last_attribute = never +ij_html_new_line_before_first_attribute = never +ij_html_quote_style = double +ij_html_remove_new_line_before_tags = br +ij_html_space_after_tag_name = false +ij_html_space_around_equality_in_attribute = false +ij_html_space_inside_empty_tag = false +ij_html_text_wrap = normal + +[{*.markdown,*.md}] +ij_markdown_force_one_space_after_blockquote_symbol = true +ij_markdown_force_one_space_after_header_symbol = true +ij_markdown_force_one_space_after_list_bullet = true +ij_markdown_force_one_space_between_words = true +ij_markdown_insert_quote_arrows_on_wrap = true +ij_markdown_keep_indents_on_empty_lines = false +ij_markdown_keep_line_breaks_inside_text_blocks = true +ij_markdown_max_lines_around_block_elements = 1 +ij_markdown_max_lines_around_header = 1 +ij_markdown_max_lines_between_paragraphs = 1 +ij_markdown_min_lines_around_block_elements = 1 +ij_markdown_min_lines_around_header = 1 +ij_markdown_min_lines_between_paragraphs = 1 +ij_markdown_wrap_text_if_long = true +ij_markdown_wrap_text_inside_blockquotes = true + +[{*.yaml,*.yml}] +indent_size = 2 +ij_yaml_align_values_properties = do_not_align +ij_yaml_autoinsert_sequence_marker = true +ij_yaml_block_mapping_on_new_line = false +ij_yaml_indent_sequence_value = true +ij_yaml_keep_indents_on_empty_lines = false +ij_yaml_keep_line_breaks = true +ij_yaml_sequence_on_new_line = false +ij_yaml_space_before_colon = false +ij_yaml_spaces_within_braces = true +ij_yaml_spaces_within_brackets = true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..bba1726a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: "Need Help with Creating an Addon?" + url: "https://discord.gg/wusTQYbYTc" + about: "Join our discord and look for #nh-addon-discussion" diff --git a/.github/workflows/docs_build.yml b/.github/workflows/docs_build.yml index 722a4857..f5b18eae 100644 --- a/.github/workflows/docs_build.yml +++ b/.github/workflows/docs_build.yml @@ -60,12 +60,6 @@ jobs: - name: Copy Schemas run: cp -rf NewHorizons/Schemas content/pages/ - - - name: Cache Site - uses: actions/cache@v2 - with: - path: .m_cache - key: docs-cache - name: Build Site uses: VaultVulp/action-pipenv@v2.0.1 diff --git a/.gitignore b/.gitignore index 941bd9e5..0b5d3b3c 100644 --- a/.gitignore +++ b/.gitignore @@ -411,7 +411,8 @@ NewHorizons/Properties/** # Docs docs/out/** docs/content/schemas/** -docs/schemas/** +docs/content/pages/[Ss]chemas/** +docs/.m_cache/** # Unity project new-horizons-unity diff --git a/NewHorizons/AssetBundle/Tornado_BH_CycloneDetail_d.png b/NewHorizons/AssetBundle/Tornado_BH_CycloneDetail_d.png new file mode 100644 index 00000000..c5bd5190 Binary files /dev/null and b/NewHorizons/AssetBundle/Tornado_BH_CycloneDetail_d.png differ diff --git a/NewHorizons/AssetBundle/Tornado_BH_Cyclone_02_d.png b/NewHorizons/AssetBundle/Tornado_BH_Cyclone_02_d.png new file mode 100644 index 00000000..317b3bf4 Binary files /dev/null and b/NewHorizons/AssetBundle/Tornado_BH_Cyclone_02_d.png differ diff --git a/NewHorizons/Builder/Atmosphere/AirBuilder.cs b/NewHorizons/Builder/Atmosphere/AirBuilder.cs index 649159a9..e39d216c 100644 --- a/NewHorizons/Builder/Atmosphere/AirBuilder.cs +++ b/NewHorizons/Builder/Atmosphere/AirBuilder.cs @@ -9,19 +9,19 @@ namespace NewHorizons.Builder.Atmosphere GameObject airGO = new GameObject("Air"); airGO.SetActive(false); airGO.layer = 17; - airGO.transform.parent = sector?.transform ?? planetGO.transform; + airGO.transform.parent = sector?.transform ? sector.transform : planetGO.transform; - SphereCollider SC = airGO.AddComponent(); - SC.isTrigger = true; - SC.radius = info.Scale; + SphereCollider sc = airGO.AddComponent(); + sc.isTrigger = true; + sc.radius = info.Scale; - SimpleFluidVolume SFV = airGO.AddComponent(); - SFV._layer = 5; - SFV._priority = 1; - SFV._density = 1.2f; - SFV._fluidType = FluidVolume.Type.AIR; - SFV._allowShipAutoroll = true; - SFV._disableOnStart = false; + SimpleFluidVolume sfv = airGO.AddComponent(); + sfv._layer = 5; + sfv._priority = 1; + sfv._density = 1.2f; + sfv._fluidType = FluidVolume.Type.AIR; + sfv._allowShipAutoroll = true; + sfv._disableOnStart = false; if (info.HasOxygen) { @@ -30,10 +30,10 @@ namespace NewHorizons.Builder.Atmosphere if (info.IsRaining) { - VisorRainEffectVolume VREF = airGO.AddComponent(); - VREF._rainDirection = VisorRainEffectVolume.RainDirection.Radial; - VREF._layer = 0; - VREF._priority = 0; + var vref = airGO.AddComponent(); + vref._rainDirection = VisorRainEffectVolume.RainDirection.Radial; + vref._layer = 0; + vref._priority = 0; AudioSource AS = airGO.AddComponent(); AS.mute = false; @@ -49,10 +49,10 @@ namespace NewHorizons.Builder.Atmosphere AS.spatialBlend = 0f; AS.reverbZoneMix = 1f; - OWAudioSource OWAS = airGO.AddComponent(); - OWAS._audioLibraryClip = AudioType.GD_RainAmbient_LP; - OWAS.SetClipSelectionType(OWAudioSource.ClipSelectionOnPlay.RANDOM); - OWAS.SetTrack(OWAudioMixer.TrackName.Environment); + var owAudioSource = airGO.AddComponent(); + owAudioSource._audioLibraryClip = AudioType.GD_RainAmbient_LP; + owAudioSource.SetClipSelectionType(OWAudioSource.ClipSelectionOnPlay.RANDOM); + owAudioSource.SetTrack(OWAudioMixer.TrackName.Environment); airGO.AddComponent(); } diff --git a/NewHorizons/Builder/Atmosphere/AtmosphereBuilder.cs b/NewHorizons/Builder/Atmosphere/AtmosphereBuilder.cs index f8cb0070..61da791c 100644 --- a/NewHorizons/Builder/Atmosphere/AtmosphereBuilder.cs +++ b/NewHorizons/Builder/Atmosphere/AtmosphereBuilder.cs @@ -4,6 +4,10 @@ namespace NewHorizons.Builder.Atmosphere { public static class AtmosphereBuilder { + private static readonly int InnerRadius = Shader.PropertyToID("_InnerRadius"); + private static readonly int OuterRadius = Shader.PropertyToID("_OuterRadius"); + private static readonly int SkyColor = Shader.PropertyToID("_SkyColor"); + public static void Make(GameObject planetGO, Sector sector, AtmosphereModule atmosphereModule, float surfaceSize) { GameObject atmoGO = new GameObject("Atmosphere"); @@ -12,16 +16,15 @@ namespace NewHorizons.Builder.Atmosphere if (atmosphereModule.UseAtmosphereShader) { - GameObject atmo = GameObject.Instantiate(GameObject.Find("TimberHearth_Body/Atmosphere_TH/AtmoSphere")); - atmo.transform.parent = atmoGO.transform; + GameObject atmo = GameObject.Instantiate(GameObject.Find("TimberHearth_Body/Atmosphere_TH/AtmoSphere"), atmoGO.transform, true); atmo.transform.position = planetGO.transform.TransformPoint(Vector3.zero); atmo.transform.localScale = Vector3.one * atmosphereModule.Size * 1.2f; foreach (var meshRenderer in atmo.GetComponentsInChildren()) { - meshRenderer.material.SetFloat("_InnerRadius", atmosphereModule.Clouds != null ? atmosphereModule.Size : surfaceSize); - meshRenderer.material.SetFloat("_OuterRadius", atmosphereModule.Size * 1.2f); + meshRenderer.material.SetFloat(InnerRadius, atmosphereModule.Clouds != null ? atmosphereModule.Size : surfaceSize); + meshRenderer.material.SetFloat(OuterRadius, atmosphereModule.Size * 1.2f); if (atmosphereModule.AtmosphereTint != null) - meshRenderer.material.SetColor("_SkyColor", atmosphereModule.AtmosphereTint.ToColor()); + meshRenderer.material.SetColor(SkyColor, atmosphereModule.AtmosphereTint.ToColor()); } atmo.SetActive(true); diff --git a/NewHorizons/Builder/Atmosphere/CloudsBuilder.cs b/NewHorizons/Builder/Atmosphere/CloudsBuilder.cs index aafbde20..a50a0059 100644 --- a/NewHorizons/Builder/Atmosphere/CloudsBuilder.cs +++ b/NewHorizons/Builder/Atmosphere/CloudsBuilder.cs @@ -11,6 +11,11 @@ namespace NewHorizons.Builder.Atmosphere private static Shader _sphereShader = null; private static Material[] _gdCloudMaterials; private static GameObject _lightningPrefab; + private static readonly int Color1 = Shader.PropertyToID("_Color"); + private static readonly int TintColor = Shader.PropertyToID("_TintColor"); + private static readonly int MainTex = Shader.PropertyToID("_MainTex"); + private static readonly int RampTex = Shader.PropertyToID("_RampTex"); + private static readonly int CapTex = Shader.PropertyToID("_CapTex"); public static void Make(GameObject planetGO, Sector sector, AtmosphereModule atmo, IModBehaviour mod) { @@ -39,8 +44,8 @@ namespace NewHorizons.Builder.Atmosphere var bottomTSRTempArray = new Material[2]; bottomTSRTempArray[0] = new Material(bottomTSRMaterials[0]); - bottomTSRTempArray[0].SetColor("_Color", bottomColor); - bottomTSRTempArray[0].SetColor("_TintColor", bottomColor); + bottomTSRTempArray[0].SetColor(Color1, bottomColor); + bottomTSRTempArray[0].SetColor(TintColor, bottomColor); bottomTSRTempArray[1] = new Material(bottomTSRMaterials[1]); @@ -133,7 +138,7 @@ namespace NewHorizons.Builder.Atmosphere public static GameObject MakeTopClouds(GameObject rootObject, AtmosphereModule atmo, IModBehaviour mod) { - Color cloudTint = atmo.Clouds.Tint == null ? Color.white : atmo.Clouds.Tint.ToColor(); + Color cloudTint = atmo.Clouds.Tint?.ToColor() ?? Color.white; Texture2D image, cap, ramp; @@ -188,12 +193,12 @@ namespace NewHorizons.Builder.Atmosphere foreach (var material in topMR.sharedMaterials) { - material.SetColor("_Color", cloudTint); - material.SetColor("_TintColor", cloudTint); + material.SetColor(Color1, cloudTint); + material.SetColor(TintColor, cloudTint); - material.SetTexture("_MainTex", image); - material.SetTexture("_RampTex", ramp); - material.SetTexture("_CapTex", cap); + material.SetTexture(MainTex, image); + material.SetTexture(RampTex, ramp); + material.SetTexture(CapTex, cap); } if (atmo.Clouds.Unlit) diff --git a/NewHorizons/Builder/Atmosphere/VolumesBuilder.cs b/NewHorizons/Builder/Atmosphere/VolumesBuilder.cs index 545de8ff..f39da7c9 100644 --- a/NewHorizons/Builder/Atmosphere/VolumesBuilder.cs +++ b/NewHorizons/Builder/Atmosphere/VolumesBuilder.cs @@ -4,6 +4,8 @@ namespace NewHorizons.Builder.Atmosphere { public static class VolumesBuilder { + private static readonly int FogColor = Shader.PropertyToID("_FogColor"); + public static void Make(GameObject planetGO, PlanetConfig config, float sphereOfInfluence) { var innerRadius = config.Base.SurfaceSize; @@ -42,7 +44,7 @@ namespace NewHorizons.Builder.Atmosphere var cloudMaterial = new Material(gdRuleset._cloudMaterial); if (config.Atmosphere?.Clouds?.Tint != null) { - cloudMaterial.SetColor("_FogColor", config.Atmosphere.Clouds.Tint.ToColor32()); + cloudMaterial.SetColor(FogColor, config.Atmosphere.Clouds.Tint.ToColor32()); } ER._cloudMaterial = cloudMaterial; diff --git a/NewHorizons/Builder/Body/FunnelBuilder.cs b/NewHorizons/Builder/Body/FunnelBuilder.cs index 00c29ded..21169231 100644 --- a/NewHorizons/Builder/Body/FunnelBuilder.cs +++ b/NewHorizons/Builder/Body/FunnelBuilder.cs @@ -9,6 +9,17 @@ namespace NewHorizons.Builder.Body { public static class FunnelBuilder { + private static readonly int FogColor = Shader.PropertyToID("_FogColor"); + private static readonly int EmissionColor = Shader.PropertyToID("_EmissionColor"); + private static readonly int HeightScale = Shader.PropertyToID("_HeightScale"); + + private enum FunnelType + { + SAND, + WATER, + LAVA, + STAR + } public static void Make(GameObject planetGO, ConstantForceDetector detector, OWRigidbody rigidbody, FunnelModule module) { @@ -67,7 +78,7 @@ namespace NewHorizons.Builder.Body materials[i] = new Material(waterMaterials[i]); if (module.Tint != null) { - materials[i].SetColor("_FogColor", module.Tint.ToColor()); + materials[i].SetColor(FogColor, module.Tint.ToColor()); } } @@ -114,7 +125,7 @@ namespace NewHorizons.Builder.Body if (module.Tint != null) { - lavaMaterial.SetColor("_EmissionColor", module.Tint.ToColor()); + lavaMaterial.SetColor(EmissionColor, module.Tint.ToColor()); } proxyGO.GetComponentInChildren().material = lavaMaterial; @@ -122,13 +133,13 @@ namespace NewHorizons.Builder.Body if (funnelType == FunnelType.Lava) { - lavaMaterial.SetFloat("_HeightScale", 0); + lavaMaterial.SetFloat(HeightScale, 0); AddDestructionVolumes(fluidVolume, DeathType.Lava); } else if (funnelType == FunnelType.Star) { lavaMaterial.renderQueue = 2999; - lavaMaterial.SetFloat("_HeightScale", 100000); + lavaMaterial.SetFloat(HeightScale, 100000); AddDestructionVolumes(fluidVolume, DeathType.Energy); } diff --git a/NewHorizons/Builder/Body/HeightMapBuilder.cs b/NewHorizons/Builder/Body/HeightMapBuilder.cs index c8fd1b1a..dda66b51 100644 --- a/NewHorizons/Builder/Body/HeightMapBuilder.cs +++ b/NewHorizons/Builder/Body/HeightMapBuilder.cs @@ -43,9 +43,11 @@ namespace NewHorizons.Builder.Body //if (PlanetShader == null) PlanetShader = Shader.Find("Standard"); var cubeSphereMR = cubeSphere.AddComponent(); - cubeSphereMR.material = new Material(PlanetShader); - cubeSphereMR.material.name = textureMap.name; - cubeSphereMR.material.mainTexture = textureMap; + var material = cubeSphereMR.material; + material = new Material(PlanetShader); + cubeSphereMR.material = material; + material.name = textureMap.name; + material.mainTexture = textureMap; var cubeSphereMC = cubeSphere.AddComponent(); cubeSphereMC.sharedMesh = mesh; diff --git a/NewHorizons/Builder/Body/LavaBuilder.cs b/NewHorizons/Builder/Body/LavaBuilder.cs index 82af7fd8..b164c036 100644 --- a/NewHorizons/Builder/Body/LavaBuilder.cs +++ b/NewHorizons/Builder/Body/LavaBuilder.cs @@ -6,6 +6,9 @@ namespace NewHorizons.Builder.Body { public static class LavaBuilder { + private static readonly int HeightScale = Shader.PropertyToID("_HeightScale"); + private static readonly int EmissionColor = Shader.PropertyToID("_EmissionColor"); + public static void Make(GameObject planetGO, Sector sector, OWRigidbody rb, LavaModule module) { var heightScale = module.Size; @@ -28,8 +31,8 @@ namespace NewHorizons.Builder.Body var lavaSphere = GameObject.Instantiate(GameObject.Find("VolcanicMoon_Body/MoltenCore_VM/LavaSphere"), moltenCore.transform); lavaSphere.transform.localScale = Vector3.one; lavaSphere.transform.name = "LavaSphere"; - lavaSphere.GetComponent().material.SetFloat("_HeightScale", heightScale); - if (module.Tint != null) lavaSphere.GetComponent().material.SetColor("_EmissionColor", module.Tint.ToColor()); + lavaSphere.GetComponent().material.SetFloat(HeightScale, heightScale); + if (module.Tint != null) lavaSphere.GetComponent().material.SetColor(EmissionColor, module.Tint.ToColor()); var sectorCullGroup = lavaSphere.GetComponent(); sectorCullGroup.SetSector(sector); @@ -40,8 +43,8 @@ namespace NewHorizons.Builder.Body var proxyLavaSphere = moltenCoreProxy.transform.Find("LavaSphere (1)"); proxyLavaSphere.transform.localScale = Vector3.one; proxyLavaSphere.name = "LavaSphere_Proxy"; - proxyLavaSphere.GetComponent().material.SetFloat("_HeightScale", heightScale); - if (module.Tint != null) proxyLavaSphere.GetComponent().material.SetColor("_EmissionColor", module.Tint.ToColor()); + proxyLavaSphere.GetComponent().material.SetFloat(HeightScale, heightScale); + if (module.Tint != null) proxyLavaSphere.GetComponent().material.SetColor(EmissionColor, module.Tint.ToColor()); var sectorProxy = moltenCoreProxy.GetComponent(); sectorProxy._renderers = new List { proxyLavaSphere.GetComponent() }; diff --git a/NewHorizons/Builder/Body/ProxyBuilder.cs b/NewHorizons/Builder/Body/ProxyBuilder.cs index 20fa7488..32b37be0 100644 --- a/NewHorizons/Builder/Body/ProxyBuilder.cs +++ b/NewHorizons/Builder/Body/ProxyBuilder.cs @@ -19,6 +19,12 @@ namespace NewHorizons.Builder.Body private static readonly string _blackHolePath = "TowerTwin_Body/Sector_TowerTwin/Sector_Tower_HGT/Interactables_Tower_HGT/Interactables_Tower_TT/Prefab_NOM_WarpTransmitter (1)/BlackHole/BlackHoleSingularity"; private static readonly string _whiteHolePath = "TowerTwin_Body/Sector_TowerTwin/Sector_Tower_HGT/Interactables_Tower_HGT/Interactables_Tower_CT/Prefab_NOM_WarpTransmitter/WhiteHole/WhiteHoleSingularity"; + private static readonly int EmissionColor = Shader.PropertyToID("_EmissionColor"); + private static readonly int Radius = Shader.PropertyToID("_Radius"); + private static readonly int MaxDistortRadius = Shader.PropertyToID("_MaxDistortRadius"); + private static readonly int MassScale = Shader.PropertyToID("_MassScale"); + private static readonly int DistortFadeDist = Shader.PropertyToID("_DistortFadeDist"); + private static readonly int Color1 = Shader.PropertyToID("_Color"); public static void Make(GameObject planetGO, NewHorizonsBody body) @@ -71,7 +77,7 @@ namespace NewHorizons.Builder.Body if (realSize < body.Config.Lava.Size) realSize = body.Config.Lava.Size; var material = new Material(lavaMaterial); - if (body.Config.Lava.Tint != null) material.SetColor("_EmissionColor", body.Config.Lava.Tint.ToColor()); + if (body.Config.Lava.Tint != null) material.SetColor(EmissionColor, body.Config.Lava.Tint.ToColor()); sphere.GetComponent().material = material; } if (body.Config.Water != null) @@ -185,10 +191,10 @@ namespace NewHorizons.Builder.Body var meshRenderer = blackHoleRender.AddComponent(); meshRenderer.material = new Material(blackHoleShader); - meshRenderer.material.SetFloat("_Radius", size * 0.4f); - meshRenderer.material.SetFloat("_MaxDistortRadius", size * 0.95f); - meshRenderer.material.SetFloat("_MassScale", 1); - meshRenderer.material.SetFloat("_DistortFadeDist", size * 0.55f); + meshRenderer.material.SetFloat(Radius, size * 0.4f); + meshRenderer.material.SetFloat(MaxDistortRadius, size * 0.95f); + meshRenderer.material.SetFloat(MassScale, 1); + meshRenderer.material.SetFloat(DistortFadeDist, size * 0.55f); blackHoleRender.SetActive(true); } @@ -210,10 +216,10 @@ namespace NewHorizons.Builder.Body var meshRenderer = whiteHoleRenderer.AddComponent(); meshRenderer.material = new Material(whiteHoleShader); - meshRenderer.sharedMaterial.SetFloat("_Radius", size * 0.4f); - meshRenderer.sharedMaterial.SetFloat("_DistortFadeDist", size); - meshRenderer.sharedMaterial.SetFloat("_MaxDistortRadius", size * 2.8f); - meshRenderer.sharedMaterial.SetColor("_Color", new Color(1.88f, 1.88f, 1.88f, 1f)); + meshRenderer.sharedMaterial.SetFloat(Radius, size * 0.4f); + meshRenderer.sharedMaterial.SetFloat(DistortFadeDist, size); + meshRenderer.sharedMaterial.SetFloat(MaxDistortRadius, size * 2.8f); + meshRenderer.sharedMaterial.SetColor(Color1, new Color(1.88f, 1.88f, 1.88f, 1f)); whiteHoleRenderer.SetActive(true); } diff --git a/NewHorizons/Builder/Body/RingBuilder.cs b/NewHorizons/Builder/Body/RingBuilder.cs index ad054193..b4fc065b 100644 --- a/NewHorizons/Builder/Body/RingBuilder.cs +++ b/NewHorizons/Builder/Body/RingBuilder.cs @@ -17,6 +17,7 @@ namespace NewHorizons.Builder.Body public static Shader RingShader1Pixel; public static Shader UnlitRingShader; public static Shader UnlitRingShader1Pixel; + private static readonly int InnerRadius = Shader.PropertyToID("_InnerRadius"); public static GameObject Make(GameObject planetGO, Sector sector, RingModule ring, IModBehaviour mod) { @@ -106,7 +107,7 @@ namespace NewHorizons.Builder.Body if (texture.width == 1) { mat = new Material(ring.Unlit ? UnlitRingShader1Pixel : RingShader1Pixel); - mat.SetFloat("_InnerRadius", 0); + mat.SetFloat(InnerRadius, 0); } ringMR.receiveShadows = !ring.Unlit; diff --git a/NewHorizons/Builder/Body/SingularityBuilder.cs b/NewHorizons/Builder/Body/SingularityBuilder.cs index d4e5dfde..46f8c190 100644 --- a/NewHorizons/Builder/Body/SingularityBuilder.cs +++ b/NewHorizons/Builder/Body/SingularityBuilder.cs @@ -12,6 +12,11 @@ namespace NewHorizons.Builder.Body private static Shader blackHoleShader = null; private static Shader whiteHoleShader = null; + private static readonly int Radius = Shader.PropertyToID("_Radius"); + private static readonly int MaxDistortRadius = Shader.PropertyToID("_MaxDistortRadius"); + private static readonly int MassScale = Shader.PropertyToID("_MassScale"); + private static readonly int DistortFadeDist = Shader.PropertyToID("_DistortFadeDist"); + private static readonly int Color1 = Shader.PropertyToID("_Color"); public static void Make(GameObject go, Sector sector, OWRigidbody OWRB, PlanetConfig config) { @@ -88,10 +93,10 @@ namespace NewHorizons.Builder.Body var meshRenderer = blackHoleRender.AddComponent(); if (blackHoleShader == null) blackHoleShader = GameObject.Find("BrittleHollow_Body/BlackHole_BH/BlackHoleRenderer").GetComponent().sharedMaterial.shader; meshRenderer.material = new Material(blackHoleShader); - meshRenderer.material.SetFloat("_Radius", size * 0.4f); - meshRenderer.material.SetFloat("_MaxDistortRadius", size * 0.95f); - meshRenderer.material.SetFloat("_MassScale", 1); - meshRenderer.material.SetFloat("_DistortFadeDist", size * 0.55f); + meshRenderer.material.SetFloat(Radius, size * 0.4f); + meshRenderer.material.SetFloat(MaxDistortRadius, size * 0.95f); + meshRenderer.material.SetFloat(MassScale, 1); + meshRenderer.material.SetFloat(DistortFadeDist, size * 0.55f); if (makeAudio) { @@ -159,11 +164,11 @@ namespace NewHorizons.Builder.Body var meshRenderer = whiteHoleRenderer.AddComponent(); if (whiteHoleShader == null) whiteHoleShader = GameObject.Find("WhiteHole_Body/WhiteHoleVisuals/Singularity").GetComponent().sharedMaterial.shader; meshRenderer.material = new Material(whiteHoleShader); - meshRenderer.sharedMaterial.SetFloat("_Radius", size * 0.4f); - meshRenderer.sharedMaterial.SetFloat("_DistortFadeDist", size); - meshRenderer.sharedMaterial.SetFloat("_MaxDistortRadius", size * 2.8f); - meshRenderer.sharedMaterial.SetFloat("_MassScale", -1); - meshRenderer.sharedMaterial.SetColor("_Color", new Color(1.88f, 1.88f, 1.88f, 1f)); + meshRenderer.sharedMaterial.SetFloat(Radius, size * 0.4f); + meshRenderer.sharedMaterial.SetFloat(DistortFadeDist, size); + meshRenderer.sharedMaterial.SetFloat(MaxDistortRadius, size * 2.8f); + meshRenderer.sharedMaterial.SetFloat(MassScale, -1); + meshRenderer.sharedMaterial.SetColor(Color1, new Color(1.88f, 1.88f, 1.88f, 1f)); var ambientLight = GameObject.Instantiate(GameObject.Find("WhiteHole_Body/WhiteHoleVisuals/AmbientLight_WH")); ambientLight.transform.parent = whiteHole.transform; diff --git a/NewHorizons/Builder/Body/StarBuilder.cs b/NewHorizons/Builder/Body/StarBuilder.cs index c79ec35b..cfbccae0 100644 --- a/NewHorizons/Builder/Body/StarBuilder.cs +++ b/NewHorizons/Builder/Body/StarBuilder.cs @@ -11,6 +11,12 @@ namespace NewHorizons.Builder.Body { public const float OuterRadiusRatio = 1.5f; private static Texture2D _colorOverTime; + private static readonly int ColorRamp = Shader.PropertyToID("_ColorRamp"); + private static readonly int SkyColor = Shader.PropertyToID("_SkyColor"); + private static readonly int AtmosFar = Shader.PropertyToID("_AtmosFar"); + private static readonly int AtmosNear = Shader.PropertyToID("_AtmosNear"); + private static readonly int InnerRadius = Shader.PropertyToID("_InnerRadius"); + private static readonly int OuterRadius = Shader.PropertyToID("_OuterRadius"); public static StarController Make(GameObject planetGO, Sector sector, StarModule starModule) { @@ -40,11 +46,11 @@ namespace NewHorizons.Builder.Body sunAtmosphere.transform.Find("AtmoSphere").transform.localScale = Vector3.one; foreach (var lod in sunAtmosphere.transform.Find("AtmoSphere").GetComponentsInChildren()) { - lod.material.SetColor("_SkyColor", starModule.Tint.ToColor()); - lod.material.SetColor("_AtmosFar", starModule.Tint.ToColor()); - lod.material.SetColor("_AtmosNear", starModule.Tint.ToColor()); - lod.material.SetFloat("_InnerRadius", starModule.Size); - lod.material.SetFloat("_OuterRadius", starModule.Size * OuterRadiusRatio); + lod.material.SetColor(SkyColor, starModule.Tint.ToColor()); + lod.material.SetColor(AtmosFar, starModule.Tint.ToColor()); + lod.material.SetColor(AtmosNear, starModule.Tint.ToColor()); + lod.material.SetFloat(InnerRadius, starModule.Size); + lod.material.SetFloat(OuterRadius, starModule.Size * OuterRadiusRatio); } } fog.transform.localScale = Vector3.one; @@ -85,15 +91,6 @@ namespace NewHorizons.Builder.Body Color lightColour = light.color; if (starModule.LightTint != null) lightColour = starModule.LightTint.ToColor(); - if (lightColour == null && starModule.Tint != null) - { - // Lighten it a bit - var r = Mathf.Clamp01(starModule.Tint.R * 1.5f); - var g = Mathf.Clamp01(starModule.Tint.G * 1.5f); - var b = Mathf.Clamp01(starModule.Tint.B * 1.5f); - lightColour = new Color(r, g, b); - } - if (lightColour != null) light.color = (Color)lightColour; light.color = lightColour; ambientLight.color = lightColour; @@ -218,7 +215,7 @@ namespace NewHorizons.Builder.Body darkenedColor = new Color(endColour.r * mod, endColour.g * mod, endColour.b * mod); } - surface.sharedMaterial.SetTexture("_ColorRamp", ImageUtilities.LerpGreyscaleImage(_colorOverTime, adjustedColour, darkenedColor)); + surface.sharedMaterial.SetTexture(ColorRamp, ImageUtilities.LerpGreyscaleImage(_colorOverTime, adjustedColour, darkenedColor)); } return starGO; @@ -240,7 +237,7 @@ namespace NewHorizons.Builder.Body var supernovaMaterial = new Material(supernova._supernovaMaterial); var ramp = ImageUtilities.LerpGreyscaleImage(ImageUtilities.GetTexture(Main.Instance, "AssetBundle/Effects_SUN_Supernova_d.png"), Color.white, colour); - supernovaMaterial.SetTexture("_ColorRamp", ramp); + supernovaMaterial.SetTexture(ColorRamp, ramp); supernova._supernovaMaterial = supernovaMaterial; // Motes diff --git a/NewHorizons/Builder/Body/WaterBuilder.cs b/NewHorizons/Builder/Body/WaterBuilder.cs index 220fc553..15c1fb3e 100644 --- a/NewHorizons/Builder/Body/WaterBuilder.cs +++ b/NewHorizons/Builder/Body/WaterBuilder.cs @@ -9,6 +9,9 @@ namespace NewHorizons.Builder.Body { public static class WaterBuilder { + private static readonly int Radius = Shader.PropertyToID("_Radius"); + private static readonly int Radius2 = Shader.PropertyToID("_Radius2"); + public static void Make(GameObject planetGO, Sector sector, OWRigidbody rb, WaterModule module) { var waterSize = module.Size; @@ -101,8 +104,8 @@ namespace NewHorizons.Builder.Body } else { - fogGO.GetComponent().material.SetFloat("_Radius", module.Size); - fogGO.GetComponent().material.SetFloat("_Radius2", module.Size / 2f); + fogGO.GetComponent().material.SetFloat(Radius, module.Size); + fogGO.GetComponent().material.SetFloat(Radius2, module.Size / 2f); } // TODO: make LOD work diff --git a/NewHorizons/Builder/Props/DetailBuilder.cs b/NewHorizons/Builder/Props/DetailBuilder.cs index 1484a41b..68247a08 100644 --- a/NewHorizons/Builder/Props/DetailBuilder.cs +++ b/NewHorizons/Builder/Props/DetailBuilder.cs @@ -1,213 +1,223 @@ -using NewHorizons.External.Configs; -using NewHorizons.External.Modules; -using NewHorizons.Handlers; -using NewHorizons.Utility; -using OWML.Common; -using System; -using System.Collections.Generic; -using System.Linq; -using UnityEngine; -using Logger = NewHorizons.Utility.Logger; -namespace NewHorizons.Builder.Props -{ - public static class DetailBuilder - { - public static void Make(GameObject go, Sector sector, PlanetConfig config, IModBehaviour mod, string uniqueModName, PropModule.DetailInfo detail) - { - GameObject detailGO = null; - - if (detail.assetBundle != null) - { - var prefab = AssetBundleUtilities.LoadPrefab(detail.assetBundle, detail.path, mod); - - detailGO = MakeDetail(go, sector, prefab, detail.position, detail.rotation, detail.scale, detail.alignToNormal); - } - else if (detail.objFilePath != null) - { - try - { - var prefab = mod.ModHelper.Assets.Get3DObject(detail.objFilePath, detail.mtlFilePath); - AssetBundleUtilities.ReplaceShaders(prefab); - prefab.SetActive(false); - detailGO = MakeDetail(go, sector, prefab, detail.position, detail.rotation, detail.scale, detail.alignToNormal); - } - catch (Exception e) - { - Logger.LogError($"Could not load 3d object {detail.objFilePath} with texture {detail.mtlFilePath} : {e.Message}"); - } - } - else detailGO = MakeDetail(go, sector, detail.path, detail.position, detail.rotation, detail.scale, detail.alignToNormal); - - if (detailGO != null && detail.removeChildren != null) - { - foreach (var childPath in detail.removeChildren) - { - var childObj = detailGO.transform.Find(childPath); - if (childObj != null) childObj.gameObject.SetActive(false); - else Logger.LogWarning($"Couldn't find {childPath}"); - } - } - - if (detailGO != null && detail.removeComponents) - { - // Just swap all the children to a new game object - var newDetailGO = new GameObject(detailGO.name); - newDetailGO.transform.position = detailGO.transform.position; - newDetailGO.transform.parent = detailGO.transform.parent; - // Can't modify parents while looping through children bc idk - var children = new List(); - foreach (Transform child in detailGO.transform) - { - children.Add(child); - } - foreach (var child in children) - { - child.parent = newDetailGO.transform; - } - GameObject.Destroy(detailGO); - detailGO = newDetailGO; - } - } - - public static GameObject MakeDetail(GameObject go, Sector sector, string propToClone, MVector3 position, MVector3 rotation, float scale, bool alignWithNormal) - { - var prefab = SearchUtilities.Find(propToClone); - if (prefab == null) Logger.LogError($"Couldn't find detail {propToClone}"); - return MakeDetail(go, sector, prefab, position, rotation, scale, alignWithNormal); - } - - public static GameObject MakeDetail(GameObject planetGO, Sector sector, GameObject prefab, MVector3 position, MVector3 rotation, float scale, bool alignWithNormal) - { - if (prefab == null) return null; - - GameObject prop = prefab.InstantiateInactive(); - prop.transform.parent = sector?.transform ?? planetGO.transform; - prop.SetActive(false); - - if (sector != null) sector.OnOccupantEnterSector += (SectorDetector sd) => OWAssetHandler.OnOccupantEnterSector(prop, sd, sector); - OWAssetHandler.LoadObject(prop); - - foreach (var component in prop.GetComponents().Concat(prop.GetComponentsInChildren())) - { - // Enable all children or something - var enabledField = component?.GetType()?.GetField("enabled"); - if (enabledField != null && enabledField.FieldType == typeof(bool)) Main.Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => enabledField.SetValue(component, true)); - - // Fix a bunch of sector stuff - if (sector != null) - { - if (component is Sector) - { - (component as Sector)._parentSector = sector; - } - - // TODO: Make this work or smthng - if (component is GhostIK) (component as GhostIK).enabled = false; - if (component is GhostEffects) (component as GhostEffects).enabled = false; - - if (component is DarkMatterVolume) - { - var probeVisuals = component.gameObject.transform.Find("ProbeVisuals"); - if (probeVisuals != null) probeVisuals.gameObject.SetActive(true); - } - - if (component is SectoredMonoBehaviour) - { - (component as SectoredMonoBehaviour).SetSector(sector); - } - else - { - var sectorField = component?.GetType()?.GetField("_sector"); - if (sectorField != null && sectorField.FieldType == typeof(Sector)) Main.Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => sectorField.SetValue(component, sector)); - } - - if (component is AnglerfishController) - { - try - { - (component as AnglerfishController)._chaseSpeed += OWPhysics.CalculateOrbitVelocity(planetGO.GetAttachedOWRigidbody(), planetGO.GetComponent().GetPrimaryBody().GetAttachedOWRigidbody()).magnitude; - } - catch (Exception e) - { - Logger.LogError($"Couldn't update AnglerFish chase speed: {e.Message}"); - } - } - - // Fix slide reel - if (component is SlideCollectionContainer) - { - sector.OnOccupantEnterSector.AddListener((_) => (component as SlideCollectionContainer).LoadStreamingTextures()); - } - - if (component is OWItemSocket) - { - (component as OWItemSocket)._sector = sector; - } - } - else - { - // Remove things that require sectors. Will just keep extending this as things pop up - - if (component is FogLight || component is SectoredMonoBehaviour) - { - GameObject.DestroyImmediate(component); - continue; - } - } - - // Fix a bunch of stuff when done loading - Main.Instance.ModHelper.Events.Unity.RunWhen(() => Main.IsSystemReady, () => - { - try - { - if (component is Animator) (component as Animator).enabled = true; - else if (component is Collider) (component as Collider).enabled = true; - else if (component is Renderer) (component as Renderer).enabled = true; - else if (component is Shape) (component as Shape).enabled = true; - // If it's not a moving anglerfish make sure the anim controller is regular - else if (component is AnglerfishAnimController && component.GetComponentInParent() == null) - { - Logger.Log("Enabling anglerfish animation"); - var angler = (component as AnglerfishAnimController); - // Remove any reference to its angler - if (angler._anglerfishController) - { - angler._anglerfishController.OnChangeAnglerState -= angler.OnChangeAnglerState; - angler._anglerfishController.OnAnglerTurn -= angler.OnAnglerTurn; - angler._anglerfishController.OnAnglerSuspended -= angler.OnAnglerSuspended; - angler._anglerfishController.OnAnglerUnsuspended -= angler.OnAnglerUnsuspended; - } - angler.enabled = true; - angler.OnChangeAnglerState(AnglerfishController.AnglerState.Lurking); - } - } - catch (Exception e) - { - Logger.LogWarning($"Exception when modifying component [{component.GetType().Name}] on [{planetGO.name}] : {e.Message}, {e.StackTrace}"); - } - }); - } - - prop.transform.position = position == null ? planetGO.transform.position : planetGO.transform.TransformPoint((Vector3)position); - - Quaternion rot = rotation == null ? Quaternion.identity : Quaternion.Euler((Vector3)rotation); - if (alignWithNormal) - { - // Apply the rotation after aligning it with normal - var up = planetGO.transform.InverseTransformPoint(prop.transform.position).normalized; - prop.transform.rotation = Quaternion.FromToRotation(Vector3.up, up); - prop.transform.rotation *= rot; - } - else - { - prop.transform.rotation = planetGO.transform.TransformRotation(rot); - } - - prop.transform.localScale = scale != 0 ? Vector3.one * scale : prefab.transform.localScale; - - prop.SetActive(true); - - return prop; - } - } -} +using NewHorizons.External.Configs; +using NewHorizons.External.Modules; +using NewHorizons.Handlers; +using NewHorizons.Utility; +using OWML.Common; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using Logger = NewHorizons.Utility.Logger; +namespace NewHorizons.Builder.Props +{ + public static class DetailBuilder + { + private static Dictionary detailInfoToCorrespondingSpawnedGameObject = new Dictionary(); + + public static GameObject GetSpawnedGameObjectByDetailInfo(PropModule.DetailInfo detail) + { + if (!detailInfoToCorrespondingSpawnedGameObject.ContainsKey(detail)) return null; + return detailInfoToCorrespondingSpawnedGameObject[detail]; + } + + public static void Make(GameObject go, Sector sector, PlanetConfig config, IModBehaviour mod, string uniqueModName, PropModule.DetailInfo detail) + { + GameObject detailGO = null; + + if (detail.assetBundle != null) + { + var prefab = AssetBundleUtilities.LoadPrefab(detail.assetBundle, detail.path, mod); + + detailGO = MakeDetail(go, sector, prefab, detail.position, detail.rotation, detail.scale, detail.alignToNormal); + } + else if (detail.objFilePath != null) + { + try + { + var prefab = mod.ModHelper.Assets.Get3DObject(detail.objFilePath, detail.mtlFilePath); + AssetBundleUtilities.ReplaceShaders(prefab); + prefab.SetActive(false); + detailGO = MakeDetail(go, sector, prefab, detail.position, detail.rotation, detail.scale, detail.alignToNormal); + } + catch (Exception e) + { + Logger.LogError($"Could not load 3d object {detail.objFilePath} with texture {detail.mtlFilePath} : {e.Message}"); + } + } + else detailGO = MakeDetail(go, sector, detail.path, detail.position, detail.rotation, detail.scale, detail.alignToNormal); + + if (detailGO != null && detail.removeChildren != null) + { + foreach (var childPath in detail.removeChildren) + { + var childObj = detailGO.transform.Find(childPath); + if (childObj != null) childObj.gameObject.SetActive(false); + else Logger.LogWarning($"Couldn't find {childPath}"); + } + } + + if (detailGO != null && detail.removeComponents) + { + // Just swap all the children to a new game object + var newDetailGO = new GameObject(detailGO.name); + newDetailGO.transform.position = detailGO.transform.position; + newDetailGO.transform.parent = detailGO.transform.parent; + // Can't modify parents while looping through children bc idk + var children = new List(); + foreach (Transform child in detailGO.transform) + { + children.Add(child); + } + foreach (var child in children) + { + child.parent = newDetailGO.transform; + } + GameObject.Destroy(detailGO); + detailGO = newDetailGO; + } + + detailInfoToCorrespondingSpawnedGameObject[detail] = detailGO; + } + + public static GameObject MakeDetail(GameObject go, Sector sector, string propToClone, MVector3 position, MVector3 rotation, float scale, bool alignWithNormal) + { + var prefab = SearchUtilities.Find(propToClone); + if (prefab == null) Logger.LogError($"Couldn't find detail {propToClone}"); + return MakeDetail(go, sector, prefab, position, rotation, scale, alignWithNormal); + } + + public static GameObject MakeDetail(GameObject planetGO, Sector sector, GameObject prefab, MVector3 position, MVector3 rotation, float scale, bool alignWithNormal) + { + if (prefab == null) return null; + + GameObject prop = prefab.InstantiateInactive(); + prop.transform.parent = sector?.transform ?? planetGO.transform; + prop.SetActive(false); + + if (sector != null) sector.OnOccupantEnterSector += (SectorDetector sd) => OWAssetHandler.OnOccupantEnterSector(prop, sd, sector); + OWAssetHandler.LoadObject(prop); + + foreach (var component in prop.GetComponents().Concat(prop.GetComponentsInChildren())) + { + // Enable all children or something + var enabledField = component?.GetType()?.GetField("enabled"); + if (enabledField != null && enabledField.FieldType == typeof(bool)) Main.Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => enabledField.SetValue(component, true)); + + // Fix a bunch of sector stuff + if (sector != null) + { + if (component is Sector) + { + (component as Sector)._parentSector = sector; + } + + // TODO: Make this work or smthng + if (component is GhostIK) (component as GhostIK).enabled = false; + if (component is GhostEffects) (component as GhostEffects).enabled = false; + + if (component is DarkMatterVolume) + { + var probeVisuals = component.gameObject.transform.Find("ProbeVisuals"); + if (probeVisuals != null) probeVisuals.gameObject.SetActive(true); + } + + if (component is SectoredMonoBehaviour) + { + (component as SectoredMonoBehaviour).SetSector(sector); + } + else + { + var sectorField = component?.GetType()?.GetField("_sector"); + if (sectorField != null && sectorField.FieldType == typeof(Sector)) Main.Instance.ModHelper.Events.Unity.FireOnNextUpdate(() => sectorField.SetValue(component, sector)); + } + + if (component is AnglerfishController) + { + try + { + (component as AnglerfishController)._chaseSpeed += OWPhysics.CalculateOrbitVelocity(planetGO.GetAttachedOWRigidbody(), planetGO.GetComponent().GetPrimaryBody().GetAttachedOWRigidbody()).magnitude; + } + catch (Exception e) + { + Logger.LogError($"Couldn't update AnglerFish chase speed: {e.Message}"); + } + } + + // Fix slide reel + if (component is SlideCollectionContainer) + { + sector.OnOccupantEnterSector.AddListener((_) => (component as SlideCollectionContainer).LoadStreamingTextures()); + } + + if (component is OWItemSocket) + { + (component as OWItemSocket)._sector = sector; + } + } + else + { + // Remove things that require sectors. Will just keep extending this as things pop up + + if (component is FogLight || component is SectoredMonoBehaviour) + { + GameObject.DestroyImmediate(component); + continue; + } + } + + // Fix a bunch of stuff when done loading + Main.Instance.ModHelper.Events.Unity.RunWhen(() => Main.IsSystemReady, () => + { + try + { + if (component is Animator) (component as Animator).enabled = true; + else if (component is Collider) (component as Collider).enabled = true; + else if (component is Renderer) (component as Renderer).enabled = true; + else if (component is Shape) (component as Shape).enabled = true; + // If it's not a moving anglerfish make sure the anim controller is regular + else if (component is AnglerfishAnimController && component.GetComponentInParent() == null) + { + Logger.Log("Enabling anglerfish animation"); + var angler = (component as AnglerfishAnimController); + // Remove any reference to its angler + if (angler._anglerfishController) + { + angler._anglerfishController.OnChangeAnglerState -= angler.OnChangeAnglerState; + angler._anglerfishController.OnAnglerTurn -= angler.OnAnglerTurn; + angler._anglerfishController.OnAnglerSuspended -= angler.OnAnglerSuspended; + angler._anglerfishController.OnAnglerUnsuspended -= angler.OnAnglerUnsuspended; + } + angler.enabled = true; + angler.OnChangeAnglerState(AnglerfishController.AnglerState.Lurking); + } + } + catch (Exception e) + { + Logger.LogWarning($"Exception when modifying component [{component.GetType().Name}] on [{planetGO.name}] : {e.Message}, {e.StackTrace}"); + } + }); + } + + prop.transform.position = position == null ? planetGO.transform.position : planetGO.transform.TransformPoint((Vector3)position); + + Quaternion rot = rotation == null ? Quaternion.identity : Quaternion.Euler((Vector3)rotation); + if (alignWithNormal) + { + // Apply the rotation after aligning it with normal + var up = planetGO.transform.InverseTransformPoint(prop.transform.position).normalized; + prop.transform.rotation = Quaternion.FromToRotation(Vector3.up, up); + prop.transform.rotation *= rot; + } + else + { + prop.transform.rotation = planetGO.transform.TransformRotation(rot); + } + + prop.transform.localScale = scale != 0 ? Vector3.one * scale : prefab.transform.localScale; + + prop.SetActive(true); + + return prop; + } + } +} diff --git a/NewHorizons/Builder/Props/ProjectionBuilder.cs b/NewHorizons/Builder/Props/ProjectionBuilder.cs index 1c46d054..4b111c86 100644 --- a/NewHorizons/Builder/Props/ProjectionBuilder.cs +++ b/NewHorizons/Builder/Props/ProjectionBuilder.cs @@ -12,6 +12,8 @@ namespace NewHorizons.Builder.Props { private static GameObject _slideReelPrefab; private static GameObject _autoPrefab; + private static readonly int EmissionMap = Shader.PropertyToID("_EmissionMap"); + public static void Make(GameObject go, Sector sector, PropModule.ProjectionInfo info, IModBehaviour mod) { switch (info.type) @@ -99,9 +101,9 @@ namespace NewHorizons.Builder.Props // Now put together the textures into a 4x4 thing for the materials var reelTexture = ImageUtilities.MakeReelTexture(textures); slidesBack.material.mainTexture = reelTexture; - slidesBack.material.SetTexture("_EmissionMap", reelTexture); + slidesBack.material.SetTexture(EmissionMap, reelTexture); slidesFront.material.mainTexture = reelTexture; - slidesFront.material.SetTexture("_EmissionMap", reelTexture); + slidesFront.material.SetTexture(EmissionMap, reelTexture); slideReelObj.SetActive(true); } @@ -156,7 +158,7 @@ namespace NewHorizons.Builder.Props // Change the picture on the lens var lens = projectorObj.transform.Find("Spotlight/Prop_IP_SingleSlideProjector/Projector_Lens").GetComponent(); lens.materials[1].mainTexture = slideCollection.slides[0]._textureOverride; - lens.materials[1].SetTexture("_EmissionMap", slideCollection.slides[0]._textureOverride); + lens.materials[1].SetTexture(EmissionMap, slideCollection.slides[0]._textureOverride); projectorObj.SetActive(true); } diff --git a/NewHorizons/Builder/Props/TornadoBuilder.cs b/NewHorizons/Builder/Props/TornadoBuilder.cs index d4b06e1d..3bbe97c3 100644 --- a/NewHorizons/Builder/Props/TornadoBuilder.cs +++ b/NewHorizons/Builder/Props/TornadoBuilder.cs @@ -9,39 +9,67 @@ namespace NewHorizons.Builder.Props { public static class TornadoBuilder { - private static GameObject upPrefab; - private static GameObject downPrefab; - private static GameObject soundPrefab; + private static GameObject _upPrefab; + private static GameObject _downPrefab; + private static GameObject _hurricanePrefab; + private static GameObject _soundPrefab; + + private static Texture2D _mainTexture; + private static Texture2D _detailTexture; + private static readonly int DetailColor = Shader.PropertyToID("_DetailColor"); + private static readonly int TintColor = Shader.PropertyToID("_TintColor"); + private static readonly int DetailTex = Shader.PropertyToID("_DetailTex"); + private static readonly int MainTex = Shader.PropertyToID("_MainTex"); + private static readonly int FresnelColor = Shader.PropertyToID("_FresnelColor"); public static void Make(GameObject planetGO, Sector sector, PropModule.TornadoInfo info, bool hasClouds) { - if (upPrefab == null) + if (_upPrefab == null) { - upPrefab = GameObject.Find("BrittleHollow_Body/Sector_BH/Sector_SouthHemisphere/Sector_SouthPole/Sector_Observatory/Interactables_Observatory/MockUpTornado").InstantiateInactive(); - upPrefab.name = "Tornado_Up_Prefab"; + _upPrefab = GameObject.Find("BrittleHollow_Body/Sector_BH/Sector_SouthHemisphere/Sector_SouthPole/Sector_Observatory/Interactables_Observatory/MockUpTornado").InstantiateInactive(); + _upPrefab.name = "Tornado_Up_Prefab"; } - if (downPrefab == null) + if (_downPrefab == null) { - downPrefab = GameObject.Find("BrittleHollow_Body/Sector_BH/Sector_SouthHemisphere/Sector_SouthPole/Sector_Observatory/Interactables_Observatory/MockDownTornado").InstantiateInactive(); - downPrefab.name = "Tornado_Down_Prefab"; + _downPrefab = GameObject.Find("BrittleHollow_Body/Sector_BH/Sector_SouthHemisphere/Sector_SouthPole/Sector_Observatory/Interactables_Observatory/MockDownTornado").InstantiateInactive(); + _downPrefab.name = "Tornado_Down_Prefab"; } - if (soundPrefab == null) + if (_hurricanePrefab == null) { - soundPrefab = GameObject.Find("GiantsDeep_Body/Sector_GD/Sector_GDInterior/Tornadoes_GDInterior/SouthernTornadoes/DownTornado_Pivot/DownTornado/AudioRail").InstantiateInactive(); - soundPrefab.name = "AudioRail_Prefab"; + _hurricanePrefab = GameObject.Find("GiantsDeep_Body/Sector_GD/Sector_GDInterior/Tornadoes_GDInterior/Hurricane/").InstantiateInactive(); + // For some reason they put the hurricane at the origin and offset all its children (450) + // Increasing by 40 will keep the bottom above the ground + foreach (Transform child in _hurricanePrefab.transform) + { + child.localPosition += new Vector3(0, 40 - 450, 0); + } + foreach (var renderer in _hurricanePrefab.GetComponentsInChildren()) + { + renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; + } + } + if (_soundPrefab == null) + { + _soundPrefab = GameObject.Find("GiantsDeep_Body/Sector_GD/Sector_GDInterior/Tornadoes_GDInterior/SouthernTornadoes/DownTornado_Pivot/DownTornado/AudioRail").InstantiateInactive(); + _soundPrefab.name = "AudioRail_Prefab"; + } + if (_mainTexture == null) + { + _mainTexture = ImageUtilities.GetTexture(Main.Instance, "AssetBundle/Tornado_BH_Cyclone_02_d.png"); + } + if (_detailTexture == null) + { + _detailTexture = ImageUtilities.GetTexture(Main.Instance, "AssetBundle/Tornado_BH_CycloneDetail_d.png"); } - float elevation; Vector3 position; if (info.position != null) { position = info.position ?? Random.onUnitSphere * info.elevation; - elevation = position.magnitude; } else if (info.elevation != 0) { position = Random.onUnitSphere * info.elevation; - elevation = info.elevation; } else { @@ -49,13 +77,19 @@ namespace NewHorizons.Builder.Props return; } - var tornadoGO = info.downwards ? downPrefab.InstantiateInactive() : upPrefab.InstantiateInactive(); + if (info.type.ToLower() == "hurricane") MakeHurricane(planetGO, sector, info, position, hasClouds); + else MakeTornado(planetGO, sector, info, position, info.type.ToLower() == "downwards"); + } + + private static void MakeTornado(GameObject planetGO, Sector sector, PropModule.TornadoInfo info, Vector3 position, bool downwards) + { + var tornadoGO = downwards ? _downPrefab.InstantiateInactive() : _upPrefab.InstantiateInactive(); tornadoGO.transform.parent = sector.transform; tornadoGO.transform.position = planetGO.transform.TransformPoint(position); tornadoGO.transform.rotation = Quaternion.FromToRotation(Vector3.up, sector.transform.TransformDirection(position.normalized)); // Add the sound thing before changing the scale - var soundGO = soundPrefab.InstantiateInactive(); + var soundGO = _soundPrefab.InstantiateInactive(); soundGO.name = "AudioRail"; soundGO.transform.parent = tornadoGO.transform; soundGO.transform.localPosition = Vector3.zero; @@ -79,7 +113,6 @@ namespace NewHorizons.Builder.Props audioSource.playOnAwake = true; var scale = info.height == 0 ? 1 : info.height / 10f; - tornadoGO.transform.localScale = Vector3.one * scale; // Resize the distance it can be heard from to match roughly with the size @@ -102,28 +135,124 @@ namespace NewHorizons.Builder.Props tornadoGO.GetComponentInChildren().enabled = true; + // Resize it so the force volume goes all the way up + switch (downwards) + { + case true: + tornadoGO.transform.Find("MockDownTornado_FluidCenter").localScale = new Vector3(1, 2f, 1); + break; + default: + tornadoGO.transform.Find("MockUpTornado_FluidCenter").localScale = new Vector3(1, 2f, 1); + break; + } + if (info.tint != null) { - var colour = info.tint.ToColor(); - foreach (var renderer in tornadoGO.GetComponentsInChildren()) - { - renderer.material.color = colour; - renderer.material.SetColor("_DetailColor", colour); - renderer.material.SetColor("_TintColor", colour); - } + ApplyTint(tornadoGO, info.tint.ToColor(), false, downwards); } if (info.wanderRate != 0) { - var wanderer = tornadoGO.AddComponent(); - wanderer.wanderRate = info.wanderRate; - wanderer.wanderDegreesX = info.wanderDegreesX; - wanderer.wanderDegreesZ = info.wanderDegreesZ; - wanderer.sector = sector; + ApplyWanderer(tornadoGO, sector, info); } soundGO.SetActive(true); tornadoGO.SetActive(true); } + + private static void MakeHurricane(GameObject planetGO, Sector sector, PropModule.TornadoInfo info, Vector3 position, bool hasClouds) + { + var hurricaneGO = _hurricanePrefab.InstantiateInactive(); + hurricaneGO.transform.parent = sector.transform; + hurricaneGO.transform.position = planetGO.transform.TransformPoint(position); + hurricaneGO.transform.rotation = Quaternion.FromToRotation(Vector3.up, sector.transform.TransformDirection(position.normalized)); + + var fluidVolume = hurricaneGO.GetComponentInChildren(); + fluidVolume._density = 8; + + var effects = hurricaneGO.transform.Find("Effects_GD_Hurricane").gameObject; + + if (!hasClouds) + { + foreach (Transform child in effects.transform) + { + if (child.name.Contains("HurricaneCloudBlend")) + { + child.localPosition = new Vector3(0, 60, 0); + child.localScale = Vector3.one * 1.1f; + } + if (child.name.Equals("Effects_GD_HurricaneCycloneExterior")) + { + child.localScale = new Vector3(0.88f, 1f, 0.88f); + } + } + } + + // Rotation is off by default for some reason + foreach (var rotate in hurricaneGO.GetComponentsInChildren()) + { + rotate._sector = sector; + } + + // Streaming render mesh handles scare me + foreach(var streamingRenderMeshHandle in hurricaneGO.GetComponentsInChildren()) + { + streamingRenderMeshHandle.enabled = false; + } + + // Height of the hurricane is 405 by default + if (info.height != 0) hurricaneGO.transform.localScale = Vector3.one * info.height / 405f; + + if (info.tint != null) + { + ApplyTint(hurricaneGO, info.tint.ToColor(), true, false); + } + + if (info.wanderRate != 0) + { + ApplyWanderer(hurricaneGO, sector, info); + } + + hurricaneGO.SetActive(true); + } + + private static void ApplyTint(GameObject go, Color colour, bool hurricane, bool downwards) + { + colour.a = 1f; + + var detailTexture = ImageUtilities.TintImage(_detailTexture, colour); + var mainTexture = ImageUtilities.TintImage(_mainTexture, colour); + + string materialName; + if (hurricane) materialName = "Hurricane_GD_Cyclone_mat"; + else materialName = $"Tornado_BH_Cyclone_{(downwards ? "Down" : "Up")}_mat"; + + foreach (var renderer in go.GetComponentsInChildren()) + { + renderer.material.SetColor(DetailColor, colour); + renderer.material.SetColor(TintColor, colour); + + if (renderer.material.name.Contains(materialName)) + { + renderer.material.SetTexture(DetailTex, detailTexture); + renderer.material.SetTexture(MainTex, mainTexture); + renderer.material.SetColor(FresnelColor, colour); + } + else + { + // If we set the colour on the ones with the material from before, it makes the gradient look bad + renderer.material.color = colour; + } + } + } + + private static void ApplyWanderer(GameObject go, Sector sector, PropModule.TornadoInfo info) + { + var wanderer = go.AddComponent(); + wanderer.wanderRate = info.wanderRate; + wanderer.wanderDegreesX = info.wanderDegreesX; + wanderer.wanderDegreesZ = info.wanderDegreesZ; + wanderer.sector = sector; + } } } diff --git a/NewHorizons/Builder/Props/VolcanoBuilder.cs b/NewHorizons/Builder/Props/VolcanoBuilder.cs index b4651697..a9e04b51 100644 --- a/NewHorizons/Builder/Props/VolcanoBuilder.cs +++ b/NewHorizons/Builder/Props/VolcanoBuilder.cs @@ -7,6 +7,8 @@ namespace NewHorizons.Builder.Props { private static Color defaultStoneTint = new Color(0.07450981f, 0.07450981f, 0.07450981f); private static Color defaultLavaTint = new Color(4.594794f, 0.3419145f, 0f, 1f); + private static readonly int Color1 = Shader.PropertyToID("_Color"); + private static readonly int EmissionColor = Shader.PropertyToID("_EmissionColor"); public static void Make(GameObject planetGO, Sector sector, PropModule.VolcanoInfo info) { @@ -48,8 +50,8 @@ namespace NewHorizons.Builder.Props meteor.transform.localScale = Vector3.one * info.scale; var mat = meteor.GetComponentInChildren().material; - mat.SetColor("_Color", info.stoneTint == null ? defaultStoneTint : info.stoneTint.ToColor()); - mat.SetColor("_EmissionColor", info.lavaTint == null ? defaultLavaTint : info.lavaTint.ToColor()); + mat.SetColor(Color1, info.stoneTint?.ToColor() ?? defaultStoneTint); + mat.SetColor(EmissionColor, info.lavaTint?.ToColor() ?? defaultLavaTint); var detectors = meteor.transform.Find("ConstantDetectors").gameObject; GameObject.Destroy(detectors.GetComponent()); diff --git a/NewHorizons/Components/FunnelController.cs b/NewHorizons/Components/FunnelController.cs index 5e625e54..c0d39468 100644 --- a/NewHorizons/Components/FunnelController.cs +++ b/NewHorizons/Components/FunnelController.cs @@ -12,7 +12,7 @@ namespace NewHorizons.Components // Temporary solution that i will never get rid of transform.position = anchor.position; - float num = scaleCurve == null ? 1f : scaleCurve.Evaluate(TimeLoop.GetMinutesElapsed()); + float num = scaleCurve?.Evaluate(TimeLoop.GetMinutesElapsed()) ?? 1f; var dist = (transform.position - target.position).magnitude; transform.localScale = new Vector3(num, num, dist / 500f); diff --git a/NewHorizons/Components/MapSatelliteOrbitFix.cs b/NewHorizons/Components/MapSatelliteOrbitFix.cs index f4bc540d..190e1a75 100644 --- a/NewHorizons/Components/MapSatelliteOrbitFix.cs +++ b/NewHorizons/Components/MapSatelliteOrbitFix.cs @@ -7,14 +7,19 @@ namespace NewHorizons.Components { public void Awake() { - var config = new PlanetConfig(); - config.Base.SurfaceSize = 10f; + var config = new PlanetConfig + { + Base = + { + SurfaceSize = 10f + } + }; - var detector = base.transform.GetComponentInChildren(); - var ao = base.GetComponent(); - var newDetector = DetectorBuilder.Make(base.gameObject, ao.GetAttachedOWRigidbody(), ao.GetPrimaryBody(), ao, config); + var detector = transform.GetComponentInChildren(); + var ao = GetComponent(); + var newDetector = DetectorBuilder.Make(gameObject, ao.GetAttachedOWRigidbody(), ao.GetPrimaryBody(), ao, config); newDetector.transform.parent = detector.transform.parent; - GameObject.Destroy(detector); + Destroy(detector); } } } diff --git a/NewHorizons/Components/Orbital/BinaryFocalPoint.cs b/NewHorizons/Components/Orbital/BinaryFocalPoint.cs index f1ce6d84..6738a690 100644 --- a/NewHorizons/Components/Orbital/BinaryFocalPoint.cs +++ b/NewHorizons/Components/Orbital/BinaryFocalPoint.cs @@ -19,24 +19,37 @@ namespace NewHorizons.Components.Orbital void Update() { - if (Primary == null || Secondary == null) return; - - // Secondary and primary must have been engulfed by a star - if (!Primary.isActiveAndEnabled && !Secondary.isActiveAndEnabled) + if (Primary == null || Secondary == null) { - ReferenceFrameTracker component = Locator.GetPlayerBody().GetComponent(); - if (component.GetReferenceFrame(true) != null && component.GetReferenceFrame(true).GetOWRigidBody() == gameObject) - { - component.UntargetReferenceFrame(); - } - MapMarker component2 = gameObject.GetComponent(); - if (component2 != null) - { - component2.DisableMarker(); - } + CleanUp(); gameObject.SetActive(false); - FakeMassBody.SetActive(false); } + else + { + // Secondary and primary must have been engulfed by a star + if (!Primary.isActiveAndEnabled && !Secondary.isActiveAndEnabled) + { + CleanUp(); + gameObject.SetActive(false); + } + } + } + + private void CleanUp() + { + ReferenceFrameTracker component = Locator.GetPlayerBody()?.GetComponent(); + if (component?.GetReferenceFrame(true)?.GetOWRigidBody() == gameObject) + { + component.UntargetReferenceFrame(); + } + + MapMarker component2 = gameObject.GetComponent(); + if (component2 != null) + { + component2.DisableMarker(); + } + + FakeMassBody.SetActive(false); } } } diff --git a/NewHorizons/Components/TornadoFix.cs b/NewHorizons/Components/TornadoFix.cs deleted file mode 100644 index a0283013..00000000 --- a/NewHorizons/Components/TornadoFix.cs +++ /dev/null @@ -1,61 +0,0 @@ -namespace NewHorizons.Components -{ - public class TornadoFix : SectoredMonoBehaviour - { - public TornadoController tornadoController; - - public new void Awake() - { - base.Awake(); - tornadoController = GetComponent(); - tornadoController._tornadoRoot.SetActive(false); - - tornadoController._formationDuration = 1f; - tornadoController._collapseDuration = 1f; - if (_sector != null) - { - _sector.OnOccupantEnterSector += OnOccupantEnterSector; - _sector.OnOccupantExitSector += OnOccupantExitSector; - } - } - - public new void SetSector(Sector sector) - { - if (_sector != null) - { - _sector.OnOccupantEnterSector -= OnOccupantEnterSector; - _sector.OnOccupantExitSector -= OnOccupantExitSector; - } - - base.SetSector(sector); - _sector.OnOccupantEnterSector += OnOccupantEnterSector; - _sector.OnOccupantExitSector += OnOccupantExitSector; - } - - public new void OnDestroy() - { - base.OnDestroy(); - _sector.OnOccupantEnterSector -= OnOccupantEnterSector; - _sector.OnOccupantExitSector -= OnOccupantExitSector; - } - - public void OnOccupantEnterSector(SectorDetector _) - { - // Only form if not active and not forming - if (tornadoController._tornadoRoot.activeInHierarchy || tornadoController._tornadoForming) return; - - tornadoController.StartFormation(); - } - - public void OnOccupantExitSector(SectorDetector _) - { - - if (_sector.ContainsAnyOccupants(DynamicOccupant.Player | DynamicOccupant.Probe | DynamicOccupant.Ship)) return; - - // If the root is inactive it has collapsed. Also don't collapse if we're already doing it - if (!tornadoController._tornadoRoot.activeInHierarchy || tornadoController._tornadoCollapsing) return; - - tornadoController.StartCollapse(); - } - } -} diff --git a/NewHorizons/External/Configs/PlanetConfig.cs b/NewHorizons/External/Configs/PlanetConfig.cs index f6e280d5..b76f6c78 100644 --- a/NewHorizons/External/Configs/PlanetConfig.cs +++ b/NewHorizons/External/Configs/PlanetConfig.cs @@ -1,6 +1,10 @@ using NewHorizons.External.Modules; using NewHorizons.External.Modules.VariableSize; using Newtonsoft.Json; +using NewHorizons.Utility; +using System.ComponentModel; +using UnityEngine; +using UnityEngine.Internal; namespace NewHorizons.External.Configs { @@ -23,6 +27,7 @@ namespace NewHorizons.External.Configs /// /// Unique star system containing your planet /// + [DefaultValue("SolarSystem")] public string StarSystem = "SolarSystem"; /// @@ -38,6 +43,7 @@ namespace NewHorizons.External.Configs /// /// Set to a higher number if you wish for this body to be built sooner /// + [DefaultValue(-1)] public int BuildPriority = -1; /// @@ -235,6 +241,14 @@ namespace NewHorizons.External.Configs Atmosphere.UseAtmosphereShader = true; } } + + if(Props?.Tornados != null) + { + foreach(var tornado in Props.Tornados) + { + if (tornado.downwards) tornado.type = "downwards"; + } + } #pragma warning restore 612, 618 } } diff --git a/NewHorizons/External/Configs/StarSystemConfig.cs b/NewHorizons/External/Configs/StarSystemConfig.cs index 291ed7ec..5a3e3420 100644 --- a/NewHorizons/External/Configs/StarSystemConfig.cs +++ b/NewHorizons/External/Configs/StarSystemConfig.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json; +using System.ComponentModel; namespace NewHorizons.External.Configs { @@ -8,6 +9,11 @@ namespace NewHorizons.External.Configs [JsonObject] public class StarSystemConfig { + /// + /// Relative path to the image file to use as the subtitle image (replaces the eote banner) + /// + public string subtitle; + /// /// Whether this system can be warped to via the warp drive /// @@ -27,15 +33,6 @@ namespace NewHorizons.External.Configs /// Set to the FactID that must be revealed before it can be warped to. Don't set `CanEnterViaWarpDrive` to `false` if you're using this, that would make no sense. /// public string factRequiredForWarp; - - /// - /// Should the player be sent back in time after 22 minutes? - /// - public bool enableTimeLoop = true; - - /// - /// Should the player be unable to use their map in this system? - /// public bool mapRestricted; /// diff --git a/NewHorizons/External/Modules/AsteroidBeltModule.cs b/NewHorizons/External/Modules/AsteroidBeltModule.cs index b46624ee..62086ea5 100644 --- a/NewHorizons/External/Modules/AsteroidBeltModule.cs +++ b/NewHorizons/External/Modules/AsteroidBeltModule.cs @@ -1,4 +1,6 @@ using Newtonsoft.Json; +using UnityEngine.Internal; +using System.ComponentModel; namespace NewHorizons.External.Modules { @@ -18,16 +20,19 @@ namespace NewHorizons.External.Modules /// /// Minimum size of the asteroids. /// - public float MinSize = 20f; + [DefaultValue(20)] + public float MinSize = 20; /// /// Maximum size of the asteroids. /// + [DefaultValue(50)] public float MaxSize = 50f; /// /// Amount of asteroids to create. /// + [DefaultValue(-1)] public int Amount = -1; /// diff --git a/NewHorizons/External/Modules/AtmosphereModule.cs b/NewHorizons/External/Modules/AtmosphereModule.cs index 18134983..6811e144 100644 --- a/NewHorizons/External/Modules/AtmosphereModule.cs +++ b/NewHorizons/External/Modules/AtmosphereModule.cs @@ -1,5 +1,6 @@ using System.Runtime.Serialization; using NewHorizons.Utility; +using System.ComponentModel; using Newtonsoft.Json; using Newtonsoft.Json.Converters; @@ -87,7 +88,7 @@ namespace NewHorizons.External.Modules [JsonConverter(typeof(StringEnumConverter))] public CloudFluidType? FluidType; [System.Obsolete("UseBasicCloudShader is deprecated, please use CloudInfo instead")] public bool UseBasicCloudShader; - [System.Obsolete("ShadowsOnClouds is deprecated, please use CloudInfo instead")] public bool ShadowsOnClouds = true; + [DefaultValue(true)] [System.Obsolete("ShadowsOnClouds is deprecated, please use CloudInfo instead")] public bool ShadowsOnClouds = true; [System.Obsolete("HasAtmosphere is deprecated, please use UseAtmosphereShader instead")] public bool HasAtmosphere; #endregion Obsolete diff --git a/NewHorizons/External/Modules/BaseModule.cs b/NewHorizons/External/Modules/BaseModule.cs index b270a6f4..477d0403 100644 --- a/NewHorizons/External/Modules/BaseModule.cs +++ b/NewHorizons/External/Modules/BaseModule.cs @@ -1,6 +1,8 @@ using System.Runtime.Serialization; using NewHorizons.Utility; using Newtonsoft.Json; +using System.ComponentModel; +using UnityEngine.Internal; namespace NewHorizons.External.Modules { @@ -65,6 +67,7 @@ namespace NewHorizons.External.Modules /// /// Allows the object to be targeted on the map. /// + [DefaultValue(true)] public bool HasReferenceFrame = true; /// @@ -85,6 +88,7 @@ namespace NewHorizons.External.Modules /// /// Do we show the minimap when walking around this planet? /// + [DefaultValue(true)] public bool ShowMinimap = true; #region Obsolete diff --git a/NewHorizons/External/Modules/OrbitModule.cs b/NewHorizons/External/Modules/OrbitModule.cs index ddcb571b..180c0a19 100644 --- a/NewHorizons/External/Modules/OrbitModule.cs +++ b/NewHorizons/External/Modules/OrbitModule.cs @@ -2,6 +2,8 @@ using NewHorizons.Utility; using Newtonsoft.Json; using UnityEngine; +using System.ComponentModel; +using UnityEngine.Internal; namespace NewHorizons.External.Modules { @@ -71,6 +73,7 @@ namespace NewHorizons.External.Modules /// /// Referring to the orbit line in the map screen. /// + [DefaultValue(true)] public bool ShowOrbitLine { get; set; } = true; /// @@ -91,7 +94,7 @@ namespace NewHorizons.External.Modules /// /// Should we just draw a line behind its orbit instead of the entire circle/ellipse? /// - public bool TrackingOrbitLine { get; set; } = false; + public bool TrackingOrbitLine { get; set; } public OrbitalParameters GetOrbitalParameters(Gravity primaryGravity, Gravity secondaryGravity) { diff --git a/NewHorizons/External/Modules/PropModule.cs b/NewHorizons/External/Modules/PropModule.cs index df4fc361..3fdb9f74 100644 --- a/NewHorizons/External/Modules/PropModule.cs +++ b/NewHorizons/External/Modules/PropModule.cs @@ -1,5 +1,6 @@ using System.Runtime.Serialization; using NewHorizons.Utility; +using System.ComponentModel; using Newtonsoft.Json; using Newtonsoft.Json.Converters; @@ -143,6 +144,7 @@ namespace NewHorizons.External.Modules /// /// Scale the prop /// + [DefaultValue(1f)] public float scale = 1f; /// @@ -195,6 +197,7 @@ namespace NewHorizons.External.Modules /// /// The height of this tornado. /// + [DefaultValue(30f)] public float height = 30f; /// @@ -211,15 +214,17 @@ namespace NewHorizons.External.Modules /// The rate at which the tornado will wander around the planet. Set to 0 for it to be stationary. Should be around 0.1. /// public float wanderRate; - + /// /// Angular distance from the starting position that it will wander, in terms of the angle around the x-axis. /// + [DefaultValue(45f)] public float wanderDegreesX = 45f; /// /// Angular distance from the starting position that it will wander, in terms of the angle around the z-axis. /// + [DefaultValue(45f)] public float wanderDegreesZ = 45f; } diff --git a/NewHorizons/External/Modules/ShipLogModule.cs b/NewHorizons/External/Modules/ShipLogModule.cs index 86e7a9d0..232dd276 100644 --- a/NewHorizons/External/Modules/ShipLogModule.cs +++ b/NewHorizons/External/Modules/ShipLogModule.cs @@ -1,5 +1,6 @@ using NewHorizons.Utility; using Newtonsoft.Json; +using System.ComponentModel; namespace NewHorizons.External.Modules { @@ -52,6 +53,7 @@ namespace NewHorizons.External.Modules /// /// Scale to apply to the planet in map mode. /// + [DefaultValue(1f)] public float scale = 1f; /// diff --git a/NewHorizons/External/Modules/SignalModule.cs b/NewHorizons/External/Modules/SignalModule.cs index 35cede00..74fce0ce 100644 --- a/NewHorizons/External/Modules/SignalModule.cs +++ b/NewHorizons/External/Modules/SignalModule.cs @@ -1,5 +1,6 @@ using NewHorizons.Utility; using Newtonsoft.Json; +using System.ComponentModel; namespace NewHorizons.External.Modules { @@ -42,11 +43,13 @@ namespace NewHorizons.External.Modules /// /// A ship log fact to reveal when the signal is identified. /// + [DefaultValue("")] public string Reveals = ""; /// /// Radius of the sphere giving off the signal. /// + [DefaultValue(1f)] public float SourceRadius = 1f; /// @@ -57,11 +60,13 @@ namespace NewHorizons.External.Modules /// /// How close the player must get to the signal to identify it. This is when you learn its name. /// + [DefaultValue(10f)] public float IdentificationRadius = 10f; /// /// `false` if the player can hear the signal without equipping the signal-scope. /// + [DefaultValue(true)] public bool OnlyAudibleToScope = true; /// diff --git a/NewHorizons/External/Modules/VariableSize/SingularityModule.cs b/NewHorizons/External/Modules/VariableSize/SingularityModule.cs index d6d9f9c3..11c8c1df 100644 --- a/NewHorizons/External/Modules/VariableSize/SingularityModule.cs +++ b/NewHorizons/External/Modules/VariableSize/SingularityModule.cs @@ -2,6 +2,7 @@ using NewHorizons.Utility; using Newtonsoft.Json; using Newtonsoft.Json.Converters; +using System.ComponentModel; namespace NewHorizons.External.Modules.VariableSize { @@ -46,6 +47,7 @@ namespace NewHorizons.External.Modules.VariableSize /// /// Only for White Holes. Should this white hole repel the player from it. /// + [DefaultValue(true)] public bool MakeZeroGVolume = true; } } diff --git a/NewHorizons/External/Modules/VariableSize/StarModule.cs b/NewHorizons/External/Modules/VariableSize/StarModule.cs index 62452bc9..75741e43 100644 --- a/NewHorizons/External/Modules/VariableSize/StarModule.cs +++ b/NewHorizons/External/Modules/VariableSize/StarModule.cs @@ -1,5 +1,7 @@ using NewHorizons.Utility; using Newtonsoft.Json; +using System.ComponentModel; +using UnityEngine.Internal; namespace NewHorizons.External.Modules.VariableSize { @@ -9,6 +11,7 @@ namespace NewHorizons.External.Modules.VariableSize /// /// Radius of the star. /// + [DefaultValue(2000f)] public float Size = 2000f; /// @@ -34,16 +37,19 @@ namespace NewHorizons.External.Modules.VariableSize /// /// Relative strength of the light compared to the sun. /// + [DefaultValue(1f)] public float SolarLuminosity = 1f; /// /// The default sun has its own atmosphere that is different from regular planets. If you want that, set this to `true`. /// + [DefaultValue(true)] public bool HasAtmosphere = true; /// /// Should this star explode after 22 minutes? /// + [DefaultValue(true)] public bool GoSupernova = true; } } diff --git a/NewHorizons/Handlers/SubtitlesHandler.cs b/NewHorizons/Handlers/SubtitlesHandler.cs new file mode 100644 index 00000000..26cdf081 --- /dev/null +++ b/NewHorizons/Handlers/SubtitlesHandler.cs @@ -0,0 +1,118 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; +using NewHorizons.Utility; +using OWML.Common; + +namespace NewHorizons.Handlers +{ + class SubtitlesHandler : MonoBehaviour + { + public static int SUBTITLE_HEIGHT = 97; + public static int SUBTITLE_WIDTH = 669; // nice + + Graphic graphic; + Image image; + + public float fadeSpeed = 0.005f; + float fade = 1; + bool fadingAway = true; + + static List possibleSubtitles = new List(); + static bool eoteSubtitleHasBeenInserted = false; + int subtitleIndex; + + System.Random randomizer; + + static readonly int PAUSE_TIMER_MAX = 50; + int pauseTimer = PAUSE_TIMER_MAX; + + public void Start() + { + randomizer = new System.Random(); + + GetComponent().alpha = 1; + graphic = GetComponent(); + image = GetComponent(); + + graphic.enabled = true; + image.enabled = true; + + if (!Main.HasDLC) image.sprite = null; // Just in case. I don't know how not having the dlc changes the subtitle game object + + if (!eoteSubtitleHasBeenInserted) + { + if (image.sprite != null) possibleSubtitles.Insert(0, image.sprite); // ensure that the Echoes of the Eye subtitle always appears first + eoteSubtitleHasBeenInserted = true; + } + } + + public static void AddSubtitle(IModBehaviour mod, string filepath) + { + var tex = ImageUtilities.GetTexture(mod, filepath); + if (tex == null) return; + + // var sprite = Sprite.Create(tex, new Rect(0.0f, 0.0f, tex.width, tex.height), new Vector2(0.5f, 0.5f), 100.0f); + var sprite = Sprite.Create(tex, new Rect(0.0f, 0.0f, tex.width, SUBTITLE_HEIGHT), new Vector2(0.5f, 0.5f), 100.0f); + AddSubtitle(sprite); + } + + public static void AddSubtitle(Sprite sprite) + { + possibleSubtitles.Add(sprite); + } + + public void Update() + { + if (image.sprite == null) image.sprite = possibleSubtitles[0]; + + // don't fade transition subtitles if there's only one subtitle + if (possibleSubtitles.Count <= 1) return; + + if (pauseTimer > 0) + { + pauseTimer--; + return; + } + + if (fadingAway) + { + fade -= fadeSpeed; + + if (fade <= 0) + { + fade = 0; + ChangeSubtitle(); + fadingAway = false; + } + } + else + { + fade += fadeSpeed; + + if (fade >= 1) + { + fade = 1; + fadingAway = true; + pauseTimer = PAUSE_TIMER_MAX; + } + } + + graphic.color = new Color(1, 1, 1, fade); + } + + public void ChangeSubtitle() + { + // to pick a new random subtitle without requiring retries, we generate a random offset less than the length of the possible subtitles array + // we then add that offset to the current index, modulo NUMBER_OF_POSSIBLE_SUBTITLES + // since the offset can never be NUMBER_OF_POSSIBLE_SUBTITLES, it will never wrap all the way back around to the initial subtitleIndex + + // note, this makes the code more confusing, but Random.Next(min, max) generates a random number on the range [min, max) + // that is, the below code will generate numbers up to and including Count-1, not Count. + var newIndexOffset = randomizer.Next(1, possibleSubtitles.Count); + subtitleIndex = (subtitleIndex + newIndexOffset) % possibleSubtitles.Count; + + image.sprite = possibleSubtitles[subtitleIndex]; + } + } +} diff --git a/NewHorizons/Handlers/TitleSceneHandler.cs b/NewHorizons/Handlers/TitleSceneHandler.cs index f0e82aa0..9a28229b 100644 --- a/NewHorizons/Handlers/TitleSceneHandler.cs +++ b/NewHorizons/Handlers/TitleSceneHandler.cs @@ -11,6 +11,20 @@ namespace NewHorizons.Handlers { public static class TitleSceneHandler { + public static void InitSubtitles() + { + GameObject subtitleContainer = GameObject.Find("TitleMenu/TitleCanvas/TitleLayoutGroup/Logo_EchoesOfTheEye"); + + if (subtitleContainer == null) + { + Logger.LogError("No subtitle container found! Failed to load subtitles."); + return; + } + + subtitleContainer.SetActive(true); + subtitleContainer.AddComponent(); + } + public static void DisplayBodyOnTitleScreen(List bodies) { //Try loading one planet why not diff --git a/NewHorizons/Main.cs b/NewHorizons/Main.cs index 286cedd9..f885bba1 100644 --- a/NewHorizons/Main.cs +++ b/NewHorizons/Main.cs @@ -18,6 +18,7 @@ using UnityEngine; using UnityEngine.Events; using UnityEngine.SceneManagement; using Logger = NewHorizons.Utility.Logger; +using NewHorizons.Utility.DebugUtilities; namespace NewHorizons { @@ -85,6 +86,7 @@ namespace NewHorizons Debug = config.GetSettingsValue("Debug"); DebugReload.UpdateReloadButton(); + DebugMenu.UpdatePauseMenuButton(); Logger.UpdateLogLevel(Debug ? Logger.LogType.Log : Logger.LogType.Error); _defaultSystemOverride = config.GetSettingsValue("Default System Override"); @@ -231,6 +233,7 @@ namespace NewHorizons if (scene.name == "TitleScreen" && _useCustomTitleScreen) { TitleSceneHandler.DisplayBodyOnTitleScreen(BodyDict.Values.ToList().SelectMany(x => x).ToList()); + TitleSceneHandler.InitSubtitles(); } if (scene.name == "EyeOfTheUniverse" && IsWarping) @@ -301,6 +304,8 @@ namespace NewHorizons private void OnSystemReady(bool shouldWarpIn) { Locator.GetPlayerBody().gameObject.AddComponent(); + Locator.GetPlayerBody().gameObject.AddComponent(); + Locator.GetPlayerBody().gameObject.AddComponent(); if (shouldWarpIn) _shipWarpController.WarpIn(WearingSuit); else FindObjectOfType().DebugWarp(SystemDict[_currentStarSystem].SpawnPoint); @@ -343,6 +348,11 @@ namespace NewHorizons if (name != "SolarSystem") SetDefaultSystem(name); } + if (starSystemConfig.subtitle != null) + { + SubtitlesHandler.AddSubtitle(mod, starSystemConfig.subtitle); + } + var system = new NewHorizonsSystem(name, starSystemConfig, mod); SystemDict[name] = system; } @@ -428,7 +438,7 @@ namespace NewHorizons BodyDict.Add(config.StarSystem, new List()); } - body = new NewHorizonsBody(config, mod); + body = new NewHorizonsBody(config, mod, relativeDirectory); } catch (Exception e) { diff --git a/NewHorizons/Schemas/body_schema.json b/NewHorizons/Schemas/body_schema.json index acd17a96..e099d6bd 100644 --- a/NewHorizons/Schemas/body_schema.json +++ b/NewHorizons/Schemas/body_schema.json @@ -1086,9 +1086,14 @@ "$ref": "#/$defs/color", "description": "The colour of the tornado." }, - "downwards": { - "type": "boolean", - "description": "Should it pull things downwards? Will push them upwards by default." + "type": { + "type": "string", + "enum": [ + "downwards", + "upwards", + "hurricane" + ], + "description": "What type of cyclone should this be? Upwards and downwards are both tornados and will push in that direction." }, "wanderRate": { "type": "number", @@ -1097,12 +1102,12 @@ }, "wanderDegreesX": { "type": "number", - "description": "Angular distance from the starting position that it will wander, in terms of the angle around the x-axis.", + "description": "Angular distance from the starting position that it will wander, in terms of the azimuthal angle (angle of rotation around the polar axis).", "default": 45 }, "wanderDegreesZ": { "type": "number", - "description": "Angular distance from the starting position that it will wander, in terms of the angle around the z-axis.", + "description": "Angular distance from the starting position that it will wander, in terms of the polar angle (angle between the radial vector and the polar axis).", "default": 45 } } diff --git a/NewHorizons/Schemas/star_system_schema.json b/NewHorizons/Schemas/star_system_schema.json index 56a8b2e5..f79550bf 100644 --- a/NewHorizons/Schemas/star_system_schema.json +++ b/NewHorizons/Schemas/star_system_schema.json @@ -30,6 +30,10 @@ "description": "Should the player be unable to use their map in this system?", "default": false }, + "subtitle": { + "type": "string", + "description": "Relative path to a subtitle image to be displayed on the main menu scene. The image should be 669x97 resolution." + }, "skybox": { "type": "object", "description": "Options for the skybox of your system", diff --git a/NewHorizons/Utility/DebugRaycaster.cs b/NewHorizons/Utility/DebugRaycaster.cs deleted file mode 100644 index 7091d658..00000000 --- a/NewHorizons/Utility/DebugRaycaster.cs +++ /dev/null @@ -1,54 +0,0 @@ -using UnityEngine; -using UnityEngine.InputSystem; -namespace NewHorizons.Utility -{ - [RequireComponent(typeof(OWRigidbody))] - public class DebugRaycaster : MonoBehaviour - { - private OWRigidbody _rb; - private GameObject _surfaceSphere; - private GameObject _normalSphere1; - private GameObject _normalSphere2; - - private void Awake() - { - _rb = this.GetRequiredComponent(); - } - - private void Update() - { - if (Main.Debug && Keyboard.current != null && Keyboard.current[Key.P].wasReleasedThisFrame) - { - // Raycast - _rb.DisableCollisionDetection(); - int layerMask = OWLayerMask.physicalMask; - var origin = Locator.GetActiveCamera().transform.position; - var direction = Locator.GetActiveCamera().transform.TransformDirection(Vector3.forward); - if (Physics.Raycast(origin, direction, out RaycastHit hitInfo, 100f, layerMask)) - { - var pos = hitInfo.transform.InverseTransformPoint(hitInfo.point); - var norm = hitInfo.transform.InverseTransformDirection(hitInfo.normal); - var o = hitInfo.transform.gameObject; - - var posText = $"{{\"x\": {pos.x}, \"y\": {pos.y}, \"z\": {pos.z}}}"; - var normText = $"{{\"x\": {norm.x}, \"y\": {norm.y}, \"z\": {norm.z}}}"; - - if (_surfaceSphere != null) GameObject.Destroy(_surfaceSphere); - if (_normalSphere1 != null) GameObject.Destroy(_normalSphere1); - if (_normalSphere2 != null) GameObject.Destroy(_normalSphere2); - - _surfaceSphere = AddDebugShape.AddSphere(hitInfo.transform.gameObject, 0.1f, Color.green); - _normalSphere1 = AddDebugShape.AddSphere(hitInfo.transform.gameObject, 0.01f, Color.red); - _normalSphere2 = AddDebugShape.AddSphere(hitInfo.transform.gameObject, 0.01f, Color.red); - - _surfaceSphere.transform.localPosition = pos; - _normalSphere1.transform.localPosition = pos + norm * 0.5f; - _normalSphere2.transform.localPosition = pos + norm; - - Logger.Log($"Raycast hit \"position\": {posText}, \"normal\": {normText} on [{o.name}] at [{SearchUtilities.GetPath(o.transform)}]"); - } - _rb.EnableCollisionDetection(); - } - } - } -} diff --git a/NewHorizons/Utility/DebugUtilities/DebugMenu.cs b/NewHorizons/Utility/DebugUtilities/DebugMenu.cs new file mode 100644 index 00000000..1046c194 --- /dev/null +++ b/NewHorizons/Utility/DebugUtilities/DebugMenu.cs @@ -0,0 +1,353 @@ +using NewHorizons.External; +using NewHorizons.External.Configs; +using NewHorizons.External.Modules; +using NewHorizons.Handlers; +using Newtonsoft.Json; +using OWML.Common; +using OWML.Common.Menus; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using UnityEngine.InputSystem; + +namespace NewHorizons.Utility.DebugUtilities +{ + + // + // + // TODO: split this into two separate classes "DebugMenu" and "DebugPropPlacerMenu" + // + // + + [RequireComponent(typeof(DebugRaycaster))] + [RequireComponent(typeof(DebugPropPlacer))] + class DebugMenu : MonoBehaviour + { + private static IModButton pauseMenuButton; + + GUIStyle _editorMenuStyle; + Vector2 EditorMenuSize = new Vector2(600, 900); + bool menuOpen = false; + static bool openMenuOnPause; + static bool staticInitialized; + + DebugPropPlacer _dpp; + DebugRaycaster _drc; + + // menu params + private Vector2 recentPropsScrollPosition = Vector2.zero; + private HashSet favoriteProps = new HashSet(); + public static readonly char separatorCharacter = '☧'; // since no chars are illegal in game object names, I picked one that's extremely unlikely to be used to be a separator + private static readonly string favoritePropsPlayerPrefKey = "FavoriteProps"; + + private static IModBehaviour loadedMod = null; + private Dictionary loadedConfigFiles = new Dictionary(); + private bool saveButtonUnlocked = false; + private Vector2 recentModListScrollPosition = Vector2.zero; + + private static JsonSerializerSettings jsonSettings = new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + DefaultValueHandling = DefaultValueHandling.Ignore, + Formatting = Formatting.Indented, + }; + + private void Awake() + { + _dpp = this.GetRequiredComponent(); + _drc = this.GetRequiredComponent(); + LoadFavoriteProps(); + } + + private void Start() + { + if (!staticInitialized) + { + staticInitialized = true; + + Main.Instance.ModHelper.Menus.PauseMenu.OnInit += PauseMenuInitHook; + Main.Instance.ModHelper.Menus.PauseMenu.OnClosed += CloseMenu; + Main.Instance.ModHelper.Menus.PauseMenu.OnOpened += RestoreMenuOpennessState; + + PauseMenuInitHook(); + + Main.Instance.OnChangeStarSystem.AddListener((string s) => SaveLoadedConfigsForRecentSystem()); + } + else + { + InitMenu(); + } + + if (loadedMod != null) + { + LoadMod(loadedMod); + } + } + + private void PauseMenuInitHook() + { + pauseMenuButton = Main.Instance.ModHelper.Menus.PauseMenu.OptionsButton.Duplicate(TranslationHandler.GetTranslation("Toggle Prop Placer Menu", TranslationHandler.TextType.UI).ToUpper()); + InitMenu(); + } + public static void UpdatePauseMenuButton() + { + if (pauseMenuButton != null) + { + if (Main.Debug) pauseMenuButton.Show(); + else pauseMenuButton.Hide(); + } + } + + private void RestoreMenuOpennessState() { menuOpen = openMenuOnPause; } + private void ToggleMenu() { menuOpen = !menuOpen; openMenuOnPause = !openMenuOnPause; } + + private void CloseMenu() { menuOpen = false; } + + private void LoadFavoriteProps() + { + string favoritePropsPlayerPref = PlayerPrefs.GetString(favoritePropsPlayerPrefKey); + + if (favoritePropsPlayerPref == null || favoritePropsPlayerPref == "") return; + + var favoritePropPaths = favoritePropsPlayerPref.Split(separatorCharacter); + foreach (string favoriteProp in favoritePropPaths) + { + DebugPropPlacer.RecentlyPlacedProps.Add(favoriteProp); + this.favoriteProps.Add(favoriteProp); + } + } + + private void OnGUI() + { + if (!menuOpen) return; + if (!Main.Debug) return; + + Vector2 menuPosition = new Vector2(10, 40); + + GUILayout.BeginArea(new Rect(menuPosition.x, menuPosition.y, EditorMenuSize.x, EditorMenuSize.y), _editorMenuStyle); + + // + // DebugPropPlacer + // + GUILayout.Label("Recently placed objects"); + _dpp.SetCurrentObject(GUILayout.TextArea(_dpp.currentObject)); + + GUILayout.Space(5); + + // List of recently placed objects + GUILayout.Label("Recently placed objects"); + recentPropsScrollPosition = GUILayout.BeginScrollView(recentPropsScrollPosition, GUILayout.Width(EditorMenuSize.x), GUILayout.Height(100)); + foreach (string propPath in DebugPropPlacer.RecentlyPlacedProps) + { + GUILayout.BeginHorizontal(); + + var propPathElements = propPath[propPath.Length-1] == '/' + ? propPath.Substring(0, propPath.Length-1).Split('/') + : propPath.Split('/'); + string propName = propPathElements[propPathElements.Length - 1]; + + string favoriteButtonIcon = favoriteProps.Contains(propPath) ? "★" : "☆"; + if (GUILayout.Button(favoriteButtonIcon, GUILayout.ExpandWidth(false))) + { + if (favoriteProps.Contains(propPath)) + { + favoriteProps.Remove(propPath); + } + else + { + favoriteProps.Add(propPath); + } + + string[] favoritePropsArray = favoriteProps.ToArray(); + PlayerPrefs.SetString(favoritePropsPlayerPrefKey, string.Join(separatorCharacter + "", favoritePropsArray)); + } + + if (GUILayout.Button(propName)) + { + _dpp.SetCurrentObject(propPath); + } + + GUILayout.EndHorizontal(); + } + GUILayout.EndScrollView(); + + GUILayout.Space(5); + + // continue working on existing mod + + GUILayout.Label("Name of your mod"); + if (loadedMod == null) + { + recentModListScrollPosition = GUILayout.BeginScrollView(recentModListScrollPosition, GUILayout.Width(EditorMenuSize.x), GUILayout.Height(100)); + + foreach (var mod in Main.MountedAddons) + { + if (GUILayout.Button(mod.ModHelper.Manifest.UniqueName)) + { + LoadMod(mod); + } + } + + GUILayout.EndScrollView(); + } + else + { + GUILayout.Label(loadedMod.ModHelper.Manifest.UniqueName); + } + + GUILayout.Space(5); + + // save your work + + { + GUILayout.BeginHorizontal(); + if (GUILayout.Button(saveButtonUnlocked ? " O " : " | ", GUILayout.ExpandWidth(false))) + { + saveButtonUnlocked = !saveButtonUnlocked; + } + GUI.enabled = saveButtonUnlocked; + if (GUILayout.Button("Update your mod's configs")) + { + SaveLoadedConfigsForRecentSystem(); + saveButtonUnlocked = false; + } + GUI.enabled = true; + GUILayout.EndHorizontal(); + } + + GUILayout.EndArea(); + } + + private void LoadMod(IModBehaviour mod) + { + loadedMod = mod; + DebugPropPlacer.active = true; + + var folder = loadedMod.ModHelper.Manifest.ModFolderPath; + + List bodiesForThisMod = Main.BodyDict.Values.SelectMany(x => x).Where(x => x.Mod == loadedMod).ToList(); + foreach (NewHorizonsBody body in bodiesForThisMod) + { + if (body.RelativePath == null) + { + Logger.Log("Error loading config for " + body.Config.Name + " in " + body.Config.StarSystem); + } + + loadedConfigFiles[folder + body.RelativePath] = (body.Config as PlanetConfig); + _dpp.FindAndRegisterPropsFromConfig(body.Config); + } + } + + private void SaveLoadedConfigsForRecentSystem() + { + UpdateLoadedConfigsForRecentSystem(); + + string backupFolderName = "configBackups\\" + DateTime.Now.ToString("yyyyMMddTHHmmss") + "\\"; + Logger.Log($"Potentially saving {loadedConfigFiles.Keys.Count} files"); + + foreach (var filePath in loadedConfigFiles.Keys) + { + Logger.Log("Possibly Saving... " + loadedConfigFiles[filePath].Name + " @ " + filePath); + if (loadedConfigFiles[filePath].StarSystem != Main.Instance.CurrentStarSystem) continue; + + var relativePath = filePath.Replace(loadedMod.ModHelper.Manifest.ModFolderPath, ""); + + var json = JsonConvert.SerializeObject(loadedConfigFiles[filePath], jsonSettings); + // Add the schema line + json = "{\n\t\"$schema\": \"https://raw.githubusercontent.com/xen-42/outer-wilds-new-horizons/main/NewHorizons/Schemas/body_schema.json\"," + json.Substring(1); + + try + { + Logger.Log("Saving... " + relativePath + " to " + filePath); + var path = loadedMod.ModHelper.Manifest.ModFolderPath + relativePath; + var directoryName = Path.GetDirectoryName(path); + Directory.CreateDirectory(directoryName); + + File.WriteAllText(path, json); + } + catch (Exception e) { Logger.LogError("Failed to save file " + backupFolderName + relativePath); Logger.LogError(e.Message + "\n" + e.StackTrace); } + + try + { + var path = Main.Instance.ModHelper.Manifest.ModFolderPath + backupFolderName + relativePath; + var directoryName = Path.GetDirectoryName(path); + Directory.CreateDirectory(directoryName); + + File.WriteAllText(path, json); + } + catch (Exception e) { Logger.LogError("Failed to save backup file " + backupFolderName + relativePath); Logger.LogError(e.Message + "\n" + e.StackTrace); } + } + } + + private void UpdateLoadedConfigsForRecentSystem() + { + var newDetails = _dpp.GetPropsConfigByBody(); + + Logger.Log("Updating config files. New Details Counts by planet: " + string.Join(", ", newDetails.Keys.Select(x => x + $" ({newDetails[x].Length})"))); + + Dictionary planetToConfigPath = new Dictionary(); + + // Get all configs + foreach (var filePath in loadedConfigFiles.Keys) + { + Logger.Log("potentially updating copy of config at " + filePath); + + if (loadedConfigFiles[filePath].StarSystem != Main.Instance.CurrentStarSystem) return; + if (loadedConfigFiles[filePath].Name == null || AstroObjectLocator.GetAstroObject(loadedConfigFiles[filePath].Name) == null) { Logger.Log("Failed to update copy of config at " + filePath); continue; } + + var astroObjectName = DebugPropPlacer.GetAstroObjectName(loadedConfigFiles[filePath].Name); + planetToConfigPath[astroObjectName] = filePath; + + if (!newDetails.ContainsKey(astroObjectName)) continue; + + if (loadedConfigFiles[filePath].Props == null) loadedConfigFiles[filePath].Props = new External.Modules.PropModule(); + loadedConfigFiles[filePath].Props.Details = newDetails[astroObjectName]; + + Logger.Log("successfully updated copy of config file for " + astroObjectName); + } + + // find all new planets that do not yet have config paths + var planetsThatDoNotHaveConfigFiles = newDetails.Keys.Where(x => !planetToConfigPath.ContainsKey(x)).ToList(); + foreach (var astroObjectName in planetsThatDoNotHaveConfigFiles) + { + Logger.Log("Fabricating new config file for " + astroObjectName); + + var filepath = "planets/" + Main.Instance.CurrentStarSystem + "/" + astroObjectName + ".json"; + PlanetConfig c = new PlanetConfig(); + c.StarSystem = Main.Instance.CurrentStarSystem; + c.Name = astroObjectName; + c.Props = new PropModule(); + c.Props.Details = newDetails[astroObjectName]; + + loadedConfigFiles[filepath] = c; + } + } + + private void InitMenu() + { + if (_editorMenuStyle != null) return; + + UpdatePauseMenuButton(); + + // TODO: figure out how to clear this event list so that we don't pile up useless instances of the DebugMenu that can't get garbage collected + pauseMenuButton.OnClick += ToggleMenu; + + _dpp = this.GetRequiredComponent(); + _drc = this.GetRequiredComponent(); + + Texture2D bgTexture = ImageUtilities.MakeSolidColorTexture((int)EditorMenuSize.x, (int)EditorMenuSize.y, Color.black); + + _editorMenuStyle = new GUIStyle + { + normal = + { + background = bgTexture + } + }; + } + } +} diff --git a/NewHorizons/Utility/DebugUtilities/DebugPropPlacer.cs b/NewHorizons/Utility/DebugUtilities/DebugPropPlacer.cs new file mode 100644 index 00000000..26f595ea --- /dev/null +++ b/NewHorizons/Utility/DebugUtilities/DebugPropPlacer.cs @@ -0,0 +1,279 @@ +using NewHorizons.Builder.Props; +using NewHorizons.External.Configs; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using UnityEngine.InputSystem; +using static NewHorizons.External.Modules.PropModule; + +namespace NewHorizons.Utility.DebugUtilities +{ + + // + // The prop placer. Doesn't interact with any files, just places and tracks props. + // + + [RequireComponent(typeof(DebugRaycaster))] + class DebugPropPlacer : MonoBehaviour + { + private struct PropPlacementData + { + public string body; + public string system; + public GameObject gameObject; + public DetailInfo detailInfo; + } + + // VASE + public static readonly string DEFAULT_OBJECT = "BrittleHollow_Body/Sector_BH/Sector_NorthHemisphere/Sector_NorthPole/Sector_HangingCity/Sector_HangingCity_District1/Props_HangingCity_District1/OtherComponentsGroup/Props_HangingCity_Building_10/Prefab_NOM_VaseThin"; + + public string currentObject { get; private set; } // path of the prop to be placed + private bool hasAddedCurrentObjectToRecentsList = false; + private List props = new List(); + private List deletedProps = new List(); + private DebugRaycaster _rc; + + public static HashSet RecentlyPlacedProps = new HashSet(); + + public static bool active = false; + + private void Awake() + { + _rc = this.GetRequiredComponent(); + currentObject = DEFAULT_OBJECT; + } + + private void Update() + { + if (!Main.Debug) return; + if (!active) return; + + if (Keyboard.current[Key.G].wasReleasedThisFrame) + { + PlaceObject(); + } + + if (Keyboard.current[Key.Minus].wasReleasedThisFrame) + { + DeleteLast(); + } + + if (Keyboard.current[Key.Equals].wasReleasedThisFrame) + { + UndoDelete(); + } + } + + public void SetCurrentObject(string s) + { + currentObject = s; + hasAddedCurrentObjectToRecentsList = false; + } + + internal void PlaceObject() + { + DebugRaycastData data = _rc.Raycast(); + PlaceObject(data, this.gameObject.transform.position); + + if (!hasAddedCurrentObjectToRecentsList) + { + hasAddedCurrentObjectToRecentsList = true; + + if (!RecentlyPlacedProps.Contains(currentObject)) + { + RecentlyPlacedProps.Add(currentObject); + } + } + } + + public void PlaceObject(DebugRaycastData data, Vector3 playerAbsolutePosition) + { + // TODO: implement sectors + // if this hits a sector, store that sector and add a config file option for it + + if (!data.hitObject.name.EndsWith("_Body")) + { + Logger.Log("Cannot place object on non-body object: " + data.hitObject.name); + } + + try + { + if (currentObject == "" || currentObject == null) + { + SetCurrentObject(DEFAULT_OBJECT); + } + + GameObject prop = DetailBuilder.MakeDetail(data.hitObject, data.hitObject.GetComponentInChildren(), currentObject, data.pos, data.norm, 1, false); + PropPlacementData propData = RegisterProp_WithReturn(data.bodyName, prop); + + // align with surface normal + Vector3 alignToSurface = (Quaternion.LookRotation(data.norm) * Quaternion.FromToRotation(Vector3.up, Vector3.forward)).eulerAngles; + prop.transform.localEulerAngles = alignToSurface; + + // rotate facing dir towards player + GameObject g = new GameObject(); + g.transform.parent = prop.transform.parent; + g.transform.localPosition = prop.transform.localPosition; + g.transform.localRotation = prop.transform.localRotation; + + prop.transform.parent = g.transform; + + var dirTowardsPlayer = prop.transform.parent.transform.InverseTransformPoint(playerAbsolutePosition) - prop.transform.localPosition; + dirTowardsPlayer.y = 0; + float rotation = Quaternion.LookRotation(dirTowardsPlayer).eulerAngles.y; + prop.transform.localEulerAngles = new Vector3(0, rotation, 0); + + prop.transform.parent = g.transform.parent; + GameObject.Destroy(g); + } + catch + { + Logger.Log($"Failed to place object {currentObject} on body ${data.hitObject} at location ${data.pos}."); + } + } + + public static string GetAstroObjectName(string bodyName) + { + if (bodyName.EndsWith("_Body")) bodyName = bodyName.Substring(0, bodyName.Length-"_Body".Length); + + var astroObject = AstroObjectLocator.GetAstroObject(bodyName); + if (astroObject == null) return null; + + var astroObjectName = astroObject.name; + if (astroObjectName.EndsWith("_Body")) astroObjectName = astroObjectName.Substring(0, astroObjectName.Length-"_Body".Length); + + return astroObjectName; + } + + public void FindAndRegisterPropsFromConfig(PlanetConfig config) + { + if (config.StarSystem != Main.Instance.CurrentStarSystem) return; + + AstroObject planet = AstroObjectLocator.GetAstroObject(config.Name); + + if (planet == null) return; + if (config.Props == null || config.Props.Details == null) return; + + var astroObjectName = GetAstroObjectName(config.Name); + + foreach (var detail in config.Props.Details) + { + GameObject spawnedProp = DetailBuilder.GetSpawnedGameObjectByDetailInfo(detail); + + if (spawnedProp == null) + { + Logger.LogError("No spawned prop found for " + detail.path); + continue; + } + + PropPlacementData data = RegisterProp_WithReturn(astroObjectName, spawnedProp, detail.path, detail); + + // note: we do not support placing props from assetbundles, so they will not be added to the + // selectable list of placed props + if (detail.assetBundle == null && !RecentlyPlacedProps.Contains(data.detailInfo.path)) + { + RecentlyPlacedProps.Add(data.detailInfo.path); + } + } + } + + public void RegisterProp(string bodyGameObjectName, GameObject prop) + { + RegisterProp_WithReturn(bodyGameObjectName, prop); + } + + private PropPlacementData RegisterProp_WithReturn(string bodyGameObjectName, GameObject prop, string propPath = null, DetailInfo detailInfo = null) + { + if (Main.Debug) + { + // TOOD: make this prop an item + } + + + string bodyName = GetAstroObjectName(bodyGameObjectName); + + Logger.Log("Adding prop to " + Main.Instance.CurrentStarSystem + "::" + bodyName); + + + detailInfo = detailInfo == null ? new DetailInfo() : detailInfo; + detailInfo.path = propPath == null ? currentObject : propPath; + + PropPlacementData data = new PropPlacementData + { + body = bodyName, + gameObject = prop, + system = Main.Instance.CurrentStarSystem, + detailInfo = detailInfo + }; + + props.Add(data); + return data; + } + + public Dictionary GetPropsConfigByBody() + { + var groupedProps = props + .GroupBy(p => p.system + "." + p.body) + .Select(grp => grp.ToList()) + .ToList(); + + Dictionary propConfigs = new Dictionary(); + + foreach (List bodyProps in groupedProps) + { + if (bodyProps == null || bodyProps.Count == 0) continue; + Logger.Log("getting prop group for body " + bodyProps[0].body); + if (AstroObjectLocator.GetAstroObject(bodyProps[0].body) == null) continue; + string bodyName = GetAstroObjectName(bodyProps[0].body); + + DetailInfo[] infoArray = new DetailInfo[bodyProps.Count]; + propConfigs[bodyName] = infoArray; + + for(int i = 0; i < bodyProps.Count; i++) + { + var prop = bodyProps[i]; + var rootTransform = prop.gameObject.transform.root; + + // Objects are parented to the sector and not to the planet + // However, raycasted positions are reported relative to the root game object + // Normally these two are the same, but there are some notable exceptions (ex, floating islands) + // So we can't use local position/rotation here, we have to inverse transform the global position/rotation relative to root object + prop.detailInfo.position = rootTransform.InverseTransformPoint(prop.gameObject.transform.position); + prop.detailInfo.scale = prop.gameObject.transform.localScale.x; + if (!prop.detailInfo.alignToNormal) prop.detailInfo.rotation = rootTransform.InverseTransformRotation(prop.gameObject.transform.rotation).eulerAngles; + + infoArray[i] = prop.detailInfo; + } + } + + return propConfigs; + } + + public void DeleteLast() + { + if (props.Count <= 0) return; + + PropPlacementData last = props[props.Count-1]; + props.RemoveAt(props.Count-1); + + last.gameObject.SetActive(false); + + deletedProps.Add(last); + } + + public void UndoDelete() + { + if (deletedProps.Count <= 0) return; + + PropPlacementData last = deletedProps[deletedProps.Count-1]; + deletedProps.RemoveAt(deletedProps.Count-1); + + last.gameObject.SetActive(true); + + props.Add(last); + } + } +} diff --git a/NewHorizons/Utility/DebugUtilities/DebugRaycastData.cs b/NewHorizons/Utility/DebugUtilities/DebugRaycastData.cs new file mode 100644 index 00000000..467bdda6 --- /dev/null +++ b/NewHorizons/Utility/DebugUtilities/DebugRaycastData.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace NewHorizons.Utility.DebugUtilities +{ + struct DebugRaycastData + { + public bool hit; + public Vector3 pos; + public Vector3 norm; + + public string bodyName; + public string bodyPath; + public GameObject hitObject; + } +} diff --git a/NewHorizons/Utility/DebugUtilities/DebugRaycaster.cs b/NewHorizons/Utility/DebugUtilities/DebugRaycaster.cs new file mode 100644 index 00000000..1c34448b --- /dev/null +++ b/NewHorizons/Utility/DebugUtilities/DebugRaycaster.cs @@ -0,0 +1,78 @@ +using UnityEngine; +using UnityEngine.InputSystem; + +namespace NewHorizons.Utility.DebugUtilities +{ + [RequireComponent(typeof(OWRigidbody))] + public class DebugRaycaster : MonoBehaviour + { + private OWRigidbody _rb; + private GameObject _surfaceSphere; + private GameObject _normalSphere1; + private GameObject _normalSphere2; + + private void Awake() + { + _rb = this.GetRequiredComponent(); + } + + + private void Update() + { + if (!Main.Debug) return; + if (Keyboard.current == null) return; + + if (Keyboard.current[Key.P].wasReleasedThisFrame) + { + PrintRaycast(); + } + } + + + + internal void PrintRaycast() + { + DebugRaycastData data = Raycast(); + var posText = $"{{\"x\": {data.pos.x}, \"y\": {data.pos.y}, \"z\": {data.pos.z}}}"; + var normText = $"{{\"x\": {data.norm.x}, \"y\": {data.norm.y}, \"z\": {data.norm.z}}}"; + + if(_surfaceSphere != null) GameObject.Destroy(_surfaceSphere); + if(_normalSphere1 != null) GameObject.Destroy(_normalSphere1); + if(_normalSphere2 != null) GameObject.Destroy(_normalSphere2); + + _surfaceSphere = AddDebugShape.AddSphere(data.hitObject, 0.1f, Color.green); + _normalSphere1 = AddDebugShape.AddSphere(data.hitObject, 0.01f, Color.red); + _normalSphere2 = AddDebugShape.AddSphere(data.hitObject, 0.01f, Color.red); + + _surfaceSphere.transform.localPosition = data.pos; + _normalSphere1.transform.localPosition = data.pos + data.norm * 0.5f; + _normalSphere2.transform.localPosition = data.pos + data.norm; + + Logger.Log($"Raycast hit \"position\": {posText}, \"normal\": {normText} on [{data.bodyName}] at [{data.bodyPath}]"); + } + internal DebugRaycastData Raycast() + { + DebugRaycastData data = new DebugRaycastData(); + + _rb.DisableCollisionDetection(); + int layerMask = OWLayerMask.physicalMask; + var origin = Locator.GetActiveCamera().transform.position; + var direction = Locator.GetActiveCamera().transform.TransformDirection(Vector3.forward); + + data.hit = Physics.Raycast(origin, direction, out RaycastHit hitInfo, 100f, layerMask); + if (data.hit) + { + data.pos = hitInfo.transform.InverseTransformPoint(hitInfo.point); + data.norm = hitInfo.transform.InverseTransformDirection(hitInfo.normal); + var o = hitInfo.transform.gameObject; + + data.bodyName = o.name; + data.bodyPath = SearchUtilities.GetPath(o.transform); + data.hitObject = hitInfo.transform.gameObject; + } + _rb.EnableCollisionDetection(); + + return data; + } + } +} diff --git a/NewHorizons/Utility/DebugReload.cs b/NewHorizons/Utility/DebugUtilities/DebugReload.cs similarity index 97% rename from NewHorizons/Utility/DebugReload.cs rename to NewHorizons/Utility/DebugUtilities/DebugReload.cs index e6be142c..8e763eab 100644 --- a/NewHorizons/Utility/DebugReload.cs +++ b/NewHorizons/Utility/DebugUtilities/DebugReload.cs @@ -3,7 +3,8 @@ using OWML.Common; using OWML.Common.Menus; using System; using UnityEngine; -namespace NewHorizons.Utility + +namespace NewHorizons.Utility.DebugUtilities { public static class DebugReload { diff --git a/NewHorizons/Utility/ImageUtilities.cs b/NewHorizons/Utility/ImageUtilities.cs index d1e4df08..eb4cf0be 100644 --- a/NewHorizons/Utility/ImageUtilities.cs +++ b/NewHorizons/Utility/ImageUtilities.cs @@ -293,5 +293,19 @@ namespace NewHorizons.Utility return new Color(r / 255, g / 255, b / 255); } + public static Texture2D MakeSolidColorTexture(int width, int height, Color color) + { + Color[] pixels = new Color[width*height]; + + for(int i = 0; i < pixels.Length; i++) + { + pixels[i] = color; + } + + Texture2D newTexture = new Texture2D(width, height); + newTexture.SetPixels(pixels); + newTexture.Apply(); + return newTexture; + } } } diff --git a/NewHorizons/Utility/MColor.cs b/NewHorizons/Utility/MColor.cs index fd77c349..0600f28a 100644 --- a/NewHorizons/Utility/MColor.cs +++ b/NewHorizons/Utility/MColor.cs @@ -14,7 +14,7 @@ namespace NewHorizons.Utility public int R { get; } public int G { get; } public int B { get; } - public int A { get; } + public int A { get; } public Color32 ToColor32() => new Color32((byte)R, (byte)G, (byte)B, (byte)A); diff --git a/NewHorizons/Utility/NewHorizonBody.cs b/NewHorizons/Utility/NewHorizonBody.cs index 9a64d2a0..48c9d81d 100644 --- a/NewHorizons/Utility/NewHorizonBody.cs +++ b/NewHorizons/Utility/NewHorizonBody.cs @@ -1,19 +1,21 @@ -using NewHorizons.External.Configs; -using OWML.Common; -using UnityEngine; -namespace NewHorizons.Utility -{ - public class NewHorizonsBody - { - public NewHorizonsBody(PlanetConfig config, IModBehaviour mod) - { - Config = config; - Mod = mod; - } - - public PlanetConfig Config; - public IModBehaviour Mod; - - public GameObject Object; - } -} +using NewHorizons.External.Configs; +using OWML.Common; +using UnityEngine; +namespace NewHorizons.Utility +{ + public class NewHorizonsBody + { + public NewHorizonsBody(PlanetConfig config, IModBehaviour mod, string relativePath = null) + { + Config = config; + Mod = mod; + RelativePath = relativePath; + } + + public PlanetConfig Config; + public IModBehaviour Mod; + public string RelativePath; + + public GameObject Object; + } +} diff --git a/NewHorizons/Utility/SearchUtilities.cs b/NewHorizons/Utility/SearchUtilities.cs index 4cd5e2c1..821e68ea 100644 --- a/NewHorizons/Utility/SearchUtilities.cs +++ b/NewHorizons/Utility/SearchUtilities.cs @@ -135,7 +135,7 @@ namespace NewHorizons.Utility // Get the root object and hope its the right one var root = GameObject.Find(names[0]); - if (root == null) root = FindObjectOfTypeAndName(names[0]); + if (root == null) root = UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects().Where(x => x.name.Equals(names[0])).FirstOrDefault(); var t = root?.transform; if (t == null) diff --git a/docs/Pipfile.lock b/docs/Pipfile.lock index ce77fdbb..f5fd8bf3 100644 --- a/docs/Pipfile.lock +++ b/docs/Pipfile.lock @@ -35,10 +35,11 @@ }, "certifi": { "hashes": [ - "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", - "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" + "sha256:9c5705e395cd70084351dd8ad5c41e65655e08ce46f2ec9cf6c2c08390f71eb7", + "sha256:f1d53542ee8cbedbe2118b5686372fb33c297fcd6379b050cca0ef13a597382a" ], - "version": "==2021.10.8" + "markers": "python_version >= '3.6'", + "version": "==2022.5.18.1" }, "charset-normalizer": { "hashes": [ @@ -111,11 +112,11 @@ }, "json-schema-for-humans": { "hashes": [ - "sha256:a96f7bb1175bf979ac6360a0dbea81a82443abdb376696dc33f5a6fb8705f25e", - "sha256:e05f0d52d6ac211eceecd5201bcefb91538c9b75ecb56a1950b47090ac3ab8b6" + "sha256:030650ab4457556d09867d1b503619652dccf1c3ae118343663848faded97fc0", + "sha256:7ea6998e6c86c724c0693ec7379559b1b568309c3500e0d64ced56b31b778fa2" ], - "markers": "python_version >= '3.7' and python_version < '4'", - "version": "==0.40.5" + "markers": "python_version >= '3.7' and python_version < '4.0'", + "version": "==0.41.1" }, "jsonschema": { "hashes": [ @@ -125,6 +126,21 @@ "markers": "python_version >= '3.7'", "version": "==4.5.1" }, + "libsass": { + "hashes": [ + "sha256:06c8776417fe930714bdc930a3d7e795ae3d72be6ac883ff72a1b8f7c49e5ffb", + "sha256:12f39712de38689a8b785b7db41d3ba2ea1d46f9379d81ea4595802d91fa6529", + "sha256:1e25dd9047a9392d3c59a0b869e0404f2b325a03871ee45285ee33b3664f5613", + "sha256:659ae41af8708681fa3ec73f47b9735a6725e71c3b66ff570bfce78952f2314e", + "sha256:6b984510ed94993708c0d697b4fef2d118929bbfffc3b90037be0f5ccadf55e7", + "sha256:a005f298f64624f313a3ac618ab03f844c71d84ae4f4a4aec4b68d2a4ffe75eb", + "sha256:abc29357ee540849faf1383e1746d40d69ed5cb6d4c346df276b258f5aa8977a", + "sha256:c9ec490609752c1d81ff6290da33485aa7cb6d7365ac665b74464c1b7d97f7da", + "sha256:d5ba529d9ce668be9380563279f3ffe988f27bc5b299c5a28453df2e0b0fbaf2", + "sha256:e2b1a7d093f2e76dc694c17c0c285e846d0b0deb0e8b21dc852ba1a3a4e2f1d6" + ], + "version": "==0.21.0" + }, "markdown": { "hashes": [ "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874", @@ -138,7 +154,7 @@ "sha256:412520c7b6bba540c2c2067d6be3a523ab885703bf6a81d93963f848b55dfb9a", "sha256:f344d4adfba5d1de821f7850b36e3507f583468a7eb47e6fa191765ed0b9c66b" ], - "markers": "python_version >= '3.5' and python_version < '4'", + "markers": "python_version >= '3.5' and python_version < '4.0'", "version": "==2.4.3" }, "markupsafe": { @@ -204,11 +220,11 @@ }, "menagerie-docs": { "hashes": [ - "sha256:6edf3371d1b4c0ac42dc1bde72b46dbfef7d96b1065d1d605fcd07af1d6c8e9a", - "sha256:fc8da001ff050859d74c6b5cdcdf887c5aa47e2b263271ab20554010fd72337d" + "sha256:5f02204f4c8a6a3eee947ee4c91266159b567fd8e22d69be43531ef2e4a99f6a", + "sha256:ad69a97a65a73ad3f2be0f28638b74d1a6af68a5ce00c7b9726a9e0e89bb3d82" ], "index": "pypi", - "version": "==0.1.5" + "version": "==0.1.8" }, "mypy-extensions": { "hashes": [ @@ -222,7 +238,7 @@ "sha256:5053fc5ca7b8a281081274702ebf1584e341f40a68e6ab8f6b4b79f4b3fdf18e", "sha256:8e8226f15c0b25565aa391797963b78c95930e12efc40e905153130783e766be" ], - "markers": "python_version >= '3.8' and python_version < '4'", + "markers": "python_version >= '3.8' and python_version < '4.0'", "version": "==0.1.0" }, "packaging": { @@ -424,6 +440,14 @@ ], "version": "==1.2.0" }, + "six": { + "hashes": [ + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.16.0" + }, "soupsieve": { "hashes": [ "sha256:3b2503d3c7084a42b1ebd08116e5f81aadfaea95863628c80a3b774a11b7c759", @@ -453,7 +477,7 @@ "sha256:44ece4d53fb1706f667c9bd1c648f5469a2ec925fcf3a776667042d645472c14", "sha256:aabaf16477806a5e1dd19aa41f8c2b7950dd3c746362d7e3223dbe6de6ac448e" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4.0'", "version": "==1.26.9" }, "xmlschema": { diff --git a/docs/config.json b/docs/config.json index c96a2dd3..f82b0aae 100644 --- a/docs/config.json +++ b/docs/config.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/Bwc9876/menagerie/master/menagerie/schemas/config_schema.json", - "cache_enabled": true, + "cache_enabled": false, "base_url": "https://nh.outerwildsmods.com/", "themes": { "bootstrap": "https://bootswatch.com/5/darkly/bootstrap.min.css", @@ -8,8 +8,7 @@ "theme": "dark" }, "styles": { - "base": "styles/base.css", - "schema": "styles/schema.css" + "base": "styles/nh_base.css" }, "search": { "enabled": true, diff --git a/docs/content/pages/home.md b/docs/content/pages/home.md index f6b13c0f..c03f69b7 100644 --- a/docs/content/pages/home.md +++ b/docs/content/pages/home.md @@ -145,3 +145,13 @@ These tools/references are highly recommended - [XML Basics Tutorial](https://www.w3schools.com/xml/xml_whatis.asp){ target="_blank" } - [JSON Basics Tutorial](https://www.tutorialspoint.com/json/index.htm){ target="_blank" } - [The Examples Mod](https://github.com/xen-42/ow-new-horizons-examples){ target="_blank" } + +## Disclaimer + +This work is unofficial fan content created under permission from the [Mobius Digital Fan Content Policy](https://www.mobiusdigitalgames.com/fan-content-policy.html). It includes materials which are the property of Mobius Digital, and it is neither approved nor endorsed by Mobius Digital. + +We are not responsible for any mods created using the New Horizons modding framework and assume no responsibility in the event an addon violates the terms. + +## License + +The license for this project is available [on the GitHub repository](https://github.com/xen-42/outer-wilds-new-horizons/blob/main/LICENSE). \ No newline at end of file diff --git a/docs/content/static/scripts/schema.js b/docs/content/static/scripts/schema.js deleted file mode 100644 index 9ff63884..00000000 --- a/docs/content/static/scripts/schema.js +++ /dev/null @@ -1,55 +0,0 @@ -$(document).on('click', 'a[href^="#"]', function (event) { - if (this.href.split("#")[1] === "top") return; - event.preventDefault(); - history.pushState({}, '', this.href); -}); - -function flashElement(elementId) { - myElement = document.getElementById(elementId).parentNode; - myElement.classList.add("jsfh-animated-property"); - setTimeout(function () { - myElement.classList.remove("jsfh-animated-property"); - }, 1000); -} - -function setAnchor(anchorLinkDestination) { - history.pushState({}, '', anchorLinkDestination); -} - -function anchorOnLoad() { - let linkTarget = window.location.hash.split("?")[0].split("&")[0]; - if (linkTarget[0] === "#") { - let idTarget = linkTarget.substring(1); - if (idTarget !== "top") { - anchorLink(idTarget); - } - } -} - -function anchorLink(linkTarget) { - const target = $("#" + linkTarget); - target.parents().addBack().filter(".collapse:not(.show), .tab-pane, [role='tab']").each( - function (index) { - if ($(this).hasClass("collapse")) { - $(this).collapse("show"); - } else if ($(this).hasClass("tab-pane")) { - const tabToShow = $("a[href='#" + $(this).attr("id") + "']"); - if (tabToShow) { - tabToShow.tab("show"); - } - } else if ($(this).attr("role") === "tab") { - $(this).tab("show"); - } - } - ); - - setTimeout(function () { - let targetElement = document.getElementById(linkTarget); - if (targetElement) { - targetElement.scrollIntoView({block: "center", behavior: "smooth"}); - setTimeout(function () { - flashElement(linkTarget); - }, 500); - } - }, 1000); -} \ No newline at end of file diff --git a/docs/content/static/styles/base.css b/docs/content/static/styles/nh_base.css similarity index 100% rename from docs/content/static/styles/base.css rename to docs/content/static/styles/nh_base.css diff --git a/docs/content/static/styles/schema.css b/docs/content/static/styles/schema.css deleted file mode 100644 index 4d958a0b..00000000 --- a/docs/content/static/styles/schema.css +++ /dev/null @@ -1,19 +0,0 @@ -.jsfh-animated-property { - animation: eclair; - animation-iteration-count: 1; - animation-fill-mode: forwards; - animation-duration: .75s; -} - -@keyframes eclair { - 0%, 100% { - transform: scale(1); - } - 50% { - transform: scale(1.03); - } -} - -.bg-warning { - color: #131313; -}