From fc838ce66a0e8a406fd8b988935395b45e1246ff Mon Sep 17 00:00:00 2001 From: Christian Koop Date: Sat, 12 Jun 2021 15:16:07 +0200 Subject: [PATCH 01/12] Full recode (v2.0.0-ALPHA) --- .DS_Store | Bin 6148 -> 0 bytes .editorconfig | 311 +++++++++++ .github/dependabot.yml | 11 + .github/workflows/build.yml | 35 ++ .gitignore | 9 +- LICENSE | 2 +- README.MD | 5 - README.md | 52 ++ modules/epicanchors-api/pom.xml | 31 ++ .../java/com/songoda/epicanchors/Anchor.java | 127 +++++ .../epicanchors/AnchorAccessCheck.java | 9 + .../songoda/epicanchors/AnchorManager.java | 486 ++++++++++++++++++ .../com/songoda/epicanchors/AnchorNMS.java | 82 +++ .../epicanchors/files/DataManager.java | 265 ++++++++++ .../songoda/epicanchors/files}/Settings.java | 68 +-- .../files/migration/AnchorMigration.java | 152 ++++++ .../files/migration/_1_InitialMigration.java | 30 ++ .../songoda/epicanchors/utils/Callback.java | 7 + .../epicanchors/utils/ReflectionUtils.java | 52 ++ .../songoda/epicanchors/utils/ThreadSync.java | 30 ++ .../epicanchors/utils/UpdateCallback.java | 7 + .../com/songoda/epicanchors/utils/Utils.java | 60 +++ modules/epicanchors-plugin/pom.xml | 221 ++++++++ .../com/songoda/epicanchors/EpicAnchors.java | 208 ++++++++ .../commands/EpicAnchorsCommand.java | 25 +- .../epicanchors/commands/sub/GiveCommand.java | 112 ++++ .../commands/sub/ReloadCommand.java | 24 +- .../commands/sub/SettingsCommand.java | 18 +- .../epicanchors/commands/sub/ShowCommand.java | 31 +- .../songoda/epicanchors/guis/AnchorGui.java | 135 +++++ .../guis/DestroyConfirmationGui.java | 64 +++ .../epicanchors/listener/AnchorListener.java | 126 +++++ .../epicanchors/listener/BlockListener.java | 77 +++ .../epicanchors/listener/DebugListener.java | 154 ++++++ .../epicanchors/listener/WorldListener.java | 30 ++ .../songoda/epicanchors/tasks/AnchorTask.java | 96 ++++ .../epicanchors/tasks/VisualizeTask.java | 113 ++++ .../src}/main/resources/en_US.lang | 9 +- .../src/main/resources/plugin.yml | 29 ++ modules/nms/epicanchors-v1_10_R1/pom.xml | 37 ++ .../main/java/epicanchors/nms/v1_10_R1.java | 267 ++++++++++ modules/nms/epicanchors-v1_11_R1/pom.xml | 37 ++ .../main/java/epicanchors/nms/v1_11_R1.java | 262 ++++++++++ modules/nms/epicanchors-v1_12_R1/pom.xml | 37 ++ .../main/java/epicanchors/nms/v1_12_R1.java | 266 ++++++++++ modules/nms/epicanchors-v1_13_R1/pom.xml | 37 ++ .../main/java/epicanchors/nms/v1_13_R1.java | 282 ++++++++++ modules/nms/epicanchors-v1_13_R2/pom.xml | 37 ++ .../main/java/epicanchors/nms/v1_13_R2.java | 294 +++++++++++ modules/nms/epicanchors-v1_14_R1/pom.xml | 37 ++ .../main/java/epicanchors/nms/v1_14_R1.java | 304 +++++++++++ modules/nms/epicanchors-v1_15_R1/pom.xml | 37 ++ .../main/java/epicanchors/nms/v1_15_R1.java | 303 +++++++++++ modules/nms/epicanchors-v1_16_R1/pom.xml | 37 ++ .../main/java/epicanchors/nms/v1_16_R1.java | 302 +++++++++++ modules/nms/epicanchors-v1_16_R2/pom.xml | 37 ++ .../main/java/epicanchors/nms/v1_16_R2.java | 299 +++++++++++ modules/nms/epicanchors-v1_16_R3/pom.xml | 37 ++ .../main/java/epicanchors/nms/v1_16_R3.java | 305 +++++++++++ modules/nms/epicanchors-v1_8_R1/pom.xml | 37 ++ .../main/java/epicanchors/nms/v1_8_R1.java | 251 +++++++++ modules/nms/epicanchors-v1_8_R2/pom.xml | 37 ++ .../main/java/epicanchors/nms/v1_8_R2.java | 248 +++++++++ modules/nms/epicanchors-v1_8_R3/pom.xml | 37 ++ .../main/java/epicanchors/nms/v1_8_R3.java | 249 +++++++++ modules/nms/epicanchors-v1_9_R1/pom.xml | 37 ++ .../main/java/epicanchors/nms/v1_9_R1.java | 259 ++++++++++ modules/nms/epicanchors-v1_9_R2/pom.xml | 37 ++ .../main/java/epicanchors/nms/v1_9_R2.java | 261 ++++++++++ pom.xml | 166 +++--- .../com/songoda/epicanchors/EpicAnchors.java | 217 -------- .../songoda/epicanchors/anchor/Anchor.java | 110 ---- .../epicanchors/anchor/AnchorManager.java | 45 -- .../epicanchors/commands/CommandGive.java | 90 ---- .../songoda/epicanchors/gui/GUIOverview.java | 92 ---- .../epicanchors/listeners/BlockListeners.java | 40 -- .../listeners/InteractListeners.java | 71 --- .../listeners/PortalListeners.java | 21 - .../songoda/epicanchors/tasks/AnchorTask.java | 145 ------ .../epicanchors/tasks/VisualizeTask.java | 104 ---- .../songoda/epicanchors/utils/Methods.java | 85 --- src/main/resources/SettingDefinitions.yml | 0 src/main/resources/plugin.yml | 13 - 83 files changed, 7995 insertions(+), 1214 deletions(-) delete mode 100644 .DS_Store create mode 100644 .editorconfig create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/build.yml delete mode 100644 README.MD create mode 100644 README.md create mode 100644 modules/epicanchors-api/pom.xml create mode 100644 modules/epicanchors-api/src/main/java/com/songoda/epicanchors/Anchor.java create mode 100644 modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorAccessCheck.java create mode 100644 modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorManager.java create mode 100644 modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorNMS.java create mode 100644 modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/DataManager.java rename {src/main/java/com/songoda/epicanchors/settings => modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files}/Settings.java (61%) create mode 100644 modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/migration/AnchorMigration.java create mode 100644 modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/migration/_1_InitialMigration.java create mode 100644 modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/Callback.java create mode 100644 modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/ReflectionUtils.java create mode 100644 modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/ThreadSync.java create mode 100644 modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/UpdateCallback.java create mode 100644 modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/Utils.java create mode 100644 modules/epicanchors-plugin/pom.xml create mode 100644 modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/EpicAnchors.java rename src/main/java/com/songoda/epicanchors/commands/CommandEpicAnchors.java => modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/EpicAnchorsCommand.java (53%) create mode 100644 modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/GiveCommand.java rename src/main/java/com/songoda/epicanchors/commands/CommandReload.java => modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/ReloadCommand.java (55%) rename src/main/java/com/songoda/epicanchors/commands/CommandSettings.java => modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/SettingsCommand.java (69%) rename src/main/java/com/songoda/epicanchors/commands/CommandShow.java => modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/ShowCommand.java (57%) create mode 100644 modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/guis/AnchorGui.java create mode 100644 modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/guis/DestroyConfirmationGui.java create mode 100644 modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/AnchorListener.java create mode 100644 modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/BlockListener.java create mode 100644 modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/DebugListener.java create mode 100644 modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/WorldListener.java create mode 100644 modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/tasks/AnchorTask.java create mode 100644 modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/tasks/VisualizeTask.java rename {src => modules/epicanchors-plugin/src}/main/resources/en_US.lang (73%) create mode 100644 modules/epicanchors-plugin/src/main/resources/plugin.yml create mode 100644 modules/nms/epicanchors-v1_10_R1/pom.xml create mode 100644 modules/nms/epicanchors-v1_10_R1/src/main/java/epicanchors/nms/v1_10_R1.java create mode 100644 modules/nms/epicanchors-v1_11_R1/pom.xml create mode 100644 modules/nms/epicanchors-v1_11_R1/src/main/java/epicanchors/nms/v1_11_R1.java create mode 100644 modules/nms/epicanchors-v1_12_R1/pom.xml create mode 100644 modules/nms/epicanchors-v1_12_R1/src/main/java/epicanchors/nms/v1_12_R1.java create mode 100644 modules/nms/epicanchors-v1_13_R1/pom.xml create mode 100644 modules/nms/epicanchors-v1_13_R1/src/main/java/epicanchors/nms/v1_13_R1.java create mode 100644 modules/nms/epicanchors-v1_13_R2/pom.xml create mode 100644 modules/nms/epicanchors-v1_13_R2/src/main/java/epicanchors/nms/v1_13_R2.java create mode 100644 modules/nms/epicanchors-v1_14_R1/pom.xml create mode 100644 modules/nms/epicanchors-v1_14_R1/src/main/java/epicanchors/nms/v1_14_R1.java create mode 100644 modules/nms/epicanchors-v1_15_R1/pom.xml create mode 100644 modules/nms/epicanchors-v1_15_R1/src/main/java/epicanchors/nms/v1_15_R1.java create mode 100644 modules/nms/epicanchors-v1_16_R1/pom.xml create mode 100644 modules/nms/epicanchors-v1_16_R1/src/main/java/epicanchors/nms/v1_16_R1.java create mode 100644 modules/nms/epicanchors-v1_16_R2/pom.xml create mode 100644 modules/nms/epicanchors-v1_16_R2/src/main/java/epicanchors/nms/v1_16_R2.java create mode 100644 modules/nms/epicanchors-v1_16_R3/pom.xml create mode 100644 modules/nms/epicanchors-v1_16_R3/src/main/java/epicanchors/nms/v1_16_R3.java create mode 100644 modules/nms/epicanchors-v1_8_R1/pom.xml create mode 100644 modules/nms/epicanchors-v1_8_R1/src/main/java/epicanchors/nms/v1_8_R1.java create mode 100644 modules/nms/epicanchors-v1_8_R2/pom.xml create mode 100644 modules/nms/epicanchors-v1_8_R2/src/main/java/epicanchors/nms/v1_8_R2.java create mode 100644 modules/nms/epicanchors-v1_8_R3/pom.xml create mode 100644 modules/nms/epicanchors-v1_8_R3/src/main/java/epicanchors/nms/v1_8_R3.java create mode 100644 modules/nms/epicanchors-v1_9_R1/pom.xml create mode 100644 modules/nms/epicanchors-v1_9_R1/src/main/java/epicanchors/nms/v1_9_R1.java create mode 100644 modules/nms/epicanchors-v1_9_R2/pom.xml create mode 100644 modules/nms/epicanchors-v1_9_R2/src/main/java/epicanchors/nms/v1_9_R2.java delete mode 100644 src/main/java/com/songoda/epicanchors/EpicAnchors.java delete mode 100644 src/main/java/com/songoda/epicanchors/anchor/Anchor.java delete mode 100644 src/main/java/com/songoda/epicanchors/anchor/AnchorManager.java delete mode 100644 src/main/java/com/songoda/epicanchors/commands/CommandGive.java delete mode 100644 src/main/java/com/songoda/epicanchors/gui/GUIOverview.java delete mode 100644 src/main/java/com/songoda/epicanchors/listeners/BlockListeners.java delete mode 100644 src/main/java/com/songoda/epicanchors/listeners/InteractListeners.java delete mode 100644 src/main/java/com/songoda/epicanchors/listeners/PortalListeners.java delete mode 100644 src/main/java/com/songoda/epicanchors/tasks/AnchorTask.java delete mode 100644 src/main/java/com/songoda/epicanchors/tasks/VisualizeTask.java delete mode 100644 src/main/java/com/songoda/epicanchors/utils/Methods.java delete mode 100644 src/main/resources/SettingDefinitions.yml delete mode 100644 src/main/resources/plugin.yml diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 9b04f28167e0e7f39dff59ec3bc6464cd5915391..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK-D(p-6h4#0b`p{1Ladj2BY06tYeia$uuYSTfQq=H7b@*;5}Jk0PRMSIHjV5} zpP{~jPvRr^AU=S8^AmA*)hiJRbKuN(_RM!qm@n+i4iT}|w7*N#Bq9!%SZiSTg~@s8 zC99Z>oMfuU5yjM_Aqkq4*fwDmunPQd3dnbNgE};(5O40!?{7le$c-rKMxqx)A^=lv z6Nm7--;^ODTBk?UrDODXLLPMr>`x{37`wv=z2B94v&{m#PS4Qyh}!fRxQ(%$@6Rp^ z6;(>G_w)*^uLaf`rR0NmMgvOo+=~AvZZJ#6MvKqEI0}<=XXgv6RBPAP);VwR#*M}s zZzyJ7>ZjABA~83{3o7i0DV`2QR|G?4)_~Sj4Fx#)F9}4*LU8UcU_EzL>Sd zH0~#=kEbU%uk-pz^VWR6x8>YF*k5cp^ZkQ+i1!{W7InUPXZKc^%$|2x0G|L2SBlU2Yfuu=-JTH9;4uq1P~mKG<^S_gg# qmnM0cMpc5r9LFkYOeB diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9737e6f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,311 @@ +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +# max_line_length = 120 +tab_width = 4 +trim_trailing_whitespace = true +ij_continuation_indent_size = 8 +ij_formatter_off_tag = @formatter:off +ij_formatter_on_tag = @formatter:on +ij_formatter_tags_enabled = false +ij_smart_tabs = false +ij_visual_guides = none +ij_wrap_on_typing = false + +[*.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 = false +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_extends_list = false +ij_java_align_multiline_for = true +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 = true +ij_java_align_multiline_ternary_operation = false +ij_java_align_multiline_text_blocks = false +ij_java_align_multiline_throws_list = false +ij_java_align_subsequent_simple_methods = false +ij_java_align_throws_keyword = false +ij_java_annotation_parameter_wrap = off +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 = off +ij_java_assert_statement_colon_on_next_line = false +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 = off +ij_java_blank_lines_after_anonymous_class_header = 0 +ij_java_blank_lines_after_class_header = 0 +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 = 0 +ij_java_block_brace_style = end_of_line +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 = off +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 = 15 +ij_java_class_names_in_javadoc = 1 +ij_java_do_not_indent_top_level_class_members = false +ij_java_do_not_wrap_after_single_annotation = 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 = true +ij_java_doc_add_blank_line_after_return = true +ij_java_doc_add_p_tag_on_empty_lines = true +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 = true +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 = off +ij_java_extends_keyword_wrap = off +ij_java_extends_list_wrap = off +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 = *, |, 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 = 0 +ij_java_keep_blank_lines_between_package_declaration_and_header = 0 +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 = true +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 = false +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_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 = off +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 = off +ij_java_modifier_list_wrap = false +ij_java_names_count_to_use_import_on_demand = 9 +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 = true +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 = off +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_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 = true +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_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 = false +ij_java_spaces_within_braces = true +ij_java_spaces_within_brackets = false +ij_java_spaces_within_cast_parentheses = false +ij_java_spaces_within_catch_parentheses = 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 = off +ij_java_test_name_suffix = Test +ij_java_throws_keyword_wrap = off +ij_java_throws_list_wrap = off +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 = off +ij_java_visibility = public +ij_java_while_brace_force = never +ij_java_while_on_new_line = false +ij_java_wrap_comments = false +ij_java_wrap_first_method_in_call_chain = false +ij_java_wrap_long_lines = 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, *.pom, *.rng, *.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_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 + +[{*.markdown, *.md}] +indent_size = 2 +tab_width = 2 +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_keep_indents_on_empty_lines = false +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 + +[{*.yaml, *.yml, *.lang}] +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/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..2bdcc46 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "maven" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "monthly" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..8bce0e4 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,35 @@ +name: Build +on: + push: + branches: + - master + pull_request: + types: [ opened, synchronize, reopened ] +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v2 + with: + java-version: 11 + distribution: adopt + + - name: 'Cache: Maven-Repository' + uses: actions/cache@v2 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + + - name: Build with Maven + run: 'mvn -B -Duser.name="GitHub Runner on $GITHUB_REPOSITORY (id=$GITHUB_RUN_ID)" clean package' + + - name: 'Upload Build Artifact: EpicAnchors-*.jar' + uses: actions/upload-artifact@v2 + with: + name: EpicAnchors-artifacts + path: ./modules/epicanchors-plugin/target/EpicAnchors-*.jar diff --git a/.gitignore b/.gitignore index 6aabd47..6cbab07 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ -.idea/* -target/* -EpicAnchors.iml +/modules/*/target/ +/modules/nms/*/target/ + +# JetBrains IDEs +/.idea/ +*.iml diff --git a/LICENSE b/LICENSE index 2ddfa07..18b94c9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018 Brianna O’Keefe +Copyright (c) 2021 Songoda Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software with minimal restriction, including the rights to use, copy, modify or merge while excluding the rights to publish, (re)distribute, sub-license, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/README.MD b/README.MD deleted file mode 100644 index 1872f3f..0000000 --- a/README.MD +++ /dev/null @@ -1,5 +0,0 @@ -# EpicAnchors - -EpicAnchors allows your players to keep chunks loaded for a limited amount of time allowing redstone machines, mob grinders, spawners, and hoppers to all remain activated while the player is either out of normal range or offline. - -![N|Solid](https://i.imgur.com/jKtE7ZM.png) \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..deb9329 --- /dev/null +++ b/README.md @@ -0,0 +1,52 @@ + +
+EpicAnchors + +# EpicAnchors + +**Allow your players to keep chunks loaded for a limited amount of time for a cost.** +**Integrates with EpicSpawners to keep your mobs spawning even when you’re offline.** + + +[![Discord](https://img.shields.io/discord/293212540723396608?color=7289DA&label=Discord&logo=discord&logoColor=7289DA)](https://discord.gg/songoda) +[![Patreon](https://img.shields.io/badge/-Support_on_Patreon-F96854.svg?logo=patreon&style=flat&logoColor=white)](https://www.patreon.com/join/songoda) +
+[![Latest version](https://img.shields.io/github/v/tag/SpraxDev/EpicAnchors?include_prereleases&label=Latest&logo=github&labelColor=black)](https://songoda.com/marketplace/product/31) +[![GitHub last commit](https://img.shields.io/github/last-commit/SpraxDev/EpicAnchors?label=Last+commit)](https://github.com/SpraxDev/EpicAnchors/commits) +
+[![bStats Servers](https://img.shields.io/bstats/servers/4816?label=Servers)](https://bstats.org/plugin/bukkit/EpicAnchors/4816) +
+ +## Table of Contents + +* [Introduction](#introduction) +* [Marketplace](#marketplace) +* [Documentation](#documentation) +* [Support](#support) +* [Suggestions](#suggestions) + +## Introduction + +`// TODO: Write an introduction` + +## Marketplace + +You can visit [our marketplace](https://songoda.com/marketplace/product/31) to download EpicAnchors as well as take a +look at many other fantastic plugins which are sure to catch your eye. + +## Documentation + +You can find all the information about EpicAnchors, including dependencies, commands, permissions and incompatible +plugins on [our wiki](https://wiki.songoda.com/Epic_Anchors). + +Feel free to also contribute to the wiki as a way to help others in the community with using the plugin. + +## Support + +If you encounter any issues while using the plugin, feel free to create a ticket +on [our support desk](https://support.songoda.com). + +## Suggestions + +For suggestions about features you think should be added to the plugin to increase its functionality, feel free to +create a thread over on [our feedback site](https://feedback.songoda.com). diff --git a/modules/epicanchors-api/pom.xml b/modules/epicanchors-api/pom.xml new file mode 100644 index 0000000..f4a69cc --- /dev/null +++ b/modules/epicanchors-api/pom.xml @@ -0,0 +1,31 @@ + + + 4.0.0 + + + com.songoda + EpicAnchors + 2.0.0-ALPHA + ../../pom.xml + + jar + epicanchors-api + + + + org.spigotmc + spigot-api + 1.8-R0.1-SNAPSHOT + provided + + + + com.songoda + SongodaCore + 2.4.56 + compile + + + diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/Anchor.java b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/Anchor.java new file mode 100644 index 0000000..87b479b --- /dev/null +++ b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/Anchor.java @@ -0,0 +1,127 @@ +package com.songoda.epicanchors; + +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; +import java.util.UUID; + +public class Anchor { + private final int dbId; + + private final UUID owner; + + private final Location location; + private int ticksLeft; + + public Anchor(int dbId, @Nullable UUID owner, @NotNull Location location, int ticksLeft) { + if (dbId <= 0) throw new IllegalArgumentException("Invalid value for dbId"); + if (ticksLeft <= 0 && ticksLeft != -1) throw new IllegalArgumentException("Invalid value for ticksLeft"); + + Objects.requireNonNull(location.getWorld()); // Sanity check + + this.dbId = dbId; + + this.owner = owner; + + this.location = location; + this.ticksLeft = ticksLeft; + } + + /** + * This method is automatically synchronized with the server's main thread using + * {@link org.bukkit.scheduler.BukkitScheduler#runTask(Plugin, Runnable)} + * + * @see Bukkit#isPrimaryThread() + * @see org.bukkit.scheduler.BukkitScheduler#runTask(Plugin, Runnable) + */ + protected void init(AnchorNMS nms) { + if (Bukkit.isPrimaryThread()) { + nms.loadAnchoredChunk(getChunk()); + } else { + Bukkit.getScheduler().runTask(nms.plugin, () -> init(nms)); + } + } + + /** + * This method is automatically synchronized with the server's main thread using + * {@link org.bukkit.scheduler.BukkitScheduler#runTask(Plugin, Runnable)} + * + * @see Bukkit#isPrimaryThread() + * @see org.bukkit.scheduler.BukkitScheduler#runTask(Plugin, Runnable) + */ + protected void deInit(AnchorNMS nms) { + // TODO: Document that holograms are not removed or add boolean flag to remove them + + if (Bukkit.isPrimaryThread()) { + nms.unloadAnchoredChunk(getChunk()); + } else { + Bukkit.getScheduler().runTask(nms.plugin, () -> deInit(nms)); + } + } + + public int getDbId() { + return this.dbId; + } + + public UUID getOwner() { + return this.owner; + } + + public boolean isLegacy() { + return this.owner == null; + } + + public @NotNull Location getLocation() { + return this.location.clone(); + } + + public @NotNull World getWorld() { + return this.location.getWorld(); + } + + public @NotNull Chunk getChunk() { + return this.location.getChunk(); + } + + public int getTicksLeft() { + return this.ticksLeft; + } + + @SuppressWarnings("unused") + public void setTicksLeft(int ticksLeft) { + if (ticksLeft < 0) throw new IllegalArgumentException("Invalid value for ticksLeft"); + + this.ticksLeft = ticksLeft; + } + + @SuppressWarnings("UnusedReturnValue") + public int addTicksLeft(int ticks) { + if (!isInfinite()) { + this.ticksLeft += ticks; + } + + return this.ticksLeft; + } + + public int removeTicksLeft(int ticks) { + if (!isInfinite()) { + this.ticksLeft -= ticks; + + if (this.ticksLeft < 0) { + this.ticksLeft = 0; + } + } + + return this.ticksLeft; + } + + public boolean isInfinite() { + return this.ticksLeft == -1; + } +} diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorAccessCheck.java b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorAccessCheck.java new file mode 100644 index 0000000..e943eac --- /dev/null +++ b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorAccessCheck.java @@ -0,0 +1,9 @@ +package com.songoda.epicanchors; + +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public interface AnchorAccessCheck { + boolean check(@NotNull Anchor anchor, @NotNull UUID uuid); +} diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorManager.java b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorManager.java new file mode 100644 index 0000000..9a0fad0 --- /dev/null +++ b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorManager.java @@ -0,0 +1,486 @@ +package com.songoda.epicanchors; + +import com.songoda.core.SongodaPlugin; +import com.songoda.core.compatibility.CompatibleMaterial; +import com.songoda.core.compatibility.CompatibleParticleHandler; +import com.songoda.core.compatibility.CompatibleSound; +import com.songoda.core.hooks.HologramManager; +import com.songoda.core.nms.NmsManager; +import com.songoda.core.nms.nbt.NBTItem; +import com.songoda.core.utils.TextUtils; +import com.songoda.core.utils.TimeUtils; +import com.songoda.epicanchors.files.DataManager; +import com.songoda.epicanchors.files.Settings; +import com.songoda.epicanchors.utils.Callback; +import com.songoda.epicanchors.utils.UpdateCallback; +import com.songoda.epicanchors.utils.Utils; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +public class AnchorManager { + private static final String ERR_WORLD_NOT_READY = "EpicAnchors has not finished initializing that world yet"; + private static final String NBT_TICKS_KEY = "EpicAnchors_Ticks".toLowerCase(); + private static SongodaPlugin staticPluginInstance; // For internal use only TODO: Find a better way for doing this + + private final SongodaPlugin plugin; + private final DataManager dataManager; + private final AnchorNMS nms; + + private final Map> anchors = new HashMap<>(3); + private final Set visualizedChunk = new HashSet<>(); + private final List accessChecks = new LinkedList<>(); + + private boolean ready; + + public AnchorManager(SongodaPlugin plugin, DataManager dataManager, AnchorNMS nms) { + this.plugin = Objects.requireNonNull(plugin); + this.dataManager = Objects.requireNonNull(dataManager); + this.nms = Objects.requireNonNull(nms); + + staticPluginInstance = plugin; + } + + protected void saveAll() { + for (Set anchorSet : anchors.values()) { + this.dataManager.updateAnchors(anchorSet, null); + } + } + + protected void deInitAll() { + for (World world : anchors.keySet().toArray(new World[0])) { + deInitAnchors(world); + } + } + + protected void initAnchorsAsync(@NotNull World world, @Nullable UpdateCallback callback) { + if (this.anchors.containsKey(world)) { + if (callback != null) { + callback.accept(null); + } + + return; + } + + long start = System.nanoTime(); + + this.dataManager.getAnchors(world, (ex, result) -> { + if (ex == null) { + this.anchors.computeIfAbsent(world, k -> new HashSet<>()); + + for (Anchor anchor : result) { + anchor.init(this.nms); + + this.anchors.computeIfAbsent(anchor.getWorld(), k -> new HashSet<>()) + .add(anchor); + } + + long end = System.nanoTime(); + this.plugin.getLogger().info("Initialized anchors in world '" + world.getName() + "' " + + "(" + TimeUnit.NANOSECONDS.toMillis(end - start) + "ms)"); + + if (callback != null) { + callback.accept(null); + } + } else { + if (callback != null) { + callback.accept(ex); + } else { + Utils.logException(this.plugin, ex, "SQLite"); + } + } + }); + } + + protected void deInitAnchors(@NotNull World world) { + Set tmpAnchors = this.anchors.remove(world); + + if (tmpAnchors != null) { + this.dataManager.updateAnchors(tmpAnchors, null); + + for (Anchor anchor : tmpAnchors) { + anchor.deInit(this.nms); + } + } + } + + protected void setReady() { + this.ready = true; + + Bukkit.getScheduler().runTaskTimer(plugin, this::saveAll, 20L * 60 * 5, 20L * 60 * 5); + } + + public AnchorNMS getNMS() { + return this.nms; + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + public boolean isReady(World world) { + return this.ready && anchors.containsKey(world); + } + + /* Getter */ + + public Anchor[] getAnchors(@NotNull World world) { + Set set = anchors.get(world); + + if (set != null) { + return set.toArray(new Anchor[0]); + } + + return new Anchor[0]; + } + + public @Nullable Anchor getAnchor(@NotNull Block b) { + if (!isReady(b.getWorld())) { + throw new IllegalStateException(ERR_WORLD_NOT_READY); + } + + Location bLoc = b.getLocation(); + Set set = anchors.get(b.getWorld()); + + if (set != null) { + for (Anchor anchor : set) { + if (anchor.getLocation().equals(bLoc)) { + return anchor; + } + } + } + + return null; + } + + public boolean isAnchor(@NotNull Block b) { + return getAnchor(b) != null; + } + + public boolean hasAnchor(@NotNull Chunk chunk) { + if (!isReady(chunk.getWorld())) { + throw new IllegalStateException(ERR_WORLD_NOT_READY); + } + + Set set = anchors.get(chunk.getWorld()); + + if (set != null) { + for (Anchor anchor : set) { + if (anchor.getChunk().equals(chunk)) { + return true; + } + } + } + + return false; + } + + @SuppressWarnings("unused") + public List searchAnchors(Location center, double searchRadius) { + return searchAnchors(center, searchRadius, false); + } + + public List searchAnchors(Location center, double searchRadius, boolean ignoreHeight) { + List result = new ArrayList<>(); + + if (ignoreHeight) { + center = center.clone(); + center.setY(0); + } + + for (Anchor anchor : getAnchors(center.getWorld())) { + Location loc = anchor.getLocation(); + + if (ignoreHeight) { + loc.setY(0); + } + + if (center.distance(loc) <= searchRadius) { + result.add(anchor); + } + } + + return result; + } + + /* Create 'n Destroy */ + + /** + * Creates a new anchor at a given location + * + * @param loc The block location for the anchor + * @param ticks The amount of ticks the anchor lives or -1 for infinite + */ + public void createAnchor(@NotNull Location loc, @NotNull UUID owner, int ticks, @Nullable Callback callback) { + if (!isReady(loc.getWorld())) { + throw new IllegalStateException(ERR_WORLD_NOT_READY); + } + + this.dataManager.insertAnchorAsync(loc, Objects.requireNonNull(owner), ticks, (ex, anchor) -> { + if (ex != null) { + if (callback != null) { + callback.accept(ex, null); + } else { + Utils.logException(this.plugin, ex, "SQLite"); + } + } else { + Bukkit.getScheduler().runTask(this.plugin, () -> { + Block b = loc.getBlock(); + b.setType(Settings.MATERIAL.getMaterial().getMaterial()); + + anchors.computeIfAbsent(anchor.getWorld(), k -> new HashSet<>()) + .add(anchor); + + updateHologram(anchor); + + if (callback != null) { + callback.accept(null, anchor); + } + }); + } + }); + } + + public void destroyAnchor(@NotNull Anchor anchor) { + destroyAnchor(anchor, false); + } + + public void destroyAnchor(@NotNull Anchor anchor, boolean forceSkipItemDrop) { + if (!isReady(anchor.getWorld())) { + throw new IllegalStateException(ERR_WORLD_NOT_READY); + } + + for (Set value : anchors.values()) { + value.remove(anchor); + } + + removeHologram(anchor); + + Location anchorLoc = anchor.getLocation(); + Block anchorBlock = anchorLoc.getBlock(); + Material anchorMaterial = anchorBlock.getType(); + + if (anchorBlock.getType() == Settings.MATERIAL.getMaterial().getMaterial()) { + anchorBlock.setType(Material.AIR); + } + + // Drop anchor as an item + if (!forceSkipItemDrop && + Settings.ALLOW_ANCHOR_BREAKING.getBoolean() && + (anchor.isInfinite() || anchor.getTicksLeft() >= 20)) { + anchor.getWorld().dropItemNaturally(anchorLoc, createAnchorItem(anchor.getTicksLeft(), anchorMaterial)); + } + + // Particles & Sound + anchor.getWorld().playSound(anchorLoc, CompatibleSound.ENTITY_GENERIC_EXPLODE.getSound(), 10, 10); + CompatibleParticleHandler.spawnParticles(CompatibleParticleHandler.ParticleType.getParticle(Settings.PARTICLE_DESTROY.getString()), + anchor.getLocation().add(.5, .5, .5), 100, .5, .5, .5); + + anchor.deInit(this.nms); + this.dataManager.deleteAnchorAsync(anchor); + } + + /* Anchor access */ + + @SuppressWarnings("unused") + public void registerAccessCheck(AnchorAccessCheck accessCheck) { + if (!accessChecks.contains(accessCheck)) { + // Adding at the start of the list makes sure the default check is + accessChecks.add(accessCheck); + } + } + + /** + * @param accessCheck The {@link AnchorAccessCheck} to remove + * + * @return true if the {@link AnchorAccessCheck} has been found and removed, false otherwise + */ + @SuppressWarnings("unused") + public boolean unregisterAccessCheck(AnchorAccessCheck accessCheck) { + return accessChecks.remove(accessCheck); + } + + public boolean hasAccess(@NotNull Anchor anchor, @NotNull OfflinePlayer p) { + return hasAccess(anchor, p.getUniqueId()); + } + + /** + * Checks if a player has access to an Anchor. By default only the owner has access to an Anchor. + *
+ * Other plugins can grant access to other players (e.g. friends). + *
+ * Legacy anchors without an owner automatically grant access to all players. + * + * @return true if the player may access the Anchor, false otherwise + * + * @see #registerAccessCheck(AnchorAccessCheck) + */ + public boolean hasAccess(@NotNull Anchor anchor, @NotNull UUID uuid) { + if (anchor.isLegacy() || anchor.getOwner().equals(uuid)) return true; + + for (AnchorAccessCheck accessCheck : this.accessChecks) { + if (accessCheck.check(anchor, uuid)) { + return true; + } + } + + return false; + } + + /* Anchor item */ + + public ItemStack createAnchorItem(int ticks) { + return createAnchorItem(ticks, Settings.MATERIAL.getMaterial()); + } + + public ItemStack createAnchorItem(int ticks, Material material) { + return createAnchorItem(ticks, CompatibleMaterial.getMaterial(material)); + } + + public ItemStack createAnchorItem(int ticks, CompatibleMaterial material) { + if (ticks <= 0 && ticks != -1) throw new IllegalArgumentException(); + + ItemStack item = material.getItem(); + ItemMeta meta = item.getItemMeta(); + + assert meta != null; + meta.setDisplayName(formatAnchorText(ticks, false)); + meta.setLore(TextUtils.formatText(Settings.LORE.getString().split("\r?\n"))); + item.setItemMeta(meta); + + NBTItem nbtItem = NmsManager.getNbt().of(item); + nbtItem.set(NBT_TICKS_KEY, ticks); + + return nbtItem.finish(); + } + + public static int getTicksFromItem(ItemStack item) { + NBTItem nbtItem = NmsManager.getNbt().of(item); + + if (nbtItem.has(NBT_TICKS_KEY)) { + return nbtItem.getInt(NBT_TICKS_KEY); + } + + // Legacy code (pre v2) to stay cross-version compatible + if (Settings.MATERIAL.getMaterial().getMaterial() == item.getType()) { + + if (nbtItem.has("ticks")) { + int result = nbtItem.getInt("ticks"); + + return result == -99 ? -1 : result; + } + + // Tries to get the ticks remaining from hidden text + if (item.hasItemMeta() && + item.getItemMeta().hasDisplayName() && + item.getItemMeta().getDisplayName().contains(":")) { + try { + int result = Integer.parseInt(item.getItemMeta().getDisplayName().replace("§", "").split(":")[0]); + + return result == -99 ? -1 : result; + } catch (NumberFormatException ignore) { + } + } + } + + return 0; + } + + /* Chunk visualization */ + + public boolean toggleChunkVisualized(Player p) { + boolean visualize = !hasChunksVisualized(p); + + setChunksVisualized(p, visualize); + + return visualize; + } + + public void setChunksVisualized(Player p, boolean visualize) { + if (visualize) { + this.visualizedChunk.add(p); + } else { + this.visualizedChunk.remove(p); + } + } + + @SuppressWarnings("BooleanMethodIsAlwaysInverted") + public boolean hasChunksVisualized(Player p) { + return this.visualizedChunk.contains(p); + } + + /* Holograms */ + + public void updateHolograms(List anchors) { + // are holograms enabled? + if (!Settings.HOLOGRAMS.getBoolean() || !HologramManager.getManager().isEnabled()) return; + + Map> hologramData = new HashMap<>(anchors.size()); + + for (Anchor anchor : anchors) { + hologramData.put(anchor.getLocation(), + Collections.singletonList(formatAnchorText(anchor.getTicksLeft(), true))); + } + + // Create the holograms + HologramManager.bulkUpdateHolograms(hologramData); + } + + private void updateHologram(Anchor anchor) { + updateHolograms(Collections.singletonList(anchor)); + } + + private String formatAnchorText(int ticks, boolean shorten) { + String remaining; + + if (ticks < 0) { + remaining = this.plugin.getLocale().getMessage("Infinite").getMessage(); + } else { + long millis = (ticks / 20L) * 1000L; + + remaining = TimeUtils.makeReadable(millis); + + if (shorten && millis > 60 * 5 * 1000 /* 5 minutes */ && + remaining.charAt(remaining.length() - 1) == 's') { + int i = remaining.lastIndexOf(' '); + + remaining = remaining.substring(0, i); + } + + if (remaining.isEmpty()) { + remaining = "0s"; + } + } + + return TextUtils.formatText(Settings.NAME_TAG.getString().replace("{REMAINING}", remaining)); + } + + private static void removeHologram(Anchor anchor) { + HologramManager.removeHologram(anchor.getLocation()); + } + + /** + * For internal use only + */ + public static SongodaPlugin getPlugin() { + return staticPluginInstance; + } +} diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorNMS.java b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorNMS.java new file mode 100644 index 0000000..a7e1010 --- /dev/null +++ b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorNMS.java @@ -0,0 +1,82 @@ +package com.songoda.epicanchors; + +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.plugin.java.JavaPlugin; + +/** + * Provides abstraction to be used in maven modules with the specified spigot version. + */ +public abstract class AnchorNMS { + protected final JavaPlugin plugin; + + protected AnchorNMS(JavaPlugin plugin) { + this.plugin = plugin; + } + + /** + * Tries to load a given chunk
+ * This method might introduce logic to keep chunks forcefully loaded. + *

+ * More information: https://minecraft.fandom.com/wiki/Tick#Chunk_tick + * + * @param chunk The chunk to load + * + * @return true, if the chunk has been successfully loaded + * + * @see #unloadAnchoredChunk(Chunk) + */ + public abstract boolean loadAnchoredChunk(Chunk chunk); + + /** + * Tries unloading a given chunk if there are no players inside.
+ * Any logic introduced in {@link #loadAnchoredChunk(Chunk)} to keep a chunk loaded is removed. + * + * @param chunk The chunk to unload + * + * @return true, if the chunk has been successfully unloaded + */ + public abstract boolean unloadAnchoredChunk(Chunk chunk); + + /** + * Ticks all inactive spawners in a specific chunk ignoring the minimum required players within a specific range.
+ * A spawner is deemed inactive if the server should already be ticking it. + * + * @param chunk The chunk to tick the spawners in + * @param amount The amount of ticks to execute for each spawner + */ + public abstract void tickInactiveSpawners(Chunk chunk, int amount); + + /** + * Performs random ticks on a specific chunks. + *

+ * More information: https://minecraft.fandom.com/wiki/Tick#Random_tick + * + * @param chunk The chunk to tick + * @param tickAmount The number of blocks to tick per ChunkSection, normally referred to as randomTickSpeed + */ + public abstract void doRandomTick(Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException; + + /** + * Returns the current value for the GameRule randomTickSpeed. + * + * @param world The world to retrieve the value from + * + * @return The current value or 3 if the GameRule does not exist + */ + public abstract int getRandomTickSpeed(World world); + + protected static class Helper { + private Helper() { + throw new IllegalStateException("Utility class"); + } + + public static int getRandomTickSpeedLegacy(World world) { + try { + return Integer.parseInt(world.getGameRuleValue("randomTickSpeed")); + } catch (NumberFormatException ignore) { + return 3; + } + } + } +} diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/DataManager.java b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/DataManager.java new file mode 100644 index 0000000..e0922d2 --- /dev/null +++ b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/DataManager.java @@ -0,0 +1,265 @@ +package com.songoda.epicanchors.files; + +import com.songoda.core.database.DataManagerAbstract; +import com.songoda.core.database.DatabaseConnector; +import com.songoda.epicanchors.Anchor; +import com.songoda.epicanchors.files.migration.AnchorMigration; +import com.songoda.epicanchors.utils.Callback; +import com.songoda.epicanchors.utils.UpdateCallback; +import com.songoda.epicanchors.utils.Utils; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +public class DataManager extends DataManagerAbstract { + private final ExecutorService thread = Executors.newSingleThreadExecutor(); + + private final String anchorTable; + + public DataManager(DatabaseConnector databaseConnector, Plugin plugin) { + super(databaseConnector, plugin); + + this.anchorTable = getTableName(super.getTablePrefix(), "anchors"); + } + + public void close() { + if (!this.thread.isShutdown()) { + this.thread.shutdown(); + + try { + if (!this.thread.awaitTermination(60, TimeUnit.SECONDS)) { + // Try stopping the thread forcefully (there is basically no hope left for the data) + this.thread.shutdownNow(); + } + } catch (InterruptedException ex) { + Utils.logException(super.plugin, ex); + } + + this.databaseConnector.closeConnection(); + } + } + + public void exists(@NotNull String worldName, int x, int y, int z, @NotNull Callback callback) { + this.databaseConnector.connect((con) -> { + try (PreparedStatement ps = con.prepareStatement("SELECT id FROM " + this.anchorTable + + " WHERE world_name =? AND x =? AND y =? AND z=?;")) { + ps.setString(1, worldName); + ps.setInt(2, x); + ps.setInt(3, y); + ps.setInt(4, z); + + ResultSet rs = ps.executeQuery(); + + callback.accept(null, rs.next()); + } catch (Exception ex) { + resolveCallback(callback, ex); + } + }); + } + + public void getAnchors(@Nullable World world, @NotNull Callback> callback) { + List result = new ArrayList<>(); + + this.databaseConnector.connect((con) -> { + try (PreparedStatement ps = con.prepareStatement("SELECT * FROM " + this.anchorTable + + (world != null ? " WHERE world_name =?" : "") + ";")) { + if (world != null) { + ps.setString(1, world.getName()); + } + + ResultSet rs = ps.executeQuery(); + + while (rs.next()) { + result.add(extractAnchor(rs)); + } + + callback.accept(null, result); + } catch (Exception ex) { + resolveCallback(callback, ex); + } + }); + } + + public void insertAnchorAsync(Location loc, UUID owner, int ticks, Callback callback) { + this.thread.execute(() -> insertAnchor(loc, owner, ticks, callback)); + } + + public void insertAnchor(Location loc, UUID owner, int ticks, Callback callback) { + this.databaseConnector.connect((con) -> { + try (PreparedStatement ps = con.prepareStatement("INSERT INTO " + this.anchorTable + + "(owner, world_name,x,y,z, ticks_left) VALUES (?,?,?,?,?, ?);");// Future SQLite version might support 'RETURNING *' + PreparedStatement psFetch = con.prepareStatement("SELECT * FROM " + this.anchorTable + + " WHERE world_name =? AND x =? AND y =? AND z=?;")) { + ps.setString(1, owner != null ? owner.toString() : null); + + ps.setString(2, Objects.requireNonNull(loc.getWorld()).getName()); + psFetch.setString(1, Objects.requireNonNull(loc.getWorld()).getName()); + + ps.setInt(3, loc.getBlockX()); + psFetch.setInt(2, loc.getBlockX()); + + ps.setInt(4, loc.getBlockY()); + psFetch.setInt(3, loc.getBlockY()); + + ps.setInt(5, loc.getBlockZ()); + psFetch.setInt(4, loc.getBlockZ()); + + ps.setInt(6, ticks); + + ps.executeUpdate(); + + if (callback != null) { + ResultSet rs = psFetch.executeQuery(); + rs.next(); + + callback.accept(null, extractAnchor(rs)); + } + } catch (Exception ex) { + resolveCallback(callback, ex); + } + }); + } + + public void migrateAnchor(List anchorEntries, UpdateCallback callback) { + this.databaseConnector.connect((con) -> { + con.setAutoCommit(false); + + SQLException err = null; + + for (AnchorMigration.LegacyAnchorEntry entry : anchorEntries) { + try (PreparedStatement ps = con.prepareStatement("INSERT INTO " + this.anchorTable + + "(world_name,x,y,z, ticks_left) VALUES (?,?,?,?, ?);")) { + ps.setString(1, entry.worldName); + ps.setInt(2, entry.x); + ps.setInt(3, entry.y); + ps.setInt(4, entry.z); + + ps.setInt(5, entry.ticksLeft); + + ps.executeUpdate(); + } catch (SQLException ex) { + err = ex; + } + } + + if (err == null) { + con.commit(); + + resolveUpdateCallback(callback, null); + } else { + con.rollback(); + + resolveUpdateCallback(callback, err); + } + + con.setAutoCommit(true); + }); + } + + public void updateAnchors(Collection anchors, UpdateCallback callback) { + this.databaseConnector.connect((con) -> { + con.setAutoCommit(false); + + SQLException err = null; + + for (Anchor anchor : anchors) { + try (PreparedStatement ps = con.prepareStatement("UPDATE " + this.anchorTable + + " SET ticks_left =? WHERE id =?;")) { + ps.setInt(1, anchor.getTicksLeft()); + ps.setInt(2, anchor.getDbId()); + + ps.executeUpdate(); + } catch (SQLException ex) { + err = ex; + break; + } + } + + if (err == null) { + con.commit(); + + resolveUpdateCallback(callback, null); + } else { + con.rollback(); + + resolveUpdateCallback(callback, err); + } + + con.setAutoCommit(true); + }); + } + + public void deleteAnchorAsync(Anchor anchor) { + deleteAnchorAsync(anchor, null); + } + + public void deleteAnchorAsync(Anchor anchor, UpdateCallback callback) { + this.thread.execute(() -> + this.databaseConnector.connect((con) -> { + try (PreparedStatement ps = con.prepareStatement("DELETE FROM " + this.anchorTable + + " WHERE id =?;")) { + ps.setInt(1, anchor.getDbId()); + + ps.executeUpdate(); + + resolveUpdateCallback(callback, null); + } catch (Exception ex) { + resolveUpdateCallback(callback, ex); + } + }) + ); + } + + public static String getTableName(String prefix, String name) { + String result = prefix + name; + + if (!result.matches("[a-z0-9_]+")) { + throw new IllegalStateException("The generated table name '" + result + "' contains invalid characters"); + } + + return result; + } + + private Anchor extractAnchor(ResultSet rs) throws SQLException { + String ownerStr = rs.getString("owner"); + + return new Anchor(rs.getInt("id"), + ownerStr != null ? UUID.fromString(ownerStr) : null, + new Location(Bukkit.getWorld(rs.getString("world_name")), + rs.getInt("x"), + rs.getInt("y"), + rs.getInt("z")), + rs.getInt("ticks_left")); + } + + private void resolveUpdateCallback(@Nullable UpdateCallback callback, @Nullable Exception ex) { + if (callback != null) { + callback.accept(ex); + } else if (ex != null) { + Utils.logException(this.plugin, ex, "SQLite"); + } + } + + private void resolveCallback(@Nullable Callback callback, @NotNull Exception ex) { + if (callback != null) { + callback.accept(ex, null); + } else { + Utils.logException(this.plugin, ex, "SQLite"); + } + } +} diff --git a/src/main/java/com/songoda/epicanchors/settings/Settings.java b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/Settings.java similarity index 61% rename from src/main/java/com/songoda/epicanchors/settings/Settings.java rename to modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/Settings.java index f1a851e..58d96ac 100644 --- a/src/main/java/com/songoda/epicanchors/settings/Settings.java +++ b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/Settings.java @@ -1,62 +1,71 @@ -package com.songoda.epicanchors.settings; +package com.songoda.epicanchors.files; import com.songoda.core.compatibility.CompatibleMaterial; -import com.songoda.core.compatibility.ServerVersion; +import com.songoda.core.compatibility.CompatibleParticleHandler; import com.songoda.core.configuration.Config; import com.songoda.core.configuration.ConfigSetting; import com.songoda.core.hooks.EconomyManager; -import com.songoda.epicanchors.EpicAnchors; - -import java.util.stream.Collectors; +import com.songoda.epicanchors.AnchorManager; public class Settings { + private Settings() { + throw new IllegalStateException("Utility class"); + } - static final Config config = EpicAnchors.getInstance().getCoreConfig(); + public static final Config config = AnchorManager.getPlugin().getCoreConfig(); - public static final ConfigSetting NAMETAG = new ConfigSetting(config, "Main.Name Tag", "&6Anchor &8(&7{REMAINING}&8)", + public static final ConfigSetting NAME_TAG = new ConfigSetting(config, "Main.Name Tag", + "&6Anchor &8(&7{REMAINING}&8)", "The anchor name tag used on the item and in the hologram."); - public static final ConfigSetting LORE = new ConfigSetting(config, "Main.Anchor Lore", "&7Place down to keep that chunk|&7loaded until the time runs out.", + public static final ConfigSetting LORE = new ConfigSetting(config, "Main.Anchor Lore", + "&7Place down to keep that chunk\n&7loaded until the time runs out.", "The lore on the anchor item."); - public static final ConfigSetting MATERIAL = new ConfigSetting(config, "Main.Anchor Block Material", CompatibleMaterial.END_PORTAL_FRAME.getMaterial().name(), - "The material an anchor is represented with?"); + public static final ConfigSetting MATERIAL = new ConfigSetting(config, "Main.Anchor Block Material", + CompatibleMaterial.END_PORTAL_FRAME.name(), "The material an anchor is represented with?"); + + public static final ConfigSetting ADD_TIME_WITH_XP = new ConfigSetting(config, "Main.Add Time With XP", true, + "Should players be able to add time to their anchors by using experience?"); + + public static final ConfigSetting XP_COST = new ConfigSetting(config, "Main.XP Cost", 10, + "The cost in experience levels to add 30 minutes to an anchor."); public static final ConfigSetting ADD_TIME_WITH_ECONOMY = new ConfigSetting(config, "Main.Add Time With Economy", true, - "Should players be able to add time to their anchors", - "by using economy?"); + "Should players be able to add time to their anchors by using economy?"); public static final ConfigSetting ECONOMY_COST = new ConfigSetting(config, "Main.Economy Cost", 5000.0, "The cost in economy to add 30 minutes to an anchor."); - public static final ConfigSetting ADD_TIME_WITH_XP = new ConfigSetting(config, "Main.Add Time With XP", true, - "Should players be able to add time to their anchors", - "by using experience?"); - - public static final ConfigSetting XP_COST = new ConfigSetting(config, "Main.XP Cost", 10, - "The cost in experience to add 30 minutes to an anchor."); - public static final ConfigSetting ALLOW_ANCHOR_BREAKING = new ConfigSetting(config, "Main.Allow Anchor Breaking", false, - "Should players be able to break anchors?"); + "Should players be able to break anchors and get an item dropped?"); public static final ConfigSetting HOLOGRAMS = new ConfigSetting(config, "Main.Holograms", true, "Toggle holograms showing above anchors."); + @SuppressWarnings("unchecked") public static final ConfigSetting ECONOMY_PLUGIN = new ConfigSetting(config, "Main.Economy", EconomyManager.getEconomy() == null ? "Vault" : EconomyManager.getEconomy().getName(), "Which economy plugin should be used?", - "Supported plugins you have installed: \"" + EconomyManager.getManager().getRegisteredPlugins().stream().collect(Collectors.joining("\", \"")) + "\"."); + "Supported plugins you have installed: \"" + String.join(", ", EconomyManager.getManager().getRegisteredPlugins()) + "\"."); - public static final ConfigSetting ECO_ICON = new ConfigSetting(config, "Interfaces.Economy Icon", "SUNFLOWER", + public static final ConfigSetting ECO_ICON = new ConfigSetting(config, "Interfaces.Economy Icon", CompatibleMaterial.SUNFLOWER.name(), "Item to be displayed as the icon for economy upgrades."); - public static final ConfigSetting XP_ICON = new ConfigSetting(config, "Interfaces.XP Icon", "EXPERIENCE_BOTTLE", + public static final ConfigSetting XP_ICON = new ConfigSetting(config, "Interfaces.XP Icon", CompatibleMaterial.EXPERIENCE_BOTTLE.name(), "Item to be displayed as the icon for XP upgrades."); - public static final ConfigSetting GLASS_TYPE_1 = new ConfigSetting(config, "Interfaces.Glass Type 1", "GRAY_STAINED_GLASS_PANE"); - public static final ConfigSetting GLASS_TYPE_2 = new ConfigSetting(config, "Interfaces.Glass Type 2", "BLUE_STAINED_GLASS_PANE"); - public static final ConfigSetting GLASS_TYPE_3 = new ConfigSetting(config, "Interfaces.Glass Type 3", "LIGHT_BLUE_STAINED_GLASS_PANE"); + public static final ConfigSetting GLASS_TYPE_1 = new ConfigSetting(config, "Interfaces.Glass Type 1", CompatibleMaterial.GRAY_STAINED_GLASS_PANE.name()); + public static final ConfigSetting GLASS_TYPE_2 = new ConfigSetting(config, "Interfaces.Glass Type 2", CompatibleMaterial.BLUE_STAINED_GLASS_PANE.name()); + public static final ConfigSetting GLASS_TYPE_3 = new ConfigSetting(config, "Interfaces.Glass Type 3", CompatibleMaterial.LIGHT_BLUE_STAINED_GLASS_PANE.name()); - public static final ConfigSetting LANGUGE_MODE = new ConfigSetting(config, "System.Language Mode", "en_US", + public static final ConfigSetting PARTICLE_DESTROY = new ConfigSetting(config, "Particles.Destroy", + CompatibleParticleHandler.ParticleType.LAVA.name()); + public static final ConfigSetting PARTICLE_UPGRADE = new ConfigSetting(config, "Particles.Upgrade", + CompatibleParticleHandler.ParticleType.SPELL_WITCH.name()); + public static final ConfigSetting PARTICLE_VISUALIZER = new ConfigSetting(config, "Particles.Visualizer", + CompatibleParticleHandler.ParticleType.VILLAGER_HAPPY.name()); + + public static final ConfigSetting LANGUAGE = new ConfigSetting(config, "System.Language Mode", "en_US", "The enabled language file.", "More language files (if available) can be found in the plugins data folder."); @@ -66,7 +75,8 @@ public class Settings { */ public static void setupConfig() { config.load(); - config.setAutoremove(true).setAutosave(true); + config.setAutoremove(true) + .setAutosave(true); // convert glass pane settings int color; @@ -91,4 +101,4 @@ public class Settings { config.saveChanges(); } -} \ No newline at end of file +} diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/migration/AnchorMigration.java b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/migration/AnchorMigration.java new file mode 100644 index 0000000..765e3c5 --- /dev/null +++ b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/migration/AnchorMigration.java @@ -0,0 +1,152 @@ +package com.songoda.epicanchors.files.migration; + +import com.songoda.core.configuration.Config; +import com.songoda.core.configuration.ConfigSection; +import com.songoda.core.database.DataMigration; +import com.songoda.core.database.DataMigrationManager; +import com.songoda.core.database.DatabaseConnector; +import com.songoda.epicanchors.files.DataManager; +import com.songoda.epicanchors.utils.ThreadSync; +import org.bukkit.Location; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; + +public class AnchorMigration extends DataMigrationManager { + private final DataManager dataManager; + + public AnchorMigration(DatabaseConnector databaseConnector, DataManager dataManager, DataMigration... migrations) { + super(databaseConnector, dataManager, migrations); + + this.dataManager = dataManager; + } + + // TODO: Migration of a lot of Anchors takes **very** long (1100 anchors => 9 seconds) + // This is easily fixed by putting all inserts into one big transaction but prevents us from + public void migrateLegacyData(JavaPlugin plugin) { + long start = System.nanoTime(); + + AtomicBoolean abortMigration = new AtomicBoolean(false); + int migratedAnchors = 0; + + Config legacyData = new Config(plugin, "data.yml"); + + if (legacyData.getFile().exists()) { + ThreadSync thSync = new ThreadSync(); + + legacyData.load(); + + ConfigSection cfgSection = legacyData.getConfigurationSection("Anchors"); + + if (cfgSection == null) return; + + List anchorQueue = new ArrayList<>(); + + for (String locationStr : cfgSection.getKeys(false)) { + int ticksLeft = cfgSection.getInt(locationStr + ".ticksLeft"); + String[] locArgs = deserializeLegacyLocation(locationStr); + + if (ticksLeft == -99) { + ticksLeft = -1; + } + + if (locArgs.length == 0) { + abortMigration.set(true); + + plugin.getLogger().warning(() -> "Error migrating anchor '" + locationStr + "': invalid format - expected 'worldName:X:Y:Z'"); + break; + } + + String worldName = locArgs[0]; + int x = Location.locToBlock(Double.parseDouble(locArgs[1])); + int y = Location.locToBlock(Double.parseDouble(locArgs[2])); + int z = Location.locToBlock(Double.parseDouble(locArgs[3])); + + int finalTicksLeft = ticksLeft; + dataManager.exists(worldName, x, y, z, (ex, anchorExists) -> { + if (ex == null) { + if (anchorExists) { + cfgSection.set(locationStr, null); + } else { + anchorQueue.add(new LegacyAnchorEntry(worldName, x, y, z, finalTicksLeft)); + } + } else { + abortMigration.set(true); + + plugin.getLogger().log(Level.WARNING, ex, () -> "Error migrating Anchor '" + locationStr + "' from '" + + legacyData.getFile().getName() + "'"); + } + + thSync.release(); + }); + + thSync.waitForRelease(); + thSync.reset(); + + if (abortMigration.get()) break; + + ++migratedAnchors; + } + + if (!abortMigration.get()) { + int finalMigratedAnchors = migratedAnchors; + this.dataManager.migrateAnchor(anchorQueue, ex -> { + long end = System.nanoTime(); + + if (ex == null) { + try { + Files.deleteIfExists(legacyData.getFile().toPath()); + } catch (IOException err) { + plugin.getLogger().warning("Could not delete '" + legacyData.getFile().getName() + "' after data migration: " + err.getMessage()); + } + + plugin.getLogger().info("Successfully migrated " + finalMigratedAnchors + " Anchors from '" + + legacyData.getFile().getName() + "' (" + TimeUnit.NANOSECONDS.toMillis(end - start) + "ms)"); + } else { + legacyData.save(); + } + }); + } + } + } + + private String[] deserializeLegacyLocation(String str) { + if (str == null || str.isEmpty()) { + return new String[0]; + } + + str = str + .replace("w:", "") + .replace("x:", ":") + .replace("y:", ":") + .replace("z:", ":") + .replace("/", "."); + + String[] args = str.split(":"); + + return args.length == 4 ? args : new String[0]; + } + + public static class LegacyAnchorEntry { + public final String worldName; + public final int x; + public final int y; + public final int z; + + public final int ticksLeft; + + public LegacyAnchorEntry(String worldName, int x, int y, int z, int ticksLeft) { + this.worldName = worldName; + this.x = x; + this.y = y; + this.z = z; + this.ticksLeft = ticksLeft; + } + } +} diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/migration/_1_InitialMigration.java b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/migration/_1_InitialMigration.java new file mode 100644 index 0000000..2a6b88b --- /dev/null +++ b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/migration/_1_InitialMigration.java @@ -0,0 +1,30 @@ +package com.songoda.epicanchors.files.migration; + +import com.songoda.core.database.DataMigration; +import com.songoda.epicanchors.files.DataManager; + +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; + +public class _1_InitialMigration extends DataMigration { + public _1_InitialMigration() { + super(1); + } + + @Override + public void migrate(Connection connection, String tablePrefix) throws SQLException { + try (Statement statement = connection.createStatement()) { + statement.execute("CREATE TABLE " + DataManager.getTableName(tablePrefix, "anchors") + "(" + + "id INTEGER NOT NULL," + + "world_name TEXT NOT NULL," + + "x INTEGER NOT NULL," + + "y INTEGER NOT NULL," + + "z INTEGER NOT NULL," + + "ticks_left INTEGER NOT NULL," + + "owner VARCHAR(36)," + + "PRIMARY KEY(id AUTOINCREMENT)" + + ");"); + } + } +} diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/Callback.java b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/Callback.java new file mode 100644 index 0000000..894e449 --- /dev/null +++ b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/Callback.java @@ -0,0 +1,7 @@ +package com.songoda.epicanchors.utils; + +import org.jetbrains.annotations.Nullable; + +public interface Callback { + void accept(@Nullable Exception ex, T result); +} diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/ReflectionUtils.java b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/ReflectionUtils.java new file mode 100644 index 0000000..2c3d452 --- /dev/null +++ b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/ReflectionUtils.java @@ -0,0 +1,52 @@ +package com.songoda.epicanchors.utils; + +import java.lang.reflect.Field; + +public class ReflectionUtils { + private ReflectionUtils() { + throw new IllegalStateException("Utility class"); + } + + public static Object getFieldValue(Object instance, String fieldName) throws NoSuchFieldException, IllegalAccessException { + Field f = getField(instance, fieldName); + boolean accessible = f.isAccessible(); + + f.setAccessible(true); + + Object result = f.get(instance); + + f.setAccessible(accessible); + + return result; + } + + public static void setFieldValue(Object instance, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException { + Field f = getField(instance, fieldName); + boolean accessible = f.isAccessible(); + + f.setAccessible(true); + + f.set(instance, value); + + f.setAccessible(accessible); + } + + private static Field getField(Object instance, String fieldName) throws NoSuchFieldException { + Field f = null; + + Class currClass = instance.getClass(); + do { + try { + f = currClass.getDeclaredField(fieldName); + } catch (NoSuchFieldException ex) { + currClass = currClass.getSuperclass(); + + if (currClass == null) { + throw ex; + } + } + } while (f == null); + + return f; + } +} diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/ThreadSync.java b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/ThreadSync.java new file mode 100644 index 0000000..cd24b20 --- /dev/null +++ b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/ThreadSync.java @@ -0,0 +1,30 @@ +package com.songoda.epicanchors.utils; + +import java.util.concurrent.atomic.AtomicReference; + +public class ThreadSync { + private final Object syncObj = new Object(); + private final AtomicReference waiting = new AtomicReference<>(true); + + public void waitForRelease() { + synchronized (syncObj) { + while (waiting.get()) { + try { + syncObj.wait(); + } catch (Exception ignore) { + } + } + } + } + + public void release() { + synchronized (syncObj) { + waiting.set(false); + syncObj.notifyAll(); + } + } + + public void reset() { + waiting.set(true); + } +} diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/UpdateCallback.java b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/UpdateCallback.java new file mode 100644 index 0000000..bd1a609 --- /dev/null +++ b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/UpdateCallback.java @@ -0,0 +1,7 @@ +package com.songoda.epicanchors.utils; + +import org.jetbrains.annotations.Nullable; + +public interface UpdateCallback { + void accept(@Nullable Exception ex); +} diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/Utils.java b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/Utils.java new file mode 100644 index 0000000..63df1d4 --- /dev/null +++ b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/Utils.java @@ -0,0 +1,60 @@ +package com.songoda.epicanchors.utils; + +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class Utils { + private Utils() { + throw new IllegalStateException("Utility class"); + } + + public static boolean isInt(String s) { + if (s != null && !s.isEmpty()) { + try { + Integer.parseInt(s); + return true; + } catch (NumberFormatException ignore) { + } + } + + return false; + } + + /** + * Get all values of a String[] which start with a given String + * + * @param value The String to search for + * @param list The array to iterate + * + * @return A list with all the matches + */ + public static List getMatches(String value, Collection list, boolean caseInsensitive) { + List result = new LinkedList<>(); + + for (String str : list) { + if (str.startsWith(value.toLowerCase()) + || (caseInsensitive && str.toLowerCase().startsWith(value.toLowerCase()))) { + result.add(str); + } + } + + return result; + } + + public static void logException(@Nullable Plugin plugin, @NotNull Throwable th) { + logException(plugin, th, null); + } + + public static void logException(@Nullable Plugin plugin, @NotNull Throwable th, @Nullable String type) { + Logger logger = plugin != null ? plugin.getLogger() : Logger.getGlobal(); + + logger.log(Level.FINER, th, () -> "A " + (type == null ? "critical" : type) + " error occurred"); + } +} diff --git a/modules/epicanchors-plugin/pom.xml b/modules/epicanchors-plugin/pom.xml new file mode 100644 index 0000000..56fbaef --- /dev/null +++ b/modules/epicanchors-plugin/pom.xml @@ -0,0 +1,221 @@ + + + 4.0.0 + + + com.songoda + EpicAnchors + 2.0.0-ALPHA + ../../pom.xml + + epicanchors-plugin + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + + ${java.version} + ${java.version} + + ${java.release} + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + + package + + + shade + + + + ${project.parent.name}-${project.version} + + false + true + + + + com.songoda.core + com.songoda.epicanchors.core + + + + epicanchors.nms + com.songoda.epicanchors.nms + + + + + + *:* + + + META-INF/** + LICENSE + LICENSE.** + + + + + org.jetbrains:annotations + + ** + + + + + com.songoda:epicanchors-v* + + ** + + + + + + + + + + + + src/main/resources + true + + + + + + + org.spigotmc + spigot-api + 1.8-R0.1-SNAPSHOT + provided + + + + + com.songoda + epicanchors-api + ${project.version} + compile + + + + com.songoda + epicanchors-v1_16_R3 + ${project.version} + compile + + + + com.songoda + epicanchors-v1_16_R2 + ${project.version} + compile + + + + com.songoda + epicanchors-v1_16_R1 + ${project.version} + compile + + + + com.songoda + epicanchors-v1_15_R1 + ${project.version} + compile + + + + com.songoda + epicanchors-v1_14_R1 + ${project.version} + compile + + + + com.songoda + epicanchors-v1_13_R2 + ${project.version} + compile + + + + com.songoda + epicanchors-v1_13_R1 + ${project.version} + compile + + + + com.songoda + epicanchors-v1_12_R1 + ${project.version} + compile + + + + com.songoda + epicanchors-v1_11_R1 + ${project.version} + compile + + + + com.songoda + epicanchors-v1_10_R1 + ${project.version} + compile + + + + com.songoda + epicanchors-v1_9_R2 + ${project.version} + compile + + + + com.songoda + epicanchors-v1_9_R1 + ${project.version} + compile + + + + com.songoda + epicanchors-v1_8_R3 + ${project.version} + compile + + + + com.songoda + epicanchors-v1_8_R2 + ${project.version} + compile + + + + com.songoda + epicanchors-v1_8_R1 + ${project.version} + compile + + + diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/EpicAnchors.java b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/EpicAnchors.java new file mode 100644 index 0000000..fa0b125 --- /dev/null +++ b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/EpicAnchors.java @@ -0,0 +1,208 @@ +package com.songoda.epicanchors; + +import com.songoda.core.SongodaCore; +import com.songoda.core.SongodaPlugin; +import com.songoda.core.commands.CommandManager; +import com.songoda.core.compatibility.CompatibleMaterial; +import com.songoda.core.compatibility.ServerVersion; +import com.songoda.core.configuration.Config; +import com.songoda.core.database.DatabaseConnector; +import com.songoda.core.database.SQLiteConnector; +import com.songoda.core.gui.GuiManager; +import com.songoda.core.hooks.EconomyManager; +import com.songoda.core.hooks.HologramManager; +import com.songoda.epicanchors.commands.EpicAnchorsCommand; +import com.songoda.epicanchors.commands.sub.GiveCommand; +import com.songoda.epicanchors.commands.sub.ReloadCommand; +import com.songoda.epicanchors.commands.sub.SettingsCommand; +import com.songoda.epicanchors.commands.sub.ShowCommand; +import com.songoda.epicanchors.files.DataManager; +import com.songoda.epicanchors.files.Settings; +import com.songoda.epicanchors.files.migration.AnchorMigration; +import com.songoda.epicanchors.files.migration._1_InitialMigration; +import com.songoda.epicanchors.listener.AnchorListener; +import com.songoda.epicanchors.listener.BlockListener; +import com.songoda.epicanchors.listener.DebugListener; +import com.songoda.epicanchors.listener.WorldListener; +import com.songoda.epicanchors.tasks.AnchorTask; +import com.songoda.epicanchors.tasks.VisualizeTask; +import com.songoda.epicanchors.utils.ThreadSync; +import com.songoda.epicanchors.utils.Utils; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.plugin.PluginManager; + +import java.io.File; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; + +public final class EpicAnchors extends SongodaPlugin { + private GuiManager guiManager; + private AnchorManager anchorManager; + + private DataManager dataManager; + + @Override + public void onPluginLoad() { + } + + @Override + public void onPluginEnable() { + // Songoda Updater + SongodaCore.registerPlugin(this, 31, CompatibleMaterial.END_PORTAL_FRAME); + + // Initialize database + this.getLogger().info("Initializing SQLite..."); + DatabaseConnector dbCon = new SQLiteConnector(this); + this.dataManager = new DataManager(dbCon, this); + AnchorMigration anchorMigration = new AnchorMigration(dbCon, this.dataManager, + new _1_InitialMigration()); + anchorMigration.runMigrations(); + + anchorMigration.migrateLegacyData(this); + this.anchorManager = new AnchorManager(this, this.dataManager, createAnchorNMS()); + + // Economy [1/2] + EconomyManager.load(); + + // Config + Settings.setupConfig(); + this.setLocale(Settings.LANGUAGE.getString(), false); + + // Economy [2/2] + EconomyManager.getManager().setPreferredHook(Settings.ECONOMY_PLUGIN.getString()); + + // Holograms + HologramManager.load(this); + + // Event Listener + this.guiManager = new GuiManager(this); + guiManager.init(); + PluginManager pluginManager = Bukkit.getPluginManager(); + pluginManager.registerEvents(new WorldListener( + world -> this.anchorManager.initAnchorsAsync(world, null), + world -> this.anchorManager.deInitAnchors(world)), + this); + pluginManager.registerEvents(new AnchorListener(this), this); + pluginManager.registerEvents(new BlockListener(this.anchorManager), this); + + // Commands + CommandManager commandManager = new CommandManager(this); + commandManager.addCommand(new EpicAnchorsCommand(this, commandManager)) + .addSubCommands( + new GiveCommand(this), + new ReloadCommand(this), + new SettingsCommand(this, this.guiManager), + new ShowCommand(this) + ); + + // TODO: remove debug + if (!new File(getDataFolder(), "no-debug.txt").exists()) { + Bukkit.getPluginManager().registerEvents(new DebugListener(this), this); + } + } + + @Override + public void onPluginDisable() { + // Save all Anchors + if (this.dataManager != null) { + this.anchorManager.deInitAll(); + + this.dataManager.close(); + } + + // Remove all holograms + HologramManager.removeAllHolograms(); + } + + @Override + public void onDataLoad() { + new Thread(() -> { + ThreadSync tSync = new ThreadSync(); + + for (World w : Bukkit.getWorlds()) { + this.anchorManager.initAnchorsAsync(w, (ex) -> { + if (ex != null) { + this.getLogger().log(Level.FINER, ex, () -> "Failed to initialize world '" + w.getName() + "'"); + } + + tSync.release(); + }); + + tSync.waitForRelease(); + tSync.reset(); + } + + this.anchorManager.setReady(); + + // Start tasks + new AnchorTask(this).startTask(); + new VisualizeTask(this).startTask(); + }).start(); + } + + @Override + public void onConfigReload() { + this.setLocale(Settings.LANGUAGE.getString(), true); + } + + @Override + public List getExtraConfig() { + return Collections.emptyList(); + } + + public GuiManager getGuiManager() { + return this.guiManager; + } + + public AnchorManager getAnchorManager() { + return this.anchorManager; + } + + private AnchorNMS createAnchorNMS() { + try { + // Try loading NMS class + return (AnchorNMS) Class.forName("epicanchors.nms." + ServerVersion.getServerVersionString()).getConstructors()[0].newInstance(this); + } catch (Exception ex) { + if (!(ex instanceof ClassNotFoundException)) { + Utils.logException(this, ex); + } + + getLogger().warning("Your server version (" + ServerVersion.getServerVersionString() + ") is not fully supported yet!"); + getLogger().warning(getName() + " will do its best, but features like plant growth or spawners require an update"); + + return new AnchorNMS(this) { + @Override + public boolean loadAnchoredChunk(Chunk chunk) { + return chunk.load(); + } + + @Override + public boolean unloadAnchoredChunk(Chunk chunk) { + return chunk.unload(); + } + + @Override + public void tickInactiveSpawners(Chunk chunk, int amount) { + // Sadly nothing we can do here + } + + @Override + public void doRandomTick(Chunk chunk, int tickAmount) { + // Sadly nothing we can do here + } + + @Override + public int getRandomTickSpeed(World world) { + try { + return Integer.parseInt(world.getGameRuleValue("randomTickSpeed")); + } catch (NumberFormatException ignore) { + return 3; + } + } + }; + } + } +} diff --git a/src/main/java/com/songoda/epicanchors/commands/CommandEpicAnchors.java b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/EpicAnchorsCommand.java similarity index 53% rename from src/main/java/com/songoda/epicanchors/commands/CommandEpicAnchors.java rename to modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/EpicAnchorsCommand.java index 34baec4..f8cf8a3 100644 --- a/src/main/java/com/songoda/epicanchors/commands/CommandEpicAnchors.java +++ b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/EpicAnchorsCommand.java @@ -1,30 +1,35 @@ package com.songoda.epicanchors.commands; import com.songoda.core.commands.AbstractCommand; +import com.songoda.core.commands.CommandManager; import com.songoda.epicanchors.EpicAnchors; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; +import java.util.Collections; import java.util.List; -public class CommandEpicAnchors extends AbstractCommand { +public class EpicAnchorsCommand extends AbstractCommand { + private final EpicAnchors plugin; + private final CommandManager commandManager; - final EpicAnchors instance; + public EpicAnchorsCommand(EpicAnchors plugin, CommandManager commandManager) { + super(CommandType.CONSOLE_OK, false, "EpicAnchors"); - public CommandEpicAnchors(EpicAnchors instance) { - super(false, "EpicAnchors"); - this.instance = instance; + this.plugin = plugin; + this.commandManager = commandManager; } @Override protected ReturnType runCommand(CommandSender sender, String... args) { sender.sendMessage(""); - instance.getLocale().newMessage("&7Version " + instance.getDescription().getVersion() + this.plugin.getLocale().newMessage("&7Version " + this.plugin.getDescription().getVersion() + " Created with <3 by &5&l&oSongoda").sendPrefixedMessage(sender); - for (AbstractCommand command : instance.getCommandManager().getAllCommands()) { - if (command.getPermissionNode() == null || sender.hasPermission(command.getPermissionNode())) { - sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&8 - &a" + command.getSyntax() + "&7 - " + command.getDescription())); + for (AbstractCommand cmd : this.commandManager.getAllCommands()) { + if (cmd.getPermissionNode() == null || sender.hasPermission(cmd.getPermissionNode())) { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', + "&8 - &a" + cmd.getSyntax() + "&7 - " + cmd.getDescription())); } } sender.sendMessage(""); @@ -34,7 +39,7 @@ public class CommandEpicAnchors extends AbstractCommand { @Override protected List onTab(CommandSender commandSender, String... strings) { - return null; + return Collections.emptyList(); } @Override diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/GiveCommand.java b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/GiveCommand.java new file mode 100644 index 0000000..7fbdc27 --- /dev/null +++ b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/GiveCommand.java @@ -0,0 +1,112 @@ +package com.songoda.epicanchors.commands.sub; + +import com.songoda.core.commands.AbstractCommand; +import com.songoda.epicanchors.EpicAnchors; +import com.songoda.epicanchors.utils.Utils; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class GiveCommand extends AbstractCommand { + private final EpicAnchors plugin; + + public GiveCommand(EpicAnchors plugin) { + super(CommandType.CONSOLE_OK, false, "give"); + + this.plugin = plugin; + } + + @Override + protected ReturnType runCommand(CommandSender sender, String... args) { + if (args.length != 2) return ReturnType.SYNTAX_ERROR; + + Player target = Bukkit.getPlayerExact(args[0]); + + if (target == null && + !args[0].trim().equalsIgnoreCase("all") && + !args[0].trim().equalsIgnoreCase("@a")) { + plugin.getLocale().newMessage("&cThat is not a player...").sendPrefixedMessage(sender); + + return ReturnType.SYNTAX_ERROR; + } + + ItemStack itemStack; + + if (Utils.isInt(args[1]) && Integer.parseInt(args[1]) > 0) { + itemStack = plugin.getAnchorManager().createAnchorItem(Integer.parseInt(args[1]) * 20 * 60 * 60); + } else if (args[1].equalsIgnoreCase("infinite")) { + itemStack = plugin.getAnchorManager().createAnchorItem(-1); + } else { + plugin.getLocale().newMessage("&cYou can only use positive whole numbers...").sendPrefixedMessage(sender); + + return ReturnType.FAILURE; + } + + if (target != null) { + target.getInventory().addItem(itemStack); + plugin.getLocale().getMessage("command.give.success").sendPrefixedMessage(target); + } else { + for (Player online : Bukkit.getOnlinePlayers()) { + online.getInventory().addItem(itemStack); + plugin.getLocale().getMessage("command.give.success").sendPrefixedMessage(online); + } + } + + return ReturnType.SUCCESS; + } + + @Override + protected List onTab(CommandSender commandSender, String... args) { + if (args.length == 1) { + Set players = new HashSet<>(); + + for (Player player : Bukkit.getOnlinePlayers()) { + players.add(player.getName()); + } + + players.add("@a"); + + return Utils.getMatches(args[0], players, true); + } else if (args.length == 2) { + List result = new ArrayList<>(); + + result.add("infinite"); + + if (args[1].isEmpty()) { + for (int i = 1; i <= 5; ++i) { + result.add(String.valueOf(i)); + } + } else if (Utils.isInt(args[1]) && args[1].charAt(0) != '-') { + result.add(args[1] + "0"); + result.add(args[1] + "00"); + result.add(args[1] + "000"); + } + + return Utils.getMatches(args[1], result, true); + } + + return Collections.emptyList(); + } + + @Override + public String getPermissionNode() { + return "EpicAnchors.cmd.give"; + } + + @Override + public String getSyntax() { + return "/ea give "; + } + + @Override + public String getDescription() { + return "Gives an operator the ability to spawn a ChunkAnchor of his or her choice."; + } +} diff --git a/src/main/java/com/songoda/epicanchors/commands/CommandReload.java b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/ReloadCommand.java similarity index 55% rename from src/main/java/com/songoda/epicanchors/commands/CommandReload.java rename to modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/ReloadCommand.java index f18f407..e8a7ccd 100644 --- a/src/main/java/com/songoda/epicanchors/commands/CommandReload.java +++ b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/ReloadCommand.java @@ -1,35 +1,36 @@ -package com.songoda.epicanchors.commands; +package com.songoda.epicanchors.commands.sub; import com.songoda.core.commands.AbstractCommand; import com.songoda.epicanchors.EpicAnchors; import org.bukkit.command.CommandSender; +import java.util.Collections; import java.util.List; -public class CommandReload extends AbstractCommand { +public class ReloadCommand extends AbstractCommand { + private final EpicAnchors plugin; - final EpicAnchors instance; - - public CommandReload(EpicAnchors instance) { - super(false, "reload"); - this.instance = instance; + public ReloadCommand(EpicAnchors plugin) { + super(CommandType.CONSOLE_OK, false, "reload"); + this.plugin = plugin; } @Override protected ReturnType runCommand(CommandSender sender, String... args) { - instance.reloadConfig(); - instance.getLocale().getMessage("&7Configuration and Language files reloaded.").sendPrefixedMessage(sender); + plugin.reloadConfig(); + plugin.getLocale().getMessage("&7Configuration and Language files reloaded.").sendPrefixedMessage(sender); + return ReturnType.SUCCESS; } @Override protected List onTab(CommandSender sender, String... args) { - return null; + return Collections.emptyList(); } @Override public String getPermissionNode() { - return "epicanchors.admin"; + return "EpicAnchors.cmd.reload"; } @Override @@ -41,5 +42,4 @@ public class CommandReload extends AbstractCommand { public String getDescription() { return "Reload the Configuration and Language files."; } - } diff --git a/src/main/java/com/songoda/epicanchors/commands/CommandSettings.java b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/SettingsCommand.java similarity index 69% rename from src/main/java/com/songoda/epicanchors/commands/CommandSettings.java rename to modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/SettingsCommand.java index 6b679e1..eaa4733 100644 --- a/src/main/java/com/songoda/epicanchors/commands/CommandSettings.java +++ b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/SettingsCommand.java @@ -1,4 +1,4 @@ -package com.songoda.epicanchors.commands; +package com.songoda.epicanchors.commands.sub; import com.songoda.core.commands.AbstractCommand; import com.songoda.core.configuration.editor.PluginConfigGui; @@ -7,15 +7,16 @@ import com.songoda.epicanchors.EpicAnchors; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import java.util.Collections; import java.util.List; -public class CommandSettings extends AbstractCommand { +public class SettingsCommand extends AbstractCommand { + private final EpicAnchors instance; + private final GuiManager guiManager; - final EpicAnchors instance; - final GuiManager guiManager; + public SettingsCommand(EpicAnchors instance, GuiManager manager) { + super(CommandType.PLAYER_ONLY, false, "settings"); - public CommandSettings(EpicAnchors instance, GuiManager manager) { - super(true, "settings"); this.instance = instance; this.guiManager = manager; } @@ -23,17 +24,18 @@ public class CommandSettings extends AbstractCommand { @Override protected ReturnType runCommand(CommandSender sender, String... args) { guiManager.showGUI((Player) sender, new PluginConfigGui(instance)); + return AbstractCommand.ReturnType.SUCCESS; } @Override protected List onTab(CommandSender commandSender, String... strings) { - return null; + return Collections.emptyList(); } @Override public String getPermissionNode() { - return "epicanchors.admin"; + return "EpicAnchors.cmd.settings"; } @Override diff --git a/src/main/java/com/songoda/epicanchors/commands/CommandShow.java b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/ShowCommand.java similarity index 57% rename from src/main/java/com/songoda/epicanchors/commands/CommandShow.java rename to modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/ShowCommand.java index 30f7161..63bd88a 100644 --- a/src/main/java/com/songoda/epicanchors/commands/CommandShow.java +++ b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/ShowCommand.java @@ -1,50 +1,49 @@ -package com.songoda.epicanchors.commands; +package com.songoda.epicanchors.commands.sub; import com.songoda.core.commands.AbstractCommand; import com.songoda.epicanchors.EpicAnchors; -import com.songoda.epicanchors.tasks.VisualizeTask; import net.md_5.bungee.api.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import java.util.Collections; import java.util.List; -public class CommandShow extends AbstractCommand { - +public class ShowCommand extends AbstractCommand { private final EpicAnchors plugin; - public CommandShow(EpicAnchors plugin) { - super(true, "show"); + public ShowCommand(EpicAnchors plugin) { + super(CommandType.PLAYER_ONLY, false, "show"); + this.plugin = plugin; } @Override protected ReturnType runCommand(CommandSender sender, String... args) { - if(!(sender instanceof Player)) { + if (!(sender instanceof Player)) { sender.sendMessage(ChatColor.RED + "Command must be called as a player"); + return ReturnType.FAILURE; } - Player player = (Player) sender; - if (args.length != 0) - return ReturnType.SYNTAX_ERROR; + if (args.length != 0) return ReturnType.SYNTAX_ERROR; - if(VisualizeTask.togglePlayer(player)) - plugin.getLocale().getMessage("command.show.start").sendPrefixedMessage(player); - else - plugin.getLocale().getMessage("command.show.stop").sendPrefixedMessage(player); + boolean visualize = this.plugin.getAnchorManager().toggleChunkVisualized((Player) sender); + + plugin.getLocale().getMessage("command.show." + (visualize ? "start" : "stop")) + .sendPrefixedMessage(sender); return ReturnType.SUCCESS; } @Override protected List onTab(CommandSender sender, String... args) { - return null; + return Collections.emptyList(); } @Override public String getPermissionNode() { - return "epicanchors.show"; + return "EpicAnchors.cmd.show"; } @Override diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/guis/AnchorGui.java b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/guis/AnchorGui.java new file mode 100644 index 0000000..83d4fb9 --- /dev/null +++ b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/guis/AnchorGui.java @@ -0,0 +1,135 @@ +package com.songoda.epicanchors.guis; + +import com.songoda.core.compatibility.CompatibleMaterial; +import com.songoda.core.compatibility.CompatibleParticleHandler; +import com.songoda.core.compatibility.CompatibleSound; +import com.songoda.core.gui.Gui; +import com.songoda.core.gui.GuiUtils; +import com.songoda.core.hooks.EconomyManager; +import com.songoda.core.utils.TextUtils; +import com.songoda.core.utils.TimeUtils; +import com.songoda.epicanchors.Anchor; +import com.songoda.epicanchors.EpicAnchors; +import com.songoda.epicanchors.files.Settings; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.GameMode; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +public class AnchorGui extends Gui { + private final EpicAnchors plugin; + private final Anchor anchor; + + public AnchorGui(EpicAnchors plugin, Anchor anchor) { + this.plugin = plugin; + this.anchor = anchor; + + setRows(3); + setTitle(TextUtils.formatText(plugin.getLocale().getMessage("interface.anchor.title").getMessage())); + + constructGUI(); + runPreparedGuiTask(this.plugin, this, this.anchor); + } + + private void constructGUI() { + prepareGui(this.plugin, this, this.anchor); + + if (Settings.ADD_TIME_WITH_XP.getBoolean()) { + String itemName = plugin.getLocale().getMessage("interface.button.addtimewithxp").getMessage(); + String itemLore = plugin.getLocale().getMessage("interface.button.addtimewithxplore") + .processPlaceholder("cost", Settings.XP_COST.getInt()) + .getMessage(); + + setButton(11, + GuiUtils.createButtonItem(Settings.XP_ICON.getMaterial(CompatibleMaterial.EXPERIENCE_BOTTLE), itemName, itemLore), + event -> buyTime(anchor, event.player, false)); + } + + if (EconomyManager.isEnabled() && Settings.ADD_TIME_WITH_ECONOMY.getBoolean()) { + String itemName = plugin.getLocale().getMessage("interface.button.addtimewitheconomy").getMessage(); + String itemLore = plugin.getLocale().getMessage("interface.button.addtimewitheconomylore") + // EconomyManager#formatEconomy adds its own prefix/suffix + .processPlaceholder("cost", EconomyManager.formatEconomy(Settings.ECONOMY_COST.getDouble())) + .getMessage(); + + setButton(15, + GuiUtils.createButtonItem(Settings.ECO_ICON.getMaterial(CompatibleMaterial.SUNFLOWER), itemName, itemLore), + event -> buyTime(anchor, event.player, true)); + } + } + + private void buyTime(Anchor anchor, Player p, boolean eco) { + if (anchor.isInfinite()) { + this.plugin.getLocale().getMessage("interface.button.infinite").sendPrefixedMessage(p); + } else { + boolean success = false; + + if (eco) { + double cost = Settings.ECONOMY_COST.getDouble(); + + success = EconomyManager.withdrawBalance(p, cost); + } else { + int cost = Settings.XP_COST.getInt(); + + if (p.getLevel() >= cost || p.getGameMode() == GameMode.CREATIVE) { + if (p.getGameMode() != GameMode.CREATIVE) { + p.setLevel(p.getLevel() - cost); + } + + success = true; + } + } + + if (success) { + anchor.addTicksLeft(20 * 60 * 30); // 30 minutes + + p.playSound(p.getLocation(), CompatibleSound.ENTITY_PLAYER_LEVELUP.getSound(), 0.6F, 15); + CompatibleParticleHandler.spawnParticles(CompatibleParticleHandler.ParticleType.getParticle(Settings.PARTICLE_UPGRADE.getString()), + anchor.getLocation().add(.5, .5, .5), 100, .5, .5, .5); + } else { + this.plugin.getLocale().getMessage("event.upgrade.cannotafford").sendPrefixedMessage(p); + } + } + } + + protected static void prepareGui(EpicAnchors plugin, Gui gui, Anchor anchor) { + ItemStack glass1 = GuiUtils.getBorderItem(Settings.GLASS_TYPE_1.getMaterial()); + ItemStack glass2 = GuiUtils.getBorderItem(Settings.GLASS_TYPE_2.getMaterial()); + ItemStack glass3 = GuiUtils.getBorderItem(Settings.GLASS_TYPE_3.getMaterial()); + + gui.setDefaultItem(glass1); + + gui.mirrorFill(0, 0, true, true, glass2); + gui.mirrorFill(0, 1, true, true, glass2); + gui.mirrorFill(0, 2, true, true, glass3); + gui.mirrorFill(1, 0, false, true, glass2); + gui.mirrorFill(1, 1, false, true, glass3); + + String itemName = plugin.getLocale().getMessage("interface.anchor.smalltitle").getMessage(); + String itemLore = anchor.isInfinite() ? + ChatColor.GRAY + "Infinite" : + ChatColor.GRAY + TimeUtils.makeReadable((long) ((anchor.getTicksLeft() / 20.0) * 1000)) + " remaining."; + + gui.setItem(13, GuiUtils.createButtonItem(plugin.getAnchorManager().createAnchorItem( + anchor.getTicksLeft(), anchor.getLocation().getBlock().getType()), + itemName, itemLore)); + } + + protected static void runPreparedGuiTask(EpicAnchors plugin, Gui gui, Anchor anchor) { + int taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, () -> { + if (anchor.getTicksLeft() == 0) { + gui.close(); + } else { + String itemName = plugin.getLocale().getMessage("interface.anchor.smalltitle").getMessage(); + String itemLore = anchor.isInfinite() ? + ChatColor.GRAY + "Infinite" : + ChatColor.GRAY + TimeUtils.makeReadable((long) ((anchor.getTicksLeft() / 20.0) * 1000)) + " remaining."; + + gui.updateItem(13, itemName, itemLore); + } + }, 0, 20); + + gui.setOnClose(action -> Bukkit.getScheduler().cancelTask(taskId)); + } +} diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/guis/DestroyConfirmationGui.java b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/guis/DestroyConfirmationGui.java new file mode 100644 index 0000000..8eda9ac --- /dev/null +++ b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/guis/DestroyConfirmationGui.java @@ -0,0 +1,64 @@ +package com.songoda.epicanchors.guis; + +import com.songoda.core.compatibility.CompatibleMaterial; +import com.songoda.core.gui.Gui; +import com.songoda.core.gui.GuiUtils; +import com.songoda.core.gui.methods.Closable; +import com.songoda.core.utils.TextUtils; +import com.songoda.epicanchors.Anchor; +import com.songoda.epicanchors.EpicAnchors; +import com.songoda.epicanchors.files.Settings; +import com.songoda.epicanchors.utils.Callback; + +public class DestroyConfirmationGui extends Gui { + private final EpicAnchors plugin; + private final Anchor anchor; + + private Callback handler; + + public DestroyConfirmationGui(EpicAnchors plugin, Anchor anchor, Callback callback) { + this.plugin = plugin; + this.anchor = anchor; + + this.handler = (ex, result) -> { + this.handler = null; + this.close(); + + callback.accept(ex, result); + }; + + this.setRows(3); + this.setTitle(TextUtils.formatText(plugin.getLocale().getMessage("interface.anchor.title").getMessage())); + + constructGUI(); + AnchorGui.runPreparedGuiTask(this.plugin, this, this.anchor); + + Closable currClosable = this.closer; + this.closer = event -> { + currClosable.onClose(event); + + if (this.handler != null) { + this.handler.accept(null, false); + } + }; + } + + private void constructGUI() { + AnchorGui.prepareGui(this.plugin, this, this.anchor); + + String cancelLore = plugin.getLocale().getMessage("interface.button.cancelDestroyLore").getMessage(); + String confirmLore = plugin.getLocale().getMessage("interface.button." + + (Settings.ALLOW_ANCHOR_BREAKING.getBoolean() ? "confirmDestroyLore" : "confirmDestroyLoreNoDrops")) + .getMessage(); + + setButton(11, GuiUtils.createButtonItem(CompatibleMaterial.RED_TERRACOTTA, + plugin.getLocale().getMessage("interface.button.cancelDestroy").getMessage(), + cancelLore.isEmpty() ? new String[0] : new String[] {cancelLore}), + event -> this.handler.accept(null, false)); + + setButton(15, GuiUtils.createButtonItem(CompatibleMaterial.GREEN_TERRACOTTA, + plugin.getLocale().getMessage("interface.button.confirmDestroy").getMessage(), + confirmLore.isEmpty() ? new String[0] : new String[] {confirmLore}), + event -> this.handler.accept(null, true)); + } +} diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/AnchorListener.java b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/AnchorListener.java new file mode 100644 index 0000000..543fc53 --- /dev/null +++ b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/AnchorListener.java @@ -0,0 +1,126 @@ +package com.songoda.epicanchors.listener; + +import com.songoda.core.compatibility.CompatibleHand; +import com.songoda.core.compatibility.CompatibleParticleHandler; +import com.songoda.core.compatibility.CompatibleSound; +import com.songoda.epicanchors.Anchor; +import com.songoda.epicanchors.AnchorManager; +import com.songoda.epicanchors.EpicAnchors; +import com.songoda.epicanchors.files.Settings; +import com.songoda.epicanchors.guis.AnchorGui; +import com.songoda.epicanchors.guis.DestroyConfirmationGui; +import com.songoda.epicanchors.utils.Utils; +import org.bukkit.Bukkit; +import org.bukkit.GameMode; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; + +public class AnchorListener implements Listener { + private final EpicAnchors plugin; + + public AnchorListener(EpicAnchors instance) { + this.plugin = instance; + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockPlace(BlockPlaceEvent e) { + ItemStack item = e.getItemInHand(); + + if (item.hasItemMeta() && + item.getItemMeta().hasDisplayName() && + Settings.MATERIAL.getMaterial().getMaterial() == e.getBlock().getType()) { + if (!plugin.getAnchorManager().isReady(e.getBlock().getWorld())) { + e.setCancelled(true); + e.getPlayer().sendMessage("Anchors are still being initialized - Please wait a moment"); // TODO + } else { + int ticksLeft = AnchorManager.getTicksFromItem(item); + + if (ticksLeft != 0) { + boolean dropOnErr = e.getPlayer().getGameMode() != GameMode.CREATIVE; + + plugin.getAnchorManager().createAnchor(e.getBlock().getLocation(), e.getPlayer().getUniqueId(), ticksLeft, + (ex, result) -> { + if (ex != null) { + Utils.logException(this.plugin, ex, "SQLite"); + e.getPlayer().sendMessage("Error creating anchor!"); // TODO + + Bukkit.getScheduler().runTask(this.plugin, () -> { + if (Settings.MATERIAL.getMaterial().getMaterial() == e.getBlock().getType()) { + e.getBlock().setType(Material.AIR); + } + + if (dropOnErr) { + e.getBlock().getWorld().dropItemNaturally(e.getBlock().getLocation(), + plugin.getAnchorManager().createAnchorItem(ticksLeft, item.getType())); + } + }); + } + }); + } + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onBlockInteract(PlayerInteractEvent e) { + if (e.getClickedBlock() == null || + !plugin.getAnchorManager().isReady(e.getClickedBlock().getWorld())) return; + + Player p = e.getPlayer(); + Anchor anchor = plugin.getAnchorManager().getAnchor(e.getClickedBlock()); + + if (anchor != null) { + e.setCancelled(true); + + if (p.hasPermission("EpicAnchors.admin") || + this.plugin.getAnchorManager().hasAccess(anchor, p)) { + if (e.getAction() == Action.LEFT_CLICK_BLOCK) { // Destroy anchor + this.plugin.getGuiManager().showGUI(e.getPlayer(), + new DestroyConfirmationGui(this.plugin, anchor, (ex, result) -> { + if (result) { + BlockBreakEvent blockBreakEvent = new BlockBreakEvent(e.getClickedBlock(), p); + Bukkit.getPluginManager().callEvent(blockBreakEvent); + + if (!blockBreakEvent.isCancelled()) { + plugin.getAnchorManager().destroyAnchor(anchor); + } + } + })); + } else if (e.getAction() == Action.RIGHT_CLICK_BLOCK) { // Manage anchor + ItemStack item = CompatibleHand.MAIN_HAND.getItem(e.getPlayer()); + int itemTicks = AnchorManager.getTicksFromItem(item); + + if (itemTicks != 0) { + if (!anchor.isInfinite()) { + if (itemTicks == -1) { + anchor.setTicksLeft(-1); + } else { + anchor.addTicksLeft(itemTicks); + } + + if (p.getGameMode() != GameMode.CREATIVE) { + CompatibleHand.MAIN_HAND.takeItem(p, 1); + } + + p.playSound(p.getLocation(), CompatibleSound.ENTITY_PLAYER_LEVELUP.getSound(), .6F, 15); + CompatibleParticleHandler.spawnParticles(CompatibleParticleHandler.ParticleType.getParticle(Settings.PARTICLE_UPGRADE.getString()), + anchor.getLocation().add(.5, .5, .5), 100, .5, .5, .5); + } + } else { + plugin.getGuiManager().showGUI(p, new AnchorGui(plugin, anchor)); + } + } + } else { + plugin.getLocale().getMessage("event.general.nopermission").sendMessage(p); + } + } + } +} diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/BlockListener.java b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/BlockListener.java new file mode 100644 index 0000000..fb0ab77 --- /dev/null +++ b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/BlockListener.java @@ -0,0 +1,77 @@ +package com.songoda.epicanchors.listener; + +import com.songoda.epicanchors.AnchorManager; +import org.bukkit.block.Block; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBurnEvent; +import org.bukkit.event.block.BlockPhysicsEvent; +import org.bukkit.event.block.BlockPistonExtendEvent; +import org.bukkit.event.block.BlockPistonRetractEvent; +import org.bukkit.event.block.LeavesDecayEvent; +import org.bukkit.event.world.PortalCreateEvent; + +public class BlockListener implements Listener { + private final AnchorManager manager; + + public BlockListener(AnchorManager manager) { + this.manager = manager; + } + + @EventHandler(ignoreCancelled = true) + private void onBlockBurn(BlockBurnEvent e) { + if (!this.manager.isReady(e.getBlock().getWorld())) return; + + if (manager.isAnchor(e.getBlock())) { + e.setCancelled(true); + } + } + + @EventHandler(ignoreCancelled = true) + private void onBlockPiston(BlockPistonExtendEvent e) { + if (!this.manager.isReady(e.getBlock().getWorld())) return; + + if (manager.isAnchor(e.getBlock())) { + e.setCancelled(true); + } + } + + @EventHandler(ignoreCancelled = true) + private void onBlockPiston(BlockPistonRetractEvent e) { + if (!this.manager.isReady(e.getBlock().getWorld())) return; + + if (manager.isAnchor(e.getBlock())) { + e.setCancelled(true); + } + } + + @EventHandler(ignoreCancelled = true) + private void onBlockPhysics(BlockPhysicsEvent e) { + if (!this.manager.isReady(e.getBlock().getWorld())) return; + + if (manager.isAnchor(e.getBlock())) { + e.setCancelled(true); + } + } + + @EventHandler(ignoreCancelled = true) + private void onBlockPiston(LeavesDecayEvent e) { + if (!this.manager.isReady(e.getBlock().getWorld())) return; + + if (manager.isAnchor(e.getBlock())) { + e.setCancelled(true); + } + } + + @EventHandler(ignoreCancelled = true) + public void onPortalCreation(PortalCreateEvent e) { + if (!this.manager.isReady(e.getWorld())) return; + + for (Block b : e.getBlocks()) { + if (manager.isAnchor(b)) { + e.setCancelled(true); + break; + } + } + } +} diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/DebugListener.java b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/DebugListener.java new file mode 100644 index 0000000..b1f5b90 --- /dev/null +++ b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/DebugListener.java @@ -0,0 +1,154 @@ +package com.songoda.epicanchors.listener; + +import com.songoda.epicanchors.EpicAnchors; +import org.apache.commons.lang.WordUtils; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.block.BlockState; +import org.bukkit.entity.Entity; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockFormEvent; +import org.bukkit.event.block.BlockFromToEvent; +import org.bukkit.event.block.BlockGrowEvent; +import org.bukkit.event.block.BlockPhysicsEvent; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.event.entity.SpawnerSpawnEvent; +import org.bukkit.event.inventory.FurnaceSmeltEvent; +import org.bukkit.event.inventory.InventoryMoveItemEvent; +import org.bukkit.event.player.PlayerToggleSneakEvent; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +public class DebugListener implements Listener { + private final EpicAnchors plugin; + private final Logger logger; + + public DebugListener(EpicAnchors plugin) { + this.plugin = plugin; + + this.logger = Logger.getLogger(plugin.getName() + "-DEBUG"); + } + + private void logDebug(String s) { + LogRecord logRecord = new LogRecord(Level.INFO, s); + logRecord.setMessage("[" + this.logger.getName() + "] " + logRecord.getMessage()); + + this.logger.log(logRecord); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onBlockPhysics(BlockPhysicsEvent e) { + if (skipEvent(e.getBlock().getChunk())) return; + + logDebug("BlockPhysicsEvent (" + e.getBlock().getType() + ")"); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onBlockForm(BlockFormEvent e) { + if (skipEvent(e.getBlock().getChunk())) return; + + logDebug("BlockFormEvent (" + e.getBlock().getType() + " -> " + e.getNewState().getType() + ")"); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onBlockFromTo(BlockFromToEvent e) { + if (skipEvent(e.getBlock().getChunk())) return; + + logDebug("BlockFromToEvent"); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onFurnace(FurnaceSmeltEvent e) { + if (skipEvent(e.getBlock().getChunk())) return; + + logDebug("FurnaceSmeltEvent"); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onSneak(PlayerToggleSneakEvent e) { + Chunk chunk = e.getPlayer().getLocation().getChunk(); + + if (e.getPlayer().isFlying() || skipEvent(chunk)) return; + + Map count = new HashMap<>(); + + if (e.isSneaking()) { + e.getPlayer().sendMessage("§e§lEntities"); + for (Entity entity : chunk.getEntities()) { + count.compute(entity.getType().name(), (k, v) -> v == null ? 1 : v + 1); + } + } else { + e.getPlayer().sendMessage("§e§lTileEntities"); + for (BlockState blockState : chunk.getTileEntities()) { + count.compute(blockState.getType().name(), (k, v) -> v == null ? 1 : v + 1); + } + } + + Map m = count.entrySet().stream() + .sorted(Map.Entry.comparingByValue().reversed()) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, + (e1, e2) -> e1, LinkedHashMap::new)); + + for (Map.Entry entry : m.entrySet()) { + String entityName = WordUtils.capitalize(entry.getKey().toLowerCase(), new char[] {'_'}).replace("_", ""); + + e.getPlayer().sendMessage("§a" + entityName + "§7:§r " + entry.getValue()); + } + + e.getPlayer().sendMessage(""); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onSpawner(SpawnerSpawnEvent e) { + if (skipEvent(e.getSpawner().getBlock().getChunk())) return; + + logDebug("SpawnerSpawnEvent (" + e.getEntity().getType().name() + ")"); + } + + @EventHandler + private void onCreatureSpawn(CreatureSpawnEvent e) { + if (skipEvent(e.getLocation().getChunk())) return; + + logDebug("CreatureSpawnEvent (" + e.getEntity().getType().name() + ")"); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onBlockGrow(BlockGrowEvent e) { + if (skipEvent(e.getBlock().getChunk())) return; + + logDebug("BlockGrowEvent (" + e.getBlock().getType() + ")"); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onInvItemMove(InventoryMoveItemEvent e) { + if (e.getSource().getHolder() == null) return; + + Location loc = null; + + try { + loc = (Location) e.getSource().getHolder().getClass().getDeclaredMethod("getLocation").invoke(e.getSource().getHolder()); + } catch (Exception ex) { + try { + loc = (Location) e.getSource().getClass().getDeclaredMethod("getLocation").invoke(e.getSource()); + } catch (Exception ex2) { + logDebug("InventoryMoveItemEvent (Potentially in a chunk without Anchor [Not supported at current server version])"); + } + } + + if (loc == null || skipEvent(loc.getChunk())) return; + + logDebug("InventoryMoveItemEvent (" + e.getSource().getType() + " -> " + e.getDestination().getType() + ")"); + } + + private boolean skipEvent(Chunk chunk) { + return !this.plugin.getAnchorManager().isReady(chunk.getWorld()) || !this.plugin.getAnchorManager().hasAnchor(chunk); + } +} diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/WorldListener.java b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/WorldListener.java new file mode 100644 index 0000000..8e389ab --- /dev/null +++ b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/WorldListener.java @@ -0,0 +1,30 @@ +package com.songoda.epicanchors.listener; + +import org.bukkit.World; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.world.WorldLoadEvent; +import org.bukkit.event.world.WorldUnloadEvent; + +import java.util.function.Consumer; + +public class WorldListener implements Listener { + private final Consumer initAnchorsInWorld; + private final Consumer deInitAnchorsInWorld; + + public WorldListener(Consumer initAnchorsInWorld, Consumer deInitAnchorsInWorld) { + this.initAnchorsInWorld = initAnchorsInWorld; + this.deInitAnchorsInWorld = deInitAnchorsInWorld; + } + + @EventHandler(priority = EventPriority.MONITOR) + private void onWorldLoad(WorldLoadEvent e) { + initAnchorsInWorld.accept(e.getWorld()); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onWorldUnload(WorldUnloadEvent e) { + deInitAnchorsInWorld.accept(e.getWorld()); + } +} diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/tasks/AnchorTask.java b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/tasks/AnchorTask.java new file mode 100644 index 0000000..4dd2566 --- /dev/null +++ b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/tasks/AnchorTask.java @@ -0,0 +1,96 @@ +package com.songoda.epicanchors.tasks; + +import com.songoda.epicanchors.Anchor; +import com.songoda.epicanchors.AnchorManager; +import com.songoda.epicanchors.EpicAnchors; +import com.songoda.epicanchors.utils.Utils; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * More information about what types of game ticks there are and what does what: https://minecraft.fandom.com/wiki/Tick + */ +public class AnchorTask extends BukkitRunnable { + private static final int TASK_INTERVAL = 3; + + private final EpicAnchors plugin; + private final AnchorManager anchorManager; + + public AnchorTask(EpicAnchors plugin) { + this.plugin = plugin; + this.anchorManager = plugin.getAnchorManager(); + } + + public void startTask() { + runTaskTimer(this.plugin, TASK_INTERVAL, TASK_INTERVAL); + } + + @Override + public void run() { + try { + for (World world : Bukkit.getWorlds()) { + if (!this.anchorManager.isReady(world)) return; + + int randomTicks = this.anchorManager.getNMS().getRandomTickSpeed(world) * TASK_INTERVAL; + + Set alreadyTicked = new HashSet<>(); + Anchor[] anchorsInWorld = this.anchorManager.getAnchors(world); + List toUpdateHolo = new ArrayList<>(anchorsInWorld.length); + + // Skip all chunks with players in them + for (Player pInWorld : world.getPlayers()) { + alreadyTicked.add(pInWorld.getLocation().getChunk()); + } + + for (Anchor anchor : anchorsInWorld) { + Chunk chunk = anchor.getChunk(); + + // Tick the anchor's chunk (but not multiple times) + if (alreadyTicked.add(chunk)) { + // Having a chunk loaded takes care of entities and weather (https://minecraft.fandom.com/wiki/Tick#Chunk_tick) + if (!chunk.isLoaded()) { + // Loading an already loaded chunk still fires the ChunkLoadEvent and might have a huge + // impact on performance if other plugins do not expect that either... + + this.anchorManager.getNMS().loadAnchoredChunk(chunk); + chunk.load(); + } + + this.anchorManager.getNMS().doRandomTick(chunk, randomTicks); + this.anchorManager.getNMS().tickInactiveSpawners(chunk, TASK_INTERVAL); + } + + // TODO: Only update hologram if a player is nearby + // Simplify player location to chunks to potentially group players + // Use the server view distance to calculate minimum distance to count as not-nearby + + // Destroy anchors and queue hologram update + if (!anchor.isInfinite()) { + int ticksLeft = anchor.removeTicksLeft(3); + + if (ticksLeft == 0) { + this.anchorManager.destroyAnchor(anchor); + } else { + toUpdateHolo.add(anchor); + } + } else { + toUpdateHolo.add(anchor); + } + } + + // Update holograms on queued anchors + anchorManager.updateHolograms(toUpdateHolo); + } + } catch (Exception ex) { + Utils.logException(this.plugin, ex); + } + } +} diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/tasks/VisualizeTask.java b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/tasks/VisualizeTask.java new file mode 100644 index 0000000..b0b1b0b --- /dev/null +++ b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/tasks/VisualizeTask.java @@ -0,0 +1,113 @@ +package com.songoda.epicanchors.tasks; + +import com.songoda.core.compatibility.CompatibleParticleHandler; +import com.songoda.epicanchors.Anchor; +import com.songoda.epicanchors.EpicAnchors; +import com.songoda.epicanchors.files.Settings; +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class VisualizeTask extends BukkitRunnable { + private static final int TASK_INTERVAL = 30; + + private final EpicAnchors plugin; + + private final int radius = Bukkit.getServer().getViewDistance(); + + public VisualizeTask(EpicAnchors plugin) { + this.plugin = plugin; + } + + public void startTask() { + runTaskTimer(plugin, TASK_INTERVAL, TASK_INTERVAL); + } + + @Override + public void run() { + HashMap> chunksToVisualize = new HashMap<>(); + Set loadedChunks = new HashSet<>(); + + CompatibleParticleHandler.ParticleType particleType = CompatibleParticleHandler.ParticleType.getParticle(Settings.PARTICLE_VISUALIZER.getString()); + + for (World world : Bukkit.getWorlds()) { + if (!this.plugin.getAnchorManager().isReady(world)) continue; + + loadedChunks.clear(); + for (Anchor anchor : this.plugin.getAnchorManager().getAnchors(world)) { + loadedChunks.add(anchor.getChunk()); + } + + if (!loadedChunks.isEmpty()) { + for (Player p : world.getPlayers()) { + if (!this.plugin.getAnchorManager().hasChunksVisualized(p)) continue; + + Location pLoc = p.getLocation(); + + // start and stop chunk coordinates + int cxi = (pLoc.getBlockX() >> 4) - radius; + int cxn = cxi + radius * 2; + int czi = (pLoc.getBlockZ() >> 4) - radius; + int czn = czi + radius * 2; + + // loop through the chunks to find applicable ones + for (int cx = cxi; cx < cxn; ++cx) { + for (int cz = czi; cz < czn; ++cz) { + Chunk chunk = world.getChunkAt(cx, cz); + + if (loadedChunks.contains(chunk)) { + chunksToVisualize.computeIfAbsent(chunk, k -> new HashSet<>()) + .add(p); + } + } + } + } + } + } + + for (Map.Entry> entry : chunksToVisualize.entrySet()) { + int maxY = entry.getKey().getWorld().getMaxHeight(); + + for (Player p : entry.getValue()) { + int startY = p.getLocation().getBlockY() + 2; + + if (startY <= 0) continue; + + // loop through the chunk + for (int x = 0; x < 16; ++x) { + for (int z = 0; z < 16; ++z) { + if (Math.random() < .125) { // Don't spawn particles on each block + if (startY >= maxY) { + startY = maxY - 1; + } + + Block b = entry.getKey().getBlock(x, startY, z); + + for (int i = 0; i < 12; ++i) { + if (b.getType().isSolid()) break; + + b = b.getRelative(BlockFace.DOWN); + } + + if (!b.isEmpty() && !b.getRelative(BlockFace.UP).getType().isOccluding()) { + CompatibleParticleHandler.spawnParticles(particleType, + b.getLocation().add(.5, 1.5, .5), + 0, 0, 0, 0, 1, p); + } + } + } + } + } + } + } +} diff --git a/src/main/resources/en_US.lang b/modules/epicanchors-plugin/src/main/resources/en_US.lang similarity index 73% rename from src/main/resources/en_US.lang rename to modules/epicanchors-plugin/src/main/resources/en_US.lang index 94a1891..cfb736e 100644 --- a/src/main/resources/en_US.lang +++ b/modules/epicanchors-plugin/src/main/resources/en_US.lang @@ -14,9 +14,16 @@ interface: addtimewithxplore: '&7Cost: &a%cost% Levels' addtimewitheconomy: '&aAdd 30 Minutes with ECO' addtimewitheconomylore: '&7Cost: &a$%cost%' + + cancelDestroy: '&4Cancel' + cancelDestroyLore: '' + confirmDestroy: '&2Confirm' + confirmDestroyLore: '&aA new anchor with the remaining time will be dropped.' + confirmDestroyLoreNoDrops: '&4The remaining time on this anchor will be lost!' + infinite: '&cCannot upgrade an infinite anchor!' anchor: - title: ChunkAnchor + title: 'ChunkAnchor' smalltitle: '&eChunkAnchor' # Command Messages diff --git a/modules/epicanchors-plugin/src/main/resources/plugin.yml b/modules/epicanchors-plugin/src/main/resources/plugin.yml new file mode 100644 index 0000000..21bf3bf --- /dev/null +++ b/modules/epicanchors-plugin/src/main/resources/plugin.yml @@ -0,0 +1,29 @@ +name: ${project.parent.name} +description: ${project.parent.description} +version: ${project.parent.version} +api-version: 1.13 + +main: com.songoda.epicanchors.EpicAnchors +softdepend: + - Holograms + - HolographicDisplays + - Vault + +author: Songoda +authors: [ SpraxDev ] +website: ${project.parent.url} + +commands: + EpicAnchors: + aliases: + - ea + +permissions: + EpicAnchors.cmd.show: + default: true + + EpicAnchors.admin: + children: + EpicAnchors.cmd.reload: true + EpicAnchors.cmd.settings: true + EpicAnchors.cmd.give: true diff --git a/modules/nms/epicanchors-v1_10_R1/pom.xml b/modules/nms/epicanchors-v1_10_R1/pom.xml new file mode 100644 index 0000000..d231d96 --- /dev/null +++ b/modules/nms/epicanchors-v1_10_R1/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + + com.songoda + EpicAnchors + 2.0.0-ALPHA + ../../../pom.xml + + jar + epicanchors-v1_10_R1 + + + + com.songoda + epicanchors-api + ${project.version} + + + + org.spigotmc + spigot-api + 1.10.2-R0.1-SNAPSHOT + provided + + + + org.spigotmc + spigot + 1.10.2 + provided + + + diff --git a/modules/nms/epicanchors-v1_10_R1/src/main/java/epicanchors/nms/v1_10_R1.java b/modules/nms/epicanchors-v1_10_R1/src/main/java/epicanchors/nms/v1_10_R1.java new file mode 100644 index 0000000..5b0b286 --- /dev/null +++ b/modules/nms/epicanchors-v1_10_R1/src/main/java/epicanchors/nms/v1_10_R1.java @@ -0,0 +1,267 @@ +package epicanchors.nms; + +import com.songoda.epicanchors.AnchorNMS; +import com.songoda.epicanchors.utils.ReflectionUtils; +import com.songoda.epicanchors.utils.Utils; +import net.minecraft.server.v1_10_R1.AxisAlignedBB; +import net.minecraft.server.v1_10_R1.Block; +import net.minecraft.server.v1_10_R1.BlockPosition; +import net.minecraft.server.v1_10_R1.ChunkRegionLoader; +import net.minecraft.server.v1_10_R1.ChunkSection; +import net.minecraft.server.v1_10_R1.Entity; +import net.minecraft.server.v1_10_R1.EntityInsentient; +import net.minecraft.server.v1_10_R1.EnumParticle; +import net.minecraft.server.v1_10_R1.IBlockData; +import net.minecraft.server.v1_10_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_10_R1.MobSpawnerData; +import net.minecraft.server.v1_10_R1.NBTTagCompound; +import net.minecraft.server.v1_10_R1.NBTTagList; +import net.minecraft.server.v1_10_R1.WorldServer; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.v1_10_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_10_R1.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.v1_10_R1.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class v1_10_R1 extends AnchorNMS { + @SuppressWarnings("unused") + public v1_10_R1(JavaPlugin plugin) { + super(plugin); + } + + @Override + public boolean loadAnchoredChunk(Chunk chunk) { + return chunk.load(); + } + + @Override + public boolean unloadAnchoredChunk(Chunk chunk) { + return chunk.unload(); + } + + @Override + public void tickInactiveSpawners(Chunk chunk, int amount) { + if (amount <= 0) return; + + try { + for (BlockState tileEntity : chunk.getTileEntities()) { + if (tileEntity instanceof CreatureSpawner) { + MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); + + for (int i = 0; i < amount; ++i) { + if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { + break; // Spawner not inactive + } + } + } + } + } catch (Exception ex) { + Utils.logException(super.plugin, ex); + } + } + + @Override + public void doRandomTick(Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); + } + + @Override + public int getRandomTickSpeed(World world) { + return Helper.getRandomTickSpeedLegacy(world); + } + + /** + * This class contains some modified methods from {@link WorldServer}. + */ + private static class NotchianServerLevel { + /** + * Method is based on {@link WorldServer#j()}. + */ + static void randomTickChunk(net.minecraft.server.v1_10_R1.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + if (tickAmount > 0) { + int j = chunk.locX * 16; + int k = chunk.locZ * 16; + + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != net.minecraft.server.v1_10_R1.Chunk.a && chunksection.shouldTick()) { + for (int i = 0; i < tickAmount; ++i) { + int worldL = (int) ReflectionUtils.getFieldValue(chunk.world, "l"); + worldL = worldL * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "l", worldL); + + int l1 = worldL >> 2; + int i2 = l1 & 15; + int j2 = l1 >> 8 & 15; + int k2 = l1 >> 16 & 15; + + IBlockData iblockdata = chunksection.getType(i2, k2, j2); + Block block = iblockdata.getBlock(); + + if (block.isTicking()) { + block.a(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), iblockdata, chunk.world.random); + } + } + } + } + } + } + } + + /** + * This class contains some modified methods from {@link MobSpawnerAbstract}. + */ + private static class NotchianBaseSpawner { + private static Method iMethod, hMethod; + + static { + try { + iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); + iMethod.setAccessible(true); + + hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); + hMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + Utils.logException(null, ex); + } + } + + static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); + + return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); + } + + /** + * This method calls {@link MobSpawnerAbstract#h()} using Reflections. + */ + static boolean isNearPlayer(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + return (boolean) hMethod.invoke(spawner); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + * + * @return false if the spawner is not inactive, true otherwise + */ + static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { + if (isNearPlayer(spawner)) return false; + + BlockPosition blockposition = spawner.b(); + + if (spawner.a().isClientSide) { + double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + + spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d0, d1, d2, 0D, 0D, 0D); + spawner.a().addParticle(EnumParticle.FLAME, d0, d1, d2, 0D, 0D, 0D); + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerD = (double) ReflectionUtils.getFieldValue(spawner, "d"); + + ReflectionUtils.setFieldValue(spawner, "e", spawnerD); + ReflectionUtils.setFieldValue(spawner, "d", (spawnerD + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return true; + } + + boolean flag = false; + int i = 0; + + int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); + int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); + int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); + MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); + + while (true) { + if (i >= spawnCount) { + if (flag) { + delay(spawner); + } + + break; + } + + NBTTagCompound nbttagcompound = spawnData.b(); + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + + net.minecraft.server.v1_10_R1.World world = spawner.a(); + + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.e(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.e(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.e(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; + + Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); + + if (entity == null) { + return true; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB(blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawnRange)).size(); + + if (k >= maxNearbyEntities) { + delay(spawner); + return true; + } + + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360.0F, 0.0F); + + if (entityinsentient == null || entityinsentient.cK() && entityinsentient.canSpawn()) { + if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { + ((EntityInsentient) entity).prepare(world.D(new BlockPosition(entity)), null); + } + + if (entity.world.spigotConfig.nerfSpawnerMobs) { + entity.fromMobSpawner = true; + } + + if (!CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); + world.triggerEffect(2004, blockposition, 0); + if (entityinsentient != null) { + entityinsentient.doSpawnEffect(); + } + + flag = true; + } + } + + ++i; + } + } + + return true; + } + + /** + * This method calls {@link MobSpawnerAbstract#i()} using Reflections. + */ + static void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + iMethod.invoke(spawner); + } + } +} diff --git a/modules/nms/epicanchors-v1_11_R1/pom.xml b/modules/nms/epicanchors-v1_11_R1/pom.xml new file mode 100644 index 0000000..e184ffa --- /dev/null +++ b/modules/nms/epicanchors-v1_11_R1/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + + com.songoda + EpicAnchors + 2.0.0-ALPHA + ../../../pom.xml + + jar + epicanchors-v1_11_R1 + + + + com.songoda + epicanchors-api + ${project.version} + + + + org.spigotmc + spigot-api + 1.11-R0.1-SNAPSHOT + provided + + + + org.spigotmc + spigot + 1.11.2 + provided + + + diff --git a/modules/nms/epicanchors-v1_11_R1/src/main/java/epicanchors/nms/v1_11_R1.java b/modules/nms/epicanchors-v1_11_R1/src/main/java/epicanchors/nms/v1_11_R1.java new file mode 100644 index 0000000..55f9d59 --- /dev/null +++ b/modules/nms/epicanchors-v1_11_R1/src/main/java/epicanchors/nms/v1_11_R1.java @@ -0,0 +1,262 @@ +package epicanchors.nms; + +import com.songoda.epicanchors.AnchorNMS; +import com.songoda.epicanchors.utils.ReflectionUtils; +import com.songoda.epicanchors.utils.Utils; +import net.minecraft.server.v1_11_R1.AxisAlignedBB; +import net.minecraft.server.v1_11_R1.Block; +import net.minecraft.server.v1_11_R1.BlockPosition; +import net.minecraft.server.v1_11_R1.ChunkRegionLoader; +import net.minecraft.server.v1_11_R1.ChunkSection; +import net.minecraft.server.v1_11_R1.Entity; +import net.minecraft.server.v1_11_R1.EntityInsentient; +import net.minecraft.server.v1_11_R1.EnumParticle; +import net.minecraft.server.v1_11_R1.IBlockData; +import net.minecraft.server.v1_11_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_11_R1.MobSpawnerData; +import net.minecraft.server.v1_11_R1.NBTTagCompound; +import net.minecraft.server.v1_11_R1.NBTTagList; +import net.minecraft.server.v1_11_R1.WorldServer; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.v1_11_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_11_R1.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.v1_11_R1.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class v1_11_R1 extends AnchorNMS { + @SuppressWarnings("unused") + public v1_11_R1(JavaPlugin plugin) { + super(plugin); + } + + @Override + public boolean loadAnchoredChunk(Chunk chunk) { + return chunk.load(); + } + + @Override + public boolean unloadAnchoredChunk(Chunk chunk) { + return chunk.unload(); + } + + @Override + public void tickInactiveSpawners(Chunk chunk, int amount) { + if (amount <= 0) return; + + try { + for (BlockState tileEntity : chunk.getTileEntities()) { + if (tileEntity instanceof CreatureSpawner) { + MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); + + for (int i = 0; i < amount; ++i) { + if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { + break; // Spawner not inactive + } + } + } + } + } catch (Exception ex) { + Utils.logException(super.plugin, ex); + } + } + + @Override + public void doRandomTick(Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); + } + + @Override + public int getRandomTickSpeed(World world) { + return Helper.getRandomTickSpeedLegacy(world); + } + + /** + * This class contains some modified methods from {@link WorldServer}. + */ + private static class NotchianServerLevel { + /** + * Method is based on {@link WorldServer#j()}. + */ + static void randomTickChunk(net.minecraft.server.v1_11_R1.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + if (tickAmount > 0) { + int j = chunk.locX * 16; + int k = chunk.locZ * 16; + + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != net.minecraft.server.v1_11_R1.Chunk.a && chunksection.shouldTick()) { + for (int i = 0; i < tickAmount; ++i) { + int worldL = (int) ReflectionUtils.getFieldValue(chunk.world, "l"); + worldL = worldL * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "l", worldL); + + int l1 = worldL >> 2; + int i2 = l1 & 15; + int j2 = l1 >> 8 & 15; + int k2 = l1 >> 16 & 15; + + IBlockData iblockdata = chunksection.getType(i2, k2, j2); + Block block = iblockdata.getBlock(); + + if (block.isTicking()) { + block.a(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), iblockdata, chunk.world.random); + } + } + } + } + } + } + } + + /** + * This class contains some modified methods from {@link MobSpawnerAbstract}. + */ + private static class NotchianBaseSpawner { + private static Method iMethod, hMethod; + + static { + try { + hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); + hMethod.setAccessible(true); + + iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); + iMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + Utils.logException(null, ex); + } + } + + static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); + + return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); + } + + /** + * This method calls {@link MobSpawnerAbstract#h()} using Reflections. + */ + static boolean isNearPlayer(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + return (boolean) hMethod.invoke(spawner); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + * + * @return false if the spawner is not inactive, true otherwise + */ + static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { + if (isNearPlayer(spawner)) return false; + + BlockPosition blockposition = spawner.b(); + + if (spawner.a().isClientSide) { + double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + + spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d0, d1, d2, 0D, 0D, 0D); + spawner.a().addParticle(EnumParticle.FLAME, d0, d1, d2, 0D, 0D, 0D); + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerD = (double) ReflectionUtils.getFieldValue(spawner, "d"); + + ReflectionUtils.setFieldValue(spawner, "e", spawnerD); + ReflectionUtils.setFieldValue(spawner, "d", (spawnerD + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return true; + } + + boolean flag = false; + int i = 0; + + int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); + int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); + int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); + MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); + + while (true) { + if (i >= spawnCount) { + if (flag) { + delay(spawner); + } + break; + } + + NBTTagCompound nbttagcompound = spawnData.b(); + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + net.minecraft.server.v1_11_R1.World world = spawner.a(); + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.e(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.e(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.e(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; + Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); + if (entity == null) { + return true; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawnRange)).size(); + if (k >= maxNearbyEntities) { + delay(spawner); + return true; + } + + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360.0F, 0.0F); + if (entityinsentient == null || entityinsentient.cM() && entityinsentient.canSpawn()) { + if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { + ((EntityInsentient) entity).prepare(world.D(new BlockPosition(entity)), null); + } + + if (entity.world.spigotConfig.nerfSpawnerMobs) { + entity.fromMobSpawner = true; + } + + if (!CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); + world.triggerEffect(2004, blockposition, 0); + + if (entityinsentient != null) { + entityinsentient.doSpawnEffect(); + } + + flag = true; + } + } + + ++i; + } + } + + return true; + } + + /** + * This method calls {@link MobSpawnerAbstract#i()} using Reflections. + */ + static void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + iMethod.invoke(spawner); + } + } +} diff --git a/modules/nms/epicanchors-v1_12_R1/pom.xml b/modules/nms/epicanchors-v1_12_R1/pom.xml new file mode 100644 index 0000000..d003f47 --- /dev/null +++ b/modules/nms/epicanchors-v1_12_R1/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + + com.songoda + EpicAnchors + 2.0.0-ALPHA + ../../../pom.xml + + jar + epicanchors-v1_12_R1 + + + + com.songoda + epicanchors-api + ${project.version} + + + + org.spigotmc + spigot-api + 1.12.2-R0.1-SNAPSHOT + provided + + + + org.spigotmc + spigot + 1.12.2 + provided + + + diff --git a/modules/nms/epicanchors-v1_12_R1/src/main/java/epicanchors/nms/v1_12_R1.java b/modules/nms/epicanchors-v1_12_R1/src/main/java/epicanchors/nms/v1_12_R1.java new file mode 100644 index 0000000..3133a4f --- /dev/null +++ b/modules/nms/epicanchors-v1_12_R1/src/main/java/epicanchors/nms/v1_12_R1.java @@ -0,0 +1,266 @@ +package epicanchors.nms; + +import com.songoda.epicanchors.AnchorNMS; +import com.songoda.epicanchors.utils.ReflectionUtils; +import com.songoda.epicanchors.utils.Utils; +import net.minecraft.server.v1_12_R1.AxisAlignedBB; +import net.minecraft.server.v1_12_R1.Block; +import net.minecraft.server.v1_12_R1.BlockPosition; +import net.minecraft.server.v1_12_R1.ChunkRegionLoader; +import net.minecraft.server.v1_12_R1.ChunkSection; +import net.minecraft.server.v1_12_R1.Entity; +import net.minecraft.server.v1_12_R1.EntityInsentient; +import net.minecraft.server.v1_12_R1.EnumParticle; +import net.minecraft.server.v1_12_R1.IBlockData; +import net.minecraft.server.v1_12_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_12_R1.MobSpawnerData; +import net.minecraft.server.v1_12_R1.NBTTagCompound; +import net.minecraft.server.v1_12_R1.NBTTagList; +import net.minecraft.server.v1_12_R1.WorldServer; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.v1_12_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_12_R1.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.v1_12_R1.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class v1_12_R1 extends AnchorNMS { + @SuppressWarnings("unused") + public v1_12_R1(JavaPlugin plugin) { + super(plugin); + } + + @Override + public boolean loadAnchoredChunk(Chunk chunk) { + return chunk.load(); + } + + @Override + public boolean unloadAnchoredChunk(Chunk chunk) { + return chunk.unload(); + } + + @Override + public void tickInactiveSpawners(Chunk chunk, int amount) { + if (amount <= 0) return; + + try { + for (BlockState tileEntity : chunk.getTileEntities()) { + if (tileEntity instanceof CreatureSpawner) { + MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); + + for (int i = 0; i < amount; ++i) { + if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { + break; // Spawner not inactive + } + } + } + } + } catch (Exception ex) { + Utils.logException(super.plugin, ex); + } + } + + @Override + public void doRandomTick(Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); + } + + @Override + public int getRandomTickSpeed(World world) { + return Helper.getRandomTickSpeedLegacy(world); + } + + /** + * This class contains some modified methods from {@link WorldServer}. + */ + private static class NotchianServerLevel { + /** + * Method is based on {@link WorldServer#j()}. + */ + static void randomTickChunk(net.minecraft.server.v1_12_R1.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + if (tickAmount > 0) { + int j = chunk.locX * 16; + int k = chunk.locZ * 16; + + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != net.minecraft.server.v1_12_R1.Chunk.a && chunksection.shouldTick()) { + for (int k1 = 0; k1 < tickAmount; ++k1) { + int worldL = (int) ReflectionUtils.getFieldValue(chunk.world, "l"); + worldL = worldL * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "l", worldL); + + int l1 = worldL >> 2; + int i2 = l1 & 15; + int j2 = l1 >> 8 & 15; + int k2 = l1 >> 16 & 15; + + IBlockData iblockdata = chunksection.getType(i2, k2, j2); + Block block = iblockdata.getBlock(); + + if (block.isTicking()) { + block.a(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), iblockdata, chunk.world.random); + } + } + } + } + } + } + } + + /** + * This class contains some modified methods from {@link MobSpawnerAbstract}. + */ + private static class NotchianBaseSpawner { + private static Method iMethod; + + static { + try { + iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); + iMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + Utils.logException(null, ex); + } + } + + static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); + + return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); + } + + /** + * This method is based on {@link MobSpawnerAbstract#h()}. + */ + static boolean isNearPlayer(MobSpawnerAbstract spawner) { + BlockPosition blockposition = spawner.b(); + + return spawner.a().isPlayerNearby( + (double) blockposition.getX() + 0.5D, + (double) blockposition.getY() + 0.5D, + (double) blockposition.getZ() + 0.5D, + spawner.requiredPlayerRange); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + * + * @return false if the spawner is not inactive, true otherwise + */ + static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { + if (isNearPlayer(spawner)) return false; + + BlockPosition blockposition = spawner.b(); + + if (spawner.a().isClientSide) { + double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d0, d1, d2, 0.0D, 0.0D, 0.0D); + spawner.a().addParticle(EnumParticle.FLAME, d0, d1, d2, 0.0D, 0.0D, 0.0D); + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerD = (double) ReflectionUtils.getFieldValue(spawner, "d"); + + ReflectionUtils.setFieldValue(spawner, "e", spawnerD); + ReflectionUtils.setFieldValue(spawner, "d", (spawnerD + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return true; + } + + boolean flag = false; + int i = 0; + + MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); + + while (true) { + if (i >= spawner.spawnCount) { + if (flag) { + delay(spawner); + } + break; + } + + NBTTagCompound nbttagcompound = spawnData.b(); + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + + net.minecraft.server.v1_12_R1.World world = spawner.a(); + + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.f(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.f(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.f(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + + Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); + + if (entity == null) { + return true; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawner.spawnRange)).size(); + + if (k >= spawner.maxNearbyEntities) { + delay(spawner); + return true; + } + + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360.0F, 0.0F); + + if (entityinsentient == null || entityinsentient.P() && entityinsentient.canSpawn()) { + if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { + ((EntityInsentient) entity).prepare(world.D(new BlockPosition(entity)), null); + } + + if (entity.world.spigotConfig.nerfSpawnerMobs) { + entity.fromMobSpawner = true; + } + + if (!CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); + world.triggerEffect(2004, blockposition, 0); + + if (entityinsentient != null) { + entityinsentient.doSpawnEffect(); + } + + flag = true; + } + } + + ++i; + } + } + + return true; + } + + /** + * This method calls {@link MobSpawnerAbstract#i()} using Reflections. + */ + static void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + iMethod.invoke(spawner); + } + } +} diff --git a/modules/nms/epicanchors-v1_13_R1/pom.xml b/modules/nms/epicanchors-v1_13_R1/pom.xml new file mode 100644 index 0000000..bf7b4e9 --- /dev/null +++ b/modules/nms/epicanchors-v1_13_R1/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + + com.songoda + EpicAnchors + 2.0.0-ALPHA + ../../../pom.xml + + jar + epicanchors-v1_13_R1 + + + + com.songoda + epicanchors-api + ${project.version} + + + + org.spigotmc + spigot-api + 1.13-R0.1-SNAPSHOT + provided + + + + org.spigotmc + spigot + 1.13 + provided + + + diff --git a/modules/nms/epicanchors-v1_13_R1/src/main/java/epicanchors/nms/v1_13_R1.java b/modules/nms/epicanchors-v1_13_R1/src/main/java/epicanchors/nms/v1_13_R1.java new file mode 100644 index 0000000..e9df416 --- /dev/null +++ b/modules/nms/epicanchors-v1_13_R1/src/main/java/epicanchors/nms/v1_13_R1.java @@ -0,0 +1,282 @@ +package epicanchors.nms; + +import com.songoda.epicanchors.AnchorNMS; +import com.songoda.epicanchors.utils.ReflectionUtils; +import com.songoda.epicanchors.utils.Utils; +import net.minecraft.server.v1_13_R1.AxisAlignedBB; +import net.minecraft.server.v1_13_R1.BlockPosition; +import net.minecraft.server.v1_13_R1.ChunkRegionLoader; +import net.minecraft.server.v1_13_R1.ChunkSection; +import net.minecraft.server.v1_13_R1.Entity; +import net.minecraft.server.v1_13_R1.EntityInsentient; +import net.minecraft.server.v1_13_R1.Fluid; +import net.minecraft.server.v1_13_R1.IBlockData; +import net.minecraft.server.v1_13_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_13_R1.MobSpawnerData; +import net.minecraft.server.v1_13_R1.NBTTagCompound; +import net.minecraft.server.v1_13_R1.NBTTagList; +import net.minecraft.server.v1_13_R1.Particles; +import net.minecraft.server.v1_13_R1.WorldServer; +import org.bukkit.Chunk; +import org.bukkit.GameRule; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.v1_13_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_13_R1.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.v1_13_R1.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class v1_13_R1 extends AnchorNMS { + @SuppressWarnings("unused") + public v1_13_R1(JavaPlugin plugin) { + super(plugin); + } + + @Override + public boolean loadAnchoredChunk(Chunk chunk) { + return chunk.load(); + } + + @Override + public boolean unloadAnchoredChunk(Chunk chunk) { + return chunk.unload(); + } + + @Override + public void tickInactiveSpawners(Chunk chunk, int amount) { + if (amount <= 0) return; + + try { + for (BlockState tileEntity : chunk.getTileEntities()) { + if (tileEntity instanceof CreatureSpawner) { + MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); + + for (int i = 0; i < amount; ++i) { + if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { + break; // Spawner not inactive + } + } + } + } + } catch (Exception ex) { + Utils.logException(super.plugin, ex); + } + } + + @Override + public void doRandomTick(Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); + } + + @Override + public int getRandomTickSpeed(World world) { + Integer result = world.getGameRuleValue(GameRule.RANDOM_TICK_SPEED); + + if (result == null) { + result = world.getGameRuleDefault(GameRule.RANDOM_TICK_SPEED); + } + + return result == null ? 3 : result; + } + + /** + * This class contains some modified methods from {@link WorldServer} + * which originally (vanilla server) goes by the name ServerLevel. + */ + private static class NotchianServerLevel { + /** + * Method is based on {@link WorldServer#l()}. + */ + static void randomTickChunk(net.minecraft.server.v1_13_R1.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + if (tickAmount > 0) { + int j = chunk.locX * 16; + int k = chunk.locZ * 16; + + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != net.minecraft.server.v1_13_R1.Chunk.a && chunksection.b()) { + for (int i = 0; i < tickAmount; ++i) { + int worldM = (int) ReflectionUtils.getFieldValue(chunk.world, "m"); + worldM = worldM * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "m", worldM); + + int l1 = worldM >> 2; + int i2 = l1 & 15; + int j2 = l1 >> 8 & 15; + int k2 = l1 >> 16 & 15; + + IBlockData iblockdata = chunksection.getType(i2, k2, j2); + Fluid fluid = chunksection.b(i2, k2, j2); + + if (iblockdata.t()) { + iblockdata.b(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), chunk.world.random); + } + + if (fluid.h()) { + fluid.b(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), chunk.world.random); + } + } + } + } + } + } + } + + /** + * This class contains some modified methods from {@link MobSpawnerAbstract} + * which originally (vanilla server) goes by the name BaseSpawner. + */ + private static class NotchianBaseSpawner { + private static Method iMethod; + + static { + try { + iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); + iMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + Utils.logException(null, ex); + } + } + + static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); + + return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); + } + + /** + * This method is based on {@link MobSpawnerAbstract#h()}. + */ + static boolean isNearPlayer(MobSpawnerAbstract spawner) { + BlockPosition blockposition = spawner.b(); + + return spawner.a().isPlayerNearby( + (double) blockposition.getX() + .5D, + (double) blockposition.getY() + .5D, + (double) blockposition.getZ() + .5D, + spawner.requiredPlayerRange); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + * + * @return false if the spawner is not inactive, true otherwise + */ + static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { + if (isNearPlayer(spawner)) return false; + + BlockPosition blockposition = spawner.b(); + + if (spawner.a().isClientSide) { + double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + + spawner.a().addParticle(Particles.M, d0, d1, d2, 0D, 0D, 0D); + spawner.a().addParticle(Particles.y, d0, d1, d2, 0D, 0D, 0D); + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return true; + } + + boolean flag = false; + int i = 0; + + MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); + + while (true) { + if (i >= spawner.spawnCount) { + if (flag) { + delay(spawner); + } + + break; + } + + NBTTagCompound nbttagcompound = spawnData.b(); + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + + net.minecraft.server.v1_13_R1.World world = spawner.a(); + + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.k(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.k(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.k(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + + Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); + + if (entity == null) { + delay(spawner); + return true; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB(blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawner.spawnRange)).size(); + + if (k >= spawner.maxNearbyEntities) { + delay(spawner); + return true; + } + + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360F, 0F); + + if (entityinsentient == null || entityinsentient.M() && entityinsentient.canSpawn()) { + if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { + ((EntityInsentient) entity).prepare(world.getDamageScaler(new BlockPosition(entity)), null, null); + } + + if (entity.world.spigotConfig.nerfSpawnerMobs) { + entity.fromMobSpawner = true; + } + + if (!CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); + world.triggerEffect(2004, blockposition, 0); + + if (entityinsentient != null) { + entityinsentient.doSpawnEffect(); + } + + flag = true; + } + } + + ++i; + } + } + + return true; + } + + /** + * This method calls {@link MobSpawnerAbstract#i()} using Reflections. + */ + static void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + iMethod.invoke(spawner); + } + } +} diff --git a/modules/nms/epicanchors-v1_13_R2/pom.xml b/modules/nms/epicanchors-v1_13_R2/pom.xml new file mode 100644 index 0000000..b70e26b --- /dev/null +++ b/modules/nms/epicanchors-v1_13_R2/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + + com.songoda + EpicAnchors + 2.0.0-ALPHA + ../../../pom.xml + + jar + epicanchors-v1_13_R2 + + + + com.songoda + epicanchors-api + ${project.version} + + + + org.spigotmc + spigot-api + 1.13.2-R0.1-SNAPSHOT + provided + + + + org.spigotmc + spigot + 1.13.2 + provided + + + diff --git a/modules/nms/epicanchors-v1_13_R2/src/main/java/epicanchors/nms/v1_13_R2.java b/modules/nms/epicanchors-v1_13_R2/src/main/java/epicanchors/nms/v1_13_R2.java new file mode 100644 index 0000000..5a7ab7f --- /dev/null +++ b/modules/nms/epicanchors-v1_13_R2/src/main/java/epicanchors/nms/v1_13_R2.java @@ -0,0 +1,294 @@ +package epicanchors.nms; + +import com.songoda.epicanchors.AnchorNMS; +import com.songoda.epicanchors.utils.ReflectionUtils; +import com.songoda.epicanchors.utils.Utils; +import net.minecraft.server.v1_13_R2.AxisAlignedBB; +import net.minecraft.server.v1_13_R2.BlockPosition; +import net.minecraft.server.v1_13_R2.ChunkRegionLoader; +import net.minecraft.server.v1_13_R2.ChunkSection; +import net.minecraft.server.v1_13_R2.Entity; +import net.minecraft.server.v1_13_R2.EntityInsentient; +import net.minecraft.server.v1_13_R2.Fluid; +import net.minecraft.server.v1_13_R2.IBlockData; +import net.minecraft.server.v1_13_R2.MobSpawnerAbstract; +import net.minecraft.server.v1_13_R2.MobSpawnerData; +import net.minecraft.server.v1_13_R2.NBTTagCompound; +import net.minecraft.server.v1_13_R2.NBTTagList; +import net.minecraft.server.v1_13_R2.Particles; +import net.minecraft.server.v1_13_R2.WorldServer; +import org.bukkit.Chunk; +import org.bukkit.GameRule; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.v1_13_R2.CraftChunk; +import org.bukkit.craftbukkit.v1_13_R2.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.v1_13_R2.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Iterator; + +public class v1_13_R2 extends AnchorNMS { + @SuppressWarnings("unused") + public v1_13_R2(JavaPlugin plugin) { + super(plugin); + } + + @Override + public boolean loadAnchoredChunk(Chunk chunk) { + return chunk.load(); + } + + @Override + public boolean unloadAnchoredChunk(Chunk chunk) { + return chunk.unload(); + } + + @Override + public void tickInactiveSpawners(Chunk chunk, int amount) { + if (amount <= 0) return; + + try { + for (BlockState tileEntity : chunk.getTileEntities()) { + if (tileEntity instanceof CreatureSpawner) { + MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); + + for (int i = 0; i < amount; ++i) { + if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { + break; // Spawner not inactive + } + } + } + } + } catch (Exception ex) { + Utils.logException(super.plugin, ex); + } + } + + @Override + public void doRandomTick(Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); + } + + @Override + public int getRandomTickSpeed(World world) { + Integer result = world.getGameRuleValue(GameRule.RANDOM_TICK_SPEED); + + if (result == null) { + result = world.getGameRuleDefault(GameRule.RANDOM_TICK_SPEED); + } + + return result == null ? 3 : result; + } + + /** + * This class contains some modified methods from {@link WorldServer} + * which originally (vanilla server) goes by the name ServerLevel. + */ + private static class NotchianServerLevel { + /** + * Method is based on {@link WorldServer#n_()}. + */ + static void randomTickChunk(net.minecraft.server.v1_13_R2.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + if (tickAmount > 0) { + int j = chunk.locX * 16; + int k = chunk.locZ * 16; + + chunk.world.methodProfiler.enter("tickBlocks"); + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != net.minecraft.server.v1_13_R2.Chunk.a && chunksection.b()) { + for (int k1 = 0; k1 < tickAmount; ++k1) { + int worldM = (int) ReflectionUtils.getFieldValue(chunk.world, "m"); + worldM = worldM * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "m", worldM); + + int l1 = worldM >> 2; + int i2 = l1 & 15; + int j2 = l1 >> 8 & 15; + int k2 = l1 >> 16 & 15; + + IBlockData iblockdata = chunksection.getType(i2, k2, j2); + Fluid fluid = chunksection.b(i2, k2, j2); + + chunk.world.methodProfiler.enter("randomTick"); + + if (iblockdata.t()) { + iblockdata.b(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), chunk.world.random); + } + + if (fluid.h()) { + fluid.b(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), chunk.world.random); + } + + chunk.world.methodProfiler.exit(); + } + } + } + + chunk.world.methodProfiler.exit(); + } + } + } + + /** + * This class contains some modified methods from {@link MobSpawnerAbstract} + * which originally (vanilla server) goes by the name BaseSpawner. + */ + private static class NotchianBaseSpawner { + private static Method iMethod; + + static { + try { + iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); + iMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + Utils.logException(null, ex); + } + } + + static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); + + return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); + } + + /** + * This method is based on {@link MobSpawnerAbstract#h()}. + */ + static boolean isNearPlayer(MobSpawnerAbstract spawner) { + BlockPosition blockposition = spawner.b(); + + return spawner.a().b( + (double) blockposition.getX() + .5D, + (double) blockposition.getY() + .5D, + (double) blockposition.getZ() + .5D, + spawner.requiredPlayerRange); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + * + * @return false if the spawner is not inactive, true otherwise + */ + static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { + if (isNearPlayer(spawner)) return false; + + BlockPosition blockposition = spawner.b(); + + if (spawner.a().isClientSide) { + double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + spawner.a().addParticle(Particles.M, d0, d1, d2, 0.0D, 0.0D, 0.0D); + spawner.a().addParticle(Particles.y, d0, d1, d2, 0.0D, 0.0D, 0.0D); + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return true; + } + + boolean flag = false; + int i = 0; + + MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); + + while (true) { + if (i >= spawner.spawnCount) { + if (flag) { + delay(spawner); + } + + break; + } + + NBTTagCompound nbttagcompound = spawnData.b(); + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + net.minecraft.server.v1_13_R2.World world = spawner.a(); + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.k(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.k(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.k(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); + if (entity == null) { + delay(spawner); + return true; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawner.spawnRange)).size(); + + if (k >= spawner.maxNearbyEntities) { + delay(spawner); + return true; + } + + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360.0F, 0.0F); + if (entityinsentient == null || entityinsentient.a(world, true) && entityinsentient.canSpawn()) { + if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { + ((EntityInsentient) entity).prepare(world.getDamageScaler(new BlockPosition(entity)), null, null); + } + + if (entity.world.spigotConfig.nerfSpawnerMobs) { + entity.fromMobSpawner = true; + } + + if (CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + Entity vehicle = entity.getVehicle(); + if (vehicle != null) { + vehicle.dead = true; + } + + Entity passenger; + for (Iterator var19 = entity.getAllPassengers().iterator(); var19.hasNext(); passenger.dead = true) { + passenger = var19.next(); + } + } else { + ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); + world.triggerEffect(2004, blockposition, 0); + + if (entityinsentient != null) { + entityinsentient.doSpawnEffect(); + } + + flag = true; + } + } + + ++i; + } + } + + return true; + } + + /** + * This method calls {@link MobSpawnerAbstract#i()} using Reflections. + */ + static void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + iMethod.invoke(spawner); + } + } +} diff --git a/modules/nms/epicanchors-v1_14_R1/pom.xml b/modules/nms/epicanchors-v1_14_R1/pom.xml new file mode 100644 index 0000000..c8ecdea --- /dev/null +++ b/modules/nms/epicanchors-v1_14_R1/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + + com.songoda + EpicAnchors + 2.0.0-ALPHA + ../../../pom.xml + + jar + epicanchors-v1_14_R1 + + + + com.songoda + epicanchors-api + ${project.version} + + + + org.spigotmc + spigot-api + 1.14.4-R0.1-SNAPSHOT + provided + + + + org.spigotmc + spigot + 1.14.4 + provided + + + diff --git a/modules/nms/epicanchors-v1_14_R1/src/main/java/epicanchors/nms/v1_14_R1.java b/modules/nms/epicanchors-v1_14_R1/src/main/java/epicanchors/nms/v1_14_R1.java new file mode 100644 index 0000000..197a985 --- /dev/null +++ b/modules/nms/epicanchors-v1_14_R1/src/main/java/epicanchors/nms/v1_14_R1.java @@ -0,0 +1,304 @@ +package epicanchors.nms; + +import com.songoda.epicanchors.AnchorNMS; +import com.songoda.epicanchors.utils.ReflectionUtils; +import com.songoda.epicanchors.utils.Utils; +import net.minecraft.server.v1_14_R1.*; +import org.bukkit.Chunk; +import org.bukkit.GameRule; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.v1_14_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_14_R1.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.v1_14_R1.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.Iterator; +import java.util.Optional; + +public class v1_14_R1 extends AnchorNMS { + @SuppressWarnings("unused") + public v1_14_R1(JavaPlugin plugin) { + super(plugin); + } + + @Override + public boolean loadAnchoredChunk(Chunk chunk) { + return chunk.load(); + } + + @Override + public boolean unloadAnchoredChunk(Chunk chunk) { + return chunk.unload(); + } + + @Override + public void tickInactiveSpawners(Chunk chunk, int amount) { + if (amount <= 0) return; + + try { + for (BlockState tileEntity : chunk.getTileEntities()) { + if (tileEntity instanceof CreatureSpawner) { + MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); + + for (int i = 0; i < amount; ++i) { + if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { + break; // Spawner not inactive + } + } + } + } + } catch (Exception ex) { + Utils.logException(super.plugin, ex); + } + } + + @Override + public void doRandomTick(Chunk chunk, int tickAmount) { + NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); + } + + @Override + public int getRandomTickSpeed(World world) { + Integer result = world.getGameRuleValue(GameRule.RANDOM_TICK_SPEED); + + if (result == null) { + result = world.getGameRuleDefault(GameRule.RANDOM_TICK_SPEED); + } + + return result == null ? 3 : result; + } + + /** + * This class contains some modified methods from {@link WorldServer} + * which originally (vanilla server) goes by the name ServerLevel. + */ + private static class NotchianServerLevel { + /** + * Method is based on {@link WorldServer#a(net.minecraft.server.v1_14_R1.Chunk, int)}. + */ + static void randomTickChunk(net.minecraft.server.v1_14_R1.Chunk chunk, int tickAmount) { + if (tickAmount > 0) { + ChunkCoordIntPair chunkcoordintpair = chunk.getPos(); + int j = chunkcoordintpair.d(); + int k = chunkcoordintpair.e(); + + GameProfilerFiller profiler = chunk.world.getMethodProfiler(); + + profiler.enter("tickBlocks"); + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != net.minecraft.server.v1_14_R1.Chunk.a && chunksection.d()) { + int j1 = chunksection.getYPosition(); + + for (int i = 0; i < tickAmount; ++i) { + BlockPosition blockposition2 = chunk.world.a(j, j1, k, 15); + profiler.enter("randomTick"); + IBlockData iblockdata = chunksection.getType(blockposition2.getX() - j, blockposition2.getY() - j1, blockposition2.getZ() - k); + + if (iblockdata.q()) { + iblockdata.b(chunk.world, blockposition2, chunk.world.random); + } + + Fluid fluid = iblockdata.p(); + if (fluid.h()) { + fluid.b(chunk.world, blockposition2, chunk.world.random); + } + + profiler.exit(); + } + } + } + + profiler.exit(); + } + } + } + + /** + * This class contains some modified methods from {@link MobSpawnerAbstract} + * which originally (vanilla server) goes by the name BaseSpawner. + */ + private static class NotchianBaseSpawner { + static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); + + return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); + } + + /** + * This method is based on {@link MobSpawnerAbstract#h()}. + */ + static boolean isNearPlayer(MobSpawnerAbstract spawner) { + BlockPosition blockposition = spawner.b(); + + return spawner.a().isPlayerNearby( + (double) blockposition.getX() + .5D, + (double) blockposition.getY() + .5D, + (double) blockposition.getZ() + .5D, + spawner.requiredPlayerRange); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + * + * @return false if the spawner is not inactive, true otherwise + */ + static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException { + if (isNearPlayer(spawner)) return false; + + net.minecraft.server.v1_14_R1.World world = spawner.a(); + BlockPosition blockposition = spawner.b(); + + if (world.isClientSide) { + double d0 = (float) blockposition.getX() + world.random.nextFloat(); + double d1 = (float) blockposition.getY() + world.random.nextFloat(); + double d2 = (float) blockposition.getZ() + world.random.nextFloat(); + + world.addParticle(Particles.SMOKE, d0, d1, d2, 0D, 0D, 0D); + world.addParticle(Particles.FLAME, d0, d1, d2, 0D, 0D, 0D); + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return true; + } + + boolean flag = false; + int i = 0; + + while (true) { + if (i >= spawner.spawnCount) { + if (flag) { + delay(spawner); + } + + break; + } + + NBTTagCompound nbttagcompound = spawner.spawnData.getEntity(); + Optional> optional = EntityTypes.a(nbttagcompound); + if (!optional.isPresent()) { + delay(spawner); + return true; + } + + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.h(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.h(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.h(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + if (world.c(optional.get().a(d3, d4, d5)) && EntityPositionTypes.a(optional.get(), world.getMinecraftWorld(), EnumMobSpawn.SPAWNER, new BlockPosition(d3, d4, d5), world.getRandom())) { + label112: + { + Entity entity = EntityTypes.a(nbttagcompound, world, (entity1) -> { + entity1.setPositionRotation(d3, d4, d5, entity1.yaw, entity1.pitch); + return entity1; + }); + if (entity == null) { + delay(spawner); + return true; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawner.spawnRange)).size(); + + if (k >= spawner.maxNearbyEntities) { + delay(spawner); + return true; + } + + entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360F, 0F); + if (entity instanceof EntityInsentient) { + EntityInsentient entityinsentient = (EntityInsentient) entity; + if (!entityinsentient.a(world, EnumMobSpawn.SPAWNER) || !entityinsentient.a(world)) { + break label112; + } + + if (spawner.spawnData.getEntity().d() == 1 && spawner.spawnData.getEntity().hasKeyOfType("id", 8)) { + ((EntityInsentient) entity).prepare(world, world.getDamageScaler(new BlockPosition(entity)), EnumMobSpawn.SPAWNER, null, null); + } + } + + if (entity.world.spigotConfig.nerfSpawnerMobs) { + entity.fromMobSpawner = true; + } + + if (CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + Entity vehicle = entity.getVehicle(); + if (vehicle != null) { + vehicle.dead = true; + } + + Entity passenger; + for (Iterator var19 = entity.getAllPassengers().iterator(); var19.hasNext(); passenger.dead = true) { + passenger = var19.next(); + } + } else { + addWithPassengers(spawner, entity); + world.triggerEffect(2004, blockposition, 0); + + if (entity instanceof EntityInsentient) { + ((EntityInsentient) entity).doSpawnEffect(); + } + + flag = true; + } + } + } + + ++i; + } + } + + return true; + } + + /** + * This method is based on {@link MobSpawnerAbstract#i()}. + */ + static void delay(MobSpawnerAbstract spawner) { + if (spawner.maxSpawnDelay <= spawner.minSpawnDelay) { + spawner.spawnDelay = spawner.minSpawnDelay; + } else { + int i = spawner.maxSpawnDelay - spawner.minSpawnDelay; + spawner.spawnDelay = spawner.minSpawnDelay + spawner.a().random.nextInt(i); + } + + if (!spawner.mobs.isEmpty()) { + spawner.setSpawnData(WeightedRandom.a(spawner.a().random, spawner.mobs)); + } + + spawner.a(1); + } + + /** + * This method is based on {@link MobSpawnerAbstract#a(Entity)}. + */ + static void addWithPassengers(MobSpawnerAbstract spawner, Entity entity) { + if (spawner.a().addEntity(entity, CreatureSpawnEvent.SpawnReason.SPAWNER)) { + for (Entity value : entity.getPassengers()) { + addWithPassengers(spawner, value); + } + } + } + } +} diff --git a/modules/nms/epicanchors-v1_15_R1/pom.xml b/modules/nms/epicanchors-v1_15_R1/pom.xml new file mode 100644 index 0000000..8498d5c --- /dev/null +++ b/modules/nms/epicanchors-v1_15_R1/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + + com.songoda + EpicAnchors + 2.0.0-ALPHA + ../../../pom.xml + + jar + epicanchors-v1_15_R1 + + + + com.songoda + epicanchors-api + ${project.version} + + + + org.spigotmc + spigot-api + 1.15.2-R0.1-SNAPSHOT + provided + + + + org.spigotmc + spigot + 1.15.2 + provided + + + diff --git a/modules/nms/epicanchors-v1_15_R1/src/main/java/epicanchors/nms/v1_15_R1.java b/modules/nms/epicanchors-v1_15_R1/src/main/java/epicanchors/nms/v1_15_R1.java new file mode 100644 index 0000000..51e5544 --- /dev/null +++ b/modules/nms/epicanchors-v1_15_R1/src/main/java/epicanchors/nms/v1_15_R1.java @@ -0,0 +1,303 @@ +package epicanchors.nms; + +import com.songoda.epicanchors.AnchorNMS; +import com.songoda.epicanchors.utils.ReflectionUtils; +import com.songoda.epicanchors.utils.Utils; +import net.minecraft.server.v1_15_R1.*; +import org.bukkit.Chunk; +import org.bukkit.GameRule; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.v1_15_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_15_R1.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.v1_15_R1.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.Iterator; +import java.util.Optional; + +public class v1_15_R1 extends AnchorNMS { + @SuppressWarnings("unused") + public v1_15_R1(JavaPlugin plugin) { + super(plugin); + } + + @Override + public boolean loadAnchoredChunk(Chunk chunk) { + return chunk.addPluginChunkTicket(super.plugin); + } + + @Override + public boolean unloadAnchoredChunk(Chunk chunk) { + chunk.removePluginChunkTicket(super.plugin); + + return chunk.unload(); + } + + @Override + public void tickInactiveSpawners(Chunk chunk, int amount) { + if (amount <= 0) return; + + try { + for (BlockState tileEntity : chunk.getTileEntities()) { + if (tileEntity instanceof CreatureSpawner) { + MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); + + for (int i = 0; i < amount; ++i) { + if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { + break; // Spawner not inactive + } + } + } + } + } catch (Exception ex) { + Utils.logException(super.plugin, ex); + } + } + + @Override + public void doRandomTick(Chunk chunk, int tickAmount) { + NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); + } + + @Override + public int getRandomTickSpeed(World world) { + Integer result = world.getGameRuleValue(GameRule.RANDOM_TICK_SPEED); + + if (result == null) { + result = world.getGameRuleDefault(GameRule.RANDOM_TICK_SPEED); + } + + return result == null ? 3 : result; + } + + /** + * This class contains some modified methods from {@link WorldServer} + * which originally (vanilla server) goes by the name ServerLevel. + */ + private static class NotchianServerLevel { + /** + * Method is based on {@link WorldServer#a(net.minecraft.server.v1_15_R1.Chunk, int)}. + */ + static void randomTickChunk(net.minecraft.server.v1_15_R1.Chunk chunk, int tickAmount) { + if (tickAmount > 0) { + ChunkCoordIntPair chunkcoordintpair = chunk.getPos(); + int j = chunkcoordintpair.d(); + int k = chunkcoordintpair.e(); + GameProfilerFiller profiler = chunk.world.getMethodProfiler(); + + profiler.enter("tickBlocks"); + + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != net.minecraft.server.v1_15_R1.Chunk.a && chunksection.d()) { + int j1 = chunksection.getYPosition(); + + for (int k1 = 0; k1 < tickAmount; ++k1) { + BlockPosition blockposition2 = chunk.world.a(j, j1, k, 15); + profiler.enter("randomTick"); + IBlockData iblockdata = chunksection.getType(blockposition2.getX() - j, blockposition2.getY() - j1, blockposition2.getZ() - k); + + if (iblockdata.q()) { + iblockdata.b((WorldServer) chunk.world, blockposition2, chunk.world.random); + } + + Fluid fluid = iblockdata.getFluid(); + if (fluid.h()) { + fluid.b(chunk.world, blockposition2, chunk.world.random); + } + + profiler.exit(); + } + } + } + + profiler.exit(); + } + } + } + + /** + * This class contains some modified methods from {@link MobSpawnerAbstract} + * which originally (vanilla server) goes by the name BaseSpawner. + */ + private static class NotchianBaseSpawner { + static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); + + return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); + } + + /** + * This method is based on {@link MobSpawnerAbstract#h()}. + */ + static boolean isNearPlayer(MobSpawnerAbstract spawner) { + BlockPosition blockposition = spawner.b(); + + return spawner.a().isPlayerNearby( + (double) blockposition.getX() + .5D, + (double) blockposition.getY() + .5D, + (double) blockposition.getZ() + .5D, + spawner.requiredPlayerRange); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + * + * @return false if the spawner is not inactive, true otherwise + */ + static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException { + if (isNearPlayer(spawner)) return false; + + net.minecraft.server.v1_15_R1.World world = spawner.a(); + BlockPosition blockposition = spawner.b(); + + if (world.isClientSide) { + double d0 = (double) blockposition.getX() + (double) world.random.nextFloat(); + double d1 = (double) blockposition.getY() + (double) world.random.nextFloat(); + double d2 = (double) blockposition.getZ() + (double) world.random.nextFloat(); + world.addParticle(Particles.SMOKE, d0, d1, d2, 0.0D, 0.0D, 0.0D); + world.addParticle(Particles.FLAME, d0, d1, d2, 0.0D, 0.0D, 0.0D); + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return true; + } + + boolean flag = false; + int i = 0; + + while (true) { + if (i >= spawner.spawnCount) { + if (flag) { + delay(spawner); + } + + break; + } + + NBTTagCompound nbttagcompound = spawner.spawnData.getEntity(); + Optional> optional = EntityTypes.a(nbttagcompound); + if (!optional.isPresent()) { + delay(spawner); + return true; + } + + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.h(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.h(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.h(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + if (world.a(optional.get().a(d3, d4, d5)) && EntityPositionTypes.a(optional.get(), world.getMinecraftWorld(), EnumMobSpawn.SPAWNER, new BlockPosition(d3, d4, d5), world.getRandom())) { + label112: + { + Entity entity = EntityTypes.a(nbttagcompound, world, (entity1) -> { + entity1.setPositionRotation(d3, d4, d5, entity1.yaw, entity1.pitch); + return entity1; + }); + if (entity == null) { + delay(spawner); + return true; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawner.spawnRange)).size(); + + if (k >= spawner.maxNearbyEntities) { + delay(spawner); + return true; + } + + entity.setPositionRotation(entity.locX(), entity.locY(), entity.locZ(), world.random.nextFloat() * 360F, 0F); + if (entity instanceof EntityInsentient) { + EntityInsentient entityinsentient = (EntityInsentient) entity; + if (!entityinsentient.a(world, EnumMobSpawn.SPAWNER) || !entityinsentient.a(world)) { + break label112; + } + + if (spawner.spawnData.getEntity().e() == 1 && spawner.spawnData.getEntity().hasKeyOfType("id", 8)) { + ((EntityInsentient) entity).prepare(world, world.getDamageScaler(new BlockPosition(entity)), EnumMobSpawn.SPAWNER, null, null); + } + + if (entityinsentient.world.spigotConfig.nerfSpawnerMobs) { + entityinsentient.aware = false; + } + } + + if (CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + Entity vehicle = entity.getVehicle(); + if (vehicle != null) { + vehicle.dead = true; + } + + Entity passenger; + for (Iterator var19 = entity.getAllPassengers().iterator(); var19.hasNext(); passenger.dead = true) { + passenger = var19.next(); + } + } else { + addWithPassengers(spawner, entity); + world.triggerEffect(2004, blockposition, 0); + if (entity instanceof EntityInsentient) { + ((EntityInsentient) entity).doSpawnEffect(); + } + + flag = true; + } + } + } + + ++i; + } + } + + return true; + } + + /** + * This method is based on {@link MobSpawnerAbstract#i()}. + */ + static void delay(MobSpawnerAbstract spawner) { + if (spawner.maxSpawnDelay <= spawner.minSpawnDelay) { + spawner.spawnDelay = spawner.minSpawnDelay; + } else { + int i = spawner.maxSpawnDelay - spawner.minSpawnDelay; + spawner.spawnDelay = spawner.minSpawnDelay + spawner.a().random.nextInt(i); + } + + if (!spawner.mobs.isEmpty()) { + spawner.setSpawnData(WeightedRandom.a(spawner.a().random, spawner.mobs)); + } + + spawner.a(1); + } + + /** + * This method is based on {@link MobSpawnerAbstract#a(Entity)}. + */ + static void addWithPassengers(MobSpawnerAbstract spawner, Entity entity) { + if (spawner.a().addEntity(entity, CreatureSpawnEvent.SpawnReason.SPAWNER)) { + for (Entity entity1 : entity.getPassengers()) { + addWithPassengers(spawner, entity1); + } + } + } + } +} diff --git a/modules/nms/epicanchors-v1_16_R1/pom.xml b/modules/nms/epicanchors-v1_16_R1/pom.xml new file mode 100644 index 0000000..572b7d6 --- /dev/null +++ b/modules/nms/epicanchors-v1_16_R1/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + + com.songoda + EpicAnchors + 2.0.0-ALPHA + ../../../pom.xml + + jar + epicanchors-v1_16_R1 + + + + com.songoda + epicanchors-api + ${project.version} + + + + org.spigotmc + spigot-api + 1.16.1-R0.1-SNAPSHOT + provided + + + + org.spigotmc + spigot + 1.16.1 + provided + + + diff --git a/modules/nms/epicanchors-v1_16_R1/src/main/java/epicanchors/nms/v1_16_R1.java b/modules/nms/epicanchors-v1_16_R1/src/main/java/epicanchors/nms/v1_16_R1.java new file mode 100644 index 0000000..3910f39 --- /dev/null +++ b/modules/nms/epicanchors-v1_16_R1/src/main/java/epicanchors/nms/v1_16_R1.java @@ -0,0 +1,302 @@ +package epicanchors.nms; + +import com.songoda.epicanchors.AnchorNMS; +import com.songoda.epicanchors.utils.ReflectionUtils; +import com.songoda.epicanchors.utils.Utils; +import net.minecraft.server.v1_16_R1.*; +import org.bukkit.Chunk; +import org.bukkit.GameRule; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.v1_16_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_16_R1.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.v1_16_R1.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.Iterator; +import java.util.Optional; + +public class v1_16_R1 extends AnchorNMS { + @SuppressWarnings("unused") + public v1_16_R1(JavaPlugin plugin) { + super(plugin); + } + + @Override + public boolean loadAnchoredChunk(Chunk chunk) { + return chunk.addPluginChunkTicket(super.plugin); + } + + @Override + public boolean unloadAnchoredChunk(Chunk chunk) { + chunk.removePluginChunkTicket(super.plugin); + + return chunk.unload(); + } + + @Override + public void tickInactiveSpawners(Chunk chunk, int amount) { + if (amount <= 0) return; + + try { + for (BlockState tileEntity : chunk.getTileEntities()) { + if (tileEntity instanceof CreatureSpawner) { + MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); + + for (int i = 0; i < amount; ++i) { + if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { + break; // Spawner not inactive + } + } + } + } + } catch (Exception ex) { + Utils.logException(super.plugin, ex); + } + } + + @Override + public void doRandomTick(Chunk chunk, int tickAmount) { + NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); + } + + @Override + public int getRandomTickSpeed(World world) { + Integer result = world.getGameRuleValue(GameRule.RANDOM_TICK_SPEED); + + if (result == null) { + result = world.getGameRuleDefault(GameRule.RANDOM_TICK_SPEED); + } + + return result == null ? 3 : result; + } + + /** + * This class contains some modified methods from {@link WorldServer} + * which originally (vanilla server) goes by the name ServerLevel. + */ + private static class NotchianServerLevel { + /** + * Method is based on {@link WorldServer#a(net.minecraft.server.v1_16_R1.Chunk, int)}. + */ + static void randomTickChunk(net.minecraft.server.v1_16_R1.Chunk chunk, int tickAmount) { + if (tickAmount > 0) { + ChunkCoordIntPair chunkcoordintpair = chunk.getPos(); + int j = chunkcoordintpair.d(); + int k = chunkcoordintpair.e(); + + GameProfilerFiller profiler = chunk.world.getMethodProfiler(); + + profiler.enter("tickBlocks"); + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != net.minecraft.server.v1_16_R1.Chunk.a && chunksection.d()) { + int j1 = chunksection.getYPosition(); + + for (int k1 = 0; k1 < tickAmount; ++k1) { + BlockPosition blockposition2 = chunk.world.a(j, j1, k, 15); + profiler.enter("randomTick"); + + IBlockData iblockdata = chunksection.getType(blockposition2.getX() - j, blockposition2.getY() - j1, blockposition2.getZ() - k); + + if (iblockdata.isTicking()) { + iblockdata.b(chunk.world, blockposition2, chunk.world.random); + } + + Fluid fluid = iblockdata.getFluid(); + if (fluid.f()) { + fluid.b(chunk.world, blockposition2, chunk.world.random); + } + + profiler.exit(); + } + } + } + + profiler.exit(); + } + } + } + + /** + * This class contains some modified methods from {@link MobSpawnerAbstract} + * which originally (vanilla server) goes by the name BaseSpawner. + */ + private static class NotchianBaseSpawner { + static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); + + return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); + } + + /** + * This method is based on {@link MobSpawnerAbstract#h()}. + */ + static boolean isNearPlayer(MobSpawnerAbstract spawner) { + BlockPosition blockposition = spawner.b(); + + return spawner.a().isPlayerNearby((double) blockposition.getX() + .5D, + (double) blockposition.getY() + .5D, + (double) blockposition.getZ() + .5D, + spawner.requiredPlayerRange); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + * + * @return false if the spawner is not inactive, true otherwise + */ + static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException { + if (isNearPlayer(spawner)) return false; + + net.minecraft.server.v1_16_R1.World world = spawner.a(); + BlockPosition blockposition = spawner.b(); + + if (world.isClientSide) { + double d0 = (double) blockposition.getX() + world.random.nextDouble(); + double d1 = (double) blockposition.getY() + world.random.nextDouble(); + double d2 = (double) blockposition.getZ() + world.random.nextDouble(); + world.addParticle(Particles.SMOKE, d0, d1, d2, 0.0D, 0.0D, 0.0D); + world.addParticle(Particles.FLAME, d0, d1, d2, 0.0D, 0.0D, 0.0D); + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return true; + } + + boolean flag = false; + int i = 0; + + while (true) { + if (i >= spawner.spawnCount) { + if (flag) { + delay(spawner); + } + break; + } + + NBTTagCompound nbttagcompound = spawner.spawnData.getEntity(); + Optional> optional = EntityTypes.a(nbttagcompound); + if (!optional.isPresent()) { + delay(spawner); + return true; + } + + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.h(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.h(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.h(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + if (world.b(optional.get().a(d3, d4, d5)) && EntityPositionTypes.a(optional.get(), world.getMinecraftWorld(), EnumMobSpawn.SPAWNER, new BlockPosition(d3, d4, d5), world.getRandom())) { + label112: + { + Entity entity = EntityTypes.a(nbttagcompound, world, (entity1) -> { + entity1.setPositionRotation(d3, d4, d5, entity1.yaw, entity1.pitch); + return entity1; + }); + if (entity == null) { + delay(spawner); + return true; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawner.spawnRange)).size(); + if (k >= spawner.maxNearbyEntities) { + delay(spawner); + return true; + } + + entity.setPositionRotation(entity.locX(), entity.locY(), entity.locZ(), world.random.nextFloat() * 360.0F, 0.0F); + if (entity instanceof EntityInsentient) { + EntityInsentient entityinsentient = (EntityInsentient) entity; + if (!entityinsentient.a(world, EnumMobSpawn.SPAWNER) || !entityinsentient.a(world)) { + break label112; + } + + if (spawner.spawnData.getEntity().e() == 1 && spawner.spawnData.getEntity().hasKeyOfType("id", 8)) { + ((EntityInsentient) entity).prepare(world, world.getDamageScaler(entity.getChunkCoordinates()), EnumMobSpawn.SPAWNER, null, null); + } + + if (entityinsentient.world.spigotConfig.nerfSpawnerMobs) { + entityinsentient.aware = false; + } + } + + if (CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + Entity vehicle = entity.getVehicle(); + if (vehicle != null) { + vehicle.dead = true; + } + + Entity passenger; + for (Iterator var19 = entity.getAllPassengers().iterator(); var19.hasNext(); passenger.dead = true) { + passenger = var19.next(); + } + } else { + addWithPassengers(spawner, entity); + world.triggerEffect(2004, blockposition, 0); + if (entity instanceof EntityInsentient) { + ((EntityInsentient) entity).doSpawnEffect(); + } + + flag = true; + } + } + } + + ++i; + } + } + + return true; + } + + /** + * This method is based on {@link MobSpawnerAbstract#i()}. + */ + static void delay(MobSpawnerAbstract spawner) { + if (spawner.maxSpawnDelay <= spawner.minSpawnDelay) { + spawner.spawnDelay = spawner.minSpawnDelay; + } else { + int i = spawner.maxSpawnDelay - spawner.minSpawnDelay; + spawner.spawnDelay = spawner.minSpawnDelay + spawner.a().random.nextInt(i); + } + + if (!spawner.mobs.isEmpty()) { + spawner.setSpawnData(WeightedRandom.a(spawner.a().random, spawner.mobs)); + } + + spawner.a(1); + } + + /** + * This method is based on {@link MobSpawnerAbstract#a(Entity)}. + */ + static void addWithPassengers(MobSpawnerAbstract spawner, Entity entity) { + if (spawner.a().addEntity(entity, CreatureSpawnEvent.SpawnReason.SPAWNER)) { + + for (Entity entity1 : entity.getPassengers()) { + addWithPassengers(spawner, entity1); + } + } + } + } +} diff --git a/modules/nms/epicanchors-v1_16_R2/pom.xml b/modules/nms/epicanchors-v1_16_R2/pom.xml new file mode 100644 index 0000000..df83392 --- /dev/null +++ b/modules/nms/epicanchors-v1_16_R2/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + + com.songoda + EpicAnchors + 2.0.0-ALPHA + ../../../pom.xml + + jar + epicanchors-v1_16_R2 + + + + com.songoda + epicanchors-api + ${project.version} + + + + org.spigotmc + spigot-api + 1.16.3-R0.1-SNAPSHOT + provided + + + + org.spigotmc + spigot + 1.16.2 + provided + + + diff --git a/modules/nms/epicanchors-v1_16_R2/src/main/java/epicanchors/nms/v1_16_R2.java b/modules/nms/epicanchors-v1_16_R2/src/main/java/epicanchors/nms/v1_16_R2.java new file mode 100644 index 0000000..d2c7f6c --- /dev/null +++ b/modules/nms/epicanchors-v1_16_R2/src/main/java/epicanchors/nms/v1_16_R2.java @@ -0,0 +1,299 @@ +package epicanchors.nms; + +import com.songoda.epicanchors.AnchorNMS; +import com.songoda.epicanchors.utils.ReflectionUtils; +import com.songoda.epicanchors.utils.Utils; +import net.minecraft.server.v1_16_R2.*; +import org.bukkit.Chunk; +import org.bukkit.GameRule; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.v1_16_R2.CraftChunk; +import org.bukkit.craftbukkit.v1_16_R2.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.v1_16_R2.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.Iterator; +import java.util.Optional; + +public class v1_16_R2 extends AnchorNMS { + @SuppressWarnings("unused") + public v1_16_R2(JavaPlugin plugin) { + super(plugin); + } + + @Override + public boolean loadAnchoredChunk(Chunk chunk) { + return chunk.addPluginChunkTicket(super.plugin); + } + + @Override + public boolean unloadAnchoredChunk(Chunk chunk) { + chunk.removePluginChunkTicket(super.plugin); + + return chunk.unload(); + } + + @Override + public void tickInactiveSpawners(Chunk chunk, int amount) { + if (amount <= 0) return; + + try { + for (BlockState tileEntity : chunk.getTileEntities()) { + if (tileEntity instanceof CreatureSpawner) { + MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); + + for (int i = 0; i < amount; ++i) { + if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { + break; // Spawner not inactive + } + } + } + } + } catch (Exception ex) { + Utils.logException(super.plugin, ex); + } + } + + @Override + public void doRandomTick(Chunk chunk, int tickAmount) { + NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); + } + + @Override + public int getRandomTickSpeed(World world) { + Integer result = world.getGameRuleValue(GameRule.RANDOM_TICK_SPEED); + + if (result == null) { + result = world.getGameRuleDefault(GameRule.RANDOM_TICK_SPEED); + } + + return result == null ? 3 : result; + } + + /** + * This class contains some modified methods from {@link WorldServer} + * which originally (vanilla server) goes by the name ServerLevel. + */ + private static class NotchianServerLevel { + /** + * Method is based on {@link WorldServer#a(net.minecraft.server.v1_16_R2.Chunk, int)}. + */ + static void randomTickChunk(net.minecraft.server.v1_16_R2.Chunk chunk, int tickAmount) { + if (tickAmount > 0) { + ChunkCoordIntPair chunkcoordintpair = chunk.getPos(); + int j = chunkcoordintpair.d(); + int k = chunkcoordintpair.e(); + + GameProfilerFiller profiler = chunk.world.getMethodProfiler(); + + profiler.enter("tickBlocks"); + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != net.minecraft.server.v1_16_R2.Chunk.a && chunksection.d()) { + int j1 = chunksection.getYPosition(); + + for (int i = 0; i < tickAmount; ++i) { + BlockPosition blockposition2 = chunk.world.a(j, j1, k, 15); + profiler.enter("randomTick"); + + IBlockData iblockdata = chunksection.getType(blockposition2.getX() - j, blockposition2.getY() - j1, blockposition2.getZ() - k); + + if (iblockdata.isTicking()) { + iblockdata.b(chunk.world, blockposition2, chunk.world.random); + } + + Fluid fluid = iblockdata.getFluid(); + if (fluid.f()) { + fluid.b(chunk.world, blockposition2, chunk.world.random); + } + + profiler.exit(); + } + } + } + + profiler.exit(); + } + } + } + + /** + * This class contains some modified methods from {@link MobSpawnerAbstract} + * which originally (vanilla server) goes by the name BaseSpawner. + */ + private static class NotchianBaseSpawner { + static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); + + return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); + } + + /** + * This method is based on {@link MobSpawnerAbstract#h()}. + */ + static boolean isNearPlayer(MobSpawnerAbstract spawner) { + BlockPosition blockposition = spawner.b(); + return spawner.a().isPlayerNearby( + (double) blockposition.getX() + .5D, + (double) blockposition.getY() + .5D, + (double) blockposition.getZ() + .5D, + spawner.requiredPlayerRange); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + * + * @return false if the spawner is not inactive, true otherwise + */ + static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException { + if (isNearPlayer(spawner)) return false; + + net.minecraft.server.v1_16_R2.World world = spawner.a(); + BlockPosition blockposition = spawner.b(); + + if (!(world instanceof WorldServer)) { + double d0 = (double) blockposition.getX() + world.random.nextDouble(); + double d1 = (double) blockposition.getY() + world.random.nextDouble(); + double d2 = (double) blockposition.getZ() + world.random.nextDouble(); + world.addParticle(Particles.SMOKE, d0, d1, d2, 0.0D, 0.0D, 0.0D); + world.addParticle(Particles.FLAME, d0, d1, d2, 0.0D, 0.0D, 0.0D); + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return true; + } + + boolean flag = false; + int i = 0; + + while (true) { + if (i >= spawner.spawnCount) { + if (flag) { + delay(spawner); + } + + break; + } + + NBTTagCompound nbttagcompound = spawner.spawnData.getEntity(); + Optional> optional = EntityTypes.a(nbttagcompound); + if (!optional.isPresent()) { + delay(spawner); + return true; + } + + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.h(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.h(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.h(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + if (world.b(optional.get().a(d3, d4, d5))) { + WorldServer worldserver = (WorldServer) world; + if (EntityPositionTypes.a(optional.get(), worldserver, EnumMobSpawn.SPAWNER, new BlockPosition(d3, d4, d5), world.getRandom())) { + label116: + { + Entity entity = EntityTypes.a(nbttagcompound, world, (entity1) -> { + entity1.setPositionRotation(d3, d4, d5, entity1.yaw, entity1.pitch); + return entity1; + }); + if (entity == null) { + delay(spawner); + return true; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawner.spawnRange)).size(); + + if (k >= spawner.maxNearbyEntities) { + delay(spawner); + return true; + } + + entity.setPositionRotation(entity.locX(), entity.locY(), entity.locZ(), world.random.nextFloat() * 360.0F, 0.0F); + if (entity instanceof EntityInsentient) { + EntityInsentient entityinsentient = (EntityInsentient) entity; + if (!entityinsentient.a(world, EnumMobSpawn.SPAWNER) || !entityinsentient.a(world)) { + break label116; + } + + if (spawner.spawnData.getEntity().e() == 1 && spawner.spawnData.getEntity().hasKeyOfType("id", 8)) { + ((EntityInsentient) entity).prepare(worldserver, world.getDamageScaler(entity.getChunkCoordinates()), EnumMobSpawn.SPAWNER, null, null); + } + + if (entityinsentient.world.spigotConfig.nerfSpawnerMobs) { + entityinsentient.aware = false; + } + } + + if (CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + Entity vehicle = entity.getVehicle(); + if (vehicle != null) { + vehicle.dead = true; + } + + Entity passenger; + for (Iterator var20 = entity.getAllPassengers().iterator(); var20.hasNext(); passenger.dead = true) { + passenger = var20.next(); + } + } else { + if (!worldserver.addAllEntitiesSafely(entity, CreatureSpawnEvent.SpawnReason.SPAWNER)) { + delay(spawner); + return true; + } + + world.triggerEffect(2004, blockposition, 0); + if (entity instanceof EntityInsentient) { + ((EntityInsentient) entity).doSpawnEffect(); + } + + flag = true; + } + } + } + } + + ++i; + } + } + + return true; + } + + /** + * This method is based on {@link MobSpawnerAbstract#i()}. + */ + static void delay(MobSpawnerAbstract spawner) { + if (spawner.maxSpawnDelay <= spawner.minSpawnDelay) { + spawner.spawnDelay = spawner.minSpawnDelay; + } else { + int i = spawner.maxSpawnDelay - spawner.minSpawnDelay; + spawner.spawnDelay = spawner.minSpawnDelay + spawner.a().random.nextInt(i); + } + + if (!spawner.mobs.isEmpty()) { + spawner.setSpawnData(WeightedRandom.a(spawner.a().random, spawner.mobs)); + } + + spawner.a(1); + } + } +} diff --git a/modules/nms/epicanchors-v1_16_R3/pom.xml b/modules/nms/epicanchors-v1_16_R3/pom.xml new file mode 100644 index 0000000..6704dc7 --- /dev/null +++ b/modules/nms/epicanchors-v1_16_R3/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + + com.songoda + EpicAnchors + 2.0.0-ALPHA + ../../../pom.xml + + jar + epicanchors-v1_16_R3 + + + + com.songoda + epicanchors-api + ${project.version} + + + + org.spigotmc + spigot-api + 1.16.5-R0.1-SNAPSHOT + provided + + + + org.spigotmc + spigot + 1.16.5 + provided + + + diff --git a/modules/nms/epicanchors-v1_16_R3/src/main/java/epicanchors/nms/v1_16_R3.java b/modules/nms/epicanchors-v1_16_R3/src/main/java/epicanchors/nms/v1_16_R3.java new file mode 100644 index 0000000..0e23b56 --- /dev/null +++ b/modules/nms/epicanchors-v1_16_R3/src/main/java/epicanchors/nms/v1_16_R3.java @@ -0,0 +1,305 @@ +package epicanchors.nms; + +import com.songoda.epicanchors.AnchorNMS; +import com.songoda.epicanchors.utils.ReflectionUtils; +import com.songoda.epicanchors.utils.Utils; +import net.minecraft.server.v1_16_R3.*; +import org.bukkit.Chunk; +import org.bukkit.GameRule; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.v1_16_R3.CraftChunk; +import org.bukkit.craftbukkit.v1_16_R3.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.v1_16_R3.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.Iterator; +import java.util.Optional; + +public class v1_16_R3 extends AnchorNMS { + @SuppressWarnings("unused") + public v1_16_R3(JavaPlugin plugin) { + super(plugin); + } + + @Override + public boolean loadAnchoredChunk(Chunk chunk) { + return chunk.addPluginChunkTicket(super.plugin); + } + + @Override + public boolean unloadAnchoredChunk(Chunk chunk) { + chunk.removePluginChunkTicket(super.plugin); + + return chunk.unload(); + } + + @Override + public void tickInactiveSpawners(Chunk chunk, int amount) { + if (amount <= 0) return; + + try { + for (BlockState tileEntity : chunk.getTileEntities()) { + if (tileEntity instanceof CreatureSpawner) { + MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); + + for (int i = 0; i < amount; ++i) { + if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { + break; // Spawner not inactive + } + } + } + } + } catch (Exception ex) { + Utils.logException(super.plugin, ex); + } + } + + @Override + public void doRandomTick(Chunk chunk, int tickAmount) { + NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); + } + + @Override + public int getRandomTickSpeed(World world) { + Integer result = world.getGameRuleValue(GameRule.RANDOM_TICK_SPEED); + + if (result == null) { + result = world.getGameRuleDefault(GameRule.RANDOM_TICK_SPEED); + } + + return result == null ? 3 : result; + } + + /** + * This class contains some modified methods from {@link WorldServer} + * which originally (vanilla server) goes by the name ServerLevel. + */ + private static class NotchianServerLevel { + /** + * Method is based on {@link WorldServer#a(net.minecraft.server.v1_16_R3.Chunk, int)}. + */ + static void randomTickChunk(net.minecraft.server.v1_16_R3.Chunk chunk, int tickAmount) { + if (tickAmount > 0) { + GameProfilerFiller profiler = chunk.world.getMethodProfiler(); + + ChunkCoordIntPair chunkPos = chunk.getPos(); + int minBlockX = chunkPos.d(); + int minBlockZ = chunkPos.e(); + + profiler.enter("tickBlocks"); + for (ChunkSection cSection : chunk.getSections()) { + if (cSection != net.minecraft.server.v1_16_R3.Chunk.a && // cSection != Chunk.EMPTY_SECTION + cSection.d()) { // #isRandomlyTicking() + int bottomBlockY = cSection.getYPosition(); + + for (int i = 0; i < tickAmount; ++i) { + BlockPosition randomBlockPos = chunk.world.a(minBlockX, bottomBlockY, minBlockZ, 15); // getBlockRandomPos + profiler.enter("randomTick"); + + IBlockData blockState = cSection.getType(randomBlockPos.getX() - minBlockX, + randomBlockPos.getY() - bottomBlockY, + randomBlockPos.getZ() - minBlockZ); // #getBlockState + + if (blockState.isTicking()) { // #isRandomlyTicking() + blockState.b(chunk.world, randomBlockPos, chunk.world.random); // #randomTick + } + + Fluid fluidState = blockState.getFluid(); // #getFluidState() + if (fluidState.f()) { // #isRandomlyTicking() + fluidState.b(chunk.world, randomBlockPos, chunk.world.random); // #randomTick + } + + profiler.exit(); + } + } + } + + profiler.exit(); + } + } + } + + /** + * This class contains some modified methods from {@link MobSpawnerAbstract} + * which originally (vanilla server) goes by the name BaseSpawner. + */ + private static class NotchianBaseSpawner { + static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); + + return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); + } + + /** + * This method is based on {@link MobSpawnerAbstract#h()}. + */ + static boolean isNearPlayer(MobSpawnerAbstract spawner) { + BlockPosition blockposition = spawner.b(); + + return spawner.a() + .isPlayerNearby((double) blockposition.getX() + 0.5D, + (double) blockposition.getY() + 0.5D, + (double) blockposition.getZ() + 0.5D, + spawner.requiredPlayerRange); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + * + * @return false if the spawner is not inactive, true otherwise + */ + static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException { + if (isNearPlayer(spawner)) return false; + + net.minecraft.server.v1_16_R3.World world = spawner.a(); + BlockPosition blockposition = spawner.b(); + if (!(world instanceof WorldServer)) { + double d0 = (double) blockposition.getX() + world.random.nextDouble(); + double d1 = (double) blockposition.getY() + world.random.nextDouble(); + double d2 = (double) blockposition.getZ() + world.random.nextDouble(); + + world.addParticle(Particles.SMOKE, d0, d1, d2, 0.0D, 0.0D, 0.0D); + world.addParticle(Particles.FLAME, d0, d1, d2, 0.0D, 0.0D, 0.0D); + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return true; + } + + boolean flag = false; + int i = 0; + + while (true) { + if (i >= spawner.spawnCount) { + if (flag) { + delay(spawner); + } + + break; + } + + NBTTagCompound nbttagcompound = spawner.spawnData.getEntity(); + Optional> optional = EntityTypes.a(nbttagcompound); + if (!optional.isPresent()) { + delay(spawner); + return true; + } + + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.h(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.h(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.h(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; + + if (world.b(optional.get().a(d3, d4, d5))) { + WorldServer worldserver = (WorldServer) world; + if (EntityPositionTypes.a(optional.get(), worldserver, EnumMobSpawn.SPAWNER, new BlockPosition(d3, d4, d5), world.getRandom())) { + label116: + { + Entity entity = EntityTypes.a(nbttagcompound, world, (entity1) -> { + entity1.setPositionRotation(d3, d4, d5, entity1.yaw, entity1.pitch); + return entity1; + }); + if (entity == null) { + delay(spawner); + return true; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawner.spawnRange)).size(); + + if (k >= spawner.maxNearbyEntities) { + delay(spawner); + return true; + } + + entity.setPositionRotation(entity.locX(), entity.locY(), entity.locZ(), world.random.nextFloat() * 360F, 0F); + if (entity instanceof EntityInsentient) { + EntityInsentient entityinsentient = (EntityInsentient) entity; + if (!entityinsentient.a(world, EnumMobSpawn.SPAWNER) || !entityinsentient.a(world)) { + break label116; + } + + if (spawner.spawnData.getEntity().e() == 1 && spawner.spawnData.getEntity().hasKeyOfType("id", 8)) { + ((EntityInsentient) entity).prepare(worldserver, world.getDamageScaler(entity.getChunkCoordinates()), EnumMobSpawn.SPAWNER, null, null); + } + + if (entityinsentient.world.spigotConfig.nerfSpawnerMobs) { + entityinsentient.aware = false; + } + } + + if (CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + Entity vehicle = entity.getVehicle(); + if (vehicle != null) { + vehicle.dead = true; + } + + Entity passenger; + for (Iterator var20 = entity.getAllPassengers().iterator(); var20.hasNext(); passenger.dead = true) { + passenger = var20.next(); + } + } else { + if (!worldserver.addAllEntitiesSafely(entity, CreatureSpawnEvent.SpawnReason.SPAWNER)) { + delay(spawner); + return true; + } + + world.triggerEffect(2004, blockposition, 0); + if (entity instanceof EntityInsentient) { + ((EntityInsentient) entity).doSpawnEffect(); + } + + flag = true; + } + } + } + } + + ++i; + } + } + + return true; + } + + /** + * This method is based on {@link MobSpawnerAbstract#i()}. + */ + static void delay(MobSpawnerAbstract spawner) { + if (spawner.maxSpawnDelay <= spawner.minSpawnDelay) { + spawner.spawnDelay = spawner.minSpawnDelay; + } else { + int i = spawner.maxSpawnDelay - spawner.minSpawnDelay; + spawner.spawnDelay = spawner.minSpawnDelay + spawner.a().random.nextInt(i); + } + + if (!spawner.mobs.isEmpty()) { + spawner.setSpawnData(WeightedRandom.a(spawner.a().random, spawner.mobs)); + } + + spawner.a(1); + } + } +} diff --git a/modules/nms/epicanchors-v1_8_R1/pom.xml b/modules/nms/epicanchors-v1_8_R1/pom.xml new file mode 100644 index 0000000..0664d7e --- /dev/null +++ b/modules/nms/epicanchors-v1_8_R1/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + + com.songoda + EpicAnchors + 2.0.0-ALPHA + ../../../pom.xml + + jar + epicanchors-v1_8_R1 + + + + com.songoda + epicanchors-api + ${project.version} + + + + org.spigotmc + spigot-api + 1.8-R0.1-SNAPSHOT + provided + + + + org.spigotmc + spigot + 1.8 + provided + + + diff --git a/modules/nms/epicanchors-v1_8_R1/src/main/java/epicanchors/nms/v1_8_R1.java b/modules/nms/epicanchors-v1_8_R1/src/main/java/epicanchors/nms/v1_8_R1.java new file mode 100644 index 0000000..e4a3e6d --- /dev/null +++ b/modules/nms/epicanchors-v1_8_R1/src/main/java/epicanchors/nms/v1_8_R1.java @@ -0,0 +1,251 @@ +package epicanchors.nms; + +import com.songoda.epicanchors.AnchorNMS; +import com.songoda.epicanchors.utils.ReflectionUtils; +import com.songoda.epicanchors.utils.Utils; +import net.minecraft.server.v1_8_R1.AxisAlignedBB; +import net.minecraft.server.v1_8_R1.Block; +import net.minecraft.server.v1_8_R1.BlockPosition; +import net.minecraft.server.v1_8_R1.ChunkSection; +import net.minecraft.server.v1_8_R1.Entity; +import net.minecraft.server.v1_8_R1.EntityInsentient; +import net.minecraft.server.v1_8_R1.EntityTypes; +import net.minecraft.server.v1_8_R1.EnumParticle; +import net.minecraft.server.v1_8_R1.IBlockData; +import net.minecraft.server.v1_8_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_8_R1.WorldServer; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.v1_8_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_8_R1.block.CraftCreatureSpawner; +import org.bukkit.plugin.java.JavaPlugin; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class v1_8_R1 extends AnchorNMS { + @SuppressWarnings("unused") + public v1_8_R1(JavaPlugin plugin) { + super(plugin); + } + + @Override + public boolean loadAnchoredChunk(Chunk chunk) { + return chunk.load(); + } + + @Override + public boolean unloadAnchoredChunk(Chunk chunk) { + return chunk.unload(); + } + + @Override + public void tickInactiveSpawners(Chunk chunk, int amount) { + if (amount <= 0) return; + + try { + for (BlockState tileEntity : chunk.getTileEntities()) { + if (tileEntity instanceof CreatureSpawner) { + MobSpawnerAbstract spawner = MobSpawnerUtils.getNotchianSpawner((CraftCreatureSpawner) tileEntity); + + for (int i = 0; i < amount; ++i) { + if (!MobSpawnerUtils.tickInactiveSpawner(spawner)) { + break; // Spawner not inactive + } + } + } + } + } catch (Exception ex) { + Utils.logException(super.plugin, ex); + } + } + + @Override + public void doRandomTick(Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + WorldServerUtils.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); + } + + @Override + public int getRandomTickSpeed(World world) { + return Helper.getRandomTickSpeedLegacy(world); + } + + /** + * This class contains some modified methods from {@link WorldServer}. + */ + private static class WorldServerUtils { + /** + * Method is based on {@link WorldServer#h()}. + */ + static void randomTickChunk(net.minecraft.server.v1_8_R1.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + if (tickAmount > 0) { + int k = chunk.locX * 16; + int l = chunk.locZ * 16; + + for (ChunkSection cSection : chunk.getSections()) { + if (cSection != null && cSection.shouldTick()) { + + for (int i = 0; i < tickAmount; ++i) { + int m = (int) ReflectionUtils.getFieldValue(chunk.world, "m"); + + m = m * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "m", m); + + int i2 = m >> 2; + int j2 = i2 & 15; + int k2 = i2 >> 8 & 15; + int l2 = i2 >> 16 & 15; + + BlockPosition blockposition2 = new BlockPosition(j2 + k, l2 + cSection.getYPosition(), k2 + l); + IBlockData iblockdata = cSection.getType(j2, l2, k2); + Block block = iblockdata.getBlock(); + + if (block.isTicking()) { + block.a(chunk.world, blockposition2, iblockdata, chunk.world.random); + } + } + } + } + } + } + } + + /** + * This class contains some modified methods from {@link MobSpawnerAbstract}. + */ + private static class MobSpawnerUtils { + private static Method aEntityBooleanMethod, gMethod, hMethod; + + static { + try { + aEntityBooleanMethod = MobSpawnerAbstract.class.getDeclaredMethod("a", Entity.class, boolean.class); + aEntityBooleanMethod.setAccessible(true); + + gMethod = MobSpawnerAbstract.class.getDeclaredMethod("g"); + gMethod.setAccessible(true); + + hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); + hMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + Utils.logException(null, ex); + } + } + + static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); + + return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); + } + + /** + * This method calls {@link MobSpawnerAbstract#g()} using Reflections. + */ + static boolean isNearPlayer(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + return (boolean) gMethod.invoke(spawner); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + * + * @return false if the spawner is not inactive, true otherwise + */ + static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { + if (isNearPlayer(spawner)) return false; + + BlockPosition blockposition = spawner.b(); + + if (spawner.a().isStatic) { + double d1 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d0 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + + spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d1, d2, d0, 0D, 0D, 0D); + spawner.a().addParticle(EnumParticle.FLAME, d1, d2, d0, 0D, 0D, 0D); + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return true; + } + + boolean flag = false; + int i = 0; + + int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); + int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); + int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); + while (true) { + if (i >= spawnCount) { + if (flag) { + delay(spawner); + } + + break; + } + + Entity entity = EntityTypes.createEntityByName(spawner.getMobName(), spawner.a()); + if (entity == null) { + return true; + } + + int j = spawner.a() + .a(entity.getClass(), (new AxisAlignedBB(blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .grow(spawnRange, spawnRange, spawnRange)).size(); + + if (j >= maxNearbyEntities) { + delay(spawner); + return true; + } + + double d0 = (double) blockposition.getX() + (spawner.a().random.nextDouble() - spawner.a().random.nextDouble()) * (double) spawnRange + 0.5D; + double d3 = blockposition.getY() + spawner.a().random.nextInt(3) - 1; + double d4 = (double) blockposition.getZ() + (spawner.a().random.nextDouble() - spawner.a().random.nextDouble()) * (double) spawnRange + 0.5D; + + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(d0, d3, d4, spawner.a().random.nextFloat() * 360.0F, 0.0F); + + if (entityinsentient == null || entityinsentient.bQ() && entityinsentient.canSpawn()) { + aEntityBooleanMethod.invoke(spawner, entity, true); + spawner.a().triggerEffect(2004, blockposition, 0); + + if (entityinsentient != null) { + entityinsentient.y(); + } + + flag = true; + } + + ++i; + } + } + + return true; + } + + /** + * This method calls {@link MobSpawnerAbstract#h()} using Reflections. + */ + static void delay(MobSpawnerAbstract spawner) throws IllegalAccessException, InvocationTargetException { + hMethod.invoke(spawner); + } + } +} diff --git a/modules/nms/epicanchors-v1_8_R2/pom.xml b/modules/nms/epicanchors-v1_8_R2/pom.xml new file mode 100644 index 0000000..3be749e --- /dev/null +++ b/modules/nms/epicanchors-v1_8_R2/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + + com.songoda + EpicAnchors + 2.0.0-ALPHA + ../../../pom.xml + + jar + epicanchors-v1_8_R2 + + + + com.songoda + epicanchors-api + ${project.version} + + + + org.spigotmc + spigot-api + 1.8.3-R0.1-SNAPSHOT + provided + + + + org.spigotmc + spigot + 1.8.3 + provided + + + diff --git a/modules/nms/epicanchors-v1_8_R2/src/main/java/epicanchors/nms/v1_8_R2.java b/modules/nms/epicanchors-v1_8_R2/src/main/java/epicanchors/nms/v1_8_R2.java new file mode 100644 index 0000000..cfbeed6 --- /dev/null +++ b/modules/nms/epicanchors-v1_8_R2/src/main/java/epicanchors/nms/v1_8_R2.java @@ -0,0 +1,248 @@ +package epicanchors.nms; + +import com.songoda.epicanchors.AnchorNMS; +import com.songoda.epicanchors.utils.ReflectionUtils; +import com.songoda.epicanchors.utils.Utils; +import net.minecraft.server.v1_8_R2.AxisAlignedBB; +import net.minecraft.server.v1_8_R2.Block; +import net.minecraft.server.v1_8_R2.BlockPosition; +import net.minecraft.server.v1_8_R2.ChunkSection; +import net.minecraft.server.v1_8_R2.Entity; +import net.minecraft.server.v1_8_R2.EntityInsentient; +import net.minecraft.server.v1_8_R2.EntityTypes; +import net.minecraft.server.v1_8_R2.EnumParticle; +import net.minecraft.server.v1_8_R2.IBlockData; +import net.minecraft.server.v1_8_R2.MobSpawnerAbstract; +import net.minecraft.server.v1_8_R2.WorldServer; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.v1_8_R2.CraftChunk; +import org.bukkit.craftbukkit.v1_8_R2.block.CraftCreatureSpawner; +import org.bukkit.plugin.java.JavaPlugin; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class v1_8_R2 extends AnchorNMS { + @SuppressWarnings("unused") + public v1_8_R2(JavaPlugin plugin) { + super(plugin); + } + + @Override + public boolean loadAnchoredChunk(Chunk chunk) { + return chunk.load(); + } + + @Override + public boolean unloadAnchoredChunk(Chunk chunk) { + return chunk.unload(); + } + + @Override + public void tickInactiveSpawners(Chunk chunk, int amount) { + if (amount <= 0) return; + + try { + for (BlockState tileEntity : chunk.getTileEntities()) { + if (tileEntity instanceof CreatureSpawner) { + MobSpawnerAbstract spawner = MobSpawnerUtils.getNotchianSpawner((CraftCreatureSpawner) tileEntity); + + for (int i = 0; i < amount; ++i) { + if (!MobSpawnerUtils.tickInactiveSpawner(spawner)) { + break; // Spawner not inactive + } + } + } + } + } catch (Exception ex) { + Utils.logException(super.plugin, ex); + } + } + + @Override + public void doRandomTick(Chunk chunk, int tickAmount) { + try { + WorldServerUtils.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); + } catch (NoSuchFieldException | IllegalAccessException ex) { + Utils.logException(super.plugin, ex); + } + } + + @Override + public int getRandomTickSpeed(World world) { + return Helper.getRandomTickSpeedLegacy(world); + } + + /** + * This class contains some modified methods from {@link WorldServer}. + */ + private static class WorldServerUtils { + /** + * Method is based on {@link WorldServer#h()}. + */ + static void randomTickChunk(net.minecraft.server.v1_8_R2.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + if (tickAmount > 0) { + int k = chunk.locX * 16; + int l = chunk.locZ * 16; + + for (ChunkSection cSection : chunk.getSections()) { + if (cSection != null && cSection.shouldTick()) { + for (int i = 0; i < tickAmount; ++i) { + int m = (int) ReflectionUtils.getFieldValue(chunk.world, "m"); + + m = m * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "m", m); + + int i2 = m >> 2; + int j2 = i2 & 15; + int k2 = i2 >> 8 & 15; + int l2 = i2 >> 16 & 15; + + BlockPosition blockposition2 = new BlockPosition(j2 + k, l2 + cSection.getYPosition(), k2 + l); + IBlockData iblockdata = cSection.getType(j2, l2, k2); + Block block = iblockdata.getBlock(); + + if (block.isTicking()) { + block.a(chunk.world, blockposition2, iblockdata, chunk.world.random); + } + } + } + } + } + } + } + + /** + * This class contains some modified methods from {@link MobSpawnerAbstract}. + */ + private static class MobSpawnerUtils { + private static Method aEntityBooleanMethod, gMethod, hMethod; + + static { + try { + aEntityBooleanMethod = MobSpawnerAbstract.class.getDeclaredMethod("a", Entity.class, boolean.class); + aEntityBooleanMethod.setAccessible(true); + + gMethod = MobSpawnerAbstract.class.getDeclaredMethod("g"); + gMethod.setAccessible(true); + + hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); + hMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + Utils.logException(null, ex); + } + } + + static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); + + return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); + } + + /** + * This method calls {@link MobSpawnerAbstract#g()} using Reflections. + */ + static boolean isNearPlayer(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + return (boolean) gMethod.invoke(spawner); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + * + * @return false if the spawner is not inactive, true otherwise + */ + static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { + if (isNearPlayer(spawner)) return false; + + BlockPosition blockposition = spawner.b(); + + if (spawner.a().isClientSide) { + double d1 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d0 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d1, d2, d0, 0.0D, 0.0D, 0.0D); + spawner.a().addParticle(EnumParticle.FLAME, d1, d2, d0, 0.0D, 0.0D, 0.0D); + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200.0F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return true; + } + + boolean flag = false; + int i = 0; + + int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); + int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); + int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); + + while (true) { + if (i >= spawnCount) { + if (flag) { + delay(spawner); + } + break; + } + + Entity entity = EntityTypes.createEntityByName(spawner.getMobName(), spawner.a()); + if (entity == null) { + return true; + } + + int j = spawner.a().a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .grow(spawnRange, spawnRange, spawnRange)).size(); + if (j >= maxNearbyEntities) { + delay(spawner); + return true; + } + + double d0 = (double) blockposition.getX() + (spawner.a().random.nextDouble() - spawner.a().random.nextDouble()) * (double) spawnRange + .5D; + double d3 = blockposition.getY() + spawner.a().random.nextInt(3) - 1; + double d4 = (double) blockposition.getZ() + (spawner.a().random.nextDouble() - spawner.a().random.nextDouble()) * (double) spawnRange + .5D; + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(d0, d3, d4, spawner.a().random.nextFloat() * 360F, 0F); + if (entityinsentient == null || entityinsentient.bR() && entityinsentient.canSpawn()) { + aEntityBooleanMethod.invoke(spawner, entity, true); + spawner.a().triggerEffect(2004, blockposition, 0); + if (entityinsentient != null) { + entityinsentient.y(); + } + + flag = true; + } + + ++i; + } + } + + return true; + } + + /** + * This method calls {@link MobSpawnerAbstract#h()} using Reflections. + */ + static void delay(MobSpawnerAbstract spawner) throws IllegalAccessException, InvocationTargetException { + hMethod.invoke(spawner); + } + } +} diff --git a/modules/nms/epicanchors-v1_8_R3/pom.xml b/modules/nms/epicanchors-v1_8_R3/pom.xml new file mode 100644 index 0000000..73fb563 --- /dev/null +++ b/modules/nms/epicanchors-v1_8_R3/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + + com.songoda + EpicAnchors + 2.0.0-ALPHA + ../../../pom.xml + + jar + epicanchors-v1_8_R3 + + + + com.songoda + epicanchors-api + ${project.version} + + + + org.spigotmc + spigot-api + 1.8.8-R0.1-SNAPSHOT + provided + + + + org.spigotmc + spigot + 1.8.8 + provided + + + diff --git a/modules/nms/epicanchors-v1_8_R3/src/main/java/epicanchors/nms/v1_8_R3.java b/modules/nms/epicanchors-v1_8_R3/src/main/java/epicanchors/nms/v1_8_R3.java new file mode 100644 index 0000000..80a8b5e --- /dev/null +++ b/modules/nms/epicanchors-v1_8_R3/src/main/java/epicanchors/nms/v1_8_R3.java @@ -0,0 +1,249 @@ +package epicanchors.nms; + +import com.songoda.epicanchors.AnchorNMS; +import com.songoda.epicanchors.utils.ReflectionUtils; +import com.songoda.epicanchors.utils.Utils; +import net.minecraft.server.v1_8_R3.AxisAlignedBB; +import net.minecraft.server.v1_8_R3.Block; +import net.minecraft.server.v1_8_R3.BlockPosition; +import net.minecraft.server.v1_8_R3.ChunkSection; +import net.minecraft.server.v1_8_R3.Entity; +import net.minecraft.server.v1_8_R3.EntityInsentient; +import net.minecraft.server.v1_8_R3.EntityTypes; +import net.minecraft.server.v1_8_R3.EnumParticle; +import net.minecraft.server.v1_8_R3.IBlockData; +import net.minecraft.server.v1_8_R3.MobSpawnerAbstract; +import net.minecraft.server.v1_8_R3.WorldServer; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.v1_8_R3.CraftChunk; +import org.bukkit.craftbukkit.v1_8_R3.block.CraftCreatureSpawner; +import org.bukkit.plugin.java.JavaPlugin; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class v1_8_R3 extends AnchorNMS { + @SuppressWarnings("unused") + public v1_8_R3(JavaPlugin plugin) { + super(plugin); + } + + @Override + public boolean loadAnchoredChunk(Chunk chunk) { + return chunk.load(); + } + + @Override + public boolean unloadAnchoredChunk(Chunk chunk) { + return chunk.unload(); + } + + @Override + public void tickInactiveSpawners(Chunk chunk, int amount) { + if (amount <= 0) return; + + try { + for (BlockState tileEntity : chunk.getTileEntities()) { + if (tileEntity instanceof CreatureSpawner) { + MobSpawnerAbstract spawner = MobSpawnerUtils.getNotchianSpawner((CraftCreatureSpawner) tileEntity); + + for (int i = 0; i < amount; ++i) { + if (!MobSpawnerUtils.tickInactiveSpawner(spawner)) { + break; // Spawner not inactive + } + } + } + } + } catch (Exception ex) { + Utils.logException(super.plugin, ex); + } + } + + @Override + public void doRandomTick(Chunk chunk, int tickAmount) { + try { + WorldServerUtils.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); + } catch (NoSuchFieldException | IllegalAccessException ex) { + Utils.logException(super.plugin, ex); + } + } + + @Override + public int getRandomTickSpeed(World world) { + return Helper.getRandomTickSpeedLegacy(world); + } + + /** + * This class contains some modified methods from {@link WorldServer}. + */ + private static class WorldServerUtils { + /** + * Method is based on {@link WorldServer#h()}. + */ + static void randomTickChunk(net.minecraft.server.v1_8_R3.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + if (tickAmount > 0) { + int k = chunk.locX * 16; + int l = chunk.locZ * 16; + + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != null && chunksection.shouldTick()) { + for (int l1 = 0; l1 < tickAmount; ++l1) { + int m = (int) ReflectionUtils.getFieldValue(chunk.world, "m"); + + m = m * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "m", m); + + int i2 = m >> 2; + int j2 = i2 & 15; + int k2 = i2 >> 8 & 15; + int l2 = i2 >> 16 & 15; + + IBlockData iblockdata = chunksection.getType(j2, l2, k2); + Block block = iblockdata.getBlock(); + + if (block.isTicking()) { + block.a(chunk.world, new BlockPosition(j2 + k, l2 + chunksection.getYPosition(), k2 + l), iblockdata, chunk.world.random); + } + } + } + } + } + } + } + + /** + * This class contains some modified methods from {@link MobSpawnerAbstract}. + */ + private static class MobSpawnerUtils { + private static Method aEntityBooleanMethod, gMethod, hMethod; + + static { + try { + aEntityBooleanMethod = MobSpawnerAbstract.class.getDeclaredMethod("a", Entity.class, boolean.class); + aEntityBooleanMethod.setAccessible(true); + + gMethod = MobSpawnerAbstract.class.getDeclaredMethod("g"); + gMethod.setAccessible(true); + + hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); + hMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + Utils.logException(null, ex); + } + } + + static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); + + return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); + } + + /** + * This method calls {@link MobSpawnerAbstract#g()} using Reflections. + */ + static boolean isNearPlayer(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + return (boolean) gMethod.invoke(spawner); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + * + * @return false if the spawner is not inactive, true otherwise + */ + static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { + if (isNearPlayer(spawner)) return false; + + BlockPosition blockposition = spawner.b(); + + if (spawner.a().isClientSide) { + double d1 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d0 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d1, d2, d0, 0D, 0D, 0D); + spawner.a().addParticle(EnumParticle.FLAME, d1, d2, d0, 0D, 0D, 0D); + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); + + ReflectionUtils.setFieldValue(spawner, "f", spawnerE); + ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return true; + } + + boolean flag = false; + int i = 0; + + int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); + int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); + int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); + + while (true) { + if (i >= spawnCount) { + if (flag) { + delay(spawner); + } + break; + } + + Entity entity = EntityTypes.createEntityByName(spawner.getMobName(), spawner.a()); + if (entity == null) { + return true; + } + + int j = spawner.a().a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .grow(spawnRange, spawnRange, spawnRange)).size(); + if (j >= maxNearbyEntities) { + delay(spawner); + return true; + } + + double d0 = (double) blockposition.getX() + (spawner.a().random.nextDouble() - spawner.a().random.nextDouble()) * (double) spawnRange + .5D; + double d3 = blockposition.getY() + spawner.a().random.nextInt(3) - 1; + double d4 = (double) blockposition.getZ() + (spawner.a().random.nextDouble() - spawner.a().random.nextDouble()) * (double) spawnRange + .5D; + + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(d0, d3, d4, spawner.a().random.nextFloat() * 360F, 0F); + + if (entityinsentient == null || entityinsentient.bR() && entityinsentient.canSpawn()) { + aEntityBooleanMethod.invoke(spawner, entity, true); + spawner.a().triggerEffect(2004, blockposition, 0); + if (entityinsentient != null) { + entityinsentient.y(); + } + + flag = true; + } + + ++i; + } + } + + return true; + } + + /** + * This method calls {@link MobSpawnerAbstract#h()} using Reflections. + */ + static void delay(MobSpawnerAbstract spawner) throws IllegalAccessException, InvocationTargetException { + hMethod.invoke(spawner); + } + } +} diff --git a/modules/nms/epicanchors-v1_9_R1/pom.xml b/modules/nms/epicanchors-v1_9_R1/pom.xml new file mode 100644 index 0000000..dfc16b6 --- /dev/null +++ b/modules/nms/epicanchors-v1_9_R1/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + + com.songoda + EpicAnchors + 2.0.0-ALPHA + ../../../pom.xml + + jar + epicanchors-v1_9_R1 + + + + com.songoda + epicanchors-api + ${project.version} + + + + org.spigotmc + spigot-api + 1.9-R0.1-SNAPSHOT + provided + + + + org.spigotmc + spigot + 1.9.2 + provided + + + diff --git a/modules/nms/epicanchors-v1_9_R1/src/main/java/epicanchors/nms/v1_9_R1.java b/modules/nms/epicanchors-v1_9_R1/src/main/java/epicanchors/nms/v1_9_R1.java new file mode 100644 index 0000000..9482130 --- /dev/null +++ b/modules/nms/epicanchors-v1_9_R1/src/main/java/epicanchors/nms/v1_9_R1.java @@ -0,0 +1,259 @@ +package epicanchors.nms; + +import com.songoda.epicanchors.AnchorNMS; +import com.songoda.epicanchors.utils.ReflectionUtils; +import com.songoda.epicanchors.utils.Utils; +import net.minecraft.server.v1_9_R1.AxisAlignedBB; +import net.minecraft.server.v1_9_R1.Block; +import net.minecraft.server.v1_9_R1.BlockPosition; +import net.minecraft.server.v1_9_R1.ChunkRegionLoader; +import net.minecraft.server.v1_9_R1.ChunkSection; +import net.minecraft.server.v1_9_R1.Entity; +import net.minecraft.server.v1_9_R1.EntityInsentient; +import net.minecraft.server.v1_9_R1.EnumParticle; +import net.minecraft.server.v1_9_R1.IBlockData; +import net.minecraft.server.v1_9_R1.MobSpawnerAbstract; +import net.minecraft.server.v1_9_R1.MobSpawnerData; +import net.minecraft.server.v1_9_R1.NBTTagCompound; +import net.minecraft.server.v1_9_R1.NBTTagList; +import net.minecraft.server.v1_9_R1.WorldServer; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.v1_9_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_9_R1.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.v1_9_R1.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class v1_9_R1 extends AnchorNMS { + @SuppressWarnings("unused") + public v1_9_R1(JavaPlugin plugin) { + super(plugin); + } + + @Override + public boolean loadAnchoredChunk(Chunk chunk) { + return chunk.load(); + } + + @Override + public boolean unloadAnchoredChunk(Chunk chunk) { + return chunk.unload(); + } + + @Override + public void tickInactiveSpawners(Chunk chunk, int amount) { + if (amount <= 0) return; + + try { + for (BlockState tileEntity : chunk.getTileEntities()) { + if (tileEntity instanceof CreatureSpawner) { + MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); + + for (int i = 0; i < amount; ++i) { + if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { + break; // Spawner not inactive + } + } + } + } + } catch (Exception ex) { + Utils.logException(super.plugin, ex); + } + } + + @Override + public void doRandomTick(Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); + } + + @Override + public int getRandomTickSpeed(World world) { + return Helper.getRandomTickSpeedLegacy(world); + } + + /** + * This class contains some modified methods from {@link WorldServer}. + */ + private static class NotchianServerLevel { + /** + * Method is based on {@link WorldServer#j()}. + */ + static void randomTickChunk(net.minecraft.server.v1_9_R1.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + if (tickAmount > 0) { + int j = chunk.locX * 16; + int k = chunk.locZ * 16; + + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != net.minecraft.server.v1_9_R1.Chunk.a && chunksection.shouldTick()) { + for (int i = 0; i < tickAmount; ++i) { + int worldL = (int) ReflectionUtils.getFieldValue(chunk.world, "l"); + + worldL = worldL * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "l", worldL); + + int l1 = worldL >> 2; + int i2 = l1 & 15; + int j2 = l1 >> 8 & 15; + int k2 = l1 >> 16 & 15; + + IBlockData iblockdata = chunksection.getType(i2, k2, j2); + Block block = iblockdata.getBlock(); + + if (block.isTicking()) { + block.a(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), iblockdata, chunk.world.random); + } + } + } + } + } + } + } + + /** + * This class contains some modified methods from {@link MobSpawnerAbstract}. + */ + private static class NotchianBaseSpawner { + private static Method iMethod, hMethod; + + static { + try { + iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); + iMethod.setAccessible(true); + + hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); + hMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + Utils.logException(null, ex); + } + } + + static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); + + return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); + } + + /** + * This method calls {@link MobSpawnerAbstract#h()} using Reflections. + */ + static boolean isNearPlayer(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + return (boolean) hMethod.invoke(spawner); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + * + * @return false if the spawner is not inactive, true otherwise + */ + static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException, NoSuchFieldException { + if (isNearPlayer(spawner)) return false; + + BlockPosition blockposition = spawner.b(); + if (spawner.a().isClientSide) { + double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d0, d1, d2, 0D, 0D, 0D); + spawner.a().addParticle(EnumParticle.FLAME, d0, d1, d2, 0D, 0D, 0D); + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerD = (double) ReflectionUtils.getFieldValue(spawner, "d"); + + ReflectionUtils.setFieldValue(spawner, "e", spawnerD); + ReflectionUtils.setFieldValue(spawner, "d", (spawnerD + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return true; + } + + boolean flag = false; + int i = 0; + + int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); + int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); + int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); + MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); + + while (true) { + if (i >= spawnCount) { + if (flag) { + delay(spawner); + } + break; + } + + NBTTagCompound nbttagcompound = spawnData.b(); + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + net.minecraft.server.v1_9_R1.World world = spawner.a(); + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.e(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.e(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.e(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; + Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); + if (entity == null) { + return true; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawnRange)).size(); + if (k >= maxNearbyEntities) { + delay(spawner); + return true; + } + + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360F, 0F); + if (entityinsentient == null || entityinsentient.cF() && entityinsentient.canSpawn()) { + if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { + ((EntityInsentient) entity).prepare(world.D(new BlockPosition(entity)), null); + } + + if (entity.world.spigotConfig.nerfSpawnerMobs) { + entity.fromMobSpawner = true; + } + + if (!CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); + world.triggerEffect(2004, blockposition, 0); + if (entityinsentient != null) { + entityinsentient.doSpawnEffect(); + } + + flag = true; + } + } + + ++i; + } + } + + return true; + } + + /** + * This method calls {@link MobSpawnerAbstract#i()} using Reflections. + */ + static void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + iMethod.invoke(spawner); + } + } +} diff --git a/modules/nms/epicanchors-v1_9_R2/pom.xml b/modules/nms/epicanchors-v1_9_R2/pom.xml new file mode 100644 index 0000000..87b66ba --- /dev/null +++ b/modules/nms/epicanchors-v1_9_R2/pom.xml @@ -0,0 +1,37 @@ + + + 4.0.0 + + + com.songoda + EpicAnchors + 2.0.0-ALPHA + ../../../pom.xml + + jar + epicanchors-v1_9_R2 + + + + com.songoda + epicanchors-api + ${project.version} + + + + org.spigotmc + spigot-api + 1.9.4-R0.1-SNAPSHOT + provided + + + + org.spigotmc + spigot + 1.9.4 + provided + + + diff --git a/modules/nms/epicanchors-v1_9_R2/src/main/java/epicanchors/nms/v1_9_R2.java b/modules/nms/epicanchors-v1_9_R2/src/main/java/epicanchors/nms/v1_9_R2.java new file mode 100644 index 0000000..c009edc --- /dev/null +++ b/modules/nms/epicanchors-v1_9_R2/src/main/java/epicanchors/nms/v1_9_R2.java @@ -0,0 +1,261 @@ +package epicanchors.nms; + +import com.songoda.epicanchors.AnchorNMS; +import com.songoda.epicanchors.utils.ReflectionUtils; +import com.songoda.epicanchors.utils.Utils; +import net.minecraft.server.v1_9_R2.AxisAlignedBB; +import net.minecraft.server.v1_9_R2.Block; +import net.minecraft.server.v1_9_R2.BlockPosition; +import net.minecraft.server.v1_9_R2.ChunkRegionLoader; +import net.minecraft.server.v1_9_R2.ChunkSection; +import net.minecraft.server.v1_9_R2.Entity; +import net.minecraft.server.v1_9_R2.EntityInsentient; +import net.minecraft.server.v1_9_R2.EnumParticle; +import net.minecraft.server.v1_9_R2.IBlockData; +import net.minecraft.server.v1_9_R2.MobSpawnerAbstract; +import net.minecraft.server.v1_9_R2.MobSpawnerData; +import net.minecraft.server.v1_9_R2.NBTTagCompound; +import net.minecraft.server.v1_9_R2.NBTTagList; +import net.minecraft.server.v1_9_R2.WorldServer; +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.block.CreatureSpawner; +import org.bukkit.craftbukkit.v1_9_R2.CraftChunk; +import org.bukkit.craftbukkit.v1_9_R2.block.CraftCreatureSpawner; +import org.bukkit.craftbukkit.v1_9_R2.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class v1_9_R2 extends AnchorNMS { + @SuppressWarnings("unused") + public v1_9_R2(JavaPlugin plugin) { + super(plugin); + } + + @Override + public boolean loadAnchoredChunk(Chunk chunk) { + return chunk.load(); + } + + @Override + public boolean unloadAnchoredChunk(Chunk chunk) { + return chunk.unload(); + } + + @Override + public void tickInactiveSpawners(Chunk chunk, int amount) { + if (amount <= 0) return; + + try { + for (BlockState tileEntity : chunk.getTileEntities()) { + if (tileEntity instanceof CreatureSpawner) { + MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); + + for (int i = 0; i < amount; ++i) { + if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { + break; // Spawner not inactive + } + } + } + } + } catch (Exception ex) { + Utils.logException(super.plugin, ex); + } + } + + @Override + public void doRandomTick(Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); + } + + @Override + public int getRandomTickSpeed(World world) { + return Helper.getRandomTickSpeedLegacy(world); + } + + /** + * This class contains some modified methods from {@link WorldServer}. + */ + private static class NotchianServerLevel { + /** + * Method is based on {@link WorldServer#j()}. + */ + static void randomTickChunk(net.minecraft.server.v1_9_R2.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { + if (tickAmount > 0) { + int j = chunk.locX * 16; + int k = chunk.locZ * 16; + + for (ChunkSection chunksection : chunk.getSections()) { + if (chunksection != net.minecraft.server.v1_9_R2.Chunk.a && chunksection.shouldTick()) { + for (int k1 = 0; k1 < tickAmount; ++k1) { + int worldL = (int) ReflectionUtils.getFieldValue(chunk.world, "l"); + worldL = worldL * 3 + 1013904223; + ReflectionUtils.setFieldValue(chunk.world, "l", worldL); + + int l1 = worldL >> 2; + int i2 = l1 & 15; + int j2 = l1 >> 8 & 15; + int k2 = l1 >> 16 & 15; + + IBlockData iblockdata = chunksection.getType(i2, k2, j2); + Block block = iblockdata.getBlock(); + + if (block.isTicking()) { + block.a(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), iblockdata, chunk.world.random); + } + } + } + } + } + } + } + + /** + * This class contains some modified methods from {@link MobSpawnerAbstract}. + */ + private static class NotchianBaseSpawner { + private static Method iMethod, hMethod; + + static { + try { + iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); + iMethod.setAccessible(true); + + hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); + hMethod.setAccessible(true); + } catch (NoSuchMethodException ex) { + Utils.logException(null, ex); + } + } + + static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { + Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); + + return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); + } + + /** + * This method calls {@link MobSpawnerAbstract#h()} using Reflections. + */ + static boolean isNearPlayer(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + return (boolean) hMethod.invoke(spawner); + } + + /** + * This method is based on {@link MobSpawnerAbstract#c()}. + * + * @return false if the spawner is not inactive, true otherwise + */ + static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException, NoSuchFieldException { + if (isNearPlayer(spawner)) return false; + + BlockPosition blockposition = spawner.b(); + + if (spawner.a().isClientSide) { + double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); + double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); + double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); + + spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d0, d1, d2, 0D, 0D, 0D); + spawner.a().addParticle(EnumParticle.FLAME, d0, d1, d2, 0D, 0D, 0D); + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + } + + double spawnerD = (double) ReflectionUtils.getFieldValue(spawner, "d"); + + ReflectionUtils.setFieldValue(spawner, "e", spawnerD); + ReflectionUtils.setFieldValue(spawner, "d", (spawnerD + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); + } else { + if (spawner.spawnDelay == -1) { + delay(spawner); + } + + if (spawner.spawnDelay > 0) { + --spawner.spawnDelay; + return true; + } + + boolean flag = false; + int i = 0; + + int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); + int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); + int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); + MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); + + while (true) { + if (i >= spawnCount) { + if (flag) { + delay(spawner); + } + break; + } + + NBTTagCompound nbttagcompound = spawnData.b(); + NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); + net.minecraft.server.v1_9_R2.World world = spawner.a(); + int j = nbttaglist.size(); + double d3 = j >= 1 ? nbttaglist.e(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; + double d4 = j >= 2 ? nbttaglist.e(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); + double d5 = j >= 3 ? nbttaglist.e(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; + Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); + if (entity == null) { + return true; + } + + int k = world.a(entity.getClass(), (new AxisAlignedBB( + blockposition.getX(), + blockposition.getY(), + blockposition.getZ(), + blockposition.getX() + 1, + blockposition.getY() + 1, + blockposition.getZ() + 1)) + .g(spawnRange)).size(); + if (k >= maxNearbyEntities) { + delay(spawner); + return true; + } + + EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; + entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360.0F, 0.0F); + if (entityinsentient == null || entityinsentient.cG() && entityinsentient.canSpawn()) { + if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { + ((EntityInsentient) entity).prepare(world.D(new BlockPosition(entity)), null); + } + + if (entity.world.spigotConfig.nerfSpawnerMobs) { + entity.fromMobSpawner = true; + } + + if (!CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { + ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); + world.triggerEffect(2004, blockposition, 0); + if (entityinsentient != null) { + entityinsentient.doSpawnEffect(); + } + + flag = true; + } + } + + ++i; + } + } + + return true; + } + + /** + * This method is based on {@link MobSpawnerAbstract#i()}. + */ + static void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { + iMethod.invoke(spawner); + } + } +} diff --git a/pom.xml b/pom.xml index 708ff92..3f90c96 100644 --- a/pom.xml +++ b/pom.xml @@ -1,119 +1,93 @@ - + + + 4.0.0 + com.songoda EpicAnchors - 4.0.0 - 1.4.10c + pom + 2.0.0-ALPHA + + + + modules/epicanchors-api + modules/epicanchors-plugin + + modules/nms/epicanchors-v1_16_R3 + modules/nms/epicanchors-v1_16_R2 + modules/nms/epicanchors-v1_16_R1 + modules/nms/epicanchors-v1_15_R1 + modules/nms/epicanchors-v1_14_R1 + modules/nms/epicanchors-v1_13_R2 + modules/nms/epicanchors-v1_13_R1 + modules/nms/epicanchors-v1_12_R1 + modules/nms/epicanchors-v1_11_R1 + modules/nms/epicanchors-v1_10_R1 + modules/nms/epicanchors-v1_9_R2 + modules/nms/epicanchors-v1_9_R1 + modules/nms/epicanchors-v1_8_R3 + modules/nms/epicanchors-v1_8_R2 + modules/nms/epicanchors-v1_8_R1 + + + EpicAnchors + Allow your players to keep chunks loaded for a limited amount of time for a cost. + https://songoda.com/marketplace/product/31 + + + 1.8 + 8 + + UTF-8 + + + + https://support.songoda.com/servicedesk/customer/portal/3 + Jira Service Desk + + + + https://github.com/songoda/EpicAnchors + scm:git:git:github.com/songoda/EpicAnchors.git + + - clean install - EpicAnchors-${project.version} org.apache.maven.plugins maven-compiler-plugin - 3.8.0 + 3.8.1 + - 1.8 - 1.8 + ${java.version} + ${java.version} + + ${java.release} - - com.google.code.maven-replacer-plugin - replacer - 1.5.3 - - - prepare-package - - replace - - - - - ${project.build.directory}/classes/plugin.yml - - - maven-version-number - ${project.version} - - - - - - org.apache.maven.plugins - maven-shade-plugin - 3.1.0 - - - shaded - package - - shade - - - false - false - true - - - com.songoda:SongodaCore - - - - - - - *:* - - META-INF/*.SF - META-INF/*.DSA - META-INF/*.RSA - - - - - - com.songoda.core - ${project.groupId}.epicanchors.core - - - - - - + - public - https://repo.songoda.com/repository/public/ - - - spigot-repo + spigotmc-repo https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + songoda-public + https://repo.songoda.com/repository/public/ + + + - org.spigotmc - spigot - 1.16.4 - provided - - - com.songoda - SongodaCore - LATEST + org.jetbrains + annotations + 21.0.0 compile - - com.songoda - epicspawners - 6-pre4 - diff --git a/src/main/java/com/songoda/epicanchors/EpicAnchors.java b/src/main/java/com/songoda/epicanchors/EpicAnchors.java deleted file mode 100644 index 2ce0405..0000000 --- a/src/main/java/com/songoda/epicanchors/EpicAnchors.java +++ /dev/null @@ -1,217 +0,0 @@ -package com.songoda.epicanchors; - -import com.songoda.core.SongodaCore; -import com.songoda.core.SongodaPlugin; -import com.songoda.core.commands.CommandManager; -import com.songoda.core.compatibility.CompatibleMaterial; -import com.songoda.core.compatibility.ServerVersion; -import com.songoda.core.configuration.Config; -import com.songoda.core.gui.GuiManager; -import com.songoda.core.hooks.EconomyManager; -import com.songoda.core.hooks.HologramManager; -import com.songoda.core.nms.NmsManager; -import com.songoda.core.nms.nbt.NBTItem; -import com.songoda.core.utils.TextUtils; -import com.songoda.epicanchors.anchor.Anchor; -import com.songoda.epicanchors.anchor.AnchorManager; -import com.songoda.epicanchors.commands.*; -import com.songoda.epicanchors.listeners.BlockListeners; -import com.songoda.epicanchors.listeners.InteractListeners; -import com.songoda.epicanchors.listeners.PortalListeners; -import com.songoda.epicanchors.settings.Settings; -import com.songoda.epicanchors.tasks.AnchorTask; -import com.songoda.epicanchors.tasks.VisualizeTask; -import com.songoda.epicanchors.utils.Methods; -import org.apache.commons.lang.math.NumberUtils; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.plugin.PluginManager; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -public class EpicAnchors extends SongodaPlugin { - - private static EpicAnchors INSTANCE; - - private final Config dataFile = new Config(this, "data.yml"); - - private final GuiManager guiManager = new GuiManager(this); - private AnchorManager anchorManager; - private CommandManager commandManager; - - public static EpicAnchors getInstance() { - return INSTANCE; - } - - @Override - public void onPluginLoad() { - INSTANCE = this; - } - - @Override - public void onPluginDisable() { - saveToFile(); - HologramManager.removeAllHolograms(); - } - - @Override - public void onDataLoad() {} - - @Override - public void onPluginEnable() { - // Run Songoda Updater - SongodaCore.registerPlugin(this, 31, CompatibleMaterial.END_PORTAL_FRAME); - - // Load Economy - EconomyManager.load(); - - // Setup Config - Settings.setupConfig(); - this.setLocale(Settings.LANGUGE_MODE.getString(), false); - - // Set economy preference - EconomyManager.getManager().setPreferredHook(Settings.ECONOMY_PLUGIN.getString()); - - // Register commands - this.commandManager = new CommandManager(this); - this.commandManager.addCommand(new CommandEpicAnchors(this)) - .addSubCommands( - new CommandGive(this), - new CommandReload(this), - new CommandSettings(this, guiManager), - new CommandShow(this) - ); - - anchorManager = new AnchorManager(); - Bukkit.getScheduler().runTaskLater(this, this::loadAnchorsFromFile, 5L); - - // Start tasks - new AnchorTask(this); - new VisualizeTask(this); - - // Register Listeners - guiManager.init(); - PluginManager pluginManager = Bukkit.getPluginManager(); - pluginManager.registerEvents(new BlockListeners(this), this); - pluginManager.registerEvents(new InteractListeners(this), this); - if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9)) - pluginManager.registerEvents(new PortalListeners(this), this); - - // Register Hologram Plugin - HologramManager.load(this); - - if (Settings.HOLOGRAMS.getBoolean()) - loadHolograms(); - - Bukkit.getScheduler().runTaskTimerAsynchronously(this, this::saveToFile, 6000, 6000); - } - - @Override - public void onConfigReload() { - this.setLocale(Settings.LANGUGE_MODE.getString(), true); - this.loadAnchorsFromFile(); - } - - @Override - public List getExtraConfig() { - return null; - } - - void loadHolograms() { - Collection anchors = getAnchorManager().getAnchors().values(); - if (anchors.size() == 0) return; - - for (Anchor anchor : anchors) { - if (anchor.getWorld() == null) continue; - updateHologram(anchor); - } - } - - public void clearHologram(Anchor anchor) { - HologramManager.removeHologram(correctHeight(anchor.getLocation())); - } - - public void updateHologram(Anchor anchor) { - // are holograms enabled? - if (!Settings.HOLOGRAMS.getBoolean() || !HologramManager.getManager().isEnabled()) return; - // verify that this is a anchor - if (anchor.getLocation().getBlock().getType() != Settings.MATERIAL.getMaterial().getMaterial()) return; - // grab the name - String name = Methods.formatName(anchor.getTicksLeft()).trim(); - Location location = correctHeight(anchor.getLocation()); - // create the hologram - HologramManager.updateHologram(location, name); - } - - private Location correctHeight(Location location) { - if (location.getBlock().getType() != CompatibleMaterial.END_PORTAL_FRAME.getMaterial()) - location.add(0, .05, 0); - return location; - } - - private void loadAnchorsFromFile() { - dataFile.load(); - if (!dataFile.contains("Anchors")) return; - for (String locationStr : dataFile.getConfigurationSection("Anchors").getKeys(false)) { - Location location = Methods.unserializeLocation(locationStr); - int ticksLeft = dataFile.getInt("Anchors." + locationStr + ".ticksLeft"); - anchorManager.addAnchor(location, new Anchor(location, ticksLeft)); - } - } - - private void saveToFile() { - dataFile.clearConfig(true); - for (Anchor anchor : anchorManager.getAnchors().values()) { - String locationStr = Methods.serializeLocation(anchor.getLocation()); - dataFile.set("Anchors." + locationStr + ".ticksLeft", anchor.getTicksLeft()); - } - dataFile.save(); - } - - public int getTicksFromItem(ItemStack item) { - NBTItem nbtItem = NmsManager.getNbt().of(item); - if (nbtItem.has("ticks")) { - return nbtItem.getNBTObject("ticks").asInt(); - } - - // Legacy code. Tries to get the ticks remaining from hidden text. - if (!item.hasItemMeta() || !item.getItemMeta().hasDisplayName()) return 0; - if (item.getItemMeta().getDisplayName().contains(":")) { - return Integer.parseInt(item.getItemMeta().getDisplayName().replace("\u00A7", "").split(":")[0]); - } - return 0; - } - - public ItemStack makeAnchorItem(int ticks) { - ItemStack item = Settings.MATERIAL.getMaterial().getItem(); - ItemMeta meta = item.getItemMeta(); - meta.setDisplayName(Methods.formatName(ticks)); - ArrayList lore = new ArrayList<>(); - String[] parts = Settings.LORE.getString().split("\\|"); - for (String line : parts) { - lore.add(TextUtils.formatText(line)); - } - meta.setLore(lore); - item.setItemMeta(meta); - - NBTItem nbtItem = NmsManager.getNbt().of(item); - nbtItem.set("ticks", ticks); - return nbtItem.finish(); - } - - public CommandManager getCommandManager() { - return commandManager; - } - - public GuiManager getGuiManager() { - return guiManager; - } - - public AnchorManager getAnchorManager() { - return anchorManager; - } -} diff --git a/src/main/java/com/songoda/epicanchors/anchor/Anchor.java b/src/main/java/com/songoda/epicanchors/anchor/Anchor.java deleted file mode 100644 index d6cc5d4..0000000 --- a/src/main/java/com/songoda/epicanchors/anchor/Anchor.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.songoda.epicanchors.anchor; - -import com.songoda.core.compatibility.ServerVersion; -import com.songoda.core.hooks.EconomyManager; -import com.songoda.epicanchors.EpicAnchors; -import com.songoda.epicanchors.settings.Settings; -import org.bukkit.*; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; - -public class Anchor { - - private Location location; - private int ticksLeft; - private boolean isInfinite; - - private final int chunkX; - private final int chunkZ; - - public Anchor(Location location, int ticksLeft) { - this.location = location; - this.chunkX = location.getBlockX() >> 4; - this.chunkZ = location.getBlockZ() >> 4; - this.ticksLeft = ticksLeft; - this.isInfinite = (ticksLeft == -99); - } - - public void addTime(String type, Player player) { - EpicAnchors instance = EpicAnchors.getInstance(); - - if (type.equals("ECO")) { - if (!EconomyManager.isEnabled()) return; - double cost = instance.getConfig().getDouble("Main.Economy Cost"); - if (EconomyManager.hasBalance(player, cost)) { - EconomyManager.withdrawBalance(player, cost); - } else { - instance.getLocale().getMessage("event.upgrade.cannotafford").sendPrefixedMessage(player); - return; - } - } else if (type.equals("XP")) { - int cost = instance.getConfig().getInt("Main.XP Cost"); - if (player.getLevel() >= cost || player.getGameMode() == GameMode.CREATIVE) { - if (player.getGameMode() != GameMode.CREATIVE) { - player.setLevel(player.getLevel() - cost); - } - } else { - instance.getLocale().getMessage("event.upgrade.cannotafford").sendPrefixedMessage(player); - return; - } - } - - ticksLeft = ticksLeft + 20 * 60 * 30; - Sound sound = ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9) ? Sound.ENTITY_PLAYER_LEVELUP : Sound.valueOf("LEVEL_UP"); - player.playSound(player.getLocation(), sound, 0.6F, 15.0F); - - if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9)) - player.getWorld().spawnParticle(Particle.SPELL_WITCH, getLocation().add(.5, .5, .5), 100, .5, .5, .5); - } - - public void bust() { - EpicAnchors plugin = EpicAnchors.getInstance(); - - if (Settings.ALLOW_ANCHOR_BREAKING.getBoolean() && getTicksLeft() > 0) { - ItemStack item = plugin.makeAnchorItem(getTicksLeft()); - getLocation().getWorld().dropItemNaturally(getLocation(), item); - } - plugin.clearHologram(this); - location.getBlock().setType(Material.AIR); - - if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9)) - location.getWorld().spawnParticle(Particle.LAVA, location.clone().add(.5, .5, .5), 5, 0, 0, 0, 5); - - location.getWorld().playSound(location, ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9) - ? Sound.ENTITY_GENERIC_EXPLODE : Sound.valueOf("EXPLODE"), 10, 10); - - plugin.getAnchorManager().removeAnchor(location); - } - - public Location getLocation() { - return location.clone(); - } - - public int getChunkX() { - return chunkX; - } - - public int getChunkZ() { - return chunkZ; - } - - public World getWorld() { - return location.getWorld(); - } - - public int getTicksLeft() { - return ticksLeft; - } - - public void setTicksLeft(int ticksLeft) { - this.ticksLeft = ticksLeft; - } - - public boolean isInfinite() { - return isInfinite; - } - - public void setInfinite(boolean infinite) { - isInfinite = infinite; - } -} diff --git a/src/main/java/com/songoda/epicanchors/anchor/AnchorManager.java b/src/main/java/com/songoda/epicanchors/anchor/AnchorManager.java deleted file mode 100644 index 1edbb81..0000000 --- a/src/main/java/com/songoda/epicanchors/anchor/AnchorManager.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.songoda.epicanchors.anchor; - -import org.bukkit.Location; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -public class AnchorManager { - - private final Map registeredAnchors = new HashMap<>(); - - public Anchor addAnchor(Location location, Anchor anchor) { - return registeredAnchors.put(roundLocation(location), anchor); - } - - public void removeAnchor(Location location) { - registeredAnchors.remove(roundLocation(location)); - } - - public Anchor getAnchor(Location location) { - return registeredAnchors.get(roundLocation(location)); - } - - public Anchor getAnchor(String world, int chunkX, int chunkZ) { - return this.registeredAnchors.values().stream() - .filter(anchor -> anchor.getWorld().getName().equals(world) && anchor.getChunkX() == chunkX && anchor.getChunkZ() == chunkZ).findFirst().orElse(null); - } - - public boolean isAnchor(Location location) { - return registeredAnchors.containsKey(location); - } - - public Map getAnchors() { - return Collections.unmodifiableMap(registeredAnchors); - } - - private Location roundLocation(org.bukkit.Location location) { - location = location.clone(); - location.setX(location.getBlockX()); - location.setY(location.getBlockY()); - location.setZ(location.getBlockZ()); - return location; - } -} diff --git a/src/main/java/com/songoda/epicanchors/commands/CommandGive.java b/src/main/java/com/songoda/epicanchors/commands/CommandGive.java deleted file mode 100644 index 1535d8b..0000000 --- a/src/main/java/com/songoda/epicanchors/commands/CommandGive.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.songoda.epicanchors.commands; - -import com.songoda.core.commands.AbstractCommand; -import com.songoda.epicanchors.EpicAnchors; -import com.songoda.epicanchors.utils.Methods; -import org.bukkit.Bukkit; -import org.bukkit.command.CommandSender; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class CommandGive extends AbstractCommand { - - final EpicAnchors instance; - - public CommandGive(EpicAnchors instance) { - super(false, "give"); - this.instance = instance; - } - - @Override - protected ReturnType runCommand(CommandSender sender, String... args) { - if (args.length != 2) return ReturnType.SYNTAX_ERROR; - - - Player target = Bukkit.getPlayer(args[0]); - if (target == null && !args[0].trim().toLowerCase().equals("all")) { - instance.getLocale().newMessage("&cThat is not a player...").sendPrefixedMessage(sender); - return ReturnType.SYNTAX_ERROR; - } - - - - ItemStack itemStack; - - if (Methods.isInt(args[1])) { - itemStack = (Integer.parseInt(args[1]) <= 0) ? instance.makeAnchorItem(-99) : instance.makeAnchorItem(Integer.parseInt(args[1]) * 20 * 60 * 60); - } else if (args[1].toLowerCase().equals("infinite")) { - itemStack = instance.makeAnchorItem(-99); - } else { - instance.getLocale().newMessage("&cYou can only use whole numbers...").sendPrefixedMessage(sender); - return ReturnType.FAILURE; - } - - if (target != null) { - target.getInventory().addItem(itemStack); - instance.getLocale().getMessage("command.give.success").sendPrefixedMessage(target); - } else { - for (Player player : Bukkit.getOnlinePlayers()) { - player.getInventory().addItem(itemStack); - instance.getLocale().getMessage("command.give.success").sendPrefixedMessage(player); - } - } - - return ReturnType.SUCCESS; - } - - @Override - protected List onTab(CommandSender commandSender, String... strings) { - if (strings.length == 1) { - List players = new ArrayList<>(); - players.add("all"); - for (Player player : Bukkit.getOnlinePlayers()) { - players.add(player.getName()); - } - return players; - } else if (strings.length == 2) { - return Arrays.asList("1", "2", "3", "4", "5"); - } - return null; - } - - @Override - public String getPermissionNode() { - return "epicanchors.admin"; - } - - @Override - public String getSyntax() { - return "/ea give "; - } - - @Override - public String getDescription() { - return "Gives an operator the ability to spawn a ChunkAnchor of his or her choice."; - } -} diff --git a/src/main/java/com/songoda/epicanchors/gui/GUIOverview.java b/src/main/java/com/songoda/epicanchors/gui/GUIOverview.java deleted file mode 100644 index 4d84226..0000000 --- a/src/main/java/com/songoda/epicanchors/gui/GUIOverview.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.songoda.epicanchors.gui; - -import com.songoda.core.compatibility.CompatibleMaterial; -import com.songoda.core.gui.Gui; -import com.songoda.core.gui.GuiUtils; -import com.songoda.core.hooks.EconomyManager; -import com.songoda.core.utils.TextUtils; -import com.songoda.core.utils.TimeUtils; -import com.songoda.epicanchors.EpicAnchors; -import com.songoda.epicanchors.anchor.Anchor; -import com.songoda.epicanchors.settings.Settings; -import com.songoda.epicanchors.utils.Methods; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; - -public class GUIOverview extends Gui { - - private final EpicAnchors plugin; - private final Anchor anchor; - private final Player player; - - private int task; - - public GUIOverview(EpicAnchors plugin, Anchor anchor, Player player) { - this.plugin = plugin; - this.anchor = anchor; - this.player = player; - - this.setRows(3); - this.setTitle(TextUtils.formatText(plugin.getLocale().getMessage("interface.anchor.title").getMessage())); - - runTask(); - constructGUI(); - this.setOnClose(action -> Bukkit.getScheduler().cancelTask(task)); - } - - private void constructGUI() { - ItemStack glass1 = GuiUtils.getBorderItem(Settings.GLASS_TYPE_1.getMaterial()); - ItemStack glass2 = GuiUtils.getBorderItem(Settings.GLASS_TYPE_2.getMaterial()); - ItemStack glass3 = GuiUtils.getBorderItem(Settings.GLASS_TYPE_3.getMaterial()); - - setDefaultItem(glass1); - - mirrorFill(0, 0, true, true, glass2); - mirrorFill(0, 1, true, true, glass2); - mirrorFill(0, 2, true, true, glass3); - mirrorFill(1, 0, false, true, glass2); - mirrorFill(1, 1, false, true, glass3); - - setItem(13, GuiUtils.createButtonItem(plugin.makeAnchorItem(anchor.getTicksLeft()), - plugin.getLocale().getMessage("interface.anchor.smalltitle").getMessage(), - (anchor.isInfinite()) ? ChatColor.GRAY + "Infinite" : ChatColor.GRAY + TimeUtils.makeReadable((long) (anchor.getTicksLeft() / 20) * 1000) + " remaining.")); - - if (EconomyManager.isEnabled() && Settings.ADD_TIME_WITH_ECONOMY.getBoolean()) { - setButton(15, GuiUtils.createButtonItem(Settings.ECO_ICON.getMaterial(CompatibleMaterial.SUNFLOWER), - plugin.getLocale().getMessage("interface.button.addtimewitheconomy").getMessage(), - plugin.getLocale().getMessage("interface.button.addtimewitheconomylore") - .processPlaceholder("cost", EconomyManager.formatEconomy(Settings.ECONOMY_COST.getDouble())).getMessage()), // EconomyManager.formatEconomy adds its own prefix/suffix - event -> checkInfiniteAndAlert(anchor, event.player, true)); - } - - if (Settings.ADD_TIME_WITH_XP.getBoolean()) { - setButton(11, GuiUtils.createButtonItem(Settings.XP_ICON.getMaterial(CompatibleMaterial.EXPERIENCE_BOTTLE), - plugin.getLocale().getMessage("interface.button.addtimewithxp").getMessage(), - plugin.getLocale().getMessage("interface.button.addtimewithxplore") - .processPlaceholder("cost", String.valueOf(Settings.XP_COST.getInt())).getMessage()), - event -> checkInfiniteAndAlert(anchor, event.player, false)); - } - - } - - private void runTask() { - task = Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, () -> { - updateItem(13, plugin.getLocale().getMessage("interface.anchor.smalltitle").getMessage(), - (anchor.isInfinite()) ? ChatColor.GRAY + "Infinite" : ChatColor.GRAY + TimeUtils.makeReadable((long) (anchor.getTicksLeft() / 20) * 1000) + " remaining."); - }, 5L, 5L); - } - - private void checkInfiniteAndAlert(Anchor anchor, Player p, boolean eco) { - if (anchor.isInfinite()) { - plugin.getLocale().getMessage("interface.button.infinite").sendPrefixedMessage(p); - } else { - if (eco) { - anchor.addTime("ECO", p); - } else { - anchor.addTime("XP", p); - } - } - } -} diff --git a/src/main/java/com/songoda/epicanchors/listeners/BlockListeners.java b/src/main/java/com/songoda/epicanchors/listeners/BlockListeners.java deleted file mode 100644 index 7f989d8..0000000 --- a/src/main/java/com/songoda/epicanchors/listeners/BlockListeners.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.songoda.epicanchors.listeners; - -import com.songoda.epicanchors.EpicAnchors; -import com.songoda.epicanchors.anchor.Anchor; -import com.songoda.epicanchors.settings.Settings; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.inventory.ItemStack; - -public class BlockListeners implements Listener { - - private EpicAnchors plugin; - - public BlockListeners(EpicAnchors instance) { - this.plugin = instance; - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBlockPlace(BlockPlaceEvent event) { - - ItemStack item = event.getItemInHand(); - - if (!item.hasItemMeta() - || !item.getItemMeta().hasDisplayName() - || Settings.MATERIAL.getMaterial().getMaterial() != event.getBlock().getType() - || plugin.getTicksFromItem(item) == 0) return; - - Anchor anchor = new Anchor(event.getBlock().getLocation(), plugin.getTicksFromItem(item)); - - if (plugin.getTicksFromItem(item) == -99) { - anchor.setInfinite(true); - } - - plugin.getAnchorManager().addAnchor(event.getBlock().getLocation(), anchor); - plugin.updateHologram(anchor); - - } -} diff --git a/src/main/java/com/songoda/epicanchors/listeners/InteractListeners.java b/src/main/java/com/songoda/epicanchors/listeners/InteractListeners.java deleted file mode 100644 index ec27077..0000000 --- a/src/main/java/com/songoda/epicanchors/listeners/InteractListeners.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.songoda.epicanchors.listeners; - -import com.songoda.core.compatibility.CompatibleHand; -import com.songoda.core.compatibility.CompatibleMaterial; -import com.songoda.core.compatibility.CompatibleParticleHandler; -import com.songoda.core.compatibility.CompatibleSound; -import com.songoda.core.utils.ItemUtils; -import com.songoda.epicanchors.EpicAnchors; -import com.songoda.epicanchors.anchor.Anchor; -import com.songoda.epicanchors.gui.GUIOverview; -import com.songoda.epicanchors.settings.Settings; -import org.bukkit.Bukkit; -import org.bukkit.GameMode; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.inventory.ItemStack; - -public class InteractListeners implements Listener { - - private final EpicAnchors instance; - - public InteractListeners(EpicAnchors instance) { - this.instance = instance; - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onBlockInteract(PlayerInteractEvent event) { - if (event.getClickedBlock() == null) return; - - Anchor anchor = instance.getAnchorManager().getAnchor(event.getClickedBlock().getLocation()); - - if (anchor == null) return; - event.setCancelled(true); - - Player player = event.getPlayer(); - - if (event.getAction() != Action.RIGHT_CLICK_BLOCK) { - BlockBreakEvent blockBreakEvent = new BlockBreakEvent(event.getClickedBlock(), player); - Bukkit.getPluginManager().callEvent(blockBreakEvent); - if (blockBreakEvent.isCancelled()) - return; - - anchor.bust(); - return; - } - - ItemStack item = player.getItemInHand(); - - if (Settings.MATERIAL.getMaterial().matches(item)) { - if (instance.getTicksFromItem(item) == 0) return; - - anchor.setTicksLeft(anchor.getTicksLeft() + instance.getTicksFromItem(item)); - - if (player.getGameMode() != GameMode.CREATIVE) - ItemUtils.takeActiveItem(player, CompatibleHand.getHand(event)); - - player.playSound(player.getLocation(), CompatibleSound.ENTITY_PLAYER_LEVELUP.getSound(), 0.6F, 15.0F); - - CompatibleParticleHandler.spawnParticles(CompatibleParticleHandler.ParticleType.SPELL_WITCH, anchor.getLocation().add(.5, .5, .5), 100, .5, .5, .5); - - } else { - instance.getGuiManager().showGUI(player, new GUIOverview(EpicAnchors.getInstance(), anchor, player)); - } - } - -} diff --git a/src/main/java/com/songoda/epicanchors/listeners/PortalListeners.java b/src/main/java/com/songoda/epicanchors/listeners/PortalListeners.java deleted file mode 100644 index 09ecaf6..0000000 --- a/src/main/java/com/songoda/epicanchors/listeners/PortalListeners.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.songoda.epicanchors.listeners; - -import com.songoda.epicanchors.EpicAnchors; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.world.PortalCreateEvent; - -public class PortalListeners implements Listener { - - private EpicAnchors plugin; - - public PortalListeners(EpicAnchors instance) { - this.plugin = instance; - } - - @EventHandler - public void onPortalCreation(PortalCreateEvent e) { - if (e.getBlocks().size() < 1) return; - if (plugin.getAnchorManager().isAnchor(e.getBlocks().get(0).getLocation())) e.setCancelled(true); - } -} diff --git a/src/main/java/com/songoda/epicanchors/tasks/AnchorTask.java b/src/main/java/com/songoda/epicanchors/tasks/AnchorTask.java deleted file mode 100644 index 0a92e14..0000000 --- a/src/main/java/com/songoda/epicanchors/tasks/AnchorTask.java +++ /dev/null @@ -1,145 +0,0 @@ -package com.songoda.epicanchors.tasks; - -import com.songoda.core.compatibility.CompatibleMaterial; -import com.songoda.core.compatibility.CompatibleParticleHandler; -import com.songoda.core.compatibility.ServerVersion; -import com.songoda.epicanchors.EpicAnchors; -import com.songoda.epicanchors.anchor.Anchor; -import com.songoda.epicanchors.settings.Settings; -import org.bukkit.*; -import org.bukkit.block.Block; -import org.bukkit.entity.Entity; -import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -public class AnchorTask extends BukkitRunnable { - - private static EpicAnchors plugin; - - private Map delays = new HashMap<>(); - - private Class clazzEntity, clazzCraftEntity, clazzMinecraftServer; - - private Method methodTick, methodGetHandle; - - private Field fieldCurrentTick, fieldActivatedTick; - - private boolean epicSpawners; - - public AnchorTask(EpicAnchors plug) { - plugin = plug; - epicSpawners = Bukkit.getPluginManager().getPlugin("EpicSpawners") != null; - - try { - String ver = Bukkit.getServer().getClass().getPackage().getName().substring(23); - clazzMinecraftServer = Class.forName("net.minecraft.server." + ver + ".MinecraftServer"); - clazzEntity = Class.forName("net.minecraft.server." + ver + ".Entity"); - clazzCraftEntity = Class.forName("org.bukkit.craftbukkit." + ver + ".entity.CraftEntity"); - - if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_13)) - methodTick = clazzEntity.getDeclaredMethod("tick"); - else if (ServerVersion.isServerVersion(ServerVersion.V1_12)) - methodTick = clazzEntity.getDeclaredMethod("B_"); - else if (ServerVersion.isServerVersion(ServerVersion.V1_11)) - methodTick = clazzEntity.getDeclaredMethod("A_"); - else if (ServerVersion.isServerVersionAtLeast(ServerVersion.V1_9)) - methodTick = clazzEntity.getDeclaredMethod("m"); - else - methodTick = clazzEntity.getDeclaredMethod("t_"); - - methodGetHandle = clazzCraftEntity.getDeclaredMethod("getHandle"); - - fieldCurrentTick = clazzMinecraftServer.getDeclaredField("currentTick"); - fieldActivatedTick = clazzEntity.getDeclaredField("activatedTick"); - - } catch (ReflectiveOperationException e) { - e.printStackTrace(); - } - - this.runTaskTimer(plugin, 0, 3); - } - - private void doParticle() { - for (Anchor anchor : plugin.getAnchorManager().getAnchors().values()) { - Location location1 = anchor.getLocation().add(.5, .5, .5); - if (location1.getWorld() == null) continue; - CompatibleParticleHandler.redstoneParticles(location1, 255, 255, 255, 1.2F, 5, .75F); - } - } - - @Override - public void run() { - doParticle(); - for (Anchor anchor : new ArrayList<>(plugin.getAnchorManager().getAnchors().values())) { - - if (anchor.getLocation() == null) continue; - - plugin.updateHologram(anchor); - - Location location = anchor.getLocation(); - if (CompatibleMaterial.getMaterial(location.getBlock()) != Settings.MATERIAL.getMaterial()) - continue; - - Chunk chunk = location.getChunk(); - chunk.load(); - - // Load entities - for (Entity entity : chunk.getEntities()) { - if (!(entity instanceof LivingEntity) || entity instanceof Player) continue; - - if (entity.getNearbyEntities(32, 32, 32).stream().anyMatch(entity1 -> entity1 instanceof Player)) { - continue; - } - - try { - Object objCraftEntity = clazzCraftEntity.cast(entity); - Object objEntity = methodGetHandle.invoke(objCraftEntity); - - fieldActivatedTick.set(objEntity, fieldCurrentTick.getLong(objEntity)); - methodTick.invoke(objEntity); - } catch (ReflectiveOperationException e) { - e.printStackTrace(); - } - } - - int ticksLeft = anchor.getTicksLeft(); - - if (!anchor.isInfinite()) { - anchor.setTicksLeft(ticksLeft - 3); - } - - if (ticksLeft <= 0 && !anchor.isInfinite()) { - anchor.bust(); - chunk.unload(); - return; - } - - if (!epicSpawners || com.songoda.epicspawners.EpicSpawners.getInstance().getSpawnerManager() == null) continue; - - com.songoda.epicspawners.EpicSpawners.getInstance().getSpawnerManager().getSpawners().stream() - .filter(spawner -> spawner.getWorld().isChunkLoaded(spawner.getX() >> 4, spawner.getZ() >> 4) - && chunk == spawner.getLocation().getChunk()).forEach(spawner -> { - Block block = spawner.getLocation().getBlock(); - - if (!delays.containsKey(block.getLocation())) { - delays.put(block.getLocation(), spawner.updateDelay()); - return; - } - int delay = delays.get(block.getLocation()); - delay -= 1; - delays.put(block.getLocation(), delay); - if (delay <= 0) { - spawner.spawn(); - delays.remove(block.getLocation()); - } - }); - } - } -} diff --git a/src/main/java/com/songoda/epicanchors/tasks/VisualizeTask.java b/src/main/java/com/songoda/epicanchors/tasks/VisualizeTask.java deleted file mode 100644 index b1e1cd6..0000000 --- a/src/main/java/com/songoda/epicanchors/tasks/VisualizeTask.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.songoda.epicanchors.tasks; - -import com.songoda.epicanchors.EpicAnchors; -import com.songoda.epicanchors.anchor.Anchor; -import com.songoda.epicanchors.anchor.AnchorManager; -import org.bukkit.*; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; - -import java.util.Map; -import java.util.Random; -import java.util.concurrent.ConcurrentHashMap; - -public class VisualizeTask extends BukkitRunnable { - - private static VisualizeTask instance; - private static EpicAnchors plugin; - private final static Map active = new ConcurrentHashMap(); - private final static Random random = new Random(); - int radius; - - public VisualizeTask(EpicAnchors plug) { - plugin = plug; - radius = Bukkit.getServer().getViewDistance(); - if (instance == null) { - instance = this; - instance.runTaskTimerAsynchronously(plugin, 60, 10); - } - } - - public static boolean togglePlayer(Player p) { - Boolean isActive = active.get(p); - active.put(p, isActive = (isActive == null || !isActive)); - return isActive; - } - - public static void removePlayer(Player p) { - active.remove(p); - } - - @Override - public void run() { - active.entrySet().stream() - .filter(e -> e.getValue() && e.getKey().isOnline()) - .forEach(e -> particleTick((Player) e.getKey())); - } - - void particleTick(Player player) { - final AnchorManager anchorManager = plugin.getAnchorManager(); - final Location playerLocation = player.getLocation(); - final World world = playerLocation.getWorld(); - // start and stop chunk coordinates - int startY = playerLocation.getBlockY() + 1; - int cxi = (playerLocation.getBlockX() >> 4) - radius, cxn = cxi + radius * 2; - int czi = (playerLocation.getBlockZ() >> 4) - radius, czn = czi + radius * 2; - // loop through the chunks to find applicable ones - for (int cx = cxi; cx < cxn; cx++) { - for (int cz = czi; cz < czn; cz++) { - // sanity check - if (!world.isChunkLoaded(cx, cz)) - continue; - - // so! Is this a claimed chunk? - Anchor anchor = anchorManager.getAnchor(world.getName(), cx, cz); - if (anchor != null) { - // we found one! - // now we get to spawn the silly particles for the player - showChunkParticles(player, world.getChunkAt(cx, cz), startY); - } - } - } - } - - void showChunkParticles(Player player, Chunk c, int startY) { - // loop through the chunk - for (int x = 0; x < 16; x++) { - for (int z = 0; z < 16; z++) { - // show about 1/5 of the blocks per tick - boolean show = random.nextFloat() < .2; - if (!show) - continue; - - // Exclude everything over max height - if (startY >= c.getWorld().getMaxHeight()) continue; - - // only show if there is a space to show above a solid block - Block b = c.getBlock(x, startY, z); - int maxDown = 8; - do { - show = b.getType().isTransparent() && !(b = b.getRelative(BlockFace.DOWN)).getType().isTransparent(); - } while (--maxDown > 0 && !show); - - // can we do this? - if (show) { - final Location loc = b.getLocation().add(.5, 1.5, .5); - - player.spawnParticle(Particle.VILLAGER_HAPPY, loc, 0, 0, 0, 0, 1); - } - } - } - } -} diff --git a/src/main/java/com/songoda/epicanchors/utils/Methods.java b/src/main/java/com/songoda/epicanchors/utils/Methods.java deleted file mode 100644 index 25fe998..0000000 --- a/src/main/java/com/songoda/epicanchors/utils/Methods.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.songoda.epicanchors.utils; - -import com.songoda.core.utils.TextUtils; -import com.songoda.core.utils.TimeUtils; -import com.songoda.epicanchors.EpicAnchors; -import com.songoda.epicanchors.settings.Settings; -import org.bukkit.*; -import org.bukkit.block.Block; - -import java.text.DecimalFormat; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -public class Methods { - - private static Map serializeCache = new HashMap<>(); - - public static String formatName(int ticks) { - - String remaining = TimeUtils.makeReadable((ticks / 20L) * 1000L); - - String name = Settings.NAMETAG.getString().replace("{REMAINING}", (ticks <= 0) - ? EpicAnchors.getInstance().getLocale().getMessage("infinite").getMessage() : remaining); - - - return TextUtils.formatText(name); - } - - /** - * Serializes the location specified. - * - * @param location The location that is to be saved. - * @return The serialized data. - */ - public static String serializeLocation(Location location) { - if (location == null) - return ""; - String w = location.getWorld().getName(); - double x = location.getX(); - double y = location.getY(); - double z = location.getZ(); - String str = w + ":" + x + ":" + y + ":" + z; - str = str.replace(".0", "").replace("/", ""); - return str; - } - - /** - * Deserializes a location from the string. - * - * @param str The string to parse. - * @return The location that was serialized in the string. - */ - public static Location unserializeLocation(String str) { - if (str == null || str.equals("")) - return null; - if (serializeCache.containsKey(str)) { - return serializeCache.get(str).clone(); - } - String cacheKey = str; - str = str.replace("y:", ":").replace("z:", ":").replace("w:", "").replace("x:", ":").replace("/", "."); - List args = Arrays.asList(str.split("\\s*:\\s*")); - - World world = Bukkit.getWorld(args.get(0)); - double x = Double.parseDouble(args.get(1)), y = Double.parseDouble(args.get(2)), z = Double.parseDouble(args.get(3)); - Location location = new Location(world, x, y, z, 0, 0); - serializeCache.put(cacheKey, location.clone()); - return location; - } - - public static boolean isInt(String number) { - if (number != null && !number.equals("")) { - try { - Integer.parseInt(number); - return true; - } catch (NumberFormatException var2) { - return false; - } - } else { - return false; - } - } -} diff --git a/src/main/resources/SettingDefinitions.yml b/src/main/resources/SettingDefinitions.yml deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml deleted file mode 100644 index dbd3c85..0000000 --- a/src/main/resources/plugin.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: EpicAnchors -description: EpicAnchors -version: maven-version-number -softdepend: [EpicSpawners, Towny, RedProtect, Kingdoms, PlotsSquared, GriefPrevention, USkyBlock, ASkyBlock, WorldGuard, Factions, Vault, HolographicDisplays, Holograms, CMI] -main: com.songoda.epicanchors.EpicAnchors -author: songoda -api-version: 1.13 -commands: - EpicAnchors: - description: I have no idea. - default: true - aliases: [ea] - usage: / [reload] \ No newline at end of file From e0507324cdb16a085a189e997bc1155288c77e20 Mon Sep 17 00:00:00 2001 From: Christian Koop Date: Sun, 30 May 2021 06:42:21 +0200 Subject: [PATCH 02/12] Setup SonarCloud --- .github/workflows/build.yml | 35 ----------------- .github/workflows/maven.yml | 76 +++++++++++++++++++++++++++++++++++++ README.md | 1 + pom.xml | 5 +++ 4 files changed, 82 insertions(+), 35 deletions(-) delete mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/maven.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 8bce0e4..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Build -on: - push: - branches: - - master - pull_request: - types: [ opened, synchronize, reopened ] -jobs: - build: - name: Build - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Set up JDK 11 - uses: actions/setup-java@v2 - with: - java-version: 11 - distribution: adopt - - - name: 'Cache: Maven-Repository' - uses: actions/cache@v2 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven- - - - name: Build with Maven - run: 'mvn -B -Duser.name="GitHub Runner on $GITHUB_REPOSITORY (id=$GITHUB_RUN_ID)" clean package' - - - name: 'Upload Build Artifact: EpicAnchors-*.jar' - uses: actions/upload-artifact@v2 - with: - name: EpicAnchors-artifacts - path: ./modules/epicanchors-plugin/target/EpicAnchors-*.jar diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 0000000..f1a8f42 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,76 @@ +name: 'Build & Test' + +on: + push: + branches: [ master ] + pull_request: + types: [ opened, synchronize, reopened ] + +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + # Setup Java + - uses: actions/setup-java@v2 + with: + java-version: 11 + distribution: adopt + + # Checkout project files + - uses: actions/checkout@v2 + + # Caches + - name: 'Cache: Maven' + uses: actions/cache@v2 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-maven- + + # Build project + - name: Build with Maven + run: 'mvn -B -Duser.name="GitHub Runner on $GITHUB_REPOSITORY (id=$GITHUB_RUN_ID)" clean package' + + # Upload build artifacts + - name: 'Upload Build Artifact: EpicAnchors-*.jar' + uses: actions/upload-artifact@v2 + with: + name: EpicAnchors-artifacts + path: ./modules/epicanchors-plugin/target/EpicAnchors-*.jar + + sonarcloud: + name: SonarCloud + runs-on: ubuntu-latest + steps: + # Setup Java + - uses: actions/setup-java@v2 + with: + java-version: 11 + distribution: adopt + + # Checkout project files + - uses: actions/checkout@v2 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + + # Caches + - name: 'Cache: Maven' + uses: actions/cache@v2 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-maven- + - name: 'Cache: SonarCloud' + uses: actions/cache@v2 + with: + path: ~/.sonar/cache + key: ${{ runner.os }}-sonar + restore-keys: ${{ runner.os }}-sonar + + # SonarCloud static analysis + - name: SonarCloud + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar diff --git a/README.md b/README.md index deb9329..eab8ce6 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ [![Patreon](https://img.shields.io/badge/-Support_on_Patreon-F96854.svg?logo=patreon&style=flat&logoColor=white)](https://www.patreon.com/join/songoda)
[![Latest version](https://img.shields.io/github/v/tag/SpraxDev/EpicAnchors?include_prereleases&label=Latest&logo=github&labelColor=black)](https://songoda.com/marketplace/product/31) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=songoda_EpicAnchors&metric=alert_status)](https://sonarcloud.io/dashboard?id=songoda_EpicAnchors) [![GitHub last commit](https://img.shields.io/github/last-commit/SpraxDev/EpicAnchors?label=Last+commit)](https://github.com/SpraxDev/EpicAnchors/commits)
[![bStats Servers](https://img.shields.io/bstats/servers/4816?label=Servers)](https://bstats.org/plugin/bukkit/EpicAnchors/4816) diff --git a/pom.xml b/pom.xml index 3f90c96..a2a3b9d 100644 --- a/pom.xml +++ b/pom.xml @@ -40,6 +40,11 @@ 8 UTF-8 + + songoda_EpicAnchors + songoda + https://sonarcloud.io + ${project.groupId}:${project.artifactId} From 474d4e447faaaeda4b1b04498cc869d7b5f93cfa Mon Sep 17 00:00:00 2001 From: Christian Koop Date: Sat, 12 Jun 2021 15:14:45 +0200 Subject: [PATCH 03/12] Give-Command: Suggest `all` instead of `@a` by default --- .../com/songoda/epicanchors/commands/sub/GiveCommand.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/GiveCommand.java b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/GiveCommand.java index 7fbdc27..c90c96c 100644 --- a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/GiveCommand.java +++ b/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/GiveCommand.java @@ -71,7 +71,11 @@ public class GiveCommand extends AbstractCommand { players.add(player.getName()); } - players.add("@a"); + players.add("all"); + + if ("@a".startsWith(args[0].toLowerCase())) { + players.add("@a"); + } return Utils.getMatches(args[0], players, true); } else if (args.length == 2) { @@ -102,7 +106,7 @@ public class GiveCommand extends AbstractCommand { @Override public String getSyntax() { - return "/ea give "; + return "/ea give "; } @Override From 5f39f1de1bffea0003978943f051b307cd436b13 Mon Sep 17 00:00:00 2001 From: Christian Koop Date: Sun, 30 May 2021 07:11:24 +0200 Subject: [PATCH 04/12] Create FUNDING.yml --- .github/FUNDING.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..c4daa16 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: songoda +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] From edea975e1615a9ffbb5b173bc464a43a79f113ac Mon Sep 17 00:00:00 2001 From: Christian Koop Date: Sat, 12 Jun 2021 15:14:14 +0200 Subject: [PATCH 05/12] Bump annotations from 21.0.0 to 21.0.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a2a3b9d..fab5a32 100644 --- a/pom.xml +++ b/pom.xml @@ -91,7 +91,7 @@ org.jetbrains annotations - 21.0.0 + 21.0.1 compile From 2b334bd900d83fb040ac3f18e18620dcd549fab3 Mon Sep 17 00:00:00 2001 From: Christian Koop Date: Sat, 26 Jun 2021 17:15:28 +0200 Subject: [PATCH 06/12] Moved NMS into SongodaCore --- .github/workflows/maven.yml | 6 +- .gitignore | 3 +- modules/epicanchors-api/pom.xml | 31 -- .../com/songoda/epicanchors/AnchorNMS.java | 82 ----- modules/epicanchors-plugin/pom.xml | 221 ------------- modules/nms/epicanchors-v1_10_R1/pom.xml | 37 --- .../main/java/epicanchors/nms/v1_10_R1.java | 267 --------------- modules/nms/epicanchors-v1_11_R1/pom.xml | 37 --- .../main/java/epicanchors/nms/v1_11_R1.java | 262 --------------- modules/nms/epicanchors-v1_12_R1/pom.xml | 37 --- .../main/java/epicanchors/nms/v1_12_R1.java | 266 --------------- modules/nms/epicanchors-v1_13_R1/pom.xml | 37 --- .../main/java/epicanchors/nms/v1_13_R1.java | 282 ---------------- modules/nms/epicanchors-v1_13_R2/pom.xml | 37 --- .../main/java/epicanchors/nms/v1_13_R2.java | 294 ----------------- modules/nms/epicanchors-v1_14_R1/pom.xml | 37 --- .../main/java/epicanchors/nms/v1_14_R1.java | 304 ----------------- modules/nms/epicanchors-v1_15_R1/pom.xml | 37 --- .../main/java/epicanchors/nms/v1_15_R1.java | 303 ----------------- modules/nms/epicanchors-v1_16_R1/pom.xml | 37 --- .../main/java/epicanchors/nms/v1_16_R1.java | 302 ----------------- modules/nms/epicanchors-v1_16_R2/pom.xml | 37 --- .../main/java/epicanchors/nms/v1_16_R2.java | 299 ----------------- modules/nms/epicanchors-v1_16_R3/pom.xml | 37 --- .../main/java/epicanchors/nms/v1_16_R3.java | 305 ------------------ modules/nms/epicanchors-v1_8_R1/pom.xml | 37 --- .../main/java/epicanchors/nms/v1_8_R1.java | 251 -------------- modules/nms/epicanchors-v1_8_R2/pom.xml | 37 --- .../main/java/epicanchors/nms/v1_8_R2.java | 248 -------------- modules/nms/epicanchors-v1_8_R3/pom.xml | 37 --- .../main/java/epicanchors/nms/v1_8_R3.java | 249 -------------- modules/nms/epicanchors-v1_9_R1/pom.xml | 37 --- .../main/java/epicanchors/nms/v1_9_R1.java | 259 --------------- modules/nms/epicanchors-v1_9_R2/pom.xml | 37 --- .../main/java/epicanchors/nms/v1_9_R2.java | 261 --------------- pom.xml | 111 +++++-- .../java/com/songoda/epicanchors/Anchor.java | 13 +- .../songoda/epicanchors/AnchorManager.java | 15 +- .../com/songoda/epicanchors/EpicAnchors.java | 50 +-- .../epicanchors/api}/AnchorAccessCheck.java | 3 +- .../commands/EpicAnchorsCommand.java | 0 .../epicanchors/commands/sub/GiveCommand.java | 0 .../commands/sub/ReloadCommand.java | 0 .../commands/sub/SettingsCommand.java | 0 .../epicanchors/commands/sub/ShowCommand.java | 0 .../epicanchors/files/DataManager.java | 0 .../songoda/epicanchors/files/Settings.java | 0 .../files/migration/AnchorMigration.java | 0 .../files/migration/_1_InitialMigration.java | 0 .../songoda/epicanchors/guis/AnchorGui.java | 0 .../guis/DestroyConfirmationGui.java | 0 .../epicanchors/listener/AnchorListener.java | 0 .../epicanchors/listener/BlockListener.java | 0 .../epicanchors/listener/DebugListener.java | 0 .../epicanchors/listener/WorldListener.java | 0 .../songoda/epicanchors/tasks/AnchorTask.java | 36 ++- .../epicanchors/tasks/VisualizeTask.java | 0 .../songoda/epicanchors/utils/Callback.java | 0 .../epicanchors/utils/ReflectionUtils.java | 0 .../songoda/epicanchors/utils/ThreadSync.java | 0 .../epicanchors/utils/UpdateCallback.java | 0 .../com/songoda/epicanchors/utils/Utils.java | 0 .../songoda/epicanchors/utils/WorldUtils.java | 66 ++++ .../src => src}/main/resources/en_US.lang | 0 .../src => src}/main/resources/plugin.yml | 8 +- 65 files changed, 209 insertions(+), 5143 deletions(-) delete mode 100644 modules/epicanchors-api/pom.xml delete mode 100644 modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorNMS.java delete mode 100644 modules/epicanchors-plugin/pom.xml delete mode 100644 modules/nms/epicanchors-v1_10_R1/pom.xml delete mode 100644 modules/nms/epicanchors-v1_10_R1/src/main/java/epicanchors/nms/v1_10_R1.java delete mode 100644 modules/nms/epicanchors-v1_11_R1/pom.xml delete mode 100644 modules/nms/epicanchors-v1_11_R1/src/main/java/epicanchors/nms/v1_11_R1.java delete mode 100644 modules/nms/epicanchors-v1_12_R1/pom.xml delete mode 100644 modules/nms/epicanchors-v1_12_R1/src/main/java/epicanchors/nms/v1_12_R1.java delete mode 100644 modules/nms/epicanchors-v1_13_R1/pom.xml delete mode 100644 modules/nms/epicanchors-v1_13_R1/src/main/java/epicanchors/nms/v1_13_R1.java delete mode 100644 modules/nms/epicanchors-v1_13_R2/pom.xml delete mode 100644 modules/nms/epicanchors-v1_13_R2/src/main/java/epicanchors/nms/v1_13_R2.java delete mode 100644 modules/nms/epicanchors-v1_14_R1/pom.xml delete mode 100644 modules/nms/epicanchors-v1_14_R1/src/main/java/epicanchors/nms/v1_14_R1.java delete mode 100644 modules/nms/epicanchors-v1_15_R1/pom.xml delete mode 100644 modules/nms/epicanchors-v1_15_R1/src/main/java/epicanchors/nms/v1_15_R1.java delete mode 100644 modules/nms/epicanchors-v1_16_R1/pom.xml delete mode 100644 modules/nms/epicanchors-v1_16_R1/src/main/java/epicanchors/nms/v1_16_R1.java delete mode 100644 modules/nms/epicanchors-v1_16_R2/pom.xml delete mode 100644 modules/nms/epicanchors-v1_16_R2/src/main/java/epicanchors/nms/v1_16_R2.java delete mode 100644 modules/nms/epicanchors-v1_16_R3/pom.xml delete mode 100644 modules/nms/epicanchors-v1_16_R3/src/main/java/epicanchors/nms/v1_16_R3.java delete mode 100644 modules/nms/epicanchors-v1_8_R1/pom.xml delete mode 100644 modules/nms/epicanchors-v1_8_R1/src/main/java/epicanchors/nms/v1_8_R1.java delete mode 100644 modules/nms/epicanchors-v1_8_R2/pom.xml delete mode 100644 modules/nms/epicanchors-v1_8_R2/src/main/java/epicanchors/nms/v1_8_R2.java delete mode 100644 modules/nms/epicanchors-v1_8_R3/pom.xml delete mode 100644 modules/nms/epicanchors-v1_8_R3/src/main/java/epicanchors/nms/v1_8_R3.java delete mode 100644 modules/nms/epicanchors-v1_9_R1/pom.xml delete mode 100644 modules/nms/epicanchors-v1_9_R1/src/main/java/epicanchors/nms/v1_9_R1.java delete mode 100644 modules/nms/epicanchors-v1_9_R2/pom.xml delete mode 100644 modules/nms/epicanchors-v1_9_R2/src/main/java/epicanchors/nms/v1_9_R2.java rename {modules/epicanchors-api/src => src}/main/java/com/songoda/epicanchors/Anchor.java (88%) rename {modules/epicanchors-api/src => src}/main/java/com/songoda/epicanchors/AnchorManager.java (98%) rename {modules/epicanchors-plugin/src => src}/main/java/com/songoda/epicanchors/EpicAnchors.java (74%) rename {modules/epicanchors-api/src/main/java/com/songoda/epicanchors => src/main/java/com/songoda/epicanchors/api}/AnchorAccessCheck.java (69%) rename {modules/epicanchors-plugin/src => src}/main/java/com/songoda/epicanchors/commands/EpicAnchorsCommand.java (100%) rename {modules/epicanchors-plugin/src => src}/main/java/com/songoda/epicanchors/commands/sub/GiveCommand.java (100%) rename {modules/epicanchors-plugin/src => src}/main/java/com/songoda/epicanchors/commands/sub/ReloadCommand.java (100%) rename {modules/epicanchors-plugin/src => src}/main/java/com/songoda/epicanchors/commands/sub/SettingsCommand.java (100%) rename {modules/epicanchors-plugin/src => src}/main/java/com/songoda/epicanchors/commands/sub/ShowCommand.java (100%) rename {modules/epicanchors-api/src => src}/main/java/com/songoda/epicanchors/files/DataManager.java (100%) rename {modules/epicanchors-api/src => src}/main/java/com/songoda/epicanchors/files/Settings.java (100%) rename {modules/epicanchors-api/src => src}/main/java/com/songoda/epicanchors/files/migration/AnchorMigration.java (100%) rename {modules/epicanchors-api/src => src}/main/java/com/songoda/epicanchors/files/migration/_1_InitialMigration.java (100%) rename {modules/epicanchors-plugin/src => src}/main/java/com/songoda/epicanchors/guis/AnchorGui.java (100%) rename {modules/epicanchors-plugin/src => src}/main/java/com/songoda/epicanchors/guis/DestroyConfirmationGui.java (100%) rename {modules/epicanchors-plugin/src => src}/main/java/com/songoda/epicanchors/listener/AnchorListener.java (100%) rename {modules/epicanchors-plugin/src => src}/main/java/com/songoda/epicanchors/listener/BlockListener.java (100%) rename {modules/epicanchors-plugin/src => src}/main/java/com/songoda/epicanchors/listener/DebugListener.java (100%) rename {modules/epicanchors-plugin/src => src}/main/java/com/songoda/epicanchors/listener/WorldListener.java (100%) rename {modules/epicanchors-plugin/src => src}/main/java/com/songoda/epicanchors/tasks/AnchorTask.java (66%) rename {modules/epicanchors-plugin/src => src}/main/java/com/songoda/epicanchors/tasks/VisualizeTask.java (100%) rename {modules/epicanchors-api/src => src}/main/java/com/songoda/epicanchors/utils/Callback.java (100%) rename {modules/epicanchors-api/src => src}/main/java/com/songoda/epicanchors/utils/ReflectionUtils.java (100%) rename {modules/epicanchors-api/src => src}/main/java/com/songoda/epicanchors/utils/ThreadSync.java (100%) rename {modules/epicanchors-api/src => src}/main/java/com/songoda/epicanchors/utils/UpdateCallback.java (100%) rename {modules/epicanchors-api/src => src}/main/java/com/songoda/epicanchors/utils/Utils.java (100%) create mode 100644 src/main/java/com/songoda/epicanchors/utils/WorldUtils.java rename {modules/epicanchors-plugin/src => src}/main/resources/en_US.lang (100%) rename {modules/epicanchors-plugin/src => src}/main/resources/plugin.yml (74%) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index f1a8f42..250ece3 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -2,7 +2,7 @@ name: 'Build & Test' on: push: - branches: [ master ] + branches: [ master, development ] pull_request: types: [ opened, synchronize, reopened ] @@ -14,7 +14,7 @@ jobs: # Setup Java - uses: actions/setup-java@v2 with: - java-version: 11 + java-version: 16 distribution: adopt # Checkout project files @@ -37,7 +37,7 @@ jobs: uses: actions/upload-artifact@v2 with: name: EpicAnchors-artifacts - path: ./modules/epicanchors-plugin/target/EpicAnchors-*.jar + path: ./target/EpicAnchors-*.jar sonarcloud: name: SonarCloud diff --git a/.gitignore b/.gitignore index 6cbab07..600a1f2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ -/modules/*/target/ -/modules/nms/*/target/ +/target/ # JetBrains IDEs /.idea/ diff --git a/modules/epicanchors-api/pom.xml b/modules/epicanchors-api/pom.xml deleted file mode 100644 index f4a69cc..0000000 --- a/modules/epicanchors-api/pom.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - 4.0.0 - - - com.songoda - EpicAnchors - 2.0.0-ALPHA - ../../pom.xml - - jar - epicanchors-api - - - - org.spigotmc - spigot-api - 1.8-R0.1-SNAPSHOT - provided - - - - com.songoda - SongodaCore - 2.4.56 - compile - - - diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorNMS.java b/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorNMS.java deleted file mode 100644 index a7e1010..0000000 --- a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorNMS.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.songoda.epicanchors; - -import org.bukkit.Chunk; -import org.bukkit.World; -import org.bukkit.plugin.java.JavaPlugin; - -/** - * Provides abstraction to be used in maven modules with the specified spigot version. - */ -public abstract class AnchorNMS { - protected final JavaPlugin plugin; - - protected AnchorNMS(JavaPlugin plugin) { - this.plugin = plugin; - } - - /** - * Tries to load a given chunk
- * This method might introduce logic to keep chunks forcefully loaded. - *

- * More information: https://minecraft.fandom.com/wiki/Tick#Chunk_tick - * - * @param chunk The chunk to load - * - * @return true, if the chunk has been successfully loaded - * - * @see #unloadAnchoredChunk(Chunk) - */ - public abstract boolean loadAnchoredChunk(Chunk chunk); - - /** - * Tries unloading a given chunk if there are no players inside.
- * Any logic introduced in {@link #loadAnchoredChunk(Chunk)} to keep a chunk loaded is removed. - * - * @param chunk The chunk to unload - * - * @return true, if the chunk has been successfully unloaded - */ - public abstract boolean unloadAnchoredChunk(Chunk chunk); - - /** - * Ticks all inactive spawners in a specific chunk ignoring the minimum required players within a specific range.
- * A spawner is deemed inactive if the server should already be ticking it. - * - * @param chunk The chunk to tick the spawners in - * @param amount The amount of ticks to execute for each spawner - */ - public abstract void tickInactiveSpawners(Chunk chunk, int amount); - - /** - * Performs random ticks on a specific chunks. - *

- * More information: https://minecraft.fandom.com/wiki/Tick#Random_tick - * - * @param chunk The chunk to tick - * @param tickAmount The number of blocks to tick per ChunkSection, normally referred to as randomTickSpeed - */ - public abstract void doRandomTick(Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException; - - /** - * Returns the current value for the GameRule randomTickSpeed. - * - * @param world The world to retrieve the value from - * - * @return The current value or 3 if the GameRule does not exist - */ - public abstract int getRandomTickSpeed(World world); - - protected static class Helper { - private Helper() { - throw new IllegalStateException("Utility class"); - } - - public static int getRandomTickSpeedLegacy(World world) { - try { - return Integer.parseInt(world.getGameRuleValue("randomTickSpeed")); - } catch (NumberFormatException ignore) { - return 3; - } - } - } -} diff --git a/modules/epicanchors-plugin/pom.xml b/modules/epicanchors-plugin/pom.xml deleted file mode 100644 index 56fbaef..0000000 --- a/modules/epicanchors-plugin/pom.xml +++ /dev/null @@ -1,221 +0,0 @@ - - - 4.0.0 - - - com.songoda - EpicAnchors - 2.0.0-ALPHA - ../../pom.xml - - epicanchors-plugin - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - - ${java.version} - ${java.version} - - ${java.release} - - - - - org.apache.maven.plugins - maven-shade-plugin - 3.2.4 - - - - package - - - shade - - - - ${project.parent.name}-${project.version} - - false - true - - - - com.songoda.core - com.songoda.epicanchors.core - - - - epicanchors.nms - com.songoda.epicanchors.nms - - - - - - *:* - - - META-INF/** - LICENSE - LICENSE.** - - - - - org.jetbrains:annotations - - ** - - - - - com.songoda:epicanchors-v* - - ** - - - - - - - - - - - - src/main/resources - true - - - - - - - org.spigotmc - spigot-api - 1.8-R0.1-SNAPSHOT - provided - - - - - com.songoda - epicanchors-api - ${project.version} - compile - - - - com.songoda - epicanchors-v1_16_R3 - ${project.version} - compile - - - - com.songoda - epicanchors-v1_16_R2 - ${project.version} - compile - - - - com.songoda - epicanchors-v1_16_R1 - ${project.version} - compile - - - - com.songoda - epicanchors-v1_15_R1 - ${project.version} - compile - - - - com.songoda - epicanchors-v1_14_R1 - ${project.version} - compile - - - - com.songoda - epicanchors-v1_13_R2 - ${project.version} - compile - - - - com.songoda - epicanchors-v1_13_R1 - ${project.version} - compile - - - - com.songoda - epicanchors-v1_12_R1 - ${project.version} - compile - - - - com.songoda - epicanchors-v1_11_R1 - ${project.version} - compile - - - - com.songoda - epicanchors-v1_10_R1 - ${project.version} - compile - - - - com.songoda - epicanchors-v1_9_R2 - ${project.version} - compile - - - - com.songoda - epicanchors-v1_9_R1 - ${project.version} - compile - - - - com.songoda - epicanchors-v1_8_R3 - ${project.version} - compile - - - - com.songoda - epicanchors-v1_8_R2 - ${project.version} - compile - - - - com.songoda - epicanchors-v1_8_R1 - ${project.version} - compile - - - diff --git a/modules/nms/epicanchors-v1_10_R1/pom.xml b/modules/nms/epicanchors-v1_10_R1/pom.xml deleted file mode 100644 index d231d96..0000000 --- a/modules/nms/epicanchors-v1_10_R1/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - 4.0.0 - - - com.songoda - EpicAnchors - 2.0.0-ALPHA - ../../../pom.xml - - jar - epicanchors-v1_10_R1 - - - - com.songoda - epicanchors-api - ${project.version} - - - - org.spigotmc - spigot-api - 1.10.2-R0.1-SNAPSHOT - provided - - - - org.spigotmc - spigot - 1.10.2 - provided - - - diff --git a/modules/nms/epicanchors-v1_10_R1/src/main/java/epicanchors/nms/v1_10_R1.java b/modules/nms/epicanchors-v1_10_R1/src/main/java/epicanchors/nms/v1_10_R1.java deleted file mode 100644 index 5b0b286..0000000 --- a/modules/nms/epicanchors-v1_10_R1/src/main/java/epicanchors/nms/v1_10_R1.java +++ /dev/null @@ -1,267 +0,0 @@ -package epicanchors.nms; - -import com.songoda.epicanchors.AnchorNMS; -import com.songoda.epicanchors.utils.ReflectionUtils; -import com.songoda.epicanchors.utils.Utils; -import net.minecraft.server.v1_10_R1.AxisAlignedBB; -import net.minecraft.server.v1_10_R1.Block; -import net.minecraft.server.v1_10_R1.BlockPosition; -import net.minecraft.server.v1_10_R1.ChunkRegionLoader; -import net.minecraft.server.v1_10_R1.ChunkSection; -import net.minecraft.server.v1_10_R1.Entity; -import net.minecraft.server.v1_10_R1.EntityInsentient; -import net.minecraft.server.v1_10_R1.EnumParticle; -import net.minecraft.server.v1_10_R1.IBlockData; -import net.minecraft.server.v1_10_R1.MobSpawnerAbstract; -import net.minecraft.server.v1_10_R1.MobSpawnerData; -import net.minecraft.server.v1_10_R1.NBTTagCompound; -import net.minecraft.server.v1_10_R1.NBTTagList; -import net.minecraft.server.v1_10_R1.WorldServer; -import org.bukkit.Chunk; -import org.bukkit.World; -import org.bukkit.block.BlockState; -import org.bukkit.block.CreatureSpawner; -import org.bukkit.craftbukkit.v1_10_R1.CraftChunk; -import org.bukkit.craftbukkit.v1_10_R1.block.CraftCreatureSpawner; -import org.bukkit.craftbukkit.v1_10_R1.event.CraftEventFactory; -import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.plugin.java.JavaPlugin; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class v1_10_R1 extends AnchorNMS { - @SuppressWarnings("unused") - public v1_10_R1(JavaPlugin plugin) { - super(plugin); - } - - @Override - public boolean loadAnchoredChunk(Chunk chunk) { - return chunk.load(); - } - - @Override - public boolean unloadAnchoredChunk(Chunk chunk) { - return chunk.unload(); - } - - @Override - public void tickInactiveSpawners(Chunk chunk, int amount) { - if (amount <= 0) return; - - try { - for (BlockState tileEntity : chunk.getTileEntities()) { - if (tileEntity instanceof CreatureSpawner) { - MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); - - for (int i = 0; i < amount; ++i) { - if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { - break; // Spawner not inactive - } - } - } - } - } catch (Exception ex) { - Utils.logException(super.plugin, ex); - } - } - - @Override - public void doRandomTick(Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { - NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); - } - - @Override - public int getRandomTickSpeed(World world) { - return Helper.getRandomTickSpeedLegacy(world); - } - - /** - * This class contains some modified methods from {@link WorldServer}. - */ - private static class NotchianServerLevel { - /** - * Method is based on {@link WorldServer#j()}. - */ - static void randomTickChunk(net.minecraft.server.v1_10_R1.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { - if (tickAmount > 0) { - int j = chunk.locX * 16; - int k = chunk.locZ * 16; - - for (ChunkSection chunksection : chunk.getSections()) { - if (chunksection != net.minecraft.server.v1_10_R1.Chunk.a && chunksection.shouldTick()) { - for (int i = 0; i < tickAmount; ++i) { - int worldL = (int) ReflectionUtils.getFieldValue(chunk.world, "l"); - worldL = worldL * 3 + 1013904223; - ReflectionUtils.setFieldValue(chunk.world, "l", worldL); - - int l1 = worldL >> 2; - int i2 = l1 & 15; - int j2 = l1 >> 8 & 15; - int k2 = l1 >> 16 & 15; - - IBlockData iblockdata = chunksection.getType(i2, k2, j2); - Block block = iblockdata.getBlock(); - - if (block.isTicking()) { - block.a(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), iblockdata, chunk.world.random); - } - } - } - } - } - } - } - - /** - * This class contains some modified methods from {@link MobSpawnerAbstract}. - */ - private static class NotchianBaseSpawner { - private static Method iMethod, hMethod; - - static { - try { - iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); - iMethod.setAccessible(true); - - hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); - hMethod.setAccessible(true); - } catch (NoSuchMethodException ex) { - Utils.logException(null, ex); - } - } - - static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { - Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); - - return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); - } - - /** - * This method calls {@link MobSpawnerAbstract#h()} using Reflections. - */ - static boolean isNearPlayer(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { - return (boolean) hMethod.invoke(spawner); - } - - /** - * This method is based on {@link MobSpawnerAbstract#c()}. - * - * @return false if the spawner is not inactive, true otherwise - */ - static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { - if (isNearPlayer(spawner)) return false; - - BlockPosition blockposition = spawner.b(); - - if (spawner.a().isClientSide) { - double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); - double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); - double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); - - spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d0, d1, d2, 0D, 0D, 0D); - spawner.a().addParticle(EnumParticle.FLAME, d0, d1, d2, 0D, 0D, 0D); - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - } - - double spawnerD = (double) ReflectionUtils.getFieldValue(spawner, "d"); - - ReflectionUtils.setFieldValue(spawner, "e", spawnerD); - ReflectionUtils.setFieldValue(spawner, "d", (spawnerD + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); - } else { - if (spawner.spawnDelay == -1) { - delay(spawner); - } - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - return true; - } - - boolean flag = false; - int i = 0; - - int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); - int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); - int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); - MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); - - while (true) { - if (i >= spawnCount) { - if (flag) { - delay(spawner); - } - - break; - } - - NBTTagCompound nbttagcompound = spawnData.b(); - NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); - - net.minecraft.server.v1_10_R1.World world = spawner.a(); - - int j = nbttaglist.size(); - double d3 = j >= 1 ? nbttaglist.e(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; - double d4 = j >= 2 ? nbttaglist.e(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); - double d5 = j >= 3 ? nbttaglist.e(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; - - Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); - - if (entity == null) { - return true; - } - - int k = world.a(entity.getClass(), (new AxisAlignedBB(blockposition.getX(), - blockposition.getY(), - blockposition.getZ(), - blockposition.getX() + 1, - blockposition.getY() + 1, - blockposition.getZ() + 1)) - .g(spawnRange)).size(); - - if (k >= maxNearbyEntities) { - delay(spawner); - return true; - } - - EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; - entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360.0F, 0.0F); - - if (entityinsentient == null || entityinsentient.cK() && entityinsentient.canSpawn()) { - if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { - ((EntityInsentient) entity).prepare(world.D(new BlockPosition(entity)), null); - } - - if (entity.world.spigotConfig.nerfSpawnerMobs) { - entity.fromMobSpawner = true; - } - - if (!CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { - ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); - world.triggerEffect(2004, blockposition, 0); - if (entityinsentient != null) { - entityinsentient.doSpawnEffect(); - } - - flag = true; - } - } - - ++i; - } - } - - return true; - } - - /** - * This method calls {@link MobSpawnerAbstract#i()} using Reflections. - */ - static void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { - iMethod.invoke(spawner); - } - } -} diff --git a/modules/nms/epicanchors-v1_11_R1/pom.xml b/modules/nms/epicanchors-v1_11_R1/pom.xml deleted file mode 100644 index e184ffa..0000000 --- a/modules/nms/epicanchors-v1_11_R1/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - 4.0.0 - - - com.songoda - EpicAnchors - 2.0.0-ALPHA - ../../../pom.xml - - jar - epicanchors-v1_11_R1 - - - - com.songoda - epicanchors-api - ${project.version} - - - - org.spigotmc - spigot-api - 1.11-R0.1-SNAPSHOT - provided - - - - org.spigotmc - spigot - 1.11.2 - provided - - - diff --git a/modules/nms/epicanchors-v1_11_R1/src/main/java/epicanchors/nms/v1_11_R1.java b/modules/nms/epicanchors-v1_11_R1/src/main/java/epicanchors/nms/v1_11_R1.java deleted file mode 100644 index 55f9d59..0000000 --- a/modules/nms/epicanchors-v1_11_R1/src/main/java/epicanchors/nms/v1_11_R1.java +++ /dev/null @@ -1,262 +0,0 @@ -package epicanchors.nms; - -import com.songoda.epicanchors.AnchorNMS; -import com.songoda.epicanchors.utils.ReflectionUtils; -import com.songoda.epicanchors.utils.Utils; -import net.minecraft.server.v1_11_R1.AxisAlignedBB; -import net.minecraft.server.v1_11_R1.Block; -import net.minecraft.server.v1_11_R1.BlockPosition; -import net.minecraft.server.v1_11_R1.ChunkRegionLoader; -import net.minecraft.server.v1_11_R1.ChunkSection; -import net.minecraft.server.v1_11_R1.Entity; -import net.minecraft.server.v1_11_R1.EntityInsentient; -import net.minecraft.server.v1_11_R1.EnumParticle; -import net.minecraft.server.v1_11_R1.IBlockData; -import net.minecraft.server.v1_11_R1.MobSpawnerAbstract; -import net.minecraft.server.v1_11_R1.MobSpawnerData; -import net.minecraft.server.v1_11_R1.NBTTagCompound; -import net.minecraft.server.v1_11_R1.NBTTagList; -import net.minecraft.server.v1_11_R1.WorldServer; -import org.bukkit.Chunk; -import org.bukkit.World; -import org.bukkit.block.BlockState; -import org.bukkit.block.CreatureSpawner; -import org.bukkit.craftbukkit.v1_11_R1.CraftChunk; -import org.bukkit.craftbukkit.v1_11_R1.block.CraftCreatureSpawner; -import org.bukkit.craftbukkit.v1_11_R1.event.CraftEventFactory; -import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.plugin.java.JavaPlugin; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class v1_11_R1 extends AnchorNMS { - @SuppressWarnings("unused") - public v1_11_R1(JavaPlugin plugin) { - super(plugin); - } - - @Override - public boolean loadAnchoredChunk(Chunk chunk) { - return chunk.load(); - } - - @Override - public boolean unloadAnchoredChunk(Chunk chunk) { - return chunk.unload(); - } - - @Override - public void tickInactiveSpawners(Chunk chunk, int amount) { - if (amount <= 0) return; - - try { - for (BlockState tileEntity : chunk.getTileEntities()) { - if (tileEntity instanceof CreatureSpawner) { - MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); - - for (int i = 0; i < amount; ++i) { - if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { - break; // Spawner not inactive - } - } - } - } - } catch (Exception ex) { - Utils.logException(super.plugin, ex); - } - } - - @Override - public void doRandomTick(Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { - NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); - } - - @Override - public int getRandomTickSpeed(World world) { - return Helper.getRandomTickSpeedLegacy(world); - } - - /** - * This class contains some modified methods from {@link WorldServer}. - */ - private static class NotchianServerLevel { - /** - * Method is based on {@link WorldServer#j()}. - */ - static void randomTickChunk(net.minecraft.server.v1_11_R1.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { - if (tickAmount > 0) { - int j = chunk.locX * 16; - int k = chunk.locZ * 16; - - for (ChunkSection chunksection : chunk.getSections()) { - if (chunksection != net.minecraft.server.v1_11_R1.Chunk.a && chunksection.shouldTick()) { - for (int i = 0; i < tickAmount; ++i) { - int worldL = (int) ReflectionUtils.getFieldValue(chunk.world, "l"); - worldL = worldL * 3 + 1013904223; - ReflectionUtils.setFieldValue(chunk.world, "l", worldL); - - int l1 = worldL >> 2; - int i2 = l1 & 15; - int j2 = l1 >> 8 & 15; - int k2 = l1 >> 16 & 15; - - IBlockData iblockdata = chunksection.getType(i2, k2, j2); - Block block = iblockdata.getBlock(); - - if (block.isTicking()) { - block.a(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), iblockdata, chunk.world.random); - } - } - } - } - } - } - } - - /** - * This class contains some modified methods from {@link MobSpawnerAbstract}. - */ - private static class NotchianBaseSpawner { - private static Method iMethod, hMethod; - - static { - try { - hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); - hMethod.setAccessible(true); - - iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); - iMethod.setAccessible(true); - } catch (NoSuchMethodException ex) { - Utils.logException(null, ex); - } - } - - static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { - Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); - - return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); - } - - /** - * This method calls {@link MobSpawnerAbstract#h()} using Reflections. - */ - static boolean isNearPlayer(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { - return (boolean) hMethod.invoke(spawner); - } - - /** - * This method is based on {@link MobSpawnerAbstract#c()}. - * - * @return false if the spawner is not inactive, true otherwise - */ - static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { - if (isNearPlayer(spawner)) return false; - - BlockPosition blockposition = spawner.b(); - - if (spawner.a().isClientSide) { - double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); - double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); - double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); - - spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d0, d1, d2, 0D, 0D, 0D); - spawner.a().addParticle(EnumParticle.FLAME, d0, d1, d2, 0D, 0D, 0D); - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - } - - double spawnerD = (double) ReflectionUtils.getFieldValue(spawner, "d"); - - ReflectionUtils.setFieldValue(spawner, "e", spawnerD); - ReflectionUtils.setFieldValue(spawner, "d", (spawnerD + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); - } else { - if (spawner.spawnDelay == -1) { - delay(spawner); - } - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - return true; - } - - boolean flag = false; - int i = 0; - - int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); - int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); - int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); - MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); - - while (true) { - if (i >= spawnCount) { - if (flag) { - delay(spawner); - } - break; - } - - NBTTagCompound nbttagcompound = spawnData.b(); - NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); - net.minecraft.server.v1_11_R1.World world = spawner.a(); - int j = nbttaglist.size(); - double d3 = j >= 1 ? nbttaglist.e(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; - double d4 = j >= 2 ? nbttaglist.e(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); - double d5 = j >= 3 ? nbttaglist.e(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; - Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); - if (entity == null) { - return true; - } - - int k = world.a(entity.getClass(), (new AxisAlignedBB( - blockposition.getX(), - blockposition.getY(), - blockposition.getZ(), - blockposition.getX() + 1, - blockposition.getY() + 1, - blockposition.getZ() + 1)) - .g(spawnRange)).size(); - if (k >= maxNearbyEntities) { - delay(spawner); - return true; - } - - EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; - entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360.0F, 0.0F); - if (entityinsentient == null || entityinsentient.cM() && entityinsentient.canSpawn()) { - if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { - ((EntityInsentient) entity).prepare(world.D(new BlockPosition(entity)), null); - } - - if (entity.world.spigotConfig.nerfSpawnerMobs) { - entity.fromMobSpawner = true; - } - - if (!CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { - ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); - world.triggerEffect(2004, blockposition, 0); - - if (entityinsentient != null) { - entityinsentient.doSpawnEffect(); - } - - flag = true; - } - } - - ++i; - } - } - - return true; - } - - /** - * This method calls {@link MobSpawnerAbstract#i()} using Reflections. - */ - static void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { - iMethod.invoke(spawner); - } - } -} diff --git a/modules/nms/epicanchors-v1_12_R1/pom.xml b/modules/nms/epicanchors-v1_12_R1/pom.xml deleted file mode 100644 index d003f47..0000000 --- a/modules/nms/epicanchors-v1_12_R1/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - 4.0.0 - - - com.songoda - EpicAnchors - 2.0.0-ALPHA - ../../../pom.xml - - jar - epicanchors-v1_12_R1 - - - - com.songoda - epicanchors-api - ${project.version} - - - - org.spigotmc - spigot-api - 1.12.2-R0.1-SNAPSHOT - provided - - - - org.spigotmc - spigot - 1.12.2 - provided - - - diff --git a/modules/nms/epicanchors-v1_12_R1/src/main/java/epicanchors/nms/v1_12_R1.java b/modules/nms/epicanchors-v1_12_R1/src/main/java/epicanchors/nms/v1_12_R1.java deleted file mode 100644 index 3133a4f..0000000 --- a/modules/nms/epicanchors-v1_12_R1/src/main/java/epicanchors/nms/v1_12_R1.java +++ /dev/null @@ -1,266 +0,0 @@ -package epicanchors.nms; - -import com.songoda.epicanchors.AnchorNMS; -import com.songoda.epicanchors.utils.ReflectionUtils; -import com.songoda.epicanchors.utils.Utils; -import net.minecraft.server.v1_12_R1.AxisAlignedBB; -import net.minecraft.server.v1_12_R1.Block; -import net.minecraft.server.v1_12_R1.BlockPosition; -import net.minecraft.server.v1_12_R1.ChunkRegionLoader; -import net.minecraft.server.v1_12_R1.ChunkSection; -import net.minecraft.server.v1_12_R1.Entity; -import net.minecraft.server.v1_12_R1.EntityInsentient; -import net.minecraft.server.v1_12_R1.EnumParticle; -import net.minecraft.server.v1_12_R1.IBlockData; -import net.minecraft.server.v1_12_R1.MobSpawnerAbstract; -import net.minecraft.server.v1_12_R1.MobSpawnerData; -import net.minecraft.server.v1_12_R1.NBTTagCompound; -import net.minecraft.server.v1_12_R1.NBTTagList; -import net.minecraft.server.v1_12_R1.WorldServer; -import org.bukkit.Chunk; -import org.bukkit.World; -import org.bukkit.block.BlockState; -import org.bukkit.block.CreatureSpawner; -import org.bukkit.craftbukkit.v1_12_R1.CraftChunk; -import org.bukkit.craftbukkit.v1_12_R1.block.CraftCreatureSpawner; -import org.bukkit.craftbukkit.v1_12_R1.event.CraftEventFactory; -import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.plugin.java.JavaPlugin; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class v1_12_R1 extends AnchorNMS { - @SuppressWarnings("unused") - public v1_12_R1(JavaPlugin plugin) { - super(plugin); - } - - @Override - public boolean loadAnchoredChunk(Chunk chunk) { - return chunk.load(); - } - - @Override - public boolean unloadAnchoredChunk(Chunk chunk) { - return chunk.unload(); - } - - @Override - public void tickInactiveSpawners(Chunk chunk, int amount) { - if (amount <= 0) return; - - try { - for (BlockState tileEntity : chunk.getTileEntities()) { - if (tileEntity instanceof CreatureSpawner) { - MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); - - for (int i = 0; i < amount; ++i) { - if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { - break; // Spawner not inactive - } - } - } - } - } catch (Exception ex) { - Utils.logException(super.plugin, ex); - } - } - - @Override - public void doRandomTick(Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { - NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); - } - - @Override - public int getRandomTickSpeed(World world) { - return Helper.getRandomTickSpeedLegacy(world); - } - - /** - * This class contains some modified methods from {@link WorldServer}. - */ - private static class NotchianServerLevel { - /** - * Method is based on {@link WorldServer#j()}. - */ - static void randomTickChunk(net.minecraft.server.v1_12_R1.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { - if (tickAmount > 0) { - int j = chunk.locX * 16; - int k = chunk.locZ * 16; - - for (ChunkSection chunksection : chunk.getSections()) { - if (chunksection != net.minecraft.server.v1_12_R1.Chunk.a && chunksection.shouldTick()) { - for (int k1 = 0; k1 < tickAmount; ++k1) { - int worldL = (int) ReflectionUtils.getFieldValue(chunk.world, "l"); - worldL = worldL * 3 + 1013904223; - ReflectionUtils.setFieldValue(chunk.world, "l", worldL); - - int l1 = worldL >> 2; - int i2 = l1 & 15; - int j2 = l1 >> 8 & 15; - int k2 = l1 >> 16 & 15; - - IBlockData iblockdata = chunksection.getType(i2, k2, j2); - Block block = iblockdata.getBlock(); - - if (block.isTicking()) { - block.a(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), iblockdata, chunk.world.random); - } - } - } - } - } - } - } - - /** - * This class contains some modified methods from {@link MobSpawnerAbstract}. - */ - private static class NotchianBaseSpawner { - private static Method iMethod; - - static { - try { - iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); - iMethod.setAccessible(true); - } catch (NoSuchMethodException ex) { - Utils.logException(null, ex); - } - } - - static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { - Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); - - return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); - } - - /** - * This method is based on {@link MobSpawnerAbstract#h()}. - */ - static boolean isNearPlayer(MobSpawnerAbstract spawner) { - BlockPosition blockposition = spawner.b(); - - return spawner.a().isPlayerNearby( - (double) blockposition.getX() + 0.5D, - (double) blockposition.getY() + 0.5D, - (double) blockposition.getZ() + 0.5D, - spawner.requiredPlayerRange); - } - - /** - * This method is based on {@link MobSpawnerAbstract#c()}. - * - * @return false if the spawner is not inactive, true otherwise - */ - static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { - if (isNearPlayer(spawner)) return false; - - BlockPosition blockposition = spawner.b(); - - if (spawner.a().isClientSide) { - double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); - double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); - double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); - spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d0, d1, d2, 0.0D, 0.0D, 0.0D); - spawner.a().addParticle(EnumParticle.FLAME, d0, d1, d2, 0.0D, 0.0D, 0.0D); - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - } - - double spawnerD = (double) ReflectionUtils.getFieldValue(spawner, "d"); - - ReflectionUtils.setFieldValue(spawner, "e", spawnerD); - ReflectionUtils.setFieldValue(spawner, "d", (spawnerD + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); - } else { - if (spawner.spawnDelay == -1) { - delay(spawner); - } - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - return true; - } - - boolean flag = false; - int i = 0; - - MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); - - while (true) { - if (i >= spawner.spawnCount) { - if (flag) { - delay(spawner); - } - break; - } - - NBTTagCompound nbttagcompound = spawnData.b(); - NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); - - net.minecraft.server.v1_12_R1.World world = spawner.a(); - - int j = nbttaglist.size(); - double d3 = j >= 1 ? nbttaglist.f(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; - double d4 = j >= 2 ? nbttaglist.f(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); - double d5 = j >= 3 ? nbttaglist.f(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; - - Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); - - if (entity == null) { - return true; - } - - int k = world.a(entity.getClass(), (new AxisAlignedBB( - blockposition.getX(), - blockposition.getY(), - blockposition.getZ(), - blockposition.getX() + 1, - blockposition.getY() + 1, - blockposition.getZ() + 1)) - .g(spawner.spawnRange)).size(); - - if (k >= spawner.maxNearbyEntities) { - delay(spawner); - return true; - } - - EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; - entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360.0F, 0.0F); - - if (entityinsentient == null || entityinsentient.P() && entityinsentient.canSpawn()) { - if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { - ((EntityInsentient) entity).prepare(world.D(new BlockPosition(entity)), null); - } - - if (entity.world.spigotConfig.nerfSpawnerMobs) { - entity.fromMobSpawner = true; - } - - if (!CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { - ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); - world.triggerEffect(2004, blockposition, 0); - - if (entityinsentient != null) { - entityinsentient.doSpawnEffect(); - } - - flag = true; - } - } - - ++i; - } - } - - return true; - } - - /** - * This method calls {@link MobSpawnerAbstract#i()} using Reflections. - */ - static void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { - iMethod.invoke(spawner); - } - } -} diff --git a/modules/nms/epicanchors-v1_13_R1/pom.xml b/modules/nms/epicanchors-v1_13_R1/pom.xml deleted file mode 100644 index bf7b4e9..0000000 --- a/modules/nms/epicanchors-v1_13_R1/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - 4.0.0 - - - com.songoda - EpicAnchors - 2.0.0-ALPHA - ../../../pom.xml - - jar - epicanchors-v1_13_R1 - - - - com.songoda - epicanchors-api - ${project.version} - - - - org.spigotmc - spigot-api - 1.13-R0.1-SNAPSHOT - provided - - - - org.spigotmc - spigot - 1.13 - provided - - - diff --git a/modules/nms/epicanchors-v1_13_R1/src/main/java/epicanchors/nms/v1_13_R1.java b/modules/nms/epicanchors-v1_13_R1/src/main/java/epicanchors/nms/v1_13_R1.java deleted file mode 100644 index e9df416..0000000 --- a/modules/nms/epicanchors-v1_13_R1/src/main/java/epicanchors/nms/v1_13_R1.java +++ /dev/null @@ -1,282 +0,0 @@ -package epicanchors.nms; - -import com.songoda.epicanchors.AnchorNMS; -import com.songoda.epicanchors.utils.ReflectionUtils; -import com.songoda.epicanchors.utils.Utils; -import net.minecraft.server.v1_13_R1.AxisAlignedBB; -import net.minecraft.server.v1_13_R1.BlockPosition; -import net.minecraft.server.v1_13_R1.ChunkRegionLoader; -import net.minecraft.server.v1_13_R1.ChunkSection; -import net.minecraft.server.v1_13_R1.Entity; -import net.minecraft.server.v1_13_R1.EntityInsentient; -import net.minecraft.server.v1_13_R1.Fluid; -import net.minecraft.server.v1_13_R1.IBlockData; -import net.minecraft.server.v1_13_R1.MobSpawnerAbstract; -import net.minecraft.server.v1_13_R1.MobSpawnerData; -import net.minecraft.server.v1_13_R1.NBTTagCompound; -import net.minecraft.server.v1_13_R1.NBTTagList; -import net.minecraft.server.v1_13_R1.Particles; -import net.minecraft.server.v1_13_R1.WorldServer; -import org.bukkit.Chunk; -import org.bukkit.GameRule; -import org.bukkit.World; -import org.bukkit.block.BlockState; -import org.bukkit.block.CreatureSpawner; -import org.bukkit.craftbukkit.v1_13_R1.CraftChunk; -import org.bukkit.craftbukkit.v1_13_R1.block.CraftCreatureSpawner; -import org.bukkit.craftbukkit.v1_13_R1.event.CraftEventFactory; -import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.plugin.java.JavaPlugin; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class v1_13_R1 extends AnchorNMS { - @SuppressWarnings("unused") - public v1_13_R1(JavaPlugin plugin) { - super(plugin); - } - - @Override - public boolean loadAnchoredChunk(Chunk chunk) { - return chunk.load(); - } - - @Override - public boolean unloadAnchoredChunk(Chunk chunk) { - return chunk.unload(); - } - - @Override - public void tickInactiveSpawners(Chunk chunk, int amount) { - if (amount <= 0) return; - - try { - for (BlockState tileEntity : chunk.getTileEntities()) { - if (tileEntity instanceof CreatureSpawner) { - MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); - - for (int i = 0; i < amount; ++i) { - if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { - break; // Spawner not inactive - } - } - } - } - } catch (Exception ex) { - Utils.logException(super.plugin, ex); - } - } - - @Override - public void doRandomTick(Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { - NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); - } - - @Override - public int getRandomTickSpeed(World world) { - Integer result = world.getGameRuleValue(GameRule.RANDOM_TICK_SPEED); - - if (result == null) { - result = world.getGameRuleDefault(GameRule.RANDOM_TICK_SPEED); - } - - return result == null ? 3 : result; - } - - /** - * This class contains some modified methods from {@link WorldServer} - * which originally (vanilla server) goes by the name ServerLevel. - */ - private static class NotchianServerLevel { - /** - * Method is based on {@link WorldServer#l()}. - */ - static void randomTickChunk(net.minecraft.server.v1_13_R1.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { - if (tickAmount > 0) { - int j = chunk.locX * 16; - int k = chunk.locZ * 16; - - for (ChunkSection chunksection : chunk.getSections()) { - if (chunksection != net.minecraft.server.v1_13_R1.Chunk.a && chunksection.b()) { - for (int i = 0; i < tickAmount; ++i) { - int worldM = (int) ReflectionUtils.getFieldValue(chunk.world, "m"); - worldM = worldM * 3 + 1013904223; - ReflectionUtils.setFieldValue(chunk.world, "m", worldM); - - int l1 = worldM >> 2; - int i2 = l1 & 15; - int j2 = l1 >> 8 & 15; - int k2 = l1 >> 16 & 15; - - IBlockData iblockdata = chunksection.getType(i2, k2, j2); - Fluid fluid = chunksection.b(i2, k2, j2); - - if (iblockdata.t()) { - iblockdata.b(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), chunk.world.random); - } - - if (fluid.h()) { - fluid.b(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), chunk.world.random); - } - } - } - } - } - } - } - - /** - * This class contains some modified methods from {@link MobSpawnerAbstract} - * which originally (vanilla server) goes by the name BaseSpawner. - */ - private static class NotchianBaseSpawner { - private static Method iMethod; - - static { - try { - iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); - iMethod.setAccessible(true); - } catch (NoSuchMethodException ex) { - Utils.logException(null, ex); - } - } - - static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { - Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); - - return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); - } - - /** - * This method is based on {@link MobSpawnerAbstract#h()}. - */ - static boolean isNearPlayer(MobSpawnerAbstract spawner) { - BlockPosition blockposition = spawner.b(); - - return spawner.a().isPlayerNearby( - (double) blockposition.getX() + .5D, - (double) blockposition.getY() + .5D, - (double) blockposition.getZ() + .5D, - spawner.requiredPlayerRange); - } - - /** - * This method is based on {@link MobSpawnerAbstract#c()}. - * - * @return false if the spawner is not inactive, true otherwise - */ - static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { - if (isNearPlayer(spawner)) return false; - - BlockPosition blockposition = spawner.b(); - - if (spawner.a().isClientSide) { - double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); - double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); - double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); - - spawner.a().addParticle(Particles.M, d0, d1, d2, 0D, 0D, 0D); - spawner.a().addParticle(Particles.y, d0, d1, d2, 0D, 0D, 0D); - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - } - - double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); - - ReflectionUtils.setFieldValue(spawner, "f", spawnerE); - ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); - } else { - if (spawner.spawnDelay == -1) { - delay(spawner); - } - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - return true; - } - - boolean flag = false; - int i = 0; - - MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); - - while (true) { - if (i >= spawner.spawnCount) { - if (flag) { - delay(spawner); - } - - break; - } - - NBTTagCompound nbttagcompound = spawnData.b(); - NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); - - net.minecraft.server.v1_13_R1.World world = spawner.a(); - - int j = nbttaglist.size(); - double d3 = j >= 1 ? nbttaglist.k(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; - double d4 = j >= 2 ? nbttaglist.k(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); - double d5 = j >= 3 ? nbttaglist.k(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; - - Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); - - if (entity == null) { - delay(spawner); - return true; - } - - int k = world.a(entity.getClass(), (new AxisAlignedBB(blockposition.getX(), - blockposition.getY(), - blockposition.getZ(), - blockposition.getX() + 1, - blockposition.getY() + 1, - blockposition.getZ() + 1)) - .g(spawner.spawnRange)).size(); - - if (k >= spawner.maxNearbyEntities) { - delay(spawner); - return true; - } - - EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; - entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360F, 0F); - - if (entityinsentient == null || entityinsentient.M() && entityinsentient.canSpawn()) { - if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { - ((EntityInsentient) entity).prepare(world.getDamageScaler(new BlockPosition(entity)), null, null); - } - - if (entity.world.spigotConfig.nerfSpawnerMobs) { - entity.fromMobSpawner = true; - } - - if (!CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { - ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); - world.triggerEffect(2004, blockposition, 0); - - if (entityinsentient != null) { - entityinsentient.doSpawnEffect(); - } - - flag = true; - } - } - - ++i; - } - } - - return true; - } - - /** - * This method calls {@link MobSpawnerAbstract#i()} using Reflections. - */ - static void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { - iMethod.invoke(spawner); - } - } -} diff --git a/modules/nms/epicanchors-v1_13_R2/pom.xml b/modules/nms/epicanchors-v1_13_R2/pom.xml deleted file mode 100644 index b70e26b..0000000 --- a/modules/nms/epicanchors-v1_13_R2/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - 4.0.0 - - - com.songoda - EpicAnchors - 2.0.0-ALPHA - ../../../pom.xml - - jar - epicanchors-v1_13_R2 - - - - com.songoda - epicanchors-api - ${project.version} - - - - org.spigotmc - spigot-api - 1.13.2-R0.1-SNAPSHOT - provided - - - - org.spigotmc - spigot - 1.13.2 - provided - - - diff --git a/modules/nms/epicanchors-v1_13_R2/src/main/java/epicanchors/nms/v1_13_R2.java b/modules/nms/epicanchors-v1_13_R2/src/main/java/epicanchors/nms/v1_13_R2.java deleted file mode 100644 index 5a7ab7f..0000000 --- a/modules/nms/epicanchors-v1_13_R2/src/main/java/epicanchors/nms/v1_13_R2.java +++ /dev/null @@ -1,294 +0,0 @@ -package epicanchors.nms; - -import com.songoda.epicanchors.AnchorNMS; -import com.songoda.epicanchors.utils.ReflectionUtils; -import com.songoda.epicanchors.utils.Utils; -import net.minecraft.server.v1_13_R2.AxisAlignedBB; -import net.minecraft.server.v1_13_R2.BlockPosition; -import net.minecraft.server.v1_13_R2.ChunkRegionLoader; -import net.minecraft.server.v1_13_R2.ChunkSection; -import net.minecraft.server.v1_13_R2.Entity; -import net.minecraft.server.v1_13_R2.EntityInsentient; -import net.minecraft.server.v1_13_R2.Fluid; -import net.minecraft.server.v1_13_R2.IBlockData; -import net.minecraft.server.v1_13_R2.MobSpawnerAbstract; -import net.minecraft.server.v1_13_R2.MobSpawnerData; -import net.minecraft.server.v1_13_R2.NBTTagCompound; -import net.minecraft.server.v1_13_R2.NBTTagList; -import net.minecraft.server.v1_13_R2.Particles; -import net.minecraft.server.v1_13_R2.WorldServer; -import org.bukkit.Chunk; -import org.bukkit.GameRule; -import org.bukkit.World; -import org.bukkit.block.BlockState; -import org.bukkit.block.CreatureSpawner; -import org.bukkit.craftbukkit.v1_13_R2.CraftChunk; -import org.bukkit.craftbukkit.v1_13_R2.block.CraftCreatureSpawner; -import org.bukkit.craftbukkit.v1_13_R2.event.CraftEventFactory; -import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.plugin.java.JavaPlugin; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Iterator; - -public class v1_13_R2 extends AnchorNMS { - @SuppressWarnings("unused") - public v1_13_R2(JavaPlugin plugin) { - super(plugin); - } - - @Override - public boolean loadAnchoredChunk(Chunk chunk) { - return chunk.load(); - } - - @Override - public boolean unloadAnchoredChunk(Chunk chunk) { - return chunk.unload(); - } - - @Override - public void tickInactiveSpawners(Chunk chunk, int amount) { - if (amount <= 0) return; - - try { - for (BlockState tileEntity : chunk.getTileEntities()) { - if (tileEntity instanceof CreatureSpawner) { - MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); - - for (int i = 0; i < amount; ++i) { - if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { - break; // Spawner not inactive - } - } - } - } - } catch (Exception ex) { - Utils.logException(super.plugin, ex); - } - } - - @Override - public void doRandomTick(Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { - NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); - } - - @Override - public int getRandomTickSpeed(World world) { - Integer result = world.getGameRuleValue(GameRule.RANDOM_TICK_SPEED); - - if (result == null) { - result = world.getGameRuleDefault(GameRule.RANDOM_TICK_SPEED); - } - - return result == null ? 3 : result; - } - - /** - * This class contains some modified methods from {@link WorldServer} - * which originally (vanilla server) goes by the name ServerLevel. - */ - private static class NotchianServerLevel { - /** - * Method is based on {@link WorldServer#n_()}. - */ - static void randomTickChunk(net.minecraft.server.v1_13_R2.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { - if (tickAmount > 0) { - int j = chunk.locX * 16; - int k = chunk.locZ * 16; - - chunk.world.methodProfiler.enter("tickBlocks"); - for (ChunkSection chunksection : chunk.getSections()) { - if (chunksection != net.minecraft.server.v1_13_R2.Chunk.a && chunksection.b()) { - for (int k1 = 0; k1 < tickAmount; ++k1) { - int worldM = (int) ReflectionUtils.getFieldValue(chunk.world, "m"); - worldM = worldM * 3 + 1013904223; - ReflectionUtils.setFieldValue(chunk.world, "m", worldM); - - int l1 = worldM >> 2; - int i2 = l1 & 15; - int j2 = l1 >> 8 & 15; - int k2 = l1 >> 16 & 15; - - IBlockData iblockdata = chunksection.getType(i2, k2, j2); - Fluid fluid = chunksection.b(i2, k2, j2); - - chunk.world.methodProfiler.enter("randomTick"); - - if (iblockdata.t()) { - iblockdata.b(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), chunk.world.random); - } - - if (fluid.h()) { - fluid.b(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), chunk.world.random); - } - - chunk.world.methodProfiler.exit(); - } - } - } - - chunk.world.methodProfiler.exit(); - } - } - } - - /** - * This class contains some modified methods from {@link MobSpawnerAbstract} - * which originally (vanilla server) goes by the name BaseSpawner. - */ - private static class NotchianBaseSpawner { - private static Method iMethod; - - static { - try { - iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); - iMethod.setAccessible(true); - } catch (NoSuchMethodException ex) { - Utils.logException(null, ex); - } - } - - static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { - Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); - - return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); - } - - /** - * This method is based on {@link MobSpawnerAbstract#h()}. - */ - static boolean isNearPlayer(MobSpawnerAbstract spawner) { - BlockPosition blockposition = spawner.b(); - - return spawner.a().b( - (double) blockposition.getX() + .5D, - (double) blockposition.getY() + .5D, - (double) blockposition.getZ() + .5D, - spawner.requiredPlayerRange); - } - - /** - * This method is based on {@link MobSpawnerAbstract#c()}. - * - * @return false if the spawner is not inactive, true otherwise - */ - static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { - if (isNearPlayer(spawner)) return false; - - BlockPosition blockposition = spawner.b(); - - if (spawner.a().isClientSide) { - double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); - double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); - double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); - spawner.a().addParticle(Particles.M, d0, d1, d2, 0.0D, 0.0D, 0.0D); - spawner.a().addParticle(Particles.y, d0, d1, d2, 0.0D, 0.0D, 0.0D); - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - } - - double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); - - ReflectionUtils.setFieldValue(spawner, "f", spawnerE); - ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); - } else { - if (spawner.spawnDelay == -1) { - delay(spawner); - } - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - return true; - } - - boolean flag = false; - int i = 0; - - MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); - - while (true) { - if (i >= spawner.spawnCount) { - if (flag) { - delay(spawner); - } - - break; - } - - NBTTagCompound nbttagcompound = spawnData.b(); - NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); - net.minecraft.server.v1_13_R2.World world = spawner.a(); - int j = nbttaglist.size(); - double d3 = j >= 1 ? nbttaglist.k(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; - double d4 = j >= 2 ? nbttaglist.k(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); - double d5 = j >= 3 ? nbttaglist.k(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; - Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); - if (entity == null) { - delay(spawner); - return true; - } - - int k = world.a(entity.getClass(), (new AxisAlignedBB( - blockposition.getX(), - blockposition.getY(), - blockposition.getZ(), - blockposition.getX() + 1, - blockposition.getY() + 1, - blockposition.getZ() + 1)) - .g(spawner.spawnRange)).size(); - - if (k >= spawner.maxNearbyEntities) { - delay(spawner); - return true; - } - - EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; - entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360.0F, 0.0F); - if (entityinsentient == null || entityinsentient.a(world, true) && entityinsentient.canSpawn()) { - if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { - ((EntityInsentient) entity).prepare(world.getDamageScaler(new BlockPosition(entity)), null, null); - } - - if (entity.world.spigotConfig.nerfSpawnerMobs) { - entity.fromMobSpawner = true; - } - - if (CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { - Entity vehicle = entity.getVehicle(); - if (vehicle != null) { - vehicle.dead = true; - } - - Entity passenger; - for (Iterator var19 = entity.getAllPassengers().iterator(); var19.hasNext(); passenger.dead = true) { - passenger = var19.next(); - } - } else { - ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); - world.triggerEffect(2004, blockposition, 0); - - if (entityinsentient != null) { - entityinsentient.doSpawnEffect(); - } - - flag = true; - } - } - - ++i; - } - } - - return true; - } - - /** - * This method calls {@link MobSpawnerAbstract#i()} using Reflections. - */ - static void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { - iMethod.invoke(spawner); - } - } -} diff --git a/modules/nms/epicanchors-v1_14_R1/pom.xml b/modules/nms/epicanchors-v1_14_R1/pom.xml deleted file mode 100644 index c8ecdea..0000000 --- a/modules/nms/epicanchors-v1_14_R1/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - 4.0.0 - - - com.songoda - EpicAnchors - 2.0.0-ALPHA - ../../../pom.xml - - jar - epicanchors-v1_14_R1 - - - - com.songoda - epicanchors-api - ${project.version} - - - - org.spigotmc - spigot-api - 1.14.4-R0.1-SNAPSHOT - provided - - - - org.spigotmc - spigot - 1.14.4 - provided - - - diff --git a/modules/nms/epicanchors-v1_14_R1/src/main/java/epicanchors/nms/v1_14_R1.java b/modules/nms/epicanchors-v1_14_R1/src/main/java/epicanchors/nms/v1_14_R1.java deleted file mode 100644 index 197a985..0000000 --- a/modules/nms/epicanchors-v1_14_R1/src/main/java/epicanchors/nms/v1_14_R1.java +++ /dev/null @@ -1,304 +0,0 @@ -package epicanchors.nms; - -import com.songoda.epicanchors.AnchorNMS; -import com.songoda.epicanchors.utils.ReflectionUtils; -import com.songoda.epicanchors.utils.Utils; -import net.minecraft.server.v1_14_R1.*; -import org.bukkit.Chunk; -import org.bukkit.GameRule; -import org.bukkit.World; -import org.bukkit.block.BlockState; -import org.bukkit.block.CreatureSpawner; -import org.bukkit.craftbukkit.v1_14_R1.CraftChunk; -import org.bukkit.craftbukkit.v1_14_R1.block.CraftCreatureSpawner; -import org.bukkit.craftbukkit.v1_14_R1.event.CraftEventFactory; -import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.plugin.java.JavaPlugin; - -import java.util.Iterator; -import java.util.Optional; - -public class v1_14_R1 extends AnchorNMS { - @SuppressWarnings("unused") - public v1_14_R1(JavaPlugin plugin) { - super(plugin); - } - - @Override - public boolean loadAnchoredChunk(Chunk chunk) { - return chunk.load(); - } - - @Override - public boolean unloadAnchoredChunk(Chunk chunk) { - return chunk.unload(); - } - - @Override - public void tickInactiveSpawners(Chunk chunk, int amount) { - if (amount <= 0) return; - - try { - for (BlockState tileEntity : chunk.getTileEntities()) { - if (tileEntity instanceof CreatureSpawner) { - MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); - - for (int i = 0; i < amount; ++i) { - if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { - break; // Spawner not inactive - } - } - } - } - } catch (Exception ex) { - Utils.logException(super.plugin, ex); - } - } - - @Override - public void doRandomTick(Chunk chunk, int tickAmount) { - NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); - } - - @Override - public int getRandomTickSpeed(World world) { - Integer result = world.getGameRuleValue(GameRule.RANDOM_TICK_SPEED); - - if (result == null) { - result = world.getGameRuleDefault(GameRule.RANDOM_TICK_SPEED); - } - - return result == null ? 3 : result; - } - - /** - * This class contains some modified methods from {@link WorldServer} - * which originally (vanilla server) goes by the name ServerLevel. - */ - private static class NotchianServerLevel { - /** - * Method is based on {@link WorldServer#a(net.minecraft.server.v1_14_R1.Chunk, int)}. - */ - static void randomTickChunk(net.minecraft.server.v1_14_R1.Chunk chunk, int tickAmount) { - if (tickAmount > 0) { - ChunkCoordIntPair chunkcoordintpair = chunk.getPos(); - int j = chunkcoordintpair.d(); - int k = chunkcoordintpair.e(); - - GameProfilerFiller profiler = chunk.world.getMethodProfiler(); - - profiler.enter("tickBlocks"); - for (ChunkSection chunksection : chunk.getSections()) { - if (chunksection != net.minecraft.server.v1_14_R1.Chunk.a && chunksection.d()) { - int j1 = chunksection.getYPosition(); - - for (int i = 0; i < tickAmount; ++i) { - BlockPosition blockposition2 = chunk.world.a(j, j1, k, 15); - profiler.enter("randomTick"); - IBlockData iblockdata = chunksection.getType(blockposition2.getX() - j, blockposition2.getY() - j1, blockposition2.getZ() - k); - - if (iblockdata.q()) { - iblockdata.b(chunk.world, blockposition2, chunk.world.random); - } - - Fluid fluid = iblockdata.p(); - if (fluid.h()) { - fluid.b(chunk.world, blockposition2, chunk.world.random); - } - - profiler.exit(); - } - } - } - - profiler.exit(); - } - } - } - - /** - * This class contains some modified methods from {@link MobSpawnerAbstract} - * which originally (vanilla server) goes by the name BaseSpawner. - */ - private static class NotchianBaseSpawner { - static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { - Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); - - return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); - } - - /** - * This method is based on {@link MobSpawnerAbstract#h()}. - */ - static boolean isNearPlayer(MobSpawnerAbstract spawner) { - BlockPosition blockposition = spawner.b(); - - return spawner.a().isPlayerNearby( - (double) blockposition.getX() + .5D, - (double) blockposition.getY() + .5D, - (double) blockposition.getZ() + .5D, - spawner.requiredPlayerRange); - } - - /** - * This method is based on {@link MobSpawnerAbstract#c()}. - * - * @return false if the spawner is not inactive, true otherwise - */ - static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException { - if (isNearPlayer(spawner)) return false; - - net.minecraft.server.v1_14_R1.World world = spawner.a(); - BlockPosition blockposition = spawner.b(); - - if (world.isClientSide) { - double d0 = (float) blockposition.getX() + world.random.nextFloat(); - double d1 = (float) blockposition.getY() + world.random.nextFloat(); - double d2 = (float) blockposition.getZ() + world.random.nextFloat(); - - world.addParticle(Particles.SMOKE, d0, d1, d2, 0D, 0D, 0D); - world.addParticle(Particles.FLAME, d0, d1, d2, 0D, 0D, 0D); - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - } - - double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); - ReflectionUtils.setFieldValue(spawner, "f", spawnerE); - ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); - } else { - if (spawner.spawnDelay == -1) { - delay(spawner); - } - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - return true; - } - - boolean flag = false; - int i = 0; - - while (true) { - if (i >= spawner.spawnCount) { - if (flag) { - delay(spawner); - } - - break; - } - - NBTTagCompound nbttagcompound = spawner.spawnData.getEntity(); - Optional> optional = EntityTypes.a(nbttagcompound); - if (!optional.isPresent()) { - delay(spawner); - return true; - } - - NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); - int j = nbttaglist.size(); - double d3 = j >= 1 ? nbttaglist.h(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; - double d4 = j >= 2 ? nbttaglist.h(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); - double d5 = j >= 3 ? nbttaglist.h(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; - if (world.c(optional.get().a(d3, d4, d5)) && EntityPositionTypes.a(optional.get(), world.getMinecraftWorld(), EnumMobSpawn.SPAWNER, new BlockPosition(d3, d4, d5), world.getRandom())) { - label112: - { - Entity entity = EntityTypes.a(nbttagcompound, world, (entity1) -> { - entity1.setPositionRotation(d3, d4, d5, entity1.yaw, entity1.pitch); - return entity1; - }); - if (entity == null) { - delay(spawner); - return true; - } - - int k = world.a(entity.getClass(), (new AxisAlignedBB( - blockposition.getX(), - blockposition.getY(), - blockposition.getZ(), - blockposition.getX() + 1, - blockposition.getY() + 1, - blockposition.getZ() + 1)) - .g(spawner.spawnRange)).size(); - - if (k >= spawner.maxNearbyEntities) { - delay(spawner); - return true; - } - - entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360F, 0F); - if (entity instanceof EntityInsentient) { - EntityInsentient entityinsentient = (EntityInsentient) entity; - if (!entityinsentient.a(world, EnumMobSpawn.SPAWNER) || !entityinsentient.a(world)) { - break label112; - } - - if (spawner.spawnData.getEntity().d() == 1 && spawner.spawnData.getEntity().hasKeyOfType("id", 8)) { - ((EntityInsentient) entity).prepare(world, world.getDamageScaler(new BlockPosition(entity)), EnumMobSpawn.SPAWNER, null, null); - } - } - - if (entity.world.spigotConfig.nerfSpawnerMobs) { - entity.fromMobSpawner = true; - } - - if (CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { - Entity vehicle = entity.getVehicle(); - if (vehicle != null) { - vehicle.dead = true; - } - - Entity passenger; - for (Iterator var19 = entity.getAllPassengers().iterator(); var19.hasNext(); passenger.dead = true) { - passenger = var19.next(); - } - } else { - addWithPassengers(spawner, entity); - world.triggerEffect(2004, blockposition, 0); - - if (entity instanceof EntityInsentient) { - ((EntityInsentient) entity).doSpawnEffect(); - } - - flag = true; - } - } - } - - ++i; - } - } - - return true; - } - - /** - * This method is based on {@link MobSpawnerAbstract#i()}. - */ - static void delay(MobSpawnerAbstract spawner) { - if (spawner.maxSpawnDelay <= spawner.minSpawnDelay) { - spawner.spawnDelay = spawner.minSpawnDelay; - } else { - int i = spawner.maxSpawnDelay - spawner.minSpawnDelay; - spawner.spawnDelay = spawner.minSpawnDelay + spawner.a().random.nextInt(i); - } - - if (!spawner.mobs.isEmpty()) { - spawner.setSpawnData(WeightedRandom.a(spawner.a().random, spawner.mobs)); - } - - spawner.a(1); - } - - /** - * This method is based on {@link MobSpawnerAbstract#a(Entity)}. - */ - static void addWithPassengers(MobSpawnerAbstract spawner, Entity entity) { - if (spawner.a().addEntity(entity, CreatureSpawnEvent.SpawnReason.SPAWNER)) { - for (Entity value : entity.getPassengers()) { - addWithPassengers(spawner, value); - } - } - } - } -} diff --git a/modules/nms/epicanchors-v1_15_R1/pom.xml b/modules/nms/epicanchors-v1_15_R1/pom.xml deleted file mode 100644 index 8498d5c..0000000 --- a/modules/nms/epicanchors-v1_15_R1/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - 4.0.0 - - - com.songoda - EpicAnchors - 2.0.0-ALPHA - ../../../pom.xml - - jar - epicanchors-v1_15_R1 - - - - com.songoda - epicanchors-api - ${project.version} - - - - org.spigotmc - spigot-api - 1.15.2-R0.1-SNAPSHOT - provided - - - - org.spigotmc - spigot - 1.15.2 - provided - - - diff --git a/modules/nms/epicanchors-v1_15_R1/src/main/java/epicanchors/nms/v1_15_R1.java b/modules/nms/epicanchors-v1_15_R1/src/main/java/epicanchors/nms/v1_15_R1.java deleted file mode 100644 index 51e5544..0000000 --- a/modules/nms/epicanchors-v1_15_R1/src/main/java/epicanchors/nms/v1_15_R1.java +++ /dev/null @@ -1,303 +0,0 @@ -package epicanchors.nms; - -import com.songoda.epicanchors.AnchorNMS; -import com.songoda.epicanchors.utils.ReflectionUtils; -import com.songoda.epicanchors.utils.Utils; -import net.minecraft.server.v1_15_R1.*; -import org.bukkit.Chunk; -import org.bukkit.GameRule; -import org.bukkit.World; -import org.bukkit.block.BlockState; -import org.bukkit.block.CreatureSpawner; -import org.bukkit.craftbukkit.v1_15_R1.CraftChunk; -import org.bukkit.craftbukkit.v1_15_R1.block.CraftCreatureSpawner; -import org.bukkit.craftbukkit.v1_15_R1.event.CraftEventFactory; -import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.plugin.java.JavaPlugin; - -import java.util.Iterator; -import java.util.Optional; - -public class v1_15_R1 extends AnchorNMS { - @SuppressWarnings("unused") - public v1_15_R1(JavaPlugin plugin) { - super(plugin); - } - - @Override - public boolean loadAnchoredChunk(Chunk chunk) { - return chunk.addPluginChunkTicket(super.plugin); - } - - @Override - public boolean unloadAnchoredChunk(Chunk chunk) { - chunk.removePluginChunkTicket(super.plugin); - - return chunk.unload(); - } - - @Override - public void tickInactiveSpawners(Chunk chunk, int amount) { - if (amount <= 0) return; - - try { - for (BlockState tileEntity : chunk.getTileEntities()) { - if (tileEntity instanceof CreatureSpawner) { - MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); - - for (int i = 0; i < amount; ++i) { - if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { - break; // Spawner not inactive - } - } - } - } - } catch (Exception ex) { - Utils.logException(super.plugin, ex); - } - } - - @Override - public void doRandomTick(Chunk chunk, int tickAmount) { - NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); - } - - @Override - public int getRandomTickSpeed(World world) { - Integer result = world.getGameRuleValue(GameRule.RANDOM_TICK_SPEED); - - if (result == null) { - result = world.getGameRuleDefault(GameRule.RANDOM_TICK_SPEED); - } - - return result == null ? 3 : result; - } - - /** - * This class contains some modified methods from {@link WorldServer} - * which originally (vanilla server) goes by the name ServerLevel. - */ - private static class NotchianServerLevel { - /** - * Method is based on {@link WorldServer#a(net.minecraft.server.v1_15_R1.Chunk, int)}. - */ - static void randomTickChunk(net.minecraft.server.v1_15_R1.Chunk chunk, int tickAmount) { - if (tickAmount > 0) { - ChunkCoordIntPair chunkcoordintpair = chunk.getPos(); - int j = chunkcoordintpair.d(); - int k = chunkcoordintpair.e(); - GameProfilerFiller profiler = chunk.world.getMethodProfiler(); - - profiler.enter("tickBlocks"); - - for (ChunkSection chunksection : chunk.getSections()) { - if (chunksection != net.minecraft.server.v1_15_R1.Chunk.a && chunksection.d()) { - int j1 = chunksection.getYPosition(); - - for (int k1 = 0; k1 < tickAmount; ++k1) { - BlockPosition blockposition2 = chunk.world.a(j, j1, k, 15); - profiler.enter("randomTick"); - IBlockData iblockdata = chunksection.getType(blockposition2.getX() - j, blockposition2.getY() - j1, blockposition2.getZ() - k); - - if (iblockdata.q()) { - iblockdata.b((WorldServer) chunk.world, blockposition2, chunk.world.random); - } - - Fluid fluid = iblockdata.getFluid(); - if (fluid.h()) { - fluid.b(chunk.world, blockposition2, chunk.world.random); - } - - profiler.exit(); - } - } - } - - profiler.exit(); - } - } - } - - /** - * This class contains some modified methods from {@link MobSpawnerAbstract} - * which originally (vanilla server) goes by the name BaseSpawner. - */ - private static class NotchianBaseSpawner { - static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { - Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); - - return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); - } - - /** - * This method is based on {@link MobSpawnerAbstract#h()}. - */ - static boolean isNearPlayer(MobSpawnerAbstract spawner) { - BlockPosition blockposition = spawner.b(); - - return spawner.a().isPlayerNearby( - (double) blockposition.getX() + .5D, - (double) blockposition.getY() + .5D, - (double) blockposition.getZ() + .5D, - spawner.requiredPlayerRange); - } - - /** - * This method is based on {@link MobSpawnerAbstract#c()}. - * - * @return false if the spawner is not inactive, true otherwise - */ - static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException { - if (isNearPlayer(spawner)) return false; - - net.minecraft.server.v1_15_R1.World world = spawner.a(); - BlockPosition blockposition = spawner.b(); - - if (world.isClientSide) { - double d0 = (double) blockposition.getX() + (double) world.random.nextFloat(); - double d1 = (double) blockposition.getY() + (double) world.random.nextFloat(); - double d2 = (double) blockposition.getZ() + (double) world.random.nextFloat(); - world.addParticle(Particles.SMOKE, d0, d1, d2, 0.0D, 0.0D, 0.0D); - world.addParticle(Particles.FLAME, d0, d1, d2, 0.0D, 0.0D, 0.0D); - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - } - - double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); - ReflectionUtils.setFieldValue(spawner, "f", spawnerE); - ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); - } else { - if (spawner.spawnDelay == -1) { - delay(spawner); - } - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - return true; - } - - boolean flag = false; - int i = 0; - - while (true) { - if (i >= spawner.spawnCount) { - if (flag) { - delay(spawner); - } - - break; - } - - NBTTagCompound nbttagcompound = spawner.spawnData.getEntity(); - Optional> optional = EntityTypes.a(nbttagcompound); - if (!optional.isPresent()) { - delay(spawner); - return true; - } - - NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); - int j = nbttaglist.size(); - double d3 = j >= 1 ? nbttaglist.h(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; - double d4 = j >= 2 ? nbttaglist.h(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); - double d5 = j >= 3 ? nbttaglist.h(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; - if (world.a(optional.get().a(d3, d4, d5)) && EntityPositionTypes.a(optional.get(), world.getMinecraftWorld(), EnumMobSpawn.SPAWNER, new BlockPosition(d3, d4, d5), world.getRandom())) { - label112: - { - Entity entity = EntityTypes.a(nbttagcompound, world, (entity1) -> { - entity1.setPositionRotation(d3, d4, d5, entity1.yaw, entity1.pitch); - return entity1; - }); - if (entity == null) { - delay(spawner); - return true; - } - - int k = world.a(entity.getClass(), (new AxisAlignedBB( - blockposition.getX(), - blockposition.getY(), - blockposition.getZ(), - blockposition.getX() + 1, - blockposition.getY() + 1, - blockposition.getZ() + 1)) - .g(spawner.spawnRange)).size(); - - if (k >= spawner.maxNearbyEntities) { - delay(spawner); - return true; - } - - entity.setPositionRotation(entity.locX(), entity.locY(), entity.locZ(), world.random.nextFloat() * 360F, 0F); - if (entity instanceof EntityInsentient) { - EntityInsentient entityinsentient = (EntityInsentient) entity; - if (!entityinsentient.a(world, EnumMobSpawn.SPAWNER) || !entityinsentient.a(world)) { - break label112; - } - - if (spawner.spawnData.getEntity().e() == 1 && spawner.spawnData.getEntity().hasKeyOfType("id", 8)) { - ((EntityInsentient) entity).prepare(world, world.getDamageScaler(new BlockPosition(entity)), EnumMobSpawn.SPAWNER, null, null); - } - - if (entityinsentient.world.spigotConfig.nerfSpawnerMobs) { - entityinsentient.aware = false; - } - } - - if (CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { - Entity vehicle = entity.getVehicle(); - if (vehicle != null) { - vehicle.dead = true; - } - - Entity passenger; - for (Iterator var19 = entity.getAllPassengers().iterator(); var19.hasNext(); passenger.dead = true) { - passenger = var19.next(); - } - } else { - addWithPassengers(spawner, entity); - world.triggerEffect(2004, blockposition, 0); - if (entity instanceof EntityInsentient) { - ((EntityInsentient) entity).doSpawnEffect(); - } - - flag = true; - } - } - } - - ++i; - } - } - - return true; - } - - /** - * This method is based on {@link MobSpawnerAbstract#i()}. - */ - static void delay(MobSpawnerAbstract spawner) { - if (spawner.maxSpawnDelay <= spawner.minSpawnDelay) { - spawner.spawnDelay = spawner.minSpawnDelay; - } else { - int i = spawner.maxSpawnDelay - spawner.minSpawnDelay; - spawner.spawnDelay = spawner.minSpawnDelay + spawner.a().random.nextInt(i); - } - - if (!spawner.mobs.isEmpty()) { - spawner.setSpawnData(WeightedRandom.a(spawner.a().random, spawner.mobs)); - } - - spawner.a(1); - } - - /** - * This method is based on {@link MobSpawnerAbstract#a(Entity)}. - */ - static void addWithPassengers(MobSpawnerAbstract spawner, Entity entity) { - if (spawner.a().addEntity(entity, CreatureSpawnEvent.SpawnReason.SPAWNER)) { - for (Entity entity1 : entity.getPassengers()) { - addWithPassengers(spawner, entity1); - } - } - } - } -} diff --git a/modules/nms/epicanchors-v1_16_R1/pom.xml b/modules/nms/epicanchors-v1_16_R1/pom.xml deleted file mode 100644 index 572b7d6..0000000 --- a/modules/nms/epicanchors-v1_16_R1/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - 4.0.0 - - - com.songoda - EpicAnchors - 2.0.0-ALPHA - ../../../pom.xml - - jar - epicanchors-v1_16_R1 - - - - com.songoda - epicanchors-api - ${project.version} - - - - org.spigotmc - spigot-api - 1.16.1-R0.1-SNAPSHOT - provided - - - - org.spigotmc - spigot - 1.16.1 - provided - - - diff --git a/modules/nms/epicanchors-v1_16_R1/src/main/java/epicanchors/nms/v1_16_R1.java b/modules/nms/epicanchors-v1_16_R1/src/main/java/epicanchors/nms/v1_16_R1.java deleted file mode 100644 index 3910f39..0000000 --- a/modules/nms/epicanchors-v1_16_R1/src/main/java/epicanchors/nms/v1_16_R1.java +++ /dev/null @@ -1,302 +0,0 @@ -package epicanchors.nms; - -import com.songoda.epicanchors.AnchorNMS; -import com.songoda.epicanchors.utils.ReflectionUtils; -import com.songoda.epicanchors.utils.Utils; -import net.minecraft.server.v1_16_R1.*; -import org.bukkit.Chunk; -import org.bukkit.GameRule; -import org.bukkit.World; -import org.bukkit.block.BlockState; -import org.bukkit.block.CreatureSpawner; -import org.bukkit.craftbukkit.v1_16_R1.CraftChunk; -import org.bukkit.craftbukkit.v1_16_R1.block.CraftCreatureSpawner; -import org.bukkit.craftbukkit.v1_16_R1.event.CraftEventFactory; -import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.plugin.java.JavaPlugin; - -import java.util.Iterator; -import java.util.Optional; - -public class v1_16_R1 extends AnchorNMS { - @SuppressWarnings("unused") - public v1_16_R1(JavaPlugin plugin) { - super(plugin); - } - - @Override - public boolean loadAnchoredChunk(Chunk chunk) { - return chunk.addPluginChunkTicket(super.plugin); - } - - @Override - public boolean unloadAnchoredChunk(Chunk chunk) { - chunk.removePluginChunkTicket(super.plugin); - - return chunk.unload(); - } - - @Override - public void tickInactiveSpawners(Chunk chunk, int amount) { - if (amount <= 0) return; - - try { - for (BlockState tileEntity : chunk.getTileEntities()) { - if (tileEntity instanceof CreatureSpawner) { - MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); - - for (int i = 0; i < amount; ++i) { - if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { - break; // Spawner not inactive - } - } - } - } - } catch (Exception ex) { - Utils.logException(super.plugin, ex); - } - } - - @Override - public void doRandomTick(Chunk chunk, int tickAmount) { - NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); - } - - @Override - public int getRandomTickSpeed(World world) { - Integer result = world.getGameRuleValue(GameRule.RANDOM_TICK_SPEED); - - if (result == null) { - result = world.getGameRuleDefault(GameRule.RANDOM_TICK_SPEED); - } - - return result == null ? 3 : result; - } - - /** - * This class contains some modified methods from {@link WorldServer} - * which originally (vanilla server) goes by the name ServerLevel. - */ - private static class NotchianServerLevel { - /** - * Method is based on {@link WorldServer#a(net.minecraft.server.v1_16_R1.Chunk, int)}. - */ - static void randomTickChunk(net.minecraft.server.v1_16_R1.Chunk chunk, int tickAmount) { - if (tickAmount > 0) { - ChunkCoordIntPair chunkcoordintpair = chunk.getPos(); - int j = chunkcoordintpair.d(); - int k = chunkcoordintpair.e(); - - GameProfilerFiller profiler = chunk.world.getMethodProfiler(); - - profiler.enter("tickBlocks"); - for (ChunkSection chunksection : chunk.getSections()) { - if (chunksection != net.minecraft.server.v1_16_R1.Chunk.a && chunksection.d()) { - int j1 = chunksection.getYPosition(); - - for (int k1 = 0; k1 < tickAmount; ++k1) { - BlockPosition blockposition2 = chunk.world.a(j, j1, k, 15); - profiler.enter("randomTick"); - - IBlockData iblockdata = chunksection.getType(blockposition2.getX() - j, blockposition2.getY() - j1, blockposition2.getZ() - k); - - if (iblockdata.isTicking()) { - iblockdata.b(chunk.world, blockposition2, chunk.world.random); - } - - Fluid fluid = iblockdata.getFluid(); - if (fluid.f()) { - fluid.b(chunk.world, blockposition2, chunk.world.random); - } - - profiler.exit(); - } - } - } - - profiler.exit(); - } - } - } - - /** - * This class contains some modified methods from {@link MobSpawnerAbstract} - * which originally (vanilla server) goes by the name BaseSpawner. - */ - private static class NotchianBaseSpawner { - static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { - Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); - - return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); - } - - /** - * This method is based on {@link MobSpawnerAbstract#h()}. - */ - static boolean isNearPlayer(MobSpawnerAbstract spawner) { - BlockPosition blockposition = spawner.b(); - - return spawner.a().isPlayerNearby((double) blockposition.getX() + .5D, - (double) blockposition.getY() + .5D, - (double) blockposition.getZ() + .5D, - spawner.requiredPlayerRange); - } - - /** - * This method is based on {@link MobSpawnerAbstract#c()}. - * - * @return false if the spawner is not inactive, true otherwise - */ - static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException { - if (isNearPlayer(spawner)) return false; - - net.minecraft.server.v1_16_R1.World world = spawner.a(); - BlockPosition blockposition = spawner.b(); - - if (world.isClientSide) { - double d0 = (double) blockposition.getX() + world.random.nextDouble(); - double d1 = (double) blockposition.getY() + world.random.nextDouble(); - double d2 = (double) blockposition.getZ() + world.random.nextDouble(); - world.addParticle(Particles.SMOKE, d0, d1, d2, 0.0D, 0.0D, 0.0D); - world.addParticle(Particles.FLAME, d0, d1, d2, 0.0D, 0.0D, 0.0D); - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - } - - double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); - ReflectionUtils.setFieldValue(spawner, "f", spawnerE); - ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); - } else { - if (spawner.spawnDelay == -1) { - delay(spawner); - } - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - return true; - } - - boolean flag = false; - int i = 0; - - while (true) { - if (i >= spawner.spawnCount) { - if (flag) { - delay(spawner); - } - break; - } - - NBTTagCompound nbttagcompound = spawner.spawnData.getEntity(); - Optional> optional = EntityTypes.a(nbttagcompound); - if (!optional.isPresent()) { - delay(spawner); - return true; - } - - NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); - int j = nbttaglist.size(); - double d3 = j >= 1 ? nbttaglist.h(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; - double d4 = j >= 2 ? nbttaglist.h(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); - double d5 = j >= 3 ? nbttaglist.h(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; - if (world.b(optional.get().a(d3, d4, d5)) && EntityPositionTypes.a(optional.get(), world.getMinecraftWorld(), EnumMobSpawn.SPAWNER, new BlockPosition(d3, d4, d5), world.getRandom())) { - label112: - { - Entity entity = EntityTypes.a(nbttagcompound, world, (entity1) -> { - entity1.setPositionRotation(d3, d4, d5, entity1.yaw, entity1.pitch); - return entity1; - }); - if (entity == null) { - delay(spawner); - return true; - } - - int k = world.a(entity.getClass(), (new AxisAlignedBB( - blockposition.getX(), - blockposition.getY(), - blockposition.getZ(), - blockposition.getX() + 1, - blockposition.getY() + 1, - blockposition.getZ() + 1)) - .g(spawner.spawnRange)).size(); - if (k >= spawner.maxNearbyEntities) { - delay(spawner); - return true; - } - - entity.setPositionRotation(entity.locX(), entity.locY(), entity.locZ(), world.random.nextFloat() * 360.0F, 0.0F); - if (entity instanceof EntityInsentient) { - EntityInsentient entityinsentient = (EntityInsentient) entity; - if (!entityinsentient.a(world, EnumMobSpawn.SPAWNER) || !entityinsentient.a(world)) { - break label112; - } - - if (spawner.spawnData.getEntity().e() == 1 && spawner.spawnData.getEntity().hasKeyOfType("id", 8)) { - ((EntityInsentient) entity).prepare(world, world.getDamageScaler(entity.getChunkCoordinates()), EnumMobSpawn.SPAWNER, null, null); - } - - if (entityinsentient.world.spigotConfig.nerfSpawnerMobs) { - entityinsentient.aware = false; - } - } - - if (CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { - Entity vehicle = entity.getVehicle(); - if (vehicle != null) { - vehicle.dead = true; - } - - Entity passenger; - for (Iterator var19 = entity.getAllPassengers().iterator(); var19.hasNext(); passenger.dead = true) { - passenger = var19.next(); - } - } else { - addWithPassengers(spawner, entity); - world.triggerEffect(2004, blockposition, 0); - if (entity instanceof EntityInsentient) { - ((EntityInsentient) entity).doSpawnEffect(); - } - - flag = true; - } - } - } - - ++i; - } - } - - return true; - } - - /** - * This method is based on {@link MobSpawnerAbstract#i()}. - */ - static void delay(MobSpawnerAbstract spawner) { - if (spawner.maxSpawnDelay <= spawner.minSpawnDelay) { - spawner.spawnDelay = spawner.minSpawnDelay; - } else { - int i = spawner.maxSpawnDelay - spawner.minSpawnDelay; - spawner.spawnDelay = spawner.minSpawnDelay + spawner.a().random.nextInt(i); - } - - if (!spawner.mobs.isEmpty()) { - spawner.setSpawnData(WeightedRandom.a(spawner.a().random, spawner.mobs)); - } - - spawner.a(1); - } - - /** - * This method is based on {@link MobSpawnerAbstract#a(Entity)}. - */ - static void addWithPassengers(MobSpawnerAbstract spawner, Entity entity) { - if (spawner.a().addEntity(entity, CreatureSpawnEvent.SpawnReason.SPAWNER)) { - - for (Entity entity1 : entity.getPassengers()) { - addWithPassengers(spawner, entity1); - } - } - } - } -} diff --git a/modules/nms/epicanchors-v1_16_R2/pom.xml b/modules/nms/epicanchors-v1_16_R2/pom.xml deleted file mode 100644 index df83392..0000000 --- a/modules/nms/epicanchors-v1_16_R2/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - 4.0.0 - - - com.songoda - EpicAnchors - 2.0.0-ALPHA - ../../../pom.xml - - jar - epicanchors-v1_16_R2 - - - - com.songoda - epicanchors-api - ${project.version} - - - - org.spigotmc - spigot-api - 1.16.3-R0.1-SNAPSHOT - provided - - - - org.spigotmc - spigot - 1.16.2 - provided - - - diff --git a/modules/nms/epicanchors-v1_16_R2/src/main/java/epicanchors/nms/v1_16_R2.java b/modules/nms/epicanchors-v1_16_R2/src/main/java/epicanchors/nms/v1_16_R2.java deleted file mode 100644 index d2c7f6c..0000000 --- a/modules/nms/epicanchors-v1_16_R2/src/main/java/epicanchors/nms/v1_16_R2.java +++ /dev/null @@ -1,299 +0,0 @@ -package epicanchors.nms; - -import com.songoda.epicanchors.AnchorNMS; -import com.songoda.epicanchors.utils.ReflectionUtils; -import com.songoda.epicanchors.utils.Utils; -import net.minecraft.server.v1_16_R2.*; -import org.bukkit.Chunk; -import org.bukkit.GameRule; -import org.bukkit.World; -import org.bukkit.block.BlockState; -import org.bukkit.block.CreatureSpawner; -import org.bukkit.craftbukkit.v1_16_R2.CraftChunk; -import org.bukkit.craftbukkit.v1_16_R2.block.CraftCreatureSpawner; -import org.bukkit.craftbukkit.v1_16_R2.event.CraftEventFactory; -import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.plugin.java.JavaPlugin; - -import java.util.Iterator; -import java.util.Optional; - -public class v1_16_R2 extends AnchorNMS { - @SuppressWarnings("unused") - public v1_16_R2(JavaPlugin plugin) { - super(plugin); - } - - @Override - public boolean loadAnchoredChunk(Chunk chunk) { - return chunk.addPluginChunkTicket(super.plugin); - } - - @Override - public boolean unloadAnchoredChunk(Chunk chunk) { - chunk.removePluginChunkTicket(super.plugin); - - return chunk.unload(); - } - - @Override - public void tickInactiveSpawners(Chunk chunk, int amount) { - if (amount <= 0) return; - - try { - for (BlockState tileEntity : chunk.getTileEntities()) { - if (tileEntity instanceof CreatureSpawner) { - MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); - - for (int i = 0; i < amount; ++i) { - if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { - break; // Spawner not inactive - } - } - } - } - } catch (Exception ex) { - Utils.logException(super.plugin, ex); - } - } - - @Override - public void doRandomTick(Chunk chunk, int tickAmount) { - NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); - } - - @Override - public int getRandomTickSpeed(World world) { - Integer result = world.getGameRuleValue(GameRule.RANDOM_TICK_SPEED); - - if (result == null) { - result = world.getGameRuleDefault(GameRule.RANDOM_TICK_SPEED); - } - - return result == null ? 3 : result; - } - - /** - * This class contains some modified methods from {@link WorldServer} - * which originally (vanilla server) goes by the name ServerLevel. - */ - private static class NotchianServerLevel { - /** - * Method is based on {@link WorldServer#a(net.minecraft.server.v1_16_R2.Chunk, int)}. - */ - static void randomTickChunk(net.minecraft.server.v1_16_R2.Chunk chunk, int tickAmount) { - if (tickAmount > 0) { - ChunkCoordIntPair chunkcoordintpair = chunk.getPos(); - int j = chunkcoordintpair.d(); - int k = chunkcoordintpair.e(); - - GameProfilerFiller profiler = chunk.world.getMethodProfiler(); - - profiler.enter("tickBlocks"); - for (ChunkSection chunksection : chunk.getSections()) { - if (chunksection != net.minecraft.server.v1_16_R2.Chunk.a && chunksection.d()) { - int j1 = chunksection.getYPosition(); - - for (int i = 0; i < tickAmount; ++i) { - BlockPosition blockposition2 = chunk.world.a(j, j1, k, 15); - profiler.enter("randomTick"); - - IBlockData iblockdata = chunksection.getType(blockposition2.getX() - j, blockposition2.getY() - j1, blockposition2.getZ() - k); - - if (iblockdata.isTicking()) { - iblockdata.b(chunk.world, blockposition2, chunk.world.random); - } - - Fluid fluid = iblockdata.getFluid(); - if (fluid.f()) { - fluid.b(chunk.world, blockposition2, chunk.world.random); - } - - profiler.exit(); - } - } - } - - profiler.exit(); - } - } - } - - /** - * This class contains some modified methods from {@link MobSpawnerAbstract} - * which originally (vanilla server) goes by the name BaseSpawner. - */ - private static class NotchianBaseSpawner { - static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { - Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); - - return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); - } - - /** - * This method is based on {@link MobSpawnerAbstract#h()}. - */ - static boolean isNearPlayer(MobSpawnerAbstract spawner) { - BlockPosition blockposition = spawner.b(); - return spawner.a().isPlayerNearby( - (double) blockposition.getX() + .5D, - (double) blockposition.getY() + .5D, - (double) blockposition.getZ() + .5D, - spawner.requiredPlayerRange); - } - - /** - * This method is based on {@link MobSpawnerAbstract#c()}. - * - * @return false if the spawner is not inactive, true otherwise - */ - static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException { - if (isNearPlayer(spawner)) return false; - - net.minecraft.server.v1_16_R2.World world = spawner.a(); - BlockPosition blockposition = spawner.b(); - - if (!(world instanceof WorldServer)) { - double d0 = (double) blockposition.getX() + world.random.nextDouble(); - double d1 = (double) blockposition.getY() + world.random.nextDouble(); - double d2 = (double) blockposition.getZ() + world.random.nextDouble(); - world.addParticle(Particles.SMOKE, d0, d1, d2, 0.0D, 0.0D, 0.0D); - world.addParticle(Particles.FLAME, d0, d1, d2, 0.0D, 0.0D, 0.0D); - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - } - - double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); - ReflectionUtils.setFieldValue(spawner, "f", spawnerE); - ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); - } else { - if (spawner.spawnDelay == -1) { - delay(spawner); - } - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - return true; - } - - boolean flag = false; - int i = 0; - - while (true) { - if (i >= spawner.spawnCount) { - if (flag) { - delay(spawner); - } - - break; - } - - NBTTagCompound nbttagcompound = spawner.spawnData.getEntity(); - Optional> optional = EntityTypes.a(nbttagcompound); - if (!optional.isPresent()) { - delay(spawner); - return true; - } - - NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); - int j = nbttaglist.size(); - double d3 = j >= 1 ? nbttaglist.h(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; - double d4 = j >= 2 ? nbttaglist.h(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); - double d5 = j >= 3 ? nbttaglist.h(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; - if (world.b(optional.get().a(d3, d4, d5))) { - WorldServer worldserver = (WorldServer) world; - if (EntityPositionTypes.a(optional.get(), worldserver, EnumMobSpawn.SPAWNER, new BlockPosition(d3, d4, d5), world.getRandom())) { - label116: - { - Entity entity = EntityTypes.a(nbttagcompound, world, (entity1) -> { - entity1.setPositionRotation(d3, d4, d5, entity1.yaw, entity1.pitch); - return entity1; - }); - if (entity == null) { - delay(spawner); - return true; - } - - int k = world.a(entity.getClass(), (new AxisAlignedBB( - blockposition.getX(), - blockposition.getY(), - blockposition.getZ(), - blockposition.getX() + 1, - blockposition.getY() + 1, - blockposition.getZ() + 1)) - .g(spawner.spawnRange)).size(); - - if (k >= spawner.maxNearbyEntities) { - delay(spawner); - return true; - } - - entity.setPositionRotation(entity.locX(), entity.locY(), entity.locZ(), world.random.nextFloat() * 360.0F, 0.0F); - if (entity instanceof EntityInsentient) { - EntityInsentient entityinsentient = (EntityInsentient) entity; - if (!entityinsentient.a(world, EnumMobSpawn.SPAWNER) || !entityinsentient.a(world)) { - break label116; - } - - if (spawner.spawnData.getEntity().e() == 1 && spawner.spawnData.getEntity().hasKeyOfType("id", 8)) { - ((EntityInsentient) entity).prepare(worldserver, world.getDamageScaler(entity.getChunkCoordinates()), EnumMobSpawn.SPAWNER, null, null); - } - - if (entityinsentient.world.spigotConfig.nerfSpawnerMobs) { - entityinsentient.aware = false; - } - } - - if (CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { - Entity vehicle = entity.getVehicle(); - if (vehicle != null) { - vehicle.dead = true; - } - - Entity passenger; - for (Iterator var20 = entity.getAllPassengers().iterator(); var20.hasNext(); passenger.dead = true) { - passenger = var20.next(); - } - } else { - if (!worldserver.addAllEntitiesSafely(entity, CreatureSpawnEvent.SpawnReason.SPAWNER)) { - delay(spawner); - return true; - } - - world.triggerEffect(2004, blockposition, 0); - if (entity instanceof EntityInsentient) { - ((EntityInsentient) entity).doSpawnEffect(); - } - - flag = true; - } - } - } - } - - ++i; - } - } - - return true; - } - - /** - * This method is based on {@link MobSpawnerAbstract#i()}. - */ - static void delay(MobSpawnerAbstract spawner) { - if (spawner.maxSpawnDelay <= spawner.minSpawnDelay) { - spawner.spawnDelay = spawner.minSpawnDelay; - } else { - int i = spawner.maxSpawnDelay - spawner.minSpawnDelay; - spawner.spawnDelay = spawner.minSpawnDelay + spawner.a().random.nextInt(i); - } - - if (!spawner.mobs.isEmpty()) { - spawner.setSpawnData(WeightedRandom.a(spawner.a().random, spawner.mobs)); - } - - spawner.a(1); - } - } -} diff --git a/modules/nms/epicanchors-v1_16_R3/pom.xml b/modules/nms/epicanchors-v1_16_R3/pom.xml deleted file mode 100644 index 6704dc7..0000000 --- a/modules/nms/epicanchors-v1_16_R3/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - 4.0.0 - - - com.songoda - EpicAnchors - 2.0.0-ALPHA - ../../../pom.xml - - jar - epicanchors-v1_16_R3 - - - - com.songoda - epicanchors-api - ${project.version} - - - - org.spigotmc - spigot-api - 1.16.5-R0.1-SNAPSHOT - provided - - - - org.spigotmc - spigot - 1.16.5 - provided - - - diff --git a/modules/nms/epicanchors-v1_16_R3/src/main/java/epicanchors/nms/v1_16_R3.java b/modules/nms/epicanchors-v1_16_R3/src/main/java/epicanchors/nms/v1_16_R3.java deleted file mode 100644 index 0e23b56..0000000 --- a/modules/nms/epicanchors-v1_16_R3/src/main/java/epicanchors/nms/v1_16_R3.java +++ /dev/null @@ -1,305 +0,0 @@ -package epicanchors.nms; - -import com.songoda.epicanchors.AnchorNMS; -import com.songoda.epicanchors.utils.ReflectionUtils; -import com.songoda.epicanchors.utils.Utils; -import net.minecraft.server.v1_16_R3.*; -import org.bukkit.Chunk; -import org.bukkit.GameRule; -import org.bukkit.World; -import org.bukkit.block.BlockState; -import org.bukkit.block.CreatureSpawner; -import org.bukkit.craftbukkit.v1_16_R3.CraftChunk; -import org.bukkit.craftbukkit.v1_16_R3.block.CraftCreatureSpawner; -import org.bukkit.craftbukkit.v1_16_R3.event.CraftEventFactory; -import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.plugin.java.JavaPlugin; - -import java.util.Iterator; -import java.util.Optional; - -public class v1_16_R3 extends AnchorNMS { - @SuppressWarnings("unused") - public v1_16_R3(JavaPlugin plugin) { - super(plugin); - } - - @Override - public boolean loadAnchoredChunk(Chunk chunk) { - return chunk.addPluginChunkTicket(super.plugin); - } - - @Override - public boolean unloadAnchoredChunk(Chunk chunk) { - chunk.removePluginChunkTicket(super.plugin); - - return chunk.unload(); - } - - @Override - public void tickInactiveSpawners(Chunk chunk, int amount) { - if (amount <= 0) return; - - try { - for (BlockState tileEntity : chunk.getTileEntities()) { - if (tileEntity instanceof CreatureSpawner) { - MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); - - for (int i = 0; i < amount; ++i) { - if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { - break; // Spawner not inactive - } - } - } - } - } catch (Exception ex) { - Utils.logException(super.plugin, ex); - } - } - - @Override - public void doRandomTick(Chunk chunk, int tickAmount) { - NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); - } - - @Override - public int getRandomTickSpeed(World world) { - Integer result = world.getGameRuleValue(GameRule.RANDOM_TICK_SPEED); - - if (result == null) { - result = world.getGameRuleDefault(GameRule.RANDOM_TICK_SPEED); - } - - return result == null ? 3 : result; - } - - /** - * This class contains some modified methods from {@link WorldServer} - * which originally (vanilla server) goes by the name ServerLevel. - */ - private static class NotchianServerLevel { - /** - * Method is based on {@link WorldServer#a(net.minecraft.server.v1_16_R3.Chunk, int)}. - */ - static void randomTickChunk(net.minecraft.server.v1_16_R3.Chunk chunk, int tickAmount) { - if (tickAmount > 0) { - GameProfilerFiller profiler = chunk.world.getMethodProfiler(); - - ChunkCoordIntPair chunkPos = chunk.getPos(); - int minBlockX = chunkPos.d(); - int minBlockZ = chunkPos.e(); - - profiler.enter("tickBlocks"); - for (ChunkSection cSection : chunk.getSections()) { - if (cSection != net.minecraft.server.v1_16_R3.Chunk.a && // cSection != Chunk.EMPTY_SECTION - cSection.d()) { // #isRandomlyTicking() - int bottomBlockY = cSection.getYPosition(); - - for (int i = 0; i < tickAmount; ++i) { - BlockPosition randomBlockPos = chunk.world.a(minBlockX, bottomBlockY, minBlockZ, 15); // getBlockRandomPos - profiler.enter("randomTick"); - - IBlockData blockState = cSection.getType(randomBlockPos.getX() - minBlockX, - randomBlockPos.getY() - bottomBlockY, - randomBlockPos.getZ() - minBlockZ); // #getBlockState - - if (blockState.isTicking()) { // #isRandomlyTicking() - blockState.b(chunk.world, randomBlockPos, chunk.world.random); // #randomTick - } - - Fluid fluidState = blockState.getFluid(); // #getFluidState() - if (fluidState.f()) { // #isRandomlyTicking() - fluidState.b(chunk.world, randomBlockPos, chunk.world.random); // #randomTick - } - - profiler.exit(); - } - } - } - - profiler.exit(); - } - } - } - - /** - * This class contains some modified methods from {@link MobSpawnerAbstract} - * which originally (vanilla server) goes by the name BaseSpawner. - */ - private static class NotchianBaseSpawner { - static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { - Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "tileEntity"); - - return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); - } - - /** - * This method is based on {@link MobSpawnerAbstract#h()}. - */ - static boolean isNearPlayer(MobSpawnerAbstract spawner) { - BlockPosition blockposition = spawner.b(); - - return spawner.a() - .isPlayerNearby((double) blockposition.getX() + 0.5D, - (double) blockposition.getY() + 0.5D, - (double) blockposition.getZ() + 0.5D, - spawner.requiredPlayerRange); - } - - /** - * This method is based on {@link MobSpawnerAbstract#c()}. - * - * @return false if the spawner is not inactive, true otherwise - */ - static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException { - if (isNearPlayer(spawner)) return false; - - net.minecraft.server.v1_16_R3.World world = spawner.a(); - BlockPosition blockposition = spawner.b(); - if (!(world instanceof WorldServer)) { - double d0 = (double) blockposition.getX() + world.random.nextDouble(); - double d1 = (double) blockposition.getY() + world.random.nextDouble(); - double d2 = (double) blockposition.getZ() + world.random.nextDouble(); - - world.addParticle(Particles.SMOKE, d0, d1, d2, 0.0D, 0.0D, 0.0D); - world.addParticle(Particles.FLAME, d0, d1, d2, 0.0D, 0.0D, 0.0D); - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - } - - double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); - ReflectionUtils.setFieldValue(spawner, "f", spawnerE); - ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); - } else { - if (spawner.spawnDelay == -1) { - delay(spawner); - } - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - return true; - } - - boolean flag = false; - int i = 0; - - while (true) { - if (i >= spawner.spawnCount) { - if (flag) { - delay(spawner); - } - - break; - } - - NBTTagCompound nbttagcompound = spawner.spawnData.getEntity(); - Optional> optional = EntityTypes.a(nbttagcompound); - if (!optional.isPresent()) { - delay(spawner); - return true; - } - - NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); - int j = nbttaglist.size(); - double d3 = j >= 1 ? nbttaglist.h(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; - double d4 = j >= 2 ? nbttaglist.h(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); - double d5 = j >= 3 ? nbttaglist.h(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawner.spawnRange + .5D; - - if (world.b(optional.get().a(d3, d4, d5))) { - WorldServer worldserver = (WorldServer) world; - if (EntityPositionTypes.a(optional.get(), worldserver, EnumMobSpawn.SPAWNER, new BlockPosition(d3, d4, d5), world.getRandom())) { - label116: - { - Entity entity = EntityTypes.a(nbttagcompound, world, (entity1) -> { - entity1.setPositionRotation(d3, d4, d5, entity1.yaw, entity1.pitch); - return entity1; - }); - if (entity == null) { - delay(spawner); - return true; - } - - int k = world.a(entity.getClass(), (new AxisAlignedBB( - blockposition.getX(), - blockposition.getY(), - blockposition.getZ(), - blockposition.getX() + 1, - blockposition.getY() + 1, - blockposition.getZ() + 1)) - .g(spawner.spawnRange)).size(); - - if (k >= spawner.maxNearbyEntities) { - delay(spawner); - return true; - } - - entity.setPositionRotation(entity.locX(), entity.locY(), entity.locZ(), world.random.nextFloat() * 360F, 0F); - if (entity instanceof EntityInsentient) { - EntityInsentient entityinsentient = (EntityInsentient) entity; - if (!entityinsentient.a(world, EnumMobSpawn.SPAWNER) || !entityinsentient.a(world)) { - break label116; - } - - if (spawner.spawnData.getEntity().e() == 1 && spawner.spawnData.getEntity().hasKeyOfType("id", 8)) { - ((EntityInsentient) entity).prepare(worldserver, world.getDamageScaler(entity.getChunkCoordinates()), EnumMobSpawn.SPAWNER, null, null); - } - - if (entityinsentient.world.spigotConfig.nerfSpawnerMobs) { - entityinsentient.aware = false; - } - } - - if (CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { - Entity vehicle = entity.getVehicle(); - if (vehicle != null) { - vehicle.dead = true; - } - - Entity passenger; - for (Iterator var20 = entity.getAllPassengers().iterator(); var20.hasNext(); passenger.dead = true) { - passenger = var20.next(); - } - } else { - if (!worldserver.addAllEntitiesSafely(entity, CreatureSpawnEvent.SpawnReason.SPAWNER)) { - delay(spawner); - return true; - } - - world.triggerEffect(2004, blockposition, 0); - if (entity instanceof EntityInsentient) { - ((EntityInsentient) entity).doSpawnEffect(); - } - - flag = true; - } - } - } - } - - ++i; - } - } - - return true; - } - - /** - * This method is based on {@link MobSpawnerAbstract#i()}. - */ - static void delay(MobSpawnerAbstract spawner) { - if (spawner.maxSpawnDelay <= spawner.minSpawnDelay) { - spawner.spawnDelay = spawner.minSpawnDelay; - } else { - int i = spawner.maxSpawnDelay - spawner.minSpawnDelay; - spawner.spawnDelay = spawner.minSpawnDelay + spawner.a().random.nextInt(i); - } - - if (!spawner.mobs.isEmpty()) { - spawner.setSpawnData(WeightedRandom.a(spawner.a().random, spawner.mobs)); - } - - spawner.a(1); - } - } -} diff --git a/modules/nms/epicanchors-v1_8_R1/pom.xml b/modules/nms/epicanchors-v1_8_R1/pom.xml deleted file mode 100644 index 0664d7e..0000000 --- a/modules/nms/epicanchors-v1_8_R1/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - 4.0.0 - - - com.songoda - EpicAnchors - 2.0.0-ALPHA - ../../../pom.xml - - jar - epicanchors-v1_8_R1 - - - - com.songoda - epicanchors-api - ${project.version} - - - - org.spigotmc - spigot-api - 1.8-R0.1-SNAPSHOT - provided - - - - org.spigotmc - spigot - 1.8 - provided - - - diff --git a/modules/nms/epicanchors-v1_8_R1/src/main/java/epicanchors/nms/v1_8_R1.java b/modules/nms/epicanchors-v1_8_R1/src/main/java/epicanchors/nms/v1_8_R1.java deleted file mode 100644 index e4a3e6d..0000000 --- a/modules/nms/epicanchors-v1_8_R1/src/main/java/epicanchors/nms/v1_8_R1.java +++ /dev/null @@ -1,251 +0,0 @@ -package epicanchors.nms; - -import com.songoda.epicanchors.AnchorNMS; -import com.songoda.epicanchors.utils.ReflectionUtils; -import com.songoda.epicanchors.utils.Utils; -import net.minecraft.server.v1_8_R1.AxisAlignedBB; -import net.minecraft.server.v1_8_R1.Block; -import net.minecraft.server.v1_8_R1.BlockPosition; -import net.minecraft.server.v1_8_R1.ChunkSection; -import net.minecraft.server.v1_8_R1.Entity; -import net.minecraft.server.v1_8_R1.EntityInsentient; -import net.minecraft.server.v1_8_R1.EntityTypes; -import net.minecraft.server.v1_8_R1.EnumParticle; -import net.minecraft.server.v1_8_R1.IBlockData; -import net.minecraft.server.v1_8_R1.MobSpawnerAbstract; -import net.minecraft.server.v1_8_R1.WorldServer; -import org.bukkit.Chunk; -import org.bukkit.World; -import org.bukkit.block.BlockState; -import org.bukkit.block.CreatureSpawner; -import org.bukkit.craftbukkit.v1_8_R1.CraftChunk; -import org.bukkit.craftbukkit.v1_8_R1.block.CraftCreatureSpawner; -import org.bukkit.plugin.java.JavaPlugin; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class v1_8_R1 extends AnchorNMS { - @SuppressWarnings("unused") - public v1_8_R1(JavaPlugin plugin) { - super(plugin); - } - - @Override - public boolean loadAnchoredChunk(Chunk chunk) { - return chunk.load(); - } - - @Override - public boolean unloadAnchoredChunk(Chunk chunk) { - return chunk.unload(); - } - - @Override - public void tickInactiveSpawners(Chunk chunk, int amount) { - if (amount <= 0) return; - - try { - for (BlockState tileEntity : chunk.getTileEntities()) { - if (tileEntity instanceof CreatureSpawner) { - MobSpawnerAbstract spawner = MobSpawnerUtils.getNotchianSpawner((CraftCreatureSpawner) tileEntity); - - for (int i = 0; i < amount; ++i) { - if (!MobSpawnerUtils.tickInactiveSpawner(spawner)) { - break; // Spawner not inactive - } - } - } - } - } catch (Exception ex) { - Utils.logException(super.plugin, ex); - } - } - - @Override - public void doRandomTick(Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { - WorldServerUtils.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); - } - - @Override - public int getRandomTickSpeed(World world) { - return Helper.getRandomTickSpeedLegacy(world); - } - - /** - * This class contains some modified methods from {@link WorldServer}. - */ - private static class WorldServerUtils { - /** - * Method is based on {@link WorldServer#h()}. - */ - static void randomTickChunk(net.minecraft.server.v1_8_R1.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { - if (tickAmount > 0) { - int k = chunk.locX * 16; - int l = chunk.locZ * 16; - - for (ChunkSection cSection : chunk.getSections()) { - if (cSection != null && cSection.shouldTick()) { - - for (int i = 0; i < tickAmount; ++i) { - int m = (int) ReflectionUtils.getFieldValue(chunk.world, "m"); - - m = m * 3 + 1013904223; - ReflectionUtils.setFieldValue(chunk.world, "m", m); - - int i2 = m >> 2; - int j2 = i2 & 15; - int k2 = i2 >> 8 & 15; - int l2 = i2 >> 16 & 15; - - BlockPosition blockposition2 = new BlockPosition(j2 + k, l2 + cSection.getYPosition(), k2 + l); - IBlockData iblockdata = cSection.getType(j2, l2, k2); - Block block = iblockdata.getBlock(); - - if (block.isTicking()) { - block.a(chunk.world, blockposition2, iblockdata, chunk.world.random); - } - } - } - } - } - } - } - - /** - * This class contains some modified methods from {@link MobSpawnerAbstract}. - */ - private static class MobSpawnerUtils { - private static Method aEntityBooleanMethod, gMethod, hMethod; - - static { - try { - aEntityBooleanMethod = MobSpawnerAbstract.class.getDeclaredMethod("a", Entity.class, boolean.class); - aEntityBooleanMethod.setAccessible(true); - - gMethod = MobSpawnerAbstract.class.getDeclaredMethod("g"); - gMethod.setAccessible(true); - - hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); - hMethod.setAccessible(true); - } catch (NoSuchMethodException ex) { - Utils.logException(null, ex); - } - } - - static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { - Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); - - return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); - } - - /** - * This method calls {@link MobSpawnerAbstract#g()} using Reflections. - */ - static boolean isNearPlayer(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { - return (boolean) gMethod.invoke(spawner); - } - - /** - * This method is based on {@link MobSpawnerAbstract#c()}. - * - * @return false if the spawner is not inactive, true otherwise - */ - static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { - if (isNearPlayer(spawner)) return false; - - BlockPosition blockposition = spawner.b(); - - if (spawner.a().isStatic) { - double d1 = (float) blockposition.getX() + spawner.a().random.nextFloat(); - double d2 = (float) blockposition.getY() + spawner.a().random.nextFloat(); - double d0 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); - - spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d1, d2, d0, 0D, 0D, 0D); - spawner.a().addParticle(EnumParticle.FLAME, d1, d2, d0, 0D, 0D, 0D); - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - } - - double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); - - ReflectionUtils.setFieldValue(spawner, "f", spawnerE); - ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); - } else { - if (spawner.spawnDelay == -1) { - delay(spawner); - } - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - return true; - } - - boolean flag = false; - int i = 0; - - int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); - int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); - int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); - while (true) { - if (i >= spawnCount) { - if (flag) { - delay(spawner); - } - - break; - } - - Entity entity = EntityTypes.createEntityByName(spawner.getMobName(), spawner.a()); - if (entity == null) { - return true; - } - - int j = spawner.a() - .a(entity.getClass(), (new AxisAlignedBB(blockposition.getX(), - blockposition.getY(), - blockposition.getZ(), - blockposition.getX() + 1, - blockposition.getY() + 1, - blockposition.getZ() + 1)) - .grow(spawnRange, spawnRange, spawnRange)).size(); - - if (j >= maxNearbyEntities) { - delay(spawner); - return true; - } - - double d0 = (double) blockposition.getX() + (spawner.a().random.nextDouble() - spawner.a().random.nextDouble()) * (double) spawnRange + 0.5D; - double d3 = blockposition.getY() + spawner.a().random.nextInt(3) - 1; - double d4 = (double) blockposition.getZ() + (spawner.a().random.nextDouble() - spawner.a().random.nextDouble()) * (double) spawnRange + 0.5D; - - EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; - entity.setPositionRotation(d0, d3, d4, spawner.a().random.nextFloat() * 360.0F, 0.0F); - - if (entityinsentient == null || entityinsentient.bQ() && entityinsentient.canSpawn()) { - aEntityBooleanMethod.invoke(spawner, entity, true); - spawner.a().triggerEffect(2004, blockposition, 0); - - if (entityinsentient != null) { - entityinsentient.y(); - } - - flag = true; - } - - ++i; - } - } - - return true; - } - - /** - * This method calls {@link MobSpawnerAbstract#h()} using Reflections. - */ - static void delay(MobSpawnerAbstract spawner) throws IllegalAccessException, InvocationTargetException { - hMethod.invoke(spawner); - } - } -} diff --git a/modules/nms/epicanchors-v1_8_R2/pom.xml b/modules/nms/epicanchors-v1_8_R2/pom.xml deleted file mode 100644 index 3be749e..0000000 --- a/modules/nms/epicanchors-v1_8_R2/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - 4.0.0 - - - com.songoda - EpicAnchors - 2.0.0-ALPHA - ../../../pom.xml - - jar - epicanchors-v1_8_R2 - - - - com.songoda - epicanchors-api - ${project.version} - - - - org.spigotmc - spigot-api - 1.8.3-R0.1-SNAPSHOT - provided - - - - org.spigotmc - spigot - 1.8.3 - provided - - - diff --git a/modules/nms/epicanchors-v1_8_R2/src/main/java/epicanchors/nms/v1_8_R2.java b/modules/nms/epicanchors-v1_8_R2/src/main/java/epicanchors/nms/v1_8_R2.java deleted file mode 100644 index cfbeed6..0000000 --- a/modules/nms/epicanchors-v1_8_R2/src/main/java/epicanchors/nms/v1_8_R2.java +++ /dev/null @@ -1,248 +0,0 @@ -package epicanchors.nms; - -import com.songoda.epicanchors.AnchorNMS; -import com.songoda.epicanchors.utils.ReflectionUtils; -import com.songoda.epicanchors.utils.Utils; -import net.minecraft.server.v1_8_R2.AxisAlignedBB; -import net.minecraft.server.v1_8_R2.Block; -import net.minecraft.server.v1_8_R2.BlockPosition; -import net.minecraft.server.v1_8_R2.ChunkSection; -import net.minecraft.server.v1_8_R2.Entity; -import net.minecraft.server.v1_8_R2.EntityInsentient; -import net.minecraft.server.v1_8_R2.EntityTypes; -import net.minecraft.server.v1_8_R2.EnumParticle; -import net.minecraft.server.v1_8_R2.IBlockData; -import net.minecraft.server.v1_8_R2.MobSpawnerAbstract; -import net.minecraft.server.v1_8_R2.WorldServer; -import org.bukkit.Chunk; -import org.bukkit.World; -import org.bukkit.block.BlockState; -import org.bukkit.block.CreatureSpawner; -import org.bukkit.craftbukkit.v1_8_R2.CraftChunk; -import org.bukkit.craftbukkit.v1_8_R2.block.CraftCreatureSpawner; -import org.bukkit.plugin.java.JavaPlugin; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class v1_8_R2 extends AnchorNMS { - @SuppressWarnings("unused") - public v1_8_R2(JavaPlugin plugin) { - super(plugin); - } - - @Override - public boolean loadAnchoredChunk(Chunk chunk) { - return chunk.load(); - } - - @Override - public boolean unloadAnchoredChunk(Chunk chunk) { - return chunk.unload(); - } - - @Override - public void tickInactiveSpawners(Chunk chunk, int amount) { - if (amount <= 0) return; - - try { - for (BlockState tileEntity : chunk.getTileEntities()) { - if (tileEntity instanceof CreatureSpawner) { - MobSpawnerAbstract spawner = MobSpawnerUtils.getNotchianSpawner((CraftCreatureSpawner) tileEntity); - - for (int i = 0; i < amount; ++i) { - if (!MobSpawnerUtils.tickInactiveSpawner(spawner)) { - break; // Spawner not inactive - } - } - } - } - } catch (Exception ex) { - Utils.logException(super.plugin, ex); - } - } - - @Override - public void doRandomTick(Chunk chunk, int tickAmount) { - try { - WorldServerUtils.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); - } catch (NoSuchFieldException | IllegalAccessException ex) { - Utils.logException(super.plugin, ex); - } - } - - @Override - public int getRandomTickSpeed(World world) { - return Helper.getRandomTickSpeedLegacy(world); - } - - /** - * This class contains some modified methods from {@link WorldServer}. - */ - private static class WorldServerUtils { - /** - * Method is based on {@link WorldServer#h()}. - */ - static void randomTickChunk(net.minecraft.server.v1_8_R2.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { - if (tickAmount > 0) { - int k = chunk.locX * 16; - int l = chunk.locZ * 16; - - for (ChunkSection cSection : chunk.getSections()) { - if (cSection != null && cSection.shouldTick()) { - for (int i = 0; i < tickAmount; ++i) { - int m = (int) ReflectionUtils.getFieldValue(chunk.world, "m"); - - m = m * 3 + 1013904223; - ReflectionUtils.setFieldValue(chunk.world, "m", m); - - int i2 = m >> 2; - int j2 = i2 & 15; - int k2 = i2 >> 8 & 15; - int l2 = i2 >> 16 & 15; - - BlockPosition blockposition2 = new BlockPosition(j2 + k, l2 + cSection.getYPosition(), k2 + l); - IBlockData iblockdata = cSection.getType(j2, l2, k2); - Block block = iblockdata.getBlock(); - - if (block.isTicking()) { - block.a(chunk.world, blockposition2, iblockdata, chunk.world.random); - } - } - } - } - } - } - } - - /** - * This class contains some modified methods from {@link MobSpawnerAbstract}. - */ - private static class MobSpawnerUtils { - private static Method aEntityBooleanMethod, gMethod, hMethod; - - static { - try { - aEntityBooleanMethod = MobSpawnerAbstract.class.getDeclaredMethod("a", Entity.class, boolean.class); - aEntityBooleanMethod.setAccessible(true); - - gMethod = MobSpawnerAbstract.class.getDeclaredMethod("g"); - gMethod.setAccessible(true); - - hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); - hMethod.setAccessible(true); - } catch (NoSuchMethodException ex) { - Utils.logException(null, ex); - } - } - - static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { - Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); - - return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); - } - - /** - * This method calls {@link MobSpawnerAbstract#g()} using Reflections. - */ - static boolean isNearPlayer(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { - return (boolean) gMethod.invoke(spawner); - } - - /** - * This method is based on {@link MobSpawnerAbstract#c()}. - * - * @return false if the spawner is not inactive, true otherwise - */ - static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { - if (isNearPlayer(spawner)) return false; - - BlockPosition blockposition = spawner.b(); - - if (spawner.a().isClientSide) { - double d1 = (float) blockposition.getX() + spawner.a().random.nextFloat(); - double d2 = (float) blockposition.getY() + spawner.a().random.nextFloat(); - double d0 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); - spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d1, d2, d0, 0.0D, 0.0D, 0.0D); - spawner.a().addParticle(EnumParticle.FLAME, d1, d2, d0, 0.0D, 0.0D, 0.0D); - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - } - - double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); - - ReflectionUtils.setFieldValue(spawner, "f", spawnerE); - ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200.0F))) % 360D); - } else { - if (spawner.spawnDelay == -1) { - delay(spawner); - } - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - return true; - } - - boolean flag = false; - int i = 0; - - int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); - int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); - int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); - - while (true) { - if (i >= spawnCount) { - if (flag) { - delay(spawner); - } - break; - } - - Entity entity = EntityTypes.createEntityByName(spawner.getMobName(), spawner.a()); - if (entity == null) { - return true; - } - - int j = spawner.a().a(entity.getClass(), (new AxisAlignedBB( - blockposition.getX(), - blockposition.getY(), - blockposition.getZ(), - blockposition.getX() + 1, - blockposition.getY() + 1, - blockposition.getZ() + 1)) - .grow(spawnRange, spawnRange, spawnRange)).size(); - if (j >= maxNearbyEntities) { - delay(spawner); - return true; - } - - double d0 = (double) blockposition.getX() + (spawner.a().random.nextDouble() - spawner.a().random.nextDouble()) * (double) spawnRange + .5D; - double d3 = blockposition.getY() + spawner.a().random.nextInt(3) - 1; - double d4 = (double) blockposition.getZ() + (spawner.a().random.nextDouble() - spawner.a().random.nextDouble()) * (double) spawnRange + .5D; - EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; - entity.setPositionRotation(d0, d3, d4, spawner.a().random.nextFloat() * 360F, 0F); - if (entityinsentient == null || entityinsentient.bR() && entityinsentient.canSpawn()) { - aEntityBooleanMethod.invoke(spawner, entity, true); - spawner.a().triggerEffect(2004, blockposition, 0); - if (entityinsentient != null) { - entityinsentient.y(); - } - - flag = true; - } - - ++i; - } - } - - return true; - } - - /** - * This method calls {@link MobSpawnerAbstract#h()} using Reflections. - */ - static void delay(MobSpawnerAbstract spawner) throws IllegalAccessException, InvocationTargetException { - hMethod.invoke(spawner); - } - } -} diff --git a/modules/nms/epicanchors-v1_8_R3/pom.xml b/modules/nms/epicanchors-v1_8_R3/pom.xml deleted file mode 100644 index 73fb563..0000000 --- a/modules/nms/epicanchors-v1_8_R3/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - 4.0.0 - - - com.songoda - EpicAnchors - 2.0.0-ALPHA - ../../../pom.xml - - jar - epicanchors-v1_8_R3 - - - - com.songoda - epicanchors-api - ${project.version} - - - - org.spigotmc - spigot-api - 1.8.8-R0.1-SNAPSHOT - provided - - - - org.spigotmc - spigot - 1.8.8 - provided - - - diff --git a/modules/nms/epicanchors-v1_8_R3/src/main/java/epicanchors/nms/v1_8_R3.java b/modules/nms/epicanchors-v1_8_R3/src/main/java/epicanchors/nms/v1_8_R3.java deleted file mode 100644 index 80a8b5e..0000000 --- a/modules/nms/epicanchors-v1_8_R3/src/main/java/epicanchors/nms/v1_8_R3.java +++ /dev/null @@ -1,249 +0,0 @@ -package epicanchors.nms; - -import com.songoda.epicanchors.AnchorNMS; -import com.songoda.epicanchors.utils.ReflectionUtils; -import com.songoda.epicanchors.utils.Utils; -import net.minecraft.server.v1_8_R3.AxisAlignedBB; -import net.minecraft.server.v1_8_R3.Block; -import net.minecraft.server.v1_8_R3.BlockPosition; -import net.minecraft.server.v1_8_R3.ChunkSection; -import net.minecraft.server.v1_8_R3.Entity; -import net.minecraft.server.v1_8_R3.EntityInsentient; -import net.minecraft.server.v1_8_R3.EntityTypes; -import net.minecraft.server.v1_8_R3.EnumParticle; -import net.minecraft.server.v1_8_R3.IBlockData; -import net.minecraft.server.v1_8_R3.MobSpawnerAbstract; -import net.minecraft.server.v1_8_R3.WorldServer; -import org.bukkit.Chunk; -import org.bukkit.World; -import org.bukkit.block.BlockState; -import org.bukkit.block.CreatureSpawner; -import org.bukkit.craftbukkit.v1_8_R3.CraftChunk; -import org.bukkit.craftbukkit.v1_8_R3.block.CraftCreatureSpawner; -import org.bukkit.plugin.java.JavaPlugin; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class v1_8_R3 extends AnchorNMS { - @SuppressWarnings("unused") - public v1_8_R3(JavaPlugin plugin) { - super(plugin); - } - - @Override - public boolean loadAnchoredChunk(Chunk chunk) { - return chunk.load(); - } - - @Override - public boolean unloadAnchoredChunk(Chunk chunk) { - return chunk.unload(); - } - - @Override - public void tickInactiveSpawners(Chunk chunk, int amount) { - if (amount <= 0) return; - - try { - for (BlockState tileEntity : chunk.getTileEntities()) { - if (tileEntity instanceof CreatureSpawner) { - MobSpawnerAbstract spawner = MobSpawnerUtils.getNotchianSpawner((CraftCreatureSpawner) tileEntity); - - for (int i = 0; i < amount; ++i) { - if (!MobSpawnerUtils.tickInactiveSpawner(spawner)) { - break; // Spawner not inactive - } - } - } - } - } catch (Exception ex) { - Utils.logException(super.plugin, ex); - } - } - - @Override - public void doRandomTick(Chunk chunk, int tickAmount) { - try { - WorldServerUtils.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); - } catch (NoSuchFieldException | IllegalAccessException ex) { - Utils.logException(super.plugin, ex); - } - } - - @Override - public int getRandomTickSpeed(World world) { - return Helper.getRandomTickSpeedLegacy(world); - } - - /** - * This class contains some modified methods from {@link WorldServer}. - */ - private static class WorldServerUtils { - /** - * Method is based on {@link WorldServer#h()}. - */ - static void randomTickChunk(net.minecraft.server.v1_8_R3.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { - if (tickAmount > 0) { - int k = chunk.locX * 16; - int l = chunk.locZ * 16; - - for (ChunkSection chunksection : chunk.getSections()) { - if (chunksection != null && chunksection.shouldTick()) { - for (int l1 = 0; l1 < tickAmount; ++l1) { - int m = (int) ReflectionUtils.getFieldValue(chunk.world, "m"); - - m = m * 3 + 1013904223; - ReflectionUtils.setFieldValue(chunk.world, "m", m); - - int i2 = m >> 2; - int j2 = i2 & 15; - int k2 = i2 >> 8 & 15; - int l2 = i2 >> 16 & 15; - - IBlockData iblockdata = chunksection.getType(j2, l2, k2); - Block block = iblockdata.getBlock(); - - if (block.isTicking()) { - block.a(chunk.world, new BlockPosition(j2 + k, l2 + chunksection.getYPosition(), k2 + l), iblockdata, chunk.world.random); - } - } - } - } - } - } - } - - /** - * This class contains some modified methods from {@link MobSpawnerAbstract}. - */ - private static class MobSpawnerUtils { - private static Method aEntityBooleanMethod, gMethod, hMethod; - - static { - try { - aEntityBooleanMethod = MobSpawnerAbstract.class.getDeclaredMethod("a", Entity.class, boolean.class); - aEntityBooleanMethod.setAccessible(true); - - gMethod = MobSpawnerAbstract.class.getDeclaredMethod("g"); - gMethod.setAccessible(true); - - hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); - hMethod.setAccessible(true); - } catch (NoSuchMethodException ex) { - Utils.logException(null, ex); - } - } - - static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { - Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); - - return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); - } - - /** - * This method calls {@link MobSpawnerAbstract#g()} using Reflections. - */ - static boolean isNearPlayer(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { - return (boolean) gMethod.invoke(spawner); - } - - /** - * This method is based on {@link MobSpawnerAbstract#c()}. - * - * @return false if the spawner is not inactive, true otherwise - */ - static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { - if (isNearPlayer(spawner)) return false; - - BlockPosition blockposition = spawner.b(); - - if (spawner.a().isClientSide) { - double d1 = (float) blockposition.getX() + spawner.a().random.nextFloat(); - double d2 = (float) blockposition.getY() + spawner.a().random.nextFloat(); - double d0 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); - spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d1, d2, d0, 0D, 0D, 0D); - spawner.a().addParticle(EnumParticle.FLAME, d1, d2, d0, 0D, 0D, 0D); - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - } - - double spawnerE = (double) ReflectionUtils.getFieldValue(spawner, "e"); - - ReflectionUtils.setFieldValue(spawner, "f", spawnerE); - ReflectionUtils.setFieldValue(spawner, "e", (spawnerE + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); - } else { - if (spawner.spawnDelay == -1) { - delay(spawner); - } - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - return true; - } - - boolean flag = false; - int i = 0; - - int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); - int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); - int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); - - while (true) { - if (i >= spawnCount) { - if (flag) { - delay(spawner); - } - break; - } - - Entity entity = EntityTypes.createEntityByName(spawner.getMobName(), spawner.a()); - if (entity == null) { - return true; - } - - int j = spawner.a().a(entity.getClass(), (new AxisAlignedBB( - blockposition.getX(), - blockposition.getY(), - blockposition.getZ(), - blockposition.getX() + 1, - blockposition.getY() + 1, - blockposition.getZ() + 1)) - .grow(spawnRange, spawnRange, spawnRange)).size(); - if (j >= maxNearbyEntities) { - delay(spawner); - return true; - } - - double d0 = (double) blockposition.getX() + (spawner.a().random.nextDouble() - spawner.a().random.nextDouble()) * (double) spawnRange + .5D; - double d3 = blockposition.getY() + spawner.a().random.nextInt(3) - 1; - double d4 = (double) blockposition.getZ() + (spawner.a().random.nextDouble() - spawner.a().random.nextDouble()) * (double) spawnRange + .5D; - - EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; - entity.setPositionRotation(d0, d3, d4, spawner.a().random.nextFloat() * 360F, 0F); - - if (entityinsentient == null || entityinsentient.bR() && entityinsentient.canSpawn()) { - aEntityBooleanMethod.invoke(spawner, entity, true); - spawner.a().triggerEffect(2004, blockposition, 0); - if (entityinsentient != null) { - entityinsentient.y(); - } - - flag = true; - } - - ++i; - } - } - - return true; - } - - /** - * This method calls {@link MobSpawnerAbstract#h()} using Reflections. - */ - static void delay(MobSpawnerAbstract spawner) throws IllegalAccessException, InvocationTargetException { - hMethod.invoke(spawner); - } - } -} diff --git a/modules/nms/epicanchors-v1_9_R1/pom.xml b/modules/nms/epicanchors-v1_9_R1/pom.xml deleted file mode 100644 index dfc16b6..0000000 --- a/modules/nms/epicanchors-v1_9_R1/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - 4.0.0 - - - com.songoda - EpicAnchors - 2.0.0-ALPHA - ../../../pom.xml - - jar - epicanchors-v1_9_R1 - - - - com.songoda - epicanchors-api - ${project.version} - - - - org.spigotmc - spigot-api - 1.9-R0.1-SNAPSHOT - provided - - - - org.spigotmc - spigot - 1.9.2 - provided - - - diff --git a/modules/nms/epicanchors-v1_9_R1/src/main/java/epicanchors/nms/v1_9_R1.java b/modules/nms/epicanchors-v1_9_R1/src/main/java/epicanchors/nms/v1_9_R1.java deleted file mode 100644 index 9482130..0000000 --- a/modules/nms/epicanchors-v1_9_R1/src/main/java/epicanchors/nms/v1_9_R1.java +++ /dev/null @@ -1,259 +0,0 @@ -package epicanchors.nms; - -import com.songoda.epicanchors.AnchorNMS; -import com.songoda.epicanchors.utils.ReflectionUtils; -import com.songoda.epicanchors.utils.Utils; -import net.minecraft.server.v1_9_R1.AxisAlignedBB; -import net.minecraft.server.v1_9_R1.Block; -import net.minecraft.server.v1_9_R1.BlockPosition; -import net.minecraft.server.v1_9_R1.ChunkRegionLoader; -import net.minecraft.server.v1_9_R1.ChunkSection; -import net.minecraft.server.v1_9_R1.Entity; -import net.minecraft.server.v1_9_R1.EntityInsentient; -import net.minecraft.server.v1_9_R1.EnumParticle; -import net.minecraft.server.v1_9_R1.IBlockData; -import net.minecraft.server.v1_9_R1.MobSpawnerAbstract; -import net.minecraft.server.v1_9_R1.MobSpawnerData; -import net.minecraft.server.v1_9_R1.NBTTagCompound; -import net.minecraft.server.v1_9_R1.NBTTagList; -import net.minecraft.server.v1_9_R1.WorldServer; -import org.bukkit.Chunk; -import org.bukkit.World; -import org.bukkit.block.BlockState; -import org.bukkit.block.CreatureSpawner; -import org.bukkit.craftbukkit.v1_9_R1.CraftChunk; -import org.bukkit.craftbukkit.v1_9_R1.block.CraftCreatureSpawner; -import org.bukkit.craftbukkit.v1_9_R1.event.CraftEventFactory; -import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.plugin.java.JavaPlugin; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class v1_9_R1 extends AnchorNMS { - @SuppressWarnings("unused") - public v1_9_R1(JavaPlugin plugin) { - super(plugin); - } - - @Override - public boolean loadAnchoredChunk(Chunk chunk) { - return chunk.load(); - } - - @Override - public boolean unloadAnchoredChunk(Chunk chunk) { - return chunk.unload(); - } - - @Override - public void tickInactiveSpawners(Chunk chunk, int amount) { - if (amount <= 0) return; - - try { - for (BlockState tileEntity : chunk.getTileEntities()) { - if (tileEntity instanceof CreatureSpawner) { - MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); - - for (int i = 0; i < amount; ++i) { - if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { - break; // Spawner not inactive - } - } - } - } - } catch (Exception ex) { - Utils.logException(super.plugin, ex); - } - } - - @Override - public void doRandomTick(Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { - NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); - } - - @Override - public int getRandomTickSpeed(World world) { - return Helper.getRandomTickSpeedLegacy(world); - } - - /** - * This class contains some modified methods from {@link WorldServer}. - */ - private static class NotchianServerLevel { - /** - * Method is based on {@link WorldServer#j()}. - */ - static void randomTickChunk(net.minecraft.server.v1_9_R1.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { - if (tickAmount > 0) { - int j = chunk.locX * 16; - int k = chunk.locZ * 16; - - for (ChunkSection chunksection : chunk.getSections()) { - if (chunksection != net.minecraft.server.v1_9_R1.Chunk.a && chunksection.shouldTick()) { - for (int i = 0; i < tickAmount; ++i) { - int worldL = (int) ReflectionUtils.getFieldValue(chunk.world, "l"); - - worldL = worldL * 3 + 1013904223; - ReflectionUtils.setFieldValue(chunk.world, "l", worldL); - - int l1 = worldL >> 2; - int i2 = l1 & 15; - int j2 = l1 >> 8 & 15; - int k2 = l1 >> 16 & 15; - - IBlockData iblockdata = chunksection.getType(i2, k2, j2); - Block block = iblockdata.getBlock(); - - if (block.isTicking()) { - block.a(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), iblockdata, chunk.world.random); - } - } - } - } - } - } - } - - /** - * This class contains some modified methods from {@link MobSpawnerAbstract}. - */ - private static class NotchianBaseSpawner { - private static Method iMethod, hMethod; - - static { - try { - iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); - iMethod.setAccessible(true); - - hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); - hMethod.setAccessible(true); - } catch (NoSuchMethodException ex) { - Utils.logException(null, ex); - } - } - - static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { - Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); - - return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); - } - - /** - * This method calls {@link MobSpawnerAbstract#h()} using Reflections. - */ - static boolean isNearPlayer(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { - return (boolean) hMethod.invoke(spawner); - } - - /** - * This method is based on {@link MobSpawnerAbstract#c()}. - * - * @return false if the spawner is not inactive, true otherwise - */ - static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException, NoSuchFieldException { - if (isNearPlayer(spawner)) return false; - - BlockPosition blockposition = spawner.b(); - if (spawner.a().isClientSide) { - double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); - double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); - double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); - spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d0, d1, d2, 0D, 0D, 0D); - spawner.a().addParticle(EnumParticle.FLAME, d0, d1, d2, 0D, 0D, 0D); - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - } - - double spawnerD = (double) ReflectionUtils.getFieldValue(spawner, "d"); - - ReflectionUtils.setFieldValue(spawner, "e", spawnerD); - ReflectionUtils.setFieldValue(spawner, "d", (spawnerD + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); - } else { - if (spawner.spawnDelay == -1) { - delay(spawner); - } - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - return true; - } - - boolean flag = false; - int i = 0; - - int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); - int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); - int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); - MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); - - while (true) { - if (i >= spawnCount) { - if (flag) { - delay(spawner); - } - break; - } - - NBTTagCompound nbttagcompound = spawnData.b(); - NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); - net.minecraft.server.v1_9_R1.World world = spawner.a(); - int j = nbttaglist.size(); - double d3 = j >= 1 ? nbttaglist.e(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; - double d4 = j >= 2 ? nbttaglist.e(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); - double d5 = j >= 3 ? nbttaglist.e(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; - Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); - if (entity == null) { - return true; - } - - int k = world.a(entity.getClass(), (new AxisAlignedBB( - blockposition.getX(), - blockposition.getY(), - blockposition.getZ(), - blockposition.getX() + 1, - blockposition.getY() + 1, - blockposition.getZ() + 1)) - .g(spawnRange)).size(); - if (k >= maxNearbyEntities) { - delay(spawner); - return true; - } - - EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; - entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360F, 0F); - if (entityinsentient == null || entityinsentient.cF() && entityinsentient.canSpawn()) { - if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { - ((EntityInsentient) entity).prepare(world.D(new BlockPosition(entity)), null); - } - - if (entity.world.spigotConfig.nerfSpawnerMobs) { - entity.fromMobSpawner = true; - } - - if (!CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { - ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); - world.triggerEffect(2004, blockposition, 0); - if (entityinsentient != null) { - entityinsentient.doSpawnEffect(); - } - - flag = true; - } - } - - ++i; - } - } - - return true; - } - - /** - * This method calls {@link MobSpawnerAbstract#i()} using Reflections. - */ - static void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { - iMethod.invoke(spawner); - } - } -} diff --git a/modules/nms/epicanchors-v1_9_R2/pom.xml b/modules/nms/epicanchors-v1_9_R2/pom.xml deleted file mode 100644 index 87b66ba..0000000 --- a/modules/nms/epicanchors-v1_9_R2/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - 4.0.0 - - - com.songoda - EpicAnchors - 2.0.0-ALPHA - ../../../pom.xml - - jar - epicanchors-v1_9_R2 - - - - com.songoda - epicanchors-api - ${project.version} - - - - org.spigotmc - spigot-api - 1.9.4-R0.1-SNAPSHOT - provided - - - - org.spigotmc - spigot - 1.9.4 - provided - - - diff --git a/modules/nms/epicanchors-v1_9_R2/src/main/java/epicanchors/nms/v1_9_R2.java b/modules/nms/epicanchors-v1_9_R2/src/main/java/epicanchors/nms/v1_9_R2.java deleted file mode 100644 index c009edc..0000000 --- a/modules/nms/epicanchors-v1_9_R2/src/main/java/epicanchors/nms/v1_9_R2.java +++ /dev/null @@ -1,261 +0,0 @@ -package epicanchors.nms; - -import com.songoda.epicanchors.AnchorNMS; -import com.songoda.epicanchors.utils.ReflectionUtils; -import com.songoda.epicanchors.utils.Utils; -import net.minecraft.server.v1_9_R2.AxisAlignedBB; -import net.minecraft.server.v1_9_R2.Block; -import net.minecraft.server.v1_9_R2.BlockPosition; -import net.minecraft.server.v1_9_R2.ChunkRegionLoader; -import net.minecraft.server.v1_9_R2.ChunkSection; -import net.minecraft.server.v1_9_R2.Entity; -import net.minecraft.server.v1_9_R2.EntityInsentient; -import net.minecraft.server.v1_9_R2.EnumParticle; -import net.minecraft.server.v1_9_R2.IBlockData; -import net.minecraft.server.v1_9_R2.MobSpawnerAbstract; -import net.minecraft.server.v1_9_R2.MobSpawnerData; -import net.minecraft.server.v1_9_R2.NBTTagCompound; -import net.minecraft.server.v1_9_R2.NBTTagList; -import net.minecraft.server.v1_9_R2.WorldServer; -import org.bukkit.Chunk; -import org.bukkit.World; -import org.bukkit.block.BlockState; -import org.bukkit.block.CreatureSpawner; -import org.bukkit.craftbukkit.v1_9_R2.CraftChunk; -import org.bukkit.craftbukkit.v1_9_R2.block.CraftCreatureSpawner; -import org.bukkit.craftbukkit.v1_9_R2.event.CraftEventFactory; -import org.bukkit.event.entity.CreatureSpawnEvent; -import org.bukkit.plugin.java.JavaPlugin; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class v1_9_R2 extends AnchorNMS { - @SuppressWarnings("unused") - public v1_9_R2(JavaPlugin plugin) { - super(plugin); - } - - @Override - public boolean loadAnchoredChunk(Chunk chunk) { - return chunk.load(); - } - - @Override - public boolean unloadAnchoredChunk(Chunk chunk) { - return chunk.unload(); - } - - @Override - public void tickInactiveSpawners(Chunk chunk, int amount) { - if (amount <= 0) return; - - try { - for (BlockState tileEntity : chunk.getTileEntities()) { - if (tileEntity instanceof CreatureSpawner) { - MobSpawnerAbstract spawner = NotchianBaseSpawner.getNotchianSpawner((CraftCreatureSpawner) tileEntity); - - for (int i = 0; i < amount; ++i) { - if (!NotchianBaseSpawner.tickInactiveSpawner(spawner)) { - break; // Spawner not inactive - } - } - } - } - } catch (Exception ex) { - Utils.logException(super.plugin, ex); - } - } - - @Override - public void doRandomTick(Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { - NotchianServerLevel.randomTickChunk(((CraftChunk) chunk).getHandle(), tickAmount); - } - - @Override - public int getRandomTickSpeed(World world) { - return Helper.getRandomTickSpeedLegacy(world); - } - - /** - * This class contains some modified methods from {@link WorldServer}. - */ - private static class NotchianServerLevel { - /** - * Method is based on {@link WorldServer#j()}. - */ - static void randomTickChunk(net.minecraft.server.v1_9_R2.Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException { - if (tickAmount > 0) { - int j = chunk.locX * 16; - int k = chunk.locZ * 16; - - for (ChunkSection chunksection : chunk.getSections()) { - if (chunksection != net.minecraft.server.v1_9_R2.Chunk.a && chunksection.shouldTick()) { - for (int k1 = 0; k1 < tickAmount; ++k1) { - int worldL = (int) ReflectionUtils.getFieldValue(chunk.world, "l"); - worldL = worldL * 3 + 1013904223; - ReflectionUtils.setFieldValue(chunk.world, "l", worldL); - - int l1 = worldL >> 2; - int i2 = l1 & 15; - int j2 = l1 >> 8 & 15; - int k2 = l1 >> 16 & 15; - - IBlockData iblockdata = chunksection.getType(i2, k2, j2); - Block block = iblockdata.getBlock(); - - if (block.isTicking()) { - block.a(chunk.world, new BlockPosition(i2 + j, k2 + chunksection.getYPosition(), j2 + k), iblockdata, chunk.world.random); - } - } - } - } - } - } - } - - /** - * This class contains some modified methods from {@link MobSpawnerAbstract}. - */ - private static class NotchianBaseSpawner { - private static Method iMethod, hMethod; - - static { - try { - iMethod = MobSpawnerAbstract.class.getDeclaredMethod("i"); - iMethod.setAccessible(true); - - hMethod = MobSpawnerAbstract.class.getDeclaredMethod("h"); - hMethod.setAccessible(true); - } catch (NoSuchMethodException ex) { - Utils.logException(null, ex); - } - } - - static MobSpawnerAbstract getNotchianSpawner(CraftCreatureSpawner spawner) throws NoSuchFieldException, IllegalAccessException { - Object cTileEntity = ReflectionUtils.getFieldValue(spawner, "spawner"); - - return (MobSpawnerAbstract) ReflectionUtils.getFieldValue(cTileEntity, "a"); - } - - /** - * This method calls {@link MobSpawnerAbstract#h()} using Reflections. - */ - static boolean isNearPlayer(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { - return (boolean) hMethod.invoke(spawner); - } - - /** - * This method is based on {@link MobSpawnerAbstract#c()}. - * - * @return false if the spawner is not inactive, true otherwise - */ - static boolean tickInactiveSpawner(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException, NoSuchFieldException { - if (isNearPlayer(spawner)) return false; - - BlockPosition blockposition = spawner.b(); - - if (spawner.a().isClientSide) { - double d0 = (float) blockposition.getX() + spawner.a().random.nextFloat(); - double d1 = (float) blockposition.getY() + spawner.a().random.nextFloat(); - double d2 = (float) blockposition.getZ() + spawner.a().random.nextFloat(); - - spawner.a().addParticle(EnumParticle.SMOKE_NORMAL, d0, d1, d2, 0D, 0D, 0D); - spawner.a().addParticle(EnumParticle.FLAME, d0, d1, d2, 0D, 0D, 0D); - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - } - - double spawnerD = (double) ReflectionUtils.getFieldValue(spawner, "d"); - - ReflectionUtils.setFieldValue(spawner, "e", spawnerD); - ReflectionUtils.setFieldValue(spawner, "d", (spawnerD + (double) (1000F / ((float) spawner.spawnDelay + 200F))) % 360D); - } else { - if (spawner.spawnDelay == -1) { - delay(spawner); - } - - if (spawner.spawnDelay > 0) { - --spawner.spawnDelay; - return true; - } - - boolean flag = false; - int i = 0; - - int spawnCount = (int) ReflectionUtils.getFieldValue(spawner, "spawnCount"); - int spawnRange = (int) ReflectionUtils.getFieldValue(spawner, "spawnRange"); - int maxNearbyEntities = (int) ReflectionUtils.getFieldValue(spawner, "maxNearbyEntities"); - MobSpawnerData spawnData = (MobSpawnerData) ReflectionUtils.getFieldValue(spawner, "spawnData"); - - while (true) { - if (i >= spawnCount) { - if (flag) { - delay(spawner); - } - break; - } - - NBTTagCompound nbttagcompound = spawnData.b(); - NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6); - net.minecraft.server.v1_9_R2.World world = spawner.a(); - int j = nbttaglist.size(); - double d3 = j >= 1 ? nbttaglist.e(0) : (double) blockposition.getX() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; - double d4 = j >= 2 ? nbttaglist.e(1) : (double) (blockposition.getY() + world.random.nextInt(3) - 1); - double d5 = j >= 3 ? nbttaglist.e(2) : (double) blockposition.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) spawnRange + .5D; - Entity entity = ChunkRegionLoader.a(nbttagcompound, world, d3, d4, d5, false); - if (entity == null) { - return true; - } - - int k = world.a(entity.getClass(), (new AxisAlignedBB( - blockposition.getX(), - blockposition.getY(), - blockposition.getZ(), - blockposition.getX() + 1, - blockposition.getY() + 1, - blockposition.getZ() + 1)) - .g(spawnRange)).size(); - if (k >= maxNearbyEntities) { - delay(spawner); - return true; - } - - EntityInsentient entityinsentient = entity instanceof EntityInsentient ? (EntityInsentient) entity : null; - entity.setPositionRotation(entity.locX, entity.locY, entity.locZ, world.random.nextFloat() * 360.0F, 0.0F); - if (entityinsentient == null || entityinsentient.cG() && entityinsentient.canSpawn()) { - if (spawnData.b().d() == 1 && spawnData.b().hasKeyOfType("id", 8) && entity instanceof EntityInsentient) { - ((EntityInsentient) entity).prepare(world.D(new BlockPosition(entity)), null); - } - - if (entity.world.spigotConfig.nerfSpawnerMobs) { - entity.fromMobSpawner = true; - } - - if (!CraftEventFactory.callSpawnerSpawnEvent(entity, blockposition).isCancelled()) { - ChunkRegionLoader.a(entity, world, CreatureSpawnEvent.SpawnReason.SPAWNER); - world.triggerEffect(2004, blockposition, 0); - if (entityinsentient != null) { - entityinsentient.doSpawnEffect(); - } - - flag = true; - } - } - - ++i; - } - } - - return true; - } - - /** - * This method is based on {@link MobSpawnerAbstract#i()}. - */ - static void delay(MobSpawnerAbstract spawner) throws InvocationTargetException, IllegalAccessException { - iMethod.invoke(spawner); - } - } -} diff --git a/pom.xml b/pom.xml index fab5a32..9d3f868 100644 --- a/pom.xml +++ b/pom.xml @@ -6,31 +6,9 @@ com.songoda EpicAnchors - pom 2.0.0-ALPHA - - modules/epicanchors-api - modules/epicanchors-plugin - - modules/nms/epicanchors-v1_16_R3 - modules/nms/epicanchors-v1_16_R2 - modules/nms/epicanchors-v1_16_R1 - modules/nms/epicanchors-v1_15_R1 - modules/nms/epicanchors-v1_14_R1 - modules/nms/epicanchors-v1_13_R2 - modules/nms/epicanchors-v1_13_R1 - modules/nms/epicanchors-v1_12_R1 - modules/nms/epicanchors-v1_11_R1 - modules/nms/epicanchors-v1_10_R1 - modules/nms/epicanchors-v1_9_R2 - modules/nms/epicanchors-v1_9_R1 - modules/nms/epicanchors-v1_8_R3 - modules/nms/epicanchors-v1_8_R2 - modules/nms/epicanchors-v1_8_R1 - - EpicAnchors Allow your players to keep chunks loaded for a limited amount of time for a cost. https://songoda.com/marketplace/product/31 @@ -71,9 +49,84 @@ ${java.release} + + + org.apache.maven.plugins + maven-shade-plugin + 3.3.0-SNAPSHOT + + + + package + + + shade + + + + ${project.name}-${project.version} + + false + true + + + + com.songoda.core + com.songoda.epicanchors.core + + + + epicanchors.nms + com.songoda.epicanchors.nms + + + + + + *:* + + + META-INF/** + LICENSE + LICENSE.** + + + + + org.jetbrains:annotations + + ** + + + + + com.songoda:epicanchors-v* + + ** + + + + + + + + + + + src/main/resources + true + + + + + apache.snapshots + https://repository.apache.org/snapshots/ + + + spigotmc-repo @@ -87,6 +140,20 @@ + + org.spigotmc + spigot-api + 1.8-R0.1-SNAPSHOT + provided + + + + com.songoda + SongodaCore + 2.5.7 + compile + + org.jetbrains diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/Anchor.java b/src/main/java/com/songoda/epicanchors/Anchor.java similarity index 88% rename from modules/epicanchors-api/src/main/java/com/songoda/epicanchors/Anchor.java rename to src/main/java/com/songoda/epicanchors/Anchor.java index 87b479b..2268a61 100644 --- a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/Anchor.java +++ b/src/main/java/com/songoda/epicanchors/Anchor.java @@ -1,5 +1,6 @@ package com.songoda.epicanchors; +import com.songoda.epicanchors.utils.WorldUtils; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Location; @@ -40,11 +41,11 @@ public class Anchor { * @see Bukkit#isPrimaryThread() * @see org.bukkit.scheduler.BukkitScheduler#runTask(Plugin, Runnable) */ - protected void init(AnchorNMS nms) { + protected void init(Plugin plugin) { if (Bukkit.isPrimaryThread()) { - nms.loadAnchoredChunk(getChunk()); + WorldUtils.loadAnchoredChunk(getChunk(), plugin); } else { - Bukkit.getScheduler().runTask(nms.plugin, () -> init(nms)); + Bukkit.getScheduler().runTask(plugin, () -> init(plugin)); } } @@ -55,13 +56,13 @@ public class Anchor { * @see Bukkit#isPrimaryThread() * @see org.bukkit.scheduler.BukkitScheduler#runTask(Plugin, Runnable) */ - protected void deInit(AnchorNMS nms) { + protected void deInit(Plugin plugin) { // TODO: Document that holograms are not removed or add boolean flag to remove them if (Bukkit.isPrimaryThread()) { - nms.unloadAnchoredChunk(getChunk()); + WorldUtils.unloadAnchoredChunk(getChunk(), plugin); } else { - Bukkit.getScheduler().runTask(nms.plugin, () -> deInit(nms)); + Bukkit.getScheduler().runTask(plugin, () -> deInit(plugin)); } } diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorManager.java b/src/main/java/com/songoda/epicanchors/AnchorManager.java similarity index 98% rename from modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorManager.java rename to src/main/java/com/songoda/epicanchors/AnchorManager.java index 9a0fad0..d3952e0 100644 --- a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorManager.java +++ b/src/main/java/com/songoda/epicanchors/AnchorManager.java @@ -9,6 +9,7 @@ import com.songoda.core.nms.NmsManager; import com.songoda.core.nms.nbt.NBTItem; import com.songoda.core.utils.TextUtils; import com.songoda.core.utils.TimeUtils; +import com.songoda.epicanchors.api.AnchorAccessCheck; import com.songoda.epicanchors.files.DataManager; import com.songoda.epicanchors.files.Settings; import com.songoda.epicanchors.utils.Callback; @@ -46,7 +47,6 @@ public class AnchorManager { private final SongodaPlugin plugin; private final DataManager dataManager; - private final AnchorNMS nms; private final Map> anchors = new HashMap<>(3); private final Set visualizedChunk = new HashSet<>(); @@ -54,10 +54,9 @@ public class AnchorManager { private boolean ready; - public AnchorManager(SongodaPlugin plugin, DataManager dataManager, AnchorNMS nms) { + public AnchorManager(SongodaPlugin plugin, DataManager dataManager) { this.plugin = Objects.requireNonNull(plugin); this.dataManager = Objects.requireNonNull(dataManager); - this.nms = Objects.requireNonNull(nms); staticPluginInstance = plugin; } @@ -90,7 +89,7 @@ public class AnchorManager { this.anchors.computeIfAbsent(world, k -> new HashSet<>()); for (Anchor anchor : result) { - anchor.init(this.nms); + anchor.init(this.plugin); this.anchors.computeIfAbsent(anchor.getWorld(), k -> new HashSet<>()) .add(anchor); @@ -120,7 +119,7 @@ public class AnchorManager { this.dataManager.updateAnchors(tmpAnchors, null); for (Anchor anchor : tmpAnchors) { - anchor.deInit(this.nms); + anchor.deInit(this.plugin); } } } @@ -131,10 +130,6 @@ public class AnchorManager { Bukkit.getScheduler().runTaskTimer(plugin, this::saveAll, 20L * 60 * 5, 20L * 60 * 5); } - public AnchorNMS getNMS() { - return this.nms; - } - @SuppressWarnings("BooleanMethodIsAlwaysInverted") public boolean isReady(World world) { return this.ready && anchors.containsKey(world); @@ -294,7 +289,7 @@ public class AnchorManager { CompatibleParticleHandler.spawnParticles(CompatibleParticleHandler.ParticleType.getParticle(Settings.PARTICLE_DESTROY.getString()), anchor.getLocation().add(.5, .5, .5), 100, .5, .5, .5); - anchor.deInit(this.nms); + anchor.deInit(this.plugin); this.dataManager.deleteAnchorAsync(anchor); } diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/EpicAnchors.java b/src/main/java/com/songoda/epicanchors/EpicAnchors.java similarity index 74% rename from modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/EpicAnchors.java rename to src/main/java/com/songoda/epicanchors/EpicAnchors.java index fa0b125..3cae57b 100644 --- a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/EpicAnchors.java +++ b/src/main/java/com/songoda/epicanchors/EpicAnchors.java @@ -4,7 +4,6 @@ import com.songoda.core.SongodaCore; import com.songoda.core.SongodaPlugin; import com.songoda.core.commands.CommandManager; import com.songoda.core.compatibility.CompatibleMaterial; -import com.songoda.core.compatibility.ServerVersion; import com.songoda.core.configuration.Config; import com.songoda.core.database.DatabaseConnector; import com.songoda.core.database.SQLiteConnector; @@ -27,9 +26,7 @@ import com.songoda.epicanchors.listener.WorldListener; import com.songoda.epicanchors.tasks.AnchorTask; import com.songoda.epicanchors.tasks.VisualizeTask; import com.songoda.epicanchors.utils.ThreadSync; -import com.songoda.epicanchors.utils.Utils; import org.bukkit.Bukkit; -import org.bukkit.Chunk; import org.bukkit.World; import org.bukkit.plugin.PluginManager; @@ -62,7 +59,7 @@ public final class EpicAnchors extends SongodaPlugin { anchorMigration.runMigrations(); anchorMigration.migrateLegacyData(this); - this.anchorManager = new AnchorManager(this, this.dataManager, createAnchorNMS()); + this.anchorManager = new AnchorManager(this, this.dataManager); // Economy [1/2] EconomyManager.load(); @@ -160,49 +157,4 @@ public final class EpicAnchors extends SongodaPlugin { public AnchorManager getAnchorManager() { return this.anchorManager; } - - private AnchorNMS createAnchorNMS() { - try { - // Try loading NMS class - return (AnchorNMS) Class.forName("epicanchors.nms." + ServerVersion.getServerVersionString()).getConstructors()[0].newInstance(this); - } catch (Exception ex) { - if (!(ex instanceof ClassNotFoundException)) { - Utils.logException(this, ex); - } - - getLogger().warning("Your server version (" + ServerVersion.getServerVersionString() + ") is not fully supported yet!"); - getLogger().warning(getName() + " will do its best, but features like plant growth or spawners require an update"); - - return new AnchorNMS(this) { - @Override - public boolean loadAnchoredChunk(Chunk chunk) { - return chunk.load(); - } - - @Override - public boolean unloadAnchoredChunk(Chunk chunk) { - return chunk.unload(); - } - - @Override - public void tickInactiveSpawners(Chunk chunk, int amount) { - // Sadly nothing we can do here - } - - @Override - public void doRandomTick(Chunk chunk, int tickAmount) { - // Sadly nothing we can do here - } - - @Override - public int getRandomTickSpeed(World world) { - try { - return Integer.parseInt(world.getGameRuleValue("randomTickSpeed")); - } catch (NumberFormatException ignore) { - return 3; - } - } - }; - } - } } diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorAccessCheck.java b/src/main/java/com/songoda/epicanchors/api/AnchorAccessCheck.java similarity index 69% rename from modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorAccessCheck.java rename to src/main/java/com/songoda/epicanchors/api/AnchorAccessCheck.java index e943eac..66b58f5 100644 --- a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/AnchorAccessCheck.java +++ b/src/main/java/com/songoda/epicanchors/api/AnchorAccessCheck.java @@ -1,5 +1,6 @@ -package com.songoda.epicanchors; +package com.songoda.epicanchors.api; +import com.songoda.epicanchors.Anchor; import org.jetbrains.annotations.NotNull; import java.util.UUID; diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/EpicAnchorsCommand.java b/src/main/java/com/songoda/epicanchors/commands/EpicAnchorsCommand.java similarity index 100% rename from modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/EpicAnchorsCommand.java rename to src/main/java/com/songoda/epicanchors/commands/EpicAnchorsCommand.java diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/GiveCommand.java b/src/main/java/com/songoda/epicanchors/commands/sub/GiveCommand.java similarity index 100% rename from modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/GiveCommand.java rename to src/main/java/com/songoda/epicanchors/commands/sub/GiveCommand.java diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/ReloadCommand.java b/src/main/java/com/songoda/epicanchors/commands/sub/ReloadCommand.java similarity index 100% rename from modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/ReloadCommand.java rename to src/main/java/com/songoda/epicanchors/commands/sub/ReloadCommand.java diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/SettingsCommand.java b/src/main/java/com/songoda/epicanchors/commands/sub/SettingsCommand.java similarity index 100% rename from modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/SettingsCommand.java rename to src/main/java/com/songoda/epicanchors/commands/sub/SettingsCommand.java diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/ShowCommand.java b/src/main/java/com/songoda/epicanchors/commands/sub/ShowCommand.java similarity index 100% rename from modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/commands/sub/ShowCommand.java rename to src/main/java/com/songoda/epicanchors/commands/sub/ShowCommand.java diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/DataManager.java b/src/main/java/com/songoda/epicanchors/files/DataManager.java similarity index 100% rename from modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/DataManager.java rename to src/main/java/com/songoda/epicanchors/files/DataManager.java diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/Settings.java b/src/main/java/com/songoda/epicanchors/files/Settings.java similarity index 100% rename from modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/Settings.java rename to src/main/java/com/songoda/epicanchors/files/Settings.java diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/migration/AnchorMigration.java b/src/main/java/com/songoda/epicanchors/files/migration/AnchorMigration.java similarity index 100% rename from modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/migration/AnchorMigration.java rename to src/main/java/com/songoda/epicanchors/files/migration/AnchorMigration.java diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/migration/_1_InitialMigration.java b/src/main/java/com/songoda/epicanchors/files/migration/_1_InitialMigration.java similarity index 100% rename from modules/epicanchors-api/src/main/java/com/songoda/epicanchors/files/migration/_1_InitialMigration.java rename to src/main/java/com/songoda/epicanchors/files/migration/_1_InitialMigration.java diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/guis/AnchorGui.java b/src/main/java/com/songoda/epicanchors/guis/AnchorGui.java similarity index 100% rename from modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/guis/AnchorGui.java rename to src/main/java/com/songoda/epicanchors/guis/AnchorGui.java diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/guis/DestroyConfirmationGui.java b/src/main/java/com/songoda/epicanchors/guis/DestroyConfirmationGui.java similarity index 100% rename from modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/guis/DestroyConfirmationGui.java rename to src/main/java/com/songoda/epicanchors/guis/DestroyConfirmationGui.java diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/AnchorListener.java b/src/main/java/com/songoda/epicanchors/listener/AnchorListener.java similarity index 100% rename from modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/AnchorListener.java rename to src/main/java/com/songoda/epicanchors/listener/AnchorListener.java diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/BlockListener.java b/src/main/java/com/songoda/epicanchors/listener/BlockListener.java similarity index 100% rename from modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/BlockListener.java rename to src/main/java/com/songoda/epicanchors/listener/BlockListener.java diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/DebugListener.java b/src/main/java/com/songoda/epicanchors/listener/DebugListener.java similarity index 100% rename from modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/DebugListener.java rename to src/main/java/com/songoda/epicanchors/listener/DebugListener.java diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/WorldListener.java b/src/main/java/com/songoda/epicanchors/listener/WorldListener.java similarity index 100% rename from modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/listener/WorldListener.java rename to src/main/java/com/songoda/epicanchors/listener/WorldListener.java diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/tasks/AnchorTask.java b/src/main/java/com/songoda/epicanchors/tasks/AnchorTask.java similarity index 66% rename from modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/tasks/AnchorTask.java rename to src/main/java/com/songoda/epicanchors/tasks/AnchorTask.java index 4dd2566..dea6ec5 100644 --- a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/tasks/AnchorTask.java +++ b/src/main/java/com/songoda/epicanchors/tasks/AnchorTask.java @@ -1,9 +1,11 @@ package com.songoda.epicanchors.tasks; +import com.songoda.core.nms.NmsManager; import com.songoda.epicanchors.Anchor; import com.songoda.epicanchors.AnchorManager; import com.songoda.epicanchors.EpicAnchors; import com.songoda.epicanchors.utils.Utils; +import com.songoda.epicanchors.utils.WorldUtils; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.World; @@ -14,6 +16,7 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.logging.Level; /** * More information about what types of game ticks there are and what does what: https://minecraft.fandom.com/wiki/Tick @@ -24,6 +27,9 @@ public class AnchorTask extends BukkitRunnable { private final EpicAnchors plugin; private final AnchorManager anchorManager; + private boolean randomTicksFailed; + private boolean spawnerTicksFailed; + public AnchorTask(EpicAnchors plugin) { this.plugin = plugin; this.anchorManager = plugin.getAnchorManager(); @@ -39,7 +45,7 @@ public class AnchorTask extends BukkitRunnable { for (World world : Bukkit.getWorlds()) { if (!this.anchorManager.isReady(world)) return; - int randomTicks = this.anchorManager.getNMS().getRandomTickSpeed(world) * TASK_INTERVAL; + int randomTicks = WorldUtils.getRandomTickSpeed(world) * TASK_INTERVAL; Set alreadyTicked = new HashSet<>(); Anchor[] anchorsInWorld = this.anchorManager.getAnchors(world); @@ -60,12 +66,32 @@ public class AnchorTask extends BukkitRunnable { // Loading an already loaded chunk still fires the ChunkLoadEvent and might have a huge // impact on performance if other plugins do not expect that either... - this.anchorManager.getNMS().loadAnchoredChunk(chunk); - chunk.load(); + WorldUtils.loadAnchoredChunk(chunk, this.plugin); } - this.anchorManager.getNMS().doRandomTick(chunk, randomTicks); - this.anchorManager.getNMS().tickInactiveSpawners(chunk, TASK_INTERVAL); + if (!randomTicksFailed) { + try { + NmsManager.getWorld().randomTickChunk(chunk, randomTicks); + } catch (NoSuchFieldException | IllegalAccessException ex) { + this.plugin.getLogger().log(Level.FINER, ex, + () -> "Failed to do random ticks on this server implementation(/version) - " + + "Skipping further random ticks."); + + randomTicksFailed = true; + } + } + + if (!spawnerTicksFailed) { + try { + NmsManager.getWorld().tickInactiveSpawners(chunk, TASK_INTERVAL); + } catch (NoSuchFieldException | IllegalAccessException ex) { + this.plugin.getLogger().log(Level.FINER, ex, + () -> "Failed to do spawner ticks on this server implementation(/version) - " + + "Skipping further spawner ticks."); + + spawnerTicksFailed = true; + } + } } // TODO: Only update hologram if a player is nearby diff --git a/modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/tasks/VisualizeTask.java b/src/main/java/com/songoda/epicanchors/tasks/VisualizeTask.java similarity index 100% rename from modules/epicanchors-plugin/src/main/java/com/songoda/epicanchors/tasks/VisualizeTask.java rename to src/main/java/com/songoda/epicanchors/tasks/VisualizeTask.java diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/Callback.java b/src/main/java/com/songoda/epicanchors/utils/Callback.java similarity index 100% rename from modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/Callback.java rename to src/main/java/com/songoda/epicanchors/utils/Callback.java diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/ReflectionUtils.java b/src/main/java/com/songoda/epicanchors/utils/ReflectionUtils.java similarity index 100% rename from modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/ReflectionUtils.java rename to src/main/java/com/songoda/epicanchors/utils/ReflectionUtils.java diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/ThreadSync.java b/src/main/java/com/songoda/epicanchors/utils/ThreadSync.java similarity index 100% rename from modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/ThreadSync.java rename to src/main/java/com/songoda/epicanchors/utils/ThreadSync.java diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/UpdateCallback.java b/src/main/java/com/songoda/epicanchors/utils/UpdateCallback.java similarity index 100% rename from modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/UpdateCallback.java rename to src/main/java/com/songoda/epicanchors/utils/UpdateCallback.java diff --git a/modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/Utils.java b/src/main/java/com/songoda/epicanchors/utils/Utils.java similarity index 100% rename from modules/epicanchors-api/src/main/java/com/songoda/epicanchors/utils/Utils.java rename to src/main/java/com/songoda/epicanchors/utils/Utils.java diff --git a/src/main/java/com/songoda/epicanchors/utils/WorldUtils.java b/src/main/java/com/songoda/epicanchors/utils/WorldUtils.java new file mode 100644 index 0000000..810ab31 --- /dev/null +++ b/src/main/java/com/songoda/epicanchors/utils/WorldUtils.java @@ -0,0 +1,66 @@ +package com.songoda.epicanchors.utils; + +import org.bukkit.Chunk; +import org.bukkit.World; +import org.bukkit.plugin.Plugin; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +@SuppressWarnings("JavaReflectionMemberAccess") +public class WorldUtils { + private WorldUtils() { + throw new IllegalStateException("Utility class"); + } + + private static final Method addChunkTicketMethod; + private static final Method removeChunkTicketMethod; + + static { + Method tmpAdd; + Method tmpRem; + + try { + tmpAdd = Chunk.class.getDeclaredMethod("addPluginChunkTicket", Plugin.class); + tmpRem = Chunk.class.getDeclaredMethod("removePluginChunkTicket", Plugin.class); + } catch (NoSuchMethodException ignore) { + tmpAdd = null; + tmpRem = null; + } + + addChunkTicketMethod = tmpAdd; + removeChunkTicketMethod = tmpRem; + } + + public static int getRandomTickSpeed(World world) { + try { + return Integer.parseInt(world.getGameRuleValue("randomTickSpeed")); + } catch (NumberFormatException ignore) { + return 3; + } + } + + public static boolean loadAnchoredChunk(Chunk chunk, Plugin plugin) { + if (addChunkTicketMethod != null) { + try { + return (boolean) addChunkTicketMethod.invoke(chunk, plugin); + } catch (IllegalAccessException | InvocationTargetException ex) { + Utils.logException(plugin, ex); + } + } + + return chunk.load(); + } + + public static boolean unloadAnchoredChunk(Chunk chunk, Plugin plugin) { + if (removeChunkTicketMethod != null) { + try { + removeChunkTicketMethod.invoke(chunk, plugin); + } catch (IllegalAccessException | InvocationTargetException ex) { + Utils.logException(plugin, ex); + } + } + + return chunk.unload(); + } +} diff --git a/modules/epicanchors-plugin/src/main/resources/en_US.lang b/src/main/resources/en_US.lang similarity index 100% rename from modules/epicanchors-plugin/src/main/resources/en_US.lang rename to src/main/resources/en_US.lang diff --git a/modules/epicanchors-plugin/src/main/resources/plugin.yml b/src/main/resources/plugin.yml similarity index 74% rename from modules/epicanchors-plugin/src/main/resources/plugin.yml rename to src/main/resources/plugin.yml index 21bf3bf..a5da9fe 100644 --- a/modules/epicanchors-plugin/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ -name: ${project.parent.name} -description: ${project.parent.description} -version: ${project.parent.version} +name: ${project.name} +description: ${project.description} +version: ${project.version} api-version: 1.13 main: com.songoda.epicanchors.EpicAnchors @@ -11,7 +11,7 @@ softdepend: author: Songoda authors: [ SpraxDev ] -website: ${project.parent.url} +website: ${project.url} commands: EpicAnchors: From be45a47b61f6a4faf25ac60c8d73d03f311da78b Mon Sep 17 00:00:00 2001 From: Christian Koop Date: Tue, 20 Jul 2021 15:02:53 +0200 Subject: [PATCH 07/12] README.md: Fixed URLs still pointing to my forked project --- LICENSE | 2 +- README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/LICENSE b/LICENSE index 18b94c9..dd5f0d5 100644 --- a/LICENSE +++ b/LICENSE @@ -6,4 +6,4 @@ The same distribution rights and limitations above shall similarly apply to any The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index eab8ce6..2f3c38d 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,9 @@ [![Discord](https://img.shields.io/discord/293212540723396608?color=7289DA&label=Discord&logo=discord&logoColor=7289DA)](https://discord.gg/songoda) [![Patreon](https://img.shields.io/badge/-Support_on_Patreon-F96854.svg?logo=patreon&style=flat&logoColor=white)](https://www.patreon.com/join/songoda)
-[![Latest version](https://img.shields.io/github/v/tag/SpraxDev/EpicAnchors?include_prereleases&label=Latest&logo=github&labelColor=black)](https://songoda.com/marketplace/product/31) +[![Latest version](https://img.shields.io/github/v/tag/songoda/EpicAnchors?include_prereleases&label=Latest&logo=github&labelColor=black)](https://songoda.com/marketplace/product/31) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=songoda_EpicAnchors&metric=alert_status)](https://sonarcloud.io/dashboard?id=songoda_EpicAnchors) -[![GitHub last commit](https://img.shields.io/github/last-commit/SpraxDev/EpicAnchors?label=Last+commit)](https://github.com/SpraxDev/EpicAnchors/commits) +[![GitHub last commit](https://img.shields.io/github/last-commit/songoda/EpicAnchors?label=Last+commit)](https://github.com/songoda/EpicAnchors/commits)
[![bStats Servers](https://img.shields.io/bstats/servers/4816?label=Servers)](https://bstats.org/plugin/bukkit/EpicAnchors/4816) From ced16e6c7e66710ac31dd7911b8cc2ecd499fe0e Mon Sep 17 00:00:00 2001 From: Christian Koop Date: Tue, 20 Jul 2021 17:06:54 +0200 Subject: [PATCH 08/12] Update Core to v2.5.8 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9d3f868..7dd2b72 100644 --- a/pom.xml +++ b/pom.xml @@ -150,7 +150,7 @@ com.songoda SongodaCore - 2.5.7 + 2.5.8 compile From 431005e01ad2e332bf7871a129d34d5ea4ad2f00 Mon Sep 17 00:00:00 2001 From: Christian Koop Date: Tue, 20 Jul 2021 17:06:36 +0200 Subject: [PATCH 09/12] Code cleanup for production --- .../java/com/songoda/epicanchors/AnchorManager.java | 10 ---------- src/main/java/com/songoda/epicanchors/EpicAnchors.java | 7 ------- .../java/com/songoda/epicanchors/files/Settings.java | 4 ++-- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/songoda/epicanchors/AnchorManager.java b/src/main/java/com/songoda/epicanchors/AnchorManager.java index d3952e0..88513f8 100644 --- a/src/main/java/com/songoda/epicanchors/AnchorManager.java +++ b/src/main/java/com/songoda/epicanchors/AnchorManager.java @@ -43,7 +43,6 @@ import java.util.concurrent.TimeUnit; public class AnchorManager { private static final String ERR_WORLD_NOT_READY = "EpicAnchors has not finished initializing that world yet"; private static final String NBT_TICKS_KEY = "EpicAnchors_Ticks".toLowerCase(); - private static SongodaPlugin staticPluginInstance; // For internal use only TODO: Find a better way for doing this private final SongodaPlugin plugin; private final DataManager dataManager; @@ -57,8 +56,6 @@ public class AnchorManager { public AnchorManager(SongodaPlugin plugin, DataManager dataManager) { this.plugin = Objects.requireNonNull(plugin); this.dataManager = Objects.requireNonNull(dataManager); - - staticPluginInstance = plugin; } protected void saveAll() { @@ -471,11 +468,4 @@ public class AnchorManager { private static void removeHologram(Anchor anchor) { HologramManager.removeHologram(anchor.getLocation()); } - - /** - * For internal use only - */ - public static SongodaPlugin getPlugin() { - return staticPluginInstance; - } } diff --git a/src/main/java/com/songoda/epicanchors/EpicAnchors.java b/src/main/java/com/songoda/epicanchors/EpicAnchors.java index 3cae57b..d4b313a 100644 --- a/src/main/java/com/songoda/epicanchors/EpicAnchors.java +++ b/src/main/java/com/songoda/epicanchors/EpicAnchors.java @@ -21,7 +21,6 @@ import com.songoda.epicanchors.files.migration.AnchorMigration; import com.songoda.epicanchors.files.migration._1_InitialMigration; import com.songoda.epicanchors.listener.AnchorListener; import com.songoda.epicanchors.listener.BlockListener; -import com.songoda.epicanchors.listener.DebugListener; import com.songoda.epicanchors.listener.WorldListener; import com.songoda.epicanchors.tasks.AnchorTask; import com.songoda.epicanchors.tasks.VisualizeTask; @@ -30,7 +29,6 @@ import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.plugin.PluginManager; -import java.io.File; import java.util.Collections; import java.util.List; import java.util.logging.Level; @@ -94,11 +92,6 @@ public final class EpicAnchors extends SongodaPlugin { new SettingsCommand(this, this.guiManager), new ShowCommand(this) ); - - // TODO: remove debug - if (!new File(getDataFolder(), "no-debug.txt").exists()) { - Bukkit.getPluginManager().registerEvents(new DebugListener(this), this); - } } @Override diff --git a/src/main/java/com/songoda/epicanchors/files/Settings.java b/src/main/java/com/songoda/epicanchors/files/Settings.java index 58d96ac..855a55b 100644 --- a/src/main/java/com/songoda/epicanchors/files/Settings.java +++ b/src/main/java/com/songoda/epicanchors/files/Settings.java @@ -5,14 +5,14 @@ import com.songoda.core.compatibility.CompatibleParticleHandler; import com.songoda.core.configuration.Config; import com.songoda.core.configuration.ConfigSetting; import com.songoda.core.hooks.EconomyManager; -import com.songoda.epicanchors.AnchorManager; +import com.songoda.epicanchors.EpicAnchors; public class Settings { private Settings() { throw new IllegalStateException("Utility class"); } - public static final Config config = AnchorManager.getPlugin().getCoreConfig(); + public static final Config config = EpicAnchors.getPlugin(EpicAnchors.class).getCoreConfig(); public static final ConfigSetting NAME_TAG = new ConfigSetting(config, "Main.Name Tag", "&6Anchor &8(&7{REMAINING}&8)", From db4cc5944f042e64247b3003f1213b225f5c94b4 Mon Sep 17 00:00:00 2001 From: Christian Koop Date: Tue, 20 Jul 2021 18:37:13 +0200 Subject: [PATCH 10/12] Vastly increase legacy data migration speed Going from 9 seconds to 486ms a --- .../epicanchors/files/DataManager.java | 21 +++++++++++++------ .../songoda/epicanchors/files/Settings.java | 3 ++- .../files/migration/AnchorMigration.java | 6 ++---- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/songoda/epicanchors/files/DataManager.java b/src/main/java/com/songoda/epicanchors/files/DataManager.java index e0922d2..21ad7d0 100644 --- a/src/main/java/com/songoda/epicanchors/files/DataManager.java +++ b/src/main/java/com/songoda/epicanchors/files/DataManager.java @@ -17,6 +17,7 @@ import org.jetbrains.annotations.Nullable; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -141,9 +142,9 @@ public class DataManager extends DataManagerAbstract { SQLException err = null; - for (AnchorMigration.LegacyAnchorEntry entry : anchorEntries) { - try (PreparedStatement ps = con.prepareStatement("INSERT INTO " + this.anchorTable + - "(world_name,x,y,z, ticks_left) VALUES (?,?,?,?, ?);")) { + try (PreparedStatement ps = con.prepareStatement("INSERT INTO " + this.anchorTable + + "(world_name,x,y,z, ticks_left) VALUES (?,?,?,?, ?);")) { + for (AnchorMigration.LegacyAnchorEntry entry : anchorEntries) { ps.setString(1, entry.worldName); ps.setInt(2, entry.x); ps.setInt(3, entry.y); @@ -151,10 +152,18 @@ public class DataManager extends DataManagerAbstract { ps.setInt(5, entry.ticksLeft); - ps.executeUpdate(); - } catch (SQLException ex) { - err = ex; + ps.addBatch(); } + + int[] batchRes = ps.executeBatch(); + + for (int i : batchRes) { + if (i < 0 && i != Statement.SUCCESS_NO_INFO) { + throw new AssertionError("Batch-INSERT failed for at least one statement with code " + i + ""); + } + } + } catch (SQLException ex) { + err = ex; } if (err == null) { diff --git a/src/main/java/com/songoda/epicanchors/files/Settings.java b/src/main/java/com/songoda/epicanchors/files/Settings.java index 855a55b..599409f 100644 --- a/src/main/java/com/songoda/epicanchors/files/Settings.java +++ b/src/main/java/com/songoda/epicanchors/files/Settings.java @@ -6,13 +6,14 @@ import com.songoda.core.configuration.Config; import com.songoda.core.configuration.ConfigSetting; import com.songoda.core.hooks.EconomyManager; import com.songoda.epicanchors.EpicAnchors; +import org.bukkit.plugin.java.JavaPlugin; public class Settings { private Settings() { throw new IllegalStateException("Utility class"); } - public static final Config config = EpicAnchors.getPlugin(EpicAnchors.class).getCoreConfig(); + public static final Config config = JavaPlugin.getPlugin(EpicAnchors.class).getCoreConfig(); public static final ConfigSetting NAME_TAG = new ConfigSetting(config, "Main.Name Tag", "&6Anchor &8(&7{REMAINING}&8)", diff --git a/src/main/java/com/songoda/epicanchors/files/migration/AnchorMigration.java b/src/main/java/com/songoda/epicanchors/files/migration/AnchorMigration.java index 765e3c5..8899362 100644 --- a/src/main/java/com/songoda/epicanchors/files/migration/AnchorMigration.java +++ b/src/main/java/com/songoda/epicanchors/files/migration/AnchorMigration.java @@ -8,7 +8,7 @@ import com.songoda.core.database.DatabaseConnector; import com.songoda.epicanchors.files.DataManager; import com.songoda.epicanchors.utils.ThreadSync; import org.bukkit.Location; -import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.plugin.Plugin; import java.io.IOException; import java.nio.file.Files; @@ -27,9 +27,7 @@ public class AnchorMigration extends DataMigrationManager { this.dataManager = dataManager; } - // TODO: Migration of a lot of Anchors takes **very** long (1100 anchors => 9 seconds) - // This is easily fixed by putting all inserts into one big transaction but prevents us from - public void migrateLegacyData(JavaPlugin plugin) { + public void migrateLegacyData(Plugin plugin) { long start = System.nanoTime(); AtomicBoolean abortMigration = new AtomicBoolean(false); From a2fe37c3d8381e1e321cf3d0daf5417b2f853c6d Mon Sep 17 00:00:00 2001 From: Christian Koop Date: Tue, 20 Jul 2021 18:09:50 +0200 Subject: [PATCH 11/12] GitHub-Actions: Report build result to Discord Webhook --- .github/workflows/maven.yml | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 250ece3..456bedc 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -2,7 +2,7 @@ name: 'Build & Test' on: push: - branches: [ master, development ] + branches: [ master, development, full-recode ] pull_request: types: [ opened, synchronize, reopened ] @@ -39,6 +39,26 @@ jobs: name: EpicAnchors-artifacts path: ./target/EpicAnchors-*.jar + ## + # Discord Webhook + # TODO: Extract into external Action for better re-usability (and readability) [Copied SongodaCore] + ## + - name: 'Discord Webhook (Success)' + if: ${{ success() && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/development' || github.ref == 'refs/heads/full-recode') }} + continue-on-error: true + run: | + curl -X POST --data "{\"content\":null,\"embeds\":[{\"title\":\"Build succeeded!\",\"description\":\"The build with the ID #$GITHUB_RUN_NUMBER has succeeded!\",\"url\":\"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID\",\"color\":5490477,\"fields\":[{\"name\":\"Branch\",\"value\":\"$GITHUB_REF\",\"inline\":true}],\"author\":{\"name\":\"$GITHUB_REPOSITORY\",\"url\":\"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY\",\"icon_url\":\"$GITHUB_SERVER_URL/songoda.png\"},\"footer\":{\"text\":\"Initiated by $GITHUB_ACTOR\",\"icon_url\":\"$GITHUB_SERVER_URL/$GITHUB_ACTOR.png\"}}],\"username\":\"OctoAgent\",\"avatar_url\":\"https://github.githubassets.com/images/modules/logos_page/Octocat.png\"}" --header 'Content-Type: application/json' $DISCORD_WEBHOOK + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_BUILD_STATUS_WEBHOOK }} + - name: 'Discord Webhook (Failure)' + if: ${{ failure() && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/development' || github.ref == 'refs/heads/full-recode') }} + continue-on-error: true + run: | + curl -X POST --data "{\"content\":null,\"embeds\":[{\"title\":\"Build failed!\",\"description\":\"The build with the ID #$GITHUB_RUN_NUMBER has failed!\",\"url\":\"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID\",\"color\":15611419,\"fields\":[{\"name\":\"Branch\",\"value\":\"$GITHUB_REF\",\"inline\":true}],\"author\":{\"name\":\"$GITHUB_REPOSITORY\",\"url\":\"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY\",\"icon_url\":\"$GITHUB_SERVER_URL/songoda.png\"},\"footer\":{\"text\":\"Initiated by $GITHUB_ACTOR\",\"icon_url\":\"$GITHUB_SERVER_URL/$GITHUB_ACTOR.png\"}}],\"username\":\"OctoAgent\",\"avatar_url\":\"https://github.githubassets.com/images/modules/logos_page/Octocat.png\"}" --header "Content-Type:application/json" $DISCORD_WEBHOOK + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_BUILD_STATUS_WEBHOOK }} + + sonarcloud: name: SonarCloud runs-on: ubuntu-latest From 36d23aa8bbd56a54b7b8d2696e90ffe0258626f0 Mon Sep 17 00:00:00 2001 From: Christian Koop Date: Tue, 20 Jul 2021 18:38:19 +0200 Subject: [PATCH 12/12] README.md: Automatically extract version from `pom.xml` for badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2f3c38d..32083db 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ [![Discord](https://img.shields.io/discord/293212540723396608?color=7289DA&label=Discord&logo=discord&logoColor=7289DA)](https://discord.gg/songoda) [![Patreon](https://img.shields.io/badge/-Support_on_Patreon-F96854.svg?logo=patreon&style=flat&logoColor=white)](https://www.patreon.com/join/songoda)
-[![Latest version](https://img.shields.io/github/v/tag/songoda/EpicAnchors?include_prereleases&label=Latest&logo=github&labelColor=black)](https://songoda.com/marketplace/product/31) +[![Latest version](https://img.shields.io/badge/dynamic/xml?style=flat&color=blue&logo=github&logoColor=white&label=Latest&url=https%3A%2F%2Fraw.githubusercontent.com%2Fsongoda%2FEpicAnchors%2Fmaster%2Fpom.xml&query=%2F*%5Blocal-name()%3D'project'%5D%2F*%5Blocal-name()%3D'version'%5D)](https://songoda.com/marketplace/product/31) [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=songoda_EpicAnchors&metric=alert_status)](https://sonarcloud.io/dashboard?id=songoda_EpicAnchors) [![GitHub last commit](https://img.shields.io/github/last-commit/songoda/EpicAnchors?label=Last+commit)](https://github.com/songoda/EpicAnchors/commits)