mirror of
https://github.com/Samsuik/Sakura.git
synced 2026-01-06 15:41:49 +00:00
Half way through feature patches
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -13,7 +13,7 @@ paper-api-generator
|
||||
build.gradle.kts.rej
|
||||
sakura-api/build.gradle.kts
|
||||
sakura-server/build.gradle.kts
|
||||
src/minecraft/
|
||||
src/vanilla/
|
||||
sakura-server/src/minecraft/
|
||||
sakura-server/src/vanilla/
|
||||
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Mon, 22 Apr 2024 23:01:26 +0100
|
||||
Subject: [PATCH] Replace explosion density cache
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index ae1fad06d85de83f53884449cff21fc0ae62bf97..6d8c513e78fa4efd8c7f6f534cf3958d46448efb 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1751,6 +1751,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
serverLevel.explosionDensityCache.clear(); // Paper - Optimize explosions
|
||||
serverLevel.explosionPositions.clear(); // Sakura - client visibility settings
|
||||
serverLevel.mergeHandler.expire(currentTick); // Sakura - merge cannon entities
|
||||
+ serverLevel.densityCache.invalidate(); // Sakura - explosion density cache
|
||||
}
|
||||
this.isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
|
||||
|
||||
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||
index a4d7c95514c3db5799efe178efee796413d1bac8..4dd2c4110d85bb7e6575b325196329900d719c64 100644
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -838,6 +838,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
}
|
||||
// Paper end - optimise random ticking
|
||||
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
|
||||
|
||||
protected Level(
|
||||
WritableLevelData levelData,
|
||||
diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java
|
||||
index 9f06e32101f494d94d9210210255d5d72ca4ff36..6d3e03b3c9fed817808de6ee08b531069d342dd5 100644
|
||||
--- a/net/minecraft/world/level/ServerExplosion.java
|
||||
+++ b/net/minecraft/world/level/ServerExplosion.java
|
||||
@@ -296,7 +296,12 @@ public class ServerExplosion implements Explosion {
|
||||
Math.fma(dz, diffZ, offZ)
|
||||
);
|
||||
|
||||
- if (!this.clipsAnything(from, source, context, blockCache, blockPos)) {
|
||||
+ // Sakura start - replace density cache
|
||||
+ final float density = this.level.densityCache.getKnownDensity(from);
|
||||
+ if (density != me.samsuik.sakura.explosion.density.BlockDensityCache.UNKNOWN_DENSITY) {
|
||||
+ missedRays += (int) density;
|
||||
+ } else if (!this.clipsAnything(from, source, context, blockCache, blockPos)) {
|
||||
+ // Sakura end - replace density cache
|
||||
++missedRays;
|
||||
}
|
||||
}
|
||||
@@ -385,8 +390,16 @@ public class ServerExplosion implements Explosion {
|
||||
double d9 = Mth.lerp(d6, boundingBox.minY, boundingBox.maxY);
|
||||
double d10 = Mth.lerp(d7, boundingBox.minZ, boundingBox.maxZ);
|
||||
Vec3 vec3 = new Vec3(d8 + d3, d9, d10 + d4);
|
||||
- if (entity.level().clip(new ClipContext(vec3, explosionVector, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, entity)).getType()
|
||||
- == HitResult.Type.MISS) {
|
||||
+ // Sakura start - replace density cache
|
||||
+ final net.minecraft.world.phys.HitResult.Type hitResult;
|
||||
+ final float density = entity.level().densityCache.getKnownDensity(vec3);
|
||||
+ if (density != me.samsuik.sakura.explosion.density.BlockDensityCache.UNKNOWN_DENSITY) {
|
||||
+ hitResult = density != 0.0f ? net.minecraft.world.phys.HitResult.Type.MISS : net.minecraft.world.phys.HitResult.Type.BLOCK;
|
||||
+ } else {
|
||||
+ hitResult = entity.level().clip(new ClipContext(vec3, explosionVector, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, entity)).getType();
|
||||
+ }
|
||||
+ if (hitResult == HitResult.Type.MISS) {
|
||||
+ // Sakura end - replace density cache
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -691,6 +704,11 @@ public class ServerExplosion implements Explosion {
|
||||
return;
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ // Sakura start - explosion density cache
|
||||
+ if (!blocks.isEmpty() && !this.level.paperConfig().environment.optimizeExplosions) {
|
||||
+ this.level.densityCache.invalidate();
|
||||
+ }
|
||||
+ // Sakura end - explosion density cache
|
||||
|
||||
for (BlockPos blockPos : blocks) {
|
||||
// CraftBukkit start - TNTPrimeEvent
|
||||
@@ -857,14 +875,12 @@ public class ServerExplosion implements Explosion {
|
||||
|
||||
// Paper start - Optimize explosions
|
||||
protected float getBlockDensity(Vec3 vec3d, Entity entity) {
|
||||
- if (!this.level.paperConfig().environment.optimizeExplosions) {
|
||||
- return this.getSeenFraction(vec3d, entity, this.directMappedBlockCache, this.mutablePos); // Paper - collision optimisations
|
||||
- }
|
||||
- CacheKey key = new CacheKey(this, entity.getBoundingBox());
|
||||
- Float blockDensity = this.level.explosionDensityCache.get(key);
|
||||
- if (blockDensity == null) {
|
||||
+ // Sakura start - replace density cache
|
||||
+ float blockDensity = this.level.densityCache.getDensity(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);
|
||||
+ this.level.densityCache.putDensity(vec3d, entity, blockDensity);
|
||||
+ // Sakura end - replace density cache
|
||||
}
|
||||
|
||||
return blockDensity;
|
||||
diff --git a/net/minecraft/world/level/block/BasePressurePlateBlock.java b/net/minecraft/world/level/block/BasePressurePlateBlock.java
|
||||
index 69d490c79e30fb42da69bbd804ecaea7b88fe7b0..497409e04dc4b9366da1fbe0641b8424c727a176 100644
|
||||
--- a/net/minecraft/world/level/block/BasePressurePlateBlock.java
|
||||
+++ b/net/minecraft/world/level/block/BasePressurePlateBlock.java
|
||||
@@ -109,6 +109,11 @@ public abstract class BasePressurePlateBlock extends Block {
|
||||
// CraftBukkit end
|
||||
if (currentSignal != signalStrength) {
|
||||
BlockState blockState = this.setSignalForState(state, signalStrength);
|
||||
+ // Sakura start - explosion density cache
|
||||
+ if (!level.paperConfig().environment.optimizeExplosions) {
|
||||
+ level.densityCache.invalidate();
|
||||
+ }
|
||||
+ // Sakura end - explosion density cache
|
||||
level.setBlock(pos, blockState, 2);
|
||||
this.updateNeighbours(level, pos);
|
||||
level.setBlocksDirty(pos, state, blockState);
|
||||
diff --git a/net/minecraft/world/level/block/TripWireHookBlock.java b/net/minecraft/world/level/block/TripWireHookBlock.java
|
||||
index 6a7e5a642e2eaf7d5dffadb81738f7385a38c0af..dd2ceb8fd24281a6dd06084145f387cff55c6cc9 100644
|
||||
--- a/net/minecraft/world/level/block/TripWireHookBlock.java
|
||||
+++ b/net/minecraft/world/level/block/TripWireHookBlock.java
|
||||
@@ -182,6 +182,11 @@ public class TripWireHookBlock extends Block {
|
||||
if (!cancelledReceiverHook) { // always trigger two events even when the first hook current change is cancelled
|
||||
// Paper end - Call BlockRedstoneEvent
|
||||
Direction opposite = direction.getOpposite();
|
||||
+ // Sakura start - explosion density cache
|
||||
+ if (!level.paperConfig().environment.optimizeExplosions) {
|
||||
+ level.densityCache.invalidate();
|
||||
+ }
|
||||
+ // Sakura end - explosion density cache
|
||||
level.setBlock(blockPosx, blockState1.setValue(FACING, opposite), 3);
|
||||
notifyNeighbors(block, level, blockPosx, opposite);
|
||||
emitState(level, blockPosx, flag2, flag3, flag, flag1);
|
||||
diff --git a/net/minecraft/world/phys/AABB.java b/net/minecraft/world/phys/AABB.java
|
||||
index 85148858db1fd5e9da8bbdde4b0d84110d80e373..23d5a2726f6113eaa79196ac6f6b8db85e386f97 100644
|
||||
--- a/net/minecraft/world/phys/AABB.java
|
||||
+++ b/net/minecraft/world/phys/AABB.java
|
||||
@@ -442,4 +442,28 @@ public class AABB {
|
||||
center.x - xSize / 2.0, center.y - ySize / 2.0, center.z - zSize / 2.0, center.x + xSize / 2.0, center.y + ySize / 2.0, center.z + zSize / 2.0
|
||||
);
|
||||
}
|
||||
+
|
||||
+ // 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
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Fri, 3 May 2024 15:18:58 +0100
|
||||
Subject: [PATCH] Optimise explosions in protected regions
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java
|
||||
index 6d3e03b3c9fed817808de6ee08b531069d342dd5..76697d12a12eeedbaab6aef169080320791aff6e 100644
|
||||
--- a/net/minecraft/world/level/ServerExplosion.java
|
||||
+++ b/net/minecraft/world/level/ServerExplosion.java
|
||||
@@ -345,6 +345,22 @@ public class ServerExplosion implements Explosion {
|
||||
return rays;
|
||||
}
|
||||
// Sakura end - optimise paper explosions
|
||||
+ // Sakura start - optimise explosion protected regions
|
||||
+ protected final boolean isRegionUnprotected() {
|
||||
+ // optimisation: We check if a plugin has cancelled the event or cleared the blockList.
|
||||
+ // It tells us if the result was thrown away, so we can avoid the block searching logic.
|
||||
+ // As a side effect the event is called twice which may interfere with some plugins.
|
||||
+ if (this.source != null && this.level.sakuraConfig().cannons.explosion.optimiseProtectedRegions) {
|
||||
+ Location location = new Location(this.level.getWorld(), this.center.x, this.center.y, this.center.z);
|
||||
+ List<org.bukkit.block.Block> blocks = new ObjectArrayList<>(1);
|
||||
+ blocks.add(location.getBlock());
|
||||
+ EntityExplodeEvent event = CraftEventFactory.callEntityExplodeEvent(this.source, blocks, 0.0f, this.blockInteraction);
|
||||
+ return !event.isCancelled() && !event.blockList().isEmpty();
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Sakura end - optimise explosion protected regions
|
||||
|
||||
public ServerExplosion(
|
||||
ServerLevel level,
|
||||
@@ -449,6 +465,11 @@ public class ServerExplosion implements Explosion {
|
||||
return ret;
|
||||
}
|
||||
// Sakura end - optimise paper explosions
|
||||
+ // Sakura start - optimise protected explosions
|
||||
+ if (!this.isRegionUnprotected()) {
|
||||
+ return ret;
|
||||
+ }
|
||||
+ // Sakura end - optimise protected explosions
|
||||
|
||||
// only ~1/3rd of the loop iterations in vanilla will result in a ray, as it is iterating the perimeter of
|
||||
// a 16x16x16 cube
|
||||
@@ -0,0 +1,165 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Fri, 3 May 2024 15:04:31 +0100
|
||||
Subject: [PATCH] Specialised Explosions
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 83bd1ddec7edb09e9a28eead178d7d07cbde8749..ee44ba44773f245d351aac9461bd6cff18204f01 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1866,7 +1866,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
case STANDARD -> Explosion.BlockInteraction.DESTROY; // CraftBukkit - handle custom explosion type
|
||||
};
|
||||
Vec3 vec3 = new Vec3(x, y, z);
|
||||
- ServerExplosion serverExplosion = new ServerExplosion(this, source, damageSource, damageCalculator, vec3, radius, fire, blockInteraction);
|
||||
+ // Sakura start - specialised explosions
|
||||
+ final ServerExplosion serverExplosion;
|
||||
+ if (source instanceof net.minecraft.world.entity.item.PrimedTnt tnt) {
|
||||
+ serverExplosion = new me.samsuik.sakura.explosion.special.TntExplosion(this, tnt, damageSource, damageCalculator, vec3, radius, fire, blockInteraction, self -> {
|
||||
+ this.notifyPlayersOfExplosion(self, self.center(), smallExplosionParticles, largeExplosionParticles, explosionSound);
|
||||
+ });
|
||||
+ } else {
|
||||
+ serverExplosion = new ServerExplosion(this, source, damageSource, damageCalculator, vec3, radius, fire, blockInteraction);
|
||||
+ }
|
||||
+ // Sakura end - specialised explosions
|
||||
if (configurator != null) configurator.accept(serverExplosion);// Paper - Allow explosions to damage source
|
||||
serverExplosion.explode();
|
||||
// CraftBukkit start
|
||||
@@ -1874,6 +1883,15 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
return serverExplosion;
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ // Sakura start - specialised explosions
|
||||
+ this.notifyPlayersOfExplosion(serverExplosion, vec3, smallExplosionParticles, largeExplosionParticles, explosionSound);
|
||||
+ return serverExplosion;
|
||||
+ }
|
||||
+
|
||||
+ private void notifyPlayersOfExplosion(ServerExplosion serverExplosion, Vec3 vec3,
|
||||
+ ParticleOptions smallExplosionParticles, ParticleOptions largeExplosionParticles,
|
||||
+ Holder<SoundEvent> explosionSound) {
|
||||
+ // Sakura end - specialised explosions
|
||||
ParticleOptions particleOptions = serverExplosion.isSmall() ? smallExplosionParticles : largeExplosionParticles;
|
||||
|
||||
for (ServerPlayer serverPlayer : this.players) {
|
||||
@@ -1894,7 +1912,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
}
|
||||
}
|
||||
|
||||
- return serverExplosion; // CraftBukkit
|
||||
+ // Sakura - specialised explosions; return moved up into explode0
|
||||
}
|
||||
|
||||
private Explosion.BlockInteraction getDestroyType(GameRules.Key<GameRules.BooleanValue> decayGameRule) {
|
||||
diff --git a/net/minecraft/world/entity/item/PrimedTnt.java b/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
index b378b4c4930c4ebd55795591aca173fd1fee46c9..c88fe6c244f6a88f1e42822dd0795187dcc3b655 100644
|
||||
--- a/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
+++ b/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
@@ -77,20 +77,7 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak
|
||||
|
||||
@Override
|
||||
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
|
||||
- tnt.setPos(this.position());
|
||||
- tnt.setDeltaMovement(this.getDeltaMovement());
|
||||
- this.entityState().apply(this);
|
||||
- tnt.explode();
|
||||
- this.storeEntityState();
|
||||
-
|
||||
- this.tick();
|
||||
- }
|
||||
+ this.mergeData.setCount(count); // Sakura - specialised explosions
|
||||
}
|
||||
// Sakura end - merge cannon entities
|
||||
|
||||
diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java
|
||||
index 76697d12a12eeedbaab6aef169080320791aff6e..0285e19d6265056fb5ff9855a5dd41bd16bbc082 100644
|
||||
--- a/net/minecraft/world/level/ServerExplosion.java
|
||||
+++ b/net/minecraft/world/level/ServerExplosion.java
|
||||
@@ -361,6 +361,38 @@ public class ServerExplosion implements Explosion {
|
||||
return true;
|
||||
}
|
||||
// Sakura end - optimise explosion protected regions
|
||||
+ // Sakura start - specialised explosions
|
||||
+ protected final void createBlockCache() {
|
||||
+ // Paper start - collision optimisations
|
||||
+ this.blockCache = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>();
|
||||
+ this.chunkPosCache = new long[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
||||
+ java.util.Arrays.fill(this.chunkPosCache, ChunkPos.INVALID_CHUNK_POS);
|
||||
+ this.chunkCache = new net.minecraft.world.level.chunk.LevelChunk[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
||||
+ this.directMappedBlockCache = new ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache[BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH];
|
||||
+ this.mutablePos = new BlockPos.MutableBlockPos();
|
||||
+ // Paper end - collision optimisations
|
||||
+ }
|
||||
+
|
||||
+ protected final void markBlocksInCacheAsExplodable(List<BlockPos> explodedPositions) {
|
||||
+ for (BlockPos blow : explodedPositions) {
|
||||
+ ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache cache = this.blockCache.get(blow.asLong());
|
||||
+ // May be null if the blockCache is cleared then retrieved from the recent block cache
|
||||
+ if (cache != null) {
|
||||
+ cache.shouldExplode = null;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ protected final void clearBlockCache() {
|
||||
+ // Paper start - collision optimisations
|
||||
+ this.blockCache = null;
|
||||
+ this.chunkPosCache = null;
|
||||
+ this.chunkCache = null;
|
||||
+ this.directMappedBlockCache = null;
|
||||
+ this.mutablePos = null;
|
||||
+ // Paper end - collision optimisations
|
||||
+ }
|
||||
+ // Sakura end - specialised explosions
|
||||
|
||||
public ServerExplosion(
|
||||
ServerLevel level,
|
||||
@@ -670,7 +702,10 @@ public class ServerExplosion implements Explosion {
|
||||
if (entity instanceof Player) {
|
||||
Player player = (Player)entity;
|
||||
if (!player.isSpectator() && (!player.isCreative() || !player.getAbilities().flying) && !level.paperConfig().environment.disableExplosionKnockback) { // Paper - Option to disable explosion knockback
|
||||
- this.hitPlayers.put(player, vec3);
|
||||
+ // Sakura start - specialised explosions; tally player velocity
|
||||
+ final Vec3 explosionImpact = vec3;
|
||||
+ this.hitPlayers.compute(player, (p, v) -> v != null ? v.add(explosionImpact) : explosionImpact);
|
||||
+ // Sakura end - specialised explosions; tally player velocity
|
||||
}
|
||||
}
|
||||
|
||||
@@ -779,14 +814,7 @@ public class ServerExplosion implements Explosion {
|
||||
return;
|
||||
}
|
||||
// CraftBukkit end
|
||||
- // Paper start - collision optimisations
|
||||
- this.blockCache = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>();
|
||||
- this.chunkPosCache = new long[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
||||
- java.util.Arrays.fill(this.chunkPosCache, ChunkPos.INVALID_CHUNK_POS);
|
||||
- this.chunkCache = new net.minecraft.world.level.chunk.LevelChunk[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
||||
- this.directMappedBlockCache = new ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache[BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH];
|
||||
- this.mutablePos = new BlockPos.MutableBlockPos();
|
||||
- // Paper end - collision optimisations
|
||||
+ this.createBlockCache(); // Sakura - specialised explosions
|
||||
this.level.gameEvent(this.source, GameEvent.EXPLODE, this.center);
|
||||
List<BlockPos> list = this.calculateExplodedPositions();
|
||||
this.hurtEntities();
|
||||
@@ -800,13 +828,7 @@ public class ServerExplosion implements Explosion {
|
||||
if (this.fire) {
|
||||
this.createFire(list);
|
||||
}
|
||||
- // Paper start - collision optimisations
|
||||
- this.blockCache = null;
|
||||
- this.chunkPosCache = null;
|
||||
- this.chunkCache = null;
|
||||
- this.directMappedBlockCache = null;
|
||||
- this.mutablePos = null;
|
||||
- // Paper end - collision optimisations
|
||||
+ this.clearBlockCache(); // Sakura - specialised explosions
|
||||
}
|
||||
|
||||
private static void addOrAppendStack(List<ServerExplosion.StackCollector> stackCollectors, ItemStack stack, BlockPos pos) {
|
||||
@@ -0,0 +1,220 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Fri, 13 Oct 2023 14:36:19 +0100
|
||||
Subject: [PATCH] Optimise cannon entity movement
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 2a617bd6d5d14cd69b149d6c5f82f8b2c3bc2d5d..8c3e0ca06f89e4d8c08d30272475cdeaca20b3ef 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -1141,6 +1141,75 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
return this.moveStartZ;
|
||||
}
|
||||
// Paper end - detailed watchdog information
|
||||
+ // Sakura start - optimise cannon entity movement; stripped back movement method
|
||||
+ public final void moveStripped(MoverType movementType, Vec3 movement) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot move an entity off-main");
|
||||
+ if (this.noPhysics) {
|
||||
+ this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z);
|
||||
+ } else {
|
||||
+ if (movementType == MoverType.PISTON) {
|
||||
+ movement = this.limitPistonMovement(movement);
|
||||
+ if (movement.equals(Vec3.ZERO)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ ProfilerFiller gameprofilerfiller = Profiler.get();
|
||||
+ gameprofilerfiller.push("move");
|
||||
+ if (this.stuckSpeedMultiplier.lengthSqr() > 1.0E-7D) {
|
||||
+ movement = movement.multiply(this.stuckSpeedMultiplier);
|
||||
+ this.stuckSpeedMultiplier = Vec3.ZERO;
|
||||
+ this.setDeltaMovement(Vec3.ZERO);
|
||||
+ }
|
||||
+
|
||||
+ Vec3 vec3d1 = this.sakura_collide(movement);
|
||||
+ double d0 = vec3d1.lengthSqr();
|
||||
+
|
||||
+ if (d0 > 1.0E-7D || movement.lengthSqr() - d0 < 1.0E-7D) {
|
||||
+ if (this.fallDistance != 0.0F && d0 >= 1.0D && !this.isFallingBlock) {
|
||||
+ BlockHitResult clipResult = this.level().clip(new ClipContext(this.position(), this.position().add(vec3d1), ClipContext.Block.FALLDAMAGE_RESETTING, ClipContext.Fluid.WATER, this));
|
||||
+ if (clipResult.getType() != HitResult.Type.MISS) {
|
||||
+ this.resetFallDistance();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ this.setPos(this.getX() + vec3d1.x, this.getY() + vec3d1.y, this.getZ() + vec3d1.z);
|
||||
+ }
|
||||
+
|
||||
+ gameprofilerfiller.pop();
|
||||
+ gameprofilerfiller.push("rest");
|
||||
+ boolean movedX = !Mth.equal(movement.x, vec3d1.x);
|
||||
+ boolean movedZ = !Mth.equal(movement.z, vec3d1.z);
|
||||
+
|
||||
+ this.horizontalCollision = movedX || movedZ;
|
||||
+ this.verticalCollision = movement.y != vec3d1.y;
|
||||
+ this.verticalCollisionBelow = this.verticalCollision && movement.y < 0.0D;
|
||||
+
|
||||
+ this.setOnGroundWithMovement(this.verticalCollisionBelow, this.horizontalCollision, vec3d1);
|
||||
+ BlockPos blockPosBelow = this.getOnPosLegacy();
|
||||
+ BlockState blockstate = this.level().getBlockState(blockPosBelow);
|
||||
+
|
||||
+ this.checkFallDamage(vec3d1.y, this.onGround(), blockstate, blockPosBelow);
|
||||
+ if (this.isRemoved()) {
|
||||
+ gameprofilerfiller.pop();
|
||||
+ } else {
|
||||
+ if (this.horizontalCollision) {
|
||||
+ Vec3 vec3d2 = this.getDeltaMovement();
|
||||
+ this.setDeltaMovement(movedX ? 0.0D : vec3d2.x, vec3d2.y, movedZ ? 0.0D : vec3d2.z);
|
||||
+ }
|
||||
+
|
||||
+ Block block = blockstate.getBlock();
|
||||
+ if (movement.y != vec3d1.y) { // remove y momentum
|
||||
+ block.updateEntityMovementAfterFallOn(this.level(), this);
|
||||
+ }
|
||||
+
|
||||
+ float f = this.getBlockSpeedFactor();
|
||||
+ this.setDeltaMovement(this.getDeltaMovement().multiply((double) f, 1.0D, (double) f));
|
||||
+ gameprofilerfiller.pop();
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Sakura end - optimise cannon entity movement; stripped back movement method
|
||||
|
||||
public void move(MoverType type, Vec3 movement) {
|
||||
final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity
|
||||
@@ -1488,6 +1557,107 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
return distance;
|
||||
}
|
||||
|
||||
+ // Sakura start - optimise cannon entity movement
|
||||
+ private Vec3 sakura_collide(Vec3 movement) {
|
||||
+ if (movement.x == 0.0 && movement.y == 0.0 && movement.z == 0.0) {
|
||||
+ return movement;
|
||||
+ }
|
||||
+
|
||||
+ List<VoxelShape> potentialCollisionsVoxel = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(0);
|
||||
+ List<AABB> potentialCollisionsBB = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(4);
|
||||
+ AABB currBoundingBox = this.getBoundingBox();
|
||||
+
|
||||
+ if (movement.lengthSqr() >= 12.0) { // axis scan on large movement
|
||||
+ return this.collideAxisScan(movement, currBoundingBox, potentialCollisionsVoxel, potentialCollisionsBB);
|
||||
+ } else {
|
||||
+ return this.collideCube(movement, currBoundingBox, potentialCollisionsVoxel, potentialCollisionsBB);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private Vec3 collideCube(Vec3 movement, AABB currBoundingBox, List<VoxelShape> voxelList, List<AABB> bbList) {
|
||||
+ final AABB bb;
|
||||
+ if (movement.x() == 0.0 && movement.z() == 0.0) {
|
||||
+ if (movement.y > 0.0) {
|
||||
+ bb = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.cutUpwards(currBoundingBox, movement.y);
|
||||
+ } else {
|
||||
+ bb = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.cutDownwards(currBoundingBox, movement.y);
|
||||
+ }
|
||||
+ } else {
|
||||
+ bb = currBoundingBox.expandTowards(movement.x, movement.y, movement.z);
|
||||
+ }
|
||||
+ this.collectCollisions(bb, voxelList, bbList);
|
||||
+ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performCollisions(movement, currBoundingBox, voxelList, bbList);
|
||||
+ }
|
||||
+
|
||||
+ private Vec3 collideAxisScan(Vec3 movement, AABB currBoundingBox, List<VoxelShape> voxelList, List<AABB> bbList) {
|
||||
+ double x = movement.x;
|
||||
+ double y = movement.y;
|
||||
+ double z = movement.z;
|
||||
+
|
||||
+ boolean xSmaller = Math.abs(x) < Math.abs(z);
|
||||
+
|
||||
+ if (y != 0.0) {
|
||||
+ y = this.scanY(currBoundingBox, y, voxelList, bbList);
|
||||
+ if (y != 0.0) {
|
||||
+ currBoundingBox = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.offsetY(currBoundingBox, y);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (xSmaller && z != 0.0) {
|
||||
+ z = this.scanZ(currBoundingBox, z, voxelList, bbList);
|
||||
+ if (z != 0.0) {
|
||||
+ currBoundingBox = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.offsetZ(currBoundingBox, z);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (x != 0.0) {
|
||||
+ x = this.scanX(currBoundingBox, x, voxelList, bbList);
|
||||
+ if (x != 0.0) {
|
||||
+ currBoundingBox = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.offsetX(currBoundingBox, x);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!xSmaller && z != 0.0) {
|
||||
+ z = this.scanZ(currBoundingBox, z, voxelList, bbList);
|
||||
+ }
|
||||
+
|
||||
+ return new Vec3(x, y, z);
|
||||
+ }
|
||||
+
|
||||
+ private void collectCollisions(AABB collisionBox, List<VoxelShape> voxelList, List<AABB> bbList) {
|
||||
+ // Copied from the collide method below
|
||||
+ ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.getCollisionsForBlocksOrWorldBorder(
|
||||
+ this.level, this, collisionBox, voxelList, bbList,
|
||||
+ ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_FLAG_CHECK_BORDER | this.getExtraCollisionFlags(), null // Sakura - load chunks on movement
|
||||
+ );
|
||||
+
|
||||
+ ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.getEntityHardCollisions(
|
||||
+ this.level, this, collisionBox, bbList, 0, null
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ private double scanX(AABB currBoundingBox, double x, List<VoxelShape> voxelList, List<AABB> bbList) {
|
||||
+ AABB scanBox = currBoundingBox.expandTowards(x, 0.0, 0.0);
|
||||
+ this.collectCollisions(scanBox, voxelList, bbList);
|
||||
+ x = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performAABBCollisionsX(currBoundingBox, x, bbList);
|
||||
+ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performVoxelCollisionsX(currBoundingBox, x, voxelList);
|
||||
+ }
|
||||
+
|
||||
+ private double scanY(AABB currBoundingBox, double y, List<VoxelShape> voxelList, List<AABB> bbList) {
|
||||
+ AABB scanBox = currBoundingBox.expandTowards(0.0, y, 0.0);
|
||||
+ this.collectCollisions(scanBox, voxelList, bbList);
|
||||
+ y = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performAABBCollisionsY(currBoundingBox, y, bbList);
|
||||
+ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performVoxelCollisionsY(currBoundingBox, y, voxelList);
|
||||
+ }
|
||||
+
|
||||
+ private double scanZ(AABB currBoundingBox, double z, List<VoxelShape> voxelList, List<AABB> bbList) {
|
||||
+ AABB scanBox = currBoundingBox.expandTowards(0.0, 0.0, z);
|
||||
+ this.collectCollisions(scanBox, voxelList, bbList);
|
||||
+ z = ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performAABBCollisionsZ(currBoundingBox, z, bbList);
|
||||
+ return ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.performVoxelCollisionsZ(currBoundingBox, z, voxelList);
|
||||
+ }
|
||||
+ // Sakura end - optimise cannon entity movement
|
||||
+
|
||||
// Paper start - optimise collisions
|
||||
protected Vec3 collide(Vec3 movement) {
|
||||
final boolean xZero = movement.x == 0.0;
|
||||
diff --git a/net/minecraft/world/entity/item/FallingBlockEntity.java b/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
index 1d9afcf995ee734f13803e26956439e5c3450f44..c6836ab9a2789520931d2119aeebeaf2179f27fa 100644
|
||||
--- a/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
+++ b/net/minecraft/world/entity/item/FallingBlockEntity.java
|
||||
@@ -213,7 +213,7 @@ public class FallingBlockEntity extends Entity implements me.samsuik.sakura.enti
|
||||
Block block = this.blockState.getBlock();
|
||||
this.time++;
|
||||
this.applyGravity();
|
||||
- this.move(MoverType.SELF, this.getDeltaMovement());
|
||||
+ this.moveStripped(MoverType.SELF, this.getDeltaMovement()); // Sakura - optimise cannon entity movement
|
||||
this.applyEffectsFromBlocks();
|
||||
// Paper start - Configurable falling blocks height nerf
|
||||
if (this.level().paperConfig().fixes.fallingBlockHeightNerf.test(v -> this.getY() > v)) {
|
||||
diff --git a/net/minecraft/world/entity/item/PrimedTnt.java b/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
index c88fe6c244f6a88f1e42822dd0795187dcc3b655..2ee04093d7c8b61a48913bd4c929528e357aa971 100644
|
||||
--- a/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
+++ b/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
@@ -148,7 +148,7 @@ public class PrimedTnt extends Entity implements TraceableEntity, me.samsuik.sak
|
||||
// Sakura - remove max tnt per tick
|
||||
this.handlePortal();
|
||||
this.applyGravity();
|
||||
- this.move(MoverType.SELF, this.getDeltaMovement());
|
||||
+ this.moveStripped(MoverType.SELF, this.getDeltaMovement()); // Sakura - optimise cannon entity movement
|
||||
this.applyEffectsFromBlocks();
|
||||
// Paper start - Configurable TNT height nerf
|
||||
if (this.level().paperConfig().fixes.tntEntityHeightNerf.test(v -> this.getY() > v)) {
|
||||
@@ -0,0 +1,117 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Thu, 27 Jun 2024 17:02:32 +0100
|
||||
Subject: [PATCH] Add maxSearch to getEntities
|
||||
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
||||
index 39148fe540d616cdd4d63c4d1a02b422cab0f6eb..50a551d5bcac9b2b6644d7b43e625185090657a6 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
||||
@@ -314,7 +314,14 @@ public final class ChunkEntitySlices {
|
||||
|
||||
public boolean getEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate,
|
||||
final int maxCount) {
|
||||
- return this.allEntities.getEntitiesLimited(except, box, into, predicate, maxCount);
|
||||
+ // Sakura start - add maxSearch to getEntities
|
||||
+ return this.getEntities(except, box, into, predicate, maxCount, Integer.MAX_VALUE);
|
||||
+ }
|
||||
+
|
||||
+ public boolean getEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate,
|
||||
+ final int maxCount, final int maxSearch) {
|
||||
+ return this.allEntities.getEntitiesLimited(except, box, into, predicate, maxCount, maxSearch);
|
||||
+ // Sakura end - add maxSearch to getEntities
|
||||
}
|
||||
|
||||
public <T extends Entity> void getEntities(final EntityType<?> type, final AABB box, final List<? super T> into,
|
||||
@@ -570,6 +577,13 @@ public final class ChunkEntitySlices {
|
||||
|
||||
public boolean getEntitiesLimited(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate,
|
||||
final int maxCount) {
|
||||
+ // Sakura start - add maxSearch to getEntities
|
||||
+ return this.getEntitiesLimited(except, box, into, predicate, maxCount, Integer.MAX_VALUE);
|
||||
+ }
|
||||
+
|
||||
+ public boolean getEntitiesLimited(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate,
|
||||
+ final int maxCount, final int maxSearch) {
|
||||
+ // Sakura end - add maxSearch to getEntities
|
||||
if (this.count == 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -591,8 +605,14 @@ public final class ChunkEntitySlices {
|
||||
|
||||
final Entity[] storage = list.storage;
|
||||
|
||||
- for (int i = 0, len = Math.min(storage.length, list.size()); i < len; ++i) {
|
||||
- final Entity entity = storage[i];
|
||||
+ // Sakura start - add maxSearch to getEntities
|
||||
+ final int len = Math.min(storage.length, list.size());
|
||||
+ final int offset = this.slices.world.random.nextInt(len);
|
||||
+ for (int i = 0; i < len; ++i) {
|
||||
+ final int pos = (i + offset) % len;
|
||||
+ final Entity entity = storage[pos];
|
||||
+ if (i > maxSearch) break;
|
||||
+ // Sakura end - add maxSearch to getEntities
|
||||
|
||||
if (entity == null || entity == except || !entity.getBoundingBox().intersects(box)) {
|
||||
continue;
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
|
||||
index 7554c109c35397bc1a43dd80e87764fd78645bbf..d60f30f7afb15cc90c1bd4b816136d00b23a53e4 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
|
||||
@@ -722,6 +722,13 @@ public abstract class EntityLookup implements LevelEntityGetter<Entity> {
|
||||
|
||||
public void getEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate,
|
||||
final int maxCount) {
|
||||
+ // Sakura start - add maxSearch to getEntities
|
||||
+ this.getEntities(except, box, into, predicate, maxCount, Integer.MAX_VALUE);
|
||||
+ }
|
||||
+
|
||||
+ public void getEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate,
|
||||
+ final int maxCount, final int maxSearch) {
|
||||
+ // Sakura end - add maxSearch to getEntities
|
||||
final int minChunkX = (Mth.floor(box.minX) - 2) >> 4;
|
||||
final int minChunkZ = (Mth.floor(box.minZ) - 2) >> 4;
|
||||
final int maxChunkX = (Mth.floor(box.maxX) + 2) >> 4;
|
||||
@@ -753,7 +760,7 @@ public abstract class EntityLookup implements LevelEntityGetter<Entity> {
|
||||
continue;
|
||||
}
|
||||
|
||||
- if (chunk.getEntities(except, box, into, predicate, maxCount)) {
|
||||
+ if (chunk.getEntities(except, box, into, predicate, maxCount, maxSearch)) { // Sakura - add maxSearch to getEntities
|
||||
return;
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||
index 4dd2c4110d85bb7e6575b325196329900d719c64..b4a8a81f1fa091e45f1f39fdb69c61871d7dc6b9 100644
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -1791,10 +1791,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
this.getEntities(entityTypeTest, bounds, predicate, output, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
- // Paper start - rewrite chunk system
|
||||
+ // Sakura start - add maxSearch to getEntities
|
||||
public <T extends Entity> void getEntities(final EntityTypeTest<Entity, T> entityTypeTest,
|
||||
final AABB boundingBox, final Predicate<? super T> predicate,
|
||||
final List<? super T> into, final int maxCount) {
|
||||
+ this.getEntities(entityTypeTest, boundingBox, predicate, into, maxCount, Integer.MAX_VALUE);
|
||||
+ }
|
||||
+
|
||||
+ // Paper start - rewrite chunk system
|
||||
+ public <T extends Entity> void getEntities(final EntityTypeTest<Entity, T> entityTypeTest,
|
||||
+ final AABB boundingBox, final Predicate<? super T> predicate,
|
||||
+ final List<? super T> into, final int maxCount, final int maxSearch) {
|
||||
+ // Sakura end - add maxSearch to getEntities
|
||||
Profiler.get().incrementCounter("getEntities");
|
||||
|
||||
if (entityTypeTest instanceof net.minecraft.world.entity.EntityType<T> byType) {
|
||||
@@ -1811,7 +1819,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
|
||||
if (entityTypeTest == null) {
|
||||
if (maxCount != Integer.MAX_VALUE) {
|
||||
- ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities((Entity)null, boundingBox, (List)into, (Predicate)predicate, maxCount);
|
||||
+ ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities((Entity)null, boundingBox, (List)into, (Predicate)predicate, maxCount, maxSearch); // Sakura - add maxSearch to getEntities
|
||||
ca.spottedleaf.moonrise.common.PlatformHooks.get().addToGetEntities((Level)(Object)this, entityTypeTest, boundingBox, predicate, into, maxCount);
|
||||
return;
|
||||
} else {
|
||||
@@ -0,0 +1,24 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Thu, 23 Sep 2021 18:50:13 +0100
|
||||
Subject: [PATCH] Use maxEntityCollision limit for entity retrieval
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
|
||||
index 7ed355448ff6fbcf585d82a88d456908f9eb3ae6..e7b92681e5d65892da00699cc29c713219c9db8c 100644
|
||||
--- a/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3640,7 +3640,12 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
return;
|
||||
}
|
||||
// Paper end - don't run getEntities if we're not going to use its result
|
||||
- List<Entity> entities = this.level().getEntities(this, this.getBoundingBox(), EntitySelector.pushable(this, this.level().paperConfig().collisions.fixClimbingBypassingCrammingRule)); // Paper - Climbing should not bypass cramming gamerule
|
||||
+ // Sakura start - use maxEntityCollision limit for entity retrieval
|
||||
+ int limit = Math.max(_int, this.level().paperConfig().collisions.maxEntityCollisions);
|
||||
+ int search = limit * limit;
|
||||
+ List<Entity> entities = new ArrayList<>();
|
||||
+ this.level().getEntities(null, this.getBoundingBox(), EntitySelector.pushable(this, this.level().paperConfig().collisions.fixClimbingBypassingCrammingRule), entities, limit, search); // Paper - Climbing should not bypass cramming gamerule
|
||||
+ // Sakura end - use maxEntityCollision limit for entity retrieval
|
||||
if (!entities.isEmpty()) {
|
||||
// Paper - don't run getEntities if we're not going to use its result; moved up
|
||||
if (_int > 0 && entities.size() > _int - 1 && this.random.nextInt(4) == 0) {
|
||||
@@ -0,0 +1,105 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Wed, 15 Nov 2023 23:18:38 +0000
|
||||
Subject: [PATCH] Explosion Durable Blocks
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/item/BlockItem.java b/net/minecraft/world/item/BlockItem.java
|
||||
index 68e50c6ade879d263424f244070677cb81c34c33..8467af4ee57b6699227370ada7bf15ca41fb91c3 100644
|
||||
--- a/net/minecraft/world/item/BlockItem.java
|
||||
+++ b/net/minecraft/world/item/BlockItem.java
|
||||
@@ -45,8 +45,31 @@ public class BlockItem extends Item {
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
+ // Sakura start - explosion durable blocks
|
||||
+ private void sendBlockDurabilityToPlayer(UseOnContext context) {
|
||||
+ Player player = context.getPlayer();
|
||||
+ BlockState state = context.getLevel().getBlockState(context.getClickedPos());
|
||||
+ Block block = state.getBlock();
|
||||
+ me.samsuik.sakura.explosion.durable.DurableMaterial material = context.getLevel().localConfig().config(context.getClickedPos()).durableMaterials.get(block);
|
||||
+
|
||||
+ if (material != null) {
|
||||
+ int remaining = context.getLevel().durabilityManager.durability(context.getClickedPos(), material);
|
||||
+ int durability = material.durability();
|
||||
+
|
||||
+ player.getBukkitEntity().sendRichMessage(
|
||||
+ me.samsuik.sakura.configuration.GlobalConfiguration.get().messages.durableBlockInteraction,
|
||||
+ net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.unparsed("remaining", String.valueOf(remaining)),
|
||||
+ net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.unparsed("durability", String.valueOf(durability))
|
||||
+ );
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
@Override
|
||||
public InteractionResult useOn(UseOnContext context) {
|
||||
+ if (this.getBlock() == net.minecraft.world.level.block.Blocks.POTATOES && context.getPlayer() != null) {
|
||||
+ this.sendBlockDurabilityToPlayer(context);
|
||||
+ }
|
||||
+ // Sakura end - explosion durable blocks
|
||||
InteractionResult interactionResult = this.place(new BlockPlaceContext(context));
|
||||
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 b4a8a81f1fa091e45f1f39fdb69c61871d7dc6b9..19aa5010b019e343d0fb085359eac98bcb5b5efa 100644
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -839,6 +839,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
// Paper end - optimise random ticking
|
||||
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.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 0285e19d6265056fb5ff9855a5dd41bd16bbc082..58c14cc2d041348f42e8466fc93f18736c2618da 100644
|
||||
--- a/net/minecraft/world/level/ServerExplosion.java
|
||||
+++ b/net/minecraft/world/level/ServerExplosion.java
|
||||
@@ -133,7 +133,7 @@ public class ServerExplosion implements Explosion {
|
||||
BlockState blockState = ((ca.spottedleaf.moonrise.patches.getblock.GetBlockChunk)chunk).moonrise$getBlock(x, y, z);
|
||||
FluidState fluidState = blockState.getFluidState();
|
||||
|
||||
- Optional<Float> resistance = !calculateResistance ? Optional.empty() : this.damageCalculator.getBlockExplosionResistance((Explosion)(Object)this, this.level, pos, blockState, fluidState);
|
||||
+ Optional<Float> resistance = !calculateResistance ? Optional.empty() : this.calculateBlockResistance(blockState, fluidState, pos); // Sakura - explosion durable blocks
|
||||
|
||||
ret = new ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache(
|
||||
key, pos, blockState, fluidState,
|
||||
@@ -393,6 +393,20 @@ public class ServerExplosion implements Explosion {
|
||||
// Paper end - collision optimisations
|
||||
}
|
||||
// Sakura end - specialised explosions
|
||||
+ // Sakura start - explosion durable blocks
|
||||
+ private Optional<Float> calculateBlockResistance(BlockState blockState, FluidState fluidState, BlockPos pos) {
|
||||
+ if (!blockState.isAir()) {
|
||||
+ Block block = blockState.getBlock();
|
||||
+ me.samsuik.sakura.explosion.durable.DurableMaterial material = this.level.localConfig().config(pos).durableMaterials.get(block);
|
||||
+
|
||||
+ if (material != null && material.resistance() >= 0.0f && (this.level.sakuraConfig().cannons.explosion.allowNonTntBreakingDurableBlocks || this.source instanceof net.minecraft.world.entity.item.PrimedTnt)) {
|
||||
+ return Optional.of(material.resistance());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return this.damageCalculator.getBlockExplosionResistance(this, this.level, pos, blockState, fluidState);
|
||||
+ }
|
||||
+ // Sakura end - explosion durable blocks
|
||||
|
||||
public ServerExplosion(
|
||||
ServerLevel level,
|
||||
@@ -779,6 +793,16 @@ public class ServerExplosion implements Explosion {
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ // Sakura start - explosion durable blocks
|
||||
+ if (this.level.sakuraConfig().cannons.explosion.allowNonTntBreakingDurableBlocks || this.source instanceof net.minecraft.world.entity.item.PrimedTnt) {
|
||||
+ me.samsuik.sakura.explosion.durable.DurableMaterial material = this.level.localConfig().config(blockposition).durableMaterials.get(block);
|
||||
+
|
||||
+ if (material != null && material.durability() >= 0 && !this.level.durabilityManager.damage(blockposition, material)) {
|
||||
+ iterator.remove();
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+ // Sakura end - explosion durable blocks
|
||||
|
||||
this.level
|
||||
.getBlockState(blockPos)
|
||||
@@ -0,0 +1,22 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Thu, 16 Nov 2023 00:59:04 +0000
|
||||
Subject: [PATCH] Destroy Waterlogged Blocks
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java
|
||||
index 58c14cc2d041348f42e8466fc93f18736c2618da..f74aee504fa048a43272a3c3e9d1c6f9fa4a5913 100644
|
||||
--- a/net/minecraft/world/level/ServerExplosion.java
|
||||
+++ b/net/minecraft/world/level/ServerExplosion.java
|
||||
@@ -402,6 +402,11 @@ public class ServerExplosion implements Explosion {
|
||||
if (material != null && material.resistance() >= 0.0f && (this.level.sakuraConfig().cannons.explosion.allowNonTntBreakingDurableBlocks || this.source instanceof net.minecraft.world.entity.item.PrimedTnt)) {
|
||||
return Optional.of(material.resistance());
|
||||
}
|
||||
+ // Sakura start - destroy water logged blocks
|
||||
+ if (!fluidState.isEmpty() && !blockState.liquid() && this.level.sakuraConfig().cannons.explosion.destroyWaterloggedBlocks) {
|
||||
+ return Optional.of(ZERO_RESISTANCE);
|
||||
+ }
|
||||
+ // Sakura end - destroy water logged blocks
|
||||
}
|
||||
|
||||
return this.damageCalculator.getBlockExplosionResistance(this, this.level, pos, blockState, fluidState);
|
||||
@@ -0,0 +1,23 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Samsuik <kfian294ma4@gmail.com>
|
||||
Date: Fri, 3 May 2024 15:04:31 +0100
|
||||
Subject: [PATCH] Specialised Explosions
|
||||
|
||||
|
||||
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java b/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java
|
||||
index c21e00812f1aaa1279834a0562d360d6b89e146c..1e1329adde1457898a3002279b53b1bbb91c36d2 100644
|
||||
--- a/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java
|
||||
+++ b/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java
|
||||
@@ -107,6 +107,12 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Sakura start - specialised explosions; add indexOf method
|
||||
+ public int indexOf(final E element) {
|
||||
+ return this.indexMap.getInt(element);
|
||||
+ }
|
||||
+ // Sakura end - specialised explosions; add indexOf method
|
||||
+
|
||||
public boolean remove(final E element) {
|
||||
final int index = this.indexMap.removeInt(element);
|
||||
if (index >= 0) {
|
||||
@@ -0,0 +1,62 @@
|
||||
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<DensityData> 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 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;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package me.samsuik.sakura.explosion.durable;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class DurableBlockManager {
|
||||
private final Cache<BlockPos, DurableBlock> durableBlocks = CacheBuilder.newBuilder()
|
||||
.expireAfterAccess(1, TimeUnit.MINUTES)
|
||||
.maximumSize(65534)
|
||||
.build();
|
||||
|
||||
public boolean damage(BlockPos pos, DurableMaterial material) {
|
||||
DurableBlock block = this.durableBlocks.getIfPresent(pos);
|
||||
if (block == null) {
|
||||
this.durableBlocks.put(pos, block = new DurableBlock(material.durability()));
|
||||
}
|
||||
return block.damage();
|
||||
}
|
||||
|
||||
public int durability(BlockPos pos, DurableMaterial material) {
|
||||
final DurableBlock block = this.durableBlocks.getIfPresent(pos);
|
||||
return block != null ? block.durability() : material.durability();
|
||||
}
|
||||
|
||||
private static final class DurableBlock {
|
||||
private int durability;
|
||||
|
||||
public DurableBlock(int durability) {
|
||||
this.durability = durability;
|
||||
}
|
||||
|
||||
public int durability() {
|
||||
return this.durability;
|
||||
}
|
||||
|
||||
public boolean damage() {
|
||||
return --this.durability <= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
package me.samsuik.sakura.explosion.special;
|
||||
|
||||
import ca.spottedleaf.moonrise.common.util.WorldUtil;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.ExplosionDamageCalculator;
|
||||
import net.minecraft.world.level.ServerExplosion;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public abstract class SpecialisedExplosion<T extends Entity> extends ServerExplosion {
|
||||
private static final double ENTITY_DISPATCH_DISTANCE = Math.pow(32.0, 2.0);
|
||||
|
||||
protected final T cause; // preferred over source
|
||||
private Vec3 impactPosition;
|
||||
protected final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
|
||||
private final Consumer<SpecialisedExplosion<T>> applyEffects;
|
||||
|
||||
public SpecialisedExplosion(ServerLevel level, T entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, Vec3 center, float power, boolean createFire, BlockInteraction destructionType, Consumer<SpecialisedExplosion<T>> applyEffects) {
|
||||
super(level, entity, damageSource, behavior, center, power, createFire, destructionType);
|
||||
this.cause = entity;
|
||||
this.impactPosition = center;
|
||||
this.applyEffects = applyEffects;
|
||||
}
|
||||
|
||||
protected double getExplosionOffset() {
|
||||
return (double) this.cause.getBbHeight() * 0.0625D;
|
||||
}
|
||||
|
||||
protected abstract int getExplosionCount();
|
||||
|
||||
protected abstract void startExplosion();
|
||||
|
||||
@Override
|
||||
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 = this.getExplosionCount() - 1; i >= 0; --i) {
|
||||
this.finalizeExplosionAndParticles(List.of());
|
||||
}
|
||||
} else {
|
||||
this.createBlockCache();
|
||||
this.startExplosion(); // search for blocks, impact entities, finalise if necessary
|
||||
this.clearBlockCache();
|
||||
}
|
||||
}
|
||||
|
||||
protected final boolean requiresImpactEntities(List<BlockPos> blocks, Vec3 center) {
|
||||
if (this.impactPosition.distanceToSqr(center) > ENTITY_DISPATCH_DISTANCE) {
|
||||
this.impactPosition = center;
|
||||
return true;
|
||||
}
|
||||
return !blocks.isEmpty();
|
||||
}
|
||||
|
||||
protected final boolean finalizeExplosionAndParticles(List<BlockPos> blocks) {
|
||||
this.wasCanceled = false;
|
||||
List<BlockPos> explodedPositions = new ObjectArrayList<>(blocks);
|
||||
this.interactWithBlocks(explodedPositions);
|
||||
|
||||
if (!this.wasCanceled) {
|
||||
this.applyEffects.accept(this);
|
||||
this.getHitPlayers().clear();
|
||||
}
|
||||
|
||||
return !explodedPositions.isEmpty();
|
||||
}
|
||||
|
||||
protected void postExplosion(List<BlockPos> foundBlocks, boolean destroyedBlocks) {
|
||||
// optimisation: Keep the block cache across explosions and invalidate any found blocks.
|
||||
// This can help reduce block retrievals while block searching when there's a durable block,
|
||||
// and when ray tracing for obstructions. This is disabled by default because plugins can
|
||||
// change blocks in the explosion event.
|
||||
if (this.level().sakuraConfig().cannons.explosion.useBlockCacheAcrossExplosions && !foundBlocks.isEmpty() && !destroyedBlocks) {
|
||||
this.markBlocksInCacheAsExplodable(foundBlocks);
|
||||
} else {
|
||||
super.blockCache.clear();
|
||||
}
|
||||
|
||||
java.util.Arrays.fill(this.directMappedBlockCache, null);
|
||||
}
|
||||
|
||||
protected final void recalculateExplosionPosition() {
|
||||
this.recalculateExplosionPosition(this.cause);
|
||||
}
|
||||
|
||||
protected final void recalculateExplosionPosition(T entity) {
|
||||
double x = entity.getX();
|
||||
double y = entity.getY() + this.getExplosionOffset();
|
||||
double z = entity.getZ();
|
||||
this.center = new Vec3(x, y, z);
|
||||
}
|
||||
|
||||
protected final void forEachEntitySliceInBounds(AABB bb, Consumer<Entity[]> sliceConsumer) {
|
||||
int minSection = WorldUtil.getMinSection(this.level());
|
||||
int maxSection = WorldUtil.getMaxSection(this.level());
|
||||
|
||||
int minChunkX = Mth.floor(bb.minX) >> 4;
|
||||
int minChunkY = Mth.clamp(Mth.floor(bb.minY) >> 4, minSection, maxSection);
|
||||
int minChunkZ = Mth.floor(bb.minZ) >> 4;
|
||||
int maxChunkX = Mth.floor(bb.maxX) >> 4;
|
||||
int maxChunkY = Mth.clamp(Mth.floor(bb.maxY) >> 4, minSection, maxSection);
|
||||
int maxChunkZ = Mth.floor(bb.maxZ) >> 4;
|
||||
|
||||
EntityLookup entityLookup = this.level().moonrise$getEntityLookup();
|
||||
for (int chunkX = minChunkX; chunkX <= maxChunkX; ++chunkX) {
|
||||
for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; ++chunkZ) {
|
||||
ChunkEntitySlices chunk = entityLookup.getChunk(chunkX, chunkZ);
|
||||
|
||||
if (chunk == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int chunkY = minChunkY; chunkY <= maxChunkY; ++chunkY) {
|
||||
sliceConsumer.accept(chunk.getSectionEntities(chunkY));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected final void impactEntitiesFromPosition(Entity[] entities, Vec3 position, int potential, double radius) {
|
||||
for (int i = 0; i < entities.length; ++i) {
|
||||
Entity entity = entities[i];
|
||||
if (entity == null) break;
|
||||
|
||||
if (entity != this.source && !entity.ignoreExplosion(this)) {
|
||||
this.impactEntity(entity, position, potential, radius);
|
||||
}
|
||||
|
||||
if (entities[i] != entity) {
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected final void impactEntity(Entity entity, Vec3 pos, int potential, double radius) {
|
||||
if (this.excludeSourceFromDamage && entity == this.source) {
|
||||
return; // for paper api
|
||||
}
|
||||
if (entity.isPrimedTNT || entity.isFallingBlock) {
|
||||
this.impactCannonEntity(entity, pos, potential, radius);
|
||||
} else {
|
||||
for (int i = 0; i < potential; ++i) {
|
||||
super.impactEntity((float) radius, entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected final void impactCannonEntity(Entity entity, Vec3 pos, int potential, double radius) {
|
||||
double distanceFromBottom = Math.sqrt(entity.distanceToSqr(pos)) / radius;
|
||||
|
||||
if (distanceFromBottom <= 1.0) {
|
||||
double x = entity.getX() - pos.x;
|
||||
double y = (entity instanceof PrimedTnt ? entity.getY() : entity.getEyeY()) - pos.y;
|
||||
double z = entity.getZ() - pos.z;
|
||||
double distance = Math.sqrt(x * x + y * y + z * z);
|
||||
|
||||
if (distance != 0.0D) {
|
||||
x /= distance;
|
||||
y /= distance;
|
||||
z /= distance;
|
||||
double density = this.getBlockDensity(pos, entity); // Paper - Optimize explosions
|
||||
double exposure = (1.0D - distanceFromBottom) * density;
|
||||
|
||||
if (exposure == 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
x *= exposure;
|
||||
y *= exposure;
|
||||
z *= exposure;
|
||||
|
||||
this.applyEntityVelocity(entity, x, y, z, potential);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected final void applyEntityVelocity(Entity entity, double x, double y, double z, int potential) {
|
||||
Vec3 movement = entity.getDeltaMovement();
|
||||
|
||||
double moveX = movement.x();
|
||||
double moveY = movement.y();
|
||||
double moveZ = movement.z();
|
||||
|
||||
for (int i = 0; i < potential; ++i) {
|
||||
moveX += x;
|
||||
moveY += y;
|
||||
moveZ += z;
|
||||
}
|
||||
|
||||
entity.setDeltaMovement(moveX, moveY, moveZ);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
package me.samsuik.sakura.explosion.special;
|
||||
|
||||
import ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import me.samsuik.sakura.entity.EntityState;
|
||||
import me.samsuik.sakura.entity.merge.MergeLevel;
|
||||
import me.samsuik.sakura.entity.merge.MergeableEntity;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.damagesource.DamageSource;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.item.PrimedTnt;
|
||||
import net.minecraft.world.level.ExplosionDamageCalculator;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.bukkit.craftbukkit.util.CraftVector;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public final class TntExplosion extends SpecialisedExplosion<PrimedTnt> {
|
||||
private static final int ALL_DIRECTIONS = 0b111;
|
||||
private static final int FOUND_ALL_BLOCKS = ALL_DIRECTIONS + 12;
|
||||
|
||||
private final Vec3 originalPosition;
|
||||
private final List<Vec3> explosions = new ObjectArrayList<>();
|
||||
private AABB bounds;
|
||||
private int wrapped = 0;
|
||||
private boolean moved = false;
|
||||
|
||||
public TntExplosion(ServerLevel level, PrimedTnt tnt, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator behavior, Vec3 center, float power, boolean createFire, BlockInteraction destructionType, Consumer<SpecialisedExplosion<PrimedTnt>> applyEffects) {
|
||||
super(level, tnt, damageSource, behavior, center, power, createFire, destructionType, applyEffects);
|
||||
this.originalPosition = center;
|
||||
this.bounds = new AABB(center, center);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getExplosionCount() {
|
||||
if (this.cause.getMergeEntityData().getMergeLevel() == MergeLevel.NONE) {
|
||||
this.mergeEntitiesBeforeExplosion();
|
||||
}
|
||||
return this.cause.getMergeEntityData().getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startExplosion() {
|
||||
for (int i = this.getExplosionCount() - 1; i >= 0; --i) {
|
||||
Vec3 previousMomentum = this.cause.entityState().momentum();
|
||||
boolean lastCycle = i == 0;
|
||||
List<BlockPos> toBlow = this.midExplosion(previousMomentum, lastCycle); // search for blocks and impact entities
|
||||
boolean destroyedBlocks = this.finalizeExplosionAndParticles(toBlow);
|
||||
|
||||
if (!lastCycle) {
|
||||
EntityState entityState = this.nextSourceVelocity();
|
||||
this.postExplosion(toBlow, destroyedBlocks); // update wrapped, clear recent block cache
|
||||
this.updateExplosionPosition(entityState, destroyedBlocks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<BlockPos> midExplosion(Vec3 previousMomentum, boolean lastCycle) {
|
||||
final List<BlockPos> explodedPositions;
|
||||
if (this.wrapped < FOUND_ALL_BLOCKS) {
|
||||
explodedPositions = this.calculateExplodedPositions();
|
||||
} else {
|
||||
explodedPositions = List.of();
|
||||
}
|
||||
|
||||
if (this.wrapped < ALL_DIRECTIONS) {
|
||||
Vec3 momentum = this.cause.entityState().momentum();
|
||||
for (Direction.Axis axis : Direction.Axis.VALUES) {
|
||||
double current = momentum.get(axis);
|
||||
double previous = previousMomentum.get(axis);
|
||||
if (current == previous || current * previous < 0) {
|
||||
this.wrapped |= 1 << axis.ordinal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.bounds = this.bounds.expand(this.center);
|
||||
this.explosions.add(this.center);
|
||||
|
||||
if (lastCycle || this.requiresImpactEntities(explodedPositions, this.center)) {
|
||||
this.locateAndImpactEntitiesInBounds();
|
||||
this.bounds = new AABB(this.center, this.center);
|
||||
this.explosions.clear();
|
||||
}
|
||||
|
||||
return explodedPositions;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postExplosion(List<BlockPos> foundBlocks, boolean destroyedBlocks) {
|
||||
super.postExplosion(foundBlocks, destroyedBlocks);
|
||||
// Update wrapped, this is for tracking swinging and if blocks are found
|
||||
if (this.wrapped >= ALL_DIRECTIONS) {
|
||||
if (!destroyedBlocks && this.level().sakuraConfig().cannons.explosion.avoidRedundantBlockSearches) {
|
||||
this.wrapped++;
|
||||
} else {
|
||||
this.wrapped = ALL_DIRECTIONS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Vector getCauseOrigin() {
|
||||
Vector origin = this.cause.getOriginVector();
|
||||
return origin == null ? CraftVector.toBukkit(this.center) : origin;
|
||||
}
|
||||
|
||||
private EntityState nextSourceVelocity() {
|
||||
Vector origin = this.getCauseOrigin(); // valid position to use while creating a temporary entity
|
||||
PrimedTnt tnt = new PrimedTnt(this.level(), origin.getX(), origin.getY(), origin.getZ(), null);
|
||||
this.cause.entityState().apply(tnt);
|
||||
this.impactCannonEntity(tnt, this.center, 1, this.radius() * 2.0f);
|
||||
return EntityState.of(tnt);
|
||||
}
|
||||
|
||||
private void updateExplosionPosition(EntityState entityState, boolean destroyedBlocks) {
|
||||
// Before setting entity state, otherwise we might cause issues.
|
||||
final boolean hasMoved;
|
||||
if (this.moved) {
|
||||
hasMoved = true;
|
||||
} else if (this.center.equals(this.cause.position())) {
|
||||
hasMoved = false;
|
||||
} else {
|
||||
double newMomentum = entityState.momentum().lengthSqr();
|
||||
double oldMomentum = this.cause.entityState().momentum().lengthSqr();
|
||||
hasMoved = oldMomentum <= Math.pow(this.radius() * 2.0 + 1.0, 2.0) || newMomentum <= oldMomentum;
|
||||
}
|
||||
|
||||
// Keep track of entity state
|
||||
entityState.apply(this.cause);
|
||||
this.cause.storeEntityState();
|
||||
|
||||
// Ticking is always required after destroying a block.
|
||||
if (destroyedBlocks || hasMoved) {
|
||||
this.cause.setFuse(100);
|
||||
this.cause.tick();
|
||||
this.moved |= !this.center.equals(this.originalPosition);
|
||||
this.recalculateExplosionPosition();
|
||||
}
|
||||
}
|
||||
|
||||
private void mergeEntitiesBeforeExplosion() {
|
||||
IteratorSafeOrderedReferenceSet<Entity> entities = this.level().entityTickList.entities;
|
||||
int index = entities.indexOf(this.cause);
|
||||
|
||||
entities.createRawIterator();
|
||||
// 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 instanceof MergeableEntity mergeEntity) || foundEntity.isRemoved() || !foundEntity.compareState(this.cause) || !mergeEntity.isSafeToMergeInto(this.cause, true))
|
||||
break;
|
||||
this.level().mergeHandler.mergeEntity(mergeEntity, this.cause);
|
||||
}
|
||||
entities.finishRawIterator();
|
||||
}
|
||||
|
||||
private void locateAndImpactEntitiesInBounds() {
|
||||
double radius = this.radius() * 2.0f;
|
||||
AABB bb = this.bounds;
|
||||
|
||||
Vec3 center = bb.getCenter();
|
||||
double change = Math.max(bb.getXsize(), Math.max(bb.getYsize(), bb.getZsize()));
|
||||
double maxDistanceSqr = Math.pow(radius + change, 2.0);
|
||||
boolean moved = (change != 0.0);
|
||||
|
||||
this.forEachEntitySliceInBounds(bb.inflate(radius), entities -> {
|
||||
if (moved) {
|
||||
this.impactEntitiesSwinging(entities, center, radius, maxDistanceSqr);
|
||||
} else {
|
||||
this.impactEntitiesFromPosition(entities, this.explosions.getFirst(), this.explosions.size(), radius);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void impactEntitiesSwinging(Entity[] entities, Vec3 center, double radius, double maxDistanceSqr) {
|
||||
for (int i = 0; i < entities.length; ++i) {
|
||||
Entity entity = entities[i];
|
||||
if (entity == null) break;
|
||||
|
||||
if (entity != this.source && !entity.ignoreExplosion(this) && entity.distanceToSqr(center.x, center.y, center.z) <= maxDistanceSqr) {
|
||||
this.impactEntity(entity, radius);
|
||||
}
|
||||
|
||||
if (entities[i] != entity) {
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void impactEntity(Entity entity, double radius) {
|
||||
//noinspection ForLoopReplaceableByForEach
|
||||
for (int i = 0; i < this.explosions.size(); i++) {
|
||||
this.impactEntity(entity, this.explosions.get(i), 1, radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
Submodule sakura-server/src/minecraft/java updated: 51af06117f...6e26d2a9a1
Submodule sakura-server/src/minecraft/resources updated: e35daf625d...6f9aaa646d
Reference in New Issue
Block a user