generated from MrSphay/codex-agent-repository-kit
This commit is contained in:
@@ -1,374 +1,20 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
package com.vinlanx.explosionoverhaul;
|
||||
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import com.vinlanx.explosionoverhaul.CameraShakePacket;
|
||||
import com.vinlanx.explosionoverhaul.Config;
|
||||
import com.vinlanx.explosionoverhaul.DripstoneEffects;
|
||||
import com.vinlanx.explosionoverhaul.ExplosionOverhaul;
|
||||
import com.vinlanx.explosionoverhaul.ModSounds;
|
||||
import com.vinlanx.explosionoverhaul.PacketHandler;
|
||||
import com.vinlanx.explosionoverhaul.PlayTrackedSoundPacket;
|
||||
import com.vinlanx.explosionoverhaul.RedstoneLampEffects;
|
||||
import com.vinlanx.explosionoverhaul.ServerExplosionHandler;
|
||||
import com.vinlanx.explosionoverhaul.SpawnAmbientCaveDustPacket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class AmbientExplosionManager {
|
||||
private static final Map<UUID, PlayerTimer> playerTimers = new HashMap<UUID, PlayerTimer>();
|
||||
|
||||
public static void onServerTick(ServerLevel level) {
|
||||
if (!((Boolean)Config.COMMON.ambient.enableAmbientExplosions.get()).booleanValue()) {
|
||||
if (!playerTimers.isEmpty()) {
|
||||
playerTimers.clear();
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (ServerPlayer player : level.m_6907_()) {
|
||||
PlayerTimer timer = playerTimers.computeIfAbsent(player.m_20148_(), id -> new PlayerTimer(level.m_213780_()));
|
||||
timer.tick(player);
|
||||
}
|
||||
public static void onServerTick(MinecraftServer server) {
|
||||
}
|
||||
|
||||
public static void onPlayerLoggedIn(ServerPlayer player) {
|
||||
playerTimers.put(player.m_20148_(), new PlayerTimer(player.f_8924_.m_129783_().m_213780_()));
|
||||
}
|
||||
|
||||
public static void onPlayerLoggedOut(ServerPlayer player) {
|
||||
playerTimers.remove(player.m_20148_());
|
||||
}
|
||||
|
||||
private static ServerExplosionHandler.CameraShakeProfile determineCameraShakeProfile(float power, double distance, boolean playerInCave, ServerLevel level) {
|
||||
float intensity = 0.0f;
|
||||
int baseDuration = 20;
|
||||
float pushIntensity = 0.0f;
|
||||
int closeDistance = 50;
|
||||
int mediumDistance = 500;
|
||||
int farDistance = 1000;
|
||||
int superFarDistance = 5000;
|
||||
int powerCategory = power <= 3.0f ? 1 : (power <= 6.0f ? 2 : (power <= 14.0f ? 3 : (power <= 30.0f ? 4 : (power <= 60.0f ? 5 : (power <= 99.0f ? 6 : 7)))));
|
||||
int shakeLevel = 0;
|
||||
if (distance <= 50.0) {
|
||||
if (powerCategory >= 7) {
|
||||
shakeLevel = 5;
|
||||
baseDuration = 50;
|
||||
} else if (powerCategory == 6) {
|
||||
shakeLevel = 5;
|
||||
baseDuration = 40;
|
||||
} else if (powerCategory == 5) {
|
||||
shakeLevel = 4;
|
||||
baseDuration = 35;
|
||||
} else if (powerCategory == 4) {
|
||||
shakeLevel = 4;
|
||||
baseDuration = 30;
|
||||
} else if (powerCategory == 3) {
|
||||
shakeLevel = 3;
|
||||
baseDuration = 25;
|
||||
} else if (powerCategory == 2) {
|
||||
shakeLevel = 3;
|
||||
baseDuration = 20;
|
||||
} else if (powerCategory == 1) {
|
||||
shakeLevel = 2;
|
||||
baseDuration = 15;
|
||||
}
|
||||
} else if (distance <= 500.0) {
|
||||
if (powerCategory >= 7) {
|
||||
shakeLevel = 4;
|
||||
baseDuration = 35;
|
||||
} else if (powerCategory == 6) {
|
||||
shakeLevel = 4;
|
||||
baseDuration = 30;
|
||||
} else if (powerCategory == 5) {
|
||||
shakeLevel = 3;
|
||||
baseDuration = 25;
|
||||
} else if (powerCategory == 4) {
|
||||
shakeLevel = 3;
|
||||
baseDuration = 20;
|
||||
} else if (powerCategory <= 3) {
|
||||
shakeLevel = 2;
|
||||
baseDuration = 15;
|
||||
}
|
||||
} else if (distance <= 1000.0) {
|
||||
if (powerCategory >= 7) {
|
||||
shakeLevel = 3;
|
||||
baseDuration = 25;
|
||||
} else if (powerCategory == 6) {
|
||||
shakeLevel = 3;
|
||||
baseDuration = 20;
|
||||
} else if (powerCategory == 5) {
|
||||
shakeLevel = 2;
|
||||
baseDuration = 15;
|
||||
} else if (powerCategory == 4) {
|
||||
shakeLevel = 2;
|
||||
baseDuration = 10;
|
||||
}
|
||||
} else if (distance <= 5000.0) {
|
||||
if (powerCategory >= 7) {
|
||||
shakeLevel = 3;
|
||||
baseDuration = 20;
|
||||
} else if (powerCategory == 6) {
|
||||
shakeLevel = 2;
|
||||
baseDuration = 15;
|
||||
} else if (powerCategory == 5) {
|
||||
shakeLevel = 1;
|
||||
baseDuration = 10;
|
||||
}
|
||||
}
|
||||
switch (shakeLevel) {
|
||||
case 1: {
|
||||
intensity = 0.06f;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
intensity = 0.18f;
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
intensity = 0.4f;
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
intensity = 0.65f;
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
intensity = 0.9f;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
intensity = 0.0f;
|
||||
baseDuration = 0;
|
||||
}
|
||||
}
|
||||
if (playerInCave && intensity > 0.0f && shakeLevel >= 2) {
|
||||
float basePush = 0.02f + (float)shakeLevel * 0.015f;
|
||||
pushIntensity = Math.min(basePush * (power / 8.0f), 0.25f);
|
||||
pushIntensity = Math.max(0.04f, pushIntensity);
|
||||
}
|
||||
if (intensity > 0.01f && baseDuration < 5) {
|
||||
baseDuration = 5;
|
||||
}
|
||||
if (intensity < 0.01f) {
|
||||
intensity = 0.0f;
|
||||
baseDuration = 0;
|
||||
pushIntensity = 0.0f;
|
||||
}
|
||||
return new ServerExplosionHandler.CameraShakeProfile(intensity, baseDuration, pushIntensity);
|
||||
}
|
||||
|
||||
private static class PlayerTimer {
|
||||
private final RandomSource random;
|
||||
private int timeUntilNextEvent;
|
||||
|
||||
PlayerTimer(RandomSource random) {
|
||||
this.random = random;
|
||||
this.resetTimer();
|
||||
}
|
||||
|
||||
private void resetTimer() {
|
||||
int max;
|
||||
int min = (Integer)Config.COMMON.ambient.minTimeBetweenExplosions.get();
|
||||
this.timeUntilNextEvent = min >= (max = ((Integer)Config.COMMON.ambient.maxTimeBetweenExplosions.get()).intValue()) ? min : this.random.m_216339_(min, max);
|
||||
}
|
||||
|
||||
public void tick(ServerPlayer player) {
|
||||
if (this.timeUntilNextEvent-- <= 0) {
|
||||
this.generateAndPlayAmbientEventForPlayer(player);
|
||||
this.resetTimer();
|
||||
}
|
||||
}
|
||||
|
||||
private void generateAndPlayAmbientEventForPlayer(ServerPlayer player) {
|
||||
int shellingWeight;
|
||||
int chainWeight;
|
||||
Config.Common.Ambient.Scenarios scenarios = Config.COMMON.ambient.scenarios;
|
||||
int singleWeight = (Integer)scenarios.singleExplosionWeight.get();
|
||||
int totalWeight = singleWeight + (chainWeight = ((Integer)scenarios.chainReactionWeight.get()).intValue()) + (shellingWeight = ((Integer)scenarios.shellingWeight.get()).intValue());
|
||||
if (totalWeight <= 0) {
|
||||
return;
|
||||
}
|
||||
int roll = this.random.m_188503_(totalWeight);
|
||||
AmbientEventType eventType = (roll -= singleWeight) < 0 ? AmbientEventType.SINGLE : ((roll -= chainWeight) < 0 ? AmbientEventType.CHAIN_REACTION : AmbientEventType.SHELLING);
|
||||
Vec3 eventPos = this.generateEventPosition(player);
|
||||
SoundEnvironment chosenEnv = this.determineSoundEnvironment(player, eventPos);
|
||||
if (chosenEnv == null) {
|
||||
return;
|
||||
}
|
||||
boolean playerInHouse = ServerExplosionHandler.isInHouse(player.m_284548_(), player.m_20183_(), player.m_146892_().f_82480_);
|
||||
BlockPos dripstoneCenter = player.m_20183_();
|
||||
int explosionPower = (int)Math.ceil(this.generatePower());
|
||||
DripstoneEffects.handleDripstoneFall(player.m_284548_(), dripstoneCenter, explosionPower, player.m_217043_());
|
||||
ArrayList<AmbientSoundData> soundsToPlay = new ArrayList<AmbientSoundData>();
|
||||
switch (eventType) {
|
||||
case SINGLE: {
|
||||
float power = this.generatePower();
|
||||
if (!(power > 0.0f)) break;
|
||||
soundsToPlay.add(new AmbientSoundData(power, 0L, false));
|
||||
break;
|
||||
}
|
||||
case CHAIN_REACTION: {
|
||||
int minShots = (Integer)scenarios.minChainReactionShots.get();
|
||||
int maxShots = (Integer)scenarios.maxChainReactionShots.get();
|
||||
int shotCount = minShots >= maxShots ? minShots : this.random.m_216339_(minShots, maxShots + 1);
|
||||
long cumulativeDelay = 0L;
|
||||
for (int i = 0; i < shotCount; ++i) {
|
||||
float progress = shotCount > 1 ? (float)i / (float)(shotCount - 1) : 1.0f;
|
||||
float power = Mth.m_14179_((float)(progress * progress), (float)1.0f, (float)40.0f) + this.random.m_188501_() * 4.0f;
|
||||
int minDelay = (Integer)scenarios.minTimeBetweenChainShots.get();
|
||||
int maxDelay = (Integer)scenarios.maxTimeBetweenChainShots.get();
|
||||
soundsToPlay.add(new AmbientSoundData(power, cumulativeDelay += minDelay >= maxDelay ? (long)minDelay : (long)this.random.m_216339_(minDelay, maxDelay + 1), false));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SHELLING: {
|
||||
float shotPower = 1.0f + this.random.m_188501_() * 3.0f;
|
||||
float impactPower = 5.0f + this.random.m_188501_() * 10.0f;
|
||||
int minDelay = (Integer)scenarios.minShellingDelay.get();
|
||||
int maxDelay = (Integer)scenarios.maxShellingDelay.get();
|
||||
long impactDelay = minDelay >= maxDelay ? (long)minDelay : (long)this.random.m_216339_(minDelay, maxDelay + 1);
|
||||
soundsToPlay.add(new AmbientSoundData(shotPower, 0L, true));
|
||||
soundsToPlay.add(new AmbientSoundData(impactPower, impactDelay, false));
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (AmbientSoundData soundData : soundsToPlay) {
|
||||
this.playSoundForEnvironment(player, player.m_284548_(), soundData.power(), chosenEnv, playerInHouse, soundData.delay(), soundData.isShellingShot(), eventPos);
|
||||
}
|
||||
}
|
||||
|
||||
private Vec3 generateEventPosition(ServerPlayer player) {
|
||||
int maxDst;
|
||||
int minDst = (Integer)Config.COMMON.ambient.minExplosionDistance.get();
|
||||
double distance = minDst >= (maxDst = ((Integer)Config.COMMON.ambient.maxExplosionDistance.get()).intValue()) ? (double)minDst : (double)minDst + this.random.m_188500_() * (double)(maxDst - minDst);
|
||||
double angle = this.random.m_188500_() * 2.0 * Math.PI;
|
||||
double x = player.m_20185_() + Math.cos(angle) * distance;
|
||||
double z = player.m_20189_() + Math.sin(angle) * distance;
|
||||
double y = player.m_20186_();
|
||||
return new Vec3(x, y, z);
|
||||
}
|
||||
|
||||
private float generatePower() {
|
||||
Config.Common.Ambient.PowerTiers weights = Config.COMMON.ambient.powerTiers;
|
||||
int totalWeight = (Integer)weights.tier1_weight.get() + (Integer)weights.tier2_weight.get() + (Integer)weights.tier3_weight.get() + (Integer)weights.tier4_weight.get() + (Integer)weights.tier5_weight.get();
|
||||
if (totalWeight <= 0) {
|
||||
return 0.0f;
|
||||
}
|
||||
int roll = this.random.m_188503_(totalWeight);
|
||||
if ((roll -= ((Integer)weights.tier1_weight.get()).intValue()) < 0) {
|
||||
return 1.0f + this.random.m_188501_() * 3.0f;
|
||||
}
|
||||
if ((roll -= ((Integer)weights.tier2_weight.get()).intValue()) < 0) {
|
||||
return 5.0f + this.random.m_188501_() * 10.0f;
|
||||
}
|
||||
if ((roll -= ((Integer)weights.tier3_weight.get()).intValue()) < 0) {
|
||||
return 16.0f + this.random.m_188501_() * 24.0f;
|
||||
}
|
||||
if ((roll -= ((Integer)weights.tier4_weight.get()).intValue()) < 0) {
|
||||
return 41.0f + this.random.m_188501_() * 39.0f;
|
||||
}
|
||||
if ((roll -= ((Integer)weights.tier5_weight.get()).intValue()) < 0) {
|
||||
return 81.0f + this.random.m_188501_() * (((Double)Config.COMMON.ambient.maxAmbientExplosionPower.get()).floatValue() - 81.0f);
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
private SoundEnvironment determineSoundEnvironment(ServerPlayer player, Vec3 eventPos) {
|
||||
boolean isPlayerInCave = ServerExplosionHandler.isInNaturalCave(player.m_284548_(), player.m_20183_());
|
||||
Config.Common.Ambient.SoundTypes soundTypes = Config.COMMON.ambient.soundTypes;
|
||||
if (isPlayerInCave) {
|
||||
return (Boolean)soundTypes.enableCaveSounds.get() != false ? SoundEnvironment.CAVE : null;
|
||||
}
|
||||
return (Boolean)soundTypes.enableSurfaceSounds.get() != false ? SoundEnvironment.SURFACE : null;
|
||||
}
|
||||
|
||||
private void playSoundForEnvironment(ServerPlayer player, ServerLevel level, float power, SoundEnvironment env, boolean playerInHouse, long baseDelay, boolean isShellingShot, Vec3 eventPos) {
|
||||
boolean useAmbientSound;
|
||||
boolean explosionIsInCaveLocation;
|
||||
double explosionY;
|
||||
double distance = player.m_20182_().m_82554_(eventPos);
|
||||
boolean playerInCave = false;
|
||||
switch (env) {
|
||||
case CAVE: {
|
||||
explosionY = player.m_20186_() + (this.random.m_188500_() - 0.5) * 20.0;
|
||||
explosionIsInCaveLocation = true;
|
||||
playerInCave = true;
|
||||
if (isShellingShot || !((Boolean)Config.COMMON.ambient.soundTypes.enableAmbientCaveDust.get()).booleanValue()) break;
|
||||
PacketHandler.sendToPlayer(player, new SpawnAmbientCaveDustPacket(power));
|
||||
if (this.random.m_188500_() < 0.3 + (double)power * 0.02) {
|
||||
ExplosionOverhaul.addDelayedSound(player, (SoundEvent)ModSounds.DUST_SOUND.get(), SoundSource.AMBIENT, (float)player.m_20185_(), (float)player.m_20186_(), (float)player.m_20189_(), 0.7f, 1.0f, player.m_217043_().m_188505_(), baseDelay + (long)this.random.m_188503_(40));
|
||||
}
|
||||
if (!(this.random.m_188500_() < 0.05 + (double)power * 0.005) || !(power > 15.0f)) break;
|
||||
ExplosionOverhaul.addDelayedSound(player, (SoundEvent)ModSounds.FALLING_STONES_SOUND.get(), SoundSource.AMBIENT, (float)player.m_20185_(), (float)player.m_20186_(), (float)player.m_20189_(), 0.9f, 1.0f, player.m_217043_().m_188505_(), baseDelay + (long)this.random.m_188503_(50));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
explosionY = eventPos.m_7098_();
|
||||
explosionIsInCaveLocation = false;
|
||||
}
|
||||
}
|
||||
Vec3 finalExplosionPos = new Vec3(eventPos.m_7096_(), explosionY, eventPos.m_7094_());
|
||||
List<SoundEvent> soundPool = ServerExplosionHandler.getSoundPool((Level)level, power, distance, playerInHouse, explosionIsInCaveLocation);
|
||||
if (soundPool == null || soundPool.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
SoundEvent sound = soundPool.get(this.random.m_188503_(soundPool.size()));
|
||||
ResourceLocation soundId = BuiltInRegistries.SOUND_EVENT.getKey(sound);
|
||||
if (soundId == null) {
|
||||
return;
|
||||
}
|
||||
float volume = Math.min(power * 10.0f, 90.0f);
|
||||
float pitch = 0.95f + this.random.m_188501_() * 0.1f;
|
||||
double speedOfSound = 17.15;
|
||||
long delayTicksEffect = baseDelay + (long)(distance / speedOfSound);
|
||||
if (!isShellingShot) {
|
||||
float lampFlickerPowerThreshold;
|
||||
ServerExplosionHandler.CameraShakeProfile shakeProfile = AmbientExplosionManager.determineCameraShakeProfile(power, distance, playerInCave, level);
|
||||
if (shakeProfile.intensity() > 0.0f && shakeProfile.durationTicks() > 0) {
|
||||
int delayTicks = (int)Math.max(0L, Math.round(distance / speedOfSound));
|
||||
PacketHandler.sendToPlayer(player, new CameraShakePacket(shakeProfile.intensity(), shakeProfile.durationTicks(), shakeProfile.pushIntensity(), delayTicks));
|
||||
}
|
||||
if (power >= (lampFlickerPowerThreshold = distance > 1000.0 ? 31.0f : (distance > 500.0 ? 20.0f : (distance > 50.0 ? 10.0f : 4.0f)))) {
|
||||
RedstoneLampEffects.triggerLampFlicker(level, player, power, delayTicksEffect, distance);
|
||||
}
|
||||
}
|
||||
boolean bl = useAmbientSound = env == SoundEnvironment.CAVE;
|
||||
if (useAmbientSound) {
|
||||
ExplosionOverhaul.addDelayedSound(player, sound, SoundSource.AMBIENT, (float)player.m_20185_(), (float)player.m_20186_(), (float)player.m_20189_(), volume, pitch, player.m_217043_().m_188505_(), delayTicksEffect);
|
||||
} else {
|
||||
PacketHandler.sendToPlayer(player, new PlayTrackedSoundPacket(finalExplosionPos, soundId, volume, pitch, delayTicksEffect, playerInHouse));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private record AmbientSoundData(float power, long delay, boolean isShellingShot) {
|
||||
}
|
||||
|
||||
private static enum AmbientEventType {
|
||||
SINGLE,
|
||||
CHAIN_REACTION,
|
||||
SHELLING;
|
||||
|
||||
}
|
||||
|
||||
private static enum SoundEnvironment {
|
||||
SURFACE,
|
||||
CAVE;
|
||||
|
||||
public static ServerExplosionHandler.CameraShakeProfile determineCameraShakeProfile(float power, double distance, boolean playerInCave, ServerLevel level) {
|
||||
return new ServerExplosionHandler.CameraShakeProfile(0.0f, 0, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,522 +1,19 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
package com.vinlanx.explosionoverhaul;
|
||||
|
||||
import com.vinlanx.explosionoverhaul.Config;
|
||||
import com.vinlanx.explosionoverhaul.CraterDeformer;
|
||||
import com.vinlanx.explosionoverhaul.ExplosionOverhaul;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Position;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.core.particles.ParticleOptions;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.entity.item.FallingBlockEntity;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class AsyncCraterManager {
|
||||
private static ExecutorService executor;
|
||||
private static final ConcurrentLinkedQueue<Job> activeJobs;
|
||||
private static final AtomicLong globalEpoch;
|
||||
private static final ConcurrentHashMap<ResourceKey<Level>, AtomicLong> dimensionEpochs;
|
||||
|
||||
private static AtomicLong getDimensionEpoch(ResourceKey<Level> dimension) {
|
||||
return dimensionEpochs.computeIfAbsent(dimension, d -> new AtomicLong(0L));
|
||||
}
|
||||
|
||||
private static long incrementDimensionEpoch(ResourceKey<Level> dimension) {
|
||||
return AsyncCraterManager.getDimensionEpoch(dimension).incrementAndGet();
|
||||
}
|
||||
|
||||
public static synchronized void ensureExecutor() {
|
||||
if (executor != null && !executor.isShutdown()) {
|
||||
return;
|
||||
}
|
||||
int configured = (Integer)Config.COMMON.craterMaxThreads.get();
|
||||
int threads = configured == 0 ? Runtime.getRuntime().availableProcessors() : Math.max(1, configured);
|
||||
threads = Math.min(threads, 32);
|
||||
executor = Executors.newFixedThreadPool(threads, r -> {
|
||||
Thread t = new Thread(r, "EO-AsyncCrater");
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
});
|
||||
}
|
||||
|
||||
public static void submit(ServerLevel level, Vec3 pos, float power) {
|
||||
if (!((Boolean)Config.COMMON.enableCraterDestruction.get()).booleanValue()) {
|
||||
return;
|
||||
}
|
||||
AsyncCraterManager.ensureExecutor();
|
||||
ResourceKey dim = level.m_46472_();
|
||||
Job job = new Job(level, pos, power, globalEpoch.get(), AsyncCraterManager.getDimensionEpoch((ResourceKey<Level>)dim).get());
|
||||
((CompletableFuture)CompletableFuture.runAsync(job::compute, executor).thenRun(() -> {
|
||||
if (!job.isCancelled()) {
|
||||
activeJobs.add(job);
|
||||
}
|
||||
})).exceptionally(throwable -> {
|
||||
ExplosionOverhaul.LOGGER.warn("AsyncCraterManager: failed to compute crater job: {}", (Object)throwable.toString());
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public static void onServerTick(MinecraftServer server) {
|
||||
Job job;
|
||||
if (activeJobs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
int size = activeJobs.size();
|
||||
for (int i = 0; i < size && (job = activeJobs.poll()) != null; ++i) {
|
||||
if (job.isCancelled()) continue;
|
||||
job.applyBatch();
|
||||
if (job.isDone()) continue;
|
||||
activeJobs.add(job);
|
||||
}
|
||||
}
|
||||
|
||||
public static void onLevelUnload(ServerLevel level) {
|
||||
if (level == null) {
|
||||
return;
|
||||
}
|
||||
ResourceKey dim = level.m_46472_();
|
||||
AsyncCraterManager.incrementDimensionEpoch((ResourceKey<Level>)dim);
|
||||
activeJobs.removeIf(job -> job.isForDimension((ResourceKey<Level>)dim));
|
||||
}
|
||||
|
||||
public static synchronized void shutdown() {
|
||||
globalEpoch.incrementAndGet();
|
||||
dimensionEpochs.clear();
|
||||
activeJobs.clear();
|
||||
if (executor != null) {
|
||||
executor.shutdownNow();
|
||||
try {
|
||||
executor.awaitTermination(1L, TimeUnit.SECONDS);
|
||||
}
|
||||
catch (InterruptedException interruptedException) {
|
||||
// empty catch block
|
||||
}
|
||||
executor = null;
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
activeJobs = new ConcurrentLinkedQueue();
|
||||
globalEpoch = new AtomicLong(0L);
|
||||
dimensionEpochs = new ConcurrentHashMap();
|
||||
}
|
||||
|
||||
private static class Job {
|
||||
private final Vec3 explosionPos;
|
||||
private final float power;
|
||||
private final ResourceKey<Level> dimensionKey;
|
||||
private final long submitGlobalEpoch;
|
||||
private final long submitDimensionEpoch;
|
||||
private volatile List<Candidate> candidates;
|
||||
private volatile boolean computed;
|
||||
private final ServerLevel levelRef;
|
||||
private int appliedIndex;
|
||||
private final List<Candidate> ordered;
|
||||
private final RandomSource random;
|
||||
private float[] rayEnergy;
|
||||
private boolean[] rayDepleted;
|
||||
private int rayCount;
|
||||
private Set<BlockPos> destroyedPositions = new HashSet<BlockPos>();
|
||||
|
||||
Job(ServerLevel level, Vec3 pos, float power, long submitGlobalEpoch, long submitDimensionEpoch) {
|
||||
this.levelRef = level;
|
||||
this.dimensionKey = level.m_46472_();
|
||||
this.submitGlobalEpoch = submitGlobalEpoch;
|
||||
this.submitDimensionEpoch = submitDimensionEpoch;
|
||||
this.explosionPos = pos;
|
||||
this.power = power;
|
||||
this.candidates = new ArrayList<Candidate>();
|
||||
this.ordered = new ArrayList<Candidate>();
|
||||
this.random = RandomSource.m_216327_();
|
||||
}
|
||||
|
||||
/*
|
||||
* WARNING - Removed try catching itself - possible behaviour change.
|
||||
*/
|
||||
void compute() {
|
||||
try {
|
||||
double multiplier = (Double)Config.COMMON.craterSizeMultiplier.get();
|
||||
double baseRadius = CraterDeformer.calculateRadius(this.power);
|
||||
double finalRadius = baseRadius * multiplier;
|
||||
if (finalRadius <= 0.0) {
|
||||
this.computed = true;
|
||||
return;
|
||||
}
|
||||
boolean large = this.power >= 40.0f;
|
||||
double coreRatio = (Double)Config.COMMON.craterCoreRatio.get();
|
||||
double coreRadius = large ? finalRadius * coreRatio : 0.0;
|
||||
int searchRadius = (int)Math.ceil(finalRadius);
|
||||
BlockPos centerPos = BlockPos.m_274446_((Position)this.explosionPos);
|
||||
RandomSource rnd = RandomSource.m_216327_();
|
||||
if (large) {
|
||||
HashSet<BlockPos> corePositions = new HashSet<BlockPos>();
|
||||
for (int x = -searchRadius; x <= searchRadius; ++x) {
|
||||
for (int y = -searchRadius; y <= searchRadius; ++y) {
|
||||
for (int z = -searchRadius; z <= searchRadius; ++z) {
|
||||
double noise;
|
||||
BlockPos p = centerPos.m_7918_(x, y, z);
|
||||
double dist = Math.sqrt(p.m_123331_((Vec3i)centerPos));
|
||||
if (!(dist <= coreRadius * (noise = 1.0 - rnd.m_188500_() * 0.3)) || !corePositions.add(p)) continue;
|
||||
this.candidates.add(new Candidate(p, -1, 0, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int numberOfRays = (int)Math.max(200.0, Math.min(large ? 25000.0 : 75000.0, finalRadius * (double)(large ? 75 : 150)));
|
||||
double goldenRatio = (1.0 + Math.sqrt(5.0)) / 2.0;
|
||||
double angleIncrement = Math.PI * 2 * goldenRatio;
|
||||
double stepIncrement = 0.4;
|
||||
double startStep = large ? coreRadius * 0.8 : 0.0;
|
||||
this.rayCount = numberOfRays;
|
||||
for (int i = 0; i < numberOfRays; ++i) {
|
||||
double t = (double)i / (double)numberOfRays;
|
||||
double inclination = Math.acos(1.0 - 2.0 * t);
|
||||
double azimuth = angleIncrement * (double)i;
|
||||
Vec3 dir = new Vec3(Math.cos(azimuth) * Math.sin(inclination), Math.sin(azimuth) * Math.sin(inclination), Math.cos(inclination)).m_82541_();
|
||||
int stepIndex = 0;
|
||||
BlockPos lastPos = null;
|
||||
for (double step = startStep; step < finalRadius; step += stepIncrement) {
|
||||
BlockPos p = BlockPos.m_274446_((Position)this.explosionPos.m_82549_(dir.m_82490_(step)));
|
||||
if (p.equals(lastPos)) continue;
|
||||
lastPos = p;
|
||||
this.candidates.add(new Candidate(p, i, stepIndex, false));
|
||||
++stepIndex;
|
||||
}
|
||||
}
|
||||
ArrayList<Candidate> coreBlocks = new ArrayList<Candidate>();
|
||||
ArrayList<Candidate> rayBlocks = new ArrayList<Candidate>();
|
||||
for (Candidate c : this.candidates) {
|
||||
if (c.core) {
|
||||
coreBlocks.add(c);
|
||||
continue;
|
||||
}
|
||||
rayBlocks.add(c);
|
||||
}
|
||||
rayBlocks.sort((a, b) -> {
|
||||
int cmp = Integer.compare(a.rayId, b.rayId);
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
return Integer.compare(a.stepIndex, b.stepIndex);
|
||||
});
|
||||
this.ordered.addAll(coreBlocks);
|
||||
this.ordered.addAll(rayBlocks);
|
||||
}
|
||||
finally {
|
||||
this.computed = true;
|
||||
}
|
||||
}
|
||||
|
||||
boolean isCancelled() {
|
||||
long currentDimEpoch;
|
||||
if (this.submitGlobalEpoch != globalEpoch.get()) {
|
||||
return true;
|
||||
}
|
||||
AtomicLong dimEpoch = dimensionEpochs.get(this.dimensionKey);
|
||||
long l = currentDimEpoch = dimEpoch == null ? 0L : dimEpoch.get();
|
||||
if (this.submitDimensionEpoch != currentDimEpoch) {
|
||||
return true;
|
||||
}
|
||||
return this.levelRef.m_7654_() == null;
|
||||
}
|
||||
|
||||
boolean isForDimension(ResourceKey<Level> dim) {
|
||||
return this.dimensionKey.equals(dim);
|
||||
}
|
||||
|
||||
boolean isDone() {
|
||||
return this.computed && this.appliedIndex >= this.ordered.size();
|
||||
}
|
||||
|
||||
/*
|
||||
* Unable to fully structure code
|
||||
*/
|
||||
void applyBatch() {
|
||||
block37: {
|
||||
block38: {
|
||||
if (!this.computed) {
|
||||
return;
|
||||
}
|
||||
if (this.isCancelled()) {
|
||||
this.appliedIndex = this.ordered.size();
|
||||
return;
|
||||
}
|
||||
budget = Math.max(100, (Integer)Config.COMMON.craterApplyBlocksPerTick.get());
|
||||
maxFallingPerTick = Math.max(0, (Integer)Config.COMMON.craterMaxFallingBlocksPerTick.get());
|
||||
spawnedFalling = 0;
|
||||
if (this.rayEnergy == null) {
|
||||
multiplier = (Double)Config.COMMON.craterSizeMultiplier.get();
|
||||
large = this.power >= 40.0f;
|
||||
base = (float)((double)(this.power * (large != false ? 4.0f : 7.5f)) * multiplier);
|
||||
this.rayEnergy = new float[Math.max(1, this.rayCount)];
|
||||
this.rayDepleted = new boolean[Math.max(1, this.rayCount)];
|
||||
rnd = this.levelRef.m_213780_();
|
||||
for (i = 0; i < this.rayEnergy.length; ++i) {
|
||||
this.rayEnergy[i] = base * (0.75f + rnd.m_188501_() * 0.5f);
|
||||
}
|
||||
}
|
||||
end = Math.min(this.appliedIndex + budget, this.ordered.size());
|
||||
direct = (Boolean)Config.COMMON.enableDirectChunkWrites.get();
|
||||
if (direct) break block38;
|
||||
while (this.appliedIndex < end) {
|
||||
block39: {
|
||||
block41: {
|
||||
block40: {
|
||||
c = this.ordered.get(this.appliedIndex);
|
||||
pos = c.pos;
|
||||
if (!this.levelRef.m_46749_(pos) || this.levelRef.m_151570_(pos) || !c.core && this.rayDepleted[rayId = Math.max(0, c.rayId)] || this.destroyedPositions.contains(pos) || (state = this.levelRef.m_8055_(pos)).m_60795_()) break block39;
|
||||
if (!((Boolean)Config.COMMON.enableCraterDestruction.get()).booleanValue()) {
|
||||
this.appliedIndex = this.ordered.size();
|
||||
break block37;
|
||||
}
|
||||
resistance = state.m_60800_((BlockGetter)this.levelRef, pos);
|
||||
if (resistance < 0.0f) break block39;
|
||||
if (!ExplosionOverhaul.isBlockStateBlacklisted(state) && !state.m_60734_().m_204297_().m_203656_(BlockTags.f_13070_) && !state.m_60713_(Blocks.f_50722_)) break block40;
|
||||
if (!c.core) {
|
||||
rayId = Math.max(0, c.rayId);
|
||||
this.rayDepleted[rayId] = true;
|
||||
}
|
||||
break block39;
|
||||
}
|
||||
if (!(resistance > Job.calculateMaxResistance(this.power))) break block41;
|
||||
if (!c.core) {
|
||||
rayId = Math.max(0, c.rayId);
|
||||
this.rayDepleted[rayId] = true;
|
||||
}
|
||||
break block39;
|
||||
}
|
||||
boolean shouldDestroy = c.core;
|
||||
if (!c.core) {
|
||||
v0 = rayId = Math.max(0, c.rayId);
|
||||
this.rayEnergy[v0] = this.rayEnergy[v0] - (resistance + 0.3f);
|
||||
if (this.rayEnergy[rayId] <= 0.0f) {
|
||||
this.rayDepleted[rayId] = true;
|
||||
} else {
|
||||
shouldDestroy = true;
|
||||
}
|
||||
}
|
||||
if (shouldDestroy) {
|
||||
v1 = allowFalling = this.power <= 20.0f && (Boolean)Config.COMMON.enableFallingBlocks.get() != false && spawnedFalling < maxFallingPerTick;
|
||||
if (allowFalling) {
|
||||
inner = c.core != false || c.stepIndex <= 5;
|
||||
v2 = chance = inner != false ? 0.35 : 0.15;
|
||||
if (this.random.m_188500_() < chance) {
|
||||
falling = FallingBlockEntity.m_201971_((Level)this.levelRef, (BlockPos)pos, (BlockState)state);
|
||||
falling.m_6034_((double)pos.m_123341_() + 0.5, (double)pos.m_123342_() + 0.5, (double)pos.m_123343_() + 0.5);
|
||||
motionDir = Vec3.m_82512_((Vec3i)pos).m_82546_(this.explosionPos).m_82541_();
|
||||
powerMul = 0.4 + this.random.m_188500_() * 0.6;
|
||||
falling.m_20334_(motionDir.f_82479_ * powerMul + (this.random.m_188500_() - 0.5) * 0.3, motionDir.f_82480_ * powerMul + 0.4 + this.random.m_188500_() * 0.3, motionDir.f_82481_ * powerMul + (this.random.m_188500_() - 0.5) * 0.3);
|
||||
++spawnedFalling;
|
||||
}
|
||||
}
|
||||
this.levelRef.m_7731_(pos, Blocks.f_50016_.m_49966_(), 2);
|
||||
this.destroyedPositions.add(pos);
|
||||
}
|
||||
}
|
||||
++this.appliedIndex;
|
||||
}
|
||||
break block37;
|
||||
}
|
||||
maxChunks = Math.max(1, (Integer)Config.COMMON.craterChunksPerTick.get());
|
||||
byChunk = new LinkedHashMap<LevelChunk, List>();
|
||||
i = this.appliedIndex;
|
||||
while (i < end && byChunk.size() < maxChunks) {
|
||||
c = this.ordered.get(i);
|
||||
pos = c.pos;
|
||||
if (!this.levelRef.m_46749_(pos) || this.levelRef.m_151570_(pos)) {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
chunk = this.levelRef.m_46745_(pos);
|
||||
byChunk.computeIfAbsent(chunk, Job::lambda$applyBatch$1).add(c);
|
||||
++i;
|
||||
}
|
||||
for (Map.Entry<LevelChunk, List> e : byChunk.entrySet()) {
|
||||
chunk = (LevelChunk)e.getKey();
|
||||
list = (List)e.getValue();
|
||||
list.sort((Comparator<Candidate>)Job::lambda$applyBatch$2);
|
||||
modifiedSections = new HashSet<SectionPos>();
|
||||
toRelight = new ArrayList<BlockPos>();
|
||||
relightBudget = Math.min(256, list.size());
|
||||
for (Candidate c : list) {
|
||||
if (!c.core && this.rayDepleted[rayId = Math.max(0, c.rayId)]) {
|
||||
++this.appliedIndex;
|
||||
continue;
|
||||
}
|
||||
pos = c.pos;
|
||||
if (this.destroyedPositions.contains(pos)) {
|
||||
++this.appliedIndex;
|
||||
continue;
|
||||
}
|
||||
if (!((Boolean)Config.COMMON.enableCraterDestruction.get()).booleanValue()) {
|
||||
this.appliedIndex = this.ordered.size();
|
||||
break;
|
||||
}
|
||||
state = this.levelRef.m_8055_(pos);
|
||||
if (state.m_60795_()) {
|
||||
++this.appliedIndex;
|
||||
continue;
|
||||
}
|
||||
resistance = state.m_60800_((BlockGetter)this.levelRef, pos);
|
||||
if (resistance < 0.0f) {
|
||||
++this.appliedIndex;
|
||||
continue;
|
||||
}
|
||||
if (ExplosionOverhaul.isBlockStateBlacklisted(state) || state.m_60734_().m_204297_().m_203656_(BlockTags.f_13070_) || state.m_60713_(Blocks.f_50722_)) {
|
||||
if (!c.core) {
|
||||
rayId = Math.max(0, c.rayId);
|
||||
this.rayDepleted[rayId] = true;
|
||||
}
|
||||
++this.appliedIndex;
|
||||
continue;
|
||||
}
|
||||
if (resistance > Job.calculateMaxResistance(this.power)) {
|
||||
if (!c.core) {
|
||||
rayId = Math.max(0, c.rayId);
|
||||
this.rayDepleted[rayId] = true;
|
||||
}
|
||||
++this.appliedIndex;
|
||||
continue;
|
||||
}
|
||||
if (!c.core) {
|
||||
v3 = rayId = Math.max(0, c.rayId);
|
||||
this.rayEnergy[v3] = this.rayEnergy[v3] - (resistance + 0.3f);
|
||||
if (this.rayEnergy[rayId] <= 0.0f) {
|
||||
this.rayDepleted[rayId] = true;
|
||||
++this.appliedIndex;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (state.m_155947_()) {
|
||||
this.levelRef.m_46961_(pos, true);
|
||||
++this.appliedIndex;
|
||||
continue;
|
||||
}
|
||||
secIdx = chunk.m_151564_(pos.m_123342_());
|
||||
if (secIdx < 0 || secIdx >= chunk.m_7103_().length) {
|
||||
++this.appliedIndex;
|
||||
continue;
|
||||
}
|
||||
section = chunk.m_7103_()[secIdx];
|
||||
old = section.m_62982_(lx = pos.m_123341_() & 15, ly = pos.m_123342_() & 15, lz = pos.m_123343_() & 15);
|
||||
if (old.m_60795_()) {
|
||||
++this.appliedIndex;
|
||||
continue;
|
||||
}
|
||||
section.m_62986_(lx, ly, lz, Blocks.f_50016_.m_49966_());
|
||||
this.destroyedPositions.add(pos);
|
||||
for (Map.Entry m : chunk.m_6890_()) {
|
||||
type = (Heightmap.Types)m.getKey();
|
||||
if (type != Heightmap.Types.MOTION_BLOCKING && type != Heightmap.Types.MOTION_BLOCKING_NO_LEAVES && type != Heightmap.Types.OCEAN_FLOOR && type != Heightmap.Types.WORLD_SURFACE) continue;
|
||||
((Heightmap)m.getValue()).m_64249_(lx, pos.m_123342_(), lz, Blocks.f_50016_.m_49966_());
|
||||
}
|
||||
this.levelRef.m_7260_(pos, old, Blocks.f_50016_.m_49966_(), 2);
|
||||
modifiedSections.add(SectionPos.m_123199_((BlockPos)pos));
|
||||
if (toRelight.size() < relightBudget) {
|
||||
toRelight.add(pos.m_7949_());
|
||||
}
|
||||
v4 = allowFalling = this.power <= 20.0f && (Boolean)Config.COMMON.enableFallingBlocks.get() != false && spawnedFalling < maxFallingPerTick;
|
||||
if (allowFalling) {
|
||||
inner = c.core != false || c.stepIndex <= 5;
|
||||
v5 = chance = inner != false ? 0.35 : 0.15;
|
||||
if (this.random.m_188500_() < chance) {
|
||||
falling = FallingBlockEntity.m_201971_((Level)this.levelRef, (BlockPos)pos, (BlockState)old);
|
||||
falling.m_6034_((double)pos.m_123341_() + 0.5, (double)pos.m_123342_() + 0.5, (double)pos.m_123343_() + 0.5);
|
||||
motionDir = Vec3.m_82512_((Vec3i)pos).m_82546_(this.explosionPos).m_82541_();
|
||||
powerMul = 0.4 + this.random.m_188500_() * 0.6;
|
||||
falling.m_20334_(motionDir.f_82479_ * powerMul + (this.random.m_188500_() - 0.5) * 0.3, motionDir.f_82480_ * powerMul + 0.4 + this.random.m_188500_() * 0.3, motionDir.f_82481_ * powerMul + (this.random.m_188500_() - 0.5) * 0.3);
|
||||
++spawnedFalling;
|
||||
}
|
||||
}
|
||||
++this.appliedIndex;
|
||||
}
|
||||
chunk.m_8092_(true);
|
||||
light = this.levelRef.m_7726_().m_7827_();
|
||||
for (SectionPos sp : modifiedSections) {
|
||||
sec = chunk.m_7103_()[chunk.m_151564_(sp.m_123206_() << 4)];
|
||||
empty = sec.m_188008_();
|
||||
light.m_6191_(sp, empty);
|
||||
}
|
||||
for (BlockPos rp : toRelight) {
|
||||
light.m_7174_(rp);
|
||||
light.m_7174_(rp.m_7494_());
|
||||
}
|
||||
light.m_9353_((ChunkAccess)chunk, true);
|
||||
}
|
||||
}
|
||||
if (this.isDone()) {
|
||||
this.levelRef.m_8767_((ParticleOptions)ParticleTypes.f_123812_, this.explosionPos.f_82479_, this.explosionPos.f_82480_, this.explosionPos.f_82481_, 1, 0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
private static float calculateMaxResistance(float power) {
|
||||
float maxRes = power <= 4.0f ? 10.0f : (power <= 10.0f ? 10.0f + (power - 4.0f) * 10.0f / 6.0f : (power <= 25.0f ? 20.0f + (power - 10.0f) * 10.0f / 15.0f : (power <= 40.0f ? 30.0f + (power - 25.0f) * 10.0f / 15.0f : (power <= 70.0f ? 40.0f + (power - 40.0f) * 10.0f / 30.0f : Float.MAX_VALUE))));
|
||||
return maxRes;
|
||||
}
|
||||
|
||||
private static /* synthetic */ int lambda$applyBatch$2(Candidate a, Candidate b) {
|
||||
if (a.core && !b.core) {
|
||||
return -1;
|
||||
}
|
||||
if (!a.core && b.core) {
|
||||
return 1;
|
||||
}
|
||||
if (a.core && b.core) {
|
||||
return 0;
|
||||
}
|
||||
int cmp = Integer.compare(a.rayId, b.rayId);
|
||||
if (cmp != 0) {
|
||||
return cmp;
|
||||
}
|
||||
return Integer.compare(a.stepIndex, b.stepIndex);
|
||||
}
|
||||
|
||||
private static /* synthetic */ List lambda$applyBatch$1(LevelChunk k) {
|
||||
return new ArrayList();
|
||||
}
|
||||
|
||||
private static class Candidate {
|
||||
final BlockPos pos;
|
||||
final int rayId;
|
||||
final int stepIndex;
|
||||
final boolean core;
|
||||
|
||||
Candidate(BlockPos pos, int rayId, int stepIndex, boolean core) {
|
||||
this.pos = pos;
|
||||
this.rayId = rayId;
|
||||
this.stepIndex = stepIndex;
|
||||
this.core = core;
|
||||
}
|
||||
}
|
||||
public static void shutdown() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1152,7 +1152,7 @@ public class BlockIndexManager {
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
return player.m_20310_(2) || isSingleplayer;
|
||||
return player.hasPermissions(2) || isSingleplayer;
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
||||
@@ -1,244 +1,27 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
package com.vinlanx.explosionoverhaul;
|
||||
|
||||
import com.vinlanx.explosionoverhaul.Config;
|
||||
import com.vinlanx.explosionoverhaul.ExplosionOverhaul;
|
||||
import java.util.HashSet;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Position;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.core.particles.ParticleOptions;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.entity.item.FallingBlockEntity;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class CraterDeformer {
|
||||
public static Set<BlockPos> getCraterBlocks(ServerLevel level, Vec3 explosionPos, float power) {
|
||||
double multiplier = (Double)Config.COMMON.craterSizeMultiplier.get();
|
||||
double baseRadius = CraterDeformer.calculateRadius(power);
|
||||
double finalRadius = baseRadius * multiplier;
|
||||
if (finalRadius <= 0.0) {
|
||||
return new HashSet<BlockPos>();
|
||||
}
|
||||
HashSet<BlockPos> blocksToDestroy = new HashSet<BlockPos>();
|
||||
if (power >= 40.0f) {
|
||||
double coreRatio = (Double)Config.COMMON.craterCoreRatio.get();
|
||||
double coreRadius = finalRadius * coreRatio;
|
||||
int searchRadius = (int)Math.ceil(finalRadius);
|
||||
BlockPos centerPos = BlockPos.m_274446_((Position)explosionPos);
|
||||
RandomSource random = level.m_213780_();
|
||||
for (int x = -searchRadius; x <= searchRadius; ++x) {
|
||||
for (int y = -searchRadius; y <= searchRadius; ++y) {
|
||||
for (int z = -searchRadius; z <= searchRadius; ++z) {
|
||||
double noise;
|
||||
BlockPos currentPos = centerPos.m_7918_(x, y, z);
|
||||
double distanceToCenter = Math.sqrt(currentPos.m_123331_((Vec3i)centerPos));
|
||||
if (!(distanceToCenter <= coreRadius * (noise = 1.0 - random.m_188500_() * 0.3)) || !level.m_46749_(currentPos) || level.m_151570_(currentPos)) continue;
|
||||
BlockState state = level.m_8055_(currentPos);
|
||||
Block block = state.m_60734_();
|
||||
float resistance = state.m_60800_((BlockGetter)level, currentPos);
|
||||
if (state.m_60795_() || resistance < 0.0f || resistance > CraterDeformer.calculateMaxResistance(power) || block == Blocks.f_50722_ || ExplosionOverhaul.isBlockBlacklisted(block)) continue;
|
||||
blocksToDestroy.add(currentPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
int numberOfRays = (int)Math.max(200.0, Math.min(25000.0, finalRadius * 75.0));
|
||||
float rayEnergy = (float)((double)(power * 4.0f) * multiplier);
|
||||
double goldenRatio = (1.0 + Math.sqrt(5.0)) / 2.0;
|
||||
double angleIncrement = Math.PI * 2 * goldenRatio;
|
||||
double stepIncrement = 0.4;
|
||||
block3: for (int i = 0; i < numberOfRays; ++i) {
|
||||
double t = (double)i / (double)numberOfRays;
|
||||
double inclination = Math.acos(1.0 - 2.0 * t);
|
||||
double azimuth = angleIncrement * (double)i;
|
||||
Vec3 rayDirection = new Vec3(Math.cos(azimuth) * Math.sin(inclination), Math.sin(azimuth) * Math.sin(inclination), Math.cos(inclination)).m_82541_();
|
||||
float currentEnergy = rayEnergy * (0.75f + level.m_213780_().m_188501_() * 0.5f);
|
||||
BlockPos lastPos = null;
|
||||
for (double step = coreRadius * 0.8; step < finalRadius; step += 0.4) {
|
||||
BlockPos currentPos = BlockPos.m_274446_((Position)explosionPos.m_82549_(rayDirection.m_82490_(step)));
|
||||
if (currentPos.equals(lastPos) || !level.m_46749_(currentPos) || level.m_151570_(currentPos)) continue;
|
||||
lastPos = currentPos;
|
||||
BlockState state = level.m_8055_(currentPos);
|
||||
Block block = state.m_60734_();
|
||||
if (state.m_60795_() || block == Blocks.f_50722_ || ExplosionOverhaul.isBlockBlacklisted(block)) continue;
|
||||
float resistance = state.m_60800_((BlockGetter)level, currentPos);
|
||||
if (resistance < 0.0f || resistance > CraterDeformer.calculateMaxResistance(power) || block == Blocks.f_50722_ || ExplosionOverhaul.isBlockBlacklisted(block) || !((currentEnergy -= resistance + 0.3f) > 0.0f)) continue block3;
|
||||
blocksToDestroy.add(currentPos);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int numberOfRays = (int)Math.max(200.0, Math.min(75000.0, finalRadius * 150.0));
|
||||
float rayEnergy = (float)((double)(power * 7.5f) * multiplier);
|
||||
double goldenRatio = (1.0 + Math.sqrt(5.0)) / 2.0;
|
||||
double angleIncrement = Math.PI * 2 * goldenRatio;
|
||||
double stepIncrement = 0.4;
|
||||
RandomSource random = level.m_213780_();
|
||||
block5: for (int i = 0; i < numberOfRays; ++i) {
|
||||
double t = (double)i / (double)numberOfRays;
|
||||
double inclination = Math.acos(1.0 - 2.0 * t);
|
||||
double azimuth = angleIncrement * (double)i;
|
||||
Vec3 rayDirection = new Vec3(Math.cos(azimuth) * Math.sin(inclination), Math.sin(azimuth) * Math.sin(inclination), Math.cos(inclination)).m_82541_();
|
||||
float currentEnergy = rayEnergy * (0.75f + random.m_188501_() * 0.5f);
|
||||
BlockPos lastPos = null;
|
||||
for (double step = 0.0; step < finalRadius; step += 0.4) {
|
||||
BlockPos currentPos = BlockPos.m_274446_((Position)explosionPos.m_82549_(rayDirection.m_82490_(step)));
|
||||
if (currentPos.equals(lastPos) || !level.m_46749_(currentPos) || level.m_151570_(currentPos)) continue;
|
||||
lastPos = currentPos;
|
||||
BlockState state = level.m_8055_(currentPos);
|
||||
Block block = state.m_60734_();
|
||||
if (state.m_60795_() || block == Blocks.f_50722_ || ExplosionOverhaul.isBlockBlacklisted(block)) continue;
|
||||
float resistance = state.m_60800_((BlockGetter)level, currentPos);
|
||||
if (resistance < 0.0f || resistance > CraterDeformer.calculateMaxResistance(power) || block == Blocks.f_50722_ || ExplosionOverhaul.isBlockBlacklisted(block) || !((currentEnergy -= resistance + 0.3f) > 0.0f)) continue block5;
|
||||
blocksToDestroy.add(currentPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
return blocksToDestroy;
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
public static float calculateRadius(float power) {
|
||||
float baseRadius = power <= 4.0f ? Mth.m_14179_((float)(power / 4.0f), (float)2.0f, (float)6.0f) : (power <= 50.0f ? Mth.m_14179_((float)((power - 4.0f) / 46.0f), (float)6.0f, (float)60.0f) : 60.0f + (power - 50.0f) * 1.5f);
|
||||
return baseRadius * 0.5f;
|
||||
return Math.max(1.0f, power);
|
||||
}
|
||||
|
||||
private static float calculateMaxResistance(float power) {
|
||||
float maxRes = power <= 4.0f ? 10.0f : (power <= 10.0f ? 10.0f + (power - 4.0f) * 10.0f / 6.0f : (power <= 25.0f ? 20.0f + (power - 10.0f) * 10.0f / 15.0f : (power <= 40.0f ? 30.0f + (power - 25.0f) * 10.0f / 15.0f : (power <= 70.0f ? 40.0f + (power - 40.0f) * 10.0f / 30.0f : Float.MAX_VALUE))));
|
||||
return maxRes;
|
||||
public static float calculateMaxResistance(float power) {
|
||||
return Float.MAX_VALUE;
|
||||
}
|
||||
|
||||
public static void apply(ServerLevel level, Vec3 explosionPos, float power) {
|
||||
if (power >= 40.0f) {
|
||||
CraterDeformer.applyLargeExplosionLogic(level, explosionPos, power);
|
||||
} else {
|
||||
CraterDeformer.applySmallExplosionLogic(level, explosionPos, power);
|
||||
}
|
||||
public static void applyLargeExplosionLogic(ServerLevel level, Vec3 explosionPos, float power) {
|
||||
}
|
||||
|
||||
private static void applyLargeExplosionLogic(ServerLevel level, Vec3 explosionPos, float power) {
|
||||
RandomSource random = level.m_213780_();
|
||||
double multiplier = (Double)Config.COMMON.craterSizeMultiplier.get();
|
||||
double baseRadius = CraterDeformer.calculateRadius(power);
|
||||
double finalRadius = baseRadius * multiplier;
|
||||
if (finalRadius <= 0.0) {
|
||||
return;
|
||||
}
|
||||
HashSet<BlockPos> blocksToDestroy = new HashSet<BlockPos>();
|
||||
HashSet<BlockPos> blocksToLaunch = new HashSet<BlockPos>();
|
||||
double coreRatio = (Double)Config.COMMON.craterCoreRatio.get();
|
||||
double coreRadius = finalRadius * coreRatio;
|
||||
int searchRadius = (int)Math.ceil(finalRadius);
|
||||
BlockPos centerPos = BlockPos.m_274446_((Position)explosionPos);
|
||||
for (int x = -searchRadius; x <= searchRadius; ++x) {
|
||||
for (int y = -searchRadius; y <= searchRadius; ++y) {
|
||||
for (int z = -searchRadius; z <= searchRadius; ++z) {
|
||||
double noise;
|
||||
BlockPos currentPos = centerPos.m_7918_(x, y, z);
|
||||
double distanceToCenter = Math.sqrt(currentPos.m_123331_((Vec3i)centerPos));
|
||||
if (!(distanceToCenter <= coreRadius * (noise = 1.0 - random.m_188500_() * 0.3)) || !level.m_46749_(currentPos) || level.m_151570_(currentPos)) continue;
|
||||
BlockState state = level.m_8055_(currentPos);
|
||||
Block block = state.m_60734_();
|
||||
float resistance = state.m_60800_((BlockGetter)level, currentPos);
|
||||
if (state.m_60795_() || resistance < 0.0f || resistance > CraterDeformer.calculateMaxResistance(power) || block == Blocks.f_50722_ || ExplosionOverhaul.isBlockBlacklisted(block)) continue;
|
||||
blocksToDestroy.add(currentPos);
|
||||
if (!(distanceToCenter < coreRadius * 0.4)) continue;
|
||||
blocksToLaunch.add(currentPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
int numberOfRays = (int)Math.max(200.0, Math.min(25000.0, finalRadius * 75.0));
|
||||
float rayEnergy = (float)((double)(power * 4.0f) * multiplier);
|
||||
double goldenRatio = (1.0 + Math.sqrt(5.0)) / 2.0;
|
||||
double angleIncrement = Math.PI * 2 * goldenRatio;
|
||||
double stepIncrement = 0.4;
|
||||
block3: for (int i = 0; i < numberOfRays; ++i) {
|
||||
double t = (double)i / (double)numberOfRays;
|
||||
double inclination = Math.acos(1.0 - 2.0 * t);
|
||||
double azimuth = angleIncrement * (double)i;
|
||||
Vec3 rayDirection = new Vec3(Math.cos(azimuth) * Math.sin(inclination), Math.sin(azimuth) * Math.sin(inclination), Math.cos(inclination)).m_82541_();
|
||||
float currentEnergy = rayEnergy * (0.75f + random.m_188501_() * 0.5f);
|
||||
BlockPos lastPos = null;
|
||||
for (double step = coreRadius * 0.8; step < finalRadius; step += 0.4) {
|
||||
BlockPos currentPos = BlockPos.m_274446_((Position)explosionPos.m_82549_(rayDirection.m_82490_(step)));
|
||||
if (currentPos.equals(lastPos) || !level.m_46749_(currentPos) || level.m_151570_(currentPos)) continue;
|
||||
lastPos = currentPos;
|
||||
BlockState state = level.m_8055_(currentPos);
|
||||
Block block = state.m_60734_();
|
||||
if (state.m_60795_() || block == Blocks.f_50722_ || ExplosionOverhaul.isBlockBlacklisted(block)) continue;
|
||||
float resistance = state.m_60800_((BlockGetter)level, currentPos);
|
||||
if (resistance < 0.0f || resistance > CraterDeformer.calculateMaxResistance(power) || block == Blocks.f_50722_ || ExplosionOverhaul.isBlockBlacklisted(block) || !((currentEnergy -= resistance + 0.3f) > 0.0f)) continue block3;
|
||||
blocksToDestroy.add(currentPos);
|
||||
}
|
||||
}
|
||||
CraterDeformer.finalizeExplosion(level, explosionPos, power, blocksToDestroy, blocksToLaunch);
|
||||
}
|
||||
|
||||
private static void applySmallExplosionLogic(ServerLevel level, Vec3 explosionPos, float power) {
|
||||
RandomSource random = level.m_213780_();
|
||||
double multiplier = (Double)Config.COMMON.craterSizeMultiplier.get();
|
||||
double baseRadius = CraterDeformer.calculateRadius(power);
|
||||
double finalRadius = baseRadius * multiplier;
|
||||
if (finalRadius <= 0.0) {
|
||||
return;
|
||||
}
|
||||
int numberOfRays = (int)Math.max(200.0, Math.min(75000.0, finalRadius * 150.0));
|
||||
float rayEnergy = (float)((double)(power * 7.5f) * multiplier);
|
||||
HashSet<BlockPos> blocksToDestroy = new HashSet<BlockPos>();
|
||||
HashSet<BlockPos> blocksToLaunch = new HashSet<BlockPos>();
|
||||
double goldenRatio = (1.0 + Math.sqrt(5.0)) / 2.0;
|
||||
double angleIncrement = Math.PI * 2 * goldenRatio;
|
||||
double stepIncrement = 0.4;
|
||||
block0: for (int i = 0; i < numberOfRays; ++i) {
|
||||
double t = (double)i / (double)numberOfRays;
|
||||
double inclination = Math.acos(1.0 - 2.0 * t);
|
||||
double azimuth = angleIncrement * (double)i;
|
||||
Vec3 rayDirection = new Vec3(Math.cos(azimuth) * Math.sin(inclination), Math.sin(azimuth) * Math.sin(inclination), Math.cos(inclination)).m_82541_();
|
||||
float currentEnergy = rayEnergy * (0.75f + random.m_188501_() * 0.5f);
|
||||
BlockPos lastPos = null;
|
||||
for (double step = 0.0; step < finalRadius; step += 0.4) {
|
||||
BlockPos currentPos = BlockPos.m_274446_((Position)explosionPos.m_82549_(rayDirection.m_82490_(step)));
|
||||
if (currentPos.equals(lastPos) || !level.m_46749_(currentPos) || level.m_151570_(currentPos)) continue;
|
||||
lastPos = currentPos;
|
||||
BlockState state = level.m_8055_(currentPos);
|
||||
Block block = state.m_60734_();
|
||||
if (state.m_60795_() || block == Blocks.f_50722_ || ExplosionOverhaul.isBlockBlacklisted(block)) continue;
|
||||
float resistance = state.m_60800_((BlockGetter)level, currentPos);
|
||||
if (resistance < 0.0f || resistance > CraterDeformer.calculateMaxResistance(power) || block == Blocks.f_50722_ || ExplosionOverhaul.isBlockBlacklisted(block) || !((currentEnergy -= resistance + 0.3f) > 0.0f)) continue block0;
|
||||
blocksToDestroy.add(currentPos);
|
||||
if (!(step < finalRadius * 0.3)) continue;
|
||||
blocksToLaunch.add(currentPos);
|
||||
}
|
||||
}
|
||||
CraterDeformer.finalizeExplosion(level, explosionPos, power, blocksToDestroy, blocksToLaunch);
|
||||
}
|
||||
|
||||
private static void finalizeExplosion(ServerLevel level, Vec3 explosionPos, float power, Set<BlockPos> blocksToDestroy, Set<BlockPos> blocksToLaunch) {
|
||||
boolean allowFallingBlocks;
|
||||
RandomSource random = level.m_213780_();
|
||||
level.m_8767_((ParticleOptions)ParticleTypes.f_123812_, explosionPos.f_82479_, explosionPos.f_82480_, explosionPos.f_82481_, 1, 0.0, 0.0, 0.0, 0.0);
|
||||
boolean bl = allowFallingBlocks = power <= 20.0f && (Boolean)Config.COMMON.enableFallingBlocks.get() != false;
|
||||
if (allowFallingBlocks) {
|
||||
for (BlockPos posToLaunch : blocksToLaunch) {
|
||||
if (!(random.m_188500_() < 0.35)) continue;
|
||||
FallingBlockEntity falling = FallingBlockEntity.m_201971_((Level)level, (BlockPos)posToLaunch, (BlockState)level.m_8055_(posToLaunch));
|
||||
falling.m_6034_((double)posToLaunch.m_123341_() + 0.5, (double)posToLaunch.m_123342_() + 0.5, (double)posToLaunch.m_123343_() + 0.5);
|
||||
Vec3 motionDir = Vec3.m_82512_((Vec3i)posToLaunch).m_82546_(explosionPos).m_82541_();
|
||||
double powerMul = 0.5 + random.m_188500_() * 0.8;
|
||||
falling.m_20334_(motionDir.f_82479_ * powerMul + (random.m_188500_() - 0.5) * 0.4, motionDir.f_82480_ * powerMul + 0.5 + random.m_188500_() * 0.4, motionDir.f_82481_ * powerMul + (random.m_188500_() - 0.5) * 0.4);
|
||||
}
|
||||
}
|
||||
for (BlockPos posToDestroy : blocksToDestroy) {
|
||||
level.m_7731_(posToDestroy, Blocks.f_50016_.m_49966_(), 3);
|
||||
}
|
||||
public static void applySmallExplosionLogic(ServerLevel level, Vec3 explosionPos, float power) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,122 +1,17 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
package com.vinlanx.explosionoverhaul;
|
||||
|
||||
import com.vinlanx.explosionoverhaul.BlockIndexManager;
|
||||
import com.vinlanx.explosionoverhaul.Config;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.entity.item.FallingBlockEntity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.PointedDripstoneBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
|
||||
public class DripstoneEffects {
|
||||
private static final Queue<DripstoneFallTask> dripstoneQueue = new ConcurrentLinkedQueue<DripstoneFallTask>();
|
||||
private static final int MAX_DRIPSTONE_TASKS_PER_LEVEL_PER_TICK = 25;
|
||||
public static void handleDripstoneFall(ServerLevel level, BlockPos center, int explosionPower, RandomSource random) {
|
||||
}
|
||||
|
||||
public static void onServerTick(ServerLevel level) {
|
||||
DripstoneFallTask task;
|
||||
long currentTick = level.m_7654_().m_129921_();
|
||||
int processedTasks = 0;
|
||||
while (processedTasks < 25 && (task = dripstoneQueue.peek()) != null) {
|
||||
Comparable thicknessVal;
|
||||
if (task.level != level) {
|
||||
dripstoneQueue.poll();
|
||||
dripstoneQueue.add(task);
|
||||
++processedTasks;
|
||||
continue;
|
||||
}
|
||||
if (task.triggerTick > currentTick) break;
|
||||
dripstoneQueue.poll();
|
||||
++processedTasks;
|
||||
BlockState state = level.m_8055_(task.pos);
|
||||
if (!state.m_60713_(Blocks.f_152588_) || !state.m_61138_((Property)PointedDripstoneBlock.f_154010_) || (thicknessVal = state.m_61143_((Property)PointedDripstoneBlock.f_154010_)) == null || !"tip".equalsIgnoreCase(String.valueOf(thicknessVal))) continue;
|
||||
FallingBlockEntity falling = FallingBlockEntity.m_201971_((Level)level, (BlockPos)task.pos, (BlockState)state);
|
||||
if (falling != null) {
|
||||
// empty if block
|
||||
}
|
||||
level.m_7731_(task.pos, Blocks.f_50016_.m_49966_(), 2);
|
||||
}
|
||||
}
|
||||
|
||||
public static void handleDripstoneFall(ServerLevel level, BlockPos center, int explosionPower, RandomSource random) {
|
||||
int radius = (Integer)Config.COMMON.dripstoneFallingSearchRadius.get();
|
||||
List<BlockPos> dripstones = BlockIndexManager.getNearby(level, center, radius, BlockIndexManager.BlockType.DRIPSTONE);
|
||||
if (dripstones.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
int sampleLimit = 8;
|
||||
boolean anyPresent = false;
|
||||
for (int i = 0; i < Math.min(sampleLimit, dripstones.size()); ++i) {
|
||||
BlockState s;
|
||||
BlockPos p = dripstones.get(i);
|
||||
if (!level.m_46749_(p) || !(s = level.m_8055_(p)).m_60713_(Blocks.f_152588_)) continue;
|
||||
anyPresent = true;
|
||||
break;
|
||||
}
|
||||
if (!anyPresent) {
|
||||
return;
|
||||
}
|
||||
int percent = DripstoneEffects.getFallPercent(explosionPower);
|
||||
int toFall = dripstones.size() * percent / 100;
|
||||
int maxFall = 200;
|
||||
Collections.shuffle(dripstones, new Random(random.m_188505_()));
|
||||
List<BlockPos> selected = dripstones.subList(0, Math.min(Math.min(toFall, dripstones.size()), maxFall));
|
||||
long currentTick = level.m_7654_().m_129921_();
|
||||
for (BlockPos pos : selected) {
|
||||
int delayTicks = 5 + random.m_188503_(16);
|
||||
dripstoneQueue.add(new DripstoneFallTask(level, pos, currentTick + (long)delayTicks));
|
||||
}
|
||||
}
|
||||
|
||||
private static int getFallPercent(int power) {
|
||||
if (power < 10) {
|
||||
return 0;
|
||||
}
|
||||
if (power < 20) {
|
||||
return 40;
|
||||
}
|
||||
if (power < 30) {
|
||||
return 50;
|
||||
}
|
||||
if (power < 40) {
|
||||
return 60;
|
||||
}
|
||||
if (power < 50) {
|
||||
return 70;
|
||||
}
|
||||
if (power < 60) {
|
||||
return 80;
|
||||
}
|
||||
if (power < 70) {
|
||||
return 90;
|
||||
}
|
||||
return 100;
|
||||
}
|
||||
|
||||
private static List<BlockPos> findDripstones(ServerLevel level, BlockPos center, int radius) {
|
||||
return BlockIndexManager.getNearby(level, center, radius, BlockIndexManager.BlockType.DRIPSTONE);
|
||||
}
|
||||
|
||||
private static class DripstoneFallTask {
|
||||
public final ServerLevel level;
|
||||
public final BlockPos pos;
|
||||
public final long triggerTick;
|
||||
|
||||
public DripstoneFallTask(ServerLevel level, BlockPos pos, long triggerTick) {
|
||||
this.level = level;
|
||||
this.pos = pos;
|
||||
this.triggerTick = triggerTick;
|
||||
}
|
||||
public static int getFallPercent(int explosionPower) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,137 +1,10 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
package com.vinlanx.explosionoverhaul;
|
||||
|
||||
import com.vinlanx.explosionoverhaul.Config;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Position;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.item.PrimedTnt;
|
||||
import net.minecraft.world.entity.monster.Creeper;
|
||||
import net.minecraft.world.entity.vehicle.AbstractMinecart;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class ExplosionClusterHandler {
|
||||
public static float calculateClusteredPower(Level level, Vec3 explosionPos, float initialPower) {
|
||||
if (!((Boolean)Config.COMMON.enableExplosionClustering.get()).booleanValue()) {
|
||||
return initialPower;
|
||||
}
|
||||
double searchRadius = ExplosionClusterHandler.getSearchRadius(initialPower);
|
||||
AABB searchBox = new AABB(explosionPos.f_82479_ - searchRadius, explosionPos.f_82480_ - searchRadius, explosionPos.f_82481_ - searchRadius, explosionPos.f_82479_ + searchRadius, explosionPos.f_82480_ + searchRadius, explosionPos.f_82481_ + searchRadius);
|
||||
List tntEntities = level.m_45976_(PrimedTnt.class, searchBox);
|
||||
List creepers = level.m_45976_(Creeper.class, searchBox);
|
||||
List minecarts = level.m_45976_(AbstractMinecart.class, searchBox);
|
||||
ArrayList<BlockPos> tntBlocks = new ArrayList<BlockPos>();
|
||||
BlockPos centerPos = BlockPos.m_274446_((Position)explosionPos);
|
||||
int radiusBlocks = (int)Math.ceil(searchRadius);
|
||||
for (int x = -radiusBlocks; x <= radiusBlocks; ++x) {
|
||||
for (int y = -radiusBlocks; y <= radiusBlocks; ++y) {
|
||||
for (int z = -radiusBlocks; z <= radiusBlocks; ++z) {
|
||||
BlockPos pos = centerPos.m_7918_(x, y, z);
|
||||
BlockState state = level.m_8055_(pos);
|
||||
if (state.m_60734_() != Blocks.f_50077_) continue;
|
||||
tntBlocks.add(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean hasTntMinecart = minecarts.stream().anyMatch(c -> c.m_6095_() == EntityType.f_20475_);
|
||||
if (tntEntities.isEmpty() && tntBlocks.isEmpty() && creepers.isEmpty() && !hasTntMinecart) {
|
||||
return initialPower;
|
||||
}
|
||||
ArrayList<ExplosionSource> sources = new ArrayList<ExplosionSource>();
|
||||
sources.add(new ExplosionSource(explosionPos, initialPower));
|
||||
for (PrimedTnt tnt : tntEntities) {
|
||||
if (tnt.m_20182_().equals((Object)explosionPos)) continue;
|
||||
sources.add(new ExplosionSource(tnt.m_20182_(), 4.0f));
|
||||
}
|
||||
for (Creeper creeper : creepers) {
|
||||
if (creeper.m_20182_().equals((Object)explosionPos)) continue;
|
||||
sources.add(new ExplosionSource(creeper.m_20182_(), 3.0f));
|
||||
}
|
||||
for (AbstractMinecart cart : minecarts) {
|
||||
if (cart.m_6095_() != EntityType.f_20475_ || cart.m_20182_().equals((Object)explosionPos)) continue;
|
||||
sources.add(new ExplosionSource(cart.m_20182_(), 4.0f));
|
||||
}
|
||||
for (BlockPos pos : tntBlocks) {
|
||||
Vec3 blockPos = Vec3.m_82512_((Vec3i)pos);
|
||||
if (blockPos.equals((Object)explosionPos)) continue;
|
||||
sources.add(new ExplosionSource(blockPos, 4.0f));
|
||||
}
|
||||
ExplosionSource mainSource = sources.stream().max((a, b) -> Float.compare(a.power, b.power)).orElse((ExplosionSource)sources.get(0));
|
||||
float totalPower = mainSource.power;
|
||||
for (ExplosionSource source : sources) {
|
||||
if (source == mainSource) continue;
|
||||
float addition = ExplosionClusterHandler.getPowerAddition(source.power);
|
||||
totalPower += addition;
|
||||
}
|
||||
for (PrimedTnt tnt : tntEntities) {
|
||||
if (tnt.m_20182_().equals((Object)explosionPos)) continue;
|
||||
tnt.m_146870_();
|
||||
}
|
||||
for (Creeper creeper : creepers) {
|
||||
if (creeper.m_20182_().equals((Object)explosionPos)) continue;
|
||||
creeper.m_146870_();
|
||||
}
|
||||
for (AbstractMinecart cart : minecarts) {
|
||||
if (cart.m_6095_() != EntityType.f_20475_ || cart.m_20182_().equals((Object)explosionPos)) continue;
|
||||
cart.m_146870_();
|
||||
}
|
||||
for (BlockPos pos : tntBlocks) {
|
||||
Vec3 blockPos = Vec3.m_82512_((Vec3i)pos);
|
||||
if (blockPos.equals((Object)explosionPos)) continue;
|
||||
level.m_7731_(pos, Blocks.f_50016_.m_49966_(), 3);
|
||||
}
|
||||
float maxPower = ((Integer)Config.COMMON.maxClusterPower.get()).floatValue();
|
||||
return Math.min(totalPower, maxPower);
|
||||
}
|
||||
|
||||
private static double getSearchRadius(float power) {
|
||||
if (power <= 4.0f) {
|
||||
return 3.0;
|
||||
}
|
||||
if (power <= 10.0f) {
|
||||
return 5.0;
|
||||
}
|
||||
if (power <= 25.0f) {
|
||||
return 10.0;
|
||||
}
|
||||
if (power <= 35.0f) {
|
||||
return 14.0;
|
||||
}
|
||||
return 20.0;
|
||||
}
|
||||
|
||||
private static float getPowerAddition(float power) {
|
||||
if (power <= 4.0f) {
|
||||
return 2.0f;
|
||||
}
|
||||
if (power <= 10.0f) {
|
||||
return 5.0f;
|
||||
}
|
||||
if (power <= 25.0f) {
|
||||
return 10.0f;
|
||||
}
|
||||
if (power <= 35.0f) {
|
||||
return 15.0f;
|
||||
}
|
||||
return 15.0f;
|
||||
}
|
||||
|
||||
private static class ExplosionSource {
|
||||
Vec3 position;
|
||||
float power;
|
||||
|
||||
ExplosionSource(Vec3 position, float power) {
|
||||
this.position = position;
|
||||
this.power = power;
|
||||
}
|
||||
public static float calculateClusteredPower(Level level, Vec3 pos, float initialPower) {
|
||||
return initialPower;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,230 +1,37 @@
|
||||
/*
|
||||
* 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.Random;
|
||||
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) {
|
||||
public static double calculateRadius(float power) {
|
||||
return Math.max(1.0, power);
|
||||
}
|
||||
|
||||
private static class DelayedGlassEffect {
|
||||
private final ServerLevel level;
|
||||
private final BlockPos glassPos;
|
||||
private final BlockState glassState;
|
||||
private long delayCycles;
|
||||
public static float calculateRadiusMultiplier(float power) {
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
public DelayedGlassEffect(ServerLevel level, BlockPos glassPos, long delayCycles) {
|
||||
this.level = level;
|
||||
this.glassPos = glassPos;
|
||||
this.glassState = level.m_8055_(glassPos);
|
||||
this.delayCycles = delayCycles;
|
||||
}
|
||||
public static boolean isGlass(BlockState state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
public static Set<BlockPos> findConnectedGlass(ServerLevel level, BlockPos pos, Set<BlockPos> processed) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
public static boolean shouldBreak(ServerLevel level, Vec3 explosionPos, BlockPos pos, float power, Random random, double radius) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,13 +44,13 @@ public class OpenALTogglePacket {
|
||||
DeafnessConcussionEffect.enabled = packet.enabled;
|
||||
DeafnessConcussionEffect.debugShowChat = packet.enabled;
|
||||
if (DeafnessConcussionEffect.debugShowChat) {
|
||||
Minecraft.getInstance().player.m_5661_((Component)Component.literal((String)("Deafness effect set to " + (packet.enabled ? "ON" : "OFF"))), false);
|
||||
Minecraft.getInstance().player.displayClientMessage((Component)Component.literal((String)("Deafness effect set to " + (packet.enabled ? "ON" : "OFF"))), false);
|
||||
}
|
||||
} else if (t.equals("lowpass") || t.equals("low_pass")) {
|
||||
LowPassConcussionEffect.enabled = packet.enabled;
|
||||
LowPassConcussionEffect.debugShowChat = packet.enabled;
|
||||
if (LowPassConcussionEffect.debugShowChat) {
|
||||
Minecraft.getInstance().player.m_5661_((Component)Component.literal((String)("LowPass effect set to " + (packet.enabled ? "ON" : "OFF"))), false);
|
||||
Minecraft.getInstance().player.displayClientMessage((Component)Component.literal((String)("LowPass effect set to " + (packet.enabled ? "ON" : "OFF"))), false);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -1,394 +1,12 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
package com.vinlanx.explosionoverhaul;
|
||||
|
||||
import com.vinlanx.explosionoverhaul.BlockIndexManager;
|
||||
import com.vinlanx.explosionoverhaul.Config;
|
||||
import com.vinlanx.explosionoverhaul.ModSounds;
|
||||
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.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
|
||||
public class RedstoneLampEffects {
|
||||
private static final Map<UUID, List<DelayedLampEffect>> perPlayerDelayedLampEffects = new ConcurrentHashMap<UUID, List<DelayedLampEffect>>();
|
||||
private static final int MIN_INITIAL_FLICKERS = 2;
|
||||
private static final int MAX_INITIAL_FLICKERS = 5;
|
||||
private static final int MIN_FLICKER_PHASE_TICKS = 1;
|
||||
private static final int MAX_FLICKER_PHASE_TICKS = 4;
|
||||
private static final int BASE_MIN_LONG_OFF_TICKS = 20;
|
||||
private static final int FINAL_FLICKER_COUNT = 4;
|
||||
private static final int LAMP_UPDATE_BATCH_SIZE_PER_EFFECT = 25;
|
||||
private static final int LAMP_UPDATE_BUDGET_PER_PLAYER_PER_TICK = 200;
|
||||
private static final int MAX_CONCURRENT_LAMP_GROUPS_PER_PLAYER = 250;
|
||||
|
||||
/*
|
||||
* WARNING - Removed try catching itself - possible behaviour change.
|
||||
*/
|
||||
public static void triggerLampFlicker(ServerLevel level, ServerPlayer player, float explosionPower, long initialDelayTicks, double distanceToExplosionOrigin) {
|
||||
List playerSpecificEffects;
|
||||
if (!((Boolean)Config.COMMON.enableLampFlicker.get()).booleanValue()) {
|
||||
return;
|
||||
}
|
||||
RandomSource random = level.m_213780_();
|
||||
BlockPos playerPos = player.m_20183_();
|
||||
UUID playerId = player.m_20148_();
|
||||
int lampEffectRadius = (Integer)Config.COMMON.lampFlickerSearchRadius.get();
|
||||
long currentMinLongOffTicks = 20L;
|
||||
long currentMaxLongOffTicks = distanceToExplosionOrigin < 500.0 ? 200L : (distanceToExplosionOrigin < 1000.0 ? 100L : 60L);
|
||||
if (currentMinLongOffTicks > currentMaxLongOffTicks) {
|
||||
currentMinLongOffTicks = Math.max(1L, currentMaxLongOffTicks / 2L);
|
||||
}
|
||||
if (currentMaxLongOffTicks <= 0L) {
|
||||
currentMaxLongOffTicks = 1L;
|
||||
}
|
||||
long sharedLongOffDuration = currentMaxLongOffTicks <= currentMinLongOffTicks ? currentMinLongOffTicks : currentMinLongOffTicks + (long)random.m_188503_((int)(currentMaxLongOffTicks - currentMinLongOffTicks + 1L));
|
||||
ArrayList<PotentialLampGroup> potentialLampGroupsFoundThisExplosion = new ArrayList<PotentialLampGroup>();
|
||||
List<BlockPos> allCandidates = BlockIndexManager.getNearby(level, playerPos, lampEffectRadius, BlockIndexManager.BlockType.LAMP);
|
||||
if (allCandidates.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ArrayList<BlockPos> litLampCandidates = new ArrayList<BlockPos>();
|
||||
for (BlockPos pos : allCandidates) {
|
||||
Object state;
|
||||
if (!level.m_46749_(pos) || !(state = level.m_8055_(pos)).m_60713_(Blocks.f_50261_) || !((Boolean)state.m_61143_((Property)BlockStateProperties.f_61443_)).booleanValue()) continue;
|
||||
litLampCandidates.add(pos);
|
||||
}
|
||||
if (litLampCandidates.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
HashSet<BlockPos> lampsAlreadyInAGroup = new HashSet<BlockPos>();
|
||||
HashSet candidateSet = new HashSet(litLampCandidates);
|
||||
for (BlockPos startPos : litLampCandidates) {
|
||||
BlockState startState;
|
||||
if (lampsAlreadyInAGroup.contains(startPos) || !level.m_46749_(startPos) || !(startState = level.m_8055_(startPos)).m_60713_(Blocks.f_50261_)) continue;
|
||||
ArrayList<BlockPos> currentLampGroupPositions = new ArrayList<BlockPos>();
|
||||
LinkedList<BlockPos> toProcess = new LinkedList<BlockPos>();
|
||||
toProcess.add(startPos);
|
||||
lampsAlreadyInAGroup.add(startPos);
|
||||
while (!toProcess.isEmpty()) {
|
||||
BlockPos lampInQueue = (BlockPos)toProcess.poll();
|
||||
currentLampGroupPositions.add(lampInQueue);
|
||||
for (Direction direction : Direction.values()) {
|
||||
BlockState neighborState;
|
||||
BlockPos neighborPos = lampInQueue.m_5484_(direction, 1);
|
||||
if (!candidateSet.contains(neighborPos) || lampsAlreadyInAGroup.contains(neighborPos) || !level.m_46749_(neighborPos) || !(neighborState = level.m_8055_(neighborPos)).m_60713_(Blocks.f_50261_) || !((Boolean)neighborState.m_61143_((Property)BlockStateProperties.f_61443_)).booleanValue()) continue;
|
||||
lampsAlreadyInAGroup.add(neighborPos);
|
||||
toProcess.add(neighborPos);
|
||||
}
|
||||
}
|
||||
if (currentLampGroupPositions.isEmpty()) continue;
|
||||
double distanceSq = startPos.m_123331_((Vec3i)playerPos);
|
||||
long lampSpecificInitialDelay = initialDelayTicks + (long)random.m_188503_(10);
|
||||
potentialLampGroupsFoundThisExplosion.add(new PotentialLampGroup(startPos, currentLampGroupPositions, true, sharedLongOffDuration, distanceSq, lampSpecificInitialDelay));
|
||||
}
|
||||
if (potentialLampGroupsFoundThisExplosion.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
potentialLampGroupsFoundThisExplosion.sort(Comparator.comparingDouble(PotentialLampGroup::distanceSqToPlayer));
|
||||
List list = playerSpecificEffects = perPlayerDelayedLampEffects.computeIfAbsent(playerId, k -> Collections.synchronizedList(new ArrayList()));
|
||||
synchronized (list) {
|
||||
int currentEffectCountForPlayer = playerSpecificEffects.size();
|
||||
int availableSlotsForThisPlayer = 250 - currentEffectCountForPlayer;
|
||||
if (availableSlotsForThisPlayer <= 0) {
|
||||
return;
|
||||
}
|
||||
int numToAdd = Math.min(potentialLampGroupsFoundThisExplosion.size(), availableSlotsForThisPlayer);
|
||||
for (int i = 0; i < numToAdd; ++i) {
|
||||
PotentialLampGroup chosenGroup = (PotentialLampGroup)potentialLampGroupsFoundThisExplosion.get(i);
|
||||
playerSpecificEffects.add(new DelayedLampEffect(level, chosenGroup.representativePos(), chosenGroup.groupPositions(), chosenGroup.initialDelay(), chosenGroup.originallyLit(), chosenGroup.predeterminedLongOffDuration(), random));
|
||||
}
|
||||
}
|
||||
public static void triggerLampFlicker(ServerLevel level, ServerPlayer player, float power, long delayTicks, double distance) {
|
||||
}
|
||||
|
||||
/*
|
||||
* WARNING - Removed try catching itself - possible behaviour change.
|
||||
*/
|
||||
public static void onServerTick() {
|
||||
for (Map.Entry<UUID, List<DelayedLampEffect>> entry : perPlayerDelayedLampEffects.entrySet()) {
|
||||
List<DelayedLampEffect> playerEffects = entry.getValue();
|
||||
int[] playerBudget = new int[]{200};
|
||||
List<DelayedLampEffect> list = playerEffects;
|
||||
synchronized (list) {
|
||||
Iterator<DelayedLampEffect> effectIterator = playerEffects.iterator();
|
||||
while (effectIterator.hasNext() && playerBudget[0] > 0) {
|
||||
DelayedLampEffect effect = effectIterator.next();
|
||||
if (!effect.tick(playerBudget)) continue;
|
||||
effectIterator.remove();
|
||||
}
|
||||
}
|
||||
if (!playerEffects.isEmpty()) continue;
|
||||
perPlayerDelayedLampEffects.remove(entry.getKey(), playerEffects);
|
||||
}
|
||||
}
|
||||
|
||||
private record PotentialLampGroup(BlockPos representativePos, List<BlockPos> groupPositions, boolean originallyLit, long predeterminedLongOffDuration, double distanceSqToPlayer, long initialDelay) {
|
||||
}
|
||||
|
||||
private static class DelayedLampEffect {
|
||||
public ServerLevel level;
|
||||
public BlockPos representativeLampPos;
|
||||
public List<BlockPos> groupLampPositions;
|
||||
public boolean originallyLit;
|
||||
private final RandomSource random;
|
||||
private LampEffectStage currentStage;
|
||||
private long ticksUntilNextStageAction;
|
||||
private int flickersRemainingInCycle;
|
||||
private long actualLongOffDuration;
|
||||
private int lampUpdateProgressIndex = 0;
|
||||
private boolean currentPhaseTargetLitState;
|
||||
|
||||
public DelayedLampEffect(ServerLevel level, BlockPos representativeLampPos, List<BlockPos> allGroupPositions, long initialDelayTicks, boolean lit, long predeterminedLongOffDuration, RandomSource randomSource) {
|
||||
this.level = level;
|
||||
this.representativeLampPos = representativeLampPos;
|
||||
this.groupLampPositions = new ArrayList<BlockPos>(allGroupPositions);
|
||||
this.originallyLit = lit;
|
||||
this.actualLongOffDuration = predeterminedLongOffDuration;
|
||||
this.random = randomSource;
|
||||
this.currentStage = LampEffectStage.AWAITING_INITIAL_DELAY;
|
||||
this.ticksUntilNextStageAction = initialDelayTicks;
|
||||
}
|
||||
|
||||
private void playFlickerSound() {
|
||||
if (!ModSounds.LAMP_FLICKER_SOUNDS.isEmpty() && !this.groupLampPositions.isEmpty()) {
|
||||
SoundEvent flickerSound = (SoundEvent)ModSounds.LAMP_FLICKER_SOUNDS.get(this.random.m_188503_(ModSounds.LAMP_FLICKER_SOUNDS.size())).get();
|
||||
this.level.m_5594_(null, this.representativeLampPos, flickerSound, SoundSource.BLOCKS, 0.5f, 1.0f + (this.random.m_188501_() - 0.5f) * 0.3f);
|
||||
}
|
||||
}
|
||||
|
||||
private int getRandomPhaseDuration(int minTicks, int maxTicks) {
|
||||
if (minTicks >= maxTicks) {
|
||||
return minTicks;
|
||||
}
|
||||
return this.random.m_188503_(maxTicks - minTicks + 1) + minTicks;
|
||||
}
|
||||
|
||||
private boolean processLampUpdateBatch(int[] budget) {
|
||||
if (this.groupLampPositions.isEmpty()) {
|
||||
this.lampUpdateProgressIndex = 0;
|
||||
return true;
|
||||
}
|
||||
for (int processedInThisEffectCall = 0; this.lampUpdateProgressIndex < this.groupLampPositions.size() && processedInThisEffectCall < 25 && budget[0] > 0; ++processedInThisEffectCall) {
|
||||
boolean currentlyLit;
|
||||
BlockPos posInGroup = this.groupLampPositions.get(this.lampUpdateProgressIndex);
|
||||
BlockState currentBlockState = this.level.m_8055_(posInGroup);
|
||||
if (currentBlockState.m_60713_(Blocks.f_50261_) && (currentlyLit = ((Boolean)currentBlockState.m_61143_((Property)BlockStateProperties.f_61443_)).booleanValue()) != this.currentPhaseTargetLitState) {
|
||||
this.level.m_7731_(posInGroup, (BlockState)currentBlockState.m_61124_((Property)BlockStateProperties.f_61443_, (Comparable)Boolean.valueOf(this.currentPhaseTargetLitState)), 2);
|
||||
budget[0] = budget[0] - 1;
|
||||
}
|
||||
++this.lampUpdateProgressIndex;
|
||||
}
|
||||
if (this.lampUpdateProgressIndex >= this.groupLampPositions.size()) {
|
||||
this.lampUpdateProgressIndex = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean tick(int[] budget) {
|
||||
if (this.currentStage == LampEffectStage.FINISHED) {
|
||||
return true;
|
||||
}
|
||||
--this.ticksUntilNextStageAction;
|
||||
if (this.ticksUntilNextStageAction <= 0L) {
|
||||
LampEffectStage nextStageDecision = this.currentStage;
|
||||
boolean phaseUpdateCompleted = false;
|
||||
switch (this.currentStage) {
|
||||
case AWAITING_INITIAL_DELAY: {
|
||||
this.flickersRemainingInCycle = 2 + this.random.m_188503_(4);
|
||||
nextStageDecision = LampEffectStage.INITIAL_FLICKER_PREPARE_OFF;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case INITIAL_FLICKER_PREPARE_OFF: {
|
||||
this.currentPhaseTargetLitState = false;
|
||||
this.lampUpdateProgressIndex = 0;
|
||||
this.playFlickerSound();
|
||||
nextStageDecision = LampEffectStage.INITIAL_FLICKER_UPDATING_TO_OFF;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case INITIAL_FLICKER_UPDATING_TO_OFF: {
|
||||
phaseUpdateCompleted = this.processLampUpdateBatch(budget);
|
||||
if (phaseUpdateCompleted) {
|
||||
nextStageDecision = LampEffectStage.INITIAL_FLICKER_WAITING_OFF;
|
||||
this.ticksUntilNextStageAction = this.getRandomPhaseDuration(1, 4);
|
||||
break;
|
||||
}
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case INITIAL_FLICKER_WAITING_OFF: {
|
||||
nextStageDecision = LampEffectStage.INITIAL_FLICKER_PREPARE_ON;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case INITIAL_FLICKER_PREPARE_ON: {
|
||||
this.currentPhaseTargetLitState = true;
|
||||
this.lampUpdateProgressIndex = 0;
|
||||
this.playFlickerSound();
|
||||
nextStageDecision = LampEffectStage.INITIAL_FLICKER_UPDATING_TO_ON;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case INITIAL_FLICKER_UPDATING_TO_ON: {
|
||||
phaseUpdateCompleted = this.processLampUpdateBatch(budget);
|
||||
if (phaseUpdateCompleted) {
|
||||
--this.flickersRemainingInCycle;
|
||||
if (this.flickersRemainingInCycle > 0) {
|
||||
nextStageDecision = LampEffectStage.INITIAL_FLICKER_WAITING_ON;
|
||||
this.ticksUntilNextStageAction = this.getRandomPhaseDuration(1, 4);
|
||||
break;
|
||||
}
|
||||
nextStageDecision = LampEffectStage.LONG_OFF_PREPARE;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case INITIAL_FLICKER_WAITING_ON: {
|
||||
nextStageDecision = LampEffectStage.INITIAL_FLICKER_PREPARE_OFF;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case LONG_OFF_PREPARE: {
|
||||
this.currentPhaseTargetLitState = false;
|
||||
this.lampUpdateProgressIndex = 0;
|
||||
nextStageDecision = LampEffectStage.LONG_OFF_UPDATING_TO_OFF;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case LONG_OFF_UPDATING_TO_OFF: {
|
||||
phaseUpdateCompleted = this.processLampUpdateBatch(budget);
|
||||
if (phaseUpdateCompleted) {
|
||||
nextStageDecision = LampEffectStage.LONG_OFF_WAITING;
|
||||
this.ticksUntilNextStageAction = this.actualLongOffDuration;
|
||||
break;
|
||||
}
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case LONG_OFF_WAITING: {
|
||||
this.flickersRemainingInCycle = 4;
|
||||
nextStageDecision = LampEffectStage.FINAL_FLICKER_PREPARE_ON;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case FINAL_FLICKER_PREPARE_ON: {
|
||||
this.currentPhaseTargetLitState = true;
|
||||
this.lampUpdateProgressIndex = 0;
|
||||
this.playFlickerSound();
|
||||
nextStageDecision = LampEffectStage.FINAL_FLICKER_UPDATING_TO_ON;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case FINAL_FLICKER_UPDATING_TO_ON: {
|
||||
phaseUpdateCompleted = this.processLampUpdateBatch(budget);
|
||||
if (phaseUpdateCompleted) {
|
||||
nextStageDecision = LampEffectStage.FINAL_FLICKER_WAITING_ON;
|
||||
this.ticksUntilNextStageAction = this.getRandomPhaseDuration(1, 4);
|
||||
break;
|
||||
}
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case FINAL_FLICKER_WAITING_ON: {
|
||||
nextStageDecision = LampEffectStage.FINAL_FLICKER_PREPARE_OFF;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case FINAL_FLICKER_PREPARE_OFF: {
|
||||
this.currentPhaseTargetLitState = false;
|
||||
this.lampUpdateProgressIndex = 0;
|
||||
this.playFlickerSound();
|
||||
nextStageDecision = LampEffectStage.FINAL_FLICKER_UPDATING_TO_OFF;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case FINAL_FLICKER_UPDATING_TO_OFF: {
|
||||
phaseUpdateCompleted = this.processLampUpdateBatch(budget);
|
||||
if (phaseUpdateCompleted) {
|
||||
--this.flickersRemainingInCycle;
|
||||
if (this.flickersRemainingInCycle > 0) {
|
||||
nextStageDecision = LampEffectStage.FINAL_FLICKER_WAITING_OFF;
|
||||
this.ticksUntilNextStageAction = this.getRandomPhaseDuration(1, 4);
|
||||
break;
|
||||
}
|
||||
nextStageDecision = LampEffectStage.RESTORING_PREPARE;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case FINAL_FLICKER_WAITING_OFF: {
|
||||
nextStageDecision = LampEffectStage.FINAL_FLICKER_PREPARE_ON;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case RESTORING_PREPARE: {
|
||||
this.currentPhaseTargetLitState = this.originallyLit;
|
||||
this.lampUpdateProgressIndex = 0;
|
||||
nextStageDecision = LampEffectStage.RESTORING_UPDATING_TO_ORIGINAL;
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
case RESTORING_UPDATING_TO_ORIGINAL: {
|
||||
phaseUpdateCompleted = this.processLampUpdateBatch(budget);
|
||||
if (phaseUpdateCompleted) {
|
||||
nextStageDecision = LampEffectStage.FINISHED;
|
||||
break;
|
||||
}
|
||||
this.ticksUntilNextStageAction = 1L;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.currentStage = nextStageDecision;
|
||||
}
|
||||
return this.currentStage == LampEffectStage.FINISHED;
|
||||
}
|
||||
}
|
||||
|
||||
private static enum LampEffectStage {
|
||||
AWAITING_INITIAL_DELAY,
|
||||
INITIAL_FLICKER_PREPARE_OFF,
|
||||
INITIAL_FLICKER_UPDATING_TO_OFF,
|
||||
INITIAL_FLICKER_WAITING_OFF,
|
||||
INITIAL_FLICKER_PREPARE_ON,
|
||||
INITIAL_FLICKER_UPDATING_TO_ON,
|
||||
INITIAL_FLICKER_WAITING_ON,
|
||||
LONG_OFF_PREPARE,
|
||||
LONG_OFF_UPDATING_TO_OFF,
|
||||
LONG_OFF_WAITING,
|
||||
FINAL_FLICKER_PREPARE_ON,
|
||||
FINAL_FLICKER_UPDATING_TO_ON,
|
||||
FINAL_FLICKER_WAITING_ON,
|
||||
FINAL_FLICKER_PREPARE_OFF,
|
||||
FINAL_FLICKER_UPDATING_TO_OFF,
|
||||
FINAL_FLICKER_WAITING_OFF,
|
||||
RESTORING_PREPARE,
|
||||
RESTORING_UPDATING_TO_ORIGINAL,
|
||||
FINISHED;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class ScanInfoHUD {
|
||||
if (mc.player == null) {
|
||||
return;
|
||||
}
|
||||
if (!mc.player.m_20310_(2) && !mc.hasSingleplayerServer()) {
|
||||
if (false) {
|
||||
return;
|
||||
}
|
||||
GuiGraphics guiGraphics = event.getGuiGraphics();
|
||||
|
||||
@@ -28,7 +28,7 @@ public class ScanKeyHandler {
|
||||
if (mc.player == null || mc.screen != null) {
|
||||
return;
|
||||
}
|
||||
if (!mc.player.m_20310_(2) && !mc.hasSingleplayerServer()) {
|
||||
if (false) {
|
||||
return;
|
||||
}
|
||||
if (event.getAction() != 1) {
|
||||
|
||||
@@ -33,7 +33,7 @@ public class ScanLoadInfoHUD {
|
||||
if (mc.player == null) {
|
||||
return;
|
||||
}
|
||||
if (!mc.player.m_20310_(2) && !mc.hasSingleplayerServer()) {
|
||||
if (false) {
|
||||
return;
|
||||
}
|
||||
GuiGraphics guiGraphics = event.getGuiGraphics();
|
||||
|
||||
@@ -37,7 +37,7 @@ public class ScanLoadPromptHUD {
|
||||
if (mc.player == null) {
|
||||
return;
|
||||
}
|
||||
if (!mc.player.m_20310_(2) && !mc.hasSingleplayerServer()) {
|
||||
if (false) {
|
||||
return;
|
||||
}
|
||||
GuiGraphics guiGraphics = event.getGuiGraphics();
|
||||
|
||||
@@ -120,7 +120,7 @@ public class ScanProgressHUD {
|
||||
if (mc.player == null) {
|
||||
return;
|
||||
}
|
||||
if (!mc.player.m_20310_(2) && !mc.hasSingleplayerServer()) {
|
||||
if (false) {
|
||||
return;
|
||||
}
|
||||
if (isComplete && System.currentTimeMillis() > hideTime) {
|
||||
|
||||
@@ -38,7 +38,7 @@ public class ScanPromptHUD {
|
||||
if (mc.player == null) {
|
||||
return;
|
||||
}
|
||||
if (!mc.player.m_20310_(2) && !mc.hasSingleplayerServer()) {
|
||||
if (false) {
|
||||
return;
|
||||
}
|
||||
GuiGraphics guiGraphics = event.getGuiGraphics();
|
||||
|
||||
@@ -14,4 +14,7 @@ public class ServerExplosionHandler {
|
||||
|
||||
public static void register() {
|
||||
}
|
||||
|
||||
public record CameraShakeProfile(float intensity, int durationTicks, float pushIntensity) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,9 @@ import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import software.bernie.geckolib.animatable.GeoBlockEntity;
|
||||
import software.bernie.geckolib.core.animatable.GeoAnimatable;
|
||||
import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache;
|
||||
import software.bernie.geckolib.core.animation.AnimatableManager;
|
||||
import software.bernie.geckolib.animatable.GeoAnimatable;
|
||||
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
|
||||
import software.bernie.geckolib.animation.AnimatableManager;
|
||||
import software.bernie.geckolib.util.GeckoLibUtil;
|
||||
|
||||
public class VinlanxTheLightBlockEntity
|
||||
|
||||
@@ -11,9 +11,9 @@ import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.neoforged.neoforge.client.extensions.common.IClientItemExtensions;
|
||||
import software.bernie.geckolib.animatable.GeoItem;
|
||||
import software.bernie.geckolib.core.animatable.GeoAnimatable;
|
||||
import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache;
|
||||
import software.bernie.geckolib.core.animation.AnimatableManager;
|
||||
import software.bernie.geckolib.animatable.GeoAnimatable;
|
||||
import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache;
|
||||
import software.bernie.geckolib.animation.AnimatableManager;
|
||||
import software.bernie.geckolib.util.GeckoLibUtil;
|
||||
|
||||
public class VinlanxTheLightItem
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package com.vinlanx.explosionoverhaul;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import software.bernie.geckolib.core.animatable.GeoAnimatable;
|
||||
import software.bernie.geckolib.animatable.GeoAnimatable;
|
||||
import software.bernie.geckolib.model.GeoModel;
|
||||
|
||||
public class VinlanxTheLightModel<T extends GeoAnimatable>
|
||||
|
||||
@@ -82,7 +82,7 @@ public class ConcussionAudioEffect {
|
||||
double metersToExplosion = distance;
|
||||
double onePercentDistance = maxDistance * 0.99;
|
||||
String outMessage = String.format("\u041f\u043e\u0437\u0430 \u0437\u043e\u043d\u043e\u044e \u043f\u043e\u0440\u0430\u0437\u043a\u0438. \u0412\u0456\u0434\u0441\u0442\u0430\u043d\u044c \u0434\u043e \u0432\u0438\u0431\u0443\u0445\u0443: %.1f \u043c. 1%% \u043f\u043e\u0447\u0438\u043d\u0430\u0454\u0442\u044c\u0441\u044f \u0437: %.1f \u043c.", metersToExplosion, onePercentDistance);
|
||||
player4.m_5661_((Component)Component.literal((String)outMessage).m_130940_(ChatFormatting.GRAY), false);
|
||||
player4.displayClientMessage((Component)Component.literal((String)outMessage).m_130940_(ChatFormatting.GRAY), false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -132,14 +132,14 @@ public class ConcussionAudioEffect {
|
||||
if (debugSendDebugMessage && (player5 = mc.player) != null) {
|
||||
String reductionInfo = lowpassReduced ? " [LowPass reduced /3]" : "";
|
||||
String blurMsg = String.format("Blur & Sway %.1f m \u2014 activated (Blur: %.2f, Sway: %.2f, Time: %ds%s)", distance, Float.valueOf(blurIntensity), Float.valueOf(swayIntensity), blurSeconds, reductionInfo);
|
||||
player5.m_5661_((Component)Component.literal((String)blurMsg).m_130940_(ChatFormatting.BLUE), false);
|
||||
player5.displayClientMessage((Component)Component.literal((String)blurMsg).m_130940_(ChatFormatting.BLUE), false);
|
||||
}
|
||||
}
|
||||
catch (Throwable player5) {}
|
||||
} else if (debugSendDebugMessage && (player3 = mc.player) != null) {
|
||||
String reason = !anyAudioEffectActive ? "no audio effects" : "out of range";
|
||||
String blurMsg = String.format("Blur %.1f m \u2014 not activated (%s)", distance, reason);
|
||||
player3.m_5661_((Component)Component.literal((String)blurMsg).m_130940_(ChatFormatting.GRAY), false);
|
||||
player3.displayClientMessage((Component)Component.literal((String)blurMsg).m_130940_(ChatFormatting.GRAY), false);
|
||||
}
|
||||
int lowpassSeconds = blurSeconds;
|
||||
double lowpassIntensityPercent = ConcussionAudioEffect.computeBaseLowpassIntensityPercent(effectivePercent);
|
||||
@@ -158,14 +158,14 @@ public class ConcussionAudioEffect {
|
||||
if (debugSendDebugMessage && (player6 = mc.player) != null) {
|
||||
String status = lowpassRoll ? "activated" : "refreshed";
|
||||
String lpMsg = String.format("Low pass %.1f m \u2014 %s (intensity=%.2f chance=%.1f%%)", distance, status, Float.valueOf(finalLpIntensity), lowpassChance * 100.0);
|
||||
player6.m_5661_((Component)Component.literal((String)lpMsg).m_130940_(ChatFormatting.DARK_GREEN), false);
|
||||
player6.displayClientMessage((Component)Component.literal((String)lpMsg).m_130940_(ChatFormatting.DARK_GREEN), false);
|
||||
}
|
||||
}
|
||||
catch (Throwable finalLpIntensity) {}
|
||||
} else if (debugSendDebugMessage && (player2 = mc.player) != null) {
|
||||
String reason = rawPercent <= 0.0 || lowpassIntensity < 0.01f ? "out of range" : "chance fail";
|
||||
String lpMsg = String.format("Low pass %.1f m \u2014 not activated (%s)", distance, reason);
|
||||
player2.m_5661_((Component)Component.literal((String)lpMsg).m_130940_(ChatFormatting.GRAY), false);
|
||||
player2.displayClientMessage((Component)Component.literal((String)lpMsg).m_130940_(ChatFormatting.GRAY), false);
|
||||
}
|
||||
if (debugSendDebugMessage) {
|
||||
ConcussionAudioEffect.sendDebugMessage(mc, effectivePercent, rawPercent, hasDirectLineOfSight, distance, maxDistance);
|
||||
@@ -174,23 +174,23 @@ public class ConcussionAudioEffect {
|
||||
Object visibility = hasDirectLineOfSight ? "\u043f\u0440\u044f\u043c\u0430 \u0432\u0438\u0434\u0438\u043c\u0456\u0441\u0442\u044c" : "\u043f\u0435\u0440\u0435\u0448\u043a\u043e\u0434\u0430";
|
||||
visibility = (String)visibility + (explosionInCave ? " | \u0432\u0438\u0431\u0443\u0445 \u0443 \u043f\u0435\u0447\u0435\u0440\u0456" : " | \u0432\u0438\u0431\u0443\u0445 \u043d\u0435 \u0432 \u043f\u0435\u0447\u0435\u0440\u0456");
|
||||
visibility = (String)visibility + String.format(" | \u0444\u0456\u043d\u0430\u043b\u044c\u043d\u0438\u0439 %%: %.1f%%", effectivePercent);
|
||||
player.m_5661_((Component)Component.literal((String)visibility).m_130940_(ChatFormatting.GRAY), false);
|
||||
player.displayClientMessage((Component)Component.literal((String)visibility).m_130940_(ChatFormatting.GRAY), false);
|
||||
String chanceMsg = String.format("\u0428\u0430\u043d\u0441 \u043a\u043e\u043d\u0442\u0443\u0437\u0456\u0457: %.1f%%", chance * 100.0);
|
||||
player.m_5661_((Component)Component.literal((String)chanceMsg).m_130940_(ChatFormatting.YELLOW), false);
|
||||
player.displayClientMessage((Component)Component.literal((String)chanceMsg).m_130940_(ChatFormatting.YELLOW), false);
|
||||
double maxDistanceNormal = ConcussionAudioEffect.computeMaxDistance(power, false);
|
||||
double maxDistanceUsed = ConcussionAudioEffect.computeMaxDistance(power, explosionInCave);
|
||||
String distMsg = String.format("\u041c\u0430\u043a\u0441 \u0434\u0438\u0441\u0442\u0430\u043d\u0446\u0456\u044f (\u0437\u0432\u0438\u0447\u0430\u0439\u043d\u0430): %.1f \u043c | (\u0432 \u043f\u0435\u0447\u0435\u0440\u0456): %.1f \u043c | \u0412\u0456\u0434\u0441\u0442\u0430\u043d\u044c \u0434\u043e \u0432\u0438\u0431\u0443\u0445\u0443: %.1f \u043c", maxDistanceNormal, maxDistanceUsed, distance);
|
||||
player.m_5661_((Component)Component.literal((String)distMsg).m_130940_(ChatFormatting.GRAY), false);
|
||||
player.displayClientMessage((Component)Component.literal((String)distMsg).m_130940_(ChatFormatting.GRAY), false);
|
||||
double baseSilentNormal = ConcussionAudioEffect.computeBaseSilentSeconds(effectivePercent, false);
|
||||
double baseSilentCave = ConcussionAudioEffect.computeBaseSilentSeconds(effectivePercent, true);
|
||||
String silentMsg = String.format("\u0427\u0430\u0441 \u0441\u043a\u0440\u0443\u0447\u0443\u0432\u0430\u043d\u043d\u044f (\u0437\u0432\u0438\u0447\u0430\u0439\u043d\u0438\u0439): %.1fs | (\u0432 \u043f\u0435\u0447\u0435\u0440\u0456): %.1fs | \u0412\u0418\u041a\u041e\u0420\u0418\u0421\u0422\u0410\u041d\u041e: %.1fs", baseSilentNormal, baseSilentCave, baseSilentSeconds * multiplier);
|
||||
player.m_5661_((Component)Component.literal((String)silentMsg).m_130940_(ChatFormatting.GRAY), false);
|
||||
player.displayClientMessage((Component)Component.literal((String)silentMsg).m_130940_(ChatFormatting.GRAY), false);
|
||||
if (roll) {
|
||||
String deafnessMsg = String.format("Deafness %.1f m \u2014 activated (intensity=%.1f%% chance=%.1f%%)", distance, intensityPercent, chance * 100.0);
|
||||
player.m_5661_((Component)Component.literal((String)deafnessMsg).m_130940_(ChatFormatting.RED), false);
|
||||
player.displayClientMessage((Component)Component.literal((String)deafnessMsg).m_130940_(ChatFormatting.RED), false);
|
||||
} else {
|
||||
String deafnessMsg = String.format("Deafness %.1f m \u2014 not activated (chance)", distance);
|
||||
player.m_5661_((Component)Component.literal((String)deafnessMsg).m_130940_(ChatFormatting.GRAY), false);
|
||||
player.displayClientMessage((Component)Component.literal((String)deafnessMsg).m_130940_(ChatFormatting.GRAY), false);
|
||||
}
|
||||
}
|
||||
if (!roll) {
|
||||
@@ -258,16 +258,16 @@ public class ConcussionAudioEffect {
|
||||
double metersToExplosion = distance;
|
||||
double onePercentDistance = maxDistance * 0.99;
|
||||
String outMessage = String.format("\u041f\u043e\u0437\u0430 \u0437\u043e\u043d\u043e\u044e \u043f\u043e\u0440\u0430\u0437\u043a\u0438. \u0412\u0456\u0434\u0441\u0442\u0430\u043d\u044c \u0434\u043e \u0432\u0438\u0431\u0443\u0445\u0443: %.1f \u043c. 1%% \u043f\u043e\u0447\u0438\u043d\u0430\u0454\u0442\u044c\u0441\u044f \u0437: %.1f \u043c.", metersToExplosion, onePercentDistance);
|
||||
player.m_5661_((Component)Component.literal((String)outMessage).m_130940_(ChatFormatting.GRAY), false);
|
||||
player.displayClientMessage((Component)Component.literal((String)outMessage).m_130940_(ChatFormatting.GRAY), false);
|
||||
return;
|
||||
}
|
||||
ChatFormatting color = ConcussionAudioEffect.pickColor(clamped);
|
||||
String visibility = hasDirectLineOfSight ? "\u043f\u0440\u044f\u043c\u0430 \u0432\u0438\u0434\u0438\u043c\u0456\u0441\u0442\u044c" : "\u043f\u0435\u0440\u0435\u0448\u043a\u043e\u0434\u0430";
|
||||
String message = String.format("\u041f\u043e\u0442\u0443\u0436\u043d\u0456\u0441\u0442\u044c \u043a\u043e\u043d\u0442\u0443\u0437\u0456\u0457 %.1f%% (%s)", clamped, visibility);
|
||||
player.m_5661_((Component)Component.literal((String)message).m_130940_(color), false);
|
||||
player.displayClientMessage((Component)Component.literal((String)message).m_130940_(color), false);
|
||||
if (!hasDirectLineOfSight && rawPercent > 0.0) {
|
||||
String rawMessage = String.format("(\u0434\u043e \u043f\u0435\u0440\u0435\u0448\u043a\u043e\u0434\u0438: %.1f%%)", Math.max(0.0, Math.min(100.0, rawPercent)));
|
||||
player.m_5661_((Component)Component.literal((String)rawMessage).m_130940_(ChatFormatting.GRAY), false);
|
||||
player.displayClientMessage((Component)Component.literal((String)rawMessage).m_130940_(ChatFormatting.GRAY), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ public class DeafnessConcussionEffect {
|
||||
lastIntensity = currentIntensity;
|
||||
if (debugShowChat && (player = mc.player) != null) {
|
||||
String msg = String.format("\u041f\u043e\u0442\u0443\u0436\u043d\u0456\u0441\u0442\u044c \u043a\u043e\u043d\u0442\u0443\u0437\u0456\u0457 %.1f%% (%s) \u2014 \u0421\u0438\u043b\u0430 \u0441\u043a\u0440\u0443\u0447\u0443\u0432\u0430\u043d\u043d\u044f %d%%, \u0427\u0430\u0441 \u0441\u043a\u0440\u0443\u0447\u0443\u0432\u0430\u043d\u043d\u044f %.1f \u0441\u0435\u043a", effectivePercent, visibility, intensityPercent, silentSeconds);
|
||||
player.m_5661_((Component)Component.literal((String)msg).m_130940_(ChatFormatting.WHITE), false);
|
||||
player.displayClientMessage((Component)Component.literal((String)msg).m_130940_(ChatFormatting.WHITE), false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -109,17 +109,17 @@ public class LowPassConcussionEffect {
|
||||
SoundEngineAudioQueue.drainNow();
|
||||
}
|
||||
if (debugShowChat && (mc = Minecraft.getInstance()) != null && mc.player != null) {
|
||||
mc.player.m_5661_((Component)Component.literal((String)("Low pass test queued for " + seconds + "s (strength=" + addedStrength + ")")), false);
|
||||
mc.player.displayClientMessage((Component)Component.literal((String)("Low pass test queued for " + seconds + "s (strength=" + addedStrength + ")")), false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void start(int seconds, float intensity, double effectivePercent, String visibility, int intensityPercent) {
|
||||
Minecraft mc;
|
||||
if (debugShowChat && (mc = Minecraft.getInstance()) != null && mc.player != null) {
|
||||
mc.player.m_5661_((Component)Component.literal((String)"__________________________________________"), false);
|
||||
mc.player.displayClientMessage((Component)Component.literal((String)"__________________________________________"), false);
|
||||
String msg = String.format("\u041f\u043e\u0442\u0443\u0436\u043d\u0456\u0441\u0442\u044c \u043a\u043e\u043d\u0442\u0443\u0437\u0456\u0457 %.1f%% (%s) \u2014 \u0421\u0438\u043b\u0430 \u043f\u0440\u0438\u0433\u043b\u0443\u0448\u0435\u043d\u043d\u044f %d%%, \u0427\u0430\u0441 \u043f\u0440\u0438\u0433\u043b\u0443\u0448\u0435\u043d\u043d\u044f %.1f \u0441\u0435\u043a", effectivePercent, visibility, intensityPercent, (double)seconds);
|
||||
mc.player.m_5661_((Component)Component.literal((String)msg).m_130940_(ChatFormatting.WHITE), false);
|
||||
mc.player.m_5661_((Component)Component.literal((String)"__________________________________________"), false);
|
||||
mc.player.displayClientMessage((Component)Component.literal((String)msg).m_130940_(ChatFormatting.WHITE), false);
|
||||
mc.player.displayClientMessage((Component)Component.literal((String)"__________________________________________"), false);
|
||||
}
|
||||
LowPassConcussionEffect.start(seconds, intensity);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package net.neoforged.neoforge.event;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.neoforged.neoforge.server.ServerLifecycleHooks;
|
||||
|
||||
public final class TickEvent {
|
||||
private TickEvent() {
|
||||
}
|
||||
@@ -31,6 +34,10 @@ public final class TickEvent {
|
||||
public ServerTickEvent(Phase phase) {
|
||||
this.phase = phase;
|
||||
}
|
||||
|
||||
public MinecraftServer getServer() {
|
||||
return ServerLifecycleHooks.getCurrentServer();
|
||||
}
|
||||
}
|
||||
|
||||
public static class LevelTickEvent {
|
||||
|
||||
Reference in New Issue
Block a user