Files
Lophine/lophine-server/minecraft-patches/features/0044-Carpet-features.patch
T
Helvetica Volubi 4df4d07ae9 Merge the duplicate configuration items (#151)
* do not release & push repo before finished

* langs update

* updateSuppression config moved up

* redirect tick command option to carpet config system

* optimizedDragonRespawn

* diff in files

* counter rules transformed

* oops!

* some fakeplayer options moved up

* simplify

* creative no clip moved

* pre remove core module

* pre update luminol to further fix a bug that config not saved to real file

* fix up transform

* fix up transform

* fix up

* fix up some problem in PR

* redirect forgotten moved config

* fix bugs in PR

* refix

* switch for final merge
2026-06-15 20:27:41 +08:00

1137 lines
74 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Bacteriawa <A3167717663@hotmail.com>
Date: Sun, 22 Mar 2026 01:39:15 +0800
Subject: [PATCH] Carpet features
diff --git a/io/papermc/paper/threadedregions/RegionizedServer.java b/io/papermc/paper/threadedregions/RegionizedServer.java
index 6e8ee04967afa410ce9dccff34bf9a43201694fd..8b05860d2787a40495f8a025bc0bc43789d6a6af 100644
--- a/io/papermc/paper/threadedregions/RegionizedServer.java
+++ b/io/papermc/paper/threadedregions/RegionizedServer.java
@@ -337,6 +337,7 @@ public final class RegionizedServer {
}
this.randomWalk();
*/
+ final long tickStartNanos = System.nanoTime();
++this.tickCount;
// Luminol start - Add a config to enable tick command
if (me.earthme.luminol.config.modules.experiment.CommandConfig.tick) {
@@ -379,6 +380,8 @@ public final class RegionizedServer {
}
// Lophine end - Add a config to enable tick command
+ fun.bm.lophine.protocol.tiscm.TISCMProtocol.broadcastMsptSample(this.tickCount, System.nanoTime() - tickStartNanos);
+
// tick connections
this.tickConnections();
diff --git a/net/minecraft/commands/arguments/blocks/BlockInput.java b/net/minecraft/commands/arguments/blocks/BlockInput.java
index a4b38651340aff56bb3e3ffd85dea0da538a7532..ed0800548e008142ec94875b0de4c4a8ed3e9d26 100644
--- a/net/minecraft/commands/arguments/blocks/BlockInput.java
+++ b/net/minecraft/commands/arguments/blocks/BlockInput.java
@@ -65,7 +65,9 @@ public class BlockInput implements Predicate<BlockInWorld> {
}
public boolean place(final ServerLevel level, final BlockPos pos, @Block.UpdateFlags final int update) {
- BlockState state = (update & Block.UPDATE_KNOWN_SHAPE) != 0 ? this.state : Block.updateFromNeighbourShapes(this.state, level, pos);
+ BlockState state = (update & Block.UPDATE_KNOWN_SHAPE) != 0 || fun.bm.lophine.carpet.InteractionUpdateCompatHelper.shouldSkipUpdates()
+ ? this.state
+ : Block.updateFromNeighbourShapes(this.state, level, pos);
if (state.isAir()) {
state = this.state;
}
diff --git a/net/minecraft/core/Direction.java b/net/minecraft/core/Direction.java
index 240fb1346b721e4aaf8517b01fa205760cee4bbd..327d6c7e0f18a88f8c9b9cfc9a972266db03842d 100644
--- a/net/minecraft/core/Direction.java
+++ b/net/minecraft/core/Direction.java
@@ -136,7 +136,7 @@ public enum Direction implements StringRepresentable, ca.spottedleaf.moonrise.pa
public static Direction[] orderedByNearest(final Entity entity) {
float pitch = entity.getViewXRot(1.0F) * Mth.DEG_TO_RAD;
- float yaw = -entity.getViewYRot(1.0F) * Mth.DEG_TO_RAD;
+ float yaw = -(fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.placementRotationFix ? entity.getYRot(1.0F) : entity.getViewYRot(1.0F)) * Mth.DEG_TO_RAD;
float pitchSin = Mth.sin(pitch);
float pitchCos = Mth.cos(pitch);
float yawSin = Mth.sin(yaw);
diff --git a/net/minecraft/network/chat/SignedMessageValidator.java b/net/minecraft/network/chat/SignedMessageValidator.java
index 5cb693319169dbd95d87ffdc450bf60bab4021aa..4095c0a6bf24a734945cbf3011271e1a9d0c39f7 100644
--- a/net/minecraft/network/chat/SignedMessageValidator.java
+++ b/net/minecraft/network/chat/SignedMessageValidator.java
@@ -31,7 +31,9 @@ public interface SignedMessageValidator {
private boolean validateChain(final PlayerChatMessage message) {
if (message.equals(this.lastMessage)) {
return true;
- } else if (this.lastMessage != null && !message.link().isDescendantOf(this.lastMessage.link())) {
+ } else if (this.lastMessage != null
+ && !fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.yeetOutOfOrderChatKick
+ && !message.link().isDescendantOf(this.lastMessage.link())) {
LOGGER.error(
"Received out-of-order chat message from {}: expected index > {} for session {}, but was {} for session {}",
message.sender(),
diff --git a/net/minecraft/server/commands/TickCommand.java b/net/minecraft/server/commands/TickCommand.java
index d8f5f1b2f75a4e23556fb016ad47f2cefe1309ce..c065084dd4b308d405b1ece04a727ca834cf89fc 100644
--- a/net/minecraft/server/commands/TickCommand.java
+++ b/net/minecraft/server/commands/TickCommand.java
@@ -20,7 +20,7 @@ public class TickCommand {
public static void register(final CommandDispatcher<CommandSourceStack> dispatcher) {
dispatcher.register(
Commands.literal("tick")
- .requires(Commands.hasPermission(Commands.LEVEL_ADMINS))
+ .requires(Commands.hasPermission(tickCommandPermissionCheck()))
.then(Commands.literal("query").executes(c -> tickQuery(c.getSource())))
.then(
Commands.literal("rate")
@@ -106,8 +106,12 @@ public class TickCommand {
return 1;
}
- private static int setFreeze(final CommandSourceStack source, final boolean freeze) {
+ private static int setFreeze(final CommandSourceStack source, boolean freeze) {
ServerTickRateManager manager = source.getServer().tickRateManager();
+ if (freeze && fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.tickFreezeCommandToggleable && manager.isFrozen()) {
+ freeze = false;
+ }
+
if (freeze) {
if (manager.isSprinting()) {
manager.stopSprinting();
@@ -163,4 +167,8 @@ public class TickCommand {
return 0;
}
}
+
+ private static net.minecraft.server.permissions.PermissionCheck tickCommandPermissionCheck() {
+ return new net.minecraft.server.permissions.PermissionCheck.Require(new net.minecraft.server.permissions.Permission.HasCommandLevel(net.minecraft.server.permissions.PermissionLevel.byId(fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.normalizedTickCommandPermission())));
+ }
}
diff --git a/net/minecraft/server/dedicated/DedicatedPlayerList.java b/net/minecraft/server/dedicated/DedicatedPlayerList.java
index 1a2b57a100c997b39f8f25ad3da121e04700d5d2..be345feecfa5b4e27a7b8a88ab5a5e5b18f23cf0 100644
--- a/net/minecraft/server/dedicated/DedicatedPlayerList.java
+++ b/net/minecraft/server/dedicated/DedicatedPlayerList.java
@@ -14,7 +14,7 @@ public class DedicatedPlayerList extends PlayerList {
public DedicatedPlayerList(final DedicatedServer server, final LayeredRegistryAccess<RegistryLayer> registries, final PlayerDataStorage playerDataStorage) {
super(server, registries, playerDataStorage, server.notificationManager());
- this.setViewDistance(server.viewDistance());
+ this.setViewDistance(Math.max(2, fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.viewDistance));
this.setSimulationDistance(server.simulationDistance());
// Paper start - fix converting txt to json file; moved from constructor
}
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 65965089d184695588c74294afb2f5c0b28bbf17..5ebff729bb7e75e1c84449c0e3021b972ad0d936 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -257,6 +257,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
private int requestedViewDistance = 2;
public String language = null; // Paper - default to null
public java.util.Locale adventure$locale = java.util.Locale.US; // Paper
+ private @Nullable ClientInformation lastKnownClientInformation;
private @Nullable Vec3 startingToFallPosition;
private @Nullable Vec3 enteredNetherPosition;
private @Nullable Vec3 enteredLavaOnVehiclePosition;
@@ -2826,6 +2827,9 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.setShoulderEntityRight(oldPlayer.getShoulderEntityRight());
this.setLastDeathLocation(oldPlayer.getLastDeathLocation());
this.waypointIcon().copyFrom(oldPlayer.waypointIcon());
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.clientSettingsLostOnRespawnFix && oldPlayer.lastKnownClientInformation != null) {
+ this.updateOptions(oldPlayer.lastKnownClientInformation);
+ }
}
private void transferInventoryXpAndScore(final Player oldPlayer) {
@@ -3109,6 +3113,9 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.particleStatus = information.particleStatus();
this.getEntityData().set(DATA_PLAYER_MODE_CUSTOMISATION, (byte)information.modelCustomisation());
this.getEntityData().set(DATA_PLAYER_MAIN_HAND, information.mainHand());
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.clientSettingsLostOnRespawnFix) {
+ this.lastKnownClientInformation = information;
+ }
}
public ClientInformation clientInformation() {
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 96088ba53f043c8bc6971bc62e5dcccd98523698..749ba2e7fa6f7bb9c6e8916a25f04fb63f88aac3 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -2099,7 +2099,13 @@ public class ServerGamePacketListenerImpl
this.player.gameMode.capturedBlockEntity = false;
this.player.gameMode.captureSentBlockEntities = true;
// Paper end - Send block entities after destroy prediction
- this.player.gameMode.handleBlockBreakAction(pos, action, packet.getDirection(), this.player.level().getMaxY(), packet.getSequence());
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.interactionUpdates) {
+ this.player.gameMode.handleBlockBreakAction(pos, action, packet.getDirection(), this.player.level().getMaxY(), packet.getSequence());
+ } else {
+ fun.bm.lophine.carpet.InteractionUpdateCompatHelper.runWithSuppressedUpdates(
+ () -> this.player.gameMode.handleBlockBreakAction(pos, action, packet.getDirection(), this.player.level().getMaxY(), packet.getSequence())
+ );
+ }
this.ackBlockChangesUpTo(packet.getSequence());
// Paper start - Send block entities after destroy prediction
this.player.gameMode.captureSentBlockEntities = false;
@@ -2202,7 +2208,9 @@ public class ServerGamePacketListenerImpl
if (!me.earthme.luminol.config.modules.fixes.ItemMultitaskConfig.enabled) { // Luminol - Add item multitask config
this.player.stopUsingItem(); // CraftBukkit - SPIGOT-4706
} // Luminol - Add item multitask config
- InteractionResult interactionResult = this.player.gameMode.useItemOn(this.player, level, itemStack, hand, blockHit);
+ InteractionResult interactionResult = this.runInteractionWithConfiguredUpdates(
+ () -> this.player.gameMode.useItemOn(this.player, level, itemStack, hand, blockHit)
+ );
if (interactionResult.consumesAction()) {
CriteriaTriggers.ANY_BLOCK_USE.trigger(this.player, blockHit.getBlockPos(), itemStack);
}
@@ -2307,7 +2315,8 @@ public class ServerGamePacketListenerImpl
}
// CraftBukkit end
- if (this.player.gameMode.useItem(this.player, level, itemStack, hand) instanceof InteractionResult.Success success
+ ItemStack itemStackToUse = itemStack;
+ if (this.runInteractionWithConfiguredUpdates(() -> this.player.gameMode.useItem(this.player, level, itemStackToUse, hand)) instanceof InteractionResult.Success success
&& success.swingSource() == InteractionResult.SwingSource.SERVER) {
this.player.swing(hand, true);
}
@@ -2315,6 +2324,14 @@ public class ServerGamePacketListenerImpl
}
}
+ private <T> T runInteractionWithConfiguredUpdates(final java.util.function.Supplier<T> action) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.interactionUpdates) {
+ return action.get();
+ }
+
+ return fun.bm.lophine.carpet.InteractionUpdateCompatHelper.supplyWithSuppressedUpdates(action);
+ }
+
@Override
public void handleTeleportToEntityPacket(final ServerboundTeleportToEntityPacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level());
@@ -2695,6 +2712,8 @@ public class ServerGamePacketListenerImpl
if (true) throw new UnsupportedOperationException(); // Folia - region threading
final String conversationInput = rawMessage;
this.server.processQueue.add(() -> ServerGamePacketListenerImpl.this.getCraftPlayer().acceptConversationInput(conversationInput));
+ } else if (fun.bm.lophine.carpet.CarpetCalculatorCompatHelper.handleChat(this.player, rawMessage)) {
+ return;
} else if (this.player.getChatVisibility() == ChatVisiblity.SYSTEM) { // Re-add "Command Only" flag check
this.send(new ClientboundSystemChatPacket(Component.translatable("chat.cannotSend").withStyle(ChatFormatting.RED), false));
} else {
@@ -2707,6 +2726,9 @@ public class ServerGamePacketListenerImpl
// Spigot start - spam exclusions
private void detectRateSpam(String message) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.antiSpamDisabled) {
+ return;
+ }
if (me.earthme.luminol.config.modules.misc.PaperPacketLimiterConfig.forceDisable) return; // Leaves - disable
// CraftBukkit start - replaced with thread safe throttle
if (org.spigotmc.SpigotConfig.enableSpamExclusions) {
@@ -3642,8 +3664,10 @@ public class ServerGamePacketListenerImpl
if (org.leavesmc.leaves.util.ItemOverstackUtils.hasOverstackingItem()) this.player.containerMenu.sendSingleSlot(packet.slotNum(), itemStack); // Leaves - item over-stack util - force send carried item
if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.updateEquipmentOnPlayerActions) this.player.detectEquipmentUpdates(); // Paper - Force update attributes.
} else if (drop && validData) {
- if (this.dropSpamThrottler.isUnderThreshold()) {
- this.dropSpamThrottler.increment();
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.antiSpamDisabled || this.dropSpamThrottler.isUnderThreshold()) {
+ if (!fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.antiSpamDisabled) {
+ this.dropSpamThrottler.increment();
+ }
this.player.drop(itemStack, true);
} else {
LOGGER.warn("Player {} was dropping items too fast in creative mode, ignoring.", this.player.getPlainTextName());
diff --git a/net/minecraft/world/entity/ExperienceOrb.java b/net/minecraft/world/entity/ExperienceOrb.java
index 2312803297321f66c9057bc54ce56dd17ecb6f1f..5327a5e33147cde1b0b26083c14433d9e6e5b575 100644
--- a/net/minecraft/world/entity/ExperienceOrb.java
+++ b/net/minecraft/world/entity/ExperienceOrb.java
@@ -351,8 +351,23 @@ public class ExperienceOrb extends Entity {
@Override
public void playerTouch(final Player player) {
if (player instanceof ServerPlayer serverPlayer) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.xpNoCooldown) {
+ player.takeXpDelay = 0;
+ }
+
if (player.takeXpDelay == 0 && new com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent(serverPlayer.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) this.getBukkitEntity()).callEvent()) { // Paper - PlayerPickupExperienceEvent
- player.takeXpDelay = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerXpCooldownEvent(player, 2, org.bukkit.event.player.PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entity.takeXpDelay = 2;
+ int newCooldown = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerXpCooldownEvent(player, 2, org.bukkit.event.player.PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entity.takeXpDelay = 2;
+ player.takeXpDelay = fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.xpNoCooldown ? 0 : newCooldown;
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.xpNoCooldown) {
+ while (this.count > 1) {
+ int remaining = this.repairPlayerItems(serverPlayer, this.getValue());
+ if (remaining > 0) {
+ player.giveExperiencePoints(org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerExpChangeEvent(player, this, remaining).getAmount()); // CraftBukkit - remaining -> event.getAmount() // Paper - supply experience orb
+ }
+ this.count--;
+ }
+ }
+
player.take(this, 1);
int remaining = this.repairPlayerItems(serverPlayer, this.getValue());
if (remaining > 0) {
@@ -368,6 +383,10 @@ public class ExperienceOrb extends Entity {
}
private int repairPlayerItems(final ServerPlayer player, final int amount) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.powerfulExpMending) {
+ return this.repairAllPlayerItems(player, amount);
+ }
+
Optional<EnchantedItemInUse> selected = EnchantmentHelper.getRandomItemWith(EnchantmentEffectComponents.REPAIR_WITH_XP, player, ItemStack::isDamaged);
if (selected.isPresent()) {
ItemStack itemStack = selected.get().itemStack();
@@ -397,6 +416,76 @@ public class ExperienceOrb extends Entity {
}
}
+ private int repairAllPlayerItems(ServerPlayer player, int value) {
+ List<MendingCandidate> candidates = new java.util.ArrayList<>();
+ net.minecraft.world.entity.player.Inventory inventory = player.getInventory();
+
+ for (int slotIndex = 0; slotIndex < inventory.getNonEquipmentItems().size(); slotIndex++) {
+ ItemStack stack = inventory.getNonEquipmentItems().get(slotIndex);
+ EquipmentSlot slot = slotIndex == inventory.getSelectedSlot() ? EquipmentSlot.MAINHAND : null;
+ candidates.add(new MendingCandidate(stack, slot));
+ }
+
+ candidates.add(new MendingCandidate(player.getItemBySlot(EquipmentSlot.HEAD), EquipmentSlot.HEAD));
+ candidates.add(new MendingCandidate(player.getItemBySlot(EquipmentSlot.CHEST), EquipmentSlot.CHEST));
+ candidates.add(new MendingCandidate(player.getItemBySlot(EquipmentSlot.LEGS), EquipmentSlot.LEGS));
+ candidates.add(new MendingCandidate(player.getItemBySlot(EquipmentSlot.FEET), EquipmentSlot.FEET));
+ candidates.add(new MendingCandidate(player.getItemBySlot(EquipmentSlot.OFFHAND), EquipmentSlot.OFFHAND));
+
+ java.util.Collections.shuffle(candidates, new java.util.Random(player.getRandom().nextLong()));
+
+ int remaining = value;
+ for (MendingCandidate candidate : candidates) {
+ if (remaining <= 0) {
+ break;
+ }
+
+ ItemStack stack = candidate.stack();
+ if (!this.canRepairWithXp(player, stack)) {
+ continue;
+ }
+
+ int durabilityToRepair = EnchantmentHelper.modifyDurabilityToRepairFromXp(player.level(), stack, remaining);
+ int repairedAmount = Math.min(durabilityToRepair, stack.getDamageValue());
+ if (repairedAmount <= 0) {
+ continue;
+ }
+
+ org.bukkit.event.player.PlayerItemMendEvent event = candidate.slot() != null
+ ? org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemMendEvent(
+ player, this, stack, candidate.slot(), repairedAmount, repairedAmount * remaining / durabilityToRepair
+ )
+ : this.callInventoryItemMendEvent(player, stack, repairedAmount);
+ repairedAmount = event.getRepairAmount();
+ if (event.isCancelled() || repairedAmount <= 0) {
+ continue;
+ }
+
+ stack.setDamageValue(stack.getDamageValue() - repairedAmount);
+ remaining -= repairedAmount * remaining / durabilityToRepair;
+ }
+
+ return remaining;
+ }
+
+ private boolean canRepairWithXp(ServerPlayer player, ItemStack stack) {
+ return !stack.isEmpty() && stack.isDamaged() && EnchantmentHelper.modifyDurabilityToRepairFromXp(player.level(), stack, 1) > 1;
+ }
+
+ private org.bukkit.event.player.PlayerItemMendEvent callInventoryItemMendEvent(ServerPlayer player, ItemStack stack, int repairAmount) {
+ org.bukkit.event.player.PlayerItemMendEvent event = new org.bukkit.event.player.PlayerItemMendEvent(
+ player.getBukkitEntity(),
+ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack),
+ (org.bukkit.entity.ExperienceOrb)this.getBukkitEntity(),
+ repairAmount
+ );
+ player.level().getCraftServer().getPluginManager().callEvent(event);
+ return event;
+ }
+
+ private record MendingCandidate(ItemStack stack, @Nullable EquipmentSlot slot) {
+ }
+
public int getValue() {
return this.entityData.get(DATA_VALUE);
}
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index 167855ad90d0c168a6d49f078ee3409ab84d4bf3..15defe6c740ab7fb3bccc4fb421c0411a4e6a646 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -601,7 +601,8 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
public boolean broadcastedDeath = false; // Folia - region threading
protected void tickDeath() {
this.deathTime++;
- if (this.deathTime >= 20 && !this.level().isClientSide() && !this.isRemoved()) {
+ int removalDelay = fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.entityInstantDeathRemoval ? 1 : 20;
+ if (this.deathTime >= removalDelay && !this.level().isClientSide() && !this.isRemoved()) {
this.level().broadcastEntityEvent(this, EntityEvent.POOF); this.broadcastedDeath = true; // Folia - region threading - death has been broadcasted
if (!(this instanceof ServerPlayer)) this.remove(Entity.RemovalReason.KILLED, org.bukkit.event.entity.EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause // Folia - region threading - don't remove, we want the tick scheduler to be running
if ((this instanceof ServerPlayer)) this.unRide(); // Folia - region threading - unmount player when dead
diff --git a/net/minecraft/world/entity/item/PrimedTnt.java b/net/minecraft/world/entity/item/PrimedTnt.java
index 42aff39d537aa6b138bc4a76304d49f423212acd..475e5abeeb29fce0f8ae0abc127f2023300ca186 100644
--- a/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/net/minecraft/world/entity/item/PrimedTnt.java
@@ -70,8 +70,12 @@ public class PrimedTnt extends Entity implements TraceableEntity {
this(EntityType.TNT, level);
this.setPos(x, y, z);
double rot = this.getRandom().nextDouble() * (float) (Math.PI * 2); // Paper - Don't use level random in entity constructors
- this.setDeltaMovement(-Math.sin(rot) * 0.02, 0.2F, -Math.cos(rot) * 0.02);
- this.setFuse(80);
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.tntPrimerMomentumRemoved) {
+ this.setDeltaMovement(0.0, 0.20000000298023224, 0.0);
+ } else {
+ this.setDeltaMovement(-Math.sin(rot) * 0.02, 0.2F, -Math.cos(rot) * 0.02);
+ }
+ this.setFuse(getConfiguredFuseTime());
this.xo = x;
this.yo = y;
this.zo = z;
@@ -80,7 +84,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
@Override
protected void defineSynchedData(final SynchedEntityData.Builder entityData) {
- entityData.define(DATA_FUSE_ID, 80);
+ entityData.define(DATA_FUSE_ID, getConfiguredFuseTime());
entityData.define(DATA_BLOCK_STATE_ID, DEFAULT_BLOCK_STATE);
}
@@ -177,7 +181,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
@Override
protected void readAdditionalSaveData(final ValueInput input) {
- this.setFuse(input.getShortOr("fuse", (short)80));
+ this.setFuse(input.getShortOr("fuse", (short)getConfiguredFuseTime()));
this.setBlockState(input.read("block_state", BlockState.CODEC).orElse(DEFAULT_BLOCK_STATE));
this.explosionPower = Mth.clamp(input.getFloatOr("explosion_power", 4.0F), 0.0F, 128.0F);
this.owner = EntityReference.read(input, "owner");
@@ -200,6 +204,10 @@ public class PrimedTnt extends Entity implements TraceableEntity {
this.entityData.set(DATA_FUSE_ID, time);
}
+ private static int getConfiguredFuseTime() {
+ return fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.normalizedTntFuseDuration();
+ }
+
public int getFuse() {
return this.entityData.get(DATA_FUSE_ID);
}
diff --git a/net/minecraft/world/entity/monster/EnderMan.java b/net/minecraft/world/entity/monster/EnderMan.java
index 459a05ca83583538f995f45c4d2c977c6d6fcd00..474004edeae737873db88b3cce79408e10cccbf4 100644
--- a/net/minecraft/world/entity/monster/EnderMan.java
+++ b/net/minecraft/world/entity/monster/EnderMan.java
@@ -643,7 +643,7 @@ public class EnderMan extends Monster implements NeutralMob {
Vec3 to = new Vec3(xt + 0.5, yt + 0.5, zt + 0.5);
BlockHitResult result = level.clip(new ClipContext(from, to, ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, this.enderman));
boolean reachable = result.getBlockPos().equals(pos);
- if (blockState.is(BlockTags.ENDERMAN_HOLDABLE) && reachable) {
+ if (canPickupBlock(blockState) && reachable) {
if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.enderman, pos, blockState.getFluidState().createLegacyBlock())) { // Paper - Place event
level.removeBlock(pos, false);
level.gameEvent(GameEvent.BLOCK_DESTROY, pos, GameEvent.Context.of(this.enderman, blockState));
@@ -651,5 +651,13 @@ public class EnderMan extends Monster implements NeutralMob {
} // CraftBukkit
}
}
+
+ private static boolean canPickupBlock(BlockState state) {
+ if (!fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.sensibleEnderman) {
+ return state.is(BlockTags.ENDERMAN_HOLDABLE);
+ }
+
+ return state.is(Blocks.MELON) || state.is(Blocks.PUMPKIN);
+ }
}
}
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index ea5de9aca4908ed972c4f44bff635f2cc423a04f..04707a48b1ad9f0c580213e5837e93ad849d1b47 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -555,7 +555,13 @@ public abstract class Player extends Avatar implements ContainerUser {
}
if (!orbs.isEmpty()) {
- this.touch(Util.getRandom(orbs, this.random));
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.xpNoCooldown) {
+ for (Entity orb : orbs) {
+ this.touch(orb);
+ }
+ } else {
+ this.touch(Util.getRandom(orbs, this.random));
+ }
}
}
@@ -1066,6 +1072,26 @@ public abstract class Player extends Avatar implements ContainerUser {
if (playerAttackEntityEvent.callEvent() && willAttack) { // Logic moved to willAttack local variable.
// Paper end - PlayerAttackEntityEvent
+ if (this.level() instanceof ServerLevel serverLevel
+ && fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.creativeOneHitKill
+ && this.isCreative()
+ && net.minecraft.world.entity.EntitySelector.NO_CREATIVE_OR_SPECTATOR.test(entity)) {
+ if (this.isShiftKeyDown()) {
+ for (Entity nearbyEntity : this.level().getEntities(
+ this,
+ entity.getBoundingBox().inflate(2.0, 0.5, 2.0),
+ candidate -> candidate.isAttackable() && net.minecraft.world.entity.EntitySelector.NO_CREATIVE_OR_SPECTATOR.test(candidate)
+ )) {
+ this.creativeInstantKill(serverLevel, nearbyEntity);
+ }
+ this.playServerSideSound(SoundEvents.PLAYER_ATTACK_SWEEP);
+ } else {
+ this.creativeInstantKill(serverLevel, entity);
+ this.playServerSideSound(SoundEvents.PLAYER_ATTACK_CRIT);
+ }
+ return;
+ }
+
float baseDamage = this.isAutoSpinAttack() ? this.autoSpinAttackDmg : (float)this.getAttributeValue(Attributes.ATTACK_DAMAGE);
ItemStack attackingItemStack = this.getWeaponItem();
DamageSource damageSource = this.createAttackSource(attackingItemStack); final DamageSource dmgSourceFinal = damageSource; // Paper - damage events
@@ -1123,6 +1149,16 @@ public abstract class Player extends Avatar implements ContainerUser {
}
}
+ private void creativeInstantKill(final ServerLevel level, final Entity target) {
+ if (target instanceof EnderDragonPart enderDragonPart) {
+ java.util.Arrays.stream(enderDragonPart.parentMob.getSubEntities()).forEach(part -> part.kill(level));
+ enderDragonPart.parentMob.kill(level);
+ return;
+ }
+
+ target.kill(level);
+ }
+
private void playServerSideSound(final SoundEvent sound) {
sendSoundEffect(this, this.getX(), this.getY(), this.getZ(), sound, this.getSoundSource(), 1.0F, 1.0F); // Paper - send while respecting visibility
}
diff --git a/net/minecraft/world/item/BlockItem.java b/net/minecraft/world/item/BlockItem.java
index 9c016e7d93e4c44ddf2df520e5c57d92a0e085b3..3413fe84a40b00e98565cdf7aa93fc1c7da6f128 100644
--- a/net/minecraft/world/item/BlockItem.java
+++ b/net/minecraft/world/item/BlockItem.java
@@ -147,8 +147,12 @@ public class BlockItem extends Item {
// CraftBukkit start
Level world = context.getLevel(); // Paper - Cancel hit for vanished players
CollisionContext collisionContext = player == null ? CollisionContext.empty() : CollisionContext.placementContext(player); // Leaves - creative no clip
+ boolean ignoreEntityCollision = fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.blockPlacementIgnoreEntity && player != null && player.isCreative();
boolean canBuild = (!this.mustSurvive() || stateForPlacement.canSurvive(world, context.getClickedPos()))
- && ((fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.creativeNoClip && context.getPlayer() != null) ? context.getPlayer().canSpectatingPlace(world, stateForPlacement, context.getClickedPos(), collisionContext) : world.checkEntityCollision(stateForPlacement, player, collisionContext, context.getClickedPos(), true)); // Paper - Cancel hit for vanished players // Leaves - creative no clip
+ && (ignoreEntityCollision
+ || ((fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.creativeNoClip && context.getPlayer() != null)
+ ? context.getPlayer().canSpectatingPlace(world, stateForPlacement, context.getClickedPos(), collisionContext)
+ : world.checkEntityCollision(stateForPlacement, player, collisionContext, context.getClickedPos(), true))); // Paper - Cancel hit for vanished players // Leaves - creative no clip
org.bukkit.entity.Player bukkitPlayer = (context.getPlayer() instanceof ServerPlayer) ? (org.bukkit.entity.Player) context.getPlayer().getBukkitEntity() : null;
org.bukkit.event.block.BlockCanBuildEvent event = new org.bukkit.event.block.BlockCanBuildEvent(
diff --git a/net/minecraft/world/item/ServerItemCooldowns.java b/net/minecraft/world/item/ServerItemCooldowns.java
index cf66ce7cf737b2abd45c76218db55c8d0fc109d4..4da0768c14918d13b7137daa74142a544cf857cb 100644
--- a/net/minecraft/world/item/ServerItemCooldowns.java
+++ b/net/minecraft/world/item/ServerItemCooldowns.java
@@ -22,6 +22,9 @@ public class ServerItemCooldowns extends ItemCooldowns {
@Override
public void addCooldown(ItemStack item, int duration) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.creativeNoItemCooldown && this.player.isCreative()) {
+ return;
+ }
final Identifier cooldownGroup = this.getCooldownGroup(item);
final io.papermc.paper.event.player.PlayerItemCooldownEvent event = new io.papermc.paper.event.player.PlayerItemCooldownEvent(
this.player.getBukkitEntity(),
diff --git a/net/minecraft/world/item/crafting/RecipeManager.java b/net/minecraft/world/item/crafting/RecipeManager.java
index 298908003d5422b8b58de631145fad381e8294c1..becd64cb00dddda42a9494f6ab36362466e5f18a 100644
--- a/net/minecraft/world/item/crafting/RecipeManager.java
+++ b/net/minecraft/world/item/crafting/RecipeManager.java
@@ -55,6 +55,9 @@ public class RecipeManager extends SimplePreparableReloadListener<RecipeMap> imp
forSingleInput(RecipeType.CAMPFIRE_COOKING)
);
private static final FileToIdConverter RECIPE_LISTER = FileToIdConverter.registry(Registries.RECIPE);
+ private static final ResourceKey<Recipe<?>> BETTER_CRAFTABLE_BONE_BLOCK_RECIPE = compatRecipeKey("better_craftable_bone_block");
+ private static final ResourceKey<Recipe<?>> BETTER_CRAFTABLE_DISPENSER_SHAPED_RECIPE = compatRecipeKey("better_craftable_dispenser_shaped");
+ private static final ResourceKey<Recipe<?>> BETTER_CRAFTABLE_DISPENSER_SHAPELESS_RECIPE = compatRecipeKey("better_craftable_dispenser_shapeless");
private final HolderLookup.Provider registries;
public RecipeMap recipes = RecipeMap.EMPTY;
private Map<ResourceKey<RecipePropertySet>, RecipePropertySet> propertySets = Map.of();
@@ -83,10 +86,73 @@ public class RecipeManager extends SimplePreparableReloadListener<RecipeMap> imp
@Override
protected void apply(final RecipeMap recipes, final ResourceManager manager, final ProfilerFiller profiler) {
+ this.injectCompatRecipes(recipes);
this.recipes = recipes;
LOGGER.info("Loaded {} recipes", recipes.values().size());
}
+ private void injectCompatRecipes(final RecipeMap recipeMap) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.betterCraftableBoneBlock) {
+ addCompatRecipe(recipeMap, createBetterCraftableBoneBlockRecipe());
+ }
+
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.betterCraftableDispenser) {
+ addCompatRecipe(recipeMap, createBetterCraftableDispenserShapedRecipe());
+ addCompatRecipe(recipeMap, createBetterCraftableDispenserShapelessRecipe());
+ }
+ }
+
+ private static void addCompatRecipe(final RecipeMap recipeMap, final RecipeHolder<?> recipeHolder) {
+ if (recipeMap.byKey(recipeHolder.id()) == null) {
+ recipeMap.addRecipe(recipeHolder);
+ }
+ }
+
+ private static RecipeHolder<?> createBetterCraftableBoneBlockRecipe() {
+ return new RecipeHolder<>(
+ BETTER_CRAFTABLE_BONE_BLOCK_RECIPE,
+ new ShapedRecipe(
+ new Recipe.CommonInfo(true),
+ new CraftingRecipe.CraftingBookInfo(CraftingBookCategory.BUILDING, "carpet_ams_better_bone_block"),
+ ShapedRecipePattern.of(Map.of('#', Ingredient.of(net.minecraft.world.item.Items.BONE)), "###", "###", "###"),
+ new net.minecraft.world.item.ItemStackTemplate(net.minecraft.world.item.Items.BONE_BLOCK, 3)
+ )
+ );
+ }
+
+ private static RecipeHolder<?> createBetterCraftableDispenserShapedRecipe() {
+ return new RecipeHolder<>(
+ BETTER_CRAFTABLE_DISPENSER_SHAPED_RECIPE,
+ new ShapedRecipe(
+ new Recipe.CommonInfo(true),
+ new CraftingRecipe.CraftingBookInfo(CraftingBookCategory.REDSTONE, "carpet_ams_better_dispenser"),
+ ShapedRecipePattern.of(
+ Map.of('S', Ingredient.of(net.minecraft.world.item.Items.STICK), 'D', Ingredient.of(net.minecraft.world.item.Items.DROPPER), 'X', Ingredient.of(net.minecraft.world.item.Items.STRING)),
+ " SX",
+ "SDX",
+ " SX"
+ ),
+ new net.minecraft.world.item.ItemStackTemplate(net.minecraft.world.item.Items.DISPENSER)
+ )
+ );
+ }
+
+ private static RecipeHolder<?> createBetterCraftableDispenserShapelessRecipe() {
+ return new RecipeHolder<>(
+ BETTER_CRAFTABLE_DISPENSER_SHAPELESS_RECIPE,
+ new ShapelessRecipe(
+ new Recipe.CommonInfo(true),
+ new CraftingRecipe.CraftingBookInfo(CraftingBookCategory.REDSTONE, "carpet_ams_better_dispenser"),
+ new net.minecraft.world.item.ItemStackTemplate(net.minecraft.world.item.Items.DISPENSER),
+ List.of(Ingredient.of(net.minecraft.world.item.Items.BOW), Ingredient.of(net.minecraft.world.item.Items.DROPPER))
+ )
+ );
+ }
+
+ private static ResourceKey<Recipe<?>> compatRecipeKey(final String path) {
+ return ResourceKey.create(Registries.RECIPE, Identifier.fromNamespaceAndPath("lophine", path));
+ }
+
// CraftBukkit start
public void addRecipe(RecipeHolder<?> holder) {
org.spigotmc.AsyncCatcher.catchOp("Recipe Add"); // Spigot
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index e06e48dd9c997ac1dc6e404aa0bc590c851e1ba8..aba2f23951a79d32238dcf948a9232d43726a43d 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -1176,6 +1176,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
BlockState state = newState;
BlockState blockState = oldState;
BlockState blockState1 = currentState;
+ boolean skipInteractionUpdates = fun.bm.lophine.carpet.InteractionUpdateCompatHelper.shouldSkipUpdates();
+ if (skipInteractionUpdates) {
+ flags &= ~Block.UPDATE_NEIGHBORS;
+ }
if (blockState1 == state) {
if (blockState != blockState1) {
this.setBlocksDirty(pos, blockState, blockState1);
@@ -1192,7 +1196,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
}
}
- if ((flags & Block.UPDATE_KNOWN_SHAPE) == 0 && recursionLeft > 0) {
+ if (!skipInteractionUpdates && (flags & Block.UPDATE_KNOWN_SHAPE) == 0 && recursionLeft > 0) {
int i = flags & ~(Block.UPDATE_SUPPRESS_DROPS | Block.UPDATE_NEIGHBORS);
// CraftBukkit start
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
index cd20d10ee4cd2fe98131c9a93367ae133f96b8d4..b9443bd4a7ee46fa9faea9f7db6352e4c6a6bd0f 100644
--- a/net/minecraft/world/level/NaturalSpawner.java
+++ b/net/minecraft/world/level/NaturalSpawner.java
@@ -292,6 +292,10 @@ public final class NaturalSpawner {
Player nearestPlayer = level.getNearestPlayer(xx, yStart, zz, -1.0, false);
if (nearestPlayer != null) {
double nearestPlayerDistanceSqr = nearestPlayer.distanceToSqr(xx, yStart, zz);
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.lagFreeSpawning) {
+ nearestPlayerDistanceSqr = fun.bm.lophine.carpet.LagFreeSpawningCompatHelper.limitDistanceSq(mobCategory, nearestPlayerDistanceSqr);
+ }
+
if (level.isLoadedAndInBounds(pos) && isRightDistanceToPlayerAndSpawnPoint(level, chunk, pos, nearestPlayerDistanceSqr)) { // Paper - don't load chunks for mob spawn
if (currentSpawnData == null) {
Optional<MobSpawnSettings.SpawnerData> nextSpawnData = getRandomSpawnMobAt(
@@ -332,6 +336,10 @@ public final class NaturalSpawner {
// SPIGOT-7045: Give ocelot babies back their special spawn reason. Note: This is the only modification required as ocelots count as monsters which means they only spawn during normal chunk ticking and do not spawn during chunk generation as starter mobs.
level.addFreshEntityWithPassengers(mob, (mob instanceof net.minecraft.world.entity.animal.feline.Ocelot && !((org.bukkit.entity.Ageable) mob.getBukkitEntity()).isAdult()) ? org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.OCELOT_BABY : org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL);
if (!mob.isRemoved()) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.lagFreeSpawning) {
+ fun.bm.lophine.carpet.LagFreeSpawningCompatHelper.markSpawned(level, mob.getType());
+ }
+
clusterSize++;
groupSize++;
spawnCallback.run(mob, chunk);
@@ -411,11 +419,20 @@ public final class NaturalSpawner {
&& canSpawnMobAt(level, structureManager, generator, mobCategory, currentSpawnData, pos)
&& SpawnPlacements.isSpawnPositionOk(type, level, pos)
&& SpawnPlacements.checkSpawnRules(type, level, EntitySpawnReason.NATURAL, pos, level.random)
- && level.noCollision(type.getSpawnAABB(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5));
+ && (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.lagFreeSpawning
+ ? fun.bm.lophine.carpet.LagFreeSpawningCompatHelper.hasNoCollision(level, type.getSpawnAABB(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5))
+ : level.noCollision(type.getSpawnAABB(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5)));
return success ? PreSpawnStatus.SUCCESS : PreSpawnStatus.FAIL; // Paper - PreCreatureSpawnEvent
}
private static @Nullable Mob getMobForSpawn(final ServerLevel level, final EntityType<?> type) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.lagFreeSpawning) {
+ Mob cachedMob = fun.bm.lophine.carpet.LagFreeSpawningCompatHelper.getOrCreateMob(level, type);
+ if (cachedMob != null) {
+ return cachedMob;
+ }
+ }
+
try {
if (type.create(level, EntitySpawnReason.NATURAL) instanceof Mob mob) {
return mob;
@@ -536,7 +553,9 @@ public final class NaturalSpawner {
float width = spawnerData.type().getWidth();
double fx = Mth.clamp((double)x, (double)xo + width, xo + 16.0 - width);
double fz = Mth.clamp((double)z, (double)zo + width, zo + 16.0 - width);
- if (!level.noCollision(spawnerData.type().getSpawnAABB(fx, pos.getY(), fz))
+ if (!(fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.lagFreeSpawning
+ ? fun.bm.lophine.carpet.LagFreeSpawningCompatHelper.hasNoCollision(level.getLevel(), spawnerData.type().getSpawnAABB(fx, pos.getY(), fz))
+ : level.noCollision(spawnerData.type().getSpawnAABB(fx, pos.getY(), fz)))
|| !SpawnPlacements.checkSpawnRules(
spawnerData.type(),
level,
@@ -568,6 +587,9 @@ public final class NaturalSpawner {
level, level.getCurrentDifficultyAt(mob.blockPosition()), EntitySpawnReason.CHUNK_GENERATION, groupSpawnData
);
level.addFreshEntityWithPassengers(mob, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN); // CraftBukkit
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.lagFreeSpawning) {
+ fun.bm.lophine.carpet.LagFreeSpawningCompatHelper.markSpawned(level.getLevel(), mob.getType());
+ }
success = true;
}
}
diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java
index 9fc97e8b01f66ada6af1fe76f4e27c9bb1a5dcfc..3d5bb6a0893db1cac5cff61e4a3607de9536c9a3 100644
--- a/net/minecraft/world/level/ServerExplosion.java
+++ b/net/minecraft/world/level/ServerExplosion.java
@@ -371,6 +371,10 @@ public class ServerExplosion implements Explosion {
}
private List<BlockPos> calculateExplodedPositions() {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.explosionNoBlockDamage) {
+ return List.of();
+ }
+
// Paper start - collision optimisations
final ObjectArrayList<BlockPos> ret = new ObjectArrayList<>();
diff --git a/net/minecraft/world/level/block/CarvedPumpkinBlock.java b/net/minecraft/world/level/block/CarvedPumpkinBlock.java
index a63dddd01ced6ba23067a113d871f2351bb690fc..6f67b18005ad9b877d7f680ff9b4afc7abed62d1 100644
--- a/net/minecraft/world/level/block/CarvedPumpkinBlock.java
+++ b/net/minecraft/world/level/block/CarvedPumpkinBlock.java
@@ -59,7 +59,8 @@ public class CarvedPumpkinBlock extends HorizontalDirectionalBlock {
public boolean canSpawnGolem(final LevelReader level, final BlockPos topPos) {
return this.getOrCreateSnowGolemBase().find(level, topPos) != null
|| this.getOrCreateIronGolemBase().find(level, topPos) != null
- || this.getOrCreateCopperGolemBase().find(level, topPos) != null;
+ || this.getOrCreateCopperGolemBase().find(level, topPos) != null
+ || this.canSpawnShulkerGolem(level, topPos);
}
private void trySpawnGolem(final Level level, final BlockPos topPos) {
@@ -92,6 +93,8 @@ public class CarvedPumpkinBlock extends HorizontalDirectionalBlock {
copperGolem.spawn(this.getWeatherStateFromPattern(copperGolemMatch));
}
}
+
+ this.trySpawnShulkerGolem(level, topPos);
}
private WeatheringCopper.WeatherState getWeatherStateFromPattern(final BlockPattern.BlockPatternMatch copperGolemMatch) {
@@ -159,6 +162,42 @@ public class CarvedPumpkinBlock extends HorizontalDirectionalBlock {
builder.add(FACING);
}
+ private boolean canSpawnShulkerGolem(LevelReader level, BlockPos pos) {
+ return fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.shulkerGolem
+ && PUMPKINS_PREDICATE.test(level.getBlockState(pos))
+ && level.getBlockState(pos.below()).is(BlockTags.SHULKER_BOXES);
+ }
+
+ private void trySpawnShulkerGolem(Level level, BlockPos pos) {
+ if (!this.canSpawnShulkerGolem(level, pos)) {
+ return;
+ }
+
+ net.minecraft.world.entity.monster.Shulker shulker = EntityType.SHULKER.create(level, EntitySpawnReason.TRIGGERED);
+ if (shulker == null) {
+ return;
+ }
+
+ BlockPos bodyPos = pos.below();
+ BlockState headState = level.getBlockState(pos);
+ BlockState bodyState = level.getBlockState(bodyPos);
+ shulker.snapTo(bodyPos.getX() + 0.5, bodyPos.getY(), bodyPos.getZ() + 0.5, 0.0F, 0.0F);
+ if (!level.addFreshEntity(shulker, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BUILD_IRONGOLEM)) {
+ return;
+ }
+
+ level.setBlock(pos, Blocks.AIR.defaultBlockState(), Block.UPDATE_CLIENTS);
+ level.setBlock(bodyPos, Blocks.AIR.defaultBlockState(), Block.UPDATE_CLIENTS);
+ level.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, pos, Block.getId(headState));
+ level.levelEvent(LevelEvent.PARTICLES_DESTROY_BLOCK, bodyPos, Block.getId(bodyState));
+ level.updateNeighborsAt(pos, Blocks.AIR);
+ level.updateNeighborsAt(bodyPos, Blocks.AIR);
+
+ for (ServerPlayer serverPlayer : level.getEntitiesOfClass(ServerPlayer.class, shulker.getBoundingBox().inflate(5.0))) {
+ CriteriaTriggers.SUMMONED_ENTITY.trigger(serverPlayer, shulker);
+ }
+ }
+
private BlockPattern getOrCreateSnowGolemBase() {
if (this.snowGolemBase == null) {
this.snowGolemBase = BlockPatternBuilder.start()
diff --git a/net/minecraft/world/level/block/ChestBlock.java b/net/minecraft/world/level/block/ChestBlock.java
index b5595d87339e4d313c5691a06c2b1b3d1b40b6de..cceb2e8170bf56c6d34520e69968ea6568a5878e 100644
--- a/net/minecraft/world/level/block/ChestBlock.java
+++ b/net/minecraft/world/level/block/ChestBlock.java
@@ -276,7 +276,8 @@ public class ChestBlock extends AbstractChestBlock<ChestBlockEntity> implements
final BlockState state, final Level level, final BlockPos pos, final Player player, final BlockHitResult hitResult
) {
if (level instanceof ServerLevel serverLevel) {
- MenuProvider menuProvider = this.getMenuProvider(state, level, pos);
+ boolean ignoreObstructions = fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.creativeOpenContainerForcibly && player.isCreative();
+ MenuProvider menuProvider = this.getMenuProvider(state, level, pos, ignoreObstructions);
if (menuProvider != null && player.openMenu(menuProvider).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation
player.awardStat(this.getOpenChestStat());
PiglinAi.angerNearbyPiglins(serverLevel, player, true);
diff --git a/net/minecraft/world/level/block/EnderChestBlock.java b/net/minecraft/world/level/block/EnderChestBlock.java
index a9f511a549681a76a962855c26b9af5980f36df7..26a5330b53f3381896e64c0b65147d69f6369773 100644
--- a/net/minecraft/world/level/block/EnderChestBlock.java
+++ b/net/minecraft/world/level/block/EnderChestBlock.java
@@ -82,7 +82,8 @@ public class EnderChestBlock extends AbstractChestBlock<EnderChestBlockEntity> i
PlayerEnderChestContainer container = player.getEnderChestInventory();
if (container != null && level.getBlockEntity(pos) instanceof EnderChestBlockEntity enderChest) {
BlockPos above = pos.above();
- if (level.getBlockState(above).isRedstoneConductor(level, above)) { // Paper - diff on change; make sure that EnderChest#isBlocked uses the same logic
+ boolean canOpenForcibly = fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.creativeOpenContainerForcibly && player.isCreative();
+ if (!canOpenForcibly && level.getBlockState(above).isRedstoneConductor(level, above)) { // Paper - diff on change; make sure that EnderChest#isBlocked uses the same logic
return InteractionResult.SUCCESS;
} else {
// Paper start - Fix InventoryOpenEvent cancellation - moved up;
diff --git a/net/minecraft/world/level/block/FarmlandBlock.java b/net/minecraft/world/level/block/FarmlandBlock.java
index ef55faf83e39c8dfd6bbe33c4943ed88bc473715..3d083f390f4dffc43e1a7f09fad87b05f296e6b8 100644
--- a/net/minecraft/world/level/block/FarmlandBlock.java
+++ b/net/minecraft/world/level/block/FarmlandBlock.java
@@ -132,7 +132,9 @@ public class FarmlandBlock extends Block {
return;
}
// CraftBukkit end
- turnToDirt(entity, state, level, pos);
+ if (!fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.farmlandTrampledDisabled) {
+ turnToDirt(entity, state, level, pos);
+ }
}
// super.fallOn(level, state, pos, entity, fallDistance); // CraftBukkit - moved up
diff --git a/net/minecraft/world/level/block/ObserverBlock.java b/net/minecraft/world/level/block/ObserverBlock.java
index be572eff561ffdd961a9602eaa6136761c4d48a4..f11f0669bfbd5bb037cd17298563694316597772 100644
--- a/net/minecraft/world/level/block/ObserverBlock.java
+++ b/net/minecraft/world/level/block/ObserverBlock.java
@@ -89,6 +89,10 @@ public class ObserverBlock extends DirectionalBlock {
}
private void startSignal(final LevelReader level, final ScheduledTickAccess ticks, final BlockPos pos) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.observerNoDetection) {
+ return;
+ }
+
if (!level.isClientSide() && !ticks.getBlockTicks().hasScheduledTick(pos, this)) {
ticks.scheduleTick(pos, this, 2);
}
diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java
index ed190e16df7c6b80fd90561e7c2fdd53c745e54a..0fcba821dc2500b7f88e87bca315ad504ebd8a62 100644
--- a/net/minecraft/world/level/block/RedStoneWireBlock.java
+++ b/net/minecraft/world/level/block/RedStoneWireBlock.java
@@ -288,7 +288,8 @@ public class RedStoneWireBlock extends Block {
* Note: Added 'source' argument so as to help determine direction of information flow
*/
private void updateSurroundingRedstone(Level worldIn, BlockPos pos, BlockState state, @Nullable Orientation orientation, boolean blockAdded) {
- if (worldIn.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.EIGENCRAFT) {
+ if (!fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.fastRedstoneDust
+ && worldIn.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.EIGENCRAFT) {
// since 24w33a the source pos is no longer given, but instead an Orientation parameter
// when this is not null, it can be used to find the source pos, which the turbo uses
// to find the direction of information flow
@@ -363,7 +364,8 @@ public class RedStoneWireBlock extends Block {
protected void onPlace(final BlockState state, final Level level, final BlockPos pos, final BlockState oldState, final boolean movedByPiston) {
if (!oldState.is(state.getBlock()) && !level.isClientSide()) {
// Paper start - optimize redstone - replace call to updatePowerStrength
- if (level.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.fastRedstoneDust
+ || level.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
level.getWireHandler().onWireAdded(pos, state); // Alternate Current
} else {
this.updateSurroundingRedstone(level, pos, state, null, true); // Vanilla/Eigencraft
@@ -388,7 +390,8 @@ public class RedStoneWireBlock extends Block {
}
// Paper start - optimize redstone - replace call to updatePowerStrength
- if (level.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.fastRedstoneDust
+ || level.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
level.getWireHandler().onWireRemoved(pos, state); // Alternate Current
} else {
this.updateSurroundingRedstone(level, pos, state, null, false); // Vanilla/Eigencraft
@@ -408,7 +411,8 @@ public class RedStoneWireBlock extends Block {
}
// Paper start - optimize redstone - replace call to updatePowerStrength
- if (level.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.fastRedstoneDust
+ || level.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
level.getWireHandler().onWireRemoved(pos, state); // Alternate Current
} else {
this.updateSurroundingRedstone(level, pos, state, null, false); // Vanilla/Eigencraft
@@ -440,7 +444,8 @@ public class RedStoneWireBlock extends Block {
if (!level.isClientSide()) {
// Paper start - optimize redstone (Alternate Current)
// Alternate Current handles breaking of redstone wires in the WireHandler.
- if (level.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.fastRedstoneDust
+ || level.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
level.getWireHandler().onWireUpdated(pos, state, orientation);
} else
// Paper end - optimize redstone (Alternate Current)
diff --git a/net/minecraft/world/level/block/ShulkerBoxBlock.java b/net/minecraft/world/level/block/ShulkerBoxBlock.java
index 59ad645785bc99758f4bc124c56e39d87c4b75c2..13176ae2b2feb8d78b24f6c40901b030accb09be 100644
--- a/net/minecraft/world/level/block/ShulkerBoxBlock.java
+++ b/net/minecraft/world/level/block/ShulkerBoxBlock.java
@@ -74,9 +74,10 @@ public class ShulkerBoxBlock extends BaseEntityBlock {
protected InteractionResult useWithoutItem(
final BlockState state, final Level level, final BlockPos pos, final Player player, final BlockHitResult hitResult
) {
+ boolean canOpenForcibly = fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.creativeOpenContainerForcibly && player.isCreative();
if (level instanceof ServerLevel serverLevel
&& level.getBlockEntity(pos) instanceof ShulkerBoxBlockEntity shulkerBoxBlockEntity
- && canOpen(state, level, pos, shulkerBoxBlockEntity) // Paper - Fix InventoryOpenEvent cancellation - expand if for belows check
+ && (canOpen(state, level, pos, shulkerBoxBlockEntity) || canOpenForcibly) // Paper - Fix InventoryOpenEvent cancellation - expand if for belows check
&& player.openMenu(shulkerBoxBlockEntity).isPresent()) { // Paper - Fix InventoryOpenEvent cancellation
player.awardStat(Stats.OPEN_SHULKER_BOX);
PiglinAi.angerNearbyPiglins(serverLevel, player, true);
diff --git a/net/minecraft/world/level/block/TntBlock.java b/net/minecraft/world/level/block/TntBlock.java
index 58142c276c976b16100e14ee9adb547f74e4cb41..7a6a05813216d0a0dcc1f4a546b51c021b07714a 100644
--- a/net/minecraft/world/level/block/TntBlock.java
+++ b/net/minecraft/world/level/block/TntBlock.java
@@ -47,7 +47,8 @@ public class TntBlock extends Block {
@Override
protected void onPlace(final BlockState state, final Level level, final BlockPos pos, final BlockState oldState, final boolean movedByPiston) {
if (!oldState.is(state.getBlock())) {
- if (level.hasNeighborSignal(pos) && prime(level, pos, () -> org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(level, pos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.REDSTONE, null, null))) { // CraftBukkit - TNTPrimeEvent
+ if (shouldPrimeFromRedstone(level, pos)
+ && prime(level, pos, () -> org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(level, pos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.REDSTONE, null, null))) { // CraftBukkit - TNTPrimeEvent
level.removeBlock(pos, false);
}
}
@@ -57,7 +58,9 @@ public class TntBlock extends Block {
protected void neighborChanged(
final BlockState state, final Level level, final BlockPos pos, final Block block, final @Nullable Orientation orientation, final boolean movedByPiston
) {
- if (level.hasNeighborSignal(pos) && prime(level, pos, () -> org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(level, pos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.REDSTONE, null, null))) { // CraftBukkit - TNTPrimeEvent
+ if (!fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.tntIgnoreRedstoneSignal
+ && level.hasNeighborSignal(pos)
+ && prime(level, pos, () -> org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(level, pos, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.REDSTONE, null, null))) { // CraftBukkit - TNTPrimeEvent
level.removeBlock(pos, false);
}
}
@@ -76,7 +79,7 @@ public class TntBlock extends Block {
if (level.getGameRules().get(GameRules.TNT_EXPLODES)) {
PrimedTnt primed = new PrimedTnt(level, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, explosion.getIndirectSourceEntity());
int fuse = primed.getFuse();
- primed.setFuse((short)(level.getRandom().nextInt(fuse / 4) + fuse / 8));
+ primed.setFuse(level.getRandom().nextInt(Math.max(fuse / 4, 1)) + fuse / 8);
level.addFreshEntity(primed);
}
}
@@ -156,4 +159,10 @@ public class TntBlock extends Block {
protected void createBlockStateDefinition(final StateDefinition.Builder<Block, BlockState> builder) {
builder.add(UNSTABLE);
}
+
+ private static boolean shouldPrimeFromRedstone(final Level level, final BlockPos pos) {
+ return !fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.tntDoNotUpdate
+ && !fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.tntIgnoreRedstoneSignal
+ && level.hasNeighborSignal(pos);
+ }
}
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index aa782c6441cdce3eb39aefb28d40f3b1970d4e62..3e4fae7a5ae7f8a26bf78727e81c4a87e8fed332 100644
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -296,6 +296,8 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
private static boolean hopperPush(final Level level, final Container destination, final Direction direction, final HopperBlockEntity hopper) {
io.papermc.paper.threadedregions.RegionizedWorldData worldData = level.getCurrentWorldData(); // Folia - region threading
worldData.skipPushModeEventFire = worldData.skipHopperEvents; // Folia - region threading
+ boolean noItemCost = fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.hopperNoItemCost
+ && org.leavesmc.leaves.util.WoolUtils.getWoolColorAtPosition(level, hopper.getBlockPos().above()) != null;
boolean foundItem = false;
for (int i = 0; i < hopper.getContainerSize(); ++i) {
final ItemStack item = hopper.getItem(i);
@@ -321,6 +323,13 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
final ItemStack remainingItem = addItem(hopper, destination, movedItem, direction);
final int remainingItemCount = remainingItem.getCount();
if (remainingItemCount != movedItemCount) {
+ if (noItemCost) {
+ origItemStack.setCount(originalItemCount);
+ hopper.setItem(i, origItemStack);
+ destination.setChanged();
+ return true;
+ }
+
origItemStack = origItemStack.copy(true);
origItemStack.setCount(originalItemCount);
if (!origItemStack.isEmpty()) {
diff --git a/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/net/minecraft/world/level/block/piston/PistonBaseBlock.java
index 5ae07ece1046dda464f284c1dd13b2780f831e02..a4d8ed890fc6bea1e961df814c00d22ae147734f 100644
--- a/net/minecraft/world/level/block/piston/PistonBaseBlock.java
+++ b/net/minecraft/world/level/block/piston/PistonBaseBlock.java
@@ -379,7 +379,7 @@ public class PistonBaseBlock extends DirectionalBlock {
for (int i = toPush.size() - 1; i >= 0; i--) {
// Paper start - fix a variety of piston desync dupes
- boolean allowDesync = io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPistonDuplication;
+ boolean allowDesync = !fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.tntDupingFix;
BlockPos oldPos = toPush.get(i);
BlockPos pos = oldPos;
BlockState blockState = allowDesync ? level.getBlockState(oldPos) : null;
diff --git a/net/minecraft/world/level/block/state/BlockBehaviour.java b/net/minecraft/world/level/block/state/BlockBehaviour.java
index ff1471f40b73582df68efbf2996a854c6aa37d65..668f59f94efb34490bdd7d6aac62fb37dd64a485 100644
--- a/net/minecraft/world/level/block/state/BlockBehaviour.java
+++ b/net/minecraft/world/level/block/state/BlockBehaviour.java
@@ -848,6 +848,10 @@ public abstract class BlockBehaviour implements FeatureElement, org.leavesmc.lea
}
public Vec3 getOffset(final BlockPos pos) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.bambooModelNoOffset && (this.getBlock() == Blocks.BAMBOO || this.getBlock() == Blocks.BAMBOO_SAPLING)) {
+ return Vec3.ZERO;
+ }
+
BlockBehaviour.OffsetFunction function = this.offsetFunction;
return function != null ? function.evaluate(this.asState(), pos) : Vec3.ZERO;
}
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
index 11f0f5e1b8ee9ce7e6833d46ccb557d896674431..5a0271b29589db3e02f87b935a787d180b3696f0 100644
--- a/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
@@ -423,10 +423,11 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
boolean blockChanged = !oldState.is(newBlock);
boolean movedByPiston = (flags & Block.UPDATE_MOVE_BY_PISTON) != 0;
boolean sideEffects = (flags & Block.UPDATE_SKIP_BLOCK_ENTITY_SIDEEFFECTS) == 0;
+ boolean skipInteractionUpdates = fun.bm.lophine.carpet.InteractionUpdateCompatHelper.shouldSkipUpdates();
// Leaves start - behaviour 1.21.1-
if (!fun.bm.lophine.config.modules.experiment.RedStoneConfig.oldBlockRemoveBehaviour) {
if (blockChanged && oldState.hasBlockEntity() && !state.shouldChangedStateKeepBlockEntity(oldState)) {
- if (!this.level.isClientSide() && sideEffects) {
+ if (!this.level.isClientSide() && sideEffects && !skipInteractionUpdates) {
BlockEntity blockEntity = this.level.getBlockEntity(pos);
if (blockEntity != null) {
blockEntity.preRemoveSideEffects(pos, oldState);
@@ -438,6 +439,7 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
if ((blockChanged || newBlock instanceof BaseRailBlock)
&& this.level instanceof ServerLevel serverLevel
+ && !skipInteractionUpdates
&& ((flags & Block.UPDATE_NEIGHBORS) != 0 || movedByPiston)) {
oldState.affectNeighborsAfterRemoval(serverLevel, pos, movedByPiston);
}
@@ -449,7 +451,10 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
if (!section.getBlockState(localX, localY, localZ).is(newBlock)) {
return null;
} else {
- if (!this.level.isClientSide() && (flags & Block.UPDATE_SKIP_ON_PLACE) == 0 && (!this.level.getCurrentWorldData().captureBlockStates || newBlock instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled. // Folia - region threading
+ if (!this.level.isClientSide()
+ && !skipInteractionUpdates
+ && (flags & Block.UPDATE_SKIP_ON_PLACE) == 0
+ && (!this.level.getCurrentWorldData().captureBlockStates || newBlock instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled. // Folia - region threading
state.onPlace(this.level, pos, oldState, movedByPiston);
}
diff --git a/net/minecraft/world/level/dimension/end/DragonRespawnStage.java b/net/minecraft/world/level/dimension/end/DragonRespawnStage.java
index e02f5432d90866a06c48a58895908f7178ef1051..5573df701aef5e1fb77d1ff57c1459c142dad638 100644
--- a/net/minecraft/world/level/dimension/end/DragonRespawnStage.java
+++ b/net/minecraft/world/level/dimension/end/DragonRespawnStage.java
@@ -55,16 +55,17 @@ public enum DragonRespawnStage implements StringRepresentable {
respawnCrystal.setBeamTarget(new BlockPos(spike.getCenterX(), spike.getHeight() + 1, spike.getCenterZ()));
}
} else {
- int radius = 10;
+ if (!fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.preventEndSpikeRespawn) {
+ for (BlockPos pos : BlockPos.betweenClosed(
+ new BlockPos(spike.getCenterX() - 10, spike.getHeight() - 10, spike.getCenterZ() - 10),
+ new BlockPos(spike.getCenterX() + 10, spike.getHeight() + 10, spike.getCenterZ() + 10)
+ )) {
+ level.removeBlock(pos, false);
+ }
- for (BlockPos pos : BlockPos.betweenClosed(
- new BlockPos(spike.getCenterX() - 10, spike.getHeight() - 10, spike.getCenterZ() - 10),
- new BlockPos(spike.getCenterX() + 10, spike.getHeight() + 10, spike.getCenterZ() + 10)
- )) {
- level.removeBlock(pos, false);
+ level.explode(null, spike.getCenterX() + 0.5F, spike.getHeight(), spike.getCenterZ() + 0.5F, 5.0F, Level.ExplosionInteraction.BLOCK);
}
- level.explode(null, spike.getCenterX() + 0.5F, spike.getHeight(), spike.getCenterZ() + 0.5F, 5.0F, Level.ExplosionInteraction.BLOCK);
EndSpikeConfiguration configuration = new EndSpikeConfiguration(true, ImmutableList.of(spike), new BlockPos(0, 128, 0));
Feature.END_SPIKE
.place(
diff --git a/net/minecraft/world/level/levelgen/feature/EndSpikeFeature.java b/net/minecraft/world/level/levelgen/feature/EndSpikeFeature.java
index 3fdf80e32bdcaab4daac8f1c7329a2bc7b2bd625..284cec8401eb75076b2d80581059f489aa4022f9 100644
--- a/net/minecraft/world/level/levelgen/feature/EndSpikeFeature.java
+++ b/net/minecraft/world/level/levelgen/feature/EndSpikeFeature.java
@@ -68,6 +68,10 @@ public class EndSpikeFeature extends Feature<EndSpikeConfiguration> {
private void placeSpike(
final ServerLevelAccessor level, final RandomSource random, final EndSpikeConfiguration config, final EndSpikeFeature.EndSpike spike
) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.preventEndSpikeRespawn && config.getCrystalBeamTarget() != null) {
+ return;
+ }
+
int radius = spike.getRadius();
for (BlockPos pos : BlockPos.betweenClosed(
diff --git a/net/minecraft/world/level/redstone/NeighborUpdater.java b/net/minecraft/world/level/redstone/NeighborUpdater.java
index 6d25139a94df7c0442cc9fea96d5839ce8a23d54..a6a85a8eccff59c8cedab70341baba06dad687be 100644
--- a/net/minecraft/world/level/redstone/NeighborUpdater.java
+++ b/net/minecraft/world/level/redstone/NeighborUpdater.java
@@ -42,6 +42,10 @@ public interface NeighborUpdater {
@Block.UpdateFlags final int updateFlags,
final int updateLimit
) {
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.totallyNoBlockUpdate) {
+ return;
+ }
+
BlockState currentState = level.getBlockState(pos);
if ((updateFlags & Block.UPDATE_SKIP_SHAPE_UPDATE_ON_WIRE) == 0 || !currentState.is(Blocks.REDSTONE_WIRE)) {
try {
@@ -72,6 +76,10 @@ public interface NeighborUpdater {
static void executeUpdate(Level level, BlockState state, BlockPos pos, Block changedBlock, @Nullable Orientation orientation, boolean movedByPiston, BlockPos sourcePos) {
// Paper end - Add source block to BlockPhysicsEvent
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.totallyNoBlockUpdate) {
+ return;
+ }
+
try {
// CraftBukkit start
org.bukkit.event.block.BlockPhysicsEvent event = new org.bukkit.event.block.BlockPhysicsEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, pos), state.asBlockData(), org.bukkit.craftbukkit.block.CraftBlock.at(level, sourcePos)); // Paper - Add source block to BlockPhysicsEvent