diff --git a/src/main/java/ua/mei/minekord/mixin/ServerLoginNetworkHandlerMixin.java b/src/main/java/ua/mei/minekord/mixin/ServerLoginNetworkHandlerMixin.java index 8a17eaf..4e1839b 100644 --- a/src/main/java/ua/mei/minekord/mixin/ServerLoginNetworkHandlerMixin.java +++ b/src/main/java/ua/mei/minekord/mixin/ServerLoginNetworkHandlerMixin.java @@ -58,6 +58,10 @@ public abstract class ServerLoginNetworkHandlerMixin { @Shadow public abstract void disconnect(Text text); + @Shadow @Nullable String profileName; + + @Shadow abstract void startVerify(GameProfile gameProfile); + @Inject(method = "onHello", at = @At("HEAD"), cancellable = true) public void minekord$checkIp(LoginHelloC2SPacket loginHelloC2SPacket, CallbackInfo ci) { if (MinekordConfig.Auth.INSTANCE.getIpBasedLogin() && IPCache.INSTANCE.isBlocked(this.connection.getAddress())) { @@ -98,27 +102,22 @@ public abstract class ServerLoginNetworkHandlerMixin { if (MinekordConfig.Auth.INSTANCE.getSnowflakeBasedUuid()) { Thread thread = new Thread("Minekord User Authenticator #" + NEXT_AUTHENTICATOR_THREAD_ID.incrementAndGet()) { public void run() { - GameProfile gameProfile = ServerLoginNetworkHandlerMixin.this.profile; - assert gameProfile != null; + assert ServerLoginNetworkHandlerMixin.this.profileName != null; if (member == null) { - member = AuthUtils.INSTANCE.findMember(gameProfile.getName()); + member = AuthUtils.INSTANCE.findMember(ServerLoginNetworkHandlerMixin.this.profileName); } if (member != null) { - ServerLoginNetworkHandlerMixin.this.profile = new GameProfile(AuthUtils.INSTANCE.uuidFromMember(member), gameProfile.getName()); + ServerLoginNetworkHandlerMixin.this.profile = new GameProfile(AuthUtils.INSTANCE.uuidFromMember(member), ServerLoginNetworkHandlerMixin.this.profileName); } if (ServerLoginNetworkHandlerMixin.this.profile != null) { LOGGER.info("Snowflake based UUID of player {} is {}", ServerLoginNetworkHandlerMixin.this.profile.getName(), ServerLoginNetworkHandlerMixin.this.profile.getId()); - ServerLoginNetworkHandlerMixin.this.state = ServerLoginNetworkHandler.State.PROTOCOL_SWITCHING; - } else if (ServerLoginNetworkHandlerMixin.this.server.isSingleplayer()) { - LOGGER.warn("Failed to verify username but will let them in anyway!"); - ServerLoginNetworkHandlerMixin.this.profile = gameProfile; - ServerLoginNetworkHandlerMixin.this.state = ServerLoginNetworkHandler.State.PROTOCOL_SWITCHING; + ServerLoginNetworkHandlerMixin.this.startVerify(ServerLoginNetworkHandlerMixin.this.profile); } else { ServerLoginNetworkHandlerMixin.this.disconnect(Text.translatable("multiplayer.disconnect.unverified_username")); - LOGGER.error("Username '{}' tried to join with an invalid session", gameProfile.getName()); + LOGGER.error("Username '{}' tried to join with an invalid session", ServerLoginNetworkHandlerMixin.this.profileName); } } }; diff --git a/src/main/kotlin/ua/mei/minekord/bot/MinekordBot.kt b/src/main/kotlin/ua/mei/minekord/bot/MinekordBot.kt index cb4c06d..96f017a 100644 --- a/src/main/kotlin/ua/mei/minekord/bot/MinekordBot.kt +++ b/src/main/kotlin/ua/mei/minekord/bot/MinekordBot.kt @@ -35,11 +35,7 @@ import ua.mei.minekord.config.MinekordConfig.Main import ua.mei.minekord.config.MinekordConfig.Presence import ua.mei.minekord.event.AdvancementGrantEvent import ua.mei.minekord.event.ChatMessageEvent -import ua.mei.minekord.utils.MinekordActivityType -import ua.mei.minekord.utils.MinekordMinecraftRenderer -import ua.mei.minekord.utils.SerializerUtils -import ua.mei.minekord.utils.asSnowflake -import ua.mei.minekord.utils.toText +import ua.mei.minekord.utils.* import kotlin.coroutines.CoroutineContext import kotlin.reflect.KCallable diff --git a/src/main/kotlin/ua/mei/minekord/bot/extension/IPCheckExtension.kt b/src/main/kotlin/ua/mei/minekord/bot/extension/IPCheckExtension.kt index a051abe..5b2a4cc 100644 --- a/src/main/kotlin/ua/mei/minekord/bot/extension/IPCheckExtension.kt +++ b/src/main/kotlin/ua/mei/minekord/bot/extension/IPCheckExtension.kt @@ -14,9 +14,10 @@ import dev.kordex.core.extensions.Extension import dev.kordex.core.i18n.toKey import dev.kordex.core.time.TimestampType import dev.kordex.core.time.toDiscord -import io.ktor.util.network.address +import io.ktor.util.network.* import kotlinx.coroutines.launch import kotlinx.datetime.Clock +import ua.mei.minekord.Minekord import ua.mei.minekord.bot.MinekordBot import ua.mei.minekord.cache.IPCache import ua.mei.minekord.config.MinekordConfig.Auth @@ -48,7 +49,7 @@ class IPCheckExtension : Extension() { } } } catch (e: Exception) { - println("Error handling IP check: ${e.message}") + Minekord.logger.info("Error handling IP check: ${e.message}") } } } diff --git a/src/main/kotlin/ua/mei/minekord/bot/extension/MessagesExtension.kt b/src/main/kotlin/ua/mei/minekord/bot/extension/MessagesExtension.kt index 0eddd16..34b95f3 100644 --- a/src/main/kotlin/ua/mei/minekord/bot/extension/MessagesExtension.kt +++ b/src/main/kotlin/ua/mei/minekord/bot/extension/MessagesExtension.kt @@ -20,15 +20,7 @@ import ua.mei.minekord.bot.MinekordExtension import ua.mei.minekord.config.MinekordConfig.Chat import ua.mei.minekord.config.MinekordConfig.Colors import ua.mei.minekord.config.MinekordConfig.Main -import ua.mei.minekord.utils.MessageSender -import ua.mei.minekord.utils.SerializerUtils -import ua.mei.minekord.utils.adventure -import ua.mei.minekord.utils.asSnowflake -import ua.mei.minekord.utils.avatarUrl -import ua.mei.minekord.utils.literal -import ua.mei.minekord.utils.native -import ua.mei.minekord.utils.summary -import ua.mei.minekord.utils.toText +import ua.mei.minekord.utils.* import kotlin.jvm.optionals.getOrNull class MessagesExtension : MinekordExtension() { diff --git a/src/main/kotlin/ua/mei/minekord/bot/extension/RoleSyncExtension.kt b/src/main/kotlin/ua/mei/minekord/bot/extension/RoleSyncExtension.kt index 324cb98..47dea36 100644 --- a/src/main/kotlin/ua/mei/minekord/bot/extension/RoleSyncExtension.kt +++ b/src/main/kotlin/ua/mei/minekord/bot/extension/RoleSyncExtension.kt @@ -1,28 +1,60 @@ package ua.mei.minekord.bot.extension +import com.mojang.authlib.GameProfile import dev.kord.core.entity.Member +import dev.kord.core.event.guild.MemberUpdateEvent +import dev.kordex.core.extensions.event +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.toList import net.fabricmc.loader.api.FabricLoader import net.luckperms.api.LuckPerms import net.luckperms.api.LuckPermsProvider import net.luckperms.api.node.types.InheritanceNode import net.minecraft.server.network.ServerPlayerEntity +import ua.mei.minekord.Minekord +import ua.mei.minekord.bot.MinekordBot import ua.mei.minekord.bot.MinekordExtension import ua.mei.minekord.config.MinekordConfig import ua.mei.minekord.utils.AuthUtils +import kotlin.jvm.optionals.getOrNull class RoleSyncExtension : MinekordExtension() { override val name: String = "minekord.rolesync" override suspend fun setup() { - + event { + action { + syncPlayer(event.member.effectiveName) + } + } } override suspend fun onPlayerJoin(player: ServerPlayerEntity) { - if (FabricLoader.getInstance().isModLoaded("luckperms") && !MinekordConfig.LuckPerms.roles.isEmpty()) { + syncPlayer(player.gameProfile.name) + } + + override suspend fun onServerStart() { + if (!MinekordConfig.LuckPerms.roles.isEmpty() && FabricLoader.getInstance().isModLoaded("luckperms")) { + val startTime = System.currentTimeMillis() + + val members: List = MinekordBot.guild.members.filter { it.roleIds.map { it.value }.containsAll(MinekordConfig.Auth.requiredRoles) }.toList() + + members.forEach { member -> + syncPlayer(member.effectiveName) + } + + val endTime = System.currentTimeMillis() + Minekord.logger.info("Roles successfully synced! Sync time: ${endTime - startTime}ms") + } + } + + fun syncPlayer(nickname: String) { + if (!MinekordConfig.LuckPerms.roles.isEmpty() && FabricLoader.getInstance().isModLoaded("luckperms")) { val lp: LuckPerms = LuckPermsProvider.get() + val member: Member = AuthUtils.findMember(nickname) ?: return + val profile: GameProfile = server.userCache?.findByName(nickname)?.getOrNull() ?: return - lp.userManager.loadUser(player.gameProfile.id).thenAcceptAsync { user -> - val member: Member = AuthUtils.findMember(player.gameProfile.name) ?: return@thenAcceptAsync + lp.userManager.loadUser(profile.id).thenAcceptAsync { user -> val roles: List = member.roleIds.map { it.value } user.data().toCollection() diff --git a/src/main/kotlin/ua/mei/minekord/cache/IPCache.kt b/src/main/kotlin/ua/mei/minekord/cache/IPCache.kt index 8f48f08..5f83b14 100644 --- a/src/main/kotlin/ua/mei/minekord/cache/IPCache.kt +++ b/src/main/kotlin/ua/mei/minekord/cache/IPCache.kt @@ -4,7 +4,7 @@ import com.google.gson.Gson import com.google.gson.GsonBuilder import com.google.gson.reflect.TypeToken import com.mojang.authlib.GameProfile -import io.ktor.util.network.address +import io.ktor.util.network.* import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents import net.fabricmc.loader.api.FabricLoader import net.minecraft.server.MinecraftServer diff --git a/src/main/kotlin/ua/mei/minekord/config/MinekordConfig.kt b/src/main/kotlin/ua/mei/minekord/config/MinekordConfig.kt index 1d63251..10e62ce 100644 --- a/src/main/kotlin/ua/mei/minekord/config/MinekordConfig.kt +++ b/src/main/kotlin/ua/mei/minekord/config/MinekordConfig.kt @@ -13,17 +13,9 @@ import net.fabricmc.loader.api.FabricLoader import net.kyori.adventure.text.format.TextColor import net.minecraft.text.Text import ua.mei.minekord.Minekord -import ua.mei.minekord.config.spec.AuthSpec -import ua.mei.minekord.config.spec.ChatSpec -import ua.mei.minekord.config.spec.ColorsSpec -import ua.mei.minekord.config.spec.CommandsSpec -import ua.mei.minekord.config.spec.LuckPermsSpec -import ua.mei.minekord.config.spec.MainSpec -import ua.mei.minekord.config.spec.MessagesSpec -import ua.mei.minekord.config.spec.PresenceSpec +import ua.mei.minekord.config.spec.* import ua.mei.minekord.utils.MinekordActivityType import ua.mei.minekord.utils.toColor - import java.util.function.Function as JavaFunction object MinekordConfig { diff --git a/src/main/kotlin/ua/mei/minekord/utils/AuthUtils.kt b/src/main/kotlin/ua/mei/minekord/utils/AuthUtils.kt index cbaef5b..15a1e4f 100644 --- a/src/main/kotlin/ua/mei/minekord/utils/AuthUtils.kt +++ b/src/main/kotlin/ua/mei/minekord/utils/AuthUtils.kt @@ -5,7 +5,7 @@ import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.runBlocking import ua.mei.minekord.bot.MinekordBot import ua.mei.minekord.config.MinekordConfig -import java.util.UUID +import java.util.* object AuthUtils { fun findMember(name: String): Member? { diff --git a/src/main/kotlin/ua/mei/minekord/utils/Extensions.kt b/src/main/kotlin/ua/mei/minekord/utils/Extensions.kt index 900f680..f7e473b 100644 --- a/src/main/kotlin/ua/mei/minekord/utils/Extensions.kt +++ b/src/main/kotlin/ua/mei/minekord/utils/Extensions.kt @@ -16,8 +16,7 @@ import net.minecraft.text.MutableText import net.minecraft.text.Text import ua.mei.minekord.config.MinekordConfig import ua.mei.minekord.config.MinekordConfig.Chat -import java.util.Base64 - +import java.util.* import java.util.function.Function as JavaFunction fun String.literal(): MutableText = Text.literal(this) diff --git a/src/main/kotlin/ua/mei/minekord/utils/SerializerUtils.kt b/src/main/kotlin/ua/mei/minekord/utils/SerializerUtils.kt index 0bfa32d..f5f5eed 100644 --- a/src/main/kotlin/ua/mei/minekord/utils/SerializerUtils.kt +++ b/src/main/kotlin/ua/mei/minekord/utils/SerializerUtils.kt @@ -6,7 +6,7 @@ import net.kyori.adventure.text.Component import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer import net.kyori.adventure.translation.GlobalTranslator import ua.mei.minekord.bot.MinekordBot -import java.util.Locale +import java.util.* object SerializerUtils { val pingRegex: Regex = Regex("@(\\S{1,32})") diff --git a/src/main/resources/minekord.accesswidener b/src/main/resources/minekord.accesswidener index cfd618b..34bf988 100644 --- a/src/main/resources/minekord.accesswidener +++ b/src/main/resources/minekord.accesswidener @@ -1,3 +1,7 @@ accessWidener v2 named -accessible class net/minecraft/server/network/ServerLoginNetworkHandler$State \ No newline at end of file +accessible class net/minecraft/server/network/ServerLoginNetworkHandler$State + +accessible field net/minecraft/util/UserCache byName Ljava/util/Map; + +accessible class net/minecraft/util/UserCache$Entry \ No newline at end of file