From 19d60ff90cfefea88354e9851e8137a83f2182c5 Mon Sep 17 00:00:00 2001 From: FluxCapacitor2 <31071265+FluxCapacitor2@users.noreply.github.com> Date: Wed, 23 Oct 2024 00:37:21 -0400 Subject: [PATCH] (WIP) Update Minestom to 1.21.2 and switch projectiles to AtlasProjectiles --- build.gradle.kts | 9 +-- common/build.gradle.kts | 3 + .../com/bluedragonmc/server/CustomPlayer.kt | 8 +-- .../server/api/DatabaseConnection.kt | 2 +- .../bluedragonmc/server/command/Arguments.kt | 14 ++--- .../server/module/combat/OldCombatModule.kt | 10 ++-- .../server/module/combat/ProjectileModule.kt | 40 +++++++------- .../module/gameplay/InstantRespawnModule.kt | 4 +- .../server/module/gameplay/MaxHealthModule.kt | 4 +- .../server/module/gameplay/NPCModule.kt | 3 +- .../module/minigame/PlayerResetModule.kt | 4 +- .../server/module/minigame/VoteStartModule.kt | 3 +- .../server/module/vanilla/DoorsModule.kt | 4 +- gradle/libs.versions.toml | 4 +- .../server/bootstrap/GlobalChatFormat.kt | 6 +- .../server/bootstrap/PerInstanceTabList.kt | 9 +-- .../server/bootstrap/dev/DevInstanceRouter.kt | 18 ++++-- .../bootstrap/prod/InitialInstanceRouter.kt | 12 +++- .../server/impl/DatabaseConnectionImpl.kt | 55 +++++++++---------- 19 files changed, 112 insertions(+), 100 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 96c13890..5479d443 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,14 +13,7 @@ repositories { mavenLocal() mavenCentral() maven(url = "https://jitpack.io") -} - -subprojects { - repositories { - mavenLocal() - mavenCentral() - maven(url = "https://jitpack.io") - } + maven("https://reposilite.worldseed.online/public") } dependencies { diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 0ec35cf7..43db9429 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -8,12 +8,15 @@ group = "com.bluedragonmc.server" version = "1.0-SNAPSHOT" repositories { + mavenLocal() mavenCentral() maven(url = "https://jitpack.io") + maven("https://reposilite.worldseed.online/public") } dependencies { implementation(libs.minestom) + implementation(libs.atlas.projectiles) implementation(libs.kmongo) implementation(libs.caffeine) implementation(libs.minimessage) diff --git a/common/src/main/kotlin/com/bluedragonmc/server/CustomPlayer.kt b/common/src/main/kotlin/com/bluedragonmc/server/CustomPlayer.kt index 80ddf91f..c33e7425 100644 --- a/common/src/main/kotlin/com/bluedragonmc/server/CustomPlayer.kt +++ b/common/src/main/kotlin/com/bluedragonmc/server/CustomPlayer.kt @@ -13,14 +13,14 @@ import net.minestom.server.entity.Player import net.minestom.server.entity.metadata.PlayerMeta import net.minestom.server.instance.Instance import net.minestom.server.instance.block.Block +import net.minestom.server.network.player.GameProfile import net.minestom.server.network.player.PlayerConnection import net.minestom.server.potion.PotionEffect import net.minestom.server.utils.async.AsyncUtils -import java.util.* import java.util.concurrent.CompletableFuture -open class CustomPlayer(uuid: UUID, username: String, playerConnection: PlayerConnection) : - Player(uuid, username, playerConnection) { +open class CustomPlayer(playerConnection: PlayerConnection, gameProfile: GameProfile) : + Player(playerConnection, gameProfile) { internal var isSpectating = false internal var lastNPCInteractionTime = 0L @@ -106,7 +106,7 @@ open class CustomPlayer(uuid: UUID, username: String, playerConnection: PlayerCo override fun getAdditionalHearts(): Float { return if (entityMeta !is PlayerMeta) 0f - else super.getAdditionalHearts() + else super.additionalHearts } fun isOnLadder() = listOf( diff --git a/common/src/main/kotlin/com/bluedragonmc/server/api/DatabaseConnection.kt b/common/src/main/kotlin/com/bluedragonmc/server/api/DatabaseConnection.kt index c37efece..71821bfe 100644 --- a/common/src/main/kotlin/com/bluedragonmc/server/api/DatabaseConnection.kt +++ b/common/src/main/kotlin/com/bluedragonmc/server/api/DatabaseConnection.kt @@ -9,7 +9,7 @@ import kotlin.reflect.KMutableProperty interface DatabaseConnection { - fun loadDataDocument(player: CustomPlayer) + suspend fun loadDataDocument(player: CustomPlayer) suspend fun getPlayerDocument(username: String): PlayerDocument? diff --git a/common/src/main/kotlin/com/bluedragonmc/server/command/Arguments.kt b/common/src/main/kotlin/com/bluedragonmc/server/command/Arguments.kt index 308a208b..e8bc3242 100644 --- a/common/src/main/kotlin/com/bluedragonmc/server/command/Arguments.kt +++ b/common/src/main/kotlin/com/bluedragonmc/server/command/Arguments.kt @@ -18,7 +18,7 @@ import net.minestom.server.command.builder.suggestion.SuggestionEntry import net.minestom.server.instance.Instance import net.minestom.server.instance.block.Block import net.minestom.server.item.ItemStack -import net.minestom.server.utils.binary.BinaryWriter +import net.minestom.server.network.NetworkBuffer import net.minestom.server.utils.entity.EntityFinder import net.minestom.server.utils.location.RelativeVec import java.util.UUID @@ -92,8 +92,8 @@ class ArgumentGameId(id: String) : Argument(id) { } override fun nodeProperties(): ByteArray { - return BinaryWriter.makeArray { packetWriter: BinaryWriter -> - packetWriter.writeVarInt(0) // Single word + return NetworkBuffer.makeArray { packetWriter: NetworkBuffer -> + packetWriter.write(NetworkBuffer.VAR_INT, 0) // Single word } } @@ -132,8 +132,8 @@ class ArgumentOfflinePlayer(id: String) : Argument(id) { } override fun nodeProperties(): ByteArray { - return BinaryWriter.makeArray { packetWriter: BinaryWriter -> - packetWriter.writeVarInt(0) // Single word + return NetworkBuffer.makeArray { packetWriter: NetworkBuffer -> + packetWriter.write(NetworkBuffer.VAR_INT, 0) // Single word } } } @@ -159,8 +159,8 @@ class ArgumentOptionalPlayer(id: String) : Argument(id) { } override fun nodeProperties(): ByteArray { - return BinaryWriter.makeArray { packetWriter: BinaryWriter -> - packetWriter.writeVarInt(0) // Single word + return NetworkBuffer.makeArray { packetWriter: NetworkBuffer -> + packetWriter.write(NetworkBuffer.VAR_INT, 0) // Single word } } } diff --git a/common/src/main/kotlin/com/bluedragonmc/server/module/combat/OldCombatModule.kt b/common/src/main/kotlin/com/bluedragonmc/server/module/combat/OldCombatModule.kt index 68746fca..fede45d2 100644 --- a/common/src/main/kotlin/com/bluedragonmc/server/module/combat/OldCombatModule.kt +++ b/common/src/main/kotlin/com/bluedragonmc/server/module/combat/OldCombatModule.kt @@ -96,14 +96,14 @@ class OldCombatModule(var allowDamage: Boolean = true, var allowKnockback: Boole eventNode.addListener(PlayerSpawnEvent::class.java) { event -> // Hint to client that there is no attack cooldown - event.player.getAttribute(Attribute.GENERIC_ATTACK_SPEED).baseValue = 100.0 - event.player.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE).baseValue = 1.0 + event.player.getAttribute(Attribute.ATTACK_SPEED).baseValue = 100.0 + event.player.getAttribute(Attribute.ATTACK_DAMAGE).baseValue = 1.0 } eventNode.addListener(PlayerLeaveGameEvent::class.java) { event -> // Reset attributes to default - event.player.getAttribute(Attribute.GENERIC_ATTACK_SPEED).baseValue = event.player.getAttribute(Attribute.GENERIC_ATTACK_SPEED).attribute.defaultValue() - event.player.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE).baseValue = event.player.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE).attribute.defaultValue() + event.player.getAttribute(Attribute.ATTACK_SPEED).baseValue = event.player.getAttribute(Attribute.ATTACK_SPEED).attribute().defaultValue() + event.player.getAttribute(Attribute.ATTACK_DAMAGE).baseValue = event.player.getAttribute(Attribute.ATTACK_DAMAGE).attribute().defaultValue() event.player.additionalHearts = 0.0f } @@ -154,7 +154,7 @@ class OldCombatModule(var allowDamage: Boolean = true, var allowKnockback: Boole if (player.gameMode == GameMode.SPECTATOR || (target is Player && (target.gameMode == GameMode.SPECTATOR || target.gameMode == GameMode.CREATIVE))) return@addListener // The base attack damage according to the item they're holding - var dmgAttribute = player.getAttributeValue(Attribute.GENERIC_ATTACK_DAMAGE) + var dmgAttribute = player.getAttributeValue(Attribute.ATTACK_DAMAGE) val heldEnchantments = player.inventory.itemInMainHand.get(ItemComponent.ENCHANTMENTS)?.enchantments ?: emptyMap, Int>() // Extra damage provided by enchants like sharpness or smite diff --git a/common/src/main/kotlin/com/bluedragonmc/server/module/combat/ProjectileModule.kt b/common/src/main/kotlin/com/bluedragonmc/server/module/combat/ProjectileModule.kt index 971a1493..0529e5b0 100644 --- a/common/src/main/kotlin/com/bluedragonmc/server/module/combat/ProjectileModule.kt +++ b/common/src/main/kotlin/com/bluedragonmc/server/module/combat/ProjectileModule.kt @@ -1,5 +1,8 @@ package com.bluedragonmc.server.module.combat +import ca.atlasengine.projectiles.entities.ArrowProjectile +import ca.atlasengine.projectiles.entities.FireballProjectile +import ca.atlasengine.projectiles.entities.ThrownItemProjectile import com.bluedragonmc.server.Game import com.bluedragonmc.server.event.ProjectileBreakBlockEvent import com.bluedragonmc.server.module.GameModule @@ -10,7 +13,6 @@ import net.minestom.server.ServerFlag import net.minestom.server.coordinate.Point import net.minestom.server.coordinate.Pos import net.minestom.server.entity.* -import net.minestom.server.entity.Player.Hand import net.minestom.server.entity.attribute.Attribute import net.minestom.server.entity.damage.Damage import net.minestom.server.entity.damage.DamageType @@ -40,13 +42,11 @@ import kotlin.math.abs import kotlin.math.ceil import kotlin.random.Random - class ProjectileModule : GameModule() { - /** - * A subclass of [PlayerProjectile] that exposes the [shooter] publicly - */ - class Projectile(val shooter: Entity?, type: EntityType?) : PlayerProjectile(shooter, type) + class CustomArrowProjectile(val shooter: Entity?, entityType: EntityType) : ArrowProjectile(entityType, shooter) + class CustomItemProjectile(val shooter: Entity?, entityType: EntityType) : ThrownItemProjectile(entityType, shooter) + class CustomFireballProjectile(val shooter: Entity?, entityType: EntityType) : FireballProjectile(entityType, shooter) private lateinit var parent: Game @@ -95,7 +95,7 @@ class ProjectileModule : GameModule() { val power = ((secondsCharged * secondsCharged + 2 * secondsCharged) / 2.0).coerceIn(0.0, 1.0) if (power > 0.2) { - val projectile = Projectile(event.player, EntityType.ARROW) + val projectile = CustomArrowProjectile(event.player, EntityType.ARROW) if (power > 0.9) (projectile.entityMeta as ArrowMeta).isCritical = true projectile.scheduleRemove(Duration.ofSeconds(30)) val eyePos = getEyePos(event.player) @@ -117,9 +117,7 @@ class ProjectileModule : GameModule() { } eventNode.addListener(ProjectileCollideWithEntityEvent::class.java) { event -> val target = event.target as? LivingEntity ?: return@addListener - val projectile = event.entity as Projectile - - if (projectile.entityType != EntityType.ARROW) return@addListener + val projectile = event.entity as? CustomArrowProjectile ?: return@addListener val arrowMeta = projectile.entityMeta as? ArrowMeta ?: return@addListener val shooter = projectile.shooter @@ -138,7 +136,7 @@ class ProjectileModule : GameModule() { ) val damageModifier = - (projectile.shooter as? LivingEntity)?.getAttribute(Attribute.GENERIC_ATTACK_DAMAGE)?.value ?: 1.0 + (projectile.shooter as? LivingEntity)?.getAttribute(Attribute.ATTACK_DAMAGE)?.value ?: 1.0 var originalDamage = damageModifier * 2.0f + Random.nextFloat() * 0.25 + 0.15f if (projectile.getTag(ARROW_DAMAGE_TAG) > 0) { @@ -186,7 +184,7 @@ class ProjectileModule : GameModule() { } // Shoot a snowball from the player's position - val snowball = Projectile(event.player, EntityType.SNOWBALL) + val snowball = CustomItemProjectile(event.player, EntityType.SNOWBALL) snowball.setInstance(event.instance, getEyePos(event.player)) snowball.shoot(getLaunchPos(event.player), 3.0, 1.0) event.player.instance?.playSound( @@ -202,7 +200,7 @@ class ProjectileModule : GameModule() { } eventNode.addListener(ProjectileCollideWithEntityEvent::class.java) { event -> val target = event.target as? LivingEntity ?: return@addListener - val projectile = event.entity as Projectile + val projectile = event.entity as? CustomItemProjectile ?: return@addListener if (projectile.entityType != EntityType.SNOWBALL) return@addListener @@ -239,7 +237,7 @@ class ProjectileModule : GameModule() { } } - private fun shootFireball(player: Player, hand: Hand, instance: Instance) { + private fun shootFireball(player: Player, hand: PlayerHand, instance: Instance) { val itemStack = player.getItemInHand(hand) if (itemStack.material() == Material.FIRE_CHARGE) { if (player.isOnCooldown()) return @@ -249,7 +247,7 @@ class ProjectileModule : GameModule() { } // Shoot a fireball from the player's position - val fireball = Projectile(player, EntityType.FIREBALL) + val fireball = CustomFireballProjectile(player, EntityType.FIREBALL) fireball.setInstance(instance, getEyePos(player)) fireball.shoot(getLaunchPos(player), 3.0, 1.0) player.instance?.playSound( @@ -261,7 +259,7 @@ class ProjectileModule : GameModule() { } private fun explodeFireball(projectile: Entity) { - projectile as Projectile + projectile as? CustomFireballProjectile ?: return projectile.remove() val pos = projectile.position @@ -294,7 +292,7 @@ class ProjectileModule : GameModule() { centerY: Float, centerZ: Float, strength: Float, - projectile: Projectile, + projectile: CustomFireballProjectile, ) = object : Explosion(centerX, centerY, centerZ, strength) { override fun prepare(instance: Instance): List { @@ -338,7 +336,7 @@ class ProjectileModule : GameModule() { } eventNode.addListener(ProjectileCollideWithEntityEvent::class.java) { event -> val target = event.target as? LivingEntity ?: return@addListener - val projectile = event.entity as Projectile + val projectile = event.entity as? CustomItemProjectile ?: return@addListener if (projectile.entityType != EntityType.EGG) return@addListener @@ -356,7 +354,7 @@ class ProjectileModule : GameModule() { } } - private fun throwEgg(player: Player, hand: Hand, instance: Instance) { + private fun throwEgg(player: Player, hand: PlayerHand, instance: Instance) { val itemStack = player.getItemInHand(hand) if (itemStack.material() == Material.EGG) { if (player.isOnCooldown()) return @@ -366,7 +364,7 @@ class ProjectileModule : GameModule() { } // Shoot an egg from the player's position - val egg = Projectile(player, EntityType.EGG) + val egg = CustomItemProjectile(player, EntityType.EGG) egg.setInstance(instance, getEyePos(player)) egg.shoot(getLaunchPos(player), 3.0, 1.0) instance.playSound( @@ -389,7 +387,7 @@ class ProjectileModule : GameModule() { val itemStack = event.player.getItemInHand(event.hand) if (itemStack.material() == Material.ENDER_PEARL) { if (event.player.isOnCooldown()) return@addListener - val pearl = Projectile(event.player, EntityType.ENDER_PEARL) + val pearl = CustomItemProjectile(event.player, EntityType.ENDER_PEARL) pearl.setTag(PEARL_OWNER_TAG, event.player.uuid) pearl.setInstance(event.instance, getEyePos(event.player)) pearl.shoot(getLaunchPos(event.player), 2.5, 1.0) diff --git a/common/src/main/kotlin/com/bluedragonmc/server/module/gameplay/InstantRespawnModule.kt b/common/src/main/kotlin/com/bluedragonmc/server/module/gameplay/InstantRespawnModule.kt index 8a25bc8a..da5cc5fb 100644 --- a/common/src/main/kotlin/com/bluedragonmc/server/module/gameplay/InstantRespawnModule.kt +++ b/common/src/main/kotlin/com/bluedragonmc/server/module/gameplay/InstantRespawnModule.kt @@ -5,7 +5,7 @@ import com.bluedragonmc.server.Game import com.bluedragonmc.server.module.GameModule import net.minestom.server.MinecraftServer import net.minestom.server.coordinate.Vec -import net.minestom.server.entity.Entity +import net.minestom.server.entity.EntityPose import net.minestom.server.entity.Player import net.minestom.server.event.Event import net.minestom.server.event.EventDispatcher @@ -37,7 +37,7 @@ class InstantRespawnModule : GameModule() { isDead = true fireTicks = 0 - pose = Entity.Pose.STANDING + pose = EntityPose.STANDING velocity = Vec.ZERO val respawnEvent = PlayerRespawnEvent(this) diff --git a/common/src/main/kotlin/com/bluedragonmc/server/module/gameplay/MaxHealthModule.kt b/common/src/main/kotlin/com/bluedragonmc/server/module/gameplay/MaxHealthModule.kt index 29bb523c..df25a923 100644 --- a/common/src/main/kotlin/com/bluedragonmc/server/module/gameplay/MaxHealthModule.kt +++ b/common/src/main/kotlin/com/bluedragonmc/server/module/gameplay/MaxHealthModule.kt @@ -17,10 +17,10 @@ class MaxHealthModule(private val maxHealth: Double) : GameModule() { override fun initialize(parent: Game, eventNode: EventNode) { eventNode.addListener(PlayerSpawnEvent::class.java) { event -> - event.player.getAttribute(Attribute.GENERIC_MAX_HEALTH).baseValue = maxHealth + event.player.getAttribute(Attribute.MAX_HEALTH).baseValue = maxHealth } eventNode.addListener(PlayerLeaveGameEvent::class.java) { event -> - event.player.getAttribute(Attribute.GENERIC_MAX_HEALTH).baseValue = 20.0 + event.player.getAttribute(Attribute.MAX_HEALTH).baseValue = 20.0 } } } \ No newline at end of file diff --git a/common/src/main/kotlin/com/bluedragonmc/server/module/gameplay/NPCModule.kt b/common/src/main/kotlin/com/bluedragonmc/server/module/gameplay/NPCModule.kt index d3291bfb..ab4ff390 100644 --- a/common/src/main/kotlin/com/bluedragonmc/server/module/gameplay/NPCModule.kt +++ b/common/src/main/kotlin/com/bluedragonmc/server/module/gameplay/NPCModule.kt @@ -130,7 +130,8 @@ class NPCModule : GameModule() { 0, GameMode.CREATIVE, Component.text("[NPC] $randomName", NamedTextColor.DARK_GRAY, TextDecoration.ITALIC), - null + null, + 0 ) ) diff --git a/common/src/main/kotlin/com/bluedragonmc/server/module/minigame/PlayerResetModule.kt b/common/src/main/kotlin/com/bluedragonmc/server/module/minigame/PlayerResetModule.kt index 9ab97051..3a8f3841 100644 --- a/common/src/main/kotlin/com/bluedragonmc/server/module/minigame/PlayerResetModule.kt +++ b/common/src/main/kotlin/com/bluedragonmc/server/module/minigame/PlayerResetModule.kt @@ -34,11 +34,11 @@ class PlayerResetModule(val defaultGameMode: GameMode? = null) : GameModule() { player.gameMode = gameMode ?: player.gameMode player.inventory.clear() Attribute.values().forEach { attribute -> - player.getAttribute(attribute).modifiers.forEach { modifier -> + player.getAttribute(attribute).modifiers().forEach { modifier -> player.getAttribute(attribute).removeModifier(modifier) } } - player.health = player.getAttribute(Attribute.GENERIC_MAX_HEALTH).value.toFloat() + player.health = player.getAttribute(Attribute.MAX_HEALTH).value.toFloat() player.food = 20 player.clearEffects() player.fireTicks = 0 diff --git a/common/src/main/kotlin/com/bluedragonmc/server/module/minigame/VoteStartModule.kt b/common/src/main/kotlin/com/bluedragonmc/server/module/minigame/VoteStartModule.kt index ebc9c630..47764e9b 100644 --- a/common/src/main/kotlin/com/bluedragonmc/server/module/minigame/VoteStartModule.kt +++ b/common/src/main/kotlin/com/bluedragonmc/server/module/minigame/VoteStartModule.kt @@ -16,6 +16,7 @@ import net.kyori.adventure.title.Title import net.kyori.adventure.title.TitlePart import net.minestom.server.MinecraftServer import net.minestom.server.entity.Player +import net.minestom.server.entity.PlayerHand import net.minestom.server.event.Event import net.minestom.server.event.EventNode import net.minestom.server.event.player.PlayerSpawnEvent @@ -53,7 +54,7 @@ class VoteStartModule( fill(event.player, voteStartItem) } eventNode.addListener(PlayerUseItemEvent::class.java) { event -> - if (event.hand != Player.Hand.MAIN) return@addListener + if (event.hand != PlayerHand.MAIN) return@addListener when (event.itemStack) { voteStartItem -> { diff --git a/common/src/main/kotlin/com/bluedragonmc/server/module/vanilla/DoorsModule.kt b/common/src/main/kotlin/com/bluedragonmc/server/module/vanilla/DoorsModule.kt index 48f1f629..7bef5648 100644 --- a/common/src/main/kotlin/com/bluedragonmc/server/module/vanilla/DoorsModule.kt +++ b/common/src/main/kotlin/com/bluedragonmc/server/module/vanilla/DoorsModule.kt @@ -12,7 +12,7 @@ import net.minestom.server.instance.EntityTracker import net.minestom.server.instance.Instance import net.minestom.server.instance.block.Block import net.minestom.server.network.packet.server.play.EffectPacket -import net.minestom.server.utils.PacketUtils +import net.minestom.server.utils.PacketSendingUtils /** * Adapted from BasicRedstone by TogAr2 under the MIT License @@ -78,7 +78,7 @@ class DoorsModule : GameModule() { player ) } - PacketUtils.sendGroupedPacket( + PacketSendingUtils.sendGroupedPacket( audience, EffectPacket(effect.id, position, 0, false) ) { player -> player != source } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 33ff34a6..0e309b0b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ metadata.format.version = "1.1" [versions] kotlin = "2.0.0" -minestom = "461c56e749" +minestom = "1_21_2-ee6a7180b4" configurate = "4.1.2" minimessage = "4.11.0" kmongo = "4.6.1" @@ -10,6 +10,7 @@ caffeine = "3.1.1" okhttp = "4.10.0" serialization = "1.5.0-RC" tinylog = "2.6.2" +atlas-projectiles = "2.0.0" # Auto-generated GRPC/Protobuf messaging code rpc = "fb16ef4cc5" # Agones SDK and its necessary runtime dependencies @@ -27,6 +28,7 @@ minestom = { group = "net.minestom", name = "minestom-snapshots", version.ref = configurate = { group = "org.spongepowered", name = "configurate-yaml", version.ref = "configurate" } 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" } 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" } diff --git a/src/main/kotlin/com/bluedragonmc/server/bootstrap/GlobalChatFormat.kt b/src/main/kotlin/com/bluedragonmc/server/bootstrap/GlobalChatFormat.kt index 9c7314eb..62330e0f 100644 --- a/src/main/kotlin/com/bluedragonmc/server/bootstrap/GlobalChatFormat.kt +++ b/src/main/kotlin/com/bluedragonmc/server/bootstrap/GlobalChatFormat.kt @@ -51,12 +51,12 @@ object GlobalChatFormat : Bootstrap() { +player.name +Component.text(": ", NamedTextColor.DARK_GRAY) if (Permissions.hasPermission(player.uuid, "chat.minimessage") == true) - +miniMessage.deserialize(event.message) - else +Component.text(event.message, NamedTextColor.WHITE) + +miniMessage.deserialize(event.rawMessage) + else +Component.text(event.rawMessage, NamedTextColor.WHITE) } // Currently, setting the chat format does not allow for translation with GlobalTranslator - // because it always sends a GroupedPacket. + // because it always sends a GroupedPacket. Instead, we cancel the event and send the messages individually. event.recipients.forEach { it.sendMessage(component) } } } diff --git a/src/main/kotlin/com/bluedragonmc/server/bootstrap/PerInstanceTabList.kt b/src/main/kotlin/com/bluedragonmc/server/bootstrap/PerInstanceTabList.kt index 08f2d8e0..0a3a66bf 100644 --- a/src/main/kotlin/com/bluedragonmc/server/bootstrap/PerInstanceTabList.kt +++ b/src/main/kotlin/com/bluedragonmc/server/bootstrap/PerInstanceTabList.kt @@ -7,7 +7,7 @@ import net.minestom.server.event.instance.AddEntityToInstanceEvent import net.minestom.server.event.instance.RemoveEntityFromInstanceEvent import net.minestom.server.network.packet.server.play.PlayerInfoRemovePacket import net.minestom.server.network.packet.server.play.PlayerInfoUpdatePacket -import net.minestom.server.utils.PacketUtils +import net.minestom.server.utils.PacketSendingUtils import java.util.* object PerInstanceTabList : Bootstrap() { @@ -26,7 +26,7 @@ object PerInstanceTabList : Bootstrap() { getAddPlayerPacket(newInstance.players) ) // Send a packet to all players in the instance to add this new player - PacketUtils.sendGroupedPacket( + PacketSendingUtils.sendGroupedPacket( newInstance.players + player, getAddPlayerPacket(player) ) @@ -35,7 +35,7 @@ object PerInstanceTabList : Bootstrap() { if (event.entity !is Player) return@addListener val player = event.entity as Player // Remove this player from everyone's tablist - PacketUtils.sendGroupedPacket( + PacketSendingUtils.sendGroupedPacket( event.instance.players - player, getRemovePlayerPacket(setOf(player)) ) @@ -78,6 +78,7 @@ object PerInstanceTabList : Bootstrap() { player.latency, player.gameMode, player.name, - null + null, + 1024 ) } \ No newline at end of file diff --git a/src/main/kotlin/com/bluedragonmc/server/bootstrap/dev/DevInstanceRouter.kt b/src/main/kotlin/com/bluedragonmc/server/bootstrap/dev/DevInstanceRouter.kt index 0034551d..558c3959 100644 --- a/src/main/kotlin/com/bluedragonmc/server/bootstrap/dev/DevInstanceRouter.kt +++ b/src/main/kotlin/com/bluedragonmc/server/bootstrap/dev/DevInstanceRouter.kt @@ -2,24 +2,34 @@ package com.bluedragonmc.server.bootstrap.dev import com.bluedragonmc.server.CustomPlayer import com.bluedragonmc.server.bootstrap.Bootstrap +import com.bluedragonmc.server.bootstrap.prod.InitialInstanceRouter.DATA_LOAD_FAILED import com.bluedragonmc.server.isLobbyInitialized import com.bluedragonmc.server.lobby import com.bluedragonmc.server.module.minigame.SpawnpointModule import com.bluedragonmc.server.service.Database import com.bluedragonmc.server.utils.listen +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeout import net.minestom.server.MinecraftServer import net.minestom.server.event.Event import net.minestom.server.event.EventNode import net.minestom.server.event.instance.InstanceTickEvent import net.minestom.server.event.player.AsyncPlayerConfigurationEvent -import net.minestom.server.event.player.AsyncPlayerPreLoginEvent object DevInstanceRouter : Bootstrap(EnvType.DEVELOPMENT) { override fun hook(eventNode: EventNode) { - eventNode.addListener(AsyncPlayerPreLoginEvent::class.java) { event -> - Database.connection.loadDataDocument(event.player as CustomPlayer) - } eventNode.addListener(AsyncPlayerConfigurationEvent::class.java) { event -> + try { + runBlocking { + withTimeout(5000) { + Database.connection.loadDataDocument(event.player as CustomPlayer) + } + } + } catch (e: Exception) { + e.printStackTrace() + event.player.kick(DATA_LOAD_FAILED) + } + if (isLobbyInitialized()) { // Send the player to the lobby event.spawningInstance = lobby.getInstance() diff --git a/src/main/kotlin/com/bluedragonmc/server/bootstrap/prod/InitialInstanceRouter.kt b/src/main/kotlin/com/bluedragonmc/server/bootstrap/prod/InitialInstanceRouter.kt index 95617927..6ac13ded 100644 --- a/src/main/kotlin/com/bluedragonmc/server/bootstrap/prod/InitialInstanceRouter.kt +++ b/src/main/kotlin/com/bluedragonmc/server/bootstrap/prod/InitialInstanceRouter.kt @@ -11,6 +11,7 @@ import com.bluedragonmc.server.service.Messaging import com.bluedragonmc.server.utils.listenSuspend import kotlinx.coroutines.async import kotlinx.coroutines.launch +import kotlinx.coroutines.withTimeout import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor import net.minestom.server.MinecraftServer @@ -24,7 +25,7 @@ object InitialInstanceRouter : Bootstrap(EnvType.PRODUCTION) { Component.text("Couldn't find which world to put you in! (Invalid world name)", NamedTextColor.RED) private val HANDSHAKE_FAILED = Component.text("Couldn't find which world to put you in! (Handshake failed)", NamedTextColor.RED) - private val DATA_LOAD_FAILED = + internal val DATA_LOAD_FAILED = Component.text("Failed to load your player data!", NamedTextColor.RED) override fun hook(eventNode: EventNode) { @@ -36,12 +37,16 @@ object InitialInstanceRouter : Bootstrap(EnvType.PRODUCTION) { val dataLoadJob = Database.IO.async { // Load player data from the database - Database.connection.loadDataDocument(event.player as CustomPlayer) + withTimeout(5000) { + Database.connection.loadDataDocument(event.player as CustomPlayer) + } } val getDestinationJob = Messaging.IO.async { // Find the game that the player requested to join - Messaging.outgoing.getDestination(event.player.uuid) + withTimeout(5000) { + Messaging.outgoing.getDestination(event.player.uuid) + } } // After starting both jobs, wait for them to complete @@ -51,6 +56,7 @@ object InitialInstanceRouter : Bootstrap(EnvType.PRODUCTION) { } catch (e: Exception) { e.printStackTrace() event.player.kick(DATA_LOAD_FAILED) + return@listenSuspend } val destination = try { diff --git a/src/main/kotlin/com/bluedragonmc/server/impl/DatabaseConnectionImpl.kt b/src/main/kotlin/com/bluedragonmc/server/impl/DatabaseConnectionImpl.kt index 22f0ff49..9dd03808 100644 --- a/src/main/kotlin/com/bluedragonmc/server/impl/DatabaseConnectionImpl.kt +++ b/src/main/kotlin/com/bluedragonmc/server/impl/DatabaseConnectionImpl.kt @@ -11,7 +11,6 @@ import com.mongodb.ConnectionString import com.mongodb.MongoClientSettings import com.mongodb.client.model.Filters import com.mongodb.client.model.Sorts -import kotlinx.coroutines.runBlocking import net.kyori.adventure.text.Component import net.kyori.adventure.text.format.NamedTextColor import net.minestom.server.MinecraftServer @@ -87,38 +86,36 @@ internal class DatabaseConnectionImpl(connectionString: String) : DatabaseConnec } } - override fun loadDataDocument(player: CustomPlayer) { + override suspend fun loadDataDocument(player: CustomPlayer) { // Load players' data from the database when they spawn if (player.isDataInitialized()) return - runBlocking { - try { - player.data = getPlayerDocument(player) - - if (player.username != player.data.username || player.data.username.isBlank()) { - // Keep an up-to-date record of player usernames - player.data.update(PlayerDocument::username, player.username) - player.data.update(PlayerDocument::usernameLower, player.username.lowercase()) - logger.info("Updated username for ${player.uuid}: ${player.data.username} -> ${player.username}") - } - if (player.data.usernameLower != player.username.lowercase()) { - player.data.update(PlayerDocument::usernameLower, player.username.lowercase()) - } - player.data.update(PlayerDocument::lastJoinDate, System.currentTimeMillis()) - MinecraftServer.getGlobalEventHandler().call(DataLoadedEvent(player)) - logger.info("Loaded player data for ${player.username}") - } catch (e: Throwable) { - logger.error("Player data for ${player.username} failed to load.") - MinecraftServer.getExceptionManager().handleException(e) - player.sendPacket( - LoginDisconnectPacket( - Component.translatable( - "module.database.data_load_fail", - NamedTextColor.RED - ) + try { + player.data = getPlayerDocument(player) + + if (player.username != player.data.username || player.data.username.isBlank()) { + // Keep an up-to-date record of player usernames + player.data.update(PlayerDocument::username, player.username) + player.data.update(PlayerDocument::usernameLower, player.username.lowercase()) + logger.info("Updated username for ${player.uuid}: ${player.data.username} -> ${player.username}") + } + if (player.data.usernameLower != player.username.lowercase()) { + player.data.update(PlayerDocument::usernameLower, player.username.lowercase()) + } + player.data.update(PlayerDocument::lastJoinDate, System.currentTimeMillis()) + MinecraftServer.getGlobalEventHandler().call(DataLoadedEvent(player)) + logger.info("Loaded player data for ${player.username}") + } catch (e: Throwable) { + logger.error("Player data for ${player.username} failed to load.") + MinecraftServer.getExceptionManager().handleException(e) + player.sendPacket( + LoginDisconnectPacket( + Component.translatable( + "module.database.data_load_fail", + NamedTextColor.RED ) ) - player.playerConnection.disconnect() - } + ) + player.playerConnection.disconnect() } }