diff --git a/.gitignore b/.gitignore index e4906fd..b8a88a0 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ build/ .idea/jarRepositories.xml .idea/compiler.xml .idea/libraries/ +.idea *.iws *.iml *.ipr diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d3352..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/compiler.xml b/.idea/compiler.xml deleted file mode 100644 index 73a50c8..0000000 --- a/.idea/compiler.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/copilot.data.migration.agent.xml b/.idea/copilot.data.migration.agent.xml deleted file mode 100644 index 4ea72a9..0000000 --- a/.idea/copilot.data.migration.agent.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/copilot.data.migration.ask2agent.xml b/.idea/copilot.data.migration.ask2agent.xml deleted file mode 100644 index 1f2ea11..0000000 --- a/.idea/copilot.data.migration.ask2agent.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/copilot.data.migration.edit.xml b/.idea/copilot.data.migration.edit.xml deleted file mode 100644 index 8648f94..0000000 --- a/.idea/copilot.data.migration.edit.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/discord.xml b/.idea/discord.xml deleted file mode 100644 index 912db82..0000000 --- a/.idea/discord.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml deleted file mode 100644 index 097aafa..0000000 --- a/.idea/gradle.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml deleted file mode 100644 index 739bc36..0000000 --- a/.idea/kotlinc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/material_theme_project_new.xml b/.idea/material_theme_project_new.xml deleted file mode 100644 index 5adc677..0000000 --- a/.idea/material_theme_project_new.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index ad18843..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/.idea/modules/surf-friends-api/surf-friends.surf-friends-api.main.iml b/.idea/modules/surf-friends-api/surf-friends.surf-friends-api.main.iml deleted file mode 100644 index a376b96..0000000 --- a/.idea/modules/surf-friends-api/surf-friends.surf-friends-api.main.iml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - ADVENTURE - - 1 - - - - \ No newline at end of file diff --git a/.idea/modules/surf-friends-core/surf-friends.surf-friends-core.main.iml b/.idea/modules/surf-friends-core/surf-friends.surf-friends-core.main.iml deleted file mode 100644 index a376b96..0000000 --- a/.idea/modules/surf-friends-core/surf-friends.surf-friends-core.main.iml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - ADVENTURE - - 1 - - - - \ No newline at end of file diff --git a/.idea/modules/surf-friends-fallback/surf-friends.surf-friends-fallback.main.iml b/.idea/modules/surf-friends-fallback/surf-friends.surf-friends-fallback.main.iml deleted file mode 100644 index a376b96..0000000 --- a/.idea/modules/surf-friends-fallback/surf-friends.surf-friends-fallback.main.iml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - ADVENTURE - - 1 - - - - \ No newline at end of file diff --git a/.idea/modules/surf-friends-velocity/surf-friends.surf-friends-velocity.main.iml b/.idea/modules/surf-friends-velocity/surf-friends.surf-friends-velocity.main.iml deleted file mode 100644 index a587e97..0000000 --- a/.idea/modules/surf-friends-velocity/surf-friends.surf-friends-velocity.main.iml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - VELOCITY - ADVENTURE - - 1 - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 7ddfc9e..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index d446010..da641c4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ kotlin.code.style=official kotlin.stdlib.default.dependency=false org.gradle.parallel=true -version=1.21.11-2.0.2-SNAPSHOT +version=1.21.11-3.0.0-SNAPSHOT diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml deleted file mode 100644 index ad6aa21..0000000 --- a/gradle/libs.versions.toml +++ /dev/null @@ -1,5 +0,0 @@ -[versions] -surf-database = "2.0.4-SNAPSHOT" - -[libraries] -surf-database = { module = "dev.slne.surf:surf-database", version.ref = "surf-database" } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f670658..103a61b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -4,4 +4,4 @@ distributionUrl=https\://services.gradle.org/distributions-snapshots/gradle-9.4. networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists +zipStorePath=wrapper/dists \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index fdf475a..e376460 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -3,5 +3,5 @@ plugins { } include("surf-friends-api") include("surf-friends-core") -include("surf-friends-velocity") -include("surf-friends-fallback") +include("surf-friends-backend") +include("surf-friends-paper") \ No newline at end of file diff --git a/surf-friends-api/build.gradle.kts b/surf-friends-api/build.gradle.kts index 749ef8e..2cf8a7e 100644 --- a/surf-friends-api/build.gradle.kts +++ b/surf-friends-api/build.gradle.kts @@ -1,3 +1,7 @@ plugins { - id("dev.slne.surf.surfapi.gradle.core") + id("dev.slne.surf.surfapi.gradle.paper-raw") +} + +surfRawPaperApi { + withCorePaper() } \ No newline at end of file diff --git a/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/SurfFriendsApi.kt b/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/SurfFriendsApi.kt index 8457622..14dcc37 100644 --- a/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/SurfFriendsApi.kt +++ b/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/SurfFriendsApi.kt @@ -1,107 +1,9 @@ package dev.slne.surf.friends.api -import dev.slne.surf.friends.api.model.FriendRequest -import dev.slne.surf.friends.api.model.Friendship -import it.unimi.dsi.fastutil.objects.ObjectSet -import java.util.UUID +import dev.slne.surf.surfapi.core.api.util.requiredService -interface SurfFriendsApi { - /** - * Creates a friendship between two users. - * - * @param uuid The UUID of the first user. - * @param friend The UUID of the friend. - * @return The created Friendship object. - */ - suspend fun createFriendship(uuid: UUID, friend: UUID): Friendship - - /** - * Removes a friendship between two users. - * - * @param uuid The UUID of the first user. - * @param friend The UUID of the friend. - */ - suspend fun removeFriendship(uuid: UUID, friend: UUID) - - /** - * Retrieves all friendships of a user. - * - * @param uuid The UUID of the user. - * @return A set of Friendships representing the user's friends. - */ - suspend fun getFriendships(uuid: UUID): ObjectSet - - /** - * Sends a friend request from one user to another. - * - * @param sender The UUID of the sender. - * @param receiver The UUID of the receiver. - * @return The created FriendRequest object. - */ - suspend fun sendFriendRequest(sender: UUID, receiver: UUID): FriendRequest - - /** - * Accepts a friend request. - * - * @param sender The UUID of the sender of the request. - * @param receiver The UUID of the receiver of the request. - */ - suspend fun acceptFriendRequest(sender: UUID, receiver: UUID) - - /** - * Declines a friend request. - * - * @param sender The UUID of the sender of the request. - * @param receiver The UUID of the receiver of the request. - */ - suspend fun declineFriendRequest(sender: UUID, receiver: UUID) +val surfFriendsApi = requiredService() - /** - * Revokes a sent friend request. - * - * @param sender The UUID of the sender of the request. - * @param receiver The UUID of the receiver of the request. - */ - suspend fun revokeFriendRequest(sender: UUID, receiver: UUID) - - /** - * Retrieves all sent friend requests of a user. - * - * @param uuid The UUID of the user. - * @return A set of FriendRequests representing the recipients of the sent requests. - */ - suspend fun getSentFriendRequests(uuid: UUID): ObjectSet - - /** - * Retrieves all received friend requests of a user. - * - * @param uuid The UUID of the user. - * @return A set of FriendRequests representing the senders of the received requests. - */ - suspend fun getReceivedFriendRequests(uuid: UUID): ObjectSet - - /** - * Toggles announcements for a user. - * - * @param uuid The UUID of the user. - * @return The new status of announcements (true if enabled, false if disabled). - */ - suspend fun toggleAnnouncements(uuid: UUID): Boolean - - /** - * Toggles sounds for a user. - * - * @param uuid The UUID of the user. - * @return The new status of sounds (true if enabled, false if disabled). - */ - suspend fun toggleSounds(uuid: UUID): Boolean +interface SurfFriendsApi { - /** - * Checks if two users are friends and retrieves their friendship details. - * - * @param uuid The UUID of the first user. - * @param friend The UUID of the second user. - * @return The Friendship object representing the friendship between the two users, or null if they are not friends. - */ - suspend fun areFriends(uuid: UUID, friend: UUID): Friendship? } \ No newline at end of file diff --git a/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/friend/FriendRequest.kt b/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/friend/FriendRequest.kt new file mode 100644 index 0000000..1e3d610 --- /dev/null +++ b/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/friend/FriendRequest.kt @@ -0,0 +1,26 @@ +package dev.slne.surf.friends.api.friend + +import dev.slne.surf.surfapi.core.api.serializer.java.datetime.datetime.offset.SerializableOffsetDateTime +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import java.time.OffsetDateTime +import java.util.* + + +fun friendRequest( + senderUuid: UUID, + receiverUuid: UUID, + senderName: String, + receiverName: String +) = FriendRequest(senderUuid, receiverUuid, senderName, receiverName, OffsetDateTime.now()) + +@Serializable +data class FriendRequest( + val senderUuid: @Contextual UUID, + val receiverUuid: @Contextual UUID, + + val senderName: String, + val receiverName: String, + + val sentAt: SerializableOffsetDateTime +) \ No newline at end of file diff --git a/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/friend/Friendship.kt b/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/friend/Friendship.kt new file mode 100644 index 0000000..80d9b71 --- /dev/null +++ b/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/friend/Friendship.kt @@ -0,0 +1,35 @@ +package dev.slne.surf.friends.api.friend + +import dev.slne.surf.surfapi.core.api.serializer.java.datetime.datetime.offset.SerializableOffsetDateTime +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import java.time.OffsetDateTime +import java.util.* + +fun friendship( + requestedBy: UUID, + acceptedBy: UUID, + + requesterName: String, + acceptorName: String, +) = Friendship( + requestedBy = requestedBy, + acceptedBy = acceptedBy, + requesterName = requesterName, + acceptorName = acceptorName, + createdAt = OffsetDateTime.now() +) + +@Serializable +data class Friendship( + val requestedBy: @Contextual UUID, + val acceptedBy: @Contextual UUID, + + val requesterName: String, + val acceptorName: String, + + val createdAt: SerializableOffsetDateTime +) { + fun getOtherName(ownUuid: UUID) = if (requestedBy == ownUuid) acceptorName else requesterName + fun getOtherUuid(ownUuid: UUID) = if (requestedBy == ownUuid) acceptedBy else requestedBy +} \ No newline at end of file diff --git a/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/model/FriendRequest.kt b/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/model/FriendRequest.kt deleted file mode 100644 index a402b12..0000000 --- a/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/model/FriendRequest.kt +++ /dev/null @@ -1,23 +0,0 @@ -package dev.slne.surf.friends.api.model - -import java.util.UUID - -/** - * Represents a friend request between two users. - */ -interface FriendRequest { - /** - * The UUID of the user who sent the friend request. - */ - val senderUuid: UUID - - /** - * The UUID of the user who received the friend request. - */ - val receiverUuid: UUID - - /** - * The timestamp (in milliseconds since epoch) when the friend request was sent. - */ - val sentAt: Long -} \ No newline at end of file diff --git a/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/model/Friendship.kt b/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/model/Friendship.kt deleted file mode 100644 index 3c54e1e..0000000 --- a/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/model/Friendship.kt +++ /dev/null @@ -1,23 +0,0 @@ -package dev.slne.surf.friends.api.model - -import java.util.UUID - -/** - * Represents a friendship between two users. - */ -interface Friendship { - /** - * The UUID of the user who is part of the friendship. - */ - val userUuid: UUID - - /** - * The UUID of the friend in the friendship. - */ - val friendUuid: UUID - - /** - * The timestamp (in milliseconds since epoch) when the friendship was created. - */ - val createdAt: Long -} \ No newline at end of file diff --git a/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/player/FriendPlayer.kt b/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/player/FriendPlayer.kt new file mode 100644 index 0000000..e22452b --- /dev/null +++ b/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/player/FriendPlayer.kt @@ -0,0 +1,29 @@ +package dev.slne.surf.friends.api.player + +import dev.slne.surf.core.api.common.surfCoreApi +import dev.slne.surf.friends.api.friend.FriendRequest +import dev.slne.surf.friends.api.friend.Friendship +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import java.util.* + +@Serializable +data class FriendPlayer( + val uuid: @Contextual UUID, + val name: String, + val texture: String, + + val friends: Set, + val sentFriendRequests: Set, + val receivedFriendRequests: Set +) { + fun hasFriend(uuid: UUID) = + friends.any { it.acceptedBy == uuid } || friends.any { it.requestedBy == uuid } + + fun hasSentFriendRequest(uuid: UUID) = sentFriendRequests.any { it.receiverUuid == uuid } + fun hasReceivedFriendRequest(uuid: UUID) = receivedFriendRequests.any { it.senderUuid == uuid } + + fun getOnlineFriendCount() = friends.count { ship -> + surfCoreApi.getOnlinePlayers().any { it.uuid == ship.getOtherUuid(uuid) } + } +} diff --git a/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/util/FriendSettings.kt b/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/util/FriendSettings.kt deleted file mode 100644 index 2cfe6cd..0000000 --- a/surf-friends-api/src/main/kotlin/dev/slne/surf/friends/api/util/FriendSettings.kt +++ /dev/null @@ -1,8 +0,0 @@ -package dev.slne.surf.friends.api.util - -interface FriendSettings { - var announcementsEnabled: Boolean - var soundsEnabled: Boolean - - fun modify(block: FriendSettings.() -> Unit): FriendSettings -} \ No newline at end of file diff --git a/surf-friends-backend/build.gradle.kts b/surf-friends-backend/build.gradle.kts new file mode 100644 index 0000000..ef4f336 --- /dev/null +++ b/surf-friends-backend/build.gradle.kts @@ -0,0 +1,12 @@ +plugins { + id("dev.slne.surf.surfapi.gradle.paper-raw") +} + +dependencies { + api(project(":surf-friends-core")) +} + +surfRawPaperApi { + withSurfDatabaseR2dbc("1.3.0", "dev.slne.surf.friends.libs") + withSurfRedis() +} \ No newline at end of file diff --git a/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/DatabaseLoaderImpl.kt b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/DatabaseLoaderImpl.kt new file mode 100644 index 0000000..193127b --- /dev/null +++ b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/DatabaseLoaderImpl.kt @@ -0,0 +1,32 @@ +package dev.slne.surf.friends.backend + +import com.google.auto.service.AutoService +import dev.slne.surf.database.DatabaseApi +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.r2dbc.SchemaUtils +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.r2dbc.transactions.suspendTransaction +import dev.slne.surf.friends.backend.table.FriendPlayerTable +import dev.slne.surf.friends.backend.table.FriendRequestsTable +import dev.slne.surf.friends.backend.table.FriendShipsTable +import dev.slne.surf.friends.core.loader.DatabaseLoader +import net.kyori.adventure.util.Services +import java.nio.file.Path + +@AutoService(DatabaseLoader::class) +class DatabaseLoaderImpl : DatabaseLoader, Services.Fallback { + lateinit var databaseApi: DatabaseApi + override suspend fun connect(dataPath: Path) { + databaseApi = DatabaseApi.create(dataPath) + + suspendTransaction { + SchemaUtils.create( + FriendPlayerTable, + FriendRequestsTable, + FriendShipsTable + ) + } + } + + override fun disconnect() { + databaseApi.shutdown() + } +} \ No newline at end of file diff --git a/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/repository/FriendPlayerRepository.kt b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/repository/FriendPlayerRepository.kt new file mode 100644 index 0000000..e0b88cc --- /dev/null +++ b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/repository/FriendPlayerRepository.kt @@ -0,0 +1,101 @@ +package dev.slne.surf.friends.backend.repository + +import com.destroystokyo.paper.profile.PlayerProfile +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.core.ResultRow +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.core.eq +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.r2dbc.insert +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.r2dbc.selectAll +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.r2dbc.transactions.suspendTransaction +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.r2dbc.upsert +import dev.slne.surf.friends.api.friend.FriendRequest +import dev.slne.surf.friends.api.friend.Friendship +import dev.slne.surf.friends.api.player.FriendPlayer +import dev.slne.surf.friends.backend.table.FriendPlayerTable +import dev.slne.surf.surfapi.bukkit.api.command.util.idOrThrow +import it.unimi.dsi.fastutil.objects.ObjectSet +import kotlinx.coroutines.flow.firstOrNull +import java.util.* + +val friendPlayerRepository = FriendPlayerRepository() + +class FriendPlayerRepository { + suspend fun loadOrCreatePlayer(profile: PlayerProfile) = suspendTransaction { + val uuid = profile.idOrThrow() + val row = + FriendPlayerTable.selectAll().where(FriendPlayerTable.playerUuid eq uuid).firstOrNull() + + if (row == null) { + FriendPlayerTable.insert { + it[playerUuid] = uuid + it[playerName] = profile.name ?: error("Profile name is null for uuid $uuid") + it[texture] = + profile.properties.find { property -> property.name == "textures" }?.value + ?: "" + } + + createPlayer( + row = FriendPlayerTable.selectAll().where(FriendPlayerTable.playerUuid eq uuid) + .firstOrNull() ?: error("Failed to load created player with uuid $uuid"), + sentRequests = friendRequestRepository.loadSentRequests(uuid), + receivedRequests = friendRequestRepository.loadReceivedRequests(uuid), + friendShips = friendShipRepository.loadFriendShips(uuid) + ) + } else { + createPlayer( + row = row, + sentRequests = friendRequestRepository.loadSentRequests(uuid), + receivedRequests = friendRequestRepository.loadReceivedRequests(uuid), + friendShips = friendShipRepository.loadFriendShips(uuid) + ) + } + } + + suspend fun loadPlayer(name: String) = suspendTransaction { + FriendPlayerTable.selectAll().where(FriendPlayerTable.playerName eq name).firstOrNull() + ?.let { + val uuid = it[FriendPlayerTable.playerUuid] + + createPlayer( + row = it, + sentRequests = friendRequestRepository.loadSentRequests(uuid), + receivedRequests = friendRequestRepository.loadReceivedRequests(uuid), + friendShips = friendShipRepository.loadFriendShips(uuid) + ) + } + } + + suspend fun loadPlayer(uuid: UUID) = suspendTransaction { + FriendPlayerTable.selectAll().where(FriendPlayerTable.playerUuid eq uuid).firstOrNull() + ?.let { + createPlayer( + row = it, + sentRequests = friendRequestRepository.loadSentRequests(uuid), + receivedRequests = friendRequestRepository.loadReceivedRequests(uuid), + friendShips = friendShipRepository.loadFriendShips(uuid) + ) + } + } + + suspend fun savePlayer(player: FriendPlayer) = suspendTransaction { + FriendPlayerTable.upsert { + it[playerUuid] = player.uuid + it[playerName] = player.name + it[texture] = player.texture + } + } + + private fun createPlayer( + row: ResultRow, + sentRequests: ObjectSet, + receivedRequests: ObjectSet, + friendShips: ObjectSet + ) = + FriendPlayer( + uuid = row[FriendPlayerTable.playerUuid], + name = row[FriendPlayerTable.playerName], + texture = row[FriendPlayerTable.texture], + sentFriendRequests = sentRequests, + receivedFriendRequests = receivedRequests, + friends = friendShips + ) +} \ No newline at end of file diff --git a/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/repository/FriendRequestRepository.kt b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/repository/FriendRequestRepository.kt new file mode 100644 index 0000000..35c5f45 --- /dev/null +++ b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/repository/FriendRequestRepository.kt @@ -0,0 +1,54 @@ +package dev.slne.surf.friends.backend.repository + +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.core.ResultRow +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.core.and +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.core.eq +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.r2dbc.deleteWhere +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.r2dbc.insert +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.r2dbc.selectAll +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.r2dbc.transactions.suspendTransaction +import dev.slne.surf.friends.api.friend.FriendRequest +import dev.slne.surf.friends.backend.table.FriendRequestsTable +import dev.slne.surf.surfapi.core.api.util.toObjectSet +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.toSet +import java.util.* + +val friendRequestRepository = FriendRequestRepository() + +class FriendRequestRepository { + suspend fun loadSentRequests(uuid: UUID) = suspendTransaction { + FriendRequestsTable.selectAll().where(FriendRequestsTable.senderUuid eq uuid) + .map { createRequest(it) } + }.toSet().toObjectSet() + + suspend fun loadReceivedRequests(uuid: UUID) = suspendTransaction { + FriendRequestsTable.selectAll().where(FriendRequestsTable.receiverUuid eq uuid) + .map { createRequest(it) } + }.toSet().toObjectSet() + + suspend fun deleteRequest(request: FriendRequest) = suspendTransaction { + FriendRequestsTable.deleteWhere { + (FriendRequestsTable.senderUuid eq request.senderUuid) and + (FriendRequestsTable.receiverUuid eq request.receiverUuid) + } + } + + suspend fun saveRequest(request: FriendRequest) = suspendTransaction { + FriendRequestsTable.insert { + it[senderUuid] = request.senderUuid + it[receiverUuid] = request.receiverUuid + it[senderName] = request.senderName + it[receiverName] = request.receiverName + it[createdAt] = request.sentAt + } + } + + private fun createRequest(row: ResultRow) = FriendRequest( + senderUuid = row[FriendRequestsTable.senderUuid], + receiverUuid = row[FriendRequestsTable.receiverUuid], + senderName = row[FriendRequestsTable.senderName], + receiverName = row[FriendRequestsTable.receiverName], + sentAt = row[FriendRequestsTable.createdAt] + ) +} \ No newline at end of file diff --git a/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/repository/FriendShipRepository.kt b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/repository/FriendShipRepository.kt new file mode 100644 index 0000000..fe537bb --- /dev/null +++ b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/repository/FriendShipRepository.kt @@ -0,0 +1,51 @@ +package dev.slne.surf.friends.backend.repository + +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.core.ResultRow +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.core.and +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.core.eq +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.core.or +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.r2dbc.deleteWhere +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.r2dbc.insert +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.r2dbc.selectAll +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.r2dbc.transactions.suspendTransaction +import dev.slne.surf.friends.api.friend.Friendship +import dev.slne.surf.friends.backend.table.FriendShipsTable +import dev.slne.surf.surfapi.core.api.util.toObjectSet +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.toSet +import java.util.* + +val friendShipRepository = FriendShipRepository() + +class FriendShipRepository { + suspend fun loadFriendShips(uuid: UUID) = suspendTransaction { + FriendShipsTable.selectAll().where { + (FriendShipsTable.requesterUuid eq uuid) or (FriendShipsTable.acceptorUuid eq uuid) + }.map { createFriendShip(it) } + }.toSet().toObjectSet() + + suspend fun saveFriendship(friendship: Friendship) = suspendTransaction { + FriendShipsTable.insert { + it[requesterUuid] = friendship.requestedBy + it[acceptorUuid] = friendship.acceptedBy + it[requesterName] = friendship.requesterName + it[acceptorName] = friendship.acceptorName + it[createdAt] = friendship.createdAt + } + } + + suspend fun deleteFriendship(friendship: Friendship) = suspendTransaction { + FriendShipsTable.deleteWhere { + (FriendShipsTable.requesterUuid eq friendship.requestedBy) and + (FriendShipsTable.acceptorUuid eq friendship.acceptedBy) + } + } + + private fun createFriendShip(row: ResultRow) = Friendship( + requestedBy = row[FriendShipsTable.requesterUuid], + acceptedBy = row[FriendShipsTable.acceptorUuid], + requesterName = row[FriendShipsTable.requesterName], + acceptorName = row[FriendShipsTable.acceptorName], + createdAt = row[FriendShipsTable.createdAt] + ) +} \ No newline at end of file diff --git a/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/service/FriendPlayerServiceImpl.kt b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/service/FriendPlayerServiceImpl.kt new file mode 100644 index 0000000..e65ab01 --- /dev/null +++ b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/service/FriendPlayerServiceImpl.kt @@ -0,0 +1,65 @@ +package dev.slne.surf.friends.backend.service + +import com.destroystokyo.paper.profile.PlayerProfile +import com.google.auto.service.AutoService +import dev.slne.surf.friends.api.player.FriendPlayer +import dev.slne.surf.friends.backend.repository.friendPlayerRepository +import dev.slne.surf.friends.core.loader.redisLoader +import dev.slne.surf.friends.core.service.FriendPlayerService +import dev.slne.surf.surfapi.bukkit.api.command.util.idOrThrow +import dev.slne.surf.surfapi.core.api.util.toObjectSet +import it.unimi.dsi.fastutil.objects.ObjectSet +import net.kyori.adventure.util.Services +import java.util.* + +@AutoService(FriendPlayerService::class) +class FriendPlayerServiceImpl : FriendPlayerService, Services.Fallback { + override val players: ObjectSet + get() = redisLoader.playerCache.snapshot().values.toObjectSet() + + override fun cachePlayer(friendPlayer: FriendPlayer) { + redisLoader.playerCache.put(friendPlayer.uuid, friendPlayer) + } + + override fun invalidatePlayer(uuid: UUID) { + redisLoader.playerCache.remove(uuid) + } + + override suspend fun loadOrCreatePlayer(profile: PlayerProfile): FriendPlayer { + val cachedPlayer = players.firstOrNull { it.uuid == profile.idOrThrow() } + if (cachedPlayer != null) { + return cachedPlayer + } + + val loadedPlayer = friendPlayerRepository.loadOrCreatePlayer(profile) + cachePlayer(loadedPlayer) + return loadedPlayer + } + + override suspend fun findOrLoadPlayer(name: String): FriendPlayer? { + val cachedPlayer = players.find { it.name == name } + if (cachedPlayer != null) { + return cachedPlayer + } + + val loadedPlayer = friendPlayerRepository.loadPlayer(name) + + loadedPlayer?.let { cachePlayer(it) } + return loadedPlayer + } + + override suspend fun findOrLoadPlayer(uuid: UUID): FriendPlayer? { + val cachedPlayer = players.firstOrNull { it.uuid == uuid } + if (cachedPlayer != null) { + return cachedPlayer + } + + val loadedPlayer = friendPlayerRepository.loadPlayer(uuid) + loadedPlayer?.let { cachePlayer(it) } + return loadedPlayer + } + + override suspend fun savePlayer(friendPlayer: FriendPlayer) { + friendPlayerRepository.savePlayer(friendPlayer) + } +} \ No newline at end of file diff --git a/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/service/FriendRequestServiceImpl.kt b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/service/FriendRequestServiceImpl.kt new file mode 100644 index 0000000..2c722e4 --- /dev/null +++ b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/service/FriendRequestServiceImpl.kt @@ -0,0 +1,64 @@ +package dev.slne.surf.friends.backend.service + +import com.google.auto.service.AutoService +import dev.slne.surf.friends.api.friend.FriendRequest +import dev.slne.surf.friends.backend.repository.friendRequestRepository +import dev.slne.surf.friends.core.service.FriendRequestService +import dev.slne.surf.friends.core.service.friendPlayerService +import dev.slne.surf.surfapi.core.api.util.toObjectSet +import net.kyori.adventure.util.Services + +@AutoService(FriendRequestService::class) +class FriendRequestServiceImpl : FriendRequestService, Services.Fallback { + override suspend fun saveFriendRequest(friendRequest: FriendRequest) { + friendRequestRepository.saveRequest(friendRequest) + + val sender = friendPlayerService.players + .firstOrNull { it.uuid == friendRequest.senderUuid } + + if (sender != null) { + val updatedSender = sender.copy( + sentFriendRequests = (sender.sentFriendRequests + friendRequest).toObjectSet() + ) + friendPlayerService.cachePlayer(updatedSender) + } + + val receiver = friendPlayerService.players + .firstOrNull { it.uuid == friendRequest.receiverUuid } + + if (receiver != null) { + val updatedReceiver = receiver.copy( + receivedFriendRequests = (receiver.receivedFriendRequests + friendRequest).toObjectSet() + ) + friendPlayerService.cachePlayer(updatedReceiver) + } + } + + override suspend fun deleteFriendRequest(friendRequest: FriendRequest) { + friendRequestRepository.deleteRequest(friendRequest) + + val sender = friendPlayerService.players + .firstOrNull { it.uuid == friendRequest.senderUuid } + + if (sender != null) { + val updatedSender = sender.copy( + sentFriendRequests = sender.sentFriendRequests + .filterNot { it == friendRequest } + .toObjectSet() + ) + friendPlayerService.cachePlayer(updatedSender) + } + + val receiver = friendPlayerService.players + .firstOrNull { it.uuid == friendRequest.receiverUuid } + + if (receiver != null) { + val updatedReceiver = receiver.copy( + receivedFriendRequests = receiver.receivedFriendRequests + .filterNot { it == friendRequest } + .toObjectSet() + ) + friendPlayerService.cachePlayer(updatedReceiver) + } + } +} \ No newline at end of file diff --git a/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/service/FriendShipServiceImpl.kt b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/service/FriendShipServiceImpl.kt new file mode 100644 index 0000000..e2cc339 --- /dev/null +++ b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/service/FriendShipServiceImpl.kt @@ -0,0 +1,60 @@ +package dev.slne.surf.friends.backend.service + +import com.google.auto.service.AutoService +import dev.slne.surf.friends.api.friend.Friendship +import dev.slne.surf.friends.backend.repository.friendShipRepository +import dev.slne.surf.friends.core.service.FriendShipService +import dev.slne.surf.friends.core.service.friendPlayerService +import dev.slne.surf.surfapi.core.api.util.toObjectSet +import net.kyori.adventure.util.Services + +@AutoService(FriendShipService::class) +class FriendShipServiceImpl : FriendShipService, Services.Fallback { + override suspend fun saveFriendShip(friendShip: Friendship) { + friendShipRepository.saveFriendship(friendShip) + + val cachedPlayers = friendPlayerService.players + + val requester = cachedPlayers.firstOrNull { it.uuid == friendShip.requestedBy } + if (requester != null) { + val updated = requester.copy( + friends = (requester.friends + friendShip).toObjectSet() + ) + friendPlayerService.cachePlayer(updated) + } + + val accepter = cachedPlayers.firstOrNull { it.uuid == friendShip.acceptedBy } + if (accepter != null) { + val updated = accepter.copy( + friends = (accepter.friends + friendShip).toObjectSet() + ) + friendPlayerService.cachePlayer(updated) + } + } + + override suspend fun deleteFriendShip(friendShip: Friendship) { + friendShipRepository.deleteFriendship(friendShip) + + val cachedPlayers = friendPlayerService.players + + val requester = cachedPlayers.firstOrNull { it.uuid == friendShip.requestedBy } + if (requester != null) { + val updated = requester.copy( + friends = requester.friends + .filterNot { it == friendShip } + .toObjectSet() + ) + friendPlayerService.cachePlayer(updated) + } + + val accepter = cachedPlayers.firstOrNull { it.uuid == friendShip.acceptedBy } + if (accepter != null) { + val updated = accepter.copy( + friends = accepter.friends + .filterNot { it == friendShip } + .toObjectSet() + ) + friendPlayerService.cachePlayer(updated) + } + } +} \ No newline at end of file diff --git a/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/table/FriendPlayerTable.kt b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/table/FriendPlayerTable.kt new file mode 100644 index 0000000..2558cad --- /dev/null +++ b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/table/FriendPlayerTable.kt @@ -0,0 +1,10 @@ +package dev.slne.surf.friends.backend.table + +import dev.slne.surf.database.columns.nativeUuid +import dev.slne.surf.database.libs.org.jetbrains.exposed.v1.core.dao.id.LongIdTable + +object FriendPlayerTable : LongIdTable("friend_players") { + val playerUuid = nativeUuid("player_uuid").uniqueIndex() + val playerName = varchar("player_name", 16) + val texture = largeText("texture") +} \ No newline at end of file diff --git a/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/table/FriendRequestsTable.kt b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/table/FriendRequestsTable.kt new file mode 100644 index 0000000..769415a --- /dev/null +++ b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/table/FriendRequestsTable.kt @@ -0,0 +1,12 @@ +package dev.slne.surf.friends.backend.table + +import dev.slne.surf.database.columns.nativeUuid +import dev.slne.surf.database.table.AuditableLongIdTable + +object FriendRequestsTable : AuditableLongIdTable("friend_requests") { + val senderUuid = nativeUuid("sender_uuid") + val receiverUuid = nativeUuid("receiver_uuid") + + val senderName = varchar("sender_name", 16) + val receiverName = varchar("receiver_name", 16) +} \ No newline at end of file diff --git a/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/table/FriendShipsTable.kt b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/table/FriendShipsTable.kt new file mode 100644 index 0000000..850ce4a --- /dev/null +++ b/surf-friends-backend/src/main/kotlin/dev/slne/surf/friends/backend/table/FriendShipsTable.kt @@ -0,0 +1,12 @@ +package dev.slne.surf.friends.backend.table + +import dev.slne.surf.database.columns.nativeUuid +import dev.slne.surf.database.table.AuditableLongIdTable + +object FriendShipsTable : AuditableLongIdTable("friend_ships") { + val requesterUuid = nativeUuid("requester_uuid") + val acceptorUuid = nativeUuid("acceptor_uuid") + + val requesterName = varchar("requester_name", 16) + val acceptorName = varchar("acceptor_name", 16) +} \ No newline at end of file diff --git a/surf-friends-core/build.gradle.kts b/surf-friends-core/build.gradle.kts index 14e6bbb..d5bb94a 100644 --- a/surf-friends-core/build.gradle.kts +++ b/surf-friends-core/build.gradle.kts @@ -1,5 +1,10 @@ plugins { - id("dev.slne.surf.surfapi.gradle.core") + id("dev.slne.surf.surfapi.gradle.paper-raw") +} + +surfRawPaperApi { + withCorePaper() + withSurfRedis() } dependencies { diff --git a/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/loader/DatabaseLoader.kt b/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/loader/DatabaseLoader.kt new file mode 100644 index 0000000..312ae53 --- /dev/null +++ b/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/loader/DatabaseLoader.kt @@ -0,0 +1,11 @@ +package dev.slne.surf.friends.core.loader + +import dev.slne.surf.surfapi.core.api.util.requiredService +import java.nio.file.Path + +val databaseLoader = requiredService() + +interface DatabaseLoader { + suspend fun connect(dataPath: Path) + fun disconnect() +} \ No newline at end of file diff --git a/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/loader/RedisLoader.kt b/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/loader/RedisLoader.kt new file mode 100644 index 0000000..a9c1998 --- /dev/null +++ b/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/loader/RedisLoader.kt @@ -0,0 +1,35 @@ +package dev.slne.surf.friends.core.loader + +import dev.slne.surf.friends.api.player.FriendPlayer +import dev.slne.surf.redis.RedisApi +import dev.slne.surf.redis.sync.map.SyncMap +import java.util.* + +val redisLoader = RedisLoader() +val redisApi get() = redisLoader.redisApi + +class RedisLoader { + val redisApi = RedisApi.create() + val playerCache: SyncMap = + redisApi.createSyncMap("surf-friends:player-cache") + + + fun load() { + } + + fun withRequestResponseHandler(handler: Any) { + redisApi.registerRequestHandler(handler) + } + + fun withListener(listener: Any) { + redisApi.subscribeToEvents(listener) + } + + fun connect() { + redisApi.freezeAndConnect() + } + + fun disconnect() { + redisApi.disconnect() + } +} \ No newline at end of file diff --git a/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/model/CoreFriendRequest.kt b/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/model/CoreFriendRequest.kt deleted file mode 100644 index 29f0705..0000000 --- a/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/model/CoreFriendRequest.kt +++ /dev/null @@ -1,10 +0,0 @@ -package dev.slne.surf.friends.core.model - -import dev.slne.surf.friends.api.model.FriendRequest -import java.util.UUID - -data class CoreFriendRequest( - override val senderUuid: UUID, - override val receiverUuid: UUID, - override val sentAt: Long -) : FriendRequest \ No newline at end of file diff --git a/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/model/CoreFriendship.kt b/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/model/CoreFriendship.kt deleted file mode 100644 index c3ba36e..0000000 --- a/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/model/CoreFriendship.kt +++ /dev/null @@ -1,10 +0,0 @@ -package dev.slne.surf.friends.core.model - -import dev.slne.surf.friends.api.model.Friendship -import java.util.UUID - -data class CoreFriendship( - override val userUuid: UUID, - override val friendUuid: UUID, - override val createdAt: Long -) : Friendship \ No newline at end of file diff --git a/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/pair/CoreFriendSettings.kt b/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/pair/CoreFriendSettings.kt deleted file mode 100644 index 7307269..0000000 --- a/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/pair/CoreFriendSettings.kt +++ /dev/null @@ -1,10 +0,0 @@ -package dev.slne.surf.friends.core.pair - -import dev.slne.surf.friends.api.util.FriendSettings - -data class CoreFriendSettings( - override var announcementsEnabled: Boolean = true, - override var soundsEnabled: Boolean = true -) : FriendSettings { - override fun modify(block: FriendSettings.() -> Unit) = this.apply(block) -} \ No newline at end of file diff --git a/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/service/DatabaseService.kt b/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/service/DatabaseService.kt deleted file mode 100644 index 846d1fe..0000000 --- a/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/service/DatabaseService.kt +++ /dev/null @@ -1,127 +0,0 @@ -package dev.slne.surf.friends.core.service - - import dev.slne.surf.friends.api.model.FriendRequest - import dev.slne.surf.friends.api.model.Friendship - import dev.slne.surf.friends.core.pair.CoreFriendSettings - import dev.slne.surf.surfapi.core.api.util.requiredService - import it.unimi.dsi.fastutil.objects.ObjectSet - import java.nio.file.Path - import java.util.UUID - - /** - * Interface for database operations related to friendships and settings. - */ - interface DatabaseService { - - /** - * Establishes a connection to the database. - * - * @param path The path to the database storage location. - */ - fun connect(path: Path) - - /** - * Retrieves the friend list of a user. - * - * @param uuid The UUID of the user. - * @return A list of friendships representing the user's friends. - */ - suspend fun getFriends(uuid: UUID): ObjectSet - - /** - * Retrieves a specific friendship between two users. - * - * @param playerA The UUID of the first user. - * @param playerB The UUID of the second user. - * @return The friendship if it exists, otherwise null. - */ - suspend fun getFriendship(playerA: UUID, playerB: UUID): Friendship? - - /** - * Retrieves a specific friend request between two users. - * - * @param sender The UUID of the sender. - * @param target The UUID of the target user. - * @return The friend request if it exists, otherwise null. - */ - suspend fun getFriendRequest(sender: UUID, target: UUID): FriendRequest? - - /** - * Retrieves the list of sent friend requests of a user. - * - * @param uuid The UUID of the user. - * @return A list of friend requests representing the recipients of the sent requests. - */ - suspend fun getSentFriendRequests(uuid: UUID): ObjectSet - - /** - * Retrieves the list of received friend requests of a user. - * - * @param uuid The UUID of the user. - * @return A list of friend requests representing the senders of the received requests. - */ - suspend fun getReceivedFriendRequests(uuid: UUID): ObjectSet - - /** - * Retrieves the friendship settings of a user. - * - * @param uuid The UUID of the user. - * @return A pair representing the user's friendship settings. - */ - suspend fun getFriendSettings(uuid: UUID): CoreFriendSettings - - /** - * Adds a friendship between two users. - * - * @param uuid The UUID of the first user. - * @param friend The UUID of the friend. - * @return The created friendship. - */ - suspend fun addFriendship(uuid: UUID, friend: UUID): Friendship - - /** - * Removes a friendship between two users. - * - * @param uuid The UUID of the first user. - * @param friend The UUID of the friend. - */ - suspend fun removeFriendship(uuid: UUID, friend: UUID) - - /** - * Adds a friend request. - * - * @param sender The UUID of the sender. - * @param receiver The UUID of the receiver. - * @return The created friend request. - */ - suspend fun addFriendRequest(sender: UUID, receiver: UUID): FriendRequest - - /** - * Removes a friend request. - * - * @param sender The UUID of the sender. - * @param receiver The UUID of the receiver. - */ - suspend fun removeFriendRequest(sender: UUID, receiver: UUID) - - /** - * Updates the friendship settings of a user. - * - * @param uuid The UUID of the user. - * @param pair The pair representing the new friendship settings. - * @return The updated friendship settings. - */ - suspend fun updateFriendSettings(uuid: UUID, pair: CoreFriendSettings): CoreFriendSettings - - companion object { - /** - * Instance of the `DatabaseService`. - */ - val INSTANCE = requiredService() - } - } - - /** - * Extension function to retrieve the instance of the `DatabaseService`. - */ - val databaseService get() = DatabaseService.INSTANCE \ No newline at end of file diff --git a/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/service/FriendPlayerService.kt b/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/service/FriendPlayerService.kt new file mode 100644 index 0000000..259bb4e --- /dev/null +++ b/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/service/FriendPlayerService.kt @@ -0,0 +1,21 @@ +package dev.slne.surf.friends.core.service + +import com.destroystokyo.paper.profile.PlayerProfile +import dev.slne.surf.friends.api.player.FriendPlayer +import dev.slne.surf.surfapi.core.api.util.requiredService +import it.unimi.dsi.fastutil.objects.ObjectSet +import java.util.* + +val friendPlayerService get() = requiredService() + +interface FriendPlayerService { + val players: ObjectSet + + fun cachePlayer(friendPlayer: FriendPlayer) + fun invalidatePlayer(uuid: UUID) + + suspend fun loadOrCreatePlayer(profile: PlayerProfile): FriendPlayer + suspend fun findOrLoadPlayer(name: String): FriendPlayer? + suspend fun findOrLoadPlayer(uuid: UUID): FriendPlayer? + suspend fun savePlayer(friendPlayer: FriendPlayer) +} \ No newline at end of file diff --git a/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/service/FriendRequestService.kt b/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/service/FriendRequestService.kt new file mode 100644 index 0000000..eba1ddf --- /dev/null +++ b/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/service/FriendRequestService.kt @@ -0,0 +1,11 @@ +package dev.slne.surf.friends.core.service + +import dev.slne.surf.friends.api.friend.FriendRequest +import dev.slne.surf.surfapi.core.api.util.requiredService + +val friendRequestService = requiredService() + +interface FriendRequestService { + suspend fun saveFriendRequest(friendRequest: FriendRequest) + suspend fun deleteFriendRequest(friendRequest: FriendRequest) +} \ No newline at end of file diff --git a/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/service/FriendService.kt b/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/service/FriendService.kt deleted file mode 100644 index 182c234..0000000 --- a/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/service/FriendService.kt +++ /dev/null @@ -1,138 +0,0 @@ -package dev.slne.surf.friends.core.service - - import dev.slne.surf.friends.api.model.FriendRequest - import dev.slne.surf.friends.api.model.Friendship - import dev.slne.surf.surfapi.core.api.util.requiredService - import it.unimi.dsi.fastutil.objects.ObjectSet - import java.util.UUID - - /** - * Service interface for managing friendships and related actions. - */ - interface FriendService { - /** - * Creates a friendship between two users. - * - * @param uuid The UUID of the first user. - * @param friend The UUID of the friend. - * @return The created Friendship object. - */ - suspend fun createFriendship(uuid: UUID, friend: UUID): Friendship - - /** - * Removes a friendship between two users. - * - * @param uuid The UUID of the first user. - * @param friend The UUID of the friend. - */ - suspend fun removeFriendship(uuid: UUID, friend: UUID) - - /** - * Retrieves a specific friendship between two users. - * - * @param playerA The UUID of the first user. - * @param playerB The UUID of the second user. - * @return The Friendship object if it exists, otherwise null. - */ - suspend fun getFriendship(playerA: UUID, playerB: UUID): Friendship? - - /** - * Checks if two users are friends. - * - * @param uuid The UUID of the first user. - * @param friend The UUID of the second user. - * @return The Friendship object if they are friends, otherwise null. - */ - suspend fun areFriends(uuid: UUID, friend: UUID): Friendship? - - /** - * Retrieves all friendships of a user. - * - * @param uuid The UUID of the user. - * @return A set of Friendships representing the user's friends. - */ - suspend fun getFriendships(uuid: UUID): ObjectSet - - /** - * Sends a friend request from one user to another. - * - * @param sender The UUID of the sender. - * @param receiver The UUID of the receiver. - * @return The created FriendRequest object. - */ - suspend fun sendFriendRequest(sender: UUID, receiver: UUID): FriendRequest - - /** - * Accepts a friend request. - * - * @param sender The UUID of the sender of the request. - * @param receiver The UUID of the receiver of the request. - */ - suspend fun acceptFriendRequest(sender: UUID, receiver: UUID) - - /** - * Declines a friend request. - * - * @param sender The UUID of the sender of the request. - * @param receiver The UUID of the receiver of the request. - */ - suspend fun declineFriendRequest(sender: UUID, receiver: UUID) - - /** - * Revokes a sent friend request. - * - * @param sender The UUID of the sender of the request. - * @param receiver The UUID of the receiver of the request. - */ - suspend fun revokeFriendRequest(sender: UUID, receiver: UUID) - - /** - * Retrieves all sent friend requests of a user. - * - * @param uuid The UUID of the user. - * @return A set of FriendRequests representing the recipients of the sent requests. - */ - suspend fun getSentFriendRequests(uuid: UUID): ObjectSet - - /** - * Retrieves all received friend requests of a user. - * - * @param uuid The UUID of the user. - * @return A set of FriendRequests representing the senders of the received requests. - */ - suspend fun getReceivedFriendRequests(uuid: UUID): ObjectSet - - /** - * Retrieves a specific friend request between two users. - * - * @param sender The UUID of the sender. - * @param target The UUID of the target user. - * @return The FriendRequest object if it exists, otherwise null. - */ - suspend fun getFriendRequest(sender: UUID, target: UUID): FriendRequest? - - /** - * Toggles announcements for a user. - * - * @param uuid The UUID of the user. - * @return The new status of announcements (true if enabled, false if disabled). - */ - suspend fun toggleAnnouncements(uuid: UUID): Boolean - - /** - * Toggles sounds for a user. - * - * @param uuid The UUID of the user. - * @return The new status of sounds (true if enabled, false if disabled). - */ - suspend fun toggleSounds(uuid: UUID): Boolean - - companion object { - val INSTANCE = requiredService() - } - } - - /** - * Extension function to get the friend service instance. - */ - val friendService get() = FriendService.INSTANCE \ No newline at end of file diff --git a/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/service/FriendShipService.kt b/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/service/FriendShipService.kt new file mode 100644 index 0000000..208d0ca --- /dev/null +++ b/surf-friends-core/src/main/kotlin/dev/slne/surf/friends/core/service/FriendShipService.kt @@ -0,0 +1,11 @@ +package dev.slne.surf.friends.core.service + +import dev.slne.surf.friends.api.friend.Friendship +import dev.slne.surf.surfapi.core.api.util.requiredService + +val friendShipService = requiredService() + +interface FriendShipService { + suspend fun saveFriendShip(friendShip: Friendship) + suspend fun deleteFriendShip(friendShip: Friendship) +} \ No newline at end of file diff --git a/surf-friends-fallback/build.gradle.kts b/surf-friends-fallback/build.gradle.kts deleted file mode 100644 index 6d793da..0000000 --- a/surf-friends-fallback/build.gradle.kts +++ /dev/null @@ -1,8 +0,0 @@ -plugins { - id("dev.slne.surf.surfapi.gradle.core") -} - -dependencies { - api(project(":surf-friends-core")) - api(libs.surf.database) -} diff --git a/surf-friends-fallback/src/main/kotlin/dev/slne/surf/friends/fallback/api/FallbackFriendApi.kt b/surf-friends-fallback/src/main/kotlin/dev/slne/surf/friends/fallback/api/FallbackFriendApi.kt deleted file mode 100644 index 456ca29..0000000 --- a/surf-friends-fallback/src/main/kotlin/dev/slne/surf/friends/fallback/api/FallbackFriendApi.kt +++ /dev/null @@ -1,70 +0,0 @@ -package dev.slne.surf.friends.fallback.api - -import com.google.auto.service.AutoService -import dev.slne.surf.friends.api.SurfFriendsApi -import dev.slne.surf.friends.api.model.FriendRequest -import dev.slne.surf.friends.api.model.Friendship -import dev.slne.surf.friends.core.service.friendService -import it.unimi.dsi.fastutil.objects.ObjectSet -import net.kyori.adventure.util.Services -import java.util.UUID - -@AutoService(SurfFriendsApi::class) -class FallbackFriendApi: SurfFriendsApi, Services.Fallback { - override suspend fun createFriendship( - uuid: UUID, - friend: UUID - ): Friendship { - return friendService.createFriendship(uuid, friend) - } - - override suspend fun removeFriendship(uuid: UUID, friend: UUID) { - friendService.removeFriendship(uuid, friend) - } - - override suspend fun getFriendships(uuid: UUID): ObjectSet { - return friendService.getFriendships(uuid) - } - - override suspend fun sendFriendRequest( - sender: UUID, - receiver: UUID - ): FriendRequest { - return friendService.sendFriendRequest(sender, receiver) - } - - override suspend fun acceptFriendRequest(sender: UUID, receiver: UUID) { - friendService.acceptFriendRequest(sender, receiver) - } - - override suspend fun declineFriendRequest(sender: UUID, receiver: UUID) { - friendService.declineFriendRequest(sender, receiver) - } - - override suspend fun revokeFriendRequest(sender: UUID, receiver: UUID) { - friendService.revokeFriendRequest(sender, receiver) - } - - override suspend fun getSentFriendRequests(uuid: UUID): ObjectSet { - return friendService.getSentFriendRequests(uuid) - } - - override suspend fun getReceivedFriendRequests(uuid: UUID): ObjectSet { - return friendService.getReceivedFriendRequests(uuid) - } - - override suspend fun toggleAnnouncements(uuid: UUID): Boolean { - return friendService.toggleAnnouncements(uuid) - } - - override suspend fun toggleSounds(uuid: UUID): Boolean { - return friendService.toggleSounds(uuid) - } - - override suspend fun areFriends( - uuid: UUID, - friend: UUID - ): Friendship? { - return friendService.areFriends(uuid, friend) - } -} \ No newline at end of file diff --git a/surf-friends-fallback/src/main/kotlin/dev/slne/surf/friends/fallback/service/FallbackDatabaseService.kt b/surf-friends-fallback/src/main/kotlin/dev/slne/surf/friends/fallback/service/FallbackDatabaseService.kt deleted file mode 100644 index 5f8d173..0000000 --- a/surf-friends-fallback/src/main/kotlin/dev/slne/surf/friends/fallback/service/FallbackDatabaseService.kt +++ /dev/null @@ -1,209 +0,0 @@ -package dev.slne.surf.friends.fallback.service - -import com.google.auto.service.AutoService -import dev.slne.surf.database.DatabaseManager -import dev.slne.surf.friends.api.model.FriendRequest -import dev.slne.surf.friends.api.model.Friendship -import dev.slne.surf.friends.core.model.CoreFriendRequest -import dev.slne.surf.friends.core.model.CoreFriendship -import dev.slne.surf.friends.core.pair.CoreFriendSettings -import dev.slne.surf.friends.core.service.DatabaseService -import dev.slne.surf.friends.fallback.table.FriendRequestTable -import dev.slne.surf.friends.fallback.table.FriendSettingsTable -import dev.slne.surf.friends.fallback.table.FriendShipTable -import dev.slne.surf.surfapi.core.api.util.toObjectSet -import it.unimi.dsi.fastutil.objects.ObjectSet -import kotlinx.coroutines.Dispatchers -import net.kyori.adventure.util.Services -import org.jetbrains.exposed.sql.ResultRow -import org.jetbrains.exposed.sql.SchemaUtils -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.deleteWhere -import org.jetbrains.exposed.sql.insert -import org.jetbrains.exposed.sql.or -import org.jetbrains.exposed.sql.selectAll -import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction -import org.jetbrains.exposed.sql.transactions.transaction -import org.jetbrains.exposed.sql.upsert -import java.nio.file.Path -import java.util.* - -@AutoService(DatabaseService::class) -class FallbackDatabaseService : DatabaseService, Services.Fallback { - override fun connect(path: Path) { - DatabaseManager(path, path).databaseProvider.connect() - - transaction { - SchemaUtils.create( - FriendShipTable, - FriendRequestTable, - FriendSettingsTable - ) - } - } - - override suspend fun getFriends( - uuid: UUID - ): ObjectSet = newSuspendedTransaction(Dispatchers.IO) { - FriendShipTable.selectAll().where(FriendShipTable.userUuid eq uuid) - .map { - CoreFriendship( - userUuid = it[FriendShipTable.userUuid], - friendUuid = it[FriendShipTable.friendUuid], - createdAt = it[FriendShipTable.created_at] - ) - } - .toObjectSet() - } - - override suspend fun getFriendship( - playerA: UUID, - playerB: UUID - ): Friendship? = newSuspendedTransaction(Dispatchers.IO) { - FriendShipTable.selectAll().where( - (FriendShipTable.userUuid eq playerA) and (FriendShipTable.friendUuid eq playerB) or ( - (FriendShipTable.userUuid eq playerB) and (FriendShipTable.friendUuid eq playerA) - ) - ) - .map { - CoreFriendship( - userUuid = it[FriendShipTable.userUuid], - friendUuid = it[FriendShipTable.friendUuid], - createdAt = it[FriendShipTable.created_at] - ) - } - .firstOrNull() - } - - override suspend fun getFriendRequest( - sender: UUID, - target: UUID - ): FriendRequest? = newSuspendedTransaction(Dispatchers.IO) { - FriendRequestTable.selectAll().where( - (FriendRequestTable.senderUuid eq sender) and (FriendRequestTable.receiverUuid eq target) - ) - .map { - CoreFriendRequest( - senderUuid = it[FriendRequestTable.senderUuid], - receiverUuid = it[FriendRequestTable.receiverUuid], - sentAt = it[FriendRequestTable.send_at] - ) - } - .firstOrNull() - } - - override suspend fun getSentFriendRequests( - uuid: UUID - ): ObjectSet = newSuspendedTransaction(Dispatchers.IO) { - FriendRequestTable.selectAll().where(FriendRequestTable.senderUuid eq uuid) - .map { - CoreFriendRequest( - senderUuid = it[FriendRequestTable.senderUuid], - receiverUuid = it[FriendRequestTable.receiverUuid], - sentAt = it[FriendRequestTable.send_at] - ) - } - .toObjectSet() - } - - override suspend fun getReceivedFriendRequests( - uuid: UUID - ): ObjectSet = newSuspendedTransaction(Dispatchers.IO) { - FriendRequestTable.selectAll().where(FriendRequestTable.receiverUuid eq uuid) - .map { - CoreFriendRequest( - senderUuid = it[FriendRequestTable.senderUuid], - receiverUuid = it[FriendRequestTable.receiverUuid], - sentAt = it[FriendRequestTable.send_at] - ) - } - .toObjectSet() - } - - override suspend fun getFriendSettings( - uuid: UUID - ): CoreFriendSettings = newSuspendedTransaction(Dispatchers.IO) { - FriendSettingsTable.selectAll().where(FriendSettingsTable.userUuid eq uuid) - .map { it.toFriendSettings() } - .firstOrNull() ?: CoreFriendSettings() - } - - override suspend fun addFriendship( - uuid: UUID, - friend: UUID - ): Friendship = newSuspendedTransaction(Dispatchers.IO) { - val current: Long = System.currentTimeMillis() - - FriendShipTable.insert { - it[FriendShipTable.userUuid] = uuid - it[FriendShipTable.friendUuid] = friend - it[FriendShipTable.created_at] = System.currentTimeMillis() - } - - CoreFriendship( - userUuid = uuid, - friendUuid = friend, - createdAt = current - ) - } - - override suspend fun removeFriendship( - uuid: UUID, - friend: UUID - ) = newSuspendedTransaction(Dispatchers.IO) { - FriendShipTable.deleteWhere { - (FriendShipTable.userUuid eq uuid) and (FriendShipTable.friendUuid eq friend) - } - return@newSuspendedTransaction - } - - override suspend fun addFriendRequest( - sender: UUID, - receiver: UUID - ): FriendRequest = newSuspendedTransaction(Dispatchers.IO) { - val current: Long = System.currentTimeMillis() - - FriendRequestTable.insert { - it[FriendRequestTable.senderUuid] = sender - it[FriendRequestTable.receiverUuid] = receiver - it[FriendRequestTable.send_at] = current - } - - CoreFriendRequest( - senderUuid = sender, - receiverUuid = receiver, - sentAt = current - ) - } - - override suspend fun removeFriendRequest( - sender: UUID, - receiver: UUID - ) = newSuspendedTransaction(Dispatchers.IO) { - FriendRequestTable.deleteWhere { - (FriendRequestTable.senderUuid eq sender) and (FriendRequestTable.receiverUuid eq receiver) - } - return@newSuspendedTransaction - } - - override suspend fun updateFriendSettings( - uuid: UUID, - pair: CoreFriendSettings - ): CoreFriendSettings = newSuspendedTransaction(Dispatchers.IO) { - FriendSettingsTable.upsert { - it[FriendSettingsTable.userUuid] = uuid - it[FriendSettingsTable.announcementsEnabled] = pair.announcementsEnabled - it[FriendSettingsTable.soundsEnabled] = pair.soundsEnabled - } - - pair - } - - fun ResultRow.toFriendSettings(): CoreFriendSettings { - return CoreFriendSettings( - announcementsEnabled = this[FriendSettingsTable.announcementsEnabled], - soundsEnabled = this[FriendSettingsTable.soundsEnabled] - ) - } -} \ No newline at end of file diff --git a/surf-friends-fallback/src/main/kotlin/dev/slne/surf/friends/fallback/service/FallbackFriendService.kt b/surf-friends-fallback/src/main/kotlin/dev/slne/surf/friends/fallback/service/FallbackFriendService.kt deleted file mode 100644 index afa43a3..0000000 --- a/surf-friends-fallback/src/main/kotlin/dev/slne/surf/friends/fallback/service/FallbackFriendService.kt +++ /dev/null @@ -1,79 +0,0 @@ -package dev.slne.surf.friends.fallback.service - -import com.google.auto.service.AutoService -import dev.slne.surf.friends.api.model.FriendRequest -import dev.slne.surf.friends.core.service.FriendService -import dev.slne.surf.friends.core.service.databaseService -import net.kyori.adventure.util.Services -import java.util.* - -@AutoService(FriendService::class) -class FallbackFriendService : FriendService, Services.Fallback { - override suspend fun createFriendship(uuid: UUID, friend: UUID) = - databaseService.getFriendship(uuid, friend) ?: databaseService.addFriendship( - uuid, - friend - ) - - override suspend fun removeFriendship(uuid: UUID, friend: UUID) { - databaseService.removeFriendship(uuid, friend) - databaseService.removeFriendship(friend, uuid) - } - - override suspend fun getFriendship( - playerA: UUID, - playerB: UUID - ) = databaseService.getFriendship(playerA, playerB) - - override suspend fun areFriends( - uuid: UUID, - friend: UUID - ) = databaseService.getFriendship(uuid, friend) - - override suspend fun getFriendships(uuid: UUID) = databaseService.getFriends(uuid) - - override suspend fun sendFriendRequest(sender: UUID, receiver: UUID): FriendRequest = - databaseService.getFriendRequest(sender, receiver) - ?: databaseService.addFriendRequest(sender, receiver) - - override suspend fun acceptFriendRequest(sender: UUID, receiver: UUID) { - databaseService.removeFriendRequest(sender, receiver) - databaseService.addFriendship(sender, receiver) - databaseService.addFriendship(receiver, sender) - } - - override suspend fun declineFriendRequest(sender: UUID, receiver: UUID) = - databaseService.removeFriendRequest(sender, receiver) - - override suspend fun revokeFriendRequest(sender: UUID, receiver: UUID) = - databaseService.removeFriendRequest(sender, receiver) - - override suspend fun getSentFriendRequests(uuid: UUID) = - databaseService.getSentFriendRequests(uuid) - - override suspend fun getReceivedFriendRequests(uuid: UUID) = - databaseService.getReceivedFriendRequests(uuid) - - override suspend fun getFriendRequest( - sender: UUID, - target: UUID - ) = databaseService.getFriendRequest(sender, target) - - override suspend fun toggleAnnouncements(uuid: UUID): Boolean { - val friendSettings = databaseService.getFriendSettings(uuid) - val newSettings = friendSettings.modify { - announcementsEnabled = !friendSettings.announcementsEnabled - } - - return databaseService.updateFriendSettings(uuid, newSettings).announcementsEnabled - } - - override suspend fun toggleSounds(uuid: UUID): Boolean { - val friendSettings = databaseService.getFriendSettings(uuid) - val newSettings = friendSettings.modify { - soundsEnabled = !friendSettings.soundsEnabled - } - - return databaseService.updateFriendSettings(uuid, newSettings).soundsEnabled - } -} \ No newline at end of file diff --git a/surf-friends-fallback/src/main/kotlin/dev/slne/surf/friends/fallback/table/FriendRequestTable.kt b/surf-friends-fallback/src/main/kotlin/dev/slne/surf/friends/fallback/table/FriendRequestTable.kt deleted file mode 100644 index 6303324..0000000 --- a/surf-friends-fallback/src/main/kotlin/dev/slne/surf/friends/fallback/table/FriendRequestTable.kt +++ /dev/null @@ -1,13 +0,0 @@ -package dev.slne.surf.friends.fallback.table - -import org.jetbrains.exposed.sql.Table -import java.util.UUID - -object FriendRequestTable : Table("friend_requests") { - val id = integer("id").autoIncrement() - val senderUuid = varchar("sender_uuid", 36).transform({ UUID.fromString(it) }, { it.toString() }) - val receiverUuid = varchar("receiver_uuid", 36).transform({ UUID.fromString(it) }, { it.toString() }) - val send_at = long("created_at") - - override val primaryKey = PrimaryKey(id) -} \ No newline at end of file diff --git a/surf-friends-fallback/src/main/kotlin/dev/slne/surf/friends/fallback/table/FriendSettingsTable.kt b/surf-friends-fallback/src/main/kotlin/dev/slne/surf/friends/fallback/table/FriendSettingsTable.kt deleted file mode 100644 index 8d0b255..0000000 --- a/surf-friends-fallback/src/main/kotlin/dev/slne/surf/friends/fallback/table/FriendSettingsTable.kt +++ /dev/null @@ -1,12 +0,0 @@ -package dev.slne.surf.friends.fallback.table - -import org.jetbrains.exposed.sql.Table -import java.util.UUID - -object FriendSettingsTable : Table("friend_settings") { - val userUuid = varchar("user_uuid", 36).transform({ UUID.fromString(it) }, { it.toString() }).uniqueIndex() - var announcementsEnabled = bool("announcements_enabled").default(true) - var soundsEnabled = bool("sounds_enabled").default(true) - - override val primaryKey = PrimaryKey(userUuid) -} \ No newline at end of file diff --git a/surf-friends-fallback/src/main/kotlin/dev/slne/surf/friends/fallback/table/FriendShipTable.kt b/surf-friends-fallback/src/main/kotlin/dev/slne/surf/friends/fallback/table/FriendShipTable.kt deleted file mode 100644 index 05f4b50..0000000 --- a/surf-friends-fallback/src/main/kotlin/dev/slne/surf/friends/fallback/table/FriendShipTable.kt +++ /dev/null @@ -1,13 +0,0 @@ -package dev.slne.surf.friends.fallback.table - -import org.jetbrains.exposed.sql.Table -import java.util.UUID - -object FriendShipTable : Table("friend_ships") { - val id = integer("id").autoIncrement() - val userUuid = varchar("user_uuid", 36).transform({ UUID.fromString(it) }, { it.toString() }) - val friendUuid = varchar("friend_uuid", 36).transform({ UUID.fromString(it) }, { it.toString() }) - val created_at = long("created_at") - - override val primaryKey = PrimaryKey(id) -} \ No newline at end of file diff --git a/surf-friends-paper/build.gradle.kts b/surf-friends-paper/build.gradle.kts new file mode 100644 index 0000000..9dd5a72 --- /dev/null +++ b/surf-friends-paper/build.gradle.kts @@ -0,0 +1,27 @@ +import dev.slne.surf.surfapi.gradle.util.registerSoft + +plugins { + id("dev.slne.surf.surfapi.gradle.paper-plugin") +} + + +surfPaperPluginApi { + mainClass("dev.slne.surf.friends.paper.PaperMain") + generateLibraryLoader(false) + foliaSupported(true) + withCorePaper() + withSurfRedis() + + authors.add("red") + + serverDependencies { + registerSoft("surf-settings-paper") + } +} + +dependencies { + api(project(":surf-friends-core")) + runtimeOnly(project(":surf-friends-backend")) + + compileOnly("dev.slne.surf.settings:surf-settings-api:1.21.11-2.0.0-SNAPSHOT") +} \ No newline at end of file diff --git a/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/PaperMain.kt b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/PaperMain.kt new file mode 100644 index 0000000..340f27a --- /dev/null +++ b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/PaperMain.kt @@ -0,0 +1,40 @@ +package dev.slne.surf.friends.paper + +import com.github.shynixn.mccoroutine.folia.SuspendingJavaPlugin +import dev.slne.surf.core.api.common.surfCoreApi +import dev.slne.surf.friends.core.loader.databaseLoader +import dev.slne.surf.friends.core.loader.redisLoader +import dev.slne.surf.friends.paper.command.friendAddCommand +import dev.slne.surf.friends.paper.command.friendCommand +import dev.slne.surf.friends.paper.command.friendListCommand +import dev.slne.surf.friends.paper.listener.PlayerConnectionListener +import dev.slne.surf.friends.paper.listener.SurfPlayerListener +import dev.slne.surf.friends.paper.redis.FriendRedisListener +import dev.slne.surf.surfapi.bukkit.api.event.register +import org.bukkit.plugin.java.JavaPlugin + +val plugin get() = JavaPlugin.getPlugin(PaperMain::class.java) + +class PaperMain : SuspendingJavaPlugin() { + override suspend fun onLoadAsync() { + redisLoader.load() + redisLoader.withListener(FriendRedisListener) + redisLoader.connect() + + databaseLoader.connect(plugin.dataPath) + } + + override suspend fun onEnableAsync() { + PlayerConnectionListener.register() + surfCoreApi.registerListener(SurfPlayerListener) + + friendCommand() + friendAddCommand() + friendListCommand() + } + + override suspend fun onDisableAsync() { + redisLoader.disconnect() + databaseLoader.disconnect() + } +} \ No newline at end of file diff --git a/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/FriendCommand.kt b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/FriendCommand.kt new file mode 100644 index 0000000..93ced21 --- /dev/null +++ b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/FriendCommand.kt @@ -0,0 +1,252 @@ +package dev.slne.surf.friends.paper.command + +import dev.jorel.commandapi.kotlindsl.commandTree +import dev.jorel.commandapi.kotlindsl.getValue +import dev.jorel.commandapi.kotlindsl.literalArgument +import dev.jorel.commandapi.kotlindsl.playerExecutor +import dev.slne.surf.core.api.common.player.SurfPlayer +import dev.slne.surf.friends.api.friend.FriendRequest +import dev.slne.surf.friends.api.player.FriendPlayer +import dev.slne.surf.friends.core.loader.redisApi +import dev.slne.surf.friends.core.service.friendRequestService +import dev.slne.surf.friends.core.service.friendShipService +import dev.slne.surf.friends.paper.command.argument.friend.nonFriendOfflinePlayerArgument +import dev.slne.surf.friends.paper.command.argument.friend.offlineFriendArgument +import dev.slne.surf.friends.paper.command.argument.request.receivedFriendRequestArgument +import dev.slne.surf.friends.paper.command.argument.request.sentFriendRequestArgument +import dev.slne.surf.friends.paper.permission.PermissionRegistry +import dev.slne.surf.friends.paper.redis.event.FriendNotifyRedisEvent +import dev.slne.surf.friends.paper.util.friendPlayer +import dev.slne.surf.surfapi.bukkit.api.command.executors.playerExecutorSuspend +import dev.slne.surf.surfapi.core.api.command.args.awaiting +import dev.slne.surf.surfapi.core.api.font.toSmallCaps +import dev.slne.surf.surfapi.core.api.messages.adventure.buildText +import dev.slne.surf.surfapi.core.api.messages.adventure.sendText +import dev.slne.surf.surfapi.core.api.messages.pagination.Pagination +import net.kyori.adventure.text.format.TextDecoration + +fun friendListCommand() = commandTree("fl") { + withPermission(PermissionRegistry.PREFIX_COMMAND) + + playerExecutor { player, _ -> + listFriends(player) + } +} + +fun friendAddCommand() = commandTree("fa") { + withPermission(PermissionRegistry.PREFIX_COMMAND) + + nonFriendOfflinePlayerArgument("target") { + playerExecutorSuspend { player, args -> + val target = args.awaiting("target") + + addFriend(player, target, args.getRaw("target") ?: "#Unknown") + } + } +} + +fun friendCommand() = commandTree("friend") { + withPermission(PermissionRegistry.PREFIX_COMMAND) + + literalArgument("add") { + nonFriendOfflinePlayerArgument("target") { + playerExecutorSuspend { player, args -> + val target = args.awaiting("target") + + addFriend(player, target, args.getRaw("target") ?: "#Unknown") + } + } + } + + literalArgument("remove") { + offlineFriendArgument("friend") { + playerExecutorSuspend { player, args -> + val friend = args.awaiting("friend") + + if (friend == null) { + player.sendText { + appendErrorPrefix() + error("Der Spieler wurde nicht gefunden.") + } + return@playerExecutorSuspend + } + + val friendPlayer = player.friendPlayer + + if (!friendPlayer.hasFriend(friend.uuid)) { + player.sendText { + appendErrorPrefix() + error("Du bist mit diesem Spieler nicht befreundet.") + } + return@playerExecutorSuspend + } + + val friendship = + friendPlayer.friends.firstOrNull { it.acceptedBy == friend.uuid || it.requestedBy == friend.uuid } + + if (friendship == null) { + player.sendText { + appendErrorPrefix() + error("Du bist mit diesem Spieler nicht befreundet.") + } + return@playerExecutorSuspend + } + + friendShipService.deleteFriendShip(friendship) + + player.sendText { + appendSuccessPrefix() + success("Du hast die Freundschaft mit ") + variableValue(friend.name) + success(" beendet.") + } + + redisApi.publishEvent( + FriendNotifyRedisEvent( + playerUuid = friend.uuid, + buildText { + appendInfoPrefix() + info("Die Freundschaft mit ") + variableValue(player.name) + info(" wurde beendet.") + } + )) + } + } + } + + literalArgument("list") { + playerExecutor { player, _ -> + listFriends(player) + } + } + + literalArgument("requests") { + literalArgument("sent") { + playerExecutor { player, _ -> + val friendPlayer = player.friendPlayer + + if (friendPlayer.sentFriendRequests.isEmpty()) { + player.sendText { + appendInfoPrefix() + info("Du hast keine gesendeten Freundschaftsanfragen.") + } + return@playerExecutor + } + + player.sendText { + appendNewline() + append(sendRequestsPagination.renderComponent(friendPlayer.sentFriendRequests)) + } + } + } + + literalArgument("received") { + playerExecutor { player, _ -> + val friendPlayer = player.friendPlayer + + if (friendPlayer.receivedFriendRequests.isEmpty()) { + player.sendText { + appendInfoPrefix() + info("Du hast keine empfangenen Freundschaftsanfragen.") + } + return@playerExecutor + } + + player.sendText { + appendNewline() + append(receivedRequestsPagination.renderComponent(friendPlayer.receivedFriendRequests)) + } + } + } + } + + literalArgument("accept") { + receivedFriendRequestArgument("receivedRequest") { + playerExecutorSuspend { player, args -> + val receivedRequest: FriendRequest by args + acceptFriend(player, receivedRequest) + } + } + } + + literalArgument("decline") { + receivedFriendRequestArgument("receivedRequest") { + playerExecutorSuspend { player, args -> + val receivedRequest: FriendRequest by args + + friendRequestService.deleteFriendRequest(receivedRequest) + + player.sendText { + appendSuccessPrefix() + success("Du hast die Freundschaftsanfrage von ") + variableValue(receivedRequest.senderName) + success(" abgelehnt.") + } + + redisApi.publishEvent( + FriendNotifyRedisEvent( + playerUuid = receivedRequest.senderUuid, + buildText { + appendInfoPrefix() + info("Deine Freundschaftsanfrage an ") + variableValue(receivedRequest.receiverName) + info(" wurde abgelehnt.") + } + )) + } + } + } + + literalArgument("revoke") { + sentFriendRequestArgument("sentRequest") { + playerExecutorSuspend { player, args -> + val sentRequest: FriendRequest by args + + friendRequestService.deleteFriendRequest(sentRequest) + + player.sendText { + appendSuccessPrefix() + success("Du hast die Freundschaftsanfrage an ") + variableValue(sentRequest.receiverName) + success(" zurückgezogen.") + } + + redisApi.publishEvent( + FriendNotifyRedisEvent( + playerUuid = sentRequest.receiverUuid, + buildText { + appendInfoPrefix() + info("Die Freundschaftsanfrage von ") + variableValue(player.name) + info(" wurde zurückgezogen.") + } + )) + } + } + } +} + +private val sendRequestsPagination = Pagination { + title { primary("Gesendete Anfragen".toSmallCaps(), TextDecoration.BOLD) } + + rowRenderer { friendRequest, _ -> + listOf(buildText { + spacer("-") + appendSpace() + variableValue(friendRequest.receiverName) + }) + } +} + +private val receivedRequestsPagination = Pagination { + title { primary("Empfangene Anfragen".toSmallCaps(), TextDecoration.BOLD) } + + rowRenderer { friendRequest, _ -> + listOf(buildText { + spacer("-") + appendSpace() + variableValue(friendRequest.senderName) + }) + } +} \ No newline at end of file diff --git a/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/argument/friend/FriendPlayerArgument.kt b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/argument/friend/FriendPlayerArgument.kt new file mode 100644 index 0000000..46cac82 --- /dev/null +++ b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/argument/friend/FriendPlayerArgument.kt @@ -0,0 +1,57 @@ +package dev.slne.surf.friends.paper.command.argument.friend + +import dev.jorel.commandapi.CommandAPICommand +import dev.jorel.commandapi.CommandTree +import dev.jorel.commandapi.arguments.Argument +import dev.jorel.commandapi.arguments.ArgumentSuggestions +import dev.jorel.commandapi.arguments.CustomArgument +import dev.jorel.commandapi.arguments.StringArgument +import dev.slne.surf.friends.api.player.FriendPlayer +import dev.slne.surf.friends.core.service.friendPlayerService +import dev.slne.surf.surfapi.core.api.messages.adventure.buildText +import dev.slne.surf.surfapi.core.api.messages.adventure.uuid + +class FriendPlayerArgument(nodeName: String) : + CustomArgument(StringArgument(nodeName), { info -> + friendPlayerService.players.firstOrNull { it.name == info.input } + ?: throw CustomArgumentException.fromAdventureComponent( + buildText { + appendErrorPrefix() + error("Der Spieler wurde nicht gefunden.") + }) + }) { + init { + this.replaceSuggestions( + ArgumentSuggestions.stringCollection { sender -> + friendPlayerService.players.find { it.uuid == sender.sender.uuid() }?.friends?.map { + it.getOtherName( + sender.sender.uuid() + ) + } + } + ) + } +} + +inline fun CommandTree.friendPlayerArgument( + nodeName: String, + optional: Boolean = false, + block: Argument<*>.() -> Unit = {} +): CommandTree = then( + FriendPlayerArgument(nodeName).setOptional(optional).apply(block) +) + +inline fun Argument<*>.friendPlayerArgument( + nodeName: String, + optional: Boolean = false, + block: Argument<*>.() -> Unit = {} +): Argument<*> = then( + FriendPlayerArgument(nodeName).setOptional(optional).apply(block) +) + +inline fun CommandAPICommand.friendPlayerArgument( + nodeName: String, + optional: Boolean = false, + block: Argument<*>.() -> Unit = {} +): CommandAPICommand = + withArguments(FriendPlayerArgument(nodeName).setOptional(optional).apply(block)) \ No newline at end of file diff --git a/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/argument/friend/NonFriendOfflinePlayerArgument.kt b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/argument/friend/NonFriendOfflinePlayerArgument.kt new file mode 100644 index 0000000..b89ab56 --- /dev/null +++ b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/argument/friend/NonFriendOfflinePlayerArgument.kt @@ -0,0 +1,74 @@ +package dev.slne.surf.friends.paper.command.argument.friend + +import dev.jorel.commandapi.CommandAPICommand +import dev.jorel.commandapi.CommandTree +import dev.jorel.commandapi.arguments.Argument +import dev.jorel.commandapi.arguments.ArgumentSuggestions +import dev.jorel.commandapi.arguments.CustomArgument +import dev.jorel.commandapi.arguments.StringArgument +import dev.slne.surf.core.api.common.player.SurfPlayer +import dev.slne.surf.core.api.common.surfCoreApi +import dev.slne.surf.friends.core.service.friendPlayerService +import dev.slne.surf.surfapi.core.api.messages.adventure.uuid +import dev.slne.surf.surfapi.core.api.util.logger +import kotlinx.coroutines.* +import kotlinx.coroutines.future.asDeferred +import kotlinx.coroutines.future.future + +class NonFriendOfflinePlayerArgument(nodeName: String) : + CustomArgument, String>(StringArgument(nodeName), { info -> + scope.future { + surfCoreApi.getOfflinePlayer(info.input) + }.asDeferred() + }) { + init { + this.replaceSuggestions( + ArgumentSuggestions.stringCollection { info -> + val friendPlayer = + friendPlayerService.players.find { it.uuid == info.sender.uuid() } + ?: return@stringCollection null + val friendUuids = friendPlayer.friends + .map { it.getOtherUuid(friendPlayer.uuid) } + .toSet() + + surfCoreApi.getOnlinePlayers() + .filterNot { it.uuid == friendPlayer.uuid } + .filterNot { it.uuid in friendUuids } + .mapNotNull { it.lastKnownName } + } + ) + } + + companion object { + private val log = logger() + private val scope = + CoroutineScope(Dispatchers.IO + CoroutineName("NonFriendOfflinePlayerArgument") + CoroutineExceptionHandler { _, throwable -> + log.atWarning() + .withCause(throwable) + .log("An error occurred in NonFriendOfflinePlayerArgument") + }) + } +} + +inline fun CommandTree.nonFriendOfflinePlayerArgument( + nodeName: String, + optional: Boolean = false, + block: Argument<*>.() -> Unit = {} +): CommandTree = then( + NonFriendOfflinePlayerArgument(nodeName).setOptional(optional).apply(block) +) + +inline fun Argument<*>.nonFriendOfflinePlayerArgument( + nodeName: String, + optional: Boolean = false, + block: Argument<*>.() -> Unit = {} +): Argument<*> = then( + NonFriendOfflinePlayerArgument(nodeName).setOptional(optional).apply(block) +) + +inline fun CommandAPICommand.nonFriendOfflinePlayerArgument( + nodeName: String, + optional: Boolean = false, + block: Argument<*>.() -> Unit = {} +): CommandAPICommand = + withArguments(NonFriendOfflinePlayerArgument(nodeName).setOptional(optional).apply(block)) \ No newline at end of file diff --git a/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/argument/friend/OfflineFriendArgument.kt b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/argument/friend/OfflineFriendArgument.kt new file mode 100644 index 0000000..e8d7c2b --- /dev/null +++ b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/argument/friend/OfflineFriendArgument.kt @@ -0,0 +1,67 @@ +package dev.slne.surf.friends.paper.command.argument.friend + +import dev.jorel.commandapi.CommandAPICommand +import dev.jorel.commandapi.CommandTree +import dev.jorel.commandapi.arguments.Argument +import dev.jorel.commandapi.arguments.ArgumentSuggestions +import dev.jorel.commandapi.arguments.CustomArgument +import dev.jorel.commandapi.arguments.StringArgument +import dev.slne.surf.friends.api.player.FriendPlayer +import dev.slne.surf.friends.core.service.friendPlayerService +import dev.slne.surf.surfapi.core.api.messages.adventure.uuid +import dev.slne.surf.surfapi.core.api.util.logger +import kotlinx.coroutines.* +import kotlinx.coroutines.future.asDeferred +import kotlinx.coroutines.future.future + +class OfflineFriendArgument(nodeName: String) : + CustomArgument, String>(StringArgument(nodeName), { info -> + scope.future { + friendPlayerService.findOrLoadPlayer(info.input) + }.asDeferred() + }) { + init { + this.replaceSuggestions( + ArgumentSuggestions.stringCollection { info -> + friendPlayerService.players.find { it.uuid == info.sender.uuid() }?.friends?.map { + it.getOtherName( + info.sender.uuid() + ) + } + } + ) + } + + companion object { + private val log = logger() + private val scope = + CoroutineScope(Dispatchers.IO + CoroutineName("OfflineFriendArgument") + CoroutineExceptionHandler { _, throwable -> + log.atWarning() + .withCause(throwable) + .log("An error occurred in OfflineFriendArgument") + }) + } +} + +inline fun CommandTree.offlineFriendArgument( + nodeName: String, + optional: Boolean = false, + block: Argument<*>.() -> Unit = {} +): CommandTree = then( + OfflineFriendArgument(nodeName).setOptional(optional).apply(block) +) + +inline fun Argument<*>.offlineFriendArgument( + nodeName: String, + optional: Boolean = false, + block: Argument<*>.() -> Unit = {} +): Argument<*> = then( + OfflineFriendArgument(nodeName).setOptional(optional).apply(block) +) + +inline fun CommandAPICommand.offlineFriendArgument( + nodeName: String, + optional: Boolean = false, + block: Argument<*>.() -> Unit = {} +): CommandAPICommand = + withArguments(OfflineFriendArgument(nodeName).setOptional(optional).apply(block)) \ No newline at end of file diff --git a/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/argument/request/ReceivedFriendRequestArgument.kt b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/argument/request/ReceivedFriendRequestArgument.kt new file mode 100644 index 0000000..0bbef0c --- /dev/null +++ b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/argument/request/ReceivedFriendRequestArgument.kt @@ -0,0 +1,60 @@ +package dev.slne.surf.friends.paper.command.argument.request + +import dev.jorel.commandapi.CommandAPICommand +import dev.jorel.commandapi.CommandTree +import dev.jorel.commandapi.arguments.Argument +import dev.jorel.commandapi.arguments.ArgumentSuggestions +import dev.jorel.commandapi.arguments.CustomArgument +import dev.jorel.commandapi.arguments.StringArgument +import dev.slne.surf.friends.api.friend.FriendRequest +import dev.slne.surf.friends.core.service.friendPlayerService +import dev.slne.surf.surfapi.core.api.messages.adventure.buildText +import dev.slne.surf.surfapi.core.api.messages.adventure.uuid + +class ReceivedFriendRequestArgument(nodeName: String) : + CustomArgument(StringArgument(nodeName), { info -> + val senderPlayer = friendPlayerService.players.firstOrNull { it.uuid == info.sender.uuid() } + ?: throw CustomArgumentException.fromAdventureComponent( + buildText { + appendErrorPrefix() + error("Dein Spielerprofil konnte nicht gefunden werden.") + }) + + senderPlayer.receivedFriendRequests.firstOrNull { it.senderName == info.input } + ?: throw CustomArgumentException.fromAdventureComponent( + buildText { + appendErrorPrefix() + error("Du hast keine Freundschaftsanfrage von diesem Spieler erhalten.") + }) + }) { + init { + this.replaceSuggestions( + ArgumentSuggestions.stringCollection { sender -> + friendPlayerService.players.first { it.uuid == sender.sender.uuid() }.receivedFriendRequests.map { it.senderName } + } + ) + } +} + +inline fun CommandTree.receivedFriendRequestArgument( + nodeName: String, + optional: Boolean = false, + block: Argument<*>.() -> Unit = {} +): CommandTree = then( + ReceivedFriendRequestArgument(nodeName).setOptional(optional).apply(block) +) + +inline fun Argument<*>.receivedFriendRequestArgument( + nodeName: String, + optional: Boolean = false, + block: Argument<*>.() -> Unit = {} +): Argument<*> = then( + ReceivedFriendRequestArgument(nodeName).setOptional(optional).apply(block) +) + +inline fun CommandAPICommand.receivedFriendRequestArgument( + nodeName: String, + optional: Boolean = false, + block: Argument<*>.() -> Unit = {} +): CommandAPICommand = + withArguments(ReceivedFriendRequestArgument(nodeName).setOptional(optional).apply(block)) \ No newline at end of file diff --git a/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/argument/request/SentFriendRequestArgument.kt b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/argument/request/SentFriendRequestArgument.kt new file mode 100644 index 0000000..46dbf64 --- /dev/null +++ b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/argument/request/SentFriendRequestArgument.kt @@ -0,0 +1,61 @@ +package dev.slne.surf.friends.paper.command.argument.request + +import dev.jorel.commandapi.CommandAPICommand +import dev.jorel.commandapi.CommandTree +import dev.jorel.commandapi.arguments.Argument +import dev.jorel.commandapi.arguments.ArgumentSuggestions +import dev.jorel.commandapi.arguments.CustomArgument +import dev.jorel.commandapi.arguments.StringArgument +import dev.slne.surf.friends.api.friend.FriendRequest +import dev.slne.surf.friends.core.service.friendPlayerService +import dev.slne.surf.surfapi.core.api.messages.adventure.buildText +import dev.slne.surf.surfapi.core.api.messages.adventure.uuid + +class SentFriendRequestArgument(nodeName: String) : + CustomArgument(StringArgument(nodeName), { info -> + val senderPlayer = + friendPlayerService.players.firstOrNull { it.uuid == info.sender.uuid() } + ?: throw CustomArgumentException.fromAdventureComponent( + buildText { + appendErrorPrefix() + error("Dein Spielerprofil konnte nicht gefunden werden.") + }) + + senderPlayer.sentFriendRequests.firstOrNull { it.receiverName == info.input } + ?: throw CustomArgumentException.fromAdventureComponent( + buildText { + appendErrorPrefix() + error("Du hast keine Freundschaftsanfrage an diesen Spieler gesendet.") + }) + }) { + init { + this.replaceSuggestions( + ArgumentSuggestions.stringCollection { sender -> + friendPlayerService.players.first { it.uuid == sender.sender.uuid() }.sentFriendRequests.map { it.receiverName } + } + ) + } +} + +inline fun CommandTree.sentFriendRequestArgument( + nodeName: String, + optional: Boolean = false, + block: Argument<*>.() -> Unit = {} +): CommandTree = then( + SentFriendRequestArgument(nodeName).setOptional(optional).apply(block) +) + +inline fun Argument<*>.sentFriendRequestArgument( + nodeName: String, + optional: Boolean = false, + block: Argument<*>.() -> Unit = {} +): Argument<*> = then( + SentFriendRequestArgument(nodeName).setOptional(optional).apply(block) +) + +inline fun CommandAPICommand.sentFriendRequestArgument( + nodeName: String, + optional: Boolean = false, + block: Argument<*>.() -> Unit = {} +): CommandAPICommand = + withArguments(SentFriendRequestArgument(nodeName).setOptional(optional).apply(block)) \ No newline at end of file diff --git a/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/friend-command-util.kt b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/friend-command-util.kt new file mode 100644 index 0000000..89ce2ac --- /dev/null +++ b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/command/friend-command-util.kt @@ -0,0 +1,194 @@ +package dev.slne.surf.friends.paper.command + +import dev.slne.surf.core.api.common.player.SurfPlayer +import dev.slne.surf.core.api.common.surfCoreApi +import dev.slne.surf.friends.api.friend.FriendRequest +import dev.slne.surf.friends.api.friend.Friendship +import dev.slne.surf.friends.api.friend.friendRequest +import dev.slne.surf.friends.api.friend.friendship +import dev.slne.surf.friends.core.loader.redisApi +import dev.slne.surf.friends.core.service.friendRequestService +import dev.slne.surf.friends.core.service.friendShipService +import dev.slne.surf.friends.paper.redis.event.FriendNotifyRedisEvent +import dev.slne.surf.friends.paper.redis.event.FriendRequestNotifyRedisEvent +import dev.slne.surf.friends.paper.util.friendPlayer +import dev.slne.surf.surfapi.core.api.font.toSmallCaps +import dev.slne.surf.surfapi.core.api.messages.adventure.buildText +import dev.slne.surf.surfapi.core.api.messages.adventure.clickRunsCommand +import dev.slne.surf.surfapi.core.api.messages.adventure.sendText +import dev.slne.surf.surfapi.core.api.messages.pagination.Pagination +import net.kyori.adventure.text.format.TextDecoration +import org.bukkit.entity.Player +import java.util.* + +suspend fun addFriend(player: Player, target: SurfPlayer?, rawTarget: String) { + if (target == null) { + player.sendText { + appendErrorPrefix() + error("Der Spieler wurde nicht gefunden.") + } + return + } + + if (target.uuid == player.uniqueId) { + player.sendText { + appendErrorPrefix() + error("Du kannst dich nicht selbst als Freund hinzufügen.") + } + return + } + + val friendPlayer = player.friendPlayer + + if (friendPlayer.hasSentFriendRequest(target.uuid)) { + player.sendText { + appendErrorPrefix() + error("Du hast diesem Spieler bereits eine Freundschaftsanfrage gesendet.") + } + return + } + + if (friendPlayer.hasFriend(target.uuid)) { + player.sendText { + appendErrorPrefix() + error("Du bist bereits mit diesem Spieler befreundet.") + } + return + } + + val existingRequest = friendPlayer.receivedFriendRequests.find { it.senderUuid == target.uuid } + + if (existingRequest != null) { + acceptFriend(player, existingRequest) + return + } + + val friendRequest = friendRequest( + senderUuid = player.uniqueId, + receiverUuid = target.uuid, + senderName = player.name, + receiverName = target.lastKnownName ?: rawTarget + ) + + friendRequestService.saveFriendRequest(friendRequest) + + player.sendText { + appendSuccessPrefix() + success("Du hast eine Freundschaftsanfrage an ") + variableValue(target.lastKnownName ?: rawTarget) + success(" gesendet.") + } + + redisApi.publishEvent( + FriendRequestNotifyRedisEvent( + playerUuid = target.uuid, + buildText { + appendInfoPrefix() + info("Du hast eine Freundschaftsanfrage von ") + variableValue(player.name) + info(" erhalten.") + appendSpace() + append { + darkSpacer("[") + success("Annehmen") + darkSpacer("]") + clickRunsCommand("/friend accept ${player.name}") + } + appendSpace() + append { + darkSpacer("[") + error("Ablehnen") + darkSpacer("]") + clickRunsCommand("/friend decline ${player.name}") + } + } + )) +} + +suspend fun acceptFriend(player: Player, receivedRequest: FriendRequest) { + val friendPlayer = player.friendPlayer + + if (friendPlayer.hasFriend(receivedRequest.senderUuid)) { + player.sendText { + appendErrorPrefix() + error("Du bist bereits mit diesem Spieler befreundet.") + } + return + } + + val friendship = friendship( + requestedBy = receivedRequest.senderUuid, + acceptedBy = receivedRequest.receiverUuid, + requesterName = receivedRequest.senderName, + acceptorName = receivedRequest.receiverName + ) + + friendRequestService.deleteFriendRequest(receivedRequest) + friendShipService.saveFriendShip(friendship) + + player.sendText { + appendSuccessPrefix() + success("Du hast die Freundschaftsanfrage von ") + variableValue(receivedRequest.senderName) + success(" angenommen.") + } + + redisApi.publishEvent( + FriendNotifyRedisEvent( + playerUuid = receivedRequest.senderUuid, + buildText { + appendInfoPrefix() + info("Deine Freundschaftsanfrage an ") + variableValue(receivedRequest.receiverName) + info(" wurde angenommen.") + } + )) +} + +fun listFriends(player: Player) { + val friendPlayer = player.friendPlayer + + if (friendPlayer.friends.isEmpty()) { + player.sendText { + appendInfoPrefix() + info("Du hast keine Freunde.") + } + return + } + + player.sendText { + appendNewline() + append( + friendPagination(player.uniqueId).renderComponent( + friendPlayer.friends + .sortedByDescending { + it.getOtherUuid(player.uniqueId).currentServerName() != null + } + .sortedBy { it.getOtherName(player.uniqueId) }) + ) + } +} + +private fun friendPagination(ownUuid: UUID) = Pagination { + title { primary("Deine Freunde".toSmallCaps(), TextDecoration.BOLD) } + + rowRenderer { friendship, _ -> + listOf(buildText { + spacer("-") + appendSpace() + variableValue(friendship.getOtherName(ownUuid)) + appendSpace() + spacer("(") + friendship.getOtherUuid(ownUuid).currentServerName().let { + if (it != null) { + success("Online auf $it") + } else { + error("Offline") + } + } + spacer(")") + }) + } +} + +fun UUID.currentServerName() = surfCoreApi.getPlayer(this)?.currentServer?.displayName \ No newline at end of file diff --git a/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/hook/SettingsHook.kt b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/hook/SettingsHook.kt new file mode 100644 index 0000000..1fbbdc8 --- /dev/null +++ b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/hook/SettingsHook.kt @@ -0,0 +1,27 @@ +package dev.slne.surf.friends.paper.hook + +import dev.slne.surf.settings.api.surfSettingsApi +import org.bukkit.Bukkit +import java.util.* + +object SettingsHook { + fun isEnabled() = Bukkit.getPluginManager().isPluginEnabled("surf-settings-paper") + + fun hasFriendRequestsEnabled(playerUuid: UUID): Boolean { + return if (isEnabled()) { + surfSettingsApi.getPlayerSetting(playerUuid, "friend_requests")?.getBoolean() + ?: true + } else { + true + } + } + + fun hasFriendNotifyEnabled(playerUuid: UUID): Boolean { + return if (isEnabled()) { + surfSettingsApi.getPlayerSetting(playerUuid, "friend_notify")?.getBoolean() + ?: true + } else { + true + } + } +} \ No newline at end of file diff --git a/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/listener/PlayerConnectionListener.kt b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/listener/PlayerConnectionListener.kt new file mode 100644 index 0000000..33587f2 --- /dev/null +++ b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/listener/PlayerConnectionListener.kt @@ -0,0 +1,49 @@ +package dev.slne.surf.friends.paper.listener + +import dev.slne.surf.friends.core.service.friendPlayerService +import dev.slne.surf.friends.paper.util.friendPlayer +import dev.slne.surf.surfapi.core.api.messages.adventure.sendText +import io.papermc.paper.event.connection.configuration.AsyncPlayerConnectionConfigureEvent +import kotlinx.coroutines.runBlocking +import org.bukkit.event.EventHandler +import org.bukkit.event.Listener +import org.bukkit.event.player.PlayerJoinEvent +import org.bukkit.event.player.PlayerQuitEvent + +@Suppress("UnstableApiUsage") +object PlayerConnectionListener : Listener { + @EventHandler + fun onConfigure(event: AsyncPlayerConnectionConfigureEvent) { + runBlocking { + friendPlayerService.cachePlayer(friendPlayerService.loadOrCreatePlayer(event.connection.profile)) + } + } + + @EventHandler + fun onJoin(event: PlayerJoinEvent) { + val friendPlayer = event.player.friendPlayer + + if (friendPlayer.receivedFriendRequests.isNotEmpty()) { + event.player.sendText { + appendInfoPrefix() + info("Du hast noch ") + variableValue(friendPlayer.receivedFriendRequests.size) + info(" offene Freundschaftsanfragen.") + } + } + + if (friendPlayer.getOnlineFriendCount() > 0) { + event.player.sendText { + appendInfoPrefix() + info("Derzeit sind ") + variableValue(friendPlayer.getOnlineFriendCount()) + info(" Freunde online.") + } + } + } + + @EventHandler + fun onQuit(event: PlayerQuitEvent) { + friendPlayerService.invalidatePlayer(event.player.uniqueId) + } +} \ No newline at end of file diff --git a/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/listener/SurfPlayerListener.kt b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/listener/SurfPlayerListener.kt new file mode 100644 index 0000000..5ed66ab --- /dev/null +++ b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/listener/SurfPlayerListener.kt @@ -0,0 +1,53 @@ +package dev.slne.surf.friends.paper.listener + +import com.github.shynixn.mccoroutine.folia.launch +import dev.slne.surf.core.api.common.event.SurfEventHandler +import dev.slne.surf.core.api.common.event.SurfPlayerConnectEvent +import dev.slne.surf.core.api.common.event.SurfPlayerDisconnectEvent +import dev.slne.surf.friends.core.service.friendPlayerService +import dev.slne.surf.friends.paper.hook.SettingsHook +import dev.slne.surf.friends.paper.plugin +import dev.slne.surf.surfapi.core.api.messages.adventure.sendText +import org.bukkit.Bukkit + +object SurfPlayerListener { + @SurfEventHandler + fun onNetworkConnect(event: SurfPlayerConnectEvent) { + plugin.launch { + val friendPlayer = + friendPlayerService.findOrLoadPlayer(event.player.uuid) ?: return@launch + + friendPlayer.friends + .mapNotNull { Bukkit.getPlayer(it.getOtherUuid(friendPlayer.uuid)) } + .filter { SettingsHook.hasFriendNotifyEnabled(it.uniqueId) } + .forEach { + it.sendText { + appendInfoPrefix() + info("Dein Freund ") + variableValue(friendPlayer.name) + info(" ist nun online.") + } + } + } + } + + @SurfEventHandler + fun onNetworkDisconnect(event: SurfPlayerDisconnectEvent) { + plugin.launch { + val friendPlayer = + friendPlayerService.findOrLoadPlayer(event.player.uuid) ?: return@launch + + friendPlayer.friends + .mapNotNull { Bukkit.getPlayer(it.getOtherUuid(friendPlayer.uuid)) } + .filter { SettingsHook.hasFriendNotifyEnabled(it.uniqueId) } + .forEach { + it.sendText { + appendInfoPrefix() + info("Dein Freund ") + variableValue(friendPlayer.name) + info(" ist nun offline.") + } + } + } + } +} \ No newline at end of file diff --git a/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/permission/PermissionRegistry.kt b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/permission/PermissionRegistry.kt new file mode 100644 index 0000000..5653cd9 --- /dev/null +++ b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/permission/PermissionRegistry.kt @@ -0,0 +1,10 @@ +package dev.slne.surf.friends.paper.permission + +import dev.slne.surf.surfapi.bukkit.api.permission.PermissionRegistry + +object PermissionRegistry : PermissionRegistry() { + const val PREFIX = "surf.friends" + const val PREFIX_COMMAND = "$PREFIX.command" + + val COMMAND = create(PREFIX_COMMAND) +} \ No newline at end of file diff --git a/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/redis/FriendRedisListener.kt b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/redis/FriendRedisListener.kt new file mode 100644 index 0000000..ce6f04b --- /dev/null +++ b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/redis/FriendRedisListener.kt @@ -0,0 +1,36 @@ +package dev.slne.surf.friends.paper.redis + +import dev.slne.surf.friends.paper.hook.SettingsHook +import dev.slne.surf.friends.paper.redis.event.FriendNotifyRedisEvent +import dev.slne.surf.friends.paper.redis.event.FriendRequestNotifyRedisEvent +import dev.slne.surf.redis.event.OnRedisEvent +import dev.slne.surf.surfapi.core.api.messages.adventure.sendText +import org.bukkit.Bukkit + +object FriendRedisListener { + @OnRedisEvent + fun onFriendNotifyMessage(event: FriendNotifyRedisEvent) { + val player = Bukkit.getPlayer(event.playerUuid) ?: return + + if (!SettingsHook.hasFriendNotifyEnabled(player.uniqueId)) { + return + } + + player.sendText { + append(event.message) + } + } + + @OnRedisEvent + fun onFriendRequestNotify(event: FriendRequestNotifyRedisEvent) { + val player = Bukkit.getPlayer(event.playerUuid) ?: return + + if (!SettingsHook.hasFriendRequestsEnabled(player.uniqueId)) { + return + } + + player.sendText { + append(event.message) + } + } +} \ No newline at end of file diff --git a/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/redis/event/FriendNotifyRedisEvent.kt b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/redis/event/FriendNotifyRedisEvent.kt new file mode 100644 index 0000000..b6bf9d1 --- /dev/null +++ b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/redis/event/FriendNotifyRedisEvent.kt @@ -0,0 +1,13 @@ +package dev.slne.surf.friends.paper.redis.event + +import dev.slne.surf.redis.event.RedisEvent +import dev.slne.surf.surfapi.core.api.serializer.adventure.component.SerializableComponent +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import java.util.* + +@Serializable +data class FriendNotifyRedisEvent( + val playerUuid: @Contextual UUID, + val message: SerializableComponent +) : RedisEvent() diff --git a/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/redis/event/FriendRequestNotifyRedisEvent.kt b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/redis/event/FriendRequestNotifyRedisEvent.kt new file mode 100644 index 0000000..d26d8f2 --- /dev/null +++ b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/redis/event/FriendRequestNotifyRedisEvent.kt @@ -0,0 +1,13 @@ +package dev.slne.surf.friends.paper.redis.event + +import dev.slne.surf.redis.event.RedisEvent +import dev.slne.surf.surfapi.core.api.serializer.adventure.component.SerializableComponent +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import java.util.* + +@Serializable +data class FriendRequestNotifyRedisEvent( + val playerUuid: @Contextual UUID, + val message: SerializableComponent +) : RedisEvent() diff --git a/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/util/friend-util.kt b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/util/friend-util.kt new file mode 100644 index 0000000..ac3c043 --- /dev/null +++ b/surf-friends-paper/src/main/kotlin/dev/slne/surf/friends/paper/util/friend-util.kt @@ -0,0 +1,8 @@ +package dev.slne.surf.friends.paper.util + +import dev.slne.surf.friends.core.service.friendPlayerService +import org.bukkit.entity.Player + +val Player.friendPlayer + get() = friendPlayerService.players.find { it.uuid == this.uniqueId } + ?: error("Player ${this.name} is not cached as a FriendPlayer") \ No newline at end of file diff --git a/surf-friends-velocity/build.gradle.kts b/surf-friends-velocity/build.gradle.kts deleted file mode 100644 index 49bd9ce..0000000 --- a/surf-friends-velocity/build.gradle.kts +++ /dev/null @@ -1,25 +0,0 @@ -plugins { - id("dev.slne.surf.surfapi.gradle.velocity") -} - -surfVelocityApi { - withSurfRedis() - withCoreVelocity() -} - -velocityPluginFile { - main = "dev.slne.surf.friends.velocity.SurfFriendsPlugin" - name = "SurfFriends" - id = "surf-friends" - authors = listOf("red") - version = "${rootProject.version}" - - pluginDependencies { - register("commandapi") - } -} - -dependencies { - api(project(":surf-friends-core")) - runtimeOnly(project(":surf-friends-fallback")) -} \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/SurfFriendsPlugin.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/SurfFriendsPlugin.kt deleted file mode 100644 index c2d161f..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/SurfFriendsPlugin.kt +++ /dev/null @@ -1,62 +0,0 @@ -package dev.slne.surf.friends.velocity - -import com.github.shynixn.mccoroutine.velocity.SuspendingPluginContainer -import com.google.inject.Inject -import com.velocitypowered.api.event.Subscribe -import com.velocitypowered.api.event.proxy.ProxyInitializeEvent -import com.velocitypowered.api.event.proxy.ProxyShutdownEvent -import com.velocitypowered.api.plugin.PluginContainer -import com.velocitypowered.api.plugin.annotation.DataDirectory -import com.velocitypowered.api.proxy.ProxyServer -import dev.slne.surf.friends.core.service.databaseService -import dev.slne.surf.friends.velocity.command.friendCommand -import dev.slne.surf.friends.velocity.command.subcommand.friend.FriendListCommand -import dev.slne.surf.friends.velocity.command.subcommand.request.FriendRequestSendCommand -import dev.slne.surf.friends.velocity.listener.ConnectionListener -import dev.slne.surf.friends.velocity.redis.listener.FriendRequestRedisListener -import dev.slne.surf.friends.velocity.redis.listener.FriendshipRedisListener -import dev.slne.surf.redis.RedisApi -import java.nio.file.Path - -class SurfFriendsPlugin -@Inject -constructor( - val proxy: ProxyServer, - val container: PluginContainer, - @param:DataDirectory val dataDirectory: Path, - suspendingPluginContainer: SuspendingPluginContainer -) { - init { - suspendingPluginContainer.initialize(this) - INSTANCE = this - } - - @Subscribe - fun onProxyInitialization(event: ProxyInitializeEvent) { - proxy.eventManager.register(this, ConnectionListener()) - - databaseService.connect(dataDirectory) - redisApi = RedisApi.create() - redisApi.subscribeToEvents(FriendshipRedisListener) - redisApi.subscribeToEvents(FriendRequestRedisListener) - redisApi.freezeAndConnect() - - friendCommand() - FriendRequestSendCommand("fa").register() - FriendListCommand("fl").register() - } - - @Subscribe - fun onProxyShutdown(event: ProxyShutdownEvent) { - redisApi.disconnect() - } - - companion object { - lateinit var redisApi: RedisApi - lateinit var INSTANCE: SurfFriendsPlugin - } -} - -val container get() = SurfFriendsPlugin.INSTANCE.container -val plugin get() = SurfFriendsPlugin.INSTANCE -val redisApi get() = SurfFriendsPlugin.redisApi \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/FriendCommand.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/FriendCommand.kt deleted file mode 100644 index adb3479..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/FriendCommand.kt +++ /dev/null @@ -1,29 +0,0 @@ -package dev.slne.surf.friends.velocity.command - -import dev.jorel.commandapi.kotlindsl.commandAPICommand -import dev.jorel.commandapi.kotlindsl.subcommand -import dev.slne.surf.friends.velocity.command.subcommand.friend.FriendListCommand -import dev.slne.surf.friends.velocity.command.subcommand.friend.friendInfoCommand -import dev.slne.surf.friends.velocity.command.subcommand.friend.friendJumpCommand -import dev.slne.surf.friends.velocity.command.subcommand.friend.friendRemoveCommand -import dev.slne.surf.friends.velocity.command.subcommand.request.* -import dev.slne.surf.friends.velocity.command.subcommand.toggle.friendToggleCommand -import dev.slne.surf.friends.velocity.util.FriendPermissionRegistry - -fun friendCommand() = commandAPICommand("friend") { - withPermission(FriendPermissionRegistry.COMMAND_FRIEND) - withAliases("f") - - friendRemoveCommand() - friendInfoCommand() - friendJumpCommand() - - friendRequestAcceptCommand() - friendRequestDeclineCommand() - friendRequestRevokeCommand() - friendRequestListCommand() - friendToggleCommand() - - subcommand(FriendListCommand("list")) - subcommand(FriendRequestSendCommand("add")) -} \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/argument/PlayerStringArgument.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/argument/PlayerStringArgument.kt deleted file mode 100644 index 59a809b..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/argument/PlayerStringArgument.kt +++ /dev/null @@ -1,43 +0,0 @@ -package dev.slne.surf.friends.velocity.command.argument - -import com.mojang.brigadier.arguments.StringArgumentType -import com.mojang.brigadier.context.CommandContext -import dev.jorel.commandapi.CommandAPICommand -import dev.jorel.commandapi.arguments.Argument -import dev.jorel.commandapi.arguments.ArgumentSuggestions -import dev.jorel.commandapi.arguments.CommandAPIArgumentType -import dev.jorel.commandapi.executors.CommandArguments -import dev.slne.surf.core.api.common.surfCoreApi - -class PlayerStringArgument(nodeName: String) : - Argument(nodeName, StringArgumentType.string()) { - override fun getPrimitiveType(): Class { - return String::class.java - } - - override fun getArgumentType(): CommandAPIArgumentType { - return CommandAPIArgumentType.PRIMITIVE_TEXT - } - - override fun parseArgument( - cmdCtx: CommandContext, - key: String, - previousArgs: CommandArguments - ): String { - return StringArgumentType.getString(cmdCtx, key) - } - - init { - replaceSuggestions(ArgumentSuggestions.stringCollection { - surfCoreApi.getOnlinePlayers().mapNotNull { it.lastKnownName } - }) - } -} - -inline fun CommandAPICommand.playerStringArgument( - nodeName: String, - optional: Boolean = false, - block: Argument<*>.() -> Unit = {} -): CommandAPICommand = withArguments( - PlayerStringArgument(nodeName).setOptional(optional).apply(block) -) \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/friend/FriendInfoCommand.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/friend/FriendInfoCommand.kt deleted file mode 100644 index 94aea7a..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/friend/FriendInfoCommand.kt +++ /dev/null @@ -1,79 +0,0 @@ -package dev.slne.surf.friends.velocity.command.subcommand.friend - -import com.github.shynixn.mccoroutine.velocity.launch -import dev.jorel.commandapi.CommandAPICommand -import dev.jorel.commandapi.kotlindsl.getValue -import dev.jorel.commandapi.kotlindsl.playerExecutor -import dev.jorel.commandapi.kotlindsl.subcommand -import dev.slne.surf.friends.core.service.friendService -import dev.slne.surf.friends.velocity.command.argument.playerStringArgument -import dev.slne.surf.friends.velocity.container -import dev.slne.surf.friends.velocity.util.FriendPermissionRegistry -import dev.slne.surf.friends.velocity.util.format -import dev.slne.surf.friends.velocity.util.getUsernameAsync -import dev.slne.surf.friends.velocity.util.sendText -import dev.slne.surf.surfapi.core.api.font.toSmallCaps -import dev.slne.surf.surfapi.core.api.messages.adventure.sendText -import dev.slne.surf.surfapi.core.api.service.PlayerLookupService -import net.kyori.adventure.text.format.TextDecoration - -fun CommandAPICommand.friendInfoCommand() = subcommand("info") { - withPermission(FriendPermissionRegistry.COMMAND_FRIEND_INFO) - playerStringArgument("target") - playerExecutor { player, args -> - container.launch { - val target: String by args - val targetUuid = PlayerLookupService.getUuid(target) ?: return@launch run { - player.uniqueId.sendText { - error("Der Spieler $target wurde nicht gefunden.") - } - } - - val friendShip = friendService.getFriendship(player.uniqueId, targetUuid) - - if (targetUuid == player.uniqueId) { - player.uniqueId.sendText { - error("Du kannst keine Informationen über dich selbst abrufen.") - } - return@launch - } - - if (friendShip == null) { - player.uniqueId.sendText { - error("Du bist nicht mit $target befreundet.") - } - return@launch - } - - val userName = friendShip.userUuid.getUsernameAsync() - val targetName = friendShip.friendUuid.getUsernameAsync() - - player.sendText { - info("Freundschaftsinformationen".toSmallCaps()) - appendNewline() - append { - info("| ") - decorate(TextDecoration.BOLD) - } - variableKey("Spieler: ".toSmallCaps()) - variableValue(userName) - appendNewline() - - append { - info("| ") - decorate(TextDecoration.BOLD) - } - variableKey("Freund: ".toSmallCaps()) - variableValue(targetName) - appendNewline() - - append { - info("| ") - decorate(TextDecoration.BOLD) - } - variableKey("Befreundet seit: ".toSmallCaps()) - variableValue(friendShip.createdAt.format()) - } - } - } -} \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/friend/FriendJumpCommand.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/friend/FriendJumpCommand.kt deleted file mode 100644 index 0edd52d..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/friend/FriendJumpCommand.kt +++ /dev/null @@ -1,68 +0,0 @@ -package dev.slne.surf.friends.velocity.command.subcommand.friend - -import com.github.shynixn.mccoroutine.velocity.launch -import dev.jorel.commandapi.CommandAPICommand -import dev.jorel.commandapi.kotlindsl.getValue -import dev.jorel.commandapi.kotlindsl.playerExecutor -import dev.jorel.commandapi.kotlindsl.subcommand - -import dev.slne.surf.friends.core.service.friendService -import dev.slne.surf.friends.velocity.command.argument.playerStringArgument -import dev.slne.surf.friends.velocity.container -import dev.slne.surf.friends.velocity.plugin -import dev.slne.surf.friends.velocity.util.FriendPermissionRegistry -import dev.slne.surf.friends.velocity.util.isOnline -import dev.slne.surf.friends.velocity.util.sendText -import dev.slne.surf.surfapi.core.api.service.PlayerLookupService -import kotlin.jvm.optionals.getOrNull - -fun CommandAPICommand.friendJumpCommand() = subcommand("jump") { - withPermission(FriendPermissionRegistry.COMMAND_FRIEND_JUMP) - playerStringArgument("target") - playerExecutor { player, args -> - container.launch { - val target: String by args - val targetUuid = PlayerLookupService.getUuid(target) ?: return@launch run { - player.uniqueId.sendText { - error("Der Spieler $target wurde nicht gefunden.") - } - } - - val friendShip = friendService.getFriendship(player.uniqueId, targetUuid) - - if (friendShip == null) { - player.uniqueId.sendText { - error("Du bist nicht mit $target befreundet.") - } - return@launch - } - - if (targetUuid.isOnline()) { - val onlineFriend = - plugin.proxy.getPlayer(targetUuid).getOrNull() ?: return@launch run { - player.uniqueId.sendText { - error("Der Spieler $target ist nicht online.") - } - } - - player.createConnectionRequest( - onlineFriend.currentServer.getOrNull()?.server ?: return@launch run { - player.uniqueId.sendText { - error("Der Spieler $target ist nicht auf einem Server.") - } - }).fireAndForget() - - player.uniqueId.sendText { - success("Du bist ") - variableValue(target) - success(" auf den Server gefolgt.") - } - return@launch - } - - player.uniqueId.sendText { - error("Der Spieler $target ist nicht online.") - } - } - } -} \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/friend/FriendListCommand.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/friend/FriendListCommand.kt deleted file mode 100644 index 3308fd4..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/friend/FriendListCommand.kt +++ /dev/null @@ -1,93 +0,0 @@ -package dev.slne.surf.friends.velocity.command.subcommand.friend - -import com.github.shynixn.mccoroutine.velocity.launch -import dev.jorel.commandapi.CommandAPICommand -import dev.jorel.commandapi.kotlindsl.integerArgument -import dev.jorel.commandapi.kotlindsl.playerExecutor -import dev.slne.surf.friends.core.service.friendService -import dev.slne.surf.friends.velocity.container -import dev.slne.surf.friends.velocity.util.* -import dev.slne.surf.surfapi.core.api.font.toSmallCaps -import dev.slne.surf.surfapi.core.api.messages.CommonComponents -import dev.slne.surf.surfapi.core.api.messages.adventure.buildText -import dev.slne.surf.surfapi.core.api.messages.adventure.clickRunsCommand -import dev.slne.surf.surfapi.core.api.messages.adventure.sendText -import dev.slne.surf.surfapi.core.api.messages.pagination.Pagination -import kotlinx.coroutines.async -import kotlinx.coroutines.awaitAll -import net.kyori.adventure.text.format.TextDecoration -import kotlin.jvm.optionals.getOrNull - -class FriendListCommand(commandName: String) : CommandAPICommand(commandName) { - init { - withPermission(FriendPermissionRegistry.COMMAND_FRIEND_LIST) - integerArgument("page", 1, optional = true) - playerExecutor { player, args -> - container.launch { - val friendList = friendService.getFriendships(player.uniqueId) - val page = args.getOrDefaultUnchecked("page", 1) - - if (friendList.isEmpty()) { - player.uniqueId.sendText { - error("Du hast keine Freunde.") - } - return@launch - } - - val friendEntries = friendList.sortedByDescending { - it.friendUuid.isOnline() - }.map { - async { - it to it.friendUuid.getUsernameAsync() - } - }.awaitAll().map { - LocalFriendEntry( - it.second, - it.first.friendUuid.isOnline(), - it.first.friendUuid.toPlayer()?.currentServer?.getOrNull()?.serverInfo?.name - ?: "Unbekannt" - ) - } - - val pagination = Pagination { - title { primary("Freundesliste".toSmallCaps(), TextDecoration.BOLD) } - - rowRenderer { row, _ -> - listOf( - buildText { - append(CommonComponents.EM_DASH) - appendSpace() - variableKey(row.friendName) - appendSpace() - if (row.isOnline) { - appendSpace() - success("(Online auf ${row.onlineServer})") - } else { - appendSpace() - error("(Offline)") - } - hoverEvent(buildText { - info("Klicke hier, um ") - variableValue(row.friendName) - info(" hinterher zuspringen.") - }) - clickRunsCommand("/friend jump ${row.friendName}") - } - ) - } - } - - - player.sendText { - append(pagination.renderComponent(friendEntries, page)) - } - } - } - } -} - -private data class LocalFriendEntry( - val friendName: String, - val isOnline: Boolean, - val onlineServer: String -) \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/friend/FriendRemoveCommand.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/friend/FriendRemoveCommand.kt deleted file mode 100644 index 6910706..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/friend/FriendRemoveCommand.kt +++ /dev/null @@ -1,53 +0,0 @@ -package dev.slne.surf.friends.velocity.command.subcommand.friend - -import com.github.shynixn.mccoroutine.velocity.launch -import dev.jorel.commandapi.CommandAPICommand -import dev.jorel.commandapi.kotlindsl.getValue -import dev.jorel.commandapi.kotlindsl.playerExecutor -import dev.jorel.commandapi.kotlindsl.subcommand -import dev.slne.surf.friends.core.service.friendService -import dev.slne.surf.friends.velocity.command.argument.playerStringArgument -import dev.slne.surf.friends.velocity.container -import dev.slne.surf.friends.velocity.redis.event.FriendRemoveRedisEvent -import dev.slne.surf.friends.velocity.redisApi -import dev.slne.surf.friends.velocity.util.FriendPermissionRegistry -import dev.slne.surf.friends.velocity.util.sendText -import dev.slne.surf.surfapi.core.api.service.PlayerLookupService - -fun CommandAPICommand.friendRemoveCommand() = subcommand("remove") { - withPermission(FriendPermissionRegistry.COMMAND_FRIEND_REMOVE) - playerStringArgument("target") - playerExecutor { player, args -> - container.launch { - val target: String by args - val targetUuid = PlayerLookupService.getUuid(target) ?: return@launch run { - player.uniqueId.sendText { - error("Der Spieler $target wurde nicht gefunden.") - } - } - - val friendShip = friendService.getFriendship(player.uniqueId, targetUuid) - - if (friendShip == null) { - player.uniqueId.sendText { - error("Du bist nicht mit $target befreundet.") - } - return@launch - } - - friendService.removeFriendship(player.uniqueId, targetUuid) - - player.uniqueId.sendText { - success("Du hast die Freundschaft mit ") - variableValue(target) - success(" beendet.") - } - - redisApi.publishEvent( - FriendRemoveRedisEvent( - player.uniqueId, player.username, targetUuid - ) - ) - } - } -} \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/request/FriendRequestAcceptCommand.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/request/FriendRequestAcceptCommand.kt deleted file mode 100644 index 5b7b774..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/request/FriendRequestAcceptCommand.kt +++ /dev/null @@ -1,62 +0,0 @@ -package dev.slne.surf.friends.velocity.command.subcommand.request - -import com.github.shynixn.mccoroutine.velocity.launch -import dev.jorel.commandapi.CommandAPICommand -import dev.jorel.commandapi.kotlindsl.getValue -import dev.jorel.commandapi.kotlindsl.playerExecutor -import dev.jorel.commandapi.kotlindsl.subcommand -import dev.slne.surf.friends.core.service.friendService -import dev.slne.surf.friends.velocity.command.argument.playerStringArgument -import dev.slne.surf.friends.velocity.container -import dev.slne.surf.friends.velocity.redis.event.FriendRequestAcceptRedisEvent -import dev.slne.surf.friends.velocity.redisApi -import dev.slne.surf.friends.velocity.util.FriendPermissionRegistry -import dev.slne.surf.friends.velocity.util.sendText -import dev.slne.surf.surfapi.core.api.service.PlayerLookupService - -fun CommandAPICommand.friendRequestAcceptCommand() = subcommand("accept") { - withPermission(FriendPermissionRegistry.COMMAND_FRIEND_REQUEST_ACCEPT) - playerStringArgument("target") - playerExecutor { player, args -> - container.launch { - val target: String by args - val targetUuid = PlayerLookupService.getUuid(target) ?: return@launch run { - player.uniqueId.sendText { - error("Der Spieler $target wurde nicht gefunden.") - } - } - - val friendRequest = friendService.getFriendRequest(targetUuid, player.uniqueId) - - if (friendRequest == null) { - player.uniqueId.sendText { - error("Du hast keine Freundschaftsanfrage von $target erhalten.") - } - return@launch - } - - val friendShip = friendService.getFriendship(player.uniqueId, targetUuid) - - if (friendShip != null) { - player.uniqueId.sendText { - error("Du bist bereits mit $target befreundet.") - } - return@launch - } - - friendService.acceptFriendRequest(targetUuid, player.uniqueId) - - player.uniqueId.sendText { - success("Du bist nun mit ") - variableValue(target) - success(" befreundet.") - } - - redisApi.publishEvent( - FriendRequestAcceptRedisEvent( - targetUuid, player.uniqueId, player.username - ) - ) - } - } -} \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/request/FriendRequestDeclineCommand.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/request/FriendRequestDeclineCommand.kt deleted file mode 100644 index 69d3415..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/request/FriendRequestDeclineCommand.kt +++ /dev/null @@ -1,53 +0,0 @@ -package dev.slne.surf.friends.velocity.command.subcommand.request - -import com.github.shynixn.mccoroutine.velocity.launch -import dev.jorel.commandapi.CommandAPICommand -import dev.jorel.commandapi.kotlindsl.getValue -import dev.jorel.commandapi.kotlindsl.playerExecutor -import dev.jorel.commandapi.kotlindsl.subcommand -import dev.slne.surf.friends.core.service.friendService -import dev.slne.surf.friends.velocity.command.argument.playerStringArgument -import dev.slne.surf.friends.velocity.container -import dev.slne.surf.friends.velocity.redis.event.FriendRequestDenyRedisEvent -import dev.slne.surf.friends.velocity.redisApi -import dev.slne.surf.friends.velocity.util.FriendPermissionRegistry -import dev.slne.surf.friends.velocity.util.sendText -import dev.slne.surf.surfapi.core.api.service.PlayerLookupService - -fun CommandAPICommand.friendRequestDeclineCommand() = subcommand("decline") { - withPermission(FriendPermissionRegistry.COMMAND_FRIEND_REQUEST_DECLINE) - playerStringArgument("target") - playerExecutor { player, args -> - container.launch { - val target: String by args - val targetUuid = PlayerLookupService.getUuid(target) ?: return@launch run { - player.uniqueId.sendText { - error("Der Spieler $target wurde nicht gefunden.") - } - } - - val friendRequest = friendService.getFriendRequest(targetUuid, player.uniqueId) - - if (friendRequest == null) { - player.uniqueId.sendText { - error("Du hast keine Freundschaftsanfrage von $target erhalten.") - } - return@launch - } - - friendService.declineFriendRequest(targetUuid, player.uniqueId) - - player.uniqueId.sendText { - success("Du hast die Freundschaftsanfrage von ") - variableValue(target) - success(" abgelehnt.") - } - - redisApi.publishEvent( - FriendRequestDenyRedisEvent( - targetUuid, player.uniqueId, player.username - ) - ) - } - } -} \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/request/FriendRequestListCommand.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/request/FriendRequestListCommand.kt deleted file mode 100644 index 6cb3236..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/request/FriendRequestListCommand.kt +++ /dev/null @@ -1,82 +0,0 @@ -package dev.slne.surf.friends.velocity.command.subcommand.request - -import com.github.shynixn.mccoroutine.velocity.launch -import dev.jorel.commandapi.CommandAPICommand -import dev.jorel.commandapi.kotlindsl.integerArgument -import dev.jorel.commandapi.kotlindsl.playerExecutor -import dev.jorel.commandapi.kotlindsl.subcommand -import dev.slne.surf.friends.core.service.friendService -import dev.slne.surf.friends.velocity.container -import dev.slne.surf.friends.velocity.util.FriendPermissionRegistry -import dev.slne.surf.friends.velocity.util.format -import dev.slne.surf.friends.velocity.util.getUsernameAsync -import dev.slne.surf.friends.velocity.util.sendText -import dev.slne.surf.surfapi.core.api.font.toSmallCaps -import dev.slne.surf.surfapi.core.api.messages.CommonComponents -import dev.slne.surf.surfapi.core.api.messages.adventure.buildText -import dev.slne.surf.surfapi.core.api.messages.adventure.clickRunsCommand -import dev.slne.surf.surfapi.core.api.messages.adventure.sendText -import dev.slne.surf.surfapi.core.api.messages.pagination.Pagination -import kotlinx.coroutines.async -import kotlinx.coroutines.awaitAll -import net.kyori.adventure.text.format.TextDecoration - -fun CommandAPICommand.friendRequestListCommand() = subcommand("requests") { - withPermission(FriendPermissionRegistry.COMMAND_FRIEND_REQUEST_LIST) - integerArgument("page", 1, optional = true) - playerExecutor { player, args -> - container.launch { - val friendRequests = friendService.getReceivedFriendRequests(player.uniqueId) - .sortedByDescending { it.sentAt } - val page = args.getOrDefaultUnchecked("page", 1) - - if (friendRequests.isEmpty()) { - player.uniqueId.sendText { - error("Du hast keine Freundschaftsanfragen offen.") - } - return@launch - } - - val requesterEntries = friendRequests.map { - async { - it to it.senderUuid.getUsernameAsync() - } - }.awaitAll().map { - LocalFriendRequest( - it.second, - it.first.sentAt - ) - } - - val pagination = Pagination { - title { primary("Offene Freundschaftsanfragen".toSmallCaps(), TextDecoration.BOLD) } - - rowRenderer { row, _ -> - listOf( - buildText { - append(CommonComponents.EM_DASH) - appendSpace() - variableKey(row.requesterName) - spacer(" (${row.sentAt.format()})") - hoverEvent(buildText { - info("Klicke hier, um die Freundschaftsanfrage von ") - variableValue(row.requesterName) - info(" anzunehmen.") - }) - clickRunsCommand("/friend accept ${row.requesterName}") - } - ) - } - } - - player.sendText { - append(pagination.renderComponent(requesterEntries, page)) - } - } - } -} - -private data class LocalFriendRequest( - val requesterName: String, - val sentAt: Long -) \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/request/FriendRequestRevokeCommand.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/request/FriendRequestRevokeCommand.kt deleted file mode 100644 index 1e9a693..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/request/FriendRequestRevokeCommand.kt +++ /dev/null @@ -1,53 +0,0 @@ -package dev.slne.surf.friends.velocity.command.subcommand.request - -import com.github.shynixn.mccoroutine.velocity.launch -import dev.jorel.commandapi.CommandAPICommand -import dev.jorel.commandapi.kotlindsl.getValue -import dev.jorel.commandapi.kotlindsl.playerExecutor -import dev.jorel.commandapi.kotlindsl.subcommand -import dev.slne.surf.friends.core.service.friendService -import dev.slne.surf.friends.velocity.command.argument.playerStringArgument -import dev.slne.surf.friends.velocity.container -import dev.slne.surf.friends.velocity.redis.event.FriendRequestRevokeRedisEvent -import dev.slne.surf.friends.velocity.redisApi -import dev.slne.surf.friends.velocity.util.FriendPermissionRegistry -import dev.slne.surf.friends.velocity.util.sendText -import dev.slne.surf.surfapi.core.api.service.PlayerLookupService - -fun CommandAPICommand.friendRequestRevokeCommand() = subcommand("revoke") { - withPermission(FriendPermissionRegistry.COMMAND_FRIEND_REQUEST_REVOKE) - playerStringArgument("target") - playerExecutor { player, args -> - container.launch { - val target: String by args - val targetUuid = PlayerLookupService.getUuid(target) ?: return@launch run { - player.uniqueId.sendText { - error("Der Spieler $target wurde nicht gefunden.") - } - } - - val friendRequest = friendService.getFriendRequest(player.uniqueId, targetUuid) - - if (friendRequest == null) { - player.uniqueId.sendText { - error("Du hast keine Freundschaftsanfrage an $target gesendet.") - } - return@launch - } - - friendService.revokeFriendRequest(player.uniqueId, targetUuid) - - player.uniqueId.sendText { - success("Du hast die Freundschaftsanfrage an ") - variableValue(target) - success(" zurückgezogen.") - } - - redisApi.publishEvent( - FriendRequestRevokeRedisEvent( - player.uniqueId, player.username, targetUuid - ) - ) - } - } -} \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/request/FriendRequestSendCommand.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/request/FriendRequestSendCommand.kt deleted file mode 100644 index ae3a899..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/request/FriendRequestSendCommand.kt +++ /dev/null @@ -1,98 +0,0 @@ -package dev.slne.surf.friends.velocity.command.subcommand.request - -import com.github.shynixn.mccoroutine.velocity.launch -import dev.jorel.commandapi.CommandAPICommand -import dev.jorel.commandapi.kotlindsl.getValue -import dev.jorel.commandapi.kotlindsl.playerExecutor -import dev.slne.surf.friends.core.service.databaseService -import dev.slne.surf.friends.core.service.friendService -import dev.slne.surf.friends.velocity.command.argument.playerStringArgument -import dev.slne.surf.friends.velocity.container -import dev.slne.surf.friends.velocity.redis.event.FriendRequestSendRedisEvent -import dev.slne.surf.friends.velocity.redisApi -import dev.slne.surf.friends.velocity.util.FriendPermissionRegistry -import dev.slne.surf.friends.velocity.util.sendText -import dev.slne.surf.surfapi.core.api.font.toSmallCaps -import dev.slne.surf.surfapi.core.api.messages.adventure.clickRunsCommand -import dev.slne.surf.surfapi.core.api.service.PlayerLookupService - -class FriendRequestSendCommand(commandName: String) : CommandAPICommand(commandName) { - init { - withPermission(FriendPermissionRegistry.COMMAND_FRIEND_REQUEST_SEND) - playerStringArgument("target") - playerExecutor { player, args -> - container.launch { - val target: String by args - val targetUuid = PlayerLookupService.getUuid(target) ?: return@launch run { - player.uniqueId.sendText { - error("Der Spieler $target wurde nicht gefunden.") - } - } - - if (player.uniqueId == targetUuid) { - player.uniqueId.sendText { - error("Du kannst dir keine Freundschaftsanfrage selbst senden.") - } - return@launch - } - - val friendShip = friendService.getFriendship(player.uniqueId, targetUuid) - - if (friendShip != null) { - player.uniqueId.sendText { - error("Du bist bereits mit $target befreundet.") - } - return@launch - } - - val friendRequest = friendService.getFriendRequest(player.uniqueId, targetUuid) - val receivedFriendRequest = friendService.getFriendship(targetUuid, player.uniqueId) - - if (friendRequest != null) { - player.uniqueId.sendText { - error("Du hast bereits eine Freundschaftsanfrage an $target gesendet.") - } - return@launch - } - - if (receivedFriendRequest != null) { - player.uniqueId.sendText { - error("Du hast bereits eine Freundschaftsanfrage von $target erhalten. Möchtest du diese annehmen?") - append { - clickRunsCommand("/friend accept $target") - spacer(" [") - info("Akzeptieren".toSmallCaps()) - spacer("]") - } - } - return@launch - } - - friendService.sendFriendRequest(player.uniqueId, targetUuid) - - player.uniqueId.sendText { - success("Du hast eine Freundschaftsanfrage an ") - variableValue(target) - success(" gesendet.") - append { - clickRunsCommand("/friend revoke $target") - spacer(" [") - info("Zurückziehen".toSmallCaps()) - spacer("]") - } - } - - val targetSettings = databaseService.getFriendSettings(targetUuid) - - redisApi.publishEvent( - FriendRequestSendRedisEvent( - player.uniqueId, - player.username, - targetUuid, - targetSettings.announcementsEnabled - ) - ) - } - } - } -} \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/toggle/FriendSettingsAnnouncementsCommand.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/toggle/FriendSettingsAnnouncementsCommand.kt deleted file mode 100644 index 38a7008..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/toggle/FriendSettingsAnnouncementsCommand.kt +++ /dev/null @@ -1,27 +0,0 @@ -package dev.slne.surf.friends.velocity.command.subcommand.toggle - -import com.github.shynixn.mccoroutine.velocity.launch -import dev.jorel.commandapi.CommandAPICommand -import dev.jorel.commandapi.kotlindsl.playerExecutor -import dev.jorel.commandapi.kotlindsl.subcommand -import dev.slne.surf.friends.core.service.friendService -import dev.slne.surf.friends.velocity.container -import dev.slne.surf.friends.velocity.util.FriendPermissionRegistry -import dev.slne.surf.friends.velocity.util.sendText - -fun CommandAPICommand.toggleAnnouncementsCommand() = subcommand("notify-messages") { - withPermission(FriendPermissionRegistry.COMMAND_FRIEND_TOGGLE_ANNOUNCEMENTS) - playerExecutor { player, _ -> - container.launch { - when (friendService.toggleAnnouncements(player.uniqueId)) { - true -> player.uniqueId.sendText { - success("Du hast die Freundes-Benachrichtigungen aktiviert.") - } - - false -> player.uniqueId.sendText { - success("Du hast die Freundes-Benachrichtigungen deaktiviert.") - } - } - } - } -} \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/toggle/FriendSettingsCommand.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/toggle/FriendSettingsCommand.kt deleted file mode 100644 index 1adc7c0..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/toggle/FriendSettingsCommand.kt +++ /dev/null @@ -1,11 +0,0 @@ -package dev.slne.surf.friends.velocity.command.subcommand.toggle - -import dev.jorel.commandapi.CommandAPICommand -import dev.jorel.commandapi.kotlindsl.subcommand -import dev.slne.surf.friends.velocity.util.FriendPermissionRegistry - -fun CommandAPICommand.friendToggleCommand() = subcommand("settings") { - withPermission(FriendPermissionRegistry.COMMAND_FRIEND_TOGGLE) - toggleAnnouncementsCommand() - toggleSoundsCommand() -} \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/toggle/FriendSettingsSoundsCommand.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/toggle/FriendSettingsSoundsCommand.kt deleted file mode 100644 index c298a79..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/command/subcommand/toggle/FriendSettingsSoundsCommand.kt +++ /dev/null @@ -1,27 +0,0 @@ -package dev.slne.surf.friends.velocity.command.subcommand.toggle - -import com.github.shynixn.mccoroutine.velocity.launch -import dev.jorel.commandapi.CommandAPICommand -import dev.jorel.commandapi.kotlindsl.playerExecutor -import dev.jorel.commandapi.kotlindsl.subcommand -import dev.slne.surf.friends.core.service.friendService -import dev.slne.surf.friends.velocity.container -import dev.slne.surf.friends.velocity.util.FriendPermissionRegistry -import dev.slne.surf.friends.velocity.util.sendText - -fun CommandAPICommand.toggleSoundsCommand() = subcommand("notify-sounds") { - withPermission(FriendPermissionRegistry.COMMAND_FRIEND_TOGGLE_SOUNDS) - playerExecutor { player, _ -> - container.launch { - when (friendService.toggleSounds(player.uniqueId)) { - true -> player.uniqueId.sendText { - success("Du hast die Soundbenachrichtigungen aktiviert.") - } - - false -> player.uniqueId.sendText { - success("Du hast die Soundbenachrichtigungen deaktiviert.") - } - } - } - } -} \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/listener/ConnectionListener.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/listener/ConnectionListener.kt deleted file mode 100644 index 0fd8acc..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/listener/ConnectionListener.kt +++ /dev/null @@ -1,93 +0,0 @@ -package dev.slne.surf.friends.velocity.listener - -import com.github.shynixn.mccoroutine.velocity.launch -import com.velocitypowered.api.event.Subscribe -import com.velocitypowered.api.event.connection.DisconnectEvent -import com.velocitypowered.api.event.player.PlayerChooseInitialServerEvent -import dev.slne.surf.friends.core.service.databaseService -import dev.slne.surf.friends.core.service.friendService -import dev.slne.surf.friends.velocity.container -import dev.slne.surf.friends.velocity.util.getOnlineFriends -import dev.slne.surf.friends.velocity.util.sendText -import dev.slne.surf.surfapi.core.api.font.toSmallCaps -import dev.slne.surf.surfapi.core.api.messages.adventure.buildText -import dev.slne.surf.surfapi.core.api.messages.adventure.clickRunsCommand - -class ConnectionListener { - @Subscribe - fun onConnect(event: PlayerChooseInitialServerEvent) { - val player = event.player - - container.launch { - val friendRequests = friendService.getReceivedFriendRequests(player.uniqueId) - val onlineFriends = friendService.getOnlineFriends(player.uniqueId) - - if (onlineFriends.isNotEmpty()) { - player.uniqueId.sendText { - info("Aktuell sind ") - variableValue(onlineFriends.size) - info(" deiner Freunde online. ") - - append { - clickRunsCommand("/friend list") - info("[Ansehen]".toSmallCaps()) - hoverEvent(buildText { - info("Klicke hier, um die Freunde anzusehen.") - }) - } - } - - onlineFriends.forEach { - val playerSettings = databaseService.getFriendSettings(it) - - if (playerSettings.announcementsEnabled) { - it.sendText { - variableValue(player.username) - info(" ist nun online.") - } - } - } - } - - if (friendRequests.isNotEmpty()) { - player.uniqueId.sendText { - info("Du hast noch ") - variableValue(friendRequests.size) - info(" Freundschaftsanfragen offen. ") - - append { - clickRunsCommand("/friend requests") - info("[Ansehen]".toSmallCaps()) - hoverEvent(buildText { - info("Klicke hier, um die Freundschaftsanfragen anzusehen.") - }) - } - } - } - } - } - - @Subscribe - fun onDisconnect(event: DisconnectEvent) { - if (event.loginStatus != DisconnectEvent.LoginStatus.SUCCESSFUL_LOGIN) { - return - } - - val player = event.player - - container.launch { - val onlineFriends = friendService.getOnlineFriends(player.uniqueId) - - onlineFriends.forEach { - val playerSettings = databaseService.getFriendSettings(it) - - if (playerSettings.announcementsEnabled) { - it.sendText { - variableValue(player.username) - info(" ist nun offline.") - } - } - } - } - } -} \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/event/FriendRemoveRedisEvent.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/event/FriendRemoveRedisEvent.kt deleted file mode 100644 index 65a8d62..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/event/FriendRemoveRedisEvent.kt +++ /dev/null @@ -1,13 +0,0 @@ -package dev.slne.surf.friends.velocity.redis.event - -import dev.slne.surf.redis.event.RedisEvent -import kotlinx.serialization.Contextual -import kotlinx.serialization.Serializable -import java.util.* - -@Serializable -data class FriendRemoveRedisEvent( - val remover: @Contextual UUID, - val removerName: String, - val target: @Contextual UUID -) : RedisEvent() diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/event/FriendRequestAcceptRedisEvent.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/event/FriendRequestAcceptRedisEvent.kt deleted file mode 100644 index ed06e88..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/event/FriendRequestAcceptRedisEvent.kt +++ /dev/null @@ -1,13 +0,0 @@ -package dev.slne.surf.friends.velocity.redis.event - -import dev.slne.surf.redis.event.RedisEvent -import kotlinx.serialization.Contextual -import kotlinx.serialization.Serializable -import java.util.* - -@Serializable -data class FriendRequestAcceptRedisEvent( - val requester: @Contextual UUID, - val target: @Contextual UUID, - val targetName: String -) : RedisEvent() diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/event/FriendRequestDenyRedisEvent.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/event/FriendRequestDenyRedisEvent.kt deleted file mode 100644 index 1cdee59..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/event/FriendRequestDenyRedisEvent.kt +++ /dev/null @@ -1,13 +0,0 @@ -package dev.slne.surf.friends.velocity.redis.event - -import dev.slne.surf.redis.event.RedisEvent -import kotlinx.serialization.Contextual -import kotlinx.serialization.Serializable -import java.util.* - -@Serializable -data class FriendRequestDenyRedisEvent( - val requester: @Contextual UUID, - val target: @Contextual UUID, - val targetName: String -) : RedisEvent() diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/event/FriendRequestRevokeRedisEvent.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/event/FriendRequestRevokeRedisEvent.kt deleted file mode 100644 index 95b9aef..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/event/FriendRequestRevokeRedisEvent.kt +++ /dev/null @@ -1,13 +0,0 @@ -package dev.slne.surf.friends.velocity.redis.event - -import dev.slne.surf.redis.event.RedisEvent -import kotlinx.serialization.Contextual -import kotlinx.serialization.Serializable -import java.util.* - -@Serializable -data class FriendRequestRevokeRedisEvent( - val requester: @Contextual UUID, - val requesterName: String, - val target: @Contextual UUID -) : RedisEvent() diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/event/FriendRequestSendRedisEvent.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/event/FriendRequestSendRedisEvent.kt deleted file mode 100644 index 64f7c9b..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/event/FriendRequestSendRedisEvent.kt +++ /dev/null @@ -1,14 +0,0 @@ -package dev.slne.surf.friends.velocity.redis.event - -import dev.slne.surf.redis.event.RedisEvent -import kotlinx.serialization.Contextual -import kotlinx.serialization.Serializable -import java.util.* - -@Serializable -data class FriendRequestSendRedisEvent( - val requester: @Contextual UUID, - val requesterName: String, - val target: @Contextual UUID, - val announce: Boolean -) : RedisEvent() diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/listener/FriendRequestRedisListener.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/listener/FriendRequestRedisListener.kt deleted file mode 100644 index a81d177..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/listener/FriendRequestRedisListener.kt +++ /dev/null @@ -1,80 +0,0 @@ -package dev.slne.surf.friends.velocity.redis.listener - -import dev.slne.surf.friends.velocity.plugin -import dev.slne.surf.friends.velocity.redis.event.FriendRequestAcceptRedisEvent -import dev.slne.surf.friends.velocity.redis.event.FriendRequestDenyRedisEvent -import dev.slne.surf.friends.velocity.redis.event.FriendRequestRevokeRedisEvent -import dev.slne.surf.friends.velocity.redis.event.FriendRequestSendRedisEvent -import dev.slne.surf.redis.event.OnRedisEvent -import dev.slne.surf.surfapi.core.api.messages.Colors -import dev.slne.surf.surfapi.core.api.messages.adventure.clickRunsCommand -import dev.slne.surf.surfapi.core.api.messages.adventure.sendText -import kotlin.jvm.optionals.getOrNull - -object FriendRequestRedisListener { - @OnRedisEvent - fun onFriendRequestAccept(event: FriendRequestAcceptRedisEvent) { - val player = plugin.proxy.getPlayer(event.requester).getOrNull() ?: return - - player.sendText { - appendInfoPrefix() - info("Du bist nun mit ") - variableValue(event.targetName) - info(" befreundet.") - } - } - - @OnRedisEvent - fun onFriendRequestDeny(event: FriendRequestDenyRedisEvent) { - val player = plugin.proxy.getPlayer(event.requester).getOrNull() ?: return - - player.sendText { - appendInfoPrefix() - info("Die Freundschaftsanfrage an ") - variableValue(event.targetName) - info(" wurde abgelehnt.") - } - } - - @OnRedisEvent - fun onFriendRequestRevoke(event: FriendRequestRevokeRedisEvent) { - val player = plugin.proxy.getPlayer(event.target).getOrNull() ?: return - - player.sendText { - appendInfoPrefix() - info("Die Freundschaftsanfrage von ") - variableValue(event.requesterName) - info(" wurde zurückgezogen.") - } - } - - @OnRedisEvent - fun onFriendRequestSend(event: FriendRequestSendRedisEvent) { - val player = plugin.proxy.getPlayer(event.target).getOrNull() ?: return - - if (!event.announce) { - return - } - - player.sendText { - appendInfoPrefix() - info("Du hast eine Freundschaftsanfrage von ") - variableValue(event.requesterName) - info(" erhalten.") - appendSpace() - append { - clickRunsCommand("/friend accept ${event.requesterName}") - spacer("[") - text("Akzeptieren", Colors.GREEN) - spacer("]") - } - appendSpace() - append { - clickRunsCommand("/friend decline ${event.requesterName}") - spacer("[") - text("Ablehnen", Colors.RED) - spacer("]") - } - } - } -} \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/listener/FriendshipRedisListener.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/listener/FriendshipRedisListener.kt deleted file mode 100644 index da8478b..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/redis/listener/FriendshipRedisListener.kt +++ /dev/null @@ -1,21 +0,0 @@ -package dev.slne.surf.friends.velocity.redis.listener - -import dev.slne.surf.friends.velocity.plugin -import dev.slne.surf.friends.velocity.redis.event.FriendRemoveRedisEvent -import dev.slne.surf.redis.event.OnRedisEvent -import dev.slne.surf.surfapi.core.api.messages.adventure.sendText -import kotlin.jvm.optionals.getOrNull - -object FriendshipRedisListener { - @OnRedisEvent - fun onFriendRemove(event: FriendRemoveRedisEvent) { - val player = plugin.proxy.getPlayer(event.target).getOrNull() ?: return - - player.sendText { - appendInfoPrefix() - info("Die Freundschaft mit ") - variableValue(event.removerName) - info(" wurde beendet.") - } - } -} \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/util/FriendPermissionRegistry.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/util/FriendPermissionRegistry.kt deleted file mode 100644 index 3c1af45..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/util/FriendPermissionRegistry.kt +++ /dev/null @@ -1,21 +0,0 @@ -package dev.slne.surf.friends.velocity.util - -object FriendPermissionRegistry { - const val COMMAND_FRIEND = "surf.friends.command" - - const val COMMAND_FRIEND_REQUEST_SEND = "surf.friends.command.request.send" - const val COMMAND_FRIEND_REQUEST_ACCEPT = "surf.friends.command.request.accept" - const val COMMAND_FRIEND_REQUEST_DECLINE = "surf.friends.command.request.decline" - const val COMMAND_FRIEND_REQUEST_REVOKE = "surf.friends.command.request.revoke" - const val COMMAND_FRIEND_REQUEST_LIST = "surf.friends.command.request.list" - - const val COMMAND_FRIEND_INFO = "surf.friends.command.info" - const val COMMAND_FRIEND_JUMP = "surf.friends.command.jump" - const val COMMAND_FRIEND_REMOVE = "surf.friends.command.remove" - const val COMMAND_FRIEND_LIST = "surf.friends.command.list" - - const val COMMAND_FRIEND_TOGGLE = "surf.friends.command.toggle" - const val COMMAND_FRIEND_TOGGLE_ANNOUNCEMENTS = "surf.friends.command.toggle.announcements" - const val COMMAND_FRIEND_TOGGLE_SOUNDS = "surf.friends.command.toggle.sounds" - -} \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/util/friend-util.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/util/friend-util.kt deleted file mode 100644 index 2db9434..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/util/friend-util.kt +++ /dev/null @@ -1,21 +0,0 @@ -package dev.slne.surf.friends.velocity.util - -import dev.slne.surf.friends.core.service.FriendService -import dev.slne.surf.friends.velocity.plugin -import dev.slne.surf.friends.velocity.util.isOnline -import dev.slne.surf.surfapi.core.api.util.mutableObjectListOf -import it.unimi.dsi.fastutil.objects.ObjectList -import java.util.UUID - -suspend fun FriendService.getOnlineFriends(user: UUID): ObjectList { - return this.getFriendships(user) - .mapNotNull { - val other = if (it.friendUuid == user) it.userUuid else it.friendUuid - if (other.isOnline()) other else null - } - .toCollection(mutableObjectListOf()) -} - -fun UUID.isOnline(): Boolean { - return plugin.proxy.getPlayer(this).isPresent -} \ No newline at end of file diff --git a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/util/uuid-util.kt b/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/util/uuid-util.kt deleted file mode 100644 index 190ea83..0000000 --- a/surf-friends-velocity/src/main/kotlin/dev/slne/surf/friends/velocity/util/uuid-util.kt +++ /dev/null @@ -1,42 +0,0 @@ -package dev.slne.surf.friends.velocity.util - -import com.velocitypowered.api.proxy.Player -import dev.slne.surf.friends.velocity.plugin -import dev.slne.surf.surfapi.core.api.messages.Colors -import dev.slne.surf.surfapi.core.api.messages.builder.SurfComponentBuilder -import dev.slne.surf.surfapi.core.api.service.PlayerLookupService -import java.time.Instant -import java.time.ZoneId -import java.time.format.DateTimeFormatter -import java.util.* -import kotlin.jvm.optionals.getOrNull - -val timeFormatter: DateTimeFormatter = DateTimeFormatter - .ofPattern("dd.MM.yyyy, HH:mm:ss", Locale.GERMANY) - .withZone(ZoneId.of("Europe/Berlin")) - -fun Long.format(): String { - return timeFormatter.format(Instant.ofEpochMilli(this)) -} - -fun formatTime(millis: Long): String { - return timeFormatter.format(Instant.ofEpochMilli(millis)) -} - -fun UUID.sendText(builder: SurfComponentBuilder.() -> Unit) { - val player = plugin.proxy.getPlayer(this).getOrNull() ?: return - - player.sendMessage(Colors.PREFIX.append(SurfComponentBuilder(builder))) -} - -suspend fun UUID.getUsernameAsync(): String { - return PlayerLookupService.getUsername(this) ?: "Unknown" -} - -fun UUID.getUsername(): String { - return plugin.proxy.getPlayer(this).getOrNull()?.username ?: "Unknown" -} - -fun UUID.toPlayer(): Player? { - return plugin.proxy.getPlayer(this).getOrNull() -} \ No newline at end of file