Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Adds drink XP feature #220

Open
wants to merge 1 commit into
base: 1.20
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/main/kotlin/io/github/lucaargolo/kibe/utils/FluidUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ fun writeTank(tag: NbtCompound, tank: SingleVariantStorage<FluidVariant>): NbtCo
fun interactPlayerHand(tank: Storage<FluidVariant>, 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
}
Expand Down
2 changes: 2 additions & 0 deletions src/main/kotlin/io/github/lucaargolo/kibe/utils/ModConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ class ModConfig {
var lassoDenyList: ArrayList<String> = 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 {
Expand Down
77 changes: 77 additions & 0 deletions src/main/kotlin/io/github/lucaargolo/kibe/utils/XpUtils.kt
Original file line number Diff line number Diff line change
@@ -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<FluidVariant>) =
tank is SingleVariantStorage<FluidVariant> && 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<FluidVariant>): 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()
Comment on lines +48 to +63
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very important step, validating on transaction success ensures that the XP was actually drained from tank before adding the experience levels to player.

XpDrain and XpShowerBlockEntity should use wasAborted or wasCommited methods of Transaction as well, as of today, if the fluid transfer fails for whatever reason, the XP will be drained / created either way

}

return ActionResult.success(true)
}

fun canPlayerDrinkXp(tank: Storage<FluidVariant>, player: PlayerEntity, hand: Hand): Boolean {
return MOD_CONFIG.miscellaneousModule.xpTankDrinkOnRightClick &&
player.mainHandStack.isEmpty &&
hand == Hand.MAIN_HAND &&
isTankValidXpDonor(tank)

}

}