Skip to content

Master#2

Open
twisti-dev wants to merge 23 commits intoversion/1.21.11from
master
Open

Master#2
twisti-dev wants to merge 23 commits intoversion/1.21.11from
master

Conversation

@twisti-dev
Copy link

No description provided.

Copilot AI review requested due to automatic review settings February 18, 2026 14:44
@TheBjoRedCraft TheBjoRedCraft requested review from TheBjoRedCraft and Copilot and removed request for TheBjoRedCraft and Copilot February 18, 2026 14:46
Added the GNU General Public License version 3 to the project.
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1d37a06d3e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +135 to +138
PlayersTable.upsert {
it[uuid] = playerUuid
it[name] = playerName
it[updatedAt] = CurrentTimestamp

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Set dataVersion in custom-stat player upsert

saveCustomStats inserts/updates players without assigning dataVersion, but PlayersTable declares dataversion as a required column with no default (PlayersTable.dataVersion). When a plugin writes custom stats for a player who is not already in players, the upsert path will try to insert a row missing dataversion, causing the write to fail instead of persisting the custom stats.

Useful? React with 👍 / 👎.


// Cancel shared scope to kill any in-flight async coroutines (quit/world-save)
// before performing the synchronous shutdown save
pluginScope.cancel("Plugin disabling")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid canceling delayed quit saves before shutdown flush

Canceling pluginScope at the start of shutdown can drop valid player saves: PlayerStatsListener schedules quit processing with a 1s delay, so a player disconnecting right before disable has an in-flight coroutine that gets canceled here, and that player is then absent from onlinePlayers for the synchronous shutdown save. In that timing window, the latest stats are never persisted.

Useful? React with 👍 / 👎.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR represents a complete architectural rewrite of the surf-stats plugin, migrating from a Java/Spring/Feign HTTP-based system to a Kotlin/Coroutines/R2DBC direct database implementation. The changes transform the plugin from a Bukkit implementation to a Paper-specific plugin with modern async processing.

Changes:

  • Complete migration from Java to Kotlin with coroutines for async operations
  • Replacement of Spring/Feign HTTP client architecture with direct R2DBC database access
  • New modular structure: surf-stats-api (interfaces) → surf-stats-core (implementation) → surf-stats-paper (Paper plugin)
  • Added comprehensive test coverage for core functionality
  • Removed old surf-stats-bukkit module, replaced with surf-stats-paper module

Reviewed changes

Copilot reviewed 78 out of 130 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
surf-stats-paper/src/main/resources/database.yml Database configuration with connection pooling settings
surf-stats-paper/src/main/resources/config.yml Server identification configuration
surf-stats-paper/src/main/kotlin/.../SurfStatsPlugin.kt Main plugin lifecycle with service initialization
surf-stats-paper/src/main/kotlin/.../listener/* Event listeners for player quit, world save, and shutdown
surf-stats-core/src/main/kotlin/.../service/StatsFileServiceImpl.kt JSON stats file parsing implementation
surf-stats-core/src/main/kotlin/.../database/* R2DBC database tables and persistence layer
surf-stats-core/src/test/kotlin/* Comprehensive unit tests for core functionality
surf-stats-api/src/main/kotlin/* Public API interfaces and data models
gradle/wrapper/gradle-wrapper.properties Gradle wrapper configuration
README.md Comprehensive documentation of architecture and usage
Files not reviewed (37)
  • .idea/.gitignore: Language not supported
  • .idea/compiler.xml: Language not supported
  • .idea/discord.xml: Language not supported
  • .idea/gradle.xml: Language not supported
  • .idea/inspectionProfiles/Project_Default.xml: Language not supported
  • .idea/intellij-javadocs-4.0.1.xml: Language not supported
  • .idea/jarRepositories.xml: Language not supported
  • .idea/jpa-buddy.xml: Language not supported
  • .idea/jpa.xml: Language not supported
  • .idea/jsLibraryMappings.xml: Language not supported
  • .idea/kotlinc.xml: Language not supported
  • .idea/material_theme_project_new.xml: Language not supported
  • .idea/misc.xml: Language not supported
  • .idea/modules.xml: Language not supported
  • .idea/modules/surf-stats-api/IdeaProjects.surf-stats.surf-stats-api.main.iml: Language not supported
  • .idea/modules/surf-stats-api/IdeaProjects.surf-stats.surf-stats-api.test.iml: Language not supported
  • .idea/modules/surf-stats-api/surf-stats-api.surf-stats.surf-stats-api.main.iml: Language not supported
  • .idea/modules/surf-stats-api/surf-stats-api.surf-stats.surf-stats-api.test.iml: Language not supported
  • .idea/modules/surf-stats-api/surf-stats.surf-stats-api.main.iml: Language not supported
  • .idea/modules/surf-stats-api/surf-stats.surf-stats-api.test.iml: Language not supported
  • .idea/modules/surf-stats-bukkit/IdeaProjects.surf-stats.surf-stats-bukkit.main.iml: Language not supported
  • .idea/modules/surf-stats-bukkit/IdeaProjects.surf-stats.surf-stats-bukkit.test.iml: Language not supported
  • .idea/modules/surf-stats-bukkit/surf-stats-bukkit.surf-stats.surf-stats-bukkit.main.iml: Language not supported
  • .idea/modules/surf-stats-bukkit/surf-stats-bukkit.surf-stats.surf-stats-bukkit.test.iml: Language not supported
  • .idea/modules/surf-stats-bukkit/surf-stats.surf-stats-bukkit.iml: Language not supported
  • .idea/modules/surf-stats-bukkit/surf-stats.surf-stats-bukkit.main.iml: Language not supported
  • .idea/modules/surf-stats-bukkit/surf-stats.surf-stats-bukkit.test.iml: Language not supported
  • .idea/modules/surf-stats-core/IdeaProjects.surf-stats.surf-stats-core.main.iml: Language not supported
  • .idea/modules/surf-stats-core/IdeaProjects.surf-stats.surf-stats-core.test.iml: Language not supported
  • .idea/modules/surf-stats-core/surf-stats-core.surf-stats.surf-stats-core.main.iml: Language not supported
  • .idea/modules/surf-stats-core/surf-stats-core.surf-stats.surf-stats-core.test.iml: Language not supported
  • .idea/modules/surf-stats-core/surf-stats.surf-stats-core.main.iml: Language not supported
  • .idea/modules/surf-stats-core/surf-stats.surf-stats-core.test.iml: Language not supported
  • .idea/prettier.xml: Language not supported
  • .idea/surf-stats.iml: Language not supported
  • .idea/uiDesigner.xml: Language not supported
  • .idea/vcs.xml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

// arrive in quick succession. We debounce by cancelling any pending job on each event,
// ensuring we only process stats once per save cycle. The 5s delay also gives Minecraft
// time to finish flushing all stats files to disk.
private var saveJob: Job? = null
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The saveJob field is accessed from multiple threads (event handler thread and coroutine context) without synchronization. While Job operations are thread-safe, consider using @volatile annotation or AtomicReference to make the intent explicit and ensure proper memory visibility across threads.

Copilot uses AI. Check for mistakes.
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
networkTimeout=10000
validateDistributionUrl=true
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-milestone-1-all.zip
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Gradle wrapper is configured to use a milestone (pre-release) version "9.5.0-milestone-1". Milestone versions are not stable releases and may contain bugs or breaking changes. Consider using a stable Gradle release version for production code to ensure reliability and compatibility.

Copilot uses AI. Check for mistakes.
Comment on lines +6 to +7
username: my_user
password: my_password
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded database credentials in a version-controlled configuration file pose a security risk. Consider using environment variables or a secure credential management system instead of committing actual credentials to the repository.

Copilot uses AI. Check for mistakes.
Comment on lines +81 to +91
runBlocking {
fileService.initialize(statsDirectory)
}

// Initialize database
saveResource("database.yml", false)
databaseApi = DatabaseApi.create(pluginPath = dataFolder.toPath())
val databaseService = StatsDatabaseService(serverName, serverLabel)
runBlocking {
databaseService.registerServer()
}
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The runBlocking calls in the onEnable lifecycle block the main server thread during plugin initialization. Consider using a launch with appropriate error handling instead, or document why blocking is necessary here. Blocking the main thread during server startup could cause performance issues.

Copilot uses AI. Check for mistakes.

@EventHandler(priority = EventPriority.MONITOR)
fun onPluginDisable(event: PluginDisableEvent) {
if (event.plugin.name != "surf-stats-paper") return
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The plugin name check uses a hardcoded string "surf-stats-paper" which could break if the plugin name changes. Consider using event.plugin == this@SurfStatsPlugin or storing the plugin reference to compare directly, making the code more robust to refactoring.

Copilot uses AI. Check for mistakes.
Comment on lines +2 to +8
surf-database = "1.3.0"
kotlinx-serialization = "1.10.0"
kotlinx-coroutines = "1.9.0"
junit = "5.11.3"

[libraries]
surf-data-api = { module = "dev.slne:surf-data-api", version.ref = "surf-data-api-version" }
surf-api = { module = "dev.slne.surf:surf-api-bukkit-api", version.ref = "surf-api-version" }
paper-api = { module = "io.papermc.paper:paper-api", version.ref = "paper-api-version" }
fast-util = { module = "it.unimi.dsi:fastutil", version.ref = "fast-util-version" }
maven-settings-plugin = { module = "net.linguica.gradle:maven-settings-plugin", version.ref = "maven-settings-plugin-version" }
shadow-plugin = { module = "com.github.johnrengelman:shadow", version.ref = "shadow-plugin-version" }

[plugins]
run-paper-plugin = { id = "xyz.jpenilla.run-paper", version = "2.2.2" } No newline at end of file
surf-database-r2dbc = { module = "dev.slne.surf:surf-database-r2dbc", version.ref = "surf-database" }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
surf-database = "1.3.0"
kotlinx-serialization = "1.10.0"
kotlinx-coroutines = "1.9.0"
junit = "5.11.3"
[libraries]
surf-data-api = { module = "dev.slne:surf-data-api", version.ref = "surf-data-api-version" }
surf-api = { module = "dev.slne.surf:surf-api-bukkit-api", version.ref = "surf-api-version" }
paper-api = { module = "io.papermc.paper:paper-api", version.ref = "paper-api-version" }
fast-util = { module = "it.unimi.dsi:fastutil", version.ref = "fast-util-version" }
maven-settings-plugin = { module = "net.linguica.gradle:maven-settings-plugin", version.ref = "maven-settings-plugin-version" }
shadow-plugin = { module = "com.github.johnrengelman:shadow", version.ref = "shadow-plugin-version" }
[plugins]
run-paper-plugin = { id = "xyz.jpenilla.run-paper", version = "2.2.2" }
\ No newline at end of file
surf-database-r2dbc = { module = "dev.slne.surf:surf-database-r2dbc", version.ref = "surf-database" }
kotlinx-serialization = "1.10.0"
kotlinx-coroutines = "1.9.0"
junit = "5.11.3"
[libraries]

Kannst du direkt über surfapi machen in dem Module wo du es brauchst
https://github.com/SLNE-Development/surf-chat/blob/238a6b7ffe5a561cb373cef57fc6906550154003/surf-chat-fallback/build.gradle.kts#L6

Comment on lines +9 to +11
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sollte alles in surf api drin sein

Suggested change
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }

Comment on lines +3 to +4
kotlinx-serialization = "1.10.0"
kotlinx-coroutines = "1.9.0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
kotlinx-serialization = "1.10.0"
kotlinx-coroutines = "1.9.0"

sollte in surf api drin sein

/**
* The server name used for stats attribution.
*/
val serverName: String
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hierfür kannst du surf core nutzen

https://docs.slne.dev/surf-core/server-management

import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.javatime.CurrentTimestamp
import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.javatime.timestamp

object PlayersTable : Table("players") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kannst einen AuditableLongIdTable nutzen, da ist updated und createdAt direkt bei

Comment on lines +1 to +18
logLevel: DEBUG
credentials:
host: localhost
port: 3306
database: my_database
username: my_user
password: my_password
pool:
sizing:
initialSize: 10
minIdle: 0
maxSize: 10
timeouts:
maxAcquireTimeMillis: 10000
maxCreateConnectionTimeMillis: 30000
maxValidationTimeMillis: -1
maxIdleTimeMillis: 60000
maxLifeTimeMillis: 1800000
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

surf database nutzen

Comment on lines +1 to +3
server:
name: "my-server"
label: "My Server"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

surf core nutzen, siehe oben


surfPaperPluginApi {
mainClass("dev.slne.surf.stats.paper.SurfStatsPlugin")
authors.add("SLNE Dev Team")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
authors.add("SLNE Dev Team")
authors.add("Jan")

}

surfPaperPluginApi {
mainClass("dev.slne.surf.stats.paper.SurfStatsPlugin")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
mainClass("dev.slne.surf.stats.paper.SurfStatsPlugin")
mainClass("dev.slne.surf.stats.paper.PaperMain")

siehe oben, direkt auch echten File und Klassennamen updaten

Comment on lines +17 to +19
tasks.processResources {
expand("version" to project.version)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

brauchen wir nicht

Co-author: red
Copilot AI review requested due to automatic review settings February 20, 2026 18:51
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

Copilot AI review requested due to automatic review settings February 21, 2026 17:44
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

Copilot AI review requested due to automatic review settings February 24, 2026 18:16
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review is ineligible. To be eligible to request a review, you need a paid Copilot license, or your organization must enable Copilot code review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants