Skip to content

Commit 1ae6b73

Browse files
committed
Player Death Loot protect
1 parent 8d8b6dd commit 1ae6b73

File tree

2 files changed

+222
-0
lines changed

2 files changed

+222
-0
lines changed
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2+
From: MidnightTale <[email protected]>
3+
Date: Mon, 21 Jul 2025 06:37:25 +0700
4+
Subject: [PATCH] Player Death Loot and XP Protection Gamerule
5+
6+
7+
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
8+
index 06e41bca6b964ca71ea7bca547b03cdb3610ba31..1e13ff78aee0951f474313f404040c80423e0741 100644
9+
--- a/net/minecraft/server/level/ServerPlayer.java
10+
+++ b/net/minecraft/server/level/ServerPlayer.java
11+
@@ -1249,7 +1249,33 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
12+
if (!keepInventory) {
13+
for (ItemStack item : this.getInventory().getContents()) {
14+
if (!item.isEmpty() && !EnchantmentHelper.has(item, net.minecraft.world.item.enchantment.EnchantmentEffectComponents.PREVENT_EQUIPMENT_DROP)) {
15+
- loot.add(new DefaultDrop(item, stack -> this.drop(stack, true, false, false, null))); // Paper - Restore vanilla drops behavior; drop function taken from Inventory#dropAll (don't fire drop event)
16+
+ loot.add(new DefaultDrop(item, stack -> {
17+
+ ItemEntity entity = this.drop(stack, true, false, false, null);
18+
+ // atDeprecated start - death loot protection
19+
+ if (entity != null) {
20+
+ if (this.level().getGameRules().getBoolean(GameRules.RULE_DEATH_ITEMS_OWNER_PICKUP_ONLY)) {
21+
+ entity.setTarget(this.getUUID());
22+
+ entity.markAsDeathLoot();
23+
+ }
24+
+ if (this.level().getGameRules().getBoolean(GameRules.RULE_DEATH_ITEMS_GLOW)) {
25+
+ entity.setGlowingTag(true);
26+
+ entity.markAsDeathLoot();
27+
+ }
28+
+ if (this.level().getGameRules().getBoolean(GameRules.RULE_DEATH_ITEMS_INVULNERABLE)) {
29+
+ entity.setInvulnerable(true);
30+
+ entity.markAsDeathLoot();
31+
+ }
32+
+ if (this.level().getGameRules().getBoolean(GameRules.RULE_DEATH_ITEMS_NO_DESPAWN)) {
33+
+ entity.setUnlimitedLifetime();
34+
+ entity.markAsDeathLoot();
35+
+ }
36+
+ if (this.level().getGameRules().getBoolean(GameRules.RULE_DEATH_ITEMS_MOB_CANT_PICKUP)) {
37+
+ entity.canMobPickup = false;
38+
+ entity.markAsDeathLoot();
39+
+ }
40+
+ }
41+
+ // atDeprecated end
42+
+ }));
43+
}
44+
}
45+
}
46+
diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java
47+
index b745eb5d9c68547335247910ff2ae8d5fb36349c..861582875a2efe3923fb94768e5f066c64b133ed 100644
48+
--- a/net/minecraft/world/entity/item/ItemEntity.java
49+
+++ b/net/minecraft/world/entity/item/ItemEntity.java
50+
@@ -56,6 +56,7 @@ public class ItemEntity extends Entity implements TraceableEntity {
51+
public boolean canMobPickup = true; // Paper - Item#canEntityPickup
52+
private int despawnRate = -1; // Paper - Alternative item-despawn-rate
53+
public net.kyori.adventure.util.TriState frictionState = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Friction API
54+
+ public boolean isDeathLoot = false; // atDeprecated - mark as player death loot
55+
56+
public ItemEntity(EntityType<? extends ItemEntity> entityType, Level level) {
57+
super(entityType, level);
58+
@@ -149,6 +150,7 @@ public class ItemEntity extends Entity implements TraceableEntity {
59+
// CraftBukkit end
60+
this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
61+
}
62+
+ // atDeprecated end
63+
}
64+
// Paper end - EAR 2
65+
66+
@@ -233,6 +235,11 @@ public class ItemEntity extends Entity implements TraceableEntity {
67+
// CraftBukkit end
68+
this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
69+
}
70+
+ // atDeprecated start - glowing for death loot
71+
+ if (this.isDeathLoot && this.level() instanceof net.minecraft.server.level.ServerLevel serverLevel && serverLevel.getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_DEATH_ITEMS_GLOW)) {
72+
+ this.setGlowingTag(true);
73+
+ }
74+
+ // atDeprecated end
75+
}
76+
}
77+
78+
@@ -342,6 +349,11 @@ public class ItemEntity extends Entity implements TraceableEntity {
79+
80+
@Override
81+
public final boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) {
82+
+ // atDeprecated start - invulnerable death loot
83+
+ if (this.isDeathLoot && level.getGameRules().getBoolean(GameRules.RULE_DEATH_ITEMS_INVULNERABLE)) {
84+
+ return false;
85+
+ }
86+
+ // atDeprecated end
87+
if (this.isInvulnerableToBase(damageSource)) {
88+
return false;
89+
} else if (!level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) && damageSource.getEntity() instanceof Mob) {
90+
@@ -386,6 +398,9 @@ public class ItemEntity extends Entity implements TraceableEntity {
91+
output.putString("Paper.FrictionState", this.frictionState.toString());
92+
}
93+
// Paper end - Friction API
94+
+ // atDeprecated start - persist isDeathLoot
95+
+ output.putBoolean("atDeprecatedIsDeathLoot", this.isDeathLoot);
96+
+ // atDeprecated end
97+
}
98+
99+
@Override
100+
@@ -405,6 +420,9 @@ public class ItemEntity extends Entity implements TraceableEntity {
101+
}
102+
});
103+
// Paper end - Friction API
104+
+ // atDeprecated start - read isDeathLoot
105+
+ this.isDeathLoot = input.getBooleanOr("atDeprecatedIsDeathLoot", false);
106+
+ // atDeprecated end
107+
if (this.getItem().isEmpty()) {
108+
this.discard(null); // CraftBukkit - add Bukkit remove cause
109+
}
110+
@@ -413,6 +431,13 @@ public class ItemEntity extends Entity implements TraceableEntity {
111+
@Override
112+
public void playerTouch(Player entity) {
113+
if (!this.level().isClientSide) {
114+
+ // atDeprecated start - enforce owner-only pickup for death loot
115+
+ if (this.isDeathLoot && this.level() instanceof net.minecraft.server.level.ServerLevel serverLevel && serverLevel.getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_DEATH_ITEMS_OWNER_PICKUP_ONLY)) {
116+
+ if (this.target != null && !this.target.equals(entity.getUUID())) {
117+
+ return;
118+
+ }
119+
+ }
120+
+ // atDeprecated end
121+
ItemStack item = this.getItem();
122+
Item item1 = item.getItem();
123+
int count = item.getCount();
124+
@@ -606,4 +631,8 @@ public class ItemEntity extends Entity implements TraceableEntity {
125+
public SlotAccess getSlot(int slot) {
126+
return slot == 0 ? SlotAccess.of(this::getItem, this::setItem) : super.getSlot(slot);
127+
}
128+
+
129+
+ // atDeprecated start - death loot util
130+
+ public void markAsDeathLoot() { this.isDeathLoot = true; }
131+
+ // atDeprecated end
132+
}
133+
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
134+
index bb9247c44bc57221f6899e88e3136603b53ea9c9..f8e0927db9fd500671b586589cb3ea72dfa226b2 100644
135+
--- a/net/minecraft/world/entity/player/Player.java
136+
+++ b/net/minecraft/world/entity/player/Player.java
137+
@@ -1840,7 +1840,15 @@ public abstract class Player extends LivingEntity {
138+
139+
@Override
140+
protected int getBaseExperienceReward(ServerLevel level) {
141+
- return !level.getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) && !this.isSpectator() ? Math.min(this.experienceLevel * 7, 100) : 0;
142+
+ // atDeprecated start - Use deathXpDropPercentage gamerule for XP drop
143+
+ if (!level.getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) && !this.isSpectator()) {
144+
+ int percent = level.getGameRules().getInt(GameRules.RULE_DEATH_XP_DROP_PERCENTAGE);
145+
+ if (percent < 0) percent = 0;
146+
+ if (percent > 100) percent = 100;
147+
+ return (int) (this.totalExperience * (percent / 100.0));
148+
+ }
149+
+ return 0;
150+
+ // atDeprecated end
151+
}
152+
153+
@Override
154+
diff --git a/net/minecraft/world/level/GameRules.java b/net/minecraft/world/level/GameRules.java
155+
index d5536dd40a1e9a2e05967652f690abbbca287852..a6277c587f9e3bdae3b00d2862dea7f4c06253bd 100644
156+
--- a/net/minecraft/world/level/GameRules.java
157+
+++ b/net/minecraft/world/level/GameRules.java
158+
@@ -240,6 +240,29 @@ public class GameRules {
159+
}
160+
}))
161+
);
162+
+ // atDeprecated start - deathItems gamerules
163+
+ public static final GameRules.Key<GameRules.BooleanValue> RULE_DEATH_ITEMS_GLOW = register(
164+
+ "deathItemsGlow", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true)
165+
+ );
166+
+ public static final GameRules.Key<GameRules.BooleanValue> RULE_DEATH_ITEMS_INVULNERABLE = register(
167+
+ "deathItemsInvulnerable", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true)
168+
+ );
169+
+ public static final GameRules.Key<GameRules.BooleanValue> RULE_DEATH_ITEMS_NO_DESPAWN = register(
170+
+ "deathItemsNoDespawn", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true)
171+
+ );
172+
+ public static final GameRules.Key<GameRules.BooleanValue> RULE_DEATH_ITEMS_OWNER_PICKUP_ONLY = register(
173+
+ "deathItemsOwnerPickupOnly", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true)
174+
+ );
175+
+ public static final GameRules.Key<GameRules.BooleanValue> RULE_DEATH_ITEMS_HOPPER_CANT_PICKUP = register(
176+
+ "deathItemsHopperCantPickup", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true)
177+
+ );
178+
+ public static final GameRules.Key<GameRules.BooleanValue> RULE_DEATH_ITEMS_MOB_CANT_PICKUP = register(
179+
+ "deathItemsMobCantPickup", GameRules.Category.PLAYER, GameRules.BooleanValue.create(true)
180+
+ );
181+
+ public static final GameRules.Key<GameRules.IntegerValue> RULE_DEATH_XP_DROP_PERCENTAGE = register(
182+
+ "deathXpDropPercentage", GameRules.Category.PLAYER, GameRules.IntegerValue.create(70, 0, 100, FeatureFlagSet.of(), (server, value) -> {})
183+
+ );
184+
+ // atDeprecated end
185+
private final Map<GameRules.Key<?>, GameRules.Value<?>> rules;
186+
private final FeatureFlagSet enabledFeatures;
187+
private final GameRules.Value<?>[] gameruleArray; // Paper - Perf: Use array for gamerule storage
188+
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
189+
index 5de769e7bd56bb3355c3c711d46ce5e103ea4409..b3f09cb52767cca16b711663046c452a2082c14a 100644
190+
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
191+
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
192+
@@ -630,6 +630,11 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
193+
}
194+
195+
public static boolean addItem(Container container, ItemEntity item) {
196+
+ // atDeprecated start - prevent hopper pickup of death loot
197+
+ if (item.isDeathLoot && item.level().getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_DEATH_ITEMS_HOPPER_CANT_PICKUP)) {
198+
+ return false;
199+
+ }
200+
+ // atDeprecated end
201+
boolean flag = false;
202+
// CraftBukkit start
203+
if (org.bukkit.event.inventory.InventoryPickupItemEvent.getHandlerList().getRegisteredListeners().length > 0) { // Paper - optimize hoppers
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2+
From: MidnightTale <[email protected]>
3+
Date: Mon, 21 Jul 2025 06:47:18 +0700
4+
Subject: [PATCH] Fix Hopper Gamerule can't pickup deathloot
5+
6+
7+
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
8+
index b3f09cb52767cca16b711663046c452a2082c14a..6b90fe800d9d7a9c0942bcfb505b98b4de227958 100644
9+
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
10+
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
11+
@@ -631,7 +631,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
12+
13+
public static boolean addItem(Container container, ItemEntity item) {
14+
// atDeprecated start - prevent hopper pickup of death loot
15+
- if (item.isDeathLoot && item.level().getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_DEATH_ITEMS_HOPPER_CANT_PICKUP)) {
16+
+ if (item.isDeathLoot && item.level() instanceof net.minecraft.server.level.ServerLevel serverLevel && serverLevel.getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_DEATH_ITEMS_HOPPER_CANT_PICKUP)) {
17+
return false;
18+
}
19+
// atDeprecated end

0 commit comments

Comments
 (0)