diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..ddb1bc5 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,673 @@ +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +max_line_length = 120 +tab_width = 4 +ij_continuation_indent_size = 8 +ij_formatter_off_tag = @formatter:off +ij_formatter_on_tag = @formatter:on +ij_formatter_tags_enabled = true +ij_smart_tabs = false +ij_visual_guides = none +ij_wrap_on_typing = false + +[*.java] +ij_smart_tabs = true +ij_java_align_consecutive_assignments = false +ij_java_align_consecutive_variable_declarations = false +ij_java_align_group_field_declarations = false +ij_java_align_multiline_annotation_parameters = true +ij_java_align_multiline_array_initializer_expression = false +ij_java_align_multiline_assignment = false +ij_java_align_multiline_binary_operation = false +ij_java_align_multiline_chained_methods = false +ij_java_align_multiline_deconstruction_list_components = true +ij_java_align_multiline_extends_list = true +ij_java_align_multiline_for = false +ij_java_align_multiline_method_parentheses = false +ij_java_align_multiline_parameters = true +ij_java_align_multiline_parameters_in_calls = false +ij_java_align_multiline_parenthesized_expression = false +ij_java_align_multiline_records = true +ij_java_align_multiline_resources = false +ij_java_align_multiline_ternary_operation = false +ij_java_align_multiline_text_blocks = false +ij_java_align_multiline_throws_list = true +ij_java_align_subsequent_simple_methods = false +ij_java_align_throws_keyword = false +ij_java_align_types_in_multi_catch = true +ij_java_annotation_parameter_wrap = on_every_item +ij_java_array_initializer_new_line_after_left_brace = false +ij_java_array_initializer_right_brace_on_new_line = false +ij_java_array_initializer_wrap = normal +ij_java_assert_statement_colon_on_next_line = true +ij_java_assert_statement_wrap = off +ij_java_assignment_wrap = off +ij_java_binary_operation_sign_on_next_line = false +ij_java_binary_operation_wrap = normal +ij_java_blank_lines_after_anonymous_class_header = 1 +ij_java_blank_lines_after_class_header = 1 +ij_java_blank_lines_after_imports = 1 +ij_java_blank_lines_after_package = 1 +ij_java_blank_lines_around_class = 1 +ij_java_blank_lines_around_field = 0 +ij_java_blank_lines_around_field_in_interface = 0 +ij_java_blank_lines_around_initializer = 1 +ij_java_blank_lines_around_method = 1 +ij_java_blank_lines_around_method_in_interface = 1 +ij_java_blank_lines_before_class_end = 0 +ij_java_blank_lines_before_imports = 1 +ij_java_blank_lines_before_method_body = 0 +ij_java_blank_lines_before_package = 1 +ij_java_block_brace_style = end_of_line +ij_java_block_comment_add_space = false +ij_java_block_comment_at_first_column = true +ij_java_builder_methods = none +ij_java_call_parameters_new_line_after_left_paren = false +ij_java_call_parameters_right_paren_on_new_line = false +ij_java_call_parameters_wrap = normal +ij_java_case_statement_on_separate_line = true +ij_java_catch_on_new_line = false +ij_java_class_annotation_wrap = split_into_lines +ij_java_class_brace_style = end_of_line +ij_java_class_count_to_use_import_on_demand = 999 +ij_java_class_names_in_javadoc = 1 +ij_java_deconstruction_list_wrap = normal +ij_java_do_not_indent_top_level_class_members = false +ij_java_do_not_wrap_after_single_annotation = false +ij_java_do_not_wrap_after_single_annotation_in_parameter = false +ij_java_do_while_brace_force = never +ij_java_doc_add_blank_line_after_description = true +ij_java_doc_add_blank_line_after_param_comments = false +ij_java_doc_add_blank_line_after_return = false +ij_java_doc_add_p_tag_on_empty_lines = false +ij_java_doc_align_exception_comments = true +ij_java_doc_align_param_comments = true +ij_java_doc_do_not_wrap_if_one_line = true +ij_java_doc_enable_formatting = true +ij_java_doc_enable_leading_asterisks = true +ij_java_doc_indent_on_continuation = false +ij_java_doc_keep_empty_lines = true +ij_java_doc_keep_empty_parameter_tag = true +ij_java_doc_keep_empty_return_tag = true +ij_java_doc_keep_empty_throws_tag = true +ij_java_doc_keep_invalid_tags = true +ij_java_doc_param_description_on_new_line = false +ij_java_doc_preserve_line_breaks = false +ij_java_doc_use_throws_not_exception_tag = true +ij_java_else_on_new_line = false +ij_java_enum_constants_wrap = split_into_lines +ij_java_extends_keyword_wrap = normal +ij_java_extends_list_wrap = normal +ij_java_field_annotation_wrap = split_into_lines +ij_java_finally_on_new_line = false +ij_java_for_brace_force = never +ij_java_for_statement_new_line_after_left_paren = false +ij_java_for_statement_right_paren_on_new_line = false +ij_java_for_statement_wrap = off +ij_java_generate_final_locals = false +ij_java_generate_final_parameters = false +ij_java_if_brace_force = never +ij_java_imports_layout = gregtech.**,|,net.**,|,codechickenlib.**,|,*,|,javax.**,java.**,|,$* +ij_java_indent_case_from_switch = true +ij_java_insert_inner_class_imports = false +ij_java_insert_override_annotation = true +ij_java_keep_blank_lines_before_right_brace = 1 +ij_java_keep_blank_lines_between_package_declaration_and_header = 1 +ij_java_keep_blank_lines_in_code = 1 +ij_java_keep_blank_lines_in_declarations = 1 +ij_java_keep_builder_methods_indents = false +ij_java_keep_control_statement_in_one_line = true +ij_java_keep_first_column_comment = false +ij_java_keep_indents_on_empty_lines = false +ij_java_keep_line_breaks = true +ij_java_keep_multiple_expressions_in_one_line = false +ij_java_keep_simple_blocks_in_one_line = true +ij_java_keep_simple_classes_in_one_line = true +ij_java_keep_simple_lambdas_in_one_line = true +ij_java_keep_simple_methods_in_one_line = true +ij_java_label_indent_absolute = false +ij_java_label_indent_size = 0 +ij_java_lambda_brace_style = end_of_line +ij_java_layout_static_imports_separately = true +ij_java_line_comment_add_space = false +ij_java_line_comment_add_space_on_reformat = false +ij_java_line_comment_at_first_column = true +ij_java_method_annotation_wrap = split_into_lines +ij_java_method_brace_style = end_of_line +ij_java_method_call_chain_wrap = normal +ij_java_method_parameters_new_line_after_left_paren = false +ij_java_method_parameters_right_paren_on_new_line = false +ij_java_method_parameters_wrap = normal +ij_java_modifier_list_wrap = false +ij_java_multi_catch_types_wrap = normal +ij_java_names_count_to_use_import_on_demand = 3 +ij_java_new_line_after_lparen_in_annotation = false +ij_java_new_line_after_lparen_in_deconstruction_pattern = true +ij_java_new_line_after_lparen_in_record_header = false +ij_java_packages_to_use_import_on_demand = java.awt.*,javax.swing.* +ij_java_parameter_annotation_wrap = off +ij_java_parentheses_expression_new_line_after_left_paren = false +ij_java_parentheses_expression_right_paren_on_new_line = false +ij_java_place_assignment_sign_on_next_line = false +ij_java_prefer_longer_names = true +ij_java_prefer_parameters_wrap = false +ij_java_record_components_wrap = normal +ij_java_repeat_synchronized = true +ij_java_replace_instanceof_and_cast = false +ij_java_replace_null_check = true +ij_java_replace_sum_lambda_with_method_ref = true +ij_java_resource_list_new_line_after_left_paren = false +ij_java_resource_list_right_paren_on_new_line = false +ij_java_resource_list_wrap = on_every_item +ij_java_rparen_on_new_line_in_annotation = false +ij_java_rparen_on_new_line_in_deconstruction_pattern = true +ij_java_rparen_on_new_line_in_record_header = false +ij_java_space_after_closing_angle_bracket_in_type_argument = false +ij_java_space_after_colon = true +ij_java_space_after_comma = true +ij_java_space_after_comma_in_type_arguments = true +ij_java_space_after_for_semicolon = true +ij_java_space_after_quest = true +ij_java_space_after_type_cast = true +ij_java_space_before_annotation_array_initializer_left_brace = false +ij_java_space_before_annotation_parameter_list = false +ij_java_space_before_array_initializer_left_brace = true +ij_java_space_before_catch_keyword = true +ij_java_space_before_catch_left_brace = true +ij_java_space_before_catch_parentheses = true +ij_java_space_before_class_left_brace = true +ij_java_space_before_colon = true +ij_java_space_before_colon_in_foreach = true +ij_java_space_before_comma = false +ij_java_space_before_deconstruction_list = false +ij_java_space_before_do_left_brace = true +ij_java_space_before_else_keyword = true +ij_java_space_before_else_left_brace = true +ij_java_space_before_finally_keyword = true +ij_java_space_before_finally_left_brace = true +ij_java_space_before_for_left_brace = true +ij_java_space_before_for_parentheses = true +ij_java_space_before_for_semicolon = false +ij_java_space_before_if_left_brace = true +ij_java_space_before_if_parentheses = true +ij_java_space_before_method_call_parentheses = false +ij_java_space_before_method_left_brace = true +ij_java_space_before_method_parentheses = false +ij_java_space_before_opening_angle_bracket_in_type_parameter = false +ij_java_space_before_quest = true +ij_java_space_before_switch_left_brace = true +ij_java_space_before_switch_parentheses = true +ij_java_space_before_synchronized_left_brace = true +ij_java_space_before_synchronized_parentheses = true +ij_java_space_before_try_left_brace = true +ij_java_space_before_try_parentheses = true +ij_java_space_before_type_parameter_list = false +ij_java_space_before_while_keyword = true +ij_java_space_before_while_left_brace = true +ij_java_space_before_while_parentheses = true +ij_java_space_inside_one_line_enum_braces = false +ij_java_space_within_empty_array_initializer_braces = false +ij_java_space_within_empty_method_call_parentheses = false +ij_java_space_within_empty_method_parentheses = false +ij_java_spaces_around_additive_operators = true +ij_java_spaces_around_annotation_eq = true +ij_java_spaces_around_assignment_operators = true +ij_java_spaces_around_bitwise_operators = true +ij_java_spaces_around_equality_operators = true +ij_java_spaces_around_lambda_arrow = true +ij_java_spaces_around_logical_operators = true +ij_java_spaces_around_method_ref_dbl_colon = false +ij_java_spaces_around_multiplicative_operators = true +ij_java_spaces_around_relational_operators = true +ij_java_spaces_around_shift_operators = true +ij_java_spaces_around_type_bounds_in_type_parameters = true +ij_java_spaces_around_unary_operator = false +ij_java_spaces_within_angle_brackets = false +ij_java_spaces_within_annotation_parentheses = false +ij_java_spaces_within_array_initializer_braces = true +ij_java_spaces_within_braces = false +ij_java_spaces_within_brackets = false +ij_java_spaces_within_cast_parentheses = false +ij_java_spaces_within_catch_parentheses = false +ij_java_spaces_within_deconstruction_list = false +ij_java_spaces_within_for_parentheses = false +ij_java_spaces_within_if_parentheses = false +ij_java_spaces_within_method_call_parentheses = false +ij_java_spaces_within_method_parentheses = false +ij_java_spaces_within_parentheses = false +ij_java_spaces_within_record_header = false +ij_java_spaces_within_switch_parentheses = false +ij_java_spaces_within_synchronized_parentheses = false +ij_java_spaces_within_try_parentheses = false +ij_java_spaces_within_while_parentheses = false +ij_java_special_else_if_treatment = true +ij_java_subclass_name_suffix = Impl +ij_java_ternary_operation_signs_on_next_line = false +ij_java_ternary_operation_wrap = normal +ij_java_test_name_suffix = Test +ij_java_throws_keyword_wrap = normal +ij_java_throws_list_wrap = normal +ij_java_use_external_annotations = false +ij_java_use_fq_class_names = false +ij_java_use_relative_indents = false +ij_java_use_single_class_imports = true +ij_java_variable_annotation_wrap = split_into_lines +ij_java_visibility = public +ij_java_while_brace_force = never +ij_java_while_on_new_line = false +ij_java_wrap_comments = true +ij_java_wrap_first_method_in_call_chain = false +ij_java_wrap_long_lines = false + +[*.nbtt] +indent_style = tab +max_line_length = 150 +ij_continuation_indent_size = 4 +ij_nbtt_keep_indents_on_empty_lines = false +ij_nbtt_space_after_colon = true +ij_nbtt_space_after_comma = true +ij_nbtt_space_before_colon = true +ij_nbtt_space_before_comma = false +ij_nbtt_spaces_within_brackets = false +ij_nbtt_spaces_within_parentheses = false + +[*.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 + +[.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,*.fxml,*.jhm,*.jnlp,*.jrxml,*.jspx,*.pom,*.rng,*.tagx,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul}] +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 + +[{*.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 + +[{*.gant,*.groovy,*.gy}] +ij_groovy_align_group_field_declarations = false +ij_groovy_align_multiline_array_initializer_expression = false +ij_groovy_align_multiline_assignment = false +ij_groovy_align_multiline_binary_operation = false +ij_groovy_align_multiline_chained_methods = false +ij_groovy_align_multiline_extends_list = false +ij_groovy_align_multiline_for = true +ij_groovy_align_multiline_list_or_map = true +ij_groovy_align_multiline_method_parentheses = false +ij_groovy_align_multiline_parameters = true +ij_groovy_align_multiline_parameters_in_calls = false +ij_groovy_align_multiline_resources = true +ij_groovy_align_multiline_ternary_operation = false +ij_groovy_align_multiline_throws_list = false +ij_groovy_align_named_args_in_map = true +ij_groovy_align_throws_keyword = false +ij_groovy_array_initializer_new_line_after_left_brace = false +ij_groovy_array_initializer_right_brace_on_new_line = false +ij_groovy_array_initializer_wrap = off +ij_groovy_assert_statement_wrap = off +ij_groovy_assignment_wrap = off +ij_groovy_binary_operation_wrap = off +ij_groovy_blank_lines_after_class_header = 0 +ij_groovy_blank_lines_after_imports = 1 +ij_groovy_blank_lines_after_package = 1 +ij_groovy_blank_lines_around_class = 1 +ij_groovy_blank_lines_around_field = 0 +ij_groovy_blank_lines_around_field_in_interface = 0 +ij_groovy_blank_lines_around_method = 1 +ij_groovy_blank_lines_around_method_in_interface = 1 +ij_groovy_blank_lines_before_imports = 1 +ij_groovy_blank_lines_before_method_body = 0 +ij_groovy_blank_lines_before_package = 0 +ij_groovy_block_brace_style = end_of_line +ij_groovy_block_comment_add_space = false +ij_groovy_block_comment_at_first_column = true +ij_groovy_call_parameters_new_line_after_left_paren = false +ij_groovy_call_parameters_right_paren_on_new_line = false +ij_groovy_call_parameters_wrap = off +ij_groovy_catch_on_new_line = false +ij_groovy_class_annotation_wrap = split_into_lines +ij_groovy_class_brace_style = end_of_line +ij_groovy_class_count_to_use_import_on_demand = 5 +ij_groovy_do_while_brace_force = never +ij_groovy_else_on_new_line = false +ij_groovy_enable_groovydoc_formatting = true +ij_groovy_enum_constants_wrap = off +ij_groovy_extends_keyword_wrap = off +ij_groovy_extends_list_wrap = off +ij_groovy_field_annotation_wrap = split_into_lines +ij_groovy_finally_on_new_line = false +ij_groovy_for_brace_force = never +ij_groovy_for_statement_new_line_after_left_paren = false +ij_groovy_for_statement_right_paren_on_new_line = false +ij_groovy_for_statement_wrap = off +ij_groovy_ginq_general_clause_wrap_policy = 2 +ij_groovy_ginq_having_wrap_policy = 1 +ij_groovy_ginq_indent_having_clause = true +ij_groovy_ginq_indent_on_clause = true +ij_groovy_ginq_on_wrap_policy = 1 +ij_groovy_ginq_space_after_keyword = true +ij_groovy_if_brace_force = never +ij_groovy_import_annotation_wrap = 2 +ij_groovy_imports_layout = *,|,javax.**,java.**,|,$* +ij_groovy_indent_case_from_switch = true +ij_groovy_indent_label_blocks = true +ij_groovy_insert_inner_class_imports = false +ij_groovy_keep_blank_lines_before_right_brace = 2 +ij_groovy_keep_blank_lines_in_code = 2 +ij_groovy_keep_blank_lines_in_declarations = 2 +ij_groovy_keep_control_statement_in_one_line = true +ij_groovy_keep_first_column_comment = true +ij_groovy_keep_indents_on_empty_lines = false +ij_groovy_keep_line_breaks = true +ij_groovy_keep_multiple_expressions_in_one_line = false +ij_groovy_keep_simple_blocks_in_one_line = false +ij_groovy_keep_simple_classes_in_one_line = true +ij_groovy_keep_simple_lambdas_in_one_line = true +ij_groovy_keep_simple_methods_in_one_line = true +ij_groovy_label_indent_absolute = false +ij_groovy_label_indent_size = 0 +ij_groovy_lambda_brace_style = end_of_line +ij_groovy_layout_static_imports_separately = true +ij_groovy_line_comment_add_space = false +ij_groovy_line_comment_add_space_on_reformat = false +ij_groovy_line_comment_at_first_column = true +ij_groovy_method_annotation_wrap = split_into_lines +ij_groovy_method_brace_style = end_of_line +ij_groovy_method_call_chain_wrap = off +ij_groovy_method_parameters_new_line_after_left_paren = false +ij_groovy_method_parameters_right_paren_on_new_line = false +ij_groovy_method_parameters_wrap = off +ij_groovy_modifier_list_wrap = false +ij_groovy_names_count_to_use_import_on_demand = 3 +ij_groovy_packages_to_use_import_on_demand = java.awt.*,javax.swing.* +ij_groovy_parameter_annotation_wrap = off +ij_groovy_parentheses_expression_new_line_after_left_paren = false +ij_groovy_parentheses_expression_right_paren_on_new_line = false +ij_groovy_prefer_parameters_wrap = false +ij_groovy_resource_list_new_line_after_left_paren = false +ij_groovy_resource_list_right_paren_on_new_line = false +ij_groovy_resource_list_wrap = off +ij_groovy_space_after_assert_separator = true +ij_groovy_space_after_colon = true +ij_groovy_space_after_comma = true +ij_groovy_space_after_comma_in_type_arguments = true +ij_groovy_space_after_for_semicolon = true +ij_groovy_space_after_quest = true +ij_groovy_space_after_type_cast = true +ij_groovy_space_before_annotation_parameter_list = false +ij_groovy_space_before_array_initializer_left_brace = false +ij_groovy_space_before_assert_separator = false +ij_groovy_space_before_catch_keyword = true +ij_groovy_space_before_catch_left_brace = true +ij_groovy_space_before_catch_parentheses = true +ij_groovy_space_before_class_left_brace = true +ij_groovy_space_before_closure_left_brace = true +ij_groovy_space_before_colon = true +ij_groovy_space_before_comma = false +ij_groovy_space_before_do_left_brace = true +ij_groovy_space_before_else_keyword = true +ij_groovy_space_before_else_left_brace = true +ij_groovy_space_before_finally_keyword = true +ij_groovy_space_before_finally_left_brace = true +ij_groovy_space_before_for_left_brace = true +ij_groovy_space_before_for_parentheses = true +ij_groovy_space_before_for_semicolon = false +ij_groovy_space_before_if_left_brace = true +ij_groovy_space_before_if_parentheses = true +ij_groovy_space_before_method_call_parentheses = false +ij_groovy_space_before_method_left_brace = true +ij_groovy_space_before_method_parentheses = false +ij_groovy_space_before_quest = true +ij_groovy_space_before_record_parentheses = false +ij_groovy_space_before_switch_left_brace = true +ij_groovy_space_before_switch_parentheses = true +ij_groovy_space_before_synchronized_left_brace = true +ij_groovy_space_before_synchronized_parentheses = true +ij_groovy_space_before_try_left_brace = true +ij_groovy_space_before_try_parentheses = true +ij_groovy_space_before_while_keyword = true +ij_groovy_space_before_while_left_brace = true +ij_groovy_space_before_while_parentheses = true +ij_groovy_space_in_named_argument = true +ij_groovy_space_in_named_argument_before_colon = false +ij_groovy_space_within_empty_array_initializer_braces = false +ij_groovy_space_within_empty_method_call_parentheses = false +ij_groovy_spaces_around_additive_operators = true +ij_groovy_spaces_around_assignment_operators = true +ij_groovy_spaces_around_bitwise_operators = true +ij_groovy_spaces_around_equality_operators = true +ij_groovy_spaces_around_lambda_arrow = true +ij_groovy_spaces_around_logical_operators = true +ij_groovy_spaces_around_multiplicative_operators = true +ij_groovy_spaces_around_regex_operators = true +ij_groovy_spaces_around_relational_operators = true +ij_groovy_spaces_around_shift_operators = true +ij_groovy_spaces_within_annotation_parentheses = false +ij_groovy_spaces_within_array_initializer_braces = false +ij_groovy_spaces_within_braces = true +ij_groovy_spaces_within_brackets = false +ij_groovy_spaces_within_cast_parentheses = false +ij_groovy_spaces_within_catch_parentheses = false +ij_groovy_spaces_within_for_parentheses = false +ij_groovy_spaces_within_gstring_injection_braces = false +ij_groovy_spaces_within_if_parentheses = false +ij_groovy_spaces_within_list_or_map = false +ij_groovy_spaces_within_method_call_parentheses = false +ij_groovy_spaces_within_method_parentheses = false +ij_groovy_spaces_within_parentheses = false +ij_groovy_spaces_within_switch_parentheses = false +ij_groovy_spaces_within_synchronized_parentheses = false +ij_groovy_spaces_within_try_parentheses = false +ij_groovy_spaces_within_tuple_expression = false +ij_groovy_spaces_within_while_parentheses = false +ij_groovy_special_else_if_treatment = true +ij_groovy_ternary_operation_wrap = off +ij_groovy_throws_keyword_wrap = off +ij_groovy_throws_list_wrap = off +ij_groovy_use_flying_geese_braces = false +ij_groovy_use_fq_class_names = false +ij_groovy_use_fq_class_names_in_javadoc = true +ij_groovy_use_relative_indents = false +ij_groovy_use_single_class_imports = true +ij_groovy_variable_annotation_wrap = off +ij_groovy_while_brace_force = never +ij_groovy_while_on_new_line = false +ij_groovy_wrap_chain_calls_after_dot = false +ij_groovy_wrap_long_lines = false + +[{*.gradle.kts,*.kt,*.kts,*.main.kts}] +ij_kotlin_align_in_columns_case_branch = false +ij_kotlin_align_multiline_binary_operation = false +ij_kotlin_align_multiline_extends_list = false +ij_kotlin_align_multiline_method_parentheses = false +ij_kotlin_align_multiline_parameters = true +ij_kotlin_align_multiline_parameters_in_calls = false +ij_kotlin_allow_trailing_comma = false +ij_kotlin_allow_trailing_comma_on_call_site = false +ij_kotlin_assignment_wrap = off +ij_kotlin_blank_lines_after_class_header = 0 +ij_kotlin_blank_lines_around_block_when_branches = 0 +ij_kotlin_blank_lines_before_declaration_with_comment_or_annotation_on_separate_line = 1 +ij_kotlin_block_comment_add_space = false +ij_kotlin_block_comment_at_first_column = true +ij_kotlin_call_parameters_new_line_after_left_paren = false +ij_kotlin_call_parameters_right_paren_on_new_line = false +ij_kotlin_call_parameters_wrap = off +ij_kotlin_catch_on_new_line = false +ij_kotlin_class_annotation_wrap = split_into_lines +ij_kotlin_continuation_indent_for_chained_calls = true +ij_kotlin_continuation_indent_for_expression_bodies = true +ij_kotlin_continuation_indent_in_argument_lists = true +ij_kotlin_continuation_indent_in_elvis = true +ij_kotlin_continuation_indent_in_if_conditions = true +ij_kotlin_continuation_indent_in_parameter_lists = true +ij_kotlin_continuation_indent_in_supertype_lists = true +ij_kotlin_else_on_new_line = false +ij_kotlin_enum_constants_wrap = off +ij_kotlin_extends_list_wrap = off +ij_kotlin_field_annotation_wrap = split_into_lines +ij_kotlin_finally_on_new_line = false +ij_kotlin_if_rparen_on_new_line = false +ij_kotlin_import_nested_classes = false +ij_kotlin_imports_layout = *,java.**,javax.**,kotlin.**,^ +ij_kotlin_insert_whitespaces_in_simple_one_line_method = true +ij_kotlin_keep_blank_lines_before_right_brace = 2 +ij_kotlin_keep_blank_lines_in_code = 2 +ij_kotlin_keep_blank_lines_in_declarations = 2 +ij_kotlin_keep_first_column_comment = true +ij_kotlin_keep_indents_on_empty_lines = false +ij_kotlin_keep_line_breaks = true +ij_kotlin_lbrace_on_next_line = false +ij_kotlin_line_break_after_multiline_when_entry = true +ij_kotlin_line_comment_add_space = false +ij_kotlin_line_comment_add_space_on_reformat = false +ij_kotlin_line_comment_at_first_column = true +ij_kotlin_method_annotation_wrap = split_into_lines +ij_kotlin_method_call_chain_wrap = off +ij_kotlin_method_parameters_new_line_after_left_paren = false +ij_kotlin_method_parameters_right_paren_on_new_line = false +ij_kotlin_method_parameters_wrap = off +ij_kotlin_name_count_to_use_star_import = 5 +ij_kotlin_name_count_to_use_star_import_for_members = 3 +ij_kotlin_packages_to_use_import_on_demand = java.util.*,kotlinx.android.synthetic.**,io.ktor.** +ij_kotlin_parameter_annotation_wrap = off +ij_kotlin_space_after_comma = true +ij_kotlin_space_after_extend_colon = true +ij_kotlin_space_after_type_colon = true +ij_kotlin_space_before_catch_parentheses = true +ij_kotlin_space_before_comma = false +ij_kotlin_space_before_extend_colon = true +ij_kotlin_space_before_for_parentheses = true +ij_kotlin_space_before_if_parentheses = true +ij_kotlin_space_before_lambda_arrow = true +ij_kotlin_space_before_type_colon = false +ij_kotlin_space_before_when_parentheses = true +ij_kotlin_space_before_while_parentheses = true +ij_kotlin_spaces_around_additive_operators = true +ij_kotlin_spaces_around_assignment_operators = true +ij_kotlin_spaces_around_equality_operators = true +ij_kotlin_spaces_around_function_type_arrow = true +ij_kotlin_spaces_around_logical_operators = true +ij_kotlin_spaces_around_multiplicative_operators = true +ij_kotlin_spaces_around_range = false +ij_kotlin_spaces_around_relational_operators = true +ij_kotlin_spaces_around_unary_operator = false +ij_kotlin_spaces_around_when_arrow = true +ij_kotlin_variable_annotation_wrap = off +ij_kotlin_while_on_new_line = false +ij_kotlin_wrap_elvis_expressions = 1 +ij_kotlin_wrap_expression_body_functions = 0 +ij_kotlin_wrap_first_method_in_call_chain = false + +[{*.har,*.json,mcmod.info,pack.mcmeta}] +indent_size = 2 +ij_json_array_wrapping = split_into_lines +ij_json_keep_blank_lines_in_code = 0 +ij_json_keep_indents_on_empty_lines = false +ij_json_keep_line_breaks = true +ij_json_keep_trailing_comma = false +ij_json_object_wrapping = split_into_lines +ij_json_property_alignment = do_not_align +ij_json_space_after_colon = true +ij_json_space_after_comma = true +ij_json_space_before_colon = false +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,*.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_format_tables = 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 + +[{*.toml,Cargo.lock,Cargo.toml.orig,Gopkg.lock,Pipfile,poetry.lock}] +ij_toml_keep_indents_on_empty_lines = false + +[{*.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/actions/build_setup/action.yml b/.github/actions/build_setup/action.yml new file mode 100644 index 0000000..96573dd --- /dev/null +++ b/.github/actions/build_setup/action.yml @@ -0,0 +1,39 @@ +name: Build Setup +description: Setup for standard Java builds + +inputs: + update-cache: + description: If cache should be updated + required: false + default: 'false' + +runs: + using: 'composite' + + steps: + # RetroFuturaGradle 2.x requires a Java 25 JDK to run the Gradle daemon. + # The last listed version becomes JAVA_HOME (used by the daemon); 8 stays + # available as a compilation toolchain. Jabel runs on the Java 25 toolchain. + - name: Set up JDK 8 and 25 + uses: actions/setup-java@v5 + with: + cache: gradle + distribution: 'zulu' + java-version: | + 8 + 25 + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v6 + with: + cache-write-only: ${{ inputs.update-cache }} + gradle-home-cache-includes: | + caches + caches/retro_futura_gradle + notifications + jdks + wrapper + + - name: Grant execute permission for gradlew + shell: bash + run: chmod +x gradlew diff --git a/.github/workflows/build-packages.yml b/.github/workflows/build-packages.yml index 4afc1b2..8dcddf4 100644 --- a/.github/workflows/build-packages.yml +++ b/.github/workflows/build-packages.yml @@ -8,16 +8,27 @@ on: jobs: zip-and-release-packages: runs-on: ubuntu-latest + + permissions: + contents: write + steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Set release version run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - - name: Prepare release folder + - name: Point Blowdryer at the released tag + if: startsWith(github.ref, 'refs/tags/') run: | - mkdir packages + # Bump the spotless source tag so the packaged settings.gradle pulls + # the Blowdryer config matching this release (keeps existing owner/repo). + sed -i -E "s#(github '[^']+', 'tag', ')[^']*(')#\1${RELEASE_VERSION}\2#" settings.gradle + grep -n "', 'tag', '" settings.gradle + + - name: Prepare release folder + run: mkdir packages - name: Zip starter uses: montudor/action-zip@v1 @@ -26,10 +37,11 @@ jobs: zip -r packages/starter.zip . \ \ -x "*.git/*" \ - -x ".github/*" \ - -x "spotless/*" \ + -x ".github/workflows/build-packages.yml" \ + -x ".github/workflows/buildscript-maintenance.yml" \ -x "docs/*" \ \ + -x "spotless.importorder" \ -x "CODEOWNERS" \ -x "LICENSE" \ -x "README.md" \ @@ -45,11 +57,12 @@ jobs: zip -r packages/migration.zip . \ \ -x "*.git/*" \ - -x ".github/*" \ - -x "spotless/*" \ + -x ".github/workflows/build-packages.yml" \ + -x ".github/workflows/buildscript-maintenance.yml" \ -x "docs/*" \ -x "src/*" \ \ + -x "spotless.importorder" \ -x "CODEOWNERS" \ -x "LICENSE" \ -x "README.md" \ diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml new file mode 100644 index 0000000..bf9744e --- /dev/null +++ b/.github/workflows/build_and_test.yml @@ -0,0 +1,97 @@ +# Build and test the mod +name: Build and test + +on: + workflow_dispatch: + inputs: + target_branch: + description: 'Target branch to build' + required: false + type: string + timeout: + description: 'Timeout for runServer (seconds)' + required: false + default: 90 + type: number + client-only: + description: 'Do not execute runServer' + required: false + default: false + type: boolean + +concurrency: + group: build-and-test-${{ inputs.target_branch || github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + build-and-test: + runs-on: ubuntu-latest + + permissions: + contents: write + pull-requests: write + + steps: + - name: Checkout Repository + uses: actions/checkout@v6 + with: + ref: ${{ inputs.target_branch || github.ref }} + + - name: Apply patch to buildscript.properties + run: sed -i 's/debug_all = false/debug_all = true/g' buildscript.properties + + - name: Setup Build + uses: ./.github/actions/build_setup + + - name: Compile the mod + run: ./gradlew --info --scan --stacktrace assemble + + - name: Upload Jars + uses: actions/upload-artifact@v7 + with: + name: plz_edit + path: build/libs/*.jar + retention-days: 31 + + - name: Run post-build checks + id: build_mod + run: ./gradlew --info build + + - name: Attempt to make a PR fixing spotless errors + if: ${{ failure() && steps.build_mod.conclusion == 'failure' && github.event_name == 'pull_request' && !github.event.pull_request.draft }} + run: | + git reset --hard + git checkout "${github.ref_name}" + ./gradlew --info spotlessApply || exit 1 + git diff --exit-code && exit 1 + git config user.name "GitHub Actions" + git config user.email "<>" + git switch -c "${FIXED_BRANCH}" + git commit -am "spotlessApply" + git push --force-with-lease origin "${FIXED_BRANCH}" + gh pr create \ + --head "${FIXED_BRANCH}" \ + --base "${github.ref_name}" \ + --title "Spotless apply for branch ${{ github.event.pull_request.head.ref }} for #${{ github.event.pull_request.number }}" \ + --body "Automatic spotless apply to fix formatting errors, applies to PR #${{ github.event.pull_request.number }}" \ + 2>&1 | tee pr-message.log || true + gh pr comment "${github.ref_name}" -F pr-message.log || true + shell: bash # ensures set -eo pipefail + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + FIXED_BRANCH: ${{ github.head_ref }}-spotless-fixes + + - name: Run server for ${{ inputs.timeout }} seconds + if: ${{ !inputs.client-only }} + run: | + mkdir -p run + echo "eula=true" > run/eula.txt + # Set a constant seed with a village at spawn + echo "stop" > run/stop.txt + timeout ${{ inputs.timeout }} ./gradlew runServer 2>&1 < run/stop.txt | tee -a server.log || true + + - name: Test no errors reported during server run + if: ${{ !inputs.client-only }} + run: | + chmod +x ./scripts/test_no_error_reports.sh + ./scripts/test_no_error_reports.sh diff --git a/.github/workflows/buildscript-maintenance.yml b/.github/workflows/buildscript-maintenance.yml index 0deeea7..028e36f 100644 --- a/.github/workflows/buildscript-maintenance.yml +++ b/.github/workflows/buildscript-maintenance.yml @@ -1,5 +1,3 @@ -# This workflow only meant for the source mod you shouldn't bring it into your own project - name: Buildscript maintenance on: @@ -13,29 +11,28 @@ on: jobs: buildscript-maintenance: runs-on: ubuntu-latest - # Avoid running this workflow on forks - if: github.repository == 'GregTechCEu/Buildscripts' + if: github.repository == 'GTModpackTeam/Buildscripts' permissions: contents: write pull-requests: write steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Ensure build script version is up to date id: update-buildscript run: | new_version="$(date +%s)" sed --in-place "1s!^//version:.*!//version: $new_version!g" build.gradle - echo "::set-output name=new_version::$new_version" + echo "new_version=$new_version" >> "$GITHUB_OUTPUT" - name: Create Pull Request id: create-pull-request - uses: peter-evans/create-pull-request@v6 + uses: peter-evans/create-pull-request@v8 env: - GITHUB_TOKEN: ${{ secrets.BUILDSCRIPT_MAINTENANCE_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - token: ${{ secrets.BUILDSCRIPT_MAINTENANCE_TOKEN }} + token: ${{ secrets.GITHUB_TOKEN }} committer: GitHub author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> add-paths: build.gradle @@ -43,3 +40,4 @@ jobs: branch: gha-buildscript-maintenance title: Update build script version to ${{ steps.update-buildscript.outputs.new_version }} body: This pull request is created by the buildscript-maintenance workflow + labels: ignore changelog diff --git a/.github/workflows/format_java.yml b/.github/workflows/format_java.yml new file mode 100644 index 0000000..525922b --- /dev/null +++ b/.github/workflows/format_java.yml @@ -0,0 +1,75 @@ +# Runs formatting requirements +name: Java Formatting + +on: + pull_request: + paths: ['src/main/java/**', 'src/test/**'] + +concurrency: + group: format-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + formatting: + name: Formatting + runs-on: ubuntu-latest + + permissions: + pull-requests: write + contents: write + + steps: + - name: Checkout Repository + uses: actions/checkout@v6 + with: + ref: ${{ github.head_ref }} + + - name: Setup Build + uses: ./.github/actions/build_setup + + - name: Check if PR is from a fork + id: fork-check + run: | + if [ "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]; then + echo "is_fork=true" >> $GITHUB_OUTPUT + else + echo "is_fork=false" >> $GITHUB_OUTPUT + fi + shell: bash + + - name: Run Spotless Formatting Check with Gradle + id: build + run: ./gradlew --info --stacktrace spotlessCheck + + - name: Attempt to make a PR fixing spotless errors + if: failure() && steps.build.conclusion == 'failure' && steps.fork-check.outputs.is_fork == 'false' + run: | + git reset --hard + git checkout "${PR_BRANCH}" + ./gradlew --info spotlessApply || exit 1 + git diff --exit-code && exit 1 + git config user.name "GitHub Actions" + git config user.email "<>" + git switch -c "${FIXED_BRANCH}" + git commit -am "spotlessApply" + git push --force-with-lease origin "${FIXED_BRANCH}" + gh pr create \ + --head "${FIXED_BRANCH}" \ + --base "${PR_BRANCH}" \ + --title "Spotless apply for branch ${PR_BRANCH} for #${PR_NUMBER}" \ + --body "Automatic spotless apply to fix formatting errors, applies to PR #${PR_NUMBER}" \ + 2>&1 | tee pr-message.log || true + gh pr comment "${PR_BRANCH}" -F pr-message.log || true + shell: bash + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_BRANCH: ${{ github.event.pull_request.head.ref }} + PR_NUMBER: ${{ github.event.pull_request.number }} + FIXED_BRANCH: ${{ github.head_ref }}-spotless-fixes + + - name: Comment to PR if from fork and formatting failed + if: failure() && steps.build.conclusion == 'failure' && steps.fork-check.outputs.is_fork == 'true' + run: | + gh pr comment ${{ github.event.pull_request.number }} --body "I can't get automatic fixes by spotless in CI. Please run './gradlew spotlessApply' and push again." + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test_java.yml b/.github/workflows/test_java.yml new file mode 100644 index 0000000..b4799b9 --- /dev/null +++ b/.github/workflows/test_java.yml @@ -0,0 +1,29 @@ +# Runs tests +name: Java Tests + +on: + pull_request: + branches: + - '*' + +concurrency: + group: test-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + test: + name: Tests + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v6 + + - name: Apply patch to buildscript.properties + run: sed -i 's/debug_all = false/debug_all = true/g' buildscript.properties + + - name: Setup Build + uses: ./.github/actions/build_setup + + - name: Run Tests with Gradle + run: ./gradlew --info --scan --stacktrace test diff --git a/.github/workflows/update_buildscript.yml b/.github/workflows/update_buildscript.yml new file mode 100644 index 0000000..39e9e1c --- /dev/null +++ b/.github/workflows/update_buildscript.yml @@ -0,0 +1,55 @@ +# Checks daily to see if the buildscript is in need of an update +name: Update Buildscript + +on: + workflow_dispatch: + schedule: + - cron: '0 0 * * *' # "min hr day month year", so run once per day + +jobs: + buildscript-update: + runs-on: ubuntu-latest + + # Avoid running this workflow on forks + if: github.repository == 'GTModpackTeam/Buildscripts' + + permissions: + contents: write + pull-requests: write + + steps: + - name: Checkout Repository + uses: actions/checkout@v6 + + - name: Setup Build + uses: ./.github/actions/build_setup + + - name: Run Buildscript Updater + run: ./gradlew --info --stacktrace updateBuildScript + + - name: Get New Buildscript Version + id: version-check + run: | + new_version=$(head -1 build.gradle | sed -r 's|//version: (.*)|\1|g') + echo "NEW_VERSION=$new_version" >> "$GITHUB_OUTPUT" + + - name: Create Pull Request + id: create-pull-request + uses: peter-evans/create-pull-request@v8 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + token: ${{ secrets.GITHUB_TOKEN }} + committer: GitHub + author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> + commit-message: 'update build script version to ${{ steps.version-check.outputs.NEW_VERSION }}' + branch: gha-update-buildscript + title: Update build script version to ${{ steps.version-check.outputs.NEW_VERSION }} + body: This pull request is created by the buildscript-update workflow + labels: ignore changelog + +# - name: Enable Pull-Request Auto-Merge +# if: steps.create-pull-request.outputs.pull-request-operation == 'created' +# run: gh pr merge --squash --auto "${{ steps.create-pull-request.outputs.pull-request-number }}" +# env: +# GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/update_gradle_cache.yml b/.github/workflows/update_gradle_cache.yml new file mode 100644 index 0000000..0c56214 --- /dev/null +++ b/.github/workflows/update_gradle_cache.yml @@ -0,0 +1,30 @@ +# Updates the Gradle Cache when necessary +name: Update Gradle Cache + +on: + push: + branches: + - master + paths: ['gradle/**', '**.gradle', 'gradle.properties', 'gradlew**', 'src/main/resources/*_at.cfg'] + workflow_dispatch: + +concurrency: + group: gradle-cache-${{ github.ref }} + cancel-in-progress: true + +jobs: + update-cache: + name: Update Gradle Cache + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v6 + + - name: Setup Build + uses: ./.github/actions/build_setup + with: + update-cache: true + + - name: Build Project with Gradle + run: ./gradlew --info --stacktrace assemble diff --git a/.github/workflows/validate_gradle_wrapper.yml b/.github/workflows/validate_gradle_wrapper.yml deleted file mode 100644 index c45f52c..0000000 --- a/.github/workflows/validate_gradle_wrapper.yml +++ /dev/null @@ -1,29 +0,0 @@ -# Validates the integrity of the Gradle Wrapper -name: Validate Gradle Wrapper - -on: - push: - branches: - - master - paths: - - 'gradle/**' - pull_request: - branches: - - '*' - paths: - - 'gradle/**' - -concurrency: - group: gradle-wrapper-validation-${{ github.head_ref || github.ref }} - cancel-in-progress: true - -jobs: - Validation: - runs-on: ubuntu-latest - - steps: - - name: Checkout Repository - uses: actions/checkout@v4 - - - name: Validate Gradle Wrapper - uses: gradle/actions/wrapper-validation@v3 diff --git a/CODEOWNERS b/CODEOWNERS deleted file mode 100644 index b27cf33..0000000 --- a/CODEOWNERS +++ /dev/null @@ -1,4 +0,0 @@ -* @GregTechCEu/gregtech-build-team - -CODEOWNERS @GregTechCEu/admin -LICENSE @GregTechCEu/admin diff --git a/build.gradle b/build.gradle index 892add0..c244008 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,4 @@ -//version: 1723428048 +//version: 1762213476 /* * DO NOT CHANGE THIS FILE! * Also, you may replace this file at any time if there is an update available. @@ -7,24 +7,14 @@ */ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -import com.gtnewhorizons.retrofuturagradle.MinecraftExtension -import com.gtnewhorizons.retrofuturagradle.mcp.MCPTasks -import com.gtnewhorizons.retrofuturagradle.minecraft.MinecraftTasks import com.gtnewhorizons.retrofuturagradle.mcp.ReobfuscatedJar -import com.gtnewhorizons.retrofuturagradle.minecraft.RunMinecraftTask -import com.gtnewhorizons.retrofuturagradle.util.Distribution import com.modrinth.minotaur.dependencies.ModDependency import com.modrinth.minotaur.dependencies.VersionDependency -import de.undercouch.gradle.tasks.download.DownloadExtension -import org.apache.commons.io.FileUtils -import org.gradle.api.internal.artifacts.configurations.DefaultUnlockedConfiguration import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent import org.gradle.internal.logging.text.StyledTextOutputFactory import org.jetbrains.gradle.ext.Gradle -import javax.inject.Inject - import static org.gradle.internal.logging.text.StyledTextOutput.Style plugins { @@ -33,23 +23,24 @@ plugins { id 'base' id 'eclipse' id 'maven-publish' - id 'org.jetbrains.gradle.plugin.idea-ext' version '1.1.8' - id 'com.gtnewhorizons.retrofuturagradle' version '1.4.0' - id 'net.darkhax.curseforgegradle' version '1.1.24' apply false + id 'org.jetbrains.gradle.plugin.idea-ext' version '1.1.9' + id 'com.gtnewhorizons.retrofuturagradle' version '2.0.2' + id 'net.darkhax.curseforgegradle' version '1.1.25' apply false id 'com.modrinth.minotaur' version '2.8.7' apply false id 'com.diffplug.spotless' version '6.13.0' apply false id 'com.palantir.git-version' version '3.0.0' apply false - id 'com.github.johnrengelman.shadow' version '8.1.1' apply false + id 'com.gradleup.shadow' version '8.3.5' apply false id 'org.jetbrains.kotlin.jvm' version '1.8.0' apply false id 'org.jetbrains.kotlin.kapt' version '1.8.0' apply false id 'com.google.devtools.ksp' version '1.8.0-1.0.9' apply false - id 'de.undercouch.download' version '5.6.0' apply false } def out = services.get(StyledTextOutputFactory).create('an-output') // Project properties +loadProjectProperties() + // Required properties: we don't know how to handle these being missing gracefully checkPropertyExists("modName") @@ -70,7 +61,6 @@ propertyDefaultIfUnset("autoUpdateBuildScript", false) propertyDefaultIfUnset("modArchivesBaseName", project.modId) propertyDefaultIfUnsetWithEnvVar("developmentEnvironmentUserName", "Developer", "DEV_USERNAME") propertyDefaultIfUnset("additionalJavaArguments", "") -propertyDefaultIfUnset("enableJava17RunTasks", false) propertyDefaultIfUnset("generateGradleTokenClass", "") propertyDefaultIfUnset("gradleTokenModId", "") propertyDefaultIfUnset("gradleTokenModName", "") @@ -80,6 +70,7 @@ propertyDefaultIfUnset("includeWellKnownRepositories", true) propertyDefaultIfUnset("includeCommonDevEnvMods", true) propertyDefaultIfUnset("stripForgeRequirements", false) propertyDefaultIfUnset("noPublishedSources", false) +propertyDefaultIfUnset("mixinProviderSpec", "zone.rong:mixinbooter:10.7") propertyDefaultIfUnset("forceEnableMixins", false) propertyDefaultIfUnset("mixinConfigRefmap", "mixins.${project.modId}.refmap.json") propertyDefaultIfUnsetWithEnvVar("enableCoreModDebug", false, "CORE_MOD_DEBUG") @@ -100,6 +91,8 @@ propertyDefaultIfUnset("mavenArtifactGroup", getDefaultArtifactGroup()) propertyDefaultIfUnset("enableModernJavaSyntax", false) propertyDefaultIfUnset("enableSpotless", false) propertyDefaultIfUnset("enableJUnit", false) +propertyDefaultIfUnset("buildscriptRepositoryOwner", "GTModpackTeam") +propertyDefaultIfUnset("buildscriptRepositoryName", "Buildscripts") propertyDefaultIfUnsetWithEnvVar("deploymentDebug", false, "DEPLOYMENT_DEBUG") @@ -271,7 +264,7 @@ if (project.file('.git/HEAD').isFile() || project.file('.git').isFile()) { // Shadowing if (usesShadowedDependencies.toBoolean()) { - apply plugin: 'com.github.johnrengelman.shadow' + apply plugin: 'com.gradleup.shadow' } @@ -280,7 +273,7 @@ if (usesShadowedDependencies.toBoolean()) { java { toolchain { if (enableModernJavaSyntax.toBoolean()) { - languageVersion.set(JavaLanguageVersion.of(17)) + languageVersion.set(JavaLanguageVersion.of(25)) } else { languageVersion.set(JavaLanguageVersion.of(8)) } @@ -300,11 +293,15 @@ tasks.withType(JavaCompile).configureEach { return } - sourceCompatibility = 17 + sourceCompatibility = 25 options.release.set(8) + // Jabel relies on Byte Buddy, which does not officially support Java 25 yet. + // Enable its experimental mode so the javac plugin can load under a Java 25 toolchain. + options.forkOptions.jvmArgs.add('-Dnet.bytebuddy.experimental=true') + javaCompiler.set(javaToolchains.compilerFor { - languageVersion.set(JavaLanguageVersion.of(17)) + languageVersion.set(JavaLanguageVersion.of(25)) vendor.set(JvmVendorSpec.AZUL) }) } @@ -315,14 +312,6 @@ tasks.withType(ScalaCompile).configureEach { } -// Allow others using this buildscript to have custom gradle code run -if (getFile('addon.gradle').exists()) { - apply from: 'addon.gradle' -} else if (getFile('addon.gradle.kts').exists()) { - apply from: 'addon.gradle.kts' -} - - // Configure Minecraft // Try to gather mod version from git tags if version is not manually specified @@ -369,11 +358,14 @@ minecraft { // JVM arguments extraRunJvmArguments.add("-ea:${modGroup}") + + // enable JLine Terminal since idea_rt.jar is no longer added to the classpath + extraRunJvmArguments.add('-Dterminal.jline=true') if (usesMixins.toBoolean()) { extraRunJvmArguments.addAll([ - '-Dmixin.hotSwap=true', - '-Dmixin.checks.interfaces=true', - '-Dmixin.debug.export=true' + '-Dmixin.hotSwap=true', + '-Dmixin.checks.interfaces=true', + '-Dmixin.debug.export=true' ]) } @@ -388,10 +380,6 @@ minecraft { if (additionalJavaArguments.size() != 0) { extraRunJvmArguments.addAll(additionalJavaArguments.split(';')) } - - if (enableJava17RunTasks.toBoolean()) { - lwjgl3Version = "3.3.2" - } } if (coreModClass) { @@ -458,28 +446,32 @@ repositories { } } maven { - name 'Cleanroom Maven' - url 'https://maven.cleanroommc.com' + name = 'Cleanroom Maven' + url = 'https://maven.cleanroommc.com' + } + maven { + name = 'BlameJared Maven' + url = 'https://maven.blamejared.com' } maven { - name 'BlameJared Maven' - url 'https://maven.blamejared.com' + name = 'GTNH Maven' + url = 'https://nexus.gtnewhorizons.com/repository/public/' } maven { - name 'GTNH Maven' - url 'https://nexus.gtnewhorizons.com/repository/public/' + name = 'GTCEu Maven' + url = 'https://maven.gtceu.com' } maven { - name 'GTCEu Maven' - url 'https://maven.gtceu.com' + name = 'Mod Maven' + url = 'https://modmaven.dev' } } if (usesMixins.toBoolean() || forceEnableMixins.toBoolean()) { // need to add this here even if we did not above if (!includeWellKnownRepositories.toBoolean()) { maven { - name 'Cleanroom Maven' - url 'https://maven.cleanroommc.com' + name = 'Cleanroom Maven' + url = 'https://maven.cleanroommc.com' } } } @@ -518,7 +510,6 @@ configurations { testRuntimeClasspath.extendsFrom(runtimeOnlyNonPublishable) } -String mixinProviderSpec = 'zone.rong:mixinbooter:9.1' dependencies { if (usesMixins.toBoolean()) { annotationProcessor 'org.ow2.asm:asm-debug-all:5.2' @@ -541,7 +532,7 @@ dependencies { if (enableJUnit.toBoolean()) { testImplementation 'org.hamcrest:hamcrest:2.2' - testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2' + testImplementation 'org.junit.jupiter:junit-jupiter:5.11.4' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } @@ -551,7 +542,7 @@ dependencies { transitive = false } // workaround for https://github.com/bsideup/jabel/issues/174 - annotationProcessor 'net.java.dev.jna:jna-platform:5.13.0' + annotationProcessor 'net.java.dev.jna:jna-platform:5.16.0' // Allow jdk.unsupported classes like sun.misc.Unsafe, workaround for JDK-8206937 and fixes Forge crashes in tests. patchedMinecraft 'me.eigenraven.java8unsupported:java-8-unsupported-shim:1.0.0' @@ -563,9 +554,9 @@ dependencies { testCompileOnly "me.eigenraven.java8unsupported:java-8-unsupported-shim:1.0.0" } - compileOnlyApi 'org.jetbrains:annotations:24.1.0' - annotationProcessor 'org.jetbrains:annotations:24.1.0' - patchedMinecraft('net.minecraft:launchwrapper:1.17.2') { + compileOnlyApi 'org.jetbrains:annotations:26.0.1' + annotationProcessor 'org.jetbrains:annotations:26.0.1' + patchedMinecraft('net.minecraft:launchwrapper:1.12') { transitive = false } @@ -635,6 +626,8 @@ test { if (enableJUnit.toBoolean()) { useJUnitPlatform() } + + failOnNoDiscoveredTests = false } @@ -846,217 +839,6 @@ def getManifestAttributes() { } -// LWJGL3ify setup -if (enableJava17RunTasks.toBoolean()) { - - apply plugin: 'de.undercouch.download' - - ext.java17Toolchain = (JavaToolchainSpec spec) -> { - spec.languageVersion.set(JavaLanguageVersion.of(17)) - spec.vendor.set(JvmVendorSpec.matching("jetbrains")) - } - ext.java21Toolchain = (JavaToolchainSpec spec) -> { - spec.languageVersion.set(JavaLanguageVersion.of(21)) - spec.vendor.set(JvmVendorSpec.matching("jetbrains")) - } - - ext.java17DependenciesCfg = (DefaultUnlockedConfiguration) configurations.create("java17Dependencies") { - extendsFrom(configurations.getByName("runtimeClasspath")) // Ensure consistent transitive dependency resolution - canBeConsumed = false - } - ext.java17PatchDependenciesCfg = (DefaultUnlockedConfiguration) configurations.create("java17PatchDependencies") { - canBeConsumed = false - } - - dependencies { - if (modId != 'lwjgl3ify') { - java17Dependencies("io.github.twilightflower:lwjgl3ify:1.0.0") - } - java17PatchDependencies("io.github.twilightflower:lwjgl3ify:1.0.0:forgePatches") { - transitive = false - } - } - - ext.java17JvmArgs = [ - "-Dfile.encoding=UTF-8", - "-Djava.system.class.loader=com.gtnewhorizons.retrofuturabootstrap.RfbSystemClassLoader", - "-Djava.security.manager=allow", - "--add-opens", "java.base/jdk.internal.loader=ALL-UNNAMED", - "--add-opens", "java.base/java.net=ALL-UNNAMED", - "--add-opens", "java.base/java.nio=ALL-UNNAMED", - "--add-opens", "java.base/java.io=ALL-UNNAMED", - "--add-opens", "java.base/java.lang=ALL-UNNAMED", - "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", - "--add-opens", "java.base/java.text=ALL-UNNAMED", - "--add-opens", "java.base/java.util=ALL-UNNAMED", - "--add-opens", "java.base/jdk.internal.reflect=ALL-UNNAMED", - "--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED", - "--add-opens", "jdk.naming.dns/com.sun.jndi.dns=ALL-UNNAMED,java.naming", - "--add-opens", "java.desktop/sun.awt=ALL-UNNAMED", - "--add-opens", "java.desktop/sun.awt.image=ALL-UNNAMED", - "--add-opens", "java.desktop/com.sun.imageio.plugins.png=ALL-UNNAMED", - "--add-opens", "jdk.dynalink/jdk.dynalink.beans=ALL-UNNAMED", - "--add-opens", "java.sql.rowset/javax.sql.rowset.serial=ALL-UNNAMED" - ] - - ext.hotswapJvmArgs = [ - // DCEVM advanced hot reload - "-XX:+AllowEnhancedClassRedefinition", - "-XX:HotswapAgent=fatjar" - ] - - ext.setupHotswapAgent17 = tasks.register("setupHotswapAgent17", SetupHotswapAgentTask, t -> { - t.setTargetForToolchain(java17Toolchain) - }) - - ext.setupHotswapAgent21 = tasks.register("setupHotswapAgent21", SetupHotswapAgentTask, t -> { - t.setTargetForToolchain(java21Toolchain) - }) - - def runClient17Task = tasks.register("runClient17", RunHotswappableMinecraftTask, Distribution.CLIENT, "runClient") - runClient17Task.configure { - dependsOn(setupHotswapAgent17) - setup(project) - javaLauncher = project.javaToolchains.launcherFor(project.java17Toolchain) - } - - def runServer17Task = tasks.register("runServer17", RunHotswappableMinecraftTask, Distribution.DEDICATED_SERVER, "runServer") - runServer17Task.configure { - dependsOn(setupHotswapAgent17) - setup(project) - javaLauncher = project.javaToolchains.launcherFor(project.java17Toolchain) - } - - def runClient21Task = tasks.register("runClient21", RunHotswappableMinecraftTask, Distribution.CLIENT, "runClient") - runClient21Task.configure { - dependsOn(setupHotswapAgent21) - setup(project) - javaLauncher = project.javaToolchains.launcherFor(project.java21Toolchain) - } - - def runServer21Task = tasks.register("runServer21", RunHotswappableMinecraftTask, Distribution.DEDICATED_SERVER, "runServer") - runServer21Task.configure { - dependsOn(setupHotswapAgent21) - setup(project) - javaLauncher = project.javaToolchains.launcherFor(project.java21Toolchain) - } -} - -abstract class RunHotswappableMinecraftTask extends RunMinecraftTask { - - // IntelliJ doesn't seem to allow pre-set commandline arguments, so we also support an env variable - private boolean enableHotswap = Boolean.valueOf(System.getenv("HOTSWAP")) - - public final Distribution side - public final String superTask - - @Input - boolean getEnableHotswap() { - return enableHotswap - } - - @Option(option = "hotswap", description = "Enables HotSwapAgent for enhanced class reloading under a debugger") - boolean setEnableHotswap(boolean enable) { - enableHotswap = enable - } - - @Inject - RunHotswappableMinecraftTask(Distribution side, String superTask, org.gradle.api.invocation.Gradle gradle) { - super(side, gradle) - - this.side = side - this.superTask = superTask - setGroup("Modded Minecraft") - setDescription("Runs the modded " + side.name().toLowerCase(Locale.ROOT) + " using modern Java and lwjgl3ify") - this.getLwjglVersion().set(3) - } - - void setup(Project project) { - final MinecraftExtension minecraft = project.getExtensions().getByType(MinecraftExtension.class) - final MCPTasks mcpTasks = project.getExtensions().getByType(MCPTasks.class) - final MinecraftTasks mcTasks = project.getExtensions().getByType(MinecraftTasks.class) - - this.getExtraJvmArgs().addAll((List) project.property("java17JvmArgs")) - if (getEnableHotswap()) { - this.getExtraJvmArgs().addAll((List) project.property("hotswapJvmArgs")) - } - - this.classpath(project.property("java17PatchDependenciesCfg")) - this.classpath(mcpTasks.getTaskPackageMcLauncher()) - this.classpath(mcpTasks.getTaskPackagePatchedMc()) - this.classpath(mcpTasks.getPatchedConfiguration()) - this.classpath(project.getTasks().named("jar")) - this.classpath(project.property("java17DependenciesCfg")) - - super.setup(project) - - dependsOn( - mcpTasks.getLauncherSources().getClassesTaskName(), - mcTasks.getTaskDownloadVanillaAssets(), - mcpTasks.getTaskPackagePatchedMc(), - "jar" - ) - - getMainClass().set((side == Distribution.CLIENT) ? "GradleStart" : "GradleStartServer") - getUsername().set(minecraft.getUsername()) - getUserUUID().set(minecraft.getUserUUID()) - if (side == Distribution.DEDICATED_SERVER) { - getExtraArgs().add("nogui") - } - - systemProperty("gradlestart.bouncerClient", "com.gtnewhorizons.retrofuturabootstrap.Main") - systemProperty("gradlestart.bouncerServer", "com.gtnewhorizons.retrofuturabootstrap.Main") - - if (project.usesMixins.toBoolean()) { - this.extraJvmArgs.addAll(project.provider(() -> { - def mixinCfg = project.configurations.detachedConfiguration(project.dependencies.create(project.mixinProviderSpec)) - mixinCfg.canBeConsumed = false - mixinCfg.canBeResolved = true - mixinCfg.transitive = false - enableHotswap ? ["-javaagent:" + mixinCfg.singleFile.absolutePath] : [] - })) - } - } -} - -abstract class SetupHotswapAgentTask extends DefaultTask { - - @OutputFile - abstract RegularFileProperty getTargetFile() - - void setTargetForToolchain(Action spec) { - getTargetFile().set(project.javaToolchains.launcherFor(spec).map { - it.metadata.installationPath.file("lib/hotswap/hotswap-agent.jar") - }) - } - - @Inject - SetupHotswapAgentTask() { - setGroup("GT Buildscript") - setDescription("Installs a recent version of HotSwapAgent into the Java runtime directory") - onlyIf("Run only if not already installed", t -> !((SetupHotswapAgentTask) t).getTargetFile().getAsFile().get().exists()) - } - - @TaskAction - void installHSA() { - final String url = 'https://github.com/HotswapProjects/HotswapAgent/releases/download/1.4.2-SNAPSHOT/hotswap-agent-1.4.2-SNAPSHOT.jar' - final File target = getTargetFile().getAsFile().get() - final File parent = target.getParentFile() - FileUtils.forceMkdir(parent) - final DownloadExtension download = getProject().getExtensions().findByType(DownloadExtension.class) - download.run(ds -> { - try { - ds.src(url) - } catch (MalformedURLException e) { - throw new RuntimeException(e) - } - ds.dest(target) - ds.overwrite(false) - ds.tempAndMove(true) - }) - } -} - // IDE Configuration @@ -1082,25 +864,9 @@ idea { '2. Run Client'(Gradle) { taskNames = ['runClient'] } - if (enableJava17RunTasks.toBoolean()) { - '2a. Run Client (Java 17)'(Gradle) { - taskNames = ['runClient17'] - } - '2b. Run Client (Java 21)'(Gradle) { - taskNames = ['runClient21'] - } - } '3. Run Server'(Gradle) { taskNames = ['runServer'] } - if (enableJava17RunTasks.toBoolean()) { - '3a. Run Server (Java 17)'(Gradle) { - taskNames = ['runServer17'] - } - '3b. Run Server (Java 21)'(Gradle) { - taskNames = ['runServer21'] - } - } '4. Run Obfuscated Client'(Gradle) { taskNames = ['runObfClient'] } @@ -1391,7 +1157,7 @@ def getChangelog() { // Buildscript updating -def buildscriptGradleVersion = '8.9' +def buildscriptGradleVersion = '9.2.0' tasks.named('wrapper', Wrapper).configure { gradleVersion = buildscriptGradleVersion @@ -1422,12 +1188,12 @@ if (!project.getGradle().startParameter.isOffline() && !Boolean.getBoolean('DISA } } -static URL availableBuildScriptUrl() { - new URL("https://raw.githubusercontent.com/GregTechCEu/Buildscripts/master/build.gradle") +URL availableBuildScriptUrl() { + new URL("https://raw.githubusercontent.com/${project.buildscriptRepositoryOwner}/${project.buildscriptRepositoryName}/master/build.gradle") } -static URL availableSettingsGradleUrl() { - new URL("https://raw.githubusercontent.com/GregTechCEu/Buildscripts/master/settings.gradle") +URL availableSettingsGradleUrl() { + new URL("https://raw.githubusercontent.com/${project.buildscriptRepositoryOwner}/${project.buildscriptRepositoryName}/master/settings.gradle") } boolean performBuildScriptUpdate() { @@ -1475,14 +1241,28 @@ tasks.register('faq') { "To add new dependencies to your project, place them in 'dependencies.gradle', NOT in 'build.gradle' as they would be replaced when the script updates.\n" + "To add new repositories to your project, place them in 'repositories.gradle'.\n" + "If you need additional gradle code to run, you can place it in a file named 'addon.gradle' (or either of the above, up to you for organization).\n\n" + - "If your build fails to recognize the syntax of newer Java versions, enable Jabel in your 'gradle.properties' under the option name 'enableModernJavaSyntax'.\n" + - "To see information on how to configure your IDE properly for Java 17, see https://github.com/GregTechCEu/Buildscripts/blob/master/docs/jabel.md\n\n" + + "If your build fails to recognize the syntax of newer Java versions, enable Jabel in your 'buildscript.properties' under the option name 'enableModernJavaSyntax'.\n" + + "To see information on how to configure your IDE properly for modern Java, see https://github.com/GregTechCEu/Buildscripts/blob/master/docs/jabel.md\n\n" + "Report any issues or feature requests you have for this build script to https://github.com/GregTechCEu/Buildscripts/issues\n") } } // Helpers +def loadProjectProperties() { + def configFile = file("buildscript.properties") + if (configFile.exists()) { + configFile.withReader { + def prop = new Properties() + prop.load(it) + new ConfigSlurper().parse(prop).forEach { String k, def v -> + project.ext.setProperty(k, v) + } + } + } else { + print("Failed to read from buildscript.properties, as it did not exist!") + } +} def getDefaultArtifactGroup() { def lastIndex = project.modGroup.lastIndexOf('.') @@ -1495,7 +1275,7 @@ def getFile(String relativePath) { def checkPropertyExists(String propertyName) { if (!project.hasProperty(propertyName)) { - throw new GradleException("This project requires a property \"" + propertyName + "\"! Please add it your \"gradle.properties\". You can find all properties and their description here: https://github.com/GregTechCEu/Buildscripts/blob/main/gradle.properties") + throw new GradleException("This project requires a property \"" + propertyName + "\"! Please add it your \"buildscript.properties\" or \"gradle.properties\". You can find all properties and their description here: https://github.com/GregTechCEu/Buildscripts/blob/main/buildscript.properties and https://github.com/GregTechCEu/Buildscripts/blob/main/gradle.properties") } } @@ -1533,3 +1313,11 @@ def getLastTag() { return runShell('git describe --abbrev=0 --tags ' + (githubTag.isPresent() ? runShell('git rev-list --tags --skip=1 --max-count=1') : '')) } + + +// Allow others using this buildscript to have custom gradle code run +if (getFile('addon.gradle').exists()) { + apply from: 'addon.gradle' +} else if (getFile('addon.gradle.kts').exists()) { + apply from: 'addon.gradle.kts' +} diff --git a/buildscript.properties b/buildscript.properties new file mode 100644 index 0000000..044c597 --- /dev/null +++ b/buildscript.properties @@ -0,0 +1,197 @@ +# +# The "buildscript.properties" file contains settings loaded and used by the "build.gradle" file. +# For settings loaded in all gradle files or custom settings, use "gradle.properties" instead. +# New properties should not be created in this file, use "gradle.properties" instead. +# + +# The name of your mod. Can be any sequence of characters. +modName = TestMod + +# This is a case-sensitive string to identify your mod. +# Must be less than 64 characters and all lowercase. Convention is to only contain alphabetic characters. +modId = testmod + +# Project package location. +modGroup = com.github.gtexpert.testmod + +# Version of your mod. +# This field can be left empty if you want your mod's version to be determined by the latest git tag instead. +modVersion = 1.0.0 + +# Whether to use the old jar naming structure (modid-mcversion-version) instead of the new version (modid-version) +includeMCVersionJar = true + +# The name of your jar when you produce builds, not including any versioning info +modArchivesBaseName = testmod + +# Will update your build.gradle automatically whenever an update is available +autoUpdateBuildScript = false + +minecraftVersion = 1.12.2 + +# Select a username for testing your mod with breakpoints. You may leave this empty for a random username each time you +# restart Minecraft in development. Choose this dependent on your mod: +# Do you need consistent player progressing (for example Thaumcraft)? -> Select a name +# Do you need to test how your custom blocks interacts with a player that is not the owner? -> leave name empty +# Alternatively this can be set with the 'DEV_USERNAME' environment variable. +developmentEnvironmentUserName = Developer + +# Additional arguments applied to the JVM when launching minecraft +# Syntax: -arg1=value1;-arg2=value2;... +# Example value: -Dmixin.debug.verify=true;-XX:+UnlockExperimentalVMOptions +additionalJavaArguments = + +# Enables using modern java syntax via Jabel, while still targeting JVM 8. +# See https://github.com/bsideup/jabel for details on how this works. +# RetroFuturaGradle 2.x requires a Java 25 JDK, which is also used as the compilation toolchain. +# Byte Buddy (used by Jabel) needs '-Dnet.bytebuddy.experimental=true' (set in gradle.properties) +# to run on Java 25. The produced jar still targets Java 8 bytecode. +enableModernJavaSyntax = true + +# Generate a class with String fields for the mod id, name and version named with the fields below +generateGradleTokenClass = com.github.gtexpert.testmod.Tags +gradleTokenModId = MODID +gradleTokenModName = MODNAME +gradleTokenVersion = VERSION + +# In case your mod provides an API for other mods to implement you may declare its package here. Otherwise, you can +# leave this property empty. +# Example value: apiPackage = api + modGroup = com.myname.mymodid -> com.myname.mymodid.api +apiPackage = + +# If you want to keep your API code in src/api instead of src/main +useSrcApiPath = false + +# Specify the configuration file for Forge's access transformers here. It must be placed into /src/main/resources/ +# There can be multiple files in a comma-separated list. +# Example value: mymodid_at.cfg,jei_at.cfg +accessTransformersFile = + +# Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled! +usesMixins = false +# Mixin Provider to use. Primarily changed when needing to use a different version. +mixinProviderSpec = zone.rong:mixinbooter:10.7 +# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail! +mixinsPackage = +# Location of the mixin config refmap. If left, blank, defaults to "mixins.${modId}.refmap.json". Target file must have the "json" extension. +mixinConfigRefmap = +# Automatically generates a mixin config json if enabled, with the name mixins.modid.json +generateMixinConfig = false +# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin! +# Example value: coreModClass = asm.FMLPlugin + modGroup = com.myname.mymodid -> com.myname.mymodid.asm.FMLPlugin +coreModClass = +# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod (meaning that +# there is no class annotated with @Mod) you want this to be true. When in doubt: leave it on false! +containsMixinsAndOrCoreModOnly = false + +# Enables Mixins even if this mod doesn't use them, useful if one of the dependencies uses mixins. +forceEnableMixins = false + +# Outputs pre-transformed and post-transformed loaded classes to run/CLASSLOADER_TEMP. Can be used in combination with +# diff to see exactly what your ASM or Mixins are changing in the target file. +# Optionally can be specified with the 'CORE_MOD_DEBUG' env var. Will output a lot of files! +enableCoreModDebug = false + +# Adds CurseMaven, Modrinth Maven, BlameJared maven, and some more well-known 1.12.2 repositories +includeWellKnownRepositories = true + +# Adds JEI and TheOneProbe to your development environment. Adds them as 'implementation', meaning they will +# be available at compiletime and runtime for your mod (in-game and in-code). +# Overrides the above setting to be always true, as these repositories are needed to fetch the mods +includeCommonDevEnvMods = true + +# Some mods require a specific forge version to launch in. When you need to use one of those mods as a dependency, +# and cannot launch with the forge version required, enable this to strip the forge version requirements from that mod. +# This will add 'strip-latest-forge-requirements' as 'runtimeOnlyNonPublishable'. +# Requires useMixins or forceEnableMixins to be true, as the mod uses mixins to function. +stripForgeRequirements = false + + +# If enabled, you may use 'shadowCompile' for dependencies. They will be integrated in your jar. It is your +# responsibility check the licence and request permission for distribution, if required. +usesShadowedDependencies = false +# If disabled, won't remove unused classes from shaded dependencies. Some libraries use reflection to access +# their own classes, making the minimization unreliable. +minimizeShadowedDependencies = true +# If disabled, won't rename the shadowed classes. +relocateShadowedDependencies = true + +# Separate run directories into "run/client" for runClient task, and "run/server" for runServer task. +# Useful for debugging a server and client simultaneously. If not enabled, it will be in the standard location "run/" +separateRunDirectories = false + +# The display name format of versions published to Curse and Modrinth. $MOD_NAME and $VERSION are available variables. +# Default: $MOD_NAME \u2212 $VERSION. \u2212 is the minus character which looks much better than the hyphen minus on Curse. +versionDisplayFormat = $MOD_NAME \u2212 $VERSION + +# Publishing to modrinth requires you to set the MODRINTH_API_KEY environment variable to your current modrinth API token. + +# The project's ID on Modrinth. Can be either the slug or the ID. +# Leave this empty if you don't want to publish on Modrinth. +# Alternatively this can be set with the 'MODRINTH_PROJECT_ID' environment variable. +modrinthProjectId = + +# The project's relations on Modrinth. You can use this to refer to other projects on Modrinth. +# Syntax: scope1-type1:name1;scope2-type2:name2;... +# Where scope can be one of [required, optional, incompatible, embedded], +# type can be one of [project, version], +# and the name is the Modrinth project or version slug/id of the other mod. +# Example: required-project:jei;optional-project:top;incompatible-project:gregtech +modrinthRelations = + + +# Publishing to CurseForge requires you to set the CURSEFORGE_API_KEY environment variable to one of your CurseForge API tokens. + +# The project's numeric ID on CurseForge. You can find this in the About Project box. +# Leave this empty if you don't want to publish on CurseForge. +# Alternatively this can be set with the 'CURSEFORGE_PROJECT_ID' environment variable. +curseForgeProjectId = + +# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge. +# Syntax: type1:name1;type2:name2;... +# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible], +# and the name is the CurseForge project slug of the other mod. +# Example: requiredDependency:railcraft;embeddedLibrary:cofhlib;incompatible:buildcraft +curseForgeRelations = + +# This project's release type on CurseForge and/or Modrinth +# Alternatively this can be set with the 'RELEASE_TYPE' environment variable. +# Allowed types: release, beta, alpha +releaseType = release + +# Generate a default changelog for releases. Requires git to be installed, as it uses it to generate a changelog of +# commits since the last tagged release. +generateDefaultChangelog = false + +# Prevent the source code from being published +noPublishedSources = false + + +# Publish to a custom maven location. Follows a few rules: +# Group ID can be set with the 'ARTIFACT_GROUP_ID' environment variable, default to 'project.group' +# Artifact ID can be set with the 'ARTIFACT_ID' environment variable, default to 'project.name' +# Version can be set with the 'RELEASE_VERSION' environment variable, default to 'modVersion' +# For maven credentials: +# Username is set with the 'MAVEN_USER' environment variable, default to "NONE" +# Password is set with the 'MAVEN_PASSWORD' environment variable, default to "NONE" +customMavenPublishUrl = + +# The group for maven artifacts. Defaults to the 'project.modGroup' until the last '.' (if any). +# So 'mymod' becomes 'mymod' and 'com.myname.mymodid' 'becomes com.myname' +mavenArtifactGroup = + +# Enable spotless checks +# Enforces code formatting on your source code +# By default this will use the files found here: https://github.com/GregTechCEu/Buildscripts/tree/master/spotless +# to format your code. However, you can create your own version of these files and place them in your project's +# root directory to apply your own formatting options instead. +enableSpotless = true + +# Enable JUnit testing platform used for testing your code. +# Uses JUnit 5. See guide and documentation here: https://junit.org/junit5/docs/current/user-guide/ +enableJUnit = true + +# Deployment debug setting +# Uncomment this to test deployments to CurseForge and Modrinth +# Alternatively, you can set the 'DEPLOYMENT_DEBUG' environment variable. +deploymentDebug = false diff --git a/dependencies.gradle b/dependencies.gradle index 0de3a01..963a849 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -21,7 +21,7 @@ * * - shadowImplementation("g:n:v:c"): effectively the same as API, but the dependency is included in your jar under a renamed package name * Requires you to enable usesShadowedDependencies in gradle.properties - * For more info, see https://github.com/GregTechCEu/Buildscripts/blob/master/docs/shadow.md + * For more info, see https://github.com/GTModpackTeam/Buildscripts/blob/master/docs/shadow.md * * You can exclude transitive dependencies (dependencies of the chosen dependency) by appending { transitive = false } if needed, * but use this sparingly as it can break using your mod as another mod's dependency if you're not careful. @@ -38,5 +38,13 @@ * For more details, see https://docs.gradle.org/8.4/userguide/java_library_plugin.html#sec:java_library_configurations_graph */ dependencies { + // Published dependencies + api("codechicken:codechickenlib:3.2.3.358") // CCL 3.2.3.358 + api("com.cleanroommc:groovyscript:1.1.2") { transitive = false } // GrS 1.1.2 + api("CraftTweaker2:CraftTweaker2-MC1120-Main:1.12-4.1.20.700") // CrT 4.1.20.700 + api("curse.maven:ae2-extended-life-570458:5411078") { transitive = false } // AE2 0.56.6(IAEWrench access error) + api rfg.deobf("curse.maven:ctm-267602:2915363") // CTM 1.0.2.31 + // Hard Dependencies + devOnlyNonPublishable(rfg.deobf("curse.maven:gregtech-ce-unofficial-557242:5519022")) // CEu 2.8.10 } diff --git a/gradle.properties b/gradle.properties index a38bf26..895c4e9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,193 +1,8 @@ -modName = MyMod - -# This is a case-sensitive string to identify your mod. Convention is to use lower case. -modId = mymodid - -modGroup = com.myname.mymodid - -# Version of your mod. -# This field can be left empty if you want your mod's version to be determined by the latest git tag instead. -modVersion = 1.0.0 - -# Whether to use the old jar naming structure (modid-mcversion-version) instead of the new version (modid-version) -includeMCVersionJar = false - -# The name of your jar when you produce builds, not including any versioning info -modArchivesBaseName = mymodid - -# Will update your build.gradle automatically whenever an update is available -autoUpdateBuildScript = false - -minecraftVersion = 1.12.2 - -# Select a username for testing your mod with breakpoints. You may leave this empty for a random username each time you -# restart Minecraft in development. Choose this dependent on your mod: -# Do you need consistent player progressing (for example Thaumcraft)? -> Select a name -# Do you need to test how your custom blocks interacts with a player that is not the owner? -> leave name empty -# Alternatively this can be set with the 'DEV_USERNAME' environment variable. -developmentEnvironmentUserName = Developer - -# Additional arguments applied to the JVM when launching minecraft -# Syntax: -arg1=value1;-arg2=value2;... -# Example value: -Dmixin.debug.verify=true;-XX:+UnlockExperimentalVMOptions -additionalJavaArguments = - -# Enables using modern java syntax (up to version 17) via Jabel, while still targeting JVM 8. -# See https://github.com/bsideup/jabel for details on how this works. -# Using this requires that you use a Java 17 JDK for development. -enableModernJavaSyntax = true - -# Enables runClient/runServer tasks for Java 17 and Java 21 using LWJGL3ify. -# This is primarily used to test if your mod is compatible with platforms running -# Minecraft 1.12.2 on modern versions of Java and LWJGL, and assist in fixing any problems with it. -# Using this requires that you use a Java 17/Java 21 JDK for development. -enableJava17RunTasks = false - -# Generate a class with String fields for the mod id, name and version named with the fields below -generateGradleTokenClass = com.myname.mymodid.Tags -gradleTokenModId = MODID -gradleTokenModName = MODNAME -gradleTokenVersion = VERSION - -# In case your mod provides an API for other mods to implement you may declare its package here. Otherwise, you can -# leave this property empty. -# Example value: apiPackage = api + modGroup = com.myname.mymodid -> com.myname.mymodid.api -apiPackage = - -# If you want to keep your API code in src/api instead of src/main -useSrcApiPath = false - -# Specify the configuration file for Forge's access transformers here. It must be placed into /src/main/resources/ -# There can be multiple files in a comma-separated list. -# Example value: mymodid_at.cfg,jei_at.cfg -accessTransformersFile = - -# Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled! -usesMixins = false -# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail! -mixinsPackage = -# Location of the mixin config refmap. If left, blank, defaults to "mixins.${modId}.refmap.json". Target file must have the "json" extension. -mixinConfigRefmap = -# Automatically generates a mixin config json if enabled, with the name mixins.modid.json -generateMixinConfig = true -# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin! -# Example value: coreModClass = asm.FMLPlugin + modGroup = com.myname.mymodid -> com.myname.mymodid.asm.FMLPlugin -coreModClass = -# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod (meaning that -# there is no class annotated with @Mod) you want this to be true. When in doubt: leave it on false! -containsMixinsAndOrCoreModOnly = false - -# Enables Mixins even if this mod doesn't use them, useful if one of the dependencies uses mixins. -forceEnableMixins = false - -# Outputs pre-transformed and post-transformed loaded classes to run/CLASSLOADER_TEMP. Can be used in combination with -# diff to see exactly what your ASM or Mixins are changing in the target file. -# Optionally can be specified with the 'CORE_MOD_DEBUG' env var. Will output a lot of files! -enableCoreModDebug = false - -# Adds CurseMaven, Modrinth Maven, BlameJared maven, and some more well-known 1.12.2 repositories -includeWellKnownRepositories = true - -# Adds JEI and TheOneProbe to your development environment. Adds them as 'implementation', meaning they will -# be available at compiletime and runtime for your mod (in-game and in-code). -# Overrides the above setting to be always true, as these repositories are needed to fetch the mods -includeCommonDevEnvMods = true - -# Some mods require a specific forge version to launch in. When you need to use one of those mods as a dependency, -# and cannot launch with the forge version required, enable this to strip the forge version requirements from that mod. -# This will add 'strip-latest-forge-requirements' as 'runtimeOnlyNonPublishable'. -# Requires useMixins or forceEnableMixins to be true, as the mod uses mixins to function. -stripForgeRequirements = false - - -# If enabled, you may use 'shadowCompile' for dependencies. They will be integrated in your jar. It is your -# responsibility check the licence and request permission for distribution, if required. -usesShadowedDependencies = false -# If disabled, won't remove unused classes from shaded dependencies. Some libraries use reflection to access -# their own classes, making the minimization unreliable. -minimizeShadowedDependencies = true -# If disabled, won't rename the shadowed classes. -relocateShadowedDependencies = true - -# Separate run directories into "run/client" for runClient task, and "run/server" for runServer task. -# Useful for debugging a server and client simultaneously. If not enabled, it will be in the standard location "run/" -separateRunDirectories = false - -# The display name format of versions published to Curse and Modrinth. $MOD_NAME and $VERSION are available variables. -# Default: $MOD_NAME \u2212 $VERSION. \u2212 is the minus character which looks much better than the hyphen minus on Curse. -versionDisplayFormat = $MOD_NAME \u2212 $VERSION - -# Publishing to modrinth requires you to set the MODRINTH_API_KEY environment variable to your current modrinth API token. - -# The project's ID on Modrinth. Can be either the slug or the ID. -# Leave this empty if you don't want to publish on Modrinth. -# Alternatively this can be set with the 'MODRINTH_PROJECT_ID' environment variable. -modrinthProjectId = - -# The project's relations on Modrinth. You can use this to refer to other projects on Modrinth. -# Syntax: scope1-type1:name1;scope2-type2:name2;... -# Where scope can be one of [required, optional, incompatible, embedded], -# type can be one of [project, version], -# and the name is the Modrinth project or version slug/id of the other mod. -# Example: required-project:jei;optional-project:top;incompatible-project:gregtech -modrinthRelations = - - -# Publishing to CurseForge requires you to set the CURSEFORGE_API_KEY environment variable to one of your CurseForge API tokens. - -# The project's numeric ID on CurseForge. You can find this in the About Project box. -# Leave this empty if you don't want to publish on CurseForge. -# Alternatively this can be set with the 'CURSEFORGE_PROJECT_ID' environment variable. -curseForgeProjectId = - -# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge. -# Syntax: type1:name1;type2:name2;... -# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible], -# and the name is the CurseForge project slug of the other mod. -# Example: requiredDependency:railcraft;embeddedLibrary:cofhlib;incompatible:buildcraft -curseForgeRelations = - -# This project's release type on CurseForge and/or Modrinth -# Alternatively this can be set with the 'RELEASE_TYPE' environment variable. -# Allowed types: release, beta, alpha -releaseType = release - -# Generate a default changelog for releases. Requires git to be installed, as it uses it to generate a changelog of -# commits since the last tagged release. -generateDefaultChangelog = false - -# Prevent the source code from being published -noPublishedSources = false - - -# Publish to a custom maven location. Follows a few rules: -# Group ID can be set with the 'ARTIFACT_GROUP_ID' environment variable, default to 'project.group' -# Artifact ID can be set with the 'ARTIFACT_ID' environment variable, default to 'project.name' -# Version can be set with the 'RELEASE_VERSION' environment variable, default to 'modVersion' -# For maven credentials: -# Username is set with the 'MAVEN_USER' environment variable, default to "NONE" -# Password is set with the 'MAVEN_PASSWORD' environment variable, default to "NONE" -customMavenPublishUrl = - -# The group for maven artifacts. Defaults to the 'project.modGroup' until the last '.' (if any). -# So 'mymod' becomes 'mymod' and 'com.myname.mymodid' 'becomes com.myname' -mavenArtifactGroup = - -# Enable spotless checks -# Enforces code formatting on your source code -# By default this will use the files found here: https://github.com/GregTechCEu/Buildscripts/tree/master/spotless -# to format your code. However, you can create your own version of these files and place them in your project's -# root directory to apply your own formatting options instead. -enableSpotless = false - -# Enable JUnit testing platform used for testing your code. -# Uses JUnit 5. See guide and documentation here: https://junit.org/junit5/docs/current/user-guide/ -enableJUnit = true - -# Deployment debug setting -# Uncomment this to test deployments to CurseForge and Modrinth -# Alternatively, you can set the 'DEPLOYMENT_DEBUG' environment variable. -deploymentDebug = false +# +# The "gradle.properties" file contains settings loaded by all gradle files. +# For the "build.gradle" file, all properties are stored in the separate and dedicated file "buildscript.properties". +# Properties can be created via any sequence of ASCII characters followed by an equal sign to set the value. +# # Gradle Settings @@ -195,4 +10,10 @@ deploymentDebug = false org.gradle.logging.stacktrace = all # Sets default memory used for gradle commands. Can be overridden by user or command line properties. # This is required to provide enough memory for the Minecraft decompilation process. -org.gradle.jvmargs = -Xmx3G +org.gradle.jvmargs = -Xmx3G -Dnet.bytebuddy.experimental=true +# Run independent tasks in parallel to speed up builds. +org.gradle.parallel = true +# Reuse outputs from previous builds via the build cache. +org.gradle.caching = true +# NOTE: configuration-cache is intentionally left disabled. This buildscript resolves git +# information (gitVersion()/runShell) at configuration time, which is incompatible with it. diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 2c35211..f8e1ee3 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 09523c0..6954be8 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-all.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index f5feea6..adff685 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -115,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -173,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -206,15 +203,14 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 9b42019..e509b2d 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,10 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..c75414b --- /dev/null +++ b/renovate.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended" + ], + "timezone": "Asia/Tokyo", + "schedule": [ + "every weekend" + ], + "automerge": false, + "packageRules": [ + { + "matchDatasources": ["gradle-version"], + "registryUrls": [ + "https://www.cursemaven.com", + "https://api.modrinth.com/maven", + "https://maven.cleanroommc.com", + "https://maven.blamejared.com", + "https://nexus.gtnewhorizons.com/repository/public/", + "https://maven.gtceu.com" + ] + }, + { + "groupName": "monthly_maintenance", + "matchDepTypes":[ "dependencies" ], + "matchUpdateTypes": ["minor", "patch"] + }, + { + "matchDepTypes": [ "dependencies"], + "matchUpdateTypes": ["major"], + "enabled": false + }, + { + "groupName": "monthly_maintenance", + "matchDepTypes":[ "devDependencies" ], + "matchUpdateTypes": ["major", "minor", "patch"] + } + ] +} diff --git a/scripts/test_no_error_reports.sh b/scripts/test_no_error_reports.sh new file mode 100644 index 0000000..1fcc739 --- /dev/null +++ b/scripts/test_no_error_reports.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash + +# bashsupport disable=BP5006 # Global environment variables +RUNDIR="run" \ + CRASH="crash-reports" \ + SERVERLOG="server.log" + +# enable nullglob to get 0 results when no match rather than the pattern +shopt -s nullglob + +# store matches in array +crash_reports=("$RUNDIR/$CRASH/crash"*.txt) + +# if array not empty there are crash_reports +if [ "${#crash_reports[@]}" -gt 0 ]; then + # get the latest crash_report from array + latest_crash_report="${crash_reports[-1]}" + { + printf 'Latest crash report detected %s:\n' "${latest_crash_report##*/}" + cat "$latest_crash_report" + } >&2 + exit 1 +fi + +if grep --quiet --fixed-strings 'Fatal errors were detected' "$SERVERLOG"; then + { + printf 'Fatal errors detected:\n' + cat server.log + } >&2 + exit 1 +fi + +if grep --quiet --fixed-strings 'The state engine was in incorrect state ERRORED and forced into state SERVER_STOPPED' \ + "$SERVERLOG"; then + { + printf 'Server force stopped:' + cat server.log + } >&2 + exit 1 +fi + +if ! grep --quiet --perl-regexp --only-matching '.+Done \(.+\)\! For help, type "help" or "\?"' "$SERVERLOG"; then + { + printf 'Server did not finish startup:' + cat server.log + } >&2 + exit 1 +fi + +printf 'No crash reports detected' +exit 0 diff --git a/settings.gradle b/settings.gradle index 771def3..2a8d150 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,8 +2,8 @@ pluginManagement { repositories { maven { // RetroFuturaGradle - name 'GTNH Maven' - url 'https://nexus.gtnewhorizons.com/repository/public/' + name = 'GTNH Maven' + url = 'https://nexus.gtnewhorizons.com/repository/public/' //noinspection GroovyAssignabilityCheck mavenContent { includeGroup 'com.gtnewhorizons' @@ -17,14 +17,25 @@ pluginManagement { } plugins { - id 'com.diffplug.blowdryerSetup' version '1.7.0' + id 'com.diffplug.blowdryerSetup' version '1.7.1' // Automatic toolchain provisioning - id 'org.gradle.toolchains.foojay-resolver-convention' version '0.7.0' + id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0' + id 'com.gradle.develocity' version '3.19' +} + +develocity { + buildScan { + termsOfUseUrl = "https://gradle.com/help/legal-terms-of-use" + termsOfUseAgree = "yes" + // Only publish a build scan in CI; locally the terms are still accepted + // so the daemon never blocks on the interactive "Do you accept?" prompt. + publishing.onlyIf { System.getenv("CI") != null } + } } blowdryerSetup { repoSubfolder 'spotless' - github 'GregTechCEu/Buildscripts', 'tag', 'v1.0.7' + github 'GTModpackTeam/Buildscripts', 'tag', 'v1.0.4' } rootProject.name = rootProject.projectDir.getName() diff --git a/spotless/spotless.importorder b/spotless/spotless.importorder index ce4fe27..41019cc 100644 --- a/spotless/spotless.importorder +++ b/spotless/spotless.importorder @@ -1,7 +1,9 @@ #Organize Import Order -#Sat Jan 28 17:57:48 GMT 2023 0=java 1=javax 2=net 3=org 4=com +5=gregtech +6=gregicality +7=com.github.gtexpert diff --git a/src/api/java/blusunrize/immersiveengineering/api/tool/BelljarHandler.java b/src/api/java/blusunrize/immersiveengineering/api/tool/BelljarHandler.java new file mode 100644 index 0000000..2ff7bf4 --- /dev/null +++ b/src/api/java/blusunrize/immersiveengineering/api/tool/BelljarHandler.java @@ -0,0 +1,14 @@ +package blusunrize.immersiveengineering.api.tool; + +import net.minecraft.item.ItemStack; + +/** + * Adapted and minimized from BelljarHandler.java + */ +public final class BelljarHandler { + + private BelljarHandler() {/**/} + + public static void registerBasicItemFertilizer(@SuppressWarnings("unused") final ItemStack stack, + @SuppressWarnings("unused") final float growthMultiplier) {/**/} +} diff --git a/src/api/java/buildcraft/api/tools/IToolWrench.java b/src/api/java/buildcraft/api/tools/IToolWrench.java new file mode 100644 index 0000000..caad463 --- /dev/null +++ b/src/api/java/buildcraft/api/tools/IToolWrench.java @@ -0,0 +1,32 @@ +/* Copyright (c) 2011-2015, SpaceToad and the BuildCraft Team http://www.mod-buildcraft.com + * + * The BuildCraft API is distributed under the terms of the MIT License. Please check the contents of the license, which + * should be located as "LICENSE.API" in the BuildCraft source code distribution. */ +package buildcraft.api.tools; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.RayTraceResult; + +/*** Implement this interface on subclasses of Item to have that item work as a wrench for buildcraft */ +public interface IToolWrench { + + /*** Called to ensure that the wrench can be used. + * + * @param player - The player doing the wrenching + * @param hand - Which hand was holding the wrench + * @param wrench - The item stack that holds the wrench + * @param rayTrace - The object that is being wrenched + * + * @return true if wrenching is allowed, false if not */ + boolean canWrench(EntityPlayer player, EnumHand hand, ItemStack wrench, RayTraceResult rayTrace); + + /*** Callback after the wrench has been used. This can be used to decrease durability or for other purposes. + * + * @param player - The player doing the wrenching + * @param hand - Which hand was holding the wrench + * @param wrench - The item stack that holds the wrench + * @param rayTrace - The object that is being wrenched */ + void wrenchUsed(EntityPlayer player, EnumHand hand, ItemStack wrench, RayTraceResult rayTrace); +} diff --git a/src/api/java/cofh/api/item/IToolHammer.java b/src/api/java/cofh/api/item/IToolHammer.java new file mode 100644 index 0000000..5806918 --- /dev/null +++ b/src/api/java/cofh/api/item/IToolHammer.java @@ -0,0 +1,17 @@ +package cofh.api.item; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; + +public interface IToolHammer { + + boolean isUsable(ItemStack item, EntityLivingBase user, BlockPos pos); + + boolean isUsable(ItemStack item, EntityLivingBase user, Entity entity); + + void toolUsed(ItemStack item, EntityLivingBase user, BlockPos pos); + + void toolUsed(ItemStack item, EntityLivingBase user, Entity entity); +} diff --git a/src/api/java/com/creativemd/creativecore/client/mods/optifine/OptifineHelper.java b/src/api/java/com/creativemd/creativecore/client/mods/optifine/OptifineHelper.java new file mode 100644 index 0000000..96b2ec5 --- /dev/null +++ b/src/api/java/com/creativemd/creativecore/client/mods/optifine/OptifineHelper.java @@ -0,0 +1,7 @@ +package com.creativemd.creativecore.client.mods.optifine; + +public class OptifineHelper { + public static boolean isActive() { + return false; + } +} diff --git a/src/api/java/com/creativemd/littletiles/client/render/cache/LayeredRenderBoxCache.java b/src/api/java/com/creativemd/littletiles/client/render/cache/LayeredRenderBoxCache.java new file mode 100644 index 0000000..5bba944 --- /dev/null +++ b/src/api/java/com/creativemd/littletiles/client/render/cache/LayeredRenderBoxCache.java @@ -0,0 +1,4 @@ +package com.creativemd.littletiles.client.render.cache; + +public class LayeredRenderBoxCache { +} diff --git a/src/api/java/com/creativemd/littletiles/client/render/tile/LittleRenderBox.java b/src/api/java/com/creativemd/littletiles/client/render/tile/LittleRenderBox.java new file mode 100644 index 0000000..10987d5 --- /dev/null +++ b/src/api/java/com/creativemd/littletiles/client/render/tile/LittleRenderBox.java @@ -0,0 +1,5 @@ +package com.creativemd.littletiles.client.render.tile; + +public class LittleRenderBox { + public boolean needsResorting; +} diff --git a/src/api/java/com/enderio/core/common/interfaces/IOverlayRenderAware.java b/src/api/java/com/enderio/core/common/interfaces/IOverlayRenderAware.java new file mode 100644 index 0000000..ef83bd8 --- /dev/null +++ b/src/api/java/com/enderio/core/common/interfaces/IOverlayRenderAware.java @@ -0,0 +1,11 @@ +package com.enderio.core.common.interfaces; + +import net.minecraft.item.ItemStack; + +import org.jetbrains.annotations.NotNull; + +public interface IOverlayRenderAware { + + public void renderItemOverlayIntoGUI(@NotNull ItemStack stack, int xPosition, int yPosition); + +} diff --git a/src/api/java/crazypants/enderio/api/farm/IFertilizer.java b/src/api/java/crazypants/enderio/api/farm/IFertilizer.java new file mode 100644 index 0000000..1c666cb --- /dev/null +++ b/src/api/java/crazypants/enderio/api/farm/IFertilizer.java @@ -0,0 +1,10 @@ +package crazypants.enderio.api.farm; + +import net.minecraftforge.registries.IForgeRegistryEntry; + +/** + * Adapted and minimized from IFertilizer.java + */ +public interface IFertilizer extends IForgeRegistryEntry { + +} diff --git a/src/api/java/crazypants/enderio/api/tool/IConduitControl.java b/src/api/java/crazypants/enderio/api/tool/IConduitControl.java new file mode 100644 index 0000000..09a453a --- /dev/null +++ b/src/api/java/crazypants/enderio/api/tool/IConduitControl.java @@ -0,0 +1,18 @@ +package crazypants.enderio.api.tool; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +import org.jetbrains.annotations.NotNull; + +public interface IConduitControl { + + /** + * Controls whether the overlay is shown and the player can change the display mode. + * + * @param stack The itemstack + * @param player The player holding the itemstack + * @return True if the overlay should be rendered and the player should be able to change modes. False otherwise. + */ + boolean showOverlay(@NotNull ItemStack stack, @NotNull EntityPlayer player); +} diff --git a/src/api/java/crazypants/enderio/api/tool/IHideFacades.java b/src/api/java/crazypants/enderio/api/tool/IHideFacades.java new file mode 100644 index 0000000..5f594f2 --- /dev/null +++ b/src/api/java/crazypants/enderio/api/tool/IHideFacades.java @@ -0,0 +1,11 @@ +package crazypants.enderio.api.tool; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +import org.jetbrains.annotations.NotNull; + +public interface IHideFacades { + + boolean shouldHideFacades(@NotNull ItemStack stack, @NotNull EntityPlayer player); +} diff --git a/src/api/java/crazypants/enderio/api/tool/ITool.java b/src/api/java/crazypants/enderio/api/tool/ITool.java new file mode 100644 index 0000000..f163c20 --- /dev/null +++ b/src/api/java/crazypants/enderio/api/tool/ITool.java @@ -0,0 +1,14 @@ +package crazypants.enderio.api.tool; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; + +import org.jetbrains.annotations.NotNull; + +public interface ITool extends IHideFacades { + + boolean canUse(@NotNull EnumHand stack, @NotNull EntityPlayer player, @NotNull BlockPos pos); + + void used(@NotNull EnumHand stack, @NotNull EntityPlayer player, @NotNull BlockPos pos); +} diff --git a/src/api/java/crazypants/enderio/base/farming/fertilizer/Bonemeal.java b/src/api/java/crazypants/enderio/base/farming/fertilizer/Bonemeal.java new file mode 100644 index 0000000..cc18c95 --- /dev/null +++ b/src/api/java/crazypants/enderio/base/farming/fertilizer/Bonemeal.java @@ -0,0 +1,15 @@ +package crazypants.enderio.base.farming.fertilizer; + +import crazypants.enderio.api.farm.IFertilizer; +import net.minecraft.item.ItemStack; +import net.minecraftforge.registries.IForgeRegistryEntry; + +import org.jetbrains.annotations.NotNull; + +/** + * Adapted and minimized from Bonemeal.java + */ +public class Bonemeal extends IForgeRegistryEntry.Impl implements IFertilizer { + + public Bonemeal(@SuppressWarnings("unused") @NotNull ItemStack stack) {/**/} +} diff --git a/src/api/java/forestry/api/arboriculture/IToolGrafter.java b/src/api/java/forestry/api/arboriculture/IToolGrafter.java new file mode 100644 index 0000000..cd25031 --- /dev/null +++ b/src/api/java/forestry/api/arboriculture/IToolGrafter.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright 2011-2014 SirSengir + * + * This work (the API) is licensed under the "MIT" License, see LICENSE.txt for details. + ******************************************************************************/ +package forestry.api.arboriculture; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public interface IToolGrafter { + /** + * Called by leaves to determine the increase in sapling droprate. + * + * @param stack ItemStack containing the grafter. + * @param world Minecraft world the player and the target block inhabit. + * @param pos Coordinate of the broken leaf block. + * @return Float representing the factor the usual drop chance is to be multiplied by. + */ + float getSaplingModifier(ItemStack stack, World world, EntityPlayer player, BlockPos pos); +} diff --git a/src/api/java/io/github/drmanganese/topaddons/reference/Colors.java b/src/api/java/io/github/drmanganese/topaddons/reference/Colors.java new file mode 100644 index 0000000..78774e5 --- /dev/null +++ b/src/api/java/io/github/drmanganese/topaddons/reference/Colors.java @@ -0,0 +1,12 @@ +package io.github.drmanganese.topaddons.reference; + +import java.util.HashMap; +import java.util.Map; + +/** + * Adapted and minimized from Colors.java + */ +public final class Colors { + + public static final Map FLUID_NAME_COLOR_MAP = new HashMap<>(); +} diff --git a/src/api/java/mods/railcraft/api/items/IToolCrowbar.java b/src/api/java/mods/railcraft/api/items/IToolCrowbar.java new file mode 100644 index 0000000..7b8006b --- /dev/null +++ b/src/api/java/mods/railcraft/api/items/IToolCrowbar.java @@ -0,0 +1,78 @@ +/*------------------------------------------------------------------------------ + Copyright (c) CovertJaguar, 2011-2020 + + This work (the API) is licensed under the "MIT" License, + see LICENSE.md for details. + -----------------------------------------------------------------------------*/ +package mods.railcraft.api.items; + +import net.minecraft.entity.item.EntityMinecart; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumHand; +import net.minecraft.util.math.BlockPos; + +/** + * @author CovertJaguar + */ +public interface IToolCrowbar { + String ORE_TAG = "toolCrowbar"; + + /** + * Controls non-rotational interactions with blocks. Crowbar specific stuff. + *

+ * Rotational interaction is handled by the Block.rotateBlock() function, + * which should be called from the Item.onUseFirst() function of your tool. + * + * @param player the player + * @param crowbar the crowbar + * @param pos the block @return true if can whack a block + */ + boolean canWhack(EntityPlayer player, EnumHand hand, ItemStack crowbar, BlockPos pos); + + /** + * Callback to do damage to the item. + * + * @param player the player + * @param crowbar the crowbar + * @param pos the block + */ + void onWhack(EntityPlayer player, EnumHand hand, ItemStack crowbar, BlockPos pos); + + /** + * Controls whether you can link a cart. + * + * @param player the player + * @param crowbar the crowbar + * @param cart the cart @return true if can link a cart + */ + boolean canLink(EntityPlayer player, EnumHand hand, ItemStack crowbar, EntityMinecart cart); + + /** + * Callback to do damage. + * + * @param player the player + * @param crowbar the crowbar + * @param cart the cart + */ + void onLink(EntityPlayer player, EnumHand hand, ItemStack crowbar, EntityMinecart cart); + + /** + * Controls whether you can boost a cart. + * + * @param player the player + * @param crowbar the crowbar + * @param cart the cart @return true if can boost a cart + */ + boolean canBoost(EntityPlayer player, EnumHand hand, ItemStack crowbar, EntityMinecart cart); + + /** + * Callback to do damage, boosting a cart usually does more damage than + * normal usage. + * + * @param player the player + * @param crowbar the crowbar + * @param cart the cart + */ + void onBoost(EntityPlayer player, EnumHand hand, ItemStack crowbar, EntityMinecart cart); +} diff --git a/src/api/java/mrtjp/projectred/api/IScrewdriver.java b/src/api/java/mrtjp/projectred/api/IScrewdriver.java new file mode 100644 index 0000000..a6298fe --- /dev/null +++ b/src/api/java/mrtjp/projectred/api/IScrewdriver.java @@ -0,0 +1,11 @@ +package mrtjp.projectred.api; + +import net.minecraft.item.ItemStack; +import net.minecraft.entity.player.EntityPlayer; + +public interface IScrewdriver { + + boolean canUse(EntityPlayer player, ItemStack stack); + + void damageScrewdriver(EntityPlayer player, ItemStack stack); // Damage the item on usage +} diff --git a/src/main/java/com/github/gtexpert/testmod/TestMod.java b/src/main/java/com/github/gtexpert/testmod/TestMod.java new file mode 100644 index 0000000..1fcb8ba --- /dev/null +++ b/src/main/java/com/github/gtexpert/testmod/TestMod.java @@ -0,0 +1,136 @@ +package com.github.gtexpert.testmod; + +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.crafting.IRecipe; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.config.Config; +import net.minecraftforge.common.config.ConfigManager; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.fml.client.event.ConfigChangedEvent; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.event.*; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import com.github.gtexpert.testmod.api.ModValues; +import com.github.gtexpert.testmod.api.util.ModLog; +import com.github.gtexpert.testmod.modules.ModuleManager; +import com.github.gtexpert.testmod.modules.Modules; + +@Mod( + modid = Tags.MODID, + name = Tags.MODNAME, + version = Tags.VERSION, + dependencies = "") +public class TestMod { + + private ModuleManager moduleManager; + + @Mod.EventHandler + public void onConstruction(FMLConstructionEvent event) { + MinecraftForge.EVENT_BUS.register(this); + ModLog.logger.info("starting construction event..."); + moduleManager = ModuleManager.getInstance(); + moduleManager.registerContainer(new Modules()); + moduleManager.setup(event.getASMHarvestedData(), Loader.instance().getConfigDir()); + moduleManager.onConstruction(event); + ModLog.logger.info("finished construction!"); + } + + @Mod.EventHandler + public void preInit(FMLPreInitializationEvent event) { + moduleManager.onPreInit(event); + } + + @Mod.EventHandler + public void init(FMLInitializationEvent event) { + moduleManager.onInit(event); + } + + @Mod.EventHandler + public void postInit(FMLPostInitializationEvent event) { + moduleManager.onPostInit(event); + } + + @Mod.EventHandler + public void loadComplete(FMLLoadCompleteEvent event) { + moduleManager.onLoadComplete(event); + } + + @Mod.EventHandler + public void serverAboutToStart(FMLServerAboutToStartEvent event) { + moduleManager.onServerAboutToStart(event); + } + + @Mod.EventHandler + public void serverStarting(FMLServerStartingEvent event) { + moduleManager.onServerStarting(event); + } + + @Mod.EventHandler + public void serverStarted(FMLServerStartedEvent event) { + moduleManager.onServerStarted(event); + } + + @Mod.EventHandler + public void serverStopping(FMLServerStoppingEvent event) { + moduleManager.onServerStopping(event); + } + + @Mod.EventHandler + public void serverStopped(FMLServerStoppedEvent event) { + moduleManager.onServerStopped(event); + } + + @Mod.EventHandler + public void respondIMC(FMLInterModComms.IMCEvent event) { + moduleManager.processIMC(event.getMessages()); + } + + @SubscribeEvent + public void registerBlocks(RegistryEvent.Register event) { + ModLog.logger.info("Registering Blocks..."); + moduleManager.registerBlocks(event); + } + + @SubscribeEvent + public void registerItems(RegistryEvent.Register event) { + ModLog.logger.info("Registering Items..."); + + moduleManager.registerItems(event); + } + + @SubscribeEvent(priority = EventPriority.HIGHEST) + public void registerRecipesHighest(RegistryEvent.Register event) { + moduleManager.registerRecipesHighest(event); + } + + @SubscribeEvent(priority = EventPriority.HIGH) + public void registerRecipesHigh(RegistryEvent.Register event) { + moduleManager.registerRecipesHigh(event); + } + + @SubscribeEvent(priority = EventPriority.NORMAL) + public void registerRecipes(RegistryEvent.Register event) { + moduleManager.registerRecipesNormal(event); + } + + @SubscribeEvent(priority = EventPriority.LOW) + public void registerRecipesLow(RegistryEvent.Register event) { + moduleManager.registerRecipesLow(event); + } + + @SubscribeEvent(priority = EventPriority.LOWEST) + public void registerRecipesLowest(RegistryEvent.Register event) { + moduleManager.registerRecipesLowest(event); + } + + @SubscribeEvent + public static void syncConfigValues(ConfigChangedEvent.OnConfigChangedEvent event) { + if (event.getModID().equals(ModValues.MODID)) { + ConfigManager.sync(ModValues.MODID, Config.Type.INSTANCE); + } + } +} diff --git a/src/main/java/com/github/gtexpert/testmod/api/ModValues.java b/src/main/java/com/github/gtexpert/testmod/api/ModValues.java new file mode 100644 index 0000000..53ac6be --- /dev/null +++ b/src/main/java/com/github/gtexpert/testmod/api/ModValues.java @@ -0,0 +1,8 @@ +package com.github.gtexpert.testmod.api; + +import com.github.gtexpert.testmod.Tags; + +public class ModValues { + + public static final String MODID = Tags.MODID; +} diff --git a/src/main/java/com/github/gtexpert/testmod/api/modules/IModule.java b/src/main/java/com/github/gtexpert/testmod/api/modules/IModule.java new file mode 100644 index 0000000..e795ef6 --- /dev/null +++ b/src/main/java/com/github/gtexpert/testmod/api/modules/IModule.java @@ -0,0 +1,93 @@ +package com.github.gtexpert.testmod.api.modules; + +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.fml.common.event.*; + +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +/** + * All modules must implement this interface. + *

+ * Provides methods for responding to FML lifecycle events, adding event bus subscriber classes, and processing IMC + * messages. + */ +public interface IModule { + + /** + * What other modules this module depends on. + *

+ * e.g. new ResourceLocation("testmod", "foo_module") represents a dependency on the module + * "foo_module" in the container "testmod" + */ + @NotNull + default Set getDependencyUids() { + return Collections.emptySet(); + } + + default void construction(FMLConstructionEvent event) {} + + default void preInit(FMLPreInitializationEvent event) {} + + default void init(FMLInitializationEvent event) {} + + default void postInit(FMLPostInitializationEvent event) {} + + default void loadComplete(FMLLoadCompleteEvent event) {} + + default void serverAboutToStart(FMLServerAboutToStartEvent event) {} + + default void serverStarting(FMLServerStartingEvent event) {} + + default void serverStarted(FMLServerStartedEvent event) {} + + default void serverStopping(FMLServerStoppingEvent event) {} + + default void serverStopped(FMLServerStoppedEvent event) {} + + default void registerItems(RegistryEvent.Register event) {} + + default void registerBlocks(RegistryEvent.Register event) {} + + default void registerRecipesHighest(RegistryEvent.Register event) {} + + default void registerRecipesHigh(RegistryEvent.Register event) {} + + default void registerRecipesNormal(RegistryEvent.Register event) {} + + default void registerRecipesLow(RegistryEvent.Register event) {} + + default void registerRecipesLowest(RegistryEvent.Register event) {} + + /** + * Register packets using TestMod's packet handling API here. + */ + default void registerPackets() {} + + /** + * @return A list of classes to subscribe to the Forge event bus. + * As the class gets subscribed, not any specific instance, event handlers must be static! + */ + @NotNull + default List> getEventBusSubscribers() { + return Collections.emptyList(); + } + + default boolean processIMC(FMLInterModComms.IMCMessage message) { + return false; + } + + /** + * @return A logger to use for this module. + */ + @NotNull + Logger getLogger(); +} diff --git a/src/main/java/com/github/gtexpert/testmod/api/modules/IModuleContainer.java b/src/main/java/com/github/gtexpert/testmod/api/modules/IModuleContainer.java new file mode 100644 index 0000000..d644d6a --- /dev/null +++ b/src/main/java/com/github/gtexpert/testmod/api/modules/IModuleContainer.java @@ -0,0 +1,9 @@ +package com.github.gtexpert.testmod.api.modules; + +public interface IModuleContainer { + + /** + * The ID of this container. If this is your mod's only container, you should use your mod ID to prevent collisions. + */ + String getID(); +} diff --git a/src/main/java/com/github/gtexpert/testmod/api/modules/IModuleManager.java b/src/main/java/com/github/gtexpert/testmod/api/modules/IModuleManager.java new file mode 100644 index 0000000..63f8973 --- /dev/null +++ b/src/main/java/com/github/gtexpert/testmod/api/modules/IModuleManager.java @@ -0,0 +1,26 @@ +package com.github.gtexpert.testmod.api.modules; + +import net.minecraft.util.ResourceLocation; + +import com.github.gtexpert.testmod.api.util.ModUtility; + +public interface IModuleManager { + + default boolean isModuleEnabled(String containerID, String moduleID) { + return isModuleEnabled(new ResourceLocation(containerID, moduleID)); + } + + default boolean isModuleEnabled(String moduleID) { + return isModuleEnabled(ModUtility.id(moduleID)); + } + + boolean isModuleEnabled(ResourceLocation id); + + void registerContainer(IModuleContainer container); + + IModuleContainer getLoadedContainer(); + + ModuleStage getStage(); + + boolean hasPassedStage(ModuleStage stage); +} diff --git a/src/main/java/com/github/gtexpert/testmod/api/modules/ModuleContainer.java b/src/main/java/com/github/gtexpert/testmod/api/modules/ModuleContainer.java new file mode 100644 index 0000000..8e30e57 --- /dev/null +++ b/src/main/java/com/github/gtexpert/testmod/api/modules/ModuleContainer.java @@ -0,0 +1,13 @@ +package com.github.gtexpert.testmod.api.modules; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotate your {@link IModule} with this for it to be automatically registered. + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface ModuleContainer {} diff --git a/src/main/java/com/github/gtexpert/testmod/api/modules/ModuleStage.java b/src/main/java/com/github/gtexpert/testmod/api/modules/ModuleStage.java new file mode 100644 index 0000000..00fa7f9 --- /dev/null +++ b/src/main/java/com/github/gtexpert/testmod/api/modules/ModuleStage.java @@ -0,0 +1,18 @@ +package com.github.gtexpert.testmod.api.modules; + +/** + * Basically {@link net.minecraftforge.fml.common.LoaderState} but only for launch stages. + * Also includes early module stages. + */ +public enum ModuleStage { + C_SETUP, // Initializing Module Containers + M_SETUP, // Initializing Modules + CONSTRUCTION, // MC Construction stage + PRE_INIT, // MC PreInitialization stage + INIT, // MC Initialization stage + POST_INIT, // MC PostInitialization stage + FINISHED, // MC LoadComplete stage + SERVER_ABOUT_TO_START, // MC ServerAboutToStart stage + SERVER_STARTING, // MC ServerStarting stage + SERVER_STARTED // MC ServerStarted stage +} diff --git a/src/main/java/com/github/gtexpert/testmod/api/modules/TModule.java b/src/main/java/com/github/gtexpert/testmod/api/modules/TModule.java new file mode 100644 index 0000000..63ac14e --- /dev/null +++ b/src/main/java/com/github/gtexpert/testmod/api/modules/TModule.java @@ -0,0 +1,51 @@ +package com.github.gtexpert.testmod.api.modules; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * All of your {@link IModule} classes must be annotated with this to be registered. + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface TModule { + + /** + * The ID of this module. Must be unique within its container. + */ + String moduleID(); + + /** + * The ID of the container to associate this module with. + */ + String containerID(); + + /** + * A human-readable name for this module. + */ + String name(); + + /** + * A list of mod IDs that this module depends on. If any mods specified are not present, the module will not load. + */ + String[] modDependencies() default {}; + + /** + * Whether this module is the "core" module for its container. + * Each container must have exactly one core module, which will be loaded before all other modules in the container. + *

+ * Core modules should not have mod dependencies. + */ + boolean coreModule() default false; + + String author() default ""; + + String version() default ""; + + /** + * A description of this module in the module configuration file. + */ + String description() default ""; +} diff --git a/src/main/java/com/github/gtexpert/testmod/api/util/ModIncompatibilityException.java b/src/main/java/com/github/gtexpert/testmod/api/util/ModIncompatibilityException.java new file mode 100644 index 0000000..d754f6d --- /dev/null +++ b/src/main/java/com/github/gtexpert/testmod/api/util/ModIncompatibilityException.java @@ -0,0 +1,35 @@ +package com.github.gtexpert.testmod.api.util; + +import java.util.List; + +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiErrorScreen; +import net.minecraftforge.fml.client.CustomModLoadingErrorDisplayException; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +@SideOnly(Side.CLIENT) +public class ModIncompatibilityException extends CustomModLoadingErrorDisplayException { + + @SuppressWarnings("all") + private static final long serialVersionUID = 1L; + + private final List messages; + + public ModIncompatibilityException(List messages) { + this.messages = messages; + } + + @Override + public void initGui(GuiErrorScreen guiErrorScreen, FontRenderer fontRenderer) {} + + @Override + public void drawScreen(GuiErrorScreen errorScreen, FontRenderer fontRenderer, int mouseX, int mouseY, float time) { + int x = errorScreen.width / 2; + int y = 75; + for (String message : messages) { + errorScreen.drawCenteredString(fontRenderer, message, x, y, 0xFFFFFF); + y += 15; + } + } +} diff --git a/src/main/java/com/github/gtexpert/testmod/api/util/ModLog.java b/src/main/java/com/github/gtexpert/testmod/api/util/ModLog.java new file mode 100644 index 0000000..a36d3ba --- /dev/null +++ b/src/main/java/com/github/gtexpert/testmod/api/util/ModLog.java @@ -0,0 +1,13 @@ +package com.github.gtexpert.testmod.api.util; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.github.gtexpert.testmod.Tags; + +public class ModLog { + + private ModLog() {} + + public static final Logger logger = LogManager.getLogger(Tags.MODNAME); +} diff --git a/src/main/java/com/github/gtexpert/testmod/api/util/ModUtility.java b/src/main/java/com/github/gtexpert/testmod/api/util/ModUtility.java new file mode 100644 index 0000000..c2d7763 --- /dev/null +++ b/src/main/java/com/github/gtexpert/testmod/api/util/ModUtility.java @@ -0,0 +1,83 @@ +package com.github.gtexpert.testmod.api.util; + +import java.util.Objects; +import java.util.Random; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fluids.FluidRegistry; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fml.common.registry.GameRegistry; +import net.minecraftforge.oredict.OreDictionary; + +import org.jetbrains.annotations.NotNull; + +import gregtech.api.unification.OreDictUnifier; +import gregtech.api.unification.material.Material; +import gregtech.api.unification.stack.ItemMaterialInfo; +import gregtech.api.unification.stack.MaterialStack; + +import com.github.gtexpert.testmod.api.ModValues; + +public class ModUtility { + + private static final Random RANDOM = new Random(); + + public static @NotNull ItemStack getModItem(String modID, String itemName) { + return GameRegistry.makeItemStack(modID + ":" + itemName, 0, 1, null); + } + + public static @NotNull ItemStack getModItem(String modID, String itemName, int amount) { + return GameRegistry.makeItemStack(modID + ":" + itemName, 0, amount, null); + } + + public static @NotNull ItemStack getModItem(String modID, String itemName, int amount, int meta) { + return GameRegistry.makeItemStack(modID + ":" + itemName, meta, amount, null); + } + + public static @NotNull ItemStack getModItem(String modID, String itemName, int amount, int meta, + NBTTagCompound nbt) { + return GameRegistry.makeItemStack(modID + ":" + itemName, meta, amount, nbt != null ? nbt.toString() : null); + } + + public static @NotNull FluidStack getModFluid(String fluidName) { + return Objects.requireNonNull(FluidRegistry.getFluidStack(fluidName, 1000)); + } + + public static @NotNull FluidStack getModFluid(String fluidName, int amount) { + return Objects.requireNonNull(FluidRegistry.getFluidStack(fluidName, amount)); + } + + public static @NotNull ResourceLocation id(String path) { + return new ResourceLocation(ModValues.MODID, path); + } + + public static void registerOre(String dictName, ItemStack... itemStacks) { + for (ItemStack stack : itemStacks) { + OreDictionary.registerOre(dictName, stack); + } + } + + public static String generateRandomString(int length) { + StringBuilder stringBuilder = new StringBuilder(length); + + for (int i = 0; i < length; i++) { + stringBuilder.append(RANDOM.nextInt(10)); + } + + return stringBuilder.toString(); + } + + public static void registerOre(ItemStack itemStack, Material material, long amount) { + registerOre(itemStack, new MaterialStack(material, amount)); + } + + public static void registerOre(ItemStack itemStack, MaterialStack... materialStacks) { + registerOre(itemStack, new ItemMaterialInfo(materialStacks)); + } + + public static void registerOre(ItemStack itemStack, ItemMaterialInfo materialInfo) { + OreDictUnifier.registerOre(itemStack, materialInfo); + } +} diff --git a/src/main/java/com/github/gtexpert/testmod/api/util/Mods.java b/src/main/java/com/github/gtexpert/testmod/api/util/Mods.java new file mode 100644 index 0000000..56e631f --- /dev/null +++ b/src/main/java/com/github/gtexpert/testmod/api/util/Mods.java @@ -0,0 +1,258 @@ +package com.github.gtexpert.testmod.api.util; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.TextFormatting; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.ModContainer; +import net.minecraftforge.fml.common.registry.GameRegistry; +import net.minecraftforge.fml.relauncher.FMLLaunchHandler; +import net.minecraftforge.fml.relauncher.Side; +import net.minecraftforge.fml.relauncher.SideOnly; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import gregtech.api.GTValues; + +import com.github.gtexpert.testmod.api.ModValues; + +public enum Mods { + + AEAdditions(Names.AE_ADDITIONS), + AE2FluidCrafting(Names.AE2_FLUID_CRAFTING), + AppliedEnergistics2(Names.APPLIED_ENERGISTICS2), + Avaritia(Names.AVARITIA), + Avaritiaaddons(Names.AVARITIAADDONS), + Baubles(Names.BAUBLES), + Chisel(Names.CHISEL), + CTM(Names.CONNECTED_TEXTURES_MOD), + CraftTweaker(Names.CRAFT_TWEAKER), + DraconicAdditions(Names.DRACONIC_ADDITIONS), + DraconicEvolution(Names.DRACONIC_EVOLUTION), + EnderCore(Names.ENDER_CORE), + EnderIO(Names.ENDER_IO), + EnderIOEndergy(Names.ENDER_ENDERGY), + EnderIOMachines(Names.ENDER_MACHINES), + EnderIOConduits(Names.ENDER_CONDUITS), + EnderIOAE2Conduits(Names.ENDER_AE2_CONDUITS), + ExtraCPUs(Names.EXTRA_CPUS), + GalacticraftCore(Names.GALACTICRAFT_CORE), + GregicalityMultiblocks(Names.GREGICALITY_MULTIBLOCKS), + GregTech(Names.GREGTECH), + GregTechFoodOption(Names.GREGTECH_FOOD_OPTION), + GregTechExpertCore(Names.GREGTECH_EXPERT_CORE), + GregTechChisel(Names.GREGTECH_CHISEL), + GregTechWoodProcessing(Names.GREGTECH_WOOD_PROCESSING), + GroovyScript(Names.GROOVY_SCRIPT), + HWYLA(Names.HWYLA), + ImplosionNoBomb(Names.IMPLOSION_NO_BOMB), + InventoryTweaks(Names.INVENTORY_TWEAKS), + JourneyMap(Names.JOURNEY_MAP), + JustEnoughItems(Names.JUST_ENOUGH_ITEMS), + ModularUI(Names.MODULRAUI), + MixinBooter(Names.MIXINBOOTER), + NeevesAE2(Names.NEEVES_AE2), + Nothirium(Names.NOTHIRIUM), + NuclearCraft(Names.NUCLEAR_CRAFT, versionExcludes("2o")), + NuclearCraftOverhauled(Names.NUCLEAR_CRAFT, versionContains("2o")), + OpenComputers(Names.OPEN_COMPUTERS), + ProjectRedCore(Names.PROJECT_RED_CORE), + ProjectRedIllumination(Names.PROJECT_RED_ILLUMINATION), + Railcraft(Names.RAILCRAFT), + RefinedStorage(Names.REFINED_STORAGE), + Thaumcraft(Names.THAUMCRAFT), + ThaumicEnergistics(Names.THAUMIC_ENERGISTICS), + TheOneProbe(Names.THE_ONE_PROBE), + TinkersConstruct(Names.TINKERS_CONSTRUCT), + TOPAddons(Names.TOP_ADDONS), + Vanilla(Names.VANILLA), + + // Special Optifine handler, but consolidated here for simplicity + Optifine(null) { + + @Override + public boolean isModLoaded() { + if (this.modLoaded == null) { + try { + Class c = Class.forName("net.optifine.shaders.Shaders"); + Field f = c.getDeclaredField("shaderPackLoaded"); + f.setAccessible(true); + this.modLoaded = f.getBoolean(null); + } catch (Exception ignored) { + this.modLoaded = false; + } + } + return this.modLoaded; + } + }; + + public static class Names { + + public static final String AE_ADDITIONS = "aeadditions"; + public static final String AE2_FLUID_CRAFTING = "ae2fc"; + public static final String APPLIED_ENERGISTICS2 = "appliedenergistics2"; + public static final String AVARITIA = "avaritia"; + public static final String AVARITIAADDONS = "avaritiaddons"; + public static final String BAUBLES = "baubles"; + public static final String BOTANY = "botany"; + public static final String CHISEL = "chisel"; + public static final String CONNECTED_TEXTURES_MOD = "ctm"; + public static final String CRAFT_TWEAKER = "crafttweaker"; + public static final String DRACONIC_ADDITIONS = "draconicadditions"; + public static final String DRACONIC_EVOLUTION = "draconicevolution"; + public static final String ENDER_CORE = "endercore"; + public static final String ENDER_IO = "enderio"; + public static final String ENDER_ENDERGY = "enderioendergy"; + public static final String ENDER_MACHINES = "enderiomachines"; + public static final String ENDER_CONDUITS = "enderioconduits"; + public static final String ENDER_AE2_CONDUITS = "enderioconduitsappliedenergistics"; + public static final String EXTRA_BEES = "extrabees"; + public static final String EXTRA_CPUS = "extracpus"; + public static final String EXTRA_TREES = "extratrees"; + public static final String GALACTICRAFT_CORE = "galacticraftcore"; + public static final String GENETICS = "genetics"; + public static final String GENDUSTRY = "gendustry"; + public static final String GREGICALITY_MULTIBLOCKS = "gcym"; + public static final String GREGTECH = GTValues.MODID; + public static final String GREGTECH_FOOD_OPTION = "gregtechfoodoption"; + public static final String GREGTECH_EXPERT_CORE = "gtexpert"; + public static final String GREGTECH_CHISEL = ModValues.MODID; + public static final String GREGTECH_WOOD_PROCESSING = "gtwp"; + public static final String GROOVY_SCRIPT = "groovyscript"; + public static final String HWYLA = "hwyla"; + public static final String IMPLOSION_NO_BOMB = "inb"; + public static final String INVENTORY_TWEAKS = "inventorytweaks"; + public static final String JOURNEY_MAP = "journeymap"; + public static final String JUST_ENOUGH_ITEMS = "jei"; + public static final String MODULRAUI = "modularui"; + public static final String MIXINBOOTER = "mixinbooter"; + public static final String NEEVES_AE2 = "nae2"; + public static final String NOTHIRIUM = "nothirium"; + public static final String NUCLEAR_CRAFT = "nuclearcraft"; + public static final String OPEN_COMPUTERS = "opencomputers"; + public static final String PROJECT_RED_CORE = "projred-core"; + public static final String PROJECT_RED_ILLUMINATION = "projectred-illumination"; + public static final String RAILCRAFT = "railcraft"; + public static final String REFINED_STORAGE = "refinedstorage"; + public static final String THAUMCRAFT = "thaumcraft"; + public static final String THAUMIC_ENERGISTICS = "thaumicenergistics"; + public static final String THE_ONE_PROBE = "theoneprobe"; + public static final String TINKERS_CONSTRUCT = "tconstruct"; + public static final String TOP_ADDONS = "topaddons"; + public static final String VANILLA = "minecraft"; + } + + private final String ID; + private final Function extraCheck; + protected Boolean modLoaded; + + Mods(String ID) { + this.ID = ID; + this.extraCheck = null; + } + + /** + * @param extraCheck A supplier that can be used to test additional factors, such as + * checking if a mod is at a specific version, or a sub-mod is loaded. + * Used in cases like NC vs NCO, where the mod id is the same + * so the version has to be parsed to test which is loaded. + * Another case is checking for specific Forestry modules, checking + * if Forestry is loaded and if a specific module is enabled. + */ + Mods(String ID, Function extraCheck) { + this.ID = ID; + this.extraCheck = extraCheck; + } + + public boolean isModLoaded() { + if (this.modLoaded == null) { + this.modLoaded = Loader.isModLoaded(this.ID); + if (this.modLoaded) { + if (this.extraCheck != null && !this.extraCheck.apply(this)) { + this.modLoaded = false; + } + } + } + return this.modLoaded; + } + + /** + * Throw an exception if this mod is found to be loaded. + * This must be called in or after + * {@link net.minecraftforge.fml.common.event.FMLPreInitializationEvent}! + */ + public void throwIncompatibilityIfLoaded(String... customMessages) { + if (isModLoaded()) { + String modName = TextFormatting.BOLD + ID + TextFormatting.RESET; + List messages = new ArrayList<>(); + messages.add(modName + " mod detected, this mod is incompatible with GregTech CE Unofficial."); + messages.addAll(Arrays.asList(customMessages)); + if (FMLLaunchHandler.side() == Side.SERVER) { + throw new RuntimeException(String.join(",", messages)); + } else { + throwClientIncompatibility(messages); + } + } + } + + @SideOnly(Side.CLIENT) + private static void throwClientIncompatibility(List messages) { + throw new ModIncompatibilityException(messages); + } + + public ItemStack getItem(@NotNull String name) { + return getItem(name, 1, 0, null); + } + + @NotNull + public ItemStack getItem(@NotNull String name, int count) { + return getItem(name, count, 0, null); + } + + @NotNull + public ItemStack getItem(@NotNull String name, int count, int meta) { + return getItem(name, count, meta, null); + } + + @NotNull + public ItemStack getItem(@NotNull String name, int count, int meta, @Nullable String nbt) { + // The following statement is intentional. + return GameRegistry.makeItemStack(ID + ":" + name, meta, count, nbt); + } + + @NotNull + public ResourceLocation getResource(@NotNull String path) { + return new ResourceLocation(ID, path); + } + + // Helpers for the extra checker + + /** Test if the mod version string contains the passed value. */ + private static Function versionContains(String versionPart) { + return mod -> { + if (mod.ID == null) return false; + if (!mod.isModLoaded()) return false; + ModContainer container = Loader.instance().getIndexedModList().get(mod.ID); + if (container == null) return false; + return container.getVersion().contains(versionPart); + }; + } + + /** Test if the mod version string does not contain the passed value. */ + private static Function versionExcludes(String versionPart) { + return mod -> { + if (mod.ID == null) return false; + if (!mod.isModLoaded()) return false; + ModContainer container = Loader.instance().getIndexedModList().get(mod.ID); + if (container == null) return false; + return !container.getVersion().contains(versionPart); + }; + } +} diff --git a/src/main/java/com/github/gtexpert/testmod/client/ClientProxy.java b/src/main/java/com/github/gtexpert/testmod/client/ClientProxy.java new file mode 100644 index 0000000..02868f3 --- /dev/null +++ b/src/main/java/com/github/gtexpert/testmod/client/ClientProxy.java @@ -0,0 +1,21 @@ +package com.github.gtexpert.testmod.client; + +import net.minecraftforge.client.event.ModelRegistryEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import net.minecraftforge.fml.relauncher.Side; + +import com.github.gtexpert.testmod.common.CommonProxy; + +@Mod.EventBusSubscriber(Side.CLIENT) +public class ClientProxy extends CommonProxy { + + @Override + public void preInit(FMLPreInitializationEvent event) { + super.preInit(event); + } + + @SubscribeEvent + public static void registerModels(ModelRegistryEvent event) {} +} diff --git a/src/main/java/com/github/gtexpert/testmod/common/CommonProxy.java b/src/main/java/com/github/gtexpert/testmod/common/CommonProxy.java new file mode 100644 index 0000000..dc14220 --- /dev/null +++ b/src/main/java/com/github/gtexpert/testmod/common/CommonProxy.java @@ -0,0 +1,12 @@ +package com.github.gtexpert.testmod.common; + +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; + +import com.github.gtexpert.testmod.api.ModValues; + +@Mod.EventBusSubscriber(modid = ModValues.MODID) +public class CommonProxy { + + public void preInit(FMLPreInitializationEvent event) {} +} diff --git a/src/main/java/com/github/gtexpert/testmod/core/CoreMod.java b/src/main/java/com/github/gtexpert/testmod/core/CoreMod.java new file mode 100644 index 0000000..2670d26 --- /dev/null +++ b/src/main/java/com/github/gtexpert/testmod/core/CoreMod.java @@ -0,0 +1,65 @@ +package com.github.gtexpert.testmod.core; + +import java.io.*; +import java.util.Map; +import java.util.Properties; + +import net.minecraftforge.fml.relauncher.IFMLLoadingPlugin; + +import org.jetbrains.annotations.Nullable; + +import com.github.gtexpert.testmod.api.ModValues; +import com.github.gtexpert.testmod.api.util.ModLog; + +public class CoreMod implements IFMLLoadingPlugin { + + static Properties coremodConfig = new Properties(); + public static boolean downloadOnlyOnce; + + @Override + public String[] getASMTransformerClass() { + ModLog.logger.info("CoreMod: getASMTransformerClass() called"); + return new String[] {}; + } + + @Override + public String getModContainerClass() { + return null; + } + + @Nullable + @Override + public String getSetupClass() { + ModLog.logger.info("CoreMod: getSetupClass() called, returning DepLoader"); + return null; + } + + @Override + public void injectData(Map data) { + ModLog.logger.info("CoreMod: injectData() called"); + coremodConfig.setProperty("downloadOnlyOnce", "true"); + File mcLocation = (File) data.get("mcLocation"); + File configDir = new File(mcLocation, "config"); + // noinspection ResultOfMethodCallIgnored + configDir.mkdir(); + File config = new File(configDir, ModValues.MODID + "/CoreMod.properties"); + try (Reader r = new FileReader(config)) { + coremodConfig.load(r); + } catch (FileNotFoundException ignored) { + // not a problem + } catch (IOException e) { + ModLog.logger.warn("Can't read coremod config. Proceeding with defaults!", e); + } + try (Writer r = new FileWriter(config)) { + coremodConfig.store(r, "Config file for GTExpert CoreMod"); + } catch (IOException e) { + ModLog.logger.warn("Can't write coremod config. Changes may not have been saved!", e); + } + downloadOnlyOnce = "true".equalsIgnoreCase(coremodConfig.getProperty("downloadOnlyOnce")); + } + + @Override + public String getAccessTransformerClass() { + return null; + } +} diff --git a/src/main/java/com/github/gtexpert/testmod/core/CoreModule.java b/src/main/java/com/github/gtexpert/testmod/core/CoreModule.java new file mode 100644 index 0000000..19662c4 --- /dev/null +++ b/src/main/java/com/github/gtexpert/testmod/core/CoreModule.java @@ -0,0 +1,46 @@ +package com.github.gtexpert.testmod.core; + +import net.minecraftforge.fml.common.SidedProxy; +import net.minecraftforge.fml.common.event.FMLConstructionEvent; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +import com.github.gtexpert.testmod.Tags; +import com.github.gtexpert.testmod.api.ModValues; +import com.github.gtexpert.testmod.api.modules.IModule; +import com.github.gtexpert.testmod.api.modules.TModule; +import com.github.gtexpert.testmod.common.CommonProxy; +import com.github.gtexpert.testmod.modules.Modules; + +@TModule( + moduleID = Modules.MODULE_CORE, + containerID = ModValues.MODID, + name = "TestMod Core", + description = "Core of TestMod", + coreModule = true) +public class CoreModule implements IModule { + + public static final Logger logger = LogManager.getLogger(Tags.MODNAME + " Core"); + @SidedProxy(modId = ModValues.MODID, + clientSide = "com.github.gtexpert.testmod.client.ClientProxy", + serverSide = "com.github.gtexpert.testmod.common.CommonProxy") + public static CommonProxy proxy; + + @Override + public @NotNull Logger getLogger() { + return logger; + } + + @Override + public void construction(FMLConstructionEvent event) {} + + @Override + public void preInit(FMLPreInitializationEvent event) { + proxy.preInit(event); + + logger.info("Hello World!"); + } +} diff --git a/src/main/java/com/github/gtexpert/testmod/modules/BaseModule.java b/src/main/java/com/github/gtexpert/testmod/modules/BaseModule.java new file mode 100644 index 0000000..06e687e --- /dev/null +++ b/src/main/java/com/github/gtexpert/testmod/modules/BaseModule.java @@ -0,0 +1,20 @@ +package com.github.gtexpert.testmod.modules; + +import java.util.Collections; +import java.util.Set; + +import net.minecraft.util.ResourceLocation; + +import org.jetbrains.annotations.NotNull; + +import com.github.gtexpert.testmod.api.modules.IModule; +import com.github.gtexpert.testmod.api.util.ModUtility; + +public abstract class BaseModule implements IModule { + + @NotNull + @Override + public Set getDependencyUids() { + return Collections.singleton(ModUtility.id(Modules.MODULE_CORE)); + } +} diff --git a/src/main/java/com/github/gtexpert/testmod/modules/ModuleManager.java b/src/main/java/com/github/gtexpert/testmod/modules/ModuleManager.java new file mode 100644 index 0000000..b804422 --- /dev/null +++ b/src/main/java/com/github/gtexpert/testmod/modules/ModuleManager.java @@ -0,0 +1,458 @@ +package com.github.gtexpert.testmod.modules; + +import java.io.File; +import java.util.*; +import java.util.stream.Collectors; + +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.crafting.IRecipe; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.common.config.Property; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.discovery.ASMDataTable; +import net.minecraftforge.fml.common.event.*; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + +import com.github.gtexpert.testmod.api.ModValues; +import com.github.gtexpert.testmod.api.modules.*; + +public class ModuleManager implements IModuleManager { + + private static final ModuleManager INSTANCE = new ModuleManager(); + private static final String MODULE_CFG_FILE_NAME = "modules.cfg"; + private static final String MODULE_CFG_CATEGORY_NAME = "modules"; + private static File configFolder; + + private Map containers = new LinkedHashMap<>(); + private final Map sortedModules = new LinkedHashMap<>(); + private final Set loadedModules = new LinkedHashSet<>(); + + private IModuleContainer currentContainer; + + private ModuleStage currentStage = ModuleStage.C_SETUP; + private final Logger logger = LogManager.getLogger("GTExpert Module Loader"); + private Configuration config; + + private ModuleManager() {} + + public static ModuleManager getInstance() { + return INSTANCE; + } + + @Override + public boolean isModuleEnabled(ResourceLocation id) { + return sortedModules.containsKey(id); + } + + public boolean isModuleEnabled(IModule module) { + TModule annotation = module.getClass().getAnnotation(TModule.class); + String comment = getComment(module); + Property prop = getConfiguration().get(MODULE_CFG_CATEGORY_NAME, + annotation.containerID() + ":" + annotation.moduleID(), true, comment); + return prop.getBoolean(); + } + + @Override + public IModuleContainer getLoadedContainer() { + return currentContainer; + } + + @Override + public ModuleStage getStage() { + return currentStage; + } + + @Override + public boolean hasPassedStage(ModuleStage stage) { + return currentStage.ordinal() > stage.ordinal(); + } + + @Override + public void registerContainer(IModuleContainer container) { + if (currentStage != ModuleStage.C_SETUP) { + logger.error("Failed to register module container {}, as module loading has already begun", container); + return; + } + Preconditions.checkNotNull(container); + containers.put(container.getID(), container); + } + + public void setup(ASMDataTable asmDataTable, File configDirectory) { + // find and register all containers registered with the @ModuleContainer annotation, then sort them by container + // name + discoverContainers(asmDataTable); + containers = containers.entrySet().stream() + .sorted(Map.Entry.comparingByKey()) + .collect(Collectors.toMap( + Map.Entry::getKey, Map.Entry::getValue, (a, b) -> a, LinkedHashMap::new)); + + currentStage = ModuleStage.M_SETUP; + configFolder = new File(configDirectory, ModValues.MODID); + Map> modules = getModules(asmDataTable); + configureModules(modules); + + for (IModule module : loadedModules) { + currentContainer = containers.get(getContainerID(module)); + module.getLogger().debug("Registering event handlers"); + for (Class clazz : module.getEventBusSubscribers()) { + MinecraftForge.EVENT_BUS.register(clazz); + } + } + } + + public void onConstruction(FMLConstructionEvent event) { + currentStage = ModuleStage.CONSTRUCTION; + for (IModule module : loadedModules) { + currentContainer = containers.get(getContainerID(module)); + module.getLogger().debug("Construction start"); + module.construction(event); + module.getLogger().debug("Construction complete"); + } + } + + public void onPreInit(FMLPreInitializationEvent event) { + currentStage = ModuleStage.PRE_INIT; + // Separate loops for strict ordering + for (IModule module : loadedModules) { + currentContainer = containers.get(getContainerID(module)); + module.getLogger().debug("Registering packets"); + module.registerPackets(); + } + for (IModule module : loadedModules) { + currentContainer = containers.get(getContainerID(module)); + module.getLogger().debug("Pre-init start"); + module.preInit(event); + module.getLogger().debug("Pre-init complete"); + } + } + + public void onInit(FMLInitializationEvent event) { + currentStage = ModuleStage.INIT; + for (IModule module : loadedModules) { + currentContainer = containers.get(getContainerID(module)); + module.getLogger().debug("Init start"); + module.init(event); + module.getLogger().debug("Init complete"); + } + } + + public void onPostInit(FMLPostInitializationEvent event) { + currentStage = ModuleStage.POST_INIT; + for (IModule module : loadedModules) { + currentContainer = containers.get(getContainerID(module)); + module.getLogger().debug("Post-init start"); + module.postInit(event); + module.getLogger().debug("Post-init complete"); + } + } + + public void onLoadComplete(FMLLoadCompleteEvent event) { + currentStage = ModuleStage.FINISHED; + for (IModule module : loadedModules) { + currentContainer = containers.get(getContainerID(module)); + module.getLogger().debug("Load-complete start"); + module.loadComplete(event); + module.getLogger().debug("Load-complete complete"); + } + } + + public void onServerAboutToStart(FMLServerAboutToStartEvent event) { + currentStage = ModuleStage.SERVER_ABOUT_TO_START; + for (IModule module : loadedModules) { + currentContainer = containers.get(getContainerID(module)); + module.getLogger().debug("Server-about-to-start start"); + module.serverAboutToStart(event); + module.getLogger().debug("Server-about-to-start complete"); + } + } + + public void onServerStarting(FMLServerStartingEvent event) { + currentStage = ModuleStage.SERVER_STARTING; + for (IModule module : loadedModules) { + currentContainer = containers.get(getContainerID(module)); + module.getLogger().debug("Server-starting start"); + module.serverStarting(event); + module.getLogger().debug("Server-starting complete"); + } + } + + public void onServerStarted(FMLServerStartedEvent event) { + currentStage = ModuleStage.SERVER_STARTED; + for (IModule module : loadedModules) { + currentContainer = containers.get(getContainerID(module)); + module.getLogger().debug("Server-started start"); + module.serverStarted(event); + module.getLogger().debug("Server-started complete"); + } + } + + public void onServerStopping(FMLServerStoppingEvent event) { + for (IModule module : loadedModules) { + currentContainer = containers.get(getContainerID(module)); + module.serverStopping(event); + } + } + + public void onServerStopped(FMLServerStoppedEvent event) { + for (IModule module : loadedModules) { + currentContainer = containers.get(getContainerID(module)); + module.serverStopped(event); + } + } + + public void processIMC(ImmutableList messages) { + for (FMLInterModComms.IMCMessage message : messages) { + for (IModule module : loadedModules) { + if (module.processIMC(message)) { + break; + } + } + } + } + + public void registerBlocks(RegistryEvent.Register event) { + for (IModule module : loadedModules) { + currentContainer = containers.get(getContainerID(module)); + module.registerBlocks(event); + } + } + + public void registerItems(RegistryEvent.Register event) { + for (IModule module : loadedModules) { + currentContainer = containers.get(getContainerID(module)); + module.registerItems(event); + } + } + + public void registerRecipesHighest(RegistryEvent.Register event) { + for (IModule module : loadedModules) { + currentContainer = containers.get(getContainerID(module)); + module.registerRecipesHighest(event); + } + } + + public void registerRecipesHigh(RegistryEvent.Register event) { + for (IModule module : loadedModules) { + currentContainer = containers.get(getContainerID(module)); + module.registerRecipesHigh(event); + } + } + + public void registerRecipesNormal(RegistryEvent.Register event) { + for (IModule module : loadedModules) { + currentContainer = containers.get(getContainerID(module)); + module.registerRecipesNormal(event); + } + } + + public void registerRecipesLow(RegistryEvent.Register event) { + for (IModule module : loadedModules) { + currentContainer = containers.get(getContainerID(module)); + module.registerRecipesLow(event); + } + } + + public void registerRecipesLowest(RegistryEvent.Register event) { + for (IModule module : loadedModules) { + currentContainer = containers.get(getContainerID(module)); + module.registerRecipesLowest(event); + } + } + + private void configureModules(Map> modules) { + Locale locale = Locale.getDefault(); + Locale.setDefault(Locale.ENGLISH); + Set toLoad = new LinkedHashSet<>(); + Set modulesToLoad = new LinkedHashSet<>(); + Configuration config = getConfiguration(); + config.load(); + config.addCustomCategoryComment(MODULE_CFG_CATEGORY_NAME, + "Module configuration file. Can individually enable/disable modules from GTExpert and its addons"); + + for (IModuleContainer container : containers.values()) { + String containerID = container.getID(); + List containerModules = modules.get(containerID); + IModule coreModule = getCoreModule(containerModules); + if (coreModule == null) { + throw new IllegalStateException("Could not find core module for module container " + containerID); + } else { + containerModules.remove(coreModule); + containerModules.add(0, coreModule); + } + + logger.debug("containterModule size: " + containerModules.size()); + + // Remove disabled modules and gather potential modules to load + Iterator iterator = containerModules.iterator(); + while (iterator.hasNext()) { + IModule module = iterator.next(); + if (!isModuleEnabled(module)) { + iterator.remove(); + logger.debug("Module disabled: {}", module); + continue; + } + TModule annotation = module.getClass().getAnnotation(TModule.class); + toLoad.add(new ResourceLocation(containerID, annotation.moduleID())); + modulesToLoad.add(module); + } + } + + // Check any module dependencies + Iterator iterator; + boolean changed; + do { + changed = false; + iterator = modulesToLoad.iterator(); + while (iterator.hasNext()) { + IModule module = iterator.next(); + + // Check module dependencies + Set dependencies = module.getDependencyUids(); + if (!toLoad.containsAll(dependencies)) { + iterator.remove(); + changed = true; + TModule annotation = module.getClass().getAnnotation(TModule.class); + String moduleID = annotation.moduleID(); + toLoad.remove(new ResourceLocation(moduleID)); + logger.debug("Module {} is missing at least one of module dependencies: {}, skipping loading...", + moduleID, dependencies); + } + } + } while (changed); + + // Sort modules by their module dependencies + do { + changed = false; + iterator = modulesToLoad.iterator(); + while (iterator.hasNext()) { + IModule module = iterator.next(); + if (sortedModules.keySet().containsAll(module.getDependencyUids())) { + iterator.remove(); + TModule annotation = module.getClass().getAnnotation(TModule.class); + sortedModules.put(new ResourceLocation(annotation.containerID(), annotation.moduleID()), module); + changed = true; + break; + } + } + } while (changed); + + loadedModules.addAll(sortedModules.values()); + + if (config.hasChanged()) { + config.save(); + } + Locale.setDefault(locale); + } + + private static IModule getCoreModule(List modules) { + for (IModule module : modules) { + TModule annotation = module.getClass().getAnnotation(TModule.class); + if (annotation.coreModule()) { + return module; + } + } + return null; + } + + private static String getContainerID(IModule module) { + TModule annotation = module.getClass().getAnnotation(TModule.class); + return annotation.containerID(); + } + + private Map> getModules(ASMDataTable table) { + List instances = getInstances(table); + Map> modules = new LinkedHashMap<>(); + for (IModule module : instances) { + TModule info = module.getClass().getAnnotation(TModule.class); + modules.computeIfAbsent(info.containerID(), k -> new ArrayList<>()).add(module); + } + return modules; + } + + @SuppressWarnings("unchecked") + private List getInstances(ASMDataTable table) { + Set dataSet = table.getAll(TModule.class.getCanonicalName()); + List instances = new ArrayList<>(); + for (ASMDataTable.ASMData data : dataSet) { + String moduleID = (String) data.getAnnotationInfo().get("moduleID"); + List modDependencies = (ArrayList) data.getAnnotationInfo().get("modDependencies"); + if (modDependencies == null || modDependencies.stream().allMatch(Loader::isModLoaded)) { + try { + Class clazz = Class.forName(data.getClassName()); + instances.add((IModule) clazz.newInstance()); + } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) { + logger.error("Could not initialize module " + moduleID, e); + } + } else { + logger.debug("Module {} is missing at least one of mod dependencies: {}, skipping loading...", moduleID, + modDependencies); + } + } + return instances.stream().sorted((m1, m2) -> { + TModule m1a = m1.getClass().getAnnotation(TModule.class); + TModule m2a = m2.getClass().getAnnotation(TModule.class); + return (m1a.containerID() + ":" + m1a.moduleID()).compareTo(m2a.containerID() + ":" + m2a.moduleID()); + }).collect(Collectors.toCollection(ArrayList::new)); + } + + private void discoverContainers(ASMDataTable table) { + Set dataSet = table.getAll(ModuleContainer.class.getCanonicalName()); + for (ASMDataTable.ASMData data : dataSet) { + try { + Class clazz = Class.forName(data.getClassName()); + registerContainer((IModuleContainer) clazz.newInstance()); + } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) { + logger.error("Could not initialize module container " + data.getClassName(), e); + } + } + } + + private String getComment(IModule module) { + TModule annotation = module.getClass().getAnnotation(TModule.class); + + String comment = annotation.description(); + Set dependencies = module.getDependencyUids(); + if (!dependencies.isEmpty()) { + Iterator iterator = dependencies.iterator(); + StringBuilder builder = new StringBuilder(comment); + builder.append("\n"); + builder.append("Module Dependencies: [ "); + builder.append(iterator.next()); + while (iterator.hasNext()) { + builder.append(", ").append(iterator.next()); + } + builder.append(" ]"); + comment = builder.toString(); + } + String[] modDependencies = annotation.modDependencies(); + if (modDependencies != null && modDependencies.length > 0) { + Iterator iterator = Arrays.stream(modDependencies).iterator(); + StringBuilder builder = new StringBuilder(comment); + builder.append("\n"); + builder.append("Mod Dependencies: [ "); + builder.append(iterator.next()); + while (iterator.hasNext()) { + builder.append(", ").append(iterator.next()); + } + builder.append(" ]"); + comment = builder.toString(); + } + return comment; + } + + private Configuration getConfiguration() { + if (config == null) { + config = new Configuration(new File(configFolder, MODULE_CFG_FILE_NAME)); + } + return config; + } +} diff --git a/src/main/java/com/github/gtexpert/testmod/modules/Modules.java b/src/main/java/com/github/gtexpert/testmod/modules/Modules.java new file mode 100644 index 0000000..aebfb4a --- /dev/null +++ b/src/main/java/com/github/gtexpert/testmod/modules/Modules.java @@ -0,0 +1,16 @@ +package com.github.gtexpert.testmod.modules; + +import com.github.gtexpert.testmod.api.ModValues; +import com.github.gtexpert.testmod.api.modules.IModuleContainer; + +public class Modules implements IModuleContainer { + + public static final String MODULE_CORE = "core"; + public static final String MODULE_TOOLS = "tools"; + public static final String MODULE_INTEGRATION = "integration"; + + @Override + public String getID() { + return ModValues.MODID; + } +} diff --git a/src/main/java/com/myname/mymodid/MyMod.java b/src/main/java/com/myname/mymodid/MyMod.java deleted file mode 100644 index 4461cc2..0000000 --- a/src/main/java/com/myname/mymodid/MyMod.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.myname.mymodid; - -import net.minecraft.block.Block; -import net.minecraft.item.Item; -import net.minecraft.item.crafting.IRecipe; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.RegistryEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.Mod.EventHandler; -import net.minecraftforge.fml.common.event.FMLInitializationEvent; -import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; -import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; -import net.minecraftforge.fml.common.event.FMLServerStartingEvent; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -@Mod(modid = Tags.MODID, version = Tags.VERSION, name = Tags.MODNAME, acceptedMinecraftVersions = "[1.12.2]") -public class MyMod { - - public static final Logger LOGGER = LogManager.getLogger(Tags.MODID); - - @EventHandler - // preInit "Run before anything else. Read your config, create blocks, items, etc. (Remove if not needed) - public void preInit(FMLPreInitializationEvent event) { - // register to the event bus so that we can listen to events - MinecraftForge.EVENT_BUS.register(this); - LOGGER.info("I am " + Tags.MODNAME + " + at version " + Tags.VERSION); - } - - @SubscribeEvent - // Register recipes here (Remove if not needed) - public void registerRecipes(RegistryEvent.Register event) { - - } - - @SubscribeEvent - // Register items here (Remove if not needed) - public void registerItems(RegistryEvent.Register event) { - - } - - @SubscribeEvent - // Register blocks here (Remove if not needed) - public void registerBlocks(RegistryEvent.Register event) { - - } - - @EventHandler - // load "Do your mod setup. Build whatever data structures you care about." (Remove if not needed) - public void init(FMLInitializationEvent event) { - } - - @EventHandler - // postInit "Handle interaction with other mods, complete your setup based on this." (Remove if not needed) - public void postInit(FMLPostInitializationEvent event) { - } - - @EventHandler - // register server commands in this event handler (Remove if not needed) - public void serverStarting(FMLServerStartingEvent event) { - } -}