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 67ca905c0821deb279383811fd112f02c46a73a1..545dee7863095b70474abcc87c9c9c0f15a016f8 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1819,6 +1819,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 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 ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache( key, pos, blockState, fluidState, @@ -158,6 +158,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 ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.LazyEntityCollisionContext context, final ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache[] blockCache, @@ -834,6 +849,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 81a4a076017527eaddfcfbe737d60257ba8a01eb..ad6ae684a13b7d3e33f5e78d7eee1f52a12e4ab9 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -656,6 +656,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl public final it.unimi.dsi.fastutil.longs.Long2IntMap minimalTNT = new it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap(); // Sakura - visibility api public final me.samsuik.sakura.entity.merge.EntityMergeHandler mergeHandler = new me.samsuik.sakura.entity.merge.EntityMergeHandler(); // Sakura - merge cannon entities 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 worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, Supplier supplier, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, Supplier sakuraWorldConfigCreator, java.util.concurrent.Executor executor) { // Sakura - sakura configuration files// Paper - create paper world config & Anti-Xray this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot