From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Samsuik <40902469+Samsuik@users.noreply.github.com> Date: Wed, 15 Nov 2023 23:18:38 +0000 Subject: [PATCH] Explosion Durable Blocks diff --git a/src/main/java/me/samsuik/sakura/explosion/durable/DurableBlockManager.java b/src/main/java/me/samsuik/sakura/explosion/durable/DurableBlockManager.java new file mode 100644 index 0000000000000000000000000000000000000000..c58e52f7cc012babf4235e405e5fb5015c6e95d9 --- /dev/null +++ b/src/main/java/me/samsuik/sakura/explosion/durable/DurableBlockManager.java @@ -0,0 +1,63 @@ +package me.samsuik.sakura.explosion.durable; + +import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import me.samsuik.sakura.utils.objects.Expiry; +import net.minecraft.core.BlockPos; +import net.minecraft.server.MinecraftServer; + +public final class DurableBlockManager { + + private final Long2ObjectOpenHashMap blocks = new Long2ObjectOpenHashMap<>(); + + public boolean damage(BlockPos pos, DurableMaterial material) { + long packed = pos.asLong(); + + DurableBlock block = this.blocks.computeIfAbsent(packed, k -> new DurableBlock( + material.durability(), + // expire after 1 minute + new Expiry(MinecraftServer.currentTickLong, 1200) + )); + + if (block.damage()) { + this.blocks.remove(packed); + return true; + } else { + block.getExpiry().refresh(MinecraftServer.currentTickLong); + return false; + } + } + + public int durability(BlockPos pos, DurableMaterial material) { + DurableBlock block = this.blocks.get(pos.asLong()); + return block != null ? block.getDurability() : material.durability(); + } + + public void expire(long tick) { + if (tick % 200 == 0) { + this.blocks.values().removeIf(block -> block.getExpiry().isExpired(tick)); + } + } + + private static class DurableBlock { + private int durability; + private final Expiry expiry; + + public DurableBlock(int durability, Expiry expiry) { + this.durability = durability; + this.expiry = expiry; + } + + public Expiry getExpiry() { + return expiry; + } + + public int getDurability() { + return durability; + } + + public boolean damage() { + return --this.durability <= 0; + } + } + +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 9257505431d00aec2225b052492b8eb88ed4d63d..a342a604ad58e3ecc8907e7ec6d6fbf58c31d246 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1805,6 +1805,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop resistance = !calculateResistance ? Optional.empty() : this.damageCalculator.getBlockExplosionResistance((Explosion)(Object)this, this.level, pos, blockState, fluidState); + Optional resistance = !calculateResistance ? Optional.empty() : this.calculateBlockResistance(blockState, fluidState, pos); // Sakura - explosion durable blocks ret = new ExplosionBlockCache( key, pos, blockState, fluidState, @@ -276,6 +276,21 @@ public class Explosion { return ret; } + // Sakura start - explosion durable blocks + private Optional 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((Explosion)(Object)this, this.level, pos, blockState, fluidState); + } + // Sakura end - explosion durable blocks + private boolean clipsAnything(final Vec3 from, final Vec3 to, final io.papermc.paper.util.CollisionUtil.LazyEntityCollisionContext context, final ExplosionBlockCache[] blockCache, @@ -868,6 +883,16 @@ public class Explosion { // CraftBukkit start - TNTPrimeEvent BlockState iblockdata = this.level.getBlockState(blockposition); Block block = iblockdata.getBlock(); + // 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)) { + objectlistiterator.remove(); + continue; + } + } + // Sakura end - explosion durable blocks if (block instanceof net.minecraft.world.level.block.TntBlock) { Entity sourceEntity = this.source == null ? null : this.source; BlockPos sourceBlock = sourceEntity == null ? BlockPos.containing(this.x, this.y, this.z) : null; diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java index d041ad1e52c78c553da4d92745d2b07fc3eab522..1901081678b25fd50d9eb2b9a51c99672d239ea3 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -220,6 +220,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { public final it.unimi.dsi.fastutil.longs.Long2IntMap minimalTNT = new it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap(); // Sakura - visibility api public final me.samsuik.sakura.entity.merge.MergeHistory mergeHistory = new me.samsuik.sakura.entity.merge.MergeHistory(); // Sakura - cannon entity merging 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 // Sakura start - add entity retrival methods with search limits public final void getLimitedEntities(Entity except, AABB box, Predicate predicate, List into, int limit, int search) {