move file patches to rejected directory

This commit is contained in:
granny
2025-03-14 21:03:05 -07:00
parent 907406a11b
commit e2a920d63c
263 changed files with 0 additions and 0 deletions

View File

@@ -1,10 +0,0 @@
--- a/net/minecraft/world/level/BaseSpawner.java
+++ b/net/minecraft/world/level/BaseSpawner.java
@@ -52,6 +_,7 @@
}
public boolean isNearPlayer(Level level, BlockPos pos) {
+ if (level.purpurConfig.spawnerDeactivateByRedstone && level.hasNeighborSignal(pos)) return false; // Purpur - Redstone deactivates spawners
return level.hasNearbyAlivePlayerThatAffectsSpawning(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, this.requiredPlayerRange); // Paper - Affects Spawning API
}

View File

@@ -1,11 +0,0 @@
--- a/net/minecraft/world/level/EntityGetter.java
+++ b/net/minecraft/world/level/EntityGetter.java
@@ -185,7 +_,7 @@
default boolean hasNearbyAlivePlayer(double x, double y, double z, double distance) {
for (Player player : this.players()) {
- if (EntitySelector.NO_SPECTATORS.test(player) && EntitySelector.LIVING_ENTITY_STILL_ALIVE.test(player)) {
+ if (EntitySelector.NO_SPECTATORS.test(player) && EntitySelector.LIVING_ENTITY_STILL_ALIVE.test(player) && EntitySelector.notAfk.test(player)) { // Purpur - AFK API
double d = player.distanceToSqr(x, y, z);
if (distance < 0.0 || d < distance * distance) {
return true;

View File

@@ -1,84 +0,0 @@
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -170,6 +_,7 @@
// Paper end - add paper world config
public final io.papermc.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
+ public final org.purpurmc.purpur.PurpurWorldConfig purpurConfig; // Purpur - Purpur config files
public static BlockPos lastPhysicsProblem; // Spigot
private org.spigotmc.TickLimiter entityLimiter;
private org.spigotmc.TickLimiter tileLimiter;
@@ -177,6 +_,49 @@
public final Map<ServerExplosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
public java.util.ArrayDeque<net.minecraft.world.level.block.RedstoneTorchBlock.Toggle> redstoneUpdateInfos; // Paper - Faster redstone torch rapid clock removal; Move from Map in BlockRedstoneTorch to here
+ // Purpur start - Add adjustable breeding cooldown to config
+ private com.google.common.cache.Cache<BreedingCooldownPair, Object> playerBreedingCooldowns;
+
+ private com.google.common.cache.Cache<BreedingCooldownPair, Object> getNewBreedingCooldownCache() {
+ return com.google.common.cache.CacheBuilder.newBuilder().expireAfterWrite(this.purpurConfig.animalBreedingCooldownSeconds, java.util.concurrent.TimeUnit.SECONDS).build();
+ }
+
+ public void resetBreedingCooldowns() {
+ this.playerBreedingCooldowns = this.getNewBreedingCooldownCache();
+ }
+
+ public boolean hasBreedingCooldown(java.util.UUID player, Class<? extends net.minecraft.world.entity.animal.Animal> animalType) { // Purpur
+ return this.playerBreedingCooldowns.getIfPresent(new BreedingCooldownPair(player, animalType)) != null;
+ }
+
+ public void addBreedingCooldown(java.util.UUID player, Class<? extends net.minecraft.world.entity.animal.Animal> animalType) {
+ this.playerBreedingCooldowns.put(new BreedingCooldownPair(player, animalType), new Object());
+ }
+
+ private static final class BreedingCooldownPair {
+ private final java.util.UUID playerUUID;
+ private final Class<? extends net.minecraft.world.entity.animal.Animal> animalType;
+
+ public BreedingCooldownPair(java.util.UUID playerUUID, Class<? extends net.minecraft.world.entity.animal.Animal> animalType) {
+ this.playerUUID = playerUUID;
+ this.animalType = animalType;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ BreedingCooldownPair that = (BreedingCooldownPair) o;
+ return playerUUID.equals(that.playerUUID) && animalType.equals(that.animalType);
+ }
+
+ @Override
+ public int hashCode() {
+ return java.util.Objects.hash(playerUUID, animalType);
+ }
+ }
+ // Purpur end - Add adjustable breeding cooldown to config
+
public CraftWorld getWorld() {
return this.world;
}
@@ -853,6 +_,8 @@
// Paper end - getblock optimisations - cache world height/sections
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName()); // Spigot
this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config
+ this.purpurConfig = new org.purpurmc.purpur.PurpurWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName(), env); // Purpur - Purpur config files
+ this.playerBreedingCooldowns = this.getNewBreedingCooldownCache(); // Purpur - Add adjustable breeding cooldown to config
this.generator = gen;
this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env);
@@ -2130,4 +_,14 @@
return this.id;
}
}
+
+ // Purpur start - Add allow water in end world option
+ public boolean isNether() {
+ return getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER;
+ }
+
+ public boolean isTheEnd() {
+ return getWorld().getEnvironment() == org.bukkit.World.Environment.THE_END;
+ }
+ // Purpur end - Add allow water in end world option
}

View File

@@ -1,11 +0,0 @@
--- a/net/minecraft/world/level/NaturalSpawner.java
+++ b/net/minecraft/world/level/NaturalSpawner.java
@@ -267,7 +_,7 @@
mutableBlockPos.set(x, y, z);
double d = x + 0.5;
double d1 = z + 0.5;
- Player nearestPlayer = level.getNearestPlayer(d, y, d1, -1.0, false);
+ Player nearestPlayer = level.getNearestPlayer(d, y, d1, -1.0, level.purpurConfig.mobSpawningIgnoreCreativePlayers); // Purpur - mob spawning option to ignore creative players
if (nearestPlayer != null) {
double d2 = nearestPlayer.distanceToSqr(d, y, d1);
if (level.isLoadedAndInBounds(mutableBlockPos) && isRightDistanceToPlayerAndSpawnPoint(level, chunk, mutableBlockPos, d2)) { // Paper - don't load chunks for mob spawn

View File

@@ -1,40 +0,0 @@
--- a/net/minecraft/world/level/ServerExplosion.java
+++ b/net/minecraft/world/level/ServerExplosion.java
@@ -319,7 +_,7 @@
) {
this.level = level;
this.source = source;
- this.radius = (float) Math.max(radius, 0.0); // CraftBukkit - clamp bad values
+ this.radius = (float) (level == null || level.purpurConfig.explosionClampRadius ? Math.max(radius, 0.0) : radius); // CraftBukkit - clamp bad values // Purpur - Config to remove explosion radius clamp
this.center = center;
this.fire = fire;
this.blockInteraction = blockInteraction;
@@ -649,10 +_,27 @@
public void explode() {
// CraftBukkit start
- if (this.radius < 0.1F) {
+ if ((this.level == null || this.level.purpurConfig.explosionClampRadius) && this.radius < 0.1F) { // Purpur - Config to remove explosion radius clamp
return;
}
// CraftBukkit end
+ // Purpur start - add PreExplodeEvents
+ if (this.source != null) {
+ Location location = new Location(this.level.getWorld(), this.center.x, this.center.y, this.center.z);
+ if(!new org.purpurmc.purpur.event.entity.PreEntityExplodeEvent(this.source.getBukkitEntity(), location, this.blockInteraction == Explosion.BlockInteraction.DESTROY_WITH_DECAY ? 1.0F / this.radius : 1.0F, org.bukkit.craftbukkit.CraftExplosionResult.toBukkit(getBlockInteraction())).callEvent()) {
+ this.wasCanceled = true;
+ return;
+ }
+ } else {
+ Location location = new Location(this.level.getWorld(), this.center.x, this.center.y, this.center.z);
+ org.bukkit.block.Block block = location.getBlock();
+ org.bukkit.block.BlockState blockState = (this.damageSource.causingBlockSnapshot() != null) ? this.damageSource.causingBlockSnapshot() : block.getState();
+ if(!new org.purpurmc.purpur.event.PreBlockExplodeEvent(location.getBlock(), this.blockInteraction == Explosion.BlockInteraction.DESTROY_WITH_DECAY ? 1.0F / this.radius : 1.0F, blockState, org.bukkit.craftbukkit.CraftExplosionResult.toBukkit(getBlockInteraction())).callEvent()) {
+ this.wasCanceled = true;
+ return;
+ }
+ }
+ // Purpur end - Add PreExplodeEvents
// Paper start - collision optimisations
this.blockCache = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>();
this.chunkPosCache = new long[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];

View File

@@ -1,56 +0,0 @@
--- a/net/minecraft/world/level/block/AnvilBlock.java
+++ b/net/minecraft/world/level/block/AnvilBlock.java
@@ -59,6 +_,53 @@
return this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getClockWise());
}
+ // Purpur start - Anvil repair/damage options
+ @Override
+ protected net.minecraft.world.InteractionResult useItemOn(final net.minecraft.world.item.ItemStack stack, final BlockState state, final Level world, final BlockPos pos, final Player player, final net.minecraft.world.InteractionHand hand, final BlockHitResult hit) {
+ if (world.purpurConfig.anvilRepairIngotsAmount > 0 && stack.is(net.minecraft.world.item.Items.IRON_INGOT)) {
+ if (stack.getCount() < world.purpurConfig.anvilRepairIngotsAmount) {
+ // not enough iron ingots, play "error" sound and consume
+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F);
+ return net.minecraft.world.InteractionResult.CONSUME;
+ }
+ if (state.is(Blocks.DAMAGED_ANVIL)) {
+ world.setBlock(pos, Blocks.CHIPPED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3);
+ } else if (state.is(Blocks.CHIPPED_ANVIL)) {
+ world.setBlock(pos, Blocks.ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3);
+ } else if (state.is(Blocks.ANVIL)) {
+ // anvil is already fully repaired, play "error" sound and consume
+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F);
+ return net.minecraft.world.InteractionResult.CONSUME;
+ }
+ if (!player.getAbilities().instabuild) {
+ stack.shrink(world.purpurConfig.anvilRepairIngotsAmount);
+ }
+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_PLACE, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F);
+ return net.minecraft.world.InteractionResult.CONSUME;
+ }
+ if (world.purpurConfig.anvilDamageObsidianAmount > 0 && stack.is(net.minecraft.world.item.Items.OBSIDIAN)) {
+ if (stack.getCount() < world.purpurConfig.anvilDamageObsidianAmount) {
+ // not enough obsidian, play "error" sound and consume
+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_HIT, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F);
+ return net.minecraft.world.InteractionResult.CONSUME;
+ }
+ if (state.is(Blocks.DAMAGED_ANVIL)) {
+ world.destroyBlock(pos, false);
+ } else if (state.is(Blocks.CHIPPED_ANVIL)) {
+ world.setBlock(pos, Blocks.DAMAGED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3);
+ } else if (state.is(Blocks.ANVIL)) {
+ world.setBlock(pos, Blocks.CHIPPED_ANVIL.defaultBlockState().setValue(FACING, state.getValue(FACING)), 3);
+ }
+ if (!player.getAbilities().instabuild) {
+ stack.shrink(world.purpurConfig.anvilDamageObsidianAmount);
+ }
+ world.playSound(null, pos, net.minecraft.sounds.SoundEvents.ANVIL_LAND, net.minecraft.sounds.SoundSource.BLOCKS, 1.0F, 1.0F);
+ return net.minecraft.world.InteractionResult.CONSUME;
+ }
+ return net.minecraft.world.InteractionResult.TRY_WITH_EMPTY_HAND;
+ }
+ // Purpur end - Anvil repair/damage options
+
@Override
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) {
if (!level.isClientSide) {

View File

@@ -1,23 +0,0 @@
--- a/net/minecraft/world/level/block/AzaleaBlock.java
+++ b/net/minecraft/world/level/block/AzaleaBlock.java
@@ -50,6 +_,20 @@
@Override
public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) {
+ // Purpur start - Chance for azalea blocks to grow into trees naturally
+ growTree(level, random, pos, state);
+ }
+
+ @Override
+ public void randomTick(net.minecraft.world.level.block.state.BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
+ double chance = state.getBlock() == Blocks.FLOWERING_AZALEA ? world.purpurConfig.floweringAzaleaGrowthChance : world.purpurConfig.azaleaGrowthChance;
+ if (chance > 0.0D && world.getMaxLocalRawBrightness(pos.above()) > 9 && random.nextDouble() < chance) {
+ growTree(world, random, pos, state);
+ }
+ }
+
+ private void growTree(ServerLevel level, RandomSource random, BlockPos pos, net.minecraft.world.level.block.state.BlockState state) {
+ // Purpur end - Chance for azalea blocks to grow into trees naturally
TreeGrower.AZALEA.growTree(level, level.getChunkSource().getGenerator(), pos, state, random);
}

View File

@@ -1,10 +0,0 @@
--- a/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java
+++ b/net/minecraft/world/level/block/BaseCoralPlantTypeBlock.java
@@ -39,6 +_,7 @@
}
protected static boolean scanForWater(BlockState state, BlockGetter level, BlockPos pos) {
+ if (!((net.minecraft.world.level.LevelAccessor) level).getMinecraftWorld().purpurConfig.coralDieOutsideWater) return true; // Purpur - Config to not let coral die
if (state.getValue(WATERLOGGED)) {
return true;
} else {

View File

@@ -1,29 +0,0 @@
--- a/net/minecraft/world/level/block/BedBlock.java
+++ b/net/minecraft/world/level/block/BedBlock.java
@@ -100,7 +_,7 @@
}
Vec3 center = pos.getCenter();
- level.explode(null, level.damageSources().badRespawnPointExplosion(center), null, center, 5.0F, true, Level.ExplosionInteraction.BLOCK);
+ if (level.purpurConfig.bedExplode) level.explode(null, level.damageSources().badRespawnPointExplosion(center), null, center, (float) level.purpurConfig.bedExplosionPower, level.purpurConfig.bedExplosionFire, level.purpurConfig.bedExplosionEffect); // Purpur - Implement bed explosion options
return InteractionResult.SUCCESS_SERVER;
} else if (state.getValue(OCCUPIED)) {
if (!BedBlock.canSetSpawn(level)) return this.explodeBed(state, level, pos); // Paper - check explode first
@@ -148,7 +_,7 @@
}
Vec3 center = pos.getCenter();
- level.explode(null, level.damageSources().badRespawnPointExplosion(center).causingBlockSnapshot(blockState), null, center, 5.0F, true, Level.ExplosionInteraction.BLOCK); // CraftBukkit - add state
+ if (level.purpurConfig.bedExplode) level.explode(null, level.damageSources().badRespawnPointExplosion(center).causingBlockSnapshot(blockState), null, center, (float) level.purpurConfig.bedExplosionPower, level.purpurConfig.bedExplosionFire, level.purpurConfig.bedExplosionEffect); // CraftBukkit - add state // Purpur - Implement bed explosion options
return InteractionResult.SUCCESS_SERVER;
}
// CraftBukkit end
@@ -169,7 +_,7 @@
@Override
public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
- super.fallOn(level, state, pos, entity, fallDistance * 0.5F);
+ super.fallOn(level, state, pos, entity, fallDistance); // Purpur - Configurable block fall damage modifiers
}
@Override

View File

@@ -1,11 +0,0 @@
--- a/net/minecraft/world/level/block/BigDripleafBlock.java
+++ b/net/minecraft/world/level/block/BigDripleafBlock.java
@@ -261,7 +_,7 @@
playTiltSound(level, pos, sound);
}
- int _int = DELAY_UNTIL_NEXT_TILT_STATE.getInt(tilt);
+ int _int = level.purpurConfig.bigDripleafTiltDelay.getOrDefault(tilt, -1); // Purpur - Big dripleaf tilt delay
if (_int != -1) {
level.scheduleTick(pos, this, _int);
}

View File

@@ -1,89 +0,0 @@
--- a/net/minecraft/world/level/block/Block.java
+++ b/net/minecraft/world/level/block/Block.java
@@ -90,6 +_,10 @@
public static final int UPDATE_LIMIT = 512;
protected final StateDefinition<Block, BlockState> stateDefinition;
private BlockState defaultBlockState;
+ // Purpur start - Configurable block fall damage modifiers
+ public float fallDamageMultiplier = 1.0F;
+ public float fallDistanceMultiplier = 1.0F;
+ // Purpur end - Configurable block fall damage modifiers
// Paper start - Protect Bedrock and End Portal/Frames from being destroyed
public final boolean isDestroyable() {
return io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.allowPermanentBlockBreakExploits ||
@@ -299,7 +_,7 @@
event.setExpToDrop(block.getExpDrop(state, serverLevel, pos, net.minecraft.world.item.ItemStack.EMPTY, true)); // Paper - Properly handle xp dropping
event.callEvent();
for (org.bukkit.inventory.ItemStack drop : event.getDrops()) {
- popResource(serverLevel, pos, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(drop));
+ popResource(serverLevel, pos, applyLoreFromTile(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(drop), blockEntity)); // Purpur - Persistent BlockEntity Lore and DisplayName
}
state.spawnAfterBreak(serverLevel, pos, ItemStack.EMPTY, false); // Paper - Properly handle xp dropping
block.popExperience(serverLevel, pos, event.getExpToDrop()); // Paper - Properly handle xp dropping
@@ -317,7 +_,7 @@
public static void dropResources(BlockState state, LevelAccessor level, BlockPos pos, @Nullable BlockEntity blockEntity) {
if (level instanceof ServerLevel) {
- getDrops(state, (ServerLevel)level, pos, blockEntity).forEach(itemStack -> popResource((ServerLevel)level, pos, itemStack));
+ getDrops(state, (ServerLevel)level, pos, blockEntity).forEach(itemStack -> popResource((ServerLevel)level, pos, applyLoreFromTile(itemStack, blockEntity))); // Purpur - Persistent BlockEntity Lore and DisplayName
state.spawnAfterBreak((ServerLevel)level, pos, ItemStack.EMPTY, true);
}
}
@@ -329,11 +_,30 @@
public static void dropResources(BlockState state, Level level, BlockPos pos, @Nullable BlockEntity blockEntity, @Nullable Entity entity, ItemStack tool, boolean dropExperience) {
// Paper end - Properly handle xp dropping
if (level instanceof ServerLevel) {
- getDrops(state, (ServerLevel)level, pos, blockEntity, entity, tool).forEach(itemStack -> popResource(level, pos, itemStack));
+ getDrops(state, (ServerLevel)level, pos, blockEntity, entity, tool).forEach(itemStack -> popResource(level, pos, applyLoreFromTile(itemStack, blockEntity))); // Purpur - Persistent BlockEntity Lore and DisplayName
state.spawnAfterBreak((ServerLevel) level, pos, tool, dropExperience); // Paper - Properly handle xp dropping
}
}
+ // Purpur start - Persistent BlockEntity Lore and DisplayName
+ private static ItemStack applyLoreFromTile(ItemStack stack, @Nullable BlockEntity blockEntity) {
+ if (stack.getItem() instanceof BlockItem) {
+ if (blockEntity != null && blockEntity.getLevel() instanceof ServerLevel) {
+ net.minecraft.world.item.component.ItemLore lore = blockEntity.getPersistentLore();
+ net.minecraft.core.component.DataComponentPatch.Builder builder = net.minecraft.core.component.DataComponentPatch.builder();
+ if (blockEntity.getLevel().purpurConfig.persistentTileEntityLore && lore != null) {
+ builder.set(net.minecraft.core.component.DataComponents.LORE, lore);
+ }
+ if (!blockEntity.getLevel().purpurConfig.persistentTileEntityDisplayName) {
+ builder.remove(net.minecraft.core.component.DataComponents.CUSTOM_NAME);
+ }
+ stack.applyComponents(builder.build());
+ }
+ }
+ return stack;
+ }
+ // Purpur end - Persistent BlockEntity Lore and DisplayName
+
public static void popResource(Level level, BlockPos pos, ItemStack stack) {
double d = EntityType.ITEM.getHeight() / 2.0;
double d1 = pos.getX() + 0.5 + Mth.nextDouble(level.random, -0.25, 0.25);
@@ -412,7 +_,15 @@
}
public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) {
- }
+ this.placer = placer; // Purpur - Store placer on Block when placed
+ }
+
+ // Purpur start - Store placer on Block when placed
+ @Nullable protected LivingEntity placer = null;
+ public void forgetPlacer() {
+ this.placer = null;
+ }
+ // Purpur end - Store placer on Block when placed
public boolean isPossibleToRespawnInThis(BlockState state) {
return !state.isSolid() && !state.liquid();
@@ -423,7 +_,7 @@
}
public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
- entity.causeFallDamage(fallDistance, 1.0F, entity.damageSources().fall());
+ entity.causeFallDamage(fallDistance * fallDistanceMultiplier, fallDamageMultiplier, entity.damageSources().fall()); // Purpur - Configurable block fall damage modifiers
}
public void updateEntityMovementAfterFallOn(BlockGetter level, Entity entity) {

View File

@@ -1,18 +0,0 @@
--- a/net/minecraft/world/level/block/Blocks.java
+++ b/net/minecraft/world/level/block/Blocks.java
@@ -6486,6 +_,7 @@
BlockBehaviour.Properties.of()
.mapColor(MapColor.PLANT)
.forceSolidOff()
+ .randomTicks() // Purpur - Chance for azalea blocks to grow into trees naturally
.instabreak()
.sound(SoundType.AZALEA)
.noOcclusion()
@@ -6497,6 +_,7 @@
BlockBehaviour.Properties.of()
.mapColor(MapColor.PLANT)
.forceSolidOff()
+ .randomTicks() // Purpur - Chance for azalea blocks to grow into trees naturally
.instabreak()
.sound(SoundType.FLOWERING_AZALEA)
.noOcclusion()

View File

@@ -1,15 +0,0 @@
--- a/net/minecraft/world/level/block/BubbleColumnBlock.java
+++ b/net/minecraft/world/level/block/BubbleColumnBlock.java
@@ -124,10 +_,10 @@
if (blockState.is(Blocks.BUBBLE_COLUMN)) {
return blockState;
} else if (blockState.is(Blocks.SOUL_SAND)) {
- return Blocks.BUBBLE_COLUMN.defaultBlockState().setValue(DRAG_DOWN, Boolean.valueOf(false));
+ return Blocks.BUBBLE_COLUMN.defaultBlockState().setValue(DRAG_DOWN, Boolean.valueOf(org.purpurmc.purpur.PurpurConfig.soulSandBlockReverseBubbleColumnFlow)); // Purpur - Config to reverse bubble column flow
} else {
return blockState.is(Blocks.MAGMA_BLOCK)
- ? Blocks.BUBBLE_COLUMN.defaultBlockState().setValue(DRAG_DOWN, Boolean.valueOf(true))
+ ? Blocks.BUBBLE_COLUMN.defaultBlockState().setValue(DRAG_DOWN, Boolean.valueOf(!org.purpurmc.purpur.PurpurConfig.magmaBlockReverseBubbleColumnFlow)) // Purpur - Config to reverse bubble column flow
: Blocks.WATER.defaultBlockState();
}
}

View File

@@ -1,27 +0,0 @@
--- a/net/minecraft/world/level/block/BushBlock.java
+++ b/net/minecraft/world/level/block/BushBlock.java
@@ -61,4 +_,24 @@
protected boolean isPathfindable(BlockState state, PathComputationType pathComputationType) {
return pathComputationType == PathComputationType.AIR && !this.hasCollision || super.isPathfindable(state, pathComputationType);
}
+
+ // Purpur start - Ability for hoe to replant crops
+ public void playerDestroyAndReplant(net.minecraft.world.level.Level world, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @javax.annotation.Nullable net.minecraft.world.level.block.entity.BlockEntity blockEntity, net.minecraft.world.item.ItemStack itemInHand, net.minecraft.world.level.ItemLike itemToReplant) {
+ player.awardStat(net.minecraft.stats.Stats.BLOCK_MINED.get(this));
+ player.causeFoodExhaustion(0.005F, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.BLOCK_MINED);
+ java.util.List<net.minecraft.world.item.ItemStack> dropList = Block.getDrops(state, (net.minecraft.server.level.ServerLevel) world, pos, blockEntity, player, itemInHand);
+
+ boolean planted = false;
+ for (net.minecraft.world.item.ItemStack itemToDrop : dropList) {
+ if (!planted && itemToDrop.getItem() == itemToReplant) {
+ world.setBlock(pos, defaultBlockState(), 3);
+ itemToDrop.setCount(itemToDrop.getCount() - 1);
+ planted = true;
+ }
+ Block.popResource(world, pos, itemToDrop);
+ }
+
+ state.spawnAfterBreak((net.minecraft.server.level.ServerLevel) world, pos, itemInHand, true);
+ }
+ // Purpur end - Ability for hoe to replant crops
}

View File

@@ -1,55 +0,0 @@
--- a/net/minecraft/world/level/block/CactusBlock.java
+++ b/net/minecraft/world/level/block/CactusBlock.java
@@ -21,7 +_,7 @@
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
-public class CactusBlock extends Block {
+public class CactusBlock extends Block implements BonemealableBlock { // Purpur - bonemealable cactus
public static final MapCodec<CactusBlock> CODEC = simpleCodec(CactusBlock::new);
public static final IntegerProperty AGE = BlockStateProperties.AGE_15;
public static final int MAX_AGE = 15;
@@ -104,7 +_,7 @@
protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
for (Direction direction : Direction.Plane.HORIZONTAL) {
BlockState blockState = level.getBlockState(pos.relative(direction));
- if (blockState.isSolid() || level.getFluidState(pos.relative(direction)).is(FluidTags.LAVA)) {
+ if ((level.getWorldBorder().world.purpurConfig.cactusBreaksFromSolidNeighbors && blockState.isSolid()) || level.getFluidState(pos.relative(direction)).is(FluidTags.LAVA)) { // Purpur - Cactus breaks from solid neighbors config
return false;
}
}
@@ -128,4 +_,34 @@
protected boolean isPathfindable(BlockState state, PathComputationType pathComputationType) {
return false;
}
+
+ // Purpur start - bonemealable cactus
+ @Override
+ public boolean isValidBonemealTarget(final LevelReader world, final BlockPos pos, final BlockState state) {
+ if (!((Level) world).purpurConfig.cactusAffectedByBonemeal || !world.isEmptyBlock(pos.above())) return false;
+
+ int cactusHeight = 0;
+ while (world.getBlockState(pos.below(cactusHeight)).is(this)) {
+ cactusHeight++;
+ }
+
+ return cactusHeight < ((Level) world).paperConfig().maxGrowthHeight.cactus;
+ }
+
+ @Override
+ public boolean isBonemealSuccess(Level world, RandomSource random, BlockPos pos, BlockState state) {
+ return true;
+ }
+
+ @Override
+ public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) {
+ int cactusHeight = 0;
+ while (world.getBlockState(pos.below(cactusHeight)).is(this)) {
+ cactusHeight++;
+ }
+ for (int i = 0; i <= world.paperConfig().maxGrowthHeight.cactus - cactusHeight; i++) {
+ world.setBlockAndUpdate(pos.above(i), state.setValue(CactusBlock.AGE, 0));
+ }
+ }
+ // Purpur end - bonemealable cactus
}

View File

@@ -1,10 +0,0 @@
--- a/net/minecraft/world/level/block/CakeBlock.java
+++ b/net/minecraft/world/level/block/CakeBlock.java
@@ -119,6 +_,7 @@
org.bukkit.event.entity.FoodLevelChangeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callFoodLevelChangeEvent(player, 2 + oldFoodLevel);
if (!event.isCancelled()) {
+ if (player.level().purpurConfig.playerBurpWhenFull && event.getFoodLevel() == 20 && oldFoodLevel < 20) player.burpDelay = player.level().purpurConfig.playerBurpDelay; // Purpur - Burp after eating food fills hunger bar completely
player.getFoodData().eat(event.getFoodLevel() - oldFoodLevel, 0.1F);
}

View File

@@ -1,11 +0,0 @@
--- a/net/minecraft/world/level/block/CampfireBlock.java
+++ b/net/minecraft/world/level/block/CampfireBlock.java
@@ -141,7 +_,7 @@
return this.defaultBlockState()
.setValue(WATERLOGGED, Boolean.valueOf(flag))
.setValue(SIGNAL_FIRE, Boolean.valueOf(this.isSmokeSource(level.getBlockState(clickedPos.below()))))
- .setValue(LIT, Boolean.valueOf(!flag))
+ .setValue(LIT, Boolean.valueOf(level.getMinecraftWorld().purpurConfig.campFireLitWhenPlaced && !flag)) // Purpur - Campfire option for lit when placed
.setValue(FACING, context.getHorizontalDirection());
}

View File

@@ -1,36 +0,0 @@
--- a/net/minecraft/world/level/block/CarvedPumpkinBlock.java
+++ b/net/minecraft/world/level/block/CarvedPumpkinBlock.java
@@ -64,7 +_,7 @@
if (blockPatternMatch != null) {
SnowGolem snowGolem = EntityType.SNOW_GOLEM.create(level, EntitySpawnReason.TRIGGERED);
if (snowGolem != null) {
- spawnGolemInWorld(level, blockPatternMatch, snowGolem, blockPatternMatch.getBlock(0, 2, 0).getPos());
+ spawnGolemInWorld(level, blockPatternMatch, snowGolem, blockPatternMatch.getBlock(0, 2, 0).getPos(), this.placer); // Purpur - Summoner API
}
} else {
BlockPattern.BlockPatternMatch blockPatternMatch1 = this.getOrCreateIronGolemFull().find(level, pos);
@@ -72,13 +_,23 @@
IronGolem ironGolem = EntityType.IRON_GOLEM.create(level, EntitySpawnReason.TRIGGERED);
if (ironGolem != null) {
ironGolem.setPlayerCreated(true);
- spawnGolemInWorld(level, blockPatternMatch1, ironGolem, blockPatternMatch1.getBlock(1, 2, 0).getPos());
+ spawnGolemInWorld(level, blockPatternMatch1, ironGolem, blockPatternMatch1.getBlock(1, 2, 0).getPos(), this.placer); // Purpur - Summoner API
}
}
}
}
private static void spawnGolemInWorld(Level level, BlockPattern.BlockPatternMatch patternMatch, Entity golem, BlockPos pos) {
+ // Purpur start - Summoner API
+ spawnGolemInWorld(level, patternMatch, golem, pos, null);
+ }
+ private static void spawnGolemInWorld(Level level, BlockPattern.BlockPatternMatch patternMatch, Entity golem, BlockPos pos, net.minecraft.world.entity.LivingEntity placer) {
+ if (golem instanceof SnowGolem snowGolem) {
+ snowGolem.setSummoner(placer == null ? null : placer.getUUID());
+ } else if (golem instanceof IronGolem ironGolem) {
+ ironGolem.setSummoner(placer == null ? null : placer.getUUID());
+ }
+ // Purpur end - Summoner API
// clearPatternBlocks(level, patternMatch); // CraftBukkit - moved down
golem.moveTo(pos.getX() + 0.5, pos.getY() + 0.05, pos.getZ() + 0.5, 0.0F, 0.0F);
if (!level.addFreshEntity(golem, (golem.getType() == EntityType.SNOW_GOLEM) ? org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BUILD_SNOWMAN : org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BUILD_IRONGOLEM)) {

View File

@@ -1,13 +0,0 @@
--- a/net/minecraft/world/level/block/CauldronBlock.java
+++ b/net/minecraft/world/level/block/CauldronBlock.java
@@ -32,8 +_,8 @@
protected static boolean shouldHandlePrecipitation(Level level, Biome.Precipitation precipitation) {
return precipitation == Biome.Precipitation.RAIN
- ? level.getRandom().nextFloat() < 0.05F
- : precipitation == Biome.Precipitation.SNOW && level.getRandom().nextFloat() < 0.1F;
+ ? level.getRandom().nextFloat() < level.purpurConfig.cauldronRainChance // Purpur - Cauldron fill chances
+ : precipitation == Biome.Precipitation.SNOW && level.getRandom().nextFloat() < level.purpurConfig.cauldronPowderSnowChance; // Purpur - Cauldron fill chances
}
@Override

View File

@@ -1,14 +0,0 @@
--- a/net/minecraft/world/level/block/CaveVinesBlock.java
+++ b/net/minecraft/world/level/block/CaveVinesBlock.java
@@ -92,4 +_,11 @@
public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) {
level.setBlock(pos, state.setValue(BERRIES, Boolean.valueOf(true)), 2);
}
+
+ // Purpur start - cave vines configurable max growth age
+ @Override
+ public int getMaxGrowthAge() {
+ return org.purpurmc.purpur.PurpurConfig.caveVinesMaxGrowthAge;
+ }
+ // Purpur end - cave vines configurable max growth age
}

View File

@@ -1,11 +0,0 @@
--- a/net/minecraft/world/level/block/ChangeOverTimeBlock.java
+++ b/net/minecraft/world/level/block/ChangeOverTimeBlock.java
@@ -51,7 +_,7 @@
}
float f = (float)(i1 + 1) / (i1 + i + 1);
- float f1 = f * f * this.getChanceModifier();
+ float f1 = level.purpurConfig.disableOxidationProximityPenalty ? this.getChanceModifier() :f * f * this.getChanceModifier();// Purpur - option to disable the copper oxidation proximity penalty
return random.nextFloat() < f1 ? this.getNext(state) : Optional.empty();
}
}

View File

@@ -1,10 +0,0 @@
--- a/net/minecraft/world/level/block/ChestBlock.java
+++ b/net/minecraft/world/level/block/ChestBlock.java
@@ -357,6 +_,7 @@
}
public static boolean isBlockedChestByBlock(BlockGetter level, BlockPos pos) {
+ if (level instanceof Level level1 && level1.purpurConfig.chestOpenWithBlockOnTop) return false; // Purpur - Option for chests to open even with a solid block on top
BlockPos blockPos = pos.above();
return level.getBlockState(blockPos).isRedstoneConductor(level, blockPos);
}

View File

@@ -1,66 +0,0 @@
--- a/net/minecraft/world/level/block/ComposterBlock.java
+++ b/net/minecraft/world/level/block/ComposterBlock.java
@@ -241,23 +_,52 @@
) {
int levelValue = state.getValue(LEVEL);
if (levelValue < 8 && COMPOSTABLES.containsKey(stack.getItem())) {
- if (levelValue < 7 && !level.isClientSide) {
- BlockState blockState = addItem(player, state, level, pos, stack);
- // Paper start - handle cancelled events
- if (blockState == null) {
- return InteractionResult.PASS;
- }
- // Paper end
- level.levelEvent(1500, pos, state != blockState ? 1 : 0);
- player.awardStat(Stats.ITEM_USED.get(stack.getItem()));
- stack.consume(1, player);
- }
+ // Purpur start - sneak to bulk process composter
+ BlockState newState = process(levelValue, player, state, level, pos, stack);
+ if (newState == null) {
+ return InteractionResult.PASS;
+ }
+ if (level.purpurConfig.composterBulkProcess && player.isShiftKeyDown() && newState != state) {
+ BlockState oldState;
+ int oldCount, newCount, oldLevel, newLevel;
+ do {
+ oldState = newState;
+ oldCount = stack.getCount();
+ oldLevel = oldState.getValue(ComposterBlock.LEVEL);
+ newState = process(oldLevel, player, oldState, level, pos, stack);
+ if (newState == null) {
+ return InteractionResult.PASS;
+ }
+ newCount = stack.getCount();
+ newLevel = newState.getValue(ComposterBlock.LEVEL);
+ } while (newCount > 0 && (newCount != oldCount || newLevel != oldLevel || newState != oldState));
+ }
+ // Purpur end - Sneak to bulk process composter
return InteractionResult.SUCCESS;
} else {
return super.useItemOn(stack, state, level, pos, player, hand, hitResult);
}
}
+
+ // Purpur start - sneak to bulk process composter
+ private static @Nullable BlockState process(int levelValue, Player player, BlockState state, Level level, BlockPos pos, ItemStack stack) {
+ if (levelValue < 7 && !level.isClientSide) {
+ BlockState iblockdata1 = ComposterBlock.addItem(player, state, level, pos, stack);
+ // Paper start - handle cancelled events
+ if (iblockdata1 == null) {
+ return null;
+ }
+ // Paper end
+
+ level.levelEvent(1500, pos, state != iblockdata1 ? 1 : 0);
+ player.awardStat(Stats.ITEM_USED.get(stack.getItem()));
+ stack.consume(1, player);
+ return iblockdata1;
+ }
+ return state;
+ }
+ // Purpur end - Sneak to bulk process composter
@Override
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) {

View File

@@ -1,10 +0,0 @@
--- a/net/minecraft/world/level/block/CoralBlock.java
+++ b/net/minecraft/world/level/block/CoralBlock.java
@@ -65,6 +_,7 @@
}
protected boolean scanForWater(BlockGetter level, BlockPos pos) {
+ if (!((net.minecraft.world.level.LevelAccessor) level).getMinecraftWorld().purpurConfig.coralDieOutsideWater) return true; // Purpur - Config to not let coral die
for (Direction direction : Direction.values()) {
FluidState fluidState = level.getFluidState(pos.relative(direction));
if (fluidState.is(FluidTags.WATER)) {

View File

@@ -1,27 +0,0 @@
--- a/net/minecraft/world/level/block/CropBlock.java
+++ b/net/minecraft/world/level/block/CropBlock.java
@@ -182,7 +_,7 @@
@Override
protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) {
if (!new io.papermc.paper.event.entity.EntityInsideBlockEvent(entity.getBukkitEntity(), org.bukkit.craftbukkit.block.CraftBlock.at(level, pos)).callEvent()) { return; } // Paper - Add EntityInsideBlockEvent
- if (level instanceof ServerLevel serverLevel && entity instanceof Ravager && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit
+ if (level instanceof ServerLevel serverLevel && entity instanceof Ravager && serverLevel.purpurConfig.ravagerGriefableBlocks.contains(serverLevel.getBlockState(pos).getBlock()) && org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.AIR.defaultBlockState(), !serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))) { // CraftBukkit // Purpur - Configurable ravager griefable blocks list
serverLevel.destroyBlock(pos, true, entity);
}
@@ -217,4 +_,15 @@
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(AGE);
}
+
+ // Purpur start - Ability for hoe to replant crops
+ @Override
+ public void playerDestroy(Level world, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @javax.annotation.Nullable net.minecraft.world.level.block.entity.BlockEntity blockEntity, ItemStack itemInHand, boolean includeDrops, boolean dropExp) {
+ if (world.purpurConfig.hoeReplantsCrops && itemInHand.getItem() instanceof net.minecraft.world.item.HoeItem) {
+ super.playerDestroyAndReplant(world, player, pos, state, blockEntity, itemInHand, getBaseSeedId());
+ } else {
+ super.playerDestroy(world, player, pos, state, blockEntity, itemInHand, includeDrops, dropExp);
+ }
+ }
+ // Purpur end - Ability for hoe to replant crops
}

View File

@@ -1,29 +0,0 @@
--- a/net/minecraft/world/level/block/DoorBlock.java
+++ b/net/minecraft/world/level/block/DoorBlock.java
@@ -206,6 +_,7 @@
protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) {
if (!this.type.canOpenByHand()) {
return InteractionResult.PASS;
+ } else if (requiresRedstone(level, state, pos)) { return InteractionResult.CONSUME; // Purpur - Option to make doors require redstone
} else {
state = state.cycle(OPEN);
level.setBlock(pos, state, 10);
@@ -294,4 +_,18 @@
public static boolean isWoodenDoor(BlockState state) {
return state.getBlock() instanceof DoorBlock doorBlock && doorBlock.type().canOpenByHand();
}
+
+ // Purpur start - Option to make doors require redstone
+ public static boolean requiresRedstone(Level level, BlockState state, BlockPos pos) {
+ if (level.purpurConfig.doorRequiresRedstone.contains(state.getBlock())) {
+ // force update client
+ BlockPos otherPos = pos.relative(state.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER ? Direction.UP : Direction.DOWN);
+ BlockState otherState = level.getBlockState(otherPos);
+ level.sendBlockUpdated(pos, state, state, 3);
+ level.sendBlockUpdated(otherPos, otherState, otherState, 3);
+ return true;
+ }
+ return false;
+ }
+ // Purpur end - Option to make doors require redstone
}

View File

@@ -1,10 +0,0 @@
--- a/net/minecraft/world/level/block/DragonEggBlock.java
+++ b/net/minecraft/world/level/block/DragonEggBlock.java
@@ -46,6 +_,7 @@
}
private void teleport(BlockState state, Level level, BlockPos pos) {
+ if (!level.purpurConfig.dragonEggTeleport) return; // Purpur - Option to disable dragon egg teleporting
WorldBorder worldBorder = level.getWorldBorder();
for (int i = 0; i < 1000; i++) {

View File

@@ -1,21 +0,0 @@
--- a/net/minecraft/world/level/block/EnchantingTableBlock.java
+++ b/net/minecraft/world/level/block/EnchantingTableBlock.java
@@ -119,4 +_,18 @@
protected boolean isPathfindable(BlockState state, PathComputationType pathComputationType) {
return false;
}
+
+ // Purpur start - Enchantment Table Persists Lapis
+ @Override
+ public void onRemove(BlockState state, Level level, BlockPos pos, BlockState newState, boolean moved) {
+ BlockEntity blockEntity = level.getBlockEntity(pos);
+
+ if (level.purpurConfig.enchantmentTableLapisPersists && blockEntity instanceof EnchantingTableBlockEntity enchantmentTable) {
+ net.minecraft.world.Containers.dropItemStack(level, pos.getX(), pos.getY(), pos.getZ(), new net.minecraft.world.item.ItemStack(net.minecraft.world.item.Items.LAPIS_LAZULI, enchantmentTable.getLapis()));
+ level.updateNeighbourForOutputSignal(pos, this);
+ }
+
+ super.onRemove(state, level, pos, newState, moved);
+ }
+ // Purpur end - Enchantment Table Persists Lapis
}

View File

@@ -1,48 +0,0 @@
--- a/net/minecraft/world/level/block/FarmBlock.java
+++ b/net/minecraft/world/level/block/FarmBlock.java
@@ -112,7 +_,7 @@
public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
super.fallOn(level, state, pos, entity, fallDistance); // CraftBukkit - moved here as game rules / events shouldn't affect fall damage.
if (level instanceof ServerLevel serverLevel
- && level.random.nextFloat() < fallDistance - 0.5F
+ && (serverLevel.purpurConfig.farmlandTrampleHeight >= 0D ? fallDistance >= serverLevel.purpurConfig.farmlandTrampleHeight : level.random.nextFloat() < fallDistance - 0.5F) // // Purpur - Configurable farmland trample height
&& entity instanceof LivingEntity
&& (entity instanceof Player || serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING))
&& entity.getBbWidth() * entity.getBbWidth() * entity.getBbHeight() > 0.512F) {
@@ -129,6 +_,27 @@
return;
}
+ if (level.purpurConfig.farmlandTramplingDisabled) return; // Purpur - Farmland trampling changes
+ if (level.purpurConfig.farmlandTramplingOnlyPlayers && !(entity instanceof Player)) return; // Purpur - Farmland trampling changes
+
+ // Purpur start - Ability to re-add farmland mechanics from Alpha
+ if (level.purpurConfig.farmlandAlpha) {
+ Block block = level.getBlockState(pos.below()).getBlock();
+ if (block instanceof FenceBlock || block instanceof WallBlock) {
+ return;
+ }
+ }
+ // Purpur end - Ability to re-add farmland mechanics from Alpha
+
+ // Purpur start - Farmland trampling changes
+ if (level.purpurConfig.farmlandTramplingFeatherFalling) {
+ java.util.Iterator<net.minecraft.world.item.ItemStack> armor = ((LivingEntity) entity).getArmorSlots().iterator();
+ if (armor.hasNext() && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.FEATHER_FALLING, armor.next()) >= (int) entity.fallDistance) {
+ return;
+ }
+ }
+ // Purpur end - Farmland trampling changes
+
if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(entity, pos, Blocks.DIRT.defaultBlockState())) {
return;
}
@@ -177,7 +_,7 @@
}
}
- return false;
+ return ((ServerLevel) level).purpurConfig.farmlandGetsMoistFromBelow && level.getFluidState(pos.relative(Direction.DOWN)).is(FluidTags.WATER); // Purpur - Allow soil to moisten from water directly under it
// Paper end - Perf: remove abstract block iteration
}

View File

@@ -1,63 +0,0 @@
--- a/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
+++ b/net/minecraft/world/level/block/GrowingPlantHeadBlock.java
@@ -34,12 +_,12 @@
@Override
public BlockState getStateForPlacement(RandomSource random) {
- return this.defaultBlockState().setValue(AGE, Integer.valueOf(random.nextInt(25)));
+ return this.defaultBlockState().setValue(AGE, Integer.valueOf(random.nextInt(getMaxGrowthAge()))); // Purpur - kelp, cave, weeping, and twisting configurable max growth age
}
@Override
protected boolean isRandomlyTicking(BlockState state) {
- return state.getValue(AGE) < 25;
+ return state.getValue(AGE) < getMaxGrowthAge(); // Purpur - kelp, cave, weeping, and twisting configurable max growth age
}
@Override
@@ -55,7 +_,7 @@
} else if (this == Blocks.CAVE_VINES) {
modifier = level.spigotConfig.caveVinesModifier;
}
- if (state.getValue(AGE) < 25 && random.nextDouble() < ((modifier / 100.0D) * this.growPerTickProbability)) { // Spigot - SPIGOT-7159: Better modifier resolution
+ if (state.getValue(AGE) < getMaxGrowthAge() && random.nextDouble() < ((modifier / 100.0D) * this.growPerTickProbability)) { // Spigot - SPIGOT-7159: Better modifier resolution // Purpur - kelp, cave, weeping, and twisting configurable max growth age
// Spigot end
BlockPos blockPos = pos.relative(this.growthDirection);
if (this.canGrowInto(level.getBlockState(blockPos))) {
@@ -75,11 +_,11 @@
}
public BlockState getMaxAgeState(BlockState state) {
- return state.setValue(AGE, Integer.valueOf(25));
+ return state.setValue(AGE, Integer.valueOf(getMaxGrowthAge())); // Purpur - kelp, cave, weeping, and twisting configurable max growth age
}
public boolean isMaxAge(BlockState state) {
- return state.getValue(AGE) == 25;
+ return state.getValue(AGE) >= getMaxGrowthAge(); // Purpur - kelp, cave, weeping, and twisting configurable max growth age
}
protected BlockState updateBodyAfterConvertedFromHead(BlockState head, BlockState body) {
@@ -130,13 +_,13 @@
@Override
public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) {
BlockPos blockPos = pos.relative(this.growthDirection);
- int min = Math.min(state.getValue(AGE) + 1, 25);
+ int min = Math.min(state.getValue(AGE) + 1, getMaxGrowthAge()); // Purpur - kelp, cave, weeping, and twisting configurable max growth age
int blocksToGrowWhenBonemealed = this.getBlocksToGrowWhenBonemealed(random);
for (int i = 0; i < blocksToGrowWhenBonemealed && this.canGrowInto(level.getBlockState(blockPos)); i++) {
level.setBlockAndUpdate(blockPos, state.setValue(AGE, Integer.valueOf(min)));
blockPos = blockPos.relative(this.growthDirection);
- min = Math.min(min + 1, 25);
+ min = Math.min(min + 1, getMaxGrowthAge()); // Purpur - kelp, cave, weeping, and twisting configurable max growth age
}
}
@@ -148,4 +_,6 @@
protected GrowingPlantHeadBlock getHeadBlock() {
return this;
}
+
+ public abstract int getMaxGrowthAge(); // Purpur - kelp, cave, weeping, and twisting configurable max growth age
}

View File

@@ -1,10 +0,0 @@
--- a/net/minecraft/world/level/block/HayBlock.java
+++ b/net/minecraft/world/level/block/HayBlock.java
@@ -23,6 +_,6 @@
@Override
public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) {
- entity.causeFallDamage(fallDistance, 0.2F, level.damageSources().fall());
+ super.fallOn(level, state, pos, entity, fallDistance); // Purpur - Configurable block fall damage modifiers
}
}

View File

@@ -1,20 +0,0 @@
--- a/net/minecraft/world/level/block/IceBlock.java
+++ b/net/minecraft/world/level/block/IceBlock.java
@@ -40,7 +_,7 @@
public void afterDestroy(Level level, BlockPos pos, ItemStack stack) {
// Paper end - Improve Block#breakNaturally API
if (!EnchantmentHelper.hasTag(stack, EnchantmentTags.PREVENTS_ICE_MELTING)) {
- if (level.dimensionType().ultraWarm()) {
+ if (level.isNether() || (level.isTheEnd() && !org.purpurmc.purpur.PurpurConfig.allowWaterPlacementInTheEnd)) { // Purpur - Add allow water in end world option
level.removeBlock(pos, false);
return;
}
@@ -65,7 +_,7 @@
return;
}
// CraftBukkit end
- if (level.dimensionType().ultraWarm()) {
+ if (level.isNether() || (level.isTheEnd() && !org.purpurmc.purpur.PurpurConfig.allowWaterPlacementInTheEnd)) { // Purpur - Add allow water in end world option
level.removeBlock(pos, false);
} else {
level.setBlockAndUpdate(pos, meltsInto());

View File

@@ -1,14 +0,0 @@
--- a/net/minecraft/world/level/block/KelpBlock.java
+++ b/net/minecraft/world/level/block/KelpBlock.java
@@ -72,4 +_,11 @@
protected FluidState getFluidState(BlockState state) {
return Fluids.WATER.getSource(false);
}
+
+ // Purpur start - kelp vines configurable max growth age
+ @Override
+ public int getMaxGrowthAge() {
+ return org.purpurmc.purpur.PurpurConfig.kelpMaxGrowthAge;
+ }
+ // Purpur end - kelp vines configurable max growth age
}

View File

@@ -1,29 +0,0 @@
--- a/net/minecraft/world/level/block/LiquidBlock.java
+++ b/net/minecraft/world/level/block/LiquidBlock.java
@@ -134,7 +_,7 @@
@Override
protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean isMoving) {
- if (this.shouldSpreadLiquid(level, pos, state)) {
+ if (level.purpurConfig.tickFluids && this.shouldSpreadLiquid(level, pos, state)) { // Purpur - Tick fluids config
level.scheduleTick(pos, state.getFluidState().getType(), this.getFlowSpeed(level, pos)); // Paper - Configurable speed for water flowing over lava
}
}
@@ -169,7 +_,7 @@
BlockState neighborState,
RandomSource random
) {
- if (state.getFluidState().isSource() || neighborState.getFluidState().isSource()) {
+ if (level.getWorldBorder().world.purpurConfig.tickFluids && state.getFluidState().isSource() || neighborState.getFluidState().isSource()) { // Purpur - Tick fluids config
scheduledTickAccess.scheduleTick(pos, state.getFluidState().getType(), this.fluid.getTickDelay(level));
}
@@ -178,7 +_,7 @@
@Override
protected void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston) {
- if (this.shouldSpreadLiquid(level, pos, state)) {
+ if (level.purpurConfig.tickFluids && this.shouldSpreadLiquid(level, pos, state)) { // Purpur - Tick fluids config
level.scheduleTick(pos, state.getFluidState().getType(), this.getFlowSpeed(level, pos)); // Paper - Configurable speed for water flowing over lava
}
}

View File

@@ -1,11 +0,0 @@
--- a/net/minecraft/world/level/block/MagmaBlock.java
+++ b/net/minecraft/world/level/block/MagmaBlock.java
@@ -28,7 +_,7 @@
@Override
public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) {
- if (!entity.isSteppingCarefully() && entity instanceof LivingEntity) {
+ if ((!entity.isSteppingCarefully() || level.purpurConfig.magmaBlockDamageWhenSneaking) && entity instanceof LivingEntity) { // Purpur - Configurable damage settings for magma blocks
entity.hurt(level.damageSources().hotFloor().eventBlockDamager(level, pos), 1.0F); // CraftBukkit
}

View File

@@ -1,20 +0,0 @@
--- a/net/minecraft/world/level/block/NetherPortalBlock.java
+++ b/net/minecraft/world/level/block/NetherPortalBlock.java
@@ -72,7 +_,7 @@
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
if (level.spigotConfig.enableZombiePigmenPortalSpawns && level.dimensionType().natural() // Spigot
&& level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)
- && random.nextInt(2000) < level.getDifficulty().getId()) {
+ && random.nextInt(level.purpurConfig.piglinPortalSpawnModifier) < level.getDifficulty().getId()) { // Purpur - Piglin portal spawn modifier
while (level.getBlockState(pos).is(this)) {
pos = pos.below();
}
@@ -129,7 +_,7 @@
@Override
public int getPortalTransitionTime(ServerLevel level, Entity entity) {
return entity instanceof Player player
- ? Math.max(
+ ? player.canPortalInstant ? 1 : Math.max( // Purpur - Add portal permission bypass
0,
level.getGameRules()
.getInt(

View File

@@ -1,46 +0,0 @@
--- a/net/minecraft/world/level/block/NetherWartBlock.java
+++ b/net/minecraft/world/level/block/NetherWartBlock.java
@@ -16,7 +_,7 @@
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
-public class NetherWartBlock extends BushBlock {
+public class NetherWartBlock extends BushBlock implements BonemealableBlock { // Purpur - bonemealable netherwart
public static final MapCodec<NetherWartBlock> CODEC = simpleCodec(NetherWartBlock::new);
public static final int MAX_AGE = 3;
public static final IntegerProperty AGE = BlockStateProperties.AGE_3;
@@ -70,4 +_,34 @@
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(AGE);
}
+
+ // Purpur start - Ability for hoe to replant nether warts
+ @Override
+ public void playerDestroy(net.minecraft.world.level.Level world, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @javax.annotation.Nullable net.minecraft.world.level.block.entity.BlockEntity blockEntity, ItemStack itemInHand, boolean includeDrops, boolean dropExp) {
+ if (world.purpurConfig.hoeReplantsNetherWarts && itemInHand.getItem() instanceof net.minecraft.world.item.HoeItem) {
+ super.playerDestroyAndReplant(world, player, pos, state, blockEntity, itemInHand, Items.NETHER_WART);
+ } else {
+ super.playerDestroy(world, player, pos, state, blockEntity, itemInHand, includeDrops, dropExp);
+ }
+ }
+ // Purpur end - Ability for hoe to replant nether warts
+
+ // Purpur start - bonemealable netherwart
+ @Override
+ public boolean isValidBonemealTarget(final net.minecraft.world.level.LevelReader world, final BlockPos pos, final BlockState state) {
+ return ((net.minecraft.world.level.Level) world).purpurConfig.netherWartAffectedByBonemeal && state.getValue(NetherWartBlock.AGE) < 3;
+ }
+
+ @Override
+ public boolean isBonemealSuccess(net.minecraft.world.level.Level world, RandomSource random, BlockPos pos, BlockState state) {
+ return true;
+ }
+
+ @Override
+ public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) {
+ int i = Math.min(3, state.getValue(NetherWartBlock.AGE) + 1);
+ state = state.setValue(NetherWartBlock.AGE, i);
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(world, pos, state, 2); // CraftBukkit
+ }
+ // Purpur end - bonemealable netherwart
}

View File

@@ -1,11 +0,0 @@
--- a/net/minecraft/world/level/block/NoteBlock.java
+++ b/net/minecraft/world/level/block/NoteBlock.java
@@ -107,7 +_,7 @@
}
private void playNote(@Nullable Entity entity, BlockState state, Level level, BlockPos pos) {
- if (state.getValue(INSTRUMENT).worksAboveNoteBlock() || level.getBlockState(pos.above()).isAir()) {
+ if (level.purpurConfig.noteBlockIgnoreAbove || state.getValue(INSTRUMENT).worksAboveNoteBlock() || level.getBlockState(pos.above()).isAir()) { // Purpur - Config to allow Note Block sounds when blocked
level.blockEvent(pos, this, 0, 0);
level.gameEvent(entity, GameEvent.NOTE_BLOCK_PLAY, pos);
}

View File

@@ -1,10 +0,0 @@
--- a/net/minecraft/world/level/block/ObserverBlock.java
+++ b/net/minecraft/world/level/block/ObserverBlock.java
@@ -81,6 +_,7 @@
RandomSource random
) {
if (state.getValue(FACING) == direction && !state.getValue(POWERED)) {
+ if (!level.getWorldBorder().world.purpurConfig.disableObserverClocks || !(neighborState.getBlock() instanceof ObserverBlock) || neighborState.getValue(ObserverBlock.FACING).getOpposite() != direction) // Purpur - Add Option for disable observer clocks
this.startSignal(level, scheduledTickAccess, pos);
}

View File

@@ -1,26 +0,0 @@
--- a/net/minecraft/world/level/block/PointedDripstoneBlock.java
+++ b/net/minecraft/world/level/block/PointedDripstoneBlock.java
@@ -197,20 +_,20 @@
@VisibleForTesting
public static void maybeTransferFluid(BlockState state, ServerLevel level, BlockPos pos, float randChance) {
- if (!(randChance > 0.17578125F) || !(randChance > 0.05859375F)) {
+ if (!(randChance > level.purpurConfig.cauldronDripstoneWaterFillChance) || !(randChance > level.purpurConfig.cauldronDripstoneLavaFillChance)) { // Purpur - Cauldron fill chances
if (isStalactiteStartPos(state, level, pos)) {
Optional<PointedDripstoneBlock.FluidInfo> fluidAboveStalactite = getFluidAboveStalactite(level, pos, state);
if (!fluidAboveStalactite.isEmpty()) {
Fluid fluid = fluidAboveStalactite.get().fluid;
float f;
if (fluid == Fluids.WATER) {
- f = 0.17578125F;
+ f = level.purpurConfig.cauldronDripstoneWaterFillChance; // Purpur - Cauldron fill chances
} else {
if (fluid != Fluids.LAVA) {
return;
}
- f = 0.05859375F;
+ f = level.purpurConfig.cauldronDripstoneLavaFillChance; // Purpur - Cauldron fill chances
}
if (!(randChance >= f)) {

View File

@@ -1,11 +0,0 @@
--- a/net/minecraft/world/level/block/PoweredRailBlock.java
+++ b/net/minecraft/world/level/block/PoweredRailBlock.java
@@ -34,7 +_,7 @@
}
protected boolean findPoweredRailSignal(Level level, BlockPos pos, BlockState state, boolean searchForward, int recursionCount) {
- if (recursionCount >= 8) {
+ if (recursionCount >= level.purpurConfig.railActivationRange) { // Purpur - Config for powered rail activation distance
return false;
} else {
int x = pos.getX();

View File

@@ -1,11 +0,0 @@
--- a/net/minecraft/world/level/block/RespawnAnchorBlock.java
+++ b/net/minecraft/world/level/block/RespawnAnchorBlock.java
@@ -159,7 +_,7 @@
};
Vec3 center = pos2.getCenter();
level.explode(
- null, level.damageSources().badRespawnPointExplosion(center).causingBlockSnapshot(blockState), explosionDamageCalculator, center, 5.0F, true, Level.ExplosionInteraction.BLOCK // CraftBukkit - add state
+ null, level.damageSources().badRespawnPointExplosion(center).causingBlockSnapshot(blockState), explosionDamageCalculator, center, (float) level.purpurConfig.respawnAnchorExplosionPower, level.purpurConfig.respawnAnchorExplosionFire, level.purpurConfig.respawnAnchorExplosionEffect // CraftBukkit - add state // Purpur - Implement respawn anchor explosion options
);
}

View File

@@ -1,11 +0,0 @@
--- a/net/minecraft/world/level/block/SculkShriekerBlock.java
+++ b/net/minecraft/world/level/block/SculkShriekerBlock.java
@@ -134,7 +_,7 @@
@Override
public BlockState getStateForPlacement(BlockPlaceContext context) {
return this.defaultBlockState()
- .setValue(WATERLOGGED, Boolean.valueOf(context.getLevel().getFluidState(context.getClickedPos()).getType() == Fluids.WATER));
+ .setValue(WATERLOGGED, Boolean.valueOf(context.getLevel().getFluidState(context.getClickedPos()).getType() == Fluids.WATER)).setValue(SculkShriekerBlock.CAN_SUMMON, context.getLevel().purpurConfig.sculkShriekerCanSummonDefault); // Purpur - Config for sculk shrieker can_summon state
}
@Override

View File

@@ -1,28 +0,0 @@
--- a/net/minecraft/world/level/block/SlabBlock.java
+++ b/net/minecraft/world/level/block/SlabBlock.java
@@ -150,4 +_,25 @@
return false;
}
}
+
+ // Purpur start - Break individual slabs when sneaking
+ public boolean halfBreak(BlockState state, BlockPos pos, net.minecraft.server.level.ServerPlayer player) {
+ if (state.getValue(SlabBlock.TYPE) != SlabType.DOUBLE) {
+ return false;
+ }
+ net.minecraft.world.phys.HitResult result = player.getRayTrace(16, net.minecraft.world.level.ClipContext.Fluid.NONE);
+ if (result.getType() != net.minecraft.world.phys.HitResult.Type.BLOCK) {
+ return false;
+ }
+ double hitY = result.getLocation().y();
+ int blockY = org.bukkit.util.NumberConversions.floor(hitY);
+ player.level().setBlock(pos, state.setValue(SlabBlock.TYPE, (hitY - blockY > 0.5 || blockY - pos.getY() == 1) ? SlabType.BOTTOM : SlabType.TOP), 3);
+ if (!player.getAbilities().instabuild) {
+ net.minecraft.world.entity.item.ItemEntity item = new net.minecraft.world.entity.item.ItemEntity(player.level(), pos.getX(), pos.getY(), pos.getZ(), new ItemStack(asItem()));
+ item.setDefaultPickUpDelay();
+ player.level().addFreshEntity(item);
+ }
+ return true;
+ }
+ // Purpur end - Break individual slabs when sneaking
}

View File

@@ -1,10 +0,0 @@
--- a/net/minecraft/world/level/block/SnowLayerBlock.java
+++ b/net/minecraft/world/level/block/SnowLayerBlock.java
@@ -96,6 +_,7 @@
@Override
protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) {
BlockState blockState = level.getBlockState(pos.below());
+ if (blockState.is(Blocks.BLUE_ICE) && !level.getWorldBorder().world.purpurConfig.snowOnBlueIce) return false; // Purpur - Add config for snow on blue ice
return !blockState.is(BlockTags.SNOW_LAYER_CANNOT_SURVIVE_ON)
&& (
blockState.is(BlockTags.SNOW_LAYER_CAN_SURVIVE_ON)

View File

@@ -1,68 +0,0 @@
--- a/net/minecraft/world/level/block/SpawnerBlock.java
+++ b/net/minecraft/world/level/block/SpawnerBlock.java
@@ -43,6 +_,57 @@
);
}
+ // Purpur start - Silk touch spawners
+ @Override
+ public void playerDestroy(Level level, net.minecraft.world.entity.player.Player player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack stack, boolean includeDrops, boolean dropExp) {
+ if (level.purpurConfig.silkTouchEnabled && player.getBukkitEntity().hasPermission("purpur.drop.spawners") && isSilkTouch(level, stack)) {
+ ItemStack item = new ItemStack(Blocks.SPAWNER.asItem());
+
+ net.minecraft.world.level.SpawnData nextSpawnData = blockEntity instanceof SpawnerBlockEntity spawnerBlock ? spawnerBlock.getSpawner().nextSpawnData : null;
+ java.util.Optional<net.minecraft.world.entity.EntityType<?>> type = java.util.Optional.empty();
+ if (nextSpawnData != null) {
+ type = net.minecraft.world.entity.EntityType.by(nextSpawnData.getEntityToSpawn());
+ net.minecraft.world.level.SpawnData.CODEC.encodeStart(net.minecraft.nbt.NbtOps.INSTANCE, nextSpawnData).result().ifPresent(tag -> item.set(net.minecraft.core.component.DataComponents.CUSTOM_DATA, net.minecraft.world.item.component.CustomData.EMPTY.update(compoundTag -> compoundTag.put("Purpur.SpawnData", tag))));
+ }
+
+ if (type.isPresent()) {
+ final net.kyori.adventure.text.Component mobName = io.papermc.paper.adventure.PaperAdventure.asAdventure(type.get().getDescription());
+
+ String name = level.purpurConfig.silkTouchSpawnerName;
+ if (name != null && !name.isEmpty() && !name.equals("Monster Spawner")) {
+ net.kyori.adventure.text.Component displayName = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(name, net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.component("mob", mobName));
+ if (name.startsWith("<reset>")) {
+ displayName = displayName.decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false);
+ }
+ item.set(net.minecraft.core.component.DataComponents.CUSTOM_NAME, io.papermc.paper.adventure.PaperAdventure.asVanilla(displayName));
+ }
+
+ List<String> lore = level.purpurConfig.silkTouchSpawnerLore;
+ if (lore != null && !lore.isEmpty()) {
+
+ List<Component> loreComponentList = new java.util.ArrayList<>();
+ for (String line : lore) {
+ net.kyori.adventure.text.Component lineComponent = net.kyori.adventure.text.minimessage.MiniMessage.miniMessage().deserialize(line, net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.component("mob", mobName));
+ if (line.startsWith("<reset>")) {
+ lineComponent = lineComponent.decoration(net.kyori.adventure.text.format.TextDecoration.ITALIC, false);
+ }
+ loreComponentList.add(io.papermc.paper.adventure.PaperAdventure.asVanilla(lineComponent));
+ }
+
+ item.set(net.minecraft.core.component.DataComponents.LORE, new net.minecraft.world.item.component.ItemLore(loreComponentList, loreComponentList));
+ }
+ item.set(net.minecraft.core.component.DataComponents.HIDE_ADDITIONAL_TOOLTIP, net.minecraft.util.Unit.INSTANCE);
+ }
+ popResource(level, pos, item);
+ }
+ super.playerDestroy(level, player, pos, state, blockEntity, stack, includeDrops, dropExp);
+ }
+
+ private boolean isSilkTouch(Level level, ItemStack stack) {
+ return stack != null && level.purpurConfig.silkTouchTools.contains(stack.getItem()) && net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.SILK_TOUCH, stack) >= level.purpurConfig.minimumSilkTouchSpawnerRequire;
+ }
+ // Purpur end - Silk touch spawners
+
@Override
protected void spawnAfterBreak(BlockState state, ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience) {
super.spawnAfterBreak(state, level, pos, stack, dropExperience);
@@ -51,6 +_,7 @@
@Override
public int getExpDrop(BlockState state, ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience) {
+ if (level.purpurConfig.silkTouchEnabled && isSilkTouch(level, stack)) return 0; // Purpur - Silk touch spawners
if (dropExperience) {
int i = 15 + level.random.nextInt(15) + level.random.nextInt(15);
// this.popExperience(level, pos, i);

View File

@@ -1,33 +0,0 @@
--- a/net/minecraft/world/level/block/SpongeBlock.java
+++ b/net/minecraft/world/level/block/SpongeBlock.java
@@ -53,8 +_,8 @@
org.bukkit.craftbukkit.util.BlockStateListPopulator blockList = new org.bukkit.craftbukkit.util.BlockStateListPopulator(level); // CraftBukkit - Use BlockStateListPopulator
BlockPos.breadthFirstTraversal(
pos,
- 6,
- 65,
+ level.purpurConfig.spongeAbsorptionRadius, // Purpur - Configurable sponge absorption
+ level.purpurConfig.spongeAbsorptionArea, // Purpur - Configurable sponge absorption
(validPos, queueAdder) -> {
for (Direction direction : ALL_DIRECTIONS) {
queueAdder.accept(validPos.relative(direction));
@@ -68,7 +_,7 @@
BlockState blockState = blockList.getBlockState(blockPos);
FluidState fluidState = blockList.getFluidState(blockPos);
// CraftBukkit end
- if (!fluidState.is(FluidTags.WATER)) {
+ if (!fluidState.is(FluidTags.WATER) && (!level.purpurConfig.spongeAbsorbsLava || !fluidState.is(FluidTags.LAVA)) && (!level.purpurConfig.spongeAbsorbsWaterFromMud || !blockState.is(Blocks.MUD))) { // Purpur - Option for sponges to work on lava and mud
return BlockPos.TraversalNodeStatus.SKIP;
} else if (blockState.getBlock() instanceof BucketPickup bucketPickup
&& !bucketPickup.pickupBlock(null, blockList, blockPos, blockState).isEmpty()) { // CraftBukkit
@@ -76,6 +_,10 @@
} else {
if (blockState.getBlock() instanceof LiquidBlock) {
blockList.setBlock(blockPos, Blocks.AIR.defaultBlockState(), 3); // CraftBukkit
+ // Purpur start - Option for sponges to work on lava and mud
+ } else if (blockState.is(Blocks.MUD)) {
+ blockList.setBlock(blockPos, Blocks.CLAY.defaultBlockState(), 3);
+ // Purpur end - Option for sponges to work on lava and mud
} else {
if (!blockState.is(Blocks.KELP)
&& !blockState.is(Blocks.KELP_PLANT)

View File

@@ -1,17 +0,0 @@
--- a/net/minecraft/world/level/block/StonecutterBlock.java
+++ b/net/minecraft/world/level/block/StonecutterBlock.java
@@ -93,4 +_,14 @@
protected boolean isPathfindable(BlockState state, PathComputationType pathComputationType) {
return false;
}
+
+ // Purpur start - Stonecutter damage
+ @Override
+ public void stepOn(Level level, BlockPos pos, BlockState state, net.minecraft.world.entity.Entity entity) {
+ if (level.purpurConfig.stonecutterDamage > 0.0F && entity instanceof net.minecraft.world.entity.LivingEntity) {
+ entity.hurtServer((net.minecraft.server.level.ServerLevel) level, entity.damageSources().stonecutter().eventBlockDamager(level, pos), level.purpurConfig.stonecutterDamage);
+ }
+ super.stepOn(level, pos, state, entity);
+ }
+ // Purpur end - Stonecutter damage
}

View File

@@ -1,46 +0,0 @@
--- a/net/minecraft/world/level/block/SugarCaneBlock.java
+++ b/net/minecraft/world/level/block/SugarCaneBlock.java
@@ -19,7 +_,7 @@
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
-public class SugarCaneBlock extends Block {
+public class SugarCaneBlock extends Block implements BonemealableBlock { // Purpur - bonemealable sugarcane
public static final MapCodec<SugarCaneBlock> CODEC = simpleCodec(SugarCaneBlock::new);
public static final IntegerProperty AGE = BlockStateProperties.AGE_15;
protected static final float AABB_OFFSET = 6.0F;
@@ -113,4 +_,34 @@
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(AGE);
}
+
+ // Purpur start - bonemealable sugarcane
+ @Override
+ public boolean isValidBonemealTarget(final LevelReader world, final BlockPos pos, final BlockState state) {
+ if (!((net.minecraft.world.level.Level) world).purpurConfig.sugarCanAffectedByBonemeal || !world.isEmptyBlock(pos.above())) return false;
+
+ int reedHeight = 0;
+ while (world.getBlockState(pos.below(reedHeight)).is(this)) {
+ reedHeight++;
+ }
+
+ return reedHeight < ((net.minecraft.world.level.Level) world).paperConfig().maxGrowthHeight.reeds;
+ }
+
+ @Override
+ public boolean isBonemealSuccess(net.minecraft.world.level.Level world, RandomSource random, BlockPos pos, BlockState state) {
+ return true;
+ }
+
+ @Override
+ public void performBonemeal(ServerLevel world, RandomSource random, BlockPos pos, BlockState state) {
+ int reedHeight = 0;
+ while (world.getBlockState(pos.below(reedHeight)).is(this)) {
+ reedHeight++;
+ }
+ for (int i = 0; i <= world.paperConfig().maxGrowthHeight.reeds - reedHeight; i++) {
+ world.setBlockAndUpdate(pos.above(i), state.setValue(SugarCaneBlock.AGE, 0));
+ }
+ }
+ // Purpur end - bonemealable sugarcane
}

View File

@@ -1,47 +0,0 @@
--- a/net/minecraft/world/level/block/TurtleEggBlock.java
+++ b/net/minecraft/world/level/block/TurtleEggBlock.java
@@ -157,7 +_,7 @@
private boolean shouldUpdateHatchLevel(Level level) {
float timeOfDay = level.getTimeOfDay(1.0F);
- return timeOfDay < 0.69 && timeOfDay > 0.65 || level.random.nextInt(500) == 0;
+ return timeOfDay < 0.69 && timeOfDay > 0.65 || level.random.nextInt(level.purpurConfig.turtleEggsRandomTickCrackChance) == 0; // Purpur - Turtle eggs random tick crack chance
}
@Override
@@ -192,9 +_,31 @@
}
private boolean canDestroyEgg(ServerLevel level, Entity entity) {
- return !(entity instanceof Turtle)
- && !(entity instanceof Bat)
- && entity instanceof LivingEntity
- && (entity instanceof Player || level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING));
+ // Purpur start - Add turtle egg block options
+ if (entity instanceof Turtle || entity instanceof Bat) {
+ return false;
+ }
+ if (level.purpurConfig.turtleEggsBreakFromExpOrbs && entity instanceof net.minecraft.world.entity.ExperienceOrb) {
+ return true;
+ }
+ if (level.purpurConfig.turtleEggsBreakFromItems && entity instanceof net.minecraft.world.entity.item.ItemEntity) {
+ return true;
+ }
+ if (level.purpurConfig.turtleEggsBreakFromMinecarts && entity instanceof net.minecraft.world.entity.vehicle.AbstractMinecart) {
+ return true;
+ }
+ if (!(entity instanceof LivingEntity)) {
+ return false;
+ }
+ // Purpur start - Option to disable turtle egg trampling with feather falling
+ if (level.purpurConfig.turtleEggsTramplingFeatherFalling) {
+ java.util.Iterator<ItemStack> armor = ((LivingEntity) entity).getArmorSlots().iterator();
+ return !armor.hasNext() || net.minecraft.world.item.enchantment.EnchantmentHelper.getItemEnchantmentLevel(net.minecraft.world.item.enchantment.Enchantments.FEATHER_FALLING, armor.next()) < (int) entity.fallDistance;
+ }
+ // Purpur end - Option to disable turtle egg trampling with feather falling
+ if (entity instanceof Player) return true;
+
+ return level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING);
+ // Purpur end - Add turtle egg block options
}
}

View File

@@ -1,14 +0,0 @@
--- a/net/minecraft/world/level/block/TwistingVinesBlock.java
+++ b/net/minecraft/world/level/block/TwistingVinesBlock.java
@@ -34,4 +_,11 @@
protected boolean canGrowInto(BlockState state) {
return NetherVines.isValidGrowthState(state);
}
+
+ // Purpur start - twisting vines configurable max growth age
+ @Override
+ public int getMaxGrowthAge() {
+ return org.purpurmc.purpur.PurpurConfig.twistingVinesMaxGrowthAge;
+ }
+ // Purpur end - twisting vines configurable max growth age
}

View File

@@ -1,14 +0,0 @@
--- a/net/minecraft/world/level/block/WeepingVinesBlock.java
+++ b/net/minecraft/world/level/block/WeepingVinesBlock.java
@@ -34,4 +_,11 @@
protected boolean canGrowInto(BlockState state) {
return NetherVines.isValidGrowthState(state);
}
+
+ // Purpur start - weeping vines configurable max growth age
+ @Override
+ public int getMaxGrowthAge() {
+ return org.purpurmc.purpur.PurpurConfig.weepingVinesMaxGrowthAge;
+ }
+ // Purpur end - weeping vines configurable max growth age
}

View File

@@ -1,10 +0,0 @@
--- a/net/minecraft/world/level/block/WitherSkullBlock.java
+++ b/net/minecraft/world/level/block/WitherSkullBlock.java
@@ -71,6 +_,7 @@
);
witherBoss.yBodyRot = blockPatternMatch.getForwards().getAxis() == Direction.Axis.X ? 0.0F : 90.0F;
witherBoss.makeInvulnerable();
+ witherBoss.setSummoner(blockState.getBlock().placer == null ? null : blockState.getBlock().placer.getUUID()); // Purpur - Summoner API
// CraftBukkit start
if (!level.addFreshEntity(witherBoss, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BUILD_WITHER)) {
return;

View File

@@ -1,33 +0,0 @@
--- a/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
@@ -191,6 +_,21 @@
}
ItemStack itemStack = furnace.items.get(1);
+ // Purpur start - Furnace uses lava from underneath
+ boolean usedLavaFromUnderneath = false;
+ if (level.purpurConfig.furnaceUseLavaFromUnderneath && !furnace.isLit() && itemStack.isEmpty() && !furnace.items.get(0).isEmpty() && level.getGameTime() % 20 == 0) {
+ BlockPos below = furnace.getBlockPos().below();
+ BlockState belowState = level.getBlockStateIfLoaded(below);
+ if (belowState != null && belowState.is(Blocks.LAVA)) {
+ net.minecraft.world.level.material.FluidState fluidState = belowState.getFluidState();
+ if (fluidState != null && fluidState.isSource()) {
+ level.setBlock(below, Blocks.AIR.defaultBlockState(), 3);
+ itemStack = Items.LAVA_BUCKET.getDefaultInstance();
+ usedLavaFromUnderneath = true;
+ }
+ }
+ }
+ // Purpur end - Furnace uses lava from underneath
ItemStack itemStack1 = furnace.items.get(0);
boolean flag1 = !itemStack1.isEmpty();
boolean flag2 = !itemStack.isEmpty();
@@ -274,6 +_,8 @@
if (flag) {
setChanged(level, pos, state);
}
+
+ if (usedLavaFromUnderneath) furnace.items.set(1, ItemStack.EMPTY); // Purpur - Furnace uses lava from underneath
}
private static boolean canBurn(

View File

@@ -1,44 +0,0 @@
--- a/net/minecraft/world/level/block/entity/BeaconBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BeaconBlockEntity.java
@@ -139,6 +_,16 @@
public double getEffectRange() {
if (this.effectRange < 0) {
+ // Purpur start - Beacon Activation Range Configurable
+ if (this.level != null) {
+ switch (this.levels) {
+ case 1: return this.level.purpurConfig.beaconLevelOne;
+ case 2: return this.level.purpurConfig.beaconLevelTwo;
+ case 3: return this.level.purpurConfig.beaconLevelThree;
+ case 4: return this.level.purpurConfig.beaconLevelFour;
+ }
+ }
+ // Purpur end - Beacon Activation Range Configurable
return this.levels * 10 + 10;
} else {
return effectRange;
@@ -168,6 +_,7 @@
int y = pos.getY();
int z = pos.getZ();
BlockPos blockPos;
+ boolean isTintedGlass = false; // Purpur - allow beacon effects when covered by tinted glass
if (blockEntity.lastCheckY < y) {
blockPos = pos;
blockEntity.checkingBeamSections = Lists.newArrayList();
@@ -197,6 +_,7 @@
}
}
} else {
+ if (level.purpurConfig.beaconAllowEffectsWithTintedGlass && blockState.getBlock().equals(Blocks.TINTED_GLASS)) {isTintedGlass = true;} // Purpur - allow beacon effects when covered by tinted glass
if (beaconBeamSection == null || blockState.getLightBlock() >= 15 && !blockState.is(Blocks.BEDROCK)) {
blockEntity.checkingBeamSections.clear();
blockEntity.lastCheckY = height;
@@ -216,7 +_,7 @@
blockEntity.levels = updateBase(level, x, y, z);
}
- if (blockEntity.levels > 0 && !blockEntity.beamSections.isEmpty()) {
+ if (blockEntity.levels > 0 && (!blockEntity.beamSections.isEmpty() || (level.purpurConfig.beaconAllowEffectsWithTintedGlass && isTintedGlass))) { // Purpur - allow beacon effects when covered by tinted glass
applyEffects(level, pos, blockEntity.levels, blockEntity.primaryPower, blockEntity.secondaryPower, blockEntity); // Paper - Custom beacon ranges
playSound(level, pos, SoundEvents.BEACON_AMBIENT);
}

View File

@@ -1,56 +0,0 @@
--- a/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java
@@ -76,7 +_,7 @@
"leash",
"UUID"
);
- public static final int MAX_OCCUPANTS = 3;
+ public static final int MAX_OCCUPANTS = org.purpurmc.purpur.PurpurConfig.beeInsideBeeHive; // Purpur - Config to change max number of bees
private static final int MIN_TICKS_BEFORE_REENTERING_HIVE = 400;
private static final int MIN_OCCUPATION_TICKS_NECTAR = 2400;
public static final int MIN_OCCUPATION_TICKS_NECTARLESS = 600;
@@ -154,11 +_,33 @@
return list;
}
+ // Purpur start - Stored Bee API
+ public List<Entity> releaseBee(BlockState iblockdata, BeehiveBlockEntity.BeeData data, BeehiveBlockEntity.BeeReleaseStatus tileentitybeehive_releasestatus, boolean force) {
+ List<Entity> list = Lists.newArrayList();
+
+ BeehiveBlockEntity.releaseOccupant(this.level, this.worldPosition, iblockdata, data.occupant, list, tileentitybeehive_releasestatus, this.savedFlowerPos, force);
+
+ if (!list.isEmpty()) {
+ stored.remove(data);
+
+ super.setChanged();
+ }
+
+ return list;
+ }
+ // Purpur end - Stored Bee API
+
@VisibleForDebug
public int getOccupantCount() {
return this.stored.size();
}
+ // Purpur start - Stored Bee API
+ public List<BeeData> getStored() {
+ return stored;
+ }
+ // Purpur end - Stored Bee API
+
// Paper start - Add EntityBlockStorage clearEntities
public void clearBees() {
this.stored.clear();
@@ -408,8 +_,8 @@
return this.stored.stream().map(BeehiveBlockEntity.BeeData::toOccupant).toList();
}
- static class BeeData {
- private final BeehiveBlockEntity.Occupant occupant;
+ public static class BeeData { // Purpur - make public - Stored Bee API
+ public final BeehiveBlockEntity.Occupant occupant; // Purpur - make public - Stored Bee API
private int exitTickCounter; // Paper - Fix bees aging inside hives; separate counter for checking if bee should exit to reduce exit attempts
private int ticksInHive;

View File

@@ -1,50 +0,0 @@
--- a/net/minecraft/world/level/block/entity/BlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BlockEntity.java
@@ -84,6 +_,14 @@
this.persistentDataContainer.putAll((CompoundTag) persistentDataTag);
}
// Paper end - read persistent data container
+
+ // Purpur start - Persistent BlockEntity Lore and DisplayName
+ if (tag.contains("Purpur.persistentLore")) {
+ net.minecraft.world.item.component.ItemLore.CODEC.decode(net.minecraft.nbt.NbtOps.INSTANCE, tag.getCompound("Purpur.persistentLore")).result()
+ .ifPresent(tag1 -> this.persistentLore = tag1.getFirst());
+ }
+ // Purpur end - Persistent BlockEntity Lore and DisplayName
+
}
public final void loadWithComponents(CompoundTag tag, HolderLookup.Provider registries) {
@@ -98,6 +_,15 @@
this.loadAdditional(tag, registries);
}
+ // Purpur start - Persistent BlockEntity Lore and DisplayName
+ protected void saveAdditional(CompoundTag nbt) {
+ if (this.persistentLore != null) {
+ net.minecraft.world.item.component.ItemLore.CODEC.encodeStart(net.minecraft.nbt.NbtOps.INSTANCE, this.persistentLore).result()
+ .ifPresent(tag -> nbt.put("Purpur.persistentLore", tag));
+ }
+ }
+ // Purpur end - Persistent BlockEntity Lore and DisplayName
+
protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
}
@@ -378,4 +_,16 @@
<T> T getOrDefault(DataComponentType<? extends T> component, T defaultValue);
}
+ // Purpur start - Persistent BlockEntity Lore and DisplayName
+ @Nullable
+ private net.minecraft.world.item.component.ItemLore persistentLore = null;
+
+ public void setPersistentLore(net.minecraft.world.item.component.ItemLore lore) {
+ this.persistentLore = lore;
+ }
+
+ public @org.jetbrains.annotations.Nullable net.minecraft.world.item.component.ItemLore getPersistentLore() {
+ return this.persistentLore;
+ }
+ // Purpur end - Persistent BlockEntity Lore and DisplayName
}

View File

@@ -1,74 +0,0 @@
--- a/net/minecraft/world/level/block/entity/ConduitBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/ConduitBlockEntity.java
@@ -155,7 +_,7 @@
BlockPos blockPos1 = pos.offset(i, i1, i2x);
BlockState blockState = level.getBlockState(blockPos1);
- for (Block block : VALID_BLOCKS) {
+ for (Block block : level.purpurConfig.conduitBlocks) { // Purpur - Conduit behavior configuration
if (blockState.is(block)) {
positions.add(blockPos1);
}
@@ -170,13 +_,13 @@
private static void applyEffects(Level level, BlockPos pos, List<BlockPos> positions) {
// CraftBukkit start
- ConduitBlockEntity.applyEffects(level, pos, ConduitBlockEntity.getRange(positions));
+ ConduitBlockEntity.applyEffects(level, pos, ConduitBlockEntity.getRange(positions, level)); // Purpur - Conduit behavior configuration
}
- public static int getRange(List<BlockPos> positions) {
+ public static int getRange(List<BlockPos> positions, Level level) { // Purpur - Conduit behavior configuration
// CraftBukkit end
int size = positions.size();
- int i = size / 7 * 16;
+ int i = size / 7 * level.purpurConfig.conduitDistance; // Purpur - Conduit behavior configuration
// CraftBukkit start
return i;
}
@@ -213,17 +_,17 @@
blockEntity.destroyTargetUUID = null;
} else if (blockEntity.destroyTarget == null) {
List<LivingEntity> entitiesOfClass = level.getEntitiesOfClass(
- LivingEntity.class, getDestroyRangeAABB(pos), collidedEntity -> collidedEntity instanceof Enemy && collidedEntity.isInWaterOrRain()
+ LivingEntity.class, getDestroyRangeAABB(pos, level), collidedEntity -> collidedEntity instanceof Enemy && collidedEntity.isInWaterOrRain() // Purpur - Conduit behavior configuration
);
if (!entitiesOfClass.isEmpty()) {
blockEntity.destroyTarget = entitiesOfClass.get(level.random.nextInt(entitiesOfClass.size()));
}
- } else if (!blockEntity.destroyTarget.isAlive() || !pos.closerThan(blockEntity.destroyTarget.blockPosition(), 8.0)) {
+ } else if (!blockEntity.destroyTarget.isAlive() || !pos.closerThan(blockEntity.destroyTarget.blockPosition(), level.purpurConfig.conduitDamageDistance)) { // Purpur - Conduit behavior configuration
blockEntity.destroyTarget = null;
}
if (damageTarget && blockEntity.destroyTarget != null) { // CraftBukkit
- if (blockEntity.destroyTarget.hurtServer((net.minecraft.server.level.ServerLevel) level, level.damageSources().magic().eventBlockDamager(level, pos), 4.0F)) // CraftBukkit
+ if (blockEntity.destroyTarget.hurtServer((net.minecraft.server.level.ServerLevel) level, level.damageSources().magic().eventBlockDamager(level, pos), level.purpurConfig.conduitDamageAmount)) // CraftBukkit // Purpur - Conduit behavior configuration
level.playSound(
null,
blockEntity.destroyTarget.getX(),
@@ -253,16 +_,22 @@
}
public static AABB getDestroyRangeAABB(BlockPos pos) {
+ // Purpur start - Conduit behavior configuration
+ return getDestroyRangeAABB(pos, null);
+ }
+
+ private static AABB getDestroyRangeAABB(BlockPos pos, Level level) {
+ // Purpur end - Conduit behavior configuration
int x = pos.getX();
int y = pos.getY();
int z = pos.getZ();
- return new AABB(x, y, z, x + 1, y + 1, z + 1).inflate(8.0);
+ return new AABB(x, y, z, x + 1, y + 1, z + 1).inflate(level == null ? 8.0 : level.purpurConfig.conduitDamageDistance); // Purpur - Conduit behavior configuration
}
@Nullable
private static LivingEntity findDestroyTarget(Level level, BlockPos pos, UUID targetId) {
List<LivingEntity> entitiesOfClass = level.getEntitiesOfClass(
- LivingEntity.class, getDestroyRangeAABB(pos), collidedEntity -> collidedEntity.getUUID().equals(targetId)
+ LivingEntity.class, getDestroyRangeAABB(pos, level), collidedEntity -> collidedEntity.getUUID().equals(targetId) // Purpur - Conduit behavior configuration
);
return entitiesOfClass.size() == 1 ? entitiesOfClass.get(0) : null;
}

View File

@@ -1,41 +0,0 @@
--- a/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/EnchantingTableBlockEntity.java
@@ -28,6 +_,7 @@
private static final RandomSource RANDOM = RandomSource.create();
@Nullable
private Component name;
+ private int lapis = 0; // Purpur - Enchantment Table Persists Lapis
public EnchantingTableBlockEntity(BlockPos pos, BlockState state) {
super(BlockEntityType.ENCHANTING_TABLE, pos, state);
@@ -39,6 +_,7 @@
if (this.hasCustomName()) {
tag.putString("CustomName", Component.Serializer.toJson(this.name, registries));
}
+ tag.putInt("Purpur.Lapis", this.lapis); // Purpur - Enchantment Table Persists Lapis
}
@Override
@@ -47,6 +_,7 @@
if (tag.contains("CustomName", 8)) {
this.name = parseCustomNameSafe(tag.getString("CustomName"), registries);
}
+ this.lapis = tag.getInt("Purpur.Lapis"); // Purpur - Enchantment Table Persists Lapis
}
public static void bookAnimationTick(Level level, BlockPos pos, BlockState state, EnchantingTableBlockEntity enchantingTable) {
@@ -138,4 +_,14 @@
public void removeComponentsFromTag(CompoundTag tag) {
tag.remove("CustomName");
}
+
+ // Purpur start - Enchantment Table Persists Lapis
+ public int getLapis() {
+ return this.lapis;
+ }
+
+ public void setLapis(int lapis) {
+ this.lapis = lapis;
+ }
+ // Purpur end - Enchantment Table Persists Lapis
}

View File

@@ -1,66 +0,0 @@
--- a/net/minecraft/world/level/block/entity/SignBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/SignBlockEntity.java
@@ -163,16 +_,32 @@
return this.setText(updater.apply(text), isFrontText);
}
+ // Purpur start - Signs allow color codes
+ private Component translateColors(org.bukkit.entity.Player player, String line, Style style) {
+ if (level.purpurConfig.signAllowColors) {
+ if (player.hasPermission("purpur.sign.color")) line = line.replaceAll("(?i)&([0-9a-fr])", "\u00a7$1");
+ if (player.hasPermission("purpur.sign.style")) line = line.replaceAll("(?i)&([l-or])", "\u00a7$1");
+ if (player.hasPermission("purpur.sign.magic")) line = line.replaceAll("(?i)&([kr])", "\u00a7$1");
+
+ return io.papermc.paper.adventure.PaperAdventure.asVanilla(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(line));
+ } else {
+ return Component.literal(line).setStyle(style);
+ }
+ }
+ // Purpur end - Signs allow color codes
+
private SignText setMessages(Player player, List<FilteredText> filteredText, SignText text, boolean front) { // CraftBukkit
SignText originalText = text; // CraftBukkit
for (int i = 0; i < filteredText.size(); i++) {
FilteredText filteredText1 = filteredText.get(i);
Style style = text.getMessage(i, player.isTextFilteringEnabled()).getStyle();
+
+ org.bukkit.entity.Player craftPlayer = (org.bukkit.craftbukkit.entity.CraftPlayer) player.getBukkitEntity(); // Purpur - Signs allow color codes
if (player.isTextFilteringEnabled()) {
- text = text.setMessage(i, Component.literal(net.minecraft.util.StringUtil.filterText(filteredText1.filteredOrEmpty())).setStyle(style)); // Paper - filter sign text to chat only
+ text = text.setMessage(i, translateColors(craftPlayer, net.minecraft.util.StringUtil.filterText(filteredText1.filteredOrEmpty()), style)); // Paper - filter sign text to chat only // Purpur - Signs allow color codes
} else {
text = text.setMessage(
- i, Component.literal(filteredText1.raw()).setStyle(style), Component.literal(net.minecraft.util.StringUtil.filterText(filteredText1.filteredOrEmpty())).setStyle(style) // Paper - filter sign text to chat only
+ i, translateColors(craftPlayer, net.minecraft.util.StringUtil.filterText(filteredText1.raw()), style), translateColors(craftPlayer, net.minecraft.util.StringUtil.filterText(filteredText1.filteredOrEmpty()), style) // Paper - filter sign text to chat only // Purpur - Signs allow color codes
);
}
}
@@ -310,6 +_,28 @@
// CraftBukkit - this
return new CommandSourceStack(commandSource, Vec3.atCenterOf(pos), Vec2.ZERO, (ServerLevel)level, 2, string, component, level.getServer(), player); // Paper - Fix commands from signs not firing command events
}
+
+ // Purpur start - Signs allow color codes
+ public ClientboundBlockEntityDataPacket getTranslatedUpdatePacket(boolean filtered, boolean front) {
+ final CompoundTag nbt = new CompoundTag();
+ this.saveAdditional(nbt, this.getLevel().registryAccess());
+ final Component[] lines = front ? frontText.getMessages(filtered) : backText.getMessages(filtered);
+ final String side = front ? "front_text" : "back_text";
+ for (int i = 0; i < 4; i++) {
+ final var component = io.papermc.paper.adventure.PaperAdventure.asAdventure(lines[i]);
+ final String line = net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacyAmpersand().serialize(component);
+ final var text = net.kyori.adventure.text.Component.text(line);
+ final String json = net.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().serialize(text);
+ if (!nbt.contains(side)) nbt.put(side, new CompoundTag());
+ final CompoundTag sideNbt = nbt.getCompound(side);
+ if (!sideNbt.contains("messages")) sideNbt.put("messages", new net.minecraft.nbt.ListTag());
+ final net.minecraft.nbt.ListTag messagesNbt = sideNbt.getList("messages", Tag.TAG_STRING);
+ messagesNbt.set(i, net.minecraft.nbt.StringTag.valueOf(json));
+ }
+ nbt.putString("PurpurEditor", "true");
+ return ClientboundBlockEntityDataPacket.create(this, (blockEntity, registryAccess) -> nbt);
+ }
+ // Purpur end - Signs allow color codes
@Override
public ClientboundBlockEntityDataPacket getUpdatePacket() {

View File

@@ -1,29 +0,0 @@
--- a/net/minecraft/world/level/block/piston/PistonStructureResolver.java
+++ b/net/minecraft/world/level/block/piston/PistonStructureResolver.java
@@ -81,7 +_,7 @@
return true;
} else {
int i = 1;
- if (i + this.toPush.size() > 12) {
+ if (i + this.toPush.size() > this.level.purpurConfig.pistonBlockPushLimit) { // Purpur - Configurable piston push limit
return false;
} else {
while (isSticky(blockState)) {
@@ -95,7 +_,7 @@
break;
}
- if (++i + this.toPush.size() > 12) {
+ if (++i + this.toPush.size() > this.level.purpurConfig.pistonBlockPushLimit) { // Purpur - Configurable piston push limit
return false;
}
}
@@ -140,7 +_,7 @@
return true;
}
- if (this.toPush.size() >= 12) {
+ if (this.toPush.size() >= this.level.purpurConfig.pistonBlockPushLimit) { // Purpur - Configurable piston push limit
return false;
}

View File

@@ -1,10 +0,0 @@
--- a/net/minecraft/world/level/chunk/storage/EntityStorage.java
+++ b/net/minecraft/world/level/chunk/storage/EntityStorage.java
@@ -106,6 +_,7 @@
}
// Paper end - Entity load/save limit per chunk
CompoundTag compoundTag1 = new CompoundTag();
+ if (!entity.canSaveToDisk()) return; // Purpur - Add canSaveToDisk to Entity
if (entity.save(compoundTag1)) {
listTag.add(compoundTag1);
}

View File

@@ -1,11 +0,0 @@
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
@@ -283,7 +_,7 @@
// Paper start
private static void printOversizedLog(String msg, Path file, int x, int z) {
- org.apache.logging.log4j.LogManager.getLogger().fatal(msg + " (" + file.toString().replaceAll(".+[\\\\/]", "") + " - " + x + "," + z + ") Go clean it up to remove this message. /minecraft:tp " + (x<<4)+" 128 "+(z<<4) + " - DO NOT REPORT THIS TO PAPER - You may ask for help on Discord, but do not file an issue. These error messages can not be removed.");
+ org.apache.logging.log4j.LogManager.getLogger().fatal(msg + " (" + file.toString().replaceAll(".+[\\\\/]", "") + " - " + x + "," + z + ") Go clean it up to remove this message. /minecraft:tp " + (x<<4)+" 128 "+(z<<4) + " - DO NOT REPORT THIS TO PURPUR - You may ask for help on Discord, but do not file an issue. These error messages can not be removed."); // Purpur - Rebrand
}
private static CompoundTag readOversizedChunk(RegionFile regionfile, ChunkPos chunkCoordinate) throws IOException {

View File

@@ -1,32 +0,0 @@
--- a/net/minecraft/world/level/levelgen/PhantomSpawner.java
+++ b/net/minecraft/world/level/levelgen/PhantomSpawner.java
@@ -43,7 +_,7 @@
int spawnAttemptMaxSeconds = level.paperConfig().entities.behavior.phantomsSpawnAttemptMaxSeconds;
this.nextTick += (spawnAttemptMinSeconds + randomSource.nextInt(spawnAttemptMaxSeconds - spawnAttemptMinSeconds + 1)) * 20;
// Paper end - Ability to control player's insomnia and phantoms
- if (level.getSkyDarken() < 5 && level.dimensionType().hasSkyLight()) {
+ if (level.getSkyDarken() < level.purpurConfig.phantomSpawnMinSkyDarkness && level.dimensionType().hasSkyLight()) { // Purpur - Add phantom spawning options
return 0;
} else {
int i = 0;
@@ -51,9 +_,9 @@
for (ServerPlayer serverPlayer : level.players()) {
if (!serverPlayer.isSpectator() && (!level.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !serverPlayer.isCreative())) { // Paper - Add phantom creative and insomniac controls
BlockPos blockPos = serverPlayer.blockPosition();
- if (!level.dimensionType().hasSkyLight() || blockPos.getY() >= level.getSeaLevel() && level.canSeeSky(blockPos)) {
+ if (!level.dimensionType().hasSkyLight() || (!level.purpurConfig.phantomSpawnOnlyAboveSeaLevel || blockPos.getY() >= level.getSeaLevel()) && (!level.purpurConfig.phantomSpawnOnlyWithVisibleSky || level.canSeeSky(blockPos))) { // Purpur - Add phantom spawning options
DifficultyInstance currentDifficultyAt = level.getCurrentDifficultyAt(blockPos);
- if (currentDifficultyAt.isHarderThan(randomSource.nextFloat() * 3.0F)) {
+ if (currentDifficultyAt.isHarderThan(randomSource.nextFloat() * (float) level.purpurConfig.phantomSpawnLocalDifficultyChance)) { // Purpur - Add phantom spawning options
ServerStatsCounter stats = serverPlayer.getStats();
int i1 = Mth.clamp(stats.getValue(Stats.CUSTOM.get(Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE);
int i2 = 24000;
@@ -65,7 +_,7 @@
FluidState fluidState = level.getFluidState(blockPos1);
if (NaturalSpawner.isValidEmptySpawnBlock(level, blockPos1, blockState, fluidState, EntityType.PHANTOM)) {
SpawnGroupData spawnGroupData = null;
- int i3 = 1 + randomSource.nextInt(currentDifficultyAt.getDifficulty().getId() + 1);
+ int i3 = level.purpurConfig.phantomSpawnMinPerAttempt + level.random.nextInt((level.purpurConfig.phantomSpawnMaxPerAttempt < 0 ? currentDifficultyAt.getDifficulty().getId() : level.purpurConfig.phantomSpawnMaxPerAttempt - level.purpurConfig.phantomSpawnMinPerAttempt) + 1); // Purpur - Add phantom spawning options
for (int i4 = 0; i4 < i3; i4++) {
// Paper start - PhantomPreSpawnEvent

View File

@@ -1,24 +0,0 @@
--- a/net/minecraft/world/level/material/FlowingFluid.java
+++ b/net/minecraft/world/level/material/FlowingFluid.java
@@ -232,7 +_,7 @@
}
}
- if (i1 >= 2 && this.canConvertToSource(level)) {
+ if (i1 >= this.getRequiredSources(level) && this.canConvertToSource(level)) { // Purpur - Implement infinite liquids
BlockState blockState1 = level.getBlockState(mutableBlockPos.setWithOffset(pos, Direction.DOWN));
FluidState fluidState1 = blockState1.getFluidState();
if (blockState1.isSolid() || this.isSourceBlockOfThisType(fluidState1)) {
@@ -319,6 +_,12 @@
}
protected abstract boolean canConvertToSource(ServerLevel level);
+
+ // Purpur start - Implement infinite liquids
+ protected int getRequiredSources(Level level) {
+ return 2;
+ }
+ // Purpur end - Implement infinite liquids
protected void spreadTo(LevelAccessor level, BlockPos pos, BlockState blockState, Direction direction, FluidState fluidState) {
if (blockState.getBlock() instanceof LiquidBlockContainer liquidBlockContainer) {

View File

@@ -1,25 +0,0 @@
--- a/net/minecraft/world/level/material/LavaFluid.java
+++ b/net/minecraft/world/level/material/LavaFluid.java
@@ -177,7 +_,7 @@
@Override
public int getTickDelay(LevelReader level) {
- return level.dimensionType().ultraWarm() ? 10 : 30;
+ return level.dimensionType().ultraWarm() ? level.getWorldBorder().world.purpurConfig.lavaSpeedNether : level.getWorldBorder().world.purpurConfig.lavaSpeedNotNether; // Purpur - Make lava flow speed configurable
}
@Override
@@ -198,6 +_,13 @@
private void fizz(LevelAccessor level, BlockPos pos) {
level.levelEvent(1501, pos, 0);
}
+
+ // Purpur start - Implement infinite liquids
+ @Override
+ protected int getRequiredSources(Level level) {
+ return level.purpurConfig.lavaInfiniteRequiredSources;
+ }
+ // Purpur end - Implement infinite liquids
@Override
protected boolean canConvertToSource(ServerLevel level) {

View File

@@ -1,15 +0,0 @@
--- a/net/minecraft/world/level/material/WaterFluid.java
+++ b/net/minecraft/world/level/material/WaterFluid.java
@@ -74,6 +_,12 @@
protected boolean canConvertToSource(ServerLevel level) {
return level.getGameRules().getBoolean(GameRules.RULE_WATER_SOURCE_CONVERSION);
}
+ // Purpur start - Implement infinite liquids
+ @Override
+ protected int getRequiredSources(Level level) {
+ return level.purpurConfig.waterInfiniteRequiredSources;
+ }
+ // Purpur end - Implement infinite liquids
// Paper start - Add BlockBreakBlockEvent
@Override
protected void beforeDestroyingBlock(LevelAccessor level, BlockPos pos, BlockState state, BlockPos source) {

View File

@@ -1,20 +0,0 @@
--- a/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
+++ b/net/minecraft/world/level/pathfinder/WalkNodeEvaluator.java
@@ -240,7 +_,7 @@
if ((node == null || node.costMalus < 0.0F)
&& verticalDeltaLimit > 0
&& (cachedPathType != PathType.FENCE || this.canWalkOverFences())
- && cachedPathType != PathType.UNPASSABLE_RAIL
+ && (this.mob.level().purpurConfig.mobsIgnoreRails || cachedPathType != PathType.UNPASSABLE_RAIL) // Purpur - Config to allow mobs to pathfind over rails
&& cachedPathType != PathType.TRAPDOOR
&& cachedPathType != PathType.POWDER_SNOW) {
node = this.tryJumpOn(x, y, z, verticalDeltaLimit, nodeFloorLevel, direction, pathType, mutableBlockPos);
@@ -493,7 +_,7 @@
return PathType.TRAPDOOR;
} else if (blockState.is(Blocks.POWDER_SNOW)) {
return PathType.POWDER_SNOW;
- } else if (blockState.is(Blocks.CACTUS) || blockState.is(Blocks.SWEET_BERRY_BUSH)) {
+ } else if (blockState.is(Blocks.CACTUS) || blockState.is(Blocks.SWEET_BERRY_BUSH) || blockState.is(Blocks.STONECUTTER)) { // Purpur - Stonecutter damage
return PathType.DAMAGE_OTHER;
} else if (blockState.is(Blocks.HONEY_BLOCK)) {
return PathType.STICKY_HONEY;

View File

@@ -1,11 +0,0 @@
--- a/net/minecraft/world/level/portal/PortalShape.java
+++ b/net/minecraft/world/level/portal/PortalShape.java
@@ -28,7 +_,7 @@
public static final int MAX_WIDTH = 21;
private static final int MIN_HEIGHT = 3;
public static final int MAX_HEIGHT = 21;
- private static final BlockBehaviour.StatePredicate FRAME = (state, level, pos) -> state.is(Blocks.OBSIDIAN);
+ private static final BlockBehaviour.StatePredicate FRAME = (state, level, pos) -> state.is(Blocks.OBSIDIAN) || (org.purpurmc.purpur.PurpurConfig.cryingObsidianValidForPortalFrame && state.is(Blocks.CRYING_OBSIDIAN)); // Purpur - Crying obsidian valid for portal frames
private static final float SAFE_TRAVEL_MAX_ENTITY_XY = 4.0F;
private static final double SAFE_TRAVEL_MAX_VERTICAL_DELTA = 1.0;
private final Direction.Axis axis;

View File

@@ -1,10 +0,0 @@
--- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
+++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
@@ -68,6 +_,7 @@
public final Map<String, MapDecoration> decorations = Maps.newLinkedHashMap();
private final Map<String, MapFrame> frameMarkers = Maps.newHashMap();
private int trackedDecorationCount;
+ public boolean isExplorerMap; // Purpur - Explorer Map API
// CraftBukkit start
public final org.bukkit.craftbukkit.map.CraftMapView mapView;

View File

@@ -1,14 +0,0 @@
--- a/net/minecraft/world/level/storage/loot/functions/EnchantedCountIncreaseFunction.java
+++ b/net/minecraft/world/level/storage/loot/functions/EnchantedCountIncreaseFunction.java
@@ -66,6 +_,11 @@
Entity entity = context.getOptionalParameter(LootContextParams.ATTACKING_ENTITY);
if (entity instanceof LivingEntity livingEntity) {
int enchantmentLevel = EnchantmentHelper.getEnchantmentLevel(this.enchantment, livingEntity);
+ // Purpur start - Add an option to fix MC-3304 projectile looting
+ if (org.purpurmc.purpur.PurpurConfig.fixProjectileLootingTransfer && context.getOptionalParameter(LootContextParams.DIRECT_ATTACKING_ENTITY) instanceof net.minecraft.world.entity.projectile.AbstractArrow arrow) {
+ enchantmentLevel = arrow.actualEnchantments.getLevel(this.enchantment);
+ }
+ // Purpur end - Add an option to fix MC-3304 projectile looting
if (enchantmentLevel == 0) {
return stack;
}