diff --git a/patches/server/0002-Sakura-Utils.patch b/patches/server/0002-Sakura-Utils.patch index 6be4192..31cac87 100644 --- a/patches/server/0002-Sakura-Utils.patch +++ b/patches/server/0002-Sakura-Utils.patch @@ -35,6 +35,66 @@ index 0000000000000000000000000000000000000000..54292c693f89ee1444f8b22f4c1488e9 + } + +} +diff --git a/src/main/java/me/samsuik/sakura/utils/collections/FixedSizeCustomObjectTable.java b/src/main/java/me/samsuik/sakura/utils/collections/FixedSizeCustomObjectTable.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e97f3cc00945f79026af894685d6104dfc920a35 +--- /dev/null ++++ b/src/main/java/me/samsuik/sakura/utils/collections/FixedSizeCustomObjectTable.java +@@ -0,0 +1,54 @@ ++package me.samsuik.sakura.utils.collections; ++ ++import it.unimi.dsi.fastutil.HashCommon; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++import java.util.function.ToIntFunction; ++ ++public final class FixedSizeCustomObjectTable { ++ private final ToIntFunction keyFunction; ++ private final T[] contents; ++ private final int mask; ++ ++ public FixedSizeCustomObjectTable(int size, @NotNull ToIntFunction keyFunction) { ++ if (size < 0) { ++ throw new IllegalArgumentException("Table size cannot be negative"); ++ } else { ++ int n = HashCommon.nextPowerOfTwo(size - 1); ++ this.keyFunction = keyFunction; ++ this.contents = (T[]) new Object[n]; ++ this.mask = (n - 1); ++ } ++ } ++ ++ private int key(T value) { ++ return this.keyFunction.applyAsInt(value); ++ } ++ ++ public @Nullable T get(T value) { ++ return this.get(this.key(value)); ++ } ++ ++ public @Nullable T get(int key) { ++ return this.contents[key & this.mask]; ++ } ++ ++ public void write(int key, T value) { ++ this.contents[key & this.mask] = value; ++ } ++ ++ public @Nullable T getAndWrite(T value) { ++ int key = this.key(value); ++ T found = this.get(key); ++ this.write(key, value); ++ return found; ++ } ++ ++ public void clear() { ++ int size = this.contents.length; ++ for (int i = 0; i < size; ++i) { ++ this.contents[i] = null; ++ } ++ } ++} diff --git a/src/main/java/me/samsuik/sakura/utils/collections/OrderedComparatorList.java b/src/main/java/me/samsuik/sakura/utils/collections/OrderedComparatorList.java new file mode 100644 index 0000000000000000000000000000000000000000..239fc8823b32ae5c8f6e3bfd6ecdde0ccd1e5a8b diff --git a/patches/server/0017-Merge-Cannon-Entities.patch b/patches/server/0017-Merge-Cannon-Entities.patch index 8378bf0..3635062 100644 --- a/patches/server/0017-Merge-Cannon-Entities.patch +++ b/patches/server/0017-Merge-Cannon-Entities.patch @@ -4,184 +4,393 @@ Date: Sat, 9 Sep 2023 18:39:15 +0100 Subject: [PATCH] Merge Cannon Entities -diff --git a/src/main/java/me/samsuik/sakura/entity/merge/MergeHistory.java b/src/main/java/me/samsuik/sakura/entity/merge/MergeHistory.java +diff --git a/src/main/java/me/samsuik/sakura/entity/merge/EntityMergeHandler.java b/src/main/java/me/samsuik/sakura/entity/merge/EntityMergeHandler.java new file mode 100644 -index 0000000000000000000000000000000000000000..7d899163b308f52b48bf72a1e9cd38d565bbe05d +index 0000000000000000000000000000000000000000..211b65246169785bce3c69ebc4ac9b4f39231605 --- /dev/null -+++ b/src/main/java/me/samsuik/sakura/entity/merge/MergeHistory.java -@@ -0,0 +1,56 @@ ++++ b/src/main/java/me/samsuik/sakura/entity/merge/EntityMergeHandler.java +@@ -0,0 +1,67 @@ ++package me.samsuik.sakura.entity.merge; ++ ++import net.minecraft.world.entity.Entity; ++import org.jetbrains.annotations.NotNull; ++import org.jetbrains.annotations.Nullable; ++ ++public final class EntityMergeHandler { ++ private final TrackedMergeHistory trackedHistory = new TrackedMergeHistory(); ++ ++ /** ++ * Tries to merge the provided entities using the {@link MergeStrategy}. ++ * ++ * @param previous the last entity to tick ++ * @param entity the entity being merged ++ * @return success ++ */ ++ public boolean tryMerge(@Nullable Entity entity, @Nullable Entity previous) { ++ if (entity instanceof MergeableEntity mergeEntity && previous instanceof MergeableEntity) { ++ MergeEntityData mergeEntityData = mergeEntity.getMergeEntityData(); ++ MergeStrategy strategy = MergeStrategy.from(mergeEntityData.getMergeLevel()); ++ Entity into = strategy.mergeEntity(entity, previous, this.trackedHistory); ++ if (into instanceof MergeableEntity intoEntity && !into.isRemoved() && mergeEntity.isSafeToMergeInto(into, strategy.trackHistory())) { ++ return this.mergeEntity(mergeEntity, intoEntity); ++ } ++ } ++ ++ return false; ++ } ++ ++ /** ++ * Stores the merged data of the provided entities if the {@link MergeStrategy} requires it. ++ * ++ * @param entity provided entity ++ */ ++ public void removeEntity(@Nullable Entity entity) { ++ if (entity instanceof MergeableEntity mergeEntity) { ++ MergeEntityData mergeEntityData = mergeEntity.getMergeEntityData(); ++ MergeStrategy strategy = MergeStrategy.from(mergeEntityData.getMergeLevel()); ++ if (mergeEntityData.hasMerged() && strategy.trackHistory()) { ++ this.trackedHistory.trackHistory(entity, mergeEntityData); ++ } ++ } ++ } ++ ++ /** ++ * Called every tick and provided the current server tick to remove any unneeded merge history. ++ * ++ * @param tick server tick ++ */ ++ public void expire(long tick) { ++ if (tick % 200 == 0) { ++ this.trackedHistory.expire(tick); ++ } ++ } ++ ++ private boolean mergeEntity(@NotNull MergeableEntity mergeEntity, @NotNull MergeableEntity into) { ++ MergeEntityData entities = mergeEntity.getMergeEntityData(); ++ MergeEntityData mergeInto = into.getMergeEntityData(); ++ mergeInto.mergeWith(entities); // merge entities together ++ ++ // discard the entity and update the bukkit handle ++ Entity nmsEntity = (Entity) mergeEntity; ++ nmsEntity.discard(); ++ nmsEntity.updateBukkitHandle((Entity) into); ++ return true; ++ } ++} +diff --git a/src/main/java/me/samsuik/sakura/entity/merge/MergeCondition.java b/src/main/java/me/samsuik/sakura/entity/merge/MergeCondition.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6c0c224bc30c9c75d4b82508661117ce16197680 +--- /dev/null ++++ b/src/main/java/me/samsuik/sakura/entity/merge/MergeCondition.java +@@ -0,0 +1,16 @@ ++package me.samsuik.sakura.entity.merge; ++ ++import net.minecraft.world.entity.Entity; ++import org.jetbrains.annotations.NotNull; ++ ++public interface MergeCondition { ++ default MergeCondition and(@NotNull MergeCondition condition) { ++ return (e,c,t) -> this.accept(e,c,t) && condition.accept(e,c,t); ++ } ++ ++ default MergeCondition or(@NotNull MergeCondition condition) { ++ return (e,c,t) -> this.accept(e,c,t) || condition.accept(e,c,t); ++ } ++ ++ boolean accept(@NotNull Entity entity, int attempts, long sinceCreation); ++} +diff --git a/src/main/java/me/samsuik/sakura/entity/merge/MergeEntityData.java b/src/main/java/me/samsuik/sakura/entity/merge/MergeEntityData.java +new file mode 100644 +index 0000000000000000000000000000000000000000..db215f9d624fb484059db1f86609847ac7a2be0b +--- /dev/null ++++ b/src/main/java/me/samsuik/sakura/entity/merge/MergeEntityData.java +@@ -0,0 +1,51 @@ ++package me.samsuik.sakura.entity.merge; ++ ++import it.unimi.dsi.fastutil.longs.LongOpenHashSet; ++import net.minecraft.world.entity.Entity; ++import org.jetbrains.annotations.NotNull; ++ ++public final class MergeEntityData { ++ private final Entity entity; ++ private MergeEntityData linked; ++ private int count = 1; ++ private MergeLevel mergeLevel = MergeLevel.NONE; ++ ++ public MergeEntityData(Entity entity) { ++ this.entity = entity; ++ } ++ ++ public void mergeWith(@NotNull MergeEntityData mergeEntityData) { ++ this.linked = mergeEntityData; ++ this.count += mergeEntityData.getCount(); ++ mergeEntityData.setCount(0); ++ } ++ ++ public LongOpenHashSet getOriginPositions() { ++ LongOpenHashSet positions = new LongOpenHashSet(); ++ MergeEntityData next = this; ++ do { ++ positions.add(next.entity.getPackedOriginPosition()); ++ } while ((next = next.linked) != null); ++ return positions; ++ } ++ ++ public boolean hasMerged() { ++ return this.linked != null; ++ } ++ ++ public void setMergeLevel(MergeLevel mergeLevel) { ++ this.mergeLevel = mergeLevel; ++ } ++ ++ public MergeLevel getMergeLevel() { ++ return mergeLevel; ++ } ++ ++ public void setCount(int count) { ++ this.count = count; ++ } ++ ++ public int getCount() { ++ return this.count; ++ } ++} +diff --git a/src/main/java/me/samsuik/sakura/entity/merge/MergeStrategy.java b/src/main/java/me/samsuik/sakura/entity/merge/MergeStrategy.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1ce8b8a54f80039c2f50496021494fbd0d81a82f +--- /dev/null ++++ b/src/main/java/me/samsuik/sakura/entity/merge/MergeStrategy.java +@@ -0,0 +1,118 @@ ++package me.samsuik.sakura.entity.merge; ++ ++import me.samsuik.sakura.utils.collections.FixedSizeCustomObjectTable; ++import net.minecraft.world.entity.Entity; ++import net.minecraft.world.level.entity.EntityTickList; ++import org.jetbrains.annotations.NotNull; ++ ++public interface MergeStrategy { ++ /** ++ * If this merge strategy requires the merge history to be tracked. ++ * ++ * @return should track history ++ */ ++ boolean trackHistory(); ++ ++ /** ++ * Tries to merge the first entity into another entity. ++ *

++ * The first entity should always be positioned right after the second entity in the ++ * {@link EntityTickList}. This method should only ++ * be called before the first entity and after the second entity has ticked. ++ * ++ * @param entity current entity ++ * @param previous last entity to tick ++ * @return success ++ */ ++ Entity mergeEntity(@NotNull Entity entity, @NotNull Entity previous, @NotNull TrackedMergeHistory mergeHistory); ++ ++ /** ++ * Gets the {@link MergeStrategy} for the {@link MergeLevel}. ++ * ++ * @param level provided level ++ * @return strategy ++ */ ++ static MergeStrategy from(MergeLevel level) { ++ return switch (level) { ++ case NONE -> None.INSTANCE; ++ case STRICT -> Strict.INSTANCE; ++ case LENIENT -> Lenient.INSTANCE; ++ case SPAWN -> Spawn.INSTANCE; ++ }; ++ } ++ ++ final class None implements MergeStrategy { ++ private static final None INSTANCE = new None(); ++ ++ @Override ++ public boolean trackHistory() { ++ return false; ++ } ++ ++ @Override ++ public Entity mergeEntity(@NotNull Entity entity, @NotNull Entity previous, @NotNull TrackedMergeHistory mergeHistory) { ++ return null; ++ } ++ } ++ ++ final class Strict implements MergeStrategy { ++ private static final Strict INSTANCE = new Strict(); ++ ++ @Override ++ public boolean trackHistory() { ++ return false; ++ } ++ ++ @Override ++ public Entity mergeEntity(@NotNull Entity entity, @NotNull Entity previous, @NotNull TrackedMergeHistory mergeHistory) { ++ return entity.compareState(previous) ? previous : null; ++ } ++ } ++ ++ final class Lenient implements MergeStrategy { ++ private static final Lenient INSTANCE = new Lenient(); ++ private final FixedSizeCustomObjectTable entityTable = new FixedSizeCustomObjectTable<>(512, entity -> { ++ return entity.blockPosition().hashCode(); ++ }); ++ ++ @Override ++ public boolean trackHistory() { ++ return true; ++ } ++ ++ @Override ++ public Entity mergeEntity(@NotNull Entity entity, @NotNull Entity previous, @NotNull TrackedMergeHistory mergeHistory) { ++ if (entity.compareState(previous)) { ++ return previous; ++ } ++ ++ Entity nextEntity = this.entityTable.getAndWrite(entity); ++ if (nextEntity == null || !nextEntity.level().equals(entity.level())) { ++ return null; ++ } ++ ++ return mergeHistory.hasPreviousMerged(entity, nextEntity) && entity.compareState(nextEntity) ? nextEntity : null; ++ } ++ } ++ ++ final class Spawn implements MergeStrategy { ++ private static final Spawn INSTANCE = new Spawn(); ++ private static final MergeCondition CONDITION = (e, shots, time) -> (shots > 16 || time >= 200); ++ ++ @Override ++ public boolean trackHistory() { ++ return true; ++ } ++ ++ @Override ++ public Entity mergeEntity(@NotNull Entity entity, @NotNull Entity previous, @NotNull TrackedMergeHistory mergeHistory) { ++ final Entity mergeInto; ++ if (entity.tickCount == 1 && mergeHistory.hasMetCondition(entity, CONDITION) && mergeHistory.hasPreviousMerged(entity, previous)) { ++ mergeInto = previous; ++ } else { ++ mergeInto = entity.compareState(previous) ? previous : null; ++ } ++ return mergeInto; ++ } ++ } ++} +diff --git a/src/main/java/me/samsuik/sakura/entity/merge/MergeableEntity.java b/src/main/java/me/samsuik/sakura/entity/merge/MergeableEntity.java +new file mode 100644 +index 0000000000000000000000000000000000000000..81b1aaa4d6718d92e4011501f55be2ab520198d9 +--- /dev/null ++++ b/src/main/java/me/samsuik/sakura/entity/merge/MergeableEntity.java +@@ -0,0 +1,23 @@ ++package me.samsuik.sakura.entity.merge; ++ ++import net.minecraft.world.entity.Entity; ++import org.jetbrains.annotations.NotNull; ++ ++public interface MergeableEntity { ++ @NotNull MergeEntityData getMergeEntityData(); ++ ++ boolean isSafeToMergeInto(@NotNull Entity entity, boolean ticksLived); ++ ++ default boolean respawnEntity() { ++ MergeEntityData mergeData = this.getMergeEntityData(); ++ int count = mergeData.getCount(); ++ if (count > 1) { ++ mergeData.setCount(0); ++ this.respawnEntity(count); ++ return true; ++ } ++ return false; ++ } ++ ++ void respawnEntity(int count); ++} +diff --git a/src/main/java/me/samsuik/sakura/entity/merge/TrackedMergeHistory.java b/src/main/java/me/samsuik/sakura/entity/merge/TrackedMergeHistory.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c78bf4fc13da8238f59bde7de9f04642eba074ae +--- /dev/null ++++ b/src/main/java/me/samsuik/sakura/entity/merge/TrackedMergeHistory.java +@@ -0,0 +1,62 @@ +package me.samsuik.sakura.entity.merge; + +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.world.entity.Entity; -+ -+import java.util.List; -+ -+public final class MergeHistory { -+ -+ // packed position -> known merging information -+ private final Long2ObjectMap mergeDataMap = new Long2ObjectOpenHashMap<>(); -+ private SpawnPositionData mergeData = null; -+ -+ public SpawnPositionData retrievePositions(Entity entity) { -+ long origin = entity.getPackedOrigin(); -+ -+ if (mergeData != null && mergeData.isPositionKnown(origin)) { -+ return mergeData; -+ } -+ -+ return mergeData = mergeDataMap.get(origin); -+ } -+ -+ public void markPositions(Entity entity) { -+ List mergeList = entity.getMergeList(); -+ long origin = entity.getPackedOrigin(); -+ -+ // After a merged entity has been discarded store all the position data -+ SpawnPositionData data = mergeDataMap.computeIfAbsent(origin, p -> new SpawnPositionData(mergeList)); -+ data.getExpiry().refresh(MinecraftServer.currentTickLong); -+ -+ // Collect all merge positions -+ LongOpenHashSet positions = new LongOpenHashSet((mergeList.size() + 1) / 2); -+ positions.add(entity.getPackedOrigin()); -+ -+ for (Entity mergedEntity : mergeList) { -+ positions.add(mergedEntity.getPackedOrigin()); -+ } -+ -+ // Retain existing positions or insert new positions -+ data.retainOrInsertPositions(positions); -+ } -+ -+ public void expire(long tick) { -+ mergeData = null; // clear this every tick -+ -+ // only expire every 20 ticks -+ if (tick % 20 != 0) return; -+ -+ mergeDataMap.values().removeIf(data -> data.getExpiry().isExpired(tick)); -+ } -+ -+} -diff --git a/src/main/java/me/samsuik/sakura/entity/merge/MergeThreshold.java b/src/main/java/me/samsuik/sakura/entity/merge/MergeThreshold.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4d08af1a7ff0ebc2b1198513c86c08087d9d6e89 ---- /dev/null -+++ b/src/main/java/me/samsuik/sakura/entity/merge/MergeThreshold.java -@@ -0,0 +1,26 @@ -+package me.samsuik.sakura.entity.merge; -+ -+/** -+ * Threshold for AOT/on spawn merging. -+ *

-+ * This is determined by the amount of spawn attempts over time. -+ */ -+public final class MergeThreshold { -+ -+ private final long startingTick; -+ private final int thresholdAttempts; -+ private final long thresholdAge; -+ private int attempts; -+ -+ public MergeThreshold(long tick, int attempts, long age) { -+ startingTick = tick; -+ thresholdAttempts = attempts; -+ thresholdAge = age; -+ } -+ -+ public boolean hasPassed(long tick) { -+ return ++attempts >= thresholdAttempts -+ || tick - startingTick >= thresholdAge; -+ } -+ -+} -diff --git a/src/main/java/me/samsuik/sakura/entity/merge/SpawnPositionData.java b/src/main/java/me/samsuik/sakura/entity/merge/SpawnPositionData.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e63935c17e213bf60571d120ad9ce311b5249d45 ---- /dev/null -+++ b/src/main/java/me/samsuik/sakura/entity/merge/SpawnPositionData.java -@@ -0,0 +1,64 @@ -+package me.samsuik.sakura.entity.merge; -+ -+import it.unimi.dsi.fastutil.longs.LongOpenHashSet; -+import it.unimi.dsi.fastutil.longs.LongSet; -+import me.samsuik.sakura.utils.collections.EntityTable; +import me.samsuik.sakura.utils.objects.Expiry; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.entity.Entity; ++import org.jetbrains.annotations.NotNull; + -+import java.util.List; ++public final class TrackedMergeHistory { ++ private final Long2ObjectMap historyMap = new Long2ObjectOpenHashMap<>(); + -+/** -+ * Contains all the positions that past entities of the same origin have merged with. -+ */ -+public final class SpawnPositionData { -+ -+ private final LongSet knownPositions = new LongOpenHashSet(); -+ private final LongSet retainedPositions = new LongOpenHashSet(); -+ -+ private final EntityTable table; -+ private final Expiry expiry = new Expiry(MinecraftServer.currentTickLong, 200); -+ private final MergeThreshold threshold = new MergeThreshold(MinecraftServer.currentTickLong, 12, 200); -+ -+ public SpawnPositionData(List mergeList) { -+ this.table = new EntityTable(mergeList.size()); ++ public boolean hasPreviousMerged(@NotNull Entity entity, @NotNull Entity into) { ++ long entityPosition = entity.getPackedOriginPosition(); ++ long intoPosition = into.getPackedOriginPosition(); ++ PositionHistory positions = this.historyMap.get(intoPosition); ++ return positions.has(entityPosition); + } + -+ public Expiry getExpiry() { -+ return expiry; ++ public void trackHistory(@NotNull Entity entity, @NotNull MergeEntityData mergeEntityData) { ++ long originPosition = entity.getPackedOriginPosition(); ++ PositionHistory positions = this.historyMap.computeIfAbsent(originPosition, p -> new PositionHistory()); ++ positions.trackPositions(mergeEntityData.getOriginPositions()); + } + -+ public void retainOrInsertPositions(LongOpenHashSet positions) { -+ if (!knownPositions.isEmpty()) { -+ retainedPositions.addAll(positions); -+ } else { -+ retainedPositions.retainAll(positions); ++ public boolean hasMetCondition(@NotNull Entity entity, MergeCondition condition) { ++ long originPosition = entity.getPackedOriginPosition(); ++ PositionHistory positions = this.historyMap.get(originPosition); ++ return positions != null && positions.hasMetConditions(entity, condition); ++ } ++ ++ public void expire(long tick) { ++ this.historyMap.values().removeIf(p -> p.expiry().isExpired(tick)); ++ } ++ ++ private static final class PositionHistory { ++ private final LongOpenHashSet positions = new LongOpenHashSet(); ++ private final Expiry expiry = new Expiry(MinecraftServer.currentTickLong, 200); ++ private final long created = MinecraftServer.currentTickLong; ++ private int cycles = 0; ++ ++ public Expiry expiry() { ++ return this.expiry; + } + -+ knownPositions.addAll(positions); -+ } -+ -+ public boolean isPositionKnown(long pos) { -+ return knownPositions.contains(pos); -+ } -+ -+ public boolean isPositionRetained(long pos) { -+ return retainedPositions.contains(pos); -+ } -+ -+ public boolean isAbleToOnSpawnMerge() { -+ return threshold.hasPassed(MinecraftServer.currentTickLong); -+ } -+ -+ public Entity findFirstEntityInSamePosition(Entity entity) { -+ Entity found = table.locate(entity); -+ -+ if (found != null && found.getId() < entity.getId() && knownPositions.contains(found.getPackedOrigin()) && !found.isRemoved() && entity.compareState(found)) { -+ return found; ++ public boolean has(long position) { ++ this.expiry.refresh(MinecraftServer.currentTickLong); ++ return this.positions.contains(position); + } + -+ return null; -+ } ++ public void trackPositions(LongOpenHashSet positions) { ++ this.positions.addAll(positions); ++ this.cycles++; ++ } + ++ public boolean hasMetConditions(@NotNull Entity entity, @NotNull MergeCondition condition) { ++ long timeSinceCreation = MinecraftServer.currentTickLong - this.created; ++ return condition.accept(entity, this.cycles, timeSinceCreation); ++ } ++ } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 564278107e38b2a1adb03dab4c92a6ed20fd1d4e..0a6a39672859aa4b70dacafc168250941f8d96d8 100644 +index 564278107e38b2a1adb03dab4c92a6ed20fd1d4e..b0e95e1dbf3248101d63bd2c0f9ba05e720623c6 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1817,6 +1817,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop youngest) -+ private final List mergeList = new java.util.ArrayList<>(1); -+ private @Nullable me.samsuik.sakura.entity.merge.SpawnPositionData originData = null; -+ private me.samsuik.sakura.entity.merge.MergeLevel mergeLevel; -+ protected int stacked = 1; // default -+ -+ public final me.samsuik.sakura.entity.merge.MergeLevel getMergeLevel() { -+ return mergeLevel; -+ } -+ -+ public final void setMergeLevel(me.samsuik.sakura.entity.merge.MergeLevel level) { -+ mergeLevel = level; -+ } -+ -+ public final int getStacked() { -+ return stacked; -+ } -+ -+ public final void setStacked(int stack) { -+ stacked = stack; -+ } -+ -+ public final List getMergeList() { -+ return mergeList; -+ } -+ -+ public final long getPackedOrigin() { -+ var v = getOriginVector(); -+ if (v == null) return Long.MIN_VALUE; -+ // Note: vector#getBlockN may not be 100% exact -+ // If there's any future issues at let's say 0.999999... -+ // giving an incorrect position change it to Mth instead. -+ return BlockPos.asLong(v.getBlockX(), v.getBlockY(), v.getBlockZ()); -+ } -+ -+ private boolean isSafeToSpawnMerge(Entity entity) { -+ return tickCount == 1 && originData != null -+ && originData.isAbleToOnSpawnMerge() // on spawn safety delay has passed -+ && originData == entity.originData // make sure it's the same group -+ && originData.isPositionRetained(entity.getPackedOrigin()); -+ } -+ -+ public boolean isMergeableType(@Nullable Entity previous) { -+ return false; -+ } -+ -+ public final boolean tryMergeInto(@Nullable Entity entity) { -+ if (mergeLevel.atLeast(me.samsuik.sakura.entity.merge.MergeLevel.LENIENT) && tickCount == 0) { -+ originData = level.mergeHistory.retrievePositions(this); ++ public final void updateBukkitHandle(Entity entity) { ++ if (this.bukkitEntity != null) { ++ this.bukkitEntity.setHandle(entity); + } ++ this.bukkitEntity = entity.getBukkitEntity(); ++ } + -+ Entity mergeEntity = null; -+ -+ if (entity == null || entity.getType() != getType()) { -+ return false; // First entity -+ } else if (mergeLevel.atLeast(me.samsuik.sakura.entity.merge.MergeLevel.SPAWN) && entity.isSafeToSpawnMerge(this)) { -+ // "SPAWN" merges entities one gametick after they have spawned. Merging is -+ // only possible after it has been established that the entity is safe to -+ // merge by collecting information on the entities that merge together over time. -+ mergeEntity = entity; ++ public final long getPackedOriginPosition() { ++ org.bukkit.util.Vector origin = this.getOriginVector(); ++ if (origin != null) { ++ return BlockPos.asLong(origin.getBlockX(), origin.getBlockY(), origin.getBlockZ()); + } else { -+ // "STRICT" merges entities with the same properties, position, momentum and OOE. -+ // This is considered safe to use, and will not break cannon mechanics. -+ if (mergeLevel.atLeast(me.samsuik.sakura.entity.merge.MergeLevel.STRICT) && compareState(entity)) { -+ mergeEntity = entity; -+ } -+ -+ // "LENIENT" merges entities aggressively by tracking the entities that have -+ // previously merged. This is a hybrid of "SPAWN" and "STRICT" merging, with the -+ // visuals of "STRICT" merging and better merging potential of "SPAWN" merging. -+ if (mergeLevel.atLeast(me.samsuik.sakura.entity.merge.MergeLevel.LENIENT) && mergeEntity == null && originData != null) { -+ mergeEntity = originData.findFirstEntityInSamePosition(this); -+ } -+ } -+ -+ if (mergeEntity != null && isSafeToMergeInto(mergeEntity)) { -+ mergeInto(mergeEntity); -+ return true; -+ } -+ -+ return false; -+ } -+ -+ protected boolean respawnMerged() { -+ return false; -+ } -+ -+ public boolean isSafeToMergeInto(Entity entity) { -+ return false; -+ } -+ -+ private void mergeInto(Entity entity) { -+ entity.mergeList.add(this); -+ entity.mergeList.addAll(mergeList); -+ entity.stacked += stacked; -+ -+ mergeList.clear(); // clear the list to stop our tracking when merging -+ stacked = 0; // prevent any possible duplication -+ -+ discard(null); // MERGE is appropriate here but plugins may not expect tnt or falling blocks to merge -+ -+ // update api handle, this is so cannondebug can function -+ //noinspection ConstantValue -+ if (bukkitEntity != null) { -+ bukkitEntity.setHandle(entity); -+ bukkitEntity = entity.bukkitEntity; ++ return Long.MIN_VALUE; + } + } + // Sakura end - merge cannon entities public Entity(EntityType type, Level world) { this.id = Entity.ENTITY_COUNTER.incrementAndGet(); -@@ -636,6 +746,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - this.entityData = datawatcher_a.build(); - this.setPos(0.0D, 0.0D, 0.0D); - this.eyeHeight = this.dimensions.eyeHeight(); -+ this.mergeLevel = level.sakuraConfig().cannons.mergeLevel; // Sakura - } +@@ -4928,6 +4945,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - public boolean isColliding(BlockPos pos, BlockState state) { -@@ -2594,6 +2705,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - nbttagcompound.putBoolean("Paper.FreezeLock", true); - } - // Paper end -+ // Sakura start -+ if (stacked > 0) { -+ nbttagcompound.putInt("Sakura.Stacked", stacked); -+ } -+ // Sakura end - return nbttagcompound; - } catch (Throwable throwable) { - CrashReport crashreport = CrashReport.forThrowable(throwable, "Saving entity NBT"); -@@ -2741,6 +2857,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - freezeLocked = nbt.getBoolean("Paper.FreezeLock"); - } - // Paper end -+ // Sakura start -+ if (nbt.contains("Sakura.Stacked")) { -+ stacked = nbt.getInt("Sakura.Stacked"); -+ } -+ // Sakura end - - } catch (Throwable throwable) { - CrashReport crashreport = CrashReport.forThrowable(throwable, "Loading entity NBT"); -@@ -4917,6 +5038,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - // Paper end - rewrite chunk system - CraftEventFactory.callEntityRemoveEvent(this, cause); - // CraftBukkit end -+ // Sakura start -+ if (entity_removalreason == RemovalReason.DISCARDED && !mergeList.isEmpty()) { -+ level.mergeHistory.markPositions(this); + if (this.removalReason != Entity.RemovalReason.UNLOADED_TO_CHUNK) { this.getPassengers().forEach(Entity::stopRiding); } // Paper - rewrite chunk system + this.levelCallback.onRemove(entity_removalreason); ++ // Sakura start - merge cannon entities ++ if (entity_removalreason == RemovalReason.DISCARDED) { ++ this.level.mergeHandler.removeEntity(this); + } -+ // Sakura end - final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers - if (this.removalReason == null) { - this.removalReason = entity_removalreason; ++ // Sakura end - merge cannon entities + // Paper start - Folia schedulers + if (!(this instanceof ServerPlayer) && entity_removalreason != RemovalReason.CHANGED_DIMENSION && !alreadyRemoved) { + // Players need to be special cased, because they are regularly removed from the world diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -index 0458d965ca266606f922bf1b03b729810a3948a4..d15d4ddc99ddc2c37efc4e0b43ab51c0abc915a9 100644 +index 0458d965ca266606f922bf1b03b729810a3948a4..172f82631e2ce3bfe791d7e8f2e841cca5a51667 100644 --- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -@@ -137,6 +137,59 @@ public class FallingBlockEntity extends Entity { - return !this.isRemoved(); - } +@@ -57,7 +57,7 @@ import org.bukkit.craftbukkit.event.CraftEventFactory; + import org.bukkit.event.entity.EntityRemoveEvent; + // CraftBukkit end + +-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(); + public BlockState blockState; +@@ -73,6 +73,57 @@ public class FallingBlockEntity extends Entity { + protected static final EntityDataAccessor DATA_START_POS = SynchedEntityData.defineId(FallingBlockEntity.class, EntityDataSerializers.BLOCK_POS); + public boolean autoExpire = true; // Paper - Expand FallingBlock 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 boolean isMergeableType(@Nullable Entity previous) { -+ return previous == null || !isRemoved() && !previous.isRemoved(); ++ public final me.samsuik.sakura.entity.merge.MergeEntityData getMergeEntityData() { ++ return this.mergeData; + } + + @Override -+ public final boolean isSafeToMergeInto(Entity entity) { ++ public final boolean isSafeToMergeInto(Entity entity, boolean ticksLived) { + return entity instanceof FallingBlockEntity fbe -+ && fbe.blockState.equals(blockState) -+ && fbe.time - 1 == time; // todo: special case in case on spawn isn't used ++ && fbe.blockState.equals(this.blockState) ++ && (!ticksLived || fbe.time - 1 == this.time); + } + + @Override -+ protected final boolean respawnMerged() { -+ if (stacked <= 1) return false; -+ -+ while (stacked-- >= 1) { ++ public final void respawnEntity(int count) { ++ while (count-- >= 1) { + // Unlike PrimedTnt we have to try respawn each stacked entity -+ FallingBlockEntity fallingBlock = new FallingBlockEntity(EntityType.FALLING_BLOCK, level()); ++ FallingBlockEntity fallingBlock = new FallingBlockEntity(EntityType.FALLING_BLOCK, this.level()); + + // Try to stack the falling block + this.entityState().apply(fallingBlock); -+ fallingBlock.spawnReason = spawnReason; -+ fallingBlock.time = time - 1; ++ 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()) { -+ stacked++; ++ this.mergeData.setCount(count + 1); + fallingBlock.storeEntityState(); + fallingBlock.entityState().apply(this); + break; -+ } else if (stacked == 0) { ++ } else if (count == 0) { + this.discard(EntityRemoveEvent.Cause.DESPAWN); + } + } -+ -+ return true; + } + + @Nullable + public ItemEntity spawnAtLocation(ItemLike item) { // may be overridden by plugins + ItemEntity itemEntity = null; + -+ while (stacked-- >= 1) { ++ for (int i = 0; i < this.mergeData.getCount(); ++i) { + itemEntity = super.spawnAtLocation(item); + } + @@ -434,47 +525,84 @@ index 0458d965ca266606f922bf1b03b729810a3948a4..d15d4ddc99ddc2c37efc4e0b43ab51c0 + } + // Sakura end - merge cannon entities + - @Override - protected double getDefaultGravity() { - return 0.04D; -@@ -207,6 +260,7 @@ public class FallingBlockEntity extends Entity { + public FallingBlockEntity(EntityType type, Level world) { + super(type, world); + this.blockState = Blocks.SAND.defaultBlockState(); +@@ -80,6 +131,7 @@ public class FallingBlockEntity extends Entity { + this.fallDamageMax = 40; + this.isFallingBlock = true; // Sakura + this.loadChunks = world.sakuraConfig().cannons.loadChunks; // Sakura - load chunks on movement ++ this.mergeData.setMergeLevel(world.sakuraConfig().cannons.mergeLevel); // Sakura - merge cannon entities + } + + public FallingBlockEntity(Level world, double x, double y, double z, BlockState block) { +@@ -207,6 +259,7 @@ public class FallingBlockEntity extends Entity { return; } // CraftBukkit end -+ if (this.respawnMerged()) return; // Sakura ++ if (this.respawnEntity()) return; // Sakura - merge cannon entities if (this.level().setBlock(blockposition, this.blockState, 3)) { ((ServerLevel) this.level()).getChunkSource().chunkMap.broadcast(this, new ClientboundBlockUpdatePacket(blockposition, this.level().getBlockState(blockposition))); this.discard(EntityRemoveEvent.Cause.DESPAWN); -diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -index af9bd6822f60ee46ff5cc173bc8bd76d13020a80..6aaaed5899393046ff31cc65edf81ae27edf1319 100644 ---- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -@@ -90,6 +90,44 @@ public class PrimedTnt extends Entity implements TraceableEntity { - return !this.isRemoved(); +@@ -326,6 +379,7 @@ public class FallingBlockEntity extends Entity { + + nbt.putBoolean("CancelDrop", this.cancelDrop); + if (!autoExpire) {nbt.putBoolean("Paper.AutoExpire", false);} // Paper - Expand FallingBlock API ++ nbt.putInt("merge_count", this.mergeData.getCount()); // Sakura - merge cannon entities } + @Override +@@ -358,6 +412,11 @@ public class FallingBlockEntity extends Entity { + this.autoExpire = nbt.getBoolean("Paper.AutoExpire"); + } + // Paper end - Expand FallingBlock API ++ // Sakura start - merge cannon entities ++ if (nbt.contains("merge_count", 3)) { ++ this.mergeData.setCount(nbt.getInt("merge_count")); ++ } ++ // Sakura end - merge cannon entities + } + + public void setHurtsEntities(float fallHurtAmount, int fallHurtMax) { +diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java +index af9bd6822f60ee46ff5cc173bc8bd76d13020a80..bdbee5ce0483a4fc4173c6ccf98d6a7a57f48867 100644 +--- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java ++++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java +@@ -30,7 +30,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 DATA_FUSE_ID = SynchedEntityData.defineId(PrimedTnt.class, EntityDataSerializers.INT); + private static final EntityDataAccessor DATA_BLOCK_STATE_ID = SynchedEntityData.defineId(PrimedTnt.class, EntityDataSerializers.BLOCK_STATE); +@@ -54,11 +54,48 @@ public class PrimedTnt extends Entity implements TraceableEntity { + public float yield = 4; // CraftBukkit - add field + public boolean isIncendiary = false; // CraftBukkit - add field + + // 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 boolean isMergeableType(@Nullable Entity previous) { -+ return previous == null || !isRemoved() && !previous.isRemoved(); ++ public final me.samsuik.sakura.entity.merge.MergeEntityData getMergeEntityData() { ++ return this.mergeData; + } + + @Override -+ public final boolean isSafeToMergeInto(Entity entity) { ++ public final boolean isSafeToMergeInto(Entity entity, boolean ticksLived) { + return entity instanceof PrimedTnt tnt -+ && tnt.getFuse() + 1 == getFuse() ++ && tnt.getFuse() + 1 == this.getFuse() + // required to prevent issues with powdered snow -+ && (tnt.entityState().fallDistance() == fallDistance -+ || tnt.entityState().fallDistance() > 2.5f && fallDistance > 2.5f); ++ && (tnt.entityState().fallDistance() == this.fallDistance ++ || tnt.entityState().fallDistance() > 2.5f && this.fallDistance > 2.5f); + } + + @Override -+ protected final boolean respawnMerged() { -+ if (stacked <= 1) return false; -+ -+ PrimedTnt tnt = new PrimedTnt(EntityType.TNT, level()); -+ -+ while (stacked-- > 1) { ++ public final void respawnEntity(int count) { ++ 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 @@ -486,96 +614,120 @@ index af9bd6822f60ee46ff5cc173bc8bd76d13020a80..6aaaed5899393046ff31cc65edf81ae2 + + this.tick(); + } -+ -+ return true; + } + // Sakura end - merge cannon entities + - @Override - protected double getDefaultGravity() { - return 0.04D; -@@ -118,6 +156,7 @@ public class PrimedTnt extends Entity implements TraceableEntity { + public PrimedTnt(EntityType type, Level world) { + super(type, world); + this.blocksBuilding = true; + this.isPrimedTNT = true; // Sakura + this.loadChunks = world.sakuraConfig().cannons.loadChunks; // Sakura - load chunks on movement ++ this.mergeData.setMergeLevel(world.sakuraConfig().cannons.mergeLevel); // Sakura - merge cannon entities + } + + public PrimedTnt(Level world, double x, double y, double z, @Nullable LivingEntity igniter) { +@@ -118,6 +155,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.respawnMerged(); // Sakura ++ this.respawnEntity(); // Sakura - merge cannon entities if (!this.level().isClientSide) { this.explode(); } -diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 4c3c6a04155fa4a0ea81beaa5bf2a2f53ab5dbbc..5ab7e3335448a262f892a3a7232179b19d91d78d 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -221,6 +221,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl - - // Paper start - rewrite chunk system - private ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup entityLookup; -+ public final me.samsuik.sakura.entity.merge.MergeHistory mergeHistory = new me.samsuik.sakura.entity.merge.MergeHistory(); // Sakura - cannon entity merging +@@ -176,6 +214,7 @@ public class PrimedTnt extends Entity implements TraceableEntity { + protected void addAdditionalSaveData(CompoundTag nbt) { + nbt.putShort("fuse", (short) this.getFuse()); + nbt.put("block_state", NbtUtils.writeBlockState(this.getBlockState())); ++ nbt.putInt("merge_count", this.mergeData.getCount()); // Sakura - merge cannon entities + } @Override - public final ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup moonrise$getEntityLookup() { +@@ -184,6 +223,11 @@ public class PrimedTnt extends Entity implements TraceableEntity { + if (nbt.contains("block_state", 10)) { + this.setBlockState(NbtUtils.readBlockState(this.level().holderLookup(Registries.BLOCK), nbt.getCompound("block_state"))); + } ++ // Sakura start - merge cannon entities ++ if (nbt.contains("merge_count", 3)) { ++ this.mergeData.setCount(nbt.getInt("merge_count")); ++ } ++ // Sakura end - merge cannon entities + + } + +diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java +index 4c3c6a04155fa4a0ea81beaa5bf2a2f53ab5dbbc..48cfc7b3358ec2a663d31af3638eda7334474241 100644 +--- a/src/main/java/net/minecraft/world/level/Level.java ++++ b/src/main/java/net/minecraft/world/level/Level.java +@@ -654,6 +654,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + } + // Paper end - optimise collisions + public final it.unimi.dsi.fastutil.longs.Long2IntMap minimalTNT = new it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap(); // Sakura - visibility api ++ public final me.samsuik.sakura.entity.merge.EntityMergeHandler mergeHandler = new me.samsuik.sakura.entity.merge.EntityMergeHandler(); // Sakura - merge cannon entities + + protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, Supplier sakuraWorldConfigCreator, java.util.concurrent.Executor executor) { // Sakura - sakura configuration files// Paper - create paper world config & Anti-Xray + this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java -index 1359d25a32b4a5d5e8e68ce737bd19f7b5afaf69..0afa2cfb04b5097788927076669e85fe24041df9 100644 +index 1359d25a32b4a5d5e8e68ce737bd19f7b5afaf69..55f67c2ca07eca0d3e1522eebbb4ce37704bdd04 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java @@ -14,6 +14,28 @@ public class CraftFallingBlock extends CraftEntity implements FallingBlock { super(server, entity); } -+ // Sakura start ++ // Sakura start - merge cannon entities + @Override + public @org.jetbrains.annotations.NotNull me.samsuik.sakura.entity.merge.MergeLevel getMergeLevel() { -+ return getHandle().getMergeLevel(); ++ return this.getHandle().getMergeEntityData().getMergeLevel(); + } + + @Override + public void setMergeLevel(@org.jetbrains.annotations.NotNull me.samsuik.sakura.entity.merge.MergeLevel level) { -+ getHandle().setMergeLevel(level); ++ this.getHandle().getMergeEntityData().setMergeLevel(level); + } + + @Override + public int getStacked() { -+ return getHandle().getStacked(); ++ return this.getHandle().getMergeEntityData().getCount(); + } + + @Override + public void setStacked(int stacked) { -+ getHandle().setStacked(stacked); ++ this.getHandle().getMergeEntityData().setCount(stacked); + } -+ // Sakura end ++ // Sakura end - merge cannon entities + @Override public FallingBlockEntity getHandle() { return (FallingBlockEntity) this.entity; diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java -index dac3d34677688ac560bc1be2087a08479ef71b87..3e80513263236d56019e3402c52f4a3677c83c76 100644 +index dac3d34677688ac560bc1be2087a08479ef71b87..e71eb9e68c3b3c433a3fe4dfbe65f60214d6c225 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTNTPrimed.java @@ -12,6 +12,28 @@ public class CraftTNTPrimed extends CraftEntity implements TNTPrimed { super(server, entity); } -+ // Sakura start ++ // Sakura start - merge cannon entities + @Override + public @org.jetbrains.annotations.NotNull me.samsuik.sakura.entity.merge.MergeLevel getMergeLevel() { -+ return getHandle().getMergeLevel(); ++ return this.getHandle().getMergeEntityData().getMergeLevel(); + } + + @Override + public void setMergeLevel(@org.jetbrains.annotations.NotNull me.samsuik.sakura.entity.merge.MergeLevel level) { -+ getHandle().setMergeLevel(level); ++ this.getHandle().getMergeEntityData().setMergeLevel(level); + } + + @Override + public int getStacked() { -+ return getHandle().getStacked(); ++ return this.getHandle().getMergeEntityData().getCount(); + } + + @Override + public void setStacked(int stacked) { -+ getHandle().setStacked(stacked); ++ this.getHandle().getMergeEntityData().setCount(stacked); + } -+ // Sakura end ++ // Sakura end - merge cannon entities + @Override public float getYield() { diff --git a/patches/server/0018-Replace-explosion-density-cache.patch b/patches/server/0018-Replace-explosion-density-cache.patch index 05c1ab8..9555ef1 100644 --- a/patches/server/0018-Replace-explosion-density-cache.patch +++ b/patches/server/0018-Replace-explosion-density-cache.patch @@ -129,19 +129,19 @@ index 0000000000000000000000000000000000000000..d7e24638f07f243502004970ab4ce646 + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 0a6a39672859aa4b70dacafc168250941f8d96d8..4ee6b6177df48701bd3521e3489797e62a85511f 100644 +index b0e95e1dbf3248101d63bd2c0f9ba05e720623c6..67ca905c0821deb279383811fd112f02c46a73a1 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1818,6 +1818,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, Supplier sakuraWorldConfigCreator, java.util.concurrent.Executor executor) { // Sakura - sakura configuration files// Paper - create paper world config & Anti-Xray + this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot diff --git a/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java b/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java index 8b33e35c843e5c0b8988a2ef2a38a2673035292f..5ec557652558bb44e9be7d32fc214091d29aac78 100644 --- a/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java diff --git a/patches/server/0020-Specialised-Explosions.patch b/patches/server/0020-Specialised-Explosions.patch index 1fbb4ff..f5d68f5 100644 --- a/patches/server/0020-Specialised-Explosions.patch +++ b/patches/server/0020-Specialised-Explosions.patch @@ -23,10 +23,10 @@ index c21e00812f1aaa1279834a0562d360d6b89e146c..442119e7c4670582556b067dfc03e39a if (index >= 0) { diff --git a/src/main/java/me/samsuik/sakura/explosion/special/SpecialisedExplosion.java b/src/main/java/me/samsuik/sakura/explosion/special/SpecialisedExplosion.java new file mode 100644 -index 0000000000000000000000000000000000000000..2dc4704b50dc9ca1e918c0869a29e333db5575d2 +index 0000000000000000000000000000000000000000..cec9432c8c6bbdb0f45b73c480fe9edb8eeb8298 --- /dev/null +++ b/src/main/java/me/samsuik/sakura/explosion/special/SpecialisedExplosion.java -@@ -0,0 +1,201 @@ +@@ -0,0 +1,203 @@ +package me.samsuik.sakura.explosion.special; + +import ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache; @@ -72,6 +72,8 @@ index 0000000000000000000000000000000000000000..2dc4704b50dc9ca1e918c0869a29e333 + return (double) this.cause.getBbHeight() * 0.0625D; + } + ++ protected abstract int getExplosionCount(); ++ + protected abstract void startExplosion(); + + @Override @@ -85,7 +87,7 @@ index 0000000000000000000000000000000000000000..2dc4704b50dc9ca1e918c0869a29e333 + public final void explode() { + if (this.radius() < 0.1F) { + // (radius < 0.1F) in bukkit is assumed to not be able to find any blocks or entities. -+ for (int i = 1; i < this.cause.getStacked(); ++i) { ++ for (int i = 1; i < this.getExplosionCount(); ++i) { + this.finalizeExplosionAndParticles(); + } + } else { @@ -230,16 +232,17 @@ index 0000000000000000000000000000000000000000..2dc4704b50dc9ca1e918c0869a29e333 +} diff --git a/src/main/java/me/samsuik/sakura/explosion/special/TntExplosion.java b/src/main/java/me/samsuik/sakura/explosion/special/TntExplosion.java new file mode 100644 -index 0000000000000000000000000000000000000000..c7c373fa24ee28f4bcd278816346171d0cdd35f2 +index 0000000000000000000000000000000000000000..2e3bcb3398c6875a5e0a7f6df07646948f852ab4 --- /dev/null +++ b/src/main/java/me/samsuik/sakura/explosion/special/TntExplosion.java -@@ -0,0 +1,189 @@ +@@ -0,0 +1,195 @@ +package me.samsuik.sakura.explosion.special; + +import ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet; +import ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import me.samsuik.sakura.entity.EntityState; ++import me.samsuik.sakura.entity.merge.MergeableEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Holder; @@ -275,6 +278,11 @@ index 0000000000000000000000000000000000000000..c7c373fa24ee28f4bcd278816346171d + } + + @Override ++ protected int getExplosionCount() { ++ return this.cause.getMergeEntityData().getCount(); ++ } ++ ++ @Override + protected void startExplosion() { + for (int i = this.calculateExplosionPotential() - 1; i >= 0; --i) { + Vec3 previousMomentum = this.cause.entityState().momentum(); @@ -369,14 +377,14 @@ index 0000000000000000000000000000000000000000..c7c373fa24ee28f4bcd278816346171d + + private int calculateExplosionPotential() { + IteratorSafeOrderedReferenceSet entities = this.level.entityTickList.entities; -+ int base = this.cause.getStacked(); ++ int base = this.getExplosionCount(); + int index = entities.indexOf(this.cause); + // iterate over the entityTickList to find entities that are exploding in the same position. + while ((index = entities.advanceRawIterator(index)) != -1) { + Entity foundEntity = entities.rawGet(index); -+ if (foundEntity.isRemoved() || !foundEntity.compareState(this.cause) || !foundEntity.isSafeToMergeInto(this.cause)) ++ if (!(foundEntity instanceof MergeableEntity mergeEntity) || foundEntity.isRemoved() || !foundEntity.compareState(this.cause) || !mergeEntity.isSafeToMergeInto(this.cause, false)) + break; -+ base += foundEntity.getStacked(); ++ base += mergeEntity.getMergeEntityData().getCount(); + foundEntity.discard(); + } + @@ -424,7 +432,7 @@ index 0000000000000000000000000000000000000000..c7c373fa24ee28f4bcd278816346171d + } +} diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index d58b95383f4bf5358f5d1c6d33c5539e77dd3798..5f09b0a94e6b1087c9207c333aa5595281a57985 100644 +index df0465e4e073af7cbcee4939175d8f8c4b280396..e11805351af06e6f4752f758a31f63cfe7a4728b 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -1771,6 +1771,12 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf. @@ -450,18 +458,16 @@ index d58b95383f4bf5358f5d1c6d33c5539e77dd3798..5f09b0a94e6b1087c9207c333aa55952 @Override diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -index 6aaaed5899393046ff31cc65edf81ae27edf1319..170eff4c5b76d037e269f973f14a1f301c205ffd 100644 +index bdbee5ce0483a4fc4173c6ccf98d6a7a57f48867..767ad73a398e61b7b4a8c57078487252e70010a9 100644 --- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java +++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -@@ -107,23 +107,7 @@ public class PrimedTnt extends Entity implements TraceableEntity { +@@ -73,20 +73,7 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak @Override - protected final boolean respawnMerged() { -- if (stacked <= 1) return false; -- -- PrimedTnt tnt = new PrimedTnt(EntityType.TNT, level()); -- -- while (stacked-- > 1) { + public final void respawnEntity(int count) { +- 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 @@ -473,13 +479,12 @@ index 6aaaed5899393046ff31cc65edf81ae27edf1319..170eff4c5b76d037e269f973f14a1f30 - - this.tick(); - } -- -+ // Sakura - specialised explosions - return true; ++ this.mergeData.setCount(count); // Sakura - specialised explosions } // Sakura end - merge cannon entities + diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java -index 5bf07349621d058739f12b9463bba47e9abfffd7..546c56d3465ca9c2358f1008d9db96f5fcdd6672 100644 +index a6cf8b00b707f10c34c32eef0c2acd7e9d78e6c9..315518ec8114b5b02778410c5e12b682e67cdc09 100644 --- a/src/main/java/net/minecraft/world/level/Explosion.java +++ b/src/main/java/net/minecraft/world/level/Explosion.java @@ -57,9 +57,11 @@ public class Explosion { @@ -576,7 +581,7 @@ index 5bf07349621d058739f12b9463bba47e9abfffd7..546c56d3465ca9c2358f1008d9db96f5 float blockDensity = this.level.densityCache.getDensity(vec3d, entity); if (blockDensity == me.samsuik.sakura.explosion.density.BlockDensityCache.UNKNOWN_DENSITY) { diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index c33826219edf60a1349583d1dc7d0008ef4037b4..64e134138b1e1311239fa19da2c8cda26e1ebc84 100644 +index 68cc57b15d2536711429ee3836d32aff7cfd1cf3..4721b405edb561e496c9cbb04dca5d7e37bcff2e 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -1480,7 +1480,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl diff --git a/patches/server/0021-Optimise-cannon-entity-movement.patch b/patches/server/0021-Optimise-cannon-entity-movement.patch index 5059742..e1f0615 100644 --- a/patches/server/0021-Optimise-cannon-entity-movement.patch +++ b/patches/server/0021-Optimise-cannon-entity-movement.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Optimise cannon entity movement diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 16b8881696f88f0a36bee78630df53f87578fed0..a3483b79f2a2859a137c22fcb3fec5bc74835d82 100644 +index d044262b2e1363151b8d076a9e3855db2a27254c..387217247431bf971dd612f42831552366de0510 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -1258,6 +1258,94 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1164,6 +1164,94 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return this.moveStartZ; } // Paper end - detailed watchdog information @@ -103,7 +103,7 @@ index 16b8881696f88f0a36bee78630df53f87578fed0..a3483b79f2a2859a137c22fcb3fec5bc public void move(MoverType movementType, Vec3 movement) { final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity -@@ -1602,6 +1690,95 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1508,6 +1596,95 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return offsetFactor; } @@ -200,10 +200,10 @@ index 16b8881696f88f0a36bee78630df53f87578fed0..a3483b79f2a2859a137c22fcb3fec5bc // Paper start - optimise collisions final boolean xZero = movement.x == 0.0; diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -index d15d4ddc99ddc2c37efc4e0b43ab51c0abc915a9..22034ec50d32a120ef5b591b76af9eb46d20c87e 100644 +index 172f82631e2ce3bfe791d7e8f2e841cca5a51667..c2f56308492d1e5d56993e32db8daaba8e081274 100644 --- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -@@ -204,7 +204,7 @@ public class FallingBlockEntity extends Entity { +@@ -203,7 +203,7 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti ++this.time; this.applyGravity(); @@ -213,10 +213,10 @@ index d15d4ddc99ddc2c37efc4e0b43ab51c0abc915a9..22034ec50d32a120ef5b591b76af9eb4 if (this.level().paperConfig().fixes.fallingBlockHeightNerf.test(v -> this.getY() > v)) { if (this.dropItem && this.level().getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) { diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -index 170eff4c5b76d037e269f973f14a1f301c205ffd..5a655606fd2dbc625696a0dc4331acd08d6dba88 100644 +index 767ad73a398e61b7b4a8c57078487252e70010a9..cc2f2dbee1d717d54014005ec57e8b864c2a7241 100644 --- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java +++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -@@ -122,7 +122,7 @@ public class PrimedTnt extends Entity implements TraceableEntity { +@@ -124,7 +124,7 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak if (this.level().spigotConfig.maxTntTicksPerTick > 0 && ++this.level().spigotConfig.currentPrimedTnt > this.level().spigotConfig.maxTntTicksPerTick) { return; } // Spigot this.handlePortal(); this.applyGravity(); diff --git a/patches/server/0022-Entity-pushed-by-fluid-API.patch b/patches/server/0022-Entity-pushed-by-fluid-API.patch index 962ec59..879791d 100644 --- a/patches/server/0022-Entity-pushed-by-fluid-API.patch +++ b/patches/server/0022-Entity-pushed-by-fluid-API.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Entity pushed by fluid API diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index a3483b79f2a2859a137c22fcb3fec5bc74835d82..526d54e3dc8473c6b1b67a9253b006cc27419ab2 100644 +index 387217247431bf971dd612f42831552366de0510..78821f286e5b0389d02dddbc1a9d8964a96c0af1 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -697,6 +697,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -604,6 +604,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } } // Sakura end - merge cannon entities @@ -16,7 +16,7 @@ index a3483b79f2a2859a137c22fcb3fec5bc74835d82..526d54e3dc8473c6b1b67a9253b006cc public Entity(EntityType type, Level world) { this.id = Entity.ENTITY_COUNTER.incrementAndGet(); -@@ -4277,7 +4278,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4173,7 +4174,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } public boolean isPushedByFluid() { diff --git a/patches/server/0023-Cannon-Mechanics.patch b/patches/server/0023-Cannon-Mechanics.patch index 832aa06..470c1a3 100644 --- a/patches/server/0023-Cannon-Mechanics.patch +++ b/patches/server/0023-Cannon-Mechanics.patch @@ -5,43 +5,44 @@ Subject: [PATCH] Cannon Mechanics diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -index 22034ec50d32a120ef5b591b76af9eb46d20c87e..ad7aa58ee5966c5d56ff8bf8070697d039d4f503 100644 +index c2f56308492d1e5d56993e32db8daaba8e081274..00c17b86c69b73d751ca93b65a54c74b6ed8fa6f 100644 --- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -@@ -72,6 +72,7 @@ public class FallingBlockEntity extends Entity { +@@ -72,6 +72,7 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti public boolean forceTickAfterTeleportToDuplicate; protected static final EntityDataAccessor DATA_START_POS = SynchedEntityData.defineId(FallingBlockEntity.class, EntityDataSerializers.BLOCK_POS); public boolean autoExpire = true; // Paper - Expand FallingBlock API + public boolean heightParity; // Sakura - configure cannon mechanics - public FallingBlockEntity(EntityType type, Level world) { - super(type, world); -@@ -80,6 +81,7 @@ public class FallingBlockEntity extends Entity { - this.fallDamageMax = 40; + // Sakura start - merge cannon entities + private final me.samsuik.sakura.entity.merge.MergeEntityData mergeData = new me.samsuik.sakura.entity.merge.MergeEntityData(this); +@@ -132,6 +133,7 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti this.isFallingBlock = true; // Sakura this.loadChunks = world.sakuraConfig().cannons.loadChunks; // Sakura - load chunks on movement + this.mergeData.setMergeLevel(world.sakuraConfig().cannons.mergeLevel); // Sakura - merge cannon entities + this.heightParity = world.sakuraConfig().cannons.mechanics.fallingBlockParity; // Sakura - configure cannon mechanics } public FallingBlockEntity(Level world, double x, double y, double z, BlockState block) { -@@ -189,6 +191,12 @@ public class FallingBlockEntity extends Entity { - return itemEntity; +@@ -189,6 +191,13 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti + return !this.isRemoved(); } - // Sakura end - merge cannon entities + + // Sakura start - configure cannon mechanics + @Override + public final double getEyeY() { + return this.heightParity ? this.getY() : super.getEyeY(); + } + // Sakura end - configure cannon mechanics - ++ @Override protected double getDefaultGravity() { + return 0.04D; diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -index 5a655606fd2dbc625696a0dc4331acd08d6dba88..92662134c56540f6215edf3c772fffd9262fbcd0 100644 +index cc2f2dbee1d717d54014005ec57e8b864c2a7241..7c2323bf7682254de14ed963e8d57b24dd55ad5f 100644 --- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java +++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -@@ -72,6 +72,12 @@ public class PrimedTnt extends Entity implements TraceableEntity { +@@ -96,6 +96,12 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak this.yo = y; this.zo = z; this.owner = igniter; @@ -54,7 +55,7 @@ index 5a655606fd2dbc625696a0dc4331acd08d6dba88..92662134c56540f6215edf3c772fffd9 } @Override -@@ -260,7 +266,7 @@ public class PrimedTnt extends Entity implements TraceableEntity { +@@ -268,7 +274,7 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak // Paper start - Option to prevent TNT from moving in water @Override public boolean isPushedByFluid() { @@ -64,23 +65,24 @@ index 5a655606fd2dbc625696a0dc4331acd08d6dba88..92662134c56540f6215edf3c772fffd9 // Paper end - Option to prevent TNT from moving in water } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java -index 0afa2cfb04b5097788927076669e85fe24041df9..8e678a811e232bbd78de45b80fae47964bdf8f98 100644 +index 55f67c2ca07eca0d3e1522eebbb4ce37704bdd04..2de0befc3948a23910cfc609fc25c57bbd0cb030 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFallingBlock.java -@@ -34,6 +34,16 @@ public class CraftFallingBlock extends CraftEntity implements FallingBlock { - public void setStacked(int stacked) { - getHandle().setStacked(stacked); +@@ -35,6 +35,17 @@ public class CraftFallingBlock extends CraftEntity implements FallingBlock { + this.getHandle().getMergeEntityData().setCount(stacked); } -+ + // Sakura end - merge cannon entities ++ // Sakura start - cannon mechanics + @Override + public void setHeightParity(boolean parity) { -+ getHandle().heightParity = parity; ++ this.getHandle().heightParity = parity; + } + + @Override + public boolean getHeightParity() { -+ return getHandle().heightParity; ++ return this.getHandle().heightParity; + } - // Sakura end ++ // Sakura end - cannon mechanics @Override + public FallingBlockEntity getHandle() { diff --git a/patches/server/0025-Optimise-TNT-fluid-state.patch b/patches/server/0025-Optimise-TNT-fluid-state.patch index 86e246e..fc4376a 100644 --- a/patches/server/0025-Optimise-TNT-fluid-state.patch +++ b/patches/server/0025-Optimise-TNT-fluid-state.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Optimise TNT fluid state diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 526d54e3dc8473c6b1b67a9253b006cc27419ab2..729bf74fb06fe4fadeecbd0d879e35ecf33990c1 100644 +index 78821f286e5b0389d02dddbc1a9d8964a96c0af1..4ff172a89cbbaba96e5c1056f9d9356a4da13499 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2246,7 +2246,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -2152,7 +2152,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return this.isInWater() || flag; } @@ -18,13 +18,13 @@ index 526d54e3dc8473c6b1b67a9253b006cc27419ab2..729bf74fb06fe4fadeecbd0d879e35ec if (entity instanceof Boat entityboat) { diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -index 92662134c56540f6215edf3c772fffd9262fbcd0..8ffa6ea08c49c3481bf8717eda3f8fa3672706eb 100644 +index 7c2323bf7682254de14ed963e8d57b24dd55ad5f..860aa93e2ae997beaacf3028e8fa7a8cfafece4e 100644 --- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java +++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -@@ -117,6 +117,20 @@ public class PrimedTnt extends Entity implements TraceableEntity { - return true; +@@ -120,6 +120,21 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak + return !this.isRemoved(); } - // Sakura end - merge cannon entities + + // Sakura start - optimise tnt fluid state + @Override + protected boolean updateInWaterStateAndDoFluidPushing() { @@ -39,6 +39,7 @@ index 92662134c56540f6215edf3c772fffd9262fbcd0..8ffa6ea08c49c3481bf8717eda3f8fa3 + } + } + // Sakura end - optimise tnt fluid state - ++ @Override protected double getDefaultGravity() { + return 0.04D; diff --git a/patches/server/0028-Despawn-falling-blocks-inside-moving-pistons.patch b/patches/server/0028-Despawn-falling-blocks-inside-moving-pistons.patch index 99800c1..a9d355b 100644 --- a/patches/server/0028-Despawn-falling-blocks-inside-moving-pistons.patch +++ b/patches/server/0028-Despawn-falling-blocks-inside-moving-pistons.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Despawn falling blocks inside moving pistons diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -index ad7aa58ee5966c5d56ff8bf8070697d039d4f503..dbc16b755f86917362d90f8801086a46c2140ceb 100644 +index 00c17b86c69b73d751ca93b65a54c74b6ed8fa6f..448f4ce99a06b6683c9cf324444dee491a11f9e9 100644 --- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -@@ -239,7 +239,7 @@ public class FallingBlockEntity extends Entity { +@@ -239,7 +239,7 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti } } diff --git a/patches/server/0030-Explosion-Durable-Blocks.patch b/patches/server/0030-Explosion-Durable-Blocks.patch index 119affc..b5a6ce2 100644 --- a/patches/server/0030-Explosion-Durable-Blocks.patch +++ b/patches/server/0030-Explosion-Durable-Blocks.patch @@ -74,12 +74,12 @@ index 0000000000000000000000000000000000000000..c58e52f7cc012babf4235e405e5fb501 + +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 4ee6b6177df48701bd3521e3489797e62a85511f..7a400d332fb4d9df7210fe4efabcc308cf37b296 100644 +index 67ca905c0821deb279383811fd112f02c46a73a1..545dee7863095b70474abcc87c9c9c0f15a016f8 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1819,6 +1819,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, Supplier sakuraWorldConfigCreator, java.util.concurrent.Executor executor) { // Sakura - sakura configuration files// Paper - create paper world config & Anti-Xray + this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot diff --git a/patches/server/0032-Cache-Vanillia-and-Eigen-Redstone.patch b/patches/server/0032-Cache-Vanillia-and-Eigen-Redstone.patch index 70f12b7..6562183 100644 --- a/patches/server/0032-Cache-Vanillia-and-Eigen-Redstone.patch +++ b/patches/server/0032-Cache-Vanillia-and-Eigen-Redstone.patch @@ -343,11 +343,11 @@ index 0000000000000000000000000000000000000000..4f5af6e241b0194ed982144fd9320315 + +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 7a400d332fb4d9df7210fe4efabcc308cf37b296..788e24171d0d57bbd6b57a51c194a38611d5dbf6 100644 +index 545dee7863095b70474abcc87c9c9c0f15a016f8..a826251f1d5f8ad670ee824bfcd093e6ab281bed 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1820,6 +1820,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, Supplier sakuraWorldConfigCreator, java.util.concurrent.Executor executor) { // Sakura - sakura configuration files// Paper - create paper world config & Anti-Xray + this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot @@ -1036,6 +1037,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl } else { BlockState iblockdata2 = this.getBlockState(pos); diff --git a/patches/server/0033-Falling-Block-Stacking-Restrictions.patch b/patches/server/0033-Falling-Block-Stacking-Restrictions.patch index f843ddc..3482e3e 100644 --- a/patches/server/0033-Falling-Block-Stacking-Restrictions.patch +++ b/patches/server/0033-Falling-Block-Stacking-Restrictions.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Falling Block Stacking Restrictions diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -index dbc16b755f86917362d90f8801086a46c2140ceb..4ad24f238343213dcba66914eab27091002361a0 100644 +index 448f4ce99a06b6683c9cf324444dee491a11f9e9..672d5cf4c8a9ae759c591a590e6205afe5f81d36 100644 --- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -@@ -257,7 +257,7 @@ public class FallingBlockEntity extends Entity { +@@ -257,7 +257,7 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti boolean flag3 = FallingBlock.isFree(this.level().getBlockState(blockposition.below())) && (!flag || !flag1); boolean flag4 = this.blockState.canSurvive(this.level(), blockposition) && !flag3; diff --git a/patches/server/0037-Remove-spigot-max-tnt-per-tick.patch b/patches/server/0037-Remove-spigot-max-tnt-per-tick.patch index c083e74..5b80a53 100644 --- a/patches/server/0037-Remove-spigot-max-tnt-per-tick.patch +++ b/patches/server/0037-Remove-spigot-max-tnt-per-tick.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Remove spigot max tnt per tick diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -index 8ffa6ea08c49c3481bf8717eda3f8fa3672706eb..5de1bbd92e235c882c700a00200fea8daf730cf7 100644 +index 860aa93e2ae997beaacf3028e8fa7a8cfafece4e..7d5fdcf1e0b3cd46e12e1ae102eadb8f198a68c4 100644 --- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java +++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -@@ -139,7 +139,7 @@ public class PrimedTnt extends Entity implements TraceableEntity { +@@ -142,7 +142,7 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak @Override public void tick() { diff --git a/patches/server/0039-Configure-cannon-physics-by-version.patch b/patches/server/0039-Configure-cannon-physics-by-version.patch index 3cebd9a..9843545 100644 --- a/patches/server/0039-Configure-cannon-physics-by-version.patch +++ b/patches/server/0039-Configure-cannon-physics-by-version.patch @@ -67,10 +67,10 @@ index 740dc010cfd42941a6f9a2b2c543973429fdbfa3..523cd7cfd5e883cc4758ab9ad13251c3 if (xSmaller && z != 0.0) { z = performAABBCollisionsZ(axisalignedbb, z, aabbs); diff --git a/src/main/java/me/samsuik/sakura/explosion/special/SpecialisedExplosion.java b/src/main/java/me/samsuik/sakura/explosion/special/SpecialisedExplosion.java -index 2dc4704b50dc9ca1e918c0869a29e333db5575d2..0644ebc5292de4924ba675a34a645f9be607635e 100644 +index cec9432c8c6bbdb0f45b73c480fe9edb8eeb8298..92e85801ccc69be589667d59f949fa0af9467f38 100644 --- a/src/main/java/me/samsuik/sakura/explosion/special/SpecialisedExplosion.java +++ b/src/main/java/me/samsuik/sakura/explosion/special/SpecialisedExplosion.java -@@ -173,9 +173,15 @@ public abstract class SpecialisedExplosion extends Explosion { +@@ -175,9 +175,15 @@ public abstract class SpecialisedExplosion extends Explosion { if (distanceFromBottom <= 1.0) { double x = entity.getX() - pos.x; @@ -88,10 +88,10 @@ index 2dc4704b50dc9ca1e918c0869a29e333db5575d2..0644ebc5292de4924ba675a34a645f9b if (distance != 0.0D) { x /= distance; diff --git a/src/main/java/me/samsuik/sakura/explosion/special/TntExplosion.java b/src/main/java/me/samsuik/sakura/explosion/special/TntExplosion.java -index c7c373fa24ee28f4bcd278816346171d0cdd35f2..3924dbd0007eb078ba016f7b1d84f6555b81261f 100644 +index 2e3bcb3398c6875a5e0a7f6df07646948f852ab4..1dd77891191845a8e47ad1c90a3ef807bf258a6a 100644 --- a/src/main/java/me/samsuik/sakura/explosion/special/TntExplosion.java +++ b/src/main/java/me/samsuik/sakura/explosion/special/TntExplosion.java -@@ -38,6 +38,13 @@ public final class TntExplosion extends SpecialisedExplosion { +@@ -39,6 +39,13 @@ public final class TntExplosion extends SpecialisedExplosion { this.bounds = new AABB(x, y, z, x, y, z); } @@ -103,10 +103,10 @@ index c7c373fa24ee28f4bcd278816346171d0cdd35f2..3924dbd0007eb078ba016f7b1d84f655 + // Sakura end - physics version api + @Override - protected void startExplosion() { - for (int i = this.calculateExplosionPotential() - 1; i >= 0; --i) { + protected int getExplosionCount() { + return this.cause.getMergeEntityData().getCount(); diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 729bf74fb06fe4fadeecbd0d879e35ecf33990c1..183204d645f294a74049c5cf1501250b0552839a 100644 +index 4ff172a89cbbaba96e5c1056f9d9356a4da13499..59635ea26387d3ea4c6bb5a64f32b7c5d9f1a5e2 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -385,7 +385,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess @@ -118,7 +118,7 @@ index 729bf74fb06fe4fadeecbd0d879e35ecf33990c1..183204d645f294a74049c5cf1501250b public boolean isInPowderSnow; public boolean wasInPowderSnow; public boolean wasOnFire; -@@ -698,6 +698,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -605,6 +605,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } // Sakura end - merge cannon entities public boolean pushedByFluid = true; // Sakura - entity pushed by fluid api @@ -132,7 +132,7 @@ index 729bf74fb06fe4fadeecbd0d879e35ecf33990c1..183204d645f294a74049c5cf1501250b public Entity(EntityType type, Level world) { this.id = Entity.ENTITY_COUNTER.incrementAndGet(); -@@ -1205,7 +1212,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1111,7 +1118,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } protected void checkSupportingBlock(boolean onGround, @Nullable Vec3 movement) { @@ -141,7 +141,7 @@ index 729bf74fb06fe4fadeecbd0d879e35ecf33990c1..183204d645f294a74049c5cf1501250b AABB axisalignedbb = this.getBoundingBox(); AABB axisalignedbb1 = new AABB(axisalignedbb.minX, axisalignedbb.minY - 1.0E-6D, axisalignedbb.minZ, axisalignedbb.maxX, axisalignedbb.minY, axisalignedbb.maxZ); Optional optional = this.level.findSupportingBlock(this, axisalignedbb1); -@@ -1266,7 +1273,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1172,7 +1179,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess if (this.noPhysics) { this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z); } else { @@ -150,7 +150,7 @@ index 729bf74fb06fe4fadeecbd0d879e35ecf33990c1..183204d645f294a74049c5cf1501250b movement = this.limitPistonMovement(movement); if (movement.equals(Vec3.ZERO)) { return; -@@ -1284,10 +1291,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1190,10 +1197,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess Vec3 vec3d1 = this.collideScan(movement); double d0 = vec3d1.lengthSqr(); @@ -163,7 +163,7 @@ index 729bf74fb06fe4fadeecbd0d879e35ecf33990c1..183204d645f294a74049c5cf1501250b BlockHitResult movingobjectpositionblock = this.level().clip(new ClipContext(this.position(), this.position().add(vec3d1), ClipContext.Block.FALLDAMAGE_RESETTING, ClipContext.Fluid.WATER, this)); if (movingobjectpositionblock.getType() != HitResult.Type.MISS) { -@@ -1323,6 +1330,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1229,6 +1236,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess if (this.horizontalCollision) { Vec3 vec3d2 = this.getDeltaMovement(); @@ -175,7 +175,7 @@ index 729bf74fb06fe4fadeecbd0d879e35ecf33990c1..183204d645f294a74049c5cf1501250b this.setDeltaMovement(flag ? 0.0D : vec3d2.x, vec3d2.y, flag1 ? 0.0D : vec3d2.z); } -@@ -1364,7 +1376,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1270,7 +1282,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z); } else { this.wasOnFire = this.isOnFire(); @@ -184,7 +184,7 @@ index 729bf74fb06fe4fadeecbd0d879e35ecf33990c1..183204d645f294a74049c5cf1501250b this.activatedTick = Math.max(this.activatedTick, MinecraftServer.currentTick + 20); // Paper this.activatedImmunityTick = Math.max(this.activatedImmunityTick, MinecraftServer.currentTick + 20); // Paper movement = this.limitPistonMovement(movement); -@@ -1391,8 +1403,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1297,8 +1309,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess Vec3 vec3d1 = this.collide(movement); double d0 = vec3d1.lengthSqr(); @@ -195,7 +195,7 @@ index 729bf74fb06fe4fadeecbd0d879e35ecf33990c1..183204d645f294a74049c5cf1501250b BlockHitResult movingobjectpositionblock = this.level().clip(new ClipContext(this.position(), this.position().add(vec3d1), ClipContext.Block.FALLDAMAGE_RESETTING, ClipContext.Fluid.WATER, this)); if (movingobjectpositionblock.getType() != HitResult.Type.MISS) { -@@ -1428,6 +1440,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1334,6 +1346,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess if (this.horizontalCollision) { Vec3 vec3d2 = this.getDeltaMovement(); @@ -207,7 +207,7 @@ index 729bf74fb06fe4fadeecbd0d879e35ecf33990c1..183204d645f294a74049c5cf1501250b this.setDeltaMovement(flag ? 0.0D : vec3d2.x, vec3d2.y, flag1 ? 0.0D : vec3d2.z); } -@@ -1707,7 +1724,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1613,7 +1630,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } else { AABB bb = currBoundingBox.expandTowards(movement.x, movement.y, movement.z); this.collectCollisions(bb, potentialCollisionsVoxel, potentialCollisionsBB); @@ -216,7 +216,7 @@ index 729bf74fb06fe4fadeecbd0d879e35ecf33990c1..183204d645f294a74049c5cf1501250b } } -@@ -1716,7 +1733,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1622,7 +1639,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess double y = movement.y; double z = movement.z; @@ -228,7 +228,7 @@ index 729bf74fb06fe4fadeecbd0d879e35ecf33990c1..183204d645f294a74049c5cf1501250b if (y != 0.0) { y = this.scanY(currBoundingBox, y, voxelList, bbList); -@@ -1832,7 +1852,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1738,7 +1758,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return movement; } @@ -237,7 +237,7 @@ index 729bf74fb06fe4fadeecbd0d879e35ecf33990c1..183204d645f294a74049c5cf1501250b if (stepHeight > 0.0 && (onGround || (limitedMoveVector.y != movement.y && movement.y < 0.0)) -@@ -1983,8 +2003,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1889,8 +1909,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess protected void checkInsideBlocks() { AABB axisalignedbb = this.getBoundingBox(); @@ -252,10 +252,10 @@ index 729bf74fb06fe4fadeecbd0d879e35ecf33990c1..183204d645f294a74049c5cf1501250b if (this.level().hasChunksAt(blockposition, blockposition1)) { BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos(); diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -index 4ad24f238343213dcba66914eab27091002361a0..0fdf97cd8d13b29db25348fc59d98391fce3346d 100644 +index 672d5cf4c8a9ae759c591a590e6205afe5f81d36..d886a5c514266cf8d46ce163e33dec35941d56aa 100644 --- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -@@ -94,6 +94,8 @@ public class FallingBlockEntity extends Entity { +@@ -146,6 +146,8 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti this.yo = y; this.zo = z; this.setStartPos(this.blockPosition()); @@ -264,7 +264,7 @@ index 4ad24f238343213dcba66914eab27091002361a0..0fdf97cd8d13b29db25348fc59d98391 } public static FallingBlockEntity fall(Level world, BlockPos pos, BlockState state) { -@@ -106,7 +108,11 @@ public class FallingBlockEntity extends Entity { +@@ -158,7 +160,11 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti FallingBlockEntity entityfallingblock = new FallingBlockEntity(world, (double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D, iblockdata.hasProperty(BlockStateProperties.WATERLOGGED) ? (BlockState) iblockdata.setValue(BlockStateProperties.WATERLOGGED, false) : iblockdata); if (!CraftEventFactory.callEntityChangeBlockEvent(entityfallingblock, blockposition, iblockdata.getFluidState().createLegacyBlock())) return entityfallingblock; // CraftBukkit @@ -277,7 +277,7 @@ index 4ad24f238343213dcba66914eab27091002361a0..0fdf97cd8d13b29db25348fc59d98391 world.addFreshEntity(entityfallingblock, spawnReason); // CraftBukkit return entityfallingblock; } -@@ -197,10 +203,47 @@ public class FallingBlockEntity extends Entity { +@@ -197,10 +203,47 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti return this.heightParity ? this.getY() : super.getEyeY(); } // Sakura end - configure cannon mechanics @@ -326,7 +326,7 @@ index 4ad24f238343213dcba66914eab27091002361a0..0fdf97cd8d13b29db25348fc59d98391 } @Override -@@ -210,6 +253,11 @@ public class FallingBlockEntity extends Entity { +@@ -210,6 +253,11 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti } else { Block block = this.blockState.getBlock(); @@ -338,7 +338,7 @@ index 4ad24f238343213dcba66914eab27091002361a0..0fdf97cd8d13b29db25348fc59d98391 ++this.time; this.applyGravity(); this.moveBasic(MoverType.SELF, this.getDeltaMovement()); // Sakura - optimise cannon entity movement -@@ -224,8 +272,15 @@ public class FallingBlockEntity extends Entity { +@@ -224,8 +272,15 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti } // Paper end - Configurable falling blocks height nerf this.handlePortal(); @@ -355,7 +355,7 @@ index 4ad24f238343213dcba66914eab27091002361a0..0fdf97cd8d13b29db25348fc59d98391 boolean flag = this.blockState.getBlock() instanceof ConcretePowderBlock; boolean flag1 = flag && this.level().getFluidState(blockposition).is(FluidTags.WATER); double d0 = this.getDeltaMovement().lengthSqr(); -@@ -250,8 +305,11 @@ public class FallingBlockEntity extends Entity { +@@ -250,8 +305,11 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti } else { BlockState iblockdata = this.level().getBlockState(blockposition); @@ -369,7 +369,7 @@ index 4ad24f238343213dcba66914eab27091002361a0..0fdf97cd8d13b29db25348fc59d98391 if (!this.cancelDrop) { boolean flag2 = iblockdata.canBeReplaced((BlockPlaceContext) (new DirectionalPlaceContext(this.level(), blockposition, Direction.DOWN, ItemStack.EMPTY, Direction.UP))); boolean flag3 = FallingBlock.isFree(this.level().getBlockState(blockposition.below())) && (!flag || !flag1); -@@ -318,7 +376,12 @@ public class FallingBlockEntity extends Entity { +@@ -318,7 +376,12 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti } } @@ -384,10 +384,10 @@ index 4ad24f238343213dcba66914eab27091002361a0..0fdf97cd8d13b29db25348fc59d98391 } diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -index 5de1bbd92e235c882c700a00200fea8daf730cf7..7247e77417264d1e9ccf23dfb7e8ec9cb38ac08a 100644 +index 7d5fdcf1e0b3cd46e12e1ae102eadb8f198a68c4..a17491a826accc23fbafcdf07ed66293cd8ae5bf 100644 --- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java +++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -@@ -78,6 +78,13 @@ public class PrimedTnt extends Entity implements TraceableEntity { +@@ -102,6 +102,13 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak case Y -> this.multiplyDeltaMovement(0, 1, 0); } // Sakura end - configure cannon mechanics @@ -401,7 +401,7 @@ index 5de1bbd92e235c882c700a00200fea8daf730cf7..7247e77417264d1e9ccf23dfb7e8ec9c } @Override -@@ -131,10 +138,26 @@ public class PrimedTnt extends Entity implements TraceableEntity { +@@ -134,10 +141,26 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak } } // Sakura end - optimise tnt fluid state @@ -429,7 +429,7 @@ index 5de1bbd92e235c882c700a00200fea8daf730cf7..7247e77417264d1e9ccf23dfb7e8ec9c } @Override -@@ -149,15 +172,19 @@ public class PrimedTnt extends Entity implements TraceableEntity { +@@ -152,15 +175,19 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak return; } // Paper end - Configurable TNT height nerf @@ -451,8 +451,8 @@ index 5de1bbd92e235c882c700a00200fea8daf730cf7..7247e77417264d1e9ccf23dfb7e8ec9c + if (this.physics.before(1_9_0) ? (i < 0) : (i <= 0)) { // Sakura - physics version api // 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.respawnMerged(); // Sakura -@@ -210,7 +237,10 @@ public class PrimedTnt extends Entity implements TraceableEntity { + this.respawnEntity(); // Sakura - merge cannon entities +@@ -213,7 +240,10 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak ExplosionPrimeEvent event = CraftEventFactory.callExplosionPrimeEvent((org.bukkit.entity.Explosive)this.getBukkitEntity()); if (!event.isCancelled()) { @@ -464,7 +464,7 @@ index 5de1bbd92e235c882c700a00200fea8daf730cf7..7247e77417264d1e9ccf23dfb7e8ec9c } // CraftBukkit end } -@@ -280,7 +310,7 @@ public class PrimedTnt extends Entity implements TraceableEntity { +@@ -289,7 +319,7 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak // Paper start - Option to prevent TNT from moving in water @Override public boolean isPushedByFluid() { @@ -474,7 +474,7 @@ index 5de1bbd92e235c882c700a00200fea8daf730cf7..7247e77417264d1e9ccf23dfb7e8ec9c // Paper end - Option to prevent TNT from moving in water } diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java -index 6e029387500807f38305520b77ff0433eb055719..665e96abe709587bdff15eab78bf9fd88b8ce9dc 100644 +index 7911b0dce3ebace1e28c7fc79c3e152a7601e017..79a08eebbbb74a8aadfe2a2b87e1009f58ad994e 100644 --- a/src/main/java/net/minecraft/world/level/Explosion.java +++ b/src/main/java/net/minecraft/world/level/Explosion.java @@ -77,6 +77,7 @@ public class Explosion { @@ -567,7 +567,7 @@ index 6e029387500807f38305520b77ff0433eb055719..665e96abe709587bdff15eab78bf9fd8 private final Level world; private final double posX, posY, posZ; diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index c06061867ab2e4ac3f2c041adfac052c13e36707..e505b00d29f805b6d2d61a27e77ae8b5b52c2bb1 100644 +index a3c968446d61965e247a1b1cb4ebe8a6b3605338..85fe16848bdf5073a48aeff482a5f07b3266873f 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -196,6 +196,205 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl diff --git a/patches/server/0041-Configure-concrete-solidifying-in-water.patch b/patches/server/0041-Configure-concrete-solidifying-in-water.patch index afb9997..6fa7e8b 100644 --- a/patches/server/0041-Configure-concrete-solidifying-in-water.patch +++ b/patches/server/0041-Configure-concrete-solidifying-in-water.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Configure concrete solidifying in water diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -index 0fdf97cd8d13b29db25348fc59d98391fce3346d..0fab05cfce5460d7025b626ff6438c72616b78c8 100644 +index d886a5c514266cf8d46ce163e33dec35941d56aa..e86ac1779cf382b70f6dabd281260c3e78e9376b 100644 --- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -@@ -281,7 +281,7 @@ public class FallingBlockEntity extends Entity { +@@ -281,7 +281,7 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti // However, it makes sense for legacy versions pre-1.17 before the world height change. BlockPos blockposition = this.physics.before(1_17_0) ? this.patchedBlockPosition() : this.blockPosition(); // Sakura end - physics version api diff --git a/patches/server/0056-Optimise-check-inside-blocks-and-fluids.patch b/patches/server/0056-Optimise-check-inside-blocks-and-fluids.patch index 0b9bfc0..121247c 100644 --- a/patches/server/0056-Optimise-check-inside-blocks-and-fluids.patch +++ b/patches/server/0056-Optimise-check-inside-blocks-and-fluids.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Optimise check inside blocks and fluids diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index d398bc33522e199ca912f460d6092464348b1a1e..f7c619df4deacd9a9c559c582b388cdd900f0165 100644 +index 85f1d44ba59d348d9c364ed684cc5df6a1eada29..012dec6d31e3932ed4a50e8c5c64a9e7751690cd 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -2018,18 +2018,37 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1924,18 +1924,37 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess BlockPos blockposition1 = BlockPos.containing(axisalignedbb.maxX - offset, axisalignedbb.maxY - offset, axisalignedbb.maxZ - offset); // Sakura end - physics version api @@ -50,7 +50,7 @@ index d398bc33522e199ca912f460d6092464348b1a1e..f7c619df4deacd9a9c559c582b388cdd try { iblockdata.entityInside(this.level(), blockposition_mutableblockposition, this); -@@ -4821,7 +4840,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4717,7 +4736,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } public boolean updateFluidHeightAndDoFluidPushing(TagKey tag, double speed) { @@ -59,7 +59,7 @@ index d398bc33522e199ca912f460d6092464348b1a1e..f7c619df4deacd9a9c559c582b388cdd return false; } else { AABB axisalignedbb = this.getBoundingBox().deflate(0.001D); -@@ -4838,11 +4857,30 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4734,11 +4753,30 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess int k1 = 0; BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos(); diff --git a/patches/server/0059-Fix-doEntityDrops-gamerule-preventing-falling-blocks.patch b/patches/server/0059-Fix-doEntityDrops-gamerule-preventing-falling-blocks.patch index 2d5c272..b0c7a55 100644 --- a/patches/server/0059-Fix-doEntityDrops-gamerule-preventing-falling-blocks.patch +++ b/patches/server/0059-Fix-doEntityDrops-gamerule-preventing-falling-blocks.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Fix doEntityDrops gamerule preventing falling blocks from diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -index 0fab05cfce5460d7025b626ff6438c72616b78c8..4d06f4eb4c36b8426fae4883154e1ae16e4064e3 100644 +index e86ac1779cf382b70f6dabd281260c3e78e9376b..d52993f1f2e8395c480fdcc639dadc32ecaa23bc 100644 --- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -@@ -356,10 +356,14 @@ public class FallingBlockEntity extends Entity { +@@ -356,10 +356,14 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti tileentity.setChanged(); } } diff --git a/patches/server/0060-Add-entity-travel-distance-limits.patch b/patches/server/0060-Add-entity-travel-distance-limits.patch index f4b9e42..87317f1 100644 --- a/patches/server/0060-Add-entity-travel-distance-limits.patch +++ b/patches/server/0060-Add-entity-travel-distance-limits.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add entity travel distance limits diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 5f09b0a94e6b1087c9207c333aa5595281a57985..d69439c51adb330066ddca62bda0e71ff36872ba 100644 +index e11805351af06e6f4752f758a31f63cfe7a4728b..f185f1fce6daf6677c4d7a09a9f5f08cd0ffebaf 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -1260,6 +1260,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ca.spottedleaf. @@ -21,10 +21,10 @@ index 5f09b0a94e6b1087c9207c333aa5595281a57985..d69439c51adb330066ddca62bda0e71f } else { entity.inactiveTick(); } // Paper - EAR 2 this.getProfiler().pop(); diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index f7c619df4deacd9a9c559c582b388cdd900f0165..d90fc6c3057102b2f14687e3c3294f7f47e270b1 100644 +index 012dec6d31e3932ed4a50e8c5c64a9e7751690cd..b5dc81e3fb62e82b3524ab812d4d194cb5fe101e 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -714,6 +714,19 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -621,6 +621,19 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return this.physics; } // Sakura end - physics version api @@ -44,11 +44,11 @@ index f7c619df4deacd9a9c559c582b388cdd900f0165..d90fc6c3057102b2f14687e3c3294f7f public Entity(EntityType type, Level world) { this.id = Entity.ENTITY_COUNTER.incrementAndGet(); -@@ -764,6 +777,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -670,6 +683,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + this.entityData = datawatcher_a.build(); this.setPos(0.0D, 0.0D, 0.0D); this.eyeHeight = this.dimensions.eyeHeight(); - this.mergeLevel = level.sakuraConfig().cannons.mergeLevel; // Sakura -+ this.travelDistanceLimit = Math.pow(level.sakuraConfig().entity.chunkTravelLimit.getOrDefault(type, Integer.MAX_VALUE) * 16.0, 2); // Sakura - entity travel distance limits ++ this.travelDistanceLimit = Math.pow(this.level.sakuraConfig().entity.chunkTravelLimit.getOrDefault(type, Integer.MAX_VALUE) * 16.0, 2); // Sakura - entity travel distance limits } public boolean isColliding(BlockPos pos, BlockState state) {