Compare commits

...

54 Commits

Author SHA1 Message Date
Christian Koop c9405d3809
Merge branch 'development' 2024-03-24 11:16:50 +01:00
Christian Koop 7e1fff7105
Release v3.1.1 2024-03-24 11:16:01 +01:00
Christian Koop affeb440fd
Merge branch 'master' into development 2024-03-18 17:45:54 +01:00
dependabot[bot] af4cd8de3e
Bump org.apache.maven.plugins:maven-shade-plugin from 3.5.1 to 3.5.2 (#39)
Bumps [org.apache.maven.plugins:maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.5.1 to 3.5.2.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.5.1...maven-shade-plugin-3.5.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-01 13:28:46 +01:00
Christian Koop e806e29a58
ci: Fix potentially problematic `increment_version` value 2024-02-26 12:53:54 +01:00
Christian Koop fa20a3f013
build: Disable 'missing' warnings in javadocs plugin 2024-02-02 18:58:01 +01:00
dependabot[bot] 3b1f12a94b
Bump actions/cache from 3 to 4 (#38)
Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-02 08:38:20 +01:00
Christian Koop ca28ff77ae
Release v3.1.0 2024-01-13 21:16:41 +01:00
Christian Koop e5b48b624f
Upgrade Craftaro Core (+dynamic library loading; +MC 1.20.4 support)
Notable changes:
* Spigot 1.20.3/3 compatibility
* dynamic library/dependency loading
  * Smaller plugin jar size
2024-01-13 21:16:41 +01:00
Christian Koop 829e97e5e2
Release v3.0.0-b3-SNAPSHOT 2024-01-13 17:01:22 +01:00
Christian Koop 95b128d73d
fix: Properly migrate the database related code to the new core's API
See previously commits for context

tl;dr
The database migration introduced a lot of changed behaviour and breaking changes.
The plugin essentially could never have worked and nobody reported the issue (or tested it).

I've completely redone the code migration, keeping changes for the plugin internals to a minimum.
Hopefully I didn't overlook anything...
2024-01-13 17:01:22 +01:00
Christian Koop f3377b08f9
Revert "Updates to new database system"
This reverts commit f3c8778ad2.
2024-01-13 17:01:22 +01:00
Christian Koop b4c5282990
Revert "Make database migrations compatible with latest CraftaroCore snapshot"
This reverts commit 22c99005dd.
2024-01-13 17:01:22 +01:00
Christian Koop fadb84f2a9
Revert "fix: A lot of issues introduced after migrating to the new database API"
This reverts commit 2eec844447.
2024-01-13 17:01:22 +01:00
dependabot[bot] ab968ea984
Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.6.2 to 3.6.3 (#36)
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.6.2 to 3.6.3.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.6.2...maven-javadoc-plugin-3.6.3)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-01 13:52:22 +01:00
dependabot[bot] d6d7d1f1bf
Bump actions/upload-artifact from 3 to 4 (#37)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-01 13:51:55 +01:00
dependabot[bot] 0cb90ec12a
Bump org.jetbrains:annotations from 24.0.1 to 24.1.0 (#35)
Bumps [org.jetbrains:annotations](https://github.com/JetBrains/java-annotations) from 24.0.1 to 24.1.0.
- [Release notes](https://github.com/JetBrains/java-annotations/releases)
- [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md)
- [Commits](https://github.com/JetBrains/java-annotations/compare/24.0.1...24.1.0)

---
updated-dependencies:
- dependency-name: org.jetbrains:annotations
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-01 18:47:14 +01:00
dependabot[bot] 0bfeb6a2f0
Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.6.0 to 3.6.2 (#34)
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.6.0 to 3.6.2.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.6.0...maven-javadoc-plugin-3.6.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-01 18:39:03 +01:00
dependabot[bot] 8cbf1b789c
Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.5.0 to 3.6.0 (#33)
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.5.0 to 3.6.0.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.5.0...maven-javadoc-plugin-3.6.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-02 15:43:22 +01:00
dependabot[bot] a539306d46
Bump actions/checkout from 3 to 4 (#32)
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-01 15:45:51 +01:00
Christian Koop 2eec844447
fix: A lot of issues introduced after migrating to the new database API
The new database API introduced a lot of breaking changes and changed behaviour sadly.
When migrating this plugin to the new API these were not taken into account properly and
essentially broke the whole database/storage layer of the plugin.

* SQL statements that were valid in SQLite but are not in H2, which is now the default
* H2 jdbc driver not being shaded into the final jar
* catching exceptions, logging a message, and then continuing code execution (in the core)
* introducing race conditions
* ...

These fixes sometimes rely on the non-multi-threaded APIs provided now which will most certaintly
come with a performance hit on larger servers.
But at least it works again... tbh I do not really want to spend too much time fixing this stuff...

A potential issue that still exists in the use of `DataManager#getNextId` in `AnchorManagerImpl`.
Right now it returns a value based on the largest ID currently in the database – Completely circumventing
the whole auto_increment characteristic of the table schema...
This is another changed behaviour that gets introduced opening the possibility for conflicting IDs
*outside* of the database table itself. The ID can be used as a reference in other places
2023-10-24 01:44:00 +02:00
Christian Koop 9e850c5a49
Release v3.0.0-b2-SNAPSHOT 2023-10-23 17:57:47 +02:00
Christian Koop 22c99005dd
Make database migrations compatible with latest CraftaroCore snapshot 2023-10-23 16:49:59 +02:00
dependabot[bot] ef6f4a8c8c
Bump org.apache.maven.plugins:maven-shade-plugin from 3.5.0 to 3.5.1 (#31)
Bumps [org.apache.maven.plugins:maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.5.0 to 3.5.1.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.5.0...maven-shade-plugin-3.5.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-09 12:34:57 +02:00
dependabot[bot] 330164ae33
Bump maven-shade-plugin from 3.4.1 to 3.5.0
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.4.1 to 3.5.0.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.4.1...maven-shade-plugin-3.5.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-03 19:59:13 +02:00
ceze88 9863b93b41 Fixes method names 2023-08-02 17:46:30 +02:00
ceze88 f3c8778ad2 Updates to new database system 2023-08-02 17:20:52 +02:00
Christian Koop 1a4a83441b
Use `SpigotMC` as maven repository ID 2023-06-29 11:28:45 +02:00
Christian Koop 8bcfca0292
Migrate usage of CompatibleSound to XSound in the CraftaroCore-Snapshot 2023-06-24 20:38:29 +02:00
Christian Koop 200df50bf6
GitHub Actions: Additionally upload plugin jar as build artifact 2023-06-24 16:07:23 +02:00
Christian Koop 72a5960d28
GitHub Actions: Updates `build.yml` based on craftaro/GH-Commons 2023-06-24 12:42:04 +02:00
Christian Koop 5e23c339f9
Configure generation of JavaDocs and Source jars for API submodule 2023-06-24 12:32:49 +02:00
Christian Koop 069b923f9f
Merge branch 'master' into development 2023-06-24 11:47:28 +02:00
Christian Koop 5622e86e0f
Changes Songoda to Craftaro in EpicAnchors command 2023-06-24 11:47:23 +02:00
Christian Koop adcff80c47
pom.xml/plugin.yml: Updates Marketplace Link from Songoda to Craftaro 2023-06-24 11:46:54 +02:00
Christian Koop a1e5c11ccb
Updates .github/FUNDING.yml to only list Craftaro+ 2023-06-24 11:30:34 +02:00
Christian Koop a2ed4c8656
Fix final plugin jar's name being suffixed with '-Plugin'
The suffix comes from the module itself but this is the main artifact of the project.
2023-06-24 11:28:44 +02:00
Christian Koop 3967209265
Moved all classes from`com.songoda` package to `com.craftaro` package 2023-06-24 11:27:25 +02:00
Christian Koop 8e5cb2405d
GitHub Actions: Temporarily removes Deployment to the maven repository
We have a new template for compiling projects and publishing them but it hasn't really been designed
with API modules in mind yet and needs some smaler adjustments before being used in all projects.
I don't want to manually update all projects if I change the template workflow file.
2023-06-24 11:05:49 +02:00
Christian Koop f82486aecb
Sets the plugin's version to v3.0.0-SNAPSHOT 2023-06-24 11:00:53 +02:00
Christian Koop da0e877d03
Fixes compatibility with DecentHolograms 2023-06-24 10:59:05 +02:00
Christian Koop dea440732e
Make the plugin compatible with the latest Core-Snapshot build
I've replaced CompatibleMaterial with a library adding XMaterial.
2023-06-24 10:57:14 +02:00
Christian Koop bbfd62c1d3
Restructures the code and add classes/interfaces to the API module
I tried creating a usable API module containing everything important without introducing
too many changes that cost time and might confuse people when migration to the new module.

We have limited time right now and need to push the 1.20 update... So no additional thoughts on
the API design (so I can regret it in the somewhat near future \o/)
2023-06-24 10:51:11 +02:00
Christian Koop da2e999ef9
Change the project structure to allow a dedicated API module to exist 2023-06-21 15:05:48 +02:00
Christian Koop b25843aee3
pom.xml: Mark the shaded jar as main artifact 2023-06-14 21:41:39 +02:00
Christian Koop ae74ffa5f0
Don't try to shade org.jetbrains.annotations and exclude it afterwards 2023-06-14 21:41:09 +02:00
Christian Koop 7f0f2a1acb
Improves NMS error handling when the server version is not supported 2023-06-14 21:25:19 +02:00
Christian Koop aef95bb831
Migrates from SongodaCore to CraftaroCore v3.0.0-SNAPSHOT 2023-06-14 21:24:50 +02:00
Christian Koop 5a8f873672
Always tick spawners in loaded chunks + Refactor of AnchorTask
When a user was inside a given chunk with a spawner, the spawner might not trigger because
of the activation range.
Anchors are supposed to ignore this limit - This change makes sure, spawners are always active.

The hack to not tick chunks with players in them is only in there because of the randomTicks done.
But this can still cause chunks to get double the randomTicks they are supposed to because
there is no good way (that I know of) to check when the server did them on a given chunk.
2023-05-18 12:24:36 +02:00
Christian Koop 47fd57a7ac
Minor code style changes (mostly use of `this.` for instance fields) 2023-05-18 12:08:01 +02:00
Christian Koop cc2307f532
README.md + pom.xml: Updates some Songoda URLs to Craftaro
The image URL (and marketplace URLs that I didn't change) contain the new product ID.
The ID changed sadly but I think they will be some work done to restore the old IDs,
so I'm not updating them for now.
2023-05-18 11:55:24 +02:00
Christian Koop 70741c3f7e
GitHub Actions: Switch to new Build + SonarCloud workflows
Based on craftaro/GH-Commons

These new workflows bring a lot of nice things - For example:
* signed jars
* Auto-Deploy to Maven Repo
* Using songoda.sprax.dev/repo/ as proxy for most repos/dependencies
* ...
2023-05-18 11:55:24 +02:00
Christian Koop d312c6c578
Updates Dependabot, .editorconfig, .gitignore, FUNDING.yml
Based on craftaro/GH-Commons
2023-05-18 11:30:30 +02:00
Christian Koop 577547b53a
Fix git connection URL in pom.xml
https://maven.apache.org/scm/git.html
2023-05-18 10:23:03 +02:00
45 changed files with 1185 additions and 1216 deletions

View File

@ -1,3 +1,6 @@
root = true
[*]
charset = utf-8
end_of_line = lf
@ -10,302 +13,14 @@ 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
ij_formatter_tags_enabled = true
[*.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}]
[{*.yaml,*.yml,*.json,*.graphqlconfig,*.har,*.jsb2,*.jsb3,*.webmanifest,.babelrc,.eslintrc,.prettierrc,.stylelintrc,bowerrc,jest.config}]
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}]
[{*.markdown,*.md,*.html,*.htm,*.ng,*.sht,*.shtm,*.shtml,*.ts,*.ats,*.js,*.cjs,*.bash,*.sh,*.zsh}]
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
tab_width = 2

13
.github/FUNDING.yml vendored
View File

@ -1,12 +1 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: songoda
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
custom: [ 'https://craftaro.to/+' ]

View File

@ -1,18 +1,16 @@
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
- package-ecosystem: "maven"
directory: "/"
target-branch: "development"
- package-ecosystem: maven
directory: /
target-branch: development
schedule:
interval: "monthly"
ignore:
- dependency-name: "com.songoda:SongodaCore"
interval: monthly
- package-ecosystem: "github-actions"
directory: "/"
target-branch: "development"
- package-ecosystem: github-actions
directory: /
target-branch: development
schedule:
interval: "monthly"
interval: monthly

95
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,95 @@
name: Build
on:
push:
branches: [ master, development ]
tags:
- 'v*'
pull_request:
types: [ opened, synchronize, reopened ]
permissions: read-all
env:
DEPLOYMENT_POM_PATH: ./EpicAnchors-API/pom.xml
DEPLOYMENT_ARTIFACT_DIR: ./EpicAnchors-API/target
DEPLOYMENT_ARTIFACT_SELECTOR: EpicAnchors-API-*.jar
PLUGIN_ARTIFACT_DIR: ./EpicAnchors-Plugin/target
PLUGIN_ARTIFACT_SELECTOR: EpicAnchors-*.jar
jobs:
Build:
name: Build + Deploy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Prepare Workspace
uses: craftaro/GH-Commons/.github/actions/setup_workspace@master
with:
maven_username: ${{ secrets.PLUGINS_MAVEN_REPO_USERNAME }}
maven_password: ${{ secrets.PLUGINS_MAVEN_REPO_PASSWORD }}
- name: Set project version
uses: craftaro/GH-Commons/.github/actions/maven_set_project_version@master
with:
append_snapshot: ${{ github.ref_type == 'tag' && 'false' || 'true' }}
version: ${{ github.ref_type == 'tag' && github.ref_name || '' }}
increment_version: ${{ github.ref_type != 'tag' && 'patch' || '' }}
increment_version_only_if_not_snapshot_version: ${{ github.ref == 'refs/heads/development' && 'true' || 'false' }}
- name: Build with Maven
run: mvn -B -Duser.name="GitHub Actions on $GITHUB_REPOSITORY (id=$GITHUB_RUN_ID)" clean package
- name: Sign jar archives
uses: craftaro/GH-Commons/.github/actions/sign_jars@master
with:
jar_file_selector: ${{ env.DEPLOYMENT_ARTIFACT_DIR }}/${{ env.DEPLOYMENT_ARTIFACT_SELECTOR }}
keystore_gpg_encrypted: ${{ secrets.PLUGINS_JARSIGNER_KEYSTORE_GPG }}
keystore_gpg_password: ${{ secrets.PLUGINS_JARSIGNER_KEYSTORE_GPG_PASSWORD }}
keystore_password: ${{ secrets.PLUGINS_JARSIGNER_KEYSTORE_PASSWORD }}
- name: Upload Build Artifacts [API]
uses: actions/upload-artifact@v4
with:
name: ${{ github.event.repository.name }}-API
path: ${{ env.DEPLOYMENT_ARTIFACT_DIR }}/${{ env.DEPLOYMENT_ARTIFACT_SELECTOR }}
- name: Upload Build Artifacts [Plugin]
uses: actions/upload-artifact@v4
with:
name: ${{ github.event.repository.name }}
path: ${{ env.PLUGIN_ARTIFACT_DIR }}/${{ env.PLUGIN_ARTIFACT_SELECTOR }}
- name: Deploy to Maven repo
if: ${{ github.event_name == 'push' }}
uses: craftaro/GH-Commons/.github/actions/maven_deploy@master
with:
repository_url: ${{ vars.PLUGINS_MAVEN_REPO_URL_RELEASE }}
repository_url_snapshots: ${{ vars.PLUGINS_MAVEN_REPO_URL_SNAPSHOT }}
maven_pom_path: ${{ env.DEPLOYMENT_POM_PATH }}
maven_out_dir: ${{ env.DEPLOYMENT_ARTIFACT_DIR }}
- name: Deploy parent pom.xml to Maven repo
if: ${{ github.event_name == 'push' }}
uses: craftaro/GH-Commons/.github/actions/maven_deploy@master
with:
repository_url: ${{ vars.PLUGINS_MAVEN_REPO_URL_RELEASE }}
repository_url_snapshots: ${{ vars.PLUGINS_MAVEN_REPO_URL_SNAPSHOT }}
only_deploy_pom: true
maven_out_dir: ${{ env.DEPLOYMENT_ARTIFACT_DIR }}
discord_webhook:
name: Send Discord Webhook
runs-on: ubuntu-latest
needs: [ Build ]
if: ${{ always() && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/development' || github.ref_type == 'tag') }}
steps:
- uses: actions/checkout@v4
- name: Notify Webhook
uses: craftaro/GH-Commons/.github/actions/discord_send_job_results@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
webhook_url: ${{ secrets.DISCORD_BUILD_STATUS_WEBHOOK }}

View File

@ -1,96 +0,0 @@
name: 'Build & Test'
on:
push:
branches: [ master, development ]
pull_request:
types: [ opened, synchronize, reopened ]
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
# Setup Java
- uses: actions/setup-java@v3
with:
java-version: 16
distribution: adopt
# Checkout project files
- uses: actions/checkout@v3
# Caches
- name: 'Cache: Maven'
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-maven-
# Build project
- name: Build with Maven
run: 'mvn -B -Duser.name="GitHub Runner on $GITHUB_REPOSITORY (id=$GITHUB_RUN_ID)" clean package'
# Upload build artifacts
- name: 'Upload Build Artifact: EpicAnchors-*.jar'
uses: actions/upload-artifact@v3
with:
name: EpicAnchors-artifacts
path: ./target/EpicAnchors-*.jar
##
# Discord Webhook
# TODO: Extract into external Action for better re-usability (and readability) [Copied SongodaCore]
##
- name: 'Discord Webhook (Success)'
if: ${{ success() && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/development') }}
continue-on-error: true
run: |
curl -X POST --data "{\"content\":null,\"embeds\":[{\"title\":\"Build succeeded!\",\"description\":\"The build with the ID #$GITHUB_RUN_NUMBER has succeeded!\",\"url\":\"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID\",\"color\":5490477,\"fields\":[{\"name\":\"Branch\",\"value\":\"$GITHUB_REF\",\"inline\":true}],\"author\":{\"name\":\"$GITHUB_REPOSITORY\",\"url\":\"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY\",\"icon_url\":\"$GITHUB_SERVER_URL/songoda.png\"},\"footer\":{\"text\":\"Initiated by $GITHUB_ACTOR\",\"icon_url\":\"$GITHUB_SERVER_URL/$GITHUB_ACTOR.png\"}}],\"username\":\"OctoAgent\",\"avatar_url\":\"https://github.githubassets.com/images/modules/logos_page/Octocat.png\"}" --header 'Content-Type: application/json' $DISCORD_WEBHOOK
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_BUILD_STATUS_WEBHOOK }}
- name: 'Discord Webhook (Failure)'
if: ${{ failure() && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/development') }}
continue-on-error: true
run: |
curl -X POST --data "{\"content\":null,\"embeds\":[{\"title\":\"Build failed!\",\"description\":\"The build with the ID #$GITHUB_RUN_NUMBER has failed!\",\"url\":\"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID\",\"color\":15611419,\"fields\":[{\"name\":\"Branch\",\"value\":\"$GITHUB_REF\",\"inline\":true}],\"author\":{\"name\":\"$GITHUB_REPOSITORY\",\"url\":\"$GITHUB_SERVER_URL/$GITHUB_REPOSITORY\",\"icon_url\":\"$GITHUB_SERVER_URL/songoda.png\"},\"footer\":{\"text\":\"Initiated by $GITHUB_ACTOR\",\"icon_url\":\"$GITHUB_SERVER_URL/$GITHUB_ACTOR.png\"}}],\"username\":\"OctoAgent\",\"avatar_url\":\"https://github.githubassets.com/images/modules/logos_page/Octocat.png\"}" --header "Content-Type:application/json" $DISCORD_WEBHOOK
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_BUILD_STATUS_WEBHOOK }}
sonarcloud:
name: SonarCloud
runs-on: ubuntu-latest
steps:
# Setup Java
- uses: actions/setup-java@v3
with:
java-version: 11
distribution: adopt
# Checkout project files
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
# Caches
- name: 'Cache: Maven'
uses: actions/cache@v3
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-maven-
- name: 'Cache: SonarCloud'
uses: actions/cache@v3
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
# SonarCloud static analysis
- name: SonarCloud
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar

42
.github/workflows/sonarcloud.yml vendored Normal file
View File

@ -0,0 +1,42 @@
name: SonarCloud
on:
push:
branches: [ master, development ]
workflow_dispatch:
permissions: read-all
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_ORGANIZATION: craftaro
SONAR_PROJECT_KEY: craftaro_EpicAnchors
jobs:
Analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Prepare Workspace
uses: craftaro/GH-Commons/.github/actions/setup_workspace@master
- name: 'Cache: SonarCloud'
uses: actions/cache@v4
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
- name: Analyze project
run: >
mvn -B \
verify \
org.sonarsource.scanner.maven:sonar-maven-plugin:sonar \
-Dsonar.host.url=https://sonarcloud.io \
"-Dsonar.organization=$SONAR_ORGANIZATION" \
"-Dsonar.projectKey=$SONAR_PROJECT_KEY"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

11
.gitignore vendored
View File

@ -1,5 +1,10 @@
/target/
# JetBrains IDEs
## JetBrains IDEs
/.idea/
*.iml
## Maven
/**/target/
dependency-reduced-pom.xml
## Misc.
.DS_Store

69
EpicAnchors-API/pom.xml Normal file
View File

@ -0,0 +1,69 @@
<?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.craftaro</groupId>
<artifactId>EpicAnchors-Parent</artifactId>
<version>3.1.1</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>EpicAnchors-API</artifactId>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.6.3</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
<configuration>
<doclint>all,-missing</doclint>
<links>
<link>https://hub.spigotmc.org/javadocs/spigot/</link>
</links>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.craftaro</groupId>
<artifactId>CraftaroCore</artifactId>
<version>${craftaro.coreVersion}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.8-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,29 @@
package com.craftaro.epicanchors;
import com.craftaro.epicanchors.api.AnchorManager;
public final class EpicAnchorsApi {
private static EpicAnchorsApi instance;
private final AnchorManager anchorManager;
private EpicAnchorsApi(AnchorManager anchorManager) {
this.anchorManager = anchorManager;
}
public AnchorManager getAnchorManager() {
return this.anchorManager;
}
public static EpicAnchorsApi getApi() {
return instance;
}
static void initApi(AnchorManager anchorManager) {
if (instance != null) {
throw new IllegalStateException("EpicAnchorsApi already initialized");
}
instance = new EpicAnchorsApi(anchorManager);
}
}

View File

@ -0,0 +1,34 @@
package com.craftaro.epicanchors.api;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
public interface Anchor {
int getDbId();
UUID getOwner();
boolean isLegacy();
@NotNull Location getLocation();
@NotNull World getWorld();
@NotNull Chunk getChunk();
int getTicksLeft();
@SuppressWarnings("unused")
void setTicksLeft(int ticksLeft);
@SuppressWarnings("UnusedReturnValue")
int addTicksLeft(int ticks);
int removeTicksLeft(int ticks);
boolean isInfinite();
}

View File

@ -1,6 +1,5 @@
package com.songoda.epicanchors.api;
package com.craftaro.epicanchors.api;
import com.songoda.epicanchors.Anchor;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;

View File

@ -0,0 +1,88 @@
package com.craftaro.epicanchors.api;
import com.craftaro.epicanchors.utils.Callback;
import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
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.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.UUID;
public interface AnchorManager {
String NBT_TICKS_KEY = "EpicAnchors_Ticks".toLowerCase();
boolean isReady(World world);
Anchor[] getAnchors(@NotNull World world);
@Nullable Anchor getAnchor(@NotNull Block block);
boolean isAnchor(@NotNull Block block);
boolean hasAnchor(@NotNull Chunk chunk);
List<Anchor> searchAnchors(Location center, double searchRadius);
List<Anchor> searchAnchors(Location center, double searchRadius, boolean ignoreHeight);
/**
* 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
*/
void createAnchor(@NotNull Location loc, @NotNull UUID owner, int ticks, @Nullable Callback<Anchor> callback);
void destroyAnchor(@NotNull Anchor anchor);
void destroyAnchor(@NotNull Anchor anchor, boolean forceSkipItemDrop);
void registerAccessCheck(AnchorAccessCheck accessCheck);
/**
* @param accessCheck The {@link AnchorAccessCheck} to remove
* @return true if the {@link AnchorAccessCheck} has been found and removed, false otherwise
*/
boolean unregisterAccessCheck(AnchorAccessCheck accessCheck);
/**
* @deprecated Use {@link #hasAccess(Anchor, UUID)} instead
*/
@Deprecated
boolean hasAccess(@NotNull Anchor anchor, @NotNull OfflinePlayer p);
/**
* 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)
*/
boolean hasAccess(@NotNull Anchor anchor, @NotNull UUID uuid);
ItemStack createAnchorItem(int ticks);
ItemStack createAnchorItem(int ticks, Material material);
ItemStack createAnchorItem(int ticks, XMaterial material);
boolean toggleChunkVisualized(Player p);
void setChunksVisualized(Player p, boolean visualize);
boolean hasChunksVisualized(Player p);
void updateHolograms(List<Anchor> anchors);
}

View File

@ -1,4 +1,4 @@
package com.songoda.epicanchors.utils;
package com.craftaro.epicanchors.utils;
import org.jetbrains.annotations.Nullable;

109
EpicAnchors-Plugin/pom.xml Normal file
View File

@ -0,0 +1,109 @@
<?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.craftaro</groupId>
<artifactId>EpicAnchors-Parent</artifactId>
<version>3.1.1</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>EpicAnchors-Plugin</artifactId>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>${project.parent.name}-${project.version}</finalName>
<shadedArtifactAttached>false</shadedArtifactAttached>
<useDependencyReducedPomInJar>true</useDependencyReducedPomInJar>
<minimizeJar>true</minimizeJar>
<relocations>
<relocation>
<pattern>com.craftaro.core</pattern>
<shadedPattern>com.craftaro.epicanchors.core</shadedPattern>
</relocation>
</relocations>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/**</exclude>
<exclude>LICENSE</exclude>
<exclude>LICENSE.**</exclude>
</excludes>
</filter>
<filter>
<artifact>com.craftaro:CraftaroCore</artifact>
<excludeDefaults>false</excludeDefaults>
<includes>
<include>**/nms/v*/**</include>
</includes>
<excludes>
<exclude>**/third_party/org/apache/**</exclude>
<exclude>**/third_party/net/kyori/**</exclude>
<exclude>**/third_party/com/zaxxer/**</exclude>
<exclude>**/third_party/org/jooq/**</exclude>
<exclude>**/third_party/org/mariadb/**</exclude>
<exclude>**/third_party/com/h2database/**</exclude>
<exclude>**/third_party/org/h2/**</exclude>
<exclude>**/third_party/com/cryptomorin/**</exclude>
<exclude>**/third_party/org/reactivestreams/**</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<dependencies>
<dependency>
<groupId>com.craftaro</groupId>
<artifactId>EpicAnchors-API</artifactId>
<version>${project.parent.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.craftaro</groupId>
<artifactId>CraftaroCore</artifactId>
<version>${craftaro.coreVersion}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.8-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,6 +1,7 @@
package com.songoda.epicanchors;
package com.craftaro.epicanchors;
import com.songoda.epicanchors.utils.WorldUtils;
import com.craftaro.epicanchors.api.Anchor;
import com.craftaro.epicanchors.utils.WorldUtils;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
@ -12,7 +13,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.UUID;
public class Anchor {
public class AnchorImpl implements Anchor {
private final int dbId;
private final UUID owner;
@ -20,7 +21,7 @@ public class Anchor {
private final Location location;
private int ticksLeft;
public Anchor(int dbId, @Nullable UUID owner, @NotNull Location location, int ticksLeft) {
public AnchorImpl(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");
@ -66,34 +67,42 @@ public class Anchor {
}
}
@Override
public int getDbId() {
return this.dbId;
}
@Override
public UUID getOwner() {
return this.owner;
}
@Override
public boolean isLegacy() {
return this.owner == null;
}
@Override
public @NotNull Location getLocation() {
return this.location.clone();
}
@Override
public @NotNull World getWorld() {
return this.location.getWorld();
}
@Override
public @NotNull Chunk getChunk() {
return this.location.getChunk();
}
@Override
public int getTicksLeft() {
return this.ticksLeft;
}
@Override
@SuppressWarnings("unused")
public void setTicksLeft(int ticksLeft) {
if (ticksLeft < 0) throw new IllegalArgumentException("Invalid value for ticksLeft");
@ -101,6 +110,7 @@ public class Anchor {
this.ticksLeft = ticksLeft;
}
@Override
@SuppressWarnings("UnusedReturnValue")
public int addTicksLeft(int ticks) {
if (!isInfinite()) {
@ -110,6 +120,7 @@ public class Anchor {
return this.ticksLeft;
}
@Override
public int removeTicksLeft(int ticks) {
if (!isInfinite()) {
this.ticksLeft -= ticks;
@ -122,6 +133,7 @@ public class Anchor {
return this.ticksLeft;
}
@Override
public boolean isInfinite() {
return this.ticksLeft == -1;
}

View File

@ -1,19 +1,22 @@
package com.songoda.epicanchors;
package com.craftaro.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.third_party.de.tr7zw.nbtapi.NBTItem;
import com.songoda.core.utils.TextUtils;
import com.songoda.core.utils.TimeUtils;
import com.songoda.epicanchors.api.AnchorAccessCheck;
import com.songoda.epicanchors.files.DataManager;
import com.songoda.epicanchors.files.Settings;
import com.songoda.epicanchors.utils.Callback;
import com.songoda.epicanchors.utils.UpdateCallback;
import com.songoda.epicanchors.utils.Utils;
import com.craftaro.core.SongodaPlugin;
import com.craftaro.core.compatibility.CompatibleMaterial;
import com.craftaro.core.compatibility.CompatibleParticleHandler;
import com.craftaro.core.hooks.HologramManager;
import com.craftaro.core.third_party.de.tr7zw.nbtapi.NBTItem;
import com.craftaro.core.utils.TextUtils;
import com.craftaro.core.utils.TimeUtils;
import com.craftaro.epicanchors.api.Anchor;
import com.craftaro.epicanchors.api.AnchorAccessCheck;
import com.craftaro.epicanchors.api.AnchorManager;
import com.craftaro.epicanchors.files.AnchorsDataManager;
import com.craftaro.epicanchors.files.Settings;
import com.craftaro.epicanchors.utils.Callback;
import com.craftaro.epicanchors.utils.UpdateCallback;
import com.craftaro.epicanchors.utils.Utils;
import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
import com.craftaro.third_party.com.cryptomorin.xseries.XSound;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
@ -39,12 +42,12 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class AnchorManager {
public class AnchorManagerImpl implements 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 final String HOLOGRAM_PREFIX = "Anchor_";
private final SongodaPlugin plugin;
private final DataManager dataManager;
private final AnchorsDataManager dataManager;
private final Map<World, Set<Anchor>> anchors = new HashMap<>(3);
private final Set<Player> visualizedChunk = new HashSet<>();
@ -52,19 +55,19 @@ public class AnchorManager {
private boolean ready;
public AnchorManager(SongodaPlugin plugin, DataManager dataManager) {
public AnchorManagerImpl(SongodaPlugin plugin, AnchorsDataManager dataManager) {
this.plugin = Objects.requireNonNull(plugin);
this.dataManager = Objects.requireNonNull(dataManager);
}
protected void saveAll() {
for (Set<Anchor> anchorSet : anchors.values()) {
for (Set<Anchor> anchorSet : this.anchors.values()) {
this.dataManager.updateAnchors(anchorSet, null);
}
}
protected void deInitAll() {
for (World world : anchors.keySet().toArray(new World[0])) {
for (World world : this.anchors.keySet().toArray(new World[0])) {
deInitAnchors(world);
}
}
@ -82,12 +85,12 @@ public class AnchorManager {
this.dataManager.getAnchors(world, (ex, result) -> {
if (ex == null) {
this.anchors.computeIfAbsent(world, k -> new HashSet<>());
this.anchors.computeIfAbsent(world, key -> new HashSet<>());
for (Anchor anchor : result) {
anchor.init(this.plugin);
((AnchorImpl) anchor).init(this.plugin);
this.anchors.computeIfAbsent(anchor.getWorld(), k -> new HashSet<>())
this.anchors.computeIfAbsent(anchor.getWorld(), key -> new HashSet<>())
.add(anchor);
}
@ -102,7 +105,7 @@ public class AnchorManager {
if (callback != null) {
callback.accept(ex);
} else {
Utils.logException(this.plugin, ex, "SQLite");
Utils.logException(this.plugin, ex, "H2");
}
}
});
@ -115,7 +118,7 @@ public class AnchorManager {
this.dataManager.updateAnchors(tmpAnchors, null);
for (Anchor anchor : tmpAnchors) {
anchor.deInit(this.plugin);
((AnchorImpl) anchor).deInit(this.plugin);
}
}
}
@ -123,18 +126,19 @@ public class AnchorManager {
protected void setReady() {
this.ready = true;
Bukkit.getScheduler().runTaskTimer(plugin, this::saveAll, 20L * 60 * 5, 20L * 60 * 5);
Bukkit.getScheduler().runTaskTimer(this.plugin, this::saveAll, 20L * 60 * 5, 20L * 60 * 5);
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
@Override
public boolean isReady(World world) {
return this.ready && anchors.containsKey(world);
return this.ready && this.anchors.containsKey(world);
}
/* Getter */
@Override
public Anchor[] getAnchors(@NotNull World world) {
Set<Anchor> set = anchors.get(world);
Set<Anchor> set = this.anchors.get(world);
if (set != null) {
return set.toArray(new Anchor[0]);
@ -143,13 +147,14 @@ public class AnchorManager {
return new Anchor[0];
}
public @Nullable Anchor getAnchor(@NotNull Block b) {
if (!isReady(b.getWorld())) {
@Override
public @Nullable Anchor getAnchor(@NotNull Block block) {
if (!isReady(block.getWorld())) {
throw new IllegalStateException(ERR_WORLD_NOT_READY);
}
Location bLoc = b.getLocation();
Set<Anchor> set = anchors.get(b.getWorld());
Location bLoc = block.getLocation();
Set<Anchor> set = this.anchors.get(block.getWorld());
if (set != null) {
for (Anchor anchor : set) {
@ -162,16 +167,18 @@ public class AnchorManager {
return null;
}
public boolean isAnchor(@NotNull Block b) {
return getAnchor(b) != null;
@Override
public boolean isAnchor(@NotNull Block block) {
return getAnchor(block) != null;
}
@Override
public boolean hasAnchor(@NotNull Chunk chunk) {
if (!isReady(chunk.getWorld())) {
throw new IllegalStateException(ERR_WORLD_NOT_READY);
}
Set<Anchor> set = anchors.get(chunk.getWorld());
Set<Anchor> set = this.anchors.get(chunk.getWorld());
if (set != null) {
for (Anchor anchor : set) {
@ -184,11 +191,13 @@ public class AnchorManager {
return false;
}
@Override
@SuppressWarnings("unused")
public List<Anchor> searchAnchors(Location center, double searchRadius) {
return searchAnchors(center, searchRadius, false);
}
@Override
public List<Anchor> searchAnchors(Location center, double searchRadius, boolean ignoreHeight) {
List<Anchor> result = new ArrayList<>();
@ -214,12 +223,7 @@ public class AnchorManager {
/* 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
*/
@Override
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);
@ -230,14 +234,14 @@ public class AnchorManager {
if (callback != null) {
callback.accept(ex, null);
} else {
Utils.logException(this.plugin, ex, "SQLite");
Utils.logException(this.plugin, ex, "H2");
}
} else {
Bukkit.getScheduler().runTask(this.plugin, () -> {
Block b = loc.getBlock();
b.setType(Settings.MATERIAL.getMaterial().getMaterial());
Block block = loc.getBlock();
block.setType(Settings.MATERIAL.getMaterial().parseMaterial());
anchors.computeIfAbsent(anchor.getWorld(), k -> new HashSet<>())
this.anchors.computeIfAbsent(anchor.getWorld(), key -> new HashSet<>())
.add(anchor);
updateHologram(anchor);
@ -250,16 +254,18 @@ public class AnchorManager {
});
}
@Override
public void destroyAnchor(@NotNull Anchor anchor) {
destroyAnchor(anchor, false);
}
@Override
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()) {
for (Set<Anchor> value : this.anchors.values()) {
value.remove(anchor);
}
@ -269,7 +275,7 @@ public class AnchorManager {
Block anchorBlock = anchorLoc.getBlock();
Material anchorMaterial = anchorBlock.getType();
if (anchorBlock.getType() == Settings.MATERIAL.getMaterial().getMaterial()) {
if (anchorBlock.getType() == Settings.MATERIAL.getMaterial().parseMaterial()) {
anchorBlock.setType(Material.AIR);
}
@ -281,49 +287,35 @@ public class AnchorManager {
}
// Particles & Sound
anchor.getWorld().playSound(anchorLoc, CompatibleSound.ENTITY_GENERIC_EXPLODE.getSound(), 10, 10);
XSound.ENTITY_GENERIC_EXPLODE.play(anchorLoc, 10, 10);
CompatibleParticleHandler.spawnParticles(CompatibleParticleHandler.ParticleType.getParticle(Settings.PARTICLE_DESTROY.getString()),
anchor.getLocation().add(.5, .5, .5), 100, .5, .5, .5);
anchor.deInit(this.plugin);
((AnchorImpl) anchor).deInit(this.plugin);
this.dataManager.deleteAnchorAsync(anchor);
}
/* Anchor access */
@SuppressWarnings("unused")
@Override
public void registerAccessCheck(AnchorAccessCheck accessCheck) {
if (!accessChecks.contains(accessCheck)) {
if (!this.accessChecks.contains(accessCheck)) {
// Adding at the start of the list makes sure the default check is
accessChecks.add(accessCheck);
this.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")
@Override
public boolean unregisterAccessCheck(AnchorAccessCheck accessCheck) {
return accessChecks.remove(accessCheck);
return this.accessChecks.remove(accessCheck);
}
@Override
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)
*/
@Override
public boolean hasAccess(@NotNull Anchor anchor, @NotNull UUID uuid) {
if (anchor.isLegacy() || anchor.getOwner().equals(uuid)) return true;
@ -338,18 +330,21 @@ public class AnchorManager {
/* Anchor item */
@Override
public ItemStack createAnchorItem(int ticks) {
return createAnchorItem(ticks, Settings.MATERIAL.getMaterial());
}
@Override
public ItemStack createAnchorItem(int ticks, Material material) {
return createAnchorItem(ticks, CompatibleMaterial.getMaterial(material));
return createAnchorItem(ticks, CompatibleMaterial.getMaterial(material).get());
}
public ItemStack createAnchorItem(int ticks, CompatibleMaterial material) {
@Override
public ItemStack createAnchorItem(int ticks, XMaterial material) {
if (ticks <= 0 && ticks != -1) throw new IllegalArgumentException();
ItemStack item = material.getItem();
ItemStack item = material.parseItem();
ItemMeta meta = item.getItemMeta();
assert meta != null;
@ -363,43 +358,9 @@ public class AnchorManager {
return nbtItem.getItem();
}
public static int getTicksFromItem(ItemStack item) {
if (item == null || item.getType() == Material.AIR) {
return 0;
}
NBTItem nbtItem = new NBTItem(item);
if (nbtItem.hasTag(NBT_TICKS_KEY)) {
return nbtItem.getInteger(NBT_TICKS_KEY);
}
// Legacy code (pre v2) to stay cross-version compatible
if (Settings.MATERIAL.getMaterial().getMaterial() == item.getType()) {
if (nbtItem.hasTag("ticks")) {
int result = nbtItem.getInteger("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 */
@Override
public boolean toggleChunkVisualized(Player p) {
boolean visualize = !hasChunksVisualized(p);
@ -408,6 +369,7 @@ public class AnchorManager {
return visualize;
}
@Override
public void setChunksVisualized(Player p, boolean visualize) {
if (visualize) {
this.visualizedChunk.add(p);
@ -416,6 +378,7 @@ public class AnchorManager {
}
}
@Override
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
public boolean hasChunksVisualized(Player p) {
return this.visualizedChunk.contains(p);
@ -423,6 +386,7 @@ public class AnchorManager {
/* Holograms */
@Override
public void updateHolograms(List<Anchor> anchors) {
// are holograms enabled?
if (!Settings.HOLOGRAMS.getBoolean() || !HologramManager.getManager().isEnabled()) return;
@ -432,12 +396,12 @@ public class AnchorManager {
for (Anchor anchor : anchors) {
List<String> lines = Collections.singletonList(formatAnchorText(anchor.getTicksLeft(), true));
if (!HologramManager.isHologramLoaded("Anchor#" + anchor.getDbId())) {
HologramManager.createHologram("Anchor#" + anchor.getDbId(), anchor.getLocation(), lines);
if (!HologramManager.isHologramLoaded(HOLOGRAM_PREFIX + anchor.getDbId())) {
HologramManager.createHologram(HOLOGRAM_PREFIX + anchor.getDbId(), anchor.getLocation(), lines);
continue;
}
hologramData.put("Anchor#" + anchor.getDbId(), lines);
hologramData.put(HOLOGRAM_PREFIX + anchor.getDbId(), lines);
}
// Create the holograms
@ -473,7 +437,42 @@ public class AnchorManager {
return TextUtils.formatText(Settings.NAME_TAG.getString().replace("{REMAINING}", remaining));
}
public static int getTicksFromItem(ItemStack item) {
if (item == null || item.getType() == Material.AIR) {
return 0;
}
NBTItem nbtItem = new NBTItem(item);
if (nbtItem.hasTag(NBT_TICKS_KEY)) {
return nbtItem.getInteger(NBT_TICKS_KEY);
}
// Legacy code (pre v2) to stay cross-version compatible
if (Settings.MATERIAL.getMaterial().parseMaterial() == item.getType()) {
if (nbtItem.hasTag("ticks")) {
int result = nbtItem.getInteger("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;
}
private static void removeHologram(Anchor anchor) {
HologramManager.removeHologram("Anchor#" + anchor.getDbId());
HologramManager.removeHologram(HOLOGRAM_PREFIX + anchor.getDbId());
}
}

View File

@ -1,30 +1,30 @@
package com.songoda.epicanchors;
package com.craftaro.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.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.WorldListener;
import com.songoda.epicanchors.tasks.AnchorTask;
import com.songoda.epicanchors.tasks.VisualizeTask;
import com.songoda.epicanchors.utils.ThreadSync;
import com.craftaro.core.SongodaCore;
import com.craftaro.core.SongodaPlugin;
import com.craftaro.core.commands.CommandManager;
import com.craftaro.core.configuration.Config;
import com.craftaro.core.dependency.Dependency;
import com.craftaro.core.gui.GuiManager;
import com.craftaro.core.hooks.EconomyManager;
import com.craftaro.core.hooks.HologramManager;
import com.craftaro.epicanchors.api.AnchorManager;
import com.craftaro.epicanchors.commands.EpicAnchorsCommand;
import com.craftaro.epicanchors.commands.sub.GiveCommand;
import com.craftaro.epicanchors.commands.sub.ReloadCommand;
import com.craftaro.epicanchors.commands.sub.SettingsCommand;
import com.craftaro.epicanchors.commands.sub.ShowCommand;
import com.craftaro.epicanchors.files.AnchorsDataManager;
import com.craftaro.epicanchors.files.Settings;
import com.craftaro.epicanchors.files.migration.LegacyYamlAnchorsMigrator;
import com.craftaro.epicanchors.files.migration._1_InitialMigration;
import com.craftaro.epicanchors.listener.AnchorListener;
import com.craftaro.epicanchors.listener.BlockListener;
import com.craftaro.epicanchors.listener.WorldListener;
import com.craftaro.epicanchors.tasks.AnchorTask;
import com.craftaro.epicanchors.tasks.VisualizeTask;
import com.craftaro.epicanchors.utils.ThreadSync;
import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.plugin.PluginManager;
@ -35,9 +35,9 @@ import java.util.logging.Level;
public final class EpicAnchors extends SongodaPlugin {
private GuiManager guiManager;
private AnchorManager anchorManager;
private AnchorManagerImpl anchorManager;
private DataManager dataManager;
private AnchorsDataManager dataManager;
@Override
public void onPluginLoad() {
@ -45,19 +45,12 @@ public final class EpicAnchors extends SongodaPlugin {
@Override
public void onPluginEnable() {
// Songoda Updater
SongodaCore.registerPlugin(this, 31, CompatibleMaterial.END_PORTAL_FRAME);
SongodaCore.registerPlugin(this, 31, XMaterial.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();
initializeDataManager();
anchorMigration.migrateLegacyData(this);
this.anchorManager = new AnchorManager(this, this.dataManager);
this.anchorManager = new AnchorManagerImpl(this, this.dataManager);
EpicAnchorsApi.initApi(this.anchorManager);
// Economy [1/2]
EconomyManager.load();
@ -74,7 +67,7 @@ public final class EpicAnchors extends SongodaPlugin {
// Event Listener
this.guiManager = new GuiManager(this);
guiManager.init();
this.guiManager.init();
PluginManager pluginManager = Bukkit.getPluginManager();
pluginManager.registerEvents(new WorldListener(
world -> this.anchorManager.initAnchorsAsync(world, null),
@ -150,4 +143,19 @@ public final class EpicAnchors extends SongodaPlugin {
public AnchorManager getAnchorManager() {
return this.anchorManager;
}
@Override
public Config getDatabaseConfig() {
Config staticDatabaseConfig = new Config();
staticDatabaseConfig.set("Connection Settings.Type", "H2");
staticDatabaseConfig.set("Connection Settings.Pool Size", 1);
return staticDatabaseConfig;
}
private void initializeDataManager() {
super.initDatabase(new _1_InitialMigration());
this.dataManager = new AnchorsDataManager(this);
LegacyYamlAnchorsMigrator.migrateLegacyData(this, this.dataManager);
}
}

View File

@ -1,8 +1,8 @@
package com.songoda.epicanchors.commands;
package com.craftaro.epicanchors.commands;
import com.songoda.core.commands.AbstractCommand;
import com.songoda.core.commands.CommandManager;
import com.songoda.epicanchors.EpicAnchors;
import com.craftaro.core.commands.AbstractCommand;
import com.craftaro.core.commands.CommandManager;
import com.craftaro.epicanchors.EpicAnchors;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
@ -24,7 +24,7 @@ public class EpicAnchorsCommand extends AbstractCommand {
protected ReturnType runCommand(CommandSender sender, String... args) {
sender.sendMessage("");
this.plugin.getLocale().newMessage("&7Version " + this.plugin.getDescription().getVersion()
+ " Created with <3 by &5&l&oSongoda").sendPrefixedMessage(sender);
+ " Created with <3 by &5&l&oCraftaro").sendPrefixedMessage(sender);
for (AbstractCommand cmd : this.commandManager.getAllCommands()) {
if (cmd.getPermissionNode() == null || sender.hasPermission(cmd.getPermissionNode())) {
@ -38,7 +38,7 @@ public class EpicAnchorsCommand extends AbstractCommand {
}
@Override
protected List<String> onTab(CommandSender commandSender, String... strings) {
protected List<String> onTab(CommandSender sender, String... args) {
return Collections.emptyList();
}

View File

@ -1,8 +1,8 @@
package com.songoda.epicanchors.commands.sub;
package com.craftaro.epicanchors.commands.sub;
import com.songoda.core.commands.AbstractCommand;
import com.songoda.epicanchors.EpicAnchors;
import com.songoda.epicanchors.utils.Utils;
import com.craftaro.core.commands.AbstractCommand;
import com.craftaro.epicanchors.EpicAnchors;
import com.craftaro.epicanchors.utils.Utils;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -32,7 +32,7 @@ public class GiveCommand extends AbstractCommand {
if (target == null &&
!args[0].trim().equalsIgnoreCase("all") &&
!args[0].trim().equalsIgnoreCase("@a")) {
plugin.getLocale().newMessage("&cThat is not a player...").sendPrefixedMessage(sender);
this.plugin.getLocale().newMessage("&cThat is not a player...").sendPrefixedMessage(sender);
return ReturnType.SYNTAX_ERROR;
}
@ -40,22 +40,22 @@ public class GiveCommand extends AbstractCommand {
ItemStack itemStack;
if (Utils.isInt(args[1]) && Integer.parseInt(args[1]) > 0) {
itemStack = plugin.getAnchorManager().createAnchorItem(Integer.parseInt(args[1]) * 20 * 60 * 60);
itemStack = this.plugin.getAnchorManager().createAnchorItem(Integer.parseInt(args[1]) * 20 * 60 * 60);
} else if (args[1].equalsIgnoreCase("infinite")) {
itemStack = plugin.getAnchorManager().createAnchorItem(-1);
itemStack = this.plugin.getAnchorManager().createAnchorItem(-1);
} else {
plugin.getLocale().newMessage("&cYou can only use positive whole numbers...").sendPrefixedMessage(sender);
this.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);
this.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);
this.plugin.getLocale().getMessage("command.give.success").sendPrefixedMessage(online);
}
}
@ -63,7 +63,7 @@ public class GiveCommand extends AbstractCommand {
}
@Override
protected List<String> onTab(CommandSender commandSender, String... args) {
protected List<String> onTab(CommandSender sender, String... args) {
if (args.length == 1) {
Set<String> players = new HashSet<>();

View File

@ -1,7 +1,7 @@
package com.songoda.epicanchors.commands.sub;
package com.craftaro.epicanchors.commands.sub;
import com.songoda.core.commands.AbstractCommand;
import com.songoda.epicanchors.EpicAnchors;
import com.craftaro.core.commands.AbstractCommand;
import com.craftaro.epicanchors.EpicAnchors;
import org.bukkit.command.CommandSender;
import java.util.Collections;
@ -17,8 +17,8 @@ public class ReloadCommand extends AbstractCommand {
@Override
protected ReturnType runCommand(CommandSender sender, String... args) {
plugin.reloadConfig();
plugin.getLocale().getMessage("&7Configuration and Language files reloaded.").sendPrefixedMessage(sender);
this.plugin.reloadConfig();
this.plugin.getLocale().getMessage("&7Configuration and Language files reloaded.").sendPrefixedMessage(sender);
return ReturnType.SUCCESS;
}

View File

@ -1,9 +1,9 @@
package com.songoda.epicanchors.commands.sub;
package com.craftaro.epicanchors.commands.sub;
import com.songoda.core.commands.AbstractCommand;
import com.songoda.core.configuration.editor.PluginConfigGui;
import com.songoda.core.gui.GuiManager;
import com.songoda.epicanchors.EpicAnchors;
import com.craftaro.core.commands.AbstractCommand;
import com.craftaro.core.configuration.editor.PluginConfigGui;
import com.craftaro.core.gui.GuiManager;
import com.craftaro.epicanchors.EpicAnchors;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -23,13 +23,13 @@ public class SettingsCommand extends AbstractCommand {
@Override
protected ReturnType runCommand(CommandSender sender, String... args) {
guiManager.showGUI((Player) sender, new PluginConfigGui(instance));
this.guiManager.showGUI((Player) sender, new PluginConfigGui(this.instance));
return AbstractCommand.ReturnType.SUCCESS;
}
@Override
protected List<String> onTab(CommandSender commandSender, String... strings) {
protected List<String> onTab(CommandSender sender, String... args) {
return Collections.emptyList();
}

View File

@ -1,7 +1,7 @@
package com.songoda.epicanchors.commands.sub;
package com.craftaro.epicanchors.commands.sub;
import com.songoda.core.commands.AbstractCommand;
import com.songoda.epicanchors.EpicAnchors;
import com.craftaro.core.commands.AbstractCommand;
import com.craftaro.epicanchors.EpicAnchors;
import net.md_5.bungee.api.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -30,7 +30,7 @@ public class ShowCommand extends AbstractCommand {
boolean visualize = this.plugin.getAnchorManager().toggleChunkVisualized((Player) sender);
plugin.getLocale().getMessage("command.show." + (visualize ? "start" : "stop"))
this.plugin.getLocale().getMessage("command.show." + (visualize ? "start" : "stop"))
.sendPrefixedMessage(sender);
return ReturnType.SUCCESS;

View File

@ -1,16 +1,16 @@
package com.songoda.epicanchors.files;
package com.craftaro.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 com.craftaro.core.SongodaPlugin;
import com.craftaro.core.database.DatabaseConnector;
import com.craftaro.epicanchors.AnchorImpl;
import com.craftaro.epicanchors.api.Anchor;
import com.craftaro.epicanchors.files.migration.LegacyYamlAnchorsMigrator;
import com.craftaro.epicanchors.utils.Callback;
import com.craftaro.epicanchors.utils.UpdateCallback;
import com.craftaro.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;
@ -27,38 +27,35 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class DataManager extends DataManagerAbstract {
public class AnchorsDataManager {
private final ExecutorService thread = Executors.newSingleThreadExecutor();
private final SongodaPlugin plugin;
private final String anchorTable;
public DataManager(DatabaseConnector databaseConnector, Plugin plugin) {
super(databaseConnector, plugin);
this.anchorTable = getTableName(super.getTablePrefix(), "anchors");
public AnchorsDataManager(SongodaPlugin plugin) {
this.plugin = plugin;
}
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();
if (this.thread.isShutdown()) {
return;
}
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(this.plugin, ex);
}
this.plugin.getDataManager().shutdown();
}
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=?;")) {
getDatabaseConnector().connect((con) -> {
try (PreparedStatement ps = con.prepareStatement("SELECT id FROM " + getAnchorTable() + " WHERE world_name =? AND x =? AND y =? AND z=?;")) {
ps.setString(1, worldName);
ps.setInt(2, x);
ps.setInt(3, y);
@ -76,9 +73,8 @@ public class DataManager extends DataManagerAbstract {
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 =?" : "") + ";")) {
getDatabaseConnector().connect((con) -> {
try (PreparedStatement ps = con.prepareStatement("SELECT * FROM " + getAnchorTable() + (world != null ? " WHERE world_name =?" : "") + ";")) {
if (world != null) {
ps.setString(1, world.getName());
}
@ -101,11 +97,10 @@ public class DataManager extends DataManagerAbstract {
}
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=?;")) {
getDatabaseConnector().connect((con) -> {
try (PreparedStatement ps = con.prepareStatement("INSERT INTO " + getAnchorTable() + "(owner, world_name,x,y,z, ticks_left) VALUES (?,?,?,?,?, ?);"); // Future SQLite version might support 'RETURNING *'
PreparedStatement psFetch = con.prepareStatement("SELECT * FROM " + getAnchorTable() + " 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());
@ -136,15 +131,14 @@ public class DataManager extends DataManagerAbstract {
});
}
public void migrateAnchor(List<AnchorMigration.LegacyAnchorEntry> anchorEntries, UpdateCallback callback) {
this.databaseConnector.connect((con) -> {
public void migrateAnchor(List<LegacyYamlAnchorsMigrator.LegacyAnchorEntry> anchorEntries, UpdateCallback callback) {
getDatabaseConnector().connect((con) -> {
con.setAutoCommit(false);
SQLException err = null;
try (PreparedStatement ps = con.prepareStatement("INSERT INTO " + this.anchorTable +
"(world_name,x,y,z, ticks_left) VALUES (?,?,?,?, ?);")) {
for (AnchorMigration.LegacyAnchorEntry entry : anchorEntries) {
try (PreparedStatement ps = con.prepareStatement("INSERT INTO " + getAnchorTable() + "(world_name,x,y,z, ticks_left) VALUES (?,?,?,?, ?);")) {
for (LegacyYamlAnchorsMigrator.LegacyAnchorEntry entry : anchorEntries) {
ps.setString(1, entry.worldName);
ps.setInt(2, entry.x);
ps.setInt(3, entry.y);
@ -159,7 +153,7 @@ public class DataManager extends DataManagerAbstract {
for (int i : batchRes) {
if (i < 0 && i != Statement.SUCCESS_NO_INFO) {
throw new AssertionError("Batch-INSERT failed for at least one statement with code " + i + "");
throw new AssertionError("Batch-INSERT failed for at least one statement with code " + i);
}
}
} catch (SQLException ex) {
@ -181,14 +175,13 @@ public class DataManager extends DataManagerAbstract {
}
public void updateAnchors(Collection<Anchor> anchors, UpdateCallback callback) {
this.databaseConnector.connect((con) -> {
getDatabaseConnector().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 =?;")) {
try (PreparedStatement ps = con.prepareStatement("UPDATE " + getAnchorTable() + " SET ticks_left =? WHERE id =?;")) {
ps.setInt(1, anchor.getTicksLeft());
ps.setInt(2, anchor.getDbId());
@ -219,9 +212,8 @@ public class DataManager extends DataManagerAbstract {
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 =?;")) {
getDatabaseConnector().connect((con) -> {
try (PreparedStatement ps = con.prepareStatement("DELETE FROM " + getAnchorTable() + " WHERE id =?;")) {
ps.setInt(1, anchor.getDbId());
ps.executeUpdate();
@ -234,20 +226,22 @@ public class DataManager extends DataManagerAbstract {
);
}
public static String getTableName(String prefix, String name) {
String result = prefix + name;
public String getAnchorTable() {
return getAnchorTable(this.plugin.getDataManager().getTablePrefix());
}
if (!result.matches("[a-z0-9_]+")) {
throw new IllegalStateException("The generated table name '" + result + "' contains invalid characters");
}
public static String getAnchorTable(String prefix) {
return prefix + "anchors";
}
return result;
private DatabaseConnector getDatabaseConnector() {
return this.plugin.getDataManager().getDatabaseConnector();
}
private Anchor extractAnchor(ResultSet rs) throws SQLException {
String ownerStr = rs.getString("owner");
return new Anchor(rs.getInt("id"),
return new AnchorImpl(rs.getInt("id"),
ownerStr != null ? UUID.fromString(ownerStr) : null,
new Location(Bukkit.getWorld(rs.getString("world_name")),
rs.getInt("x"),
@ -260,7 +254,7 @@ public class DataManager extends DataManagerAbstract {
if (callback != null) {
callback.accept(ex);
} else if (ex != null) {
Utils.logException(this.plugin, ex, "SQLite");
Utils.logException(this.plugin, ex, "H2");
}
}
@ -268,7 +262,7 @@ public class DataManager extends DataManagerAbstract {
if (callback != null) {
callback.accept(ex, null);
} else {
Utils.logException(this.plugin, ex, "SQLite");
Utils.logException(this.plugin, ex, "H2");
}
}
}

View File

@ -1,11 +1,12 @@
package com.songoda.epicanchors.files;
package com.craftaro.epicanchors.files;
import com.songoda.core.compatibility.CompatibleMaterial;
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 com.craftaro.core.compatibility.CompatibleMaterial;
import com.craftaro.core.compatibility.CompatibleParticleHandler;
import com.craftaro.core.configuration.Config;
import com.craftaro.core.configuration.ConfigSetting;
import com.craftaro.core.hooks.EconomyManager;
import com.craftaro.epicanchors.EpicAnchors;
import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
import org.bukkit.plugin.java.JavaPlugin;
public class Settings {
@ -13,60 +14,60 @@ public class Settings {
throw new IllegalStateException("Utility class");
}
public static final Config config = JavaPlugin.getPlugin(EpicAnchors.class).getCoreConfig();
public static final Config CONFIG = JavaPlugin.getPlugin(EpicAnchors.class).getCoreConfig();
public static final ConfigSetting NAME_TAG = new ConfigSetting(config, "Main.Name Tag",
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",
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.name(), "The material an anchor is represented with?");
public static final ConfigSetting MATERIAL = new ConfigSetting(CONFIG, "Main.Anchor Block Material",
XMaterial.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,
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,
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,
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?");
public static final ConfigSetting ECONOMY_COST = new ConfigSetting(config, "Main.Economy Cost", 5000.0,
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 ALLOW_ANCHOR_BREAKING = new ConfigSetting(config, "Main.Allow Anchor Breaking", false,
public static final ConfigSetting ALLOW_ANCHOR_BREAKING = new ConfigSetting(CONFIG, "Main.Allow Anchor Breaking", false,
"Should players be able to break anchors and get an item dropped?");
public static final ConfigSetting HOLOGRAMS = new ConfigSetting(config, "Main.Holograms", true,
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(),
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: \"" + String.join(", ", EconomyManager.getManager().getRegisteredPlugins()) + "\".");
public static final ConfigSetting ECO_ICON = new ConfigSetting(config, "Interfaces.Economy Icon", CompatibleMaterial.SUNFLOWER.name(),
public static final ConfigSetting ECO_ICON = new ConfigSetting(CONFIG, "Interfaces.Economy Icon", XMaterial.SUNFLOWER.name(),
"Item to be displayed as the icon for economy upgrades.");
public static final ConfigSetting XP_ICON = new ConfigSetting(config, "Interfaces.XP Icon", CompatibleMaterial.EXPERIENCE_BOTTLE.name(),
public static final ConfigSetting XP_ICON = new ConfigSetting(CONFIG, "Interfaces.XP Icon", XMaterial.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", 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 GLASS_TYPE_1 = new ConfigSetting(CONFIG, "Interfaces.Glass Type 1", XMaterial.GRAY_STAINED_GLASS_PANE.name());
public static final ConfigSetting GLASS_TYPE_2 = new ConfigSetting(CONFIG, "Interfaces.Glass Type 2", XMaterial.BLUE_STAINED_GLASS_PANE.name());
public static final ConfigSetting GLASS_TYPE_3 = new ConfigSetting(CONFIG, "Interfaces.Glass Type 3", XMaterial.LIGHT_BLUE_STAINED_GLASS_PANE.name());
public static final ConfigSetting PARTICLE_DESTROY = new ConfigSetting(config, "Particles.Destroy",
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",
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",
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",
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.");
@ -75,31 +76,31 @@ public class Settings {
* called after EconomyManager load
*/
public static void setupConfig() {
config.load();
config.setAutoremove(true)
CONFIG.load();
CONFIG.setAutoremove(true)
.setAutosave(true);
// convert glass pane settings
int color;
if ((color = GLASS_TYPE_1.getInt(-1)) != -1) {
config.set(GLASS_TYPE_1.getKey(), CompatibleMaterial.getGlassPaneColor(color).name());
CONFIG.set(GLASS_TYPE_1.getKey(), CompatibleMaterial.getGlassPaneForColor(color).name());
}
if ((color = GLASS_TYPE_2.getInt(-1)) != -1) {
config.set(GLASS_TYPE_2.getKey(), CompatibleMaterial.getGlassPaneColor(color).name());
CONFIG.set(GLASS_TYPE_2.getKey(), CompatibleMaterial.getGlassPaneForColor(color).name());
}
if ((color = GLASS_TYPE_3.getInt(-1)) != -1) {
config.set(GLASS_TYPE_3.getKey(), CompatibleMaterial.getGlassPaneColor(color).name());
CONFIG.set(GLASS_TYPE_3.getKey(), CompatibleMaterial.getGlassPaneForColor(color).name());
}
// convert economy settings
if (config.getBoolean("Economy.Use Vault Economy") && EconomyManager.getManager().isEnabled("Vault")) {
config.set("Main.Economy", "Vault");
} else if (config.getBoolean("Economy.Use Reserve Economy") && EconomyManager.getManager().isEnabled("Reserve")) {
config.set("Main.Economy", "Reserve");
} else if (config.getBoolean("Economy.Use Player Points Economy") && EconomyManager.getManager().isEnabled("PlayerPoints")) {
config.set("Main.Economy", "PlayerPoints");
if (CONFIG.getBoolean("Economy.Use Vault Economy") && EconomyManager.getManager().isEnabled("Vault")) {
CONFIG.set("Main.Economy", "Vault");
} else if (CONFIG.getBoolean("Economy.Use Reserve Economy") && EconomyManager.getManager().isEnabled("Reserve")) {
CONFIG.set("Main.Economy", "Reserve");
} else if (CONFIG.getBoolean("Economy.Use Player Points Economy") && EconomyManager.getManager().isEnabled("PlayerPoints")) {
CONFIG.set("Main.Economy", "PlayerPoints");
}
config.saveChanges();
CONFIG.saveChanges();
}
}

View File

@ -1,12 +1,9 @@
package com.songoda.epicanchors.files.migration;
package com.craftaro.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 com.craftaro.core.configuration.Config;
import com.craftaro.core.configuration.ConfigSection;
import com.craftaro.epicanchors.files.AnchorsDataManager;
import com.craftaro.epicanchors.utils.ThreadSync;
import org.bukkit.Location;
import org.bukkit.plugin.Plugin;
@ -18,16 +15,8 @@ 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;
}
public void migrateLegacyData(Plugin plugin) {
public class LegacyYamlAnchorsMigrator {
public static void migrateLegacyData(Plugin plugin, AnchorsDataManager dataManager) {
long start = System.nanoTime();
AtomicBoolean abortMigration = new AtomicBoolean(false);
@ -94,7 +83,7 @@ public class AnchorMigration extends DataMigrationManager {
if (!abortMigration.get()) {
int finalMigratedAnchors = migratedAnchors;
this.dataManager.migrateAnchor(anchorQueue, ex -> {
dataManager.migrateAnchor(anchorQueue, ex -> {
long end = System.nanoTime();
if (ex == null) {
@ -114,7 +103,7 @@ public class AnchorMigration extends DataMigrationManager {
}
}
private String[] deserializeLegacyLocation(String str) {
private static String[] deserializeLegacyLocation(String str) {
if (str == null || str.isEmpty()) {
return new String[0];
}

View File

@ -0,0 +1,31 @@
package com.craftaro.epicanchors.files.migration;
import com.craftaro.core.database.DataMigration;
import com.craftaro.epicanchors.files.AnchorsDataManager;
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 " + AnchorsDataManager.getAnchorTable(tablePrefix) +
"(" +
"id INTEGER NOT NULL PRIMARY KEY auto_increment," +
"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)" +
");");
}
}
}

View File

@ -1,16 +1,16 @@
package com.songoda.epicanchors.guis;
package com.craftaro.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 com.craftaro.core.compatibility.CompatibleParticleHandler;
import com.craftaro.core.gui.Gui;
import com.craftaro.core.gui.GuiUtils;
import com.craftaro.core.hooks.EconomyManager;
import com.craftaro.core.utils.TextUtils;
import com.craftaro.core.utils.TimeUtils;
import com.craftaro.epicanchors.EpicAnchors;
import com.craftaro.epicanchors.api.Anchor;
import com.craftaro.epicanchors.files.Settings;
import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
import com.craftaro.third_party.com.cryptomorin.xseries.XSound;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
@ -36,26 +36,26 @@ public class AnchorGui extends Gui {
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")
String itemName = this.plugin.getLocale().getMessage("interface.button.addtimewithxp").getMessage();
String itemLore = this.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));
GuiUtils.createButtonItem(Settings.XP_ICON.getMaterial(XMaterial.EXPERIENCE_BOTTLE), itemName, itemLore),
event -> buyTime(this.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")
String itemName = this.plugin.getLocale().getMessage("interface.button.addtimewitheconomy").getMessage();
String itemLore = this.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));
GuiUtils.createButtonItem(Settings.ECO_ICON.getMaterial(XMaterial.SUNFLOWER), itemName, itemLore),
event -> buyTime(this.anchor, event.player, true));
}
}
@ -84,7 +84,7 @@ public class AnchorGui extends Gui {
if (success) {
anchor.addTicksLeft(20 * 60 * 30); // 30 minutes
p.playSound(p.getLocation(), CompatibleSound.ENTITY_PLAYER_LEVELUP.getSound(), 0.6F, 15);
XSound.ENTITY_PLAYER_LEVELUP.play(p, .6f, 15);
CompatibleParticleHandler.spawnParticles(CompatibleParticleHandler.ParticleType.getParticle(Settings.PARTICLE_UPGRADE.getString()),
anchor.getLocation().add(.5, .5, .5), 100, .5, .5, .5);
} else {
@ -112,7 +112,7 @@ public class AnchorGui extends Gui {
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()),
anchor.getTicksLeft(), anchor.getLocation().getBlock().getType()),
itemName, itemLore));
}

View File

@ -0,0 +1,64 @@
package com.craftaro.epicanchors.guis;
import com.craftaro.core.gui.Gui;
import com.craftaro.core.gui.GuiUtils;
import com.craftaro.core.gui.methods.Closable;
import com.craftaro.core.utils.TextUtils;
import com.craftaro.epicanchors.EpicAnchors;
import com.craftaro.epicanchors.api.Anchor;
import com.craftaro.epicanchors.files.Settings;
import com.craftaro.epicanchors.utils.Callback;
import com.craftaro.third_party.com.cryptomorin.xseries.XMaterial;
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 = this.plugin.getLocale().getMessage("interface.button.cancelDestroyLore").getMessage();
String confirmLore = this.plugin.getLocale().getMessage("interface.button." +
(Settings.ALLOW_ANCHOR_BREAKING.getBoolean() ? "confirmDestroyLore" : "confirmDestroyLoreNoDrops"))
.getMessage();
setButton(11, GuiUtils.createButtonItem(XMaterial.RED_TERRACOTTA,
this.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(XMaterial.GREEN_TERRACOTTA,
this.plugin.getLocale().getMessage("interface.button.confirmDestroy").getMessage(),
confirmLore.isEmpty() ? new String[0] : new String[]{confirmLore}),
event -> this.handler.accept(null, true));
}
}

View File

@ -1,15 +1,15 @@
package com.songoda.epicanchors.listener;
package com.craftaro.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 com.craftaro.core.compatibility.CompatibleHand;
import com.craftaro.core.compatibility.CompatibleParticleHandler;
import com.craftaro.epicanchors.AnchorManagerImpl;
import com.craftaro.epicanchors.EpicAnchors;
import com.craftaro.epicanchors.api.Anchor;
import com.craftaro.epicanchors.files.Settings;
import com.craftaro.epicanchors.guis.AnchorGui;
import com.craftaro.epicanchors.guis.DestroyConfirmationGui;
import com.craftaro.epicanchors.utils.Utils;
import com.craftaro.third_party.com.cryptomorin.xseries.XSound;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Material;
@ -36,30 +36,30 @@ public class AnchorListener implements Listener {
if (item.hasItemMeta() &&
item.getItemMeta().hasDisplayName() &&
Settings.MATERIAL.getMaterial().getMaterial() == e.getBlock().getType()) {
if (!plugin.getAnchorManager().isReady(e.getBlock().getWorld())) {
Settings.MATERIAL.getMaterial().parseMaterial() == e.getBlock().getType()) {
if (!this.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);
int ticksLeft = AnchorManagerImpl.getTicksFromItem(item);
if (ticksLeft != 0) {
boolean dropOnErr = e.getPlayer().getGameMode() != GameMode.CREATIVE;
plugin.getAnchorManager().createAnchor(e.getBlock().getLocation(), e.getPlayer().getUniqueId(), ticksLeft,
this.plugin.getAnchorManager().createAnchor(e.getBlock().getLocation(), e.getPlayer().getUniqueId(), ticksLeft,
(ex, result) -> {
if (ex != null) {
Utils.logException(this.plugin, ex, "SQLite");
Utils.logException(this.plugin, ex, "H2");
e.getPlayer().sendMessage("Error creating anchor!"); // TODO
Bukkit.getScheduler().runTask(this.plugin, () -> {
if (Settings.MATERIAL.getMaterial().getMaterial() == e.getBlock().getType()) {
if (Settings.MATERIAL.getMaterial().parseMaterial() == e.getBlock().getType()) {
e.getBlock().setType(Material.AIR);
}
if (dropOnErr) {
e.getBlock().getWorld().dropItemNaturally(e.getBlock().getLocation(),
plugin.getAnchorManager().createAnchorItem(ticksLeft, item.getType()));
this.plugin.getAnchorManager().createAnchorItem(ticksLeft, item.getType()));
}
});
}
@ -72,16 +72,16 @@ public class AnchorListener implements Listener {
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
public void onBlockInteract(PlayerInteractEvent e) {
if (e.getClickedBlock() == null ||
!plugin.getAnchorManager().isReady(e.getClickedBlock().getWorld())) return;
!this.plugin.getAnchorManager().isReady(e.getClickedBlock().getWorld())) return;
Player p = e.getPlayer();
Anchor anchor = plugin.getAnchorManager().getAnchor(e.getClickedBlock());
Anchor anchor = this.plugin.getAnchorManager().getAnchor(e.getClickedBlock());
if (anchor != null) {
e.setCancelled(true);
if (p.hasPermission("EpicAnchors.admin") ||
this.plugin.getAnchorManager().hasAccess(anchor, p)) {
this.plugin.getAnchorManager().hasAccess(anchor, p.getUniqueId())) {
if (e.getAction() == Action.LEFT_CLICK_BLOCK) { // Destroy anchor
this.plugin.getGuiManager().showGUI(e.getPlayer(),
new DestroyConfirmationGui(this.plugin, anchor, (ex, result) -> {
@ -90,13 +90,13 @@ public class AnchorListener implements Listener {
Bukkit.getPluginManager().callEvent(blockBreakEvent);
if (!blockBreakEvent.isCancelled()) {
plugin.getAnchorManager().destroyAnchor(anchor);
this.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);
int itemTicks = AnchorManagerImpl.getTicksFromItem(item);
if (itemTicks != 0) {
if (!anchor.isInfinite()) {
@ -110,16 +110,16 @@ public class AnchorListener implements Listener {
CompatibleHand.MAIN_HAND.takeItem(p, 1);
}
p.playSound(p.getLocation(), CompatibleSound.ENTITY_PLAYER_LEVELUP.getSound(), .6F, 15);
XSound.ENTITY_PLAYER_LEVELUP.play(p, .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));
this.plugin.getGuiManager().showGUI(p, new AnchorGui(this.plugin, anchor));
}
}
} else {
plugin.getLocale().getMessage("event.general.nopermission").sendMessage(p);
this.plugin.getLocale().getMessage("event.general.nopermission").sendMessage(p);
}
}
}

View File

@ -1,6 +1,6 @@
package com.songoda.epicanchors.listener;
package com.craftaro.epicanchors.listener;
import com.songoda.epicanchors.AnchorManager;
import com.craftaro.epicanchors.api.AnchorManager;
import org.bukkit.block.Block;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@ -22,7 +22,7 @@ public class BlockListener implements Listener {
private void onBlockBurn(BlockBurnEvent e) {
if (!this.manager.isReady(e.getBlock().getWorld())) return;
if (manager.isAnchor(e.getBlock())) {
if (this.manager.isAnchor(e.getBlock())) {
e.setCancelled(true);
}
}
@ -31,7 +31,7 @@ public class BlockListener implements Listener {
private void onBlockPiston(BlockPistonExtendEvent e) {
if (!this.manager.isReady(e.getBlock().getWorld())) return;
if (manager.isAnchor(e.getBlock())) {
if (this.manager.isAnchor(e.getBlock())) {
e.setCancelled(true);
}
}
@ -40,7 +40,7 @@ public class BlockListener implements Listener {
private void onBlockPiston(BlockPistonRetractEvent e) {
if (!this.manager.isReady(e.getBlock().getWorld())) return;
if (manager.isAnchor(e.getBlock())) {
if (this.manager.isAnchor(e.getBlock())) {
e.setCancelled(true);
}
}
@ -49,7 +49,7 @@ public class BlockListener implements Listener {
private void onBlockPhysics(BlockPhysicsEvent e) {
if (!this.manager.isReady(e.getBlock().getWorld())) return;
if (manager.isAnchor(e.getBlock())) {
if (this.manager.isAnchor(e.getBlock())) {
e.setCancelled(true);
}
}
@ -58,7 +58,7 @@ public class BlockListener implements Listener {
private void onBlockPiston(LeavesDecayEvent e) {
if (!this.manager.isReady(e.getBlock().getWorld())) return;
if (manager.isAnchor(e.getBlock())) {
if (this.manager.isAnchor(e.getBlock())) {
e.setCancelled(true);
}
}
@ -67,8 +67,8 @@ public class BlockListener implements Listener {
public void onPortalCreation(PortalCreateEvent e) {
if (!this.manager.isReady(e.getWorld())) return;
for (Block b : e.getBlocks()) {
if (manager.isAnchor(b)) {
for (Block block : e.getBlocks()) {
if (this.manager.isAnchor(block)) {
e.setCancelled(true);
break;
}

View File

@ -1,6 +1,6 @@
package com.songoda.epicanchors.listener;
package com.craftaro.epicanchors.listener;
import com.songoda.epicanchors.EpicAnchors;
import com.craftaro.epicanchors.EpicAnchors;
import org.apache.commons.lang.WordUtils;
import org.bukkit.Chunk;
import org.bukkit.Location;
@ -83,22 +83,22 @@ public class DebugListener implements Listener {
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);
count.compute(entity.getType().name(), (key, value) -> value == null ? 1 : value + 1);
}
} else {
e.getPlayer().sendMessage("§e§lTileEntities");
for (BlockState blockState : chunk.getTileEntities()) {
count.compute(blockState.getType().name(), (k, v) -> v == null ? 1 : v + 1);
count.compute(blockState.getType().name(), (key, value) -> value == null ? 1 : value + 1);
}
}
Map<String, Integer> m = count.entrySet().stream()
Map<String, Integer> sortedEntitiyCount = count.entrySet()
.stream()
.sorted(Map.Entry.<String, Integer>comparingByValue().reversed())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
(e1, e2) -> e1, LinkedHashMap::new));
.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("_", "");
for (Map.Entry<String, Integer> entry : sortedEntitiyCount.entrySet()) {
String entityName = WordUtils.capitalize(entry.getKey().toLowerCase(), new char[]{'_'}).replace("_", "");
e.getPlayer().sendMessage("§a" + entityName + "§7:§r " + entry.getValue());
}

View File

@ -1,4 +1,4 @@
package com.songoda.epicanchors.listener;
package com.craftaro.epicanchors.listener;
import org.bukkit.World;
import org.bukkit.event.EventHandler;
@ -20,11 +20,11 @@ public class WorldListener implements Listener {
@EventHandler(priority = EventPriority.MONITOR)
private void onWorldLoad(WorldLoadEvent e) {
initAnchorsInWorld.accept(e.getWorld());
this.initAnchorsInWorld.accept(e.getWorld());
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
private void onWorldUnload(WorldUnloadEvent e) {
deInitAnchorsInWorld.accept(e.getWorld());
this.deInitAnchorsInWorld.accept(e.getWorld());
}
}

View File

@ -0,0 +1,153 @@
package com.craftaro.epicanchors.tasks;
import com.craftaro.core.nms.Nms;
import com.craftaro.core.nms.UnsupportedServerVersionException;
import com.craftaro.epicanchors.EpicAnchors;
import com.craftaro.epicanchors.api.Anchor;
import com.craftaro.epicanchors.api.AnchorManager;
import com.craftaro.epicanchors.utils.Utils;
import com.craftaro.epicanchors.utils.WorldUtils;
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;
import java.util.logging.Level;
/**
* More information about what types of game ticks there are and what does what: https://minecraft.fandom.com/wiki/Tick
*/
public class AnchorTask extends BukkitRunnable {
private static final int TASK_INTERVAL = 3;
private final EpicAnchors plugin;
private final AnchorManager anchorManager;
private boolean randomTicksFailed;
private boolean spawnerTicksFailed;
public AnchorTask(EpicAnchors plugin) {
this.plugin = plugin;
this.anchorManager = plugin.getAnchorManager();
}
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 randomTicksToDo = WorldUtils.getRandomTickSpeed(world) * TASK_INTERVAL;
Set<Chunk> alreadyTicked = new HashSet<>();
Anchor[] anchorsInWorld = this.anchorManager.getAnchors(world);
List<Anchor> toUpdateHolo = new ArrayList<>(anchorsInWorld.length);
List<Chunk> chunksWithPlayers = getChunksWithPlayers(world);
for (Anchor anchor : anchorsInWorld) {
Chunk chunk = anchor.getChunk();
if (alreadyTicked.add(chunk)) {
// Having a chunk loaded takes care of entities and weather (https://minecraft.fandom.com/wiki/Tick#Chunk_tick)
loadChunk(chunk);
executeTicksForInactiveSpawners(chunk);
if (!chunksWithPlayers.contains(chunk)) {
executeRandomTick(chunk, randomTicksToDo);
}
}
if (updateAnchorTimeLeftAndCheckIfHologramsNeedsUpdate(anchor)) {
toUpdateHolo.add(anchor);
}
}
this.anchorManager.updateHolograms(toUpdateHolo);
}
} catch (Exception ex) {
Utils.logException(this.plugin, ex);
}
}
private List<Chunk> getChunksWithPlayers(World world) {
List<Player> playersInWorld = world.getPlayers();
List<Chunk> chunksWithPlayers = new ArrayList<>(playersInWorld.size());
for (Player p : playersInWorld) {
chunksWithPlayers.add(p.getLocation().getChunk());
}
return chunksWithPlayers;
}
private void loadChunk(Chunk chunk) {
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...
return;
}
WorldUtils.loadAnchoredChunk(chunk, this.plugin);
}
private void executeTicksForInactiveSpawners(Chunk chunk) {
if (this.spawnerTicksFailed) {
return;
}
try {
Nms.getImplementations().getWorld().tickInactiveSpawners(chunk, TASK_INTERVAL);
} catch (UnsupportedServerVersionException | ReflectiveOperationException | IncompatibleClassChangeError ex) {
this.plugin.getLogger().log(Level.SEVERE, ex,
() -> "Failed to do spawner ticks on this server implementation(/version) - " +
"Skipping further spawner ticks.");
this.spawnerTicksFailed = true;
}
}
private void executeRandomTick(Chunk chunk, int randomTicks) {
if (this.randomTicksFailed) {
return;
}
try {
Nms.getImplementations().getWorld().randomTickChunk(chunk, randomTicks);
} catch (UnsupportedServerVersionException | ReflectiveOperationException | IncompatibleClassChangeError ex) {
this.plugin.getLogger().log(Level.SEVERE, ex,
() -> "Failed to do random ticks on this server implementation(/version) - " +
"Skipping further random ticks.");
this.randomTicksFailed = true;
}
}
private boolean updateAnchorTimeLeftAndCheckIfHologramsNeedsUpdate(Anchor anchor) {
// 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
if (!anchor.isInfinite()) {
int ticksLeft = anchor.removeTicksLeft(TASK_INTERVAL);
if (ticksLeft == 0) {
this.anchorManager.destroyAnchor(anchor);
} else {
return true;
}
} else {
return true;
}
return false;
}
}

View File

@ -1,9 +1,9 @@
package com.songoda.epicanchors.tasks;
package com.craftaro.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 com.craftaro.core.compatibility.CompatibleParticleHandler;
import com.craftaro.epicanchors.EpicAnchors;
import com.craftaro.epicanchors.api.Anchor;
import com.craftaro.epicanchors.files.Settings;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.Location;
@ -30,7 +30,7 @@ public class VisualizeTask extends BukkitRunnable {
}
public void startTask() {
runTaskTimer(plugin, TASK_INTERVAL, TASK_INTERVAL);
runTaskTimer(this.plugin, TASK_INTERVAL, TASK_INTERVAL);
}
@Override
@ -55,10 +55,10 @@ public class VisualizeTask extends BukkitRunnable {
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;
int cxi = (pLoc.getBlockX() >> 4) - this.radius;
int cxn = cxi + this.radius * 2;
int czi = (pLoc.getBlockZ() >> 4) - this.radius;
int czn = czi + this.radius * 2;
// loop through the chunks to find applicable ones
for (int cx = cxi; cx < cxn; ++cx) {
@ -66,7 +66,7 @@ public class VisualizeTask extends BukkitRunnable {
Chunk chunk = world.getChunkAt(cx, cz);
if (loadedChunks.contains(chunk)) {
chunksToVisualize.computeIfAbsent(chunk, k -> new HashSet<>())
chunksToVisualize.computeIfAbsent(chunk, key -> new HashSet<>())
.add(p);
}
}
@ -91,17 +91,17 @@ public class VisualizeTask extends BukkitRunnable {
startY = maxY - 1;
}
Block b = entry.getKey().getBlock(x, startY, z);
Block block = entry.getKey().getBlock(x, startY, z);
for (int i = 0; i < 12; ++i) {
if (b.getType().isSolid()) break;
if (block.getType().isSolid()) break;
b = b.getRelative(BlockFace.DOWN);
block = block.getRelative(BlockFace.DOWN);
}
if (!b.isEmpty() && !b.getRelative(BlockFace.UP).getType().isOccluding()) {
if (!block.isEmpty() && !block.getRelative(BlockFace.UP).getType().isOccluding()) {
CompatibleParticleHandler.spawnParticles(particleType,
b.getLocation().add(.5, 1.5, .5),
block.getLocation().add(.5, 1.5, .5),
0, 0, 0, 0, 1, p);
}
}

View File

@ -1,4 +1,4 @@
package com.songoda.epicanchors.utils;
package com.craftaro.epicanchors.utils;
import java.util.concurrent.atomic.AtomicReference;
@ -7,10 +7,10 @@ public class ThreadSync {
private final AtomicReference<Boolean> waiting = new AtomicReference<>(true);
public void waitForRelease() {
synchronized (syncObj) {
while (waiting.get()) {
synchronized (this.syncObj) {
while (this.waiting.get()) {
try {
syncObj.wait();
this.syncObj.wait();
} catch (Exception ignore) {
}
}
@ -18,13 +18,13 @@ public class ThreadSync {
}
public void release() {
synchronized (syncObj) {
waiting.set(false);
syncObj.notifyAll();
synchronized (this.syncObj) {
this.waiting.set(false);
this.syncObj.notifyAll();
}
}
public void reset() {
waiting.set(true);
this.waiting.set(true);
}
}

View File

@ -1,4 +1,4 @@
package com.songoda.epicanchors.utils;
package com.craftaro.epicanchors.utils;
import org.jetbrains.annotations.Nullable;

View File

@ -1,4 +1,4 @@
package com.songoda.epicanchors.utils;
package com.craftaro.epicanchors.utils;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;

View File

@ -1,4 +1,4 @@
package com.songoda.epicanchors.utils;
package com.craftaro.epicanchors.utils;
import org.bukkit.Chunk;
import org.bukkit.World;

View File

@ -1,17 +1,18 @@
name: ${project.name}
description: ${project.description}
name: ${project.parent.name}
description: ${project.parent.description}
version: ${project.version}
api-version: 1.13
main: com.songoda.epicanchors.EpicAnchors
main: com.craftaro.epicanchors.EpicAnchors
softdepend:
- Holograms
- HolographicDisplays
- Vault
- DecentHolograms
author: Songoda
author: Craftaro
authors: [ SpraxDev ]
website: ${project.url}
website: ${project.parent.url}
commands:
EpicAnchors:

143
pom.xml
View File

@ -4,154 +4,63 @@
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>
<version>2.2.7</version>
<groupId>com.craftaro</groupId>
<artifactId>EpicAnchors-Parent</artifactId>
<packaging>pom</packaging>
<version>3.1.1</version>
<!-- Run 'mvn versions:set -DgenerateBackupPoms=false -DnewVersion=X.Y.Z-DEV' to update version recursively -->
<modules>
<module>EpicAnchors-API</module>
<module>EpicAnchors-Plugin</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>
<url>https://craftaro.com/marketplace/product/31</url>
<properties>
<java.version>1.8</java.version>
<java.release>8</java.release>
<craftaro.coreVersion>3.0.1-SNAPSHOT</craftaro.coreVersion>
<maven.compiler.release>8</maven.compiler.release>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<sonar.projectKey>songoda_EpicAnchors</sonar.projectKey>
<sonar.organization>songoda</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
<sonar.moduleKey>${project.groupId}:${project.artifactId}</sonar.moduleKey>
</properties>
<issueManagement>
<url>https://support.songoda.com/servicedesk/customer/portal/3</url>
<system>Jira Service Desk</system>
<url>https://discord.gg/craftaro</url>
<system>Discord server</system>
</issueManagement>
<scm>
<url>https://github.com/songoda/EpicAnchors</url>
<connection>scm:git:git:github.com/songoda/EpicAnchors.git</connection>
<url>https://github.com/craftaro/EpicAnchors</url>
<connection>scm:git:git://github.com/craftaro/EpicAnchors.git</connection>
</scm>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</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.4.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>${project.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>
<repositories>
<repository>
<id>spigotmc-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
<id>craftaro-minecraft-plugins</id>
<url>https://repo.craftaro.com/repository/minecraft-plugins/</url>
</repository>
<repository>
<id>songoda-public</id>
<url>https://repo.songoda.com/repository/public/</url>
<id>SpigotMC</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
</repositories>
<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.6.20</version>
<scope>compile</scope>
</dependency>
<!-- Dev dependencies -->
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>24.0.1</version>
<scope>compile</scope>
<version>24.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,30 +0,0 @@
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)" +
");");
}
}
}

View File

@ -1,64 +0,0 @@
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));
}
}

View File

@ -1,122 +0,0 @@
package com.songoda.epicanchors.tasks;
import com.songoda.core.nms.NmsManager;
import com.songoda.epicanchors.Anchor;
import com.songoda.epicanchors.AnchorManager;
import com.songoda.epicanchors.EpicAnchors;
import com.songoda.epicanchors.utils.Utils;
import com.songoda.epicanchors.utils.WorldUtils;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.World;
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;
import java.util.logging.Level;
/**
* More information about what types of game ticks there are and what does what: https://minecraft.fandom.com/wiki/Tick
*/
public class AnchorTask extends BukkitRunnable {
private static final int TASK_INTERVAL = 3;
private final EpicAnchors plugin;
private final AnchorManager anchorManager;
private boolean randomTicksFailed;
private boolean spawnerTicksFailed;
public AnchorTask(EpicAnchors plugin) {
this.plugin = plugin;
this.anchorManager = plugin.getAnchorManager();
}
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 = WorldUtils.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...
WorldUtils.loadAnchoredChunk(chunk, this.plugin);
}
if (!randomTicksFailed) {
try {
NmsManager.getWorld().randomTickChunk(chunk, randomTicks);
} catch (ReflectiveOperationException ex) {
this.plugin.getLogger().log(Level.SEVERE, ex,
() -> "Failed to do random ticks on this server implementation(/version) - " +
"Skipping further random ticks.");
randomTicksFailed = true;
}
}
if (!spawnerTicksFailed) {
try {
NmsManager.getWorld().tickInactiveSpawners(chunk, TASK_INTERVAL);
} catch (ReflectiveOperationException ex) {
this.plugin.getLogger().log(Level.SEVERE, ex,
() -> "Failed to do spawner ticks on this server implementation(/version) - " +
"Skipping further spawner ticks.");
spawnerTicksFailed = true;
}
}
}
// TODO: Only update hologram if a player is nearby
// 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);
}
}
}

View File

@ -1,52 +0,0 @@
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;
}
}