-
Notifications
You must be signed in to change notification settings - Fork 17
Add liquid XP #809
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
base: master
Are you sure you want to change the base?
Add liquid XP #809
Changes from all commits
e35bb5d
fe0fb2e
34176f9
e871eae
35343c3
00e4c06
bbea585
c300932
8b3bde2
0ff15bb
ef088dc
ba10a5f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,137 @@ | ||
| package io.github.pylonmc.pylon.content.machines.experience; | ||
|
|
||
| import io.github.pylonmc.pylon.PylonFluids; | ||
| import io.github.pylonmc.pylon.PylonKeys; | ||
| import io.github.pylonmc.pylon.util.PylonUtils; | ||
| import io.github.pylonmc.rebar.block.RebarBlock; | ||
| import io.github.pylonmc.rebar.block.base.RebarFluidBufferBlock; | ||
| import io.github.pylonmc.rebar.block.base.RebarSimpleMultiblock; | ||
| import io.github.pylonmc.rebar.block.base.RebarTickingBlock; | ||
| import io.github.pylonmc.rebar.block.context.BlockCreateContext; | ||
| import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; | ||
| import io.github.pylonmc.rebar.fluid.FluidPointType; | ||
| import io.github.pylonmc.rebar.i18n.RebarArgument; | ||
| import io.github.pylonmc.rebar.item.RebarItem; | ||
| import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; | ||
| import io.github.pylonmc.rebar.waila.WailaDisplay; | ||
| import net.kyori.adventure.text.Component; | ||
| import net.kyori.adventure.text.format.TextColor; | ||
| import org.bukkit.Material; | ||
| import org.bukkit.block.Block; | ||
| import org.bukkit.block.BlockFace; | ||
| import org.bukkit.entity.Player; | ||
| import org.bukkit.inventory.ItemStack; | ||
| import org.bukkit.persistence.PersistentDataContainer; | ||
| import org.jetbrains.annotations.NotNull; | ||
| import org.jetbrains.annotations.Nullable; | ||
| import org.joml.Vector3i; | ||
|
|
||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| public class ExperienceDrain extends RebarBlock implements RebarTickingBlock, RebarFluidBufferBlock, RebarSimpleMultiblock { | ||
| public final int xpDrainPeriodTicks = getSettings().getOrThrow("xp-drain-period-ticks", ConfigAdapter.INTEGER); | ||
| public final int xpDrainAmount = getSettings().getOrThrow("xp-drain-amount", ConfigAdapter.INTEGER); | ||
| public final int xpBufferAmount = getSettings().getOrThrow("xp-buffer-amount", ConfigAdapter.INTEGER); | ||
| private static final MultiblockComponent PEDESTAL_COMPONENT = new RebarSimpleMultiblock.VanillaMultiblockComponent(Material.COBBLESTONE_WALL); | ||
|
|
||
| public ExperienceDrain(@NotNull Block block, BlockCreateContext ctx) { | ||
| super(block, ctx); | ||
| createFluidBuffer(PylonFluids.LIQUID_XP, xpBufferAmount, false, true); | ||
| createFluidPoint(FluidPointType.OUTPUT, BlockFace.NORTH, ctx, false, 0.5f); | ||
| setTickInterval(xpDrainPeriodTicks); | ||
| } | ||
|
|
||
| public ExperienceDrain(@NotNull Block block, PersistentDataContainer pdc) { | ||
| super(block, pdc); | ||
| } | ||
|
|
||
| @Override | ||
| public @Nullable WailaDisplay getWaila(@NotNull Player player) { | ||
| return new WailaDisplay(getDefaultWailaTranslationKey().arguments( | ||
| RebarArgument.of("bar", PylonUtils.createFluidAmountBar( | ||
| fluidAmount(PylonFluids.LIQUID_XP), | ||
| fluidCapacity(PylonFluids.LIQUID_XP), | ||
| 20, | ||
| TextColor.fromHexString("#1dcE420") | ||
| )) | ||
| )); | ||
| } | ||
|
|
||
| @Override | ||
| public @NotNull Map<@NotNull Vector3i, @NotNull MultiblockComponent> getComponents() { | ||
| return Map.of( | ||
| new Vector3i(3, 0, 0), PEDESTAL_COMPONENT, | ||
| new Vector3i(2, 0, 2), PEDESTAL_COMPONENT, | ||
| new Vector3i(0, 0, 3), PEDESTAL_COMPONENT, | ||
| new Vector3i(-2, 0, 2), PEDESTAL_COMPONENT, | ||
| new Vector3i(-3, 0, 0), PEDESTAL_COMPONENT, | ||
| new Vector3i(-2, 0, -2), PEDESTAL_COMPONENT, | ||
| new Vector3i(0, 0, -3), PEDESTAL_COMPONENT, | ||
| new Vector3i(2, 0, -2), PEDESTAL_COMPONENT | ||
| ); | ||
| } | ||
|
Comment on lines
+61
to
+73
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there any reason for this to be a multiblock? It seems a bit illogical to me especially as the other blocks are not magic components and serve no functional purpose |
||
|
|
||
| // For some unknown reason, if you use /xp to give someone xp, it doesn't update player.getTotalExperience | ||
| public int getRealTotalExperience(Player player) { | ||
| int level = player.getLevel(); | ||
| int totalExp = 0; | ||
|
|
||
| if (level <= 16) { | ||
| totalExp = (int) (Math.pow(level, 2) + (6 * level)); | ||
| } else if (level <= 31) { | ||
| totalExp = (int) (2.5 * Math.pow(level, 2) - (40.5 * level) + 360); | ||
| } else { | ||
| totalExp = (int) (4.5 * Math.pow(level, 2) - (162.5 * level) + 2220); | ||
| } | ||
|
|
||
| float progress = player.getExp(); | ||
| int expForNextLevel = Math.round(getExpToNextLevel(level) * progress); | ||
|
|
||
| return totalExp + expForNextLevel; | ||
| } | ||
|
|
||
| private int getExpToNextLevel(int level) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can be static (probably doesnt need to be its own function anyway as it's only used in 1 place) |
||
| if (level <= 15) return 2 * level + 7; | ||
| if (level <= 30) return 5 * level - 38; | ||
| return 9 * level - 158; | ||
| } | ||
|
|
||
| public int subtractExperience(Player player, int amountToSubtract) { | ||
| int currentTotalExp = getRealTotalExperience(player); | ||
|
|
||
| int actualSubtracted = Math.min(currentTotalExp, amountToSubtract); | ||
| int newTotalExp = currentTotalExp - actualSubtracted; | ||
|
|
||
| player.setExp(0); | ||
| player.setLevel(0); | ||
| player.setTotalExperience(0); | ||
|
|
||
| player.giveExp(newTotalExp); | ||
|
|
||
| return actualSubtracted; | ||
| } | ||
|
|
||
| @Override | ||
| public void tick() { | ||
| for (Player player : getBlock().getWorld().getNearbyPlayers(getBlock().getLocation(), 1d, 5d, Player::isSneaking)) { | ||
| int actualSubtracted = subtractExperience(player, Math.min(xpDrainAmount, (int) Math.floor(fluidSpaceRemaining(PylonFluids.LIQUID_XP)))); | ||
| addFluid(PylonFluids.LIQUID_XP, actualSubtracted); | ||
| } | ||
| } | ||
|
|
||
| public static class Item extends RebarItem { | ||
| public final int xpDrainPeriodTicks = getSettings().getOrThrow("xp-drain-period-ticks", ConfigAdapter.INTEGER); | ||
| public final int xpDrainAmount = getSettings().getOrThrow("xp-drain-amount", ConfigAdapter.INTEGER); | ||
|
|
||
| public Item(@NotNull ItemStack stack) { | ||
| super(stack); | ||
| } | ||
|
|
||
| @Override | ||
| public @NotNull List<@NotNull RebarArgument> getPlaceholders() { | ||
| return List.of( | ||
| RebarArgument.of("xp-drain-rate", UnitFormat.EXPERIENCE_PER_SECOND.format((double) xpDrainAmount / ((double) xpDrainPeriodTicks / 20)))); | ||
| } | ||
| } | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. XP is spawned on the corner of this block atm, I think it would be nice to have the XP orbs come out of the top of the spout
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The orbs aren't merging together for some reason. No idea why this would be but it's probably a good idea to look into it because that could cause a lot of lag if the machine is just left on |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| package io.github.pylonmc.pylon.content.machines.experience; | ||
|
|
||
| import io.github.pylonmc.pylon.PylonFluids; | ||
| import io.github.pylonmc.pylon.PylonKeys; | ||
| import io.github.pylonmc.pylon.util.PylonUtils; | ||
| import io.github.pylonmc.rebar.block.RebarBlock; | ||
| import io.github.pylonmc.rebar.block.base.RebarFluidBufferBlock; | ||
| import io.github.pylonmc.rebar.block.base.RebarSimpleMultiblock; | ||
| import io.github.pylonmc.rebar.block.base.RebarTickingBlock; | ||
| import io.github.pylonmc.rebar.block.context.BlockCreateContext; | ||
| import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; | ||
| import io.github.pylonmc.rebar.fluid.FluidPointType; | ||
| import io.github.pylonmc.rebar.i18n.RebarArgument; | ||
| import io.github.pylonmc.rebar.item.RebarItem; | ||
| import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; | ||
| import io.github.pylonmc.rebar.waila.WailaDisplay; | ||
| import net.kyori.adventure.text.format.TextColor; | ||
| import org.bukkit.block.Block; | ||
| import org.bukkit.block.BlockFace; | ||
| import org.bukkit.entity.EntityType; | ||
| import org.bukkit.entity.ExperienceOrb; | ||
| import org.bukkit.entity.Player; | ||
| import org.bukkit.inventory.ItemStack; | ||
| import org.bukkit.persistence.PersistentDataContainer; | ||
| import org.jetbrains.annotations.NotNull; | ||
| import org.jetbrains.annotations.Nullable; | ||
| import org.joml.Vector3i; | ||
|
|
||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
| public class ExperienceFountain extends RebarBlock implements RebarTickingBlock, RebarFluidBufferBlock, RebarSimpleMultiblock { | ||
| public final int amountToConvert = getSettings().getOrThrow("amount-to-convert", ConfigAdapter.INTEGER); | ||
| public final int tickInterval = getSettings().getOrThrow("tick-interval", ConfigAdapter.INTEGER); | ||
| public final int liquidXpCapacity = getSettings().getOrThrow("liquid-xp-capacity", ConfigAdapter.INTEGER); | ||
|
|
||
| public ExperienceFountain(@NotNull Block block, BlockCreateContext ctx) { | ||
| super(block, ctx); | ||
| createFluidBuffer(PylonFluids.LIQUID_XP, liquidXpCapacity, true, false); | ||
| createFluidPoint(FluidPointType.INPUT, BlockFace.WEST, ctx, false, 0.5f); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fluid point should spawn facing the player by convention (north or south, can't remember which) |
||
| setTickInterval(tickInterval); | ||
| } | ||
|
|
||
| public ExperienceFountain(@NotNull Block block, PersistentDataContainer pdc) { | ||
| super(block, pdc); | ||
| } | ||
|
|
||
| @Override | ||
| public void tick() { | ||
| if(!isFormedAndFullyLoaded()){ | ||
| return; | ||
| } | ||
| int amountConverted = (int)Math.min(amountToConvert, fluidAmount(PylonFluids.LIQUID_XP)); | ||
| if(amountConverted <= 0){ | ||
| return; | ||
| } | ||
| removeFluid(PylonFluids.LIQUID_XP, amountConverted); | ||
| ExperienceOrb orb = (ExperienceOrb) getBlock().getWorld().spawnEntity(getBlock().getLocation(), EntityType.EXPERIENCE_ORB); | ||
| orb.setExperience(amountConverted); | ||
| } | ||
|
|
||
| @Override | ||
| public @Nullable WailaDisplay getWaila(@NotNull Player player) { | ||
| return new WailaDisplay(getDefaultWailaTranslationKey().arguments( | ||
| RebarArgument.of("bar", PylonUtils.createFluidAmountBar( | ||
| fluidAmount(PylonFluids.LIQUID_XP), | ||
| fluidCapacity(PylonFluids.LIQUID_XP), | ||
| 20, | ||
| TextColor.fromHexString("#1dc420") | ||
| )) | ||
| )); | ||
| } | ||
|
|
||
| @Override | ||
| public @NotNull Map<@NotNull Vector3i, @NotNull MultiblockComponent> getComponents() { | ||
| return Map.of(new Vector3i(0, 1, 0), new RebarSimpleMultiblock.RebarMultiblockComponent(PylonKeys.EXPERIENCE_FOUNTAIN_SPOUT)); | ||
| } | ||
|
|
||
| public static class Item extends RebarItem { | ||
| public final int amountToConvert = getSettings().getOrThrow("amount-to-convert", ConfigAdapter.INTEGER); | ||
| public final int tickInterval = getSettings().getOrThrow("tick-interval", ConfigAdapter.INTEGER); | ||
|
|
||
| public Item(@NotNull ItemStack stack) { | ||
| super(stack); | ||
| } | ||
|
|
||
| @Override | ||
| public @NotNull List<@NotNull RebarArgument> getPlaceholders() { | ||
| return List.of(RebarArgument.of("production-rate", UnitFormat.EXPERIENCE_PER_SECOND.format((double) amountToConvert / ((double) tickInterval / 20)).decimalPlaces(0))); | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reckon some particles when XP is drained would be really nice here