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