diff --git a/build.gradle.kts b/build.gradle.kts index c2e0f1a..d0bf2f2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,10 +1,22 @@ -import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import dev.slne.surf.surfapi.gradle.util.slnePublic +buildscript { + repositories { + gradlePluginPortal() + maven("https://repo.slne.dev/repository/maven-public/") { name = "maven-public" } + } + dependencies { + classpath("dev.slne.surf:surf-api-gradle-plugin:1.21.8+") + } +} + allprojects { + group = "dev.slne.surf.roleplay" + version = findProperty("version") as String + repositories { slnePublic() + gradlePluginPortal() } } @@ -12,16 +24,7 @@ subprojects { afterEvaluate { plugins.withType { configure { - toolchain.languageVersion.set(JavaLanguageVersion.of(24)) - } - } - plugins.withType { - tasks.withType { - dependencies { - exclude(dependency("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm")) - exclude(dependency("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8")) - exclude(dependency("org.jetbrains.kotlin:kotlin-stdlib")) - } + toolchain.languageVersion.set(JavaLanguageVersion.of(21)) } } } diff --git a/gradle.properties b/gradle.properties index a481e58..cc97c39 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,14 @@ +org.gradle.configuration-cache=true +org.gradle.parallel=true +org.gradle.caching=true kotlin.code.style=official kotlin.stdlib.default.dependency=false -org.gradle.parallel=true -version=1.21.7-1.0.0 \ No newline at end of file +version=1.21.7-1.0.0 +# Mod Properties +mod_version=1.21.8-1.0.0-SNAPSHOT +maven_group=dev.slne.roleplay.mod +archives_name=roleplay +enabled_platforms=fabric,neoforge +# Dependencies +fabric_version=0.131.0+1.21.8 +org.gradle.jvmargs=-Xmx8G diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7c44d96..cf845d5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,34 @@ [versions] -surf-database = "2.2.1-SNAPSHOT" -surf-npc-api = "1.21.7-1.4.1-SNAPSHOT" +surf-npc-api = "1.21.7-1.4.2-SNAPSHOT" +loom = "1.11-SNAPSHOT" +netty = "4.2.4.Final" +datafixerupper = "8.0.16" +bytebuddy = "1.15.10" +kotlin-byte-buf-serializer = "1.1.0" +protoweaver = "1.4.9" +architectury-base = "3.4.161" +architectury-loom = "1.10.433" +architectury-api = "17.0.8" +neoforge = "21.8.32" + +# Mod +minecraft = "1.21.8" +yarn-mappings = "1.21.8+build.1" +fabric-loader = "0.17.2" +fabric-kotlin = "1.13.5+kotlin.2.2.10" +fabric-api = "0.132.0+1.21.8" [libraries] -surf-database = { module = "dev.slne.surf:surf-database", version.ref = "surf-database" } surf-npc-api = { module = "dev.slne.surf.npc:surf-npc-api", version.ref = "surf-npc-api" } +netty = { module = "io.netty:netty-all", version.ref = "netty" } +datafixerupper = { module = "com.mojang:datafixerupper", version.ref = "datafixerupper" } +bytebuddy = { module = "net.bytebuddy:byte-buddy", version.ref = "bytebuddy" } +kotlin-byte-buf-serializer = { module = "dev.slne.surf:kotlin-byte-buf-serializer", version.ref = "kotlin-byte-buf-serializer" } +protoweaver-common = { module = "me.mrnavastar.protoweaver:common", version.ref = "protoweaver" } +protoweaver-fabric = { module = "me.mrnavastar.protoweaver:client", version.ref = "protoweaver" } +protoweaver-paper = { module = "me.mrnavastar.protoweaver:common", version.ref = "protoweaver" } + +[plugins] +loom = { id = "fabric-loom", version.ref = "loom" } +architectury-base = { id = "architectury-plugin", version.ref = "architectury-base" } +architectury-loom = { id = "dev.architectury.loom", version.ref = "architectury-loom" } diff --git a/settings.gradle.kts b/settings.gradle.kts index e049f61..1c72896 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,20 +1,26 @@ -plugins { - id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" -} +rootProject.name = "surf-roleplay" -buildscript { +pluginManagement { repositories { + mavenCentral() + maven("https://maven.fabricmc.net") + maven("https://maven.architectury.dev") + maven("https://files.minecraftforge.net/maven") gradlePluginPortal() - maven("https://repo.slne.dev/repository/maven-public/") { name = "maven-public" } - } - dependencies { - classpath("dev.slne.surf:surf-api-gradle-plugin:1.21.7+") } } -rootProject.name = "surf-roleplay" +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" +} + +include("surf-roleplay-core:surf-roleplay-core-common") +include("surf-roleplay-paper") +include("surf-roleplay-server") + +include("surf-roleplay-mod:surf-roleplay-mod-common") +include("surf-roleplay-mod:surf-roleplay-mod-server") -include("surf-roleplay-api") -include("surf-roleplay-core") -include("surf-roleplay-mechanic") -include("surf-roleplay-paper") \ No newline at end of file +include("surf-roleplay-mod:surf-roleplay-mod-client:common") +include("surf-roleplay-mod:surf-roleplay-mod-client:fabric") +//include("surf-roleplay-mod:surf-roleplay-mod-client:neoforge") diff --git a/surf-roleplay-api/build.gradle.kts b/surf-roleplay-api/build.gradle.kts deleted file mode 100644 index 64d286f..0000000 --- a/surf-roleplay-api/build.gradle.kts +++ /dev/null @@ -1,3 +0,0 @@ -plugins { - id("dev.slne.surf.surfapi.gradle.paper-raw") -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/coroutine/RpJob.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/coroutine/RpJob.kt deleted file mode 100644 index 1a8b389..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/coroutine/RpJob.kt +++ /dev/null @@ -1,63 +0,0 @@ -package dev.slne.surf.roleplay.api.coroutine - -import dev.slne.surf.surfapi.core.api.util.logger -import kotlinx.coroutines.* -import kotlin.time.Duration - -abstract class RpJob( - val name: String, - val delay: Duration -) { - private val supervisor: CompletableJob - private val scope: CoroutineScope - - init { - val (supervisor, scope) = buildCoroutineScope(name) - - this.supervisor = supervisor - this.scope = scope - } - - fun start() = scope.launch { - while (isActive) { - tick() - delay(delay) - } - } - - suspend fun stop() { - supervisor.cancelAndJoin() - } - - abstract suspend fun tick() - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is RpJob) return false - - if (name != other.name) return false - if (delay != other.delay) return false - - return true - } - - override fun hashCode(): Int { - var result = name.hashCode() - result = 31 * result + delay.hashCode() - return result - } -} - -private val log = logger() - -private fun buildCoroutineScope(name: String): Pair { - val supervisor = SupervisorJob() - val scope = - CoroutineScope(supervisor + CoroutineName(name) + CoroutineExceptionHandler { _, throwable -> - if (throwable is CancellationException) return@CoroutineExceptionHandler - - log.atSevere().withCause(throwable).log("$name failed") - }) - - return supervisor to scope -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/events/CancellableRpEvent.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/events/CancellableRpEvent.kt deleted file mode 100644 index 5d54cf9..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/events/CancellableRpEvent.kt +++ /dev/null @@ -1,14 +0,0 @@ -package dev.slne.surf.roleplay.api.events - -import org.bukkit.event.Cancellable - -open class CancellableRpEvent() : RpEvent(), Cancellable { - - private var cancelled = false - - override fun isCancelled() = cancelled - - override fun setCancelled(cancel: Boolean) { - cancelled = cancel - } -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/events/RpEvent.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/events/RpEvent.kt deleted file mode 100644 index de9e961..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/events/RpEvent.kt +++ /dev/null @@ -1,19 +0,0 @@ -package dev.slne.surf.roleplay.api.events - -import org.bukkit.Bukkit -import org.bukkit.event.Event -import org.bukkit.event.HandlerList - -open class RpEvent( - async: Boolean = !Bukkit.isPrimaryThread() -) : Event(async) { - - override fun getHandlers() = handlerList - - companion object { - private val handlerList = HandlerList() - - @JvmStatic - fun getHandlerList(): HandlerList = handlerList - } -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/Mechanic.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/Mechanic.kt deleted file mode 100644 index 13d30b7..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/Mechanic.kt +++ /dev/null @@ -1,69 +0,0 @@ -package dev.slne.surf.roleplay.api.mechanic - -import com.github.retrooper.packetevents.event.PacketListener -import com.github.retrooper.packetevents.event.PacketListenerPriority -import dev.slne.surf.roleplay.api.coroutine.RpJob -import it.unimi.dsi.fastutil.objects.ObjectSet -import org.bukkit.event.Listener - -interface Mechanic { - - /** - * Returns the name of the mechanic. - * This name should be unique across all mechanics. - */ - val name: String - - /** - * Returns an object set of handlers for this mechanic. - */ - val handlers: ObjectSet - - /** - * Returns an object set of all rp jobs associated with this mechanic. - * Rp jobs are tasks that can be scheduled to run periodically or at specific times. - * This is used for mechanics that require periodic updates or tasks. - */ - val rpJobs: ObjectSet - - /** - * Returns an object set of all packet listeners associated with this mechanic. - */ - val packetListeners: ObjectSet> - - /** - * Called when the mechanic is loaded. - */ - suspend fun onLoad() - - /** - * Called when the mechanic is enabled. - */ - suspend fun onEnable() - - /** - * Called when the mechanic is disabled. - */ - suspend fun onDisable() - - companion object { - /** - * Gets the mechanic by its class type. - * - * @param T The type of the mechanic. - * @param mechanic The class type of the mechanic. - * @return The [Mechanic] instance of type [T]. - */ - fun getMechanic(mechanic: Class): T = - MechanicRegistry.getMechanic(mechanic) - - /** - * Gets the mechanic by its class type. - * - * @param T The type of the mechanic. - * @return The [Mechanic] instance of type [T]. - */ - inline fun getMechanic(): T = - getMechanic(T::class.java) - } -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/MechanicRegistry.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/MechanicRegistry.kt deleted file mode 100644 index be4966d..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/MechanicRegistry.kt +++ /dev/null @@ -1,29 +0,0 @@ -package dev.slne.surf.roleplay.api.mechanic - -import dev.slne.surf.surfapi.core.api.util.requiredService - -private val mechanicRegistry = requiredService() - -interface MechanicRegistry { - - /** - * Returns the mechanic instance of the specified class. - * - * @param clazz The class of the mechanic to retrieve. - * @return The mechanic instance of the specified class. - * @throws IllegalArgumentException if no mechanic of the specified class is registered. - */ - fun getMechanic(clazz: Class): T - - companion object : MechanicRegistry by mechanicRegistry { - val INSTANCE get() = mechanicRegistry - } -} - -/** - * Returns the mechanic instance of the specified type. - * This is a convenience function that uses reified type parameters - * - * @return The mechanic instance of the specified type - */ -inline fun MechanicRegistry.getMechanic(): T = getMechanic(T::class.java) \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/idcard/IdCardMechanic.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/idcard/IdCardMechanic.kt deleted file mode 100644 index 15de4ce..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/idcard/IdCardMechanic.kt +++ /dev/null @@ -1,5 +0,0 @@ -package dev.slne.surf.roleplay.api.mechanic.idcard - -import dev.slne.surf.roleplay.api.mechanic.Mechanic - -interface IdCardMechanic : Mechanic \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/Rentable.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/Rentable.kt deleted file mode 100644 index f9be7e0..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/Rentable.kt +++ /dev/null @@ -1,120 +0,0 @@ -package dev.slne.surf.roleplay.api.mechanic.rentable - -import dev.slne.surf.roleplay.api.mechanic.rentable.events.RentableMemberAddEvent -import dev.slne.surf.roleplay.api.mechanic.rentable.events.RentableMemberRemoveEvent -import dev.slne.surf.roleplay.api.mechanic.rentable.events.RentableOwnerChangeEvent -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.StorageContainer -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.door.Door -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.door.DoorContainer -import dev.slne.surf.roleplay.api.player.RpPlayer -import it.unimi.dsi.fastutil.objects.ObjectSet -import net.kyori.adventure.key.Key -import net.kyori.adventure.text.ComponentLike -import org.jetbrains.annotations.Unmodifiable -import java.time.ZonedDateTime -import kotlin.time.Duration - -/** - * Represents a rentable property in the game. - * A rentable property can be owned, rented, and have members associated with it. - */ -interface Rentable : ComponentLike { - - /** - * The unique identifier for the rentable property. - */ - val key: Key - - /** - * The name of the rentable property. - */ - val rent: Int - - /** - * The duration for which the property can be rented, after this the rent will be due again. - */ - val rentDuration: Duration - - /** - * The date and time when the rent was last collected. - */ - val lastRentCollection: ZonedDateTime? - - /** - * The size of the rentable property in square blocks. - */ - val size: Double - - /** - * The number of stories in the rentable property. - */ - val stories: Int - - /** - * The owner of the rentable property, if any. - */ - val owner: RpPlayer? - - /** - * The members of the rentable property, if any. - */ - val members: @Unmodifiable ObjectSet - - /** - * The [StorageContainer]s of this rentable - */ - val storageContainers: @Unmodifiable ObjectSet - - /** - * The [Door]s of this rentable - */ - val doorContainers: @Unmodifiable ObjectSet - - /** - * Checks if the property is currently rented. - */ - val isRented: Boolean - - /** - * Sets the owner of the rentable property and collects the first rent - * - * @param player The player to set as the owner of the rentable property. - * @param reason The reason for the owner change, which can be used to determine the context of the change. - * @return The result of the owner change event, indicating success or failure. - */ - suspend fun setOwner( - player: RpPlayer?, - reason: RentableOwnerChangeEvent.OwnerChangeReason - ): RentableOwnerChangeEvent.OwnerSetResult - - /** - * Adds a member to the rentable property. - * - * @param player The player to add as a member. - * @return The result of the member addition event, indicating success or failure. - */ - fun addMember(player: RpPlayer): RentableMemberAddEvent.MemberAddResult - - /** - * Removes a member from the rentable property. - * - * @param player The player to remove from the members. - * @return The result of the member removal event, indicating success or failure. - */ - fun removeMember(player: RpPlayer): RentableMemberRemoveEvent.MemberRemoveResult - - /** - * Checks if the player is a member of the rentable property. - * - * @param player The player to check. - * @return True if the player is a member, false otherwise. - */ - fun isMember(player: RpPlayer): Boolean - - /** - * Collects the rent for the rentable property. - * - * @return The result of the rent collection, indicating success or failure. - */ - suspend fun collectRent(): RentableMechanic.RentCollectResult -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/RentableMechanic.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/RentableMechanic.kt deleted file mode 100644 index e4e122d..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/RentableMechanic.kt +++ /dev/null @@ -1,81 +0,0 @@ -package dev.slne.surf.roleplay.api.mechanic.rentable - -import dev.slne.surf.roleplay.api.mechanic.Mechanic -import dev.slne.surf.roleplay.api.player.RpPlayer -import it.unimi.dsi.fastutil.objects.ObjectSet -import net.kyori.adventure.key.Key -import org.jetbrains.annotations.Unmodifiable - -interface RentableMechanic : Mechanic { - - /** - * The rentables - */ - val rentables: @Unmodifiable ObjectSet - - /** - * Adds a rentable - * - * @param rentable the [Rentable] - * @return If adding the rentable was successful - */ - fun addRentable(rentable: Rentable): Boolean - - /** - * Collects the rent for a [Rentable] - * - * @param rentable the [Rentable] to collect rent for - * @return the result of the rent collection - */ - suspend fun collectRent(rentable: Rentable): RentCollectResult - - /** - * Returns the owned [Rentable]s for one [RpPlayer] - * - * @param player the [RpPlayer] - * @return an object set of [Rentable]s - */ - fun getOwnedRentablesByPlayer(player: RpPlayer): ObjectSet - - /** - * Returns the maximum number of ownable rentables for a player. - * - * @param player the [RpPlayer] to check - * @return the maximum number of ownable rentables - */ - fun getMaxOwnableRentablesByPlayer(player: RpPlayer): Int - - /** - * Returns a [Rentable] by its key. - * - * @param key the [Key] of the [Rentable] - * @return the [Rentable] if found, or null if not found - */ - fun getByKey(key: Key): Rentable? - - /** - * The result of a rent collection attempt. - */ - enum class RentCollectResult { - /** - * The rent was successfully collected. - */ - SUCCESS, - - /** - * The rent collection was cancelled, possibly due to an event. - */ - EVENT_CANCELLED, - - /** - * The player does not have enough money to pay the rent. - */ - NOT_ENOUGH_MONEY, - - /** - * The rentable is not currently rented. - */ - NOT_RENTED, - } - -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/rentables/Apartment.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/rentables/Apartment.kt deleted file mode 100644 index 940404b..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/rentables/Apartment.kt +++ /dev/null @@ -1,8 +0,0 @@ -package dev.slne.surf.roleplay.api.mechanic.rentable.rentables - -import dev.slne.surf.roleplay.api.mechanic.rentable.Rentable - -/** - * Represents an apartment that can be rented. - */ -interface Apartment : Rentable \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/rentables/House.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/rentables/House.kt deleted file mode 100644 index f34f72e..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/rentables/House.kt +++ /dev/null @@ -1,8 +0,0 @@ -package dev.slne.surf.roleplay.api.mechanic.rentable.rentables - -import dev.slne.surf.roleplay.api.mechanic.rentable.Rentable - -/** - * Represents a house that can be rented. - */ -interface House : Rentable \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/utils/door/Door.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/utils/door/Door.kt deleted file mode 100644 index 7e9722a..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/utils/door/Door.kt +++ /dev/null @@ -1,38 +0,0 @@ -package dev.slne.surf.roleplay.api.mechanic.rentable.utils.door - -import dev.slne.surf.roleplay.api.mechanic.rentable.Rentable -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.Crackable -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.Lockable -import org.bukkit.Location - -/** - * Represents a door in the game that can be locked and cracked. - * A door is associated with a rentable property and has a specific location in the world. - */ -interface Door : Lockable, Crackable { - - /** - * The rentable property that this door belongs to. - */ - val rentable: Rentable - - /** - * The door container of this door, which holds multiple doors. - */ - val container: DoorContainer - - /** - * The location of the door in the world. - */ - val location: Location - - /** - * Opens the door. - */ - suspend fun open() - - /** - * Closes the door. - */ - suspend fun close() -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/weapon/Weapon.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/weapon/Weapon.kt deleted file mode 100644 index e6efb0c..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/weapon/Weapon.kt +++ /dev/null @@ -1,29 +0,0 @@ -package dev.slne.surf.roleplay.api.mechanic.weapon - -import dev.slne.surf.roleplay.api.mechanic.weapon.magazine.Magazine -import dev.slne.surf.roleplay.api.mechanic.weapon.utils.WeaponType -import dev.slne.surf.surfapi.bukkit.api.builder.LoreBuilder -import dev.slne.surf.surfapi.core.api.messages.builder.SurfComponentBuilder -import it.unimi.dsi.fastutil.objects.ObjectSet -import org.bukkit.Material -import kotlin.time.Duration - -interface Weapon { - - val type: WeaponType - - val name: String - - val weaponMaterial: Material - - val displayName: SurfComponentBuilder.() -> Unit - - val description: LoreBuilder.() -> Unit - - val weaponShootCooldown: Duration - - val supportedMagazines: ObjectSet - - fun isApplicableMagazine(magazine: Magazine): Boolean - -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/weapon/WeaponMechanic.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/weapon/WeaponMechanic.kt deleted file mode 100644 index edd2902..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/weapon/WeaponMechanic.kt +++ /dev/null @@ -1,10 +0,0 @@ -package dev.slne.surf.roleplay.api.mechanic.weapon - -import it.unimi.dsi.fastutil.objects.ObjectSet -import org.jetbrains.annotations.Unmodifiable - -interface WeaponMechanic { - - val weapons: @Unmodifiable ObjectSet - -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/weapon/magazine/Magazine.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/weapon/magazine/Magazine.kt deleted file mode 100644 index 3056b39..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/weapon/magazine/Magazine.kt +++ /dev/null @@ -1,22 +0,0 @@ -package dev.slne.surf.roleplay.api.mechanic.weapon.magazine - -import dev.slne.surf.surfapi.bukkit.api.builder.LoreBuilder -import dev.slne.surf.surfapi.core.api.messages.builder.SurfComponentBuilder - -interface Magazine { - - val name: String - - val displayName: SurfComponentBuilder.() -> Unit - - val description: LoreBuilder.() -> Unit - - val maxAmmo: Int - - /** - * Function to calculate the damage dealt by the weapon using this magazine. - * The function takes the distance to the target hit as a parameter and returns the damage dealt. - */ - val damageFunction: (Double) -> Double - -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/weapon/magazine/PlayerMagazine.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/weapon/magazine/PlayerMagazine.kt deleted file mode 100644 index c45b2e1..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/weapon/magazine/PlayerMagazine.kt +++ /dev/null @@ -1,13 +0,0 @@ -package dev.slne.surf.roleplay.api.mechanic.weapon.magazine - -import org.bukkit.inventory.ItemStack - -interface PlayerMagazine { - - val magazine: Magazine - - val currentAmmo: Int - - fun buildItemStack(): ItemStack - -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/weapon/player/PlayerWeapon.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/weapon/player/PlayerWeapon.kt deleted file mode 100644 index f2cb902..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/weapon/player/PlayerWeapon.kt +++ /dev/null @@ -1,16 +0,0 @@ -package dev.slne.surf.roleplay.api.mechanic.weapon.player - -import dev.slne.surf.roleplay.api.mechanic.weapon.Weapon -import dev.slne.surf.roleplay.api.mechanic.weapon.magazine.PlayerMagazine -import org.bukkit.inventory.ItemStack - -interface PlayerWeapon { - - val weapon: Weapon - - val currentMagazine: PlayerMagazine? - - fun setCurrentMagazine(magazine: PlayerMagazine?) - - fun buildItemStack(): ItemStack -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/RpPlayer.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/RpPlayer.kt deleted file mode 100644 index e1a7850..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/RpPlayer.kt +++ /dev/null @@ -1,150 +0,0 @@ -package dev.slne.surf.roleplay.api.player - -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.api.player.license.HasLicenses -import dev.slne.surf.roleplay.api.transaction.HasTransactions -import it.unimi.dsi.fastutil.objects.ObjectSet -import net.kyori.adventure.text.ComponentLike -import org.bukkit.OfflinePlayer -import org.bukkit.entity.Player -import java.time.ZonedDateTime -import java.util.* - -interface RpPlayer : HasTransactions, HasLicenses, - ComponentLike { - - /** - * The [UUID] of the player - */ - val uuid: UUID - - /** - * The username of the player. - */ - val username: String? - - /** - * The active identity of the player. - */ - val activeIdentity: RpIdentity? - - /** - * The identities of the player. - */ - val identities: ObjectSet - - /** - * The Bukkit [Player] representation of this player, if they are online. - * Returns `null` if the player is not online. - */ - val bukkitPlayer: Player? - - /** - * The Bukkit [OfflinePlayer] representation of this player. - */ - val bukkitOfflinePlayer: OfflinePlayer - - /** - * The date and time when the player was created. - */ - val createdAt: ZonedDateTime - - /** - * The last time the player's information was updated. - */ - val updatedAt: ZonedDateTime - - /** - * Sets the active identity for the player. - * - * @param identity The [RpIdentity] to set as the active identity. - */ - suspend fun setActiveIdentity(identity: RpIdentity) - - /** - * Gets one of the player's identities by type. - * - * @param type The type of the identity to retrieve. - * @return The identity of the specified type, or `null` if not found. - */ - fun getIdentity(type: RpIdentity.RpIdentityType): RpIdentity? - - /** - * Gets one of the player's identities by class type. - * - * @param clazz The class type of the identity to retrieve. - * @param T The type of the identity. - */ - fun getIdentity(clazz: Class): RpIdentity? - - /** - * Checks if the player has a specific permission. - * - * @param permission The permission to check. - * @return `true` if the player has the permission, `false` otherwise. - */ - fun hasPermission(permission: String): Boolean = bukkitPlayer?.hasPermission(permission) == true - - /** - * Updates the player's username. - * - * @param username The new username to set for the player. - */ - suspend fun updateUsername(username: String) - - /** - * Creates a new identity for the player. - * - * @param identity The identity to create. - * @return The created identity. - */ - suspend fun createIdentity(identity: T): T - - /** - * Updates the player's identity information. - * - * @param identity the [T] - * @return The updated identity, or `null` if the identity was not found and `createIfNotExists` is `false`. - */ - suspend fun updateIdentity(identity: T): T? - - /** - * Creates or updates the player's identity. - * - * If the identity already exists, it will be updated using the provided lambda function. - * If it does not exist, a new identity will be created. - * - * @param identity the [T] - * @return The created or updated identity, or `null` if the operation failed. - */ - suspend fun createOrUpdateIdentity(identity: T): T - - /** - * Checks if the player is a citizen. - * - * @return `true` if the player is a citizen, `false` otherwise. - */ - fun hasCompletedCitizenship(): Boolean - - companion object { - /** - * Gets a [RpPlayer] by their [UUID]. - */ - suspend operator fun get(uuid: UUID) = RpPlayerManager[uuid] - } -} - -/** - * Gets the [RpIdentity] of the specified type for this [RpPlayer]. - * - * @param T The type of the identity to retrieve. - * @return The identity of the specified type, or `null` if not found. - */ -inline fun RpPlayer.getIdentity() = getIdentity(T::class.java) - -/** - * Gets the [RpPlayer] associated with this [Player]. - * - * @return The [RpPlayer] instance for this player. - */ -suspend fun Player.rpPlayer() = RpPlayer[uniqueId] \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/RpPlayerManager.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/RpPlayerManager.kt deleted file mode 100644 index e505738..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/RpPlayerManager.kt +++ /dev/null @@ -1,32 +0,0 @@ -package dev.slne.surf.roleplay.api.player - -import dev.slne.surf.surfapi.core.api.util.requiredService -import it.unimi.dsi.fastutil.objects.ObjectSet -import org.jetbrains.annotations.Unmodifiable -import java.util.* - -private val rpPlayerManager = requiredService() - -interface RpPlayerManager { - - /** - * A set of all [RpPlayer] instances currently managed by this manager. - */ - val players: @Unmodifiable ObjectSet - - /** - * Gets a [RpPlayer] by their UUID. - * - * @param uuid the UUID of the player - * @return the [RpPlayer] associated with the UUID - */ - suspend operator fun get(uuid: UUID): RpPlayer - - companion object : RpPlayerManager by rpPlayerManager { - /** - * The singleton instance of [RpPlayerManager]. - */ - val INSTANCE get() = rpPlayerManager - } - -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/events/RpPlayerJoinEvent.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/events/RpPlayerJoinEvent.kt deleted file mode 100644 index f9b19e8..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/events/RpPlayerJoinEvent.kt +++ /dev/null @@ -1,8 +0,0 @@ -package dev.slne.surf.roleplay.api.player.events - -import dev.slne.surf.roleplay.api.events.RpEvent -import dev.slne.surf.roleplay.api.player.RpPlayer - -class RpPlayerJoinEvent( - val rpPlayer: RpPlayer, -) : RpEvent() \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/events/RpPlayerQuitEvent.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/events/RpPlayerQuitEvent.kt deleted file mode 100644 index 5455c6b..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/events/RpPlayerQuitEvent.kt +++ /dev/null @@ -1,8 +0,0 @@ -package dev.slne.surf.roleplay.api.player.events - -import dev.slne.surf.roleplay.api.events.RpEvent -import dev.slne.surf.roleplay.api.player.RpPlayer - -class RpPlayerQuitEvent( - val rpPlayer: RpPlayer, -) : RpEvent() \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/identity/RpIdentity.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/identity/RpIdentity.kt deleted file mode 100644 index 6b3a1d2..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/identity/RpIdentity.kt +++ /dev/null @@ -1,90 +0,0 @@ -package dev.slne.surf.roleplay.api.player.identity - -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.license.HasLicenses -import dev.slne.surf.roleplay.api.transaction.HasTransactions -import dev.slne.surf.surfapi.core.api.messages.adventure.buildText -import net.kyori.adventure.text.ComponentLike -import java.time.LocalDate -import java.time.ZonedDateTime - -/** - * Represents a roleplay identity of a player - */ -interface RpIdentity : HasTransactions, HasLicenses { - - /** - * The player associated with this identity. - */ - val player: RpPlayer - - /** - * The type of the identity. - */ - val type: RpIdentityType - - /** - * The first name of the player. - */ - var firstName: String - - /** - * The last name of the player. - */ - var lastName: String - - /** - * The birth date of the player. - */ - var dateOfBirth: LocalDate - - /** - * The date and time when the identity was created. - */ - val createdAt: ZonedDateTime - - /** - * The date and time when the identity was last updated. - */ - var updatedAt: ZonedDateTime - - enum class RpIdentityType : ComponentLike { - /** - * Represents a player who is a member of the civilian population. - */ - CIVILIAN { - override fun asComponent() = buildText { - text("Zivilist") - } - }, - - /** - * Represents a player who is a member of the emergency medical service. - */ - POLICE { - override fun asComponent() = buildText { - text("Polizist") - } - }, - - /** - * Represents a player who is a member of the rescue service. - */ - RESCUE_SERVICE { - override fun asComponent() = buildText { - text("SAR") - } - } - } - - interface CivilianIdentity : RpIdentity - - interface RescueServiceIdentity : RpIdentity { - val rank: String - } - - interface PoliceIdentity : RpIdentity { - val rank: String - val badgeNumber: String - } -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/ExpirableLicense.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/ExpirableLicense.kt deleted file mode 100644 index c373553..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/ExpirableLicense.kt +++ /dev/null @@ -1,13 +0,0 @@ -package dev.slne.surf.roleplay.api.player.license - -import kotlin.time.Duration - -interface ExpirableLicense : License { - - /** - * The duration for which the license is valid. - * If null, the license does not expire. - */ - val expiresIn: Duration - -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/License.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/License.kt deleted file mode 100644 index c8fba69..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/License.kt +++ /dev/null @@ -1,60 +0,0 @@ -package dev.slne.surf.roleplay.api.player.license - -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.api.player.license.utils.UnobtainableReason -import dev.slne.surf.surfapi.bukkit.api.builder.LoreBuilder -import it.unimi.dsi.fastutil.objects.ObjectSet -import net.kyori.adventure.key.Key -import net.kyori.adventure.text.Component - -interface License { - /** - * The internal name of the license, used for identification. - */ - val key: Key - - /** - * The display name of the license, shown to players. - */ - val displayName: Component - - /** - * A function that builds the description of the license using a [LoreBuilder]. - * This allows for a flexible and formatted description. - */ - val description: LoreBuilder.() -> Unit - - /** - * The price of the license in the game currency. - * This is the amount a player must pay to obtain the license. - */ - val price: Int - - /** - * A set of other licenses that must be obtained before this one. - * This allows for dependencies between licenses. - */ - val dependencies: ObjectSet - - /** - * A set of child licenses that can be obtained after this one. - * This allows for a hierarchy of licenses. - */ - val children: ObjectSet - - /** - * The permission required to obtain this license. - * This is used to check if a player has the necessary permissions. - */ - val permission: String - - /** - * Checks if the player can obtain this license. - * Returns a pair where the first element is a boolean indicating success, - * and the second element is an [UnobtainableReason] if applicable. - * - * @param identity The identity of the player that is trying to obtain the license. - * @return A pair containing a boolean indicating if the player can obtain the license, - */ - suspend fun canObtain(identity: RpIdentity): Pair> -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/LicenseService.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/LicenseService.kt deleted file mode 100644 index acd9727..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/LicenseService.kt +++ /dev/null @@ -1,110 +0,0 @@ -package dev.slne.surf.roleplay.api.player.license - -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.surfapi.core.api.util.requiredService -import it.unimi.dsi.fastutil.objects.ObjectSet -import net.kyori.adventure.key.Key -import org.jetbrains.annotations.Unmodifiable - -private val licenseService = requiredService() - -interface LicenseService { - - /** - * All licenses available in the game. - */ - val licenses: @Unmodifiable ObjectSet - - /** - * Returns the license by its class. - * - * @param license the class of the license to retrieve. - * @return the license instance if found, or null if not found. - */ - fun getLicense(license: Class): License? - - /** - * Returns the license by its class. - * - * @param license the class of the license to retrieve. - * @return the license instance if found, or null if not found. - * @throws IllegalArgumentException if the license is not found. - */ - fun getLicenseOrThrow(license: Class): License - - /** - * Returns the license by its key. - * - * @param key the key of the license to retrieve. - * @return the license instance if found, or null if not found. - */ - fun getLicenseByKey(key: Key): License? - - /** - * Returns the license by its key. - * - * @param key the key of the license to retrieve. - * @return the license instance if found. - * @throws IllegalArgumentException if the license is not found. - */ - fun getLicenseByKeyOrThrow(key: Key): License - - /** - * Creates a new license for the given identity. - * - * @param identityLicense the license to create. - * @return the result of the license creation, including success status and any unobtainable reasons. - */ - suspend fun createLicense(identityLicense: IdentityLicense): IdentityLicense - - /** - * Confiscates a license from the given identity. - * - * @param identity the identity from which the license will be confiscated. - * @param license the license to be confiscated. - * @param confiscatedBy the player who is confiscating the license. - * @param confiscatedReason the reason for confiscation. - * @return a result indicating whether the confiscation was successful. - */ - suspend fun confiscateLicense( - identity: RpIdentity, - license: License, - confiscatedBy: RpPlayer, - confiscatedReason: String - ): Boolean - - /** - * Removes a license from the given identity. - * - * @param identity the identity from which the license will be removed. - * @param license the license to be removed. - * @return true if the removal was successful, false otherwise. - */ - suspend fun removeLicense( - identity: RpIdentity, - license: License - ): Boolean - - companion object : LicenseService by licenseService { - val INSTANCE get() = licenseService - } -} - -/** - * Convenience function to get a license by its type. - * - * @param T the type of the license to retrieve. - * @return the license instance if found, or null if not found. - */ -inline fun LicenseService.getLicense() = getLicense(T::class.java) - -/** - * Convenience function to get a license by its type, or throw an exception if not found. - * - * @param T the type of the license to retrieve. - * @return the license instance if found. - * @throws IllegalArgumentException if the license is not found. - */ -inline fun LicenseService.getLicenseOrThrow() = - getLicenseOrThrow(T::class.java) \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/event/RpPlayerLicenseAddedEvent.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/event/RpPlayerLicenseAddedEvent.kt deleted file mode 100644 index 29a8a59..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/event/RpPlayerLicenseAddedEvent.kt +++ /dev/null @@ -1,14 +0,0 @@ -package dev.slne.surf.roleplay.api.player.license.event - -import dev.slne.surf.roleplay.api.events.CancellableRpEvent -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.api.player.license.IdentityLicense - -class RpPlayerLicenseAddedEvent( - val player: RpPlayer, - val identity: RpIdentity, - val license: IdentityLicense -) : CancellableRpEvent() { - var cancelReason: String? = null -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/event/RpPlayerLicenseRemovedEvent.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/event/RpPlayerLicenseRemovedEvent.kt deleted file mode 100644 index 060ce19..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/event/RpPlayerLicenseRemovedEvent.kt +++ /dev/null @@ -1,14 +0,0 @@ -package dev.slne.surf.roleplay.api.player.license.event - -import dev.slne.surf.roleplay.api.events.CancellableRpEvent -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.api.player.license.IdentityLicense -import dev.slne.surf.roleplay.api.player.license.utils.LicenseRemovedReason - -class RpPlayerLicenseRemovedEvent( - val player: RpPlayer, - val identity: RpIdentity, - val license: IdentityLicense, - val reason: LicenseRemovedReason, -) : CancellableRpEvent() \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/licenses/civilian/CivilianFishingLicense.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/licenses/civilian/CivilianFishingLicense.kt deleted file mode 100644 index 68a00f6..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/licenses/civilian/CivilianFishingLicense.kt +++ /dev/null @@ -1,5 +0,0 @@ -package dev.slne.surf.roleplay.api.player.license.licenses.civilian - -import dev.slne.surf.roleplay.api.player.license.License - -interface CivilianFishingLicense : License \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/licenses/civilian/CivilianVehicleLicense.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/licenses/civilian/CivilianVehicleLicense.kt deleted file mode 100644 index 81391d1..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/licenses/civilian/CivilianVehicleLicense.kt +++ /dev/null @@ -1,14 +0,0 @@ -package dev.slne.surf.roleplay.api.player.license.licenses.civilian - -import dev.slne.surf.roleplay.api.player.license.License - - -interface CivilianVehicleLicense { - interface DriversLicense : License - interface TruckLicense : License - interface BusLicense : License - interface TaxiLicense : License - interface MotorcycleLicense : License - interface BoatLicense : License - interface PilotLicense : License -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/licenses/civilian/CivilianWeaponLicense.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/licenses/civilian/CivilianWeaponLicense.kt deleted file mode 100644 index c09397e..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/licenses/civilian/CivilianWeaponLicense.kt +++ /dev/null @@ -1,8 +0,0 @@ -package dev.slne.surf.roleplay.api.player.license.licenses.civilian - -import dev.slne.surf.roleplay.api.player.license.License - -interface CivilianWeaponLicense { - interface LightWeaponLicense : License - interface HeavyWeaponLicense : License -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/licenses/police/PoliceWeaponLicense.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/licenses/police/PoliceWeaponLicense.kt deleted file mode 100644 index 42c575b..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/licenses/police/PoliceWeaponLicense.kt +++ /dev/null @@ -1,8 +0,0 @@ -package dev.slne.surf.roleplay.api.player.license.licenses.police - -import dev.slne.surf.roleplay.api.player.license.License - -interface PoliceWeaponLicense { - interface LightWeaponLicense : License - interface HeavyWeaponLicense : License -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/utils/LicenseCreateResult.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/utils/LicenseCreateResult.kt deleted file mode 100644 index c9ee17a..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/utils/LicenseCreateResult.kt +++ /dev/null @@ -1,10 +0,0 @@ -package dev.slne.surf.roleplay.api.player.license.utils - -import dev.slne.surf.roleplay.api.player.license.IdentityLicense -import it.unimi.dsi.fastutil.objects.ObjectSet - -data class LicenseCreateResult( - val success: Boolean, - val reason: ObjectSet, - val license: IdentityLicense? -) diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/utils/BalanceType.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/utils/BalanceType.kt deleted file mode 100644 index 8c7bd61..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/utils/BalanceType.kt +++ /dev/null @@ -1,35 +0,0 @@ -package dev.slne.surf.roleplay.api.player.utils - -import dev.slne.surf.roleplay.api.player.identity.RpIdentity - -enum class BalanceType(val currencyName: (RpIdentity) -> String) { - CASH({ - when (it) { - is RpIdentity.CivilianIdentity -> "civilian_cash" - is RpIdentity.PoliceIdentity -> "police_cash" - is RpIdentity.RescueServiceIdentity -> "rescue_service_cash" - else -> error("Unknown identity type: ${it::class.simpleName}") - } - }), - - BANK({ - when (it) { - is RpIdentity.CivilianIdentity -> "civilian_bank" - is RpIdentity.PoliceIdentity -> "police_bank" - is RpIdentity.RescueServiceIdentity -> "rescue_service_bank" - else -> error("Unknown identity type: ${it::class.simpleName}") - } - }), - - CRYPTO({ - when (it) { - is RpIdentity.CivilianIdentity -> "civilian_crypto" - is RpIdentity.PoliceIdentity -> "police_crypto" - is RpIdentity.RescueServiceIdentity -> "rescue_service_crypto" - else -> error("Unknown identity type: ${it::class.simpleName}") - } - }); - - fun getCurrencyName(identity: RpIdentity) = - currencyName(identity).let { "roleplay_$it" } -} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/transaction/RpTransaction.kt b/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/transaction/RpTransaction.kt deleted file mode 100644 index b563b87..0000000 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/transaction/RpTransaction.kt +++ /dev/null @@ -1,45 +0,0 @@ -package dev.slne.surf.roleplay.api.transaction - -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.utils.BalanceType -import java.time.ZonedDateTime -import java.util.* - -interface RpTransaction { - - /** - * Unique identifier for the transaction. - */ - val uniqueId: UUID - - /** - * The sender of the transaction. - */ - val sender: RpPlayer? - - /** - * The receiver of the transaction. - */ - val receiver: RpPlayer? - - /** - * The amount of money involved in the transaction. - */ - val amount: Int - - /** - * The type of balance this transaction affects. - */ - val balanceType: BalanceType - - /** - * A description of the transaction, providing additional context or details. - */ - val description: String? - - /** - * The timestamp when the transaction was created. - */ - val createdAt: ZonedDateTime - -} \ No newline at end of file diff --git a/surf-roleplay-core/build.gradle.kts b/surf-roleplay-core/build.gradle.kts deleted file mode 100644 index 3d359ee..0000000 --- a/surf-roleplay-core/build.gradle.kts +++ /dev/null @@ -1,9 +0,0 @@ -plugins { - id("dev.slne.surf.surfapi.gradle.paper-raw") -} - -dependencies { - api(project(":surf-roleplay-api")) - api(libs.surf.database) - compileOnlyApi(libs.surf.npc.api) -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/RpCore.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/RpCore.kt deleted file mode 100644 index b332ac3..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/RpCore.kt +++ /dev/null @@ -1,11 +0,0 @@ -package dev.slne.surf.roleplay.core - -import com.github.shynixn.mccoroutine.folia.SuspendingJavaPlugin - -val plugin get() = RpCore.plugin - -object RpCore { - - lateinit var plugin: SuspendingJavaPlugin - -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/RpDatabase.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/RpDatabase.kt deleted file mode 100644 index 02c1110..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/RpDatabase.kt +++ /dev/null @@ -1,43 +0,0 @@ -package dev.slne.surf.roleplay.core - -import dev.slne.surf.database.DatabaseManager -import dev.slne.surf.roleplay.core.player.db.RpPlayerTable -import dev.slne.surf.roleplay.core.player.identity.db.impl.civilian.RpPlayerCivilianIdentityTable -import dev.slne.surf.roleplay.core.player.identity.db.impl.police.RpPlayerPoliceIdentityTable -import dev.slne.surf.roleplay.core.player.identity.db.impl.rescueservice.RpPlayerRescueServiceIdentityTable -import dev.slne.surf.roleplay.core.player.license.db.IdentityLicenseTable -import dev.slne.surf.surfapi.core.api.util.mutableObjectSetOf -import org.jetbrains.exposed.sql.SchemaUtils -import org.jetbrains.exposed.sql.Table -import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction -import java.nio.file.Path -import kotlin.io.path.div - -class RpDatabase(val configPath: Path, val storagePath: Path = configPath / "storage") { - - private lateinit var dbManager: DatabaseManager - private val mechanicTables = mutableObjectSetOf() - - fun registerMechanicTable(table: Table) = mechanicTables.add(table) - - suspend fun onLoad() { - dbManager = DatabaseManager(configPath, storagePath) - dbManager.databaseProvider.connect() - - newSuspendedTransaction { - SchemaUtils.create( - RpPlayerTable, - RpPlayerCivilianIdentityTable, - RpPlayerRescueServiceIdentityTable, - RpPlayerPoliceIdentityTable, - IdentityLicenseTable, - *mechanicTables.toTypedArray() - ) - } - } - - fun onDisable() { - dbManager.databaseProvider.disconnect() - } - -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/RpPlayerManagerImpl.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/RpPlayerManagerImpl.kt deleted file mode 100644 index 1e26557..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/RpPlayerManagerImpl.kt +++ /dev/null @@ -1,209 +0,0 @@ -package dev.slne.surf.roleplay.core.player - -import com.github.benmanes.caffeine.cache.Caffeine -import com.google.auto.service.AutoService -import com.sksamuel.aedile.core.asLoadingCache -import com.sksamuel.aedile.core.withRemovalListener -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.RpPlayerManager -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.core.player.db.RpPlayerModel -import dev.slne.surf.roleplay.core.player.db.RpPlayerTable -import dev.slne.surf.roleplay.core.player.identity.db.impl.civilian.RpPlayerCivilianIdentityModel -import dev.slne.surf.roleplay.core.player.identity.db.impl.civilian.RpPlayerCivilianIdentityTable -import dev.slne.surf.roleplay.core.player.identity.db.impl.police.RpPlayerPoliceIdentityModel -import dev.slne.surf.roleplay.core.player.identity.db.impl.police.RpPlayerPoliceIdentityTable -import dev.slne.surf.roleplay.core.player.identity.db.impl.rescueservice.RpPlayerRescueServiceIdentityModel -import dev.slne.surf.roleplay.core.player.identity.db.impl.rescueservice.RpPlayerRescueServiceIdentityTable -import dev.slne.surf.surfapi.core.api.util.getCallerClass -import dev.slne.surf.surfapi.core.api.util.toObjectSet -import kotlinx.coroutines.Dispatchers -import net.kyori.adventure.util.Services -import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq -import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction -import java.time.ZonedDateTime -import java.util.* - -@AutoService(RpPlayerManager::class) -class RpPlayerManagerImpl : RpPlayerManager, Services.Fallback { - - private val cache = Caffeine.newBuilder() - .withRemovalListener { key, _, cause -> - println("Removing RpPlayer from cache: $key due to $cause") - } - .asLoadingCache { - println("Loading RpPlayer from database: $it") - findOrCreate(it).toApi() - } - - override val players - get() = cache.underlying().asMap().values.mapNotNull { it.getNow(null) }.toObjectSet() - - fun onDisconnect(player: RpPlayer) = cache.invalidate(player.uuid) - - suspend fun findOrCreate(uuid: UUID) = newSuspendedTransaction(Dispatchers.IO) { - RpPlayerModel.find { RpPlayerTable.uuid eq uuid }.singleOrNull() ?: RpPlayerModel.new { - this.uuid = uuid - this.createdAt = ZonedDateTime.now() - this.updatedAt = ZonedDateTime.now() - } - } - - suspend fun updateUsername( - rpPlayer: RpPlayerImpl, - username: String - ): Unit = newSuspendedTransaction(Dispatchers.IO) { - rpPlayer.username = username - rpPlayer.updatedAt = ZonedDateTime.now() - - RpPlayerModel.findSingleByAndUpdate((RpPlayerTable.uuid eq rpPlayer.uuid)) { - it.username = username - it.updatedAt = rpPlayer.updatedAt - } - } - - private suspend fun findIdentityByType( - rpPlayer: RpPlayerImpl, - identity: T - ) = newSuspendedTransaction(Dispatchers.IO) { - val rpPlayerModel = rpPlayerManagerImpl.findOrCreate(rpPlayer.uuid) - - when (identity) { - is RpIdentity.CivilianIdentity -> { - RpPlayerCivilianIdentityModel.find { - (RpPlayerCivilianIdentityTable.player eq rpPlayerModel.id) - }.singleOrNull() - } - - is RpIdentity.PoliceIdentity -> { - RpPlayerPoliceIdentityModel.find { - (RpPlayerPoliceIdentityTable.player eq rpPlayerModel.id) - }.singleOrNull() - } - - is RpIdentity.RescueServiceIdentity -> { - RpPlayerRescueServiceIdentityModel.find { - (RpPlayerRescueServiceIdentityTable.player eq rpPlayerModel.id) - }.singleOrNull() - } - - else -> error("Unsupported identity type: ${identity::class.qualifiedName}") - } - } - - @Suppress("UNCHECKED_CAST") - suspend fun createIdentity( - player: RpPlayerImpl, - identity: T - ): T = newSuspendedTransaction(Dispatchers.IO) { - val rpPlayerModel = rpPlayerManagerImpl.findOrCreate(player.uuid) - - val identity = when (identity) { - is RpIdentity.CivilianIdentity -> { - RpPlayerCivilianIdentityModel.new { - this.player = rpPlayerModel - firstName = identity.firstName - lastName = identity.lastName - dateOfBirth = identity.dateOfBirth - createdAt = identity.createdAt - updatedAt = identity.updatedAt - } - } - - is RpIdentity.PoliceIdentity -> { - RpPlayerPoliceIdentityModel.new { - this.player = rpPlayerModel - firstName = identity.firstName - lastName = identity.lastName - dateOfBirth = identity.dateOfBirth - badgeNumber = identity.badgeNumber - rank = identity.rank - createdAt = identity.createdAt - updatedAt = identity.updatedAt - } - } - - is RpIdentity.RescueServiceIdentity -> { - RpPlayerRescueServiceIdentityModel.new { - this.player = rpPlayerModel - firstName = identity.firstName - lastName = identity.lastName - dateOfBirth = identity.dateOfBirth - rank = identity.rank - createdAt = identity.createdAt - updatedAt = identity.updatedAt - } - } - - else -> error("Unsupported identity type: ${identity::class.qualifiedName}") - } - - val api = identity.toApi(player) - player.addIdentity(api) - - api as T - } - - suspend fun createOrUpdateIdentity( - player: RpPlayerImpl, - identity: T - ): T = newSuspendedTransaction(Dispatchers.IO) { - val entity = findIdentityByType(player, identity) - - if (entity == null) { - return@newSuspendedTransaction createIdentity(player, identity) - } - - updateIdentity(player, identity) - } - - suspend fun updateIdentity( - player: RpPlayerImpl, - identity: T, - ): T = newSuspendedTransaction(Dispatchers.IO) { - val entity = findIdentityByType(player, identity) - - identity.updatedAt = ZonedDateTime.now() - - when (entity) { - is RpPlayerCivilianIdentityModel -> { - entity.firstName = identity.firstName - entity.lastName = identity.lastName - entity.dateOfBirth = identity.dateOfBirth - entity.updatedAt = identity.updatedAt - } - - is RpPlayerPoliceIdentityModel -> { - identity as RpIdentity.PoliceIdentity - - entity.firstName = identity.firstName - entity.lastName = identity.lastName - entity.dateOfBirth = identity.dateOfBirth - entity.badgeNumber = identity.badgeNumber - entity.rank = identity.rank - entity.updatedAt = identity.updatedAt - } - - is RpPlayerRescueServiceIdentityModel -> { - identity as RpIdentity.RescueServiceIdentity - - entity.firstName = identity.firstName - entity.lastName = identity.lastName - entity.dateOfBirth = identity.dateOfBirth - entity.rank = identity.rank - entity.updatedAt = identity.updatedAt - } - - else -> error("Unsupported identity type: ${identity::class.qualifiedName}") - } - - identity - } - - override suspend fun get(uuid: UUID): RpPlayer { - println("Caller: " + getCallerClass(1)) - return cache.get(uuid) - } -} - -val rpPlayerManagerImpl get() = RpPlayerManager.INSTANCE as RpPlayerManagerImpl \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/db/RpPlayerModel.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/db/RpPlayerModel.kt deleted file mode 100644 index c318b2e..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/db/RpPlayerModel.kt +++ /dev/null @@ -1,41 +0,0 @@ -package dev.slne.surf.roleplay.core.player.db - -import dev.slne.surf.roleplay.core.player.RpPlayerImpl -import dev.slne.surf.roleplay.core.player.identity.db.impl.civilian.RpPlayerCivilianIdentityModel -import dev.slne.surf.roleplay.core.player.identity.db.impl.civilian.RpPlayerCivilianIdentityTable -import dev.slne.surf.roleplay.core.player.identity.db.impl.police.RpPlayerPoliceIdentityModel -import dev.slne.surf.roleplay.core.player.identity.db.impl.police.RpPlayerPoliceIdentityTable -import dev.slne.surf.roleplay.core.player.identity.db.impl.rescueservice.RpPlayerRescueServiceIdentityModel -import dev.slne.surf.roleplay.core.player.identity.db.impl.rescueservice.RpPlayerRescueServiceIdentityTable -import kotlinx.coroutines.Dispatchers -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID -import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction - -class RpPlayerModel(id: EntityID) : LongEntity(id) { - - companion object : LongEntityClass(RpPlayerTable) - - var uuid by RpPlayerTable.uuid - var username by RpPlayerTable.username - - var createdAt by RpPlayerTable.createdAt - var updatedAt by RpPlayerTable.updatedAt - - val civilianIdentity by RpPlayerCivilianIdentityModel optionalBackReferencedOn RpPlayerCivilianIdentityTable.player - val policeIdentity by RpPlayerPoliceIdentityModel optionalBackReferencedOn RpPlayerPoliceIdentityTable.player - val rescueServiceIdentity by RpPlayerRescueServiceIdentityModel optionalBackReferencedOn RpPlayerRescueServiceIdentityTable.player - - suspend fun toApi() = newSuspendedTransaction(Dispatchers.IO) { - RpPlayerImpl(uuid = uuid).apply { - civilianIdentity?.let { addIdentity(it.toApi(this)) } - policeIdentity?.let { addIdentity(it.toApi(this)) } - rescueServiceIdentity?.let { addIdentity(it.toApi(this)) } - - this.username = this@RpPlayerModel.username - this.createdAt = this@RpPlayerModel.createdAt - this.updatedAt = this@RpPlayerModel.updatedAt - } - } -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/db/RpPlayerTable.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/db/RpPlayerTable.kt deleted file mode 100644 index cef302e..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/db/RpPlayerTable.kt +++ /dev/null @@ -1,15 +0,0 @@ -package dev.slne.surf.roleplay.core.player.db - -import dev.slne.surf.database.database.columns.CurrentZonedDateTime -import dev.slne.surf.database.database.columns.zonedDateTime -import org.jetbrains.exposed.dao.id.LongIdTable - -object RpPlayerTable : LongIdTable("rp_players") { - - val uuid = uuid("uuid").uniqueIndex() - val username = varchar("username", 16).nullable() - - val createdAt = zonedDateTime("created_at").defaultExpression(CurrentZonedDateTime) - val updatedAt = zonedDateTime("updated_at").defaultExpression(CurrentZonedDateTime) - -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/RpIdentityImpl.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/RpIdentityImpl.kt deleted file mode 100644 index 6c4f1ea..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/RpIdentityImpl.kt +++ /dev/null @@ -1,178 +0,0 @@ -package dev.slne.surf.roleplay.core.player.identity - -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.api.player.license.ExpirableLicense -import dev.slne.surf.roleplay.api.player.license.IdentityLicense -import dev.slne.surf.roleplay.api.player.license.License -import dev.slne.surf.roleplay.api.player.license.LicenseService -import dev.slne.surf.roleplay.api.player.license.event.RpPlayerLicenseAddedEvent -import dev.slne.surf.roleplay.api.player.license.event.RpPlayerLicenseRemovedEvent -import dev.slne.surf.roleplay.api.player.license.utils.LicenseCreateResult -import dev.slne.surf.roleplay.api.player.license.utils.LicenseRemovedReason -import dev.slne.surf.roleplay.api.player.license.utils.UnobtainableReason -import dev.slne.surf.roleplay.api.player.utils.BalanceType -import dev.slne.surf.roleplay.api.transaction.RpTransaction -import dev.slne.surf.surfapi.core.api.util.mutableObject2ObjectMapOf -import dev.slne.surf.surfapi.core.api.util.mutableObjectSetOf -import dev.slne.surf.surfapi.core.api.util.objectSetOf -import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet -import java.time.LocalDate -import java.time.ZonedDateTime - -abstract class RpIdentityImpl( - override val player: RpPlayer, - override val type: RpIdentity.RpIdentityType, - override var firstName: String, - override var lastName: String, - override var dateOfBirth: LocalDate, - override val createdAt: ZonedDateTime = ZonedDateTime.now(), - override var updatedAt: ZonedDateTime = ZonedDateTime.now() -) : RpIdentity { - - private val _licenses = mutableObjectSetOf() - override val licenses get() = _licenses - - fun addLicense(license: IdentityLicense) { - _licenses.add(license) - } - - override suspend fun addLicense(license: License): LicenseCreateResult { - val (canObtain, reason) = license.canObtain(this) - - if (!canObtain) { - return LicenseCreateResult(false, reason, null) - } - - val expiresAt = if (license is ExpirableLicense) { - ZonedDateTime.now().plusSeconds(license.expiresIn.inWholeSeconds) - } else { - null - } - - val playerLicense = IdentityLicense( - identity = this, - license = license, - expiresAt = expiresAt, - ) - - val event = RpPlayerLicenseAddedEvent( - player = player, - identity = this, - license = playerLicense, - ) - - if (!event.callEvent()) { - return LicenseCreateResult( - false, - objectSetOf(UnobtainableReason.EventCancelled(event.cancelReason)), - null - ) - } - - player.removeCashBalance(license.price) - - val createdPlayerLicense = LicenseService.createLicense(playerLicense) - _licenses.add(createdPlayerLicense) - - return LicenseCreateResult( - true, - objectSetOf(), - createdPlayerLicense - ) - } - - override suspend fun removeLicense(license: License, reason: LicenseRemovedReason): Boolean { - val playerLicense = getLicense(license.javaClass) ?: return false - - val event = RpPlayerLicenseRemovedEvent( - player = player, - identity = this, - license = playerLicense, - reason = reason - ) - - if (!event.callEvent()) { - return false - } - - val result = LicenseService.removeLicense(this, license) - - if (result) { - _licenses.removeIf { it.license == license } - } - - return result - } - - override suspend fun confiscateLicense( - identity: RpIdentity, - license: License, - confiscatedBy: RpPlayer, - confiscatedReason: String - ) = LicenseService.confiscateLicense(identity, license, confiscatedBy, confiscatedReason) - - override fun getLicense(license: Class) = - _licenses.firstOrNull { it.license::class.java == license } - - override fun hasLicense(license: Class) = - _licenses.any { it.license::class.java == license } - - private val currencyMap = mutableObject2ObjectMapOf( - BalanceType.CASH to 0, - BalanceType.BANK to 0, - BalanceType.CRYPTO to 0 - ) - - override suspend fun getBalance(balanceType: BalanceType): Int { - val currencyName = balanceType.getCurrencyName(this) - ?: throw IllegalArgumentException("Unknown balance type: $balanceType") - - return currencyMap[balanceType] ?: 0 - } - - override suspend fun addBalance( - balanceType: BalanceType, - amount: Int - ): Boolean { - val currencyName = balanceType.getCurrencyName(this) - ?: throw IllegalArgumentException("Unknown balance type: $balanceType") - - return if (amount > 0) { - currencyMap[balanceType] = (currencyMap[balanceType] ?: 0) + amount - true - } else { - false - } - } - - override suspend fun removeBalance( - balanceType: BalanceType, - amount: Int - ): Boolean { - val currencyName = balanceType.getCurrencyName(this) - ?: throw IllegalArgumentException("Unknown balance type: $balanceType") - - return if (amount > 0 && (currencyMap[balanceType] ?: 0) >= amount) { - currencyMap[balanceType] = (currencyMap[balanceType] ?: 0) - amount - true - } else { - false - } - } - - override suspend fun getBalanceHistory( - balanceType: BalanceType, - limit: Int - ): ObjectLinkedOpenHashSet { - val currencyName = balanceType.getCurrencyName(this) - ?: throw IllegalArgumentException("Unknown balance type: $balanceType") - - return ObjectLinkedOpenHashSet() - } - - override fun toString(): String { - return "RpIdentityImpl(type=$type, firstName='$firstName', lastName='$lastName', dateOfBirth=$dateOfBirth, createdAt=$createdAt, updatedAt=$updatedAt, licenses=$licenses)" - } - -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/RpPlayerIdentityBaseModel.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/RpPlayerIdentityBaseModel.kt deleted file mode 100644 index 16584ba..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/RpPlayerIdentityBaseModel.kt +++ /dev/null @@ -1,23 +0,0 @@ -package dev.slne.surf.roleplay.core.player.identity.db - -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.core.player.db.RpPlayerModel -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.id.EntityID - -abstract class RpPlayerIdentityBaseModel( - id: EntityID, - table: RpPlayerIdentityBaseTable -) : LongEntity(id) { - var player by RpPlayerModel referencedOn table.player - - var firstName by table.firstName - var lastName by table.lastName - var dateOfBirth by table.dateOfBirth - - var createdAt by table.createdAt - var updatedAt by table.updatedAt - - abstract suspend fun toApi(player: RpPlayer): I -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/RpPlayerIdentityBaseTable.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/RpPlayerIdentityBaseTable.kt deleted file mode 100644 index cf6003c..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/RpPlayerIdentityBaseTable.kt +++ /dev/null @@ -1,24 +0,0 @@ -package dev.slne.surf.roleplay.core.player.identity.db - -import dev.slne.surf.database.database.columns.CurrentZonedDateTime -import dev.slne.surf.database.database.columns.zonedDateTime -import dev.slne.surf.roleplay.core.player.db.RpPlayerTable -import org.jetbrains.exposed.dao.id.LongIdTable -import org.jetbrains.exposed.sql.ReferenceOption -import org.jetbrains.exposed.sql.javatime.date - -abstract class RpPlayerIdentityBaseTable(table: String) : LongIdTable(table) { - val player = reference( - "player_id", - RpPlayerTable, - onDelete = ReferenceOption.CASCADE, - onUpdate = ReferenceOption.CASCADE - ).uniqueIndex() - - val firstName = varchar("first_name", 16) - val lastName = varchar("last_name", 16) - val dateOfBirth = date("date_of_birth") - - val createdAt = zonedDateTime("created_at").defaultExpression(CurrentZonedDateTime) - val updatedAt = zonedDateTime("updated_at").defaultExpression(CurrentZonedDateTime) -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/impl/civilian/RpPlayerCivilianIdentityModel.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/impl/civilian/RpPlayerCivilianIdentityModel.kt deleted file mode 100644 index 1f77b4f..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/impl/civilian/RpPlayerCivilianIdentityModel.kt +++ /dev/null @@ -1,31 +0,0 @@ -package dev.slne.surf.roleplay.core.player.identity.db.impl.civilian - -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.core.player.identity.db.RpPlayerIdentityBaseModel -import dev.slne.surf.roleplay.core.player.identity.identities.CivilianIdentityImpl -import dev.slne.surf.roleplay.core.player.license.licenseServiceImpl -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID - -class RpPlayerCivilianIdentityModel( - id: EntityID -) : RpPlayerIdentityBaseModel( - id, - RpPlayerCivilianIdentityTable -) { - companion object : LongEntityClass(RpPlayerCivilianIdentityTable) - - override suspend fun toApi(player: RpPlayer) = CivilianIdentityImpl( - player = player, - firstName = firstName, - lastName = lastName, - dateOfBirth = dateOfBirth, - createdAt = createdAt, - updatedAt = updatedAt, - ).apply { - licenseServiceImpl.fetchLicenses(this).forEach { - addLicense(it) - } - } -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/impl/civilian/RpPlayerCivilianIdentityTable.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/impl/civilian/RpPlayerCivilianIdentityTable.kt deleted file mode 100644 index 5e52f06..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/impl/civilian/RpPlayerCivilianIdentityTable.kt +++ /dev/null @@ -1,5 +0,0 @@ -package dev.slne.surf.roleplay.core.player.identity.db.impl.civilian - -import dev.slne.surf.roleplay.core.player.identity.db.RpPlayerIdentityBaseTable - -object RpPlayerCivilianIdentityTable : RpPlayerIdentityBaseTable("rp_player_civilian_identities") \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/impl/police/RpPlayerPoliceIdentityModel.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/impl/police/RpPlayerPoliceIdentityModel.kt deleted file mode 100644 index 90154d2..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/impl/police/RpPlayerPoliceIdentityModel.kt +++ /dev/null @@ -1,36 +0,0 @@ -package dev.slne.surf.roleplay.core.player.identity.db.impl.police - -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.core.player.identity.db.RpPlayerIdentityBaseModel -import dev.slne.surf.roleplay.core.player.identity.identities.PoliceIdentityImpl -import dev.slne.surf.roleplay.core.player.license.licenseServiceImpl -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID - -class RpPlayerPoliceIdentityModel( - id: EntityID -) : RpPlayerIdentityBaseModel( - id, - RpPlayerPoliceIdentityTable -) { - companion object : LongEntityClass(RpPlayerPoliceIdentityTable) - - var badgeNumber by RpPlayerPoliceIdentityTable.badgeNumber - var rank by RpPlayerPoliceIdentityTable.rank - - override suspend fun toApi(player: RpPlayer) = PoliceIdentityImpl( - player = player, - firstName = firstName, - lastName = lastName, - dateOfBirth = dateOfBirth, - badgeNumber = badgeNumber, - rank = rank, - createdAt = createdAt, - updatedAt = updatedAt, - ).apply { - licenseServiceImpl.fetchLicenses(this).forEach { - addLicense(it) - } - } -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/impl/rescueservice/RpPlayerRescueServiceIdentityModel.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/impl/rescueservice/RpPlayerRescueServiceIdentityModel.kt deleted file mode 100644 index 675ea64..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/impl/rescueservice/RpPlayerRescueServiceIdentityModel.kt +++ /dev/null @@ -1,35 +0,0 @@ -package dev.slne.surf.roleplay.core.player.identity.db.impl.rescueservice - -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.core.player.identity.db.RpPlayerIdentityBaseModel -import dev.slne.surf.roleplay.core.player.identity.identities.RescueServiceIdentityImpl -import dev.slne.surf.roleplay.core.player.license.licenseServiceImpl -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID - -class RpPlayerRescueServiceIdentityModel( - id: EntityID -) : RpPlayerIdentityBaseModel( - id, - RpPlayerRescueServiceIdentityTable -) { - companion object : - LongEntityClass(RpPlayerRescueServiceIdentityTable) - - var rank by RpPlayerRescueServiceIdentityTable.rank - - override suspend fun toApi(player: RpPlayer) = RescueServiceIdentityImpl( - player = player, - firstName = firstName, - lastName = lastName, - dateOfBirth = dateOfBirth, - rank = rank, - createdAt = createdAt, - updatedAt = updatedAt, - ).apply { - licenseServiceImpl.fetchLicenses(this).forEach { - addLicense(it) - } - } -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/impl/rescueservice/RpPlayerRescueServiceIdentityTable.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/impl/rescueservice/RpPlayerRescueServiceIdentityTable.kt deleted file mode 100644 index 5c259f9..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/impl/rescueservice/RpPlayerRescueServiceIdentityTable.kt +++ /dev/null @@ -1,9 +0,0 @@ -package dev.slne.surf.roleplay.core.player.identity.db.impl.rescueservice - -import dev.slne.surf.roleplay.core.player.identity.db.RpPlayerIdentityBaseTable - -object RpPlayerRescueServiceIdentityTable : RpPlayerIdentityBaseTable( - "rp_player_rescue_service_identities" -) { - val rank = varchar("rank", 255) -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/identities/CivilianIdentityImpl.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/identities/CivilianIdentityImpl.kt deleted file mode 100644 index ce81760..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/identities/CivilianIdentityImpl.kt +++ /dev/null @@ -1,30 +0,0 @@ -package dev.slne.surf.roleplay.core.player.identity.identities - -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.core.player.identity.RpIdentityImpl -import java.time.LocalDate -import java.time.ZonedDateTime - -class CivilianIdentityImpl( - player: RpPlayer, - firstName: String, - lastName: String, - dateOfBirth: LocalDate, - createdAt: ZonedDateTime = ZonedDateTime.now(), - updatedAt: ZonedDateTime = ZonedDateTime.now() -) : RpIdentityImpl( - player, - type = RpIdentity.RpIdentityType.CIVILIAN, - firstName, - lastName, - dateOfBirth, - createdAt, - updatedAt -), RpIdentity.CivilianIdentity { - override fun toString(): String { - val parent = super.toString() - - return "CivilianIdentityImpl($parent)" - } -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/identities/PoliceIdentityImpl.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/identities/PoliceIdentityImpl.kt deleted file mode 100644 index d8e3bb8..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/identities/PoliceIdentityImpl.kt +++ /dev/null @@ -1,32 +0,0 @@ -package dev.slne.surf.roleplay.core.player.identity.identities - -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.core.player.identity.RpIdentityImpl -import java.time.LocalDate -import java.time.ZonedDateTime - -class PoliceIdentityImpl( - player: RpPlayer, - firstName: String, - lastName: String, - dateOfBirth: LocalDate, - override val badgeNumber: String, - override val rank: String, - createdAt: ZonedDateTime = ZonedDateTime.now(), - updatedAt: ZonedDateTime = ZonedDateTime.now() -) : RpIdentityImpl( - player = player, - type = RpIdentity.RpIdentityType.POLICE, - firstName, - lastName, - dateOfBirth, - createdAt, - updatedAt -), RpIdentity.PoliceIdentity { - override fun toString(): String { - val parent = super.toString() - - return "PoliceIdentityImpl(badgeNumber='$badgeNumber', rank='$rank', $parent)" - } -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/identities/RescueServiceIdentityImpl.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/identities/RescueServiceIdentityImpl.kt deleted file mode 100644 index 984cc8a..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/identities/RescueServiceIdentityImpl.kt +++ /dev/null @@ -1,31 +0,0 @@ -package dev.slne.surf.roleplay.core.player.identity.identities - -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.core.player.identity.RpIdentityImpl -import java.time.LocalDate -import java.time.ZonedDateTime - -class RescueServiceIdentityImpl( - player: RpPlayer, - firstName: String, - lastName: String, - dateOfBirth: LocalDate, - override val rank: String, - createdAt: ZonedDateTime = ZonedDateTime.now(), - updatedAt: ZonedDateTime = ZonedDateTime.now() -) : RpIdentityImpl( - player = player, - type = RpIdentity.RpIdentityType.RESCUE_SERVICE, - firstName, - lastName, - dateOfBirth, - createdAt, - updatedAt -), RpIdentity.RescueServiceIdentity { - override fun toString(): String { - val parent = super.toString() - - return "RescueServiceIdentityImpl(rank='$rank', $parent)" - } -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/LicenseExpirationJob.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/LicenseExpirationJob.kt deleted file mode 100644 index ffd0330..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/LicenseExpirationJob.kt +++ /dev/null @@ -1,17 +0,0 @@ -package dev.slne.surf.roleplay.core.player.license - -import dev.slne.surf.roleplay.api.coroutine.RpJob -import dev.slne.surf.roleplay.api.player.license.utils.LicenseRemovedReason -import kotlin.time.Duration.Companion.seconds - -object LicenseExpirationJob : RpJob("LicenseExpirationJob", 1.seconds) { - override suspend fun tick() { - val licenses = licenseServiceImpl.getAllExpiredLicenses() - - licenses.forEach { (identity, expiredLicenses) -> - expiredLicenses.forEach { expiredLicense -> - identity.removeLicense(expiredLicense.license, LicenseRemovedReason.Expired) - } - } - } -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/LicenseImpl.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/LicenseImpl.kt deleted file mode 100644 index 782a280..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/LicenseImpl.kt +++ /dev/null @@ -1,76 +0,0 @@ -package dev.slne.surf.roleplay.core.player.license - -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.api.player.license.License -import dev.slne.surf.roleplay.api.player.license.utils.UnobtainableReason -import dev.slne.surf.roleplay.core.player.license.utils.LicensePermissionRegistry -import dev.slne.surf.surfapi.bukkit.api.builder.LoreBuilder -import dev.slne.surf.surfapi.core.api.util.mutableObjectSetOf -import dev.slne.surf.surfapi.core.api.util.objectSetOf -import dev.slne.surf.surfapi.core.api.util.toObjectSet -import it.unimi.dsi.fastutil.objects.ObjectSet -import net.kyori.adventure.key.Key -import net.kyori.adventure.text.Component - -abstract class LicenseImpl( - override val key: Key, - override val displayName: Component, - override val description: LoreBuilder.() -> Unit, - override val price: Int, - override val dependencies: ObjectSet = objectSetOf(), - override val permission: String = LicensePermissionRegistry.createLicensePermission(key) -) : License { - - override val children - get() = licenseServiceImpl.licenses.filter { - it.dependencies.contains(this) - }.toObjectSet() - - override suspend fun canObtain(identity: RpIdentity): Pair> { - val player = identity.player - val reasons = mutableObjectSetOf() - - if (!player.hasPermission(permission)) { - reasons.add(UnobtainableReason.NoPermissions) - } - - if (identity.hasLicense(this)) { - reasons.add(UnobtainableReason.AlreadyHasLicense) - } - - val missingDependencies = dependencies - .filterNot { identity.hasLicense(it) } - .toObjectSet() - - if (missingDependencies.isNotEmpty()) { - reasons.add(UnobtainableReason.DependenciesNotMet(missingDependencies)) - } - - if (!player.hasCashBalance(price)) { - reasons.add( - UnobtainableReason.NotEnoughCash( - currentAmount = player.getCashBalance(), - neededAmount = price - ) - ) - } - - return reasons.isEmpty() to reasons - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is LicenseImpl) return false - - if (key != other.key) return false - - return true - } - - override fun hashCode() = key.hashCode() - - override fun toString(): String { - return "LicenseImpl(key=$key, displayName=$displayName, description=$description, price=$price, dependencies=$dependencies, permission='$permission')" - } - -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/LicenseServiceImpl.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/LicenseServiceImpl.kt deleted file mode 100644 index 44f5a05..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/LicenseServiceImpl.kt +++ /dev/null @@ -1,195 +0,0 @@ -package dev.slne.surf.roleplay.core.player.license - -import com.github.shynixn.mccoroutine.folia.launch -import com.google.auto.service.AutoService -import dev.jorel.commandapi.arguments.ArgumentSuggestions -import dev.jorel.commandapi.kotlindsl.commandAPICommand -import dev.jorel.commandapi.kotlindsl.getValue -import dev.jorel.commandapi.kotlindsl.playerExecutor -import dev.jorel.commandapi.kotlindsl.textArgument -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.RpPlayerManager -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.api.player.license.IdentityLicense -import dev.slne.surf.roleplay.api.player.license.License -import dev.slne.surf.roleplay.api.player.license.LicenseService -import dev.slne.surf.roleplay.api.player.license.utils.LicenseRemovedReason -import dev.slne.surf.roleplay.core.player.license.db.IdentityLicenseModel -import dev.slne.surf.roleplay.core.player.license.db.IdentityLicenseTable -import dev.slne.surf.roleplay.core.player.license.licenses.civilian.CivilianFishingLicenseImpl -import dev.slne.surf.roleplay.core.player.license.licenses.civilian.CivilianVehicleLicenseImpl -import dev.slne.surf.roleplay.core.player.license.licenses.civilian.CivilianWeaponLicenseImpl -import dev.slne.surf.roleplay.core.player.license.listeners.LicenseBuyHandler -import dev.slne.surf.roleplay.core.player.license.listeners.LicenseChangedHandler -import dev.slne.surf.roleplay.core.player.rpPlayerManagerImpl -import dev.slne.surf.roleplay.core.plugin -import dev.slne.surf.surfapi.bukkit.api.event.register -import dev.slne.surf.surfapi.core.api.messages.adventure.key -import dev.slne.surf.surfapi.core.api.messages.adventure.sendText -import dev.slne.surf.surfapi.core.api.util.freeze -import dev.slne.surf.surfapi.core.api.util.mutableObjectSetOf -import dev.slne.surf.surfapi.core.api.util.toObjectList -import kotlinx.coroutines.Dispatchers -import net.kyori.adventure.key.Key -import net.kyori.adventure.util.Services -import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction - -@AutoService(LicenseService::class) -class LicenseServiceImpl : LicenseService, Services.Fallback { - - suspend fun onLoad() { - _licenses.add(CivilianFishingLicenseImpl) - - CivilianWeaponLicenseImpl.register { _licenses.add(it) } - CivilianVehicleLicenseImpl.register { _licenses.add(it) } - } - - suspend fun onEnable() { - LicenseExpirationJob.start() - - LicenseChangedHandler.register() - LicenseBuyHandler.register() - - LicenseNpc.spawnNpc() - - commandAPICommand("give-license") { - textArgument("licenseName") { - replaceSuggestions( - ArgumentSuggestions.stringCollection { - licenses.map { it.key.asString() } - } - ) - } - - playerExecutor { player, args -> - val licenseName: String by args - val namespace = licenseName.substringBefore(":") - val value = licenseName.substringAfter(":") - val license = LicenseService.getLicenseByKey(key(namespace, value)) - - if (license == null) { - player.sendText { - appendPrefix() - - error("Die Lizenz ") - variableValue(licenseName) - error(" konnte nicht gefunden werden.") - } - - return@playerExecutor - } - - plugin.launch { - RpPlayer[player.uniqueId].addLicense(license) - } - } - } - } - - suspend fun onDisable() { - LicenseExpirationJob.stop() - } - - private val _licenses = mutableObjectSetOf() - override val licenses get() = _licenses.freeze() - - suspend fun fetchLicenses(identity: RpIdentity) = newSuspendedTransaction(Dispatchers.IO) { - val rpPlayerModel = rpPlayerManagerImpl.findOrCreate(identity.player.uuid) - - IdentityLicenseModel.find { - (IdentityLicenseTable.player eq rpPlayerModel.id) and - (IdentityLicenseTable.identity eq identity.type) - }.map { it.toApi(identity) }.toObjectList() - } - - override fun getLicense(license: Class) = - _licenses.firstOrNull { license.isAssignableFrom(it::class.java) } - - override fun getLicenseOrThrow(license: Class) = - getLicense(license) ?: error("License not found: ${license.name}") - - override fun getLicenseByKey(key: Key) = _licenses.firstOrNull { it.key == key } - - override fun getLicenseByKeyOrThrow(key: Key) = - getLicenseByKey(key) ?: error("License not found: $key") - - override suspend fun createLicense( - identityLicense: IdentityLicense - ) = newSuspendedTransaction(Dispatchers.IO) { - val (license, identity, expiresAt, createdAt) = identityLicense - val rpPlayerModel = rpPlayerManagerImpl.findOrCreate(identity.player.uuid) - - IdentityLicenseModel.new { - this.player = rpPlayerModel - this.identity = identity.type - this.license = license.key.asString() - this.expiresAt = expiresAt - this.createdAt = createdAt - }.toApi(identityLicense.identity) - } - - override suspend fun confiscateLicense( - identity: RpIdentity, - license: License, - confiscatedBy: RpPlayer, - confiscatedReason: String - ) = newSuspendedTransaction(Dispatchers.IO) { - val player = identity.player - val parentLicense = player.getIdentity(identity.type)?.getLicense(license::class.java) - ?: return@newSuspendedTransaction false - - val parentResult = player.removeLicense( - license, - LicenseRemovedReason.Confiscated(confiscatedBy, confiscatedReason) - ) - - val childrenResults = license.children.map { childLicense -> - if (player.hasLicense(childLicense)) { - player.removeLicense( - childLicense, - LicenseRemovedReason.ConfiscatedChild( - parentLicense, - confiscatedBy, - confiscatedReason - ) - ) - return@map true - } - - false - } - - parentResult && childrenResults.all { it } - } - - override suspend fun removeLicense( - identity: RpIdentity, - license: License - ) = newSuspendedTransaction(Dispatchers.IO) { - val player = identity.player - val rpPlayerModel = rpPlayerManagerImpl.findOrCreate(player.uuid) - val playerLicense = IdentityLicenseModel.find { - (IdentityLicenseTable.player eq rpPlayerModel.id) and - (IdentityLicenseTable.identity eq identity.type) and - (IdentityLicenseTable.license eq license.key.asString()) - } - - if (playerLicense.empty()) { - return@newSuspendedTransaction false - } - - playerLicense.forEach { it.delete() } - - true - } - - fun getAllExpiredLicenses() = RpPlayerManager.players - .mapNotNull { - val activeIdentity = it.activeIdentity ?: return@mapNotNull null - - activeIdentity to activeIdentity.licenses.filter { license -> license.isExpired } - }.toObjectList() -} - -val licenseServiceImpl get() = LicenseService.INSTANCE as LicenseServiceImpl \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/db/IdentityLicenseModel.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/db/IdentityLicenseModel.kt deleted file mode 100644 index b4d5683..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/db/IdentityLicenseModel.kt +++ /dev/null @@ -1,50 +0,0 @@ -package dev.slne.surf.roleplay.core.player.license.db - -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.api.player.license.IdentityLicense -import dev.slne.surf.roleplay.api.player.license.LicenseService -import dev.slne.surf.roleplay.core.player.db.RpPlayerModel -import dev.slne.surf.surfapi.core.api.messages.adventure.key -import org.jetbrains.exposed.dao.LongEntity -import org.jetbrains.exposed.dao.LongEntityClass -import org.jetbrains.exposed.dao.id.EntityID - -class IdentityLicenseModel(id: EntityID) : LongEntity(id) { - - companion object : LongEntityClass(IdentityLicenseTable) - - var player by RpPlayerModel referencedOn IdentityLicenseTable.player - var identity by IdentityLicenseTable.identity - - var license by IdentityLicenseTable.license - var expiresAt by IdentityLicenseTable.expiresAt - var createdAt by IdentityLicenseTable.createdAt - - fun toApi(identity: RpIdentity): IdentityLicense { - val license = IdentityLicense( - identity = identity, - license = LicenseService.getLicenseByKeyOrThrow(key(license)), - expiresAt = expiresAt, - createdAt = createdAt - ) - - return license - } - - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is IdentityLicenseModel) return false - - if (player != other.player) return false - if (license != other.license) return false - if (identity != other.identity) return false - - return true - } - - override fun hashCode(): Int { - var result = player.hashCode() - result = 31 * result + license.hashCode() - return result - } -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/db/IdentityLicenseTable.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/db/IdentityLicenseTable.kt deleted file mode 100644 index ece6f30..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/db/IdentityLicenseTable.kt +++ /dev/null @@ -1,24 +0,0 @@ -package dev.slne.surf.roleplay.core.player.license.db - -import dev.slne.surf.database.database.columns.CurrentZonedDateTime -import dev.slne.surf.database.database.columns.zonedDateTime -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.core.player.db.RpPlayerTable -import org.jetbrains.exposed.dao.id.LongIdTable -import org.jetbrains.exposed.sql.ReferenceOption - -object IdentityLicenseTable : LongIdTable("identity_licenses") { - - val player = reference( - "player_id", RpPlayerTable, - onUpdate = ReferenceOption.CASCADE, - onDelete = ReferenceOption.CASCADE - ) - val identity = enumerationByName("identity", 255) - - val license = varchar("license", 255) - - val expiresAt = zonedDateTime("expires_at").nullable() - val createdAt = zonedDateTime("created_at").defaultExpression(CurrentZonedDateTime) - -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/licenses/civilian/CivilianFishingLicenseImpl.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/licenses/civilian/CivilianFishingLicenseImpl.kt deleted file mode 100644 index 3211cef..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/licenses/civilian/CivilianFishingLicenseImpl.kt +++ /dev/null @@ -1,17 +0,0 @@ -package dev.slne.surf.roleplay.core.player.license.licenses.civilian - -import dev.slne.surf.roleplay.api.player.license.licenses.civilian.CivilianFishingLicense -import dev.slne.surf.roleplay.core.player.license.LicenseImpl -import dev.slne.surf.surfapi.core.api.messages.adventure.buildText -import dev.slne.surf.surfapi.core.api.messages.adventure.key - -object CivilianFishingLicenseImpl : LicenseImpl( - key = key("roleplay", "fishing_license"), - displayName = buildText { primary("Angelschein") }, - description = { - line { - spacer("Die Angel-Lizenz erlaubt es dir, in der Wildnis zu angeln.") - } - }, - price = 500, -), CivilianFishingLicense \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/licenses/civilian/CivilianVehicleLicenseImpl.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/licenses/civilian/CivilianVehicleLicenseImpl.kt deleted file mode 100644 index ae845b7..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/licenses/civilian/CivilianVehicleLicenseImpl.kt +++ /dev/null @@ -1,110 +0,0 @@ -package dev.slne.surf.roleplay.core.player.license.licenses.civilian - -import dev.slne.surf.roleplay.api.player.license.License -import dev.slne.surf.roleplay.api.player.license.licenses.civilian.CivilianVehicleLicense -import dev.slne.surf.roleplay.core.player.license.ExpirableLicenseImpl -import dev.slne.surf.roleplay.core.player.license.LicenseImpl -import dev.slne.surf.surfapi.core.api.messages.adventure.key -import dev.slne.surf.surfapi.core.api.util.objectSetOf -import net.kyori.adventure.text.Component -import kotlin.time.Duration.Companion.minutes - -object CivilianVehicleLicenseImpl { - fun register(registration: (License) -> Boolean) { - registration(DriversLicenseImpl) - registration(TruckLicenseImpl) - registration(BusLicenseImpl) - registration(TaxiLicenseImpl) - registration(MotorcycleLicenseImpl) - registration(BoatLicenseImpl) - registration(PilotLicenseImpl) - } - - object DriversLicenseImpl : LicenseImpl( - key = key("roleplay", "drivers_license"), - displayName = Component.text("Führerschein"), - description = { - line { - spacer("Der Führerschein erlaubt es dir, Fahrzeuge zu führen.") - } - }, - price = 1000, - ), CivilianVehicleLicense.DriversLicense - - object TruckLicenseImpl : ExpirableLicenseImpl( - key = key("roleplay", "truck_license"), - displayName = Component.text("Lkw-Führerschein"), - description = { - line { - spacer("Der Lkw-Führerschein erlaubt es dir, Lastkraftwagen zu fahren.") - } - }, - price = 2000, - expiresIn = 5.minutes, - dependencies = objectSetOf( - DriversLicenseImpl, - BusLicenseImpl - ) - ), CivilianVehicleLicense.TruckLicense - - object BusLicenseImpl : LicenseImpl( - key = key("roleplay", "bus_license"), - displayName = Component.text("Bus-Führerschein"), - description = { - line { - spacer("Der Bus-Führerschein erlaubt es dir, Busse zu fahren.") - } - }, - price = 2500, - dependencies = objectSetOf( - DriversLicenseImpl - ) - ), CivilianVehicleLicense.BusLicense - - object TaxiLicenseImpl : LicenseImpl( - key = key("roleplay", "taxi_license"), - displayName = Component.text("Taxi-Führerschein"), - description = { - line { - spacer("Der Taxi-Führerschein erlaubt es dir, Taxis zu fahren.") - } - }, - price = 3000, - dependencies = objectSetOf( - DriversLicenseImpl - ) - ), CivilianVehicleLicense.TaxiLicense - - object MotorcycleLicenseImpl : LicenseImpl( - key = key("roleplay", "motorcycle_license"), - displayName = Component.text("Motorrad-Führerschein"), - description = { - line { - spacer("Der Motorrad-Führerschein erlaubt es dir, Motorräder zu fahren.") - } - }, - price = 1500, - ), CivilianVehicleLicense.MotorcycleLicense - - object BoatLicenseImpl : LicenseImpl( - key = key("roleplay", "boat_license"), - displayName = Component.text("Bootsführerschein"), - description = { - line { - spacer("Der Bootsführerschein erlaubt es dir, Boote zu fahren.") - } - }, - price = 1800, - ), CivilianVehicleLicense.BoatLicense - - object PilotLicenseImpl : LicenseImpl( - key = key("roleplay", "pilot_license"), - displayName = Component.text("Pilotenschein"), - description = { - line { - spacer("Der Pilotenschein erlaubt es dir, Flugzeuge zu fliegen.") - } - }, - price = 5000, - ), CivilianVehicleLicense.PilotLicense -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/licenses/civilian/CivilianWeaponLicenseImpl.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/licenses/civilian/CivilianWeaponLicenseImpl.kt deleted file mode 100644 index d427d72..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/licenses/civilian/CivilianWeaponLicenseImpl.kt +++ /dev/null @@ -1,40 +0,0 @@ -package dev.slne.surf.roleplay.core.player.license.licenses.civilian - -import dev.slne.surf.roleplay.api.player.license.License -import dev.slne.surf.roleplay.api.player.license.licenses.civilian.CivilianWeaponLicense -import dev.slne.surf.roleplay.core.player.license.LicenseImpl -import dev.slne.surf.surfapi.core.api.messages.adventure.buildText -import dev.slne.surf.surfapi.core.api.messages.adventure.key -import dev.slne.surf.surfapi.core.api.util.objectSetOf - -object CivilianWeaponLicenseImpl { - fun register(registration: (License) -> Boolean) { - registration(LightWeaponLicenseImpl) - registration(HeavyWeaponLicenseImpl) - } - - object LightWeaponLicenseImpl : LicenseImpl( - key = key("roleplay", "light_weapon_license"), - displayName = buildText { success("Kleiner Waffenschein") }, - description = { - line { - info("Erlaubt das Führen von leichten Waffen wie Pistolen und Revolvern.") - } - }, - price = 5000 - ), CivilianWeaponLicense.LightWeaponLicense - - object HeavyWeaponLicenseImpl : LicenseImpl( - key = key("roleplay", "heavy_weapon_license"), - displayName = buildText { error("Großer Waffenschein") }, - description = { - line { - info("Erlaubt das Führen von schweren Waffen wie Maschinengewehren und Scharfschützengewehren.") - } - }, - price = 10000, - dependencies = objectSetOf( - LightWeaponLicenseImpl - ) - ), CivilianWeaponLicense.HeavyWeaponLicense -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/listeners/LicenseChangedHandler.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/listeners/LicenseChangedHandler.kt deleted file mode 100644 index ee7063a..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/listeners/LicenseChangedHandler.kt +++ /dev/null @@ -1,60 +0,0 @@ -package dev.slne.surf.roleplay.core.player.license.listeners - -import com.github.shynixn.mccoroutine.folia.entityDispatcher -import com.github.shynixn.mccoroutine.folia.launch -import dev.slne.surf.roleplay.api.player.license.event.RpPlayerLicenseAddedEvent -import dev.slne.surf.roleplay.api.player.license.event.RpPlayerLicenseRemovedEvent -import dev.slne.surf.roleplay.core.plugin -import dev.slne.surf.surfapi.core.api.messages.adventure.buildText -import dev.slne.surf.surfapi.core.api.messages.adventure.playSound -import dev.slne.surf.surfapi.core.api.messages.adventure.sendText -import org.bukkit.Sound -import org.bukkit.event.EventHandler -import org.bukkit.event.Listener - -object LicenseChangedHandler : Listener { - - @EventHandler - fun onPlayerLicenseAdded(event: RpPlayerLicenseAddedEvent) { - val license = event.license - val bukkitPlayer = event.player.bukkitPlayer ?: return - - plugin.launch(plugin.entityDispatcher(bukkitPlayer)) { - bukkitPlayer.sendText { - appendPrefix() - - info("Du hast eine ") - append(license.license.displayName) - info(" Lizenz erhalten.") - } - - bukkitPlayer.playSound(true) { - type(Sound.ENTITY_PLAYER_LEVELUP) - volume(.75f) - source(net.kyori.adventure.sound.Sound.Source.NEUTRAL) - } - } - } - - @EventHandler - fun onPlayerLicenseRemoved(event: RpPlayerLicenseRemovedEvent) { - val license = event.license - val bukkitPlayer = event.player.bukkitPlayer ?: return - val reason = buildText { - appendPrefix() - - event.reason.apply { message(license) } - } - - plugin.launch(plugin.entityDispatcher(bukkitPlayer)) { - bukkitPlayer.sendMessage(reason) - - bukkitPlayer.playSound(true) { - type(Sound.ENTITY_VILLAGER_HURT) - volume(.75f) - source(net.kyori.adventure.sound.Sound.Source.NEUTRAL) - } - } - } - -} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/utils/LicensePermissionRegistry.kt b/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/utils/LicensePermissionRegistry.kt deleted file mode 100644 index 24fa7b4..0000000 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/utils/LicensePermissionRegistry.kt +++ /dev/null @@ -1,14 +0,0 @@ -package dev.slne.surf.roleplay.core.player.license.utils - -import dev.slne.surf.surfapi.bukkit.api.permission.PermissionRegistry -import net.kyori.adventure.key.Key - -object LicensePermissionRegistry : PermissionRegistry() { - - private const val PREFIX = "surf.roleplay.license" - - fun createLicensePermission(key: Key) = create( - "${PREFIX}.license.${key.asString().replace(":", "-").replace("_", "-")}" - ) - -} \ No newline at end of file diff --git a/surf-roleplay-core/surf-roleplay-core-common/build.gradle.kts b/surf-roleplay-core/surf-roleplay-core-common/build.gradle.kts new file mode 100644 index 0000000..7516627 --- /dev/null +++ b/surf-roleplay-core/surf-roleplay-core-common/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + id("dev.slne.surf.surfapi.gradle.core") +} + +surfCoreApi { + withCloudCommon() +} \ No newline at end of file diff --git a/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/RoleplayApplication.kt b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/RoleplayApplication.kt new file mode 100644 index 0000000..ae00658 --- /dev/null +++ b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/RoleplayApplication.kt @@ -0,0 +1,11 @@ +package dev.slne.surf.roleplay + +import dev.slne.surf.cloud.api.common.SurfCloudApplication +import org.springframework.context.ApplicationContext + +@SurfCloudApplication +class RoleplayApplication { + companion object { + lateinit var context: ApplicationContext + } +} \ No newline at end of file diff --git a/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/RpInstance.kt b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/RpInstance.kt new file mode 100644 index 0000000..ac8691d --- /dev/null +++ b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/RpInstance.kt @@ -0,0 +1,24 @@ +package dev.slne.surf.roleplay.core.common + +import dev.slne.surf.cloud.api.common.util.forEachAnnotationOrdered +import dev.slne.surf.cloud.api.common.util.forEachAnnotationOrderedReversed +import org.springframework.beans.factory.ObjectProvider +import org.springframework.stereotype.Component +import javax.annotation.OverridingMethodsMustInvokeSuper + +@Component +class RpInstance(private val lifecycles: ObjectProvider) { + + suspend fun onLoad() { + lifecycles.forEachAnnotationOrdered { it.onLoad() } + } + + suspend fun onEnable() { + lifecycles.forEachAnnotationOrdered { it.onEnable() } + } + + suspend fun onDisable() { + lifecycles.forEachAnnotationOrderedReversed { it.onDisable() } + } + +} \ No newline at end of file diff --git a/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/RpLifecycle.kt b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/RpLifecycle.kt new file mode 100644 index 0000000..a186bdd --- /dev/null +++ b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/RpLifecycle.kt @@ -0,0 +1,10 @@ +package dev.slne.surf.roleplay.core.common + +import org.springframework.stereotype.Component + +@Component +interface RpLifecycle { + suspend fun onLoad() = Unit + suspend fun onEnable() = Unit + suspend fun onDisable() = Unit +} \ No newline at end of file diff --git a/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/network/packets/IdentityResponsePacket.kt b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/network/packets/IdentityResponsePacket.kt new file mode 100644 index 0000000..6070ad6 --- /dev/null +++ b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/network/packets/IdentityResponsePacket.kt @@ -0,0 +1,11 @@ +package dev.slne.surf.roleplay.core.common.network.packets + +import dev.slne.surf.cloud.api.common.meta.SurfNettyPacket +import dev.slne.surf.cloud.api.common.netty.network.protocol.PacketFlow +import dev.slne.surf.cloud.api.common.netty.packet.ResponseNettyPacket +import dev.slne.surf.roleplay.core.common.player.identity.NetworkIdentity +import kotlinx.serialization.Serializable + +@SurfNettyPacket("roleplay:response:identity", PacketFlow.BIDIRECTIONAL) +@Serializable +class IdentityResponsePacket(val identity: NetworkIdentity) : ResponseNettyPacket() \ No newline at end of file diff --git a/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/network/packets/ServerboundCreateLicensePacket.kt b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/network/packets/ServerboundCreateLicensePacket.kt new file mode 100644 index 0000000..ac84f15 --- /dev/null +++ b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/network/packets/ServerboundCreateLicensePacket.kt @@ -0,0 +1,11 @@ +package dev.slne.surf.roleplay.core.common.network.packets + +import dev.slne.surf.cloud.api.common.meta.SurfNettyPacket +import dev.slne.surf.cloud.api.common.netty.network.protocol.PacketFlow +import dev.slne.surf.cloud.api.common.netty.network.protocol.boolean.BooleanResponsePacket +import dev.slne.surf.roleplay.core.common.player.license.NetworkIdentityLicense +import kotlinx.serialization.Serializable + +@SurfNettyPacket("roleplay:serverbound:create-license", PacketFlow.SERVERBOUND) +@Serializable +class ServerboundCreateLicensePacket(val license: NetworkIdentityLicense) : BooleanResponsePacket() \ No newline at end of file diff --git a/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/network/packets/ServerboundCreateOrUpdateIdentityPacket.kt b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/network/packets/ServerboundCreateOrUpdateIdentityPacket.kt new file mode 100644 index 0000000..3e46e8c --- /dev/null +++ b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/network/packets/ServerboundCreateOrUpdateIdentityPacket.kt @@ -0,0 +1,12 @@ +package dev.slne.surf.roleplay.core.common.network.packets + +import dev.slne.surf.cloud.api.common.meta.SurfNettyPacket +import dev.slne.surf.cloud.api.common.netty.network.protocol.PacketFlow +import dev.slne.surf.cloud.api.common.netty.packet.RespondingNettyPacket +import dev.slne.surf.roleplay.core.common.player.identity.NetworkIdentity +import kotlinx.serialization.Serializable + +@SurfNettyPacket("roleplay:serverbound:create-or-update-identity", PacketFlow.SERVERBOUND) +@Serializable +class ServerboundCreateOrUpdateIdentityPacket(val identity: NetworkIdentity) : + RespondingNettyPacket() \ No newline at end of file diff --git a/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/network/packets/ServerboundDeleteLicensePacket.kt b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/network/packets/ServerboundDeleteLicensePacket.kt new file mode 100644 index 0000000..bcff4f0 --- /dev/null +++ b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/network/packets/ServerboundDeleteLicensePacket.kt @@ -0,0 +1,18 @@ +package dev.slne.surf.roleplay.core.common.network.packets + +import dev.slne.surf.cloud.api.common.meta.SurfNettyPacket +import dev.slne.surf.cloud.api.common.netty.network.protocol.PacketFlow +import dev.slne.surf.cloud.api.common.netty.network.protocol.boolean.BooleanResponsePacket +import dev.slne.surf.roleplay.core.common.player.identity.RpIdentityType +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import net.kyori.adventure.key.Key +import java.util.* + +@SurfNettyPacket("roleplay:serverbound:delete-license", PacketFlow.BIDIRECTIONAL) +@Serializable +class ServerboundDeleteLicensePacket( + val uuid: @Contextual UUID, + val identityType: RpIdentityType, + val licenseKey: @Contextual Key +) : BooleanResponsePacket() \ No newline at end of file diff --git a/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/network/packets/ServerboundFetchIdentitiesByUuidPacket.kt b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/network/packets/ServerboundFetchIdentitiesByUuidPacket.kt new file mode 100644 index 0000000..538348a --- /dev/null +++ b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/network/packets/ServerboundFetchIdentitiesByUuidPacket.kt @@ -0,0 +1,20 @@ +package dev.slne.surf.roleplay.core.common.network.packets + +import dev.slne.surf.cloud.api.common.meta.SurfNettyPacket +import dev.slne.surf.cloud.api.common.netty.network.protocol.PacketFlow +import dev.slne.surf.cloud.api.common.netty.packet.RespondingNettyPacket +import dev.slne.surf.cloud.api.common.netty.packet.ResponseNettyPacket +import dev.slne.surf.roleplay.core.common.player.identity.NetworkIdentity +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import java.util.* + +@SurfNettyPacket("roleplay:serverbound:fetch-identies-by-uuid", PacketFlow.SERVERBOUND) +@Serializable +class ServerboundFetchIdentitiesByUuidPacket(val uuid: @Contextual UUID) : + RespondingNettyPacket() + +@SurfNettyPacket("roleplay:response:fetch-identies-by-uuid", PacketFlow.BIDIRECTIONAL) +@Serializable +class FetchIdentitiesByUuidPacketResponse(val identies: List) : + ResponseNettyPacket() \ No newline at end of file diff --git a/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/RpPlayer.kt b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/RpPlayer.kt new file mode 100644 index 0000000..bf8c037 --- /dev/null +++ b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/RpPlayer.kt @@ -0,0 +1,78 @@ +package dev.slne.surf.roleplay.core.common.player + +import dev.slne.surf.cloud.api.common.player.OfflineCloudPlayer +import dev.slne.surf.cloud.api.common.player.toOfflineCloudPlayer +import dev.slne.surf.roleplay.RoleplayApplication +import dev.slne.surf.roleplay.core.common.transaction.HasRpTransactions +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.buildClassSerialDescriptor +import kotlinx.serialization.descriptors.element +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import net.kyori.adventure.text.ComponentLike +import org.springframework.beans.factory.getBean +import java.time.ZonedDateTime +import java.util.* + +@Serializable(with = RpPlayerSerializer::class) +abstract class RpPlayer( + val uuid: UUID, + var createdAt: ZonedDateTime = ZonedDateTime.now(), + var updatedAt: ZonedDateTime = ZonedDateTime.now() +) : HasRpTransactions, ComponentLike { + val cloudPlayer: OfflineCloudPlayer + get() = uuid.toOfflineCloudPlayer() + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is RpPlayer) return false + + if (uuid != other.uuid) return false + + return true + } + + override fun hashCode(): Int { + return uuid.hashCode() + } + + + companion object { + operator fun get(cloudPlayer: OfflineCloudPlayer) = get(cloudPlayer.uuid) + operator fun get(uuid: UUID) = + RoleplayApplication.context.getBean() + .getPlayerByUuid(uuid) + } + +} + +/** + * Gets the [RpPlayer] associated with this [OfflineCloudPlayer]. + * + * @return The [RpPlayer] instance for this player. + */ +fun OfflineCloudPlayer.rpPlayer() = RpPlayer[this] + +object RpPlayerSerializer : KSerializer { + override val descriptor = buildClassSerialDescriptor("RpPlayer") { + element("mostSigBits") + element("leastSigBits") + } + + override fun serialize( + encoder: Encoder, + value: RpPlayer + ) { + val uuid = value.uuid + encoder.encodeLong(uuid.mostSignificantBits) + encoder.encodeLong(uuid.leastSignificantBits) + } + + override fun deserialize(decoder: Decoder): RpPlayer { + val mostSigBits = decoder.decodeLong() + val leastSigBits = decoder.decodeLong() + val uuid = UUID(mostSigBits, leastSigBits) + return RpPlayer[uuid] + } +} \ No newline at end of file diff --git a/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/RpPlayerManager.kt b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/RpPlayerManager.kt new file mode 100644 index 0000000..a87d9c0 --- /dev/null +++ b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/RpPlayerManager.kt @@ -0,0 +1,34 @@ +package dev.slne.surf.roleplay.core.common.player + +import com.github.benmanes.caffeine.cache.Caffeine +import com.sksamuel.aedile.core.expireAfterAccess +import dev.slne.surf.surfapi.core.api.util.toObjectList +import it.unimi.dsi.fastutil.objects.ObjectList +import org.springframework.scheduling.annotation.Scheduled +import org.springframework.stereotype.Component +import java.util.* +import java.util.concurrent.TimeUnit +import kotlin.time.Duration.Companion.minutes + +@Component +abstract class RpPlayerManager { + + private val cache = Caffeine.newBuilder() + .maximumSize(10_000) + .expireAfterAccess(30.minutes) + .build { createPlayer(it) } + + val players: ObjectList get() = cache.asMap().values.toObjectList() + + abstract fun createPlayer(uuid: UUID): RpPlayer + abstract fun onlineUuids(): List + + fun getPlayerByUuid(uuid: UUID) = cache.get(uuid) + + @Scheduled(fixedDelay = 15, timeUnit = TimeUnit.MINUTES) + fun cacheRefresh() { + onlineUuids().forEach { uuid -> + cache.getIfPresent(uuid) + } + } +} \ No newline at end of file diff --git a/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/identity/NetworkIdentity.kt b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/identity/NetworkIdentity.kt new file mode 100644 index 0000000..5c79c9c --- /dev/null +++ b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/identity/NetworkIdentity.kt @@ -0,0 +1,50 @@ +package dev.slne.surf.roleplay.core.common.player.identity + +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import java.time.LocalDate +import java.time.ZonedDateTime +import java.util.* + +@Serializable +sealed class NetworkIdentity(val type: RpIdentityType) { + abstract val uuid: @Contextual UUID + abstract val firstName: String + abstract val lastName: String + abstract val dateOfBirth: @Contextual LocalDate + abstract val createdAt: @Contextual ZonedDateTime + abstract val updatedAt: @Contextual ZonedDateTime + + @Serializable + data class Civilian( + override val uuid: @Contextual UUID, + override val firstName: String, + override val lastName: String, + override val dateOfBirth: @Contextual LocalDate, + override val createdAt: @Contextual ZonedDateTime = ZonedDateTime.now(), + override val updatedAt: @Contextual ZonedDateTime = ZonedDateTime.now() + ) : NetworkIdentity(RpIdentityType.CIVILIAN) + + @Serializable + data class Police( + override val uuid: @Contextual UUID, + override val firstName: String, + override val lastName: String, + override val dateOfBirth: @Contextual LocalDate, + val badgeNumber: String, + val rank: String, + override val createdAt: @Contextual ZonedDateTime = ZonedDateTime.now(), + override val updatedAt: @Contextual ZonedDateTime = ZonedDateTime.now() + ) : NetworkIdentity(RpIdentityType.POLICE) + + @Serializable + data class RescueService( + override val uuid: @Contextual UUID, + override val firstName: String, + override val lastName: String, + override val dateOfBirth: @Contextual LocalDate, + val rank: String, + override val createdAt: @Contextual ZonedDateTime = ZonedDateTime.now(), + override val updatedAt: @Contextual ZonedDateTime = ZonedDateTime.now() + ) : NetworkIdentity(RpIdentityType.RESCUE_SERVICE) +} \ No newline at end of file diff --git a/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/identity/RpIdentityType.kt b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/identity/RpIdentityType.kt new file mode 100644 index 0000000..197793e --- /dev/null +++ b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/identity/RpIdentityType.kt @@ -0,0 +1,33 @@ +package dev.slne.surf.roleplay.core.common.player.identity + +import dev.slne.surf.surfapi.core.api.messages.adventure.buildText +import net.kyori.adventure.text.ComponentLike + +enum class RpIdentityType : ComponentLike { + /** + * Represents a player who is a member of the civilian population. + */ + CIVILIAN { + override fun asComponent() = buildText { + text("Zivilist") + } + }, + + /** + * Represents a player who is a member of the emergency medical service. + */ + POLICE { + override fun asComponent() = buildText { + text("Polizist") + } + }, + + /** + * Represents a player who is a member of the rescue service. + */ + RESCUE_SERVICE { + override fun asComponent() = buildText { + text("SAR") + } + } +} \ No newline at end of file diff --git a/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/identity/create/RpIdentityCreationData.kt b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/identity/create/RpIdentityCreationData.kt new file mode 100644 index 0000000..a7cf754 --- /dev/null +++ b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/identity/create/RpIdentityCreationData.kt @@ -0,0 +1,37 @@ +package dev.slne.surf.roleplay.core.common.player.identity.create + +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import java.time.LocalDate + +@Serializable +sealed class RpIdentityCreationData { + abstract val firstName: String + abstract val lastName: String + abstract val dateOfBirth: LocalDate + + @Serializable + data class Civilian( + override val firstName: String, + override val lastName: String, + override val dateOfBirth: @Contextual LocalDate + ) : RpIdentityCreationData() + + @Serializable + data class Police( + override val firstName: String, + override val lastName: String, + override val dateOfBirth: @Contextual LocalDate, + val badgeNumber: String, + val rank: String + ) : RpIdentityCreationData() + + @Serializable + data class RescueService( + override val firstName: String, + override val lastName: String, + override val dateOfBirth: @Contextual LocalDate, + val rank: String + ) : RpIdentityCreationData() + +} \ No newline at end of file diff --git a/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/identity/update/RpIdentityUpdateData.kt b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/identity/update/RpIdentityUpdateData.kt new file mode 100644 index 0000000..4ce5445 --- /dev/null +++ b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/identity/update/RpIdentityUpdateData.kt @@ -0,0 +1,38 @@ +package dev.slne.surf.roleplay.core.common.player.identity.update + +import dev.slne.surf.roleplay.core.common.player.identity.RpIdentityType +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import java.time.LocalDate + +@Serializable +sealed class RpIdentityUpdateData(val identityType: RpIdentityType) { + abstract val firstName: String? + abstract val lastName: String? + abstract val dateOfBirth: LocalDate? + + @Serializable + data class Civilian( + override val firstName: String? = null, + override val lastName: String? = null, + override val dateOfBirth: @Contextual LocalDate? = null + ) : RpIdentityUpdateData(RpIdentityType.CIVILIAN) + + @Serializable + data class Police( + override val firstName: String? = null, + override val lastName: String? = null, + override val dateOfBirth: @Contextual LocalDate? = null, + val badgeNumber: String? = null, + val rank: String? = null + ) : RpIdentityUpdateData(RpIdentityType.POLICE) + + @Serializable + data class RescueService( + override val firstName: String? = null, + override val lastName: String? = null, + override val dateOfBirth: @Contextual LocalDate? = null, + val rank: String? = null + ) : RpIdentityUpdateData(RpIdentityType.RESCUE_SERVICE) + +} \ No newline at end of file diff --git a/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/license/NetworkIdentityLicense.kt b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/license/NetworkIdentityLicense.kt new file mode 100644 index 0000000..b75c199 --- /dev/null +++ b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/player/license/NetworkIdentityLicense.kt @@ -0,0 +1,18 @@ +package dev.slne.surf.roleplay.core.common.player.license + +import dev.slne.surf.roleplay.core.common.player.identity.RpIdentityType +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import net.kyori.adventure.key.Key +import java.time.ZonedDateTime +import java.util.* + +@Serializable +data class NetworkIdentityLicense( + val owner: @Contextual UUID, + val identityType: RpIdentityType, + val licenseKey: @Contextual Key, + val expiresAt: @Contextual ZonedDateTime?, + val createdAt: @Contextual ZonedDateTime = ZonedDateTime.now() +) { +} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/transaction/HasTransactions.kt b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/transaction/HasRpTransactions.kt similarity index 97% rename from surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/transaction/HasTransactions.kt rename to surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/transaction/HasRpTransactions.kt index 07173ec..12a3017 100644 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/transaction/HasTransactions.kt +++ b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/transaction/HasRpTransactions.kt @@ -1,9 +1,9 @@ -package dev.slne.surf.roleplay.api.transaction +package dev.slne.surf.roleplay.core.common.transaction -import dev.slne.surf.roleplay.api.player.utils.BalanceType +import dev.slne.surf.roleplay.core.common.transaction.utils.BalanceType import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet -interface HasTransactions { +interface HasRpTransactions { /** * Returns the player's balance for the specified [BalanceType]. diff --git a/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/transaction/RpTransaction.kt b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/transaction/RpTransaction.kt new file mode 100644 index 0000000..19243d1 --- /dev/null +++ b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/transaction/RpTransaction.kt @@ -0,0 +1,19 @@ +package dev.slne.surf.roleplay.core.common.transaction + +import dev.slne.surf.roleplay.core.common.player.RpPlayer +import dev.slne.surf.roleplay.core.common.transaction.utils.BalanceType +import kotlinx.serialization.Contextual +import kotlinx.serialization.Serializable +import java.time.ZonedDateTime +import java.util.* + +@Serializable +data class RpTransaction( + val uniqueId: @Contextual UUID, + val sender: RpPlayer?, + val receiver: RpPlayer?, + val amount: Int, + val balanceType: BalanceType, + val description: String? = null, + val createdAt: @Contextual ZonedDateTime = ZonedDateTime.now() +) \ No newline at end of file diff --git a/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/transaction/utils/BalanceType.kt b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/transaction/utils/BalanceType.kt new file mode 100644 index 0000000..b5dce35 --- /dev/null +++ b/surf-roleplay-core/surf-roleplay-core-common/src/main/kotlin/dev/slne/surf/roleplay/core/common/transaction/utils/BalanceType.kt @@ -0,0 +1,31 @@ +package dev.slne.surf.roleplay.core.common.transaction.utils + +import dev.slne.surf.roleplay.core.common.player.identity.RpIdentityType + +enum class BalanceType(private val currencyName: (RpIdentityType) -> String) { + CASH({ + when (it) { + RpIdentityType.CIVILIAN -> "civilian_cash" + RpIdentityType.POLICE -> "police_cash" + RpIdentityType.RESCUE_SERVICE -> "rescue_service_cash" + } + }), + + BANK({ + when (it) { + RpIdentityType.CIVILIAN -> "civilian_bank" + RpIdentityType.POLICE -> "police_bank" + RpIdentityType.RESCUE_SERVICE -> "rescue_service_bank" + } + }), + + CRYPTO({ + when (it) { + RpIdentityType.CIVILIAN -> "civilian_crypto" + RpIdentityType.POLICE -> "police_crypto" + RpIdentityType.RESCUE_SERVICE -> "rescue_service_crypto" + } + }); + + fun getCurrencyName(type: RpIdentityType) = "roleplay_${currencyName(type)}" +} \ No newline at end of file diff --git a/surf-roleplay-mechanic/build.gradle.kts b/surf-roleplay-mechanic/build.gradle.kts deleted file mode 100644 index 8710723..0000000 --- a/surf-roleplay-mechanic/build.gradle.kts +++ /dev/null @@ -1,7 +0,0 @@ -plugins { - id("dev.slne.surf.surfapi.gradle.paper-raw") -} - -dependencies { - compileOnly(project(":surf-roleplay-core")) -} \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/MechanicImpl.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/MechanicImpl.kt deleted file mode 100644 index bc51da0..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/MechanicImpl.kt +++ /dev/null @@ -1,23 +0,0 @@ -package dev.slne.surf.roleplay.mechanic - -import com.github.retrooper.packetevents.event.PacketListener -import com.github.retrooper.packetevents.event.PacketListenerPriority -import dev.slne.surf.roleplay.api.coroutine.RpJob -import dev.slne.surf.roleplay.api.mechanic.Mechanic -import dev.slne.surf.surfapi.core.api.util.objectSetOf -import it.unimi.dsi.fastutil.objects.ObjectSet -import org.bukkit.event.Listener -import org.jetbrains.exposed.sql.Table - -abstract class MechanicImpl( - override val name: String, - override val handlers: ObjectSet = objectSetOf(), - override val rpJobs: ObjectSet = objectSetOf(), - override val packetListeners: ObjectSet> = objectSetOf() -) : Mechanic { - open fun getDatabaseTables(): ObjectSet
= objectSetOf() - - override suspend fun onLoad() {} - override suspend fun onEnable() {} - override suspend fun onDisable() {} -} \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/MechanicRegistryImpl.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/MechanicRegistryImpl.kt deleted file mode 100644 index f515ba6..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/MechanicRegistryImpl.kt +++ /dev/null @@ -1,70 +0,0 @@ -package dev.slne.surf.roleplay.mechanic - -import com.github.shynixn.mccoroutine.folia.SuspendingJavaPlugin -import com.google.auto.service.AutoService -import dev.slne.surf.roleplay.api.mechanic.Mechanic -import dev.slne.surf.roleplay.api.mechanic.MechanicRegistry -import dev.slne.surf.roleplay.core.RpDatabase -import dev.slne.surf.roleplay.mechanic.mechanics.idcard.IdCardMechanicImpl -import dev.slne.surf.roleplay.mechanic.mechanics.rentable.RentableMechanicImpl -import dev.slne.surf.surfapi.bukkit.api.event.register -import dev.slne.surf.surfapi.core.api.util.mutableObjectSetOf -import net.kyori.adventure.util.Services - -val plugin get() = mechanicRegistryImpl.plugin - -@AutoService(MechanicRegistry::class) -class MechanicRegistryImpl : MechanicRegistry, Services.Fallback { - - lateinit var plugin: SuspendingJavaPlugin - private set - - private val mechanics = mutableObjectSetOf() - - @Suppress("UNCHECKED_CAST") - override fun getMechanic(clazz: Class) = - mechanics.firstOrNull { clazz.isAssignableFrom(it.javaClass) } as? T - ?: throw IllegalArgumentException("No mechanic of class ${clazz.name} is registered.") - - fun registerMechanics(plugin: SuspendingJavaPlugin) { - this.plugin = plugin - - mechanics.add(IdCardMechanicImpl) - mechanics.add(RentableMechanicImpl) - } - - fun registerBukkitHandlers() { - mechanics.forEach { mechanic -> mechanic.handlers.forEach { it.register() } } - } - - fun registerDatabaseTables(rpDatabase: RpDatabase) { - mechanics.map { it as MechanicImpl }.flatMap { it.getDatabaseTables() } - .forEach { rpDatabase.registerMechanicTable(it) } - } - - fun startAllRpJobs() { - mechanics.forEach { it.rpJobs.forEach { job -> job.start() } } - } - - suspend fun stopAllRpJobs() { - mechanics.forEach { it.rpJobs.forEach { job -> job.stop() } } - } - - suspend fun loadMechanics() { - mechanics.forEach { it.onLoad() } - } - - suspend fun enableMechanics() { - mechanics.forEach { it.onEnable() } - - startAllRpJobs() - } - - suspend fun disableMechanics() { - stopAllRpJobs() - - mechanics.forEach { it.onDisable() } - } -} - -val mechanicRegistryImpl get() = MechanicRegistry.INSTANCE as MechanicRegistryImpl \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/idcard/IdCardMechanicImpl.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/idcard/IdCardMechanicImpl.kt deleted file mode 100644 index efa44fb..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/idcard/IdCardMechanicImpl.kt +++ /dev/null @@ -1,20 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.idcard - -import dev.slne.surf.roleplay.api.mechanic.idcard.IdCardMechanic -import dev.slne.surf.roleplay.mechanic.MechanicImpl -import dev.slne.surf.roleplay.mechanic.mechanics.idcard.listeners.IdCardHandler -import dev.slne.surf.surfapi.core.api.util.objectSetOf - -object IdCardMechanicImpl : MechanicImpl( - name = "IdCardMechanic", - handlers = objectSetOf( - IdCardHandler - ) -), IdCardMechanic { - - const val NPC_NAME = "ID-Card_npc" - - override suspend fun onEnable() { - IdCardNpc.spawnNpc() - } -} \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/RentCollectorJob.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/RentCollectorJob.kt deleted file mode 100644 index 5d8c4ce..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/RentCollectorJob.kt +++ /dev/null @@ -1,24 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.rentable - -import dev.slne.surf.roleplay.api.coroutine.RpJob -import java.time.ZonedDateTime -import kotlin.time.Duration.Companion.seconds - -object RentCollectorJob : RpJob("RentCollectorJob", 1.seconds) { - - override suspend fun tick() { - val now = ZonedDateTime.now() - - RentableMechanicImpl.rentables.forEach { rentable -> - if (rentable.owner == null) return@forEach - - val lastCollection = rentable.lastRentCollection - val delay = rentable.rentDuration - - if (lastCollection == null || now.isAfter(lastCollection.plusSeconds(delay.inWholeSeconds))) { - rentable.collectRent() - } - } - } - -} \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/RentableImpl.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/RentableImpl.kt deleted file mode 100644 index 0138665..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/RentableImpl.kt +++ /dev/null @@ -1,162 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.rentable - -import dev.slne.surf.roleplay.api.mechanic.Mechanic -import dev.slne.surf.roleplay.api.mechanic.rentable.Rentable -import dev.slne.surf.roleplay.api.mechanic.rentable.RentableMechanic -import dev.slne.surf.roleplay.api.mechanic.rentable.events.RentableMemberAddEvent -import dev.slne.surf.roleplay.api.mechanic.rentable.events.RentableMemberRemoveEvent -import dev.slne.surf.roleplay.api.mechanic.rentable.events.RentableOwnerChangeEvent -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.StorageContainer -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.door.DoorContainer -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.surfapi.core.api.messages.adventure.buildText -import dev.slne.surf.surfapi.core.api.util.freeze -import dev.slne.surf.surfapi.core.api.util.mutableObjectSetOf -import dev.slne.surf.surfapi.core.api.util.objectSetOf -import it.unimi.dsi.fastutil.objects.ObjectSet -import net.kyori.adventure.key.Key -import java.time.ZonedDateTime -import kotlin.time.Duration - -abstract class RentableImpl( - override val key: Key, - override val rent: Int, - override val rentDuration: Duration, - override val size: Double, - override val stories: Int, - storageContainers: ObjectSet = objectSetOf(), - doorContainers: ObjectSet = objectSetOf() -) : Rentable { - - private val _members = mutableObjectSetOf() - private val _storageContainers = mutableObjectSetOf() - private val _doorContainers = mutableObjectSetOf() - - override val storageContainers = _storageContainers.freeze() - override val doorContainers = _doorContainers.freeze() - - init { - _storageContainers.addAll(storageContainers) - _doorContainers.addAll(doorContainers) - } - - override var owner: RpPlayer? = null - override val members get() = _members.freeze() - override val isRented: Boolean get() = owner != null - override var lastRentCollection: ZonedDateTime? = null - - override suspend fun collectRent(): RentableMechanic.RentCollectResult { - val result = Mechanic.getMechanic().collectRent(this) - - if (result == RentableMechanic.RentCollectResult.SUCCESS) { - lastRentCollection = ZonedDateTime.now() - } - - return result - } - - override suspend fun setOwner( - player: RpPlayer?, - reason: RentableOwnerChangeEvent.OwnerChangeReason - ): RentableOwnerChangeEvent.OwnerSetResult { - val event = RentableOwnerChangeEvent(this, owner, player, reason) - - if (!event.callEvent()) { - return RentableOwnerChangeEvent.OwnerSetResult.Failure( - RentableOwnerChangeEvent.OwnerSetFailureReason.EventCancelled( - event.cancelReason ?: "Unbekannt" - ) - ) - } - - if (player == null) { - owner = null - lastRentCollection = null - _members.clear() - - return RentableOwnerChangeEvent.OwnerSetResult.Success - } - - if (player == owner) { - return RentableOwnerChangeEvent.OwnerSetResult.Failure( - RentableOwnerChangeEvent.OwnerSetFailureReason.AlreadyOwned - ) - } - - val rentableMechanic = Mechanic.getMechanic() - - val maxRentables = rentableMechanic.getMaxOwnableRentablesByPlayer(player) - val ownedRentables = rentableMechanic.getOwnedRentablesByPlayer(player) - - if (ownedRentables.size >= maxRentables) { - return RentableOwnerChangeEvent.OwnerSetResult.Failure( - RentableOwnerChangeEvent.OwnerSetFailureReason.AlreadyOwningTooManyRentables( - ownedRentables.size, - maxRentables - ) - ) - } - - val currentMoney = player.getBankBalance().toInt() - - if (currentMoney < rent) { - return RentableOwnerChangeEvent.OwnerSetResult.Failure( - RentableOwnerChangeEvent.OwnerSetFailureReason.NotEnoughMoney( - currentMoney = currentMoney, - requiredMoney = rent - ) - ) - } - - owner = player - val result = collectRent() - - if (result != RentableMechanic.RentCollectResult.SUCCESS) { - owner = null - - return RentableOwnerChangeEvent.OwnerSetResult.Failure( - RentableOwnerChangeEvent.OwnerSetFailureReason.RentCollectionFailed(result) - ) - } - - return RentableOwnerChangeEvent.OwnerSetResult.Success - } - - override fun addMember(player: RpPlayer): RentableMemberAddEvent.MemberAddResult { - if (isMember(player)) { - return RentableMemberAddEvent.MemberAddResult.Failure(RentableMemberAddEvent.MemberAddFailureReason.AlreadyMember) - } - - val event = RentableMemberAddEvent(this, player) - - if (!event.callEvent()) { - return RentableMemberAddEvent.MemberAddResult.Failure(RentableMemberAddEvent.MemberAddFailureReason.EventCancelled) - } - - _members.add(player) - - return RentableMemberAddEvent.MemberAddResult.Success - } - - override fun removeMember(player: RpPlayer): RentableMemberRemoveEvent.MemberRemoveResult { - if (!isMember(player)) { - return RentableMemberRemoveEvent.MemberRemoveResult.Failure(RentableMemberRemoveEvent.MemberRemoveFailureReason.NotMember) - } - - val event = RentableMemberRemoveEvent(this, player) - - if (!event.callEvent()) { - return RentableMemberRemoveEvent.MemberRemoveResult.Failure(RentableMemberRemoveEvent.MemberRemoveFailureReason.EventCancelled) - } - - _members.remove(player) - - return RentableMemberRemoveEvent.MemberRemoveResult.Success - } - - override fun isMember(player: RpPlayer) = _members.contains(player) || owner == player - - override fun asComponent() = buildText { - variableValue(key.asString()) - } -} \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/RentableMechanicImpl.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/RentableMechanicImpl.kt deleted file mode 100644 index d68cf71..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/RentableMechanicImpl.kt +++ /dev/null @@ -1,160 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.rentable - -import com.github.shynixn.mccoroutine.folia.launch -import dev.jorel.commandapi.arguments.ArgumentSuggestions -import dev.jorel.commandapi.kotlindsl.* -import dev.slne.surf.roleplay.api.mechanic.rentable.Rentable -import dev.slne.surf.roleplay.api.mechanic.rentable.RentableMechanic -import dev.slne.surf.roleplay.api.mechanic.rentable.events.RentableOwnerChangeEvent -import dev.slne.surf.roleplay.api.mechanic.rentable.events.RentableRentCollectEvent -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.rpPlayer -import dev.slne.surf.roleplay.mechanic.MechanicImpl -import dev.slne.surf.roleplay.mechanic.mechanics.rentable.listeners.RentCollectedListener -import dev.slne.surf.roleplay.mechanic.mechanics.rentable.listeners.RentableListener -import dev.slne.surf.roleplay.mechanic.mechanics.rentable.listeners.RentableOnlineListener -import dev.slne.surf.roleplay.mechanic.mechanics.rentable.rentables.HouseImpl -import dev.slne.surf.roleplay.mechanic.plugin -import dev.slne.surf.surfapi.core.api.messages.adventure.appendNewline -import dev.slne.surf.surfapi.core.api.messages.adventure.key -import dev.slne.surf.surfapi.core.api.messages.adventure.sendText -import dev.slne.surf.surfapi.core.api.util.freeze -import dev.slne.surf.surfapi.core.api.util.mutableObjectSetOf -import dev.slne.surf.surfapi.core.api.util.objectSetOf -import dev.slne.surf.surfapi.core.api.util.toObjectSet -import net.kyori.adventure.key.Key -import org.bukkit.NamespacedKey -import kotlin.time.Duration.Companion.seconds - -object RentableMechanicImpl : MechanicImpl( - name = "RentableMechanic", - handlers = objectSetOf( - RentableOnlineListener, - RentCollectedListener, - RentableListener - ), - rpJobs = objectSetOf( - RentCollectorJob - ) -), RentableMechanic { - - private val _rentables = mutableObjectSetOf() - override val rentables get() = _rentables.freeze() - - override fun addRentable(rentable: Rentable) = _rentables.add(rentable) - - override suspend fun onEnable() { - val rentable = HouseImpl( - key = key("roleplay_house", "house_1"), - rent = 1000, - rentDuration = 10.seconds, - size = 100.0, - stories = 3, - storageContainers = objectSetOf(), - doors = objectSetOf() - ) - - addRentable(rentable) - - commandAPICommand("rentable") { - subcommand("rent") { - namespacedKeyArgument("rentableKey") { - replaceSuggestions(ArgumentSuggestions.stringCollection { info -> - rentables.map { it.key.asString() } - }) - } - - playerExecutor { player, args -> - val rentableKey: NamespacedKey by args - val rentable = getByKey(rentableKey) ?: run { - player.sendText { - appendPrefix() - - error("Es konnte kein Mietobjekt mit dem Key ") - variableValue(rentableKey.asString()) - error(" gefunden werden.") - - } - - return@playerExecutor - } - - if (rentable.isRented) { - player.sendText { - appendPrefix() - - error("Das Mietobjekt ") - variableValue(rentableKey.asString()) - error(" ist bereits vermietet.") - - return@playerExecutor - } - } - - plugin.launch { - val rpPlayer = player.rpPlayer() - - val result = rentable.setOwner( - rpPlayer, - RentableOwnerChangeEvent.OwnerChangeReason.RentableBought - ) - - if (result is RentableOwnerChangeEvent.OwnerSetResult.Success) { - player.sendText { - appendPrefix() - - success("Du hast das Mietobjekt ") - variableValue(rentableKey.asString()) - success(" erfolgreich gemietet.") - } - } else if (result is RentableOwnerChangeEvent.OwnerSetResult.Failure) { - player.sendText { - appendPrefix() - - error("Das Mietobjekt ") - variableValue(rentableKey.asString()) - error(" konnte nicht gemietet werden: ") - appendNewline(2) - - result.reason.message(this) - } - } - } - } - } - } - } - - override suspend fun collectRent(rentable: Rentable): RentableMechanic.RentCollectResult { - val currentOwner = rentable.owner ?: return RentableMechanic.RentCollectResult.NOT_RENTED - val currentBankBalance = currentOwner.getBankBalance() - - val event = RentableRentCollectEvent( - rentable = rentable, - amount = rentable.rent - ) - - if (!event.callEvent()) { - return RentableMechanic.RentCollectResult.EVENT_CANCELLED - } - - val rent = event.amount - - if (rent > currentBankBalance) { - return RentableMechanic.RentCollectResult.NOT_ENOUGH_MONEY - } - - currentOwner.removeBankBalance(rent) - - return RentableMechanic.RentCollectResult.SUCCESS - } - - override fun getOwnedRentablesByPlayer(player: RpPlayer) = - _rentables.filter { it.owner == player }.toObjectSet() - - override fun getMaxOwnableRentablesByPlayer(player: RpPlayer) = 1 - - override fun getByKey(key: Key) = _rentables.find { it.key == key } - ?: _rentables.find { it.key.asString() == key.asString() } - ?: _rentables.find { it.key.namespace() == key.namespace() && it.key.value() == key.value() } -} \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/listeners/RentCollectedListener.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/listeners/RentCollectedListener.kt deleted file mode 100644 index e57c0d7..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/listeners/RentCollectedListener.kt +++ /dev/null @@ -1,39 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.rentable.listeners - -import com.github.shynixn.mccoroutine.folia.entityDispatcher -import com.github.shynixn.mccoroutine.folia.launch -import dev.slne.surf.roleplay.api.mechanic.rentable.events.RentableRentCollectEvent -import dev.slne.surf.roleplay.mechanic.plugin -import dev.slne.surf.surfapi.core.api.messages.adventure.playSound -import dev.slne.surf.surfapi.core.api.messages.adventure.sendText -import org.bukkit.Sound -import org.bukkit.event.EventHandler -import org.bukkit.event.Listener - -object RentCollectedListener : Listener { - - @EventHandler - fun onRentableRentCollect(event: RentableRentCollectEvent) { - val rentable = event.rentable - val player = rentable.owner?.bukkitPlayer ?: return - - plugin.launch(plugin.entityDispatcher(player)) { - player.sendText { - appendPrefix() - - info("Du hast die Miete in Höhe von ") - variableValue("${event.amount} €") - info(" für deine Immobilie ") - append(rentable) - info(" bezahlt.") - } - - player.playSound(true) { - type(Sound.BLOCK_ANVIL_LAND) - volume(.5f) - source(net.kyori.adventure.sound.Sound.Source.BLOCK) - } - } - } - -} \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/listeners/RentableListener.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/listeners/RentableListener.kt deleted file mode 100644 index 784e279..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/listeners/RentableListener.kt +++ /dev/null @@ -1,175 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.rentable.listeners - -import com.github.shynixn.mccoroutine.folia.entityDispatcher -import com.github.shynixn.mccoroutine.folia.launch -import dev.slne.surf.roleplay.api.mechanic.rentable.events.RentableMemberAddEvent -import dev.slne.surf.roleplay.api.mechanic.rentable.events.RentableMemberRemoveEvent -import dev.slne.surf.roleplay.api.mechanic.rentable.events.RentableOwnerChangeEvent -import dev.slne.surf.roleplay.mechanic.plugin -import dev.slne.surf.surfapi.core.api.messages.adventure.playSound -import dev.slne.surf.surfapi.core.api.messages.adventure.sendText -import kotlinx.coroutines.withContext -import org.bukkit.Sound -import org.bukkit.event.EventHandler -import org.bukkit.event.Listener - -object RentableListener : Listener { - - @EventHandler - fun onRentableMemberAdd(event: RentableMemberAddEvent) { - val rentable = event.rentable - val members = event.rentable.members - - plugin.launch { - val memberPlayer = event.member.bukkitPlayer - - if (memberPlayer != null) { - withContext(plugin.entityDispatcher(memberPlayer)) { - memberPlayer.sendText { - appendPrefix() - - info("Du wurdest zu der Immobilie ") - append(rentable) - info(" hinzugefügt.") - } - - memberPlayer.playSound(true) { - type(Sound.ENTITY_VILLAGER_CELEBRATE) - volume(.5f) - source(net.kyori.adventure.sound.Sound.Source.NEUTRAL) - } - } - } - - members.filterNot { it == event.member }.forEach { member -> - val memberPlayer = member.bukkitPlayer ?: return@forEach - - withContext(plugin.entityDispatcher(memberPlayer)) { - memberPlayer.sendText { - appendPrefix() - - append(event.member) - info(" wurde zu der Immobilie ") - append(rentable) - info(" hinzugefügt.") - } - - memberPlayer.playSound(true) { - type(Sound.ENTITY_VILLAGER_CELEBRATE) - volume(.5f) - source(net.kyori.adventure.sound.Sound.Source.NEUTRAL) - } - } - } - } - } - - @EventHandler - fun onRentableMemberRemove(event: RentableMemberRemoveEvent) { - val rentable = event.rentable - val members = event.rentable.members - - plugin.launch { - val memberPlayer = event.member.bukkitPlayer - if (memberPlayer != null) { - withContext(plugin.entityDispatcher(memberPlayer)) { - memberPlayer.sendText { - appendPrefix() - - info("Du wurdest von der Immobilie ") - append(rentable) - info(" entfernt.") - } - - memberPlayer.playSound(true) { - type(Sound.ENTITY_VILLAGER_NO) - volume(.5f) - source(net.kyori.adventure.sound.Sound.Source.NEUTRAL) - } - } - } - - members.filterNot { it == event.member }.forEach { member -> - val memberPlayer = member.bukkitPlayer ?: return@forEach - - withContext(plugin.entityDispatcher(memberPlayer)) { - memberPlayer.sendText { - appendPrefix() - - append(event.member) - info(" wurde von der Immobilie ") - append(rentable) - info(" entfernt.") - } - - memberPlayer.playSound(true) { - type(Sound.ENTITY_VILLAGER_NO) - volume(.5f) - source(net.kyori.adventure.sound.Sound.Source.NEUTRAL) - } - } - } - } - } - - @EventHandler - fun onRentableOwnerChange(event: RentableOwnerChangeEvent) { - val reason = event.reason - val rentable = event.rentable - - val newOwner = event.newOwner - val oldOwner = event.oldOwner - - val newOwnerPlayer = newOwner?.bukkitPlayer - val oldOwnerPlayer = oldOwner?.bukkitPlayer - - plugin.launch { - if (newOwner != null && newOwnerPlayer != null) { - withContext(plugin.entityDispatcher(newOwnerPlayer)) { - newOwnerPlayer.sendText { - appendPrefix() - - success("Du bist jetzt der Eigentümer der Immobilie ") - append(rentable) - success(".") - - if (reason == RentableOwnerChangeEvent.OwnerChangeReason.RentableBought) { - info(" Du hast die Immobilie gemietet.") - } else if (reason is RentableOwnerChangeEvent.OwnerChangeReason.OwnerSetNewOwner) { - info(" Du wurdest als neuer Eigentümer gesetzt.") - } - } - - newOwnerPlayer.playSound(true) { - type(Sound.ENTITY_PLAYER_LEVELUP) - volume(.5f) - source(net.kyori.adventure.sound.Sound.Source.NEUTRAL) - } - } - } - - if (oldOwner != null && oldOwnerPlayer != null) { - withContext(plugin.entityDispatcher(oldOwnerPlayer)) { - oldOwnerPlayer.sendText { - appendPrefix() - - info("Du bist nicht mehr der Eigentümer der Immobilie ") - append(rentable) - info(".") - - if (reason is RentableOwnerChangeEvent.OwnerChangeReason.OwnerSetNewOwner) { - error(" Du wurdest als Eigentümer entfernt.") - } - } - - oldOwnerPlayer.playSound(true) { - type(Sound.ENTITY_VILLAGER_NO) - volume(.5f) - source(net.kyori.adventure.sound.Sound.Source.NEUTRAL) - } - } - } - } - } - -} \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/listeners/RentableOnlineListener.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/listeners/RentableOnlineListener.kt deleted file mode 100644 index 549e55d..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/listeners/RentableOnlineListener.kt +++ /dev/null @@ -1,27 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.rentable.listeners - -import com.github.shynixn.mccoroutine.folia.launch -import dev.slne.surf.roleplay.api.mechanic.Mechanic -import dev.slne.surf.roleplay.api.mechanic.rentable.RentableMechanic -import dev.slne.surf.roleplay.api.mechanic.rentable.events.RentableOwnerChangeEvent -import dev.slne.surf.roleplay.api.player.events.RpPlayerQuitEvent -import dev.slne.surf.roleplay.mechanic.plugin -import org.bukkit.event.EventHandler -import org.bukkit.event.EventPriority -import org.bukkit.event.Listener - -object RentableOnlineListener : Listener { - - @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR) - fun onRpPlayerQuit(event: RpPlayerQuitEvent) { - val mechanic = Mechanic.getMechanic() - val ownedRentables = mechanic.getOwnedRentablesByPlayer(event.rpPlayer) - - plugin.launch { - ownedRentables.forEach { rentable -> - rentable.setOwner(null, RentableOwnerChangeEvent.OwnerChangeReason.OwnerQuit) - } - } - } - -} \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/DoorImpl.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/DoorImpl.kt deleted file mode 100644 index 13a86bd..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/DoorImpl.kt +++ /dev/null @@ -1,62 +0,0 @@ -@file:Suppress("UnstableApiUsage") - -package dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils - -import dev.slne.surf.roleplay.api.mechanic.rentable.Rentable -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.LockPick -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.door.Door -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.door.DoorContainer -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.surfapi.bukkit.api.util.getBlockAtAsync -import org.bukkit.Location -import kotlin.time.Duration - -abstract class DoorImpl( - override val rentable: Rentable, - override val container: DoorContainer, - override val location: Location, - override val crackDuration: Duration -) : Door { - - override var cracked: Boolean = false - - private suspend fun doorStateOperation( - door: Door, - operation: (org.bukkit.block.data.type.Door) -> Unit - ) { - val doorLocation = door.location - - val doorBlock = doorLocation.world.getBlockAtAsync(doorLocation.toBlock()) - val doorBlockState = doorBlock.state - - if (doorBlockState is org.bukkit.block.data.type.Door) { - operation(doorBlockState) - doorBlockState.update(true, false) - } - } - - override suspend fun open() { - container.doors.forEach { door -> - doorStateOperation(door) { state -> - state.isOpen = true - } - } - } - - override suspend fun close() { - container.doors.forEach { door -> - doorStateOperation(door) { state -> - state.isOpen = false - } - } - } - - override fun canAccess(player: RpPlayer) = cracked || rentable.isMember(player) - - override suspend fun crack( - player: RpPlayer, - lockPick: LockPick - ) = Cracker.crack(player, this, lockPick) { - cracked = true - } -} \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/LockPickImpl.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/LockPickImpl.kt deleted file mode 100644 index 129798b..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/LockPickImpl.kt +++ /dev/null @@ -1,10 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils - -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.LockPick -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.surfapi.core.api.messages.builder.SurfComponentBuilder - -abstract class LockPickImpl( - override val displayName: SurfComponentBuilder.() -> Unit, - override val breakChance: (RpPlayer) -> Double -) : LockPick \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/StorageContainerImpl.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/StorageContainerImpl.kt deleted file mode 100644 index 14d12f4..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/StorageContainerImpl.kt +++ /dev/null @@ -1,34 +0,0 @@ -@file:Suppress("UnstableApiUsage") - -package dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils - -import com.github.shynixn.mccoroutine.folia.regionDispatcher -import dev.slne.surf.roleplay.api.mechanic.rentable.Rentable -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.Crackable -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.Lockable -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.StorageContainer -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.mechanic.plugin -import dev.slne.surf.surfapi.bukkit.api.util.getBlockAtAsync -import kotlinx.coroutines.withContext -import org.bukkit.Location - -open class StorageContainerImpl( - override val rentable: Rentable, - override val location: Location, - override val type: StorageContainer.StorageContainerType, - override val size: StorageContainer.StorageContainerSize -) : StorageContainer, Lockable { - - override suspend fun placeInWorld() = withContext(plugin.regionDispatcher(location)) { - val block = location.world.getBlockAtAsync(location.toBlock()) - - block.type = type.material - } - - override fun canAccess(player: RpPlayer): Boolean { - val crackableAndCracked = this is Crackable && this.cracked - - return crackableAndCracked || rentable.isMember(player) - } -} \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/containers/RegularStorageContainer.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/containers/RegularStorageContainer.kt deleted file mode 100644 index b48d7d5..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/containers/RegularStorageContainer.kt +++ /dev/null @@ -1,17 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils.containers - -import dev.slne.surf.roleplay.api.mechanic.rentable.Rentable -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.StorageContainer -import dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils.StorageContainerImpl -import org.bukkit.Location - -class RegularStorageContainer( - rentable: Rentable, - location: Location, - size: StorageContainer.StorageContainerSize -) : StorageContainerImpl( - rentable = rentable, - location = location, - type = StorageContainer.StorageContainerType.REGULAR, - size = size, -) \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/containers/VaultStorageContainer.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/containers/VaultStorageContainer.kt deleted file mode 100644 index 379abfd..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/containers/VaultStorageContainer.kt +++ /dev/null @@ -1,32 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils.containers - -import dev.slne.surf.roleplay.api.mechanic.rentable.Rentable -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.Crackable -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.LockPick -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.StorageContainer -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils.Cracker -import dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils.StorageContainerImpl -import org.bukkit.Location -import kotlin.time.Duration - -class VaultStorageContainer( - rentable: Rentable, - location: Location, - size: StorageContainer.StorageContainerSize, - override val crackDuration: Duration = size.vaultCrackDuration -) : StorageContainerImpl( - rentable = rentable, - location = location, - type = StorageContainer.StorageContainerType.VAULT, - size = size, -), Crackable { - override var cracked: Boolean = false - - override suspend fun crack( - player: RpPlayer, - lockPick: LockPick - ) = Cracker.crack(player, this, lockPick) { - cracked = true - } -} \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/doors/FrontDoor.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/doors/FrontDoor.kt deleted file mode 100644 index 78493da..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/doors/FrontDoor.kt +++ /dev/null @@ -1,18 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils.doors - -import dev.slne.surf.roleplay.api.mechanic.rentable.Rentable -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.door.DoorContainer -import dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils.DoorImpl -import org.bukkit.Location -import kotlin.time.Duration.Companion.seconds - -class FrontDoor( - rentable: Rentable, - container: DoorContainer, - location: Location -) : DoorImpl( - rentable = rentable, - container = container, - location = location, - crackDuration = 30.seconds -) \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/doors/GarageDoor.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/doors/GarageDoor.kt deleted file mode 100644 index 7eba985..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/doors/GarageDoor.kt +++ /dev/null @@ -1,18 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils.doors - -import dev.slne.surf.roleplay.api.mechanic.rentable.Rentable -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.door.DoorContainer -import dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils.DoorImpl -import org.bukkit.Location -import kotlin.time.Duration.Companion.seconds - -class GarageDoor( - rentable: Rentable, - container: DoorContainer, - location: Location -) : DoorImpl( - rentable = rentable, - container = container, - location = location, - crackDuration = 15.seconds -) \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/doors/RegularDoor.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/doors/RegularDoor.kt deleted file mode 100644 index 5498bed..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/doors/RegularDoor.kt +++ /dev/null @@ -1,18 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils.doors - -import dev.slne.surf.roleplay.api.mechanic.rentable.Rentable -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.door.DoorContainer -import dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils.DoorImpl -import org.bukkit.Location -import kotlin.time.Duration.Companion.seconds - -class RegularDoor( - rentable: Rentable, - container: DoorContainer, - location: Location -) : DoorImpl( - rentable = rentable, - container = container, - location = location, - crackDuration = 15.seconds -) \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/lockpick/BatteringRam.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/lockpick/BatteringRam.kt deleted file mode 100644 index 6c67e77..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/lockpick/BatteringRam.kt +++ /dev/null @@ -1,10 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils.lockpick - -import dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils.LockPickImpl - -object BatteringRam : LockPickImpl( - displayName = { - primary("Rammbock") - }, - breakChance = { 0.0 } -) \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/lockpick/PremiumLockPick.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/lockpick/PremiumLockPick.kt deleted file mode 100644 index ca36a13..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/lockpick/PremiumLockPick.kt +++ /dev/null @@ -1,10 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils.lockpick - -import dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils.LockPickImpl - -object PremiumLockPick : LockPickImpl( - displayName = { - primary("Verzinkter Vierkantstahl Dietrich") - }, - breakChance = { 0.1 } -) \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/lockpick/RegularLockPick.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/lockpick/RegularLockPick.kt deleted file mode 100644 index a3b9cb1..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/lockpick/RegularLockPick.kt +++ /dev/null @@ -1,10 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils.lockpick - -import dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils.LockPickImpl - -object RegularLockPick : LockPickImpl( - displayName = { - primary("Dietrich") - }, - breakChance = { 0.5 } -) \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/utils/PermissionRegistry.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/utils/PermissionRegistry.kt deleted file mode 100644 index fad0861..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/utils/PermissionRegistry.kt +++ /dev/null @@ -1,10 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.utils - -import dev.slne.surf.surfapi.bukkit.api.permission.PermissionRegistry - -object PermissionRegistry : PermissionRegistry() { - - const val PREFIX = "surf.roleplay.mechanic" - private const val COMMAND_PREFIX = "$PREFIX.command" - -} \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/weapon/WeaponImpl.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/weapon/WeaponImpl.kt deleted file mode 100644 index a2ceda7..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/weapon/WeaponImpl.kt +++ /dev/null @@ -1,37 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.weapon - -import dev.slne.surf.roleplay.api.mechanic.weapon.Weapon -import dev.slne.surf.roleplay.api.mechanic.weapon.magazine.Magazine -import dev.slne.surf.roleplay.api.mechanic.weapon.utils.WeaponType -import dev.slne.surf.surfapi.bukkit.api.builder.LoreBuilder -import dev.slne.surf.surfapi.core.api.messages.builder.SurfComponentBuilder -import dev.slne.surf.surfapi.core.api.util.objectSetOf -import it.unimi.dsi.fastutil.objects.ObjectSet -import org.bukkit.Material -import org.bukkit.inventory.ItemStack -import kotlin.time.Duration -import kotlin.time.Duration.Companion.seconds - -abstract class WeaponImpl( - override val type: WeaponType, - override val weaponMaterial: Material, - override val name: String, - override val displayName: SurfComponentBuilder.() -> Unit = { - primary(name) - }, - override val description: LoreBuilder.() -> Unit = { - line { - spacer("Eine ") - append(displayName) - spacer(" Waffe") - } - }, - override val weaponShootCooldown: Duration = 1.seconds, - override val supportedMagazines: ObjectSet = objectSetOf() -) : Weapon { - override fun isApplicableMagazine(magazine: Magazine) = magazine in supportedMagazines - - override fun buildItemStack(): ItemStack { - - } -} \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/weapon/WeaponMechanicImpl.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/weapon/WeaponMechanicImpl.kt deleted file mode 100644 index 8ce65d5..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/weapon/WeaponMechanicImpl.kt +++ /dev/null @@ -1,18 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.weapon - -import dev.slne.surf.roleplay.api.mechanic.weapon.Weapon -import dev.slne.surf.roleplay.api.mechanic.weapon.WeaponMechanic -import dev.slne.surf.roleplay.mechanic.MechanicImpl -import dev.slne.surf.surfapi.core.api.util.freeze -import dev.slne.surf.surfapi.core.api.util.mutableObjectSetOf -import dev.slne.surf.surfapi.core.api.util.objectSetOf - -object WeaponMechanicImpl : MechanicImpl( - name = "WeaponMechanic", - handlers = objectSetOf(), - rpJobs = objectSetOf(), - packetListeners = objectSetOf() -), WeaponMechanic { - private val _weapons = mutableObjectSetOf() - override val weapons get() = _weapons.freeze() -} \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/weapon/magazine/MagazineImpl.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/weapon/magazine/MagazineImpl.kt deleted file mode 100644 index 719ce96..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/weapon/magazine/MagazineImpl.kt +++ /dev/null @@ -1,21 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.weapon.magazine - -import dev.slne.surf.roleplay.api.mechanic.weapon.magazine.Magazine -import dev.slne.surf.surfapi.bukkit.api.builder.LoreBuilder -import dev.slne.surf.surfapi.core.api.messages.builder.SurfComponentBuilder - -abstract class MagazineImpl( - override val name: String, - override val displayName: SurfComponentBuilder.() -> Unit = { - primary(name) - }, - override val description: LoreBuilder.() -> Unit = { - line { - spacer("Ein ") - append(displayName) - spacer(" Magazin") - } - }, - override val maxAmmo: Int, - override val damageFunction: (Double) -> Double -) : Magazine \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/weapon/magazine/PlayerMagazineImpl.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/weapon/magazine/PlayerMagazineImpl.kt deleted file mode 100644 index bfe498a..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/weapon/magazine/PlayerMagazineImpl.kt +++ /dev/null @@ -1,11 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.weapon.magazine - -import dev.slne.surf.roleplay.api.mechanic.weapon.magazine.Magazine -import dev.slne.surf.roleplay.api.mechanic.weapon.magazine.PlayerMagazine - -class PlayerMagazineImpl( - override val magazine: Magazine, -) : PlayerMagazine { - private var _currentAmmo = magazine.maxAmmo - override val currentAmmo get() = _currentAmmo -} \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/weapon/player/PlayerWeaponImpl.kt b/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/weapon/player/PlayerWeaponImpl.kt deleted file mode 100644 index 0fde671..0000000 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/weapon/player/PlayerWeaponImpl.kt +++ /dev/null @@ -1,16 +0,0 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.weapon.player - -import dev.slne.surf.roleplay.api.mechanic.weapon.Weapon -import dev.slne.surf.roleplay.api.mechanic.weapon.magazine.PlayerMagazine -import dev.slne.surf.roleplay.api.mechanic.weapon.player.PlayerWeapon - -class PlayerWeaponImpl( - override val weapon: Weapon -) : PlayerWeapon { - private var _currentMagazine: PlayerMagazine? = null - override val currentMagazine get() = _currentMagazine - - override fun setCurrentMagazine(magazine: PlayerMagazine?) { - _currentMagazine = magazine - } -} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-client-old/build.gradle.kts b/surf-roleplay-mod/surf-roleplay-mod-client-old/build.gradle.kts new file mode 100644 index 0000000..6b8745c --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client-old/build.gradle.kts @@ -0,0 +1,50 @@ +plugins { + id("dev.slne.surf.surfapi.gradle.core") + alias(libs.plugins.loom) +} + +base { + archivesName.set(project.extra["archives_base_name"] as String) +} + +fabricApi { + configureDataGeneration { + client = true + } +} + +dependencies { + val minecraftVersion = libs.versions.minecraft.get() + val yarnMappings = libs.versions.yarn.mappings.get() + val loaderVersion = libs.versions.fabric.loader.get() + val fabricVersion = libs.versions.fabric.api.get() + val fabricKotlinVersion = libs.versions.fabric.kotlin.get() + + minecraft("com.mojang:minecraft:$minecraftVersion") + mappings("net.fabricmc:yarn:$yarnMappings:v2") + modImplementation("net.fabricmc:fabric-loader:$loaderVersion") + + implementation(project(":surf-roleplay-mod:surf-roleplay-mod-common")) + implementation(libs.protoweaver.fabric) + + modImplementation("net.fabricmc.fabric-api:fabric-api:$fabricVersion") + modImplementation("net.fabricmc:fabric-language-kotlin:$fabricKotlinVersion") +} + +tasks.processResources { + from(project.project(":surf-roleplay-mod:surf-roleplay-mod-common").sourceSets.main.get().resources) + + inputs.property("version", project.version) + + filesMatching("fabric.mod.json") { + expand("version" to inputs.properties["version"]) + } +} + +tasks.jar { + inputs.property("archivesName", base.archivesName.get()) + + from("LICENSE") { + rename { "${it}_${inputs.properties["archivesName"]}" } + } +} diff --git a/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/java/dev/slne/surf/roleplay/mod/mixin/ExampleMixin.java b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/java/dev/slne/surf/roleplay/mod/mixin/ExampleMixin.java new file mode 100644 index 0000000..80f2310 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/java/dev/slne/surf/roleplay/mod/mixin/ExampleMixin.java @@ -0,0 +1,16 @@ +package dev.slne.surf.roleplay.mod.mixin; + +import net.minecraft.server.MinecraftServer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(MinecraftServer.class) +public class ExampleMixin { + + @Inject(at = @At("HEAD"), method = "loadWorld") + private void init(CallbackInfo info) { + // This code is injected into the start of MinecraftServer.loadWorld()V + } +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/RoleplayMod.kt b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/RoleplayMod.kt new file mode 100644 index 0000000..eb30465 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/RoleplayMod.kt @@ -0,0 +1,34 @@ +package dev.slne.surf.roleplay.mod + +import dev.slne.surf.roleplay.mod.common.network.PacketRegistry +import dev.slne.surf.roleplay.mod.common.network.user.userManager +import dev.slne.surf.roleplay.mod.keybind.Keybinds +import me.mrnavastar.protoweaver.client.ProtoClient +import net.fabricmc.api.ClientModInitializer +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents +import net.minecraft.client.MinecraftClient +import java.util.* + +object RoleplayMod : ClientModInitializer { + var client: ProtoClient? = null + + val uuid: UUID get() = MinecraftClient.getInstance().gameProfile.id + + override fun onInitializeClient() { + Keybinds.registerKeybindings() + + ClientPlayConnectionEvents.JOIN.register { handler, sender, client -> + val server = client.server!! + this.client = ProtoClient(server.serverIp, server.serverPort).also { + it.connect(PacketRegistry.loginProtocol) + userManager.init(uuid, it.connection) + } + } + + ClientPlayConnectionEvents.DISCONNECT.register { handler, client -> + this.client?.disconnect() + this.client = null + userManager.destroy(uuid) + } + } +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/RoleplayModDataGenerator.kt b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/RoleplayModDataGenerator.kt new file mode 100644 index 0000000..65485b1 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/RoleplayModDataGenerator.kt @@ -0,0 +1,9 @@ +package dev.slne.surf.roleplay.mod + +import net.fabricmc.fabric.api.datagen.v1.DataGeneratorEntrypoint +import net.fabricmc.fabric.api.datagen.v1.FabricDataGenerator + +object RoleplayModDataGenerator : DataGeneratorEntrypoint { + override fun onInitializeDataGenerator(fabricDataGenerator: FabricDataGenerator) { + } +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/keybind/KeybindAction.kt b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/keybind/KeybindAction.kt new file mode 100644 index 0000000..3c9d760 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/keybind/KeybindAction.kt @@ -0,0 +1,7 @@ +package dev.slne.surf.roleplay.mod.keybind + +import net.minecraft.client.network.ClientPlayerEntity + +fun interface KeybindAction { + fun handle(player: ClientPlayerEntity) +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/keybind/KeybindCategory.kt b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/keybind/KeybindCategory.kt new file mode 100644 index 0000000..820c9df --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/keybind/KeybindCategory.kt @@ -0,0 +1,7 @@ +package dev.slne.surf.roleplay.mod.keybind + +enum class KeybindCategory(val translationKey: String) { + + TEST("key.category.roleplay.test") + +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/keybind/Keybinds.kt b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/keybind/Keybinds.kt new file mode 100644 index 0000000..2ee7729 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/keybind/Keybinds.kt @@ -0,0 +1,64 @@ +package dev.slne.surf.roleplay.mod.keybind + +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents +import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper +import net.minecraft.client.option.KeyBinding +import net.minecraft.client.util.InputUtil +import net.minecraft.text.Text +import org.lwjgl.glfw.GLFW + +enum class Keybinds( + val key: Int, + val translationKey: String, + val category: KeybindCategory, + val action: KeybindAction, + val actionExecutableInGui: Boolean = false, + val type: InputUtil.Type = InputUtil.Type.KEYSYM, +) { + TEST( + GLFW.GLFW_KEY_N, + "key.roleplay.test", + KeybindCategory.TEST, + { player -> + player.sendMessage(Text.literal("Test keybind pressed!"), false) + } + ), + TEST2( + GLFW.GLFW_KEY_Z, + "key.roleplay.test2", + KeybindCategory.TEST, + { player -> + player.sendMessage(Text.literal("Test2 keybind pressed!"), false) + } + ); + + companion object { + fun registerKeybindings() { + val registeredKeybinds = entries.associateWith { + KeyBindingHelper.registerKeyBinding( + KeyBinding( + it.translationKey, + it.type, + it.key, + it.category.translationKey + ) + ) + } + + ClientTickEvents.END_CLIENT_TICK.register { client -> + registeredKeybinds.forEach { (keybind, keybinding) -> + if (keybinding.wasPressed()) { + val player = client.player ?: return@forEach + + if (player.currentScreenHandler != player.playerScreenHandler && !keybind.actionExecutableInGui) { + return@forEach + } + + keybind.action.handle(player) + } + } + } + } + } + +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/network/ClientLoginPacketListenerImpl.kt b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/network/ClientLoginPacketListenerImpl.kt new file mode 100644 index 0000000..eb05935 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/network/ClientLoginPacketListenerImpl.kt @@ -0,0 +1,21 @@ +package dev.slne.surf.roleplay.mod.network + +import dev.slne.surf.roleplay.mod.RoleplayMod +import dev.slne.surf.roleplay.mod.common.network.protocol.clientbound.ClientboundHandshakePacket +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.login.ClientLoginPacketListener +import dev.slne.surf.roleplay.mod.common.network.protocol.serverbound.ServerboundHandshakePacket + +object ClientLoginPacketListenerImpl : ClientLoginPacketListener { + private val connection + get() = RoleplayMod.client?.connection ?: error("Not connected to a roleplay server") + + override fun handleHandshake(packet: ClientboundHandshakePacket) { + connection.send( + ServerboundHandshakePacket( + handshake = packet.handshake, + uuid = RoleplayMod.uuid, + clientVersion = "1" + ) + ) + } +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/network/ClientNetworkBridgeImpl.kt b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/network/ClientNetworkBridgeImpl.kt new file mode 100644 index 0000000..ee4da73 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/network/ClientNetworkBridgeImpl.kt @@ -0,0 +1,24 @@ +package dev.slne.surf.roleplay.mod.network + +import com.google.auto.service.AutoService +import dev.slne.surf.roleplay.mod.RoleplayMod +import dev.slne.surf.roleplay.mod.common.network.NetworkBridge +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.login.ClientLoginPacketListener +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.login.ServerLoginPacketListener +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.packet.login.ClientLoginPacketHandler +import me.mrnavastar.protoweaver.api.netty.ProtoConnection + +@AutoService(NetworkBridge::class) +class ClientNetworkBridgeImpl : NetworkBridge { + override val serverLoginPacketHandlerClass = null + override val clientLoginPacketHandlerClass = ClientLoginPacketHandler::class.java + + override fun createServerLoginPacketHandler(connection: ProtoConnection): ServerLoginPacketListener { + error("Client login packet handler is not implemented on the client side") + } + + override fun createClientLoginPacketHandler(connection: ProtoConnection): ClientLoginPacketListener { + require(connection == RoleplayMod.client?.connection) { "Connection mismatch" } + return ClientLoginPacketListenerImpl + } +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/network/user/ClientProtoUser.kt b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/network/user/ClientProtoUser.kt new file mode 100644 index 0000000..9349c6e --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/network/user/ClientProtoUser.kt @@ -0,0 +1,10 @@ +package dev.slne.surf.roleplay.mod.network.user + +import dev.slne.surf.roleplay.mod.RoleplayMod +import dev.slne.surf.roleplay.mod.common.network.user.ProtoUser +import me.mrnavastar.protoweaver.api.netty.ProtoConnection + +object ClientProtoUser : ProtoUser(RoleplayMod.uuid) { + override val connection: ProtoConnection + get() = RoleplayMod.client?.connection ?: error("Not connected to a roleplay server") +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/network/user/ClientProtoUserManager.kt b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/network/user/ClientProtoUserManager.kt new file mode 100644 index 0000000..1db2ca8 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/kotlin/dev/slne/surf/roleplay/mod/network/user/ClientProtoUserManager.kt @@ -0,0 +1,18 @@ +package dev.slne.surf.roleplay.mod.network.user + +import com.google.auto.service.AutoService +import dev.slne.surf.roleplay.mod.common.network.user.ProtoUser +import dev.slne.surf.roleplay.mod.common.network.user.ProtoUserManager +import me.mrnavastar.protoweaver.api.netty.ProtoConnection +import java.util.* + +@AutoService(ProtoUserManager::class) +class ClientProtoUserManager : ProtoUserManager() { + override fun createUser( + uuid: UUID, + connection: ProtoConnection + ): ProtoUser { + require(uuid == ClientProtoUser.uuid) { "UUID mismatch: expected ${ClientProtoUser.uuid}, got $uuid" } + return ClientProtoUser + } +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/resources/assets/lang/de_de.json b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/resources/assets/lang/de_de.json new file mode 100644 index 0000000..4925bfd --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/resources/assets/lang/de_de.json @@ -0,0 +1,5 @@ +{ + "key.roleplay.test": "Dies ist ein Testschlüssel", + "key.roleplay.test2": "Dies ist ein Testschlüssel2", + "key.category.roleplay.test": "Testkategorie" +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/resources/assets/roleplay/icon.png b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/resources/assets/roleplay/icon.png new file mode 100644 index 0000000..725f4db Binary files /dev/null and b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/resources/assets/roleplay/icon.png differ diff --git a/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/resources/fabric.mod.json b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..3a70a33 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/resources/fabric.mod.json @@ -0,0 +1,43 @@ +{ + "schemaVersion": 1, + "id": "surf-roleplay", + "version": "${version}", + "name": "Surf Roleplay", + "description": "A roleplay mod for Surf", + "authors": [ + "Ammo" + ], + "contact": { + "homepage": "https://github.com/SLNE-Development/surf-roleplay", + "sources": "https://github.com/SLNE-Development/surf-roleplay" + }, + "license": "CC0-1.0", + "icon": "assets/roleplay/icon.png", + "environment": "client", + "entrypoints": { + "client": [ + { + "value": "dev.slne.surf.roleplay.mod.RoleplayMod", + "adapter": "kotlin" + } + ], + "fabric-datagen": [ + { + "value": "dev.slne.surf.roleplay.mod.RoleplayModDataGenerator", + "adapter": "kotlin" + } + ] + }, + "mixins": [ + "roleplay.mixins.json" + ], + "depends": { + "fabricloader": ">=0.17.2", + "minecraft": "~1.21.8", + "java": ">=21", + "fabric-api": "*", + "fabric-language-kotlin": "*", + "fabric-key-binding-api-v1": "*", + "protoweaver": ">=1.4.9" + } +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/resources/roleplay.mixins.json b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/resources/roleplay.mixins.json new file mode 100644 index 0000000..80d5464 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client-old/src/main/resources/roleplay.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "package": "dev.slne.roleplay.mod.mixin", + "compatibilityLevel": "JAVA_21", + "mixins": [ + "dev.slne.surf.roleplay.mod.mixin.ExampleMixin" + ], + "injectors": { + "defaultRequire": 1 + }, + "overwrites": { + "requireAnnotations": true + } +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-client/.gitignore b/surf-roleplay-mod/surf-roleplay-mod-client/.gitignore new file mode 100644 index 0000000..d5f737e --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client/.gitignore @@ -0,0 +1,119 @@ +# User-specific stuff +.idea/ + +*.iml +*.ipr +*.iws + +# IntelliJ +out/ +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +.gradle +build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Cache of project +.gradletasknamecache + +**/build/ + +# Common working directory +run/ +runs/ + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar diff --git a/surf-roleplay-mod/surf-roleplay-mod-client/build.gradle.kts b/surf-roleplay-mod/surf-roleplay-mod-client/build.gradle.kts new file mode 100644 index 0000000..b7a408a --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client/build.gradle.kts @@ -0,0 +1,34 @@ +import net.fabricmc.loom.api.LoomGradleExtensionAPI + +plugins { + id("dev.slne.surf.surfapi.gradle.core") + alias(libs.plugins.architectury.base) + alias(libs.plugins.architectury.loom) apply false +} + +val minecraftVersion = libs.versions.minecraft.get() +val modName = rootProject.findProperty("archives_name") as String + +architectury { + minecraft = minecraftVersion +} + +repositories { + maven("https://maven.neoforged.net/releases") +} + +subprojects { + apply(plugin = "dev.architectury.loom") + apply(plugin = "architectury-plugin") + + base { + archivesName = "$modName-${project.name}" + } + + val loomExtension = extensions.getByType() + + dependencies { + "minecraft"("net.minecraft:minecraft:$minecraftVersion") + "mappings"(loomExtension.officialMojangMappings()) + } +} diff --git a/surf-roleplay-mod/surf-roleplay-mod-client/common/build.gradle.kts b/surf-roleplay-mod/surf-roleplay-mod-client/common/build.gradle.kts new file mode 100644 index 0000000..c5249a3 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client/common/build.gradle.kts @@ -0,0 +1,16 @@ +plugins { + id("dev.slne.surf.surfapi.gradle.core") +} + +architectury { + val enabledPlatforms = findProperty("enabled_platforms") as String + common(enabledPlatforms.split(',')) +} + +val fabricLoaderVersion = libs.versions.fabric.loader.get() +val architecturyApiVersion = libs.versions.architectury.api.get() + +dependencies { + modImplementation("net.fabricmc:fabric-loader:$fabricLoaderVersion") + modImplementation("dev.architectury:architectury:$architecturyApiVersion") +} diff --git a/surf-roleplay-mod/surf-roleplay-mod-client/common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/RoleplayMod.java b/surf-roleplay-mod/surf-roleplay-mod-client/common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/RoleplayMod.java new file mode 100644 index 0000000..65a8f04 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client/common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/RoleplayMod.java @@ -0,0 +1,10 @@ +package dev.slne.testmod3; + +public final class RoleplayMod { + + public static final String MOD_ID = "surf-roleplay"; + + public static void init() { + // Write common init code here. + } +} diff --git a/surf-roleplay-mod/surf-roleplay-mod-client/common/src/main/resources/roleplay.mixins.json b/surf-roleplay-mod/surf-roleplay-mod-client/common/src/main/resources/roleplay.mixins.json new file mode 100644 index 0000000..6261f7c --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client/common/src/main/resources/roleplay.mixins.json @@ -0,0 +1,13 @@ +{ + "required": true, + "package": "dev.slne.surf.roleplay.mixin", + "compatibilityLevel": "JAVA_24", + "minVersion": "0.8", + "client": [ + ], + "mixins": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/surf-roleplay-mod/surf-roleplay-mod-client/fabric/build.gradle.kts b/surf-roleplay-mod/surf-roleplay-mod-client/fabric/build.gradle.kts new file mode 100644 index 0000000..c237daa --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client/fabric/build.gradle.kts @@ -0,0 +1,73 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import net.fabricmc.loom.task.RemapJarTask + +plugins { + id("dev.slne.surf.surfapi.gradle.core") +} + +architectury { + platformSetupLoomIde() + fabric() +} + +configurations { + create("common") { + isCanBeResolved = true + isCanBeConsumed = false + } + + named("compileClasspath").get().extendsFrom(configurations.getByName("common")) + named("runtimeClasspath").get().extendsFrom(configurations.getByName("common")) + named("developmentFabric").get().extendsFrom(configurations.getByName("common")) + + create("shadowBundle") { + isCanBeResolved = true + isCanBeConsumed = false + } +} + + +val fabricLoaderVersion = libs.versions.fabric.loader.get() +val fabricApiVersion = libs.versions.fabric.api.get() +val architecturyApiVersion = libs.versions.architectury.api.get() + +dependencies { + modImplementation("net.fabricmc:fabric-loader:$fabricLoaderVersion") + modImplementation("net.fabricmc.fabric-api:fabric-api:$fabricApiVersion") + modImplementation("dev.architectury:architectury-fabric:$architecturyApiVersion") + + add( + "common", project( + mapOf( + "path" to ":surf-roleplay-mod:surf-roleplay-mod-client:common", + "configuration" to "namedElements" + ) + ) + ) + + add( + "shadowBundle", project( + mapOf( + "path" to ":surf-roleplay-mod:surf-roleplay-mod-client:common", + "configuration" to "transformProductionFabric" + ) + ) + ) +} + +tasks.processResources { + inputs.property("version", project.version) + + filesMatching("fabric.mod.json") { + expand("version" to project.version) + } +} + +tasks.withType { + configurations = listOf(project.configurations.getByName("shadowBundle")) + archiveClassifier.set("dev-shadow") +} + +tasks.withType { + input.set(tasks.withType()["shadowJar"].archiveFile) +} diff --git a/surf-roleplay-mod/surf-roleplay-mod-client/fabric/src/main/kotlin/dev/slne/surf/roleplay/mod/fabric/RoleplayFabricMod.java b/surf-roleplay-mod/surf-roleplay-mod-client/fabric/src/main/kotlin/dev/slne/surf/roleplay/mod/fabric/RoleplayFabricMod.java new file mode 100644 index 0000000..0329b09 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client/fabric/src/main/kotlin/dev/slne/surf/roleplay/mod/fabric/RoleplayFabricMod.java @@ -0,0 +1,11 @@ +package dev.slne.surf.roleplay.mod.fabric; + +import net.fabricmc.api.ClientModInitializer; + +public final class RoleplayFabricMod implements ClientModInitializer { + + @Override + public void onInitializeClient() { + // This entrypoint is suitable for setting up client-specific logic, such as rendering. + } +} diff --git a/surf-roleplay-mod/surf-roleplay-mod-client/fabric/src/main/resources/fabric.mod.json b/surf-roleplay-mod/surf-roleplay-mod-client/fabric/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..230af70 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client/fabric/src/main/resources/fabric.mod.json @@ -0,0 +1,31 @@ +{ + "schemaVersion": 1, + "id": "surf-roleplay", + "version": "${version}", + "name": "surf-roleplay", + "description": "", + "authors": [ + "SLNE Development" + ], + "contact": { + "homepage": "" + }, + "license": "All-Rights-Reserved", + "icon": "assets/roleplay/icon.png", + "environment": "*", + "entrypoints": { + "client": [ + "dev.slne.surf.roleplay.mod.fabric.RoleplayFabricMod" + ] + }, + "mixins": [ + "roleplay.mixins.json" + ], + "depends": { + "fabricloader": ">=0.17.2", + "minecraft": "~1.21", + "java": ">=21", + "architectury": ">=13.0.8", + "fabric-api": "*" + } +} diff --git a/surf-roleplay-mod/surf-roleplay-mod-client/neoforge/build.gradle.kts b/surf-roleplay-mod/surf-roleplay-mod-client/neoforge/build.gradle.kts new file mode 100644 index 0000000..72e6327 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client/neoforge/build.gradle.kts @@ -0,0 +1,70 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import net.fabricmc.loom.task.RemapJarTask + +plugins { + id("dev.slne.surf.surfapi.gradle.core") +} + +architectury { + platformSetupLoomIde() + neoForge() +} + +configurations { + create("common") { + isCanBeResolved = true + isCanBeConsumed = false + } + + named("compileClasspath").get().extendsFrom(configurations.getByName("common")) + named("runtimeClasspath").get().extendsFrom(configurations.getByName("common")) + named("developmentNeoForge").get().extendsFrom(configurations.getByName("common")) + + create("shadowBundle") { + isCanBeResolved = true + isCanBeConsumed = false + } +} + +val neoForgeVersion = libs.versions.neoforge.get() +val architecturyApiVersion = libs.versions.architectury.api.get() + +dependencies { + neoForge("net.neoforged:neoforge:$neoForgeVersion") + modImplementation("dev.architectury:architectury-neoforge:$architecturyApiVersion") + + add( + "common", project( + mapOf( + "path" to ":surf-roleplay-mod:surf-roleplay-mod-client:common", + "configuration" to "namedElements" + ) + ) + ) + + add( + "shadowBundle", project( + mapOf( + "path" to ":surf-roleplay-mod:surf-roleplay-mod-client:common", + "configuration" to "transformProductionNeoForge" + ) + ) + ) +} + +tasks.processResources { + inputs.property("version", project.version) + + filesMatching("META-INF/neoforge.mods.toml") { + expand("version" to project.version) + } +} + +tasks.withType { + configurations = listOf(project.configurations.getByName("shadowBundle")) + archiveClassifier.set("dev-shadow") +} + +tasks.withType { + input.set(tasks.withType()["shadowJar"].archiveFile) +} diff --git a/surf-roleplay-mod/surf-roleplay-mod-client/neoforge/gradle.properties b/surf-roleplay-mod/surf-roleplay-mod-client/neoforge/gradle.properties new file mode 100644 index 0000000..7da18ea --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client/neoforge/gradle.properties @@ -0,0 +1 @@ +loom.platform=neoforge diff --git a/surf-roleplay-mod/surf-roleplay-mod-client/neoforge/src/main/kotlin/dev/slne/surf/roleplay/mod/neoforge/RoleplayNeoforgeMod.kt b/surf-roleplay-mod/surf-roleplay-mod-client/neoforge/src/main/kotlin/dev/slne/surf/roleplay/mod/neoforge/RoleplayNeoforgeMod.kt new file mode 100644 index 0000000..6d09167 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client/neoforge/src/main/kotlin/dev/slne/surf/roleplay/mod/neoforge/RoleplayNeoforgeMod.kt @@ -0,0 +1,12 @@ +package dev.slne.surf.roleplay.mod.neoforge + +import dev.slne.surf.roleplay.mod.common.RoleplayMod +import net.neoforged.fml.common.Mod + +@Mod(RoleplayMod.MOD_ID) +class RoleplayNeoForgeModa { + init { + // Run our common setup. + RoleplayMod.init() + } +} diff --git a/surf-roleplay-mod/surf-roleplay-mod-client/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/surf-roleplay-mod/surf-roleplay-mod-client/neoforge/src/main/resources/META-INF/neoforge.mods.toml new file mode 100644 index 0000000..76280d6 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-client/neoforge/src/main/resources/META-INF/neoforge.mods.toml @@ -0,0 +1,24 @@ +modLoader = "javafml" +loaderVersion = "[2,)" +#issueTrackerURL = "" +license = "All Rights Reserved" + +[[mods]] +modId = "surf-roleplay" +version = "${version}" +displayName = "surf-roleplay" +authors = "SLNE Development" +description = ''' + +''' +#logoFile = "" + +#[[dependencies.testmod3]] +#modId = "neoforge" +#type = "required" +#versionRange = "[21,)" +#ordering = "NONE" +#side = "BOTH" + +[[mixins]] +config = "roleplay.mixins.json" diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/build.gradle.kts b/surf-roleplay-mod/surf-roleplay-mod-common/build.gradle.kts new file mode 100644 index 0000000..65e13dc --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/build.gradle.kts @@ -0,0 +1,7 @@ +plugins { + id("dev.slne.surf.surfapi.gradle.core") +} + +dependencies { + compileOnlyApi(libs.protoweaver.common) +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/NetworkBridge.kt b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/NetworkBridge.kt new file mode 100644 index 0000000..27bf381 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/NetworkBridge.kt @@ -0,0 +1,22 @@ +package dev.slne.surf.roleplay.mod.common.network + +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.login.ClientLoginPacketListener +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.login.ServerLoginPacketListener +import dev.slne.surf.surfapi.core.api.util.requiredService +import me.mrnavastar.protoweaver.api.ProtoConnectionHandler +import me.mrnavastar.protoweaver.api.netty.ProtoConnection + +private val networkBridge = requiredService() + +interface NetworkBridge { + + val serverLoginPacketHandlerClass: Class? + val clientLoginPacketHandlerClass: Class? + + fun createServerLoginPacketHandler(connection: ProtoConnection): ServerLoginPacketListener + fun createClientLoginPacketHandler(connection: ProtoConnection): ClientLoginPacketListener + + companion object : NetworkBridge by networkBridge { + val INSTANCE: NetworkBridge get() = networkBridge + } +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/PacketRegistry.kt b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/PacketRegistry.kt new file mode 100644 index 0000000..dbab34c --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/PacketRegistry.kt @@ -0,0 +1,37 @@ +package dev.slne.surf.roleplay.mod.common.network + +import dev.slne.surf.roleplay.mod.common.network.protocol.clientbound.ClientboundHandshakePacket +import dev.slne.surf.roleplay.mod.common.network.protocol.serverbound.ServerboundHandshakePacket +import me.mrnavastar.protoweaver.api.ProtoWeaver +import me.mrnavastar.protoweaver.api.protocol.CompressionType +import me.mrnavastar.protoweaver.api.protocol.Protocol + +@Suppress("UNCHECKED_CAST") +object PacketRegistry { + + val loginProtocol: Protocol = registerLoginProtocol() + val playProtocol: Protocol = registerPlayProtocol() + + init { + ProtoWeaver.load(loginProtocol) +// ProtoWeaver.load(playProtocol) + } + + private fun getBaseProtocol(protocolName: String) = + Protocol.create("surf-roleplay", protocolName) + .setCompression(CompressionType.GZIP) + + private fun registerLoginProtocol() = getBaseProtocol("login") + .apply { + NetworkBridge.clientLoginPacketHandlerClass?.let { setServerHandler(it) } + NetworkBridge.serverLoginPacketHandlerClass?.let { setClientHandler(it) } + } + .addPacket(ClientboundHandshakePacket::class.java) + .addPacket(ServerboundHandshakePacket::class.java) + .build() + + private fun registerPlayProtocol() = getBaseProtocol("play") +// .setServerHandler() +// .setClientHandler() + .build() +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/SurfRoleplayPacket.kt b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/SurfRoleplayPacket.kt new file mode 100644 index 0000000..6a4dfb0 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/SurfRoleplayPacket.kt @@ -0,0 +1,7 @@ +package dev.slne.surf.roleplay.mod.common.network + +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.RUNTIME) +annotation class SurfRoleplayPacket( + val id: String, +) \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/packet/RoleplayPacket.kt b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/packet/RoleplayPacket.kt new file mode 100644 index 0000000..08a6f76 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/packet/RoleplayPacket.kt @@ -0,0 +1,15 @@ +package dev.slne.surf.roleplay.mod.common.network.packet + +import dev.slne.surf.roleplay.mod.common.network.SurfRoleplayPacket +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.PacketListener + +interface RoleplayPacket { + + val meta: SurfRoleplayPacket + get() = javaClass.getDeclaredAnnotation(SurfRoleplayPacket::class.java) + + val id: String get() = meta.id + + fun handle(listener: L) + +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/packet/login/ClientboundRoleplayLoginPacket.kt b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/packet/login/ClientboundRoleplayLoginPacket.kt new file mode 100644 index 0000000..50ab90e --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/packet/login/ClientboundRoleplayLoginPacket.kt @@ -0,0 +1,6 @@ +package dev.slne.surf.roleplay.mod.common.network.packet.login + +import dev.slne.surf.roleplay.mod.common.network.packet.RoleplayPacket +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.login.ClientLoginPacketListener + +interface ClientboundRoleplayLoginPacket : RoleplayPacket \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/packet/login/ServerboundRoleplayLoginPacket.kt b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/packet/login/ServerboundRoleplayLoginPacket.kt new file mode 100644 index 0000000..643724d --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/packet/login/ServerboundRoleplayLoginPacket.kt @@ -0,0 +1,6 @@ +package dev.slne.surf.roleplay.mod.common.network.packet.login + +import dev.slne.surf.roleplay.mod.common.network.packet.RoleplayPacket +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.login.ServerLoginPacketListener + +interface ServerboundRoleplayLoginPacket : RoleplayPacket \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/DefaultIds.kt b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/DefaultIds.kt new file mode 100644 index 0000000..7c195f9 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/DefaultIds.kt @@ -0,0 +1,7 @@ +package dev.slne.surf.roleplay.mod.common.network.protocol + +object DefaultIds { + // Handshake + const val CLIENTBOUND_HANDSHAKE = "clientbound:handshake" + const val SERVERBOUND_HANDSHAKE = "serverbound:handshake" +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/clientbound/ClientboundHandshakePacket.kt b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/clientbound/ClientboundHandshakePacket.kt new file mode 100644 index 0000000..6942ea4 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/clientbound/ClientboundHandshakePacket.kt @@ -0,0 +1,16 @@ +package dev.slne.surf.roleplay.mod.common.network.protocol.clientbound + +import dev.slne.surf.roleplay.mod.common.network.SurfRoleplayPacket +import dev.slne.surf.roleplay.mod.common.network.packet.login.ClientboundRoleplayLoginPacket +import dev.slne.surf.roleplay.mod.common.network.protocol.DefaultIds +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.login.ClientLoginPacketListener +import java.util.* + +@SurfRoleplayPacket(id = DefaultIds.CLIENTBOUND_HANDSHAKE) +class ClientboundHandshakePacket( + val handshake: UUID +) : ClientboundRoleplayLoginPacket { + override fun handle(listener: ClientLoginPacketListener) { + listener.handleHandshake(this) + } +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/listener/PacketListener.kt b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/listener/PacketListener.kt new file mode 100644 index 0000000..b132701 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/listener/PacketListener.kt @@ -0,0 +1,8 @@ +package dev.slne.surf.roleplay.mod.common.network.protocol.listener + +sealed interface PacketListener { + + interface LoginPacketListener : PacketListener + interface PlayPacketListener : PacketListener + +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/listener/TickablePacketListener.kt b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/listener/TickablePacketListener.kt new file mode 100644 index 0000000..ce5d5a1 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/listener/TickablePacketListener.kt @@ -0,0 +1,5 @@ +package dev.slne.surf.roleplay.mod.common.network.protocol.listener + +interface TickablePacketListener { + fun tick() +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/listener/login/ClientLoginPacketListener.kt b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/listener/login/ClientLoginPacketListener.kt new file mode 100644 index 0000000..94eb79d --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/listener/login/ClientLoginPacketListener.kt @@ -0,0 +1,8 @@ +package dev.slne.surf.roleplay.mod.common.network.protocol.listener.login + +import dev.slne.surf.roleplay.mod.common.network.protocol.clientbound.ClientboundHandshakePacket +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.PacketListener + +interface ClientLoginPacketListener : PacketListener.LoginPacketListener { + fun handleHandshake(packet: ClientboundHandshakePacket) +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/listener/login/ServerLoginPacketListener.kt b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/listener/login/ServerLoginPacketListener.kt new file mode 100644 index 0000000..a0b0d80 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/listener/login/ServerLoginPacketListener.kt @@ -0,0 +1,8 @@ +package dev.slne.surf.roleplay.mod.common.network.protocol.listener.login + +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.PacketListener +import dev.slne.surf.roleplay.mod.common.network.protocol.serverbound.ServerboundHandshakePacket + +interface ServerLoginPacketListener : PacketListener.LoginPacketListener { + fun handleHandshake(packet: ServerboundHandshakePacket) +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/listener/packet/BasePacketHandler.kt b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/listener/packet/BasePacketHandler.kt new file mode 100644 index 0000000..b59c2fa --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/listener/packet/BasePacketHandler.kt @@ -0,0 +1,31 @@ +package dev.slne.surf.roleplay.mod.common.network.protocol.listener.packet + +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.PacketListener +import dev.slne.surf.surfapi.core.api.util.logger +import me.mrnavastar.protoweaver.api.ProtoConnectionHandler +import me.mrnavastar.protoweaver.api.netty.ProtoConnection +import java.util.concurrent.ConcurrentHashMap + +abstract class BasePacketHandler

( + private val packetListenerFactory: (ProtoConnection) -> P +) : ProtoConnectionHandler { + + private val log = logger() + + private val _handlers = ConcurrentHashMap() + protected val handlers get() = _handlers.toMap() + + fun getHandlerOrThrow(connection: ProtoConnection) = + _handlers[connection] ?: error("Unknown connection type: ${connection.remoteAddress}") + + override fun onReady(connection: ProtoConnection) { + log.atInfo().log("New connection from ${connection.remoteAddress}") + _handlers[connection] = packetListenerFactory(connection) + } + + override fun onDisconnect(connection: ProtoConnection) { + log.atInfo().log("Connection from ${connection.remoteAddress} disconnected") + + _handlers.remove(connection) + } +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/listener/packet/login/ClientLoginPacketHandler.kt b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/listener/packet/login/ClientLoginPacketHandler.kt new file mode 100644 index 0000000..02e182d --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/listener/packet/login/ClientLoginPacketHandler.kt @@ -0,0 +1,19 @@ +package dev.slne.surf.roleplay.mod.common.network.protocol.listener.packet.login + +import dev.slne.surf.roleplay.mod.common.network.NetworkBridge +import dev.slne.surf.roleplay.mod.common.network.packet.login.ClientboundRoleplayLoginPacket +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.login.ClientLoginPacketListener +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.packet.BasePacketHandler +import me.mrnavastar.protoweaver.api.netty.ProtoConnection + +class ClientLoginPacketHandler : BasePacketHandler( + { NetworkBridge.createClientLoginPacketHandler(it) } +) { + override fun handlePacket(connection: ProtoConnection, packet: Any) { + val handler = getHandlerOrThrow(connection) + + if (packet is ClientboundRoleplayLoginPacket) { + packet.handle(handler) + } + } +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/serverbound/ServerboundHandshakePacket.kt b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/serverbound/ServerboundHandshakePacket.kt new file mode 100644 index 0000000..423cccf --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/protocol/serverbound/ServerboundHandshakePacket.kt @@ -0,0 +1,18 @@ +package dev.slne.surf.roleplay.mod.common.network.protocol.serverbound + +import dev.slne.surf.roleplay.mod.common.network.SurfRoleplayPacket +import dev.slne.surf.roleplay.mod.common.network.packet.login.ServerboundRoleplayLoginPacket +import dev.slne.surf.roleplay.mod.common.network.protocol.DefaultIds +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.login.ServerLoginPacketListener +import java.util.* + +@SurfRoleplayPacket(id = DefaultIds.SERVERBOUND_HANDSHAKE) +class ServerboundHandshakePacket( + val handshake: UUID, + val uuid: UUID, + val clientVersion: String, +) : ServerboundRoleplayLoginPacket { + override fun handle(listener: ServerLoginPacketListener) { + listener.handleHandshake(this) + } +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/user/ProtoUser.kt b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/user/ProtoUser.kt new file mode 100644 index 0000000..d5f12b1 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/user/ProtoUser.kt @@ -0,0 +1,11 @@ +package dev.slne.surf.roleplay.mod.common.network.user + +import me.mrnavastar.protoweaver.api.netty.ProtoConnection +import java.util.* + +abstract class ProtoUser( + val uuid: UUID, +) { + abstract val connection: ProtoConnection + +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/user/ProtoUserManager.kt b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/user/ProtoUserManager.kt new file mode 100644 index 0000000..b439c09 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/user/ProtoUserManager.kt @@ -0,0 +1,27 @@ +package dev.slne.surf.roleplay.mod.common.network.user + +import com.github.benmanes.caffeine.cache.Caffeine +import dev.slne.surf.surfapi.core.api.util.requiredService +import me.mrnavastar.protoweaver.api.netty.ProtoConnection +import java.util.* + +val userManager = requiredService() + +abstract class ProtoUserManager { + private val users = Caffeine.newBuilder() + .build() + + + fun init(uuid: UUID, connection: ProtoConnection) { + users.put(uuid, createUser(uuid, connection)) + } + + fun destroy(uuid: UUID) { + users.invalidate(uuid) + } + + protected abstract fun createUser(uuid: UUID, connection: ProtoConnection): ProtoUser + + operator fun get(uuid: UUID): ProtoUser = + users.getIfPresent(uuid) ?: error("No user exists for $uuid") +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/utils/RoleplayPacketHandler.kt b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/utils/RoleplayPacketHandler.kt new file mode 100644 index 0000000..3702f67 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/utils/RoleplayPacketHandler.kt @@ -0,0 +1,5 @@ +package dev.slne.surf.roleplay.mod.common.network.utils + +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.FUNCTION) +annotation class RoleplayPacketHandler() diff --git a/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/utils/RoleplayPacketListener.kt b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/utils/RoleplayPacketListener.kt new file mode 100644 index 0000000..a4e9dac --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-common/src/main/kotlin/dev/slne/surf/roleplay/mod/common/network/utils/RoleplayPacketListener.kt @@ -0,0 +1,3 @@ +package dev.slne.surf.roleplay.mod.common.network.utils + +interface RoleplayPacketListener \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-server/build.gradle.kts b/surf-roleplay-mod/surf-roleplay-mod-server/build.gradle.kts new file mode 100644 index 0000000..b579e25 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-server/build.gradle.kts @@ -0,0 +1,29 @@ +import dev.slne.surf.surfapi.gradle.util.registerRequired +import dev.slne.surf.surfapi.gradle.util.withSurfApiBukkit + +plugins { + id("dev.slne.surf.surfapi.gradle.paper-plugin") +} + +surfPaperPluginApi { + mainClass("dev.slne.surf.roleplay.mod.server.ModServer") + foliaSupported(true) + generateLibraryLoader(false) + + serverDependencies { + registerRequired("ProtoWeaver") + } + + runServer { + withSurfApiBukkit() + + downloadPlugins { + modrinth("protoweaver", "FUBheaaQ") + } + } +} + +dependencies { + api(project(":surf-roleplay-mod:surf-roleplay-mod-common")) + compileOnlyApi(libs.protoweaver.paper) +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/ModServer.kt b/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/ModServer.kt new file mode 100644 index 0000000..e13a86e --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/ModServer.kt @@ -0,0 +1,17 @@ +package dev.slne.surf.roleplay.mod.server + +import com.github.shynixn.mccoroutine.folia.SuspendingJavaPlugin +import dev.slne.surf.roleplay.mod.server.listener.ListenerManager +import org.bukkit.plugin.java.JavaPlugin + +val plugin get() = JavaPlugin.getPlugin(ModServer::class.java) + +class ModServer : SuspendingJavaPlugin() { + + override suspend fun onEnableAsync() { + ListenerManager.register() + } + + override suspend fun onDisableAsync() { + } +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/listener/ListenerManager.kt b/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/listener/ListenerManager.kt new file mode 100644 index 0000000..3541e5f --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/listener/ListenerManager.kt @@ -0,0 +1,8 @@ +package dev.slne.surf.roleplay.mod.server.listener + +object ListenerManager { + + fun register() { + } + +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/network/ServerLoginPacketHandler.kt b/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/network/ServerLoginPacketHandler.kt new file mode 100644 index 0000000..ddbc171 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/network/ServerLoginPacketHandler.kt @@ -0,0 +1,24 @@ +package dev.slne.surf.roleplay.mod.server.network + +import dev.slne.surf.roleplay.mod.common.network.packet.login.ServerboundRoleplayLoginPacket +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.packet.BasePacketHandler +import dev.slne.surf.roleplay.mod.server.network.listener.ServerLoginPacketListenerImpl +import me.mrnavastar.protoweaver.api.netty.ProtoConnection + +class ServerLoginPacketHandler : BasePacketHandler( + { ServerLoginPacketListenerImpl(it) } +) { + + override fun onReady(connection: ProtoConnection) { + super.onReady(connection) + getHandlerOrThrow(connection).startVerifying() + } + + override fun handlePacket(connection: ProtoConnection, packet: Any) { + val handler = getHandlerOrThrow(connection) + + if (packet is ServerboundRoleplayLoginPacket) { + packet.handle(handler) + } + } +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/network/ServerNetworkBridgeImpl.kt b/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/network/ServerNetworkBridgeImpl.kt new file mode 100644 index 0000000..e87c499 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/network/ServerNetworkBridgeImpl.kt @@ -0,0 +1,21 @@ +package dev.slne.surf.roleplay.mod.server.network + +import com.google.auto.service.AutoService +import dev.slne.surf.roleplay.mod.common.network.NetworkBridge +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.login.ClientLoginPacketListener +import dev.slne.surf.roleplay.mod.server.network.listener.ServerLoginPacketListenerImpl +import me.mrnavastar.protoweaver.api.netty.ProtoConnection + +@AutoService(NetworkBridge::class) +class ServerNetworkBridgeImpl : NetworkBridge { + + override val serverLoginPacketHandlerClass = ServerLoginPacketHandler::class.java + override val clientLoginPacketHandlerClass = null + + override fun createServerLoginPacketHandler(connection: ProtoConnection) = + ServerLoginPacketListenerImpl(connection) + + override fun createClientLoginPacketHandler(connection: ProtoConnection): ClientLoginPacketListener { + error("Client login packet handler is not implemented on the server side") + } +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/network/listener/ServerLoginPacketListenerImpl.kt b/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/network/listener/ServerLoginPacketListenerImpl.kt new file mode 100644 index 0000000..6544b36 --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/network/listener/ServerLoginPacketListenerImpl.kt @@ -0,0 +1,44 @@ +package dev.slne.surf.roleplay.mod.server.network.listener + +import dev.slne.surf.roleplay.mod.common.network.protocol.clientbound.ClientboundHandshakePacket +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.TickablePacketListener +import dev.slne.surf.roleplay.mod.common.network.protocol.listener.login.ServerLoginPacketListener +import dev.slne.surf.roleplay.mod.common.network.protocol.serverbound.ServerboundHandshakePacket +import dev.slne.surf.roleplay.mod.common.network.user.userManager +import me.mrnavastar.protoweaver.api.netty.ProtoConnection +import java.util.* + +class ServerLoginPacketListenerImpl(val connection: ProtoConnection) : ServerLoginPacketListener, + TickablePacketListener { + + private var loginTime: Int = 0 + private val handshake = UUID.randomUUID() + + fun startVerifying() { + connection.send(ClientboundHandshakePacket(handshake)) + } + + override fun tick() { + if (loginTime++ >= LOGIN_TIMEOUT) { + disconnect("Login timeout") + } + } + + override fun handleHandshake(packet: ServerboundHandshakePacket) { + if (packet.handshake != handshake) { + disconnect("Handshake mismatch") + return + } + + + userManager.init(packet.uuid, connection) + } + + private fun disconnect(reason: String) { + + } + + companion object { + const val LOGIN_TIMEOUT = 30 // seconds + } +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/network/user/ServerProtoUser.kt b/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/network/user/ServerProtoUser.kt new file mode 100644 index 0000000..45c50ac --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/network/user/ServerProtoUser.kt @@ -0,0 +1,8 @@ +package dev.slne.surf.roleplay.mod.server.network.user + +import dev.slne.surf.roleplay.mod.common.network.user.ProtoUser +import me.mrnavastar.protoweaver.api.netty.ProtoConnection +import java.util.* + +class ServerProtoUser(uuid: UUID, override val connection: ProtoConnection) : ProtoUser(uuid) { +} \ No newline at end of file diff --git a/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/network/user/ServerProtoUserManager.kt b/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/network/user/ServerProtoUserManager.kt new file mode 100644 index 0000000..59adc7e --- /dev/null +++ b/surf-roleplay-mod/surf-roleplay-mod-server/src/main/kotlin/dev/slne/surf/roleplay/mod/server/network/user/ServerProtoUserManager.kt @@ -0,0 +1,14 @@ +package dev.slne.surf.roleplay.mod.server.network.user + +import com.google.auto.service.AutoService +import dev.slne.surf.roleplay.mod.common.network.user.ProtoUserManager +import me.mrnavastar.protoweaver.api.netty.ProtoConnection +import java.util.* + +@AutoService(ProtoUserManager::class) +class ServerProtoUserManager : ProtoUserManager() { + override fun createUser( + uuid: UUID, + connection: ProtoConnection + ) = ServerProtoUser(uuid, connection) +} \ No newline at end of file diff --git a/surf-roleplay-paper/build.gradle.kts b/surf-roleplay-paper/build.gradle.kts index 2d2bf72..907e4d8 100644 --- a/surf-roleplay-paper/build.gradle.kts +++ b/surf-roleplay-paper/build.gradle.kts @@ -1,41 +1,26 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import dev.slne.surf.surfapi.gradle.util.registerRequired -import dev.slne.surf.surfapi.gradle.util.withSurfApiBukkit plugins { id("dev.slne.surf.surfapi.gradle.paper-plugin") } -dependencies { - api(project(":surf-roleplay-core")) - api(project(":surf-roleplay-mechanic")) - - runtimeOnly(libs.surf.database) -} - surfPaperPluginApi { - mainClass("dev.slne.surf.roleplay.paper.SurfRoleplay") - generateLibraryLoader(false) - authors.add("Ammo") + withCloudClientPaper() + mainClass("dev.slne.surf.roleplay.paper.PaperMain") foliaSupported(true) serverDependencies { registerRequired("surf-npc-bukkit") } +} - runServer { - withSurfApiBukkit() +dependencies { + api(project(":surf-roleplay-core:surf-roleplay-core-common")) - val npcVersion = - libs.surf.npc.api.get().version ?: error("NPC API version is not specified") - val npcAsset = "surf-npc-bukkit-${npcVersion}.jar" + compileOnly(libs.surf.npc.api) +} - downloadPlugins { - github( - "slne-development", - "surf-npc", - "v$npcVersion", - npcAsset - ) - } - } +tasks.withType { + destinationDirectory.set(rootProject.file("output")) } \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/PaperBootstrap.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/PaperBootstrap.kt new file mode 100644 index 0000000..2a025b2 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/PaperBootstrap.kt @@ -0,0 +1,15 @@ +package dev.slne.surf.roleplay.paper + +import dev.slne.surf.cloud.api.common.CloudInstance +import dev.slne.surf.cloud.api.common.startSpringApplication +import dev.slne.surf.roleplay.RoleplayApplication +import io.papermc.paper.plugin.bootstrap.BootstrapContext +import io.papermc.paper.plugin.bootstrap.PluginBootstrap + +@Suppress("UnstableApiUsage") +class PaperBootstrap : PluginBootstrap { + override fun bootstrap(context: BootstrapContext) { + RoleplayApplication.context = + CloudInstance.startSpringApplication(RoleplayApplication::class) + } +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/PaperMain.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/PaperMain.kt new file mode 100644 index 0000000..4cb1984 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/PaperMain.kt @@ -0,0 +1,31 @@ +package dev.slne.surf.roleplay.paper + +import com.github.shynixn.mccoroutine.folia.SuspendingJavaPlugin +import dev.slne.surf.roleplay.RoleplayApplication +import dev.slne.surf.roleplay.core.common.RpInstance +import dev.slne.surf.roleplay.paper.command.activeIdentityCommand +import dev.slne.surf.roleplay.paper.command.balanceCommand +import org.bukkit.plugin.java.JavaPlugin +import org.springframework.beans.factory.getBean + +class PaperMain : SuspendingJavaPlugin() { + private val rpInstance get() = RoleplayApplication.context.getBean() + + override suspend fun onLoadAsync() { + rpInstance.onLoad() + + balanceCommand() + activeIdentityCommand() + } + + override suspend fun onEnableAsync() { + rpInstance.onEnable() + } + + override suspend fun onDisableAsync() { + rpInstance.onDisable() + } + +} + +val plugin get() = JavaPlugin.getPlugin(PaperMain::class.java) \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/SurfRoleplay.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/SurfRoleplay.kt index 96e7e53..dcb75d2 100644 --- a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/SurfRoleplay.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/SurfRoleplay.kt @@ -1,185 +1,41 @@ package dev.slne.surf.roleplay.paper -import com.github.shynixn.mccoroutine.folia.SuspendingJavaPlugin -import com.github.shynixn.mccoroutine.folia.launch -import dev.jorel.commandapi.kotlindsl.* -import dev.slne.surf.roleplay.api.player.rpPlayer -import dev.slne.surf.roleplay.api.player.utils.BalanceType -import dev.slne.surf.roleplay.core.RpCore -import dev.slne.surf.roleplay.core.RpDatabase -import dev.slne.surf.roleplay.core.player.license.licenseServiceImpl -import dev.slne.surf.roleplay.mechanic.mechanicRegistryImpl -import dev.slne.surf.roleplay.paper.command.args.balanceTypeArgument -import dev.slne.surf.roleplay.paper.listeners.ListenerManager -import dev.slne.surf.surfapi.core.api.messages.adventure.sendText -import org.bukkit.entity.Player -import org.bukkit.plugin.java.JavaPlugin - -val plugin get() = JavaPlugin.getPlugin(SurfRoleplay::class.java) - -class SurfRoleplay : SuspendingJavaPlugin() { - - private lateinit var rpDatabase: RpDatabase - - override suspend fun onLoadAsync() { - RpCore.plugin = this - rpDatabase = RpDatabase(dataPath) - - mechanicRegistryImpl.registerMechanics(this) - mechanicRegistryImpl.registerDatabaseTables(rpDatabase) - - licenseServiceImpl.onLoad() - - rpDatabase.onLoad() - - mechanicRegistryImpl.loadMechanics() - } - - override suspend fun onEnableAsync() { - ListenerManager.registerListeners() - - mechanicRegistryImpl.enableMechanics() - mechanicRegistryImpl.registerBukkitHandlers() - - licenseServiceImpl.onEnable() - - commandAPICommand("balance") { - subcommand("get") { - balanceTypeArgument("balanceType") - entitySelectorArgumentOnePlayer("player") - - playerExecutor { sender, args -> - val player: Player by args - val balanceType: BalanceType by args - - plugin.launch { - val rpPlayer = player.rpPlayer() - val balance = rpPlayer.getBalance(balanceType) - - sender.sendText { - appendPrefix() - - info("Der Kontostand von ") - append(rpPlayer) - info(" beträgt: ") - variableValue(balance) - info(".") - } - } - } - } - - subcommand("set") { - balanceTypeArgument("balanceType") - entitySelectorArgumentOnePlayer("player") - integerArgument("amount") - - playerExecutor { sender, args -> - val player: Player by args - val balanceType: BalanceType by args - val amount: Int by args - - plugin.launch { - val rpPlayer = player.rpPlayer() - val currentAmount = rpPlayer.getBalance(balanceType) - - rpPlayer.removeBalance(balanceType, currentAmount) - rpPlayer.addBalance(balanceType, amount) - - sender.sendText { - appendPrefix() - - info("Der Kontostand von ") - append(rpPlayer) - info(" wurde auf ") - variableValue(amount) - info(" gesetzt.") - } - } - } - } - - subcommand("add") { - balanceTypeArgument("balanceType") - entitySelectorArgumentOnePlayer("player") - integerArgument("amount") - - playerExecutor { sender, args -> - val player: Player by args - val balanceType: BalanceType by args - val amount: Int by args - - plugin.launch { - val rpPlayer = player.rpPlayer() - rpPlayer.addBalance(balanceType, amount) - - sender.sendText { - appendPrefix() - - info("Der Kontostand von ") - append(rpPlayer) - info(" wurde um ") - variableValue(amount) - info(" erhöht.") - } - } - } - } - - subcommand("remove") { - balanceTypeArgument("balanceType") - entitySelectorArgumentOnePlayer("player") - integerArgument("amount") - - playerExecutor { sender, args -> - val player: Player by args - val balanceType: BalanceType by args - val amount: Int by args - - plugin.launch { - val rpPlayer = player.rpPlayer() - rpPlayer.removeBalance(balanceType, amount) - - sender.sendText { - appendPrefix() - - info("Der Kontostand von ") - append(rpPlayer) - info(" wurde um ") - variableValue(amount) - info(" verringert.") - } - } - } - } - } - - commandAPICommand("active-identity") { - playerExecutor { player, args -> - plugin.launch { - val rpPlayer = player.rpPlayer() - val activeIdentity = rpPlayer.activeIdentity - - player.sendText { - appendPrefix() - - info("Deine aktive Identität: ") - if (activeIdentity != null) { - append(activeIdentity.type) - } else { - variableValue("Keine aktive Identität gesetzt") - } - } - } - } - } - } - - override suspend fun onDisableAsync() { - licenseServiceImpl.onDisable() - mechanicRegistryImpl.disableMechanics() - - rpDatabase.onDisable() - } - -} \ No newline at end of file +//val plugin get() = JavaPlugin.getPlugin(SurfRoleplay::class.java) +// +//class SurfRoleplay : SuspendingJavaPlugin() { +// +// private lateinit var rpDatabase: RpDatabase +// +// override suspend fun onLoadAsync() { +// RpCore.plugin = this +// rpDatabase = RpDatabase(dataPath) +// +// mechanicRegistryImpl.registerMechanics(this) +// mechanicRegistryImpl.registerDatabaseTables(rpDatabase) +// +// licenseServiceImpl.onLoad() +// +// rpDatabase.onLoad() +// +// mechanicRegistryImpl.loadMechanics() +// } +// +// override suspend fun onEnableAsync() { +// ListenerManager.registerListeners() +// +// mechanicRegistryImpl.enableMechanics() +// mechanicRegistryImpl.registerBukkitHandlers() +// +// licenseServiceImpl.onEnable() +// +// +// } +// +// override suspend fun onDisableAsync() { +// licenseServiceImpl.onDisable() +// mechanicRegistryImpl.disableMechanics() +// +// rpDatabase.onDisable() +// } +// +//} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/command/ActiveIdentityCommand.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/command/ActiveIdentityCommand.kt new file mode 100644 index 0000000..76abd41 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/command/ActiveIdentityCommand.kt @@ -0,0 +1,24 @@ +package dev.slne.surf.roleplay.paper.command + +import dev.jorel.commandapi.kotlindsl.commandAPICommand +import dev.jorel.commandapi.kotlindsl.playerExecutor +import dev.slne.surf.roleplay.paper.player.rpPlayer +import dev.slne.surf.surfapi.core.api.messages.adventure.sendText + +fun activeIdentityCommand() = commandAPICommand("active-identity") { + playerExecutor { player, args -> + val rpPlayer = player.rpPlayer + val activeIdentity = rpPlayer.activeIdentity + + player.sendText { + appendPrefix() + + info("Deine aktive Identität: ") + if (activeIdentity != null) { + append(activeIdentity.type) + } else { + variableValue("Keine aktive Identität gesetzt") + } + } + } +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/command/BalanceCommand.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/command/BalanceCommand.kt new file mode 100644 index 0000000..31e3069 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/command/BalanceCommand.kt @@ -0,0 +1,121 @@ +package dev.slne.surf.roleplay.paper.command + +import com.github.shynixn.mccoroutine.folia.launch +import dev.jorel.commandapi.kotlindsl.* +import dev.slne.surf.roleplay.core.common.transaction.utils.BalanceType +import dev.slne.surf.roleplay.paper.command.args.balanceTypeArgument +import dev.slne.surf.roleplay.paper.player.rpPlayer +import dev.slne.surf.roleplay.paper.plugin +import dev.slne.surf.surfapi.core.api.messages.adventure.sendText +import org.bukkit.entity.Player + +fun balanceCommand() = commandAPICommand("balance") { + subcommand("get") { + balanceTypeArgument("balanceType") + entitySelectorArgumentOnePlayer("player") + + playerExecutor { sender, args -> + val player: Player by args + val balanceType: BalanceType by args + + plugin.launch { + val rpPlayer = player.rpPlayer + val balance = rpPlayer.getBalance(balanceType) + + sender.sendText { + appendPrefix() + + info("Der Kontostand von ") + append(rpPlayer.asComponent()) + info(" beträgt: ") + variableValue(balance) + info(".") + } + } + } + } + + subcommand("set") { + balanceTypeArgument("balanceType") + entitySelectorArgumentOnePlayer("player") + integerArgument("amount") + + playerExecutor { sender, args -> + val player: Player by args + val balanceType: BalanceType by args + val amount: Int by args + + plugin.launch { + val rpPlayer = player.rpPlayer + val currentAmount = rpPlayer.getBalance(balanceType) + + rpPlayer.removeBalance(balanceType, currentAmount) + rpPlayer.addBalance(balanceType, amount) + + sender.sendText { + appendPrefix() + + info("Der Kontostand von ") + append(rpPlayer.asComponent()) + info(" wurde auf ") + variableValue(amount) + info(" gesetzt.") + } + } + } + } + + subcommand("add") { + balanceTypeArgument("balanceType") + entitySelectorArgumentOnePlayer("player") + integerArgument("amount") + + playerExecutor { sender, args -> + val player: Player by args + val balanceType: BalanceType by args + val amount: Int by args + + plugin.launch { + val rpPlayer = player.rpPlayer + rpPlayer.addBalance(balanceType, amount) + + sender.sendText { + appendPrefix() + + info("Der Kontostand von ") + append(rpPlayer.asComponent()) + info(" wurde um ") + variableValue(amount) + info(" erhöht.") + } + } + } + } + + subcommand("remove") { + balanceTypeArgument("balanceType") + entitySelectorArgumentOnePlayer("player") + integerArgument("amount") + + playerExecutor { sender, args -> + val player: Player by args + val balanceType: BalanceType by args + val amount: Int by args + + plugin.launch { + val rpPlayer = player.rpPlayer + rpPlayer.removeBalance(balanceType, amount) + + sender.sendText { + appendPrefix() + + info("Der Kontostand von ") + append(rpPlayer.asComponent()) + info(" wurde um ") + variableValue(amount) + info(" verringert.") + } + } + } + } +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/command/args/BalanceTypeArgument.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/command/args/BalanceTypeArgument.kt index 0139d07..394924c 100644 --- a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/command/args/BalanceTypeArgument.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/command/args/BalanceTypeArgument.kt @@ -5,7 +5,7 @@ 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.roleplay.api.player.utils.BalanceType +import dev.slne.surf.roleplay.core.common.transaction.utils.BalanceType class BalanceTypeArgument(nodeName: String) : CustomArgument( StringArgument(nodeName), @@ -24,7 +24,5 @@ inline fun CommandAPICommand.balanceTypeArgument( nodeName: String, optional: Boolean = false, block: Argument<*>.() -> Unit = {} -) = withArguments(BalanceTypeArgument(nodeName).apply { - isOptional = optional - block() -}) \ No newline at end of file +): CommandAPICommand = + withArguments(BalanceTypeArgument(nodeName).setOptional(optional).apply(block)) \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/identity/listener/IdentityOnlineListener.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/identity/listener/IdentityOnlineListener.kt deleted file mode 100644 index f14e3a9..0000000 --- a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/identity/listener/IdentityOnlineListener.kt +++ /dev/null @@ -1,33 +0,0 @@ -package dev.slne.surf.roleplay.paper.identity.listener - -import com.github.shynixn.mccoroutine.folia.launch -import dev.slne.surf.roleplay.api.player.events.RpPlayerJoinEvent -import dev.slne.surf.roleplay.paper.identity.dialogs.createIdentitySelectorDialog -import dev.slne.surf.roleplay.paper.plugin -import org.bukkit.event.EventHandler -import org.bukkit.event.EventPriority -import org.bukkit.event.Listener - -object IdentityOnlineListener : Listener { - - @EventHandler(priority = EventPriority.LOWEST) - fun onRpPlayerJoin(event: RpPlayerJoinEvent) { - plugin.launch { - val player = event.rpPlayer - val identities = player.identities - - if (identities.isEmpty()) { - return@launch - } - - if (identities.size == 1) { - val identity = identities.first() - player.setActiveIdentity(identity) - - return@launch - } - - player.bukkitPlayer?.showDialog(createIdentitySelectorDialog(player)) - } - } -} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/listeners/ListenerManager.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/listener/ListenerManager.kt similarity index 84% rename from surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/listeners/ListenerManager.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/listener/ListenerManager.kt index 26b821f..b5357b1 100644 --- a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/listeners/ListenerManager.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/listener/ListenerManager.kt @@ -1,10 +1,8 @@ @file:Suppress("UnstableApiUsage") -package dev.slne.surf.roleplay.paper.listeners +package dev.slne.surf.roleplay.paper.listener -import com.github.retrooper.packetevents.PacketEvents import com.github.retrooper.packetevents.event.PacketListener -import com.github.retrooper.packetevents.event.PacketListenerPriority import com.github.retrooper.packetevents.event.PacketSendEvent import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes import com.github.retrooper.packetevents.protocol.packettype.PacketType @@ -16,10 +14,10 @@ import com.github.shynixn.mccoroutine.folia.launch import com.github.shynixn.mccoroutine.folia.regionDispatcher import dev.jorel.commandapi.kotlindsl.commandAPICommand import dev.jorel.commandapi.kotlindsl.playerExecutor -import dev.slne.surf.roleplay.paper.identity.listener.IdentityOnlineListener +import dev.slne.surf.cloud.api.common.util.objectSetOf import dev.slne.surf.roleplay.paper.plugin +import dev.slne.surf.roleplay.paper.spring.RpPacketListener import dev.slne.surf.surfapi.bukkit.api.builder.ItemStack -import dev.slne.surf.surfapi.bukkit.api.event.register import dev.slne.surf.surfapi.core.api.messages.adventure.playSound import io.papermc.paper.datacomponent.DataComponentTypes import io.papermc.paper.datacomponent.item.Consumable @@ -34,19 +32,12 @@ import org.bukkit.event.EventHandler import org.bukkit.event.Listener import org.bukkit.event.entity.ProjectileHitEvent import org.bukkit.event.entity.ProjectileLaunchEvent +import org.springframework.stereotype.Component -object ListenerManager : Listener { +@Component +class ListenerManager : Listener { fun registerListeners() { - OnlineListener.register() - IdentityOnlineListener.register() - register() - - PacketEvents.getAPI().eventManager.registerListener( - ArrowHitListener, - PacketListenerPriority.LOWEST - ) - commandAPICommand("give-bow") { playerExecutor { player, arguments -> player.inventory.addItem(ItemStack(Material.BOW) { @@ -70,7 +61,14 @@ object ListenerManager : Listener { } } - object ArrowHitListener : PacketListener { + @RpPacketListener + class ArrowHitListener : PacketListener { + private val blockSounds = objectSetOf( + Sounds.ENTITY_ARROW_HIT, + Sounds.ENTITY_ARROW_SHOOT, + Sounds.ENTITY_ARROW_SHOOT + ) + override fun onPacketSend(event: PacketSendEvent) { if (event.packetType == PacketType.Play.Server.SPAWN_ENTITY) { val packet = WrapperPlayServerSpawnEntity(event) @@ -79,18 +77,10 @@ object ListenerManager : Listener { if (type == EntityTypes.ARROW) { event.isCancelled = true } - } - - if (event.packetType == PacketType.Play.Server.SOUND_EFFECT) { + } else if (event.packetType == PacketType.Play.Server.SOUND_EFFECT) { val packet = WrapperPlayServerSoundEffect(event) val sound = packet.sound - val blockSounds = setOf( - Sounds.ENTITY_ARROW_HIT, - Sounds.ENTITY_ARROW_SHOOT, - Sounds.ENTITY_ARROW_SHOOT - ) - if (sound in blockSounds) { event.isCancelled = true } diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/listener/OnlineListener.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/listener/OnlineListener.kt new file mode 100644 index 0000000..b66f744 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/listener/OnlineListener.kt @@ -0,0 +1,35 @@ +package dev.slne.surf.roleplay.paper.listener + +import dev.slne.surf.roleplay.paper.player.events.RpPlayerDeathEvent +import dev.slne.surf.roleplay.paper.player.events.RpPlayerJoinEvent +import dev.slne.surf.roleplay.paper.player.events.RpPlayerQuitEvent +import dev.slne.surf.roleplay.paper.player.rpPlayer +import org.bukkit.event.EventHandler +import org.bukkit.event.EventPriority +import org.bukkit.event.Listener +import org.bukkit.event.entity.PlayerDeathEvent +import org.bukkit.event.player.PlayerJoinEvent +import org.bukkit.event.player.PlayerQuitEvent +import org.springframework.stereotype.Component + +@Component +class OnlineListener : Listener { + + @EventHandler + fun onJoin(event: PlayerJoinEvent) { + val player = event.player.rpPlayer + RpPlayerJoinEvent(this, player).postAndForget() + } + + @EventHandler + fun onQuit(event: PlayerQuitEvent) { + val player = event.player.rpPlayer + RpPlayerQuitEvent(this, player).postAndForget() + } + + @EventHandler(priority = EventPriority.HIGHEST) + fun onPlayerDeath(event: PlayerDeathEvent) { + val player = event.player.rpPlayer + RpPlayerDeathEvent(this, player, event).postAndForget() + } +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/listeners/OnlineListener.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/listeners/OnlineListener.kt deleted file mode 100644 index 75cfffd..0000000 --- a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/listeners/OnlineListener.kt +++ /dev/null @@ -1,55 +0,0 @@ -package dev.slne.surf.roleplay.paper.listeners - -import com.github.shynixn.mccoroutine.folia.globalRegionDispatcher -import com.github.shynixn.mccoroutine.folia.launch -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.events.RpPlayerDeathEvent -import dev.slne.surf.roleplay.api.player.events.RpPlayerJoinEvent -import dev.slne.surf.roleplay.api.player.events.RpPlayerQuitEvent -import dev.slne.surf.roleplay.core.player.rpPlayerManagerImpl -import dev.slne.surf.roleplay.paper.plugin -import kotlinx.coroutines.withContext -import org.bukkit.event.EventHandler -import org.bukkit.event.EventPriority -import org.bukkit.event.Listener -import org.bukkit.event.entity.PlayerDeathEvent -import org.bukkit.event.player.PlayerJoinEvent -import org.bukkit.event.player.PlayerQuitEvent - -object OnlineListener : Listener { - - @EventHandler(priority = EventPriority.LOWEST) - fun onJoin(event: PlayerJoinEvent) { - plugin.launch { - val player = RpPlayer[event.player.uniqueId] - - player.updateUsername(event.player.name) - - withContext(plugin.globalRegionDispatcher) { - RpPlayerJoinEvent(player).callEvent() - } - } - } - - @EventHandler(priority = EventPriority.MONITOR) - fun onQuit(event: PlayerQuitEvent) { - plugin.launch { - val player = RpPlayer[event.player.uniqueId] - - withContext(plugin.globalRegionDispatcher) { - RpPlayerQuitEvent(player).callEvent() - - rpPlayerManagerImpl.onDisconnect(player) - } - } - } - - @EventHandler(priority = EventPriority.MONITOR) - fun onPlayerDeath(event: PlayerDeathEvent) { - plugin.launch { - withContext(plugin.globalRegionDispatcher) { - RpPlayerDeathEvent(RpPlayer[event.player.uniqueId], event).callEvent() - } - } - } -} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/AbstractMechanic.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/AbstractMechanic.kt new file mode 100644 index 0000000..1197d0a --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/AbstractMechanic.kt @@ -0,0 +1,11 @@ +package dev.slne.surf.roleplay.paper.mechanics + +import dev.slne.surf.roleplay.core.common.RpLifecycle + +abstract class AbstractMechanic : RpLifecycle { + private val annotation by lazy { + javaClass.getAnnotation(Mechanic::class.java) ?: error("@Mechanic annotation is missing!") + } + + val name by lazy { annotation.name } +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/Mechanic.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/Mechanic.kt new file mode 100644 index 0000000..51c5a42 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/Mechanic.kt @@ -0,0 +1,8 @@ +package dev.slne.surf.roleplay.paper.mechanics + +import org.springframework.stereotype.Component + +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.CLASS) +@Component +annotation class Mechanic(val name: String) diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/idcard/IdCard.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/idcard/IdCard.kt similarity index 65% rename from surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/idcard/IdCard.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/idcard/IdCard.kt index 7e177f1..cdf2908 100644 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/idcard/IdCard.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/idcard/IdCard.kt @@ -1,6 +1,6 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.idcard +package dev.slne.surf.roleplay.paper.mechanics.idcard -import dev.slne.surf.surfapi.bukkit.api.builder.ItemStack +import dev.slne.surf.surfapi.bukkit.api.builder.buildItem import dev.slne.surf.surfapi.bukkit.api.builder.buildLore import dev.slne.surf.surfapi.bukkit.api.builder.displayName import dev.slne.surf.surfapi.core.api.font.toSmallCaps @@ -10,30 +10,31 @@ import org.bukkit.persistence.PersistentDataType import java.time.LocalDate import java.time.format.DateTimeFormatter - object IdCard { internal val formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy") val idCardKey = NamespacedKey("surf-roleplay-mechanic", "id_card") - fun idCard(firstName: String, lastName: String, birthDate: LocalDate) = ItemStack(Material.FEATHER) { - displayName { - primary("Personalausweis") - } + fun idCard( + firstName: String, + lastName: String, + birthDate: LocalDate + ) = buildItem(Material.FEATHER) { + displayName { primary("Personalausweis") } buildLore { line { - spacer(" - ") + spacer(" — ") variableKey("Vorname: ".toSmallCaps()) variableValue(firstName) } line { - spacer(" - ") - variableKey("nachname: ".toSmallCaps()) + spacer(" — ") + variableKey("Nachname: ".toSmallCaps()) variableValue(lastName) } line { - spacer(" - ") - variableKey("geburtsdatum: ".toSmallCaps()) + spacer(" — ") + variableKey("Geburtsdatum: ".toSmallCaps()) variableValue(formatter.format(birthDate)) } } diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/idcard/IdCardMechanic.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/idcard/IdCardMechanic.kt new file mode 100644 index 0000000..919ffa3 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/idcard/IdCardMechanic.kt @@ -0,0 +1,11 @@ +package dev.slne.surf.roleplay.paper.mechanics.idcard + +import dev.slne.surf.roleplay.paper.mechanics.AbstractMechanic +import dev.slne.surf.roleplay.paper.mechanics.Mechanic + +@Mechanic("IdCardMechanic") +class IdCardMechanic : AbstractMechanic() { + override suspend fun onEnable() { + IdCardNpc.spawnNpc() + } +} \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/idcard/IdCardNpc.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/idcard/IdCardNpc.kt similarity index 61% rename from surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/idcard/IdCardNpc.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/idcard/IdCardNpc.kt index 0a35e60..97e0596 100644 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/idcard/IdCardNpc.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/idcard/IdCardNpc.kt @@ -1,15 +1,18 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.idcard +package dev.slne.surf.roleplay.paper.mechanics.idcard import dev.slne.surf.npc.api.dsl.npc import dev.slne.surf.npc.api.surfNpcApi -import dev.slne.surf.roleplay.mechanic.plugin +import dev.slne.surf.roleplay.paper.plugin +import dev.slne.surf.surfapi.bukkit.api.extensions.server object IdCardNpc { + const val NPC_NAME = "idcard_npc" + suspend fun spawnNpc() { val npcSkin = surfNpcApi.getSkin("MikeyLLP") npc(plugin) { - uniqueName = IdCardMechanicImpl.NPC_NAME + uniqueName = NPC_NAME displayName = { primary("Bürgeramt") } @@ -17,7 +20,7 @@ object IdCardNpc { skin = npcSkin location { - world = "world" + world = server.worlds.first().name x = 2.0 y = 100.0 z = 0.0 diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/idcard/dialogs/CreateIdDialog.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/idcard/dialogs/CreateIdDialog.kt similarity index 72% rename from surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/idcard/dialogs/CreateIdDialog.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/idcard/dialogs/CreateIdDialog.kt index 32b1563..1ddce04 100644 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/idcard/dialogs/CreateIdDialog.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/idcard/dialogs/CreateIdDialog.kt @@ -1,13 +1,13 @@ @file:Suppress("UnstableApiUsage") @file:OptIn(NmsUseWithCaution::class) -package dev.slne.surf.roleplay.mechanic.mechanics.idcard.dialogs +package dev.slne.surf.roleplay.paper.mechanics.idcard.dialogs import com.github.shynixn.mccoroutine.folia.launch -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.core.player.identity.identities.CivilianIdentityImpl -import dev.slne.surf.roleplay.mechanic.mechanics.idcard.IdCard -import dev.slne.surf.roleplay.mechanic.plugin +import dev.slne.surf.roleplay.paper.mechanics.idcard.IdCard +import dev.slne.surf.roleplay.paper.player.identity.identities.CivilianIdentity +import dev.slne.surf.roleplay.paper.player.rpPlayer +import dev.slne.surf.roleplay.paper.plugin import dev.slne.surf.surfapi.bukkit.api.dialog.base import dev.slne.surf.surfapi.bukkit.api.dialog.builder.DialogBodyBuilder import dev.slne.surf.surfapi.bukkit.api.dialog.builder.actionButton @@ -15,16 +15,22 @@ import dev.slne.surf.surfapi.bukkit.api.dialog.clearDialogs import dev.slne.surf.surfapi.bukkit.api.dialog.dialog import dev.slne.surf.surfapi.bukkit.api.dialog.type import dev.slne.surf.surfapi.bukkit.api.nms.NmsUseWithCaution +import dev.slne.surf.surfapi.core.api.command.builder.CommandExceptionBuilder +import dev.slne.surf.surfapi.core.api.messages.adventure.appendNewline import io.papermc.paper.dialog.Dialog import io.papermc.paper.registry.data.dialog.ActionButton -import io.papermc.paper.registry.data.dialog.DialogBase +import io.papermc.paper.registry.data.dialog.DialogBase.DialogAfterAction import net.kyori.adventure.text.format.TextDecoration -import org.bukkit.entity.Player import java.time.LocalDate import java.time.Year +import java.time.format.DateTimeParseException -private val nameRegex = Regex("^[a-zA-ZÄÖÜäöüß]{3,16}") -private val nameRegexDashes = Regex("^[a-zA-ZÄÖÜäöüß-]{3,16}") +private val nameRegex = "^[a-zA-ZÄÖÜäöüß]{3,16}".toRegex() +private val nameRegexDashes = "^[a-zA-ZÄÖÜäöüß-]{3,16}".toRegex() + +private const val FIRST_NAME_INPUT = "first_name" +private const val LAST_NAME_INPUT = "last_name" +private const val BIRTH_DATE_INPUT = "birth_date" fun createIdDialog( firstName: String? = null, @@ -33,7 +39,7 @@ fun createIdDialog( ) = dialog { base { title { primary("Personalausweis beantragen") } - afterAction(DialogBase.DialogAfterAction.WAIT_FOR_RESPONSE) + afterAction(DialogAfterAction.WAIT_FOR_RESPONSE) body { plainMessage(400) { @@ -47,28 +53,26 @@ fun createIdDialog( } input { - text("first_name") { + text(FIRST_NAME_INPUT) { label { text("Vorname") } - firstName?.let { initial(it) } + initial = firstName maxLength(16) width(400) } - } - input { - text("last_name") { + + text(LAST_NAME_INPUT) { label { text("Nachname") } - lastName?.let { initial(it) } + initial = lastName maxLength(16) width(400) } - } - input { - text("birth_date") { + + text(BIRTH_DATE_INPUT) { label { text("Geburtsdatum ") spacer("[DD.MM.JJJJ]") } - birthDateString?.let { initial(it) } + initial = birthDateString maxLength(10) width(400) } @@ -87,21 +91,21 @@ private fun confirmCreationButton(): ActionButton = actionButton { } action { - customClick { info, audience -> - val player = audience as? Player ?: error("Audience is not a Player") - - val firstName = info.getText("first_name") ?: "" - val lastName = info.getText("last_name") ?: "" - val birthDateString = info.getText("birth_date") ?: "" + customPlayerClick { info, player -> + val firstName = info.getText(FIRST_NAME_INPUT) ?: "" + val lastName = info.getText(LAST_NAME_INPUT) ?: "" + val birthDateString = info.getText(BIRTH_DATE_INPUT) ?: "" val isValidFirstNameLength = firstName.matches(nameRegex) val isValidLastNameLength = lastName.matches(nameRegex) val isValidFirstName = firstName.matches(nameRegexDashes) val isValidLastName = lastName.matches(nameRegexDashes) - val isValidBirthDateString = validateDate(birthDateString) + val parsedBirthDate = runCatching { LocalDate.parse(birthDateString, IdCard.formatter) } + + val isValidBirthDateString = validateDate(parsedBirthDate) if (!isValidBirthDateString || !isValidFirstName || !isValidLastName || !isValidFirstNameLength || !isValidLastNameLength) { - audience.showDialog( + player.showDialog( invalidInputDialog( firstName, lastName, @@ -132,6 +136,16 @@ private fun confirmCreationButton(): ActionButton = actionButton { if (!isValidBirthDateString) { val now = LocalDate.now() val validYear = now.minusYears(100) + val exception = parsedBirthDate.exceptionOrNull() + val exceptionMessage = + if (exception != null && exception is DateTimeParseException) { + CommandExceptionBuilder( + exception.message, + exception.parsedString, + exception.errorIndex + ).build(null) + } else null + plainMessage(400) { error("Das angegebene Geburtsdatum ist ungültig. Bitte gib ein gültiges Datum im folgenden Format ein: ") variableValue("TT.MM.JJJJ") @@ -141,30 +155,31 @@ private fun confirmCreationButton(): ActionButton = actionButton { error(" und nicht nach ") variableValue(now.year) error(" liegen.") + + if (exceptionMessage != null) { + appendNewline(2) + append(exceptionMessage) + } } } } ) - return@customClick + return@customPlayerClick } - val birthDate = LocalDate.parse(birthDateString, IdCard.formatter) - plugin.launch { - val rpPlayer = RpPlayer[player.uniqueId] - + val rpPlayer = player.rpPlayer val identity = rpPlayer.createOrUpdateIdentity( - CivilianIdentityImpl( - player = rpPlayer, + CivilianIdentity( + uuid = player.uniqueId, firstName = firstName, lastName = lastName, - dateOfBirth = birthDate + dateOfBirth = parsedBirthDate.getOrThrow() ) ) - - rpPlayer.setActiveIdentity(identity) - audience.showDialog(idCreationSuccess(firstName, lastName, birthDate)) + rpPlayer.setActiveIdentity(identity) + player.showDialog(idCreationSuccess(firstName, lastName, parsedBirthDate.getOrThrow())) } } } @@ -178,7 +193,7 @@ private fun invalidInputDialog( ): Dialog = dialog { base { title { error("Der Personalausweis konnte nicht erstellt werden!") } - afterAction(DialogBase.DialogAfterAction.NONE) + afterAction(DialogAfterAction.NONE) body { plainMessage(400) {} @@ -205,7 +220,8 @@ private fun idCreationSuccess( ): Dialog = dialog { base { title { success("Dein Personalausweises wurde erfolgreich mit folgenden Angaben erstellt:") } - afterAction(DialogBase.DialogAfterAction.NONE) + afterAction(DialogAfterAction.NONE) + preventClosingWithEscape() body { plainMessage(400) { @@ -249,6 +265,14 @@ private fun cancelCreationButton() = actionButton { } } +private fun validateDate(result: Result): Boolean { + val date = result.getOrNull() ?: return false + + val currentYear = Year.now().value + val minYear = currentYear - 100 + return date.year in minYear..currentYear +} + private fun validateDate(dateString: String): Boolean { val parts = dateString.split(".") diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/idcard/listeners/IdCardHandler.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/idcard/listeners/IdCardHandler.kt similarity index 63% rename from surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/idcard/listeners/IdCardHandler.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/idcard/listeners/IdCardHandler.kt index 0072cb7..e288653 100644 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/idcard/listeners/IdCardHandler.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/idcard/listeners/IdCardHandler.kt @@ -1,24 +1,26 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.idcard.listeners +package dev.slne.surf.roleplay.paper.mechanics.idcard.listeners import com.github.shynixn.mccoroutine.folia.entityDispatcher import com.github.shynixn.mccoroutine.folia.launch import dev.slne.surf.npc.api.event.NpcInteractEvent import dev.slne.surf.npc.api.surfNpcApi -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.mechanic.mechanics.idcard.IdCardMechanicImpl -import dev.slne.surf.roleplay.mechanic.mechanics.idcard.dialogs.createIdDialog -import dev.slne.surf.roleplay.mechanic.plugin +import dev.slne.surf.roleplay.paper.mechanics.idcard.IdCardNpc +import dev.slne.surf.roleplay.paper.mechanics.idcard.dialogs.createIdDialog +import dev.slne.surf.roleplay.paper.player.rpPlayer +import dev.slne.surf.roleplay.paper.plugin import dev.slne.surf.surfapi.core.api.messages.adventure.playSound import dev.slne.surf.surfapi.core.api.messages.adventure.sendText +import net.kyori.adventure.sound.Sound.Source import org.bukkit.Sound import org.bukkit.event.EventHandler import org.bukkit.event.Listener +import org.springframework.stereotype.Component -object IdCardHandler : Listener { +@Component +class IdCardHandler : Listener { private val idCardNpc - get() = surfNpcApi.getNpc(IdCardMechanicImpl.NPC_NAME) - ?: error("The IDCard NPC is not registered") + get() = surfNpcApi.getNpc(IdCardNpc.NPC_NAME) ?: error("The IDCard NPC is not registered") @EventHandler fun onNpcInteract(event: NpcInteractEvent) { @@ -28,7 +30,7 @@ object IdCardHandler : Listener { if (npc.npcUuid != idCardNpc.npcUuid) return plugin.launch(plugin.entityDispatcher(player)) { - val rpPlayer = RpPlayer[player.uniqueId] + val rpPlayer = player.rpPlayer if (rpPlayer.hasCompletedCitizenship()) { player.sendText { @@ -38,8 +40,8 @@ object IdCardHandler : Listener { player.playSound(true) { type(Sound.BLOCK_NOTE_BLOCK_BASS) - volume(.5f) - source(net.kyori.adventure.sound.Sound.Source.MUSIC) + volume(0.5f) + source(Source.MUSIC) } return@launch } diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/Cracker.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/Cracker.kt similarity index 50% rename from surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/Cracker.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/Cracker.kt index 82a32e2..2510c6b 100644 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/utils/Cracker.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/Cracker.kt @@ -1,8 +1,8 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.rentable.utils +package dev.slne.surf.roleplay.paper.mechanics.rentable -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.Crackable -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.LockPick -import dev.slne.surf.roleplay.api.player.RpPlayer +import dev.slne.surf.roleplay.paper.mechanics.rentable.lockpick.LockPick +import dev.slne.surf.roleplay.paper.mechanics.rentable.utils.Crackable +import dev.slne.surf.roleplay.core.common.player.RpPlayer object Cracker { diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/Rentable.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/Rentable.kt new file mode 100644 index 0000000..a658323 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/Rentable.kt @@ -0,0 +1,235 @@ +package dev.slne.surf.roleplay.paper.mechanics.rentable + +import dev.slne.surf.roleplay.core.common.player.RpPlayer +import dev.slne.surf.roleplay.paper.mechanics.rentable.RentableMechanic.RentCollectResult +import dev.slne.surf.roleplay.paper.mechanics.rentable.events.RentableMemberAddEvent +import dev.slne.surf.roleplay.paper.mechanics.rentable.events.RentableMemberAddEvent.MemberAddFailureReason +import dev.slne.surf.roleplay.paper.mechanics.rentable.events.RentableMemberAddEvent.MemberAddResult +import dev.slne.surf.roleplay.paper.mechanics.rentable.events.RentableMemberRemoveEvent +import dev.slne.surf.roleplay.paper.mechanics.rentable.events.RentableMemberRemoveEvent.MemberRemoveFailureReason +import dev.slne.surf.roleplay.paper.mechanics.rentable.events.RentableMemberRemoveEvent.MemberRemoveResult +import dev.slne.surf.roleplay.paper.mechanics.rentable.events.RentableOwnerChangeEvent +import dev.slne.surf.roleplay.paper.mechanics.rentable.events.RentableOwnerChangeEvent.* +import dev.slne.surf.roleplay.paper.mechanics.rentable.events.RentableRentCollectEvent +import dev.slne.surf.roleplay.paper.mechanics.rentable.utils.DoorContainer +import dev.slne.surf.roleplay.paper.player.PaperRpPlayer +import dev.slne.surf.surfapi.core.api.collection.TransformingObjectSet +import dev.slne.surf.surfapi.core.api.messages.adventure.buildText +import dev.slne.surf.surfapi.core.api.util.freeze +import dev.slne.surf.surfapi.core.api.util.mutableObjectSetOf +import dev.slne.surf.surfapi.core.api.util.objectSetOf +import it.unimi.dsi.fastutil.objects.ObjectSet +import net.kyori.adventure.key.Key +import net.kyori.adventure.text.ComponentLike +import java.time.ZonedDateTime +import java.util.* +import java.util.concurrent.atomic.AtomicBoolean +import kotlin.time.Duration + +abstract class Rentable( + val key: Key, + val rent: Int, + val rentDuration: Duration, + val size: Double, + val stories: Int, + val mechanic: RentableMechanic, + storageContainers: ObjectSet = objectSetOf(), + doorContainers: ObjectSet = objectSetOf() +) : ComponentLike { + + private val _members = mutableObjectSetOf() + private val _storageContainers = mutableObjectSetOf() + private val _doorContainers = mutableObjectSetOf() + private val collectingRent = AtomicBoolean(false) + + init { + _storageContainers.addAll(storageContainers) + _doorContainers.addAll(doorContainers) + } + + val storageContainers = _storageContainers.freeze() + val doorContainers = _doorContainers.freeze() + + private var ownerUuid: UUID? = null + var owner: PaperRpPlayer? + get() = ownerUuid?.let(PaperRpPlayer::get) + set(value) { + ownerUuid = value?.uuid + } + + + val members = TransformingObjectSet(_members, PaperRpPlayer::get, PaperRpPlayer::uuid).freeze() + val isRented: Boolean get() = owner != null + var lastRentCollection: ZonedDateTime? = null + + /** + * Collects the rent for the rentable property. + * + * @return The result of the rent collection, indicating success or failure. + */ + suspend fun collectRent(): RentCollectResult { + if (!collectingRent.compareAndSet(false, true)) { // exit quickly if already collecting + return RentCollectResult.ALREADY_COLLECTING + } + + try { + val currentOwner = owner ?: return RentCollectResult.NOT_RENTED + val currentBankBalance = currentOwner.getBankBalance() + + val event = RentableRentCollectEvent( + source = this, + rentable = this, + amount = rent + ) + event.post() + + if (event.isCancelled) { + return RentCollectResult.EVENT_CANCELLED + } + + val rent = event.amount + + if (rent > currentBankBalance) { + return RentCollectResult.NOT_ENOUGH_MONEY + } + + currentOwner.removeBankBalance(rent) + lastRentCollection = ZonedDateTime.now() + + return RentCollectResult.SUCCESS + } finally { + collectingRent.set(false) + } + } + + /** + * Sets the owner of the rentable property and collects the first rent + * + * @param player The player to set as the owner of the rentable property. + * @param reason The reason for the owner change, which can be used to determine the context of the change. + * @return The result of the owner change event, indicating success or failure. + */ + suspend fun setOwner( + player: PaperRpPlayer?, + reason: OwnerChangeReason + ): OwnerSetResult { + val event = RentableOwnerChangeEvent(this, this, owner, player, reason) + event.post() + + if (event.isCancelled) { + return OwnerSetResult.Failure( + OwnerSetFailureReason.EventCancelled( + event.cancelReason ?: "Unbekannt" + ) + ) + } + + if (player == null) { + ownerUuid = null + lastRentCollection = null + _members.clear() + + return OwnerSetResult.Success + } + + if (player == owner) { + return OwnerSetResult.Failure( + OwnerSetFailureReason.AlreadyOwned + ) + } + + val maxRentables = mechanic.getMaxOwnableRentablesByPlayer(player) + val ownedRentables = mechanic.getOwnedRentablesByPlayer(player) + + if (ownedRentables.size >= maxRentables) { + return OwnerSetResult.Failure( + OwnerSetFailureReason.AlreadyOwningTooManyRentables( + ownedRentables.size, + maxRentables + ) + ) + } + + val currentMoney = player.getBankBalance() + + if (currentMoney < rent) { + return OwnerSetResult.Failure( + OwnerSetFailureReason.NotEnoughMoney( + currentMoney = currentMoney, + requiredMoney = rent + ) + ) + } + + owner = player + val result = collectRent() + + if (result != RentCollectResult.SUCCESS) { + owner = null + + return OwnerSetResult.Failure( + OwnerSetFailureReason.RentCollectionFailed(result) + ) + } + + return OwnerSetResult.Success + } + + /** + * Adds a member to the rentable property. + * + * @param player The player to add as a member. + * @return The result of the member addition event, indicating success or failure. + */ + suspend fun addMember(player: RpPlayer): MemberAddResult { + if (isMember(player)) { + return MemberAddResult.Failure(MemberAddFailureReason.AlreadyMember) + } + + val event = RentableMemberAddEvent(this, this, player) + event.post() + + if (event.isCancelled) { + return MemberAddResult.Failure(MemberAddFailureReason.EventCancelled) + } + + _members.add(player.uuid) + + return MemberAddResult.Success + } + + /** + * Removes a member from the rentable property. + * + * @param player The player to remove from the members. + * @return The result of the member removal event, indicating success or failure. + */ + suspend fun removeMember(player: RpPlayer): MemberRemoveResult { + if (!isMember(player)) { + return MemberRemoveResult.Failure(MemberRemoveFailureReason.NotMember) + } + + val event = RentableMemberRemoveEvent(this, this, player) + event.post() + + if (event.isCancelled) { + return MemberRemoveResult.Failure(MemberRemoveFailureReason.EventCancelled) + } + + _members.remove(player.uuid) + + return MemberRemoveResult.Success + } + + /** + * Checks if the player is a member of the rentable property. + * + * @param player The player to check. + * @return True if the player is a member, false otherwise. + */ + fun isMember(player: RpPlayer) = _members.contains(player.uuid) || ownerUuid == player.uuid + + override fun asComponent() = buildText { + variableValue(key.asString()) + } +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/RentableMechanic.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/RentableMechanic.kt new file mode 100644 index 0000000..9e66b28 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/RentableMechanic.kt @@ -0,0 +1,128 @@ +package dev.slne.surf.roleplay.paper.mechanics.rentable + +import dev.slne.surf.roleplay.paper.mechanics.AbstractMechanic +import dev.slne.surf.roleplay.paper.mechanics.Mechanic +import dev.slne.surf.roleplay.paper.mechanics.rentable.rentables.House +import dev.slne.surf.roleplay.core.common.player.RpPlayer +import dev.slne.surf.surfapi.core.api.messages.adventure.key +import dev.slne.surf.surfapi.core.api.util.freeze +import dev.slne.surf.surfapi.core.api.util.mutableObjectSetOf +import dev.slne.surf.surfapi.core.api.util.objectSetOf +import net.kyori.adventure.key.Key +import org.springframework.scheduling.annotation.Scheduled +import java.time.ZonedDateTime +import java.util.concurrent.TimeUnit +import kotlin.time.Duration.Companion.seconds + +@Mechanic("RentableMechanic") +class RentableMechanic : AbstractMechanic() { + + private val _rentables = mutableObjectSetOf() + val rentables = _rentables.freeze() + + /** + * Adds a rentable + * + * @param rentable the [Rentable] + * @return If adding the rentable was successful + */ + fun addRentable(rentable: Rentable) = _rentables.add(rentable) + + override suspend fun onEnable() { + val rentable = House( + key = key("roleplay_house", "house_1"), + rent = 1000, + rentDuration = 10.seconds, + size = 100.0, + stories = 3, + mechanic = this, + storageContainers = objectSetOf(), + doors = objectSetOf() + ) + + addRentable(rentable) + } + + /** + * Collects the rent for a [Rentable] + * + * @param rentable the [Rentable] to collect rent for + * @return the result of the rent collection + */ + @Deprecated("Use rentable.collectRent() instead", ReplaceWith("rentable.collectRent()")) + suspend fun collectRent(rentable: Rentable): RentCollectResult { + return rentable.collectRent() + } + + @Scheduled(fixedDelay = 1, timeUnit = TimeUnit.SECONDS) + suspend fun collectRents() { + val now = ZonedDateTime.now() + + for (rentable in _rentables) { + if (rentable.owner == null) continue + val lastCollection = rentable.lastRentCollection + val delay = rentable.rentDuration + + if (lastCollection == null || now.isAfter(lastCollection.plusSeconds(delay.inWholeSeconds))) { + rentable.collectRent() + } + } + } + + + /** + * Returns the owned [Rentable]s for one [RpPlayer] + * + * @param player the [RpPlayer] + * @return an object set of [Rentable]s + */ + fun getOwnedRentablesByPlayer(player: RpPlayer) = + _rentables.filterTo(mutableObjectSetOf()) { it.owner == player } + + /** + * Returns the maximum number of ownable rentables for a player. + * + * @param player the [RpPlayer] to check + * @return the maximum number of ownable rentables + */ + fun getMaxOwnableRentablesByPlayer(player: RpPlayer) = 1 + + /** + * Returns a [Rentable] by its key. + * + * @param key the [Key] of the [Rentable] + * @return the [Rentable] if found, or null if not found + */ + fun getByKey(key: Key) = _rentables.find { it.key == key } + + + /** + * The result of a rent collection attempt. + */ + enum class RentCollectResult { + /** + * The rent was successfully collected. + */ + SUCCESS, + + /** + * The rent collection was cancelled, possibly due to an event. + */ + EVENT_CANCELLED, + + /** + * The player does not have enough money to pay the rent. + */ + NOT_ENOUGH_MONEY, + + /** + * The rentable is not currently rented. + */ + NOT_RENTED, + + /** + * The rent collection is already in progress. + */ + ALREADY_COLLECTING + } +} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/utils/StorageContainer.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/StorageContainer.kt similarity index 54% rename from surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/utils/StorageContainer.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/StorageContainer.kt index 3fce7ed..04f3062 100644 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/utils/StorageContainer.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/StorageContainer.kt @@ -1,47 +1,35 @@ -package dev.slne.surf.roleplay.api.mechanic.rentable.utils +@file:Suppress("UnstableApiUsage") -import dev.slne.surf.roleplay.api.mechanic.rentable.Rentable -import org.bukkit.Location -import org.bukkit.Material +package dev.slne.surf.roleplay.paper.mechanics.rentable + +import dev.slne.surf.cloud.api.common.player.teleport.WorldLocation +import dev.slne.surf.roleplay.paper.mechanics.rentable.utils.Crackable +import dev.slne.surf.roleplay.paper.mechanics.rentable.utils.Lockable +import dev.slne.surf.roleplay.core.common.player.RpPlayer +import dev.slne.surf.surfapi.core.api.generated.BlockTypeKeys +import net.kyori.adventure.key.Key import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds -/** - * Represents a storage container that can be placed in the world and is associated with a rentable property. - */ -interface StorageContainer { - - /** - * The rentable property that this storage container belongs to. - */ - val rentable: Rentable - - /** - * The location of the storage container in the world. - */ - val location: Location - - /** - * The type of the storage container, which can be either a regular storage container or a vault. - */ - val type: StorageContainerType - - /** - * The size of the storage container, which determines how many slots it has. - */ +abstract class StorageContainer( + val rentable: Rentable, + val location: WorldLocation, + val type: StorageContainerType, val size: StorageContainerSize +) : Lockable { - /** - * Places the storage container in the world at its designated location. - */ - suspend fun placeInWorld() + override fun canAccess(player: RpPlayer): Boolean { + val crackableAndCracked = this is Crackable && this.cracked + + return crackableAndCracked || rentable.isMember(player) + } /** * The different types of storage containers. */ - enum class StorageContainerType(val material: Material) { - REGULAR(Material.CHEST), - VAULT(Material.VAULT); + enum class StorageContainerType(val blockType: Key) { + REGULAR(BlockTypeKeys.CHEST), + VAULT(BlockTypeKeys.VAULT); } /** @@ -81,5 +69,4 @@ interface StorageContainer { */ SIZE_9X6(54, 90.seconds), ; } - } \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/commands/RentableCommand.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/commands/RentableCommand.kt new file mode 100644 index 0000000..0159a14 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/commands/RentableCommand.kt @@ -0,0 +1,80 @@ +package dev.slne.surf.roleplay.paper.mechanics.rentable.commands + +import com.github.shynixn.mccoroutine.folia.launch +import dev.jorel.commandapi.arguments.ArgumentSuggestions +import dev.jorel.commandapi.kotlindsl.* +import dev.slne.surf.roleplay.paper.mechanics.rentable.RentableMechanic +import dev.slne.surf.roleplay.paper.mechanics.rentable.events.RentableOwnerChangeEvent.OwnerChangeReason +import dev.slne.surf.roleplay.paper.mechanics.rentable.events.RentableOwnerChangeEvent.OwnerSetResult +import dev.slne.surf.roleplay.paper.player.rpPlayer +import dev.slne.surf.roleplay.paper.plugin +import dev.slne.surf.surfapi.core.api.messages.adventure.appendNewline +import dev.slne.surf.surfapi.core.api.messages.adventure.sendText +import org.bukkit.NamespacedKey + +fun rentableCommand(mechanic: RentableMechanic) = commandAPICommand("rentable") { + subcommand("rent") { + namespacedKeyArgument("rentableKey") { + replaceSuggestions(ArgumentSuggestions.stringCollection { info -> + mechanic.rentables.map { it.key.asString() } + }) + } + + playerExecutor { player, args -> + val rentableKey: NamespacedKey by args + val rentable = mechanic.getByKey(rentableKey) ?: run { + player.sendText { + appendPrefix() + + error("Es konnte kein Mietobjekt mit dem Key ") + variableValue(rentableKey.asString()) + error(" gefunden werden.") + + } + + return@playerExecutor + } + + if (rentable.isRented) { + player.sendText { + appendPrefix() + + error("Das Mietobjekt ") + variableValue(rentableKey.asString()) + error(" ist bereits vermietet.") + + return@playerExecutor + } + } + + plugin.launch { + val rpPlayer = player.rpPlayer + + val result = rentable.setOwner( + rpPlayer, + OwnerChangeReason.RentableBought + ) + + if (result is OwnerSetResult.Success) { + player.sendText { + appendPrefix() + + success("Du hast das Mietobjekt ") + variableValue(rentableKey.asString()) + success(" erfolgreich gemietet.") + } + } else if (result is OwnerSetResult.Failure) { + player.sendText { + appendPrefix() + + error("Das Mietobjekt ") + variableValue(rentableKey.asString()) + error(" konnte nicht gemietet werden: ") + appendNewline(2) + append(result.reason.message) + } + } + } + } + } +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/containers/RegularStorageContainer.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/containers/RegularStorageContainer.kt new file mode 100644 index 0000000..9d26c9e --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/containers/RegularStorageContainer.kt @@ -0,0 +1,16 @@ +package dev.slne.surf.roleplay.paper.mechanics.rentable.containers + +import dev.slne.surf.cloud.api.common.player.teleport.WorldLocation +import dev.slne.surf.roleplay.paper.mechanics.rentable.Rentable +import dev.slne.surf.roleplay.paper.mechanics.rentable.StorageContainer + +class RegularStorageContainer( + rentable: Rentable, + location: WorldLocation, + size: StorageContainerSize +) : StorageContainer( + rentable = rentable, + location = location, + type = StorageContainerType.REGULAR, + size = size, +) \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/containers/VaultStorageContainer.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/containers/VaultStorageContainer.kt new file mode 100644 index 0000000..bd574bb --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/containers/VaultStorageContainer.kt @@ -0,0 +1,31 @@ +package dev.slne.surf.roleplay.paper.mechanics.rentable.containers + +import dev.slne.surf.cloud.api.common.player.teleport.WorldLocation +import dev.slne.surf.roleplay.paper.mechanics.rentable.Cracker +import dev.slne.surf.roleplay.paper.mechanics.rentable.Rentable +import dev.slne.surf.roleplay.paper.mechanics.rentable.StorageContainer +import dev.slne.surf.roleplay.paper.mechanics.rentable.lockpick.LockPick +import dev.slne.surf.roleplay.paper.mechanics.rentable.utils.Crackable +import dev.slne.surf.roleplay.core.common.player.RpPlayer +import kotlin.time.Duration + +class VaultStorageContainer( + rentable: Rentable, + location: WorldLocation, + size: StorageContainerSize, + override val crackDuration: Duration = size.vaultCrackDuration +) : StorageContainer( + rentable = rentable, + location = location, + type = StorageContainerType.VAULT, + size = size, +), Crackable { + override var cracked: Boolean = false + + override suspend fun crack( + player: RpPlayer, + lockPick: LockPick + ) = Cracker.crack(player, this, lockPick) { + cracked = true + } +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/door/Door.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/door/Door.kt new file mode 100644 index 0000000..f7a1ff3 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/door/Door.kt @@ -0,0 +1,73 @@ +package dev.slne.surf.roleplay.paper.mechanics.rentable.door + +import com.github.shynixn.mccoroutine.folia.regionDispatcher +import dev.slne.surf.cloud.api.client.paper.toLocation +import dev.slne.surf.cloud.api.common.player.teleport.WorldLocation +import dev.slne.surf.roleplay.paper.mechanics.rentable.Cracker +import dev.slne.surf.roleplay.paper.mechanics.rentable.Rentable +import dev.slne.surf.roleplay.paper.mechanics.rentable.lockpick.LockPick +import dev.slne.surf.roleplay.paper.mechanics.rentable.utils.Crackable +import dev.slne.surf.roleplay.paper.mechanics.rentable.utils.DoorContainer +import dev.slne.surf.roleplay.paper.mechanics.rentable.utils.Lockable +import dev.slne.surf.roleplay.core.common.player.RpPlayer +import dev.slne.surf.roleplay.paper.plugin +import dev.slne.surf.surfapi.bukkit.api.util.getBlockAtAsync +import dev.slne.surf.surfapi.core.api.util.mapAsync +import kotlinx.coroutines.withContext +import org.bukkit.Location +import kotlin.collections.forEach +import kotlin.time.Duration +import org.bukkit.block.data.type.Door as DoorBlockData + +@Suppress("UnstableApiUsage") +abstract class Door( + val rentable: Rentable, + val container: DoorContainer, + val location: Location, + override val crackDuration: Duration +) : Lockable, Crackable { + + override var cracked: Boolean = false + + private suspend fun doorStateOperation( + door: Door, + operation: (DoorBlockData) -> Unit + ) { + val doorLocation = door.location + + withContext(plugin.regionDispatcher(doorLocation)) { + val doorBlock = doorLocation.world.getBlockAtAsync(doorLocation.toBlock()) + val doorBlockState = doorBlock.state + + if (doorBlockState is DoorBlockData) { + operation(doorBlockState) + doorBlockState.update(true, false) + } + } + } + + suspend fun open() { + container.doors.mapAsync { door -> + doorStateOperation(door) { state -> + state.isOpen = true + } + } + } + + suspend fun close() { + container.doors.mapAsync { door -> + doorStateOperation(door) { state -> + state.isOpen = false + } + } + } + + override fun canAccess(player: RpPlayer) = cracked || rentable.isMember(player) + + override suspend fun crack( + player: RpPlayer, + lockPick: LockPick + ) = Cracker.crack(player, this, lockPick) { + cracked = true + } +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/door/doors/FrontDoor.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/door/doors/FrontDoor.kt new file mode 100644 index 0000000..942c593 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/door/doors/FrontDoor.kt @@ -0,0 +1,19 @@ +package dev.slne.surf.roleplay.paper.mechanics.rentable.door.doors + +import dev.slne.surf.cloud.api.common.player.teleport.WorldLocation +import dev.slne.surf.roleplay.paper.mechanics.rentable.Rentable +import dev.slne.surf.roleplay.paper.mechanics.rentable.door.Door +import dev.slne.surf.roleplay.paper.mechanics.rentable.utils.DoorContainer +import org.bukkit.Location +import kotlin.time.Duration.Companion.seconds + +class FrontDoor( + rentable: Rentable, + container: DoorContainer, + location: Location +) : Door( + rentable = rentable, + container = container, + location = location, + crackDuration = 30.seconds +) \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/door/doors/GarageDoor.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/door/doors/GarageDoor.kt new file mode 100644 index 0000000..287263e --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/door/doors/GarageDoor.kt @@ -0,0 +1,19 @@ +package dev.slne.surf.roleplay.paper.mechanics.rentable.door.doors + +import dev.slne.surf.cloud.api.common.player.teleport.WorldLocation +import dev.slne.surf.roleplay.paper.mechanics.rentable.Rentable +import dev.slne.surf.roleplay.paper.mechanics.rentable.door.Door +import dev.slne.surf.roleplay.paper.mechanics.rentable.utils.DoorContainer +import org.bukkit.Location +import kotlin.time.Duration.Companion.seconds + +class GarageDoor( + rentable: Rentable, + container: DoorContainer, + location: Location +) : Door( + rentable = rentable, + container = container, + location = location, + crackDuration = 15.seconds +) \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/door/doors/RegularDoor.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/door/doors/RegularDoor.kt new file mode 100644 index 0000000..794710d --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/door/doors/RegularDoor.kt @@ -0,0 +1,19 @@ +package dev.slne.surf.roleplay.paper.mechanics.rentable.door.doors + +import dev.slne.surf.cloud.api.common.player.teleport.WorldLocation +import dev.slne.surf.roleplay.paper.mechanics.rentable.Rentable +import dev.slne.surf.roleplay.paper.mechanics.rentable.door.Door +import dev.slne.surf.roleplay.paper.mechanics.rentable.utils.DoorContainer +import org.bukkit.Location +import kotlin.time.Duration.Companion.seconds + +class RegularDoor( + rentable: Rentable, + container: DoorContainer, + location: Location +) : Door( + rentable = rentable, + container = container, + location = location, + crackDuration = 15.seconds +) \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/events/RentableMemberAddEvent.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/events/RentableMemberAddEvent.kt similarity index 82% rename from surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/events/RentableMemberAddEvent.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/events/RentableMemberAddEvent.kt index 757a4a8..3814b00 100644 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/events/RentableMemberAddEvent.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/events/RentableMemberAddEvent.kt @@ -1,8 +1,8 @@ -package dev.slne.surf.roleplay.api.mechanic.rentable.events +package dev.slne.surf.roleplay.paper.mechanics.rentable.events -import dev.slne.surf.roleplay.api.events.CancellableRpEvent -import dev.slne.surf.roleplay.api.mechanic.rentable.Rentable -import dev.slne.surf.roleplay.api.player.RpPlayer +import dev.slne.surf.cloud.api.common.event.CancellableCloudEvent +import dev.slne.surf.roleplay.paper.mechanics.rentable.Rentable +import dev.slne.surf.roleplay.core.common.player.RpPlayer /** * Event triggered when a member is added to a rentable property. @@ -12,9 +12,24 @@ import dev.slne.surf.roleplay.api.player.RpPlayer * @property member The player who is being added as a member to the rentable property. */ class RentableMemberAddEvent( + source: Any, val rentable: Rentable, val member: RpPlayer, -) : CancellableRpEvent() { +) : CancellableCloudEvent(source) { + /** + * Represents the reasons why adding a member to a rentable property might fail. + */ + sealed class MemberAddFailureReason { + /** + * Indicates that the member is already part of the rentable property. + */ + data object AlreadyMember : MemberAddFailureReason() + + /** + * Indicates that the addition of the member was cancelled by an event handler. + */ + data object EventCancelled : MemberAddFailureReason() + } /** * The result of the member addition operation. @@ -33,19 +48,4 @@ class RentableMemberAddEvent( */ data class Failure(val reason: MemberAddFailureReason) : MemberAddResult() } - - /** - * Represents the reasons why adding a member to a rentable property might fail. - */ - sealed class MemberAddFailureReason { - /** - * Indicates that the member is already part of the rentable property. - */ - data object AlreadyMember : MemberAddFailureReason() - - /** - * Indicates that the addition of the member was cancelled by an event handler. - */ - data object EventCancelled : MemberAddFailureReason() - } } \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/events/RentableMemberRemoveEvent.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/events/RentableMemberRemoveEvent.kt similarity index 83% rename from surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/events/RentableMemberRemoveEvent.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/events/RentableMemberRemoveEvent.kt index 5b1aaae..cc4f2cc 100644 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/events/RentableMemberRemoveEvent.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/events/RentableMemberRemoveEvent.kt @@ -1,8 +1,8 @@ -package dev.slne.surf.roleplay.api.mechanic.rentable.events +package dev.slne.surf.roleplay.paper.mechanics.rentable.events -import dev.slne.surf.roleplay.api.events.CancellableRpEvent -import dev.slne.surf.roleplay.api.mechanic.rentable.Rentable -import dev.slne.surf.roleplay.api.player.RpPlayer +import dev.slne.surf.cloud.api.common.event.CancellableCloudEvent +import dev.slne.surf.roleplay.paper.mechanics.rentable.Rentable +import dev.slne.surf.roleplay.core.common.player.RpPlayer /** * Event triggered when a member is removed from a rentable property. @@ -12,9 +12,24 @@ import dev.slne.surf.roleplay.api.player.RpPlayer * @property member The player who is being removed as a member from the rentable property. */ class RentableMemberRemoveEvent( + source: Any, val rentable: Rentable, val member: RpPlayer, -) : CancellableRpEvent() { +) : CancellableCloudEvent(source) { + /** + * Represents the reasons why removing a member from a rentable property might fail. + */ + sealed class MemberRemoveFailureReason { + /** + * Indicates that the member is not part of the rentable property. + */ + data object NotMember : MemberRemoveFailureReason() + + /** + * Indicates that the event was cancelled, preventing the member from being removed. + */ + data object EventCancelled : MemberRemoveFailureReason() + } /** * The result of the member removal operation. @@ -33,19 +48,4 @@ class RentableMemberRemoveEvent( */ data class Failure(val reason: MemberRemoveFailureReason) : MemberRemoveResult() } - - /** - * Represents the reasons why removing a member from a rentable property might fail. - */ - sealed class MemberRemoveFailureReason { - /** - * Indicates that the member is not part of the rentable property. - */ - data object NotMember : MemberRemoveFailureReason() - - /** - * Indicates that the event was cancelled, preventing the member from being removed. - */ - data object EventCancelled : MemberRemoveFailureReason() - } } \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/events/RentableOwnerChangeEvent.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/events/RentableOwnerChangeEvent.kt similarity index 89% rename from surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/events/RentableOwnerChangeEvent.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/events/RentableOwnerChangeEvent.kt index e336a82..fa03c9a 100644 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/events/RentableOwnerChangeEvent.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/events/RentableOwnerChangeEvent.kt @@ -1,9 +1,10 @@ -package dev.slne.surf.roleplay.api.mechanic.rentable.events +package dev.slne.surf.roleplay.paper.mechanics.rentable.events -import dev.slne.surf.roleplay.api.events.CancellableRpEvent -import dev.slne.surf.roleplay.api.mechanic.rentable.Rentable -import dev.slne.surf.roleplay.api.mechanic.rentable.RentableMechanic -import dev.slne.surf.roleplay.api.player.RpPlayer +import dev.slne.surf.cloud.api.common.event.CancellableCloudEvent +import dev.slne.surf.roleplay.core.common.player.RpPlayer +import dev.slne.surf.roleplay.paper.mechanics.rentable.Rentable +import dev.slne.surf.roleplay.paper.mechanics.rentable.RentableMechanic +import dev.slne.surf.surfapi.core.api.messages.adventure.buildText import dev.slne.surf.surfapi.core.api.messages.builder.SurfComponentBuilder /** @@ -16,11 +17,12 @@ import dev.slne.surf.surfapi.core.api.messages.builder.SurfComponentBuilder * @property reason The reason for the owner change. */ class RentableOwnerChangeEvent( + source: Any, val rentable: Rentable, val oldOwner: RpPlayer?, val newOwner: RpPlayer?, val reason: OwnerChangeReason, -) : CancellableRpEvent() { +) : CancellableCloudEvent(source) { /** * The reason why the owner change was cancelled, if applicable. @@ -47,30 +49,14 @@ class RentableOwnerChangeEvent( data object OwnerSetNewOwner : OwnerChangeReason() } - /** - * The result of setting a new owner for the rentable property. - */ - sealed class OwnerSetResult { - /** - * Indicates a successful owner change operation. - */ - data object Success : OwnerSetResult() - - /** - * Indicates a failure in setting the new owner for the rentable property. - * Contains the reason for the failure. - * - * @property reason The reason why the owner change failed. - */ - data class Failure(val reason: OwnerSetFailureReason) : OwnerSetResult() - } /** * Represents the reasons why setting a new owner for a rentable property might fail. * * @property message A function that builds a message describing the failure reason. */ - sealed class OwnerSetFailureReason(val message: SurfComponentBuilder.() -> Unit) { + sealed class OwnerSetFailureReason(message: SurfComponentBuilder.() -> Unit) { + val message = buildText(message) /** * Indicates that the new owner is already a member of the rentable property. @@ -135,4 +121,23 @@ class RentableOwnerChangeEvent( variableValue(reason) }) } + + /** + * The result of setting a new owner for the rentable property. + */ + sealed class OwnerSetResult { + /** + * Indicates a successful owner change operation. + */ + data object Success : OwnerSetResult() + + /** + * Indicates a failure in setting the new owner for the rentable property. + * Contains the reason for the failure. + * + * @property reason The reason why the owner change failed. + */ + data class Failure(val reason: OwnerSetFailureReason) : OwnerSetResult() + } + } \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/events/RentableRentCollectEvent.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/events/RentableRentCollectEvent.kt similarity index 61% rename from surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/events/RentableRentCollectEvent.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/events/RentableRentCollectEvent.kt index aebce6d..2820276 100644 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/events/RentableRentCollectEvent.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/events/RentableRentCollectEvent.kt @@ -1,7 +1,7 @@ -package dev.slne.surf.roleplay.api.mechanic.rentable.events +package dev.slne.surf.roleplay.paper.mechanics.rentable.events -import dev.slne.surf.roleplay.api.events.CancellableRpEvent -import dev.slne.surf.roleplay.api.mechanic.rentable.Rentable +import dev.slne.surf.cloud.api.common.event.CancellableCloudEvent +import dev.slne.surf.roleplay.paper.mechanics.rentable.Rentable /** * Event triggered when rent is collected from a rentable property. @@ -11,6 +11,7 @@ import dev.slne.surf.roleplay.api.mechanic.rentable.Rentable * @property amount The amount of rent being collected. */ class RentableRentCollectEvent( + source: Any, val rentable: Rentable, var amount: Int, -) : CancellableRpEvent() \ No newline at end of file +) : CancellableCloudEvent(source) \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/listeners/RentCollectedListener.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/listeners/RentCollectedListener.kt new file mode 100644 index 0000000..b2c0311 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/listeners/RentCollectedListener.kt @@ -0,0 +1,36 @@ +package dev.slne.surf.roleplay.paper.mechanics.rentable.listeners + +import dev.slne.surf.cloud.api.common.event.CloudEventHandler +import dev.slne.surf.roleplay.paper.mechanics.rentable.events.RentableRentCollectEvent +import dev.slne.surf.surfapi.core.api.messages.adventure.playSound +import dev.slne.surf.surfapi.core.api.messages.adventure.sendText +import net.kyori.adventure.sound.Sound.Source +import org.bukkit.Sound +import org.springframework.stereotype.Component + +@Suppress("unused") +@Component +class RentCollectedListener { + + @CloudEventHandler + fun onRentableRentCollect(event: RentableRentCollectEvent) { + val rentable = event.rentable + val player = rentable.owner?.cloudPlayer?.player ?: return + + player.sendText { + appendPrefix() + + info("Du hast die Miete in Höhe von ") + variableValue("${event.amount} €") + info(" für deine Immobilie ") + append(rentable) + info(" bezahlt.") + } + + player.playSound(true) { + type(Sound.BLOCK_ANVIL_LAND) + volume(.5f) + source(Source.BLOCK) + } + } +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/listeners/RentableListener.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/listeners/RentableListener.kt new file mode 100644 index 0000000..8464e39 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/listeners/RentableListener.kt @@ -0,0 +1,155 @@ +package dev.slne.surf.roleplay.paper.mechanics.rentable.listeners + +import dev.slne.surf.cloud.api.common.event.CloudEventHandler +import dev.slne.surf.roleplay.paper.mechanics.rentable.events.RentableMemberAddEvent +import dev.slne.surf.roleplay.paper.mechanics.rentable.events.RentableMemberRemoveEvent +import dev.slne.surf.roleplay.paper.mechanics.rentable.events.RentableOwnerChangeEvent +import dev.slne.surf.roleplay.paper.mechanics.rentable.events.RentableOwnerChangeEvent.OwnerChangeReason +import dev.slne.surf.surfapi.core.api.messages.adventure.playSound +import dev.slne.surf.surfapi.core.api.messages.adventure.sendText +import net.kyori.adventure.sound.Sound.Source +import org.bukkit.Sound +import org.springframework.stereotype.Component + +@Suppress("unused") +@Component +class RentableListener { + + @CloudEventHandler + fun onRentableMemberAdd(event: RentableMemberAddEvent) { + val rentable = event.rentable + val members = event.rentable.members + val memberPlayer = event.member.cloudPlayer.player + + if (memberPlayer != null) { + memberPlayer.sendText { + appendPrefix() + + info("Du wurdest zu der Immobilie ") + append(rentable) + info(" hinzugefügt.") + } + + memberPlayer.playSound(true) { + type(Sound.ENTITY_VILLAGER_CELEBRATE) + volume(0.5f) + source(Source.NEUTRAL) + } + } + + for (member in members) { + if (member == event.member) continue + val memberPlayer = member.cloudPlayer.player ?: continue + memberPlayer.sendText { + appendPrefix() + + append(event.member) + info(" wurde zu der Immobilie ") + append(rentable) + info(" hinzugefügt.") + } + + memberPlayer.playSound(true) { + type(Sound.ENTITY_VILLAGER_CELEBRATE) + volume(.5f) + source(Source.NEUTRAL) + } + } + } + + @CloudEventHandler + fun onRentableMemberRemove(event: RentableMemberRemoveEvent) { + val rentable = event.rentable + val members = event.rentable.members + val memberPlayer = event.member.cloudPlayer.player + + if (memberPlayer != null) { + memberPlayer.sendText { + appendPrefix() + + info("Du wurdest von der Immobilie ") + append(rentable) + info(" entfernt.") + } + + memberPlayer.playSound(true) { + type(Sound.ENTITY_VILLAGER_NO) + volume(.5f) + source(Source.NEUTRAL) + } + } + + for (member in members) { + if (member == event.member) continue + val memberPlayer = member.cloudPlayer.player ?: continue + memberPlayer.sendText { + appendPrefix() + + append(event.member.asComponent()) + info(" wurde von der Immobilie ") + append(rentable) + info(" entfernt.") + } + + memberPlayer.playSound(true) { + type(Sound.ENTITY_VILLAGER_NO) + volume(.5f) + source(Source.NEUTRAL) + } + } + } + + @CloudEventHandler + fun onRentableOwnerChange(event: RentableOwnerChangeEvent) { + val reason = event.reason + val rentable = event.rentable + + val newOwner = event.newOwner + val oldOwner = event.oldOwner + + val newOwnerPlayer = newOwner?.cloudPlayer?.player + val oldOwnerPlayer = oldOwner?.cloudPlayer?.player + + if (newOwner != null && newOwnerPlayer != null) { + newOwnerPlayer.sendText { + appendPrefix() + + success("Du bist jetzt der Eigentümer der Immobilie ") + append(rentable) + success(".") + + if (reason == OwnerChangeReason.RentableBought) { + info(" Du hast die Immobilie gemietet.") + } else if (reason is OwnerChangeReason.OwnerSetNewOwner) { + info(" Du wurdest als neuer Eigentümer gesetzt.") + } + } + + newOwnerPlayer.playSound(true) { + type(Sound.ENTITY_PLAYER_LEVELUP) + volume(.5f) + source(Source.NEUTRAL) + } + } + + if (oldOwner != null && oldOwnerPlayer != null) { + oldOwnerPlayer.sendText { + appendPrefix() + + info("Du bist nicht mehr der Eigentümer der Immobilie ") + append(rentable) + info(".") + + if (reason is OwnerChangeReason.OwnerSetNewOwner) { + error(" Du wurdest als Eigentümer entfernt.") + } + } + + oldOwnerPlayer.playSound(true) { + type(Sound.ENTITY_VILLAGER_NO) + volume(.5f) + source(Source.NEUTRAL) + } + } + } +} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/utils/LockPick.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/lockpick/LockPick.kt similarity index 55% rename from surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/utils/LockPick.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/lockpick/LockPick.kt index 725913b..6d9a19e 100644 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/utils/LockPick.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/lockpick/LockPick.kt @@ -1,23 +1,14 @@ -package dev.slne.surf.roleplay.api.mechanic.rentable.utils +package dev.slne.surf.roleplay.paper.mechanics.rentable.lockpick -import dev.slne.surf.roleplay.api.player.RpPlayer +import dev.slne.surf.roleplay.core.common.player.RpPlayer +import dev.slne.surf.surfapi.core.api.messages.adventure.buildText import dev.slne.surf.surfapi.core.api.messages.builder.SurfComponentBuilder -/** - * Represents a lock pick that can be used to pick locks. - */ -interface LockPick { - - /** - * The display name of the lock pick. - */ - val displayName: SurfComponentBuilder.() -> Unit - - /** - * The chance of successfully picking the lock. - * A value between 0.0 (0%) and 1.0 (100%). - */ +abstract class LockPick( + displayName: SurfComponentBuilder.() -> Unit, val breakChance: (RpPlayer) -> Double +) { + val displayName = buildText(displayName) enum class LockPickResult { /** @@ -40,5 +31,4 @@ interface LockPick { */ EVENT_CANCELLED } - } \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/lockpick/lockpicks/BatteringRam.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/lockpick/lockpicks/BatteringRam.kt new file mode 100644 index 0000000..d3efd41 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/lockpick/lockpicks/BatteringRam.kt @@ -0,0 +1,10 @@ +package dev.slne.surf.roleplay.paper.mechanics.rentable.lockpick.lockpicks + +import dev.slne.surf.roleplay.paper.mechanics.rentable.lockpick.LockPick + +object BatteringRam : LockPick( + displayName = { + primary("Rammbock") + }, + breakChance = { 0.0 } +) \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/lockpick/lockpicks/PremiumLockPick.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/lockpick/lockpicks/PremiumLockPick.kt new file mode 100644 index 0000000..a6a3bf4 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/lockpick/lockpicks/PremiumLockPick.kt @@ -0,0 +1,10 @@ +package dev.slne.surf.roleplay.paper.mechanics.rentable.lockpick.lockpicks + +import dev.slne.surf.roleplay.paper.mechanics.rentable.lockpick.LockPick + +object PremiumLockPick : LockPick( + displayName = { + primary("Verzinkter Vierkantstahl Dietrich") + }, + breakChance = { 0.1 } +) \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/lockpick/lockpicks/RegularLockPick.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/lockpick/lockpicks/RegularLockPick.kt new file mode 100644 index 0000000..58b8a21 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/lockpick/lockpicks/RegularLockPick.kt @@ -0,0 +1,10 @@ +package dev.slne.surf.roleplay.paper.mechanics.rentable.lockpick.lockpicks + +import dev.slne.surf.roleplay.paper.mechanics.rentable.lockpick.LockPick + +object RegularLockPick : LockPick( + displayName = { + primary("Dietrich") + }, + breakChance = { 0.5 } +) \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/rentables/ApartmentImpl.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/rentables/Apartment.kt similarity index 53% rename from surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/rentables/ApartmentImpl.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/rentables/Apartment.kt index 4656254..66756db 100644 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/rentables/ApartmentImpl.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/rentables/Apartment.kt @@ -1,28 +1,30 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.rentable.rentables +package dev.slne.surf.roleplay.paper.mechanics.rentable.rentables -import dev.slne.surf.roleplay.api.mechanic.rentable.rentables.Apartment -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.StorageContainer -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.door.DoorContainer -import dev.slne.surf.roleplay.mechanic.mechanics.rentable.RentableImpl +import dev.slne.surf.roleplay.paper.mechanics.rentable.Rentable +import dev.slne.surf.roleplay.paper.mechanics.rentable.RentableMechanic +import dev.slne.surf.roleplay.paper.mechanics.rentable.StorageContainer +import dev.slne.surf.roleplay.paper.mechanics.rentable.utils.DoorContainer import dev.slne.surf.surfapi.core.api.util.mutableObjectSetOf import it.unimi.dsi.fastutil.objects.ObjectSet import net.kyori.adventure.key.Key import kotlin.time.Duration -class ApartmentImpl( +class Apartment( key: Key, rent: Int, rentDuration: Duration, size: Double, stories: Int, + mechanic: RentableMechanic, storageContainers: ObjectSet = mutableObjectSetOf(), doors: ObjectSet = mutableObjectSetOf() -) : RentableImpl( +) : Rentable( key, rent, rentDuration, size, stories, + mechanic, storageContainers, doors -), Apartment \ No newline at end of file +) \ No newline at end of file diff --git a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/rentables/HouseImpl.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/rentables/House.kt similarity index 53% rename from surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/rentables/HouseImpl.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/rentables/House.kt index 69864cb..66f629c 100644 --- a/surf-roleplay-mechanic/src/main/kotlin/dev/slne/surf/roleplay/mechanic/mechanics/rentable/rentables/HouseImpl.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/rentables/House.kt @@ -1,28 +1,30 @@ -package dev.slne.surf.roleplay.mechanic.mechanics.rentable.rentables +package dev.slne.surf.roleplay.paper.mechanics.rentable.rentables -import dev.slne.surf.roleplay.api.mechanic.rentable.rentables.House -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.StorageContainer -import dev.slne.surf.roleplay.api.mechanic.rentable.utils.door.DoorContainer -import dev.slne.surf.roleplay.mechanic.mechanics.rentable.RentableImpl +import dev.slne.surf.roleplay.paper.mechanics.rentable.Rentable +import dev.slne.surf.roleplay.paper.mechanics.rentable.RentableMechanic +import dev.slne.surf.roleplay.paper.mechanics.rentable.StorageContainer +import dev.slne.surf.roleplay.paper.mechanics.rentable.utils.DoorContainer import dev.slne.surf.surfapi.core.api.util.mutableObjectSetOf import it.unimi.dsi.fastutil.objects.ObjectSet import net.kyori.adventure.key.Key import kotlin.time.Duration -class HouseImpl( +class House( key: Key, rent: Int, rentDuration: Duration, size: Double, stories: Int, + mechanic: RentableMechanic, storageContainers: ObjectSet = mutableObjectSetOf(), doors: ObjectSet = mutableObjectSetOf() -) : RentableImpl( +) : Rentable( key, rent, rentDuration, size, stories, + mechanic, storageContainers, doors -), House \ No newline at end of file +) \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/utils/Crackable.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/utils/Crackable.kt similarity index 82% rename from surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/utils/Crackable.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/utils/Crackable.kt index af9815a..6c4c63b 100644 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/utils/Crackable.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/utils/Crackable.kt @@ -1,6 +1,7 @@ -package dev.slne.surf.roleplay.api.mechanic.rentable.utils +package dev.slne.surf.roleplay.paper.mechanics.rentable.utils -import dev.slne.surf.roleplay.api.player.RpPlayer +import dev.slne.surf.roleplay.paper.mechanics.rentable.lockpick.LockPick +import dev.slne.surf.roleplay.core.common.player.RpPlayer import kotlin.time.Duration /** diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/utils/door/DoorContainer.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/utils/DoorContainer.kt similarity index 65% rename from surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/utils/door/DoorContainer.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/utils/DoorContainer.kt index a7f843e..045ddd9 100644 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/utils/door/DoorContainer.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/utils/DoorContainer.kt @@ -1,5 +1,6 @@ -package dev.slne.surf.roleplay.api.mechanic.rentable.utils.door +package dev.slne.surf.roleplay.paper.mechanics.rentable.utils +import dev.slne.surf.roleplay.paper.mechanics.rentable.door.Door import it.unimi.dsi.fastutil.objects.ObjectSet /** diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/utils/Lockable.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/utils/Lockable.kt similarity index 78% rename from surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/utils/Lockable.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/utils/Lockable.kt index 10d0548..4dfa378 100644 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/rentable/utils/Lockable.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/rentable/utils/Lockable.kt @@ -1,6 +1,6 @@ -package dev.slne.surf.roleplay.api.mechanic.rentable.utils +package dev.slne.surf.roleplay.paper.mechanics.rentable.utils -import dev.slne.surf.roleplay.api.player.RpPlayer +import dev.slne.surf.roleplay.core.common.player.RpPlayer /** * Represents an entity that can be locked and accessed by players. diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/weapon/Weapon.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/weapon/Weapon.kt new file mode 100644 index 0000000..8c49299 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/weapon/Weapon.kt @@ -0,0 +1,32 @@ +package dev.slne.surf.roleplay.paper.mechanics.weapon + +import dev.slne.surf.roleplay.paper.mechanics.weapon.magazine.Magazine +import dev.slne.surf.roleplay.paper.mechanics.weapon.utils.WeaponType +import dev.slne.surf.surfapi.core.api.messages.adventure.buildText +import dev.slne.surf.surfapi.core.api.messages.builder.SurfComponentBuilder +import dev.slne.surf.surfapi.core.api.util.objectSetOf +import it.unimi.dsi.fastutil.objects.ObjectSet +import net.kyori.adventure.key.Key +import kotlin.time.Duration +import kotlin.time.Duration.Companion.seconds + +abstract class Weapon( + val type: WeaponType, + val weaponItemType: Key, + val name: String, + displayName: SurfComponentBuilder.() -> Unit = { + primary(name) + }, + description: SurfComponentBuilder.() -> Unit = { + spacer("Eine ") + append(displayName) + spacer(" Waffe") + }, + val weaponShootCooldown: Duration = 1.seconds, + val supportedMagazines: ObjectSet = objectSetOf() +) { + val displayName = buildText(displayName) + val description = buildText(description) + + fun isApplicableMagazine(magazine: Magazine) = magazine in supportedMagazines +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/weapon/WeaponMechanic.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/weapon/WeaponMechanic.kt new file mode 100644 index 0000000..9afd574 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/weapon/WeaponMechanic.kt @@ -0,0 +1,12 @@ +package dev.slne.surf.roleplay.paper.mechanics.weapon + +import dev.slne.surf.roleplay.paper.mechanics.AbstractMechanic +import dev.slne.surf.roleplay.paper.mechanics.Mechanic +import dev.slne.surf.surfapi.core.api.util.freeze +import dev.slne.surf.surfapi.core.api.util.mutableObjectSetOf + +@Mechanic("WeaponMechanic") +class WeaponMechanic : AbstractMechanic() { + private val _weapons = mutableObjectSetOf() + val weapons = _weapons.freeze() +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/weapon/magazine/Magazine.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/weapon/magazine/Magazine.kt new file mode 100644 index 0000000..616f33f --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/weapon/magazine/Magazine.kt @@ -0,0 +1,21 @@ +package dev.slne.surf.roleplay.paper.mechanics.weapon.magazine + +import dev.slne.surf.surfapi.core.api.messages.adventure.buildText +import dev.slne.surf.surfapi.core.api.messages.builder.SurfComponentBuilder + +abstract class Magazine( + val name: String, + displayName: SurfComponentBuilder.() -> Unit = { + primary(name) + }, + description: SurfComponentBuilder.() -> Unit = { + spacer("Ein ") + append(displayName) + spacer(" Magazin") + }, + val maxAmmo: Int, + val damageFunction: (Double) -> Double +) { + val displayName = buildText(displayName) + val description = buildText(description) +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/weapon/magazine/PlayerMagazine.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/weapon/magazine/PlayerMagazine.kt new file mode 100644 index 0000000..4f274e7 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/weapon/magazine/PlayerMagazine.kt @@ -0,0 +1,6 @@ +package dev.slne.surf.roleplay.paper.mechanics.weapon.magazine + +class PlayerMagazine(val magazine: Magazine) { + var currentAmmo = magazine.maxAmmo + private set +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/weapon/player/PlayerWeapon.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/weapon/player/PlayerWeapon.kt new file mode 100644 index 0000000..ae98484 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/weapon/player/PlayerWeapon.kt @@ -0,0 +1,13 @@ +package dev.slne.surf.roleplay.paper.mechanics.weapon.player + +import dev.slne.surf.roleplay.paper.mechanics.weapon.Weapon +import dev.slne.surf.roleplay.paper.mechanics.weapon.magazine.PlayerMagazine + +class PlayerWeapon(val weapon: Weapon) { + var currentMagazine: PlayerMagazine? = null + private set + + fun setCurrentMagazine(magazine: PlayerMagazine?) { + currentMagazine = magazine + } +} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/weapon/utils/WeaponType.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/weapon/utils/WeaponType.kt similarity index 75% rename from surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/weapon/utils/WeaponType.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/weapon/utils/WeaponType.kt index 6c0e4b0..e7e7083 100644 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/mechanic/weapon/utils/WeaponType.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/mechanics/weapon/utils/WeaponType.kt @@ -1,7 +1,6 @@ -package dev.slne.surf.roleplay.api.mechanic.weapon.utils +package dev.slne.surf.roleplay.paper.mechanics.weapon.utils enum class WeaponType { - PISTOL, RIFLE, SHOTGUN, diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/RpPlayerImpl.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/PaperRpPlayer.kt similarity index 50% rename from surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/RpPlayerImpl.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/PaperRpPlayer.kt index 2d651fe..30f9842 100644 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/RpPlayerImpl.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/PaperRpPlayer.kt @@ -1,62 +1,56 @@ -package dev.slne.surf.roleplay.core.player - -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.getIdentity -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.api.player.license.License -import dev.slne.surf.roleplay.api.player.license.utils.LicenseRemovedReason -import dev.slne.surf.roleplay.api.player.utils.BalanceType +package dev.slne.surf.roleplay.paper.player + +import dev.slne.surf.roleplay.RoleplayApplication +import dev.slne.surf.roleplay.core.common.player.RpPlayer +import dev.slne.surf.roleplay.core.common.player.identity.RpIdentityType +import dev.slne.surf.roleplay.core.common.transaction.utils.BalanceType +import dev.slne.surf.roleplay.paper.player.identity.PaperIdentityService +import dev.slne.surf.roleplay.paper.player.identity.RpIdentity +import dev.slne.surf.roleplay.paper.player.license.HasLicenses +import dev.slne.surf.roleplay.paper.player.license.License +import dev.slne.surf.roleplay.paper.player.license.utils.LicenseRemovedReason import dev.slne.surf.surfapi.bukkit.api.extensions.server import dev.slne.surf.surfapi.core.api.messages.adventure.appendNewline import dev.slne.surf.surfapi.core.api.messages.adventure.buildText +import dev.slne.surf.surfapi.core.api.util.freeze import dev.slne.surf.surfapi.core.api.util.mutableObjectSetOf -import it.unimi.dsi.fastutil.objects.ObjectSet -import org.bukkit.OfflinePlayer -import org.bukkit.entity.Player -import java.time.ZonedDateTime +import io.papermc.paper.datacomponent.item.attribute.AttributeModifierDisplay.override +import org.springframework.beans.factory.getBean import java.util.* -class RpPlayerImpl( - override val uuid: UUID, - override var createdAt: ZonedDateTime = ZonedDateTime.now(), - override var updatedAt: ZonedDateTime = ZonedDateTime.now() -) : RpPlayer { +class PaperRpPlayer(uuid: UUID) : RpPlayer(uuid), HasLicenses { - private val _identities = mutableObjectSetOf() - override val identities: ObjectSet get() = _identities + private val _identities = + mutableObjectSetOf() // TODO: 22.08.2025 20:31 - replace with cloud cache soon + val identities = _identities.freeze() - override var username: String? = null - override val bukkitPlayer: Player? get() = server.getPlayer(uuid) - override val bukkitOfflinePlayer: OfflinePlayer get() = server.getOfflinePlayer(uuid) + var activeIdentity: RpIdentity? = null + private set - override var activeIdentity: RpIdentity? = null + val player get() = server.getPlayer(uuid) - override suspend fun setActiveIdentity(identity: RpIdentity) { - if (!_identities.contains(identity)) { - error("Tried to set an active identity that is not part of the player's identities: $identity") - } + override val licenses + get() = activeIdentity?.licenses + ?: error("Tried accessing licenses of a player without an active identity $uuid") + + suspend fun fetchIdentities() { + val fetched = identityService.fetchIdentities(uuid) + _identities.clear() + _identities.addAll(fetched) + } + + fun setActiveIdentity(identity: RpIdentity) { + require(identity in _identities) { "Tried to set an active identity that is not part of the player's identities: $identity" } activeIdentity = identity } fun addIdentity(identity: RpIdentity) = _identities.add(identity) - @Suppress("UNCHECKED_CAST") - override fun getIdentity(type: RpIdentity.RpIdentityType) = - _identities.firstOrNull { it.type == type } - ?: error("No identity of type $type found for player $uuid") - - override suspend fun createIdentity(identity: T) = - rpPlayerManagerImpl.createIdentity(this, identity) - - override suspend fun createOrUpdateIdentity(identity: T) = - rpPlayerManagerImpl.createOrUpdateIdentity(this, identity) + suspend fun createOrUpdateIdentity(identity: T) = + identityService.createOrUpdateIdentity(identity) - override suspend fun updateIdentity(identity: T) = - rpPlayerManagerImpl.updateIdentity(this, identity) - - override suspend fun updateUsername(username: String) = - rpPlayerManagerImpl.updateUsername(this, username) + fun getIdentity(type: RpIdentityType) = _identities.find { it.type == type } override suspend fun getBalance(balanceType: BalanceType) = activeIdentity?.getBalance(balanceType) @@ -80,15 +74,10 @@ class RpPlayerImpl( ) = activeIdentity?.getBalanceHistory(balanceType, limit) ?: error("Tried accessing balance history of a player without an active identity $uuid") - override fun getIdentity(clazz: Class) = identities.firstOrNull { - clazz.isAssignableFrom(it.javaClass) - } + fun getIdentity(clazz: Class) = + identities.find { clazz.isAssignableFrom(it.javaClass) } - override fun hasCompletedCitizenship() = getIdentity() != null - - override val licenses - get() = activeIdentity?.licenses - ?: error("Tried accessing licenses of a player without an active identity $uuid") + fun hasCompletedCitizenship() = getIdentity(RpIdentityType.CIVILIAN) != null override suspend fun addLicense(license: License) = activeIdentity?.addLicense(license) @@ -117,9 +106,10 @@ class RpPlayerImpl( override fun asComponent() = buildText { val activeIdentity = activeIdentity + val name = cloudPlayer.player?.name if (activeIdentity == null) { - variableKey(username ?: uuid.toString()) + variableKey(name ?: uuid.toString()) return@buildText } @@ -134,26 +124,15 @@ class RpPlayerImpl( variableValue(uuid.toString()) appendNewline(2) - username?.let { + name?.let { variableKey("Username: ") variableValue(it) } }) } - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is RpPlayerImpl) return false - - if (uuid != other.uuid) return false - - return true - } - - override fun hashCode() = uuid.hashCode() - - override fun toString(): String { - return "RpPlayerImpl(uuid=$uuid, createdAt=$createdAt, updatedAt=$updatedAt, identities=$identities, username=$username, activeIdentity=$activeIdentity, licenses=$licenses)" + companion object { + private val identityService get() = RoleplayApplication.context.getBean() + operator fun get(uuid: UUID) = RpPlayer[uuid] as PaperRpPlayer } - } \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/PaperRpPlayerManager.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/PaperRpPlayerManager.kt new file mode 100644 index 0000000..b976a5e --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/PaperRpPlayerManager.kt @@ -0,0 +1,20 @@ +package dev.slne.surf.roleplay.paper.player + +import dev.slne.surf.roleplay.core.common.player.RpPlayer +import dev.slne.surf.roleplay.core.common.player.RpPlayerManager +import dev.slne.surf.roleplay.paper.player.identity.RpIdentity +import dev.slne.surf.surfapi.bukkit.api.extensions.server +import io.papermc.paper.datacomponent.item.attribute.AttributeModifierDisplay.override +import it.unimi.dsi.fastutil.objects.ObjectList +import org.springframework.stereotype.Component +import java.util.* + +@Component +class PaperRpPlayerManager : RpPlayerManager() { + override val players get() = super.players as ObjectList + + override fun createPlayer(uuid: UUID) = PaperRpPlayer(uuid) + override fun onlineUuids() = server.onlinePlayers.map { it.uniqueId } + + +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/PlayerIdentityFetcher.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/PlayerIdentityFetcher.kt new file mode 100644 index 0000000..d28264c --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/PlayerIdentityFetcher.kt @@ -0,0 +1,23 @@ +package dev.slne.surf.roleplay.paper.player + +import dev.slne.surf.cloud.api.common.player.OfflineCloudPlayer +import dev.slne.surf.cloud.api.common.player.task.PrePlayerJoinTask +import dev.slne.surf.surfapi.core.api.util.logger +import org.springframework.stereotype.Component + +@Component +class PlayerIdentityFetcher : PrePlayerJoinTask { + private val log = logger() + + override suspend fun preJoin(player: OfflineCloudPlayer): PrePlayerJoinTask.Result { + try { + PaperRpPlayer[player.uuid].fetchIdentities() + return PrePlayerJoinTask.Result.ALLOWED + } catch (e: Throwable) { + log.atSevere() + .withCause(e) + .log("Failed to fetch player identity for ${player.uuid}") + return PrePlayerJoinTask.Result.ERROR + } + } +} \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/events/RpPlayerDeathEvent.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/events/RpPlayerDeathEvent.kt similarity index 55% rename from surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/events/RpPlayerDeathEvent.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/events/RpPlayerDeathEvent.kt index abd8a8c..03e7588 100644 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/events/RpPlayerDeathEvent.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/events/RpPlayerDeathEvent.kt @@ -1,7 +1,8 @@ -package dev.slne.surf.roleplay.api.player.events +package dev.slne.surf.roleplay.paper.player.events -import dev.slne.surf.roleplay.api.events.RpEvent -import dev.slne.surf.roleplay.api.player.RpPlayer +import dev.slne.surf.cloud.api.common.event.CloudEvent +import dev.slne.surf.roleplay.paper.player.PaperRpPlayer +import dev.slne.surf.roleplay.paper.player.rpPlayer import org.bukkit.block.Block import org.bukkit.entity.Entity import org.bukkit.entity.Player @@ -9,10 +10,19 @@ import org.bukkit.event.entity.EntityDamageByBlockEvent import org.bukkit.event.entity.EntityDamageByEntityEvent import org.bukkit.event.entity.PlayerDeathEvent +/** + * Event triggered when a player dies in the game. + * This event provides information about the player who died, the entity or block that caused the death, + * and allows access to the killer's RpPlayer instance if applicable. + * + * @property player The RpPlayer instance representing the player who died. + * @property bukkitEvent The original Bukkit PlayerDeathEvent that this event wraps. + */ class RpPlayerDeathEvent( - val rpPlayer: RpPlayer, + source: Any, + val player: PaperRpPlayer, bukkitEvent: PlayerDeathEvent -) : RpEvent() { +) : CloudEvent(source) { var killerEntity: Entity? private set @@ -20,7 +30,7 @@ class RpPlayerDeathEvent( var killerBlock: Block? = null private set - suspend fun killerRpPlayer() = (killerEntity as? Player)?.let { RpPlayer[it.uniqueId] } + fun killerRpPlayer() = (killerEntity as? Player)?.rpPlayer init { val player = bukkitEvent.player diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/events/RpPlayerJoinEvent.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/events/RpPlayerJoinEvent.kt new file mode 100644 index 0000000..527ed20 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/events/RpPlayerJoinEvent.kt @@ -0,0 +1,9 @@ +package dev.slne.surf.roleplay.paper.player.events + +import dev.slne.surf.cloud.api.common.event.CloudEvent +import dev.slne.surf.roleplay.paper.player.PaperRpPlayer + +class RpPlayerJoinEvent( + source: Any, + val player: PaperRpPlayer, +) : CloudEvent(source) \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/events/RpPlayerQuitEvent.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/events/RpPlayerQuitEvent.kt new file mode 100644 index 0000000..6fe8280 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/events/RpPlayerQuitEvent.kt @@ -0,0 +1,9 @@ +package dev.slne.surf.roleplay.paper.player.events + +import dev.slne.surf.cloud.api.common.event.CloudEvent +import dev.slne.surf.roleplay.core.common.player.RpPlayer + +class RpPlayerQuitEvent( + source: Any, + val player: RpPlayer, +) : CloudEvent(source) \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/PaperIdentityService.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/PaperIdentityService.kt new file mode 100644 index 0000000..d06d8ba --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/PaperIdentityService.kt @@ -0,0 +1,25 @@ +package dev.slne.surf.roleplay.paper.player.identity + +import dev.slne.surf.cloud.api.client.netty.packet.fireAndAwaitOrThrow +import dev.slne.surf.roleplay.core.common.network.packets.ServerboundCreateOrUpdateIdentityPacket +import dev.slne.surf.roleplay.core.common.network.packets.ServerboundFetchIdentitiesByUuidPacket +import org.springframework.stereotype.Service +import java.util.* + +@Service +class PaperIdentityService { + + suspend fun fetchIdentities(uuid: UUID) = ServerboundFetchIdentitiesByUuidPacket(uuid) + .fireAndAwaitOrThrow() + .identies + .map(RpIdentity::fromNetwork) + .toSet() + + @Suppress("UNCHECKED_CAST") + suspend fun createOrUpdateIdentity( + identity: T + ): T = ServerboundCreateOrUpdateIdentityPacket(identity.toNetwork()) + .fireAndAwaitOrThrow() + .identity + .let(RpIdentity::fromNetwork) as T +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/RpIdentity.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/RpIdentity.kt new file mode 100644 index 0000000..088943b --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/RpIdentity.kt @@ -0,0 +1,236 @@ +package dev.slne.surf.roleplay.paper.player.identity + +import dev.slne.surf.roleplay.RoleplayApplication +import dev.slne.surf.roleplay.core.common.player.RpPlayer +import dev.slne.surf.roleplay.core.common.player.identity.NetworkIdentity +import dev.slne.surf.roleplay.core.common.player.identity.RpIdentityType +import dev.slne.surf.roleplay.core.common.transaction.HasRpTransactions +import dev.slne.surf.roleplay.core.common.transaction.RpTransaction +import dev.slne.surf.roleplay.core.common.transaction.utils.BalanceType +import dev.slne.surf.roleplay.paper.player.PaperRpPlayer +import dev.slne.surf.roleplay.paper.player.identity.identities.CivilianIdentity +import dev.slne.surf.roleplay.paper.player.identity.identities.PoliceIdentity +import dev.slne.surf.roleplay.paper.player.identity.identities.RescueServiceIdentity +import dev.slne.surf.roleplay.paper.player.license.* +import dev.slne.surf.roleplay.paper.player.license.events.RpPlayerLicenseAddedEvent +import dev.slne.surf.roleplay.paper.player.license.events.RpPlayerLicenseRemovedEvent +import dev.slne.surf.roleplay.paper.player.license.utils.LicenseCreateResult +import dev.slne.surf.roleplay.paper.player.license.utils.LicenseRemovedReason +import dev.slne.surf.roleplay.paper.player.license.utils.UnobtainableReason +import dev.slne.surf.surfapi.core.api.util.freeze +import dev.slne.surf.surfapi.core.api.util.mutableObject2ObjectMapOf +import dev.slne.surf.surfapi.core.api.util.mutableObjectSetOf +import dev.slne.surf.surfapi.core.api.util.objectSetOf +import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet +import kotlinx.serialization.Contextual +import kotlinx.serialization.Transient +import org.springframework.beans.factory.getBean +import java.time.LocalDate +import java.time.ZonedDateTime +import java.util.* + +abstract class RpIdentity : HasRpTransactions, HasLicenses { + abstract val uuid: @Contextual UUID + abstract val type: RpIdentityType + abstract var firstName: String + abstract var lastName: String + abstract var dateOfBirth: @Contextual LocalDate + open val createdAt: @Contextual ZonedDateTime = ZonedDateTime.now() + open var updatedAt: @Contextual ZonedDateTime = ZonedDateTime.now() + + val player get() = PaperRpPlayer[uuid] + + @Transient + private val _licenses = mutableObjectSetOf() + + @Transient + override val licenses = _licenses.freeze() + + abstract fun toNetwork(): NetworkIdentity + + fun addLicense(license: IdentityLicense) { + _licenses.add(license) + } + + suspend fun updateInformation(identity: T.() -> Unit): T { + TODO("Not yet implemented") + } + + override suspend fun addLicense(license: License): LicenseCreateResult { + val unobtainableReasons = license.canObtain(this) + + if (unobtainableReasons.isNotEmpty()) { + return LicenseCreateResult(false, unobtainableReasons, null) + } + + val expiresAt = if (license is ExpirableLicense) { + ZonedDateTime.now().plusSeconds(license.expiresIn.inWholeSeconds) + } else { + null + } + + val playerLicense = IdentityLicense( + identity = this, + license = license, + expiresAt = expiresAt, + ) + + val event = RpPlayerLicenseAddedEvent( + source = this, + player = player, + identity = this, + license = playerLicense, + ).also { it.post() } + + if (event.isCancelled) { + return LicenseCreateResult( + false, + objectSetOf(UnobtainableReason.EventCancelled(event.cancelReason)), + null + ) + } + + player.removeCashBalance(license.price) + + val createdPlayerLicense = licenseService.createLicense(playerLicense) + _licenses.add(createdPlayerLicense) + + return LicenseCreateResult( + true, + objectSetOf(), + createdPlayerLicense + ) + } + + override suspend fun removeLicense(license: License, reason: LicenseRemovedReason): Boolean { + val playerLicense = getLicense(license.javaClass) ?: return false + + val event = RpPlayerLicenseRemovedEvent( + source = this, + player = player, + identity = this, + license = playerLicense, + reason = reason + ).also { it.post() } + + if (event.isCancelled) { + return false + } + + val result = licenseService.removeLicense(this, license) + + if (result) { + _licenses.removeIf { it.license == license } + } + + return result + } + + override suspend fun confiscateLicense( + identity: RpIdentity, + license: License, + confiscatedBy: RpPlayer, + confiscatedReason: String + ) = licenseService.confiscateLicense(identity, license, confiscatedBy, confiscatedReason) + + override fun getLicense(license: Class) = + _licenses.firstOrNull { it.license::class.java == license } + + override fun hasLicense(license: Class) = + _licenses.any { it.license::class.java == license } + + @Transient + private val currencyMap = mutableObject2ObjectMapOf( + BalanceType.CASH to 0, + BalanceType.BANK to 0, + BalanceType.CRYPTO to 0 + ) + + override suspend fun getBalance(balanceType: BalanceType): Int { + val currencyName = balanceType.getCurrencyName(type) + ?: throw IllegalArgumentException("Unknown balance type: $balanceType") + + return currencyMap[balanceType] ?: 0 + } + + override suspend fun addBalance( + balanceType: BalanceType, + amount: Int + ): Boolean { + val currencyName = balanceType.getCurrencyName(type) + ?: throw IllegalArgumentException("Unknown balance type: $balanceType") + + return if (amount > 0) { + currencyMap[balanceType] = (currencyMap[balanceType] ?: 0) + amount + true + } else { + false + } + } + + override suspend fun removeBalance( + balanceType: BalanceType, + amount: Int + ): Boolean { + val currencyName = balanceType.getCurrencyName(type) + ?: throw IllegalArgumentException("Unknown balance type: $balanceType") + + return if (amount > 0 && (currencyMap[balanceType] ?: 0) >= amount) { + currencyMap[balanceType] = (currencyMap[balanceType] ?: 0) - amount + true + } else { + false + } + } + + override suspend fun getBalanceHistory( + balanceType: BalanceType, + limit: Int + ): ObjectLinkedOpenHashSet { + val currencyName = balanceType.getCurrencyName(type) + ?: throw IllegalArgumentException("Unknown balance type: $balanceType") + + return ObjectLinkedOpenHashSet() + } + + override fun toString(): String { + return "RpIdentity(uuid=$uuid, type=$type, firstName='$firstName', lastName='$lastName', dateOfBirth=$dateOfBirth, createdAt=$createdAt, updatedAt=$updatedAt)" + } + + companion object { + private val licenseService get() = RoleplayApplication.context.getBean() + + + fun fromNetwork(network: NetworkIdentity) = when (network) { + is NetworkIdentity.Civilian -> CivilianIdentity( + network.uuid, + network.firstName, + network.lastName, + network.dateOfBirth, + network.createdAt, + network.updatedAt + ) + + is NetworkIdentity.Police -> PoliceIdentity( + network.uuid, + network.firstName, + network.lastName, + network.dateOfBirth, + network.badgeNumber, + network.rank, + network.createdAt, + network.updatedAt + ) + + is NetworkIdentity.RescueService -> RescueServiceIdentity( + network.uuid, + network.firstName, + network.lastName, + network.dateOfBirth, + network.rank, + network.createdAt, + network.updatedAt + ) + } + } +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/identity/dialogs/IdentitySelectorDialog.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/dialogs/IdentitySelectorDialog.kt similarity index 92% rename from surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/identity/dialogs/IdentitySelectorDialog.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/dialogs/IdentitySelectorDialog.kt index 54099e6..a22922a 100644 --- a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/identity/dialogs/IdentitySelectorDialog.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/dialogs/IdentitySelectorDialog.kt @@ -1,10 +1,10 @@ @file:Suppress("UnstableApiUsage") @file:OptIn(NmsUseWithCaution::class) -package dev.slne.surf.roleplay.paper.identity.dialogs +package dev.slne.surf.roleplay.paper.player.identity.dialogs import com.github.shynixn.mccoroutine.folia.launch -import dev.slne.surf.roleplay.api.player.RpPlayer +import dev.slne.surf.roleplay.paper.player.PaperRpPlayer import dev.slne.surf.roleplay.paper.plugin import dev.slne.surf.surfapi.bukkit.api.dialog.base import dev.slne.surf.surfapi.bukkit.api.dialog.builder.actionButton @@ -15,7 +15,7 @@ import dev.slne.surf.surfapi.bukkit.api.nms.NmsUseWithCaution import dev.slne.surf.surfapi.core.api.messages.adventure.appendNewline import io.papermc.paper.registry.data.dialog.DialogBase -fun createIdentitySelectorDialog(player: RpPlayer) = dialog { +fun createIdentitySelectorDialog(player: PaperRpPlayer) = dialog { val identities = player.identities base { @@ -56,7 +56,7 @@ fun createIdentitySelectorDialog(player: RpPlayer) = dialog { } private fun createIdentitySelectorButtons( - player: RpPlayer, + player: PaperRpPlayer, ) = player.identities.map { identity -> actionButton { label(identity.type.asComponent()) diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/identities/CivilianIdentity.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/identities/CivilianIdentity.kt new file mode 100644 index 0000000..46a1b26 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/identities/CivilianIdentity.kt @@ -0,0 +1,33 @@ +package dev.slne.surf.roleplay.paper.player.identity.identities + +import dev.slne.surf.roleplay.core.common.player.identity.NetworkIdentity +import dev.slne.surf.roleplay.core.common.player.identity.RpIdentityType +import dev.slne.surf.roleplay.paper.player.identity.RpIdentity +import kotlinx.serialization.Contextual +import java.time.LocalDate +import java.time.ZonedDateTime +import java.util.* + +class CivilianIdentity( + override val uuid: @Contextual UUID, + override var firstName: String, + override var lastName: String, + override var dateOfBirth: @Contextual LocalDate, + override val createdAt: @Contextual ZonedDateTime = ZonedDateTime.now(), + override var updatedAt: @Contextual ZonedDateTime = ZonedDateTime.now() +) : RpIdentity() { + override val type = RpIdentityType.CIVILIAN + + override fun toNetwork() = NetworkIdentity.Civilian( + uuid = uuid, + firstName = firstName, + lastName = lastName, + dateOfBirth = dateOfBirth, + createdAt = createdAt, + updatedAt = updatedAt + ) + + override fun toString(): String { + return "CivilianIdentity() ${super.toString()}" + } +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/identities/PoliceIdentity.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/identities/PoliceIdentity.kt new file mode 100644 index 0000000..ac23bd4 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/identities/PoliceIdentity.kt @@ -0,0 +1,37 @@ +package dev.slne.surf.roleplay.paper.player.identity.identities + +import dev.slne.surf.roleplay.core.common.player.identity.NetworkIdentity +import dev.slne.surf.roleplay.core.common.player.identity.RpIdentityType +import dev.slne.surf.roleplay.paper.player.identity.RpIdentity +import kotlinx.serialization.Contextual +import java.time.LocalDate +import java.time.ZonedDateTime +import java.util.* + +class PoliceIdentity( + override val uuid: @Contextual UUID, + override var firstName: String, + override var lastName: String, + override var dateOfBirth: @Contextual LocalDate, + val badgeNumber: String, + val rank: String, + override val createdAt: @Contextual ZonedDateTime = ZonedDateTime.now(), + override var updatedAt: @Contextual ZonedDateTime = ZonedDateTime.now() +) : RpIdentity() { + override val type = RpIdentityType.POLICE + + override fun toNetwork() = NetworkIdentity.Police( + uuid = uuid, + firstName = firstName, + lastName = lastName, + dateOfBirth = dateOfBirth, + badgeNumber = badgeNumber, + rank = rank, + createdAt = createdAt, + updatedAt = updatedAt + ) + + override fun toString(): String { + return "PoliceIdentity(rank='$rank') ${super.toString()}" + } +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/identities/RescueServiceIdentity.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/identities/RescueServiceIdentity.kt new file mode 100644 index 0000000..8191c86 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/identities/RescueServiceIdentity.kt @@ -0,0 +1,35 @@ +package dev.slne.surf.roleplay.paper.player.identity.identities + +import dev.slne.surf.roleplay.core.common.player.identity.NetworkIdentity +import dev.slne.surf.roleplay.core.common.player.identity.RpIdentityType +import dev.slne.surf.roleplay.paper.player.identity.RpIdentity +import kotlinx.serialization.Contextual +import java.time.LocalDate +import java.time.ZonedDateTime +import java.util.* + +class RescueServiceIdentity( + override val uuid: @Contextual UUID, + override var firstName: String, + override var lastName: String, + override var dateOfBirth: @Contextual LocalDate, + val rank: String, + override val createdAt: @Contextual ZonedDateTime = ZonedDateTime.now(), + override var updatedAt: @Contextual ZonedDateTime = ZonedDateTime.now() +) : RpIdentity() { + override val type = RpIdentityType.RESCUE_SERVICE + + override fun toNetwork() = NetworkIdentity.RescueService( + uuid = uuid, + firstName = firstName, + lastName = lastName, + dateOfBirth = dateOfBirth, + rank = rank, + createdAt = createdAt, + updatedAt = updatedAt + ) + + override fun toString(): String { + return "RescueServiceIdentity(rank='$rank') ${super.toString()}" + } +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/listener/IdentityOnlineListener.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/listener/IdentityOnlineListener.kt new file mode 100644 index 0000000..0a63657 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/identity/listener/IdentityOnlineListener.kt @@ -0,0 +1,28 @@ +package dev.slne.surf.roleplay.paper.player.identity.listener + +import dev.slne.surf.cloud.api.common.event.CloudEventHandler +import dev.slne.surf.roleplay.paper.player.events.RpPlayerJoinEvent +import dev.slne.surf.roleplay.paper.player.identity.dialogs.createIdentitySelectorDialog +import org.springframework.stereotype.Component + +@Suppress("unused") +@Component +class IdentityOnlineListener { + + @CloudEventHandler + fun onRpPlayerJoin(event: RpPlayerJoinEvent) { + val player = event.player + val identities = player.identities + + if (identities.isEmpty()) return + + if (identities.size == 1) { + val identity = identities.first() + player.setActiveIdentity(identity) + + return + } + + player.player?.showDialog(createIdentitySelectorDialog(player)) + } +} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/ExpirableLicenseImpl.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/ExpirableLicense.kt similarity index 51% rename from surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/ExpirableLicenseImpl.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/ExpirableLicense.kt index d337bb7..befa73b 100644 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/ExpirableLicenseImpl.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/ExpirableLicense.kt @@ -1,28 +1,25 @@ -package dev.slne.surf.roleplay.core.player.license +package dev.slne.surf.roleplay.paper.player.license -import dev.slne.surf.roleplay.api.player.license.ExpirableLicense -import dev.slne.surf.roleplay.api.player.license.License -import dev.slne.surf.roleplay.core.player.license.utils.LicensePermissionRegistry -import dev.slne.surf.surfapi.bukkit.api.builder.LoreBuilder +import dev.slne.surf.surfapi.core.api.messages.builder.SurfComponentBuilder import dev.slne.surf.surfapi.core.api.util.objectSetOf import it.unimi.dsi.fastutil.objects.ObjectSet import net.kyori.adventure.key.Key import net.kyori.adventure.text.Component import kotlin.time.Duration -abstract class ExpirableLicenseImpl( +abstract class ExpirableLicense( key: Key, displayName: Component, - description: LoreBuilder.() -> Unit, + description: SurfComponentBuilder.() -> Unit, price: Int, - override val expiresIn: Duration, + val expiresIn: Duration, dependencies: ObjectSet = objectSetOf(), permission: String = LicensePermissionRegistry.createLicensePermission(key) -) : LicenseImpl( +) : License( key, displayName, description, price, dependencies, permission -), ExpirableLicense \ No newline at end of file +) \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/HasLicenses.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/HasLicenses.kt similarity index 86% rename from surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/HasLicenses.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/HasLicenses.kt index 5d2fd62..a9451e7 100644 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/HasLicenses.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/HasLicenses.kt @@ -1,10 +1,10 @@ -package dev.slne.surf.roleplay.api.player.license +package dev.slne.surf.roleplay.paper.player.license -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.api.player.license.utils.LicenseCreateResult -import dev.slne.surf.roleplay.api.player.license.utils.LicenseRemovedReason -import dev.slne.surf.roleplay.api.player.license.utils.UnobtainableReason +import dev.slne.surf.roleplay.core.common.player.RpPlayer +import dev.slne.surf.roleplay.paper.player.identity.RpIdentity +import dev.slne.surf.roleplay.paper.player.license.utils.LicenseCreateResult +import dev.slne.surf.roleplay.paper.player.license.utils.LicenseRemovedReason +import dev.slne.surf.roleplay.paper.player.license.utils.UnobtainableReason import it.unimi.dsi.fastutil.objects.ObjectSet import org.jetbrains.annotations.Unmodifiable @@ -73,6 +73,8 @@ interface HasLicenses { * @return A boolean indicating whether the player has the license. */ fun hasLicense(license: License) = hasLicense(license::class.java) + + fun getExpiredLicenses() = licenses.filter { it.isExpired } } /** diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/IdentityLicense.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/IdentityLicense.kt similarity index 65% rename from surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/IdentityLicense.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/IdentityLicense.kt index 94477db..adc5023 100644 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/IdentityLicense.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/IdentityLicense.kt @@ -1,6 +1,7 @@ -package dev.slne.surf.roleplay.api.player.license +package dev.slne.surf.roleplay.paper.player.license -import dev.slne.surf.roleplay.api.player.identity.RpIdentity +import dev.slne.surf.roleplay.core.common.player.license.NetworkIdentityLicense +import dev.slne.surf.roleplay.paper.player.identity.RpIdentity import java.time.ZonedDateTime /** @@ -10,7 +11,7 @@ import java.time.ZonedDateTime * the expiration time, and the creation time. * * @property license The [License] associated with this identity. - * @property identity The [RpIdentity] associated with this license. + * @property identity The [dev.slne.surf.roleplay.paper.player.identity.RpIdentity] associated with this license. * @property expiresAt The expiration time of the license, if applicable. Defaults to null if the license does not expire. */ data class IdentityLicense( @@ -24,32 +25,20 @@ data class IdentityLicense( */ val isExpired get() = expiresAt?.isBefore(ZonedDateTime.now()) ?: false - override fun equals(other: Any?): Boolean { - if (this === other) return true - if (other !is IdentityLicense) return false - - if (license != other.license) return false - if (identity != other.identity) return false - - return true - } - - override fun hashCode(): Int { - var result = license.hashCode() - result = 31 * result + identity.hashCode() - return result - } - - override fun toString(): String { - return "IdentityLicense(license=$license, expiresAt=$expiresAt, createdAt=$createdAt, isExpired=$isExpired)" - } + fun toNetwork() = NetworkIdentityLicense( + identity.uuid, + identity.type, + license.key, + expiresAt, + createdAt + ) companion object { /** - * Creates an [IdentityLicense] from a [License] and an [RpIdentity]. + * Creates an [IdentityLicense] from a [License] and an [dev.slne.surf.roleplay.paper.player.identity.RpIdentity]. * * @param license The [License] to create the identity license from. - * @param identity The [RpIdentity] associated with the license. + * @param identity The [dev.slne.surf.roleplay.paper.player.identity.RpIdentity] associated with the license. * @param createdAt The creation time of the identity license, defaults to the current time. * @return A new [IdentityLicense] instance. */ @@ -69,5 +58,4 @@ data class IdentityLicense( ) } - } \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/License.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/License.kt new file mode 100644 index 0000000..8b51f07 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/License.kt @@ -0,0 +1,70 @@ +package dev.slne.surf.roleplay.paper.player.license + +import dev.slne.surf.roleplay.paper.player.identity.RpIdentity +import dev.slne.surf.roleplay.paper.player.license.utils.UnobtainableReason +import dev.slne.surf.surfapi.core.api.messages.adventure.buildText +import dev.slne.surf.surfapi.core.api.messages.builder.SurfComponentBuilder +import dev.slne.surf.surfapi.core.api.util.objectSetOf +import dev.slne.surf.surfapi.core.api.util.toObjectSet +import it.unimi.dsi.fastutil.objects.ObjectSet +import net.kyori.adventure.key.Key +import net.kyori.adventure.text.Component +import org.springframework.beans.factory.annotation.Autowired + +abstract class License( + val key: Key, + val displayName: Component, + description: SurfComponentBuilder.() -> Unit, + val price: Int, + val dependencies: ObjectSet = objectSetOf(), + val permission: String = LicensePermissionRegistry.createLicensePermission(key) +) { + + @Autowired + private lateinit var licenseService: PaperLicenseService + + val description = buildText(description) + val children + get() = licenseService.all() + .filter { this in it.dependencies } + .toObjectSet() + + suspend fun canObtain(identity: RpIdentity) = buildSet { + val player = identity.player + val onlineCloudPlayer = player.cloudPlayer.player + + if (onlineCloudPlayer?.hasPermission(permission) != true) { + add(UnobtainableReason.NoPermissions) + } + + if (identity.hasLicense(this@License)) { + add(UnobtainableReason.AlreadyHasLicense) + } + + val missingDependencies = dependencies.filterNot { identity.hasLicense(it) } + if (missingDependencies.isNotEmpty()) { + add(UnobtainableReason.DependenciesNotMet(missingDependencies)) + } + + if (!player.hasCashBalance(price)) { + add(UnobtainableReason.NotEnoughCash(player.getCashBalance(), price)) + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is License) return false + + if (key != other.key) return false + + return true + } + + override fun hashCode(): Int { + return key.hashCode() + } + + override fun toString(): String { + return "License(key=$key, price=$price, dependencies=$dependencies, permission='$permission', children=$children)" + } +} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/LicenseNpc.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/LicenseNpc.kt similarity index 56% rename from surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/LicenseNpc.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/LicenseNpc.kt index f057da2..0210262 100644 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/LicenseNpc.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/LicenseNpc.kt @@ -1,12 +1,21 @@ -package dev.slne.surf.roleplay.core.player.license +package dev.slne.surf.roleplay.paper.player.license import dev.slne.surf.npc.api.dsl.npc import dev.slne.surf.npc.api.surfNpcApi -import dev.slne.surf.roleplay.core.plugin +import dev.slne.surf.roleplay.core.common.RpLifecycle +import dev.slne.surf.roleplay.paper.plugin +import org.springframework.stereotype.Component -object LicenseNpc { +@Component +class LicenseNpc : RpLifecycle { - const val NPC_NAME = "license_npc" + companion object { + const val NPC_NAME = "license_npc" + } + + override suspend fun onEnable() { + spawnNpc() + } suspend fun spawnNpc() { val npcSkin = surfNpcApi.getSkin("CastCrafter") diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/LicensePermissionRegistry.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/LicensePermissionRegistry.kt new file mode 100644 index 0000000..20bdda9 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/LicensePermissionRegistry.kt @@ -0,0 +1,8 @@ +package dev.slne.surf.roleplay.paper.player.license + +import net.kyori.adventure.key.Key + +object LicensePermissionRegistry { + fun createLicensePermission(key: Key)= + "surf.roleplay.license.${key.asString().replace(":", ".").replace("_", "-")}" +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/PaperLicenseService.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/PaperLicenseService.kt new file mode 100644 index 0000000..d885bcf --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/PaperLicenseService.kt @@ -0,0 +1,78 @@ +package dev.slne.surf.roleplay.paper.player.license + +import dev.slne.surf.cloud.api.client.netty.packet.awaitOrThrow +import dev.slne.surf.roleplay.core.common.network.packets.ServerboundCreateLicensePacket +import dev.slne.surf.roleplay.core.common.network.packets.ServerboundDeleteLicensePacket +import dev.slne.surf.roleplay.core.common.player.RpPlayer +import dev.slne.surf.roleplay.paper.player.PaperRpPlayerManager +import dev.slne.surf.roleplay.paper.player.identity.RpIdentity +import dev.slne.surf.roleplay.paper.player.license.utils.LicenseRemovedReason +import dev.slne.surf.surfapi.core.api.util.mapAsync +import org.springframework.beans.factory.ObjectProvider +import org.springframework.scheduling.annotation.Scheduled +import org.springframework.stereotype.Service +import java.util.concurrent.TimeUnit + +@Service +class PaperLicenseService( + private val licenses: ObjectProvider, + private val rpPlayerManager: PaperRpPlayerManager +) { + fun all() = licenses.asSequence() + + suspend fun createLicense(identityLicense: IdentityLicense): IdentityLicense { + ServerboundCreateLicensePacket(identityLicense.toNetwork()).awaitOrThrow() + return identityLicense + } + + suspend fun removeLicense( + identity: RpIdentity, + license: License + ): Boolean = ServerboundDeleteLicensePacket(identity.uuid, identity.type, license.key) + .awaitOrThrow() + + suspend fun confiscateLicense( + identity: RpIdentity, + license: License, + confiscatedBy: RpPlayer, + confiscatedReason: String + ): Boolean { + val player = identity.player + val parentLicense = + player.getIdentity(identity.type)?.getLicense(license::class.java) ?: return false + + val parentResult = player.removeLicense( + license, + LicenseRemovedReason.Confiscated(confiscatedBy, confiscatedReason) + ) + + val childrenResults = license.children.mapAsync { childLicense -> + if (player.hasLicense(childLicense)) { + player.removeLicense( + childLicense, + LicenseRemovedReason.ConfiscatedChild( + parentLicense, + confiscatedBy, + confiscatedReason + ) + ) + } else { + true + } + } + + return parentResult && childrenResults.all { it } + } + + fun getAllExpiredLicenses() = rpPlayerManager.players + .mapNotNull { it.activeIdentity } + .flatMap { id -> id.getExpiredLicenses().map { license -> id to license } } + + @Scheduled(fixedDelay = 1, timeUnit = TimeUnit.SECONDS) + suspend fun removeExpiredLicenses() { + getAllExpiredLicenses() + .mapAsync { (identity, license) -> + identity.removeLicense(license.license, LicenseRemovedReason.Expired) + } + } +} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/dialogs/BuyLicenseDialog.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/dialogs/BuyLicenseDialog.kt similarity index 71% rename from surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/dialogs/BuyLicenseDialog.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/dialogs/BuyLicenseDialog.kt index 429acfa..21b8023 100644 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/dialogs/BuyLicenseDialog.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/dialogs/BuyLicenseDialog.kt @@ -1,14 +1,15 @@ @file:Suppress("UnstableApiUsage") -package dev.slne.surf.roleplay.core.player.license.dialogs +package dev.slne.surf.roleplay.paper.player.license.dialogs import com.github.shynixn.mccoroutine.folia.launch -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.api.player.license.IdentityLicense -import dev.slne.surf.roleplay.api.player.license.License -import dev.slne.surf.roleplay.api.player.license.utils.UnobtainableReason -import dev.slne.surf.roleplay.core.plugin +import dev.slne.surf.roleplay.paper.player.PaperRpPlayer +import dev.slne.surf.roleplay.paper.player.identity.RpIdentity +import dev.slne.surf.roleplay.paper.player.license.IdentityLicense +import dev.slne.surf.roleplay.paper.player.license.License +import dev.slne.surf.roleplay.paper.player.license.PaperLicenseService +import dev.slne.surf.roleplay.paper.player.license.utils.UnobtainableReason +import dev.slne.surf.roleplay.paper.plugin import dev.slne.surf.surfapi.bukkit.api.dialog.base import dev.slne.surf.surfapi.bukkit.api.dialog.builder.actionButton import dev.slne.surf.surfapi.bukkit.api.dialog.dialog @@ -16,14 +17,14 @@ import dev.slne.surf.surfapi.bukkit.api.dialog.type import dev.slne.surf.surfapi.core.api.messages.adventure.appendNewline import io.papermc.paper.dialog.Dialog import io.papermc.paper.registry.data.dialog.DialogBase -import it.unimi.dsi.fastutil.objects.ObjectSet suspend fun buyLicenseDialog( - player: RpPlayer, + player: PaperRpPlayer, identity: RpIdentity, license: License, + licenseService: PaperLicenseService ): Dialog { - val canObtain = license.canObtain(identity) + val unobtainableReasons = license.canObtain(identity) return dialog { base { @@ -51,19 +52,18 @@ suspend fun buyLicenseDialog( appendLicenseDependencies(player, license.dependencies) appendNewline(2) - if (canObtain.first) { + if (unobtainableReasons.isEmpty()) { info("Klicke auf ") variableValue(""""Erwerben"""") info(", um die Lizenz zu kaufen.") } else { error("Du kannst diese Lizenz nicht erwerben:") appendNewline(2) - canObtain.second.forEachIndexed { index, reason -> + unobtainableReasons.forEachIndexed { index, reason -> if (index > 0) { appendNewline(2) } - - reason.message(this) + append(reason.message) } } } @@ -71,22 +71,23 @@ suspend fun buyLicenseDialog( } type { - if (canObtain.first) { + if (unobtainableReasons.isEmpty()) { confirmation( - buyLicenseButton(player, identity, license), - backButton(player, identity) + buyLicenseButton(player, identity, license, licenseService), + backButton(player, identity, licenseService) ) } else { - notice(backButton(player, identity)) + notice(backButton(player, identity, licenseService)) } } } } private fun buyLicenseButton( - player: RpPlayer, + player: PaperRpPlayer, identity: RpIdentity, - license: License + license: License, + licenseService: PaperLicenseService ) = actionButton { label { success("Erwerben") } tooltip { @@ -106,23 +107,32 @@ private fun buyLicenseButton( player, identity, license, - result.reason + result.reason, + licenseService ) ) return@launch } - it.showDialog(boughtLicenseNotice(player, identity, result.license!!)) + it.showDialog( + boughtLicenseNotice( + player, + identity, + result.license!!, + licenseService + ) + ) } } } } private fun boughtLicenseNotice( - player: RpPlayer, + player: PaperRpPlayer, identity: RpIdentity, - license: IdentityLicense + license: IdentityLicense, + licenseService: PaperLicenseService ): Dialog = dialog { base { title { success("Lizenz erworben") } @@ -148,7 +158,7 @@ private fun boughtLicenseNotice( action { playerCallback { - it.showDialog(myLicenseDialog(player, identity, license)) + it.showDialog(myLicenseDialog(player, identity, license, licenseService)) } } } @@ -156,10 +166,11 @@ private fun boughtLicenseNotice( } private fun cannotBuyLicenseNotice( - player: RpPlayer, + player: PaperRpPlayer, identity: RpIdentity, license: License, - reason: ObjectSet, + reason: Set, + licenseService: PaperLicenseService ): Dialog = dialog { base { title { error("Lizenz kann nicht erworben werden") } @@ -181,7 +192,7 @@ private fun cannotBuyLicenseNotice( appendNewline(2) } - unobtainableReason.message(this) + append(unobtainableReason.message) } } } @@ -199,7 +210,7 @@ private fun cannotBuyLicenseNotice( action { playerCallback { plugin.launch { - it.showDialog(buyLicenseDialog(player, identity, license)) + it.showDialog(buyLicenseDialog(player, identity, license, licenseService)) } } } @@ -207,13 +218,17 @@ private fun cannotBuyLicenseNotice( } } -private fun backButton(player: RpPlayer, identity: RpIdentity) = actionButton { +private fun backButton( + player: PaperRpPlayer, + identity: RpIdentity, + licenseService: PaperLicenseService +) = actionButton { label { text("Zurück") } tooltip { info("Klicke, um zur Übersicht der erwerbbaren Lizenzen zurückzukehren.") } action { playerCallback { - it.showDialog(buyLicensesDialog(player, identity)) + it.showDialog(buyLicensesDialog(player, identity, licenseService)) } } } \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/dialogs/BuyLicensesDialog.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/dialogs/BuyLicensesDialog.kt similarity index 53% rename from surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/dialogs/BuyLicensesDialog.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/dialogs/BuyLicensesDialog.kt index 566e147..8a04389 100644 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/dialogs/BuyLicensesDialog.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/dialogs/BuyLicensesDialog.kt @@ -1,12 +1,13 @@ @file:Suppress("UnstableApiUsage") -package dev.slne.surf.roleplay.core.player.license.dialogs +package dev.slne.surf.roleplay.paper.player.license.dialogs import com.github.shynixn.mccoroutine.folia.launch -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.api.player.license.LicenseService -import dev.slne.surf.roleplay.core.plugin +import dev.slne.surf.roleplay.paper.player.PaperRpPlayer +import dev.slne.surf.roleplay.paper.player.identity.RpIdentity +import dev.slne.surf.roleplay.paper.player.license.PaperLicenseService +import dev.slne.surf.roleplay.paper.player.license.dialogs.backButton +import dev.slne.surf.roleplay.paper.plugin import dev.slne.surf.surfapi.bukkit.api.dialog.base import dev.slne.surf.surfapi.bukkit.api.dialog.builder.actionButton import dev.slne.surf.surfapi.bukkit.api.dialog.dialog @@ -14,8 +15,12 @@ import dev.slne.surf.surfapi.bukkit.api.dialog.type import dev.slne.surf.surfapi.core.api.messages.adventure.appendNewline import io.papermc.paper.registry.data.dialog.DialogBase -fun buyLicensesDialog(player: RpPlayer, identity: RpIdentity) = dialog { - val actions = buildDialogList(player, identity) +fun buyLicensesDialog( + player: PaperRpPlayer, + identity: RpIdentity, + licenseService: PaperLicenseService +) = dialog { + val actions = buildDialogList(player, identity, licenseService) base { title { primary("Lizenzen erwerben") } @@ -42,45 +47,50 @@ fun buyLicensesDialog(player: RpPlayer, identity: RpIdentity) = dialog { type { if (actions.isEmpty()) { - notice(backButton(player, identity)) + notice(backButton(player, identity, licenseService)) } else { multiAction { actions.forEach { action(it) } columns(1) - exitAction(backButton(player, identity)) + exitAction(backButton(player, identity, licenseService)) } } } } -private fun backButton(player: RpPlayer, identity: RpIdentity) = actionButton { +private fun backButton( + player: PaperRpPlayer, + identity: RpIdentity, + licenseService: PaperLicenseService +) = actionButton { label { text("Zurück") } tooltip { info("Klicke, um zum Hauptmenü zurückzukehren.") } action { playerCallback { - it.showDialog(licenseDialog(player, identity)) + it.showDialog(licenseDialog(player, identity, licenseService)) } } } private fun buildDialogList( - player: RpPlayer, - identity: RpIdentity -) = LicenseService.licenses.filterNot { - identity.hasLicense(it) -}.map { license -> - actionButton { - label(license.displayName) - tooltip { info("Klicke, um zur Detailansicht zu gelangen.") } - width(300) + player: PaperRpPlayer, + identity: RpIdentity, + licenseService: PaperLicenseService +) = licenseService.all() + .filterNot { identity.hasLicense(it) } + .map { license -> + actionButton { + label(license.displayName) + tooltip { info("Klicke, um zur Detailansicht zu gelangen.") } + width(300) - action { - playerCallback { - plugin.launch { - it.showDialog(buyLicenseDialog(player, identity, license)) + action { + playerCallback { + plugin.launch { + it.showDialog(buyLicenseDialog(player, identity, license, licenseService)) + } } } } - } -} \ No newline at end of file + }.toList() \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/dialogs/LicenseDialog.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/dialogs/LicenseDialog.kt similarity index 75% rename from surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/dialogs/LicenseDialog.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/dialogs/LicenseDialog.kt index 3905a20..af37e07 100644 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/dialogs/LicenseDialog.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/dialogs/LicenseDialog.kt @@ -1,12 +1,12 @@ @file:Suppress("UnstableApiUsage") -package dev.slne.surf.roleplay.core.player.license.dialogs +package dev.slne.surf.roleplay.paper.player.license.dialogs -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.api.player.license.IdentityLicense -import dev.slne.surf.roleplay.api.player.license.License -import dev.slne.surf.surfapi.bukkit.api.builder.LoreBuilder +import dev.slne.surf.roleplay.paper.player.PaperRpPlayer +import dev.slne.surf.roleplay.paper.player.identity.RpIdentity +import dev.slne.surf.roleplay.paper.player.license.IdentityLicense +import dev.slne.surf.roleplay.paper.player.license.License +import dev.slne.surf.roleplay.paper.player.license.PaperLicenseService import dev.slne.surf.surfapi.bukkit.api.dialog.base import dev.slne.surf.surfapi.bukkit.api.dialog.builder.actionButton import dev.slne.surf.surfapi.bukkit.api.dialog.dialog @@ -25,7 +25,7 @@ import java.time.LocalDateTime import java.time.format.DateTimeFormatter fun SurfComponentBuilder.appendLicenseDependencies( - player: RpPlayer, + player: PaperRpPlayer, dependencies: ObjectSet ) { variableKey("Voraussetzungen: ") @@ -51,13 +51,7 @@ fun SurfComponentBuilder.appendLicenseDependencies( fun SurfComponentBuilder.appendLicenseDescription(license: License) { variableKey("Beschreibung:") appendNewline() - - LoreBuilder().apply(license.description).build().forEachIndexed { index, line -> - if (index > 0) { - appendNewline() - } - append(line) - } + append(license.description) } private val formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm") @@ -129,7 +123,11 @@ private fun buildRelativeString(from: LocalDateTime, to: LocalDateTime): String return if (to.isAfter(from)) "in $joined" else "vor $joined" } -fun licenseDialog(player: RpPlayer, identity: RpIdentity) = dialog { +fun licenseDialog( + player: PaperRpPlayer, + identity: RpIdentity, + licenseService: PaperLicenseService +) = dialog { base { title { primary("Lizenzsystem v1.0") } afterAction(DialogBase.DialogAfterAction.NONE) @@ -161,32 +159,42 @@ fun licenseDialog(player: RpPlayer, identity: RpIdentity) = dialog { type { multiAction { columns(1) - action(myLicensesButton(player, identity)) - action(buyLicensesButton(player, identity)) + action(myLicensesButton(player, identity, licenseService)) + action(buyLicensesButton(player, identity, licenseService)) } } } -private fun myLicensesButton(player: RpPlayer, identity: RpIdentity): ActionButton = actionButton { - label { text("Meine Lizenzen") } - tooltip { info("Klicke, um deine Lizenzen zu sehen.") } - width(400) - - action { - playerCallback { - it.showDialog(myLicensesDialog(player, identity)) +private fun myLicensesButton( + player: PaperRpPlayer, + identity: RpIdentity, + licenseService: PaperLicenseService +): ActionButton = + actionButton { + label { text("Meine Lizenzen") } + tooltip { info("Klicke, um deine Lizenzen zu sehen.") } + width(400) + + action { + playerCallback { + it.showDialog(myLicensesDialog(player, identity, licenseService)) + } } } -} - -private fun buyLicensesButton(player: RpPlayer, identity: RpIdentity): ActionButton = actionButton { - label { text("Lizenz erwerben") } - tooltip { info("Klicke, um eine Lizenz zu erwerben.") } - width(400) - action { - playerCallback { - it.showDialog(buyLicensesDialog(player, identity)) +private fun buyLicensesButton( + player: PaperRpPlayer, + identity: RpIdentity, + licenseService: PaperLicenseService +): ActionButton = + actionButton { + label { text("Lizenz erwerben") } + tooltip { info("Klicke, um eine Lizenz zu erwerben.") } + width(400) + + action { + playerCallback { + it.showDialog(buyLicensesDialog(player, identity, licenseService)) + } } - } -} \ No newline at end of file + } \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/dialogs/MyLicenseDialog.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/dialogs/MyLicenseDialog.kt similarity index 77% rename from surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/dialogs/MyLicenseDialog.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/dialogs/MyLicenseDialog.kt index 7de80df..a743e4b 100644 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/dialogs/MyLicenseDialog.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/dialogs/MyLicenseDialog.kt @@ -1,10 +1,11 @@ @file:Suppress("UnstableApiUsage") -package dev.slne.surf.roleplay.core.player.license.dialogs +package dev.slne.surf.roleplay.paper.player.license.dialogs -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.identity.RpIdentity -import dev.slne.surf.roleplay.api.player.license.IdentityLicense +import dev.slne.surf.roleplay.paper.player.PaperRpPlayer +import dev.slne.surf.roleplay.paper.player.identity.RpIdentity +import dev.slne.surf.roleplay.paper.player.license.IdentityLicense +import dev.slne.surf.roleplay.paper.player.license.PaperLicenseService import dev.slne.surf.surfapi.bukkit.api.dialog.base import dev.slne.surf.surfapi.bukkit.api.dialog.dialog import dev.slne.surf.surfapi.bukkit.api.dialog.type @@ -13,9 +14,10 @@ import io.papermc.paper.dialog.Dialog import io.papermc.paper.registry.data.dialog.DialogBase fun myLicenseDialog( - player: RpPlayer, + player: PaperRpPlayer, identity: RpIdentity, - identityLicense: IdentityLicense + identityLicense: IdentityLicense, + licenseService: PaperLicenseService ): Dialog = dialog { val license = identityLicense.license @@ -51,7 +53,7 @@ fun myLicenseDialog( action { playerCallback { - it.showDialog(myLicensesDialog(player, identity)) + it.showDialog(myLicensesDialog(player, identity, licenseService)) } } } diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/dialogs/MyLicensesDialog.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/dialogs/MyLicensesDialog.kt similarity index 60% rename from surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/dialogs/MyLicensesDialog.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/dialogs/MyLicensesDialog.kt index 57c6add..a7d28bd 100644 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/dialogs/MyLicensesDialog.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/dialogs/MyLicensesDialog.kt @@ -1,9 +1,10 @@ @file:Suppress("UnstableApiUsage") -package dev.slne.surf.roleplay.core.player.license.dialogs +package dev.slne.surf.roleplay.paper.player.license.dialogs -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.identity.RpIdentity +import dev.slne.surf.roleplay.paper.player.PaperRpPlayer +import dev.slne.surf.roleplay.paper.player.identity.RpIdentity +import dev.slne.surf.roleplay.paper.player.license.PaperLicenseService import dev.slne.surf.surfapi.bukkit.api.dialog.base import dev.slne.surf.surfapi.bukkit.api.dialog.builder.actionButton import dev.slne.surf.surfapi.bukkit.api.dialog.dialog @@ -12,8 +13,12 @@ import dev.slne.surf.surfapi.core.api.messages.adventure.appendNewline import dev.slne.surf.surfapi.core.api.util.toObjectSet import io.papermc.paper.registry.data.dialog.DialogBase -fun myLicensesDialog(player: RpPlayer, identity: RpIdentity) = dialog { - val dialogList = buildDialogList(player, identity) +fun myLicensesDialog( + player: PaperRpPlayer, + identity: RpIdentity, + licenseService: PaperLicenseService +) = dialog { + val dialogList = buildDialogList(player, identity, licenseService) base { title { primary("Meine Lizenzen") } @@ -38,24 +43,30 @@ fun myLicensesDialog(player: RpPlayer, identity: RpIdentity) = dialog { addAll(dialogList) buttonWidth(300) columns(1) - exitAction(backButton(player, identity)) + exitAction(backButton(player, identity, licenseService)) } } } -private fun backButton(player: RpPlayer, identity: RpIdentity) = actionButton { +private fun backButton( + player: PaperRpPlayer, + identity: RpIdentity, + licenseService: PaperLicenseService +) = actionButton { label { text("Zurück") } tooltip { info("Klicke, um zum Hauptmenü zurückzukehren.") } action { playerCallback { - it.showDialog(licenseDialog(player, identity)) + it.showDialog(licenseDialog(player, identity, licenseService)) } } } private fun buildDialogList( - player: RpPlayer, identity: RpIdentity + player: PaperRpPlayer, + identity: RpIdentity, + licenseService: PaperLicenseService ) = player.licenses.map { license -> - myLicenseDialog(player, identity, license) + myLicenseDialog(player, identity, license, licenseService) }.toObjectSet() \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/events/RpPlayerLicenseAddedEvent.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/events/RpPlayerLicenseAddedEvent.kt new file mode 100644 index 0000000..3134f3f --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/events/RpPlayerLicenseAddedEvent.kt @@ -0,0 +1,15 @@ +package dev.slne.surf.roleplay.paper.player.license.events + +import dev.slne.surf.cloud.api.common.event.CancellableCloudEvent +import dev.slne.surf.roleplay.core.common.player.RpPlayer +import dev.slne.surf.roleplay.paper.player.identity.RpIdentity +import dev.slne.surf.roleplay.paper.player.license.IdentityLicense + +class RpPlayerLicenseAddedEvent( + source: Any, + val player: RpPlayer, + val identity: RpIdentity, + val license: IdentityLicense +) : CancellableCloudEvent(source) { + var cancelReason: String? = null +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/events/RpPlayerLicenseRemovedEvent.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/events/RpPlayerLicenseRemovedEvent.kt new file mode 100644 index 0000000..3fedb57 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/events/RpPlayerLicenseRemovedEvent.kt @@ -0,0 +1,15 @@ +package dev.slne.surf.roleplay.paper.player.license.events + +import dev.slne.surf.cloud.api.common.event.CancellableCloudEvent +import dev.slne.surf.roleplay.core.common.player.RpPlayer +import dev.slne.surf.roleplay.paper.player.identity.RpIdentity +import dev.slne.surf.roleplay.paper.player.license.IdentityLicense +import dev.slne.surf.roleplay.paper.player.license.utils.LicenseRemovedReason + +class RpPlayerLicenseRemovedEvent( + source: Any, + val player: RpPlayer, + val identity: RpIdentity, + val license: IdentityLicense, + val reason: LicenseRemovedReason, +) : CancellableCloudEvent(source) \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/licenses/civilian/CivilianFishingLicense.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/licenses/civilian/CivilianFishingLicense.kt new file mode 100644 index 0000000..c646b93 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/licenses/civilian/CivilianFishingLicense.kt @@ -0,0 +1,16 @@ +package dev.slne.surf.roleplay.paper.player.license.licenses.civilian + +import dev.slne.surf.roleplay.paper.player.license.License +import dev.slne.surf.surfapi.core.api.messages.adventure.buildText +import dev.slne.surf.surfapi.core.api.messages.adventure.key +import org.springframework.stereotype.Component + +@Component +class CivilianFishingLicense : License( + key = key("civilian", "fishing_license"), + displayName = buildText { primary("Angelschein") }, + description = { + spacer("Die Angel-Lizenz erlaubt es dir, in der Wildnis zu angeln.") + }, + price = 500, +) \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/licenses/civilian/CivilianVehicleLicenses.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/licenses/civilian/CivilianVehicleLicenses.kt new file mode 100644 index 0000000..545024e --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/licenses/civilian/CivilianVehicleLicenses.kt @@ -0,0 +1,106 @@ +package dev.slne.surf.roleplay.paper.player.license.licenses.civilian + +import dev.slne.surf.roleplay.paper.player.license.ExpirableLicense +import dev.slne.surf.roleplay.paper.player.license.License +import dev.slne.surf.surfapi.core.api.messages.adventure.key +import dev.slne.surf.surfapi.core.api.messages.adventure.text +import dev.slne.surf.surfapi.core.api.util.objectSetOf +import org.springframework.stereotype.Component +import kotlin.time.Duration.Companion.minutes + +@Component +class DriversLicense : License( + key = key("civilian", "drivers_license"), + displayName = text("Führerschein"), + description = { + spacer("Der Führerschein erlaubt es dir, Fahrzeuge zu führen.") + }, + price = 1000, +) + +@Component +class TruckLicense( + driversLicense: DriversLicense +) : ExpirableLicense( + key = key("civilian", "truck_license"), + displayName = text("Lkw-Führerschein"), + description = { + spacer("Der Lkw-Führerschein erlaubt es dir, Lastkraftwagen zu fahren.") + }, + price = 2000, + expiresIn = 5.minutes, + dependencies = objectSetOf( + driversLicense + ) +) + +@Component +class BusLicense( + driversLicense: DriversLicense +) : License( + key = key("civilian", "bus_license"), + displayName = text("Bus-Führerschein"), + description = { + spacer("Der Bus-Führerschein erlaubt es dir, Busse zu fahren.") + }, + price = 2500, + dependencies = objectSetOf( + driversLicense + ) +) + +@Component +class TaxiLicense( + driversLicense: DriversLicense +) : License( + key = key("civilian", "taxi_license"), + displayName = text("Taxi-Führerschein"), + description = { + spacer("Der Taxi-Führerschein erlaubt es dir, Taxis zu fahren.") + + }, + price = 3000, + dependencies = objectSetOf( + driversLicense + ) +) + +@Component +class MotorcycleLicense : License( + key = key("civilian", "motorcycle_license"), + displayName = text("Motorrad-Führerschein"), + description = { + spacer("Der Motorrad-Führerschein erlaubt es dir, Motorräder zu fahren.") + }, + price = 1500, +) + +@Component +class BoatLicense : License( + key = key("civilian", "boat_license"), + displayName = text("Bootsführerschein"), + description = { + spacer("Der Bootsführerschein erlaubt es dir, Boote zu fahren.") + }, + price = 1800, +) + +@Component +class PilotLicense : License( + key = key("civilian", "pilot_license"), + displayName = text("Pilotenschein"), + description = { + spacer("Der Pilotenschein erlaubt es dir, Flugzeuge zu fliegen.") + }, + price = 5000, +) + +@Component +class HelicopterLicense : License( + key = key("civilian", "helicopter_license"), + displayName = text("Hubschrauber-Führerschein"), + description = { + spacer("Der Hubschrauber-Führerschein erlaubt es dir, Hubschrauber zu fliegen.") + }, + price = 6000, +) diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/licenses/civilian/CivilianWeaponLicenses.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/licenses/civilian/CivilianWeaponLicenses.kt new file mode 100644 index 0000000..5a74c2d --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/licenses/civilian/CivilianWeaponLicenses.kt @@ -0,0 +1,33 @@ +package dev.slne.surf.roleplay.paper.player.license.licenses.civilian + +import dev.slne.surf.roleplay.paper.player.license.License +import dev.slne.surf.surfapi.core.api.messages.adventure.buildText +import dev.slne.surf.surfapi.core.api.messages.adventure.key +import dev.slne.surf.surfapi.core.api.util.objectSetOf +import org.springframework.stereotype.Component + + +@Component +class LightWeaponLicense : License( + key = key("civilian", "light_weapon_license"), + displayName = buildText { success("Kleiner Waffenschein") }, + description = { + spacer("Erlaubt das Führen von leichten Waffen wie Pistolen und Revolvern.") + }, + price = 5000 +) + +@Component +class HeavyWeaponLicense( + lightWeaponLicense: LightWeaponLicense +) : License( + key = key("civilian", "heavy_weapon_license"), + displayName = buildText { error("Großer Waffenschein") }, + description = { + spacer("Erlaubt das Führen von schweren Waffen wie Maschinengewehren und Scharfschützengewehren.") + }, + price = 10000, + dependencies = objectSetOf( + lightWeaponLicense + ) +) diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/listeners/LicenseBuyHandler.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/listeners/LicenseBuyHandler.kt similarity index 50% rename from surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/listeners/LicenseBuyHandler.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/listeners/LicenseBuyHandler.kt index ce16829..78ac112 100644 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/license/listeners/LicenseBuyHandler.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/listeners/LicenseBuyHandler.kt @@ -1,18 +1,21 @@ -package dev.slne.surf.roleplay.core.player.license.listeners +package dev.slne.surf.roleplay.paper.player.license.listeners import com.github.shynixn.mccoroutine.folia.entityDispatcher import com.github.shynixn.mccoroutine.folia.launch import dev.slne.surf.npc.api.event.NpcInteractEvent import dev.slne.surf.npc.api.surfNpcApi -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.core.player.license.LicenseNpc -import dev.slne.surf.roleplay.core.player.license.dialogs.licenseDialog -import dev.slne.surf.roleplay.core.plugin +import dev.slne.surf.roleplay.paper.player.license.LicenseNpc +import dev.slne.surf.roleplay.paper.player.license.PaperLicenseService +import dev.slne.surf.roleplay.paper.player.license.dialogs.licenseDialog +import dev.slne.surf.roleplay.paper.player.rpPlayer +import dev.slne.surf.roleplay.paper.plugin import dev.slne.surf.surfapi.core.api.messages.adventure.sendText import org.bukkit.event.EventHandler import org.bukkit.event.Listener +import org.springframework.stereotype.Component -object LicenseBuyHandler : Listener { +@Component +class LicenseBuyHandler(private val paperLicenseService: PaperLicenseService) : Listener { private val licenseNpc get() = surfNpcApi.getNpc(LicenseNpc.NPC_NAME) @@ -24,19 +27,19 @@ object LicenseBuyHandler : Listener { val npc = event.npc if (npc.npcUuid != licenseNpc.npcUuid) return + val rpPlayer = player.rpPlayer + val activeIdentity = rpPlayer.activeIdentity ?: run { + player.sendText { + appendPrefix() - plugin.launch(plugin.entityDispatcher(player)) { - val rpPlayer = RpPlayer[player.uniqueId] - val activeIdentity = rpPlayer.activeIdentity ?: run { - player.sendText { - appendPrefix() - - error("Du musst eine Identität ausgewählt haben, um Lizenzen zu kaufen.") - } - return@launch + error("Du musst eine Identität ausgewählt haben, um Lizenzen zu kaufen.") } - player.showDialog(licenseDialog(rpPlayer, activeIdentity)) + return + } + + plugin.launch(plugin.entityDispatcher(player)) { + player.showDialog(licenseDialog(rpPlayer, activeIdentity, paperLicenseService)) } } diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/listeners/LicenseChangedHandler.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/listeners/LicenseChangedHandler.kt new file mode 100644 index 0000000..28dc9c1 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/listeners/LicenseChangedHandler.kt @@ -0,0 +1,54 @@ +package dev.slne.surf.roleplay.paper.player.license.listeners + +import dev.slne.surf.cloud.api.common.event.CloudEventHandler +import dev.slne.surf.roleplay.paper.player.license.events.RpPlayerLicenseAddedEvent +import dev.slne.surf.roleplay.paper.player.license.events.RpPlayerLicenseRemovedEvent +import dev.slne.surf.surfapi.core.api.messages.adventure.buildText +import dev.slne.surf.surfapi.core.api.messages.adventure.playSound +import dev.slne.surf.surfapi.core.api.messages.adventure.sendText +import net.kyori.adventure.sound.Sound.Source +import org.bukkit.Sound +import org.springframework.stereotype.Component + +@Suppress("unused") +@Component +class LicenseChangedHandler { + + @CloudEventHandler + fun onPlayerLicenseAdded(event: RpPlayerLicenseAddedEvent) { + val license = event.license + val cloudPlayer = event.player.cloudPlayer.player ?: return + + cloudPlayer.sendText { + appendPrefix() + + info("Du hast eine ") + append(license.license.displayName) + info(" Lizenz erhalten.") + } + + cloudPlayer.playSound(true) { + type(Sound.ENTITY_PLAYER_LEVELUP) + volume(.75f) + source(Source.NEUTRAL) + } + } + + @CloudEventHandler + fun onPlayerLicenseRemoved(event: RpPlayerLicenseRemovedEvent) { + val license = event.license + val cloudPlayer = event.player.cloudPlayer.player ?: return + + val reason = buildText { + appendPrefix() + append(event.reason.message(license)) + } + + cloudPlayer.sendMessage(reason) + cloudPlayer.playSound(true) { + type(Sound.ENTITY_VILLAGER_HURT) + volume(.75f) + source(Source.NEUTRAL) + } + } +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/utils/LicenseCreateResult.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/utils/LicenseCreateResult.kt new file mode 100644 index 0000000..ef6db73 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/utils/LicenseCreateResult.kt @@ -0,0 +1,10 @@ +package dev.slne.surf.roleplay.paper.player.license.utils + +import dev.slne.surf.roleplay.paper.player.license.IdentityLicense +import it.unimi.dsi.fastutil.objects.ObjectSet + +data class LicenseCreateResult( + val success: Boolean, + val reason: Set, + val license: IdentityLicense? +) diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/utils/LicenseRemovedReason.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/utils/LicenseRemovedReason.kt similarity index 74% rename from surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/utils/LicenseRemovedReason.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/utils/LicenseRemovedReason.kt index a1129cd..f73f722 100644 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/utils/LicenseRemovedReason.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/utils/LicenseRemovedReason.kt @@ -1,10 +1,11 @@ -package dev.slne.surf.roleplay.api.player.license.utils +package dev.slne.surf.roleplay.paper.player.license.utils -import dev.slne.surf.roleplay.api.player.RpPlayer -import dev.slne.surf.roleplay.api.player.license.IdentityLicense +import dev.slne.surf.roleplay.core.common.player.RpPlayer +import dev.slne.surf.roleplay.paper.player.license.IdentityLicense +import dev.slne.surf.surfapi.core.api.messages.adventure.buildText import dev.slne.surf.surfapi.core.api.messages.builder.SurfComponentBuilder -sealed class LicenseRemovedReason(val message: SurfComponentBuilder.(IdentityLicense) -> Unit) { +sealed class LicenseRemovedReason(private val messageBuilder: SurfComponentBuilder.(IdentityLicense) -> Unit) { object Expired : LicenseRemovedReason({ info("Deine ") append(it.license.displayName) @@ -30,7 +31,7 @@ sealed class LicenseRemovedReason(val message: SurfComponentBuilder.(IdentityLic info("Deine ") append(it.license.displayName) info(" Lizenz wurde durch ") - variableValue(confiscatedBy.username ?: confiscatedBy.uuid.toString()) + append(confiscatedBy) info(" beschlagnahmt. Grund: ") variableValue(confiscatedReason) info(".") @@ -44,7 +45,7 @@ sealed class LicenseRemovedReason(val message: SurfComponentBuilder.(IdentityLic info("Deine ") append(it.license.displayName) info(" Lizenz wurde von ") - variableValue(confiscatedBy.username ?: confiscatedBy.uuid.toString()) + append(confiscatedBy) info(" beschlagnahmt, da die übergeordnete Lizenz ") append(parent.license.displayName) info(" beschlagnahmt wurde. Grund: ") @@ -57,4 +58,6 @@ sealed class LicenseRemovedReason(val message: SurfComponentBuilder.(IdentityLic append(it.license.displayName) info(" Lizenz wurde entfernt, Grund unbekannt.") }) + + fun message(license: IdentityLicense) = buildText { this.messageBuilder(license) } } \ No newline at end of file diff --git a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/utils/UnobtainableReason.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/utils/UnobtainableReason.kt similarity index 81% rename from surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/utils/UnobtainableReason.kt rename to surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/utils/UnobtainableReason.kt index 0c5c4ff..6b27fb1 100644 --- a/surf-roleplay-api/src/main/kotlin/dev/slne/surf/roleplay/api/player/license/utils/UnobtainableReason.kt +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/license/utils/UnobtainableReason.kt @@ -1,12 +1,14 @@ -package dev.slne.surf.roleplay.api.player.license.utils +package dev.slne.surf.roleplay.paper.player.license.utils -import dev.slne.surf.roleplay.api.player.license.License +import dev.slne.surf.roleplay.paper.player.license.License import dev.slne.surf.surfapi.core.api.messages.adventure.appendNewline +import dev.slne.surf.surfapi.core.api.messages.adventure.buildText import dev.slne.surf.surfapi.core.api.messages.builder.SurfComponentBuilder -import it.unimi.dsi.fastutil.objects.ObjectSet import net.kyori.adventure.text.Component -sealed class UnobtainableReason(val message: SurfComponentBuilder.() -> Unit) { +sealed class UnobtainableReason(message: SurfComponentBuilder.() -> Unit) { + val message = buildText(message) + class NotEnoughCash( val currentAmount: Int, val neededAmount: Int ) : UnobtainableReason({ @@ -44,7 +46,7 @@ sealed class UnobtainableReason(val message: SurfComponentBuilder.() -> Unit) { }) class DependenciesNotMet( - val missingDependencies: ObjectSet + val missingDependencies: List ) : UnobtainableReason({ error("Du erfüllst nicht die Voraussetzungen, um diese Lizenz zu erwerben.") appendNewline(2) diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/player-utils.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/player-utils.kt new file mode 100644 index 0000000..c59218f --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/player/player-utils.kt @@ -0,0 +1,6 @@ +package dev.slne.surf.roleplay.paper.player + +import dev.slne.surf.roleplay.core.common.player.RpPlayer +import org.bukkit.OfflinePlayer + +val OfflinePlayer.rpPlayer get() = RpPlayer[uniqueId] as PaperRpPlayer diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/spring/RpPacketListener.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/spring/RpPacketListener.kt new file mode 100644 index 0000000..e7da892 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/spring/RpPacketListener.kt @@ -0,0 +1,11 @@ +package dev.slne.surf.roleplay.paper.spring + +import com.github.retrooper.packetevents.event.PacketListenerPriority +import org.springframework.stereotype.Component + +@Component +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.CLASS) +annotation class RpPacketListener( + val priority: PacketListenerPriority = PacketListenerPriority.NORMAL, +) \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/spring/postprocessor/BukkitListenerPostProcessor.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/spring/postprocessor/BukkitListenerPostProcessor.kt new file mode 100644 index 0000000..df101a1 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/spring/postprocessor/BukkitListenerPostProcessor.kt @@ -0,0 +1,28 @@ +package dev.slne.surf.roleplay.paper.spring.postprocessor + +import dev.slne.surf.cloud.api.common.util.mutableObjectSetOf +import dev.slne.surf.roleplay.core.common.RpLifecycle +import dev.slne.surf.surfapi.bukkit.api.event.register +import org.bukkit.event.Listener +import org.springframework.beans.factory.config.BeanPostProcessor +import org.springframework.stereotype.Component + +@Component +class BukkitListenerPostProcessor : BeanPostProcessor, RpLifecycle { + + private val watched = mutableObjectSetOf() + + override fun postProcessAfterInitialization(bean: Any, beanName: String): Any { + if (bean is Listener) { + watched.add(bean) + } + + return bean + } + + override suspend fun onEnable() { + for (listener in watched) { + listener.register() + } + } +} \ No newline at end of file diff --git a/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/spring/postprocessor/PacketListenerPostProcessor.kt b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/spring/postprocessor/PacketListenerPostProcessor.kt new file mode 100644 index 0000000..99ac801 --- /dev/null +++ b/surf-roleplay-paper/src/main/kotlin/dev/slne/surf/roleplay/paper/spring/postprocessor/PacketListenerPostProcessor.kt @@ -0,0 +1,35 @@ +package dev.slne.surf.roleplay.paper.spring.postprocessor + +import com.github.retrooper.packetevents.event.PacketListener +import dev.slne.surf.cloud.api.common.util.findAnnotation +import dev.slne.surf.cloud.api.common.util.object2ObjectMapOf +import dev.slne.surf.roleplay.core.common.RpLifecycle +import dev.slne.surf.roleplay.paper.spring.RpPacketListener +import dev.slne.surf.surfapi.core.api.extensions.packetEvents +import org.springframework.beans.factory.config.BeanPostProcessor +import org.springframework.stereotype.Component + +@Component +class PacketListenerPostProcessor : BeanPostProcessor, RpLifecycle { + private val packetListeners = object2ObjectMapOf() + + override fun postProcessAfterInitialization(bean: Any, beanName: String): Any { + if (bean !is PacketListener) return bean + + val annotation = bean::class.findAnnotation() + + if (annotation != null) { + packetListeners[bean] = annotation + } + + return bean + } + + override suspend fun onEnable() { + val eventManager = packetEvents.eventManager + + packetListeners.forEach { (listener, annotation) -> + eventManager.registerListener(listener, annotation.priority) + } + } +} \ No newline at end of file diff --git a/surf-roleplay-server/build.gradle.kts b/surf-roleplay-server/build.gradle.kts new file mode 100644 index 0000000..9ecb990 --- /dev/null +++ b/surf-roleplay-server/build.gradle.kts @@ -0,0 +1,17 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +plugins { + id("dev.slne.surf.surfapi.gradle.core") +} + +surfCoreApi { + withCloudServer() +} + +dependencies { + api(project(":surf-roleplay-core:surf-roleplay-core-common")) +} + +tasks.withType { + destinationDirectory.set(rootProject.file("output")) +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/GenerateExposedMigrationScript.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/GenerateExposedMigrationScript.kt new file mode 100644 index 0000000..e33cda5 --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/GenerateExposedMigrationScript.kt @@ -0,0 +1,11 @@ +package dev.slne.surf.roleplay.server + +import dev.slne.surf.cloud.api.server.exposed.migration.generateSimpleExposedMigration +import org.jetbrains.exposed.sql.ExperimentalDatabaseMigrationApi + +@OptIn(ExperimentalDatabaseMigrationApi::class) +fun main() { + generateSimpleExposedMigration( + scriptName = "V1__create_initial_tables", + ) +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/PluginBootstrap.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/PluginBootstrap.kt new file mode 100644 index 0000000..1fd8b91 --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/PluginBootstrap.kt @@ -0,0 +1,14 @@ +package dev.slne.surf.roleplay.server + +import dev.slne.surf.cloud.api.common.CloudInstance +import dev.slne.surf.cloud.api.common.startSpringApplication +import dev.slne.surf.cloud.api.server.plugin.bootstrap.BootstrapContext +import dev.slne.surf.cloud.api.server.plugin.bootstrap.StandalonePluginBootstrap +import dev.slne.surf.roleplay.RoleplayApplication + +class PluginBootstrap : StandalonePluginBootstrap { + override suspend fun bootstrap(context: BootstrapContext) { + RoleplayApplication.context = + CloudInstance.startSpringApplication(RoleplayApplication::class) + } +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/PluginMain.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/PluginMain.kt new file mode 100644 index 0000000..2aee3a8 --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/PluginMain.kt @@ -0,0 +1,18 @@ +package dev.slne.surf.roleplay.server + +import dev.slne.surf.cloud.api.server.plugin.StandalonePlugin + +class PluginMain : StandalonePlugin() { + + override suspend fun load() { + + } + + override suspend fun enable() { + + } + + override suspend fun disable() { + + } +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/RpPlayerManagerImpl.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/RpPlayerManagerImpl.kt new file mode 100644 index 0000000..0058536 --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/RpPlayerManagerImpl.kt @@ -0,0 +1,26 @@ +package dev.slne.surf.roleplay.server.player + +import dev.slne.surf.cloud.api.common.player.CloudPlayerManager +import dev.slne.surf.roleplay.core.common.player.RpPlayerManager +import org.springframework.stereotype.Component +import java.util.* + +@Component +class RpPlayerManagerImpl(private val rpPlayerService: RpPlayerService) : RpPlayerManager() { + + override fun createPlayer(uuid: UUID) = ServerRpPlayer(uuid) + override fun onlineUuids() = CloudPlayerManager.getOnlinePlayers().uuidSnapshot() + +// suspend fun updateUsername( +// rpPlayer: RpPlayerImpl, +// username: String +// ): Unit = newSuspendedTransaction(Dispatchers.IO) { +// rpPlayer.username = username +// rpPlayer.updatedAt = ZonedDateTime.now() +// +// RpPlayerModel.findSingleByAndUpdate((RpPlayerTable.uuid eq rpPlayer.uuid)) { +// it.username = username +// it.updatedAt = rpPlayer.updatedAt +// } +// } +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/RpPlayerService.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/RpPlayerService.kt new file mode 100644 index 0000000..402e439 --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/RpPlayerService.kt @@ -0,0 +1,11 @@ +package dev.slne.surf.roleplay.server.player + +import org.springframework.stereotype.Service + +@Service +class RpPlayerService { + + suspend fun updateUsername(player: ServerRpPlayer, username: String) { + // TODO: 23.08.2025 12:11 - needed? + } +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/ServerRpPlayer.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/ServerRpPlayer.kt new file mode 100644 index 0000000..7e5e675 --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/ServerRpPlayer.kt @@ -0,0 +1,39 @@ +package dev.slne.surf.roleplay.server.player + +import dev.slne.surf.roleplay.core.common.player.RpPlayer +import dev.slne.surf.roleplay.core.common.transaction.RpTransaction +import dev.slne.surf.roleplay.core.common.transaction.utils.BalanceType +import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet +import net.kyori.adventure.text.Component +import java.util.UUID + +class ServerRpPlayer(uuid: UUID) : RpPlayer(uuid) { + override suspend fun getBalance(balanceType: BalanceType): Int { + TODO("Not yet implemented") + } + + override suspend fun addBalance( + balanceType: BalanceType, + amount: Int + ): Boolean { + TODO("Not yet implemented") + } + + override suspend fun removeBalance( + balanceType: BalanceType, + amount: Int + ): Boolean { + TODO("Not yet implemented") + } + + override suspend fun getBalanceHistory( + balanceType: BalanceType, + limit: Int + ): ObjectLinkedOpenHashSet { + TODO("Not yet implemented") + } + + override fun asComponent(): Component { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/db/RpPlayerModel.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/db/RpPlayerModel.kt new file mode 100644 index 0000000..6398471 --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/db/RpPlayerModel.kt @@ -0,0 +1,26 @@ +package dev.slne.surf.roleplay.server.player.db + +import dev.slne.surf.roleplay.server.player.identity.db.impl.civilian.RpPlayerCivilianIdentityModel +import dev.slne.surf.roleplay.server.player.identity.db.impl.civilian.RpPlayerCivilianIdentityTable +import dev.slne.surf.roleplay.server.player.identity.db.impl.police.RpPlayerPoliceIdentityModel +import dev.slne.surf.roleplay.server.player.identity.db.impl.police.RpPlayerPoliceIdentityTable +import dev.slne.surf.roleplay.server.player.identity.db.impl.rescueservice.RpPlayerRescueServiceIdentityModel +import dev.slne.surf.roleplay.server.player.identity.db.impl.rescueservice.RpPlayerRescueServiceIdentityTable +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID + +class RpPlayerModel(id: EntityID) : LongEntity(id) { + + companion object : LongEntityClass(RpPlayerTable) + + var uuid by RpPlayerTable.uuid + var username by RpPlayerTable.username + + var createdAt by RpPlayerTable.createdAt + var updatedAt by RpPlayerTable.updatedAt + + val civilianIdentity by RpPlayerCivilianIdentityModel optionalBackReferencedOn RpPlayerCivilianIdentityTable.player + val policeIdentity by RpPlayerPoliceIdentityModel optionalBackReferencedOn RpPlayerPoliceIdentityTable.player + val rescueServiceIdentity by RpPlayerRescueServiceIdentityModel optionalBackReferencedOn RpPlayerRescueServiceIdentityTable.player +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/db/RpPlayerRepository.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/db/RpPlayerRepository.kt new file mode 100644 index 0000000..bb4fa7f --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/db/RpPlayerRepository.kt @@ -0,0 +1,31 @@ +package dev.slne.surf.roleplay.server.player.db + +import dev.slne.surf.cloud.api.common.util.singleOrNullOrThrow +import dev.slne.surf.cloud.api.server.plugin.CoroutineTransactional +import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq +import org.springframework.stereotype.Repository +import java.time.ZonedDateTime +import java.util.* + +@CoroutineTransactional +@Repository +class RpPlayerRepository { + + suspend fun findPlayerId(uuid: UUID) = RpPlayerTable.select(RpPlayerTable.id) + .where { RpPlayerTable.uuid eq uuid } + .singleOrNullOrThrow() + ?.get(RpPlayerTable.id) + + suspend fun findOrCreateModel(uuid: UUID) = + RpPlayerModel.find { RpPlayerTable.uuid eq uuid }.singleOrNullOrThrow() + ?: RpPlayerModel.new { + this.uuid = uuid + this.createdAt = ZonedDateTime.now() + this.updatedAt = ZonedDateTime.now() + } + + suspend fun updateUsername(uuid: UUID, username: String) = + RpPlayerModel.findSingleByAndUpdate(RpPlayerTable.uuid eq uuid) { + it.username = username + } +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/db/RpPlayerTable.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/db/RpPlayerTable.kt new file mode 100644 index 0000000..4836032 --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/db/RpPlayerTable.kt @@ -0,0 +1,9 @@ +package dev.slne.surf.roleplay.server.player.db + +import dev.slne.surf.cloud.api.server.exposed.columns.nativeUuid +import dev.slne.surf.cloud.api.server.exposed.table.AuditableLongIdTable + +object RpPlayerTable : AuditableLongIdTable("rp_players") { + val uuid = nativeUuid("uuid").uniqueIndex() + val username = char("username", 16).nullable() +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/RpIdentityPacketListener.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/RpIdentityPacketListener.kt new file mode 100644 index 0000000..a3cda56 --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/RpIdentityPacketListener.kt @@ -0,0 +1,24 @@ +package dev.slne.surf.roleplay.server.player.identity + +import dev.slne.surf.cloud.api.common.meta.SurfNettyPacketHandler +import dev.slne.surf.roleplay.core.common.network.packets.FetchIdentitiesByUuidPacketResponse +import dev.slne.surf.roleplay.core.common.network.packets.IdentityResponsePacket +import dev.slne.surf.roleplay.core.common.network.packets.ServerboundCreateOrUpdateIdentityPacket +import dev.slne.surf.roleplay.core.common.network.packets.ServerboundFetchIdentitiesByUuidPacket +import org.springframework.stereotype.Component + +@Component +class RpIdentityPacketListener(private val rpIdentityService: RpIdentityService) { + + @SurfNettyPacketHandler + suspend fun handleFetchIdentitiesByUuid(packet: ServerboundFetchIdentitiesByUuidPacket) { + val identities = rpIdentityService.fetchByUuid(packet.uuid) + packet.respond(FetchIdentitiesByUuidPacketResponse(identities)) + } + + @SurfNettyPacketHandler + suspend fun handleCreateOrUpdateIdentity(packet: ServerboundCreateOrUpdateIdentityPacket) { + val created = rpIdentityService.createOrUpdateIdentity(packet.identity) + packet.respond(IdentityResponsePacket(created)) + } +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/RpIdentityService.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/RpIdentityService.kt new file mode 100644 index 0000000..16475fc --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/RpIdentityService.kt @@ -0,0 +1,13 @@ +package dev.slne.surf.roleplay.server.player.identity + +import dev.slne.surf.roleplay.core.common.player.identity.NetworkIdentity +import dev.slne.surf.roleplay.server.player.identity.db.RpIdentityRepository +import org.springframework.stereotype.Service +import java.util.* + +@Service +class RpIdentityService(private val rpIdentityRepository: RpIdentityRepository) { + suspend fun fetchByUuid(uuid: UUID) = rpIdentityRepository.findByUuid(uuid) + suspend fun createOrUpdateIdentity(identity: NetworkIdentity) = + rpIdentityRepository.updateOrCreateIdentity(identity.uuid, identity) +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/RpIdentityRepository.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/RpIdentityRepository.kt new file mode 100644 index 0000000..d949edf --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/RpIdentityRepository.kt @@ -0,0 +1,108 @@ +package dev.slne.surf.roleplay.server.player.identity.db + +import dev.slne.surf.cloud.api.common.util.singleOrNullOrThrow +import dev.slne.surf.roleplay.core.common.player.identity.NetworkIdentity +import dev.slne.surf.roleplay.core.common.player.identity.RpIdentityType +import dev.slne.surf.roleplay.server.player.db.RpPlayerRepository +import dev.slne.surf.roleplay.server.player.identity.db.impl.civilian.RpPlayerCivilianIdentityModel +import dev.slne.surf.roleplay.server.player.identity.db.impl.police.RpPlayerPoliceIdentityModel +import dev.slne.surf.roleplay.server.player.identity.db.impl.rescueservice.RpPlayerRescueServiceIdentityModel +import org.springframework.stereotype.Repository +import java.util.* + +@Repository +class RpIdentityRepository(private val rpPlayerRepository: RpPlayerRepository) { + + suspend fun findByUuid(uuid: UUID): List { + val player = rpPlayerRepository.findOrCreateModel(uuid) + + return listOfNotNull( + player.civilianIdentity?.toNetwork(), + player.policeIdentity?.toNetwork(), + player.rescueServiceIdentity?.toNetwork() + ) + } + + private suspend fun findIdentityModelByType( + uuid: UUID, + type: RpIdentityType + ): RpPlayerIdentityBaseModel? { + val playerId = rpPlayerRepository.findPlayerId(uuid) ?: return null + val modelClass = when (type) { + RpIdentityType.CIVILIAN -> RpPlayerCivilianIdentityModel + RpIdentityType.POLICE -> RpPlayerPoliceIdentityModel + RpIdentityType.RESCUE_SERVICE -> RpPlayerRescueServiceIdentityModel + } + + return modelClass.find { modelClass.identityTable.player eq playerId }.singleOrNullOrThrow() + } + + suspend fun createIdentity(uuid: UUID, identity: NetworkIdentity): NetworkIdentity { + val playerModel = rpPlayerRepository.findOrCreateModel(uuid) + + fun RpPlayerIdentityBaseModel.applyCommonData() { + this.player = playerModel + this.firstName = identity.firstName + this.lastName = identity.lastName + this.dateOfBirth = identity.dateOfBirth + } + + val created = when (identity) { + is NetworkIdentity.Civilian -> RpPlayerCivilianIdentityModel.new { + applyCommonData() + } + + is NetworkIdentity.Police -> RpPlayerPoliceIdentityModel.new { + applyCommonData() + this.badgeNumber = identity.badgeNumber + this.rank = identity.rank + } + + is NetworkIdentity.RescueService -> RpPlayerRescueServiceIdentityModel.new { + applyCommonData() + this.rank = identity.rank + } + } + + return created.toNetwork() + } + + suspend fun updateOrCreateIdentity(uuid: UUID, identity: NetworkIdentity): NetworkIdentity { + val existingModel = + findIdentityModelByType(uuid, identity.type) ?: return createIdentity(uuid, identity) + + fun RpPlayerIdentityBaseModel.applyCommonUpdate() = apply { + this.firstName = identity.firstName + this.lastName = identity.lastName + this.dateOfBirth = identity.dateOfBirth + } + + val updated = when (existingModel) { + is RpPlayerCivilianIdentityModel -> { + require(identity is NetworkIdentity.Civilian) { "Invalid identity type: ${identity::class.qualifiedName}. Expected: ${NetworkIdentity.Civilian::class.qualifiedName}" } + existingModel.applyCommonUpdate() + } + + is RpPlayerPoliceIdentityModel -> { + require(identity is NetworkIdentity.Police) { "Invalid identity type: ${identity::class.qualifiedName}. Expected: ${NetworkIdentity.Police::class.qualifiedName}" } + existingModel.apply { + applyCommonUpdate() + this.badgeNumber = identity.badgeNumber + this.rank = identity.rank + } + } + + is RpPlayerRescueServiceIdentityModel -> { + require(identity is NetworkIdentity.RescueService) { "Invalid identity type: ${identity::class.qualifiedName}. Expected: ${NetworkIdentity.RescueService::class.qualifiedName}" } + existingModel.apply { + applyCommonUpdate() + this.rank = identity.rank + } + } + + else -> error("Unsupported identity type: ${identity::class.qualifiedName}") + } + + return updated.toNetwork() + } +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/RpPlayerIdentityBaseModel.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/RpPlayerIdentityBaseModel.kt new file mode 100644 index 0000000..bc85e80 --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/RpPlayerIdentityBaseModel.kt @@ -0,0 +1,23 @@ +package dev.slne.surf.roleplay.server.player.identity.db + +import dev.slne.surf.cloud.api.server.exposed.table.AuditableLongEntity +import dev.slne.surf.cloud.api.server.exposed.table.AuditableLongEntityClass +import dev.slne.surf.roleplay.core.common.player.identity.NetworkIdentity +import dev.slne.surf.roleplay.server.player.db.RpPlayerModel +import org.jetbrains.exposed.dao.id.EntityID + +abstract class RpPlayerIdentityBaseModel( + id: EntityID, + table: RpPlayerIdentityBaseTable +) : AuditableLongEntity(id, table) { + var player by RpPlayerModel referencedOn table.player + + var firstName by table.firstName + var lastName by table.lastName + var dateOfBirth by table.dateOfBirth + + abstract fun toNetwork(): NetworkIdentity +} + +abstract class RpPlayerIdentityBaseClass(val identityTable: RpPlayerIdentityBaseTable) : + AuditableLongEntityClass(identityTable) \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/RpPlayerIdentityBaseTable.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/RpPlayerIdentityBaseTable.kt new file mode 100644 index 0000000..0d17190 --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/RpPlayerIdentityBaseTable.kt @@ -0,0 +1,19 @@ +package dev.slne.surf.roleplay.server.player.identity.db + +import dev.slne.surf.cloud.api.server.exposed.table.AuditableLongIdTable +import dev.slne.surf.roleplay.server.player.db.RpPlayerTable +import org.jetbrains.exposed.sql.ReferenceOption +import org.jetbrains.exposed.sql.javatime.date + +abstract class RpPlayerIdentityBaseTable(table: String) : AuditableLongIdTable(table) { + val player = reference( + "player_id", + RpPlayerTable, + onDelete = ReferenceOption.CASCADE, + onUpdate = ReferenceOption.CASCADE + ).uniqueIndex() + + val firstName = char("first_name", 16) + val lastName = char("last_name", 16) + val dateOfBirth = date("date_of_birth") +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/impl/civilian/RpPlayerCivilianIdentityModel.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/impl/civilian/RpPlayerCivilianIdentityModel.kt new file mode 100644 index 0000000..f61300a --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/impl/civilian/RpPlayerCivilianIdentityModel.kt @@ -0,0 +1,21 @@ +package dev.slne.surf.roleplay.server.player.identity.db.impl.civilian + +import dev.slne.surf.roleplay.core.common.player.identity.NetworkIdentity +import dev.slne.surf.roleplay.server.player.identity.db.RpPlayerIdentityBaseClass +import dev.slne.surf.roleplay.server.player.identity.db.RpPlayerIdentityBaseModel +import org.jetbrains.exposed.dao.id.EntityID + +class RpPlayerCivilianIdentityModel(id: EntityID) : + RpPlayerIdentityBaseModel(id, RpPlayerCivilianIdentityTable) { + companion object : + RpPlayerIdentityBaseClass(RpPlayerCivilianIdentityTable) + + override fun toNetwork() = NetworkIdentity.Civilian( + uuid = player.uuid, + firstName = firstName, + lastName = lastName, + dateOfBirth = dateOfBirth, + createdAt = createdAt, + updatedAt = updatedAt + ) +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/impl/civilian/RpPlayerCivilianIdentityTable.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/impl/civilian/RpPlayerCivilianIdentityTable.kt new file mode 100644 index 0000000..c6ccbeb --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/impl/civilian/RpPlayerCivilianIdentityTable.kt @@ -0,0 +1,5 @@ +package dev.slne.surf.roleplay.server.player.identity.db.impl.civilian + +import dev.slne.surf.roleplay.server.player.identity.db.RpPlayerIdentityBaseTable + +object RpPlayerCivilianIdentityTable : RpPlayerIdentityBaseTable("rp_player_civilian_identities") \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/impl/police/RpPlayerPoliceIdentityModel.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/impl/police/RpPlayerPoliceIdentityModel.kt new file mode 100644 index 0000000..4edf26f --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/impl/police/RpPlayerPoliceIdentityModel.kt @@ -0,0 +1,26 @@ +package dev.slne.surf.roleplay.server.player.identity.db.impl.police + +import dev.slne.surf.roleplay.core.common.player.identity.NetworkIdentity +import dev.slne.surf.roleplay.server.player.identity.db.RpPlayerIdentityBaseClass +import dev.slne.surf.roleplay.server.player.identity.db.RpPlayerIdentityBaseModel +import org.jetbrains.exposed.dao.id.EntityID + +class RpPlayerPoliceIdentityModel(id: EntityID) : + RpPlayerIdentityBaseModel(id, RpPlayerPoliceIdentityTable) { + companion object : + RpPlayerIdentityBaseClass(RpPlayerPoliceIdentityTable) + + var badgeNumber by RpPlayerPoliceIdentityTable.badgeNumber + var rank by RpPlayerPoliceIdentityTable.rank + + override fun toNetwork() = NetworkIdentity.Police( + uuid = player.uuid, + firstName = firstName, + lastName = lastName, + dateOfBirth = dateOfBirth, + badgeNumber = badgeNumber, + rank = rank, + createdAt = createdAt, + updatedAt = updatedAt + ) +} \ No newline at end of file diff --git a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/impl/police/RpPlayerPoliceIdentityTable.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/impl/police/RpPlayerPoliceIdentityTable.kt similarity index 55% rename from surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/impl/police/RpPlayerPoliceIdentityTable.kt rename to surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/impl/police/RpPlayerPoliceIdentityTable.kt index 93625d8..c003d79 100644 --- a/surf-roleplay-core/src/main/kotlin/dev/slne/surf/roleplay/core/player/identity/db/impl/police/RpPlayerPoliceIdentityTable.kt +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/impl/police/RpPlayerPoliceIdentityTable.kt @@ -1,6 +1,6 @@ -package dev.slne.surf.roleplay.core.player.identity.db.impl.police +package dev.slne.surf.roleplay.server.player.identity.db.impl.police -import dev.slne.surf.roleplay.core.player.identity.db.RpPlayerIdentityBaseTable +import dev.slne.surf.roleplay.server.player.identity.db.RpPlayerIdentityBaseTable object RpPlayerPoliceIdentityTable : RpPlayerIdentityBaseTable("rp_player_police_identities") { val rank = varchar("rank", 255) diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/impl/rescueservice/RpPlayerRescueServiceIdentityModel.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/impl/rescueservice/RpPlayerRescueServiceIdentityModel.kt new file mode 100644 index 0000000..5f6ab10 --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/impl/rescueservice/RpPlayerRescueServiceIdentityModel.kt @@ -0,0 +1,26 @@ +package dev.slne.surf.roleplay.server.player.identity.db.impl.rescueservice + +import dev.slne.surf.roleplay.core.common.player.identity.NetworkIdentity +import dev.slne.surf.roleplay.server.player.identity.db.RpPlayerIdentityBaseClass +import dev.slne.surf.roleplay.server.player.identity.db.RpPlayerIdentityBaseModel +import org.jetbrains.exposed.dao.id.EntityID + +class RpPlayerRescueServiceIdentityModel(id: EntityID) : + RpPlayerIdentityBaseModel(id, RpPlayerRescueServiceIdentityTable) { + companion object : + RpPlayerIdentityBaseClass( + RpPlayerRescueServiceIdentityTable + ) + + var rank by RpPlayerRescueServiceIdentityTable.rank + + override fun toNetwork() = NetworkIdentity.RescueService( + uuid = player.uuid, + firstName = firstName, + lastName = lastName, + dateOfBirth = dateOfBirth, + rank = rank, + createdAt = createdAt, + updatedAt = updatedAt + ) +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/impl/rescueservice/RpPlayerRescueServiceIdentityTable.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/impl/rescueservice/RpPlayerRescueServiceIdentityTable.kt new file mode 100644 index 0000000..d450487 --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/identity/db/impl/rescueservice/RpPlayerRescueServiceIdentityTable.kt @@ -0,0 +1,8 @@ +package dev.slne.surf.roleplay.server.player.identity.db.impl.rescueservice + +import dev.slne.surf.roleplay.server.player.identity.db.RpPlayerIdentityBaseTable + +object RpPlayerRescueServiceIdentityTable : + RpPlayerIdentityBaseTable("rp_player_rescue_service_identities") { + val rank = varchar("rank", 255) +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/license/LicensePacketListener.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/license/LicensePacketListener.kt new file mode 100644 index 0000000..1288e5a --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/license/LicensePacketListener.kt @@ -0,0 +1,29 @@ +package dev.slne.surf.roleplay.server.player.license + +import dev.slne.surf.cloud.api.common.meta.SurfNettyPacketHandler +import dev.slne.surf.cloud.api.common.netty.network.protocol.respond +import dev.slne.surf.roleplay.core.common.network.packets.ServerboundCreateLicensePacket +import dev.slne.surf.roleplay.core.common.network.packets.ServerboundDeleteLicensePacket +import org.springframework.stereotype.Component + +@Suppress("unused") +@Component +class LicensePacketListener(private val licenseService: LicenseService) { + + @SurfNettyPacketHandler + suspend fun handleCreateLicense(packet: ServerboundCreateLicensePacket) { + licenseService.createLicense(packet.license) + packet.respond(true) + } + + @SurfNettyPacketHandler + suspend fun handleDeleteLicense(packet: ServerboundDeleteLicensePacket) { + val deleted = licenseService.deleteLicense( + packet.uuid, + packet.identityType, + packet.licenseKey + ) + + packet.respond(deleted) + } +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/license/LicenseService.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/license/LicenseService.kt new file mode 100644 index 0000000..030c357 --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/license/LicenseService.kt @@ -0,0 +1,26 @@ +package dev.slne.surf.roleplay.server.player.license + +import dev.slne.surf.roleplay.core.common.player.identity.RpIdentityType +import dev.slne.surf.roleplay.core.common.player.license.NetworkIdentityLicense +import dev.slne.surf.roleplay.server.player.license.db.LicenseRepository +import net.kyori.adventure.key.Key +import org.springframework.stereotype.Service +import java.util.* + +@Service +class LicenseService(private val licenseRepository: LicenseRepository) { + + suspend fun createLicense(license: NetworkIdentityLicense) { + licenseRepository.createLicense( + license.owner, + license.identityType, + license.licenseKey, + license.expiresAt, + license.createdAt + ) + } + + suspend fun deleteLicense(uuid: UUID, identityType: RpIdentityType, licenseKey: Key): Boolean { + return licenseRepository.deleteLicense(uuid, identityType, licenseKey) > 0 + } +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/license/LicenseServiceImpl.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/license/LicenseServiceImpl.kt new file mode 100644 index 0000000..0a019b9 --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/license/LicenseServiceImpl.kt @@ -0,0 +1,105 @@ +package dev.slne.surf.roleplay.server.player.license + +class LicenseServiceImpl { + + +// private val _licenses = mutableObjectSetOf() +// override val licenses get() = _licenses.freeze() +// +// suspend fun fetchLicenses(identity: RpIdentity) = newSuspendedTransaction(Dispatchers.IO) { +// val rpPlayerModel = rpPlayerManagerImpl.findOrCreate(identity.player.uuid) +// +// IdentityLicenseModel.find { +// (IdentityLicenseTable.player eq rpPlayerModel.id) and +// (IdentityLicenseTable.identity eq identity.type) +// }.map { it.toApi(identity) }.toObjectList() +// } +// +// override fun getLicense(license: Class) = +// _licenses.firstOrNull { license.isAssignableFrom(it::class.java) } +// +// override fun getLicenseOrThrow(license: Class) = +// getLicense(license) ?: error("License not found: ${license.name}") +// +// override fun getLicenseByKey(key: Key) = _licenses.firstOrNull { it.key == key } +// +// override fun getLicenseByKeyOrThrow(key: Key) = +// getLicenseByKey(key) ?: error("License not found: $key") +// +// override suspend fun createLicense( +// identityLicense: IdentityLicense +// ) = newSuspendedTransaction(Dispatchers.IO) { +// val (license, identity, expiresAt, createdAt) = identityLicense +// val rpPlayerModel = rpPlayerManagerImpl.findOrCreate(identity.player.uuid) +// +// IdentityLicenseModel.new { +// this.player = rpPlayerModel +// this.identity = identity.type +// this.license = license.key.asString() +// this.expiresAt = expiresAt +// this.createdAt = createdAt +// }.toApi(identityLicense.identity) +// } +// +// override suspend fun confiscateLicense( +// identity: RpIdentity, +// license: License, +// confiscatedBy: RpPlayer, +// confiscatedReason: String +// ) = newSuspendedTransaction(Dispatchers.IO) { +// val player = identity.player +// val parentLicense = player.getIdentity(identity.type)?.getLicense(license::class.java) +// ?: return@newSuspendedTransaction false +// +// val parentResult = player.removeLicense( +// license, +// LicenseRemovedReason.Confiscated(confiscatedBy, confiscatedReason) +// ) +// +// val childrenResults = license.children.map { childLicense -> +// if (player.hasLicense(childLicense)) { +// player.removeLicense( +// childLicense, +// LicenseRemovedReason.ConfiscatedChild( +// parentLicense, +// confiscatedBy, +// confiscatedReason +// ) +// ) +// return@map true +// } +// +// false +// } +// +// parentResult && childrenResults.all { it } +// } +// +// override suspend fun removeLicense( +// identity: RpIdentity, +// license: License +// ) = newSuspendedTransaction(Dispatchers.IO) { +// val player = identity.player +// val rpPlayerModel = rpPlayerManagerImpl.findOrCreate(player.uuid) +// val playerLicense = IdentityLicenseModel.find { +// (IdentityLicenseTable.player eq rpPlayerModel.id) and +// (IdentityLicenseTable.identity eq identity.type) and +// (IdentityLicenseTable.license eq license.key.asString()) +// } +// +// if (playerLicense.empty()) { +// return@newSuspendedTransaction false +// } +// +// playerLicense.forEach { it.delete() } +// +// true +// } +// +// fun getAllExpiredLicenses() = RpPlayerManager.players +// .mapNotNull { +// val activeIdentity = it.activeIdentity ?: return@mapNotNull null +// +// activeIdentity to activeIdentity.licenses.filter { license -> license.isExpired } +// }.toObjectList() +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/license/db/IdentityLicenseModel.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/license/db/IdentityLicenseModel.kt new file mode 100644 index 0000000..d02fb05 --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/license/db/IdentityLicenseModel.kt @@ -0,0 +1,27 @@ +package dev.slne.surf.roleplay.server.player.license.db + +import dev.slne.surf.roleplay.core.common.player.license.NetworkIdentityLicense +import dev.slne.surf.roleplay.server.player.db.RpPlayerModel +import org.jetbrains.exposed.dao.LongEntity +import org.jetbrains.exposed.dao.LongEntityClass +import org.jetbrains.exposed.dao.id.EntityID + +class IdentityLicenseModel(id: EntityID) : LongEntity(id) { + + companion object : LongEntityClass(IdentityLicenseTable) + + var player by RpPlayerModel referencedOn IdentityLicenseTable.player + var identity by IdentityLicenseTable.identity + + var license by IdentityLicenseTable.license + var expiresAt by IdentityLicenseTable.expiresAt + var createdAt by IdentityLicenseTable.createdAt + + fun toNetwork() = NetworkIdentityLicense( + owner = player.uuid, + identityType = identity, + licenseKey = license, + expiresAt = expiresAt, + createdAt = createdAt + ) +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/license/db/IdentityLicenseTable.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/license/db/IdentityLicenseTable.kt new file mode 100644 index 0000000..7cfbbc6 --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/license/db/IdentityLicenseTable.kt @@ -0,0 +1,24 @@ +package dev.slne.surf.roleplay.server.player.license.db + +import dev.slne.surf.cloud.api.server.exposed.columns.CurrentZonedDateTime +import dev.slne.surf.cloud.api.server.exposed.columns.zonedDateTime +import dev.slne.surf.roleplay.core.common.player.identity.RpIdentityType +import dev.slne.surf.roleplay.server.player.db.RpPlayerTable +import dev.slne.surf.surfapi.core.api.messages.adventure.key +import org.jetbrains.exposed.dao.id.LongIdTable +import org.jetbrains.exposed.sql.ReferenceOption + +object IdentityLicenseTable : LongIdTable("identity_licenses") { + + val player = reference( + "player_id", RpPlayerTable, + onUpdate = ReferenceOption.CASCADE, + onDelete = ReferenceOption.CASCADE + ) + val identity = enumerationByName("identity", 255) + val license = char("license", 255).transform({ key(it) }, { it.asString() }) + + val expiresAt = zonedDateTime("expires_at").nullable() + val createdAt = zonedDateTime("created_at").defaultExpression(CurrentZonedDateTime) + +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/license/db/LicenseRepository.kt b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/license/db/LicenseRepository.kt new file mode 100644 index 0000000..90be6dd --- /dev/null +++ b/surf-roleplay-server/src/main/kotlin/dev/slne/surf/roleplay/server/player/license/db/LicenseRepository.kt @@ -0,0 +1,53 @@ +package dev.slne.surf.roleplay.server.player.license.db + +import dev.slne.surf.cloud.api.server.plugin.CoroutineTransactional +import dev.slne.surf.roleplay.core.common.player.identity.RpIdentityType +import dev.slne.surf.roleplay.core.common.player.license.NetworkIdentityLicense +import dev.slne.surf.roleplay.server.player.db.RpPlayerRepository +import net.kyori.adventure.key.Key +import org.jetbrains.exposed.sql.SqlExpressionBuilder.eq +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.deleteWhere +import org.springframework.stereotype.Repository +import java.time.ZonedDateTime +import java.util.* + +@CoroutineTransactional +@Repository +class LicenseRepository(private val rpPlayerRepository: RpPlayerRepository) { + + suspend fun findLicensesForIdentity( + uuid: UUID, + type: RpIdentityType + ): List { + val playerId = rpPlayerRepository.findPlayerId(uuid) ?: return emptyList() + return IdentityLicenseModel.find { (IdentityLicenseTable.player eq playerId) and (IdentityLicenseTable.identity eq type) } + .map { it.toNetwork() } + } + + suspend fun createLicense( + uuid: UUID, + identityType: RpIdentityType, + licenseKey: Key, + expiresAt: ZonedDateTime?, + createdAt: ZonedDateTime + ) { + val playerModel = rpPlayerRepository.findOrCreateModel(uuid) + + IdentityLicenseModel.new { + this.player = playerModel + this.identity = identityType + this.license = licenseKey + this.expiresAt = expiresAt + this.createdAt = createdAt + } + } + + suspend fun deleteLicense(uuid: UUID, identityType: RpIdentityType, licenseKey: Key): Int { + val playerId = rpPlayerRepository.findPlayerId(uuid) ?: return 0 + val deleted = IdentityLicenseTable.deleteWhere { + (player eq playerId) and (identity eq identityType) and (license eq licenseKey) + } + return deleted + } +} \ No newline at end of file diff --git a/surf-roleplay-server/src/main/resources/standalone-plugin.yml b/surf-roleplay-server/src/main/resources/standalone-plugin.yml new file mode 100644 index 0000000..7c2640f --- /dev/null +++ b/surf-roleplay-server/src/main/resources/standalone-plugin.yml @@ -0,0 +1,8 @@ +name: surf-roleplay-server +main: 'dev.slne.surf.roleplay.server.PluginMain' +bootstrapper: 'dev.slne.surf.roleplay.server.PluginBootstrap' +version: 1.21.7-1.0.0 +description: 'Roleplay Plugin' +authors: + - 'Ammo' + - 'Jo_field' \ No newline at end of file