diff --git a/.checkstyle.xml b/.checkstyle.xml new file mode 100644 index 00000000..3e01cc5c --- /dev/null +++ b/.checkstyle.xml @@ -0,0 +1,212 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..f311b058 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,289 @@ +# https://editorconfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_size = 4 +indent_style = space +trim_trailing_whitespace = true + +[*.java] +max_line_length = 120 +ij_java_imports_layout = java.**,|,javax.**,|,*,|,com.mojang.**,|,net.minecraft.**,|,net.fabricmc.**,|,dev.jpcode.**,|,$* + +[*.{json,xml,yml}] +indent_size = 2 + +[*.md] +max_line_length = 80 + +trim_trailing_whitespace = false + +# Export: +# +[*.java] +ij_continuation_indent_size = 4 +ij_visual_guides = 80,100,120 +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 = true +ij_java_binary_operation_wrap = on_every_item +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_add_space = false +ij_java_block_comment_at_first_column = true +ij_java_builder_methods = none +ij_java_call_parameters_new_line_after_left_paren = true +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 = 5 +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 = false +ij_java_doc_add_blank_line_after_return = false +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 = false +ij_java_doc_enable_formatting = true +ij_java_doc_enable_leading_asterisks = true +ij_java_doc_indent_on_continuation = false +ij_java_doc_keep_empty_lines = true +ij_java_doc_keep_empty_parameter_tag = true +ij_java_doc_keep_empty_return_tag = true +ij_java_doc_keep_empty_throws_tag = true +ij_java_doc_keep_invalid_tags = true +ij_java_doc_param_description_on_new_line = false +ij_java_doc_preserve_line_breaks = false +ij_java_doc_use_throws_not_exception_tag = true +ij_java_else_on_new_line = false +ij_java_enum_constants_wrap = 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 = if_multiline +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 = 2 +ij_java_keep_blank_lines_between_package_declaration_and_header = 2 +ij_java_keep_blank_lines_in_code = 2 +ij_java_keep_blank_lines_in_declarations = 2 +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 = next_line_if_wrapped +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 = 3 +ij_java_new_line_after_lparen_in_record_header = false +ij_java_packages_to_use_import_on_demand = java.awt.*,javax.swing.* +ij_java_parameter_annotation_wrap = off +ij_java_parentheses_expression_new_line_after_left_paren = false +ij_java_parentheses_expression_right_paren_on_new_line = false +ij_java_place_assignment_sign_on_next_line = false +ij_java_prefer_longer_names = true +ij_java_prefer_parameters_wrap = false +ij_java_record_components_wrap = normal +ij_java_repeat_synchronized = true +ij_java_replace_instanceof_and_cast = false +ij_java_replace_null_check = true +ij_java_replace_sum_lambda_with_method_ref = true +ij_java_resource_list_new_line_after_left_paren = false +ij_java_resource_list_right_paren_on_new_line = false +ij_java_resource_list_wrap = 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 = false +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 = false +ij_java_space_within_empty_method_call_parentheses = false +ij_java_space_within_empty_method_parentheses = false +ij_java_spaces_around_additive_operators = true +ij_java_spaces_around_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 = false +ij_java_spaces_within_brackets = false +ij_java_spaces_within_cast_parentheses = false +ij_java_spaces_within_catch_parentheses = false +ij_java_spaces_within_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 + +[*.nbtt] +max_line_length = 150 +ij_continuation_indent_size = 4 +ij_visual_guides = none +ij_nbtt_keep_indents_on_empty_lines = false +ij_nbtt_space_after_colon = true +ij_nbtt_space_after_comma = true +ij_nbtt_space_before_colon = true +ij_nbtt_space_before_comma = false +ij_nbtt_spaces_within_brackets = false +ij_nbtt_spaces_within_parentheses = false + +[*.properties] +ij_visual_guides = none +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_visual_guides = none +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 diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 74a8c6da..7859749c 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -1,11 +1,11 @@ # This workflow will build a Java project with Gradle # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle -name: Build with Gradle +name: Build and Test with Gradle on: push: - branches: [ master ] + branches: [ "1.17.x", "1.18.x", "1.19.x" ] paths: - '**/src/**' - '**/build.gradle' @@ -15,7 +15,7 @@ on: - LICENCE pull_request: - branches: [ master ] + branches: [ "1.17.x", "1.18.x", "1.19.x" ] paths: - '**/src/**' - '**/build.gradle' @@ -26,7 +26,7 @@ on: jobs: build: - name: Build + name: Build and Test runs-on: ubuntu-latest @@ -37,10 +37,10 @@ jobs: - name: 🛂 Validate Gradle wrapper uses: gradle/wrapper-validation-action@v1 - - name: 🏗 Set up JDK 16 + - name: 🏗 Set up JDK 17 uses: actions/setup-java@v2 with: - java-version: 16 + java-version: 17 distribution: adopt - name: 📷 Begin Gradle cache @@ -52,8 +52,11 @@ jobs: key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} restore-keys: | ${{ runner.os }}-gradle- - - name: 🔨 Build artifacts - run: gradle -b build-github-action.gradle -c settings-github-action.gradle clean build + + - name: 🔨 Build artifacts and Run Tests + env: + IS_PIPELINE: true + run: gradle clean build - name: 📦 Upload artifacts uses: actions/upload-artifact@v2 diff --git a/.gitignore b/.gitignore index 88f1fdfc..1c5aa5d5 100644 --- a/.gitignore +++ b/.gitignore @@ -30,7 +30,24 @@ bin/ # fabric +run_orig/ run/ # env -.env \ No newline at end of file +.env + +*.orig +changelog*.md +cfmd.py +*cf.md +showcase.md +temp.md + +remappedSrc + +/ec-core/logs +/logs + +*/logs/* +*.log.gz +*.log diff --git a/README.md b/README.md index 875780b8..72c57ea7 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ Configurable, permissions-backed utility commands for Fabric servers. [![Release](https://img.shields.io/github/v/release/John-Paul-R/essential-commands?style=for-the-badge&include_prereleases&sort=semver)][releases] [![Available For](https://img.shields.io/badge/dynamic/json?label=Available%20For&style=for-the-badge&color=34aa2f&query=$[:]&url=https%3A%2F%2Fwww.jpcode.dev%2Fessentialcommands%2Fsupported_mc_versions.json)][modrinth:files] -[![Modrinth Downloads](https://img.shields.io/badge/dynamic/json?color=5da545&label=modrinth&query=downloads&url=https://api.modrinth.com/api/v1/mod/essential-commands&style=for-the-badge&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMSAxMSIgd2lkdGg9IjE0LjY2NyIgaGVpZ2h0PSIxNC42NjciICB4bWxuczp2PSJodHRwczovL3ZlY3RhLmlvL25hbm8iPjxkZWZzPjxjbGlwUGF0aCBpZD0iQSI+PHBhdGggZD0iTTAgMGgxMXYxMUgweiIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNBKSI+PHBhdGggZD0iTTEuMzA5IDcuODU3YTQuNjQgNC42NCAwIDAgMS0uNDYxLTEuMDYzSDBDLjU5MSA5LjIwNiAyLjc5NiAxMSA1LjQyMiAxMWMxLjk4MSAwIDMuNzIyLTEuMDIgNC43MTEtMi41NTZoMGwtLjc1LS4zNDVjLS44NTQgMS4yNjEtMi4zMSAyLjA5Mi0zLjk2MSAyLjA5MmE0Ljc4IDQuNzggMCAwIDEtMy4wMDUtMS4wNTVsMS44MDktMS40NzQuOTg0Ljg0NyAxLjkwNS0xLjAwM0w4LjE3NCA1LjgybC0uMzg0LS43ODYtMS4xMTYuNjM1LS41MTYuNjk0LS42MjYuMjM2LS44NzMtLjM4N2gwbC0uMjEzLS45MS4zNTUtLjU2Ljc4Ny0uMzcuODQ1LS45NTktLjcwMi0uNTEtMS44NzQuNzEzLTEuMzYyIDEuNjUxLjY0NSAxLjA5OC0xLjgzMSAxLjQ5MnptOS42MTQtMS40NEE1LjQ0IDUuNDQgMCAwIDAgMTEgNS41QzExIDIuNDY0IDguNTAxIDAgNS40MjIgMCAyLjc5NiAwIC41OTEgMS43OTQgMCA0LjIwNmguODQ4QzEuNDE5IDIuMjQ1IDMuMjUyLjgwOSA1LjQyMi44MDljMi42MjYgMCA0Ljc1OCAyLjEwMiA0Ljc1OCA0LjY5MSAwIC4xOS0uMDEyLjM3Ni0uMDM0LjU2bC43NzcuMzU3aDB6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGZpbGw9IiM1ZGE0MjYiLz48L2c+PC9zdmc+)][modrinth:files] -[![Curseforge Downloads](https://img.shields.io/badge/dynamic/json?color=f16436&style=for-the-badge&label=CurseForge&query=downloadCount&url=https://addons-ecs.forgesvc.net/api/v2/addon/475964&logo=CurseForge)][curseforge:files] +[![Modrinth Downloads](https://img.shields.io/modrinth/dt/essential-commands?color=00AF5C&label=modrinth&style=for-the-badge&logo=modrinth)][modrinth:files] +[![Curseforge Downloads](https://img.shields.io/badge/dynamic/json?color=f16436&style=for-the-badge&label=CurseForge&query=downloadCount&url=https://www.fibermc.com/api/v1.0/ForeignMods/475964&logo=CurseForge)][curseforge:files] [![GitHub Downloads (all releases)](https://img.shields.io/github/downloads/John-Paul-R/Essential-Commands/total?style=for-the-badge&label=GitHub&prefix=downloads%20&color=4078c0&logo=github)][releases] @@ -52,12 +52,14 @@ See the [full List of Commands & Permissions](https://github.com/John-Paul-R/Ess - /home set \ - /home tp \ - /home delete \ + - /home list ### Warps - /warp set \ - /warp tp \ - /warp delete \ + - /warp list ### Back @@ -74,12 +76,25 @@ See the [full List of Commands & Permissions](https://github.com/John-Paul-R/Ess - /randomteleport - /rtp +### Workbench + + - /workbench + - /anvil + - /enderchest + - /stonecutter + - /grindstone + - /wastebin + ### Kitchen sink + - /afk - /fly - /fly \ - - /workbench - - /enderchest + - /invuln + - /invuln \ + - /top + - /day + - /gametime ### Config diff --git a/build-github-action.gradle b/build-github-action.gradle deleted file mode 100644 index 879832b7..00000000 --- a/build-github-action.gradle +++ /dev/null @@ -1,124 +0,0 @@ -plugins { - id 'groovy' - id 'java-gradle-plugin' - id 'fabric-loom' version '0.8-SNAPSHOT' -} - -sourceCompatibility = JavaVersion.VERSION_16 -targetCompatibility = JavaVersion.VERSION_16 - -archivesBaseName = project.archives_base_name -version = project.mod_version -group = project.maven_group - - -allprojects { - apply plugin: 'fabric-loom' - apply plugin: 'idea' - - group = project.maven_group - String full_version = "${project.mod_version}-mc${project.minecraft_version}+${getTimestamp()}" - version = full_version - archivesBaseName = "${project.mod_id}"//-mc${project.minecraft_version} - - sourceCompatibility = targetCompatibility = JavaVersion.VERSION_16 - - // Declare dependencies - dependencies { - // Fabric - minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - - // Mods - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" -// modImplementation "com.terraformersmc:modmenu:${project.mod_menu_version}" - modImplementation "me.lucko:fabric-permissions-api:${project.permissions_api_version}" - - // Code Quality - compileOnly "org.jetbrains:annotations:${project.jetbrains_annotations_version}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${project.junit_jupiter_version}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${project.junit_jupiter_version}" - - // JIJ Dependencies - modApi "me.lucko:fabric-permissions-api:${project.permissions_api_version}" - include "me.lucko:fabric-permissions-api:${project.permissions_api_version}" - modApi "eu.pb4:placeholder-api:${project.placeholder_api_version}" - include "eu.pb4:placeholder-api:${project.placeholder_api_version}" - modImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.12.2' - include 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.12.2' - modImplementation "io.github.ladysnake:PlayerAbilityLib:${pal_version}" - include "io.github.ladysnake:PlayerAbilityLib:${pal_version}" - - // Subprojects - subprojects.each { - implementation project(":${it.name}") - include project("${it.name}:") // nest within distribution - } - } - - // Perform tests using the JUnit test suite - test { - useJUnitPlatform() - } - - // Produce a sources distribution - java { - withSourcesJar() - } - - // Add the licence to all distributions - tasks.withType(Jar).configureEach { - it.from rootProject.file('LICENCE') - } - - // Process any resources - processResources { - inputs.property 'id', project.mod_id - inputs.property 'name', project.mod_name - inputs.property 'version', project.version - - // fabric.mod.json - filesMatching('fabric.mod.json') { - expand(['id': project.mod_id, 'name': project.mod_name, 'version': project.version]) - } - } - - // Add any additional repositories - repositories { - mavenCentral() - maven { name 'Fabric'; url 'https://maven.fabricmc.net/' } -// maven { name 'TerraformersMC'; url 'https://maven.terraformersmc.com/' } - // Add repositories to retrieve artifacts from in here. - // You should only use this when depending on other mods because - // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. - // See https://docs.gradle.org/current/userguide/declaring_repositories.html - // for more information about repositories. - maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } - maven { url 'https://maven.nucleoid.xyz' } - maven { - name = 'Ladysnake Mods' - url = 'https://ladysnake.jfrog.io/artifactory/mods' - content { - includeGroup 'io.github.ladysnake' - includeGroupByRegex 'io\\.github\\.onyxstudios.*' - } - } - } - -} - -tasks.withType(JavaCompile).configureEach { - // ensure that the encoding is set to UTF-8, no matter what the system default is - // this fixes some edge cases with special characters not displaying correctly - // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html - // If Javadoc is generated, this must be specified in that task too. - it.options.encoding = "UTF-8" - - // Minecraft 1.17 (21w19a) upwards uses Java 16. - it.options.release = 16 -} - -def getTimestamp() { - return new Date().format('yyyyMMddHHmmss') -} \ No newline at end of file diff --git a/build.gradle b/build.gradle index ebbeacd6..0b22882b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,289 +1,318 @@ plugins { - id 'groovy' - id 'java-gradle-plugin' - id 'fabric-loom' version '0.8-SNAPSHOT' - id 'maven-publish' - id "com.modrinth.minotaur" version "1.2.1" - id 'com.matthewprenger.cursegradle' version "1.4.0" - id "com.github.breadmoirai.github-release" version "2.2.12" + id 'groovy' + id 'java-gradle-plugin' + id 'fabric-loom' version '0.10-SNAPSHOT' + id 'maven-publish' + id "com.modrinth.minotaur" version "2.+" + id 'com.matthewprenger.cursegradle' version "1.4.0" + id "com.github.breadmoirai.github-release" version "2.3.7" } -allprojects { - apply plugin: 'fabric-loom' - apply plugin: 'idea' - - group = project.maven_group - String full_version = "${project.mod_version}-mc${project.minecraft_version}" - version = full_version - archivesBaseName = "${project.mod_id}" - - sourceCompatibility = targetCompatibility = JavaVersion.VERSION_16 - - // Declare dependencies - dependencies { - // Fabric - minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - - // Mods - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" -// modImplementation "com.terraformersmc:modmenu:${project.mod_menu_version}" - modImplementation "me.lucko:fabric-permissions-api:${project.permissions_api_version}" - - // Code Quality - compileOnly "org.jetbrains:annotations:${project.jetbrains_annotations_version}" - testImplementation "org.junit.jupiter:junit-jupiter-api:${project.junit_jupiter_version}" - testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${project.junit_jupiter_version}" - - // JIJ Dependencies - modApi "me.lucko:fabric-permissions-api:${project.permissions_api_version}" - include "me.lucko:fabric-permissions-api:${project.permissions_api_version}" - modApi "eu.pb4:placeholder-api:${project.placeholder_api_version}" - include "eu.pb4:placeholder-api:${project.placeholder_api_version}" - modImplementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.12.2' - include 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.12.2' - modImplementation "io.github.ladysnake:PlayerAbilityLib:${pal_version}" - include "io.github.ladysnake:PlayerAbilityLib:${pal_version}" - - // Subprojects - subprojects.each { - implementation project(":${it.name}") - include project("${it.name}:") // nest within distribution - } - } - - // Perform tests using the JUnit test suite - test { - useJUnitPlatform() - } - - // Produce a sources distribution - java { - withSourcesJar() - } - - // Add the licence to all distributions - tasks.withType(Jar).configureEach { - it.from rootProject.file('LICENCE') - } - - // Process any resources - processResources { - inputs.property 'id', project.mod_id - inputs.property 'name', project.mod_name - inputs.property 'version', project.version - - // fabric.mod.json - filesMatching('fabric.mod.json') { - expand(['id': project.mod_id, 'name': project.mod_name, 'version': project.version]) - } - } - - // Add any additional repositories - repositories { - mavenCentral() - maven { name 'Fabric'; url 'https://maven.fabricmc.net/' } -// maven { name 'TerraformersMC'; url 'https://maven.terraformersmc.com/' } - // Add repositories to retrieve artifacts from in here. - // You should only use this when depending on other mods because - // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. - // See https://docs.gradle.org/current/userguide/declaring_repositories.html - // for more information about repositories. - maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } - maven { url 'https://maven.nucleoid.xyz' } - // Used by FabricPlaceholderAPI - - maven { - name = 'Ladysnake Mods' - url = 'https://ladysnake.jfrog.io/artifactory/mods' - content { - includeGroup 'io.github.ladysnake' - includeGroupByRegex 'io\\.github\\.onyxstudios.*' - } - } - } - +build { + dependsOn ':ec-core:build' } +ext.env = loadenv() -tasks.withType(JavaCompile).configureEach { - // ensure that the encoding is set to UTF-8, no matter what the system default is - // this fixes some edge cases with special characters not displaying correctly - // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html - // If Javadoc is generated, this must be specified in that task too. - it.options.encoding = "UTF-8" - - // Minecraft 1.17 (21w19a) upwards uses Java 16. - it.options.release = 16 +String getenv(String key) { + return env.getOrDefault(key, "NOT FOUND") } +allprojects { + apply plugin: 'fabric-loom' + apply plugin: 'idea' + + + group = project.maven_group + String full_version = Boolean.parseBoolean(getenv("IS_PIPELINE")) + ? "${project.mod_version}-mc${project.minecraft_version}+${getTimestamp()}" + : "${project.mod_version}-mc${project.minecraft_version}" + + version = full_version + archivesBaseName = "${project.mod_id}" + + sourceCompatibility = targetCompatibility = JavaVersion.VERSION_17 + + // Declare dependencies + dependencies { + // Fabric + minecraft "com.mojang:minecraft:${project.minecraft_version}" + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + + // Mods + modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" +// modImplementation "com.terraformersmc:modmenu:${project.mod_menu_version}" + modImplementation "me.lucko:fabric-permissions-api:${project.permissions_api_version}" + + // Code Quality + compileOnly "org.jetbrains:annotations:${project.jetbrains_annotations_version}" + testImplementation "org.junit.jupiter:junit-jupiter-api:${project.junit_jupiter_version}" + testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${project.junit_jupiter_version}" + + // JIJ Dependencies + modApi "me.lucko:fabric-permissions-api:${project.permissions_api_version}" + include "me.lucko:fabric-permissions-api:${project.permissions_api_version}" + modApi "eu.pb4:placeholder-api:${project.placeholder_api_version}" + include "eu.pb4:placeholder-api:${project.placeholder_api_version}" + modImplementation 'org.yaml:snakeyaml:1.33' + include 'org.yaml:snakeyaml:1.33' + modImplementation "io.github.ladysnake:PlayerAbilityLib:${pal_version}" + include "io.github.ladysnake:PlayerAbilityLib:${pal_version}" + + // Subprojects + subprojects.each { + implementation project(path: ":${it.name}", configuration: "namedElements") + include project("${it.name}:") // nest within distribution + } + } + + // Perform tests using the JUnit test suite + test { + useJUnitPlatform() + } + + // Produce a sources distribution + java { + withSourcesJar() + } + + // Add the licence to all distributions + tasks.withType(Jar).configureEach { + it.from rootProject.file('LICENCE') + } + + // Process any resources + processResources { + inputs.property 'id', project.mod_id + inputs.property 'name', project.mod_name + inputs.property 'version', project.version + + // fabric.mod.json + filesMatching('fabric.mod.json') { + expand(['id': project.mod_id, 'name': project.mod_name, 'version': project.version]) + } + } + + // Add any additional repositories + repositories { + mavenCentral() + maven { name 'Fabric'; url 'https://maven.fabricmc.net/' } +// maven { name 'TerraformersMC'; url 'https://maven.terraformersmc.com/' } + // Add repositories to retrieve artifacts from in here. + // You should only use this when depending on other mods because + // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. + // See https://docs.gradle.org/current/userguide/declaring_repositories.html + // for more information about repositories. + maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } + maven { url 'https://maven.nucleoid.xyz' } + // Used by FabricPlaceholderAPI + + maven { + name = 'Ladysnake Mods' + url = 'https://ladysnake.jfrog.io/artifactory/mods' + content { + includeGroup 'io.github.ladysnake' + includeGroupByRegex 'io\\.github\\.onyxstudios.*' + } + } + } +} +tasks.withType(JavaCompile).configureEach { + // ensure that the encoding is set to UTF-8, no matter what the system default is + // this fixes some edge cases with special characters not displaying correctly + // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html + // If Javadoc is generated, this must be specified in that task too. + it.options.encoding = "UTF-8" + + // Minecraft 1.17 (21w19a) upwards uses Java 16. + it.options.release.set(17) +} //jar { -// from("LICENSE") { -// rename { "${it}_${project.archivesBaseName}"} -// } +// from("LICENSE") { +// rename { "${it}_${project.archivesBaseName}"} +// } //} // Define how packages are published publishing { - // Declare all publications - publications { - mavenJava(MavenPublication) { - artifactId = project.mod_id - groupId = project.maven_group - version = project.version - // Main - artifact(remapJar) { builtBy remapJar } - // Sources - artifact(sourcesJar) { - builtBy remapSourcesJar - - } - } - } - Map env = getenv() - // Add repositories to publish to - repositories { - // GitHub Packages (https://pkg.github.com) - mavenLocal { - - } - maven { - name 'GitHub' - url "https://maven.pkg.github.com/${project.github_repo}" - credentials { - username env.get('GITHUB_ACTOR') - password env.get('GITHUB_TOKEN') - } - } - } + // Declare all publications + publications { + mavenJava(MavenPublication) { + artifactId = project.mod_id + groupId = project.maven_group + version = project.version + // Main + artifact(remapJar) { builtBy remapJar } + // Sources + artifact(sourcesJar) { + builtBy remapSourcesJar + } + } + } + // Add repositories to publish to + repositories { + // GitHub Packages (https://pkg.github.com) + mavenLocal { + + } + maven { + name 'GitHub' + url "https://maven.pkg.github.com/${project.github_repo}" + credentials { + username = getenv('GITHUB_ACTOR') + password = getenv('GITHUB_TOKEN') + } + } + } } - -import com.github.breadmoirai.githubreleaseplugin.GithubReleaseExtension +import com.github.breadmoirai.githubreleaseplugin.GithubReleaseTask import com.modrinth.minotaur.TaskModrinthUpload -task publishModrinth (type: TaskModrinthUpload){ // Make sure it runs after build! - description 'Uploads all Modrinth projects' - group 'upload' - - Map env = getenv() - - onlyIf { - // Only attempt to run this task if the MODRINTH variable is set in .env, otherwise SKIP it - env.containsKey("MODRINTH") - } - - token = env.get("MODRINTH") // An environment property called MODRINTH that is your token, set via Gradle CLI, GitHub Actions, Idea Run Configuration, or other - projectId = modrinth_project_id - versionNumber = project.version // Will fail if Modrinth has this version already - versionType = project.version.contains('alpha') ? 'alpha' : project.version.contains('beta') ? 'beta' : 'release' - - // On fabric, use 'remapJar' instead of 'jar' - - uploadFile = jar.outputs.getFiles().asPath // This is the java jar task. If it can't find the jar, try 'jar.outputs.getFiles().asPath' in place of 'jar' - project.mr_game_versions.split(',').each { addGameVersion it } // Call this multiple times to add multiple game versions. There are tools that can help you generate the list of versions - changelog = getChangelog() - addLoader('fabric') +import com.modrinth.minotaur.request.VersionType + +modrinth { + token = getenv("MODRINTH") // An environment property called MODRINTH that is your token, set via Gradle CLI, GitHub Actions, Idea Run Configuration, or other + projectId = project.modrinth_project_id + versionNumber = project.version // Will fail if Modrinth has this version already + versionType = project.version.contains('alpha') ? VersionType.ALPHA.toString() + : project.version.contains('beta') ? VersionType.BETA.toString() + : VersionType.RELEASE.toString() + + // On fabric, use 'remapJar' instead of 'jar' + + uploadFile = remapJar + // This is the java jar task. If it can't find the jar, try 'jar.outputs.getFiles().asPath' in place of 'jar' + gameVersions = List.of(project.mr_game_versions.split(',')) + changelog = readChangelogFromFile() + loaders = ['fabric'] + +// dependencies = { +// var requiredMods = (project.mr_relations_required).split(',').collect { new ModDependency(it, DependencyType.REQUIRED)} +// var optionalMods = (project.mr_relations_optional).split(',').collect { new ModDependency(it, DependencyType.OPTIONAL)} +// var incompatibleMods = (project.mr_relations_incompatible).split(',').collect { new ModDependency(it, DependencyType.INCOMPATIBLE)} +// +// var outList = new ArrayList(requiredMods.size() + optionalMods.size() + incompatibleMods.size()) +// outList.addAll(requiredMods) +// outList.addAll(optionalMods) +// outList.addAll(incompatibleMods) +// return outList +// }() +} - if (project.mr_relations_required) project.mr_relations_required.split(',').each { addDependency it, 'required' } - if (project.mr_relations_optional) project.mr_relations_optional.split(',').each { addDependency it, 'optional' } - if (project.mr_relations_incompatible) project.mr_relations_incompatible.split(',').each { addDependency it, 'incompatible' } +task publishModrinth(type: TaskModrinthUpload) { // Make sure it runs after build! + description 'Uploads all Modrinth projects' + group 'upload' + onlyIf { + // Only attempt to run this task if the MODRINTH variable is set in .env, otherwise SKIP it + env.containsKey("MODRINTH") + } } + //curseforge475964 // Begin the cursegradle task. Replacing ID with the id you set on the cursegradle config. curseforge { - Map env = getenv() - apiKey = env.get("CURSEFORGE") as String//changelog = new File('./changelog.md').getText('UTF-8') - - // Declare all projects - //noinspection GroovyAssignabilityCheck - project { - // Set the project id - id = project.cf_project_id - // Set the release type - releaseType = project.version.contains('alpha') ? 'alpha' : project.version.contains('beta') ? 'beta' : 'release' - // Set the release notes - changelog = "For a list of changes, please refer to https://github.com/${project.github_repo}/releases/tag/${project.version}" - // Add all supported game versions - project.cf_game_versions.split(',').each { addGameVersion it } - // Add the main artifact - mainArtifact(remapJar) { displayName = "${project.version}" } - - // Add any additional artifacts - addArtifact sourcesJar - addArtifact jar - subprojects.each { -// addArtifact it.remapJar -// addArtifact it.sourcesJar - addArtifact it.jar - } - // Add any dependencies - relations { - if (project.cf_relations_required) project.cf_relations_required.split(',').each { requiredDependency it } - if (project.cf_relations_optional) project.cf_relations_optional.split(',').each { optionalDependency it } - if (project.cf_relations_embedded) project.cf_relations_embedded.split(',').each { embeddedLibrary it } - if (project.cf_relations_tools) project.cf_relations_tools.split(',').each { tool it } - if (project.cf_relations_incompatible) project.cf_relations_incompatible.split(',').each { incompatible it } - } - } - - // Configure other options - options { - forgeGradleIntegration = false - } + apiKey = getenv("CURSEFORGE") + + // Declare all projects + //noinspection GroovyAssignabilityCheck + project { + // Set the project id + id = project.cf_project_id + // Set the release type + releaseType = project.version.contains('alpha') ? 'alpha' + : project.version.contains('beta') ? 'beta' + : 'release' + // Set the release notes + changelog = "For a list of changes, please refer to https://github.com/${project.github_repo}/releases/tag/${project.version}" + // Add all supported game versions + project.cf_game_versions.split(',').each { addGameVersion it } + // Add the main artifact + mainArtifact(remapJar) { displayName = "${project.version}" } + + // Add any additional artifacts + subprojects.each { + addArtifact it.remapJar +// addArtifact it.sourcesJar +// addArtifact it.jar + } + // Add any dependencies + relations { + if (project.cf_relations_required) project.cf_relations_required.split(',').each { requiredDependency it } + if (project.cf_relations_optional) project.cf_relations_optional.split(',').each { optionalDependency it } + if (project.cf_relations_embedded) project.cf_relations_embedded.split(',').each { embeddedLibrary it } + if (project.cf_relations_tools) project.cf_relations_tools.split(',').each { tool it } + if (project.cf_relations_incompatible) project.cf_relations_incompatible.split(',').each { incompatible it } + } + } + + // Configure other options + options { + forgeGradleIntegration = false + } } -tasks.getByName("githubRelease").each { task -> configure(task) { - group = "upload" -}} +task publishGithubRelease (type: GithubReleaseTask){ + description 'Creates a GitHub Release for the project' + group 'upload' + + onlyIf { + env.containsKey("GITHUB") + } +} githubRelease { - Map env = getenv() - group = "upload" - token env.get("GITHUB") as String // This is your personal access token with Repo permissions - // You get this from your user settings > developer settings > Personal Access Tokens - owner project.gh_owner // default is the last part of your group. Eg group: "com.github.breadmoirai" => owner: "breadmoirai" - repo project.gh_repo // by default this is set to your project name - tagName project.version // by default this is set to "v${project.version}" - targetCommitish "master" // by default this is set to "master" - releaseName project.version // Release title, by default this is the same as the tagName - body getChangelog() // by default this is empty - draft false // by default this is false - prerelease false // by default this is false - releaseAssets jar.destinationDirectory.getAsFileTree().matching { - include "**/*${project.version}.jar" -// include "**/*${project.mod_version}-sources.jar" - }// this points to which files you want to upload as assets with your release - //jar.outputs.getFiles().asPath// - overwrite false // by default false; if set to true, will delete an existing release with the same tag and name - dryRun false // by default false; you can use this to see what actions would be taken without making a release - apiEndpoint "https://api.github.com" // should only change for github enterprise users - client // This is the okhttp client used for http requests + token = getenv("GITHUB") // This is your personal access token with Repo permissions + // You get this from your user settings > developer settings > Personal Access Tokens + owner = project.gh_owner // default is the last part of your group. Eg group: "com.github.breadmoirai" => owner: "breadmoirai" + repo = project.gh_repo // by default this is set to your project name + tagName = project.version as String // by default this is set to "v${project.version}" + targetCommitish = "1.17.x" // by default this is set to "master" + releaseName = project.version as String // Release title, by default this is the same as the tagName + body = readChangelogFromFile() // by default this is empty + draft = false // by default this is false + prerelease = false // by default this is false + releaseAssets libsDirectory + .getAsFileTree() + .matching((PatternFilterable pattern) -> pattern.include("**/*${project.version}.jar")) + //jar.outputs.getFiles().asPath// + overwrite = false // by default false; if set to true, will delete an existing release with the same tag and name + dryRun = false // by default false; you can use this to see what actions would be taken without making a release + apiEndpoint = "https://api.github.com" // should only change for github enterprise users + client // This is the okhttp client used for http requests + allowUploadToExisting = false } generatePomFileForMavenJavaPublication {} -def static getenv(path = ".env") { - def env = [:] - - def file = new File(path) - if (file.exists()) { - file.eachLine { line -> - def (name, value) = line.tokenize("=") - env[name.trim()] = value.trim() - } - } - return env +def static loadenv(String path = ".env") { + def env = [:] + + def file = new File(path) + if (file.exists()) { + file.eachLine { line -> + def (name, value) = line.tokenize("=") + env[name.trim()] = value.trim() + } + } + for (el in System.getenv()) { + env[el.key] = el.value; + } + return env } -def getChangelog() { - try { - return new File('./changelog.md').getText('UTF-8') +String readChangelogFromFile() { + String changelogFilePath = './changelog.md' + var file = new File(changelogFilePath) + if (!file.exists()) { + logger.warn("'%s' not found.", changelogFilePath) + return "changelog file not found" + } + return file.getText('UTF-8') +} - } catch (FileNotFoundException e) { - logger.warn('./changelog.md not found.') - } - return "null"; +static def getTimestamp() { + return new Date().format('yyyyMMddHHmmss') } diff --git a/ec-core/gradle.properties b/ec-core/gradle.properties index 370fb464..223597b8 100644 --- a/ec-core/gradle.properties +++ b/ec-core/gradle.properties @@ -1,6 +1,6 @@ # Mod mod_name = Essential Commands Core mod_id = ec-core -mod_version = 1.0.0 +mod_version = 1.3.0 maven_group = dev.jpcode diff --git a/ec-core/src/main/java/dev/jpcode/eccore/ECCore.java b/ec-core/src/main/java/dev/jpcode/eccore/ECCore.java index f2449d6e..1ba9462e 100644 --- a/ec-core/src/main/java/dev/jpcode/eccore/ECCore.java +++ b/ec-core/src/main/java/dev/jpcode/eccore/ECCore.java @@ -3,7 +3,9 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -public class ECCore { +public final class ECCore { + private ECCore() {} + public static final Logger LOGGER = LogManager.getLogger("ec-core"); } diff --git a/ec-core/src/main/java/dev/jpcode/eccore/config/Config.java b/ec-core/src/main/java/dev/jpcode/eccore/config/Config.java index 51bb55ef..42417e90 100644 --- a/ec-core/src/main/java/dev/jpcode/eccore/config/Config.java +++ b/ec-core/src/main/java/dev/jpcode/eccore/config/Config.java @@ -1,28 +1,29 @@ package dev.jpcode.eccore.config; -import net.minecraft.text.LiteralText; -import net.minecraft.text.MutableText; -import net.minecraft.text.Style; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; +import java.io.*; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.List; +import java.util.function.Consumer; import java.util.stream.Collectors; -public abstract class Config { +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import net.minecraft.text.MutableText; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +import dev.jpcode.eccore.util.TextUtil; + +public abstract class Config> { static final Logger LOGGER = LogManager.getLogger("ec-core-config"); protected SortedProperties props; @@ -30,6 +31,13 @@ public abstract class Config { private final String displayName; private final String documentationLink; + private @Nullable String existingPropsStr; + private String getNonCommentsLines(String propsContent) { + return propsContent.lines() + .skip(displayName.lines().count() + 2) + .collect(Collectors.joining("\n")); + } + public Config(Path savePath, String displayName, String documentationLink) { this.configPath = savePath; this.displayName = displayName; @@ -42,15 +50,22 @@ public void loadOrCreateProperties() { File inFile = configPath.toFile(); try { + inFile.getParentFile().mkdirs(); boolean fileAlreadyExisted = !inFile.createNewFile(); if (fileAlreadyExisted) { + var stringWriter = new StringWriter(); + new FileReader(inFile).transferTo(stringWriter); + existingPropsStr = stringWriter.toString(); + props.load(new FileReader(inFile)); } } catch (IOException e) { LOGGER.warn("Failed to load preferences."); + LOGGER.error(e.getMessage()); } initProperties(); storeProperties(); + configLoadHandlers.forEach(consumer -> consumer.accept((T) this)); } private void initProperties() { @@ -69,18 +84,26 @@ private void initProperties() { public void storeProperties() { try { - File outFile = configPath.toFile(); - FileWriter writer = new FileWriter(outFile); - - props.storeSorted(writer, new StringBuilder(80) - .append(displayName) - .append("\n") - .append("Config Documentation: ") - .append(documentationLink) - .toString() - ); + var propsComments = displayName + "\n" + "Config Documentation: " + documentationLink; + + var stringWriter = new StringWriter(); + props.storeSorted(stringWriter, propsComments); + stringWriter.close(); + + var strinifiedProps = stringWriter.toString(); + var stringifiedPropsNoComments = getNonCommentsLines(strinifiedProps); + if (existingPropsStr == null + || !stringifiedPropsNoComments.equals(getNonCommentsLines(existingPropsStr))) + { + File outFile = configPath.toFile(); + FileWriter writer = new FileWriter(outFile); + props.storeSorted(writer, propsComments); + existingPropsStr = strinifiedProps; + } + } catch (IOException e) { LOGGER.warn("Failed to store preferences to disk."); + LOGGER.error(e.getMessage()); } } @@ -89,12 +112,12 @@ public void storeProperties() { static final Style ACCENT_STYLE = Style.EMPTY.withFormatting(Formatting.GREEN); public @NotNull Text stateAsText() { - LiteralText result = new LiteralText(""); + var result = TextUtil.empty(); String newLine = "\n";//System.getProperty("line.separator"); - result.append(new LiteralText(displayName + " {").setStyle(DEFAULT_STYLE)); + result.append(TextUtil.literal(displayName + " {").setStyle(DEFAULT_STYLE)); result.append(newLine); - LiteralText propsText = new LiteralText(""); + var propsText = TextUtil.empty(); result.append(propsText); //print field names paired with their values @@ -107,7 +130,7 @@ public void storeProperties() { ex.printStackTrace(); } } - result.append(new LiteralText("}").setStyle(ACCENT_STYLE)); + result.append(TextUtil.literal("}").setStyle(ACCENT_STYLE)); return result; @@ -135,10 +158,10 @@ public List getPublicFieldNames() { } private MutableText fieldAsText(Field field) throws IllegalAccessException { - var value = (Option)field.get(this); - return new LiteralText("") - .append(new LiteralText(field.getName() + ": ").setStyle(DEFAULT_STYLE)) - .append(new LiteralText(value.getValue().toString())); + var value = (Option) field.get(this); + return TextUtil.empty() + .append(TextUtil.literal(field.getName() + ": ").setStyle(DEFAULT_STYLE)) + .append(TextUtil.literal(value.getValue().toString())); } public @Nullable MutableText getFieldValueAsText(String fieldName) throws NoSuchFieldException { @@ -150,4 +173,9 @@ private MutableText fieldAsText(Field field) throws IllegalAccessException { return null; } + private final List> configLoadHandlers = new ArrayList<>(); + + public void registerLoadHandler(Consumer handler) { + configLoadHandlers.add(handler); + } } diff --git a/ec-core/src/main/java/dev/jpcode/eccore/config/ConfigUtil.java b/ec-core/src/main/java/dev/jpcode/eccore/config/ConfigUtil.java index 8c4fe949..c0558ae6 100644 --- a/ec-core/src/main/java/dev/jpcode/eccore/config/ConfigUtil.java +++ b/ec-core/src/main/java/dev/jpcode/eccore/config/ConfigUtil.java @@ -2,13 +2,19 @@ import com.google.gson.JsonParser; import com.google.gson.JsonSyntaxException; + +import dev.jpcode.eccore.util.TimeUtil; + import net.minecraft.text.Style; import net.minecraft.text.Text; import net.minecraft.util.Formatting; + import org.apache.logging.log4j.Level; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.time.Duration; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -24,8 +30,7 @@ public final class ConfigUtil { private ConfigUtil() {} // TODO do not delclair serializer objects out here. Pretty sure is bad for concurrent parsing. - private static final Style.Serializer styleJsonDeserializer = new Style.Serializer(); - private static final JsonParser jsonParser = new JsonParser(); + private static final Style.Serializer STYLE_JSON_DESERIALIZER = new Style.Serializer(); public static Style parseStyleOrDefault(String styleStr, String defaultStyleStr) { Style outStyle = null; @@ -36,13 +41,15 @@ public static Style parseStyleOrDefault(String styleStr, String defaultStyleStr) if (outStyle == null) { outStyle = parseStyle(defaultStyleStr); LOGGER.log( - Level.WARN, - String.format("Could not load malformed style: '%s'. Using default, '%s'.", styleStr, defaultStyleStr) + Level.WARN, + String.format("Could not load malformed style: '%s'. Using default, '%s'.", styleStr, defaultStyleStr) ); } return outStyle; } + private static JsonParser jsonParser = new JsonParser(); + @Nullable public static Style parseStyle(String styleStr) { Style outStyle = null; Formatting formatting = Formatting.byName(styleStr); @@ -52,15 +59,14 @@ public static Style parseStyle(String styleStr) { if (outStyle == null) { try { - outStyle = styleJsonDeserializer.deserialize( - jsonParser.parse(styleStr), - null, null + outStyle = STYLE_JSON_DESERIALIZER.deserialize( + jsonParser.parse(styleStr), + null, null ); } catch (JsonSyntaxException e) { LOGGER.log(Level.ERROR, String.format( - "Malformed Style JSON in config: %s", styleStr + "Malformed Style JSON in config: %s", styleStr )); -// e.printStackTrace(); } } @@ -77,8 +83,8 @@ public static Text parseTextOrDefault(String textStr, String defaultTextStr) { if (outText == null) { outText = parseText(defaultTextStr); LOGGER.log( - Level.WARN, - String.format("Could not load malformed Text: '%s'. Using default, '%s'.", textStr, defaultTextStr) + Level.WARN, + String.format("Could not load malformed Text: '%s'. Using default, '%s'.", textStr, defaultTextStr) ); } return outText; @@ -93,6 +99,15 @@ public static int parseInt(String s) { return -1; } + public static int parseIntOrDefault(String s, int fallback) { + try { + return Integer.parseInt(s); + } catch (NumberFormatException e) { + logNumberParseError(s, "int"); + return fallback; + } + } + public static double parseDouble(String s) { try { return Double.parseDouble(s); @@ -109,7 +124,7 @@ public static double parseDouble(String s) { public static List parseCsv(@NotNull String csvString, @NotNull ValueParser valueParser) { return Arrays.stream(csvString.split(",")).sequential().map(String::trim) - .map(valueParser::parseValue).collect(Collectors.toList()); + .map(valueParser::parseValue).collect(Collectors.toList()); } @Contract(pure = true) @@ -120,18 +135,26 @@ public static List parseCsv(@NotNull String csvString, @NotNull ValuePars public static List parseArray(@NotNull String arrayString, @NotNull ValueParser valueParser) { int endIdx = arrayString.indexOf(']'); return parseCsv( - arrayString.substring(arrayString.indexOf('[') + 1, endIdx == -1 ? arrayString.length() : endIdx), - valueParser + arrayString.substring(arrayString.indexOf('[') + 1, endIdx == -1 ? arrayString.length() : endIdx), + valueParser ); } private static void logNumberParseError(String num, String type) { Config.LOGGER.log(Level.WARN, String.format( - "Invalid number format for type '%s' in config. Value provided: '%s'", type, num + "Invalid number format for type '%s' in config. Value provided: '%s'", type, num )); } public static String serializeStyle(Style style) { - return String.valueOf(styleJsonDeserializer.serialize(style, null, null)); + return String.valueOf(STYLE_JSON_DESERIALIZER.serialize(style, null, null)); + } + + public static int parseDurationToTicks(String str) { + return TimeUtil.durationToTicks(Duration.parse(str)); + } + + public static String serializeTicksAsDuration(int ticks) { + return Duration.ofMillis(TimeUtil.ticksToMs(ticks)).toString(); } } diff --git a/ec-core/src/main/java/dev/jpcode/eccore/config/Option.java b/ec-core/src/main/java/dev/jpcode/eccore/config/Option.java index 62eda646..222453c4 100644 --- a/ec-core/src/main/java/dev/jpcode/eccore/config/Option.java +++ b/ec-core/src/main/java/dev/jpcode/eccore/config/Option.java @@ -1,11 +1,11 @@ package dev.jpcode.eccore.config; -import net.fabricmc.fabric.api.event.Event; -import net.fabricmc.fabric.api.event.EventFactory; - import java.util.Properties; import java.util.function.Consumer; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; + public class Option { private final String key; diff --git a/ec-core/src/main/java/dev/jpcode/eccore/config/SortedProperties.java b/ec-core/src/main/java/dev/jpcode/eccore/config/SortedProperties.java index 84c76839..344ef21d 100644 --- a/ec-core/src/main/java/dev/jpcode/eccore/config/SortedProperties.java +++ b/ec-core/src/main/java/dev/jpcode/eccore/config/SortedProperties.java @@ -1,11 +1,11 @@ package dev.jpcode.eccore.config; -import org.jetbrains.annotations.NotNull; - import java.io.IOException; import java.io.Writer; import java.util.*; +import org.jetbrains.annotations.NotNull; + class SortedProperties extends Properties { public void storeSorted(Writer out, String comments) throws IOException { diff --git a/ec-core/src/main/java/dev/jpcode/eccore/util/StringBuilderPlus.java b/ec-core/src/main/java/dev/jpcode/eccore/util/StringBuilderPlus.java index faa57440..b4d36c1a 100644 --- a/ec-core/src/main/java/dev/jpcode/eccore/util/StringBuilderPlus.java +++ b/ec-core/src/main/java/dev/jpcode/eccore/util/StringBuilderPlus.java @@ -1,10 +1,10 @@ package dev.jpcode.eccore.util; -public class StringBuilderPlus { +public class StringBuilderPlus { private final StringBuilder sb; - public StringBuilderPlus(){ + public StringBuilderPlus() { sb = new StringBuilder(); } @@ -24,4 +24,4 @@ public String toString() { return sb.toString(); } -} \ No newline at end of file +} diff --git a/ec-core/src/main/java/dev/jpcode/eccore/util/TextUtil.java b/ec-core/src/main/java/dev/jpcode/eccore/util/TextUtil.java index eb7b616b..ed170ad7 100644 --- a/ec-core/src/main/java/dev/jpcode/eccore/util/TextUtil.java +++ b/ec-core/src/main/java/dev/jpcode/eccore/util/TextUtil.java @@ -1,64 +1,95 @@ package dev.jpcode.eccore.util; +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; + import com.google.gson.JsonParseException; -import dev.jpcode.eccore.ECCore; import eu.pb4.placeholders.TextParser; -import net.minecraft.text.*; import org.apache.logging.log4j.Level; -import java.util.ArrayList; -import java.util.Collection; +import net.minecraft.text.*; -public class TextUtil { +import dev.jpcode.eccore.ECCore; +public final class TextUtil { + private TextUtil() {} + + public static MutableText empty() { + return new LiteralText(""); + } + + public static MutableText literal(String content) { + return new LiteralText(content); + } public static MutableText concat(Text... arr) { - MutableText out = new LiteralText(""); + MutableText out = empty(); for (Text text : arr) { out.append(text); } return out; } -/** - *

Joins the elements of the provided array into a single Text - * containing the provided list of elements.

- * - *

No delimiter is added before or after the list. - * Null objects or empty strings within the array are represented by - * empty strings.

- * - *
-  * StringUtils.join(null, *)               = null
-  * StringUtils.join([], *)                 = ""
-  * StringUtils.join([null], *)             = ""
-  * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
-  * StringUtils.join(["a", "b", "c"], null) = "abc"
-  * StringUtils.join([null, "", "a"], ';')  = ";;a"
-  * 
- * - * @param array the array of values to join together, may be null - * @param separator the separator character to use - * @return the joined String, null if null array input - * @since 2.0 - */ - public static Text join(Text[] array, Text separator) { + + public static MutableText deepCopy(Text text) { + if (text.getSiblings().isEmpty()) { + return text.copy(); + } + + var siblings = text.getSiblings(); + var newSiblings = siblings.stream() + .map(TextUtil::deepCopy) + .toList(); + siblings.clear(); + siblings.addAll(newSiblings); + return text.copy(); + } + + /** + *

Joins the elements of the provided array into a single Text + * containing the provided list of elements.

+ * + *

No delimiter is added before or after the list. + * Null objects or empty strings within the array are represented by + * empty strings.

+ * + *
+     * StringUtils.join(null, *)               = null
+     * StringUtils.join([], *)                 = ""
+     * StringUtils.join([null], *)             = ""
+     * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
+     * StringUtils.join(["a", "b", "c"], null) = "abc"
+     * StringUtils.join([null, "", "a"], ';')  = ";;a"
+     * 
+ * + * @param array the array of values to join together, may be null + * @param separator the separator character to use + * @return the joined String, null if null array input + * @since 2.0 + */ + public static MutableText join(Text[] array, Text separator) { if (array == null) { - return null; - } + return null; + } return join(array, separator, 0, array.length); } - public static Text join(Collection textCollection, Text separator) { + + public static MutableText join(Collection textCollection, Text separator) { if (textCollection == null) { return null; } return join(textCollection.toArray(new Text[0]), separator, 0, textCollection.size()); } - public static Text join(Collection stringCollection, Text separator, Style stringsFormatting) { + + public static MutableText join(Collection stringCollection, Text separator, Style stringsFormatting) { if (stringCollection == null) { return null; } return join( - stringCollection.stream().map(str -> new LiteralText(str).setStyle(stringsFormatting)).toArray(Text[]::new), + stringCollection.stream().map(str -> literal(str).setStyle(stringsFormatting)).toArray(Text[]::new), separator, 0, stringCollection.size() ); } @@ -68,8 +99,8 @@ public static String joinStrings(Collection stringCollection, String sep return null; } return joinStrings( - stringCollection.toArray(String[]::new), - separator, 0, stringCollection.size() + stringCollection.toArray(String[]::new), + separator, 0, stringCollection.size() ); } @@ -93,8 +124,7 @@ public static String joinStrings(String[] array, String separator, int startInde return buf.toString(); } - - public static Text join(Text[] array, Text separator, int startIndex, int endIndex) { + public static MutableText join(Text[] array, Text separator, int startIndex, int endIndex) { if (array == null) { return null; } @@ -102,7 +132,7 @@ public static Text join(Text[] array, Text separator, int startIndex, int endInd if (bufSize <= 0) { return null; } - MutableText buf = new LiteralText(""); + MutableText buf = empty(); for (int i = startIndex; i < endIndex; i++) { if (i > startIndex) { buf.append(separator); @@ -114,12 +144,10 @@ public static Text join(Text[] array, Text separator, int startIndex, int endInd return buf; } - public static Text spaceBetween(Text[] array, int totalWidth, int padding) { + public static MutableText spaceBetween(Text[] array, int totalWidth, int padding) { int totalTextSize = 0; - ArrayList strings = new ArrayList<>(array.length); for (Text txt : array) { String str = txt.getString(); - strings.add(str); totalTextSize += str.length(); } @@ -128,39 +156,42 @@ public static Text spaceBetween(Text[] array, int totalWidth, int padding) { return concat(array); } - MutableText outText = new LiteralText("");//new ArrayList<>(strings.size() * 2 - 1); + MutableText outText = empty(); String lrPadStr = " ".repeat(padding); String spaceStr = " ".repeat((totalWidth - padding * 2 - totalTextSize) / (array.length - 1)); - outText.append(new LiteralText(lrPadStr)); + outText.append(literal(lrPadStr)); for (int i = 0; i < array.length; i++) { outText.append(array[i]); - if (i != array.length - 1) - outText.append(new LiteralText(spaceStr)); + if (i != array.length - 1) { + outText.append(literal(spaceStr)); + } } - outText.append(new LiteralText(lrPadStr)); + outText.append(literal(lrPadStr)); return outText; } - public static Text clickableTeleport(MutableText originalText, String destinationName, String commandBaseString) { + public static MutableText clickableTeleport(MutableText originalText, String destinationName, String commandBaseString) { String teleportCommand = String.format("%s %s", commandBaseString, destinationName); Style outStyle = originalText.getStyle() .withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, teleportCommand)) - .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new LiteralText("Click to teleport to " + destinationName +"."))); + .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, literal("Click to teleport to " + + destinationName + + "."))); return originalText.setStyle(outStyle); } + private static final Collection TEXT_PARSERS = new ArrayList<>(); - private static final Collection textParsers = new ArrayList<>(); /** * Parsers should be registered in order of most-restrictive to least restrictive. */ public static void registerTextParser(StringToTextParser parser) { - textParsers.add(parser); + TEXT_PARSERS.add(parser); } static { @@ -181,18 +212,70 @@ public static void registerTextParser(StringToTextParser parser) { )); } } + public static Text parseText(String textStr) { Text outText = null; - for (StringToTextParser parser : textParsers) { + for (StringToTextParser parser : TEXT_PARSERS) { try { outText = parser.parseText(textStr); } catch (JsonParseException e) { ECCore.LOGGER.log(Level.INFO, String.format("Failed to parse string '%s' as MinecraftText, trying Fabric Placeholder API...", textStr)); } - if (outText != null) + if (outText != null) { break; + } } return outText; } + + public static Collector collect() { + return new Collector<>() { + @Override + public Supplier supplier() { + return TextUtil::empty; + } + + @Override + public BiConsumer accumulator() { + return MutableText::append; + } + + @Override + public BinaryOperator combiner() { + return (r1, r2) -> { + r1.append(r2); + return r1; + }; + } + + @Override + public Function finisher() { + return (a) -> a; + } + + @Override + public Set characteristics() { + return Collections.emptySet(); + } + }; + } + + /** + * indempotent + * + * @return flattened text + */ + public static List flattenRoot(Text text) { + var siblings = text.getSiblings(); + if (siblings.size() == 0) { + return List.of(text); + } + + List content = new ArrayList<>(siblings.size() + 1); + content.add(text.copy().setStyle(text.getStyle())); + content.addAll(siblings); + + return content; + } } diff --git a/ec-core/src/main/java/dev/jpcode/eccore/util/TimeUtil.java b/ec-core/src/main/java/dev/jpcode/eccore/util/TimeUtil.java new file mode 100644 index 00000000..f4228e04 --- /dev/null +++ b/ec-core/src/main/java/dev/jpcode/eccore/util/TimeUtil.java @@ -0,0 +1,47 @@ +package dev.jpcode.eccore.util; + +import java.time.Duration; + +import net.minecraft.server.MinecraftServer; + +public final class TimeUtil { + private TimeUtil() {} + + public static final int TPS = 20; + public static final double SECONDS_PER_TICK = 1 / (double) TPS; + public static final long MS_PER_TICK = (long) (SECONDS_PER_TICK * 1000); + private static MinecraftServer server; + + public static void init(MinecraftServer server) { + TimeUtil.server = server; + } + + public static int getTicks() { + return server.getTicks(); + } + + public static long ticksToMs(int ticks) { + return ticks * MS_PER_TICK; + } + + public static int msToTicks(long ms) { + return (int) (ms / MS_PER_TICK); + } + + public static long tickTimeToEpochMs(int ticks) { + return ticksToMs(ticks - server.getTicks()) + net.minecraft.util.Util.getEpochTimeMs(); + } + + public static int epochTimeMsToTicks(long epochTimeMs) { + var msFromNow = epochTimeMs - net.minecraft.util.Util.getEpochTimeMs(); + return server.getTicks() + msToTicks(msFromNow); + } + + public static int durationToTicks(Duration duration) { + return TimeUtil.msToTicks(duration.toMillis()); + } + + public static double ticksToSeconds(int teleportDelayTicks) { + return teleportDelayTicks * SECONDS_PER_TICK; + } +} diff --git a/ec-core/src/main/java/dev/jpcode/eccore/util/Util.java b/ec-core/src/main/java/dev/jpcode/eccore/util/Util.java index 332e3823..85f35501 100644 --- a/ec-core/src/main/java/dev/jpcode/eccore/util/Util.java +++ b/ec-core/src/main/java/dev/jpcode/eccore/util/Util.java @@ -1,13 +1,17 @@ package dev.jpcode.eccore.util; -public class Util { +public final class Util { + private Util() {} + static int getJavaVersion() { String version = System.getProperty("java.version"); - if(version.startsWith("1.")) { + if (version.startsWith("1.")) { version = version.substring(2, 3); } else { int dot = version.indexOf("."); - if(dot != -1) { version = version.substring(0, dot); } + if (dot != -1) { + version = version.substring(0, dot); + } } int versionNum = 0; try { diff --git a/ec-core/src/main/resources/eccore.mixins.json b/ec-core/src/main/resources/eccore.mixins.json index 684a550f..905f42c9 100644 --- a/ec-core/src/main/resources/eccore.mixins.json +++ b/ec-core/src/main/resources/eccore.mixins.json @@ -1,7 +1,7 @@ { "required": true, "package": "com.fibermc.essentialcommands.mixin", - "compatibilityLevel": "JAVA_16", + "compatibilityLevel": "JAVA_17", "mixins": [ ], "client": [ diff --git a/ec-core/src/main/resources/fabric.mod.json b/ec-core/src/main/resources/fabric.mod.json index 675eefbb..7810761a 100644 --- a/ec-core/src/main/resources/fabric.mod.json +++ b/ec-core/src/main/resources/fabric.mod.json @@ -30,7 +30,6 @@ ] }, "mixins": [ - "eccore.mixins.json" ], "depends": { diff --git a/ec-core/src/test/java/dev/jpcode/eccore/util/TextUtilTests.java b/ec-core/src/test/java/dev/jpcode/eccore/util/TextUtilTests.java new file mode 100644 index 00000000..0ec7a6cc --- /dev/null +++ b/ec-core/src/test/java/dev/jpcode/eccore/util/TextUtilTests.java @@ -0,0 +1,32 @@ +package dev.jpcode.eccore.util; + +import org.junit.jupiter.api.DisplayName; + +@DisplayName("TextUtil") +public class TextUtilTests { + // This is a 1.19 test. 1.18 text works differently for what this is testing + // iirc. +// @Test +// @DisplayName("flattenRoot output is shaped correctly") +// void flattenRoot_flattensCorrectly() +// { +// var baseStyle = Style.EMPTY.withColor(Formatting.AQUA); +// var input = TextUtil.literal("testing").setStyle(baseStyle) +// .append("token2") +// .append("token3"); +// +// var output = TextUtil.flattenRoot(input); +// +// assertEquals(output.get(0).getContent(), input.getContent()); +// assertEquals(output.get(0).getStyle(), baseStyle); +// +// var inputSiblings = input.getSiblings(); +// for (int i = 1; i < output.size(); i++) { +// var inputToken = inputSiblings.get(i - 1); +// var outToken = output.get(i); +// +// assertEquals(inputToken.getContent(), outToken.getContent()); +// assertEquals(inputToken.getStyle(), outToken.getStyle()); +// } +// } +} diff --git a/gradle.properties b/gradle.properties index 39d313a3..55d9ed0f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,33 +3,35 @@ org.gradle.jvmargs=-Xmx2048M # Fabric Properties # check these on https://fabricmc.net/versions.html - minecraft_version=1.17.1 - yarn_mappings=1.17.1+build.37 - loader_version=0.11.6 - fabric_version=0.37.2+1.17 +minecraft_version=1.17.1 +yarn_mappings=1.17.1+build.65 +loader_version=0.14.13 + +#Fabric api +fabric_version=0.46.1+1.17 # Mod Properties - mod_name = Essential Commands - mod_id = essential_commands - mod_version = 0.17.1 - maven_group = com.fibermc - archives_base_name = essential_commands +mod_name = Essential Commands +mod_id = essential_commands +mod_version = 0.31.1 +maven_group = com.fibermc +archives_base_name = essential_commands # Dependencies - permissions_api_version=0.1-SNAPSHOT - placeholder_api_version=1.1.0+1.17.1 - pal_version=1.3.0 - #mod_menu_version = 2.0.2 +permissions_api_version=0.1-SNAPSHOT +placeholder_api_version=1.1.3+1.17.1 +pal_version=1.3.0 +#mod_menu_version = 2.0.2 - jetbrains_annotations_version = 21.0.1 - junit_jupiter_version = 5.7.2 +jetbrains_annotations_version = 22.0.0 +junit_jupiter_version = 5.8.2 # Publish # Modrinth modrinth_project_id=6VdDUivB # Modrinth errors if you provide required deps as project slugs. I think you need ids. Err msg not very descriptive *at all*. # Not project slugs. File slugs. Found at https://modrinth.com/mod/PROJECT_SLUG/version/ -mr_game_versions = 1.17,1.17.1 +mr_game_versions = 1.17.1 mr_relations_required = nSk00F5M #fabric-api mr_relations_optional = AFeyDid4 @@ -38,7 +40,7 @@ mr_relations_incompatible = # CurseForge cf_project_id=475964 -cf_game_versions = Fabric,Java 16,1.17,1.17.1 +cf_game_versions = Fabric,Java 17,Java 18,1.17.1 cf_relations_required = fabric-api cf_relations_optional = luckperms cf_relations_embedded = @@ -49,3 +51,5 @@ cf_relations_incompatible = github_repo=John-Paul-R/essential-commands gh_owner=John-Paul-R gh_repo=essential-commands + +mod_menu_version=3.0.0 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0f80bbf5..e750102e 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/settings-github-action.gradle b/settings-github-action.gradle deleted file mode 100644 index 5109f8b4..00000000 --- a/settings-github-action.gradle +++ /dev/null @@ -1,12 +0,0 @@ -pluginManagement { - repositories { - maven { - name = 'Fabric' - url = 'https://maven.fabricmc.net/' - } - gradlePluginPortal() - } -} -rootProject.name = 'essential_commands' -rootProject.buildFileName = "build-github-action.gradle" -include 'ec-core' diff --git a/src/main/java/com/fibermc/essentialcommands/ECAbilitySources.java b/src/main/java/com/fibermc/essentialcommands/ECAbilitySources.java index 211cb980..49947e14 100644 --- a/src/main/java/com/fibermc/essentialcommands/ECAbilitySources.java +++ b/src/main/java/com/fibermc/essentialcommands/ECAbilitySources.java @@ -2,8 +2,19 @@ import io.github.ladysnake.pal.AbilitySource; import io.github.ladysnake.pal.Pal; -import net.minecraft.util.Identifier; -public class ECAbilitySources { +public final class ECAbilitySources { + private ECAbilitySources() {} + + // Call this on startup. + // Forces clinit, so that ability sources get registered with Pal. + // If a player joins rejoins the server with an EC ability active before + // ECAbilitySources clinit has occurred, Pal will disable the ability, as it + // does not recognize the (not yet registered source). + @SuppressWarnings("EmptyMethod") + public static void init() {} + public static final AbilitySource FLY_COMMAND = Pal.getAbilitySource(EssentialCommands.MOD_ID, "ec-fly-command"); + public static final AbilitySource INVULN_COMMAND = Pal.getAbilitySource(EssentialCommands.MOD_ID, "ec-invuln-command"); + public static final AbilitySource AFK_INVULN = Pal.getAbilitySource(EssentialCommands.MOD_ID, "ec-afk-invuln"); } diff --git a/src/main/java/com/fibermc/essentialcommands/ECPerms.java b/src/main/java/com/fibermc/essentialcommands/ECPerms.java index 2d1c04cd..a032e183 100644 --- a/src/main/java/com/fibermc/essentialcommands/ECPerms.java +++ b/src/main/java/com/fibermc/essentialcommands/ECPerms.java @@ -1,22 +1,25 @@ package com.fibermc.essentialcommands; -import me.lucko.fabric.api.permissions.v0.PermissionCheckEvent; -import me.lucko.fabric.api.permissions.v0.Permissions; -import net.fabricmc.fabric.api.util.TriState; -import net.minecraft.command.CommandSource; -import net.minecraft.server.command.ServerCommandSource; -import org.jetbrains.annotations.NotNull; - import java.util.Arrays; import java.util.Collection; import java.util.function.Predicate; +import java.util.stream.Stream; + +import me.lucko.fabric.api.permissions.v0.Permissions; +import org.jetbrains.annotations.NotNull; + +import net.minecraft.command.CommandSource; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; -public class ECPerms { +public final class ECPerms { + private ECPerms() {} //`essentialcommands..` // `essentialcommands..*` + @SuppressWarnings({"checkstyle:constantname", "checkstyle:staticvariablename"}) public static final class Registry { public static final String tpa = "essentialcommands.tpa"; public static final String tpahere = "essentialcommands.tpahere"; @@ -24,10 +27,13 @@ public static final class Registry { public static final String tpdeny = "essentialcommands.tpdeny"; public static final String home_set = "essentialcommands.home.set"; public static final String home_tp = "essentialcommands.home.tp"; + public static final String home_tp_others = "essentialcommands.home_tp_others"; public static final String home_delete = "essentialcommands.home.delete"; public static final String warp_set = "essentialcommands.warp.set"; public static final String warp_tp = "essentialcommands.warp.tp"; public static final String warp_delete = "essentialcommands.warp.delete"; + public static final String warp_tp_named = "essentialcommands.warp.tp_named"; + public static final String warp_tp_others = "essentialcommands.warp_tp_others"; public static final String back = "essentialcommands.back"; public static final String spawn_tp = "essentialcommands.spawn.tp"; public static final String spawn_set = "essentialcommands.spawn.set"; @@ -38,16 +44,32 @@ public static final class Registry { public static final String nickname_style_fancy = "essentialcommands.nickname.style.fancy"; public static final String nickname_style_hover = "essentialcommands.nickname.style.hover"; public static final String nickname_style_click = "essentialcommands.nickname.style.click"; + public static final String nickname_selector_and_ctx = "essentialcommands.nickname.style.selector_and_context"; + public static final String nickname_placeholders = "essentialcommands.nickname.placeholders"; public static final String randomteleport = "essentialcommands.randomteleport"; public static final String fly_self = "essentialcommands.fly.self"; public static final String fly_others = "essentialcommands.fly.others"; + public static final String invuln_self = "essentialcommands.invuln.self"; + public static final String invuln_others = "essentialcommands.invuln.others"; public static final String workbench = "essentialcommands.workbench"; + public static final String stonecutter = "essentialcommands.stonecutter"; + public static final String grindstone = "essentialcommands.grindstone"; + public static final String anvil = "essentialcommands.anvil"; public static final String enderchest = "essentialcommands.enderchest"; + public static final String wastebin = "essentialcommands.wastebin"; public static final String top = "essentialcommands.top"; + public static final String gametime = "essentialcommands.gametime"; + public static final String time_set_day = "essentialcommands.day"; + public static final String afk = "essentialcommands.afk"; + public static final String bed = "essentialcommands.bed"; public static final String config_reload = "essentialcommands.config.reload"; public static final String bypass_teleport_delay = "essentialcommands.bypass.teleport_delay"; public static final String bypass_allow_teleport_between_dimensions = "essentialcommands.bypass.allow_teleport_between_dimensions"; public static final String bypass_teleport_interrupt_on_damaged = "essentialcommands.bypass.teleport_interrupt_on_damaged"; + public static final String bypass_teleport_interrupt_on_move = "essentialcommands.bypass.teleport_interrupt_on_move"; + public static final String rules_reload = "essentialcommands.rules_reload"; + public static final String rules = "essentialcommands.rules"; + public static final class Group { public static final String[] tpa_group = {tpa, tpahere, tpaccept, tpdeny}; public static final String[] home_group = {home_set, home_tp, home_delete}; @@ -55,51 +77,57 @@ public static final class Group { public static final String[] spawn_group = {spawn_tp, spawn_set}; public static final String[] nickname_group = {nickname_self, nickname_others, nickname_reveal}; public static final String[] fly_group = {fly_self, fly_others}; + public static final String[] invuln_group = {invuln_self, invuln_others}; public static final String[] config_group = {config_reload}; public static String[] home_limit_group; + public static final String[] stateful_player_abilities = {fly_self, fly_others, invuln_self, invuln_others}; } + + public static String[] per_warp_permissions = null; } /** * Registers PermissionCheckEvent handler if permissions api enabled in config. */ static void init() { - if (CONFIG.USE_PERMISSIONS_API.getValue()) { - PermissionCheckEvent.EVENT.register((source, permission) -> { - if (isSuperAdmin(source)) { - return TriState.TRUE; - } - return TriState.DEFAULT; - }); - } + var worldDataManager = ManagerLocator.getInstance().getWorldDataManager(); + Registry.per_warp_permissions = worldDataManager.getWarpNames().toArray(String[]::new); + worldDataManager.warpsLoadEvent.register((warps) -> { + Registry.per_warp_permissions = warps.keySet().toArray(String[]::new); + }); } private static boolean isSuperAdmin(CommandSource source) { return source.hasPermissionLevel(4); } - - static @NotNull Predicate require(@NotNull String permission, int defaultRequireLevel) { + public static @NotNull Predicate require(@NotNull String permission, int defaultRequireLevel) { return player -> check(player, permission, defaultRequireLevel); } - static @NotNull Predicate requireAny(@NotNull String[] permissions, int defaultRequireLevel) { + public static @NotNull Predicate requireAny(@NotNull String[] permissions, int defaultRequireLevel) { return player -> checkAny(player, permissions, defaultRequireLevel); } - static boolean check(@NotNull CommandSource source, @NotNull String permission, int defaultRequireLevel) { - if (CONFIG.USE_PERMISSIONS_API.getValue()) { - return Permissions.getPermissionValue(source, permission).orElse(false); + public static boolean check(@NotNull CommandSource source, @NotNull String permission, int defaultRequireLevel) { + if (CONFIG.USE_PERMISSIONS_API) { + try { + // TODO: In the future, config option for granting ops all perms. + return Permissions.getPermissionValue(source, permission).orElse(source.hasPermissionLevel(Math.max(2, defaultRequireLevel))); + } catch (Exception e) { + EssentialCommands.LOGGER.error(e); + return false; + } } else { - return (source.hasPermissionLevel(defaultRequireLevel) ? TriState.TRUE:TriState.FALSE).orElse(false); + return source.hasPermissionLevel(defaultRequireLevel); } } - static boolean check(@NotNull CommandSource source, @NotNull String permission) { + public static boolean check(@NotNull CommandSource source, @NotNull String permission) { return check(source, permission, 4); } - static boolean checkAny(@NotNull CommandSource source, @NotNull String[] permissions, int defaultRequireLevel) { + public static boolean checkAny(@NotNull CommandSource source, @NotNull String[] permissions, int defaultRequireLevel) { for (String permission : permissions) { if (check(source, permission, defaultRequireLevel)) { return true; @@ -112,7 +140,7 @@ private static int getNumericValue(String permission) { return Integer.parseInt(permission.substring(permission.lastIndexOf('.') + 1)); } - static int getHighestNumericPermission(@NotNull CommandSource source, @NotNull String[] permissionGroup) { + public static int getHighestNumericPermission(@NotNull CommandSource source, @NotNull String[] permissionGroup) { // No effective numeric limits for ops. if (isSuperAdmin(source)) { return Integer.MAX_VALUE; @@ -124,21 +152,21 @@ static int getHighestNumericPermission(@NotNull CommandSource source, @NotNull S } // If permissions API is disabled, min int value in permission group is used for all non-op players. - if (!CONFIG.USE_PERMISSIONS_API.getValue()) { + if (!CONFIG.USE_PERMISSIONS_API) { return Arrays.stream(permissionGroup).mapToInt(ECPerms::getNumericValue).min().getAsInt(); } // If permissions api is enabled, find the highest numeric permission node that the user has & return its // numeric value. int highestValue; - if (CONFIG.GRANT_LOWEST_NUMERIC_BY_DEFAULT.getValue()) { + if (CONFIG.GRANT_LOWEST_NUMERIC_BY_DEFAULT) { // Grant min perm value in group by default, if none are set. highestValue = Arrays.stream(permissionGroup).mapToInt(ECPerms::getNumericValue).min().getAsInt(); } else { // Set value to -1 in the case where the user has no relevant permissions set. highestValue = -1; } - for (String permission: permissionGroup) { + for (String permission : permissionGroup) { if (check(source, permission)) { highestValue = Math.max(highestValue, getNumericValue(permission)); } @@ -151,5 +179,10 @@ public static String[] makeNumericPermissionGroup(String basePermission, Collect return numericValues.stream().map(el -> trueBasePermission.concat(el.toString())).toArray(String[]::new); } - -} \ No newline at end of file + public static Stream getGrantedStatefulPlayerAbilityPermissions(ServerPlayerEntity player) { + var list = Arrays.stream(Registry.Group.stateful_player_abilities); + return player.hasPermissionLevel(2) + ? list // TODO: this is hacky + : list.filter(permission -> check(player.getCommandSource(), permission)); + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/ECPlaceholderRegistry.java b/src/main/java/com/fibermc/essentialcommands/ECPlaceholderRegistry.java new file mode 100644 index 00000000..b261ccee --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/ECPlaceholderRegistry.java @@ -0,0 +1,28 @@ +package com.fibermc.essentialcommands; + +import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; +import eu.pb4.placeholders.PlaceholderAPI; +import eu.pb4.placeholders.PlaceholderResult; + +import net.minecraft.util.Identifier; + +final class ECPlaceholderRegistry { + private ECPlaceholderRegistry() {} + + public static void register() { + var namespace = EssentialCommands.MOD_ID; + PlaceholderAPI.register( + new Identifier(namespace, "nickname"), + (ctx) -> { + if (ctx.hasPlayer()) { + return PlaceholderResult.value( + ((ServerPlayerEntityAccess)ctx.getPlayer()) + .ec$getPlayerData() + .getFullNickname()); + } + return PlaceholderResult.invalid("No player!"); + } + ); + + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/ECText.java b/src/main/java/com/fibermc/essentialcommands/ECText.java deleted file mode 100644 index c8d4f9fc..00000000 --- a/src/main/java/com/fibermc/essentialcommands/ECText.java +++ /dev/null @@ -1,143 +0,0 @@ -package com.fibermc.essentialcommands; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.gson.Gson; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParseException; -import net.minecraft.client.font.TextVisitFactory; -import net.minecraft.text.*; -import net.minecraft.util.JsonHelper; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.function.BiConsumer; -import java.util.regex.Pattern; - -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; -import static com.fibermc.essentialcommands.EssentialCommands.LOGGER; - -public abstract class ECText { - -// Map textRegistry; - private static final Gson GSON = new Gson(); - private static final Pattern TOKEN_PATTERN = Pattern.compile("%(\\d+\\$)?[\\d.]*[df]"); - public static final String DEFAULT_LANGUAGE = "en_us"; - - private static volatile ECText instance = create("en_us"); - - private ECText() {} - - static { - CONFIG.LANGUAGE.changeEvent.register((langId) -> { - instance = create(langId); - }); - } - - private static ECText create(String langId) { - ImmutableMap.Builder builder = ImmutableMap.builder(); - Objects.requireNonNull(builder); - BiConsumer biConsumer = builder::put; -// String var2 = "/assets/minecraft/lang/en_us.json"; - final String resourceFString = "/assets/essential_commands/lang/%s.json"; - final String resourceLocation = String.format(resourceFString, langId); - try { - InputStream inputStream = ECText.class.getResourceAsStream(resourceLocation); - if (inputStream == null) { - LOGGER.info(String.format("No EC lang file for the language '%s' found. Defulting to 'en_us'.", langId)); - inputStream = ECText.class.getResourceAsStream(String.format(resourceFString, "en_us")); - } - - try { - load(inputStream, biConsumer); - } catch (Throwable var7) { - if (inputStream != null) { - try { - inputStream.close(); - } catch (Throwable var6) { - var7.addSuppressed(var6); - } - } - - throw var7; - } - - if (inputStream != null) { - inputStream.close(); - } - } catch (JsonParseException | IOException var8) { - LOGGER.error("Couldn't read strings from {}", resourceLocation, var8); - } - - final Map map = builder.build(); - return new ECText() { - public String get(String key) { - return (String)map.getOrDefault(key, key); - } - - public MutableText getText(String key) { - return new LiteralText(get(key)); - } - - public MutableText getText(String key, Object... args) { - return new LiteralText(String.format(get(key), (Object[]) args)); - } - - public boolean hasTranslation(String key) { - return map.containsKey(key); - } - - public boolean isRightToLeft() { - return false; - } - - public OrderedText reorder(StringVisitable text) { - return (visitor) -> { - return text.visit((style, string) -> { - return TextVisitFactory.visitFormatted(string, style, visitor) ? Optional.empty() : StringVisitable.TERMINATE_VISIT; - }, Style.EMPTY).isPresent(); - }; - } - }; - } - - public static void load(InputStream inputStream, BiConsumer entryConsumer) { - JsonObject jsonObject = (JsonObject)GSON.fromJson(new InputStreamReader(inputStream, StandardCharsets.UTF_8), JsonObject.class); - Iterator var3 = jsonObject.entrySet().iterator(); - - while(var3.hasNext()) { - Map.Entry entry = (Map.Entry)var3.next(); - String string = TOKEN_PATTERN.matcher(JsonHelper.asString((JsonElement)entry.getValue(), (String)entry.getKey())).replaceAll("%$1s"); - entryConsumer.accept((String)entry.getKey(), string); - } - - } - - public static ECText getInstance() { - return instance; - } - -// public static String get(String key) { -// Language -// } - public abstract String get(String key); - - public abstract MutableText getText(String key, Object... args); - - public abstract MutableText getText(String key); - - public abstract boolean hasTranslation(String key); - - public abstract boolean isRightToLeft(); - - public abstract OrderedText reorder(StringVisitable text); - - public List reorder(List texts) { - return (List)texts.stream().map(this::reorder).collect(ImmutableList.toImmutableList()); - } - -} diff --git a/src/main/java/com/fibermc/essentialcommands/EssentialCommandRegistry.java b/src/main/java/com/fibermc/essentialcommands/EssentialCommandRegistry.java index 6e0c2857..6773b1fb 100644 --- a/src/main/java/com/fibermc/essentialcommands/EssentialCommandRegistry.java +++ b/src/main/java/com/fibermc/essentialcommands/EssentialCommandRegistry.java @@ -1,412 +1,553 @@ package com.fibermc.essentialcommands; +import java.io.FileNotFoundException; +import java.nio.file.NotDirectoryException; +import java.nio.file.Path; +import java.util.HashSet; +import java.util.function.Predicate; + import com.fibermc.essentialcommands.commands.*; -import com.fibermc.essentialcommands.commands.suggestions.*; +import com.fibermc.essentialcommands.commands.bench.*; +import com.fibermc.essentialcommands.commands.suggestions.ListSuggestion; +import com.fibermc.essentialcommands.commands.suggestions.NicknamePlayersSuggestion; +import com.fibermc.essentialcommands.commands.suggestions.TeleportResponseSuggestion; +import com.fibermc.essentialcommands.commands.suggestions.WarpSuggestion; +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.text.ECText; +import com.fibermc.essentialcommands.util.EssentialsConvertor; import com.fibermc.essentialcommands.util.EssentialsXParser; -import com.fibermc.essentialcommands.util.TextUtil; +import org.spongepowered.asm.util.IConsumer; + import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.BoolArgumentType; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.tree.LiteralCommandNode; import com.mojang.brigadier.tree.RootCommandNode; -import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; + import net.minecraft.command.argument.EntityArgumentType; import net.minecraft.command.argument.TextArgumentType; import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; -import java.io.FileNotFoundException; -import java.nio.file.NotDirectoryException; -import java.nio.file.Path; -import java.util.function.Predicate; +import dev.jpcode.eccore.util.TextUtil; +import static com.fibermc.essentialcommands.EssentialCommands.BACKING_CONFIG; import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; import static net.minecraft.server.command.CommandManager.argument; +import static net.minecraft.server.command.CommandManager.literal; /** - * BasicCommands + * Primary registry class for EssentialCommands. + * Contains logic for building the brigaider command trees, and registers + * required permissions for each node. */ -public class EssentialCommandRegistry { - - public static void register() { - - CommandRegistrationCallback.EVENT.register( - (CommandDispatcher dispatcher, boolean dedicated) -> { - - //TODO Command literals still get registered, they just don't do anything if disabled. Fix this. - RootCommandNode rootNode = dispatcher.getRoot(); - - LiteralCommandNode ecInfoNode = CommandManager.literal("info") - .executes(new ModInfoCommand()) - .build(); - - LiteralCommandNode essentialCommandsRootNode = - CommandManager.literal("essentialcommands") - .executes(ecInfoNode.getCommand()) - .build(); - - essentialCommandsRootNode.addChild(ecInfoNode); - - //Make some new nodes - //Tpa - if (CONFIG.ENABLE_TPA.getValue()) { - LiteralCommandNode tpAskNode = CommandManager.literal("tpa") - .requires(ECPerms.require(ECPerms.Registry.tpa, 0)) - .then(argument("target", EntityArgumentType.player()) - .executes(new TeleportAskCommand()) - ).build(); - - LiteralCommandNode tpAcceptNode = CommandManager.literal("tpaccept") - .requires(ECPerms.require(ECPerms.Registry.tpaccept, 0)) - .executes(new TeleportAcceptCommand()::runDefault) - .then(argument("target", EntityArgumentType.player()) - .suggests(TeleportResponseSuggestion.suggestedStrings()) - .executes(new TeleportAcceptCommand()) - ).build(); - - LiteralCommandNode tpDenyNode = CommandManager.literal("tpdeny") - .requires(ECPerms.require(ECPerms.Registry.tpdeny, 0)) - .executes(new TeleportDenyCommand()::runDefault) - .then(argument("target", EntityArgumentType.player()) - .suggests(TeleportResponseSuggestion.suggestedStrings()) - .executes(new TeleportDenyCommand()) - ).build(); - - LiteralCommandNode tpAskHereNode = CommandManager.literal("tpahere") - .requires(ECPerms.require(ECPerms.Registry.tpahere, 0)) - .then(argument("target", EntityArgumentType.player()) - .executes(new TeleportAskHereCommand()) - ).build(); - - rootNode.addChild(tpAskNode); - rootNode.addChild(tpAcceptNode); - rootNode.addChild(tpDenyNode); - rootNode.addChild(tpAskHereNode); - - essentialCommandsRootNode.addChild(tpAskNode); - essentialCommandsRootNode.addChild(tpAcceptNode); - essentialCommandsRootNode.addChild(tpDenyNode); - essentialCommandsRootNode.addChild(tpAskHereNode); - - - } - - - //Homes - if (CONFIG.ENABLE_HOME.getValue()) { - LiteralArgumentBuilder homeBuilder = CommandManager.literal("home"); - LiteralArgumentBuilder homeSetBuilder = CommandManager.literal("set"); - LiteralArgumentBuilder homeTpBuilder = CommandManager.literal("tp"); - LiteralArgumentBuilder homeDeleteBuilder = CommandManager.literal("delete"); - LiteralArgumentBuilder homeListBuilder = CommandManager.literal("list"); - - homeSetBuilder - .requires(ECPerms.require(ECPerms.Registry.home_set, 0)) - .then(argument("home_name", StringArgumentType.word()) - .executes(new HomeSetCommand())); - - homeTpBuilder - .requires(ECPerms.require(ECPerms.Registry.home_tp, 0)) - .executes(new HomeCommand()::runDefault) - .then(argument("home_name", StringArgumentType.word()) - .suggests(HomeSuggestion.suggestedStrings()) - .executes(new HomeCommand())); - - homeDeleteBuilder - .requires(ECPerms.require(ECPerms.Registry.home_delete, 0)) - .then(argument("home_name", StringArgumentType.word()) - .suggests(HomeSuggestion.suggestedStrings()) - .executes(new HomeDeleteCommand())); - - homeListBuilder - .requires(ECPerms.require(ECPerms.Registry.home_tp, 0)) - .executes(ListCommandFactory.create( - ECText.getInstance().get("cmd.home.list.start"), - "home tp", - HomeSuggestion::getSuggestionEntries - )); - - LiteralCommandNode homeNode = homeBuilder - .requires(ECPerms.requireAny(ECPerms.Registry.Group.home_group, 0)) - .build(); - homeNode.addChild(homeTpBuilder.build()); - homeNode.addChild(homeSetBuilder.build()); - homeNode.addChild(homeDeleteBuilder.build()); - homeNode.addChild(homeListBuilder.build()); - - rootNode.addChild(homeNode); - essentialCommandsRootNode.addChild(homeNode); - } - - - //Back - if (CONFIG.ENABLE_BACK.getValue()) { - LiteralArgumentBuilder backBuilder = CommandManager.literal("back"); - backBuilder - .requires(ECPerms.require(ECPerms.Registry.back, 0)) - .executes(new BackCommand()); - - LiteralCommandNode backNode = backBuilder.build(); - - rootNode.addChild(backNode); - essentialCommandsRootNode.addChild(backNode); - } - - //Warp - if (CONFIG.ENABLE_WARP.getValue()) { - LiteralArgumentBuilder warpBuilder = CommandManager.literal("warp"); - LiteralArgumentBuilder warpSetBuilder = CommandManager.literal("set"); - LiteralArgumentBuilder warpTpBuilder = CommandManager.literal("tp"); - LiteralArgumentBuilder warpDeleteBuilder = CommandManager.literal("delete"); - LiteralArgumentBuilder warpListBuilder = CommandManager.literal("list"); - - warpSetBuilder - .requires(ECPerms.require(ECPerms.Registry.warp_set, 4)) - .then(argument("warp_name", StringArgumentType.word()) - .executes(new WarpSetCommand())); - - warpTpBuilder - .requires(ECPerms.require(ECPerms.Registry.warp_tp, 0)) - .then(argument("warp_name", StringArgumentType.word()) - .suggests(WarpSuggestion.suggestedStrings()) - .executes(new WarpTpCommand())); - - warpDeleteBuilder - .requires(ECPerms.require(ECPerms.Registry.warp_delete, 4)) - .then(argument("warp_name", StringArgumentType.word()) - .suggests(WarpSuggestion.suggestedStrings()) - .executes(new WarpDeleteCommand())); - - warpListBuilder - .requires(ECPerms.require(ECPerms.Registry.warp_tp, 0)) - .executes(ListCommandFactory.create( - ECText.getInstance().get("cmd.warp.list.start"), - "warp tp", - (context) -> ManagerLocator.getInstance().getWorldDataManager().getWarpEntries() - )); - - - LiteralCommandNode warpNode = warpBuilder - .requires(ECPerms.requireAny(ECPerms.Registry.Group.warp_group, 0)) - .build(); - warpNode.addChild(warpTpBuilder.build()); - warpNode.addChild(warpSetBuilder.build()); - warpNode.addChild(warpDeleteBuilder.build()); - warpNode.addChild(warpListBuilder.build()); - - - rootNode.addChild(warpNode); - essentialCommandsRootNode.addChild(warpNode); +public final class EssentialCommandRegistry { + private EssentialCommandRegistry() {} + + public static void register(CommandDispatcher dispatcher, boolean dedicated) { + RootCommandNode rootNode = dispatcher.getRoot(); + + LiteralCommandNode essentialCommandsRootNode; + { + LiteralCommandNode ecInfoNode = CommandManager.literal("info") + .executes(new ModInfoCommand()) + .build(); + + essentialCommandsRootNode = CommandManager.literal("essentialcommands") + .executes(ecInfoNode.getCommand()) + .build(); + + essentialCommandsRootNode.addChild(ecInfoNode); + } + + var excludedTopLevelCommands = new HashSet<>(CONFIG.EXCLUDED_TOP_LEVEL_COMMANDS); + IConsumer> registerNode = CONFIG.REGISTER_TOP_LEVEL_COMMANDS + ? (node) -> { + if (!excludedTopLevelCommands.contains(node.getLiteral())) { + rootNode.addChild(node); } - - //Spawn - if (CONFIG.ENABLE_SPAWN.getValue()) { - LiteralArgumentBuilder spawnBuilder = CommandManager.literal("spawn"); - LiteralArgumentBuilder spawnSetBuilder = CommandManager.literal("set"); - LiteralArgumentBuilder spawnTpBuilder = CommandManager.literal("tp"); - - spawnSetBuilder - .requires(ECPerms.require(ECPerms.Registry.spawn_set, 4)) - .executes(new SpawnSetCommand()); - - SpawnCommand cmd = new SpawnCommand(); - spawnBuilder - .requires(ECPerms.require(ECPerms.Registry.spawn_tp, 0)) - .executes(cmd); - spawnTpBuilder - .requires(ECPerms.require(ECPerms.Registry.spawn_tp, 0)) - .executes(cmd); - - LiteralCommandNode spawnNode = spawnBuilder.build(); - spawnNode.addChild(spawnSetBuilder.build()); - spawnNode.addChild(spawnTpBuilder.build()); - - rootNode.addChild(spawnNode); - essentialCommandsRootNode.addChild(spawnNode); - } - - //Nickname - if (CONFIG.ENABLE_NICK.getValue()) { - LiteralArgumentBuilder nickBuilder = CommandManager.literal("nickname"); - LiteralArgumentBuilder nickSetBuilder = CommandManager.literal("set"); - LiteralArgumentBuilder nickClearBuilder = CommandManager.literal("clear"); - LiteralArgumentBuilder nickRevealBuilder = CommandManager.literal("reveal"); - - Predicate permissionSelf = ECPerms.require(ECPerms.Registry.nickname_self, 2); - Predicate permissionOther = ECPerms.require(ECPerms.Registry.nickname_others, 4); - nickSetBuilder.requires(permissionSelf) - .then(argument("nickname", TextArgumentType.text()) - .executes(new NicknameSetCommand()) - ).then(argument("target", EntityArgumentType.player()) - .requires(permissionOther) - .then(argument("nickname", TextArgumentType.text()) - .executes(new NicknameSetCommand()) - ).then(argument("nickname_placeholder_api", StringArgumentType.greedyString()) - .executes(NicknameSetCommand::runStringToText) - ) - ).then(argument("nickname_placeholder_api", StringArgumentType.greedyString()) - .executes(NicknameSetCommand::runStringToText) - ); - - nickClearBuilder - .requires(ECPerms.require(ECPerms.Registry.nickname_self, 2)) - .executes(new NicknameClearCommand()) - .then(argument("target", EntityArgumentType.player()) - .requires(ECPerms.require(ECPerms.Registry.nickname_others, 4)) - .executes(new NicknameClearCommand())); - - nickRevealBuilder - .requires(ECPerms.require(ECPerms.Registry.nickname_reveal, 4)) - .then(argument("player_nickname", StringArgumentType.word()) - .suggests(NicknamePlayersSuggestion.suggestedStrings()) - .executes(new RealNameCommand()) - ); - - LiteralCommandNode nickNode = nickBuilder - .requires(ECPerms.requireAny(ECPerms.Registry.Group.nickname_group, 2)) - .build(); - nickNode.addChild(nickSetBuilder.build()); - nickNode.addChild(nickClearBuilder.build()); - nickNode.addChild(nickRevealBuilder.build()); - - rootNode.addChild(nickNode); - essentialCommandsRootNode.addChild(nickNode); - } - - if (CONFIG.ENABLE_RTP.getValue()) { - LiteralCommandNode rtpNode = dispatcher.register( - CommandManager.literal("randomteleport") - .requires(ECPerms.require(ECPerms.Registry.randomteleport, 2)) - .executes(new RandomTeleportCommand()) - ); - - dispatcher.register(CommandManager.literal("rtp") - .requires(ECPerms.require(ECPerms.Registry.randomteleport, 2)) - .executes(new RandomTeleportCommand()) - ); - essentialCommandsRootNode.addChild(rtpNode); - - } - - if (CONFIG.ENABLE_FLY.getValue()) { - LiteralCommandNode flyNode = dispatcher.register( - CommandManager.literal("fly") - .requires(ECPerms.require(ECPerms.Registry.fly_self, 2)) - .executes(new FlyCommand()) - .then(argument("target_player", EntityArgumentType.player()) - .requires(ECPerms.require(ECPerms.Registry.fly_others, 4)) - .then(argument("flight_enabled", BoolArgumentType.bool()) - .executes(new FlyCommand())) - ) - ); - - essentialCommandsRootNode.addChild(flyNode); - } - - if (CONFIG.ENABLE_WORKBENCH.getValue()) { - LiteralCommandNode workbenchNode = dispatcher.register( - CommandManager.literal("workbench") - .requires(ECPerms.require(ECPerms.Registry.workbench, 0)) - .executes(new WorkbenchCommand()) - ); - - essentialCommandsRootNode.addChild(workbenchNode); - } - - if (CONFIG.ENABLE_ENDERCHEST.getValue()) { - LiteralCommandNode enderchestNode = dispatcher.register( - CommandManager.literal("enderchest") - .requires(ECPerms.require(ECPerms.Registry.enderchest, 0)) - .executes(new EnderchestCommand()) + essentialCommandsRootNode.addChild(node); + } + : essentialCommandsRootNode::addChild; + + if (CONFIG.ENABLE_TPA) { + registerNode.accept(CommandManager.literal("tpa") + .requires(ECPerms.require(ECPerms.Registry.tpa, 0)) + .then(CommandUtil.targetPlayerArgument() + .executes(new TeleportAskCommand())) + .build()); + + registerNode.accept(CommandManager.literal("tpcancel") + .requires(ECPerms.require(ECPerms.Registry.tpa, 0)) + .executes(new TeleportCancelCommand()) + .build()); + + registerNode.accept(CommandManager.literal("tpaccept") + .requires(ECPerms.require(ECPerms.Registry.tpaccept, 0)) + .executes(new TeleportAcceptCommand()::runDefault) + .then(CommandUtil.targetPlayerArgument() + .suggests(TeleportResponseSuggestion.STRING_SUGGESTIONS_PROVIDER) + .executes(new TeleportAcceptCommand())) + .build()); + + registerNode.accept(CommandManager.literal("tpdeny") + .requires(ECPerms.require(ECPerms.Registry.tpdeny, 0)) + .executes(new TeleportDenyCommand()::runDefault) + .then(CommandUtil.targetPlayerArgument() + .suggests(TeleportResponseSuggestion.STRING_SUGGESTIONS_PROVIDER) + .executes(new TeleportDenyCommand())) + .build()); + + registerNode.accept(CommandManager.literal("tpahere") + .requires(ECPerms.require(ECPerms.Registry.tpahere, 0)) + .then(CommandUtil.targetPlayerArgument() + .executes(new TeleportAskHereCommand())) + .build()); + } + + if (CONFIG.ENABLE_HOME) { + LiteralArgumentBuilder homeBuilder = CommandManager.literal("home"); + LiteralArgumentBuilder homeSetBuilder = CommandManager.literal("set"); + LiteralArgumentBuilder homeTpBuilder = CommandManager.literal("tp"); + LiteralArgumentBuilder homeTpOtherBuilder = CommandManager.literal("tp_other"); + LiteralArgumentBuilder homeTpOfflineBuilder = CommandManager.literal("tp_offline"); + LiteralArgumentBuilder homeDeleteBuilder = CommandManager.literal("delete"); + LiteralArgumentBuilder homeListBuilder = CommandManager.literal("list"); + LiteralArgumentBuilder homeListOfflineBuilder = CommandManager.literal("list_offline"); + + homeSetBuilder + .requires(ECPerms.require(ECPerms.Registry.home_set, 0)) + .then(argument("home_name", StringArgumentType.word()) + .executes(new HomeSetCommand())); + + homeTpBuilder + .requires(ECPerms.require(ECPerms.Registry.home_tp, 0)) + .executes(new HomeCommand()::runDefault) + .then(argument("home_name", StringArgumentType.word()) + .suggests(HomeCommand.Suggestion.LIST_SUGGESTION_PROVIDER) + .executes(new HomeCommand())); + + homeTpOtherBuilder + .requires(ECPerms.require(ECPerms.Registry.home_tp_others, 2)) + .then(argument("target_player", EntityArgumentType.player()) + .then(argument("home_name", StringArgumentType.word()) + .suggests(HomeTeleportOtherCommand.Suggestion.LIST_SUGGESTION_PROVIDER) + .executes(new HomeTeleportOtherCommand()))); + + homeTpOfflineBuilder + .requires(ECPerms.require(ECPerms.Registry.home_tp_others, 2)) + .then(argument("target_player", StringArgumentType.word()) + .then(argument("home_name", StringArgumentType.word()) + .executes(new HomeTeleportOtherCommand()::runOfflinePlayer))); + + homeDeleteBuilder + .requires(ECPerms.require(ECPerms.Registry.home_delete, 0)) + .then(argument("home_name", StringArgumentType.word()) + .suggests(HomeCommand.Suggestion.LIST_SUGGESTION_PROVIDER) + .executes(new HomeDeleteCommand())); + + homeListBuilder + .requires(ECPerms.require(ECPerms.Registry.home_tp, 0)) + .executes(ListCommandFactory.create( + ECText.getInstance().getString("cmd.home.list.start"), + "home tp", + HomeCommand.Suggestion::getSuggestionEntries)); + + homeListOfflineBuilder + .requires(ECPerms.require(ECPerms.Registry.home_tp_others, 2)) + .then(argument("target_player", StringArgumentType.word()) + .executes(HomeTeleportOtherCommand::runListOffline)); + + LiteralCommandNode homeNode = homeBuilder + .requires(ECPerms.requireAny(ECPerms.Registry.Group.home_group, 0)) + .build(); + homeNode.addChild(homeTpBuilder.build()); + homeNode.addChild(homeTpOtherBuilder.build()); + homeNode.addChild(homeTpOfflineBuilder.build()); + homeNode.addChild(homeSetBuilder.build()); + homeNode.addChild(homeDeleteBuilder.build()); + homeNode.addChild(homeListBuilder.build()); + homeNode.addChild(homeListOfflineBuilder.build()); + + registerNode.accept(homeNode); + } + + //Back + if (CONFIG.ENABLE_BACK) { + LiteralArgumentBuilder backBuilder = CommandManager.literal("back"); + backBuilder + .requires(ECPerms.require(ECPerms.Registry.back, 0)) + .executes(new BackCommand()); + + LiteralCommandNode backNode = backBuilder.build(); + + rootNode.addChild(backNode); + essentialCommandsRootNode.addChild(backNode); + } + + //Warp + if (CONFIG.ENABLE_WARP) { + LiteralArgumentBuilder warpBuilder = CommandManager.literal("warp"); + LiteralArgumentBuilder warpSetBuilder = CommandManager.literal("set"); + LiteralArgumentBuilder warpTpBuilder = CommandManager.literal("tp"); + LiteralArgumentBuilder warpTpOtherBuilder = CommandManager.literal("tp_other"); + LiteralArgumentBuilder warpDeleteBuilder = CommandManager.literal("delete"); + LiteralArgumentBuilder warpListBuilder = CommandManager.literal("list"); + + warpSetBuilder + .requires(ECPerms.require(ECPerms.Registry.warp_set, 4)) + .then(argument("warp_name", StringArgumentType.word()) + .executes(new WarpSetCommand()) + .then(argument("requires_permission", BoolArgumentType.bool()) + .executes(new WarpSetCommand()))); + + warpTpBuilder + .requires(ECPerms.require(ECPerms.Registry.warp_tp, 0)) + .then(argument("warp_name", StringArgumentType.word()) + .suggests(WarpSuggestion.STRING_SUGGESTIONS_PROVIDER) + .executes(new WarpTpCommand())); + + warpTpOtherBuilder + .requires(ECPerms.require(ECPerms.Registry.home_tp_others, 2)) + .then(argument("target_player", EntityArgumentType.player()) + .then(argument("warp_name", StringArgumentType.word()) + .suggests(WarpSuggestion.STRING_SUGGESTIONS_PROVIDER) + .executes(new WarpTpCommand()::runOther))); + + warpDeleteBuilder + .requires(ECPerms.require(ECPerms.Registry.warp_delete, 4)) + .then(argument("warp_name", StringArgumentType.word()) + .suggests(WarpSuggestion.STRING_SUGGESTIONS_PROVIDER) + .executes(new WarpDeleteCommand())); + + warpListBuilder + .requires(ECPerms.require(ECPerms.Registry.warp_tp, 0)) + .executes(ListCommandFactory.create( + ECText.getInstance().getString("cmd.warp.list.start"), + "warp tp", + (context) -> ManagerLocator.getInstance().getWorldDataManager().getWarpEntries() + )); + + LiteralCommandNode warpNode = warpBuilder + .requires(ECPerms.requireAny(ECPerms.Registry.Group.warp_group, 0)) + .build(); + warpNode.addChild(warpTpBuilder.build()); + warpNode.addChild(warpTpOtherBuilder.build()); + warpNode.addChild(warpSetBuilder.build()); + warpNode.addChild(warpDeleteBuilder.build()); + warpNode.addChild(warpListBuilder.build()); + + registerNode.accept(warpNode); + } + + //Spawn + if (CONFIG.ENABLE_SPAWN) { + LiteralArgumentBuilder spawnBuilder = CommandManager.literal("spawn"); + LiteralArgumentBuilder spawnSetBuilder = CommandManager.literal("set"); + LiteralArgumentBuilder spawnTpBuilder = CommandManager.literal("tp"); + + spawnSetBuilder + .requires(ECPerms.require(ECPerms.Registry.spawn_set, 4)) + .executes(new SpawnSetCommand()); + + SpawnCommand cmd = new SpawnCommand(); + spawnBuilder + .requires(ECPerms.require(ECPerms.Registry.spawn_tp, 0)) + .executes(cmd); + spawnTpBuilder + .requires(ECPerms.require(ECPerms.Registry.spawn_tp, 0)) + .executes(cmd); + + LiteralCommandNode spawnNode = spawnBuilder.build(); + spawnNode.addChild(spawnSetBuilder.build()); + spawnNode.addChild(spawnTpBuilder.build()); + + registerNode.accept(spawnNode); + } + + if (CONFIG.ENABLE_NICK) { + LiteralArgumentBuilder nickBuilder = CommandManager.literal("nickname"); + LiteralArgumentBuilder nickSetBuilder = CommandManager.literal("set"); + LiteralArgumentBuilder nickClearBuilder = CommandManager.literal("clear"); + LiteralArgumentBuilder nickRevealBuilder = CommandManager.literal("reveal"); + + Predicate permissionSelf = ECPerms.require(ECPerms.Registry.nickname_self, 2); + Predicate permissionOther = ECPerms.require(ECPerms.Registry.nickname_others, 2); + nickSetBuilder.requires(permissionSelf) + .then(argument("nickname", TextArgumentType.text()) + .executes(new NicknameSetCommand()) + ).then(CommandUtil.targetPlayerArgument() + .requires(permissionOther) + .then(argument("nickname", TextArgumentType.text()) + .executes(new NicknameSetCommand()) + ).then(argument("nickname_placeholder_api", StringArgumentType.greedyString()) + .executes(NicknameSetCommand::runStringToText) + ) + ) + .then(argument("nickname_placeholder_api", StringArgumentType.greedyString()) + .executes(NicknameSetCommand::runStringToText) + ); + + nickClearBuilder + .requires(ECPerms.require(ECPerms.Registry.nickname_self, 2)) + .executes(new NicknameClearCommand()) + .then(CommandUtil.targetPlayerArgument() + .requires(ECPerms.require(ECPerms.Registry.nickname_others, 2)) + .executes(new NicknameClearCommand())); + + nickRevealBuilder + .requires(ECPerms.require(ECPerms.Registry.nickname_reveal, 2)) + .then(argument("player_nickname", StringArgumentType.word()) + .suggests(NicknamePlayersSuggestion.STRING_SUGGESTIONS_PROVIDER) + .executes(new RealNameCommand()) + ); + + LiteralCommandNode nickNode = nickBuilder + .requires(ECPerms.requireAny(ECPerms.Registry.Group.nickname_group, 2)) + .build(); + nickNode.addChild(nickSetBuilder.build()); + nickNode.addChild(nickClearBuilder.build()); + nickNode.addChild(nickRevealBuilder.build()); + + registerNode.accept(nickNode); + } + + if (CONFIG.ENABLE_RTP) { + registerNode.accept(CommandManager.literal("randomteleport") + .requires(ECPerms.require(ECPerms.Registry.randomteleport, 2)) + .executes(new RandomTeleportCommand()) + .build()); + + registerNode.accept(CommandManager.literal("rtp") + .requires(ECPerms.require(ECPerms.Registry.randomteleport, 2)) + .executes(new RandomTeleportCommand()) + .build() + ); + } + + if (CONFIG.ENABLE_FLY) { + registerNode.accept(CommandManager.literal("fly") + .requires(ECPerms.require(ECPerms.Registry.fly_self, 2)) + .executes(new FlyCommand()) + .then(CommandUtil.targetPlayerArgument() + .requires(ECPerms.require(ECPerms.Registry.fly_others, 2)) + .then(argument("flight_enabled", BoolArgumentType.bool()) + .executes(new FlyCommand()))) + .build()); + } + + if (CONFIG.ENABLE_INVULN) { + registerNode.accept( + CommandManager.literal("invuln") + .requires(ECPerms.require(ECPerms.Registry.invuln_self, 2)) + .executes(new InvulnCommand()) + .then(CommandUtil.targetPlayerArgument() + .requires(ECPerms.require(ECPerms.Registry.invuln_others, 2)) + .then(argument("invuln_enabled", BoolArgumentType.bool()) + .executes(new InvulnCommand()))) + .build()); + } + + if (CONFIG.ENABLE_WORKBENCH) { + registerNode.accept(CommandManager.literal("workbench") + .requires(ECPerms.require(ECPerms.Registry.workbench, 0)) + .executes(new WorkbenchCommand()) + .build()); + + registerNode.accept(CommandManager.literal("stonecutter") + .requires(ECPerms.require(ECPerms.Registry.stonecutter, 0)) + .executes(new StonecutterCommand()) + .build()); + + registerNode.accept(CommandManager.literal("grindstone") + .requires(ECPerms.require(ECPerms.Registry.grindstone, 0)) + .executes(new GrindstoneCommand()) + .build()); + } + + if (CONFIG.ENABLE_ANVIL) { + registerNode.accept(CommandManager.literal("anvil") + .requires(ECPerms.require(ECPerms.Registry.anvil, 0)) + .executes(new AnvilCommand()) + .build()); + } + + if (CONFIG.ENABLE_ENDERCHEST) { + registerNode.accept(CommandManager.literal("enderchest") + .requires(ECPerms.require(ECPerms.Registry.enderchest, 0)) + .executes(new EnderchestCommand()) + .build()); + } + + if (CONFIG.ENABLE_WASTEBIN) { + registerNode.accept(CommandManager.literal("wastebin") + .requires(ECPerms.require(ECPerms.Registry.wastebin, 0)) + .executes(new WastebinCommand()) + .build()); + } + + if (CONFIG.ENABLE_TOP) { + registerNode.accept(CommandManager.literal("top") + .requires(ECPerms.require(ECPerms.Registry.top, 2)) + .executes(new TopCommand()) + .build()); + } + + if (CONFIG.ENABLE_GAMETIME) { + registerNode.accept(CommandManager.literal("gametime") + .requires(ECPerms.require(ECPerms.Registry.gametime, 0)) + .executes(new GametimeCommand()) + .build()); + } + + if (CONFIG.ENABLE_AFK) { + registerNode.accept(CommandManager.literal("afk") + .requires(ECPerms.require(ECPerms.Registry.afk, 0)) + .executes(new AfkCommand()) + .build()); + } + + if (CONFIG.ENABLE_BED) { + registerNode.accept(CommandManager.literal("bed") + .requires(ECPerms.require(ECPerms.Registry.bed, 0)) + .executes(new BedCommand()) + .build()); + } + + registerNode.accept(CommandManager.literal("lastPos") + .requires(ECPerms.require("essentialcommands.admin.lastpos", 2)) + .then(argument("target_player", StringArgumentType.word()) + .executes((context) -> { + var targetPlayerName = StringArgumentType.getString(context, "target_player"); + ManagerLocator.getInstance() + .getOfflinePlayerRepo() + .getOfflinePlayerByNameAsync(targetPlayerName) + .whenComplete((playerEntity, err) -> { + if (playerEntity == null) { + context.getSource().sendError(Text.of("No player with the specified name found.")); + return; + } + context.getSource().sendFeedback( + Text.of(playerEntity.getPos().toString()), + EssentialCommands.CONFIG.BROADCAST_TO_OPS); + }); + return 1; + })) + .build()); + + if (CONFIG.ENABLE_DAY) { + registerNode.accept(CommandManager.literal("day") + .requires(ECPerms.require(ECPerms.Registry.time_set_day, 2)) + .executes((context) -> { + var source = context.getSource(); + var playerData = PlayerData.accessFromContextOrThrow(context); + var world = source.getServer().getOverworld(); + if (world.isDay()) { + playerData.sendCommandFeedback("cmd.day.error.already_daytime"); + return -1; + } + var time = world.getTimeOfDay(); + var timeToDay = 24000L - time % 24000L; + + world.setTimeOfDay(time + timeToDay); + playerData.sendCommandFeedback("cmd.day.feedback"); + return 1; + }) + .build()); + } + + if (CONFIG.ENABLE_RULES) { + registerNode.accept(CommandManager.literal("rules") + .requires(ECPerms.require(ECPerms.Registry.rules, 0)) + .executes(RulesCommand::run) + .then(literal("reload") + .requires(ECPerms.require(ECPerms.Registry.rules_reload, 4)) + .executes(RulesCommand::reloadCommand)) + .build()); + } + + var profileNode = ProfileCommand.buildNode(); + essentialCommandsRootNode.addChild(profileNode); + + LiteralCommandNode configNode = CommandManager.literal("config") + .requires(ECPerms.requireAny(ECPerms.Registry.Group.config_group, 4)) + .then(CommandManager.literal("reload") + .executes((context) -> { + BACKING_CONFIG.loadOrCreateProperties(); + var player = context.getSource().getPlayer(); + var ecText = player != null ? ECText.access(player) : ECText.getInstance(); + context.getSource().sendFeedback( + ecText.getText("cmd.config.reload"), + true ); - - essentialCommandsRootNode.addChild(enderchestNode); - } - - if (CONFIG.ENABLE_TOP.getValue()) { - LiteralCommandNode topNode = dispatcher.register( - CommandManager.literal("top") - .requires(ECPerms.require(ECPerms.Registry.top, 2)) - .executes(new TopCommand()) + return 1; + }).requires( + ECPerms.require(ECPerms.Registry.config_reload, 4) + ).build()) + .then(CommandManager.literal("display") + .requires(ECPerms.require(ECPerms.Registry.config_reload, 4)) + .executes((context) -> { + BACKING_CONFIG.loadOrCreateProperties(); + context.getSource().sendFeedback( + BACKING_CONFIG.stateAsText(), + false ); - - essentialCommandsRootNode.addChild(topNode); - } - - LiteralCommandNode configNode = CommandManager.literal("config") - .requires(ECPerms.requireAny(ECPerms.Registry.Group.config_group, 4)) - .then(CommandManager.literal("reload") - .executes((context) -> { - CONFIG.loadOrCreateProperties(); - context.getSource().sendFeedback( - TextUtil.concat( - ECText.getInstance().getText("essentialcommands.fullprefix"), - ECText.getInstance().getText("cmd.config.reload") - ), - true - ); - return 1; - }).requires( - ECPerms.require(ECPerms.Registry.config_reload, 4) - ).build()) - .then(CommandManager.literal("display") - .requires(ECPerms.require(ECPerms.Registry.config_reload, 4)) - .executes((context) -> { - CONFIG.loadOrCreateProperties(); - context.getSource().sendFeedback( - CONFIG.stateAsText(), - false - ); - return 1; - }) - .then(CommandManager.argument("config_property", StringArgumentType.word()) - .suggests(ListSuggestion.of(CONFIG::getPublicFieldNames)) - .executes(context -> { - try { - context.getSource().sendFeedback(CONFIG.getFieldValueAsText( - StringArgumentType.getString(context, "config_property") - ), false); - } catch (NoSuchFieldException e) { - e.printStackTrace(); - } - - return 1; - }) - ) - ).build(); - - essentialCommandsRootNode.addChild(configNode); - - if (CONFIG.ENABLE_ESSENTIALSX_CONVERT.getValue()) { - essentialCommandsRootNode.addChild(CommandManager.literal("convertEssentialsXPlayerHomes") - .requires(source -> source.hasPermissionLevel(4)) - .executes((source) -> { - Path mcDir = source.getSource().getServer().getRunDirectory().toPath(); - try { - EssentialsXParser.convertPlayerDataDir( - mcDir.resolve("plugins/Essentials/userdata").toFile(), - mcDir.resolve("world/modplayerdata").toFile(), - source.getSource().getServer() - ); - source.getSource().sendFeedback(new LiteralText("Successfully converted data dirs."), CONFIG.BROADCAST_TO_OPS.getValue()); - } catch (NotDirectoryException | FileNotFoundException e) { - e.printStackTrace(); - } - return 0; - }).build() + return 1; + }) + .then(CommandManager.argument("config_property", StringArgumentType.word()) + .suggests(ListSuggestion.of(BACKING_CONFIG::getPublicFieldNames)) + .executes(context -> { + try { + context.getSource().sendFeedback(BACKING_CONFIG.getFieldValueAsText( + StringArgumentType.getString(context, "config_property") + ), false); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } + + return 1; + }) + ) + ).build(); + + essentialCommandsRootNode.addChild(configNode); + + if (CONFIG.ENABLE_ESSENTIALSX_CONVERT) { + essentialCommandsRootNode.addChild(CommandManager.literal("convertEssentialsXPlayerHomes") + .requires(source -> source.hasPermissionLevel(4)) + .executes((source) -> { + Path mcDir = source.getSource().getServer().getRunDirectory().toPath(); + try { + EssentialsXParser.convertPlayerDataDir( + mcDir.resolve("plugins/Essentials/userdata").toFile(), + mcDir.resolve("world/modplayerdata").toFile(), + source.getSource().getServer() + ); + source.getSource().sendFeedback(TextUtil.literal("Successfully converted data dirs."), CONFIG.BROADCAST_TO_OPS); + } catch (NotDirectoryException | FileNotFoundException e) { + e.printStackTrace(); + } + return 0; + }).build() + ); + essentialCommandsRootNode.addChild(CommandManager.literal("convertEssentialsXWarps") + .requires(source -> source.hasPermissionLevel(4)) + .executes((source) -> { + Path mcDir = source.getSource().getServer().getRunDirectory().toPath(); + EssentialsConvertor.warpConvert( + source.getSource().getServer(), + mcDir.resolve("plugins/Essentials/warps").toFile() ); - } + source.getSource().sendFeedback(TextUtil.literal("Successfully converted warps."), CONFIG.BROADCAST_TO_OPS); + return 0; + }).build() + ); -// essentialCommandsRootNode.addChild(CommandManager.literal("test") -// .executes(configReloadNode.getCommand()) -// .build() -// ); + } - rootNode.addChild(essentialCommandsRootNode); - } - ); + rootNode.addChild(essentialCommandsRootNode); } -} \ No newline at end of file +} diff --git a/src/main/java/com/fibermc/essentialcommands/EssentialCommands.java b/src/main/java/com/fibermc/essentialcommands/EssentialCommands.java index 4df677a9..40efdf51 100644 --- a/src/main/java/com/fibermc/essentialcommands/EssentialCommands.java +++ b/src/main/java/com/fibermc/essentialcommands/EssentialCommands.java @@ -1,54 +1,81 @@ package com.fibermc.essentialcommands; -//import net.fabricmc.api.DedicatedServerModInitializer; +import java.io.IOException; +import java.nio.file.Path; +import com.fibermc.essentialcommands.commands.RulesCommand; import com.fibermc.essentialcommands.config.EssentialCommandsConfig; +import com.fibermc.essentialcommands.config.EssentialCommandsConfigSnapshot; +import com.fibermc.essentialcommands.text.ECText; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.loader.api.FabricLoader; +import net.fabricmc.loader.api.ModContainer; import net.fabricmc.loader.api.metadata.ModMetadata; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import java.nio.file.Path; +import dev.jpcode.eccore.util.TimeUtil; public final class EssentialCommands implements ModInitializer { - public static final ModMetadata MOD_METADATA = FabricLoader.getInstance().getModContainer("essential_commands").get().getMetadata(); - public static final String MOD_ID = MOD_METADATA.getId(); - public static Logger LOGGER = LogManager.getLogger("EssentialCommands"); - public static final EssentialCommandsConfig CONFIG = new EssentialCommandsConfig( - Path.of("./config/EssentialCommands.properties"), - "Essential Commands Config", - "https://github.com/John-Paul-R/Essential-Commands/wiki/Config-Documentation" - ); - public static void log(Level level, String message) { - final String logPrefix = "[EssentialCommands]: "; - LOGGER.log(level, logPrefix.concat(message)); - } + private static final String MOD_CONTAINER_ID = "essential_commands"; + public static final ModMetadata MOD_METADATA = FabricLoader.getInstance().getModContainer(MOD_CONTAINER_ID).map(ModContainer::getMetadata).orElse(null); + public static final String MOD_ID = MOD_METADATA == null ? "essentialcommands | ERR - NO MOD DATA" : MOD_METADATA.getId(); + public static final Logger LOGGER = LogManager.getLogger("EssentialCommands"); + public static final EssentialCommandsConfig BACKING_CONFIG = new EssentialCommandsConfig( + Path.of("./config/EssentialCommands.properties"), + "Essential Commands Config", + "https://github.com/John-Paul-R/Essential-Commands/wiki/Config-Documentation" + ); + @SuppressWarnings("checkstyle:StaticVariableName") + public static EssentialCommandsConfigSnapshot CONFIG = EssentialCommandsConfigSnapshot.create(BACKING_CONFIG); + public static void log(Level level, String message, Object... args) { + final String logPrefix = "[EssentialCommands]: "; + LOGGER.log(level, logPrefix.concat(message), args); + } @Override - public void onInitialize/*Server*/() { - log(Level.INFO, "Mod Load Initiated."); + public void onInitialize() { + if (MOD_METADATA == null) { + log(Level.WARN, "failed to load mod metadata using mod container id '{}' ", MOD_CONTAINER_ID); + } + + log(Level.INFO, "Mod Load Initiated."); + + BACKING_CONFIG.registerLoadHandler((backingConfig) -> CONFIG = EssentialCommandsConfigSnapshot.create(backingConfig)); + BACKING_CONFIG.loadOrCreateProperties(); + + ECPlaceholderRegistry.register(); + ECAbilitySources.init(); - //Load Preferences - CONFIG.loadOrCreateProperties(); + ManagerLocator managers = ManagerLocator.getInstance(); + managers.init(); + ServerLifecycleEvents.SERVER_STARTING.register((server) -> { + ECText.init(server); + TimeUtil.init(server); + managers.onServerStart(server); + ECPerms.init(); // ECPerms must start after WorldDataManager at present (for warps). - //init mod stuff - ManagerLocator managers = ManagerLocator.getInstance(); - managers.init(); - ServerLifecycleEvents.SERVER_STARTING.register(managers::onServerStart); + if (CONFIG.ENABLE_RULES) { + try { + RulesCommand.reload(server); + } catch (IOException e) { + LOGGER.error("An error occurred while loading EssentialCommands rules file."); + e.printStackTrace(); + } + } + }); - ECPerms.init(); - - //Register Mod - EssentialCommandRegistry.register(); + CommandRegistrationCallback.EVENT.register(EssentialCommandRegistry::register); - if (CONFIG.CHECK_FOR_UPDATES.getValue()) { - Updater.checkForUpdates(); - } + if (CONFIG.CHECK_FOR_UPDATES) { + Updater.checkForUpdates(); + } - log(Level.INFO, "Mod Load Complete."); - } + log(Level.INFO, "Mod Load Complete."); + } } diff --git a/src/main/java/com/fibermc/essentialcommands/ManagerLocator.java b/src/main/java/com/fibermc/essentialcommands/ManagerLocator.java index 6f963cf7..a057a3cc 100644 --- a/src/main/java/com/fibermc/essentialcommands/ManagerLocator.java +++ b/src/main/java/com/fibermc/essentialcommands/ManagerLocator.java @@ -1,43 +1,44 @@ package com.fibermc.essentialcommands; +import com.fibermc.essentialcommands.commands.suggestions.OfflinePlayerRepo; +import com.fibermc.essentialcommands.playerdata.PlayerDataManager; +import com.fibermc.essentialcommands.teleportation.TeleportManager; + import net.minecraft.server.MinecraftServer; import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; -public class ManagerLocator { +public final class ManagerLocator { private PlayerDataManager playerDataManager; - private TeleportRequestManager tpManager; + private TeleportManager tpManager; private WorldDataManager worldDataManager; + private OfflinePlayerRepo offlinePlayerRepo; - public static ManagerLocator INSTANCE; + public static ManagerLocator instance; - private ManagerLocator() { - INSTANCE = this; - } + private ManagerLocator() {} public static ManagerLocator getInstance() { - if (INSTANCE != null) - return INSTANCE; - return new ManagerLocator(); - }; - - static boolean playerDataEnabled() { - return ( - CONFIG.ENABLE_HOME.getValue() || - CONFIG.ENABLE_TPA.getValue() || - CONFIG.ENABLE_BACK.getValue() || - CONFIG.ENABLE_WARP.getValue() || - CONFIG.ENABLE_SPAWN.getValue() || - CONFIG.ENABLE_NICK.getValue() - ); - + if (instance != null) { + return instance; + } + return instance = new ManagerLocator(); } - static boolean teleportRequestEnabled() { - return (CONFIG.ENABLE_TPA.getValue()); + + public static boolean playerDataEnabled() { + return CONFIG.ENABLE_HOME + || CONFIG.ENABLE_TPA + || CONFIG.ENABLE_BACK + || CONFIG.ENABLE_WARP + || CONFIG.ENABLE_SPAWN + || CONFIG.ENABLE_NICK + || CONFIG.ENABLE_AFK + ; } - static boolean warpEnabled() { - return (CONFIG.ENABLE_TPA.getValue() || CONFIG.ENABLE_SPAWN.getValue()); + + public static boolean teleportRequestEnabled() { + return (CONFIG.ENABLE_TPA); } public void init() { @@ -45,32 +46,30 @@ public void init() { PlayerDataManager.init(); } if (teleportRequestEnabled()) { - TeleportRequestManager.init(); + TeleportManager.init(); } } public void onServerStart(MinecraftServer server) { - if (playerDataEnabled()) { - this.playerDataManager = new PlayerDataManager(); - } - if (teleportRequestEnabled()) { - this.tpManager = new TeleportRequestManager(this.playerDataManager); - } - if (warpEnabled()) { - this.worldDataManager = new WorldDataManager(); - this.worldDataManager.onServerStart(server); - } + this.playerDataManager = PlayerDataManager.getInstance(); + this.tpManager = TeleportManager.getInstance(); + this.worldDataManager = WorldDataManager.createForServer(server); + this.offlinePlayerRepo = new OfflinePlayerRepo(server); } public PlayerDataManager getPlayerDataManager() { return playerDataManager; } - public TeleportRequestManager getTpManager() { + public TeleportManager getTpManager() { return tpManager; } public WorldDataManager getWorldDataManager() { return worldDataManager; } + + public OfflinePlayerRepo getOfflinePlayerRepo() { + return offlinePlayerRepo; + } } diff --git a/src/main/java/com/fibermc/essentialcommands/NamedLocationStorage.java b/src/main/java/com/fibermc/essentialcommands/NamedLocationStorage.java deleted file mode 100644 index 6310f330..00000000 --- a/src/main/java/com/fibermc/essentialcommands/NamedLocationStorage.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.fibermc.essentialcommands; - -import com.fibermc.essentialcommands.commands.exceptions.ECExceptions; -import com.fibermc.essentialcommands.types.MinecraftLocation; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtElement; -import net.minecraft.nbt.NbtList; - -import java.util.HashMap; - -public class NamedLocationStorage extends HashMap implements NbtSerializable { - - public NamedLocationStorage() { - super(); - } - - public NamedLocationStorage(NbtCompound nbt) { - this(); - loadNbt(nbt); - } - - @Override - public NbtCompound writeNbt(NbtCompound nbt) { - this.forEach((key, value) -> { - nbt.put(key, value.asNbt()); - }); - - return nbt; - } - - /** - * - * @param nbt NbtCompound or NbtList. (Latter is deprecated) - */ - public void loadNbt(NbtElement nbt) { - if (nbt.getType() == 9) { - // Legacy format - NbtList homesNbtList = (NbtList)nbt; - for (NbtElement t : homesNbtList) { - NbtCompound homeTag = (NbtCompound) t; - super.put(homeTag.getString("homeName"), new MinecraftLocation(homeTag)); - } - } else { - NbtCompound nbtCompound = (NbtCompound) nbt; - nbtCompound.getKeys().forEach((key) -> { - super.put(key, new MinecraftLocation(nbtCompound.getCompound(key))); - }); - } - - } - - public MinecraftLocation putCommand(String name, MinecraftLocation location) throws CommandSyntaxException { - if (this.get(name) == null) { - return super.put(name, location); - } else { - throw ECExceptions.keyExists().create(name); - } - } - -} diff --git a/src/main/java/com/fibermc/essentialcommands/PlayerData.java b/src/main/java/com/fibermc/essentialcommands/PlayerData.java deleted file mode 100644 index cdaeec0c..00000000 --- a/src/main/java/com/fibermc/essentialcommands/PlayerData.java +++ /dev/null @@ -1,345 +0,0 @@ -package com.fibermc.essentialcommands; - -import com.fibermc.essentialcommands.types.MinecraftLocation; -import com.fibermc.essentialcommands.util.TextUtil; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import io.github.ladysnake.pal.Pal; -import io.github.ladysnake.pal.VanillaAbilities; -import net.minecraft.entity.player.PlayerAbilities; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtElement; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.HoverEvent; -import net.minecraft.text.LiteralText; -import net.minecraft.text.MutableText; -import net.minecraft.text.Text; -import net.minecraft.util.Formatting; -import net.minecraft.util.Util; -import net.minecraft.world.PersistentState; - -import java.io.File; -import java.util.*; - -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; - -public class PlayerData extends PersistentState { - - // ServerPlayerEntity - private ServerPlayerEntity player; - private UUID pUuid; - private final File saveFile; - - // TELEPORT - // Remaining time before current tp Ask (sent by this player) expires. - private int tpTimer; - // Target of tpAsk - private TeleportRequest teleportRequest; - - // players that have Asked to tp to this player - // This list exists for autofilling the 'tpaccept' command - private final LinkedHashMap incomingTeleportRequests; - - // HOMES - NamedLocationStorage homes; - private MinecraftLocation previousLocation; - private int tpCooldown; - - // Nickname - private Text nickname; - private MutableText fullNickname; - - // RTP Cooldown - private int rtpNextUsableTime; - - public PlayerData(ServerPlayerEntity player, File saveFile) { - this.player = player; - this.pUuid = player.getUuid(); - this.saveFile = saveFile; - tpTimer = -1; - incomingTeleportRequests = new LinkedHashMap<>(); - homes = new NamedLocationStorage(); - } - - /** - * DO NOT USE FOR LOGGED-IN PLAYERS. - * This constructor should ONLY be used for temporarily - * handling data of offline players. - * - * getPlayer() will always return null on an instance created in this fashion, - * and any operations that would require a ServerPlayerEntity will fail. - * - * @param playerUuid UUID of the player whose data we want to grab or modify. - * @param homes NamedLocationStorage of the player's homes (fills field) - * @param saveFile The save file for this PlayerData instance. - */ - public PlayerData(UUID playerUuid, NamedLocationStorage homes, File saveFile) { - this.pUuid = playerUuid; - this.saveFile = saveFile; - tpTimer = -1; - incomingTeleportRequests = new LinkedHashMap<>(); - this.homes = homes; - } - - - public int getTpTimer() { - return tpTimer; - } - - public void setTpTimer(int tpTimer) { - this.tpTimer = tpTimer; - } - - public void tickTpTimer() { - tpTimer--; - } - - public TeleportRequest getSentTeleportRequest() { - return teleportRequest; - } - - public void setSentTeleportRequest(TeleportRequest request) { - this.teleportRequest = request; - } - - public LinkedHashMap getIncomingTeleportRequests() { - return incomingTeleportRequests; - } - - public TeleportRequest getIncomingTeleportRequest(UUID tpAsker) { - return incomingTeleportRequests.get(tpAsker); - } - - public void addIncomingTeleportRequest(TeleportRequest teleportRequest) { - this.incomingTeleportRequests.put(teleportRequest.getSenderPlayer().getUuid(), teleportRequest); - } - - public void removeIncomingTeleportRequest(UUID tpAsker) { - this.incomingTeleportRequests.remove(tpAsker); - } - - public ServerPlayerEntity getPlayer() { - return player; - } - - // Homes - public int addHome(String homeName, MinecraftLocation minecraftLocation) throws CommandSyntaxException { - int outCode = 0; - int playerMaxHomes = ECPerms.getHighestNumericPermission(this.player.getCommandSource(), ECPerms.Registry.Group.home_limit_group); - if (this.homes.size() < playerMaxHomes) { - homes.putCommand(homeName, minecraftLocation); - this.markDirty(); - outCode = 1; - } else { - this.sendError(TextUtil.concat( - ECText.getInstance().getText("cmd.home.feedback.1").setStyle(CONFIG.FORMATTING_ERROR.getValue()), - new LiteralText(homeName).setStyle(CONFIG.FORMATTING_ACCENT.getValue()), - ECText.getInstance().getText("cmd.home.set.error.limit.2").setStyle(CONFIG.FORMATTING_ERROR.getValue()), - new LiteralText(String.valueOf(playerMaxHomes)).setStyle(CONFIG.FORMATTING_ACCENT.getValue()), - ECText.getInstance().getText("cmd.home.set.error.limit.3").setStyle(CONFIG.FORMATTING_ERROR.getValue()) - )); - } - - return outCode; - } - - public void sendError(Text message) { - this.player.sendSystemMessage((new LiteralText("")).append(message).formatted(Formatting.RED), Util.NIL_UUID); - } - - public Set getHomeNames() { - return homes.keySet(); - } - - public Set> getHomeEntries() { - return homes.entrySet(); - } - - public MinecraftLocation getHomeLocation(String homeName) { - return homes.get(homeName); - } - - public void fromNbt(NbtCompound tag) { - NbtCompound dataTag = tag.getCompound("data"); - this.pUuid = dataTag.getUuid("playerUuid"); - - NamedLocationStorage homes = new NamedLocationStorage(); - NbtElement homesTag = dataTag.get("homes"); - if (homesTag != null) { - homes.loadNbt(homesTag); - } - this.homes = homes; - - if (dataTag.contains("nickname")){ - this.nickname = Text.Serializer.fromJson(dataTag.getString("nickname")); - try { - reloadFullNickname(); - } catch (NullPointerException ignore) { - EssentialCommands.LOGGER.warn("Could not refresh player full nickanme, as ServerPlayerEntity was null in PlayerData."); - } - } - - if (this.player != null) { - updatePlayer(this.player); - } - - } - - @Override - public NbtCompound writeNbt(NbtCompound tag) { - tag.putUuid("playerUuid", pUuid); - - NbtCompound homesNbt = new NbtCompound(); - homes.writeNbt(homesNbt); - tag.put("homes", homesNbt); - - tag.putString("nickname", Text.Serializer.toJson(nickname)); - - return tag; - } - - public void setPreviousLocation(MinecraftLocation location) { - this.previousLocation = location; - } - - public MinecraftLocation getPreviousLocation() { - return this.previousLocation; - } - - public boolean removeHome(String homeName) { - //returns false if home does not exist - true if successful - boolean out = false; - MinecraftLocation old = this.homes.remove(homeName); - if (old != null) { - out = true; - this.markDirty(); - } - return out; - } - - public void updatePlayer(ServerPlayerEntity serverPlayerEntity) { - this.player = serverPlayerEntity; - - // This is to fix a bug with ability to fly being lost upon being teleported to a new dim via /execute...tp. - PlayerDataManager.scheduleTask(this::updateFlight); - } - - private void updateFlight() { - this.player.sendAbilitiesUpdate(); - } - - public void setFlight(boolean canFly) { - setFlight(canFly, false); - } - - public void setFlight(boolean canFly, boolean flyImmediately) { - PlayerAbilities abilities = this.player.getAbilities(); - if (canFly) { - Pal.grantAbility(this.player, VanillaAbilities.ALLOW_FLYING, ECAbilitySources.FLY_COMMAND); - if (flyImmediately) { - abilities.flying = true; - } - } else { - Pal.revokeAbility(this.player, VanillaAbilities.ALLOW_FLYING, ECAbilitySources.FLY_COMMAND); - } - this.player.sendAbilitiesUpdate(); - } - - public void tickTpCooldown() { - this.tpCooldown--; - } - - public int getTpCooldown() { - return tpCooldown; - } - - public void setTpCooldown(int cooldown) { - this.tpCooldown = cooldown; - } - - public MutableText getNickname() { - return Objects.nonNull(nickname) ? nickname.shallowCopy() : null; - } - public MutableText getFullNickname() { - return Objects.nonNull(fullNickname) ? fullNickname : null; - } - - public int setNickname(Text nickname) { - int resultCode = 0; - // Reset nickname - if (nickname == null) { - this.nickname = null; - resultCode = 1; - EssentialCommands.LOGGER.info(String.format( - "Cleared %s's nickname", - this.player.getGameProfile().getName() - )); - } else { - // Ensure nickname does not exceed max length - if (nickname.getString().length() > CONFIG.NICKNAME_MAX_LENGTH.getValue()) { - return -2; - } - // Ensure player has permissions required to set the specified nickname - boolean hasRequiredPerms = NicknameText.checkPerms(nickname, this.player.getCommandSource()); - if (!hasRequiredPerms) { - EssentialCommands.LOGGER.info(String.format( - "%s attempted to set nickname to '%s', with insufficient permissions to do so.", - this.player.getGameProfile().getName(), - nickname - )); - return -1; - } else { - EssentialCommands.LOGGER.info(String.format( - "Set %s's nickname to '%s'.", - this.player.getGameProfile().getName(), - nickname - )); - } - - // Set nickname - this.nickname = nickname; - } - - reloadFullNickname(); - PlayerDataManager.getInstance().markNicknameDirty(this); - this.markDirty(); - // Return codes based on fail/success - // ex: caused by profanity filter. - return resultCode; - } - - public void save() { - super.save(saveFile); - } - - public void setRtpNextUsableTime(int i) { - this.rtpNextUsableTime = i; - } - - public int getRtpNextUsableTime() { - return rtpNextUsableTime; - } - - public void reloadFullNickname() { - MutableText baseName = new LiteralText(this.getPlayer().getGameProfile().getName()); - MutableText tempFullNickname = new LiteralText(""); - // Note: this doesn't ever display if nickname is null, - // because our mixin to getDisplayName does a null check on getNickname - if (this.nickname != null) { - tempFullNickname - .append(CONFIG.NICKNAME_PREFIX.getValue()) - .append(this.nickname ); - } else { - tempFullNickname - .append(baseName); - } - - if (CONFIG.NICK_REVEAL_ON_HOVER.getValue()) { - tempFullNickname.setStyle(tempFullNickname.getStyle().withHoverEvent( - HoverEvent.Action.SHOW_TEXT.buildHoverEvent(baseName) - )); - } - - this.fullNickname = tempFullNickname; - } - -} diff --git a/src/main/java/com/fibermc/essentialcommands/PlayerDataFactory.java b/src/main/java/com/fibermc/essentialcommands/PlayerDataFactory.java deleted file mode 100644 index b0d7c77d..00000000 --- a/src/main/java/com/fibermc/essentialcommands/PlayerDataFactory.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.fibermc.essentialcommands; - -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtIo; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.WorldSavePath; -import org.apache.logging.log4j.Level; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.UUID; - -public class PlayerDataFactory { - - public static PlayerData create(ServerPlayerEntity player, File saveFile) { - PlayerData pData = new PlayerData(player, saveFile); - if (Files.exists(saveFile.toPath()) && saveFile.length() != 0) { - try { - NbtCompound NbtCompound3 = NbtIo.readCompressed(new FileInputStream(saveFile)); - pData.fromNbt(NbtCompound3); - //Testing: - - } catch (IOException e) { - EssentialCommands.log(Level.WARN, "Failed to load essential_commands player data for {"+player.getName().getString()+"}"); - e.printStackTrace(); - } - } - pData.markDirty(); - return pData; - } - - public static PlayerData create(NamedLocationStorage homes, File saveFile) { - String fileName = saveFile.getName(); - UUID playerUuid = UUID.fromString(fileName.substring(0, fileName.indexOf(".dat"))); - PlayerData pData = new PlayerData(playerUuid, homes, saveFile); - if (Files.exists(saveFile.toPath()) && saveFile.length() != 0) { - try { - NbtCompound NbtCompound3 = NbtIo.readCompressed(new FileInputStream(saveFile)); - pData.fromNbt(NbtCompound3); - // If a EC data already existed, the homes we just initialized the pData with (from paramater) just got overwritten. - // Now, add them back if their keys do not already exist in the set we just loaded from EC save file. - homes.forEach((name, minecraftLocation) -> pData.homes.putIfAbsent(name, minecraftLocation)); - //Testing: - - } catch (IOException e) { - EssentialCommands.log(Level.WARN, "Failed to load essential_commands player data for {"+playerUuid+"}"); - e.printStackTrace(); - } - } - - pData.markDirty(); - return pData; - } - - - public static PlayerData create(ServerPlayerEntity player) { - return create(player, getPlayerDataFile(player)); - } - - private static File getPlayerDataFile(ServerPlayerEntity player) { - String pUuid = player.getUuidAsString(); - - //Path mainDirectory = player.getServer().getRunDirectory().toPath(); - Path dataDirectoryPath; - File playerDataFile = null; - try { - try { - dataDirectoryPath = Files.createDirectories(player.getServer().getSavePath(WorldSavePath.ROOT).resolve("modplayerdata")); - } catch (NullPointerException e){ - dataDirectoryPath = Files.createDirectories(Paths.get("./world/modplayerdata/")); - EssentialCommands.log(Level.WARN, "Session save path could not be found. Defaulting to ./world/modplayerdata"); - } - playerDataFile = dataDirectoryPath.resolve(pUuid+".dat").toFile(); - playerDataFile.createNewFile(); -// if (playerDataFile.createNewFile() || playerDataFile.length()==0) {//creates file and returns true only if file did not exist, otherwise returns false -// //Initialize file if just created -// pData.markDirty(); -// pData.save(); -// } - } catch (IOException e) { - e.printStackTrace(); - } - - return playerDataFile; - } -} diff --git a/src/main/java/com/fibermc/essentialcommands/PlayerTeleporter.java b/src/main/java/com/fibermc/essentialcommands/PlayerTeleporter.java deleted file mode 100644 index 07b61cb6..00000000 --- a/src/main/java/com/fibermc/essentialcommands/PlayerTeleporter.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.fibermc.essentialcommands; - -import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; -import com.fibermc.essentialcommands.types.MinecraftLocation; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.LiteralText; -import net.minecraft.text.MutableText; -import net.minecraft.util.Util; - -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; - -/** - * Teleporter - */ -public class PlayerTeleporter { - - public static void requestTeleport(PlayerData pData, MinecraftLocation dest, MutableText destName) { - requestTeleport(new QueuedLocationTeleport(pData, dest, destName)); - } - public static void requestTeleport(QueuedTeleport queuedTeleport) { - ServerPlayerEntity player = queuedTeleport.getPlayerData().getPlayer(); -// if (pData.getTpCooldown() < 0 || player.getServer().getPlayerManager().isOperator(player.getGameProfile())) { -// //send TP request to tpManager -// } - if (playerHasTpRulesBypass(player, ECPerms.Registry.bypass_teleport_delay) || CONFIG.TELEPORT_DELAY.getValue() <= 0) { - teleport(queuedTeleport.getPlayerData(), queuedTeleport.getDest()); - } else { - ((ServerPlayerEntityAccess) player).setEcQueuedTeleport(queuedTeleport); - TeleportRequestManager.getInstance().queueTeleport(queuedTeleport); - player.sendSystemMessage( - ECText.getInstance().getText("teleport.queued.1").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()) - .append(queuedTeleport.getDestName().setStyle(CONFIG.FORMATTING_ACCENT.getValue())) - .append(ECText.getInstance().getText("teleport.queued.2").setStyle(CONFIG.FORMATTING_DEFAULT.getValue())) - .append(new LiteralText(String.format("%.1f", CONFIG.TELEPORT_DELAY.getValue())).setStyle(CONFIG.FORMATTING_ACCENT.getValue())) - .append(ECText.getInstance().getText("teleport.queued.3")).setStyle(CONFIG.FORMATTING_DEFAULT.getValue()), - Util.NIL_UUID - ); - } - } - public static void requestTeleport(ServerPlayerEntity playerEntity, MinecraftLocation dest, MutableText destName) { - requestTeleport(((ServerPlayerEntityAccess)playerEntity).getEcPlayerData(), dest, destName); - } - public static void teleport(QueuedTeleport queuedTeleport) { - queuedTeleport.complete(); - teleport(queuedTeleport.getPlayerData(), queuedTeleport.getDest()); - } - public static void teleport(PlayerData pData, MinecraftLocation dest) {//forceTeleport - ServerPlayerEntity player = pData.getPlayer(); - - // If teleporting between dimensions is disabled and player doesn't have TP rules override - if (!CONFIG.ALLOW_TELEPORT_BETWEEN_DIMENSIONS.getValue() && !playerHasTpRulesBypass(player, ECPerms.Registry.bypass_allow_teleport_between_dimensions)) { - // If this teleport is between dimensions - if (dest.dim != player.getServerWorld().getRegistryKey()) { - player.sendSystemMessage( - ECText.getInstance().getText("teleport.error.interdimensional_teleport_disabled").setStyle(CONFIG.FORMATTING_ERROR.getValue()), - Util.NIL_UUID - ); - return; - } - } - - execTeleport(player, dest); - } - public static void teleport(ServerPlayerEntity playerEntity, MinecraftLocation dest) { - if (ManagerLocator.playerDataEnabled()) - teleport(((ServerPlayerEntityAccess)playerEntity).getEcPlayerData(), dest); - else - execTeleport(playerEntity, dest); - } - - private static void execTeleport(ServerPlayerEntity playerEntity, MinecraftLocation dest) { - playerEntity.teleport( - playerEntity.getServer().getWorld(dest.dim), - dest.pos.x, dest.pos.y, dest.pos.z, - dest.headYaw, dest.pitch - ); - playerEntity.sendSystemMessage( - ECText.getInstance().getText("teleport.done.1").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()) - .append(dest.toLiteralTextSimple().setStyle(CONFIG.FORMATTING_ACCENT.getValue())) - .append(new LiteralText(".").setStyle(CONFIG.FORMATTING_DEFAULT.getValue())), - Util.NIL_UUID - ); - } - - public static boolean playerHasTpRulesBypass(ServerPlayerEntity player, String permission) { - return ( - (player.hasPermissionLevel(4) && CONFIG.OPS_BYPASS_TELEPORT_RULES.getValue()) - || ECPerms.check(player.getCommandSource(), permission, 5) - ); - - } -} \ No newline at end of file diff --git a/src/main/java/com/fibermc/essentialcommands/TeleportRequestManager.java b/src/main/java/com/fibermc/essentialcommands/TeleportRequestManager.java deleted file mode 100644 index 8e1439f5..00000000 --- a/src/main/java/com/fibermc/essentialcommands/TeleportRequestManager.java +++ /dev/null @@ -1,148 +0,0 @@ -package com.fibermc.essentialcommands; - -import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; -import com.fibermc.essentialcommands.events.PlayerDamageCallback; -import com.fibermc.essentialcommands.types.MinecraftLocation; -import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; -import net.minecraft.entity.damage.DamageSource; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.LiteralText; -import net.minecraft.text.MutableText; -import net.minecraft.util.Util; - -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; - -/** - * TeleportRequestManager - */ -public class TeleportRequestManager { - - private static final int TPS = 20; - private final PlayerDataManager dataManager; - private final LinkedList activeTpRequestList; - private final LinkedList tpCooldownList; - private final ConcurrentHashMap delayedQueuedTeleportMap; - - private static TeleportRequestManager INSTANCE; - - public TeleportRequestManager(PlayerDataManager dataManager) { - INSTANCE = this; - this.dataManager = dataManager; - activeTpRequestList = new LinkedList(); - tpCooldownList = new LinkedList<>(); - delayedQueuedTeleportMap = new ConcurrentHashMap<>(); - } - - public static TeleportRequestManager getInstance() { - return INSTANCE; - } - - public static void init() { - PlayerDamageCallback.EVENT.register((ServerPlayerEntity playerEntity, DamageSource source) -> TeleportRequestManager.INSTANCE.onPlayerDamaged(playerEntity, source)); - ServerTickEvents.END_SERVER_TICK.register((MinecraftServer server) -> TeleportRequestManager.INSTANCE.tick(server)); - } - - public void endTpRequest(TeleportRequest teleportRequest) { - endTpRequestFinal(teleportRequest); - this.activeTpRequestList.remove(teleportRequest); - } - private void endTpRequestFinal(TeleportRequest teleportRequest) { - PlayerData target = teleportRequest.getTargetPlayerData(); - if (target != null) { - target.removeIncomingTeleportRequest(teleportRequest.getSenderPlayer().getUuid()); - teleportRequest.getSenderPlayerData().setSentTeleportRequest(null); - } - } - - public void tick(MinecraftServer server) { - ListIterator tpRequestIterator = activeTpRequestList.listIterator(); - //decrement the tp timer for all players that have put in a tp request - while (tpRequestIterator.hasNext()) { - TeleportRequest teleportRequest = tpRequestIterator.next(); - PlayerData requesterPlayerData = ((ServerPlayerEntityAccess) teleportRequest.getSenderPlayer()).getEcPlayerData(); - requesterPlayerData.tickTpTimer(); - if (requesterPlayerData.getTpTimer() < 0) { - endTpRequestFinal(teleportRequest); - tpRequestIterator.remove(); - } - } - - ListIterator toCooldownIterator = tpCooldownList.listIterator(); - while (toCooldownIterator.hasNext()) { - PlayerData e = toCooldownIterator.next(); - e.tickTpCooldown(); - if (e.getTpCooldown() < 0) { - toCooldownIterator.remove(); - } - } - - Iterator> tpQueueIter = delayedQueuedTeleportMap.entrySet().iterator(); - while (tpQueueIter.hasNext()) { - Map.Entry entry = tpQueueIter.next(); - QueuedTeleport queuedTeleport = entry.getValue(); - queuedTeleport.tick(server); - if (queuedTeleport.getTicksRemaining() < 0) { - tpQueueIter.remove(); - PlayerTeleporter.teleport(queuedTeleport); - } - } - } - - public void onPlayerDamaged(ServerPlayerEntity playerEntity, DamageSource damageSource) { - if (CONFIG.TELEPORT_INTERRUPT_ON_DAMAGED.getValue() && !PlayerTeleporter.playerHasTpRulesBypass(playerEntity, ECPerms.Registry.bypass_teleport_interrupt_on_damaged)) { - try { - Objects.requireNonNull( ((ServerPlayerEntityAccess)playerEntity).endEcQueuedTeleport()); - - delayedQueuedTeleportMap.remove(playerEntity.getUuid()); - playerEntity.sendSystemMessage( - new LiteralText("Teleport interrupted. Reason: Damage Taken").setStyle(CONFIG.FORMATTING_ERROR.getValue()), - Util.NIL_UUID - ); - } catch (NullPointerException ignored) {} - } - } - - public void startTpRequest(ServerPlayerEntity requestSender, ServerPlayerEntity targetPlayer, TeleportRequest.Type requestType) { - PlayerData requestSenderData = ((ServerPlayerEntityAccess)requestSender).getEcPlayerData(); - PlayerData targetPlayerData = ((ServerPlayerEntityAccess)targetPlayer).getEcPlayerData(); - - final int TRD = CONFIG.TELEPORT_REQUEST_DURATION.getValue() * TPS;//sec * ticks per sec - requestSenderData.setTpTimer(TRD); - TeleportRequest teleportRequest = new TeleportRequest(requestSender, targetPlayer, requestType); - requestSenderData.setSentTeleportRequest(teleportRequest); - targetPlayerData.addIncomingTeleportRequest(teleportRequest); - activeTpRequestList.add(teleportRequest); - } - - public void startTpCooldown(ServerPlayerEntity player) { - PlayerData pData = ((ServerPlayerEntityAccess)player).getEcPlayerData(); - - final int TC = (int)(CONFIG.TELEPORT_COOLDOWN.getValue() * TPS); - pData.setTpCooldown(TC); - tpCooldownList.add(pData); - } - - public void queueTeleport(ServerPlayerEntity player, MinecraftLocation dest, MutableText destName) { - queueTeleport(new QueuedLocationTeleport(((ServerPlayerEntityAccess)player).getEcPlayerData(), dest, destName)); - } - - - public void queueTeleport(QueuedTeleport queuedTeleport) { - QueuedTeleport prevValue = delayedQueuedTeleportMap.put( - queuedTeleport.getPlayerData().getPlayer().getUuid(), - queuedTeleport - ); - if (Objects.nonNull(prevValue)) { - prevValue.getPlayerData().getPlayer().sendSystemMessage( - new LiteralText("Teleport request canceled. Reason: New teleport started!") - .setStyle(CONFIG.FORMATTING_DEFAULT.getValue()), - Util.NIL_UUID - ); - } - - } -} \ No newline at end of file diff --git a/src/main/java/com/fibermc/essentialcommands/TradeUI.java b/src/main/java/com/fibermc/essentialcommands/TradeUI.java deleted file mode 100644 index 9324e84f..00000000 --- a/src/main/java/com/fibermc/essentialcommands/TradeUI.java +++ /dev/null @@ -1,39 +0,0 @@ -//package com.fibermc.essentialcommands; -// -//import net.minecraft.client.MinecraftClient; -//import net.minecraft.client.gui.screen.Screen; -//import net.minecraft.client.gui.screen.ingame.ContainerScreen54; -//import net.minecraft.container.ContainerType; -//import net.minecraft.container.GenericContainer; -//import net.minecraft.inventory.BasicInventory; -//import net.minecraft.inventory.Inventory; -//import net.minecraft.item.ItemStack; -//import net.minecraft.item.Items; -//import net.minecraft.server.network.ServerPlayerEntity; -//import net.minecraft.text.LiteralText; -// -//public class TradeUI { -// -// -// public void showScreens(ServerPlayerEntity player1, ServerPlayerEntity player2) { -// MinecraftClient.getInstance().openScreen(getPlayerUI(player1, player2)); -// } -// -// private Screen getPlayerUI(ServerPlayerEntity player1, ServerPlayerEntity player2) { -// ContainerScreen54 p1UI = new ContainerScreen54(getUIContainer(player1, player2), player1.inventory, new LiteralText("Trade with " + player2.getName()) ); -// -// return p1UI; -// } -// -// private GenericContainer getUIContainer(ServerPlayerEntity thisPlayer, ServerPlayerEntity otherPlayer) { -// Inventory containerInv = new BasicInventory(); -// final int rows = 6; -// for (int i=5; i < 9*rows; i+=9) { -// containerInv.setInvStack(i, new ItemStack(Items.LIME_STAINED_GLASS_PANE)); -// } -// GenericContainer out = new GenericContainer(ContainerType.GENERIC_9X6, 0, thisPlayer.inventory, containerInv, rows); -// -// return out; -// } -//} -// diff --git a/src/main/java/com/fibermc/essentialcommands/Updater.java b/src/main/java/com/fibermc/essentialcommands/Updater.java index 9f84574c..befe95eb 100644 --- a/src/main/java/com/fibermc/essentialcommands/Updater.java +++ b/src/main/java/com/fibermc/essentialcommands/Updater.java @@ -1,21 +1,18 @@ package com.fibermc.essentialcommands; -import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; -import net.fabricmc.loader.api.FabricLoader; -import net.fabricmc.loader.api.SemanticVersion; -import net.fabricmc.loader.api.VersionParsingException; -import net.fabricmc.loader.api.metadata.ModMetadata; -import net.fabricmc.loader.util.version.VersionDeserializer; - import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; -import java.util.Objects; -import java.util.function.UnaryOperator; -public class Updater { +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; +import net.fabricmc.loader.api.Version; +import net.fabricmc.loader.api.VersionParsingException; +import net.fabricmc.loader.api.metadata.ModMetadata; + +public final class Updater { + private Updater() {} public static void checkForUpdates() { HttpClient client = HttpClient.newBuilder() @@ -31,17 +28,16 @@ public static void checkForUpdates() { ).thenAcceptAsync((HttpResponse response) -> { String latestVersionStr = response.body(); - ModMetadata modMetadata = FabricLoader.getInstance().getModContainer("essential_commands").get().getMetadata(); - if (Objects.isNull(modMetadata)) { + ModMetadata modMetadata = EssentialCommands.MOD_METADATA; + if (modMetadata == null) { EssentialCommands.LOGGER.warn("Failed to check for Essential Commands updates."); return; } - UnaryOperator stripMinecraftVersion = (String versionStr) -> versionStr.substring(0, versionStr.indexOf("-mc")); String currentVersionStr = modMetadata.getVersion().getFriendlyString(); try { - SemanticVersion currentVers = VersionDeserializer.deserializeSemantic(stripMinecraftVersion.apply(currentVersionStr)); - SemanticVersion latestVers = VersionDeserializer.deserializeSemantic(stripMinecraftVersion.apply(latestVersionStr)); + Version currentVers = Version.parse(stripMinecraftVersion(currentVersionStr));//VersionDeserializer.deserializeSemantic(stripMinecraftVersion.apply(currentVersionStr)); + Version latestVers = Version.parse(stripMinecraftVersion(latestVersionStr)); if (latestVers.compareTo(currentVers) > 0) { String updateMessage = String.format( "A new version of Essential Commands is available. Current: '%s' Latest: '%s'. Get the new version at %s", @@ -59,4 +55,8 @@ public static void checkForUpdates() { } }); } + + private static String stripMinecraftVersion(String versionStr) { + return versionStr.substring(0, versionStr.indexOf("-mc")); + } } diff --git a/src/main/java/com/fibermc/essentialcommands/WorldDataManager.java b/src/main/java/com/fibermc/essentialcommands/WorldDataManager.java index edbd1cde..e4e5aebe 100644 --- a/src/main/java/com/fibermc/essentialcommands/WorldDataManager.java +++ b/src/main/java/com/fibermc/essentialcommands/WorldDataManager.java @@ -1,37 +1,52 @@ package com.fibermc.essentialcommands; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Map.Entry; +import java.util.Set; +import java.util.function.Consumer; + import com.fibermc.essentialcommands.types.MinecraftLocation; +import com.fibermc.essentialcommands.types.WarpLocation; +import com.fibermc.essentialcommands.types.WarpStorage; +import org.apache.logging.log4j.Level; + import com.mojang.brigadier.exceptions.CommandSyntaxException; + import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtIo; import net.minecraft.server.MinecraftServer; import net.minecraft.util.WorldSavePath; import net.minecraft.world.PersistentState; -import org.apache.logging.log4j.Level; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.Map.Entry; -import java.util.Set; +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; public class WorldDataManager extends PersistentState { - private NamedLocationStorage warps; + private final WarpStorage warps; private MinecraftLocation spawnLocation; private Path saveDir; private File worldDataFile; - private final String SPAWN_KEY = "spawn"; - private final String WARPS_KEY = "warps"; + private static final String SPAWN_KEY = "spawn"; + private static final String WARPS_KEY = "warps"; public WorldDataManager() { - warps = new NamedLocationStorage(); + warps = new WarpStorage(); spawnLocation = null; } + public static WorldDataManager createForServer(MinecraftServer server) + { + var worldDataManager = new WorldDataManager(); + worldDataManager.onServerStart(server); + return worldDataManager; + } + public void onServerStart(MinecraftServer server) { this.saveDir = server.getSavePath(WorldSavePath.ROOT).resolve("essentialcommands"); try { @@ -62,15 +77,25 @@ private File getDataFile() { } public void fromNbt(NbtCompound tag) { - MinecraftLocation tempSpawnLocation = new MinecraftLocation(tag.getCompound(SPAWN_KEY)); - if (tempSpawnLocation.dim.getValue().getPath().isEmpty()) + MinecraftLocation tempSpawnLocation = MinecraftLocation.fromNbt(tag.getCompound(SPAWN_KEY)); + if (tempSpawnLocation.dim().getValue().getPath().isEmpty()) { this.spawnLocation = null; - else + } else { this.spawnLocation = tempSpawnLocation; + } NbtCompound warpsNbt = tag.getCompound(WARPS_KEY); warps.loadNbt(warpsNbt); + warpsLoadEvent.invoker().accept(warps); } + public final Event> warpsLoadEvent = EventFactory.createArrayBacked( + Consumer.class, + (listeners) -> (warps) -> { + for (Consumer event : listeners) { + event.accept(warps); + } + }); + public void save() { EssentialCommands.log(Level.INFO, "Saving world_data.dat (Spawn/Warps)..."); super.save(this.worldDataFile); @@ -80,11 +105,10 @@ public void save() { @Override public NbtCompound writeNbt(NbtCompound tag) { // Spawn to NBT - NbtElement spawnNbt; - if (spawnLocation != null) - spawnNbt = spawnLocation.asNbt(); - else - spawnNbt = new NbtCompound(); + NbtElement spawnNbt = spawnLocation != null + ? spawnLocation.asNbt() + : new NbtCompound(); + tag.put(SPAWN_KEY, spawnNbt); // Warps to NBT @@ -96,25 +120,32 @@ public NbtCompound writeNbt(NbtCompound tag) { } // Command Actions - public void setWarp(String warpName, MinecraftLocation location) throws CommandSyntaxException { - warps.putCommand(warpName, location); + public void setWarp(String warpName, MinecraftLocation location, boolean requiresPermission) throws CommandSyntaxException { + warps.putCommand(warpName, new WarpLocation( + location, + requiresPermission ? warpName : null, + warpName + )); this.markDirty(); this.save(); } + public boolean delWarp(String warpName) { MinecraftLocation prevValue = warps.remove(warpName); this.markDirty(); this.save(); return prevValue != null; } - public MinecraftLocation getWarp(String warpName) { + + public WarpLocation getWarp(String warpName) { return warps.get(warpName); } public List getWarpNames() { return this.warps.keySet().stream().toList(); } - public Set> getWarpEntries() { + + public Set> getWarpEntries() { return this.warps.entrySet(); } @@ -123,6 +154,7 @@ public void setSpawn(MinecraftLocation location) { this.markDirty(); this.save(); } + public MinecraftLocation getSpawn() { return spawnLocation; } diff --git a/src/main/java/com/fibermc/essentialcommands/access/ServerPlayerEntityAccess.java b/src/main/java/com/fibermc/essentialcommands/access/ServerPlayerEntityAccess.java index 729d9b9b..f29b46f6 100644 --- a/src/main/java/com/fibermc/essentialcommands/access/ServerPlayerEntityAccess.java +++ b/src/main/java/com/fibermc/essentialcommands/access/ServerPlayerEntityAccess.java @@ -1,17 +1,24 @@ package com.fibermc.essentialcommands.access; -import com.fibermc.essentialcommands.PlayerData; -import com.fibermc.essentialcommands.QueuedTeleport; +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.playerdata.PlayerProfile; +import com.fibermc.essentialcommands.teleportation.QueuedTeleport; +import com.fibermc.essentialcommands.text.ECText; public interface ServerPlayerEntityAccess { - QueuedTeleport getEcQueuedTeleport(); + QueuedTeleport ec$getQueuedTeleport(); - void setEcQueuedTeleport(QueuedTeleport queuedTeleport); + void ec$setQueuedTeleport(QueuedTeleport queuedTeleport); - QueuedTeleport endEcQueuedTeleport(); + QueuedTeleport ec$endQueuedTeleport(); - PlayerData getEcPlayerData(); + PlayerData ec$getPlayerData(); - void setEcPlayerData(PlayerData playerData); + void ec$setPlayerData(PlayerData playerData); + PlayerProfile ec$getProfile(); + + void ec$setProfile(PlayerProfile profile); + + ECText ec$getEcText(); } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/AfkCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/AfkCommand.java new file mode 100644 index 00000000..f589d914 --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/commands/AfkCommand.java @@ -0,0 +1,39 @@ +package com.fibermc.essentialcommands.commands; + +import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; +import com.fibermc.essentialcommands.text.TextFormatType; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.command.CommandException; +import net.minecraft.server.command.ServerCommandSource; + +import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; + +public class AfkCommand implements Command { + @Override + public int run(CommandContext context) throws CommandSyntaxException { + var source = context.getSource(); + var player = source.getPlayer(); + var playerAccess = ((ServerPlayerEntityAccess) player); + var playerData = playerAccess.ec$getPlayerData(); + var playerProfile = playerAccess.ec$getProfile(); + + if (CONFIG.INVULN_WHILE_AFK) { + if (playerData.isInCombat()) { + throw new CommandException(playerAccess.ec$getEcText().getText( + "cmd.afk.error.in_combat", + TextFormatType.Error, + playerProfile)); + } + } + + // Message sending is done in here + playerData.setAfk(!playerData.isAfk()); + playerData.updateLastActionTick(); + + return 0; + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/BackCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/BackCommand.java index d3100de1..6a2b827f 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/BackCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/BackCommand.java @@ -1,45 +1,41 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.ECText; -import com.fibermc.essentialcommands.PlayerData; -import com.fibermc.essentialcommands.PlayerTeleporter; import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.teleportation.PlayerTeleporter; +import com.fibermc.essentialcommands.text.ECText; import com.fibermc.essentialcommands.types.MinecraftLocation; + import com.mojang.brigadier.Command; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; + import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; - - public class BackCommand implements Command { public BackCommand() {} @Override public int run(CommandContext context) throws CommandSyntaxException { - int out = 0; //Store command sender ServerPlayerEntity player = context.getSource().getPlayer(); - PlayerData playerData = ((ServerPlayerEntityAccess)player).getEcPlayerData(); + PlayerData playerData = ((ServerPlayerEntityAccess) player).ec$getPlayerData(); //Get previous location MinecraftLocation loc = playerData.getPreviousLocation(); //chat message - if (loc != null) { - //Teleport player to home location - PlayerTeleporter.requestTeleport(playerData, loc, ECText.getInstance().getText("cmd.back.location_name")); - - out=1; - } else { - context.getSource().sendError( - ECText.getInstance().getText("cmd.back.error.no_prev_location").setStyle(CONFIG.FORMATTING_ERROR.getValue()) - ); + if (loc == null) { + playerData.sendCommandError("cmd.back.error.no_prev_location"); + return 0; } - return out; + //Teleport player to home location + var prevLocationName = ECText.access(player).getText("cmd.back.location_name"); + PlayerTeleporter.requestTeleport(playerData, loc, prevLocationName); + + return 1; } } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/BedCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/BedCommand.java new file mode 100644 index 00000000..2fb5de11 --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/commands/BedCommand.java @@ -0,0 +1,32 @@ +package com.fibermc.essentialcommands.commands; + +import com.fibermc.essentialcommands.teleportation.PlayerTeleporter; +import com.fibermc.essentialcommands.text.ECText; +import com.fibermc.essentialcommands.text.TextFormatType; +import com.fibermc.essentialcommands.types.MinecraftLocation; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.command.CommandException; +import net.minecraft.server.command.ServerCommandSource; + +public class BedCommand implements Command { + @Override + public int run(CommandContext context) throws CommandSyntaxException { + var player = context.getSource().getPlayer(); + var spawnPos = player.getSpawnPointPosition(); + var spawnDim = player.getSpawnPointDimension(); + + if (spawnPos == null) { + throw new CommandException(ECText.access(player).getText("cmd.bed.error.none_set", TextFormatType.Error)); + } + PlayerTeleporter.requestTeleport( + player, + new MinecraftLocation(spawnDim, spawnPos.getX(), spawnPos.getY(), spawnPos.getZ()), + ECText.access(player).getText("cmd.bed.bed_destination_name", TextFormatType.Accent)); + + return 0; + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/CommandUtil.java b/src/main/java/com/fibermc/essentialcommands/commands/CommandUtil.java index 7d9c8e42..474a71b5 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/CommandUtil.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/CommandUtil.java @@ -1,24 +1,35 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.ECText; -import com.fibermc.essentialcommands.util.TextUtil; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.Message; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; import com.mojang.brigadier.tree.CommandNode; + +import net.minecraft.command.EntitySelector; +import net.minecraft.command.argument.EntityArgumentType; +import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; + +import dev.jpcode.eccore.util.TextUtil; public final class CommandUtil { private CommandUtil() {} + public static RequiredArgumentBuilder targetPlayerArgument() { + return CommandManager.argument("target_player", EntityArgumentType.player()); + } + public static String getCommandString(ServerCommandSource source, CommandNode commandNode) { CommandDispatcher dispatcher = source.getServer().getCommandManager().getDispatcher(); return "/" + TextUtil.joinStrings( - dispatcher.getPath(commandNode), - CommandDispatcher.ARGUMENT_SEPARATOR + dispatcher.getPath(commandNode), + CommandDispatcher.ARGUMENT_SEPARATOR ); } @@ -26,4 +37,12 @@ public static CommandSyntaxException createSimpleException(Message msg) { return new CommandSyntaxException(new SimpleCommandExceptionType(msg), msg); } + public static ServerPlayerEntity getCommandTargetPlayer(CommandContext context) throws CommandSyntaxException { + try { + return EntityArgumentType.getPlayer(context, "target_player"); + } catch (IllegalArgumentException e) { + return context.getSource().getPlayer(); + } + } + } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/EnderchestCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/EnderchestCommand.java deleted file mode 100644 index d7646bef..00000000 --- a/src/main/java/com/fibermc/essentialcommands/commands/EnderchestCommand.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.fibermc.essentialcommands.commands; - -import com.fibermc.essentialcommands.ECText; -import com.mojang.brigadier.Command; -import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.minecraft.screen.GenericContainerScreenHandler; -import net.minecraft.screen.NamedScreenHandlerFactory; -import net.minecraft.screen.SimpleNamedScreenHandlerFactory; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.stat.Stats; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; - -public class EnderchestCommand implements Command { - - public EnderchestCommand() { - } - - @Override - public int run(CommandContext context) throws CommandSyntaxException { - ServerCommandSource source = context.getSource(); - ServerPlayerEntity senderPlayer = source.getPlayer(); - - senderPlayer.openHandledScreen(createScreenHandlerFactory(senderPlayer.getEntityWorld(), senderPlayer.getBlockPos())); - senderPlayer.incrementStat(Stats.OPEN_ENDERCHEST); - - source.sendFeedback( - ECText.getInstance().getText("cmd.enderchest.feedback").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()), - CONFIG.BROADCAST_TO_OPS.getValue() - ); - - return 0; - } - - private NamedScreenHandlerFactory createScreenHandlerFactory(World world, BlockPos pos) { - return new SimpleNamedScreenHandlerFactory((syncId, inventory, player) -> { - return GenericContainerScreenHandler.createGeneric9x3(syncId, inventory, player.getEnderChestInventory()); - }, ECText.getInstance().getText("cmd.enderchest.container_ui_name")); - - } - -} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/FlyCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/FlyCommand.java index a1cfabc3..28d15c0b 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/FlyCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/FlyCommand.java @@ -1,25 +1,20 @@ package com.fibermc.essentialcommands.commands; import com.fibermc.essentialcommands.ECAbilitySources; -import com.fibermc.essentialcommands.ECText; -import com.fibermc.essentialcommands.PlayerData; import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; -import com.fibermc.essentialcommands.util.TextUtil; +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.text.ECText; +import com.fibermc.essentialcommands.text.TextFormatType; +import io.github.ladysnake.pal.VanillaAbilities; + import com.mojang.brigadier.Command; import com.mojang.brigadier.arguments.BoolArgumentType; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import io.github.ladysnake.pal.Pal; -import io.github.ladysnake.pal.VanillaAbilities; -import net.minecraft.command.argument.EntityArgumentType; + import net.minecraft.entity.player.PlayerAbilities; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.LiteralText; - -import java.util.function.Consumer; - -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; public class FlyCommand implements Command { @@ -29,14 +24,7 @@ public FlyCommand() { @Override public int run(CommandContext context) throws CommandSyntaxException { ServerCommandSource source = context.getSource(); - ServerPlayerEntity senderPlayer = source.getPlayer(); - - ServerPlayerEntity targetPlayer; - try { - targetPlayer = EntityArgumentType.getPlayer(context, "target_player"); - } catch (IllegalArgumentException e) { - targetPlayer = senderPlayer; - } + ServerPlayerEntity targetPlayer = CommandUtil.getCommandTargetPlayer(context); boolean shouldEnableFly; try { @@ -46,7 +34,7 @@ public int run(CommandContext context) throws CommandSyntax try { // Fall back to toggling the current PAL flight state granted by EC shouldEnableFly = !VanillaAbilities.ALLOW_FLYING - .getTracker(targetPlayer).isGrantedBy(ECAbilitySources.FLY_COMMAND); + .getTracker(targetPlayer).isGrantedBy(ECAbilitySources.FLY_COMMAND); } catch (NoClassDefFoundError ign) { // If PAL is not found, fall back to toggling the current vanilla flight state. shouldEnableFly = !targetPlayer.getAbilities().allowFlying; @@ -57,10 +45,10 @@ public int run(CommandContext context) throws CommandSyntax return 0; } - public static void exec(ServerCommandSource source, ServerPlayerEntity target, boolean shouldEnableFly) { + public static void exec(ServerCommandSource source, ServerPlayerEntity target, boolean shouldEnableFly) throws CommandSyntaxException { PlayerAbilities playerAbilities = target.getAbilities(); - PlayerData playerData = ((ServerPlayerEntityAccess) target).getEcPlayerData(); + PlayerData playerData = ((ServerPlayerEntityAccess) target).ec$getPlayerData(); try { playerData.setFlight(shouldEnableFly); @@ -75,15 +63,17 @@ public static void exec(ServerCommandSource source, ServerPlayerEntity target, b // Label boolean values in suggestions, or switch to single state value (present or it's not) - source.sendFeedback( - TextUtil.concat( - ECText.getInstance().getText("cmd.fly.feedback.1").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()), - new LiteralText(shouldEnableFly ? "enabled" : "disabled").setStyle(CONFIG.FORMATTING_ACCENT.getValue()), - ECText.getInstance().getText("cmd.fly.feedback.2").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()), - target.getDisplayName(), - new LiteralText(".").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()) - ), - CONFIG.BROADCAST_TO_OPS.getValue() + var senderPlayer = source.getPlayer(); + var senderPlayerData = PlayerData.access(senderPlayer); + var ecText = ECText.access(senderPlayer); + var enabledText = ecText.getText( + shouldEnableFly ? "generic.enabled" : "generic.disabled", + TextFormatType.Accent); + + senderPlayerData.sendCommandFeedback( + "cmd.fly.feedback", + enabledText, + target.getDisplayName() ); } -} \ No newline at end of file +} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/GametimeCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/GametimeCommand.java new file mode 100644 index 00000000..73934b80 --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/commands/GametimeCommand.java @@ -0,0 +1,61 @@ +package com.fibermc.essentialcommands.commands; + +import com.fibermc.essentialcommands.EssentialCommands; +import com.fibermc.essentialcommands.playerdata.PlayerProfile; +import com.fibermc.essentialcommands.text.TextFormatType; +import com.fibermc.essentialcommands.types.IStyleProvider; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.HoverEvent; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; + +import dev.jpcode.eccore.util.TextUtil; + +public class GametimeCommand implements Command { + + private final String modVersion = EssentialCommands.MOD_METADATA.getVersion().getFriendlyString(); + private static final int TICKS_PER_SECOND = 20; + private static final int SECONDS_PER_MINUTE = 60; + private static final int MINUTES_PER_HOUR = 60; + private static final int MINUTES_PER_MINECRAFT_DAY = 20; + private static final double TICKS_PER_DAY = TICKS_PER_SECOND * SECONDS_PER_MINUTE * MINUTES_PER_MINECRAFT_DAY; + private static final int HOURS_PER_DAY = 24; + private static final int MINUTES_PER_DAY = HOURS_PER_DAY * MINUTES_PER_HOUR; + + @Override + public int run(CommandContext context) throws CommandSyntaxException { + context.getSource().sendFeedback( + getFormattedTime( + context.getSource().getWorld().getTimeOfDay(), + PlayerProfile.accessFromContextOrThrow(context)), + false); + + return 0; + } + + private static String formatGameTimeOfDay(long tickTime) { + int tickTimeOfDay = (int)(tickTime % 24000L); + double dayPercentComplete = tickTimeOfDay / TICKS_PER_DAY; + int dayHoursComplete = (int)(dayPercentComplete * HOURS_PER_DAY); + int dayMinutesComplete = (int)Math.round((dayPercentComplete - ((double)dayHoursComplete / HOURS_PER_DAY)) * MINUTES_PER_DAY); + return String.format( + "%02d:%02d", + dayHoursComplete, + dayMinutesComplete + ); + } + + private static Text getFormattedTime(long time, IStyleProvider styleProvider) { + return new TranslatableText( + "commands.time.query", + TextUtil.literal(formatGameTimeOfDay(time)).setStyle(styleProvider.getStyle(TextFormatType.Accent))) + .setStyle(styleProvider.getStyle(TextFormatType.Default) + .withHoverEvent( + new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtil.literal(String.valueOf(time % 24000L))))); + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/HomeCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/HomeCommand.java index e1e632ae..7aa6ba31 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/HomeCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/HomeCommand.java @@ -1,69 +1,115 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.ECText; -import com.fibermc.essentialcommands.PlayerData; -import com.fibermc.essentialcommands.PlayerTeleporter; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; +import com.fibermc.essentialcommands.commands.suggestions.ListSuggestion; +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.teleportation.PlayerTeleporter; +import com.fibermc.essentialcommands.text.ECText; +import com.fibermc.essentialcommands.text.TextFormatType; import com.fibermc.essentialcommands.types.MinecraftLocation; +import com.fibermc.essentialcommands.types.NamedMinecraftLocation; + import com.mojang.brigadier.Command; import com.mojang.brigadier.Message; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.network.ServerPlayerEntity; +import com.mojang.brigadier.suggestion.SuggestionProvider; -import java.util.Set; +import net.minecraft.server.command.ServerCommandSource; +import dev.jpcode.eccore.util.TextUtil; public class HomeCommand implements Command { - public HomeCommand() { - } + public HomeCommand() {} @Override public int run(CommandContext context) throws CommandSyntaxException { - //Store command sender - ServerPlayerEntity senderPlayer = context.getSource().getPlayer(); - PlayerData senderPlayerData = ((ServerPlayerEntityAccess)senderPlayer).getEcPlayerData(); - //Store home name + PlayerData senderPlayerData = ((ServerPlayerEntityAccess) context.getSource().getPlayer()).ec$getPlayerData(); String homeName = StringArgumentType.getString(context, "home_name"); return exec(senderPlayerData, homeName); } - public int runDefault(CommandContext context) throws CommandSyntaxException { - PlayerData playerData = ((ServerPlayerEntityAccess) context.getSource().getPlayer()).getEcPlayerData(); + private static PlayerData getTargetPlayerData(CommandContext context) throws CommandSyntaxException { + return ((ServerPlayerEntityAccess) context.getSource().getPlayer()).ec$getPlayerData(); + } + + // TODO: Ideally the styling here should come from a context, intead of from the player we're + // accessing, but I don't think it matters, practically speaking, for now. + public static String getSoleHomeName(PlayerData playerData) throws CommandSyntaxException { Set homeNames = playerData.getHomeNames(); + var ecText = ECText.access(playerData.getPlayer()); if (homeNames.size() > 1) { - throw CommandUtil.createSimpleException(ECText.getInstance().getText("cmd.home.tp.error.shortcut_more_than_one")); - } else if (homeNames.size() < 1) { - throw CommandUtil.createSimpleException(ECText.getInstance().getText("cmd.home.tp.error.shortcut_none_exist")); + throw CommandUtil.createSimpleException( + ecText.getText("cmd.home.tp.error.shortcut_more_than_one", TextFormatType.Error)); + } else if (homeNames.isEmpty()) { + throw CommandUtil.createSimpleException( + ecText.getText("cmd.home.tp.error.shortcut_none_exist", TextFormatType.Error)); } + return homeNames.stream().findAny().get(); + } + + public int runDefault(CommandContext context) throws CommandSyntaxException { + PlayerData playerData = ((ServerPlayerEntityAccess) context.getSource().getPlayer()).ec$getPlayerData(); + return exec( - playerData, - homeNames.stream().findAny().get() + playerData, + getSoleHomeName(playerData) ); } - private int exec(PlayerData senderPlayerData, String homeName) throws CommandSyntaxException { - int out; + private static int exec(PlayerData senderPlayerData, String homeName) throws CommandSyntaxException { + return exec(senderPlayerData, senderPlayerData, homeName); + } + public static int exec(PlayerData senderPlayerData, PlayerData targetPlayerData, String homeName) throws CommandSyntaxException { //Get home location - MinecraftLocation loc = senderPlayerData.getHomeLocation(homeName); + MinecraftLocation loc = targetPlayerData.getHomeLocation(homeName); + var ecText = ECText.access(senderPlayerData.getPlayer()); + if (loc == null) { + Message msg = ecText.getText( + "cmd.home.tp.error.not_found", + TextFormatType.Error, + TextUtil.literal(homeName)); + throw new CommandSyntaxException(new SimpleCommandExceptionType(msg), msg); + } // Teleport & chat message - if (loc != null) { - //Teleport player to home location - PlayerTeleporter.requestTeleport(senderPlayerData, loc, ECText.getInstance().getText("cmd.home.location_name", homeName)); - out = 1; - } else { - Message msg = ECText.getInstance().getText("cmd.home.tp.error.not_found", "null"); - throw new CommandSyntaxException(new SimpleCommandExceptionType(msg), msg); + var homeNameText = ecText.getText( + "cmd.home.location_name", + TextFormatType.Default, + ecText.accent(homeName)); + + PlayerTeleporter.requestTeleport(senderPlayerData, loc, homeNameText); + return 1; + } + + public static class Suggestion { + //Brigader Suggestions + public static final SuggestionProvider LIST_SUGGESTION_PROVIDER + = ListSuggestion.ofContext(Suggestion::getSuggestionsList); + + /** + * Gets a list of suggested strings to be used with Brigader + */ + public static List getSuggestionsList(CommandContext context) throws CommandSyntaxException { + return new ArrayList<>(HomeCommand.getTargetPlayerData(context).getHomeNames()); } - return out; + /** + * Gets a set of suggestion entries to be used with ListCommandFactory + */ + public static Set> getSuggestionEntries(CommandContext context) throws CommandSyntaxException { + return HomeCommand.getTargetPlayerData(context).getHomeEntries(); + } } } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/HomeDeleteCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/HomeDeleteCommand.java index ae935af3..23654943 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/HomeDeleteCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/HomeDeleteCommand.java @@ -1,19 +1,16 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.ECText; -import com.fibermc.essentialcommands.PlayerData; import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; -import com.fibermc.essentialcommands.util.TextUtil; +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.text.ECText; + import com.mojang.brigadier.Command; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; + import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.LiteralText; - -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; - public class HomeDeleteCommand implements Command { @@ -21,34 +18,24 @@ public HomeDeleteCommand() {} @Override public int run(CommandContext context) throws CommandSyntaxException { - int out = 1; ServerCommandSource source = context.getSource(); //Store command sender ServerPlayerEntity senderPlayer = source.getPlayer(); - PlayerData senderPlayerData = ((ServerPlayerEntityAccess)senderPlayer).getEcPlayerData(); + PlayerData senderPlayerData = ((ServerPlayerEntityAccess) senderPlayer).ec$getPlayerData(); //Store home name String homeName = StringArgumentType.getString(context, "home_name"); //Remove Home - TODO Require player to type the command again to confirm deletion. boolean wasSuccessful = senderPlayerData.removeHome(homeName); + var homeNameText = ECText.access(senderPlayer).accent(homeName); //inform command sender that the home has been removed if (wasSuccessful) { - source.sendFeedback( - TextUtil.concat( - ECText.getInstance().getText("cmd.home.feedback.1").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()), - new LiteralText(homeName).setStyle(CONFIG.FORMATTING_ACCENT.getValue()), - ECText.getInstance().getText("cmd.home.delete.feedback.2").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()) - ), CONFIG.BROADCAST_TO_OPS.getValue()); - } else { - source.sendError(TextUtil.concat( - ECText.getInstance().getText("cmd.home.feedback.1").setStyle(CONFIG.FORMATTING_ERROR.getValue()), - new LiteralText(homeName).setStyle(CONFIG.FORMATTING_ACCENT.getValue()), - ECText.getInstance().getText("cmd.home.delete.error.2").setStyle(CONFIG.FORMATTING_ERROR.getValue()) - )); - out = 0; + senderPlayerData.sendCommandFeedback("cmd.home.delete.feedback", homeNameText); + return 1; } - return out; + senderPlayerData.sendCommandError("cmd.home.delete.error", homeNameText); + return 0; } } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/HomeSetCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/HomeSetCommand.java index 6347df73..f99473a4 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/HomeSetCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/HomeSetCommand.java @@ -1,20 +1,17 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.ECText; -import com.fibermc.essentialcommands.PlayerData; import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.text.ECText; import com.fibermc.essentialcommands.types.MinecraftLocation; -import com.fibermc.essentialcommands.util.TextUtil; + import com.mojang.brigadier.Command; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; + import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.LiteralText; - -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; - public class HomeSetCommand implements Command { @@ -23,37 +20,18 @@ public HomeSetCommand() {} @Override public int run(CommandContext context) throws CommandSyntaxException { ServerCommandSource source = context.getSource(); - //Store command sender ServerPlayerEntity senderPlayer = source.getPlayer(); - //Store home name + PlayerData playerData = ((ServerPlayerEntityAccess) senderPlayer).ec$getPlayerData(); String homeName = StringArgumentType.getString(context, "home_name"); - //Add home to PlayerData //TODO if home with given name is already set, warn of overwrite and require that the command be typed again, or a confirmation message be given - PlayerData pData = ((ServerPlayerEntityAccess)senderPlayer).getEcPlayerData(); - int successCode = 0; - try { - successCode = pData.addHome(homeName, new MinecraftLocation(senderPlayer)); - } catch (CommandSyntaxException e) { - source.sendError(TextUtil.concat( - ECText.getInstance().getText("cmd.home.feedback.1").setStyle(CONFIG.FORMATTING_ERROR.getValue()), - new LiteralText(homeName).setStyle(CONFIG.FORMATTING_ACCENT.getValue()), - ECText.getInstance().getText("cmd.home.set.error.exists.2").setStyle(CONFIG.FORMATTING_ERROR.getValue()) - )); - } - - pData.markDirty(); - pData.save(); + var homeNameText = ECText.access(senderPlayer).accent(homeName); + playerData.addHome(homeName, new MinecraftLocation(senderPlayer)); + + playerData.save(); //inform command sender that the home has been set - if (successCode == 1) { - source.sendFeedback( - ECText.getInstance().getText("cmd.home.feedback.1").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()) - .append(new LiteralText(homeName).setStyle(CONFIG.FORMATTING_ACCENT.getValue())) - .append(ECText.getInstance().getText("cmd.home.set.feedback.2").setStyle(CONFIG.FORMATTING_DEFAULT.getValue())), - CONFIG.BROADCAST_TO_OPS.getValue() - ); - } - - return successCode; + playerData.sendCommandFeedback("cmd.home.set.feedback", homeNameText); + + return 0; } } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/HomeTeleportOtherCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/HomeTeleportOtherCommand.java new file mode 100644 index 00000000..93cdc7ea --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/commands/HomeTeleportOtherCommand.java @@ -0,0 +1,131 @@ +package com.fibermc.essentialcommands.commands; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.fibermc.essentialcommands.ManagerLocator; +import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; +import com.fibermc.essentialcommands.commands.suggestions.ListSuggestion; +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.playerdata.PlayerProfile; +import com.fibermc.essentialcommands.text.ECText; +import com.fibermc.essentialcommands.types.NamedMinecraftLocation; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.SuggestionProvider; + +import net.minecraft.command.argument.EntityArgumentType; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.Text; + +import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; + +public class HomeTeleportOtherCommand extends HomeCommand implements Command { + @Override + public int run(CommandContext context) throws CommandSyntaxException { + PlayerData senderPlayerData = ((ServerPlayerEntityAccess) context.getSource().getPlayer()).ec$getPlayerData(); + String homeName = StringArgumentType.getString(context, "home_name"); + + return HomeCommand.exec(senderPlayerData, getTargetPlayerData(context), homeName); + } + + private static PlayerData getTargetPlayerData(CommandContext context) throws CommandSyntaxException { + return ((ServerPlayerEntityAccess) EntityArgumentType.getPlayer(context, "target_player")).ec$getPlayerData(); + } + + public int runDefault(CommandContext context) throws CommandSyntaxException { + var senderPlayerData = ((ServerPlayerEntityAccess) context.getSource().getPlayer()).ec$getPlayerData(); + var targetPlayerData = getTargetPlayerData(context); + + return HomeCommand.exec( + senderPlayerData, + targetPlayerData, + HomeCommand.getSoleHomeName(targetPlayerData) + ); + } + + public int runOfflinePlayer(CommandContext context) throws CommandSyntaxException { + PlayerData senderPlayerData = ((ServerPlayerEntityAccess) context.getSource().getPlayer()).ec$getPlayerData(); + String homeName = StringArgumentType.getString(context, "home_name"); + + var targetPlayerName = StringArgumentType.getString(context, "target_player"); + ManagerLocator.getInstance() + .getOfflinePlayerRepo() + .getOfflinePlayerByNameAsync(targetPlayerName) + .whenComplete((playerEntity, err) -> { + if (playerEntity == null) { + context.getSource().sendError(Text.of("No player with the specified name found.")); + return; + } + + var targetPlayerData = ((ServerPlayerEntityAccess) playerEntity).ec$getPlayerData(); + + try { + HomeCommand.exec( + senderPlayerData, + targetPlayerData, + homeName + ); + } catch (CommandSyntaxException e) { + context.getSource().sendError(ECText.access(senderPlayerData.getPlayer()).error(e.getMessage())); + } + }); + return 1; + + } + + public static int runListOffline(CommandContext context) throws CommandSyntaxException { + var targetPlayerName = StringArgumentType.getString(context, "target_player"); + var senderPlayerProfile = PlayerProfile.accessFromContextOrThrow(context); + ManagerLocator.getInstance() + .getOfflinePlayerRepo() + .getOfflinePlayerByNameAsync(targetPlayerName) + .whenComplete((targetPlayerEntity, err) -> { + if (targetPlayerEntity == null) { + context.getSource().sendError(Text.of("No player with the specified name found.")); + return; + } + + var targetPlayerData = ((ServerPlayerEntityAccess) targetPlayerEntity).ec$getPlayerData(); + var suggestionText = ListCommandFactory.getSuggestionText( + ECText.getInstance().getString("cmd.home.list.start"), + "home tp_offline %s".formatted(targetPlayerName), + targetPlayerData.getHomeEntries(), + senderPlayerProfile + ); + + context.getSource().sendFeedback( + suggestionText, + CONFIG.BROADCAST_TO_OPS + ); + + }); + return 0; + } + + public static class Suggestion { + //Brigader Suggestions + public static final SuggestionProvider LIST_SUGGESTION_PROVIDER + = ListSuggestion.ofContext(HomeTeleportOtherCommand.Suggestion::getSuggestionsList); + + /** + * Gets a list of suggested strings to be used with Brigader + */ + public static List getSuggestionsList(CommandContext context) throws CommandSyntaxException { + return new ArrayList<>(HomeTeleportOtherCommand.getTargetPlayerData(context).getHomeNames()); + } + + /** + * Gets a set of suggestion entries to be used with ListCommandFactory + */ + public static Set> getSuggestionEntries(CommandContext context) throws CommandSyntaxException { + return HomeTeleportOtherCommand.getTargetPlayerData(context).getHomeEntries(); + } + + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/InvulnCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/InvulnCommand.java new file mode 100644 index 00000000..86f040f9 --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/commands/InvulnCommand.java @@ -0,0 +1,58 @@ +package com.fibermc.essentialcommands.commands; + +import com.fibermc.essentialcommands.ECAbilitySources; +import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; +import com.fibermc.essentialcommands.text.TextFormatType; +import io.github.ladysnake.pal.Pal; +import io.github.ladysnake.pal.VanillaAbilities; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.arguments.BoolArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; + +public class InvulnCommand implements Command { + @Override + public int run(CommandContext context) throws CommandSyntaxException { + ServerCommandSource source = context.getSource(); + ServerPlayerEntity targetPlayer = CommandUtil.getCommandTargetPlayer(context); + + boolean shouldEnableInvuln; + try { + // Prefer explicitly specified flight state from commands args... + shouldEnableInvuln = BoolArgumentType.getBool(context, "invuln_enabled"); + } catch (IllegalArgumentException e) { + shouldEnableInvuln = !VanillaAbilities.INVULNERABLE + .getTracker(targetPlayer).isGrantedBy(ECAbilitySources.INVULN_COMMAND); + } + + exec(targetPlayer, shouldEnableInvuln); + + // TODO Label boolean values in suggestions, or switch to single state value (present, or it's not) + + var senderPlayerAccess = ((ServerPlayerEntityAccess) source.getPlayer()); + var enabledText = senderPlayerAccess.ec$getEcText().getText( + shouldEnableInvuln ? "generic.enabled" : "generic.disabled", + TextFormatType.Accent); + + senderPlayerAccess.ec$getPlayerData().sendCommandFeedback( + "cmd.invuln.feedback", + enabledText, + targetPlayer.getDisplayName() + ); + + return 0; + } + + public static void exec(ServerPlayerEntity target, boolean shouldEnableInvuln) { + if (shouldEnableInvuln) { + Pal.grantAbility(target, VanillaAbilities.INVULNERABLE, ECAbilitySources.INVULN_COMMAND); + } else { + Pal.revokeAbility(target, VanillaAbilities.INVULNERABLE, ECAbilitySources.INVULN_COMMAND); + } + target.sendAbilitiesUpdate(); + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/ListCommandFactory.java b/src/main/java/com/fibermc/essentialcommands/commands/ListCommandFactory.java index 87605ba7..db61ceb1 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/ListCommandFactory.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/ListCommandFactory.java @@ -1,51 +1,74 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.ECText; +import java.util.Collection; +import java.util.List; +import java.util.Map.Entry; +import java.util.stream.Collectors; + import com.fibermc.essentialcommands.commands.suggestions.SuggestionListProvider; -import com.fibermc.essentialcommands.types.MinecraftLocation; -import com.fibermc.essentialcommands.util.TextUtil; +import com.fibermc.essentialcommands.playerdata.PlayerProfile; +import com.fibermc.essentialcommands.text.ECText; +import com.fibermc.essentialcommands.text.TextFormatType; +import com.fibermc.essentialcommands.types.IStyleProvider; + import com.mojang.brigadier.Command; import com.mojang.brigadier.context.CommandContext; + import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.text.LiteralText; import net.minecraft.text.MutableText; import net.minecraft.text.Text; -import java.util.Collection; -import java.util.List; -import java.util.Map.Entry; -import java.util.stream.Collectors; +import dev.jpcode.eccore.util.TextUtil; import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; -import static com.fibermc.essentialcommands.util.TextUtil.clickableTeleport; +import static dev.jpcode.eccore.util.TextUtil.clickableTeleport; + +public final class ListCommandFactory { + private ListCommandFactory() {} -public class ListCommandFactory { // Specify leading response text, and supplier of list of strings/Text - public static Command create(String responsePreText, String commandExecText, SuggestionListProvider> suggestionsProvider) { + public static Command create( + String responsePreText, + String commandExecText, + SuggestionListProvider> suggestionsProvider) + { return (CommandContext context) -> { - MutableText responseText = new LiteralText(""); - responseText.append(new LiteralText(responsePreText).setStyle(CONFIG.FORMATTING_DEFAULT.getValue())); - Collection> suggestionsList = suggestionsProvider.getSuggestionList(context); + var styleProvider = PlayerProfile.accessFromContextOrThrow(context); + Collection> suggestionsList = suggestionsProvider.getSuggestionList(context); - List suggestionTextList = suggestionsList.stream().map((entry) -> clickableTeleport( - new LiteralText(entry.getKey()).setStyle(CONFIG.FORMATTING_ACCENT.getValue()), - entry.getKey(), - String.format("/%s", commandExecText)) - ).collect(Collectors.toList()); - - if (suggestionTextList.size() > 0) { - responseText.append(TextUtil.join( - suggestionTextList, - new LiteralText(", ").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()) - )); - } else { - responseText.append(ECText.getInstance().getText("cmd.list.feedback.empty").setStyle(CONFIG.FORMATTING_ERROR.getValue())); - } context.getSource().sendFeedback( - responseText, - CONFIG.BROADCAST_TO_OPS.getValue() + getSuggestionText(responsePreText, commandExecText, suggestionsList, styleProvider), + CONFIG.BROADCAST_TO_OPS ); return 0; }; } + + public static Text getSuggestionText( + String responsePreText, + String commandExecText, + Collection> suggestionsList, + IStyleProvider styleProvider) + { + MutableText responseText = TextUtil.empty() + .append(TextUtil.literal(responsePreText).setStyle(styleProvider.getStyle(TextFormatType.Default))); + + List suggestionTextList = suggestionsList.stream() + .map((entry) -> clickableTeleport( + TextUtil.literal(entry.getKey()).setStyle(styleProvider.getStyle(TextFormatType.Accent)), + entry.getKey(), + String.format("/%s", commandExecText) + )) + .collect(Collectors.toList()); + + if (suggestionTextList.size() > 0) { + responseText.append(TextUtil.join( + suggestionTextList, + TextUtil.literal(", ").setStyle(styleProvider.getStyle(TextFormatType.Default)) + )); + } else { + responseText.append(ECText.getInstance().getText("cmd.list.feedback.empty", TextFormatType.Error, styleProvider)); + } + return responseText; + } } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/ModInfoCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/ModInfoCommand.java index 8d8234de..9d92704b 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/ModInfoCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/ModInfoCommand.java @@ -1,14 +1,16 @@ package com.fibermc.essentialcommands.commands; import com.fibermc.essentialcommands.EssentialCommands; +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.text.ECText; + import com.mojang.brigadier.Command; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import dev.jpcode.eccore.util.TextUtil; + import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.text.LiteralText; -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; +import dev.jpcode.eccore.util.TextUtil; public class ModInfoCommand implements Command { @@ -16,12 +18,13 @@ public class ModInfoCommand implements Command { @Override public int run(CommandContext context) throws CommandSyntaxException { - - context.getSource().sendFeedback(TextUtil.concat( - new LiteralText(EssentialCommands.MOD_METADATA.getName()).setStyle(CONFIG.FORMATTING_DEFAULT.getValue()), - new LiteralText(" "), - new LiteralText(modVersion).setStyle(CONFIG.FORMATTING_ACCENT.getValue()) - ), false); + var senderPlayer = context.getSource().getPlayer(); + var ecText = ECText.access(senderPlayer); + PlayerData.access(senderPlayer).sendCommandFeedback(TextUtil.concat( + ecText.literal(EssentialCommands.MOD_METADATA.getName()), + TextUtil.literal(" "), + ecText.accent(modVersion) + )); return 0; } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/NicknameClearCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/NicknameClearCommand.java index f2133558..4c5509f8 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/NicknameClearCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/NicknameClearCommand.java @@ -1,44 +1,31 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.ECText; -import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; -import com.fibermc.essentialcommands.util.TextUtil; +import com.fibermc.essentialcommands.playerdata.PlayerData; + import com.mojang.brigadier.Command; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.minecraft.command.argument.EntityArgumentType; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.LiteralText; - -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; +import net.minecraft.server.command.ServerCommandSource; -public class NicknameClearCommand implements Command { - public NicknameClearCommand() {} +import dev.jpcode.eccore.util.TextUtil; +public class NicknameClearCommand implements Command { @Override public int run(CommandContext context) throws CommandSyntaxException { - //Store command sender - ServerPlayerEntity senderPlayerEntity = context.getSource().getPlayer(); - ServerPlayerEntity targetPlayer; - try { - targetPlayer = EntityArgumentType.getPlayer(context, "target"); - } catch (IllegalArgumentException e) { - targetPlayer = senderPlayerEntity; - } - - ServerPlayerEntityAccess targetPlayerEntityAccess = (ServerPlayerEntityAccess) targetPlayer; - targetPlayerEntityAccess.getEcPlayerData().setNickname(null); + var senderPlayerData = PlayerData.accessFromContextOrThrow(context); + + var targetPlayer = CommandUtil.getCommandTargetPlayer(context); + var targetPlayerData = PlayerData.access(targetPlayer); + + targetPlayerData.setNickname(null); //inform command sender that the nickname has been set - context.getSource().sendFeedback(TextUtil.concat( - ECText.getInstance().getText("cmd.nickname.set.feedback").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()), - new LiteralText(targetPlayer.getGameProfile().getName()), - ECText.getInstance().getText("generic.quote_fullstop").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()) - ), CONFIG.BROADCAST_TO_OPS.getValue()); + senderPlayerData.sendCommandFeedback( + "cmd.nickname.set.feedback", + TextUtil.literal(targetPlayer.getGameProfile().getName()) + ); return 1; } - } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/NicknameSetCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/NicknameSetCommand.java index 5e9283c3..835017cb 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/NicknameSetCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/NicknameSetCommand.java @@ -1,28 +1,31 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.ECText; -import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; -import com.fibermc.essentialcommands.util.TextUtil; +import com.fibermc.essentialcommands.ECPerms; +import com.fibermc.essentialcommands.commands.helpers.FeedbackReceiver; +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.text.ECText; +import com.fibermc.essentialcommands.text.TextFormatType; +import eu.pb4.placeholders.PlaceholderAPI; + import com.mojang.brigadier.Command; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.minecraft.command.argument.EntityArgumentType; + import net.minecraft.command.argument.TextArgumentType; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.LiteralText; import net.minecraft.text.MutableText; import net.minecraft.text.Text; +import net.minecraft.text.Texts; -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; +import dev.jpcode.eccore.util.TextUtil; -public class NicknameSetCommand implements Command { - public NicknameSetCommand() {} +import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; +public class NicknameSetCommand implements Command { @Override public int run(CommandContext context) throws CommandSyntaxException { - //Get specified new nickname return exec(context, TextArgumentType.getTextArgument(context, "nickname")); } @@ -31,50 +34,46 @@ public static int runStringToText(CommandContext context) t return 1; } - public static ServerPlayerEntity getTargetPlayer(CommandContext context) throws CommandSyntaxException { - ServerPlayerEntity targetPlayer; - try { - targetPlayer = EntityArgumentType.getPlayer(context, "target"); - } catch (IllegalArgumentException e) { - targetPlayer = context.getSource().getPlayer(); - } - return targetPlayer; - } + public static int exec(CommandContext context, Text rawNicknameText) throws CommandSyntaxException { + ServerPlayerEntity targetPlayer = CommandUtil.getCommandTargetPlayer(context); - public static int exec(CommandContext context, Text nicknameText) throws CommandSyntaxException { - ServerCommandSource source = context.getSource(); + var nicknameWithContext = ECPerms.check(context.getSource(), ECPerms.Registry.nickname_selector_and_ctx, 2) + ? Texts.parse( + context.getSource(), + rawNicknameText, + targetPlayer, + 0) + : rawNicknameText; - ServerPlayerEntity targetPlayer = getTargetPlayer(context); + var nicknameText = ECPerms.check(context.getSource(), ECPerms.Registry.nickname_placeholders, 2) + ? PlaceholderAPI.parseText(nicknameWithContext, targetPlayer) + : nicknameWithContext; + int successCode = PlayerData.access(targetPlayer).setNickname(nicknameText); - ServerPlayerEntityAccess targetPlayerEntityAccess = (ServerPlayerEntityAccess) targetPlayer; - int successCode = targetPlayerEntityAccess.getEcPlayerData().setNickname(nicknameText); + var senderPlayer = context.getSource().getPlayer(); + var senderFeedbackReceiver = FeedbackReceiver.ofSource(context.getSource()); + + var ecText = ECText.access(senderPlayer); //inform command sender that the nickname has been set if (successCode >= 0) { - source.sendFeedback(TextUtil.concat( - ECText.getInstance().getText("cmd.nickname.set.feedback").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()), - (nicknameText != null) ? nicknameText : new LiteralText(targetPlayer.getGameProfile().getName()), - ECText.getInstance().getText("generic.quote_fullstop").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()) - ), CONFIG.BROADCAST_TO_OPS.getValue()); + senderFeedbackReceiver.sendCommandFeedback( + "cmd.nickname.set.feedback", + nicknameText != null ? nicknameText : TextUtil.literal(targetPlayer.getGameProfile().getName()) + ); } else { MutableText failReason = switch (successCode) { - case -1 -> ECText.getInstance().getText("cmd.nickname.set.error.perms"); - case -2 -> ECText.getInstance().getText( - "cmd.nickname.set.error.length", - nicknameText.getString().length(), - CONFIG.NICKNAME_MAX_LENGTH.getValue() + case -1 -> ecText.getText("cmd.nickname.set.error.perms", TextFormatType.Error); + case -2 -> ecText.getText( + "cmd.nickname.set.error.length", TextFormatType.Error, + ecText.accent(String.valueOf(nicknameText.getString().length())), + ecText.accent(String.valueOf(CONFIG.NICKNAME_MAX_LENGTH)) ); - default -> ECText.getInstance().getText("generic.error.unknown"); + default -> ecText.getText("generic.error.unknown", TextFormatType.Error); }; - source.sendError(TextUtil.concat( - ECText.getInstance().getText("cmd.nickname.set.error.1").setStyle(CONFIG.FORMATTING_ERROR.getValue()), - nicknameText, - ECText.getInstance().getText("cmd.nickname.set.error.2").setStyle(CONFIG.FORMATTING_ERROR.getValue()), - failReason.setStyle(CONFIG.FORMATTING_ERROR.getValue()) - )); + senderFeedbackReceiver.sendCommandError("cmd.nickname.set.error", nicknameText, failReason); } return successCode; } - } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/ProfileCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/ProfileCommand.java new file mode 100644 index 00000000..0ae17f1a --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/commands/ProfileCommand.java @@ -0,0 +1,58 @@ +package com.fibermc.essentialcommands.commands; + +import java.util.Map; + +import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; +import com.fibermc.essentialcommands.playerdata.PlayerProfile; +import com.fibermc.essentialcommands.types.ProfileOption; + +import com.mojang.brigadier.tree.LiteralCommandNode; + +import net.minecraft.server.command.CommandManager; +import net.minecraft.server.command.ServerCommandSource; + +import dev.jpcode.eccore.util.TextUtil; + +import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; +import static net.minecraft.server.command.CommandManager.argument; + +public final class ProfileCommand { + private ProfileCommand() {} + + public static LiteralCommandNode buildNode() { + var root = CommandManager.literal("profile"); + var set = CommandManager.literal("set"); + var get = CommandManager.literal("get"); + + for (Map.Entry> entry : PlayerProfile.OPTIONS.entrySet()) { + var name = entry.getKey(); + var option = entry.getValue(); + + set.then(CommandManager.literal(name) + .then(argument("value", option.argumentType()).executes((context) -> { + var player = context.getSource().getPlayer(); + var profile = ((ServerPlayerEntityAccess) player).ec$getProfile(); + option.profileSetter().setValue(context, "value", profile); + profile.markDirty(); + profile.save(); + return 0; + })) + ); + + get.then(CommandManager.literal(name) + .executes((context) -> { + var player = context.getSource().getPlayer(); + var profile = ((ServerPlayerEntityAccess) player).ec$getProfile(); + context.getSource().sendFeedback( + TextUtil.literal(option.profileGetter().getValue(profile).toString()), + CONFIG.BROADCAST_TO_OPS); + return 0; + }) + ); + } + + root.then(set); + root.then(get); + return root.build(); + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/RandomTeleportCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/RandomTeleportCommand.java index 5d570003..efae50ba 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/RandomTeleportCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/RandomTeleportCommand.java @@ -1,44 +1,83 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.*; +import java.util.Random; + +import com.fibermc.essentialcommands.EssentialCommands; +import com.fibermc.essentialcommands.ManagerLocator; import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.teleportation.PlayerTeleporter; +import com.fibermc.essentialcommands.text.ECText; +import com.fibermc.essentialcommands.text.TextFormatType; import com.fibermc.essentialcommands.types.MinecraftLocation; -import com.fibermc.essentialcommands.util.TextUtil; import com.google.common.base.Stopwatch; + import com.mojang.brigadier.Command; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; + import net.minecraft.block.BlockState; +import net.minecraft.block.Material; +import net.minecraft.command.CommandException; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; -import net.minecraft.text.LiteralText; -import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.RaycastContext; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; -import java.util.Random; +import dev.jpcode.eccore.util.TextUtil; import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; +import static com.fibermc.essentialcommands.commands.TopCommand.getTop; /** + *

* Heavily referenced from * https://github.com/javachaos/randomteleport/blob/master/src/main/java/net.ethermod/commands/RandomTeleportCommand.java + *

+ *

+ * Additionally, tons of optimization tips & examples provided by @Wesley1808 on GitHub: + * https://github.com/Wesley1808/ServerCore/issues/16 + *

*/ - +@SuppressWarnings("checkstyle:all") public class RandomTeleportCommand implements Command { public RandomTeleportCommand() {} @Override public int run(CommandContext context) throws CommandSyntaxException { - int resultCode = -1; - ServerPlayerEntity player = context.getSource().getPlayer(); ServerWorld world = context.getSource().getWorld(); + var ecText = ECText.access(player); + if (!world.getRegistryKey().equals(World.OVERWORLD)) { + throw new CommandException(TextUtil.concat( + ecText.getText("cmd.rtp.error.pre", TextFormatType.Error), + ecText.getText("cmd.rtp.error.not_overworld", TextFormatType.Error) + )); + } + + //TODO Add OP/Permission bypass for RTP cooldown. + if (CONFIG.RTP_COOLDOWN > 0) { + ServerCommandSource source = context.getSource(); + int curServerTickTime = source.getServer().getTicks(); + PlayerData playerData = ((ServerPlayerEntityAccess) player).ec$getPlayerData(); + var rtpCooldownEndTime = playerData.getTimeUsedRtp() + CONFIG.RTP_COOLDOWN * 20; + var rtpCooldownRemaining = rtpCooldownEndTime - curServerTickTime; + if (rtpCooldownRemaining > 0) { + throw new CommandException( + ecText.getText( + "cmd.rtp.error.cooldown", + TextFormatType.Error, + ecText.accent(String.format("%.1f", rtpCooldownRemaining / 20D))) + ); + } + // if cooldown has expired + playerData.setTimeUsedRtp(curServerTickTime); + } - Thread thread = new Thread("RTP Location Calculator Thread") { + new Thread("RTP Location Calculator Thread") { public void run() { try { exec(context.getSource(), world); @@ -46,85 +85,72 @@ public void run() { e.printStackTrace(); } } - }; - - //TODO Add OP/Permission bypass for RTP cooldown. - if (CONFIG.RTP_COOLDOWN.getValue() > 0) { - ServerCommandSource source = context.getSource(); - int ticks = source.getServer().getTicks(); - PlayerData playerData = ((ServerPlayerEntityAccess)player).getEcPlayerData(); - // if cooldown has expired - if (playerData.getRtpNextUsableTime() < ticks) { - playerData.setRtpNextUsableTime(ticks + CONFIG.RTP_COOLDOWN.getValue()*20); - thread.start(); - resultCode = 1; - } else { - source.sendError(TextUtil.concat( - ECText.getInstance().getText("cmd.rtp.error.cooldown.1").setStyle(CONFIG.FORMATTING_ERROR.getValue()), - new LiteralText(String.format("%.1f", (playerData.getRtpNextUsableTime() - ticks)/20D)).setStyle(CONFIG.FORMATTING_ACCENT.getValue()), - ECText.getInstance().getText("cmd.rtp.error.cooldown.2").setStyle(CONFIG.FORMATTING_ERROR.getValue()) - )); - resultCode = -2; - } - } else { - thread.start(); - resultCode = 1; - } - - return resultCode; + }.start(); + return 1; } private static boolean isValidSpawnPosition(ServerWorld world, double x, double y, double z) { // TODO This should be memoized. Cuts exec time in 1/2. BlockState targetBlockState = world.getBlockState(new BlockPos(x, y, z)); - BlockState footBlockState = world.getBlockState(new BlockPos(x, y-1, z)); + BlockState footBlockState = world.getBlockState(new BlockPos(x, y - 1, z)); return targetBlockState.isAir() && footBlockState.getMaterial().isSolid(); } private static int exec(ServerCommandSource source, ServerWorld world) throws CommandSyntaxException { // Position relative to EC spawn locaiton. MinecraftLocation center = ManagerLocator.getInstance().getWorldDataManager().getSpawn(); + var ecText = ECText.access(source.getPlayer()); if (center == null) { source.sendError(TextUtil.concat( - ECText.getInstance().getText("cmd.rtp.error.pre"), - ECText.getInstance().getText("cmd.rtp.error.no_spawn_set") + ecText.getText("cmd.rtp.error.pre", TextFormatType.Error), + ecText.getText("cmd.rtp.error.no_spawn_set", TextFormatType.Error) )); return -1; } return exec(source.getPlayer(), world, center, 0); } + private static final ThreadLocal maxY = new ThreadLocal<>(); + private static int exec(ServerPlayerEntity player, ServerWorld world, MinecraftLocation center, int timesRun) { - if (timesRun > CONFIG.RTP_MAX_ATTEMPTS.getValue()) { + var ecText = ECText.access(player); + if (timesRun > CONFIG.RTP_MAX_ATTEMPTS) { return -1; } + maxY.set(world.getHeight()); // TODO: Per-world, preset maximums (or some other mechanism of making this work in the nether) // Calculate position on circle perimeter - int r = CONFIG.RTP_RADIUS.getValue(); - double angle = (new Random()).nextDouble()*2*Math.PI; - double delta_x = r * Math.cos(angle); - double delta_z = r * Math.sin(angle); - - double new_x = center.pos.x + delta_x; - double new_z = center.pos.z + delta_z; + var rand = new Random(); + int r_max = CONFIG.RTP_RADIUS; + int r_min = CONFIG.RTP_MIN_RADIUS; + int r = r_max == r_min + ? r_max + : rand.nextInt(r_min, r_max); + final double angle = rand.nextDouble() * 2 * Math.PI; + final double delta_x = r * Math.cos(angle); + final double delta_z = r * Math.sin(angle); + + final double new_x = center.pos().x + delta_x; + final double new_z = center.pos().z + delta_z; // Search for a valid y-level (not in a block, underwater, out of the world, etc.) - // TODO Can maybe run a loop that checks every-other block? (player is 2 blocks high) int new_y; - Stopwatch timer = Stopwatch.createStarted(); - BlockHitResult blockHitResult = world.raycast(new RaycastContext( - new Vec3d(new_x, world.getHeight(), new_z), - new Vec3d(new_x, 1, new_z), - RaycastContext.ShapeType.COLLIDER, - RaycastContext.FluidHandling.SOURCE_ONLY, - player - )); - new_y = blockHitResult.getBlockPos().getY() + 1; - - EssentialCommands.LOGGER.info(ECText.getInstance().getText("cmd.rtp.log.location_validate_time", timer.stop()).getString()); + final BlockPos targetXZ = new BlockPos(new_x, 0, new_z); + + Chunk chunk = world.getChunk(targetXZ); + + { + Stopwatch timer = Stopwatch.createStarted(); + new_y = getTop(chunk, (int) new_x, (int) new_z); + EssentialCommands.LOGGER.info( + ECText.getInstance().getText( + "cmd.rtp.log.location_validate_time", + TextUtil.literal(String.valueOf(timer.stop())) + ).getString()); + } // This creates an infinite recursive call in the case where all positions on RTP circle are in water. // Addressed by adding timesRun limit. - if (world.isWater(new BlockPos(new_x, new_y-2, new_z))) { + if (!isSafePosition(chunk, new BlockPos(new_x, new_y - 2, new_z))) { return exec(player, world, center, timesRun + 1); } @@ -132,10 +158,19 @@ private static int exec(ServerPlayerEntity player, ServerWorld world, MinecraftL PlayerTeleporter.requestTeleport( player, new MinecraftLocation(world.getRegistryKey(), new_x, new_y, new_z, 0, 0), - ECText.getInstance().getText("cmd.rtp.location_name") + ecText.getText("cmd.rtp.location_name") ); return 1; } + private static boolean isSafePosition(Chunk chunk, BlockPos pos) { + if (pos.getY() <= chunk.getBottomY()) { + return false; + } + + var material = chunk.getBlockState(pos).getMaterial(); + return pos.getY() < maxY.get() && !material.isLiquid() && material != Material.FIRE; + } + } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/RealNameCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/RealNameCommand.java index c7258c73..6e3c7140 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/RealNameCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/RealNameCommand.java @@ -1,17 +1,20 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.ECText; -import com.fibermc.essentialcommands.PlayerData; -import com.fibermc.essentialcommands.PlayerDataManager; +import java.util.List; + +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.playerdata.PlayerDataManager; +import com.fibermc.essentialcommands.text.ECText; + import com.mojang.brigadier.Command; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; + import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.text.LiteralText; import net.minecraft.text.MutableText; -import java.util.List; +import dev.jpcode.eccore.util.TextUtil; import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; @@ -21,30 +24,26 @@ public int run(CommandContext context) throws CommandSyntax String nicknameStr = StringArgumentType.getString(context, "player_nickname"); List nicknamePlayers = PlayerDataManager.getInstance().getPlayerDataMatchingNickname(nicknameStr); - MutableText responseText = new LiteralText(""); + MutableText responseText = TextUtil.empty(); + var ecText = ECText.access(context.getSource().getPlayer()); + var nicknameText = ecText.accent(nicknameStr); // If no players matched the provided nickname if (nicknamePlayers.size() == 0) { responseText - .append(ECText.getInstance().getText("cmd.realname.feedback.none_match").setStyle(CONFIG.FORMATTING_DEFAULT.getValue())) - .append(new LiteralText(nicknameStr).setStyle(CONFIG.FORMATTING_ACCENT.getValue())) - .append(ECText.getInstance().getText("generic.quote_fullstop").setStyle(CONFIG.FORMATTING_DEFAULT.getValue())); + .append(ecText.getText("cmd.realname.feedback.none_match", nicknameText)); } else { responseText - .append(ECText.getInstance().getText("cmd.realname.feedback.matching.1").setStyle(CONFIG.FORMATTING_DEFAULT.getValue())) - .append(new LiteralText(nicknameStr).setStyle(CONFIG.FORMATTING_ACCENT.getValue())) - .append(ECText.getInstance().getText("cmd.realname.feedback.matching.2").setStyle(CONFIG.FORMATTING_DEFAULT.getValue())); + .append(ecText.getText("cmd.realname.feedback.matching", nicknameText)); for (PlayerData nicknamePlayer : nicknamePlayers) { responseText.append("\n "); responseText.append(nicknamePlayer.getPlayer().getGameProfile().getName()); } - } - context.getSource().sendFeedback( - responseText, CONFIG.BROADCAST_TO_OPS.getValue() - ); + + context.getSource().sendFeedback(responseText, CONFIG.BROADCAST_TO_OPS); return 0; } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/RulesCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/RulesCommand.java new file mode 100644 index 00000000..9daa1d4f --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/commands/RulesCommand.java @@ -0,0 +1,52 @@ +package com.fibermc.essentialcommands.commands; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import com.fibermc.essentialcommands.EssentialCommands; +import com.fibermc.essentialcommands.playerdata.PlayerData; + +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.Text; + +import dev.jpcode.eccore.util.TextUtil; + +public final class RulesCommand { + + private RulesCommand() {} + + private static Text rulesText; + + public static int run(CommandContext context) throws CommandSyntaxException { + context.getSource().sendFeedback(rulesText, false); + return 0; + } + + public static int reloadCommand(CommandContext context) throws CommandSyntaxException { + var playerData = PlayerData.accessFromContextOrThrow(context); + try { + reload(context.getSource().getServer()); + playerData.sendCommandFeedback("rules.reload.success"); + } catch (IOException e) { + playerData.sendCommandError("rules.reload.error.unexpected"); + e.printStackTrace(); + } + return 0; + } + + @SuppressWarnings("ResultOfMethodCallIgnored") + public static void reload(MinecraftServer server) throws IOException { + Path mcDir = server.getRunDirectory().toPath(); + var rulesFile = mcDir.resolve("config/essentialcommands/rules.txt").toFile(); + EssentialCommands.LOGGER.info("Ensuring rules file exists at path: " + rulesFile.toPath()); + rulesFile.getParentFile().mkdirs(); + rulesFile.createNewFile(); + String rulesStr = Files.readString(rulesFile.toPath()); + rulesText = TextUtil.parseText(rulesStr); + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/SpawnCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/SpawnCommand.java index 8c18c23b..427ea6fe 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/SpawnCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/SpawnCommand.java @@ -1,45 +1,40 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.ECText; import com.fibermc.essentialcommands.ManagerLocator; -import com.fibermc.essentialcommands.PlayerTeleporter; import com.fibermc.essentialcommands.WorldDataManager; +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.teleportation.PlayerTeleporter; +import com.fibermc.essentialcommands.text.ECText; import com.fibermc.essentialcommands.types.MinecraftLocation; + import com.mojang.brigadier.Command; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.network.ServerPlayerEntity; - -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; +import net.minecraft.server.command.ServerCommandSource; public class SpawnCommand implements Command { - public SpawnCommand() { - } + public SpawnCommand() {} @Override public int run(CommandContext context) throws CommandSyntaxException { WorldDataManager worldDataManager = ManagerLocator.getInstance().getWorldDataManager(); - int out; - //Store command sender - ServerPlayerEntity senderPlayer = context.getSource().getPlayer(); - - //Get home location MinecraftLocation loc = worldDataManager.getSpawn(); - // Teleport & chat message - if (loc != null) { - //Teleport player to home location - PlayerTeleporter.requestTeleport(senderPlayer, loc, ECText.getInstance().getText("cmd.spawn.location_name")); - out = 1; - } else { - context.getSource().sendError(ECText.getInstance().getText("cmd.spawn.tp.error.no_spawn_set").setStyle(CONFIG.FORMATTING_ERROR.getValue())); - out = -2; + var playerData = PlayerData.accessFromContextOrThrow(context); + if (loc == null) { + playerData.sendCommandError("cmd.spawn.tp.error.no_spawn_set"); + return -2; } - return out; + var senderPlayer = context.getSource().getPlayer(); + + // Teleport & chat message + var styledLocationName = ECText.access(senderPlayer).getText("cmd.spawn.location_name"); + + PlayerTeleporter.requestTeleport(senderPlayer, loc, styledLocationName); + return 1; } } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/SpawnSetCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/SpawnSetCommand.java index d388e494..39ac61a1 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/SpawnSetCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/SpawnSetCommand.java @@ -1,17 +1,15 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.ECText; import com.fibermc.essentialcommands.ManagerLocator; -import com.fibermc.essentialcommands.WorldDataManager; +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.playerdata.PlayerProfile; import com.fibermc.essentialcommands.types.MinecraftLocation; + import com.mojang.brigadier.Command; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.network.ServerPlayerEntity; - -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; +import net.minecraft.server.command.ServerCommandSource; public class SpawnSetCommand implements Command { @@ -19,24 +17,20 @@ public SpawnSetCommand() {} @Override public int run(CommandContext context) throws CommandSyntaxException { - WorldDataManager worldDataManager = ManagerLocator.getInstance().getWorldDataManager(); - - ServerCommandSource source = context.getSource(); - //Store command sender - ServerPlayerEntity senderPlayer = source.getPlayer(); - - int successCode = 1; + var worldDataManager = ManagerLocator.getInstance().getWorldDataManager(); + var senderPlayer = context.getSource().getPlayer(); + var playerData = PlayerData.access(senderPlayer); //Set spawn - MinecraftLocation loc = new MinecraftLocation(senderPlayer); + var loc = new MinecraftLocation(senderPlayer); worldDataManager.setSpawn(loc); //inform command sender that the home has been set - source.sendFeedback( - ECText.getInstance().getText("cmd.spawn.set.feedback").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()) - .append(loc.toLiteralTextSimple().setStyle(CONFIG.FORMATTING_ACCENT.getValue())) - , CONFIG.BROADCAST_TO_OPS.getValue()); + playerData.sendCommandFeedback( + "cmd.spawn.set.feedback", + loc.toText(PlayerProfile.access(senderPlayer)) + ); - return successCode; + return 1; } } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/TeleportAcceptCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/TeleportAcceptCommand.java index e5ea4b9a..20f17e47 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/TeleportAcceptCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/TeleportAcceptCommand.java @@ -1,55 +1,40 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.ECText; -import com.fibermc.essentialcommands.PlayerData; -import com.fibermc.essentialcommands.TeleportRequest; -import com.fibermc.essentialcommands.TeleportRequestManager; import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.teleportation.TeleportRequest; + import com.mojang.brigadier.context.CommandContext; + import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.Util; - -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; public class TeleportAcceptCommand extends TeleportResponseCommand { - - public TeleportAcceptCommand() {} - protected int exec(CommandContext context, ServerPlayerEntity senderPlayer, ServerPlayerEntity targetPlayer) { - ServerCommandSource source = context.getSource(); - PlayerData targetPlayerData = ((ServerPlayerEntityAccess)targetPlayer).getEcPlayerData(); + var senderPlayerData = PlayerData.access(senderPlayer); + var targetPlayerData = ((ServerPlayerEntityAccess) targetPlayer).ec$getPlayerData(); //identify if target player did indeed request to teleport. Continue if so, otherwise throw exception. TeleportRequest teleportRequest = targetPlayerData.getSentTeleportRequest(); if (teleportRequest != null && teleportRequest.getTargetPlayer().equals(senderPlayer)) { //inform target player that teleport has been accepted via chat - targetPlayer.sendSystemMessage( - ECText.getInstance().getText("cmd.tpaccept.feedback").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()) - , Util.NIL_UUID); + targetPlayerData.sendMessage("cmd.tpaccept.feedback"); //Conduct teleportation teleportRequest.queue(); //Send message to command sender confirming that request has been accepted - source.sendFeedback( - ECText.getInstance().getText("cmd.tpaccept.feedback").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()) - , CONFIG.BROADCAST_TO_OPS.getValue()); + senderPlayerData.sendMessage("cmd.tpaccept.feedback"); - //Clean up TPAsk - targetPlayerData.setTpTimer(-1); // Remove the tp request, as it has been completed. - TeleportRequestManager.getInstance().endTpRequest(teleportRequest); + teleportRequest.end(); return 1; } else { - source.sendError( - ECText.getInstance().getText("cmd.tpa_reply.error.no_request_from_target").setStyle(CONFIG.FORMATTING_ERROR.getValue()) - ); + senderPlayerData.sendError("cmd.tpa_reply.error.no_request_from_target"); return -1; } } - } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/TeleportAskCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/TeleportAskCommand.java index 444244b9..c1a576ec 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/TeleportAskCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/TeleportAskCommand.java @@ -1,17 +1,19 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.*; -import com.fibermc.essentialcommands.util.TextUtil; +import com.fibermc.essentialcommands.ManagerLocator; +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.teleportation.TeleportManager; +import com.fibermc.essentialcommands.teleportation.TeleportRequest; +import com.fibermc.essentialcommands.text.ChatConfirmationPrompt; +import com.fibermc.essentialcommands.text.ECText; + import com.mojang.brigadier.Command; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; + import net.minecraft.command.argument.EntityArgumentType; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.LiteralText; -import net.minecraft.util.Util; - -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; public class TeleportAskCommand implements Command { @@ -19,36 +21,46 @@ public TeleportAskCommand() {} @Override public int run(CommandContext context) throws CommandSyntaxException { - TeleportRequestManager tpMgr = ManagerLocator.getInstance().getTpManager(); - //Store command sender + TeleportManager tpMgr = ManagerLocator.getInstance().getTpManager(); ServerPlayerEntity senderPlayer = context.getSource().getPlayer(); - //Store Target Player - ServerPlayerEntity targetPlayer = EntityArgumentType.getPlayer(context, "target"); + ServerPlayerEntity targetPlayer = EntityArgumentType.getPlayer(context, "target_player"); + var senderPlayerData = PlayerData.access(senderPlayer); + var targetPlayerData = PlayerData.access(targetPlayer); + + // Don't allow spamming same target. + { + var existingTeleportRequest = senderPlayerData.getSentTeleportRequest(); + if (existingTeleportRequest != null && existingTeleportRequest.getTargetPlayer().equals(targetPlayer)) { + PlayerData.access(senderPlayer).sendCommandError( + "cmd.tpask.error.exists", + existingTeleportRequest.getTargetPlayer().getDisplayName()); + return 0; + } + } //inform target player of tp request via chat - targetPlayer.sendSystemMessage(TextUtil.concat( - new LiteralText(senderPlayer.getEntityName()).setStyle(CONFIG.FORMATTING_ACCENT.getValue()), - ECText.getInstance().getText("cmd.tpask.receive").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()) - ), Util.NIL_UUID); + var targetPlayerEcText = ECText.access(targetPlayer); + targetPlayerData.sendMessage( + "cmd.tpask.receive", + targetPlayerEcText.accent(senderPlayer.getEntityName()) + ); - String senderName = context.getSource().getPlayer().getGameProfile().getName(); + String senderName = senderPlayer.getGameProfile().getName(); new ChatConfirmationPrompt( - targetPlayer, - "/tpaccept " + senderName, - "/tpdeny " + senderName, - new LiteralText("[" + ECText.getInstance().get("generic.accept") + "]").setStyle(CONFIG.FORMATTING_ACCENT.getValue()), - new LiteralText("[" + ECText.getInstance().get("generic.deny") + "]").setStyle(CONFIG.FORMATTING_ERROR.getValue()) + targetPlayer, + "/tpaccept " + senderName, + "/tpdeny " + senderName, + targetPlayerEcText.accent("[" + ECText.getInstance().getString("generic.accept") + "]"), + targetPlayerEcText.error("[" + ECText.getInstance().getString("generic.deny") + "]") ).send(); - + //Mark TPRequest Sender as having requested a teleport tpMgr.startTpRequest(senderPlayer, targetPlayer, TeleportRequest.Type.TPA_TO); //inform command sender that request has been sent - context.getSource().sendFeedback(TextUtil.concat( - new LiteralText("Teleport request has been sent to ").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()), - new LiteralText(targetPlayer.getEntityName()).setStyle(CONFIG.FORMATTING_ACCENT.getValue()) - ), CONFIG.BROADCAST_TO_OPS.getValue()); - + var targetPlayerText = ECText.access(senderPlayer).accent(targetPlayer.getEntityName()); + senderPlayerData.sendCommandFeedback("cmd.tpask.send", targetPlayerText); + return 1; } } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/TeleportAskHereCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/TeleportAskHereCommand.java index dc214090..9a89c6fe 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/TeleportAskHereCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/TeleportAskHereCommand.java @@ -1,17 +1,19 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.*; -import com.fibermc.essentialcommands.util.TextUtil; +import com.fibermc.essentialcommands.ManagerLocator; +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.teleportation.TeleportManager; +import com.fibermc.essentialcommands.teleportation.TeleportRequest; +import com.fibermc.essentialcommands.text.ChatConfirmationPrompt; +import com.fibermc.essentialcommands.text.ECText; + import com.mojang.brigadier.Command; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; + import net.minecraft.command.argument.EntityArgumentType; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.LiteralText; -import net.minecraft.util.Util; - -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; public class TeleportAskHereCommand implements Command { @@ -19,35 +21,45 @@ public TeleportAskHereCommand() {} @Override public int run(CommandContext context) throws CommandSyntaxException { - TeleportRequestManager tpMgr = ManagerLocator.getInstance().getTpManager(); - //Store command sender + TeleportManager tpMgr = ManagerLocator.getInstance().getTpManager(); ServerPlayerEntity senderPlayer = context.getSource().getPlayer(); - //Store Target Player - ServerPlayerEntity targetPlayer = EntityArgumentType.getPlayer(context, "target"); + ServerPlayerEntity targetPlayer = EntityArgumentType.getPlayer(context, "target_player"); + var senderPlayerData = PlayerData.access(senderPlayer); + var targetPlayerData = PlayerData.access(targetPlayer); + + // Don't allow spamming same target. + { + var existingTeleportRequest = senderPlayerData.getSentTeleportRequest(); + if (existingTeleportRequest != null && existingTeleportRequest.getTargetPlayer().equals(targetPlayer)) { + PlayerData.access(senderPlayer).sendCommandError( + "cmd.tpask.error.exists", + existingTeleportRequest.getTargetPlayer().getDisplayName()); + return 0; + } + } //inform target player of tp request via chat - targetPlayer.sendSystemMessage(TextUtil.concat( - new LiteralText(senderPlayer.getEntityName()).setStyle(CONFIG.FORMATTING_ACCENT.getValue()), - ECText.getInstance().getText("cmd.tpaskhere.receive").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()) - ), Util.NIL_UUID); + var targetPlayerEcText = ECText.access(targetPlayer); + targetPlayerData.sendMessage( + "cmd.tpaskhere.receive", + targetPlayerEcText.accent(senderPlayer.getEntityName()) + ); - String senderName = context.getSource().getPlayer().getGameProfile().getName(); + String senderName = senderPlayer.getGameProfile().getName(); new ChatConfirmationPrompt( - targetPlayer, - "/tpaccept " + senderName, - "/tpdeny " + senderName, - new LiteralText("[" + ECText.getInstance().get("generic.accept") + "]").setStyle(CONFIG.FORMATTING_ACCENT.getValue()), - new LiteralText("[" + ECText.getInstance().get("generic.deny") + "]").setStyle(CONFIG.FORMATTING_ERROR.getValue()) + targetPlayer, + "/tpaccept " + senderName, + "/tpdeny " + senderName, + targetPlayerEcText.accent("[" + ECText.getInstance().getString("generic.accept") + "]"), + targetPlayerEcText.error("[" + ECText.getInstance().getString("generic.deny") + "]") ).send(); //Mark TPRequest Sender as having requested a teleport tpMgr.startTpRequest(senderPlayer, targetPlayer, TeleportRequest.Type.TPA_HERE); //inform command sender that request has been sent - context.getSource().sendFeedback(TextUtil.concat( - new LiteralText("Teleport request has been sent to ").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()), - new LiteralText(targetPlayer.getEntityName()).setStyle(CONFIG.FORMATTING_ACCENT.getValue()) - ), CONFIG.BROADCAST_TO_OPS.getValue()); + var targetPlayerText = ECText.access(senderPlayer).accent(targetPlayer.getEntityName()); + senderPlayerData.sendCommandFeedback("cmd.tpask.send", targetPlayerText); return 1; } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/TeleportCancelCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/TeleportCancelCommand.java new file mode 100644 index 00000000..13a3b47e --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/commands/TeleportCancelCommand.java @@ -0,0 +1,38 @@ +package com.fibermc.essentialcommands.commands; + +import com.fibermc.essentialcommands.playerdata.PlayerData; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; + +public class TeleportCancelCommand implements Command { + + public TeleportCancelCommand() {} + + @Override + public int run(CommandContext context) throws CommandSyntaxException { + //Store command sender + ServerPlayerEntity senderPlayer = context.getSource().getPlayer(); + var senderPlayerData = PlayerData.access(senderPlayer); + + var existingTeleportRequest = senderPlayerData.getSentTeleportRequest(); + + if (existingTeleportRequest == null) { + senderPlayerData.sendCommandError("cmd.tpcancel.error.no_exists"); + return 0; + } + + existingTeleportRequest.end(); + + senderPlayerData.sendCommandFeedback( + "cmd.tpcancel.feedback", + existingTeleportRequest.getTargetPlayer().getDisplayName() + ); + + return 1; + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/TeleportDenyCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/TeleportDenyCommand.java index 107886c7..f4a8e8da 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/TeleportDenyCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/TeleportDenyCommand.java @@ -1,51 +1,34 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.ECText; -import com.fibermc.essentialcommands.PlayerData; -import com.fibermc.essentialcommands.TeleportRequest; -import com.fibermc.essentialcommands.TeleportRequestManager; -import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.teleportation.TeleportRequest; + import com.mojang.brigadier.context.CommandContext; + import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.Util; - -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; public class TeleportDenyCommand extends TeleportResponseCommand { - - public TeleportDenyCommand() {} - protected int exec(CommandContext context, ServerPlayerEntity senderPlayer, ServerPlayerEntity targetPlayer) { - ServerCommandSource source = context.getSource(); - PlayerData targetPlayerData = ((ServerPlayerEntityAccess)targetPlayer).getEcPlayerData(); + var targetPlayerData = PlayerData.access(targetPlayer); + var senderPlayerData = PlayerData.access(senderPlayer); //identify if target player did indeed request to teleport. Continue if so, otherwise throw exception. TeleportRequest teleportRequest = targetPlayerData.getSentTeleportRequest(); - if (teleportRequest != null && teleportRequest.getTargetPlayer().equals(senderPlayer)) { - //inform target player that teleport has been accepted via chat - targetPlayer.sendSystemMessage( - ECText.getInstance().getText("cmd.tpdeny.feedback").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()) - , Util.NIL_UUID); - - //Send message to command sender confirming that request has been accepted - source.sendFeedback( - ECText.getInstance().getText("cmd.tpdeny.feedback").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()) - , CONFIG.BROADCAST_TO_OPS.getValue() - ); - - //Clean up TPAsk - targetPlayerData.setTpTimer(-1); - // Remove the tp request, as it has been completed. - TeleportRequestManager.getInstance().endTpRequest(teleportRequest); - - return 1; - } else { - source.sendError( - ECText.getInstance().getText("cmd.tpa_reply.error.no_request_from_target").setStyle(CONFIG.FORMATTING_ERROR.getValue()) - ); + if (teleportRequest == null || !teleportRequest.getTargetPlayer().equals(senderPlayer)) { + senderPlayerData.sendCommandError("cmd.tpa_reply.error.no_request_from_target"); return -1; } + //inform target player that teleport has been accepted via chat + targetPlayerData.sendMessage("cmd.tpdeny.feedback"); + + //Send message to command sender confirming that request has been accepted + senderPlayerData.sendCommandFeedback("cmd.tpdeny.feedback"); + + // Remove the tp request, as it has been completed. + teleportRequest.end(); + + return 1; } } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/TeleportResponseCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/TeleportResponseCommand.java index 1e8fe963..697e35ff 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/TeleportResponseCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/TeleportResponseCommand.java @@ -1,53 +1,52 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.ECText; -import com.fibermc.essentialcommands.PlayerData; -import com.fibermc.essentialcommands.TeleportRequest; -import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; +import java.util.LinkedHashMap; +import java.util.UUID; + +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.teleportation.TeleportRequest; +import com.fibermc.essentialcommands.text.ECText; +import com.fibermc.essentialcommands.text.TextFormatType; + import com.mojang.brigadier.Command; -import com.mojang.brigadier.Message; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; + import net.minecraft.command.argument.EntityArgumentType; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; -import java.util.LinkedHashMap; -import java.util.UUID; - public abstract class TeleportResponseCommand implements Command { public int run(CommandContext context) throws CommandSyntaxException { return exec( - context, - context.getSource().getPlayer(), - EntityArgumentType.getPlayer(context, "target") + context, + context.getSource().getPlayer(), + EntityArgumentType.getPlayer(context, "target_player") ); } public int runDefault(CommandContext context) throws CommandSyntaxException { - ServerPlayerEntity senderPlayer = context.getSource().getPlayer(); - PlayerData senderPlayerData = ((ServerPlayerEntityAccess) senderPlayer).getEcPlayerData(); + var senderPlayer = context.getSource().getPlayer(); + var senderPlayerData = PlayerData.access(senderPlayer); + var ecText = ECText.access(senderPlayer); LinkedHashMap incomingTeleportRequests = senderPlayerData.getIncomingTeleportRequests(); - ServerPlayerEntity targetPlayer; if (incomingTeleportRequests.size() > 1) { - throw CommandUtil.createSimpleException(ECText.getInstance().getText("cmd.tpa_reply.error.shortcut_more_than_one")); + throw CommandUtil.createSimpleException( + ecText.getText("cmd.tpa_reply.error.shortcut_more_than_one", TextFormatType.Error)); } else if (incomingTeleportRequests.size() < 1) { - throw CommandUtil.createSimpleException(ECText.getInstance().getText("cmd.tpa_reply.error.shortcut_none_exist")); - } else { - targetPlayer = incomingTeleportRequests.values().stream().findFirst().get().getTargetPlayer(); - if (targetPlayer == null) { - throw CommandUtil.createSimpleException(ECText.getInstance().getText("cmd.tpa_reply.error.no_request_from_target")); - } + throw CommandUtil.createSimpleException( + ecText.getText("cmd.tpa_reply.error.shortcut_none_exist", TextFormatType.Error)); } - return exec( - context, - senderPlayer, - targetPlayer - ); + ServerPlayerEntity targetPlayer = incomingTeleportRequests.values().stream().findFirst().get().getTargetPlayer(); + if (targetPlayer == null) { + throw CommandUtil.createSimpleException( + ecText.getText("cmd.tpa_reply.error.no_request_from_target", TextFormatType.Error)); + } + + return exec(context, senderPlayer, targetPlayer); } abstract int exec(CommandContext context, ServerPlayerEntity senderPlayer, ServerPlayerEntity targetPlayer); diff --git a/src/main/java/com/fibermc/essentialcommands/commands/TopCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/TopCommand.java index b263d02b..7d43bc10 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/TopCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/TopCommand.java @@ -1,20 +1,24 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.ECText; -import com.fibermc.essentialcommands.PlayerTeleporter; +import com.fibermc.essentialcommands.teleportation.PlayerTeleporter; +import com.fibermc.essentialcommands.text.ECText; import com.fibermc.essentialcommands.types.MinecraftLocation; -import com.google.common.base.Stopwatch; + import com.mojang.brigadier.Command; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; + import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; -import net.minecraft.world.RaycastContext; import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.ChunkSection; public class TopCommand implements Command { + @SuppressWarnings("checkstyle:LocalVariableName") @Override public int run(CommandContext context) throws CommandSyntaxException { ServerCommandSource source = context.getSource(); @@ -26,26 +30,58 @@ public int run(CommandContext context) throws CommandSyntax double new_x = playerPos.x; double new_z = playerPos.z; - Stopwatch timer = Stopwatch.createStarted(); - BlockHitResult blockHitResult = world.raycast(new RaycastContext( - new Vec3d(new_x, world.getHeight(), new_z), - new Vec3d(new_x, 1, new_z), - RaycastContext.ShapeType.COLLIDER, - RaycastContext.FluidHandling.SOURCE_ONLY, - player - )); - new_y = blockHitResult.getBlockPos().getY() + 1; + final BlockPos targetXZ = new BlockPos(new_x, 0, new_z); + + Chunk chunk = world.getChunk(targetXZ); + new_y = getTop(chunk, (int) new_x, (int) new_z); // Teleport the player PlayerTeleporter.requestTeleport( - player, - new MinecraftLocation(world.getRegistryKey(), new_x, new_y, new_z, player.getHeadYaw(), player.getPitch()), - ECText.getInstance().getText("cmd.top.location_name") + player, + new MinecraftLocation(world.getRegistryKey(), new_x, new_y, new_z, player.getHeadYaw(), player.getPitch()), + ECText.access(player).getText("cmd.top.location_name") ); return 0; + } + + public static int getTop(Chunk chunk, int x, int z) { + final int maxY = calculateMaxY(chunk); + final int bottomY = chunk.getBottomY(); + if (maxY <= bottomY) { + return Integer.MIN_VALUE; + } + + final BlockPos.Mutable mutablePos = new BlockPos.Mutable(x, maxY, z); + boolean isAir1 = chunk.getBlockState(mutablePos).isAir(); // Block at head level + boolean isAir2 = chunk.getBlockState(mutablePos.move(Direction.DOWN)).isAir(); // Block at feet level + boolean isAir3; // Block below feet + while (mutablePos.getY() > bottomY) { + isAir3 = chunk.getBlockState(mutablePos.move(Direction.DOWN)).isAir(); + if (!isAir3 && isAir2 && isAir1) { // If there is a floor block and space for player body+head + return mutablePos.getY() + 1; + } + + isAir1 = isAir2; + isAir2 = isAir3; + } + + return Integer.MIN_VALUE; } + private static int calculateMaxY(Chunk chunk) { + final int maxY = chunk.getHeight(); + ChunkSection[] sections = chunk.getSectionArray(); + int maxSectionIndex = Math.min(sections.length - 1, maxY >> 4); + + for (int index = maxSectionIndex; index >= 0; --index) { + if (!sections[index].isEmpty()) { + return Math.min(index << 4 + 15, maxY); + } + } + + return Integer.MAX_VALUE; + } } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/WarpDeleteCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/WarpDeleteCommand.java index 7da75490..a540fde4 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/WarpDeleteCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/WarpDeleteCommand.java @@ -1,19 +1,16 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.ECText; import com.fibermc.essentialcommands.ManagerLocator; import com.fibermc.essentialcommands.WorldDataManager; -import com.fibermc.essentialcommands.util.TextUtil; +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.text.ECText; + import com.mojang.brigadier.Command; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.LiteralText; - -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; +import net.minecraft.server.command.ServerCommandSource; public class WarpDeleteCommand implements Command { @@ -22,32 +19,19 @@ public WarpDeleteCommand() {} @Override public int run(CommandContext context) throws CommandSyntaxException { WorldDataManager worldDataManager = ManagerLocator.getInstance().getWorldDataManager(); - int out = 0; - ServerCommandSource source = context.getSource(); - //Store command sender - ServerPlayerEntity senderPlayer = context.getSource().getPlayer(); - //Store home name + var senderPlayerData = PlayerData.accessFromContextOrThrow(context); String warpName = StringArgumentType.getString(context, "warp_name"); boolean wasSuccessful = worldDataManager.delWarp(warpName); + var warpNameText = ECText.access(senderPlayerData.getPlayer()).accent(warpName); //inform command sender that the warp has been removed - if (wasSuccessful) { - source.sendFeedback(TextUtil.concat( - ECText.getInstance().getText("cmd.warp.feedback.1").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()), - new LiteralText(warpName).setStyle(CONFIG.FORMATTING_ACCENT.getValue()), - ECText.getInstance().getText("cmd.warp.delete.feedback.2").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()) - ), CONFIG.BROADCAST_TO_OPS.getValue()); - out = 1; - } else { - source.sendFeedback(TextUtil.concat( - ECText.getInstance().getText("cmd.warp.feedback.1").setStyle(CONFIG.FORMATTING_ERROR.getValue()), - new LiteralText(warpName).setStyle(CONFIG.FORMATTING_ACCENT.getValue()), - ECText.getInstance().getText("cmd.warp.delete.error.2").setStyle(CONFIG.FORMATTING_ERROR.getValue()) - ), CONFIG.BROADCAST_TO_OPS.getValue()); + if (!wasSuccessful) { + senderPlayerData.sendCommandError("cmd.warp.delete.error", warpNameText); + return 0; } - - return out; + senderPlayerData.sendCommandFeedback("cmd.warp.delete.feedback", warpNameText); + return 1; } } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/WarpSetCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/WarpSetCommand.java index 68a2cdf8..c56feed7 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/WarpSetCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/WarpSetCommand.java @@ -1,20 +1,18 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.ECText; import com.fibermc.essentialcommands.ManagerLocator; import com.fibermc.essentialcommands.WorldDataManager; +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.text.ECText; import com.fibermc.essentialcommands.types.MinecraftLocation; -import com.fibermc.essentialcommands.util.TextUtil; + import com.mojang.brigadier.Command; +import com.mojang.brigadier.arguments.BoolArgumentType; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.LiteralText; - -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; +import net.minecraft.server.command.ServerCommandSource; public class WarpSetCommand implements Command { @@ -23,28 +21,25 @@ public WarpSetCommand() {} @Override public int run(CommandContext context) throws CommandSyntaxException { WorldDataManager worldDataManager = ManagerLocator.getInstance().getWorldDataManager(); - - ServerCommandSource source = context.getSource(); - //Store command sender - ServerPlayerEntity senderPlayer = source.getPlayer(); - //Store home name + var senderPlayer = context.getSource().getPlayer(); + var senderPlayerData = PlayerData.access(senderPlayer); String warpName = StringArgumentType.getString(context, "warp_name"); + boolean requiresPermission; + try { + requiresPermission = BoolArgumentType.getBool(context, "requires_permission"); + } catch (IllegalArgumentException ign) { + requiresPermission = false; + } + + var warpNameText = ECText.access(senderPlayer).accent(warpName); //Add warp try { - worldDataManager.setWarp(warpName, new MinecraftLocation(senderPlayer)); + worldDataManager.setWarp(warpName, new MinecraftLocation(senderPlayer), requiresPermission); //inform command sender that the home has been set - source.sendFeedback(TextUtil.concat( - ECText.getInstance().getText("cmd.warp.feedback.1").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()), - new LiteralText(warpName).setStyle(CONFIG.FORMATTING_ACCENT.getValue()), - ECText.getInstance().getText("cmd.warp.set.feedback.2").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()) - ), CONFIG.BROADCAST_TO_OPS.getValue()); + senderPlayerData.sendCommandFeedback("cmd.warp.set.feedback", warpNameText); } catch (CommandSyntaxException e) { - source.sendError(TextUtil.concat( - ECText.getInstance().getText("cmd.warp.feedback.1").setStyle(CONFIG.FORMATTING_ERROR.getValue()), - new LiteralText(warpName).setStyle(CONFIG.FORMATTING_ACCENT.getValue()), - ECText.getInstance().getText("cmd.warp.set.error.exists.2").setStyle(CONFIG.FORMATTING_ERROR.getValue()) - )); + senderPlayerData.sendCommandError("cmd.warp.set.error.exists", warpNameText); } return 1; diff --git a/src/main/java/com/fibermc/essentialcommands/commands/WarpTpCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/WarpTpCommand.java index 1c7a53d6..6fb6e361 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/WarpTpCommand.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/WarpTpCommand.java @@ -1,49 +1,67 @@ package com.fibermc.essentialcommands.commands; -import com.fibermc.essentialcommands.ECText; import com.fibermc.essentialcommands.ManagerLocator; -import com.fibermc.essentialcommands.PlayerTeleporter; -import com.fibermc.essentialcommands.WorldDataManager; -import com.fibermc.essentialcommands.types.MinecraftLocation; +import com.fibermc.essentialcommands.teleportation.PlayerTeleporter; +import com.fibermc.essentialcommands.text.ECText; +import com.fibermc.essentialcommands.text.TextFormatType; +import com.fibermc.essentialcommands.types.WarpLocation; + import com.mojang.brigadier.Command; -import com.mojang.brigadier.Message; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; + +import net.minecraft.command.argument.EntityArgumentType; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.server.network.ServerPlayerEntity; - public class WarpTpCommand implements Command { - public WarpTpCommand() { - } + public WarpTpCommand() {} @Override public int run(CommandContext context) throws CommandSyntaxException { - WorldDataManager worldDataManager = ManagerLocator.getInstance().getWorldDataManager(); - int out; - ServerCommandSource source = context.getSource(); - //Store command sender - ServerPlayerEntity senderPlayer = source.getPlayer(); - //Store home name + ServerPlayerEntity senderPlayer = context.getSource().getPlayer(); + exec(context, senderPlayer); + + return 1; + } + + private void exec( + CommandContext context, + ServerPlayerEntity targetPlayer) throws CommandSyntaxException + { + var worldDataManager = ManagerLocator.getInstance().getWorldDataManager(); + var senderPlayer = context.getSource().getPlayer(); + var ecText = ECText.access(senderPlayer); + String warpName = StringArgumentType.getString(context, "warp_name"); + var warpNameText = ecText.accent(warpName); + WarpLocation loc = worldDataManager.getWarp(warpName); - //Get home location - MinecraftLocation loc = worldDataManager.getWarp(warpName); + if (loc == null) { + throw CommandUtil.createSimpleException(ecText.getText( + "cmd.warp.tp.error.not_found", + TextFormatType.Error, + warpNameText)); + } - // Teleport & chat message - if (loc != null) { - //Teleport player to home location - PlayerTeleporter.requestTeleport(senderPlayer, loc, ECText.getInstance().getText("cmd.warp.location_name", warpName)); - out = 1; - } else { - Message msg = ECText.getInstance().getText("cmd.warp.tp.error.not_found", warpName); - throw new CommandSyntaxException(new SimpleCommandExceptionType(msg), msg); + if (!loc.hasPermission(senderPlayer)) { + throw CommandUtil.createSimpleException(ecText.getText( + "cmd.warp.tp.error.permission", + TextFormatType.Error, + warpNameText)); } - return out; + // Teleport & chat message + PlayerTeleporter.requestTeleport( + targetPlayer, + loc, + ecText.getText("cmd.warp.location_name", warpNameText)); } + public int runOther(CommandContext context) throws CommandSyntaxException { + exec(context, EntityArgumentType.getPlayer(context, "target_player")); + return 0; + } } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/WorkbenchCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/WorkbenchCommand.java deleted file mode 100644 index dae62365..00000000 --- a/src/main/java/com/fibermc/essentialcommands/commands/WorkbenchCommand.java +++ /dev/null @@ -1,48 +0,0 @@ -package com.fibermc.essentialcommands.commands; - -import com.fibermc.essentialcommands.ECText; -import com.fibermc.essentialcommands.screen.CraftingCommandScreenHandler; -import com.mojang.brigadier.Command; -import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.minecraft.screen.NamedScreenHandlerFactory; -import net.minecraft.screen.ScreenHandlerContext; -import net.minecraft.screen.SimpleNamedScreenHandlerFactory; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.stat.Stats; -import net.minecraft.text.LiteralText; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; - -import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; - -public class WorkbenchCommand implements Command { - - public WorkbenchCommand() { - } - - @Override - public int run(CommandContext context) throws CommandSyntaxException { - ServerCommandSource source = context.getSource(); - ServerPlayerEntity senderPlayer = source.getPlayer(); - - senderPlayer.openHandledScreen(createScreenHandlerFactory(senderPlayer.getEntityWorld(), senderPlayer.getBlockPos())); - senderPlayer.incrementStat(Stats.INTERACT_WITH_CRAFTING_TABLE); - - source.sendFeedback( - new LiteralText("Opened workbench.").setStyle(CONFIG.FORMATTING_DEFAULT.getValue()), - CONFIG.BROADCAST_TO_OPS.getValue() - ); - - return 0; - } - - private NamedScreenHandlerFactory createScreenHandlerFactory(World world, BlockPos pos) { - return new SimpleNamedScreenHandlerFactory((syncId, inventory, player) -> { - return new CraftingCommandScreenHandler(syncId, inventory, ScreenHandlerContext.create(world, pos)); - }, ECText.getInstance().getText("cmd.workbench.container_ui_name")); - - } - -} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/bench/AnvilCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/bench/AnvilCommand.java new file mode 100644 index 00000000..23e051ec --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/commands/bench/AnvilCommand.java @@ -0,0 +1,35 @@ +package com.fibermc.essentialcommands.commands.bench; + +import com.fibermc.essentialcommands.screen.AnvilCommandScreenHandler; +import org.jetbrains.annotations.NotNull; + +import net.minecraft.screen.ScreenHandlerContext; +import net.minecraft.screen.ScreenHandlerFactory; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.stat.Stats; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; + +public class AnvilCommand extends SimpleScreenCommand { + private static final ScreenHandlerFactory SCREEN_HANDLER_FACTORY = (syncId, inventory, player) -> + new AnvilCommandScreenHandler( + syncId, + inventory, + ScreenHandlerContext.create(player.getEntityWorld(), player.getBlockPos()) + ); + + @Override + protected Text getScreenTitle() { + return new TranslatableText("block.minecraft.anvil"); + } + + @Override + protected @NotNull ScreenHandlerFactory getScreenHandlerFactory() { + return SCREEN_HANDLER_FACTORY; + } + + @Override + protected void onOpen(ServerPlayerEntity player) { + player.incrementStat(Stats.INTERACT_WITH_ANVIL); + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/bench/EnderchestCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/bench/EnderchestCommand.java new file mode 100644 index 00000000..6811d513 --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/commands/bench/EnderchestCommand.java @@ -0,0 +1,32 @@ +package com.fibermc.essentialcommands.commands.bench; + +import org.jetbrains.annotations.NotNull; + +import net.minecraft.screen.GenericContainerScreenHandler; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.SimpleNamedScreenHandlerFactory; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.stat.Stats; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; + +public class EnderchestCommand extends SimpleScreenCommand { + @Override + protected Text getScreenTitle() { + return new TranslatableText("container.enderchest"); + } + + @Override + protected @NotNull NamedScreenHandlerFactory getScreenHandlerFactory() { + return new SimpleNamedScreenHandlerFactory( + (syncId, inventory, player) -> + GenericContainerScreenHandler.createGeneric9x3(syncId, inventory, player.getEnderChestInventory()), + new TranslatableText("container.enderchest") + ); + } + + @Override + protected void onOpen(ServerPlayerEntity player) { + player.incrementStat(Stats.OPEN_ENDERCHEST); + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/bench/GrindstoneCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/bench/GrindstoneCommand.java new file mode 100644 index 00000000..9d92e358 --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/commands/bench/GrindstoneCommand.java @@ -0,0 +1,35 @@ +package com.fibermc.essentialcommands.commands.bench; + +import com.fibermc.essentialcommands.screen.GrindstoneCommandScreenHandler; +import org.jetbrains.annotations.NotNull; + +import net.minecraft.screen.ScreenHandlerContext; +import net.minecraft.screen.ScreenHandlerFactory; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.stat.Stats; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; + +public class GrindstoneCommand extends SimpleScreenCommand { + private static final ScreenHandlerFactory SCREEN_HANDLER_FACTORY = (syncId, inventory, player) -> + new GrindstoneCommandScreenHandler( + syncId, + inventory, + ScreenHandlerContext.create(player.getEntityWorld(), player.getBlockPos()) + ); + + @Override + protected Text getScreenTitle() { + return new TranslatableText("block.minecraft.grindstone"); + } + + @Override + protected @NotNull ScreenHandlerFactory getScreenHandlerFactory() { + return SCREEN_HANDLER_FACTORY; + } + + @Override + protected void onOpen(ServerPlayerEntity player) { + player.incrementStat(Stats.INTERACT_WITH_GRINDSTONE); + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/bench/SimpleScreenCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/bench/SimpleScreenCommand.java new file mode 100644 index 00000000..fa8c57ef --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/commands/bench/SimpleScreenCommand.java @@ -0,0 +1,41 @@ +package com.fibermc.essentialcommands.commands.bench; + +import com.fibermc.essentialcommands.playerdata.PlayerData; +import org.jetbrains.annotations.NotNull; + +import com.mojang.brigadier.Command; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.ScreenHandlerFactory; +import net.minecraft.screen.SimpleNamedScreenHandlerFactory; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; + +public abstract class SimpleScreenCommand implements Command { + @Override + public int run(CommandContext context) throws CommandSyntaxException { + var senderPlayer = context.getSource().getPlayer(); + var senderPlayerData = PlayerData.access(senderPlayer); + + senderPlayer.openHandledScreen(createNamedScreenHandlerFactory()); + + senderPlayerData.sendCommandFeedback("cmd.workbench.feedback", getScreenTitle()); + + onOpen(senderPlayer); + + return 0; + } + + protected NamedScreenHandlerFactory createNamedScreenHandlerFactory() { + return new SimpleNamedScreenHandlerFactory(getScreenHandlerFactory(), getScreenTitle()); + } + + protected abstract Text getScreenTitle(); + + protected abstract @NotNull ScreenHandlerFactory getScreenHandlerFactory(); + + protected abstract void onOpen(ServerPlayerEntity player); +} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/bench/StonecutterCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/bench/StonecutterCommand.java new file mode 100644 index 00000000..81a8e0f7 --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/commands/bench/StonecutterCommand.java @@ -0,0 +1,35 @@ +package com.fibermc.essentialcommands.commands.bench; + +import com.fibermc.essentialcommands.screen.StonecutterCommandScreenHandler; +import org.jetbrains.annotations.NotNull; + +import net.minecraft.screen.ScreenHandlerContext; +import net.minecraft.screen.ScreenHandlerFactory; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.stat.Stats; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; + +public class StonecutterCommand extends SimpleScreenCommand { + private static final ScreenHandlerFactory SCREEN_HANDLER_FACTORY = (syncId, inventory, player) -> + new StonecutterCommandScreenHandler( + syncId, + inventory, + ScreenHandlerContext.create(player.getEntityWorld(), player.getBlockPos()) + ); + + @Override + protected Text getScreenTitle() { + return new TranslatableText("block.minecraft.stonecutter"); + } + + @Override + protected @NotNull ScreenHandlerFactory getScreenHandlerFactory() { + return SCREEN_HANDLER_FACTORY; + } + + @Override + protected void onOpen(ServerPlayerEntity player) { + player.incrementStat(Stats.INTERACT_WITH_STONECUTTER); + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/bench/WastebinCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/bench/WastebinCommand.java new file mode 100644 index 00000000..5928c694 --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/commands/bench/WastebinCommand.java @@ -0,0 +1,31 @@ +package com.fibermc.essentialcommands.commands.bench; + +import com.fibermc.essentialcommands.text.ECText; +import com.fibermc.essentialcommands.text.TextFormatType; +import org.jetbrains.annotations.NotNull; + +import net.minecraft.inventory.SimpleInventory; +import net.minecraft.screen.GenericContainerScreenHandler; +import net.minecraft.screen.ScreenHandlerFactory; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; + +public class WastebinCommand extends SimpleScreenCommand { + private static final ScreenHandlerFactory SCREEN_HANDLER_FACTORY = (syncId, inventory, player) -> + GenericContainerScreenHandler.createGeneric9x3(syncId, inventory, new SimpleInventory(27)); + + @Override + protected Text getScreenTitle() { + return ECText.getInstance().getText("cmd.wastebin.name", TextFormatType.Empty); + } + + @Override + protected @NotNull ScreenHandlerFactory getScreenHandlerFactory() { + return SCREEN_HANDLER_FACTORY; + } + + @Override + protected void onOpen(ServerPlayerEntity player) { + + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/bench/WorkbenchCommand.java b/src/main/java/com/fibermc/essentialcommands/commands/bench/WorkbenchCommand.java new file mode 100644 index 00000000..6f8e8ec8 --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/commands/bench/WorkbenchCommand.java @@ -0,0 +1,35 @@ +package com.fibermc.essentialcommands.commands.bench; + +import com.fibermc.essentialcommands.screen.CraftingCommandScreenHandler; +import org.jetbrains.annotations.NotNull; + +import net.minecraft.screen.ScreenHandlerContext; +import net.minecraft.screen.ScreenHandlerFactory; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.stat.Stats; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; + +public class WorkbenchCommand extends SimpleScreenCommand { + private static final ScreenHandlerFactory SCREEN_HANDLER_FACTORY = (syncId, inventory, player) -> + new CraftingCommandScreenHandler( + syncId, + inventory, + ScreenHandlerContext.create(player.getEntityWorld(), player.getBlockPos()) + ); + + @Override + protected Text getScreenTitle() { + return new TranslatableText("block.minecraft.crafting_table"); + } + + @Override + protected @NotNull ScreenHandlerFactory getScreenHandlerFactory() { + return SCREEN_HANDLER_FACTORY; + } + + @Override + protected void onOpen(ServerPlayerEntity player) { + player.incrementStat(Stats.INTERACT_WITH_CRAFTING_TABLE); + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/exceptions/ECExceptions.java b/src/main/java/com/fibermc/essentialcommands/commands/exceptions/ECExceptions.java index 9722da98..cacf8bc9 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/exceptions/ECExceptions.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/exceptions/ECExceptions.java @@ -1,12 +1,6 @@ package com.fibermc.essentialcommands.commands.exceptions; -import com.mojang.brigadier.LiteralMessage; -import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +public final class ECExceptions { + private ECExceptions() {} -public class ECExceptions { - private static final DynamicCommandExceptionType KEY_EXISTS = new DynamicCommandExceptionType((value) -> new LiteralMessage(String.format("The key '%s' already has an associated location.", value))); - - public static DynamicCommandExceptionType keyExists() { - return KEY_EXISTS; - } } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/helpers/FeedbackReceiver.java b/src/main/java/com/fibermc/essentialcommands/commands/helpers/FeedbackReceiver.java new file mode 100644 index 00000000..6ac881ca --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/commands/helpers/FeedbackReceiver.java @@ -0,0 +1,47 @@ +package com.fibermc.essentialcommands.commands.helpers; + +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.text.ECText; +import com.fibermc.essentialcommands.text.TextFormatType; + +import com.mojang.brigadier.exceptions.CommandSyntaxException; + +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.Text; + +import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; + +public final class FeedbackReceiver implements IFeedbackReceiver { + + private final ServerCommandSource commandSource; + + private FeedbackReceiver(ServerCommandSource commandSource) { + this.commandSource = commandSource; + } + + public static IFeedbackReceiver ofSource(ServerCommandSource commandSource) throws CommandSyntaxException { + var player = commandSource.getPlayer(); + return player != null + ? PlayerData.access(player) + : new FeedbackReceiver(commandSource); + } + + @Override + public void sendCommandFeedback(Text text) { + commandSource.sendFeedback(text, CONFIG.BROADCAST_TO_OPS); + } + + @Override + public void sendCommandFeedback(String messageKey, Text... args) { + sendCommandFeedback(ECText.getInstance().getText(messageKey, TextFormatType.Default, args)); + } + + public void sendCommandError(Text text) { + commandSource.sendError(text); + } + + @Override + public void sendCommandError(String messageKey, Text... args) { + sendCommandError(ECText.getInstance().getText(messageKey, TextFormatType.Error, args)); + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/helpers/IFeedbackReceiver.java b/src/main/java/com/fibermc/essentialcommands/commands/helpers/IFeedbackReceiver.java new file mode 100644 index 00000000..a902c5c1 --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/commands/helpers/IFeedbackReceiver.java @@ -0,0 +1,13 @@ +package com.fibermc.essentialcommands.commands.helpers; + +import net.minecraft.text.Text; + +public interface IFeedbackReceiver { + void sendCommandFeedback(Text text); + + void sendCommandFeedback(String messageKey, Text... args); + + void sendCommandError(Text text); + + void sendCommandError(String messageKey, Text... args); +} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/suggestions/HomeSuggestion.java b/src/main/java/com/fibermc/essentialcommands/commands/suggestions/HomeSuggestion.java deleted file mode 100644 index 11462f3a..00000000 --- a/src/main/java/com/fibermc/essentialcommands/commands/suggestions/HomeSuggestion.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.fibermc.essentialcommands.commands.suggestions; - -import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; -import com.fibermc.essentialcommands.types.MinecraftLocation; -import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.suggestion.SuggestionProvider; -import net.minecraft.server.command.ServerCommandSource; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class HomeSuggestion { - //Brigader Suggestions - public static SuggestionProvider suggestedStrings() { - return ListSuggestion.ofContext(HomeSuggestion::getSuggestionsList); - } - - /** - * Gets a list of suggested strings to be used with Brigader - */ - public static List getSuggestionsList(CommandContext context) throws CommandSyntaxException { - return new ArrayList<>(((ServerPlayerEntityAccess)context.getSource().getPlayer()).getEcPlayerData().getHomeNames()); - } - - /** - * Gets a set of suggestion entries to be used with ListCommandFactory - */ - public static Set> getSuggestionEntries(CommandContext context) throws CommandSyntaxException { - return ((ServerPlayerEntityAccess)context.getSource().getPlayer()).getEcPlayerData().getHomeEntries(); - } - -} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/suggestions/ListSuggestion.java b/src/main/java/com/fibermc/essentialcommands/commands/suggestions/ListSuggestion.java index 25d2e1f4..3c94c587 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/suggestions/ListSuggestion.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/suggestions/ListSuggestion.java @@ -1,23 +1,27 @@ package com.fibermc.essentialcommands.commands.suggestions; +import java.util.Collection; +import java.util.Locale; +import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.suggestion.SuggestionProvider; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; + import net.minecraft.server.command.ServerCommandSource; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import java.util.Collection; -import java.util.Locale; -import java.util.concurrent.CompletableFuture; -import java.util.function.Supplier; +public final class ListSuggestion { + private ListSuggestion() {} -public class ListSuggestion { public static CompletableFuture buildSuggestions(SuggestionsBuilder builder, Collection suggestionCollection) { String remaining = builder.getRemaining().toLowerCase(Locale.ROOT); - if(suggestionCollection.isEmpty()) { // If the list is empty then return no suggestions + if (suggestionCollection.isEmpty()) { // If the list is empty then return no suggestions return Suggestions.empty(); // No suggestions } @@ -31,16 +35,14 @@ public static CompletableFuture buildSuggestions(SuggestionsBuilder @Contract(pure = true) public static @NotNull SuggestionProvider of(Supplier> suggestionCollection) { - return (CommandContext context, SuggestionsBuilder builder) -> { - return buildSuggestions(builder, suggestionCollection.get()); - }; + return (CommandContext context, SuggestionsBuilder builder) + -> buildSuggestions(builder, suggestionCollection.get()); } @Contract(pure = true) public static @NotNull SuggestionProvider ofContext(ContextFunction, Collection> suggestionCollection) { - return (CommandContext context, SuggestionsBuilder builder) -> { - return buildSuggestions(builder, suggestionCollection.apply(context)); - }; + return (CommandContext context, SuggestionsBuilder builder) + -> buildSuggestions(builder, suggestionCollection.apply(context)); } } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/suggestions/NicknamePlayersSuggestion.java b/src/main/java/com/fibermc/essentialcommands/commands/suggestions/NicknamePlayersSuggestion.java index d6ad7f4b..152fddd4 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/suggestions/NicknamePlayersSuggestion.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/suggestions/NicknamePlayersSuggestion.java @@ -1,23 +1,27 @@ package com.fibermc.essentialcommands.commands.suggestions; -import com.fibermc.essentialcommands.PlayerData; -import com.fibermc.essentialcommands.PlayerDataManager; +import java.util.Optional; + +import com.fibermc.essentialcommands.playerdata.PlayerData; +import com.fibermc.essentialcommands.playerdata.PlayerDataManager; + import com.mojang.brigadier.suggestion.SuggestionProvider; + import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.MutableText; -import java.util.Objects; +public final class NicknamePlayersSuggestion { + private NicknamePlayersSuggestion() {} -public class NicknamePlayersSuggestion { //Brigader Suggestions - public static SuggestionProvider suggestedStrings() { - return ListSuggestion.ofContext(context -> + public static final SuggestionProvider STRING_SUGGESTIONS_PROVIDER = + ListSuggestion.ofContext(context -> PlayerDataManager.getInstance().getAllPlayerData().stream() .map(PlayerData::getNickname) - .filter(Objects::nonNull) + .filter(Optional::isPresent) + .map(Optional::get) .map(MutableText::getString) .sorted(String.CASE_INSENSITIVE_ORDER) .toList() ); - } } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/suggestions/OfflinePlayerRepo.java b/src/main/java/com/fibermc/essentialcommands/commands/suggestions/OfflinePlayerRepo.java new file mode 100644 index 00000000..ba3ce108 --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/commands/suggestions/OfflinePlayerRepo.java @@ -0,0 +1,72 @@ +package com.fibermc.essentialcommands.commands.suggestions; + +import java.util.HashMap; +import java.util.concurrent.CompletableFuture; + +import com.mojang.authlib.Agent; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.ProfileLookupCallback; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; + +public class OfflinePlayerRepo { + + private final HashMap gameProfileCache = new HashMap<>(); + private final MinecraftServer server; + + public OfflinePlayerRepo(MinecraftServer server) { + this.server = server; + } + + public CompletableFuture getOfflinePlayerByNameAsync(String playerName) { + return getGameProfile(playerName) + .handle(((gameProfile, throwable) -> gameProfile == null + ? null + : getOfflinePlayer(gameProfile))); + } + + public ServerPlayerEntity getOfflinePlayer(GameProfile playerProfile) { + var player = new ServerPlayerEntity( + server, + server.getOverworld(), + playerProfile); + + server.getPlayerManager().loadPlayerData(player); + + return player; + } + + public CompletableFuture getGameProfile(String playerName) { + var profile = gameProfileCache.get(playerName); + if (profile != null) { + CompletableFuture.completedFuture(profile); + } + return requestGameProfile(playerName) + .whenComplete((gameProfile, err) -> { + if (gameProfile != null) { + gameProfileCache.put(gameProfile.getName(), gameProfile); + } + }); + } + + private CompletableFuture requestGameProfile(String playerName) { + CompletableFuture out = new CompletableFuture<>(); + server.getGameProfileRepo().findProfilesByNames( + new String[]{playerName}, + Agent.MINECRAFT, + new ProfileLookupCallback() { + @Override + public void onProfileLookupSucceeded(GameProfile profile) { + System.out.println(profile.toString()); + out.complete(profile); + } + + @Override + public void onProfileLookupFailed(GameProfile profile, Exception exception) { + out.complete(null); + } + }); + return out; + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/commands/suggestions/SuggestionListProvider.java b/src/main/java/com/fibermc/essentialcommands/commands/suggestions/SuggestionListProvider.java index ec527748..f2317185 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/suggestions/SuggestionListProvider.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/suggestions/SuggestionListProvider.java @@ -1,13 +1,13 @@ package com.fibermc.essentialcommands.commands.suggestions; +import java.util.Collection; + import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.minecraft.server.command.ServerCommandSource; -import java.util.Collection; -import java.util.List; +import net.minecraft.server.command.ServerCommandSource; @FunctionalInterface public interface SuggestionListProvider { - Collection getSuggestionList(final CommandContext context) throws CommandSyntaxException; + Collection getSuggestionList(CommandContext context) throws CommandSyntaxException; } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/suggestions/TeleportResponseSuggestion.java b/src/main/java/com/fibermc/essentialcommands/commands/suggestions/TeleportResponseSuggestion.java index 45f12462..a2523bed 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/suggestions/TeleportResponseSuggestion.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/suggestions/TeleportResponseSuggestion.java @@ -1,21 +1,22 @@ package com.fibermc.essentialcommands.commands.suggestions; +import java.util.stream.Collectors; + import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; + import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.suggestion.SuggestionProvider; -import net.minecraft.server.command.ServerCommandSource; -import org.apache.logging.log4j.core.jmx.Server; -import java.util.stream.Collectors; +import net.minecraft.server.command.ServerCommandSource; -public class TeleportResponseSuggestion { +public final class TeleportResponseSuggestion { + private TeleportResponseSuggestion() {} //Brigader Suggestions - public static SuggestionProvider suggestedStrings() { - return ListSuggestion.ofContext((CommandContext context) -> - ((ServerPlayerEntityAccess)context.getSource().getPlayer()).getEcPlayerData().getIncomingTeleportRequests().values() - .stream().map((entry) -> entry.getSenderPlayer().getGameProfile().getName()) - .collect(Collectors.toList()) - ); - } + public static final SuggestionProvider STRING_SUGGESTIONS_PROVIDER + = ListSuggestion.ofContext((CommandContext context) -> + ((ServerPlayerEntityAccess) context.getSource().getPlayer()).ec$getPlayerData().getIncomingTeleportRequests().values() + .stream().map((entry) -> entry.getSenderPlayer().getGameProfile().getName()) + .collect(Collectors.toList()) + ); } diff --git a/src/main/java/com/fibermc/essentialcommands/commands/suggestions/WarpSuggestion.java b/src/main/java/com/fibermc/essentialcommands/commands/suggestions/WarpSuggestion.java index 2b5553bb..269f6665 100644 --- a/src/main/java/com/fibermc/essentialcommands/commands/suggestions/WarpSuggestion.java +++ b/src/main/java/com/fibermc/essentialcommands/commands/suggestions/WarpSuggestion.java @@ -1,13 +1,16 @@ package com.fibermc.essentialcommands.commands.suggestions; import com.fibermc.essentialcommands.ManagerLocator; -import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; + import com.mojang.brigadier.suggestion.SuggestionProvider; + import net.minecraft.server.command.ServerCommandSource; -public class WarpSuggestion { +public final class WarpSuggestion { + private WarpSuggestion() {} + //Brigader Suggestions - public static SuggestionProvider suggestedStrings() { - return ListSuggestion.of(() -> ManagerLocator.getInstance().getWorldDataManager().getWarpNames()); - } + public static final SuggestionProvider STRING_SUGGESTIONS_PROVIDER + = ListSuggestion.of(() -> ManagerLocator.getInstance().getWorldDataManager().getWarpNames()); + } diff --git a/src/main/java/com/fibermc/essentialcommands/config/EssentialCommandsConfig.java b/src/main/java/com/fibermc/essentialcommands/config/EssentialCommandsConfig.java index a86d745f..779221a7 100644 --- a/src/main/java/com/fibermc/essentialcommands/config/EssentialCommandsConfig.java +++ b/src/main/java/com/fibermc/essentialcommands/config/EssentialCommandsConfig.java @@ -1,22 +1,30 @@ package com.fibermc.essentialcommands.config; +import java.nio.file.Path; +import java.time.Duration; +import java.util.List; + import com.fibermc.essentialcommands.ECPerms; +import com.fibermc.essentialcommands.types.RespawnCondition; +import org.jetbrains.annotations.NotNull; + +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + import dev.jpcode.eccore.config.Config; import dev.jpcode.eccore.config.ConfigOption; import dev.jpcode.eccore.config.ConfigUtil; import dev.jpcode.eccore.config.Option; import dev.jpcode.eccore.util.TextUtil; -import net.minecraft.text.Style; -import net.minecraft.text.Text; -import java.nio.file.Path; -import java.util.List; - -import static dev.jpcode.eccore.config.ConfigUtil.arrayParser; -import static dev.jpcode.eccore.config.ConfigUtil.parseStyle; +import static com.fibermc.essentialcommands.EssentialCommands.LOGGER; +import static dev.jpcode.eccore.config.ConfigUtil.*; import static dev.jpcode.eccore.util.TextUtil.parseText; +import static dev.jpcode.eccore.util.TimeUtil.durationToTicks; -public final class EssentialCommandsConfig extends Config { +@SuppressWarnings("checkstyle:all") +public final class EssentialCommandsConfig extends Config { @ConfigOption public final Option