Add experience points api (#9688)

This commit is contained in:
Md5Lukas 2023-12-28 00:49:45 +01:00 committed by GitHub
parent 88d28d6bdd
commit c081104395
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 183 additions and 10 deletions

View file

@ -0,0 +1,56 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lukas Planz <lukas.planz@web.de>
Date: Tue, 5 Sep 2023 20:33:52 +0200
Subject: [PATCH] Add experience points API
diff --git a/src/main/java/org/bukkit/entity/Player.java b/src/main/java/org/bukkit/entity/Player.java
index c09f423fe2a029c933bd2697c8ff104fc4230cf0..ae61a39b25267b84fe0b8766e4b12d9b24b44ded 100644
--- a/src/main/java/org/bukkit/entity/Player.java
+++ b/src/main/java/org/bukkit/entity/Player.java
@@ -1765,6 +1765,45 @@ public interface Player extends HumanEntity, Conversable, OfflinePlayer, PluginM
* @param exp New total experience points
*/
public void setTotalExperience(int exp);
+ // Paper start
+ /**
+ * Gets the players total amount of experience points he collected to reach the current level and level progress.
+ *
+ * <p>This method differs from {@link #getTotalExperience()} in that this method always returns an
+ * up-to-date value that reflects the players{@link #getLevel() level} and {@link #getExp() level progress}</p>
+ *
+ * @return Current total experience points
+ * @see #getLevel()
+ * @see #getExp()
+ * @see #setExperienceLevelAndProgress(int)
+ */
+ @org.jetbrains.annotations.Range(from = 0, to = Integer.MAX_VALUE) int calculateTotalExperiencePoints();
+
+ /**
+ * Updates the players level and level progress to that what would be reached when the total amount of experience
+ * had been collected.
+ *
+ * <p>This method differs from {@link #setTotalExperience(int)} in that this method actually updates the
+ * {@link #getLevel() level} and {@link #getExp() level progress} so that a subsequent call of
+ * {@link #calculateTotalExperiencePoints()} yields the same amount of points that have been set</p>
+ *
+ * @param totalExperience New total experience points
+ * @see #setLevel(int)
+ * @see #setExp(float)
+ * @see #calculateTotalExperiencePoints()
+ */
+ void setExperienceLevelAndProgress(@org.jetbrains.annotations.Range(from = 0, to = Integer.MAX_VALUE) int totalExperience);
+
+ /**
+ * Gets the total amount of experience points that are needed to reach the next level from zero progress towards it.
+ *
+ * <p>Can be used with {@link #getExp()} to calculate the current points for the current level and alike</p>
+ *
+ * @return The required experience points
+ * @see #getExp()
+ */
+ int getExperiencePointsNeededForNextLevel();
+ // Paper end
/**
* Send an experience change.

View file

@ -4,21 +4,25 @@ Date: Sat, 3 Oct 2020 20:32:25 -0500
Subject: [PATCH] Fix item locations dropped from campfires Subject: [PATCH] Fix item locations dropped from campfires
Fixes #4259 by not flooring the blockposition among other weirdness Fixes #4259 by not flooring the blockposition among other weirdness
Vanilla Issue: MC-267622
diff --git a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java diff --git a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
index c4cf6abf0a962794ddbb4d7a691406054062ffee..24e2063db933bfbc8fc1f34edb8106ae4d7c633c 100644 index c4cf6abf0a962794ddbb4d7a691406054062ffee..f706c787f7608f7440a5f5e05e7e9c4cb582368c 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java --- a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
@@ -82,7 +82,11 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable { @@ -82,7 +82,14 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
result = blockCookEvent.getResult(); result = blockCookEvent.getResult();
itemstack1 = CraftItemStack.asNMSCopy(result); itemstack1 = CraftItemStack.asNMSCopy(result);
// CraftBukkit end // CraftBukkit end
- Containers.dropItemStack(world, (double) pos.getX(), (double) pos.getY(), (double) pos.getZ(), itemstack1); - Containers.dropItemStack(world, (double) pos.getX(), (double) pos.getY(), (double) pos.getZ(), itemstack1);
+ // Paper start + // Paper start
+ net.minecraft.world.entity.item.ItemEntity droppedItem = new net.minecraft.world.entity.item.ItemEntity(world, pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, itemstack1.split(world.random.nextInt(21) + 10)); + double deviation = 0.05F * RandomSource.GAUSSIAN_SPREAD_FACTOR;
+ droppedItem.setDeltaMovement(world.random.nextGaussian() * 0.05D, world.random.nextGaussian() * 0.05D + 0.2D, world.random.nextGaussian() * 0.05D); + while (!itemstack1.isEmpty()) {
+ world.addFreshEntity(droppedItem); + net.minecraft.world.entity.item.ItemEntity droppedItem = new net.minecraft.world.entity.item.ItemEntity(world, pos.getX() + 0.5D, pos.getY() + 0.5D, pos.getZ() + 0.5D, itemstack1.split(world.random.nextInt(21) + 10));
+ // Paper end + droppedItem.setDeltaMovement(world.random.triangle(0.0D, deviation), world.random.triangle(0.2D, deviation), world.random.triangle(0.0D, deviation));
+ world.addFreshEntity(droppedItem);
+ }
+ // Paper end
campfire.items.set(i, ItemStack.EMPTY); campfire.items.set(i, ItemStack.EMPTY);
world.sendBlockUpdated(pos, state, state, 3); world.sendBlockUpdated(pos, state, state, 3);
world.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(state)); world.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(state));

View file

@ -5,7 +5,7 @@ Subject: [PATCH] Add more Campfire API
diff --git a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java diff --git a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
index 04b2697ee857e714b1202d02d093b0c60f079a6f..d80855b22dc10dbf697578d5f78664ed7b6ac572 100644 index f776289eea00bd741ad55bb9bc338dd2c05c8b39..18d3cb828f85e17ec27dbb5b33c6f17fff178a1d 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java --- a/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/CampfireBlockEntity.java
@@ -42,6 +42,7 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable { @@ -42,6 +42,7 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
@ -34,7 +34,7 @@ index 04b2697ee857e714b1202d02d093b0c60f079a6f..d80855b22dc10dbf697578d5f78664ed
if (campfire.cookingProgress[i] >= campfire.cookingTime[i]) { if (campfire.cookingProgress[i] >= campfire.cookingTime[i]) {
SimpleContainer inventorysubcontainer = new SimpleContainer(new ItemStack[]{itemstack}); SimpleContainer inventorysubcontainer = new SimpleContainer(new ItemStack[]{itemstack});
@@ -168,6 +172,16 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable { @@ -171,6 +175,16 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
System.arraycopy(aint, 0, this.cookingTime, 0, Math.min(this.cookingTime.length, aint.length)); System.arraycopy(aint, 0, this.cookingTime, 0, Math.min(this.cookingTime.length, aint.length));
} }
@ -51,7 +51,7 @@ index 04b2697ee857e714b1202d02d093b0c60f079a6f..d80855b22dc10dbf697578d5f78664ed
} }
@Override @Override
@@ -176,6 +190,13 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable { @@ -179,6 +193,13 @@ public class CampfireBlockEntity extends BlockEntity implements Clearable {
ContainerHelper.saveAllItems(nbt, this.items, true); ContainerHelper.saveAllItems(nbt, this.items, true);
nbt.putIntArray("CookingTimes", this.cookingProgress); nbt.putIntArray("CookingTimes", this.cookingProgress);
nbt.putIntArray("CookingTotalTimes", this.cookingTime); nbt.putIntArray("CookingTotalTimes", this.cookingTime);

View file

@ -6,6 +6,46 @@ Subject: [PATCH] Fire CauldronLevelChange on initial fill
Also don't fire level events or game events if stalactite Also don't fire level events or game events if stalactite
drip is cancelled drip is cancelled
diff --git a/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java b/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java
index 4c9334dde0734a3550a810845cee53f474e9c96b..ef7f1a871144f4a6897769f2459a4dd5eeffa5b4 100644
--- a/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java
+++ b/src/main/java/net/minecraft/core/cauldron/CauldronInteraction.java
@@ -80,7 +80,7 @@ public interface CauldronInteraction {
} else {
if (!world.isClientSide) {
// CraftBukkit start
- if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, Blocks.WATER_CAULDRON.defaultBlockState(), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY)) {
+ if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, Blocks.WATER_CAULDRON.defaultBlockState(), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY, false)) { // Paper
return InteractionResult.SUCCESS;
}
// CraftBukkit end
@@ -128,7 +128,7 @@ public interface CauldronInteraction {
if ((Integer) iblockdata.getValue(LayeredCauldronBlock.LEVEL) != 3 && PotionUtils.getPotion(itemstack) == Potions.WATER) {
if (!world.isClientSide) {
// CraftBukkit start
- if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, iblockdata.cycle(LayeredCauldronBlock.LEVEL), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY)) {
+ if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, iblockdata.cycle(LayeredCauldronBlock.LEVEL), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY, false)) { // Paper
return InteractionResult.SUCCESS;
}
// CraftBukkit end
@@ -212,7 +212,7 @@ public interface CauldronInteraction {
} else {
if (!world.isClientSide) {
// CraftBukkit start
- if (!LayeredCauldronBlock.changeLevel(state, world, pos, Blocks.CAULDRON.defaultBlockState(), player, CauldronLevelChangeEvent.ChangeReason.BUCKET_FILL)) {
+ if (!LayeredCauldronBlock.changeLevel(state, world, pos, Blocks.CAULDRON.defaultBlockState(), player, CauldronLevelChangeEvent.ChangeReason.BUCKET_FILL, false)) { // Paper
return InteractionResult.SUCCESS;
}
// CraftBukkit end
@@ -233,7 +233,7 @@ public interface CauldronInteraction {
static InteractionResult emptyBucket(Level world, BlockPos pos, Player player, InteractionHand hand, ItemStack stack, BlockState state, SoundEvent soundEvent) {
if (!world.isClientSide) {
// CraftBukkit start
- if (!LayeredCauldronBlock.changeLevel(state, world, pos, state, player, CauldronLevelChangeEvent.ChangeReason.BUCKET_EMPTY)) {
+ if (!LayeredCauldronBlock.changeLevel(state, world, pos, state, player, CauldronLevelChangeEvent.ChangeReason.BUCKET_EMPTY, false)) { // Paper
return InteractionResult.SUCCESS;
}
// CraftBukkit end
diff --git a/src/main/java/net/minecraft/world/level/block/CauldronBlock.java b/src/main/java/net/minecraft/world/level/block/CauldronBlock.java diff --git a/src/main/java/net/minecraft/world/level/block/CauldronBlock.java b/src/main/java/net/minecraft/world/level/block/CauldronBlock.java
index 588b3e911d9b22dad2928ea9e32e8a8a3a8e9b96..a821a981adbebdcf22997731b9bbea3d033cd2b1 100644 index 588b3e911d9b22dad2928ea9e32e8a8a3a8e9b96..a821a981adbebdcf22997731b9bbea3d033cd2b1 100644
--- a/src/main/java/net/minecraft/world/level/block/CauldronBlock.java --- a/src/main/java/net/minecraft/world/level/block/CauldronBlock.java

View file

@ -0,0 +1,73 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Lukas Planz <lukas.planz@web.de>
Date: Tue, 5 Sep 2023 20:34:20 +0200
Subject: [PATCH] Add experience points API
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
index 7f3466340891b4409d1399ebeb2ca865d77841cd..3e597833b57377b855505b8a0f2744801c791f90 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -1833,7 +1833,7 @@ public abstract class Player extends LivingEntity {
}
public int getXpNeededForNextLevel() {
- return this.experienceLevel >= 30 ? 112 + (this.experienceLevel - 30) * 9 : (this.experienceLevel >= 15 ? 37 + (this.experienceLevel - 15) * 5 : 7 + this.experienceLevel * 2);
+ return this.experienceLevel >= 30 ? 112 + (this.experienceLevel - 30) * 9 : (this.experienceLevel >= 15 ? 37 + (this.experienceLevel - 15) * 5 : 7 + this.experienceLevel * 2); // Paper - diff on change
}
// Paper start - send SoundEffect to everyone who can see fromEntity
private static void sendSoundEffect(Player fromEntity, double x, double y, double z, SoundEvent soundEffect, SoundSource soundCategory, float volume, float pitch) {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 4ae4436671b05a3535b9955af60842d4c9d1d102..2ec8b8f65661001716d1cb34dcc21cda7286e5d7 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -1815,6 +1815,49 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
Preconditions.checkArgument(exp >= 0, "Total experience points must not be negative (%s)", exp);
this.getHandle().totalExperience = exp;
}
+ // Paper start
+ @Override
+ public int calculateTotalExperiencePoints() {
+ return calculateTotalExperiencePoints(this.getLevel()) + Math.round(this.getExperiencePointsNeededForNextLevel() * getExp());
+ }
+
+ @Override
+ public void setExperienceLevelAndProgress(final int totalExperience) {
+ Preconditions.checkArgument(totalExperience >= 0, "Total experience points must not be negative (%s)", totalExperience);
+ int level = calculateLevelsForExperiencePoints(totalExperience);
+ int remainingPoints = totalExperience - calculateTotalExperiencePoints(level);
+
+ this.getHandle().experienceLevel = level;
+ this.getHandle().experienceProgress = (float) remainingPoints / this.getExperiencePointsNeededForNextLevel();
+ this.getHandle().lastSentExp = -1;
+ }
+
+ @Override
+ public int getExperiencePointsNeededForNextLevel() {
+ return this.getHandle().getXpNeededForNextLevel();
+ }
+
+ // See https://minecraft.wiki/w/Experience#Leveling_up for reference
+ private int calculateTotalExperiencePoints(int level) {
+ if (level <= 16) {
+ return (int) (Math.pow(level, 2) + 6 * level);
+ } else if (level <= 31) {
+ return (int) (2.5 * Math.pow(level, 2) - 40.5 * level + 360.0);
+ } else {
+ return (int) (4.5 * Math.pow(level, 2) - 162.5 * level + 2220.0);
+ }
+ }
+
+ private int calculateLevelsForExperiencePoints(int points) {
+ if (points <= 352) { // Level 0-16
+ return (int) Math.floor(Math.sqrt(points + 9) - 3);
+ } else if (points <= 1507) { // Level 17-31
+ return (int) Math.floor(8.1 + Math.sqrt(0.4 * (points - (7839.0 / 40.0))));
+ } else { // 32+
+ return (int) Math.floor((325.0 / 18.0) + Math.sqrt((2.0 / 9.0) * (points - (54215.0 / 72.0))));
+ }
+ }
+ // Paper end
@Override
public void sendExperienceChange(float progress) {