9
0
mirror of https://github.com/Samsuik/Sakura.git synced 2025-12-27 02:39:06 +00:00
Files
SakuraMC/sakura-server/minecraft-patches/features/0008-Merge-Cannon-Entities.patch
Samsuik 1530ca1264 Updated Upstream (Paper)
Upstream has released updates that appear to apply and compile correctly

Paper Changes:
PaperMC/Paper@914fb08 Fix Entity#updateFluidHeightAndDoFluidPushing inconsistency with Vanilla
PaperMC/Paper@e9fa3a7 Use correct queue when blocking on futures
PaperMC/Paper@0ff899d Prevent world mutation on copper golem spawn cancel (#13152)
PaperMC/Paper@bae47d3 Update to 1.21.10 (#13127)
PaperMC/Paper@8339bb3 Update DataConverter constants for 1.21.10
PaperMC/Paper@3982efa Sync Moonrise
PaperMC/Paper@fa57d4b Remove Vanilla packet processing at start of tick
PaperMC/Paper@fba780d Rebuild patches
2025-10-07 20:21:51 +01:00

347 lines
18 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Sat, 9 Sep 2023 18:39:15 +0100
Subject: [PATCH] Merge Cannon Entities
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 477c3436d6586a9fd9f0486bc8102808c15c5bae..4bf46b1a7ce64f39ca7d4e915001f54391a3e89c 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -716,6 +716,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// Paper end - rewrite chunk system
this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
this.levelTickScheduler.repeatingTask(this.explosionPositions::clear, 0); // Sakura - client visibility settings
+ this.levelTickScheduler.repeatingTask(this.mergeHandler::expire, 200); // Sakura - merge cannon entities
}
// Paper start
@@ -834,6 +835,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
io.papermc.paper.entity.activation.ActivationRange.activateEntities(this); // Paper - EAR
+ final Entity[] previousEntity = new Entity[1]; // Sakura - merge cannon entities
this.entityTickList
.forEach(
entity -> {
@@ -852,6 +854,15 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
entity.stopRiding();
}
+ // Sakura start - merge cannon entities
+ final Entity previous = previousEntity[0];
+ if (this.mergeHandler.tryMerge(entity, previous)) {
+ return;
+ } else {
+ previousEntity[0] = entity;
+ }
+ // Sakura end - merge cannon entities
+
profilerFiller.push("tick");
this.guardEntityTick(this::tickNonPassenger, entity);
profilerFiller.pop();
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index 5fd20439dd1686e5f2ee20d3f89dab78932d5a15..f7d0b0017ebcec507d88f90c9b894cbf51e3511a 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -567,6 +567,27 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
return to.entityState() != null && to.entityState().comparePositionAndMotion(this);
}
// Sakura end - store entity data/state
+ // Sakura start - merge cannon entities
+ public final void updateBukkitHandle(final Entity entity) {
+ if (this.bukkitEntity != null) {
+ this.bukkitEntity.setHandle(entity);
+ } else {
+ this.bukkitEntity = entity.getBukkitEntity();
+ }
+ }
+
+ public final long getPackedOriginPosition() {
+ if (this.origin != null) {
+ return BlockPos.asLong(
+ Mth.floor(this.origin.x()),
+ Mth.floor(this.origin.y()),
+ Mth.floor(this.origin.z())
+ );
+ } else {
+ return Long.MIN_VALUE;
+ }
+ }
+ // Sakura end - merge cannon entities
public Entity(EntityType<?> entityType, Level level) {
this.type = entityType;
@@ -5236,6 +5257,11 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name
if (this.removalReason != Entity.RemovalReason.UNLOADED_TO_CHUNK) { this.getPassengers().forEach(Entity::stopRiding); } // Paper - rewrite chunk system
this.levelCallback.onRemove(removalReason);
this.onRemoval(removalReason);
+ // Sakura start - merge cannon entities
+ if (removalReason == RemovalReason.DISCARDED) {
+ this.level.mergeHandler.removeEntity(this);
+ }
+ // Sakura end - merge cannon entities
// Paper start - Folia schedulers
if (!(this instanceof ServerPlayer) && removalReason != RemovalReason.CHANGED_DIMENSION && !alreadyRemoved) {
// Players need to be special cased, because they are regularly removed from the world
diff --git a/net/minecraft/world/entity/item/FallingBlockEntity.java b/net/minecraft/world/entity/item/FallingBlockEntity.java
index 59aa539b7d830de48ff582b0da6fa17796b8c4b8..af7dd04ecbf9e8b35357da421fb156aee61261b5 100644
--- a/net/minecraft/world/entity/item/FallingBlockEntity.java
+++ b/net/minecraft/world/entity/item/FallingBlockEntity.java
@@ -53,7 +53,7 @@ import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.Vec3;
import org.slf4j.Logger;
-public class FallingBlockEntity extends Entity {
+public class FallingBlockEntity extends Entity implements me.samsuik.sakura.entity.merge.MergeableEntity { // Sakura - merge cannon entities
private static final Logger LOGGER = LogUtils.getLogger();
private static final BlockState DEFAULT_BLOCK_STATE = Blocks.SAND.defaultBlockState();
private static final int DEFAULT_TIME = 0;
@@ -75,12 +75,63 @@ public class FallingBlockEntity extends Entity {
public boolean autoExpire = true; // Paper - Expand FallingBlock API
public boolean heightParity; // Sakura - falling block height parity api
+ // Sakura start - merge cannon entities
+ private final me.samsuik.sakura.entity.merge.MergeEntityData mergeData = new me.samsuik.sakura.entity.merge.MergeEntityData(this);
+
+ @Override
+ public final me.samsuik.sakura.entity.merge.MergeEntityData getMergeEntityData() {
+ return this.mergeData;
+ }
+
+ @Override
+ public final boolean isSafeToMergeInto(final me.samsuik.sakura.entity.merge.MergeableEntity entity, final boolean ticksLived) {
+ return entity instanceof FallingBlockEntity fbe
+ && fbe.blockState.equals(this.blockState)
+ && (!ticksLived || fbe.time - 1 == this.time);
+ }
+
+ @Override
+ public final void respawnEntity(int count) {
+ while (count-- >= 1) {
+ // Unlike PrimedTnt we have to try respawn each stacked entity
+ final FallingBlockEntity fallingBlock = new FallingBlockEntity(EntityType.FALLING_BLOCK, this.level());
+
+ // Try to stack the falling block
+ this.entityState().apply(fallingBlock);
+ fallingBlock.blockState = this.blockState;
+ fallingBlock.spawnReason = this.spawnReason;
+ fallingBlock.time = this.time - 1;
+ fallingBlock.tick();
+
+ // If you horizontal stack into a moving piston block this condition will be met.
+ if (!fallingBlock.isRemoved()) {
+ this.mergeData.count = count + 1;
+ fallingBlock.storeEntityState();
+ fallingBlock.entityState().apply(this);
+ break;
+ } else if (count == 0) {
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN);
+ }
+ }
+ }
+
+ @Override
+ public @Nullable ItemEntity spawnAtLocation(final ServerLevel level, final net.minecraft.world.level.ItemLike item) { // may be overridden by plugins
+ ItemEntity itemEntity = null;
+ for (int i = 0; i < this.mergeData.count; ++i) {
+ itemEntity = super.spawnAtLocation(level, item);
+ }
+ return itemEntity;
+ }
+ // Sakura end - merge cannon entities
+
public FallingBlockEntity(EntityType<? extends FallingBlockEntity> entityType, Level level) {
super(entityType, level);
this.dropItem = level.sakuraConfig().cannons.sand.dropItems; // Sakura - configure falling blocks dropping items
this.heightParity = level.sakuraConfig().cannons.mechanics.fallingBlockParity; // Sakura - configure cannon mechanics
this.isFallingBlock = true; // Sakura - client visibility settings
this.loadChunks = level.sakuraConfig().cannons.loadChunks; // Sakura - load chunks on movement
+ this.mergeData.mergeLevel = level.sakuraConfig().cannons.mergeLevel; // Sakura - merge cannon entities
}
public FallingBlockEntity(Level level, double x, double y, double z, BlockState state) {
@@ -239,6 +290,7 @@ public class FallingBlockEntity extends Entity {
return;
}
// CraftBukkit end
+ if (this.tryToRespawnEntity()) return; // Sakura - merge cannon entities
if (this.level().setBlock(blockPos, this.blockState, 3)) {
serverLevel.getChunkSource()
.chunkMap
@@ -345,6 +397,11 @@ public class FallingBlockEntity extends Entity {
output.putBoolean("CancelDrop", this.cancelDrop);
if (!this.autoExpire) output.putBoolean("Paper.AutoExpire", false); // Paper - Expand FallingBlock API
+ // Sakura start - merge cannon entities; save to nbt
+ if (this.mergeData.count != 1) {
+ output.putInt("merge_count", this.mergeData.count);
+ }
+ // Sakura end - merge cannon entities; save to nbt
}
@Override
@@ -359,6 +416,7 @@ public class FallingBlockEntity extends Entity {
this.blockData = input.read("TileEntityData", CompoundTag.CODEC).map(blockData -> this.level().paperConfig().entities.spawning.filterBadTileEntityNbtFromFallingBlocks && this.blockState.getBlock() instanceof net.minecraft.world.level.block.GameMasterBlock ? null : blockData).map(CompoundTag::copy).orElse(null); // Paper - Filter bad block entity nbt data from falling blocks
this.cancelDrop = input.getBooleanOr("CancelDrop", false);
this.autoExpire = input.getBooleanOr("Paper.AutoExpire", true); // Paper - Expand FallingBlock API
+ this.mergeData.count = input.getIntOr("merge_count", 1); // Sakura - merge cannon entities; load from nbt
}
public void setHurtsEntities(float fallDamagePerDistance, int fallDamageMax) {
diff --git a/net/minecraft/world/entity/item/PrimedTnt.java b/net/minecraft/world/entity/item/PrimedTnt.java
index 6797e16f973b11d168906dfce240c70db25bc6f0..8a36e0ce4792e7152905256dde7746fd09d42729 100644
--- a/net/minecraft/world/entity/item/PrimedTnt.java
+++ b/net/minecraft/world/entity/item/PrimedTnt.java
@@ -34,7 +34,7 @@ import org.bukkit.event.entity.EntityRemoveEvent;
import org.bukkit.event.entity.ExplosionPrimeEvent;
// CraftBukkit end
-public class PrimedTnt extends Entity implements TraceableEntity {
+public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sakura.entity.merge.MergeableEntity { // Sakura - merge cannon entities
private static final EntityDataAccessor<Integer> DATA_FUSE_ID = SynchedEntityData.defineId(PrimedTnt.class, EntityDataSerializers.INT);
private static final EntityDataAccessor<BlockState> DATA_BLOCK_STATE_ID = SynchedEntityData.defineId(PrimedTnt.class, EntityDataSerializers.BLOCK_STATE);
private static final short DEFAULT_FUSE_TIME = 80;
@@ -60,11 +60,48 @@ public class PrimedTnt extends Entity implements TraceableEntity {
public float explosionPower = 4.0F;
public boolean isIncendiary = false; // CraftBukkit
+ // Sakura start - merge cannon entities
+ private final me.samsuik.sakura.entity.merge.MergeEntityData mergeData = new me.samsuik.sakura.entity.merge.MergeEntityData(this);
+
+ @Override
+ public final me.samsuik.sakura.entity.merge.MergeEntityData getMergeEntityData() {
+ return this.mergeData;
+ }
+
+ @Override
+ public final boolean isSafeToMergeInto(final me.samsuik.sakura.entity.merge.MergeableEntity entity, final boolean ticksLived) {
+ return entity instanceof PrimedTnt tnt
+ && tnt.getFuse() + 1 == this.getFuse()
+ // required to prevent issues with powdered snow
+ && (tnt.entityState().fallDistance() == this.fallDistance
+ || tnt.entityState().fallDistance() > 2.5f && this.fallDistance > 2.5f);
+ }
+
+ @Override
+ public final void respawnEntity(int count) {
+ final PrimedTnt tnt = new PrimedTnt(EntityType.TNT, this.level());
+ tnt.updateBukkitHandle(this); // update handle for plugins
+ while (count-- > 1) {
+ this.setFuse(100); // Prevent unwanted explosions while ticking
+
+ // Cause an explosion to affect this entity
+ tnt.setPos(this.position());
+ tnt.setDeltaMovement(this.getDeltaMovement());
+ this.entityState().apply(this);
+ tnt.explode();
+ this.storeEntityState();
+
+ this.tick();
+ }
+ }
+ // Sakura end - merge cannon entities
+
public PrimedTnt(EntityType<? extends PrimedTnt> entityType, Level level) {
super(entityType, level);
this.blocksBuilding = true;
this.isPrimedTNT = true; // Sakura - client visibility settings
this.loadChunks = level.sakuraConfig().cannons.loadChunks; // Sakura - load chunks on movement
+ this.mergeData.mergeLevel = level.sakuraConfig().cannons.mergeLevel; // Sakura - merge cannon entities
}
public PrimedTnt(Level level, double x, double y, double z, @Nullable LivingEntity owner) {
@@ -144,6 +181,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
if (i <= 0) {
// CraftBukkit start - Need to reverse the order of the explosion and the entity death so we have a location for the event
//this.discard();
+ this.tryToRespawnEntity(); // Sakura - merge cannon entities
if (!this.level().isClientSide()) {
this.explode();
}
@@ -203,6 +241,11 @@ public class PrimedTnt extends Entity implements TraceableEntity {
}
EntityReference.store(this.owner, output, "owner");
+ // Sakura start - merge cannon entities; save to nbt
+ if (this.mergeData.count != 1) {
+ output.putInt("merge_count", this.mergeData.count);
+ }
+ // Sakura end - merge cannon entities; save to nbt
}
@Override
@@ -211,6 +254,7 @@ public class PrimedTnt extends Entity implements TraceableEntity {
this.setBlockState(input.read("block_state", BlockState.CODEC).orElse(DEFAULT_BLOCK_STATE));
this.explosionPower = Mth.clamp(input.getFloatOr("explosion_power", 4.0F), 0.0F, 128.0F);
this.owner = EntityReference.read(input, "owner");
+ this.mergeData.count = input.getIntOr("merge_count", 1); // Sakura - merge cannon entities; load from nbt
}
@Nullable
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 5f49990b13ac7fdd4366585d976d50bd3ae183cb..93ff0fdaee21ac493833640b5f620f9bec1a69c8 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -833,6 +833,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
public final me.samsuik.sakura.listener.LevelTickScheduler levelTickScheduler = new me.samsuik.sakura.listener.LevelTickScheduler(this);
public final me.samsuik.sakura.listener.BlockChangeTracker blockChangeTracker = new me.samsuik.sakura.listener.BlockChangeTracker(this);
// Sakura end - track block changes and tick scheduler
+ public final me.samsuik.sakura.entity.merge.EntityMergeHandler mergeHandler = new me.samsuik.sakura.entity.merge.EntityMergeHandler(); // Sakura - merge cannon entities
protected Level(
WritableLevelData levelData,
diff --git a/net/minecraft/world/level/block/BasePressurePlateBlock.java b/net/minecraft/world/level/block/BasePressurePlateBlock.java
index 02289b88710f9305192e3fa7eed3e7c45eda1178..2ca8c39c4883ff7f398ed931d560e7cfcf474e1a 100644
--- a/net/minecraft/world/level/block/BasePressurePlateBlock.java
+++ b/net/minecraft/world/level/block/BasePressurePlateBlock.java
@@ -92,7 +92,7 @@ public abstract class BasePressurePlateBlock extends Block {
}
private void checkPressed(@Nullable Entity entity, Level level, BlockPos pos, BlockState state, int currentSignal) {
- int signalStrength = this.getSignalStrength(level, pos);
+ int signalStrength = this.getSignalStrength(level, pos, currentSignal == 0); // Sakura - merge cannon entities
boolean flag = currentSignal > 0;
boolean flag1 = signalStrength > 0;
@@ -162,6 +162,12 @@ public abstract class BasePressurePlateBlock extends Block {
// CraftBukkit end
}
+ // Sakura start - merge cannon entities
+ protected int getSignalStrength(final Level world, final BlockPos pos, final boolean entityInside) {
+ return this.getSignalStrength(world, pos);
+ }
+ // Sakura end - merge cannon entities
+
protected abstract int getSignalStrength(Level level, BlockPos pos);
protected abstract int getSignalForState(BlockState state);
diff --git a/net/minecraft/world/level/block/WeightedPressurePlateBlock.java b/net/minecraft/world/level/block/WeightedPressurePlateBlock.java
index 5e095919828e89d12f2676b3c544842a81e047a1..e45ceec307a4944f40d044af0369d0c598a4e9ae 100644
--- a/net/minecraft/world/level/block/WeightedPressurePlateBlock.java
+++ b/net/minecraft/world/level/block/WeightedPressurePlateBlock.java
@@ -39,6 +39,13 @@ public class WeightedPressurePlateBlock extends BasePressurePlateBlock {
@Override
protected int getSignalStrength(Level level, BlockPos pos) {
+ // Sakura start - merge cannon entities
+ return this.getSignalStrength(level, pos, false);
+ }
+
+ @Override
+ protected final int getSignalStrength(final Level level, final BlockPos pos, final boolean entityInside) {
+ // Sakura end - merge cannon entities
// CraftBukkit start
// int min = Math.min(getEntityCount(level, TOUCH_AABB.move(pos), Entity.class), this.maxWeight);
int min = 0;
@@ -54,7 +61,7 @@ public class WeightedPressurePlateBlock extends BasePressurePlateBlock {
// We only want to block turning the plate on if all events are cancelled
if (!cancellable.isCancelled()) {
- min++;
+ min += !entityInside && entity instanceof me.samsuik.sakura.entity.merge.MergeableEntity mergeEntity ? mergeEntity.getMergeEntityData().count : 1; // Sakura - merge cannon entities
}
}
// CraftBukkit end