From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Samsuik Date: Mon, 22 Apr 2024 23:01:26 +0100 Subject: [PATCH] Replace explosion density cache diff --git a/src/main/java/me/samsuik/sakura/explosion/density/BlockDensityCache.java b/src/main/java/me/samsuik/sakura/explosion/density/BlockDensityCache.java new file mode 100644 index 0000000000000000000000000000000000000000..b760b03f9ddc1fb2aed135105030fc1b5dc2c9c9 --- /dev/null +++ b/src/main/java/me/samsuik/sakura/explosion/density/BlockDensityCache.java @@ -0,0 +1,65 @@ +package me.samsuik.sakura.explosion.density; + +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; + +/** + * This is a replacement for papers explosion density cache to be more lenient and efficient. + */ +public final class BlockDensityCache { + public static final float UNKNOWN_DENSITY = -1.0f; + + private final Int2ObjectOpenHashMap densityDataMap = new Int2ObjectOpenHashMap<>(); + private DensityData data; + private int key; + private boolean knownSource; + + public float getDensity(Vec3 explosion, Entity entity) { + int key = getKey(explosion, entity); + DensityData data = this.densityDataMap.get(key); + + 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 getKnownDensity(Vec3 point) { + if (this.knownSource && this.data.isKnownPosition(point)) { + return this.data.density(); + } else { + return UNKNOWN_DENSITY; + } + } + + 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); + } + } + + public void clear(long tick) { + // trim size every 30 seconds + if (tick != -1 && tick % 600 == 0) + this.densityDataMap.trim(); + 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; + } +} diff --git a/src/main/java/me/samsuik/sakura/explosion/density/DensityData.java b/src/main/java/me/samsuik/sakura/explosion/density/DensityData.java new file mode 100644 index 0000000000000000000000000000000000000000..d7e24638f07f243502004970ab4ce646cbe1e436 --- /dev/null +++ b/src/main/java/me/samsuik/sakura/explosion/density/DensityData.java @@ -0,0 +1,47 @@ +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.isAABBInBounds(entity); + } + + public boolean isKnownPosition(Vec3 point) { + return this.entity.isVec3InBounds(point); + } + + public boolean isExplosionPosition(Vec3 explosion) { + return this.source.isVec3InBounds(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()); + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 536dd6fd0317779e04f133d2ae32a251da9e4394..532abec1030f28df6ee0629ca3aef2766311bd99 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1621,6 +1621,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop getTypeKey(); 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 f44d79ed9f3b93712ce8b40c020955d19ec8fb9d..4c5dbc6a6a03c9504ca7de35462d369305b08edd 100644 --- a/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java +++ b/src/main/java/net/minecraft/world/level/block/BasePressurePlateBlock.java @@ -99,6 +99,11 @@ public abstract class BasePressurePlateBlock extends Block { if (output != j) { BlockState iblockdata1 = this.setSignalForState(state, j); + // Sakura start - explosion density cache + if (!world.paperConfig().environment.optimizeExplosions) { + world.densityCache.clear(-1); + } + // Sakura end - explosion density cache world.setBlock(pos, iblockdata1, 2); this.updateNeighbours(world, pos); world.setBlocksDirty(pos, state, iblockdata1); diff --git a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java index 5e973eb53b240615e70b7d46ef4dc17b907ecaf9..5655aa0f5c91bb9c65a00d2f8a6fb6426d2a1c5d 100644 --- a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java +++ b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java @@ -163,6 +163,11 @@ public class TripWireHookBlock extends Block { blockposition1 = pos.relative(enumdirection, j); Direction enumdirection1 = enumdirection.getOpposite(); + // Sakura start - explosion density cache + if (!world.paperConfig().environment.optimizeExplosions) { + world.densityCache.clear(-1); + } + // Sakura end - explosion density cache world.setBlock(blockposition1, (BlockState) iblockdata3.setValue(TripWireHookBlock.FACING, enumdirection1), 3); this.notifyNeighbors(world, blockposition1, enumdirection1); this.playSound(world, blockposition1, flag4, flag5, flag2, flag3); diff --git a/src/main/java/net/minecraft/world/phys/AABB.java b/src/main/java/net/minecraft/world/phys/AABB.java index 68cc6f2a78a06293a29317fda72ab3ee79b3533a..a142bf12ef0b8c8d41cab846da2e161700f2db2b 100644 --- a/src/main/java/net/minecraft/world/phys/AABB.java +++ b/src/main/java/net/minecraft/world/phys/AABB.java @@ -367,4 +367,28 @@ public class AABB { public static AABB ofSize(Vec3 center, double dx, double dy, double dz) { return new AABB(center.x - dx / 2.0D, center.y - dy / 2.0D, center.z - dz / 2.0D, center.x + dx / 2.0D, center.y + dy / 2.0D, center.z + dz / 2.0D); } + + // Sakura start - explosion density cache + public final boolean isAABBInBounds(AABB bb) { + return this.minX <= bb.minX && this.maxX >= bb.maxX + && this.minY <= bb.minY && this.maxY >= bb.maxY + && this.minZ <= bb.minZ && this.maxZ >= bb.maxZ; + } + + public final boolean isVec3InBounds(Vec3 p) { + return this.minX <= p.x && this.maxX >= p.x + && this.minY <= p.y && this.maxY >= p.y + && this.minZ <= p.z && this.maxZ >= p.z; + } + + public final AABB expand(Vec3 pos) { + double minX = Math.min(this.minX, pos.x); + double minY = Math.min(this.minY, pos.y); + double minZ = Math.min(this.minZ, pos.z); + double maxX = Math.max(this.maxX, pos.x); + double maxY = Math.max(this.maxY, pos.y); + double maxZ = Math.max(this.maxZ, pos.z); + return new AABB(minX, minY, minZ, maxX, maxY, maxZ); + } + // Sakura end - explosion density cache }