From 40797db7e247b362ce8f7ad707612d872982760e Mon Sep 17 00:00:00 2001 From: Kaique Lisboa Date: Mon, 25 Sep 2023 23:34:58 -0300 Subject: [PATCH] Feature: Adds drink XP feature --- .../github/lucaargolo/kibe/utils/FluidUtil.kt | 2 + .../github/lucaargolo/kibe/utils/ModConfig.kt | 2 + .../github/lucaargolo/kibe/utils/XpUtils.kt | 77 +++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 src/main/kotlin/io/github/lucaargolo/kibe/utils/XpUtils.kt diff --git a/src/main/kotlin/io/github/lucaargolo/kibe/utils/FluidUtil.kt b/src/main/kotlin/io/github/lucaargolo/kibe/utils/FluidUtil.kt index 3831cdf..904eadf 100644 --- a/src/main/kotlin/io/github/lucaargolo/kibe/utils/FluidUtil.kt +++ b/src/main/kotlin/io/github/lucaargolo/kibe/utils/FluidUtil.kt @@ -25,6 +25,8 @@ fun writeTank(tag: NbtCompound, tank: SingleVariantStorage): NbtCo fun interactPlayerHand(tank: Storage, player: PlayerEntity, hand: Hand): ActionResult { return if (FluidStorageUtil.interactWithFluidStorage(tank, player, hand)) { ActionResult.success(player.world.isClient) + } else if (!player.world.isClient && XpUtils.canPlayerDrinkXp(tank, player, hand)) { + XpUtils.donateXpAction(player, tank as SingleVariantStorage) } else { ActionResult.PASS } diff --git a/src/main/kotlin/io/github/lucaargolo/kibe/utils/ModConfig.kt b/src/main/kotlin/io/github/lucaargolo/kibe/utils/ModConfig.kt index 81677f1..fc66f34 100644 --- a/src/main/kotlin/io/github/lucaargolo/kibe/utils/ModConfig.kt +++ b/src/main/kotlin/io/github/lucaargolo/kibe/utils/ModConfig.kt @@ -26,6 +26,8 @@ class ModConfig { var lassoDenyList: ArrayList = arrayListOf() //Max rings per player var maxRingsPerPlayer: Int = 1 + //Should interacting with XP tank make player drink the XP + var xpTankDrinkOnRightClick: Boolean = true } class ChunkLoaderModule { diff --git a/src/main/kotlin/io/github/lucaargolo/kibe/utils/XpUtils.kt b/src/main/kotlin/io/github/lucaargolo/kibe/utils/XpUtils.kt new file mode 100644 index 0000000..6cd422f --- /dev/null +++ b/src/main/kotlin/io/github/lucaargolo/kibe/utils/XpUtils.kt @@ -0,0 +1,77 @@ +package io.github.lucaargolo.kibe.utils + +import io.github.lucaargolo.kibe.MOD_CONFIG +import io.github.lucaargolo.kibe.fluids.LIQUID_XP +import io.github.lucaargolo.kibe.fluids.miscellaneous.LiquidXpFluid +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidConstants +import net.fabricmc.fabric.api.transfer.v1.fluid.FluidVariant +import net.fabricmc.fabric.api.transfer.v1.storage.Storage +import net.fabricmc.fabric.api.transfer.v1.storage.base.SingleVariantStorage +import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.sound.SoundCategory +import net.minecraft.sound.SoundEvents +import net.minecraft.util.ActionResult +import net.minecraft.util.Hand +import kotlin.math.min + + +object XpUtils { + + const val MB_PER_XP = FluidConstants.BUCKET / 100 + + private fun isTankValidXpDonor(tank: Storage) = + tank is SingleVariantStorage && tank.variant.fluid is LiquidXpFluid + + + fun expToReachNextLvl(nextLevelExp: Int, progress: Float): Int { + return nextLevelExp - (nextLevelExp * progress).toInt() + } + + fun convertXpToMilibuckets(xp: Long) = MB_PER_XP * xp + + fun convertMilibucketsToXp(milibuckets: Long) = milibuckets / MB_PER_XP + + fun donateXpAction(player: PlayerEntity, tank: SingleVariantStorage): ActionResult { + if(tank.amount < MB_PER_XP) return ActionResult.FAIL + + val xpToNextLevel = expToReachNextLvl(player.nextLevelExperience, player.experienceProgress) + + val liquidXpToExtract = min( + convertXpToMilibuckets(xpToNextLevel.toLong()), + tank.amount + ) + + Transaction.openOuter().also { transaction -> + var extractedAmount = -1L + tank.extract(FluidVariant.of(LIQUID_XP), liquidXpToExtract, transaction).let { extractedAmount = it } + transaction.addCloseCallback { _, result -> + if(result.wasAborted()) { + return@addCloseCallback + } + player.addExperience(convertMilibucketsToXp(liquidXpToExtract).toInt()) + if(extractedAmount > 0) { + player.world.playSound( + null, + player.blockPos, + SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP, + SoundCategory.AMBIENT, + .5f, + player.world.random.nextBetween(3,9).toFloat() / 10) + } + } + transaction.commit() + } + + return ActionResult.success(true) + } + + fun canPlayerDrinkXp(tank: Storage, player: PlayerEntity, hand: Hand): Boolean { + return MOD_CONFIG.miscellaneousModule.xpTankDrinkOnRightClick && + player.mainHandStack.isEmpty && + hand == Hand.MAIN_HAND && + isTankValidXpDonor(tank) + + } + +} \ No newline at end of file