Files
Explosion-Overhaul/com/vinlanx/explosionoverhaul/client/LowPassConcussionEffect.java
2026-05-04 10:03:58 +00:00

312 lines
12 KiB
Java

/*
* Decompiled with CFR 0.152.
*/
package com.vinlanx.explosionoverhaul.client;
import com.vinlanx.explosionoverhaul.Config;
import com.vinlanx.explosionoverhaul.client.SoundEngineAudioQueue;
import com.vinlanx.explosionoverhaul.client.SoundPhysicsCompatibility;
import java.util.concurrent.atomic.AtomicBoolean;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.network.chat.Component;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import org.lwjgl.openal.AL10;
import org.lwjgl.openal.ALC10;
import org.lwjgl.openal.EXTEfx;
@OnlyIn(value=Dist.CLIENT)
@Mod.EventBusSubscriber(modid="explosionoverhaul", value={Dist.CLIENT})
public class LowPassConcussionEffect {
private static final float HF_MIN = 0.01f;
private static final float HF_MAX = 1.0f;
private static final float GAIN_MIN = 0.1f;
private static final int FADE_IN_TICKS = 40;
private static final int FADE_OUT_TICKS = 100;
private static volatile Phase phase = Phase.IDLE;
private static volatile int holdTicks = 0;
private static volatile int ticksInPhase = 0;
private static final AtomicBoolean efxAvailable = new AtomicBoolean(false);
private static volatile int filterId = 0;
private static volatile float targetHfMin = 1.0f;
private static volatile float targetGainMin = 1.0f;
private static volatile float currentDeafnessGain = 1.0f;
public static volatile boolean enabled = true;
public static volatile boolean debugShowChat = false;
private static volatile boolean compatibilityMode = false;
private static volatile float lastAppliedHf = 1.0f;
private static volatile float lastAppliedGain = 1.0f;
public static void setDeafnessGain(float gain) {
currentDeafnessGain = Math.max(0.0f, Math.min(1.0f, gain));
if (phase == Phase.IDLE && currentDeafnessGain < 0.99f && !compatibilityMode) {
SoundEngineAudioQueue.enqueueAudio(() -> LowPassConcussionEffect.ensureFilterExists());
}
}
private static void ensureFilterExists() {
if (!efxAvailable.get()) {
long ctx = ALC10.alcGetCurrentContext();
long dev = ALC10.alcGetContextsDevice((long)ctx);
if (!ALC10.alcIsExtensionPresent((long)dev, (CharSequence)"ALC_EXT_EFX")) {
efxAvailable.set(false);
return;
}
efxAvailable.set(true);
}
if (filterId == 0) {
filterId = EXTEfx.alGenFilters();
EXTEfx.alFilteri((int)filterId, (int)32769, (int)1);
EXTEfx.alFilterf((int)filterId, (int)1, (float)1.0f);
EXTEfx.alFilterf((int)filterId, (int)2, (float)1.0f);
}
}
public static void start(int seconds, float intensity) {
Minecraft mc;
if (!enabled) {
return;
}
if (seconds < 1) {
seconds = 1;
}
if (seconds > 600) {
seconds = 600;
}
float effectiveIntensity = (Boolean)Config.CLIENT.enableLowPass.get() != false ? intensity : 0.001f;
float addedStrength = Math.max(0.0f, Math.min(1.0f, effectiveIntensity));
if (phase != Phase.IDLE) {
float currentStrength = (1.0f - targetHfMin) / 0.99f;
float totalStrength = Math.min(1.0f, currentStrength + addedStrength);
targetHfMin = 1.0f - totalStrength * 0.99f;
holdTicks = Math.min(2000, holdTicks + seconds * 20);
if (phase == Phase.FADE_OUT) {
phase = Phase.HOLD;
ticksInPhase = 0;
}
} else {
float totalStrength = addedStrength;
targetHfMin = 1.0f - totalStrength * 0.99f;
targetGainMin = 0.1f;
holdTicks = seconds * 20;
ticksInPhase = 0;
phase = Phase.FADE_IN;
}
if (!compatibilityMode) {
SoundEngineAudioQueue.enqueueAudio(() -> {
try {
LowPassConcussionEffect.ensureFilterExists();
}
catch (Throwable ex) {
efxAvailable.set(false);
}
});
SoundEngineAudioQueue.drainNow();
}
if (debugShowChat && (mc = Minecraft.m_91087_()) != null && mc.f_91074_ != null) {
mc.f_91074_.m_5661_((Component)Component.m_237113_((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.m_91087_()) != null && mc.f_91074_ != null) {
mc.f_91074_.m_5661_((Component)Component.m_237113_((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.f_91074_.m_5661_((Component)Component.m_237113_((String)msg).m_130940_(ChatFormatting.WHITE), false);
mc.f_91074_.m_5661_((Component)Component.m_237113_((String)"__________________________________________"), false);
}
LowPassConcussionEffect.start(seconds, intensity);
}
public static void stop() {
phase = Phase.IDLE;
ticksInPhase = 0;
lastAppliedHf = 1.0f;
lastAppliedGain = 1.0f;
targetGainMin = 1.0f;
if (compatibilityMode) {
SoundEngineAudioQueue.enqueueAudio(SoundPhysicsCompatibility::reapplyDirectFilterParameters);
}
SoundEngineAudioQueue.enqueueAudio(() -> {
if (filterId != 0) {
try {
EXTEfx.alFilterf((int)filterId, (int)2, (float)1.0f);
EXTEfx.alFilterf((int)filterId, (int)1, (float)1.0f);
}
catch (Throwable throwable) {
// empty catch block
}
}
});
}
public static boolean isActive() {
return phase != Phase.IDLE || currentDeafnessGain < 0.99f;
}
public static int getFilterId() {
return filterId;
}
@SubscribeEvent
public static void onClientTick(TickEvent.ClientTickEvent event) {
if (event.phase == TickEvent.Phase.END) {
LowPassConcussionEffect.onClientTick();
}
}
public static void onClientTick() {
Minecraft mc = Minecraft.m_91087_();
if (mc != null && mc.m_91104_()) {
return;
}
if (currentDeafnessGain < 0.99f || phase != Phase.IDLE) {
float hf = 1.0f;
float gainInterp = 1.0f;
if (phase != Phase.IDLE) {
++ticksInPhase;
switch (phase) {
case FADE_IN: {
float t = Math.min(1.0f, (float)ticksInPhase / 40.0f);
hf = LowPassConcussionEffect.lerp(1.0f, targetHfMin, LowPassConcussionEffect.easeOutQuad(t));
gainInterp = LowPassConcussionEffect.lerp(1.0f, targetGainMin, LowPassConcussionEffect.easeOutQuad(t));
if (ticksInPhase < 40) break;
phase = Phase.HOLD;
ticksInPhase = 0;
hf = targetHfMin;
gainInterp = targetGainMin;
break;
}
case HOLD: {
hf = targetHfMin;
gainInterp = targetGainMin;
if (ticksInPhase < holdTicks) break;
phase = Phase.FADE_OUT;
ticksInPhase = 0;
break;
}
case FADE_OUT: {
float t = Math.min(1.0f, (float)ticksInPhase / 100.0f);
hf = LowPassConcussionEffect.lerp(targetHfMin, 1.0f, LowPassConcussionEffect.easeInQuad(t));
gainInterp = LowPassConcussionEffect.lerp(targetGainMin, 1.0f, LowPassConcussionEffect.easeInQuad(t));
if (ticksInPhase < 100) break;
LowPassConcussionEffect.stop();
hf = 1.0f;
gainInterp = 1.0f;
}
}
}
float combinedGain = Math.max(0.0f, Math.min(1.0f, gainInterp * currentDeafnessGain));
LowPassConcussionEffect.applyFilterParamsOnAudioThread(hf, combinedGain);
}
}
private static void applyFilterParamsOnAudioThread(float hf, float gain) {
float clampedHf = Math.max(0.01f, Math.min(1.0f, hf));
float clampedGain = Math.max(0.0f, Math.min(1.0f, gain));
lastAppliedHf = clampedHf;
lastAppliedGain = clampedGain;
if (compatibilityMode) {
SoundEngineAudioQueue.enqueueAudio(SoundPhysicsCompatibility::reapplyDirectFilterParameters);
}
if (!efxAvailable.get()) {
return;
}
int fid = filterId;
if (fid == 0) {
return;
}
SoundEngineAudioQueue.enqueueAudio(() -> {
try {
EXTEfx.alFilterf((int)fid, (int)2, (float)clampedHf);
EXTEfx.alFilterf((int)fid, (int)1, (float)clampedGain);
}
catch (Throwable throwable) {
// empty catch block
}
});
}
private static float lerp(float a, float b, float t) {
return a + (b - a) * t;
}
private static float easeOutQuad(float t) {
return 1.0f - (1.0f - t) * (1.0f - t);
}
private static float easeInQuad(float t) {
return t * t;
}
private static String alErrorName(int err) {
return switch (err) {
case 0 -> "AL_NO_ERROR";
case 40961 -> "AL_INVALID_NAME";
case 40962 -> "AL_INVALID_ENUM";
case 40963 -> "AL_INVALID_VALUE";
case 40964 -> "AL_INVALID_OPERATION";
case 40965 -> "AL_OUT_OF_MEMORY";
default -> "AL_UNKNOWN_ERROR";
};
}
public static void setCompatibilityMode(boolean compatibilityActive) {
compatibilityMode = compatibilityActive;
}
public static float getCurrentHfMultiplier() {
return Math.max(0.01f, Math.min(1.0f, lastAppliedHf));
}
public static float getCurrentGainMultiplier() {
return Math.max(0.0f, Math.min(1.0f, lastAppliedGain));
}
public static void attachFilterToSource(int sourceId) {
if (sourceId <= 0) {
return;
}
if (!efxAvailable.get() || filterId == 0) {
return;
}
try {
if (!AL10.alIsSource((int)sourceId)) {
return;
}
if (AL10.alGetSourcei((int)sourceId, (int)514) == 1) {
return;
}
AL10.alSourcei((int)sourceId, (int)131077, (int)filterId);
}
catch (Throwable throwable) {
// empty catch block
}
}
public static void detachFilterFromSource(int sourceId) {
try {
if (AL10.alIsSource((int)sourceId)) {
AL10.alSourcei((int)sourceId, (int)131077, (int)0);
}
}
catch (Throwable throwable) {
// empty catch block
}
}
private static enum Phase {
IDLE,
FADE_IN,
HOLD,
FADE_OUT;
}
}