From 67771102ea628d558a02dc2eed7f6a127ee978b9 Mon Sep 17 00:00:00 2001 From: Alice Isabel Date: Mon, 1 Jan 2024 23:01:34 -0300 Subject: [PATCH 1/7] Fix wrong ActionResult on FabricDoorClaimPermission `ActionResult.SUCCESS` is used to indicate to FabricAPI that *all processing is done*, since it "cancels further processing". Although it might seem that this is what you want to convey, unfortunately since it cancels ALL further processing, the first callback to get that event from the queue consumes it, and all the logic that should follow that is blocked from ever existing. The most common (and visible) side effect is the complete inability to place any blocks in the world, even though this permission should only ever check for block interactions not new blocks being placed. Placing blocks is another permission entirely, and since this is a clear overreach of `FabricDoorClaimPermission`, which should only "Allow the player to open and close doors in the claim." --- .../fabric/service/permission/FabricDoorClaimPermission.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/service/permission/FabricDoorClaimPermission.kt b/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/service/permission/FabricDoorClaimPermission.kt index 316ea19..8d145f4 100644 --- a/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/service/permission/FabricDoorClaimPermission.kt +++ b/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/service/permission/FabricDoorClaimPermission.kt @@ -41,7 +41,7 @@ class FabricDoorClaimPermission: ClaimPermission( val block = blockState.block if (block !is DoorBlock && block !is TrapdoorBlock) { - return ActionResult.SUCCESS + return ActionResult.PASS } val claim = MineCity.claims[world, clickPos] ?: return ActionResult.PASS From 41bf1b2f218e2aff476ac8d29fc49f6f2aa43dac Mon Sep 17 00:00:00 2001 From: Alice Isabel Date: Mon, 1 Jan 2024 23:42:34 -0300 Subject: [PATCH 2/7] Add reflection helpers. Currently only has `isInstanceOfAny` and `isInstanceOfNone` functions. --- .../minecity/core/helpers/Reflection.kt | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 core/src/main/kotlin/br/com/gamemods/minecity/core/helpers/Reflection.kt diff --git a/core/src/main/kotlin/br/com/gamemods/minecity/core/helpers/Reflection.kt b/core/src/main/kotlin/br/com/gamemods/minecity/core/helpers/Reflection.kt new file mode 100644 index 0000000..a837f2a --- /dev/null +++ b/core/src/main/kotlin/br/com/gamemods/minecity/core/helpers/Reflection.kt @@ -0,0 +1,42 @@ +package br.com.gamemods.minecity.core.helpers + +import kotlin.reflect.KClass +import kotlin.reflect.full.isSubclassOf + +/** + * Checks if an object **is** an instance of **ANY** of the classes given. + * @param types A list of [KClass] that will be checked. + * + * The following code examples are equivalent. + * ```kt + * obj is TypeA || obj is TypeB + * obj.isInstanceOfAny(TypeA::class, TypeB::class) + * ``` + * @author alikindsys + */ +fun Any.isInstanceOfAny(vararg types: KClass<*>): Boolean { + // Short-circuiting on a list based on an OR operation. + for (cls in types) { + // ⊤ OR { ⊥,⊤ } = ⊤ + // { ⊥,⊤ } OR ⊥ = { ⊥,⊤ } + if (this::class.isSubclassOf(cls)) return true + } + // ⊥ OR ⊥ = ⊥ + return false +} + +/** + * Checks if an object **is NOT** an instance of **ALL** the classes given. + * @param types A list of [KClass] that will be . + * + * The following code examples are equivalent. + * ```kt + * obj !is TypeA && obj !is TypeB + * obj.isInstanceOfNone(TypeA::class, TypeB::class) + * ``` + * @author alikindsys + */ +fun Any.isInstanceOfNone(vararg types: KClass<*>): Boolean { + // !(P OR Q) = (!P AND !Q) + return !this.isInstanceOfAny(*types) +} \ No newline at end of file From 778ceb180b06a813b83d837e0bb8864f58c23413 Mon Sep 17 00:00:00 2001 From: Alice Isabel Date: Mon, 1 Jan 2024 23:42:59 -0300 Subject: [PATCH 3/7] Add permission helpers. Currently only has `UniqueId.hasPermissionIn`. --- .../minecity/fabric/helpers/Permission.kt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/helpers/Permission.kt diff --git a/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/helpers/Permission.kt b/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/helpers/Permission.kt new file mode 100644 index 0000000..9948312 --- /dev/null +++ b/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/helpers/Permission.kt @@ -0,0 +1,25 @@ +package br.com.gamemods.minecity.fabric.helpers + +import br.com.gamemods.minecity.api.claim.Claim +import br.com.gamemods.minecity.api.id.ClaimPermissionId +import br.com.gamemods.minecity.api.serializer.UniqueId +import net.minecraft.util.ActionResult + +/** + * Checks if a [UniqueId] has a given [ClaimPermissionId] inside a [Claim]. + * + * *Note*: This is platform-dependent code since each loader treats [ActionResult]s differently. + * This code is **expected to work with Fabric API**'s event system. + * @param claim The claim being checked. Usually the one the player is located at. + * @param permissionId The [ClaimPermissionId] of the permission. E.g. [ClaimPermissionId.BUILD]. + * @return An [ActionResult.PASS] if the player **has** the permission. An [ActionResult.FAIL] if the player **doesn't** have the permission. + * @see [ClaimPermissionId] + * @author alikindsys + */ +fun UniqueId.hasPermissionIn(claim: Claim, permissionId: ClaimPermissionId): ActionResult { + return if (claim.hasPermission(this, permissionId)) { + ActionResult.PASS + } else { + ActionResult.FAIL + } +} From 5df569cee119dadca7b3dcad0e89f0a27f8cb919 Mon Sep 17 00:00:00 2001 From: Alice Isabel Date: Mon, 1 Jan 2024 23:43:39 -0300 Subject: [PATCH 4/7] Add world access helpers. Currently only has `BlockHitResult.blockStateBy` and `BlockHitResult.blockEntityBy`. --- .../minecity/fabric/helpers/WorldAccess.kt | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/helpers/WorldAccess.kt diff --git a/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/helpers/WorldAccess.kt b/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/helpers/WorldAccess.kt new file mode 100644 index 0000000..aa9f2d3 --- /dev/null +++ b/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/helpers/WorldAccess.kt @@ -0,0 +1,31 @@ +package br.com.gamemods.minecity.fabric.helpers + +import net.minecraft.block.BlockState +import net.minecraft.block.entity.BlockEntity +import net.minecraft.util.hit.BlockHitResult +import net.minecraft.world.World + +/** + * Gets a [BlockState] from a [BlockHitResult] by accessing a [World] + * + * You *should* have a reference to a world on which this [BlockHitResult] was queried. + * + * **Trivial**: This is a mere convenience extension function. + * @param world The world being queried. + * @author alikindsys + */ +fun BlockHitResult.blockStateBy(world: World) : BlockState { + return world.getBlockState(this.blockPos) +} + +/** + * Gets a [BlockEntity] from a [BlockHitResult] by accessing a [World] + * + * You *should* have a reference to a world on which this [BlockHitResult] was queried. + * + * **Trivial**: This is a mere convenience extension function. + * @param world The world being queried. + * @author alikindsys + */fun BlockHitResult.blockEntityBy(world: World) : BlockEntity? { + return world.getBlockEntity(this.blockPos) +} \ No newline at end of file From 2a0d3a77269bdace2cc289bb438aef308f1160ba Mon Sep 17 00:00:00 2001 From: Alice Isabel Date: Mon, 1 Jan 2024 23:48:48 -0300 Subject: [PATCH 5/7] Add `FabricButtonClaimPermission` This implements PC-1051 --- .../minecity/fabric/MineCityFabric.kt | 2 + .../permission/FabricButtonClaimPermission.kt | 58 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/service/permission/FabricButtonClaimPermission.kt diff --git a/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/MineCityFabric.kt b/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/MineCityFabric.kt index 43e94f6..dd60edd 100644 --- a/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/MineCityFabric.kt +++ b/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/MineCityFabric.kt @@ -17,6 +17,7 @@ import br.com.gamemods.minecity.fabric.math.pos.FabricEntityLocation import br.com.gamemods.minecity.fabric.server.MineCityFabricServer import br.com.gamemods.minecity.fabric.service.FabricNamedPlayerService import br.com.gamemods.minecity.fabric.service.FabricWorldService +import br.com.gamemods.minecity.fabric.service.permission.FabricButtonClaimPermission import br.com.gamemods.minecity.fabric.service.permission.FabricDoorClaimPermission import br.com.gamemods.minecity.fabric.wrapper.FabricBlockPosWrapper import br.com.gamemods.minecity.fabric.wrapper.FabricChunkPosWrapper @@ -80,6 +81,7 @@ object MineCityFabric : ModInitializer, MineCityPlatform { private fun registerPermissions() { core.permission += FabricDoorClaimPermission() + core.permission += FabricButtonClaimPermission() } @ServerSideOnly diff --git a/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/service/permission/FabricButtonClaimPermission.kt b/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/service/permission/FabricButtonClaimPermission.kt new file mode 100644 index 0000000..0bcb24f --- /dev/null +++ b/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/service/permission/FabricButtonClaimPermission.kt @@ -0,0 +1,58 @@ +package br.com.gamemods.minecity.fabric.service.permission + +import br.com.gamemods.minecity.api.MineCity +import br.com.gamemods.minecity.api.annotation.internal.InternalMineCityApi +import br.com.gamemods.minecity.api.id.ClaimPermissionId +import br.com.gamemods.minecity.api.service.permission.ClaimPermission +import br.com.gamemods.minecity.core.helpers.isInstanceOfNone +import br.com.gamemods.minecity.fabric.helpers.blockStateBy +import br.com.gamemods.minecity.fabric.helpers.hasPermissionIn +import br.com.gamemods.minecity.fabric.service.claim.FabricClaimService.Companion.get +import net.fabricmc.fabric.api.event.player.UseBlockCallback +import net.kyori.adventure.text.Component +import net.minecraft.block.ButtonBlock +import net.minecraft.block.DaylightDetectorBlock +import net.minecraft.block.LeverBlock +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.util.ActionResult +import net.minecraft.util.Hand +import net.minecraft.util.hit.BlockHitResult +import net.minecraft.util.hit.HitResult +import net.minecraft.world.World + +@InternalMineCityApi +class FabricButtonClaimPermission: ClaimPermission( + id = ClaimPermissionId.BUTTONS, + name = Component.text("Buttons"), + description = Component.text("Allows the player to trigger buttons, daylight sensors, switches and more.") +) { + override fun onRegister() { + UseBlockCallback.EVENT.register(OnUseBlock()) + } + + private inner class OnUseBlock() : UseBlockCallback { + override fun interact( player: PlayerEntity, world: World, hand: Hand, hitResult: BlockHitResult): ActionResult { + if (world.isClient) { + return ActionResult.PASS + } + + if (hitResult.type != HitResult.Type.BLOCK) { + return ActionResult.PASS + } + + val hitPos = hitResult.blockPos + val block = hitResult.blockStateBy(world).block + + if (block.isInstanceOfNone(ButtonBlock::class, LeverBlock::class, DaylightDetectorBlock::class)) { + return ActionResult.PASS + } + + val claim = MineCity.claims[world, hitPos] ?: return ActionResult.PASS + + return player.uuid.hasPermissionIn(claim, permissionId = ClaimPermissionId.BUTTONS) + } + } +} + + + From 4e26b72cfdfc226837ce2e4f8ad778e9c4179bd7 Mon Sep 17 00:00:00 2001 From: alikindsys Date: Mon, 5 Feb 2024 19:15:53 -0300 Subject: [PATCH 6/7] Add linebreak on `blockEntityBy` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lobo Metalúrgico <43734867+LoboMetalurgico@users.noreply.github.com> --- .../br/com/gamemods/minecity/fabric/helpers/WorldAccess.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/helpers/WorldAccess.kt b/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/helpers/WorldAccess.kt index aa9f2d3..c02fbcd 100644 --- a/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/helpers/WorldAccess.kt +++ b/platform/fabric/src/main/kotlin/br/com/gamemods/minecity/fabric/helpers/WorldAccess.kt @@ -26,6 +26,7 @@ fun BlockHitResult.blockStateBy(world: World) : BlockState { * **Trivial**: This is a mere convenience extension function. * @param world The world being queried. * @author alikindsys - */fun BlockHitResult.blockEntityBy(world: World) : BlockEntity? { + */ + fun BlockHitResult.blockEntityBy(world: World) : BlockEntity? { return world.getBlockEntity(this.blockPos) } \ No newline at end of file From c6325534793ff21f8d353b79e533ff9adc0db7c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lobo=20Metal=C3=BArgico?= <43734867+LoboMetalurgico@users.noreply.github.com> Date: Mon, 5 Feb 2024 21:26:39 -0300 Subject: [PATCH 7/7] (fix): ci build --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2ca3795..f5cea60 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,4 +37,4 @@ jobs: uses: actions/upload-artifact@v3 with: name: Artifacts - path: build/libs/ \ No newline at end of file + path: platform/fabric/build/libs/