Full recode (v2.0.0-ALPHA)
This commit is contained in:
parent
9fd066624a
commit
fc838ce66a
|
@ -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
|
|
@ -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"
|
|
@ -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
|
|
@ -1,3 +1,6 @@
|
|||
.idea/*
|
||||
target/*
|
||||
EpicAnchors.iml
|
||||
/modules/*/target/
|
||||
/modules/nms/*/target/
|
||||
|
||||
# JetBrains IDEs
|
||||
/.idea/
|
||||
*.iml
|
||||
|
|
2
LICENSE
2
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:
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -0,0 +1,52 @@
|
|||
<!--suppress HtmlDeprecatedAttribute -->
|
||||
<div align="center">
|
||||
<img alt="EpicAnchors" src="https://cdn2.songoda.com/products/epicanchors/xTjYNZqmo1pVKZ1Za8YiLojGB6uM4bm6Bb0M5Spu.gif">
|
||||
|
||||
# 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.**
|
||||
|
||||
<!-- Shields -->
|
||||
[![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)
|
||||
<br>
|
||||
[![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)
|
||||
<br>
|
||||
[![bStats Servers](https://img.shields.io/bstats/servers/4816?label=Servers)](https://bstats.org/plugin/bukkit/EpicAnchors/4816)
|
||||
</div>
|
||||
|
||||
## 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).
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>EpicAnchors</artifactId>
|
||||
<version>2.0.0-ALPHA</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>epicanchors-api</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.8-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>SongodaCore</artifactId>
|
||||
<version>2.4.56</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* <b></b>This method is automatically synchronized with the server's main thread using
|
||||
* {@link org.bukkit.scheduler.BukkitScheduler#runTask(Plugin, Runnable)}</b>
|
||||
*
|
||||
* @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));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <b></b>This method is automatically synchronized with the server's main thread using
|
||||
* {@link org.bukkit.scheduler.BukkitScheduler#runTask(Plugin, Runnable)}</b>
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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<World, Set<Anchor>> anchors = new HashMap<>(3);
|
||||
private final Set<Player> visualizedChunk = new HashSet<>();
|
||||
private final List<AnchorAccessCheck> 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<Anchor> 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<Anchor> 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<Anchor> 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<Anchor> 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<Anchor> 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<Anchor> searchAnchors(Location center, double searchRadius) {
|
||||
return searchAnchors(center, searchRadius, false);
|
||||
}
|
||||
|
||||
public List<Anchor> searchAnchors(Location center, double searchRadius, boolean ignoreHeight) {
|
||||
List<Anchor> 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<Anchor> 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<Anchor> 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.
|
||||
* <br>
|
||||
* Other plugins can grant access to other players (e.g. friends).
|
||||
* <br>
|
||||
* 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<Anchor> anchors) {
|
||||
// are holograms enabled?
|
||||
if (!Settings.HOLOGRAMS.getBoolean() || !HologramManager.getManager().isEnabled()) return;
|
||||
|
||||
Map<Location, List<String>> 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());
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>For internal use only</b>
|
||||
*/
|
||||
public static SongodaPlugin getPlugin() {
|
||||
return staticPluginInstance;
|
||||
}
|
||||
}
|
|
@ -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<br>
|
||||
* This method <em>might</em> introduce logic to keep chunks forcefully loaded.
|
||||
* <p>
|
||||
* More information: <a href="https://minecraft.fandom.com/wiki/Tick#Chunk_tick">https://minecraft.fandom.com/wiki/Tick#Chunk_tick</a>
|
||||
*
|
||||
* @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.<br>
|
||||
* 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.<br>
|
||||
* 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.
|
||||
* <br><br>
|
||||
* More information: <a href="https://minecraft.fandom.com/wiki/Tick#Random_tick">https://minecraft.fandom.com/wiki/Tick#Random_tick</a>
|
||||
*
|
||||
* @param chunk The chunk to tick
|
||||
* @param tickAmount The number of blocks to tick per ChunkSection, normally referred to as <code>randomTickSpeed</code>
|
||||
*/
|
||||
public abstract void doRandomTick(Chunk chunk, int tickAmount) throws NoSuchFieldException, IllegalAccessException;
|
||||
|
||||
/**
|
||||
* Returns the current value for the GameRule <code>randomTickSpeed</code>.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<Boolean> 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<List<Anchor>> callback) {
|
||||
List<Anchor> 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<Anchor> callback) {
|
||||
this.thread.execute(() -> insertAnchor(loc, owner, ticks, callback));
|
||||
}
|
||||
|
||||
public void insertAnchor(Location loc, UUID owner, int ticks, Callback<Anchor> 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<AnchorMigration.LegacyAnchorEntry> 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<Anchor> 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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<LegacyAnchorEntry> 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)" +
|
||||
");");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.songoda.epicanchors.utils;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface Callback<T> {
|
||||
void accept(@Nullable Exception ex, T result);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<Boolean> 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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.songoda.epicanchors.utils;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface UpdateCallback {
|
||||
void accept(@Nullable Exception ex);
|
||||
}
|
|
@ -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<String> getMatches(String value, Collection<String> list, boolean caseInsensitive) {
|
||||
List<String> 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");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>EpicAnchors</artifactId>
|
||||
<version>2.0.0-ALPHA</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>epicanchors-plugin</artifactId>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
|
||||
<release>${java.release}</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.2.4</version>
|
||||
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
|
||||
<configuration>
|
||||
<finalName>${project.parent.name}-${project.version}</finalName>
|
||||
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<minimizeJar>true</minimizeJar>
|
||||
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>com.songoda.core</pattern>
|
||||
<shadedPattern>com.songoda.epicanchors.core</shadedPattern>
|
||||
</relocation>
|
||||
|
||||
<relocation>
|
||||
<pattern>epicanchors.nms</pattern>
|
||||
<shadedPattern>com.songoda.epicanchors.nms</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
|
||||
<filters>
|
||||
<filter>
|
||||
<artifact>*:*</artifact>
|
||||
|
||||
<excludes>
|
||||
<exclude>META-INF/**</exclude>
|
||||
<exclude>LICENSE</exclude>
|
||||
<exclude>LICENSE.**</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
|
||||
<filter>
|
||||
<artifact>org.jetbrains:annotations</artifact>
|
||||
<excludes>
|
||||
<exclude>**</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
|
||||
<filter>
|
||||
<artifact>com.songoda:epicanchors-v*</artifact>
|
||||
<includes>
|
||||
<include>**</include>
|
||||
</includes>
|
||||
</filter>
|
||||
</filters>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.8-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Modules -->
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-v1_16_R3</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-v1_16_R2</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-v1_16_R1</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-v1_15_R1</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-v1_14_R1</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-v1_13_R2</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-v1_13_R1</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-v1_12_R1</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-v1_11_R1</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-v1_10_R1</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-v1_9_R2</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-v1_9_R1</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-v1_8_R3</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-v1_8_R2</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-v1_8_R1</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -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<Config> 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;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<String> onTab(CommandSender commandSender, String... strings) {
|
||||
return null;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
|
@ -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<String> onTab(CommandSender commandSender, String... args) {
|
||||
if (args.length == 1) {
|
||||
Set<String> 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<String> 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 <player/@a> <amount in hours / infinite>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Gives an operator the ability to spawn a ChunkAnchor of his or her choice.";
|
||||
}
|
||||
}
|
|
@ -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<String> 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.";
|
||||
}
|
||||
|
||||
}
|
|
@ -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<String> onTab(CommandSender commandSender, String... strings) {
|
||||
return null;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPermissionNode() {
|
||||
return "epicanchors.admin";
|
||||
return "EpicAnchors.cmd.settings";
|
||||
}
|
||||
|
||||
@Override
|
|
@ -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<String> onTab(CommandSender sender, String... args) {
|
||||
return null;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPermissionNode() {
|
||||
return "epicanchors.show";
|
||||
return "EpicAnchors.cmd.show";
|
||||
}
|
||||
|
||||
@Override
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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<Boolean> handler;
|
||||
|
||||
public DestroyConfirmationGui(EpicAnchors plugin, Anchor anchor, Callback<Boolean> 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));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<String, Integer> 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<String, Integer> m = count.entrySet().stream()
|
||||
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
|
||||
(e1, e2) -> e1, LinkedHashMap::new));
|
||||
|
||||
for (Map.Entry<String, Integer> 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);
|
||||
}
|
||||
}
|
|
@ -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<World> initAnchorsInWorld;
|
||||
private final Consumer<World> deInitAnchorsInWorld;
|
||||
|
||||
public WorldListener(Consumer<World> initAnchorsInWorld, Consumer<World> 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());
|
||||
}
|
||||
}
|
|
@ -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<Chunk> alreadyTicked = new HashSet<>();
|
||||
Anchor[] anchorsInWorld = this.anchorManager.getAnchors(world);
|
||||
List<Anchor> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<Chunk, Set<Player>> chunksToVisualize = new HashMap<>();
|
||||
Set<Chunk> 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<Chunk, Set<Player>> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>EpicAnchors</artifactId>
|
||||
<version>2.0.0-ALPHA</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>epicanchors-v1_10_R1</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.10.2-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.10.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>EpicAnchors</artifactId>
|
||||
<version>2.0.0-ALPHA</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>epicanchors-v1_11_R1</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.11-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.11.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>EpicAnchors</artifactId>
|
||||
<version>2.0.0-ALPHA</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>epicanchors-v1_12_R1</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.12.2-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.12.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>EpicAnchors</artifactId>
|
||||
<version>2.0.0-ALPHA</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>epicanchors-v1_13_R1</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.13-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.13</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -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 <code>ServerLevel</code>.
|
||||
*/
|
||||
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 <code>BaseSpawner</code>.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>EpicAnchors</artifactId>
|
||||
<version>2.0.0-ALPHA</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>epicanchors-v1_13_R2</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.13.2-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.13.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -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 <code>ServerLevel</code>.
|
||||
*/
|
||||
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 <code>BaseSpawner</code>.
|
||||
*/
|
||||
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<Entity> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>EpicAnchors</artifactId>
|
||||
<version>2.0.0-ALPHA</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>epicanchors-v1_14_R1</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.14.4-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.14.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -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 <code>ServerLevel</code>.
|
||||
*/
|
||||
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 <code>BaseSpawner</code>.
|
||||
*/
|
||||
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<EntityTypes<?>> 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<Entity> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>EpicAnchors</artifactId>
|
||||
<version>2.0.0-ALPHA</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>epicanchors-v1_15_R1</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.15.2-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.15.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -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 <code>ServerLevel</code>.
|
||||
*/
|
||||
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 <code>BaseSpawner</code>.
|
||||
*/
|
||||
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<EntityTypes<?>> 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<Entity> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>EpicAnchors</artifactId>
|
||||
<version>2.0.0-ALPHA</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>epicanchors-v1_16_R1</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.16.1-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.16.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -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 <code>ServerLevel</code>.
|
||||
*/
|
||||
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 <code>BaseSpawner</code>.
|
||||
*/
|
||||
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<EntityTypes<?>> 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<Entity> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>EpicAnchors</artifactId>
|
||||
<version>2.0.0-ALPHA</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>epicanchors-v1_16_R2</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.16.3-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.16.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -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 <code>ServerLevel</code>.
|
||||
*/
|
||||
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 <code>BaseSpawner</code>.
|
||||
*/
|
||||
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<EntityTypes<?>> 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<Entity> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>EpicAnchors</artifactId>
|
||||
<version>2.0.0-ALPHA</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>epicanchors-v1_16_R3</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.16.5-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.16.5</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -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 <code>ServerLevel</code>.
|
||||
*/
|
||||
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 <code>BaseSpawner</code>.
|
||||
*/
|
||||
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<EntityTypes<?>> 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<Entity> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>EpicAnchors</artifactId>
|
||||
<version>2.0.0-ALPHA</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>epicanchors-v1_8_R1</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.8-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.8</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>EpicAnchors</artifactId>
|
||||
<version>2.0.0-ALPHA</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>epicanchors-v1_8_R2</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.8.3-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.8.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>EpicAnchors</artifactId>
|
||||
<version>2.0.0-ALPHA</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>epicanchors-v1_8_R3</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.8.8-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.8.8</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>EpicAnchors</artifactId>
|
||||
<version>2.0.0-ALPHA</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>epicanchors-v1_9_R1</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.9-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.9.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>EpicAnchors</artifactId>
|
||||
<version>2.0.0-ALPHA</version>
|
||||
<relativePath>../../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<artifactId>epicanchors-v1_9_R2</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicanchors-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.9.4-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.9.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
166
pom.xml
166
pom.xml
|
@ -1,119 +1,93 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>EpicAnchors</artifactId>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<version>1.4.10c</version>
|
||||
<packaging>pom</packaging>
|
||||
<version>2.0.0-ALPHA</version>
|
||||
<!-- Run 'mvn versions:set -DgenerateBackupPoms=false -DnewVersion=X.Y.Z-DEV' to update version recursively -->
|
||||
|
||||
<modules>
|
||||
<module>modules/epicanchors-api</module>
|
||||
<module>modules/epicanchors-plugin</module>
|
||||
|
||||
<module>modules/nms/epicanchors-v1_16_R3</module>
|
||||
<module>modules/nms/epicanchors-v1_16_R2</module>
|
||||
<module>modules/nms/epicanchors-v1_16_R1</module>
|
||||
<module>modules/nms/epicanchors-v1_15_R1</module>
|
||||
<module>modules/nms/epicanchors-v1_14_R1</module>
|
||||
<module>modules/nms/epicanchors-v1_13_R2</module>
|
||||
<module>modules/nms/epicanchors-v1_13_R1</module>
|
||||
<module>modules/nms/epicanchors-v1_12_R1</module>
|
||||
<module>modules/nms/epicanchors-v1_11_R1</module>
|
||||
<module>modules/nms/epicanchors-v1_10_R1</module>
|
||||
<module>modules/nms/epicanchors-v1_9_R2</module>
|
||||
<module>modules/nms/epicanchors-v1_9_R1</module>
|
||||
<module>modules/nms/epicanchors-v1_8_R3</module>
|
||||
<module>modules/nms/epicanchors-v1_8_R2</module>
|
||||
<module>modules/nms/epicanchors-v1_8_R1</module>
|
||||
</modules>
|
||||
|
||||
<name>EpicAnchors</name>
|
||||
<description>Allow your players to keep chunks loaded for a limited amount of time for a cost.</description>
|
||||
<url>https://songoda.com/marketplace/product/31</url>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<java.release>8</java.release>
|
||||
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<issueManagement>
|
||||
<url>https://support.songoda.com/servicedesk/customer/portal/3</url>
|
||||
<system>Jira Service Desk</system>
|
||||
</issueManagement>
|
||||
|
||||
<scm>
|
||||
<url>https://github.com/songoda/EpicAnchors</url>
|
||||
<connection>scm:git:git:github.com/songoda/EpicAnchors.git</connection>
|
||||
</scm>
|
||||
|
||||
<build>
|
||||
<defaultGoal>clean install</defaultGoal>
|
||||
<finalName>EpicAnchors-${project.version}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.1</version>
|
||||
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
|
||||
<release>${java.release}</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.google.code.maven-replacer-plugin</groupId>
|
||||
<artifactId>replacer</artifactId>
|
||||
<version>1.5.3</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>replace</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<file>${project.build.directory}/classes/plugin.yml</file>
|
||||
<replacements>
|
||||
<replacement>
|
||||
<token>maven-version-number</token>
|
||||
<value>${project.version}</value>
|
||||
</replacement>
|
||||
</replacements>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>shaded</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<shadedArtifactAttached>false</shadedArtifactAttached>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
<minimizeJar>true</minimizeJar>
|
||||
<artifactSet>
|
||||
<includes>
|
||||
<include>com.songoda:SongodaCore</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
<filters>
|
||||
<!-- This filter is primarily for anvil gui right now -->
|
||||
<!--<filter>
|
||||
<artifact>com.songoda:SongodaCore-NMS*</artifact>
|
||||
<includes>
|
||||
<include>**</include>
|
||||
</includes>
|
||||
</filter>-->
|
||||
<filter>
|
||||
<artifact>*:*</artifact>
|
||||
<excludes>
|
||||
<exclude>META-INF/*.SF</exclude>
|
||||
<exclude>META-INF/*.DSA</exclude>
|
||||
<exclude>META-INF/*.RSA</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>com.songoda.core</pattern>
|
||||
<shadedPattern>${project.groupId}.epicanchors.core</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>public</id>
|
||||
<url>https://repo.songoda.com/repository/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<id>spigotmc-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
|
||||
<repository>
|
||||
<id>songoda-public</id>
|
||||
<url>https://repo.songoda.com/repository/public/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<!-- Dev dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.16.4</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>SongodaCore</artifactId>
|
||||
<version>LATEST</version>
|
||||
<groupId>org.jetbrains</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
<version>21.0.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.songoda</groupId>
|
||||
<artifactId>epicspawners</artifactId>
|
||||
<version>6-pre4</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -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<Config> getExtraConfig() {
|
||||
return null;
|
||||
}
|
||||
|
||||
void loadHolograms() {
|
||||
Collection<Anchor> 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<String> 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<Location, Anchor> 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<Location, Anchor> 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;
|
||||
}
|
||||
}
|
|
@ -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<String> onTab(CommandSender commandSender, String... strings) {
|
||||
if (strings.length == 1) {
|
||||
List<String> 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 <player/all> <amount in hours / infinite>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Gives an operator the ability to spawn a ChunkAnchor of his or her choice.";
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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<Location, Integer> 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());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<OfflinePlayer, Boolean> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<String, Location> 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<String> 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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: /<command> [reload]
|
Loading…
Reference in New Issue