Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# for the Dockerfile that is run on our CI/CD pipeline, see production.Dockerfile

# Build the project into an executable JAR
FROM gradle:jdk21 as build
FROM gradle:jdk25 as build
# Copy build files and source code
COPY . /work
WORKDIR /work
Expand All @@ -13,7 +13,7 @@ RUN --mount=target=/home/gradle/.gradle,type=cache \
/usr/bin/gradle --console=plain --info --stacktrace --no-daemon -x test --build-cache build

# Run the built JAR and expose port 25565
FROM eclipse-temurin:21-jre-alpine
FROM eclipse-temurin:25-jre-alpine
EXPOSE 25565
EXPOSE 50051
WORKDIR /server
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ available [here](https://wiki.minestom.net).
## Usage

Build with `./gradlew build` and run the JAR created at `build/libs/Server-x.x.x-all.jar`.
Requires Java 21 or higher.
Requires Java 25 or higher.

## Development

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ plugins {

tasks.withType<KotlinCompile> {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_21)
jvmTarget.set(JvmTarget.JVM_25)
}
}
6 changes: 3 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
plugins {
id("server.common-conventions")
id("com.gradleup.shadow") version "9.0.1"
kotlin("plugin.serialization") version "2.1.10"
id("com.gradleup.shadow") version "9.4.0"
kotlin("plugin.serialization") version "2.3.0"
id("net.kyori.blossom") version "2.1.0"
`maven-publish`
}
Expand Down Expand Up @@ -75,7 +75,7 @@ publishing {

kotlin {
jvmToolchain {
languageVersion.set(JavaLanguageVersion.of(21))
languageVersion.set(JavaLanguageVersion.of(25))
}
}

Expand Down
11 changes: 9 additions & 2 deletions common/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
plugins {
id("server.common-conventions")
kotlin("plugin.serialization") version "2.1.10"
kotlin("plugin.serialization") version "2.3.0"
`maven-publish`
}

Expand All @@ -24,6 +24,7 @@ dependencies {
implementation(libs.bundles.messaging)
implementation(libs.serialization.json)
implementation(libs.bundles.tinylog)
implementation(libs.fastutil)
}

publishing {
Expand All @@ -40,4 +41,10 @@ publishing {

tasks.getByName<Test>("test") {
useJUnitPlatform()
}
}

kotlin {
jvmToolchain {
languageVersion.set(JavaLanguageVersion.of(25))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import net.minestom.server.coordinate.Pos
import net.minestom.server.entity.Entity
import net.minestom.server.entity.GameMode
import net.minestom.server.entity.Player
import net.minestom.server.entity.metadata.PlayerMeta
import net.minestom.server.entity.metadata.avatar.PlayerMeta
import net.minestom.server.instance.Instance
import net.minestom.server.instance.block.Block
import net.minestom.server.network.player.GameProfile
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ class CustomDeathMessageModule : GameModule() {
if (playerName != null) {
Component.translatable("death.attack.player", BRAND_COLOR_PRIMARY_2, player.name, playerName)
} else {
Component.translatable("death.attack.mob", BRAND_COLOR_PRIMARY_2, player.name, Component.translatable(src.source.entityType.registry().translationKey()))
Component.translatable("death.attack.mob", BRAND_COLOR_PRIMARY_2, player.name, Component.translatable(src.source!!.entityType.registry()!!.translationKey()))
}
}
is EntityProjectileDamage -> {
val playerName = (src.shooter as? Player)?.name
if (playerName != null) {
Component.translatable("death.attack.arrow", BRAND_COLOR_PRIMARY_2, player.name, playerName)
} else if (src.shooter != null) {
Component.translatable("death.attack.arrow", BRAND_COLOR_PRIMARY_2, player.name, Component.translatable(src.shooter!!.entityType.registry().translationKey()))
Component.translatable("death.attack.arrow", BRAND_COLOR_PRIMARY_2, player.name, Component.translatable(src.shooter!!.entityType.registry()!!.translationKey()))
} else {
Component.translatable("death.attack.generic", BRAND_COLOR_PRIMARY_2, player.name)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ class ProjectileModule : GameModule() {
).filter { pos ->
// Check if the block should be destroyed based on the radius
val distance = pos.distanceSquared(centerX.toDouble(), centerY.toDouble(), centerZ.toDouble())
val resistance = instance.getBlock(pos).registry().explosionResistance()
val resistance = instance.getBlock(pos).registry()!!.explosionResistance()
val maxStrength = strength * 1.5 - resistance / 2.0
if (maxStrength <= 0 || Random.nextDouble(0.0, maxStrength) < distance)
return@filter false
Expand All @@ -359,7 +359,7 @@ class ProjectileModule : GameModule() {
parent.callEvent(event)

if (dropItems && !event.isCancelled) {
val material = block.registry().material()
val material = block.registry()!!.material()
if (material != null)
parent.getModule<ItemDropModule>().dropItem(ItemStack.of(material), instance, pos)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import net.minestom.server.MinecraftServer
import net.minestom.server.coordinate.Pos
import net.minestom.server.entity.*
import net.minestom.server.entity.damage.DamageType
import net.minestom.server.entity.metadata.PlayerMeta
import net.minestom.server.entity.metadata.avatar.PlayerMeta
import net.minestom.server.entity.metadata.display.AbstractDisplayMeta
import net.minestom.server.entity.metadata.display.TextDisplayMeta
import net.minestom.server.event.Event
Expand Down Expand Up @@ -144,7 +144,8 @@ class NPCModule : GameModule() {
GameMode.CREATIVE,
Component.text("[NPC] $randomName", NamedTextColor.DARK_GRAY, TextDecoration.ITALIC),
null,
0
0,
true
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class DoorsModule : GameModule() {
val shouldPlaySound = playEffect && (block.getProperty("open").equals("true")) != open

if (shouldPlaySound) {
val (openSound, closeSound) = (getSounds(block.registry().material() ?: return) ?: return)
val (openSound, closeSound) = (getSounds(block.registry()!!.material() ?: return) ?: return)
val soundEvent = if (open) openSound else closeSound

val audience = mutableListOf<Player>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ class FallDamageModule : GameModule() {

val blockPos = Pos(x.toDouble(), y.toDouble(), z.toDouble())
val blockCenter = blockPos.add(0.5, 0.5, 0.5)
val blockBoundingBox = player.instance.getBlock(blockPos).registry().collisionShape()
val blockBoundingBox = player.instance.getBlock(blockPos).registry()!!.collisionShape()

val collides = blockBoundingBox.intersectBox(player.position.sub(blockPos), expandedBoundingBox)
if (!collides) continue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class ItemDropModule(var dropBlocksOnBreak: Boolean = true, var dropAllOnDeath:
}
eventNode.addListener(PlayerBlockBreakEvent::class.java) { event ->
if (dropBlocksOnBreak && !event.isCancelled && !excludedBlocks.contains(event.block)) {
val itemStack = ItemStack.of(event.block.registry().material() ?: Material.AIR, 1)
val itemStack = ItemStack.of(event.block.registry()!!.material() ?: Material.AIR, 1)
val dropEvent = BlockItemDropEvent(event.instance, event.block, event.blockPosition, itemStack)
parent.callCancellable(dropEvent) {
dropItem(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.bluedragonmc.server.utils

import net.minestom.server.instance.block.Block

fun Block.isFullCube() = registry().collisionShape().run {
fun Block.isFullCube() = registry()!!.collisionShape().run {
val start = relativeStart().isZero
val end = relativeEnd().samePoint(1.0, 1.0, 1.0)
start && end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,29 +51,29 @@ fun Component.hoverEventTranslatable(key: String, color: TextColor): Component =
hoverEvent(Component.translatable(key, color))

fun Component.clickEvent(command: String): Component =
clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, command))
clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, ClickEvent.Payload.string(command)))

fun Component.clickEvent(action: ClickEvent.Action, value: String): Component {
if (action == ClickEvent.Action.COPY_TO_CLIPBOARD && hoverEvent() == null) {
return clickEvent(ClickEvent.clickEvent(action, value)).hoverEventTranslatable(
return clickEvent(ClickEvent.clickEvent(action, ClickEvent.Payload.string(value))).hoverEventTranslatable(
"command.click_to_copy",
ALT_COLOR_1
)
}
if (action == ClickEvent.Action.OPEN_URL && hoverEvent() == null) {
return clickEvent(ClickEvent.clickEvent(action, value)).hoverEvent(
return clickEvent(ClickEvent.clickEvent(action, ClickEvent.Payload.string(value))).hoverEvent(
Component.translatable(
"command.click_to_open_url",
ALT_COLOR_1,
Component.text(value, NamedTextColor.GRAY)
)
)
}
return clickEvent(ClickEvent.clickEvent(action, value))
return clickEvent(ClickEvent.clickEvent(action, ClickEvent.Payload.string(value)))
}

fun Material.displayName() = Component.translatable(registry().translationKey())
fun Material.displayName(color: TextColor) = Component.translatable(registry().translationKey(), color)
fun Material.displayName() = Component.translatable(registry()!!.translationKey())
fun Material.displayName(color: TextColor) = Component.translatable(registry()!!.translationKey(), color)

fun Component.noItalic() = decoration(TextDecoration.ITALIC, false)
fun Component.noBold() = decoration(TextDecoration.BOLD, false)
Expand Down
8 changes: 5 additions & 3 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
metadata.format.version = "1.1"

[versions]
kotlin = "2.1.10"
minestom = "2025.07.27-1.21.8"
kotlin = "2.3.0"
minestom = "2026.03.03-1.21.11"
jukebox = "a941945c86"
configurate = "4.2.0"
minimessage = "4.19.0"
Expand All @@ -12,14 +12,15 @@ okhttp = "4.12.0"
serialization = "1.8.0"
tinylog = "2.7.0"
atlas-projectiles = "2.1.2"
fastutil = "8.5.18"
# Auto-generated GRPC/Protobuf messaging code
rpc = "d40ac743b5"
# Messaging dependencies
grpc = "1.71.0"
grpc-kotlin-stub = "1.4.1"
protobuf-kotlin = "4.30.1"
# Testing dependencies
mockk = "1.13.11"
mockk = "1.14.9"
junit = "5.9.0"

[libraries]
Expand All @@ -31,6 +32,7 @@ configurate = { group = "org.spongepowered", name = "configurate-yaml", version.
configurate-extra-kotlin = { group = "org.spongepowered", name = "configurate-extra-kotlin", version.ref = "configurate" }
minimessage = { group = "net.kyori", name = "adventure-text-minimessage", version.ref = "minimessage" }
atlas-projectiles = { group = "ca.atlasengine", name = "atlas-projectiles", version.ref = "atlas-projectiles" }
fastutil = { group = "it.unimi.dsi", name = "fastutil", version.ref = "fastutil" }
kmongo = { group = "org.litote.kmongo", name = "kmongo-coroutine-serialization", version.ref = "kmongo" }
serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "serialization" }
caffeine = { group = "com.github.ben-manes.caffeine", name = "caffeine", version.ref = "caffeine" }
Expand Down
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
6 changes: 3 additions & 3 deletions gradlew

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions gradlew.bat

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion jitpack.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
jdk:
- openjdk21
- openjdk25
4 changes: 2 additions & 2 deletions production.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
# This Dockerfile runs on the CI/CD pipeline when the Server is being deployed.

# Build the project into an executable JAR
FROM docker.io/library/gradle:8.13-jdk21 as build
FROM docker.io/library/gradle:9.4-jdk25 as build
# Copy build files and source code
COPY . /work
WORKDIR /work
# Run gradle in the /work directory
RUN /usr/bin/gradle --console=plain --info --stacktrace --no-daemon build

# Run the built JAR and expose port 25565
FROM docker.io/library/eclipse-temurin:21-jre-alpine
FROM docker.io/library/eclipse-temurin:25-jre-alpine
EXPOSE 25565
EXPOSE 50051
WORKDIR /server
Expand Down
1 change: 0 additions & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,3 @@ pluginManagement {
}

include("common")

20 changes: 15 additions & 5 deletions src/main/kotlin/com/bluedragonmc/server/Server.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ package com.bluedragonmc.server
import com.bluedragonmc.server.api.Environment
import com.bluedragonmc.server.bootstrap.*
import com.bluedragonmc.server.bootstrap.dev.DevInstanceRouter
import com.bluedragonmc.server.bootstrap.dev.MojangAuthentication
import com.bluedragonmc.server.bootstrap.dev.OpenToLAN
import com.bluedragonmc.server.bootstrap.prod.AgonesIntegration
import com.bluedragonmc.server.bootstrap.prod.InitialInstanceRouter
import com.bluedragonmc.server.bootstrap.prod.VelocityForwarding
import com.bluedragonmc.server.queue.GameLoader
import com.bluedragonmc.server.queue.createEnvironment
import net.minestom.server.Auth
import net.minestom.server.MinecraftServer
import org.slf4j.LoggerFactory
import java.text.DateFormat
Expand Down Expand Up @@ -38,7 +37,20 @@ fun start() {
Environment.setEnvironment(createEnvironment())
logger.info("Starting Minecraft server in environment ${Environment.current::class.simpleName}")

val minecraftServer = MinecraftServer.init()
lateinit var auth: Auth
val velocitySecret: String? = System.getenv("PUFFIN_VELOCITY_SECRET")

if (velocitySecret != null) {
auth = Auth.Velocity(System.getenv("PUFFIN_VELOCITY_SECRET").trim())
MinecraftServer.setCompressionThreshold(0) // Disable compression because packets are being proxied
} else {
if (!Environment.isDev) {
logger.warn("Warning: Running in a production-like environment without Velocity forwarding!")
}
auth = Auth.Online()
}

val minecraftServer = MinecraftServer.init(auth)
val eventNode = MinecraftServer.getGlobalEventHandler()

val services = listOf(
Expand All @@ -55,13 +67,11 @@ fun start() {
InitialInstanceRouter,
IntegrationsInit,
Jukebox,
MojangAuthentication,
OpenToLAN,
PerInstanceChat,
PerInstanceTabList,
ServerListPingHandler,
TabListFormat,
VelocityForwarding
).filter { it.canHook() }

// Load game plugins and preinitialize their main classes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ object PerInstanceTabList : Bootstrap() {
player.gameMode,
player.name,
null,
1024
1024,
true
)
}
Loading
Loading