diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 0000000..ebb2e64 --- /dev/null +++ b/.gitea/workflows/build.yml @@ -0,0 +1,31 @@ +name: Build + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: '21' + + - name: Build + run: ./gradlew build --stacktrace + + - name: Upload mod jar + uses: actions/upload-artifact@v3 + if: always() + with: + name: explosionoverhaul-neoforge-build + path: | + build/libs/** diff --git a/.gitignore b/.gitignore index b746d15..6d60ce3 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ run/ out/ _mdk/ +_decompiled/ tools/ upstream/ decompiled/ diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..dd88f0d --- /dev/null +++ b/build.gradle @@ -0,0 +1,184 @@ +plugins { + id 'java-library' + id 'maven-publish' + id 'net.neoforged.moddev' version '2.0.141' + id 'idea' +} + +tasks.named('wrapper', Wrapper).configure { + // Define wrapper values here so as to not have to always do so when updating gradlew.properties. + // Switching this to Wrapper.DistributionType.ALL will download the full gradle sources that comes with + // documentation attached on cursor hover of gradle classes and methods. However, this comes with increased + // file size for Gradle. If you do switch this to ALL, run the Gradle wrapper task twice afterwards. + // (Verify by checking gradle/wrapper/gradle-wrapper.properties to see if distributionUrl now points to `-all`) + distributionType = Wrapper.DistributionType.BIN +} + +version = mod_version +group = mod_group_id + +sourceSets.main.resources { + // Include resources generated by data generators. + srcDir('src/generated/resources') + + // Exclude common development only resources from finalized outputs + exclude("**/*.bbmodel") // BlockBench project files + exclude("src/generated/**/.cache") // datagen cache files +} + +repositories { + maven { + name = "CurseMaven" + url = "https://cursemaven.com" + } + maven { + name = "GeckoLib" + url = "https://dl.cloudsmith.io/public/geckolib3/geckolib/maven/" + } + maven { + name = "TerraformersMC" + url = "https://maven.terraformersmc.com/releases/" + } +} + +base { + archivesName = mod_id +} + +// Mojang ships Java 21 to end users in 1.21.1, so mods should target Java 21. +java.toolchain.languageVersion = JavaLanguageVersion.of(21) + +neoForge { + // Specify the version of NeoForge to use. + version = project.neo_version + + parchment { + mappingsVersion = project.parchment_mappings_version + minecraftVersion = project.parchment_minecraft_version + } + + // This line is optional. Access Transformers are automatically detected + // accessTransformers = project.files('src/main/resources/META-INF/accesstransformer.cfg') + + // Default run configurations. + // These can be tweaked, removed, or duplicated as needed. + runs { + client { + client() + + // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. + systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id + } + + server { + server() + programArgument '--nogui' + systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id + } + + // This run config launches GameTestServer and runs all registered gametests, then exits. + // By default, the server will crash when no gametests are provided. + // The gametest system is also enabled by default for other run configs under the /test command. + gameTestServer { + type = "gameTestServer" + systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id + } + + data { + data() + + // example of overriding the workingDirectory set in configureEach above, uncomment if you want to use it + // gameDirectory = project.file('run-data') + + // Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources. + programArguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath() + } + + // applies to all the run configs above + configureEach { + // Recommended logging data for a userdev environment + // The markers can be added/remove as needed separated by commas. + // "SCAN": For mods scan. + // "REGISTRIES": For firing of registry events. + // "REGISTRYDUMP": For getting the contents of all registries. + systemProperty 'forge.logging.markers', 'REGISTRIES' + + // Recommended logging level for the console + // You can set various levels here. + // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels + logLevel = org.slf4j.event.Level.DEBUG + } + } + + mods { + // define mod <-> source bindings + // these are used to tell the game which sources are for which mod + // multi mod projects should define one per mod + "${mod_id}" { + sourceSet(sourceSets.main) + } + } +} + +// Sets up a dependency configuration called 'localRuntime'. +// This configuration should be used instead of 'runtimeOnly' to declare +// a dependency that will be present for runtime testing but that is +// "optional", meaning it will not be pulled by dependents of this mod. +configurations { + runtimeClasspath.extendsFrom localRuntime +} + +dependencies { + implementation "curse.maven:cloth-config-348521:5623420" + implementation "curse.maven:geckolib-388172:5763144" +} + +// This block of code expands all declared replace properties in the specified resource targets. +// A missing property will result in an error. Properties are expanded using ${} Groovy notation. +var generateModMetadata = tasks.register("generateModMetadata", ProcessResources) { + var replaceProperties = [ + minecraft_version : minecraft_version, + minecraft_version_range: minecraft_version_range, + neo_version : neo_version, + loader_version_range : loader_version_range, + mod_id : mod_id, + mod_name : mod_name, + mod_license : mod_license, + mod_version : mod_version, + ] + inputs.properties replaceProperties + expand replaceProperties + from "src/main/templates" + into "build/generated/sources/modMetadata" +} +// Include the output of "generateModMetadata" as an input directory for the build +// this works with both building through Gradle and the IDE. +sourceSets.main.resources.srcDir generateModMetadata +// To avoid having to run "generateModMetadata" manually, make it run on every project reload +neoForge.ideSyncTask generateModMetadata + +// Example configuration to allow publishing using the maven-publish plugin +publishing { + publications { + register('mavenJava', MavenPublication) { + from components.java + } + } + repositories { + maven { + url "file://${project.projectDir}/repo" + } + } +} + +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation +} + +// IDEA no longer automatically downloads sources/javadoc jars for dependencies, so we need to explicitly enable the behavior. +idea { + module { + downloadSources = true + downloadJavadoc = true + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..448e264 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,39 @@ +# Sets default memory used for gradle commands. Can be overridden by user or command line properties. +org.gradle.jvmargs=-Xmx3G +org.gradle.daemon=true +org.gradle.parallel=true +org.gradle.caching=true +org.gradle.configuration-cache=true + +#read more on this at https://github.com/neoforged/ModDevGradle?tab=readme-ov-file#better-minecraft-parameter-names--javadoc-parchment +# you can also find the latest versions at: https://parchmentmc.org/docs/getting-started +parchment_minecraft_version=1.21.1 +parchment_mappings_version=2024.11.17 +# Environment Properties +# You can find the latest versions here: https://projects.neoforged.net/neoforged/neoforge +# The Minecraft version must agree with the Neo version to get a valid artifact +minecraft_version=1.21.1 +# The Minecraft version range can use any release version of Minecraft as bounds. +# Snapshots, pre-releases, and release candidates are not guaranteed to sort properly +# as they do not follow standard versioning conventions. +minecraft_version_range=[1.21.1] +# The Neo version must agree with the Minecraft version to get a valid artifact +neo_version=21.1.228 +# The loader version range can only use the major version of FML as bounds +loader_version_range=[1,) + +## Mod Properties + +# The unique mod identifier for the mod. Must be lowercase in English locale. Must fit the regex [a-z][a-z0-9_]{1,63} +# Must match the String constant located in the main mod class annotated with @Mod. +mod_id=explosionoverhaul +# The human-readable display name for the mod. +mod_name=Explosion Overhaul +# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. +mod_license=All Rights Reserved +# The mod version. See https://semver.org/ +mod_version=0.2.3.0-neoforge-1.21.1 +# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. +# This should match the base package used for the mod sources. +# See https://maven.apache.org/guides/mini/guide-naming-conventions.html +mod_group_id=com.vinlanx.explosionoverhaul diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..23449a2 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..23d15a9 --- /dev/null +++ b/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH="\\\"\\\"" + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..db3a6ac --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,94 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH= + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..7a488e3 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,9 @@ +pluginManagement { + repositories { + gradlePluginPortal() + } +} + +plugins { + id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0' +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/AmbientExplosionManager.java b/src/main/java/com/vinlanx/explosionoverhaul/AmbientExplosionManager.java new file mode 100644 index 0000000..fc837fa --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/AmbientExplosionManager.java @@ -0,0 +1,375 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +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.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; +import net.neoforged.neoforge.network.PacketDistributor; +import net.neoforged.neoforge.registries.ForgeRegistries; + +public class AmbientExplosionManager { + private static final Map playerTimers = new HashMap(); + + 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 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 soundsToPlay = new ArrayList(); + 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.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)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 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 = ForgeRegistries.SOUND_EVENTS.getKey((Object)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.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)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.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)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; + + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/AsyncCraterManager.java b/src/main/java/com/vinlanx/explosionoverhaul/AsyncCraterManager.java new file mode 100644 index 0000000..195c950 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/AsyncCraterManager.java @@ -0,0 +1,522 @@ +/* + * 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.lang.invoke.LambdaMetafactory; +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 java.util.function.Function; +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 activeJobs; + private static final AtomicLong globalEpoch; + private static final ConcurrentHashMap, AtomicLong> dimensionEpochs; + + private static AtomicLong getDimensionEpoch(ResourceKey dimension) { + return dimensionEpochs.computeIfAbsent(dimension, d -> new AtomicLong(0L)); + } + + private static long incrementDimensionEpoch(ResourceKey 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)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)dim); + activeJobs.removeIf(job -> job.isForDimension((ResourceKey)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 dimensionKey; + private final long submitGlobalEpoch; + private final long submitDimensionEpoch; + private volatile List candidates; + private volatile boolean computed; + private final ServerLevel levelRef; + private int appliedIndex; + private final List ordered; + private final RandomSource random; + private float[] rayEnergy; + private boolean[] rayDepleted; + private int rayCount; + private Set destroyedPositions = new HashSet(); + + 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(); + this.ordered = new ArrayList(); + 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 corePositions = new HashSet(); + 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 coreBlocks = new ArrayList(); + ArrayList rayBlocks = new ArrayList(); + 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 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; + } + if (c.core) ** GOTO lbl-1000 + 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 lbl-1000: + // 2 sources + + { + 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(); + 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, (Function)LambdaMetafactory.metafactory(null, null, null, (Ljava/lang/Object;)Ljava/lang/Object;, lambda$applyBatch$1(net.minecraft.world.level.chunk.LevelChunk ), (Lnet/minecraft/world/level/chunk/LevelChunk;)Ljava/util/List;)()).add(c); + ++i; + } + for (Map.Entry e : byChunk.entrySet()) { + chunk = (LevelChunk)e.getKey(); + list = (List)e.getValue(); + list.sort((Comparator)LambdaMetafactory.metafactory(null, null, null, (Ljava/lang/Object;Ljava/lang/Object;)I, lambda$applyBatch$2(com.vinlanx.explosionoverhaul.AsyncCraterManager$Job$Candidate com.vinlanx.explosionoverhaul.AsyncCraterManager$Job$Candidate ), (Lcom/vinlanx/explosionoverhaul/AsyncCraterManager$Job$Candidate;Lcom/vinlanx/explosionoverhaul/AsyncCraterManager$Job$Candidate;)I)()); + modifiedSections = new HashSet(); + toRelight = new ArrayList(); + 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; + } + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/BlockIndexManager.java b/src/main/java/com/vinlanx/explosionoverhaul/BlockIndexManager.java new file mode 100644 index 0000000..ca6a497 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/BlockIndexManager.java @@ -0,0 +1,1804 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.DynamicOps; +import com.vinlanx.explosionoverhaul.Config; +import com.vinlanx.explosionoverhaul.ExplosionOverhaul; +import com.vinlanx.explosionoverhaul.PacketHandler; +import com.vinlanx.explosionoverhaul.ScanLoadPromptPacket; +import com.vinlanx.explosionoverhaul.ScanProgressPacket; +import com.vinlanx.explosionoverhaul.ScanPromptPacket; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.ByteArrayInputStream; +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.RandomAccessFile; +import java.io.Reader; +import java.lang.invoke.LambdaMetafactory; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.FileAttribute; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Locale; +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.CopyOnWriteArrayList; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.atomic.LongAdder; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.zip.GZIPInputStream; +import java.util.zip.InflaterInputStream; +import net.minecraft.core.BlockPos; +import net.minecraft.core.IdMap; +import net.minecraft.core.registries.Registries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.NbtOps; +import net.minecraft.resources.ResourceKey; +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.world.entity.player.Player; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +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.level.chunk.PalettedContainer; +import net.minecraft.world.level.storage.LevelResource; +import net.neoforged.neoforge.event.TickEvent; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; +import net.neoforged.neoforge.event.level.BlockEvent; +import net.neoforged.neoforge.event.level.ChunkEvent; +import net.neoforged.neoforge.event.server.ServerStartedEvent; +import net.neoforged.neoforge.event.server.ServerStoppedEvent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; +import net.neoforged.neoforge.network.PacketDistributor; +import net.neoforged.neoforge.registries.ForgeRegistries; +import net.neoforged.neoforge.server.ServerLifecycleHooks; + +@Mod.EventBusSubscriber +public class BlockIndexManager { + private static volatile MinecraftServer currentServer; + private static final Map, ConcurrentHashMap>> indexByDimension; + private static final ConcurrentLinkedQueue chunkScanQueue; + private static final Map, Set> pendingChunkKeys; + public static volatile boolean ENABLED; + private static final boolean SCAN_ONLY_ON_START = true; + private static volatile boolean INITIAL_SCAN_ENQUEUED; + private static volatile int totalChunksToScan; + private static volatile int chunksScanned; + private static volatile boolean scanningComplete; + private static volatile boolean abortCurrentScan; + private static volatile int lampsFound; + private static volatile int dripstonesFound; + private static volatile int glassBlocksFound; + private static volatile ResourceKey lastScannedDimension; + private static volatile boolean waitingForUserInput; + private static volatile ServerLevel pendingScanLevel; + private static volatile ResourceKey currentScannedWorld; + private static volatile boolean isSingleplayer; + private static volatile boolean serverScanPromptShown; + private static volatile boolean serverScanDecisionMade; + private static volatile boolean isRescanMode; + private static volatile ServerPlayer rescanRequestingPlayer; + private static volatile boolean userDeclinedScan; + private static volatile boolean waitingForLoadDecision; + private static volatile boolean hasSaveFile; + private static volatile String currentWorldId; + private static final List DEFAULT_REINFORCED_GLASS_BLACKLIST; + private static final Path MOD_CONFIG_DIRECTORY; + private static final Path GLASS_BLACKLIST_FILE; + private static final CopyOnWriteArrayList GLASS_BLACKLIST; + private static final AtomicReference> GLASS_BLACKLIST_LOOKUP; + + private static ConcurrentHashMap> getOrCreateDimIndex(ServerLevel level) { + ResourceKey dim = level.m_46472_(); + return indexByDimension.computeIfAbsent((ResourceKey)dim, k -> new ConcurrentHashMap()); + } + + private static Set getOrCreatePendingSet(ServerLevel level) { + ResourceKey dim = level.m_46472_(); + return pendingChunkKeys.computeIfAbsent((ResourceKey)dim, k -> Collections.newSetFromMap(new ConcurrentHashMap())); + } + + private static long chunkKey(ChunkPos cp) { + return (long)cp.f_45578_ & 0xFFFFFFFFL | ((long)cp.f_45579_ & 0xFFFFFFFFL) << 32; + } + + private static long packPos(BlockPos pos) { + return pos.m_121878_(); + } + + private static BlockPos unpackPos(long packed) { + return BlockPos.m_122022_((long)packed); + } + + public static int getTotalChunksToScan() { + return totalChunksToScan; + } + + public static int getChunksScanned() { + return chunksScanned; + } + + public static float getScanProgress() { + if (totalChunksToScan == 0) { + return 1.0f; + } + return Math.min(1.0f, (float)chunksScanned / (float)totalChunksToScan); + } + + public static boolean isScanningComplete() { + return scanningComplete; + } + + public static int getLampsFound() { + return lampsFound; + } + + public static int getDripstonesFound() { + return dripstonesFound; + } + + public static int getGlassBlocksFound() { + return glassBlocksFound; + } + + private static void clearScanDataSilent() { + indexByDimension.clear(); + chunkScanQueue.clear(); + pendingChunkKeys.clear(); + totalChunksToScan = 0; + chunksScanned = 0; + scanningComplete = false; + currentScannedWorld = null; + lastScannedDimension = null; + lampsFound = 0; + dripstonesFound = 0; + glassBlocksFound = 0; + } + + private static void clearScanData() { + BlockIndexManager.clearScanDataSilent(); + BlockIndexManager.sendProgressUpdate(); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: cleared all scan data for world switch"); + } + + private static void clearAndSaveData() { + if (!indexByDimension.isEmpty() && scanningComplete) { + try { + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + if (server != null) { + BlockIndexManager.saveIndexData(server); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: saved data before clearing"); + } + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to save data before clearing: {}", (Object)e.getMessage()); + } + } + BlockIndexManager.clearScanData(); + } + + private static void startSingleplayerScan(ServerLevel level) { + ExplosionOverhaul.LOGGER.info("BlockIndexManager: starting singleplayer scan for ALL dimensions"); + BlockIndexManager.clearScanDataSilent(); + MinecraftServer server = level.m_7654_(); + BlockIndexManager.scanExistingChunksOnServer(server); + } + + private static void startServerScan(MinecraftServer server) { + ExplosionOverhaul.LOGGER.info("BlockIndexManager: starting server-wide scan for all dimensions"); + BlockIndexManager.clearScanDataSilent(); + BlockIndexManager.scanExistingChunksOnServer(server); + } + + private static void scanSingleWorld(ServerLevel level) { + try { + chunksScanned = 0; + scanningComplete = false; + lastScannedDimension = level.m_46472_(); + lampsFound = 0; + dripstonesFound = 0; + glassBlocksFound = 0; + String dimensionName = level.m_46472_().m_135782_().toString(); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: scanning existing chunks in world: {}", (Object)dimensionName); + Set existingChunks = BlockIndexManager.getAllExistingChunks(level); + totalChunksToScan = existingChunks.size(); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: found {} chunks to scan", (Object)totalChunksToScan); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: using safe server-thread scanning for live chunks"); + BlockIndexManager.scanWithSingleThread(level, existingChunks); + } + catch (Exception ex) { + ExplosionOverhaul.LOGGER.warn("BlockIndexManager: failed to start scan: {}", (Object)ex.toString()); + } + } + + private static void scanWithSingleThread(ServerLevel level, Set existingChunks) { + for (ChunkPos cp : existingChunks) { + chunkScanQueue.add(new ScanTask((ResourceKey)level.m_46472_(), cp)); + } + BlockIndexManager.sendProgressUpdate(); + } + + private static Set getAllExistingChunks(ServerLevel level) { + Set existingChunks; + block18: { + existingChunks = Collections.newSetFromMap(new ConcurrentHashMap()); + try { + ExplosionOverhaul.LOGGER.info("BlockIndexManager: scanning for all existing chunks..."); + MinecraftServer server = level.m_7654_(); + String dimPath = level.m_46472_().m_135782_().m_135815_(); + Path worldPath = server.m_129843_(LevelResource.f_78182_); + Path regionPath = "overworld".equals(dimPath) ? worldPath.resolve("region") : ("the_nether".equals(dimPath) ? worldPath.resolve("DIM-1").resolve("region") : ("the_end".equals(dimPath) ? worldPath.resolve("DIM1").resolve("region") : worldPath.resolve("dimensions").resolve(level.m_46472_().m_135782_().m_135827_()).resolve(level.m_46472_().m_135782_().m_135815_()).resolve("region"))); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: scanning region files in: {}", (Object)regionPath); + if (Files.exists(regionPath, new LinkOption[0])) { + try (Stream regionFiles = Files.list(regionPath);){ + List mcaFiles = regionFiles.filter(path -> path.toString().endsWith(".mca")).collect(Collectors.toList()); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: found {} .mca files in region directory", (Object)mcaFiles.size()); + mcaFiles.parallelStream().forEach(regionFile -> { + block13: { + try { + int chunksInThisRegion; + int regionZ; + int regionX; + block14: { + String[] parts; + String fileName = regionFile.getFileName().toString(); + if (!fileName.startsWith("r.") || !fileName.endsWith(".mca") || (parts = fileName.substring(2, fileName.length() - 4).split("\\.")).length != 2) break block13; + regionX = Integer.parseInt(parts[0]); + regionZ = Integer.parseInt(parts[1]); + chunksInThisRegion = 0; + try (InputStream is = Files.newInputStream(regionFile, new OpenOption[0]);){ + byte[] header = new byte[4096]; + int bytesRead = is.read(header); + if (bytesRead < 4096) break block14; + for (int i = 0; i < 1024; ++i) { + int offset = i * 4; + int chunkOffset = (header[offset] & 0xFF) << 16 | (header[offset + 1] & 0xFF) << 8 | header[offset + 2] & 0xFF; + if (chunkOffset <= 0) continue; + int cx = i % 32; + int cz = i / 32; + int chunkX = regionX * 32 + cx; + int chunkZ = regionZ * 32 + cz; + ChunkPos cp = new ChunkPos(chunkX, chunkZ); + existingChunks.add(cp); + ++chunksInThisRegion; + } + } + catch (Exception readEx) { + ExplosionOverhaul.LOGGER.warn("BlockIndexManager: failed to read region file {}: {}", (Object)fileName, (Object)readEx.getMessage()); + for (int cx = 0; cx < 32; ++cx) { + for (int cz = 0; cz < 32; ++cz) { + int chunkX = regionX * 32 + cx; + int chunkZ = regionZ * 32 + cz; + ChunkPos cp = new ChunkPos(chunkX, chunkZ); + existingChunks.add(cp); + ++chunksInThisRegion; + } + } + } + } + ExplosionOverhaul.LOGGER.info("BlockIndexManager: region {},{} - found {} existing chunks (read from .mca header)", new Object[]{regionX, regionZ, chunksInThisRegion}); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("BlockIndexManager: failed to parse region file {}: {}", (Object)regionFile.getFileName(), (Object)e.getMessage()); + } + } + }); + } + ExplosionOverhaul.LOGGER.info("BlockIndexManager: scanned region files and found {} existing chunks", (Object)existingChunks.size()); + break block18; + } + ExplosionOverhaul.LOGGER.warn("BlockIndexManager: region directory not found: {}", (Object)regionPath); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.error("BlockIndexManager: failed to scan world storage: {}", (Object)e.getMessage()); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: using fallback - estimate chunks from .mca files"); + try { + String dimPath = level.m_46472_().m_135782_().m_135815_(); + MinecraftServer server = level.m_7654_(); + Path worldPath = server.m_129843_(LevelResource.f_78182_); + Path regionPath = "overworld".equals(dimPath) ? worldPath.resolve("region") : ("the_nether".equals(dimPath) ? worldPath.resolve("DIM-1").resolve("region") : ("the_end".equals(dimPath) ? worldPath.resolve("DIM1").resolve("region") : worldPath.resolve("dimensions").resolve(level.m_46472_().m_135782_().m_135827_()).resolve(level.m_46472_().m_135782_().m_135815_()).resolve("region"))); + if (!Files.exists(regionPath, new LinkOption[0])) break block18; + try (Stream regionFiles = Files.list(regionPath);){ + regionFiles.filter(path -> path.toString().endsWith(".mca")).forEach(regionFile -> { + String[] parts; + String fileName = regionFile.getFileName().toString(); + if (fileName.startsWith("r.") && fileName.endsWith(".mca") && (parts = fileName.substring(2, fileName.length() - 4).split("\\.")).length == 2) { + int regionX = Integer.parseInt(parts[0]); + int regionZ = Integer.parseInt(parts[1]); + for (int cx = 0; cx < 32; ++cx) { + for (int cz = 0; cz < 32; ++cz) { + int chunkX = regionX * 32 + cx; + int chunkZ = regionZ * 32 + cz; + ChunkPos cp = new ChunkPos(chunkX, chunkZ); + existingChunks.add(cp); + } + } + ExplosionOverhaul.LOGGER.info("BlockIndexManager: fallback added ~1024 chunks from region {},{}", (Object)regionX, (Object)regionZ); + } + }); + } + ExplosionOverhaul.LOGGER.info("BlockIndexManager: fallback found {} estimated chunks", (Object)existingChunks.size()); + } + catch (Exception fallbackEx) { + ExplosionOverhaul.LOGGER.error("BlockIndexManager: fallback also failed: {}", (Object)fallbackEx.getMessage()); + } + } + } + return existingChunks; + } + + private static void saveIndexDataAfterScan(MinecraftServer server) { + try { + ExplosionOverhaul.LOGGER.info("BlockIndexManager: Starting auto-save after scan completion..."); + BlockIndexManager.saveIndexData(server); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to auto-save scan data: {}", (Object)e.getMessage()); + e.printStackTrace(); + } + } + + private static void sendProgressUpdate() { + try { + ExplosionOverhaul.LOGGER.debug("sendProgressUpdate: {}/{} chunks, complete={}, L:{} D:{} G:{}", new Object[]{chunksScanned, totalChunksToScan, scanningComplete, lampsFound, dripstonesFound, glassBlocksFound}); + if (scanningComplete) { + ExplosionOverhaul.LOGGER.info("BlockIndexManager: sending final progress update to OP players - {}/{} chunks, lamps={}, dripstones={}, glass={}", new Object[]{chunksScanned, totalChunksToScan, lampsFound, dripstonesFound, glassBlocksFound}); + } + ScanProgressPacket packet = new ScanProgressPacket(totalChunksToScan, chunksScanned, scanningComplete, lampsFound, dripstonesFound, glassBlocksFound); + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + if (server != null) { + for (ServerPlayer player : server.m_6846_().m_11314_()) { + if (!BlockIndexManager.isPlayerAuthorized(player)) continue; + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)packet); + } + } + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to send scan progress update: {}", (Object)e.getMessage()); + } + } + + private static void sendMultiThreadProgressUpdate(int currentProcessed, int currentLamps, int currentDripstones, int currentGlass) { + try { + ScanProgressPacket packet = new ScanProgressPacket(totalChunksToScan, currentProcessed, false, currentLamps, currentDripstones, currentGlass); + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + if (server != null) { + for (ServerPlayer player : server.m_6846_().m_11314_()) { + if (!BlockIndexManager.isPlayerAuthorized(player)) continue; + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)packet); + } + } + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to send multi-thread progress update: {}", (Object)e.getMessage()); + } + } + + private static void sendScanPromptPacket(ServerPlayer player) { + try { + ScanPromptPacket packet = new ScanPromptPacket(true); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)packet); + ExplosionOverhaul.LOGGER.info("Sent scan prompt to authorized player: {}", (Object)player.m_7755_().getString()); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to send scan prompt: {}", (Object)e.getMessage()); + } + } + + public static void startManualScan() { + if (BlockIndexManager.isChunkScanningDisabled()) { + ExplosionOverhaul.LOGGER.info("BlockIndexManager: manual scan cancelled - chunk scanning is disabled in config"); + BlockIndexManager.cancelManualScan(); + return; + } + if (waitingForUserInput && pendingScanLevel != null) { + waitingForUserInput = false; + serverScanDecisionMade = true; + userDeclinedScan = false; + if (isRescanMode) { + ExplosionOverhaul.LOGGER.info("BlockIndexManager: clearing data for rescan as user confirmed"); + BlockIndexManager.clearScanDataSilent(); + try { + MinecraftServer server = pendingScanLevel.m_7654_(); + Path saveFile = BlockIndexManager.getSaveFilePath(server); + if (Files.exists(saveFile, new LinkOption[0])) { + Files.delete(saveFile); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: deleted old save file for rescan"); + } + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to delete old save file: {}", (Object)e.getMessage()); + } + } + if (isSingleplayer || isRescanMode) { + BlockIndexManager.startSingleplayerScan(pendingScanLevel); + } else { + BlockIndexManager.startServerScan(pendingScanLevel.m_7654_()); + } + ServerPlayer requestingPlayer = rescanRequestingPlayer; + pendingScanLevel = null; + isRescanMode = false; + rescanRequestingPlayer = null; + try { + if (requestingPlayer != null && requestingPlayer.m_6084_()) { + ScanPromptPacket packet = new ScanPromptPacket(false); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> requestingPlayer), (Object)packet); + } else { + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + if (server != null) { + for (ServerPlayer player : server.m_6846_().m_11314_()) { + if (!BlockIndexManager.isPlayerAuthorized(player)) continue; + ScanPromptPacket packet = new ScanPromptPacket(false); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)packet); + } + } + } + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to hide scan prompt: {}", (Object)e.getMessage()); + } + } + } + + /* + * Unable to fully structure code + */ + public static void loadExistingData() { + if (BlockIndexManager.waitingForLoadDecision && BlockIndexManager.pendingScanLevel != null) { + BlockIndexManager.waitingForLoadDecision = false; + BlockIndexManager.serverScanDecisionMade = true; + server = BlockIndexManager.pendingScanLevel.m_7654_(); + loaded = BlockIndexManager.loadIndexData(server); + if (loaded) { + ExplosionOverhaul.LOGGER.info("BlockIndexManager: Successfully loaded existing scan data"); + BlockIndexManager.sendProgressUpdate(); + try { + currentServer = ServerLifecycleHooks.getCurrentServer(); + if (currentServer == null) ** GOTO lbl24 + for (ServerPlayer serverPlayer : currentServer.m_6846_().m_11314_()) { + if (!BlockIndexManager.isPlayerAuthorized(serverPlayer)) continue; + packet = new ScanLoadPromptPacket(false); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with((Supplier)LambdaMetafactory.metafactory(null, null, null, ()Ljava/lang/Object;, lambda$loadExistingData$11(net.minecraft.server.level.ServerPlayer ), ()Lnet/minecraft/server/level/ServerPlayer;)((ServerPlayer)serverPlayer)), (Object)packet); + ExplosionOverhaul.LOGGER.debug("Hidden load prompt for authorized player: {}", (Object)serverPlayer.m_7755_().getString()); + } + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to hide load prompt: {}", (Object)e.getMessage()); + } + } else { + ExplosionOverhaul.LOGGER.warn("BlockIndexManager: Failed to load existing data, falling back to new scan"); + BlockIndexManager.startNewScan(); + } +lbl24: + // 4 sources + + BlockIndexManager.pendingScanLevel = null; + } + } + + public static void startNewScan() { + if (waitingForLoadDecision && pendingScanLevel != null) { + waitingForLoadDecision = false; + serverScanDecisionMade = true; + userDeclinedScan = false; + try { + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + if (server != null) { + for (ServerPlayer serverPlayer : server.m_6846_().m_11314_()) { + if (!BlockIndexManager.isPlayerAuthorized(serverPlayer)) continue; + ScanLoadPromptPacket hideLoadPacket = new ScanLoadPromptPacket(false); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> serverPlayer), (Object)hideLoadPacket); + ScanPromptPacket showScanPacket = new ScanPromptPacket(true); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> serverPlayer), (Object)showScanPacket); + ExplosionOverhaul.LOGGER.debug("Switched prompts for authorized player: {}", (Object)serverPlayer.m_7755_().getString()); + } + } + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to switch prompts: {}", (Object)e.getMessage()); + } + waitingForUserInput = true; + serverScanDecisionMade = false; + } + } + + public static void cancelManualScan() { + if (waitingForUserInput) { + waitingForUserInput = false; + serverScanDecisionMade = true; + userDeclinedScan = true; + pendingScanLevel = null; + ServerPlayer requestingPlayer = rescanRequestingPlayer; + isRescanMode = false; + rescanRequestingPlayer = null; + chunkScanQueue.clear(); + totalChunksToScan = 0; + chunksScanned = 0; + scanningComplete = false; + ExplosionOverhaul.LOGGER.info("BlockIndexManager: manual scan cancelled by user - cleared scan queue"); + try { + if (requestingPlayer != null && requestingPlayer.m_6084_()) { + ScanPromptPacket packet = new ScanPromptPacket(false); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> requestingPlayer), (Object)packet); + } else { + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + if (server != null) { + for (ServerPlayer player : server.m_6846_().m_11314_()) { + if (!BlockIndexManager.isPlayerAuthorized(player)) continue; + ScanPromptPacket packet = new ScanPromptPacket(false); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)packet); + } + } + } + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to hide scan prompt: {}", (Object)e.getMessage()); + } + } + } + + public static void resetScanState() { + waitingForUserInput = false; + waitingForLoadDecision = false; + pendingScanLevel = null; + serverScanPromptShown = false; + serverScanDecisionMade = false; + isRescanMode = false; + rescanRequestingPlayer = null; + userDeclinedScan = false; + hasSaveFile = false; + INITIAL_SCAN_ENQUEUED = false; + BlockIndexManager.clearAndSaveData(); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: scan state reset by command"); + } + + public static void forceServerScan(MinecraftServer server) { + BlockIndexManager.resetScanState(); + BlockIndexManager.startServerScan(server); + } + + public static void forceSingleplayerScan(ServerLevel level) { + BlockIndexManager.resetScanState(); + BlockIndexManager.startSingleplayerScan(level); + } + + public static void showRescanPrompt(ServerPlayer player) { + isRescanMode = true; + waitingForUserInput = true; + pendingScanLevel = player.m_284548_(); + rescanRequestingPlayer = player; + serverScanPromptShown = true; + serverScanDecisionMade = false; + try { + ScanPromptPacket packet = new ScanPromptPacket(true); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)packet); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: showing rescan prompt to player: {}", (Object)player.m_7755_().getString()); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to send rescan prompt: {}", (Object)e.getMessage()); + } + } + + private static void sendScanPromptPacket(boolean show) { + try { + MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); + if (server != null) { + for (ServerPlayer player : server.m_6846_().m_11314_()) { + if (!BlockIndexManager.isPlayerAuthorized(player)) continue; + ScanPromptPacket packet = new ScanPromptPacket(show); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)packet); + if (!show) continue; + ExplosionOverhaul.LOGGER.debug("Sent scan prompt to authorized player: {}", (Object)player.m_7755_().getString()); + } + } + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to send scan prompt packet: {}", (Object)e.getMessage()); + } + } + + private static boolean isGlassBlock(BlockState state) { + try { + String blockName = ForgeRegistries.BLOCKS.getKey((Object)state.m_60734_()).toString().toLowerCase(Locale.ROOT); + if (BlockIndexManager.isGlassProtected(blockName)) { + return false; + } + return blockName.contains("glass"); + } + catch (Exception e) { + return state.m_60713_(Blocks.f_50058_) || state.m_60713_(Blocks.f_152498_); + } + } + + private static boolean isLampName(String name) { + return "minecraft:redstone_lamp".equals(name); + } + + private static boolean isDripstoneName(String name) { + return "minecraft:pointed_dripstone".equals(name); + } + + private static boolean isGlassName(String name) { + if (name == null) { + return false; + } + String normalized = name.toLowerCase(Locale.ROOT); + return normalized.contains("glass") && !BlockIndexManager.isGlassProtected(normalized); + } + + public static boolean isReinforcedGlass(BlockState state) { + try { + String blockName = ForgeRegistries.BLOCKS.getKey((Object)state.m_60734_()).toString().toLowerCase(Locale.ROOT); + return BlockIndexManager.isGlassProtected(blockName); + } + catch (Exception e) { + return false; + } + } + + public static List getReinforcedGlassBlacklist() { + return new ArrayList(GLASS_BLACKLIST); + } + + public static List getDefaultReinforcedGlassBlacklist() { + return new ArrayList(DEFAULT_REINFORCED_GLASS_BLACKLIST); + } + + public static void setReinforcedGlassBlacklistFromList(List list) { + BlockIndexManager.applyGlassBlacklistList(list); + BlockIndexManager.saveGlassBlacklistToJson(); + } + + private static void ensureModConfigDirectory() { + try { + Files.createDirectories(MOD_CONFIG_DIRECTORY, new FileAttribute[0]); + } + catch (IOException e) { + ExplosionOverhaul.LOGGER.warn("BlockIndexManager: failed to create config directory for glass blacklist", (Throwable)e); + } + } + + private static void loadGlassBlacklistFromJson() { + BlockIndexManager.ensureModConfigDirectory(); + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + if (!Files.exists(GLASS_BLACKLIST_FILE, new LinkOption[0])) { + BlockIndexManager.applyGlassBlacklistList(DEFAULT_REINFORCED_GLASS_BLACKLIST); + BlockIndexManager.saveGlassBlacklistToJson(); + return; + } + try (BufferedReader reader = Files.newBufferedReader(GLASS_BLACKLIST_FILE);){ + List list = (List)gson.fromJson((Reader)reader, new TypeToken>(){}.getType()); + if (list == null) { + BlockIndexManager.applyGlassBlacklistList(DEFAULT_REINFORCED_GLASS_BLACKLIST); + return; + } + BlockIndexManager.applyGlassBlacklistList(list); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("BlockIndexManager: failed to load GlassBlacklist.json, falling back to defaults", (Throwable)e); + BlockIndexManager.applyGlassBlacklistList(DEFAULT_REINFORCED_GLASS_BLACKLIST); + } + } + + private static void saveGlassBlacklistToJson() { + BlockIndexManager.ensureModConfigDirectory(); + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + try (BufferedWriter writer = Files.newBufferedWriter(GLASS_BLACKLIST_FILE, new OpenOption[0]);){ + gson.toJson(new ArrayList(GLASS_BLACKLIST), (Appendable)writer); + } + catch (IOException e) { + ExplosionOverhaul.LOGGER.warn("BlockIndexManager: failed to save GlassBlacklist.json", (Throwable)e); + } + } + + private static void applyGlassBlacklistList(List list) { + List normalized = BlockIndexManager.normalizeBlacklist(list); + GLASS_BLACKLIST.clear(); + GLASS_BLACKLIST.addAll(normalized); + GLASS_BLACKLIST_LOOKUP.set(new HashSet(normalized)); + } + + private static List normalizeBlacklist(List entries) { + if (entries == null) { + return new ArrayList(); + } + ArrayList result = new ArrayList(); + HashSet seen = new HashSet(); + for (String raw : entries) { + String candidate; + if (raw == null || (candidate = raw.trim().toLowerCase(Locale.ROOT)).isEmpty() || !seen.add(candidate)) continue; + result.add(candidate); + } + return result; + } + + private static boolean isGlassProtected(String name) { + return GLASS_BLACKLIST_LOOKUP.get().contains(name); + } + + private static String generateWorldId(MinecraftServer server) { + try { + Path worldPath = server.m_129843_(LevelResource.f_78182_); + String worldName = server.m_129910_().m_5462_(); + String folderName = worldPath.getFileName().toString(); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: World path: {}", (Object)worldPath); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: World name from level.dat: '{}'", (Object)worldName); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: Folder name: '{}'", (Object)folderName); + if (folderName == null || folderName.trim().isEmpty()) { + folderName = "world"; + } + if (worldName == null || worldName.trim().isEmpty()) { + worldName = "Unknown"; + } + String combined = folderName + "_" + worldName; + String result = combined.replaceAll("[^a-zA-Z0-9_-]", "_").toLowerCase(); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: Generated world ID: '{}'", (Object)result); + return result; + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to generate world ID, using fallback: {}", (Object)e.getMessage()); + String fallback = "unknown_world_" + System.currentTimeMillis(); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: Using fallback ID: '{}'", (Object)fallback); + return fallback; + } + } + + private static Path getSaveFilePath(MinecraftServer server) { + String worldId = BlockIndexManager.generateWorldId(server); + Path configDir = server.m_129843_(LevelResource.f_78182_).getParent().resolve("config").resolve("explosionoverhaul"); + try { + Files.createDirectories(configDir, new FileAttribute[0]); + ExplosionOverhaul.LOGGER.debug("BlockIndexManager: Using config directory: {}", (Object)configDir); + } + catch (IOException e) { + ExplosionOverhaul.LOGGER.error("Failed to create config directory: {}", (Object)e.getMessage()); + } + Path saveFile = configDir.resolve("block_index_" + worldId + ".json"); + ExplosionOverhaul.LOGGER.debug("BlockIndexManager: Save file path: {}", (Object)saveFile); + return saveFile; + } + + public static void saveIndexData(MinecraftServer server) { + ExplosionOverhaul.LOGGER.info("BlockIndexManager: Attempting to save data..."); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: IndexByDimension size: {}", (Object)indexByDimension.size()); + try { + Path saveFile = BlockIndexManager.getSaveFilePath(server); + if (!scanningComplete) { + ExplosionOverhaul.LOGGER.warn("BlockIndexManager: Scan incomplete - deleting save file instead of saving corrupted data"); + if (Files.exists(saveFile, new LinkOption[0])) { + Files.delete(saveFile); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: Deleted incomplete save file: {}", (Object)saveFile); + } + return; + } + if (indexByDimension.isEmpty()) { + ExplosionOverhaul.LOGGER.warn("BlockIndexManager: No data to save - index is empty!"); + return; + } + ExplosionOverhaul.LOGGER.info("BlockIndexManager: Saving to file: {}", (Object)saveFile); + HashMap saveData = new HashMap(); + int totalBlocks = 0; + for (Map.Entry, ConcurrentHashMap>> dimEntry : indexByDimension.entrySet()) { + String dimKey = dimEntry.getKey().m_135782_().toString(); + HashMap> chunkMap = new HashMap>(); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: Processing dimension: {}", (Object)dimKey); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: Chunks in dimension: {}", (Object)dimEntry.getValue().size()); + for (Map.Entry> chunkEntry : dimEntry.getValue().entrySet()) { + Set blocks = chunkEntry.getValue(); + if (blocks.isEmpty()) continue; + chunkMap.put(chunkEntry.getKey().toString(), blocks); + totalBlocks += blocks.size(); + } + if (chunkMap.isEmpty()) continue; + saveData.put(dimKey, chunkMap); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: Added {} chunks with blocks to save data for dimension {}", (Object)chunkMap.size(), (Object)dimKey); + } + ExplosionOverhaul.LOGGER.info("BlockIndexManager: Total blocks to save: {}", (Object)totalBlocks); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: Dimensions to save: {}", (Object)saveData.size()); + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + String json = gson.toJson(saveData); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: JSON length: {}", (Object)json.length()); + if (json.length() < 20) { + ExplosionOverhaul.LOGGER.warn("BlockIndexManager: JSON too small ({} bytes) - skipping save to prevent corruption", (Object)json.length()); + return; + } + Files.write(saveFile, json.getBytes(), new OpenOption[0]); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: Successfully saved index data to {}", (Object)saveFile); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.error("BlockIndexManager: Failed to save index data: {}", (Object)e.getMessage()); + e.printStackTrace(); + } + } + + public static boolean loadIndexData(MinecraftServer server) { + try { + Type saveDataType; + Path saveFile = BlockIndexManager.getSaveFilePath(server); + if (!Files.exists(saveFile, new LinkOption[0])) { + ExplosionOverhaul.LOGGER.debug("BlockIndexManager: No save file found at {}", (Object)saveFile); + return false; + } + Gson gson = new Gson(); + String json = new String(Files.readAllBytes(saveFile)); + Map saveData = (Map)gson.fromJson(json, saveDataType = new TypeToken>>>(){}.getType()); + if (saveData == null || saveData.isEmpty()) { + ExplosionOverhaul.LOGGER.warn("BlockIndexManager: Save file is empty or corrupted"); + return false; + } + indexByDimension.clear(); + for (Map.Entry dimEntry : saveData.entrySet()) { + try { + ResourceKey dimKey = ResourceKey.m_135785_((ResourceKey)Registries.f_256858_, (ResourceLocation)ResourceLocation.parse((String)((String)dimEntry.getKey()))); + ConcurrentHashMap chunkMap = new ConcurrentHashMap(); + for (Map.Entry chunkEntry : ((Map)dimEntry.getValue()).entrySet()) { + Long chunkKey = Long.parseLong((String)chunkEntry.getKey()); + Set blockSet = Collections.newSetFromMap(new ConcurrentHashMap()); + blockSet.addAll((Collection)chunkEntry.getValue()); + chunkMap.put(chunkKey, blockSet); + } + indexByDimension.put((ResourceKey)dimKey, chunkMap); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("BlockIndexManager: Failed to load dimension {}: {}", dimEntry.getKey(), (Object)e.getMessage()); + } + } + ExplosionOverhaul.LOGGER.info("BlockIndexManager: Successfully loaded index data from {}", (Object)saveFile); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: Loaded {} dimensions with indexed blocks", (Object)indexByDimension.size()); + scanningComplete = true; + totalChunksToScan = 0; + chunksScanned = 0; + lampsFound = 0; + dripstonesFound = 0; + glassBlocksFound = 0; + return true; + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.error("BlockIndexManager: Failed to load index data: {}", (Object)e.getMessage()); + e.printStackTrace(); + return false; + } + } + + public static boolean hasSaveFile(MinecraftServer server) { + Path saveFile = BlockIndexManager.getSaveFilePath(server); + return Files.exists(saveFile, new LinkOption[0]) && Files.isRegularFile(saveFile, new LinkOption[0]); + } + + private static int getChunksToScanPerTick() { + int cpuPercent = (Integer)Config.COMMON.scan.cpuUsagePercent.get(); + int baseChunks = 500; + return Math.max(1, baseChunks * cpuPercent / 100); + } + + private static boolean isChunkScanningDisabled() { + return (Boolean)Config.COMMON.scan.enableBlockIndexing.get() == false; + } + + private static boolean isScanning() { + return !chunkScanQueue.isEmpty() && totalChunksToScan > 0 && !scanningComplete; + } + + public static boolean isRescanMode() { + return isRescanMode; + } + + public static void register(ServerLevel level, BlockPos pos, BlockType type) { + ConcurrentHashMap> dimIndex = BlockIndexManager.getOrCreateDimIndex(level); + ChunkPos cp = new ChunkPos(pos); + long ck = BlockIndexManager.chunkKey(cp); + dimIndex.computeIfAbsent(ck, k -> Collections.newSetFromMap(new ConcurrentHashMap())).add(BlockIndexManager.packPos(pos)); + } + + public static void unregister(ServerLevel level, BlockPos pos, BlockType type) { + ChunkPos cp; + long ck; + ConcurrentHashMap> dimIndex = BlockIndexManager.getOrCreateDimIndex(level); + Set set = dimIndex.get(ck = BlockIndexManager.chunkKey(cp = new ChunkPos(pos))); + if (set != null) { + set.remove(BlockIndexManager.packPos(pos)); + if (set.isEmpty()) { + dimIndex.remove(ck); + } + } + } + + public static void scanChunk(ServerLevel level, ChunkPos cp) { + long ck; + ConcurrentHashMap> dimIndex = BlockIndexManager.getOrCreateDimIndex(level); + if (dimIndex.containsKey(ck = BlockIndexManager.chunkKey(cp))) { + return; + } + int baseX = cp.m_45604_(); + int baseZ = cp.m_45605_(); + Set set = Collections.newSetFromMap(new ConcurrentHashMap()); + int chunkLamps = 0; + int chunkDripstones = 0; + int chunkGlass = 0; + for (int lx = 0; lx < 16; ++lx) { + for (int lz = 0; lz < 16; ++lz) { + for (int y = level.m_141937_(); y < level.m_151558_(); ++y) { + BlockPos pos = new BlockPos(baseX + lx, y, baseZ + lz); + if (!level.m_46749_(pos)) continue; + BlockState state = level.m_8055_(pos); + if (state.m_60713_(Blocks.f_50261_)) { + set.add(BlockIndexManager.packPos(pos)); + ++chunkLamps; + continue; + } + if (state.m_60713_(Blocks.f_152588_)) { + set.add(BlockIndexManager.packPos(pos)); + ++chunkDripstones; + continue; + } + if (!BlockIndexManager.isGlassBlock(state)) continue; + set.add(BlockIndexManager.packPos(pos)); + ++chunkGlass; + } + } + } + lampsFound += chunkLamps; + dripstonesFound += chunkDripstones; + glassBlocksFound += chunkGlass; + if (!set.isEmpty()) { + dimIndex.put(ck, set); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: Found {} blocks in chunk {} {}: {}", new Object[]{set.size(), cp.f_45578_, cp.f_45579_, set.size() > 10 ? set.size() + " blocks" : set}); + } + if (++chunksScanned >= totalChunksToScan && totalChunksToScan > 0) { + MinecraftServer server; + scanningComplete = true; + int totalBlocksFound = 0; + for (Map.Entry, ConcurrentHashMap>> dimEntry : indexByDimension.entrySet()) { + for (Map.Entry> chunkEntry : dimEntry.getValue().entrySet()) { + totalBlocksFound += chunkEntry.getValue().size(); + } + } + ExplosionOverhaul.LOGGER.info("BlockIndexManager: chunk scanning completed! Scanned {}/{} chunks", (Object)chunksScanned, (Object)totalChunksToScan); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: Found {} total blocks across {} dimensions", (Object)totalBlocksFound, (Object)indexByDimension.size()); + try { + server = ServerLifecycleHooks.getCurrentServer(); + if (server != null) { + ExplosionOverhaul.LOGGER.info("BlockIndexManager: Starting auto-save after scan completion..."); + BlockIndexManager.saveIndexData(server); + } + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to auto-save scan data: {}", (Object)e.getMessage()); + e.printStackTrace(); + } + try { + server = ServerLifecycleHooks.getCurrentServer(); + if (server != null) { + server.execute(() -> BlockIndexManager.sendProgressUpdate()); + } + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to enqueue final progress update: {}", (Object)e.getMessage()); + } + } + if (chunksScanned % 10 == 0 || scanningComplete) { + BlockIndexManager.sendProgressUpdate(); + } + } + + public static void removeChunk(ServerLevel level, ChunkPos cp) { + ConcurrentHashMap> dimIndex = BlockIndexManager.getOrCreateDimIndex(level); + long ck = BlockIndexManager.chunkKey(cp); + dimIndex.remove(ck); + Set pending = BlockIndexManager.getOrCreatePendingSet(level); + pending.remove(ck); + } + + public static List getNearby(ServerLevel level, BlockPos center, int radius, BlockType type) { + ArrayList result = new ArrayList(); + int minX = center.m_123341_() - radius; + int maxX = center.m_123341_() + radius; + int minZ = center.m_123343_() - radius; + int maxZ = center.m_123343_() + radius; + int minChunkX = minX >> 4; + int maxChunkX = maxX >> 4; + int minChunkZ = minZ >> 4; + int maxChunkZ = maxZ >> 4; + ConcurrentHashMap> dimIndex = BlockIndexManager.getOrCreateDimIndex(level); + long r2 = (long)radius * (long)radius; + for (int cx = minChunkX; cx <= maxChunkX; ++cx) { + for (int cz = minChunkZ; cz <= maxChunkZ; ++cz) { + long ck = BlockIndexManager.chunkKey(new ChunkPos(cx, cz)); + Set set = dimIndex.get(ck); + if (set == null || set.isEmpty()) continue; + for (long packed : set) { + long dz; + long dy; + BlockPos pos = BlockIndexManager.unpackPos(packed); + long dx = pos.m_123341_() - center.m_123341_(); + if (dx * dx + (dy = (long)(pos.m_123342_() - center.m_123342_())) * dy + (dz = (long)(pos.m_123343_() - center.m_123343_())) * dz > r2) continue; + BlockState state = level.m_8055_(pos); + if (type == BlockType.LAMP && state.m_60713_(Blocks.f_50261_)) { + result.add(pos); + } + if (type == BlockType.DRIPSTONE && state.m_60713_(Blocks.f_152588_)) { + result.add(pos); + } + if (type != BlockType.GLASS || !BlockIndexManager.isGlassBlock(state)) continue; + result.add(pos); + } + } + } + return result; + } + + @SubscribeEvent + public static void onChunkLoad(ChunkEvent.Load event) { + if (!ENABLED) { + return; + } + if (BlockIndexManager.isChunkScanningDisabled()) { + return; + } + LevelAccessor levelAccessor = event.getLevel(); + if (!(levelAccessor instanceof ServerLevel)) { + return; + } + ServerLevel level = (ServerLevel)levelAccessor; + if (userDeclinedScan) { + return; + } + if (!isSingleplayer && !serverScanDecisionMade) { + return; + } + if (INITIAL_SCAN_ENQUEUED) { + return; + } + ResourceKey chunkDimension = level.m_46472_(); + if (lastScannedDimension != null && !lastScannedDimension.equals((Object)chunkDimension)) { + return; + } + if (scanningComplete) { + return; + } + long ck = BlockIndexManager.chunkKey(event.getChunk().m_7697_()); + Set pending = BlockIndexManager.getOrCreatePendingSet(level); + if (pending.add(ck)) { + chunkScanQueue.add(new ScanTask((ResourceKey)level.m_46472_(), event.getChunk().m_7697_())); + } + } + + @SubscribeEvent + public static void onChunkUnload(ChunkEvent.Unload event) { + if (!ENABLED) { + return; + } + LevelAccessor levelAccessor = event.getLevel(); + if (!(levelAccessor instanceof ServerLevel)) { + return; + } + ServerLevel level = (ServerLevel)levelAccessor; + BlockIndexManager.removeChunk(level, event.getChunk().m_7697_()); + chunkScanQueue.removeIf(t -> t.dim().equals((Object)level.m_46472_()) && t.chunkPos().equals((Object)event.getChunk().m_7697_())); + } + + @SubscribeEvent + public static void onBlockPlaced(BlockEvent.EntityPlaceEvent event) { + if (!ENABLED) { + return; + } + LevelAccessor levelAccessor = event.getLevel(); + if (!(levelAccessor instanceof ServerLevel)) { + return; + } + ServerLevel level = (ServerLevel)levelAccessor; + BlockPos pos = event.getPos(); + BlockState state = level.m_8055_(pos); + if (state.m_60713_(Blocks.f_50261_)) { + BlockIndexManager.register(level, pos, BlockType.LAMP); + } else if (state.m_60713_(Blocks.f_152588_)) { + BlockIndexManager.register(level, pos, BlockType.DRIPSTONE); + } else if (BlockIndexManager.isGlassBlock(state)) { + BlockIndexManager.register(level, pos, BlockType.GLASS); + } + } + + @SubscribeEvent + public static void onBlockBroken(BlockEvent.BreakEvent event) { + if (!ENABLED) { + return; + } + LevelAccessor levelAccessor = event.getLevel(); + if (!(levelAccessor instanceof ServerLevel)) { + return; + } + ServerLevel level = (ServerLevel)levelAccessor; + BlockPos pos = event.getPos(); + BlockIndexManager.unregister(level, pos, BlockType.LAMP); + BlockIndexManager.unregister(level, pos, BlockType.DRIPSTONE); + BlockIndexManager.unregister(level, pos, BlockType.GLASS); + } + + public static boolean isPlayerAuthorized(ServerPlayer player) { + if (player == null) { + return false; + } + return player.m_20310_(2) || isSingleplayer; + } + + @SubscribeEvent + public static void onPlayerJoinServer(PlayerEvent.PlayerLoggedInEvent event) { + if (!ENABLED) { + return; + } + if (BlockIndexManager.isChunkScanningDisabled()) { + return; + } + Player player = event.getEntity(); + if (!(player instanceof ServerPlayer)) { + return; + } + ServerPlayer player2 = (ServerPlayer)player; + if (BlockIndexManager.isPlayerAuthorized(player2)) { + ServerLevel level = player2.m_284548_(); + MinecraftServer server = level.m_7654_(); + boolean saveFileExists = BlockIndexManager.hasSaveFile(server); + if (isSingleplayer) { + if (!(waitingForUserInput || waitingForLoadDecision || scanningComplete)) { + chunkScanQueue.clear(); + totalChunksToScan = 0; + chunksScanned = 0; + } + if (!(waitingForUserInput || waitingForLoadDecision || BlockIndexManager.isScanning() || scanningComplete || userDeclinedScan)) { + pendingScanLevel = level; + if (saveFileExists) { + waitingForLoadDecision = true; + hasSaveFile = true; + try { + ScanLoadPromptPacket packet = new ScanLoadPromptPacket(true); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player2), (Object)packet); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: showing load prompt for existing save file in world: {}", (Object)level.m_46472_().m_135782_()); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to send load prompt: {}", (Object)e.getMessage()); + } + } else { + waitingForUserInput = true; + hasSaveFile = false; + BlockIndexManager.sendScanPromptPacket(true); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: waiting for user input to start scan in world: {}", (Object)level.m_46472_().m_135782_()); + } + } else if (BlockIndexManager.isScanning() || !chunkScanQueue.isEmpty() && totalChunksToScan > 0) { + try { + ScanProgressPacket packet = new ScanProgressPacket(totalChunksToScan, chunksScanned, scanningComplete, lampsFound, dripstonesFound, glassBlocksFound); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player2), (Object)packet); + ExplosionOverhaul.LOGGER.debug("Sent scan progress to rejoining OP player: {}/{} chunks", (Object)chunksScanned, (Object)totalChunksToScan); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to send scan progress to rejoining OP player: {}", (Object)e.getMessage()); + } + } + } else if (!serverScanDecisionMade && !userDeclinedScan) { + if (!serverScanPromptShown) { + serverScanPromptShown = true; + ExplosionOverhaul.LOGGER.info("BlockIndexManager: first OP joined server, waiting for scan decision from: {}", (Object)player2.m_7755_().getString()); + } else { + ExplosionOverhaul.LOGGER.info("BlockIndexManager: additional OP joined server, showing pending decision to: {}", (Object)player2.m_7755_().getString()); + } + pendingScanLevel = level; + if (saveFileExists) { + waitingForLoadDecision = true; + hasSaveFile = true; + try { + ScanLoadPromptPacket packet = new ScanLoadPromptPacket(true); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player2), (Object)packet); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: showing load prompt for existing save file to OP: {}", (Object)player2.m_7755_().getString()); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to send load prompt: {}", (Object)e.getMessage()); + } + } else { + waitingForUserInput = true; + hasSaveFile = false; + try { + ScanPromptPacket packet = new ScanPromptPacket(true); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player2), (Object)packet); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: showing scan prompt to OP: {}", (Object)player2.m_7755_().getString()); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to send scan prompt: {}", (Object)e.getMessage()); + } + } + } else if (totalChunksToScan > 0 && !scanningComplete) { + try { + ScanProgressPacket packet = new ScanProgressPacket(totalChunksToScan, chunksScanned, scanningComplete, lampsFound, dripstonesFound, glassBlocksFound); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player2), (Object)packet); + ExplosionOverhaul.LOGGER.debug("Sent scan progress to joining OP player: {}/{} chunks", (Object)chunksScanned, (Object)totalChunksToScan); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to send scan progress to joining OP player: {}", (Object)e.getMessage()); + } + } + } + } + + @SubscribeEvent + public static void onServerTick(TickEvent.ServerTickEvent event) { + ScanTask task; + if (event.phase != TickEvent.Phase.END) { + return; + } + if (BlockIndexManager.isChunkScanningDisabled()) { + return; + } + if (userDeclinedScan) { + return; + } + if (!isSingleplayer && !serverScanDecisionMade) { + return; + } + int chunksToScan = BlockIndexManager.getChunksToScanPerTick(); + for (int processed = 0; processed < chunksToScan && (task = chunkScanQueue.poll()) != null; ++processed) { + MinecraftServer server = event.getServer(); + ServerLevel level = server.m_129880_(task.dim()); + if (level == null) continue; + try { + BlockIndexManager.scanChunk(level, task.chunkPos()); + long ck = BlockIndexManager.chunkKey(task.chunkPos()); + Set pending = BlockIndexManager.getOrCreatePendingSet(level); + pending.remove(ck); + continue; + } + catch (Exception ex) { + ExplosionOverhaul.LOGGER.warn("BlockIndexManager: error scanning chunk {} {}: {}", new Object[]{task.chunkPos().f_45578_, task.chunkPos().f_45579_, ex.toString()}); + } + } + } + + @SubscribeEvent + public static void onServerStarted(ServerStartedEvent event) { + currentServer = event.getServer(); + abortCurrentScan = false; + if (!ENABLED) { + return; + } + if (BlockIndexManager.isChunkScanningDisabled()) { + return; + } + if (INITIAL_SCAN_ENQUEUED) { + return; + } + MinecraftServer server = event.getServer(); + isSingleplayer = server.m_129792_(); + if (!isSingleplayer) { + userDeclinedScan = false; + } + serverScanPromptShown = false; + serverScanDecisionMade = false; + if (isSingleplayer) { + ExplosionOverhaul.LOGGER.info("BlockIndexManager: singleplayer detected, will scan on world entry"); + INITIAL_SCAN_ENQUEUED = true; + return; + } + ExplosionOverhaul.LOGGER.info("BlockIndexManager: multiplayer server detected, will wait for user decision before scanning"); + INITIAL_SCAN_ENQUEUED = true; + } + + private static void scanExistingChunksOnServer(MinecraftServer server) { + try { + int totalChunks; + chunksScanned = 0; + scanningComplete = false; + lampsFound = 0; + dripstonesFound = 0; + glassBlocksFound = 0; + chunkScanQueue.clear(); + pendingChunkKeys.clear(); + HyperScanner scanner = new HyperScanner(server); + totalChunksToScan = totalChunks = scanner.prepareTasks(); + INITIAL_SCAN_ENQUEUED = true; + BlockIndexManager.sendProgressUpdate(); + CompletableFuture.runAsync(() -> { + try { + scanner.run(); + chunksScanned = scanner.getProcessedChunks(); + lampsFound = scanner.getLampsFound(); + dripstonesFound = scanner.getDripstonesFound(); + glassBlocksFound = scanner.getGlassFound(); + scanningComplete = true; + server.execute(() -> { + BlockIndexManager.sendProgressUpdate(); + BlockIndexManager.saveIndexDataAfterScan(server); + ExplosionOverhaul.LOGGER.info("HyperScanner: background scan complete. Found {} lamps, {} dripstones, {} glass.", new Object[]{lampsFound, dripstonesFound, glassBlocksFound}); + }); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.error("HyperScanner: background scan failed", (Throwable)e); + } + }); + } + catch (Exception ex) { + ExplosionOverhaul.LOGGER.warn("BlockIndexManager: failed to start scan: {}", (Object)ex.toString()); + } + } + + @SubscribeEvent + public static void onServerStopped(ServerStoppedEvent event) { + if (!ENABLED) { + return; + } + abortCurrentScan = true; + if (!indexByDimension.isEmpty() && scanningComplete) { + try { + BlockIndexManager.saveIndexData(event.getServer()); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: saved data before server shutdown"); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to save data on server stop: {}", (Object)e.getMessage()); + } + } + userDeclinedScan = false; + serverScanPromptShown = false; + serverScanDecisionMade = false; + waitingForUserInput = false; + waitingForLoadDecision = false; + pendingScanLevel = null; + isRescanMode = false; + rescanRequestingPlayer = null; + hasSaveFile = false; + currentWorldId = null; + INITIAL_SCAN_ENQUEUED = false; + try { + ScanProgressPacket packet = new ScanProgressPacket(0, 0, true, 0, 0, 0); + PacketHandler.INSTANCE.send(PacketDistributor.ALL.noArg(), (Object)packet); + } + catch (Exception exception) { + // empty catch block + } + currentServer = null; + scanningComplete = false; + totalChunksToScan = 0; + chunksScanned = 0; + ExplosionOverhaul.LOGGER.info("BlockIndexManager: reset scan state and aborted background tasks on server stop"); + } + + @SubscribeEvent + public static void onPlayerLogout(PlayerEvent.PlayerLoggedOutEvent event) { + Player player; + if (!ENABLED) { + return; + } + if (isSingleplayer) { + abortCurrentScan = true; + waitingForUserInput = false; + waitingForLoadDecision = false; + pendingScanLevel = null; + userDeclinedScan = false; + hasSaveFile = false; + scanningComplete = false; + totalChunksToScan = 0; + chunksScanned = 0; + BlockIndexManager.clearAndSaveData(); + ExplosionOverhaul.LOGGER.info("BlockIndexManager: saved and cleared scan data on singleplayer logout"); + } + if ((player = event.getEntity()) instanceof ServerPlayer) { + ServerPlayer player2 = (ServerPlayer)player; + try { + ScanProgressPacket packet = new ScanProgressPacket(0, 0, true, 0, 0, 0); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player2), (Object)packet); + } + catch (Exception exception) { + // empty catch block + } + } + } + + private static Path resolveRegionPath(ServerLevel lvl) { + try { + Path worldPath = lvl.m_7654_().m_129843_(LevelResource.f_78182_); + String dimPath = lvl.m_46472_().m_135782_().m_135815_(); + if ("overworld".equals(dimPath)) { + return worldPath.resolve("region"); + } + if ("the_nether".equals(dimPath)) { + return worldPath.resolve("DIM-1").resolve("region"); + } + if ("the_end".equals(dimPath)) { + return worldPath.resolve("DIM1").resolve("region"); + } + return worldPath.resolve("dimensions").resolve(lvl.m_46472_().m_135782_().m_135827_()).resolve(lvl.m_46472_().m_135782_().m_135815_()).resolve("region"); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("HyperScanner: failed to resolve region path: {}", (Object)e.getMessage()); + return null; + } + } + + private static /* synthetic */ ServerPlayer lambda$loadExistingData$11(ServerPlayer serverPlayer) { + return serverPlayer; + } + + static { + indexByDimension = new ConcurrentHashMap, ConcurrentHashMap>>(); + chunkScanQueue = new ConcurrentLinkedQueue(); + pendingChunkKeys = new ConcurrentHashMap, Set>(); + ENABLED = true; + INITIAL_SCAN_ENQUEUED = false; + totalChunksToScan = 0; + chunksScanned = 0; + scanningComplete = false; + abortCurrentScan = false; + lampsFound = 0; + dripstonesFound = 0; + glassBlocksFound = 0; + lastScannedDimension = null; + waitingForUserInput = false; + pendingScanLevel = null; + currentScannedWorld = null; + isSingleplayer = false; + serverScanPromptShown = false; + serverScanDecisionMade = false; + isRescanMode = false; + rescanRequestingPlayer = null; + userDeclinedScan = false; + waitingForLoadDecision = false; + hasSaveFile = false; + currentWorldId = null; + DEFAULT_REINFORCED_GLASS_BLACKLIST = List.of("securitycraft:reinforced_white_stained_glass", "securitycraft:reinforced_orange_stained_glass", "securitycraft:reinforced_magenta_stained_glass", "securitycraft:reinforced_light_blue_stained_glass", "securitycraft:reinforced_yellow_stained_glass", "securitycraft:reinforced_lime_stained_glass", "securitycraft:reinforced_pink_stained_glass", "securitycraft:reinforced_gray_stained_glass", "securitycraft:reinforced_light_gray_stained_glass", "securitycraft:reinforced_cyan_stained_glass", "securitycraft:reinforced_purple_stained_glass", "securitycraft:reinforced_blue_stained_glass", "securitycraft:reinforced_brown_stained_glass", "securitycraft:reinforced_green_stained_glass", "securitycraft:reinforced_red_stained_glass", "securitycraft:reinforced_black_stained_glass", "securitycraft:reinforced_white_stained_glass_pane", "securitycraft:reinforced_orange_stained_glass_pane", "securitycraft:reinforced_magenta_stained_glass_pane", "securitycraft:reinforced_light_blue_stained_glass_pane", "securitycraft:reinforced_yellow_stained_glass_pane", "securitycraft:reinforced_lime_stained_glass_pane", "securitycraft:reinforced_pink_stained_glass_pane", "securitycraft:reinforced_gray_stained_glass_pane", "securitycraft:reinforced_light_gray_stained_glass_pane", "securitycraft:reinforced_cyan_stained_glass_pane", "securitycraft:reinforced_purple_stained_glass_pane", "securitycraft:reinforced_blue_stained_glass_pane", "securitycraft:reinforced_brown_stained_glass_pane", "securitycraft:reinforced_green_stained_glass_pane", "securitycraft:reinforced_red_stained_glass_pane", "securitycraft:reinforced_black_stained_glass_pane", "securitycraft:reinforced_glass", "securitycraft:reinforced_glass_pane", "create_tank_defenses:titanium_morning_reinforced_blast_glass", "mofus_better_end_:reinforced_glass", "crusty_chunks:reinforced_glass", "createnuclear:reinforced_glass", "mekanismgenerators:reactor_glass", "mekanism:structural_glass"); + MOD_CONFIG_DIRECTORY = Paths.get("config", "explosionoverhaul"); + GLASS_BLACKLIST_FILE = MOD_CONFIG_DIRECTORY.resolve("GlassBlacklist.json"); + GLASS_BLACKLIST = new CopyOnWriteArrayList(DEFAULT_REINFORCED_GLASS_BLACKLIST); + GLASS_BLACKLIST_LOOKUP = new AtomicReference>(new HashSet(DEFAULT_REINFORCED_GLASS_BLACKLIST)); + BlockIndexManager.loadGlassBlacklistFromJson(); + } + + private record ScanTask(ResourceKey dim, ChunkPos chunkPos) { + } + + public static enum BlockType { + LAMP, + DRIPSTONE, + GLASS; + + } + + private static class HyperScanner { + private static final int SECTOR_BYTES = 4096; + private final MinecraftServer server; + private final ConcurrentLinkedQueue tasks = new ConcurrentLinkedQueue(); + private final AtomicInteger processedChunks = new AtomicInteger(); + private final LongAdder lamps = new LongAdder(); + private final LongAdder drips = new LongAdder(); + private final LongAdder glass = new LongAdder(); + private final int workerCount; + + HyperScanner(MinecraftServer server) { + this.server = server; + this.workerCount = this.resolveWorkerCount(); + } + + int prepareTasks() { + int total = 0; + for (ServerLevel level : this.server.m_129785_()) { + Path regionPath = BlockIndexManager.resolveRegionPath(level); + if (regionPath == null || !Files.exists(regionPath, new LinkOption[0])) { + ExplosionOverhaul.LOGGER.info("HyperScanner: region path not found for {}", (Object)level.m_46472_().m_135782_()); + continue; + } + try { + Stream regionFiles = Files.list(regionPath); + try { + for (Path regionFile : regionFiles.filter(p -> p.toString().endsWith(".mca")).toList()) { + RegionInfo info = this.parseRegion(regionFile); + if (info == null || info.chunkCount <= 0) continue; + this.tasks.add(new RegionTask(level, regionFile, info.regionX, info.regionZ)); + total += info.chunkCount; + } + } + finally { + if (regionFiles == null) continue; + regionFiles.close(); + } + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("HyperScanner: failed to enumerate region files in {}: {}", (Object)regionPath, (Object)e.getMessage()); + } + } + ExplosionOverhaul.LOGGER.info("HyperScanner: prepared {} region tasks, total chunks {}", (Object)this.tasks.size(), (Object)total); + return total; + } + + void run() { + if (this.tasks.isEmpty()) { + ExplosionOverhaul.LOGGER.info("HyperScanner: no tasks to run"); + return; + } + ExecutorService pool = Executors.newFixedThreadPool(this.workerCount, r -> { + Thread t = new Thread(r, "EO-HyperScanner"); + t.setDaemon(true); + return t; + }); + for (int i = 0; i < this.workerCount; ++i) { + pool.execute(this::workerLoop); + } + pool.shutdown(); + try { + while (!pool.isTerminated()) { + pool.awaitTermination(1L, TimeUnit.SECONDS); + } + } + catch (InterruptedException ie) { + Thread.currentThread().interrupt(); + } + } + + int getProcessedChunks() { + return this.processedChunks.get(); + } + + int getLampsFound() { + return this.lamps.intValue(); + } + + int getDripstonesFound() { + return this.drips.intValue(); + } + + int getGlassFound() { + return this.glass.intValue(); + } + + private void workerLoop() { + RegionTask task; + while (!abortCurrentScan && (task = this.tasks.poll()) != null) { + this.scanRegion(task); + } + } + + private void scanRegion(RegionTask task) { + try (RandomAccessFile raf = new RandomAccessFile(task.file().toFile(), "r");){ + byte[] header = new byte[4096]; + int read = raf.read(header); + if (read < 4096) { + return; + } + for (int i = 0; i < 1024; ++i) { + if (abortCurrentScan) { + return; + } + int offsetIndex = i * 4; + int chunkOffset = (header[offsetIndex] & 0xFF) << 16 | (header[offsetIndex + 1] & 0xFF) << 8 | header[offsetIndex + 2] & 0xFF; + int sectorCount = header[offsetIndex + 3] & 0xFF; + if (chunkOffset == 0 || sectorCount == 0) continue; + int localX = i % 32; + int localZ = i / 32; + int chunkX = task.regionX() * 32 + localX; + int chunkZ = task.regionZ() * 32 + localZ; + try { + this.processChunk(raf, chunkOffset, sectorCount, new ChunkPos(chunkX, chunkZ), task.level()); + continue; + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("HyperScanner: failed to process chunk {} {} in {}: {}", new Object[]{chunkX, chunkZ, task.file().getFileName(), e.getMessage()}); + } + } + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("HyperScanner: failed to scan region {}: {}", (Object)task.file().getFileName(), (Object)e.getMessage()); + } + } + + private void processChunk(RandomAccessFile raf, int chunkOffsetSectors, int sectorCount, ChunkPos chunkPos, ServerLevel level) throws IOException { + InflaterInputStream in; + long filePos = (long)chunkOffsetSectors * 4096L; + raf.seek(filePos); + int length = raf.readInt(); + if (length <= 0 || length > sectorCount * 4096) { + return; + } + int compressionType = raf.readUnsignedByte(); + byte[] data = new byte[length - 1]; + raf.readFully(data); + ByteArrayInputStream base = new ByteArrayInputStream(data); + if (compressionType == 2) { + in = new InflaterInputStream(base); + } else if (compressionType == 1) { + in = new GZIPInputStream(base); + } else { + return; + } + CompoundTag root = NbtIo.m_128928_((DataInput)new DataInputStream(in)); + if (root == null) { + return; + } + CompoundTag levelTag = root.m_128425_("Level", 10) ? root.m_128469_("Level") : (root.m_128425_("level", 10) ? root.m_128469_("level") : root); + ListTag sections = levelTag.m_128437_("sections", 10); + HashSet found = new HashSet(); + for (int i = 0; i < sections.size(); ++i) { + CompoundTag section = sections.m_128728_(i); + this.processSection(section, chunkPos, level, found); + } + if (!found.isEmpty()) { + ConcurrentHashMap> dimIndex = BlockIndexManager.getOrCreateDimIndex(level); + dimIndex.put(BlockIndexManager.chunkKey(chunkPos), found); + } + if (abortCurrentScan) { + return; + } + int processed = this.processedChunks.incrementAndGet(); + this.maybeSendProgress(processed); + } + + private void processSection(CompoundTag section, ChunkPos chunkPos, ServerLevel level, Set out) { + if (!section.m_128425_("block_states", 10)) { + return; + } + CompoundTag blockStatesTag = section.m_128469_("block_states"); + if (blockStatesTag.m_128425_("palette", 9)) { + ListTag palette = blockStatesTag.m_128437_("palette", 10); + boolean hasInterestingBlock = false; + for (int i = 0; i < palette.size(); ++i) { + String name = palette.m_128728_(i).m_128461_("Name"); + if (!name.equals("minecraft:redstone_lamp") && !name.equals("minecraft:pointed_dripstone") && (!name.contains("glass") || BlockIndexManager.isGlassProtected(name))) continue; + hasInterestingBlock = true; + break; + } + if (!hasInterestingBlock) { + return; + } + } + try { + DataResult result = PalettedContainer.m_238371_((IdMap)Block.f_49791_, (Codec)BlockState.f_61039_, (PalettedContainer.Strategy)PalettedContainer.Strategy.f_188137_, (Object)Blocks.f_50016_.m_49966_()).parse((DynamicOps)NbtOps.f_128958_, (Object)blockStatesTag); + result.resultOrPartial(err -> {}).ifPresent(container -> { + byte sectionY = section.m_128445_("Y"); + int baseY = sectionY * 16; + if (baseY < level.m_141937_() || baseY >= level.m_151558_()) { + return; + } + IdentityHashMap stateTypeCache = new IdentityHashMap(); + for (int y = 0; y < 16; ++y) { + int worldY = baseY + y; + if (worldY < level.m_141937_() || worldY >= level.m_151558_()) continue; + for (int z = 0; z < 16; ++z) { + for (int x = 0; x < 16; ++x) { + BlockState state = (BlockState)container.m_63087_(x, y, z); + Byte type = (Byte)stateTypeCache.get(state); + if (type == null) { + type = state.m_60713_(Blocks.f_50261_) ? Byte.valueOf((byte)1) : (state.m_60713_(Blocks.f_152588_) ? Byte.valueOf((byte)2) : (BlockIndexManager.isGlassBlock(state) ? Byte.valueOf((byte)3) : Byte.valueOf((byte)0))); + stateTypeCache.put(state, type); + } + if (type == 0) continue; + int worldX = chunkPos.m_45604_() + x; + int worldZ = chunkPos.m_45605_() + z; + out.add(BlockPos.m_121882_((int)worldX, (int)worldY, (int)worldZ)); + if (type == 1) { + this.lamps.increment(); + continue; + } + if (type == 2) { + this.drips.increment(); + continue; + } + if (type != 3) continue; + this.glass.increment(); + } + } + } + }); + } + catch (Exception exception) { + // empty catch block + } + } + + private void maybeSendProgress(int processed) { + if (processed % 50 == 0 || processed == totalChunksToScan) { + int l = this.lamps.intValue(); + int d = this.drips.intValue(); + int g = this.glass.intValue(); + this.server.execute(() -> BlockIndexManager.sendMultiThreadProgressUpdate(processed, l, d, g)); + } + } + + private RegionInfo parseRegion(Path regionFile) { + int regionZ; + int regionX; + String fileName = regionFile.getFileName().toString(); + if (!fileName.startsWith("r.") || !fileName.endsWith(".mca")) { + return null; + } + String[] parts = fileName.substring(2, fileName.length() - 4).split("\\."); + if (parts.length != 2) { + return null; + } + try { + regionX = Integer.parseInt(parts[0]); + regionZ = Integer.parseInt(parts[1]); + } + catch (NumberFormatException nfe) { + return null; + } + int chunkCount = this.countChunksInRegion(regionFile); + return new RegionInfo(regionX, regionZ, chunkCount); + } + + /* + * Enabled aggressive block sorting + * Enabled unnecessary exception pruning + * Enabled aggressive exception aggregation + */ + private int countChunksInRegion(Path regionFile) { + int count = 0; + try (RandomAccessFile raf = new RandomAccessFile(regionFile.toFile(), "r");){ + byte[] header = new byte[4096]; + int read = raf.read(header); + if (read < 4096) { + int n = 0; + return n; + } + int i = 0; + while (i < 1024) { + int offset = i * 4; + int chunkOffset = (header[offset] & 0xFF) << 16 | (header[offset + 1] & 0xFF) << 8 | header[offset + 2] & 0xFF; + int sectorCount = header[offset + 3] & 0xFF; + if (chunkOffset > 0 && sectorCount > 0) { + ++count; + } + ++i; + } + return count; + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("HyperScanner: failed to read region header {}: {}", (Object)regionFile.getFileName(), (Object)e.getMessage()); + } + return count; + } + + private int resolveWorkerCount() { + int configured = (Integer)Config.COMMON.scan.maxScanThreads.get(); + int cores = Runtime.getRuntime().availableProcessors(); + if (configured <= 0) { + return Math.max(1, cores); + } + return Math.max(1, Math.min(configured, cores)); + } + } + + private record RegionInfo(int regionX, int regionZ, int chunkCount) { + } + + private record RegionTask(ServerLevel level, Path file, int regionX, int regionZ) { + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/BlurTestPacket.java b/src/main/java/com/vinlanx/explosionoverhaul/BlurTestPacket.java new file mode 100644 index 0000000..671f9e4 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/BlurTestPacket.java @@ -0,0 +1,38 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.client.Blur; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.neoforge.network.NetworkEvent; + +public class BlurTestPacket { + private final int durationSeconds; + + public BlurTestPacket(int durationSeconds) { + this.durationSeconds = durationSeconds; + } + + public static void encode(BlurTestPacket msg, FriendlyByteBuf buf) { + buf.writeInt(msg.durationSeconds); + } + + public static BlurTestPacket decode(FriendlyByteBuf buf) { + return new BlurTestPacket(buf.readInt()); + } + + public static void handle(BlurTestPacket msg, Supplier ctxSupplier) { + NetworkEvent.Context ctx = ctxSupplier.get(); + ctx.enqueueWork(() -> BlurTestPacket.handleClient(msg)); + ctx.setPacketHandled(true); + } + + @OnlyIn(value=Dist.CLIENT) + private static void handleClient(BlurTestPacket msg) { + Blur.start(msg.durationSeconds); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/CameraShakeConcussionPacket.java b/src/main/java/com/vinlanx/explosionoverhaul/CameraShakeConcussionPacket.java new file mode 100644 index 0000000..bbb8176 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/CameraShakeConcussionPacket.java @@ -0,0 +1,41 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.client.CameraShakeConcussionEffect; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.neoforge.network.NetworkEvent; + +public class CameraShakeConcussionPacket { + private final int durationSeconds; + private final float intensity; + + public CameraShakeConcussionPacket(int durationSeconds, float intensity) { + this.durationSeconds = durationSeconds; + this.intensity = intensity; + } + + public static void encode(CameraShakeConcussionPacket msg, FriendlyByteBuf buf) { + buf.writeInt(msg.durationSeconds); + buf.writeFloat(msg.intensity); + } + + public static CameraShakeConcussionPacket decode(FriendlyByteBuf buf) { + return new CameraShakeConcussionPacket(buf.readInt(), buf.readFloat()); + } + + public static void handle(CameraShakeConcussionPacket msg, Supplier ctxSupplier) { + NetworkEvent.Context ctx = ctxSupplier.get(); + ctx.enqueueWork(() -> CameraShakeConcussionPacket.handleClient(msg)); + ctx.setPacketHandled(true); + } + + @OnlyIn(value=Dist.CLIENT) + private static void handleClient(CameraShakeConcussionPacket msg) { + CameraShakeConcussionEffect.start(msg.durationSeconds, msg.intensity); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/CameraShakePacket.java b/src/main/java/com/vinlanx/explosionoverhaul/CameraShakePacket.java new file mode 100644 index 0000000..a012de5 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/CameraShakePacket.java @@ -0,0 +1,57 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.client.ClientEffects; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.DistExecutor; +import net.neoforged.neoforge.network.NetworkEvent; + +public class CameraShakePacket { + private final float intensity; + private final int durationTicks; + private final float pushIntensity; + private final int delayTicks; + + public CameraShakePacket(float intensity, int durationTicks, float pushIntensity, int delayTicks) { + this.intensity = intensity; + this.durationTicks = durationTicks; + this.pushIntensity = pushIntensity; + this.delayTicks = delayTicks; + } + + public static void encode(CameraShakePacket msg, FriendlyByteBuf buf) { + buf.writeFloat(msg.intensity); + buf.writeInt(msg.durationTicks); + buf.writeFloat(msg.pushIntensity); + buf.writeInt(msg.delayTicks); + } + + public static CameraShakePacket decode(FriendlyByteBuf buf) { + return new CameraShakePacket(buf.readFloat(), buf.readInt(), buf.readFloat(), buf.readInt()); + } + + public static void handle(CameraShakePacket msg, Supplier ctx) { + ctx.get().enqueueWork(() -> DistExecutor.unsafeRunWhenOn((Dist)Dist.CLIENT, () -> () -> ClientEffects.triggerDelayedCameraShake(msg.getIntensity(), msg.getDurationTicks(), msg.getPushIntensity(), msg.getDelayTicks()))); + ctx.get().setPacketHandled(true); + } + + public float getIntensity() { + return this.intensity; + } + + public int getDurationTicks() { + return this.durationTicks; + } + + public float getPushIntensity() { + return this.pushIntensity; + } + + public int getDelayTicks() { + return this.delayTicks; + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ClientSoundHandler.java b/src/main/java/com/vinlanx/explosionoverhaul/ClientSoundHandler.java new file mode 100644 index 0000000..83e9c27 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ClientSoundHandler.java @@ -0,0 +1,37 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import net.neoforged.neoforge.client.event.sound.PlaySoundEvent; +import net.neoforged.neoforge.event.TickEvent; +import net.neoforged.bus.api.EventPriority; +import net.neoforged.bus.api.SubscribeEvent; + +public class ClientSoundHandler { + private static boolean suppressVanillaExplosionSound = false; + private static int suppressionTicksRemaining = 0; + + public static void setSuppressVanillaExplosionSound(boolean suppress, int durationTicks) { + suppressVanillaExplosionSound = suppress; + suppressionTicksRemaining = durationTicks; + } + + @SubscribeEvent + public void onClientTick(TickEvent.ClientTickEvent event) { + if (event.phase == TickEvent.Phase.END) { + if (suppressionTicksRemaining > 0) { + --suppressionTicksRemaining; + } else if (suppressionTicksRemaining == 0 && suppressVanillaExplosionSound) { + suppressVanillaExplosionSound = false; + } + } + } + + @SubscribeEvent(priority=EventPriority.HIGH) + public void onExplosionSound(PlaySoundEvent event) { + if (event.getSound() != null && event.getSound().m_7904_().m_135815_().equals("entity.generic.explode") && suppressVanillaExplosionSound) { + event.setSound(null); + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/Config.java b/src/main/java/com/vinlanx/explosionoverhaul/Config.java new file mode 100644 index 0000000..d1eacfd --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/Config.java @@ -0,0 +1,368 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import java.io.BufferedReader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; +import net.neoforged.neoforge.common.ForgeConfigSpec; +import net.neoforged.fml.loading.FMLPaths; +import org.apache.commons.lang3.tuple.Pair; + +public class Config { + public static final ForgeConfigSpec CLIENT_SPEC; + public static final Client CLIENT; + public static final ForgeConfigSpec COMMON_SPEC; + public static final Common COMMON; + + public static boolean isFirstLaunch() { + if (((Boolean)Config.CLIENT.firstLaunchComplete.get()).booleanValue()) { + return false; + } + try { + Boolean fileVal = Config.readFirstLaunchFromFile(); + if (fileVal != null && fileVal.booleanValue()) { + Config.CLIENT.firstLaunchComplete.set((Object)true); + return false; + } + } + catch (Exception exception) { + // empty catch block + } + return true; + } + + public static void markFirstLaunchComplete() { + Config.CLIENT.firstLaunchComplete.set((Object)true); + CLIENT_SPEC.save(); + } + + /* + * Enabled aggressive block sorting + * Enabled unnecessary exception pruning + * Enabled aggressive exception aggregation + */ + private static Boolean readFirstLaunchFromFile() { + Path configPath = FMLPaths.CONFIGDIR.get().resolve("explosionoverhaul").resolve("explosionoverhaul-client.toml"); + if (!Files.exists(configPath, new LinkOption[0])) { + return null; + } + try (BufferedReader reader = Files.newBufferedReader(configPath);){ + int eq; + String line; + String trimmed; + do { + if ((line = reader.readLine()) == null) return null; + } while (!(trimmed = line.trim()).startsWith("firstLaunchComplete") || (eq = trimmed.indexOf(61)) <= 0); + String val = trimmed.substring(eq + 1).trim(); + if (val.startsWith("\"") && val.endsWith("\"")) { + val = val.substring(1, val.length() - 1); + } + Boolean bl = Boolean.parseBoolean(val); + return bl; + } + catch (IOException iOException) { + // empty catch block + } + return null; + } + + static { + Pair clientSpecPair = new ForgeConfigSpec.Builder().configure(Client::new); + CLIENT_SPEC = (ForgeConfigSpec)clientSpecPair.getRight(); + CLIENT = (Client)clientSpecPair.getLeft(); + Pair commonSpecPair = new ForgeConfigSpec.Builder().configure(Common::new); + COMMON_SPEC = (ForgeConfigSpec)commonSpecPair.getRight(); + COMMON = (Common)commonSpecPair.getLeft(); + } + + public static class Client { + public final ForgeConfigSpec.EnumValue glowTextureQuality; + public final ForgeConfigSpec.EnumValue particleRenderMode; + public final ForgeConfigSpec.DoubleValue particleSizeScale; + public final ForgeConfigSpec.BooleanValue firstLaunchComplete; + public final ForgeConfigSpec.BooleanValue enableGroundDustEffect; + public final ForgeConfigSpec.DoubleValue groundDustQuality; + public final ForgeConfigSpec.IntValue groundDustRaycastFrequency; + public final ForgeConfigSpec.BooleanValue enableGroundMistEffect; + public final ForgeConfigSpec.DoubleValue groundMistQuality; + public final ForgeConfigSpec.IntValue groundMistRaycastFrequency; + public final ForgeConfigSpec.BooleanValue enableExplosionParticles; + public final ForgeConfigSpec.BooleanValue enablePlasmaParticles; + public final ForgeConfigSpec.BooleanValue enablePlasmaSmokeTrail; + public final ForgeConfigSpec.DoubleValue plasmaSmokeFrequency; + public final ForgeConfigSpec.IntValue plasmaSmokeCount; + public final ForgeConfigSpec.BooleanValue enableFlashEffect; + public final ForgeConfigSpec.DoubleValue flashMaxOpacity; + public final ForgeConfigSpec.BooleanValue enableLineSparks; + public final ForgeConfigSpec.DoubleValue lineSparkAmountMultiplier; + public final ForgeConfigSpec.BooleanValue enableCameraShake; + public final ForgeConfigSpec.DoubleValue cameraShakeAmplifier; + public final ForgeConfigSpec.BooleanValue enableShockwaveEffect; + public final ForgeConfigSpec.BooleanValue showWindControls; + public final ForgeConfigSpec.DoubleValue windVisualizationOpacity; + public final ForgeConfigSpec.BooleanValue enableWindEffect; + public final ForgeConfigSpec.DoubleValue windSpeedMultiplier; + public final ForgeConfigSpec.BooleanValue enableConcussion; + public final ForgeConfigSpec.DoubleValue concussionDurationMultiplier; + public final ForgeConfigSpec.DoubleValue concussionChanceMultiplier; + public final ForgeConfigSpec.BooleanValue enableHeartbeatPulse; + public final ForgeConfigSpec.BooleanValue enableCameraSway; + public final ForgeConfigSpec.DoubleValue cameraSwayIntensity; + public final ForgeConfigSpec.BooleanValue enableDeafness; + public final ForgeConfigSpec.BooleanValue enableLowPass; + public final ForgeConfigSpec.DoubleValue deafnessChanceMultiplier; + public final ForgeConfigSpec.DoubleValue lowPassChanceMultiplier; + public final ForgeConfigSpec.BooleanValue showHeartbeatHUD; + + Client(ForgeConfigSpec.Builder builder) { + builder.comment("Visual effect settings (client-side only)").push("Render Settings"); + this.glowTextureQuality = builder.comment(new String[]{"Quality of the main explosion fireball textures (glow, glow_2, sglow).", "Lower quality (64p) can significantly improve performance on systems with less VRAM.", "Requires a resource pack reload (F3+T) to apply the change."}).defineEnum("glowTextureQuality", (Enum)GlowTextureQuality.QUALITY_256); + this.particleRenderMode = builder.comment(new String[]{"Particle rendering system mode:", "REALISTIC - Uses animated sprite sheets with complex textures (current system)", "VANILA - Vanilla-like simple textures with color phases (better performance)"}).defineEnum("particleRenderMode", (Enum)ParticleRenderMode.VANILA); + this.particleSizeScale = builder.comment(new String[]{"Scales the size of all explosion particles across all render modes.", "1.0 = default size, 0.1 = 10% of default, 5.0 = 500% of default."}).defineInRange("particleSizeScale", 1.0, 0.1, 5.0); + this.firstLaunchComplete = builder.comment("Internal flag: marks whether the first-time setup screen has been shown.").define("firstLaunchComplete", false); + builder.comment("\nCore explosion visual effects"); + this.enableExplosionParticles = builder.comment("Enables the main fiery glow particles (glow, glow_2, sglow). Disabling this can significantly improve performance.").define("enableExplosionParticles", true); + builder.comment("\nPlasma particle effects"); + this.enablePlasmaParticles = builder.comment("Enables or disables plasma sparks entirely.").define("enablePlasmaParticles", true); + this.enablePlasmaSmokeTrail = builder.comment("Enables the smoke trail that follows plasma sparks.").define("enablePlasmaSmokeTrail", true); + this.plasmaSmokeFrequency = builder.comment("Frequency of plasma smoke spawning. 0.0 = no smoke, 0.7 = default chance (70%), 1.0 = always spawn smoke.").defineInRange("plasmaSmokeFrequency", 0.25, 0.0, 1.0); + this.plasmaSmokeCount = builder.comment("Number of smoke particles spawned per plasma particle tick. Default was 2.").defineInRange("plasmaSmokeCount", 1, 0, 5); + this.enableFlashEffect = builder.comment("Enables the flash overlay effect on explosions.").define("enableFlashEffect", true); + this.flashMaxOpacity = builder.comment("Maximum opacity of the flash effect overlay. 0.0 = no flash, 1.0 = full opacity.").defineInRange("flashMaxOpacity", 0.5, 0.0, 1.0); + builder.comment("\nConfiguration for the electrical spark effects"); + this.enableLineSparks = builder.comment("Enables or disables the electrical line sparks that shoot out from explosions.").define("enableLineSparks", true); + this.lineSparkAmountMultiplier = builder.comment(new String[]{"Multiplier for the number of sparks generated by an explosion.", "0.0 = no sparks, 1.0 = default amount, 2.0 = double amount.", "Higher values can impact performance."}).defineInRange("lineSparkAmountMultiplier", 1.0, 0.0, 5.0); + builder.comment("\nConfiguration for the ground dust cloud effect"); + this.enableGroundDustEffect = builder.comment("Enables or disables the dust cloud effect from explosions.").define("enableGroundDustEffect", true); + this.groundDustQuality = builder.comment(new String[]{"Quality of the dust cloud effect. Affects particle count and duration.", "Lower values can improve performance on weaker PCs.", "0.0 = minimum particles, 1.0 = default quality."}).defineInRange("groundDustQuality", 1.0, 0.0, 1.0); + this.groundDustRaycastFrequency = builder.comment(new String[]{"Dust Propagation Quality. Controls how often dust particles check for the ground beneath them.", "A value of 1 means every particle checks (highest quality, high performance cost).", "A value of 10 means every 10th particle checks (default performance)."}).defineInRange("groundDustRaycastFrequency", 10, 1, 20); + builder.comment("\nConfiguration for the ground mist effect"); + this.enableGroundMistEffect = builder.comment("Enables or disables the mist cloud effect from explosions.").define("enableGroundMistEffect", true); + this.groundMistQuality = builder.comment(new String[]{"Quality of the mist cloud effect. Affects particle count and duration.", "Lower values can improve performance on weaker PCs.", "0.0 = minimum particles, 1.0 = default quality."}).defineInRange("groundMistQuality", 1.0, 0.0, 1.0); + this.groundMistRaycastFrequency = builder.comment(new String[]{"Mist Propagation Quality. Controls how often mist particles check for the ground beneath them.", "A value of 1 means every particle checks (highest quality, high performance cost).", "A value of 10 means every 10th particle checks (default performance)."}).defineInRange("groundMistRaycastFrequency", 10, 1, 20); + builder.comment("\nConfiguration for the shockwave effect"); + this.enableShockwaveEffect = builder.comment("Enables or disables the shockwave particle effect from explosions.").define("enableShockwaveEffect", true); + builder.pop(); + builder.comment("\nCamera shake settings").push("Camera Shake"); + this.enableCameraShake = builder.comment("Enables or disables the camera shake effect from explosions.").define("enableCameraShake", true); + this.cameraShakeAmplifier = builder.comment("Amplifier for the camera shake intensity. 0.0 = no shake, 1.0 = default, 10.0 = maximum shake.").defineInRange("cameraShakeAmplifier", 1.0, 0.0, 10.0); + builder.pop(); + builder.comment("\nWind Effect Settings").push("Wind System"); + this.enableWindEffect = builder.comment(new String[]{"Enables or disables the wind effect that moves explosion particles (dust and glow).", "When disabled, particles will not be affected by wind and will behave as they originally did."}).define("enableWindEffect", true); + this.windSpeedMultiplier = builder.comment(new String[]{"Speed multiplier for the wind effect on particles.", "1.0 = default wind speed, 1.5 = 50% faster, 2.0 = double speed.", "Supports precise values like 1.01, 1.25, 1.75, etc.", "Higher values make particles move faster in the wind direction."}).defineInRange("windSpeedMultiplier", 1.0, 1.0, 2.0); + builder.comment("\nWind Visualization").push("Wind Visualization"); + this.showWindControls = builder.comment(new String[]{"Shows additional wind control information in debug screens or overlays.", "This is a client-only visual setting that doesn't affect gameplay."}).define("showWindControls", false); + this.windVisualizationOpacity = builder.comment(new String[]{"Opacity of wind direction visualization effects (if any are implemented).", "0.0 = invisible, 1.0 = fully opaque."}).defineInRange("windVisualizationOpacity", 0.3, 0.0, 1.0); + builder.pop(); + builder.comment("\nConcussion Effect Settings").push("Concussion"); + this.enableConcussion = builder.comment("Enables or disables the concussion system (blur, deafness, heartbeat, etc.)").define("enableConcussion", true); + this.concussionDurationMultiplier = builder.comment("Multiplier for the duration of concussion effects.").defineInRange("concussionDurationMultiplier", 1.0, 0.0, 5.0); + this.concussionChanceMultiplier = builder.comment("General chance multiplier for all concussion effects.").defineInRange("concussionChanceMultiplier", 1.0, 0.0, 5.0); + this.enableHeartbeatPulse = builder.comment("Enables or disables the visual screen pulse and audio heartbeat (lub-dub).").define("enableHeartbeatPulse", true); + this.enableCameraSway = builder.comment("Enables or disables the camera sway (disorientation) effect.").define("enableCameraSway", true); + this.cameraSwayIntensity = builder.comment("Intensity (radius) multiplier for camera sway.").defineInRange("cameraSwayIntensity", 1.0, 0.0, 5.0); + this.enableDeafness = builder.comment("Enables or disables the high-pitched ringing (deafness) effect.").define("enableDeafness", true); + this.enableLowPass = builder.comment("Enables or disables the low-pass (muffled sound) effect.").define("enableLowPass", true); + this.deafnessChanceMultiplier = builder.comment("Multiplier for the chance of deafness occurring.").defineInRange("deafnessChanceMultiplier", 1.0, 0.0, 5.0); + this.lowPassChanceMultiplier = builder.comment("Multiplier for the chance of low-pass effect occurring.").defineInRange("lowPassChanceMultiplier", 1.0, 0.0, 5.0); + this.showHeartbeatHUD = builder.comment("Whether to show the Heartbeat BPM/BPS HUD in the top-right corner.").define("showHeartbeatHUD", false); + builder.pop(); + builder.pop(); + } + + public static enum GlowTextureQuality { + QUALITY_256, + QUALITY_64; + + } + + public static enum ParticleRenderMode { + REALISTIC, + REALISTIC_2, + VANILA; + + } + } + + public static class Common { + public final ForgeConfigSpec.BooleanValue enablePlayerShake; + public final ForgeConfigSpec.DoubleValue playerShakeAmplifier; + public final ForgeConfigSpec.BooleanValue enableCraterDestruction; + public final ForgeConfigSpec.BooleanValue enableFallingBlocks; + public final ForgeConfigSpec.BooleanValue enableExplosionClustering; + public final ForgeConfigSpec.IntValue maxClusterPower; + public final ForgeConfigSpec.BooleanValue enableGlassBreaking; + public final ForgeConfigSpec.BooleanValue enableAsyncCrater; + public final ForgeConfigSpec.IntValue craterMaxThreads; + public final ForgeConfigSpec.IntValue craterApplyBlocksPerTick; + public final ForgeConfigSpec.IntValue craterMaxFallingBlocksPerTick; + public final ForgeConfigSpec.BooleanValue enableDirectChunkWrites; + public final ForgeConfigSpec.IntValue craterChunksPerTick; + public final ForgeConfigSpec.IntValue glassBreakingIntervalTicks; + public final ForgeConfigSpec.IntValue glassBlocksPerCycle; + public final ForgeConfigSpec.DoubleValue craterSizeMultiplier; + public final ForgeConfigSpec.DoubleValue craterCoreRatio; + public final ForgeConfigSpec.BooleanValue enableLampFlicker; + public final ForgeConfigSpec.IntValue lampFlickerSearchRadius; + public final ForgeConfigSpec.BooleanValue enableDripstoneFalling; + public final ForgeConfigSpec.IntValue dripstoneFallingSearchRadius; + public final ForgeConfigSpec.BooleanValue enableAdvancedSoundSpeed; + public final Ambient ambient; + public final Scan scan; + + Common(ForgeConfigSpec.Builder builder) { + builder.comment("Sound system settings").push("Sounds"); + this.enableAdvancedSoundSpeed = builder.comment("Enable advanced sound speed system for explosions. If disabled, sound always travels at 343 m/s.").define("enableAdvancedSoundSpeed", false); + builder.pop(); + builder.comment("\nPlayer shake settings").push("Player Shake"); + this.enablePlayerShake = builder.comment("Enables or disables the player shake effect from explosions.").define("enablePlayerShake", true); + this.playerShakeAmplifier = builder.comment("Amplifier for the player shake intensity. 0.0 = no shake, 1.0 = default, 10.0 = maximum shake.").defineInRange("playerShakeAmplifier", 1.0, 0.0, 10.0); + builder.pop(); + builder.comment("Common settings that will be synced from server to client.").push("General"); + this.enableFallingBlocks = builder.comment(new String[]{"Enables or disables blocks being launched from explosions.", "If false, explosions will still destroy blocks but won't create falling block entities."}).define("enableFallingBlocks", true); + this.enableExplosionClustering = builder.comment(new String[]{"Enables or disables the clustering of nearby explosives into a single, more powerful explosion.", "If true, multiple TNT blocks/entities close together will merge into one explosion with increased power."}).define("enableExplosionClustering", true); + this.maxClusterPower = builder.comment(new String[]{"Maximum total power for clustered TNT explosions.", "4 = minimum (single TNT), 100 = default, 1000 = extreme (high crash risk).", "WARNING: Values above 150 may cause rendering lag. Values above 500 risk game crashes."}).defineInRange("maxClusterPower", 100, 4, 1000); + this.enableDripstoneFalling = builder.comment("Enables or disables the falling effect for pointed dripstone near explosions.").define("enableDripstoneFalling", true); + this.enableCraterDestruction = builder.comment(new String[]{"Enables or disables the destruction of blocks, creating craters.", "If false, explosions will still cause visual and sound effects, but won't break blocks."}).define("enableCraterDestruction", true); + this.enableGlassBreaking = builder.comment("Enables or disables glass being shattered by the explosion's shockwave.").define("enableGlassBreaking", true); + this.enableLampFlicker = builder.comment("Enables or disables the flickering effect on Redstone Lamps near explosions.").define("enableLampFlicker", true); + builder.pop(); + builder.comment("\nDripstone Falling").push("Dripstone Falling"); + this.dripstoneFallingSearchRadius = builder.comment(new String[]{"The radius around the explosion in which to search for pointed dripstone to fall.", "Warning: High values on servers with many players and dripstones can cause lag."}).defineInRange("dripstoneFallingSearchRadius", 50, 1, 100); + builder.pop(); + builder.comment("\nFine-tuning for the glass breaking effect. High values can impact performance.").push("Glass Breaking"); + this.glassBreakingIntervalTicks = builder.comment(new String[]{"The interval in game ticks between each glass breaking cycle.", "1 tick = 0.05 seconds. Lower values make the effect smoother but use more server resources.", "Default: 1"}).defineInRange("glassBreakingIntervalTicks", 1, 1, 20); + this.glassBlocksPerCycle = builder.comment(new String[]{"The maximum number of glass blocks that can be broken in a single processing cycle.", "This prevents server lag from massive explosions. Higher values can handle large glass structures better but may cause spikes.", "Default: 70"}).defineInRange("glassBlocksPerCycle", 70, 10, 500); + builder.pop(); + builder.comment("\nCrater Customization").push("Crater Settings"); + this.craterSizeMultiplier = builder.comment(new String[]{"Multiplier for the radius of the explosion crater.", "Affects both crater size and the number of generated particles.", "1.0 = default size."}).defineInRange("craterSizeMultiplier", 1.0, 0.1, 50.0); + this.craterCoreRatio = builder.comment(new String[]{"For explosions with power 40+, this controls the shape of the crater.", "Determines the size of the solid 'core' relative to the total radius.", "0.1 = very ray-like, 0.95 = almost a perfect sphere.", "Default: 0.7 (70%)"}).defineInRange("craterCoreRatio", 0.7, 0.1, 0.95); + builder.pop(); + int availableThreadsForCrater = Runtime.getRuntime().availableProcessors(); + int maxThreadsForSystemCrater = Math.min(32, availableThreadsForCrater); + builder.comment("\nAsync crater pipeline (off-thread ray geometry + main-thread batched application)").push("Async Crater"); + this.enableAsyncCrater = builder.comment(new String[]{"Enable the asynchronous crater pipeline.", "Compute crater geometry off-thread and apply block changes in small batches per tick to keep TPS smooth on large explosions.", "", "WARNING: When asynchronous and multi-threaded mode is enabled - destruction of VS objects - does not work."}).define("enableAsyncCrater", true); + this.craterMaxThreads = builder.comment(new String[]{"Maximum number of threads for off-thread crater geometry precomputation.", "0 = Auto (use all available: " + availableThreadsForCrater + ")", "1 = Single-threaded", "2-" + maxThreadsForSystemCrater + " = Custom thread count for this system"}).defineInRange("craterMaxThreads", 0, 0, maxThreadsForSystemCrater); + this.craterApplyBlocksPerTick = builder.comment(new String[]{"Maximum number of blocks to evaluate/apply per server tick when building a crater.", "Higher values complete faster but can cause small TPS dips.", "Lower values keep TPS flatter but take longer."}).defineInRange("craterApplyBlocksPerTick", 50000, 0, 150000); + this.craterMaxFallingBlocksPerTick = builder.comment(new String[]{"Limit of falling block entities to spawn per tick during crater application (visual debris).", "Set to 0 to disable spawning via the async pipeline."}).defineInRange("craterMaxFallingBlocksPerTick", 500, 0, 2000); + this.enableDirectChunkWrites = builder.comment(new String[]{"Directly write block states into chunk sections during crater application (much faster).", "When enabled, bypasses Level#setBlock and updates heightmaps/light manually.", "Note: This skips Forge block events and neighbor updates."}).define("enableDirectChunkWrites", true); + this.craterChunksPerTick = builder.comment(new String[]{"Maximum number of chunks to process per tick when direct writes are enabled.", "Used along with block budget to smooth TPS."}).defineInRange("craterChunksPerTick", 120, 0, 500); + builder.pop(); + builder.comment("\nRedstone Lamp Flickering").push("Lamp Flickering"); + this.lampFlickerSearchRadius = builder.comment(new String[]{"The radius around the player in which to search for lamps to flicker.", "Warning: High values on servers with many players and lamps can cause lag."}).defineInRange("lampFlickerSearchRadius", 50, 1, 100); + builder.pop(); + this.ambient = new Ambient(builder); + this.scan = new Scan(builder); + } + + public static class Ambient { + public final ForgeConfigSpec.BooleanValue enableAmbientExplosions; + public final ForgeConfigSpec.IntValue minTimeBetweenExplosions; + public final ForgeConfigSpec.IntValue maxTimeBetweenExplosions; + public final ForgeConfigSpec.IntValue minExplosionDistance; + public final ForgeConfigSpec.IntValue maxExplosionDistance; + public final ForgeConfigSpec.DoubleValue maxAmbientExplosionPower; + public final Scenarios scenarios; + public final PowerTiers powerTiers; + public final SoundTypes soundTypes; + + Ambient(ForgeConfigSpec.Builder builder) { + builder.comment("Settings for the ambient explosion system, creating a 'battlefield' atmosphere.").push("Ambient"); + this.enableAmbientExplosions = builder.comment("Globally enables or disables the ambient explosion sound system.").define("enableAmbientExplosions", false); + this.minTimeBetweenExplosions = builder.comment("Minimum time in ticks between ambient explosion events (20 ticks = 1 second).").defineInRange("minTimeBetweenExplosions", 1200, 100, 72000); + this.maxTimeBetweenExplosions = builder.comment("Maximum time in ticks between ambient explosion events.").defineInRange("maxTimeBetweenExplosions", 6000, 200, 72000); + this.minExplosionDistance = builder.comment("Minimum distance in blocks from the player where an ambient sound can originate.").defineInRange("minExplosionDistance", 501, 100, 10000); + this.maxExplosionDistance = builder.comment("Maximum distance in blocks from the player where an ambient sound can originate.").defineInRange("maxExplosionDistance", 5001, 200, 10000); + this.maxAmbientExplosionPower = builder.comment("The maximum power a random 'Cataclysm' tier explosion can have.").defineInRange("maxAmbientExplosionPower", 80.0, 40.0, 200.0); + this.scenarios = new Scenarios(builder); + this.powerTiers = new PowerTiers(builder); + this.soundTypes = new SoundTypes(builder); + builder.pop(); + } + + public static class Scenarios { + public final ForgeConfigSpec.IntValue singleExplosionWeight; + public final ForgeConfigSpec.IntValue chainReactionWeight; + public final ForgeConfigSpec.IntValue shellingWeight; + public final ForgeConfigSpec.IntValue minChainReactionShots; + public final ForgeConfigSpec.IntValue maxChainReactionShots; + public final ForgeConfigSpec.IntValue minTimeBetweenChainShots; + public final ForgeConfigSpec.IntValue maxTimeBetweenChainShots; + public final ForgeConfigSpec.IntValue minShellingDelay; + public final ForgeConfigSpec.IntValue maxShellingDelay; + + Scenarios(ForgeConfigSpec.Builder builder) { + builder.comment(new String[]{"\nConfiguration for different ambient event scenarios.", "The chance for a scenario is (its_weight / sum_of_all_scenario_weights)."}).push("Scenarios"); + this.singleExplosionWeight = builder.comment("Weight for a standard, single explosion event.").defineInRange("singleExplosionWeight", 70, 0, 1000); + this.chainReactionWeight = builder.comment("Weight for a 'Chain Reaction' event (a series of increasingly powerful explosions).").defineInRange("chainReactionWeight", 15, 0, 1000); + this.shellingWeight = builder.comment("Weight for an 'Artillery Shelling' event (a quiet shot followed by a delayed, loud impact).").defineInRange("shellingWeight", 15, 0, 1000); + builder.comment("\nSettings for the 'Chain Reaction' scenario.").push("ChainReaction"); + this.minChainReactionShots = builder.defineInRange("minChainReactionShots", 3, 2, 20); + this.maxChainReactionShots = builder.defineInRange("maxChainReactionShots", 7, 2, 20); + this.minTimeBetweenChainShots = builder.defineInRange("minTimeBetweenChainShots", 10, 5, 200); + this.maxTimeBetweenChainShots = builder.defineInRange("maxTimeBetweenChainShots", 40, 10, 400); + builder.pop(); + builder.comment("\nSettings for the 'Artillery Shelling' scenario.").push("Shelling"); + this.minShellingDelay = builder.comment("Minimum delay in ticks between the 'shot' sound and the 'impact' sound (20 ticks = 1s).").defineInRange("minShellingDelay", 40, 20, 400); + this.maxShellingDelay = builder.comment("Maximum delay in ticks between the 'shot' and 'impact' sounds.").defineInRange("maxShellingDelay", 140, 20, 400); + builder.pop(); + builder.pop(); + } + } + + public static class PowerTiers { + public final ForgeConfigSpec.IntValue tier1_weight; + public final ForgeConfigSpec.IntValue tier2_weight; + public final ForgeConfigSpec.IntValue tier3_weight; + public final ForgeConfigSpec.IntValue tier4_weight; + public final ForgeConfigSpec.IntValue tier5_weight; + + PowerTiers(ForgeConfigSpec.Builder builder) { + builder.comment(new String[]{"\nWeighted chances for explosion power tiers (for single and shelling events).", "The chance for a tier is (its_weight / sum_of_all_weights). Set a weight to 0 to disable that tier."}).push("Power_Tiers_Weight"); + this.tier1_weight = builder.comment("Weight for 'Background Noise' (Power 1-4)").defineInRange("tier1_weight", 50, 0, 1000); + this.tier2_weight = builder.comment("Weight for 'Local Skirmish' (Power 5-15)").defineInRange("tier2_weight", 25, 0, 1000); + this.tier3_weight = builder.comment("Weight for 'Serious Battle' (Power 16-40)").defineInRange("tier3_weight", 15, 0, 1000); + this.tier4_weight = builder.comment("Weight for 'Epicenter' (Power 41-80)").defineInRange("tier4_weight", 8, 0, 1000); + this.tier5_weight = builder.comment("Weight for 'Cataclysm' (Power 81+)").defineInRange("tier5_weight", 2, 0, 1000); + builder.pop(); + } + } + + public static class SoundTypes { + public final ForgeConfigSpec.BooleanValue enableSurfaceSounds; + public final ForgeConfigSpec.BooleanValue enableCaveSounds; + public final ForgeConfigSpec.BooleanValue enableAmbientCaveDust; + + SoundTypes(ForgeConfigSpec.Builder builder) { + builder.comment("\nEnable or disable specific types of ambient sound environments.").push("Sound_Types"); + this.enableSurfaceSounds = builder.comment("Surface: A clear explosion sound in an open area.").define("enableSurfaceSounds", true); + this.enableCaveSounds = builder.comment("Cave: A loud, reverberating sound when both player and explosion are in a cave.").define("enableCaveSounds", true); + this.enableAmbientCaveDust = builder.comment("If enabled, an ambient cave explosion will cause a visual dust effect to fall from the ceiling.").define("enableAmbientCaveDust", true); + builder.pop(); + } + } + } + + public static class Scan { + public final ForgeConfigSpec.IntValue maxScanThreads; + public final ForgeConfigSpec.IntValue cpuUsagePercent; + public final ForgeConfigSpec.BooleanValue enableBlockIndexing; + public final ForgeConfigSpec.BooleanValue showScanProgressHUD; + + Scan(ForgeConfigSpec.Builder builder) { + int availableThreads = Runtime.getRuntime().availableProcessors(); + builder.comment(new String[]{"Settings for chunk scanning and block indexing system.", "System detected: " + availableThreads + " CPU threads available", "Configuration ranges are automatically adjusted for your system"}).push("Scan"); + int maxThreadsForSystem = Math.min(32, availableThreads); + this.maxScanThreads = builder.comment(new String[]{"Maximum number of threads to use for chunk scanning.", "Available range for your system: 0-" + maxThreadsForSystem + " threads", "0 = Auto-detect (recommended): uses all " + availableThreads + " available threads", "1 = Single-threaded (slowest but safest)", "2-" + maxThreadsForSystem + " = Custom thread count for this system", "Your system supports up to " + availableThreads + " concurrent threads"}).defineInRange("maxScanThreads", 0, 0, maxThreadsForSystem); + this.cpuUsagePercent = builder.comment(new String[]{"How much CPU power to use for chunk scanning (1-100%).", "100% = Maximum speed, uses all available threads intensively", "50% = Balanced, leaves room for other server processes", "25% = Conservative, minimal impact on server performance", "Lower values add delays between chunk processing to reduce CPU load."}).defineInRange("cpuUsagePercent", 75, 1, 100); + this.enableBlockIndexing = builder.comment(new String[]{"Enables or disables the block indexing system.", "When enabled, chunks are automatically scanned for Redstone Lamps and Pointed Dripstone.", "When disabled, only manual registration/unregistration of blocks will occur.", "This affects Redstone Lamp flickering and Pointed Dripstone falling effects near explosions."}).define("enableBlockIndexing", true); + this.showScanProgressHUD = builder.comment(new String[]{"Controls visibility of the scanning progress HUD.", "When disabled, no progress bar will be shown even if scanning is enabled.", "Shows percentage of chunks scanned during world initialization and automatically hides when complete."}).define("showScanProgressHUD", true); + builder.pop(); + } + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/CraterDeformer.java b/src/main/java/com/vinlanx/explosionoverhaul/CraterDeformer.java new file mode 100644 index 0000000..debbede --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/CraterDeformer.java @@ -0,0 +1,244 @@ +/* + * 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.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 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(); + } + HashSet blocksToDestroy = new HashSet(); + 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; + } + + 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; + } + + 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 void apply(ServerLevel level, Vec3 explosionPos, float power) { + if (power >= 40.0f) { + CraterDeformer.applyLargeExplosionLogic(level, explosionPos, power); + } else { + CraterDeformer.applySmallExplosionLogic(level, explosionPos, 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 blocksToDestroy = new HashSet(); + HashSet blocksToLaunch = new HashSet(); + 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 blocksToDestroy = new HashSet(); + HashSet blocksToLaunch = new HashSet(); + 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 blocksToDestroy, Set 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); + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/CustomGlowParticleOptions.java b/src/main/java/com/vinlanx/explosionoverhaul/CustomGlowParticleOptions.java new file mode 100644 index 0000000..65b769a --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/CustomGlowParticleOptions.java @@ -0,0 +1,116 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.datafixers.kinds.App; +import com.mojang.datafixers.kinds.Applicative; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import com.vinlanx.explosionoverhaul.ModParticles; +import java.util.Locale; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.ParticleType; +import net.minecraft.network.FriendlyByteBuf; + +public class CustomGlowParticleOptions +implements ParticleOptions { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group((App)Codec.INT.fieldOf("zone").forGetter(CustomGlowParticleOptions::getZone), (App)Codec.FLOAT.fieldOf("power").forGetter(CustomGlowParticleOptions::getPower), (App)Codec.FLOAT.fieldOf("scale").forGetter(CustomGlowParticleOptions::getScale), (App)Codec.INT.fieldOf("animationType").forGetter(CustomGlowParticleOptions::getAnimationType), (App)Codec.FLOAT.fieldOf("centerY").forGetter(CustomGlowParticleOptions::getCenterY), (App)Codec.FLOAT.fieldOf("maxRadius").forGetter(CustomGlowParticleOptions::getMaxRadius), (App)Codec.FLOAT.fieldOf("heightPercent").forGetter(CustomGlowParticleOptions::getHeightPercent)).apply((Applicative)instance, CustomGlowParticleOptions::new)); + public static final ParticleOptions.Deserializer DESERIALIZER = new ParticleOptions.Deserializer(){ + + public CustomGlowParticleOptions fromCommand(ParticleType particleType, StringReader reader) throws CommandSyntaxException { + reader.expect(' '); + int zone = reader.readInt(); + reader.expect(' '); + float power = reader.readFloat(); + reader.expect(' '); + float scale = reader.readFloat(); + reader.expect(' '); + int animationType = reader.readInt(); + reader.expect(' '); + float centerY = reader.readFloat(); + reader.expect(' '); + float maxRadius = reader.readFloat(); + reader.expect(' '); + float heightPercent = reader.readFloat(); + return new CustomGlowParticleOptions(zone, power, scale, animationType, centerY, maxRadius, heightPercent); + } + + public CustomGlowParticleOptions fromNetwork(ParticleType particleType, FriendlyByteBuf buffer) { + return new CustomGlowParticleOptions(buffer.readInt(), buffer.readFloat(), buffer.readFloat(), buffer.readInt(), buffer.readFloat(), buffer.readFloat(), buffer.readFloat()); + } + }; + private final int zone; + private final float power; + private final float scale; + private final int animationType; + private final float centerY; + private final float maxRadius; + private final float heightPercent; + + public CustomGlowParticleOptions(int zone, float power, float scale, int animationType, float centerY, float maxRadius, float heightPercent) { + this.zone = zone; + this.power = power; + this.scale = scale; + this.animationType = animationType; + this.centerY = centerY; + this.maxRadius = maxRadius; + this.heightPercent = heightPercent; + } + + public CustomGlowParticleOptions(int zone, float power, float scale, int animationType) { + this(zone, power, scale, animationType, 0.0f, Math.max(1.0f, power * 2.0f), 0.0f); + } + + public CustomGlowParticleOptions(int zone, float power, float scale) { + this(zone, power, scale, 0, 0.0f, Math.max(1.0f, power * 2.0f), 0.0f); + } + + public ParticleType m_6012_() { + return (ParticleType)ModParticles.CUSTOM_GLOW.get(); + } + + public void m_7711_(FriendlyByteBuf buffer) { + buffer.writeInt(this.zone); + buffer.writeFloat(this.power); + buffer.writeFloat(this.scale); + buffer.writeInt(this.animationType); + buffer.writeFloat(this.centerY); + buffer.writeFloat(this.maxRadius); + buffer.writeFloat(this.heightPercent); + } + + public String m_5942_() { + return String.format(Locale.ROOT, "%s %d %.2f %.2f %d %.2f %.2f %.2f", ModParticles.CUSTOM_GLOW.getId(), this.zone, Float.valueOf(this.power), Float.valueOf(this.scale), this.animationType, Float.valueOf(this.centerY), Float.valueOf(this.maxRadius), Float.valueOf(this.heightPercent)); + } + + public int getZone() { + return this.zone; + } + + public float getPower() { + return this.power; + } + + public float getScale() { + return this.scale; + } + + public int getAnimationType() { + return this.animationType; + } + + public float getCenterY() { + return this.centerY; + } + + public float getMaxRadius() { + return this.maxRadius; + } + + public float getHeightPercent() { + return this.heightPercent; + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/DripstoneEffects.java b/src/main/java/com/vinlanx/explosionoverhaul/DripstoneEffects.java new file mode 100644 index 0000000..588bdf7 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/DripstoneEffects.java @@ -0,0 +1,122 @@ +/* + * 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 dripstoneQueue = new ConcurrentLinkedQueue(); + private static final int MAX_DRIPSTONE_TASKS_PER_LEVEL_PER_TICK = 25; + + 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 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 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 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; + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ExplosionClusterHandler.java b/src/main/java/com/vinlanx/explosionoverhaul/ExplosionClusterHandler.java new file mode 100644 index 0000000..1b8ac44 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ExplosionClusterHandler.java @@ -0,0 +1,137 @@ +/* + * 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 tntBlocks = new ArrayList(); + 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 sources = new ArrayList(); + 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; + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ExplosionOverhaul.java b/src/main/java/com/vinlanx/explosionoverhaul/ExplosionOverhaul.java new file mode 100644 index 0000000..eb324aa --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ExplosionOverhaul.java @@ -0,0 +1,681 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.logging.LogUtils; +import com.vinlanx.explosionoverhaul.AmbientExplosionManager; +import com.vinlanx.explosionoverhaul.AsyncCraterManager; +import com.vinlanx.explosionoverhaul.BlockIndexManager; +import com.vinlanx.explosionoverhaul.ClientSoundHandler; +import com.vinlanx.explosionoverhaul.Config; +import com.vinlanx.explosionoverhaul.CustomGlowParticleOptions; +import com.vinlanx.explosionoverhaul.DripstoneEffects; +import com.vinlanx.explosionoverhaul.GlassBreakingEffects; +import com.vinlanx.explosionoverhaul.ModBlockEntities; +import com.vinlanx.explosionoverhaul.ModBlocks; +import com.vinlanx.explosionoverhaul.ModCreativeTabs; +import com.vinlanx.explosionoverhaul.ModItems; +import com.vinlanx.explosionoverhaul.ModParticles; +import com.vinlanx.explosionoverhaul.ModSounds; +import com.vinlanx.explosionoverhaul.PacketHandler; +import com.vinlanx.explosionoverhaul.PlasmaParticleOptions; +import com.vinlanx.explosionoverhaul.RedstoneLampEffects; +import com.vinlanx.explosionoverhaul.ScanInfoHUD; +import com.vinlanx.explosionoverhaul.ScanKeyHandler; +import com.vinlanx.explosionoverhaul.ScanLoadInfoHUD; +import com.vinlanx.explosionoverhaul.ScanLoadPromptHUD; +import com.vinlanx.explosionoverhaul.ScanProgressHUD; +import com.vinlanx.explosionoverhaul.ScanPromptHUD; +import com.vinlanx.explosionoverhaul.ServerExplosionHandler; +import com.vinlanx.explosionoverhaul.VinlanxTheLightRenderer; +import com.vinlanx.explosionoverhaul.client.Blur; +import com.vinlanx.explosionoverhaul.client.ClientEffects; +import com.vinlanx.explosionoverhaul.client.ConcussionAudioEffect; +import com.vinlanx.explosionoverhaul.client.CustomGlowParticleProvider; +import com.vinlanx.explosionoverhaul.client.ExplosionTextureManager; +import com.vinlanx.explosionoverhaul.client.ExplosionWindController; +import com.vinlanx.explosionoverhaul.client.FirstTimeSetupHandler; +import com.vinlanx.explosionoverhaul.client.IntroMusicTickHandler; +import com.vinlanx.explosionoverhaul.client.LineSparkParticleProvider; +import com.vinlanx.explosionoverhaul.client.ModConfigScreen; +import com.vinlanx.explosionoverhaul.client.ModKeyMappings; +import com.vinlanx.explosionoverhaul.client.PlasmaParticle; +import com.vinlanx.explosionoverhaul.client.SmokeParticle; +import com.vinlanx.explosionoverhaul.client.SoundPhysicsCompatibility; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.Reader; +import java.nio.file.CopyOption; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.nio.file.attribute.FileAttribute; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.ShaderInstance; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.particles.BlockParticleOption; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.ParticleType; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientboundSoundPacket; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.packs.resources.PreparableReloadListener; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.RandomSource; +import net.minecraft.util.profiling.ProfilerFiller; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.neoforge.client.ConfigScreenHandler; +import net.neoforged.neoforge.client.event.ClientPlayerNetworkEvent; +import net.neoforged.neoforge.client.event.EntityRenderersEvent; +import net.neoforged.neoforge.client.event.RegisterClientReloadListenersEvent; +import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent; +import net.neoforged.neoforge.client.event.RegisterParticleProvidersEvent; +import net.neoforged.neoforge.client.event.RegisterShadersEvent; +import net.neoforged.neoforge.client.event.RenderGuiOverlayEvent; +import net.neoforged.neoforge.common.MinecraftForge; +import net.neoforged.neoforge.event.TickEvent; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; +import net.neoforged.neoforge.event.level.LevelEvent; +import net.neoforged.neoforge.event.server.ServerStoppedEvent; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.DistExecutor; +import net.neoforged.fml.ModLoadingContext; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.config.IConfigSpec; +import net.neoforged.fml.config.ModConfig; +import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; +import net.neoforged.fml.javafmlmod.FMLJavaModLoadingContext; +import net.neoforged.neoforge.registries.ForgeRegistries; +import net.neoforged.neoforge.server.ServerLifecycleHooks; +import org.slf4j.Logger; +import software.bernie.geckolib.GeckoLib; + +@Mod(value="explosionoverhaul") +public class ExplosionOverhaul { + public static final String MODID = "explosionoverhaul"; + public static final Logger LOGGER = LogUtils.getLogger(); + private static final Map SOURCE_MODES = new HashMap(); + private static final List EXPLOSION_BLACKLIST = new ArrayList(); + private static final List DEFAULT_BLACKLIST = List.of("ancient_elements:block_of_raw_infernal_ore", "ancient_elements:celestium_ore", "ancient_elements:deepslate_frost_ore", "ancient_elements:deepslate_jungle_steel_ore", "ancient_elements:deepslate_lead_ore", "ancient_elements:deepslate_steel_ore", "ancient_elements:deepslate_tin_ore", "ancient_elements:deepslate_titanium_ore", "ancient_elements:ender_steel_ore", "ancient_elements:endrium_ore", "ancient_elements:frost_ore", "ancient_elements:infernal_ore", "ancient_elements:jungle_steel_ore", "ancient_elements:lead_ore", "ancient_elements:meteorite_ore", "ancient_elements:nether_steel_ore", "ancient_elements:palladium_ore", "ancient_elements:spectrillium_ore", "ancient_elements:steel_ore", "ancient_elements:tin_ore", "ancient_elements:titanium_ore", "ancient_elements:void_steel_ore", "mofus_better_end_:void_portal_block", "mofus_better_end_:void_portal_igniter", "mofus_better_end_:star_portal"); + private static final Path CONFIG_DIR = Paths.get("config", "explosionoverhaul"); + private static final Path OLD_COMMON = Paths.get("config", "explosionoverhaul-common.toml"); + private static final Path OLD_CLIENT = Paths.get("config", "explosionoverhaul-client.toml"); + private static final Path NEW_COMMON = CONFIG_DIR.resolve("explosionoverhaul-common.toml"); + private static final Path NEW_CLIENT = CONFIG_DIR.resolve("explosionoverhaul-client.toml"); + private static final Path BLACKLIST_JSON = CONFIG_DIR.resolve("DestroyingBlacklist.json"); + private static final Path SOURCE_MODES_JSON = CONFIG_DIR.resolve("ExplosionSourceBlacklist.json"); + private static final List delayedSounds = Collections.synchronizedList(new ArrayList()); + private static final List delayedParticles = Collections.synchronizedList(new ArrayList()); + + @SubscribeEvent + public static void onServerTick(TickEvent.LevelTickEvent event) { + } + + private static void ensureConfigDirectory() { + try { + Files.createDirectories(CONFIG_DIR, new FileAttribute[0]); + ExplosionOverhaul.writeConfigReadme(); + } + catch (Exception e) { + LOGGER.warn("Failed to create config/explosionoverhaul directory", (Throwable)e); + } + } + + private static void writeConfigReadme() { + Path readmePath = CONFIG_DIR.resolve("README.md"); + if (Files.exists(readmePath, new LinkOption[0])) { + return; + } + try { + String content = "# Explosion Overhaul Config Helpers\n\n## Blacklist Files (.json)\n\n### DestroyingBlacklist.json\n- **Format**: `[\"namespace:block_id\", ...]`\n- **Effect**: Blocks listed here are immune to explosion craters.\n\n### GlassBlacklist.json\n- **Format**: `[\"namespace:block_id\", ...]`\n- **Effect**: Blocks listed here won't be shattered by the glass-breaking system.\n\n### ExplosionSourceBlacklist.json\n- **Format**: `{\"namespace:entity_id\": \"MODE\"}`\n- **Modes**:\n - `DEFAULT`: Standard mod behavior (crater + concussion + sounds).\n - `VANILLA`: Reverts to vanilla explosion logic for this source.\n - `NO_DESTRUCTION`: Concussions and sounds only (no crater or glass breaking).\n - `NO_DESTRUCTION_GLASSWORKS`: Like NO_DESTRUCTION, but glass still shatters.\n\n**Note**: Invalid JSON (extra commas, comments) will cause the mod to use defaults. Restart the game/server for changes to take effect.\n\nhttps://www.youtube.com/watch?v=dQw4w9WgXcQ"; + Files.writeString(readmePath, (CharSequence)content, new OpenOption[0]); + } + catch (Exception e) { + LOGGER.warn("Failed to write config README.md", (Throwable)e); + } + } + + private static void migrateOldTomlIfPresent() { + try { + byte[] oldBytes; + if (Files.exists(OLD_COMMON, new LinkOption[0])) { + ExplosionOverhaul.ensureConfigDirectory(); + if (!Files.exists(NEW_COMMON, new LinkOption[0])) { + Files.move(OLD_COMMON, NEW_COMMON, new CopyOption[0]); + } else { + oldBytes = Files.readAllBytes(OLD_COMMON); + Files.write(NEW_COMMON, oldBytes, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE); + Files.delete(OLD_COMMON); + } + } + if (Files.exists(OLD_CLIENT, new LinkOption[0])) { + ExplosionOverhaul.ensureConfigDirectory(); + if (!Files.exists(NEW_CLIENT, new LinkOption[0])) { + Files.move(OLD_CLIENT, NEW_CLIENT, new CopyOption[0]); + } else { + oldBytes = Files.readAllBytes(OLD_CLIENT); + Files.write(NEW_CLIENT, oldBytes, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE); + Files.delete(OLD_CLIENT); + } + } + } + catch (Exception e) { + LOGGER.warn("Failed to migrate old toml configs", (Throwable)e); + } + } + + private static void loadBlacklistFromJson() { + ExplosionOverhaul.ensureConfigDirectory(); + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + try { + if (!Files.exists(BLACKLIST_JSON, new LinkOption[0])) { + try (BufferedWriter w = Files.newBufferedWriter(BLACKLIST_JSON, new OpenOption[0]);){ + gson.toJson(DEFAULT_BLACKLIST, (Appendable)w); + } + EXPLOSION_BLACKLIST.clear(); + EXPLOSION_BLACKLIST.addAll(DEFAULT_BLACKLIST); + return; + } + try (BufferedReader r = Files.newBufferedReader(BLACKLIST_JSON);){ + List list = (List)gson.fromJson((Reader)r, new TypeToken>(){}.getType()); + if (list != null) { + EXPLOSION_BLACKLIST.clear(); + EXPLOSION_BLACKLIST.addAll(list); + } + } + } + catch (Exception e) { + LOGGER.warn("Failed to load DestroyingBlacklist.json, falling back to defaults", (Throwable)e); + EXPLOSION_BLACKLIST.clear(); + EXPLOSION_BLACKLIST.addAll(DEFAULT_BLACKLIST); + } + } + + private static void loadSourceModesFromJson() { + ExplosionOverhaul.ensureConfigDirectory(); + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + try { + if (!Files.exists(SOURCE_MODES_JSON, new LinkOption[0])) { + ExplosionOverhaul.ensureConfigDirectory(); + SOURCE_MODES.clear(); + try (BufferedWriter w = Files.newBufferedWriter(SOURCE_MODES_JSON, new OpenOption[0]);){ + gson.toJson(SOURCE_MODES, (Appendable)w); + } + return; + } + try (BufferedReader r = Files.newBufferedReader(SOURCE_MODES_JSON);){ + Map map = (Map)gson.fromJson((Reader)r, new TypeToken>(){}.getType()); + if (map != null) { + SOURCE_MODES.clear(); + SOURCE_MODES.putAll(map); + } + } + } + catch (Exception e) { + LOGGER.warn("Failed to load ExplosionSourceBlacklist.json", (Throwable)e); + } + } + + public static ExplosionSourceMode getSourceMode(String id) { + return SOURCE_MODES.getOrDefault(id, ExplosionSourceMode.DEFAULT); + } + + public static Map getSourceModes() { + return new HashMap(SOURCE_MODES); + } + + public static void setSourceModes(Map modes) { + SOURCE_MODES.clear(); + SOURCE_MODES.putAll(modes); + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + try (BufferedWriter w = Files.newBufferedWriter(SOURCE_MODES_JSON, new OpenOption[0]);){ + gson.toJson(SOURCE_MODES, (Appendable)w); + } + catch (Exception e) { + LOGGER.warn("Failed to save ExplosionSourceBlacklist.json", (Throwable)e); + } + } + + public static List getExplosionBlacklistList() { + return new ArrayList(EXPLOSION_BLACKLIST); + } + + public static List getDefaultExplosionBlacklist() { + return new ArrayList(DEFAULT_BLACKLIST); + } + + public static void setExplosionBlacklistFromList(List list) { + EXPLOSION_BLACKLIST.clear(); + for (String s : list) { + if (s == null || s.isBlank()) continue; + EXPLOSION_BLACKLIST.add(s.trim()); + } + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + try (BufferedWriter w = Files.newBufferedWriter(BLACKLIST_JSON, new OpenOption[0]);){ + gson.toJson(ExplosionOverhaul.getExplosionBlacklistList(), (Appendable)w); + } + catch (Exception e) { + LOGGER.warn("Failed to save DestroyingBlacklist.json", (Throwable)e); + } + } + + public static boolean isBlockBlacklisted(Block block) { + ResourceLocation blockId = ForgeRegistries.BLOCKS.getKey((Object)block); + if (blockId != null) { + String blockName = blockId.toString(); + return EXPLOSION_BLACKLIST.contains(blockName); + } + return false; + } + + public static boolean isBlockStateBlacklisted(BlockState state) { + ResourceLocation blockId = ForgeRegistries.BLOCKS.getKey((Object)state.m_60734_()); + if (blockId != null) { + String blockName = blockId.toString(); + return EXPLOSION_BLACKLIST.contains(blockName); + } + return false; + } + + public ExplosionOverhaul() { + IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); + GeckoLib.initialize(); + ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, (IConfigSpec)Config.COMMON_SPEC, "explosionoverhaul/explosionoverhaul-common.toml"); + ModLoadingContext.get().registerConfig(ModConfig.Type.CLIENT, (IConfigSpec)Config.CLIENT_SPEC, "explosionoverhaul/explosionoverhaul-client.toml"); + ModLoadingContext.get().registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class, () -> new ConfigScreenHandler.ConfigScreenFactory((client, parent) -> ModConfigScreen.create(parent))); + ModSounds.register(modEventBus); + ModParticles.register(modEventBus); + ModBlocks.register(modEventBus); + ModItems.register(modEventBus); + ModBlockEntities.register(modEventBus); + ModCreativeTabs.register(modEventBus); + MinecraftForge.EVENT_BUS.register(ExplosionOverhaul.class); + MinecraftForge.EVENT_BUS.register((Object)new ServerExplosionHandler()); + MinecraftForge.EVENT_BUS.register(BlockIndexManager.class); + modEventBus.addListener(this::commonSetup); + DistExecutor.unsafeRunWhenOn((Dist)Dist.CLIENT, () -> () -> { + SoundPhysicsCompatibility.init(); + modEventBus.addListener(ClientSetup::init); + modEventBus.addListener(ClientSetup::registerParticleFactories); + modEventBus.addListener(ClientSetup::registerBlockEntityRenderers); + modEventBus.addListener(ClientSetup::registerShaders); + modEventBus.addListener(ClientSetup::registerReloadListeners); + modEventBus.addListener(ClientSetup::onRegisterKeyMappings); + MinecraftForge.EVENT_BUS.register(ClientSetup.class); + MinecraftForge.EVENT_BUS.register((Object)new ClientSoundHandler()); + MinecraftForge.EVENT_BUS.register(ScanProgressHUD.class); + MinecraftForge.EVENT_BUS.register(ScanPromptHUD.class); + MinecraftForge.EVENT_BUS.register(ScanInfoHUD.class); + MinecraftForge.EVENT_BUS.register(ScanLoadPromptHUD.class); + MinecraftForge.EVENT_BUS.register(ScanLoadInfoHUD.class); + MinecraftForge.EVENT_BUS.register((Object)new ScanKeyHandler()); + MinecraftForge.EVENT_BUS.register(FirstTimeSetupHandler.class); + MinecraftForge.EVENT_BUS.register(IntroMusicTickHandler.class); + MinecraftForge.EVENT_BUS.register(ConcussionAudioEffect.class); + }); + } + + private void commonSetup(FMLCommonSetupEvent event) { + ExplosionOverhaul.migrateOldTomlIfPresent(); + ExplosionOverhaul.loadBlacklistFromJson(); + ExplosionOverhaul.loadSourceModesFromJson(); + event.enqueueWork(PacketHandler::register); + } + + @SubscribeEvent + public static void onServerTick(TickEvent.ServerTickEvent event) { + if (event.phase == TickEvent.Phase.END) { + RedstoneLampEffects.onServerTick(); + if (event.getServer() != null) { + for (ServerLevel level : event.getServer().m_129785_()) { + DripstoneEffects.onServerTick(level); + } + } + GlassBreakingEffects.onServerTick(); + AmbientExplosionManager.onServerTick(event.getServer().m_129783_()); + if (ServerLifecycleHooks.getCurrentServer() != null) { + AsyncCraterManager.onServerTick(ServerLifecycleHooks.getCurrentServer()); + } + delayedSounds.removeIf(delayedSound -> { + --delayedSound.ticksRemaining; + if (delayedSound.ticksRemaining <= 0L) { + delayedSound.play(); + return true; + } + return false; + }); + delayedParticles.removeIf(delayedParticle -> { + --delayedParticle.ticksRemaining; + if (delayedParticle.ticksRemaining <= 0L) { + delayedParticle.spawn(); + if (delayedParticle.durationTicks > 1L) { + --delayedParticle.durationTicks; + delayedParticle.ticksRemaining = 1L; + return false; + } + return true; + } + return false; + }); + } + } + + @SubscribeEvent + public static void onLevelUnload(LevelEvent.Unload event) { + LevelAccessor levelAccessor = event.getLevel(); + if (levelAccessor instanceof ServerLevel) { + ServerLevel level = (ServerLevel)levelAccessor; + AsyncCraterManager.onLevelUnload(level); + } + } + + @SubscribeEvent + public static void onServerStopped(ServerStoppedEvent event) { + AsyncCraterManager.shutdown(); + } + + @SubscribeEvent + public static void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) { + if (event.getEntity() instanceof ServerPlayer) { + AmbientExplosionManager.onPlayerLoggedIn((ServerPlayer)event.getEntity()); + } + } + + @SubscribeEvent + public static void onPlayerLogout(PlayerEvent.PlayerLoggedOutEvent event) { + if (event.getEntity() instanceof ServerPlayer) { + AmbientExplosionManager.onPlayerLoggedOut((ServerPlayer)event.getEntity()); + } + } + + public static void addDelayedSound(ServerPlayer player, SoundEvent sound, SoundSource source, float x, float y, float z, float volume, float pitch, long seed, long delayTicks) { + if (player.f_8906_ == null) { + return; + } + if (delayTicks <= 0L) { + player.f_8906_.m_9829_((Packet)new ClientboundSoundPacket((Holder)ForgeRegistries.SOUND_EVENTS.getHolder((Object)sound).orElseThrow(), source, (double)x, (double)y, (double)z, volume, pitch, seed)); + } else { + delayedSounds.add(new DelayedSound(player, sound, source, x, y, z, volume, pitch, seed, delayTicks)); + } + } + + public static void addDelayedParticle(ServerLevel level, BlockParticleOption particleOption, double x, double y, double z, int count, double dx, double dy, double dz, double speed, long delayTicks, long durationTicks) { + if (delayTicks <= 0L && durationTicks <= 1L) { + level.m_8767_((ParticleOptions)particleOption, x, y, z, count, dx, dy, dz, speed); + } else { + delayedParticles.add(new DelayedParticle(level, particleOption, x, y, z, count, dx, dy, dz, speed, delayTicks, Math.max(1L, durationTicks))); + } + } + + public static enum ExplosionSourceMode { + DEFAULT, + VANILLA, + NO_DESTRUCTION, + NO_DESTRUCTION_GLASSWORKS; + + } + + public static class DelayedSound { + public ServerPlayer player; + public SoundEvent sound; + public SoundSource source; + public float x; + public float y; + public float z; + public float volume; + public float pitch; + public long seed; + public long ticksRemaining; + + public DelayedSound(ServerPlayer player, SoundEvent sound, SoundSource source, float x, float y, float z, float volume, float pitch, long seed, long ticksRemaining) { + this.player = player; + this.sound = sound; + this.source = source; + this.x = x; + this.y = y; + this.z = z; + this.volume = volume; + this.pitch = pitch; + this.seed = seed; + this.ticksRemaining = ticksRemaining; + } + + public void play() { + if (this.player.f_8906_ == null) { + return; + } + this.player.f_8906_.m_9829_((Packet)new ClientboundSoundPacket((Holder)ForgeRegistries.SOUND_EVENTS.getHolder((Object)this.sound).orElseThrow(), this.source, (double)this.x, (double)this.y, (double)this.z, this.volume, this.pitch, this.seed)); + } + } + + public static class DelayedParticle { + public ServerLevel level; + public BlockParticleOption particleOption; + public double x; + public double y; + public double z; + public int count; + public double dx; + public double dy; + public double dz; + public double speed; + public long ticksRemaining; + public long durationTicks; + + public DelayedParticle(ServerLevel level, BlockParticleOption particleOption, double x, double y, double z, int count, double dx, double dy, double dz, double speed, long ticksRemaining, long durationTicks) { + this.level = level; + this.particleOption = particleOption; + this.x = x; + this.y = y; + this.z = z; + this.count = count; + this.dx = dx; + this.dy = dy; + this.dz = dz; + this.speed = speed; + this.ticksRemaining = ticksRemaining; + this.durationTicks = durationTicks; + } + + public void spawn() { + int particlesPerSpawn = Math.max(1, this.count / (int)Math.max(1L, this.durationTicks)); + this.level.m_8767_((ParticleOptions)this.particleOption, this.x, this.y, this.z, particlesPerSpawn, this.dx, this.dy, this.dz, this.speed); + } + } + + public static class ClientSetup { + private static boolean hasPreWarmed = false; + + public static void init(FMLClientSetupEvent event) { + ExplosionTextureManager.getInstance().reload(); + } + + public static void registerReloadListeners(RegisterClientReloadListenersEvent event) { + event.registerReloadListener((PreparableReloadListener)new TexturePreloader()); + } + + @SubscribeEvent + public static void registerShaders(RegisterShadersEvent event) { + try { + event.registerShader(new ShaderInstance(event.getResourceProvider(), new ResourceLocation(ExplosionOverhaul.MODID, "blur"), DefaultVertexFormat.f_85817_), Blur::setShader); + } + catch (IOException e) { + LOGGER.warn("Failed to load core shaders", (Throwable)e); + } + } + + @SubscribeEvent + public static void registerParticleFactories(RegisterParticleProvidersEvent event) { + event.registerSpriteSet((ParticleType)ModParticles.CUSTOM_GLOW.get(), CustomGlowParticleProvider::new); + event.registerSpriteSet((ParticleType)ModParticles.PLASMA.get(), PlasmaParticle.Provider::new); + event.registerSpriteSet((ParticleType)ModParticles.CUSTOM_SMOKE.get(), SmokeParticle.Provider::new); + event.registerSpriteSet((ParticleType)ModParticles.LINE_SPARK.get(), LineSparkParticleProvider::new); + LOGGER.info("Registered custom particle providers."); + } + + @SubscribeEvent + public static void onRegisterKeyMappings(RegisterKeyMappingsEvent event) { + ModKeyMappings.register(event); + } + + @SubscribeEvent + public static void registerBlockEntityRenderers(EntityRenderersEvent.RegisterRenderers event) { + event.registerBlockEntityRenderer((BlockEntityType)ModBlockEntities.VINLANX_THE_LIGHT.get(), VinlanxTheLightRenderer::new); + } + + @SubscribeEvent + public static void onClientTick(TickEvent.ClientTickEvent event) { + if (event.phase == TickEvent.Phase.END) { + ClientEffects.onClientTick(); + if (!hasPreWarmed && Minecraft.m_91087_().f_91073_ != null && Minecraft.m_91087_().f_91074_ != null) { + LOGGER.info("Pre-warming explosion particle render pipeline..."); + ClientLevel level = Minecraft.m_91087_().f_91073_; + double x = Minecraft.m_91087_().f_91074_.m_20185_(); + double y = -200.0; + double z = Minecraft.m_91087_().f_91074_.m_20189_(); + level.m_7106_((ParticleOptions)new PlasmaParticleOptions(1.0f), x, y, z, 0.0, 0.0, 0.0); + LOGGER.info("Pre-warming 'glow' animation..."); + level.m_7106_((ParticleOptions)new CustomGlowParticleOptions(0, 1.0f, 0.01f, 0, (float)y, 4.0f, 0.0f), x, y, z, 0.0, 0.0, 0.0); + LOGGER.info("Pre-warming 'glow_2' animation..."); + level.m_7106_((ParticleOptions)new CustomGlowParticleOptions(0, 1.0f, 0.01f, 1, (float)y, 4.0f, 0.0f), x, y, z, 0.0, 0.0, 0.0); + LOGGER.info("Pre-warming 'sglow' animation..."); + level.m_7106_((ParticleOptions)new CustomGlowParticleOptions(0, 1.0f, 0.01f, 2, (float)y, 4.0f, 0.0f), x, y, z, 0.0, 0.0, 0.0); + hasPreWarmed = true; + LOGGER.info("Explosion particle pipeline pre-warmed successfully."); + } + } + } + + @SubscribeEvent + public static void onPlayerLogout(ClientPlayerNetworkEvent.LoggingOut event) { + LOGGER.info("Player logged out, resetting particle pre-warmer and scan HUDs."); + hasPreWarmed = false; + ExplosionWindController.reset(); + ScanProgressHUD.reset(); + ScanPromptHUD.setVisible(false); + ScanLoadPromptHUD.setVisible(false); + ScanInfoHUD.setVisible(false); + ScanLoadInfoHUD.setVisible(false); + } + + @SubscribeEvent + public static void onRenderGuiOverlay(RenderGuiOverlayEvent.Post event) { + if (event.getOverlay().id().m_135815_().equals("all")) { + Blur.render(Blur.RenderStage.HUD); + } + if (event.getOverlay().id().m_135815_().equals("crosshair")) { + ClientEffects.renderFlash(event); + ConcussionAudioEffect.renderHeartbeatHUD(event.getGuiGraphics()); + } + } + + public static class TexturePreloader + implements PreparableReloadListener { + public CompletableFuture m_5540_(PreparableReloadListener.PreparationBarrier pPreparationBarrier, ResourceManager pResourceManager, ProfilerFiller pPreparationsProfiler, ProfilerFiller pReloadProfiler, Executor pBackgroundExecutor, Executor pGameExecutor) { + CompletableFuture prepareFuture = CompletableFuture.supplyAsync(() -> { + LOGGER.info("Scanning for all mod textures to preload..."); + return pResourceManager.m_214159_("textures", path -> path.m_135827_().equals(ExplosionOverhaul.MODID) && path.m_135815_().endsWith(".png")).keySet().stream().toList(); + }, pBackgroundExecutor); + return prepareFuture.thenCompose(locationsToLoad -> pPreparationBarrier.m_6769_(locationsToLoad).thenRunAsync(() -> { + if (locationsToLoad.isEmpty()) { + LOGGER.warn("Did not find any textures to preload for mod '{}'.", (Object)ExplosionOverhaul.MODID); + return; + } + LOGGER.info("Preloading {} textures from '{}' to GPU...", (Object)locationsToLoad.size(), (Object)ExplosionOverhaul.MODID); + TextureManager textureManager = Minecraft.m_91087_().m_91097_(); + for (ResourceLocation location : locationsToLoad) { + textureManager.m_118506_(location); + } + ExplosionTextureManager.getInstance().reload(); + LOGGER.info("Finished preloading all textures for the mod."); + }, pGameExecutor)); + } + } + } + + public static class CaveEffects { + private static final int PLAYER_EFFECT_RADIUS = 10; + + public static void spawnFallingBlocksAndDust(ServerLevel level, Vec3 explosionPos, ServerPlayer player, float power, long initialDelayTicks) { + RandomSource random = level.m_213780_(); + long maxEffectOverallDurationTicks = (2 + random.m_188503_(5)) * 20; + int totalEffectSpawns = 15 + (int)(power / 5.0f * 3.0f); + totalEffectSpawns = Math.min(totalEffectSpawns, 60); + for (int i = 0; i < totalEffectSpawns; ++i) { + long individualDelay = initialDelayTicks + (long)random.m_188503_((int)maxEffectOverallDurationTicks / 2); + long randomDurationTicks = 10 + random.m_188503_(40); + CaveEffects.spawnEffectAtPlayer(level, player, individualDelay, random, power, randomDurationTicks); + } + } + + private static void spawnEffectAtPlayer(ServerLevel level, ServerPlayer player, long delayTicks, RandomSource random, float power, long durationTicks) { + int xOffset = random.m_188503_(21) - 10; + int zOffset = random.m_188503_(21) - 10; + int ySearchStart = (int)player.m_20186_() + 3 + random.m_188503_(4); + BlockPos playerBlockPos = player.m_20183_(); + BlockPos checkPosBase = new BlockPos(playerBlockPos.m_123341_() + xOffset, ySearchStart, playerBlockPos.m_123343_() + zOffset); + BlockPos effectPos = null; + for (int i = 0; i < 8; ++i) { + BlockState aboveState; + BlockState currentState; + BlockPos currentCheck = checkPosBase.m_6625_(i); + if (!level.m_46749_(currentCheck) || (double)currentCheck.m_123342_() <= player.m_20186_() - 1.0 || !(currentState = level.m_8055_(currentCheck)).m_280296_() || currentState.m_60795_() || !(aboveState = level.m_8055_(currentCheck.m_7494_())).m_60795_() && !level.m_8055_(currentCheck.m_7495_()).m_60795_()) continue; + effectPos = currentCheck; + break; + } + if (effectPos != null && effectPos.m_123342_() > level.m_141937_()) { + boolean isSpecialBlock; + BlockState blockState = level.m_8055_(effectPos); + if (blockState.m_60795_()) { + return; + } + ResourceLocation registryName = ForgeRegistries.BLOCKS.getKey((Object)blockState.m_60734_()); + String name = registryName != null ? registryName.m_135815_() : ""; + boolean bl = isSpecialBlock = name.contains("bedrock") || name.contains("end_portal") || name.contains("end_portal_frame") || name.contains("command_block") || name.contains("barrier"); + if (isSpecialBlock) { + return; + } + int particleCount = 8 + (int)((double)(power / 10.0f) * 1.5); + particleCount = Math.min(particleCount, 25); + ExplosionOverhaul.addDelayedParticle(level, new BlockParticleOption(ParticleTypes.f_123814_, blockState), (double)effectPos.m_123341_() + 0.5, (double)effectPos.m_123342_() + 0.2, (double)effectPos.m_123343_() + 0.5, particleCount, 0.3, 0.3, 0.3, 0.02, delayTicks, durationTicks); + if (random.m_188500_() < 0.3 + (double)power * 0.02) { + ExplosionOverhaul.addDelayedSound(player, (SoundEvent)ModSounds.DUST_SOUND.get(), SoundSource.BLOCKS, (float)effectPos.m_123341_() + 0.5f, (float)effectPos.m_123342_() + 0.5f, (float)effectPos.m_123343_() + 0.5f, 0.6f + random.m_188501_() * 0.4f, 0.85f + random.m_188501_() * 0.3f, player.m_217043_().m_188505_(), delayTicks + (long)random.m_188503_(10)); + } + if (random.m_188500_() < 0.03 + (double)power * 0.005 && power > 10.0f) { + ExplosionOverhaul.addDelayedSound(player, (SoundEvent)ModSounds.FALLING_STONES_SOUND.get(), SoundSource.BLOCKS, (float)effectPos.m_123341_() + 0.5f, (float)effectPos.m_123342_() + 0.5f, (float)effectPos.m_123343_() + 0.5f, 0.8f + random.m_188501_() * 0.2f, 0.9f + random.m_188501_() * 0.2f, player.m_217043_().m_188505_(), delayTicks + (long)random.m_188503_(20)); + } + } + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ExplosionVisualsPacket.java b/src/main/java/com/vinlanx/explosionoverhaul/ExplosionVisualsPacket.java new file mode 100644 index 0000000..8653f39 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ExplosionVisualsPacket.java @@ -0,0 +1,44 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.client.ClientEffects; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.phys.Vec3; +import net.neoforged.neoforge.network.NetworkEvent; + +public class ExplosionVisualsPacket { + private final Vec3 position; + private final float power; + + public ExplosionVisualsPacket(Vec3 position, float power) { + this.position = position; + this.power = power; + } + + public static void encode(ExplosionVisualsPacket msg, FriendlyByteBuf buf) { + buf.writeDouble(msg.position.f_82479_); + buf.writeDouble(msg.position.f_82480_); + buf.writeDouble(msg.position.f_82481_); + buf.writeFloat(msg.power); + } + + public static ExplosionVisualsPacket decode(FriendlyByteBuf buf) { + return new ExplosionVisualsPacket(new Vec3(buf.readDouble(), buf.readDouble(), buf.readDouble()), buf.readFloat()); + } + + public static void handle(ExplosionVisualsPacket msg, Supplier ctx) { + ctx.get().enqueueWork(() -> ClientEffects.triggerRealisticExplosion(msg.position, msg.power)); + ctx.get().setPacketHandled(true); + } + + public Vec3 getPosition() { + return this.position; + } + + public float getPower() { + return this.power; + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/FlashEffectPacket.java b/src/main/java/com/vinlanx/explosionoverhaul/FlashEffectPacket.java new file mode 100644 index 0000000..465c674 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/FlashEffectPacket.java @@ -0,0 +1,38 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.client.ClientEffects; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.phys.Vec3; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.DistExecutor; +import net.neoforged.neoforge.network.NetworkEvent; + +public class FlashEffectPacket { + private final Vec3 explosionPos; + private final float power; + + public FlashEffectPacket(Vec3 explosionPos, float power) { + this.explosionPos = explosionPos; + this.power = power; + } + + public static void encode(FlashEffectPacket msg, FriendlyByteBuf buf) { + buf.writeDouble(msg.explosionPos.f_82479_); + buf.writeDouble(msg.explosionPos.f_82480_); + buf.writeDouble(msg.explosionPos.f_82481_); + buf.writeFloat(msg.power); + } + + public static FlashEffectPacket decode(FriendlyByteBuf buf) { + return new FlashEffectPacket(new Vec3(buf.readDouble(), buf.readDouble(), buf.readDouble()), buf.readFloat()); + } + + public static void handle(FlashEffectPacket msg, Supplier ctx) { + ctx.get().enqueueWork(() -> DistExecutor.unsafeRunWhenOn((Dist)Dist.CLIENT, () -> () -> ClientEffects.addFlashEffect(msg.explosionPos, msg.power))); + ctx.get().setPacketHandled(true); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/GlassBreakingEffects.java b/src/main/java/com/vinlanx/explosionoverhaul/GlassBreakingEffects.java new file mode 100644 index 0000000..2e7d77b --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/GlassBreakingEffects.java @@ -0,0 +1,230 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.BlockIndexManager; +import com.vinlanx.explosionoverhaul.Config; +import com.vinlanx.explosionoverhaul.ExplosionOverhaul; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Position; +import net.minecraft.core.Vec3i; +import net.minecraft.core.particles.BlockParticleOption; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.tags.BlockTags; +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +public class GlassBreakingEffects { + private static final Map> perExplosionEffects = new ConcurrentHashMap>(); + 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 glassBlocks = BlockIndexManager.getNearby(level, center, (int)Math.ceil(radius), BlockIndexManager.BlockType.GLASS); + if (glassBlocks.isEmpty()) { + return; + } + HashSet foundGlassBlocks = new HashSet(); + 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 groups = new ArrayList(); + HashSet processed = new HashSet(); + for (BlockPos glassPos : foundGlassBlocks) { + List 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 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 findConnectedGlass(ServerLevel level, BlockPos start, Set processed) { + ArrayList group = new ArrayList(); + LinkedList queue = new LinkedList(); + 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 effects : perExplosionEffects.values()) { + int explosionBudget = budgetPerExplosion; + Iterator 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 positions, BlockPos representativePos, double distanceSq) { + } + + private static class DelayedGlassEffect { + private final ServerLevel level; + private final BlockPos glassPos; + private final BlockState glassState; + private long delayCycles; + + public DelayedGlassEffect(ServerLevel level, BlockPos glassPos, long delayCycles) { + this.level = level; + this.glassPos = glassPos; + this.glassState = level.m_8055_(glassPos); + this.delayCycles = delayCycles; + } + + public boolean tick() { + if (--this.delayCycles <= 0L) { + this.level.m_46961_(this.glassPos, false); + this.level.m_8767_((ParticleOptions)new BlockParticleOption(ParticleTypes.f_123794_, this.glassState), (double)this.glassPos.m_123341_() + 0.5, (double)this.glassPos.m_123342_() + 0.5, (double)this.glassPos.m_123343_() + 0.5, 20, 0.3, 0.3, 0.3, 0.1); + this.level.m_5594_(null, this.glassPos, SoundEvents.f_11983_, SoundSource.BLOCKS, 0.7f, 1.0f); + return true; + } + return false; + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/LowPassTestPacket.java b/src/main/java/com/vinlanx/explosionoverhaul/LowPassTestPacket.java new file mode 100644 index 0000000..6bad472 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/LowPassTestPacket.java @@ -0,0 +1,38 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.client.LowPassConcussionEffect; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.neoforge.network.NetworkEvent; + +public class LowPassTestPacket { + private final int durationSeconds; + + public LowPassTestPacket(int durationSeconds) { + this.durationSeconds = durationSeconds; + } + + public static void encode(LowPassTestPacket msg, FriendlyByteBuf buf) { + buf.writeInt(msg.durationSeconds); + } + + public static LowPassTestPacket decode(FriendlyByteBuf buf) { + return new LowPassTestPacket(buf.readInt()); + } + + public static void handle(LowPassTestPacket msg, Supplier ctxSupplier) { + NetworkEvent.Context ctx = ctxSupplier.get(); + ctx.enqueueWork(() -> LowPassTestPacket.handleClient(msg)); + ctx.setPacketHandled(true); + } + + @OnlyIn(value=Dist.CLIENT) + private static void handleClient(LowPassTestPacket msg) { + LowPassConcussionEffect.start(msg.durationSeconds, 0.5f); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ModBlockEntities.java b/src/main/java/com/vinlanx/explosionoverhaul/ModBlockEntities.java new file mode 100644 index 0000000..b6ec03a --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ModBlockEntities.java @@ -0,0 +1,23 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.ModBlocks; +import com.vinlanx.explosionoverhaul.VinlanxTheLightBlockEntity; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.neoforge.registries.ForgeRegistries; +import net.neoforged.neoforge.registries.IForgeRegistry; +import net.neoforged.neoforge.registries.RegistryObject; + +public class ModBlockEntities { + public static final DeferredRegister> BLOCK_ENTITIES = DeferredRegister.create((IForgeRegistry)ForgeRegistries.BLOCK_ENTITY_TYPES, (String)"explosionoverhaul"); + public static final RegistryObject> VINLANX_THE_LIGHT = BLOCK_ENTITIES.register("vinlanx_the_light", () -> BlockEntityType.Builder.m_155273_(VinlanxTheLightBlockEntity::new, (Block[])new Block[]{(Block)ModBlocks.VINLANX_THE_LIGHT.get()}).m_58966_(null)); + + public static void register(IEventBus eventBus) { + BLOCK_ENTITIES.register(eventBus); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ModBlocks.java b/src/main/java/com/vinlanx/explosionoverhaul/ModBlocks.java new file mode 100644 index 0000000..981719e --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ModBlocks.java @@ -0,0 +1,21 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.VinlanxTheLightBlock; +import net.minecraft.world.level.block.Block; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.neoforge.registries.ForgeRegistries; +import net.neoforged.neoforge.registries.IForgeRegistry; +import net.neoforged.neoforge.registries.RegistryObject; + +public class ModBlocks { + public static final DeferredRegister BLOCKS = DeferredRegister.create((IForgeRegistry)ForgeRegistries.BLOCKS, (String)"explosionoverhaul"); + public static final RegistryObject VINLANX_THE_LIGHT = BLOCKS.register("vinlanx_the_light", () -> new VinlanxTheLightBlock(VinlanxTheLightBlock.defaultProperties())); + + public static void register(IEventBus eventBus) { + BLOCKS.register(eventBus); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ModCommands.java b/src/main/java/com/vinlanx/explosionoverhaul/ModCommands.java new file mode 100644 index 0000000..6ec6380 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ModCommands.java @@ -0,0 +1,130 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.arguments.FloatArgumentType; +import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import com.vinlanx.explosionoverhaul.BlockIndexManager; +import com.vinlanx.explosionoverhaul.BlurTestPacket; +import com.vinlanx.explosionoverhaul.CameraShakeConcussionPacket; +import com.vinlanx.explosionoverhaul.ExplosionOverhaul; +import com.vinlanx.explosionoverhaul.LowPassTestPacket; +import com.vinlanx.explosionoverhaul.ModParticles; +import com.vinlanx.explosionoverhaul.OpenALTogglePacket; +import com.vinlanx.explosionoverhaul.PacketHandler; +import com.vinlanx.explosionoverhaul.SpawnCustomGlowPacket; +import java.util.Arrays; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.arguments.coordinates.Vec3Argument; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.SimpleParticleType; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.RandomSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; +import net.neoforged.neoforge.event.RegisterCommandsEvent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; +import net.neoforged.neoforge.network.PacketDistributor; + +@Mod.EventBusSubscriber(modid="explosionoverhaul") +public class ModCommands { + @SubscribeEvent + public static void onCommandsRegister(RegisterCommandsEvent event) { + CommandDispatcher dispatcher = event.getDispatcher(); + dispatcher.register((LiteralArgumentBuilder)((LiteralArgumentBuilder)Commands.m_82127_((String)"modparticle").requires(source -> source.m_6761_(2))).then(Commands.m_82129_((String)"pos", (ArgumentType)Vec3Argument.m_120841_()).then(Commands.m_82129_((String)"zone", (ArgumentType)IntegerArgumentType.integer((int)0, (int)1)).then(Commands.m_82129_((String)"power", (ArgumentType)FloatArgumentType.floatArg((float)1.0f)).then(Commands.m_82129_((String)"scale", (ArgumentType)FloatArgumentType.floatArg((float)0.1f)).then(Commands.m_82129_((String)"count", (ArgumentType)IntegerArgumentType.integer((int)1)).executes(ctx -> { + ServerLevel level = ((CommandSourceStack)ctx.getSource()).m_81372_(); + Vec3 pos = Vec3Argument.m_120844_((CommandContext)ctx, (String)"pos"); + int zone = IntegerArgumentType.getInteger((CommandContext)ctx, (String)"zone"); + float power = FloatArgumentType.getFloat((CommandContext)ctx, (String)"power"); + float scale = FloatArgumentType.getFloat((CommandContext)ctx, (String)"scale"); + int count = IntegerArgumentType.getInteger((CommandContext)ctx, (String)"count"); + PacketDistributor.TargetPoint targetPoint = new PacketDistributor.TargetPoint(pos.m_7096_(), pos.m_7098_(), pos.m_7094_(), 256.0, level.m_46472_()); + for (int i = 0; i < count; ++i) { + Vec3 motion = new Vec3((level.m_213780_().m_188500_() - 0.5) * 0.5, (level.m_213780_().m_188500_() - 0.5) * 0.5, (level.m_213780_().m_188500_() - 0.5) * 0.5); + float centerY = (float)pos.f_82480_; + float maxRadius = Math.max(1.0f, power * 2.0f); + float heightPercent = 0.0f; + PacketHandler.INSTANCE.send(PacketDistributor.NEAR.with(() -> targetPoint), (Object)new SpawnCustomGlowPacket(pos, motion, zone, power, scale, centerY, maxRadius, heightPercent)); + } + return 1; + }))))))); + dispatcher.register((LiteralArgumentBuilder)((LiteralArgumentBuilder)Commands.m_82127_((String)"spawnspark").requires(source -> source.m_6761_(2))).executes(ctx -> { + ServerPlayer player = ((CommandSourceStack)ctx.getSource()).m_81375_(); + ServerLevel level = player.m_284548_(); + Vec3 pos = player.m_146892_().m_82549_(player.m_20154_().m_82490_(2.0)); + RandomSource random = level.m_213780_(); + for (int i = 0; i < 50; ++i) { + level.m_8767_((ParticleOptions)((SimpleParticleType)ModParticles.LINE_SPARK.get()), pos.m_7096_(), pos.m_7098_(), pos.m_7094_(), 1, (random.m_188500_() - 0.5) * 2.5, (random.m_188500_() - 0.5) * 2.5, (random.m_188500_() - 0.5) * 2.5, 1.0); + } + ((CommandSourceStack)ctx.getSource()).m_288197_(() -> Component.m_237113_((String)"Spawned 50 juicy sparks!"), true); + return 1; + })); + dispatcher.register((LiteralArgumentBuilder)((LiteralArgumentBuilder)Commands.m_82127_((String)"rescanchunks").requires(source -> source.m_6761_(2))).executes(ctx -> { + try { + Entity patt5242$temp = ((CommandSourceStack)ctx.getSource()).m_81373_(); + if (!(patt5242$temp instanceof ServerPlayer)) { + ((CommandSourceStack)ctx.getSource()).m_81352_((Component)Component.m_237113_((String)"\u00a76[Explosion Overhaul] \u00a7cThis command can only be used by players")); + return 0; + } + ServerPlayer player = (ServerPlayer)patt5242$temp; + BlockIndexManager.showRescanPrompt(player); + ((CommandSourceStack)ctx.getSource()).m_288197_(() -> Component.m_237113_((String)"\u00a76[Explosion Overhaul] \u00a7eShowing rescan prompt..."), false); + return 1; + } + catch (Exception e) { + ((CommandSourceStack)ctx.getSource()).m_81352_((Component)Component.m_237113_((String)("\u00a76[Explosion Overhaul] \u00a7cFailed to show rescan prompt: " + e.getMessage()))); + ExplosionOverhaul.LOGGER.error("Failed to execute rescanchunks command", (Throwable)e); + return 0; + } + })); + dispatcher.register((LiteralArgumentBuilder)((LiteralArgumentBuilder)Commands.m_82127_((String)"lowpasstest").requires(source -> source.m_6761_(2))).then(Commands.m_82129_((String)"duration", (ArgumentType)IntegerArgumentType.integer((int)1, (int)600)).executes(ctx -> { + ServerPlayer player = ((CommandSourceStack)ctx.getSource()).m_81375_(); + int duration = IntegerArgumentType.getInteger((CommandContext)ctx, (String)"duration"); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)new LowPassTestPacket(duration)); + ((CommandSourceStack)ctx.getSource()).m_288197_(() -> Component.m_237113_((String)("Started low-pass test for " + duration + "s")), false); + return 1; + }))); + dispatcher.register((LiteralArgumentBuilder)((LiteralArgumentBuilder)Commands.m_82127_((String)"blurtesting").requires(source -> source.m_6761_(2))).then(Commands.m_82129_((String)"duration", (ArgumentType)IntegerArgumentType.integer((int)1, (int)600)).executes(ctx -> { + ServerPlayer player = ((CommandSourceStack)ctx.getSource()).m_81375_(); + int duration = IntegerArgumentType.getInteger((CommandContext)ctx, (String)"duration"); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)new BlurTestPacket(duration)); + ((CommandSourceStack)ctx.getSource()).m_288197_(() -> Component.m_237113_((String)("Started blur test for " + duration + "s")), false); + return 1; + }))); + dispatcher.register((LiteralArgumentBuilder)((LiteralArgumentBuilder)Commands.m_82127_((String)"testcamerashake").requires(source -> source.m_6761_(2))).then(Commands.m_82129_((String)"duration", (ArgumentType)IntegerArgumentType.integer((int)1, (int)600)).then(Commands.m_82129_((String)"intensity", (ArgumentType)IntegerArgumentType.integer((int)1, (int)100)).executes(ctx -> { + ServerPlayer player = ((CommandSourceStack)ctx.getSource()).m_81375_(); + int duration = IntegerArgumentType.getInteger((CommandContext)ctx, (String)"duration"); + int intensityPercent = IntegerArgumentType.getInteger((CommandContext)ctx, (String)"intensity"); + float intensity = (float)intensityPercent / 100.0f; + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)new CameraShakeConcussionPacket(duration, intensity)); + ((CommandSourceStack)ctx.getSource()).m_288197_(() -> Component.m_237113_((String)("Started camera shake test for " + duration + "s at " + intensityPercent + "% intensity")), false); + return 1; + })))); + dispatcher.register((LiteralArgumentBuilder)((LiteralArgumentBuilder)Commands.m_82127_((String)"openaltest").requires(source -> source.m_6761_(2))).then(Commands.m_82129_((String)"target", (ArgumentType)StringArgumentType.word()).suggests((ctx, sb) -> SharedSuggestionProvider.m_82970_(Arrays.asList("deafness", "lowpass", "low_pass"), (SuggestionsBuilder)sb)).then(Commands.m_82129_((String)"state", (ArgumentType)StringArgumentType.word()).suggests((ctx, sb) -> SharedSuggestionProvider.m_82970_(Arrays.asList("on", "off", "enable", "disable", "true", "false"), (SuggestionsBuilder)sb)).executes(ctx -> { + boolean turnOn; + String target = StringArgumentType.getString((CommandContext)ctx, (String)"target").toLowerCase(); + String state = StringArgumentType.getString((CommandContext)ctx, (String)"state").toLowerCase(); + boolean bl = turnOn = state.equals("on") || state.equals("enable") || state.equals("true"); + if (target.equals("deafness") || target.equals("lowpass") || target.equals("low_pass")) { + ServerPlayer player = ((CommandSourceStack)ctx.getSource()).m_81375_(); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)new OpenALTogglePacket(target, turnOn)); + ((CommandSourceStack)ctx.getSource()).m_288197_(() -> Component.m_237113_((String)("Sent OpenAL toggle to player: " + target + " -> " + (turnOn ? "ON" : "OFF"))), false); + return 1; + } + ((CommandSourceStack)ctx.getSource()).m_81352_((Component)Component.m_237113_((String)("Unknown target: " + target + ". Use 'Deafness' or 'LowPass'."))); + return 0; + })))); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ModCreativeTabs.java b/src/main/java/com/vinlanx/explosionoverhaul/ModCreativeTabs.java new file mode 100644 index 0000000..d31efa1 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ModCreativeTabs.java @@ -0,0 +1,24 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.ModItems; +import net.minecraft.core.registries.Registries; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ItemLike; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.neoforge.registries.RegistryObject; + +public class ModCreativeTabs { + public static final DeferredRegister CREATIVE_MODE_TABS = DeferredRegister.create((ResourceKey)Registries.f_279569_, (String)"explosionoverhaul"); + public static final RegistryObject MAIN = CREATIVE_MODE_TABS.register("main", () -> CreativeModeTab.builder().m_257737_(() -> new ItemStack((ItemLike)ModItems.MOD_LOGO.get())).m_257941_((Component)Component.m_237115_((String)"itemGroup.explosionoverhaul.main")).m_257501_((parameters, output) -> output.m_246326_((ItemLike)ModItems.VINLANX_THE_LIGHT.get())).m_257652_()); + + public static void register(IEventBus eventBus) { + CREATIVE_MODE_TABS.register(eventBus); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ModItems.java b/src/main/java/com/vinlanx/explosionoverhaul/ModItems.java new file mode 100644 index 0000000..ad9bb05 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ModItems.java @@ -0,0 +1,24 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.ModBlocks; +import com.vinlanx.explosionoverhaul.VinlanxTheLightItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.neoforge.registries.ForgeRegistries; +import net.neoforged.neoforge.registries.IForgeRegistry; +import net.neoforged.neoforge.registries.RegistryObject; + +public class ModItems { + public static final DeferredRegister ITEMS = DeferredRegister.create((IForgeRegistry)ForgeRegistries.ITEMS, (String)"explosionoverhaul"); + public static final RegistryObject VINLANX_THE_LIGHT = ITEMS.register("vinlanx_the_light", () -> new VinlanxTheLightItem((Block)ModBlocks.VINLANX_THE_LIGHT.get(), new Item.Properties())); + public static final RegistryObject MOD_LOGO = ITEMS.register("mod_logo", () -> new Item(new Item.Properties())); + + public static void register(IEventBus eventBus) { + ITEMS.register(eventBus); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ModParticles.java b/src/main/java/com/vinlanx/explosionoverhaul/ModParticles.java new file mode 100644 index 0000000..e67b8a8 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ModParticles.java @@ -0,0 +1,43 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.mojang.serialization.Codec; +import com.vinlanx.explosionoverhaul.CustomGlowParticleOptions; +import com.vinlanx.explosionoverhaul.PlasmaParticleOptions; +import com.vinlanx.explosionoverhaul.SmokeParticleOptions; +import net.minecraft.core.particles.ParticleType; +import net.minecraft.core.particles.SimpleParticleType; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.neoforge.registries.ForgeRegistries; +import net.neoforged.neoforge.registries.IForgeRegistry; +import net.neoforged.neoforge.registries.RegistryObject; + +public class ModParticles { + public static final DeferredRegister> PARTICLE_TYPES = DeferredRegister.create((IForgeRegistry)ForgeRegistries.PARTICLE_TYPES, (String)"explosionoverhaul"); + public static final RegistryObject> CUSTOM_GLOW = PARTICLE_TYPES.register("custom_glow", () -> new ParticleType(true, CustomGlowParticleOptions.DESERIALIZER){ + + public Codec m_7652_() { + return CustomGlowParticleOptions.CODEC; + } + }); + public static final RegistryObject> PLASMA = PARTICLE_TYPES.register("plasma", () -> new ParticleType(false, PlasmaParticleOptions.DESERIALIZER){ + + public Codec m_7652_() { + return PlasmaParticleOptions.CODEC; + } + }); + public static final RegistryObject> CUSTOM_SMOKE = PARTICLE_TYPES.register("smoke", () -> new ParticleType(false, SmokeParticleOptions.DESERIALIZER){ + + public Codec m_7652_() { + return SmokeParticleOptions.CODEC; + } + }); + public static final RegistryObject LINE_SPARK = PARTICLE_TYPES.register("line_spark", () -> new SimpleParticleType(true)); + + public static void register(IEventBus eventBus) { + PARTICLE_TYPES.register(eventBus); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ModSounds.java b/src/main/java/com/vinlanx/explosionoverhaul/ModSounds.java new file mode 100644 index 0000000..5406fae --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ModSounds.java @@ -0,0 +1,374 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import java.util.List; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvent; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.neoforge.registries.ForgeRegistries; +import net.neoforged.neoforge.registries.IForgeRegistry; +import net.neoforged.neoforge.registries.RegistryObject; + +public class ModSounds { + public static final DeferredRegister SOUNDS = DeferredRegister.create((IForgeRegistry)ForgeRegistries.SOUND_EVENTS, (String)"explosionoverhaul"); + public static final RegistryObject BUTTON_SOUND = ModSounds.register("button_sound"); + public static final RegistryObject HEART_LAB = ModSounds.register("lab"); + public static final RegistryObject HEART_DAB = ModSounds.register("dab"); + public static final RegistryObject LOW_SOUND = ModSounds.register("low"); + public static final RegistryObject DUST_SOUND = ModSounds.register("dust"); + public static final RegistryObject FALLING_STONES_SOUND = ModSounds.register("falling_stones"); + public static final RegistryObject EXPLODE_CLOSE_POWER_1_1 = ModSounds.register("explode_close_power_1_1"); + public static final RegistryObject EXPLODE_CLOSE_POWER_1_2 = ModSounds.register("explode_close_power_1_2"); + public static final RegistryObject EXPLODE_CLOSE_POWER_1_3 = ModSounds.register("explode_close_power_1_3"); + public static final RegistryObject EXPLODE_CLOSE_POWER_2_1 = ModSounds.register("explode_close_power_2_1"); + public static final RegistryObject EXPLODE_CLOSE_POWER_2_2 = ModSounds.register("explode_close_power_2_2"); + public static final RegistryObject EXPLODE_CLOSE_POWER_2_3 = ModSounds.register("explode_close_power_2_3"); + public static final RegistryObject EXPLODE_CLOSE_POWER_3_1 = ModSounds.register("explode_close_power_3_1"); + public static final RegistryObject EXPLODE_CLOSE_POWER_3_2 = ModSounds.register("explode_close_power_3_2"); + public static final RegistryObject EXPLODE_CLOSE_POWER_3_3 = ModSounds.register("explode_close_power_3_3"); + public static final RegistryObject EXPLODE_CLOSE_POWER_4_1 = ModSounds.register("explode_close_power_4_1"); + public static final RegistryObject EXPLODE_CLOSE_POWER_4_2 = ModSounds.register("explode_close_power_4_2"); + public static final RegistryObject EXPLODE_CLOSE_POWER_4_3 = ModSounds.register("explode_close_power_4_3"); + public static final RegistryObject EXPLODE_CLOSE_POWER_5_1 = ModSounds.register("explode_close_power_5_1"); + public static final RegistryObject EXPLODE_CLOSE_POWER_5_2 = ModSounds.register("explode_close_power_5_2"); + public static final RegistryObject EXPLODE_CLOSE_POWER_5_3 = ModSounds.register("explode_close_power_5_3"); + public static final RegistryObject EXPLODE_CLOSE_POWER_6_1 = ModSounds.register("explode_close_power_6_1"); + public static final RegistryObject EXPLODE_CLOSE_POWER_6_2 = ModSounds.register("explode_close_power_6_2"); + public static final RegistryObject EXPLODE_CLOSE_POWER_6_3 = ModSounds.register("explode_close_power_6_3"); + public static final RegistryObject EXPLODE_CLOSE_POWER_7_1 = ModSounds.register("explode_close_power_7_1"); + public static final RegistryObject EXPLODE_CLOSE_POWER_7_2 = ModSounds.register("explode_close_power_7_2"); + public static final RegistryObject EXPLODE_CLOSE_POWER_7_3 = ModSounds.register("explode_close_power_7_3"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_1_1 = ModSounds.register("explode_medium_power_1_1"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_1_2 = ModSounds.register("explode_medium_power_1_2"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_1_3 = ModSounds.register("explode_medium_power_1_3"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_2_1 = ModSounds.register("explode_medium_power_2_1"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_2_2 = ModSounds.register("explode_medium_power_2_2"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_2_3 = ModSounds.register("explode_medium_power_2_3"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_3_1 = ModSounds.register("explode_medium_power_3_1"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_3_2 = ModSounds.register("explode_medium_power_3_2"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_3_3 = ModSounds.register("explode_medium_power_3_3"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_4_1 = ModSounds.register("explode_medium_power_4_1"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_4_2 = ModSounds.register("explode_medium_power_4_2"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_4_3 = ModSounds.register("explode_medium_power_4_3"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_5_1 = ModSounds.register("explode_medium_power_5_1"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_5_2 = ModSounds.register("explode_medium_power_5_2"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_5_3 = ModSounds.register("explode_medium_power_5_3"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_6_1 = ModSounds.register("explode_medium_power_6_1"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_6_2 = ModSounds.register("explode_medium_power_6_2"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_6_3 = ModSounds.register("explode_medium_power_6_3"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_7_1 = ModSounds.register("explode_medium_power_7_1"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_7_2 = ModSounds.register("explode_medium_power_7_2"); + public static final RegistryObject EXPLODE_MEDIUM_POWER_7_3 = ModSounds.register("explode_medium_power_7_3"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_1_1 = ModSounds.register("explode_medium_cave_power_1_1"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_1_2 = ModSounds.register("explode_medium_cave_power_1_2"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_1_3 = ModSounds.register("explode_medium_cave_power_1_3"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_2_1 = ModSounds.register("explode_medium_cave_power_2_1"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_2_2 = ModSounds.register("explode_medium_cave_power_2_2"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_2_3 = ModSounds.register("explode_medium_cave_power_2_3"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_3_1 = ModSounds.register("explode_medium_cave_power_3_1"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_3_2 = ModSounds.register("explode_medium_cave_power_3_2"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_3_3 = ModSounds.register("explode_medium_cave_power_3_3"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_4_1 = ModSounds.register("explode_medium_cave_power_4_1"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_4_2 = ModSounds.register("explode_medium_cave_power_4_2"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_4_3 = ModSounds.register("explode_medium_cave_power_4_3"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_5_1 = ModSounds.register("explode_medium_cave_power_5_1"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_5_2 = ModSounds.register("explode_medium_cave_power_5_2"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_5_3 = ModSounds.register("explode_medium_cave_power_5_3"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_6_1 = ModSounds.register("explode_medium_cave_power_6_1"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_6_2 = ModSounds.register("explode_medium_cave_power_6_2"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_6_3 = ModSounds.register("explode_medium_cave_power_6_3"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_7_1 = ModSounds.register("explode_medium_cave_power_7_1"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_7_2 = ModSounds.register("explode_medium_cave_power_7_2"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_POWER_7_3 = ModSounds.register("explode_medium_cave_power_7_3"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_1_1 = ModSounds.register("explode_medium_to_house_power_1_1"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_1_2 = ModSounds.register("explode_medium_to_house_power_1_2"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_1_3 = ModSounds.register("explode_medium_to_house_power_1_3"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_2_1 = ModSounds.register("explode_medium_to_house_power_2_1"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_2_2 = ModSounds.register("explode_medium_to_house_power_2_2"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_2_3 = ModSounds.register("explode_medium_to_house_power_2_3"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_3_1 = ModSounds.register("explode_medium_to_house_power_3_1"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_3_2 = ModSounds.register("explode_medium_to_house_power_3_2"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_3_3 = ModSounds.register("explode_medium_to_house_power_3_3"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_4_1 = ModSounds.register("explode_medium_to_house_power_4_1"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_4_2 = ModSounds.register("explode_medium_to_house_power_4_2"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_4_3 = ModSounds.register("explode_medium_to_house_power_4_3"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_5_1 = ModSounds.register("explode_medium_to_house_power_5_1"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_5_2 = ModSounds.register("explode_medium_to_house_power_5_2"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_5_3 = ModSounds.register("explode_medium_to_house_power_5_3"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_6_1 = ModSounds.register("explode_medium_to_house_power_6_1"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_6_2 = ModSounds.register("explode_medium_to_house_power_6_2"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_6_3 = ModSounds.register("explode_medium_to_house_power_6_3"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_7_1 = ModSounds.register("explode_medium_to_house_power_7_1"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_7_2 = ModSounds.register("explode_medium_to_house_power_7_2"); + public static final RegistryObject EXPLODE_MEDIUM_TO_HOUSE_POWER_7_3 = ModSounds.register("explode_medium_to_house_power_7_3"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_1_1 = ModSounds.register("explode_medium_underground_power_1_1"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_1_2 = ModSounds.register("explode_medium_underground_power_1_2"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_1_3 = ModSounds.register("explode_medium_underground_power_1_3"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_2_1 = ModSounds.register("explode_medium_underground_power_2_1"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_2_2 = ModSounds.register("explode_medium_underground_power_2_2"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_2_3 = ModSounds.register("explode_medium_underground_power_2_3"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_3_1 = ModSounds.register("explode_medium_underground_power_3_1"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_3_2 = ModSounds.register("explode_medium_underground_power_3_2"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_3_3 = ModSounds.register("explode_medium_underground_power_3_3"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_4_1 = ModSounds.register("explode_medium_underground_power_4_1"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_4_2 = ModSounds.register("explode_medium_underground_power_4_2"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_4_3 = ModSounds.register("explode_medium_underground_power_4_3"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_5_1 = ModSounds.register("explode_medium_underground_power_5_1"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_5_2 = ModSounds.register("explode_medium_underground_power_5_2"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_5_3 = ModSounds.register("explode_medium_underground_power_5_3"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_6_1 = ModSounds.register("explode_medium_underground_power_6_1"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_6_2 = ModSounds.register("explode_medium_underground_power_6_2"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_6_3 = ModSounds.register("explode_medium_underground_power_6_3"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_7_1 = ModSounds.register("explode_medium_underground_power_7_1"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_7_2 = ModSounds.register("explode_medium_underground_power_7_2"); + public static final RegistryObject EXPLODE_MEDIUM_UNDERGROUND_POWER_7_3 = ModSounds.register("explode_medium_underground_power_7_3"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_1_1 = ModSounds.register("explode_medium_cave_to_house_power_1_1"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_1_2 = ModSounds.register("explode_medium_cave_to_house_power_1_2"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_1_3 = ModSounds.register("explode_medium_cave_to_house_power_1_3"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_2_1 = ModSounds.register("explode_medium_cave_to_house_power_2_1"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_2_2 = ModSounds.register("explode_medium_cave_to_house_power_2_2"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_2_3 = ModSounds.register("explode_medium_cave_to_house_power_2_3"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_3_1 = ModSounds.register("explode_medium_cave_to_house_power_3_1"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_3_2 = ModSounds.register("explode_medium_cave_to_house_power_3_2"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_3_3 = ModSounds.register("explode_medium_cave_to_house_power_3_3"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_4_1 = ModSounds.register("explode_medium_cave_to_house_power_4_1"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_4_2 = ModSounds.register("explode_medium_cave_to_house_power_4_2"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_4_3 = ModSounds.register("explode_medium_cave_to_house_power_4_3"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_5_1 = ModSounds.register("explode_medium_cave_to_house_power_5_1"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_5_2 = ModSounds.register("explode_medium_cave_to_house_power_5_2"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_5_3 = ModSounds.register("explode_medium_cave_to_house_power_5_3"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_6_1 = ModSounds.register("explode_medium_cave_to_house_power_6_1"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_6_2 = ModSounds.register("explode_medium_cave_to_house_power_6_2"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_6_3 = ModSounds.register("explode_medium_cave_to_house_power_6_3"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_7_1 = ModSounds.register("explode_medium_cave_to_house_power_7_1"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_7_2 = ModSounds.register("explode_medium_cave_to_house_power_7_2"); + public static final RegistryObject EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_7_3 = ModSounds.register("explode_medium_cave_to_house_power_7_3"); + public static final RegistryObject EXPLODE_FAR_POWER_1_1 = ModSounds.register("explode_far_power_1_1"); + public static final RegistryObject EXPLODE_FAR_POWER_1_2 = ModSounds.register("explode_far_power_1_2"); + public static final RegistryObject EXPLODE_FAR_POWER_1_3 = ModSounds.register("explode_far_power_1_3"); + public static final RegistryObject EXPLODE_FAR_POWER_2_1 = ModSounds.register("explode_far_power_2_1"); + public static final RegistryObject EXPLODE_FAR_POWER_2_2 = ModSounds.register("explode_far_power_2_2"); + public static final RegistryObject EXPLODE_FAR_POWER_2_3 = ModSounds.register("explode_far_power_2_3"); + public static final RegistryObject EXPLODE_FAR_POWER_3_1 = ModSounds.register("explode_far_power_3_1"); + public static final RegistryObject EXPLODE_FAR_POWER_3_2 = ModSounds.register("explode_far_power_3_2"); + public static final RegistryObject EXPLODE_FAR_POWER_3_3 = ModSounds.register("explode_far_power_3_3"); + public static final RegistryObject EXPLODE_FAR_POWER_4_1 = ModSounds.register("explode_far_power_4_1"); + public static final RegistryObject EXPLODE_FAR_POWER_4_2 = ModSounds.register("explode_far_power_4_2"); + public static final RegistryObject EXPLODE_FAR_POWER_4_3 = ModSounds.register("explode_far_power_4_3"); + public static final RegistryObject EXPLODE_FAR_POWER_5_1 = ModSounds.register("explode_far_power_5_1"); + public static final RegistryObject EXPLODE_FAR_POWER_5_2 = ModSounds.register("explode_far_power_5_2"); + public static final RegistryObject EXPLODE_FAR_POWER_5_3 = ModSounds.register("explode_far_power_5_3"); + public static final RegistryObject EXPLODE_FAR_POWER_6_1 = ModSounds.register("explode_far_power_6_1"); + public static final RegistryObject EXPLODE_FAR_POWER_6_2 = ModSounds.register("explode_far_power_6_2"); + public static final RegistryObject EXPLODE_FAR_POWER_6_3 = ModSounds.register("explode_far_power_6_3"); + public static final RegistryObject EXPLODE_FAR_POWER_7_1 = ModSounds.register("explode_far_power_7_1"); + public static final RegistryObject EXPLODE_FAR_POWER_7_2 = ModSounds.register("explode_far_power_7_2"); + public static final RegistryObject EXPLODE_FAR_POWER_7_3 = ModSounds.register("explode_far_power_7_3"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_1_1 = ModSounds.register("explode_superfar_power_1_1"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_1_2 = ModSounds.register("explode_superfar_power_1_2"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_1_3 = ModSounds.register("explode_superfar_power_1_3"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_2_1 = ModSounds.register("explode_superfar_power_2_1"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_2_2 = ModSounds.register("explode_superfar_power_2_2"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_2_3 = ModSounds.register("explode_superfar_power_2_3"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_3_1 = ModSounds.register("explode_superfar_power_3_1"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_3_2 = ModSounds.register("explode_superfar_power_3_2"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_3_3 = ModSounds.register("explode_superfar_power_3_3"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_4_1 = ModSounds.register("explode_superfar_power_4_1"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_4_2 = ModSounds.register("explode_superfar_power_4_2"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_4_3 = ModSounds.register("explode_superfar_power_4_3"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_5_1 = ModSounds.register("explode_superfar_power_5_1"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_5_2 = ModSounds.register("explode_superfar_power_5_2"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_5_3 = ModSounds.register("explode_superfar_power_5_3"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_6_1 = ModSounds.register("explode_superfar_power_6_1"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_6_2 = ModSounds.register("explode_superfar_power_6_2"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_6_3 = ModSounds.register("explode_superfar_power_6_3"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_7_1 = ModSounds.register("explode_superfar_power_7_1"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_7_2 = ModSounds.register("explode_superfar_power_7_2"); + public static final RegistryObject EXPLODE_SUPERFAR_POWER_7_3 = ModSounds.register("explode_superfar_power_7_3"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_1_1 = ModSounds.register("explode_far_cave_power_1_1"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_1_2 = ModSounds.register("explode_far_cave_power_1_2"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_1_3 = ModSounds.register("explode_far_cave_power_1_3"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_2_1 = ModSounds.register("explode_far_cave_power_2_1"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_2_2 = ModSounds.register("explode_far_cave_power_2_2"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_2_3 = ModSounds.register("explode_far_cave_power_2_3"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_3_1 = ModSounds.register("explode_far_cave_power_3_1"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_3_2 = ModSounds.register("explode_far_cave_power_3_2"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_3_3 = ModSounds.register("explode_far_cave_power_3_3"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_4_1 = ModSounds.register("explode_far_cave_power_4_1"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_4_2 = ModSounds.register("explode_far_cave_power_4_2"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_4_3 = ModSounds.register("explode_far_cave_power_4_3"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_5_1 = ModSounds.register("explode_far_cave_power_5_1"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_5_2 = ModSounds.register("explode_far_cave_power_5_2"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_5_3 = ModSounds.register("explode_far_cave_power_5_3"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_6_1 = ModSounds.register("explode_far_cave_power_6_1"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_6_2 = ModSounds.register("explode_far_cave_power_6_2"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_6_3 = ModSounds.register("explode_far_cave_power_6_3"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_7_1 = ModSounds.register("explode_far_cave_power_7_1"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_7_2 = ModSounds.register("explode_far_cave_power_7_2"); + public static final RegistryObject EXPLODE_FAR_CAVE_POWER_7_3 = ModSounds.register("explode_far_cave_power_7_3"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_1_1 = ModSounds.register("explode_superfar_cave_power_1_1"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_1_2 = ModSounds.register("explode_superfar_cave_power_1_2"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_1_3 = ModSounds.register("explode_superfar_cave_power_1_3"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_2_1 = ModSounds.register("explode_superfar_cave_power_2_1"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_2_2 = ModSounds.register("explode_superfar_cave_power_2_2"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_2_3 = ModSounds.register("explode_superfar_cave_power_2_3"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_3_1 = ModSounds.register("explode_superfar_cave_power_3_1"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_3_2 = ModSounds.register("explode_superfar_cave_power_3_2"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_3_3 = ModSounds.register("explode_superfar_cave_power_3_3"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_4_1 = ModSounds.register("explode_superfar_cave_power_4_1"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_4_2 = ModSounds.register("explode_superfar_cave_power_4_2"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_4_3 = ModSounds.register("explode_superfar_cave_power_4_3"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_5_1 = ModSounds.register("explode_superfar_cave_power_5_1"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_5_2 = ModSounds.register("explode_superfar_cave_power_5_2"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_5_3 = ModSounds.register("explode_superfar_cave_power_5_3"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_6_1 = ModSounds.register("explode_superfar_cave_power_6_1"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_6_2 = ModSounds.register("explode_superfar_cave_power_6_2"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_6_3 = ModSounds.register("explode_superfar_cave_power_6_3"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_7_1 = ModSounds.register("explode_superfar_cave_power_7_1"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_7_2 = ModSounds.register("explode_superfar_cave_power_7_2"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_POWER_7_3 = ModSounds.register("explode_superfar_cave_power_7_3"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_1_1 = ModSounds.register("explode_far_underground_power_1_1"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_1_2 = ModSounds.register("explode_far_underground_power_1_2"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_1_3 = ModSounds.register("explode_far_underground_power_1_3"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_2_1 = ModSounds.register("explode_far_underground_power_2_1"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_2_2 = ModSounds.register("explode_far_underground_power_2_2"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_2_3 = ModSounds.register("explode_far_underground_power_2_3"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_3_1 = ModSounds.register("explode_far_underground_power_3_1"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_3_2 = ModSounds.register("explode_far_underground_power_3_2"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_3_3 = ModSounds.register("explode_far_underground_power_3_3"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_4_1 = ModSounds.register("explode_far_underground_power_4_1"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_4_2 = ModSounds.register("explode_far_underground_power_4_2"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_4_3 = ModSounds.register("explode_far_underground_power_4_3"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_5_1 = ModSounds.register("explode_far_underground_power_5_1"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_5_2 = ModSounds.register("explode_far_underground_power_5_2"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_5_3 = ModSounds.register("explode_far_underground_power_5_3"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_6_1 = ModSounds.register("explode_far_underground_power_6_1"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_6_2 = ModSounds.register("explode_far_underground_power_6_2"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_6_3 = ModSounds.register("explode_far_underground_power_6_3"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_7_1 = ModSounds.register("explode_far_underground_power_7_1"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_7_2 = ModSounds.register("explode_far_underground_power_7_2"); + public static final RegistryObject EXPLODE_FAR_UNDERGROUND_POWER_7_3 = ModSounds.register("explode_far_underground_power_7_3"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_1_1 = ModSounds.register("explode_superfar_underground_power_1_1"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_1_2 = ModSounds.register("explode_superfar_underground_power_1_2"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_1_3 = ModSounds.register("explode_superfar_underground_power_1_3"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_2_1 = ModSounds.register("explode_superfar_underground_power_2_1"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_2_2 = ModSounds.register("explode_superfar_underground_power_2_2"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_2_3 = ModSounds.register("explode_superfar_underground_power_2_3"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_3_1 = ModSounds.register("explode_superfar_underground_power_3_1"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_3_2 = ModSounds.register("explode_superfar_underground_power_3_2"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_3_3 = ModSounds.register("explode_superfar_underground_power_3_3"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_4_1 = ModSounds.register("explode_superfar_underground_power_4_1"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_4_2 = ModSounds.register("explode_superfar_underground_power_4_2"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_4_3 = ModSounds.register("explode_superfar_underground_power_4_3"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_5_1 = ModSounds.register("explode_superfar_underground_power_5_1"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_5_2 = ModSounds.register("explode_superfar_underground_power_5_2"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_5_3 = ModSounds.register("explode_superfar_underground_power_5_3"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_6_1 = ModSounds.register("explode_superfar_underground_power_6_1"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_6_2 = ModSounds.register("explode_superfar_underground_power_6_2"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_6_3 = ModSounds.register("explode_superfar_underground_power_6_3"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_7_1 = ModSounds.register("explode_superfar_underground_power_7_1"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_7_2 = ModSounds.register("explode_superfar_underground_power_7_2"); + public static final RegistryObject EXPLODE_SUPERFAR_UNDERGROUND_POWER_7_3 = ModSounds.register("explode_superfar_underground_power_7_3"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_1_1 = ModSounds.register("explode_far_to_house_power_1_1"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_1_2 = ModSounds.register("explode_far_to_house_power_1_2"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_1_3 = ModSounds.register("explode_far_to_house_power_1_3"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_2_1 = ModSounds.register("explode_far_to_house_power_2_1"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_2_2 = ModSounds.register("explode_far_to_house_power_2_2"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_2_3 = ModSounds.register("explode_far_to_house_power_2_3"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_3_1 = ModSounds.register("explode_far_to_house_power_3_1"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_3_2 = ModSounds.register("explode_far_to_house_power_3_2"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_3_3 = ModSounds.register("explode_far_to_house_power_3_3"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_4_1 = ModSounds.register("explode_far_to_house_power_4_1"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_4_2 = ModSounds.register("explode_far_to_house_power_4_2"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_4_3 = ModSounds.register("explode_far_to_house_power_4_3"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_5_1 = ModSounds.register("explode_far_to_house_power_5_1"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_5_2 = ModSounds.register("explode_far_to_house_power_5_2"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_5_3 = ModSounds.register("explode_far_to_house_power_5_3"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_6_1 = ModSounds.register("explode_far_to_house_power_6_1"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_6_2 = ModSounds.register("explode_far_to_house_power_6_2"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_6_3 = ModSounds.register("explode_far_to_house_power_6_3"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_7_1 = ModSounds.register("explode_far_to_house_power_7_1"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_7_2 = ModSounds.register("explode_far_to_house_power_7_2"); + public static final RegistryObject EXPLODE_FAR_TO_HOUSE_POWER_7_3 = ModSounds.register("explode_far_to_house_power_7_3"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_1_1 = ModSounds.register("explode_far_cave_to_house_power_1_1"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_1_2 = ModSounds.register("explode_far_cave_to_house_power_1_2"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_1_3 = ModSounds.register("explode_far_cave_to_house_power_1_3"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_2_1 = ModSounds.register("explode_far_cave_to_house_power_2_1"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_2_2 = ModSounds.register("explode_far_cave_to_house_power_2_2"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_2_3 = ModSounds.register("explode_far_cave_to_house_power_2_3"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_3_1 = ModSounds.register("explode_far_cave_to_house_power_3_1"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_3_2 = ModSounds.register("explode_far_cave_to_house_power_3_2"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_3_3 = ModSounds.register("explode_far_cave_to_house_power_3_3"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_4_1 = ModSounds.register("explode_far_cave_to_house_power_4_1"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_4_2 = ModSounds.register("explode_far_cave_to_house_power_4_2"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_4_3 = ModSounds.register("explode_far_cave_to_house_power_4_3"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_5_1 = ModSounds.register("explode_far_cave_to_house_power_5_1"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_5_2 = ModSounds.register("explode_far_cave_to_house_power_5_2"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_5_3 = ModSounds.register("explode_far_cave_to_house_power_5_3"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_6_1 = ModSounds.register("explode_far_cave_to_house_power_6_1"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_6_2 = ModSounds.register("explode_far_cave_to_house_power_6_2"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_6_3 = ModSounds.register("explode_far_cave_to_house_power_6_3"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_7_1 = ModSounds.register("explode_far_cave_to_house_power_7_1"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_7_2 = ModSounds.register("explode_far_cave_to_house_power_7_2"); + public static final RegistryObject EXPLODE_FAR_CAVE_TO_HOUSE_POWER_7_3 = ModSounds.register("explode_far_cave_to_house_power_7_3"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_1_1 = ModSounds.register("explode_superfar_to_house_power_1_1"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_1_2 = ModSounds.register("explode_superfar_to_house_power_1_2"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_1_3 = ModSounds.register("explode_superfar_to_house_power_1_3"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_2_1 = ModSounds.register("explode_superfar_to_house_power_2_1"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_2_2 = ModSounds.register("explode_superfar_to_house_power_2_2"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_2_3 = ModSounds.register("explode_superfar_to_house_power_2_3"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_3_1 = ModSounds.register("explode_superfar_to_house_power_3_1"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_3_2 = ModSounds.register("explode_superfar_to_house_power_3_2"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_3_3 = ModSounds.register("explode_superfar_to_house_power_3_3"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_4_1 = ModSounds.register("explode_superfar_to_house_power_4_1"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_4_2 = ModSounds.register("explode_superfar_to_house_power_4_2"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_4_3 = ModSounds.register("explode_superfar_to_house_power_4_3"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_5_1 = ModSounds.register("explode_superfar_to_house_power_5_1"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_5_2 = ModSounds.register("explode_superfar_to_house_power_5_2"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_5_3 = ModSounds.register("explode_superfar_to_house_power_5_3"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_6_1 = ModSounds.register("explode_superfar_to_house_power_6_1"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_6_2 = ModSounds.register("explode_superfar_to_house_power_6_2"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_6_3 = ModSounds.register("explode_superfar_to_house_power_6_3"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_7_1 = ModSounds.register("explode_superfar_to_house_power_7_1"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_7_2 = ModSounds.register("explode_superfar_to_house_power_7_2"); + public static final RegistryObject EXPLODE_SUPERFAR_TO_HOUSE_POWER_7_3 = ModSounds.register("explode_superfar_to_house_power_7_3"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_1_1 = ModSounds.register("explode_superfar_cave_to_house_power_1_1"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_1_2 = ModSounds.register("explode_superfar_cave_to_house_power_1_2"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_1_3 = ModSounds.register("explode_superfar_cave_to_house_power_1_3"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_2_1 = ModSounds.register("explode_superfar_cave_to_house_power_2_1"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_2_2 = ModSounds.register("explode_superfar_cave_to_house_power_2_2"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_2_3 = ModSounds.register("explode_superfar_cave_to_house_power_2_3"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_3_1 = ModSounds.register("explode_superfar_cave_to_house_power_3_1"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_3_2 = ModSounds.register("explode_superfar_cave_to_house_power_3_2"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_3_3 = ModSounds.register("explode_superfar_cave_to_house_power_3_3"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_4_1 = ModSounds.register("explode_superfar_cave_to_house_power_4_1"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_4_2 = ModSounds.register("explode_superfar_cave_to_house_power_4_2"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_4_3 = ModSounds.register("explode_superfar_cave_to_house_power_4_3"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_5_1 = ModSounds.register("explode_superfar_cave_to_house_power_5_1"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_5_2 = ModSounds.register("explode_superfar_cave_to_house_power_5_2"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_5_3 = ModSounds.register("explode_superfar_cave_to_house_power_5_3"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_6_1 = ModSounds.register("explode_superfar_cave_to_house_power_6_1"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_6_2 = ModSounds.register("explode_superfar_cave_to_house_power_6_2"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_6_3 = ModSounds.register("explode_superfar_cave_to_house_power_6_3"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_7_1 = ModSounds.register("explode_superfar_cave_to_house_power_7_1"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_7_2 = ModSounds.register("explode_superfar_cave_to_house_power_7_2"); + public static final RegistryObject EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_7_3 = ModSounds.register("explode_superfar_cave_to_house_power_7_3"); + public static final RegistryObject LAMP_FLICKER_SPARK_1 = ModSounds.register("lamp_flicker_spark_1"); + public static final RegistryObject LAMP_FLICKER_SPARK_2 = ModSounds.register("lamp_flicker_spark_2"); + public static final RegistryObject LAMP_FLICKER_SPARK_3 = ModSounds.register("lamp_flicker_spark_3"); + public static final RegistryObject INTRO_MUSIC = ModSounds.register("intro_music"); + public static final RegistryObject INTRO_BOOM = ModSounds.register("intro_boom"); + public static final RegistryObject INTRO_BOOM_2 = ModSounds.register("intro_boom_2"); + public static final List> LAMP_FLICKER_SOUNDS = List.of(LAMP_FLICKER_SPARK_1, LAMP_FLICKER_SPARK_2, LAMP_FLICKER_SPARK_3); + + private static RegistryObject register(String name) { + return SOUNDS.register(name, () -> SoundEvent.m_262824_((ResourceLocation)new ResourceLocation("explosionoverhaul", name))); + } + + public static void register(IEventBus eventBus) { + SOUNDS.register(eventBus); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/OpenALTogglePacket.java b/src/main/java/com/vinlanx/explosionoverhaul/OpenALTogglePacket.java new file mode 100644 index 0000000..16b2894 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/OpenALTogglePacket.java @@ -0,0 +1,59 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.client.DeafnessConcussionEffect; +import com.vinlanx.explosionoverhaul.client.LowPassConcussionEffect; +import java.util.function.Supplier; +import net.minecraft.client.Minecraft; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.DistExecutor; +import net.neoforged.neoforge.network.NetworkEvent; + +public class OpenALTogglePacket { + private final String target; + private final boolean enabled; + + public OpenALTogglePacket(String target, boolean enabled) { + this.target = target; + this.enabled = enabled; + } + + public OpenALTogglePacket(FriendlyByteBuf buf) { + this.target = buf.m_130136_(Short.MAX_VALUE); + this.enabled = buf.readBoolean(); + } + + public void encode(FriendlyByteBuf buf) { + buf.m_130070_(this.target); + buf.writeBoolean(this.enabled); + } + + public static OpenALTogglePacket decode(FriendlyByteBuf buf) { + return new OpenALTogglePacket(buf); + } + + public static void handle(OpenALTogglePacket packet, Supplier ctxSupplier) { + NetworkEvent.Context ctx = ctxSupplier.get(); + ctx.enqueueWork(() -> DistExecutor.unsafeRunWhenOn((Dist)Dist.CLIENT, () -> () -> { + String t = packet.target.toLowerCase(); + if (t.equals("deafness")) { + DeafnessConcussionEffect.enabled = packet.enabled; + DeafnessConcussionEffect.debugShowChat = packet.enabled; + if (DeafnessConcussionEffect.debugShowChat) { + Minecraft.m_91087_().f_91074_.m_5661_((Component)Component.m_237113_((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.m_91087_().f_91074_.m_5661_((Component)Component.m_237113_((String)("LowPass effect set to " + (packet.enabled ? "ON" : "OFF"))), false); + } + } + })); + ctx.setPacketHandled(true); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/PacketHandler.java b/src/main/java/com/vinlanx/explosionoverhaul/PacketHandler.java new file mode 100644 index 0000000..40e3db0 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/PacketHandler.java @@ -0,0 +1,61 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.BlurTestPacket; +import com.vinlanx.explosionoverhaul.CameraShakeConcussionPacket; +import com.vinlanx.explosionoverhaul.CameraShakePacket; +import com.vinlanx.explosionoverhaul.ExplosionVisualsPacket; +import com.vinlanx.explosionoverhaul.FlashEffectPacket; +import com.vinlanx.explosionoverhaul.LowPassTestPacket; +import com.vinlanx.explosionoverhaul.OpenALTogglePacket; +import com.vinlanx.explosionoverhaul.PlayTrackedSoundPacket; +import com.vinlanx.explosionoverhaul.ScanControlPacket; +import com.vinlanx.explosionoverhaul.ScanInfoPacket; +import com.vinlanx.explosionoverhaul.ScanLoadControlPacket; +import com.vinlanx.explosionoverhaul.ScanLoadPromptPacket; +import com.vinlanx.explosionoverhaul.ScanProgressPacket; +import com.vinlanx.explosionoverhaul.ScanPromptPacket; +import com.vinlanx.explosionoverhaul.SpawnAmbientCaveDustPacket; +import com.vinlanx.explosionoverhaul.SpawnCustomGlowPacket; +import com.vinlanx.explosionoverhaul.SpawnDustCloudPacket; +import com.vinlanx.explosionoverhaul.SpawnLineSparksPacket; +import com.vinlanx.explosionoverhaul.SpawnMistCloudPacket; +import com.vinlanx.explosionoverhaul.SpawnShockwavePacket; +import com.vinlanx.explosionoverhaul.StartConcussionPacket; +import com.vinlanx.explosionoverhaul.SuppressExplosionSoundPacket; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.neoforge.network.NetworkRegistry; +import net.neoforged.neoforge.network.simple.SimpleChannel; + +public class PacketHandler { + private static final String PROTOCOL_VERSION = "1"; + public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel((ResourceLocation)ResourceLocation.fromNamespaceAndPath((String)"explosionoverhaul", (String)"main"), () -> "1", "1"::equals, "1"::equals); + + public static void register() { + int messageId = 0; + INSTANCE.registerMessage(messageId++, CameraShakePacket.class, CameraShakePacket::encode, CameraShakePacket::decode, CameraShakePacket::handle); + INSTANCE.registerMessage(messageId++, ExplosionVisualsPacket.class, ExplosionVisualsPacket::encode, ExplosionVisualsPacket::decode, ExplosionVisualsPacket::handle); + INSTANCE.registerMessage(messageId++, SpawnCustomGlowPacket.class, SpawnCustomGlowPacket::encode, SpawnCustomGlowPacket::decode, SpawnCustomGlowPacket::handle); + INSTANCE.registerMessage(messageId++, PlayTrackedSoundPacket.class, PlayTrackedSoundPacket::encode, PlayTrackedSoundPacket::decode, PlayTrackedSoundPacket::handle); + INSTANCE.registerMessage(messageId++, SuppressExplosionSoundPacket.class, SuppressExplosionSoundPacket::encode, SuppressExplosionSoundPacket::decode, SuppressExplosionSoundPacket::handle); + INSTANCE.registerMessage(messageId++, StartConcussionPacket.class, StartConcussionPacket::encode, StartConcussionPacket::decode, StartConcussionPacket::handle); + INSTANCE.registerMessage(messageId++, SpawnShockwavePacket.class, SpawnShockwavePacket::encode, SpawnShockwavePacket::decode, SpawnShockwavePacket::handle); + INSTANCE.registerMessage(messageId++, SpawnDustCloudPacket.class, SpawnDustCloudPacket::encode, SpawnDustCloudPacket::decode, SpawnDustCloudPacket::handle); + INSTANCE.registerMessage(messageId++, SpawnMistCloudPacket.class, SpawnMistCloudPacket::encode, SpawnMistCloudPacket::decode, SpawnMistCloudPacket::handle); + INSTANCE.registerMessage(messageId++, SpawnAmbientCaveDustPacket.class, SpawnAmbientCaveDustPacket::encode, SpawnAmbientCaveDustPacket::decode, SpawnAmbientCaveDustPacket::handle); + INSTANCE.registerMessage(messageId++, SpawnLineSparksPacket.class, SpawnLineSparksPacket::encode, SpawnLineSparksPacket::decode, SpawnLineSparksPacket::handle); + INSTANCE.registerMessage(messageId++, FlashEffectPacket.class, FlashEffectPacket::encode, FlashEffectPacket::decode, FlashEffectPacket::handle); + INSTANCE.registerMessage(messageId++, LowPassTestPacket.class, LowPassTestPacket::encode, LowPassTestPacket::decode, LowPassTestPacket::handle); + INSTANCE.registerMessage(messageId++, BlurTestPacket.class, BlurTestPacket::encode, BlurTestPacket::decode, BlurTestPacket::handle); + INSTANCE.registerMessage(messageId++, CameraShakeConcussionPacket.class, CameraShakeConcussionPacket::encode, CameraShakeConcussionPacket::decode, CameraShakeConcussionPacket::handle); + INSTANCE.registerMessage(messageId++, OpenALTogglePacket.class, OpenALTogglePacket::encode, OpenALTogglePacket::decode, OpenALTogglePacket::handle); + INSTANCE.registerMessage(messageId++, ScanProgressPacket.class, ScanProgressPacket::encode, ScanProgressPacket::new, ScanProgressPacket::handle); + INSTANCE.registerMessage(messageId++, ScanPromptPacket.class, ScanPromptPacket::encode, ScanPromptPacket::decode, ScanPromptPacket::handle); + INSTANCE.registerMessage(messageId++, ScanControlPacket.class, ScanControlPacket::encode, ScanControlPacket::decode, ScanControlPacket::handle); + INSTANCE.registerMessage(messageId++, ScanInfoPacket.class, ScanInfoPacket::encode, ScanInfoPacket::decode, ScanInfoPacket::handle); + INSTANCE.registerMessage(messageId++, ScanLoadPromptPacket.class, ScanLoadPromptPacket::encode, ScanLoadPromptPacket::decode, ScanLoadPromptPacket::handle); + INSTANCE.registerMessage(messageId++, ScanLoadControlPacket.class, ScanLoadControlPacket::encode, ScanLoadControlPacket::decode, ScanLoadControlPacket::handle); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/PlasmaParticleOptions.java b/src/main/java/com/vinlanx/explosionoverhaul/PlasmaParticleOptions.java new file mode 100644 index 0000000..1e8dc2a --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/PlasmaParticleOptions.java @@ -0,0 +1,54 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.datafixers.kinds.App; +import com.mojang.datafixers.kinds.Applicative; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import com.vinlanx.explosionoverhaul.ModParticles; +import java.util.Locale; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.ParticleType; +import net.minecraft.network.FriendlyByteBuf; + +public class PlasmaParticleOptions +implements ParticleOptions { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group((App)Codec.FLOAT.fieldOf("power").forGetter(PlasmaParticleOptions::getPower)).apply((Applicative)instance, PlasmaParticleOptions::new)); + public static final ParticleOptions.Deserializer DESERIALIZER = new ParticleOptions.Deserializer(){ + + public PlasmaParticleOptions fromCommand(ParticleType particleType, StringReader reader) throws CommandSyntaxException { + reader.expect(' '); + float power = reader.readFloat(); + return new PlasmaParticleOptions(power); + } + + public PlasmaParticleOptions fromNetwork(ParticleType particleType, FriendlyByteBuf buffer) { + return new PlasmaParticleOptions(buffer.readFloat()); + } + }; + private final float power; + + public PlasmaParticleOptions(float power) { + this.power = power; + } + + public ParticleType m_6012_() { + return (ParticleType)ModParticles.PLASMA.get(); + } + + public void m_7711_(FriendlyByteBuf buffer) { + buffer.writeFloat(this.power); + } + + public String m_5942_() { + return String.format(Locale.ROOT, "%s %.2f", ModParticles.PLASMA.getId(), Float.valueOf(this.power)); + } + + public float getPower() { + return this.power; + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/PlayTrackedSoundPacket.java b/src/main/java/com/vinlanx/explosionoverhaul/PlayTrackedSoundPacket.java new file mode 100644 index 0000000..8bf8aa8 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/PlayTrackedSoundPacket.java @@ -0,0 +1,75 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.client.ClientEffects; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.phys.Vec3; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.DistExecutor; +import net.neoforged.neoforge.network.NetworkEvent; + +public class PlayTrackedSoundPacket { + private final Vec3 explosionPos; + private final ResourceLocation soundId; + private final float volume; + private final float pitch; + private final long delayTicks; + private final boolean isPlayerInHouse; + + public PlayTrackedSoundPacket(Vec3 explosionPos, ResourceLocation soundId, float volume, float pitch, long delayTicks, boolean isPlayerInHouse) { + this.explosionPos = explosionPos; + this.soundId = soundId; + this.volume = volume; + this.pitch = pitch; + this.delayTicks = delayTicks; + this.isPlayerInHouse = isPlayerInHouse; + } + + public static void encode(PlayTrackedSoundPacket msg, FriendlyByteBuf buf) { + buf.writeDouble(msg.explosionPos.f_82479_); + buf.writeDouble(msg.explosionPos.f_82480_); + buf.writeDouble(msg.explosionPos.f_82481_); + buf.m_130085_(msg.soundId); + buf.writeFloat(msg.volume); + buf.writeFloat(msg.pitch); + buf.m_130103_(msg.delayTicks); + buf.writeBoolean(msg.isPlayerInHouse); + } + + public static PlayTrackedSoundPacket decode(FriendlyByteBuf buf) { + return new PlayTrackedSoundPacket(new Vec3(buf.readDouble(), buf.readDouble(), buf.readDouble()), buf.m_130281_(), buf.readFloat(), buf.readFloat(), buf.m_130258_(), buf.readBoolean()); + } + + public static void handle(PlayTrackedSoundPacket msg, Supplier ctx) { + ctx.get().enqueueWork(() -> DistExecutor.unsafeRunWhenOn((Dist)Dist.CLIENT, () -> () -> ClientEffects.addTrackedSound(msg))); + ctx.get().setPacketHandled(true); + } + + public Vec3 getExplosionPos() { + return this.explosionPos; + } + + public ResourceLocation getSoundId() { + return this.soundId; + } + + public float getVolume() { + return this.volume; + } + + public float getPitch() { + return this.pitch; + } + + public long getDelayTicks() { + return this.delayTicks; + } + + public boolean isPlayerInHouse() { + return this.isPlayerInHouse; + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/RedstoneLampEffects.java b/src/main/java/com/vinlanx/explosionoverhaul/RedstoneLampEffects.java new file mode 100644 index 0000000..74292e8 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/RedstoneLampEffects.java @@ -0,0 +1,394 @@ +/* + * 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> perPlayerDelayedLampEffects = new ConcurrentHashMap>(); + 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 potentialLampGroupsFoundThisExplosion = new ArrayList(); + List allCandidates = BlockIndexManager.getNearby(level, playerPos, lampEffectRadius, BlockIndexManager.BlockType.LAMP); + if (allCandidates.isEmpty()) { + return; + } + ArrayList litLampCandidates = new ArrayList(); + 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 lampsAlreadyInAGroup = new HashSet(); + 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 currentLampGroupPositions = new ArrayList(); + LinkedList toProcess = new LinkedList(); + 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)); + } + } + } + + /* + * WARNING - Removed try catching itself - possible behaviour change. + */ + public static void onServerTick() { + for (Map.Entry> entry : perPlayerDelayedLampEffects.entrySet()) { + List playerEffects = entry.getValue(); + int[] playerBudget = new int[]{200}; + List list = playerEffects; + synchronized (list) { + Iterator 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 groupPositions, boolean originallyLit, long predeterminedLongOffDuration, double distanceSqToPlayer, long initialDelay) { + } + + private static class DelayedLampEffect { + public ServerLevel level; + public BlockPos representativeLampPos; + public List 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 allGroupPositions, long initialDelayTicks, boolean lit, long predeterminedLongOffDuration, RandomSource randomSource) { + this.level = level; + this.representativeLampPos = representativeLampPos; + this.groupLampPositions = new ArrayList(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; + + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ScanControlPacket.java b/src/main/java/com/vinlanx/explosionoverhaul/ScanControlPacket.java new file mode 100644 index 0000000..9bfb9e0 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ScanControlPacket.java @@ -0,0 +1,40 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.BlockIndexManager; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.neoforged.neoforge.network.NetworkEvent; + +public class ScanControlPacket { + private final boolean startScan; + + public ScanControlPacket(boolean startScan) { + this.startScan = startScan; + } + + public static void encode(ScanControlPacket msg, FriendlyByteBuf buf) { + buf.writeBoolean(msg.startScan); + } + + public static ScanControlPacket decode(FriendlyByteBuf buf) { + return new ScanControlPacket(buf.readBoolean()); + } + + public static void handle(ScanControlPacket msg, Supplier ctx) { + ctx.get().enqueueWork(() -> { + ServerPlayer player = ((NetworkEvent.Context)ctx.get()).getSender(); + if (player != null && BlockIndexManager.isPlayerAuthorized(player)) { + if (msg.startScan) { + BlockIndexManager.startManualScan(); + } else { + BlockIndexManager.cancelManualScan(); + } + } + }); + ctx.get().setPacketHandled(true); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ScanInfoHUD.java b/src/main/java/com/vinlanx/explosionoverhaul/ScanInfoHUD.java new file mode 100644 index 0000000..394e79c --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ScanInfoHUD.java @@ -0,0 +1,63 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.client.ModKeyMappings; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.neoforge.client.event.RenderGuiOverlayEvent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; + +@Mod.EventBusSubscriber(value={Dist.CLIENT}) +public class ScanInfoHUD { + private static boolean isVisible = false; + + public static boolean isVisible() { + return isVisible; + } + + public static void setVisible(boolean visible) { + isVisible = visible; + } + + @SubscribeEvent + public static void onRenderGuiOverlay(RenderGuiOverlayEvent.Post event) { + if (!isVisible) { + return; + } + Minecraft mc = Minecraft.m_91087_(); + if (mc.f_91074_ == null) { + return; + } + if (!mc.f_91074_.m_20310_(2) && !mc.m_91091_()) { + return; + } + GuiGraphics guiGraphics = event.getGuiGraphics(); + String[] infoLines = new String[]{"\u00a76\u00a7lChunk Scanning Information", "", "\u00a7eWhat is chunk scanning?", "\u00a77Chunk scanning analyzes your world to find", "\u00a77and index specific blocks for explosion effects:", "", "\u00a7a\u2022 \u00a77Redstone Lamps \u00a77- for lamp flickering effects", "\u00a7a\u2022 \u00a77Pointed Dripstone \u00a77- for dripstone collapse in caves", "\u00a7a\u2022 \u00a77Glass Blocks \u00a77- for realistic glass breaking", "", "\u00a7eWhy scan chunks?", "\u00a77This allows the mod to create more realistic", "\u00a77explosion effects by knowing where these", "\u00a77blocks are located in your world.", "", "\u00a7ePerformance:", "\u00a77Scanning happens in background and won't", "\u00a77affect your gameplay. You can adjust speed", "\u00a77in mod settings if needed.", "", "\u00a7cPress [" + ModKeyMappings.INFO_SCAN.m_90863_().getString() + "] again to close this info"}; + int maxWidth = 0; + for (String line : infoLines) { + int lineWidth = mc.f_91062_.m_92895_(line); + if (lineWidth <= maxWidth) continue; + maxWidth = lineWidth; + } + int windowWidth = maxWidth + 20; + int windowHeight = infoLines.length * 12 + 20; + int screenWidth = mc.m_91268_().m_85445_(); + int screenHeight = mc.m_91268_().m_85446_(); + int x = (screenWidth - windowWidth) / 2; + int y = (screenHeight - windowHeight) / 2; + guiGraphics.m_280509_(x - 5, y - 5, x + windowWidth, y + windowHeight, -536870912); + guiGraphics.m_280509_(x - 6, y - 6, x + windowWidth + 1, y - 5, -12303292); + guiGraphics.m_280509_(x - 6, y + windowHeight, x + windowWidth + 1, y + windowHeight + 1, -12303292); + guiGraphics.m_280509_(x - 6, y - 5, x - 5, y + windowHeight, -12303292); + guiGraphics.m_280509_(x + windowWidth, y - 5, x + windowWidth + 1, y + windowHeight, -12303292); + for (int i = 0; i < infoLines.length; ++i) { + String line = infoLines[i]; + if (line.isEmpty()) continue; + guiGraphics.m_280488_(mc.f_91062_, line, x + 10, y + 10 + i * 12, 0xFFFFFF); + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ScanInfoPacket.java b/src/main/java/com/vinlanx/explosionoverhaul/ScanInfoPacket.java new file mode 100644 index 0000000..eec5180 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ScanInfoPacket.java @@ -0,0 +1,31 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.ScanInfoHUD; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.neoforged.neoforge.network.NetworkEvent; + +public class ScanInfoPacket { + private final boolean show; + + public ScanInfoPacket(boolean show) { + this.show = show; + } + + public void encode(FriendlyByteBuf buf) { + buf.writeBoolean(this.show); + } + + public static ScanInfoPacket decode(FriendlyByteBuf buf) { + boolean show = buf.readBoolean(); + return new ScanInfoPacket(show); + } + + public void handle(Supplier ctx) { + ctx.get().enqueueWork(() -> ScanInfoHUD.setVisible(this.show)); + ctx.get().setPacketHandled(true); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ScanKeyHandler.java b/src/main/java/com/vinlanx/explosionoverhaul/ScanKeyHandler.java new file mode 100644 index 0000000..ccf8c07 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ScanKeyHandler.java @@ -0,0 +1,90 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.mojang.blaze3d.platform.InputConstants; +import com.vinlanx.explosionoverhaul.PacketHandler; +import com.vinlanx.explosionoverhaul.ScanControlPacket; +import com.vinlanx.explosionoverhaul.ScanInfoHUD; +import com.vinlanx.explosionoverhaul.ScanLoadControlPacket; +import com.vinlanx.explosionoverhaul.ScanLoadInfoHUD; +import com.vinlanx.explosionoverhaul.ScanLoadPromptHUD; +import com.vinlanx.explosionoverhaul.ScanPromptHUD; +import com.vinlanx.explosionoverhaul.client.ModKeyMappings; +import net.minecraft.client.KeyMapping; +import net.minecraft.client.Minecraft; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.neoforge.client.event.InputEvent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; + +@Mod.EventBusSubscriber(value={Dist.CLIENT}) +public class ScanKeyHandler { + @SubscribeEvent + public static void onKeyInput(InputEvent.Key event) { + Minecraft mc = Minecraft.m_91087_(); + if (mc.f_91074_ == null || mc.f_91080_ != null) { + return; + } + if (!mc.f_91074_.m_20310_(2) && !mc.m_91091_()) { + return; + } + if (event.getAction() != 1) { + return; + } + InputConstants.Key key = InputConstants.m_84827_((int)event.getKey(), (int)event.getScanCode()); + if (ScanLoadPromptHUD.isVisible()) { + if (key.equals((Object)ModKeyMappings.ACCEPT_SCAN.getKey())) { + PacketHandler.INSTANCE.sendToServer((Object)new ScanLoadControlPacket(true)); + ScanLoadPromptHUD.setVisible(false); + ScanLoadInfoHUD.setVisible(false); + if (event.getKey() != 49 && event.getKey() != 50) { + ScanKeyHandler.consumeKey(event.getKey()); + } + } else if (key.equals((Object)ModKeyMappings.DECLINE_SCAN.getKey())) { + PacketHandler.INSTANCE.sendToServer((Object)new ScanLoadControlPacket(false)); + ScanLoadPromptHUD.setVisible(false); + ScanLoadInfoHUD.setVisible(false); + if (event.getKey() != 49 && event.getKey() != 50) { + ScanKeyHandler.consumeKey(event.getKey()); + } + } else if (key.equals((Object)ModKeyMappings.INFO_SCAN.getKey())) { + boolean currentlyVisible = ScanLoadInfoHUD.isVisible(); + ScanLoadInfoHUD.setVisible(!currentlyVisible); + ScanKeyHandler.consumeKey(event.getKey()); + } + return; + } + if (ScanPromptHUD.isVisible()) { + if (key.equals((Object)ModKeyMappings.ACCEPT_SCAN.getKey())) { + PacketHandler.INSTANCE.sendToServer((Object)new ScanControlPacket(true)); + ScanPromptHUD.setVisible(false); + ScanInfoHUD.setVisible(false); + if (event.getKey() != 49 && event.getKey() != 50) { + ScanKeyHandler.consumeKey(event.getKey()); + } + } else if (key.equals((Object)ModKeyMappings.DECLINE_SCAN.getKey())) { + PacketHandler.INSTANCE.sendToServer((Object)new ScanControlPacket(false)); + ScanPromptHUD.setVisible(false); + ScanInfoHUD.setVisible(false); + if (event.getKey() != 49 && event.getKey() != 50) { + ScanKeyHandler.consumeKey(event.getKey()); + } + } else if (key.equals((Object)ModKeyMappings.INFO_SCAN.getKey())) { + boolean currentlyVisible = ScanInfoHUD.isVisible(); + ScanInfoHUD.setVisible(!currentlyVisible); + ScanKeyHandler.consumeKey(event.getKey()); + } + } + } + + private static void consumeKey(int keyCode) { + Minecraft mc = Minecraft.m_91087_(); + for (KeyMapping mapping : mc.f_91066_.f_92059_) { + if (mapping.getKey().m_84873_() != keyCode) continue; + while (mapping.m_90859_()) { + } + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ScanLoadControlPacket.java b/src/main/java/com/vinlanx/explosionoverhaul/ScanLoadControlPacket.java new file mode 100644 index 0000000..5166e34 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ScanLoadControlPacket.java @@ -0,0 +1,40 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.BlockIndexManager; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.neoforged.neoforge.network.NetworkEvent; + +public class ScanLoadControlPacket { + private final boolean loadExisting; + + public ScanLoadControlPacket(boolean loadExisting) { + this.loadExisting = loadExisting; + } + + public static void encode(ScanLoadControlPacket msg, FriendlyByteBuf buf) { + buf.writeBoolean(msg.loadExisting); + } + + public static ScanLoadControlPacket decode(FriendlyByteBuf buf) { + return new ScanLoadControlPacket(buf.readBoolean()); + } + + public static void handle(ScanLoadControlPacket msg, Supplier ctx) { + ctx.get().enqueueWork(() -> { + ServerPlayer player = ((NetworkEvent.Context)ctx.get()).getSender(); + if (player != null && BlockIndexManager.isPlayerAuthorized(player)) { + if (msg.loadExisting) { + BlockIndexManager.loadExistingData(); + } else { + BlockIndexManager.startNewScan(); + } + } + }); + ctx.get().setPacketHandled(true); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ScanLoadInfoHUD.java b/src/main/java/com/vinlanx/explosionoverhaul/ScanLoadInfoHUD.java new file mode 100644 index 0000000..e8ca797 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ScanLoadInfoHUD.java @@ -0,0 +1,63 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.client.ModKeyMappings; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.neoforge.client.event.RenderGuiOverlayEvent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; + +@Mod.EventBusSubscriber(value={Dist.CLIENT}) +public class ScanLoadInfoHUD { + private static boolean isVisible = false; + + public static boolean isVisible() { + return isVisible; + } + + public static void setVisible(boolean visible) { + isVisible = visible; + } + + @SubscribeEvent + public static void onRenderGuiOverlay(RenderGuiOverlayEvent.Post event) { + if (!isVisible) { + return; + } + Minecraft mc = Minecraft.m_91087_(); + if (mc.f_91074_ == null) { + return; + } + if (!mc.f_91074_.m_20310_(2) && !mc.m_91091_()) { + return; + } + GuiGraphics guiGraphics = event.getGuiGraphics(); + String[] infoLines = new String[]{"\u00a76\u00a7lExisting Scan Data Found", "", "\u00a7eThis world has previously scanned block data.", "\u00a7eYou have two options:", "", "\u00a7a\u00a7l[" + ModKeyMappings.ACCEPT_SCAN.m_90863_().getString() + "] Load Data \u00a7r\u00a77- Load existing scan results", "\u00a77\u2022 Instant setup - no waiting time", "\u00a77\u2022 Uses previously found block positions", "\u00a77\u2022 May miss blocks placed after last scan", "\u00a77\u2022 Recommended for established worlds", "", "\u00a7c\u00a7l[" + ModKeyMappings.DECLINE_SCAN.m_90863_().getString() + "] New Scan \u00a7r\u00a77- Perform fresh scan", "\u00a77\u2022 Scans all chunks for current blocks", "\u00a77\u2022 Takes time but finds all blocks", "\u00a77\u2022 Replaces old data with new results", "\u00a77\u2022 Recommended if world changed significantly", "", "\u00a7eNote: \u00a77Block changes are tracked automatically", "\u00a77after loading, so both options work well for", "\u00a77ongoing gameplay.", "", "\u00a7cPress [" + ModKeyMappings.INFO_SCAN.m_90863_().getString() + "] again to close this info"}; + int maxWidth = 0; + for (String line : infoLines) { + int lineWidth = mc.f_91062_.m_92895_(line); + if (lineWidth <= maxWidth) continue; + maxWidth = lineWidth; + } + int windowWidth = maxWidth + 20; + int windowHeight = infoLines.length * 12 + 20; + int screenWidth = mc.m_91268_().m_85445_(); + int screenHeight = mc.m_91268_().m_85446_(); + int x = (screenWidth - windowWidth) / 2; + int y = (screenHeight - windowHeight) / 2; + guiGraphics.m_280509_(x - 5, y - 5, x + windowWidth, y + windowHeight, -536870912); + guiGraphics.m_280509_(x - 6, y - 6, x + windowWidth + 1, y - 5, -12303292); + guiGraphics.m_280509_(x - 6, y + windowHeight, x + windowWidth + 1, y + windowHeight + 1, -12303292); + guiGraphics.m_280509_(x - 6, y - 5, x - 5, y + windowHeight, -12303292); + guiGraphics.m_280509_(x + windowWidth, y - 5, x + windowWidth + 1, y + windowHeight, -12303292); + for (int i = 0; i < infoLines.length; ++i) { + String line = infoLines[i]; + if (line.isEmpty()) continue; + guiGraphics.m_280488_(mc.f_91062_, line, x + 10, y + 10 + i * 12, 0xFFFFFF); + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ScanLoadPromptHUD.java b/src/main/java/com/vinlanx/explosionoverhaul/ScanLoadPromptHUD.java new file mode 100644 index 0000000..2766e7f --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ScanLoadPromptHUD.java @@ -0,0 +1,61 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.ScanLoadInfoHUD; +import com.vinlanx.explosionoverhaul.client.ModKeyMappings; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.neoforge.client.event.RenderGuiOverlayEvent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; + +@Mod.EventBusSubscriber(value={Dist.CLIENT}) +public class ScanLoadPromptHUD { + private static boolean isVisible = false; + + public static boolean isVisible() { + return isVisible; + } + + public static void setVisible(boolean visible) { + isVisible = visible; + if (!visible) { + ScanLoadInfoHUD.setVisible(false); + } + } + + @SubscribeEvent + public static void onRenderGuiOverlay(RenderGuiOverlayEvent.Post event) { + if (!isVisible) { + return; + } + Minecraft mc = Minecraft.m_91087_(); + if (mc.f_91074_ == null) { + return; + } + if (!mc.f_91074_.m_20310_(2) && !mc.m_91091_()) { + return; + } + GuiGraphics guiGraphics = event.getGuiGraphics(); + String promptText = "Found existing scan data for this world!"; + int x = 10; + int y = 10; + String key1Text = "[" + ModKeyMappings.ACCEPT_SCAN.m_90863_().getString() + "] = Load Data"; + String key2Text = "[" + ModKeyMappings.DECLINE_SCAN.m_90863_().getString() + "] = New Scan"; + String key3Text = "[" + ModKeyMappings.INFO_SCAN.m_90863_().getString() + "] = Info"; + int maxWidth = Math.max(mc.f_91062_.m_92895_(promptText), mc.f_91062_.m_92895_("Press " + key1Text + ", " + key2Text + ", " + key3Text)); + guiGraphics.m_280509_(x - 5, y - 5, x + maxWidth + 10, y + 35, Integer.MIN_VALUE); + guiGraphics.m_280488_(mc.f_91062_, promptText, x, y, 0xFFFFFF); + int currentX = x; + int textY = y + 12; + guiGraphics.m_280488_(mc.f_91062_, "Press ", currentX, textY, 0xFFFFFF); + guiGraphics.m_280488_(mc.f_91062_, key1Text, currentX += mc.f_91062_.m_92895_("Press "), textY, 65280); + guiGraphics.m_280488_(mc.f_91062_, ", ", currentX += mc.f_91062_.m_92895_(key1Text), textY, 0xFFFFFF); + guiGraphics.m_280488_(mc.f_91062_, key2Text, currentX += mc.f_91062_.m_92895_(", "), textY, 0xFF0000); + guiGraphics.m_280488_(mc.f_91062_, ", ", currentX += mc.f_91062_.m_92895_(key2Text), textY, 0xFFFFFF); + guiGraphics.m_280488_(mc.f_91062_, key3Text, currentX += mc.f_91062_.m_92895_(", "), textY, 0xFFFF00); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ScanLoadPromptPacket.java b/src/main/java/com/vinlanx/explosionoverhaul/ScanLoadPromptPacket.java new file mode 100644 index 0000000..4dbb5b9 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ScanLoadPromptPacket.java @@ -0,0 +1,30 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.ScanLoadPromptHUD; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.neoforged.neoforge.network.NetworkEvent; + +public class ScanLoadPromptPacket { + private final boolean showPrompt; + + public ScanLoadPromptPacket(boolean showPrompt) { + this.showPrompt = showPrompt; + } + + public static void encode(ScanLoadPromptPacket msg, FriendlyByteBuf buf) { + buf.writeBoolean(msg.showPrompt); + } + + public static ScanLoadPromptPacket decode(FriendlyByteBuf buf) { + return new ScanLoadPromptPacket(buf.readBoolean()); + } + + public static void handle(ScanLoadPromptPacket msg, Supplier ctx) { + ctx.get().enqueueWork(() -> ScanLoadPromptHUD.setVisible(msg.showPrompt)); + ctx.get().setPacketHandled(true); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ScanProgressHUD.java b/src/main/java/com/vinlanx/explosionoverhaul/ScanProgressHUD.java new file mode 100644 index 0000000..240d6a9 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ScanProgressHUD.java @@ -0,0 +1,159 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.Config; +import com.vinlanx.explosionoverhaul.ScanInfoHUD; +import com.vinlanx.explosionoverhaul.ScanLoadInfoHUD; +import com.vinlanx.explosionoverhaul.ScanLoadPromptHUD; +import com.vinlanx.explosionoverhaul.ScanPromptHUD; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.neoforge.client.event.RenderGuiOverlayEvent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; + +@Mod.EventBusSubscriber(value={Dist.CLIENT}) +public class ScanProgressHUD { + private static int totalChunks = 0; + private static int scannedChunks = 0; + private static boolean isComplete = false; + private static boolean isVisible = false; + private static long hideTime = 0L; + private static final long HIDE_DELAY = 4000L; + private static int lampsFound = 0; + private static int dripstonesFound = 0; + private static int glassBlocksFound = 0; + private static long startTime = 0L; + private static double chunksPerSecond = 0.0; + + public static void updateProgress(int total, int scanned, boolean complete) { + ScanProgressHUD.updateProgress(total, scanned, complete, 0, 0, 0); + } + + public static void updateProgress(int total, int scanned, boolean complete, int lamps, int dripstones, int glass) { + long currentTime; + long elapsedTime; + if (!((Boolean)Config.COMMON.scan.enableBlockIndexing.get()).booleanValue()) { + ScanProgressHUD.reset(); + return; + } + totalChunks = total; + scannedChunks = scanned; + boolean wasComplete = isComplete; + isComplete = complete; + lampsFound = lamps; + dripstonesFound = dripstones; + glassBlocksFound = glass; + if (scannedChunks == 0 && totalChunks > 0 && !isComplete) { + startTime = System.currentTimeMillis(); + chunksPerSecond = 0.0; + } + if (scannedChunks > 0 && !isComplete && startTime > 0L && (elapsedTime = (currentTime = System.currentTimeMillis()) - startTime) > 1000L) { + chunksPerSecond = (double)scannedChunks / ((double)elapsedTime / 1000.0); + } + if (total > 0) { + if (complete && !wasComplete) { + hideTime = System.currentTimeMillis() + 4000L; + isVisible = true; + } else if (!complete) { + isVisible = true; + hideTime = 0L; + } + } else if (total == 0) { + ScanProgressHUD.reset(); + } + } + + public static void reset() { + totalChunks = 0; + scannedChunks = 0; + isComplete = false; + isVisible = false; + hideTime = 0L; + lampsFound = 0; + dripstonesFound = 0; + glassBlocksFound = 0; + startTime = 0L; + chunksPerSecond = 0.0; + } + + private static String getEstimatedTimeRemaining() { + if (isComplete) { + return "Complete!"; + } + if (totalChunks <= 0 || scannedChunks <= 0 || chunksPerSecond <= 0.1) { + return "Calculating..."; + } + int remainingChunks = totalChunks - scannedChunks; + double secondsRemaining = (double)remainingChunks / chunksPerSecond; + if (secondsRemaining < 0.0) { + return "Calculating..."; + } + int minutes = (int)(secondsRemaining / 60.0); + int seconds = (int)(secondsRemaining % 60.0); + return String.format("ETA: %02d:%02d", minutes, seconds); + } + + @SubscribeEvent + public static void onRenderGuiOverlay(RenderGuiOverlayEvent.Post event) { + if (!((Boolean)Config.COMMON.scan.enableBlockIndexing.get()).booleanValue()) { + return; + } + if (!((Boolean)Config.COMMON.scan.showScanProgressHUD.get()).booleanValue()) { + return; + } + if (!isVisible) { + return; + } + if (totalChunks <= 0) { + return; + } + if (ScanPromptHUD.isVisible() || ScanInfoHUD.isVisible() || ScanLoadPromptHUD.isVisible() || ScanLoadInfoHUD.isVisible()) { + return; + } + Minecraft mc = Minecraft.m_91087_(); + if (mc.f_91074_ == null) { + return; + } + if (!mc.f_91074_.m_20310_(2) && !mc.m_91091_()) { + return; + } + if (isComplete && System.currentTimeMillis() > hideTime) { + isVisible = false; + return; + } + GuiGraphics guiGraphics = event.getGuiGraphics(); + Font font = mc.f_91062_; + float progress = totalChunks > 0 ? (float)scannedChunks / (float)totalChunks : 0.0f; + int percentage = isComplete ? 100 : Math.round(progress * 100.0f); + String statusText = isComplete ? "Scan Complete! (100%)" : String.format("Scanning Chunks: %d%%", percentage); + String detailText = String.format("%d / %d chunks", scannedChunks, totalChunks); + String blockCountText = String.format("Lamps: %d; Dripstones: %d; Glass: %d", lampsFound, dripstonesFound, glassBlocksFound); + String timeText = ScanProgressHUD.getEstimatedTimeRemaining(); + int x = 10; + int y = 10; + int textColor = isComplete ? 65280 : 0xFFFFFF; + boolean shadowColor = false; + int maxWidth = Math.max(Math.max(Math.max(font.m_92895_(statusText), font.m_92895_(detailText)), font.m_92895_(blockCountText)), font.m_92895_(timeText)); + int bgWidth = Math.max(maxWidth, 100) + 10; + int bgHeight = 64; + guiGraphics.m_280509_(x - 5, y - 2, x + bgWidth, y + bgHeight, Integer.MIN_VALUE); + guiGraphics.m_280488_(font, statusText, x, y, textColor); + guiGraphics.m_280488_(font, detailText, x, y + 12, 0xAAAAAA); + guiGraphics.m_280488_(font, blockCountText, x, y + 24, 0xCCCCCC); + int timeTextColor = isComplete ? 65280 : 0xFFFF00; + guiGraphics.m_280488_(font, timeText, x, y + 36, timeTextColor); + int barWidth = 100; + int barHeight = 4; + int barX = x; + int barY = y + 52; + guiGraphics.m_280509_(barX, barY, barX + barWidth, barY + barHeight, -13421773); + int progressWidth = isComplete ? barWidth : (int)((float)barWidth * progress); + int barColor = isComplete ? -16711936 : -16733696; + guiGraphics.m_280509_(barX, barY, barX + progressWidth, barY + barHeight, barColor); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ScanProgressPacket.java b/src/main/java/com/vinlanx/explosionoverhaul/ScanProgressPacket.java new file mode 100644 index 0000000..792d3a7 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ScanProgressPacket.java @@ -0,0 +1,75 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.ScanProgressHUD; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.neoforged.neoforge.network.NetworkEvent; + +public class ScanProgressPacket { + private final int totalChunks; + private final int scannedChunks; + private final boolean isComplete; + private final int lampsFound; + private final int dripstonesFound; + private final int glassBlocksFound; + + public ScanProgressPacket(int totalChunks, int scannedChunks, boolean isComplete, int lampsFound, int dripstonesFound, int glassBlocksFound) { + this.totalChunks = totalChunks; + this.scannedChunks = scannedChunks; + this.isComplete = isComplete; + this.lampsFound = lampsFound; + this.dripstonesFound = dripstonesFound; + this.glassBlocksFound = glassBlocksFound; + } + + public ScanProgressPacket(FriendlyByteBuf buffer) { + this.totalChunks = buffer.readInt(); + this.scannedChunks = buffer.readInt(); + this.isComplete = buffer.readBoolean(); + this.lampsFound = buffer.readInt(); + this.dripstonesFound = buffer.readInt(); + this.glassBlocksFound = buffer.readInt(); + } + + public void encode(FriendlyByteBuf buffer) { + buffer.writeInt(this.totalChunks); + buffer.writeInt(this.scannedChunks); + buffer.writeBoolean(this.isComplete); + buffer.writeInt(this.lampsFound); + buffer.writeInt(this.dripstonesFound); + buffer.writeInt(this.glassBlocksFound); + } + + public void handle(Supplier contextSupplier) { + NetworkEvent.Context context = contextSupplier.get(); + context.enqueueWork(() -> ScanProgressHUD.updateProgress(this.totalChunks, this.scannedChunks, this.isComplete, this.lampsFound, this.dripstonesFound, this.glassBlocksFound)); + context.setPacketHandled(true); + } + + public int getTotalChunks() { + return this.totalChunks; + } + + public int getScannedChunks() { + return this.scannedChunks; + } + + public boolean isComplete() { + return this.isComplete; + } + + public int getLampsFound() { + return this.lampsFound; + } + + public int getDripstonesFound() { + return this.dripstonesFound; + } + + public int getGlassBlocksFound() { + return this.glassBlocksFound; + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ScanPromptHUD.java b/src/main/java/com/vinlanx/explosionoverhaul/ScanPromptHUD.java new file mode 100644 index 0000000..485ecd7 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ScanPromptHUD.java @@ -0,0 +1,62 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.BlockIndexManager; +import com.vinlanx.explosionoverhaul.ScanInfoHUD; +import com.vinlanx.explosionoverhaul.client.ModKeyMappings; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.neoforge.client.event.RenderGuiOverlayEvent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; + +@Mod.EventBusSubscriber(value={Dist.CLIENT}) +public class ScanPromptHUD { + private static boolean isVisible = false; + + public static boolean isVisible() { + return isVisible; + } + + public static void setVisible(boolean visible) { + isVisible = visible; + if (!visible) { + ScanInfoHUD.setVisible(false); + } + } + + @SubscribeEvent + public static void onRenderGuiOverlay(RenderGuiOverlayEvent.Post event) { + if (!isVisible) { + return; + } + Minecraft mc = Minecraft.m_91087_(); + if (mc.f_91074_ == null) { + return; + } + if (!mc.f_91074_.m_20310_(2) && !mc.m_91091_()) { + return; + } + GuiGraphics guiGraphics = event.getGuiGraphics(); + String promptText = BlockIndexManager.isRescanMode() ? "Rescan all chunks?" : "Start chunk scanning?"; + int x = 10; + int y = 10; + String key1Text = "[" + ModKeyMappings.ACCEPT_SCAN.m_90863_().getString() + "] = Yes"; + String key2Text = "[" + ModKeyMappings.DECLINE_SCAN.m_90863_().getString() + "] = No"; + String key3Text = "[" + ModKeyMappings.INFO_SCAN.m_90863_().getString() + "] = Info"; + int maxWidth = Math.max(mc.f_91062_.m_92895_(promptText), mc.f_91062_.m_92895_("Press " + key1Text + ", " + key2Text + ", " + key3Text)); + guiGraphics.m_280509_(x - 5, y - 5, x + maxWidth + 10, y + 35, Integer.MIN_VALUE); + guiGraphics.m_280488_(mc.f_91062_, promptText, x, y, 0xFFFFFF); + int currentX = x; + int textY = y + 12; + guiGraphics.m_280488_(mc.f_91062_, "Press ", currentX, textY, 0xFFFFFF); + guiGraphics.m_280488_(mc.f_91062_, key1Text, currentX += mc.f_91062_.m_92895_("Press "), textY, 65280); + guiGraphics.m_280488_(mc.f_91062_, ", ", currentX += mc.f_91062_.m_92895_(key1Text), textY, 0xFFFFFF); + guiGraphics.m_280488_(mc.f_91062_, key2Text, currentX += mc.f_91062_.m_92895_(", "), textY, 0xFF0000); + guiGraphics.m_280488_(mc.f_91062_, ", ", currentX += mc.f_91062_.m_92895_(key2Text), textY, 0xFFFFFF); + guiGraphics.m_280488_(mc.f_91062_, key3Text, currentX += mc.f_91062_.m_92895_(", "), textY, 0xFFFF00); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ScanPromptPacket.java b/src/main/java/com/vinlanx/explosionoverhaul/ScanPromptPacket.java new file mode 100644 index 0000000..560f0d9 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ScanPromptPacket.java @@ -0,0 +1,30 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.ScanPromptHUD; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.neoforged.neoforge.network.NetworkEvent; + +public class ScanPromptPacket { + private final boolean showPrompt; + + public ScanPromptPacket(boolean showPrompt) { + this.showPrompt = showPrompt; + } + + public static void encode(ScanPromptPacket msg, FriendlyByteBuf buf) { + buf.writeBoolean(msg.showPrompt); + } + + public static ScanPromptPacket decode(FriendlyByteBuf buf) { + return new ScanPromptPacket(buf.readBoolean()); + } + + public static void handle(ScanPromptPacket msg, Supplier ctx) { + ctx.get().enqueueWork(() -> ScanPromptHUD.setVisible(msg.showPrompt)); + ctx.get().setPacketHandled(true); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/ServerExplosionHandler.java b/src/main/java/com/vinlanx/explosionoverhaul/ServerExplosionHandler.java new file mode 100644 index 0000000..5ec3870 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/ServerExplosionHandler.java @@ -0,0 +1,642 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.AsyncCraterManager; +import com.vinlanx.explosionoverhaul.CameraShakePacket; +import com.vinlanx.explosionoverhaul.Config; +import com.vinlanx.explosionoverhaul.CraterDeformer; +import com.vinlanx.explosionoverhaul.DripstoneEffects; +import com.vinlanx.explosionoverhaul.ExplosionClusterHandler; +import com.vinlanx.explosionoverhaul.ExplosionOverhaul; +import com.vinlanx.explosionoverhaul.ExplosionVisualsPacket; +import com.vinlanx.explosionoverhaul.FlashEffectPacket; +import com.vinlanx.explosionoverhaul.GlassBreakingEffects; +import com.vinlanx.explosionoverhaul.ModSounds; +import com.vinlanx.explosionoverhaul.PacketHandler; +import com.vinlanx.explosionoverhaul.PlayTrackedSoundPacket; +import com.vinlanx.explosionoverhaul.RedstoneLampEffects; +import com.vinlanx.explosionoverhaul.SpawnDustCloudPacket; +import com.vinlanx.explosionoverhaul.SpawnLineSparksPacket; +import com.vinlanx.explosionoverhaul.SpawnMistCloudPacket; +import com.vinlanx.explosionoverhaul.SpawnShockwavePacket; +import com.vinlanx.explosionoverhaul.StartConcussionPacket; +import com.vinlanx.explosionoverhaul.SuppressExplosionSoundPacket; +import com.vinlanx.explosionoverhaul.api.IExplosionPower; +import com.vinlanx.explosionoverhaul.mixinhelper.ExplosionAccessor; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Random; +import java.util.Set; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Position; +import net.minecraft.resources.ResourceLocation; +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.tags.BlockTags; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.Explosion; +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.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; +import net.neoforged.neoforge.network.PacketDistributor; +import net.neoforged.neoforge.registries.ForgeRegistries; + +public class ServerExplosionHandler { + private static final ServerExplosionHandler INSTANCE = new ServerExplosionHandler(); + private final Random random = new Random(); + + public static void handleExplosion(ServerLevel level, Explosion explosion, List affectedBlocks) { + INSTANCE.onExplosion(level, explosion, affectedBlocks); + } + + public static void register() { + } + + private void onExplosion(ServerLevel level, Explosion explosion, List affectedBlocks) { + boolean shouldBreakGlass; + boolean shouldDestroyBlocks; + float power; + Vec3 explosionPos; + ExplosionOverhaul.ExplosionSourceMode mode; + Entity exploder; + String sourceId = "generic"; + if (explosion instanceof ExplosionAccessor) { + ExplosionAccessor accessor = (ExplosionAccessor)explosion; + v0 = accessor.explosionoverhaul$getSource(); + } else { + v0 = exploder = null; + } + if (exploder != null) { + IExplosionPower pw; + ResourceLocation exploderId = ForgeRegistries.ENTITY_TYPES.getKey((Object)exploder.m_6095_()); + if (exploderId != null) { + sourceId = exploderId.toString(); + } + if (exploderId != null && "createbigcannons".equals(exploderId.m_135827_()) && explosion instanceof IExplosionPower && (pw = (IExplosionPower)explosion).getPower() <= 2.0f) { + return; + } + } + if ((mode = ExplosionOverhaul.getSourceMode(sourceId)) == ExplosionOverhaul.ExplosionSourceMode.VANILLA) { + return; + } + if (explosion instanceof ExplosionAccessor) { + ExplosionAccessor accessor = (ExplosionAccessor)explosion; + v1 = accessor.explosionoverhaul$getCenter(); + } else { + v1 = explosionPos = Vec3.f_82478_; + } + if (explosion instanceof IExplosionPower) { + IExplosionPower powerHolder = (IExplosionPower)explosion; + power = powerHolder.getPower(); + if (power >= 1.0f) { + for (ServerPlayer player : level.m_6907_()) { + if (player.f_8906_ == null) continue; + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)new SuppressExplosionSoundPacket(power)); + } + } + } else { + System.err.println("[explosionoverhaul] WARNING: Explosion is not IExplosionPower \u2014 Mixin did not work. Explosion processing canceled."); + return; + } + power = ExplosionClusterHandler.calculateClusteredPower((Level)level, explosionPos, power); + boolean bl = shouldDestroyBlocks = (Boolean)Config.COMMON.enableCraterDestruction.get() != false && mode != ExplosionOverhaul.ExplosionSourceMode.NO_DESTRUCTION && mode != ExplosionOverhaul.ExplosionSourceMode.NO_DESTRUCTION_GLASSWORKS; + if (shouldDestroyBlocks) { + boolean useAsync = (Boolean)Config.COMMON.enableAsyncCrater.get(); + if (useAsync) { + affectedBlocks.clear(); + AsyncCraterManager.submit(level, explosionPos, power); + } else { + HashSet originalAffectedBlocks = new HashSet(affectedBlocks); + affectedBlocks.clear(); + Iterator iterator = originalAffectedBlocks.iterator(); + while (iterator.hasNext()) { + BlockPos pos = (BlockPos)iterator.next(); + BlockState state = level.m_8055_(pos); + Block block = state.m_60734_(); + if (ExplosionOverhaul.isBlockBlacklisted(block)) continue; + affectedBlocks.add(pos); + } + Set craterBlocks = CraterDeformer.getCraterBlocks(level, explosionPos, power); + for (BlockPos pos : craterBlocks) { + if (affectedBlocks.contains(pos)) continue; + BlockState state = level.m_8055_(pos); + Block block = state.m_60734_(); + if (state.m_60795_() || !(state.m_60800_((BlockGetter)level, pos) >= 0.0f) || block.m_204297_().m_203656_(BlockTags.f_13070_) || block == Blocks.f_50722_ || ExplosionOverhaul.isBlockBlacklisted(block)) continue; + affectedBlocks.add(pos); + } + } + } else { + affectedBlocks.clear(); + } + boolean bl2 = shouldBreakGlass = (Boolean)Config.COMMON.enableGlassBreaking.get() != false && mode != ExplosionOverhaul.ExplosionSourceMode.NO_DESTRUCTION; + if (shouldBreakGlass) { + GlassBreakingEffects.trigger(level, explosionPos, power); + } + for (ServerPlayer player : level.m_6907_()) { + long delayTicksEffect; + double speedOfSound; + if (player.f_8906_ == null) continue; + double distance = player.m_20182_().m_82554_(explosionPos); + BlockPos playerBlockPos = player.m_20183_(); + boolean playerInCave = ServerExplosionHandler.isInNaturalCave(level, playerBlockPos); + boolean playerInHouse = ServerExplosionHandler.isInHouse(level, playerBlockPos, player.m_146892_().f_82480_); + BlockPos explosionOrigin = BlockPos.m_274446_((Position)explosionPos); + BlockPos nearestSolidAbove = ServerExplosionHandler.findNearestSolidUp(level, explosionOrigin, 50); + boolean explosionIsInCaveLocation = nearestSolidAbove != null ? ServerExplosionHandler.isInNaturalCave(level, nearestSolidAbove) : ServerExplosionHandler.isInNaturalCave(level, explosionOrigin); + boolean hasDirectLineOfSight = false; + if (distance > 0.1 && distance <= 200.0) { + Vec3 playerEyePos = player.m_146892_(); + hasDirectLineOfSight = ServerExplosionHandler.hasLineOfSight(level, playerEyePos, explosionPos, (Entity)player); + } + if (distance <= 200.0) { + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)new StartConcussionPacket(power, distance, hasDirectLineOfSight, explosionIsInCaveLocation)); + } + int dripstoneThreshold = 0; + if (distance >= 500.0 && distance < 1000.0) { + dripstoneThreshold = 10; + } else if (distance >= 1000.0 && distance < 5000.0) { + dripstoneThreshold = 25; + } else if (distance >= 5000.0) { + dripstoneThreshold = 50; + } + if (dripstoneThreshold > 0 && power >= (float)dripstoneThreshold) { + DripstoneEffects.handleDripstoneFall(level, playerBlockPos, (int)Math.ceil(power), player.m_217043_()); + } + List soundPool = null; + int closeSoundDistanceThreshold = level.m_46472_() == Level.f_46429_ ? 100 : (level.m_46472_() == Level.f_46430_ ? 150 : 50); + if (distance <= (double)closeSoundDistanceThreshold) { + soundPool = power <= 3.0f ? List.of((SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_1_3.get()) : (power <= 6.0f ? List.of((SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_2_3.get()) : (power <= 14.0f ? List.of((SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_3_3.get()) : (power <= 30.0f ? List.of((SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_4_3.get()) : (power <= 60.0f ? List.of((SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_5_3.get()) : (power <= 99.0f ? List.of((SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_6_3.get()) : List.of((SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_7_3.get())))))); + } else { + if (hasDirectLineOfSight) { + if (playerInHouse) { + if (distance <= 500.0) { + soundPool = ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_7_3.get()); + } else if (distance <= 1000.0) { + soundPool = ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_7_3.get()); + } else if (distance <= 5000.0) { + soundPool = ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_7_3.get()); + } + } else if (distance <= 500.0) { + soundPool = ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_7_3.get()); + } else if (distance <= 1000.0) { + soundPool = ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_FAR_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_7_3.get()); + } else if (distance <= 5000.0) { + soundPool = ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_7_3.get()); + } + } else if (distance <= 500.0) { + soundPool = playerInHouse && explosionIsInCaveLocation ? ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_7_3.get()) : (playerInHouse ? ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_7_3.get()) : (explosionIsInCaveLocation && !playerInCave ? ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_UNDERGROUND_POWER_7_3.get()) : (playerInCave ? ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_7_3.get()) : ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_7_3.get())))); + } else if (distance <= 1000.0) { + soundPool = playerInHouse && explosionIsInCaveLocation ? ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_7_3.get()) : (playerInHouse ? ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_7_3.get()) : (explosionIsInCaveLocation && !playerInCave ? ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_UNDERGROUND_POWER_7_3.get()) : (playerInCave ? ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_7_3.get()) : ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_FAR_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_7_3.get())))); + } else if (distance <= 5000.0) { + soundPool = playerInHouse && explosionIsInCaveLocation ? ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_7_3.get()) : (playerInHouse ? ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_7_3.get()) : (explosionIsInCaveLocation && !playerInCave ? ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_UNDERGROUND_POWER_7_3.get()) : (playerInCave ? ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_7_3.get()) : ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_7_3.get())))); + } + if (!(soundPool != null || distance > 5000.0 && distance <= 6000.0 && power > 60.0f) && distance > 5000.0) continue; + } + if (!((Boolean)Config.COMMON.enableAdvancedSoundSpeed.get()).booleanValue()) { + speedOfSound = 343.0; + delayTicksEffect = (long)(distance / (speedOfSound / 20.0)); + } else { + speedOfSound = distance <= 20.0 ? 40.0 : (distance <= 40.0 ? 40.0 : (distance <= 80.0 ? 80.0 : (distance <= 160.0 ? 66.7 : (distance <= 240.0 ? 266.7 : 343.0)))); + double speedPerTick = speedOfSound / 20.0; + delayTicksEffect = distance <= 240.0 ? (long)(distance / speedPerTick) : (long)(distance / 17.15); + } + if (soundPool != null && !soundPool.isEmpty()) { + boolean useAmbientSound; + SoundEvent sound = soundPool.get(this.random.nextInt(soundPool.size())); + float pitch = 0.95f + this.random.nextFloat() * 0.1f; + float volume = Math.min(power * 10.0f, 90.0f); + boolean bl3 = useAmbientSound = !hasDirectLineOfSight && (playerInCave || explosionIsInCaveLocation); + if (distance <= (double)closeSoundDistanceThreshold) { + ExplosionOverhaul.addDelayedSound(player, sound, SoundSource.BLOCKS, (float)explosionPos.f_82479_, (float)explosionPos.f_82480_, (float)explosionPos.f_82481_, volume, pitch, player.m_217043_().m_188505_(), delayTicksEffect); + } else 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 { + ResourceLocation soundId = ForgeRegistries.SOUND_EVENTS.getKey((Object)sound); + if (soundId != null) { + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)new PlayTrackedSoundPacket(explosionPos, soundId, volume, pitch, delayTicksEffect, playerInHouse)); + } + } + } + float fireballPowerFraction = Mth.m_14036_((float)power, (float)1.0f, (float)100.0f) / 100.0f; + float fireballRadius = Mth.m_14179_((float)fireballPowerFraction, (float)3.0f, (float)40.0f); + float normalizedPowerSqrt = Mth.m_184655_((float)((float)Math.sqrt(power)), (float)((float)Math.sqrt(5.0)), (float)((float)Math.sqrt(100.0))); + float shockwaveMultiplier = Mth.m_14179_((float)normalizedPowerSqrt, (float)2.0f, (float)8.0f); + float maxShockwaveRadius = fireballRadius * shockwaveMultiplier * 3.0f; + if (distance <= (double)(maxShockwaveRadius *= 4.0f)) { + float sendIntensity; + CameraShakeProfile closeProfile = this.determineCameraShakeProfile(power, 0.0, playerInCave, closeSoundDistanceThreshold, level); + float baseIntensity = closeProfile.intensity; + int durationTicks = closeProfile.durationTicks; + float basePush = closeProfile.pushIntensity; + if (distance <= 10.0) { + sendIntensity = baseIntensity; + } else { + float t = 1.0f - Mth.m_14036_((float)((float)(distance / (double)maxShockwaveRadius)), (float)0.0f, (float)1.0f); + float atten = t * t; + sendIntensity = baseIntensity * atten; + } + if (sendIntensity > 0.01f && durationTicks > 0) { + int delayTicks = (int)Math.max(0L, Math.round(distance / speedOfSound)); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)new CameraShakePacket(sendIntensity, durationTicks, basePush, delayTicks)); + } + } + float lampFlickerPowerThreshold = distance > 1000.0 && distance <= 5000.0 ? 31.0f : (distance > 500.0 && distance <= 1000.0 ? 20.0f : (distance > (double)closeSoundDistanceThreshold && distance <= 500.0 ? 10.0f : (distance <= (double)closeSoundDistanceThreshold ? 4.0f : Float.MAX_VALUE))); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)new ExplosionVisualsPacket(explosionPos, power)); + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)new FlashEffectPacket(explosionPos, power)); + if (power >= lampFlickerPowerThreshold) { + RedstoneLampEffects.triggerLampFlicker(level, player, power, delayTicksEffect, distance); + if (((Boolean)Config.COMMON.enableDripstoneFalling.get()).booleanValue()) { + DripstoneEffects.handleDripstoneFall(level, player.m_20183_(), (int)power, level.f_46441_); + } + } + if (power >= 5.0f) { + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)new SpawnShockwavePacket(explosionPos, power)); + } + if (power >= 5.0f) { + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)new SpawnDustCloudPacket(explosionPos, power)); + } + if (power >= 5.0f) { + PacketHandler.INSTANCE.send(PacketDistributor.PLAYER.with(() -> player), (Object)new SpawnMistCloudPacket(explosionPos, power)); + } + if (!playerInCave) continue; + ExplosionOverhaul.CaveEffects.spawnFallingBlocksAndDust(level, explosionPos, player, power, delayTicksEffect); + } + if (power >= 2.0f) { + SpawnLineSparksPacket packet = new SpawnLineSparksPacket(explosionPos, power); + PacketDistributor.TargetPoint targetPoint = new PacketDistributor.TargetPoint(explosionPos.m_7096_(), explosionPos.m_7098_(), explosionPos.m_7094_(), 700.0, level.m_46472_()); + PacketHandler.INSTANCE.send(PacketDistributor.NEAR.with(() -> targetPoint), (Object)packet); + } + } + + private CameraShakeProfile determineCameraShakeProfile(float power, double distance, boolean playerInCave, int actualCloseDistance, ServerLevel level) { + float intensity = 0.0f; + int baseDuration = 20; + float pushIntensity = 0.0f; + int baseMediumDistance = 500; + int baseFarDistance = 1000; + int baseSuperFarDistance = 5000; + int mediumDistance = Math.round(2000.0f); + int farDistance = Math.round(4000.0f); + int superFarDistance = Math.round(20000.0f); + int scaledCloseDistance = Math.round((float)actualCloseDistance * 4.0f); + 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 <= (double)scaledCloseDistance) { + if (powerCategory == 1) { + shakeLevel = 2; + baseDuration = 15; + } else if (powerCategory == 2) { + shakeLevel = 3; + baseDuration = 20; + } else if (powerCategory == 3) { + shakeLevel = 3; + baseDuration = 25; + } else if (powerCategory == 4) { + shakeLevel = 4; + baseDuration = 30; + } else if (powerCategory == 5) { + shakeLevel = 4; + baseDuration = 35; + } else if (powerCategory == 6) { + shakeLevel = 5; + baseDuration = 40; + } else if (powerCategory >= 7) { + shakeLevel = 5; + baseDuration = 50; + } + } else if (distance <= (double)mediumDistance) { + if (powerCategory == 1) { + shakeLevel = 2; + baseDuration = 10; + } else if (powerCategory == 2) { + shakeLevel = 2; + baseDuration = 15; + } else if (powerCategory == 3) { + shakeLevel = 2; + baseDuration = 20; + } else if (powerCategory == 4) { + shakeLevel = 3; + baseDuration = 20; + } else if (powerCategory == 5) { + shakeLevel = 3; + baseDuration = 25; + } else if (powerCategory == 6) { + shakeLevel = 4; + baseDuration = 30; + } else if (powerCategory >= 7) { + shakeLevel = 4; + baseDuration = 35; + } + } else if (distance <= (double)farDistance) { + if (powerCategory == 4) { + shakeLevel = 2; + baseDuration = 10; + } else if (powerCategory == 5) { + shakeLevel = 2; + baseDuration = 15; + } else if (powerCategory == 6) { + shakeLevel = 3; + baseDuration = 20; + } else if (powerCategory >= 7) { + shakeLevel = 3; + baseDuration = 25; + } + } else if (distance <= (double)superFarDistance) { + if (powerCategory == 5) { + shakeLevel = 1; + baseDuration = 10; + } else if (powerCategory == 6) { + shakeLevel = 2; + baseDuration = 15; + } else if (powerCategory >= 7) { + shakeLevel = 3; + baseDuration = 20; + } + } + switch (shakeLevel) { + case 1: { + intensity = 0.3f; + break; + } + case 2: { + intensity = 0.9f; + break; + } + case 3: { + intensity = 2.0f; + break; + } + case 4: { + intensity = 3.25f; + break; + } + case 5: { + intensity = 4.5f; + break; + } + default: { + intensity = 0.0f; + baseDuration = 0; + } + } + if (playerInCave && intensity > 0.0f) { + if (shakeLevel >= 2) { + float basePush = 0.06f + (float)shakeLevel * 0.03f; + pushIntensity = Math.min(basePush * (power / 6.0f), 0.45f); + pushIntensity = Math.max(0.06f, pushIntensity); + } + if (distance > 10.0) { + float attenMax = superFarDistance; + if (attenMax <= 0.0f) { + attenMax = 1.0f; + } + float atten = 1.0f - Mth.m_14036_((float)((float)distance / attenMax), (float)0.0f, (float)1.0f); + intensity *= atten; + pushIntensity *= atten; + } + } + if (intensity > 0.01f && baseDuration < 5) { + baseDuration = 5; + } + if (intensity < 0.01f) { + intensity = 0.0f; + baseDuration = 0; + pushIntensity = 0.0f; + } + return new CameraShakeProfile(intensity, baseDuration, pushIntensity); + } + + public static List getSoundPoolForPower(float power, SoundEvent ... sounds) { + if (sounds.length != 21) { + ExplosionOverhaul.LOGGER.error("Expected 21 sounds for power-based selection, but got " + sounds.length + ". Returning fallback."); + return sounds.length >= 3 ? List.of(sounds[0], sounds[1], sounds[2]) : List.of(); + } + if (power <= 3.0f) { + return List.of(sounds[0], sounds[1], sounds[2]); + } + if (power <= 6.0f) { + return List.of(sounds[3], sounds[4], sounds[5]); + } + if (power <= 14.0f) { + return List.of(sounds[6], sounds[7], sounds[8]); + } + if (power <= 30.0f) { + return List.of(sounds[9], sounds[10], sounds[11]); + } + if (power <= 60.0f) { + return List.of(sounds[12], sounds[13], sounds[14]); + } + if (power <= 99.0f) { + return List.of(sounds[15], sounds[16], sounds[17]); + } + return List.of(sounds[18], sounds[19], sounds[20]); + } + + public static boolean isInNaturalCave(ServerLevel level, BlockPos origin) { + BlockPos[] corners; + boolean isBelowY60; + boolean isBedrockLevel; + if (level.m_46472_() == Level.f_46430_) { + return false; + } + boolean bl = isBedrockLevel = origin.m_123342_() < level.m_141937_() + 5; + if (isBedrockLevel && !level.m_45527_(origin)) { + return true; + } + boolean bl2 = isBelowY60 = origin.m_123342_() < 60; + if (isBelowY60 && !level.m_45527_(origin)) { + return true; + } + int radius = 4; + for (int dy = 0; dy <= 55; ++dy) { + BlockPos[] upPos = origin.m_6630_(dy); + if (!level.m_46749_((BlockPos)upPos) || !level.m_45527_((BlockPos)upPos)) continue; + return false; + } + for (BlockPos corner : corners = new BlockPos[]{origin.m_7918_(radius, 0, radius), origin.m_7918_(radius, 0, -radius), origin.m_7918_(-radius, 0, radius), origin.m_7918_(-radius, 0, -radius)}) { + for (int dy = 0; dy <= 55; ++dy) { + BlockPos p = corner.m_6630_(dy); + if (!level.m_46749_(p) || !level.m_45527_(p)) continue; + return false; + } + } + int stoneCount = 0; + int solidCount = 0; + boolean skySeenInVicinity = false; + int checkedBlocks = 0; + List caveStoneBlocks = List.of(Blocks.f_50069_, Blocks.f_50652_, Blocks.f_50079_, Blocks.f_152550_, Blocks.f_152551_, Blocks.f_50334_, Blocks.f_50228_, Blocks.f_50122_, Blocks.f_152496_, Blocks.f_50134_, Blocks.f_50730_, Blocks.f_50137_, Blocks.f_50135_, Blocks.f_50136_); + for (int dx = -radius; dx <= radius; ++dx) { + for (int dy = -radius; dy <= radius; ++dy) { + for (int dz = -radius; dz <= radius; ++dz) { + BlockPos checkPos = origin.m_7918_(dx, dy, dz); + if (!level.m_46749_(checkPos)) continue; + ++checkedBlocks; + BlockState state = level.m_8055_(checkPos); + if (state.m_280296_()) { + ++solidCount; + if (!caveStoneBlocks.contains(state.m_60734_())) continue; + ++stoneCount; + continue; + } + if (!level.m_45527_(checkPos)) continue; + return false; + } + } + } + if (checkedBlocks == 0) { + return false; + } + return false; + } + + public static boolean isInHouse(ServerLevel level, BlockPos origin, double playerEyeY) { + if (level.m_46472_() == Level.f_46430_) { + return false; + } + if (level.m_45527_(origin)) { + return false; + } + if (origin.m_123342_() < level.m_5736_() - 10 && level.m_46472_() == Level.f_46428_) { + return false; + } + int artificialBlockCount = 0; + int functionalBlockCount = 0; + boolean hasSolidRoofDirectlyAbove = false; + int radius = 2; + int checkedBlocks = 0; + List artificialKeywords = Arrays.asList("planks", "log", "wood", "brick", "stone_brick", "glass", "wool", "terracotta", "concrete", "door", "fence", "stairs", "slab", "wall", "iron_block", "gold_block", "diamond_block", "emerald_block", "quartz_block", "purpur_block"); + List specificArtificialBlocks = Arrays.asList(Blocks.f_50652_, Blocks.f_50079_); + List functionalBlocks = Arrays.asList(Blocks.f_50091_, Blocks.f_50094_, Blocks.f_50620_, Blocks.f_50619_, Blocks.f_50087_, Blocks.f_50325_, Blocks.f_50265_, Blocks.f_50618_, Blocks.f_50322_, Blocks.f_50323_, Blocks.f_50324_, Blocks.f_50624_, Blocks.f_50621_, Blocks.f_50617_, Blocks.f_50625_, Blocks.f_50623_, Blocks.f_50679_, Blocks.f_50680_, Blocks.f_50131_, Blocks.f_50255_); + BlockPos headPos = BlockPos.m_274561_((double)origin.m_123341_(), (double)playerEyeY, (double)origin.m_123343_()); + if (level.m_8055_(headPos.m_6630_(1)).m_280296_() && level.m_8055_(headPos.m_6630_(2)).m_280296_()) { + hasSolidRoofDirectlyAbove = true; + } + for (int dx = -radius; dx <= radius; ++dx) { + for (int dy = -radius; dy <= radius; ++dy) { + for (int dz = -radius; dz <= radius; ++dz) { + BlockPos checkPos = origin.m_7918_(dx, dy, dz); + if (!level.m_46749_(checkPos)) continue; + ++checkedBlocks; + BlockState state = level.m_8055_(checkPos); + Block block = state.m_60734_(); + ResourceLocation registryName = ForgeRegistries.BLOCKS.getKey((Object)block); + String name = registryName != null ? registryName.m_135815_() : ""; + boolean isKeywordArtificial = artificialKeywords.stream().anyMatch(name::contains); + if (state.m_280296_() && (isKeywordArtificial || specificArtificialBlocks.contains(block))) { + ++artificialBlockCount; + } + if (!state.m_204336_(BlockTags.f_13038_) && !functionalBlocks.contains(block)) continue; + ++functionalBlockCount; + } + } + } + if (checkedBlocks == 0) { + return false; + } + double artificialRatio = (double)artificialBlockCount / (double)checkedBlocks; + if (hasSolidRoofDirectlyAbove && (artificialBlockCount > 3 || functionalBlockCount > 0)) { + return true; + } + if (artificialBlockCount > 7 && (functionalBlockCount > 0 || artificialRatio > 0.35)) { + return true; + } + return artificialRatio > 0.2 && artificialBlockCount > 5; + } + + public static boolean hasLineOfSight(ServerLevel level, Vec3 startPos, Vec3 endPos, Entity entityContext) { + if (startPos.equals((Object)endPos)) { + return true; + } + ClipContext clipContext = new ClipContext(startPos, endPos, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, entityContext); + BlockHitResult hitResult = level.m_45547_(clipContext); + return hitResult.m_6662_() == HitResult.Type.MISS; + } + + public static BlockPos findNearestSolidUp(ServerLevel level, BlockPos origin, int maxUp) { + for (int dy = 0; dy <= maxUp; ++dy) { + BlockState s; + BlockPos p = origin.m_6630_(dy); + if (!level.m_46749_(p) || !(s = level.m_8055_(p)).m_280296_()) continue; + return p; + } + return null; + } + + public static List getSoundPool(Level level, float power, double distance, boolean playerInHouse, boolean explosionIsInCaveLocation) { + int closeSoundDistanceThreshold = level.m_46472_() == Level.f_46429_ ? 100 : (level.m_46472_() == Level.f_46430_ ? 150 : 50); + if (distance <= (double)closeSoundDistanceThreshold) { + if (power <= 3.0f) { + return List.of((SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_1_3.get()); + } + if (power <= 6.0f) { + return List.of((SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_2_3.get()); + } + if (power <= 14.0f) { + return List.of((SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_3_3.get()); + } + if (power <= 30.0f) { + return List.of((SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_4_3.get()); + } + if (power <= 60.0f) { + return List.of((SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_5_3.get()); + } + if (power <= 99.0f) { + return List.of((SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_6_3.get()); + } + return List.of((SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_CLOSE_POWER_7_3.get()); + } + if (distance <= 500.0) { + if (playerInHouse && explosionIsInCaveLocation) { + return ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_TO_HOUSE_POWER_7_3.get()); + } + if (playerInHouse) { + return ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_TO_HOUSE_POWER_7_3.get()); + } + if (explosionIsInCaveLocation) { + return ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_CAVE_POWER_7_3.get()); + } + return ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_MEDIUM_POWER_7_3.get()); + } + if (distance <= 1000.0) { + if (playerInHouse && explosionIsInCaveLocation) { + return ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_TO_HOUSE_POWER_7_3.get()); + } + if (playerInHouse) { + return ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_TO_HOUSE_POWER_7_3.get()); + } + if (explosionIsInCaveLocation) { + return ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_CAVE_POWER_7_3.get()); + } + return ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_FAR_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_FAR_POWER_7_3.get()); + } + if (distance <= 5001.0) { + if (playerInHouse && explosionIsInCaveLocation) { + return ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_TO_HOUSE_POWER_7_3.get()); + } + if (playerInHouse) { + return ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_TO_HOUSE_POWER_7_3.get()); + } + if (explosionIsInCaveLocation) { + return ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_CAVE_POWER_7_3.get()); + } + return ServerExplosionHandler.getSoundPoolForPower(power, (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_1_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_1_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_1_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_2_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_2_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_2_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_3_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_3_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_3_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_4_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_4_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_4_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_5_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_5_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_5_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_6_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_6_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_6_3.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_7_1.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_7_2.get(), (SoundEvent)ModSounds.EXPLODE_SUPERFAR_POWER_7_3.get()); + } + return null; + } + + public record CameraShakeProfile(float intensity, int durationTicks, float pushIntensity) { + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/SmokeParticleOptions.java b/src/main/java/com/vinlanx/explosionoverhaul/SmokeParticleOptions.java new file mode 100644 index 0000000..09cbe6c --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/SmokeParticleOptions.java @@ -0,0 +1,137 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.datafixers.kinds.App; +import com.mojang.datafixers.kinds.Applicative; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import com.vinlanx.explosionoverhaul.ModParticles; +import java.util.Locale; +import net.minecraft.client.particle.SpriteSet; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.ParticleType; +import net.minecraft.network.FriendlyByteBuf; + +public class SmokeParticleOptions +implements ParticleOptions { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group((App)Codec.FLOAT.fieldOf("scale").forGetter(SmokeParticleOptions::getScale), (App)Codec.INT.fieldOf("lifetime").forGetter(SmokeParticleOptions::getLifetime), (App)Codec.FLOAT.fieldOf("r").forGetter(SmokeParticleOptions::getRed), (App)Codec.FLOAT.fieldOf("g").forGetter(SmokeParticleOptions::getGreen), (App)Codec.FLOAT.fieldOf("b").forGetter(SmokeParticleOptions::getBlue), (App)Codec.FLOAT.fieldOf("a").forGetter(SmokeParticleOptions::getAlpha), (App)Codec.BOOL.fieldOf("isHeavy").forGetter(SmokeParticleOptions::isHeavy), (App)Codec.FLOAT.fieldOf("windSpeed").forGetter(SmokeParticleOptions::getWindSpeed), (App)Codec.FLOAT.fieldOf("heightPercent").forGetter(SmokeParticleOptions::getHeightPercent)).apply((Applicative)instance, (scale, lifetime, r, g, b, a, isHeavy, windSpeed, heightPercent) -> new SmokeParticleOptions(scale.floatValue(), (int)lifetime, r.floatValue(), g.floatValue(), b.floatValue(), a.floatValue(), (boolean)isHeavy, windSpeed.floatValue(), heightPercent.floatValue(), null))); + public static final ParticleOptions.Deserializer DESERIALIZER = new ParticleOptions.Deserializer(){ + + public SmokeParticleOptions fromCommand(ParticleType particleType, StringReader reader) throws CommandSyntaxException { + reader.expect(' '); + float scale = reader.readFloat(); + reader.expect(' '); + int lifetime = reader.readInt(); + reader.expect(' '); + float r = reader.readFloat(); + reader.expect(' '); + float g = reader.readFloat(); + reader.expect(' '); + float b = reader.readFloat(); + reader.expect(' '); + float a = reader.readFloat(); + reader.expect(' '); + boolean isHeavy = reader.readBoolean(); + reader.expect(' '); + float windSpeed = reader.readFloat(); + reader.expect(' '); + float heightPercent = reader.readFloat(); + return new SmokeParticleOptions(scale, lifetime, r, g, b, a, isHeavy, windSpeed, heightPercent, null); + } + + public SmokeParticleOptions fromNetwork(ParticleType particleType, FriendlyByteBuf buffer) { + return new SmokeParticleOptions(buffer.readFloat(), buffer.readInt(), buffer.readFloat(), buffer.readFloat(), buffer.readFloat(), buffer.readFloat(), buffer.readBoolean(), buffer.readFloat(), buffer.readFloat(), null); + } + }; + private final float scale; + private final int lifetime; + private final float r; + private final float g; + private final float b; + private final float a; + private final boolean isHeavy; + private final float windSpeed; + private final float heightPercent; + private final SpriteSet sprites; + + public SmokeParticleOptions(float scale, int lifetime, float r, float g, float b, float a, boolean isHeavy, float windSpeed, float heightPercent, SpriteSet sprites) { + this.scale = scale; + this.lifetime = lifetime; + this.r = r; + this.g = g; + this.b = b; + this.a = a; + this.isHeavy = isHeavy; + this.windSpeed = windSpeed; + this.heightPercent = heightPercent; + this.sprites = sprites; + } + + public SmokeParticleOptions(float scale, int lifetime, float r, float g, float b, float a, SpriteSet sprites) { + this(scale, lifetime, r, g, b, a, false, 0.0f, 0.0f, sprites); + } + + public ParticleType m_6012_() { + return (ParticleType)ModParticles.CUSTOM_SMOKE.get(); + } + + public void m_7711_(FriendlyByteBuf buffer) { + buffer.writeFloat(this.scale); + buffer.writeInt(this.lifetime); + buffer.writeFloat(this.r); + buffer.writeFloat(this.g); + buffer.writeFloat(this.b); + buffer.writeFloat(this.a); + buffer.writeBoolean(this.isHeavy); + buffer.writeFloat(this.windSpeed); + buffer.writeFloat(this.heightPercent); + } + + public String m_5942_() { + return String.format(Locale.ROOT, "%s %.2f %d %.2f %.2f %.2f %.2f %b", ModParticles.CUSTOM_SMOKE.getId(), Float.valueOf(this.scale), this.lifetime, Float.valueOf(this.r), Float.valueOf(this.g), Float.valueOf(this.b), Float.valueOf(this.a), this.isHeavy); + } + + public float getScale() { + return this.scale; + } + + public int getLifetime() { + return this.lifetime; + } + + public float getRed() { + return this.r; + } + + public float getGreen() { + return this.g; + } + + public float getBlue() { + return this.b; + } + + public float getAlpha() { + return this.a; + } + + public boolean isHeavy() { + return this.isHeavy; + } + + public float getWindSpeed() { + return this.windSpeed; + } + + public float getHeightPercent() { + return this.heightPercent; + } + + public SpriteSet getSprites() { + return this.sprites; + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/SpawnAmbientCaveDustPacket.java b/src/main/java/com/vinlanx/explosionoverhaul/SpawnAmbientCaveDustPacket.java new file mode 100644 index 0000000..95fc3b5 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/SpawnAmbientCaveDustPacket.java @@ -0,0 +1,32 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.client.ClientEffects; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.DistExecutor; +import net.neoforged.neoforge.network.NetworkEvent; + +public class SpawnAmbientCaveDustPacket { + private final float power; + + public SpawnAmbientCaveDustPacket(float power) { + this.power = power; + } + + public static void encode(SpawnAmbientCaveDustPacket msg, FriendlyByteBuf buf) { + buf.writeFloat(msg.power); + } + + public static SpawnAmbientCaveDustPacket decode(FriendlyByteBuf buf) { + return new SpawnAmbientCaveDustPacket(buf.readFloat()); + } + + public static void handle(SpawnAmbientCaveDustPacket msg, Supplier ctx) { + ctx.get().enqueueWork(() -> DistExecutor.unsafeRunWhenOn((Dist)Dist.CLIENT, () -> () -> ClientEffects.triggerAmbientCaveDust(msg.power))); + ctx.get().setPacketHandled(true); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/SpawnCustomGlowPacket.java b/src/main/java/com/vinlanx/explosionoverhaul/SpawnCustomGlowPacket.java new file mode 100644 index 0000000..c308cc0 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/SpawnCustomGlowPacket.java @@ -0,0 +1,71 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.CustomGlowParticleOptions; +import java.util.function.Supplier; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.phys.Vec3; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.DistExecutor; +import net.neoforged.neoforge.network.NetworkEvent; + +public class SpawnCustomGlowPacket { + private final Vec3 pos; + private final Vec3 motion; + private final int zone; + private final float power; + private final float scale; + private final float centerY; + private final float maxRadius; + private final float heightPercent; + + public SpawnCustomGlowPacket(Vec3 pos, Vec3 motion, int zone, float power, float scale, float centerY, float maxRadius, float heightPercent) { + this.pos = pos; + this.motion = motion; + this.zone = zone; + this.power = power; + this.scale = scale; + this.centerY = centerY; + this.maxRadius = maxRadius; + this.heightPercent = heightPercent; + } + + public static void encode(SpawnCustomGlowPacket msg, FriendlyByteBuf buf) { + buf.writeDouble(msg.pos.f_82479_); + buf.writeDouble(msg.pos.f_82480_); + buf.writeDouble(msg.pos.f_82481_); + buf.writeDouble(msg.motion.f_82479_); + buf.writeDouble(msg.motion.f_82480_); + buf.writeDouble(msg.motion.f_82481_); + buf.writeInt(msg.zone); + buf.writeFloat(msg.power); + buf.writeFloat(msg.scale); + buf.writeFloat(msg.centerY); + buf.writeFloat(msg.maxRadius); + buf.writeFloat(msg.heightPercent); + } + + public static SpawnCustomGlowPacket decode(FriendlyByteBuf buf) { + return new SpawnCustomGlowPacket(new Vec3(buf.readDouble(), buf.readDouble(), buf.readDouble()), new Vec3(buf.readDouble(), buf.readDouble(), buf.readDouble()), buf.readInt(), buf.readFloat(), buf.readFloat(), buf.readFloat(), buf.readFloat(), buf.readFloat()); + } + + public static void handle(SpawnCustomGlowPacket msg, Supplier ctx) { + ctx.get().enqueueWork(() -> DistExecutor.unsafeRunWhenOn((Dist)Dist.CLIENT, () -> () -> ClientPacketHandler.handlePacket(msg))); + ctx.get().setPacketHandled(true); + } + + public static class ClientPacketHandler { + public static void handlePacket(SpawnCustomGlowPacket msg) { + ClientLevel level = Minecraft.m_91087_().f_91073_; + if (level != null) { + CustomGlowParticleOptions options = new CustomGlowParticleOptions(msg.zone, msg.power, msg.scale, 0, msg.centerY, msg.maxRadius, msg.heightPercent); + level.m_7106_((ParticleOptions)options, msg.pos.f_82479_, msg.pos.f_82480_, msg.pos.f_82481_, msg.motion.f_82479_, msg.motion.f_82480_, msg.motion.f_82481_); + } + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/SpawnDustCloudPacket.java b/src/main/java/com/vinlanx/explosionoverhaul/SpawnDustCloudPacket.java new file mode 100644 index 0000000..c315bce --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/SpawnDustCloudPacket.java @@ -0,0 +1,38 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.client.ClientEffects; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.phys.Vec3; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.DistExecutor; +import net.neoforged.neoforge.network.NetworkEvent; + +public class SpawnDustCloudPacket { + private final Vec3 position; + private final float power; + + public SpawnDustCloudPacket(Vec3 position, float power) { + this.position = position; + this.power = power; + } + + public static void encode(SpawnDustCloudPacket msg, FriendlyByteBuf buf) { + buf.writeDouble(msg.position.f_82479_); + buf.writeDouble(msg.position.f_82480_); + buf.writeDouble(msg.position.f_82481_); + buf.writeFloat(msg.power); + } + + public static SpawnDustCloudPacket decode(FriendlyByteBuf buf) { + return new SpawnDustCloudPacket(new Vec3(buf.readDouble(), buf.readDouble(), buf.readDouble()), buf.readFloat()); + } + + public static void handle(SpawnDustCloudPacket msg, Supplier ctx) { + ctx.get().enqueueWork(() -> DistExecutor.unsafeRunWhenOn((Dist)Dist.CLIENT, () -> () -> ClientEffects.triggerDustCloud(msg.position, msg.power))); + ctx.get().setPacketHandled(true); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/SpawnLineSparksPacket.java b/src/main/java/com/vinlanx/explosionoverhaul/SpawnLineSparksPacket.java new file mode 100644 index 0000000..f597040 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/SpawnLineSparksPacket.java @@ -0,0 +1,38 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.client.ClientEffects; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.phys.Vec3; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.DistExecutor; +import net.neoforged.neoforge.network.NetworkEvent; + +public class SpawnLineSparksPacket { + private final Vec3 position; + private final float power; + + public SpawnLineSparksPacket(Vec3 position, float power) { + this.position = position; + this.power = power; + } + + public static void encode(SpawnLineSparksPacket msg, FriendlyByteBuf buf) { + buf.writeDouble(msg.position.f_82479_); + buf.writeDouble(msg.position.f_82480_); + buf.writeDouble(msg.position.f_82481_); + buf.writeFloat(msg.power); + } + + public static SpawnLineSparksPacket decode(FriendlyByteBuf buf) { + return new SpawnLineSparksPacket(new Vec3(buf.readDouble(), buf.readDouble(), buf.readDouble()), buf.readFloat()); + } + + public static void handle(SpawnLineSparksPacket msg, Supplier ctx) { + ctx.get().enqueueWork(() -> DistExecutor.unsafeRunWhenOn((Dist)Dist.CLIENT, () -> () -> ClientEffects.triggerLineSparks(msg.position, msg.power))); + ctx.get().setPacketHandled(true); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/SpawnMistCloudPacket.java b/src/main/java/com/vinlanx/explosionoverhaul/SpawnMistCloudPacket.java new file mode 100644 index 0000000..15ec784 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/SpawnMistCloudPacket.java @@ -0,0 +1,38 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.client.ClientEffects; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.phys.Vec3; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.DistExecutor; +import net.neoforged.neoforge.network.NetworkEvent; + +public class SpawnMistCloudPacket { + private final Vec3 position; + private final float power; + + public SpawnMistCloudPacket(Vec3 position, float power) { + this.position = position; + this.power = power; + } + + public static void encode(SpawnMistCloudPacket msg, FriendlyByteBuf buf) { + buf.writeDouble(msg.position.f_82479_); + buf.writeDouble(msg.position.f_82480_); + buf.writeDouble(msg.position.f_82481_); + buf.writeFloat(msg.power); + } + + public static SpawnMistCloudPacket decode(FriendlyByteBuf buf) { + return new SpawnMistCloudPacket(new Vec3(buf.readDouble(), buf.readDouble(), buf.readDouble()), buf.readFloat()); + } + + public static void handle(SpawnMistCloudPacket msg, Supplier ctx) { + ctx.get().enqueueWork(() -> DistExecutor.unsafeRunWhenOn((Dist)Dist.CLIENT, () -> () -> ClientEffects.triggerMistCloud(msg.position, msg.power))); + ctx.get().setPacketHandled(true); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/SpawnShockwavePacket.java b/src/main/java/com/vinlanx/explosionoverhaul/SpawnShockwavePacket.java new file mode 100644 index 0000000..d8c45bb --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/SpawnShockwavePacket.java @@ -0,0 +1,38 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.client.ClientEffects; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.phys.Vec3; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.DistExecutor; +import net.neoforged.neoforge.network.NetworkEvent; + +public class SpawnShockwavePacket { + private final Vec3 position; + private final float power; + + public SpawnShockwavePacket(Vec3 position, float power) { + this.position = position; + this.power = power; + } + + public static void encode(SpawnShockwavePacket msg, FriendlyByteBuf buf) { + buf.writeDouble(msg.position.f_82479_); + buf.writeDouble(msg.position.f_82480_); + buf.writeDouble(msg.position.f_82481_); + buf.writeFloat(msg.power); + } + + public static SpawnShockwavePacket decode(FriendlyByteBuf buf) { + return new SpawnShockwavePacket(new Vec3(buf.readDouble(), buf.readDouble(), buf.readDouble()), buf.readFloat()); + } + + public static void handle(SpawnShockwavePacket msg, Supplier ctx) { + ctx.get().enqueueWork(() -> DistExecutor.unsafeRunWhenOn((Dist)Dist.CLIENT, () -> () -> ClientEffects.triggerShockwave(msg.position, msg.power))); + ctx.get().setPacketHandled(true); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/StartConcussionPacket.java b/src/main/java/com/vinlanx/explosionoverhaul/StartConcussionPacket.java new file mode 100644 index 0000000..ef6dc91 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/StartConcussionPacket.java @@ -0,0 +1,65 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.client.ConcussionAudioEffect; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.DistExecutor; +import net.neoforged.neoforge.network.NetworkEvent; + +public class StartConcussionPacket { + private final float power; + private final double distance; + private final boolean hasDirectLineOfSight; + private final boolean explosionInCave; + + public StartConcussionPacket(float power, double distance, boolean hasDirectLineOfSight, boolean explosionInCave) { + this.power = power; + this.distance = distance; + this.hasDirectLineOfSight = hasDirectLineOfSight; + this.explosionInCave = explosionInCave; + } + + public StartConcussionPacket(FriendlyByteBuf buf) { + this.power = buf.readFloat(); + this.distance = buf.readDouble(); + this.hasDirectLineOfSight = buf.readBoolean(); + this.explosionInCave = buf.readBoolean(); + } + + public void encode(FriendlyByteBuf buf) { + buf.writeFloat(this.power); + buf.writeDouble(this.distance); + buf.writeBoolean(this.hasDirectLineOfSight); + buf.writeBoolean(this.explosionInCave); + } + + public static StartConcussionPacket decode(FriendlyByteBuf buf) { + return new StartConcussionPacket(buf); + } + + public float getPower() { + return this.power; + } + + public double getDistance() { + return this.distance; + } + + public boolean hasDirectLineOfSight() { + return this.hasDirectLineOfSight; + } + + public boolean isExplosionInCave() { + return this.explosionInCave; + } + + public static void handle(StartConcussionPacket packet, Supplier ctxSupplier) { + NetworkEvent.Context ctx = ctxSupplier.get(); + ctx.enqueueWork(() -> DistExecutor.unsafeRunWhenOn((Dist)Dist.CLIENT, () -> () -> ConcussionAudioEffect.start(packet.power, packet.distance, packet.hasDirectLineOfSight, packet.isExplosionInCave()))); + ctx.setPacketHandled(true); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/SuppressExplosionSoundPacket.java b/src/main/java/com/vinlanx/explosionoverhaul/SuppressExplosionSoundPacket.java new file mode 100644 index 0000000..6ed5033 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/SuppressExplosionSoundPacket.java @@ -0,0 +1,36 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.ClientSoundHandler; +import java.util.function.Supplier; +import net.minecraft.network.FriendlyByteBuf; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.DistExecutor; +import net.neoforged.neoforge.network.NetworkEvent; + +public class SuppressExplosionSoundPacket { + private final float power; + + public SuppressExplosionSoundPacket(float power) { + this.power = power; + } + + public static void encode(SuppressExplosionSoundPacket msg, FriendlyByteBuf buf) { + buf.writeFloat(msg.power); + } + + public static SuppressExplosionSoundPacket decode(FriendlyByteBuf buf) { + return new SuppressExplosionSoundPacket(buf.readFloat()); + } + + public static void handle(SuppressExplosionSoundPacket msg, Supplier ctx) { + ctx.get().enqueueWork(() -> DistExecutor.unsafeRunWhenOn((Dist)Dist.CLIENT, () -> () -> ClientSoundHandler.setSuppressVanillaExplosionSound(true, 10))); + ctx.get().setPacketHandled(true); + } + + public float getPower() { + return this.power; + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/VinlanxTheLightBlock.java b/src/main/java/com/vinlanx/explosionoverhaul/VinlanxTheLightBlock.java new file mode 100644 index 0000000..a385e13 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/VinlanxTheLightBlock.java @@ -0,0 +1,64 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.VinlanxTheLightBlockEntity; +import javax.annotation.Nullable; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.block.BaseEntityBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.block.state.properties.Property; +import net.minecraft.world.level.material.MapColor; + +public class VinlanxTheLightBlock +extends BaseEntityBlock { + public static final DirectionProperty FACING = HorizontalDirectionalBlock.f_54117_; + + public VinlanxTheLightBlock(BlockBehaviour.Properties properties) { + super(properties); + this.m_49959_((BlockState)((BlockState)this.f_49792_.m_61090_()).m_61124_((Property)FACING, (Comparable)Direction.NORTH)); + } + + public static BlockBehaviour.Properties defaultProperties() { + return BlockBehaviour.Properties.m_284310_().m_284180_(MapColor.f_283811_).m_60978_(2.5f).m_60955_().m_60918_(SoundType.f_154654_).m_60953_(state -> 12); + } + + public RenderShape m_7514_(BlockState state) { + return RenderShape.ENTITYBLOCK_ANIMATED; + } + + @Nullable + public BlockEntity m_142194_(BlockPos pos, BlockState state) { + return new VinlanxTheLightBlockEntity(pos, state); + } + + public BlockState m_5573_(BlockPlaceContext context) { + Direction direction = context.m_8125_(); + return (BlockState)this.m_49966_().m_61124_((Property)FACING, (Comparable)direction); + } + + public BlockState m_6843_(BlockState state, Rotation rotation) { + return (BlockState)state.m_61124_((Property)FACING, (Comparable)rotation.m_55954_((Direction)state.m_61143_((Property)FACING))); + } + + public BlockState m_6943_(BlockState state, Mirror mirror) { + return state.m_60717_(mirror.m_54846_((Direction)state.m_61143_((Property)FACING))); + } + + protected void m_7926_(StateDefinition.Builder builder) { + builder.m_61104_(new Property[]{FACING}); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/VinlanxTheLightBlockEntity.java b/src/main/java/com/vinlanx/explosionoverhaul/VinlanxTheLightBlockEntity.java new file mode 100644 index 0000000..b5c314b --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/VinlanxTheLightBlockEntity.java @@ -0,0 +1,32 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.ModBlockEntities; +import net.minecraft.core.BlockPos; +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.util.GeckoLibUtil; + +public class VinlanxTheLightBlockEntity +extends BlockEntity +implements GeoBlockEntity { + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache((GeoAnimatable)this); + + public VinlanxTheLightBlockEntity(BlockPos pos, BlockState state) { + super((BlockEntityType)ModBlockEntities.VINLANX_THE_LIGHT.get(), pos, state); + } + + public void registerControllers(AnimatableManager.ControllerRegistrar controllers) { + } + + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/VinlanxTheLightItem.java b/src/main/java/com/vinlanx/explosionoverhaul/VinlanxTheLightItem.java new file mode 100644 index 0000000..0596185 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/VinlanxTheLightItem.java @@ -0,0 +1,44 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.VinlanxTheLightItemRenderer; +import java.util.function.Consumer; +import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; +import net.minecraft.world.item.BlockItem; +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.util.GeckoLibUtil; + +public class VinlanxTheLightItem +extends BlockItem +implements GeoItem { + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache((GeoAnimatable)this); + + public VinlanxTheLightItem(Block block, Item.Properties properties) { + super(block, properties); + } + + public void registerControllers(AnimatableManager.ControllerRegistrar controllers) { + } + + public void initializeClient(Consumer consumer) { + consumer.accept(new IClientItemExtensions(){ + private final VinlanxTheLightItemRenderer renderer = new VinlanxTheLightItemRenderer(); + + public BlockEntityWithoutLevelRenderer getCustomRenderer() { + return this.renderer; + } + }); + } + + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/VinlanxTheLightItemRenderer.java b/src/main/java/com/vinlanx/explosionoverhaul/VinlanxTheLightItemRenderer.java new file mode 100644 index 0000000..d2319a8 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/VinlanxTheLightItemRenderer.java @@ -0,0 +1,29 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import com.vinlanx.explosionoverhaul.VinlanxTheLightItem; +import com.vinlanx.explosionoverhaul.VinlanxTheLightModel; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemDisplayContext; +import software.bernie.geckolib.cache.object.BakedGeoModel; +import software.bernie.geckolib.renderer.GeoItemRenderer; + +public class VinlanxTheLightItemRenderer +extends GeoItemRenderer { + public VinlanxTheLightItemRenderer() { + super(new VinlanxTheLightModel()); + } + + public void preRender(PoseStack poseStack, VinlanxTheLightItem animatable, BakedGeoModel model, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) { + super.preRender(poseStack, (Item)animatable, model, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, red, green, blue, alpha); + if (this.renderPerspective == ItemDisplayContext.GUI || this.renderPerspective == ItemDisplayContext.FIXED) { + poseStack.m_252781_(Axis.f_252436_.m_252977_(180.0f)); + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/VinlanxTheLightModel.java b/src/main/java/com/vinlanx/explosionoverhaul/VinlanxTheLightModel.java new file mode 100644 index 0000000..eefb97e --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/VinlanxTheLightModel.java @@ -0,0 +1,27 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import net.minecraft.resources.ResourceLocation; +import software.bernie.geckolib.core.animatable.GeoAnimatable; +import software.bernie.geckolib.model.GeoModel; + +public class VinlanxTheLightModel +extends GeoModel { + private static final ResourceLocation MODEL = ResourceLocation.fromNamespaceAndPath((String)"explosionoverhaul", (String)"geo/vinlanxthelight.geo.json"); + private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath((String)"explosionoverhaul", (String)"textures/block/vinlanxthelight.png"); + private static final ResourceLocation ANIMATION = ResourceLocation.fromNamespaceAndPath((String)"explosionoverhaul", (String)"animations/vinlanxthelight.animation.json"); + + public ResourceLocation getModelResource(T animatable) { + return MODEL; + } + + public ResourceLocation getTextureResource(T animatable) { + return TEXTURE; + } + + public ResourceLocation getAnimationResource(T animatable) { + return ANIMATION; + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/VinlanxTheLightRenderer.java b/src/main/java/com/vinlanx/explosionoverhaul/VinlanxTheLightRenderer.java new file mode 100644 index 0000000..2b3ca1f --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/VinlanxTheLightRenderer.java @@ -0,0 +1,16 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul; + +import com.vinlanx.explosionoverhaul.VinlanxTheLightBlockEntity; +import com.vinlanx.explosionoverhaul.VinlanxTheLightModel; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import software.bernie.geckolib.renderer.GeoBlockRenderer; + +public class VinlanxTheLightRenderer +extends GeoBlockRenderer { + public VinlanxTheLightRenderer(BlockEntityRendererProvider.Context context) { + super(new VinlanxTheLightModel()); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/api/IExplosionPower.java b/src/main/java/com/vinlanx/explosionoverhaul/api/IExplosionPower.java new file mode 100644 index 0000000..2f2b187 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/api/IExplosionPower.java @@ -0,0 +1,10 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.api; + +public interface IExplosionPower { + public float getPower(); + + public void setPower(float var1); +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/AnimationSoundManager.java b/src/main/java/com/vinlanx/explosionoverhaul/client/AnimationSoundManager.java new file mode 100644 index 0000000..a1c6e57 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/AnimationSoundManager.java @@ -0,0 +1,101 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.vinlanx.explosionoverhaul.ModSounds; +import java.util.ArrayList; +import java.util.List; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.util.RandomSource; +import net.neoforged.neoforge.registries.RegistryObject; + +public class AnimationSoundManager { + private static final RandomSource RANDOM = RandomSource.m_216327_(); + private static final List> ANIMATION_SOUNDS = new ArrayList>(); + private static final List> FAR_POWER_2_SOUNDS = new ArrayList>(); + private static final List> FAR_POWER_3_SOUNDS = new ArrayList>(); + private static final List> MEDIUM_CAVE_POWER_4_SOUNDS = new ArrayList>(); + private static final List> SUPERFAR_POWER_4_SOUNDS = new ArrayList>(); + private static int lastAnimationSoundIndex = -1; + private static int lastFarPower2SoundIndex = -1; + private static int lastFarPower3SoundIndex = -1; + private static int lastMediumCavePower4SoundIndex = -1; + private static int lastSuperfar4SoundIndex = -1; + + private static int getNextRandomIndex(List list, int lastIndex) { + int nextIndex; + if (list.size() <= 1) { + return 0; + } + while ((nextIndex = RANDOM.m_188503_(list.size())) == lastIndex) { + } + return nextIndex; + } + + public static void playRandomAnimationSound() { + if (ANIMATION_SOUNDS.isEmpty()) { + return; + } + lastAnimationSoundIndex = AnimationSoundManager.getNextRandomIndex(ANIMATION_SOUNDS, lastAnimationSoundIndex); + SoundEvent sound = (SoundEvent)ANIMATION_SOUNDS.get(lastAnimationSoundIndex).get(); + Minecraft.m_91087_().m_91106_().m_120367_((SoundInstance)SimpleSoundInstance.m_119752_((SoundEvent)sound, (float)1.0f)); + } + + public static void playRandomFarPower2Sound() { + if (FAR_POWER_2_SOUNDS.isEmpty()) { + return; + } + lastFarPower2SoundIndex = AnimationSoundManager.getNextRandomIndex(FAR_POWER_2_SOUNDS, lastFarPower2SoundIndex); + SoundEvent sound = (SoundEvent)FAR_POWER_2_SOUNDS.get(lastFarPower2SoundIndex).get(); + Minecraft.m_91087_().m_91106_().m_120367_((SoundInstance)SimpleSoundInstance.m_119752_((SoundEvent)sound, (float)1.0f)); + } + + public static void playRandomFarPower3Sound() { + if (FAR_POWER_3_SOUNDS.isEmpty()) { + return; + } + lastFarPower3SoundIndex = AnimationSoundManager.getNextRandomIndex(FAR_POWER_3_SOUNDS, lastFarPower3SoundIndex); + SoundEvent sound = (SoundEvent)FAR_POWER_3_SOUNDS.get(lastFarPower3SoundIndex).get(); + Minecraft.m_91087_().m_91106_().m_120367_((SoundInstance)SimpleSoundInstance.m_119752_((SoundEvent)sound, (float)1.0f)); + } + + public static void playRandomMediumCavePower4Sound() { + if (MEDIUM_CAVE_POWER_4_SOUNDS.isEmpty()) { + return; + } + lastMediumCavePower4SoundIndex = AnimationSoundManager.getNextRandomIndex(MEDIUM_CAVE_POWER_4_SOUNDS, lastMediumCavePower4SoundIndex); + SoundEvent sound = (SoundEvent)MEDIUM_CAVE_POWER_4_SOUNDS.get(lastMediumCavePower4SoundIndex).get(); + Minecraft.m_91087_().m_91106_().m_120367_((SoundInstance)SimpleSoundInstance.m_119752_((SoundEvent)sound, (float)1.0f)); + } + + public static void playRandomSuperfar4Sound() { + if (SUPERFAR_POWER_4_SOUNDS.isEmpty()) { + return; + } + lastSuperfar4SoundIndex = AnimationSoundManager.getNextRandomIndex(SUPERFAR_POWER_4_SOUNDS, lastSuperfar4SoundIndex); + SoundEvent sound = (SoundEvent)SUPERFAR_POWER_4_SOUNDS.get(lastSuperfar4SoundIndex).get(); + Minecraft.m_91087_().m_91106_().m_120367_((SoundInstance)SimpleSoundInstance.m_119752_((SoundEvent)sound, (float)1.0f)); + } + + static { + ANIMATION_SOUNDS.add(ModSounds.EXPLODE_SUPERFAR_POWER_2_1); + ANIMATION_SOUNDS.add(ModSounds.EXPLODE_SUPERFAR_POWER_2_2); + ANIMATION_SOUNDS.add(ModSounds.EXPLODE_SUPERFAR_POWER_3_1); + FAR_POWER_2_SOUNDS.add(ModSounds.EXPLODE_FAR_POWER_2_1); + FAR_POWER_2_SOUNDS.add(ModSounds.EXPLODE_FAR_POWER_2_2); + FAR_POWER_2_SOUNDS.add(ModSounds.EXPLODE_FAR_POWER_2_3); + FAR_POWER_3_SOUNDS.add(ModSounds.EXPLODE_FAR_POWER_3_1); + FAR_POWER_3_SOUNDS.add(ModSounds.EXPLODE_FAR_POWER_3_2); + FAR_POWER_3_SOUNDS.add(ModSounds.EXPLODE_FAR_POWER_3_3); + MEDIUM_CAVE_POWER_4_SOUNDS.add(ModSounds.EXPLODE_MEDIUM_CAVE_POWER_4_1); + MEDIUM_CAVE_POWER_4_SOUNDS.add(ModSounds.EXPLODE_MEDIUM_CAVE_POWER_4_2); + MEDIUM_CAVE_POWER_4_SOUNDS.add(ModSounds.EXPLODE_MEDIUM_CAVE_POWER_4_3); + SUPERFAR_POWER_4_SOUNDS.add(ModSounds.EXPLODE_SUPERFAR_POWER_4_1); + SUPERFAR_POWER_4_SOUNDS.add(ModSounds.EXPLODE_SUPERFAR_POWER_4_2); + SUPERFAR_POWER_4_SOUNDS.add(ModSounds.EXPLODE_SUPERFAR_POWER_4_3); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/BackgroundParticle.java b/src/main/java/com/vinlanx/explosionoverhaul/client/BackgroundParticle.java new file mode 100644 index 0000000..3764116 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/BackgroundParticle.java @@ -0,0 +1,111 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; + +public class BackgroundParticle { + public float x; + public float y; + public float vx; + public float vy; + public float size; + public float life; + public float maxLife; + public int color; + public ParticleType type; + + public BackgroundParticle(float x, float y, float vx, float vy, float size, float life, int color, ParticleType type) { + this.x = x; + this.y = y; + this.vx = vx; + this.vy = vy; + this.size = size; + this.life = life; + this.maxLife = life; + this.color = color; + this.type = type; + } + + public void tick(float deltaTime) { + this.x += this.vx * deltaTime * 60.0f; + this.y += this.vy * deltaTime * 60.0f; + this.life -= deltaTime; + if (this.type == ParticleType.EMBER) { + this.vy += 0.5f * deltaTime * 60.0f; + } + if (this.type == ParticleType.SMOKE) { + this.size += 0.3f * deltaTime * 60.0f; + } + } + + public boolean isDead() { + return this.life <= 0.0f; + } + + public float getAlpha() { + float lifeRatio = this.life / this.maxLife; + if (this.type == ParticleType.FLASH) { + return lifeRatio > 0.7f ? 1.0f - (lifeRatio - 0.7f) / 0.3f : lifeRatio / 0.7f; + } + return Mth.m_14036_((float)lifeRatio, (float)0.0f, (float)1.0f); + } + + public static BackgroundParticle createSpark(RandomSource random, int screenWidth, int screenHeight) { + float x = random.m_188501_() * (float)screenWidth; + float y = random.m_188501_() * (float)screenHeight; + float angle = random.m_188501_() * (float)Math.PI * 2.0f; + float speed = 2.0f + random.m_188501_() * 4.0f; + float vx = (float)Math.cos(angle) * speed; + float vy = (float)Math.sin(angle) * speed; + float size = 1.0f + random.m_188501_() * 2.0f; + float life = 0.5f + random.m_188501_() * 1.5f; + int[] colors = new int[]{-881908, -21965, -8841, -86}; + int color = colors[random.m_188503_(colors.length)]; + return new BackgroundParticle(x, y, vx, vy, size, life, color, ParticleType.SPARK); + } + + public static BackgroundParticle createEmber(RandomSource random, int screenWidth, int screenHeight) { + float x = random.m_188501_() * (float)screenWidth; + float y = -20.0f; + float vx = (random.m_188501_() - 0.5f) * 2.0f; + float vy = 1.0f + random.m_188501_() * 2.0f; + float size = 2.0f + random.m_188501_() * 4.0f; + float life = 3.0f + random.m_188501_() * 4.0f; + int[] colors = new int[]{-4250588, -2529701, -10939115, -48094}; + int color = colors[random.m_188503_(colors.length)]; + return new BackgroundParticle(x, y, vx, vy, size, life, color, ParticleType.EMBER); + } + + public static BackgroundParticle createFlash(RandomSource random, int screenWidth, int screenHeight) { + float x = random.m_188501_() * (float)screenWidth; + float y = random.m_188501_() * (float)screenHeight; + float size = 30.0f + random.m_188501_() * 70.0f; + float life = 0.2f + random.m_188501_() * 0.4f; + int[] colors = new int[]{-881908, -4250588, -21948}; + int color = colors[random.m_188503_(colors.length)]; + return new BackgroundParticle(x, y, 0.0f, 0.0f, size, life, color, ParticleType.FLASH); + } + + public static BackgroundParticle createSmoke(RandomSource random, int screenWidth, int screenHeight) { + float x = random.m_188501_() * (float)screenWidth; + float y = (float)screenHeight + 20.0f; + float vx = (random.m_188501_() - 0.5f) * 1.0f; + float vy = -1.0f - random.m_188501_() * 2.0f; + float size = 15.0f + random.m_188501_() * 30.0f; + float life = 4.0f + random.m_188501_() * 6.0f; + int gray = 13 + random.m_188503_(30); + int color = 0xFF000000 | gray << 16 | gray << 8 | gray; + return new BackgroundParticle(x, y, vx, vy, size, life, color, ParticleType.SMOKE); + } + + public static enum ParticleType { + SPARK, + EMBER, + FLASH, + SMOKE; + + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/BlacklistScreen.java b/src/main/java/com/vinlanx/explosionoverhaul/client/BlacklistScreen.java new file mode 100644 index 0000000..cb7e00b --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/BlacklistScreen.java @@ -0,0 +1,495 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.vinlanx.explosionoverhaul.BlockIndexManager; +import com.vinlanx.explosionoverhaul.ExplosionOverhaul; +import java.util.ArrayList; +import java.util.Collections; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.CycleButton; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.components.ObjectSelectionList; +import net.minecraft.client.gui.components.Tooltip; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.FormattedText; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.ItemLike; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.neoforged.neoforge.registries.ForgeRegistries; + +public class BlacklistScreen +extends Screen { + private static final int NAV_WIDTH = 160; + private static final int PADDING = 12; + private static final int HEADER_HEIGHT = 48; + private static final int FOOTER_HEIGHT = 64; + private static final int SEARCH_WIDTH = 200; + private static final int INPUT_WIDTH = 240; + private static final int BUTTON_HEIGHT = 20; + private static final int SPACING = 4; + private final Screen parent; + private BlacklistList widget; + private EditBox inputField; + private Button addButton; + private EditBox searchField; + private Button backButton; + private Button resetButton; + private Button infoButton; + private CycleButton defaultToggle; + private final LinkedHashSet persistedEntries = new LinkedHashSet(); + private final Map persistedSourceModes = new HashMap(); + private final Set defaultEntries = new LinkedHashSet(); + private boolean showDefaults = false; + private final EnumMap categoryButtons = new EnumMap(BlacklistCategory.class); + private BlacklistCategory currentCategory = BlacklistCategory.EXPLOSION; + private List suggestions = Collections.emptyList(); + private List registryCache = new ArrayList(); + + public BlacklistScreen(Screen parent) { + super((Component)Component.m_237115_((String)"title.explosionoverhaul.blacklist")); + this.parent = parent; + } + + protected void m_7856_() { + this.categoryButtons.clear(); + this.setupLayout(); + this.addNavigation(); + this.addTopControls(); + this.addInputArea(); + this.updateCache(); + this.loadCurrentCategoryEntries(); + } + + private void setupLayout() { + int listTop = 48; + int listBottom = this.f_96544_ - 64; + int listWidth = this.f_96543_ - 160 - 24; + int listLeft = 172; + this.widget = new BlacklistList(this.f_96541_, listWidth, listBottom - listTop, listTop, listBottom, 24); + this.widget.m_93507_(listLeft); + this.m_142416_((GuiEventListener)this.widget); + } + + private void addNavigation() { + int buttonY = 48; + for (BlacklistCategory category : BlacklistCategory.values()) { + Button button = Button.m_253074_((Component)this.formatCategoryLabel(category), b -> this.selectCategory(category)).m_252794_(12, buttonY).m_253046_(160, 20).m_257505_(Tooltip.m_257550_((Component)Component.m_237115_((String)category.getTooltipKey()))).m_253136_(); + this.categoryButtons.put(category, button); + this.m_142416_((GuiEventListener)button); + buttonY += 24; + } + } + + private void addTopControls() { + int listLeft = 172; + this.backButton = Button.m_253074_((Component)Component.m_237115_((String)"gui.back"), b -> this.m_7379_()).m_252794_(12, 12).m_253046_(80, 20).m_253136_(); + this.m_142416_((GuiEventListener)this.backButton); + this.searchField = new EditBox(this.f_96547_, listLeft, 26, 200, 18, (Component)Component.m_237119_()); + this.searchField.m_257771_((Component)Component.m_237115_((String)"option.explosionoverhaul.blacklist_search")); + this.searchField.m_94151_(s -> this.refreshList()); + this.m_142416_((GuiEventListener)this.searchField); + this.resetButton = Button.m_253074_((Component)Component.m_237115_((String)"option.explosionoverhaul.reset_list"), this::onResetClicked).m_252794_(this.f_96543_ - 250, 12).m_253046_(60, 20).m_257505_(Tooltip.m_257550_((Component)Component.m_237115_((String)"tooltip.explosionoverhaul.reset_list"))).m_253136_(); + this.m_142416_((GuiEventListener)this.resetButton); + this.defaultToggle = CycleButton.m_168916_((boolean)this.showDefaults).m_232498_(value -> Tooltip.m_257550_((Component)Component.m_237115_((String)"tooltip.explosionoverhaul.show_defaults"))).m_168936_(this.f_96543_ - 180, 12, 168, 20, (Component)Component.m_237115_((String)"option.explosionoverhaul.show_defaults"), (btn, value) -> { + this.showDefaults = value; + this.refreshList(); + }); + this.m_142416_((GuiEventListener)this.defaultToggle); + } + + private void addInputArea() { + int y = this.f_96544_ - 28; + this.inputField = new EditBox(this.f_96547_, (this.f_96543_ - 240) / 2, y, 240, 18, (Component)Component.m_237119_()); + this.inputField.m_94199_(128); + this.inputField.m_257771_((Component)Component.m_237115_((String)"option.explosionoverhaul.blacklist_input")); + this.inputField.m_94151_(this::updateSuggestions); + this.m_142416_((GuiEventListener)this.inputField); + this.addButton = Button.m_253074_((Component)Component.m_237115_((String)"option.explosionoverhaul.blacklist_add"), b -> this.addCurrentInput()).m_252794_(this.inputField.m_252754_() + 240 + 8, this.inputField.m_252907_() - 1).m_253046_(80, 20).m_253136_(); + this.m_142416_((GuiEventListener)this.addButton); + this.infoButton = Button.m_253074_((Component)Component.m_237115_((String)"option.explosionoverhaul.blacklist_info"), b -> {}).m_252794_(this.addButton.m_252754_() + 80 + 4, this.addButton.m_252907_()).m_253046_(40, 20).m_257505_(Tooltip.m_257550_((Component)Component.m_237115_((String)"tooltip.explosionoverhaul.blacklist_info"))).m_253136_(); + this.infoButton.f_93624_ = this.currentCategory == BlacklistCategory.SOURCES; + this.m_142416_((GuiEventListener)this.infoButton); + } + + private void onResetClicked(Button b) { + if (BlacklistScreen.m_96638_()) { + List defaults = this.currentCategory.loadDefaults(); + this.currentCategory.saveEntries(defaults); + this.persistedEntries.clear(); + this.persistedEntries.addAll(defaults); + if (this.currentCategory == BlacklistCategory.SOURCES) { + this.persistedSourceModes.clear(); + this.save(); + } + this.refreshList(); + this.displayStatus((Component)Component.m_237115_((String)"message.explosionoverhaul.list_reset")); + } + } + + private void updateCache() { + LinkedHashSet uniqueRegistry = new LinkedHashSet(); + if (this.currentCategory == BlacklistCategory.SOURCES) { + uniqueRegistry.add("generic"); + ForgeRegistries.ENTITY_TYPES.getKeys().stream().map(ResourceLocation::toString).forEach(uniqueRegistry::add); + ForgeRegistries.BLOCKS.getKeys().stream().map(ResourceLocation::toString).forEach(uniqueRegistry::add); + ForgeRegistries.ITEMS.getKeys().stream().map(ResourceLocation::toString).forEach(uniqueRegistry::add); + } else { + ForgeRegistries.BLOCKS.getKeys().stream().map(ResourceLocation::toString).forEach(uniqueRegistry::add); + } + this.registryCache = new ArrayList(uniqueRegistry); + } + + private void loadCurrentCategoryEntries() { + this.persistedEntries.clear(); + this.persistedEntries.addAll(this.currentCategory.loadEntries()); + if (this.currentCategory == BlacklistCategory.SOURCES) { + this.persistedSourceModes.clear(); + this.persistedSourceModes.putAll(ExplosionOverhaul.getSourceModes()); + } + this.defaultEntries.clear(); + this.defaultEntries.addAll(this.currentCategory.loadDefaults()); + this.refreshList(); + } + + private void selectCategory(BlacklistCategory category) { + if (this.currentCategory == category) { + return; + } + this.currentCategory = category; + this.updateCache(); + this.loadCurrentCategoryEntries(); + this.updateCategoryButtons(); + if (this.infoButton != null) { + boolean bl = this.infoButton.f_93624_ = this.currentCategory == BlacklistCategory.SOURCES; + } + if (this.inputField != null) { + this.inputField.m_94144_(""); + this.updateSuggestions(""); + this.inputField.m_257771_((Component)Component.m_237115_((String)(this.currentCategory == BlacklistCategory.SOURCES ? "option.explosionoverhaul.blacklist_input_entities" : "option.explosionoverhaul.blacklist_input"))); + } + } + + private void updateCategoryButtons() { + this.categoryButtons.forEach((category, button) -> button.m_93666_(this.formatCategoryLabel((BlacklistCategory)((Object)category)))); + } + + private Component formatCategoryLabel(BlacklistCategory category) { + MutableComponent label = Component.m_237115_((String)category.getLabelKey()); + if (category == this.currentCategory) { + return Component.m_237113_((String)"\u25b6 ").m_7220_((Component)label); + } + return label; + } + + private void refreshList() { + String query = this.searchField == null ? "" : this.searchField.m_94155_().trim().toLowerCase(Locale.ROOT); + boolean hasQuery = !query.isEmpty(); + ArrayList entries = new ArrayList(); + for (String id : this.persistedEntries) { + boolean isDefault = this.defaultEntries.contains(id); + if (!hasQuery && !this.showDefaults && isDefault || hasQuery && !id.toLowerCase(Locale.ROOT).contains(query)) continue; + entries.add(new BlacklistEntry(id, isDefault)); + } + this.widget.rebuild(entries); + } + + private void addCurrentInput() { + String normalized; + String raw = this.inputField.m_94155_().trim().toLowerCase(Locale.ROOT); + if (raw.isEmpty()) { + return; + } + if (raw.equals("generic")) { + normalized = "generic"; + } else { + ResourceLocation id = ResourceLocation.m_135820_((String)(raw.contains(":") ? raw : "minecraft:" + raw)); + if (id == null) { + this.displayStatus((Component)Component.m_237115_((String)"message.explosionoverhaul.invalid_id")); + return; + } + normalized = id.toString(); + } + if (!this.persistedEntries.add(normalized)) { + this.displayStatus((Component)Component.m_237115_((String)"message.explosionoverhaul.duplicate_entry")); + return; + } + if (this.currentCategory == BlacklistCategory.SOURCES) { + this.persistedSourceModes.put(normalized, ExplosionOverhaul.ExplosionSourceMode.DEFAULT); + } + this.save(); + this.inputField.m_94144_(""); + this.updateSuggestions(""); + this.refreshList(); + } + + private void removeEntry(String id) { + if (this.persistedEntries.remove(id)) { + if (this.currentCategory == BlacklistCategory.SOURCES) { + this.persistedSourceModes.remove(id); + } + this.save(); + this.refreshList(); + } + } + + private void save() { + if (this.currentCategory == BlacklistCategory.SOURCES) { + HashMap toSave = new HashMap(); + for (String id : this.persistedEntries) { + toSave.put(id, this.persistedSourceModes.getOrDefault(id, ExplosionOverhaul.ExplosionSourceMode.DEFAULT)); + } + ExplosionOverhaul.setSourceModes(toSave); + } else { + this.currentCategory.saveEntries(new ArrayList(this.persistedEntries)); + } + } + + private void updateSuggestions(String current) { + String query = current.trim().toLowerCase(Locale.ROOT); + if (query.isEmpty()) { + this.suggestions = Collections.emptyList(); + return; + } + this.suggestions = this.registryCache.stream().filter(name -> name.startsWith(query)).limit(12L).collect(Collectors.toList()); + } + + private void displayStatus(Component message) { + if (this.f_96541_ != null && this.f_96541_.f_91065_ != null) { + this.f_96541_.f_91065_.m_93063_(message, false); + } + } + + public boolean m_7933_(int keyCode, int scanCode, int modifiers) { + if (this.inputField.m_93696_() && (keyCode == 257 || keyCode == 335)) { + this.addCurrentInput(); + return true; + } + return super.m_7933_(keyCode, scanCode, modifiers); + } + + public void m_88315_(GuiGraphics graphics, int mouseX, int mouseY, float delta) { + this.m_280273_(graphics); + graphics.m_280614_(this.f_96547_, this.f_96539_, this.f_96543_ / 2 - this.f_96547_.m_92852_((FormattedText)this.f_96539_) / 2, 16, 0xFFFFFF, false); + this.widget.m_88315_(graphics, mouseX, mouseY, delta); + super.m_88315_(graphics, mouseX, mouseY, delta); + this.inputField.m_88315_(graphics, mouseX, mouseY, delta); + this.renderSuggestions(graphics, mouseX, mouseY); + } + + private void renderSuggestions(GuiGraphics graphics, int mouseX, int mouseY) { + if (this.suggestions.isEmpty() || !this.inputField.m_93696_()) { + return; + } + int x = this.inputField.m_252754_(); + int y = this.inputField.m_252907_() - this.suggestions.size() * 12 - 4; + int width = this.inputField.m_5711_(); + int line = 0; + for (String s : this.suggestions) { + int yy = y + line * 12; + graphics.m_280509_(x, yy, x + width, yy + 12, -1442840576); + graphics.m_280056_(this.f_96547_, s, x + 4, yy + 2, 0xE0E0E0, false); + ++line; + } + } + + public boolean m_6375_(double mouseX, double mouseY, int button) { + if (this.inputField.m_93696_() && !this.suggestions.isEmpty()) { + int x = this.inputField.m_252754_(); + int y = this.inputField.m_252907_() - this.suggestions.size() * 12 - 4; + int width = this.inputField.m_5711_(); + for (int i = 0; i < this.suggestions.size(); ++i) { + int yy = y + i * 12; + if (!(mouseX >= (double)x) || !(mouseX <= (double)(x + width)) || !(mouseY >= (double)yy) || !(mouseY <= (double)(yy + 12))) continue; + this.inputField.m_94144_(this.suggestions.get(i)); + this.inputField.m_94196_(this.inputField.m_94155_().length()); + this.updateSuggestions(this.inputField.m_94155_()); + return true; + } + } + return super.m_6375_(mouseX, mouseY, button); + } + + public void m_7379_() { + this.save(); + this.f_96541_.m_91152_(this.parent); + } + + private static enum BlacklistCategory { + EXPLOSION("option.explosionoverhaul.blacklist_category_explosion", "tooltip.explosionoverhaul.blacklist_category_explosion", ExplosionOverhaul::getExplosionBlacklistList, ExplosionOverhaul::getDefaultExplosionBlacklist, ExplosionOverhaul::setExplosionBlacklistFromList), + GLASS("option.explosionoverhaul.blacklist_category_glass", "tooltip.explosionoverhaul.blacklist_category_glass", BlockIndexManager::getReinforcedGlassBlacklist, BlockIndexManager::getDefaultReinforcedGlassBlacklist, BlockIndexManager::setReinforcedGlassBlacklistFromList), + SOURCES("option.explosionoverhaul.blacklist_category_sources", "tooltip.explosionoverhaul.blacklist_category_sources", () -> new ArrayList(ExplosionOverhaul.getSourceModes().keySet()), ArrayList::new, list -> {}); + + private final String labelKey; + private final String tooltipKey; + private final Supplier> entriesSupplier; + private final Supplier> defaultsSupplier; + private final Consumer> saveAction; + + private BlacklistCategory(String labelKey, String tooltipKey, Supplier> entriesSupplier, Supplier> defaultsSupplier, Consumer> saveAction) { + this.labelKey = labelKey; + this.tooltipKey = tooltipKey; + this.entriesSupplier = entriesSupplier; + this.defaultsSupplier = defaultsSupplier; + this.saveAction = saveAction; + } + + String getLabelKey() { + return this.labelKey; + } + + String getTooltipKey() { + return this.tooltipKey; + } + + List loadEntries() { + return this.entriesSupplier.get(); + } + + List loadDefaults() { + return this.defaultsSupplier.get(); + } + + void saveEntries(List entries) { + this.saveAction.accept(entries); + } + } + + private class BlacklistList + extends ObjectSelectionList { + public BlacklistList(Minecraft mc, int width, int height, int top, int bottom, int itemHeight) { + super(mc, width, height, top, bottom, itemHeight); + } + + void rebuild(List entries) { + this.m_5988_(entries); + } + + public int m_5759_() { + return this.f_93388_ - 12; + } + + protected int m_5756_() { + return this.m_5747_() + this.m_5759_(); + } + + public boolean m_7979_(double mouseX, double mouseY, int button, double dragX, double dragY) { + return super.m_7979_(mouseX, mouseY, button, dragX, dragY); + } + } + + private class BlacklistEntry + extends ObjectSelectionList.Entry { + private final String id; + private final boolean isDefault; + private final Button removeButton; + private CycleButton modeButton; + private ItemStack icon; + private int lastX; + private int lastY; + private int lastRowWidth; + private int lastRowHeight; + + BlacklistEntry(String id, boolean isDefault) { + this.id = id; + this.isDefault = isDefault; + if (BlacklistScreen.this.currentCategory == BlacklistCategory.SOURCES) { + if (id.equals("generic")) { + this.icon = new ItemStack((ItemLike)Items.f_41996_); + } else { + ResourceLocation rl = ResourceLocation.m_135820_((String)id); + ItemStack stack = ItemStack.f_41583_; + if (rl != null) { + Block b2; + stack = new ItemStack((ItemLike)ForgeRegistries.ITEMS.getValue(rl)); + if (stack.m_41619_()) { + stack = new ItemStack((ItemLike)ForgeRegistries.ITEMS.getValue(new ResourceLocation(rl.m_135827_(), rl.m_135815_() + "_spawn_egg"))); + } + if (stack.m_41619_() && (b2 = (Block)ForgeRegistries.BLOCKS.getValue(rl)) != Blocks.f_50016_) { + stack = new ItemStack((ItemLike)b2.m_5456_()); + } + } + this.icon = stack.m_41619_() ? new ItemStack((ItemLike)Items.f_41996_) : stack; + } + ExplosionOverhaul.ExplosionSourceMode currentMode = BlacklistScreen.this.persistedSourceModes.getOrDefault(id, ExplosionOverhaul.ExplosionSourceMode.DEFAULT); + String entryId = id; + this.modeButton = CycleButton.m_168894_(m -> Component.m_237115_((String)("option.explosionoverhaul.sourcemode_" + m.name().toLowerCase(Locale.ROOT)))).m_168961_((Object[])ExplosionOverhaul.ExplosionSourceMode.values()).m_168948_((Object)currentMode).m_232498_(m -> Tooltip.m_257550_((Component)Component.m_237115_((String)("tooltip.explosionoverhaul.sourcemode_" + m.name().toLowerCase(Locale.ROOT))))).m_168936_(0, 0, 150, 20, (Component)Component.m_237119_(), (btn, value) -> { + BlacklistScreen.this.persistedSourceModes.put(entryId, (ExplosionOverhaul.ExplosionSourceMode)((Object)value)); + BlacklistScreen.this.save(); + }); + } else { + ItemStack stack; + Block block = (Block)ForgeRegistries.BLOCKS.getValue(ResourceLocation.m_135820_((String)id)); + ItemStack itemStack = stack = block == null || block == Blocks.f_50016_ ? ItemStack.f_41583_ : new ItemStack((ItemLike)block.m_5456_()); + if (stack.m_41619_()) { + stack = new ItemStack((ItemLike)Items.f_42127_); + } + this.icon = stack; + } + this.removeButton = Button.m_253074_((Component)Component.m_237113_((String)"\u2715"), b -> BlacklistScreen.this.removeEntry(this.id)).m_252794_(0, 0).m_253046_(20, 20).m_253136_(); + } + + public Component m_142172_() { + return Component.m_237113_((String)this.id); + } + + public boolean m_6375_(double mouseX, double mouseY, int button) { + if (this.modeButton != null && this.modeButton.m_6375_(mouseX, mouseY, button)) { + return true; + } + int btnX = this.lastX + this.lastRowWidth - 26; + int btnY = this.lastY + (this.lastRowHeight - 20) / 2; + if (mouseX >= (double)btnX && mouseX <= (double)(btnX + 20) && mouseY >= (double)btnY && mouseY <= (double)(btnY + 20)) { + BlacklistScreen.this.removeEntry(this.id); + return true; + } + return super.m_6375_(mouseX, mouseY, button); + } + + public void m_6311_(GuiGraphics graphics, int index, int y, int x, int rowWidth, int rowHeight, int mouseX, int mouseY, boolean hovered, float delta) { + this.lastX = x; + this.lastY = y; + this.lastRowWidth = rowWidth; + this.lastRowHeight = rowHeight; + int iconX = x + 6; + int iconY = y + (rowHeight - 16) / 2; + try { + graphics.m_280480_(this.icon, iconX, iconY); + } + catch (Throwable t) { + this.icon = new ItemStack((ItemLike)Items.f_42127_); + graphics.m_280480_(this.icon, iconX, iconY); + } + int textX = iconX + 22; + int color = this.isDefault ? -5197648 : -1; + graphics.m_280056_(BlacklistScreen.this.f_96547_, this.id, textX, y + (rowHeight - 8) / 2, color, false); + if (this.modeButton != null) { + int modeX = x + rowWidth - 180; + this.modeButton.m_264152_(modeX, y + (rowHeight - 20) / 2); + this.modeButton.m_88315_(graphics, mouseX, mouseY, delta); + } + int btnX = x + rowWidth - 26; + this.removeButton.m_264152_(btnX, y + (rowHeight - 20) / 2); + this.removeButton.m_88315_(graphics, mouseX, mouseY, delta); + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/Blur.java b/src/main/java/com/vinlanx/explosionoverhaul/client/Blur.java new file mode 100644 index 0000000..4b2a398 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/Blur.java @@ -0,0 +1,262 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.pipeline.TextureTarget; +import com.mojang.blaze3d.shaders.Uniform; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.BufferUploader; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.vinlanx.explosionoverhaul.client.ConcussionAudioEffect; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ShaderInstance; +import net.minecraft.util.Mth; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; + +@OnlyIn(value=Dist.CLIENT) +public class Blur { + private static final int FADE_IN_TICKS = 40; + private static final int FADE_OUT_TICKS = 100; + private static Phase phase = Phase.IDLE; + private static int holdTicks = 0; + private static int ticksInPhase = 0; + private static ShaderInstance shader; + private static RenderTarget blurTarget; + private static int lastWidth; + private static int lastHeight; + private static float currentIntensity; + private static float targetIntensity; + private static float currentDesaturation; + public static boolean APPLY_TO_HUD; + public static boolean APPLY_TO_HAND; + + public static boolean isActive() { + return phase != Phase.IDLE; + } + + public static float getCurrentIntensity() { + return currentIntensity; + } + + public static void setShader(ShaderInstance instance) { + shader = instance; + } + + public static void setDesaturation(float v) { + currentDesaturation = Mth.m_14036_((float)v, (float)0.0f, (float)1.0f); + } + + public static void start(int seconds) { + Blur.start(seconds, 1.0f); + } + + public static void start(int seconds, float intensity) { + int newHoldTicks = Mth.m_14045_((int)seconds, (int)1, (int)100) * 20; + float newIntensity = Mth.m_14036_((float)intensity, (float)0.0f, (float)1.0f); + if (phase != Phase.IDLE) { + targetIntensity = Mth.m_14036_((float)(targetIntensity + newIntensity), (float)0.0f, (float)1.0f); + holdTicks = Math.min(2000, holdTicks + newHoldTicks); + if (phase == Phase.FADE_OUT) { + phase = Phase.HOLD; + ticksInPhase = 0; + } + } else { + holdTicks = newHoldTicks; + ticksInPhase = 0; + targetIntensity = newIntensity; + phase = Phase.FADE_IN; + currentIntensity = 0.0f; + } + } + + public static void stop() { + phase = Phase.IDLE; + ticksInPhase = 0; + holdTicks = 0; + currentIntensity = 0.0f; + targetIntensity = 0.0f; + } + + public static void onClientTick() { + float intensity; + Minecraft mc = Minecraft.m_91087_(); + if (mc.m_91104_() || phase == Phase.IDLE) { + return; + } + ++ticksInPhase; + switch (phase) { + case FADE_IN: { + float t = Math.min(1.0f, (float)ticksInPhase / 40.0f); + intensity = Blur.easeOutCubic(t) * targetIntensity; + if (ticksInPhase < 40) break; + phase = Phase.HOLD; + ticksInPhase = 0; + break; + } + case HOLD: { + intensity = targetIntensity; + if (ticksInPhase < holdTicks) break; + phase = Phase.FADE_OUT; + ticksInPhase = 0; + break; + } + case FADE_OUT: { + float t = Math.min(1.0f, (float)ticksInPhase / 100.0f); + intensity = targetIntensity * (1.0f - Blur.easeInCubic(t)); + if (ticksInPhase < 100) break; + currentIntensity = 0.0f; + Blur.stop(); + return; + } + default: { + intensity = 0.0f; + } + } + currentIntensity = intensity; + if (mc.f_91074_ != null) { + ConcussionAudioEffect.updateHeartbeat(mc.f_91074_, currentIntensity); + } + } + + public static void render(RenderStage stage) { + if (phase == Phase.IDLE || shader == null) { + return; + } + if (!Blur.shouldRenderStage(stage)) { + return; + } + Minecraft mc = Minecraft.m_91087_(); + if (mc == null) { + return; + } + RenderTarget mainTarget = mc.m_91385_(); + if (mainTarget == null) { + return; + } + Blur.ensureTarget(mainTarget.f_83915_, mainTarget.f_83916_); + if (blurTarget == null) { + return; + } + RenderSystem.disableDepthTest(); + RenderSystem.depthMask((boolean)false); + RenderSystem.disableBlend(); + RenderSystem.setShaderColor((float)1.0f, (float)1.0f, (float)1.0f, (float)1.0f); + blurTarget.m_83947_(true); + RenderSystem.viewport((int)0, (int)0, (int)Blur.blurTarget.f_83915_, (int)Blur.blurTarget.f_83916_); + Blur.renderFullscreen(mainTarget.m_83975_(), currentIntensity, mainTarget.f_83915_, mainTarget.f_83916_); + mainTarget.m_83947_(true); + RenderSystem.viewport((int)0, (int)0, (int)mainTarget.f_83915_, (int)mainTarget.f_83916_); + Blur.renderFullscreen(blurTarget.m_83975_(), 0.0f, mainTarget.f_83915_, mainTarget.f_83916_); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.depthMask((boolean)true); + RenderSystem.enableDepthTest(); + } + + private static boolean shouldRenderStage(RenderStage stage) { + if (APPLY_TO_HUD) { + return stage == RenderStage.HUD; + } + if (APPLY_TO_HAND && Blur.isFirstPerson()) { + return stage == RenderStage.HAND; + } + return stage == RenderStage.WORLD; + } + + private static boolean isFirstPerson() { + Minecraft mc = Minecraft.m_91087_(); + if (mc == null) { + return false; + } + return mc.f_91066_.m_92176_().m_90612_(); + } + + private static void ensureTarget(int width, int height) { + if (blurTarget == null || width != lastWidth || height != lastHeight) { + if (blurTarget != null) { + blurTarget.m_83930_(); + } + blurTarget = new TextureTarget(width, height, false, Minecraft.f_91002_); + lastWidth = width; + lastHeight = height; + } + } + + private static void renderFullscreen(int textureId, float intensity, int width, int height) { + Uniform desatUniform; + Uniform vignetteUniform; + Uniform heartbeatUniform; + Uniform outSizeUniform; + Uniform inSizeUniform; + RenderSystem.setShader(() -> shader); + RenderSystem.setShaderTexture((int)0, (int)textureId); + shader.m_173350_("DiffuseSampler", (Object)textureId); + float clamped = Mth.m_14036_((float)intensity, (float)0.0f, (float)1.0f); + Uniform intensityUniform = shader.m_173348_("Intensity"); + if (intensityUniform != null) { + intensityUniform.m_5985_(clamped); + } + if ((inSizeUniform = shader.m_173348_("InSize")) != null) { + inSizeUniform.m_7971_((float)width, (float)height); + } + if ((outSizeUniform = shader.m_173348_("OutSize")) != null) { + outSizeUniform.m_7971_((float)width, (float)height); + } + if ((heartbeatUniform = shader.m_173348_("Heartbeat")) != null) { + heartbeatUniform.m_5985_(ConcussionAudioEffect.getCurrentHeartbeatVisual()); + } + if ((vignetteUniform = shader.m_173348_("Vignette")) != null) { + vignetteUniform.m_5985_(1.0E-5f); + } + if ((desatUniform = shader.m_173348_("Desaturation")) != null) { + desatUniform.m_5985_(clamped); + } + BufferBuilder builder = Tesselator.m_85913_().m_85915_(); + builder.m_166779_(VertexFormat.Mode.QUADS, DefaultVertexFormat.f_85817_); + builder.m_5483_(-1.0, -1.0, 0.0).m_7421_(0.0f, 1.0f).m_5752_(); + builder.m_5483_(1.0, -1.0, 0.0).m_7421_(1.0f, 1.0f).m_5752_(); + builder.m_5483_(1.0, 1.0, 0.0).m_7421_(1.0f, 0.0f).m_5752_(); + builder.m_5483_(-1.0, 1.0, 0.0).m_7421_(0.0f, 0.0f).m_5752_(); + BufferUploader.m_231202_((BufferBuilder.RenderedBuffer)builder.m_231175_()); + } + + private static float easeOutCubic(float t) { + float inv = 1.0f - t; + return 1.0f - inv * inv * inv; + } + + private static float easeInCubic(float t) { + return t * t * t; + } + + static { + lastWidth = -1; + lastHeight = -1; + currentIntensity = 0.0f; + targetIntensity = 1.0f; + currentDesaturation = 0.0f; + APPLY_TO_HUD = false; + APPLY_TO_HAND = true; + } + + private static enum Phase { + IDLE, + FADE_IN, + HOLD, + FADE_OUT; + + } + + public static enum RenderStage { + WORLD, + HAND, + HUD; + + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/CameraShakeConcussionEffect.java b/src/main/java/com/vinlanx/explosionoverhaul/client/CameraShakeConcussionEffect.java new file mode 100644 index 0000000..37deebd --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/CameraShakeConcussionEffect.java @@ -0,0 +1,124 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.util.Mth; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; + +@OnlyIn(value=Dist.CLIENT) +public class CameraShakeConcussionEffect { + private static final int FADE_IN_TICKS = 40; + private static final int FADE_OUT_TICKS = 40; + private static Phase phase = Phase.IDLE; + private static int ticksInPhase = 0; + private static int holdTicks = 0; + private static float currentIntensity = 0.0f; + private static float targetIntensity = 0.0f; + private static float lastYawOffset = 0.0f; + private static float lastPitchOffset = 0.0f; + + public static boolean isActive() { + return phase != Phase.IDLE; + } + + public static void start(int seconds, float intensity) { + int newHoldTicks = Mth.m_14045_((int)seconds, (int)1, (int)100) * 20; + float newIntensity = Math.max(0.0f, intensity); + if (phase != Phase.IDLE) { + targetIntensity += newIntensity; + holdTicks = Math.min(2000, holdTicks + newHoldTicks); + if (phase == Phase.FADE_OUT) { + phase = Phase.HOLD; + ticksInPhase = 0; + } + } else { + targetIntensity = newIntensity; + holdTicks = newHoldTicks; + ticksInPhase = 0; + phase = Phase.FADE_IN; + currentIntensity = 0.0f; + } + } + + public static void onClientTick() { + Minecraft mc = Minecraft.m_91087_(); + if (mc.m_91104_()) { + return; + } + LocalPlayer player = mc.f_91074_; + if (player == null) { + CameraShakeConcussionEffect.stop(); + return; + } + player.m_19884_((double)(-lastYawOffset), (double)(-lastPitchOffset)); + lastYawOffset = 0.0f; + lastPitchOffset = 0.0f; + if (phase == Phase.IDLE) { + return; + } + ++ticksInPhase; + switch (phase) { + case FADE_IN: { + float t = (float)ticksInPhase / 40.0f; + currentIntensity = CameraShakeConcussionEffect.easeInOutCubic(t) * targetIntensity; + if (ticksInPhase < 40) break; + phase = Phase.HOLD; + ticksInPhase = 0; + break; + } + case HOLD: { + currentIntensity = targetIntensity; + if (ticksInPhase < holdTicks) break; + phase = Phase.FADE_OUT; + ticksInPhase = 0; + break; + } + case FADE_OUT: { + float t = (float)ticksInPhase / 40.0f; + currentIntensity = targetIntensity * CameraShakeConcussionEffect.easeInOutCubic(1.0f - t); + if (ticksInPhase < 40) break; + CameraShakeConcussionEffect.stop(); + return; + } + } + if (currentIntensity > 0.0f) { + CameraShakeConcussionEffect.applySway(player, (float)player.f_19797_ + mc.m_91296_()); + } + } + + private static void applySway(LocalPlayer player, float totalTicks) { + float horizontalSway = Mth.m_14031_((float)(totalTicks * 0.04f)) * 1.5f + Mth.m_14031_((float)(totalTicks * 0.025f)) * 1.0f; + float verticalSway = Mth.m_14089_((float)(totalTicks * 0.035f)) * 0.8f + Mth.m_14031_((float)(totalTicks * 0.015f)) * 0.5f; + float yawChange = horizontalSway * currentIntensity * 50.0f; + float pitchChange = verticalSway * currentIntensity * 30.0f; + player.m_19884_((double)yawChange, (double)pitchChange); + lastYawOffset = yawChange; + lastPitchOffset = pitchChange; + } + + public static void stop() { + phase = Phase.IDLE; + ticksInPhase = 0; + holdTicks = 0; + currentIntensity = 0.0f; + targetIntensity = 0.0f; + lastYawOffset = 0.0f; + lastPitchOffset = 0.0f; + } + + private static float easeInOutCubic(float t) { + return t < 0.5f ? 4.0f * t * t * t : 1.0f - (float)Math.pow(-2.0f * t + 2.0f, 3.0) / 2.0f; + } + + private static enum Phase { + IDLE, + FADE_IN, + HOLD, + FADE_OUT; + + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/ClientEffects.java b/src/main/java/com/vinlanx/explosionoverhaul/client/ClientEffects.java new file mode 100644 index 0000000..59770e5 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/ClientEffects.java @@ -0,0 +1,481 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.vinlanx.explosionoverhaul.Config; +import com.vinlanx.explosionoverhaul.ModParticles; +import com.vinlanx.explosionoverhaul.PlayTrackedSoundPacket; +import com.vinlanx.explosionoverhaul.client.Blur; +import com.vinlanx.explosionoverhaul.client.CameraShakeConcussionEffect; +import com.vinlanx.explosionoverhaul.client.ExplosionWindController; +import com.vinlanx.explosionoverhaul.client.GroundDustEffect; +import com.vinlanx.explosionoverhaul.client.GroundMistEffect; +import com.vinlanx.explosionoverhaul.client.PhysicsBasedExplosionEffect; +import com.vinlanx.explosionoverhaul.client.PositionalSoundInstance; +import com.vinlanx.explosionoverhaul.client.ShockwaveEffect; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Random; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.BlockParticleOption; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.core.particles.SimpleParticleType; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; +import net.neoforged.neoforge.client.event.RenderGuiOverlayEvent; +import net.neoforged.neoforge.registries.ForgeRegistries; + +public class ClientEffects { + private static float currentShakeIntensity = 0.0f; + private static int shakeDurationTicks = 0; + private static float currentPushIntensity = 0.0f; + private static float lastYawOffset = 0.0f; + private static float lastPitchOffset = 0.0f; + private static final Random random = new Random(); + private static final List activeExplosions = new ArrayList(); + private static final List activeTrackedSounds = new ArrayList(); + private static final List activeShockwaves = new ArrayList(); + private static final List activeDustClouds = new ArrayList(); + private static final List activeMistClouds = new ArrayList(); + private static final List activeFlashEffects = new ArrayList(); + private static final List pendingShakes = new ArrayList(); + + public static void addTrackedSound(PlayTrackedSoundPacket msg) { + SoundEvent sound = (SoundEvent)ForgeRegistries.SOUND_EVENTS.getValue(msg.getSoundId()); + if (sound != null) { + activeTrackedSounds.add(new TrackedSound(msg.getExplosionPos(), sound, msg.getVolume(), msg.getPitch(), msg.getDelayTicks(), msg.isPlayerInHouse())); + } + } + + private static Vec3 calculateSoundPosition(Player player, Vec3 explosionPos, boolean isPlayerInHouse) { + float FIXED_DISTANCE = 45.0f; + Vec3 playerPos = player.m_146892_(); + Vec3 startPos = isPlayerInHouse ? explosionPos : playerPos; + Vec3 endPos = isPlayerInHouse ? playerPos : explosionPos; + ClipContext context = new ClipContext(startPos, endPos, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, (Entity)player); + BlockHitResult hitResult = player.m_9236_().m_45547_(context); + if (hitResult.m_6662_() == HitResult.Type.MISS) { + Vec3 direction = explosionPos.m_82546_(playerPos).m_82541_(); + if (direction.m_82556_() < 0.001) { + direction = player.m_20154_(); + } + return playerPos.m_82549_(direction.m_82490_(45.0)); + } + Vec3 hitPos = hitResult.m_82450_(); + Vec3 rayDir = endPos.m_82546_(startPos).m_82541_(); + return hitPos.m_82546_(rayDir.m_82490_(0.1)); + } + + private static void handleTrackedSoundsTick() { + Minecraft mc = Minecraft.m_91087_(); + if (mc.f_91074_ == null || mc.m_91106_() == null) { + return; + } + Iterator iterator = activeTrackedSounds.iterator(); + while (iterator.hasNext()) { + TrackedSound tracked = iterator.next(); + if (tracked.isFinished()) { + iterator.remove(); + continue; + } + tracked.tick((Player)mc.f_91074_, mc.m_91106_(), mc.f_91074_.m_217043_()); + } + } + + public static void triggerLocalCameraShake(float intensity, int durationTicks, float pushIntensity) { + if (!((Boolean)Config.CLIENT.enableCameraShake.get()).booleanValue()) { + return; + } + float amplifiedIntensity = intensity * (((Double)Config.CLIENT.cameraShakeAmplifier.get()).floatValue() * 10.0f); + float amplifiedPush = 0.0f; + if (((Boolean)Config.COMMON.enablePlayerShake.get()).booleanValue()) { + amplifiedPush = pushIntensity * (((Double)Config.COMMON.playerShakeAmplifier.get()).floatValue() * 5.0f); + } + if (amplifiedIntensity > currentShakeIntensity || shakeDurationTicks == 0 || durationTicks > shakeDurationTicks) { + currentShakeIntensity = amplifiedIntensity; + shakeDurationTicks = durationTicks; + currentPushIntensity = amplifiedPush; + } + } + + public static void triggerDelayedCameraShake(float intensity, int durationTicks, float pushIntensity, int delayTicks) { + if (!((Boolean)Config.CLIENT.enableCameraShake.get()).booleanValue()) { + return; + } + if (delayTicks <= 0) { + ClientEffects.triggerLocalCameraShake(intensity, durationTicks, pushIntensity); + return; + } + pendingShakes.add(new PendingShake(delayTicks, intensity, durationTicks, pushIntensity)); + } + + public static void triggerRealisticExplosion(Vec3 position, float power) { + activeExplosions.add(new PhysicsBasedExplosionEffect(position, power)); + } + + public static void addFlashEffect(Vec3 explosionPos, float power) { + activeFlashEffects.add(new FlashEffect(explosionPos, power)); + } + + public static void onClientTick() { + if (Minecraft.m_91087_().m_91104_()) { + return; + } + Blur.onClientTick(); + CameraShakeConcussionEffect.onClientTick(); + ExplosionWindController.tick(); + ClientEffects.handleCameraShakeTick(); + ClientEffects.handlePendingShakesTick(); + ClientEffects.handleTrackedSoundsTick(); + activeExplosions.removeIf(effect -> { + effect.tick(); + return effect.isFinished(); + }); + activeShockwaves.removeIf(effect -> { + effect.tick(); + return effect.isFinished(); + }); + activeDustClouds.removeIf(effect -> { + effect.tick(); + return effect.isFinished(); + }); + activeMistClouds.removeIf(effect -> { + effect.tick(); + return effect.isFinished(); + }); + activeFlashEffects.removeIf(effect -> effect.isFinished()); + } + + public static void renderFlash(RenderGuiOverlayEvent.Post event) { + if (!((Boolean)Config.CLIENT.enableFlashEffect.get()).booleanValue()) { + return; + } + Minecraft mc = Minecraft.m_91087_(); + if (mc.f_91074_ == null || activeFlashEffects.isEmpty()) { + return; + } + float maxOpacity = 0.0f; + for (FlashEffect effect : activeFlashEffects) { + float opacity = effect.getCurrentOpacity((Player)mc.f_91074_); + if (!(opacity > maxOpacity)) continue; + maxOpacity = opacity; + } + if (maxOpacity <= 0.0f) { + return; + } + GuiGraphics guiGraphics = event.getGuiGraphics(); + int screenWidth = mc.m_91268_().m_85445_(); + int screenHeight = mc.m_91268_().m_85446_(); + ResourceLocation flashTexture = ResourceLocation.fromNamespaceAndPath((String)"explosionoverhaul", (String)"textures/effects/flash.png"); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.setShaderColor((float)1.0f, (float)1.0f, (float)1.0f, (float)maxOpacity); + guiGraphics.m_280163_(flashTexture, 0, 0, 0.0f, 0.0f, screenWidth, screenHeight, screenWidth, screenHeight); + RenderSystem.disableBlend(); + RenderSystem.setShaderColor((float)1.0f, (float)1.0f, (float)1.0f, (float)1.0f); + } + + private static void handlePendingShakesTick() { + if (pendingShakes.isEmpty()) { + return; + } + Iterator it = pendingShakes.iterator(); + while (it.hasNext()) { + PendingShake ps = it.next(); + --ps.delayTicks; + if (ps.delayTicks > 0) continue; + ClientEffects.triggerLocalCameraShake(ps.intensity, ps.durationTicks, ps.pushIntensity); + it.remove(); + } + } + + public static void triggerShockwave(Vec3 position, float power) { + activeShockwaves.add(new ShockwaveEffect(position, power)); + } + + public static void triggerDustCloud(Vec3 position, float power) { + if (!((Boolean)Config.CLIENT.enableGroundDustEffect.get()).booleanValue()) { + return; + } + activeDustClouds.add(new GroundDustEffect(position, power)); + } + + public static void triggerMistCloud(Vec3 position, float power) { + if (!((Boolean)Config.CLIENT.enableGroundMistEffect.get()).booleanValue()) { + return; + } + activeMistClouds.add(new GroundMistEffect(position, power)); + } + + public static void triggerAmbientCaveDust(float power) { + int i; + Minecraft mc = Minecraft.m_91087_(); + LocalPlayer player = mc.f_91074_; + ClientLevel level = mc.f_91073_; + if (player == null || level == null) { + return; + } + int particleCount = 15 + (int)((double)(power / 10.0f) * 3.5); + particleCount = Mth.m_14045_((int)particleCount, (int)10, (int)70); + BlockPos playerPos = player.m_20183_(); + BlockState ceilingState = Blocks.f_50069_.m_49966_(); + for (i = 3; i < 10; ++i) { + BlockState state = level.m_8055_(playerPos.m_6630_(i)); + if (state.m_60795_()) continue; + ceilingState = state; + break; + } + for (i = 0; i < particleCount; ++i) { + double x = player.m_20185_() + (random.nextDouble() - 0.5) * 16.0; + double z = player.m_20189_() + (random.nextDouble() - 0.5) * 16.0; + double y = player.m_20186_() + 4.0 + random.nextDouble() * 6.0; + level.m_7106_((ParticleOptions)new BlockParticleOption(ParticleTypes.f_123814_, ceilingState), x, y, z, 0.0, -0.15, 0.0); + } + } + + private static void handleCameraShakeTick() { + Minecraft mc = Minecraft.m_91087_(); + LocalPlayer player = mc.f_91074_; + if (player == null) { + if (shakeDurationTicks > 0 || lastYawOffset != 0.0f || lastPitchOffset != 0.0f) { + lastYawOffset = 0.0f; + lastPitchOffset = 0.0f; + shakeDurationTicks = 0; + currentShakeIntensity = 0.0f; + currentPushIntensity = 0.0f; + } + return; + } + player.m_19884_((double)(-lastYawOffset), (double)(-lastPitchOffset)); + lastYawOffset = 0.0f; + lastPitchOffset = 0.0f; + if (shakeDurationTicks > 0) { + float progress = (float)shakeDurationTicks / 30.0f; + float cameraIntensity = currentShakeIntensity * Mth.m_14031_((float)(progress * (float)Math.PI)); + float yawChange = (random.nextFloat() - 0.5f) * 2.0f * cameraIntensity; + float pitchChange = (random.nextFloat() - 0.5f) * 1.0f * cameraIntensity; + player.m_19884_((double)yawChange, (double)pitchChange); + lastYawOffset = yawChange; + lastPitchOffset = pitchChange; + if (currentPushIntensity > 0.0f) { + float pushFactor = currentPushIntensity * Mth.m_14031_((float)(progress * (float)Math.PI)) * 0.1f; + player.m_5997_((random.nextDouble() - 0.5) * (double)pushFactor, 0.0, (random.nextDouble() - 0.5) * (double)pushFactor); + } + --shakeDurationTicks; + } else { + currentShakeIntensity = 0.0f; + currentPushIntensity = 0.0f; + } + } + + public static void triggerLineSparks(Vec3 position, float power) { + if (!((Boolean)Config.CLIENT.enableLineSparks.get()).booleanValue()) { + return; + } + Minecraft mc = Minecraft.m_91087_(); + ClientLevel level = mc.f_91073_; + if (level == null) { + return; + } + double amountMultiplier = (Double)Config.CLIENT.lineSparkAmountMultiplier.get(); + if (amountMultiplier <= 0.0) { + return; + } + int sparkCount = (int)((double)(power * 15.0f) * amountMultiplier); + sparkCount = Mth.m_14045_((int)sparkCount, (int)15, (int)500); + for (int i = 0; i < sparkCount; ++i) { + Vec3 motion = new Vec3(random.nextDouble() - 0.5, random.nextDouble() - 0.5, random.nextDouble() - 0.5).m_82541_(); + float powerFraction = power / 100.0f; + float force = random.nextFloat() < 0.25f ? Mth.m_14179_((float)powerFraction, (float)0.5f, (float)8.0f) * (0.9f + random.nextFloat() * 0.4f) : Mth.m_14179_((float)powerFraction, (float)0.3f, (float)4.5f) * (0.7f + random.nextFloat() * 0.4f); + motion = motion.m_82490_((double)force); + level.m_7106_((ParticleOptions)((SimpleParticleType)ModParticles.LINE_SPARK.get()), position.f_82479_, position.f_82480_, position.f_82481_, motion.f_82479_, motion.f_82480_, motion.f_82481_); + } + } + + private static class TrackedSound { + final Vec3 explosionPos; + final SoundEvent sound; + final float volume; + final float pitch; + long delayTicks; + PositionalSoundInstance soundInstance; + boolean started = false; + private int updateCooldown = 0; + private final boolean isPlayerInHouse; + + TrackedSound(Vec3 explosionPos, SoundEvent sound, float volume, float pitch, long delayTicks, boolean isPlayerInHouse) { + this.explosionPos = explosionPos; + this.sound = sound; + this.volume = volume; + this.pitch = pitch; + this.delayTicks = delayTicks; + this.isPlayerInHouse = isPlayerInHouse; + } + + public void tick(Player player, SoundManager soundManager, RandomSource random) { + if (this.soundInstance != null && this.soundInstance.m_7801_()) { + return; + } + if (!this.started) { + --this.delayTicks; + if (this.delayTicks <= 0L) { + Vec3 soundPos = ClientEffects.calculateSoundPosition(player, this.explosionPos, this.isPlayerInHouse); + this.soundInstance = new PositionalSoundInstance(this.sound, SoundSource.BLOCKS, this.volume, this.pitch, random, soundPos.f_82479_, soundPos.f_82480_, soundPos.f_82481_); + soundManager.m_120367_((SoundInstance)this.soundInstance); + this.started = true; + } + } else { + --this.updateCooldown; + if (this.updateCooldown <= 0) { + this.updateCooldown = 10; + Vec3 newSoundPos = ClientEffects.calculateSoundPosition(player, this.explosionPos, this.isPlayerInHouse); + this.soundInstance.updatePosition(newSoundPos); + } + } + } + + public boolean isFinished() { + return this.soundInstance != null && this.soundInstance.m_7801_(); + } + } + + private static class PendingShake { + int delayTicks; + final float intensity; + final int durationTicks; + final float pushIntensity; + + PendingShake(int delayTicks, float intensity, int durationTicks, float pushIntensity) { + this.delayTicks = delayTicks; + this.intensity = intensity; + this.durationTicks = durationTicks; + this.pushIntensity = pushIntensity; + } + } + + private static class FlashEffect { + final Vec3 explosionPos; + final float power; + final long startTime; + final float maxDurationTicks; + final float maxOpacity; + final float maxDistance; + + FlashEffect(Vec3 explosionPos, float power) { + this.explosionPos = explosionPos; + this.power = power; + this.startTime = System.currentTimeMillis(); + this.maxDurationTicks = this.calculateDuration(power) * 20.0f; + this.maxOpacity = this.calculateMaxOpacity(power); + this.maxDistance = this.calculateMaxDistance(power); + } + + private float calculateDuration(float power) { + if (power <= 1.0f) { + return 0.5f; + } + if (power <= 5.0f) { + return 1.0f; + } + if (power <= 10.0f) { + return 2.5f; + } + if (power <= 25.0f) { + return 3.5f; + } + return 5.5f; + } + + private float calculateMaxDistance(float power) { + if (power <= 1.0f) { + return 30.0f; + } + if (power <= 5.0f) { + return 30.0f + (power - 1.0f) * 70.0f / 4.0f; + } + if (power <= 10.0f) { + return 100.0f + (power - 5.0f) * 100.0f / 5.0f; + } + if (power <= 25.0f) { + return 200.0f + (power - 10.0f) * 200.0f / 15.0f; + } + if (power <= 40.0f) { + return 400.0f + (power - 25.0f) * 300.0f / 15.0f; + } + return 700.0f + (power - 40.0f) * 50.0f; + } + + private float calculateMaxOpacity(float power) { + float baseOpacity = power <= 1.0f ? 0.5f : (power <= 5.0f ? 0.7f : (power <= 10.0f ? 0.9f : 1.0f)); + return baseOpacity * ((Double)Config.CLIENT.flashMaxOpacity.get()).floatValue(); + } + + public float getCurrentOpacity(Player player) { + long elapsed = System.currentTimeMillis() - this.startTime; + float elapsedTicks = (float)elapsed / 50.0f; + if (elapsedTicks > this.maxDurationTicks) { + return 0.0f; + } + float progress = elapsedTicks / this.maxDurationTicks; + float fadeOpacity = this.maxOpacity * (1.0f - progress * progress); + double distance = player.m_146892_().m_82554_(this.explosionPos); + float distanceFactor = Math.max(0.0f, 1.0f - (float)distance / this.maxDistance); + Vec3 viewVec = player.m_20154_(); + Vec3 dirToExplosion = this.explosionPos.m_82546_(player.m_146892_()).m_82541_(); + float dot = (float)viewVec.m_82526_(dirToExplosion); + float angleFactor = Math.max(0.0f, dot); + if (!this.isVisible(player, this.explosionPos)) { + return 0.0f; + } + return fadeOpacity * distanceFactor * angleFactor; + } + + private boolean isVisible(Player player, Vec3 explosionPos) { + Vec3 start = player.m_146892_(); + Vec3 end = explosionPos; + ClipContext context = new ClipContext(start, end, ClipContext.Block.VISUAL, ClipContext.Fluid.NONE, (Entity)player); + BlockHitResult hit = player.m_9236_().m_45547_(context); + if (hit.m_6662_() == HitResult.Type.MISS) { + return true; + } + if (this.power > 10.0f) { + int numChecks = Math.max(1, (int)(this.power / 10.0f)); + for (int i = 1; i <= numChecks; ++i) { + Vec3 elevatedStart = start.m_82520_(0.0, (double)(5 * i), 0.0); + Vec3 elevatedEnd = end.m_82520_(0.0, (double)(5 * i), 0.0); + ClipContext elevatedContext = new ClipContext(elevatedStart, elevatedEnd, ClipContext.Block.VISUAL, ClipContext.Fluid.NONE, (Entity)player); + BlockHitResult elevatedHit = player.m_9236_().m_45547_(elevatedContext); + if (elevatedHit.m_6662_() != HitResult.Type.MISS) continue; + return true; + } + } + return false; + } + + public boolean isFinished() { + long elapsed = System.currentTimeMillis() - this.startTime; + return (float)elapsed / 50.0f > this.maxDurationTicks; + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/ConcussionAudioEffect.java b/src/main/java/com/vinlanx/explosionoverhaul/client/ConcussionAudioEffect.java new file mode 100644 index 0000000..03d743c --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/ConcussionAudioEffect.java @@ -0,0 +1,663 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.vinlanx.explosionoverhaul.Config; +import com.vinlanx.explosionoverhaul.ModSounds; +import com.vinlanx.explosionoverhaul.client.Blur; +import com.vinlanx.explosionoverhaul.client.CameraShakeConcussionEffect; +import com.vinlanx.explosionoverhaul.client.DeafnessConcussionEffect; +import com.vinlanx.explosionoverhaul.client.LowPassConcussionEffect; +import java.util.concurrent.ThreadLocalRandom; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundEvent; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.neoforge.event.TickEvent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.loading.FMLEnvironment; + +@Mod.EventBusSubscriber(modid="explosionoverhaul", value={Dist.CLIENT}) +public class ConcussionAudioEffect { + public static boolean debugSendDebugMessage = false; + public static boolean TestingHudHeart = true; + public static float currentBPM = 23.3f; + private static double heartbeatCycleTimer = 0.0; + private static float heartbeatVisualPulse = 0.0f; + private static float explosionBPMMod = 0.0f; + private static float jumpBPMMod = 0.0f; + private static boolean wasOnGround = true; + private static int idleTicks = 0; + private static boolean lubTriggered = false; + private static boolean dubTriggered = false; + + @SubscribeEvent + public static void onClientTick(TickEvent.ClientTickEvent event) { + if (event.phase == TickEvent.Phase.END) { + Minecraft mc = Minecraft.m_91087_(); + if (mc.f_91074_ != null && !mc.f_91074_.m_6084_()) { + ConcussionAudioEffect.stopAll(); + } + } + } + + public static void stopAll() { + Blur.stop(); + DeafnessConcussionEffect.stop(); + LowPassConcussionEffect.stop(); + CameraShakeConcussionEffect.stop(); + } + + public static void start(float power, double distance, boolean hasDirectLineOfSight, boolean explosionInCave) { + LocalPlayer player; + LocalPlayer player2; + LocalPlayer player3; + if (!FMLEnvironment.dist.isClient()) { + return; + } + if (!((Boolean)Config.CLIENT.enableConcussion.get()).booleanValue()) { + return; + } + Minecraft mc = Minecraft.m_91087_(); + if (mc == null || mc.f_91073_ == null || mc.f_91074_ == null) { + return; + } + double rawPercent = ConcussionAudioEffect.computePercent(power, distance, explosionInCave); + if (explosionInCave) { + rawPercent = Math.min(100.0, rawPercent * 1.5); + } + double effectivePercent = hasDirectLineOfSight ? rawPercent : ConcussionAudioEffect.applyOcclusion(rawPercent); + double maxDistance = ConcussionAudioEffect.computeMaxDistance(power, explosionInCave); + if (rawPercent <= 0.0) { + LocalPlayer player4 = mc.f_91074_; + if (player4 != null && debugSendDebugMessage) { + 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.m_237113_((String)outMessage).m_130940_(ChatFormatting.GRAY), false); + } + return; + } + double normalized = Math.max(0.0, Math.min(1.0, effectivePercent / 100.0)); + float intensity = (float)normalized; + if (intensity < 0.01f) { + return; + } + double baseSilentSeconds = ConcussionAudioEffect.computeBaseSilentSeconds(effectivePercent, explosionInCave); + double intensityPercent = ConcussionAudioEffect.computeBaseIntensityPercent(effectivePercent); + double multiplier = ConcussionAudioEffect.computePowerMultiplier(power); + double finalSilentSeconds = baseSilentSeconds * multiplier * (Double)Config.CLIENT.concussionDurationMultiplier.get(); + double lowpassChance = ConcussionAudioEffect.computeLowpassPowerChance(power, explosionInCave) * (Double)Config.CLIENT.concussionChanceMultiplier.get() * (Double)Config.CLIENT.lowPassChanceMultiplier.get(); + boolean lowpassRoll = ThreadLocalRandom.current().nextDouble() <= lowpassChance; + double chance = ConcussionAudioEffect.computePowerChance(power, explosionInCave) * (Double)Config.CLIENT.concussionChanceMultiplier.get() * (Double)Config.CLIENT.deafnessChanceMultiplier.get(); + boolean roll = ThreadLocalRandom.current().nextDouble() <= chance; + boolean anyAudioEffectActive = roll || lowpassRoll; + double baseBlurSeconds = ConcussionAudioEffect.computeBaseBlurSilentSeconds(effectivePercent, explosionInCave); + double blurMultiplier = ConcussionAudioEffect.computeBlurPowerMultiplier(power); + double finalBlurSeconds = baseBlurSeconds * blurMultiplier * (Double)Config.CLIENT.concussionDurationMultiplier.get(); + boolean lowpassReduced = false; + if (!lowpassRoll) { + finalBlurSeconds = roll ? finalSilentSeconds : (finalBlurSeconds /= 3.0); + lowpassReduced = true; + } + int blurSeconds = Math.max(1, (int)Math.round(finalBlurSeconds)); + double blurIntensityPercent = ConcussionAudioEffect.computeBaseBlurIntensityPercent(effectivePercent); + float blurIntensity = (float)(blurIntensityPercent / 100.0); + double swayIntensityPercent = ConcussionAudioEffect.computeBaseSwayIntensityPercent(effectivePercent) * (Double)Config.CLIENT.cameraSwayIntensity.get(); + float swayIntensity = (float)(swayIntensityPercent / 100.0); + if (rawPercent > 0.0 && blurIntensity >= 0.01f && anyAudioEffectActive) { + float addedBPM = 0.0f; + if (rawPercent > 80.0) { + addedBPM = 60.0f; + } else if (rawPercent > 60.0) { + addedBPM = 40.0f; + } else if (rawPercent > 30.0) { + addedBPM = 20.0f; + } + explosionBPMMod = Math.min(200.0f, explosionBPMMod + addedBPM); + try { + LocalPlayer player5; + Blur.start(blurSeconds, blurIntensity); + if (((Boolean)Config.CLIENT.enableCameraSway.get()).booleanValue()) { + CameraShakeConcussionEffect.start(blurSeconds, swayIntensity); + } + if (debugSendDebugMessage && (player5 = mc.f_91074_) != 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.m_237113_((String)blurMsg).m_130940_(ChatFormatting.BLUE), false); + } + } + catch (Throwable player5) {} + } else if (debugSendDebugMessage && (player3 = mc.f_91074_) != 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.m_237113_((String)blurMsg).m_130940_(ChatFormatting.GRAY), false); + } + int lowpassSeconds = blurSeconds; + double lowpassIntensityPercent = ConcussionAudioEffect.computeBaseLowpassIntensityPercent(effectivePercent); + float lowpassIntensity = (float)(lowpassIntensityPercent / 100.0); + if (lowpassIntensity < 0.01f) { + lowpassIntensity = 0.01f; + } + String lpVisibility = hasDirectLineOfSight ? "\u043f\u0440\u044f\u043c\u0430 \u0432\u0438\u0434\u0438\u043c\u0456\u0441\u0442\u044c" : "\u043f\u0435\u0440\u0435\u0448\u043a\u043e\u0434\u0430"; + int lowpassIntensityRound = (int)Math.round(lowpassIntensityPercent); + if (((Boolean)Config.CLIENT.enableLowPass.get()).booleanValue() && rawPercent > 0.0 && lowpassIntensity >= 0.01f && (lowpassRoll || LowPassConcussionEffect.isActive())) { + try { + LocalPlayer player6; + float finalLpIntensity = lowpassRoll ? lowpassIntensity : 0.0f; + int finalLpRound = lowpassRoll ? lowpassIntensityRound : 0; + LowPassConcussionEffect.start(lowpassSeconds, finalLpIntensity, effectivePercent, lpVisibility, finalLpRound); + if (debugSendDebugMessage && (player6 = mc.f_91074_) != 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.m_237113_((String)lpMsg).m_130940_(ChatFormatting.DARK_GREEN), false); + } + } + catch (Throwable finalLpIntensity) {} + } else if (debugSendDebugMessage && (player2 = mc.f_91074_) != 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.m_237113_((String)lpMsg).m_130940_(ChatFormatting.GRAY), false); + } + if (debugSendDebugMessage) { + ConcussionAudioEffect.sendDebugMessage(mc, effectivePercent, rawPercent, hasDirectLineOfSight, distance, maxDistance); + } + if (debugSendDebugMessage && (player = mc.f_91074_) != null) { + 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.m_237113_((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.m_237113_((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.m_237113_((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.m_237113_((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.m_237113_((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.m_237113_((String)deafnessMsg).m_130940_(ChatFormatting.GRAY), false); + } + } + if (!roll) { + return; + } + if (!((Boolean)Config.CLIENT.enableDeafness.get()).booleanValue()) { + return; + } + int intensityRound = (int)Math.round(intensityPercent); + 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"; + float intensityFromIntensityPercent = (float)(intensityPercent / 100.0); + DeafnessConcussionEffect.start(intensityFromIntensityPercent, (float)finalSilentSeconds, effectivePercent, visibility, intensityRound); + } + + private static double computePercent(float power, double distance, boolean explosionInCave) { + double maxDistance = ConcussionAudioEffect.computeMaxDistance(power, explosionInCave); + if (maxDistance <= 0.0) { + return 0.0; + } + double normalized = 1.0 - Math.max(0.0, distance) / maxDistance; + return Math.max(0.0, Math.min(1.0, normalized)) * 100.0; + } + + private static double computeMaxDistance(float power, boolean explosionInCave) { + double[][] points = explosionInCave ? new double[][]{{1.0, 5.0}, {3.0, 10.0}, {10.0, 50.0}, {25.0, 90.0}, {50.0, 150.0}, {80.0, 200.0}, {120.0, 200.0}} : new double[][]{{1.0, 2.0}, {3.0, 5.0}, {10.0, 30.0}, {25.0, 70.0}, {50.0, 100.0}, {80.0, 150.0}, {120.0, 200.0}}; + double clampedPower = Math.max(points[0][0], Math.min(points[points.length - 1][0], (double)power)); + for (int i = 1; i < points.length; ++i) { + double lowerP = points[i - 1][0]; + double upperP = points[i][0]; + if (!(clampedPower <= upperP)) continue; + double lowerD = points[i - 1][1]; + double upperD = points[i][1]; + double t = (clampedPower - lowerP) / (upperP - lowerP); + return lowerD + (upperD - lowerD) * t; + } + return points[points.length - 1][1]; + } + + private static double applyOcclusion(double percent) { + if (percent >= 80.0) { + return percent / 1.2; + } + if (percent >= 60.0) { + return percent / 1.4; + } + if (percent >= 40.0) { + return percent / 1.6; + } + if (percent >= 20.0) { + return percent / 3.0; + } + if (percent >= 1.0) { + return 0.0; + } + return 0.0; + } + + private static void sendDebugMessage(Minecraft mc, double effectivePercent, double rawPercent, boolean hasDirectLineOfSight, double distance, double maxDistance) { + LocalPlayer player = mc.f_91074_; + if (player == null) { + return; + } + double clamped = Math.max(0.0, Math.min(100.0, effectivePercent)); + if (rawPercent <= 0.0) { + 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.m_237113_((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.m_237113_((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.m_237113_((String)rawMessage).m_130940_(ChatFormatting.GRAY), false); + } + } + + private static ChatFormatting pickColor(double percent) { + if (percent >= 80.0) { + return ChatFormatting.RED; + } + if (percent >= 60.0) { + return ChatFormatting.GOLD; + } + if (percent >= 40.0) { + return ChatFormatting.YELLOW; + } + if (percent >= 20.0) { + return ChatFormatting.AQUA; + } + if (percent > 0.0) { + return ChatFormatting.BLUE; + } + return ChatFormatting.GRAY; + } + + private static double computeBaseSilentSeconds(double effectivePercent, boolean explosionInCave) { + if (!explosionInCave) { + if (effectivePercent <= 40.0) { + return 0.0; + } + if (effectivePercent > 80.0) { + double t = (effectivePercent - 80.0) / 20.0; + return 4.0 + 1.0 * t; + } + if (effectivePercent > 60.0) { + double t = (effectivePercent - 60.0) / 20.0; + return 2.0 + 2.0 * t; + } + double t = (effectivePercent - 40.0) / 20.0; + return 1.0 + 1.0 * t; + } + if (effectivePercent <= 20.0) { + return 0.0; + } + if (effectivePercent > 80.0) { + double t = (effectivePercent - 80.0) / 20.0; + return 7.0 + 3.0 * t; + } + if (effectivePercent > 60.0) { + double t = (effectivePercent - 60.0) / 20.0; + return 4.0 + 1.0 * t; + } + double t = (effectivePercent - 20.0) / 40.0; + if (effectivePercent <= 40.0) { + double tt = (effectivePercent - 20.0) / 20.0; + return 2.0 + 1.0 * tt; + } + double tt = (effectivePercent - 40.0) / 20.0; + return 2.0 + 1.0 * tt; + } + + private static double computeBaseIntensityPercent(double effectivePercent) { + if (effectivePercent <= 60.0) { + return 0.0; + } + if (effectivePercent <= 70.0) { + double t = (effectivePercent - 60.0) / 10.0; + return 0.0 + 60.0 * t; + } + if (effectivePercent <= 85.0) { + double t = (effectivePercent - 70.0) / 15.0; + return 60.0 + 20.0 * t; + } + if (effectivePercent <= 90.0) { + double t = (effectivePercent - 85.0) / 5.0; + return 80.0 + 20.0 * t; + } + return 100.0; + } + + private static double computePowerMultiplier(double power) { + double[][] points = new double[][]{{2.0, 1.0}, {5.0, 1.2}, {6.0, 1.4}, {12.0, 1.8}, {13.0, 2.0}, {22.0, 2.3}, {23.0, 2.7}, {50.0, 3.0}, {51.0, 3.2}, {80.0, 5.0}, {120.0, 7.0}}; + double clamped = Math.max(points[0][0], Math.min(points[points.length - 1][0], power)); + for (int i = 1; i < points.length; ++i) { + double lowerP = points[i - 1][0]; + double upperP = points[i][0]; + if (!(clamped <= upperP)) continue; + double lowerM = points[i - 1][1]; + double upperM = points[i][1]; + double t = (clamped - lowerP) / (upperP - lowerP); + return lowerM + (upperM - lowerM) * t; + } + return points[points.length - 1][1]; + } + + private static double computePowerChance(double power, boolean explosionInCave) { + double[][] points = explosionInCave ? new double[][]{{1.0, 0.25}, {2.0, 0.3}, {3.0, 0.35}, {5.0, 0.4}, {6.0, 0.5}, {10.0, 0.75}, {15.0, 0.9}, {20.0, 1.0}, {120.0, 1.0}} : new double[][]{{1.0, 0.15}, {2.0, 0.15}, {3.0, 0.175}, {5.0, 0.215}, {6.0, 0.225}, {10.0, 0.225}, {11.0, 0.35}, {25.0, 0.4}, {26.0, 0.5}, {34.0, 0.75}, {42.0, 0.9}, {50.0, 1.0}, {120.0, 1.0}}; + double clamped = Math.max(points[0][0], Math.min(points[points.length - 1][0], power)); + for (int i = 1; i < points.length; ++i) { + double lowerP = points[i - 1][0]; + double upperP = points[i][0]; + if (!(clamped <= upperP)) continue; + double lowerC = points[i - 1][1]; + double upperC = points[i][1]; + double t = (clamped - lowerP) / (upperP - lowerP); + return lowerC + (upperC - lowerC) * t; + } + return 1.0; + } + + private static double computeBaseBlurSilentSeconds(double effectivePercent, boolean explosionInCave) { + if (!explosionInCave) { + if (effectivePercent <= 40.0) { + return 0.0; + } + if (effectivePercent > 80.0) { + double t = (effectivePercent - 80.0) / 20.0; + return 6.0 + 2.0 * t; + } + if (effectivePercent > 60.0) { + double t = (effectivePercent - 60.0) / 20.0; + return 2.0 + 4.0 * t; + } + double t = (effectivePercent - 40.0) / 20.0; + return 0.0 + 2.0 * t; + } + if (effectivePercent <= 20.0) { + return 0.0; + } + if (effectivePercent > 80.0) { + double t = (effectivePercent - 80.0) / 20.0; + return 12.0 + 6.0 * t; + } + if (effectivePercent > 60.0) { + double t = (effectivePercent - 60.0) / 20.0; + return 6.0 + 2.0 * t; + } + if (effectivePercent <= 40.0) { + double tt = (effectivePercent - 20.0) / 20.0; + return 2.0 + 2.0 * Math.max(0.0, Math.min(1.0, tt)); + } + double tt = (effectivePercent - 40.0) / 20.0; + return 2.0 + 2.0 * Math.max(0.0, Math.min(1.0, tt)); + } + + private static double computeBaseBlurIntensityPercent(double effectivePercent) { + if (effectivePercent < 60.0) { + return 0.0; + } + double t = (effectivePercent - 60.0) / 40.0; + return 1.0 + 49.0 * t; + } + + private static double computeBaseSwayIntensityPercent(double effectivePercent) { + if (effectivePercent < 50.0) { + return 0.0; + } + double t = (effectivePercent - 50.0) / 50.0; + return 100.0 * t; + } + + private static double computeBlurPowerMultiplier(double power) { + double[][] points = new double[][]{{2.0, 1.0}, {5.0, 1.2}, {6.0, 1.4}, {12.0, 1.8}, {13.0, 2.0}, {22.0, 2.3}, {23.0, 2.7}, {50.0, 3.0}, {51.0, 3.2}, {80.0, 5.0}, {120.0, 7.0}}; + double clamped = Math.max(points[0][0], Math.min(points[points.length - 1][0], power)); + for (int i = 1; i < points.length; ++i) { + double lowerP = points[i - 1][0]; + double upperP = points[i][0]; + if (!(clamped <= upperP)) continue; + double lowerM = points[i - 1][1]; + double upperM = points[i][1]; + double t = (clamped - lowerP) / (upperP - lowerP); + return lowerM + (upperM - lowerM) * t; + } + return points[points.length - 1][1]; + } + + public static void renderHeartbeatHUD(GuiGraphics ctx) { + if (!((Boolean)Config.CLIENT.showHeartbeatHUD.get()).booleanValue() || !Blur.isActive()) { + return; + } + Minecraft mc = Minecraft.m_91087_(); + if (mc.f_91074_ == null) { + return; + } + float bps = currentBPM / 60.0f; + String text = String.format("%.2f bps (%.1f BPM)", Float.valueOf(bps), Float.valueOf(currentBPM)); + int x = ctx.m_280182_() - 10; + int y = 10; + int color = -65536; + if (currentBPM < 30.0f) { + color = -11141291; + } else if (currentBPM < 50.0f) { + color = -171; + } + ctx.m_280056_(mc.f_91062_, text, x - mc.f_91062_.m_92895_(text), y, color, false); + } + + public static float getCurrentHeartbeatVisual() { + return heartbeatVisualPulse; + } + + public static void updateHeartbeat(LocalPlayer player, float blurIntensity) { + float healthPercent; + boolean isMoving; + if (player == null) { + return; + } + if (!Blur.isActive()) { + explosionBPMMod *= 0.98f; + jumpBPMMod *= 0.98f; + if ((currentBPM += (23.3f - currentBPM) * 0.05f) < 24.0f && explosionBPMMod < 0.1f && jumpBPMMod < 0.1f) { + currentBPM = 23.3f; + explosionBPMMod = 0.0f; + jumpBPMMod = 0.0f; + heartbeatVisualPulse = 0.0f; + return; + } + } + float baseBPM = 23.3f; + boolean bl = isMoving = player.m_20184_().m_165925_() > 0.001; + if (isMoving) { + if (player.m_20142_()) { + baseBPM = 50.0f; + if (!player.m_20096_()) { + baseBPM = 60.0f; + } + } else { + baseBPM = 35.0f; + } + } + if ((healthPercent = player.m_21223_() / player.m_21233_()) < 0.1f) { + baseBPM += 63.3f; + } else if (healthPercent < 0.3f) { + baseBPM += 43.3f; + } + if (!player.m_20096_() && wasOnGround && isMoving) { + jumpBPMMod = Math.min(13.3f, jumpBPMMod + 3.3f); + } + wasOnGround = player.m_20096_(); + jumpBPMMod *= 0.99f; + explosionBPMMod *= 0.995f; + if (player.f_19789_ > 3.0f) { + baseBPM += Math.min(16.6f, player.f_19789_ * 1.6f); + } + if (player.m_20146_() <= 0) { + baseBPM += 5.0f; + } + if (player.m_6047_()) { + baseBPM -= 3.3f; + } + if (!isMoving) { + if (++idleTicks >= 60) { + baseBPM -= 1.6f; + idleTicks = 0; + } + } else { + idleTicks = 0; + } + float finalTarget = baseBPM + jumpBPMMod + explosionBPMMod; + if ((finalTarget = Math.max(20.0f, Math.min(130.0f, finalTarget))) > currentBPM) { + float rampSpeed = explosionBPMMod > 5.0f || Blur.isActive() ? 0.4f : 0.15f; + currentBPM += (finalTarget - currentBPM) * rampSpeed; + } else { + currentBPM += (finalTarget - currentBPM) * 0.04f; + } + double cycleSeconds = 60.0 / (double)Math.max(5.0f, currentBPM); + heartbeatCycleTimer += 0.05; + if (heartbeatCycleTimer >= cycleSeconds) { + heartbeatCycleTimer -= cycleSeconds; + lubTriggered = false; + dubTriggered = false; + } + double t = heartbeatCycleTimer; + float pulse = 0.0f; + double lubEnd = cycleSeconds * 0.35; + double pause1End = cycleSeconds * 0.45; + double dubEnd = cycleSeconds * 0.7; + if (t < lubEnd) { + s = (float)Math.sin(t / lubEnd * Math.PI); + pulse = (float)Math.pow(s, 1.2); + if (!lubTriggered) { + lubTriggered = true; + if (blurIntensity >= 0.1f && ((Boolean)Config.CLIENT.enableHeartbeatPulse.get()).booleanValue()) { + try { + Minecraft mc = Minecraft.m_91087_(); + if (mc != null) { + mc.m_91106_().m_120367_((SoundInstance)SimpleSoundInstance.m_119755_((SoundEvent)((SoundEvent)ModSounds.HEART_LAB.get()), (float)1.0f, (float)100.0f)); + } + } + catch (Throwable mc) {} + } + } + } else if (t > pause1End && t < dubEnd) { + s = (float)Math.sin((t - pause1End) / (dubEnd - pause1End) * Math.PI); + pulse = (float)Math.pow(s, 1.2) * 0.7f; + if (!dubTriggered) { + dubTriggered = true; + if (blurIntensity >= 0.1f && ((Boolean)Config.CLIENT.enableHeartbeatPulse.get()).booleanValue()) { + try { + Minecraft mc = Minecraft.m_91087_(); + if (mc != null) { + mc.m_91106_().m_120367_((SoundInstance)SimpleSoundInstance.m_119755_((SoundEvent)((SoundEvent)ModSounds.HEART_DAB.get()), (float)1.0f, (float)100.0f)); + } + } + catch (Throwable throwable) { + // empty catch block + } + } + } + } + if ((healthPercent < 0.05f || explosionBPMMod > 80.0f && t < 2.0) && ThreadLocalRandom.current().nextDouble() < 0.03) { + heartbeatCycleTimer += 0.08; + } + float pulseScale = 0.3f + blurIntensity * 1.5f; + heartbeatVisualPulse = pulse * pulseScale; + } + + private static double computeBaseLowpassSilentSeconds(double effectivePercent, boolean explosionInCave) { + if (!explosionInCave) { + if (effectivePercent <= 40.0) { + return 0.0; + } + if (effectivePercent > 80.0) { + double t = (effectivePercent - 80.0) / 20.0; + return 8.0 + 2.0 * t; + } + if (effectivePercent > 60.0) { + double t = (effectivePercent - 60.0) / 20.0; + return 4.0 + 4.0 * t; + } + double t = (effectivePercent - 40.0) / 20.0; + return 2.0 + 2.0 * t; + } + if (effectivePercent <= 20.0) { + return 0.0; + } + if (effectivePercent > 80.0) { + double t = (effectivePercent - 80.0) / 20.0; + return 14.0 + 6.0 * t; + } + if (effectivePercent > 60.0) { + double t = (effectivePercent - 60.0) / 20.0; + return 8.0 + 2.0 * t; + } + if (effectivePercent <= 40.0) { + double tt = (effectivePercent - 20.0) / 20.0; + return 4.0 + 2.0 * Math.max(0.0, Math.min(1.0, tt)); + } + double tt = (effectivePercent - 40.0) / 20.0; + return 4.0 + 2.0 * Math.max(0.0, Math.min(1.0, tt)); + } + + private static double computeBaseLowpassIntensityPercent(double effectivePercent) { + if (effectivePercent <= 40.0) { + return 0.0; + } + if (effectivePercent <= 50.0) { + double t = (effectivePercent - 40.0) / 10.0; + return 0.0 + 70.0 * t; + } + if (effectivePercent <= 70.0) { + double t = (effectivePercent - 50.0) / 20.0; + return 70.0 + 30.0 * t; + } + return 100.0; + } + + private static double computeLowpassPowerMultiplier(double power) { + double[][] points = new double[][]{{2.0, 1.0}, {5.0, 1.2}, {6.0, 1.4}, {12.0, 1.8}, {13.0, 2.0}, {22.0, 2.3}, {23.0, 2.7}, {50.0, 3.0}, {51.0, 3.2}, {80.0, 5.0}, {120.0, 7.0}}; + double clamped = Math.max(points[0][0], Math.min(points[points.length - 1][0], power)); + for (int i = 1; i < points.length; ++i) { + double lowerP = points[i - 1][0]; + double upperP = points[i][0]; + if (!(clamped <= upperP)) continue; + double lowerM = points[i - 1][1]; + double upperM = points[i][1]; + double t = (clamped - lowerP) / (upperP - lowerP); + return lowerM + (upperM - lowerM) * t; + } + return points[points.length - 1][1]; + } + + private static double computeLowpassPowerChance(double power, boolean explosionInCave) { + double[][] points = explosionInCave ? new double[][]{{1.0, 0.5}, {2.0, 0.6}, {3.0, 0.7}, {5.0, 0.8}, {6.0, 0.95}, {120.0, 1.0}} : new double[][]{{1.0, 0.3}, {2.0, 0.3}, {3.0, 0.35}, {5.0, 0.43}, {6.0, 0.45}, {10.0, 0.45}, {11.0, 0.7}, {25.0, 0.8}, {26.0, 1.0}, {120.0, 1.0}}; + double clamped = Math.max(points[0][0], Math.min(points[points.length - 1][0], power)); + for (int i = 1; i < points.length; ++i) { + double lowerP = points[i - 1][0]; + double upperP = points[i][0]; + if (!(clamped <= upperP)) continue; + double lowerC = points[i - 1][1]; + double upperC = points[i][1]; + double t = (clamped - lowerP) / (upperP - lowerP); + return lowerC + (upperC - lowerC) * t; + } + return 1.0; + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/ConcussionSoundManager.java b/src/main/java/com/vinlanx/explosionoverhaul/client/ConcussionSoundManager.java new file mode 100644 index 0000000..8fca728 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/ConcussionSoundManager.java @@ -0,0 +1,65 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.vinlanx.explosionoverhaul.ModSounds; +import com.vinlanx.explosionoverhaul.client.Blur; +import com.vinlanx.explosionoverhaul.client.DeafnessConcussionEffect; +import com.vinlanx.explosionoverhaul.client.FadingMusicInstance; +import com.vinlanx.explosionoverhaul.client.LowPassConcussionEffect; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundSource; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.neoforge.event.TickEvent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; + +@OnlyIn(value=Dist.CLIENT) +@Mod.EventBusSubscriber(modid="explosionoverhaul", value={Dist.CLIENT}) +public class ConcussionSoundManager { + private static FadingMusicInstance currentLowSound = null; + + @SubscribeEvent + public static void onClientTick(TickEvent.ClientTickEvent event) { + if (event.phase != TickEvent.Phase.END) { + return; + } + Minecraft mc = Minecraft.m_91087_(); + if (mc.f_91073_ == null || mc.f_91074_ == null) { + if (currentLowSound != null) { + mc.m_91106_().m_120399_((SoundInstance)currentLowSound); + currentLowSound = null; + } + return; + } + if (mc.m_91104_()) { + return; + } + boolean deafness = DeafnessConcussionEffect.isActive(); + boolean lowpass = LowPassConcussionEffect.isActive(); + boolean blur = Blur.isActive(); + float targetVolume = 0.0f; + if (blur) { + if (deafness) { + targetVolume = 1.0f; + } else if (lowpass) { + targetVolume = 0.4f; + } + } + if (targetVolume > 0.0f) { + if (currentLowSound == null || !mc.m_91106_().m_120403_((SoundInstance)currentLowSound)) { + currentLowSound = new FadingMusicInstance((SoundEvent)ModSounds.LOW_SOUND.get(), 0.01f, SoundSource.MASTER); + currentLowSound.fadeTo(targetVolume, 1.0f); + mc.m_91106_().m_120367_((SoundInstance)currentLowSound); + } else if (Math.abs(currentLowSound.getCurrentVolume() - targetVolume) > 0.01f && !currentLowSound.hasFinishedFading()) { + currentLowSound.fadeTo(targetVolume, 0.5f); + } + } else if (currentLowSound != null && mc.m_91106_().m_120403_((SoundInstance)currentLowSound) && !currentLowSound.hasFinishedFading()) { + currentLowSound.fadeOutAndStop(1.0f); + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/CustomGlowParticle.java b/src/main/java/com/vinlanx/explosionoverhaul/client/CustomGlowParticle.java new file mode 100644 index 0000000..d0fd491 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/CustomGlowParticle.java @@ -0,0 +1,346 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.vinlanx.explosionoverhaul.Config; +import com.vinlanx.explosionoverhaul.CustomGlowParticleOptions; +import com.vinlanx.explosionoverhaul.client.ExplosionTextureManager; +import com.vinlanx.explosionoverhaul.client.ExplosionWindController; +import net.minecraft.client.Camera; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.particle.ParticleRenderType; +import net.minecraft.client.particle.TextureSheetParticle; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; +import org.joml.Quaternionf; +import org.joml.Quaternionfc; +import org.joml.Vector3f; + +public class CustomGlowParticle +extends TextureSheetParticle { + private final float power; + private final float initialQuadSize; + private final int animationDuration; + private final int animationType; + private final float centerY; + private final float maxRadius; + private float currentHeightPercent; + private final int peakFireEndTick; + private final int fireTransitionEndTick; + private final int smokeStartTick; + private static final int GLOW_FRAME_COUNT = 239; + private static final int SGLOW_FRAME_COUNT = 224; + private static final int FRAMES_PER_SHEET = 64; + private static final int FRAMES_PER_ROW = 8; + private int baseSheetIndex; + private int baseFrameOnSheet; + private int emissiveSheetIndex; + private int emissiveFrameOnSheet; + + public CustomGlowParticle(ClientLevel pLevel, double pX, double pY, double pZ, double pXSpeed, double pYSpeed, double pZSpeed, CustomGlowParticleOptions options) { + super(pLevel, pX, pY, pZ, pXSpeed, pYSpeed, pZSpeed); + int fadeOutDurationTicks; + this.f_172258_ = 0.98f; + this.f_107226_ = 0.0f; + this.f_107215_ = pXSpeed; + this.f_107216_ = pYSpeed; + this.f_107217_ = pZSpeed; + this.power = options.getPower(); + this.initialQuadSize = options.getScale(); + this.animationType = options.getAnimationType(); + this.f_107663_ = this.initialQuadSize; + this.centerY = options.getCenterY(); + this.maxRadius = options.getMaxRadius(); + this.currentHeightPercent = options.getHeightPercent(); + if (this.power <= 1.0f) { + this.animationDuration = 40; + fadeOutDurationTicks = 40; + } else if (this.power <= 10.0f) { + this.animationDuration = this.interpolate(this.power, 1.0f, 40.0f, 10.0f, 100.0f); + fadeOutDurationTicks = this.interpolate(this.power, 1.0f, 40.0f, 10.0f, 60.0f); + } else if (this.power <= 60.0f) { + this.animationDuration = this.interpolate(this.power, 10.0f, 100.0f, 60.0f, 140.0f); + fadeOutDurationTicks = this.interpolate(this.power, 10.0f, 60.0f, 60.0f, 80.0f); + } else if (this.power <= 100.0f) { + this.animationDuration = this.interpolate(this.power, 60.0f, 140.0f, 100.0f, 200.0f); + fadeOutDurationTicks = this.interpolate(this.power, 60.0f, 80.0f, 100.0f, 120.0f); + } else { + this.animationDuration = 200; + fadeOutDurationTicks = 120; + } + this.f_107225_ = this.animationDuration + fadeOutDurationTicks; + float powerFraction = Mth.m_14036_((float)(this.power / 100.0f), (float)0.0f, (float)1.0f); + float totalFirePercent = Mth.m_14179_((float)powerFraction, (float)0.02f, (float)0.2f); + float cooldownToSmokePercent = Mth.m_14179_((float)powerFraction, (float)0.04f, (float)0.08f); + int totalFireDuration = (int)((float)this.f_107225_ * totalFirePercent); + this.peakFireEndTick = (int)((float)totalFireDuration * 0.9f); + this.fireTransitionEndTick = totalFireDuration; + int cooldownDuration = (int)((float)this.f_107225_ * cooldownToSmokePercent); + this.smokeStartTick = this.fireTransitionEndTick + cooldownDuration; + if (Config.CLIENT.particleRenderMode.get() == Config.Client.ParticleRenderMode.VANILA) { + this.f_107230_ = 1.0f; + this.f_107227_ = 1.0f; + this.f_107228_ = 0.85f; + this.f_107229_ = 0.5f; + } + } + + public void m_5989_() { + double targetSpeed; + this.f_107209_ = this.f_107212_; + this.f_107210_ = this.f_107213_; + this.f_107211_ = this.f_107214_; + if (this.f_107224_++ >= this.f_107225_) { + this.m_107274_(); + return; + } + if (Config.CLIENT.particleRenderMode.get() == Config.Client.ParticleRenderMode.VANILA) { + this.tickVanila(); + } else if (Config.CLIENT.particleRenderMode.get() == Config.Client.ParticleRenderMode.REALISTIC_2) { + this.tickRealistic2(); + } else { + this.tickRealistic(); + } + this.m_6257_(this.f_107215_, this.f_107216_, this.f_107217_); + this.f_107215_ *= (double)this.f_172258_; + this.f_107216_ *= (double)this.f_172258_; + this.f_107217_ *= (double)this.f_172258_; + float heightPercent = this.updateHeightPercent(); + Vec3 direction = ExplosionWindController.getWindDirection(); + if (direction != Vec3.f_82478_ && (targetSpeed = ExplosionWindController.computeGlowSpeed(heightPercent)) > 0.0) { + double targetX = direction.f_82479_ * targetSpeed; + double targetZ = direction.f_82481_ * targetSpeed; + this.f_107215_ += (targetX - this.f_107215_) * 0.1; + this.f_107217_ += (targetZ - this.f_107217_) * 0.1; + } + } + + private void tickVanila() { + this.baseSheetIndex = 0; + this.f_107663_ = this.initialQuadSize; + if (this.f_107224_ < this.peakFireEndTick) { + this.f_107230_ = 1.0f; + this.f_107227_ = 1.0f; + this.f_107228_ = 0.85f; + this.f_107229_ = 0.5f; + } else if (this.f_107224_ < this.fireTransitionEndTick) { + float progress = (float)(this.f_107224_ - this.peakFireEndTick) / (float)(this.fireTransitionEndTick - this.peakFireEndTick); + this.f_107230_ = 1.0f; + this.f_107227_ = 1.0f; + this.f_107228_ = Mth.m_14179_((float)progress, (float)0.85f, (float)0.5f); + this.f_107229_ = Mth.m_14179_((float)progress, (float)0.5f, (float)0.1f); + } else if (this.f_107224_ < this.smokeStartTick) { + float progress = (float)(this.f_107224_ - this.fireTransitionEndTick) / (float)(this.smokeStartTick - this.fireTransitionEndTick); + float smokeCol = 0.15f; + this.f_107227_ = Mth.m_14179_((float)progress, (float)1.0f, (float)(smokeCol + 0.1f)); + this.f_107228_ = Mth.m_14179_((float)progress, (float)0.5f, (float)smokeCol); + this.f_107229_ = Mth.m_14179_((float)progress, (float)0.1f, (float)smokeCol); + this.f_107230_ = Mth.m_14179_((float)progress, (float)1.0f, (float)0.9f); + } else { + float progress = (float)(this.f_107224_ - this.smokeStartTick) / (float)(this.f_107225_ - this.smokeStartTick); + float finalSmokeCol = 0.05f; + this.f_107228_ = this.f_107229_ = Mth.m_14179_((float)progress, (float)0.15f, (float)finalSmokeCol); + this.f_107227_ = this.f_107229_; + this.f_107230_ = 0.9f * (1.0f - progress * progress * progress); + } + } + + private void tickRealistic2() { + int frameIndex; + int emissiveSheetStart; + int baseSheetStart; + int frameCountForAnim; + this.f_107663_ = this.initialQuadSize * 2.0f; + if (this.animationType == 2) { + frameCountForAnim = 224; + baseSheetStart = 18; + emissiveSheetStart = 22; + } else if (this.animationType == 1) { + frameCountForAnim = 239; + baseSheetStart = 10; + emissiveSheetStart = 14; + } else { + frameCountForAnim = 239; + baseSheetStart = 2; + emissiveSheetStart = 6; + } + if (this.f_107224_ < this.animationDuration) { + float animProgress = (float)this.f_107224_ / (float)this.animationDuration; + float easedProgress = 1.0f - (float)Math.pow(1.0f - animProgress, 3.0); + frameIndex = (int)(easedProgress * (float)(frameCountForAnim - 1)); + this.f_107230_ = 1.0f; + } else { + frameIndex = frameCountForAnim - 1; + int fadeDuration = this.f_107225_ - this.animationDuration; + int ageInFade = this.f_107224_ - this.animationDuration; + this.f_107230_ = 1.0f - (float)ageInFade / (float)fadeDuration; + } + frameIndex = Mth.m_14045_((int)frameIndex, (int)0, (int)(frameCountForAnim - 1)); + this.baseSheetIndex = baseSheetStart + frameIndex / 64; + this.baseFrameOnSheet = frameIndex % 64; + this.emissiveSheetIndex = emissiveSheetStart + frameIndex / 64; + this.emissiveFrameOnSheet = frameIndex % 64; + } + + private void tickRealistic() { + int frameIndex; + int emissiveSheetStart; + int baseSheetStart; + int frameCountForAnim; + if (this.animationType == 2) { + frameCountForAnim = 224; + baseSheetStart = 18; + emissiveSheetStart = 22; + } else if (this.animationType == 1) { + frameCountForAnim = 239; + baseSheetStart = 10; + emissiveSheetStart = 14; + } else { + frameCountForAnim = 239; + baseSheetStart = 2; + emissiveSheetStart = 6; + } + if (this.f_107224_ < this.animationDuration) { + float animProgress = (float)this.f_107224_ / (float)this.animationDuration; + float easedProgress = 1.0f - (float)Math.pow(1.0f - animProgress, 3.0); + frameIndex = (int)(easedProgress * (float)(frameCountForAnim - 1)); + this.f_107230_ = 1.0f; + } else { + frameIndex = frameCountForAnim - 1; + int fadeDuration = this.f_107225_ - this.animationDuration; + int ageInFade = this.f_107224_ - this.animationDuration; + this.f_107230_ = 1.0f - (float)ageInFade / (float)fadeDuration; + } + frameIndex = Mth.m_14045_((int)frameIndex, (int)0, (int)(frameCountForAnim - 1)); + this.baseSheetIndex = baseSheetStart + frameIndex / 64; + this.baseFrameOnSheet = frameIndex % 64; + this.emissiveSheetIndex = emissiveSheetStart + frameIndex / 64; + this.emissiveFrameOnSheet = frameIndex % 64; + } + + public void m_5744_(VertexConsumer pBuffer, Camera pRenderInfo, float pPartialTicks) { + Vector3f[] avector3f; + Vec3 vec3 = pRenderInfo.m_90583_(); + float f = (float)(Mth.m_14139_((double)pPartialTicks, (double)this.f_107209_, (double)this.f_107212_) - vec3.m_7096_()); + float f1 = (float)(Mth.m_14139_((double)pPartialTicks, (double)this.f_107210_, (double)this.f_107213_) - vec3.m_7098_()); + float f2 = (float)(Mth.m_14139_((double)pPartialTicks, (double)this.f_107211_, (double)this.f_107214_) - vec3.m_7094_()); + Quaternionf quaternion = new Quaternionf((Quaternionfc)pRenderInfo.m_253121_()); + if (this.f_107231_ != 0.0f) { + float f3 = Mth.m_14179_((float)pPartialTicks, (float)this.f_107204_, (float)this.f_107231_); + quaternion.rotateZ(f3); + } + if (this.animationType == 2) { + float aspectRatio = 0.5629139f; + avector3f = new Vector3f[]{new Vector3f(-0.5629139f, -1.0f, 0.0f), new Vector3f(-0.5629139f, 1.0f, 0.0f), new Vector3f(0.5629139f, 1.0f, 0.0f), new Vector3f(0.5629139f, -1.0f, 0.0f)}; + } else { + avector3f = new Vector3f[]{new Vector3f(-1.0f, -1.0f, 0.0f), new Vector3f(-1.0f, 1.0f, 0.0f), new Vector3f(1.0f, 1.0f, 0.0f), new Vector3f(1.0f, -1.0f, 0.0f)}; + } + float f4 = this.m_5902_(pPartialTicks); + for (int i = 0; i < 4; ++i) { + Vector3f vector3f = avector3f[i]; + vector3f.rotate((Quaternionfc)quaternion); + vector3f.mul(f4); + vector3f.add(f, f1, f2); + } + int worldLight = this.m_6355_(pPartialTicks); + int frameToRender = Config.CLIENT.particleRenderMode.get() == Config.Client.ParticleRenderMode.VANILA ? 0 : this.baseFrameOnSheet; + ResourceLocation baseTexture = ExplosionTextureManager.getInstance().getTexture(this.baseSheetIndex); + this.renderFrame(avector3f, baseTexture, frameToRender, this.f_107227_, this.f_107228_, this.f_107229_, this.f_107230_, worldLight); + if (Config.CLIENT.particleRenderMode.get() == Config.Client.ParticleRenderMode.REALISTIC || Config.CLIENT.particleRenderMode.get() == Config.Client.ParticleRenderMode.REALISTIC_2) { + ResourceLocation emissiveTexture = ExplosionTextureManager.getInstance().getTexture(this.emissiveSheetIndex); + int fullBright = 240; + this.renderFrame(avector3f, emissiveTexture, this.emissiveFrameOnSheet, this.f_107227_, this.f_107228_, this.f_107229_, this.f_107230_, fullBright); + } else if (this.f_107224_ < this.smokeStartTick) { + ResourceLocation emissiveTexture = ExplosionTextureManager.getInstance().getTexture(1); + int fullBright = 240; + this.renderFrame(avector3f, emissiveTexture, 0, this.f_107227_, this.f_107228_, this.f_107229_, this.f_107230_ * 0.8f, fullBright); + } + } + + private void renderFrame(Vector3f[] vertices, ResourceLocation texture, int frame, float r, float g, float b, float a, int light) { + float v1; + float u1; + float v0; + float u0; + if (texture == null) { + return; + } + RenderSystem.setShader(GameRenderer::m_172829_); + RenderSystem.setShaderTexture((int)0, (ResourceLocation)texture); + RenderSystem.enableDepthTest(); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.depthMask((boolean)true); + Tesselator tesselator = Tesselator.m_85913_(); + BufferBuilder buffer = tesselator.m_85915_(); + buffer.m_166779_(VertexFormat.Mode.QUADS, DefaultVertexFormat.f_85813_); + if (frame == 0 && Config.CLIENT.particleRenderMode.get() == Config.Client.ParticleRenderMode.VANILA) { + u0 = 0.0f; + v0 = 0.0f; + u1 = 1.0f; + v1 = 1.0f; + } else { + float frameUWidth = 0.125f; + float frameVHeight = 0.125f; + int col = frame % 8; + int row = frame / 8; + u0 = (float)col * frameUWidth; + v0 = (float)row * frameVHeight; + u1 = u0 + frameUWidth; + v1 = v0 + frameVHeight; + } + buffer.m_5483_((double)vertices[0].x(), (double)vertices[0].y(), (double)vertices[0].z()).m_7421_(u0, v1).m_85950_(r, g, b, a).m_85969_(light).m_5752_(); + buffer.m_5483_((double)vertices[1].x(), (double)vertices[1].y(), (double)vertices[1].z()).m_7421_(u0, v0).m_85950_(r, g, b, a).m_85969_(light).m_5752_(); + buffer.m_5483_((double)vertices[2].x(), (double)vertices[2].y(), (double)vertices[2].z()).m_7421_(u1, v0).m_85950_(r, g, b, a).m_85969_(light).m_5752_(); + buffer.m_5483_((double)vertices[3].x(), (double)vertices[3].y(), (double)vertices[3].z()).m_7421_(u1, v1).m_85950_(r, g, b, a).m_85969_(light).m_5752_(); + tesselator.m_85914_(); + } + + public ParticleRenderType m_7556_() { + return ParticleRenderType.f_107433_; + } + + private int interpolate(float power, float p1, float v1, float p2, float v2) { + if (p2 == p1) { + return (int)v1; + } + float fraction = (power - p1) / (p2 - p1); + return (int)(v1 + fraction * (v2 - v1)); + } + + private float updateHeightPercent() { + if (this.maxRadius <= 0.0f) { + return 0.5f; + } + return Math.max(0.25f, this.currentHeightPercent); + } + + public int m_6355_(float pPartialTick) { + if (Config.CLIENT.particleRenderMode.get() == Config.Client.ParticleRenderMode.VANILA) { + float currentAge = (float)this.f_107224_ + pPartialTick; + if (currentAge < (float)this.fireTransitionEndTick) { + return 240; + } + if (currentAge > (float)this.smokeStartTick) { + return super.m_6355_(pPartialTick); + } + float progress = (currentAge - (float)this.fireTransitionEndTick) / (float)(this.smokeStartTick - this.fireTransitionEndTick); + int packedAmbient = super.m_6355_(pPartialTick); + int skyLightAmbient = packedAmbient >> 20 & 0xF; + int blockLightAmbient = packedAmbient >> 4 & 0xF; + int skyLightCurrent = (int)Mth.m_14179_((float)progress, (float)15.0f, (float)skyLightAmbient); + int blockLightCurrent = (int)Mth.m_14179_((float)progress, (float)15.0f, (float)blockLightAmbient); + return skyLightCurrent << 20 | blockLightCurrent << 4; + } + return super.m_6355_(pPartialTick); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/CustomGlowParticleProvider.java b/src/main/java/com/vinlanx/explosionoverhaul/client/CustomGlowParticleProvider.java new file mode 100644 index 0000000..bda7fb2 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/CustomGlowParticleProvider.java @@ -0,0 +1,21 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.vinlanx.explosionoverhaul.CustomGlowParticleOptions; +import com.vinlanx.explosionoverhaul.client.CustomGlowParticle; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.particle.ParticleProvider; +import net.minecraft.client.particle.SpriteSet; + +public class CustomGlowParticleProvider +implements ParticleProvider { + public CustomGlowParticleProvider(SpriteSet pSprites) { + } + + public Particle createParticle(CustomGlowParticleOptions options, ClientLevel pLevel, double pX, double pY, double pZ, double pXSpeed, double pYSpeed, double pZSpeed) { + return new CustomGlowParticle(pLevel, pX, pY, pZ, pXSpeed, pYSpeed, pZSpeed, options); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/DeafnessConcussionEffect.java b/src/main/java/com/vinlanx/explosionoverhaul/client/DeafnessConcussionEffect.java new file mode 100644 index 0000000..b221e28 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/DeafnessConcussionEffect.java @@ -0,0 +1,178 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.vinlanx.explosionoverhaul.Config; +import com.vinlanx.explosionoverhaul.client.LowPassConcussionEffect; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.Options; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundSource; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.neoforge.event.TickEvent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.loading.FMLEnvironment; + +@OnlyIn(value=Dist.CLIENT) +@Mod.EventBusSubscriber(modid="explosionoverhaul", value={Dist.CLIENT}) +public class DeafnessConcussionEffect { + public static int DELAY_TICKS = 3; + public static int FADE_TO_SILENT_TICKS = 5; + public static int FADE_FROM_SILENT_TICKS = 100; + private static Phase phase = Phase.NONE; + private static int ticksInPhase = 0; + private static int phaseTicksTotal = 0; + private static int silentTicks = 0; + private static double baseMasterVolume = 1.0; + private static float currentIntensity = 0.0f; + private static float lastIntensity = 0.0f; + public static boolean debugShowChat = false; + public static volatile boolean enabled = true; + + public static boolean start(float intensity, double silentSeconds, double effectivePercent, String visibility, int intensityPercent) { + LocalPlayer player; + float effectiveIntensity; + if (!FMLEnvironment.dist.isClient()) { + return false; + } + if (!enabled) { + return false; + } + float f = effectiveIntensity = (Boolean)Config.CLIENT.enableDeafness.get() != false ? intensity : 0.001f; + if (effectiveIntensity < 1.0E-4f) { + return false; + } + Minecraft mc = Minecraft.m_91087_(); + if (mc == null || mc.f_91073_ == null || mc.f_91074_ == null) { + return false; + } + Options options = mc.f_91066_; + if (options == null) { + return false; + } + baseMasterVolume = (Double)options.m_246669_(SoundSource.MASTER).m_231551_(); + if (phase != Phase.NONE) { + currentIntensity = Math.min(1.0f, currentIntensity + effectiveIntensity); + silentTicks = Math.min(2000, silentTicks + (int)Math.round(silentSeconds * 20.0)); + if (phase != Phase.SILENT) { + phase = Phase.FADE_IN; + ticksInPhase = 0; + phaseTicksTotal = FADE_TO_SILENT_TICKS; + } + } else { + currentIntensity = effectiveIntensity; + silentTicks = Math.max(0, (int)Math.round(silentSeconds * 20.0)); + phase = Phase.DELAY; + ticksInPhase = 0; + phaseTicksTotal = DELAY_TICKS; + } + lastIntensity = currentIntensity; + if (debugShowChat && (player = mc.f_91074_) != 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.m_237113_((String)msg).m_130940_(ChatFormatting.WHITE), false); + } + return true; + } + + @SubscribeEvent + public static void onClientTick(TickEvent.ClientTickEvent event) { + if (event.phase != TickEvent.Phase.END) { + return; + } + if (phase == Phase.NONE) { + return; + } + Minecraft mc = Minecraft.m_91087_(); + if (mc == null || mc.f_91066_ == null) { + DeafnessConcussionEffect.resetVolume(); + return; + } + if (mc.m_91104_()) { + return; + } + double t = Math.min(1.0, (double)(++ticksInPhase) / (double)phaseTicksTotal); + switch (phase) { + case DELAY: { + if (ticksInPhase < phaseTicksTotal) break; + DeafnessConcussionEffect.nextPhase(Phase.FADE_IN, FADE_TO_SILENT_TICKS); + break; + } + case FADE_IN: { + double minGain = baseMasterVolume * (1.0 - (double)currentIntensity); + double gain = DeafnessConcussionEffect.lerp(baseMasterVolume, minGain, DeafnessConcussionEffect.easeOutQuad(t)); + DeafnessConcussionEffect.applyMasterVolume(mc, gain); + if (ticksInPhase < phaseTicksTotal) break; + DeafnessConcussionEffect.nextPhase(Phase.SILENT, silentTicks); + break; + } + case SILENT: { + double minGain = baseMasterVolume * (1.0 - (double)currentIntensity); + DeafnessConcussionEffect.applyMasterVolume(mc, minGain); + if (ticksInPhase < phaseTicksTotal) break; + DeafnessConcussionEffect.nextPhase(Phase.FADE_OUT, FADE_FROM_SILENT_TICKS); + break; + } + case FADE_OUT: { + double minGain = baseMasterVolume * (1.0 - (double)currentIntensity); + double gain = DeafnessConcussionEffect.lerp(minGain, baseMasterVolume, DeafnessConcussionEffect.easeInOutQuad(t)); + DeafnessConcussionEffect.applyMasterVolume(mc, gain); + if (ticksInPhase < phaseTicksTotal) break; + DeafnessConcussionEffect.stop(); + break; + } + } + } + + private static void nextPhase(Phase next, int durationTicks) { + phase = next; + ticksInPhase = 0; + phaseTicksTotal = durationTicks; + } + + public static void stop() { + DeafnessConcussionEffect.resetVolume(); + phase = Phase.NONE; + ticksInPhase = 0; + phaseTicksTotal = 0; + lastIntensity = 0.0f; + } + + public static boolean isActive() { + return phase != Phase.NONE; + } + + private static void resetVolume() { + LowPassConcussionEffect.setDeafnessGain(1.0f); + } + + private static void applyMasterVolume(Minecraft mc, double volume) { + float clamped = (float)Math.max(0.0, Math.min(1.0, volume)); + LowPassConcussionEffect.setDeafnessGain(clamped); + } + + private static double lerp(double a, double b, double t) { + return a + (b - a) * t; + } + + private static double easeOutQuad(double t) { + return 1.0 - (1.0 - t) * (1.0 - t); + } + + private static double easeInOutQuad(double t) { + return t < 0.5 ? 2.0 * t * t : 1.0 - Math.pow(-2.0 * t + 2.0, 2.0) / 2.0; + } + + private static enum Phase { + NONE, + DELAY, + FADE_IN, + SILENT, + FADE_OUT; + + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/ExplosionTextureManager.java b/src/main/java/com/vinlanx/explosionoverhaul/client/ExplosionTextureManager.java new file mode 100644 index 0000000..6e59c91 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/ExplosionTextureManager.java @@ -0,0 +1,102 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.mojang.blaze3d.platform.NativeImage; +import com.mojang.logging.LogUtils; +import com.vinlanx.explosionoverhaul.Config; +import com.vinlanx.explosionoverhaul.ExplosionOverhaul; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.Resource; + +public class ExplosionTextureManager { + private static final LogUtils LOGGER_WRAPPER = null; + private static final ExplosionTextureManager INSTANCE = new ExplosionTextureManager(); + private final Map textures = new HashMap(); + private final Map resourceLocations = new HashMap(); + public static final int INDEX_SOFT_GLOW = 0; + public static final int INDEX_SOFT_GLOW_E = 1; + public static final int GLOW_BASE_START = 2; + public static final int GLOW_EMISSIVE_START = 6; + public static final int GLOW2_BASE_START = 10; + public static final int GLOW2_EMISSIVE_START = 14; + public static final int SGLOW_BASE_START = 18; + public static final int SGLOW_EMISSIVE_START = 22; + private static final String BASE_PATH = "explosions/"; + + public static ExplosionTextureManager getInstance() { + return INSTANCE; + } + + private ExplosionTextureManager() { + } + + public void reload() { + this.clear(); + if (Minecraft.m_91087_().m_91098_() == null) { + return; + } + ExplosionOverhaul.LOGGER.info("Reloading Explosion Texture Manager..."); + this.loadTexture(0, "soft_glow.png"); + this.loadTexture(1, "soft_glow_e.png"); + Config.Client.ParticleRenderMode mode = (Config.Client.ParticleRenderMode)((Object)Config.CLIENT.particleRenderMode.get()); + if (mode == Config.Client.ParticleRenderMode.VANILA) { + ExplosionOverhaul.LOGGER.info("Vanilla mode active - skipping high-res sheet loading to save VRAM."); + return; + } + Config.Client.GlowTextureQuality quality = (Config.Client.GlowTextureQuality)((Object)Config.CLIENT.glowTextureQuality.get()); + boolean is64 = quality == Config.Client.GlowTextureQuality.QUALITY_64; + this.loadSheetGroup(2, "glow/glow_sheet_", is64); + this.loadSheetGroup(6, "glow/glow_e_sheet_", is64); + this.loadSheetGroup(10, "glow_2/glow_2_sheet_", is64); + this.loadSheetGroup(14, "glow_2/glow_2_e_sheet_", is64); + this.loadSheetGroup(18, "sglow/sglow_sheet_", is64); + this.loadSheetGroup(22, "sglow/sglow_e_sheet_", is64); + ExplosionOverhaul.LOGGER.info("Explosion sheets loaded successfully (Quality: {}).", (Object)(is64 ? "64" : "256")); + } + + private void loadSheetGroup(int startIndex, String prefix, boolean is64) { + String pathPrefix = is64 ? prefix.replace("/", "/64/") : prefix; + for (int i = 0; i < 4; ++i) { + this.loadTexture(startIndex + i, pathPrefix + (i + 1) + ".png"); + } + } + + private void loadTexture(int index, String path) { + ResourceLocation fullPath = new ResourceLocation("explosionoverhaul", BASE_PATH + path); + try { + InputStream is = ((Resource)Minecraft.m_91087_().m_91098_().m_213713_(fullPath).get()).m_215507_(); + NativeImage image = NativeImage.m_85058_((InputStream)is); + DynamicTexture texture = new DynamicTexture(image); + ResourceLocation loc = Minecraft.m_91087_().m_91097_().m_118490_("explosion_sheet_" + index, texture); + this.textures.put(index, texture); + this.resourceLocations.put(index, loc); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.error("Failed to load explosion sheet from {}: {}", (Object)fullPath, (Object)e.getMessage()); + } + } + + public ResourceLocation getTexture(int index) { + ResourceLocation loc = this.resourceLocations.get(index); + if (loc == null) { + loc = this.resourceLocations.get(0); + } + if (loc == null) { + return new ResourceLocation("minecraft", "textures/particle/generic_0.png"); + } + return loc; + } + + public void clear() { + this.textures.values().forEach(DynamicTexture::close); + this.textures.clear(); + this.resourceLocations.clear(); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/ExplosionWindController.java b/src/main/java/com/vinlanx/explosionoverhaul/client/ExplosionWindController.java new file mode 100644 index 0000000..f1edf76 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/ExplosionWindController.java @@ -0,0 +1,144 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.vinlanx.explosionoverhaul.Config; +import java.util.Random; +import net.minecraft.client.Minecraft; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.phys.Vec3; + +public class ExplosionWindController { + private static final double BASE_SPEED = 0.05; + private static final double MAX_SPEED = 0.06; + private static final double LERP_FACTOR = 0.03; + private static final Random RANDOM = new Random(); + private static final double[] HEIGHT_STOPS = new double[]{0.0, 0.25, 0.5, 0.75, 1.0}; + private static final double[] DUST_SPEEDS = new double[]{0.02, 0.02, 0.02, 0.02, 0.02}; + private static final double[] GLOW_SPEEDS = new double[]{0.0, 0.02, 0.04, 0.06, 0.08}; + private static Vec3 currentWind = Vec3.f_82478_; + private static Vec3 targetDirection = Vec3.f_82478_; + private static int ticksUntilDirectionShift = 0; + + private ExplosionWindController() { + } + + public static void tick() { + Vec3 desiredWind; + if (ticksUntilDirectionShift-- <= 0) { + targetDirection = ExplosionWindController.randomHorizontalDirection(); + ticksUntilDirectionShift = 80 + RANDOM.nextInt(120); + } + if ((currentWind = ExplosionWindController.lerp(currentWind, desiredWind = targetDirection.m_82490_(0.05), 0.03)).m_82553_() > 0.06) { + currentWind = currentWind.m_82541_().m_82490_(0.06); + } + } + + public static void reset() { + currentWind = Vec3.f_82478_; + targetDirection = Vec3.f_82478_; + ticksUntilDirectionShift = 0; + } + + public static Vec3 getWind() { + if (!((Boolean)Config.CLIENT.enableWindEffect.get()).booleanValue()) { + return Vec3.f_82478_; + } + double multiplier = (Double)Config.CLIENT.windSpeedMultiplier.get(); + return currentWind.m_82490_(multiplier); + } + + public static Vec3 getScaledWind(double scale) { + if (!((Boolean)Config.CLIENT.enableWindEffect.get()).booleanValue()) { + return Vec3.f_82478_; + } + double multiplier = (Double)Config.CLIENT.windSpeedMultiplier.get(); + return currentWind.m_82490_(scale * multiplier); + } + + public static Vec3 getWindDirection() { + if (!((Boolean)Config.CLIENT.enableWindEffect.get()).booleanValue()) { + return Vec3.f_82478_; + } + double length = Math.sqrt(ExplosionWindController.currentWind.f_82479_ * ExplosionWindController.currentWind.f_82479_ + ExplosionWindController.currentWind.f_82481_ * ExplosionWindController.currentWind.f_82481_); + if (length < 1.0E-4) { + return Vec3.f_82478_; + } + return new Vec3(ExplosionWindController.currentWind.f_82479_ / length, 0.0, ExplosionWindController.currentWind.f_82481_ / length); + } + + private static double getWeatherMultiplier() { + Minecraft minecraft = Minecraft.m_91087_(); + if (minecraft.f_91073_ != null && minecraft.f_91074_ != null) { + Biome.Precipitation precipitation = ((Biome)minecraft.f_91073_.m_204166_(minecraft.f_91074_.m_20183_()).m_203334_()).m_264600_(minecraft.f_91074_.m_20183_()); + if (minecraft.f_91073_.m_46471_() || minecraft.f_91073_.m_46470_()) { + return 1.5; + } + } + return 1.0; + } + + public static double computeDustSpeed(double heightPercent) { + if (!((Boolean)Config.CLIENT.enableWindEffect.get()).booleanValue()) { + return 0.0; + } + double baseSpeed = ExplosionWindController.sampleProfile(heightPercent, DUST_SPEEDS); + double weatherMultiplier = ExplosionWindController.getWeatherMultiplier(); + return baseSpeed * (Double)Config.CLIENT.windSpeedMultiplier.get() * weatherMultiplier; + } + + public static double computeGlowSpeed(double heightPercent) { + if (!((Boolean)Config.CLIENT.enableWindEffect.get()).booleanValue()) { + return 0.0; + } + double baseSpeed = ExplosionWindController.sampleProfile(heightPercent, GLOW_SPEEDS); + double weatherMultiplier = ExplosionWindController.getWeatherMultiplier(); + return baseSpeed * (Double)Config.CLIENT.windSpeedMultiplier.get() * weatherMultiplier; + } + + public static Vec3 getDustWindVector(double heightPercent) { + Vec3 direction = ExplosionWindController.getWindDirection(); + if (direction == Vec3.f_82478_) { + return direction; + } + return direction.m_82490_(ExplosionWindController.computeDustSpeed(heightPercent)); + } + + public static Vec3 getGlowWindVector(double heightPercent) { + Vec3 direction = ExplosionWindController.getWindDirection(); + if (direction == Vec3.f_82478_) { + return direction; + } + return direction.m_82490_(ExplosionWindController.computeGlowSpeed(heightPercent)); + } + + private static double sampleProfile(double heightPercent, double[] speeds) { + double clamped = Math.max(0.0, Math.min(1.0, heightPercent)); + for (int i = 1; i < HEIGHT_STOPS.length; ++i) { + double prevStop = HEIGHT_STOPS[i - 1]; + double stop = HEIGHT_STOPS[i]; + if (!(clamped <= stop)) continue; + double t = stop <= prevStop ? 0.0 : (clamped - prevStop) / (stop - prevStop); + double prevValue = speeds[i - 1]; + double value = speeds[i]; + return prevValue + (value - prevValue) * t; + } + return speeds[speeds.length - 1]; + } + + private static Vec3 lerp(Vec3 from, Vec3 to, double factor) { + double clamped = Math.max(0.0, Math.min(1.0, factor)); + double x = from.f_82479_ + (to.f_82479_ - from.f_82479_) * clamped; + double y = from.f_82480_ + (to.f_82480_ - from.f_82480_) * clamped; + double z = from.f_82481_ + (to.f_82481_ - from.f_82481_) * clamped; + return new Vec3(x, y, z); + } + + private static Vec3 randomHorizontalDirection() { + double angle = RANDOM.nextDouble() * Math.PI * 2.0; + double x = Math.cos(angle); + double z = Math.sin(angle); + return new Vec3(x, 0.0, z); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/FadingMusicInstance.java b/src/main/java/com/vinlanx/explosionoverhaul/client/FadingMusicInstance.java new file mode 100644 index 0000000..e169f36 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/FadingMusicInstance.java @@ -0,0 +1,70 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import net.minecraft.client.resources.sounds.AbstractTickableSoundInstance; +import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.RandomSource; + +public class FadingMusicInstance +extends AbstractTickableSoundInstance { + private float targetVolume = 1.0f; + private float fadeSpeed = 0.0f; + private boolean shouldStop = false; + + public FadingMusicInstance(SoundEvent sound, float volume, SoundSource source) { + super(sound, source, RandomSource.m_216327_()); + this.f_119578_ = true; + this.f_119579_ = 0; + this.f_119573_ = volume; + this.f_119574_ = 1.0f; + this.f_119575_ = 0.0; + this.f_119576_ = 0.0; + this.f_119577_ = 0.0; + this.f_119582_ = true; + this.f_119580_ = SoundInstance.Attenuation.NONE; + this.targetVolume = volume; + } + + public void m_7788_() { + if (Math.abs(this.f_119573_ - this.targetVolume) > 0.001f) { + if (this.fadeSpeed != 0.0f) { + this.f_119573_ += this.fadeSpeed; + if (this.fadeSpeed > 0.0f && this.f_119573_ >= this.targetVolume) { + this.f_119573_ = this.targetVolume; + } else if (this.fadeSpeed < 0.0f && this.f_119573_ <= this.targetVolume) { + this.f_119573_ = this.targetVolume; + } + this.f_119573_ = Math.max(0.0f, Math.min(1.0f, this.f_119573_)); + } else { + this.f_119573_ = this.targetVolume; + } + } + if (this.shouldStop && this.f_119573_ <= 0.001f) { + this.m_119609_(); + } + } + + public void fadeTo(float targetVolume, float durationSeconds) { + this.targetVolume = Math.max(0.0f, Math.min(1.0f, targetVolume)); + float totalTicks = durationSeconds * 20.0f; + float volumeDifference = this.targetVolume - this.f_119573_; + this.fadeSpeed = volumeDifference / totalTicks; + } + + public void fadeOutAndStop(float durationSeconds) { + this.fadeTo(0.0f, durationSeconds); + this.shouldStop = true; + } + + public float getCurrentVolume() { + return this.f_119573_; + } + + public boolean hasFinishedFading() { + return this.shouldStop && this.f_119573_ <= 0.001f; + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/FirstTimeScreen.java b/src/main/java/com/vinlanx/explosionoverhaul/client/FirstTimeScreen.java new file mode 100644 index 0000000..0ae9f06 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/FirstTimeScreen.java @@ -0,0 +1,751 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.vinlanx.explosionoverhaul.Config; +import com.vinlanx.explosionoverhaul.ExplosionOverhaul; +import com.vinlanx.explosionoverhaul.ModSounds; +import com.vinlanx.explosionoverhaul.client.BackgroundParticle; +import com.vinlanx.explosionoverhaul.client.ExplosionTextureManager; +import com.vinlanx.explosionoverhaul.client.IntroMusicManager; +import com.vinlanx.explosionoverhaul.client.SpriteSheetAnimator; +import java.util.ArrayList; +import java.util.List; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.TitleScreen; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; + +public class FirstTimeScreen +extends Screen { + private static final ResourceLocation SPRITE_REALISTIC = ResourceLocation.fromNamespaceAndPath((String)"explosionoverhaul", (String)"intro_gui/gui_screen_1.png"); + private static final ResourceLocation SPRITE_VANILLA = ResourceLocation.fromNamespaceAndPath((String)"explosionoverhaul", (String)"intro_gui/gui_screen_2.png"); + private static final ResourceLocation SPRITE_REALISTIC_2 = ResourceLocation.fromNamespaceAndPath((String)"explosionoverhaul", (String)"intro_gui/gui_screen_3.png"); + private static final ResourceLocation SPRITE_STYLE_256 = ResourceLocation.fromNamespaceAndPath((String)"explosionoverhaul", (String)"intro_gui/gui_screen_1.png"); + private static final ResourceLocation SPRITE_STYLE_64 = ResourceLocation.fromNamespaceAndPath((String)"explosionoverhaul", (String)"intro_gui/gui_screen_4.png"); + private static final int FRAME_WIDTH = 854; + private static final int FRAME_HEIGHT = 480; + private static final int COLUMNS = 10; + private static final int ROWS = 10; + private static final int TOTAL_FRAMES = 61; + private static final int FPS = 15; + private static final int COLOR_BG = -15921907; + private static final int COLOR_ACCENT_ORANGE = -881908; + private static final int COLOR_ACCENT_RED = -4250588; + private static final int COLOR_ACCENT_ROSE = -2529701; + private static final int COLOR_ACCENT_DARK_RED = -10939115; + private ScreenState currentState = ScreenState.CHOOSING_MODE; + private Config.Client.ParticleRenderMode selectedRenderMode = null; + private SpriteSheetAnimator realisticAnimator; + private SpriteSheetAnimator vanillaAnimator; + private SpriteSheetAnimator realistic2Animator; + private SpriteSheetAnimator style256Animator; + private SpriteSheetAnimator style64Animator; + private boolean shouldSwitchState = false; + private ScreenState nextState = ScreenState.CHOOSING_MODE; + private int leftBoxX; + private int leftBoxY; + private int leftBoxW; + private int leftBoxH; + private int rightBoxX; + private int rightBoxY; + private int rightBoxW; + private int rightBoxH; + private int bottomBoxX; + private int bottomBoxY; + private int bottomBoxW; + private int bottomBoxH; + private int backButtonX; + private int backButtonY; + private int backButtonW; + private int backButtonH; + private boolean backButtonHovered = false; + private float backButtonScale = 1.0f; + private float leftHoverScale = 1.0f; + private float rightHoverScale = 1.0f; + private float bottomHoverScale = 1.0f; + private static final float HOVER_SCALE_TARGET = 1.05f; + private static final float SCALE_SPEED = 0.15f; + private boolean leftHovered = false; + private boolean rightHovered = false; + private boolean bottomHovered = false; + private long lastFrameTime = System.currentTimeMillis(); + private float transitionAlpha = 1.0f; + private boolean isTransitioning = false; + private static final float TRANSITION_DURATION = 0.8f; + private float transitionTime = 0.0f; + private List particles = new ArrayList(); + private RandomSource random = RandomSource.m_216327_(); + private float backgroundTime = 0.0f; + private IntroMusicManager musicManager; + private static final float FADE_IN_DURATION = 5.0f; + private static final float FADE_OUT_DURATION = 3.0f; + private float fadeTime = 0.0f; + private boolean fadingIn = true; + private boolean fadingOut = false; + private float screenAlpha = 0.0f; + private float fadeOutStartAlpha = 1.0f; + private long fadeOutStartMillis = -1L; + private static final long FORCE_CLOSE_BUFFER_MS = 2000L; + + public FirstTimeScreen() { + super((Component)Component.m_237113_((String)"First Time Setup")); + } + + protected void m_7856_() { + int i; + int displayHeight; + int displayWidth; + super.m_7856_(); + this.fadingIn = true; + this.fadingOut = false; + this.fadeTime = 0.0f; + this.screenAlpha = 0.0f; + this.lastFrameTime = System.currentTimeMillis(); + this.leftHovered = false; + this.rightHovered = false; + this.bottomHovered = false; + this.backButtonHovered = false; + this.backButtonScale = 1.0f; + this.musicManager = IntroMusicManager.getInstance(); + if (this.currentState == ScreenState.CHOOSING_MODE) { + this.realisticAnimator = new SpriteSheetAnimator(SPRITE_REALISTIC, 854, 480, 10, 10, 61, 15); + this.vanillaAnimator = new SpriteSheetAnimator(SPRITE_VANILLA, 854, 480, 10, 10, 61, 15); + this.realistic2Animator = new SpriteSheetAnimator(SPRITE_REALISTIC_2, 854, 480, 10, 10, 61, 15); + this.realisticAnimator.load(); + this.vanillaAnimator.load(); + this.realistic2Animator.load(); + } else if (this.currentState == ScreenState.CHOOSING_STYLE) { + this.style256Animator = new SpriteSheetAnimator(SPRITE_STYLE_256, 854, 480, 10, 10, 61, 15); + this.style64Animator = new SpriteSheetAnimator(SPRITE_STYLE_64, 854, 480, 10, 10, 61, 15); + this.style256Animator.load(); + this.style64Animator.load(); + ExplosionOverhaul.LOGGER.warn("Style selection screen loaded. Ensure gui_screen_4.png and gui_screen_5.png exist in intro_gui folder for proper animations."); + } + int maxWidth = (int)((float)this.f_96543_ * 0.3f); + int maxHeight = (int)((float)this.f_96544_ * 0.44f); + float aspectRatio = 1.7777778f; + if ((float)maxWidth / aspectRatio <= (float)maxHeight) { + displayWidth = maxWidth; + displayHeight = (int)((float)maxWidth / aspectRatio); + } else { + displayHeight = maxHeight; + displayWidth = (int)((float)maxHeight * aspectRatio); + } + if (this.currentState == ScreenState.CHOOSING_MODE) { + gap = (int)((float)this.f_96543_ * 0.03f); + totalWidth = displayWidth * 2 + gap; + startX = (this.f_96543_ - totalWidth) / 2; + startY = (this.f_96544_ - displayHeight) / 2 - (int)((float)this.f_96544_ * 0.15f); + this.leftBoxX = startX; + this.leftBoxY = startY; + this.leftBoxW = displayWidth; + this.leftBoxH = displayHeight; + this.rightBoxX = startX + displayWidth + gap; + this.rightBoxY = startY; + this.rightBoxW = displayWidth; + this.rightBoxH = displayHeight; + this.bottomBoxX = (this.f_96543_ - displayWidth) / 2; + this.bottomBoxY = startY + displayHeight + (int)((float)this.f_96544_ * 0.08f); + this.bottomBoxW = displayWidth; + this.bottomBoxH = displayHeight; + } else if (this.currentState == ScreenState.CHOOSING_STYLE) { + gap = (int)((float)this.f_96543_ * 0.03f); + totalWidth = displayWidth * 2 + gap; + startX = (this.f_96543_ - totalWidth) / 2; + startY = (this.f_96544_ - displayHeight) / 2; + this.leftBoxX = startX; + this.leftBoxY = startY; + this.leftBoxW = displayWidth; + this.leftBoxH = displayHeight; + this.rightBoxX = startX + displayWidth + gap; + this.rightBoxY = startY; + this.rightBoxW = displayWidth; + this.rightBoxH = displayHeight; + this.bottomBoxX = 0; + this.bottomBoxY = 0; + this.bottomBoxW = 0; + this.bottomBoxH = 0; + this.backButtonW = (int)((float)this.f_96543_ * 0.1f); + this.backButtonH = (int)((float)this.f_96544_ * 0.08f); + this.backButtonX = (int)((float)this.f_96543_ * 0.02f); + this.backButtonY = this.f_96544_ - this.backButtonH - (int)((float)this.f_96544_ * 0.02f); + } + for (i = 0; i < 40; ++i) { + this.particles.add(BackgroundParticle.createSpark(this.random, this.f_96543_, this.f_96544_)); + } + for (i = 0; i < 15; ++i) { + this.particles.add(BackgroundParticle.createEmber(this.random, this.f_96543_, this.f_96544_)); + } + for (i = 0; i < 8; ++i) { + this.particles.add(BackgroundParticle.createSmoke(this.random, this.f_96543_, this.f_96544_)); + } + } + + public void m_86600_() { + float progress; + super.m_86600_(); + long currentTime = System.currentTimeMillis(); + float rawDeltaTime = (float)(currentTime - this.lastFrameTime) / 1000.0f; + this.lastFrameTime = currentTime; + float deltaTime = Math.min(rawDeltaTime, 0.1f); + this.backgroundTime += deltaTime; + if (this.isTransitioning) { + this.transitionTime += deltaTime; + progress = Math.min(1.0f, this.transitionTime / 0.8f); + if (this.transitionTime < 0.4f) { + this.transitionAlpha = 1.0f - progress * 2.0f; + } else { + this.transitionAlpha = (progress - 0.5f) * 2.0f; + if (this.transitionTime >= 0.4f && !this.shouldSwitchState) { + this.shouldSwitchState = true; + if (this.currentState == ScreenState.CHOOSING_MODE) { + if (this.realisticAnimator != null) { + this.realisticAnimator.close(); + } + if (this.vanillaAnimator != null) { + this.vanillaAnimator.close(); + } + if (this.realistic2Animator != null) { + this.realistic2Animator.close(); + } + this.nextState = ScreenState.CHOOSING_STYLE; + } else if (this.currentState == ScreenState.CHOOSING_STYLE) { + if (this.style256Animator != null) { + this.style256Animator.close(); + } + if (this.style64Animator != null) { + this.style64Animator.close(); + } + this.nextState = ScreenState.CHOOSING_MODE; + } + this.currentState = this.nextState; + this.m_7856_(); + } + } + if (this.transitionTime >= 0.8f) { + this.isTransitioning = false; + this.transitionAlpha = 1.0f; + this.transitionTime = 0.0f; + this.shouldSwitchState = false; + } + } + if (this.fadingIn) { + this.fadeTime += deltaTime; + progress = Math.min(1.0f, this.fadeTime / 5.0f); + this.screenAlpha = this.easeOutCubic(progress); + if (this.fadeTime >= 5.0f) { + this.fadingIn = false; + this.screenAlpha = 1.0f; + } + } else if (this.fadingOut) { + long threshold; + long elapsed; + this.fadeTime += deltaTime; + progress = Math.min(1.0f, this.fadeTime / 3.0f); + this.screenAlpha = this.fadeOutStartAlpha * (1.0f - this.easeInCubic(progress)); + if (this.fadeTime >= 3.0f) { + boolean musicStillFading; + boolean bl = musicStillFading = this.musicManager != null && this.musicManager.isFadingOut(); + if (!musicStillFading) { + ExplosionOverhaul.LOGGER.info("Screen and music fade out complete. Opening TitleScreen."); + this.cleanupAnimators(); + Minecraft.m_91087_().m_91152_((Screen)new TitleScreen()); + } else { + ExplosionOverhaul.LOGGER.info("Waiting for music to finish fading..."); + } + } + if (this.fadeOutStartMillis > 0L && (elapsed = System.currentTimeMillis() - this.fadeOutStartMillis) > (threshold = 5000L)) { + ExplosionOverhaul.LOGGER.warn("Fade out timeout exceeded ({} ms). Forcing close and opening TitleScreen.", (Object)elapsed); + if (this.musicManager != null) { + this.musicManager.stop(); + } + this.cleanupAnimators(); + this.fadingOut = false; + this.fadeOutStartMillis = -1L; + Minecraft.m_91087_().m_91152_((Screen)new TitleScreen()); + return; + } + } + if (this.musicManager != null) { + this.musicManager.tick(deltaTime); + } + if (this.currentState == ScreenState.CHOOSING_MODE) { + if (this.realisticAnimator != null) { + this.realisticAnimator.tick(deltaTime); + } + if (this.vanillaAnimator != null) { + this.vanillaAnimator.tick(deltaTime); + } + if (this.realistic2Animator != null) { + this.realistic2Animator.tick(deltaTime); + } + } else if (this.currentState == ScreenState.CHOOSING_STYLE) { + if (this.style256Animator != null) { + this.style256Animator.tick(deltaTime); + } + if (this.style64Animator != null) { + this.style64Animator.tick(deltaTime); + } + } + this.leftHoverScale = Mth.m_14179_((float)0.15f, (float)this.leftHoverScale, (float)(this.leftHovered ? 1.05f : 1.0f)); + this.rightHoverScale = Mth.m_14179_((float)0.15f, (float)this.rightHoverScale, (float)(this.rightHovered ? 1.05f : 1.0f)); + this.bottomHoverScale = Mth.m_14179_((float)0.15f, (float)this.bottomHoverScale, (float)(this.bottomHovered ? 1.05f : 1.0f)); + this.particles.removeIf(p -> { + p.tick(deltaTime); + return p.isDead() || p.x < -50.0f || p.x > (float)(this.f_96543_ + 50) || p.y < -50.0f || p.y > (float)(this.f_96544_ + 50); + }); + if (this.random.m_188501_() < 0.15f) { + this.particles.add(BackgroundParticle.createSpark(this.random, this.f_96543_, this.f_96544_)); + } + if (this.random.m_188501_() < 0.05f) { + this.particles.add(BackgroundParticle.createEmber(this.random, this.f_96543_, this.f_96544_)); + } + if (this.random.m_188501_() < 0.02f) { + this.particles.add(BackgroundParticle.createSmoke(this.random, this.f_96543_, this.f_96544_)); + } + if (this.random.m_188501_() < 0.01f) { + this.particles.add(BackgroundParticle.createFlash(this.random, this.f_96543_, this.f_96544_)); + } + } + + private void cleanupAnimators() { + if (this.realisticAnimator != null) { + this.realisticAnimator.close(); + } + if (this.vanillaAnimator != null) { + this.vanillaAnimator.close(); + } + if (this.realistic2Animator != null) { + this.realistic2Animator.close(); + } + if (this.style256Animator != null) { + this.style256Animator.close(); + } + if (this.style64Animator != null) { + this.style64Animator.close(); + } + } + + public void m_88315_(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) { + graphics.m_280509_(0, 0, this.f_96543_, this.f_96544_, -16777216); + if (this.screenAlpha < 0.01f) { + return; + } + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + float renderAlpha = this.screenAlpha * this.transitionAlpha; + RenderSystem.setShaderColor((float)1.0f, (float)1.0f, (float)1.0f, (float)renderAlpha); + graphics.m_280168_().m_85836_(); + this.renderCinematicBackground(graphics, partialTick, renderAlpha); + if (this.currentState == ScreenState.CHOOSING_MODE) { + this.renderModeSelection(graphics, mouseX, mouseY, renderAlpha); + } else if (this.currentState == ScreenState.CHOOSING_STYLE) { + this.renderStyleSelection(graphics, mouseX, mouseY, renderAlpha); + } + graphics.m_280168_().m_85849_(); + RenderSystem.setShaderColor((float)1.0f, (float)1.0f, (float)1.0f, (float)1.0f); + super.m_88315_(graphics, mouseX, mouseY, partialTick); + } + + private void renderModeSelection(GuiGraphics graphics, int mouseX, int mouseY, float renderAlpha) { + String title = "Choose Your Explosion Style"; + int titleWidth = this.f_96547_.m_92895_(title); + int titleX = (this.f_96543_ - titleWidth) / 2; + int titleY = this.leftBoxY - 40; + int titleAlpha = (int)(renderAlpha * 255.0f) << 24; + graphics.m_280056_(this.f_96547_, title, titleX + 2, titleY + 2, 0xF28B0C | (int)(64.0f * renderAlpha) << 24, false); + graphics.m_280056_(this.f_96547_, title, titleX + 1, titleY + 1, 0xF28B0C | (int)(128.0f * renderAlpha) << 24, false); + graphics.m_280056_(this.f_96547_, title, titleX, titleY, 0xF28B0C | titleAlpha, true); + String subtitle = "You can change this anytime in the config"; + int subtitleWidth = this.f_96547_.m_92895_(subtitle); + graphics.m_280056_(this.f_96547_, subtitle, (this.f_96543_ - subtitleWidth) / 2, titleY + 15, 0xCCCCCC | titleAlpha, false); + String psNote = "P.S. Colors in the game may differ from the animations because compression has altered the colors"; + int psWidth = this.f_96547_.m_92895_(psNote); + int psColor = 0x999999 | titleAlpha; + graphics.m_280056_(this.f_96547_, psNote, (this.f_96543_ - psWidth) / 2, titleY + 30, psColor, false); + if (!this.isTransitioning) { + boolean wasLeftHovered = this.leftHovered; + boolean wasRightHovered = this.rightHovered; + boolean wasBottomHovered = this.bottomHovered; + this.leftHovered = this.isMouseOver(mouseX, mouseY, this.leftBoxX, this.leftBoxY, this.leftBoxW, this.leftBoxH); + this.rightHovered = this.isMouseOver(mouseX, mouseY, this.rightBoxX, this.rightBoxY, this.rightBoxW, this.rightBoxH); + this.bottomHovered = this.isMouseOver(mouseX, mouseY, this.bottomBoxX, this.bottomBoxY, this.bottomBoxW, this.bottomBoxH); + if (this.leftHovered && !wasLeftHovered) { + this.realisticAnimator.reset(); + this.realisticAnimator.play(); + } else if (!this.leftHovered && wasLeftHovered) { + this.realisticAnimator.reset(); + } + if (this.rightHovered && !wasRightHovered) { + this.vanillaAnimator.reset(); + this.vanillaAnimator.play(); + } else if (!this.rightHovered && wasRightHovered) { + this.vanillaAnimator.reset(); + } + if (this.bottomHovered && !wasBottomHovered) { + this.realistic2Animator.reset(); + this.realistic2Animator.play(); + } else if (!this.bottomHovered && wasBottomHovered) { + this.realistic2Animator.reset(); + } + } + this.renderBox(graphics, this.leftBoxX, this.leftBoxY, this.leftBoxW, this.leftBoxH, this.leftHoverScale, this.realisticAnimator, "REALISTIC", this.leftHovered, -881908, renderAlpha); + this.renderBox(graphics, this.rightBoxX, this.rightBoxY, this.rightBoxW, this.rightBoxH, this.rightHoverScale, this.vanillaAnimator, "VANILLA-LIKE", this.rightHovered, -4250588, renderAlpha); + this.renderBox(graphics, this.bottomBoxX, this.bottomBoxY, this.bottomBoxW, this.bottomBoxH, this.bottomHoverScale, this.realistic2Animator, "REALISTIC 2", this.bottomHovered, -2529701, renderAlpha); + } + + private void renderStyleSelection(GuiGraphics graphics, int mouseX, int mouseY, float renderAlpha) { + String title = "Choose Render Style"; + int titleWidth = this.f_96547_.m_92895_(title); + int titleX = (this.f_96543_ - titleWidth) / 2; + int titleY = this.leftBoxY - 40; + int titleAlpha = (int)(renderAlpha * 255.0f) << 24; + graphics.m_280056_(this.f_96547_, title, titleX + 2, titleY + 2, 0xF28B0C | (int)(64.0f * renderAlpha) << 24, false); + graphics.m_280056_(this.f_96547_, title, titleX + 1, titleY + 1, 0xF28B0C | (int)(128.0f * renderAlpha) << 24, false); + graphics.m_280056_(this.f_96547_, title, titleX, titleY, 0xF28B0C | titleAlpha, true); + String subtitle = "Higher quality requires more VRAM"; + int subtitleWidth = this.f_96547_.m_92895_(subtitle); + graphics.m_280056_(this.f_96547_, subtitle, (this.f_96543_ - subtitleWidth) / 2, titleY + 15, 0xCCCCCC | titleAlpha, false); + if (!this.isTransitioning) { + boolean wasLeftHovered = this.leftHovered; + boolean wasRightHovered = this.rightHovered; + boolean wasBackHovered = this.backButtonHovered; + this.leftHovered = this.isMouseOver(mouseX, mouseY, this.leftBoxX, this.leftBoxY, this.leftBoxW, this.leftBoxH); + this.rightHovered = this.isMouseOver(mouseX, mouseY, this.rightBoxX, this.rightBoxY, this.rightBoxW, this.rightBoxH); + this.backButtonHovered = this.isMouseOver(mouseX, mouseY, this.backButtonX, this.backButtonY, this.backButtonW, this.backButtonH); + this.bottomHovered = false; + if (this.leftHovered && !wasLeftHovered) { + this.style256Animator.reset(); + this.style256Animator.play(); + } else if (!this.leftHovered && wasLeftHovered) { + this.style256Animator.reset(); + } + if (this.rightHovered && !wasRightHovered) { + this.style64Animator.reset(); + this.style64Animator.play(); + } else if (!this.rightHovered && wasRightHovered) { + this.style64Animator.reset(); + } + if (this.backButtonHovered && !wasBackHovered || this.backButtonHovered || wasBackHovered) { + // empty if block + } + } + this.backButtonScale = Mth.m_14179_((float)0.15f, (float)this.backButtonScale, (float)(this.backButtonHovered ? 1.05f : 1.0f)); + this.renderBox(graphics, this.leftBoxX, this.leftBoxY, this.leftBoxW, this.leftBoxH, this.leftHoverScale, this.style256Animator, "256 PIXELS", this.leftHovered, -881908, renderAlpha); + this.renderBox(graphics, this.rightBoxX, this.rightBoxY, this.rightBoxW, this.rightBoxH, this.rightHoverScale, this.style64Animator, "64 PIXELS", this.rightHovered, -4250588, renderAlpha); + this.renderBackButton(graphics, renderAlpha); + } + + private void renderBox(GuiGraphics graphics, int x, int y, int width, int height, float scale, SpriteSheetAnimator animator, String label, boolean hovered, int accentColor, float alpha) { + graphics.m_280168_().m_85836_(); + int centerX = x + width / 2; + int centerY = y + height / 2; + graphics.m_280168_().m_252880_((float)centerX, (float)centerY, 0.0f); + graphics.m_280168_().m_85841_(scale, scale, 1.0f); + graphics.m_280168_().m_252880_((float)(-width / 2), (float)(-height / 2), 0.0f); + if (hovered) { + int glowSize = 4; + int glowAlpha = (int)(128.0f * alpha) << 24; + graphics.m_280509_(-glowSize, -glowSize, width + glowSize, height + glowSize, accentColor & 0xFFFFFF | glowAlpha); + } + int bgAlpha = (int)(255.0f * alpha) << 24; + graphics.m_280509_(0, 0, width, height, 0x591515 | bgAlpha); + if (animator != null && animator.getTextureLocation() != null) { + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + RenderSystem.setShaderColor((float)1.0f, (float)1.0f, (float)1.0f, (float)alpha); + RenderSystem.setShaderTexture((int)0, (ResourceLocation)animator.getTextureLocation()); + graphics.m_280163_(animator.getTextureLocation(), 0, 0, 0.0f, 0.0f, width, height, width, height); + RenderSystem.setShaderColor((float)1.0f, (float)1.0f, (float)1.0f, (float)1.0f); + } else { + int placeholderTextColor = (int)(150.0f * alpha) << 24 | 0xFFFFFFFF; + String placeholder = "[Image not found]"; + int placeholderWidth = this.f_96547_.m_92895_(placeholder); + graphics.m_280056_(this.f_96547_, placeholder, (width - placeholderWidth) / 2, height / 2 - 5, placeholderTextColor, false); + } + int borderColor = hovered ? accentColor : -2529701; + int borderAlpha = (int)(255.0f * alpha) << 24; + int fadedBorderColor = borderColor & 0xFFFFFF | borderAlpha; + graphics.m_280509_(0, 0, width, 2, fadedBorderColor); + graphics.m_280509_(0, height - 2, width, height, fadedBorderColor); + graphics.m_280509_(0, 0, 2, height, fadedBorderColor); + graphics.m_280509_(width - 2, 0, width, height, fadedBorderColor); + graphics.m_280168_().m_85849_(); + int labelAlpha = (int)(255.0f * alpha) << 24; + int labelColor = hovered ? accentColor : -1; + int fadedLabelColor = labelColor & 0xFFFFFF | labelAlpha; + int labelWidth = this.f_96547_.m_92895_(label); + graphics.m_280056_(this.f_96547_, label, x + (width - labelWidth) / 2, y + height + 10, fadedLabelColor, true); + } + + public boolean m_6375_(double mouseX, double mouseY, int button) { + if (this.fadingOut || this.isTransitioning) { + return true; + } + if (button == 0) { + if (this.currentState == ScreenState.CHOOSING_MODE) { + if (this.isMouseOver((int)mouseX, (int)mouseY, this.leftBoxX, this.leftBoxY, this.leftBoxW, this.leftBoxH)) { + this.selectRealisticMode(); + return true; + } + if (this.isMouseOver((int)mouseX, (int)mouseY, this.rightBoxX, this.rightBoxY, this.rightBoxW, this.rightBoxH)) { + this.selectVanillaLike(); + return true; + } + if (this.isMouseOver((int)mouseX, (int)mouseY, this.bottomBoxX, this.bottomBoxY, this.bottomBoxW, this.bottomBoxH)) { + this.selectRealistic2Mode(); + return true; + } + } else if (this.currentState == ScreenState.CHOOSING_STYLE) { + if (this.isMouseOver((int)mouseX, (int)mouseY, this.leftBoxX, this.leftBoxY, this.leftBoxW, this.leftBoxH)) { + this.selectStyle256(); + return true; + } + if (this.isMouseOver((int)mouseX, (int)mouseY, this.rightBoxX, this.rightBoxY, this.rightBoxW, this.rightBoxH)) { + this.selectStyle64(); + return true; + } + if (this.isMouseOver((int)mouseX, (int)mouseY, this.backButtonX, this.backButtonY, this.backButtonW, this.backButtonH)) { + this.goBack(); + return true; + } + } + } + return super.m_6375_(mouseX, mouseY, button); + } + + private void selectRealisticMode() { + this.playButtonSound(); + this.selectedRenderMode = Config.Client.ParticleRenderMode.REALISTIC; + this.isTransitioning = true; + this.transitionTime = 0.0f; + this.transitionAlpha = 1.0f; + } + + private void selectRealistic2Mode() { + this.playButtonSound(); + this.selectedRenderMode = Config.Client.ParticleRenderMode.REALISTIC_2; + this.isTransitioning = true; + this.transitionTime = 0.0f; + this.transitionAlpha = 1.0f; + } + + private void selectStyle256() { + this.playButtonSound(); + Config.CLIENT.glowTextureQuality.set((Object)Config.Client.GlowTextureQuality.QUALITY_256); + Config.CLIENT.particleRenderMode.set((Object)this.selectedRenderMode); + this.saveAndClose(); + } + + private void selectStyle64() { + this.playButtonSound(); + Config.CLIENT.glowTextureQuality.set((Object)Config.Client.GlowTextureQuality.QUALITY_64); + Config.CLIENT.particleRenderMode.set((Object)this.selectedRenderMode); + this.saveAndClose(); + } + + private boolean isMouseOver(int mouseX, int mouseY, int x, int y, int width, int height) { + return mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height; + } + + private void selectVanillaLike() { + this.playButtonSound(); + Config.CLIENT.particleRenderMode.set((Object)Config.Client.ParticleRenderMode.VANILA); + this.saveAndClose(); + } + + private void goBack() { + this.playButtonSound(); + this.isTransitioning = true; + this.transitionTime = 0.0f; + this.transitionAlpha = 1.0f; + this.selectedRenderMode = null; + } + + private void saveAndClose() { + Config.CLIENT.firstLaunchComplete.set((Object)true); + Config.CLIENT_SPEC.save(); + ExplosionTextureManager.getInstance().reload(); + if (this.musicManager != null && this.musicManager.isPlaying()) { + ExplosionOverhaul.LOGGER.info("Starting music and screen fade out (duration: {} seconds)", (Object)Float.valueOf(3.0f)); + this.musicManager.startFadeOut(); + } + if (this.fadingIn) { + this.fadingIn = false; + ExplosionOverhaul.LOGGER.info("Interrupting fade in (was at {:.1f}%) to start fade out from current alpha", (Object)Float.valueOf(this.screenAlpha * 100.0f)); + } + this.fadeOutStartAlpha = this.screenAlpha; + this.fadingOut = true; + this.fadeTime = 0.0f; + this.fadeOutStartMillis = System.currentTimeMillis(); + } + + private void renderCinematicBackground(GuiGraphics graphics, float partialTick, float globalAlpha) { + int i; + int bgAlpha1; + int bgColor1 = bgAlpha1 = (int)(255.0f * globalAlpha) << 24; + int bgColor2 = 0xD0D0D | bgAlpha1; + graphics.m_280024_(0, 0, this.f_96543_, this.f_96544_ / 2, bgColor1, bgColor2); + graphics.m_280024_(0, this.f_96544_ / 2, this.f_96543_, this.f_96544_, bgColor2, bgColor1); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + for (BackgroundParticle p : this.particles) { + float particleAlpha = p.getAlpha(); + float finalAlpha = particleAlpha * globalAlpha; + int colorWithAlpha = p.color & 0xFFFFFF | (int)(finalAlpha * 255.0f) << 24; + switch (p.type) { + case SPARK: { + float sparkLen = p.size * 3.0f; + float sparkAngle = (float)Math.atan2(p.vy, p.vx); + int ex = (int)((double)p.x + Math.cos(sparkAngle) * (double)sparkLen); + int ey = (int)((double)p.y + Math.sin(sparkAngle) * (double)sparkLen); + this.drawLine(graphics, (int)p.x, (int)p.y, ex, ey, colorWithAlpha); + break; + } + case EMBER: { + int emberSize = (int)p.size; + graphics.m_280509_((int)p.x - emberSize, (int)p.y - emberSize, (int)p.x + emberSize, (int)p.y + emberSize, colorWithAlpha); + break; + } + case FLASH: { + int flashSize = (int)(p.size * 0.7f); + int flashColor = colorWithAlpha & 0xFFFFFF | (int)(finalAlpha * 180.0f) << 24; + graphics.m_280509_((int)p.x - flashSize, (int)p.y - flashSize, (int)p.x + flashSize, (int)p.y + flashSize, flashColor); + break; + } + case SMOKE: { + int smokeSize = (int)p.size; + int smokeColor = colorWithAlpha & 0xFFFFFF | (int)(finalAlpha * 60.0f) << 24; + graphics.m_280509_((int)p.x - smokeSize, (int)p.y - smokeSize, (int)p.x + smokeSize, (int)p.y + smokeSize, smokeColor); + } + } + } + int vignetteSteps = 15; + for (i = 0; i < vignetteSteps; ++i) { + float ratio = (float)i / (float)vignetteSteps; + int vignetteAlpha = (int)(ratio * ratio * 180.0f * globalAlpha); + int vignetteColor = vignetteAlpha << 24; + int thickness = 4; + graphics.m_280509_(0, i * thickness, this.f_96543_, (i + 1) * thickness, vignetteColor); + graphics.m_280509_(0, this.f_96544_ - (i + 1) * thickness, this.f_96543_, this.f_96544_ - i * thickness, vignetteColor); + graphics.m_280509_(i * thickness, 0, (i + 1) * thickness, this.f_96544_, vignetteColor); + graphics.m_280509_(this.f_96543_ - (i + 1) * thickness, 0, this.f_96543_ - i * thickness, this.f_96544_, vignetteColor); + } + for (i = 0; i < 150; ++i) { + int gx = this.random.m_188503_(this.f_96543_); + int gy = this.random.m_188503_(this.f_96544_); + int grainAlpha = (int)((float)(20 + this.random.m_188503_(30)) * globalAlpha); + int grainColor = grainAlpha << 24 | 0xFFFFFF; + graphics.m_280509_(gx, gy, gx + 1, gy + 1, grainColor); + } + for (int y = 0; y < this.f_96544_; y += 4) { + graphics.m_280509_(0, y, this.f_96543_, y + 1, 0x8000000); + } + RenderSystem.disableBlend(); + } + + private void drawLine(GuiGraphics graphics, int x1, int y1, int x2, int y2, int color) { + int dx = Math.abs(x2 - x1); + int dy = Math.abs(y2 - y1); + int sx = x1 < x2 ? 1 : -1; + int sy = y1 < y2 ? 1 : -1; + int err = dx - dy; + for (int steps = 0; steps < 200; ++steps) { + graphics.m_280509_(x1, y1, x1 + 1, y1 + 1, color); + if (x1 == x2 && y1 == y2) break; + int e2 = 2 * err; + if (e2 > -dy) { + err -= dy; + x1 += sx; + } + if (e2 >= dx) continue; + err += dx; + y1 += sy; + } + } + + public void m_7379_() { + if (!this.fadingOut) { + this.cleanupAnimators(); + super.m_7379_(); + } + } + + public boolean m_7933_(int keyCode, int scanCode, int modifiers) { + if (keyCode == 256) { + return true; + } + return super.m_7933_(keyCode, scanCode, modifiers); + } + + public boolean m_7043_() { + return true; + } + + private float easeOutCubic(float x) { + return 1.0f - (float)Math.pow(1.0f - x, 3.0); + } + + private float easeInCubic(float x) { + return x * x * x; + } + + private void renderBackButton(GuiGraphics graphics, float alpha) { + graphics.m_280168_().m_85836_(); + int centerX = this.backButtonX + this.backButtonW / 2; + int centerY = this.backButtonY + this.backButtonH / 2; + graphics.m_280168_().m_252880_((float)centerX, (float)centerY, 0.0f); + graphics.m_280168_().m_85841_(this.backButtonScale, this.backButtonScale, 1.0f); + graphics.m_280168_().m_252880_((float)(-this.backButtonW / 2), (float)(-this.backButtonH / 2), 0.0f); + if (this.backButtonHovered) { + int glowSize = 3; + int glowAlpha = (int)(128.0f * alpha) << 24; + graphics.m_280509_(-glowSize, -glowSize, this.backButtonW + glowSize, this.backButtonH + glowSize, 0xF28B0C | glowAlpha); + } + int bgAlpha = (int)(255.0f * alpha) << 24; + graphics.m_280509_(0, 0, this.backButtonW, this.backButtonH, 0x591515 | bgAlpha); + int borderColor = this.backButtonHovered ? -881908 : -2529701; + int borderAlpha = (int)(255.0f * alpha) << 24; + int fadedBorderColor = borderColor & 0xFFFFFF | borderAlpha; + graphics.m_280509_(0, 0, this.backButtonW, 2, fadedBorderColor); + graphics.m_280509_(0, this.backButtonH - 2, this.backButtonW, this.backButtonH, fadedBorderColor); + graphics.m_280509_(0, 0, 2, this.backButtonH, fadedBorderColor); + graphics.m_280509_(this.backButtonW - 2, 0, this.backButtonW, this.backButtonH, fadedBorderColor); + graphics.m_280168_().m_85849_(); + String buttonText = "BACK"; + int textWidth = this.f_96547_.m_92895_(buttonText); + int textColor = this.backButtonHovered ? -881908 : -1; + int textAlpha = (int)(255.0f * alpha) << 24; + int fadedTextColor = textColor & 0xFFFFFF | textAlpha; + graphics.m_280056_(this.f_96547_, buttonText, this.backButtonX + (this.backButtonW - textWidth) / 2, this.backButtonY + (this.backButtonH - 8) / 2, fadedTextColor, true); + } + + private void playButtonSound() { + try { + Minecraft minecraft = Minecraft.m_91087_(); + if (minecraft.m_91106_() != null) { + minecraft.m_91106_().m_120367_((SoundInstance)SimpleSoundInstance.m_119755_((SoundEvent)((SoundEvent)ModSounds.BUTTON_SOUND.get()), (float)1.0f, (float)1.0f)); + } + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to play button sound", (Throwable)e); + } + } + + private static enum ScreenState { + CHOOSING_MODE, + CHOOSING_STYLE, + FADING_OUT; + + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/FirstTimeSetupHandler.java b/src/main/java/com/vinlanx/explosionoverhaul/client/FirstTimeSetupHandler.java new file mode 100644 index 0000000..0bd752a --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/FirstTimeSetupHandler.java @@ -0,0 +1,48 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.vinlanx.explosionoverhaul.Config; +import com.vinlanx.explosionoverhaul.ExplosionOverhaul; +import com.vinlanx.explosionoverhaul.client.IntroSplashScreen; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.TitleScreen; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.neoforge.event.TickEvent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; + +@Mod.EventBusSubscriber(modid="explosionoverhaul", bus=Mod.EventBusSubscriber.Bus.FORGE, value={Dist.CLIENT}) +public class FirstTimeSetupHandler { + private static boolean hasChecked = false; + private static boolean pendingShowIntro = false; + + @SubscribeEvent + public static void onClientTick(TickEvent.ClientTickEvent event) { + if (event.phase != TickEvent.Phase.END) { + return; + } + Minecraft mc = Minecraft.m_91087_(); + if (!hasChecked && mc.f_91080_ instanceof TitleScreen) { + hasChecked = true; + ExplosionOverhaul.LOGGER.info("Detected TitleScreen on client, hasChecked=true"); + if (Config.isFirstLaunch()) { + pendingShowIntro = true; + } + } + if (!pendingShowIntro) { + return; + } + if (mc.f_91080_ instanceof TitleScreen) { + pendingShowIntro = false; + ExplosionOverhaul.LOGGER.info("Showing IntroSplashScreen (first launch)"); + mc.m_91152_((Screen)new IntroSplashScreen()); + } + } + + static { + ExplosionOverhaul.LOGGER.info("FirstTimeSetupHandler class loaded (waiting for TitleScreen)"); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/GroundDustEffect.java b/src/main/java/com/vinlanx/explosionoverhaul/client/GroundDustEffect.java new file mode 100644 index 0000000..d55018b --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/GroundDustEffect.java @@ -0,0 +1,173 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.vinlanx.explosionoverhaul.Config; +import com.vinlanx.explosionoverhaul.SmokeParticleOptions; +import com.vinlanx.explosionoverhaul.client.ExplosionWindController; +import java.awt.Color; +import java.util.Random; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.tags.BlockTags; +import net.minecraft.util.Mth; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.MapColor; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +public class GroundDustEffect { + private final ClientLevel level; + private final Vec3 initialPosition; + private final float power; + private final Random random = new Random(); + private int age = 0; + private final int maxAge; + private final float maxRadius; + private final float particleBaseSize; + private final int particlesPerTick; + private Color currentDustColor = new Color(128, 128, 128); + private boolean finished = false; + private final int raycastFrequency; + + public GroundDustEffect(Vec3 position, float power) { + this.level = Minecraft.m_91087_().f_91073_; + this.initialPosition = position; + this.power = power; + double qualityMultiplier = (Double)Config.CLIENT.groundDustQuality.get(); + this.raycastFrequency = (Integer)Config.CLIENT.groundDustRaycastFrequency.get(); + float powerFraction = Mth.m_14036_((float)(power / 100.0f), (float)0.0f, (float)1.0f); + int calculatedParticles = (int)((double)Mth.m_14179_((float)powerFraction, (float)40.0f, (float)200.0f) * qualityMultiplier); + int calculatedMaxAge = (int)((double)Mth.m_14179_((float)powerFraction, (float)30.0f, (float)70.0f) * qualityMultiplier); + if (qualityMultiplier > 0.0) { + if (calculatedParticles == 0) { + calculatedParticles = 1; + } + if (calculatedMaxAge == 0) { + calculatedMaxAge = 1; + } + } + this.particlesPerTick = calculatedParticles; + this.maxAge = calculatedMaxAge; + this.maxRadius = power * this.calculateRadiusMultiplier(power); + this.particleBaseSize = Mth.m_14179_((float)powerFraction, (float)1.0f, (float)12.0f); + } + + private 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 Color getDustColorForState(BlockState state) { + if (state.m_204336_(BlockTags.f_13035_) || state.m_284242_((BlockGetter)this.level, BlockPos.f_121853_) == MapColor.f_283808_) { + return null; + } + if (state.m_60713_(Blocks.f_50440_)) { + return new Color(Blocks.f_50493_.m_49966_().m_284242_((BlockGetter)this.level, (BlockPos)BlockPos.f_121853_).f_283871_); + } + if (state.m_60713_(Blocks.f_50125_) || state.m_60713_(Blocks.f_50127_)) { + return new Color(Blocks.f_50127_.m_49966_().m_284242_((BlockGetter)this.level, (BlockPos)BlockPos.f_121853_).f_283871_); + } + return new Color(state.m_284242_((BlockGetter)this.level, (BlockPos)BlockPos.f_121853_).f_283871_); + } + + public void tick() { + BlockPos blockPos; + BlockState blockState; + Color newColor; + double checkZ; + double checkAngle; + double checkX; + BlockHitResult hitResult; + if (this.finished || this.level == null) { + return; + } + ++this.age; + if (this.age > this.maxAge) { + this.finished = true; + return; + } + float progress = (float)this.age / (float)this.maxAge; + float easedProgress = 1.0f - (float)Math.pow(1.0f - progress, 3.0); + float currentRadius = this.maxRadius * easedProgress; + if (this.age % 10 == 0 && (hitResult = this.level.m_45547_(new ClipContext(new Vec3(checkX = this.initialPosition.f_82479_ + Math.cos(checkAngle = this.random.nextDouble() * 2.0 * Math.PI) * (double)currentRadius, this.initialPosition.f_82480_ + 15.0, checkZ = this.initialPosition.f_82481_ + Math.sin(checkAngle) * (double)currentRadius), new Vec3(checkX, this.initialPosition.f_82480_ - 15.0, checkZ), ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, null))).m_6662_() == HitResult.Type.BLOCK && (newColor = this.getDustColorForState(blockState = this.level.m_8055_(blockPos = hitResult.m_82425_()))) != null) { + this.currentDustColor = newColor; + } + double cachedY = this.initialPosition.f_82480_; + for (int i = 0; i < this.particlesPerTick; ++i) { + float scale; + float a; + float r; + float g; + float b; + double angle = (double)i / (double)this.particlesPerTick * 2.0 * Math.PI + (this.random.nextDouble() - 0.5) * 0.1; + double radiusFrac = this.random.nextDouble(); + double spawnRadius = (double)currentRadius * (0.6 + radiusFrac * 0.4); + double spawnX = this.initialPosition.f_82479_ + Math.cos(angle) * spawnRadius; + double spawnZ = this.initialPosition.f_82481_ + Math.sin(angle) * spawnRadius; + if (i % this.raycastFrequency == 0) { + BlockHitResult hitResult2 = this.level.m_45547_(new ClipContext(new Vec3(spawnX, this.initialPosition.f_82480_ + 15.0, spawnZ), new Vec3(spawnX, this.initialPosition.f_82480_ - 15.0, spawnZ), ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, null)); + if (hitResult2.m_6662_() != HitResult.Type.BLOCK) continue; + cachedY = hitResult2.m_82450_().f_82480_; + } + double spawnY = cachedY; + Vec3 direction = new Vec3(spawnX - this.initialPosition.f_82479_, 0.0, spawnZ - this.initialPosition.f_82481_).m_82541_(); + double motionStrength = Mth.m_14179_((float)(1.0f - progress), (float)0.05f, (float)0.45f); + double motionX = direction.f_82479_ * motionStrength + (this.random.nextDouble() - 0.5) * 0.05; + double motionZ = direction.f_82481_ * motionStrength + (this.random.nextDouble() - 0.5) * 0.05; + double motionY = (this.random.nextDouble() - 0.5) * 0.02; + double heightPercent = 0.0; + Vec3 windDirection = ExplosionWindController.getWindDirection(); + double windSpeed = ExplosionWindController.computeDustSpeed(0.0); + double initialBoostFactor = 0.65; + if (windDirection != Vec3.f_82478_ && windSpeed > 0.0) { + motionX += windDirection.f_82479_ * windSpeed * initialBoostFactor; + motionZ += windDirection.f_82481_ * windSpeed * initialBoostFactor; + } + int lifetime = 100 + this.random.nextInt(60); + if (radiusFrac <= 0.2) { + b = 0.2f; + g = 0.2f; + r = 0.2f; + a = 0.9f; + scale = this.particleBaseSize * 0.5f; + } else if (radiusFrac <= 0.65) { + b = 0.4f; + g = 0.4f; + r = 0.4f; + a = 0.6f; + scale = this.particleBaseSize * 0.75f; + } else { + r = (float)this.currentDustColor.getRed() / 255.0f; + g = (float)this.currentDustColor.getGreen() / 255.0f; + b = (float)this.currentDustColor.getBlue() / 255.0f; + a = 0.35f; + scale = this.particleBaseSize; + } + SmokeParticleOptions options = new SmokeParticleOptions(scale * (0.8f + this.random.nextFloat() * 0.4f), lifetime, r, g, b, a, false, (float)windSpeed, (float)heightPercent, null); + this.level.m_6493_((ParticleOptions)options, true, spawnX, spawnY + 0.2, spawnZ, motionX, motionY, motionZ); + } + } + + public boolean isFinished() { + return this.finished; + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/GroundMistEffect.java b/src/main/java/com/vinlanx/explosionoverhaul/client/GroundMistEffect.java new file mode 100644 index 0000000..eb25309 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/GroundMistEffect.java @@ -0,0 +1,145 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.vinlanx.explosionoverhaul.Config; +import com.vinlanx.explosionoverhaul.SmokeParticleOptions; +import java.awt.Color; +import java.util.Random; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.util.Mth; +import net.minecraft.world.level.ClipContext; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraft.world.phys.Vec3; + +public class GroundMistEffect { + private final ClientLevel level; + private final Vec3 initialPosition; + private final float power; + private final Random random = new Random(); + private int age = 0; + private final int maxAge; + private final float maxRadius; + private final float particleBaseSize; + private final int particlesPerTick; + private Color currentMistColor = new Color(255, 255, 255); + private boolean finished = false; + private final int raycastFrequency; + + public GroundMistEffect(Vec3 position, float power) { + this.level = Minecraft.m_91087_().f_91073_; + this.initialPosition = position; + this.power = power; + double qualityMultiplier = (Double)Config.CLIENT.groundMistQuality.get(); + this.raycastFrequency = (Integer)Config.CLIENT.groundMistRaycastFrequency.get(); + float powerFraction = Mth.m_14036_((float)(power / 100.0f), (float)0.0f, (float)1.0f); + int calculatedParticles = (int)((double)Mth.m_14179_((float)powerFraction, (float)40.0f, (float)200.0f) * qualityMultiplier * 1.5); + int calculatedMaxAge = (int)((double)Mth.m_14179_((float)powerFraction, (float)30.0f, (float)70.0f) * qualityMultiplier / 3.0); + if (qualityMultiplier > 0.0) { + if (calculatedParticles == 0) { + calculatedParticles = 1; + } + if (calculatedMaxAge == 0) { + calculatedMaxAge = 1; + } + } + this.particlesPerTick = calculatedParticles; + this.maxAge = calculatedMaxAge; + this.maxRadius = power * this.calculateRadiusMultiplier(power) * 3.0f; + this.particleBaseSize = Mth.m_14179_((float)powerFraction, (float)1.0f, (float)12.0f); + } + + private 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; + } + + public void tick() { + double checkZ; + double checkAngle; + double checkX; + BlockHitResult hitResult; + if (this.finished || this.level == null) { + return; + } + ++this.age; + if (this.age > this.maxAge) { + this.finished = true; + return; + } + float progress = (float)this.age / (float)this.maxAge; + float easedProgress = 1.0f - (float)Math.pow(1.0f - progress, 3.0); + float currentRadius = this.maxRadius * easedProgress; + if (this.age % 10 == 0 && (hitResult = this.level.m_45547_(new ClipContext(new Vec3(checkX = this.initialPosition.f_82479_ + Math.cos(checkAngle = this.random.nextDouble() * 2.0 * Math.PI) * (double)currentRadius, this.initialPosition.f_82480_ + 15.0, checkZ = this.initialPosition.f_82481_ + Math.sin(checkAngle) * (double)currentRadius), new Vec3(checkX, this.initialPosition.f_82480_ - 15.0, checkZ), ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, null))).m_6662_() == HitResult.Type.BLOCK) { + BlockPos blockPos = hitResult.m_82425_(); + BlockState blockState = this.level.m_8055_(blockPos); + } + double cachedY = this.initialPosition.f_82480_; + for (int i = 0; i < this.particlesPerTick; ++i) { + float scale; + float a; + float r; + float g; + float b; + double angle = (double)i / (double)this.particlesPerTick * 2.0 * Math.PI + (this.random.nextDouble() - 0.5) * 0.1; + double radiusFrac = this.random.nextDouble(); + double spawnRadius = (double)currentRadius * (0.6 + radiusFrac * 0.4); + double spawnX = this.initialPosition.f_82479_ + Math.cos(angle) * spawnRadius; + double spawnZ = this.initialPosition.f_82481_ + Math.sin(angle) * spawnRadius; + if (i % this.raycastFrequency == 0) { + BlockHitResult hitResult2 = this.level.m_45547_(new ClipContext(new Vec3(spawnX, this.initialPosition.f_82480_ + 15.0, spawnZ), new Vec3(spawnX, this.initialPosition.f_82480_ - 15.0, spawnZ), ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, null)); + if (hitResult2.m_6662_() != HitResult.Type.BLOCK) continue; + cachedY = hitResult2.m_82450_().f_82480_; + } + double spawnY = cachedY; + Vec3 direction = new Vec3(spawnX - this.initialPosition.f_82479_, 0.0, spawnZ - this.initialPosition.f_82481_).m_82541_(); + double motionStrength = Mth.m_14179_((float)(1.0f - progress), (float)0.02f, (float)0.15f); + double motionX = direction.f_82479_ * motionStrength + (this.random.nextDouble() - 0.5) * 0.02; + double motionZ = direction.f_82481_ * motionStrength + (this.random.nextDouble() - 0.5) * 0.02; + double motionY = -0.01 - this.random.nextDouble() * 0.02; + int lifetime = 100 + this.random.nextInt(60); + if (radiusFrac <= 0.2) { + b = 0.8f; + g = 0.8f; + r = 0.8f; + a = 0.3f; + scale = this.particleBaseSize * 0.1667f; + } else if (radiusFrac <= 0.65) { + b = 0.9f; + g = 0.9f; + r = 0.9f; + a = 0.2f; + scale = this.particleBaseSize * 0.25f; + } else { + r = (float)this.currentMistColor.getRed() / 255.0f; + g = (float)this.currentMistColor.getGreen() / 255.0f; + b = (float)this.currentMistColor.getBlue() / 255.0f; + a = 0.15f; + scale = this.particleBaseSize * 0.333f; + } + SmokeParticleOptions options = new SmokeParticleOptions(scale * (0.8f + this.random.nextFloat() * 0.4f), lifetime, r, g, b, a, false, 0.0f, 0.0f, null); + this.level.m_6493_((ParticleOptions)options, true, spawnX, spawnY + 0.05, spawnZ, motionX, motionY, motionZ); + } + } + + public boolean isFinished() { + return this.finished; + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/GuideSlidesScreen.java b/src/main/java/com/vinlanx/explosionoverhaul/client/GuideSlidesScreen.java new file mode 100644 index 0000000..2248c5a --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/GuideSlidesScreen.java @@ -0,0 +1,633 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.vinlanx.explosionoverhaul.ExplosionOverhaul; +import com.vinlanx.explosionoverhaul.ModSounds; +import com.vinlanx.explosionoverhaul.client.AnimationSoundManager; +import com.vinlanx.explosionoverhaul.client.BackgroundParticle; +import com.vinlanx.explosionoverhaul.client.FirstTimeScreen; +import com.vinlanx.explosionoverhaul.client.IntroMusicManager; +import com.vinlanx.explosionoverhaul.client.SpriteSheetAnimator; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.Queue; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; + +public class GuideSlidesScreen +extends Screen { + private static final SlideData[] SLIDES = new SlideData[]{new SlideData("claster_slide.png", 177, "Cluster TNT \u2013 If you place more than two TNT blocks next to each other, the explosion will be much stronger!"), new SlideData("cave_slide.png", 121, "Caves \u2013 If an explosion happens on the surface while you're underground, you'll hear a terrifying rumble, and the ground and dripstones will start to crumble!"), new SlideData("glass_slide.png", 98, "Glass Shattering \u2013 Explosions create shockwaves! Be careful when working with explosives near settlements."), new SlideData("lamp_slide.png", 154, "Lamp Flickering \u2013 If an explosion happens near lamps, the lights will start to flicker."), new SlideData("speed_of_sound_slide.png", 140, "Speed of Sound \u2013 Explosions travel at the speed of sound. You can also enable \"Epic Mode\" in the settings!")}; + private static final int FRAME_WIDTH = 854; + private static final int FRAME_HEIGHT = 480; + private static final int COLUMNS = 14; + private static final int ROWS = 14; + private static final int FPS = 24; + private static final int COLOR_BG = -15921907; + private static final int COLOR_ACCENT_ORANGE = -881908; + private static final int COLOR_ACCENT_RED = -4250588; + private static final int COLOR_ACCENT_ROSE = -2529701; + private static final int COLOR_ACCENT_DARK_RED = -10939115; + private static final int COLOR_TEXT = -1; + private static final int COLOR_PROGRESS_BG = Integer.MIN_VALUE; + private static final int COLOR_PROGRESS_FILL = -881908; + private static final float FADE_IN_DURATION = 1.5f; + private static final float SLIDE_TRANSITION_DURATION = 1.0f; + private static final float AUTO_ADVANCE_DELAY = 0.5f; + private int currentSlideIndex = 0; + private SpriteSheetAnimator currentAnimator; + private float fadeAlpha = 0.0f; + private boolean fadingIn = true; + private float fadeTime = 0.0f; + private boolean isTransitioning = false; + private float transitionTime = 0.0f; + private int transitionToIndex = -1; + private float transitionAlpha = 0.0f; + private SpriteSheetAnimator nextAnimator; + private float autoAdvanceTimer = 0.0f; + private boolean waitingForAutoAdvance = false; + private Queue transitionQueue = new LinkedList(); + private int animationX; + private int animationY; + private int animationWidth; + private int animationHeight; + private int progressBarX; + private int progressBarY; + private int progressBarWidth; + private int progressBarHeight; + private int leftArrowX; + private int leftArrowY; + private int arrowSize; + private int rightArrowX; + private int rightArrowY; + private boolean leftArrowHovered = false; + private boolean rightArrowHovered = false; + private float leftArrowScale = 1.0f; + private float rightArrowScale = 1.0f; + private int continueButtonX; + private int continueButtonY; + private int continueButtonWidth; + private int continueButtonHeight; + private boolean continueButtonHovered = false; + private float continueButtonScale = 1.0f; + private List particles = new ArrayList(); + private RandomSource random = RandomSource.m_216327_(); + private long lastFrameTime = System.currentTimeMillis(); + private IntroMusicManager musicManager; + + public GuideSlidesScreen() { + super((Component)Component.m_237113_((String)"Guide Slides")); + } + + protected void m_7856_() { + int i; + super.m_7856_(); + this.fadingIn = true; + this.fadeTime = 0.0f; + this.fadeAlpha = 0.0f; + this.isTransitioning = false; + this.waitingForAutoAdvance = false; + this.autoAdvanceTimer = 0.0f; + this.lastFrameTime = System.currentTimeMillis(); + this.musicManager = IntroMusicManager.getInstance(); + this.loadSlide(this.currentSlideIndex); + int maxWidth = (int)((float)this.f_96543_ * 0.76f); + int maxHeight = (int)((float)this.f_96544_ * 0.65f); + float aspectRatio = 1.7791667f; + if ((float)maxWidth / aspectRatio <= (float)maxHeight) { + this.animationWidth = maxWidth; + this.animationHeight = (int)((float)maxWidth / aspectRatio); + } else { + this.animationHeight = maxHeight; + this.animationWidth = (int)((float)maxHeight * aspectRatio); + } + this.animationX = (this.f_96543_ - this.animationWidth) / 2; + this.animationY = (int)((float)this.f_96544_ * 0.12f); + this.progressBarWidth = this.animationWidth; + this.progressBarHeight = (int)((float)this.f_96544_ * 0.025f); + this.progressBarX = this.animationX; + this.progressBarY = this.animationY + this.animationHeight + (int)((float)this.f_96544_ * 0.03f); + this.arrowSize = (int)((float)this.f_96544_ * 0.08f); + int arrowGap = (int)((float)this.f_96543_ * 0.02f); + this.leftArrowX = this.animationX - this.arrowSize - arrowGap; + this.leftArrowY = this.animationY + (this.animationHeight - this.arrowSize) / 2; + this.rightArrowX = this.animationX + this.animationWidth + arrowGap; + this.rightArrowY = this.animationY + (this.animationHeight - this.arrowSize) / 2; + this.continueButtonWidth = (int)((float)this.f_96543_ * 0.15f); + this.continueButtonHeight = (int)((float)this.f_96544_ * 0.06f); + this.continueButtonX = (this.f_96543_ - this.continueButtonWidth) / 2; + this.continueButtonY = (int)((float)this.f_96544_ * 0.88f); + for (i = 0; i < 30; ++i) { + this.particles.add(BackgroundParticle.createSpark(this.random, this.f_96543_, this.f_96544_)); + } + for (i = 0; i < 10; ++i) { + this.particles.add(BackgroundParticle.createEmber(this.random, this.f_96543_, this.f_96544_)); + } + for (i = 0; i < 5; ++i) { + this.particles.add(BackgroundParticle.createSmoke(this.random, this.f_96543_, this.f_96544_)); + } + } + + private void loadSlide(int index) { + if (index < 0 || index >= SLIDES.length) { + return; + } + if (this.currentAnimator != null) { + this.currentAnimator.close(); + } + SlideData slide = SLIDES[index]; + this.currentAnimator = new SpriteSheetAnimator(slide.spriteSheet, 854, 480, 14, 14, slide.totalFrames, 24); + this.currentAnimator.load(); + this.registerSoundCallbacks(index, this.currentAnimator); + this.currentAnimator.play(); + ExplosionOverhaul.LOGGER.info("Loaded guide slide {} - texture created fresh", (Object)index); + } + + private void registerSoundCallbacks(int slideIndex, SpriteSheetAnimator animator) { + switch (slideIndex) { + case 0: { + animator.registerFrameCallback(43, AnimationSoundManager::playRandomFarPower2Sound); + animator.registerFrameCallback(132, AnimationSoundManager::playRandomSuperfar4Sound); + break; + } + case 1: { + animator.registerFrameCallback(43, AnimationSoundManager::playRandomMediumCavePower4Sound); + break; + } + case 2: { + animator.registerFrameCallback(30, AnimationSoundManager::playRandomFarPower3Sound); + break; + } + case 3: { + animator.registerFrameCallback(34, AnimationSoundManager::playRandomFarPower2Sound); + break; + } + case 4: { + animator.registerFrameCallback(30, AnimationSoundManager::playRandomFarPower2Sound); + } + } + } + + public void m_86600_() { + float progress; + super.m_86600_(); + long currentTime = System.currentTimeMillis(); + float deltaTime = Math.min((float)(currentTime - this.lastFrameTime) / 1000.0f, 0.1f); + this.lastFrameTime = currentTime; + if (this.fadingIn) { + this.fadeTime += deltaTime; + progress = Math.min(1.0f, this.fadeTime / 1.5f); + this.fadeAlpha = this.easeOutCubic(progress); + if (this.fadeTime >= 1.5f) { + this.fadingIn = false; + this.fadeAlpha = 1.0f; + } + } + if (this.isTransitioning) { + this.transitionTime += deltaTime; + progress = Math.min(1.0f, this.transitionTime / 1.0f); + this.transitionAlpha = this.easeInOutCubic(progress); + if (this.transitionTime >= 1.0f) { + this.isTransitioning = false; + this.currentSlideIndex = this.transitionToIndex; + if (this.currentAnimator != null) { + this.currentAnimator.close(); + } + this.currentAnimator = this.nextAnimator; + this.nextAnimator = null; + this.transitionToIndex = -1; + this.waitingForAutoAdvance = false; + this.autoAdvanceTimer = 0.0f; + ExplosionOverhaul.LOGGER.info("Transition complete to slide {}", (Object)this.currentSlideIndex); + if (!this.transitionQueue.isEmpty()) { + int nextIndex = this.transitionQueue.poll(); + ExplosionOverhaul.LOGGER.info("Processing queued transition to slide {}", (Object)nextIndex); + this.startTransition(nextIndex); + } + } else if (this.transitionAlpha >= 0.5f && this.nextAnimator == null && this.transitionToIndex >= 0 && this.transitionToIndex < SLIDES.length) { + SlideData slide = SLIDES[this.transitionToIndex]; + this.nextAnimator = new SpriteSheetAnimator(slide.spriteSheet, 854, 480, 14, 14, slide.totalFrames, 24); + this.nextAnimator.load(); + this.registerSoundCallbacks(this.transitionToIndex, this.nextAnimator); + this.nextAnimator.play(); + ExplosionOverhaul.LOGGER.info("Created next slide {} animator at transition midpoint", (Object)this.transitionToIndex); + } + } + if (this.currentAnimator != null && !this.isTransitioning) { + this.currentAnimator.tick(deltaTime); + } + float scaleSpeed = 0.2f; + float targetScale = 1.1f; + this.leftArrowScale = Mth.m_14179_((float)scaleSpeed, (float)this.leftArrowScale, (float)(this.leftArrowHovered ? targetScale : 1.0f)); + this.rightArrowScale = Mth.m_14179_((float)scaleSpeed, (float)this.rightArrowScale, (float)(this.rightArrowHovered ? targetScale : 1.0f)); + this.continueButtonScale = Mth.m_14179_((float)scaleSpeed, (float)this.continueButtonScale, (float)(this.continueButtonHovered ? targetScale : 1.0f)); + this.particles.removeIf(p -> { + p.tick(deltaTime); + return p.isDead() || p.x < -50.0f || p.x > (float)(this.f_96543_ + 50) || p.y < -50.0f || p.y > (float)(this.f_96544_ + 50); + }); + if (this.random.m_188501_() < 0.1f) { + this.particles.add(BackgroundParticle.createSpark(this.random, this.f_96543_, this.f_96544_)); + } + if (this.random.m_188501_() < 0.03f) { + this.particles.add(BackgroundParticle.createEmber(this.random, this.f_96543_, this.f_96544_)); + } + if (this.random.m_188501_() < 0.01f) { + this.particles.add(BackgroundParticle.createSmoke(this.random, this.f_96543_, this.f_96544_)); + } + if (this.musicManager != null) { + this.musicManager.tick(deltaTime); + } + } + + private void startTransition(int toIndex) { + if (toIndex < 0 || toIndex >= SLIDES.length || this.isTransitioning) { + return; + } + this.isTransitioning = true; + this.transitionTime = 0.0f; + this.transitionAlpha = 0.0f; + this.transitionToIndex = toIndex; + this.waitingForAutoAdvance = false; + this.autoAdvanceTimer = 0.0f; + ExplosionOverhaul.LOGGER.info("Starting transition from slide {} to {}", (Object)this.currentSlideIndex, (Object)toIndex); + } + + public void m_88315_(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) { + graphics.m_280509_(0, 0, this.f_96543_, this.f_96544_, -15921907); + if (this.fadeAlpha < 0.01f) { + return; + } + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + this.renderBackgroundParticles(graphics, this.fadeAlpha * 0.6f); + if (this.isTransitioning) { + float currentAlpha = 1.0f - this.transitionAlpha; + float nextAlpha = this.transitionAlpha; + if (this.currentAnimator != null && currentAlpha > 0.01f) { + this.renderAnimation(graphics, this.currentAnimator, this.fadeAlpha * currentAlpha); + } + if (this.nextAnimator != null && nextAlpha > 0.01f) { + this.renderAnimation(graphics, this.nextAnimator, this.fadeAlpha * nextAlpha); + } + } else if (this.currentAnimator != null) { + this.renderAnimation(graphics, this.currentAnimator, this.fadeAlpha); + } + this.renderGuideText(graphics, this.fadeAlpha); + this.renderArrows(graphics, mouseX, mouseY, this.fadeAlpha); + this.renderContinueButton(graphics, mouseX, mouseY, this.fadeAlpha); + RenderSystem.disableBlend(); + } + + private void renderBackgroundParticles(GuiGraphics graphics, float alpha) { + for (BackgroundParticle p : this.particles) { + float particleAlpha = p.getAlpha(); + float finalAlpha = particleAlpha * alpha; + int colorWithAlpha = p.color & 0xFFFFFF | (int)(finalAlpha * 255.0f) << 24; + switch (p.type) { + case SPARK: { + float sparkLen = p.size * 3.0f; + float sparkAngle = (float)Math.atan2(p.vy, p.vx); + int ex = (int)((double)p.x + Math.cos(sparkAngle) * (double)sparkLen); + int ey = (int)((double)p.y + Math.sin(sparkAngle) * (double)sparkLen); + this.drawLine(graphics, (int)p.x, (int)p.y, ex, ey, colorWithAlpha); + break; + } + case EMBER: { + int emberSize = (int)p.size; + graphics.m_280509_((int)p.x - emberSize, (int)p.y - emberSize, (int)p.x + emberSize, (int)p.y + emberSize, colorWithAlpha); + break; + } + case FLASH: { + int flashSize = (int)(p.size * 0.7f); + int flashColor = colorWithAlpha & 0xFFFFFF | (int)(finalAlpha * 180.0f) << 24; + graphics.m_280509_((int)p.x - flashSize, (int)p.y - flashSize, (int)p.x + flashSize, (int)p.y + flashSize, flashColor); + break; + } + case SMOKE: { + int smokeSize = (int)p.size; + int smokeColor = colorWithAlpha & 0xFFFFFF | (int)(finalAlpha * 60.0f) << 24; + graphics.m_280509_((int)p.x - smokeSize, (int)p.y - smokeSize, (int)p.x + smokeSize, (int)p.y + smokeSize, smokeColor); + } + } + } + } + + private void renderAnimation(GuiGraphics graphics, SpriteSheetAnimator animator, float alpha) { + ResourceLocation texture = animator.getTextureLocation(); + if (texture == null) { + return; + } + RenderSystem.setShader(GameRenderer::m_172817_); + RenderSystem.setShaderTexture((int)0, (ResourceLocation)texture); + RenderSystem.setShaderColor((float)1.0f, (float)1.0f, (float)1.0f, (float)alpha); + graphics.m_280411_(texture, this.animationX, this.animationY, this.animationWidth, this.animationHeight, 0.0f, 0.0f, 854, 480, 854, 480); + int glowColor = (int)(alpha * 32.0f) << 24 | 0xF28B0C; + int borderThickness = 2; + graphics.m_280509_(this.animationX - borderThickness, this.animationY - borderThickness, this.animationX + this.animationWidth + borderThickness, this.animationY, glowColor); + graphics.m_280509_(this.animationX - borderThickness, this.animationY + this.animationHeight, this.animationX + this.animationWidth + borderThickness, this.animationY + this.animationHeight + borderThickness, glowColor); + graphics.m_280509_(this.animationX - borderThickness, this.animationY, this.animationX, this.animationY + this.animationHeight, glowColor); + graphics.m_280509_(this.animationX + this.animationWidth, this.animationY, this.animationX + this.animationWidth + borderThickness, this.animationY + this.animationHeight, glowColor); + } + + private void renderProgressBar(GuiGraphics graphics, float alpha) { + if (this.currentAnimator == null) { + return; + } + int currentFrame = this.currentAnimator.getCurrentFrame(); + int totalFrames = GuideSlidesScreen.SLIDES[this.currentSlideIndex].totalFrames; + float progress = (float)currentFrame / (float)totalFrames; + int bgColor = (int)(alpha * 128.0f) << 24 | 0; + graphics.m_280509_(this.progressBarX, this.progressBarY, this.progressBarX + this.progressBarWidth, this.progressBarY + this.progressBarHeight, bgColor); + int fillWidth = (int)((float)this.progressBarWidth * progress); + int fillColor = (int)(alpha * 255.0f) << 24 | 0xF28B0C; + graphics.m_280509_(this.progressBarX, this.progressBarY, this.progressBarX + fillWidth, this.progressBarY + this.progressBarHeight, fillColor); + if (fillWidth > 0) { + int glowColor = (int)(alpha * 64.0f) << 24 | 0xF28B0C; + graphics.m_280509_(this.progressBarX + fillWidth - 4, this.progressBarY - 1, this.progressBarX + fillWidth, this.progressBarY + this.progressBarHeight + 1, glowColor); + } + } + + private void renderGuideText(GuiGraphics graphics, float alpha) { + String text = GuideSlidesScreen.SLIDES[this.currentSlideIndex].guideText; + int textColor = (int)(alpha * 255.0f) << 24 | 0xFFFFFF; + int textY = this.animationY + this.animationHeight + (int)((float)this.f_96544_ * 0.04f); + int maxLineWidth = this.animationWidth; + List lines = this.wrapText(text, maxLineWidth); + Objects.requireNonNull(this.f_96547_); + int lineHeight = 9 + 4; + int totalTextHeight = lines.size() * lineHeight; + int startY = textY; + for (int i = 0; i < lines.size(); ++i) { + String line = lines.get(i); + int lineWidth = this.f_96547_.m_92895_(line); + int x = this.animationX + (this.animationWidth - lineWidth) / 2; + graphics.m_280056_(this.f_96547_, line, x, startY + i * lineHeight, textColor, true); + } + } + + private List wrapText(String text, int maxWidth) { + ArrayList lines = new ArrayList(); + String[] words = text.split(" "); + StringBuilder currentLine = new StringBuilder(); + for (String word : words) { + Object testLine = currentLine.length() > 0 ? currentLine + " " + word : word; + int width = this.f_96547_.m_92895_((String)testLine); + if (width > maxWidth && currentLine.length() > 0) { + lines.add(currentLine.toString()); + currentLine = new StringBuilder(word); + continue; + } + if (currentLine.length() > 0) { + currentLine.append(" "); + } + currentLine.append(word); + } + if (currentLine.length() > 0) { + lines.add(currentLine.toString()); + } + return lines; + } + + private void renderArrows(GuiGraphics graphics, int mouseX, int mouseY, float alpha) { + this.leftArrowHovered = this.isPointInArrow(mouseX, mouseY, this.leftArrowX, this.leftArrowY, this.arrowSize); + this.rightArrowHovered = this.isPointInArrow(mouseX, mouseY, this.rightArrowX, this.rightArrowY, this.arrowSize); + if (this.currentSlideIndex > 0) { + this.renderArrow(graphics, this.leftArrowX, this.leftArrowY, this.arrowSize, true, this.leftArrowScale, this.leftArrowHovered, alpha); + } + if (this.currentSlideIndex < SLIDES.length - 1) { + this.renderArrow(graphics, this.rightArrowX, this.rightArrowY, this.arrowSize, false, this.rightArrowScale, this.rightArrowHovered, alpha); + } + } + + private void renderArrow(GuiGraphics graphics, int x, int y, int size, boolean pointLeft, float scale, boolean hovered, float alpha) { + int scaledSize = (int)((float)size * scale); + int offset = (scaledSize - size) / 2; + int drawX = x - offset; + int drawY = y - offset; + int bgColor = hovered ? (int)(alpha * 192.0f) << 24 | 0xF28B0C : (int)(alpha * 128.0f) << 24 | 0x591515; + this.fillCircle(graphics, drawX + scaledSize / 2, drawY + scaledSize / 2, scaledSize / 2, bgColor); + int arrowColor = (int)(alpha * 255.0f) << 24 | 0xFFFFFF; + int centerX = drawX + scaledSize / 2; + int centerY = drawY + scaledSize / 2; + int arrowWidth = scaledSize / 3; + int arrowHeight = scaledSize / 4; + if (pointLeft) { + this.fillTriangle(graphics, centerX + arrowWidth / 2, centerY - arrowHeight, centerX + arrowWidth / 2, centerY + arrowHeight, centerX - arrowWidth / 2, centerY, arrowColor); + } else { + this.fillTriangle(graphics, centerX - arrowWidth / 2, centerY - arrowHeight, centerX - arrowWidth / 2, centerY + arrowHeight, centerX + arrowWidth / 2, centerY, arrowColor); + } + if (hovered) { + int glowColor = (int)(alpha * 64.0f) << 24 | 0xF28B0C; + this.fillCircle(graphics, drawX + scaledSize / 2, drawY + scaledSize / 2, scaledSize / 2 + 4, glowColor); + } + } + + private boolean isPointInArrow(int px, int py, int arrowX, int arrowY, int size) { + int centerX = arrowX + size / 2; + int dx = px - centerX; + int centerY = arrowY + size / 2; + int dy = py - centerY; + int radius = size / 2; + return dx * dx + dy * dy <= radius * radius; + } + + private void fillCircle(GuiGraphics graphics, int centerX, int centerY, int radius, int color) { + for (int y = -radius; y <= radius; ++y) { + for (int x = -radius; x <= radius; ++x) { + if (x * x + y * y > radius * radius) continue; + graphics.m_280509_(centerX + x, centerY + y, centerX + x + 1, centerY + y + 1, color); + } + } + } + + private void fillTriangle(GuiGraphics graphics, int x1, int y1, int x2, int y2, int x3, int y3, int color) { + int minY = Math.min(y1, Math.min(y2, y3)); + int maxY = Math.max(y1, Math.max(y2, y3)); + for (int y = minY; y <= maxY; ++y) { + int x; + int minX = Integer.MAX_VALUE; + int maxX = Integer.MIN_VALUE; + if (this.checkIntersection(y, y1, y2, x1, x2)) { + x = this.interpolate(y, y1, y2, x1, x2); + minX = Math.min(minX, x); + maxX = Math.max(maxX, x); + } + if (this.checkIntersection(y, y2, y3, x2, x3)) { + x = this.interpolate(y, y2, y3, x2, x3); + minX = Math.min(minX, x); + maxX = Math.max(maxX, x); + } + if (this.checkIntersection(y, y3, y1, x3, x1)) { + x = this.interpolate(y, y3, y1, x3, x1); + minX = Math.min(minX, x); + maxX = Math.max(maxX, x); + } + if (minX == Integer.MAX_VALUE || maxX == Integer.MIN_VALUE) continue; + graphics.m_280509_(minX, y, maxX + 1, y + 1, color); + } + } + + private boolean checkIntersection(int y, int y1, int y2, int x1, int x2) { + return y >= Math.min(y1, y2) && y <= Math.max(y1, y2) && y1 != y2; + } + + private int interpolate(int y, int y1, int y2, int x1, int x2) { + return x1 + (y - y1) * (x2 - x1) / (y2 - y1); + } + + public boolean m_6375_(double mouseX, double mouseY, int button) { + if (button == 0) { + if (this.isPointInButton((int)mouseX, (int)mouseY)) { + this.playButtonSound(); + this.transitionToFirstTimeScreen(); + return true; + } + if (this.currentSlideIndex > 0 && this.isPointInArrow((int)mouseX, (int)mouseY, this.leftArrowX, this.leftArrowY, this.arrowSize)) { + Integer nextTransition; + this.playButtonSound(); + int targetIndex = this.currentSlideIndex - 1; + this.transitionQueue.offer(targetIndex); + if (!this.isTransitioning && (nextTransition = this.transitionQueue.poll()) != null) { + this.startTransition(nextTransition); + } + ExplosionOverhaul.LOGGER.info("Queued left arrow transition to {}, queue size: {}", (Object)targetIndex, (Object)this.transitionQueue.size()); + return true; + } + if (this.currentSlideIndex < SLIDES.length - 1 && this.isPointInArrow((int)mouseX, (int)mouseY, this.rightArrowX, this.rightArrowY, this.arrowSize)) { + Integer nextTransition; + this.playButtonSound(); + int targetIndex = this.currentSlideIndex + 1; + this.transitionQueue.offer(targetIndex); + if (!this.isTransitioning && (nextTransition = this.transitionQueue.poll()) != null) { + this.startTransition(nextTransition); + } + ExplosionOverhaul.LOGGER.info("Queued right arrow transition to {}, queue size: {}", (Object)targetIndex, (Object)this.transitionQueue.size()); + return true; + } + } + return super.m_6375_(mouseX, mouseY, button); + } + + private boolean isPointInButton(int px, int py) { + return px >= this.continueButtonX && px <= this.continueButtonX + this.continueButtonWidth && py >= this.continueButtonY && py <= this.continueButtonY + this.continueButtonHeight; + } + + private void renderContinueButton(GuiGraphics graphics, int mouseX, int mouseY, float alpha) { + this.continueButtonHovered = this.isPointInButton(mouseX, mouseY); + int scaledWidth = (int)((float)this.continueButtonWidth * this.continueButtonScale); + int scaledHeight = (int)((float)this.continueButtonHeight * this.continueButtonScale); + int offsetX = (scaledWidth - this.continueButtonWidth) / 2; + int offsetY = (scaledHeight - this.continueButtonHeight) / 2; + int drawX = this.continueButtonX - offsetX; + int drawY = this.continueButtonY - offsetY; + int bgColor = this.continueButtonHovered ? (int)(alpha * 220.0f) << 24 | 0xF28B0C : (int)(alpha * 160.0f) << 24 | 0x591515; + graphics.m_280509_(drawX, drawY, drawX + scaledWidth, drawY + scaledHeight, bgColor); + if (this.continueButtonHovered) { + int glowColor = (int)(alpha * 80.0f) << 24 | 0xF28B0C; + int border = 3; + graphics.m_280509_(drawX - border, drawY - border, drawX + scaledWidth + border, drawY, glowColor); + graphics.m_280509_(drawX - border, drawY + scaledHeight, drawX + scaledWidth + border, drawY + scaledHeight + border, glowColor); + graphics.m_280509_(drawX - border, drawY, drawX, drawY + scaledHeight, glowColor); + graphics.m_280509_(drawX + scaledWidth, drawY, drawX + scaledWidth + border, drawY + scaledHeight, glowColor); + } + String text = "Skip Guide"; + int textColor = (int)(alpha * 255.0f) << 24 | 0xFFFFFF; + int textX = drawX + (scaledWidth - this.f_96547_.m_92895_(text)) / 2; + Objects.requireNonNull(this.f_96547_); + int textY = drawY + (scaledHeight - 9) / 2; + graphics.m_280056_(this.f_96547_, text, textX, textY, textColor, true); + } + + public boolean m_6913_() { + return false; + } + + public boolean m_7043_() { + return false; + } + + public void m_7861_() { + super.m_7861_(); + this.transitionQueue.clear(); + if (this.currentAnimator != null) { + this.currentAnimator.close(); + } + if (this.nextAnimator != null) { + this.nextAnimator.close(); + } + } + + private void transitionToFirstTimeScreen() { + ExplosionOverhaul.LOGGER.info("All guide slides complete. Transitioning to FirstTimeScreen."); + Minecraft.m_91087_().m_91152_((Screen)new FirstTimeScreen()); + } + + private void drawLine(GuiGraphics graphics, int x1, int y1, int x2, int y2, int color) { + int dx = Math.abs(x2 - x1); + int dy = Math.abs(y2 - y1); + int sx = x1 < x2 ? 1 : -1; + int sy = y1 < y2 ? 1 : -1; + int err = dx - dy; + for (int steps = 0; steps < 200; ++steps) { + graphics.m_280509_(x1, y1, x1 + 1, y1 + 1, color); + if (x1 == x2 && y1 == y2) break; + int e2 = 2 * err; + if (e2 > -dy) { + err -= dy; + x1 += sx; + } + if (e2 >= dx) continue; + err += dx; + y1 += sy; + } + } + + private float easeOutCubic(float t) { + return 1.0f - (float)Math.pow(1.0f - t, 3.0); + } + + private float easeInCubic(float t) { + return t * t * t; + } + + private float easeInOutCubic(float t) { + return t < 0.5f ? 4.0f * t * t * t : 1.0f - (float)Math.pow(-2.0f * t + 2.0f, 3.0) / 2.0f; + } + + private void playButtonSound() { + try { + Minecraft minecraft = Minecraft.m_91087_(); + if (minecraft.m_91106_() != null) { + minecraft.m_91106_().m_120367_((SoundInstance)SimpleSoundInstance.m_119755_((SoundEvent)((SoundEvent)ModSounds.BUTTON_SOUND.get()), (float)1.0f, (float)1.0f)); + } + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to play button sound", (Throwable)e); + } + } + + private static class SlideData { + final ResourceLocation spriteSheet; + final int totalFrames; + final String guideText; + + SlideData(String filename, int frames, String text) { + this.spriteSheet = ResourceLocation.fromNamespaceAndPath((String)"explosionoverhaul", (String)("intro_gui/" + filename)); + this.totalFrames = frames; + this.guideText = text; + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/IntroMusicManager.java b/src/main/java/com/vinlanx/explosionoverhaul/client/IntroMusicManager.java new file mode 100644 index 0000000..e089ed8 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/IntroMusicManager.java @@ -0,0 +1,139 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.vinlanx.explosionoverhaul.ExplosionOverhaul; +import com.vinlanx.explosionoverhaul.ModSounds; +import com.vinlanx.explosionoverhaul.client.FadingMusicInstance; +import net.minecraft.client.Minecraft; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundSource; + +public class IntroMusicManager { + private static IntroMusicManager INSTANCE; + private static final float FADE_OUT_DURATION = 3.0f; + private FadingMusicInstance musicInstance; + private SimpleSoundInstance boomInstance; + private boolean isPlaying = false; + private boolean isFadingOut = false; + private boolean vanillaMusicBlocked = false; + + private IntroMusicManager() { + } + + public static IntroMusicManager getInstance() { + if (INSTANCE == null) { + INSTANCE = new IntroMusicManager(); + } + return INSTANCE; + } + + public void start() { + if (this.isPlaying) { + return; + } + SoundManager soundManager = Minecraft.m_91087_().m_91106_(); + this.musicInstance = new FadingMusicInstance((SoundEvent)ModSounds.INTRO_MUSIC.get(), 0.25f, SoundSource.MASTER); + soundManager.m_120367_((SoundInstance)this.musicInstance); + ExplosionOverhaul.LOGGER.info("Started intro music with FadingMusicInstance"); + this.boomInstance = SimpleSoundInstance.m_119755_((SoundEvent)((SoundEvent)ModSounds.INTRO_BOOM.get()), (float)1.0f, (float)1.0f); + soundManager.m_120367_((SoundInstance)this.boomInstance); + this.isPlaying = true; + this.vanillaMusicBlocked = true; + this.stopVanillaMusic(); + } + + public void startFadeOut() { + ExplosionOverhaul.LOGGER.info("startFadeOut called. isPlaying={}, isFadingOut={}", (Object)this.isPlaying, (Object)this.isFadingOut); + if (!this.isPlaying || this.isFadingOut) { + ExplosionOverhaul.LOGGER.warn("Cannot start fade out - already fading or not playing"); + return; + } + if (this.musicInstance != null) { + this.musicInstance.fadeOutAndStop(3.0f); + ExplosionOverhaul.LOGGER.info("Started smooth fade out over {} seconds", (Object)Float.valueOf(3.0f)); + } + this.isFadingOut = true; + } + + public void stopBoomSound() { + if (this.boomInstance != null) { + try { + SoundManager soundManager = Minecraft.m_91087_().m_91106_(); + soundManager.m_120399_((SoundInstance)this.boomInstance); + this.boomInstance = null; + ExplosionOverhaul.LOGGER.info("Boom sound stopped."); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to stop boom sound: {}", (Object)e.toString()); + } + } + } + + public void stop() { + ExplosionOverhaul.LOGGER.info("stop() called! Stack trace:", (Throwable)new Exception("Music stop trace")); + SoundManager soundManager = Minecraft.m_91087_().m_91106_(); + if (this.musicInstance != null) { + soundManager.m_120399_((SoundInstance)this.musicInstance); + this.musicInstance = null; + } + if (this.boomInstance != null) { + soundManager.m_120399_((SoundInstance)this.boomInstance); + this.boomInstance = null; + } + this.isPlaying = false; + this.isFadingOut = false; + this.vanillaMusicBlocked = false; + ExplosionOverhaul.LOGGER.info("Music stopped completely."); + } + + public void tick(float deltaTime) { + if (!this.isPlaying) { + return; + } + if (this.isFadingOut && this.musicInstance != null) { + if (this.musicInstance.hasFinishedFading()) { + ExplosionOverhaul.LOGGER.info("Music fade out complete!"); + this.stop(); + return; + } + float currentVolume = this.musicInstance.getCurrentVolume(); + if (currentVolume % 0.1f < 0.05f) { + ExplosionOverhaul.LOGGER.info("Fade out progress - volume: {}", (Object)Float.valueOf(currentVolume)); + } + } + if (this.vanillaMusicBlocked) { + this.stopVanillaMusic(); + } + } + + private void stopVanillaMusic() { + Minecraft mc = Minecraft.m_91087_(); + if (mc.m_91397_() != null) { + mc.m_91397_().m_120186_(); + } + } + + public boolean isPlaying() { + return this.isPlaying; + } + + public boolean isFadingOut() { + return this.isFadingOut; + } + + public boolean isVanillaMusicBlocked() { + return this.vanillaMusicBlocked; + } + + public float getFadeProgress() { + if (!this.isFadingOut || this.musicInstance == null) { + return 0.0f; + } + return 1.0f - this.musicInstance.getCurrentVolume(); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/IntroMusicTickHandler.java b/src/main/java/com/vinlanx/explosionoverhaul/client/IntroMusicTickHandler.java new file mode 100644 index 0000000..72b1920 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/IntroMusicTickHandler.java @@ -0,0 +1,29 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.vinlanx.explosionoverhaul.client.IntroMusicManager; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.neoforge.event.TickEvent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; + +@Mod.EventBusSubscriber(modid="explosionoverhaul", bus=Mod.EventBusSubscriber.Bus.FORGE, value={Dist.CLIENT}) +public class IntroMusicTickHandler { + private static long lastTickTime = System.currentTimeMillis(); + + @SubscribeEvent + public static void onClientTick(TickEvent.ClientTickEvent event) { + if (event.phase != TickEvent.Phase.END) { + return; + } + IntroMusicManager musicManager = IntroMusicManager.getInstance(); + if (musicManager.isPlaying() || musicManager.isFadingOut()) { + long currentTime = System.currentTimeMillis(); + float deltaTime = (float)(currentTime - lastTickTime) / 1000.0f; + lastTickTime = currentTime; + musicManager.tick(deltaTime); + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/IntroSplashScreen.java b/src/main/java/com/vinlanx/explosionoverhaul/client/IntroSplashScreen.java new file mode 100644 index 0000000..4428087 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/IntroSplashScreen.java @@ -0,0 +1,143 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.vinlanx.explosionoverhaul.client.IntroMusicManager; +import com.vinlanx.explosionoverhaul.client.SpriteSheetAnimator; +import com.vinlanx.explosionoverhaul.client.VinlanxSplashScreen; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.TitleScreen; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +public class IntroSplashScreen +extends Screen { + private static final ResourceLocation SPRITE_SHEET = ResourceLocation.fromNamespaceAndPath((String)"explosionoverhaul", (String)"intro_gui/screen.png"); + private static final int FRAME_WIDTH = 1280; + private static final int FRAME_HEIGHT = 720; + private static final int COLUMNS = 14; + private static final int ROWS = 14; + private static final int TOTAL_FRAMES = 196; + private static final int FPS = 24; + private SpriteSheetAnimator animator; + private IntroMusicManager musicManager; + private long lastFrameTime = System.currentTimeMillis(); + private boolean animationFinished = false; + + public IntroSplashScreen() { + super((Component)Component.m_237113_((String)"Intro")); + } + + protected void m_7856_() { + super.m_7856_(); + this.animator = new SpriteSheetAnimator(SPRITE_SHEET, 1280, 720, 14, 14, 196, 24); + this.animator.load(); + this.animator.play(); + this.musicManager = IntroMusicManager.getInstance(); + this.musicManager.start(); + } + + public void m_86600_() { + super.m_86600_(); + long currentTime = System.currentTimeMillis(); + float deltaTime = (float)(currentTime - this.lastFrameTime) / 1000.0f; + this.lastFrameTime = currentTime; + if (this.animator != null) { + this.animator.tick(deltaTime); + if (this.animator.getCurrentFrame() >= 195 && !this.animationFinished) { + this.animationFinished = true; + this.transitionToFirstTimeScreen(); + } + } + if (this.musicManager != null) { + this.musicManager.tick(deltaTime); + } + } + + public void m_88315_(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) { + int displayWidth; + int displayHeight; + graphics.m_280509_(0, 0, this.f_96543_, this.f_96544_, -16777216); + if (this.animator == null) { + return; + } + ResourceLocation texture = this.animator.getTextureLocation(); + if (texture == null) { + return; + } + float screenAspectRatio = (float)this.f_96543_ / (float)this.f_96544_; + float targetAspectRatio = 1.7777778f; + if (screenAspectRatio > targetAspectRatio) { + displayHeight = this.f_96544_; + displayWidth = (int)((float)displayHeight * targetAspectRatio); + } else { + displayWidth = this.f_96543_; + displayHeight = (int)((float)displayWidth / targetAspectRatio); + } + int x = (this.f_96543_ - displayWidth) / 2; + int y = (this.f_96544_ - displayHeight) / 2; + RenderSystem.setShader(GameRenderer::m_172817_); + RenderSystem.setShaderTexture((int)0, (ResourceLocation)texture); + RenderSystem.setShaderColor((float)1.0f, (float)1.0f, (float)1.0f, (float)1.0f); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + graphics.m_280411_(texture, x, y, displayWidth, displayHeight, 0.0f, 0.0f, 1280, 720, 1280, 720); + RenderSystem.disableBlend(); + } + + public boolean m_6913_() { + return true; + } + + public boolean m_7933_(int keyCode, int scanCode, int modifiers) { + if (keyCode == 256) { + this.skipToNext(); + return true; + } + return super.m_7933_(keyCode, scanCode, modifiers); + } + + public boolean m_6375_(double mouseX, double mouseY, int button) { + this.skipToNext(); + return true; + } + + public boolean m_7043_() { + return false; + } + + public void m_7861_() { + super.m_7861_(); + if (this.animator != null) { + this.animator.close(); + } + if (this.musicManager != null) { + this.musicManager.stopBoomSound(); + } + } + + private void skipToNext() { + this.animationFinished = true; + this.transitionToFirstTimeScreen(); + } + + private void transitionToFirstTimeScreen() { + Minecraft mc = Minecraft.m_91087_(); + if (!(mc.f_91080_ instanceof TitleScreen)) { + mc.execute(() -> { + if (mc.f_91080_ instanceof TitleScreen) { + mc.m_91152_((Screen)new VinlanxSplashScreen()); + } else { + mc.m_91152_((Screen)new VinlanxSplashScreen()); + } + }); + return; + } + mc.m_91152_((Screen)new VinlanxSplashScreen()); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/LineSparkParticle.java b/src/main/java/com/vinlanx/explosionoverhaul/client/LineSparkParticle.java new file mode 100644 index 0000000..d53a419 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/LineSparkParticle.java @@ -0,0 +1,122 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.particle.ParticleRenderType; +import net.minecraft.client.particle.SpriteSet; +import net.minecraft.client.particle.TextureSheetParticle; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; +import org.joml.Vector3f; +import org.joml.Vector3fc; + +public class LineSparkParticle +extends TextureSheetParticle { + private final SpriteSet spriteSet; + private float length; + private float width; + private final float initialLength; + private static final Vec3 UP = new Vec3(0.0, 1.0, 0.0); + + public LineSparkParticle(ClientLevel pLevel, double pX, double pY, double pZ, double pXSpeed, double pYSpeed, double pZSpeed, SpriteSet pSpriteSet) { + super(pLevel, pX, pY, pZ, pXSpeed, pYSpeed, pZSpeed); + float baseSize; + this.f_107215_ = pXSpeed; + this.f_107216_ = pYSpeed; + this.f_107217_ = pZSpeed; + this.spriteSet = pSpriteSet; + this.f_172258_ = 0.97f; + this.f_107226_ = 0.4f; + this.f_107225_ = 250 + this.f_107223_.m_188503_(150); + this.initialLength = baseSize = (this.f_107223_.m_188501_() * 0.4f + 0.5f) * 1.2f; + this.length = 0.1f; + this.width = baseSize * 0.125f; + this.m_108337_(this.spriteSet.m_5819_(0, 1)); + } + + public void m_5989_() { + float stretchFactor; + super.m_5989_(); + float lifeProgress = (float)this.f_107224_ / (float)this.f_107225_; + if (lifeProgress < 0.2f) { + t = lifeProgress / 0.2f; + stretchFactor = 1.0f - (1.0f - t) * (1.0f - t); + } else if (lifeProgress < 0.7f) { + stretchFactor = 1.0f; + } else { + t = (lifeProgress - 0.7f) / 0.3f; + stretchFactor = 1.0f - t * t; + } + stretchFactor = Mth.m_14036_((float)stretchFactor, (float)0.0f, (float)1.0f); + float distanceScale = 1.0f; + Minecraft mc = Minecraft.m_91087_(); + if (mc.f_91074_ != null) { + double distSqr = mc.f_91074_.m_20275_(this.f_107212_, this.f_107213_, this.f_107214_); + double dist = Math.sqrt(distSqr); + if (dist > 171.0) { + distanceScale = 2.5f; + } else if (dist > 141.0) { + distanceScale = 2.2f; + } else if (dist > 101.0) { + distanceScale = 2.0f; + } else if (dist > 71.0) { + distanceScale = 1.7f; + } else if (dist > 50.0) { + distanceScale = 1.5f; + } + } + this.length = this.initialLength * stretchFactor * distanceScale; + this.width = this.initialLength * 0.125f * distanceScale; + if (this.length < 0.01f) { + this.length = 0.01f; + } + this.f_107230_ = Mth.m_14089_((float)((float)this.f_107224_ / (float)this.f_107225_ * (float)Math.PI / 2.0f)); + if (this.f_107218_) { + this.m_107274_(); + } + } + + public ParticleRenderType m_7556_() { + return ParticleRenderType.f_107431_; + } + + public void m_5744_(VertexConsumer buffer, Camera camera, float partialTicks) { + Vec3 camPos = camera.m_90583_(); + float x = (float)(Mth.m_14139_((double)partialTicks, (double)this.f_107209_, (double)this.f_107212_) - camPos.m_7096_()); + float y = (float)(Mth.m_14139_((double)partialTicks, (double)this.f_107210_, (double)this.f_107213_) - camPos.m_7098_()); + float z = (float)(Mth.m_14139_((double)partialTicks, (double)this.f_107211_, (double)this.f_107214_) - camPos.m_7094_()); + Vec3 velocity = new Vec3(this.f_107215_, this.f_107216_, this.f_107217_).m_82541_(); + if (velocity.m_82556_() < 1.0E-4) { + return; + } + Vec3 viewVector = new Vec3((double)x, (double)y, (double)z).m_82541_(); + Vec3 rightVector = velocity.m_82537_(viewVector).m_82541_(); + if (rightVector.m_82556_() < 1.0E-4 && (rightVector = velocity.m_82537_(UP).m_82541_()).m_82556_() < 1.0E-4) { + rightVector = velocity.m_82537_(new Vec3(1.0, 0.0, 0.0)).m_82541_(); + } + Vec3 upVector = rightVector.m_82537_(velocity).m_82541_(); + Vector3f[] vertices = new Vector3f[]{new Vector3f(x, y, z).add((Vector3fc)upVector.m_82490_((double)(-this.length / 2.0f)).m_82549_(rightVector.m_82490_((double)(this.width / 2.0f))).m_252839_()), new Vector3f(x, y, z).add((Vector3fc)upVector.m_82490_((double)(this.length / 2.0f)).m_82549_(rightVector.m_82490_((double)(this.width / 2.0f))).m_252839_()), new Vector3f(x, y, z).add((Vector3fc)upVector.m_82490_((double)(this.length / 2.0f)).m_82549_(rightVector.m_82490_((double)(-this.width / 2.0f))).m_252839_()), new Vector3f(x, y, z).add((Vector3fc)upVector.m_82490_((double)(-this.length / 2.0f)).m_82549_(rightVector.m_82490_((double)(-this.width / 2.0f))).m_252839_())}; + int worldLight = this.m_6355_(partialTicks); + this.renderQuad(buffer, vertices, this.f_108321_, this.f_107227_, this.f_107228_, this.f_107229_, this.f_107230_, worldLight); + TextureAtlasSprite emissiveSprite = this.spriteSet.m_5819_(1, 1); + int fullBright = 240; + this.renderQuad(buffer, vertices, emissiveSprite, 1.0f, 1.0f, 1.0f, this.f_107230_, fullBright); + } + + private void renderQuad(VertexConsumer buffer, Vector3f[] vertices, TextureAtlasSprite sprite, float r, float g, float b, float a, int light) { + float u0 = sprite.m_118409_(); + float u1 = sprite.m_118410_(); + float v0 = sprite.m_118411_(); + float v1 = sprite.m_118412_(); + buffer.m_5483_((double)vertices[0].x(), (double)vertices[0].y(), (double)vertices[0].z()).m_7421_(u1, v1).m_85950_(r, g, b, a).m_85969_(light).m_5752_(); + buffer.m_5483_((double)vertices[1].x(), (double)vertices[1].y(), (double)vertices[1].z()).m_7421_(u1, v0).m_85950_(r, g, b, a).m_85969_(light).m_5752_(); + buffer.m_5483_((double)vertices[2].x(), (double)vertices[2].y(), (double)vertices[2].z()).m_7421_(u0, v0).m_85950_(r, g, b, a).m_85969_(light).m_5752_(); + buffer.m_5483_((double)vertices[3].x(), (double)vertices[3].y(), (double)vertices[3].z()).m_7421_(u0, v1).m_85950_(r, g, b, a).m_85969_(light).m_5752_(); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/LineSparkParticleProvider.java b/src/main/java/com/vinlanx/explosionoverhaul/client/LineSparkParticleProvider.java new file mode 100644 index 0000000..8a13b65 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/LineSparkParticleProvider.java @@ -0,0 +1,24 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.vinlanx.explosionoverhaul.client.LineSparkParticle; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.particle.ParticleProvider; +import net.minecraft.client.particle.SpriteSet; +import net.minecraft.core.particles.SimpleParticleType; + +public class LineSparkParticleProvider +implements ParticleProvider { + private final SpriteSet spriteSet; + + public LineSparkParticleProvider(SpriteSet pSprites) { + this.spriteSet = pSprites; + } + + public Particle createParticle(SimpleParticleType pType, ClientLevel pLevel, double pX, double pY, double pZ, double pXSpeed, double pYSpeed, double pZSpeed) { + return new LineSparkParticle(pLevel, pX, pY, pZ, pXSpeed, pYSpeed, pZSpeed, this.spriteSet); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/LowPassConcussionEffect.java b/src/main/java/com/vinlanx/explosionoverhaul/client/LowPassConcussionEffect.java new file mode 100644 index 0000000..ab5e3b8 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/LowPassConcussionEffect.java @@ -0,0 +1,310 @@ +/* + * 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.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.neoforge.event.TickEvent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.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; + + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/ModConfigScreen.java b/src/main/java/com/vinlanx/explosionoverhaul/client/ModConfigScreen.java new file mode 100644 index 0000000..88ce954 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/ModConfigScreen.java @@ -0,0 +1,256 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.vinlanx.explosionoverhaul.Config; +import com.vinlanx.explosionoverhaul.CraterDeformer; +import com.vinlanx.explosionoverhaul.client.BlacklistScreen; +import com.vinlanx.explosionoverhaul.client.ExplosionTextureManager; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import me.shedaniel.clothconfig2.api.AbstractConfigListEntry; +import me.shedaniel.clothconfig2.api.ConfigBuilder; +import me.shedaniel.clothconfig2.api.ConfigCategory; +import me.shedaniel.clothconfig2.api.ConfigEntryBuilder; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.narration.NarratableEntry; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.neoforged.neoforge.common.ForgeConfigSpec; + +public class ModConfigScreen { + public static Screen create(Screen parent) { + ConfigBuilder builder = ConfigBuilder.create().setParentScreen(parent).setTitle((Component)Component.m_237115_((String)"title.explosionoverhaul.config")); + ConfigEntryBuilder entryBuilder = builder.entryBuilder(); + ConfigCategory serverCategory = builder.getOrCreateCategory((Component)Component.m_237115_((String)"category.explosionoverhaul.server")); + builder.setSavingRunnable(() -> { + Config.CLIENT_SPEC.save(); + Config.COMMON_SPEC.save(); + ExplosionTextureManager.getInstance().reload(); + }); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableFallingBlocks"), ((Boolean)Config.COMMON.enableFallingBlocks.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableFallingBlocks")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.COMMON.enableFallingBlocks).set(arg_0)).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableExplosionClustering"), ((Boolean)Config.COMMON.enableExplosionClustering.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableExplosionClustering")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.COMMON.enableExplosionClustering).set(arg_0)).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableCraterDestruction"), ((Boolean)Config.COMMON.enableCraterDestruction.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableCraterDestruction")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.COMMON.enableCraterDestruction).set(arg_0)).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableGlassBreaking"), ((Boolean)Config.COMMON.enableGlassBreaking.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableGlassBreaking")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.COMMON.enableGlassBreaking).set(arg_0)).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableDripstoneFalling"), ((Boolean)Config.COMMON.enableDripstoneFalling.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableDripstoneFalling")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.COMMON.enableDripstoneFalling).set(arg_0)).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableLampFlicker"), ((Boolean)Config.COMMON.enableLampFlicker.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableLampFlicker")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.COMMON.enableLampFlicker).set(arg_0)).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237113_((String)" ")).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237115_((String)"option.explosionoverhaul.craterSettingsHeader")).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.craterSizeMultiplier"), (int)((Double)Config.COMMON.craterSizeMultiplier.get() * 100.0), 10, 5000).setDefaultValue(100).setTextGetter(value -> { + double val = (double)value.intValue() / 100.0; + Object text = String.format("%.2fx", val); + if (val > 10.0) { + text = (String)text + " \u00a7c(EXTREME!)"; + } + return Component.m_237113_((String)text); + }).setTooltipSupplier(value -> Optional.of(ModConfigScreen.generateCraterTable((double)value.intValue() / 100.0))).setSaveConsumer(newValue -> Config.COMMON.craterSizeMultiplier.set((Object)((double)newValue.intValue() / 100.0))).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.craterCoreRatio"), (int)((Double)Config.COMMON.craterCoreRatio.get() * 100.0), 10, 95).setDefaultValue(70).setTextGetter(value -> Component.m_237113_((String)(value + "%"))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.craterCoreRatio")}).setSaveConsumer(newValue -> Config.COMMON.craterCoreRatio.set((Object)((double)newValue.intValue() / 100.0))).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237113_((String)" ")).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237113_((String)"--- Async Crater Pipeline ---")).setTooltip(new Component[]{Component.m_237113_((String)"Computes crater geometry off-thread and applies block changes in batches per tick.")}).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableAsyncCrater"), ((Boolean)Config.COMMON.enableAsyncCrater.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableAsyncCrater")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.COMMON.enableAsyncCrater).set(arg_0)).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.maxClusterPower"), ((Integer)Config.COMMON.maxClusterPower.get()).intValue(), 4, 1000).setDefaultValue(100).setTextGetter(v -> Component.m_237113_((String)String.valueOf(v))).setTooltipSupplier(v -> { + if (v >= 500) { + return Optional.of(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.maxClusterPower"), Component.m_237113_((String)""), Component.m_237113_((String)"\u26a0 ").m_130944_(new ChatFormatting[]{ChatFormatting.RED, ChatFormatting.BOLD}).m_7220_((Component)Component.m_237115_((String)"warning.explosionoverhaul.crashRisk").m_130944_(new ChatFormatting[]{ChatFormatting.DARK_RED, ChatFormatting.BOLD}))}); + } + if (v >= 300) { + return Optional.of(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.maxClusterPower"), Component.m_237113_((String)""), Component.m_237115_((String)"warning.explosionoverhaul.severeRenderingLag").m_130940_(ChatFormatting.DARK_RED)}); + } + if (v >= 150) { + return Optional.of(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.maxClusterPower"), Component.m_237113_((String)""), Component.m_237115_((String)"warning.explosionoverhaul.renderingLag").m_130940_(ChatFormatting.GOLD)}); + } + return Optional.of(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.maxClusterPower")}); + }).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)Config.COMMON.maxClusterPower).set(arg_0)).build()); + int availableThreads = Runtime.getRuntime().availableProcessors(); + int maxThreadsForSystem = Math.min(32, availableThreads); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.craterMaxThreads"), ((Integer)Config.COMMON.craterMaxThreads.get()).intValue(), 0, maxThreadsForSystem).setDefaultValue(0).setTextGetter(v -> Component.m_237113_((String)(v == 0 ? "Auto (" + availableThreads + ")" : String.valueOf(v)))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.craterMaxThreads")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)Config.COMMON.craterMaxThreads).set(arg_0)).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.craterApplyBlocksPerTick"), ((Integer)Config.COMMON.craterApplyBlocksPerTick.get()).intValue(), 0, 150000).setDefaultValue(50000).setTextGetter(v -> Component.m_237113_((String)(v + " blocks/tick"))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.craterApplyBlocksPerTick")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)Config.COMMON.craterApplyBlocksPerTick).set(arg_0)).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.craterMaxFallingBlocksPerTick"), ((Integer)Config.COMMON.craterMaxFallingBlocksPerTick.get()).intValue(), 0, 2000).setDefaultValue(500).setTextGetter(v -> Component.m_237113_((String)(v + " entities/tick"))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.craterMaxFallingBlocksPerTick")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)Config.COMMON.craterMaxFallingBlocksPerTick).set(arg_0)).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableDirectChunkWrites"), ((Boolean)Config.COMMON.enableDirectChunkWrites.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableDirectChunkWrites")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.COMMON.enableDirectChunkWrites).set(arg_0)).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.craterChunksPerTick"), ((Integer)Config.COMMON.craterChunksPerTick.get()).intValue(), 0, 500).setDefaultValue(120).setTextGetter(v -> Component.m_237113_((String)(v + " chunks/tick"))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.craterChunksPerTick")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)Config.COMMON.craterChunksPerTick).set(arg_0)).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237113_((String)" ")).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237115_((String)"option.explosionoverhaul.glassBreakingSettings")).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.glassBreakingIntervalTicks"), ((Integer)Config.COMMON.glassBreakingIntervalTicks.get()).intValue(), 1, 20).setDefaultValue(1).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.glassBreakingIntervalTicks")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)Config.COMMON.glassBreakingIntervalTicks).set(arg_0)).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.glassBlocksPerCycle"), ((Integer)Config.COMMON.glassBlocksPerCycle.get()).intValue(), 10, 500).setDefaultValue(70).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.glassBlocksPerCycle")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)Config.COMMON.glassBlocksPerCycle).set(arg_0)).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237113_((String)" ")).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237115_((String)"option.explosionoverhaul.lampFlickerSettings")).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.lampFlickerSearchRadius"), ((Integer)Config.COMMON.lampFlickerSearchRadius.get()).intValue(), 1, 100).setDefaultValue(50).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.lampFlickerSearchRadius")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)Config.COMMON.lampFlickerSearchRadius).set(arg_0)).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237115_((String)"option.explosionoverhaul.dripstoneFallingSettings")).build()); + serverCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.dripstoneFallingSearchRadius"), ((Integer)Config.COMMON.dripstoneFallingSearchRadius.get()).intValue(), 1, 100).setDefaultValue(50).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.dripstoneFallingSearchRadius")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)Config.COMMON.dripstoneFallingSearchRadius).set(arg_0)).build()); + ConfigCategory ambientCategory = builder.getOrCreateCategory((Component)Component.m_237115_((String)"category.explosionoverhaul.ambient")); + Config.Common.Ambient ambientConfig = Config.COMMON.ambient; + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableAmbientExplosions"), ((Boolean)ambientConfig.enableAmbientExplosions.get()).booleanValue()).setDefaultValue(false).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableAmbientExplosions")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)ambientConfig.enableAmbientExplosions).set(arg_0)).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.minTimeBetweenExplosions"), (Integer)ambientConfig.minTimeBetweenExplosions.get() / 20, 5, 3600).setDefaultValue(60).setTextGetter(value -> Component.m_237113_((String)(value + " s"))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.minTimeBetweenExplosions")}).setSaveConsumer(newValue -> ambientConfig.minTimeBetweenExplosions.set((Object)(newValue * 20))).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.maxTimeBetweenExplosions"), (Integer)ambientConfig.maxTimeBetweenExplosions.get() / 20, 10, 3600).setDefaultValue(300).setTextGetter(value -> Component.m_237113_((String)(value + " s"))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.maxTimeBetweenExplosions")}).setSaveConsumer(newValue -> ambientConfig.maxTimeBetweenExplosions.set((Object)(newValue * 20))).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.minExplosionDistance"), ((Integer)ambientConfig.minExplosionDistance.get()).intValue(), 100, 10000).setDefaultValue(501).setTextGetter(value -> Component.m_237113_((String)(value + " blocks"))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.minExplosionDistance")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)ambientConfig.minExplosionDistance).set(arg_0)).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.maxExplosionDistance"), ((Integer)ambientConfig.maxExplosionDistance.get()).intValue(), 200, 10000).setDefaultValue(5001).setTextGetter(value -> Component.m_237113_((String)(value + " blocks"))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.maxExplosionDistance")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)ambientConfig.maxExplosionDistance).set(arg_0)).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.maxAmbientExplosionPower"), (int)((Double)ambientConfig.maxAmbientExplosionPower.get() * 10.0), 400, 2000).setDefaultValue(800).setTextGetter(value -> Component.m_237113_((String)String.format("%.1f", (double)value.intValue() / 10.0))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.maxAmbientExplosionPower")}).setSaveConsumer(newValue -> ambientConfig.maxAmbientExplosionPower.set((Object)((double)newValue.intValue() / 10.0))).build()); + Config.Common.Ambient.Scenarios scenariosConfig = ambientConfig.scenarios; + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237113_((String)" ")).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237115_((String)"option.explosionoverhaul.scenariosHeader")).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.scenariosHeader")}).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.singleExplosionWeight"), ((Integer)scenariosConfig.singleExplosionWeight.get()).intValue(), 0, 100).setTextGetter(v -> Component.m_237113_((String)(v + "%"))).setDefaultValue(70).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)scenariosConfig.singleExplosionWeight).set(arg_0)).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.chainReactionWeight"), ((Integer)scenariosConfig.chainReactionWeight.get()).intValue(), 0, 100).setTextGetter(v -> Component.m_237113_((String)(v + "%"))).setDefaultValue(15).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)scenariosConfig.chainReactionWeight).set(arg_0)).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.shellingWeight"), ((Integer)scenariosConfig.shellingWeight.get()).intValue(), 0, 100).setTextGetter(v -> Component.m_237113_((String)(v + "%"))).setDefaultValue(15).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)scenariosConfig.shellingWeight).set(arg_0)).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237115_((String)"option.explosionoverhaul.chainReactionSettingsHeader")).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.minChainReactionShots"), ((Integer)scenariosConfig.minChainReactionShots.get()).intValue(), 2, 20).setDefaultValue(3).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)scenariosConfig.minChainReactionShots).set(arg_0)).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.maxChainReactionShots"), ((Integer)scenariosConfig.maxChainReactionShots.get()).intValue(), 2, 20).setDefaultValue(7).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)scenariosConfig.maxChainReactionShots).set(arg_0)).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.minTimeBetweenChainShots"), ((Integer)scenariosConfig.minTimeBetweenChainShots.get()).intValue(), 5, 200).setTextGetter(v -> Component.m_237113_((String)String.format("%.2fs", (double)v.intValue() / 20.0))).setDefaultValue(10).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)scenariosConfig.minTimeBetweenChainShots).set(arg_0)).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.maxTimeBetweenChainShots"), ((Integer)scenariosConfig.maxTimeBetweenChainShots.get()).intValue(), 10, 400).setTextGetter(v -> Component.m_237113_((String)String.format("%.2fs", (double)v.intValue() / 20.0))).setDefaultValue(40).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)scenariosConfig.maxTimeBetweenChainShots).set(arg_0)).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237115_((String)"option.explosionoverhaul.shellingSettingsHeader")).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.minShellingDelay"), ((Integer)scenariosConfig.minShellingDelay.get()).intValue(), 20, 400).setTextGetter(v -> Component.m_237113_((String)String.format("%.2fs", (double)v.intValue() / 20.0))).setDefaultValue(40).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)scenariosConfig.minShellingDelay).set(arg_0)).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.maxShellingDelay"), ((Integer)scenariosConfig.maxShellingDelay.get()).intValue(), 20, 400).setTextGetter(v -> Component.m_237113_((String)String.format("%.2fs", (double)v.intValue() / 20.0))).setDefaultValue(140).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)scenariosConfig.maxShellingDelay).set(arg_0)).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237113_((String)" ")).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237115_((String)"option.explosionoverhaul.powerTiersHeader")).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.powerTiersHeader")}).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.tier1_weight"), ((Integer)ambientConfig.powerTiers.tier1_weight.get()).intValue(), 0, 100).setTextGetter(v -> Component.m_237113_((String)(v + "%"))).setDefaultValue(50).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)ambientConfig.powerTiers.tier1_weight).set(arg_0)).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.tier2_weight"), ((Integer)ambientConfig.powerTiers.tier2_weight.get()).intValue(), 0, 100).setTextGetter(v -> Component.m_237113_((String)(v + "%"))).setDefaultValue(25).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)ambientConfig.powerTiers.tier2_weight).set(arg_0)).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.tier3_weight"), ((Integer)ambientConfig.powerTiers.tier3_weight.get()).intValue(), 0, 100).setTextGetter(v -> Component.m_237113_((String)(v + "%"))).setDefaultValue(15).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)ambientConfig.powerTiers.tier3_weight).set(arg_0)).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.tier4_weight"), ((Integer)ambientConfig.powerTiers.tier4_weight.get()).intValue(), 0, 100).setTextGetter(v -> Component.m_237113_((String)(v + "%"))).setDefaultValue(8).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)ambientConfig.powerTiers.tier4_weight).set(arg_0)).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.tier5_weight"), ((Integer)ambientConfig.powerTiers.tier5_weight.get()).intValue(), 0, 100).setTextGetter(v -> Component.m_237113_((String)(v + "%"))).setDefaultValue(2).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)ambientConfig.powerTiers.tier5_weight).set(arg_0)).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237113_((String)" ")).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237115_((String)"option.explosionoverhaul.soundTypesHeader")).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableSurfaceSounds"), ((Boolean)ambientConfig.soundTypes.enableSurfaceSounds.get()).booleanValue()).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableSurfaceSounds")}).setDefaultValue(true).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)ambientConfig.soundTypes.enableSurfaceSounds).set(arg_0)).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableCaveSounds"), ((Boolean)ambientConfig.soundTypes.enableCaveSounds.get()).booleanValue()).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableCaveSounds")}).setDefaultValue(true).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)ambientConfig.soundTypes.enableCaveSounds).set(arg_0)).build()); + ambientCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableAmbientCaveDust"), ((Boolean)ambientConfig.soundTypes.enableAmbientCaveDust.get()).booleanValue()).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableAmbientCaveDust")}).setDefaultValue(true).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)ambientConfig.soundTypes.enableAmbientCaveDust).set(arg_0)).build()); + ConfigCategory renderCategory = builder.getOrCreateCategory((Component)Component.m_237115_((String)"category.explosionoverhaul.render")); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startEnumSelector((Component)Component.m_237115_((String)"option.explosionoverhaul.glowTextureQuality"), Config.Client.GlowTextureQuality.class, (Enum)((Config.Client.GlowTextureQuality)((Object)Config.CLIENT.glowTextureQuality.get()))).setDefaultValue((Enum)Config.Client.GlowTextureQuality.QUALITY_256).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.glowTextureQuality")}).setSaveConsumer(arg_0 -> Config.CLIENT.glowTextureQuality.set(arg_0)).setEnumNameProvider(value -> Component.m_237113_((String)(value == Config.Client.GlowTextureQuality.QUALITY_64 ? "64x" : "256x"))).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startEnumSelector((Component)Component.m_237115_((String)"option.explosionoverhaul.particleRenderMode"), Config.Client.ParticleRenderMode.class, (Enum)((Config.Client.ParticleRenderMode)((Object)Config.CLIENT.particleRenderMode.get()))).setDefaultValue((Enum)Config.Client.ParticleRenderMode.VANILA).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.particleRenderMode")}).setSaveConsumer(arg_0 -> Config.CLIENT.particleRenderMode.set(arg_0)).setEnumNameProvider(value -> { + if (value == Config.Client.ParticleRenderMode.VANILA) { + return Component.m_237113_((String)"Vanilla-like"); + } + if (value == Config.Client.ParticleRenderMode.REALISTIC_2) { + return Component.m_237113_((String)"Realistic 2"); + } + return Component.m_237113_((String)"Realistic"); + }).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.particleSizeScale"), (int)((Double)Config.CLIENT.particleSizeScale.get() * 100.0), 10, 500).setDefaultValue(100).setTextGetter(value -> Component.m_237113_((String)String.format("%.2fx", (double)value.intValue() / 100.0))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.particleSizeScale")}).setSaveConsumer(newValue -> Config.CLIENT.particleSizeScale.set((Object)((double)newValue.intValue() / 100.0))).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableExplosionParticles"), ((Boolean)Config.CLIENT.enableExplosionParticles.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableExplosionParticles")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.CLIENT.enableExplosionParticles).set(arg_0)).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237113_((String)" ")).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enablePlasmaParticles"), ((Boolean)Config.CLIENT.enablePlasmaParticles.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enablePlasmaParticles")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.CLIENT.enablePlasmaParticles).set(arg_0)).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enablePlasmaSmokeTrail"), ((Boolean)Config.CLIENT.enablePlasmaSmokeTrail.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enablePlasmaSmokeTrail")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.CLIENT.enablePlasmaSmokeTrail).set(arg_0)).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.plasmaSmokeFrequency"), (int)((Double)Config.CLIENT.plasmaSmokeFrequency.get() * 100.0), 0, 100).setDefaultValue(25).setTextGetter(value -> Component.m_237113_((String)(value + "%"))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.plasmaSmokeFrequency")}).setSaveConsumer(newValue -> Config.CLIENT.plasmaSmokeFrequency.set((Object)((double)newValue.intValue() / 100.0))).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.plasmaSmokeCount"), ((Integer)Config.CLIENT.plasmaSmokeCount.get()).intValue(), 0, 5).setDefaultValue(1).setTextGetter(value -> Component.m_237113_((String)String.valueOf(value))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.plasmaSmokeCount")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)Config.CLIENT.plasmaSmokeCount).set(arg_0)).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237113_((String)" ")).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableFlashEffect"), ((Boolean)Config.CLIENT.enableFlashEffect.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableFlashEffect")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.CLIENT.enableFlashEffect).set(arg_0)).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.flashMaxOpacity"), (int)((Double)Config.CLIENT.flashMaxOpacity.get() * 100.0), 0, 100).setDefaultValue(50).setTextGetter(value -> Component.m_237113_((String)(value + "%"))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.flashMaxOpacity")}).setSaveConsumer(newValue -> Config.CLIENT.flashMaxOpacity.set((Object)((double)newValue.intValue() / 100.0))).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237113_((String)" ")).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableLineSparks"), ((Boolean)Config.CLIENT.enableLineSparks.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableLineSparks")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.CLIENT.enableLineSparks).set(arg_0)).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.lineSparkAmountMultiplier"), (int)((Double)Config.CLIENT.lineSparkAmountMultiplier.get() * 100.0), 0, 500).setDefaultValue(100).setTextGetter(value -> Component.m_237113_((String)String.format("%d%%", value))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.lineSparkAmountMultiplier")}).setSaveConsumer(newValue -> Config.CLIENT.lineSparkAmountMultiplier.set((Object)((double)newValue.intValue() / 100.0))).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237113_((String)" ")).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableGroundDustEffect"), ((Boolean)Config.CLIENT.enableGroundDustEffect.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableGroundDustEffect")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.CLIENT.enableGroundDustEffect).set(arg_0)).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.groundDustQuality"), (int)((Double)Config.CLIENT.groundDustQuality.get() * 100.0), 0, 100).setDefaultValue(100).setTextGetter(value -> Component.m_237113_((String)(value + "%"))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.groundDustQuality")}).setSaveConsumer(newValue -> Config.CLIENT.groundDustQuality.set((Object)((double)newValue.intValue() / 100.0))).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.groundDustRaycastFrequency"), ((Integer)Config.CLIENT.groundDustRaycastFrequency.get()).intValue(), 1, 20).setDefaultValue(10).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.groundDustRaycastFrequency")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)Config.CLIENT.groundDustRaycastFrequency).set(arg_0)).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237113_((String)" ")).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableGroundMistEffect"), ((Boolean)Config.CLIENT.enableGroundMistEffect.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableGroundMistEffect")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.CLIENT.enableGroundMistEffect).set(arg_0)).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.groundMistQuality"), (int)((Double)Config.CLIENT.groundMistQuality.get() * 100.0), 0, 100).setDefaultValue(100).setTextGetter(value -> Component.m_237113_((String)(value + "%"))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.groundMistQuality")}).setSaveConsumer(newValue -> Config.CLIENT.groundMistQuality.set((Object)((double)newValue.intValue() / 100.0))).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.groundMistRaycastFrequency"), ((Integer)Config.CLIENT.groundMistRaycastFrequency.get()).intValue(), 1, 20).setDefaultValue(10).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.groundMistRaycastFrequency")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)Config.CLIENT.groundMistRaycastFrequency).set(arg_0)).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237113_((String)" ")).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableShockwaveEffect"), ((Boolean)Config.CLIENT.enableShockwaveEffect.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableShockwaveEffect")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.CLIENT.enableShockwaveEffect).set(arg_0)).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237113_((String)" ")).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableWindEffect"), ((Boolean)Config.CLIENT.enableWindEffect.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableWindEffect")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.CLIENT.enableWindEffect).set(arg_0)).build()); + renderCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.windSpeedMultiplier"), (int)((Double)Config.CLIENT.windSpeedMultiplier.get() * 100.0), 100, 200).setDefaultValue(100).setTextGetter(value -> Component.m_237113_((String)String.format("%.2fx", (double)value.intValue() / 100.0))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.windSpeedMultiplier")}).setSaveConsumer(newValue -> Config.CLIENT.windSpeedMultiplier.set((Object)((double)newValue.intValue() / 100.0))).build()); + ConfigCategory cameraCategory = builder.getOrCreateCategory((Component)Component.m_237115_((String)"category.explosionoverhaul.camera")); + cameraCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableCameraShake"), ((Boolean)Config.CLIENT.enableCameraShake.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableCameraShake")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.CLIENT.enableCameraShake).set(arg_0)).build()); + cameraCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.cameraShakeAmplifier"), (int)((Double)Config.CLIENT.cameraShakeAmplifier.get() * 10.0), 0, 100).setDefaultValue(10).setTextGetter(value -> Component.m_237113_((String)String.format("%.1fx", (double)value.intValue() / 10.0))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.cameraShakeAmplifier")}).setSaveConsumer(newValue -> Config.CLIENT.cameraShakeAmplifier.set((Object)((double)newValue.intValue() / 10.0))).build()); + cameraCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237115_((String)"option.explosionoverhaul.cameraServerHeader")).build()); + cameraCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enablePlayerShake"), ((Boolean)Config.COMMON.enablePlayerShake.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enablePlayerShake")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.COMMON.enablePlayerShake).set(arg_0)).build()); + cameraCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.playerShakeAmplifier"), (int)((Double)Config.COMMON.playerShakeAmplifier.get() * 10.0), 0, 100).setDefaultValue(10).setTextGetter(value -> Component.m_237113_((String)String.format("%.1fx", (double)value.intValue() / 10.0))).setTooltip(new Component[]{Component.m_237115_((String)"option.explosionoverhaul.playerShakeAmplifier")}).setSaveConsumer(newValue -> Config.COMMON.playerShakeAmplifier.set((Object)((double)newValue.intValue() / 10.0))).build()); + ConfigCategory scanCategory = builder.getOrCreateCategory((Component)Component.m_237115_((String)"category.explosionoverhaul.scan")); + scanCategory.addEntry((AbstractConfigListEntry)entryBuilder.startTextDescription((Component)Component.m_237115_((String)"option.explosionoverhaul.scanSettingsHeader")).build()); + int availableCores = Runtime.getRuntime().availableProcessors(); + int maxThreads = Math.min(32, availableCores); + scanCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.maxScanThreads"), ((Integer)Config.COMMON.scan.maxScanThreads.get()).intValue(), 0, maxThreads).setDefaultValue(0).setTextGetter(value -> { + if (value == 0) { + return Component.m_237113_((String)("Auto (" + availableCores + " threads)")); + } + return Component.m_237113_((String)String.valueOf(value)); + }).setTooltip(new Component[]{Component.m_237113_((String)("Maximum number of threads to use for chunk scanning.\n0 = Auto-detect (recommended): automatically uses all " + availableCores + " available threads\n1 = Single-threaded (slowest but safest for low-end servers)\n2-" + maxThreads + " = Custom thread count (available range for your system)\nYour system supports up to " + availableCores + " threads.\nMore threads = faster scanning but higher CPU usage."))}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)Config.COMMON.scan.maxScanThreads).set(arg_0)).build()); + scanCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.cpuUsagePercent"), ((Integer)Config.COMMON.scan.cpuUsagePercent.get()).intValue(), 1, 100).setDefaultValue(75).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.cpuUsagePercent")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.IntValue)Config.COMMON.scan.cpuUsagePercent).set(arg_0)).build()); + scanCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableBlockIndexing"), ((Boolean)Config.COMMON.scan.enableBlockIndexing.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableBlockIndexing")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.COMMON.scan.enableBlockIndexing).set(arg_0)).build()); + scanCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.showScanProgressHUD"), ((Boolean)Config.COMMON.scan.showScanProgressHUD.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.showScanProgressHUD")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.COMMON.scan.showScanProgressHUD).set(arg_0)).build()); + ConfigCategory soundsCategory = builder.getOrCreateCategory((Component)Component.m_237115_((String)"category.explosionoverhaul.sounds")); + soundsCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableAdvancedSoundSpeed"), ((Boolean)Config.COMMON.enableAdvancedSoundSpeed.get()).booleanValue()).setDefaultValue(false).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableAdvancedSoundSpeed")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.COMMON.enableAdvancedSoundSpeed).set(arg_0)).build()); + ConfigCategory concussionCategory = builder.getOrCreateCategory((Component)Component.m_237115_((String)"category.explosionoverhaul.concussion")); + concussionCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableConcussion"), ((Boolean)Config.CLIENT.enableConcussion.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableConcussion")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.CLIENT.enableConcussion).set(arg_0)).build()); + concussionCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.concussionDurationMultiplier"), (int)((Double)Config.CLIENT.concussionDurationMultiplier.get() * 100.0), 0, 500).setDefaultValue(100).setTextGetter(value -> Component.m_237113_((String)String.format("%.2fx", (double)value.intValue() / 100.0))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.concussionDurationMultiplier")}).setSaveConsumer(newValue -> Config.CLIENT.concussionDurationMultiplier.set((Object)((double)newValue.intValue() / 100.0))).build()); + concussionCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.concussionChanceMultiplier"), (int)((Double)Config.CLIENT.concussionChanceMultiplier.get() * 100.0), 0, 500).setDefaultValue(100).setTextGetter(value -> Component.m_237113_((String)(value + "%"))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.concussionChanceMultiplier")}).setSaveConsumer(newValue -> Config.CLIENT.concussionChanceMultiplier.set((Object)((double)newValue.intValue() / 100.0))).build()); + concussionCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableHeartbeatPulse"), ((Boolean)Config.CLIENT.enableHeartbeatPulse.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableHeartbeatPulse")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.CLIENT.enableHeartbeatPulse).set(arg_0)).build()); + concussionCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableCameraSway"), ((Boolean)Config.CLIENT.enableCameraSway.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableCameraSway")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.CLIENT.enableCameraSway).set(arg_0)).build()); + concussionCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.cameraSwayIntensity"), (int)((Double)Config.CLIENT.cameraSwayIntensity.get() * 100.0), 0, 500).setDefaultValue(100).setTextGetter(value -> Component.m_237113_((String)String.format("%.2fx", (double)value.intValue() / 100.0))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.cameraSwayIntensity")}).setSaveConsumer(newValue -> Config.CLIENT.cameraSwayIntensity.set((Object)((double)newValue.intValue() / 100.0))).build()); + concussionCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableDeafness"), ((Boolean)Config.CLIENT.enableDeafness.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableDeafness")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.CLIENT.enableDeafness).set(arg_0)).build()); + concussionCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.enableLowPass"), ((Boolean)Config.CLIENT.enableLowPass.get()).booleanValue()).setDefaultValue(true).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.enableLowPass")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.CLIENT.enableLowPass).set(arg_0)).build()); + concussionCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.deafnessChanceMultiplier"), (int)((Double)Config.CLIENT.deafnessChanceMultiplier.get() * 100.0), 0, 500).setDefaultValue(100).setTextGetter(value -> Component.m_237113_((String)(value + "%"))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.deafnessChanceMultiplier")}).setSaveConsumer(newValue -> Config.CLIENT.deafnessChanceMultiplier.set((Object)((double)newValue.intValue() / 100.0))).build()); + concussionCategory.addEntry((AbstractConfigListEntry)entryBuilder.startIntSlider((Component)Component.m_237115_((String)"option.explosionoverhaul.lowPassChanceMultiplier"), (int)((Double)Config.CLIENT.lowPassChanceMultiplier.get() * 100.0), 0, 500).setDefaultValue(100).setTextGetter(value -> Component.m_237113_((String)(value + "%"))).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.lowPassChanceMultiplier")}).setSaveConsumer(newValue -> Config.CLIENT.lowPassChanceMultiplier.set((Object)((double)newValue.intValue() / 100.0))).build()); + concussionCategory.addEntry((AbstractConfigListEntry)entryBuilder.startBooleanToggle((Component)Component.m_237115_((String)"option.explosionoverhaul.showHeartbeatHUD"), ((Boolean)Config.CLIENT.showHeartbeatHUD.get()).booleanValue()).setDefaultValue(false).setTooltip(new Component[]{Component.m_237115_((String)"tooltip.explosionoverhaul.showHeartbeatHUD")}).setSaveConsumer(arg_0 -> ((ForgeConfigSpec.BooleanValue)Config.CLIENT.showHeartbeatHUD).set(arg_0)).build()); + ConfigCategory blacklistCategory = builder.getOrCreateCategory((Component)Component.m_237115_((String)"category.explosionoverhaul.blacklists")); + blacklistCategory.addEntry((AbstractConfigListEntry)new LinkButtonEntry((Component)Component.m_237115_((String)"option.explosionoverhaul.blacklist_button"), (Component)Component.m_237115_((String)"tooltip.explosionoverhaul.blacklist_button"), () -> Minecraft.m_91087_().m_91152_((Screen)new BlacklistScreen(parent)))); + return builder.build(); + } + + private static Component[] generateCraterTable(double multiplier) { + int[] powerLevels; + ArrayList lines = new ArrayList(); + lines.add(Component.m_237115_((String)"tooltip.explosionoverhaul.craterSizeMultiplier.title")); + lines.add(Component.m_237113_((String)"")); + lines.add(Component.m_237113_((String)"\u00a7bPower \u00a78| \u00a7aApprox. Diameter")); + lines.add(Component.m_237113_((String)"\u00a77--------------------------")); + for (int power : powerLevels = new int[]{4, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100}) { + float baseRadius = CraterDeformer.calculateRadius(power); + float diameter = (float)((double)baseRadius * multiplier * 2.0); + String formattedLine = String.format("\u00a7f%-12d\u00a78| \u00a7a~%.1f blocks", power, Float.valueOf(diameter)); + lines.add(Component.m_237113_((String)formattedLine)); + } + lines.add(Component.m_237113_((String)"\u00a77--------------------------")); + lines.add(Component.m_237115_((String)"tooltip.explosionoverhaul.craterSizeMultiplier.footer")); + lines.add(Component.m_237113_((String)"")); + lines.add(Component.m_237115_((String)"tooltip.explosionoverhaul.craterShapeInfo")); + return lines.toArray(new Component[0]); + } + + public static class LinkButtonEntry + extends AbstractConfigListEntry { + private final Button button; + private final Component tooltip; + + public LinkButtonEntry(Component fieldName, Component tooltip, Runnable action) { + super(fieldName, false); + this.tooltip = tooltip; + this.button = Button.m_253074_((Component)fieldName, b -> action.run()).m_253136_(); + this.button.m_93674_(200); + } + + public void render(GuiGraphics graphics, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) { + this.button.m_252865_(x + entryWidth / 2 - 100); + this.button.m_253211_(y); + this.button.m_88315_(graphics, mouseX, mouseY, delta); + if (mouseX >= this.button.m_252754_() && mouseX <= this.button.m_252754_() + this.button.m_5711_() && mouseY >= this.button.m_252907_() && mouseY <= this.button.m_252907_() + this.button.m_93694_()) { + graphics.m_280557_(Minecraft.m_91087_().f_91062_, this.tooltip, mouseX, mouseY); + } + } + + public List m_6702_() { + return Collections.singletonList(this.button); + } + + public List narratables() { + return Collections.singletonList(this.button); + } + + public Object getValue() { + return null; + } + + public Optional getDefaultValue() { + return Optional.empty(); + } + + public void save() { + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/ModKeyMappings.java b/src/main/java/com/vinlanx/explosionoverhaul/client/ModKeyMappings.java new file mode 100644 index 0000000..62a1505 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/ModKeyMappings.java @@ -0,0 +1,21 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.mojang.blaze3d.platform.InputConstants; +import net.minecraft.client.KeyMapping; +import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent; + +public class ModKeyMappings { + public static final String KEY_CATEGORY = "key.categories.explosionoverhaul"; + public static final KeyMapping ACCEPT_SCAN = new KeyMapping("key.explosionoverhaul.accept_scan", InputConstants.Type.KEYSYM, 49, "key.categories.explosionoverhaul"); + public static final KeyMapping DECLINE_SCAN = new KeyMapping("key.explosionoverhaul.decline_scan", InputConstants.Type.KEYSYM, 50, "key.categories.explosionoverhaul"); + public static final KeyMapping INFO_SCAN = new KeyMapping("key.explosionoverhaul.info_scan", InputConstants.Type.KEYSYM, 51, "key.categories.explosionoverhaul"); + + public static void register(RegisterKeyMappingsEvent event) { + event.register(ACCEPT_SCAN); + event.register(DECLINE_SCAN); + event.register(INFO_SCAN); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/PhysicsBasedExplosionEffect.java b/src/main/java/com/vinlanx/explosionoverhaul/client/PhysicsBasedExplosionEffect.java new file mode 100644 index 0000000..189b09f --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/PhysicsBasedExplosionEffect.java @@ -0,0 +1,210 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.vinlanx.explosionoverhaul.Config; +import com.vinlanx.explosionoverhaul.CustomGlowParticleOptions; +import com.vinlanx.explosionoverhaul.PlasmaParticleOptions; +import com.vinlanx.explosionoverhaul.client.ExplosionWindController; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Random; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; + +public class PhysicsBasedExplosionEffect { + private final ClientLevel level; + private final Random random; + private final Vec3 position; + private final float power; + private int age = 0; + private final int maxAge = 8; + private final float maxRadius; + private final int particleCount; + private final float particleScaleBase; + private final int totalLifetime; + private boolean finished = false; + private final int totalSparks; + private float sparkSpawnAccumulator = 0.0f; + private final List sparkDirections; + private int sparkIndex = 0; + + public PhysicsBasedExplosionEffect(Vec3 position, float power) { + this.position = position; + this.power = power; + this.random = new Random(); + this.level = Minecraft.m_91087_().f_91073_; + if (this.level == null) { + this.finished = true; + this.maxRadius = 0.0f; + this.particleCount = 0; + this.particleScaleBase = 0.0f; + this.totalLifetime = 0; + this.totalSparks = 0; + this.sparkDirections = new ArrayList(); + return; + } + float calcPower = Mth.m_14036_((float)power, (float)1.0f, (float)100.0f); + float powerFraction = calcPower / 100.0f; + this.maxRadius = Mth.m_14179_((float)powerFraction, (float)3.0f, (float)40.0f); + this.particleCount = (int)Mth.m_14179_((float)powerFraction, (float)40.0f, (float)400.0f); + this.particleScaleBase = Mth.m_14179_((float)powerFraction, (float)5.0f, (float)37.5f); + this.totalLifetime = (int)Mth.m_14179_((float)powerFraction, (float)300.0f, (float)1800.0f) + this.random.nextInt(100) - 50; + this.totalSparks = (int)Mth.m_14179_((float)powerFraction, (float)3.0f, (float)150.0f); + this.sparkDirections = new ArrayList(); + if (this.totalSparks > 0) { + double goldenRatio = (1.0 + Math.sqrt(5.0)) / 2.0; + double angleIncrement = Math.PI * 2 * goldenRatio; + for (int i = 0; i < this.totalSparks; ++i) { + double y = 1.0 - (double)i / (double)(this.totalSparks - 1) * 2.0; + double radius = Math.sqrt(1.0 - y * y); + double theta = angleIncrement * (double)i; + double x = Math.cos(theta) * radius; + double z = Math.sin(theta) * radius; + this.sparkDirections.add(new Vec3(x, z, y).m_82541_()); + } + Collections.shuffle(this.sparkDirections, this.random); + } + } + + public void tick() { + if (this.finished) { + return; + } + if (!((Boolean)Config.CLIENT.enableExplosionParticles.get()).booleanValue()) { + this.finished = true; + return; + } + ++this.age; + if (this.age > this.maxAge) { + this.finished = true; + return; + } + if (Config.CLIENT.particleRenderMode.get() == Config.Client.ParticleRenderMode.REALISTIC_2) { + this.tickRealistic2(); + } else { + this.tickRegular(); + } + } + + private void tickRealistic2() { + if (this.age == 1) { + double distance; + float f = this.age; + Objects.requireNonNull(this); + float progress = f / 8.0f; + float currentRadius = this.maxRadius * (float)Math.pow(progress, 0.4); + Vec3 particlePos = this.position.m_82520_((this.random.nextDouble() - 0.5) * (double)currentRadius, (this.random.nextDouble() - 0.5) * (double)currentRadius, (this.random.nextDouble() - 0.5) * (double)currentRadius); + Vec3 motion = new Vec3((this.random.nextDouble() - 0.5) * 0.05, (this.random.nextDouble() - 0.5) * 0.05, (this.random.nextDouble() - 0.5) * 0.05); + double distance3D = particlePos.m_82554_(this.position); + double heightPercent = this.maxRadius <= 0.0f ? 0.5 : Mth.m_14008_((double)(distance3D / (double)this.maxRadius), (double)0.25, (double)1.0); + Vec3 windDirection = ExplosionWindController.getWindDirection(); + double glowSpeed = ExplosionWindController.computeGlowSpeed(heightPercent); + if (windDirection != Vec3.f_82478_ && glowSpeed > 0.0) { + motion = motion.m_82549_(windDirection.m_82490_(glowSpeed * 0.6)); + } + int zone = (distance = particlePos.m_82554_(this.position)) / (double)this.maxRadius < 0.4 ? 1 : 0; + float particleScale = this.particleScaleBase * 1.0f * ((Double)Config.CLIENT.particleSizeScale.get()).floatValue(); + int animationType = this.power <= 5.0f ? 2 : this.random.nextInt(2); + CustomGlowParticleOptions options = new CustomGlowParticleOptions(zone, this.power, particleScale, animationType, (float)this.position.f_82480_, this.maxRadius, (float)heightPercent); + this.level.m_7106_((ParticleOptions)options, particlePos.f_82479_, particlePos.f_82480_, particlePos.f_82481_, motion.f_82479_, motion.f_82480_, motion.f_82481_); + } + if (this.totalSparks > 0 && this.sparkIndex < this.totalSparks && ((Boolean)Config.CLIENT.enablePlasmaParticles.get()).booleanValue()) { + float f = this.age; + Objects.requireNonNull(this); + float progress2 = f / 8.0f; + float currentRadius2 = this.maxRadius * (float)Math.pow(progress2, 0.4); + float f2 = this.totalSparks; + Objects.requireNonNull(this); + float sparksToSpawnThisTick = f2 / 8.0f; + this.sparkSpawnAccumulator += sparksToSpawnThisTick; + int sparksToActuallySpawn = (int)this.sparkSpawnAccumulator; + if (sparksToActuallySpawn > 0) { + this.sparkSpawnAccumulator -= (float)sparksToActuallySpawn; + for (int j = 0; j < sparksToActuallySpawn && this.sparkIndex < this.totalSparks; ++j) { + Vec3 plasmaMotion = this.sparkDirections.get(this.sparkIndex); + ++this.sparkIndex; + Vec3 plasmaSpawnPos = this.position.m_82549_(plasmaMotion.m_82490_((double)currentRadius2 * 0.8)); + float strongSparkChance = 0.1f; + if (this.power > 10.0f) { + float powerFractionForChance = Mth.m_184655_((float)this.power, (float)10.0f, (float)100.0f); + strongSparkChance = Mth.m_14179_((float)powerFractionForChance, (float)0.1f, (float)0.35f); + } + float force = this.random.nextFloat() < strongSparkChance ? Mth.m_14179_((float)(this.power / 100.0f), (float)2.0f, (float)14.0f) * (0.9f + this.random.nextFloat() * 0.4f) : Mth.m_14179_((float)(this.power / 100.0f), (float)1.3f, (float)6.5f) * (0.6f + this.random.nextFloat() * 0.4f); + plasmaMotion = plasmaMotion.m_82490_((double)force); + PlasmaParticleOptions plasmaOptions = new PlasmaParticleOptions(this.power); + this.level.m_6493_((ParticleOptions)plasmaOptions, true, plasmaSpawnPos.f_82479_, plasmaSpawnPos.f_82480_, plasmaSpawnPos.f_82481_, plasmaMotion.f_82479_, plasmaMotion.f_82480_, plasmaMotion.f_82481_); + } + } + } + this.finished = false; + } + + private void tickRegular() { + int particlesThisTick = this.particleCount / this.maxAge; + if (this.age == this.maxAge) { + particlesThisTick = this.particleCount - particlesThisTick * (this.maxAge - 1); + } + float f = this.age; + Objects.requireNonNull(this); + float progress = f / 8.0f; + float currentRadius = this.maxRadius * (float)Math.pow(progress, 0.4); + for (int i = 0; i < particlesThisTick; ++i) { + double distance; + double u = this.random.nextDouble(); + double v = this.random.nextDouble(); + double theta = Math.PI * 2 * u; + double phi = Math.acos(2.0 * v - 1.0); + double r = currentRadius; + Vec3 particlePos = this.position.m_82520_(r * Math.sin(phi) * Math.cos(theta), r * Math.sin(phi) * Math.sin(theta), r * Math.cos(phi)); + Vec3 motion = new Vec3((this.random.nextDouble() - 0.5) * 0.05, (this.random.nextDouble() - 0.5) * 0.05, (this.random.nextDouble() - 0.5) * 0.05); + double distance3D = particlePos.m_82554_(this.position); + double heightPercent = this.maxRadius <= 0.0f ? 0.5 : Mth.m_14008_((double)(distance3D / (double)this.maxRadius), (double)0.25, (double)1.0); + Vec3 windDirection = ExplosionWindController.getWindDirection(); + double glowSpeed = ExplosionWindController.computeGlowSpeed(heightPercent); + if (windDirection != Vec3.f_82478_ && glowSpeed > 0.0) { + motion = motion.m_82549_(windDirection.m_82490_(glowSpeed * 0.6)); + } + int zone = (distance = particlePos.m_82554_(this.position)) / (double)this.maxRadius < 0.4 ? 1 : 0; + float particleScale = this.particleScaleBase * (0.8f + this.random.nextFloat() * 0.4f) * ((Double)Config.CLIENT.particleSizeScale.get()).floatValue(); + int animationType = this.power <= 5.0f ? 2 : this.random.nextInt(2); + CustomGlowParticleOptions options = new CustomGlowParticleOptions(zone, this.power, particleScale, animationType, (float)this.position.f_82480_, this.maxRadius, (float)heightPercent); + this.level.m_7106_((ParticleOptions)options, particlePos.f_82479_, particlePos.f_82480_, particlePos.f_82481_, motion.f_82479_, motion.f_82480_, motion.f_82481_); + } + if (this.totalSparks > 0 && this.sparkIndex < this.totalSparks && ((Boolean)Config.CLIENT.enablePlasmaParticles.get()).booleanValue()) { + float f2 = this.totalSparks; + Objects.requireNonNull(this); + float sparksToSpawnThisTick = f2 / 8.0f; + this.sparkSpawnAccumulator += sparksToSpawnThisTick; + int sparksToActuallySpawn = (int)this.sparkSpawnAccumulator; + if (sparksToActuallySpawn > 0) { + this.sparkSpawnAccumulator -= (float)sparksToActuallySpawn; + for (int j = 0; j < sparksToActuallySpawn && this.sparkIndex < this.totalSparks; ++j) { + Vec3 plasmaMotion = this.sparkDirections.get(this.sparkIndex); + ++this.sparkIndex; + Vec3 plasmaSpawnPos = this.position.m_82549_(plasmaMotion.m_82490_((double)currentRadius * 0.8)); + float strongSparkChance = 0.1f; + if (this.power > 10.0f) { + float powerFractionForChance = Mth.m_184655_((float)this.power, (float)10.0f, (float)100.0f); + strongSparkChance = Mth.m_14179_((float)powerFractionForChance, (float)0.1f, (float)0.35f); + } + float force = this.random.nextFloat() < strongSparkChance ? Mth.m_14179_((float)(this.power / 100.0f), (float)2.0f, (float)14.0f) * (0.9f + this.random.nextFloat() * 0.4f) : Mth.m_14179_((float)(this.power / 100.0f), (float)1.3f, (float)6.5f) * (0.6f + this.random.nextFloat() * 0.4f); + plasmaMotion = plasmaMotion.m_82490_((double)force); + PlasmaParticleOptions plasmaOptions = new PlasmaParticleOptions(this.power); + this.level.m_6493_((ParticleOptions)plasmaOptions, true, plasmaSpawnPos.f_82479_, plasmaSpawnPos.f_82480_, plasmaSpawnPos.f_82481_, plasmaMotion.f_82479_, plasmaMotion.f_82480_, plasmaMotion.f_82481_); + } + } + } + this.finished = false; + } + + public boolean isFinished() { + return this.finished; + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/PlasmaParticle.java b/src/main/java/com/vinlanx/explosionoverhaul/client/PlasmaParticle.java new file mode 100644 index 0000000..73063f5 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/PlasmaParticle.java @@ -0,0 +1,116 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.vinlanx.explosionoverhaul.Config; +import com.vinlanx.explosionoverhaul.PlasmaParticleOptions; +import com.vinlanx.explosionoverhaul.SmokeParticleOptions; +import net.minecraft.client.Camera; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.particle.ParticleProvider; +import net.minecraft.client.particle.ParticleRenderType; +import net.minecraft.client.particle.SpriteSet; +import net.minecraft.client.particle.TextureSheetParticle; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; +import org.joml.Quaternionf; +import org.joml.Quaternionfc; +import org.joml.Vector3f; + +public class PlasmaParticle +extends TextureSheetParticle { + private final SpriteSet sprites; + private final float initialQuadSize; + + protected PlasmaParticle(ClientLevel pLevel, double pX, double pY, double pZ, double pXSpeed, double pYSpeed, double pZSpeed, PlasmaParticleOptions options, SpriteSet pSpriteSet) { + super(pLevel, pX, pY, pZ, pXSpeed, pYSpeed, pZSpeed); + this.sprites = pSpriteSet; + this.f_172258_ = 0.96f; + this.f_107226_ = 0.2f; + this.f_107215_ = pXSpeed; + this.f_107216_ = pYSpeed; + this.f_107217_ = pZSpeed; + float power = options.getPower(); + float powerFraction = Mth.m_14036_((float)(power / 100.0f), (float)0.0f, (float)1.0f); + this.f_107663_ = this.initialQuadSize = Mth.m_14179_((float)powerFraction, (float)0.4f, (float)2.5f); + this.f_107225_ = 200 + this.f_107223_.m_188503_(40) - 20; + this.f_107227_ = 0.8f; + this.f_107228_ = 0.8f; + this.f_107229_ = 0.8f; + this.m_108335_(pSpriteSet); + } + + public ParticleRenderType m_7556_() { + return ParticleRenderType.f_107431_; + } + + public int m_6355_(float pPartialTick) { + return 240; + } + + public void m_5744_(VertexConsumer pBuffer, Camera pRenderInfo, float pPartialTicks) { + RenderSystem.disableDepthTest(); + Vec3 vec3 = pRenderInfo.m_90583_(); + float f = (float)(Mth.m_14139_((double)pPartialTicks, (double)this.f_107209_, (double)this.f_107212_) - vec3.m_7096_()); + float f1 = (float)(Mth.m_14139_((double)pPartialTicks, (double)this.f_107210_, (double)this.f_107213_) - vec3.m_7098_()); + float f2 = (float)(Mth.m_14139_((double)pPartialTicks, (double)this.f_107211_, (double)this.f_107214_) - vec3.m_7094_()); + Quaternionf quaternion = new Quaternionf((Quaternionfc)pRenderInfo.m_253121_()); + if (this.f_107231_ != 0.0f) { + float f3 = Mth.m_14179_((float)pPartialTicks, (float)this.f_107204_, (float)this.f_107231_); + quaternion.rotateZ(f3); + } + Vector3f[] avector3f = new Vector3f[]{new Vector3f(-1.0f, -1.0f, 0.0f), new Vector3f(-1.0f, 1.0f, 0.0f), new Vector3f(1.0f, 1.0f, 0.0f), new Vector3f(1.0f, -1.0f, 0.0f)}; + float f4 = this.m_5902_(pPartialTicks); + for (int i = 0; i < 4; ++i) { + Vector3f vector3f = avector3f[i]; + vector3f.rotate((Quaternionfc)quaternion); + vector3f.mul(f4); + vector3f.add(f, f1, f2); + } + float f7 = this.m_5970_(); + float f8 = this.m_5952_(); + float f5 = this.m_5951_(); + float f6 = this.m_5950_(); + int j = this.m_6355_(pPartialTicks); + pBuffer.m_5483_((double)avector3f[0].x(), (double)avector3f[0].y(), (double)avector3f[0].z()).m_7421_(f8, f6).m_85950_(this.f_107227_, this.f_107228_, this.f_107229_, this.f_107230_).m_85969_(j).m_5752_(); + pBuffer.m_5483_((double)avector3f[1].x(), (double)avector3f[1].y(), (double)avector3f[1].z()).m_7421_(f8, f5).m_85950_(this.f_107227_, this.f_107228_, this.f_107229_, this.f_107230_).m_85969_(j).m_5752_(); + pBuffer.m_5483_((double)avector3f[2].x(), (double)avector3f[2].y(), (double)avector3f[2].z()).m_7421_(f7, f5).m_85950_(this.f_107227_, this.f_107228_, this.f_107229_, this.f_107230_).m_85969_(j).m_5752_(); + pBuffer.m_5483_((double)avector3f[3].x(), (double)avector3f[3].y(), (double)avector3f[3].z()).m_7421_(f7, f6).m_85950_(this.f_107227_, this.f_107228_, this.f_107229_, this.f_107230_).m_85969_(j).m_5752_(); + RenderSystem.enableDepthTest(); + } + + public void m_5989_() { + super.m_5989_(); + this.m_108339_(this.sprites); + if (!this.f_107220_) { + float lifeProgress = (float)this.f_107224_ / (float)this.f_107225_; + float flicker = 1.0f - this.f_107223_.m_188501_() * 0.3f; + this.f_107230_ = Mth.m_14036_((float)(flicker * (1.0f - lifeProgress * lifeProgress)), (float)0.0f, (float)1.0f); + this.f_107663_ = this.initialQuadSize * (0.9f + this.f_107223_.m_188501_() * 0.2f); + if (((Boolean)Config.CLIENT.enablePlasmaSmokeTrail.get()).booleanValue() && this.f_107224_ > 2 && (double)this.f_107223_.m_188501_() < (Double)Config.CLIENT.plasmaSmokeFrequency.get()) { + int smokeCount = (Integer)Config.CLIENT.plasmaSmokeCount.get(); + for (int i = 0; i < smokeCount; ++i) { + this.f_107208_.m_7106_((ParticleOptions)new SmokeParticleOptions(0.5f, 200, 0.6f, 0.6f, 0.6f, 0.4f, false, 0.0f, 0.0f, null), this.f_107212_, this.f_107213_, this.f_107214_, (this.f_107223_.m_188500_() - 0.5) * 0.03, (this.f_107223_.m_188500_() - 0.5) * 0.03, (this.f_107223_.m_188500_() - 0.5) * 0.03); + } + } + } + } + + public static class Provider + implements ParticleProvider { + private final SpriteSet sprites; + + public Provider(SpriteSet pSprites) { + this.sprites = pSprites; + } + + public Particle createParticle(PlasmaParticleOptions pType, ClientLevel pLevel, double pX, double pY, double pZ, double pXSpeed, double pYSpeed, double pZSpeed) { + return new PlasmaParticle(pLevel, pX, pY, pZ, pXSpeed, pYSpeed, pZSpeed, pType, this.sprites); + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/PositionalSoundInstance.java b/src/main/java/com/vinlanx/explosionoverhaul/client/PositionalSoundInstance.java new file mode 100644 index 0000000..5e2f4aa --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/PositionalSoundInstance.java @@ -0,0 +1,36 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import net.minecraft.client.resources.sounds.AbstractTickableSoundInstance; +import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.RandomSource; +import net.minecraft.world.phys.Vec3; + +public class PositionalSoundInstance +extends AbstractTickableSoundInstance { + public PositionalSoundInstance(SoundEvent pSound, SoundSource pSource, float pVolume, float pPitch, RandomSource pRandom, double pX, double pY, double pZ) { + super(pSound, pSource, pRandom); + this.f_119573_ = pVolume; + this.f_119574_ = pPitch; + this.f_119575_ = pX; + this.f_119576_ = pY; + this.f_119577_ = pZ; + this.f_119578_ = false; + this.f_119579_ = 0; + this.f_119582_ = false; + this.f_119580_ = SoundInstance.Attenuation.LINEAR; + } + + public void m_7788_() { + } + + public void updatePosition(Vec3 newPosition) { + this.f_119575_ = newPosition.m_7096_(); + this.f_119576_ = newPosition.m_7098_(); + this.f_119577_ = newPosition.m_7094_(); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/ShockwaveEffect.java b/src/main/java/com/vinlanx/explosionoverhaul/client/ShockwaveEffect.java new file mode 100644 index 0000000..a418106 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/ShockwaveEffect.java @@ -0,0 +1,76 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.vinlanx.explosionoverhaul.Config; +import java.util.Random; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.util.Mth; +import net.minecraft.world.phys.Vec3; + +public class ShockwaveEffect { + private final ClientLevel level; + private final Vec3 position; + private final float power; + private final Random random = new Random(); + private int age = 0; + private final int maxAge; + private final float maxRadius; + private final int particlesPerTick; + private final float shellThickness; + private boolean finished = false; + + public ShockwaveEffect(Vec3 position, float power) { + this.level = Minecraft.m_91087_().f_91073_; + this.position = position; + this.power = power; + float powerFraction = Mth.m_184655_((float)this.power, (float)5.0f, (float)100.0f); + this.maxAge = (int)Mth.m_14179_((float)powerFraction, (float)4.0f, (float)7.0f); + float fireballPowerFraction = Mth.m_14036_((float)power, (float)1.0f, (float)100.0f) / 100.0f; + float fireballRadius = Mth.m_14179_((float)fireballPowerFraction, (float)3.0f, (float)40.0f); + float normalizedPowerSqrt = Mth.m_184655_((float)((float)Math.sqrt(power)), (float)((float)Math.sqrt(5.0)), (float)((float)Math.sqrt(100.0))); + float shockwaveMultiplier = Mth.m_14179_((float)normalizedPowerSqrt, (float)2.0f, (float)8.0f); + this.maxRadius = fireballRadius * shockwaveMultiplier * 3.0f; + this.particlesPerTick = (int)Mth.m_14179_((float)powerFraction, (float)70.0f, (float)400.0f); + this.shellThickness = Mth.m_14179_((float)powerFraction, (float)0.5f, (float)4.0f); + } + + public void tick() { + if (this.finished || this.level == null) { + return; + } + if (!((Boolean)Config.CLIENT.enableShockwaveEffect.get()).booleanValue()) { + this.finished = true; + return; + } + ++this.age; + if (this.age > this.maxAge) { + this.finished = true; + return; + } + float progress = (float)this.age / (float)this.maxAge; + float easedProgress = Mth.m_14031_((float)(progress * (float)Math.PI / 2.0f)); + float currentRadius = this.maxRadius * easedProgress; + for (int i = 0; i < this.particlesPerTick; ++i) { + double u = this.random.nextDouble(); + double v = this.random.nextDouble(); + double theta = Math.PI * 2 * u; + double phi = Math.acos(2.0 * v - 1.0); + float radiusOffset = (this.random.nextFloat() - 0.5f) * this.shellThickness; + float finalRadius = currentRadius + radiusOffset; + if (finalRadius < 0.0f) { + finalRadius = 0.0f; + } + Vec3 particlePos = this.position.m_82520_((double)finalRadius * Math.sin(phi) * Math.cos(theta), (double)finalRadius * Math.sin(phi) * Math.sin(theta), (double)finalRadius * Math.cos(phi)); + this.level.m_6493_((ParticleOptions)ParticleTypes.f_123813_, true, particlePos.f_82479_, particlePos.f_82480_, particlePos.f_82481_, 0.0, 0.0, 0.0); + } + } + + public boolean isFinished() { + return this.finished; + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/SmokeParticle.java b/src/main/java/com/vinlanx/explosionoverhaul/client/SmokeParticle.java new file mode 100644 index 0000000..dc20d4f --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/SmokeParticle.java @@ -0,0 +1,95 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.vinlanx.explosionoverhaul.SmokeParticleOptions; +import com.vinlanx.explosionoverhaul.client.ExplosionWindController; +import net.minecraft.client.Camera; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.particle.Particle; +import net.minecraft.client.particle.ParticleProvider; +import net.minecraft.client.particle.ParticleRenderType; +import net.minecraft.client.particle.SpriteSet; +import net.minecraft.client.particle.TextureSheetParticle; +import net.minecraft.world.phys.Vec3; + +public class SmokeParticle +extends TextureSheetParticle { + private final float initialAlpha; + private final boolean isHeavy; + private final float windSpeed; + private final float heightPercent; + + protected SmokeParticle(ClientLevel pLevel, double pX, double pY, double pZ, double pXSpeed, double pYSpeed, double pZSpeed, SmokeParticleOptions options, SpriteSet spriteSet) { + super(pLevel, pX, pY, pZ, pXSpeed, pYSpeed, pZSpeed); + this.f_172258_ = 0.96f; + this.f_107226_ = 0.0f; + this.f_107225_ = options.getLifetime(); + this.f_107663_ = options.getScale(); + this.f_107227_ = options.getRed(); + this.f_107228_ = options.getGreen(); + this.f_107229_ = options.getBlue(); + this.f_107230_ = options.getAlpha(); + this.initialAlpha = options.getAlpha(); + this.isHeavy = options.isHeavy(); + this.windSpeed = options.getWindSpeed(); + this.heightPercent = options.getHeightPercent(); + this.m_108337_(spriteSet.m_213979_(this.f_107223_)); + } + + public void m_5744_(VertexConsumer pBuffer, Camera pRenderInfo, float pPartialTicks) { + RenderSystem.depthMask((this.f_107230_ > 0.3f ? 1 : 0) != 0); + super.m_5744_(pBuffer, pRenderInfo, pPartialTicks); + RenderSystem.depthMask((boolean)true); + } + + public void m_5989_() { + Vec3 direction; + this.f_107209_ = this.f_107212_; + this.f_107210_ = this.f_107213_; + this.f_107211_ = this.f_107214_; + if (this.f_107224_++ >= this.f_107225_) { + this.m_107274_(); + return; + } + if (this.isHeavy) { + this.f_107216_ = -0.04; + } + this.m_6257_(this.f_107215_, this.f_107216_, this.f_107217_); + this.f_107215_ *= (double)this.f_172258_; + this.f_107216_ *= (double)this.f_172258_; + this.f_107217_ *= (double)this.f_172258_; + if (this.windSpeed > 0.0f && (direction = ExplosionWindController.getWindDirection()) != Vec3.f_82478_) { + double targetX = direction.f_82479_ * (double)this.windSpeed; + double targetZ = direction.f_82481_ * (double)this.windSpeed; + this.f_107215_ += (targetX - this.f_107215_) * 0.12; + this.f_107217_ += (targetZ - this.f_107217_) * 0.12; + } + float lifeProgress = (float)this.f_107224_ / (float)this.f_107225_; + this.f_107230_ = this.initialAlpha * (1.0f - lifeProgress); + } + + public boolean shouldCull() { + return false; + } + + public ParticleRenderType m_7556_() { + return ParticleRenderType.f_107431_; + } + + public static class Provider + implements ParticleProvider { + private final SpriteSet sprites; + + public Provider(SpriteSet pSprites) { + this.sprites = pSprites; + } + + public Particle createParticle(SmokeParticleOptions options, ClientLevel pLevel, double pX, double pY, double pZ, double pXSpeed, double pYSpeed, double pZSpeed) { + return new SmokeParticle(pLevel, pX, pY, pZ, pXSpeed, pYSpeed, pZSpeed, options, this.sprites); + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/SoundEngineAudioQueue.java b/src/main/java/com/vinlanx/explosionoverhaul/client/SoundEngineAudioQueue.java new file mode 100644 index 0000000..867ac39 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/SoundEngineAudioQueue.java @@ -0,0 +1,50 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; + +public final class SoundEngineAudioQueue { + private static final Queue QUEUE = new ConcurrentLinkedQueue(); + + private SoundEngineAudioQueue() { + } + + public static void enqueueAudio(Runnable task) { + if (task == null) { + return; + } + if (SoundEngineAudioQueue.isSoundThread()) { + try { + task.run(); + } + catch (Throwable t) { + t.printStackTrace(); + } + SoundEngineAudioQueue.drainNow(); + } else { + QUEUE.offer(task); + } + } + + public static void drainNow() { + Runnable next; + if (!SoundEngineAudioQueue.isSoundThread()) { + return; + } + while ((next = QUEUE.poll()) != null) { + try { + next.run(); + } + catch (Throwable t) { + t.printStackTrace(); + } + } + } + + private static boolean isSoundThread() { + return "Sound engine".equals(Thread.currentThread().getName()); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/SoundPhysicsCompatibility.java b/src/main/java/com/vinlanx/explosionoverhaul/client/SoundPhysicsCompatibility.java new file mode 100644 index 0000000..27e1554 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/SoundPhysicsCompatibility.java @@ -0,0 +1,89 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.sonicether.soundphysics.SoundPhysics; +import com.vinlanx.explosionoverhaul.client.LowPassConcussionEffect; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import net.neoforged.fml.ModList; +import org.lwjgl.openal.AL10; + +public class SoundPhysicsCompatibility { + private static boolean sprLoaded = false; + private static final Map sourceParams = new ConcurrentHashMap(); + + public static void init() { + sprLoaded = ModList.get().isLoaded("sound_physics_remastered"); + if (sprLoaded) { + LowPassConcussionEffect.setCompatibilityMode(true); + } + } + + public static boolean isCompatibilityEnabled() { + return sprLoaded; + } + + public static void cacheParams(int sourceID, float sg0, float sg1, float sg2, float sg3, float sc0, float sc1, float sc2, float sc3, float dc, float dg) { + sourceParams.put(sourceID, new SprParams(sg0, sg1, sg2, sg3, sc0, sc1, sc2, sc3, dc, dg)); + } + + public static void onSourceStop(int sourceID) { + sourceParams.remove(sourceID); + } + + public static void reapplyDirectFilterParameters() { + if (!sprLoaded || sourceParams.isEmpty()) { + return; + } + sourceParams.entrySet().removeIf(entry -> { + int id = (Integer)entry.getKey(); + if (!AL10.alIsSource((int)id)) { + return true; + } + SprParams p = (SprParams)entry.getValue(); + try { + SoundPhysics.setEnvironment((int)id, (float)p.sg0, (float)p.sg1, (float)p.sg2, (float)p.sg3, (float)p.sc0, (float)p.sc1, (float)p.sc2, (float)p.sc3, (float)p.dc, (float)p.dg); + } + catch (Throwable t) { + return true; + } + return false; + }); + } + + public static float combineGain(float sprGain) { + return sprGain * LowPassConcussionEffect.getCurrentGainMultiplier(); + } + + public static float combineHF(float sprHF) { + return Math.min(sprHF, LowPassConcussionEffect.getCurrentHfMultiplier()); + } + + private static class SprParams { + float sg0; + float sg1; + float sg2; + float sg3; + float sc0; + float sc1; + float sc2; + float sc3; + float dc; + float dg; + + SprParams(float sg0, float sg1, float sg2, float sg3, float sc0, float sc1, float sc2, float sc3, float dc, float dg) { + this.sg0 = sg0; + this.sg1 = sg1; + this.sg2 = sg2; + this.sg3 = sg3; + this.sc0 = sc0; + this.sc1 = sc1; + this.sc2 = sc2; + this.sc3 = sc3; + this.dc = dc; + this.dg = dg; + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/SpriteSheetAnimator.java b/src/main/java/com/vinlanx/explosionoverhaul/client/SpriteSheetAnimator.java new file mode 100644 index 0000000..de1668c --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/SpriteSheetAnimator.java @@ -0,0 +1,173 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.mojang.blaze3d.platform.NativeImage; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.Resource; + +public class SpriteSheetAnimator { + private final ResourceLocation spriteSheetLocation; + private final int frameWidth; + private final int frameHeight; + private final int columns; + private final int rows; + private final int totalFrames; + private final float frameTime; + private NativeImage spriteSheet; + private DynamicTexture dynamicTexture; + private ResourceLocation dynamicTextureLocation; + private int currentFrame = 0; + private float animationTime = 0.0f; + private boolean isPlaying = false; + private Map frameCallbacks = new HashMap(); + private Map frameCallbacksTriggered = new HashMap(); + + public SpriteSheetAnimator(ResourceLocation spriteSheetLocation, int frameWidth, int frameHeight, int columns, int rows, int totalFrames, int fps) { + this.spriteSheetLocation = spriteSheetLocation; + this.frameWidth = frameWidth; + this.frameHeight = frameHeight; + this.columns = columns; + this.rows = rows; + this.totalFrames = totalFrames; + this.frameTime = 1.0f / (float)fps; + } + + public void load() { + Minecraft mc = Minecraft.m_91087_(); + try { + InputStream stream = ((Resource)mc.m_91098_().m_213713_(this.spriteSheetLocation).orElseThrow()).m_215507_(); + this.spriteSheet = NativeImage.m_85058_((InputStream)stream); + stream.close(); + NativeImage frameImage = new NativeImage(this.frameWidth, this.frameHeight, false); + this.dynamicTexture = new DynamicTexture(frameImage); + this.dynamicTextureLocation = mc.m_91097_().m_118490_("explosionoverhaul_anim", this.dynamicTexture); + this.updateTexture(); + } + catch (IOException e) { + e.printStackTrace(); + } + catch (Exception e) { + System.err.println("Failed to load sprite sheet: " + this.spriteSheetLocation); + e.printStackTrace(); + this.spriteSheet = null; + this.dynamicTexture = null; + } + } + + public void tick(float deltaTime) { + if (!this.isPlaying || this.spriteSheet == null) { + return; + } + this.animationTime += deltaTime; + if (this.animationTime >= this.frameTime) { + Boolean wasTriggered; + this.animationTime = 0.0f; + ++this.currentFrame; + if (this.currentFrame >= this.totalFrames) { + this.currentFrame = 0; + this.frameCallbacksTriggered.clear(); + } + this.updateTexture(); + if (this.frameCallbacks.containsKey(this.currentFrame) && !(wasTriggered = this.frameCallbacksTriggered.getOrDefault(this.currentFrame, false)).booleanValue()) { + this.frameCallbacks.get(this.currentFrame).run(); + this.frameCallbacksTriggered.put(this.currentFrame, true); + } + } + } + + private void updateTexture() { + if (this.spriteSheet == null || this.dynamicTexture == null) { + return; + } + if (this.currentFrame < 0) { + this.currentFrame = 0; + } + if (this.currentFrame >= this.totalFrames) { + this.currentFrame = this.totalFrames - 1; + } + int col = this.currentFrame % this.columns; + int row = this.currentFrame / this.columns; + int srcX = col * this.frameWidth; + int srcY = row * this.frameHeight; + NativeImage frameImage = this.dynamicTexture.m_117991_(); + if (frameImage == null) { + return; + } + for (int y = 0; y < this.frameHeight; ++y) { + for (int x = 0; x < this.frameWidth; ++x) { + if (srcX + x < this.spriteSheet.m_84982_() && srcY + y < this.spriteSheet.m_85084_()) { + int pixel = this.spriteSheet.m_84985_(srcX + x, srcY + y); + frameImage.m_84988_(x, y, pixel); + continue; + } + frameImage.m_84988_(x, y, 0); + } + } + this.dynamicTexture.m_117985_(); + } + + public void play() { + this.isPlaying = true; + } + + public void pause() { + this.isPlaying = false; + } + + public void reset() { + this.currentFrame = 0; + this.animationTime = 0.0f; + this.isPlaying = false; + this.frameCallbacksTriggered.clear(); + this.updateTexture(); + } + + public ResourceLocation getTextureLocation() { + return this.dynamicTextureLocation; + } + + public int getFrameWidth() { + return this.frameWidth; + } + + public int getFrameHeight() { + return this.frameHeight; + } + + public int getCurrentFrame() { + return this.currentFrame; + } + + public void registerFrameCallback(int frameNumber, Runnable callback) { + if (frameNumber >= 0 && frameNumber < this.totalFrames) { + this.frameCallbacks.put(frameNumber, callback); + } + } + + public void unregisterFrameCallback(int frameNumber) { + this.frameCallbacks.remove(frameNumber); + this.frameCallbacksTriggered.remove(frameNumber); + } + + public void clearFrameCallbacks() { + this.frameCallbacks.clear(); + this.frameCallbacksTriggered.clear(); + } + + public void close() { + if (this.dynamicTexture != null) { + this.dynamicTexture.close(); + } + if (this.spriteSheet != null) { + this.spriteSheet.close(); + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/client/VinlanxSplashScreen.java b/src/main/java/com/vinlanx/explosionoverhaul/client/VinlanxSplashScreen.java new file mode 100644 index 0000000..0736518 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/client/VinlanxSplashScreen.java @@ -0,0 +1,145 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.client; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.vinlanx.explosionoverhaul.ExplosionOverhaul; +import com.vinlanx.explosionoverhaul.ModSounds; +import com.vinlanx.explosionoverhaul.client.GuideSlidesScreen; +import com.vinlanx.explosionoverhaul.client.SpriteSheetAnimator; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.client.resources.sounds.SoundInstance; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvent; + +public class VinlanxSplashScreen +extends Screen { + private static final ResourceLocation SPRITE_SHEET = ResourceLocation.fromNamespaceAndPath((String)"explosionoverhaul", (String)"intro_gui/vinlanx_screen.png"); + private static final int FRAME_WIDTH = 1280; + private static final int FRAME_HEIGHT = 720; + private static final int COLUMNS = 12; + private static final int ROWS = 12; + private static final int TOTAL_FRAMES = 126; + private static final int FPS = 24; + private SpriteSheetAnimator animator; + private boolean animationFinished = false; + private long lastFrameTime = System.currentTimeMillis(); + private SimpleSoundInstance boomSoundInstance; + + public VinlanxSplashScreen() { + super((Component)Component.m_237113_((String)"Vinlanx Intro")); + } + + protected void m_7856_() { + super.m_7856_(); + this.animator = new SpriteSheetAnimator(SPRITE_SHEET, 1280, 720, 12, 12, 126, 24); + this.animator.load(); + this.animator.play(); + try { + SoundManager soundManager = Minecraft.m_91087_().m_91106_(); + this.boomSoundInstance = SimpleSoundInstance.m_119755_((SoundEvent)((SoundEvent)ModSounds.INTRO_BOOM_2.get()), (float)1.0f, (float)1.0f); + soundManager.m_120367_((SoundInstance)this.boomSoundInstance); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to play intro_boom_2: {}", (Object)e.toString()); + } + } + + public void m_86600_() { + super.m_86600_(); + long currentTime = System.currentTimeMillis(); + float deltaTime = (float)(currentTime - this.lastFrameTime) / 1000.0f; + this.lastFrameTime = currentTime; + if (this.animator != null) { + this.animator.tick(deltaTime); + if (!this.animationFinished && this.animator.getCurrentFrame() >= 125) { + this.animationFinished = true; + this.transitionToFirstTimeScreen(); + } + } + } + + public void m_88315_(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) { + int displayWidth; + int displayHeight; + graphics.m_280509_(0, 0, this.f_96543_, this.f_96544_, -16777216); + if (this.animator == null) { + return; + } + ResourceLocation texture = this.animator.getTextureLocation(); + if (texture == null) { + return; + } + float screenAspectRatio = (float)this.f_96543_ / (float)this.f_96544_; + float targetAspectRatio = 1.7777778f; + if (screenAspectRatio > targetAspectRatio) { + displayHeight = this.f_96544_; + displayWidth = (int)((float)displayHeight * targetAspectRatio); + } else { + displayWidth = this.f_96543_; + displayHeight = (int)((float)displayWidth / targetAspectRatio); + } + int x = (this.f_96543_ - displayWidth) / 2; + int y = (this.f_96544_ - displayHeight) / 2; + RenderSystem.setShader(GameRenderer::m_172817_); + RenderSystem.setShaderTexture((int)0, (ResourceLocation)texture); + RenderSystem.setShaderColor((float)1.0f, (float)1.0f, (float)1.0f, (float)1.0f); + RenderSystem.enableBlend(); + RenderSystem.defaultBlendFunc(); + graphics.m_280411_(texture, x, y, displayWidth, displayHeight, 0.0f, 0.0f, 1280, 720, 1280, 720); + RenderSystem.disableBlend(); + } + + public boolean m_6913_() { + return true; + } + + public boolean m_7933_(int keyCode, int scanCode, int modifiers) { + if (keyCode == 256) { + this.skipToNext(); + return true; + } + return super.m_7933_(keyCode, scanCode, modifiers); + } + + public boolean m_6375_(double mouseX, double mouseY, int button) { + this.skipToNext(); + return true; + } + + public boolean m_7043_() { + return false; + } + + public void m_7861_() { + super.m_7861_(); + if (this.animator != null) { + this.animator.close(); + } + if (this.boomSoundInstance != null) { + try { + Minecraft.m_91087_().m_91106_().m_120399_((SoundInstance)this.boomSoundInstance); + } + catch (Exception e) { + ExplosionOverhaul.LOGGER.warn("Failed to stop intro_boom_2: {}", (Object)e.toString()); + } + } + } + + private void skipToNext() { + this.animationFinished = true; + this.transitionToFirstTimeScreen(); + } + + private void transitionToFirstTimeScreen() { + Minecraft mc = Minecraft.m_91087_(); + mc.m_91152_((Screen)new GuideSlidesScreen()); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/mixin/ChannelAccessor.java b/src/main/java/com/vinlanx/explosionoverhaul/mixin/ChannelAccessor.java new file mode 100644 index 0000000..5a13849 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/mixin/ChannelAccessor.java @@ -0,0 +1,14 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.mixin; + +import com.mojang.blaze3d.audio.Channel; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(value={Channel.class}) +public interface ChannelAccessor { + @Accessor(value="source") + public int explosionoverhaul$getSource(); +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/mixin/ChannelLowpassMixin.java b/src/main/java/com/vinlanx/explosionoverhaul/mixin/ChannelLowpassMixin.java new file mode 100644 index 0000000..452a7bf --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/mixin/ChannelLowpassMixin.java @@ -0,0 +1,57 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.mixin; + +import com.mojang.blaze3d.audio.Channel; +import com.vinlanx.explosionoverhaul.client.LowPassConcussionEffect; +import com.vinlanx.explosionoverhaul.client.SoundEngineAudioQueue; +import com.vinlanx.explosionoverhaul.client.SoundPhysicsCompatibility; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value={Channel.class}) +public class ChannelLowpassMixin { + @Shadow + @Final + private int f_83642_; + + @Inject(method={"play"}, at={@At(value="HEAD")}) + private void onPlay(CallbackInfo ci) { + try { + boolean active = LowPassConcussionEffect.isActive(); + if ("Sound engine".equals(Thread.currentThread().getName())) { + SoundEngineAudioQueue.drainNow(); + } + if (active) { + SoundEngineAudioQueue.enqueueAudio(() -> LowPassConcussionEffect.attachFilterToSource(this.f_83642_)); + if ("Sound engine".equals(Thread.currentThread().getName())) { + SoundEngineAudioQueue.drainNow(); + } + } + } + catch (Throwable throwable) { + // empty catch block + } + } + + @Inject(method={"stop"}, at={@At(value="HEAD")}) + private void onStop(CallbackInfo ci) { + if (SoundPhysicsCompatibility.isCompatibilityEnabled()) { + SoundPhysicsCompatibility.onSourceStop(this.f_83642_); + } + try { + SoundEngineAudioQueue.enqueueAudio(() -> LowPassConcussionEffect.detachFilterFromSource(this.f_83642_)); + if ("Sound engine".equals(Thread.currentThread().getName())) { + SoundEngineAudioQueue.drainNow(); + } + } + catch (Throwable throwable) { + // empty catch block + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/mixin/ExplosionMixin.java b/src/main/java/com/vinlanx/explosionoverhaul/mixin/ExplosionMixin.java new file mode 100644 index 0000000..4bb3fa7 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/mixin/ExplosionMixin.java @@ -0,0 +1,91 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.mixin; + +import com.vinlanx.explosionoverhaul.ServerExplosionHandler; +import com.vinlanx.explosionoverhaul.api.IExplosionPower; +import com.vinlanx.explosionoverhaul.mixinhelper.ExplosionAccessor; +import java.util.List; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.ExplosionDamageCalculator; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value={Explosion.class}) +public abstract class ExplosionMixin +implements IExplosionPower, +ExplosionAccessor { + @Shadow + @Final + private Level f_46012_; + @Shadow + @Final + @Nullable + private Entity f_46016_; + @Shadow + @Final + private double f_46013_; + @Shadow + @Final + private double f_46014_; + @Shadow + @Final + private double f_46015_; + @Unique + private float explosionPower; + + @Shadow + public abstract List m_46081_(); + + @Inject(method={"(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/Entity;DDDFZLnet/minecraft/world/level/Explosion$BlockInteraction;)V"}, at={@At(value="RETURN")}) + private void capturePowerSimple(Level level, Entity source, double x, double y, double z, float power, boolean fire, Explosion.BlockInteraction interaction, CallbackInfo ci) { + this.explosionPower = power; + } + + @Inject(method={"(Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/damagesource/DamageSource;Lnet/minecraft/world/level/ExplosionDamageCalculator;DDDFZLnet/minecraft/world/level/Explosion$BlockInteraction;)V"}, at={@At(value="RETURN")}) + private void capturePowerComplex(Level level, @Nullable Entity entity, @Nullable DamageSource damageSource, @Nullable ExplosionDamageCalculator damageCalculator, double x, double y, double z, float power, boolean fire, Explosion.BlockInteraction blockInteraction, CallbackInfo ci) { + this.explosionPower = power; + } + + @Override + public float getPower() { + return this.explosionPower; + } + + @Override + public void setPower(float power) { + this.explosionPower = power; + } + + @Override + public Vec3 explosionoverhaul$getCenter() { + return new Vec3(this.f_46013_, this.f_46014_, this.f_46015_); + } + + @Override + public Entity explosionoverhaul$getSource() { + return this.f_46016_; + } + + @Inject(method={"finalizeExplosion(Z)V"}, at={@At(value="HEAD")}) + private void onFinalizeExplosion(boolean spawnParticles, CallbackInfo ci) { + Level level = this.f_46012_; + if (level instanceof ServerLevel) { + ServerLevel serverLevel = (ServerLevel)level; + ServerExplosionHandler.handleExplosion(serverLevel, (Explosion)this, this.m_46081_()); + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/mixin/GameRendererBlurMixin.java b/src/main/java/com/vinlanx/explosionoverhaul/mixin/GameRendererBlurMixin.java new file mode 100644 index 0000000..42f8f82 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/mixin/GameRendererBlurMixin.java @@ -0,0 +1,30 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.mixin; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.vinlanx.explosionoverhaul.client.Blur; +import net.minecraft.client.renderer.GameRenderer; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value={GameRenderer.class}) +public class GameRendererBlurMixin { + @Inject(method={"renderLevel"}, at={@At(value="INVOKE", target="Lnet/minecraft/client/renderer/LevelRenderer;renderLevel(Lcom/mojang/blaze3d/vertex/PoseStack;FJZLnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/GameRenderer;Lnet/minecraft/client/renderer/LightTexture;Lorg/joml/Matrix4f;)V", shift=At.Shift.AFTER)}) + private void explosionoverhaul$afterWorld(float tickDelta, long nanoTime, PoseStack poseStack, CallbackInfo ci) { + Blur.render(Blur.RenderStage.WORLD); + } + + @Inject(method={"renderLevel"}, at={@At(value="INVOKE", target="Lnet/minecraft/client/renderer/GameRenderer;renderItemInHand(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/Camera;F)V", shift=At.Shift.AFTER)}) + private void explosionoverhaul$afterHand(float tickDelta, long nanoTime, PoseStack poseStack, CallbackInfo ci) { + Blur.render(Blur.RenderStage.HAND); + } + + @Inject(method={"render"}, at={@At(value="TAIL")}) + private void explosionoverhaul$afterGui(float tickDelta, long nanoTime, boolean renderLevel, CallbackInfo ci) { + Blur.render(Blur.RenderStage.HUD); + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/mixin/SoundEngineAudioQueueMixin.java b/src/main/java/com/vinlanx/explosionoverhaul/mixin/SoundEngineAudioQueueMixin.java new file mode 100644 index 0000000..fdf3294 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/mixin/SoundEngineAudioQueueMixin.java @@ -0,0 +1,41 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.mixin; + +import com.vinlanx.explosionoverhaul.client.LowPassConcussionEffect; +import com.vinlanx.explosionoverhaul.client.SoundEngineAudioQueue; +import com.vinlanx.explosionoverhaul.mixin.ChannelAccessor; +import net.minecraft.client.sounds.ChannelAccess; +import net.minecraft.client.sounds.SoundEngine; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value={SoundEngine.class}) +public class SoundEngineAudioQueueMixin { + @Shadow + @Final + private ChannelAccess f_120224_; + @Unique + private boolean explosionoverhaul$wasActive = false; + + @Inject(method={"tick(Z)V"}, at={@At(value="HEAD")}) + private void explosionoverhaul$drainAudioQueue(boolean paused, CallbackInfo ci) { + boolean active = LowPassConcussionEffect.isActive(); + boolean wasActive = this.explosionoverhaul$wasActive; + this.f_120224_.m_120137_(channels -> { + SoundEngineAudioQueue.drainNow(); + if (active) { + channels.forEach(channel -> LowPassConcussionEffect.attachFilterToSource(((ChannelAccessor)channel).explosionoverhaul$getSource())); + } else if (wasActive) { + channels.forEach(channel -> LowPassConcussionEffect.detachFilterFromSource(((ChannelAccessor)channel).explosionoverhaul$getSource())); + } + }); + this.explosionoverhaul$wasActive = active; + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/mixin/SoundPhysicsEnvironmentMixin.java b/src/main/java/com/vinlanx/explosionoverhaul/mixin/SoundPhysicsEnvironmentMixin.java new file mode 100644 index 0000000..fe759d6 --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/mixin/SoundPhysicsEnvironmentMixin.java @@ -0,0 +1,110 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.mixin; + +import com.sonicether.soundphysics.SoundPhysics; +import com.vinlanx.explosionoverhaul.client.SoundPhysicsCompatibility; +import org.lwjgl.openal.AL10; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyVariable; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value={SoundPhysics.class}, remap=false) +public abstract class SoundPhysicsEnvironmentMixin { + @Inject(method={"setEnvironment"}, at={@At(value="HEAD")}) + private static void onSetEnvironment(int sourceID, float sg0, float sg1, float sg2, float sg3, float sc0, float sc1, float sc2, float sc3, float dc, float dg, CallbackInfo ci) { + SoundPhysicsCompatibility.cacheParams(sourceID, sg0, sg1, sg2, sg3, sc0, sc1, sc2, sc3, dc, dg); + } + + @ModifyVariable(method={"setEnvironment"}, at=@At(value="HEAD"), ordinal=0, argsOnly=true) + private static float modifySendGain0(float value, int sourceID) { + if (SoundPhysicsEnvironmentMixin.isRelative(sourceID)) { + return value; + } + return SoundPhysicsCompatibility.combineGain(value); + } + + @ModifyVariable(method={"setEnvironment"}, at=@At(value="HEAD"), ordinal=1, argsOnly=true) + private static float modifySendGain1(float value, int sourceID) { + if (SoundPhysicsEnvironmentMixin.isRelative(sourceID)) { + return value; + } + return SoundPhysicsCompatibility.combineGain(value); + } + + @ModifyVariable(method={"setEnvironment"}, at=@At(value="HEAD"), ordinal=2, argsOnly=true) + private static float modifySendGain2(float value, int sourceID) { + if (SoundPhysicsEnvironmentMixin.isRelative(sourceID)) { + return value; + } + return SoundPhysicsCompatibility.combineGain(value); + } + + @ModifyVariable(method={"setEnvironment"}, at=@At(value="HEAD"), ordinal=3, argsOnly=true) + private static float modifySendGain3(float value, int sourceID) { + if (SoundPhysicsEnvironmentMixin.isRelative(sourceID)) { + return value; + } + return SoundPhysicsCompatibility.combineGain(value); + } + + @ModifyVariable(method={"setEnvironment"}, at=@At(value="HEAD"), ordinal=4, argsOnly=true) + private static float modifySendCutoff0(float value, int sourceID) { + if (SoundPhysicsEnvironmentMixin.isRelative(sourceID)) { + return value; + } + return SoundPhysicsCompatibility.combineHF(value); + } + + @ModifyVariable(method={"setEnvironment"}, at=@At(value="HEAD"), ordinal=5, argsOnly=true) + private static float modifySendCutoff1(float value, int sourceID) { + if (SoundPhysicsEnvironmentMixin.isRelative(sourceID)) { + return value; + } + return SoundPhysicsCompatibility.combineHF(value); + } + + @ModifyVariable(method={"setEnvironment"}, at=@At(value="HEAD"), ordinal=6, argsOnly=true) + private static float modifySendCutoff2(float value, int sourceID) { + if (SoundPhysicsEnvironmentMixin.isRelative(sourceID)) { + return value; + } + return SoundPhysicsCompatibility.combineHF(value); + } + + @ModifyVariable(method={"setEnvironment"}, at=@At(value="HEAD"), ordinal=7, argsOnly=true) + private static float modifySendCutoff3(float value, int sourceID) { + if (SoundPhysicsEnvironmentMixin.isRelative(sourceID)) { + return value; + } + return SoundPhysicsCompatibility.combineHF(value); + } + + @ModifyVariable(method={"setEnvironment"}, at=@At(value="HEAD"), ordinal=8, argsOnly=true) + private static float modifyDirectCutoff(float value, int sourceID) { + if (SoundPhysicsEnvironmentMixin.isRelative(sourceID)) { + return value; + } + return SoundPhysicsCompatibility.combineHF(value); + } + + @ModifyVariable(method={"setEnvironment"}, at=@At(value="HEAD"), ordinal=9, argsOnly=true) + private static float modifyDirectGain(float value, int sourceID) { + if (SoundPhysicsEnvironmentMixin.isRelative(sourceID)) { + return value; + } + return SoundPhysicsCompatibility.combineGain(value); + } + + private static boolean isRelative(int sourceID) { + try { + return AL10.alGetSourcei((int)sourceID, (int)514) == 1; + } + catch (Throwable ignored) { + return false; + } + } +} diff --git a/src/main/java/com/vinlanx/explosionoverhaul/mixinhelper/ExplosionAccessor.java b/src/main/java/com/vinlanx/explosionoverhaul/mixinhelper/ExplosionAccessor.java new file mode 100644 index 0000000..333efeb --- /dev/null +++ b/src/main/java/com/vinlanx/explosionoverhaul/mixinhelper/ExplosionAccessor.java @@ -0,0 +1,13 @@ +/* + * Decompiled with CFR 0.152. + */ +package com.vinlanx.explosionoverhaul.mixinhelper; + +import net.minecraft.world.entity.Entity; +import net.minecraft.world.phys.Vec3; + +public interface ExplosionAccessor { + public Vec3 explosionoverhaul$getCenter(); + + public Entity explosionoverhaul$getSource(); +} diff --git a/src/main/resources/CREDITS.txt b/src/main/resources/CREDITS.txt new file mode 100644 index 0000000..dc3c728 --- /dev/null +++ b/src/main/resources/CREDITS.txt @@ -0,0 +1,12 @@ +# Explosion Overhaul Credits + +## Assets: +- Explosion animation textures are based on assets by "huykhoi2407" from CGTrader. + Link: https://www.cgtrader.com/designers/huykhoi2407 + +## Audio: +- Some sound effects were taken from Pixabay under the Pixabay License, provided by "freesound_community": + - https://pixabay.com/sound-effects/033830-fxlm-neon-lights-flicker-bathroomwav-75200/ + - https://pixabay.com/sound-effects/lights-flicker-on-and-some-electrical-noises-33079/ + - https://pixabay.com/sound-effects//?utm_source=link-attribution&utm_medium=referral&utm_campaign=music&utm_content=205398 + - https://pixabay.com/music/ambient-horror-background-atmosphere-07-389389/ diff --git a/src/main/resources/LICENSE.txt b/src/main/resources/LICENSE.txt new file mode 100644 index 0000000..7a9d094 --- /dev/null +++ b/src/main/resources/LICENSE.txt @@ -0,0 +1,34 @@ +Custom License for Explosion Overhaul Mod   +Copyright © 2025 Vinlanx. All rights reserved. + +You are permitted to: + +- Use this mod in non-commercial modpacks or videos, provided that proper credit is given. +- Share the unmodified version of the mod. +- Modify the mod for personal and private use only. + +You are NOT permitted to: + +- Use this mod or any part of it for commercial purposes. +- Re-upload or redistribute modified or unmodified versions of this mod without explicit written permission. +- Include this mod in paid modpacks, monetized servers, or any commercial platform. + +Liability Disclaimer: +The author of this mod is not responsible for any unauthorized redistribution, modification, or commercial use performed by third parties. Any legal issues arising from such actions fall solely on the individuals involved in the unauthorized use. + +Attribution Notice:   +This mod includes third-party assets used under their respective licenses: + +- Explosion animation textures based on assets by "huykhoi2407" from CGTrader   +  https://www.cgtrader.com/designers/huykhoi2407 + +- Explosion animation textures based on video Green Screen Ai  +  https://www.youtube.com/shorts/kiL6WBmBCPk + +- Sound effects from Pixabay under the Pixabay License: +  - https://pixabay.com/sound-effects/033830-fxlm-neon-lights-flicker-bathroomwav-75200/ +  - https://pixabay.com/sound-effects/lights-flicker-on-and-some-electrical-noises-33079/   +  Provided by "freesound_community" + +All third-party assets remain the property of their respective creators and are used in compliance with their stated terms. +If you are the copyright holder of any referenced asset and object to this usage, please contact the author. diff --git a/src/main/resources/assets/explosionoverhaul/animations/vinlanxthelight.animation.json b/src/main/resources/assets/explosionoverhaul/animations/vinlanxthelight.animation.json new file mode 100644 index 0000000..909c619 --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/animations/vinlanxthelight.animation.json @@ -0,0 +1,4 @@ +{ + "format_version": "1.8.0", + "animations": {} +} diff --git a/src/main/resources/assets/explosionoverhaul/blockstates/vinlanx_the_light.json b/src/main/resources/assets/explosionoverhaul/blockstates/vinlanx_the_light.json new file mode 100644 index 0000000..c355a90 --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/blockstates/vinlanx_the_light.json @@ -0,0 +1,8 @@ +{ + "variants": { + "facing=north": { "model": "explosionoverhaul:block/vinlanx_the_light" }, + "facing=south": { "model": "explosionoverhaul:block/vinlanx_the_light", "y": 180 }, + "facing=east": { "model": "explosionoverhaul:block/vinlanx_the_light", "y": 90 }, + "facing=west": { "model": "explosionoverhaul:block/vinlanx_the_light", "y": 270 } + } +} diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_e_sheet_1.png b/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_e_sheet_1.png new file mode 100644 index 0000000..0dbd3fb Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_e_sheet_1.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_e_sheet_2.png b/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_e_sheet_2.png new file mode 100644 index 0000000..e4472a0 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_e_sheet_2.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_e_sheet_3.png b/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_e_sheet_3.png new file mode 100644 index 0000000..2108296 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_e_sheet_3.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_e_sheet_4.png b/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_e_sheet_4.png new file mode 100644 index 0000000..144818c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_e_sheet_4.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_sheet_1.png b/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_sheet_1.png new file mode 100644 index 0000000..cf5fa02 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_sheet_1.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_sheet_2.png b/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_sheet_2.png new file mode 100644 index 0000000..32cf7f4 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_sheet_2.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_sheet_3.png b/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_sheet_3.png new file mode 100644 index 0000000..5b75795 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_sheet_3.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_sheet_4.png b/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_sheet_4.png new file mode 100644 index 0000000..349c797 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow/64/glow_sheet_4.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_e_sheet_1.png b/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_e_sheet_1.png new file mode 100644 index 0000000..2fb544c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_e_sheet_1.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_e_sheet_2.png b/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_e_sheet_2.png new file mode 100644 index 0000000..8966f56 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_e_sheet_2.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_e_sheet_3.png b/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_e_sheet_3.png new file mode 100644 index 0000000..8507fc3 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_e_sheet_3.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_e_sheet_4.png b/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_e_sheet_4.png new file mode 100644 index 0000000..7ee46c8 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_e_sheet_4.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_sheet_1.png b/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_sheet_1.png new file mode 100644 index 0000000..2b5e0bd Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_sheet_1.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_sheet_2.png b/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_sheet_2.png new file mode 100644 index 0000000..19afb76 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_sheet_2.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_sheet_3.png b/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_sheet_3.png new file mode 100644 index 0000000..c3b358c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_sheet_3.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_sheet_4.png b/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_sheet_4.png new file mode 100644 index 0000000..027f8f1 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow/glow_sheet_4.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_e_sheet_1.png b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_e_sheet_1.png new file mode 100644 index 0000000..05b7ce9 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_e_sheet_1.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_e_sheet_2.png b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_e_sheet_2.png new file mode 100644 index 0000000..7f9c8d0 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_e_sheet_2.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_e_sheet_3.png b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_e_sheet_3.png new file mode 100644 index 0000000..68a3d8a Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_e_sheet_3.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_e_sheet_4.png b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_e_sheet_4.png new file mode 100644 index 0000000..795070c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_e_sheet_4.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_sheet_1.png b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_sheet_1.png new file mode 100644 index 0000000..ef602aa Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_sheet_1.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_sheet_2.png b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_sheet_2.png new file mode 100644 index 0000000..8a625f6 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_sheet_2.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_sheet_3.png b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_sheet_3.png new file mode 100644 index 0000000..512ca85 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_sheet_3.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_sheet_4.png b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_sheet_4.png new file mode 100644 index 0000000..7a925d9 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/64/glow_2_sheet_4.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_e_sheet_1.png b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_e_sheet_1.png new file mode 100644 index 0000000..3bb46db Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_e_sheet_1.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_e_sheet_2.png b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_e_sheet_2.png new file mode 100644 index 0000000..7de2a13 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_e_sheet_2.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_e_sheet_3.png b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_e_sheet_3.png new file mode 100644 index 0000000..5464253 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_e_sheet_3.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_e_sheet_4.png b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_e_sheet_4.png new file mode 100644 index 0000000..c4f1694 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_e_sheet_4.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_sheet_1.png b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_sheet_1.png new file mode 100644 index 0000000..32919c4 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_sheet_1.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_sheet_2.png b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_sheet_2.png new file mode 100644 index 0000000..f1e58a4 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_sheet_2.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_sheet_3.png b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_sheet_3.png new file mode 100644 index 0000000..fc325ff Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_sheet_3.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_sheet_4.png b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_sheet_4.png new file mode 100644 index 0000000..4e88f0a Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/glow_2/glow_2_sheet_4.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_e_sheet_1.png b/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_e_sheet_1.png new file mode 100644 index 0000000..1f2669e Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_e_sheet_1.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_e_sheet_2.png b/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_e_sheet_2.png new file mode 100644 index 0000000..144818c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_e_sheet_2.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_e_sheet_3.png b/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_e_sheet_3.png new file mode 100644 index 0000000..144818c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_e_sheet_3.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_e_sheet_4.png b/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_e_sheet_4.png new file mode 100644 index 0000000..144818c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_e_sheet_4.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_sheet_1.png b/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_sheet_1.png new file mode 100644 index 0000000..a42817b Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_sheet_1.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_sheet_2.png b/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_sheet_2.png new file mode 100644 index 0000000..3ee42bd Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_sheet_2.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_sheet_3.png b/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_sheet_3.png new file mode 100644 index 0000000..7c69322 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_sheet_3.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_sheet_4.png b/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_sheet_4.png new file mode 100644 index 0000000..144818c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/sglow/64/sglow_sheet_4.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_e_sheet_1.png b/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_e_sheet_1.png new file mode 100644 index 0000000..22965a5 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_e_sheet_1.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_e_sheet_2.png b/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_e_sheet_2.png new file mode 100644 index 0000000..f271fcb Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_e_sheet_2.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_e_sheet_3.png b/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_e_sheet_3.png new file mode 100644 index 0000000..7fe7859 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_e_sheet_3.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_e_sheet_4.png b/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_e_sheet_4.png new file mode 100644 index 0000000..7fe7859 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_e_sheet_4.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_sheet_1.png b/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_sheet_1.png new file mode 100644 index 0000000..ba4e3ef Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_sheet_1.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_sheet_2.png b/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_sheet_2.png new file mode 100644 index 0000000..4c19ed1 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_sheet_2.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_sheet_3.png b/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_sheet_3.png new file mode 100644 index 0000000..84205b2 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_sheet_3.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_sheet_4.png b/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_sheet_4.png new file mode 100644 index 0000000..7ee46c8 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/sglow/sglow_sheet_4.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/soft_glow.png b/src/main/resources/assets/explosionoverhaul/explosions/soft_glow.png new file mode 100644 index 0000000..590e934 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/soft_glow.png differ diff --git a/src/main/resources/assets/explosionoverhaul/explosions/soft_glow_e.png b/src/main/resources/assets/explosionoverhaul/explosions/soft_glow_e.png new file mode 100644 index 0000000..590e934 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/explosions/soft_glow_e.png differ diff --git a/src/main/resources/assets/explosionoverhaul/geo/vinlanxthelight.geo.json b/src/main/resources/assets/explosionoverhaul/geo/vinlanxthelight.geo.json new file mode 100644 index 0000000..138b205 --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/geo/vinlanxthelight.geo.json @@ -0,0 +1,427 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.steve base by jpc craft", + "texture_width": 64, + "texture_height": 64, + "visible_bounds_width": 3, + "visible_bounds_height": 4.5, + "visible_bounds_offset": [0, 1.75, 0] + }, + "bones": [ + { + "name": "bb_main", + "pivot": [0, 0, 0], + "cubes": [ + { + "origin": [8, 0, -9], + "size": [2, 15, 2], + "pivot": [9, 0, -8], + "rotation": [-4.99527, -0.21782, -2.4905], + "uv": { + "north": {"uv": [58, 42], "uv_size": [2, 2]}, + "east": {"uv": [58, 41], "uv_size": [2, 2]}, + "south": {"uv": [60, 42], "uv_size": [2, 2]}, + "west": {"uv": [60, 42], "uv_size": [2, 2]}, + "up": {"uv": [59, 42], "uv_size": [2, 2]}, + "down": {"uv": [59, 44], "uv_size": [2, -2]} + } + }, + { + "origin": [-7, 0, 7], + "size": [2, 15, 2], + "pivot": [-5, 0, 8], + "rotation": [6.78263, 0.66416, 7.7344], + "uv": { + "north": {"uv": [58, 42], "uv_size": [2, 2]}, + "east": {"uv": [58, 41], "uv_size": [2, 2]}, + "south": {"uv": [60, 42], "uv_size": [2, 2]}, + "west": {"uv": [60, 42], "uv_size": [2, 2]}, + "up": {"uv": [59, 42], "uv_size": [2, 2]}, + "down": {"uv": [59, 44], "uv_size": [2, -2]} + } + }, + { + "origin": [-7, 15.5, 7], + "size": [2, 10.5, 2], + "pivot": [-5, 15, 8], + "rotation": [1.55224, -6.6366, 90.10504], + "uv": { + "north": {"uv": [58, 42], "uv_size": [2, 2]}, + "east": {"uv": [58, 41], "uv_size": [2, 2]}, + "south": {"uv": [60, 42], "uv_size": [2, 2]}, + "west": {"uv": [60, 42], "uv_size": [2, 2]}, + "up": {"uv": [59, 42], "uv_size": [2, 2]}, + "down": {"uv": [59, 44], "uv_size": [2, -2]} + } + }, + { + "origin": [-3, 16, 6.8], + "size": [1, 16, 1], + "pivot": [-2, 16, 6], + "rotation": [6.56592, 1.82933, -2.20001], + "uv": { + "north": {"uv": [58, 42], "uv_size": [2, 2]}, + "east": {"uv": [58, 41], "uv_size": [2, 2]}, + "south": {"uv": [60, 42], "uv_size": [2, 2]}, + "west": {"uv": [60, 42], "uv_size": [2, 2]}, + "up": {"uv": [59, 42], "uv_size": [2, 2]}, + "down": {"uv": [59, 44], "uv_size": [2, -2]} + } + }, + { + "origin": [-5, 16, 6.8], + "size": [1, 15, 1], + "pivot": [-4, 16, 6], + "rotation": [6.48042, 2.11339, -4.6853], + "uv": { + "north": {"uv": [58, 42], "uv_size": [2, 2]}, + "east": {"uv": [58, 41], "uv_size": [2, 2]}, + "south": {"uv": [60, 42], "uv_size": [2, 2]}, + "west": {"uv": [60, 42], "uv_size": [2, 2]}, + "up": {"uv": [59, 42], "uv_size": [2, 2]}, + "down": {"uv": [59, 44], "uv_size": [2, -2]} + } + }, + { + "origin": [-10.3, 32.2, 5.3], + "size": [1.5, 6.5, 1.3], + "pivot": [-9, 30, 4], + "rotation": [3.22235, -6.00814, 75.02589], + "uv": { + "north": {"uv": [58, 42], "uv_size": [2, 2]}, + "east": {"uv": [58, 41], "uv_size": [2, 2]}, + "south": {"uv": [60, 42], "uv_size": [2, 2]}, + "west": {"uv": [60, 42], "uv_size": [2, 2]}, + "up": {"uv": [59, 42], "uv_size": [2, 2]}, + "down": {"uv": [59, 44], "uv_size": [2, -2]} + } + }, + { + "origin": [-8.3, 38, 5.1], + "size": [1.5, 3.5, 1.3], + "pivot": [-7, 32, 4], + "rotation": [1.8414, -6.56256, 87.58946], + "uv": { + "north": {"uv": [58, 42], "uv_size": [2, 2]}, + "east": {"uv": [58, 41], "uv_size": [2, 2]}, + "south": {"uv": [60, 42], "uv_size": [2, 2]}, + "west": {"uv": [60, 42], "uv_size": [2, 2]}, + "up": {"uv": [59, 42], "uv_size": [2, 2]}, + "down": {"uv": [59, 44], "uv_size": [2, -2]} + } + }, + { + "origin": [0.5, 32, 4.8], + "size": [1.5, 6, 1.3], + "pivot": [2, 32, 4], + "rotation": [0.07241, -6.81454, 102.69073], + "uv": { + "north": {"uv": [58, 42], "uv_size": [2, 2]}, + "east": {"uv": [58, 41], "uv_size": [2, 2]}, + "south": {"uv": [60, 42], "uv_size": [2, 2]}, + "west": {"uv": [60, 42], "uv_size": [2, 2]}, + "up": {"uv": [59, 42], "uv_size": [2, 2]}, + "down": {"uv": [59, 44], "uv_size": [2, -2]} + } + }, + { + "origin": [0, 16, 6.8], + "size": [1, 17, 1], + "pivot": [1, 16, 6], + "rotation": [6.63902, 1.54184, 1], + "uv": { + "north": {"uv": [58, 42], "uv_size": [2, 2]}, + "east": {"uv": [58, 41], "uv_size": [2, 2]}, + "south": {"uv": [60, 42], "uv_size": [2, 2]}, + "west": {"uv": [60, 42], "uv_size": [2, 2]}, + "up": {"uv": [59, 42], "uv_size": [2, 2]}, + "down": {"uv": [59, 44], "uv_size": [2, -2]} + } + }, + { + "origin": [3, 16, 6.8], + "size": [1, 16, 1], + "pivot": [4, 16, 6], + "rotation": [6.69956, 1.25145, 2.7683], + "uv": { + "north": {"uv": [58, 42], "uv_size": [2, 2]}, + "east": {"uv": [58, 41], "uv_size": [2, 2]}, + "south": {"uv": [60, 42], "uv_size": [2, 2]}, + "west": {"uv": [60, 42], "uv_size": [2, 2]}, + "up": {"uv": [59, 42], "uv_size": [2, 2]}, + "down": {"uv": [59, 44], "uv_size": [2, -2]} + } + }, + { + "origin": [5, 16, 6.8], + "size": [1, 15, 1], + "pivot": [6, 16, 6], + "rotation": [6.74746, 0.9587, 5.25156], + "uv": { + "north": {"uv": [58, 42], "uv_size": [2, 2]}, + "east": {"uv": [58, 41], "uv_size": [2, 2]}, + "south": {"uv": [60, 42], "uv_size": [2, 2]}, + "west": {"uv": [60, 42], "uv_size": [2, 2]}, + "up": {"uv": [59, 42], "uv_size": [2, 2]}, + "down": {"uv": [59, 44], "uv_size": [2, -2]} + } + }, + { + "origin": [5, 0, 7], + "size": [2, 15, 2], + "pivot": [6, 0, 8], + "rotation": [6.48042, 2.11339, -4.6853], + "uv": { + "north": {"uv": [58, 42], "uv_size": [2, 2]}, + "east": {"uv": [58, 41], "uv_size": [2, 2]}, + "south": {"uv": [60, 42], "uv_size": [2, 2]}, + "west": {"uv": [60, 42], "uv_size": [2, 2]}, + "up": {"uv": [59, 42], "uv_size": [2, 2]}, + "down": {"uv": [59, 44], "uv_size": [2, -2]} + } + }, + { + "origin": [-9, 0, -9], + "size": [2, 15, 2], + "pivot": [-7, 0, -8], + "rotation": [-4.99527, 0.21782, 2.4905], + "uv": { + "north": {"uv": [58, 42], "uv_size": [2, 2]}, + "east": {"uv": [58, 41], "uv_size": [2, 2]}, + "south": {"uv": [60, 42], "uv_size": [2, 2]}, + "west": {"uv": [60, 42], "uv_size": [2, 2]}, + "up": {"uv": [59, 42], "uv_size": [2, 2]}, + "down": {"uv": [59, 44], "uv_size": [2, -2]} + } + }, + { + "origin": [-8.4, 14.8, -9.1], + "size": [10, 16, 2], + "pivot": [-6, 15, -8], + "rotation": [-87.93404, 12.77179, 1.03865], + "uv": { + "north": {"uv": [58, 42], "uv_size": [2, 2]}, + "east": {"uv": [58, 41], "uv_size": [2, 2]}, + "south": {"uv": [60, 42], "uv_size": [2, 2]}, + "west": {"uv": [60, 42], "uv_size": [2, 2]}, + "up": {"uv": [59, 42], "uv_size": [2, 2]}, + "down": {"uv": [59, 44], "uv_size": [2, -2]} + } + }, + { + "origin": [0.6, 14.5, -8], + "size": [9, 16, 2], + "pivot": [10, 15, -7], + "rotation": [-86.83195, -12.17879, -0.09276], + "uv": { + "north": {"uv": [58, 42], "uv_size": [2, 2]}, + "east": {"uv": [58, 41], "uv_size": [2, 2]}, + "south": {"uv": [60, 42], "uv_size": [2, 2]}, + "west": {"uv": [60, 42], "uv_size": [2, 2]}, + "up": {"uv": [59, 42], "uv_size": [2, 2]}, + "down": {"uv": [59, 44], "uv_size": [2, -2]} + } + }, + { + "origin": [-9, 0, -9], + "size": [2, 15, 2], + "pivot": [-7, 0, -8], + "rotation": [-4.99527, 0.21782, 2.4905], + "uv": { + "north": {"uv": [58, 42], "uv_size": [2, 2]}, + "east": {"uv": [58, 41], "uv_size": [2, 2]}, + "south": {"uv": [60, 42], "uv_size": [2, 2]}, + "west": {"uv": [60, 42], "uv_size": [2, 2]}, + "up": {"uv": [59, 42], "uv_size": [2, 2]}, + "down": {"uv": [59, 44], "uv_size": [2, -2]} + } + } + ] + }, + { + "name": "Head", + "pivot": [1, 32, -6], + "cubes": [ + { + "origin": [-4, 32, -10], + "size": [9, 9, 9], + "uv": { + "north": {"uv": [8, 8], "uv_size": [8, 8]}, + "east": {"uv": [0, 8], "uv_size": [8, 8]}, + "south": {"uv": [24, 8], "uv_size": [8, 8]}, + "west": {"uv": [16, 8], "uv_size": [8, 8]}, + "up": {"uv": [8, 0], "uv_size": [8, 8]}, + "down": {"uv": [16, 8], "uv_size": [8, -8]} + } + } + ] + }, + { + "name": "Head2", + "parent": "Head", + "pivot": [1, 32, -6], + "cubes": [ + { + "origin": [-5, 32, -11], + "size": [11, 10, 11], + "uv": { + "north": {"uv": [39, 8], "uv_size": [9, 8]}, + "east": {"uv": [32, 8], "uv_size": [8, 8]}, + "south": {"uv": [55, 8], "uv_size": [9, 8]}, + "west": {"uv": [48, 8], "uv_size": [8, 8]}, + "up": {"uv": [39, 0], "uv_size": [9, 8]}, + "down": {"uv": [48, 8], "uv_size": [9, -8]} + } + } + ] + }, + { + "name": "Body", + "pivot": [1, 32, -6], + "cubes": [ + { + "origin": [-4, 20, -8], + "size": [9, 13, 5], + "uv": { + "north": {"uv": [20, 20], "uv_size": [8, 12]}, + "east": {"uv": [16, 20], "uv_size": [4, 12]}, + "south": {"uv": [32, 20], "uv_size": [8, 12]}, + "west": {"uv": [28, 20], "uv_size": [4, 12]}, + "up": {"uv": [20, 16], "uv_size": [8, 4]}, + "down": {"uv": [28, 20], "uv_size": [8, -4]} + } + } + ] + }, + { + "name": "RightArm", + "pivot": [-4, 30, -6], + "cubes": [ + { + "origin": [-8, 20, -8], + "size": [5, 13, 5], + "uv": { + "north": {"uv": [44, 20], "uv_size": [4, 12]}, + "east": {"uv": [40, 20], "uv_size": [4, 12]}, + "south": {"uv": [52, 20], "uv_size": [4, 12]}, + "west": {"uv": [48, 20], "uv_size": [4, 12]}, + "up": {"uv": [44, 16], "uv_size": [4, 4]}, + "down": {"uv": [48, 20], "uv_size": [4, -4]} + } + }, + { + "origin": [-9, 20, -9], + "size": [7, 14, 7], + "uv": { + "north": {"uv": [42, 35], "uv_size": [6, 13]}, + "east": {"uv": [36, 35], "uv_size": [6, 13]}, + "south": {"uv": [46, 37], "uv_size": [6, 13]}, + "west": {"uv": [48, 35], "uv_size": [6, 13]}, + "up": {"uv": [42, 33], "uv_size": [6, 6]}, + "down": {"uv": [48, 39], "uv_size": [6, -6]} + } + } + ] + }, + { + "name": "LeftArm", + "pivot": [6, 30, -6], + "cubes": [ + { + "origin": [4, 20, -8], + "size": [5, 13, 5], + "uv": { + "north": {"uv": [36, 52], "uv_size": [4, 12]}, + "east": {"uv": [32, 52], "uv_size": [4, 12]}, + "south": {"uv": [44, 52], "uv_size": [4, 12]}, + "west": {"uv": [40, 52], "uv_size": [4, 12]}, + "up": {"uv": [36, 48], "uv_size": [4, 4]}, + "down": {"uv": [40, 52], "uv_size": [4, -4]} + } + }, + { + "origin": [3, 20, -9], + "size": [7, 14, 7], + "uv": { + "north": {"uv": [58, 30], "uv_size": [6, 13]}, + "east": {"uv": [50, 51], "uv_size": [6, 13]}, + "south": {"uv": [58, 51], "uv_size": [6, 13]}, + "west": {"uv": [52, 51], "uv_size": [6, 13]}, + "up": {"uv": [48, 45], "uv_size": [6, 6]}, + "down": {"uv": [52, 51], "uv_size": [6, -6]} + } + } + ] + }, + { + "name": "RightLeg", + "pivot": [-0.9, 20, -6], + "rotation": [-50, 0, 0], + "cubes": [ + { + "origin": [-3.9, 8, -8], + "size": [5, 13, 5], + "uv": { + "north": {"uv": [4, 20], "uv_size": [4, 12]}, + "east": {"uv": [0, 20], "uv_size": [4, 12]}, + "south": {"uv": [12, 20], "uv_size": [4, 12]}, + "west": {"uv": [8, 20], "uv_size": [4, 12]}, + "up": {"uv": [4, 16], "uv_size": [4, 4]}, + "down": {"uv": [8, 20], "uv_size": [4, -4]} + } + }, + { + "origin": [-4.9, 8, -9], + "size": [7, 14, 7], + "uv": { + "north": {"uv": [4, 36], "uv_size": [4, 12]}, + "east": {"uv": [0, 36], "uv_size": [4, 12]}, + "south": {"uv": [12, 36], "uv_size": [4, 12]}, + "west": {"uv": [8, 36], "uv_size": [4, 12]}, + "up": {"uv": [4, 32], "uv_size": [4, 4]}, + "down": {"uv": [8, 36], "uv_size": [4, -4]} + } + } + ] + }, + { + "name": "LeftLeg", + "pivot": [2.9, 20, -6], + "cubes": [ + { + "origin": [-0.1, 12, -17], + "size": [5, 13, 5], + "pivot": [1, 12, -15], + "rotation": [-47.5, 0, 0], + "uv": { + "north": {"uv": [20, 52], "uv_size": [4, 12]}, + "east": {"uv": [16, 52], "uv_size": [4, 12]}, + "south": {"uv": [28, 52], "uv_size": [4, 12]}, + "west": {"uv": [24, 52], "uv_size": [4, 12]}, + "up": {"uv": [20, 48], "uv_size": [4, 4]}, + "down": {"uv": [24, 52], "uv_size": [4, -4]} + } + }, + { + "origin": [-0.9, 13, -18], + "size": [7, 14, 7], + "pivot": [6, 13, -16], + "rotation": [-50, 0, 0], + "uv": { + "north": {"uv": [4, 52], "uv_size": [4, 12]}, + "east": {"uv": [0, 52], "uv_size": [4, 12]}, + "south": {"uv": [11.75, 52], "uv_size": [4, 12]}, + "west": {"uv": [8, 52], "uv_size": [4, 12]}, + "up": {"uv": [3.75, 48], "uv_size": [4, 4]}, + "down": {"uv": [7.75, 52], "uv_size": [4, -4]} + } + } + ] + } + ] + } + ] +} diff --git a/src/main/resources/assets/explosionoverhaul/intro_gui/cave_slide.png b/src/main/resources/assets/explosionoverhaul/intro_gui/cave_slide.png new file mode 100644 index 0000000..3f98d60 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/intro_gui/cave_slide.png differ diff --git a/src/main/resources/assets/explosionoverhaul/intro_gui/claster_slide.png b/src/main/resources/assets/explosionoverhaul/intro_gui/claster_slide.png new file mode 100644 index 0000000..2be1afd Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/intro_gui/claster_slide.png differ diff --git a/src/main/resources/assets/explosionoverhaul/intro_gui/glass_slide.png b/src/main/resources/assets/explosionoverhaul/intro_gui/glass_slide.png new file mode 100644 index 0000000..9a6234f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/intro_gui/glass_slide.png differ diff --git a/src/main/resources/assets/explosionoverhaul/intro_gui/gui_screen_1.png b/src/main/resources/assets/explosionoverhaul/intro_gui/gui_screen_1.png new file mode 100644 index 0000000..d575741 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/intro_gui/gui_screen_1.png differ diff --git a/src/main/resources/assets/explosionoverhaul/intro_gui/gui_screen_2.png b/src/main/resources/assets/explosionoverhaul/intro_gui/gui_screen_2.png new file mode 100644 index 0000000..a0419bf Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/intro_gui/gui_screen_2.png differ diff --git a/src/main/resources/assets/explosionoverhaul/intro_gui/gui_screen_3.png b/src/main/resources/assets/explosionoverhaul/intro_gui/gui_screen_3.png new file mode 100644 index 0000000..2e186f5 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/intro_gui/gui_screen_3.png differ diff --git a/src/main/resources/assets/explosionoverhaul/intro_gui/gui_screen_4.png b/src/main/resources/assets/explosionoverhaul/intro_gui/gui_screen_4.png new file mode 100644 index 0000000..7251683 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/intro_gui/gui_screen_4.png differ diff --git a/src/main/resources/assets/explosionoverhaul/intro_gui/lamp_slide.png b/src/main/resources/assets/explosionoverhaul/intro_gui/lamp_slide.png new file mode 100644 index 0000000..61ecea0 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/intro_gui/lamp_slide.png differ diff --git a/src/main/resources/assets/explosionoverhaul/intro_gui/screen.png b/src/main/resources/assets/explosionoverhaul/intro_gui/screen.png new file mode 100644 index 0000000..533a627 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/intro_gui/screen.png differ diff --git a/src/main/resources/assets/explosionoverhaul/intro_gui/speed_of_sound_slide.png b/src/main/resources/assets/explosionoverhaul/intro_gui/speed_of_sound_slide.png new file mode 100644 index 0000000..9758eae Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/intro_gui/speed_of_sound_slide.png differ diff --git a/src/main/resources/assets/explosionoverhaul/intro_gui/vinlanx_screen.png b/src/main/resources/assets/explosionoverhaul/intro_gui/vinlanx_screen.png new file mode 100644 index 0000000..3485f2b Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/intro_gui/vinlanx_screen.png differ diff --git a/src/main/resources/assets/explosionoverhaul/lang/en_us.json b/src/main/resources/assets/explosionoverhaul/lang/en_us.json new file mode 100644 index 0000000..1e0b20b --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/lang/en_us.json @@ -0,0 +1,247 @@ +{ + "key.categories.explosionoverhaul": "Explosion Overhaul", + "key.explosionoverhaul.accept_scan": "Accept Scan", + "key.explosionoverhaul.decline_scan": "Decline Scan", + "key.explosionoverhaul.info_scan": "Scan Info", + "option.explosionoverhaul.enableAdvancedSoundSpeed": "Enable Slow Sound Speed at Close Range", + "tooltip.explosionoverhaul.enableAdvancedSoundSpeed": "If enabled, explosion sounds up to 240 meters will travel at slower speeds for a more epic effect. Beyond 240 meters, sound travels at 343 m/s. If disabled, sound always travels at 343 m/s.", + "title.explosionoverhaul.blacklist": "Explosion Blacklists", + "option.explosionoverhaul.show_defaults": "Show default entries", + "tooltip.explosionoverhaul.show_defaults": "Toggle to view the built-in protected blocks.", + "option.explosionoverhaul.reset_list": "Reset", + "tooltip.explosionoverhaul.reset_list": "Hold SHIFT and click to reset this list to its original defaults", + "option.explosionoverhaul.blacklist_search": "Search blacklist...", + "option.explosionoverhaul.blacklist_input": "modid:block_name", + "option.explosionoverhaul.blacklist_add": "Add", + "option.explosionoverhaul.blacklist_category_explosion": "Destruction by explosion", + "tooltip.explosionoverhaul.blacklist_category_explosion": "Blocks that must not be destroyed by explosions (e.g., bedrock).", + "option.explosionoverhaul.blacklist_category_glass": "Glass breaking", + "tooltip.explosionoverhaul.blacklist_category_glass": "Blocks that prevent the glass breaking effect from destroying them.", + "option.explosionoverhaul.blacklist_category_sources": "Explosion Sources", + "tooltip.explosionoverhaul.blacklist_category_sources": "Control how the mod handles explosions from specific entities (e.g. TacZ grenades).", + "option.explosionoverhaul.blacklist_input_entities": "modid:entity_name or 'generic'", + "message.explosionoverhaul.invalid_id": "Invalid id format.", + "message.explosionoverhaul.invalid_block": "Block not found in registry.", + "message.explosionoverhaul.invalid_entity": "Entity not found in registry (use 'generic' for non-entity explosions).", + "message.explosionoverhaul.duplicate_entry": "This entry is already on the list.", + "message.explosionoverhaul.list_reset": "List has been reset to defaults.", + "option.explosionoverhaul.blacklist_info": "Info", + "tooltip.explosionoverhaul.blacklist_info": "Compatibility Tips:\n- For TACZ Grenades/Rockets: Use 'tacz:bullet' to control them explosions.", + "category.explosionoverhaul.sounds": "Sounds Settings", + "option.explosionoverhaul.cameraServerHeader": "--- Server ---", + "option.explosionoverhaul.enablePlayerShake": "Enable Player Shake", + "tooltip.explosionoverhaul.enablePlayerShake": "Enables or disables the player shake effect from explosions.", + "title.explosionoverhaul.config": "Explosion Overhaul Settings", + "category.explosionoverhaul.server": "Server Settings", + "category.explosionoverhaul.render": "Render Settings", + "category.explosionoverhaul.blacklists": "Black Lists", + "option.explosionoverhaul.blacklist_button": "Blacklists Page", + "tooltip.explosionoverhaul.blacklist_button": "This button will redirect you to the page containing all blacklists.", + "category.explosionoverhaul.camera": "Camera Settings", + "category.explosionoverhaul.ambient": "Ambient Settings", + "category.explosionoverhaul.scan": "Scan Settings", + "category.explosionoverhaul.concussion": "Concussion Settings", + + "option.explosionoverhaul.enableConcussion": "Enable Concussion Effects", + "tooltip.explosionoverhaul.enableConcussion": "Master switch for the entire concussion system (blur, deafness, heartbeat, etc.)", + "option.explosionoverhaul.concussionDurationMultiplier": "Duration Multiplier", + "tooltip.explosionoverhaul.concussionDurationMultiplier": "How long the concussion effects last after the explosion.", + "option.explosionoverhaul.concussionChanceMultiplier": "General Chance Multiplier", + "tooltip.explosionoverhaul.concussionChanceMultiplier": "Global multiplier for the chance of any concussion effect occurring.", + "option.explosionoverhaul.sourcemode_default": "DEFAULT", + "tooltip.explosionoverhaul.sourcemode_default": "The mod handles this explosion with all overhaul effects enabled.", + "option.explosionoverhaul.sourcemode_vanilla": "VANILLA", + "tooltip.explosionoverhaul.sourcemode_vanilla": "Bypasses all mod effects. This explosion will behave exactly as in vanilla Minecraft.", + "option.explosionoverhaul.sourcemode_no_destruction": "NO DESTRUCTION", + "tooltip.explosionoverhaul.sourcemode_no_destruction": "Modifies the explosion to cause zero block damage, while keeping all visual and sound effects.", + "option.explosionoverhaul.sourcemode_no_destruction_glassworks": "NO DESTRUCT. (G)", + "tooltip.explosionoverhaul.sourcemode_no_destruction_glassworks": "Same as NO DESTRUCTION, but also prevents the specialized 'Glass Breaking' effect.", + "option.explosionoverhaul.enableHeartbeatPulse": "Heartbeat Pulse & Sound", + "tooltip.explosionoverhaul.enableHeartbeatPulse": "Enables or disables visual screen pulsing and 'lub-dub' heartbeat sounds.", + "option.explosionoverhaul.enableCameraSway": "Camera Sway", + "tooltip.explosionoverhaul.enableCameraSway": "Enables the disorientation camera sway effect.", + "option.explosionoverhaul.cameraSwayIntensity": "Camera Sway Intensity", + "tooltip.explosionoverhaul.cameraSwayIntensity": "Radius multiplier for the camera sway effect.", + "option.explosionoverhaul.enableDeafness": "Deafness (Ringing)", + "tooltip.explosionoverhaul.enableDeafness": "Enables the high-pitched ringing effect after a close explosion.", + "option.explosionoverhaul.enableLowPass": "Low-Pass (Muffled Audio)", + "tooltip.explosionoverhaul.enableLowPass": "Enables the muffled sound effect that dampens environmental audio.", + "option.explosionoverhaul.deafnessChanceMultiplier": "Deafness Chance", + "tooltip.explosionoverhaul.deafnessChanceMultiplier": "Probability multiplier for the deafness effect.", + "option.explosionoverhaul.lowPassChanceMultiplier": "Low-Pass Chance", + "tooltip.explosionoverhaul.lowPassChanceMultiplier": "Probability multiplier for the low-pass effect.", + "option.explosionoverhaul.showHeartbeatHUD": "Show Heartbeat HUD", + "tooltip.explosionoverhaul.showHeartbeatHUD": "Shows a BPM/BPS counter in the top-right corner of the screen.", + + "option.explosionoverhaul.enableFallingBlocks": "Enable Falling Blocks", + "tooltip.explosionoverhaul.enableFallingBlocks": "If enabled, blocks will be launched from explosions. This is a server-side setting.", + "option.explosionoverhaul.enableExplosionClustering": "Enable Explosion Clustering", + "tooltip.explosionoverhaul.enableExplosionClustering": "Enables or disables the clustering of nearby explosives into a single, more powerful explosion.", + "option.explosionoverhaul.maxClusterPower": "Max Cluster Power", + "tooltip.explosionoverhaul.maxClusterPower": "Maximum total power for clustered TNT explosions.\n4 = minimum (single TNT)\n100 = default (safe)\n150+ = rendering lag risk\n300+ = severe rendering issues\n500+ = game crash risk", + "warning.explosionoverhaul.renderingLag": "WARNING: LARGE EXPLOSIONS MAY CAUSE RENDERING LAG", + "warning.explosionoverhaul.severeRenderingLag": "WARNING: LARGE EXPLOSIONS MAY CAUSE SEVERE RENDERING LAG", + "warning.explosionoverhaul.crashRisk": "WARNING: GAME CRASH RISK WITH LARGE EXPLOSIONS", + "option.explosionoverhaul.enableCraterDestruction": "Enable Crater Destruction", + "tooltip.explosionoverhaul.enableCraterDestruction": "If false, explosions will still cause visual and sound effects, but won't break blocks.", + "option.explosionoverhaul.enableGlassBreaking": "Enable Glass Breaking", + "tooltip.explosionoverhaul.enableGlassBreaking": "Enables or disables glass being shattered by the explosion's shockwave.", + "option.explosionoverhaul.enableLampFlicker": "Enable Lamp Flicker", + "tooltip.explosionoverhaul.enableLampFlicker": "Enables the flickering effect on Redstone Lamps near explosions.", + + "option.explosionoverhaul.craterSettingsHeader": "--- Crater Customization ---", + "option.explosionoverhaul.craterSizeMultiplier": "Crater Size Multiplier", + "tooltip.explosionoverhaul.craterSizeMultiplier.title": "Adjusts the diameter and depth of craters.", + "tooltip.explosionoverhaul.craterSizeMultiplier.footer": "This value multiplies the calculated base size.", + "tooltip.explosionoverhaul.craterShapeInfo": "The 'Crater Core Ratio' setting only applies to explosions with a power of 40 or higher.", + "option.explosionoverhaul.craterCoreRatio": "Crater Solidity (for Power 40+)", + "tooltip.explosionoverhaul.craterCoreRatio": "For powerful explosions, this defines the crater's shape.\n10% = very 'ray-like' (like a sun)\n95% = almost a perfect sphere (solid bowl)", + + "option.explosionoverhaul.enableAsyncCrater": "Enable Async Crater Pipeline", + "tooltip.explosionoverhaul.enableAsyncCrater": "Compute crater geometry off-thread and apply block changes in small batches per tick to keep TPS smooth on large explosions.\n\nWARNING: When asynchronous and multi-threaded mode is enabled - destruction of VS objects - does not work.", + "option.explosionoverhaul.craterMaxThreads": "Async Crater Max Threads", + "tooltip.explosionoverhaul.craterMaxThreads": "Maximum worker threads used for off-thread crater precomputation.\n0 = Auto (use all available threads)", + "option.explosionoverhaul.craterApplyBlocksPerTick": "Crater Apply Budget (blocks/tick)", + "tooltip.explosionoverhaul.craterApplyBlocksPerTick": "How many blocks to process per server tick while applying crater changes.\nHigher = faster crater application but potentially more TPS spikes.", + "option.explosionoverhaul.craterMaxFallingBlocksPerTick": "Max Falling Blocks (entities/tick)", + "tooltip.explosionoverhaul.craterMaxFallingBlocksPerTick": "Caps the number of falling block entities spawned per tick during crater application.\nSet to 0 to disable spawning in async mode.", + "option.explosionoverhaul.enableDirectChunkWrites": "Direct Chunk Writes", + "tooltip.explosionoverhaul.enableDirectChunkWrites": "Directly write block states into chunk sections instead of using Level#setBlock.\nMuch faster, but skips Forge block events and neighbor updates.", + "option.explosionoverhaul.craterChunksPerTick": "Crater Chunk Budget (chunks/tick)", + "tooltip.explosionoverhaul.craterChunksPerTick": "Maximum number of chunks to process per tick when direct writes are enabled.\nUse together with blocks/tick to smooth TPS.", + + "option.explosionoverhaul.glassBreakingSettings": "--- Glass Breaking ---", + "option.explosionoverhaul.glassBreakingIntervalTicks": "Processing Interval (Ticks)", + "tooltip.explosionoverhaul.glassBreakingIntervalTicks": "How often the server processes breaking glass (1 tick = 0.05s). Lower is smoother but more resource-intensive.", + "option.explosionoverhaul.glassBlocksPerCycle": "Blocks Broken Per Cycle", + "tooltip.explosionoverhaul.glassBlocksPerCycle": "Max glass blocks to break in one go. Prevents lag from huge explosions.", + + + "option.explosionoverhaul.lampFlickerSettings": "--- Lamp Flickering ---", + "option.explosionoverhaul.lampFlickerSearchRadius": "Lamp Search Radius", + "tooltip.explosionoverhaul.lampFlickerSearchRadius": "The radius around the player to search for lamps. High values can cause lag.", + + "option.explosionoverhaul.enableExplosionParticles": "Enable Core Explosion Particles", + "tooltip.explosionoverhaul.enableExplosionParticles": "Enables the main fiery glow particles (glow, glow_2, sglow). Disabling can improve performance.", + "option.explosionoverhaul.enablePlasmaParticles": "Enable Plasma Sparks", + "tooltip.explosionoverhaul.enablePlasmaParticles": "Enables or disables plasma sparks entirely.", + "option.explosionoverhaul.enablePlasmaSmokeTrail": "Enable Plasma Smoke Trail", + "tooltip.explosionoverhaul.enablePlasmaSmokeTrail": "Enables the smoke trail that follows plasma sparks.", + "option.explosionoverhaul.plasmaSmokeFrequency": "Plasma Smoke Frequency", + "tooltip.explosionoverhaul.plasmaSmokeFrequency": "How often smoke spawns from plasma particles. 0% = no smoke, 25% = reduced, 70% = original.", + "option.explosionoverhaul.plasmaSmokeCount": "Plasma Smoke Count", + "tooltip.explosionoverhaul.plasmaSmokeCount": "Number of smoke particles spawned per plasma tick. Original was 2.", + "option.explosionoverhaul.enableFlashEffect": "Enable Flash Effect", + "tooltip.explosionoverhaul.enableFlashEffect": "Enables the flash overlay effect on explosions.", + "option.explosionoverhaul.flashMaxOpacity": "Flash Max Opacity", + "tooltip.explosionoverhaul.flashMaxOpacity": "Maximum opacity of the flash effect overlay. 0% = no flash, 100% = full opacity.", + "option.explosionoverhaul.enableGroundDustEffect": "Enable Ground Dust", + "tooltip.explosionoverhaul.enableGroundDustEffect": "Enables the dust cloud effect from explosions.", + "option.explosionoverhaul.groundDustQuality": "Ground Dust Quality", + "tooltip.explosionoverhaul.groundDustQuality": "Affects particle count and duration. Lower values improve performance.", + "option.explosionoverhaul.groundDustRaycastFrequency": "Ground Dust Propagation", + "tooltip.explosionoverhaul.groundDustRaycastFrequency": "Controls how often dust particles check for the ground. Higher values can reduce performance.", + + "option.explosionoverhaul.enableGroundMistEffect": "Enable Ground Mist", + "tooltip.explosionoverhaul.enableGroundMistEffect": "Enables the white mist cloud effect from explosions.", + "option.explosionoverhaul.groundMistQuality": "Ground Mist Quality", + "tooltip.explosionoverhaul.groundMistQuality": "Affects mist particle count and duration. Lower values improve performance.", + "option.explosionoverhaul.groundMistRaycastFrequency": "Ground Mist Propagation", + "tooltip.explosionoverhaul.groundMistRaycastFrequency": "Controls how often mist particles check for the ground. Higher values can reduce performance.", + + "option.explosionoverhaul.enableMistEffect": "Enable Mist Effect", + "tooltip.explosionoverhaul.enableMistEffect": "Enables the white mist effect that spreads from explosions.", + "option.explosionoverhaul.mistQuality": "Mist Quality", + "tooltip.explosionoverhaul.mistQuality": "Affects mist particle count and duration.", + "option.explosionoverhaul.mistRaycastFrequency": "Mist Propagation", + "tooltip.explosionoverhaul.mistRaycastFrequency": "Controls how often mist particles check for the ground.", + + "option.explosionoverhaul.enableCameraShake": "Enable Camera Shake", + "tooltip.explosionoverhaul.enableCameraShake": "Enables or disables the camera shake effect from explosions.", + "option.explosionoverhaul.cameraShakeAmplifier": "Camera Shake Amplifier", + "tooltip.explosionoverhaul.cameraShakeAmplifier": "Multiplies the intensity of the camera shake. 0.0x = no shake, 1.0x = default.", + "option.explosionoverhaul.playerShakeAmplifier": "Player Shake Amplifier", + "tooltip.explosionoverhaul.playerShakeAmplifier": "Multiplies the intensity of the player shake (side-to-side movement). 0.0x = no shake, 1.0x = default.", + + "option.explosionoverhaul.enableAmbientExplosions": "Enable Ambient Explosions", + "tooltip.explosionoverhaul.enableAmbientExplosions": "Enables a system that simulates distant random explosions to create a battlefield atmosphere.", + "option.explosionoverhaul.minTimeBetweenExplosions": "Min Time Between Events (s)", + "tooltip.explosionoverhaul.minTimeBetweenExplosions": "Minimum time in seconds between ambient explosion events.", + "option.explosionoverhaul.maxTimeBetweenExplosions": "Max Time Between Events (s)", + "tooltip.explosionoverhaul.maxTimeBetweenExplosions": "Maximum time in seconds between ambient explosion events.", + "option.explosionoverhaul.minExplosionDistance": "Min Event Distance", + "tooltip.explosionoverhaul.minExplosionDistance": "Minimum distance in blocks from the player where an ambient sound can originate.", + "option.explosionoverhaul.maxExplosionDistance": "Max Event Distance", + "tooltip.explosionoverhaul.maxExplosionDistance": "Maximum distance in blocks from the player where an ambient sound can originate.", + "option.explosionoverhaul.maxAmbientExplosionPower": "Max Ambient Power", + "tooltip.explosionoverhaul.maxAmbientExplosionPower": "The maximum power a random 'Cataclysm' tier explosion can have.", + + "option.explosionoverhaul.scenariosHeader": "--- Ambient Scenarios ---", + "tooltip.explosionoverhaul.scenariosHeader": "Configure the types and frequency of different ambient explosion events.", + "option.explosionoverhaul.singleExplosionWeight": "Single Explosion Weight", + "option.explosionoverhaul.chainReactionWeight": "Chain Reaction Weight", + "option.explosionoverhaul.shellingWeight": "Artillery Shelling Weight", + + "option.explosionoverhaul.chainReactionSettingsHeader": "--- Chain Reaction Settings ---", + "option.explosionoverhaul.minChainReactionShots": "Min Shots in Chain", + "option.explosionoverhaul.maxChainReactionShots": "Max Shots in Chain", + "option.explosionoverhaul.minTimeBetweenChainShots": "Min Time Between Shots", + "option.explosionoverhaul.maxTimeBetweenChainShots": "Max Time Between Shots", + + "option.explosionoverhaul.shellingSettingsHeader": "--- Artillery Shelling Settings ---", + "option.explosionoverhaul.minShellingDelay": "Min Impact Delay", + "option.explosionoverhaul.maxShellingDelay": "Max Impact Delay", + + "option.explosionoverhaul.powerTiersHeader": "--- Power Tier Weights ---", + "tooltip.explosionoverhaul.powerTiersHeader": "Weights for different explosion power levels in 'Single' and 'Shelling' events.", + "option.explosionoverhaul.tier1_weight": "Tier 1 (1-4 Power) Weight", + "option.explosionoverhaul.tier2_weight": "Tier 2 (5-15 Power) Weight", + "option.explosionoverhaul.tier3_weight": "Tier 3 (16-40 Power) Weight", + "option.explosionoverhaul.tier4_weight": "Tier 4 (41-80 Power) Weight", + "option.explosionoverhaul.tier5_weight": "Tier 5 (81+ Power) Weight", + + "option.explosionoverhaul.soundTypesHeader": "--- Sound Environment Toggles ---", + "option.explosionoverhaul.enableSurfaceSounds": "Enable Surface Sounds", + "tooltip.explosionoverhaul.enableSurfaceSounds": "Surface: A clear explosion sound in an open area.", + "option.explosionoverhaul.enableCaveSounds": "Enable Cave Sounds", + "tooltip.explosionoverhaul.enableCaveSounds": "Cave: A loud, reverberating sound when both player and explosion are in a cave.", + "option.explosionoverhaul.enableAmbientCaveDust": "Enable Ambient Cave Dust", + "option.explosionoverhaul.glowTextureQuality": "Glow Texture Quality", + "tooltip.explosionoverhaul.glowTextureQuality": "Sets the resolution for the main fireball textures.\nLower quality can improve performance. Requires resource reload (F3+T).", + "option.explosionoverhaul.particleSizeScale": "Particle Size Scale", + "tooltip.explosionoverhaul.particleSizeScale": "Scales the size of all explosion particles across all render modes.\n100 = default size (1.0x), 10 = 10% of default (0.1x), 500 = 500% of default (5.0x).", + "option.explosionoverhaul.particleRenderMode": "Particle Rendering System", + "tooltip.explosionoverhaul.particleRenderMode": "Choose between three particle rendering systems:\nRealistic: Current system with complex animated sprite sheets (better quality)\nRealistic 2: Optimized system with single large particle (best performance)\nVanilla-like: Uses simple textures with color phases (good performance)", + "tooltip.explosionoverhaul.enableAmbientCaveDust": "If an ambient cave explosion occurs, a visual dust effect will fall from the ceiling.", + "option.explosionoverhaul.enableLineSparks": "Enable Sparks", + "tooltip.explosionoverhaul.enableLineSparks": "Enables or disables sparks that shoot out from the explosion's epicenter.", + "option.explosionoverhaul.lineSparkAmountMultiplier": "Spark Amount", + "tooltip.explosionoverhaul.lineSparkAmountMultiplier": "Multiplier for the number of sparks from explosions. Higher values may impact performance.", + "option.explosionoverhaul.dripstoneFallingSettings": "--- Dripstone Falling ---", + "option.explosionoverhaul.enableDripstoneFalling": "Enable Dripstone Falling", + "tooltip.explosionoverhaul.enableDripstoneFalling": "Enables or disables the falling effect for pointed dripstone.", + "option.explosionoverhaul.dripstoneFallingSearchRadius": "Dripstone Search Radius", + "tooltip.explosionoverhaul.dripstoneFallingSearchRadius": "The radius around the player to search for pointed dripstone. High values can cause lag.", + + "option.explosionoverhaul.scanSettingsHeader": "--- Chunk Scanning ---", + "option.explosionoverhaul.maxScanThreads": "Max Scan Threads", + "tooltip.explosionoverhaul.maxScanThreads": "Maximum number of threads to use for chunk scanning.\nRange is automatically adjusted for your system.\n0 = Auto-detect (recommended): uses all available threads\n1 = Single-threaded (safest for low-end systems)\nHigher values = faster scanning but more CPU usage.", + "option.explosionoverhaul.cpuUsagePercent": "CPU Usage Percentage", + "tooltip.explosionoverhaul.cpuUsagePercent": "How much CPU power to dedicate to chunk scanning (1-100%).\n100% = Maximum speed, uses all available processing power intensively\n75% = Balanced (recommended), fast scanning with some CPU headroom\n50% = Conservative, leaves room for other server processes\n25% = Minimal impact, slowest but safest for busy servers\nLower values add delays between processing to reduce CPU load.", + "option.explosionoverhaul.enableBlockIndexing": "Block Indexing", + "tooltip.explosionoverhaul.enableBlockIndexing": "Enables or disables the block indexing system.\nWhen enabled, chunks are automatically scanned for Redstone Lamps, Pointed Dripstone, and Glass blocks.\nWhen disabled, only manual registration/unregistration of blocks will occur.\nThis affects the performance of Redstone Lamp flickering, Pointed Dripstone falling effects, and Glass breaking effects near explosions.\nUseful for servers that want to minimize background processing.", + "option.explosionoverhaul.showScanProgressHUD": "Show Scan Progress HUD", + "tooltip.explosionoverhaul.showScanProgressHUD": "Controls visibility of the scanning progress HUD in the top-left corner.\nShows percentage of chunks scanned during world initialization.\nAutomatically hides when scanning is complete.", + + "option.explosionoverhaul.enableShockwaveEffect": "Enable Shockwave Effect", + "tooltip.explosionoverhaul.enableShockwaveEffect": "Enables or disables the shockwave particle effect from explosions.", + + "option.explosionoverhaul.enableWindEffect": "Enable Wind Effect", + "tooltip.explosionoverhaul.enableWindEffect": "Enables wind effects on explosion particles (dust, mist, glow). Particles will move with wind direction and speed.", + "option.explosionoverhaul.windSpeedMultiplier": "Wind Speed Multiplier", + "tooltip.explosionoverhaul.windSpeedMultiplier": "Controls the global wind speed affecting all particles. 1.0 = normal speed, 1.5 = 50% faster, 2.0 = double speed.", + "block.explosionoverhaul.vinlanx_the_light": "Vinlanx The Light", + "item.explosionoverhaul.vinlanx_the_light": "Vinlanx The Light", + "item.explosionoverhaul.mod_logo": "Explosion Overhaul Icon", + "itemGroup.explosionoverhaul.main": "Explosion Overhaul: A new level of destruction" +} diff --git a/src/main/resources/assets/explosionoverhaul/lang/fr_fr.json b/src/main/resources/assets/explosionoverhaul/lang/fr_fr.json new file mode 100644 index 0000000..50bb4c6 --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/lang/fr_fr.json @@ -0,0 +1,247 @@ +{ + "key.categories.explosionoverhaul": "Refonte des Explosions", + "key.explosionoverhaul.accept_scan": "Accepter le Scan", + "key.explosionoverhaul.decline_scan": "Refuser le Scan", + "key.explosionoverhaul.info_scan": "Info de Scan", + "option.explosionoverhaul.enableAdvancedSoundSpeed": "Activer la vitesse du son lente à courte distance", + "tooltip.explosionoverhaul.enableAdvancedSoundSpeed": "Si activé, les sons d'explosion jusqu'à 240 mètres voyageront à des vitesses plus lentes pour un effet plus épique. Au-delà de 240 mètres, le son voyage à 343 m/s. Si désactivé, le son voyage toujours à 343 m/s.", + "title.explosionoverhaul.blacklist": "Listes noires d'explosions", + "option.explosionoverhaul.show_defaults": "Afficher les entrées par défaut", + "tooltip.explosionoverhaul.show_defaults": "Basculer pour voir les blocs protégés intégrés.", + "option.explosionoverhaul.reset_list": "Réinitialiser", + "tooltip.explosionoverhaul.reset_list": "Maintenez SHIFT et cliquez pour réinitialiser cette liste à ses valeurs par défaut originales", + "option.explosionoverhaul.blacklist_search": "Rechercher dans la liste noire...", + "option.explosionoverhaul.blacklist_input": "modid:nom_du_bloc", + "option.explosionoverhaul.blacklist_add": "Ajouter", + "option.explosionoverhaul.blacklist_category_explosion": "Destruction par explosion", + "tooltip.explosionoverhaul.blacklist_category_explosion": "Blocs qui ne doivent pas être détruits par les explosions (ex: bedrock).", + "option.explosionoverhaul.blacklist_category_glass": "Bris de glace", + "tooltip.explosionoverhaul.blacklist_category_glass": "Blocs empêchant l'effet de bris de glace de les détruire.", + "option.explosionoverhaul.blacklist_category_sources": "Sources d'explosion", + "tooltip.explosionoverhaul.blacklist_category_sources": "Contrôlez comment le mod gère les explosions d'entités spécifiques (ex: grenades TacZ).", + "option.explosionoverhaul.blacklist_input_entities": "modid:nom_de_l_entite ou 'generic'", + "message.explosionoverhaul.invalid_id": "Format d'ID invalide.", + "message.explosionoverhaul.invalid_block": "Bloc non trouvé dans le registre.", + "message.explosionoverhaul.invalid_entity": "Entité non trouvée dans le registre (utilisez 'generic' pour les explosions hors entité).", + "message.explosionoverhaul.duplicate_entry": "Cette entrée est déjà sur la liste.", + "message.explosionoverhaul.list_reset": "La liste a été réinitialisée par défaut.", + "option.explosionoverhaul.blacklist_info": "Info", + "tooltip.explosionoverhaul.blacklist_info": "Conseils de compatibilité :\n- Pour les grenades/roquettes TACZ : Utilisez 'tacz:bullet' pour contrôler leurs explosions.", + "category.explosionoverhaul.sounds": "Paramètres audio", + "option.explosionoverhaul.cameraServerHeader": "--- Serveur ---", + "option.explosionoverhaul.enablePlayerShake": "Activer le tremblement du joueur", + "tooltip.explosionoverhaul.enablePlayerShake": "Active ou désactive l'effet de tremblement du joueur lors des explosions.", + "title.explosionoverhaul.config": "Paramètres de Refonte des Explosions", + "category.explosionoverhaul.server": "Paramètres serveur", + "category.explosionoverhaul.render": "Paramètres de rendu", + "category.explosionoverhaul.blacklists": "Listes noires", + "option.explosionoverhaul.blacklist_button": "Page des listes noires", + "tooltip.explosionoverhaul.blacklist_button": "Ce bouton vous redirigera vers la page contenant toutes les listes noires.", + "category.explosionoverhaul.camera": "Paramètres de caméra", + "category.explosionoverhaul.ambient": "Paramètres d'ambiance", + "category.explosionoverhaul.scan": "Paramètres de scan", + "category.explosionoverhaul.concussion": "Paramètres de commotion", + + "option.explosionoverhaul.enableConcussion": "Activer les effets de commotion", + "tooltip.explosionoverhaul.enableConcussion": "Interrupteur principal pour tout le système de commotion (flou, surdité, battements de cœur, etc.)", + "option.explosionoverhaul.concussionDurationMultiplier": "Multiplicateur de durée", + "tooltip.explosionoverhaul.concussionDurationMultiplier": "Durée des effets de commotion après l'explosion.", + "option.explosionoverhaul.concussionChanceMultiplier": "Multiplicateur de chance générale", + "tooltip.explosionoverhaul.concussionChanceMultiplier": "Multiplicateur global pour la probabilité qu'un effet de commotion se produise.", + "option.explosionoverhaul.sourcemode_default": "PAR DÉFAUT", + "tooltip.explosionoverhaul.sourcemode_default": "Le mod gère cette explosion avec tous les effets de refonte activés.", + "option.explosionoverhaul.sourcemode_vanilla": "VANILLE", + "tooltip.explosionoverhaul.sourcemode_vanilla": "Ignore tous les effets du mod. Cette explosion se comportera exactement comme dans Minecraft vanille.", + "option.explosionoverhaul.sourcemode_no_destruction": "AUCUNE DESTRUCTION", + "tooltip.explosionoverhaul.sourcemode_no_destruction": "Modifie l'explosion pour ne causer aucun dégât aux blocs, tout en conservant tous les effets visuels et sonores.", + "option.explosionoverhaul.sourcemode_no_destruction_glassworks": "PAS DE DESTRUCT. (V)", + "tooltip.explosionoverhaul.sourcemode_no_destruction_glassworks": "Idem que AUCUNE DESTRUCTION, mais empêche également l'effet spécial de 'Bris de Glace'.", + "option.explosionoverhaul.enableHeartbeatPulse": "Pulsation & Son du cœur", + "tooltip.explosionoverhaul.enableHeartbeatPulse": "Active ou désactive les pulsations visuelles de l'écran et les sons de battement de cœur.", + "option.explosionoverhaul.enableCameraSway": "Balancement de caméra", + "tooltip.explosionoverhaul.enableCameraSway": "Active l'effet de balancement de caméra lié à la désorientation.", + "option.explosionoverhaul.cameraSwayIntensity": "Intensité du balancement", + "tooltip.explosionoverhaul.cameraSwayIntensity": "Multiplicateur de rayon pour l'effet de balancement de caméra.", + "option.explosionoverhaul.enableDeafness": "Surdité (Bourdonnement)", + "tooltip.explosionoverhaul.enableDeafness": "Active l'effet de bourdonnement aigu après une explosion proche.", + "option.explosionoverhaul.enableLowPass": "Passe-bas (Audio étouffé)", + "tooltip.explosionoverhaul.enableLowPass": "Active l'effet de son étouffé qui atténue les sons ambiants.", + "option.explosionoverhaul.deafnessChanceMultiplier": "Chance de surdité", + "tooltip.explosionoverhaul.deafnessChanceMultiplier": "Multiplicateur de probabilité pour l'effet de surdité.", + "option.explosionoverhaul.lowPassChanceMultiplier": "Chance de filtre passe-bas", + "tooltip.explosionoverhaul.lowPassChanceMultiplier": "Multiplicateur de probabilité pour l'effet passe-bas.", + "option.explosionoverhaul.showHeartbeatHUD": "Afficher l'HUD cardiaque", + "tooltip.explosionoverhaul.showHeartbeatHUD": "Affiche un compteur BPM/BPS dans le coin supérieur droit de l'écran.", + + "option.explosionoverhaul.enableFallingBlocks": "Activer les blocs filants", + "tooltip.explosionoverhaul.enableFallingBlocks": "Si activé, les blocs seront projetés par les explosions. Paramètre côté serveur.", + "option.explosionoverhaul.enableExplosionClustering": "Activer le regroupement d'explosions", + "tooltip.explosionoverhaul.enableExplosionClustering": "Active ou désactive le regroupement d'explosifs proches en une seule explosion plus puissante.", + "option.explosionoverhaul.maxClusterPower": "Puissance max du groupe", + "tooltip.explosionoverhaul.maxClusterPower": "Puissance totale maximale pour les explosions de TNT regroupées.\n4 = minimum (une TNT)\n100 = défaut (sûr)\n150+ = risque de lag de rendu\n300+ = problèmes de rendu sévères\n500+ = risque de crash du jeu", + "warning.explosionoverhaul.renderingLag": "ATTENTION : LES GRANDES EXPLOSIONS PEUVENT CAUSER DU LAG DE RENDU", + "warning.explosionoverhaul.severeRenderingLag": "ATTENTION : LES GRANDES EXPLOSIONS PEUVENT CAUSER UN LAG DE RENDU SÉVÈRE", + "warning.explosionoverhaul.crashRisk": "ATTENTION : RISQUE DE CRASH DU JEU AVEC LES GRANDES EXPLOSIONS", + "option.explosionoverhaul.enableCraterDestruction": "Activer la destruction de cratère", + "tooltip.explosionoverhaul.enableCraterDestruction": "Si faux, les explosions auront toujours des effets visuels et sonores, mais ne briseront pas de blocs.", + "option.explosionoverhaul.enableGlassBreaking": "Activer le bris de glace", + "tooltip.explosionoverhaul.enableGlassBreaking": "Active ou désactive le bris de verre par l'onde de choc de l'explosion.", + "option.explosionoverhaul.enableLampFlicker": "Activer le scintillement des lampes", + "tooltip.explosionoverhaul.enableLampFlicker": "Active l'effet de scintillement sur les lampes de redstone près des explosions.", + + "option.explosionoverhaul.craterSettingsHeader": "--- Personnalisation du cratère ---", + "option.explosionoverhaul.craterSizeMultiplier": "Multiplicateur de taille du cratère", + "tooltip.explosionoverhaul.craterSizeMultiplier.title": "Ajuste le diamètre et la profondeur des cratères.", + "tooltip.explosionoverhaul.craterSizeMultiplier.footer": "Cette valeur multiplie la taille de base calculée.", + "tooltip.explosionoverhaul.craterShapeInfo": "Le paramètre 'Solidité du Cratère' ne s'applique qu'aux explosions de puissance 40+.", + "option.explosionoverhaul.craterCoreRatio": "Solidité du Cratère (pour Puissance 40+)", + "tooltip.explosionoverhaul.craterCoreRatio": "Pour les explosions puissantes, définit la forme du cratère.\n10% = très 'rayonnant' (comme un soleil)\n95% = presque une sphère parfaite (bol solide)", + + "option.explosionoverhaul.enableAsyncCrater": "Activer le pipeline de cratère asynchrone", + "tooltip.explosionoverhaul.enableAsyncCrater": "Calcule la géométrie du cratère hors-thread et applique les changements de blocs par lots pour garder les TPS fluides.\n\nATTENTION : En mode asynchrone et multi-thread, la destruction d'objets VS ne fonctionne pas.", + "option.explosionoverhaul.craterMaxThreads": "Threads max pour cratère asynchrone", + "tooltip.explosionoverhaul.craterMaxThreads": "Threads maximum utilisés pour le calcul préalable du cratère.\n0 = Auto (tous les threads disponibles)", + "option.explosionoverhaul.craterApplyBlocksPerTick": "Budget d'application (blocs/tick)", + "tooltip.explosionoverhaul.craterApplyBlocksPerTick": "Nombre de blocs à traiter par tick lors de l'application du cratère.\nPlus c'est haut, plus c'est rapide mais risque de pics de TPS.", + "option.explosionoverhaul.craterMaxFallingBlocksPerTick": "Entités filantes max (entités/tick)", + "tooltip.explosionoverhaul.craterMaxFallingBlocksPerTick": "Limite le nombre d'entités de blocs filants générés par tick.\n0 pour désactiver en mode asynchrone.", + "option.explosionoverhaul.enableDirectChunkWrites": "Écritures directes dans les chunks", + "tooltip.explosionoverhaul.enableDirectChunkWrites": "Écrit directement dans les sections de chunks sans passer par Level#setBlock.\nPlus rapide, mais ignore les événements Forge et les mises à jour de voisins.", + "option.explosionoverhaul.craterChunksPerTick": "Budget de chunks (chunks/tick)", + "tooltip.explosionoverhaul.craterChunksPerTick": "Nombre maximum de chunks à traiter par tick avec écritures directes.\nÀ utiliser avec blocs/tick pour lisser les TPS.", + + "option.explosionoverhaul.glassBreakingSettings": "--- Bris de Glace ---", + "option.explosionoverhaul.glassBreakingIntervalTicks": "Intervalle de traitement (Ticks)", + "tooltip.explosionoverhaul.glassBreakingIntervalTicks": "Fréquence de traitement du bris de verre (1 tick = 0,05s). Plus bas est plus fluide mais plus lourd.", + "option.explosionoverhaul.glassBlocksPerCycle": "Blocs brisés par cycle", + "tooltip.explosionoverhaul.glassBlocksPerCycle": "Max de blocs de verre à briser d'un coup. Empêche le lag.", + + + "option.explosionoverhaul.lampFlickerSettings": "--- Scintillement des Lampes ---", + "option.explosionoverhaul.lampFlickerSearchRadius": "Rayon de recherche des lampes", + "tooltip.explosionoverhaul.lampFlickerSearchRadius": "Rayon autour du joueur pour chercher les lampes. Une valeur élevée peut lagger.", + + "option.explosionoverhaul.enableExplosionParticles": "Activer les particules centrales", + "tooltip.explosionoverhaul.enableExplosionParticles": "Active les particules de lueur enflammée (glow, glow_2, sglow). Désactiver peut améliorer les perfs.", + "option.explosionoverhaul.enablePlasmaParticles": "Activer les étincelles de plasma", + "tooltip.explosionoverhaul.enablePlasmaParticles": "Active ou désactive totalement les étincelles de plasma.", + "option.explosionoverhaul.enablePlasmaSmokeTrail": "Activer la traînée de fumée plasma", + "tooltip.explosionoverhaul.enablePlasmaSmokeTrail": "Active la traînée de fumée qui suit les étincelles.", + "option.explosionoverhaul.plasmaSmokeFrequency": "Fréquence de fumée plasma", + "tooltip.explosionoverhaul.plasmaSmokeFrequency": "Fréquence d'apparition de la fumée. 0% = aucune, 25% = réduite, 70% = originale.", + "option.explosionoverhaul.plasmaSmokeCount": "Quantité de fumée plasma", + "tooltip.explosionoverhaul.plasmaSmokeCount": "Nombre de particules de fumée par tick plasma. 2 par défaut.", + "option.explosionoverhaul.enableFlashEffect": "Activer l'effet de flash", + "tooltip.explosionoverhaul.enableFlashEffect": "Active l'overlay de flash lors des explosions.", + "option.explosionoverhaul.flashMaxOpacity": "Opacité max du flash", + "tooltip.explosionoverhaul.flashMaxOpacity": "Opacité maximale du flash. 0% = aucun, 100% = plein.", + "option.explosionoverhaul.enableGroundDustEffect": "Activer la poussière au sol", + "tooltip.explosionoverhaul.enableGroundDustEffect": "Active l'effet de nuage de poussière.", + "option.explosionoverhaul.groundDustQuality": "Qualité de la poussière", + "tooltip.explosionoverhaul.groundDustQuality": "Affecte le nombre et la durée. Plus bas améliore les perfs.", + "option.explosionoverhaul.groundDustRaycastFrequency": "Propagation de la poussière", + "tooltip.explosionoverhaul.groundDustRaycastFrequency": "Fréquence de vérification du sol via raycast. Élevé = impact perfs.", + + "option.explosionoverhaul.enableGroundMistEffect": "Activer la brume au sol", + "tooltip.explosionoverhaul.enableGroundMistEffect": "Active l'effet de nuage de brume blanche.", + "option.explosionoverhaul.groundMistQuality": "Qualité de la brume au sol", + "tooltip.explosionoverhaul.groundMistQuality": "Affecte le nombre et la durée des particules de brume.", + "option.explosionoverhaul.groundMistRaycastFrequency": "Propagation de la brume au sol", + "tooltip.explosionoverhaul.groundMistRaycastFrequency": "Fréquence de vérification du sol pour la brume.", + + "option.explosionoverhaul.enableMistEffect": "Activer l'effet de brume", + "tooltip.explosionoverhaul.enableMistEffect": "Active la brume blanche qui se répand.", + "option.explosionoverhaul.mistQuality": "Qualité de la brume", + "tooltip.explosionoverhaul.mistQuality": "Affecte le nombre et la durée des particules.", + "option.explosionoverhaul.mistRaycastFrequency": "Propagation de la brume", + "tooltip.explosionoverhaul.mistRaycastFrequency": "Fréquence de vérification du sol.", + + "option.explosionoverhaul.enableCameraShake": "Activer le tremblement caméra", + "tooltip.explosionoverhaul.enableCameraShake": "Active ou désactive le tremblement de caméra.", + "option.explosionoverhaul.cameraShakeAmplifier": "Amplificateur de tremblement caméra", + "tooltip.explosionoverhaul.cameraShakeAmplifier": "Multiplie l'intensité. 0.0x = aucun, 1.0x = défaut.", + "option.explosionoverhaul.playerShakeAmplifier": "Amplificateur de tremblement joueur", + "tooltip.explosionoverhaul.playerShakeAmplifier": "Multiplie l'intensité du tremblement joueur (mouvement latéral). 0.0x = aucun, 1.0x = défaut.", + + "option.explosionoverhaul.enableAmbientExplosions": "Activer les explosions d'ambiance", + "tooltip.explosionoverhaul.enableAmbientExplosions": "Active un système simulant des explosions lointaines pour l'ambiance.", + "option.explosionoverhaul.minTimeBetweenExplosions": "Temps min entre événements (s)", + "tooltip.explosionoverhaul.minTimeBetweenExplosions": "Temps minimum entre deux explosions d'ambiance.", + "option.explosionoverhaul.maxTimeBetweenExplosions": "Temps max entre événements (s)", + "tooltip.explosionoverhaul.maxTimeBetweenExplosions": "Temps maximum entre deux explosions d'ambiance.", + "option.explosionoverhaul.minExplosionDistance": "Distance min de l'événement", + "tooltip.explosionoverhaul.minExplosionDistance": "Distance minimum d'origine du son.", + "option.explosionoverhaul.maxExplosionDistance": "Distance max de l'événement", + "tooltip.explosionoverhaul.maxExplosionDistance": "Distance maximum d'origine du son.", + "option.explosionoverhaul.maxAmbientExplosionPower": "Puissance d'ambiance max", + "tooltip.explosionoverhaul.maxAmbientExplosionPower": "Puissance maximale d'une explosion de type 'Cataclysm'.", + + "option.explosionoverhaul.scenariosHeader": "--- Scénarios d'Ambiance ---", + "tooltip.explosionoverhaul.scenariosHeader": "Configure les types et la fréquence des événements d'ambiance.", + "option.explosionoverhaul.singleExplosionWeight": "Poids de l'explosion unique", + "option.explosionoverhaul.chainReactionWeight": "Poids de la réaction en chaîne", + "option.explosionoverhaul.shellingWeight": "Poids du pilonnage d'artillerie", + + "option.explosionoverhaul.chainReactionSettingsHeader": "--- Réaction en Chaîne ---", + "option.explosionoverhaul.minChainReactionShots": "Coups min", + "option.explosionoverhaul.maxChainReactionShots": "Coups max", + "option.explosionoverhaul.minTimeBetweenChainShots": "Temps min entre coups", + "option.explosionoverhaul.maxTimeBetweenChainShots": "Temps max entre coups", + + "option.explosionoverhaul.shellingSettingsHeader": "--- Pilonnage d'Artillerie ---", + "option.explosionoverhaul.minShellingDelay": "Délai d'impact min", + "option.explosionoverhaul.maxShellingDelay": "Délai d'impact max", + + "option.explosionoverhaul.powerTiersHeader": "--- Poids des Paliers ---", + "tooltip.explosionoverhaul.powerTiersHeader": "Poids des niveaux de puissance pour les événements 'Unique' et 'Pilonnage'.", + "option.explosionoverhaul.tier1_weight": "Poids Palier 1 (1-4)", + "option.explosionoverhaul.tier2_weight": "Poids Palier 2 (5-15)", + "option.explosionoverhaul.tier3_weight": "Poids Palier 3 (16-40)", + "option.explosionoverhaul.tier4_weight": "Poids Palier 4 (41-80)", + "option.explosionoverhaul.tier5_weight": "Poids Palier 5 (81+)", + + "option.explosionoverhaul.soundTypesHeader": "--- Bascules d'Environnement ---", + "option.explosionoverhaul.enableSurfaceSounds": "Activer sons de surface", + "tooltip.explosionoverhaul.enableSurfaceSounds": "Surface : Un son clair en zone ouverte.", + "option.explosionoverhaul.enableCaveSounds": "Activer sons de grotte", + "tooltip.explosionoverhaul.enableCaveSounds": "Grotte : Un son résonnant quand joueur et explosion sont en grotte.", + "option.explosionoverhaul.enableAmbientCaveDust": "Activer poussière de grotte", + "option.explosionoverhaul.glowTextureQuality": "Qualité des textures lueurs", + "tooltip.explosionoverhaul.glowTextureQuality": "Définit la résolution des textures de boules de feu.\nRecharge des ressources requise (F3+T).", + "option.explosionoverhaul.particleSizeScale": "Échelle de taille des particules", + "tooltip.explosionoverhaul.particleSizeScale": "Échelle globale des particules. 100 = défaut (1.0x).", + "option.explosionoverhaul.particleRenderMode": "Système de rendu", + "tooltip.explosionoverhaul.particleRenderMode": "Choisissez le système de rendu :\nRealistic : Sheets animés complexes (Qualité)\nRealistic 2 : Particule unique large (Performance)\nVanilla-like : Textures simples (Équilibre)", + "tooltip.explosionoverhaul.enableAmbientCaveDust": "Lors d'une explosion en grotte, de la poussière tombera du plafond.", + "option.explosionoverhaul.enableLineSparks": "Activer étincelles", + "tooltip.explosionoverhaul.enableLineSparks": "Active les étincelles jaillissant de l'épicentre.", + "option.explosionoverhaul.lineSparkAmountMultiplier": "Quantité d'étincelles", + "tooltip.explosionoverhaul.lineSparkAmountMultiplier": "Multiplicateur de perfs.", + "option.explosionoverhaul.dripstoneFallingSettings": "--- Chute de Spéléothèmes ---", + "option.explosionoverhaul.enableDripstoneFalling": "Activer chute de spéléothèmes", + "tooltip.explosionoverhaul.enableDripstoneFalling": "Active l'effet de chute des spéléothèmes pointus.", + "option.explosionoverhaul.dripstoneFallingSearchRadius": "Rayon de recherche", + "tooltip.explosionoverhaul.dripstoneFallingSearchRadius": "Rayon de recherche des spéléothèmes.", + + "option.explosionoverhaul.scanSettingsHeader": "--- Scan des Chunks ---", + "option.explosionoverhaul.maxScanThreads": "Threads de scan max", + "tooltip.explosionoverhaul.maxScanThreads": "Nombre de threads pour le scan des chunks.\n0 = Auto-détection (recommandé).", + "option.explosionoverhaul.cpuUsagePercent": "Utilisation CPU (%)", + "tooltip.explosionoverhaul.cpuUsagePercent": "Puissance CPU dédiée au scan (1-100%).", + "option.explosionoverhaul.enableBlockIndexing": "Indexation des blocs", + "tooltip.explosionoverhaul.enableBlockIndexing": "Active le scan automatique pour lampes, spéléothèmes et verre.\nUtile pour minimiser les tâches de fond.", + "option.explosionoverhaul.showScanProgressHUD": "Afficher l'HUD de progrès", + "tooltip.explosionoverhaul.showScanProgressHUD": "Affiche le % de chunks scannés en haut à gauche.", + + "option.explosionoverhaul.enableShockwaveEffect": "Activer l'onde de choc", + "tooltip.explosionoverhaul.enableShockwaveEffect": "Active les particules d'onde de choc.", + + "option.explosionoverhaul.enableWindEffect": "Activer l'effet du vent", + "tooltip.explosionoverhaul.enableWindEffect": "Les particules bougeront selon la direction et vitesse du vent.", + "option.explosionoverhaul.windSpeedMultiplier": "Multiplier de vent", + "tooltip.explosionoverhaul.windSpeedMultiplier": "Contrôle la vitesse globale du vent.", + "block.explosionoverhaul.vinlanx_the_light": "Vinlanx La Lumière", + "item.explosionoverhaul.vinlanx_the_light": "Vinlanx La Lumière", + "item.explosionoverhaul.mod_logo": "Icône de Refonte des Explosions", + "itemGroup.explosionoverhaul.main": "Refonte des Explosions : Un nouveau niveau de destruction" +} diff --git a/src/main/resources/assets/explosionoverhaul/lang/ru_ru.json b/src/main/resources/assets/explosionoverhaul/lang/ru_ru.json new file mode 100644 index 0000000..06bab62 --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/lang/ru_ru.json @@ -0,0 +1,247 @@ +{ + "key.categories.explosionoverhaul": "Переработка взрывов", + "key.explosionoverhaul.accept_scan": "Принять сканирование", + "key.explosionoverhaul.decline_scan": "Отклонить сканирование", + "key.explosionoverhaul.info_scan": "Инфо о сканировании", + "option.explosionoverhaul.enableAdvancedSoundSpeed": "Включить низкую скорость звука на близком расстоянии", + "tooltip.explosionoverhaul.enableAdvancedSoundSpeed": "Если включено, звуки взрывов на расстоянии до 240 метров будут распространяться медленнее для более эпичного эффекта. Свыше 240 метров звук распространяется со скоростью 343 м/с. Если выключено, звук всегда распространяется со скоростью 343 м/с.", + "title.explosionoverhaul.blacklist": "Черные списки взрывов", + "option.explosionoverhaul.show_defaults": "Показать записи по умолчанию", + "tooltip.explosionoverhaul.show_defaults": "Переключите, чтобы просмотреть встроенные защищенные блоки.", + "option.explosionoverhaul.reset_list": "Сброс", + "tooltip.explosionoverhaul.reset_list": "Зажмите SHIFT и кликните, чтобы сбросить этот список до исходных значений", + "option.explosionoverhaul.blacklist_search": "Поиск по черному списку...", + "option.explosionoverhaul.blacklist_input": "modid:block_name", + "option.explosionoverhaul.blacklist_add": "Добавить", + "option.explosionoverhaul.blacklist_category_explosion": "Разрушение взрывом", + "tooltip.explosionoverhaul.blacklist_category_explosion": "Блоки, которые не должны разрушаться взрывами (например, бедрок).", + "option.explosionoverhaul.blacklist_category_glass": "Разрушение стекла", + "tooltip.explosionoverhaul.blacklist_category_glass": "Блоки, предотвращающие разрушение стекла.", + "option.explosionoverhaul.blacklist_category_sources": "Источники взрывов", + "tooltip.explosionoverhaul.blacklist_category_sources": "Управляйте тем, как мод обрабатывает взрывы от конкретных сущностей (например, гранаты TacZ).", + "option.explosionoverhaul.blacklist_input_entities": "modid:entity_name или 'generic'", + "message.explosionoverhaul.invalid_id": "Неверный формат ID.", + "message.explosionoverhaul.invalid_block": "Блок не найден в реестре.", + "message.explosionoverhaul.invalid_entity": "Сущность не найдена в реестре (используйте 'generic' для взрывов без сущностей).", + "message.explosionoverhaul.duplicate_entry": "Эта запись уже есть в списке.", + "message.explosionoverhaul.list_reset": "Список сброшен до значений по умолчанию.", + "option.explosionoverhaul.blacklist_info": "Инфо", + "tooltip.explosionoverhaul.blacklist_info": "Советы по совместимости:\n- Для гранат/ракет TACZ: используйте 'tacz:bullet' для управления их взрывами.", + "category.explosionoverhaul.sounds": "Настройки звуков", + "option.explosionoverhaul.cameraServerHeader": "--- Сервер ---", + "option.explosionoverhaul.enablePlayerShake": "Включить тряску игрока", + "tooltip.explosionoverhaul.enablePlayerShake": "Включает или отключает эффект тряски игрока от взрывов.", + "title.explosionoverhaul.config": "Настройки Переработки взрывов", + "category.explosionoverhaul.server": "Настройки сервера", + "category.explosionoverhaul.render": "Настройки отрисовки", + "category.explosionoverhaul.blacklists": "Черные списки", + "option.explosionoverhaul.blacklist_button": "Страница черных списков", + "tooltip.explosionoverhaul.blacklist_button": "Эта кнопка перенаправит вас на страницу со всеми черными списками.", + "category.explosionoverhaul.camera": "Настройки камеры", + "category.explosionoverhaul.ambient": "Настройки окружения", + "category.explosionoverhaul.scan": "Настройки сканирования", + "category.explosionoverhaul.concussion": "Настройки контузии", + + "option.explosionoverhaul.enableConcussion": "Включить эффекты контузии", + "tooltip.explosionoverhaul.enableConcussion": "Главный переключатель для всей системы контузии (размытие, глухота, сердцебиение и т. д.)", + "option.explosionoverhaul.concussionDurationMultiplier": "Множитель длительности", + "tooltip.explosionoverhaul.concussionDurationMultiplier": "Как долго длятся эффекты контузии после взрыва.", + "option.explosionoverhaul.concussionChanceMultiplier": "Общий множитель шанса", + "tooltip.explosionoverhaul.concussionChanceMultiplier": "Глобальный множитель вероятности возникновения любого эффекта контузии.", + "option.explosionoverhaul.sourcemode_default": "ПО УМОЛЧАНИЮ", + "tooltip.explosionoverhaul.sourcemode_default": "Мод обрабатывает этот взрыв со всеми включенными эффектами переработки.", + "option.explosionoverhaul.sourcemode_vanilla": "ВАНИЛЬНЫЙ", + "tooltip.explosionoverhaul.sourcemode_vanilla": "Обходит все эффекты мода. Этот взрыв будет вести себя точно так же, как в ванильном Minecraft.", + "option.explosionoverhaul.sourcemode_no_destruction": "БЕЗ РАЗРУШЕНИЙ", + "tooltip.explosionoverhaul.sourcemode_no_destruction": "Изменяет взрыв так, чтобы он не наносил урона блокам, сохраняя при этом все визуальные и звуковые эффекты.", + "option.explosionoverhaul.sourcemode_no_destruction_glassworks": "БЕЗ РАЗРУШ. (С)", + "tooltip.explosionoverhaul.sourcemode_no_destruction_glassworks": "То же самое, что БЕЗ РАЗРУШЕНИЙ, но также предотвращает специализированный эффект «Разрушения стекла».", + "option.explosionoverhaul.enableHeartbeatPulse": "Пульсация и звук сердцебиения", + "tooltip.explosionoverhaul.enableHeartbeatPulse": "Включает или отключает визуальную пульсацию экрана и звуки сердцебиения «тук-тук».", + "option.explosionoverhaul.enableCameraSway": "Покачивание камеры", + "tooltip.explosionoverhaul.enableCameraSway": "Включает эффект дезориентации при покачивании камеры.", + "option.explosionoverhaul.cameraSwayIntensity": "Интенсивность покачивания камеры", + "tooltip.explosionoverhaul.cameraSwayIntensity": "Множитель радиуса для эффекта покачивания камеры.", + "option.explosionoverhaul.enableDeafness": "Глухота (Звон)", + "tooltip.explosionoverhaul.enableDeafness": "Включает эффект высокочастотного звона после близкого взрыва.", + "option.explosionoverhaul.enableLowPass": "Низкие частоты (Приглушенный звук)", + "tooltip.explosionoverhaul.enableLowPass": "Включает эффект приглушенного звука, который подавляет звуки окружающей среды.", + "option.explosionoverhaul.deafnessChanceMultiplier": "Шанс глухоты", + "tooltip.explosionoverhaul.deafnessChanceMultiplier": "Множитель вероятности для эффекта глухоты.", + "option.explosionoverhaul.lowPassChanceMultiplier": "Шанс приглушения звука", + "tooltip.explosionoverhaul.lowPassChanceMultiplier": "Множитель вероятности для эффекта фильтра низких частот.", + "option.explosionoverhaul.showHeartbeatHUD": "Показывать HUD сердцебиения", + "tooltip.explosionoverhaul.showHeartbeatHUD": "Показывает счетчик BPM/BPS в правом верхнем углу экрана.", + + "option.explosionoverhaul.enableFallingBlocks": "Включить падающие блоки", + "tooltip.explosionoverhaul.enableFallingBlocks": "Если включено, блоки будут разлетаться от взрывов. Это серверная настройка.", + "option.explosionoverhaul.enableExplosionClustering": "Включить кластеризацию взрывов", + "tooltip.explosionoverhaul.enableExplosionClustering": "Включает или отключает объединение близлежащих взрывчатых веществ в один более мощный взрыв.", + "option.explosionoverhaul.maxClusterPower": "Макс. мощность кластера", + "tooltip.explosionoverhaul.maxClusterPower": "Максимальная общая мощность для кластерных взрывов динамита.\n4 = минимум (один ТНТ)\n100 = по умолчанию (безопасно)\n150+ = риск задержек рендеринга\n300+ = серьезные проблемы с рендерингом\n500+ = риск вылета игры", + "warning.explosionoverhaul.renderingLag": "ПРЕДУПРЕЖДЕНИЕ: МОЩНЫЕ ВЗРЫВЫ МОГУТ ВЫЗВАТЬ ЗАДЕРЖКИ РЕНДЕРИНГА", + "warning.explosionoverhaul.severeRenderingLag": "ПРЕДУПРЕЖДЕНИЕ: МОЩНЫЕ ВЗРЫВЫ МОГУТ ВЫЗВАТЬ СЕРЬЕЗНЫЕ ЗАДЕРЖКИ РЕНДЕРИНГА", + "warning.explosionoverhaul.crashRisk": "ПРЕДУПРЕЖДЕНИЕ: РИСК ВЫЛЕТА ИГРЫ ПРИ МОЩНЫХ ВЗРЫВАХ", + "option.explosionoverhaul.enableCraterDestruction": "Включить разрушение кратера", + "tooltip.explosionoverhaul.enableCraterDestruction": "Если отключено, взрывы все равно будут вызывать визуальные и звуковые эффекты, но не будут разрушать блоки.", + "option.explosionoverhaul.enableGlassBreaking": "Включить разрушение стекла", + "tooltip.explosionoverhaul.enableGlassBreaking": "Включает или отключает разрушение стекла ударной волной взрыва.", + "option.explosionoverhaul.enableLampFlicker": "Включить мерцание ламп", + "tooltip.explosionoverhaul.enableLampFlicker": "Включает эффект мерцания редстоуновых ламп вблизи взрывов.", + + "option.explosionoverhaul.craterSettingsHeader": "--- Настройка кратера ---", + "option.explosionoverhaul.craterSizeMultiplier": "Множитель размера кратера", + "tooltip.explosionoverhaul.craterSizeMultiplier.title": "Настраивает диаметр и глубину кратеров.", + "tooltip.explosionoverhaul.craterSizeMultiplier.footer": "Это значение умножает рассчитанный базовый размер.", + "tooltip.explosionoverhaul.craterShapeInfo": "Параметр «Плотность кратера» применяется только к взрывам мощностью 40 и выше.", + "option.explosionoverhaul.craterCoreRatio": "Плотность кратера (для мощности 40+)", + "tooltip.explosionoverhaul.craterCoreRatio": "Для мощных взрывов это определяет форму кратера.\n10% = очень «лучистый» (как солнце)\n95% = почти идеальная сфера (сплошная чаша)", + + "option.explosionoverhaul.enableAsyncCrater": "Включить асинхронный конвейер кратера", + "tooltip.explosionoverhaul.enableAsyncCrater": "Вычисляет геометрию кратера вне основного потока и применяет изменения блоков небольшими партиями за такт, чтобы сохранить стабильность TPS при мощных взрывах.\n\nВНИМАНИЕ: Когда включен асинхронный и многопоточный режим — разрушение объектов VS — не работает.", + "option.explosionoverhaul.craterMaxThreads": "Макс. потоков асинхронного кратера", + "tooltip.explosionoverhaul.craterMaxThreads": "Максимальное количество рабочих потоков, используемых для подготовки кратера вне основного потока.\n0 = Авто (использовать все доступные потоки)", + "option.explosionoverhaul.craterApplyBlocksPerTick": "Бюджет применения кратера (блоков/такт)", + "tooltip.explosionoverhaul.craterApplyBlocksPerTick": "Сколько блоков обрабатывать за один такт сервера при применении изменений кратера.\nЧем выше, тем быстрее создание кратера, но потенциально больше скачков TPS.", + "option.explosionoverhaul.craterMaxFallingBlocksPerTick": "Макс. падающих блоков (сущностей/такт)", + "tooltip.explosionoverhaul.craterMaxFallingBlocksPerTick": "Ограничивает количество сущностей падающих блоков, создаваемых за такт при создании кратера.\nУстановите 0, чтобы отключить создание в асинхронном режиме.", + "option.explosionoverhaul.enableDirectChunkWrites": "Прямая запись в чанки", + "tooltip.explosionoverhaul.enableDirectChunkWrites": "Прямая запись состояний блоков в секции чанков вместо использования Level#setBlock.\nНамного быстрее, но пропускает события блоков Forge и обновления соседей.", + "option.explosionoverhaul.craterChunksPerTick": "Бюджет чанков кратера (чанков/такт)", + "tooltip.explosionoverhaul.craterChunksPerTick": "Максимальное количество чанков для обработки за такт при включении прямой записи.\nИспользуйте вместе с параметром блоков/такт для сглаживания TPS.", + + "option.explosionoverhaul.glassBreakingSettings": "--- Разрушение стекла ---", + "option.explosionoverhaul.glassBreakingIntervalTicks": "Интервал обработки (в тактах)", + "tooltip.explosionoverhaul.glassBreakingIntervalTicks": "Как часто сервер обрабатывает разрушение стекла (1 такт = 0,05 с). Меньшее значение — плавнее, но ресурсозатратнее.", + "option.explosionoverhaul.glassBlocksPerCycle": "Блоков разрушено за цикл", + "tooltip.explosionoverhaul.glassBlocksPerCycle": "Максимальное количество стеклянных блоков, разрушаемых за один раз. Предотвращает лаги от мощных взрывов.", + + + "option.explosionoverhaul.lampFlickerSettings": "--- Мерцание ламп ---", + "option.explosionoverhaul.lampFlickerSearchRadius": "Радиус поиска ламп", + "tooltip.explosionoverhaul.lampFlickerSearchRadius": "Радиус вокруг игрока для поиска ламп. Высокие значения могут вызвать задержки.", + + "option.explosionoverhaul.enableExplosionParticles": "Включить основные частицы взрыва", + "tooltip.explosionoverhaul.enableExplosionParticles": "Включает основные частицы огненного свечения (glow, glow_2, sglow). Отключение может повысить производительность.", + "option.explosionoverhaul.enablePlasmaParticles": "Включить плазменные искры", + "tooltip.explosionoverhaul.enablePlasmaParticles": "Включает или полностью отключает плазменные искры.", + "option.explosionoverhaul.enablePlasmaSmokeTrail": "Включить плазменный дымовой шлейф", + "tooltip.explosionoverhaul.enablePlasmaSmokeTrail": "Включает дымовой шлейф, следующий за плазменными искрами.", + "option.explosionoverhaul.plasmaSmokeFrequency": "Частота плазменного дыма", + "tooltip.explosionoverhaul.plasmaSmokeFrequency": "Как часто появляется дым от плазменных частиц. 0% = нет дыма, 25% = меньше, 70% = оригинал.", + "option.explosionoverhaul.plasmaSmokeCount": "Количество плазменного дыма", + "tooltip.explosionoverhaul.plasmaSmokeCount": "Количество частиц дыма, создаваемых за такт плазмы. По умолчанию было 2.", + "option.explosionoverhaul.enableFlashEffect": "Включить эффект вспышки", + "tooltip.explosionoverhaul.enableFlashEffect": "Включает эффект наложения вспышки при взрывах.", + "option.explosionoverhaul.flashMaxOpacity": "Макс. непрозрачность вспышки", + "tooltip.explosionoverhaul.flashMaxOpacity": "Максимальная непрозрачность оверлея эффекта вспышки. 0% = нет вспышки, 100% = полная непрозрачность.", + "option.explosionoverhaul.enableGroundDustEffect": "Включить наземную пыль", + "tooltip.explosionoverhaul.enableGroundDustEffect": "Включает эффект облака пыли от взрывов.", + "option.explosionoverhaul.groundDustQuality": "Качество наземной пыли", + "tooltip.explosionoverhaul.groundDustQuality": "Влияет на количество и длительность частиц. Низкие значения повышают производительность.", + "option.explosionoverhaul.groundDustRaycastFrequency": "Распространение наземной пыли", + "tooltip.explosionoverhaul.groundDustRaycastFrequency": "Управляет тем, как часто частицы пыли проверяют наличие земли. Высокие значения могут снизить производительность.", + + "option.explosionoverhaul.enableGroundMistEffect": "Включить наземный туман", + "tooltip.explosionoverhaul.enableGroundMistEffect": "Включает эффект белого облака тумана от взрывов.", + "option.explosionoverhaul.groundMistQuality": "Качество наземного тумана", + "tooltip.explosionoverhaul.groundMistQuality": "Влияет на количество и длительность частиц тумана. Низкие значения повышают производительность.", + "option.explosionoverhaul.groundMistRaycastFrequency": "Распространение наземного тумана", + "tooltip.explosionoverhaul.groundMistRaycastFrequency": "Управляет тем, как часто частицы тумана проверяют наличие земли. Высокие значения могут снизить производительность.", + + "option.explosionoverhaul.enableMistEffect": "Включить эффект тумана", + "tooltip.explosionoverhaul.enableMistEffect": "Включает эффект белого тумана, распространяющегося от взрывов.", + "option.explosionoverhaul.mistQuality": "Качество тумана", + "tooltip.explosionoverhaul.mistQuality": "Влияет на количество и длительность частиц тумана.", + "option.explosionoverhaul.mistRaycastFrequency": "Распространение тумана", + "tooltip.explosionoverhaul.mistRaycastFrequency": "Управляет тем, как часто частицы тумана проверяют наличие земли.", + + "option.explosionoverhaul.enableCameraShake": "Включить тряску камеры", + "tooltip.explosionoverhaul.enableCameraShake": "Включает или отключает эффект тряски камеры от взрывов.", + "option.explosionoverhaul.cameraShakeAmplifier": "Усилитель тряски камеры", + "tooltip.explosionoverhaul.cameraShakeAmplifier": "Умножает интенсивность тряски камеры. 0.0x = без тряски, 1.0x = по умолчанию.", + "option.explosionoverhaul.playerShakeAmplifier": "Усилитель тряски игрока", + "tooltip.explosionoverhaul.playerShakeAmplifier": "Умножает интенсивность тряски игрока (движение из стороны в сторону). 0.0x = без тряски, 1.0x = по умолчанию.", + + "option.explosionoverhaul.enableAmbientExplosions": "Включить фоновые взрывы", + "tooltip.explosionoverhaul.enableAmbientExplosions": "Включает систему, имитирующую далекие случайные взрывы для создания атмосферы поля боя.", + "option.explosionoverhaul.minTimeBetweenExplosions": "Мин. время между событиями (с)", + "tooltip.explosionoverhaul.minTimeBetweenExplosions": "Минимальное время в секундах между фоновыми взрывами.", + "option.explosionoverhaul.maxTimeBetweenExplosions": "Макс. время между событиями (с)", + "tooltip.explosionoverhaul.maxTimeBetweenExplosions": "Максимальное время в секундах между фоновыми взрывами.", + "option.explosionoverhaul.minExplosionDistance": "Мин. расстояние события", + "tooltip.explosionoverhaul.minExplosionDistance": "Минимальное расстояние в блоках от игрока, где может возникнуть фоновый звук.", + "option.explosionoverhaul.maxExplosionDistance": "Макс. расстояние события", + "tooltip.explosionoverhaul.maxExplosionDistance": "Максимальное расстояние в блоках от игрока, где может возникнуть фоновый звук.", + "option.explosionoverhaul.maxAmbientExplosionPower": "Макс. фоновая мощность", + "tooltip.explosionoverhaul.maxAmbientExplosionPower": "Максимальная мощность, которую может иметь случайный взрыв уровня «Катаклизм».", + + "option.explosionoverhaul.scenariosHeader": "--- Сценарии окружения ---", + "tooltip.explosionoverhaul.scenariosHeader": "Настройка типов и частоты различных фоновых взрывов.", + "option.explosionoverhaul.singleExplosionWeight": "Вес одиночного взрыва", + "option.explosionoverhaul.chainReactionWeight": "Вес цепной реакции", + "option.explosionoverhaul.shellingWeight": "Вес арт-обстрела", + + "option.explosionoverhaul.chainReactionSettingsHeader": "--- Настройки цепной реакции ---", + "option.explosionoverhaul.minChainReactionShots": "Мин. выстрелов в цепи", + "option.explosionoverhaul.maxChainReactionShots": "Макс. выстрелов в цепи", + "option.explosionoverhaul.minTimeBetweenChainShots": "Мин. время между выстрелами", + "option.explosionoverhaul.maxTimeBetweenChainShots": "Макс. время между выстрелами", + + "option.explosionoverhaul.shellingSettingsHeader": "--- Настройки арт-обстрела ---", + "option.explosionoverhaul.minShellingDelay": "Мин. задержка попадания", + "option.explosionoverhaul.maxShellingDelay": "Макс. задержка попадания", + + "option.explosionoverhaul.powerTiersHeader": "--- Веса ступеней мощности ---", + "tooltip.explosionoverhaul.powerTiersHeader": "Веса для различных уровней мощности взрыва в событиях «Одиночный» и «Обстрел».", + "option.explosionoverhaul.tier1_weight": "Вес 1-й ступени (1-4 мощн.)", + "option.explosionoverhaul.tier2_weight": "Вес 2-й ступени (5-15 мощн.)", + "option.explosionoverhaul.tier3_weight": "Вес 3-й ступени (16-40 мощн.)", + "option.explosionoverhaul.tier4_weight": "Вес 4-й ступени (41-80 мощн.)", + "option.explosionoverhaul.tier5_weight": "Вес 5-й ступени (81+ мощн.)", + + "option.explosionoverhaul.soundTypesHeader": "--- Переключатели звуковой среды ---", + "option.explosionoverhaul.enableSurfaceSounds": "Включить надземные звуки", + "tooltip.explosionoverhaul.enableSurfaceSounds": "Поверхность: Четкий звук взрыва на открытой местности.", + "option.explosionoverhaul.enableCaveSounds": "Включить пещерные звуки", + "tooltip.explosionoverhaul.enableCaveSounds": "Пещера: Громкий, отдающийся эхом звук, когда игрок и взрыв находятся в пещере.", + "option.explosionoverhaul.enableAmbientCaveDust": "Включить фоновую пещерную пыль", + "option.explosionoverhaul.glowTextureQuality": "Качество текстур свечения", + "tooltip.explosionoverhaul.glowTextureQuality": "Устанавливает разрешение для текстур основного огненного шара.\nНизкое качество может повысить производительность. Требует перезагрузки ресурсов (F3+T).", + "option.explosionoverhaul.particleSizeScale": "Масштаб размера частиц", + "tooltip.explosionoverhaul.particleSizeScale": "Масштабирует размер всех частиц взрыва во всех режимах рендеринга.\n100 = масштаб по умолчанию (1.0х), 10 = 10% от дефолта (0.1х), 500 = 500% от дефолта (5.0х).", + "option.explosionoverhaul.particleRenderMode": "Система рендеринга частиц", + "tooltip.explosionoverhaul.particleRenderMode": "Выберите одну из систем рендеринга частиц:\nРеалистичная: Текущая система со сложными анимированными листами спрайтов (лучшее качество)\nРеалистичная 2: Оптимизированная система с одной большой частицей (лучшая производительность)\nВанильная: Использует простые текстуры с цветовыми фазами (хорошая производительность)", + "tooltip.explosionoverhaul.enableAmbientCaveDust": "Если происходит фоновый пещерный взрыв, с потолка будет падать визуальный эффект пыли.", + "option.explosionoverhaul.enableLineSparks": "Включить искры", + "tooltip.explosionoverhaul.enableLineSparks": "Включает или отключает искры, вылетающие из эпицентра взрыва.", + "option.explosionoverhaul.lineSparkAmountMultiplier": "Количество искр", + "tooltip.explosionoverhaul.lineSparkAmountMultiplier": "Множитель количества искр от взрывов. Высокие значения могут повлиять на производительность.", + "option.explosionoverhaul.dripstoneFallingSettings": "--- Падение капельников ---", + "option.explosionoverhaul.enableDripstoneFalling": "Включить падение капельников", + "tooltip.explosionoverhaul.enableDripstoneFalling": "Включает или отключает эффект падения для остроконечного капельника.", + "option.explosionoverhaul.dripstoneFallingSearchRadius": "Радиус поиска капельников", + "tooltip.explosionoverhaul.dripstoneFallingSearchRadius": "Радиус вокруг игрока для поиска остроконечных капельников. Высокие значения могут вызвать задержки.", + + "option.explosionoverhaul.scanSettingsHeader": "--- Сканирование чанков ---", + "option.explosionoverhaul.maxScanThreads": "Макс. потоков сканирования", + "tooltip.explosionoverhaul.maxScanThreads": "Максимальное количество потоков для сканирования чанков.\nДиапазон настраивается автоматически под вашу систему.\n0 = Авто (рекомендуется): использует все доступные потоки\n1 = Однопоточный (безопаснее для слабых систем)\nВысокие значения — быстрее сканирование, но выше нагрузка на ЦП.", + "option.explosionoverhaul.cpuUsagePercent": "Процент использования ЦП", + "tooltip.explosionoverhaul.cpuUsagePercent": "Какую мощность процессора выделить на сканирование чанков (1-100%).\n100% = Максимальная скорость, интенсивное использование всей мощности\n75% = Сбалансировано (рекомендуется), быстрое сканирование с запасом\n50% = Консервативно, оставляет место для других серверных процессов\n25% = Минимальное влияние, медленно, но безопасно для загруженных серверов\nНизкие значения добавляют задержки между обработкой для снижения нагрузки.", + "option.explosionoverhaul.enableBlockIndexing": "Индексация блоков", + "tooltip.explosionoverhaul.enableBlockIndexing": "Включает или отключает систему индексации блоков.\nЕсли включено, чанки автоматически сканируются на наличие редстоуновых ламп, капельников и стекла.\nЕсли отключено, будет происходить только ручная регистрация блоков.\nЭто влияет на производительность мерцания ламп, падения капельников и разрушения стекла.\nПолезно для серверов, которые хотят минимизировать фоновые процессы.", + "option.explosionoverhaul.showScanProgressHUD": "Показывать HUD прогресса сканирования", + "tooltip.explosionoverhaul.showScanProgressHUD": "Управляет видимостью HUD прогресса сканирования в левом верхнем углу.\nПоказывает процент просканированных чанков при инициализации мира.\nАвтоматически скрывается после завершения сканирования.", + + "option.explosionoverhaul.enableShockwaveEffect": "Включить эффект ударной волны", + "tooltip.explosionoverhaul.enableShockwaveEffect": "Включает или отключает частицы ударной волны при взрывe.", + + "option.explosionoverhaul.enableWindEffect": "Включить эффект ветра", + "tooltip.explosionoverhaul.enableWindEffect": "Включает эффекты ветра на частицах взрыва (пыль, туман, свечение). Частицы будут двигаться согласно направлению и скорости ветра.", + "option.explosionoverhaul.windSpeedMultiplier": "Множитель скорости ветра", + "tooltip.explosionoverhaul.windSpeedMultiplier": "Управляет глобальной скоростью ветра, влияющей на все частицы. 1.0 = нормальная скорость, 1.5 = на 50% быстрее, 2.0 = двойная скорость.", + "block.explosionoverhaul.vinlanx_the_light": "Винланс Свет", + "item.explosionoverhaul.vinlanx_the_light": "Винланс Свет", + "item.explosionoverhaul.mod_logo": "Иконка Переработки взрывов", + "itemGroup.explosionoverhaul.main": "Переработка взрывов: новый уровень разрушения" +} diff --git a/src/main/resources/assets/explosionoverhaul/lang/uk_ua.json b/src/main/resources/assets/explosionoverhaul/lang/uk_ua.json new file mode 100644 index 0000000..0224575 --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/lang/uk_ua.json @@ -0,0 +1,247 @@ +{ + "key.categories.explosionoverhaul": "Переробка вибухів", + "key.explosionoverhaul.accept_scan": "Прийняти сканування", + "key.explosionoverhaul.decline_scan": "Відхилити сканування", + "key.explosionoverhaul.info_scan": "Інфо про сканування", + "option.explosionoverhaul.enableAdvancedSoundSpeed": "Увімкнути низьку швидкість звуку на близькій відстані", + "tooltip.explosionoverhaul.enableAdvancedSoundSpeed": "Якщо увімкнено, звуки вибухів на відстані до 240 метрів поширюватимуться повільніше для більш епічного ефекту. Понад 240 метрів звук поширюється зі швидкістю 343 м/с. Якщо вимкнено, звук завжди поширюється зі швидкістю 343 м/с.", + "title.explosionoverhaul.blacklist": "Чорні списки вибухів", + "option.explosionoverhaul.show_defaults": "Показати записи за замовчуванням", + "tooltip.explosionoverhaul.show_defaults": "Перемикач для перегляду вбудованих захищених блоків.", + "option.explosionoverhaul.reset_list": "Скинути", + "tooltip.explosionoverhaul.reset_list": "Затисніть SHIFT та клацніть, щоб скинути цей список до початкових значень", + "option.explosionoverhaul.blacklist_search": "Пошук у чорному списку...", + "option.explosionoverhaul.blacklist_input": "modid:назва_блоку", + "option.explosionoverhaul.blacklist_add": "Додати", + "option.explosionoverhaul.blacklist_category_explosion": "Руйнування вибухом", + "tooltip.explosionoverhaul.blacklist_category_explosion": "Блоки, які не повинні руйнуватися вибухами (наприклад, бедрок).", + "option.explosionoverhaul.blacklist_category_glass": "Руйнування скла", + "tooltip.explosionoverhaul.blacklist_category_glass": "Блоки, що запобігають руйнуванню скла.", + "option.explosionoverhaul.blacklist_category_sources": "Джерела вибухів", + "tooltip.explosionoverhaul.blacklist_category_sources": "Керуйте тим, як мод обробляє вибухи від конкретних сутностей (наприклад, гранати TacZ).", + "option.explosionoverhaul.blacklist_input_entities": "modid:назва_сутності або 'generic'", + "message.explosionoverhaul.invalid_id": "Невірний формат ID.", + "message.explosionoverhaul.invalid_block": "Блок не знайдено в реєстрі.", + "message.explosionoverhaul.invalid_entity": "Сутність не знайдена в реєстрі (використовуйте 'generic' для вибухів без сутностей).", + "message.explosionoverhaul.duplicate_entry": "Цей запис вже є у списку.", + "message.explosionoverhaul.list_reset": "Список скинуто до значень за замовчуванням.", + "option.explosionoverhaul.blacklist_info": "Інфо", + "tooltip.explosionoverhaul.blacklist_info": "Поради щодо сумісності:\n- Для гранат/ракет TACZ: використовуйте 'tacz:bullet' для керування їхніми вибухами.", + "category.explosionoverhaul.sounds": "Налаштування звуків", + "option.explosionoverhaul.cameraServerHeader": "--- Сервер ---", + "option.explosionoverhaul.enablePlayerShake": "Увімкнути тряску гравця", + "tooltip.explosionoverhaul.enablePlayerShake": "Умикає або вимикає ефект тряски гравця від вибухів.", + "title.explosionoverhaul.config": "Налаштування переробки вибухів", + "category.explosionoverhaul.server": "Налаштування сервера", + "category.explosionoverhaul.render": "Налаштування рендерингу", + "category.explosionoverhaul.blacklists": "Чорні списки", + "option.explosionoverhaul.blacklist_button": "Сторінка чорних списків", + "tooltip.explosionoverhaul.blacklist_button": "Ця кнопка перенаправить вас на сторінку з усіма чорними списками.", + "category.explosionoverhaul.camera": "Налаштування камери", + "category.explosionoverhaul.ambient": "Налаштування оточення", + "category.explosionoverhaul.scan": "Налаштування сканування", + "category.explosionoverhaul.concussion": "Налаштування контузії", + + "option.explosionoverhaul.enableConcussion": "Увімкнути ефекти контузії", + "tooltip.explosionoverhaul.enableConcussion": "Головний перемикач для всієї системи контузії (розмиття, глухота, серцебиття тощо).", + "option.explosionoverhaul.concussionDurationMultiplier": "Множник тривалості", + "tooltip.explosionoverhaul.concussionDurationMultiplier": "Як довго тривають ефекти контузії після вибуху.", + "option.explosionoverhaul.concussionChanceMultiplier": "Загальний множник шансу", + "tooltip.explosionoverhaul.concussionChanceMultiplier": "Глобальний множник ймовірності виникнення будь-якого ефекту контузії.", + "option.explosionoverhaul.sourcemode_default": "ЗА ЗАМОВЧУВАННЯМ", + "tooltip.explosionoverhaul.sourcemode_default": "Мод обробляє цей вибух з усіма увімкненими ефектами переробки.", + "option.explosionoverhaul.sourcemode_vanilla": "ВАНІЛЬНИЙ", + "tooltip.explosionoverhaul.sourcemode_vanilla": "Обходить усі ефекти мода. Цей вибух буде поводитися точно так само, як у ванільному Minecraft.", + "option.explosionoverhaul.sourcemode_no_destruction": "БЕЗ РУЙНУВАНЬ", + "tooltip.explosionoverhaul.sourcemode_no_destruction": "Змінює вибух так, щоб він не завдавав шкоди блокам, зберігаючи при цьому всі візуальні та звукові ефекти.", + "option.explosionoverhaul.sourcemode_no_destruction_glassworks": "БЕЗ РУЙНУВ. (С)", + "tooltip.explosionoverhaul.sourcemode_no_destruction_glassworks": "Те саме, що БЕЗ РУЙНУВАНЬ, але також запобігає спеціальному ефекту «Руйнування скла».", + "option.explosionoverhaul.enableHeartbeatPulse": "Пульсація та звук серцебиття", + "tooltip.explosionoverhaul.enableHeartbeatPulse": "Умикає або вимикає візуальну пульсацію екрана та звуки серцебиття «тук-тук».", + "option.explosionoverhaul.enableCameraSway": "Погойдування камери", + "tooltip.explosionoverhaul.enableCameraSway": "Умикає ефект погойдування камери при дезорієнтації.", + "option.explosionoverhaul.cameraSwayIntensity": "Інтенсивність погойдування камери", + "tooltip.explosionoverhaul.cameraSwayIntensity": "Множник радіуса для ефекту погойдування камери.", + "option.explosionoverhaul.enableDeafness": "Глухота (Дзвін)", + "tooltip.explosionoverhaul.enableDeafness": "Умикає ефект високочастотного дзвону після близького вибуху.", + "option.explosionoverhaul.enableLowPass": "Низькі частоти (Приглушений звук)", + "tooltip.explosionoverhaul.enableLowPass": "Умикає ефект приглушеного звуку, який поглинає звуки навколишнього середовища.", + "option.explosionoverhaul.deafnessChanceMultiplier": "Шанс глухоти", + "tooltip.explosionoverhaul.deafnessChanceMultiplier": "Множник ймовірності для ефекту глухоти.", + "option.explosionoverhaul.lowPassChanceMultiplier": "Шанс приглушення звуку", + "tooltip.explosionoverhaul.lowPassChanceMultiplier": "Множник ймовірності для ефекту фільтра низьких частот.", + "option.explosionoverhaul.showHeartbeatHUD": "Показувати HUD серцебиття", + "tooltip.explosionoverhaul.showHeartbeatHUD": "Показує лічильник BPM/BPS у верхньому правому куті екрана.", + + "option.explosionoverhaul.enableFallingBlocks": "Увімкнути падаючі блоки", + "tooltip.explosionoverhaul.enableFallingBlocks": "Якщо увімкнено, блоки будуть розлітатися від вибухів. Це серверне налаштування.", + "option.explosionoverhaul.enableExplosionClustering": "Увімкнути кластеризацію вибухів", + "tooltip.explosionoverhaul.enableExplosionClustering": "Умикає або вимикає об'єднання прилеглих вибухових речовин в один потужніший вибух.", + "option.explosionoverhaul.maxClusterPower": "Макс. потужність кластера", + "tooltip.explosionoverhaul.maxClusterPower": "Максимальна загальна потужність для кластерних вибухів динаміту.\n4 = мінімум (один ТНТ)\n100 = за замовчуванням (безпечно)\n150+ = ризик затримок рендерингу\n300+ = серйозні проблеми з рендерингом\n500+ = ризик вильоту гри", + "warning.explosionoverhaul.renderingLag": "ПОПЕРЕДЖЕННЯ: ПОТУЖНІ ВИБУХИ МОЖУТЬ ВИКЛИКАТИ ЗАТРИМКИ РЕНДЕРИНГУ", + "warning.explosionoverhaul.severeRenderingLag": "ПОПЕРЕДЖЕННЯ: ПОТУЖНІ ВИБУХИ МОЖУТЬ ВИКЛИКАТИ СЕРЙОЗНІ ЗАТРИМКИ РЕНДЕРИНГУ", + "warning.explosionoverhaul.crashRisk": "ПОПЕРЕДЖЕННЯ: РИЗИК ВИЛЬОТУ ГРИ ПРИ ПОТУЖНИХ ВИБУХАХ", + "option.explosionoverhaul.enableCraterDestruction": "Увімкнути руйнування кратера", + "tooltip.explosionoverhaul.enableCraterDestruction": "Якщо вимкнено, вибухи все одно спричинятимуть візуальні та звукові ефекти, але не руйнуватимуть блоки.", + "option.explosionoverhaul.enableGlassBreaking": "Увімкнути руйнування скла", + "tooltip.explosionoverhaul.enableGlassBreaking": "Умикає або вимикає руйнування скла ударною хвилею вибуху.", + "option.explosionoverhaul.enableLampFlicker": "Увімкнути мерехтіння ламп", + "tooltip.explosionoverhaul.enableLampFlicker": "Умикає ефект мерехтіння редстоунових ламп поблизу вибухів.", + + "option.explosionoverhaul.craterSettingsHeader": "--- Налаштування кратера ---", + "option.explosionoverhaul.craterSizeMultiplier": "Множник розміру кратера", + "tooltip.explosionoverhaul.craterSizeMultiplier.title": "Налаштовує діаметр і глибину кратерів.", + "tooltip.explosionoverhaul.craterSizeMultiplier.footer": "Це значення помножує розрахований базовий розмір.", + "tooltip.explosionoverhaul.craterShapeInfo": "Параметр «Щільність кратера» застосовується лише до вибухів потужністю 40 і вище.", + "option.explosionoverhaul.craterCoreRatio": "Щільність кратера (для потужності 40+)", + "tooltip.explosionoverhaul.craterCoreRatio": "Для потужних вибухів це визначає форму кратера.\n10% = дуже «променистий» (як сонце)\n95% = майже ідеальна сфера (суцільна чаша)", + + "option.explosionoverhaul.enableAsyncCrater": "Увімкнути асинхронний конвейер кратера", + "tooltip.explosionoverhaul.enableAsyncCrater": "Обчислює геометрію кратера поза основним потоком і застосовує зміни блоків невеликими партіями за такт, щоб зберегти стабільність TPS при потужних вибухах.\n\nУВАГА: Коли увімкнено асинхронний та багатопотоковий режим — руйнування об'єктів VS — не працює.", + "option.explosionoverhaul.craterMaxThreads": "Макс. потоків асинхронного кратера", + "tooltip.explosionoverhaul.craterMaxThreads": "Максимальна кількість робочих потоків, що використовуються для підготовки кратера поза основним потоком.\n0 = Авто (використовувати всі доступні потоки)", + "option.explosionoverhaul.craterApplyBlocksPerTick": "Бюджет застосування кратера (блоків/такт)", + "tooltip.explosionoverhaul.craterApplyBlocksPerTick": "Скільки блоків обробляти за один такт сервера під час застосування змін кратера.\nЧим вище, тим швидше створення кратера, але потенційно більше стрибків TPS.", + "option.explosionoverhaul.craterMaxFallingBlocksPerTick": "Макс. падаючих блоків (сутностей/такт)", + "tooltip.explosionoverhaul.craterMaxFallingBlocksPerTick": "Обмежує кількість сутностей падаючих блоків, що створюються за такт під час створення кратера.\nВстановіть 0, щоб вимкнути створення в асинхронному режимі.", + "option.explosionoverhaul.enableDirectChunkWrites": "Прямий запис у чанки", + "tooltip.explosionoverhaul.enableDirectChunkWrites": "Прямий запис станів блоків у секції чанків замість використання Level#setBlock.\nНабагато швидше, але пропускає події блоків Forge та оновлення сусідів.", + "option.explosionoverhaul.craterChunksPerTick": "Бюджет чанків кратера (чанків/такт)", + "tooltip.explosionoverhaul.craterChunksPerTick": "Максимальна кількість чанків для обробки за такт при увімкненні прямого запису.\nВикористовуйте разом із параметром блоків/такт для зглажування TPS.", + + "option.explosionoverhaul.glassBreakingSettings": "--- Руйнування скла ---", + "option.explosionoverhaul.glassBreakingIntervalTicks": "Інтервал обробки (в тактах)", + "tooltip.explosionoverhaul.glassBreakingIntervalTicks": "Як часто сервер обробляє руйнування скла (1 такт = 0,05 с). Менше значення — плавніше, але ресурсозатратніше.", + "option.explosionoverhaul.glassBlocksPerCycle": "Блоків зруйновано за цикл", + "tooltip.explosionoverhaul.glassBlocksPerCycle": "Максимальна кількість скляних блоків, що руйнуються за один раз. Запобігає лагам від потужних вибухів.", + + + "option.explosionoverhaul.lampFlickerSettings": "--- Мерехтіння ламп ---", + "option.explosionoverhaul.lampFlickerSearchRadius": "Радіус пошуку ламп", + "tooltip.explosionoverhaul.lampFlickerSearchRadius": "Радіус навколо гравця для пошуку ламп. Високі значення можуть спричинити затримки.", + + "option.explosionoverhaul.enableExplosionParticles": "Увімкнути основні частинки вибуху", + "tooltip.explosionoverhaul.enableExplosionParticles": "Умикає основні частинки вогняного світіння (glow, glow_2, sglow). Вимкнення може підвищити продуктивність.", + "option.explosionoverhaul.enablePlasmaParticles": "Увімкнути плазмові іскри", + "tooltip.explosionoverhaul.enablePlasmaParticles": "Умикає або повністю вимикає плазмові іскри.", + "option.explosionoverhaul.enablePlasmaSmokeTrail": "Увімкнути плазмовий димовий шлейф", + "tooltip.explosionoverhaul.enablePlasmaSmokeTrail": "Умикає димовий шлейф, що слідує за плазмовими іскрами.", + "option.explosionoverhaul.plasmaSmokeFrequency": "Частота плазмового диму", + "tooltip.explosionoverhaul.plasmaSmokeFrequency": "Як часто з'являється дим від плазмових частинок. 0% = немає диму, 25% = менше, 70% = оригінал.", + "option.explosionoverhaul.plasmaSmokeCount": "Кількість плазмового диму", + "tooltip.explosionoverhaul.plasmaSmokeCount": "Кількість частинок диму, що створюються за такт плазми. За замовчуванням було 2.", + "option.explosionoverhaul.enableFlashEffect": "Увімкнути ефект спалаху", + "tooltip.explosionoverhaul.enableFlashEffect": "Умикає ефект накладання спалаху при вибухах.", + "option.explosionoverhaul.flashMaxOpacity": "Макс. непрозорість спалаху", + "tooltip.explosionoverhaul.flashMaxOpacity": "Максимальна непрозорість оверлея ефекту спалаху. 0% = немає спалаху, 100% = повна непрозорість.", + "option.explosionoverhaul.enableGroundDustEffect": "Увімкнути наземний пил", + "tooltip.explosionoverhaul.enableGroundDustEffect": "Умикає ефект хмари пилу від вибухів.", + "option.explosionoverhaul.groundDustQuality": "Якість наземного пилу", + "tooltip.explosionoverhaul.groundDustQuality": "Впливає на кількість та тривалість частинок. Низькі значення підвищують продуктивність.", + "option.explosionoverhaul.groundDustRaycastFrequency": "Поширення наземного пилу", + "tooltip.explosionoverhaul.groundDustRaycastFrequency": "Керує тим, як часто частинки пилу перевіряють наявність землі. Високі значення можуть знизити продуктивність.", + + "option.explosionoverhaul.enableGroundMistEffect": "Увімкнути наземний туман", + "tooltip.explosionoverhaul.enableGroundMistEffect": "Умикає ефект білої хмари туману від вибухів.", + "option.explosionoverhaul.groundMistQuality": "Якість наземного туману", + "tooltip.explosionoverhaul.groundMistQuality": "Впливає на кількість та тривалість частинок туману. Низькі значення підвищують продуктивність.", + "option.explosionoverhaul.groundMistRaycastFrequency": "Поширення наземного туману", + "tooltip.explosionoverhaul.groundMistRaycastFrequency": "Керує тим, як часто частинки туману перевіряють наявність землі. Високі значення можуть знизити продуктивність.", + + "option.explosionoverhaul.enableMistEffect": "Увімкнути ефект туману", + "tooltip.explosionoverhaul.enableMistEffect": "Умикає ефект білого туману, що поширюється від вибухів.", + "option.explosionoverhaul.mistQuality": "Якість туману", + "tooltip.explosionoverhaul.mistQuality": "Впливає на кількість та тривалість частинок туману.", + "option.explosionoverhaul.mistRaycastFrequency": "Поширення туману", + "tooltip.explosionoverhaul.mistRaycastFrequency": "Керує тим, як часто частинки туману перевіряють наявність землі.", + + "option.explosionoverhaul.enableCameraShake": "Увімкнути тряску камери", + "tooltip.explosionoverhaul.enableCameraShake": "Умикає або вимикає ефект тряски камери від вибухів.", + "option.explosionoverhaul.cameraShakeAmplifier": "Підсилювач тряски камери", + "tooltip.explosionoverhaul.cameraShakeAmplifier": "Помножує інтенсивність тряски камери. 0.0x = без тряски, 1.0x = за замовчуванням.", + "option.explosionoverhaul.playerShakeAmplifier": "Підсилювач тряски гравця", + "tooltip.explosionoverhaul.playerShakeAmplifier": "Помножує інтенсивність тряски гравця (рух з боку в бік). 0.0x = без тряски, 1.0x = за замовчуванням.", + + "option.explosionoverhaul.enableAmbientExplosions": "Увімкнути фонові вибухи", + "tooltip.explosionoverhaul.enableAmbientExplosions": "Умикає систему, що імітує далекі випадкові вибухи для створення атмосфери поля бою.", + "option.explosionoverhaul.minTimeBetweenExplosions": "Мін. час між подіями (с)", + "tooltip.explosionoverhaul.minTimeBetweenExplosions": "Мінімальний час у секундах між фоновими вибухами.", + "option.explosionoverhaul.maxTimeBetweenExplosions": "Макс. час між подіями (с)", + "tooltip.explosionoverhaul.maxTimeBetweenExplosions": "Максимальний час у секундах між фоновими вибухами.", + "option.explosionoverhaul.minExplosionDistance": "Мін. відстань події", + "tooltip.explosionoverhaul.minExplosionDistance": "Мінімальна відстань у блоках від гравця, де може виникнути фоновий звук.", + "option.explosionoverhaul.maxExplosionDistance": "Макс. відстань події", + "tooltip.explosionoverhaul.maxExplosionDistance": "Максимальна відстань у блоках від гравця, де може виникнути фоновий звук.", + "option.explosionoverhaul.maxAmbientExplosionPower": "Макс. фонова потужність", + "tooltip.explosionoverhaul.maxAmbientExplosionPower": "Максимальна потужність, яку може мати випадковий вибух рівня «Катаклізм».", + + "option.explosionoverhaul.scenariosHeader": "--- Сценарії оточення ---", + "tooltip.explosionoverhaul.scenariosHeader": "Налаштування типів та частоти різних фонових вибухів.", + "option.explosionoverhaul.singleExplosionWeight": "Вага поодинокого вибуху", + "option.explosionoverhaul.chainReactionWeight": "Вага ланцюгової реакції", + "option.explosionoverhaul.shellingWeight": "Вага арт-обстрілу", + + "option.explosionoverhaul.chainReactionSettingsHeader": "--- Налаштування ланцюгової реакції ---", + "option.explosionoverhaul.minChainReactionShots": "Мін. пострілів у ланцюгу", + "option.explosionoverhaul.maxChainReactionShots": "Макс. пострілів у ланцюгу", + "option.explosionoverhaul.minTimeBetweenChainShots": "Мін. час між пострілами", + "option.explosionoverhaul.maxTimeBetweenChainShots": "Макс. час між пострілами", + + "option.explosionoverhaul.shellingSettingsHeader": "--- Налаштування арт-обстрілу ---", + "option.explosionoverhaul.minShellingDelay": "Мін. задержка влучання", + "option.explosionoverhaul.maxShellingDelay": "Макс. задержка влучання", + + "option.explosionoverhaul.powerTiersHeader": "--- Вага рівнів потужності ---", + "tooltip.explosionoverhaul.powerTiersHeader": "Вага для різних рівнів потужності вибуху в подіях «Поодинокий» та «Обстріл».", + "option.explosionoverhaul.tier1_weight": "Вага 1-го рівня (1-4 потуж.)", + "option.explosionoverhaul.tier2_weight": "Вага 2-го рівня (5-15 потуж.)", + "option.explosionoverhaul.tier3_weight": "Вага 3-го рівня (16-40 потуж.)", + "option.explosionoverhaul.tier4_weight": "Вага 4-го рівня (41-80 потуж.)", + "option.explosionoverhaul.tier5_weight": "Вага 5-го рівня (81+ потуж.)", + + "option.explosionoverhaul.soundTypesHeader": "--- Перемикачі звукового середовища ---", + "option.explosionoverhaul.enableSurfaceSounds": "Увімкнути надземні звуки", + "tooltip.explosionoverhaul.enableSurfaceSounds": "Поверхня: Чіткий звук вибуху на відкритій місцевості.", + "option.explosionoverhaul.enableCaveSounds": "Увімкнути печерні звуки", + "tooltip.explosionoverhaul.enableCaveSounds": "Печера: Гучний звук з відлунням, коли гравець і вибух перебувають у печері.", + "option.explosionoverhaul.enableAmbientCaveDust": "Увімкнути фоновий печерний пил", + "option.explosionoverhaul.glowTextureQuality": "Якість текстур світіння", + "tooltip.explosionoverhaul.glowTextureQuality": "Встановлює роздільну здатність для текстур основної вогняної кулі.\nНизька якість може підвищити продуктивність. Потребує перезавантаження ресурсів (F3+T).", + "option.explosionoverhaul.particleSizeScale": "Масштаб розміру частинок", + "tooltip.explosionoverhaul.particleSizeScale": "Масштабує розмір усіх частинок вибуху у всіх режимах рендерингу.\n100 = масштаб за замовчуванням (1.0х), 10 = 10% від дефолту (0.1х), 500 = 500% від дефолту (5.0х).", + "option.explosionoverhaul.particleRenderMode": "Система рендерингу частинок", + "tooltip.explosionoverhaul.particleRenderMode": "Виберіть одну з систем рендерингу частинок:\nРеалістична: Поточна система зі складними анімованими спрайтами (краща якість)\nРеалістична 2: Оптимізована система з однією великою частинкою (найкраща продуктивність)\nВанільна: Використовує прості текстури з кольоровими фазами (добра продуктивність)", + "tooltip.explosionoverhaul.enableAmbientCaveDust": "Якщо стається фоновий печерний вибух, зі стелі падатиме візуальний ефект пилу.", + "option.explosionoverhaul.enableLineSparks": "Увімкнути іскри", + "tooltip.explosionoverhaul.enableLineSparks": "Умикає або вимикає іскри, що вилітають з епіцентру вибуху.", + "option.explosionoverhaul.lineSparkAmountMultiplier": "Кількість іскор", + "tooltip.explosionoverhaul.lineSparkAmountMultiplier": "Множник кількості іскор від вибухів. Високі значення можуть вплинути на продуктивність.", + "option.explosionoverhaul.dripstoneFallingSettings": "--- Падіння крапельників ---", + "option.explosionoverhaul.enableDripstoneFalling": "Увімкнути падіння крапельників", + "tooltip.explosionoverhaul.enableDripstoneFalling": "Умикає або вимикає ефект падіння для гостроверхого крапельника.", + "option.explosionoverhaul.dripstoneFallingSearchRadius": "Радіус пошуку крапельників", + "tooltip.explosionoverhaul.dripstoneFallingSearchRadius": "Радіус навколо гравця для пошуку гостроверхих крапельників. Високі значення можуть спричинити затримки.", + + "option.explosionoverhaul.scanSettingsHeader": "--- Сканування чанків ---", + "option.explosionoverhaul.maxScanThreads": "Макс. потоків сканування", + "tooltip.explosionoverhaul.maxScanThreads": "Максимальна кількість потоків для сканування чанків.\nДіапазон налаштовується автоматично під вашу систему.\n0 = Авто (рекомендовано): використовує всі доступні потоки\n1 = Однопотоковий (найбезпечніше для слабких систем)\nВисоких значення — швидше сканування, але вище навантаження на ЦП.", + "option.explosionoverhaul.cpuUsagePercent": "Відсоток використання ЦП", + "tooltip.explosionoverhaul.cpuUsagePercent": "Яку потужність процесора виділити на сканування чанків (1-100%).\n100% = Максимальна швидкість, інтенсивне використання всієї потужності\n75% = Збалансовано (рекомендовано), швидке сканування із запасом\n50% = Консервативно, залишає місце для інших серверних процесів\n25% = Мінімальний вплив, повільно, але безпечно для завантажених серверів\nНизькі значення додають затримки між обробкою для зниження навантаження.", + "option.explosionoverhaul.enableBlockIndexing": "Індексація блоків", + "tooltip.explosionoverhaul.enableBlockIndexing": "Умикає або вимикає систему індексації блоків.\nЯкщо увімкнено, чанки автоматично скануються на наявність редстоунових ламп, крапельників та скла.\nЯкщо вимкнено, відбуватиметься лише ручна реєстрація блоків.\nЦе впливає на продуктивність мерехтіння ламп, падіння крапельників та руйнування скла.\nКорисно для серверів, які хочуть мінімізувати фонові процеси.", + "option.explosionoverhaul.showScanProgressHUD": "Показувати HUD прогресу сканування", + "tooltip.explosionoverhaul.showScanProgressHUD": "Керує видимістю HUD прогресу сканування у лівому верхньому куті.\nПоказує відсоток просканованих чанків при ініціалізації світу.\nАвтоматично ховається після завершення сканування.", + + "option.explosionoverhaul.enableShockwaveEffect": "Увімкнути ефект ударної хвилі", + "tooltip.explosionoverhaul.enableShockwaveEffect": "Умикає або вимикає частинки ударної хвилі при вибухy.", + + "option.explosionoverhaul.enableWindEffect": "Увімкнути ефект вітру", + "tooltip.explosionoverhaul.enableWindEffect": "Умикає ефект вітру на частинках вибуху (пил, туман, світіння). Частинки будуть рухатися згідно з напрямком та швидкістю вітру.", + "option.explosionoverhaul.windSpeedMultiplier": "Множник швидкості вітру", + "tooltip.explosionoverhaul.windSpeedMultiplier": "Керує глобальною швидкістю вітру, що впливає на всі частинки. 1.0 = нормальна швидкість, 1.5 = на 50% швидше, 2.0 = подвійна швидкість.", + "block.explosionoverhaul.vinlanx_the_light": "Вінланс Світло", + "item.explosionoverhaul.vinlanx_the_light": "Вінланс Світло", + "item.explosionoverhaul.mod_logo": "Ікона Переробки вибухів", + "itemGroup.explosionoverhaul.main": "Переробка вибухів: новий рівень руйнування" +} diff --git a/src/main/resources/assets/explosionoverhaul/models/block/vinlanx_the_light.json b/src/main/resources/assets/explosionoverhaul/models/block/vinlanx_the_light.json new file mode 100644 index 0000000..a8b3bef --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/models/block/vinlanx_the_light.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "explosionoverhaul:block/vinlanxthelight" + }, + "particle": "explosionoverhaul:block/vinlanxthelight" +} diff --git a/src/main/resources/assets/explosionoverhaul/models/item/mod_logo.json b/src/main/resources/assets/explosionoverhaul/models/item/mod_logo.json new file mode 100644 index 0000000..6a400ec --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/models/item/mod_logo.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "explosionoverhaul:item/mod_logo" + } +} diff --git a/src/main/resources/assets/explosionoverhaul/models/item/vinlanx_the_light.json b/src/main/resources/assets/explosionoverhaul/models/item/vinlanx_the_light.json new file mode 100644 index 0000000..ab46712 --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/models/item/vinlanx_the_light.json @@ -0,0 +1,3 @@ +{ + "parent": "builtin/entity" +} diff --git a/src/main/resources/assets/explosionoverhaul/particles/custom_glow.json b/src/main/resources/assets/explosionoverhaul/particles/custom_glow.json new file mode 100644 index 0000000..97d0a55 --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/particles/custom_glow.json @@ -0,0 +1,54 @@ +{ + "textures": [ + "explosionoverhaul:soft_glow", + "explosionoverhaul:soft_glow_e", + "explosionoverhaul:glow/glow_sheet_1", + "explosionoverhaul:glow/glow_sheet_2", + "explosionoverhaul:glow/glow_sheet_3", + "explosionoverhaul:glow/glow_sheet_4", + "explosionoverhaul:glow_2/glow_2_sheet_1", + "explosionoverhaul:glow_2/glow_2_sheet_2", + "explosionoverhaul:glow_2/glow_2_sheet_3", + "explosionoverhaul:glow_2/glow_2_sheet_4", + "explosionoverhaul:sglow/sglow_sheet_1", + "explosionoverhaul:sglow/sglow_sheet_2", + "explosionoverhaul:sglow/sglow_sheet_3", + "explosionoverhaul:sglow/sglow_sheet_4", + "explosionoverhaul:glow/glow_e_sheet_1", + "explosionoverhaul:glow/glow_e_sheet_2", + "explosionoverhaul:glow/glow_e_sheet_3", + "explosionoverhaul:glow/glow_e_sheet_4", + "explosionoverhaul:glow_2/glow_2_e_sheet_1", + "explosionoverhaul:glow_2/glow_2_e_sheet_2", + "explosionoverhaul:glow_2/glow_2_e_sheet_3", + "explosionoverhaul:glow_2/glow_2_e_sheet_4", + "explosionoverhaul:sglow/sglow_e_sheet_1", + "explosionoverhaul:sglow/sglow_e_sheet_2", + "explosionoverhaul:sglow/sglow_e_sheet_3", + "explosionoverhaul:sglow/sglow_e_sheet_4", + "explosionoverhaul:glow/64/glow_sheet_1", + "explosionoverhaul:glow/64/glow_sheet_2", + "explosionoverhaul:glow/64/glow_sheet_3", + "explosionoverhaul:glow/64/glow_sheet_4", + "explosionoverhaul:glow_2/64/glow_2_sheet_1", + "explosionoverhaul:glow_2/64/glow_2_sheet_2", + "explosionoverhaul:glow_2/64/glow_2_sheet_3", + "explosionoverhaul:glow_2/64/glow_2_sheet_4", + "explosionoverhaul:sglow/64/sglow_sheet_1", + "explosionoverhaul:sglow/64/sglow_sheet_2", + "explosionoverhaul:sglow/64/sglow_sheet_3", + "explosionoverhaul:sglow/64/sglow_sheet_4", + "explosionoverhaul:glow/64/glow_e_sheet_1", + "explosionoverhaul:glow/64/glow_e_sheet_2", + "explosionoverhaul:glow/64/glow_e_sheet_3", + "explosionoverhaul:glow/64/glow_e_sheet_4", + "explosionoverhaul:glow_2/64/glow_2_e_sheet_1", + "explosionoverhaul:glow_2/64/glow_2_e_sheet_2", + "explosionoverhaul:glow_2/64/glow_2_e_sheet_3", + "explosionoverhaul:glow_2/64/glow_2_e_sheet_4", + "explosionoverhaul:sglow/64/sglow_e_sheet_1", + "explosionoverhaul:sglow/64/sglow_e_sheet_2", + "explosionoverhaul:sglow/64/sglow_e_sheet_3", + "explosionoverhaul:sglow/64/sglow_e_sheet_4" + ] +} diff --git a/src/main/resources/assets/explosionoverhaul/particles/line_spark.json b/src/main/resources/assets/explosionoverhaul/particles/line_spark.json new file mode 100644 index 0000000..ff99290 --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/particles/line_spark.json @@ -0,0 +1,6 @@ +{ + "textures": [ + "explosionoverhaul:line_spark/line_spark", + "explosionoverhaul:line_spark/line_spark_e" + ] +} diff --git a/src/main/resources/assets/explosionoverhaul/particles/plasma.json b/src/main/resources/assets/explosionoverhaul/particles/plasma.json new file mode 100644 index 0000000..7671d76 --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/particles/plasma.json @@ -0,0 +1,9 @@ +{ + "textures": [ + "explosionoverhaul:plasma" + ], + "flipbook": { + "frames_per_second": 7, + "frame_count": 10 + } +} diff --git a/src/main/resources/assets/explosionoverhaul/particles/smoke.json b/src/main/resources/assets/explosionoverhaul/particles/smoke.json new file mode 100644 index 0000000..1b3776a --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/particles/smoke.json @@ -0,0 +1,12 @@ +{ + "textures": [ + "explosionoverhaul:blast_wave/smoke/blast_smoke_1", + "explosionoverhaul:blast_wave/smoke/blast_smoke_2", + "explosionoverhaul:blast_wave/smoke/blast_smoke_3", + "explosionoverhaul:blast_wave/smoke/blast_smoke_4", + "explosionoverhaul:blast_wave/smoke/blast_smoke_5", + "explosionoverhaul:blast_wave/smoke/blast_smoke_6", + "explosionoverhaul:blast_wave/smoke/blast_smoke_7", + "explosionoverhaul:blast_wave/smoke/blast_smoke_8" + ] +} diff --git a/src/main/resources/assets/explosionoverhaul/shaders/core/blur.fsh b/src/main/resources/assets/explosionoverhaul/shaders/core/blur.fsh new file mode 100644 index 0000000..4bbd92f --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/shaders/core/blur.fsh @@ -0,0 +1,75 @@ +#version 150 + +uniform sampler2D DiffuseSampler; +uniform vec2 InSize; +uniform vec2 OutSize; +uniform float Intensity; +uniform float Vignette; +uniform float Heartbeat; +uniform float Desaturation; + +in vec2 texCoord; + +out vec4 FragColor; + +const int SAMPLES = 16; +const float CA_strength = 0.02; + +void main() { + // Smoother entry: blend master effect over a wider range (0.0 to 0.25) + float masterAlpha = smoothstep(0.0, 0.25, Intensity); + + if (masterAlpha <= 0.0) { + FragColor = texture(DiffuseSampler, texCoord); + return; + } + + vec2 uv = texCoord; + vec2 center = vec2(0.5, 0.5); + vec2 toCenter = uv - center; + float dist = length(toCenter); + + float distortionStrength = (Intensity * 0.4) + (Heartbeat * 0.1); + + vec3 color = vec3(0.0); + float totalWeight = 0.0; + + float blurBase = (Intensity * 0.05) + (Heartbeat * 0.05); + + for(int i = 0; i < SAMPLES; i++) { + float scale = 1.0 - blurBase * (float(i) / float(SAMPLES - 1)); + + vec2 sampleUV = center + (toCenter * (1.0 - distortionStrength * dist * dist)) * scale; + sampleUV = clamp(sampleUV, 0.0, 1.0); + + float ca_current = (Intensity * CA_strength) + (Heartbeat * 0.02); + float aberration = ca_current * dist * float(i); + + vec2 aberrR = clamp(sampleUV + (toCenter * aberration), 0.0, 1.0); + vec2 aberrB = clamp(sampleUV - (toCenter * aberration), 0.0, 1.0); + + float r = texture(DiffuseSampler, aberrR).r; + float g = texture(DiffuseSampler, sampleUV).g; + float b = texture(DiffuseSampler, aberrB).b; + + color += vec3(r, g, b); + totalWeight += 1.0; + } + + color /= totalWeight; + + float currentVignette = Vignette; + float vigFactor = 1.0 - (dist * currentVignette); + vigFactor = clamp(vigFactor, 0.1, 1.1); + + vec3 processedColor = color * vigFactor; + + float des = clamp(Desaturation, 0.0, 1.0); + if (des > 0.001) { + float lum = dot(processedColor, vec3(0.2126, 0.7152, 0.0722)); + processedColor = mix(processedColor, vec3(lum), des); + } + + vec3 finalColor = mix(texture(DiffuseSampler, texCoord).rgb, processedColor, masterAlpha); + FragColor = vec4(finalColor, 1.0); +} diff --git a/src/main/resources/assets/explosionoverhaul/shaders/core/blur.json b/src/main/resources/assets/explosionoverhaul/shaders/core/blur.json new file mode 100644 index 0000000..3e74a96 --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/shaders/core/blur.json @@ -0,0 +1,16 @@ +{ + "vertex": "explosionoverhaul:blur", + "fragment": "explosionoverhaul:blur", + "attributes": [ "Position", "UV0" ], + "samplers": [ + { "name": "DiffuseSampler" } + ], + "uniforms": [ + { "name": "Intensity", "type": "float", "count": 1, "values": [ 0.0 ] }, + { "name": "InSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, + { "name": "OutSize", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, + { "name": "Heartbeat", "type": "float", "count": 1, "values": [ 0.0 ] }, + { "name": "Vignette", "type": "float", "count": 1, "values": [ 0.0 ] }, + { "name": "Desaturation", "type": "float", "count": 1, "values": [ 0.0 ] } + ] +} diff --git a/src/main/resources/assets/explosionoverhaul/shaders/core/blur.vsh b/src/main/resources/assets/explosionoverhaul/shaders/core/blur.vsh new file mode 100644 index 0000000..c42b6ee --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/shaders/core/blur.vsh @@ -0,0 +1,11 @@ +#version 150 + +in vec3 Position; +in vec2 UV0; + +out vec2 texCoord; + +void main() { + texCoord = UV0; + gl_Position = vec4(Position, 1.0); +} diff --git a/src/main/resources/assets/explosionoverhaul/sounds.json b/src/main/resources/assets/explosionoverhaul/sounds.json new file mode 100644 index 0000000..12bfd60 --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/sounds.json @@ -0,0 +1,1743 @@ +{ + "low": { + "sounds": [ + "explosionoverhaul:low" + ] + }, + "explode_close_power_1_1": { + "sounds": [ + "explosionoverhaul:explode_close_power_1_1" + ] + }, + "explode_close_power_1_2": { + "sounds": [ + "explosionoverhaul:explode_close_power_1_2" + ] + }, + "explode_close_power_1_3": { + "sounds": [ + "explosionoverhaul:explode_close_power_1_3" + ] + }, + "explode_close_power_2_1": { + "sounds": [ + "explosionoverhaul:explode_close_power_2_1" + ] + }, + "explode_close_power_2_2": { + "sounds": [ + "explosionoverhaul:explode_close_power_2_2" + ] + }, + "explode_close_power_2_3": { + "sounds": [ + "explosionoverhaul:explode_close_power_2_3" + ] + }, + "explode_close_power_3_1": { + "sounds": [ + "explosionoverhaul:explode_close_power_3_1" + ] + }, + "explode_close_power_3_2": { + "sounds": [ + "explosionoverhaul:explode_close_power_3_2" + ] + }, + "explode_close_power_3_3": { + "sounds": [ + "explosionoverhaul:explode_close_power_3_3" + ] + }, + "explode_close_power_4_1": { + "sounds": [ + "explosionoverhaul:explode_close_power_4_1" + ] + }, + "explode_close_power_4_2": { + "sounds": [ + "explosionoverhaul:explode_close_power_4_2" + ] + }, + "explode_close_power_4_3": { + "sounds": [ + "explosionoverhaul:explode_close_power_4_3" + ] + }, + "explode_close_power_5_1": { + "sounds": [ + "explosionoverhaul:explode_close_power_5_1" + ] + }, + "explode_close_power_5_2": { + "sounds": [ + "explosionoverhaul:explode_close_power_5_2" + ] + }, + "explode_close_power_5_3": { + "sounds": [ + "explosionoverhaul:explode_close_power_5_3" + ] + }, + "explode_close_power_6_1": { + "sounds": [ + "explosionoverhaul:explode_close_power_6_1" + ] + }, + "explode_close_power_6_2": { + "sounds": [ + "explosionoverhaul:explode_close_power_6_2" + ] + }, + "explode_close_power_6_3": { + "sounds": [ + "explosionoverhaul:explode_close_power_6_3" + ] + }, + "explode_close_power_7_1": { + "sounds": [ + "explosionoverhaul:explode_close_power_7_1" + ] + }, + "explode_close_power_7_2": { + "sounds": [ + "explosionoverhaul:explode_close_power_7_2" + ] + }, + "explode_close_power_7_3": { + "sounds": [ + "explosionoverhaul:explode_close_power_7_3" + ] + }, + "explode_medium_power_1_1": { + "sounds": [ + "explosionoverhaul:explode_medium_power_1_1" + ] + }, + "explode_medium_power_1_2": { + "sounds": [ + "explosionoverhaul:explode_medium_power_1_2" + ] + }, + "explode_medium_power_1_3": { + "sounds": [ + "explosionoverhaul:explode_medium_power_1_3" + ] + }, + "explode_medium_power_2_1": { + "sounds": [ + "explosionoverhaul:explode_medium_power_2_1" + ] + }, + "explode_medium_power_2_2": { + "sounds": [ + "explosionoverhaul:explode_medium_power_2_2" + ] + }, + "explode_medium_power_2_3": { + "sounds": [ + "explosionoverhaul:explode_medium_power_2_3" + ] + }, + "explode_medium_power_3_1": { + "sounds": [ + "explosionoverhaul:explode_medium_power_3_1" + ] + }, + "explode_medium_power_3_2": { + "sounds": [ + "explosionoverhaul:explode_medium_power_3_2" + ] + }, + "explode_medium_power_3_3": { + "sounds": [ + "explosionoverhaul:explode_medium_power_3_3" + ] + }, + "explode_medium_power_4_1": { + "sounds": [ + "explosionoverhaul:explode_medium_power_4_1" + ] + }, + "explode_medium_power_4_2": { + "sounds": [ + "explosionoverhaul:explode_medium_power_4_2" + ] + }, + "explode_medium_power_4_3": { + "sounds": [ + "explosionoverhaul:explode_medium_power_4_3" + ] + }, + "explode_medium_power_5_1": { + "sounds": [ + "explosionoverhaul:explode_medium_power_5_1" + ] + }, + "explode_medium_power_5_2": { + "sounds": [ + "explosionoverhaul:explode_medium_power_5_2" + ] + }, + "explode_medium_power_5_3": { + "sounds": [ + "explosionoverhaul:explode_medium_power_5_3" + ] + }, + "explode_medium_power_6_1": { + "sounds": [ + "explosionoverhaul:explode_medium_power_6_1" + ] + }, + "explode_medium_power_6_2": { + "sounds": [ + "explosionoverhaul:explode_medium_power_6_2" + ] + }, + "explode_medium_power_6_3": { + "sounds": [ + "explosionoverhaul:explode_medium_power_6_3" + ] + }, + "explode_medium_power_7_1": { + "sounds": [ + "explosionoverhaul:explode_medium_power_7_1" + ] + }, + "explode_medium_power_7_2": { + "sounds": [ + "explosionoverhaul:explode_medium_power_7_2" + ] + }, + "explode_medium_power_7_3": { + "sounds": [ + "explosionoverhaul:explode_medium_power_7_3" + ] + }, + "explode_medium_cave_power_1_1": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_1_1" + ] + }, + "explode_medium_cave_power_1_2": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_1_2" + ] + }, + "explode_medium_cave_power_1_3": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_1_3" + ] + }, + "explode_medium_cave_power_2_1": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_2_1" + ] + }, + "explode_medium_cave_power_2_2": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_2_2" + ] + }, + "explode_medium_cave_power_2_3": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_2_3" + ] + }, + "explode_medium_cave_power_3_1": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_3_1" + ] + }, + "explode_medium_cave_power_3_2": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_3_2" + ] + }, + "explode_medium_cave_power_3_3": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_3_3" + ] + }, + "explode_medium_cave_power_4_1": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_4_1" + ] + }, + "explode_medium_cave_power_4_2": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_4_2" + ] + }, + "explode_medium_cave_power_4_3": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_4_3" + ] + }, + "explode_medium_cave_power_5_1": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_5_1" + ] + }, + "explode_medium_cave_power_5_2": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_5_2" + ] + }, + "explode_medium_cave_power_5_3": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_5_3" + ] + }, + "explode_medium_cave_power_6_1": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_6_1" + ] + }, + "explode_medium_cave_power_6_2": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_6_2" + ] + }, + "explode_medium_cave_power_6_3": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_6_3" + ] + }, + "explode_medium_cave_power_7_1": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_7_1" + ] + }, + "explode_medium_cave_power_7_2": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_7_2" + ] + }, + "explode_medium_cave_power_7_3": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_power_7_3" + ] + }, + "explode_medium_to_house_power_1_1": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_1_1" + ] + }, + "explode_medium_to_house_power_1_2": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_1_2" + ] + }, + "explode_medium_to_house_power_1_3": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_1_3" + ] + }, + "explode_medium_to_house_power_2_1": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_2_1" + ] + }, + "explode_medium_to_house_power_2_2": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_2_2" + ] + }, + "explode_medium_to_house_power_2_3": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_2_3" + ] + }, + "explode_medium_to_house_power_3_1": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_3_1" + ] + }, + "explode_medium_to_house_power_3_2": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_3_2" + ] + }, + "explode_medium_to_house_power_3_3": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_3_3" + ] + }, + "explode_medium_to_house_power_4_1": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_4_1" + ] + }, + "explode_medium_to_house_power_4_2": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_4_2" + ] + }, + "explode_medium_to_house_power_4_3": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_4_3" + ] + }, + "explode_medium_to_house_power_5_1": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_5_1" + ] + }, + "explode_medium_to_house_power_5_2": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_5_2" + ] + }, + "explode_medium_to_house_power_5_3": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_5_3" + ] + }, + "explode_medium_to_house_power_6_1": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_6_1" + ] + }, + "explode_medium_to_house_power_6_2": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_6_2" + ] + }, + "explode_medium_to_house_power_6_3": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_6_3" + ] + }, + "explode_medium_to_house_power_7_1": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_7_1" + ] + }, + "explode_medium_to_house_power_7_2": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_7_2" + ] + }, + "explode_medium_to_house_power_7_3": { + "sounds": [ + "explosionoverhaul:explode_medium_to_house_power_7_3" + ] + }, + "explode_medium_underground_power_1_1": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_1_1" + ] + }, + "explode_medium_underground_power_1_2": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_1_2" + ] + }, + "explode_medium_underground_power_1_3": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_1_3" + ] + }, + "explode_medium_underground_power_2_1": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_2_1" + ] + }, + "explode_medium_underground_power_2_2": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_2_2" + ] + }, + "explode_medium_underground_power_2_3": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_2_3" + ] + }, + "explode_medium_underground_power_3_1": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_3_1" + ] + }, + "explode_medium_underground_power_3_2": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_3_2" + ] + }, + "explode_medium_underground_power_3_3": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_3_3" + ] + }, + "explode_medium_underground_power_4_1": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_4_1" + ] + }, + "explode_medium_underground_power_4_2": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_4_2" + ] + }, + "explode_medium_underground_power_4_3": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_4_3" + ] + }, + "explode_medium_underground_power_5_1": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_5_1" + ] + }, + "explode_medium_underground_power_5_2": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_5_2" + ] + }, + "explode_medium_underground_power_5_3": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_5_3" + ] + }, + "explode_medium_underground_power_6_1": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_6_1" + ] + }, + "explode_medium_underground_power_6_2": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_6_2" + ] + }, + "explode_medium_underground_power_6_3": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_6_3" + ] + }, + "explode_medium_underground_power_7_1": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_7_1" + ] + }, + "explode_medium_underground_power_7_2": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_7_2" + ] + }, + "explode_medium_underground_power_7_3": { + "sounds": [ + "explosionoverhaul:explode_medium_underground_power_7_3" + ] + }, + "explode_medium_cave_to_house_power_1_1": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_1_1" + ] + }, + "explode_medium_cave_to_house_power_1_2": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_1_2" + ] + }, + "explode_medium_cave_to_house_power_1_3": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_1_3" + ] + }, + "explode_medium_cave_to_house_power_2_1": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_2_1" + ] + }, + "explode_medium_cave_to_house_power_2_2": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_2_2" + ] + }, + "explode_medium_cave_to_house_power_2_3": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_2_3" + ] + }, + "explode_medium_cave_to_house_power_3_1": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_3_1" + ] + }, + "explode_medium_cave_to_house_power_3_2": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_3_2" + ] + }, + "explode_medium_cave_to_house_power_3_3": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_3_3" + ] + }, + "explode_medium_cave_to_house_power_4_1": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_4_1" + ] + }, + "explode_medium_cave_to_house_power_4_2": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_4_2" + ] + }, + "explode_medium_cave_to_house_power_4_3": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_4_3" + ] + }, + "explode_medium_cave_to_house_power_5_1": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_5_1" + ] + }, + "explode_medium_cave_to_house_power_5_2": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_5_2" + ] + }, + "explode_medium_cave_to_house_power_5_3": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_5_3" + ] + }, + "explode_medium_cave_to_house_power_6_1": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_6_1" + ] + }, + "explode_medium_cave_to_house_power_6_2": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_6_2" + ] + }, + "explode_medium_cave_to_house_power_6_3": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_6_3" + ] + }, + "explode_medium_cave_to_house_power_7_1": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_7_1" + ] + }, + "explode_medium_cave_to_house_power_7_2": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_7_2" + ] + }, + "explode_medium_cave_to_house_power_7_3": { + "sounds": [ + "explosionoverhaul:explode_medium_cave_to_house_power_7_3" + ] + }, + "explode_far_power_1_1": { + "sounds": [ + "explosionoverhaul:explode_far_power_1_1" + ] + }, + "explode_far_power_1_2": { + "sounds": [ + "explosionoverhaul:explode_far_power_1_2" + ] + }, + "explode_far_power_1_3": { + "sounds": [ + "explosionoverhaul:explode_far_power_1_3" + ] + }, + "explode_far_power_2_1": { + "sounds": [ + "explosionoverhaul:explode_far_power_2_1" + ] + }, + "explode_far_power_2_2": { + "sounds": [ + "explosionoverhaul:explode_far_power_2_2" + ] + }, + "explode_far_power_2_3": { + "sounds": [ + "explosionoverhaul:explode_far_power_2_3" + ] + }, + "explode_far_power_3_1": { + "sounds": [ + "explosionoverhaul:explode_far_power_3_1" + ] + }, + "explode_far_power_3_2": { + "sounds": [ + "explosionoverhaul:explode_far_power_3_2" + ] + }, + "explode_far_power_3_3": { + "sounds": [ + "explosionoverhaul:explode_far_power_3_3" + ] + }, + "explode_far_power_4_1": { + "sounds": [ + "explosionoverhaul:explode_far_power_4_1" + ] + }, + "explode_far_power_4_2": { + "sounds": [ + "explosionoverhaul:explode_far_power_4_2" + ] + }, + "explode_far_power_4_3": { + "sounds": [ + "explosionoverhaul:explode_far_power_4_3" + ] + }, + "explode_far_power_5_1": { + "sounds": [ + "explosionoverhaul:explode_far_power_5_1" + ] + }, + "explode_far_power_5_2": { + "sounds": [ + "explosionoverhaul:explode_far_power_5_2" + ] + }, + "explode_far_power_5_3": { + "sounds": [ + "explosionoverhaul:explode_far_power_5_3" + ] + }, + "explode_far_power_6_1": { + "sounds": [ + "explosionoverhaul:explode_far_power_6_1" + ] + }, + "explode_far_power_6_2": { + "sounds": [ + "explosionoverhaul:explode_far_power_6_2" + ] + }, + "explode_far_power_6_3": { + "sounds": [ + "explosionoverhaul:explode_far_power_6_3" + ] + }, + "explode_far_power_7_1": { + "sounds": [ + "explosionoverhaul:explode_far_power_7_1" + ] + }, + "explode_far_power_7_2": { + "sounds": [ + "explosionoverhaul:explode_far_power_7_2" + ] + }, + "explode_far_power_7_3": { + "sounds": [ + "explosionoverhaul:explode_far_power_7_3" + ] + }, + "explode_superfar_power_1_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_1_1" + ] + }, + "explode_superfar_power_1_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_1_2" + ] + }, + "explode_superfar_power_1_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_1_3" + ] + }, + "explode_superfar_power_2_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_2_1" + ] + }, + "explode_superfar_power_2_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_2_2" + ] + }, + "explode_superfar_power_2_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_2_3" + ] + }, + "explode_superfar_power_3_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_3_1" + ] + }, + "explode_superfar_power_3_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_3_2" + ] + }, + "explode_superfar_power_3_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_3_3" + ] + }, + "explode_superfar_power_4_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_4_1" + ] + }, + "explode_superfar_power_4_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_4_2" + ] + }, + "explode_superfar_power_4_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_4_3" + ] + }, + "explode_superfar_power_5_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_5_1" + ] + }, + "explode_superfar_power_5_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_5_2" + ] + }, + "explode_superfar_power_5_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_5_3" + ] + }, + "explode_superfar_power_6_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_6_1" + ] + }, + "explode_superfar_power_6_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_6_2" + ] + }, + "explode_superfar_power_6_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_6_3" + ] + }, + "explode_superfar_power_7_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_7_1" + ] + }, + "explode_superfar_power_7_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_7_2" + ] + }, + "explode_superfar_power_7_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_power_7_3" + ] + }, + "explode_far_cave_power_1_1": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_1_1" + ] + }, + "explode_far_cave_power_1_2": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_1_2" + ] + }, + "explode_far_cave_power_1_3": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_1_3" + ] + }, + "explode_far_cave_power_2_1": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_2_1" + ] + }, + "explode_far_cave_power_2_2": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_2_2" + ] + }, + "explode_far_cave_power_2_3": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_2_3" + ] + }, + "explode_far_cave_power_3_1": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_3_1" + ] + }, + "explode_far_cave_power_3_2": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_3_2" + ] + }, + "explode_far_cave_power_3_3": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_3_3" + ] + }, + "explode_far_cave_power_4_1": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_4_1" + ] + }, + "explode_far_cave_power_4_2": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_4_2" + ] + }, + "explode_far_cave_power_4_3": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_4_3" + ] + }, + "explode_far_cave_power_5_1": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_5_1" + ] + }, + "explode_far_cave_power_5_2": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_5_2" + ] + }, + "explode_far_cave_power_5_3": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_5_3" + ] + }, + "explode_far_cave_power_6_1": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_6_1" + ] + }, + "explode_far_cave_power_6_2": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_6_2" + ] + }, + "explode_far_cave_power_6_3": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_6_3" + ] + }, + "explode_far_cave_power_7_1": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_7_1" + ] + }, + "explode_far_cave_power_7_2": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_7_2" + ] + }, + "explode_far_cave_power_7_3": { + "sounds": [ + "explosionoverhaul:explode_far_cave_power_7_3" + ] + }, + "explode_superfar_cave_power_1_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_1_1" + ] + }, + "explode_superfar_cave_power_1_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_1_2" + ] + }, + "explode_superfar_cave_power_1_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_1_3" + ] + }, + "explode_superfar_cave_power_2_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_2_1" + ] + }, + "explode_superfar_cave_power_2_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_2_2" + ] + }, + "explode_superfar_cave_power_2_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_2_3" + ] + }, + "explode_superfar_cave_power_3_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_3_1" + ] + }, + "explode_superfar_cave_power_3_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_3_2" + ] + }, + "explode_superfar_cave_power_3_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_3_3" + ] + }, + "explode_superfar_cave_power_4_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_4_1" + ] + }, + "explode_superfar_cave_power_4_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_4_2" + ] + }, + "explode_superfar_cave_power_4_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_4_3" + ] + }, + "explode_superfar_cave_power_5_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_5_1" + ] + }, + "explode_superfar_cave_power_5_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_5_2" + ] + }, + "explode_superfar_cave_power_5_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_5_3" + ] + }, + "explode_superfar_cave_power_6_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_6_1" + ] + }, + "explode_superfar_cave_power_6_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_6_2" + ] + }, + "explode_superfar_cave_power_6_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_6_3" + ] + }, + "explode_superfar_cave_power_7_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_7_1" + ] + }, + "explode_superfar_cave_power_7_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_7_2" + ] + }, + "explode_superfar_cave_power_7_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_power_7_3" + ] + }, + "explode_far_to_house_power_1_1": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_1_1" + ] + }, + "explode_far_to_house_power_1_2": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_1_2" + ] + }, + "explode_far_to_house_power_1_3": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_1_3" + ] + }, + "explode_far_to_house_power_2_1": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_2_1" + ] + }, + "explode_far_to_house_power_2_2": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_2_2" + ] + }, + "explode_far_to_house_power_2_3": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_2_3" + ] + }, + "explode_far_to_house_power_3_1": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_3_1" + ] + }, + "explode_far_to_house_power_3_2": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_3_2" + ] + }, + "explode_far_to_house_power_3_3": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_3_3" + ] + }, + "explode_far_to_house_power_4_1": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_4_1" + ] + }, + "explode_far_to_house_power_4_2": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_4_2" + ] + }, + "explode_far_to_house_power_4_3": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_4_3" + ] + }, + "explode_far_to_house_power_5_1": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_5_1" + ] + }, + "explode_far_to_house_power_5_2": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_5_2" + ] + }, + "explode_far_to_house_power_5_3": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_5_3" + ] + }, + "explode_far_to_house_power_6_1": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_6_1" + ] + }, + "explode_far_to_house_power_6_2": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_6_2" + ] + }, + "explode_far_to_house_power_6_3": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_6_3" + ] + }, + "explode_far_to_house_power_7_1": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_7_1" + ] + }, + "explode_far_to_house_power_7_2": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_7_2" + ] + }, + "explode_far_to_house_power_7_3": { + "sounds": [ + "explosionoverhaul:explode_far_to_house_power_7_3" + ] + }, + "explode_far_cave_to_house_power_1_1": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_1_1" + ] + }, + "explode_far_cave_to_house_power_1_2": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_1_2" + ] + }, + "explode_far_cave_to_house_power_1_3": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_1_3" + ] + }, + "explode_far_cave_to_house_power_2_1": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_2_1" + ] + }, + "explode_far_cave_to_house_power_2_2": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_2_2" + ] + }, + "explode_far_cave_to_house_power_2_3": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_2_3" + ] + }, + "explode_far_cave_to_house_power_3_1": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_3_1" + ] + }, + "explode_far_cave_to_house_power_3_2": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_3_2" + ] + }, + "explode_far_cave_to_house_power_3_3": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_3_3" + ] + }, + "explode_far_cave_to_house_power_4_1": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_4_1" + ] + }, + "explode_far_cave_to_house_power_4_2": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_4_2" + ] + }, + "explode_far_cave_to_house_power_4_3": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_4_3" + ] + }, + "explode_far_cave_to_house_power_5_1": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_5_1" + ] + }, + "explode_far_cave_to_house_power_5_2": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_5_2" + ] + }, + "explode_far_cave_to_house_power_5_3": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_5_3" + ] + }, + "explode_far_cave_to_house_power_6_1": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_6_1" + ] + }, + "explode_far_cave_to_house_power_6_2": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_6_2" + ] + }, + "explode_far_cave_to_house_power_6_3": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_6_3" + ] + }, + "explode_far_cave_to_house_power_7_1": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_7_1" + ] + }, + "explode_far_cave_to_house_power_7_2": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_7_2" + ] + }, + "explode_far_cave_to_house_power_7_3": { + "sounds": [ + "explosionoverhaul:explode_far_cave_to_house_power_7_3" + ] + }, + "explode_superfar_to_house_power_1_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_1_1" + ] + }, + "explode_superfar_to_house_power_1_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_1_2" + ] + }, + "explode_superfar_to_house_power_1_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_1_3" + ] + }, + "explode_superfar_to_house_power_2_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_2_1" + ] + }, + "explode_superfar_to_house_power_2_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_2_2" + ] + }, + "explode_superfar_to_house_power_2_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_2_3" + ] + }, + "explode_superfar_to_house_power_3_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_3_1" + ] + }, + "explode_superfar_to_house_power_3_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_3_2" + ] + }, + "explode_superfar_to_house_power_3_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_3_3" + ] + }, + "explode_superfar_to_house_power_4_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_4_1" + ] + }, + "explode_superfar_to_house_power_4_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_4_2" + ] + }, + "explode_superfar_to_house_power_4_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_4_3" + ] + }, + "explode_superfar_to_house_power_5_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_5_1" + ] + }, + "explode_superfar_to_house_power_5_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_5_2" + ] + }, + "explode_superfar_to_house_power_5_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_5_3" + ] + }, + "explode_superfar_to_house_power_6_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_6_1" + ] + }, + "explode_superfar_to_house_power_6_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_6_2" + ] + }, + "explode_superfar_to_house_power_6_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_6_3" + ] + }, + "explode_superfar_to_house_power_7_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_7_1" + ] + }, + "explode_superfar_to_house_power_7_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_7_2" + ] + }, + "explode_superfar_to_house_power_7_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_to_house_power_7_3" + ] + }, + "explode_superfar_cave_to_house_power_1_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_1_1" + ] + }, + "explode_superfar_cave_to_house_power_1_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_1_2" + ] + }, + "explode_superfar_cave_to_house_power_1_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_1_3" + ] + }, + "explode_superfar_cave_to_house_power_2_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_2_1" + ] + }, + "explode_superfar_cave_to_house_power_2_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_2_2" + ] + }, + "explode_superfar_cave_to_house_power_2_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_2_3" + ] + }, + "explode_superfar_cave_to_house_power_3_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_3_1" + ] + }, + "explode_superfar_cave_to_house_power_3_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_3_2" + ] + }, + "explode_superfar_cave_to_house_power_3_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_3_3" + ] + }, + "explode_superfar_cave_to_house_power_4_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_4_1" + ] + }, + "explode_superfar_cave_to_house_power_4_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_4_2" + ] + }, + "explode_superfar_cave_to_house_power_4_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_4_3" + ] + }, + "explode_superfar_cave_to_house_power_5_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_5_1" + ] + }, + "explode_superfar_cave_to_house_power_5_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_5_2" + ] + }, + "explode_superfar_cave_to_house_power_5_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_5_3" + ] + }, + "explode_superfar_cave_to_house_power_6_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_6_1" + ] + }, + "explode_superfar_cave_to_house_power_6_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_6_2" + ] + }, + "explode_superfar_cave_to_house_power_6_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_6_3" + ] + }, + "explode_superfar_cave_to_house_power_7_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_7_1" + ] + }, + "explode_superfar_cave_to_house_power_7_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_7_2" + ] + }, + "explode_superfar_cave_to_house_power_7_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_cave_to_house_power_7_3" + ] + }, + "explode_far_underground_power_1_1": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_1_1" + ] + }, + "explode_far_underground_power_1_2": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_1_2" + ] + }, + "explode_far_underground_power_1_3": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_1_3" + ] + }, + "explode_far_underground_power_2_1": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_2_1" + ] + }, + "explode_far_underground_power_2_2": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_2_2" + ] + }, + "explode_far_underground_power_2_3": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_2_3" + ] + }, + "explode_far_underground_power_3_1": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_3_1" + ] + }, + "explode_far_underground_power_3_2": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_3_2" + ] + }, + "explode_far_underground_power_3_3": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_3_3" + ] + }, + "explode_far_underground_power_4_1": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_4_1" + ] + }, + "explode_far_underground_power_4_2": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_4_2" + ] + }, + "explode_far_underground_power_4_3": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_4_3" + ] + }, + "explode_far_underground_power_5_1": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_5_1" + ] + }, + "explode_far_underground_power_5_2": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_5_2" + ] + }, + "explode_far_underground_power_5_3": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_5_3" + ] + }, + "explode_far_underground_power_6_1": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_6_1" + ] + }, + "explode_far_underground_power_6_2": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_6_2" + ] + }, + "explode_far_underground_power_6_3": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_6_3" + ] + }, + "explode_far_underground_power_7_1": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_7_1" + ] + }, + "explode_far_underground_power_7_2": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_7_2" + ] + }, + "explode_far_underground_power_7_3": { + "sounds": [ + "explosionoverhaul:explode_far_underground_power_7_3" + ] + }, + "explode_superfar_underground_power_1_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_1_1" + ] + }, + "explode_superfar_underground_power_1_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_1_2" + ] + }, + "explode_superfar_underground_power_1_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_1_3" + ] + }, + "explode_superfar_underground_power_2_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_2_1" + ] + }, + "explode_superfar_underground_power_2_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_2_2" + ] + }, + "explode_superfar_underground_power_2_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_2_3" + ] + }, + "explode_superfar_underground_power_3_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_3_1" + ] + }, + "explode_superfar_underground_power_3_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_3_2" + ] + }, + "explode_superfar_underground_power_3_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_3_3" + ] + }, + "explode_superfar_underground_power_4_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_4_1" + ] + }, + "explode_superfar_underground_power_4_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_4_2" + ] + }, + "explode_superfar_underground_power_4_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_4_3" + ] + }, + "explode_superfar_underground_power_5_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_5_1" + ] + }, + "explode_superfar_underground_power_5_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_5_2" + ] + }, + "explode_superfar_underground_power_5_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_5_3" + ] + }, + "explode_superfar_underground_power_6_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_6_1" + ] + }, + "explode_superfar_underground_power_6_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_6_2" + ] + }, + "explode_superfar_underground_power_6_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_6_3" + ] + }, + "explode_superfar_underground_power_7_1": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_7_1" + ] + }, + "explode_superfar_underground_power_7_2": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_7_2" + ] + }, + "explode_superfar_underground_power_7_3": { + "sounds": [ + "explosionoverhaul:explode_superfar_underground_power_7_3" + ] + }, + "dust": { + "sounds": [ + "explosionoverhaul:dust" + ] + }, + "falling_stones": { + "sounds": [ + "explosionoverhaul:falling_stones" + ] + }, + "lamp_flicker_spark_1": { + "sounds": [ + "explosionoverhaul:lamp_flicker_spark_1" + ] + }, + "lamp_flicker_spark_2": { + "sounds": [ + "explosionoverhaul:lamp_flicker_spark_2" + ] + }, + "lamp_flicker_spark_3": { + "sounds": [ + "explosionoverhaul:lamp_flicker_spark_3" + ] + }, + "intro_music": { + "sounds": [ + "explosionoverhaul:music" + ] + }, + "intro_boom": { + "sounds": [ + "explosionoverhaul:boom" + ] + }, + + "intro_boom_2": { + "sounds": [ + "explosionoverhaul:boom_2" + ] + }, + "button_sound": { + "sounds": [ + "explosionoverhaul:button_sound" + ] + }, + "lab": { + "sounds": [ + "explosionoverhaul:lab" + ] + }, + "dab": { + "sounds": [ + "explosionoverhaul:dab" + ] + } +} diff --git a/src/main/resources/assets/explosionoverhaul/sounds/boom.ogg b/src/main/resources/assets/explosionoverhaul/sounds/boom.ogg new file mode 100644 index 0000000..2256248 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/boom.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/boom_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/boom_2.ogg new file mode 100644 index 0000000..851313f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/boom_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/button_sound.ogg b/src/main/resources/assets/explosionoverhaul/sounds/button_sound.ogg new file mode 100644 index 0000000..ce41b61 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/button_sound.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/dab.ogg b/src/main/resources/assets/explosionoverhaul/sounds/dab.ogg new file mode 100644 index 0000000..284ce3b Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/dab.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/desktop.ini b/src/main/resources/assets/explosionoverhaul/sounds/desktop.ini new file mode 100644 index 0000000..d957fd1 --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/sounds/desktop.ini @@ -0,0 +1,4 @@ +[ViewState] +Mode= +Vid= +FolderType=Generic diff --git a/src/main/resources/assets/explosionoverhaul/sounds/dust.ogg b/src/main/resources/assets/explosionoverhaul/sounds/dust.ogg new file mode 100644 index 0000000..731412a Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/dust.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_1_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_1_1.ogg new file mode 100644 index 0000000..dac9ad7 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_1_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_1_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_1_2.ogg new file mode 100644 index 0000000..a141c65 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_1_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_1_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_1_3.ogg new file mode 100644 index 0000000..1d378eb Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_1_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_2_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_2_1.ogg new file mode 100644 index 0000000..4e6b708 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_2_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_2_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_2_2.ogg new file mode 100644 index 0000000..0600669 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_2_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_2_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_2_3.ogg new file mode 100644 index 0000000..1ec78bd Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_2_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_3_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_3_1.ogg new file mode 100644 index 0000000..cf009c5 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_3_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_3_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_3_2.ogg new file mode 100644 index 0000000..4514833 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_3_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_3_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_3_3.ogg new file mode 100644 index 0000000..9a5948b Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_3_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_4_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_4_1.ogg new file mode 100644 index 0000000..bb14b57 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_4_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_4_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_4_2.ogg new file mode 100644 index 0000000..7ca9239 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_4_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_4_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_4_3.ogg new file mode 100644 index 0000000..f420944 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_4_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_5_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_5_1.ogg new file mode 100644 index 0000000..b31f291 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_5_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_5_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_5_2.ogg new file mode 100644 index 0000000..eb2c26e Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_5_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_5_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_5_3.ogg new file mode 100644 index 0000000..0f50b4e Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_5_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_6_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_6_1.ogg new file mode 100644 index 0000000..73180b9 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_6_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_6_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_6_2.ogg new file mode 100644 index 0000000..7527031 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_6_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_6_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_6_3.ogg new file mode 100644 index 0000000..cbcafaa Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_6_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_7_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_7_1.ogg new file mode 100644 index 0000000..b0da894 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_7_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_7_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_7_2.ogg new file mode 100644 index 0000000..979934d Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_7_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_7_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_7_3.ogg new file mode 100644 index 0000000..71ccf0d Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_close_power_7_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_1_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_1_1.ogg new file mode 100644 index 0000000..fdef559 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_1_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_1_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_1_2.ogg new file mode 100644 index 0000000..ec9e68f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_1_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_1_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_1_3.ogg new file mode 100644 index 0000000..448a154 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_1_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_2_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_2_1.ogg new file mode 100644 index 0000000..e2701e8 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_2_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_2_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_2_2.ogg new file mode 100644 index 0000000..2ee8040 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_2_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_2_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_2_3.ogg new file mode 100644 index 0000000..3c43bc9 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_2_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_3_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_3_1.ogg new file mode 100644 index 0000000..454a1d3 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_3_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_3_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_3_2.ogg new file mode 100644 index 0000000..fa9e931 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_3_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_3_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_3_3.ogg new file mode 100644 index 0000000..cc304b9 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_3_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_4_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_4_1.ogg new file mode 100644 index 0000000..7d43d34 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_4_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_4_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_4_2.ogg new file mode 100644 index 0000000..904fcb9 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_4_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_4_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_4_3.ogg new file mode 100644 index 0000000..c502945 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_4_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_5_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_5_1.ogg new file mode 100644 index 0000000..c9a03c9 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_5_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_5_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_5_2.ogg new file mode 100644 index 0000000..52a64f6 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_5_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_5_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_5_3.ogg new file mode 100644 index 0000000..282a951 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_5_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_6_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_6_1.ogg new file mode 100644 index 0000000..a73350b Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_6_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_6_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_6_2.ogg new file mode 100644 index 0000000..15fecc5 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_6_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_6_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_6_3.ogg new file mode 100644 index 0000000..eeb8863 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_6_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_7_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_7_1.ogg new file mode 100644 index 0000000..3f00a68 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_7_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_7_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_7_2.ogg new file mode 100644 index 0000000..55e293f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_7_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_7_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_7_3.ogg new file mode 100644 index 0000000..200b98f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_power_7_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_1_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_1_1.ogg new file mode 100644 index 0000000..79c4750 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_1_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_1_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_1_2.ogg new file mode 100644 index 0000000..98e697d Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_1_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_1_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_1_3.ogg new file mode 100644 index 0000000..4dcdabb Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_1_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_2_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_2_1.ogg new file mode 100644 index 0000000..9bcc565 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_2_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_2_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_2_2.ogg new file mode 100644 index 0000000..6f41386 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_2_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_2_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_2_3.ogg new file mode 100644 index 0000000..314250b Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_2_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_3_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_3_1.ogg new file mode 100644 index 0000000..c0b3c68 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_3_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_3_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_3_2.ogg new file mode 100644 index 0000000..c66306e Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_3_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_3_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_3_3.ogg new file mode 100644 index 0000000..5d2cdb1 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_3_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_4_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_4_1.ogg new file mode 100644 index 0000000..a5efd61 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_4_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_4_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_4_2.ogg new file mode 100644 index 0000000..2795b00 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_4_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_4_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_4_3.ogg new file mode 100644 index 0000000..7c3cba1 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_4_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_5_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_5_1.ogg new file mode 100644 index 0000000..5d6c54c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_5_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_5_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_5_2.ogg new file mode 100644 index 0000000..6660202 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_5_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_5_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_5_3.ogg new file mode 100644 index 0000000..e236584 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_5_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_6_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_6_1.ogg new file mode 100644 index 0000000..6f891be Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_6_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_6_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_6_2.ogg new file mode 100644 index 0000000..f6639e9 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_6_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_6_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_6_3.ogg new file mode 100644 index 0000000..0a23ad4 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_6_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_7_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_7_1.ogg new file mode 100644 index 0000000..7ca2bb5 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_7_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_7_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_7_2.ogg new file mode 100644 index 0000000..0bc1ac7 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_7_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_7_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_7_3.ogg new file mode 100644 index 0000000..1579b0f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_cave_to_house_power_7_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_1_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_1_1.ogg new file mode 100644 index 0000000..30cb4a2 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_1_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_1_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_1_2.ogg new file mode 100644 index 0000000..e965a26 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_1_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_1_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_1_3.ogg new file mode 100644 index 0000000..18d5de1 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_1_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_2_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_2_1.ogg new file mode 100644 index 0000000..4d71a9a Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_2_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_2_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_2_2.ogg new file mode 100644 index 0000000..32f47b0 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_2_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_2_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_2_3.ogg new file mode 100644 index 0000000..ab076a2 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_2_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_3_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_3_1.ogg new file mode 100644 index 0000000..83875a5 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_3_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_3_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_3_2.ogg new file mode 100644 index 0000000..d4ad49f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_3_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_3_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_3_3.ogg new file mode 100644 index 0000000..d1d17e9 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_3_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_4_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_4_1.ogg new file mode 100644 index 0000000..8093453 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_4_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_4_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_4_2.ogg new file mode 100644 index 0000000..fac81f1 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_4_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_4_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_4_3.ogg new file mode 100644 index 0000000..33817bc Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_4_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_5_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_5_1.ogg new file mode 100644 index 0000000..ec702a7 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_5_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_5_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_5_2.ogg new file mode 100644 index 0000000..b7f2be4 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_5_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_5_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_5_3.ogg new file mode 100644 index 0000000..d13760f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_5_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_6_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_6_1.ogg new file mode 100644 index 0000000..dbac50a Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_6_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_6_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_6_2.ogg new file mode 100644 index 0000000..93d5512 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_6_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_6_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_6_3.ogg new file mode 100644 index 0000000..b3da10b Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_6_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_7_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_7_1.ogg new file mode 100644 index 0000000..fc8c3cd Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_7_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_7_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_7_2.ogg new file mode 100644 index 0000000..d964ad4 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_7_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_7_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_7_3.ogg new file mode 100644 index 0000000..2d49fb4 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_power_7_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_1_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_1_1.ogg new file mode 100644 index 0000000..3b91cfe Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_1_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_1_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_1_2.ogg new file mode 100644 index 0000000..6f248cd Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_1_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_1_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_1_3.ogg new file mode 100644 index 0000000..c85c265 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_1_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_2_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_2_1.ogg new file mode 100644 index 0000000..95c0ebb Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_2_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_2_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_2_2.ogg new file mode 100644 index 0000000..b9d19f0 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_2_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_2_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_2_3.ogg new file mode 100644 index 0000000..636e210 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_2_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_3_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_3_1.ogg new file mode 100644 index 0000000..4c6d5ed Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_3_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_3_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_3_2.ogg new file mode 100644 index 0000000..8059628 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_3_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_3_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_3_3.ogg new file mode 100644 index 0000000..e3d7aea Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_3_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_4_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_4_1.ogg new file mode 100644 index 0000000..c9cea9d Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_4_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_4_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_4_2.ogg new file mode 100644 index 0000000..f6ed73c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_4_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_4_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_4_3.ogg new file mode 100644 index 0000000..f3463ac Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_4_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_5_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_5_1.ogg new file mode 100644 index 0000000..deb7bb8 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_5_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_5_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_5_2.ogg new file mode 100644 index 0000000..d9e90ea Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_5_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_5_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_5_3.ogg new file mode 100644 index 0000000..8c1b732 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_5_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_6_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_6_1.ogg new file mode 100644 index 0000000..12b2499 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_6_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_6_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_6_2.ogg new file mode 100644 index 0000000..0c17f65 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_6_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_6_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_6_3.ogg new file mode 100644 index 0000000..1581e83 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_6_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_7_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_7_1.ogg new file mode 100644 index 0000000..fbe0e74 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_7_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_7_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_7_2.ogg new file mode 100644 index 0000000..b677c93 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_7_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_7_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_7_3.ogg new file mode 100644 index 0000000..2ebf062 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_to_house_power_7_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_1_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_1_1.ogg new file mode 100644 index 0000000..3501482 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_1_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_1_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_1_2.ogg new file mode 100644 index 0000000..3501482 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_1_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_1_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_1_3.ogg new file mode 100644 index 0000000..3501482 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_1_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_2_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_2_1.ogg new file mode 100644 index 0000000..3501482 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_2_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_2_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_2_2.ogg new file mode 100644 index 0000000..3501482 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_2_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_2_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_2_3.ogg new file mode 100644 index 0000000..46bff72 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_2_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_3_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_3_1.ogg new file mode 100644 index 0000000..3501482 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_3_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_3_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_3_2.ogg new file mode 100644 index 0000000..3501482 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_3_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_3_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_3_3.ogg new file mode 100644 index 0000000..46bff72 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_3_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_4_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_4_1.ogg new file mode 100644 index 0000000..3501482 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_4_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_4_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_4_2.ogg new file mode 100644 index 0000000..3501482 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_4_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_4_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_4_3.ogg new file mode 100644 index 0000000..46bff72 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_4_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_5_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_5_1.ogg new file mode 100644 index 0000000..3501482 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_5_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_5_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_5_2.ogg new file mode 100644 index 0000000..3501482 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_5_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_5_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_5_3.ogg new file mode 100644 index 0000000..46bff72 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_5_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_6_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_6_1.ogg new file mode 100644 index 0000000..3411b02 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_6_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_6_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_6_2.ogg new file mode 100644 index 0000000..afc89d9 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_6_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_6_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_6_3.ogg new file mode 100644 index 0000000..98c4b98 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_6_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_7_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_7_1.ogg new file mode 100644 index 0000000..c9d214b Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_7_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_7_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_7_2.ogg new file mode 100644 index 0000000..e1a80f9 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_7_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_7_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_7_3.ogg new file mode 100644 index 0000000..a927d60 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_far_underground_power_7_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_1_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_1_1.ogg new file mode 100644 index 0000000..dee4781 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_1_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_1_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_1_2.ogg new file mode 100644 index 0000000..b48caff Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_1_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_1_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_1_3.ogg new file mode 100644 index 0000000..5236686 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_1_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_2_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_2_1.ogg new file mode 100644 index 0000000..f2329ef Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_2_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_2_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_2_2.ogg new file mode 100644 index 0000000..7880d29 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_2_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_2_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_2_3.ogg new file mode 100644 index 0000000..905beea Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_2_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_3_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_3_1.ogg new file mode 100644 index 0000000..07e1c37 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_3_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_3_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_3_2.ogg new file mode 100644 index 0000000..ea1ec00 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_3_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_3_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_3_3.ogg new file mode 100644 index 0000000..ec3269d Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_3_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_4_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_4_1.ogg new file mode 100644 index 0000000..69235a3 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_4_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_4_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_4_2.ogg new file mode 100644 index 0000000..2985c99 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_4_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_4_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_4_3.ogg new file mode 100644 index 0000000..8327eb8 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_4_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_5_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_5_1.ogg new file mode 100644 index 0000000..6e96871 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_5_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_5_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_5_2.ogg new file mode 100644 index 0000000..bf0dadc Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_5_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_5_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_5_3.ogg new file mode 100644 index 0000000..7e087f1 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_5_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_6_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_6_1.ogg new file mode 100644 index 0000000..41af930 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_6_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_6_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_6_2.ogg new file mode 100644 index 0000000..831e8c0 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_6_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_6_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_6_3.ogg new file mode 100644 index 0000000..dd3c84c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_6_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_7_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_7_1.ogg new file mode 100644 index 0000000..4671728 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_7_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_7_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_7_2.ogg new file mode 100644 index 0000000..661ae4f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_7_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_7_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_7_3.ogg new file mode 100644 index 0000000..1fc68c2 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_power_7_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_1_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_1_1.ogg new file mode 100644 index 0000000..19af191 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_1_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_1_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_1_2.ogg new file mode 100644 index 0000000..46e3340 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_1_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_1_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_1_3.ogg new file mode 100644 index 0000000..a64ad8c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_1_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_2_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_2_1.ogg new file mode 100644 index 0000000..3b849a8 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_2_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_2_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_2_2.ogg new file mode 100644 index 0000000..e55519f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_2_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_2_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_2_3.ogg new file mode 100644 index 0000000..276a3d1 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_2_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_3_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_3_1.ogg new file mode 100644 index 0000000..a431de3 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_3_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_3_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_3_2.ogg new file mode 100644 index 0000000..13c499a Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_3_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_3_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_3_3.ogg new file mode 100644 index 0000000..35427a9 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_3_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_4_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_4_1.ogg new file mode 100644 index 0000000..904adc2 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_4_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_4_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_4_2.ogg new file mode 100644 index 0000000..4cafc24 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_4_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_4_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_4_3.ogg new file mode 100644 index 0000000..7c20911 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_4_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_5_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_5_1.ogg new file mode 100644 index 0000000..6dc40f7 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_5_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_5_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_5_2.ogg new file mode 100644 index 0000000..9299a6c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_5_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_5_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_5_3.ogg new file mode 100644 index 0000000..ccd3b14 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_5_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_6_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_6_1.ogg new file mode 100644 index 0000000..5d399e1 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_6_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_6_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_6_2.ogg new file mode 100644 index 0000000..b933599 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_6_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_6_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_6_3.ogg new file mode 100644 index 0000000..8828b5a Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_6_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_7_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_7_1.ogg new file mode 100644 index 0000000..22838e9 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_7_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_7_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_7_2.ogg new file mode 100644 index 0000000..e49e6b2 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_7_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_7_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_7_3.ogg new file mode 100644 index 0000000..2a6d188 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_cave_to_house_power_7_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_1_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_1_1.ogg new file mode 100644 index 0000000..13e1a65 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_1_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_1_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_1_2.ogg new file mode 100644 index 0000000..396010e Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_1_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_1_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_1_3.ogg new file mode 100644 index 0000000..493218d Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_1_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_2_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_2_1.ogg new file mode 100644 index 0000000..1a00fa7 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_2_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_2_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_2_2.ogg new file mode 100644 index 0000000..fbfab6b Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_2_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_2_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_2_3.ogg new file mode 100644 index 0000000..0b33de5 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_2_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_3_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_3_1.ogg new file mode 100644 index 0000000..7fb525e Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_3_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_3_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_3_2.ogg new file mode 100644 index 0000000..7639a36 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_3_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_3_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_3_3.ogg new file mode 100644 index 0000000..1f14784 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_3_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_4_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_4_1.ogg new file mode 100644 index 0000000..b2b3f5d Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_4_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_4_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_4_2.ogg new file mode 100644 index 0000000..78c6acf Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_4_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_4_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_4_3.ogg new file mode 100644 index 0000000..58afee1 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_4_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_5_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_5_1.ogg new file mode 100644 index 0000000..e42ac3c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_5_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_5_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_5_2.ogg new file mode 100644 index 0000000..1f88cdb Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_5_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_5_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_5_3.ogg new file mode 100644 index 0000000..bbabd36 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_5_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_6_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_6_1.ogg new file mode 100644 index 0000000..f8de54e Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_6_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_6_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_6_2.ogg new file mode 100644 index 0000000..38478c2 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_6_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_6_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_6_3.ogg new file mode 100644 index 0000000..2245275 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_6_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_7_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_7_1.ogg new file mode 100644 index 0000000..176143c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_7_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_7_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_7_2.ogg new file mode 100644 index 0000000..3a4a655 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_7_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_7_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_7_3.ogg new file mode 100644 index 0000000..c5aff2d Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_power_7_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_1_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_1_1.ogg new file mode 100644 index 0000000..aee0c82 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_1_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_1_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_1_2.ogg new file mode 100644 index 0000000..a03ba9a Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_1_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_1_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_1_3.ogg new file mode 100644 index 0000000..fbf075f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_1_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_2_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_2_1.ogg new file mode 100644 index 0000000..112d560 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_2_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_2_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_2_2.ogg new file mode 100644 index 0000000..761fdd3 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_2_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_2_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_2_3.ogg new file mode 100644 index 0000000..6d09f02 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_2_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_3_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_3_1.ogg new file mode 100644 index 0000000..d59d97d Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_3_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_3_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_3_2.ogg new file mode 100644 index 0000000..46e426a Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_3_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_3_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_3_3.ogg new file mode 100644 index 0000000..72dd5e5 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_3_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_4_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_4_1.ogg new file mode 100644 index 0000000..b9aefd9 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_4_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_4_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_4_2.ogg new file mode 100644 index 0000000..712894c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_4_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_4_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_4_3.ogg new file mode 100644 index 0000000..e578cc8 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_4_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_5_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_5_1.ogg new file mode 100644 index 0000000..2a0d6ee Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_5_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_5_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_5_2.ogg new file mode 100644 index 0000000..6bdbab2 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_5_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_5_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_5_3.ogg new file mode 100644 index 0000000..c2442b8 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_5_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_6_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_6_1.ogg new file mode 100644 index 0000000..aa88497 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_6_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_6_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_6_2.ogg new file mode 100644 index 0000000..52c985d Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_6_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_6_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_6_3.ogg new file mode 100644 index 0000000..ffb464e Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_6_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_7_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_7_1.ogg new file mode 100644 index 0000000..cb14f2f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_7_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_7_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_7_2.ogg new file mode 100644 index 0000000..c2cf161 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_7_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_7_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_7_3.ogg new file mode 100644 index 0000000..c020651 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_to_house_power_7_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_1_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_1_1.ogg new file mode 100644 index 0000000..3bce31e Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_1_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_1_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_1_2.ogg new file mode 100644 index 0000000..3bce31e Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_1_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_1_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_1_3.ogg new file mode 100644 index 0000000..0c28c05 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_1_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_2_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_2_1.ogg new file mode 100644 index 0000000..0c28c05 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_2_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_2_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_2_2.ogg new file mode 100644 index 0000000..0c28c05 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_2_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_2_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_2_3.ogg new file mode 100644 index 0000000..0c28c05 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_2_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_3_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_3_1.ogg new file mode 100644 index 0000000..0c28c05 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_3_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_3_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_3_2.ogg new file mode 100644 index 0000000..fc59cbf Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_3_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_3_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_3_3.ogg new file mode 100644 index 0000000..fc59cbf Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_3_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_4_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_4_1.ogg new file mode 100644 index 0000000..fc59cbf Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_4_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_4_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_4_2.ogg new file mode 100644 index 0000000..fc59cbf Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_4_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_4_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_4_3.ogg new file mode 100644 index 0000000..fc59cbf Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_4_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_5_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_5_1.ogg new file mode 100644 index 0000000..f323c1e Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_5_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_5_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_5_2.ogg new file mode 100644 index 0000000..320a56d Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_5_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_5_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_5_3.ogg new file mode 100644 index 0000000..1b0f5c1 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_5_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_6_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_6_1.ogg new file mode 100644 index 0000000..db12abf Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_6_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_6_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_6_2.ogg new file mode 100644 index 0000000..3967221 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_6_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_6_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_6_3.ogg new file mode 100644 index 0000000..e15d174 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_6_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_7_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_7_1.ogg new file mode 100644 index 0000000..c3a10f8 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_7_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_7_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_7_2.ogg new file mode 100644 index 0000000..902c569 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_7_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_7_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_7_3.ogg new file mode 100644 index 0000000..e1b9ea5 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_medium_underground_power_7_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_1_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_1_1.ogg new file mode 100644 index 0000000..38f088c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_1_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_1_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_1_2.ogg new file mode 100644 index 0000000..590c173 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_1_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_1_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_1_3.ogg new file mode 100644 index 0000000..986473f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_1_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_2_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_2_1.ogg new file mode 100644 index 0000000..81e1442 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_2_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_2_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_2_2.ogg new file mode 100644 index 0000000..e515e1d Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_2_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_2_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_2_3.ogg new file mode 100644 index 0000000..b5e7026 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_2_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_3_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_3_1.ogg new file mode 100644 index 0000000..ae4dc77 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_3_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_3_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_3_2.ogg new file mode 100644 index 0000000..cc52a3c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_3_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_3_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_3_3.ogg new file mode 100644 index 0000000..89a0cea Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_3_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_4_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_4_1.ogg new file mode 100644 index 0000000..ce362f9 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_4_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_4_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_4_2.ogg new file mode 100644 index 0000000..2ffcbf0 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_4_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_4_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_4_3.ogg new file mode 100644 index 0000000..1692a71 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_4_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_5_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_5_1.ogg new file mode 100644 index 0000000..785c48c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_5_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_5_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_5_2.ogg new file mode 100644 index 0000000..01bca1c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_5_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_5_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_5_3.ogg new file mode 100644 index 0000000..2d50fa3 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_5_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_6_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_6_1.ogg new file mode 100644 index 0000000..a9a3a02 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_6_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_6_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_6_2.ogg new file mode 100644 index 0000000..e92e65d Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_6_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_6_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_6_3.ogg new file mode 100644 index 0000000..001b0bf Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_6_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_7_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_7_1.ogg new file mode 100644 index 0000000..7364408 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_7_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_7_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_7_2.ogg new file mode 100644 index 0000000..683b29c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_7_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_7_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_7_3.ogg new file mode 100644 index 0000000..e0ff630 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_power_7_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_1_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_1_1.ogg new file mode 100644 index 0000000..d1f8765 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_1_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_1_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_1_2.ogg new file mode 100644 index 0000000..28013fb Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_1_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_1_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_1_3.ogg new file mode 100644 index 0000000..e376029 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_1_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_2_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_2_1.ogg new file mode 100644 index 0000000..982a45e Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_2_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_2_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_2_2.ogg new file mode 100644 index 0000000..4f7a26c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_2_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_2_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_2_3.ogg new file mode 100644 index 0000000..70b18e1 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_2_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_3_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_3_1.ogg new file mode 100644 index 0000000..792fdc1 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_3_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_3_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_3_2.ogg new file mode 100644 index 0000000..8cb208d Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_3_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_3_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_3_3.ogg new file mode 100644 index 0000000..c7ea673 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_3_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_4_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_4_1.ogg new file mode 100644 index 0000000..911ea23 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_4_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_4_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_4_2.ogg new file mode 100644 index 0000000..0d952c4 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_4_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_4_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_4_3.ogg new file mode 100644 index 0000000..1d2f3b8 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_4_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_5_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_5_1.ogg new file mode 100644 index 0000000..59331d7 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_5_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_5_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_5_2.ogg new file mode 100644 index 0000000..d73b5bd Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_5_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_5_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_5_3.ogg new file mode 100644 index 0000000..a3968d2 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_5_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_6_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_6_1.ogg new file mode 100644 index 0000000..d9c54fa Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_6_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_6_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_6_2.ogg new file mode 100644 index 0000000..7b08173 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_6_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_6_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_6_3.ogg new file mode 100644 index 0000000..111ea06 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_6_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_7_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_7_1.ogg new file mode 100644 index 0000000..183c29a Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_7_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_7_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_7_2.ogg new file mode 100644 index 0000000..2aa7170 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_7_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_7_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_7_3.ogg new file mode 100644 index 0000000..90cd950 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_cave_to_house_power_7_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_1_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_1_1.ogg new file mode 100644 index 0000000..fa82555 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_1_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_1_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_1_2.ogg new file mode 100644 index 0000000..6efb688 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_1_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_1_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_1_3.ogg new file mode 100644 index 0000000..a3d1b1c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_1_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_2_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_2_1.ogg new file mode 100644 index 0000000..b997366 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_2_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_2_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_2_2.ogg new file mode 100644 index 0000000..dd7937e Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_2_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_2_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_2_3.ogg new file mode 100644 index 0000000..3d9b8a8 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_2_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_3_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_3_1.ogg new file mode 100644 index 0000000..ddec4ae Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_3_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_3_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_3_2.ogg new file mode 100644 index 0000000..ea5a10b Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_3_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_3_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_3_3.ogg new file mode 100644 index 0000000..a4098b4 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_3_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_4_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_4_1.ogg new file mode 100644 index 0000000..2314252 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_4_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_4_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_4_2.ogg new file mode 100644 index 0000000..dd5ec71 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_4_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_4_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_4_3.ogg new file mode 100644 index 0000000..1408ce3 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_4_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_5_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_5_1.ogg new file mode 100644 index 0000000..51d17f7 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_5_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_5_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_5_2.ogg new file mode 100644 index 0000000..4c3348c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_5_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_5_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_5_3.ogg new file mode 100644 index 0000000..3a951b5 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_5_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_6_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_6_1.ogg new file mode 100644 index 0000000..d44ea17 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_6_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_6_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_6_2.ogg new file mode 100644 index 0000000..e21aff1 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_6_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_6_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_6_3.ogg new file mode 100644 index 0000000..930cce1 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_6_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_7_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_7_1.ogg new file mode 100644 index 0000000..3c444fd Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_7_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_7_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_7_2.ogg new file mode 100644 index 0000000..861e85d Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_7_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_7_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_7_3.ogg new file mode 100644 index 0000000..9ec26dc Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_power_7_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_1_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_1_1.ogg new file mode 100644 index 0000000..36130be Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_1_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_1_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_1_2.ogg new file mode 100644 index 0000000..ad861f6 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_1_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_1_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_1_3.ogg new file mode 100644 index 0000000..2ca20ca Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_1_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_2_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_2_1.ogg new file mode 100644 index 0000000..4425bf6 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_2_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_2_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_2_2.ogg new file mode 100644 index 0000000..e01b1d4 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_2_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_2_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_2_3.ogg new file mode 100644 index 0000000..4ec673e Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_2_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_3_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_3_1.ogg new file mode 100644 index 0000000..cb86205 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_3_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_3_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_3_2.ogg new file mode 100644 index 0000000..306cfd2 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_3_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_3_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_3_3.ogg new file mode 100644 index 0000000..88c8745 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_3_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_4_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_4_1.ogg new file mode 100644 index 0000000..68d0a97 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_4_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_4_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_4_2.ogg new file mode 100644 index 0000000..0a67f43 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_4_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_4_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_4_3.ogg new file mode 100644 index 0000000..48e4590 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_4_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_5_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_5_1.ogg new file mode 100644 index 0000000..4fee031 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_5_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_5_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_5_2.ogg new file mode 100644 index 0000000..0462fa3 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_5_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_5_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_5_3.ogg new file mode 100644 index 0000000..c12ef45 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_5_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_6_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_6_1.ogg new file mode 100644 index 0000000..9982310 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_6_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_6_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_6_2.ogg new file mode 100644 index 0000000..8052336 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_6_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_6_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_6_3.ogg new file mode 100644 index 0000000..4f627a3 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_6_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_7_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_7_1.ogg new file mode 100644 index 0000000..35c6566 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_7_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_7_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_7_2.ogg new file mode 100644 index 0000000..5fa6ac6 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_7_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_7_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_7_3.ogg new file mode 100644 index 0000000..0f8cd11 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_to_house_power_7_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_1_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_1_1.ogg new file mode 100644 index 0000000..b2473d0 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_1_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_1_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_1_2.ogg new file mode 100644 index 0000000..b2473d0 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_1_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_1_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_1_3.ogg new file mode 100644 index 0000000..b2473d0 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_1_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_2_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_2_1.ogg new file mode 100644 index 0000000..17cd82f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_2_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_2_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_2_2.ogg new file mode 100644 index 0000000..17cd82f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_2_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_2_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_2_3.ogg new file mode 100644 index 0000000..17cd82f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_2_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_3_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_3_1.ogg new file mode 100644 index 0000000..17cd82f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_3_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_3_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_3_2.ogg new file mode 100644 index 0000000..17cd82f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_3_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_3_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_3_3.ogg new file mode 100644 index 0000000..17cd82f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_3_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_4_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_4_1.ogg new file mode 100644 index 0000000..8245aa3 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_4_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_4_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_4_2.ogg new file mode 100644 index 0000000..8245aa3 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_4_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_4_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_4_3.ogg new file mode 100644 index 0000000..8245aa3 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_4_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_5_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_5_1.ogg new file mode 100644 index 0000000..8245aa3 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_5_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_5_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_5_2.ogg new file mode 100644 index 0000000..8245aa3 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_5_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_5_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_5_3.ogg new file mode 100644 index 0000000..8245aa3 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_5_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_6_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_6_1.ogg new file mode 100644 index 0000000..09cfab8 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_6_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_6_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_6_2.ogg new file mode 100644 index 0000000..827ac5c Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_6_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_6_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_6_3.ogg new file mode 100644 index 0000000..ac79373 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_6_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_7_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_7_1.ogg new file mode 100644 index 0000000..5049792 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_7_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_7_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_7_2.ogg new file mode 100644 index 0000000..ef13694 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_7_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_7_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_7_3.ogg new file mode 100644 index 0000000..a0fb189 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/explode_superfar_underground_power_7_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/falling_stones.ogg b/src/main/resources/assets/explosionoverhaul/sounds/falling_stones.ogg new file mode 100644 index 0000000..bc20c4f Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/falling_stones.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/lab.ogg b/src/main/resources/assets/explosionoverhaul/sounds/lab.ogg new file mode 100644 index 0000000..f717261 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/lab.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/lamp_flicker_spark_1.ogg b/src/main/resources/assets/explosionoverhaul/sounds/lamp_flicker_spark_1.ogg new file mode 100644 index 0000000..9c87cab Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/lamp_flicker_spark_1.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/lamp_flicker_spark_2.ogg b/src/main/resources/assets/explosionoverhaul/sounds/lamp_flicker_spark_2.ogg new file mode 100644 index 0000000..01ce15b Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/lamp_flicker_spark_2.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/lamp_flicker_spark_3.ogg b/src/main/resources/assets/explosionoverhaul/sounds/lamp_flicker_spark_3.ogg new file mode 100644 index 0000000..369a43a Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/lamp_flicker_spark_3.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/low.ogg b/src/main/resources/assets/explosionoverhaul/sounds/low.ogg new file mode 100644 index 0000000..bd0bd17 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/low.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/sounds/music.ogg b/src/main/resources/assets/explosionoverhaul/sounds/music.ogg new file mode 100644 index 0000000..d9cd0a9 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/sounds/music.ogg differ diff --git a/src/main/resources/assets/explosionoverhaul/textures/block/vinlanxthelight.png b/src/main/resources/assets/explosionoverhaul/textures/block/vinlanxthelight.png new file mode 100644 index 0000000..0f6b3e4 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/textures/block/vinlanxthelight.png differ diff --git a/src/main/resources/assets/explosionoverhaul/textures/effects/flash.png b/src/main/resources/assets/explosionoverhaul/textures/effects/flash.png new file mode 100644 index 0000000..a436a50 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/textures/effects/flash.png differ diff --git a/src/main/resources/assets/explosionoverhaul/textures/item/mod_logo.png b/src/main/resources/assets/explosionoverhaul/textures/item/mod_logo.png new file mode 100644 index 0000000..3cad1f3 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/textures/item/mod_logo.png differ diff --git a/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_1.png b/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_1.png new file mode 100644 index 0000000..83bea5a Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_1.png differ diff --git a/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_2.png b/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_2.png new file mode 100644 index 0000000..6b279df Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_2.png differ diff --git a/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_3.png b/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_3.png new file mode 100644 index 0000000..588b783 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_3.png differ diff --git a/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_4.png b/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_4.png new file mode 100644 index 0000000..72aceca Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_4.png differ diff --git a/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_5.png b/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_5.png new file mode 100644 index 0000000..e9f5459 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_5.png differ diff --git a/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_6.png b/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_6.png new file mode 100644 index 0000000..597a467 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_6.png differ diff --git a/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_7.png b/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_7.png new file mode 100644 index 0000000..72aceca Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_7.png differ diff --git a/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_8.png b/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_8.png new file mode 100644 index 0000000..0455557 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/textures/particle/blast_wave/smoke/blast_smoke_8.png differ diff --git a/src/main/resources/assets/explosionoverhaul/textures/particle/line_spark/line_spark.png b/src/main/resources/assets/explosionoverhaul/textures/particle/line_spark/line_spark.png new file mode 100644 index 0000000..071083b Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/textures/particle/line_spark/line_spark.png differ diff --git a/src/main/resources/assets/explosionoverhaul/textures/particle/line_spark/line_spark_e.png b/src/main/resources/assets/explosionoverhaul/textures/particle/line_spark/line_spark_e.png new file mode 100644 index 0000000..4fc3f77 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/textures/particle/line_spark/line_spark_e.png differ diff --git a/src/main/resources/assets/explosionoverhaul/textures/particle/plasma.png b/src/main/resources/assets/explosionoverhaul/textures/particle/plasma.png new file mode 100644 index 0000000..2500bb1 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/textures/particle/plasma.png differ diff --git a/src/main/resources/assets/explosionoverhaul/textures/particle/plasma.png.mcmeta b/src/main/resources/assets/explosionoverhaul/textures/particle/plasma.png.mcmeta new file mode 100644 index 0000000..0645f48 --- /dev/null +++ b/src/main/resources/assets/explosionoverhaul/textures/particle/plasma.png.mcmeta @@ -0,0 +1,5 @@ +{ + "animation": { + "frametime": 2 + } +} diff --git a/src/main/resources/assets/explosionoverhaul/textures/particle/plasma_e.png b/src/main/resources/assets/explosionoverhaul/textures/particle/plasma_e.png new file mode 100644 index 0000000..5d8e875 Binary files /dev/null and b/src/main/resources/assets/explosionoverhaul/textures/particle/plasma_e.png differ diff --git a/src/main/resources/explosionoverhaul.mixins.json b/src/main/resources/explosionoverhaul.mixins.json new file mode 100644 index 0000000..44f3bea --- /dev/null +++ b/src/main/resources/explosionoverhaul.mixins.json @@ -0,0 +1,21 @@ +{ + "refmap": "explosionoverhaul.mixins.refmap.json", + "required": true, + "minVersion": "0.8", + "package": "com.vinlanx.explosionoverhaul.mixin", + "compatibilityLevel": "JAVA_21", + "mixins": [ + "ExplosionMixin" + ], + "client": [ + "GameRendererBlurMixin", + "ChannelAccessor", + "ChannelLowpassMixin", + "SoundEngineAudioQueueMixin", + "SoundPhysicsEnvironmentMixin" + ], + "server": [], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png new file mode 100644 index 0000000..3cad1f3 Binary files /dev/null and b/src/main/resources/logo.png differ diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta new file mode 100644 index 0000000..c057322 --- /dev/null +++ b/src/main/resources/pack.mcmeta @@ -0,0 +1,14 @@ +{ + "pack": { + "pack_format": 15, + "description": "Explosion Overhaul: A new level of destruction" + }, + "filter": { + "block": [ + { + "namespace": "explosionoverhaul", + "path": "intro_gui/.*\\.png" + } + ] + } +} diff --git a/src/main/templates/META-INF/neoforge.mods.toml b/src/main/templates/META-INF/neoforge.mods.toml new file mode 100644 index 0000000..5224893 --- /dev/null +++ b/src/main/templates/META-INF/neoforge.mods.toml @@ -0,0 +1,44 @@ +modLoader="javafml" +loaderVersion="${loader_version_range}" +license="${mod_license}" + +[[mods]] +modId="${mod_id}" +version="${mod_version}" +displayName="${mod_name}" +displayURL="https://vinlanx.github.io/vinlanx/" +logoFile="logo.png" +authors="Vinlanx" +credits="Check CREDITS.txt file for details." +description='''Private NeoForge 1.21.1 port of Explosion Overhaul.''' + +[[mixins]] +config="explosionoverhaul.mixins.json" + +[[dependencies.${mod_id}]] +modId="neoforge" +type="required" +versionRange="[21.1.228,)" +ordering="NONE" +side="BOTH" + +[[dependencies.${mod_id}]] +modId="minecraft" +type="required" +versionRange="${minecraft_version_range}" +ordering="NONE" +side="BOTH" + +[[dependencies.${mod_id}]] +modId="cloth_config" +type="required" +versionRange="[15.0.130,)" +ordering="NONE" +side="CLIENT" + +[[dependencies.${mod_id}]] +modId="geckolib" +type="required" +versionRange="[4.6.6,)" +ordering="NONE" +side="BOTH"