Skip to content

Commit 8d07727

Browse files
committed
generating uuid based on discord user id
1 parent adc6c00 commit 8d07727

File tree

9 files changed

+129
-7
lines changed

9 files changed

+129
-7
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package ua.mei.minekord.mixin;
2+
3+
import com.mojang.authlib.GameProfile;
4+
import net.minecraft.network.ClientConnection;
5+
import net.minecraft.network.packet.c2s.login.LoginHelloC2SPacket;
6+
import net.minecraft.network.packet.s2c.login.LoginHelloS2CPacket;
7+
import net.minecraft.network.packet.s2c.login.LoginSuccessS2CPacket;
8+
import net.minecraft.server.MinecraftServer;
9+
import net.minecraft.server.network.ServerLoginNetworkHandler;
10+
import net.minecraft.text.Text;
11+
import org.jetbrains.annotations.Nullable;
12+
import org.spongepowered.asm.mixin.Final;
13+
import org.spongepowered.asm.mixin.Mixin;
14+
import org.spongepowered.asm.mixin.Shadow;
15+
import org.spongepowered.asm.mixin.injection.At;
16+
import org.spongepowered.asm.mixin.injection.Inject;
17+
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
18+
import ua.mei.minekord.auth.SnowflakeToUUID;
19+
20+
import java.util.UUID;
21+
22+
@Mixin(ServerLoginNetworkHandler.class)
23+
public abstract class ServerLoginNetworkHandlerMixin {
24+
@Shadow public abstract void disconnect(Text text);
25+
26+
@Shadow @Nullable private GameProfile profile;
27+
28+
@Shadow protected abstract void sendSuccessPacket(GameProfile gameProfile);
29+
30+
@Inject(method = "onHello", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;isOnlineMode()Z"), cancellable = true)
31+
private void minekord$trueUuids(LoginHelloC2SPacket loginHelloC2SPacket, CallbackInfo ci) {
32+
if (SnowflakeToUUID.INSTANCE.enabled()) {
33+
UUID trueUuid = SnowflakeToUUID.INSTANCE.generateFromNickname(loginHelloC2SPacket.comp_765());
34+
35+
if (trueUuid != null) {
36+
this.profile = new GameProfile(trueUuid, loginHelloC2SPacket.comp_765());
37+
sendSuccessPacket(this.profile);
38+
} else {
39+
this.disconnect(Text.literal("lol"));
40+
}
41+
42+
ci.cancel();
43+
}
44+
}
45+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package ua.mei.minekord.auth
2+
3+
import dev.kord.common.annotation.KordExperimental
4+
import dev.kord.core.entity.Member
5+
import kotlinx.coroutines.flow.filter
6+
import kotlinx.coroutines.flow.firstOrNull
7+
import kotlinx.coroutines.runBlocking
8+
import ua.mei.minekord.bot.MinekordBot
9+
import ua.mei.minekord.config.AuthSpec
10+
import ua.mei.minekord.config.config
11+
import java.util.UUID
12+
13+
object SnowflakeToUUID {
14+
fun enabled(): Boolean = config[AuthSpec.uuidFromSnowflake]
15+
16+
@OptIn(KordExperimental::class)
17+
fun generateFromNickname(nickname: String): UUID? {
18+
return runBlocking {
19+
return@runBlocking try {
20+
val member: Member = MinekordBot.guild?.getMembers(nickname)?.filter {
21+
it.roleIds.map { it.value }.all { it in config[AuthSpec.requiredRoles] }
22+
}?.firstOrNull() ?: return@runBlocking null
23+
24+
generateFromId(member.id.value)
25+
} catch (_: Throwable) {
26+
null
27+
}
28+
}
29+
}
30+
31+
fun generateFromId(discordId: ULong): UUID {
32+
val mostSigBytes: ByteArray = ByteArray(8) { i -> (discordId shr ((7 - i) * 8) and 0xFFu).toByte() }
33+
val leastSigBytes: ByteArray = ByteArray(8) { i -> ((ULong.MAX_VALUE - discordId) shr ((7 - i) * 8) and 0xFFu).toByte() }
34+
35+
val mostSigBits: Long = mostSigBytes.fold(0L) { acc, byte -> (acc shl 8) or (byte.toLong() and 0xFF) }
36+
val leastSigBits: Long = leastSigBytes.fold(0L) { acc, byte -> (acc shl 8) or (byte.toLong() and 0xFF) }
37+
38+
return UUID(mostSigBits, leastSigBits)
39+
}
40+
}
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
11
package ua.mei.minekord.bot
22

3+
import dev.kord.core.entity.Guild
34
import dev.kordex.core.ExtensibleBot
45
import kotlinx.coroutines.CoroutineScope
56
import kotlinx.coroutines.Dispatchers
67
import kotlinx.coroutines.launch
78
import ua.mei.minekord.config.BotSpec
89
import ua.mei.minekord.config.config
10+
import ua.mei.minekord.extensions.StartupExtension
911
import kotlin.coroutines.CoroutineContext
1012

1113
object MinekordBot : CoroutineScope {
1214
lateinit var bot: ExtensibleBot
1315

16+
var guild: Guild? = null
17+
1418
fun launchBot() {
1519
launch {
1620
bot = ExtensibleBot(config[BotSpec.token]) {
17-
members {
18-
fill(config[BotSpec.guild])
21+
extensions {
22+
add(::StartupExtension)
1923
}
2024
}
2125

@@ -24,4 +28,4 @@ object MinekordBot : CoroutineScope {
2428
}
2529

2630
override val coroutineContext: CoroutineContext = Dispatchers.Default
27-
}
31+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package ua.mei.minekord.config
2+
3+
import com.uchuhimo.konf.ConfigSpec
4+
5+
object AuthSpec : ConfigSpec() {
6+
val uuidFromSnowflake by required<Boolean>()
7+
val requiredRoles by required<List<ULong>>()
8+
}

src/main/kotlin/ua/mei/minekord/config/BotSpec.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ object BotSpec : ConfigSpec() {
66
val token by required<String>()
77
val guild by required<ULong>()
88
val chat by required<ULong>()
9-
}
9+
}

src/main/kotlin/ua/mei/minekord/config/MinekordConfig.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@ import net.fabricmc.loader.api.FabricLoader
66

77
const val CONFIG_PATH: String = "minekord.toml"
88

9-
val config: Config = Config { addSpec(BotSpec) }
9+
val config: Config = Config { addSpec(BotSpec); addSpec(AuthSpec) }
1010
.from.toml.resource(CONFIG_PATH)
1111
.from.toml.watchFile(FabricLoader.getInstance().configDir.resolve(CONFIG_PATH).toFile())
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package ua.mei.minekord.extensions
2+
3+
import dev.kord.common.entity.Snowflake
4+
import dev.kordex.core.extensions.Extension
5+
import ua.mei.minekord.bot.MinekordBot
6+
import ua.mei.minekord.config.BotSpec
7+
import ua.mei.minekord.config.config
8+
9+
class StartupExtension : Extension() {
10+
override val name: String = "Startup"
11+
12+
override suspend fun setup() {
13+
MinekordBot.guild = kord.getGuildOrNull(Snowflake(config[BotSpec.guild]))
14+
}
15+
}

src/main/resources/minekord.mixins.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44
"package": "ua.mei.minekord.mixin",
55
"compatibilityLevel": "JAVA_21",
66
"mixins": [
7-
],
8-
"client": [
7+
"ServerLoginNetworkHandlerMixin"
98
],
109
"injectors": {
1110
"defaultRequire": 1

src/main/resources/minekord.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,14 @@
33
token = ""
44
guild = 0
55
chat = 0
6+
7+
[Auth]
8+
9+
# If true, player UUID will be generated by they Discord ID.
10+
# If user doens't exists in guild with player nickname, player will be kicked.
11+
# Works with offline and online mode.
12+
uuidFromSnowflake = false
13+
14+
# Roles which required for server join.
15+
# Can be empty.
16+
requiredRoles = []

0 commit comments

Comments
 (0)