Update gradle to 8.14.3

This commit is contained in:
NotAlexNoyle committed 2025-08-27 02:56:17 -04:00
1 parent 0603b5405d
commit a7c8b9ff7c
51 files changed
+1701 -269

No files matched your search

+73 -39
View File
@@ -1,86 +1,120 @@
/* ------------------------------ Plugins ------------------------------ */
plugins {
id("java") // Tell gradle this is a java project.
id("java-library") // Import helper for source-based libraries.
id("com.diffplug.spotless") version "7.0.4" // Import auto-formatter.
id("com.gradleup.shadow") version "8.3.6" // Import shadow API.
eclipse // Import eclipse plugin for IDE integration.
id("java") // Import Java plugin.
id("java-library") // Import Java Library plugin.
id("com.diffplug.spotless") version "7.0.4" // Import Spotless plugin.
id("com.gradleup.shadow") version "8.3.6" // Import Shadow plugin.
id("checkstyle") // Import Checkstyle plugin.
eclipse // Import Eclipse plugin.
kotlin("jvm") version "2.1.21" // Import Kotlin JVM plugin.
id("io.freefair.lombok") version "8.13.1" // Automatic lombok support.
}
extra["kotlinAttribute"] = Attribute.of("kotlin-tag", Boolean::class.javaObjectType)
val kotlinAttribute: Attribute<Boolean> by rootProject.extra
/* --------------------------- JDK / Kotlin ---------------------------- */
java {
// Declare java version.
sourceCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_17 // Compile with JDK 17 compatibility.
toolchain { // Select Java toolchain.
languageVersion.set(JavaLanguageVersion.of(17)) // Use JDK 17.
vendor.set(JvmVendorSpec.GRAAL_VM) // Use GraalVM CE.
}
}
group = "dev.codedred" // Declare bundle identifier.
kotlin { jvmToolchain(17) }
/* ----------------------------- Metadata ------------------------------ */
group = "net.trueog.playtimes-og" // Declare bundle identifier.
version = "1.0" // Declare plugin version (will be in .jar).
val apiVersion = "1.19" // Declare minecraft server target version.
/* ----------------------------- Resources ----------------------------- */
tasks.named<ProcessResources>("processResources") {
val props = mapOf("version" to version, "apiVersion" to apiVersion)
inputs.properties(props) // Indicates to rerun if version changes.
filesMatching("plugin.yml") { expand(props) }
from("LICENSE") { // Bundle license into .jars.
into("/")
}
from("LICENSE") { into("/") } // Bundle licenses into jarfiles.
}
/* ---------------------------- Repos ---------------------------------- */
repositories {
mavenCentral()
gradlePluginPortal()
maven { url = uri("https://repo.purpurmc.org/snapshots") }
maven { url = uri("https://oss.sonatype.org/content/groups/public/") }
mavenCentral() // Import the Maven Central Maven Repository.
gradlePluginPortal() // Import the Gradle Plugin Portal Maven Repository.
maven { url = uri("https://repo.purpurmc.org/snapshots") } // Import the PurpurMC Maven Repository.
}
/* ---------------------- Java project deps ---------------------------- */
dependencies {
compileOnly("org.purpurmc.purpur:purpur-api:1.19.4-R0.1-SNAPSHOT") // Declare purpur API version to be packaged.
compileOnly("org.purpurmc.purpur:purpur-api:1.19.4-R0.1-SNAPSHOT") // Declare Purpur API version to be packaged.
compileOnly("io.github.miniplaceholders:miniplaceholders-api:2.2.3") // Import MiniPlaceholders API.
compileOnlyApi(project(":libs:Utilities-OG")) // Import TrueOG Network Utilities-OG API.
compileOnlyApi(project(":libs:Utilities-OG")) // Import TrueOG Network Utilities-OG Java API (from source).
}
apply(from = "eclipse.gradle.kts") // Import eclipse classpath support script.
/* ---------------------- Reproducible jars ---------------------------- */
tasks.withType<AbstractArchiveTask>().configureEach { // Ensure reproducible .jars
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
}
/* ----------------------------- Shadow -------------------------------- */
tasks.shadowJar {
exclude("io.github.miniplaceholders.*") // Exclude the MiniPlaceholders package from being shadowed.
archiveClassifier.set("") // Use empty string instead of null.
minimize()
}
tasks.build {
dependsOn(tasks.spotlessApply)
dependsOn(tasks.shadowJar)
}
tasks.jar { archiveClassifier.set("part") } // Applies to root jarfile only.
tasks.jar { archiveClassifier.set("part") }
tasks.build { dependsOn(tasks.spotlessApply, tasks.shadowJar) } // Build depends on spotless and shadow.
/* --------------------------- Javac opts ------------------------------- */
tasks.withType<JavaCompile>().configureEach {
options.compilerArgs.add("-parameters")
options.compilerArgs.add("-Xlint:deprecation") // Triggers deprecation warning messages.
options.encoding = "UTF-8"
options.isFork = true
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
vendor = JvmVendorSpec.GRAAL_VM
}
options.compilerArgs.add("-parameters") // Enable reflection for java code.
options.isFork = true // Run javac in its own process.
options.compilerArgs.add("-Xlint:deprecation") // Trigger deprecation warning messages.
options.encoding = "UTF-8" // Use UTF-8 file encoding.
}
/* ----------------------------- Auto Formatting ------------------------ */
spotless {
java {
removeUnusedImports()
palantirJavaFormat()
eclipse().configFile("config/formatter/eclipse-java-formatter.xml") // Eclipse java formatting.
leadingTabsToSpaces() // Convert leftover leading tabs to spaces.
removeUnusedImports() // Remove imports that aren't being called.
}
kotlinGradle {
ktfmt().kotlinlangStyle().configure { it.setMaxWidth(120) }
target("build.gradle.kts", "settings.gradle.kts")
ktfmt().kotlinlangStyle().configure { it.setMaxWidth(120) } // JetBrains Kotlin formatting.
target("build.gradle.kts", "settings.gradle.kts") // Gradle files to format.
}
}
checkstyle {
toolVersion = "10.18.1" // Declare checkstyle version to use.
configFile = file("config/checkstyle/checkstyle.xml") // Point checkstyle to config file.
isIgnoreFailures = true // Don't fail the build if checkstyle does not pass.
isShowViolations = true // Show the violations in any IDE with the checkstyle plugin.
}
tasks.named("compileJava") {
dependsOn("spotlessApply") // Run spotless before compiling with the JDK.
}
tasks.named("spotlessCheck") {
dependsOn("spotlessApply") // Run spotless before checking if spotless ran.
}
/* ------------------------------ Eclipse SHIM ------------------------- */
// This can't be put in eclipse.gradle.kts because Gradle is weird.
subprojects {
apply(plugin = "java-library")
apply(plugin = "eclipse")
eclipse.project.name = "${project.name}-${rootProject.name}"
tasks.withType<Jar>().configureEach { archiveBaseName.set("${project.name}-${rootProject.name}") }
}
+34
View File
@@ -0,0 +1,34 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
"https://checkstyle.org/dtds/configuration_1_3.dtd">
<module name="Checker">
<module name="FileTabCharacter">
<property name="eachLine" value="true"/>
<property name="severity" value="error"/>
</module>
<module name="TreeWalker">
<module name="FinalLocalVariable"/>
<module name="AvoidStarImport"/>
<module name="Indentation">
<property name="severity" value="ignore"/>
</module>
</module>
<module name="RegexpSingleline">
<property name="format" value="\borg\.junit\.jupiter\.api\.Assertions\.fail\s*\(\s*&quot;Not yet implemented&quot;\s*\)\s*;"/>
<property name="message" value="Remove placeholder fail() and implement the test."/>
<property name="ignoreCase" value="true"/>
<property name="severity" value="warning"/>
</module>
<module name="RegexpSingleline">
<property name="format" value="(?&lt;!\w)fail\s*\(\s*&quot;Not yet implemented&quot;\s*\)\s*;"/>
<property name="message" value="Remove placeholder fail() and implement the test."/>
<property name="severity" value="warning"/>
</module>
</module>
+404
View File
@@ -0,0 +1,404 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<profiles version="23">
<profile kind="CodeFormatterProfile" name="TrueOG Network Formatting" version="23">
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_switch_case_arrow_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_permitted_types" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_permitted_types_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.javadoc_do_not_separate_block_tags" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case_after_arrow" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.align_arrows_in_switch_on_columns" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.join_line_comments" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow" value="20"/>
<setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="49"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_permitted_types" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_never"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="next_line_on_wrap"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="false"/>
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block" value="1"/>
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
<setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="true"/>
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
</profile>
</profiles>
+151
View File
@@ -0,0 +1,151 @@
/* This is free and unencumbered software released into the public domain */
import org.gradle.plugins.ide.eclipse.model.EclipseModel
import java.nio.file.Files
import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.transform.OutputKeys
import javax.xml.transform.TransformerFactory
import javax.xml.transform.dom.DOMSource
import javax.xml.transform.stream.StreamResult
val kotlinAttribute: Attribute<Boolean> by rootProject.extra
val kotlinPluginProjects = configurations
.getByName("compileClasspath")
.allDependencies
.filterIsInstance<ProjectDependency>()
.filter { it -> it.attributes.getAttribute(kotlinAttribute) != null }
.map { it.path }
kotlinPluginProjects.forEach { evaluationDependsOn(it) }
val ideLibs: Configuration by
configurations.creating {
isCanBeResolved = true
isCanBeConsumed = false
}
configure<EclipseModel> {
project {
name = "Template-OG-Plugin"
}
classpath {
plusConfigurations.add(ideLibs)
}
}
val ideLibDir = layout.buildDirectory.dir("ide-libs")
val hashRegex = Regex("-[0-9a-fA-F]{10}(?=\\.jar$)") // Black magic.
val copyTasks = mutableListOf<TaskProvider<Copy>>()
kotlinPluginProjects.forEach { path ->
val sub = project(path)
val shadowJarProv = sub.tasks.named("shadowJar")
val copyTask =
tasks.register<Copy>("ideCopy${sub.name.replaceFirstChar(Char::titlecase)}") {
dependsOn(shadowJarProv)
from(shadowJarProv)
into(ideLibDir)
rename { it.replace(hashRegex, "") } // Remove git commit hash from jarfile.
}
copyTasks += copyTask
}
/* Ensure the jars exist before .classpath is generated */
tasks.named("eclipseClasspath").configure { dependsOn(copyTasks) }
/* Supply those jars to the ideLibs configuration (after evaluation) */
afterEvaluate { dependencies { add("ideLibs", fileTree(ideLibDir) { include("*.jar") }) } }
val injectIdeLibs =
tasks.register("injectIdeLibs") {
dependsOn("eclipse") // run after all eclipse files are generated
doLast {
val cpFile = file(".classpath")
if (!cpFile.exists()) return@doLast
val jars = fileTree(ideLibDir.get()) { include("*.jar") }.files.sortedBy { it.name }
if (jars.isEmpty()) return@doLast
// Parse DOM
val dbf = DocumentBuilderFactory.newInstance()
val doc = dbf.newDocumentBuilder().parse(cpFile)
val root = doc.documentElement
// Helper to see if an entry already exists
fun exists(path: String): Boolean =
root.getElementsByTagName("classpathentry").let { list ->
(0 until list.length).any { i ->
val n = list.item(i)
val kind = n.attributes?.getNamedItem("kind")?.nodeValue
val p = n.attributes?.getNamedItem("path")?.nodeValue
kind == "lib" && p == path
}
}
// Remove any entry that points to ide-libs dir (folder or jars) to avoid dupes
val toRemove = mutableListOf<org.w3c.dom.Node>()
val list = root.getElementsByTagName("classpathentry")
val dirPath = ideLibDir.get().asFile.absolutePath
for (i in 0 until list.length) {
val n = list.item(i)
val kind = n.attributes?.getNamedItem("kind")?.nodeValue
val p = n.attributes?.getNamedItem("path")?.nodeValue ?: ""
if (kind == "lib" && (p == dirPath || p.startsWith("$dirPath/"))) {
toRemove += n
}
}
toRemove.forEach { root.removeChild(it) }
// Append our jar entries LAST
jars.forEach { f ->
val abs = f.absolutePath
if (!exists(abs)) {
val entry = doc.createElement("classpathentry")
entry.setAttribute("kind", "lib")
entry.setAttribute("path", abs)
root.appendChild(entry)
}
}
// Write back pretty
val tf =
TransformerFactory.newInstance().newTransformer().apply {
setOutputProperty(OutputKeys.INDENT, "yes")
setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "1")
setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no")
setOutputProperty(OutputKeys.ENCODING, "UTF-8")
}
Files.newBufferedWriter(cpFile.toPath()).use { w -> tf.transform(DOMSource(doc), StreamResult(w)) }
}
}
tasks.named("eclipse").configure { finalizedBy(injectIdeLibs) }
val eclipseModel = extensions.getByType<EclipseModel>()
fun Project.addResolvableEclipseConfigs() {
val jarAttr =
objects.named(org.gradle.api.attributes.LibraryElements::class, org.gradle.api.attributes.LibraryElements.JAR)
val apiAttr = objects.named(org.gradle.api.attributes.Usage::class, org.gradle.api.attributes.Usage.JAVA_API)
val compileOnlyRes =
configurations.create("eclipseCompileOnly") {
extendsFrom(configurations.getByName("compileOnly"))
isCanBeResolved = true
isCanBeConsumed = false
attributes.attribute(org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE, apiAttr)
attributes.attribute(org.gradle.api.attributes.LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, jarAttr)
}
val compileOnlyApiRes =
configurations.create("eclipseCompileOnlyApi") {
extendsFrom(configurations.getByName("compileOnlyApi"))
isCanBeResolved = true
isCanBeConsumed = false
attributes.attribute(org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE, apiAttr)
attributes.attribute(org.gradle.api.attributes.LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, jarAttr)
}
eclipseModel.classpath.plusConfigurations.addAll(listOf(compileOnlyRes, compileOnlyApiRes))
}
addResolvableEclipseConfigs()
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
+9 -15
View File
@@ -1,19 +1,13 @@
pluginManagement {
repositories {
mavenLocal()
gradlePluginPortal()
}
}
rootProject.name = "PlayTimes-OG"
// Run the bootstrap at configuration time.
val process = ProcessBuilder("sh", "bootstrap.sh").directory(rootDir).start()
val exitValue = process.waitFor()
if (exitValue != 0) {
throw GradleException("bootstrap.sh failed with exit code $exitValue")
ProcessBuilder("sh", "bootstrap.sh").directory(rootDir).inheritIO().start().let {
if (it.waitFor() != 0) throw GradleException("bootstrap.sh failed")
}
include("libs:Utilities-OG")
file("libs")
.listFiles()
?.filter { it.isDirectory && !it.name.startsWith(".") }
?.forEach { dir ->
include(":libs:${dir.name}")
project(":libs:${dir.name}").projectDir = dir
}
@@ -35,15 +35,19 @@ public class PlayTimes extends JavaPlugin {
AFKManager.getInstance().startAFKChecker();
getLogger().info("Successfully loaded.");
}
@Override
public void onDisable() {
AFKManager.getInstance().endAFKChecker();
getLogger().info("PlayTimes shutting down");
}
private void registerEvents() {
PluginManager pm = getServer().getPluginManager();
DataManager data = DataManager.getInstance();
@@ -51,6 +55,7 @@ public class PlayTimes extends JavaPlugin {
pm.registerEvents(new Quit(), this);
if (data.hasAfkEnabled()) {
pm.registerEvents(new onJoinQuit(), this);
FileConfiguration config = data.getConfig();
@@ -59,41 +64,66 @@ public class PlayTimes extends JavaPlugin {
boolean cancelAfkOnInteract = config.getBoolean("afk-settings.cancel-afk.on-player-interact");
if (cancelAfkOnMove || cancelAfkOnChat || cancelAfkOnInteract) {
if (cancelAfkOnMove) pm.registerEvents(new onMove(), this);
if (cancelAfkOnChat) pm.registerEvents(new onChat(), this);
if (cancelAfkOnInteract) pm.registerEvents(new onInteract(), this);
if (cancelAfkOnMove)
pm.registerEvents(new onMove(), this);
if (cancelAfkOnChat)
pm.registerEvents(new onChat(), this);
if (cancelAfkOnInteract)
pm.registerEvents(new onInteract(), this);
}
}
}
private void registerCommands() {
Objects.requireNonNull(getCommand("playtime")).setExecutor(new Time());
Objects.requireNonNull(getCommand("uptime")).setExecutor(new Uptime());
Objects.requireNonNull(getCommand("topplaytime")).setExecutor(new TopTime());
Objects.requireNonNull(this.getCommand("pt")).setTabCompleter(new TimeTabCompleter());
}
public void loadDatabase() {
if (DataManager.getInstance().getDBConfig().getBoolean("database-settings.enabled")) {
getLogger().info("Connecting to Database...");
DatabaseManager databaseManager = DatabaseManager.getInstance();
try {
if (databaseManager.getDataSource().getConnection() != null) {
try {
databaseManager.getDataSource().closeConnection();
} catch (Exception e) {
getLogger().warning("Error while trying to close Database connection..");
}
databaseManager.load();
if (DataManager.getInstance().getDBConfig().getBoolean("purge-database.enabled"))
databaseManager.purgeOldPlaytimeData();
}
} catch (SQLException e) {
getLogger().severe("Error loading the database: " + e.getMessage());
e.printStackTrace();
}
}
}
}
@@ -30,88 +30,122 @@ public class AFKManager {
private BukkitTask afkCheckerTask = null;
private AFKManager() {
config = DataManager.getInstance().getConfig();
afkThresholdMillis = config.getLong("afk-settings.threshold") * 60L * 1000L;
notifyOnAfk = config.getBoolean("afk-settings.broadcast-afk.on-enter-afk");
notifyOnBack = config.getBoolean("afk-settings.broadcast-afk.on-exit-afk");
onAfkMessage = config.getString("afk-settings.on-enter-afk-message");
onBackMessage = config.getString("afk-settings.on-exit-afk-message");
}
public static AFKManager getInstance() {
if (instance == null) {
instance = new AFKManager();
}
return instance;
}
public void updateActivity(Player player) {
boolean wasAFK = isAFK(player);
lastActive.put(player.getUniqueId(), System.currentTimeMillis());
if (wasAFK && notifyOnBack) {
player.sendMessage(ChatUtil.format(onBackMessage));
}
}
public boolean isAFK(Player player) {
return (lastActive.containsKey(player.getUniqueId())
&& System.currentTimeMillis() - lastActive.get(player.getUniqueId()) > afkThresholdMillis);
}
public void startAFKChecker() {
if (afkCheckerTask == null || afkCheckerTask.isCancelled()) {
afkCheckerTask = Bukkit.getScheduler()
.runTaskTimerAsynchronously(
PlayTimes.getPlugin(PlayTimes.class),
() -> {
for (Player player : Bukkit.getOnlinePlayers()) {
if (isAFK(player)) {
if (!afkTime.containsKey(player.getUniqueId()) && notifyOnAfk) {
player.sendMessage(ChatUtil.format(onAfkMessage));
}
afkTime.put(
player.getUniqueId(),
afkTime.getOrDefault(
player.getUniqueId(),
getDefaultAfkTime(player.getUniqueId()))
+ 1);
}
afkCheckerTask = Bukkit.getScheduler().runTaskTimerAsynchronously(PlayTimes.getPlugin(PlayTimes.class),
() ->
{
for (Player player : Bukkit.getOnlinePlayers()) {
if (isAFK(player)) {
if (!afkTime.containsKey(player.getUniqueId()) && notifyOnAfk) {
player.sendMessage(ChatUtil.format(onAfkMessage));
}
},
20L,
20L);
afkTime.put(player.getUniqueId(), afkTime.getOrDefault(player.getUniqueId(),
getDefaultAfkTime(player.getUniqueId())) + 1);
}
}
}, 20L, 20L);
}
}
public void endAFKChecker() {
if (afkCheckerTask != null) {
afkCheckerTask.cancel();
afkCheckerTask = null;
}
}
private Long getDefaultAfkTime(UUID uuid) {
DataManager dataManager = DataManager.getInstance();
if (dataManager.hasDatabase() && DatabaseManager.getInstance().hasTimeForServer(uuid)) {
Map<String, Long> timeMap = DatabaseManager.getInstance().getTimeForServer(uuid);
return timeMap != null ? timeMap.getOrDefault("afktime", 0L) : 0L;
} else {
return dataManager.getData().getLong("afktime." + uuid, 0L);
}
}
public void removePlayer(UUID uuid) {
lastActive.remove(uuid);
afkTime.remove(uuid);
}
public long getAFKTime(UUID uuid) {
return afkTime.getOrDefault(uuid, getDefaultAfkTime(uuid));
}
public void reload() {
endAFKChecker();
FileConfiguration config = DataManager.getInstance().getConfig();
afkThresholdMillis = config.getLong("afk-settings.threshold") * 60L * 1000L;
@@ -120,5 +154,7 @@ public class AFKManager {
onAfkMessage = config.getString("afk-settings.on-enter-afk-message");
onBackMessage = config.getString("afk-settings.on-exit-afk-message");
startAFKChecker();
}
}
@@ -9,6 +9,9 @@ public class onChat implements Listener {
@EventHandler
public void onPlayerChat(AsyncChatEvent event) {
AFKManager.getInstance().updateActivity(event.getPlayer());
}
}
@@ -9,6 +9,9 @@ public class onInteract implements Listener {
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
AFKManager.getInstance().updateActivity(event.getPlayer());
}
}
@@ -10,11 +10,16 @@ public class onJoinQuit implements Listener {
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
AFKManager.getInstance().updateActivity(event.getPlayer());
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
AFKManager.getInstance().removePlayer(event.getPlayer().getUniqueId());
}
}
@@ -9,9 +9,15 @@ public class onMove implements Listener {
@EventHandler
public void onPlayerMove(PlayerMoveEvent event) {
if (event.getFrom().getBlock().equals(event.getTo().getBlock())) {
return;
}
AFKManager.getInstance().updateActivity(event.getPlayer());
}
}
@@ -13,22 +13,31 @@ public class TimelessPlayer {
private final TimeManager timings;
public TimelessPlayer(final Player player) {
this.uuid = player.getUniqueId();
this.stats = StatManager.getInstance();
this.timings = TimeManager.getInstance();
}
public TimelessPlayer(final UUID player) {
this.uuid = player;
this.stats = StatManager.getInstance();
this.timings = TimeManager.getInstance();
}
public String getPlayTime() {
return this.timings.buildFormat(this.stats.getPlayerStat(this.uuid, StatisticType.PLAYTIME) / 20L);
}
public long getRawPlayTimeInSeconds() {
return this.stats.getPlayerStat(this.uuid, StatisticType.PLAYTIME) / 20L;
}
}
@@ -12,78 +12,114 @@ import me.codedred.playtimes.statistics.StatManager;
public class TimelessServer {
public List<UUID> getTop10Players() {
final List<UUID> players = new ArrayList<>();
final Leaderboard board = new Leaderboard();
final Map<String, Integer> map = board.getTopTen();
final Object[] array = map.keySet().toArray();
for (int i = 0; i < map.size(); ++i) {
players.add(UUID.fromString(array[i].toString()));
}
return players;
}
public List<Integer> getTop10Times() {
final List<Integer> players = new ArrayList<>();
final Leaderboard board = new Leaderboard();
final Map<String, Integer> map = board.getTopTen();
final Object[] array = map.values().toArray();
for (int i = 0; i < map.size(); ++i) {
players.add(Integer.parseInt(array[i].toString()) / 20);
}
return players;
}
public Map<String, Integer> getTopMap() {
final Leaderboard board = new Leaderboard();
return board.getTopTen();
}
public UUID getNumberOne() {
return this.getTop10Players().get(0);
}
public UUID getNumberTwo() {
return this.getTop10Players().get(1);
}
public UUID getNumberThree() {
return this.getTop10Players().get(2);
}
public UUID getNumberFour() {
return this.getTop10Players().get(3);
}
public UUID getNumberFive() {
return this.getTop10Players().get(4);
}
public UUID getNumberSix() {
return this.getTop10Players().get(5);
}
public UUID getNumberSeven() {
return this.getTop10Players().get(6);
}
public UUID getNumberEight() {
return this.getTop10Players().get(7);
}
public UUID getNumberNine() {
return this.getTop10Players().get(8);
}
public UUID getNumberTen() {
return this.getTop10Players().get(9);
}
public String getUptime() {
return StatManager.getInstance().getUptime();
}
public long getUptimeInSeconds() {
return TimeUnit.MILLISECONDS.toSeconds(
ManagementFactory.getRuntimeMXBean().getUptime());
return TimeUnit.MILLISECONDS.toSeconds(ManagementFactory.getRuntimeMXBean().getUptime());
}
}
@@ -28,14 +28,18 @@ public class Time implements CommandExecutor {
private final DataManager data = DataManager.getInstance();
public boolean onCommand(CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args) {
if (!sender.hasPermission("pt.use")) {
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
return true;
}
String arg = args.length > 0 ? args[0].toLowerCase() : "";
switch (arg) {
case "":
handlePlayerCommand(sender);
break;
@@ -63,16 +67,22 @@ public class Time implements CommandExecutor {
default:
handleOtherPlayerCommand(sender, args);
break;
}
return true;
}
private void handleHelpCommand(CommandSender sender) {
if (!sender.hasPermission("pt.reload")) {
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
return;
}
sender.sendMessage(ChatUtil.format("&6&l*** PlayTimes Help ***"));
sender.sendMessage(ChatUtil.format("&e/pt: &7Displays your play time"));
sender.sendMessage(ChatUtil.format("&e/pt <player>: &7Displays the play time of <player>"));
@@ -81,187 +91,236 @@ public class Time implements CommandExecutor {
sender.sendMessage(ChatUtil.format("&e/pt block <player>: &7Blocks a player from leaderboards"));
sender.sendMessage(ChatUtil.format("&e/pt unblock <player>: &7Unblocks a player from leaderboards"));
sender.sendMessage(ChatUtil.format("&e/pt version: &7Displays the version info"));
}
private void handleVersionCommand(CommandSender sender) {
if (!sender.hasPermission("pt.reload")) {
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
return;
}
sender.sendMessage(ChatUtil.format("&6&l*** PlayTimes Version Info ***"));
if (sender instanceof Player) {
UtilitiesOG.trueogMessage(
(Player) sender,
"&6" + "Server version: "
+ "&f"
+ Bukkit.getServer().getVersion()
+ "&6"
+ "\nPlayTimes version: "
+ "&f"
+ "v1.0"
+ "&6"
+ "\nStat Manager: "
+ "&f"
+ StatManager.getInstance().name
+ "&6"
+ "\nDatabase connected: "
+ "&f"
+ DataManager.getInstance().hasDatabase()
+ "&6"
+ "\nAFK Status: "
+ "&f"
+ DataManager.getInstance().hasAfkEnabled());
UtilitiesOG.trueogMessage((Player) sender,
"&6" + "Server version: " + "&f" + Bukkit.getServer().getVersion() + "&6" + "\nPlayTimes version: "
+ "&f" + "v1.0" + "&6" + "\nStat Manager: " + "&f" + StatManager.getInstance().name + "&6"
+ "\nDatabase connected: " + "&f" + DataManager.getInstance().hasDatabase() + "&6"
+ "\nAFK Status: " + "&f" + DataManager.getInstance().hasAfkEnabled());
} else {
UtilitiesOG.logToConsole(
"[PlayTimes-OG] ",
"&6" + "Server version: "
+ "&f"
+ Bukkit.getServer().getVersion()
+ "&6"
+ "\nPlayTimes version: "
+ "&f"
+ "v1.0"
+ "&6"
+ "\nStat Manager: "
+ "&f"
+ StatManager.getInstance().name
+ "&6"
+ "\nDatabase connected: "
+ "&f"
+ DataManager.getInstance().hasDatabase()
+ "&6"
+ "\nAFK Status: "
+ "&f"
+ DataManager.getInstance().hasAfkEnabled());
UtilitiesOG.logToConsole("[PlayTimes-OG] ",
"&6" + "Server version: " + "&f" + Bukkit.getServer().getVersion() + "&6" + "\nPlayTimes version: "
+ "&f" + "v1.0" + "&6" + "\nStat Manager: " + "&f" + StatManager.getInstance().name + "&6"
+ "\nDatabase connected: " + "&f" + DataManager.getInstance().hasDatabase() + "&6"
+ "\nAFK Status: " + "&f" + DataManager.getInstance().hasAfkEnabled());
}
}
private void handlePlayerCommand(CommandSender sender) {
if (!(sender instanceof Player)) {
StatManager stats = StatManager.getInstance();
sender.sendMessage(ChatUtil.format("&cThe console has been up for " + stats.getUptime()));
return;
}
new BukkitRunnable() {
@Override
public void run() {
Player player = (Player) sender;
Message message = new Message(sender, player.getUniqueId(), player.getName());
message.sendMessageToTarget();
}
}.runTaskAsynchronously(JavaPlugin.getPlugin(PlayTimes.class));
}
private void handleReloadCommand(CommandSender sender) {
if (!sender.hasPermission("pt.reload")) {
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
return;
}
data.reloadAll();
TimeConstants.reload();
TimeManager.getInstance().registerTimings();
sender.sendMessage(ChatUtil.format("&aPlayTimes Configurations Reloaded!"));
if (DataManager.getInstance().hasDatabase()) {
sender.sendMessage(ChatUtil.format("&aTrying to reload the Database settings?"));
sender.sendMessage(ChatUtil.format(" &e&oTry, /pt reloadDatabase"));
}
}
private void handleReloadDatabaseCommand(CommandSender sender) {
if (!sender.hasPermission("pt.reload")) {
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
return;
}
data.reloadDatabase();
PlayTimes.getPlugin(PlayTimes.class).loadDatabase();
sender.sendMessage(ChatUtil.format("&aDatabase Reloaded."));
sender.sendMessage(ChatUtil.format("&oIf you are still encountering issues try restarting your server."));
}
private void handleTopCommand(CommandSender sender) {
Bukkit.dispatchCommand(sender, "toppt");
}
private void handleBlockCommand(CommandSender sender, String[] args, boolean block) {
String blockAction = block ? "block" : "unblock";
if (!sender.hasPermission("pt.block")) {
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
return;
}
if (args.length < 2) {
sender.sendMessage(
ChatUtil.formatWithPrefix("&c&lIncorrect Usage&c, try &7/pt " + blockAction + " <player>"));
return;
}
String playerName = args[1];
String blockedKey = "blocked." + playerName.toLowerCase();
if (block == data.getData().contains(blockedKey)) {
sender.sendMessage(ChatUtil.formatWithPrefix("&cUser is already " + blockAction + "ed!"));
sender.sendMessage(
ChatUtil.formatWithPrefix("&c&oMaybe try, &7/pt " + (block ? "unblock" : "block") + " <player>"));
return;
}
UUID uuid;
if (Bukkit.getPlayer(playerName) == null) {
try {
uuid = ServerManager.getInstance().getUUID(playerName.toLowerCase());
} catch (NullPointerException e) {
ChatUtil.errno(sender, ChatUtil.ChatTypes.PLAYER_NOT_FOUND);
return;
}
} else {
uuid = Objects.requireNonNull(Bukkit.getPlayer(playerName)).getUniqueId();
}
if (uuid == null) {
sender.sendMessage(ChatUtil.formatWithPrefix("&c&lUser not found."));
return;
}
if (block) {
data.getData().set(blockedKey, uuid.toString());
if (data.getData().contains("leaderboard." + uuid)) {
data.getData().set("leaderboard." + uuid, null);
}
sender.sendMessage(ChatUtil.formatWithPrefix("&aUser &c&lBLOCKED &afrom leaderboards!"));
} else {
data.getData().set(blockedKey, null);
sender.sendMessage(ChatUtil.formatWithPrefix("&aUser &b&lUNBLOCKED &afrom leaderboards!"));
}
data.saveData();
}
private void handleOtherPlayerCommand(CommandSender sender, String[] args) {
if (!sender.hasPermission("pt.others")) {
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
return;
}
new BukkitRunnable() {
@Override
public void run() {
Pattern p = Pattern.compile("[^a-z0-9_]", Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(args[0]);
boolean b = m.find();
if (b) {
ChatUtil.errno(sender, ChatUtil.ChatTypes.PLAYER_NOT_FOUND);
return;
}
UUID target;
if (Bukkit.getPlayer(args[0]) == null) {
target = ServerManager.getInstance().getUUID(args[0]);
if (target == null) {
ChatUtil.errno(sender, ChatUtil.ChatTypes.PLAYER_NOT_FOUND);
return;
}
} else {
target = Objects.requireNonNull(Bukkit.getPlayer(args[0])).getUniqueId();
}
OfflinePlayer offlinePlayer = Bukkit.getServer().getOfflinePlayer(target);
Message message = new Message(sender, target, offlinePlayer.getName());
message.sendMessageToTarget();
}
}.runTaskAsynchronously(JavaPlugin.getPlugin(PlayTimes.class));
}
}
@@ -21,34 +21,43 @@ public class TopTime implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, @NotNull Command cmd, @NotNull String label, String[] args) {
if (!sender.hasPermission("pt.top")) {
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
return true;
}
DataManager data = DataManager.getInstance();
if (data.getConfig().getBoolean("top-playtime.enable-cooldown")
&& !sender.hasPermission("pt.block-cooldown")
&& sender instanceof Player) {
if (data.getConfig().getBoolean("top-playtime.enable-cooldown") && !sender.hasPermission("pt.block-cooldown")
&& sender instanceof Player)
{
Player player = (Player) sender;
if (CoolDownUtil.contains(player.getUniqueId())) {
String cooldownMessage = Objects.requireNonNull(data.getConfig().getString("messages.cooldown"))
.replace("%timeleft%", Integer.toString(CoolDownUtil.left(player.getUniqueId())));
sender.sendMessage(ChatUtil.formatWithPrefix(cooldownMessage));
return true;
}
CoolDownUtil.add(
player.getUniqueId(),
CoolDownUtil.add(player.getUniqueId(),
System.currentTimeMillis() + (data.getConfig().getInt("top-playtime.cooldown-seconds") * 1000L));
}
Leaderboard board = new Leaderboard();
Map<String, Integer> map = board.getTopTen();
if (map.isEmpty()) {
sender.sendMessage(ChatUtil.format("&cRejoin the server to fill the leaderboard!"));
return true;
}
StatManager statManager = StatManager.getInstance();
@@ -60,6 +69,7 @@ public class TopTime implements CommandExecutor {
sender.sendMessage(header);
for (int i = 0; i < map.size(); i++) {
UUID uuid = UUID.fromString(map.keySet().toArray()[i].toString());
org.bukkit.OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid);
@@ -69,25 +79,27 @@ public class TopTime implements CommandExecutor {
String offlinePlayerName = offlinePlayer.getName() != null ? offlinePlayer.getName() : defaultPlayerName;
String place = String.valueOf(i + 1);
String time =
timeManager.buildFormat(map.get(offlinePlayer.getUniqueId().toString()) / 20);
String time = timeManager.buildFormat(map.get(offlinePlayer.getUniqueId().toString()) / 20);
String joinDate = statManager.getJoinDate(uuid) != null ? statManager.getJoinDate(uuid) : defaultJoinDate;
if (time == null) {
time = defaultTime;
}
String formattedContent = content.replace("%player%", offlinePlayerName)
.replace("%place%", place)
.replace("%time%", time)
.replace("%joindate%", joinDate);
String formattedContent = content.replace("%player%", offlinePlayerName).replace("%place%", place)
.replace("%time%", time).replace("%joindate%", joinDate);
sender.sendMessage(ChatUtil.format(formattedContent));
content = data.getConfig().getString("top-playtime.content");
}
sender.sendMessage(footer);
return true;
}
}
@@ -15,17 +15,22 @@ public class Uptime implements CommandExecutor {
@Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command cmd, String cmdL, String[] args) {
// command must be uptime,serveruptime,or serverupt
if (!cmdL.equalsIgnoreCase("uptime")
&& !cmdL.equalsIgnoreCase("serveruptime")
&& !cmdL.equalsIgnoreCase("serverupt")) {
if (!cmdL.equalsIgnoreCase("uptime") && !cmdL.equalsIgnoreCase("serveruptime")
&& !cmdL.equalsIgnoreCase("serverupt"))
{
return false;
}
// check for permission
if (!sender.hasPermission("pt.uptime")) {
ChatUtil.errno(sender, ChatUtil.ChatTypes.NO_PERMISSION);
return true;
}
// get the uptime
@@ -34,24 +39,30 @@ public class Uptime implements CommandExecutor {
// iterate through the messages and replace the placeholders
for (String message : messages) {
// 1: replace them using placeholder api
// TODO: use MMAPI
/*
if (ServerUtils.hasPAPI() && sender instanceof Player) {
Player player = (Player) sender;
message = PlaceholderAPI.setPlaceholders(player, message);
}
*/
* if (ServerUtils.hasPAPI() && sender instanceof Player) { Player player =
* (Player) sender; message = PlaceholderAPI.setPlaceholders(player, message); }
*/
// 2. replace them using java string methods
if (message.contains("{\"text\":") && sender instanceof Player) {
String consoleCommand = "tellraw " + sender.getName() + " " + message.replace("%serveruptime%", uptime);
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), consoleCommand);
// 3. if all else fails dont send name
} else if (sender instanceof Player) {
sender.sendMessage(ChatUtil.format(message.replace("%serveruptime%", uptime)));
}
}
return true;
}
}
@@ -13,43 +13,70 @@ import org.jetbrains.annotations.NotNull;
public class TimeTabCompleter implements TabCompleter {
@Override
public List<String> onTabComplete(
@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, String[] args) {
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias,
String[] args)
{
List<String> completions = new ArrayList<>();
if (args.length == 1) {
if (sender.hasPermission("pt.use")) {
completions.add("top");
completions.addAll(getOnlinePlayerNames(sender));
}
if (sender.hasPermission("pt.block")) {
completions.add("block");
completions.add("unblock");
}
if (sender.hasPermission("pt.reload")) {
completions.add("reload");
completions.add("version");
completions.add("help");
}
}
return completions;
}
private List<String> getOnlinePlayerNames(CommandSender sender) {
List<String> playerNames = new ArrayList<>();
for (Player player : Bukkit.getOnlinePlayers()) {
if (!isVanished(player) || sender.equals(player) || sender.hasPermission("pt.seevanished")) {
playerNames.add(player.getName());
}
}
return playerNames;
}
private boolean isVanished(Player player) {
for (MetadataValue meta : player.getMetadata("vanished")) {
if (meta.asBoolean()) return true;
if (meta.asBoolean())
return true;
}
return false;
}
}
@@ -19,43 +19,54 @@ public class CustomConfig {
private File dataConfigFile = null;
public CustomConfig(PlayTimes plugin, String fileName) {
this.plugin = plugin;
this.name = fileName;
saveDefaultConfig();
}
public void reloadConfig() {
if (this.dataConfigFile == null) {
this.dataConfigFile = new File(this.plugin.getDataFolder(), name);
}
this.dataConfig = YamlConfiguration.loadConfiguration(this.dataConfigFile);
if ("config.yml".equals(name)) checkAndAddDefaults();
if ("config.yml".equals(name))
checkAndAddDefaults();
try (InputStream defConfigStream = this.plugin.getResource(name)) {
if (defConfigStream != null) {
YamlConfiguration defConfig =
YamlConfiguration.loadConfiguration(new InputStreamReader(defConfigStream));
YamlConfiguration defConfig = YamlConfiguration
.loadConfiguration(new InputStreamReader(defConfigStream));
this.dataConfig.setDefaults(defConfig);
}
} catch (IOException e) {
this.plugin.getLogger().log(Level.SEVERE, "Error reading default config", e);
}
}
private void checkAndAddDefaults() {
Map<String, Object> requiredKeys = new LinkedHashMap<>();
requiredKeys.put("prefix", "&7[&b&lPlayTimes&7]");
requiredKeys.put("use-papi-placeholders", false);
requiredKeys.put("playtime.message", new String[] {
"&b&m=======&b&l[%player%]&b&m=======",
"&aPlaytime:&f %playtime%",
"&aTimes Joined:&f %timesjoined%",
"&aJoin Date:&f %joindate%",
"&b&m============================",
});
requiredKeys.put("playtime.message",
new String[]
{ "&b&m=======&b&l[%player%]&b&m=======", "&aPlaytime:&f %playtime%", "&aTimes Joined:&f %timesjoined%",
"&aJoin Date:&f %joindate%", "&b&m============================", });
requiredKeys.put("playtime.name.second", "s");
requiredKeys.put("playtime.name.minute", "min ");
@@ -80,9 +91,10 @@ public class CustomConfig {
requiredKeys.put("afk-settings.cancel-afk.on-player-chat", true);
requiredKeys.put("afk-settings.cancel-afk.on-player-interact", true);
requiredKeys.put("uptime.message", new String[] {
"&b&m============================", "&aServer Uptime:&f %serveruptime%", "&b&m============================",
});
requiredKeys.put("uptime.message",
new String[]
{ "&b&m============================", "&aServer Uptime:&f %serveruptime%",
"&b&m============================", });
requiredKeys.put("top-playtime.header", "&b******&9[&3&lPlayTime Leaderboards&9]&b*****");
requiredKeys.put("top-playtime.content", "&5%place%) &9&l%player% &9&o- %time%");
@@ -98,44 +110,69 @@ public class CustomConfig {
requiredKeys.put("messages.player-never-joined", "&cThis player has not joined the server.");
requiredKeys.put("messages.cooldown", "&cCommand unavailable for %timeleft% seconds!");
requiredKeys.put(
"uuid-lookups.what-does-this-do", "https://github.com/CodedRed-Spigot/PlayTimes/wiki/UUID-LOOKUPS");
requiredKeys.put("uuid-lookups.what-does-this-do",
"https://github.com/CodedRed-Spigot/PlayTimes/wiki/UUID-LOOKUPS");
requiredKeys.put("uuid-lookups.type", "default");
boolean changesMade = false;
for (Map.Entry<String, Object> entry : requiredKeys.entrySet()) {
if (!this.dataConfig.contains(entry.getKey())) {
this.dataConfig.set(entry.getKey(), entry.getValue());
changesMade = true;
}
}
if (changesMade) {
plugin.getLogger().info("Missing configuration keys detected in 'Config.yml'. Adding them now.");
saveConfig();
}
}
public FileConfiguration getConfig() {
if (this.dataConfig == null) reloadConfig();
if (this.dataConfig == null)
reloadConfig();
return this.dataConfig;
}
public void saveConfig() {
if (this.dataConfig == null || this.dataConfigFile == null) return;
if (this.dataConfig == null || this.dataConfigFile == null)
return;
try {
getConfig().save(this.dataConfigFile);
} catch (IOException ex) {
this.plugin.getLogger().log(Level.SEVERE, ex, () -> "Could not save config to " + this.dataConfigFile);
}
}
public void saveDefaultConfig() {
if (this.dataConfigFile == null) {
this.dataConfigFile = new File(this.plugin.getDataFolder(), name);
}
if (!this.dataConfigFile.exists()) {
this.plugin.saveResource(name, false);
}
}
}
@@ -14,42 +14,61 @@ public class DataManager {
private final CustomConfig cfg = new CustomConfig(JavaPlugin.getPlugin(PlayTimes.class), "config.yml");
public static DataManager getInstance() {
return instance;
}
public FileConfiguration getConfig() {
return cfg.getConfig();
}
public FileConfiguration getData() {
return data.getConfig();
}
public FileConfiguration getDBConfig() {
return db.getConfig();
}
public void saveData() {
data.saveConfig();
}
public void reloadAll() {
data.reloadConfig();
cfg.reloadConfig();
db.reloadConfig();
if (hasAfkEnabled()) AFKManager.getInstance().reload();
if (hasAfkEnabled())
AFKManager.getInstance().reload();
}
public void reloadDatabase() {
db.reloadConfig();
}
public boolean hasDatabase() {
return (getDBConfig().getBoolean("database-settings.enabled")
&& DatabaseManager.getInstance().isConnected());
return (getDBConfig().getBoolean("database-settings.enabled") && DatabaseManager.getInstance().isConnected());
}
public boolean hasAfkEnabled() {
return getConfig().getBoolean("afk-settings.enabled", false);
}
}
@@ -4,7 +4,9 @@ import java.sql.Connection;
import java.sql.SQLException;
public interface DataSource {
Connection getConnection() throws SQLException;
void closeConnection() throws SQLException;
}
@@ -14,6 +14,7 @@ public class MySQL implements DataSource {
private final String password;
public MySQL(PlayTimes plugin) {
var config = DataManager.getInstance().getDBConfig().getConfigurationSection("database-settings");
String host = config.getString("host");
String port = config.getString("port");
@@ -22,24 +23,33 @@ public class MySQL implements DataSource {
String database = config.getString("database");
boolean SSL = config.getBoolean("useSSL");
this.connectionUrl =
String.format("jdbc:mysql://%s:%s/%s?autoReconnect=true&useSSL=" + SSL, host, port, database);
this.connectionUrl = String.format("jdbc:mysql://%s:%s/%s?autoReconnect=true&useSSL=" + SSL, host, port,
database);
try {
Class.forName("com.mysql.cj.jdbc.Driver");
plugin.getLogger().info("Successfully connected to database.");
} catch (ClassNotFoundException e) {
plugin.getLogger().severe("MySQL JDBC Driver not found: " + e.getMessage());
}
}
@Override
public Connection getConnection() throws SQLException {
return DriverManager.getConnection(connectionUrl, user, password);
}
@Override
public void closeConnection() throws SQLException {
// connection.close();
}
}
@@ -12,26 +12,37 @@ public class SQLite implements DataSource {
private Connection connection;
public SQLite(PlayTimes plugin) {
var config = DataManager.getInstance().getDBConfig();
var database = config.getString("database");
try {
Class.forName("org.sqlite.JDBC");
String url = "jdbc:sqlite:" + plugin.getDataFolder() + "/" + database + ".db";
this.connection = DriverManager.getConnection(url);
plugin.getLogger().info("Successfully connected to database.");
} catch (SQLException | ClassNotFoundException exception) {
plugin.getLogger().severe("ERROR! Database failed to connect. Please check your config.yml and try again.");
}
}
@Override
public Connection getConnection() {
return connection;
}
@Override
public void closeConnection() throws SQLException {
connection.close();
}
}
@@ -29,25 +29,36 @@ public class DatabaseManager {
private Map<UUID, Map<String, Map<String, Long>>> userPlaytimes = new HashMap<>();
private DatabaseManager() {
serverId = DataManager.getInstance().getDBConfig().getString("database-settings.serverId");
setupDataSource();
}
public static DatabaseManager getInstance() {
if (instance == null) {
instance = new DatabaseManager();
}
return instance;
}
public DataSource getDataSource() {
return this.dataSource;
}
private void setupDataSource() {
String type = DataManager.getInstance().getDBConfig().getString("database-settings.type");
switch (type.toLowerCase()) {
case "mysql":
this.dataSource = new MySQL(PlayTimes.getPlugin(PlayTimes.class));
break;
@@ -57,127 +68,187 @@ public class DatabaseManager {
default:
throw new IllegalStateException(
"Unexpected database type: " + type + ". Accepted Values: 'mysql', 'sqlite'");
}
try {
connected = dataSource != null && dataSource.getConnection() != null;
} catch (SQLException e) {
Bukkit.getServer().getLogger().warning("[PlayTimes] Error thrown from DatabaseManager!");
}
}
public boolean isConnected() {
return connected;
}
public void load() {
if (isConnected()) {
this.usersTable = new UsersTable(dataSource);
this.usersTable.createTable();
} else {
Bukkit.getServer().getLogger().warning("[PlayTimes] Couldn't connect to Database!");
}
}
private UsersTable getUsersTable() {
if (this.usersTable == null) {
this.usersTable = new UsersTable(dataSource);
}
return this.usersTable;
}
public boolean retrievePlaytime(UUID uuid) {
Map<String, Map<String, Long>> timeMap = getUsersTable().getPlaytimesByUuid(uuid);
if (timeMap != null && !timeMap.isEmpty()) {
userPlaytimes.put(uuid, timeMap);
return true;
}
return false;
}
public void updatePlaytime(UUID uuid, Long playtime, Long afktime) {
getUsersTable().insertOrUpdate(uuid.toString(), serverId, playtime, afktime);
userPlaytimes
.computeIfAbsent(uuid, k -> new HashMap<>())
.computeIfAbsent(serverId, k -> new HashMap<>())
userPlaytimes.computeIfAbsent(uuid, k -> new HashMap<>()).computeIfAbsent(serverId, k -> new HashMap<>())
.put("playtime", playtime);
userPlaytimes.get(uuid).get(serverId).put("afktime", afktime);
}
public boolean hasTimeForServer(UUID uuid, String server) {
if (!userPlaytimes.containsKey(uuid)) {
return retrievePlaytime(uuid);
}
return (userPlaytimes.containsKey(uuid) && userPlaytimes.get(uuid).containsKey(server));
}
public boolean hasTimeForServer(UUID uuid) {
return (hasTimeForServer(uuid, serverId));
}
public Map<String, Long> getTimeForServer(UUID uuid, String server) {
return userPlaytimes.get(uuid).get(server);
}
public Map<String, Long> getTimeForServer(UUID uuid) {
return getTimeForServer(uuid, serverId);
}
public Long getTotalRawtime(UUID uuid) {
Long rawtime = 0L;
Map<String, Map<String, Long>> userTimeData = userPlaytimes.get(uuid);
if (userTimeData != null) {
for (Map.Entry<String, Map<String, Long>> entry : userTimeData.entrySet()) {
String server = entry.getKey();
Map<String, Long> serverData = entry.getValue();
if (!server.equals(serverId)) {
Long individualRawtime = serverData.getOrDefault("playtime", 0L);
rawtime += individualRawtime;
}
}
}
StatManager stats = StatManager.getInstance();
Long currentServerRawtime = stats.getPlayerStat(uuid, StatisticType.PLAYTIME) / 20;
rawtime += currentServerRawtime;
return rawtime;
}
public Long getTotalAfktime(UUID uuid) {
Long afktime = 0L;
Map<String, Map<String, Long>> userTimeData = userPlaytimes.get(uuid);
if (userTimeData != null) {
for (Map.Entry<String, Map<String, Long>> entry : userTimeData.entrySet()) {
String server = entry.getKey();
Map<String, Long> serverData = entry.getValue();
if (!server.equals(serverId)) {
Long individualAfktime = serverData.getOrDefault("afktime", 0L);
afktime += individualAfktime;
}
}
}
long currentServerAfkTime = AFKManager.getInstance().getAFKTime(uuid);
afktime += currentServerAfkTime;
return afktime;
}
// Calculate the total playtime after subtracting total afktime
public Long getTotalPlaytime(UUID uuid) {
Long totalPlaytime = 0L;
Long totalAfktime = 0L;
Map<String, Map<String, Long>> userTimeData = userPlaytimes.get(uuid);
if (userTimeData != null) {
for (Map.Entry<String, Map<String, Long>> entry : userTimeData.entrySet()) {
String server = entry.getKey();
Map<String, Long> serverData = entry.getValue();
if (!server.equals(serverId)) {
totalPlaytime += serverData.getOrDefault("playtime", 0L);
totalAfktime += serverData.getOrDefault("afktime", 0L);
}
}
}
StatManager stats = StatManager.getInstance();
@@ -188,17 +259,21 @@ public class DatabaseManager {
totalAfktime += afkTime;
return totalPlaytime - totalAfktime;
}
public void purgeOldPlaytimeData() {
Bukkit.getLogger().info("[PlayTimes] Initiating purge of outdated playtime data...");
int months = DataManager.getInstance().getDBConfig().getInt("purge-database.months", 12);
Bukkit.getLogger()
.info(String.format(
"[PlayTimes] Purging playtime data for server ID '%s' that is older than %d months.",
serverId, months));
"[PlayTimes] Purging playtime data for server ID '%s' that is older than %d months.", serverId,
months));
this.usersTable.purgeOldPlaytimes(serverId, months);
}
}
@@ -18,36 +18,45 @@ public class UsersTable {
private final DataSource dataSource;
public UsersTable(DataSource dataSource) {
this.dataSource = dataSource;
}
public void createTable() {
String createTableSql = String.format(
"CREATE TABLE IF NOT EXISTS `%s` (" + "`uniqueId` VARCHAR(36) NOT NULL,"
+ "`serverId` VARCHAR(255) NOT NULL,"
+ "`playtime` BIGINT NOT NULL DEFAULT 0,"
+ "`afktime` BIGINT NOT NULL DEFAULT 0,"
+ "`lastUpdated` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,"
+ "PRIMARY KEY (`uniqueId`, `serverId`))",
TABLE_NAME);
String createTableSql = String.format("CREATE TABLE IF NOT EXISTS `%s` (" + "`uniqueId` VARCHAR(36) NOT NULL,"
+ "`serverId` VARCHAR(255) NOT NULL," + "`playtime` BIGINT NOT NULL DEFAULT 0,"
+ "`afktime` BIGINT NOT NULL DEFAULT 0,"
+ "`lastUpdated` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,"
+ "PRIMARY KEY (`uniqueId`, `serverId`))", TABLE_NAME);
try (Connection conn = dataSource.getConnection();
PreparedStatement preparedStatement = conn.prepareStatement(createTableSql)) {
PreparedStatement preparedStatement = conn.prepareStatement(createTableSql))
{
preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
public void insertOrUpdate(String uuid, String serverId, long playtime, long afktime) {
Async.run(() -> {
String query = String.format(
"INSERT INTO `%s` (`uniqueId`, `serverId`, `playtime`, `afktime`) VALUES (?, ?, ?, ?) "
+ "ON DUPLICATE KEY UPDATE `playtime` = ?, `afktime` = ?",
TABLE_NAME);
String query = String
.format("INSERT INTO `%s` (`uniqueId`, `serverId`, `playtime`, `afktime`) VALUES (?, ?, ?, ?) "
+ "ON DUPLICATE KEY UPDATE `playtime` = ?, `afktime` = ?", TABLE_NAME);
try (Connection conn = dataSource.getConnection();
PreparedStatement preparedStatement = conn.prepareStatement(query)) {
PreparedStatement preparedStatement = conn.prepareStatement(query))
{
preparedStatement.setString(1, uuid);
preparedStatement.setString(2, serverId);
preparedStatement.setLong(3, playtime);
@@ -56,22 +65,32 @@ public class UsersTable {
preparedStatement.setLong(6, afktime);
preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
});
}
public Map<String, Map<String, Long>> getPlaytimesByUuid(UUID uuid) {
Map<String, Map<String, Long>> timesMap = new HashMap<>();
try (Connection conn = dataSource.getConnection();
PreparedStatement preparedStatement =
conn.prepareStatement(String.format("SELECT * FROM `%s` WHERE `uniqueId` = ?", TABLE_NAME))) {
PreparedStatement preparedStatement = conn
.prepareStatement(String.format("SELECT * FROM `%s` WHERE `uniqueId` = ?", TABLE_NAME)))
{
preparedStatement.setString(1, uuid.toString());
try (ResultSet resultSet = preparedStatement.executeQuery()) {
while (resultSet.next()) {
String serverId = resultSet.getString("serverId");
long playtime = resultSet.getLong("playtime");
long afktime = resultSet.getLong("afktime");
@@ -81,64 +100,87 @@ public class UsersTable {
timeData.put("afktime", afktime);
timesMap.put(serverId, timeData);
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return timesMap;
}
public Map<String, Timestamp> getLastUpdatedTimesByUuid(UUID uuid) {
Map<String, Timestamp> lastUpdatedTimes = new HashMap<>();
String query = String.format("SELECT `serverId`, `lastUpdated` FROM `%s` WHERE `uniqueId` = ?", TABLE_NAME);
try (Connection conn = dataSource.getConnection();
PreparedStatement preparedStatement = conn.prepareStatement(query)) {
PreparedStatement preparedStatement = conn.prepareStatement(query))
{
preparedStatement.setString(1, uuid.toString());
try (ResultSet resultSet = preparedStatement.executeQuery()) {
while (resultSet.next()) {
String serverId = resultSet.getString("serverId");
Timestamp lastUpdated = resultSet.getTimestamp("lastUpdated");
lastUpdatedTimes.put(serverId, lastUpdated);
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return lastUpdatedTimes;
}
/**
* Deletes rows from the database where the last update was more than the specified number of months ago.
* Deletes rows from the database where the last update was more than the
* specified number of months ago.
*
* @param serverId The server ID to match rows.
* @param months The number of months to check for old data.
*/
public void purgeOldPlaytimes(String serverId, int months) {
Async.run(() -> {
String query = String.format(
"DELETE FROM `%s` WHERE `serverId` = ? AND `lastUpdated` < (NOW() - INTERVAL ? MONTH)", TABLE_NAME);
try (Connection conn = dataSource.getConnection();
PreparedStatement preparedStatement = conn.prepareStatement(query)) {
PreparedStatement preparedStatement = conn.prepareStatement(query))
{
preparedStatement.setString(1, serverId);
preparedStatement.setInt(2, months);
int deletedRows = preparedStatement.executeUpdate();
Bukkit.getLogger()
.info("[PlayTimes] Deleted " + deletedRows
+ " rows for serverId "
+ serverId
+ " older than "
+ months
+ " months.");
Bukkit.getLogger().info("[PlayTimes] Deleted " + deletedRows + " rows for serverId " + serverId
+ " older than " + months + " months.");
} catch (SQLException e) {
e.printStackTrace();
}
});
}
}
@@ -17,48 +17,59 @@ public class Join implements Listener {
@EventHandler
public void onJoin(PlayerJoinEvent event) {
UUID uuid = event.getPlayer().getUniqueId();
DataManager data = DataManager.getInstance();
// Database
if (data.hasDatabase()) {
DatabaseManager dbManager = DatabaseManager.getInstance();
dbManager.retrievePlaytime(uuid);
// hacky bug fix that will update data again if database query was too slow.
// this bug only arises when switching servers super fast!
Bukkit.getScheduler()
.runTaskLaterAsynchronously(
PlayTimes.getPlugin(PlayTimes.class),
() -> {
dbManager.retrievePlaytime(uuid);
},
20L * 30);
Bukkit.getScheduler().runTaskLaterAsynchronously(PlayTimes.getPlugin(PlayTimes.class), () -> {
dbManager.retrievePlaytime(uuid);
}, 20L * 30);
}
// Leaderboard
if (data.getData().contains("blocked." + event.getPlayer().getName().toLowerCase())) {
return;
}
ConfigurationSection leaderboardSection = data.getData().getConfigurationSection("leaderboard");
if (leaderboardSection == null) {
leaderboardSection = data.getData().createSection("leaderboard");
}
if (leaderboardSection.contains(uuid.toString())) {
return;
}
long time = StatManager.getInstance().getPlayerStat(uuid, StatisticType.PLAYTIME);
if (!data.getConfig().getBoolean("top-playtime.track-rawtime", false) && data.hasAfkEnabled()) {
time -= AFKManager.getInstance().getAFKTime(event.getPlayer().getUniqueId()) * 20;
}
leaderboardSection.set(uuid.toString(), time);
data.saveData();
}
}
@@ -15,42 +15,58 @@ public class Quit implements Listener {
@EventHandler
public void onQuit(PlayerQuitEvent event) {
UUID uuid = event.getPlayer().getUniqueId();
DataManager data = DataManager.getInstance();
// Database
if (data.hasDatabase()) {
CompletableFuture.runAsync(() -> {
DatabaseManager dbManager = DatabaseManager.getInstance();
dbManager.updatePlaytime(
uuid,
dbManager.updatePlaytime(uuid,
StatManager.getInstance().getPlayerStat(uuid, StatisticType.PLAYTIME) / 20,
AFKManager.getInstance().getAFKTime(uuid));
});
} else {
// Save AFK time in data.yml
CompletableFuture.runAsync(() -> {
data.getData().set("afktime." + uuid, AFKManager.getInstance().getAFKTime(uuid));
data.saveData();
});
}
// Leaderboard
String playerName = event.getPlayer().getName().toLowerCase();
if (data.getData().contains("blocked." + playerName)) {
return;
}
// Run leaderboard update
CompletableFuture.runAsync(() -> {
StatManager statManager = StatManager.getInstance();
long playtime = statManager.getPlayerStat(uuid, StatisticType.PLAYTIME);
if (!data.getConfig().getBoolean("top-playtime.track-rawtime", false) && data.hasAfkEnabled()) {
playtime -= AFKManager.getInstance().getAFKTime(uuid) * 20;
}
data.getData().set("leaderboard." + uuid, playtime);
data.saveData();
});
}
}
@@ -11,66 +11,91 @@ public class Leaderboard {
final String LEADERBOARD = "leaderboard";
/**
* Grabs the uuids from the data file, sorts them, then removes redundant uuids and updates the top 10
* Grabs the uuids from the data file, sorts them, then removes redundant uuids
* and updates the top 10
*
* @return listing of top 10 players
*/
public Map<String, Integer> getTopTen() {
Map<String, Integer> topTen = new LinkedHashMap<>();
DataManager data = DataManager.getInstance();
if (!data.getData().contains("leaderboard")) {
return topTen;
}
for (String key : data.getData().getConfigurationSection(LEADERBOARD).getKeys(false)) {
topTen.put(key, Integer.valueOf(data.getData().getString(LEADERBOARD + "." + key)));
}
List<Map.Entry<String, Integer>> list = new LinkedList<>(topTen.entrySet());
list.sort((o1, o2) -> o2.getValue() - o1.getValue());
if (list.size() > 20) {
List<Map.Entry<String, Integer>> delList = list.subList(20, list.size());
for (Map.Entry<String, Integer> key : delList) {
data.getData().set(LEADERBOARD + "." + key.getKey(), null);
}
data.saveData();
}
if (list.size() > 9) {
list = list.subList(0, 10);
}
topTen.clear();
for (Map.Entry<String, Integer> entry : list) {
topTen.put(entry.getKey(), entry.getValue());
}
updateTimes(topTen);
return topTen;
}
/**
* Updates the top ten times by querying the latest times from the StatManager and sorting the list.
* Updates the top ten times by querying the latest times from the StatManager
* and sorting the list.
*
* @param topTen the current leaderboard, with UUIDs and their corresponding time
* @param topTen the current leaderboard, with UUIDs and their corresponding
* time
*/
private void updateTimes(Map<String, Integer> topTen) {
StatManager statManager = StatManager.getInstance();
DataManager dataManager = DataManager.getInstance();
List<Map.Entry<String, Integer>> list = new ArrayList<>(topTen.entrySet());
for (Map.Entry<String, Integer> entry : list) {
String uuid = entry.getKey();
int latestTime = (int) statManager.getPlayerStat(UUID.fromString(uuid), StatisticType.PLAYTIME);
if (!dataManager.getConfig().getBoolean("top-playtime.track-rawtime", false)
&& dataManager.hasAfkEnabled()) {
&& dataManager.hasAfkEnabled())
{
latestTime -= AFKManager.getInstance().getAFKTime(UUID.fromString(uuid)) * 20;
}
topTen.put(uuid, latestTime);
}
list = new ArrayList<>(topTen.entrySet());
@@ -79,8 +104,12 @@ public class Leaderboard {
topTen.clear();
for (int i = 0; i < Math.min(list.size(), 10); i++) {
Map.Entry<String, Integer> entry = list.get(i);
topTen.put(entry.getKey(), entry.getValue());
}
}
}
@@ -30,14 +30,14 @@ public class Message {
private final TimeManager timeManager;
/**
* Constructor for Message.
* Initializes the message for the target player.
* Constructor for Message. Initializes the message for the target player.
*
* @param sender The command sender.
* @param sender The command sender.
* @param targetUUID The UUID of the offline player.
* @param targetName The name of the offline player.
* @param targetName The name of the offline player.
*/
public Message(CommandSender sender, UUID targetUUID, String targetName) {
this.sender = sender;
this.targetUUID = targetUUID;
this.targetName = targetName;
@@ -47,46 +47,56 @@ public class Message {
this.timeManager = TimeManager.getInstance();
this.message = buildMessage();
}
/**
* Builds the message to be sent to the sender about the target player.
* This involves fetching playtime statistics, formatting them,
* and applying any necessary replacements and PlaceholderAPI placeholders.
* Builds the message to be sent to the sender about the target player. This
* involves fetching playtime statistics, formatting them, and applying any
* necessary replacements and PlaceholderAPI placeholders.
*
* @return A list of formatted strings representing the message.
*/
private List<String> buildMessage() {
List<String> builtMessage = dataManager.getConfig().getStringList("playtime.message");
long rawTime = statManager.getPlayerStat(targetUUID, StatisticType.PLAYTIME);
long afkTime = AFKManager.getInstance().getAFKTime(targetUUID);
if (dataManager.hasDatabase()) {
DatabaseManager dbManager = DatabaseManager.getInstance();
dbManager.updatePlaytime(targetUUID, rawTime / 20, afkTime);
}
return processMessageWithReplacements(builtMessage, prepareReplacements(rawTime, afkTime));
}
/**
* Prepares a map of replacements to be used in the message.
*
* @param rawTime The playtime statistic to format and include in the replacements.
* @param afkTime The afktime statistic to format and include in the replacements.
* @param rawTime The playtime statistic to format and include in the
* replacements.
* @param afkTime The afktime statistic to format and include in the
* replacements.
* @return A map of placeholder keys and their replacement values.
*/
private Map<String, String> prepareReplacements(long rawTime, long afkTime) {
Map<String, String> replacements = new HashMap<>();
replacements.put("%time%", timeManager.buildFormat(rawTime / 20 - afkTime));
replacements.put("%playtime%", timeManager.buildFormat(rawTime / 20 - afkTime));
replacements.put("%rawtime%", timeManager.buildFormat(rawTime / 20));
replacements.put("%afktime%", timeManager.buildFormat(afkTime));
replacements.put("%player%", targetName);
replacements.put(
"%timesjoined%", Long.toString(statManager.getPlayerStat(targetUUID, StatisticType.TIMES_JOINED)));
replacements.put("%timesjoined%",
Long.toString(statManager.getPlayerStat(targetUUID, StatisticType.TIMES_JOINED)));
replacements.put("%joindate%", statManager.getJoinDate(targetUUID));
if (dataManager.hasDatabase()) {
DatabaseManager dbManager = DatabaseManager.getInstance();
long globalPlaytime = dbManager.getTotalPlaytime(targetUUID);
@@ -96,9 +106,11 @@ public class Message {
replacements.put("%global_playtime%", timeManager.buildFormat(globalPlaytime));
replacements.put("%global_rawtime%", timeManager.buildFormat(globalRawtime));
replacements.put("%global_afktime%", timeManager.buildFormat(globalAfktime));
}
return replacements;
}
/**
@@ -109,58 +121,82 @@ public class Message {
* @return A list of processed messages.
*/
private List<String> processMessageWithReplacements(List<String> message, Map<String, String> replacements) {
List<String> newMessage = new ArrayList<>();
boolean hasDatabase = dataManager.hasDatabase();
DatabaseManager dbManager = hasDatabase ? DatabaseManager.getInstance() : null;
Pattern pattern = Pattern.compile("%(rawtime|afktime|playtime)_(\\w+)%");
for (String msg : message) {
StringBuffer sb = new StringBuffer();
if (hasDatabase && dbManager != null) {
Matcher matcher = pattern.matcher(msg);
while (matcher.find()) {
String placeholderType = matcher.group(1);
String serverId = matcher.group(2);
Long timeValue = 0L;
if (dbManager.hasTimeForServer(targetUUID, serverId)) {
Map<String, Long> timeForServer = dbManager.getTimeForServer(targetUUID, serverId);
timeValue = timeForServer.getOrDefault(
placeholderType.equals("rawtime") ? "playtime" : placeholderType, 0L);
timeValue = timeForServer
.getOrDefault(placeholderType.equals("rawtime") ? "playtime" : placeholderType, 0L);
if (placeholderType.equals("playtime")) {
timeValue -= timeForServer.getOrDefault("afktime", 0L);
}
}
matcher.appendReplacement(sb, timeManager.buildFormat(timeValue));
}
matcher.appendTail(sb);
msg = sb.toString();
}
for (Map.Entry<String, String> entry : replacements.entrySet()) {
msg = msg.replace(entry.getKey(), entry.getValue() != null ? entry.getValue() : entry.getKey());
}
newMessage.add(msg);
}
return newMessage;
}
/**
* Sends the formatted message to the sender.
* This method determines the appropriate method to send the message
* (e.g., standard chat message or JSON formatted tellraw command).
* Sends the formatted message to the sender. This method determines the
* appropriate method to send the message (e.g., standard chat message or JSON
* formatted tellraw command).
*/
public void sendMessageToTarget() {
for (String msg : message) {
TextComponent formattedMsg = ChatUtil.format(msg);
if (formattedMsg.content().contains("{\"text\":")) {
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), "tellraw " + sender.getName() + " " + formattedMsg);
} else {
sender.sendMessage(formattedMsg);
}
}
}
}
@@ -9,28 +9,47 @@ public class ServerManager {
private static final ServerManager instance = new ServerManager();
public static ServerManager getInstance() {
return instance;
}
@Nullable
public UUID getUUID(String name) {
if (Bukkit.getPlayer(name) != null) {
return Bukkit.getPlayer(name).getUniqueId();
} else if (Bukkit.getOfflinePlayer(name) != null) {
return Bukkit.getOfflinePlayer(name).getUniqueId();
} else {
return null;
}
}
@Nullable
public String getName(UUID uuid) {
if (Bukkit.getPlayer(uuid) != null) {
return Bukkit.getPlayer(uuid).getName();
} else if (Bukkit.getOfflinePlayer(uuid) != null) {
return Bukkit.getOfflinePlayer(uuid).getName();
} else {
return null;
}
}
}
@@ -4,9 +4,11 @@ import java.io.IOException;
import java.util.UUID;
public interface ServerStatus {
public UUID getUUID(String name);
public boolean isOnline();
public String getName(UUID uuid) throws IOException;
}
@@ -15,51 +15,72 @@ public class LegacyStats implements Stats {
@Override
public long getPlayerStatistic(UUID uuid, StatisticType type) {
File playerStatistics = new File(worldFolder, uuid + ".json");
if (playerStatistics.exists()) {
try {
JsonObject jsonObject = new Gson().fromJson(new FileReader(playerStatistics), JsonObject.class);
switch (type) {
case PLAYTIME:
return jsonObject.get("stat.playOneMinute").getAsLong();
case TIMES_JOINED:
return jsonObject.get("stat.leaveGame").getAsLong();
}
} catch (Exception e) {
// e.printStackTrace();
}
}
return 0;
}
@Override
public long getOnlineStatistic(Player player, StatisticType type) {
return getPlayerStatistic(player.getUniqueId(), type);
}
@Override
public boolean hasJoinedBefore(UUID uuid) {
File playerStatistics = new File(worldFolder, uuid + ".json");
return playerStatistics.exists();
}
@Override
public String getJoinDate(UUID uuid) {
Player player = Bukkit.getPlayer(uuid);
SimpleDateFormat simpleDateFormat =
new SimpleDateFormat(DataManager.getInstance().getConfig().getString("date-format"));
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(
DataManager.getInstance().getConfig().getString("date-format"));
Calendar calendar = Calendar.getInstance();
if (player == null) {
calendar.setTimeInMillis(Bukkit.getOfflinePlayer(uuid).getFirstPlayed());
return simpleDateFormat.format(calendar.getTime());
} else if (player.hasPlayedBefore()) {
calendar.setTimeInMillis(player.getFirstPlayed());
return simpleDateFormat.format(calendar.getTime());
}
return "Never Joined";
}
}
@@ -16,63 +16,87 @@ public class RisenStats implements Stats {
@Override
public long getPlayerStatistic(UUID uuid, StatisticType type) {
if (Bukkit.getPlayer(uuid) != null) return getOnlineStatistic(Bukkit.getPlayer(uuid), type);
if (Bukkit.getPlayer(uuid) != null)
return getOnlineStatistic(Bukkit.getPlayer(uuid), type);
File playerStatistics = new File(worldFolder, uuid + ".json");
if (playerStatistics.exists()) {
try {
JsonObject jsonObject = new Gson().fromJson(new FileReader(playerStatistics), JsonObject.class);
JsonObject pilot = (JsonObject) jsonObject.get("stats");
JsonObject passenger = (JsonObject) pilot.get("minecraft:custom");
switch (type) {
case PLAYTIME:
if (passenger.get("minecraft:play_time") == null)
return passenger.get("minecraft:play_one_minute").getAsLong();
return passenger.get("minecraft:play_time").getAsLong();
case TIMES_JOINED:
return passenger.get("minecraft:leave_game").getAsLong();
}
} catch (Exception e) {
// e.printStackTrace();
}
}
return 0;
}
@Override
public long getOnlineStatistic(Player player, StatisticType type) {
switch (type) {
case PLAYTIME:
return player.getStatistic(Statistic.PLAY_ONE_MINUTE);
case TIMES_JOINED:
return player.getStatistic(Statistic.LEAVE_GAME) + 1;
default:
return 0;
}
}
@Override
public boolean hasJoinedBefore(UUID uuid) {
File playerStatistics = new File(worldFolder, uuid + ".json");
return playerStatistics.exists();
}
@Override
public String getJoinDate(UUID uuid) {
Player player = Bukkit.getPlayer(uuid);
SimpleDateFormat simpleDateFormat =
new SimpleDateFormat(DataManager.getInstance().getConfig().getString("date-format"));
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(
DataManager.getInstance().getConfig().getString("date-format"));
Calendar calendar = Calendar.getInstance();
if (player == null) {
calendar.setTimeInMillis(Bukkit.getOfflinePlayer(uuid).getFirstPlayed());
return simpleDateFormat.format(calendar.getTime());
} else if (player.hasPlayedBefore()) {
calendar.setTimeInMillis(player.getFirstPlayed());
return simpleDateFormat.format(calendar.getTime());
}
return "Never Joined";
}
}
@@ -16,61 +16,85 @@ public class RisingStats implements Stats {
@Override
public long getPlayerStatistic(UUID uuid, StatisticType type) {
if (Bukkit.getPlayer(uuid) != null) return getOnlineStatistic(Bukkit.getPlayer(uuid), type);
if (Bukkit.getPlayer(uuid) != null)
return getOnlineStatistic(Bukkit.getPlayer(uuid), type);
File playerStatistics = new File(worldFolder, uuid + ".json");
if (playerStatistics.exists()) {
try {
JsonObject jsonObject = new Gson().fromJson(new FileReader(playerStatistics), JsonObject.class);
JsonObject pilot = (JsonObject) jsonObject.get("stats");
JsonObject passenger = (JsonObject) pilot.get("minecraft:custom");
switch (type) {
case PLAYTIME:
return passenger.get("minecraft:play_one_minute").getAsLong();
case TIMES_JOINED:
return passenger.get("minecraft:leave_game").getAsLong();
}
} catch (Exception e) {
// e.printStackTrace();
}
}
return 0;
}
@Override
public long getOnlineStatistic(Player player, StatisticType type) {
switch (type) {
case PLAYTIME:
return player.getStatistic(Statistic.PLAY_ONE_MINUTE);
case TIMES_JOINED:
return player.getStatistic(Statistic.LEAVE_GAME) + 1;
default:
return 0;
}
}
@Override
public boolean hasJoinedBefore(UUID uuid) {
File playerStatistics = new File(worldFolder, uuid + ".json");
return playerStatistics.exists();
}
@Override
public String getJoinDate(UUID uuid) {
Player player = Bukkit.getPlayer(uuid);
SimpleDateFormat simpleDateFormat =
new SimpleDateFormat(DataManager.getInstance().getConfig().getString("date-format"));
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(
DataManager.getInstance().getConfig().getString("date-format"));
Calendar calendar = Calendar.getInstance();
if (player == null) {
calendar.setTimeInMillis(Bukkit.getOfflinePlayer(uuid).getFirstPlayed());
return simpleDateFormat.format(calendar.getTime());
} else if (player.hasPlayedBefore()) {
calendar.setTimeInMillis(player.getFirstPlayed());
return simpleDateFormat.format(calendar.getTime());
}
return "Never Joined";
}
}
@@ -11,7 +11,9 @@ public class StatManager {
private static final StatManager instance = new StatManager();
public static StatManager getInstance() {
return instance;
}
private Stats stats;
@@ -20,45 +22,68 @@ public class StatManager {
public String name;
public void registerStatistics() {
if (ServerUtils.isRisenVersion()) {
stats = new RisenStats();
name = "Risen";
} else if (ServerUtils.isNewerVersion()) {
stats = new RisingStats();
name = "Rising";
} else {
stats = new LegacyStats();
setLegacy();
name = "Legacy";
}
}
public Stats getStats() {
return stats;
}
public long getPlayerStat(UUID uuid, StatisticType type) {
return getStats().getPlayerStatistic(uuid, type);
}
public boolean hasJoinedBefore(UUID uuid) {
return getStats().hasJoinedBefore(uuid);
}
public String getJoinDate(UUID uuid) {
return getStats().getJoinDate(uuid);
}
private void setLegacy() {
legacy = true;
}
public boolean isLegacy() {
return legacy;
}
public String getUptime() {
return TimeManager.getInstance().buildFormat((int) TimeUnit.MILLISECONDS.toSeconds(
ManagementFactory.getRuntimeMXBean().getUptime()));
return TimeManager.getInstance()
.buildFormat((int) TimeUnit.MILLISECONDS.toSeconds(ManagementFactory.getRuntimeMXBean().getUptime()));
}
}
@@ -1,6 +1,5 @@
package me.codedred.playtimes.statistics;
public enum StatisticType {
PLAYTIME,
TIMES_JOINED,
PLAYTIME, TIMES_JOINED,
}
@@ -6,6 +6,7 @@ import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
public interface Stats {
long getPlayerStatistic(UUID uuid, StatisticType type);
boolean hasJoinedBefore(UUID uuid);
@@ -15,4 +16,5 @@ public interface Stats {
long getOnlineStatistic(Player player, StatisticType type);
File worldFolder = new File(Bukkit.getServer().getWorlds().get(0).getWorldFolder(), "stats");
}
@@ -9,10 +9,13 @@ public class TimeConstants {
private static boolean rounded;
static {
reload();
}
public static void reload() {
FileConfiguration data = DataManager.getInstance().getConfig();
second = data.getString("playtime.name.second");
seconds = data.getString("playtime.name.seconds");
@@ -23,41 +26,61 @@ public class TimeConstants {
day = data.getString("playtime.name.day");
days = data.getString("playtime.name.days");
rounded = data.getBoolean("playtime.round-numbers");
}
public static String getSecond() {
return second;
}
public static String getSeconds() {
return seconds;
}
public static String getMinute() {
return minute;
}
public static String getMinutes() {
return minutes;
}
public static String getHour() {
return hour;
}
public static String getHours() {
return hours;
}
public static String getDay() {
return day;
}
public static String getDays() {
return days;
}
public static boolean getRounded() {
return rounded;
}
}
@@ -8,40 +8,59 @@ public class TimeManager {
private static final TimeManager instance = new TimeManager();
public static TimeManager getInstance() {
return instance;
}
private Timings timings;
public void registerTimings() {
DataManager data = DataManager.getInstance();
if (data.getConfig().getBoolean("playtime.only-hours")) {
timings = new OnlyHours();
return;
}
if (!data.getConfig().getBoolean("playtime.show-seconds")) {
if (!data.getConfig().getBoolean("playtime.show-days")) {
timings = new NoDaysNoSeconds();
return;
}
timings = new NoSeconds();
return;
}
if (!data.getConfig().getBoolean("playtime.show-days")) {
timings = new NoDays();
return;
}
timings = new NativeFormat();
}
private Timings getTimings() {
return timings;
}
public String buildFormat(long time) {
return getTimings().buildFormat(time);
}
}
@@ -1,5 +1,7 @@
package me.codedred.playtimes.time;
public interface Timings {
String buildFormat(long time);
}
@@ -7,55 +7,80 @@ public class NativeFormat implements Timings {
@Override
public String buildFormat(long time) {
if (time < 60) return formatSeconds(time);
if (time < 60)
return formatSeconds(time);
int minutes = (int) (time / 60);
int secondsLeft = (int) (time % 60);
// Time less than 1 hour
if (minutes < 60) return formatMinutes(minutes, secondsLeft);
if (minutes < 60)
return formatMinutes(minutes, secondsLeft);
// Time less than 1 Day
if (minutes < 1440) {
int hours = minutes / 60;
int minutesLeft = minutes % 60;
return formatHours(hours, minutesLeft, secondsLeft);
}
// Time greater than 1 day
int days = minutes / 1440;
int minutesLeft = minutes % 1440;
return formatDays(days, minutesLeft, secondsLeft);
}
private String formatSeconds(long seconds) {
return (seconds + (seconds == 1 ? TimeConstants.getSeconds() : TimeConstants.getSecond()));
}
private String formatMinutes(int minutes, int secondsLeft) {
String format = minutes + (minutes == 1 ? TimeConstants.getMinute() : TimeConstants.getMinutes());
if (secondsLeft > 0) format += formatSeconds(secondsLeft);
if (secondsLeft > 0)
format += formatSeconds(secondsLeft);
return format;
}
private String formatHours(int hours, int minutesLeft, int secondsLeft) {
String format = hours + (hours == 1 ? TimeConstants.getHour() : TimeConstants.getHours());
if (minutesLeft >= 1) format += formatMinutes(minutesLeft, secondsLeft);
else if (secondsLeft > 0) format += formatSeconds(secondsLeft);
if (minutesLeft >= 1)
format += formatMinutes(minutesLeft, secondsLeft);
else if (secondsLeft > 0)
format += formatSeconds(secondsLeft);
return format;
}
private String formatDays(int days, int minutesLeft, int secondsLeft) {
String format = days + (days == 1 ? TimeConstants.getDay() : TimeConstants.getDays());
if (minutesLeft >= 60) {
int hours = minutesLeft / 60;
int minutesAfterHours = minutesLeft % 60;
format += formatHours(hours, minutesAfterHours, secondsLeft);
} else if (minutesLeft >= 1) {
format += formatMinutes(minutesLeft, secondsLeft);
} else if (secondsLeft > 0) {
format += formatSeconds(secondsLeft);
}
return format;
}
}
@@ -7,35 +7,49 @@ public class NoDays implements Timings {
@Override
public String buildFormat(long time) {
if (time < 60) return formatSeconds(time);
if (time < 60)
return formatSeconds(time);
int minutes = (int) (time / 60);
int secondsLeft = (int) (time % 60);
// Time less than 1 hour
if (minutes < 60) return formatMinutes(minutes, secondsLeft);
if (minutes < 60)
return formatMinutes(minutes, secondsLeft);
// Greater than 1 hour, only in hours
int hours = minutes / 60;
int minutesLeft = minutes % 60;
return formatHours(hours, minutesLeft, secondsLeft);
}
private String formatSeconds(long seconds) {
return (seconds + (seconds == 1 ? TimeConstants.getSeconds() : TimeConstants.getSecond()));
}
private String formatMinutes(int minutes, int secondsLeft) {
String format = minutes + (minutes == 1 ? TimeConstants.getMinute() : TimeConstants.getMinutes());
if (secondsLeft > 0) format += formatSeconds(secondsLeft);
if (secondsLeft > 0)
format += formatSeconds(secondsLeft);
return format;
}
private String formatHours(int hours, int minutesLeft, int secondsLeft) {
String format = hours + (hours == 1 ? TimeConstants.getHour() : TimeConstants.getHours());
if (minutesLeft >= 1) format += formatMinutes(minutesLeft, secondsLeft);
else if (secondsLeft > 0) format += formatSeconds(secondsLeft);
if (minutesLeft >= 1)
format += formatMinutes(minutesLeft, secondsLeft);
else if (secondsLeft > 0)
format += formatSeconds(secondsLeft);
return format;
}
}
@@ -7,12 +7,15 @@ public class NoDaysNoSeconds implements Timings {
@Override
public String buildFormat(long time) {
if (time < 60) return (time + (time == 1 ? TimeConstants.getSeconds() : TimeConstants.getSecond()));
if (time < 60)
return (time + (time == 1 ? TimeConstants.getSeconds() : TimeConstants.getSecond()));
int minutes = (int) (time / 60);
// Time less than 1 hour
if (minutes < 60) return (minutes + (minutes == 1 ? TimeConstants.getMinute() : TimeConstants.getMinutes()));
if (minutes < 60)
return (minutes + (minutes == 1 ? TimeConstants.getMinute() : TimeConstants.getMinutes()));
String format;
@@ -21,8 +24,11 @@ public class NoDaysNoSeconds implements Timings {
int inMins = 60 * hours;
int left = minutes - inMins;
if (left >= 1) format = format + left + (left == 1 ? TimeConstants.getMinute() : TimeConstants.getMinutes());
if (left >= 1)
format = format + left + (left == 1 ? TimeConstants.getMinute() : TimeConstants.getMinutes());
return format;
}
}
@@ -7,49 +7,70 @@ public class NoSeconds implements Timings {
@Override
public String buildFormat(long time) {
if (time < 60) return formatSeconds(time);
if (time < 60)
return formatSeconds(time);
int minutes = (int) (time / 60);
// Time less than 1 hour
if (minutes < 60) return formatMinutes(minutes);
if (minutes < 60)
return formatMinutes(minutes);
// Time less than 1 Day
if (minutes < 1440) {
int hours = minutes / 60;
int minutesLeft = minutes % 60;
return formatHours(hours, minutesLeft);
}
// Time greater than 1 day
int days = minutes / 1440;
int minutesLeft = minutes % 1440;
return formatDays(days, minutesLeft);
}
private String formatSeconds(long seconds) {
return (seconds + (seconds == 1 ? TimeConstants.getSeconds() : TimeConstants.getSecond()));
}
private String formatMinutes(int minutes) {
return (minutes + (minutes == 1 ? TimeConstants.getMinute() : TimeConstants.getMinutes()));
}
private String formatHours(int hours, int minutesLeft) {
String format = hours + (hours == 1 ? TimeConstants.getHour() : TimeConstants.getHours());
if (minutesLeft >= 1) format += formatMinutes(minutesLeft);
if (minutesLeft >= 1)
format += formatMinutes(minutesLeft);
return format;
}
private String formatDays(int days, int minutesLeft) {
String format = days + (days == 1 ? TimeConstants.getDay() : TimeConstants.getDays());
if (minutesLeft >= 60) {
int hours = minutesLeft / 60;
int minutesAfterHours = minutesLeft % 60;
format += formatHours(hours, minutesAfterHours);
} else if (minutesLeft >= 1) {
format += formatMinutes(minutesLeft);
}
return format;
}
}
@@ -7,15 +7,20 @@ public class OnlyHours implements Timings {
@Override
public String buildFormat(long time) {
boolean round = TimeConstants.getRounded();
double hours = time / 3600.0;
if (round) {
int roundedHours = (int) Math.round(hours);
return roundedHours + TimeConstants.getHours();
}
hours = (Math.round(hours * 100d)) / 100d;
return hours + TimeConstants.getHours();
}
}
@@ -8,18 +8,25 @@ import lombok.Getter;
public class Async {
@Getter
private static final ForkJoinPool worker =
new ForkJoinPool(8, ForkJoinPool.defaultForkJoinWorkerThreadFactory, (t, e) -> e.printStackTrace(), false);
private static final ForkJoinPool worker = new ForkJoinPool(8, ForkJoinPool.defaultForkJoinWorkerThreadFactory,
(t, e) -> e.printStackTrace(), false);
public static CompletableFuture<Void> run(Runnable runnable) {
return CompletableFuture.runAsync(
() -> {
try {
runnable.run();
} catch (Exception exception) {
throw new CompletionException(exception);
}
},
worker);
return CompletableFuture.runAsync(() -> {
try {
runnable.run();
} catch (Exception exception) {
throw new CompletionException(exception);
}
}, worker);
}
}
@@ -10,14 +10,13 @@ public class ChatUtil {
private static final DataManager DATA_MANAGER = DataManager.getInstance();
public enum ChatTypes {
NO_PERMISSION,
PLAYER_NOT_FOUND,
PLAYER_NEVER_PLAYED,
NO_PERMISSION, PLAYER_NOT_FOUND, PLAYER_NEVER_PLAYED,
}
public static void errno(CommandSender sender, ChatTypes type) {
switch (type) {
case NO_PERMISSION:
sender.sendMessage(format(DATA_MANAGER.getConfig().getString("messages.noPermission")));
break;
@@ -28,16 +27,21 @@ public class ChatUtil {
sender.sendMessage(
formatWithPrefix(DATA_MANAGER.getConfig().getString("messages.player-never-joined")));
break;
}
}
public static TextComponent format(String msg) {
return UtilitiesOG.trueogColorize(msg);
}
public static TextComponent formatWithPrefix(String msg) {
return UtilitiesOG.trueogColorize(DATA_MANAGER.getConfig().getString("prefix") + msg);
}
}
@@ -6,28 +6,43 @@ import java.util.UUID;
public class CoolDownUtil {
private CoolDownUtil() {
throw new IllegalStateException("Utility Class");
}
private static final HashMap<UUID, Long> cooldowns = new HashMap<>();
public static void remove(UUID uuid) {
cooldowns.remove(uuid);
}
public static void add(UUID uuid, long time) {
cooldowns.put(uuid, time);
}
public static int left(UUID uuid) {
return (int) (cooldowns.get(uuid) / 1000 - (System.currentTimeMillis() / 1000));
}
public static boolean contains(UUID uuid) {
if (cooldowns.containsKey(uuid)) {
if (cooldowns.get(uuid) > System.currentTimeMillis()) return true;
if (cooldowns.get(uuid) > System.currentTimeMillis())
return true;
remove(uuid);
}
return false;
}
}
@@ -7,6 +7,7 @@ public class HexUtil {
private HexUtil() {
throw new IllegalStateException("Utility Class");
}
public static String hex(String message) {
@@ -24,18 +25,23 @@ public class HexUtil {
i += 8;
continue;
}
}
builder.append(message.charAt(i));
}
return TextUtils.processColorCodes(builder.toString());
}
private static boolean isValidHexCode(String hexCode) {
return hexCode.matches("^[a-fA-F0-9]{6}$");
}
private static String toLegacyHex(String hexCode) {
@@ -45,8 +51,11 @@ public class HexUtil {
for (char c : hexCode.toCharArray()) {
legacy.append('&').append(c);
}
return legacy.toString();
}
}
@@ -10,20 +10,31 @@ public class ServerUtils {
private static Boolean isNewerVersion = null;
private ServerUtils() {
throw new IllegalStateException("Utility Class");
}
public static boolean isNewerVersion() {
if (isNewerVersion == null) {
try {
Class<?> classMaterial = Material.class;
Method method = classMaterial.getDeclaredMethod("matchMaterial", String.class, boolean.class);
isNewerVersion = (method != null);
} catch (ReflectiveOperationException ex) {
isNewerVersion = false;
}
}
return isNewerVersion;
}
/**
@@ -32,35 +43,48 @@ public class ServerUtils {
* @return true if so
*/
public static boolean isRisenVersion() {
String version = Bukkit.getServer().getVersion();
String mcVersion = null;
if (version.contains("(MC:")) {
int startIndex = version.indexOf("(MC:") + 5;
int endIndex = version.indexOf(")", startIndex);
mcVersion = version.substring(startIndex, endIndex).trim();
}
if (mcVersion == null) {
Bukkit.getLogger().warning("PlayTimes failed to extract Minecraft version: " + version);
return false;
}
String[] versionParts = mcVersion.split("\\.");
try {
int minorVersion = versionParts.length >= 2 ? Integer.parseInt(versionParts[1]) : 0;
return minorVersion >= 17;
} catch (NumberFormatException e) {
Bukkit.getLogger().warning("PlayTimes failed to parse Minecraft version: " + mcVersion);
return false;
}
}
public static boolean hasPAPI() {
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null)
return DataManager.getInstance().getConfig().getBoolean("use-papi-placeholders");
return false;
}
}