Files
Lophine/lophine-server/minecraft-patches/features/0126-Carpet-features.patch
T
2026-08-08 01:51:27 +08:00

1301 lines
84 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 f881d10d63a665a73aefe03ba1305ca9ae956513..7577533f82688304f06c445fd5a1c3fa3c4575fc 100644
--- a/io/papermc/paper/threadedregions/RegionizedServer.java
+++ b/io/papermc/paper/threadedregions/RegionizedServer.java
@@ -238,6 +238,7 @@ public final class RegionizedServer {
private long tickCount;
private void globalTick(final long tickCount) {
+ final long tickStartNanos = System.nanoTime(); // Lophine - Carpet features
++this.tickCount;
// Luminol start - Add a config to enable tick command
if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.commandTick) { // Lophine - redirect
@@ -280,6 +281,10 @@ public final class RegionizedServer {
}
// Lophine end - Add a config to enable tick command
+ // Lophine start - Carpet features
+ fun.bm.lophine.protocol.tiscm.TISCMProtocol.broadcastMsptSample(this.tickCount, System.nanoTime() - tickStartNanos);
+
+ // Lophine end - Carpet features
// tick connections
this.tickConnections();
diff --git a/net/minecraft/commands/arguments/blocks/BlockInput.java b/net/minecraft/commands/arguments/blocks/BlockInput.java
index 29dcaa5b33e4f6c649b0918721cfaafe9c74eb01..804f7d9d5b71ccff3c16f4c743081c38b658dd3c 100644
--- a/net/minecraft/commands/arguments/blocks/BlockInput.java
+++ b/net/minecraft/commands/arguments/blocks/BlockInput.java
@@ -65,7 +65,11 @@ public class BlockInput implements Predicate<BlockInWorld> {
}
public boolean place(final ServerLevel level, final BlockPos pos, final @Block.UpdateFlags int update) {
- BlockState state = (update & Block.UPDATE_KNOWN_SHAPE) != 0 ? this.state : Block.updateFromNeighbourShapes(this.state, level, pos);
+ // Lophine start - Carpet features
+ BlockState state = (update & Block.UPDATE_KNOWN_SHAPE) != 0 || fun.bm.lophine.carpet.InteractionUpdateHelper.shouldSkipUpdates()
+ ? this.state
+ : Block.updateFromNeighbourShapes(this.state, level, pos);
+ // Lophine end - Carpet features
if (state.isAir()) {
state = this.state;
}
diff --git a/net/minecraft/core/Direction.java b/net/minecraft/core/Direction.java
index 46547155b817a89a8afe2f8d1a30bf881efc07bc..c9a766f14fd2ad7f42af252b702e8ecd9956cb64 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; // Lophine - Carpet features
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 a28958b8ab09b3ffdcedba19e0063af07f177080..c37a985102198add61f7d70e33e21d585fb2b399 100644
--- a/net/minecraft/network/chat/SignedMessageValidator.java
+++ b/net/minecraft/network/chat/SignedMessageValidator.java
@@ -31,7 +31,11 @@ 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())) {
+ // Lophine start - Carpet features
+ } else if (this.lastMessage != null
+ && !fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.yeetOutOfOrderChatKick
+ && !message.link().isDescendantOf(this.lastMessage.link())) {
+ // Lophine end - Carpet features
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 4421658e4061299dea2ff72a77506214cc9045d8..53bda989ce23d9eb144f1dc3d54fbe2a91cd1e17 100644
--- a/net/minecraft/server/commands/TickCommand.java
+++ b/net/minecraft/server/commands/TickCommand.java
@@ -21,7 +21,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())) // Lophine - Carpet features
.then(Commands.literal("query").executes(c -> tickQuery(c.getSource())))
.then( // Lophine - Add tick rate support
Commands.literal("rate")
@@ -107,8 +107,14 @@ public class TickCommand {
return Command.SINGLE_SUCCESS;
}
- private static int setFreeze(final CommandSourceStack source, final boolean freeze) {
+ private static int setFreeze(final CommandSourceStack source, boolean freeze) { // Lophine - Carpet features
ServerTickRateManager manager = source.getServer().tickRateManager();
+ // Lophine start - Carpet features
+ if (freeze && fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.tickFreezeCommandToggleable && manager.isFrozen()) {
+ freeze = false;
+ }
+
+ // Lophine end - Carpet features
if (freeze) {
if (manager.isSprinting()) {
manager.stopSprinting();
@@ -164,4 +170,10 @@ public class TickCommand {
return 0;
}
}
+ // Lophine start - Carpet features
+
+ 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())));
+ }
+ // Lophine end - Carpet features
}
diff --git a/net/minecraft/server/dedicated/DedicatedPlayerList.java b/net/minecraft/server/dedicated/DedicatedPlayerList.java
index 8cc4fe9feb57902a4b9a6a26e6175ac00a2cef65..9ab1a812e43145120859734075e2ac995d0357c2 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)); // Lophine - Carpet features
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 ac6561a1552f7a2f724fefe0aa1507dbd9a703ef..d393f485965ddd960b4a3cb26ad7eb48deccb4ab 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -260,6 +260,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; // Lophine - Carpet features
private @Nullable Vec3 startingToFallPosition;
private @Nullable Vec3 enteredNetherPosition;
private @Nullable Vec3 enteredLavaOnVehiclePosition;
@@ -2147,7 +2148,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.lastSentFood = -1;
this.teleportSpectators(transition, oldLevel);
// Leaves start - bot support
- if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.checkEnabled()) {
this.server.getBotList().bots.forEach(bot -> bot.sendFakeDataIfNeed(this, true)); // Leaves - render bot
}
// Leaves end - bot support
@@ -2784,6 +2785,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
this.setShoulderEntityRight(oldPlayer.getShoulderEntityRight());
this.setLastDeathLocation(oldPlayer.getLastDeathLocation());
this.waypointIcon().copyFrom(oldPlayer.waypointIcon());
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.clientSettingsLostOnRespawnFix && oldPlayer.lastKnownClientInformation != null) {
+ this.updateOptions(oldPlayer.lastKnownClientInformation);
+ }
+ // Lophine end - Carpet features
}
private void transferInventoryXpAndScore(final Player oldPlayer) {
@@ -3063,6 +3069,11 @@ 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());
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.clientSettingsLostOnRespawnFix) {
+ this.lastKnownClientInformation = information;
+ }
+ // Lophine end - Carpet features
}
public ClientInformation clientInformation() {
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 11d177e486958727f880f073550ae5db7e233dcd..e489da1acbb77c003951b608856ea706570cbed6 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -2092,7 +2092,15 @@ 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());
+ // Lophine start - Carpet features
+ 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.InteractionUpdateHelper.runWithSuppressedUpdates(
+ () -> this.player.gameMode.handleBlockBreakAction(pos, action, packet.getDirection(), this.player.level().getMaxY(), packet.getSequence())
+ );
+ }
+ // Lophine end - Carpet features
this.ackBlockChangesUpTo(packet.getSequence());
// Paper start - Send block entities after destroy prediction
this.player.gameMode.captureSentBlockEntities = false;
@@ -2195,7 +2203,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);
}
@@ -2300,7 +2310,10 @@ public class ServerGamePacketListenerImpl
}
// CraftBukkit end
- if (this.player.gameMode.useItem(this.player, level, itemStack, hand) instanceof InteractionResult.Success success
+ // Lophine start - Carpet features
+ ItemStack itemStackToUse = itemStack;
+ if (this.runInteractionWithConfiguredUpdates(() -> this.player.gameMode.useItem(this.player, level, itemStackToUse, hand)) instanceof InteractionResult.Success success
+ // Lophine end - Carpet features
&& success.swingSource() == InteractionResult.SwingSource.SERVER) {
this.player.swing(hand, true);
}
@@ -2308,6 +2321,16 @@ public class ServerGamePacketListenerImpl
}
}
+ // Lophine start - Carpet features
+ 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.InteractionUpdateHelper.supplyWithSuppressedUpdates(action);
+ }
+
+ // Lophine end - Carpet features
@Override
public void handleTeleportToEntityPacket(final ServerboundTeleportToEntityPacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level());
@@ -2688,6 +2711,10 @@ public class ServerGamePacketListenerImpl
if (true) throw new UnsupportedOperationException(); // Folia - region threading
final String conversationInput = rawMessage;
this.server.processQueue.add(() -> ServerGamePacketListenerImpl.this.getCraftPlayer().acceptConversationInput(conversationInput));
+ // Lophine start - Carpet features
+ } else if (fun.bm.lophine.carpet.CarpetCalculatorHelper.handleChat(this.player, rawMessage)) {
+ return;
+ // Lophine end - Carpet features
} 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 {
@@ -2700,6 +2727,9 @@ public class ServerGamePacketListenerImpl
// Spigot start - spam exclusions
private void detectRateSpam(final TickThrottler throttler, final 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) {
@@ -3646,8 +3676,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/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index 7f3492a909536ca14577c3ec3aa511e98ca5551f..2d6500eb0a01f455de8d7a627cabcc06bb60ca61 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -280,7 +280,7 @@ public abstract class PlayerList {
// org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player); // Leaves - protocol
// Leaves start - bot support
- if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.checkEnabled()) {
org.leavesmc.leaves.bot.ServerBot bot = this.server.getBotList().getBotByName(player.getScoreboardName());
if (bot != null) {
this.server.getBotList().removeBot(bot, org.leavesmc.leaves.event.bot.BotRemoveEvent.RemoveReason.INTERNAL, player.getBukkitEntity(), false, false);
@@ -442,7 +442,7 @@ public abstract class PlayerList {
org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player); // Leaves - protocol
// Leaves start - bot support
- if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.checkEnabled()) {
org.leavesmc.leaves.bot.ServerBot bot = this.server.getBotList().getBotByName(player.getScoreboardName());
if (bot != null) {
this.server.getBotList().removeBot(bot, org.leavesmc.leaves.event.bot.BotRemoveEvent.RemoveReason.INTERNAL, player.getBukkitEntity(), false, false);
@@ -970,7 +970,7 @@ public abstract class PlayerList {
).callEvent();
// Paper end
// Leaves start - bot support
- if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.checkEnabled()) {
this.server.getBotList().bots.forEach(bot -> bot.sendFakeDataIfNeed(player, true)); // Leaves - render bot
}
// Leaves end - bot support
diff --git a/net/minecraft/world/entity/ExperienceOrb.java b/net/minecraft/world/entity/ExperienceOrb.java
index b95c56e0699fbe16e65efcf010cd514f0ac0962f..0125d59551accd9005aa33a5c7cc8ec288fb7757 100644
--- a/net/minecraft/world/entity/ExperienceOrb.java
+++ b/net/minecraft/world/entity/ExperienceOrb.java
@@ -356,8 +356,27 @@ public class ExperienceOrb extends Entity {
@Override
public void playerTouch(final Player player) {
if (player instanceof ServerPlayer serverPlayer) {
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.xpNoCooldown) {
+ player.takeXpDelay = 0;
+ }
+
+ // Lophine end - Carpet features
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;
+ // Lophine start - Carpet features
+ 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--;
+ }
+ }
+
+ // Lophine end - Carpet features
player.take(this, 1);
int remaining = this.repairPlayerItems(serverPlayer, this.getValue());
if (remaining > 0) {
@@ -373,6 +392,12 @@ public class ExperienceOrb extends Entity {
}
private int repairPlayerItems(final ServerPlayer player, final int amount) {
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.powerfulExpMending) {
+ return this.repairAllPlayerItems(player, amount);
+ }
+
+ // Lophine end - Carpet features
Optional<EnchantedItemInUse> selected = EnchantmentHelper.getRandomItemWith(EnchantmentEffectComponents.REPAIR_WITH_XP, player, ItemStack::isDamaged);
if (selected.isPresent()) {
ItemStack itemStack = selected.get().itemStack();
@@ -402,6 +427,78 @@ public class ExperienceOrb extends Entity {
}
}
+ // Lophine start - Carpet features
+ 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) {
+ }
+
+ // Lophine end - Carpet features
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 dae262a073acb3bb3464d169dd5a0b6d67f27846..0990e393c8695b17571d9a7646d895ab07ec30ba 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -623,7 +623,10 @@ 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()) {
+ // Lophine start - Carpet features
+ int removalDelay = fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.entityInstantDeathRemoval ? 1 : 20;
+ if (this.deathTime >= removalDelay && !this.level().isClientSide() && !this.isRemoved()) {
+ // Lophine end - Carpet features
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 4e8385b340686531297324983754fab4150e41b8..34018a6f7a8c97c489a938222df189e8790d015d 100644
--- a/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/net/minecraft/world/entity/item/PrimedTnt.java
@@ -73,8 +73,14 @@ public class PrimedTnt extends Entity implements TraceableEntity {
this(EntityTypes.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);
+ // Lophine start - Carpet features
+ 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());
+ // Lophine end - Carpet features
this.xo = x;
this.yo = y;
this.zo = z;
@@ -83,7 +89,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()); // Lophine - Carpet features
entityData.define(DATA_BLOCK_STATE_ID, DEFAULT_BLOCK_STATE);
}
@@ -180,7 +186,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())); // Lophine - Carpet features
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");
@@ -203,6 +209,12 @@ public class PrimedTnt extends Entity implements TraceableEntity {
this.entityData.set(DATA_FUSE_ID, time);
}
+ // Lophine start - Carpet features
+ private static int getConfiguredFuseTime() {
+ return fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.normalizedTntFuseDuration();
+ }
+
+ // Lophine end - Carpet features
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 d2ac2a0c5bb18c2bca18e5166ed65afd01166e04..6b3adf1af870c3d710494d34d2f25850126516eb 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) { // Lophine - Carpet features
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,15 @@ public class EnderMan extends Monster implements NeutralMob {
} // CraftBukkit
}
}
+ // Lophine start - Carpet features
+
+ 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);
+ }
+ // Lophine end - Carpet features
}
}
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
index 8709dabd6d3574e53210543321ca88c778594afc..76af5d1aa163e399cd4b5ed1ffd0a03757e31555 100644
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -560,7 +560,15 @@ public abstract class Player extends Avatar implements ContainerUser {
}
if (!orbs.isEmpty()) {
- this.touch(Util.getRandom(orbs, this.random));
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.xpNoCooldown) {
+ for (Entity orb : orbs) {
+ this.touch(orb);
+ }
+ } else {
+ this.touch(Util.getRandom(orbs, this.random));
+ }
+ // Lophine end - Carpet features
}
}
@@ -1078,6 +1086,28 @@ public abstract class Player extends Avatar implements ContainerUser {
if (playerAttackEntityEvent.callEvent() && willAttack) { // Logic moved to willAttack local variable.
// Paper end - PlayerAttackEntityEvent
+ // Lophine start - Carpet features
+ 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;
+ }
+
+ // Lophine end - Carpet features
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
@@ -1137,6 +1167,18 @@ public abstract class Player extends Avatar implements ContainerUser {
}
}
+ // Lophine start - Carpet features
+ 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);
+ }
+
+ // Lophine end - Carpet features
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 aebcab247f49ada6af76b3c0e60944134d8f6f88..eb65e9323f75a28ddc55619bf84d103750631870 100644
--- a/net/minecraft/world/item/BlockItem.java
+++ b/net/minecraft/world/item/BlockItem.java
@@ -150,8 +150,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 ca548c006dfde82bef3f8855e275df63a42b8e09..c447a5ccce7c859ed61ab42e25d683262df9e062 100644
--- a/net/minecraft/world/item/ServerItemCooldowns.java
+++ b/net/minecraft/world/item/ServerItemCooldowns.java
@@ -14,6 +14,11 @@ public class ServerItemCooldowns extends ItemCooldowns {
// Paper start - Add PlayerItemCooldownEvent
@Override
public void addCooldown(ItemStack item, int duration) {
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.creativeNoItemCooldown && this.player.isCreative()) {
+ return;
+ }
+ // Lophine end - Carpet features
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 6812ade4d9de26d507234b8357b109ec7e5cbb50..071d2cd7e0c2e5bba0732590ba804a5cb5db3f5e 100644
--- a/net/minecraft/world/item/crafting/RecipeManager.java
+++ b/net/minecraft/world/item/crafting/RecipeManager.java
@@ -55,6 +55,11 @@ public class RecipeManager extends SimplePreparableReloadListener<RecipeMap> imp
forSingleInput(RecipeType.CAMPFIRE_COOKING)
);
private static final FileToIdConverter RECIPE_LISTER = FileToIdConverter.registry(Registries.RECIPE);
+ // Lophine start - Carpet features
+ 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");
+ // Lophine end - Carpet features
private final HolderLookup.Provider registries;
public RecipeMap recipes = RecipeMap.EMPTY;
private Map<ResourceKey<RecipePropertySet>, RecipePropertySet> propertySets = Map.of();
@@ -83,10 +88,75 @@ public class RecipeManager extends SimplePreparableReloadListener<RecipeMap> imp
@Override
protected void apply(final RecipeMap recipes, final ResourceManager manager, final ProfilerFiller profiler) {
+ this.injectCompatRecipes(recipes); // Lophine - Carpet features
this.recipes = recipes;
LOGGER.info("Loaded {} recipes", recipes.values().size());
}
+ // Lophine start - Carpet features
+ 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));
+ }
+
+ // Lophine end - Carpet features
// 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 000e4924e8e338728715a3946002903a3118a98a..ca92bb3a8b739c0da3f48a2dd16c5fb4fa7e8453 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -1179,7 +1179,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
// CraftBukkit start - Split off from above in order to directly send client and physic updates
public void notifyAndUpdatePhysics(BlockPos pos, LevelChunk chunk, BlockState oldState, BlockState blockState, BlockState newState, @Block.UpdateFlags int updateFlags, int updateLimit) {
if (newState == blockState) {
- if (oldState != newState) {
+ // Lophine start - Carpet features
+ boolean skipInteractionUpdates = fun.bm.lophine.carpet.InteractionUpdateHelper.shouldSkipUpdates();
+ if (skipInteractionUpdates) {
+ updateFlags &= ~Block.UPDATE_NEIGHBORS;
+ }
+ // Lophine end - Carpet features
+ if (oldState != newState) {
this.setBlocksDirty(pos, oldState, newState);
}
@@ -1194,7 +1200,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
}
}
- if ((updateFlags & Block.UPDATE_KNOWN_SHAPE) == 0 && updateLimit > 0) {
+ if (!skipInteractionUpdates && (updateFlags & Block.UPDATE_KNOWN_SHAPE) == 0 && updateLimit > 0) { // Lophine - Carpet features
int neighbourUpdateFlags = updateFlags & ~(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 0d8d2459457167d78a9a9ea43765980240416947..6da302e1dd755217b82dbc10051324bc8b5d10c1 100644
--- a/net/minecraft/world/level/NaturalSpawner.java
+++ b/net/minecraft/world/level/NaturalSpawner.java
@@ -289,6 +289,12 @@ public final class NaturalSpawner {
Player nearestPlayer = level.getNearestPlayer(xx, yStart, zz, -1.0, false);
if (nearestPlayer != null) {
double nearestPlayerDistanceSqr = nearestPlayer.distanceToSqr(xx, yStart, zz);
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.lagFreeSpawning) {
+ nearestPlayerDistanceSqr = fun.bm.lophine.carpet.LagFreeSpawningHelper.limitDistanceSq(mobCategory, nearestPlayerDistanceSqr);
+ }
+
+ // Lophine end - Carpet features
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(
@@ -329,6 +335,12 @@ 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()) {
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.lagFreeSpawning) {
+ fun.bm.lophine.carpet.LagFreeSpawningHelper.markSpawned(level, mob.getType());
+ }
+
+ // Lophine end - Carpet features
clusterSize++;
groupSize++;
spawnCallback.run(mob, chunk);
@@ -408,11 +420,24 @@ 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));
+ // Lophine start - Carpet features
+ && (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.lagFreeSpawning
+ ? fun.bm.lophine.carpet.LagFreeSpawningHelper.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)));
+ // Lophine end - Carpet features
return success ? PreSpawnStatus.SUCCESS : PreSpawnStatus.FAIL; // Paper - PreCreatureSpawnEvent
}
private static @Nullable Mob getMobForSpawn(final ServerLevel level, final EntityType<?> type) {
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.lagFreeSpawning) {
+ Mob cachedMob = fun.bm.lophine.carpet.LagFreeSpawningHelper.getOrCreateMob(level, type);
+ if (cachedMob != null) {
+ return cachedMob;
+ }
+ }
+
+ // Lophine end - Carpet features
try {
if (type.create(level, EntitySpawnReason.NATURAL) instanceof Mob mob) {
return mob;
@@ -533,7 +558,11 @@ public final class NaturalSpawner {
float width = spawnerData.type().getWidth();
double fx = Mth.clamp(x, (double)xo + width, xo + 16.0 - width);
double fz = Mth.clamp(z, (double)zo + width, zo + 16.0 - width);
- if (!level.noCollision(spawnerData.type().getSpawnAABB(fx, pos.getY(), fz))
+ // Lophine start - Carpet features
+ if (!(fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.lagFreeSpawning
+ ? fun.bm.lophine.carpet.LagFreeSpawningHelper.hasNoCollision(level.getLevel(), spawnerData.type().getSpawnAABB(fx, pos.getY(), fz))
+ : level.noCollision(spawnerData.type().getSpawnAABB(fx, pos.getY(), fz)))
+ // Lophine end - Carpet features
|| !SpawnPlacements.checkSpawnRules(
spawnerData.type(),
level,
@@ -565,6 +594,11 @@ 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
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.lagFreeSpawning) {
+ fun.bm.lophine.carpet.LagFreeSpawningHelper.markSpawned(level.getLevel(), mob.getType());
+ }
+ // Lophine end - Carpet features
success = true;
}
}
diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java
index b90077b44ce81d5d60f9d0ad2414f0b7c6b1e720..4f4512d30717e5e41bd98703574485c0e2b866fb 100644
--- a/net/minecraft/world/level/ServerExplosion.java
+++ b/net/minecraft/world/level/ServerExplosion.java
@@ -371,6 +371,12 @@ public class ServerExplosion implements Explosion {
}
private List<BlockPos> calculateExplodedPositions() {
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.explosionNoBlockDamage) {
+ return List.of();
+ }
+
+ // Lophine end - Carpet features
// 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 5a316fedee1992efd4a21c4678b659c4589d57ec..f0a46c30b3c446cdc52a8198608d7f60441b7d1b 100644
--- a/net/minecraft/world/level/block/CarvedPumpkinBlock.java
+++ b/net/minecraft/world/level/block/CarvedPumpkinBlock.java
@@ -59,7 +59,10 @@ 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;
+ // Lophine start - Carpet features
+ || this.getOrCreateCopperGolemBase().find(level, topPos) != null
+ || this.canSpawnShulkerGolem(level, topPos);
+ // Lophine end - Carpet features
}
private void trySpawnGolem(final Level level, final BlockPos topPos) {
@@ -92,6 +95,10 @@ public class CarvedPumpkinBlock extends HorizontalDirectionalBlock {
copperGolem.spawn(this.getWeatherStateFromPattern(copperGolemMatch));
}
}
+ // Lophine start - Carpet features
+
+ this.trySpawnShulkerGolem(level, topPos);
+ // Lophine end - Carpet features
}
private WeatheringCopper.WeatherState getWeatherStateFromPattern(final BlockPattern.BlockPatternMatch copperGolemMatch) {
@@ -162,6 +169,44 @@ public class CarvedPumpkinBlock extends HorizontalDirectionalBlock {
builder.add(FACING);
}
+ // Lophine start - Carpet features
+ 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 = EntityTypes.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);
+ }
+ }
+
+ // Lophine end - Carpet features
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 70a0d30552d42d91778e0524bb89f6619c1fd0b0..ff4f28446759a5d5968286323675a7cdbf75e92b 100644
--- a/net/minecraft/world/level/block/ChestBlock.java
+++ b/net/minecraft/world/level/block/ChestBlock.java
@@ -272,7 +272,10 @@ 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);
+ // Lophine start - Carpet features
+ boolean ignoreObstructions = fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.creativeOpenContainerForcibly && player.isCreative();
+ MenuProvider menuProvider = this.getMenuProvider(state, level, pos, ignoreObstructions);
+ // Lophine end - Carpet features
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 bfc34508937befc0f7610176ebe625563f7a4fe0..b96afc074191d91e21d13c28c88f26f4e1881ee0 100644
--- a/net/minecraft/world/level/block/EnderChestBlock.java
+++ b/net/minecraft/world/level/block/EnderChestBlock.java
@@ -83,7 +83,10 @@ 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
+ // Lophine start - Carpet features
+ 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
+ // Lophine end - Carpet features
return InteractionResult.SUCCESS;
}
diff --git a/net/minecraft/world/level/block/FarmlandBlock.java b/net/minecraft/world/level/block/FarmlandBlock.java
index ef55faf83e39c8dfd6bbe33c4943ed88bc473715..f91a8608ba4948217fce4a62affe1e4e6cfb7bf2 100644
--- a/net/minecraft/world/level/block/FarmlandBlock.java
+++ b/net/minecraft/world/level/block/FarmlandBlock.java
@@ -132,7 +132,11 @@ public class FarmlandBlock extends Block {
return;
}
// CraftBukkit end
- turnToDirt(entity, state, level, pos);
+ // Lophine start - Carpet features
+ if (!fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.farmlandTrampledDisabled) {
+ turnToDirt(entity, state, level, pos);
+ }
+ // Lophine end - Carpet features
}
// 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 1d68ebf02f4e83a69fc30f36e0b9f688799210c3..505c3b1a99394ec89ea0589e0cad1af44c48959a 100644
--- a/net/minecraft/world/level/block/ObserverBlock.java
+++ b/net/minecraft/world/level/block/ObserverBlock.java
@@ -89,6 +89,12 @@ public class ObserverBlock extends DirectionalBlock {
}
private void startSignal(final LevelReader level, final ScheduledTickAccess ticks, final BlockPos pos) {
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.observerNoDetection) {
+ return;
+ }
+
+ // Lophine end - Carpet features
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 1ccacb7ffa7e8b9c3fdd37910d3e8bded86a4d3a..239258ad543571a5213d1b06aa9e4e9f44261a14 100644
--- a/net/minecraft/world/level/block/RedStoneWireBlock.java
+++ b/net/minecraft/world/level/block/RedStoneWireBlock.java
@@ -292,7 +292,10 @@ 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) {
+ // Lophine start - Carpet features
+ if (!fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.fastRedstoneDust
+ && worldIn.paperConfig().misc.redstoneImplementation == io.papermc.paper.configuration.WorldConfiguration.Misc.RedstoneImplementation.EIGENCRAFT) {
+ // Lophine end - Carpet features
// 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
@@ -367,7 +370,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
@@ -392,7 +396,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
@@ -412,7 +417,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
@@ -444,7 +450,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 a80535ebb7b4fcc3a6c7b84eb08e275461c7ae36..c470631eba2495e6363ea29aad7515d65dd46f4b 100644
--- a/net/minecraft/world/level/block/ShulkerBoxBlock.java
+++ b/net/minecraft/world/level/block/ShulkerBoxBlock.java
@@ -76,9 +76,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(); // Lophine - Carpet features
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 c27fc92d6ff9dd7e07a61513601ef73ff16cf842..e5915893a06e332992c34b8ac511595534f48cdf 100644
--- a/net/minecraft/world/level/block/TntBlock.java
+++ b/net/minecraft/world/level/block/TntBlock.java
@@ -47,7 +47,10 @@ 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
+ // Lophine start - Carpet features
+ 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
+ // Lophine end - Carpet features
level.removeBlock(pos, false);
}
}
@@ -57,7 +60,11 @@ 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
+ // Lophine start - Carpet features
+ 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
+ // Lophine end - Carpet features
level.removeBlock(pos, false);
}
}
@@ -154,4 +161,12 @@ public class TntBlock extends Block {
protected void createBlockStateDefinition(final StateDefinition.Builder<Block, BlockState> builder) {
builder.add(UNSTABLE);
}
+ // Lophine start - Carpet features
+
+ 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);
+ }
+ // Lophine end - Carpet features
}
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index 569f96a1b0b8a03b6a70775f4b7f58a66feed939..df57ae93f91daf8daed2fef48b685c72f0615763 100644
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -241,7 +241,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
}
// Leaves start - Wool hopper counter
- if (fun.bm.lophine.config.modules.function.WoolHopperCounterConfig.unlimitedSpeed && org.leavesmc.leaves.util.HopperCounter.isEnabled()) {
+ if (fun.bm.lophine.carpet.config.modules.WoolHopperCounterConfig.hopperCountersUnlimitedSpeed && org.leavesmc.leaves.util.HopperCounter.isEnabled()) {
net.minecraft.world.item.DyeColor woolColor = org.leavesmc.leaves.util.WoolUtils.getWoolColorAtPosition(level, entity.getBlockPos().relative(state.getValue(HopperBlock.FACING)));
if (woolColor != null) {
for (int i = 0; i < Short.MAX_VALUE; i++) {
@@ -259,7 +259,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
if (changed) {
entity.setCooldown(level.spigotConfig.hopperTransfer); // Spigot
// Leaves start - Wool hopper counter
- if (fun.bm.lophine.config.modules.function.WoolHopperCounterConfig.unlimitedSpeed && org.leavesmc.leaves.util.HopperCounter.isEnabled() && woolHopperCounter(level, pos, state, HopperBlockEntity.getContainerAt(level, pos))) {
+ if (fun.bm.lophine.carpet.config.modules.WoolHopperCounterConfig.hopperCountersUnlimitedSpeed && org.leavesmc.leaves.util.HopperCounter.isEnabled() && woolHopperCounter(level, pos, state, HopperBlockEntity.getContainerAt(level, pos))) {
entity.setCooldown(0);
return true;
}
@@ -296,6 +296,10 @@ 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
+ // Lophine start - Carpet features
+ boolean noItemCost = fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.hopperNoItemCost
+ && org.leavesmc.leaves.util.WoolUtils.getWoolColorAtPosition(level, hopper.getBlockPos().above()) != null;
+ // Lophine end - Carpet features
boolean foundItem = false;
for (int i = 0; i < hopper.getContainerSize(); ++i) {
final ItemStack item = hopper.getItem(i);
@@ -321,6 +325,15 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
final ItemStack remainingItem = addItem(hopper, destination, movedItem, direction);
final int remainingItemCount = remainingItem.getCount();
if (remainingItemCount != movedItemCount) {
+ // Lophine start - Carpet features
+ if (noItemCost) {
+ origItemStack.setCount(originalItemCount);
+ hopper.setItem(i, origItemStack);
+ destination.setChanged();
+ return true;
+ }
+
+ // Lophine end - Carpet features
origItemStack = origItemStack.copy(true);
origItemStack.setCount(originalItemCount);
if (!origItemStack.isEmpty()) {
@@ -655,7 +668,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
}
public static boolean addItem(final Container container, final ItemEntity entity) {
- if (fun.bm.lophine.config.modules.function.WoolHopperCounterConfig.unlimitedSpeed && org.leavesmc.leaves.util.HopperCounter.isEnabled() && entity.isRemoved()) return false; // Leaves - Wool hopper counter
+ if (fun.bm.lophine.carpet.config.modules.WoolHopperCounterConfig.hopperCountersUnlimitedSpeed && org.leavesmc.leaves.util.HopperCounter.isEnabled() && entity.isRemoved()) return false; // Leaves - Wool hopper counter
boolean changed = false;
// CraftBukkit start
if (org.bukkit.event.inventory.InventoryPickupItemEvent.getHandlerList().getRegisteredListeners().length > 0) { // Paper - optimize hoppers
diff --git a/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/net/minecraft/world/level/block/piston/PistonBaseBlock.java
index b4f5d462e4012451328210018c24de5a1d9e8c2e..e8f7944220d76d5c9111c6552e7904751aa26018 100644
--- a/net/minecraft/world/level/block/piston/PistonBaseBlock.java
+++ b/net/minecraft/world/level/block/piston/PistonBaseBlock.java
@@ -387,7 +387,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 972b953a579120c1c05f2dc9bfc2b408d6071d26..a60bb8af6b6aa356193befa9d7e9cdfc7cf38f39 100644
--- a/net/minecraft/world/level/block/state/BlockBehaviour.java
+++ b/net/minecraft/world/level/block/state/BlockBehaviour.java
@@ -859,6 +859,12 @@ public abstract class BlockBehaviour implements FeatureElement, org.leavesmc.lea
}
public Vec3 getOffset(final BlockPos pos) {
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.bambooModelNoOffset && (this.getBlock() == Blocks.BAMBOO || this.getBlock() == Blocks.BAMBOO_SAPLING)) {
+ return Vec3.ZERO;
+ }
+
+ // Lophine end - Carpet features
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 a4d5bf1773a9ce8184a940384696f0d38690a421..5b306cc2d4a3cdc3ce08595dc63975c87fca9d3f 100644
--- a/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
@@ -425,10 +425,10 @@ 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;
- // Leaves start - behaviour 1.21.1-
+ boolean skipInteractionUpdates = fun.bm.lophine.carpet.InteractionUpdateHelper.shouldSkipUpdates(); // Lophine - Carpet features// 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);
@@ -440,7 +440,8 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
if ((blockChanged || newBlock instanceof BaseRailBlock)
&& this.level instanceof ServerLevel serverLevel
- && ((flags & Block.UPDATE_NEIGHBORS) != 0 || movedByPiston)) {
+ && !skipInteractionUpdates
+ && ((flags & Block.UPDATE_NEIGHBORS) != 0 || movedByPiston)) {
oldState.affectNeighborsAfterRemoval(serverLevel, pos, movedByPiston);
}
} else {
@@ -452,7 +453,10 @@ public class LevelChunk extends ChunkAccess implements DebugValueSource, ca.spot
return null;
}
- 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 8d33e8888980f57d4f6d502b4f6912a5f56eff06..f90eb5768b1af9ca07bf6abdea7dbb2509ceb358 100644
--- a/net/minecraft/world/level/dimension/end/DragonRespawnStage.java
+++ b/net/minecraft/world/level/dimension/end/DragonRespawnStage.java
@@ -55,16 +55,19 @@ public enum DragonRespawnStage implements StringRepresentable {
respawnCrystal.setBeamTarget(new BlockPos(spike.getCenterX(), spike.getHeight() + 1, spike.getCenterZ()));
}
} else {
- int radius = 10;
+ // Lophine start - Carpet features
+ 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);
+ }
+ // Lophine end - Carpet features
- 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); // Lophine - Carpet features
}
- 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 f18523cc88dad77b4c7f2174f7db6ca13a199c7c..2e09964a0b3ae755d4b79cfdfe2ae52bd14f37bb 100644
--- a/net/minecraft/world/level/levelgen/feature/EndSpikeFeature.java
+++ b/net/minecraft/world/level/levelgen/feature/EndSpikeFeature.java
@@ -68,6 +68,12 @@ public class EndSpikeFeature extends Feature<EndSpikeConfiguration> {
private void placeSpike(
final ServerLevelAccessor level, final RandomSource random, final EndSpikeConfiguration config, final EndSpikeFeature.EndSpike spike
) {
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.preventEndSpikeRespawn && config.getCrystalBeamTarget() != null) {
+ return;
+ }
+
+ // Lophine end - Carpet features
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 90145a3ea384b568897ee665b80b24cccba1b6c5..4556860c8a8c728e8c64b6b3081fdc7f8608df98 100644
--- a/net/minecraft/world/level/redstone/NeighborUpdater.java
+++ b/net/minecraft/world/level/redstone/NeighborUpdater.java
@@ -42,6 +42,12 @@ public interface NeighborUpdater {
final @Block.UpdateFlags int updateFlags,
final int updateLimit
) {
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.totallyNoBlockUpdate) {
+ return;
+ }
+
+ // Lophine end - Carpet features
BlockState currentState = level.getBlockState(pos);
if ((updateFlags & Block.UPDATE_SKIP_SHAPE_UPDATE_ON_WIRE) == 0 || !currentState.is(Blocks.REDSTONE_WIRE)) {
try {
@@ -72,6 +78,12 @@ 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
+ // Lophine start - Carpet features
+ if (fun.bm.lophine.carpet.config.modules.GeneralCompatConfig.totallyNoBlockUpdate) {
+ return;
+ }
+
+ // Lophine end - Carpet features
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