mirror of
https://github.com/PurpurMC/Purpur.git
synced 2026-02-21 10:27:44 +01:00
move file patches to rejected directory
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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];
|
||||
@@ -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) {
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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) {
|
||||
@@ -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()
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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)) {
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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) {
|
||||
@@ -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)) {
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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++) {
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)) {
|
||||
@@ -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();
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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);
|
||||
@@ -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)
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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(
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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() {
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 {
|
||||
@@ -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
|
||||
@@ -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) {
|
||||
@@ -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) {
|
||||
@@ -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) {
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user