generated from MrSphay/codex-agent-repository-kit
232 lines
11 KiB
Java
232 lines
11 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*/
|
|
package com.vinlanx.explosionoverhaul;
|
|
|
|
import com.vinlanx.explosionoverhaul.BlockIndexManager;
|
|
import com.vinlanx.explosionoverhaul.Config;
|
|
import com.vinlanx.explosionoverhaul.ExplosionOverhaul;
|
|
import java.util.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.Comparator;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.UUID;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.core.Position;
|
|
import net.minecraft.core.Vec3i;
|
|
import net.minecraft.core.particles.BlockParticleOption;
|
|
import net.minecraft.core.particles.ParticleOptions;
|
|
import net.minecraft.core.particles.ParticleTypes;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.sounds.SoundEvents;
|
|
import net.minecraft.sounds.SoundSource;
|
|
import net.minecraft.tags.BlockTags;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.util.RandomSource;
|
|
import net.minecraft.world.level.BlockGetter;
|
|
import net.minecraft.world.level.ClipContext;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.phys.HitResult;
|
|
import net.minecraft.world.phys.Vec3;
|
|
|
|
public class GlassBreakingEffects {
|
|
private static final Map<UUID, List<DelayedGlassEffect>> perExplosionEffects = new ConcurrentHashMap<UUID, List<DelayedGlassEffect>>();
|
|
private static final int MAX_GROUPS_PER_EXPLOSION = 250;
|
|
private static int tickCounter = 0;
|
|
|
|
public static void trigger(ServerLevel level, Vec3 explosionPos, float power) {
|
|
if (!((Boolean)Config.COMMON.enableGlassBreaking.get()).booleanValue()) {
|
|
return;
|
|
}
|
|
RandomSource random = level.m_213780_();
|
|
double radius = GlassBreakingEffects.calculateRadius(power);
|
|
BlockPos center = BlockPos.m_274446_((Position)explosionPos);
|
|
List<BlockPos> glassBlocks = BlockIndexManager.getNearby(level, center, (int)Math.ceil(radius), BlockIndexManager.BlockType.GLASS);
|
|
if (glassBlocks.isEmpty()) {
|
|
return;
|
|
}
|
|
HashSet<BlockPos> foundGlassBlocks = new HashSet<BlockPos>();
|
|
float initialRayEnergy = power * 2.5f;
|
|
block0: for (BlockPos glassPos : glassBlocks) {
|
|
Vec3 glassCenter = Vec3.m_82512_((Vec3i)glassPos);
|
|
Vec3 rayDirection = glassCenter.m_82546_(explosionPos).m_82541_();
|
|
double distanceToGlass = explosionPos.m_82554_(glassCenter);
|
|
if (distanceToGlass > radius) continue;
|
|
float currentEnergy = initialRayEnergy * (0.8f + random.m_188501_() * 0.4f);
|
|
BlockPos lastPos = null;
|
|
for (double step = 0.5; step < distanceToGlass + 1.0; step += 0.4) {
|
|
float resistance;
|
|
BlockPos currentPos = BlockPos.m_274446_((Position)explosionPos.m_82549_(rayDirection.m_82490_(step)));
|
|
if (currentPos.equals(lastPos)) continue;
|
|
lastPos = currentPos;
|
|
if (!level.m_46749_(currentPos) || currentPos.m_123342_() < level.m_141937_() || currentPos.m_123342_() >= level.m_151558_()) continue block0;
|
|
BlockState state = level.m_8055_(currentPos);
|
|
if (state.m_60795_()) continue;
|
|
if (GlassBreakingEffects.isGlass(state)) {
|
|
foundGlassBlocks.add(currentPos);
|
|
continue;
|
|
}
|
|
if (BlockIndexManager.isReinforcedGlass(state) || ExplosionOverhaul.isBlockStateBlacklisted(state) || (currentEnergy -= (resistance = state.getExplosionResistance((BlockGetter)level, currentPos, null)) + 0.3f) <= 0.0f) continue block0;
|
|
}
|
|
}
|
|
if (foundGlassBlocks.isEmpty()) {
|
|
return;
|
|
}
|
|
ArrayList<GlassGroup> groups = new ArrayList<GlassGroup>();
|
|
HashSet<BlockPos> processed = new HashSet<BlockPos>();
|
|
for (BlockPos glassPos : foundGlassBlocks) {
|
|
List<BlockPos> groupPositions;
|
|
if (processed.contains(glassPos) || (groupPositions = GlassBreakingEffects.findConnectedGlass(level, glassPos, processed)).isEmpty()) continue;
|
|
groups.add(new GlassGroup(groupPositions, glassPos, glassPos.m_123331_((Vec3i)center)));
|
|
}
|
|
if (groups.isEmpty()) {
|
|
return;
|
|
}
|
|
groups.sort(Comparator.comparingDouble(g -> g.distanceSq));
|
|
List<DelayedGlassEffect> effects = Collections.synchronizedList(new ArrayList());
|
|
UUID explosionId = UUID.randomUUID();
|
|
int groupsToProcess = Math.min(groups.size(), 250);
|
|
for (int i = 0; i < groupsToProcess; ++i) {
|
|
GlassGroup group = (GlassGroup)groups.get(i);
|
|
for (BlockPos pos : group.positions()) {
|
|
if (!GlassBreakingEffects.shouldBreak(level, explosionPos, pos, power, random, radius)) continue;
|
|
double distance = Math.sqrt(pos.m_123331_((Vec3i)BlockPos.m_274446_((Position)explosionPos)));
|
|
long delayInTicks = (long)(distance / 3.0);
|
|
int processingInterval = Math.max(1, (Integer)Config.COMMON.glassBreakingIntervalTicks.get());
|
|
long delayInProcessingCycles = Math.max(1L, delayInTicks / (long)processingInterval);
|
|
effects.add(new DelayedGlassEffect(level, pos, delayInProcessingCycles += (long)random.m_188503_(2)));
|
|
}
|
|
}
|
|
if (!effects.isEmpty()) {
|
|
perExplosionEffects.put(explosionId, effects);
|
|
}
|
|
}
|
|
|
|
private static boolean shouldBreak(ServerLevel level, Vec3 explosionPos, BlockPos glassPos, float power, RandomSource random, double maxRadius) {
|
|
ClipContext context;
|
|
double distance = Math.sqrt(glassPos.m_123331_((Vec3i)BlockPos.m_274446_((Position)explosionPos)));
|
|
float distanceFraction = (float)(distance / maxRadius);
|
|
if (distanceFraction > 1.0f) {
|
|
return false;
|
|
}
|
|
float baseChance = distanceFraction <= 0.25f ? Mth.m_14179_((float)(distanceFraction / 0.25f), (float)1.0f, (float)0.95f) : (distanceFraction <= 0.5f ? Mth.m_14179_((float)((distanceFraction - 0.25f) / 0.25f), (float)0.95f, (float)0.68f) : (distanceFraction <= 0.85f ? Mth.m_14179_((float)((distanceFraction - 0.5f) / 0.35f), (float)0.68f, (float)0.2f) : Mth.m_14179_((float)((distanceFraction - 0.85f) / 0.15f), (float)0.2f, (float)0.0f)));
|
|
baseChance *= Mth.m_14036_((float)(power / 25.0f), (float)0.8f, (float)1.5f);
|
|
BlockState state = level.m_8055_(glassPos);
|
|
if (state.m_60734_().toString().contains("pane")) {
|
|
baseChance += 0.2f;
|
|
}
|
|
if (level.m_45547_(context = new ClipContext(explosionPos, Vec3.m_82512_((Vec3i)glassPos), ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, null)).m_6662_() != HitResult.Type.MISS) {
|
|
baseChance *= 0.5f;
|
|
}
|
|
return random.m_188501_() < Mth.m_14036_((float)baseChance, (float)0.0f, (float)1.0f);
|
|
}
|
|
|
|
private static double calculateRadius(float power) {
|
|
if (power <= 5.0f) {
|
|
return Mth.m_14179_((float)Mth.m_184655_((float)power, (float)1.0f, (float)4.0f), (float)20.0f, (float)48.0f);
|
|
}
|
|
float dustRadius = power * GlassBreakingEffects.calculateRadiusMultiplier(power);
|
|
return dustRadius * 1.75f;
|
|
}
|
|
|
|
private static float calculateRadiusMultiplier(float power) {
|
|
if (power <= 5.0f) {
|
|
return 2.0f;
|
|
}
|
|
if (power <= 40.0f) {
|
|
return Mth.m_14179_((float)((power - 5.0f) / 35.0f), (float)2.0f, (float)4.0f);
|
|
}
|
|
if (power <= 80.0f) {
|
|
return Mth.m_14179_((float)((power - 40.0f) / 40.0f), (float)4.0f, (float)5.0f);
|
|
}
|
|
if (power <= 100.0f) {
|
|
return Mth.m_14179_((float)((power - 80.0f) / 20.0f), (float)5.0f, (float)7.0f);
|
|
}
|
|
return 7.0f;
|
|
}
|
|
|
|
private static List<BlockPos> findConnectedGlass(ServerLevel level, BlockPos start, Set<BlockPos> processed) {
|
|
ArrayList<BlockPos> group = new ArrayList<BlockPos>();
|
|
LinkedList<BlockPos> queue = new LinkedList<BlockPos>();
|
|
queue.add(start);
|
|
processed.add(start);
|
|
while (!queue.isEmpty()) {
|
|
BlockPos current = (BlockPos)queue.poll();
|
|
group.add(current);
|
|
if (group.size() > 200) break;
|
|
for (Direction dir : Direction.values()) {
|
|
BlockPos neighbor = current.m_5484_(dir, 1);
|
|
if (processed.contains(neighbor) || !GlassBreakingEffects.isGlass(level.m_8055_(neighbor))) continue;
|
|
processed.add(neighbor);
|
|
queue.add(neighbor);
|
|
}
|
|
}
|
|
return group;
|
|
}
|
|
|
|
private static boolean isGlass(BlockState state) {
|
|
if (BlockIndexManager.isReinforcedGlass(state)) {
|
|
return false;
|
|
}
|
|
return state.m_204336_(BlockTags.f_13049_) || state.m_60734_().toString().contains("glass");
|
|
}
|
|
|
|
public static void onServerTick() {
|
|
int processingInterval = (Integer)Config.COMMON.glassBreakingIntervalTicks.get();
|
|
if (++tickCounter < processingInterval) {
|
|
return;
|
|
}
|
|
tickCounter = 0;
|
|
if (perExplosionEffects.isEmpty()) {
|
|
return;
|
|
}
|
|
int budgetPerExplosion = (Integer)Config.COMMON.glassBlocksPerCycle.get();
|
|
for (List<DelayedGlassEffect> effects : perExplosionEffects.values()) {
|
|
int explosionBudget = budgetPerExplosion;
|
|
Iterator<DelayedGlassEffect> iterator = effects.iterator();
|
|
while (iterator.hasNext() && explosionBudget > 0) {
|
|
DelayedGlassEffect effect = iterator.next();
|
|
if (!effect.tick()) continue;
|
|
iterator.remove();
|
|
--explosionBudget;
|
|
}
|
|
}
|
|
perExplosionEffects.values().removeIf(List::isEmpty);
|
|
}
|
|
|
|
private record GlassGroup(List<BlockPos> positions, BlockPos representativePos, double distanceSq) {
|
|
}
|
|
|
|
private static class DelayedGlassEffect {
|
|
private final ServerLevel level;
|
|
private final BlockPos glassPos;
|
|
private final BlockState glassState;
|
|
private long delayCycles;
|
|
|
|
public DelayedGlassEffect(ServerLevel level, BlockPos glassPos, long delayCycles) {
|
|
this.level = level;
|
|
this.glassPos = glassPos;
|
|
this.glassState = level.m_8055_(glassPos);
|
|
this.delayCycles = delayCycles;
|
|
}
|
|
|
|
public boolean tick() {
|
|
if (--this.delayCycles <= 0L) {
|
|
this.level.m_46961_(this.glassPos, false);
|
|
this.level.m_8767_((ParticleOptions)new BlockParticleOption(ParticleTypes.f_123794_, this.glassState), (double)this.glassPos.m_123341_() + 0.5, (double)this.glassPos.m_123342_() + 0.5, (double)this.glassPos.m_123343_() + 0.5, 20, 0.3, 0.3, 0.3, 0.1);
|
|
this.level.m_5594_(null, this.glassPos, SoundEvents.f_11983_, SoundSource.BLOCKS, 0.7f, 1.0f);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|