9
0
mirror of https://github.com/Samsuik/Sakura.git synced 2025-12-27 02:39:06 +00:00

Clean up BlockDensityCache and replicate optimise-explosions behaviour

This commit is contained in:
Samsuik
2025-09-25 13:21:15 +01:00
parent 8d3126aa11
commit 6e5f86e665
11 changed files with 223 additions and 102 deletions

View File

@@ -5,31 +5,31 @@ Subject: [PATCH] Replace explosion density cache
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 496e23c110cbb3b60a6565e1903545e09715f79e..8c4b4cb9e98b8c0334bb7e247e67206bd57c3de2 100644
index 496e23c110cbb3b60a6565e1903545e09715f79e..a73395c1ec0f36019de553c39199957032e316c4 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -693,6 +693,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
this.levelTickScheduler.repeatingTask(this.explosionPositions::clear, 0); // Sakura - client visibility settings
this.levelTickScheduler.repeatingTask(this.mergeHandler::expire, 200); // Sakura - merge cannon entities
+ this.levelTickScheduler.repeatingTask(this.densityCache::invalidate, 0); // Sakura - explosion density cache
+ this.levelTickScheduler.repeatingTask(this.densityCache::expire, 0); // Sakura - explosion density cache
}
// Paper start
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 7b9e61b2286d18f55a365eebda1fe2128023bec9..3e4784e7dbb264e08f944e03d1f59218fafe710b 100644
index 7b9e61b2286d18f55a365eebda1fe2128023bec9..7a30a227a417ecf9f16ce97d53b238935e652d68 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -829,6 +829,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
public final me.samsuik.sakura.listener.BlockChangeTracker blockChangeTracker = new me.samsuik.sakura.listener.BlockChangeTracker(this);
// Sakura end - track block changes and tick scheduler
public final me.samsuik.sakura.entity.merge.EntityMergeHandler mergeHandler = new me.samsuik.sakura.entity.merge.EntityMergeHandler(); // Sakura - merge cannon entities
+ public final me.samsuik.sakura.explosion.density.BlockDensityCache densityCache = new me.samsuik.sakura.explosion.density.BlockDensityCache(); // Sakura - explosion density cache
+ public final me.samsuik.sakura.explosion.density.BlockDensityCache densityCache = new me.samsuik.sakura.explosion.density.BlockDensityCache(this); // Sakura - optimise explosion density cache
protected Level(
WritableLevelData levelData,
diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java
index cc6ee993470a274cdad124b4a7befb016d9a2b6e..c3c90cc17c4f1ebcaddffea4087929e3708aa22f 100644
index cc6ee993470a274cdad124b4a7befb016d9a2b6e..fde0528e00939972adc2f48b1456002dcd28343b 100644
--- a/net/minecraft/world/level/ServerExplosion.java
+++ b/net/minecraft/world/level/ServerExplosion.java
@@ -294,7 +294,12 @@ public class ServerExplosion implements Explosion {
@@ -88,7 +88,7 @@ index cc6ee993470a274cdad124b4a7befb016d9a2b6e..c3c90cc17c4f1ebcaddffea4087929e3
- Float blockDensity = this.level.explosionDensityCache.get(key);
- if (blockDensity == null) {
+ // Sakura start - replace density cache
+ float blockDensity = this.level.densityCache.getDensity(vec3d, entity);
+ float blockDensity = this.level.densityCache.getBlockDensity(vec3d, entity);
+ if (blockDensity == me.samsuik.sakura.explosion.density.BlockDensityCache.UNKNOWN_DENSITY) {
blockDensity = this.getSeenFraction(vec3d, entity, this.directMappedBlockCache, this.mutablePos); // Paper - collision optimisations
- this.level.explosionDensityCache.put(key, blockDensity);

View File

@@ -40,19 +40,19 @@ index 6db566adf2d0df1d26221eda04aa01738df6d3d2..23c135a6355e920535734e946e5bd4d0
return !interactionResult.consumesAction() && context.getItemInHand().has(DataComponents.CONSUMABLE)
? super.use(context.getLevel(), context.getPlayer(), context.getHand())
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 4a258b105b4d27f214178439df1c4ee569c12895..d4b2f81aebc888e6fe041537b71ac52d8dc8b4e7 100644
index a99273ac64a223cc0a728137abca9331e79a546b..f41caed876beff43778e6138ac444f6e2608883d 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -830,6 +830,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
// Sakura end - track block changes and tick scheduler
public final me.samsuik.sakura.entity.merge.EntityMergeHandler mergeHandler = new me.samsuik.sakura.entity.merge.EntityMergeHandler(); // Sakura - merge cannon entities
public final me.samsuik.sakura.explosion.density.BlockDensityCache densityCache = new me.samsuik.sakura.explosion.density.BlockDensityCache(); // Sakura - explosion density cache
public final me.samsuik.sakura.explosion.density.BlockDensityCache densityCache = new me.samsuik.sakura.explosion.density.BlockDensityCache(this); // Sakura - optimise explosion density cache
+ public final me.samsuik.sakura.explosion.durable.DurableBlockManager durabilityManager = new me.samsuik.sakura.explosion.durable.DurableBlockManager(); // Sakura - explosion durable blocks
protected Level(
WritableLevelData levelData,
diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java
index d2b33fb06ce9a806466208d7afd65fa8d3da0292..f8933e198a250f2184fb64bb987575b441ae8a32 100644
index 88192b561c2a071f583d16d1de926917108a8f45..d12473581f5285aff5867e8bebfe34ccbdb1285f 100644
--- a/net/minecraft/world/level/ServerExplosion.java
+++ b/net/minecraft/world/level/ServerExplosion.java
@@ -131,7 +131,7 @@ public class ServerExplosion implements Explosion {

View File

@@ -462,7 +462,7 @@ index 2146efa860d8323a88f3ad365c0cdb66de42154a..b6ddb1ad889a115daeba64321d38b236
if (!visitor.visit(blockPos, 0)) {
return false;
diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java
index f79e8f48a1f9a6964e1449c099df39076615dd88..e79de0fc3102c107d2c49e1b084b65d5c667e6e3 100644
index e6ca200bf17e097f65204d7cead78306573e4782..5ac921b85f4dd200dd9932c7a702c07cfad36e63 100644
--- a/net/minecraft/world/level/ServerExplosion.java
+++ b/net/minecraft/world/level/ServerExplosion.java
@@ -376,6 +376,7 @@ public class ServerExplosion implements Explosion {
@@ -529,7 +529,7 @@ index f79e8f48a1f9a6964e1449c099df39076615dd88..e79de0fc3102c107d2c49e1b084b65d5
d2 /= squareRoot;
@@ -913,7 +937,7 @@ public class ServerExplosion implements Explosion {
// Sakura start - replace density cache
float blockDensity = this.level.densityCache.getDensity(vec3d, entity);
float blockDensity = this.level.densityCache.getBlockDensity(vec3d, entity);
if (blockDensity == me.samsuik.sakura.explosion.density.BlockDensityCache.UNKNOWN_DENSITY) {
- blockDensity = this.getSeenFraction(vec3d, entity, this.directMappedBlockCache, this.mutablePos); // Paper - collision optimisations
+ blockDensity = this.sakura_getSeenPercent(vec3d, entity); // Sakura - configure server mechanics

View File

@@ -33,24 +33,24 @@ index ff747a1ecdf3c888bca0d69de4f85dcd810b6139..d90f6aa4557b5863eba6a206226f763c
}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 29e1683741241f4f1e578041371a116170f2d1d2..fa109c801fd556e9e09dd0a81d5e05cb942082dd 100644
index 8a046ad7590bd358d416f4aa21a3c173d0931d2a..cdcc64da3481ea8ab4bc680fef775bc193e65c41 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -694,6 +694,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
this.levelTickScheduler.repeatingTask(this.explosionPositions::clear, 0); // Sakura - client visibility settings
this.levelTickScheduler.repeatingTask(this.mergeHandler::expire, 200); // Sakura - merge cannon entities
this.levelTickScheduler.repeatingTask(this.densityCache::invalidate, 0); // Sakura - explosion density cache
this.levelTickScheduler.repeatingTask(this.densityCache::expire, 0); // Sakura - explosion density cache
+ this.levelTickScheduler.repeatingTask(this.redstoneWireCache::expire, 300); // Sakura - cache vanilla and eigencraft wires
}
// Paper start
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 92b3a69b2f87f44cb0c797d5986d501a649f4fe4..c1f9d65aba951963ebb297393580df3d6969c021 100644
index 38baa1b6c846fd1f8cdbe9faf5e38300dade87e9..307542eff210e8824f651ca42e15b00c22df98fc 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -831,6 +831,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
public final me.samsuik.sakura.entity.merge.EntityMergeHandler mergeHandler = new me.samsuik.sakura.entity.merge.EntityMergeHandler(); // Sakura - merge cannon entities
public final me.samsuik.sakura.explosion.density.BlockDensityCache densityCache = new me.samsuik.sakura.explosion.density.BlockDensityCache(); // Sakura - explosion density cache
public final me.samsuik.sakura.explosion.density.BlockDensityCache densityCache = new me.samsuik.sakura.explosion.density.BlockDensityCache(this); // Sakura - optimise explosion density cache
public final me.samsuik.sakura.explosion.durable.DurableBlockManager durabilityManager = new me.samsuik.sakura.explosion.durable.DurableBlockManager(); // Sakura - explosion durable blocks
+ public final me.samsuik.sakura.redstone.RedstoneWireCache redstoneWireCache = new me.samsuik.sakura.redstone.RedstoneWireCache(this); // Sakura - cache vanilla and eigencraft wires

View File

@@ -0,0 +1,29 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Thu, 25 Sep 2025 11:26:32 +0100
Subject: [PATCH] fixup! Configure cannon physics
diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java
index f8ad47d47ee060be66b735eacdcb19ee8e5c7628..f008ffa972eddf1d6bd0c3c2ef75332a56fb3448 100644
--- a/net/minecraft/world/level/ServerExplosion.java
+++ b/net/minecraft/world/level/ServerExplosion.java
@@ -391,7 +391,17 @@ public class ServerExplosion implements Explosion {
return this.damageCalculator.getBlockExplosionResistance(this, this.level, pos, blockState, fluidState);
}
// Sakura end - explosion durable blocks
- protected final me.samsuik.sakura.mechanics.MinecraftMechanicsTarget mechanicsTarget; // Sakura - configure server mechanics
+ // Sakura start - configure server mechanics
+ protected final me.samsuik.sakura.mechanics.MinecraftMechanicsTarget mechanicsTarget;
+
+ private float sakura$getSeenPercent(final Vec3 explosionPos, final Entity entity) {
+ if (this.mechanicsTarget.atLeast(me.samsuik.sakura.mechanics.MechanicVersion.v1_16)) {
+ return this.getSeenFraction(explosionPos, entity, this.directMappedBlockCache, this.mutablePos); // Paper - collision optimisations
+ } else {
+ return getSeenPercent(explosionPos, entity);
+ }
+ }
+ // Sakura end - configure server mechanics
public ServerExplosion(
ServerLevel level,

View File

@@ -0,0 +1,19 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Thu, 25 Sep 2025 11:26:32 +0100
Subject: [PATCH] fixup! Configure cannon physics
diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java
index f008ffa972eddf1d6bd0c3c2ef75332a56fb3448..ba4979657e65bfc97bb597e7aaa6ce6d030c1346 100644
--- a/net/minecraft/world/level/ServerExplosion.java
+++ b/net/minecraft/world/level/ServerExplosion.java
@@ -967,7 +967,7 @@ public class ServerExplosion implements Explosion {
// Sakura start - replace density cache
float blockDensity = this.level.densityCache.getBlockDensity(vec3d, entity);
if (blockDensity == me.samsuik.sakura.explosion.density.BlockDensityCache.UNKNOWN_DENSITY) {
- blockDensity = this.sakura_getSeenPercent(vec3d, entity); // Sakura - configure server mechanics
+ blockDensity = this.sakura$getSeenPercent(vec3d, entity); // Sakura - configure server mechanics
this.level.densityCache.putDensity(vec3d, entity, blockDensity);
// Sakura end - replace density cache
}

View File

@@ -0,0 +1,27 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Thu, 25 Sep 2025 11:26:32 +0100
Subject: [PATCH] fixup! Configure cannon physics
diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java
index ba4979657e65bfc97bb597e7aaa6ce6d030c1346..a88add750945a1a374d248ba6b2eb0688d9bec18 100644
--- a/net/minecraft/world/level/ServerExplosion.java
+++ b/net/minecraft/world/level/ServerExplosion.java
@@ -975,16 +975,6 @@ public class ServerExplosion implements Explosion {
return blockDensity;
}
- // Sakura start - configure server mechanics
- private float sakura_getSeenPercent(final Vec3 vec3d, final Entity entity) {
- if (this.mechanicsTarget.atLeast(me.samsuik.sakura.mechanics.MechanicVersion.v1_16)) {
- return this.getSeenFraction(vec3d, entity, this.directMappedBlockCache, this.mutablePos); // Paper - collision optimisations
- } else {
- return getSeenPercent(vec3d, entity);
- }
- }
- // Sakura end - configure server mechanics
-
static class CacheKey {
private final Level world;
private final double posX, posY, posZ;

View File

@@ -1,62 +1,85 @@
package me.samsuik.sakura.explosion.density;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minecraft.util.Mth;
import it.unimi.dsi.fastutil.objects.Object2FloatOpenHashMap;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
/**
* This is a replacement for papers explosion density cache to be more lenient and efficient.
*/
@NullMarked
public final class BlockDensityCache {
public static final float UNKNOWN_DENSITY = -1.0f;
private final Int2ObjectOpenHashMap<DensityData> densityDataMap = new Int2ObjectOpenHashMap<>();
private DensityData data;
private int key;
private final Object2FloatOpenHashMap<BlockDensityCacheKey> paperExactPosDensityCache = new Object2FloatOpenHashMap<>();
private final Int2ObjectOpenHashMap<CachedBlockDensity> lenientDensityCache = new Int2ObjectOpenHashMap<>();
private @Nullable BlockDensityCacheKey densityCacheKey;
private @Nullable CachedBlockDensity cacheInUse;
private int cacheKeyInUse;
private boolean knownSource;
private final Level level;
public float getDensity(Vec3 explosion, Entity entity) {
int key = getKey(explosion, entity);
DensityData data = this.densityDataMap.get(key);
public BlockDensityCache(final Level level) {
this.level = level;
this.paperExactPosDensityCache.defaultReturnValue(UNKNOWN_DENSITY);
}
if (data != null && data.hasPosition(explosion, entity.getBoundingBox())) {
return data.density();
} else {
this.knownSource = data != null && data.complete() && data.isExplosionPosition(explosion);
this.data = data;
this.key = key;
return UNKNOWN_DENSITY;
public float getBlockDensity(final Vec3 explosionPos, final Entity entity) {
final int lenientKey = BlockDensityCacheKey.getLenientKey(explosionPos, entity.blockPosition());
final CachedBlockDensity cache = this.lenientDensityCache.get(lenientKey);
// Check if the density is cached
if (cache != null && cache.hasPosition(explosionPos, entity.getBoundingBox())) {
return cache.blockDensity();
}
// Replicate the broken behaviour of optimize-explosions
if (this.level.paperConfig().environment.optimizeExplosions) {
final BlockDensityCacheKey cacheKey = new BlockDensityCacheKey(explosionPos, entity);
final float blockDensity = this.paperExactPosDensityCache.getFloat(cacheKey);
if (blockDensity != UNKNOWN_DENSITY) {
return blockDensity;
}
this.densityCacheKey = cacheKey;
}
this.knownSource = cache != null && cache.complete() && cache.isExplosionPosition(explosionPos);
this.cacheInUse = cache;
this.cacheKeyInUse = lenientKey;
return UNKNOWN_DENSITY;
}
public float getKnownDensity(final Vec3 point) {
return this.knownSource && this.cacheInUse.isKnownPosition(point)
? this.cacheInUse.blockDensity()
: UNKNOWN_DENSITY;
}
public void putDensity(final Vec3 explosionPos, final Entity entity, final float blockDensity) {
final CachedBlockDensity cache = this.cacheInUse;
if (cache == null || !cache.complete()) {
this.lenientDensityCache.put(this.cacheKeyInUse, new CachedBlockDensity(explosionPos, entity, blockDensity));
} else if (cache.blockDensity() == blockDensity) {
cache.expand(explosionPos, entity);
}
if (this.level.paperConfig().environment.optimizeExplosions && this.densityCacheKey != null) {
this.paperExactPosDensityCache.put(this.densityCacheKey, blockDensity);
}
}
public float getKnownDensity(Vec3 point) {
if (this.knownSource && this.data.isKnownPosition(point)) {
return this.data.density();
} else {
return UNKNOWN_DENSITY;
}
}
public void expire(final long tick) {
this.invalidate();
public void putDensity(Vec3 explosion, Entity entity, float density) {
if (this.data == null || !this.data.complete()) {
this.densityDataMap.put(this.key, new DensityData(explosion, entity, density));
} else if (this.data.density() == density) {
this.data.expand(explosion, entity);
if (tick % 600 == 0) {
// Trim everything down every 600 ticks
this.paperExactPosDensityCache.trim(0);
this.lenientDensityCache.trim(0);
}
}
public void invalidate() {
this.densityDataMap.clear();
}
private static int getKey(Vec3 explosion, Entity entity) {
int key = Mth.floor(explosion.x());
key = 31 * key + Mth.floor(explosion.y());
key = 31 * key + Mth.floor(explosion.z());
key = 31 * key + entity.getBlockX();
key = 31 * key + entity.getBlockY();
key = 31 * key + entity.getBlockZ();
return key;
this.lenientDensityCache.clear();
}
}

View File

@@ -0,0 +1,24 @@
package me.samsuik.sakura.explosion.density;
import net.minecraft.core.BlockPos;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.Vec3;
import org.jspecify.annotations.NullMarked;
@NullMarked
public record BlockDensityCacheKey(Vec3 explosionPos, Vec3 entityPos) {
public BlockDensityCacheKey(final Vec3 explosionPos, final Entity entity) {
this(explosionPos, entity.position());
}
public static int getLenientKey(final Vec3 explosionPos, final BlockPos entityBlockPos) {
int key = Mth.floor(explosionPos.x());
key = 31 * key + Mth.floor(explosionPos.y());
key = 31 * key + Mth.floor(explosionPos.z());
key = 31 * key + entityBlockPos.getX();
key = 31 * key + entityBlockPos.getY();
key = 31 * key + entityBlockPos.getZ();
return key;
}
}

View File

@@ -0,0 +1,46 @@
package me.samsuik.sakura.explosion.density;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.jspecify.annotations.NullMarked;
@NullMarked
public final class CachedBlockDensity {
private AABB source;
private AABB entity;
private final float blockDensity;
private final boolean complete;
public CachedBlockDensity(final Vec3 explosionPos, final Entity entity, final float blockDensity) {
this.source = new AABB(explosionPos, explosionPos);
this.entity = entity.getBoundingBox();
this.blockDensity = blockDensity;
this.complete = blockDensity == 0.0f || blockDensity == 1.0f;
}
public float blockDensity() {
return this.blockDensity;
}
public boolean complete() {
return this.complete;
}
public boolean hasPosition(final Vec3 explosionPos, final AABB entityBoundingBox) {
return this.isExplosionPosition(explosionPos) && this.entity.containsInclusive(entityBoundingBox);
}
public boolean isKnownPosition(final Vec3 point) {
return this.entity.containsInclusive(point);
}
public boolean isExplosionPosition(final Vec3 explosionPos) {
return this.source.containsInclusive(explosionPos);
}
public void expand(final Vec3 explosionPos, final Entity entity) {
this.source = this.source.expand(explosionPos);
this.entity = this.entity.minmax(entity.getBoundingBox());
}
}

View File

@@ -1,47 +0,0 @@
package me.samsuik.sakura.explosion.density;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
public final class DensityData {
private AABB source;
private AABB known;
private AABB entity;
private final float density;
private final boolean complete;
public DensityData(Vec3 explosion, Entity entity, float density) {
this.source = new AABB(explosion, explosion);
this.known = new AABB(entity.position(), entity.position());
this.entity = entity.getBoundingBox();
this.density = density;
this.complete = Math.abs(density - 0.5f) == 0.5f;
}
public float density() {
return this.density;
}
public boolean complete() {
return this.complete;
}
public boolean hasPosition(Vec3 explosion, AABB entity) {
return this.isExplosionPosition(explosion) && this.entity.containsInclusive(entity);
}
public boolean isKnownPosition(Vec3 point) {
return this.entity.containsInclusive(point);
}
public boolean isExplosionPosition(Vec3 explosion) {
return this.source.containsInclusive(explosion);
}
public void expand(Vec3 explosion, Entity entity) {
this.source = this.source.expand(explosion);
this.known = this.known.expand(entity.position());
this.entity = this.entity.minmax(entity.getBoundingBox());
}
}