Skip to content

Commit

Permalink
PC-1050 Implements door permission check and necessary subsystems
Browse files Browse the repository at this point in the history
  • Loading branch information
Polyana committed Dec 28, 2023
1 parent 7541e64 commit c10268a
Show file tree
Hide file tree
Showing 13 changed files with 192 additions and 48 deletions.
6 changes: 6 additions & 0 deletions api/src/main/kotlin/br/com/gamemods/minecity/api/MineCity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package br.com.gamemods.minecity.api

import br.com.gamemods.minecity.api.annotation.internal.InternalMineCityApi
import br.com.gamemods.minecity.api.service.MineCityInternal
import br.com.gamemods.minecity.api.service.claim.ClaimService
import br.com.gamemods.minecity.api.service.namedplayer.NamedPlayerService
import br.com.gamemods.minecity.api.service.permission.PermissionService

Expand All @@ -25,6 +26,11 @@ public interface MineCity {
*/
public val permission: PermissionService

/**
* Allows to get the claims with easy
*/
public val claims: ClaimService

/**
* This companion object allows MineCity interface to be used directly in kotlin delegating all API calls to
* the instance that is set at [MineCityInternal.implementation].
Expand Down
27 changes: 25 additions & 2 deletions api/src/main/kotlin/br/com/gamemods/minecity/api/claim/Claim.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,40 @@
package br.com.gamemods.minecity.api.claim

import br.com.gamemods.minecity.api.MineCity
import br.com.gamemods.minecity.api.annotation.internal.InternalMineCityApi
import br.com.gamemods.minecity.api.id.ClaimId
import br.com.gamemods.minecity.api.id.ClaimPermissionId
import br.com.gamemods.minecity.api.serializer.UniqueId
import br.com.gamemods.minecity.api.service.MineCityInternal
import kotlinx.serialization.Serializable

@Serializable
public data class Claim(
val id: ClaimId = ClaimId(),
val id: ClaimId,
val shape: Set<ClaimShape>,
val name: String,
val parentId: ClaimId? = null,
val owner: UniqueId? = null,
val rent: ClaimRentContract? = null,
val city: City? = null,
val isAdmin: Boolean = false,
val settings: ClaimSettings = ClaimSettings(),
)
) {
@OptIn(InternalMineCityApi::class)
public fun hasPermission(playerId: UniqueId, permissionId: ClaimPermissionId, silent: Boolean = false): Boolean {
if (MineCity.players.isAdminMode(playerId)) {
return true
}
if (rent != null && rent.rentedTo == playerId) {
return true
} else if (playerId == owner) {
return true
}

val allow = settings.hasPermission(playerId, permissionId)
if (!allow && !silent) {
MineCity.players.sendMessage(playerId, MineCityInternal.permissionDeniedMessage(this, permissionId))
}
return allow
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package br.com.gamemods.minecity.api.claim

import br.com.gamemods.minecity.api.id.ClaimPermissionId
import br.com.gamemods.minecity.api.id.ClamFlagId
import br.com.gamemods.minecity.api.id.ClamPermissionId
import br.com.gamemods.minecity.api.serializer.UniqueId
import kotlinx.serialization.Serializable

/**
Expand All @@ -14,6 +15,22 @@ import kotlinx.serialization.Serializable
@Serializable
public data class ClaimSettings(
val defaultFlags: Map<ClamFlagId, ClaimFlagValue> = emptyMap(),
val defaultPermissions: Map<ClamPermissionId, Boolean?> = emptyMap(),
val defaultPermissions: Map<ClaimPermissionId, Boolean?> = emptyMap(),
val trustLevels: List<TrustLevel> = emptyList(),
)
) {
/**
* Calculates the effective flags of this claim.
*
* @param playerId The player that is checking the flags
* @return The effective flags of this claim
*/
public fun hasPermission(playerId: UniqueId, permissionId: ClaimPermissionId): Boolean {
return defaultPermissions[permissionId] ?: trustLevels.fold(false) { currentResult, level ->
if (playerId !in level.players) {
currentResult
} else {
level.permissions[permissionId] ?: currentResult
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package br.com.gamemods.minecity.api.claim

import br.com.gamemods.minecity.api.id.ClaimPermissionId
import br.com.gamemods.minecity.api.id.ClamFlagId
import br.com.gamemods.minecity.api.id.ClamPermissionId
import br.com.gamemods.minecity.api.id.TrustLevelId
import br.com.gamemods.minecity.api.serializer.MiniComponent
import br.com.gamemods.minecity.api.serializer.UniqueId
Expand All @@ -21,5 +21,5 @@ public data class TrustLevel(
val displayName: MiniComponent,
val players: Set<UniqueId> = emptySet(),
val flags: Map<ClamFlagId, ClaimFlagValue> = emptyMap(),
val permissions: Map<ClamPermissionId, Boolean?> = emptyMap()
val permissions: Map<ClaimPermissionId, Boolean?> = emptyMap()
)

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package br.com.gamemods.minecity.api.service

import br.com.gamemods.minecity.api.MineCity
import br.com.gamemods.minecity.api.annotation.internal.InternalMineCityApi
import br.com.gamemods.minecity.api.claim.Claim
import br.com.gamemods.minecity.api.id.ClaimPermissionId
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.format.NamedTextColor

/**
* Internal MineCity states and services, should not be used by API users.
Expand All @@ -12,4 +16,19 @@ public object MineCityInternal {
* Access to the MineCity API implementation, must be modified only by MineCity itself, can be accessed freely.
*/
public lateinit var implementation: MineCity

/**
* Creates a message to be sent to the player when a permission is denied.
*/
public fun permissionDeniedMessage(claim: Claim, permissionId: ClaimPermissionId): Component {
return Component.text()
.content("MineCity> ").color(NamedTextColor.DARK_RED)
.append(
Component.text().color(NamedTextColor.RED)
.append(Component.text("You don't have "))
.append(MineCity.permission[permissionId].name.color(NamedTextColor.YELLOW))
.append(Component.text(" permission in "))
.append(Component.text(claim.name, NamedTextColor.YELLOW))
).build()
}
}
Original file line number Diff line number Diff line change
@@ -1,33 +1,47 @@
package br.com.gamemods.minecity.api.service.namedplayer

import br.com.gamemods.minecity.api.annotation.threading.ASyncFriendly
import br.com.gamemods.minecity.api.annotation.threading.SyncFriendly
import br.com.gamemods.minecity.api.id.NamedPlayer
import br.com.gamemods.minecity.api.serializer.UniqueId
import kotlinx.coroutines.Deferred
import java.util.*
import net.kyori.adventure.text.Component

/**
* Manages the [NamedPlayer] objects.
*/
public interface NamedPlayerService {
/**
* Gets [NamedPlayer] for the given player [uuid], attempts to use a cached value before starting a query.
* Gets [NamedPlayer] for the given player [playerId], attempts to use a cached value before starting a query.
*/
public operator fun get(uuid: UUID): Deferred<NamedPlayer?>
public operator fun get(playerId: UniqueId): Deferred<NamedPlayer?>

/**
* Gets [NamedPlayer] for the given player [name], attempts to use a cached value before starting a query.
*/
public operator fun get(name: String): Deferred<NamedPlayer?>

/**
* Checks if the given player [uuid] has ready-to-use cached value.
* Checks if the given player [playerId] has ready-to-use cached value.
*/
@SyncFriendly
public operator fun contains(uuid: UUID): Boolean
public operator fun contains(playerId: UniqueId): Boolean

/**
* Checks if the given player [name] has ready-to-use cached value.
*/
@SyncFriendly
public operator fun contains(name: String): Boolean

/**
* Sends a message to the given player [playerId] if the player is online.
*/
@SyncFriendly
@ASyncFriendly
public fun sendMessage(playerId: UniqueId, message: Component)

/**
* Checks if the given player [playerId] is in admin mode.
*/
public fun isAdminMode(playerId: UniqueId): Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import br.com.gamemods.minecity.api.MineCity
import br.com.gamemods.minecity.api.MineCityPlatform
import br.com.gamemods.minecity.api.annotation.internal.InternalMineCityApi
import br.com.gamemods.minecity.api.annotation.side.ServerSideOnly
import br.com.gamemods.minecity.api.service.claim.ClaimService
import br.com.gamemods.minecity.api.service.namedplayer.NamedPlayerService
import br.com.gamemods.minecity.api.service.permission.PermissionService
import br.com.gamemods.minecity.core.service.world.WorldService
Expand All @@ -23,6 +24,7 @@ class MineCityCore(
val worlds: WorldService,
override val players: NamedPlayerService,
override val permission: PermissionService,
override val claims: ClaimService,
): MineCity {

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package br.com.gamemods.minecity.core.service.claim

import br.com.gamemods.minecity.api.annotation.internal.InternalMineCityApi
import br.com.gamemods.minecity.api.claim.Claim
import br.com.gamemods.minecity.api.id.ClaimId
import br.com.gamemods.minecity.api.id.WorldId
import br.com.gamemods.minecity.api.math.pos.BlockGridPositioned
import br.com.gamemods.minecity.api.service.claim.ClaimService
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Deferred

@InternalMineCityApi
class CoreClaimService: ClaimService {
@Suppress("CanBeVal", "UnnecessaryVariable")
override fun get(worldId: WorldId, pos: BlockGridPositioned): Claim? {
//TODO Implement
var result: Claim? = Claim(
id = ClaimId(),
shape = emptySet(),
name = "TestClaim",
)
//result = null
return result
}

override fun load(worldId: WorldId, pos: BlockGridPositioned): Deferred<Claim?> {
//TODO Implement
return CompletableDeferred(null)
}

override fun create(claim: Claim): Deferred<Claim> {
//TODO Implement
return CompletableDeferred(claim)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import br.com.gamemods.minecity.api.service.MineCityInternal
import br.com.gamemods.minecity.core.MineCityCore
import br.com.gamemods.minecity.core.dispatchers.Async
import br.com.gamemods.minecity.core.dispatchers.Sync
import br.com.gamemods.minecity.core.service.claim.CoreClaimService
import br.com.gamemods.minecity.core.service.permission.CorePermissionService
import br.com.gamemods.minecity.fabric.math.pos.FabricBlockLocation
import br.com.gamemods.minecity.fabric.math.pos.FabricChunkLocation
Expand Down Expand Up @@ -63,6 +64,7 @@ object MineCityFabric : ModInitializer, MineCityPlatform {
worlds = FabricWorldService(this),
players = FabricNamedPlayerService(this),
permission = CorePermissionService(),
claims = CoreClaimService(),
)
MineCityInternal.implementation = core
core.onInitialize()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package br.com.gamemods.minecity.fabric.service

import br.com.gamemods.minecity.api.annotation.internal.InternalMineCityApi
import br.com.gamemods.minecity.api.id.NamedPlayer
import br.com.gamemods.minecity.api.serializer.UniqueId
import br.com.gamemods.minecity.api.service.namedplayer.NamedPlayerService
import br.com.gamemods.minecity.fabric.MineCityFabric
import com.google.common.cache.CacheBuilder
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.datetime.Clock
import net.kyori.adventure.text.Component
import java.util.*
import java.util.concurrent.TimeUnit

Expand All @@ -17,12 +19,27 @@ class FabricNamedPlayerService(private val platform: MineCityFabric): NamedPlaye
private val uuid2named = CacheBuilder.newBuilder().expireAfterAccess(30L, TimeUnit.MINUTES).build<UUID, Deferred<NamedPlayer?>>()
private val name2named = CacheBuilder.newBuilder().expireAfterAccess(30L, TimeUnit.MINUTES).build<String, Deferred<NamedPlayer?>>()

override fun get(uuid: UUID): Deferred<NamedPlayer?> {
override fun isAdminMode(playerId: UniqueId): Boolean {
//TODO Implement
return false
}

@Suppress("DeferredResultUnused")
override fun sendMessage(playerId: UniqueId, message: Component) {
platform.runOnServer { server ->
server.syncOnly {
server.mcServer.native.playerManager.getPlayer(playerId)?.sendMessage(message)
}
}
}

@Suppress("CheckedExceptionsKotlin")
override fun get(playerId: UUID): Deferred<NamedPlayer?> {
@Suppress("DuplicatedCode")
return uuid2named.get(uuid) {
return uuid2named.get(playerId) {
platform.runOnServer { server ->
server.syncOnly {
server.mcServer.native.playerManager.getPlayer(uuid)?.let { player ->
server.mcServer.native.playerManager.getPlayer(playerId)?.let { player ->
NamedPlayer(player.uuid, player.entityName, Clock.System.now()).also { named ->
name2named.put(named.name, CompletableDeferred(named))
}
Expand All @@ -32,6 +49,7 @@ class FabricNamedPlayerService(private val platform: MineCityFabric): NamedPlaye
}
}

@Suppress("CheckedExceptionsKotlin")
override fun get(name: String): Deferred<NamedPlayer?> {
@Suppress("DuplicatedCode")
return name2named.get(name) {
Expand All @@ -48,8 +66,8 @@ class FabricNamedPlayerService(private val platform: MineCityFabric): NamedPlaye
}

@OptIn(ExperimentalCoroutinesApi::class)
override fun contains(uuid: UUID): Boolean {
return uuid2named.getIfPresent(uuid)?.let { deferred ->
override fun contains(playerId: UUID): Boolean {
return uuid2named.getIfPresent(playerId)?.let { deferred ->
if (deferred.isCompleted) {
try {
deferred.getCompleted() != null
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package br.com.gamemods.minecity.fabric.service.claim

import br.com.gamemods.minecity.api.annotation.PlatformDependent
import br.com.gamemods.minecity.api.annotation.internal.InternalMineCityApi
import br.com.gamemods.minecity.api.id.WorldId
import br.com.gamemods.minecity.api.service.claim.ClaimService
import br.com.gamemods.minecity.fabric.wrapper.FabricBlockPosWrapper.Companion.wrapper
import net.minecraft.registry.RegistryKey
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World

@InternalMineCityApi
class FabricClaimService {
companion object {
operator fun ClaimService.get(world: World, pos: BlockPos) = this[world.mineCityWorldId, pos.wrapper]

@OptIn(PlatformDependent::class)
val RegistryKey<World>.mineCityWorldId get() = WorldId(value.toString())

val World.mineCityWorldId get() = registryKey.mineCityWorldId
}
}
Loading

0 comments on commit c10268a

Please sign in to comment.